This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Group identifier of a comdat group


On Mon, Jun 03, 2002 at 01:49:46PM +0930, Alan Modra wrote:
>  .section .text.foo,"axG",@progbits,foo_group,comdat

I chose this option to implement, but I'm open to other suggestions.

> Once we get these issues sorted out, it shouldn't be too hard to
> implement in the linker.

Ever the optimist.  It was a little harder than I expected.  :)
Not well tested yet, but this ought to be worth playing with.  I'll
commit this after some feedback (positive, hopefully).

bfd/ChangeLog
	* elf.c (bfd_section_from_shdr): Set SEC_LINK_ONCE on group
	section if GRP_COMDAT.
	(setup_group): Likewise.  Ensure symbol table is available.
	(bfd_elf_discard_group): New function.
	(_bfd_elf_make_section_from_shdr): Don't set SEC_LINK_ONCE on
	.gnu.linkonce* sections if they are members of a group.
	(set_group_contents): Set GRP_COMDAT flag.
	* section.c (bfd_discard_group): New function.
	* bfd-in.h (bfd_elf_discard_group): Declare.
	* bfd-in2.h: Regenerate.
	* elf-bfd.h (struct bfd_elf_section_data): Add linkonce_p field.
	(elf_linkonce_p): Define.

gas/ChangeLog
	* config/obj-elf.c (obj_elf_change_section): Set and check elf
	linkonce flag.  Print all warnings.
	(obj_elf_section): Parse ",comdat" for groups.
	(elf_frob_file): Set SEC_LINK_ONCE on COMDAT groups.  Check
	consistency of comdat flag.

ld/ChangeLog
	* ldlang.c (section_already_linked): Call bfd_discard_group.
	Typo fix.

Index: bfd/elf.c
===================================================================
RCS file: /cvs/src/src/bfd/elf.c,v
retrieving revision 1.140
diff -u -p -r1.140 elf.c
--- bfd/elf.c	31 May 2002 02:59:47 -0000	1.140
+++ bfd/elf.c	3 Jun 2002 14:07:34 -0000
@@ -440,6 +440,9 @@ setup_group (abfd, hdr, newsect)
 		      if (src == shdr->contents)
 			{
 			  dest->flags = idx;
+			  if (shdr->bfd_section != NULL && (idx & GRP_COMDAT))
+			    shdr->bfd_section->flags
+			      |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
 			  break;
 			}
 		      if (idx >= shnum)
@@ -498,9 +501,13 @@ setup_group (abfd, hdr, newsect)
 		    unsigned long iname;
 		    const char *gname;
 
-		    /* Humbug.  Get the name from the group signature
-		       symbol.  Why isn't the signature just a string?
-		       Fortunately, the name index is at the same
+		    /* Get the name from the group signature symbol.
+		       Why isn't the signature just a string?  First
+		       we need to get the symbol table.  */
+		    if (! bfd_section_from_shdr (abfd, shdr->sh_link))
+		      return false;
+
+		    /* Fortunately, the name index is at the same
 		       place in the external symbol for both 32 and 64
 		       bit ELF.  */
 		    bed = get_elf_backend_data (abfd);
@@ -516,8 +523,10 @@ setup_group (abfd, hdr, newsect)
 		    /* Start a circular list with one element.  */
 		    elf_next_in_group (newsect) = newsect;
 		  }
+
 		if (shdr->bfd_section != NULL)
 		  elf_next_in_group (shdr->bfd_section) = newsect;
+
 		i = num_group - 1;
 		break;
 	      }
@@ -532,6 +541,24 @@ setup_group (abfd, hdr, newsect)
   return true;
 }
 
+void
+bfd_elf_discard_group (abfd, group)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *group;
+{
+  asection *first = elf_next_in_group (group);
+  asection *s = first;
+
+  while (s != NULL)
+    {
+      s->output_section = bfd_abs_section_ptr;
+      s = elf_next_in_group (s);
+      /* These lists are circular.  */
+      if (s == first)
+	break;
+    }
+}
+
 /* Make a BFD section from an ELF section.  We store a pointer to the
    BFD section in the bfd_section field of the header.  */
 
