While investigating PR bootstrap/84017, it turned out that it *is* possible to enable COMDAT group support on Solaris 10 with Solaris ld in some circumstances. I'm posting my findings and the resulting patch here for reference only; this is certainly not GCC 8 material.
Besides, there's a abi_check failure in libstdc++ which makes it unclear if this desirable at all. So here's the deal: I remembered that Solaris ld has a -z relaxreloc option, documented as -z relaxreloc ld normally issues a fatal error upon encountering a relocation using a symbol that references an eliminated COMDAT section. If -z relaxreloc is enabled, ld instead redirects such relocations to the equivalent symbol in the COMDAT section that was kept. -z relaxreloc is a specialized option, mainly of interest to compiler authors, and is not intended for general use. It was only introduced in Solaris 10 Update 10, so won't help on earlier versions. When ld supports that option, I always pass it when linking and enable comdat_group (and hidden_linkonce) in configure.ac. Test results are astonishingly good: * On Solaris 10/x86, I get three tests where ld SEGVs with -flto (skipped/xfailed in the present patch). * On both Solaris 10/SPARC and x86, libstdc++-abi/abi_check FAILs: # of added symbols: 2 # of missing symbols: 0 # of undesignated symbols: 0 # of incompatible symbols: 2 2 added symbols 0 _ZNSt7__cxx1115basic_stringbufIwSt11char_traitsIwESaIwEED2Ev std::__cxx11::basic_stringbuf<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >::~basic_stringbuf() version status: incompatible GLIBCXX_3.4.21 type: function status: added 1 _ZNSt7__cxx1115basic_stringbufIcSt11char_traitsIcESaIcEED2Ev std::__cxx11::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::~basic_stringbuf() version status: incompatible GLIBCXX_3.4.21 type: function status: added 2 incompatible symbols 0 _ZNSt7__cxx1115basic_stringbufIwSt11char_traitsIwESaIwEED2Ev std::__cxx11::basic_stringbuf<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >::~basic_stringbuf() version status: incompatible GLIBCXX_3.4.21 type: function status: added 1 _ZNSt7__cxx1115basic_stringbufIcSt11char_traitsIcESaIcEED2Ev std::__cxx11::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::~basic_stringbuf() version status: incompatible GLIBCXX_3.4.21 type: function status: added Those symbols are present in the Solaris 11 baselines (where COMDAT group always works), which is also used with Solaris 10 and GNU ld. I'm not yet sure how to deal with this: we'd have to introduce 3 baselines: * Solaris 10 without COMDAT group support * Solaris 10 with COMDAT group support * Solaris 11 Seems like a lot of trouble to me actually. I've not done anything about this yet, so as is the patch shows the abi_check failures. Rainer -- ----------------------------------------------------------------------------- Rainer Orth, Center for Biotechnology, Bielefeld University 2018-01-28 Rainer Orth <r...@cebitec.uni-bielefeld.de> gcc/testsuite: * g++.dg/lto/pr65475c_0.C: Skip on Solaris 10/x86 with ld/comdat. * g++.dg/lto/pr68057_0.C: Likewise. * gcc.dg/debug/pr41893-1.c: Xfail on Solaris 10/x86 with ld/comdat for -gdwarf-2 -g3. gcc: * configure.ac (gcc_cv_ld_relaxreloc): New test. (comdat_group): Enable on Solaris 10 if ld -z relaxreloc is present. (hidden_linkonce): Enable on Solaris 10 if COMDAT group support is present. * configure: Regenerate. * config.in: Regenerate. * config/sol2.h (LINK_RELAXRELOC_SPEC): Define. (LINK_SPEC): Use it.
# HG changeset patch # Parent a2aa0e644c08a13add93210418e981320cac0513 Enable comdat on Solaris 10 diff --git a/gcc/config/sol2.h b/gcc/config/sol2.h --- a/gcc/config/sol2.h +++ b/gcc/config/sol2.h @@ -379,13 +379,20 @@ along with GCC; see the file COPYING3. #define LINK_CLEARCAP_SPEC "" #endif +/* Relax linker COMDAT checks. Necessary to support COMDAT on Solaris 10. */ +#ifdef HAVE_LD_RELAXRELOC +#define LINK_RELAXRELOC_SPEC " -z relaxreloc" +#else +#define LINK_RELAXRELOC_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}} " \ - LINK_LIBGCC_MAPFILE_SPEC LINK_CLEARCAP_SPEC " \ + LINK_LIBGCC_MAPFILE_SPEC LINK_CLEARCAP_SPEC LINK_RELAXRELOC_SPEC " \ %{symbolic:-Bsymbolic -G -dy -z text} \ %(link_arch) \ %{Qy:} %{!Qn:-Qy}" diff --git a/gcc/configure.ac b/gcc/configure.ac --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -2971,6 +2971,25 @@ gcc_GAS_CHECK_FEATURE([stabs directive], [AC_DEFINE(HAVE_AS_STABS_DIRECTIVE, 1, [Define if your assembler supports .stabs.])]) +case "$target" in + # Solaris 10 Update 10 added ld support for relaxing COMDAT checks. The + # option later got renamed/generalized to -z relax=comdat. Only check on + # Solaris 10, though. It isn't needed/desirable on later Solaris releases. + *-*-solaris2.10*) + AC_MSG_CHECKING(linker -z relaxreloc option) + if $gcc_cv_ld -z help 2>&1 | grep relaxreloc > /dev/null; then + gcc_cv_ld_relaxreloc=yes + else + gcc_cv_ld_relaxreloc=no + fi + if test x"$gcc_cv_ld_relaxreloc" = xyes; then + AC_DEFINE(HAVE_LD_RELAXRELOC, 1, + [Define if your linker supports -z relaxreloc.]) + fi + AC_MSG_RESULT($gcc_cv_ld_relaxreloc) + ;; +esac + gcc_GAS_CHECK_FEATURE([COMDAT group support (GNU as)], gcc_cv_as_comdat_group, [elf,2,16,0], [--fatal-warnings], @@ -3040,11 +3059,20 @@ elif echo "$ld_ver" | grep GNU > /dev/nu else changequote(,)dnl case "${target}" in + *-*-solaris2.10*) + # On Solaris 10, the -z relaxreloc option allows to override some + # checks and make COMDAT group work. + if test x"$gcc_cv_ld_relaxreloc" = xyes; then + comdat_group=yes + else + comdat_group=no + fi + ;; *-*-solaris2.1[1-9]*) comdat_group=no # Sun ld has COMDAT group support since Solaris 9, but it doesn't - # interoperate with GNU as until Solaris 11 build 130, i.e. ld - # version 1.688. + # interoperate out of the box with GNU as until Solaris 11 build 130, + # i.e. ld version 1.688. # # If using Sun as for COMDAT group as emitted by GCC, one needs at # least ld version 1.2267. @@ -3085,15 +3113,20 @@ case "${target}" in if test $in_tree_ld = yes || echo "$ld_ver" | grep GNU > /dev/null; then hidden_linkonce=yes else + hidden_linkonce=no case "${target}" in + # When COMDAT group support is enabled on Solaris 10, hidden + # linkonce works, too. + *-*-solaris2.10*) + if x$comdat_group = xyes; then + hidden_linkonce=yes + fi + ;; # Full support for hidden thunks in linkonce sections only appeared in # Solaris 11/OpenSolaris. *-*-solaris2.1[[1-9]]*) hidden_linkonce=yes ;; - *) - hidden_linkonce=no - ;; esac fi AC_MSG_RESULT($hidden_linkonce) diff --git a/gcc/testsuite/g++.dg/lto/pr65475c_0.C b/gcc/testsuite/g++.dg/lto/pr65475c_0.C --- a/gcc/testsuite/g++.dg/lto/pr65475c_0.C +++ b/gcc/testsuite/g++.dg/lto/pr65475c_0.C @@ -1,6 +1,7 @@ /* { dg-lto-do link } */ /* { dg-extra-ld-options { -O2 -Wno-odr -r -nostdlib } } */ /* { dg-lto-options { "-O2 -w -Wno-return-type" } } */ +/* { dg-skip-if "Solaris 10/x86 ld SEGVs" { { i?86-*-solaris2.10* x86_64-*-solaris2.10* } && { comdat_group && { ! gld } } } } */ namespace std { diff --git a/gcc/testsuite/g++.dg/lto/pr68057_0.C b/gcc/testsuite/g++.dg/lto/pr68057_0.C --- a/gcc/testsuite/g++.dg/lto/pr68057_0.C +++ b/gcc/testsuite/g++.dg/lto/pr68057_0.C @@ -1,5 +1,6 @@ // { dg-lto-do link } /* { dg-extra-ld-options { -O2 -Wno-odr -r -nostdlib } } */ +/* { dg-skip-if "Solaris 10/x86 ld SEGVs" { { i?86-*-solaris2.10* x86_64-*-solaris2.10* } && { comdat_group && { ! gld } } } } */ struct SPxPricer; struct SoPlex { virtual void setPricer(SPxPricer *); diff --git a/gcc/testsuite/gcc.dg/debug/pr41893-1.c b/gcc/testsuite/gcc.dg/debug/pr41893-1.c --- a/gcc/testsuite/gcc.dg/debug/pr41893-1.c +++ b/gcc/testsuite/gcc.dg/debug/pr41893-1.c @@ -3,6 +3,7 @@ /* { dg-require-effective-target lto } */ /* { dg-options "-flto -fwhole-program -O" } */ /* { dg-additional-sources "pr41893-2.c" } */ +/* { dg-xfail-if "Solaris 10/x86 ld SEGVs" { { i?86-*-solaris2.10* x86_64-*-solaris2.10* } && { comdat_group && { ! gld } } } { "-gdwarf-2 -g3" } } */ struct S { int v; }; struct S s;