Merge linker plugin handling into BFD plugin support
authorH.J. Lu <hjl.tools@gmail.com>
Wed, 11 Feb 2015 13:01:03 +0000 (05:01 -0800)
committerH.J. Lu <hjl.tools@gmail.com>
Wed, 11 Feb 2015 13:02:12 +0000 (05:02 -0800)
Linker plugin_maybe_claim is the interface of linker plugin support.
This patch extracts linker plugin_maybe_claim into plugin_object_p and
makes it available to BFD via a new function:

void register_ld_plugin_object_p (const bfd_target *(*) (bfd *));

bfd_plugin_object_p calls plugin_object_p registered by linker first.  It
adds an enum bfd_plugin_format field and a pointer to plugin dummy BFD so
that plugin_object_p stores plugin dummy BFD to allow plugin_maybe_claim
to retrieve it later.

bfd/

PR ld/17878
* bfd.c (bfd_plugin_format): New.
(bfd): Add plugin_format and plugin_dummy_bfd.
* plugin.c (try_load_plugin): Take a pointer to bfd_boolean
argument to return TRUE if any plugin is found.  Set plugin_format.
(has_plugin): New.
(bfd_plugin_target_p): New.
(bfd_plugin_specified_p): Likewise.
(bfd_plugin_target_p): Likewise.
(register_ld_plugin_object_p): Likewise.
(bfd_plugin_set_plugin): Set has_plugin.
(load_plugin): Cache try_load_plugin result.
(bfd_plugin_object_p): Try ld_plugin_object_p first.  Check
plugin_format.
* plugin.h (bfd_plugin_target_p): New.
(bfd_plugin_specified_p): Likewise.
(register_ld_plugin_object_p): Likewise.
* bfd-in2.h: Regenerated.

ld/

PR ld/17878
* plugin.c: Include ../bfd/plugin.h.
(plugin_get_ir_dummy_bfd): Call bfd_create with
link_info.output_bfd instead of srctemplate.  Copy BFD info
from srctemplate only if it doesn't use BFD plugin target
vector.
(plugin_load_plugins): Call register_ld_plugin_object_p with
(plugin_object_p)
(plugin_maybe_claim): Renamed to ...
(plugin_object_p): This.  Return dummy BFD target vector if
input is calimed by plugin library, otherwise return NULL.
Update plugin_format and plugin_dummy_bfd.
(plugin_maybe_claim): New.  Use plugin_object_p.

xx

bfd/bfd-in2.h
bfd/bfd.c
bfd/plugin.c
bfd/plugin.h
ld/plugin.c

index 91dbf8077d9f62a3e23c4b309e702286a5e89e84..678eaeda2e74615fe074401cba14efde69c5e02f 100644 (file)
@@ -6272,6 +6272,13 @@ enum bfd_direction
     both_direction = 3
   };
 
+enum bfd_plugin_format
+  {
+    bfd_plugin_uknown = 0,
+    bfd_plugin_yes = 1,
+    bfd_plugin_no = 2
+  };
+
 struct bfd
 {
   /* The filename the application opened the BFD with.  */
@@ -6428,6 +6435,13 @@ struct bfd
   /* Set if this is the linker output BFD.  */
   unsigned int is_linker_output : 1;
 
+  /* If this is an input for a compiler plug-in library.  */
+  ENUM_BITFIELD (bfd_plugin_format) plugin_format : 2;
+
+  /* Set to dummy BFD created when claimed by a compiler plug-in
+     library.  */
+  bfd *plugin_dummy_bfd;
+
   /* Currently my_archive is tested before adding origin to
      anything. I believe that this can become always an add of
      origin, with origin set to 0 for non archive files.  */
index 29a7c5d2bfc1b7fef0201c54580ee4dd3a437887..69c6bde129a704599412fdf6c8d2ea20e7e655c6 100644 (file)
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -44,6 +44,13 @@ CODE_FRAGMENT
 .    both_direction = 3
 .  };
 .
