SHT_GROUP support, part 1

Alan Modra amodra@bigpond.net.au
Mon Oct 8 23:03:00 GMT 2001


On Sun, Oct 07, 2001 at 09:44:29AM -0700, Ulrich Drepper wrote:
> Alan Modra <amodra@bigpond.net.au> writes:
> 
> > I'm a little puzzled as to why a symbol is needed for the signature.
> > Surely, a string is all that's needed?
> 
> The string is what is important but how to represent it?  The cleanest
> way is by a symbol.  The spec contains appropriate rules for the case
> when you remove a section group.  And it is also possible to have
> multiple symbol tables, one for each section group.  So, using a
> symbol is no bad choice.

It would have been a little easier if the group had been identified using
sh_link and sh_info to point into the string table, that's all.  Getting
at symbols in BFD is not quite as simple as accessing strtab.  I guess
I'm whinging more about BFD than the design of SHT_GROUP sections.

> > The other slightly puzzling thing in the info you sent me some time
> > ago, is why "The group section must appear in the section table
> > before any section it is referencing"
> 
> Why is this puzzling?  This makes handling section groups much easier.

That depends on the internal representation used for group info.  I chose
to put the section group info as a linked list in per-section structures (*),
so for this particular implementation it makes more sense to put the group
info after any section in the group.  That way, you could read sections in
their natural order, setting up a couple of pointers in member sections
when reading the SHT_GROUP section.  No big deal anyway, and the code I've
written will handle any placement of SHT_GROUP sections.  Hmm, I suppose
that means my current patch doesn't quite comply with the spec as I haven't
ordered the sections.

(*) Makes --gc-sections change easy.  See gc_mark_hook.

Here's what I'm about to commit.

bfd/ChangeLog
	* elf-bfd.h (struct bfd_elf_section_data): Add "group" and
	"next_in_group".  Fix gp and gp_size comments.
	* elf.c (union elf_internal_group): New.
	(setup_group): New function.
	(_bfd_elf_make_section_from_shdr): Set BFD flags for SHT_GROUP.
	Call setup_group for SHF_GROUP sections.
	(bfd_section_from_shdr): Build a BFD section for SHT_GROUP.
	(elf_fake_sections): Set header type for SEC_GROUP, and header
	flags for sections in a group.
	(set_group_contents): New function.
	(_bfd_elf_compute_section_file_positions): Call it.
	(assign_section_numbers): Set sh_link for SHT_GROUP.
	* elflink.h (gc_mark_hook): Handle section groups.
	* elfxx-target.h: Add SEC_GROUP to applicable_flags.
	* section.c (SEC_GROUP): Define.
	(struct sec): Comment fixes.
	* bfd-in2.h: Regenerate.

[some tidying unrelated to SHT_GROUP support]
	* elf.c (bfd_elf_print_symbol): Formatting fix; migrate expression
	out of function args.
	(_bfd_elf_canonicalize_reloc): Similarly.
	(_bfd_elf_get_symtab): Here too.
	(_bfd_elf_canonicalize_dynamic_symtab): And here.
	* elfcode.h (elf_slurp_symbol_table): Don't recalculate size for
	bfd_bread, and remove unnecessary cast.

gas/ChangeLog
	* config/obj-elf.c: (obj_elf_change_section): Add "group" param.
	Set elf_section_data group from it.  Warn if group name changed.
	(obj_elf_parse_section_letters): Parse 'G' too.
	(obj_elf_section): Parse group name.
	(struct group_list): New.
	(build_group_lists): New function.
	(elf_frob_file): Create SEC_GROUP section(s).

	* config/obj-elf.c: (elf_copy_symbol_attributes): Zap trailing
	whitespace.

-- 
Alan Modra

Index: bfd/elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.50
diff -u -p -r1.50 elf-bfd.h
--- elf-bfd.h	2001/10/04 12:30:26	1.50
+++ elf-bfd.h	2001/10/09 05:03:47
@@ -815,6 +815,13 @@ struct bfd_elf_section_data
   /* A pointer used for SEC_MERGE optimizations.  */
   PTR merge_info;
 
+  /* Group name, if this section is part of a group.  */
+  const char *group;
+
+  /* A linked list of sections in the group.  Circular when used by
+     the linker.  */
+  asection *next_in_group;
+
   /* A pointer available for the processor specific ELF backend.  */
   PTR tdata;
 
@@ -905,8 +912,11 @@ struct elf_obj_tdata
   void *prstatus;			/* The raw /proc prstatus structure */
   void *prpsinfo;			/* The raw /proc prpsinfo structure */
 #endif
-  bfd_vma gp;				/* The gp value (MIPS only, for now) */
-  unsigned int gp_size;			/* The gp size (MIPS only, for now) */
+  bfd_vma gp;				/* The gp value */
+  unsigned int gp_size;			/* The gp size */
+
+  Elf_Internal_Shdr **group_sect_ptr;
+  int num_group;
 
   /* Information grabbed from an elf core file.  */
   int core_signal;
