[cfe-dev] GCC and Clang produce undefined references to functions with vague linkage
Rafael EspĂndola
rafael.espindola at gmail.com
Thu Jun 28 11:13:47 PDT 2012
Note1: I am not subscribed to the gcc list, please use reply-all.
Note2: I think the clang list is moderated for the first post, but it
is usually really fast. Sorry about that.
I recently implemented an optimization in LLVM to hide symbols that
the we "know" are available in every DSO that uses them. This is very
similar to a more generic optimization that is possible during LTO
when using recent versions of the gold plugin.
Unfortunately, this found a bug in both gcc and clang (or in the
itanium ABI, it is not very clear). The testcase is
$ cat test.h
struct foo {
virtual ~foo();
};
struct bar : public foo {
virtual void zed();
};
$ cat def.cpp
#include "test.h"
void bar::zed() {
}
$ cat undef.cpp
#include "test.h"
void f() {
foo *x(new bar);
delete x;
}
Both gcc (>= 4.6) and clang will produce and undefined reference to
_ZN3barD0Ev when compiling undef.cpp with optimizations:
$ ~/gcc/build/gcc/xgcc -B ~/gcc/build/gcc/ -c undef.cpp -o undef.o -O3 -fPIC
$ nm undef.o | grep D0
U _ZN3barD0Ev
And, when using LTO, a shared library built from def.cpp has a visible
vtable, but the destructor itself is not visible:
$ ~/gcc/build/gcc/xgcc -B ~/gcc/build/gcc/ -c def.cpp -o def.o -O3 -flto -fPIC
$ ~/gcc/build/gcc/xgcc -B ~/gcc/build/gcc/ def.o -o def.so -shared
-fuse-linker-plugin
$ readelf -sDW def.so | grep bar
12 7: 0000000000000931 5 OBJECT WEAK DEFAULT 13 _ZTS3bar
11 10: 0000000000001ca0 40 OBJECT WEAK DEFAULT 24 _ZTV3bar
13 14: 0000000000001cd0 24 OBJECT WEAK DEFAULT 24 _ZTI3bar
8 15: 00000000000008b0 10 FUNC GLOBAL DEFAULT 11 _ZN3bar3zedEv
And the final result is that we get an undefined reference when linking:
$ g++ -shared -o foo.so undef.o def.so -Wl,-z,defs
undef.o:undef.cpp:function f(): error: undefined reference to 'bar::~bar()'
I can see two ways of solving this and would like for both clang and
gcc to implement the same:
* Make sure the destructor is emitted everywhere. That is, clang and
gcc have a bug in producing an undefined reference to _ZN3barD0Ev.
* Make it clear that the file exporting the vtable has to export the
symbols used in it. That is, the Itanium c++ abi needs clarification
and so does gcc's lto plugin (and the llvm patch I am working on).
In an earlier discussion on the llvm list, it was pointed out that
* The second solution would probably be the most backward compatible
one, as gcc (even without lto) has been producing the undefined symbol
since 4.6.
* If implementing the second solution, the destructor still has to be
a weak symbol on OS X at least.
* The first solution has the advantage that it is semantically simpler
as it avoids a special case about when a function can be assumed to be
available externally.
* The first solution has the advantage that more symbols can be marked
hidden, as the gcc lto plugin does currently.
Cheers,
Rafael
More information about the cfe-dev
mailing list