Change ld "notice" interface for better handling of indirect symbols
authorAlan Modra <amodra@gmail.com>
Tue, 12 Aug 2014 01:13:33 +0000 (10:43 +0930)
committerAlan Modra <amodra@gmail.com>
Tue, 12 Aug 2014 11:17:36 +0000 (20:47 +0930)
The main aim of this change was to have non_ir_ref set correctly on
new indirect symbols.  I could have added a "copy" param to the "notice"
function, so that indirect symbols could be created in plugin_notice,
but it seemed cleaner to create indirect syms earlier and pass them
rather than "string" to "notice".

include/
* bfdlink.h (struct bfd_link_callbacks <notice>): Remove "string"
param, add "inh".
bfd/
* coff-aux.c (coff_m68k_aux_link_add_one_symbol): Only call "notice"
here when not calling the generic add_symbol function.  Formatting.
Correct handling of indirect symbols.  Update notice call.
* elflink.c (_bfd_elf_notice_as_needed): Update notice call.
* linker.c (_bfd_generic_link_add_one_symbol): Create indirect
symbols early.  Update notice call.  Add comments regarding weak
symbols vs. indirect.
ld/
* ldmain.c (notice): Update args.
* plugin.c (plugin_notice): Likewise.  Follow warning sym link.
Handle new indirect symbol.

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 e2855ad518271fc2fc1dcf578d2df4f4133ee218..8fda279f7c92926843c5648bda5cd17278594a56 100644 (file)
@@ -1,3 +1,13 @@
+2014-08-12  Alan Modra  <amodra@gmail.com>
+
+       * coff-aux.c (coff_m68k_aux_link_add_one_symbol): Only call "notice"
+       here when not calling the generic add_symbol function.  Formatting.
+       Correct handling of indirect symbols.  Update notice call.
+       * elflink.c (_bfd_elf_notice_as_needed): Update notice call.
+       * linker.c (_bfd_generic_link_add_one_symbol): Create indirect
+       symbols early.  Update notice call.  Add comments regarding weak
+       symbols vs. indirect.
+
 2014-08-12  Alan Modra  <amodra@gmail.com>
 
        PR ld/16746
index e79c77ae50424cf8cccd9d5f3d566609dd727e18..d95b98bc65c7f24c75c6f458e9f2a6220a7af1a1 100644 (file)
@@ -73,20 +73,17 @@ coff_m68k_aux_link_add_one_symbol (struct bfd_link_info *info,
                                   bfd_boolean collect,
                                   struct bfd_link_hash_entry **hashp)
 {
-  struct bfd_link_hash_entry *h;
+  struct bfd_link_hash_entry *h, *inh, *t;
 
-  if ((flags & (BSF_WARNING | BSF_CONSTRUCTOR | BSF_WEAK)) == 0 &&
-      !bfd_is_und_section (section) &&
-      !bfd_is_com_section (section))
+  if ((flags & (BSF_WARNING | BSF_CONSTRUCTOR | BSF_WEAK)) == 0
+      && !bfd_is_und_section (section)
+      && !bfd_is_com_section (section))
     {
       /* The new symbol is a definition or an indirect definition */
 
       /* This bit copied from linker.c */
       if (hashp != NULL && *hashp != NULL)
-       {
-         h = *hashp;
-         BFD_ASSERT (strcmp (h->root.string, name) == 0);
-       }
+       h = *hashp;
       else
        {
          h = bfd_link_hash_lookup (info->hash, name, TRUE, copy, FALSE);
@@ -98,37 +95,46 @@ coff_m68k_aux_link_add_one_symbol (struct bfd_link_info *info,
            }
        }
 
-      if (info->notice_hash != (struct bfd_hash_table *) NULL
-         && (bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE)
-             != (struct bfd_hash_entry *) NULL))
-       {
-         if (! (*info->callbacks->notice) (info, h, abfd, section, value,
-                                           flags, string))
-           return FALSE;
-       }
-
       if (hashp != (struct bfd_link_hash_entry **) NULL)
        *hashp = h;
       /* end duplication from linker.c */
 
-      if (h->type == bfd_link_hash_defined
-         || h->type == bfd_link_hash_indirect)
+      t = h;
+      inh = NULL;
+      if (h->type == bfd_link_hash_indirect)
        {
-         asection *msec;
+         inh = h->u.i.link;
+         t = inh;
+       }
 
-         if (h->type == bfd_link_hash_defined)
-           msec = h->u.def.section;
-         else
-           msec = bfd_ind_section_ptr;
+      if (t->type == bfd_link_hash_defined)
+       {
+         asection *msec = t->u.def.section;
+         bfd_boolean special = FALSE;
 
          if (bfd_is_abs_section (msec) && !bfd_is_abs_section (section))
            {
-             h->u.def.section = section;
-             h->u.def.value = value;
-             return TRUE;
+             t->u.def.section = section;
+             t->u.def.value = value;
+             special = TRUE;
            }
          else if (bfd_is_abs_section (section) && !bfd_is_abs_section (msec))
-           return TRUE;
+           special = TRUE;
+
+         if (special)
+           {
+             if (info->notice_all
+                 || (info->notice_hash != NULL
+                     && bfd_hash_lookup (info->notice_hash, name,
+                                         FALSE, FALSE) != NULL))
+               {
+                 if (!(*info->callbacks->notice) (info, h, inh,
+                                                  abfd, section, value, flags))
+                   return FALSE;
+               }
+
+             return TRUE;
+           }
        }
     }
 
