* plugin.c (is_visible_from_outside): New function.
authorDave Korn <dave.korn@artimi.com>
Fri, 19 Nov 2010 03:31:06 +0000 (03:31 +0000)
committerDave Korn <dave.korn@artimi.com>
Fri, 19 Nov 2010 03:31:06 +0000 (03:31 +0000)
(get_symbols): Use it.

ld/ChangeLog
ld/plugin.c

index 7ece09f93f98e25a6988e21e96aaa7fbba1ab2ac..654f94dc1baefbdf9508ebee11d2928cc631c6df 100644 (file)
@@ -1,3 +1,8 @@
+2010-11-19  Dave Korn  <dave.korn.cygwin@gmail.com>
+
+       * plugin.c (is_visible_from_outside): New function.
+       (get_symbols): Use it.
+
 2010-11-16  Jie Zhang  <jie.zhang@analog.com>
 
        * Makefile.am (eelf32bfinfd.c, eelf32bfin.c): Depend on bfin.em.
index ea647886fcc6c87b2bf2c13a556b50c25cb3d8ba..79b39e8b285f811396d6a37212a5893c899ac8a9 100644 (file)
@@ -382,6 +382,43 @@ release_input_file (const void *handle)
   return LDPS_ERR;
 }
 
+/* Return TRUE if a defined symbol might be reachable from outside the
+   universe of claimed objects.  */
+static inline bfd_boolean
+is_visible_from_outside (struct ld_plugin_symbol *lsym, asection *section,
+                       struct bfd_link_hash_entry *blhe)
+{
+  /* 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))
+    return TRUE;
+  if (link_info.relocatable)
+    return TRUE;
+  if (link_info.export_dynamic || link_info.shared)
+    {
+      /* Only ELF symbols really have visibility.  */
+      if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour)
+       {
+         struct elf_link_hash_entry *el = (struct elf_link_hash_entry *)blhe;
+         int vis = ELF_ST_VISIBILITY (el->other);
+         return vis == STV_DEFAULT || vis == STV_PROTECTED;
+       }
+      /* On non-ELF targets, we can safely make inferences by considering
+         what visibility the plugin would have liked to apply when it first
+        sent us the symbol.  During ELF symbol processing, visibility only
+        ever becomes more restrictive, not less, when symbols are merged,
+        so this is a conservative estimate; it may give false positives,
+        declaring something visible from outside when it in fact would
+        not have been, but this will only lead to missed optimisation
+        opportunities during LTRANS at worst; it will not give false
+        negatives, which can lead to the disastrous conclusion that the
+        related symbol is IRONLY.  (See GCC PR46319 for an example.)  */
+      return lsym->visibility == LDPV_DEFAULT
+         || lsym->visibility == LDPV_PROTECTED;
+    }
+  return FALSE;
+}
+
 /* Get the symbol resolution info for a plugin-claimed input file.  */
 static enum ld_plugin_status
 get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
@@ -393,6 +430,7 @@ get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
     {
       struct bfd_link_hash_entry *blhe;
       bfd_boolean ironly;
+      asection *owner_sec;
 
       blhe = bfd_link_hash_lookup (link_info.hash, syms[n].name,
                                FALSE, FALSE, TRUE);
@@ -418,17 +456,25 @@ get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
                called_plugin->name, blhe->type);
        }
 
-      /* We need to know if the sym is referenced from non-IR files.  */
-      ironly = !bfd_hash_lookup (non_ironly_hash, syms[n].name, FALSE, FALSE);
+      /* Find out which section owns the symbol.  Since it's not undef,
+        it must have an owner; if it's not a common symbol, both defs
+        and weakdefs keep it in the same place. */
+      owner_sec = (blhe->type == bfd_link_hash_common)
+               ? blhe->u.c.p->section
+               : blhe->u.def.section;
+
+      /* We need to know if the sym is referenced from non-IR files.  Or
+         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);
 
       /* If it was originally undefined or common, then it has been
          resolved; determine how.  */
       if (syms[n].def == LDPK_UNDEF || syms[n].def == LDPK_WEAKUNDEF
          || syms[n].def == LDPK_COMMON)
        {
-         asection *owner_sec = (blhe->type == bfd_link_hash_common)
-                               ? blhe->u.c.p->section
-                               : blhe->u.def.section;
          if (owner_sec->owner == link_info.output_bfd)
            syms[n].resolution = LDPR_RESOLVED_EXEC;
          else if (owner_sec->owner == abfd)
@@ -447,9 +493,9 @@ get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
       /* Was originally def, or weakdef.  Does it prevail?  If the
          owner is the original dummy bfd that supplied it, then this
         is the definition that has prevailed.  */
-      if (blhe->u.def.section->owner == link_info.output_bfd)
+      if (owner_sec->owner == link_info.output_bfd)
        syms[n].resolution = LDPR_PREEMPTED_REG;
-      else if (blhe->u.def.section->owner == abfd)
+      else if (owner_sec->owner == abfd)
        {
          syms[n].resolution = (ironly)
                                ? LDPR_PREVAILING_DEF_IRONLY
@@ -458,7 +504,7 @@ get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
        }
 
       /* Was originally def, weakdef, or common, but has been pre-empted.  */
-      syms[n].resolution = is_ir_dummy_bfd (blhe->u.def.section->owner)
+      syms[n].resolution = is_ir_dummy_bfd (owner_sec->owner)
                                ? LDPR_PREEMPTED_IR
                                : LDPR_PREEMPTED_REG;
     }