+.enum bfd_plugin_format
+.  {
+.    bfd_plugin_uknown = 0,
+.    bfd_plugin_yes = 1,
+.    bfd_plugin_no = 2
+.  };
+.
 .struct bfd
 .{
 .  {* The filename the application opened the BFD with.  *}
@@ -200,6 +207,13 @@ CODE_FRAGMENT
 .  {* Set if this is the linker output BFD.  *}
 .  unsigned int is_linker_output : 1;
 .
+.  {* If this is an input for a compiler plug-in library.  *}
+.  ENUM_BITFIELD (bfd_plugin_format) plugin_format : 2;
+.
+.  {* Set to dummy BFD created when claimed by a compiler plug-in
+.     library.  *}
+.  bfd *plugin_dummy_bfd;
+.
 .  {* Currently my_archive is tested before adding origin to
 .     anything. I believe that this can become always an add of
 .     origin, with origin set to 0 for non archive files.  *}
index 94ed95b1c2aca806384d243a7fc14d039211a78e..b41e0925e808068cdc97958e09993595cf2bf1af 100644 (file)
@@ -203,7 +203,7 @@ try_claim (bfd *abfd)
 }
 
 static int
-try_load_plugin (const char *pname, bfd *abfd)
+try_load_plugin (const char *pname, bfd *abfd, int *has_plugin_p)
 {
   void *plugin_handle;
   int tv_size = 4;
@@ -212,6 +212,8 @@ try_load_plugin (const char *pname, bfd *abfd)
   ld_plugin_onload onload;
   enum ld_plugin_status status;
 
+  *has_plugin_p = 0;
+
   plugin_handle = dlopen (pname, RTLD_NOW);
   if (!plugin_handle)
     {
@@ -244,25 +246,63 @@ try_load_plugin (const char *pname, bfd *abfd)
   if (status != LDPS_OK)
     goto err;
 
+  *has_plugin_p = 1;
+
+  abfd->plugin_format = bfd_plugin_no;
+
   if (!claim_file)
     goto err;
 
   if (!try_claim (abfd))
     goto err;
 
+  abfd->plugin_format = bfd_plugin_yes;
+
   return 1;
 
  err:
-  plugin_handle = NULL;
   return 0;
 }
 
+/* There may be plugin libraries in lib/bfd-plugins.  */
+
+static int has_plugin = -1;
+
+static const bfd_target *(*ld_plugin_object_p) (bfd *);
+
 static const char *plugin_name;
 
 void
 bfd_plugin_set_plugin (const char *p)
 {
   plugin_name = p;
+  has_plugin = p != NULL;
+}
+
+/* Return TRUE if a plugin library is used.  */
+
+bfd_boolean
+bfd_plugin_specified_p (void)
+{
+  return has_plugin > 0;
+}
+
+extern const bfd_target plugin_vec;
+
+/* Return TRUE if TARGET is a pointer to plugin_vec.  */
+
+bfd_boolean
+bfd_plugin_target_p (const bfd_target *target)
+{
+  return target == &plugin_vec;
+}
+
+/* Register OBJECT_P to be used by bfd_plugin_object_p.  */
+
+void
+register_ld_plugin_object_p (const bfd_target *(*object_p) (bfd *))
+{
+  ld_plugin_object_p = object_p;
 }
 
 static int
@@ -274,11 +314,14 @@ load_plugin (bfd *abfd)
   struct dirent *ent;
   int found = 0;
 
+  if (!has_plugin)
+    return found;
+
   if (plugin_name)
-    return try_load_plugin (plugin_name, abfd);
+    return try_load_plugin (plugin_name, abfd, &has_plugin);
 
   if (plugin_program_name == NULL)
-    return 0;
+    return found;
 
   plugin_dir = concat (BINDIR, "/../lib/bfd-plugins", NULL);
   p = make_relative_prefix (plugin_program_name,
@@ -295,10 +338,13 @@ load_plugin (bfd *abfd)
     {
       char *full_name;
       struct stat s;
+      int valid_plugin;
 
       full_name = concat (p, "/", ent->d_name, NULL);
       if (stat(full_name, &s) == 0 && S_ISREG (s.st_mode))
-       found = try_load_plugin (full_name, abfd);
+       found = try_load_plugin (full_name, abfd, &valid_plugin);
+      if (has_plugin <= 0)
+       has_plugin = valid_plugin;
       free (full_name);
       if (found)
        break;
@@ -316,10 +362,13 @@ load_plugin (bfd *abfd)
 static const bfd_target *
 bfd_plugin_object_p (bfd *abfd)
 {
-  if (!load_plugin (abfd))
+  if (ld_plugin_object_p)
+    return ld_plugin_object_p (abfd);
+
+  if (abfd->plugin_format == bfd_plugin_uknown && !load_plugin (abfd))
     return NULL;
 
-  return abfd->xvec;
+  return abfd->plugin_format == bfd_plugin_yes ? abfd->xvec : NULL;
 }
 
 /* Copy any private info we understand from the input bfd
index af98c5950f3a2cde7ea08607edb5a0fc93257511..1a66e6e459120b807dd5624ea174716107686462 100644 (file)
@@ -25,6 +25,9 @@
 
 void bfd_plugin_set_program_name (const char *);
 void bfd_plugin_set_plugin (const char *);
+bfd_boolean bfd_plugin_target_p (const bfd_target *);
+bfd_boolean bfd_plugin_specified_p (void);
+void register_ld_plugin_object_p (const bfd_target *(*object_p) (bfd *));
 
 typedef struct plugin_data_struct
 {
index e5bdb01878b06fb9a40dfc1d3fbf49f8dab58965..b48ce86a6f1ecc4d1561171d212a8526d91270c2 100644 (file)
@@ -30,6 +30,7 @@
 #include "ldexp.h"
 #include "ldlang.h"
 #include "ldfile.h"
+#include "../bfd/plugin.h"
 #include "plugin.h"
 #include "plugin-api.h"
 #include "elf-bfd.h"
@@ -174,6 +175,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.  */
@@ -295,14 +298,19 @@ plugin_get_ir_dummy_bfd (const char *name, bfd *srctemplate)
 
   bfd_use_reserved_id = 1;
   abfd = bfd_create (concat (name, IRONLY_SUFFIX, (const char *) NULL),
-                    srctemplate);
+                    link_info.output_bfd);
   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_p (srctemplate->xvec))
+       {
+         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 +321,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;
 }
@@ -979,6 +988,8 @@ 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 ();;
 #endif
@@ -1024,22 +1035,36 @@ 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);
+  bfd_boolean inarchive;
+  const char *name;
+  int fd;
+
+  /* Don't try the dummy object file.  */
+  if ((ibfd->flags & BFD_PLUGIN) != 0)
+    return NULL;
+
+  if (ibfd->plugin_format != bfd_plugin_uknown)
+    {
+      if (ibfd->plugin_format == bfd_plugin_yes)
+       return ibfd->plugin_dummy_bfd->xvec;
+      else
+       return NULL;
+    }
+
+  inarchive = bfd_my_archive (ibfd) != NULL;
+  name = inarchive ? bfd_my_archive (ibfd)->filename : ibfd->filename;
+  fd = open (name, O_RDONLY | O_BINARY);
 
   if (fd < 0)
-    return;
+    return NULL;
 
   /* We create a dummy BFD, initially empty, to house whatever symbols
      the plugin may want to add.  */
@@ -1085,35 +1110,32 @@ plugin_maybe_claim (lang_input_statement_type *entry)
   input->filesize = 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.  */
+      /* 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 (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
     {
@@ -1134,8 +1156,27 @@ 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.  */
+
+      /* BFD archive handling caches elements so we can't call
+        bfd_close for archives.  */
+      if (entry->the_bfd->my_archive == NULL)
+       bfd_close (entry->the_bfd);
+      entry->the_bfd = abfd;
+      entry->flags.claimed = 1;
     }
 }