Index: bfd/elf.c
===================================================================
RCS file: /cvs/src/src/bfd/elf.c,v
retrieving revision 1.97
diff -u -p -r1.97 elf.c
--- elf.c	2001/10/03 08:33:18	1.97
+++ elf.c	2001/10/09 05:03:51
@@ -51,7 +51,9 @@ static boolean prep_headers PARAMS ((bfd
 static boolean swap_out_syms PARAMS ((bfd *, struct bfd_strtab_hash **, int));
 static boolean copy_private_bfd_data PARAMS ((bfd *, bfd *));
 static char *elf_read PARAMS ((bfd *, file_ptr, bfd_size_type));
+static boolean setup_group PARAMS ((bfd *, Elf_Internal_Shdr *, asection *));
 static void elf_fake_sections PARAMS ((bfd *, asection *, PTR));
+static void set_group_contents PARAMS ((bfd *, asection *, PTR));
 static boolean assign_section_numbers PARAMS ((bfd *));
 static INLINE int sym_is_global PARAMS ((bfd *, asymbol *));
 static boolean elf_map_symbols PARAMS ((bfd *));
@@ -345,6 +347,191 @@ bfd_elf_string_from_elf_section (abfd, s
   return ((char *) hdr->contents) + strindex;
 }
 
+/* Elf_Internal_Shdr->contents is an array of these for SHT_GROUP
+   sections.  The first element is the flags, the rest are section
+   pointers.  */
+
+typedef union elf_internal_group {
+  Elf_Internal_Shdr *shdr;
+  unsigned int flags;
+} Elf_Internal_Group;
+
+/* Set next_in_group list pointer, and group name for NEWSECT.  */
+
+static boolean
+setup_group (abfd, hdr, newsect)
+     bfd *abfd;
+     Elf_Internal_Shdr *hdr;
+     asection *newsect;
+{
+  unsigned int num_group = elf_tdata (abfd)->num_group;
+
+  /* If num_group is zero, read in all SHT_GROUP sections.  The count
+     is set to -1 if there are no SHT_GROUP sections.  */
+  if (num_group == 0)
+    {
+      unsigned int i, shnum;
+
+      /* First count the number of groups.  If we have a SHT_GROUP
+	 section with just a flag word (ie. sh_size is 4), ignore it.  */
+      shnum = elf_elfheader (abfd)->e_shnum;
+      num_group = 0;
+      for (i = 0; i < shnum; i++)
+	{
+	  Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i];
+	  if (shdr->sh_type == SHT_GROUP && shdr->sh_size >= 8)
+	    num_group += 1;
+	}
+
+      if (num_group == 0)
+	num_group = -1;
+      elf_tdata (abfd)->num_group = num_group;
+
+      if (num_group > 0)
+	{
+	  /* We keep a list of elf section headers for group sections,
+	     so we can find them quickly.  */
+	  bfd_size_type amt = num_group * sizeof (Elf_Internal_Shdr *);
+	  elf_tdata (abfd)->group_sect_ptr = bfd_alloc (abfd, amt);
+	  if (elf_tdata (abfd)->group_sect_ptr == NULL)
+	    return false;
+
+	  num_group = 0;
+	  for (i = 0; i < shnum; i++)
+	    {
+	      Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i];
+	      if (shdr->sh_type == SHT_GROUP && shdr->sh_size >= 8)
+		{
+		  char *src;
+		  Elf_Internal_Group *dest;
+
+		  /* Add to list of sections.  */
+		  elf_tdata (abfd)->group_sect_ptr[num_group] = shdr;
+		  num_group += 1;
+
+		  /* Read the raw contents.  */
+		  BFD_ASSERT (sizeof (*dest) >= 4);
+		  amt = shdr->sh_size * sizeof (*dest) / 4;
+		  shdr->contents = bfd_alloc (abfd, amt);
+		  if (shdr->contents == NULL
+		      || bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0
+		      || (bfd_bread (shdr->contents, shdr->sh_size, abfd)
+			  != shdr->sh_size))
+		    return false;
+
+		  /* Translate raw contents, a flag word followed by an
+		     array of elf section indices all in target byte order,
+		     to the flag word followed by an array of elf section
+		     pointers.  */
+		  src = shdr->contents + shdr->sh_size;
+		  dest = (Elf_Internal_Group *) (shdr->contents + amt);
+		  while (1)
+		    {
+		      unsigned int idx;
+
+		      src -= 4;
+		      --dest;
+		      idx = H_GET_32 (abfd, src);
+		      if (src == shdr->contents)
+			{
+			  dest->flags = idx;
+			  break;
+			}
+		      if (idx >= shnum)
+			{
+			  ((*_bfd_error_handler)
+			   (_("%s: invalid SHT_GROUP entry"),
+			    bfd_archive_filename (abfd)));
+			  idx = 0;
+			}
+		      dest->shdr = elf_elfsections (abfd)[idx];
+		    }
+		}
+	    }
+	}
+    }
+
+  if (num_group != (unsigned) -1)
+    {
+      unsigned int i;
+
+      for (i = 0; i < num_group; i++)
+	{
+	  Elf_Internal_Shdr *shdr = elf_tdata (abfd)->group_sect_ptr[i];
+	  Elf_Internal_Group *idx = (Elf_Internal_Group *) shdr->contents;
+	  unsigned int n_elt = shdr->sh_size / 4;
+
+	  /* Look through this group's sections to see if current
+	     section is a member.  */
+	  while (--n_elt != 0)
+	    if ((++idx)->shdr == hdr)
+	      {
+		asection *s;
+
+		/* We are a member of this group.  Go looking through
+		   other members to see if any others are linked via
+		   next_in_group.  */
+		idx = (Elf_Internal_Group *) shdr->contents;
+		n_elt = shdr->sh_size / 4;
+		while (--n_elt != 0)
+		  if ((s = (++idx)->shdr->bfd_section) != NULL
+		      && elf_section_data (s)->next_in_group != NULL)
+		    break;
+		if (n_elt != 0)
+		  {
+		    const char *gname;
+		    asection *next;
+
+		    /* Snarf the group name from other member, and
+		       insert current section in circular list.  */
+		    gname = elf_section_data (s)->group;
+		    elf_section_data (newsect)->group = gname;
+		    next = elf_section_data (s)->next_in_group;
+		    elf_section_data (newsect)->next_in_group = next;
+		    elf_section_data (s)->next_in_group = newsect;
+		  }
+		else
+		  {
+		    struct elf_backend_data *bed;
+		    file_ptr pos;
+		    unsigned char ename[4];
+		    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
+		       place in the external symbol for both 32 and 64
+		       bit ELF.  */
+		    bed = get_elf_backend_data (abfd);
+		    pos = elf_tdata (abfd)->symtab_hdr.sh_offset;
+		    pos += shdr->sh_info * bed->s->sizeof_sym;
+		    if (bfd_seek (abfd, pos, SEEK_SET) != 0
+			|| bfd_bread (ename, 4, abfd) != 4)
+		      return false;
+		    iname = H_GET_32 (abfd, ename);
+		    gname = elf_string_from_elf_strtab (abfd, iname);
+		    elf_section_data (newsect)->group = gname;
+
+		    /* Start a circular list with one element.  */
+		    elf_section_data (newsect)->next_in_group = newsect;
+		  }
+		if (shdr->bfd_section != NULL)
+		  shdr->bfd_section->lineno = (alent *) newsect;
+		i = num_group - 1;
+		break;
+	      }
+	}
+    }
+
+  if (elf_section_data (newsect)->group == NULL)
+    {
+      (*_bfd_error_handler) (_("%s: no group info for section %s"),
+			     bfd_archive_filename (abfd), newsect->name);
+    }
+  return true;
+}
+
 /* Make a BFD section from an ELF section.  We store a pointer to the
    BFD section in the bfd_section field of the header.  */
 
