Bug 59879 - reducing symbol visibility of shared objects / static libstdc++
Summary: reducing symbol visibility of shared objects / static libstdc++
Status: RESOLVED FIXED
Alias: None
Product: Mesa
Classification: Unclassified
Component: Mesa core (show other bugs)
Version: unspecified
Hardware: x86-64 (AMD64) Linux (All)
: medium normal
Assignee: mesa-dev
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-01-26 01:29 UTC by Tobias Jakobi
Modified: 2014-12-26 19:32 UTC (History)
1 user (show)

See Also:
i915 platform:
i915 features:


Attachments

Description Tobias Jakobi 2013-01-26 01:29:59 UTC
Hello,

this is sort of cleaned up report of bug #37637.

To quickly summarize what happens there: Build r600g with the llvm compiler backend and try starting ut2003. Segfault happens since apparantly ut's engine has a version of libstdc++ built in, which now clashes with the libstdc++ shared lib which either r600_dri.so or LLVM (when build as shared) loads. This is independent of preloading order. When the symbols from the system libstdc++ take preference, then the game engine crashes. When the game engine symbols take preference, the r600g driver initialization crashes.

The fix for the problem: Since we can't modify the ut2003 binary, we have to hide the "duplicate" symbols somehow.

This means:
- build r600g with static llvm
- build r600 with static libstdc++
- only make those symbols in r600_dri.so visible which are necessary

Building r600g with static llvm is trivial. The symbol visibility can be properly handled by ld:
http://sourceware.org/binutils/docs-2.21/ld/VERSION.html#VERSION

My current dri-symbols.map:
{
  global: __dri*; dri*; _glapi*;
  local: *;
};

This hides everything except for the symbols matching __dri*, dri* and _glapi*. This can be potentially reduced even further. However it's not clear to me what the loader code in libGL really needs.

This version-script'ing can be properly put into autotools language:
http://www.gnu.org/software/gnulib/manual/html_node/LD-Version-Scripts.html

----------------------------


What I'm struggling with is properly telling autotools to build a shared lib with static libstdc++. The gcc manpage mentions an option called "-static-libstdc++", but it doesn't seem to have any effect.

Let's look at the critical calls (I've shortened them somewhat):

OK, we're in src/gallium/targets/dri-r600. The last libtool call that the Makefile executes is the following one:

bin/sh ../../../../libtool  --tag=CXX   --mode=link g++  -g -O2 -Wall -fno-strict-aliasing -fno-builtin-memcmp  -module -avoid-version -shared -no-undefined -Wl,--version-script=../../../../src/gallium/targets/dri-symbols.map -L/usr/lib64/llvm  -lpthread -lffi -ldl -lm   -o r600_dri.la -rpath /usr/local/lib/dri target.lo utils.lo dri_util.lo xmlconfig.lo <libtool files> -ldrm   -lexpat -lm -lrt -lpthread -ldl -ldrm   -ldrm_radeon   <llvm libs>


libtool itself produces this call from it:

g++ -fPIC -DPIC -shared -nostdlib <some object files> -Wl,--whole-archive <the archives> -Wl,--no-whole-archive  -L/usr/lib64/llvm <llvm libs part 1> -lexpat -lrt -lpthread -ldl -ldrm -ldrm_radeon <llvm libs part 2> -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.2 -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.2/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.2/../../../../x86_64-pc-linux-gnu/lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.2/../../.. -lstdc++ -lm -lc -lgcc_s <more object files> -O2 -Wl,--version-script=../../../../src/gallium/targets/dri-symbols.map -Wl,-soname -Wl,r600_dri.so -o .libs/r600_dri.so

Notice the "-lstdc++", dynamic linking to libstdc++. What I'd like libtool (and eventually autotools) to produce is the following:

g++ -fPIC -DPIC -shared -nostdlib <some object files> -Wl,-Bstatic -lstdc++ -Wl,-Bdynamic -Wl,--whole-archive <the archives> -Wl,--no-whole-archive  -L/usr/lib64/llvm <llvm libs part 1> -lexpat -lrt -lpthread -ldl -ldrm -ldrm_radeon <llvm libs part 2> -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.2 -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.2/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.2/../../../../x86_64-pc-linux-gnu/lib -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.2/../../.. -lm -lc -lgcc_s <more object files> -O2 -Wl,--version-script=../../../../src/gallium/targets/dri-symbols.map -Wl,-soname -Wl,r600_dri.so -o .libs/r600_dri.so

This is just removing "-lstdc++" and replacing it by "-Wl,-Bstatic -lstdc++ -Wl,-Bdynamic" at a different position (!). Putting it in front of the archive assembly seems to be critical.

This links fine (no warnings, etc.) and produces a .so that is loaded properly by libGL's loader and (more importantly) works fine with ut2003.

However it is still a mystery to me how to makes this clear to either libtool or autotools.

Greets,
Tobias
Comment 1 Jose Fonseca 2013-01-28 14:35:44 UTC
(In reply to comment #0)
> Hello,
> 
> this is sort of cleaned up report of bug #37637.
> 
> To quickly summarize what happens there: Build r600g with the llvm compiler
> backend and try starting ut2003. Segfault happens since apparantly ut's
> engine has a version of libstdc++ built in, which now clashes with the
> libstdc++ shared lib which either r600_dri.so or LLVM (when build as shared)
> loads. This is independent of preloading order. When the symbols from the
> system libstdc++ take preference, then the game engine crashes. When the
> game engine symbols take preference, the r600g driver initialization crashes.
> 
> The fix for the problem: Since we can't modify the ut2003 binary, we have to
> hide the "duplicate" symbols somehow.
> 
> This means:
> - build r600g with static llvm
> - build r600 with static libstdc++
[...]
> What I'm struggling with is properly telling autotools to build a shared lib with static libstdc++. The gcc manpage mentions an option called "-static-libstdc++", but it doesn't seem to have any effect.


AFAIK, -static-libstdc++ allows one to statically link libstdc++ to an _executable_, not to a dynamic library (as it lacks -fPIC).

I see two ways of achieving this:
- have our own custom build of libstdc++ where we build a static library of libstdc++.a with -fPIC.
- statically link (w/ -Bsymbolic) against stubs of libstdc++ symbols, where each stub does dlsym(dlopen('/usr/lib32/libstdc++.so.6', RTLD_LOCAL), "foo")

FWIW, either seem a lot of work just for sake of an old binary-only game.

The ideal would be for UT to rely on distro's libstdc++ instead of its own version...
Comment 2 Jose Fonseca 2013-01-28 14:36:16 UTC
Ignore the "lib32" above. I meant "lib"
Comment 3 Emil Velikov 2014-09-22 18:57:28 UTC
The issue here is that while -static-libstdc++ should work for both executables and libraries and gcc is smart enough to understand it, libtool is not :\

The latter essentially ignores the switch and always explicitly appends "-lstdc++". Thus even adding "-Wl,-Bstatic -lstdc++ -Wl,-Bdynamic" to our linker flags (inside the makefiles) will not work, as those come prior to "-lstdc++".

I fear that someone familiar with libtool will need to fix it... that or we can nuke the c++ code from mesa xD

Either way, at least the symbol visibility is resolved has been fixed with recent mesa :)
Comment 4 Tobias Jakobi 2014-12-26 19:32:24 UTC
Closing this since I no longer own a system where the AMD GPU relies on r600g. On my current radeonsi system the ut2003 issue doesn't appear, so I guess the visibility fixes mentioned by Emil have fixes this one as well.


Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.