Bug 54482 - failures in static linking with libstdc++, due to versioned symbols
Summary: failures in static linking with libstdc++, due to versioned symbols
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 4.8.0
: P3 normal
Target Milestone: 4.7.3
Assignee: Ollie Wild
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-09-04 16:51 UTC by Simon Baldwin
Modified: 2014-05-21 13:35 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail: 4.7.2
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Simon Baldwin 2012-09-04 16:51:43 UTC
Libstdc++ uses '#ifdef PIC' as a proxy for deciding when to include versioned symbols.

However, libtool will set -DPIC if -fPIC, even if the code being built is not destined for a shared library.  This leads to versioned symbols being compiled into libstdc++.a, and the resulting static libstdc++ can then fail to link.  Can be triggered by 'configure --with-pic=yes ...' recommended by __cxxabiv1::__forced_unwind.

See also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=28811#c19

Example, using current 4.8 head at r190920:

$ cat /tmp/hello-world.cc
#include <iostream>
void func() {
  std::cout << "Hello, world" << std::endl;
}

$ configure --disable-bootstrap --enable-languages=c,c++ --build=x86_64-unknown-linux-gnu --host=x86_64-unknown-linux-gnu --target=x86_64-unknown-linux-gnu
$ make..., make install...
g++ -shared -fPIC -static-libstdc++ -Wl,-whole-archive -o /dev/null /tmp/hello-world.cc
/usr/bin/ld: /usr/local/google/home/simonb/install_clean/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.8.0/../../../../lib64/libstdc++.a(compatibility.o): relocation R_X86_64_32 against `_ZTIN10__cxxabiv115__forced_unwindE' can not be used when making a shared object; recompile with -fPIC

$ configure --with-pic=yes --disable-bootstrap --enable-languages=c,c++ --build=x86_64-unknown-linux-gnu --host=x86_64-unknown-linux-gnu --target=x86_64-unknown-linux-gnu
$ make..., make install...
$ ../install/bin/g++ -shared -fPIC -static-libstdc++ -Wl,-whole-archive -o /dev/null /tmp/hello-world.cc
/usr/bin/ld: /dev/null: version node not found for symbol _ZNKSt14basic_ifstreamIcSt11char_traitsIcEE7is_openEv@GLIBCXX_3.4
Comment 1 Ollie Wild 2012-09-06 14:52:23 UTC
The best solution I could come up with was to patch libtool to enable passing options destined for only the shared or static library builds.  See http://gcc.gnu.org/ml/gcc-patches/2012-09/msg00340.html for the temporary workaround I've applied to the google/* branches.

Getting this submitted to trunk is going to be a roundabout process.  I need to patch libtool, import an updated libtool to gcc (last one was in 2009), and convert libstdc++ to use a macro other than PIC for identifying that it's being compiled as part of a shared library.

If other people have better ideas, I'm all ears.
Comment 2 Benjamin Kosnik 2012-09-12 03:26:23 UTC
FYI this bug is a duplicate of 28811. The summary/diagnosis is wrong. It's not about versioned symbols, at least not in 4.7.x and above (after fix of 52689).

The issue is that even for all libstdc++ sources that are destined for the static library, ie libstdc++.a, compile flags should include -fPIC or equivalent, so that -static-libstdc++ works.

These files are not compiled this way at the moment.

So, compat*.o files need to be compiled with -prefer-pic.

But, using that means that the delicate balance of the non-convenience library files in src, ie compat*.cc files is disturbed.

At the moment, compat*.cc files are special, and have have code suitable for static and shared libs, and some code intended only for shared libs. Right now, the compile-time macro to designate these shared-only sections is PIC.

But, using libtool's -prefer-pic for the compat*.cc files means -fPIC -DPIC, which messes up static/shared code paths. So, one solution may be to use -prefer-pic when using libtool to create all object files, but to use another macro, say _GLIBCXX_SHARED when compiling only shared code.

(Another solution is to make yet-another convenience libary, that is only shared, and manually separate the source file dependencies. Let's try not to do it this way.)

So, what is desired is a compile-time hook or flag into libtool that deals with just the static or just the shared compiled objects. There are currently configure-time hooks for this (--enable-shared/-static, etc).

One "hook"  is to create an override for libtool's pic_flag variable, using CXX_pic_flag, that is special for libstdc++. 

ie, from the generated libtool:

from:
pic_flag=" -fPIC -DPIC"

to:
pic_flag="-D_GLIBCXX_SHARED  -fPIC -DPIC"

Sadly, I cannot figure out the correct way to do this, perhaps Ralf can help me.

In the meantime:

A hacky way to do this in configure.ac:

# Use _GLIBCXX_SHARED as a compile-time switch just for libstdc++ to designate
# a shared-only codepath.
AC_CONFIG_COMMANDS([libtool-pic-patch],
[echo "config.status: patching libtool's pic_flag with -D_GLIBCXX_SHARED";
 sed < libtool > libtool.tmp 's/^pic_flag="/pic_flag="-D_GLIBCXX_SHARED /';
 mv libtool.tmp libtool;
 chmod 775 libtool;
])
Comment 3 Ollie Wild 2012-09-12 04:58:29 UTC
Note, however, that simply changing pic_flag to

  pic_flag="-D_GLIBCXX_SHARED  -fPIC -DPIC"

is insufficient.  It suffers from the same issue as the original problem, namely that, when configured with --with-pic, pic_flag is passed even when compiling objects for libstdc++.a.  Since your solution passes -DPIC and -D_GLIBCXX_SHARED in tandem, keying off the new macro suffers from the same limitations as the old one.

See my previous comment.  In particular, the link there points to a more detailed analysis, as well as a patch which outlines the basics of what I think needs to change.  As you correctly suggest, we need a mechanism to pass flags based on whether we're compiling for a static or shared library independently of whether or not -fPIC is used.  The aforementioned patch does that in our branch, but that will need to be cleaned up and submitted to upstream libtool before incorporating it in GCC trunk.
Comment 4 Benjamin Kosnik 2012-09-20 02:10:32 UTC
Author: bkoz
Date: Thu Sep 20 02:10:22 2012
New Revision: 191509

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=191509
Log:
2012-09-18  Benjamin Kosnik  <bkoz@redhat.com>

        PR libstdc++/28811
        PR libstdc++/54482
        * configure.ac (glibcxx_lt_pic_flag,
          glibcxx_compiler_pic_flag,
          glibcxx_compiler_shared_flag): New. Use them.
        (lt_prog_compiler_pic_CXX): Set via glibcxx_*_flag(s) above.
        (pic_mode): Set to default.
        (PIC_CXXFLAGS): Remove.
        * Makefile.am (PICFLAG, PICFLAG_FOR_TARGET): Remove. Comment.
        * libsupc++/Makefile.am: Use glibcxx_ld_pic_flag and
          glibcxx_compiler_shared_flag. Comment.
        * src/c++11/Makefile.am: Same.
        * src/c++98/Makefile.am: Same.
        * src/Makefile.am: Use glibcxx_compiler_pic_flag.

        * Makefile.in: Regenerated.
        * aclocal.m4: Same.
        * configure: Same.
        * doc/Makefile.in: Same.
        * include/Makefile.in: Same.
        * libsupc++/Makefile.in: Same.
        * po/Makefile.in: Same.
        * python/Makefile.in: Same.
        * src/Makefile.in: Same.
        * src/c++11/Makefile.in: Same.
        * src/c++98/Makefile.in: Same.
        * testsuite/Makefile.in: Same.

        * src/c++11/compatibility-atomic-c++0x.cc: Use
          _GLIBCXX_SHARED instead of PIC to designate shared-only
          code blocks.
        * src/c++11/compatibility-c++0x.cc: Same.
        * src/c++11/compatibility-thread-c++0x.cc: Same.
        * src/c++98/compatibility-list-2.cc: Same.
        * src/c++98/compatibility.cc: : Same.

        * testsuite/17_intro/shared_with_static_deps.cc: New.

        * doc/xml/manual/build_hacking.xml: Separate configure from
        make/build issues, add build details.

Added:
    trunk/libstdc++-v3/testsuite/17_intro/shared_with_static_deps.cc
Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/Makefile.am
    trunk/libstdc++-v3/Makefile.in
    trunk/libstdc++-v3/aclocal.m4
    trunk/libstdc++-v3/configure
    trunk/libstdc++-v3/configure.ac
    trunk/libstdc++-v3/doc/Makefile.in
    trunk/libstdc++-v3/doc/xml/manual/build_hacking.xml
    trunk/libstdc++-v3/include/Makefile.in
    trunk/libstdc++-v3/libsupc++/Makefile.am
    trunk/libstdc++-v3/libsupc++/Makefile.in
    trunk/libstdc++-v3/po/Makefile.in
    trunk/libstdc++-v3/python/Makefile.in
    trunk/libstdc++-v3/src/Makefile.am
    trunk/libstdc++-v3/src/Makefile.in
    trunk/libstdc++-v3/src/c++11/Makefile.am
    trunk/libstdc++-v3/src/c++11/Makefile.in
    trunk/libstdc++-v3/src/c++11/compatibility-atomic-c++0x.cc
    trunk/libstdc++-v3/src/c++11/compatibility-c++0x.cc
    trunk/libstdc++-v3/src/c++11/compatibility-thread-c++0x.cc
    trunk/libstdc++-v3/src/c++98/Makefile.am
    trunk/libstdc++-v3/src/c++98/Makefile.in
    trunk/libstdc++-v3/src/c++98/compatibility-list-2.cc
    trunk/libstdc++-v3/src/c++98/compatibility.cc
    trunk/libstdc++-v3/testsuite/Makefile.in
Comment 5 Benjamin Kosnik 2012-11-05 23:42:36 UTC
Author: bkoz
Date: Mon Nov  5 23:42:32 2012
New Revision: 193195

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=193195
Log:
2012-11-05  Benjamin Kosnik  <bkoz@redhat.com>

        PR libstdc++/28811
        PR libstdc++/54482
        * configure.ac (glibcxx_lt_pic_flag,
          glibcxx_compiler_pic_flag,
          glibcxx_compiler_shared_flag): New. Use them.
        (lt_prog_compiler_pic_CXX): Set via glibcxx_*_flag(s) above.
        (pic_mode): Set to default.
        (PIC_CXXFLAGS): Remove.
        * Makefile.am (PICFLAG, PICFLAG_FOR_TARGET): Remove. Comment.
        * libsupc++/Makefile.am: Use glibcxx_ld_pic_flag and
          glibcxx_compiler_shared_flag. Comment.
        * src/c++11/Makefile.am: Same.
        * src/c++98/Makefile.am: Same.
        * src/Makefile.am: Use glibcxx_compiler_pic_flag.

        * Makefile.in: Regenerated.
        * aclocal.m4: Same.
        * configure: Same.
        * doc/Makefile.in: Same.
        * include/Makefile.in: Same.
        * libsupc++/Makefile.in: Same.
        * po/Makefile.in: Same.
        * python/Makefile.in: Same.
        * src/Makefile.in: Same.
        * src/c++11/Makefile.in: Same.
        * src/c++98/Makefile.in: Same.
        * testsuite/Makefile.in: Same.

        * src/c++11/compatibility-atomic-c++0x.cc: Use
          _GLIBCXX_SHARED instead of PIC to designate shared-only
          code blocks.
        * src/c++11/compatibility-c++0x.cc: Same.
        * src/c++11/compatibility-thread-c++0x.cc: Same.
        * src/c++98/compatibility-list-2.cc: Same.
        * src/c++98/compatibility.cc: : Same.

        * testsuite/17_intro/shared_with_static_deps.cc: New.

        * doc/xml/manual/build_hacking.xml: Separate configure from
        make/build issues, add build details.


Added:
    branches/gcc-4_7-branch/libstdc++-v3/testsuite/17_intro/shared_with_static_deps.cc
Modified:
    branches/gcc-4_7-branch/libstdc++-v3/ChangeLog
    branches/gcc-4_7-branch/libstdc++-v3/Makefile.am
    branches/gcc-4_7-branch/libstdc++-v3/Makefile.in
    branches/gcc-4_7-branch/libstdc++-v3/configure
    branches/gcc-4_7-branch/libstdc++-v3/configure.ac
    branches/gcc-4_7-branch/libstdc++-v3/doc/Makefile.in
    branches/gcc-4_7-branch/libstdc++-v3/doc/xml/manual/build_hacking.xml
    branches/gcc-4_7-branch/libstdc++-v3/include/Makefile.in
    branches/gcc-4_7-branch/libstdc++-v3/libsupc++/Makefile.am
    branches/gcc-4_7-branch/libstdc++-v3/libsupc++/Makefile.in
    branches/gcc-4_7-branch/libstdc++-v3/po/Makefile.in
    branches/gcc-4_7-branch/libstdc++-v3/python/Makefile.in
    branches/gcc-4_7-branch/libstdc++-v3/src/Makefile.am
    branches/gcc-4_7-branch/libstdc++-v3/src/Makefile.in
    branches/gcc-4_7-branch/libstdc++-v3/src/c++11/Makefile.am
    branches/gcc-4_7-branch/libstdc++-v3/src/c++11/Makefile.in
    branches/gcc-4_7-branch/libstdc++-v3/src/c++11/compatibility-atomic-c++0x.cc
    branches/gcc-4_7-branch/libstdc++-v3/src/c++11/compatibility-c++0x.cc
    branches/gcc-4_7-branch/libstdc++-v3/src/c++11/compatibility-thread-c++0x.cc
    branches/gcc-4_7-branch/libstdc++-v3/src/c++98/Makefile.am
    branches/gcc-4_7-branch/libstdc++-v3/src/c++98/Makefile.in
    branches/gcc-4_7-branch/libstdc++-v3/src/c++98/compatibility-list-2.cc
    branches/gcc-4_7-branch/libstdc++-v3/src/c++98/compatibility.cc
    branches/gcc-4_7-branch/libstdc++-v3/testsuite/Makefile.in
Comment 6 Jonathan Wakely 2014-05-21 13:35:45 UTC
(In reply to Simon Baldwin from comment #0)
> $ configure --disable-bootstrap --enable-languages=c,c++
> --build=x86_64-unknown-linux-gnu --host=x86_64-unknown-linux-gnu
> --target=x86_64-unknown-linux-gnu
> $ make..., make install...
> g++ -shared -fPIC -static-libstdc++ -Wl,-whole-archive -o /dev/null
> /tmp/hello-world.cc
> /usr/bin/ld:
> /usr/local/google/home/simonb/install_clean/bin/../lib/gcc/x86_64-unknown-
> linux-gnu/4.8.0/../../../../lib64/libstdc++.a(compatibility.o): relocation
> R_X86_64_32 against `_ZTIN10__cxxabiv115__forced_unwindE' can not be used
> when making a shared object; recompile with -fPIC

This error no longer happens with 4.7.3 due to Benjamin's fix

> $ configure --with-pic=yes --disable-bootstrap --enable-languages=c,c++
> --build=x86_64-unknown-linux-gnu --host=x86_64-unknown-linux-gnu
> --target=x86_64-unknown-linux-gnu
> $ make..., make install...
> $ ../install/bin/g++ -shared -fPIC -static-libstdc++ -Wl,-whole-archive -o
> /dev/null /tmp/hello-world.cc
> /usr/bin/ld: /dev/null: version node not found for symbol
> _ZNKSt14basic_ifstreamIcSt11char_traitsIcEE7is_openEv@GLIBCXX_3.4

--with-pic is no longer necessary, but if you do use it this error doesn't happen with 4.7.3

So I'm marking this fixed.