Home > Software engineering >  How to load a .word symbol into a register in Arm assembly?
How to load a .word symbol into a register in Arm assembly?

Time:05-18

Probably a common beginner question, and similar questions have been asked on this site, but I can't find any help on a couple points. If you have a 32-bit symbol defined with .word, and you want to load it into register r1, what's the conventional way to do it?

.syntax unified
.cpu cortex-m4
.thumb
/* ... */
_allones:  .word 0xffffffff
test:
    /* This seems to not work as expected */
    ldr    r1,_allones   @ Value is corrupted/misaligned?

    /* Two-line solution */
    ldr    r1,=_allones  @ Loads the address of _allones into r1, not the value itself
    ldr    r1,[r1]       @ Get value proper

My confusion is when you see tutorials like this one where only the ldr r1,=_allones is used to load the value of _allones (see "Initialization Code", first listing and explanation), and the answer I linked above which makes it seem like the first option in my example should work. Target is Cortex-M4, in Thumb mode, with unified syntax.

FWIW The ldr r1,_allones line instead loads the last two bytes of _allones and then the first two bytes of its address in memory, or something in that vain, I haven't looked that closely at the value.

CodePudding user response:

In general, ldr r1, =sym will load the value of the symbol sym into r1. (It does so by assembling the value of sym into memory at a location called a literal pool which is fairly near to the instruction, so that it can be reached with the pc-relative literal form of the load instruction.)

But there are two different ways to define a symbol. It can be defined as a label, like sym:, in which case the value of the symbol is the address that it labels (which may not actually be known until the linking stage of the build). That's the case in your code. But a symbol can also be defined as a numerical constant, like sym EQU 12345, in which case its value is simply the number 12345. That's what is happening in the tutorial.

So if you want to load 0xffffffff into r1, the two possibilities would look as follows:

allones:
    .word 0xffffffff
...
    ldr r1, =allones @ now r1 contains the address where 0xffffffff is stored
    ldr r1, [r1]     @ load from that address

or

allones EQU 0xffffffff
...
    ldr r1, =allones

Of course, if the value actually is 0xffffffff, then it would be best to just write mov r1, 0xffffffff, or allones equ 0xffffffff ; mov r1, allones. (The # is optional in some assemblers.) The mov immediate instruction has a limited set of values that can be used as the immediate, but 0xffffffff is one of them. Some assemblers might optimize ldr r1, =const into mov r1, const when the constant has an appropriate value.

  • Related