PR ld/12365

PR ld/12672
bfd/
	* bfd.c (BFD_PLUGIN): Define.
	(BFD_FLAGS_SAVED, BFD_FLAGS_FOR_BFD_USE_MASK): Add BFD_PLUGIN.
	* bfd-in2.h: Regenerate.
	* elflink.c (elf_link_output_extsym): Strip undefined plugin syms.
	* opncls.c (bfd_make_readable): Don't lose original bfd flags.
ld/
	* ldfile.c (ldfile_try_open_bfd): Don't attempt any plugin action
	when no_more_claiming.
	* ldmain.c (add_archive_element): Likewise.
	(multiple_definition): Remove plugin_multiple_definition call.
	(notice): Remove plugin_notice call.
	* ldlang.c (lang_list_insert_after, void lang_list_remove_tail): Move.
	Delete prototype.
	(plugin_insert): New static var.
	(open_input_bfds): Only rescan libs after plugin insert point.
	(lang_gc_sections): Omit plugin claimed files.
	(lang_process): Set plugin_insert.  Only rescan when plugin adds
	objects.
	* plugin.h (no_more_claiming): Declare.
	(plugin_notice, plugin_multiple_definition): Don't declare.
	* plugin.c: Formatting.
	(orig_notice_all, orig_allow_multiple_defs, orig_callbacks,
	plugin_callbacks): New static vars.
	(no_more_claiming): Make global.
	(plugin_cached_allow_multiple_defs): Delete.
	(plugin_get_ir_dummy_bfd): Set SEC_EXCLUDE on dummy .text section,
	use newer bfd_make_section variant.  Make COMMON section too.
	Error handling.  Correct setting of gp size.
	(asymbol_from_plugin_symbol): Properly cast last arg of concat.
	(message): Likewise for ACONCAT.
	(asymbol_from_plugin_symbol): Use our COMMON section.
	(get_symbols): When report_plugin_symbols, show visibility too.
	(init_non_ironly_hash): Move.  Don't test non_ironly_hash.
	(plugin_load_plugins): Save state of linker callbacks, set up to
	call plugin_notice instead.  Call init_non_ironly_hash here.
	(plugin_call_all_symbols_read): Set plugin_multiple_definition in
	plugin callbacks.
	(plugin_notice): Rewrite.
	(plugin_multiple_definition): Make static, call original callback.
ld/testsuite/
	* ld-plugin/plugin-7.d: Adjust for plugin changes.
	* ld-plugin/plugin-8.d: Likewise.
	* ld-plugin/plugin.exp: Pass --verbose=2 for visibility test, and
	compare ld output to..
	* ld-plugin/plugin-12.d: New.
This commit is contained in:
Alan Modra
2011-04-17 23:15:13 +00:00
parent 0283589814
commit 9e2278f567
13 changed files with 223 additions and 184 deletions

View File

@@ -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)
if (name != NULL)
{
/* 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)
{
/* 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);
}