diff mbox

[build] Support COMDAT group with Sun as (PR target/40483), final version

Message ID yddaaeizs0e.fsf@manam.CeBiTec.Uni-Bielefeld.DE
State New
Headers show

Commit Message

Rainer Orth May 19, 2011, 2:25 p.m. UTC
This patch had long been approved in the original thread

	[build, c++, lto] Support COMDAT group with Sun as (PR target/40483)
        http://gcc.gnu.org/ml/gcc-patches/2010-05/msg01365.html
        http://gcc.gnu.org/ml/gcc-patches/2010-06/msg00600.html

but installation had been stalled on what was originally believed to be
a Sun assembler bug, but ultimately turned out to be gas/gld lazyness.
This can e.g. be seen in

FAIL: g++.old-deja/g++.other/comdat5.C (test for excess errors)

ld: fatal: relocation error: R_386_GOTOFF: file comdat5-aux.o: section [11].rel.eh_frame: symbol .text._Z3fooi%_Z3fooi (section): symbol has been discarded with discarded section: [4].text._Z3fooi%_Z3fooi

The relocation in question is

Relocation Section:  .rel.eh_frame
    type                       offset             section / symbol
  R_386_GOTOFF                   0x20             .rel.eh_frame  .text._Z3fooi%_
Z3fooi (section)

The problem didn't show up when doing COMDAT with GNU as and Sun ld
because a couple of ld checks had already been relaxed to accomodate
gas.  After some discussion with the Sun assembler and linker
maintainers, it was decided to work around this in Sun ld instead and
relax a few checks there, too, to allow COMDAT with Sun as to work.  The
necessary support is included in ld 2.2267 (Solaris 11, build 164).

This allowed a couple of simplifications in gcc/configure.ac.  Besides,
I've augmented the messages for the various COMDAT group support
variants to clarify which one is detected.

Bootstrapped on i386-pc-solaris2.11 and sparc-sun-solaris2.11 (Sun as,
ld; GNU as, Sun ld) without regressions.  I've also bootstrapped on
x86_64-pc-linux-gnu (64-bit multilib only) to make sure the i386 changes
don't break that target.

Installed on mainline.

	Rainer


2010-03-07  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>

	PR target/40483
	* configure.ac (gcc_cv_as_comdat_group_group): Check for Sun as
	COMDAT group syntax, both SPARC and x86 variants.
	(HAVE_COMDAT_GROUP): Also define if gcc_cv_as_comdat_group_group.
	* configure: Regenerate.
	* config/sol2.h (TARGET_SOLARIS): Define.
	(PUSHSECTION_FORMAT): Remove.
	(SECTION_NAME_FORMAT): Define.
	* config/sol2.c: Include hashtab.h.
	(solaris_output_init_fini): Replace PUSHSECTION_FORMAT by its
	expansion, using SECTION_NAME_FORMAT.
	(solaris_comdat_htab): New variable.
	(struct comdat_entry): Define.
	(comdat_hash): New function.
	(comdat_eq): New function.
	(solaris_elf_asm_comdat_section): New function.
	(solaris_define_comdat_signature): New function.
	(solaris_code_end): New function.
	* config/sol2-protos.h (solaris_elf_asm_comdat_section): Declare.
	(solaris_code_end): Declare.
	* config/t-sol2 (sol2.o): Add $HASHTAB_H dependency.
	* config/i386/i386.c (ix86_code_end) [TARGET_SOLARIS]: Call
	solaris_code_end.
	(i386_solaris_elf_named_section): Wrap in TARGET_SOLARIS.
	Remove ATTRIBUTE_UNUSED.
	[!USE_GAS]: Call solaris_elf_asm_comdat_section for
	SECTION_LINKONCE sections if HAVE_COMDAT_GROUP.
	* config/sparc/sparc.c (sparc_solaris_elf_asm_named_section):
	Likewise.
	* config/i386/sol2-10.h (TARGET_ASM_NAMED_SECTION): Moved ...
	* config/i386/sol2.h (TARGET_ASM_NAMED_SECTION): ... here.
	* config/sparc/sol2.h (TARGET_ASM_CODE_END): Redefine.
	(PUSHSECTION_FORMAT): Remove.
	(SECTION_NAME_FORMAT): Redefine.
