While learning ARMv6 ASM (using raspberry pi) I was trying to implement a loop which would modify the contents of a string, however I cannot seem to store the modified byte back to memory.
Using GDB and breaking at various points shows me all registry values are working perfectly until it comes to the STRB instruction. Then it crashes for some unknown reason.
The loop should decrement all bytes by 1 in reverse order.
.text
.global _start
_start:
/* Thumb mode */
.code 32
add r6, pc, #1
bx r6
.code 16
mov r4, #6
mov r0, pc
add r0, #16
loop:
/*load, modify, store*/
ldrb r3, [r0]
sub r3, #1
strb r3, [r0] /*THIS IS BROKEN*/
sub r0, #1
sub r4, r4, #1
bne loop
bx lr
.data
string:
asciz "HiThere"
The STRB instruction seems to crash the program, I am using an old book to learn from, am I missing something obvious here?
EDIT: yes I know that isnt the best way to load r0 but it works...i guess it could use a label in future.
EDIT2: Sorry I know my question was badly written, Ive included more code for clarity. Still crashes on STRB when stepping through in gdb.
EDIT: rather than increasing r0, your loop decreases it. So, rather than scrolling through the string, you are scrolling up straight into your code, overwriting instructions with less-by-one byte values. Once you overwrite the strb instruction, SIGILL happens.
Replace
sub r0, #1
with
add r0, #1
PREVIOUS: I see r0 being initialized to a memory location in the code section, past pc. Is that a writable memory block? I'm not so sure.
Place the string in the data section instead.
EDIT: there's another thing; your loop has no exit condition. SUB doesn't set flags unless told to; so replace
sub r4, r4, #1
with
subs r4, r4, #1
Related
I was debugging the following code on CPULator
.global _start
_start:
MOV R4, #0x61
LDR R0, =freq
ADD R0, R4
LDR R2, [R0]
ADD R2, #1
STR R2, [R0]
_exit:
MOV R7, #1
SWI 0
.data
freq: .rept 128
.word 0x00 # initialise character counts as 0
.endr
I get an error on the CPULator console:
0000000c Warning: Memory read of 4 bytes at address 00000089 is misaligned. Throwing data abort exception.
Simulator requested a breakpoint.
The exception was thrown on line 7:
LDR R2, [R0]
Why is this and how can I solve it?
the CPU is trying to access an odd address of the memory.
LDR R2, [R0] --> Load R2 with the content of the memory address referenced by R0
R0 contains and odd number.
All 32-bit and 64-bit CPU's can access even addresses of the memory:
0x00000000 is good
0x00000004 is good
0x00000008 is good
0x00000009 is not good
Enrico Migliore
P.S.
CPU's can only access: "aligned memory addresses" which are even addresses multiple of 4 or 8 depending on the CPU type.
A very few and special ARM instructions can access "unaligned addresses".
Take a look at here:
https://community.arm.com/developer/tools-software/oss-platforms/f/dev-platforms-forum/8806/loads-and-stores-for-unaligned-memory-addresses
I'm trying to make an Assembly program concatenate two Strings. Here's my program.
AREA Assignment4, CODE, READONLY
ENTRY
;;;;;;;;;;Setting Up
ADR r0, StrF ;Address of first block in destination
;;;String 1
ADR r1, Str1 ;Address of first string
ADR r2, EoS ;Address of EoS1
SUBS r2, r2,r1 ;Length of str1, counter
;;;;String2
ADR r3, Str2 ;Address of second string
ADR r4, EoS2 ;Address of EoS2
SUBS r4, r4,r3 ;Length of Str2
;;;;;;;;;;Performing Actions
;;;;First String
Loop LDRB r5,[r1],#1 ;Load next bit of "r1" in r5
STRB r5,[r0],#1 ;Store prev bit in memory at r0
SUBS r2, r2, #1 ;Decrement counter
CMP r2, #0 ;Compare our counter
BNE Loop ;Branch if counter != 0
;;;;;Second String
Loop2 LDRB r5,[r3],#1 ;Load next bit of "r3" to r5
STRB r0,[r5],#1 ;Store this bit in r0
SUBS r4, r4, #1 ;Decrement length counter
CMP r4, #0 ;Compare our counter
BNE Loop2 ;Branch if counter != 0
;; Testing the memory - Delete these lines later
ADR r0, StrF
loop3 LDRB r1,[r0],#1
B loop3
Finished B Finished
Str1 DCB "This is a test string1" ;Str1
EoS DCB 0x00
Str2 DCB "This is a test string2" ;Str2
EoS2 DCB 0x00
StrF DCB 0x00 ;Saving this
END
My problem is on lines 22 + 29. I don't know how to successfully store the current byte onto the memory; more specifically the memory in register r0, initialized initially by StrF.
Any ideas on how to fix my STRB or STR?
I get this once I pass that line:
"error 65: access violation at 0x00000082 : no 'write' permission"
thats the memory address that at StrF that im trying to save into.
You see that big "READONLY" in the first line?
Since strF is located in the same area as the code declared as readonly, it of course doesn't work.
You should put strF in a differnt area declared as readwrite, but you won't be able to use adr then.
All in all, you should design the routines in a way that they receive memory addresses as parameters from the callers.
i had this problem, so if you are using keil, when u in debug mode go to debug -> memorymap, then add memory range manually
0x00000048 ,0x0000011A
and check on read, write a/o execute
check this page
DEBUGGER: ERROR 65 (ACCESS VIOLATION)
I am trying to print a number that I have stored. I'm not sure if I am close or way off. Any help would be appreciated though. Here is my code:
.data
.balign 4
a: .word 4
.text
.global main
main:
ldr r0, addr_of_a
mov r1, #8
str r1, [r0]
write:
mov r0, #1
ldr r1, addr_of_a
mov r2, #4
mov r7, #4
swi #0
bx lr
addr_of_a: .word a
It compiles and runs, but I don't see anything printed. From what I understand, I need the address of where to start printing in r1, how many bytes in r2, the file descriptor in r0, and r7 specifies the write call if it is set to #4. I am simply trying to store #8, then print the stored number.
The syscall write takes on the second argument (r1) as a pointer to the string you want to print. You are passing it a pointer to an integer, which is why it's not printing anything, because there are no ASCII characters on the memory region you are passing to it.
Below you'll find a "Hello World" program using the syscall write.
.text
.global main
main:
push {r7, lr}
mov r0, #1
ldr r1, =string
mov r2, #12
mov r7, #4
svc #0
pop {r7, pc}
.data
string: .asciz "Hello World\n"
If you want to print a number you can use the printf function from the C library. Like this:
.text
.global main
.extern printf
main:
push {ip, lr}
ldr r0, =string
mov r1, #1024
bl printf
pop {ip, pc}
.data
string: .asciz "The number is: %d\n"
Finally, if you want to print the number with the syscall write you can also implement a itoa function (one that converts an integer to a string).
Hi I appreciate that this is a pretty old thread but I've scratched my head over this for a while and would like to share my solution. Maybe it'll help someone along the way!
I was aiming to print to digit without recourse to using C++ in any way, though I realise that simply decompiling a tostring() - or whatever equivalent exists in C++ - and seeing what that came up with would have been a far quicker route.
Basically I ended up with creating a pointer to an empty .ascii string in the section .data and added the digit that I wanted to print + 48 to it before printing off that digit.
The +48 of course is to refer to the specific digit's ascii index number.
.global _start
_start:
MOV R8, #8
ADD R8, R8, #48
LDR R9, =num
STR R8, [R9]
MOV R0, #1
LDR R1, =num
MOV R2, #1
MOV R7, #4
SWI 0
.data
num:
.ascii: " "
The biggest drawback of this approach is that it doesn't handle any number more than one digit long of course.
My solution for that was much, much uglier and beyond the scope of this answer here but if you've a strong stomach you can see it here:
I have a simple function written in ARM assembler. The first time it's ran, everything works as desired (it prints BOOT\n). However, the second time the function is executed, nothing is printed.
.globl __printTest
.text
.align 2
__printTest:
sub sp, #64 /* yes, I know this is too much */
mov r0, #66
str r0, [sp]
mov r0, #79
str r0, [sp, #1]
mov r0, #79
str r0, [sp, #2]
mov r0, #84
str r0, [sp, #3]
mov r0, #10
str r0, [sp, #4]
mov r0, #0
mov r1, sp
mov r2, #5
bl _write
add sp, #64
bx lr
What could be the issue? I suspect that this somehow screws up the buffer that it no longer works. Write is a function that calls the write syscall on Linux using the svc instruction.
The problem is that you're not saving lr.
bl _write
add sp, #64
bx lr
bl _write will overwrite lr which then points to add sp, #64, so your bx lr will just result in an endless loop on the last two instructions.
It should work if you modify your code like this:
__printTest:
push {lr}
sub sp, #64 /* yes, I know this is too much */
....
bl _write
add sp, #64
pop {pc}
As already stated in another answer, you should also use strb instead of str for byte-stores.
This function is pushing 32-bit values into unaligned stack pointer addresses. It should be using strb to write single bytes. For unaligned str, the ARM Architecture Reference Manual says:
if UnalignedSupport() || address<1:0> == ‘00’ then
MemU[address,4] = R[t];
else // Can only occur before ARMv7
MemU[address,4] = bits(32) UNKNOWN;
So depending on your configuration, you might be getting junk in your stack if you're hitting the UNKNOWN case.
Can anybody point out why? I can't see the problem.
String to search: "aassaas"
String to search with: "as"
SEARCHSTRING:
STMFD SP!, {R4-R7, LR}
MOV R6, #0 #Matches found
MOV R3, #0 #Placeholder
LOOP: LDRB R4, [R0] #R4 = String to search
LDRB R5, [R1] #R5 = String to search with
CMP R4, R5 #Do they match?
ADDEQ R3, R3, #1 #If yes, increase placeholder
LDREQB R4, [R0, #1]! #Get next char
LDREQB R5, [R1, #1]! #Get next char
BLNE RESET #If not, reset placeholder and strings.
#R0 is nevertheless initial pos+1
CMP R5, #0 #Is string to search with at the end?
ADDEQ R6, R6, #1 #If so, add +1 to matches
BLEQ RESET #Reset placeholder and strings.
CMP R4, #0 #Is the string to search finished?
BNE LOOP #If not, start over.
MOV R0, R6 #If so, move answer into R0.
LDMFD SP!, {R4-R7, PC} #Jump back.
RESET:
STMFD SP!, {LR}
CMP R3, #0 #Is the placeholder at 0? (initial position)
SUBNE R0, R0, R3 #If not, subtract from String to search pos
SUBNE R1, R1, R3 #And string to be searched pos
ADDNE R0, R0, #1 #Increment string to search+1 so we don't start at the same spot
MOVNE R3, #0 #Empty the placeholder
LDMFD SP!, {PC} #Jump back
I don't understand why a) you're writing this in assembler instead of C, and b) why you're not using some routine based on strstr. The most likely scenario is that this is a homework problem, or some other form of learning exercise, so I don't want to give too much away. In any event, there are a couple of problems that I noticed. The first bit I notice is in the RESET routine:
RESET:
STMFD SP!, {LR}
CMP R3, #0 #Is the placeholder at 0? (initial position)
SUBNE R0, R0, R3 #If not, subtract from String to search pos
SUBNE R1, R1, R3 #And string to be searched pos
ADDNE R0, R0, #1 #Increment string to search+1 so we don't start at the same spot
MOVNE R3, #0 #Empty the placeholder
LDMFD SP!, {PC} #Jump back
The CMP is unnecessary - consider what the effect of the SUBNE calls will be if R3 is 0, and you'll see that you can perform the subtractions unconditionally. You want to run ADD R0, R0, #1 unconditionally - in fact, this is a big part of the reason you have an infinite loop. If you get to the RESET subroutine, and R3 is 0, then it doesn't change any state. I also notice that the STMFD / LDMFD pair is really not necessary - LR won't be modified in this subroutine, so it doesn't need to go on the stack.
Next, I notice that you're not careful enough about when to terminate your loop. Consider what happens if you give two empty strings as arguments to SEARCHSTRING. Call it with two empty strings as arguments, and single-step through your assembly code to see the problem. The general form of a for loop, when compiled to assembly, will be something like:
for(initial; comparison; increment) {
body;
}
INITIAL:
MOV R0, #0 #initialize variables
B CONDITION #jump to condition check
BODY:
LDR R1, [R0]
INCREMENT: #really, part of the for-loop body.
ADD R0, R0, #1
CONDITION:
CMP BLAH, BLAH #test-condition
BLT BODY #restart loop if condition indicates we should do so.
hopefully this will help you to reorganize the code in a more straightforward way.