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;

Reply via email to