diff mbox

Patch

diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -8768,6 +8768,10 @@  ix86_code_end (void)
   rtx xops[2];
   int regno;
 
+#ifdef TARGET_SOLARIS
+  solaris_code_end ();
+#endif
+
   for (regno = AX_REG; regno <= SP_REG; regno++)
     {
       char name[32];
@@ -32148,9 +32152,10 @@  void ix86_emit_swsqrtsf (rtx res, rtx a,
 			  gen_rtx_MULT (mode, e2, e3)));
 }
 
+#ifdef TARGET_SOLARIS
 /* Solaris implementation of TARGET_ASM_NAMED_SECTION.  */
 
-static void ATTRIBUTE_UNUSED
+static void
 i386_solaris_elf_named_section (const char *name, unsigned int flags,
 				tree decl)
 {
@@ -32164,8 +32169,18 @@  i386_solaris_elf_named_section (const ch
 	       flags & SECTION_WRITE ? "aw" : "a");
       return;
     }
+
+#ifndef USE_GAS
+  if (HAVE_COMDAT_GROUP && flags & SECTION_LINKONCE)
+    {
+      solaris_elf_asm_comdat_section (name, flags, decl);
+      return;
+    }
+#endif
+
   default_elf_asm_named_section (name, flags, decl);
 }
+#endif /* TARGET_SOLARIS */
 
 /* Return the mangling of TYPE if it is an extended fundamental type.  */
 
diff --git a/gcc/config/i386/sol2-10.h b/gcc/config/i386/sol2-10.h
--- a/gcc/config/i386/sol2-10.h
+++ b/gcc/config/i386/sol2-10.h
@@ -133,6 +133,3 @@  along with GCC; see the file COPYING3.  
 
 /* We do not need to search a special directory for startup files.  */
 #undef MD_STARTFILE_PREFIX
-
-#undef TARGET_ASM_NAMED_SECTION
-#define TARGET_ASM_NAMED_SECTION i386_solaris_elf_named_section
diff --git a/gcc/config/i386/sol2.h b/gcc/config/i386/sol2.h
--- a/gcc/config/i386/sol2.h
+++ b/gcc/config/i386/sol2.h
@@ -154,6 +154,9 @@  along with GCC; see the file COPYING3.  
     }								\
   while (0)
 
+#undef TARGET_ASM_NAMED_SECTION
+#define TARGET_ASM_NAMED_SECTION i386_solaris_elf_named_section
+
 /* We do not need NT_VERSION notes.  */
 #undef X86_FILE_START_VERSION_DIRECTIVE
 #define X86_FILE_START_VERSION_DIRECTIVE false
