Hello ARM Community,
I am using DS-5 5.18.1. I have a C function which must be compiled inline to decrease latency of an FIQ handler. I referenced following document for syntax:
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0472k/chr1359124973480.html
Note that the attribute may accompany the function declaration and/or definition.
I added the attribute to the function declaration as below in example.c:
void foo(void) __attribute__((always_inline));
The following linking error was produced:
L6218E: Undefined symbol foo (referred from example.o). C/C++ Problem
It is important to note that this error was not present before adding the inline attribute. There are no related warnings, nor any other errors. Why would this single change cause the preceding error?
Thank you,
Ryan
Hi Ryan,
I think I managed to reproduce the issue you're seeing with ARM Compiler. I have the following code:
main.c
#include "extra.h" int main() { foo(); return 0; }
extra.c
#include "extra.h" void foo(void) { int i = 0; i = i+1; }
extra.h
#ifndef EXTRA_H_ #define EXTRA_H_ void foo(void) __attribute__((always_inline)); #endif /* EXTRA_H_ */
This set of code causes the linking error you mentioned in your question. When compiling main.c, armcc sees the declaration of void foo(void) but can't see the definition of the function. I think armcc here just ignores the attribute and it assumes that the function is defined somewhere else. If you disassemble main.o using fromelf -c you can see the call to the label foo:
main 0x00000000: e92d4010 .@-. PUSH {r4,lr} 0x00000004: ebfffffe .... BL foo 0x00000008: e3a00000 .... MOV r0,#0 0x0000000c: e8bd8010 .... POP {r4,pc}
main
0x00000000: e92d4010 .@-. PUSH {r4,lr}
0x00000004: ebfffffe .... BL foo
0x00000008: e3a00000 .... MOV r0,#0
0x0000000c: e8bd8010 .... POP {r4,pc}
In the same way, when armcc compiles extra.c, it sees that foo is declared as always_inline and it's not used anywhere thus it won't be included in extra.o (you can check that with fromelf, too).
In order to fix this is sufficient to move the definition of the function from extra.c to extra.h so that it's visible to any c file using that function (and then properly inlined).
extra.h will look like:
#ifndef EXTRA_H_ #define EXTRA_H_ void foo(void) __attribute__((always_inline)); void foo(void) { int i = 0; i = i+1; } #endif /* EXTRA_H_ */
Hope this helps. If you need further help please do let me know.
Best Regards,Stefano
Yes, you have accurately recreated the scenario. It is against our code standard to have a function definition in a header file. An alternate solution is to move the declaration of foo into the same file as it is called as done in your first reply. This is not preferable in order to preserve code modularity. Is there another solution?
the tricky part here is that you need to have the definition of the function available when compiling main.c otherwise armcc would ignore the always_inline statement and would put a BL to that function. A possible alternative, from my point of view less clear, is to include the source file instead of the header as:
#include "extra.c" int main() { foo(); return 0; }
In this way armcc will have visbility over both the declaration (through extra.h included by extra.c) and definition of the function.
I would suggest, for the clarity of the code, to keep the definition and the declaration of the function together in extra.h: this is because the function will be inlined everytime so it does not need to be compiled in a different object file (extra.o).
Hope this helps.
Stefano,
Thank you for your thorough and prompt replies. You present another valid but frowned-upon method of keeping the declaration and definition of the function together by including the .c file. I agree that placing the function definition in the header is at least slightly better practice than this. Instead of inlining the function I have instead decided to check a condition outside the function call in the FIQ handler which will never evaluate true unless a fault occurred. In this way, the speed of the function call is less important.