Search code examples
cassemblyarm

arm inline assembly - store C variable in arm register


Trying to save a variable in an arm register using inline assembly.

    unsigned int lma_offset = 0x1234; // typically calculated, hardcoded for example

    __asm volatile ("MOV R10, %[input]"
        : [input] "=r" (lma_offset)
      );

This changes lma_offset to 0xd100 in my case, instead of setting the register. What am I doing wrong?

PS: when I declare lma_offset as const it gives a compiler error because lma_offset is used as output. So obviously something is wrong, still I cant find the correct syntax for this.


Solution

  • For future reference, according to Erics comment

    const unsigned int lma_offset = 0x10000;
    
    __asm__ volatile ("MOV R10, %[input]"
        : // no C variable outputs
        : [input] "r" (lma_offset)
        : "R10"      // tell the compiler R10 is modified
          );
    

    using double : and replacing the "=r" with "r" indeed solves the problem.

    It would also be possible to ask the compiler to have that constant already in R10 for an asm statement, by using a register local variable to force the "r" input to pick r10. (Then we can omit the redundant mov r10, r10).

     register unsigned r10 __asm__("r10") = lma_offset;  // picks r10 for "r" constraints, no other *guaranteed* effects
     __asm__ volatile ("@ inline asm went here"  // empty template, actually just a comment you can see if looking at the compiler's asm output
       : // no C variable outputs
       : [input] "r" (lma_offset)
       : // no clobbers needed
     );
    

    When writing a register to some output C variable it would result in

    unsigned int lma_offset = 0x0;
    
    __asm__ volatile ("MOV %[output], R11"
        : [output] "=r" (lma_offset)
        // no clobbers needed; reading a register doesn't step on the compiler's toes
          );