[PATCH 4/7] Fix --gc-sections for C++ MIPS ELF

Richard Sandiford rsandifo@nildram.co.uk
Sun Dec 2 20:31:00 GMT 2007


This is the main patch.  The core routine is mark_entry, which "marks
all relocations" against a CIE or FDE ("marking a relocation" being
shorthand for "marking the section in which a relocation's symbol
is defined").

The parsing routines now chain together the FDEs for each code section
into a list, and a new routine called _bfd_elf_gc_mark_fdes marks all
the FDEs for a particular code section.  CIEs are marked when one
their dependent FDEs is marked.

FDEs are only marked once, when their associated section is marked,
so there's no need for them to have a separate gc_mark field.  However,
CIEs might be processed many times, so a gc_mark field does seem
appropriate there.

bfd_elf_gc_sections tries to parse each input .eh_frame section.
It stores the .eh_frame section in a new ELF bfd field called
"eh_frame_section" on success, otherwise the .eh_frame section
is marked like any other section would be.

If eh_frame_section is nonnull, _bfd_elf_gc_mark marks all the FDEs
associated with the section it is marking.  It doesn't process the
relocations in eh_frame_section itself.

Richard


bfd/
	* elf-bfd.h (eh_cie_fde): Add u.fde.next_for_section and
	u.cie.gc_mark.
	(bfd_elf_section_data): Add fde_list.
	(elf_fde_list): New macro.
	(elf_obj_tdata): Add eh_frame_section.
	(elf_eh_frame_section): New macro.
	(_bfd_elf_gc_mark_reloc): Remove last parameter.
	(_bfd_elf_gc_mark_fdes): Declare.
	* elf-eh-frame.c (_bfd_elf_get_eh_frame_sec_info): Chain the FDEs
	for each input section.
	(mark_entry, _bfd_elf_gc_mark_fdes): New functions.
	* elflink.c (_bfd_elf_gc_mark_reloc): Remove is_eh parameter.
	(_bfd_elf_gc_mark): Update call accordingly.  Mark the relocations
	againts the section's FDEs.  Don't mark the bfd's elf_eh_frame_section.
	(bfd_elf_gc_sections): Parse each input bfd's .eh_frame before
	marking any input sections.  Remove the current EH handling.
	* section.c (bfd_section): Remove gc_mark_from_eh.
	* ecoff.c (bfd_debug_section): Update initializer accordingly.

Index: bfd/elf-bfd.h
===================================================================
--- bfd/elf-bfd.h	2007-12-02 17:21:33.000000000 +0000
+++ bfd/elf-bfd.h	2007-12-02 17:22:22.000000000 +0000
@@ -273,6 +273,7 @@ struct eh_cie_fde
 	 the output FDE.  The CIE's REMOVED field is also 0, but the CIE
 	 might belong to a different .eh_frame input section from the FDE.  */
       struct eh_cie_fde *cie_inf;
+      struct eh_cie_fde *next_for_section;
     } fde;
     struct {
       /* In general, equivalent CIEs are grouped together, with one CIE
@@ -281,6 +282,9 @@ struct eh_cie_fde
 	 following this pointer brings us "closer" to the CIE's group
 	 representative, and reapplying always gives the representative.  */
       struct eh_cie_fde *merged;
+
+      /* True if we have marked relocations associated with this CIE.  */
+      unsigned int gc_mark : 1;
     } cie;
   } u;
   unsigned int reloc_index;
@@ -1243,6 +1247,10 @@ struct bfd_elf_section_data
      the linker.  For the SHT_GROUP section, points at first member.  */
   asection *next_in_group;
 
+  /* The FDEs associated with this section.  The u.fde.next_in_section
+     field acts as a chain pointer.  */
+  struct eh_cie_fde *fde_list;
+
   /* A pointer used for various section optimizations.  */
   void *sec_info;
 };
