aboutsummaryrefslogtreecommitdiff
path: root/ld/plugin.c
diff options
context:
space:
mode:
Diffstat (limited to 'ld/plugin.c')
-rw-r--r--ld/plugin.c213
1 files changed, 124 insertions, 89 deletions
diff --git a/ld/plugin.c b/ld/plugin.c
index 6a14f22..07f3afe 100644
--- a/ld/plugin.c
+++ b/ld/plugin.c
@@ -97,15 +97,18 @@ static const char *error_plugin = NULL;
cases when establishing symbol resolutions. */
static struct bfd_hash_table *non_ironly_hash = NULL;
+/* State of linker "notice" and "multiple_definition" interfaces
+ before we poked at them. */
+static bfd_boolean orig_notice_all;
+static bfd_boolean orig_allow_multiple_defs;
+
+/* Original linker callbacks, and the plugin version. */
+static const struct bfd_link_callbacks *orig_callbacks;
+static struct bfd_link_callbacks plugin_callbacks;
+
/* Set at all symbols read time, to avoid recursively offering the plugin
its own newly-added input files and libs to claim. */
-static bfd_boolean no_more_claiming = FALSE;
-
-/* If the --allow-multiple-definition command-line option is active, we
- have to disable it so that BFD always calls our hook, and simulate the
- effect (when not resolving IR vs. real symbols) ourselves by ensuring
- TRUE is returned from the hook. */
-static bfd_boolean plugin_cached_allow_multiple_defs = FALSE;
+bfd_boolean no_more_claiming = FALSE;
/* List of tags to set in the constant leading part of the tv array. */
static const enum ld_plugin_tag tv_header_tags[] =
@@ -130,6 +133,17 @@ static const enum ld_plugin_tag tv_header_tags[] =
/* How many entries in the constant leading part of the tv array. */
static const size_t tv_header_size = ARRAY_SIZE (tv_header_tags);
+/* Forward references. */
+static bfd_boolean plugin_notice (struct bfd_link_info *info,
+ const char *name, bfd *abfd,
+ asection *section, bfd_vma value);
+static bfd_boolean plugin_multiple_definition (struct bfd_link_info *info,
+ const char *name,
+ bfd *obfd, asection *osec,
+ bfd_vma oval, bfd *nbfd,
+ asection *nsec,
+ bfd_vma nval);
+
#if !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H)
#define RTLD_NOW 0 /* Dummy value. */
@@ -225,24 +239,30 @@ plugin_opt_plugin_arg (const char *arg)
bfd *
plugin_get_ir_dummy_bfd (const char *name, bfd *srctemplate)
{
- asection *sec;
bfd *abfd;
bfd_use_reserved_id = 1;
- abfd = bfd_create (concat (name, IRONLY_SUFFIX, (const char *)NULL),
+ abfd = bfd_create (concat (name, IRONLY_SUFFIX, (const char *) NULL),
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,
- (SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY
- | SEC_ALLOC | SEC_LOAD | SEC_KEEP));
- sec->output_section = sec;
- sec->output_offset = 0;
- return abfd;
+ 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))
+ {
+ flagword flags;
+
+ /* Create sections to own the symbols. */
+ flags = (SEC_CODE | SEC_HAS_CONTENTS | SEC_READONLY
+ | SEC_ALLOC | SEC_LOAD | SEC_KEEP | SEC_EXCLUDE);
+ if (bfd_make_section_anyway_with_flags (abfd, ".text", flags))
+ return abfd;
+ }
+ }
+ einfo (_("could not create dummy IR bfd: %F%E\n"));
+ return NULL;
}
/* Check if the BFD passed in is an IR dummy object file. */
@@ -254,9 +274,9 @@ is_ir_dummy_bfd (const bfd *abfd)
Likewise, the usrdata field may be NULL if ABFD was added by the
backend without a corresponding input statement, as happens e.g.
when processing DT_NEEDED dependencies. */
- return abfd
- && abfd->usrdata
- && ((lang_input_statement_type *)(abfd->usrdata))->claimed;
+ return (abfd
+ && abfd->usrdata
+ && ((lang_input_statement_type *)(abfd->usrdata))->claimed);
}
/* Helpers to convert between BFD and GOLD symbol formats. */
@@ -269,7 +289,7 @@ asymbol_from_plugin_symbol (bfd *abfd, asymbol *asym,
asym->the_bfd = abfd;
asym->name = (ldsym->version
- ? concat (ldsym->name, "@", ldsym->version, NULL)
+ ? concat (ldsym->name, "@", ldsym->version, (const char *) NULL)
: ldsym->name);
asym->value = 0;
switch (ldsym->def)
@@ -487,9 +507,9 @@ get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
/* 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;
+ 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
@@ -539,10 +559,12 @@ get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
? LDPR_PREEMPTED_IR
: LDPR_PREEMPTED_REG);
-report_symbol:
+ report_symbol:
if (report_plugin_symbols)
- einfo ("%P: %B: symbol `%s' definition: %d, resolution: %d\n",
- abfd, syms[n].name, syms[n].def, syms[n].resolution);
+ einfo (_("%P: %B: symbol `%s' "
+ "definition: %d, visibility: %d, resolution: %d\n"),
+ abfd, syms[n].name,
+ syms[n].def, syms[n].visibility, syms[n].resolution);
}
return LDPS_OK;
}
@@ -599,14 +621,13 @@ message (int level, const char *format, ...)
case LDPL_FATAL:
case LDPL_ERROR:
default:
- {
- char *newfmt = ACONCAT ((level == LDPL_FATAL
- ? "%P%F: " : "%P%X: ",
- format, "\n", NULL));
- fflush (stdout);
- vfinfo (stderr, newfmt, args, TRUE);
- fflush (stderr);
- }
+ {
+ char *newfmt = ACONCAT ((level == LDPL_FATAL ? "%P%F: " : "%P%X: ",
+ format, "\n", (const char *) NULL));
+ fflush (stdout);
+ vfinfo (stderr, newfmt, args, TRUE);
+ fflush (stderr);
+ }
break;
}
@@ -714,6 +735,27 @@ plugin_active_plugins_p (void)
return plugins_list != NULL;
}
+/* Init the non_ironly hash table. */
+static void
+init_non_ironly_hash (void)
+{
+ struct bfd_sym_chain *sym;
+
+ non_ironly_hash
+ = (struct bfd_hash_table *) xmalloc (sizeof (struct bfd_hash_table));
+ if (!bfd_hash_table_init_n (non_ironly_hash,
+ bfd_hash_newfunc,
+ sizeof (struct bfd_hash_entry),
+ 61))
+ einfo (_("%P%F: bfd_hash_table_init failed: %E\n"));
+
+ for (sym = &entry_symbol; sym != NULL; sym = sym->next)
+ if (sym->name
+ && !bfd_hash_lookup (non_ironly_hash, sym->name, TRUE, TRUE))
+ einfo (_("%P%X: hash table failure adding symbol %s\n"),
+ sym->name);
+}
+
/* Load up and initialise all plugins after argument parsing. */
int
plugin_load_plugins (void)
@@ -761,7 +803,13 @@ plugin_load_plugins (void)
/* Since plugin(s) inited ok, assume they're going to want symbol
resolutions, which needs us to track which symbols are referenced
by non-IR files using the linker's notice callback. */
+ orig_notice_all = link_info.notice_all;
+ orig_callbacks = link_info.callbacks;
+ plugin_callbacks = *orig_callbacks;
+ plugin_callbacks.notice = &plugin_notice;
link_info.notice_all = TRUE;
+ link_info.callbacks = &plugin_callbacks;
+ init_non_ironly_hash ();
return 0;
}
@@ -803,8 +851,9 @@ plugin_call_all_symbols_read (void)
as the plugin infrastructure relies on the multiple_definition
callback to swap out the dummy IR-only BFDs for new real ones
when it starts opening the files added during this callback. */
- plugin_cached_allow_multiple_defs = link_info.allow_multiple_definition;
+ orig_allow_multiple_defs = link_info.allow_multiple_definition;
link_info.allow_multiple_definition = FALSE;
+ plugin_callbacks.multiple_definition = &plugin_multiple_definition;
while (curplug)
{
@@ -847,30 +896,6 @@ plugin_call_cleanup (void)
plugin_error_plugin ());
}
-/* Lazily init the non_ironly hash table. */
-static void
-init_non_ironly_hash (void)
-{
- struct bfd_sym_chain *sym;
-
- if (non_ironly_hash == NULL)
- {
- non_ironly_hash =
- (struct bfd_hash_table *) xmalloc (sizeof (struct bfd_hash_table));
- if (!bfd_hash_table_init_n (non_ironly_hash,
- bfd_hash_newfunc,
- sizeof (struct bfd_hash_entry),
- 61))
- einfo (_("%P%F: bfd_hash_table_init failed: %E\n"));
-
- for (sym = &entry_symbol; sym != NULL; sym = sym->next)
- if (sym->name
- && !bfd_hash_lookup (non_ironly_hash, sym->name, TRUE, TRUE))
- einfo (_("%P%X: hash table failure adding symbol %s\n"),
- sym->name);
- }
-}
-
/* To determine which symbols should be resolved LDPR_PREVAILING_DEF
and which LDPR_PREVAILING_DEF_IRONLY, we notice all the symbols as
the linker adds them to the linker hash table. If we see a symbol
@@ -879,32 +904,38 @@ init_non_ironly_hash (void)
it was referenced only by IR files. We have to notice_all symbols,
because we won't necessarily know until later which ones will be
contributed by IR files. */
-bfd_boolean
-plugin_notice (struct bfd_link_info *info ATTRIBUTE_UNUSED,
- const char *name, bfd *abfd,
- asection *section, bfd_vma value ATTRIBUTE_UNUSED)
+static bfd_boolean
+plugin_notice (struct bfd_link_info *info,
+ const char *name,
+ bfd *abfd,
+ asection *section,
+ bfd_vma value)
{
- bfd_boolean is_ref = bfd_is_und_section (section);
- bfd_boolean is_dummy = is_ir_dummy_bfd (abfd);
- init_non_ironly_hash ();
- /* We only care about refs, not defs, indicated by section pointing
- to the undefined section (according to the bfd linker notice callback
- interface definition). */
- if (is_ref && !is_dummy)
- {
- /* 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\n"),
- abfd->filename, name);
- }
- else if (!is_ref && is_dummy)
+ if (name != NULL)
{
- /* No further processing since this is a def from an IR dummy BFD. */
- return FALSE;
+ /* No further processing if this def/ref is from an IR dummy BFD. */
+ if (is_ir_dummy_bfd (abfd))
+ return TRUE;
+
+ /* We only care about refs, not defs, indicated by section
+ pointing to the undefined section (according to the bfd
+ linker notice callback interface definition). */
+ if (bfd_is_und_section (section))
+ {
+ /* 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\n"),
+ abfd->filename, name);
+ }
}
/* Continue with cref/nocrossref/trace-sym processing. */
+ if (name == NULL
+ || orig_notice_all
+ || (info->notice_hash != NULL
+ && bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE) != NULL))
+ return (*orig_callbacks->notice) (info, name, abfd, section, value);
return TRUE;
}
@@ -917,10 +948,9 @@ plugin_notice (struct bfd_link_info *info ATTRIBUTE_UNUSED,
real BFD. We return true if this was not-really-a-clash because
we've fixed it up, or anyway if --allow-multiple-definition was in
effect (before we disabled it to ensure we got called back). */
-bfd_boolean
+static bfd_boolean
plugin_multiple_definition (struct bfd_link_info *info, const char *name,
- bfd *obfd, asection *osec ATTRIBUTE_UNUSED,
- bfd_vma oval ATTRIBUTE_UNUSED,
+ bfd *obfd, asection *osec, bfd_vma oval,
bfd *nbfd, asection *nsec, bfd_vma nval)
{
if (is_ir_dummy_bfd (obfd))
@@ -937,5 +967,10 @@ plugin_multiple_definition (struct bfd_link_info *info, const char *name,
blhe->u.def.value = nval;
return TRUE;
}
- return plugin_cached_allow_multiple_defs;
+
+ if (orig_allow_multiple_defs)
+ return TRUE;
+
+ return (*orig_callbacks->multiple_definition) (info, name, obfd, osec, oval,
+ nbfd, nsec, nval);
}