@@ -380,6 +567,8 @@ _bfd_elf_make_section_from_shdr (abfd, h
   flags = SEC_NO_FLAGS;
   if (hdr->sh_type != SHT_NOBITS)
     flags |= SEC_HAS_CONTENTS;
+  if (hdr->sh_type == SHT_GROUP)
+    flags |= SEC_GROUP | SEC_EXCLUDE;
   if ((hdr->sh_flags & SHF_ALLOC) != 0)
     {
       flags |= SEC_ALLOC;
@@ -399,6 +588,9 @@ _bfd_elf_make_section_from_shdr (abfd, h
       if ((hdr->sh_flags & SHF_STRINGS) != 0)
 	flags |= SEC_STRINGS;
     }
+  if (hdr->sh_flags & SHF_GROUP)
+    if (!setup_group (abfd, hdr, newsect))
+      return false;
 
   /* The debugging sections appear to be recognized only by name, not
      any sort of flag.  */
@@ -841,6 +1033,7 @@ bfd_elf_print_symbol (abfd, filep, symbo
 	const char *name = NULL;
 	struct elf_backend_data *bed;
 	unsigned char st_other;
+	bfd_vma val;
 
 	section_name = symbol->section ? symbol->section->name : "(*none*)";
 
@@ -859,10 +1052,11 @@ bfd_elf_print_symbol (abfd, filep, symbo
 	   we've already printed the size; now print the alignment.
 	   For other symbols, we have no specified alignment, and
 	   we've printed the address; now print the size.  */
-	bfd_fprintf_vma (abfd, file,
-			 (bfd_is_com_section (symbol->section)
-			  ? ((elf_symbol_type *) symbol)->internal_elf_sym.st_value
-			  : ((elf_symbol_type *) symbol)->internal_elf_sym.st_size));
+	if (bfd_is_com_section (symbol->section))
+	  val = ((elf_symbol_type *) symbol)->internal_elf_sym.st_value;
+	else
+	  val = ((elf_symbol_type *) symbol)->internal_elf_sym.st_size;
+	bfd_fprintf_vma (abfd, file, val);
 
 	/* If we have version information, print it.  */
 	if (elf_tdata (abfd)->dynversym_section != 0
@@ -1512,6 +1706,26 @@ bfd_section_from_shdr (abfd, shindex)
     case SHT_SHLIB:
       return true;
 
+    case SHT_GROUP:
+      /* Make a section for objcopy and relocatable links.  */
+      if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name))
+	return false;
+      if (hdr->contents != NULL)
+	{
+	  Elf_Internal_Group *idx = (Elf_Internal_Group *) hdr->contents;
+	  unsigned int n_elt = hdr->sh_size / 4;
+	  asection *s;
+
+	  while (--n_elt != 0)
+	    if ((s = (++idx)->shdr->bfd_section) != NULL
+		&& elf_section_data (s)->next_in_group != NULL)
+	      {
+		hdr->bfd_section->lineno = (alent *) s;
+		break;
+	      }
+	}
+      break;
+
     default:
       /* Check for any processor-specific section types.  */
       {
@@ -1847,6 +2061,11 @@ elf_fake_sections (abfd, asect, failedpt
 	BFD_ASSERT (elf_tdata (abfd)->cverrefs == 0
 		    || this_hdr->sh_info == elf_tdata (abfd)->cverrefs);
     }
+  else if ((asect->flags & SEC_GROUP) != 0)
+    {
+      this_hdr->sh_type = SHT_GROUP;
+      this_hdr->sh_entsize = 4;
+    }
   else if ((asect->flags & SEC_ALLOC) != 0
 	   && ((asect->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0))
     this_hdr->sh_type = SHT_NOBITS;
@@ -1866,6 +2085,8 @@ elf_fake_sections (abfd, asect, failedpt
       if ((asect->flags & SEC_STRINGS) != 0)
 	this_hdr->sh_flags |= SHF_STRINGS;
     }
+  if (elf_section_data (asect)->group != NULL)
+    this_hdr->sh_flags |= SHF_GROUP;
 
   /* Check for processor-specific section types.  */
   if (bed->elf_backend_fake_sections)
@@ -1883,6 +2104,82 @@ elf_fake_sections (abfd, asect, failedpt
     *failedptr = true;
 }
 
+/* Fill in the contents of a SHT_GROUP section.  */
+
+static void
+set_group_contents (abfd, sec, failedptrarg)
+     bfd *abfd;
+     asection *sec;
+     PTR failedptrarg ATTRIBUTE_UNUSED;
+{
+  boolean *failedptr = (boolean *) failedptrarg;
+  unsigned long symindx;
+  asection *elt;
+  unsigned char *loc;
+  struct bfd_link_order *l;
+
+  if (elf_section_data (sec)->this_hdr.sh_type != SHT_GROUP
+      || *failedptr)
+    return;
+
+  /* If called from the assembler, swap_out_syms will have set up
+     udata.i;  If called for "ld -r", the symbols won't yet be mapped,
+     so emulate elf_bfd_final_link.  */
+  symindx = sec->symbol->udata.i;
+  if (symindx == 0)
+    symindx = elf_section_data (sec)->this_idx;
+  elf_section_data (sec)->this_hdr.sh_info = symindx;
+
+  /* Nor will the contents be allocated for "ld -r".  */
+  if (sec->contents == NULL)
+    {
+      sec->contents = bfd_alloc (abfd, sec->_raw_size);
+      if (sec->contents == NULL)
+	{
+	  *failedptr = true;
+	  return;
+	}
+    }
+
+  loc = sec->contents + sec->_raw_size;
+
+  /* Get the pointer to the first section in the group that we
+     squirreled away here.  */
+  elt = (asection *) sec->lineno;
+
+  /* First element is a flag word.  Rest of section is elf section
+     indices for all the sections of the group.  Write them backwards
+     just to keep the group in the same order as given in .section
+     directives, not that it matters.  */
+  while (elt != NULL)
+    {
+      loc -= 4;
+      H_PUT_32 (abfd, elf_section_data (elt)->this_idx, loc);
+      elt = elf_section_data (elt)->next_in_group;
+    }
+
+  /* If this is a relocatable link, then the above did nothing because
+     SEC is the output section.  Look through the input sections
+     instead.  */
+  for (l = sec->link_order_head; l != NULL; l = l->next)
+    if (l->type == bfd_indirect_link_order
+	&& (elt = (asection *) l->u.indirect.section->lineno) != NULL)
+      do
+	{
+	  loc -= 4;
+	  H_PUT_32 (abfd,
+		    elf_section_data (elt->output_section)->this_idx, loc);
+	  elt = elf_section_data (elt)->next_in_group;
+	  /* During a relocatable link, the lists are circular.  */
+	}
+      while (elt != (asection *) l->u.indirect.section->lineno);
+
+  loc -= 4;
+  H_PUT_32 (abfd, 0, loc);
+
+  BFD_ASSERT (loc == sec->contents);
+}
+
 /* Assign all ELF section numbers.  The dummy first section is handled here
    too.  The link/info pointers for the standard section types are filled
    in here too, while we're at it.  */
@@ -2055,6 +2352,9 @@ assign_section_numbers (abfd)
 	  if (s != NULL)
 	    d->this_hdr.sh_link = elf_section_data (s)->this_idx;
 	  break;
+
+	case SHT_GROUP:
+	  d->this_hdr.sh_link = t->symtab_section;
 	}
     }
 
@@ -2331,6 +2631,13 @@ _bfd_elf_compute_section_file_positions 
 	return false;
     }
 
+  if (link_info == NULL || link_info->relocateable)
+    {
+      bfd_map_over_sections (abfd, set_group_contents, &failed);
+      if (failed)
+	return false;
+    }
+
   shstrtab_hdr = &elf_tdata (abfd)->shstrtab_hdr;
   /* sh_name was set in prep_headers.  */
   shstrtab_hdr->sh_type = SHT_STRTAB;
@@ -4569,11 +4876,9 @@ _bfd_elf_canonicalize_reloc (abfd, secti
 {
   arelent *tblptr;
   unsigned int i;
+  struct elf_backend_data *bed = get_elf_backend_data (abfd);
 
-  if (! get_elf_backend_data (abfd)->s->slurp_reloc_table (abfd,
-							   section,
-							   symbols,
-							   false))
+  if (! bed->s->slurp_reloc_table (abfd, section, symbols, false))
     return -1;
 
   tblptr = section->relocation;
@@ -4590,8 +4895,8 @@ _bfd_elf_get_symtab (abfd, alocation)
      bfd *abfd;
      asymbol **alocation;
 {
-  long symcount = get_elf_backend_data (abfd)->s->slurp_symbol_table
-    (abfd, alocation, false);
+  struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  long symcount = bed->s->slurp_symbol_table (abfd, alocation, false);
 
   if (symcount >= 0)
     bfd_get_symcount (abfd) = symcount;
@@ -4603,8 +4908,8 @@ _bfd_elf_canonicalize_dynamic_symtab (ab
      bfd *abfd;
      asymbol **alocation;
 {
-  return get_elf_backend_data (abfd)->s->slurp_symbol_table
-    (abfd, alocation, true);
+  struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  return bed->s->slurp_symbol_table (abfd, alocation, true);
 }
 
 /* Return the size required for the dynamic reloc entries.  Any
Index: bfd/elfcode.h
===================================================================
RCS file: /cvs/src/src/bfd/elfcode.h,v
retrieving revision 1.21
diff -u -p -r1.21 elfcode.h
--- elfcode.h	2001/09/22 03:16:01	1.21
+++ elfcode.h	2001/10/09 05:03:52
@@ -1084,10 +1084,7 @@ elf_slurp_symbol_table (abfd, symptrs, d
       if (x_symp == NULL && symcount != 0)
 	goto error_return;
 
-      if (bfd_bread ((PTR) x_symp,
-		    (bfd_size_type) (symcount * sizeof (Elf_External_Sym)),
-		    abfd)
-	  != symcount * sizeof (Elf_External_Sym))
+      if (bfd_bread ((PTR) x_symp, amt, abfd) != amt)
 	goto error_return;
 
       /* Read the raw ELF version symbol information.  */
@@ -1115,7 +1112,7 @@ elf_slurp_symbol_table (abfd, symptrs, d
 	  if (x_versymp == NULL && verhdr->sh_size != 0)
 	    goto error_return;
 
-	  if (bfd_bread ((PTR) x_versymp, (bfd_size_type) verhdr->sh_size, abfd)
+	  if (bfd_bread ((PTR) x_versymp, verhdr->sh_size, abfd)
 	      != verhdr->sh_size)
 	    goto error_return;
 	}
Index: bfd/elflink.h
===================================================================
RCS file: /cvs/src/src/bfd/elflink.h,v
retrieving revision 1.112
diff -u -p -r1.112 elflink.h
--- elflink.h	2001/10/06 07:25:40	1.112
+++ elflink.h	2001/10/09 05:03:57
@@ -6878,7 +6878,8 @@ static boolean elf_gc_smash_unused_vtent
   PARAMS ((struct elf_link_hash_entry *h, PTR dummy));
 
 /* The mark phase of garbage collection.  For a given section, mark
-   it, and all the sections which define symbols to which it refers.  */
+   it and any sections in this section's group, and all the sections
+   which define symbols to which it refers.  */
 
 static boolean
 elf_gc_mark (info, sec, gc_mark_hook)
@@ -6888,12 +6889,19 @@ elf_gc_mark (info, sec, gc_mark_hook)
        PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Rela *,
 		struct elf_link_hash_entry *, Elf_Internal_Sym *));
 {
-  boolean ret = true;
+  boolean ret;
+  asection *group_sec;
 
   sec->gc_mark = 1;
 
-  /* Look through the section relocs.  */
+  /* Mark all the sections in the group.  */
+  group_sec = elf_section_data (sec)->next_in_group;
+  if (group_sec && !group_sec->gc_mark)
+    if (!elf_gc_mark (info, group_sec, gc_mark_hook))
+      return false;
 
+  /* Look through the section relocs.  */
+  ret = true;
   if ((sec->flags & SEC_RELOC) != 0 && sec->reloc_count > 0)
     {
       Elf_Internal_Rela *relstart, *rel, *relend;
Index: bfd/elfxx-target.h
===================================================================
RCS file: /cvs/src/src/bfd/elfxx-target.h,v
retrieving revision 1.31
diff -u -p -r1.31 elfxx-target.h
--- elfxx-target.h	2001/09/29 06:21:59	1.31
+++ elfxx-target.h	2001/10/09 05:03:57
@@ -495,7 +495,7 @@ const bfd_target TARGET_BIG_SYM =
   /* section_flags: mask of all section flags */
   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY
    | SEC_CODE | SEC_DATA | SEC_DEBUGGING | SEC_EXCLUDE | SEC_SORT_ENTRIES
-   | SEC_ARCH_BIT_0 | SEC_SMALL_DATA | SEC_MERGE | SEC_STRINGS),
+   | SEC_ARCH_BIT_0 | SEC_SMALL_DATA | SEC_MERGE | SEC_STRINGS | SEC_GROUP),
 
    /* leading_symbol_char: is the first char of a user symbol
       predictable, and if so what is it */
@@ -591,7 +591,7 @@ const bfd_target TARGET_LITTLE_SYM =
   /* section_flags: mask of all section flags */
   (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY
    | SEC_CODE | SEC_DATA | SEC_DEBUGGING | SEC_EXCLUDE | SEC_SORT_ENTRIES
-   | SEC_ARCH_BIT_0 | SEC_SMALL_DATA | SEC_MERGE | SEC_STRINGS),
+   | SEC_ARCH_BIT_0 | SEC_SMALL_DATA | SEC_MERGE | SEC_STRINGS | SEC_GROUP),
 
    /* leading_symbol_char: is the first char of a user symbol
       predictable, and if so what is it */
Index: bfd/section.c
===================================================================
RCS file: /cvs/src/src/bfd/section.c,v
retrieving revision 1.36
diff -u -p -r1.36 section.c
--- section.c	2001/09/29 12:07:00	1.36
+++ section.c	2001/10/09 05:04:00
@@ -177,7 +177,7 @@ CODE_FRAGMENT
 .
 .  int id;
 .
-.  {* Which section is it; 0..nth.  *}
+.  {* Which section in the bfd; 0..n-1 as sections are created in a bfd.  *}
 .
 .  int index;
 .
@@ -292,9 +292,10 @@ CODE_FRAGMENT
 .     objects are to be further relocated.  *}
 .#define SEC_EXCLUDE 0x40000
 .
-.  {* The contents of this section are to be sorted by the
-.     based on the address specified in the associated symbol
-.     table.  *}
+.  {* The contents of this section are to be sorted based on the sum of
+.     the symbol and addend values specified by the associated relocation
+.     entries.  Entries without associated relocation entries will be
+.     appended to the end of the section in an unspecified order.  *}
 .#define SEC_SORT_ENTRIES 0x80000
 .
 .  {* When linking, duplicate sections of the same name should be
@@ -361,6 +362,9 @@ CODE_FRAGMENT
 .     size entries.  *}
 .#define SEC_STRINGS 0x40000000
 .
+.  {* This section contains data about section groups.  *}
+.#define SEC_GROUP 0x80000000
+.
 .  {*  End of section flags.  *}
 .
 .  {* Some internal packed boolean fields.  *}
@@ -381,7 +385,8 @@ CODE_FRAGMENT
 .  {* A mark flag used by some linker backends for garbage collection.  *}
 .  unsigned int gc_mark : 1;
 .
-.  {* Used by the ELF code to mark sections which have been allocated to segments.  *}
+.  {* Used by the ELF code to mark sections which have been allocated
+.     to segments.  *}
 .  unsigned int segment_mark : 1;
 .
 .  {* End of internal packed boolean fields.  *}
Index: gas/config/obj-elf.c
===================================================================
RCS file: /cvs/src/src/gas/config/obj-elf.c,v
retrieving revision 1.41
diff -u -p -r1.41 obj-elf.c
--- obj-elf.c	2001/10/07 06:16:54	1.41
+++ obj-elf.c	2001/10/09 05:04:03
@@ -58,6 +58,7 @@ static void elf_s_set_align PARAMS ((sym
 static void elf_s_set_other PARAMS ((symbolS *, int));
 static int elf_sec_sym_ok_for_reloc PARAMS ((asection *));
 static void adjust_stab_sections PARAMS ((bfd *, asection *, PTR));
+static void build_group_lists PARAMS ((bfd *, asection *, PTR));
 static int elf_separate_stab_sections PARAMS ((void));
 static void elf_init_stab_section PARAMS ((segT));
 
@@ -74,7 +75,8 @@ static void obj_elf_ident PARAMS ((int))
 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 ((char *, int, int, int, int));
+static void obj_elf_change_section
+  PARAMS ((const char *, int, int, int, const char *, 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));
@@ -618,9 +620,13 @@ static struct special_section const spec
 };
 
 static void
-obj_elf_change_section (name, type, attr, entsize, push)
-     char *name;
-     int type, attr, entsize, push;
+obj_elf_change_section (name, type, attr, entsize, group, push)
+     const char *name;
+     int type;
+     int attr;
+     int entsize;
+     const char *group;
+     int push;
 {
   asection *old_sec;
   segT sec;
@@ -706,6 +712,7 @@ obj_elf_change_section (name, type, attr
       bfd_set_section_flags (stdoutput, sec, flags);
       if (flags & SEC_MERGE)
 	sec->entsize = entsize;
+      elf_section_data (sec)->group = group;
 
       /* Add a symbol for this section to the symbol table.  */
       secsym = symbol_find (name);
@@ -725,6 +732,9 @@ obj_elf_change_section (name, type, attr
 	as_warn (_("ignoring changed section attributes for %s"), name);
       else 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_section_data (old_sec)->group, group) != 0)
+	as_warn (_("ignoring new section group for %s"), name);
     }
 
 #ifdef md_elf_section_change_hook
@@ -758,6 +768,9 @@ obj_elf_parse_section_letters (str, len)
 	case 'S':
 	  attr |= SHF_STRINGS;
 	  break;
+	case 'G':
+	  attr |= SHF_GROUP;
+	  break;
 	/* Compatibility.  */
 	case 'm':
 	  if (*(str - 1) == 'a')
@@ -772,7 +785,7 @@ obj_elf_parse_section_letters (str, len)
 	    }
 	default:
 	  {
-	    char *bad_msg = _("unrecognized .section attribute: want a,w,x,M,S");
+	    char *bad_msg = _("unrecognized .section attribute: want a,w,x,M,S,G");
 #ifdef md_elf_section_letter
 	    int md_attr = md_elf_section_letter (*str, &bad_msg);
 	    if (md_attr >= 0)
@@ -882,7 +895,7 @@ void
 obj_elf_section (push)
      int push;
 {
-  char *name, *beg;
+  char *name, *group, *beg;
   int type, attr, dummy;
   int entsize;
 
@@ -913,6 +926,7 @@ obj_elf_section (push)
     return;
   type = SHT_NULL;
   attr = 0;
+  group = NULL;
   entsize = 0;
 
   if (*input_line_pointer == ',')
@@ -935,6 +949,8 @@ obj_elf_section (push)
 	  if (*input_line_pointer == ',')
 	    {
 	      char c;
+	      char *save = input_line_pointer;
+
 	      ++input_line_pointer;
 	      SKIP_WHITESPACE ();
 	      c = *input_line_pointer;
@@ -955,6 +971,8 @@ obj_elf_section (push)
 		  *input_line_pointer = c;
 		  type = obj_elf_section_type (beg, input_line_pointer - beg);
 		}
+	      else
+		input_line_pointer = save;
 	    }
 
 	  SKIP_WHITESPACE ();
@@ -976,6 +994,19 @@ obj_elf_section (push)
 	      as_warn (_("entity size for SHF_MERGE not specified"));
 	      attr &= ~SHF_MERGE;
 	    }
+
+	  if ((attr & SHF_GROUP) != 0 && *input_line_pointer == ',')
+	    {
+	      ++input_line_pointer;
+	      group = obj_elf_section_name ();
+	      if (group == NULL)
+		attr &= ~SHF_GROUP;
+	    }
+	  else if ((attr & SHF_GROUP) != 0)
+	    {
+	      as_warn (_("group name for SHF_GROUP not specified"));
+	      attr &= ~SHF_GROUP;
+	    }
 	}
       else
 	{
@@ -1005,7 +1036,7 @@ obj_elf_section (push)
 
   demand_empty_rest_of_line ();
 
-  obj_elf_change_section (name, type, attr, entsize, push);
+  obj_elf_change_section (name, type, attr, entsize, group, push);
 }
 
 /* Change to the .data section.  */
@@ -1361,23 +1392,23 @@ void
 elf_copy_symbol_attributes (dest, src)
      symbolS *dest, *src;
 {
-  struct elf_obj_sy *srcelf = symbol_get_obj (src);		
-  struct elf_obj_sy *destelf = symbol_get_obj (dest);		
-  if (srcelf->size)						
-    {								
-      if (destelf->size == NULL)				
-	destelf->size =					
-	  (expressionS *) xmalloc (sizeof (expressionS));	
-      *destelf->size = *srcelf->size;				
-    }								
-  else							
-    {								
-      if (destelf->size != NULL)				
-	free (destelf->size);					
-      destelf->size = NULL;					
-    }								
-  S_SET_SIZE (dest, S_GET_SIZE (src));			
-  S_SET_OTHER (dest, S_GET_OTHER (src));			
+  struct elf_obj_sy *srcelf = symbol_get_obj (src);
+  struct elf_obj_sy *destelf = symbol_get_obj (dest);
+  if (srcelf->size)
+    {
+      if (destelf->size == NULL)
+	destelf->size =
+	  (expressionS *) xmalloc (sizeof (expressionS));
+      *destelf->size = *srcelf->size;
+    }
+  else
+    {
+      if (destelf->size != NULL)
+	free (destelf->size);
+      destelf->size = NULL;
+    }
+  S_SET_SIZE (dest, S_GET_SIZE (src));
+  S_SET_OTHER (dest, S_GET_OTHER (src));
 }
 
 void
@@ -1860,10 +1891,102 @@ elf_frob_symbol (symp, puntp)
 #endif
 }
 
+struct group_list
+{
+  asection **head;		/* Section lists.  */
+  unsigned int *elt_count;	/* Number of sections in each list.  */
+  unsigned int num_group;	/* Number of lists.  */
+};
+
+/* Called via bfd_map_over_sections.  If SEC is a member of a group,
+   add it to a list of sections belonging to the group.  INF is a
+   pointer to a struct group_list, which is where we store the head of
+   each list.  */
+
+static void
+build_group_lists (abfd, sec, inf)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *sec;
+     PTR inf;
+{
+  struct group_list *list = (struct group_list *) inf;
+  const char *group_name = elf_section_data (sec)->group;
+  unsigned int i;
+
+  if (group_name == NULL)
+    return;
+
+  /* If this group already has a list, add the section to the head of
+     the list.  */
+  for (i = 0; i < list->num_group; i++)
+    {
+      if (strcmp (group_name, elf_section_data (list->head[i])->group) == 0)
+	{
+	  elf_section_data (sec)->next_in_group = list->head[i];
+	  list->head[i] = sec;
+	  list->elt_count[i] += 1;
+	  return;
+	}
+    }
+
+  /* New group.  Make the arrays bigger in chunks to minimize calls to
+     realloc.  */
+  i = list->num_group;
+  if ((i & 127) == 0)
+    {
+      unsigned int newsize = i + 128;
+      list->head = xrealloc (list->head, newsize * sizeof (*list->head));
+      list->elt_count = xrealloc (list->elt_count,
+				  newsize * sizeof (*list->elt_count));
+    }
+  list->head[i] = sec;
+  list->elt_count[i] = 1;
+  list->num_group += 1;
+}
+
 void
 elf_frob_file ()
 {
+  struct group_list list;
+  unsigned int i;
+
   bfd_map_over_sections (stdoutput, adjust_stab_sections, (PTR) 0);
+
+  /* Go find section groups.  */
+  list.num_group = 0;
+  list.head = NULL;
+  list.elt_count = NULL;
+  bfd_map_over_sections (stdoutput, build_group_lists, (PTR) &list);
+
+  /* Make the SHT_GROUP sections that describe each section group.  We
+     can't set up the section contents here yet, because elf section
+     indices have yet to be calculated.  elf.c:set_group_contents does
+     the rest of the work.  */
+  for (i = 0; i < list.num_group; i++)
+    {
+      const char *group_name = elf_section_data (list.head[i])->group;
+      asection *s;
+      flagword flags;
+
+      s = subseg_force_new (group_name, 0);
+      flags = SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_GROUP;
+      if (s == NULL
+	  || !bfd_set_section_flags (stdoutput, s, flags)
+	  || !bfd_set_section_alignment (stdoutput, s, 2))
+	{
+	  as_fatal (_("can't create group: %s"),
+		    bfd_errmsg (bfd_get_error ()));
+	}
+
+      /* Pass a pointer to the first section in this group.  This
+	 seems as good a field to use as any;  It's not used otherwise
+	 by the ELF code.  */
+      s->lineno = (alent *) list.head[i];
+
+      s->_raw_size = 4 * (list.elt_count[i] + 1);
+      s->contents = frag_more (s->_raw_size);
+      frag_now->fr_fix = frag_now_fix_octets ();
+    }
 
 #ifdef elf_tc_final_processing
   elf_tc_final_processing ();



More information about the Binutils mailing list