@@ -1254,6 +1262,7 @@ #define elf_section_flags(sec) (elf_sect
 #define elf_group_name(sec)    (elf_section_data(sec)->group.name)
 #define elf_group_id(sec)      (elf_section_data(sec)->group.id)
 #define elf_next_in_group(sec) (elf_section_data(sec)->next_in_group)
+#define elf_fde_list(sec)      (elf_section_data(sec)->fde_list)
 #define elf_sec_group(sec)	(elf_section_data(sec)->sec_group)
 
 #define xvec_get_elf_backend_data(xvec) \
@@ -1459,6 +1468,9 @@ struct elf_obj_tdata
   asection *elf_data_section;
   asection *elf_text_section;
 
+  /* A pointer to the .eh_frame section.  */
+  asection *eh_frame_section;
+
   /* Whether a dyanmic object was specified normally on the linker
      command line, or was specified when --as-needed was in effect,
      or was found via a DT_NEEDED entry.  */
@@ -1504,6 +1516,8 @@ #define elf_dynsymtab(bfd)	(elf_tdata(bf
 #define elf_dynversym(bfd)	(elf_tdata(bfd) -> dynversym_section)
 #define elf_dynverdef(bfd)	(elf_tdata(bfd) -> dynverdef_section)
 #define elf_dynverref(bfd)	(elf_tdata(bfd) -> dynverref_section)
+#define elf_eh_frame_section(bfd) \
+				(elf_tdata(bfd) -> eh_frame_section)
 #define elf_num_locals(bfd)	(elf_tdata(bfd) -> num_locals)
 #define elf_num_globals(bfd)	(elf_tdata(bfd) -> num_globals)
 #define elf_section_syms(bfd)	(elf_tdata(bfd) -> section_syms)
@@ -2004,7 +2018,11 @@ extern void _bfd_elf_set_osabi (bfd * , 
 
 extern bfd_boolean _bfd_elf_gc_mark_reloc
   (struct bfd_link_info *, asection *, elf_gc_mark_hook_fn,
-   struct elf_reloc_cookie *, bfd_boolean);
+   struct elf_reloc_cookie *);
+
+extern bfd_boolean _bfd_elf_gc_mark_fdes
+  (struct bfd_link_info *, asection *, asection *, elf_gc_mark_hook_fn,
+   struct elf_reloc_cookie *);
 
 extern bfd_boolean _bfd_elf_gc_mark
   (struct bfd_link_info *, asection *, elf_gc_mark_hook_fn);
Index: bfd/elf-eh-frame.c
===================================================================
--- bfd/elf-eh-frame.c	2007-12-02 17:03:27.000000000 +0000
+++ bfd/elf-eh-frame.c	2007-12-02 17:26:13.000000000 +0000
@@ -475,6 +475,7 @@ #define REQUIRE(COND)					\
   unsigned int ptr_size;
   unsigned int num_cies;
   unsigned int num_entries;
+  elf_gc_mark_hook_fn gc_mark_hook;
 
   htab = elf_hash_table (info);
   hdr_info = &htab->eh_info;
@@ -577,6 +578,7 @@ #define GET_RELOC(buf)					\
 
   buf = ehbuf;
   ecie_count = 0;
+  gc_mark_hook = get_elf_backend_data (abfd)->gc_mark_hook;
   while ((bfd_size_type) (buf - ehbuf) != sec->size)
     {
       char *aug;
@@ -821,6 +823,8 @@ #define GET_RELOC(buf)					\
 	}
       else
 	{
+	  asection *rsec;
+
 	  /* Find the corresponding CIE.  */
 	  unsigned int cie_offset = this_inf->offset + 4 - hdr_id;
 	  for (ecie = ecies; ecie < ecies + ecie_count; ++ecie)
@@ -836,6 +840,12 @@ #define GET_RELOC(buf)					\
 	  ENSURE_NO_RELOCS (buf);
 	  REQUIRE (GET_RELOC (buf));
 
+	  /* Chain together the FDEs for each section.  */
+	  rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie);
+	  REQUIRE (rsec && rsec->owner == abfd);
+	  this_inf->u.fde.next_for_section = elf_fde_list (rsec);
+	  elf_fde_list (rsec) = this_inf;
+
 	  /* Skip the initial location and address range.  */
 	  start = buf;
 	  length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size);