index 69a87a6b44b5e4209b9009568e38a49c3d657835..de0a734c99ac7781946d2657f5cf934747514fb0 100644 (file)
@@ -3299,7 +3299,7 @@ _bfd_elf_notice_as_needed (bfd *ibfd,
                           struct bfd_link_info *info,
                           enum notice_asneeded_action act)
 {
-  return (*info->callbacks->notice) (info, NULL, ibfd, NULL, act, 0, NULL);
+  return (*info->callbacks->notice) (info, NULL, NULL, ibfd, NULL, act, 0);
 }
 
 /* Add symbols from an ELF object file to the linker hash table.  */
index 1a5ecef8480279f7dc9e43f5014bcce35551de95..abdf5b0e2645cbc169ade263088e4c597516aad4 100644 (file)
@@ -1442,13 +1442,23 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
 {
   enum link_row row;
   struct bfd_link_hash_entry *h;
+  struct bfd_link_hash_entry *inh = NULL;
   bfd_boolean cycle;
 
   BFD_ASSERT (section != NULL);
 
   if (bfd_is_ind_section (section)
       || (flags & BSF_INDIRECT) != 0)
-    row = INDR_ROW;
+    {
+      row = INDR_ROW;
+      /* Create the indirect symbol here.  This is for the benefit of
+        the plugin "notice" function.
+        STRING is the name of the symbol we want to indirect to.  */
+      inh = bfd_wrapped_link_hash_lookup (abfd, info, string, TRUE,
+                                         copy, FALSE);
+      if (inh == NULL)
+       return FALSE;
+    }
   else if ((flags & BSF_WARNING) != 0)
     row = WARN_ROW;
   else if ((flags & BSF_CONSTRUCTOR) != 0)
@@ -1493,8 +1503,8 @@ _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,
-                                       abfd, section, value, flags, string))
+      if (! (*info->callbacks->notice) (info, h, inh,
+                                       abfd, section, value, flags))
        return FALSE;
     }
 
@@ -1728,44 +1738,40 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info,
            return FALSE;
          /* Fall through.  */
        case IND:
-         /* Create an indirect symbol.  */
-         {
-           struct bfd_link_hash_entry *inh;
-
-           /* STRING is the name of the symbol we want to indirect
-              to.  */
-           inh = bfd_wrapped_link_hash_lookup (abfd, info, string, TRUE,
-                                               copy, FALSE);
-           if (inh == NULL)
+         if (inh->type == bfd_link_hash_indirect
+             && inh->u.i.link == h)
+           {
+             (*_bfd_error_handler)
+               (_("%B: indirect symbol `%s' to `%s' is a loop"),
+                abfd, name, string);
+             bfd_set_error (bfd_error_invalid_operation);
              return FALSE;
-           if (inh->type == bfd_link_hash_indirect
-               && inh->u.i.link == h)
-             {
-               (*_bfd_error_handler)
-                 (_("%B: indirect symbol `%s' to `%s' is a loop"),
-                  abfd, name, string);
-               bfd_set_error (bfd_error_invalid_operation);
-               return FALSE;
-             }
-           if (inh->type == bfd_link_hash_new)
-             {
-               inh->type = bfd_link_hash_undefined;
-               inh->u.undef.abfd = abfd;
-               bfd_link_add_undef (info->hash, inh);
-             }
+           }
+         if (inh->type == bfd_link_hash_new)
+           {
+             inh->type = bfd_link_hash_undefined;
+             inh->u.undef.abfd = abfd;
+             bfd_link_add_undef (info->hash, inh);
+           }
 
-           /* If the indirect symbol has been referenced, we need to
-              push the reference down to the symbol we are
-              referencing.  */
-           if (h->type != bfd_link_hash_new)
-             {
-               row = UNDEF_ROW;
-               cycle = TRUE;
-             }
+         /* If the indirect symbol has been referenced, we need to
+            push the reference down to the symbol we are referencing.  */
+         if (h->type != bfd_link_hash_new)
+           {
+             /* ??? If inh->type == bfd_link_hash_undefweak this
+                converts inh to bfd_link_hash_undefined.  */
+             row = UNDEF_ROW;
+             cycle = TRUE;
+           }
 
-           h->type = bfd_link_hash_indirect;
-           h->u.i.link = inh;
-         }
+         h->type = bfd_link_hash_indirect;
+         h->u.i.link = inh;
+         /* Not setting h = h->u.i.link here means that when cycle is
+            set above we'll always go to REFC, and then cycle again
+            to the indirected symbol.  This means that any successful
+            change of an existing symbol to indirect counts as a
+            reference.  ??? That may not be correct when the existing
+            symbol was defweak.  */
          break;
 
        case SET:
index 75c218ce558f9528a8a3a6ff01caecdbb1399997..f13af307a6446fc8bd837fd5b6d13bebcad92210 100644 (file)
@@ -1,3 +1,8 @@
+2014-08-12  Alan Modra  <amodra@gmail.com>
+
+       * bfdlink.h (struct bfd_link_callbacks <notice>): Remove "string"
+       param, add "inh".
+
 2014-08-12  Alan Modra  <amodra@gmail.com>
 
        * bfdlink.h (struct bfd_link_info): Add lto_plugin_active.
index 58dba2a1724f86d61234c6a43130e2a2821abb22..125683db8673ec4ec74ab2df692b0ca821f3e0a9 100644 (file)
@@ -640,15 +640,14 @@ 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.  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.  FLAGS are the symbol
-     BSF_* flags.  STRING is the name of the symbol to indirect to if
-     the sym is indirect, or the warning string if a warning sym.  */
+     defined or referenced.  H is the symbol, INH the indirect symbol
+     if applicable.  ABFD, SECTION and ADDRESS are the (new) value of
+     the symbol.  If SECTION is bfd_und_section, this is a reference.
+     FLAGS are the symbol BSF_* flags.  */
   bfd_boolean (*notice)
     (struct bfd_link_info *, struct bfd_link_hash_entry *h,
-     bfd *abfd, asection *section, bfd_vma address, flagword flags,
-     const char *string);
+     struct bfd_link_hash_entry *inh,
+     bfd *abfd, asection *section, bfd_vma address, flagword flags);
   /* Error or warning link info message.  */
   void (*einfo)
     (const char *fmt, ...);
index 9f194ea7e8dcea6717571fbf609fe05c18ead932..ade3a40725278b81abbbc641a40587cfbaa8eaf5 100644 (file)
@@ -1,3 +1,9 @@
+2014-08-12  Alan Modra  <amodra@gmail.com>
+
+       * ldmain.c (notice): Update args.
+       * plugin.c (plugin_notice): Likewise.  Follow warning sym link.
+       Handle new indirect symbol.
+
 2014-08-12  Alan Modra  <amodra@gmail.com>
 
        * plugin.c (plugin_load_plugins): Set link_info.lto_plugin_active.