@@ -620,7 +647,8 @@ _bfd_elf_make_section_from_shdr (abfd, h
      The symbols will be defined as weak, so that multiple definitions
      are permitted.  The GNU linker extension is to actually discard
      all but one of the sections.  */
-  if (strncmp (name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0)
+  if (strncmp (name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0
+      && elf_next_in_group (newsect) == NULL)
     flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
 
   bed = get_elf_backend_data (abfd);
@@ -1829,6 +1857,10 @@ bfd_section_from_shdr (abfd, shindex)
 	  unsigned int n_elt = hdr->sh_size / 4;
 	  asection *s;
 
+	  if (idx->flags & GRP_COMDAT)
+	    hdr->bfd_section->flags
+	      |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
+
 	  while (--n_elt != 0)
 	    if ((s = (++idx)->shdr->bfd_section) != NULL
 		&& elf_next_in_group (s) != NULL)
@@ -2369,7 +2401,7 @@ set_group_contents (abfd, sec, failedptr
       while (elt != elf_next_in_group (l->u.indirect.section));
 
   loc -= 4;
-  H_PUT_32 (abfd, 0, loc);
+  H_PUT_32 (abfd, sec->flags & SEC_LINK_ONCE ? GRP_COMDAT : 0, loc);
 
   BFD_ASSERT (loc == sec->contents);
 }
Index: bfd/section.c
===================================================================
RCS file: /cvs/src/src/bfd/section.c,v
retrieving revision 1.45
diff -u -p -r1.45 section.c
--- bfd/section.c	23 May 2002 13:12:46 -0000	1.45
+++ bfd/section.c	3 Jun 2002 12:58:00 -0000
@@ -1375,3 +1375,24 @@ _bfd_strip_section_from_output (info, s)
 
   s->flags |= SEC_EXCLUDE;
 }
+
+/*
+FUNCTION
+	bfd_discard_group
+
+SYNOPSIS
+	void bfd_discard_group (bfd *abfd, asection *group);
+
+DESCRIPTION
+	Remove all members of @var{group} from the output.
+*/
+
+void
+bfd_discard_group (abfd, group)
+     bfd *abfd;
+     asection *group;
+{
+  if ((group->flags & SEC_GROUP) != 0
+      && abfd->xvec->flavour == bfd_target_elf_flavour)
+    bfd_elf_discard_group (abfd, group);
+}
Index: bfd/bfd-in.h
===================================================================
RCS file: /cvs/src/src/bfd/bfd-in.h,v
retrieving revision 1.46
diff -u -p -r1.46 bfd-in.h
--- bfd/bfd-in.h	29 May 2002 16:03:04 -0000	1.46
+++ bfd/bfd-in.h	3 Jun 2002 12:57:32 -0000
@@ -657,6 +657,8 @@ extern boolean bfd_elf32_discard_info
   PARAMS ((bfd *, struct bfd_link_info *));
 extern boolean bfd_elf64_discard_info
   PARAMS ((bfd *, struct bfd_link_info *));
+extern void bfd_elf_discard_group
+  PARAMS ((bfd *, struct sec *));
 
 /* Return an upper bound on the number of bytes required to store a
    copy of ABFD's program header table entries.  Return -1 if an error
Index: bfd/elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.73
diff -u -p -r1.73 elf-bfd.h
--- bfd/elf-bfd.h	31 May 2002 02:59:47 -0000	1.73
+++ bfd/elf-bfd.h	3 Jun 2002 12:57:42 -0000
@@ -926,11 +926,15 @@ struct bfd_elf_section_data
 
   /* Nonzero if this section uses RELA relocations, rather than REL.  */
   unsigned int use_rela_p:1;
+
+  /* Nonzero when a group is COMDAT.  */
+  unsigned int linkonce_p:1;
 };
 
 #define elf_section_data(sec)  ((struct bfd_elf_section_data*)sec->used_by_bfd)
 #define elf_group_name(sec)    (elf_section_data(sec)->group_name)
 #define elf_next_in_group(sec) (elf_section_data(sec)->next_in_group)
+#define elf_linkonce_p(sec)    (elf_section_data(sec)->linkonce_p)
 
 /* Return true if section has been discarded.  */
 #define elf_discarded_section(sec)					\
Index: gas/config/obj-elf.c
===================================================================
RCS file: /cvs/src/src/gas/config/obj-elf.c,v
retrieving revision 1.50
diff -u -p -r1.50 obj-elf.c
--- gas/config/obj-elf.c	23 May 2002 13:12:47 -0000	1.50
+++ gas/config/obj-elf.c	3 Jun 2002 12:57:28 -0000
@@ -77,7 +77,7 @@ static void obj_elf_weak PARAMS ((int));
 static void obj_elf_local PARAMS ((int));
 static void obj_elf_visibility PARAMS ((int));
 static void obj_elf_change_section
-  PARAMS ((const char *, int, int, int, const char *, int));
+  PARAMS ((const char *, int, int, int, const char *, int, int));
 static int obj_elf_parse_section_letters PARAMS ((char *, size_t));
 static int obj_elf_section_word PARAMS ((char *, size_t));
 static char *obj_elf_section_name PARAMS ((void));
@@ -664,12 +664,13 @@ static struct special_section const spec
 };
 
 static void
-obj_elf_change_section (name, type, attr, entsize, group_name, push)
+obj_elf_change_section (name, type, attr, entsize, group_name, linkonce, push)
      const char *name;
      int type;
      int attr;
      int entsize;
      const char *group_name;
