Search code examples
gccarmc-preprocessorinline-assembly

inline ARMv7-M assembly code into c using gcc and macros


I have this code that works fine:

void function( void )
{
    __asm volatile
    (
        "   ldr r3, .ADDRESS            \n"
        "   mov r2, %0                  \n"
        "   str r2, [r3, %1]            \n"
        ".ADDRESS:  .word 0x401C4000    \n"
        :: "i" (1<<17), "i" (16)
    );
}

But to declare .ADDRESS I used the magic number 0x401C4000. I actually have a macro for this.

For Example:

#define ADDR_BASE 0x401C4000
#define ADDR ((void *)ADDR_BASE)

void function( void )
{
    __asm volatile
    (
        "   ldr r3, .ADDRESS            \n"
        "   mov r2, %0                  \n"
        "   str r2, [r3, %1]            \n"
        ".ADDRESS:    .word %2          \n"
        :: "i" (1<<17), "i" (16), "i" (ADDR)
    );
}

That doesn't build.

How can I use a macro in this case?


Solution

  • See the edit below. I'm only leaving this first solution as an example of what you shouldn't do.


    I found this post where a solution is given to my same problem, but it involves x86. I wanted to try it anyway, and it works.

    Then use %c2 instead of %2, as shown here:

    #define ADDR_BASE 0x401C4000
    #define ADDR ((void *)0x401C4000)
    
    void function( void )
    {
        __asm volatile
        (
            "   ldr r3, .ADDRESS            \n"
            "   mov r2, %0                  \n"
            "   str r2, [r3, %1]            \n"
            ".ADDRESS:   .word %c2          \n"
            :: "i" (1<<17), "i" (16), "i" (ADDR): "r2", "r3", "memory"
        );
    }
    

    EDIT

    The solution I suggested above may not work by seeing the generated code:

      20                function:
      21                    @ Function supports interworking.
      22                    @ args = 0, pretend = 0, frame = 0
      23                    @ frame_needed = 1, uses_anonymous_args = 0
      24                    @ link register save eliminated.
      25 0000 04B02DE5      str fp, [sp, #-4]!
      26 0004 00B08DE2      add fp, sp, #0
      27                    .syntax divided
      28                @ 6 "test.c" 1
      29 0008 04309FE5         ldr r3, .ADDRESS            
      30 000c 0228A0E3     mov r2, #131072                  
      31 0010 102083E5     str r2, [r3, #16]            
      32 0014 00401C40  .ADDRESS:   .word 1075593216          
      33                
      34                @ 0 "" 2
      35                    .arm
      36                    .syntax unified
      37 0018 0000A0E1      nop
      38 001c 00D08BE2      add sp, fp, #0
      39                    @ sp needed
      40 0020 04B09DE4      ldr fp, [sp], #4
      41 0024 1EFF2FE1      bx  lr
    

    You can see at line 32 the symbol .ADDRESS has been issued, but it is surrounded by code, and there is no instruction to skip it. I believe that it can be attempted to be executed as if it were an instruction.

    Maybe a better solution, suggested by Peter, is

    #define ADDR_BASE 0x401C4000
    #define ADDR ((void *)0x401C4000)
    
    void function( void )
    {
        __asm volatile
        (
        "str %0, [%2, %1]"
        :: "r" (1<<17), "i" (16), "r" (ADDR) : "memory"
        );
    }