4

I'm programming for an embedded power-pc platform (using the wind-river diab compiler, if that matters) and want to link my code with pre-compiled object files *.o (compiled for the same platform, of course). One of these object files needs an external symbol, that I have to define myself and link against that *.o file - otherwise the linker would complain:

Undefined symbol 'mySymbolName' in file 'precompiled.o'

However, even if I compile a source file with that missing symbol (same signature that the precompiled o.* file expects: 'unsigned char const [16]') & link it against the precompiled.o, the linker still complains. myCFile.c:

unsigned char const mySymbolName[16] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ,0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

I compile the code with the command:

bin/dplus -g -Xdebug-dwarf3 -W:c++:.c -Xc++-abr -Xmake-dependency=0xd -Xsmall-data=0 -Xsmall-const=0 -Xlint=0x40 -O -tPPC5554FF:cross -I{some include pathes...}   -DTOOL_FAMILY=diab -DTOOL=diab -DPowerPC -DPPC5500  -o "myObjectFile.o" -c "myCFile.c"

The compiler warns me, that mySymbolName is declared but never used (of course it's not - it's referenced from another object file - so the warning is fine in my opinion). Linking with the command:

bin/dld   -tPPC5554FF:cross file.dld -o "output.elf"  myObjectFile.o precompiled.o

Fails with the error:

Undefined symbol 'mySymbolName' in file 'precompiled.o'

Using nm (of course for the specific target platform) I figured out, that my symbol is not visible in my compiled object file: nm just doesn't show anything. However, I found a way to Show my symbol in nm. If I drop the 'const' specifier in my c file, to:

unsigned char mySymbolName[16] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ,0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

nm shows mySymbolName correctly.

So my question is: How is that possible? Is this expected behaviour - or does it behave differently on different platforms? Is it a allowed optimization for ANSI-C Compiler to remove unreferenced const-variables at compile-time?

Constantin
  • 8,721
  • 13
  • 75
  • 126
  • Did you try adding an additional extern declaration to `myCFile.c`? `extern unsigned char const mySymbolName[16];` – Sergey L. Oct 30 '13 at 11:25
  • 1
    The Diab Data compiler does a very heavy job of optimizing things. I would suggest removing all optimization and seeing of the problem is still there (_with_ the `const` qualifier), and if that lets it re-appear, you've bounded the problem and can figure out which optimizer flag is responsible. (And if not, you can ignore my comment :) – mah Oct 30 '13 at 11:25
  • 1
    @SergeyL. the `extern` keyword in fileA.c will have no effect on what gets placed into fileB.c's compiled object... and if it's required for fileA.c then the source will fail to compile without it. – mah Oct 30 '13 at 11:25

1 Answers1

4

Your Diab compiler invocation appears to be forcing C++ compilation, the semantics of const in C++ differ from those of C in a number if ways.

In C++ a const at file scope has implicit static (or internal) linkage, so will not be placed in the object file's symbol table. This differs from the behaviour of C, so had you used C compilation, it would have produced what you expected.

Add an explicit extern declaration (or use C compilation):

extern unsigned char const mySymbolName[16] ;

For more information see Ben Voigt answer to a question on const semantics I asked a while ago.

Community
  • 1
  • 1
Clifford
  • 88,407
  • 13
  • 85
  • 165
  • 1
    Nooo... Instead, compile C code as C code. None of that C++ nonsense! (for pure C anyway... [this diagram](http://www.windriver.com/products/development_suite/wind_river_compiler/) suggests that the compiler has a proper, real C fronted, is that right?) –  Oct 30 '13 at 23:26
  • @H2CO3: Of course, I was typing that suggestion as you were adding your comment. That said there are valid reasons why you might deliberately use C++ compilation even for code that is also compilable as C, but you have to accept that the resulting code *is* C++ and not C, and there are a few subtle semantic differences. In this case however it seems like this may perhaps be an error; you'd have thought Constantin would have mentioned it had it been deliberate. – Clifford Oct 30 '13 at 23:32
  • Definitely. Valid point about the deliberate compilation, although I still don't like that approach (something tells me that if it's needed, then *something, somewhere* is broken, not necessarily the programmer's fault, but still.) Thanks for adding that remark anyway, +1. –  Oct 30 '13 at 23:33
  • Since adding the `extern` would make it semantically identical in both C and C++, I'd suggest doing it in any case. But just to declare an interest, I develop embedded systems in C++ as a preference, so I will wave that particular flag. ;) – Clifford Oct 30 '13 at 23:37
  • No no, I mean, writing C++ code for embedded is perfectly fine of course. Rather, what I was referring to is mixing the two languages (and doing it in an erroneous manner, a la OP). –  Oct 30 '13 at 23:39
  • 2
    Yes, you were right! The flag '-W:c++:.c' caused the compiler to force C++ compilation and that's why the symbol wasn't in the object-file symbol table. After removing this flag, it works for me - and just adding ´extern´ (instead of removing the flag) works also. Thank you! – Constantin Oct 31 '13 at 07:07
  • @Constantin: You are welcome, and well done for including the compiler command line - that was critical. – Clifford Oct 31 '13 at 09:34