Fix pr20528 testsuite
[deliverable/binutils-gdb.git] / ld / plugin.c
index 89083db89dd1392ef6565e0fe2200f652f4f3b43..36094dd7c8cb6683e5521601b0768c81a2f8618d 100644 (file)
@@ -1,5 +1,5 @@
 /* Plugin control for the GNU linker.
-   Copyright (C) 2010-2015 Free Software Foundation, Inc.
+   Copyright (C) 2010-2016 Free Software Foundation, Inc.
 
    This file is part of the GNU Binutils.
 
@@ -21,7 +21,6 @@
 #include "sysdep.h"
 #include "libiberty.h"
 #include "bfd.h"
-#include "libbfd.h"
 #include "bfdlink.h"
 #include "bfdver.h"
 #include "ld.h"
@@ -30,8 +29,9 @@
 #include "ldexp.h"
 #include "ldlang.h"
 #include "ldfile.h"
-#include "plugin.h"
 #include "plugin-api.h"
+#include "../bfd/plugin.h"
+#include "plugin.h"
 #include "elf-bfd.h"
 #if HAVE_MMAP
 # include <sys/mman.h>
@@ -174,6 +174,8 @@ static bfd_boolean plugin_notice (struct bfd_link_info *,
                                  struct bfd_link_hash_entry *,
                                  bfd *, asection *, bfd_vma, flagword);
 
+static const bfd_target * plugin_object_p (bfd *);
+
 #if !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H)
 
 #define RTLD_NOW 0     /* Dummy value.  */
@@ -234,6 +236,7 @@ void
 plugin_opt_plugin (const char *plugin)
 {
   plugin_t *newplug;
+  plugin_t *curplug = plugins_list;
 
   newplug = xmalloc (sizeof *newplug);
   memset (newplug, 0, sizeof *newplug);
@@ -242,6 +245,18 @@ plugin_opt_plugin (const char *plugin)
   if (!newplug->dlhandle)
     einfo (_("%P%F: %s: error loading plugin: %s\n"), plugin, dlerror ());
 
+  /* Check if plugin has been loaded already.  */
+  while (curplug)
+    {
+      if (newplug->dlhandle == curplug->dlhandle)
+       {
+         einfo (_("%P: %s: duplicated plugin\n"), plugin);
+         free (newplug);
+         return;
+       }
+      curplug = curplug->next;
+    }
+
   /* Chain on end, so when we run list it is in command-line order.  */
   *plugins_tail_chain_ptr = newplug;
   plugins_tail_chain_ptr = &newplug->next;
@@ -292,17 +307,24 @@ static bfd *
 plugin_get_ir_dummy_bfd (const char *name, bfd *srctemplate)
 {
   bfd *abfd;
+  bfd_boolean bfd_plugin_target;
 
   bfd_use_reserved_id = 1;
+  bfd_plugin_target = bfd_plugin_target_p (srctemplate->xvec);
   abfd = bfd_create (concat (name, IRONLY_SUFFIX, (const char *) NULL),
-                    srctemplate);
+                    bfd_plugin_target ? link_info.output_bfd : srctemplate);
   if (abfd != NULL)
     {
       abfd->flags |= BFD_LINKER_CREATED | BFD_PLUGIN;
-      bfd_set_arch_info (abfd, bfd_get_arch_info (srctemplate));
-      bfd_set_gp_size (abfd, bfd_get_gp_size (srctemplate));
-      if (bfd_make_writable (abfd)
-         && bfd_copy_private_bfd_data (srctemplate, abfd))
+      if (!bfd_make_writable (abfd))
+       goto report_error;
+      if (!bfd_plugin_target)
+       {
+         bfd_set_arch_info (abfd, bfd_get_arch_info (srctemplate));
+         bfd_set_gp_size (abfd, bfd_get_gp_size (srctemplate));
+         if (!bfd_copy_private_bfd_data (srctemplate, abfd))
+           goto report_error;
+       }
        {
          flagword flags;
 
@@ -313,6 +335,7 @@ plugin_get_ir_dummy_bfd (const char *name, bfd *srctemplate)
            return abfd;
        }
     }
+report_error:
   einfo (_("could not create dummy IR bfd: %F%E\n"));
   return NULL;
 }
