As described in the PR, the 64-bit Solaris 10+/x86 libc contains an implementation of those _Unwind_* functions required by the AMD64 ABI, i.e. those contained in libgcc_s.so.1 at version GCC_3.0.
If by some circumstance (use of -Bdirect, -z lazyload, maybe others) libc.so.1 happens to be searched by ld.so.1 before libgcc_s.so.1 and some library (e.g. libstdc++.so.6) uses functions both from GCC_3.0 (then resolved from libc.so.1) and others (resolved from libgcc_s.so.1), crashes result due to mixing those different implementations with different internal data structures. To avoid this, I suggest linking libgcc_s.so.1 with a mapfile that enforces direct binding to the libgcc_s.so.1 implementation to avoid that mixture. The following patch does just that. Initially, I tried to only use the mapfile when -lgcc_s is used, but libtool often links shared objects with -shared -nostdlib, adding -lgcc_s -lc -lgcc_s itself (for whatever reason it deems appropriate to second-guess the compiler driver here). Therefore I'm keying the mapfile use off -shared resp. -shared-libgcc instead. Unfortunately, the patch needs a change to the bundled ltmain.sh: by default, libtool `optimizes' -lgcc_s -lc -lgcc_s into -lc -lgcc_s. Combined with direct binding, this lead to exactly the failure the patch intends to avoid. The libtool bug has already been reported and a patch proposed: http://lists.gnu.org/archive/html/libtool-patches/2014-01/msg00005.html The patch has been tested on i386-pc-solaris2.{9,10,11} and sparc-sun-solaris2.{9,10,11} with Sun as/ld and on i386-pc-solaris2.10 with Sun as/GNU ld. I don't need approval for the Solaris specific parts, but another pair of eyes would certainly be helpful. One potential issue would be a version of gcc containing the patch used with a libtool without the change. The last libtool release was almost two years ago, so this is quite a likely condition. Fortunately, problems would only ensure if some 64-bit Solaris/x86 program/library uses the gcc extensions to the AMD64 unwinder. According to a code search, uses of those functions are very rare outside of gcc, and the problem can be worked around by invoking libtool with --preserve-dup-deps, so I consider this risk acceptable. Rainer 2014-01-14 Rainer Orth <r...@cebitec.uni-bielefeld.de> gcc: PR target/59788 * config/sol2.h (LINK_LIBGCC_MAPFILE_SPEC): Define. (LINK_SPEC): Use it for -shared, -shared-libgcc. libgcc: PR target/59788 * config/t-slibgcc-sld (libgcc-unwind.map): New target. (install-libgcc-unwind-map-forbuild): New target. (all): Depend on install-libgcc-unwind-map-forbuild. (install-libgcc-unwind-map): New target. (install): Depend on install-libgcc-unwind-map. gcc/testsuite: PR target/59788 * g++.dg/eh/unwind-direct.C: New test. libgo: PR target/59788 * config/ltmain.sh (opt_duplicate_compiler_generated_deps): Enable on *solaris2*. toplevel: PR target/59788 * ltmain.sh (opt_duplicate_compiler_generated_deps): Enable on *solaris2*.
# HG changeset patch # Parent a6e6484e3cdf3a53d0e325f3faf34e291f8469fb Ensure libgcc_s unwinder is always used on 64-bit Solaris 10+/x86 (PR target/59788) diff --git a/gcc/config/sol2.h b/gcc/config/sol2.h --- a/gcc/config/sol2.h +++ b/gcc/config/sol2.h @@ -174,12 +174,21 @@ along with GCC; see the file COPYING3. #define RDYNAMIC_SPEC "--export-dynamic" #endif +#ifndef USE_GLD +/* With Sun ld, use mapfile to enforce direct binding to libgcc_s unwinder. */ +#define LINK_LIBGCC_MAPFILE_SPEC \ + "%{shared|shared-libgcc:-M %slibgcc-unwind.map}" +#else +/* GNU ld doesn't support direct binding. */ +#define LINK_LIBGCC_MAPFILE_SPEC "" +#endif + #undef LINK_SPEC #define LINK_SPEC \ "%{h*} %{v:-V} \ %{!shared:%{!static:%{rdynamic: " RDYNAMIC_SPEC "}}} \ %{static:-dn -Bstatic} \ - %{shared:-G -dy %{!mimpure-text:-z text}} \ + %{shared:-G -dy %{!mimpure-text:-z text}} " LINK_LIBGCC_MAPFILE_SPEC " \ %{symbolic:-Bsymbolic -G -dy -z text} \ %(link_arch) \ %{Qy:} %{!Qn:-Qy}" diff --git a/gcc/testsuite/g++.dg/eh/unwind-direct.C b/gcc/testsuite/g++.dg/eh/unwind-direct.C new file mode 100644 --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/unwind-direct.C @@ -0,0 +1,15 @@ +// PR target/59788 +// { dg-do run { target { *-*-solaris2* && { ! gld } } } } +// { dg-options "-Wl,-Bdirect" } + +#include <stdexcept> + +int +main(void) +{ + try + { throw std::runtime_error( "Catch me if you can!"); } + catch(...) + { return 0; } + return 1; +} diff --git a/libgcc/config/t-slibgcc-sld b/libgcc/config/t-slibgcc-sld --- a/libgcc/config/t-slibgcc-sld +++ b/libgcc/config/t-slibgcc-sld @@ -3,3 +3,26 @@ SHLIB_LDFLAGS = -Wl,-h,$(SHLIB_SONAME) -Wl,-z,text -Wl,-z,defs \ -Wl,-M,$(SHLIB_MAP) + +# Linker mapfile to enforce direct binding to libgcc_s unwinder +# (PR target/59788). +libgcc-unwind.map: libgcc-std.ver + @(echo "{"; \ + for f in `grep _Unwind_ $< | sort`; do \ + echo " $$f = EXTERN DIRECT;"; \ + done; \ + echo "};" ) > $@ + +# Copy libgcc-unwind.map to the place where gcc will look for it at build-time. +install-libgcc-unwind-map-forbuild: libgcc-unwind.map + dest=$(gcc_objdir)/tmp$$$$-$<; \ + cp $< $$dest; \ + chmod a+r $$dest; \ + sh $(srcdir)/../move-if-change $$dest $(gcc_objdir)/$< + +all: install-libgcc-unwind-map-forbuild + +install-libgcc-unwind-map: libgcc-unwind.map + $(INSTALL_DATA) $< $(DESTDIR)$(slibdir) + +install: install-libgcc-unwind-map diff --git a/libgo/config/ltmain.sh b/libgo/config/ltmain.sh --- a/libgo/config/ltmain.sh +++ b/libgo/config/ltmain.sh @@ -976,7 +976,7 @@ func_enable_tag () case $host in - *cygwin* | *mingw* | *pw32* | *cegcc*) + *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* ) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; diff --git a/ltmain.sh b/ltmain.sh --- a/ltmain.sh +++ b/ltmain.sh @@ -976,7 +976,7 @@ func_enable_tag () case $host in - *cygwin* | *mingw* | *pw32* | *cegcc*) + *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* ) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;;
-- ----------------------------------------------------------------------------- Rainer Orth, Center for Biotechnology, Bielefeld University