index ea25afe4f444e1bea43d831d030452784c1738f2..77235d522168e5292792e930994f84c33400d720 100644 (file)
@@ -137,7 +137,7 @@ static bfd_boolean unattached_reloc
   (struct bfd_link_info *, const char *, bfd *, asection *, bfd_vma);
 static bfd_boolean notice
   (struct bfd_link_info *, struct bfd_link_hash_entry *,
-   bfd *, asection *, bfd_vma, flagword, const char *);
+   struct bfd_link_hash_entry *, bfd *, asection *, bfd_vma, flagword);
 
 static struct bfd_link_callbacks link_callbacks =
 {
@@ -1461,11 +1461,11 @@ unattached_reloc (struct bfd_link_info *info ATTRIBUTE_UNUSED,
 static bfd_boolean
 notice (struct bfd_link_info *info,
        struct bfd_link_hash_entry *h,
+       struct bfd_link_hash_entry *inh ATTRIBUTE_UNUSED,
        bfd *abfd,
        asection *section,
        bfd_vma value,
-       flagword flags ATTRIBUTE_UNUSED,
-       const char *string ATTRIBUTE_UNUSED)
+       flagword flags ATTRIBUTE_UNUSED)
 {
   const char *name;
 
index 8d6ae05123af33e3ca714c2c5979ee14f9644171..8cca7d02c6eeff0b203445993b0233aae7b60bd8 100644 (file)
@@ -127,8 +127,9 @@ static const size_t tv_header_size = ARRAY_SIZE (tv_header_tags);
 
 /* Forward references.  */
 static bfd_boolean plugin_notice (struct bfd_link_info *,
-                                 struct bfd_link_hash_entry *, bfd *,
-                                 asection *, bfd_vma, flagword, const char *);
+                                 struct bfd_link_hash_entry *,
+                                 struct bfd_link_hash_entry *,
+                                 bfd *, asection *, bfd_vma, flagword);
 
 #if !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H)
 
@@ -962,16 +963,21 @@ plugin_call_cleanup (void)
 static bfd_boolean
 plugin_notice (struct bfd_link_info *info,
               struct bfd_link_hash_entry *h,
+              struct bfd_link_hash_entry *inh,
               bfd *abfd,
               asection *section,
               bfd_vma value,
-              flagword flags,
-              const char *string)
+              flagword flags)
 {
+  struct bfd_link_hash_entry *orig_h = h;
+
   if (h != NULL)
     {
       bfd *sym_bfd;
 
+      if (h->type == bfd_link_hash_warning)
+       h = h->u.i.link;
+
       /* Nothing to do here if this def/ref is from an IR dummy BFD.  */
       if (is_ir_dummy_bfd (abfd))
        ;
@@ -981,16 +987,15 @@ plugin_notice (struct bfd_link_info *info,
       else if (bfd_is_ind_section (section)
               || (flags & BSF_INDIRECT) != 0)
        {
+         /* ??? Some of this is questionable.  See comments in
+            _bfd_generic_link_add_one_symbol for case IND.  */
          if (h->type != bfd_link_hash_new)
            {
-             struct bfd_link_hash_entry *inh;
-
              h->non_ir_ref = TRUE;
-             inh = bfd_wrapped_link_hash_lookup (abfd, info, string, FALSE,
-                                                 FALSE, FALSE);
-             if (inh != NULL)
-               inh->non_ir_ref = TRUE;
+             inh->non_ir_ref = TRUE;
            }
+         else if (inh->type == bfd_link_hash_new)
+           inh->non_ir_ref = TRUE;
        }
 
       /* Nothing to do here for warning symbols.  */
@@ -1031,13 +1036,13 @@ plugin_notice (struct bfd_link_info *info,
     }
 
   /* Continue with cref/nocrossref/trace-sym processing.  */
-  if (h == NULL
+  if (orig_h == NULL
       || orig_notice_all
       || (info->notice_hash != NULL
-         && bfd_hash_lookup (info->notice_hash, h->root.string,
+         && bfd_hash_lookup (info->notice_hash, orig_h->root.string,
                              FALSE, FALSE) != NULL))
-    return (*orig_callbacks->notice) (info, h,
-                                     abfd, section, value, flags, string);
+    return (*orig_callbacks->notice) (info, orig_h, inh,
+                                     abfd, section, value, flags);
   return TRUE;
 }