+     int linkonce;
      int push;
 {
   asection *old_sec;
@@ -758,6 +759,7 @@ obj_elf_change_section (name, type, attr
       if (flags & SEC_MERGE)
 	sec->entsize = entsize;
       elf_group_name (sec) = group_name;
+      elf_linkonce_p (sec) = linkonce;
 
       /* Add a symbol for this section to the symbol table.  */
       secsym = symbol_find (name);
@@ -771,15 +773,16 @@ obj_elf_change_section (name, type, attr
       /* If section attributes are specified the second time we see a
 	 particular section, then check that they are the same as we
 	 saw the first time.  */
-      if ((old_sec->flags ^ flags)
-	  & (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
-	     | SEC_EXCLUDE | SEC_SORT_ENTRIES | SEC_MERGE | SEC_STRINGS
-	     | SEC_THREAD_LOCAL))
+      if (((old_sec->flags ^ flags)
+	   & (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
+	      | SEC_EXCLUDE | SEC_SORT_ENTRIES | SEC_MERGE | SEC_STRINGS
+	      | SEC_THREAD_LOCAL))
+	  || linkonce != elf_linkonce_p (sec))
 	as_warn (_("ignoring changed section attributes for %s"), name);
-      else if ((flags & SEC_MERGE) && old_sec->entsize != (unsigned) entsize)
+      if ((flags & SEC_MERGE) && old_sec->entsize != (unsigned) entsize)
 	as_warn (_("ignoring changed section entity size for %s"), name);
-      else if ((attr & SHF_GROUP) != 0
-	       && strcmp (elf_group_name (old_sec), group_name) != 0)
+      if ((attr & SHF_GROUP) != 0
+	  && strcmp (elf_group_name (old_sec), group_name) != 0)
 	as_warn (_("ignoring new section group for %s"), name);
     }
 
@@ -947,6 +950,7 @@ obj_elf_section (push)
   char *name, *group_name, *beg;
   int type, attr, dummy;
   int entsize;
+  int linkonce;
 
 #ifndef TC_I370
   if (flag_mri)
@@ -977,6 +981,7 @@ obj_elf_section (push)
   attr = 0;
   group_name = NULL;
   entsize = 0;
+  linkonce = 0;
 
   if (*input_line_pointer == ',')
     {
@@ -1050,6 +1055,11 @@ obj_elf_section (push)
 	      group_name = obj_elf_section_name ();
 	      if (group_name == NULL)
 		attr &= ~SHF_GROUP;
+	      else if (strncmp (input_line_pointer, ",comdat", 7) == 0)
+		{
+		  input_line_pointer += 7;
+		  linkonce = 1;
+		}
 	    }
 	  else if ((attr & SHF_GROUP) != 0)
 	    {
@@ -1085,7 +1095,7 @@ obj_elf_section (push)
 
   demand_empty_rest_of_line ();
 
-  obj_elf_change_section (name, type, attr, entsize, group_name, push);
+  obj_elf_change_section (name, type, attr, entsize, group_name, linkonce, push);
 }
 
 /* Change to the .data section.  */
@@ -2015,8 +2025,20 @@ elf_frob_file ()
       asection *s;
       flagword flags;
 
-      s = subseg_force_new (group_name, 0);
       flags = SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_GROUP;
+      for (s = list.head[i]; s != NULL; s = elf_next_in_group (s))
+	if (elf_linkonce_p (s) != ((flags & SEC_LINK_ONCE) != 0))
+	  {
+	    flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
+	    if (s != list.head[i])
+	      {
+		as_warn (_("assuming all members of group `%s' are COMDAT"),
+			 group_name);
+		break;
+	      }
+	  }
+
+      s = subseg_force_new (group_name, 0);
       if (s == NULL
 	  || !bfd_set_section_flags (stdoutput, s, flags)
 	  || !bfd_set_section_alignment (stdoutput, s, 2))
Index: ld/ldlang.c
===================================================================
RCS file: /cvs/src/src/ld/ldlang.c,v
retrieving revision 1.88
diff -u -p -r1.88 ldlang.c
--- ld/ldlang.c	27 May 2002 08:22:07 -0000	1.88
+++ ld/ldlang.c	3 Jun 2002 12:58:03 -0000
@@ -985,7 +985,7 @@ section_already_linked (abfd, sec, data)
      of having link once sections in the first place.
 
      Also, not merging link once sections in a relocatable link
-     causes trouble for MIPS ELF, which relies in link once semantics
+     causes trouble for MIPS ELF, which relies on link once semantics
      to handle the .reginfo section correctly.  */
 
   name = bfd_get_section_name (abfd, sec);
@@ -1038,6 +1038,9 @@ section_already_linked (abfd, sec, data)
 	     does not create a lang_input_section structure for this
 	     section.  */
 	  sec->output_section = bfd_abs_section_ptr;
+
+	  if (flags & SEC_GROUP)
+	    bfd_discard_group (abfd, sec);
 
 	  return;
 	}

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]