bfd/
authorRichard Sandiford <rdsandiford@googlemail.com>
Sat, 15 Dec 2007 09:34:48 +0000 (09:34 +0000)
committerRichard Sandiford <rdsandiford@googlemail.com>
Sat, 15 Dec 2007 09:34:48 +0000 (09:34 +0000)
* 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.

bfd/ChangeLog
bfd/ecoff.c
bfd/elf-bfd.h
bfd/elf-eh-frame.c
bfd/elflink.c
bfd/section.c

index 54c909b..b1e840e 100644 (file)
@@ -1,5 +1,26 @@
 2007-12-15  Richard Sandiford  <rsandifo@nildram.co.uk>
 
+       * 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.
+
+2007-12-15  Richard Sandiford  <rsandifo@nildram.co.uk>
+
        * elf-bfd.h (eh_cie_fde): Add u.cie.  Document how u.fde.cie_inf
        changes when removed == 0.
        (eh_frame_hdr_info): Add parsed_eh_frames.
index 0bd4add..149df64 100644 (file)
@@ -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,                */
index c91af27..f5fcc6f 100644 (file)
@@ -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 @@ struct bfd_elf_section_data
 #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 @@ struct elf_obj_tdata
 #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 asection *_bfd_elf_gc_mark_rsec
 
 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 63b6ba4..460112c 100644 (file)
@@ -475,6 +475,7 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info,
   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 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info,
 
   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 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info,
        }
       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 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info,
          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 bfd_link_info *info)
   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 4201e28..31c9de9 100644 (file)
@@ -11137,15 +11137,13 @@ _bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec,
 
 /* 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_info *info,
     {
       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 *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 *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 *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 *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 bfd_link_info *info)
       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 bfd_link_info *info)
   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 4ee6c89..11ce0d6 100644 (file)
@@ -357,9 +357,8 @@ CODE_FRAGMENT
 .     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. *}
 .