Search code examples
assemblyarm

How to use STR and LDR in Assembly


I'm a newbie in assembly and I can't solve a problem a teacher of mine gave me, I just want an explanation of what I am doing wrong. Basically what I have to do is save in R0 the number 65 (decimal), in R1 1B001B00 (hexadecimal) (This part isn't wrong because it compiled but if you have any suggestions of better ways to do it i'll be happy)

(The part that is not compiling) Store R0 in the address 0x20000040 and R1 in 0x20000044 and finally load what is in the address 0x20000040 in R7

Here is the code I wrote so far:

MOV R0, #65
MOV R1, #0x1B00
MOVT R1, #0x1B00
STR R0, 0x20000040
STR R1, 0x20000044
LDR R7, 0x20000040

The error I'm getting is

Bad symbol, not defined or external


Solution

  • The ARM architecture does not support direct addressing. Instead, you have to load the address into a register and then use an indexed addressing mode.

    For example, you could do:

    MOV R2, #0x20000000
    STR R0, [R2, #0x40]  @ 0x20000000 + 0x40 = 0x20000040
    STR R1, [R2, #0x44]  @ 0x20000000 + 0x44 = 0x20000044
    LDR R7, [R2, #0x40]
    

    We split up the address into 0x20000000 and 2 small offsets because ARM mov-immediate can only encode certain types of constants, like an 8-bit value rotated by any even count. Even with a rotate to bring the set bits together, the "simple" choice of 0x20000040 (one of the two adjacent addresses) has set bits 10 bits apart. So if you wanted that, you'd do ldr r2, =0x20000040 and let the assembler figure out how to get it into a register for you.

    You could use R7 to hold the address. You're going to overwrite it with the last load, so if you wanted to avoid using any temporary registers beyond the ones specified, that would do it.