Can't load a word into register

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.

Leave a Reply