PR ld/12365
authorAlan Modra <amodra@gmail.com>
Sun, 24 Apr 2011 10:02:14 +0000 (10:02 +0000)
committerAlan Modra <amodra@gmail.com>
Sun, 24 Apr 2011 10:02:14 +0000 (10:02 +0000)
PR ld/12696
include/
* bfdlink.h (ENUM_BITFIELD): Define.
(struct bfd_link_hash_entry): Make "type" a bitfield.  Add "non_ir_ref".
(struct bfd_link_callbacks <notice>): Pass bfd_link_hash_entry pointer
rather than "name".
bfd/
* coff-aux.c (coff_m68k_aux_link_add_one_symbol): Update "notice" call.
* linker.c (_bfd_link_hash_newfunc): Clear bitfields.
(_bfd_generic_link_add_one_symbol): Update "notice" call.
* elflink.c (_bfd_elf_merge_symbol): Don't skip weak redefs when
it is a redef of an IR symbol in a real BFD.
ld/
* ldmain.c (notice): Delete "name" param, add "h".
* plugin.c (plugin_notice): Likewise.  Set non_ir_ref.  Handle
redefinitions of IR symbols in real BFDs.
(plugin_multiple_definition, plugin_multiple_common): Delete.
(non_ironly_hash, init_non_ironly_hash): Delete.
(is_visible_from_outside): Traverse entry_symbol chain.
(get_symbols): Use non_ir_ref flag rather than hash lookup.

bfd/ChangeLog
bfd/coff-aux.c
bfd/elflink.c
bfd/linker.c
include/ChangeLog
include/bfdlink.h
ld/ChangeLog
ld/ldmain.c
ld/plugin.c

index cc10c522ff4370d3823953d8d529a6dc9b7e00b4..ad71e254cce08edba8ba2b1579e08d7f979ba704 100644 (file)
@@ -1,3 +1,13 @@
+2011-04-24  Alan Modra  <amodra@gmail.com>
+
+       PR ld/12365
+       PR ld/12696
+       * coff-aux.c (coff_m68k_aux_link_add_one_symbol): Update "notice" call.
+       * linker.c (_bfd_link_hash_newfunc): Clear bitfields.
+       (_bfd_generic_link_add_one_symbol): Update "notice" call.
+       * elflink.c (_bfd_elf_merge_symbol): Don't skip weak redefs when
+       it is a redef of an IR symbol in a real BFD.
+
 2011-04-22  H.J. Lu  <hongjiu.lu@intel.com>
 
        * elf32-i386.c (elf_i386_readonly_dynrelocs): Warn relocation
index af1db03836dad232c08fba8837ee514216d69ce5..20a680ca4dd641e473be9091f3248c8a536a5e1f 100644 (file)
@@ -1,5 +1,5 @@
 /* BFD back-end for Apple M68K COFF A/UX 3.x files.
-   Copyright 1996, 1997, 2000, 2002, 2005, 2007, 2008
+   Copyright 1996, 1997, 2000, 2002, 2005, 2007, 2008, 2011
    Free Software Foundation, Inc.
    Written by Richard Henderson <rth@tamu.edu>.
 
@@ -105,7 +105,7 @@ coff_m68k_aux_link_add_one_symbol (info, abfd, name, flags, section, value,
          && (bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE)
              != (struct bfd_hash_entry *) NULL))
        {
-         if (! (*info->callbacks->notice) (info, name, abfd, section, value))
+         if (! (*info->callbacks->notice) (info, h, abfd, section, value))
            return FALSE;
        }
 
index 3a4d22c4cf873e8591417f5dee4dfcd09b23609b..082355d72e83b4e3de05dbe26fc9ce5c5b959612 100644 (file)
@@ -1427,7 +1427,10 @@ _bfd_elf_merge_symbol (bfd *abfd,
   /* Skip weak definitions of symbols that are already defined.  */
   if (newdef && olddef && newweak)
     {
-      *skip = TRUE;
+      /* Don't skip new non-IR weak syms.  */
+      if (!((oldbfd->flags & BFD_PLUGIN) != 0
+           && (abfd->flags & BFD_PLUGIN) == 0))
+       *skip = TRUE;
 
       /* Merge st_other.  If the symbol already has a dynamic index,
         but visibility says it should not be visible, turn it into a
index 9f2bac3c44f4771278931b3cbc8ad3f9e7234111..d7ac067824866465aec47e19179e6676d1d507ef 100644 (file)
@@ -465,10 +465,8 @@ _bfd_link_hash_newfunc (struct bfd_hash_entry *entry,
       struct bfd_link_hash_entry *h = (struct bfd_link_hash_entry *) entry;
 
       /* Initialize the local fields.  */
-      h->type = bfd_link_hash_new;
-      memset (&h->u.undef.next, 0,
-             (sizeof (struct bfd_link_hash_entry)
-              - offsetof (struct bfd_link_hash_entry, u.undef.next)));
+      memset ((char *) &h->root + sizeof (h->root), 0,
+             sizeof (*h) - sizeof (h->root));
     }
 
   return entry;
