Being a newbie in Assembly language I managed to tripped up over this hello-world-like program:
.global _start
_start:
ldr R0, =val
mov R7, #1
svc 0
.data
val: .word 0xffffffff
My intent is just to load the val word into R0, so its value would be used as the program’s exit status (its the least significant byte, to be precise). However, instead of the expected value, ff_16 = 255, I get such an output from bash:
$ ./prog; echo $?
132
Output of disassemblying:
00000000 <_start>:
0: e59f0004 ldr r0, [pc, #4] ; c <_start+0xc>
4: e3a07001 mov r7, #1
8: ef000000 svc 0x00000000
c: 00000000 .word 0x00000000
It shows the presence of an offset from PC by 4 but the word marked as 4: is not the desired one, is it? On the other hand, even this word does not contain 84_16 = 132 value, so where it springs from?
Some clarification is needed, please.
Architecture: arm7l, OS: raspberrypi 5.4.72-v7+
>Solution :
The instruction
ldr r0, =val
loads the address of val into R0. It assembles to something like
ldr r0, foo
...
foo: .int val
To load the value of val, you need
ldr r0, val
Note that this only works if val is reasonably close by (e.g. closer than about ±1 kB). If val is far away or in another segment (as is in your case), you’ll need to first load the address and then the datum:
ldr r0, =val
ldr r0, [r0]
Also note that you might want to use a movw/movt pair instead of the ldr r0, =... instruction if supported (ARMv7 has it); it’s slightly faster where supported as it eliminates a load:
movw r0, :lower16:val
movt r0, :upper16:val
These two instructions can be issued interspersed with other instructions, but if they are given consecutively, they macro fuse on some cores which gives a performance benefit, so try to do that. You can also use a lone movw to load any 16 bit value into a register.