Hi tech --

While doing some ports testing with clang, I came across the binutils bug mentioned here:
http://lists.gnu.org/archive/html/bug-binutils/2004-07/msg00000.html

Below is a backport of the commit mentioned later in the thread. It fixes the issue. I was able to rebuild working kernels and do a full 'make build' on amd64, loongson, and macppc with this patch. But since it affects all archs, testing on the archs I don't have access to will be needed.

OK?

~Brian

Index: elf-bfd.h
===================================================================
RCS file: /cvs/src/gnu/usr.bin/binutils/bfd/elf-bfd.h,v
retrieving revision 1.8
diff -u -p -r1.8 elf-bfd.h
--- elf-bfd.h    2 Nov 2004 20:45:06 -0000    1.8
+++ elf-bfd.h    16 Feb 2013 22:43:53 -0000
@@ -1055,8 +1055,8 @@ struct bfd_elf_section_data
 #define elf_discarded_section(sec)                \
   (!bfd_is_abs_section (sec)                    \
    && bfd_is_abs_section ((sec)->output_section) \
-   && sec->sec_info_type != ELF_INFO_TYPE_MERGE     \
-   && sec->sec_info_type != ELF_INFO_TYPE_JUST_SYMS)
+   && (sec)->sec_info_type != ELF_INFO_TYPE_MERGE              \
+   && (sec)->sec_info_type != ELF_INFO_TYPE_JUST_SYMS)

 #define get_elf_backend_data(abfd) \
   ((const struct elf_backend_data *) (abfd)->xvec->backend_data)
Index: elflink.c
===================================================================
RCS file: /cvs/src/gnu/usr.bin/binutils/bfd/elflink.c,v
retrieving revision 1.9
diff -u -p -r1.9 elflink.c
--- elflink.c    24 Nov 2004 16:55:31 -0000    1.9
+++ elflink.c    16 Feb 2013 22:43:56 -0000
@@ -6239,6 +6239,9 @@ elf_link_output_extsym (struct elf_link_
   return TRUE;
 }

