1

I have this example from a text:

MOV R1, #7
LDR R2, = ioadr
STR R1, [R2]
ioadr .word 0x20001000

It says that it then stores the value 7 to the memory adress 0x20001000. But I am wondering about the line LDR R2, = ioadr. Why is it that we don't get that we load the adress of ioadr to R2?, but instead load the value if ioadr to R2? Does the assembler know that ioadr is a constant and not a variable? Aren't there cases where the adress would be loaded?

PS: The example was with DCD, but as I understand it this is equivalent to .word.

Original code:

MOV R1, #7
LDR R2, = ioadr
STR R1, [R2]
ioadr DCD 0x20001000

source: chapter 9 here https://booksite.elsevier.com/9780128000564/

user394334
  • 243
  • 1
  • 10
  • 1
    If you want to have `R2` hold `0x20001000`, then just use `LDR R2, ioadr` or `LDR R2, =0x2000100`. – fuz Aug 23 '22 at 15:12
  • 1
    *loads the value 7 to the memory adress 0x2000100* - I think you mean **stores**. Writing to memory is a store, not a load. Anyway, `LDR R2, = ioadr` *does* load the address of the label into R2, not the word stored there. This code doesn't store to address `0x2000100`. – Peter Cordes Aug 23 '22 at 15:24
  • If you defined `ioadr` with `.equ ioadr, 0x2000100` or `ioadr = 0x2000100`, then the symbol "address" would be `0x2000100` and the code would work. As far as GAS figuring out whether a symbol is a label or an assemble-time constant, that *is* a real problem in syntaxes where there's ambiguity, like Intel syntax for x86: [Distinguishing memory from constant in GNU as .intel\_syntax](https://stackoverflow.com/q/39355188) – Peter Cordes Aug 23 '22 at 15:27
  • you should have posted the original code and your translation to another assembly language. please complete the question and show the from. – old_timer Aug 23 '22 at 17:51
  • 2
    That STR will overwrite the word at label `ioaddr` holding 0x20001000 with the value 7. Might want to recheck your source. If you remove the `=`, it will do as you're describing. – Erik Eidt Aug 23 '22 at 17:56
  • @old_timer I posted the original code. – user394334 Aug 23 '22 at 19:45

1 Answers1

1

Using gnu assembler for arm.

MOV R1, #7
LDR R2, = ioadr
STR R1, [R2]
ioadr .word 0x20001000

This will fail because there is no colon after ioadr

so.s: Assembler messages:
so.s:5: Error: bad instruction `ioadr .word 0x20001000'

so

MOV R1, #7
LDR R2, = ioadr
STR R1, [R2]
ioadr: .word 0x20001000

this

LDR R2, = ioadr

is pseudo code that 1) is not supported by all tools for arm, 2) not supported in the same way. It says you want the address of ioadr loaded into r2. being pseudo code you should see what the tool does with it

unlinked:

Disassembly of section .text:

00000000 <ioadr-0xc>:
   0:   e3a01007    mov r1, #7
   4:   e59f2004    ldr r2, [pc, #4]    ; 10 <ioadr+0x4>
   8:   e5821000    str r1, [r2]

0000000c <ioadr>:
   c:   20001000    .word   0x20001000
  10:   0000000c    .word   0x0000000c

linked

Disassembly of section .text:

00008000 <ioadr-0xc>:
    8000:   e3a01007    mov r1, #7
    8004:   e59f2004    ldr r2, [pc, #4]    ; 8010 <ioadr+0x4>
    8008:   e5821000    str r1, [r2]

0000800c <ioadr>:
    800c:   20001000    andcs   r1, r0, r0
    8010:   0000800c    andeq   r8, r0, ip

So you can now use this against the architectural reference manual and trivially see that it is loading the ADDRESS of ioadr into r2 not 0x20001000

So when the store happens it stores it writes over the 0x20001000 not a write to 0x20001000

Change it to different pseudo code, remove the equals

MOV R1, #7
LDR R2, ioadr
STR R1, [R2]
ioadr: .word 0x20001000

Now it does what the book seems to be describing.

Disassembly of section .text:

00008000 <ioadr-0xc>:
    8000:   e3a01007    mov r1, #7
    8004:   e59f2000    ldr r2, [pc]    ; 800c <ioadr>
    8008:   e5821000    str r1, [r2]

0000800c <ioadr>:
    800c:   20001000    andcs   r1, r0, r0

The load loads the value 0x20001000 into r2 so that the store then is actually written to 0x20001000.

DCD and .word are not the only assembly language issues that you needed to look at. As you can see now above. If you have any questions then assemble and disassemble and look up the instructions yourself first then if still confused post it along with the source.

I suspect the book is wrong, and that is another life lesson. Documentation is buggy, assume that it is, including the arm docs. If you have access to arms tools that match the assembly language in the book (if the book is halfway decent it will specify the exact tool and version, I did not look) then assemble and disassemble.

As you can see in the many answers on this site related to the equal sign pseudo code for ARM, for example

ldr r0,=0x12345678
ldr r1,=0x00000007

You will find that gnu will choose the optimal instruction(s). But other tools, if they support it at all, might take it literally and generate a ldr using a literal pool. The first one above will probably be a pc relative load from a literal pool as shown in the examples above based on your code. the latter, with gnu, will generate a mov r1,#7 instead of a pc relative load. So when using these kinds of things, use with care. Most important understand that assembly language is specific to the tool, not the target. And sometimes the version of the tool. In the same way it takes work to convert a c program to java or python it takes work to convert assembly language to one of arms tools (note that arm has had a series of tools over time, re-writes or purchases of smaller companies) to gnu binutils and back. It is literally a conversion from one programming language to another, just not as harsh as C to python.

old_timer
  • 69,149
  • 8
  • 89
  • 168
  • Oh and of course since there was no branch between the str and the ioadr this code is expected to crash if you really wanted to run it. The code does not terminate, it just executes data, which as shown are likely not to stop so whatever is found in memory after these will eventually crash. – old_timer Aug 24 '22 at 03:49