bfd: ensure that symbols targeted by DWARF relocations are kept in XCOFF
authorClément Chigot <clement.chigot@atos.net>
Thu, 29 Jul 2021 07:50:37 +0000 (09:50 +0200)
committerClément Chigot <clement.chigot@atos.net>
Fri, 30 Jul 2021 06:38:14 +0000 (08:38 +0200)
This patch improves XCOFF garbage collector pass, in order to keep
symbols being referenced only by special sections like DWARF sections.

bfd/
* xcofflink.c (xcoff_mark): Replace SEC_MARK by gc_mark.
Look through relocations even if xcoff_section_data is NULL.
(xcoff_sweep): Check if any sections of a file is kept before
adding its special sections.
Call xcoff_mark for special sessions being kept instead of just
marking them.
(SEC_MARK): Remove
(xcoff_mark_symbol): Replace SEC_MARK by gc_mark.
(xcoff_keep_symbol_p): Likewise.
(bfd_xcoff_size_dynamic_sections): Likewise.
(xcoff_find_tc0): Likewise.

bfd/xcofflink.c

index a00ae895e4149ef1b17b3d18f22735039d51db30..3ca74ce02774f336442f683c329630c2e042b161 100644 (file)
 #undef  STRING_SIZE_SIZE
 #define STRING_SIZE_SIZE 4
 
-/* We reuse the SEC_ROM flag as a mark flag for garbage collection.
-   This flag will only be used on input sections.  */
-
-#define SEC_MARK (SEC_ROM)
-
 /* The list of import files.  */
 
 struct xcoff_import_file
