From 5ae0078cd2b6b69e6119864e20987c8724916b29 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Wed, 11 Feb 2015 05:01:03 -0800 Subject: [PATCH] Merge linker plugin handling into BFD plugin support 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 | 14 +++++++ bfd/bfd.c | 14 +++++++ bfd/plugin.c | 63 ++++++++++++++++++++++++++---- bfd/plugin.h | 3 ++ ld/plugin.c | 105 +++++++++++++++++++++++++++++++++++--------------- 5 files changed, 160 insertions(+), 39 deletions(-) diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 91dbf8077d9..678eaeda2e7 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -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. */ diff --git a/bfd/bfd.c b/bfd/bfd.c index 29a7c5d2bfc..69c6bde129a 100644 --- 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. *} diff --git a/bfd/plugin.c b/bfd/plugin.c index 94ed95b1c2a..b41e0925e80 100644 --- a/bfd/plugin.c +++ b/bfd/plugin.c @@ -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 diff --git a/bfd/plugin.h b/bfd/plugin.h index af98c5950f3..1a66e6e4591 100644 --- a/bfd/plugin.h +++ b/bfd/plugin.h @@ -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 { diff --git a/ld/plugin.c b/ld/plugin.c index e5bdb01878b..b48ce86a6f1 100644 --- a/ld/plugin.c +++ b/ld/plugin.c @@ -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; } } -- 2.30.2