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+
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.