bfd/
[binutils-gdb.git] / ld / plugin.c
index 6afc14baba1e19e26bdf31e0a80113daadc99b79..b285787694b724ad8ea5b23d3074afe2ec159635 100644 (file)
@@ -1,5 +1,5 @@
 /* Plugin control for the GNU linker.
-   Copyright 2010 Free Software Foundation, Inc.
+   Copyright 2010, 2011 Free Software Foundation, Inc.
 
    This file is part of the GNU Binutils.
 
@@ -108,6 +108,9 @@ static bfd_boolean no_more_claiming = FALSE;
    TRUE is returned from the hook.  */
 static bfd_boolean plugin_cached_allow_multiple_defs = FALSE;
 
+/* Call 'cleanup' hook for all plugins at exit.  */
+static void plugin_call_cleanup (void);
+
 /* List of tags to set in the constant leading part of the tv array. */
 static const enum ld_plugin_tag tv_header_tags[] =
 {
@@ -234,6 +237,8 @@ plugin_get_ir_dummy_bfd (const char *name, bfd *srctemplate)
                     srctemplate);
   bfd_set_arch_info (abfd, bfd_get_arch_info (srctemplate));
   bfd_make_writable (abfd);
+  bfd_copy_private_bfd_data (srctemplate, abfd);
+  bfd_set_gp_size (abfd, bfd_get_gp_size (abfd));
   /* Create a minimal set of sections to own the symbols.  */
   sec = bfd_make_section_old_way (abfd, ".text");
   bfd_set_section_flags (abfd, sec,
@@ -307,10 +312,31 @@ asymbol_from_plugin_symbol (bfd *abfd, asymbol *asym,
   if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
     {
       elf_symbol_type *elfsym = elf_symbol_from (abfd, asym);
+      unsigned char visibility;
+
       if (!elfsym)
-       einfo (_("%P%F: %s: non-ELF symbol in ELF BFD!"), asym->name);
-      elfsym->internal_elf_sym.st_other &= ~3;
-      elfsym->internal_elf_sym.st_other |= ldsym->visibility;
+       einfo (_("%P%F: %s: non-ELF symbol in ELF BFD!\n"), asym->name);
+      switch (ldsym->visibility)
+       {
+       default:
+         einfo (_("%P%F: unknown ELF symbol visibility: %d!\n"),
+                ldsym->visibility);
+       case LDPV_DEFAULT:
+         visibility = STV_DEFAULT;
+         break;
+       case LDPV_PROTECTED:
+         visibility = STV_PROTECTED;
+         break;
+       case LDPV_INTERNAL:
+         visibility = STV_INTERNAL;
+         break;
+       case LDPV_HIDDEN:
+         visibility = STV_HIDDEN;
+         break;
+       }
+      elfsym->internal_elf_sym.st_other
+       = (visibility | (elfsym->internal_elf_sym.st_other
+                        & ~ELF_ST_VISIBILITY (-1)));
     }
 
   return LDPS_OK;
@@ -416,8 +442,8 @@ is_visible_from_outside (struct ld_plugin_symbol *lsym, asection *section,
         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 (lsym->visibility == LDPV_DEFAULT
+             || lsym->visibility == LDPV_PROTECTED);
     }
   return FALSE;
 }
@@ -455,7 +481,7 @@ get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
          && blhe->type != bfd_link_hash_common)
        {
          /* We should not have a new, indirect or warning symbol here.  */
-         einfo ("%P%F: %s: plugin symbol table corrupt (sym type %d)",
+         einfo ("%P%F: %s: plugin symbol table corrupt (sym type %d)\n",
                 called_plugin->name, blhe->type);
        }
 
@@ -487,7 +513,8 @@ get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
                                  : LDPR_PREVAILING_DEF);
          else if (is_ir_dummy_bfd (owner_sec->owner))
            syms[n].resolution = LDPR_RESOLVED_IR;
-         else if (owner_sec->owner->flags & DYNAMIC)
+         else if (owner_sec->owner != NULL
+                  && (owner_sec->owner->flags & DYNAMIC) != 0)
            syms[n].resolution =  LDPR_RESOLVED_DYN;
          else
            syms[n].resolution = LDPR_RESOLVED_EXEC;
@@ -558,17 +585,22 @@ message (int level, const char *format, ...)
     {
     case LDPL_INFO:
       vfinfo (stdout, format, args, FALSE);
+      putchar ('\n');
       break;
     case LDPL_WARNING:
       vfinfo (stdout, format, args, TRUE);
+      putchar ('\n');
       break;
     case LDPL_FATAL:
     case LDPL_ERROR:
     default:
        {
-         char *newfmt = ACONCAT ((level == LDPL_FATAL ? "%F" : "%X",
-                                  format, NULL));
+         char *newfmt = ACONCAT ((level == LDPL_FATAL
+                                  ? "%P%F: " : "%P%X: ",
+                                  format, "\n", NULL));
+         fflush (stdout);
          vfinfo (stderr, newfmt, args, TRUE);
+         fflush (stderr);
        }
       break;
     }
@@ -689,6 +721,8 @@ plugin_load_plugins (void)
   if (!curplug)
     return 0;
 
+  xatexit (plugin_call_cleanup);
+
   /* First pass over plugins to find max # args needed so that we
      can size and allocate the tv array.  */
   while (curplug)
@@ -785,8 +819,8 @@ plugin_call_all_symbols_read (void)
   return plugin_error_p () ? -1 : 0;
 }
 
-/* Call 'cleanup' hook for all plugins.  */
-int
+/* Call 'cleanup' hook for all plugins at exit.  */
+static void
 plugin_call_cleanup (void)
 {
   plugin_t *curplug = plugins_list;
@@ -805,7 +839,9 @@ plugin_call_cleanup (void)
        }
       curplug = curplug->next;
     }
-  return plugin_error_p () ? -1 : 0;
+  if (plugin_error_p ())
+    info_msg (_("%P: %s: error in plugin cleanup (ignored)\n"),
+             plugin_error_plugin ());
 }
 
 /* Lazily init the non_ironly hash table.  */
@@ -848,7 +884,7 @@ plugin_notice (struct bfd_link_info *info ATTRIBUTE_UNUSED,
       /* 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"),
+       einfo (_("%P%X: %s: hash table failure adding symbol %s\n"),
               abfd->filename, name);
     }
   else if (!is_ref && is_dummy)
@@ -881,10 +917,10 @@ plugin_multiple_definition (struct bfd_link_info *info, const char *name,
       struct bfd_link_hash_entry *blhe
        = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, FALSE);
       if (!blhe)
-       einfo (_("%P%X: %s: can't find IR symbol '%s'"), nbfd->filename,
+       einfo (_("%P%X: %s: can't find IR symbol '%s'\n"), nbfd->filename,
               name);
       else if (blhe->type != bfd_link_hash_defined)
-       einfo (_("%P%x: %s: bad IR symbol type %d"), name, blhe->type);
+       einfo (_("%P%x: %s: bad IR symbol type %d\n"), name, blhe->type);
       /* Replace it with new details.  */
       blhe->u.def.section = nsec;
       blhe->u.def.value = nval;