Handle __start_* and __stop_* symbols in --gc-sections
authorAlan Modra <amodra@gmail.com>
Fri, 23 Oct 2015 11:53:05 +0000 (22:23 +1030)
committerAlan Modra <amodra@gmail.com>
Fri, 23 Oct 2015 11:56:25 +0000 (22:26 +1030)
PR ld/11133
PR ld/19161
PR ld/19167
* elflink.c (_bfd_elf_gc_mark_hook): Delete code handling __start_*
and __stop_* symbol refs.
(_bfd_elf_gc_mark_rsec): Add start_stop parameter.  Handle __start_*
and __stop_* symbol refs here..
(_bfd_elf_gc_mark_reloc): ..and here.
* elf-bfd.h (_bfd_elf_gc_mark_hook): Update prototype.
* elf-eh-frame.c (_bfd_elf_parse_eh_frame): Update
_bfd_elf_gc_mark_rsec call.

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

index 481d972177f4ad043db813f8b7db253728242981..19723d25af7a8cbaea1a3270963a563c7c57e017 100644 (file)
@@ -1,3 +1,17 @@
+2015-10-23  Alan Modra  <amodra@gmail.com>
+
+       PR ld/11133
+       PR ld/19161
+       PR ld/19167
+       * elflink.c (_bfd_elf_gc_mark_hook): Delete code handling __start_*
+       and __stop_* symbol refs.
+       (_bfd_elf_gc_mark_rsec): Add start_stop parameter.  Handle __start_*
+       and __stop_* symbol refs here..
+       (_bfd_elf_gc_mark_reloc): ..and here.
+       * elf-bfd.h (_bfd_elf_gc_mark_hook): Update prototype.
+       * elf-eh-frame.c (_bfd_elf_parse_eh_frame): Update
+       _bfd_elf_gc_mark_rsec call.
+
 2015-10-23  Alan Modra  <amodra@gmail.com>
 
        PR ld/11133
index b7ca2d0a5d50fc3574784ac042c37cbd96641809..2b05089a5266dd95948320a17efa8615bcd51859 100644 (file)
@@ -2296,7 +2296,7 @@ extern asection *_bfd_elf_gc_mark_hook
 
 extern asection *_bfd_elf_gc_mark_rsec
   (struct bfd_link_info *, asection *, elf_gc_mark_hook_fn,
-   struct elf_reloc_cookie *);
+   struct elf_reloc_cookie *, bfd_boolean *);
 
 extern bfd_boolean _bfd_elf_gc_mark_reloc
   (struct bfd_link_info *, asection *, elf_gc_mark_hook_fn,
index 7d65daefc3736133a472ec044365b9f5f5869ddf..e303189ee4f45036017e73bae5d9d8bc6d2e0a93 100644 (file)
@@ -902,7 +902,8 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info,
              REQUIRE (GET_RELOC (buf));
 
              /* Chain together the FDEs for each section.  */
-             rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie);
+             rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook,
+                                           cookie, NULL);
              /* RSEC will be NULL if FDE was cleared out as it was belonging to
                 a discarded SHT_GROUP.  */
              if (rsec)
