Symbian
Symbian OS Library

FAQ-0616 What causes "undefined reference to LC0"?

[Index][spacer] [Previous] [Next]



 

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.