+/* Return TRUE if special handling is done for relocs in SEC against
+   symbols defined in discarded sections.  */
+
 static bfd_boolean
 elf_section_ignore_discarded_relocs (asection *sec)
 {
@@ -6261,6 +6264,26 @@ elf_section_ignore_discarded_relocs (ase
   return FALSE;
 }

+/* Return TRUE if we should complain about a reloc in SEC against a
+   symbol defined in a discarded section.  */
+
+static bfd_boolean
+elf_section_complain_discarded (asection *sec)
+{
+  if (strncmp (".stab", sec->name, 5) == 0
+      && (!sec->name[5] ||
+         (sec->name[5] == '.' && ISDIGIT (sec->name[6]))))
+    return FALSE;
+
+  if (strcmp (".eh_frame", sec->name) == 0)
+    return FALSE;
+
+  if (strcmp (".gcc_except_table", sec->name) == 0)
+    return FALSE;
+
+  return TRUE;
+}
+
 /* Link an input file into the linker output file.  This function
    handles all the sections and relocations of the input file at once.
    This is so that we only have to read the local symbols once, and
@@ -6532,13 +6555,16 @@ elf_link_input_bfd (struct elf_final_lin
       if (!elf_section_ignore_discarded_relocs (o))
         {
           Elf_Internal_Rela *rel, *relend;
+              bfd_boolean complain = elf_section_complain_discarded (o);

           rel = internal_relocs;
           relend = rel + o->reloc_count * bed->s->int_rels_per_ext_rel;
           for ( ; rel < relend; rel++)
         {
           unsigned long r_symndx = rel->r_info >> r_sym_shift;
-          asection *sec;
+          asection **ps, *sec;
+                  struct elf_link_hash_entry *h = NULL;
+                  const char *sym_name;

           if (r_symndx >= locsymcount
               || (elf_bad_symtab (input_bfd)
@@ -6551,79 +6577,70 @@ elf_link_input_bfd (struct elf_final_lin
                  || h->root.type == bfd_link_hash_warning)
             h = (struct elf_link_hash_entry *) h->root.u.i.link;

-              /* Complain if the definition comes from a
-             discarded section.  */
-              sec = h->root.u.def.section;
-              if ((h->root.type == bfd_link_hash_defined
-               || h->root.type == bfd_link_hash_defweak)
-              && elf_discarded_section (sec))
-            {
-              if ((o->flags & SEC_DEBUGGING) != 0)
-                {
-                  BFD_ASSERT (r_symndx != 0);
-                  /* Try to preserve debug information.  */
-                  if ((o->flags & SEC_DEBUGGING) != 0
-                  && sec->kept_section != NULL
-                  && sec->_raw_size == sec->kept_section->_raw_size)
-                h->root.u.def.section
-                  = sec->kept_section;
-                  else
-                memset (rel, 0, sizeof (*rel));
-                }
-              else
-                finfo->info->callbacks->error_handler
-                  (LD_DEFINITION_IN_DISCARDED_SECTION,
-                   _("%T: discarded in section `%s' from %s\n"),
-                   h->root.root.string,
-                   h->root.root.string,
-                   h->root.u.def.section->name,
-                   bfd_archive_filename (h->root.u.def.section->owner));
-            }
-            }
-          else
-            {
-              sec = finfo->sections[r_symndx];
-
-              if (sec != NULL && elf_discarded_section (sec))
-            {
-              if ((o->flags & SEC_DEBUGGING) != 0
-                  || (sec->flags & SEC_LINK_ONCE) != 0)
-                {
-                  BFD_ASSERT (r_symndx != 0);
-                  /* Try to preserve debug information.  */
-                  if ((o->flags & SEC_DEBUGGING) != 0
-                  && sec->kept_section != NULL
-                  && sec->_raw_size == sec->kept_section->_raw_size)
-                finfo->sections[r_symndx]
-                  = sec->kept_section;
-                  else
-                {
-                  rel->r_info &= r_type_mask;
-                  rel->r_addend = 0;
-                }
-                }
-              else
-                {
-                  static int count;
-                  int ok;
-                  char *buf;
-
-                  ok = asprintf (&buf, "local symbol %d",
-                         count++);
-                  if (ok <= 0)
-                buf = (char *) "local symbol";
-                  finfo->info->callbacks->error_handler
-                (LD_DEFINITION_IN_DISCARDED_SECTION,
-                 _("%T: discarded in section `%s' from %s\n"),
-                 buf, buf, sec->name,
-                 bfd_archive_filename (input_bfd));
-                  if (ok != -1)
-                free (buf);
-                }
-            }
-            }
-        }
-        }
+                      if (h->root.type != bfd_link_hash_defined
+                          && h->root.type != bfd_link_hash_defweak)
+                        continue;
+
+                      ps = &h->root.u.def.section;
+                      sym_name = h->root.root.string;
+                    }
+                  else
+                    {
+                      Elf_Internal_Sym *sym = isymbuf + r_symndx;
+                      ps = &finfo->sections[r_symndx];
+                      sym_name = bfd_elf_local_sym_name (input_bfd, sym);
+                    }
+
+                  /* Complain if the definition comes from a
+                     discarded section.  */
+                  if ((sec = *ps) != NULL && elf_discarded_section (sec))
+                    {
+                      if ((o->flags & SEC_DEBUGGING) != 0)
+                        {
+                          BFD_ASSERT (r_symndx != 0);
+
+                          /* Try to preserve debug information.
+                             FIXME: This is quite broken. Modifying
+                             the symbol here means we will be changing
+                             all uses of the symbol, not just those in
+                             debug sections.  The only thing that makes
+                             this half reasonable is that debug sections
+                             tend to come after other sections.  Of
+                             course, that doesn't help with globals.
+                             ??? All link-once sections of the same name
+                             ought to define the same set of symbols, so
+                             it would seem that globals ought to always
+                             be defined in the kept section.  */
+                          if (sec->kept_section != NULL
+ && sec->_cooked_size == sec->kept_section->_cooked_size)
+                            {
+                              *ps = sec->kept_section;
+                              continue;
+                            }
+                        }
+                      else if (complain)
+                        {
+ finfo->info->callbacks->error_handler
+                            (LD_DEFINITION_IN_DISCARDED_SECTION,
+                             _("`%T' referenced in section `%s' of %B: "
+ "defined in discarded section `%s' of %B\n"),
+                             sym_name,
+                             sym_name, o->name, input_bfd,
+                             sec->name, sec->owner);
+                        }
+
+                      /* Remove the symbol reference from the reloc, but
+                         don't kill the reloc completely.  This is so that
+                         a zero value will be written into the section,
+                         which may have non-zero contents put there by the
+                         assembler.  Zero in things like an eh_frame fde
+                         pc_begin allows stack unwinders to recognize the
+                         fde as bogus.  */
+                      rel->r_info &= r_type_mask;
+                      rel->r_addend = 0;
+                    }
+                }
+            }

       /* Relocate the section by invoking a back end routine.


Reply via email to