index 6dcc43181cbbe333609e3211fedb3a1a4daefea4..1cfdd313569ae80addfe461dfb8f2894d95b5b72 100644 (file)
@@ -12066,8 +12066,6 @@ _bfd_elf_gc_mark_hook (asection *sec,
                       struct elf_link_hash_entry *h,
                       Elf_Internal_Sym *sym)
 {
-  const char *sec_name;
-
   if (h != NULL)
     {
       switch (h->root.type)
@@ -12079,33 +12077,6 @@ _bfd_elf_gc_mark_hook (asection *sec,
        case bfd_link_hash_common:
          return h->root.u.c.p->section;
 
-       case bfd_link_hash_undefined:
-       case bfd_link_hash_undefweak:
-         /* To work around a glibc bug, keep all XXX input sections
-            when there is an as yet undefined reference to __start_XXX
-            or __stop_XXX symbols.  The linker will later define such
-            symbols for orphan input sections that have a name
-            representable as a C identifier.  */
-         if (strncmp (h->root.root.string, "__start_", 8) == 0)
-           sec_name = h->root.root.string + 8;
-         else if (strncmp (h->root.root.string, "__stop_", 7) == 0)
-           sec_name = h->root.root.string + 7;
-         else
-           sec_name = NULL;
-
-         if (sec_name && *sec_name != '\0')
-           {
-             bfd *i;
-
-             for (i = info->input_bfds; i; i = i->link.next)
-               {
-                 sec = bfd_get_section_by_name (i, sec_name);
-                 if (sec)
-                   return sec;
-               }
-           }
-         break;
-
        default:
          break;
        }
@@ -12123,7 +12094,8 @@ _bfd_elf_gc_mark_hook (asection *sec,
 asection *
 _bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec,
                       elf_gc_mark_hook_fn gc_mark_hook,
-                      struct elf_reloc_cookie *cookie)
+                      struct elf_reloc_cookie *cookie,
+                      bfd_boolean *start_stop)
 {
   unsigned long r_symndx;
   struct elf_link_hash_entry *h;
@@ -12152,6 +12124,38 @@ _bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec,
         handling copy relocs.  */
       if (h->u.weakdef != NULL)
        h->u.weakdef->mark = 1;
+
+      if (start_stop != NULL
+         && (h->root.type == bfd_link_hash_undefined
+             || h->root.type == bfd_link_hash_undefweak))
+       {
+         /* To work around a glibc bug, mark all XXX input sections
+            when there is an as yet undefined reference to __start_XXX
+            or __stop_XXX symbols.  The linker will later define such
+            symbols for orphan input sections that have a name
+            representable as a C identifier.  */
+         const char *sec_name = NULL;
+         if (strncmp (h->root.root.string, "__start_", 8) == 0)
+           sec_name = h->root.root.string + 8;
+         else if (strncmp (h->root.root.string, "__stop_", 7) == 0)
+           sec_name = h->root.root.string + 7;
+
+         if (sec_name != NULL && *sec_name != '\0')
+           {
+             bfd *i;
+
+             for (i = info->input_bfds; i != NULL; i = i->link.next)
+               {
+                 asection *s = bfd_get_section_by_name (i, sec_name);
+                 if (s != NULL && !s->gc_mark)
+                   {
+                     *start_stop = TRUE;
+                     return s;
+                   }
+               }
+           }
+       }
+
       return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL);
     }
 
@@ -12170,15 +12174,39 @@ _bfd_elf_gc_mark_reloc (struct bfd_link_info *info,
                        struct elf_reloc_cookie *cookie)
 {
   asection *rsec;
+  bfd_boolean start_stop = FALSE;
 
-  rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie);
-  if (rsec && !rsec->gc_mark)
+  rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie, &start_stop);
+  while (rsec != NULL)
     {
-      if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour
-         || (rsec->owner->flags & DYNAMIC) != 0)
-       rsec->gc_mark = 1;
-      else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
-       return FALSE;
+      asection *s;
+
+      if (!rsec->gc_mark)
+       {
+         if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour
+             || (rsec->owner->flags & DYNAMIC) != 0)
+           rsec->gc_mark = 1;
+         else if (!_bfd_elf_gc_mark (info, rsec, gc_mark_hook))
+           return FALSE;
+       }
+      if (!start_stop)
+       break;
+      s = bfd_get_next_section_by_name (rsec);
+      if (s == NULL)
+       {
+         bfd *i = rsec->owner;
+
+         if (i != NULL)
+           {
+             while ((i = i->link.next) != NULL)
+               {
+                 s = bfd_get_section_by_name (i, rsec->name);
+                 if (s != NULL)
+                   break;
+               }
+           }
+       }
+      rsec = s;
     }
   return TRUE;
 }