diff --git a/gcc/config/sol2-protos.h b/gcc/config/sol2-protos.h
--- a/gcc/config/sol2-protos.h
+++ b/gcc/config/sol2-protos.h
@@ -22,3 +22,5 @@  extern void solaris_insert_attributes (t
 extern void solaris_register_pragmas (void);
 extern void solaris_output_init_fini (FILE *, tree);
 extern void solaris_assemble_visibility (tree, int);
+extern void solaris_elf_asm_comdat_section (const char *, unsigned int, tree);
+extern void solaris_code_end (void);
diff --git a/gcc/config/sol2.c b/gcc/config/sol2.c
--- a/gcc/config/sol2.c
+++ b/gcc/config/sol2.c
@@ -29,6 +29,7 @@  along with GCC; see the file COPYING3.  
 #include "tm_p.h"
 #include "diagnostic-core.h"
 #include "ggc.h"
+#include "hashtab.h"
 
 tree solaris_pending_aligns, solaris_pending_inits, solaris_pending_finis;
 
@@ -106,14 +107,14 @@  solaris_output_init_fini (FILE *file, tr
 {
   if (lookup_attribute ("init", DECL_ATTRIBUTES (decl)))
     {
-      fprintf (file, PUSHSECTION_FORMAT, ".init");
+      fprintf (file, "\t.pushsection\t" SECTION_NAME_FORMAT "\n", ".init");
       ASM_OUTPUT_CALL (file, decl);
       fprintf (file, "\t.popsection\n");
     }
 
   if (lookup_attribute ("fini", DECL_ATTRIBUTES (decl)))
     {
-      fprintf (file, PUSHSECTION_FORMAT, ".fini");
+      fprintf (file, "\t.pushsection\t" SECTION_NAME_FORMAT "\n", ".fini");
       ASM_OUTPUT_CALL (file, decl);
       fprintf (file, "\t.popsection\n");
     }
@@ -155,3 +156,129 @@  solaris_assemble_visibility (tree decl A
 	   "in this configuration; ignored");
 #endif
 }
+
+/* Hash table of group signature symbols.  */
+
+static htab_t solaris_comdat_htab;
+
+/* Group section information entry stored in solaris_comdat_htab.  */
+
+typedef struct comdat_entry
+{
+  const char *name;
+  unsigned int flags;
+  tree decl;
+  const char *sig;
+} comdat_entry;
+
+/* Helper routines for maintaining solaris_comdat_htab.  */
+
+static hashval_t
+comdat_hash (const void *p)
+{
+  const comdat_entry *entry = (const comdat_entry *) p;
+
+  return htab_hash_string (entry->sig);
+}
+
+static int
+comdat_eq (const void *p1, const void *p2)
+{
+  const comdat_entry *entry1 = (const comdat_entry *) p1;
+  const comdat_entry *entry2 = (const comdat_entry *) p2;
+
+  return strcmp (entry1->sig, entry2->sig) == 0;
+}
+
+/* Output assembly to switch to COMDAT group section NAME with attributes
+   FLAGS and group signature symbol DECL, using Sun as syntax.  */
+
+void
+solaris_elf_asm_comdat_section (const char *name, unsigned int flags, tree decl)
+{
+  const char *signature;
+  char *section;
+  comdat_entry entry, **slot;
+
+  if (TREE_CODE (decl) == IDENTIFIER_NODE)
+    signature = IDENTIFIER_POINTER (decl);
+  else
+    signature = IDENTIFIER_POINTER (DECL_COMDAT_GROUP (decl));
+
+  /* Sun as requires group sections to be fragmented, i.e. to have names of
+     the form <section>%<fragment>.  Strictly speaking this is only
+     necessary to support cc -xF, but is enforced globally in violation of
+     the ELF gABI.  We keep the section names generated by GCC (generally
+     of the form .text.<signature>) and append %<signature> to pacify as,
+     despite the redundancy.  */
+  section = concat (name, "%", signature, NULL);
+
+  /* Clear SECTION_LINKONCE flag so targetm.asm_out.named_section only
+     emits this as a regular section.  Emit section before .group
+     directive since Sun as treats undeclared sections as @progbits,
+     which conflicts with .bss* sections which are @nobits.  */
+  targetm.asm_out.named_section (section, flags & ~SECTION_LINKONCE, decl);
+  
+  /* Sun as separates declaration of a group section and of the group
+     itself, using the .group directive and the #comdat flag.  */
+  fprintf (asm_out_file, "\t.group\t%s," SECTION_NAME_FORMAT ",#comdat\n",
+	   signature, section);
+
+  /* Unlike GNU as, group signature symbols need to be defined explicitly
+     for Sun as.  With a few exceptions, this is already the case.  To
+     identify the missing ones without changing the affected frontents,
+     remember the signature symbols and emit those not marked
+     TREE_SYMBOL_REFERENCED in solaris_code_end.  */
+  if (solaris_comdat_htab == NULL)
+    solaris_comdat_htab = htab_create_alloc (37, comdat_hash, comdat_eq, NULL,
+					     xcalloc, free);
+
+  entry.sig = signature;
+  slot = (comdat_entry **) htab_find_slot (solaris_comdat_htab, &entry, INSERT);
+
+  if (*slot == NULL)
+    {
+      *slot = XCNEW (comdat_entry);
+      /* Remember fragmented section name.  */
+      (*slot)->name = section;
+      /* Emit as regular section, .group declaration has already been done.  */
+      (*slot)->flags = flags & ~SECTION_LINKONCE;
+      (*slot)->decl = decl;
+      (*slot)->sig = signature;
+    }
+}
+
+/* Define unreferenced COMDAT group signature symbol corresponding to SLOT.  */
+
+static int
+solaris_define_comdat_signature (void **slot, void *aux ATTRIBUTE_UNUSED)
+{
+  comdat_entry *entry = *(comdat_entry **) slot;
+  tree decl = entry->decl;
+
+  if (TREE_CODE (decl) != IDENTIFIER_NODE)
+    decl = DECL_COMDAT_GROUP (decl);
+
+  if (!TREE_SYMBOL_REFERENCED (decl))
+    {
+      /* Switch to group section, otherwise Sun as complains
+	 `Group Id symbol defined outside of group'.  */
+      switch_to_section (get_section (entry->name, entry->flags, entry->decl));
+
+      ASM_OUTPUT_LABEL (asm_out_file, entry->sig);
+    }
+
+  /* Continue with scan.  */
+  return 1;
+}
+
+/* Emit unreferenced COMDAT group signature symbols for Sun as.  */
+
+void
+solaris_code_end (void)
+{
+  if (solaris_comdat_htab == NULL)
+    return;
+
+  htab_traverse (solaris_comdat_htab, solaris_define_comdat_signature, NULL);
+}
diff --git a/gcc/config/sol2.h b/gcc/config/sol2.h
--- a/gcc/config/sol2.h
+++ b/gcc/config/sol2.h
@@ -19,6 +19,9 @@  You should have received a copy of the G
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
+/* We are compiling for Solaris 2 now.  */
+#define TARGET_SOLARIS 1
+
 /* We use stabs-in-elf for debugging, because that is what the native
    toolchain uses.  */
 #undef PREFERRED_DEBUGGING_TYPE
@@ -257,9 +260,8 @@  __enable_execute_stack (void *addr)					
   { "init",      0, 0, true,  false,  false, NULL, false },		\
   { "fini",      0, 0, true,  false,  false, NULL, false }
 
-/* Solaris/x86 as and gas support the common ELF .section/.pushsection
-   syntax.  */
-#define PUSHSECTION_FORMAT	"\t.pushsection\t%s\n"
+/* Solaris/x86 as and gas support unquoted section names.  */
+#define SECTION_NAME_FORMAT	"%s"
 
 /* This is how to declare the size of a function.  For Solaris, we output
    any .init or .fini entries here.  */
diff --git a/gcc/config/sparc/sol2.h b/gcc/config/sparc/sol2.h
--- a/gcc/config/sparc/sol2.h
+++ b/gcc/config/sparc/sol2.h
@@ -188,9 +188,16 @@  along with GCC; see the file COPYING3.  
 #undef TARGET_ASM_NAMED_SECTION
 #define TARGET_ASM_NAMED_SECTION sparc_solaris_elf_asm_named_section
 
-/* And SPARC non-standard pushsection syntax.  */
-#undef PUSHSECTION_FORMAT
-#define PUSHSECTION_FORMAT "\t.pushsection\t\"%s\"\n"
+/* Emit COMDAT group signature symbols for Sun as.  */
+#undef TARGET_ASM_CODE_END
+#define TARGET_ASM_CODE_END solaris_code_end
+
+/* Solaris/SPARC as requires doublequoted section names.  While gas
+   supports that, too, we prefer the standard variant.  */
+#ifndef USE_GAS
+#undef SECTION_NAME_FORMAT
+#define SECTION_NAME_FORMAT	"\"%s\""
+#endif
 
 /* Static stack checking is supported by means of probes.  */
 #define STACK_CHECK_STATIC_BUILTIN 1
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -8537,12 +8537,19 @@  sparc_profile_hook (int labelno)
     }
 }
 
