Search code examples
assemblyarm

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.