@@ -2880,7 +2875,7 @@ xcoff_mark_symbol (struct bfd_link_info *info, struct xcoff_link_hash_entry *h)
 
       hsec = h->root.u.def.section;
       if (! bfd_is_abs_section (hsec)
-         && (hsec->flags & SEC_MARK) == 0)
+         && hsec->gc_mark == 0)
        {
          if (! xcoff_mark (info, hsec))
            return false;
@@ -2888,7 +2883,7 @@ xcoff_mark_symbol (struct bfd_link_info *info, struct xcoff_link_hash_entry *h)
     }
 
   if (h->toc_section != NULL
-      && (h->toc_section->flags & SEC_MARK) == 0)
+      && h->toc_section->gc_mark == 0)
     {
       if (! xcoff_mark (info, h->toc_section))
        return false;
@@ -2931,17 +2926,21 @@ static bool
 xcoff_mark (struct bfd_link_info *info, asection *sec)
 {
   if (bfd_is_const_section (sec)
-      || (sec->flags & SEC_MARK) != 0)
+      || sec->gc_mark != 0)
+    return true;
+
+  sec->gc_mark = 1;
+
+  if (sec->owner->xvec != info->output_bfd->xvec)
+    return true;
+
+  if (coff_section_data (sec->owner, sec) == NULL)
     return true;
 
-  sec->flags |= SEC_MARK;
 
-  if (sec->owner->xvec == info->output_bfd->xvec
-      && coff_section_data (sec->owner, sec) != NULL
-      && xcoff_section_data (sec->owner, sec) != NULL)
+  if (xcoff_section_data (sec->owner, sec) != NULL)
     {
       struct xcoff_link_hash_entry **syms;
-      struct internal_reloc *rel, *relend;
       asection **csects;
       unsigned long i, first, last;
 
@@ -2958,64 +2957,67 @@ xcoff_mark (struct bfd_link_info *info, asection *sec)
            if (!xcoff_mark_symbol (info, syms[i]))
              return false;
          }
+    }
+
+  /* Look through the section relocs.  */
+  if ((sec->flags & SEC_RELOC) != 0
+      && sec->reloc_count > 0)
+    {
+      struct internal_reloc *rel, *relend;
 
-      /* Look through the section relocs.  */
-      if ((sec->flags & SEC_RELOC) != 0
-         && sec->reloc_count > 0)
+      rel = xcoff_read_internal_relocs (sec->owner, sec, true,
+                                       NULL, false, NULL);
+      if (rel == NULL)
+       return false;
+      relend = rel + sec->reloc_count;
+      for (; rel < relend; rel++)
        {
-         rel = xcoff_read_internal_relocs (sec->owner, sec, true,
-                                           NULL, false, NULL);
-         if (rel == NULL)
-           return false;
-         relend = rel + sec->reloc_count;
-         for (; rel < relend; rel++)
-           {
-             struct xcoff_link_hash_entry *h;
+         struct xcoff_link_hash_entry *h;
 
-             if ((unsigned int) rel->r_symndx
-                 > obj_raw_syment_count (sec->owner))
-               continue;
+         if ((unsigned int) rel->r_symndx
+             > obj_raw_syment_count (sec->owner))
+           continue;
 
-             h = obj_xcoff_sym_hashes (sec->owner)[rel->r_symndx];
-             if (h != NULL)
-               {
-                 if ((h->flags & XCOFF_MARK) == 0)
-                   {
-                     if (!xcoff_mark_symbol (info, h))
-                       return false;
-                   }
-               }
-             else
+         h = obj_xcoff_sym_hashes (sec->owner)[rel->r_symndx];
+         if (h != NULL)
+           {
+             if ((h->flags & XCOFF_MARK) == 0)
                {
-                 asection *rsec;
-
-                 rsec = xcoff_data (sec->owner)->csects[rel->r_symndx];
-                 if (rsec != NULL
-                     && (rsec->flags & SEC_MARK) == 0)
-                   {
-                     if (!xcoff_mark (info, rsec))
-                       return false;
-                   }
+                 if (!xcoff_mark_symbol (info, h))
+                   return false;
                }
+           }
+         else
+           {
+             asection *rsec;
 
-             /* See if this reloc needs to be copied into the .loader
-                section.  */
-             if (xcoff_need_ldrel_p (info, rel, h, sec))
+             rsec = xcoff_data (sec->owner)->csects[rel->r_symndx];
+             if (rsec != NULL
+                 && rsec->gc_mark == 0)
                {
-                 ++xcoff_hash_table (info)->ldrel_count;
-                 if (h != NULL)
-                   h->flags |= XCOFF_LDREL;
+                 if (!xcoff_mark (info, rsec))
+                   return false;
                }
            }
 
-         if (! info->keep_memory
-             && coff_section_data (sec->owner, sec) != NULL
-             && ! coff_section_data (sec->owner, sec)->keep_relocs)
+         /* See if this reloc needs to be copied into the .loader
+            section.  */
+         if ((sec->flags & SEC_DEBUGGING) == 0
+             && xcoff_need_ldrel_p (info, rel, h, sec))
            {
-             free (coff_section_data (sec->owner, sec)->relocs);
-             coff_section_data (sec->owner, sec)->relocs = NULL;
+             ++xcoff_hash_table (info)->ldrel_count;
+             if (h != NULL)
+               h->flags |= XCOFF_LDREL;
            }
        }
+
+      if (! info->keep_memory
+         && coff_section_data (sec->owner, sec) != NULL
+         && ! coff_section_data (sec->owner, sec)->keep_relocs)
+       {
+         free (coff_section_data (sec->owner, sec)->relocs);
+         coff_section_data (sec->owner, sec)->relocs = NULL;
+       }
     }
 
   return true;
@@ -3035,27 +3037,52 @@ xcoff_sweep (struct bfd_link_info *info)
   for (sub = info->input_bfds; sub != NULL; sub = sub->link.next)
     {
       asection *o;
+      bool some_kept = false;
+
+      /* As says below keep all sections from non-XCOFF
+         input files.  */
+      if (sub->xvec != info->output_bfd->xvec)
+       some_kept = true;
+      else
+       {
+         /* See whether any section is already marked.  */
+         for (o = sub->sections; o != NULL; o = o->next)
+           if (o->gc_mark)
+             some_kept = true;
+       }
 
+      /* If no section in this file will be kept, then we can
+        toss out debug sections.  */
+      if (!some_kept)
+       {
+         for (o = sub->sections; o != NULL; o = o->next)
+           {
+             o->size = 0;
+             o->reloc_count = 0;
+           }
+         continue;
+       }
+
+      /* Keep all sections from non-XCOFF input files.  Keep
+        special sections.  Keep .debug sections for the
+        moment.  */
       for (o = sub->sections; o != NULL; o = o->next)
        {
-         if ((o->flags & SEC_MARK) == 0)
+         if (o->gc_mark == 1)
+           continue;
+
+         if (sub->xvec != info->output_bfd->xvec
+             || o == xcoff_hash_table (info)->debug_section
+             || o == xcoff_hash_table (info)->loader_section
+             || o == xcoff_hash_table (info)->linkage_section
+             || o == xcoff_hash_table (info)->descriptor_section
+             || (bfd_section_flags (o) & SEC_DEBUGGING)
+             || strcmp (o->name, ".debug") == 0)
+           xcoff_mark (info, o);
+         else
            {
-             /* Keep all sections from non-XCOFF input files.  Keep
-                special sections.  Keep .debug sections for the
-                moment.  */
-             if (sub->xvec != info->output_bfd->xvec
-                 || o == xcoff_hash_table (info)->debug_section
-                 || o == xcoff_hash_table (info)->loader_section
-                 || o == xcoff_hash_table (info)->linkage_section
-                 || o == xcoff_hash_table (info)->descriptor_section
-                 || (bfd_section_flags (o) & SEC_DEBUGGING)
-                 || strcmp (o->name, ".debug") == 0)
-               o->flags |= SEC_MARK;
-             else
-               {
-                 o->size = 0;
-                 o->reloc_count = 0;
-               }
+             o->size = 0;
+             o->reloc_count = 0;
            }
        }
     }
@@ -3457,7 +3484,7 @@ xcoff_keep_symbol_p (struct bfd_link_info *info, bfd *input_bfd,
   if (xcoff_hash_table (info)->gc
       && !bfd_is_abs_section (csect)
       && !bfd_is_und_section (csect)
-      && (csect->flags & SEC_MARK) == 0)
+      && csect->gc_mark == 0)
     return 0;
 
   /* An XCOFF linker always removes C_STAT symbols.  */
@@ -3769,7 +3796,7 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd,
                 (a) one of the input files did or (b) we end up
                 creating TOC references as part of the link process.  */
              if (o != xcoff_hash_table (info)->toc_section
-                 && (o->flags & SEC_MARK) == 0)
+                 && o->gc_mark == 0)
                {
                  if (! xcoff_mark (info, o))
                    goto error_return;
@@ -3806,7 +3833,7 @@ bfd_xcoff_size_dynamic_sections (bfd *output_bfd,
 
       if (sec != NULL
          && gc
-         && (sec->flags & SEC_MARK) == 0)
+         && sec->gc_mark == 0)
        sec = NULL;
 
       special_sections[i] = sec;
@@ -5103,7 +5130,7 @@ xcoff_find_tc0 (bfd *output_bfd, struct xcoff_final_link_info *flinfo)
        input_bfd != NULL;
        input_bfd = input_bfd->link.next)
     for (sec = input_bfd->sections; sec != NULL; sec = sec->next)
-      if ((sec->flags & SEC_MARK) != 0 && xcoff_toc_section_p (sec))
+      if (sec->gc_mark != 0 && xcoff_toc_section_p (sec))
        {
          start = sec->output_section->vma + sec->output_offset;
          if (toc_start > start)
@@ -5135,7 +5162,7 @@ xcoff_find_tc0 (bfd *output_bfd, struct xcoff_final_link_info *flinfo)
           input_bfd != NULL;
           input_bfd = input_bfd->link.next)
        for (sec = input_bfd->sections; sec != NULL; sec = sec->next)
-         if ((sec->flags & SEC_MARK) != 0 && xcoff_toc_section_p (sec))
+         if (sec->gc_mark != 0 && xcoff_toc_section_p (sec))
            {
              start = sec->output_section->vma + sec->output_offset;
              if (start < best_address