Classification: |
C++ |
Category: |
Development |
Created: |
06/16/98 |
Modified: |
12/29/2001 |
Number: |
FAQ-0616 |
Platform: |
ER5 |
|
Question: My code compiles for WINS, but when I build it for MARM I get link errors which say "undefined reference to LCnnn" for some number, even though I don't have anything called LCnnn in the source code anywhere. What causes this and how do I fix it?
Answer: This is a known bug with the version of GCC currently used for MARM builds.
If an class scoped enumeration constant is passed to a function which takes the enum parameter by const reference, GCC generates
incorrect assembler code, resulting in errors at link time of the form:
...(.text+...)... undefined reference to 'LC0'
[[ 17th June 1998: Example updated to include the CArrayFixFlat<> version of this problem ]]
Here is an example of some source code which compiles, but generates code with unresolved references to LC0 and LC1:
#include
class foo { public: enum bar {EBarValue1, EBarGum}; void test2(); private: CArrayFixFlat* iArray; // array of foo::bar values };
void problem(const foo::bar& aParam); // const reference to a foo::bar value
void test() { problem(foo::EBarGum); // call supplying a specific foo::bar constant }
void foo::test2() { iArray->AppendL(foo::EBarGum); // call supplying a specific foo::bar constant }
And the assembler that is generated by GCC:
1 @ Generated by gcc cygnus-2.7.2-960323 (Psion GCC tools v113 05/03/1997) for ARM/pe 2 .file "enum.cpp" 3 .section .rdata 4 .text 5 .align 0 6 .global test__Fv 7 test__Fv: 8 @ args = 0, pretend = 0, frame = 0 9 @ frame_needed = 0, current_function_anonymous_args = 0 10 @ I don't think this function clobbers lr 11 0000 00009FE5 ldr r0, .L1216 12 0004 FEFFFFEA b problem__FRCQ23foo3bar 13 .L1217: 14 .align 0 15 .L1216: 16 0008 00000000 .word .LC0 17 .section .rdata 18 .text 19 .align 0 20 .global test2__3foo 21 test2__3foo: 22 @ args = 0, pretend = 0, frame = 0 23 @ frame_needed = 0, current_function_anonymous_args = 0 24 @ I don't think this function clobbers lr 25 000c 000090E5 ldr r0, [r0, #0] 26 0010 04209FE5 ldr r2, .L1225 27 0014 041090E5 ldr r1, [r0, #4] 28 0018 FEFFFFEA b InsertL__13CArrayFixBaseiPCv 29 .L1226: 30 .align 0 31 .L1225: 32 001c 00000000 .word .LC1
The compiler has correctly decided that it needs to pass a pointer to somewhere that contains the numeric value of the constant,
but it has forgotten to generate the constant itself.
HOW DO I FIX IT
It's not usually necessary to pass these values by reference (and the Psion Software coding standards tell you not to do
it). The problem() function should be fixed by changing the definition to:
void problem(foo::bar aParam); // passed by value, not by reference - const not needed
As a bonus this is also more efficient.
The CArrayFixFlat<> example is more awkward - this is an entirely reasonable thing to want to do, and the implementation
of CArrayFixFlat<> cannot be changed, so the calling code must be altered. It turns out to be sufficient to do the following:
inline void foo::ArrayAppendL(foo::bar aValue) { iArray->AppendL(aValue); }
void foo::test2() { ArrayAppendL(foo::EBarGum); // use the inline function instead }
Somehow the parameter passing aspect of the inline function causes GCC to take a different path through its code generation,
and it then produces valid code.
|