@@ -976,6 +986,55 @@ _bfd_elf_end_eh_frame_parsing (struct bf
   hdr_info->parsed_eh_frames = TRUE;
 }
 
+/* Mark all relocations against CIE or FDE ENT, which occurs in
+   .eh_frame section SEC.  COOKIE describes the relocations in SEC;
+   its "rel" field can be changed freely.  */
+
+static bfd_boolean
+mark_entry (struct bfd_link_info *info, asection *sec,
+	    struct eh_cie_fde *ent, elf_gc_mark_hook_fn gc_mark_hook,
+	    struct elf_reloc_cookie *cookie)
+{
+  for (cookie->rel = cookie->rels + ent->reloc_index;
+       cookie->rel < cookie->relend
+	 && cookie->rel->r_offset < ent->offset + ent->size;
+       cookie->rel++)
+    if (!_bfd_elf_gc_mark_reloc (info, sec, gc_mark_hook, cookie))
+      return FALSE;
+
+  return TRUE;
+}
+
+/* Mark all the relocations against FDEs that relate to code in input
+   section SEC.  The FDEs belong to .eh_frame section EH_FRAME, whose
+   relocations are described by COOKIE.  */
+
+bfd_boolean
+_bfd_elf_gc_mark_fdes (struct bfd_link_info *info, asection *sec,
+		       asection *eh_frame, elf_gc_mark_hook_fn gc_mark_hook,
+		       struct elf_reloc_cookie *cookie)
+{
+  struct eh_cie_fde *fde, *cie, *merged;
+
+  for (fde = elf_fde_list (sec); fde; fde = fde->u.fde.next_for_section)
+    {
+      if (!mark_entry (info, eh_frame, fde, gc_mark_hook, cookie))
+	return FALSE;
+
+      /* At this stage, all cie_inf fields point to local CIEs, so we
+	 can use the same cookie to refer to them.  */
+      cie = fde->u.fde.cie_inf;
+      merged = cie->u.cie.merged;
+      if (!merged->u.cie.gc_mark)
+	{
+	  merged->u.cie.gc_mark = 1;
+	  if (!mark_entry (info, eh_frame, cie, gc_mark_hook, cookie))
+	    return FALSE;
+	}
+    }
+  return TRUE;
+}
+
 /* This function is called for each input file before the .eh_frame
    section is relocated.  It discards duplicate CIEs and FDEs for discarded
    functions.  The function returns TRUE iff any entries have been
Index: bfd/elflink.c
===================================================================
--- bfd/elflink.c	2007-12-02 17:03:27.000000000 +0000
+++ bfd/elflink.c	2007-12-02 17:22:00.000000000 +0000
@@ -11137,15 +11137,13 @@ _bfd_elf_gc_mark_rsec (struct bfd_link_i
 
 /* COOKIE->rel describes a relocation against section SEC, which is
    a section we've decided to keep.  Mark the section that contains
-   the relocation symbol.  IS_EH is true if the mark comes from
-   .eh_frame.  */
+   the relocation symbol.  */
 
 bfd_boolean
 _bfd_elf_gc_mark_reloc (struct bfd_link_info *info,
 			asection *sec,
 			elf_gc_mark_hook_fn gc_mark_hook,
-			struct elf_reloc_cookie *cookie,
-			bfd_boolean is_eh)
+			struct elf_reloc_cookie *cookie)
 {
   asection *rsec;
 
@@ -11154,8 +11152,6 @@ _bfd_elf_gc_mark_reloc (struct bfd_link_
     {
       if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour)
 	rsec->gc_mark = 1;
-      else if (is_eh)
-	rsec->gc_mark_from_eh = 1;
       else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
 	return FALSE;
     }
@@ -11172,8 +11168,7 @@ _bfd_elf_gc_mark (struct bfd_link_info *
 		  elf_gc_mark_hook_fn gc_mark_hook)
 {
   bfd_boolean ret;
-  bfd_boolean is_eh;
-  asection *group_sec;
+  asection *group_sec, *eh_frame;
 
   sec->gc_mark = 1;
 
@@ -11185,8 +11180,10 @@ _bfd_elf_gc_mark (struct bfd_link_info *
 
   /* Look through the section relocs.  */
   ret = TRUE;
-  is_eh = strcmp (sec->name, ".eh_frame") == 0;
-  if ((sec->flags & SEC_RELOC) != 0 && sec->reloc_count > 0)
+  eh_frame = elf_eh_frame_section (sec->owner);
+  if ((sec->flags & SEC_RELOC) != 0
+      && sec->reloc_count > 0
+      && sec != eh_frame)
     {
       struct elf_reloc_cookie cookie;
 
@@ -11195,8 +11192,7 @@ _bfd_elf_gc_mark (struct bfd_link_info *
       else
 	{
 	  for (; cookie.rel < cookie.relend; cookie.rel++)
-	    if (!_bfd_elf_gc_mark_reloc (info, sec, gc_mark_hook,
-					 &cookie, is_eh))
+	    if (!_bfd_elf_gc_mark_reloc (info, sec, gc_mark_hook, &cookie))
 	      {
 		ret = FALSE;
 		break;
@@ -11204,6 +11200,22 @@ _bfd_elf_gc_mark (struct bfd_link_info *
 	  fini_reloc_cookie_for_section (&cookie, sec);
 	}
     }
+
+  if (ret && eh_frame && elf_fde_list (sec))
+    {
+      struct elf_reloc_cookie cookie;
+
+      if (!init_reloc_cookie_for_section (&cookie, info, eh_frame))
+	ret = FALSE;
+      else
+	{
+	  if (!_bfd_elf_gc_mark_fdes (info, sec, eh_frame,
+				      gc_mark_hook, &cookie))
+	    ret = FALSE;
+	  fini_reloc_cookie_for_section (&cookie, eh_frame);
+	}
+    }
+
   return ret;
 }
 
@@ -11469,6 +11481,25 @@ bfd_elf_gc_sections (bfd *abfd, struct b
       return TRUE;
     }
 
+  /* Try to parse each bfd's .eh_frame section.  Point elf_eh_frame_section
+     at the .eh_frame section if we can mark the FDEs individually.  */
+  _bfd_elf_begin_eh_frame_parsing (info);
+  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+    {
+      asection *sec;
+      struct elf_reloc_cookie cookie;
+
+      sec = bfd_get_section_by_name (sub, ".eh_frame");
+      if (sec && init_reloc_cookie_for_section (&cookie, info, sec))
+	{
+	  _bfd_elf_parse_eh_frame (sub, info, sec, &cookie);
+	  if (elf_section_data (sec)->sec_info)
+	    elf_eh_frame_section (sub) = sec;
+	  fini_reloc_cookie_for_section (&cookie, sec);
+	}
+    }
+  _bfd_elf_end_eh_frame_parsing (info);
+
   /* Apply transitive closure to the vtable entry usage info.  */
   elf_link_hash_traverse (elf_hash_table (info),
 			  elf_gc_propagate_vtable_entries_used,
@@ -11508,68 +11539,6 @@ bfd_elf_gc_sections (bfd *abfd, struct b
   if (bed->gc_mark_extra_sections)
     bed->gc_mark_extra_sections(info, gc_mark_hook);
 
-  /* ... again for sections marked from eh_frame.  */
-  for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
-    {
-      asection *o;
-
-      if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
-	continue;
-
-      /* Keep .gcc_except_table.* if the associated .text.* (or the
-	 associated .gnu.linkonce.t.* if .text.* doesn't exist) is
-	 marked.  This isn't very nice, but the proper solution,
-	 splitting .eh_frame up and using comdat doesn't pan out
-	 easily due to needing special relocs to handle the
-	 difference of two symbols in separate sections.
-	 Don't keep code sections referenced by .eh_frame.  */
-#define TEXT_PREFIX			".text."
-#define TEXT_PREFIX2			".gnu.linkonce.t."
-#define GCC_EXCEPT_TABLE_PREFIX		".gcc_except_table."
-      for (o = sub->sections; o != NULL; o = o->next)
-	if (!o->gc_mark && o->gc_mark_from_eh && (o->flags & SEC_CODE) == 0)
-	  {
-	    if (CONST_STRNEQ (o->name, GCC_EXCEPT_TABLE_PREFIX))
-	      {
-		char *fn_name;
-		const char *sec_name;
-		asection *fn_text;
-		unsigned o_name_prefix_len , fn_name_prefix_len, tmp;
-
-		o_name_prefix_len = strlen (GCC_EXCEPT_TABLE_PREFIX);
-		sec_name = o->name + o_name_prefix_len;
-		fn_name_prefix_len = strlen (TEXT_PREFIX);
-		tmp = strlen (TEXT_PREFIX2);
-		if (tmp > fn_name_prefix_len)
-		  fn_name_prefix_len = tmp;
-		fn_name
-		  = bfd_malloc (fn_name_prefix_len + strlen (sec_name) + 1);
-		if (fn_name == NULL)
-		  return FALSE;
-
-		/* Try the first prefix.  */
-		sprintf (fn_name, "%s%s", TEXT_PREFIX, sec_name);
-		fn_text = bfd_get_section_by_name (sub, fn_name);
-
-		/* Try the second prefix.  */
-		if (fn_text == NULL)
-		  {
-		    sprintf (fn_name, "%s%s", TEXT_PREFIX2, sec_name);
-		    fn_text = bfd_get_section_by_name (sub, fn_name);
-		  }
-
-		free (fn_name);
-		if (fn_text == NULL || !fn_text->gc_mark)
-		  continue;
-	      }
-
-	    /* If not using specially named exception table section,
-	       then keep whatever we are using.  */
-	    if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
-	      return FALSE;
-	  }
-    }
-
   /* ... and mark SEC_EXCLUDE for those that go.  */
   return elf_gc_sweep (abfd, info);
 }
Index: bfd/section.c
===================================================================
--- bfd/section.c	2007-12-02 16:52:51.000000000 +0000
+++ bfd/section.c	2007-12-02 17:21:41.000000000 +0000
@@ -357,9 +357,8 @@ typedef asection, section prototypes, Se
 .     output sections that have an input section.  *}
 .  unsigned int linker_has_input : 1;
 .
-.  {* Mark flags used by some linker backends for garbage collection.  *}
+.  {* Mark flag used by some linker backends for garbage collection.  *}
 .  unsigned int gc_mark : 1;
-.  unsigned int gc_mark_from_eh : 1;
 .
 .  {* The following flags are used by the ELF linker. *}
 .
Index: bfd/ecoff.c
===================================================================
--- bfd/ecoff.c	2007-12-02 16:52:51.000000000 +0000
+++ bfd/ecoff.c	2007-12-02 17:21:41.000000000 +0000
@@ -55,8 +55,8 @@ static asection bfd_debug_section =
 {
   /* name,      id,  index, next, prev, flags, user_set_vma,       */
      "*DEBUG*", 0,   0,     NULL, NULL, 0,     0,
-  /* linker_mark, linker_has_input, gc_mark, gc_mark_from_eh,      */
-     0,           0,                1,       0,
+  /* linker_mark, linker_has_input, gc_mark,                       */
+     0,           0,                1,
   /* segment_mark, sec_info_type, use_rela_p, has_tls_reloc,       */
      0,            0,             0,          0,
   /* has_gp_reloc, need_finalize_relax, reloc_done,                */



More information about the Binutils mailing list