@@ -602,9 +625,9 @@ is_visible_from_outside (struct ld_plugin_symbol *lsym,
 {
   struct bfd_sym_chain *sym;
 
-  if (link_info.relocatable)
+  if (bfd_link_relocatable (&link_info))
     return TRUE;
-  if (link_info.export_dynamic || !link_info.executable)
+  if (link_info.export_dynamic || bfd_link_dll (&link_info))
     {
       /* Check if symbol is hidden by version script.  */
       if (bfd_hide_sym_by_version (link_info.version_info,
@@ -663,7 +686,24 @@ get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms,
                                             syms[n].name, FALSE, FALSE, TRUE);
       if (!blhe)
        {
-         res = LDPR_UNKNOWN;
+         /* The plugin is called to claim symbols in an archive element
+            from plugin_object_p.  But those symbols aren't needed to
+            create output.  They are defined and referenced only within
+            IR.  */
+         switch (syms[n].def)
+           {
+           default:
+             abort ();
+           case LDPK_UNDEF:
+           case LDPK_WEAKUNDEF:
+             res = LDPR_UNDEF;
+             break;
+           case LDPK_DEF:
+           case LDPK_WEAKDEF:
+           case LDPK_COMMON:
+             res = LDPR_PREVAILING_DEF_IRONLY;
+             break;
+           }
          goto report_symbol;
        }
 
@@ -763,10 +803,14 @@ get_symbols_v2 (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
 static enum ld_plugin_status
 add_input_file (const char *pathname)
 {
+  lang_input_statement_type *is;
+
   ASSERT (called_plugin);
-  if (!lang_add_input_file (xstrdup (pathname), lang_input_file_is_file_enum,
-                           NULL))
+  is = lang_add_input_file (xstrdup (pathname), lang_input_file_is_file_enum,
+                           NULL);
+  if (!is)
     return LDPS_ERR;
+  is->flags.lto_output = 1;
   return LDPS_OK;
 }
 
@@ -774,10 +818,14 @@ add_input_file (const char *pathname)
 static enum ld_plugin_status
 add_input_library (const char *pathname)
 {
+  lang_input_statement_type *is;
+
   ASSERT (called_plugin);
-  if (!lang_add_input_file (xstrdup (pathname), lang_input_file_is_l_enum,
-                           NULL))
+  is = lang_add_input_file (xstrdup (pathname), lang_input_file_is_l_enum,
+                           NULL);
+  if (!is)
     return LDPS_ERR;
+  is->flags.lto_output = 1;
   return LDPS_OK;
 }
 
@@ -805,18 +853,24 @@ message (int level, const char *format, ...)
       putchar ('\n');
       break;
     case LDPL_WARNING:
-      vfinfo (stdout, format, args, TRUE);
-      putchar ('\n');
+      {
+       char *newfmt = concat ("%P: warning: ", format, "\n",
+                              (const char *) NULL);
+       vfinfo (stdout, newfmt, args, TRUE);
+       free (newfmt);
+      }
       break;
     case LDPL_FATAL:
     case LDPL_ERROR:
     default:
       {
-       char *newfmt = ACONCAT ((level == LDPL_FATAL ? "%P%F: " : "%P%X: ",
-                                format, "\n", (const char *) NULL));
+       char *newfmt = concat (level == LDPL_FATAL ? "%P%F" : "%P%X",
+                              ": error: ", format, "\n",
+                              (const char *) NULL);
        fflush (stdout);
        vfinfo (stderr, newfmt, args, TRUE);
        fflush (stderr);
+       free (newfmt);
       }
       break;
     }
@@ -851,11 +905,10 @@ set_tv_header (struct ld_plugin_tv *tv)
          TVU(val) = major * 100 + minor;
          break;
        case LDPT_LINKER_OUTPUT:
-         TVU(val) = (link_info.relocatable
-                     ? LDPO_REL
-                     : (link_info.executable
-                        ? (link_info.pie ? LDPO_PIE : LDPO_EXEC)
-                        : LDPO_DYN));
+         TVU(val) = (bfd_link_relocatable (&link_info) ? LDPO_REL
+                     : bfd_link_pde (&link_info) ? LDPO_EXEC
+                     : bfd_link_pie (&link_info) ? LDPO_PIE
+                     : LDPO_DYN);
          break;
        case LDPT_OUTPUT_NAME:
          TVU(string) = output_filename;
@@ -979,8 +1032,10 @@ plugin_load_plugins (void)
   link_info.lto_plugin_active = TRUE;
   link_info.callbacks = &plugin_callbacks;
 
+  register_ld_plugin_object_p (plugin_object_p);
+
 #if HAVE_MMAP && HAVE_GETPAGESIZE
-  plugin_pagesize = getpagesize ();;
+  plugin_pagesize = getpagesize ();
 #endif
 }
 
@@ -990,15 +1045,18 @@ plugin_call_claim_file (const struct ld_plugin_input_file *file, int *claimed)
 {
   plugin_t *curplug = plugins_list;
   *claimed = FALSE;
-  if (no_more_claiming)
-    return 0;
   while (curplug && !*claimed)
     {
       if (curplug->claim_file_handler)
        {
+         off_t cur_offset;
          enum ld_plugin_status rv;
+
          called_plugin = curplug;
+         cur_offset = lseek (file->fd, 0, SEEK_CUR);
          rv = (*curplug->claim_file_handler) (file, claimed);
+         if (!*claimed)
+           lseek (file->fd, cur_offset, SEEK_SET);
          called_plugin = NULL;
          if (rv != LDPS_OK)
            set_plugin_error (curplug->name);
@@ -1024,22 +1082,25 @@ plugin_strdup (bfd *abfd, const char *str)
   return copy;
 }
 
-void
-plugin_maybe_claim (lang_input_statement_type *entry)
+static const bfd_target *
+plugin_object_p (bfd *ibfd)
 {
-  int claimed = 0;
+  int claimed;
   plugin_input_file_t *input;
-  off_t offset, filesize;
   struct ld_plugin_input_file file;
   bfd *abfd;
-  bfd *ibfd = entry->the_bfd;
-  bfd_boolean inarchive = bfd_my_archive (ibfd) != NULL;
-  const char *name
-    = inarchive ? bfd_my_archive (ibfd)->filename : ibfd->filename;
-  int fd = open (name, O_RDONLY | O_BINARY);
 
-  if (fd < 0)
-    return;
+  /* Don't try the dummy object file.  */
+  if ((ibfd->flags & BFD_PLUGIN) != 0)
+    return NULL;
+
+  if (ibfd->plugin_format != bfd_plugin_unknown)
+    {
+      if (ibfd->plugin_format == bfd_plugin_yes)
+       return ibfd->plugin_dummy_bfd->xvec;
+      else
+       return NULL;
+    }
 
   /* We create a dummy BFD, initially empty, to house whatever symbols
      the plugin may want to add.  */
@@ -1050,69 +1111,59 @@ plugin_maybe_claim (lang_input_statement_type *entry)
     einfo (_("%P%F: plugin failed to allocate memory for input: %s\n"),
           bfd_get_error ());
 
-  if (inarchive)
-    {
-      /* Offset and filesize must refer to the individual archive
-        member, not the whole file, and must exclude the header.
-        Fortunately for us, that is how the data is stored in the
-        origin field of the bfd and in the arelt_data.  */
-      offset = ibfd->origin;
-      filesize = arelt_size (ibfd);
-    }
-  else
-    {
-      offset = 0;
-      filesize = lseek (fd, 0, SEEK_END);
+  if (!bfd_plugin_open_input (ibfd, &file))
+    return NULL;
 
+  if (file.name == ibfd->filename)
+    {
       /* We must copy filename attached to ibfd if it is not an archive
         member since it may be freed by bfd_close below.  */
-      name = plugin_strdup (abfd, name);
+      file.name = plugin_strdup (abfd, file.name);
     }
 
-  file.name = name;
-  file.offset = offset;
-  file.filesize = filesize;
-  file.fd = fd;
   file.handle = input;
+  /* The plugin API expects that the file descriptor won't be closed
+     and reused as done by the bfd file cache.  So dup one.  */
+  file.fd = dup (file.fd);
+  if (file.fd < 0)
+    return NULL;
 
   input->abfd = abfd;
   input->view_buffer.addr = NULL;
   input->view_buffer.filesize = 0;
   input->view_buffer.offset = 0;
-  input->fd = fd;
-  input->offset = offset;
-  input->filesize = filesize;
+  input->fd = file.fd;
+  input->use_mmap = FALSE;
+  input->offset = file.offset;
+  input->filesize = file.filesize;
   input->name = plugin_strdup (abfd, ibfd->filename);
 
+  claimed = 0;
+
   if (plugin_call_claim_file (&file, &claimed))
     einfo (_("%P%F: %s: plugin reported error claiming file\n"),
           plugin_error_plugin ());
 
-  if (input->fd != -1 && ibfd->format == bfd_object)
+  if (input->fd != -1 && !bfd_plugin_target_p (ibfd->xvec))
     {
-      /* FIXME: fd belongs to us, not the plugin.  IR for GCC plugin,
-        which doesn't need fd after plugin_call_claim_file, is
-        stored in bfd_object file.  Since GCC plugin before GCC 5
-        doesn't call release_input_file, we close it here.  IR for
-        LLVM plugin, which needs fd after plugin_call_claim_file and
-        calls release_input_file after it is done, is stored in
-        non-bfd_object file.  This scheme doesn't work when a plugin
-        needs fd and its IR is stored in bfd_object file.  */
-      close (fd);
+      /* FIXME: fd belongs to us, not the plugin.  GCC plugin, which
+        doesn't need fd after plugin_call_claim_file, doesn't use
+        BFD plugin target vector.  Since GCC plugin doesn't call
+        release_input_file, we close it here.  LLVM plugin, which
+        needs fd after plugin_call_claim_file and calls
+        release_input_file after it is done, uses BFD plugin target
+        vector.  This scheme doesn't work when a plugin needs fd and
+        doesn't use BFD plugin target vector neither.  */
+      close (input->fd);
       input->fd = -1;
     }
 
   if (claimed)
     {
-      /* Discard the real file's BFD and substitute the dummy one.  */
-
-      /* BFD archive handling caches elements so we can't call
-        bfd_close for archives.  */
-      if (!inarchive)
-       bfd_close (ibfd);
+      ibfd->plugin_format = bfd_plugin_yes;
+      ibfd->plugin_dummy_bfd = abfd;
       bfd_make_readable (abfd);
-      entry->the_bfd = abfd;
-      entry->flags.claimed = TRUE;
+      return abfd->xvec;
     }
   else
     {
@@ -1133,8 +1184,29 @@ plugin_maybe_claim (lang_input_statement_type *entry)
 
       /* If plugin didn't claim the file, we don't need the dummy bfd.
         Can't avoid speculatively creating it, alas.  */
+      ibfd->plugin_format = bfd_plugin_no;
       bfd_close_all_done (abfd);
-      entry->flags.claimed = FALSE;
+      return NULL;
+    }
+}
+
+void
+plugin_maybe_claim (lang_input_statement_type *entry)
+{
+  if (plugin_object_p (entry->the_bfd))
+    {
+      bfd *abfd = entry->the_bfd->plugin_dummy_bfd;
+
+      /* Discard the real file's BFD and substitute the dummy one.  */
+
+      /* We can't call bfd_close on archives.  BFD archive handling
+        caches elements, and add_archive_element keeps pointers to
+        the_bfd and the_bfd->filename in a lang_input_statement_type
+        linker script statement.  */
+      if (entry->the_bfd->my_archive == NULL)
+       bfd_close (entry->the_bfd);
+      entry->the_bfd = abfd;
+      entry->flags.claimed = 1;
     }
 }
 
@@ -1250,20 +1322,30 @@ plugin_notice (struct bfd_link_info *info,
          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 (sym_bfd = h->u.def.section->owner))
-              || (h->type == bfd_link_hash_common
-                  && is_ir_dummy_bfd (sym_bfd = h->u.c.p->section->owner)))
+      /* Otherwise, it must be a new def.  */
+      else
        {
-         h->type = bfd_link_hash_undefweak;
-         h->u.undef.abfd = sym_bfd;
+         /* A common symbol should be merged with other commons or
+            defs with the same name.  In particular, a common ought
+            to be overridden by a def in a -flto object.  In that
+            sense a common is also a ref.  */
+         if (bfd_is_com_section (section))
+           h->non_ir_ref = TRUE;
+
+         /* 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.  */
+         if (((h->type == bfd_link_hash_defweak
+               || h->type == bfd_link_hash_defined)
+              && is_ir_dummy_bfd (sym_bfd = h->u.def.section->owner))
+             || (h->type == bfd_link_hash_common
+                 && is_ir_dummy_bfd (sym_bfd = h->u.c.p->section->owner)))
+           {
+             h->type = bfd_link_hash_undefweak;
+             h->u.undef.abfd = sym_bfd;
+           }
        }
     }
 
This page took 0.029294 seconds and 4 git commands to generate.