Bug 10326 - globbing in linker script doesn't match C++ vtable/typeinfo/etc.
Summary: globbing in linker script doesn't match C++ vtable/typeinfo/etc.
Status: NEW
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.19
: P2 normal
Target Milestone: ---
Assignee: unassigned
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-06-24 13:27 UTC by Thiago Macieira
Modified: 2012-02-17 22:09 UTC (History)
3 users (show)

See Also:
Host: i586-manbo-linux-gnu
Target: i586-manbo-linux-gnu
Build: i586-manbo-linux-gnu
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Thiago Macieira 2009-06-24 13:27:54 UTC
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)
Comment 1 Thiago Macieira 2009-09-06 01:47:03 UTC
Anything? It's nearly impossible to write proper export whitelists in C++ with
this bug.
Comment 2 Alan Modra 2009-09-07 01:55:00 UTC
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.
Comment 3 Mike Frysinger 2012-02-17 22:09:19 UTC
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