+#ifdef TARGET_SOLARIS
 /* Solaris implementation of TARGET_ASM_NAMED_SECTION.  */
 
 static void
 sparc_solaris_elf_asm_named_section (const char *name, unsigned int flags,
 				     tree decl ATTRIBUTE_UNUSED)
 {
+  if (HAVE_COMDAT_GROUP && flags & SECTION_LINKONCE)
+    {
+      solaris_elf_asm_comdat_section (name, flags, decl);
+      return;
+    }
+
   fprintf (asm_out_file, "\t.section\t\"%s\"", name);
 
   if (!(flags & SECTION_DEBUG))
@@ -8558,6 +8565,7 @@  sparc_solaris_elf_asm_named_section (con
 
   fputc ('\n', asm_out_file);
 }
+#endif /* TARGET_SOLARIS */
 
 /* We do not allow indirect calls to be optimized into sibling calls.
 
diff --git a/gcc/configure.ac b/gcc/configure.ac
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -2589,15 +2589,48 @@  AC_DEFINE_UNQUOTED(HAVE_GAS_SHF_MERGE,
   [`if test $gcc_cv_as_shf_merge = yes; then echo 1; else echo 0; fi`],
 [Define 0/1 if your assembler supports marking sections with SHF_MERGE flag.])
 
-gcc_GAS_CHECK_FEATURE(COMDAT group support, gcc_cv_as_comdat_group,
+gcc_GAS_CHECK_FEATURE([COMDAT group support (GNU as)],
+ gcc_cv_as_comdat_group,
  [elf,2,16,0], [--fatal-warnings],
  [.section .text,"axG",@progbits,.foo,comdat])
 if test $gcc_cv_as_comdat_group = yes; then
   gcc_cv_as_comdat_group_percent=no
+  gcc_cv_as_comdat_group_group=no
 else
- gcc_GAS_CHECK_FEATURE(COMDAT group support, gcc_cv_as_comdat_group_percent,
+ gcc_GAS_CHECK_FEATURE([COMDAT group support (GNU as, %type)],
+   gcc_cv_as_comdat_group_percent,
    [elf,2,16,0], [--fatal-warnings],
    [.section .text,"axG",%progbits,.foo,comdat])
+ if test $gcc_cv_as_comdat_group_percent = yes; then
+   gcc_cv_as_comdat_group_group=no
+ else
+   case "${target}" in
+     # Sun as uses a completely different syntax.
+     *-*-solaris2*)
+       case "${target}" in
+         sparc*-*-solaris2*)
+           conftest_s='
+               .group foo,".text%foo",#comdat
+               .section ".text%foo", #alloc,#execinstr,#progbits
+               .globl foo
+             foo:
+	     '
+           ;;
+         i?86-*-solaris2*)
+	   conftest_s='
+               .group foo,.text%foo,#comdat
+               .section .text%foo, "ax", @progbits
+               .globl  foo
+             foo:
+	     '
+	   ;;
+       esac
+       gcc_GAS_CHECK_FEATURE([COMDAT group support (Sun as, .group)],
+         gcc_cv_as_comdat_group_group,
+         ,, [$conftest_s])
+       ;;
+   esac
+ fi
 fi
 if test x"$ld_is_gold" = xyes; then
   comdat_group=yes
@@ -2623,16 +2656,19 @@  else
 changequote(,)dnl
   case "${target}" in
     *-*-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.
       #
-      # FIXME: Maybe need to refine later when COMDAT group support with
-      # Sun as is implemented.
-      if test "$ld_vers_major" -gt 1 || test "$ld_vers_minor" -ge 1688; then
+      # If using Sun as for COMDAT group as emitted by GCC, one needs at
+      # least ld version 1.2267.
+      if test "$ld_vers_major" -gt 1; then
         comdat_group=yes
-      else
-        comdat_group=no
+      elif test "x$gas_flag" = xyes && test "$ld_vers_minor" -ge 1688; then
+	comdat_group=yes
+      elif test "$ld_vers_minor" -ge 2267; then
+	comdat_group=yes
       fi
       ;;
     *)
@@ -2649,9 +2685,12 @@  AC_ARG_ENABLE(comdat,
 if test $comdat_group = no; then
   gcc_cv_as_comdat_group=no
   gcc_cv_as_comdat_group_percent=no
+  gcc_cv_as_comdat_group_group=no
 fi
 AC_DEFINE_UNQUOTED(HAVE_COMDAT_GROUP,
-  [`if test $gcc_cv_as_comdat_group = yes || test $gcc_cv_as_comdat_group_percent = yes; then echo 1; else echo 0; fi`],
+  [`if test $gcc_cv_as_comdat_group = yes \
+    || test $gcc_cv_as_comdat_group_percent = yes \
+    || test $gcc_cv_as_comdat_group_group = yes; then echo 1; else echo 0; fi`],
 [Define 0/1 if your assembler and linker support COMDAT groups.])
 
 gcc_GAS_CHECK_FEATURE([line table discriminator support],