@@ -1609,8 +1607,7 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
       || (info->notice_hash != NULL
          && bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE) != NULL))
     {
-      if (! (*info->callbacks->notice) (info, h->root.string, abfd, section,
-                                       value))
+      if (! (*info->callbacks->notice) (info, h, abfd, section, value))
        return FALSE;
     }
 
index bf7128f225f49c97afa972a082674771af151c17..634b21ceb900d10e5149ea3e543e9adbdc18a44c 100644 (file)
@@ -1,3 +1,12 @@
+2011-04-24  Alan Modra  <amodra@gmail.com>
+
+       PR ld/12365
+       PR ld/12696
+       * bfdlink.h (ENUM_BITFIELD): Define.
+       (struct bfd_link_hash_entry): Make "type" a bitfield.  Add "non_ir_ref".
+       (struct bfd_link_callbacks <notice>): Pass bfd_link_hash_entry pointer
+       rather than "name".
+
 2011-04-20  Alan Modra  <amodra@gmail.com>
 
        PR ld/12365
index 7cfaea08e0d7cadd86a6e33b5a59963d1fc7a25c..4c649d9395b196cf9d1970aff1bf97a8be47c2c3 100644 (file)
 #ifndef BFDLINK_H
 #define BFDLINK_H
 
+#if (__GNUC__ * 1000 + __GNUC_MINOR__ > 2000)
+#define ENUM_BITFIELD(TYPE) __extension__ enum TYPE
+#else
+#define ENUM_BITFIELD(TYPE) unsigned int
+#endif
+
 /* Which symbols to strip during a link.  */
 enum bfd_link_strip
 {
@@ -91,7 +97,9 @@ struct bfd_link_hash_entry
   struct bfd_hash_entry root;
 
   /* Type of this entry.  */
-  enum bfd_link_hash_type type;
+  ENUM_BITFIELD (bfd_link_hash_type) type : 8;
+
+  unsigned int non_ir_ref : 1;
 
   /* A union of information depending upon the type.  */
   union
@@ -570,11 +578,11 @@ struct bfd_link_callbacks
     (struct bfd_link_info *, const char *name,
      bfd *abfd, asection *section, bfd_vma address);
   /* A function which is called when a symbol in notice_hash is
-     defined or referenced.  NAME is the symbol.  ABFD, SECTION and
-     ADDRESS are the value of the symbol.  If SECTION is
+     defined or referenced.  H is the symbol.  ABFD, SECTION and
+     ADDRESS are the (new) value of the symbol.  If SECTION is
      bfd_und_section, this is a reference.  */
   bfd_boolean (*notice)
-    (struct bfd_link_info *, const char *name,
+    (struct bfd_link_info *, struct bfd_link_hash_entry *h,
      bfd *abfd, asection *section, bfd_vma address);
   /* Error or warning link info message.  */
   void (*einfo)
index bb1724983f2471d8811dc1a9c870f99c91c83157..b25a87f14780662e35e038fd025409a284fbb3b0 100644 (file)
@@ -1,3 +1,15 @@
+2011-04-24  Alan Modra  <amodra@gmail.com>
+
+       PR ld/12365
+       PR ld/12696
+       * ldmain.c (notice): Delete "name" param, add "h".
+       * plugin.c (plugin_notice): Likewise.  Set non_ir_ref.  Handle
+       redefinitions of IR symbols in real BFDs.
+       (plugin_multiple_definition, plugin_multiple_common): Delete.
+       (non_ironly_hash, init_non_ironly_hash): Delete.
+       (is_visible_from_outside): Traverse entry_symbol chain.
+       (get_symbols): Use non_ir_ref flag rather than hash lookup.
+
 2011-04-21  Tristan Gingold  <gingold@adacore.com>
 
        * scripttempl/alphavms.sc: Add dwarf2 embedding marks.
index 0de78903bbb2df358347cca3ed69c3523b70e372..bfa6066b097a93b4ac63bd00219be96c6b0dd8cd 100644 (file)
@@ -150,7 +150,8 @@ static bfd_boolean reloc_dangerous
 static bfd_boolean unattached_reloc
   (struct bfd_link_info *, const char *, bfd *, asection *, bfd_vma);
 static bfd_boolean notice
-  (struct bfd_link_info *, const char *, bfd *, asection *, bfd_vma);
+  (struct bfd_link_info *, struct bfd_link_hash_entry *,
+   bfd *, asection *, bfd_vma);
 
 static struct bfd_link_callbacks link_callbacks =
 {
@@ -1479,18 +1480,21 @@ unattached_reloc (struct bfd_link_info *info ATTRIBUTE_UNUSED,
 
 static bfd_boolean
 notice (struct bfd_link_info *info,
-       const char *name,
+       struct bfd_link_hash_entry *h,
        bfd *abfd,
        asection *section,
        bfd_vma value)
 {
-  if (name == NULL)
+  const char *name;
+
+  if (h == NULL)
     {
       if (command_line.cref || nocrossref_list != NULL)
        return handle_asneeded_cref (abfd, (enum notice_asneeded_action) value);
       return TRUE;
     }
 
+  name = h->root.string;
   if (info->notice_hash != NULL
       && bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE) != NULL)
     {
index f45064efb270cf35d622454ec58b128ef6e3f551..8d9603bb9d727e0285c6499f485e41ffd20ff2be 100644 (file)
@@ -90,13 +90,6 @@ static plugin_t *called_plugin = NULL;
 /* Last plugin to cause an error, if any.  */
 static const char *error_plugin = NULL;
 
-/* A hash table that records symbols referenced by non-IR files.  Used
-   at get_symbols time to determine whether any prevailing defs from
-   IR files are referenced only from other IR files, so tthat we can
-   we can distinguish the LDPR_PREVAILING_DEF and LDPR_PREVAILING_DEF_IRONLY
-   cases when establishing symbol resolutions.  */
-static struct bfd_hash_table *non_ironly_hash = NULL;
-
 /* State of linker "notice" interface before we poked at it.  */
 static bfd_boolean orig_notice_all;
 
@@ -133,18 +126,8 @@ static const size_t tv_header_size = ARRAY_SIZE (tv_header_tags);
 
 /* Forward references.  */
 static bfd_boolean plugin_notice (struct bfd_link_info *info,
-                                 const char *name, bfd *abfd,
+                                 struct bfd_link_hash_entry *h, bfd *abfd,
                                  asection *section, bfd_vma value);
-static bfd_boolean plugin_multiple_definition (struct bfd_link_info *info,
-                                              struct bfd_link_hash_entry *h,
-                                              bfd *nbfd,
-                                              asection *nsec,
-                                              bfd_vma nval);
-static bfd_boolean plugin_multiple_common (struct bfd_link_info *info,
-                                          struct bfd_link_hash_entry *h,
-                                          bfd *nbfd,
-                                          enum bfd_link_hash_type ntype,
-                                          bfd_vma nsize);
 
 #if !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H)
 
@@ -438,6 +421,8 @@ static inline bfd_boolean
 is_visible_from_outside (struct ld_plugin_symbol *lsym, asection *section,
                         struct bfd_link_hash_entry *blhe)
 {
+  struct bfd_sym_chain *sym;
+
   /* Section's owner may be NULL if it is the absolute
      section, fortunately is_ir_dummy_bfd handles that.  */
   if (!is_ir_dummy_bfd (section->owner))
@@ -466,6 +451,12 @@ is_visible_from_outside (struct ld_plugin_symbol *lsym, asection *section,
       return (lsym->visibility == LDPV_DEFAULT
              || lsym->visibility == LDPV_PROTECTED);
     }
+
+  for (sym = &entry_symbol; sym != NULL; sym = sym->next)
+    if (sym->name
+       && strcmp (sym->name, blhe->root.string) == 0)
+      return TRUE;
+
   return FALSE;
 }
 
@@ -520,9 +511,8 @@ get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
         even potentially-referenced, perhaps in a future final link if
         this is a partial one, perhaps dynamically at load-time if the
         symbol is externally visible.  */
-      ironly = (!is_visible_from_outside (&syms[n], owner_sec, blhe)
-               && !bfd_hash_lookup (non_ironly_hash, syms[n].name,
-                                    FALSE, FALSE));
+      ironly = !(blhe->non_ir_ref
+                || is_visible_from_outside (&syms[n], owner_sec, blhe));
 
       /* If it was originally undefined or common, then it has been
         resolved; determine how.  */
@@ -740,27 +730,6 @@ plugin_active_plugins_p (void)
   return plugins_list != NULL;
 }
 
-/* Init the non_ironly hash table.  */
-static void
-init_non_ironly_hash (void)
-{
-  struct bfd_sym_chain *sym;
-
-  non_ironly_hash
-    = (struct bfd_hash_table *) xmalloc (sizeof (struct bfd_hash_table));
-  if (!bfd_hash_table_init_n (non_ironly_hash,
-                             bfd_hash_newfunc,
-                             sizeof (struct bfd_hash_entry),
-                             61))
-    einfo (_("%P%F: bfd_hash_table_init failed: %E\n"));
-
-  for (sym = &entry_symbol; sym != NULL; sym = sym->next)
-    if (sym->name
-       && !bfd_hash_lookup (non_ironly_hash, sym->name, TRUE, TRUE))
-      einfo (_("%P%X: hash table failure adding symbol %s\n"),
-            sym->name);
-}
-
 /* Load up and initialise all plugins after argument parsing.  */
 int
 plugin_load_plugins (void)
@@ -814,7 +783,6 @@ plugin_load_plugins (void)
   plugin_callbacks.notice = &plugin_notice;
   link_info.notice_all = TRUE;
   link_info.callbacks = &plugin_callbacks;
-  init_non_ironly_hash ();
 
   return 0;
 }
@@ -888,9 +856,6 @@ plugin_call_all_symbols_read (void)
   /* Disable any further file-claiming.  */
   no_more_claiming = TRUE;
 
-  plugin_callbacks.multiple_definition = &plugin_multiple_definition;
-  plugin_callbacks.multiple_common = &plugin_multiple_common;
-
   while (curplug)
     {
       if (curplug->all_symbols_read_handler)
@@ -934,88 +899,47 @@ plugin_call_cleanup (void)
 
 /* To determine which symbols should be resolved LDPR_PREVAILING_DEF
    and which LDPR_PREVAILING_DEF_IRONLY, we notice all the symbols as
-   the linker adds them to the linker hash table.  If we see a symbol
-   being referenced from a non-IR file, we add it to the non_ironly hash
-   table.  If we can't find it there at get_symbols time, we know that
-   it was referenced only by IR files.  We have to notice_all symbols,
-   because we won't necessarily know until later which ones will be
-   contributed by IR files.  */
+   the linker adds them to the linker hash table.  Mark those
+   referenced from a non-IR file with non_ir_ref.  We have to
+   notice_all symbols, because we won't necessarily know until later
+   which ones will be contributed by IR files.  */
 static bfd_boolean
 plugin_notice (struct bfd_link_info *info,
-              const char *name,
+              struct bfd_link_hash_entry *h,
               bfd *abfd,
               asection *section,
               bfd_vma value)
 {
-  if (name != NULL)
+  if (h != NULL)
     {
       /* No further processing if this def/ref is from an IR dummy BFD.  */
       if (is_ir_dummy_bfd (abfd))
        return TRUE;
 
-      /* We only care about refs, not defs, indicated by section
-        pointing to the undefined section (according to the bfd
-        linker notice callback interface definition).  */
+      /* If this is a ref, set non_ir_ref.  */
       if (bfd_is_und_section (section))
-       {
-         /* This is a ref from a non-IR file, so note the ref'd
-            symbol in the non-IR-only hash.  */
-         if (!bfd_hash_lookup (non_ironly_hash, name, TRUE, TRUE))
-           einfo (_("%P%X: %s: hash table failure adding symbol %s\n"),
-                  abfd->filename, name);
-       }
+       h->non_ir_ref = TRUE;
+
+      /* Otherwise, it must be a new def.  Ensure any symbol defined
+        in an IR dummy BFD takes on a new value from a real BFD.
+        Weak symbols are not normally overridden by a new weak
+        definition, and strong symbols will normally cause multiple
+        definition errors.  Avoid this by making the symbol appear
+        to be undefined.  */
+      else if (((h->type == bfd_link_hash_defweak
+                || h->type == bfd_link_hash_defined)
+               && is_ir_dummy_bfd (h->u.def.section->owner))
+              || (h->type == bfd_link_hash_common
+                  && is_ir_dummy_bfd (h->u.c.p->section->owner)))
+       h->type = bfd_link_hash_undefweak;
     }
 
   /* Continue with cref/nocrossref/trace-sym processing.  */
-  if (name == NULL
+  if (h == NULL
       || orig_notice_all
       || (info->notice_hash != NULL
-         && bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE) != NULL))
-    return (*orig_callbacks->notice) (info, name, abfd, section, value);
+         && bfd_hash_lookup (info->notice_hash, h->root.string,
+                             FALSE, FALSE) != NULL))
+    return (*orig_callbacks->notice) (info, h, abfd, section, value);
   return TRUE;
 }
-
-/* When we add new object files to the link at all symbols read time,
-   these contain the real code and symbols generated from the IR files,
-   and so duplicate all the definitions already supplied by the dummy
-   IR-only BFDs that we created at claim files time.  We use the linker's
-   multiple-definitions callback hook to fix up the clash, discarding
-   the symbol from the IR-only BFD in favour of the symbol from the
-   real BFD.  We return true if this was not-really-a-clash because
-   we've fixed it up, or anyway if --allow-multiple-definition was in
-   effect (before we disabled it to ensure we got called back).  */
-static bfd_boolean
-plugin_multiple_definition (struct bfd_link_info *info,
-                           struct bfd_link_hash_entry *h,
-                           bfd *nbfd, asection *nsec, bfd_vma nval)
-{
-  if (h->type == bfd_link_hash_defined
-      && is_ir_dummy_bfd (h->u.def.section->owner))
-    {
-      /* Replace it with new details.  */
-      h->u.def.section = nsec;
-      h->u.def.value = nval;
-      return TRUE;
-    }
-
-  return (*orig_callbacks->multiple_definition) (info, h, nbfd, nsec, nval);
-}
-
-static bfd_boolean
-plugin_multiple_common (struct bfd_link_info *info,
-                       struct bfd_link_hash_entry *h,
-                       bfd *nbfd, enum bfd_link_hash_type ntype, bfd_vma nsize)
-{
-  if (h->type == bfd_link_hash_common
-      && is_ir_dummy_bfd (h->u.c.p->section->owner)
-      && ntype == bfd_link_hash_common
-      && !is_ir_dummy_bfd (nbfd))
-    {
-      /* Arrange to have it replaced.  */
-      ASSERT (nsize != 0);
-      h->u.c.size = 0;
-      return TRUE;
-    }
-
-  return (*orig_callbacks->multiple_common) (info, h, nbfd, ntype, nsize);
-}