When writing a linker script to control the versioning/exporting/unexporting of C++ symbols, the globbing provided in the linker script doesn't match some of the automatically-generated symbols by the C++ ABI. I have noticed that this applies to the vtable, the VTT, construction vtables, typeinfo, typeinfo names and all manners of thunks. Suppose the following code: $ cat a.cpp struct Padding { virtual ~Padding() {} }; struct PublicA { virtual ~PublicA(); virtual PublicA *a(); }; struct PublicB: Padding, PublicA { virtual PublicB *a(); }; struct PublicC: virtual PublicA { virtual PublicC *a(); }; PublicA::~PublicA() { } PublicA *PublicA::a() { return 0; } PublicB *PublicB::a() { return 0; } PublicC *PublicC::a() { return 0; } If we compile it into a shared library: $ g++ -shared -o a.so a.cpp The dynamic symbol table will be like this: $ paste <(nm -D --defined a.so) <(nm -DC --defined a.so | cut -b11-) | grep Public 00000cee T _ZN7PublicA1aEv PublicA::a() 00000cc8 T _ZN7PublicAD0Ev PublicA::~PublicA() 00000ca2 T _ZN7PublicAD1Ev PublicA::~PublicA() 00000c7c T _ZN7PublicAD2Ev PublicA::~PublicA() 00000d00 T _ZN7PublicB1aEv PublicB::a() 00000ef0 W _ZN7PublicBD0Ev PublicB::~PublicB() 00000ea0 W _ZN7PublicBD1Ev PublicB::~PublicB() 00000d1a T _ZN7PublicC1aEv PublicC::a() 00000e4c W _ZN7PublicCD0Ev PublicC::~PublicC() 00000df0 W _ZN7PublicCD1Ev PublicC::~PublicC() 0000108c V _ZTI7PublicA typeinfo for PublicA 00001060 V _ZTI7PublicB typeinfo for PublicB 00001030 V _ZTI7PublicC typeinfo for PublicC 00001094 V _ZTS7PublicA typeinfo name for PublicA 00001080 V _ZTS7PublicB typeinfo name for PublicB 00001048 V _ZTS7PublicC typeinfo name for PublicC 00000fc8 V _ZTT7PublicC VTT for PublicC 00001008 V _ZTV7PublicA vtable for PublicA 00000fe0 V _ZTV7PublicB vtable for PublicB 00000fa0 V _ZTV7PublicC vtable for PublicC 00000d4d T _ZTch0_h4_N7PublicB1aEv covariant return thunk to PublicB::a() 00000d24 T _ZTch0_v0_n20_N7PublicC1aEv covariant return thunk to PublicC::a() 00000cf8 T _ZTchn4_h4_N7PublicB1aEv covariant return thunk to PublicB::a() 00000d0a T _ZTcv0_n16_v0_n20_N7PublicC1aEv covariant return thunk to PublicC::a() 00000ee8 W _ZThn4_N7PublicBD0Ev non-virtual thunk to PublicB::~PublicB() 00000e98 W _ZThn4_N7PublicBD1Ev non-virtual thunk to PublicB::~PublicB() 00000e3c W _ZTv0_n12_N7PublicCD0Ev virtual thunk to PublicC::~PublicC() 00000de0 W _ZTv0_n12_N7PublicCD1Ev virtual thunk to PublicC::~PublicC() Now suppose we use a linker script to hide the internal symbols in our library, but export only those that we want to: $ cat a.script VERSION { { global: extern "C++" { Public*; }; local: *; }; } If we compile it: $ g++ -shared -o a.so a.cpp a.script The symbol table is: $ paste <(nm -D --defined a.so) <(nm -DC --defined a.so | cut -b11-) | grep Public 000007fe T _ZN7PublicA1aEv PublicA::a() 000007d8 T _ZN7PublicAD0Ev PublicA::~PublicA() 000007b2 T _ZN7PublicAD1Ev PublicA::~PublicA() 0000078c T _ZN7PublicAD2Ev PublicA::~PublicA() 00000810 T _ZN7PublicB1aEv PublicB::a() 00000a00 W _ZN7PublicBD0Ev PublicB::~PublicB() 000009b0 W _ZN7PublicBD1Ev PublicB::~PublicB() 0000082a T _ZN7PublicC1aEv PublicC::a() 0000095c W _ZN7PublicCD0Ev PublicC::~PublicC() 00000900 W _ZN7PublicCD1Ev PublicC::~PublicC() To export those symbols, I am forced to know of their existence and the mangling that they acquire. And it's not possible to match them effectively with simple globbing (regexp would be necessary at least). And note that spaces in symbol names are also not possible to match without wildcards in the linker scripts, which makes it impossible to match " for Public*" reliably. One way I can think of to solve this problem would be to change the demangling (the pretty name) of those symbols to place the class name leftmost. For example: 0000108c V _ZTI7PublicA PublicA::.typeinfo 00001060 V _ZTI7PublicB PublicB::.typeinfo 00001030 V _ZTI7PublicC PublicC::.typeinfo 00001094 V _ZTS7PublicA PublicA::.typeinfo name 00001080 V _ZTS7PublicB PublicB::.typeinfo name 00001048 V _ZTS7PublicC PublicC::.typeinfo name 00000fc8 V _ZTT7PublicC PublicC::.VTT 00001008 V _ZTV7PublicA PublicA::.vtable 00000fe0 V _ZTV7PublicB PublicB::.vtable 00000fa0 V _ZTV7PublicC PublicC::.vtable 00000d4d T _ZTch0_h4_N7PublicB1aEv PublicB::a() [covariant return thunk] 00000d24 T _ZTch0_v0_n20_N7PublicC1aEv PublicC::a() [covariant return thunk] 00000cf8 T _ZTchn4_h4_N7PublicB1aEv PublicB::a() [covariant return thunk] 00000d0a T _ZTcv0_n16_v0_n20_N7PublicC1aEv PublicC::a() [covariant return thunk] 00000ee8 W _ZThn4_N7PublicBD0Ev PublicB::~PublicB() [non-virtual thunk] 00000e98 W _ZThn4_N7PublicBD1Ev PublicB::~PublicB() [non-virtual thunk] 00000e3c W _ZTv0_n12_N7PublicCD0Ev PublicC::~PublicC() [virtual thunk] 00000de0 W _ZTv0_n12_N7PublicCD1Ev PublicC::~PublicC() [virtual thunk] (For the thunks, it may be a good idea to match to the base encoding, so that exporting "PublicC::a()" exports all thunks associated with it)
Anything? It's nearly impossible to write proper export whitelists in C++ with this bug.
I like your proposed change, but you are asking for a change to libiberty, specifically cp-demangle.c:c_print_comp. This has the potential to affect more than just ld. For instance, I know that the gcc testsuite would need adjusting if this change was made unconditionally. I suggest that you raise this issue on gcc@gcc.gnu.org, preferably supplying a libiberty patch, to gain the attention of c++ and libiberty maintainers. You're probably not going to get any traction on this problem otherwise.
we've seen people ask for this in other places too (and i noticed because i wanted this behavior myself just now) http://www.cygwin.com/ml/binutils/2007-07/msg00402.html