4

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.

10
  • Try adding an underscore to the beginning of IRQHandler_real: _IRQHandler_real Commented Jun 26, 2018 at 16:29
  • I think the code is also intended to pass SP to the called function rather than PC. Commented Jun 26, 2018 at 16:31
  • Thomas, I tried both single and double underscores, both failed with the same compile. Commented Jun 26, 2018 at 16:37
  • Supercat, I updated the question. Thanks for the catch. Commented Jun 26, 2018 at 16:37
  • 1
    All of our code is written in C. I asked around the office, it looks like we are using ARMCC 5.06, not GCC ARM. I was trying to avoid creating a new file for such a small change, but I can move it into a new file if there's no inline solution. I'll try loading the struct into the interrupt vector and will check back with that Commented Jun 26, 2018 at 18:06

2 Answers 2

2

If your compiler is a C++ compiler you will need to use extern "C" like this;

extern "C" {
  void IRQHandler_real( uint32_t *sp )
  {
     // Do some work
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

I would expect that this would work for VS/C++. Unfortunately, it doesn't work for ARMCC.
@MPStoering you might need to surround it by #ifdef __cplusplus but it's documented here on the ARM website. I didn't think anyone uses armcc anymore, but I'm also sure this works with gcc.
1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.