Search code examples
carminline-assemblycortex-marmcc

Calling a C function from ARM function defined with __asm


I am having trouble understanding my compiler. We use the Scons utility to compile ARM code for an M0+ processor (on Windows, if it matters. It's an ARMCC compile) I am trying to capture the address of the stack pointer during an interrupt using the answer to this question.

For my compiler, I get the following: Error: #20: identifier "asm" is undefined The only way that I was able to get it to (mostly) compile was with the following:

  void IRQHandler_real( uint32_t *sp )
  {
     // Do some work
  }

  __asm void IRQHandler( void )
  {
     MOV R0,SP
     ADDS R0, #1
     LDR R1, =IRQHandler_real //<<-- This line fails
     BX R1
  }

The error code is

  Error: A1516E: Bad symbol 'IRQHandler_real', not defined or external

Replacing the last two assembly lines with BL IRQHandler_real results in the same error.

This answer explains that inline assembly is extremely compiler dependent, so I haven't been able to find an example that matches my code.

I read here that I need an "extern C" call, but I haven't yet found details on what that looks like.

I double checked my syntax of the compiled processor code, and it looks identical to the commands that I am using. I think that the symbol is not defined at the time when the assembly is evaluated. I just haven't figured out how to define and link the symbols.

TL:DR, I need to call a C function from ARM assembly, but I haven't gotten past the compiler.


Solution

  • It seems like the compiler is evaluating the ARM code separately from and after all C code is evaluated. I fixed it by importing the function with the IMPORT command. My final code looks like this:

    IMPORT IRQHandler_real
    PUSH { R4, lr }
    MOV R4, SP; The compiler does this from the C code, I'm assuming to avoid a hardware limitation.
    MOV R0, R4
    BL IRQHandler_real
    POP { R4, PC }
    ENDP
    

    This works for ARMCC 5.6. I think that most of the documentation out there is for GCC ARM (asm("statement");). I am still getting Warning: #667-D: "asm" function is nonstandard, so I will gladly accept a "more correct" answer if one exists.