squirem
squirem

Reputation: 247

Labels as Values in Inline Assembly Macros

I'm wondering how I can load a register with a the value of a label in inline assembly.

I tried naively doing it in this fashion:

#define inline_macro(a) \
    asm volatile("1: movw %[rega], #:lower16:1b\n" \
                 "   movt %[rega], #:upper16:1b\n" \
                 : [rega] "+r" (a)       \
                 :                       \
                 :                       \
    );

int main(void){
    register int   i     asm("r2");
    register void* value asm("r1");
    i++;
    i += 2;
    inline_macro(value);
    return i;
}

However, the object dump shows this assembly code being generated:

00000000 <main>:
   0:   e52db004    push    {fp}        ; (str fp, [sp, #-4]!)
   4:   e28db000    add fp, sp, #0
   8:   e1a03002    mov r3, r2
   c:   e2833001    add r3, r3, #1
  10:   e1a02003    mov r2, r3
  14:   e1a03002    mov r3, r2
  18:   e2833002    add r3, r3, #2
  1c:   e1a02003    mov r2, r3

00000020 <.L11>:
  20:   e3001000    movw    r1, #0
  24:   e3401000    movt    r1, #0
  28:   e1a03002    mov r3, r2
  2c:   e1a00003    mov r0, r3
  30:   e24bd000    sub sp, fp, #0
  34:   e49db004    pop {fp}        ; (ldr fp, [sp], #4)
  38:   e12fff1e    bx  lr

What I want is for the value 0x20 to be loaded into register r1.

Upvotes: 2

Views: 559

Answers (2)

Notlikethat
Notlikethat

Reputation: 20924

There is actually a whole instruction for getting the address of a label into a register: ADR.

Since it works by arithmetic on the PC, it's completely position-independent and doesn't have unlimited range, but neither seems an issue here - taking advantage of the assembler's "current instruction" pseudo-label ., the example in the question becomes:

#define inline_macro(a) \
    asm volatile("adr %[rega], . \n"     \
                 : [rega] "=r" (a)       \
                 :                       \
                 :                       \
    );

Upvotes: 2

Peter Cordes
Peter Cordes

Reputation: 364180

I don't know arm asm, but you're trying to get the address of the movw instruction? Does ARM really require two separate 16bit mov instructions for that?

It looks like you're disassembling the .o, where the linker hasn't replaced symbol references with their actual values, and you're seeing 0 as a placeholder.

Since I think your code doesn't depend on the old value of the register, you should use it as a write-only output operand (=r), not a read-write operand (+r).

Upvotes: 1

Related Questions