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:
parent
0283589814
commit
9e2278f567
|
@ -5110,14 +5110,17 @@ struct bfd
|
|||
/* Decompress sections in this BFD. */
|
||||
#define BFD_DECOMPRESS 0x10000
|
||||
|
||||
/* BFD is a dummy, for plugins. */
|
||||
#define BFD_PLUGIN 0x20000
|
||||
|
||||
/* Flags bits to be saved in bfd_preserve_save. */
|
||||
#define BFD_FLAGS_SAVED \
|
||||
(BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS)
|
||||
(BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_PLUGIN)
|
||||
|
||||
/* Flags bits which are for BFD use only. */
|
||||
#define BFD_FLAGS_FOR_BFD_USE_MASK \
|
||||
(BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
|
||||
| BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT)
|
||||
| BFD_PLUGIN | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT)
|
||||
|
||||
/* Currently my_archive is tested before adding origin to
|
||||
anything. I believe that this can become always an add of
|
||||
|
|
|
@ -157,14 +157,17 @@ CODE_FRAGMENT
|
|||
. {* Decompress sections in this BFD. *}
|
||||
.#define BFD_DECOMPRESS 0x10000
|
||||
.
|
||||
. {* BFD is a dummy, for plugins. *}
|
||||
.#define BFD_PLUGIN 0x20000
|
||||
.
|
||||
. {* Flags bits to be saved in bfd_preserve_save. *}
|
||||
.#define BFD_FLAGS_SAVED \
|
||||
. (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS)
|
||||
. (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_PLUGIN)
|
||||
.
|
||||
. {* Flags bits which are for BFD use only. *}
|
||||
.#define BFD_FLAGS_FOR_BFD_USE_MASK \
|
||||
. (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
|
||||
. | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT)
|
||||
. | BFD_PLUGIN | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT)
|
||||
.
|
||||
. {* Currently my_archive is tested before adding origin to
|
||||
. anything. I believe that this can become always an add of
|
||||
|
|
|
@ -8704,6 +8704,11 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
|
|||
|| h->root.type == bfd_link_hash_defweak)
|
||||
&& elf_discarded_section (h->root.u.def.section))
|
||||
strip = TRUE;
|
||||
else if ((h->root.type == bfd_link_hash_undefined
|
||||
|| h->root.type == bfd_link_hash_undefweak)
|
||||
&& h->root.u.undef.abfd != NULL
|
||||
&& (h->root.u.undef.abfd->flags & BFD_PLUGIN) != 0)
|
||||
strip = TRUE;
|
||||
else
|
||||
strip = FALSE;
|
||||
|
||||
|
|
|
@ -875,7 +875,7 @@ bfd_make_readable (bfd *abfd)
|
|||
abfd->section_count = 0;
|
||||
abfd->usrdata = NULL;
|
||||
abfd->cacheable = FALSE;
|
||||
abfd->flags = BFD_IN_MEMORY;
|
||||
abfd->flags |= BFD_IN_MEMORY;
|
||||
abfd->mtime_set = FALSE;
|
||||
|
||||
abfd->target_defaulted = TRUE;
|
||||
|
|
|
@ -313,7 +313,8 @@ success:
|
|||
will be needed when and if we want to bfd_create a new
|
||||
one using this one as a template. */
|
||||
if (bfd_check_format (entry->the_bfd, bfd_object)
|
||||
&& plugin_active_plugins_p ())
|
||||
&& plugin_active_plugins_p ()
|
||||
&& !no_more_claiming)
|
||||
{
|
||||
int fd = open (attempt, O_RDONLY | O_BINARY);
|
||||
if (fd >= 0)
|
||||
|
|
111
ld/ldlang.c
111
ld/ldlang.c
|
@ -86,13 +86,6 @@ static void print_statement_list (lang_statement_union_type *,
|
|||
static void print_statements (void);
|
||||
static void print_input_section (asection *, bfd_boolean);
|
||||
static bfd_boolean lang_one_common (struct bfd_link_hash_entry *, void *);
|
||||
#ifdef ENABLE_PLUGINS
|
||||
static void lang_list_insert_after (lang_statement_list_type *destlist,
|
||||
lang_statement_list_type *srclist,
|
||||
lang_statement_union_type **field);
|
||||
static void lang_list_remove_tail (lang_statement_list_type *destlist,
|
||||
lang_statement_list_type *origlist);
|
||||
#endif /* ENABLE_PLUGINS */
|
||||
static void lang_record_phdrs (void);
|
||||
static void lang_do_version_exports_section (void);
|
||||
static void lang_finalize_version_expr_head
|
||||
|
@ -3180,6 +3173,9 @@ enum open_bfd_mode
|
|||
OPEN_BFD_FORCE = 1,
|
||||
OPEN_BFD_RESCAN = 2
|
||||
};
|
||||
#ifdef ENABLE_PLUGINS
|
||||
static lang_input_statement_type *plugin_insert = NULL;
|
||||
#endif
|
||||
|
||||
static void
|
||||
open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
|
||||
|
@ -3236,6 +3232,10 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
|
|||
force it to be researched unless the whole archive
|
||||
has been loaded already. Do the same for a rescan. */
|
||||
if (mode != OPEN_BFD_NORMAL
|
||||
#ifdef ENABLE_PLUGINS
|
||||
&& ((mode & OPEN_BFD_RESCAN) == 0
|
||||
|| plugin_insert == NULL)
|
||||
#endif
|
||||
&& !s->input_statement.whole_archive
|
||||
&& s->input_statement.loaded
|
||||
&& bfd_check_format (s->input_statement.the_bfd,
|
||||
|
@ -3271,6 +3271,12 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
|
|||
}
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_PLUGINS
|
||||
/* If we have found the point at which a plugin added new
|
||||
files, clear plugin_insert to enable archive rescan. */
|
||||
if (&s->input_statement == plugin_insert)
|
||||
plugin_insert = NULL;
|
||||
#endif
|
||||
break;
|
||||
case lang_assignment_statement_enum:
|
||||
if (s->assignment_statement.exp->assign.hidden)
|
||||
|
@ -6279,6 +6285,10 @@ lang_gc_sections (void)
|
|||
LANG_FOR_EACH_INPUT_STATEMENT (f)
|
||||
{
|
||||
asection *sec;
|
||||
#ifdef ENABLE_PLUGINS
|
||||
if (f->claimed)
|
||||
continue;
|
||||
#endif
|
||||
for (sec = f->the_bfd->sections; sec != NULL; sec = sec->next)
|
||||
if ((sec->flags & SEC_DEBUGGING) == 0)
|
||||
sec->flags &= ~SEC_EXCLUDE;
|
||||
|
@ -6452,6 +6462,38 @@ find_replacements_insert_point (void)
|
|||
insert point. */
|
||||
return lastobject;
|
||||
}
|
||||
|
||||
/* Insert SRCLIST into DESTLIST after given element by chaining
|
||||
on FIELD as the next-pointer. (Counterintuitively does not need
|
||||
a pointer to the actual after-node itself, just its chain field.) */
|
||||
|
||||
static void
|
||||
lang_list_insert_after (lang_statement_list_type *destlist,
|
||||
lang_statement_list_type *srclist,
|
||||
lang_statement_union_type **field)
|
||||
{
|
||||
*(srclist->tail) = *field;
|
||||
*field = srclist->head;
|
||||
if (destlist->tail == field)
|
||||
destlist->tail = srclist->tail;
|
||||
}
|
||||
|
||||
/* Detach new nodes added to DESTLIST since the time ORIGLIST
|
||||
was taken as a copy of it and leave them in ORIGLIST. */
|
||||
|
||||
static void
|
||||
lang_list_remove_tail (lang_statement_list_type *destlist,
|
||||
lang_statement_list_type *origlist)
|
||||
{
|
||||
union lang_statement_union **savetail;
|
||||
/* Check that ORIGLIST really is an earlier state of DESTLIST. */
|
||||
ASSERT (origlist->head == destlist->head);
|
||||
savetail = origlist->tail;
|
||||
origlist->head = *(savetail);
|
||||
origlist->tail = destlist->tail;
|
||||
destlist->tail = savetail;
|
||||
*savetail = NULL;
|
||||
}
|
||||
#endif /* ENABLE_PLUGINS */
|
||||
|
||||
void
|
||||
|
@ -6484,6 +6526,7 @@ lang_process (void)
|
|||
{
|
||||
lang_statement_list_type added;
|
||||
lang_statement_list_type files, inputfiles;
|
||||
|
||||
/* Now all files are read, let the plugin(s) decide if there
|
||||
are any more to be added to the link before we call the
|
||||
emulation's after_open hook. We create a private list of
|
||||
|
@ -6509,27 +6552,29 @@ lang_process (void)
|
|||
{
|
||||
/* If so, we will insert them into the statement list immediately
|
||||
after the first input file that was claimed by the plugin. */
|
||||
lang_input_statement_type *claim1 = find_replacements_insert_point ();
|
||||
plugin_insert = find_replacements_insert_point ();
|
||||
/* If a plugin adds input files without having claimed any, we
|
||||
don't really have a good idea where to place them. Just putting
|
||||
them at the start or end of the list is liable to leave them
|
||||
outside the crtbegin...crtend range. */
|
||||
ASSERT (claim1 != NULL);
|
||||
/* Splice the new statement list into the old one after claim1. */
|
||||
lang_list_insert_after (stat_ptr, &added, &claim1->header.next);
|
||||
ASSERT (plugin_insert != NULL);
|
||||
/* Splice the new statement list into the old one. */
|
||||
lang_list_insert_after (stat_ptr, &added,
|
||||
&plugin_insert->header.next);
|
||||
/* Likewise for the file chains. */
|
||||
lang_list_insert_after (&input_file_chain, &inputfiles,
|
||||
&claim1->next_real_file);
|
||||
&plugin_insert->next_real_file);
|
||||
/* We must be careful when relinking file_chain; we may need to
|
||||
insert the new files at the head of the list if the insert
|
||||
point chosen is the dummy first input file. */
|
||||
if (claim1->filename)
|
||||
lang_list_insert_after (&file_chain, &files, &claim1->next);
|
||||
if (plugin_insert->filename)
|
||||
lang_list_insert_after (&file_chain, &files, &plugin_insert->next);
|
||||
else
|
||||
lang_list_insert_after (&file_chain, &files, &file_chain.head);
|
||||
|
||||
/* Rescan archives in case new undefined symbols have appeared. */
|
||||
open_input_bfds (statement_list.head, OPEN_BFD_RESCAN);
|
||||
}
|
||||
/* Rescan any archives in case new undefined symbols have appeared. */
|
||||
open_input_bfds (statement_list.head, OPEN_BFD_RESCAN);
|
||||
}
|
||||
#endif /* ENABLE_PLUGINS */
|
||||
|
||||
|
@ -6952,40 +6997,6 @@ lang_statement_append (lang_statement_list_type *list,
|
|||
list->tail = field;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_PLUGINS
|
||||
/* Insert SRCLIST into DESTLIST after given element by chaining
|
||||
on FIELD as the next-pointer. (Counterintuitively does not need
|
||||
a pointer to the actual after-node itself, just its chain field.) */
|
||||
|
||||
static void
|
||||
lang_list_insert_after (lang_statement_list_type *destlist,
|
||||
lang_statement_list_type *srclist,
|
||||
lang_statement_union_type **field)
|
||||
{
|
||||
*(srclist->tail) = *field;
|
||||
*field = srclist->head;
|
||||
if (destlist->tail == field)
|
||||
destlist->tail = srclist->tail;
|
||||
}
|
||||
|
||||
/* Detach new nodes added to DESTLIST since the time ORIGLIST
|
||||
was taken as a copy of it and leave them in ORIGLIST. */
|
||||
|
||||
static void
|
||||
lang_list_remove_tail (lang_statement_list_type *destlist,
|
||||
lang_statement_list_type *origlist)
|
||||
{
|
||||
union lang_statement_union **savetail;
|
||||
/* Check that ORIGLIST really is an earlier state of DESTLIST. */
|
||||
ASSERT (origlist->head == destlist->head);
|
||||
savetail = origlist->tail;
|
||||
origlist->head = *(savetail);
|
||||
origlist->tail = destlist->tail;
|
||||
destlist->tail = savetail;
|
||||
*savetail = NULL;
|
||||
}
|
||||
#endif /* ENABLE_PLUGINS */
|
||||
|
||||
/* Set the output format type. -oformat overrides scripts. */
|
||||
|
||||
void
|
||||
|
|
30
ld/ldmain.c
30
ld/ldmain.c
|
@ -804,7 +804,9 @@ add_archive_element (struct bfd_link_info *info,
|
|||
BFD, but we still want to output the original BFD filename. */
|
||||
orig_input = *input;
|
||||
#ifdef ENABLE_PLUGINS
|
||||
if (bfd_my_archive (abfd) != NULL && plugin_active_plugins_p ())
|
||||
if (bfd_my_archive (abfd) != NULL
|
||||
&& plugin_active_plugins_p ()
|
||||
&& !no_more_claiming)
|
||||
{
|
||||
/* We must offer this archive member to the plugins to claim. */
|
||||
int fd = open (bfd_my_archive (abfd)->filename, O_RDONLY | O_BINARY);
|
||||
|
@ -944,22 +946,11 @@ multiple_definition (struct bfd_link_info *info ATTRIBUTE_UNUSED,
|
|||
asection *nsec,
|
||||
bfd_vma nval)
|
||||
{
|
||||
#ifdef ENABLE_PLUGINS
|
||||
/* We may get called back even when --allow-multiple-definition is in
|
||||
effect, as the plugin infrastructure needs to use this hook in
|
||||
order to swap out IR-only symbols for real ones. In that case,
|
||||
it will let us know not to continue by returning TRUE even if this
|
||||
is not an IR-only vs. non-IR symbol conflict. */
|
||||
if (plugin_multiple_definition (info, name, obfd, osec, oval, nbfd,
|
||||
nsec, nval))
|
||||
return TRUE;
|
||||
#endif /* ENABLE_PLUGINS */
|
||||
|
||||
/* If either section has the output_section field set to
|
||||
bfd_abs_section_ptr, it means that the section is being
|
||||
discarded, and this is not really a multiple definition at all.
|
||||
FIXME: It would be cleaner to somehow ignore symbols defined in
|
||||
sections which are being discarded. */
|
||||
FIXME: It would be cleaner to somehow ignore symbols defined in
|
||||
sections which are being discarded. */
|
||||
if ((osec->output_section != NULL
|
||||
&& ! bfd_is_abs_section (osec)
|
||||
&& bfd_is_abs_section (osec->output_section))
|
||||
|
@ -1456,17 +1447,8 @@ notice (struct bfd_link_info *info,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_PLUGINS
|
||||
/* We should hide symbols in the dummy IR BFDs from the nocrossrefs list
|
||||
and let the real object files that are generated and added later trip
|
||||
the error instead. Similarly would be better to trace the real symbol
|
||||
from the real file than the temporary dummy. */
|
||||
if (!plugin_notice (info, name, abfd, section, value))
|
||||
return TRUE;
|
||||
#endif /* ENABLE_PLUGINS */
|
||||
|
||||
if (info->notice_hash != NULL
|
||||
&& bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE) != NULL)
|
||||
&& bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE) != NULL)
|
||||
{
|
||||
if (bfd_is_und_section (section))
|
||||
einfo ("%B: reference to %s\n", abfd, name);
|
||||
|
|
213
ld/plugin.c
213
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)
|
||||
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);
|
||||
}
|
||||
|
|
17
ld/plugin.h
17
ld/plugin.h
|
@ -24,6 +24,10 @@
|
|||
/* Report plugin symbols. */
|
||||
extern bfd_boolean report_plugin_symbols;
|
||||
|
||||
/* Set at all symbols read time, to avoid recursively offering the plugin
|
||||
its own newly-added input files and libs to claim. */
|
||||
extern bfd_boolean no_more_claiming;
|
||||
|
||||
/* This is the only forward declaration we need to avoid having
|
||||
to include the plugin-api.h header in order to use this file. */
|
||||
struct ld_plugin_input_file;
|
||||
|
@ -62,17 +66,4 @@ extern void plugin_call_cleanup (void);
|
|||
add_symbols hook has been called so that it can be read when linking. */
|
||||
extern bfd *plugin_get_ir_dummy_bfd (const char *name, bfd *template);
|
||||
|
||||
/* Notice-symbol bfd linker callback hook. */
|
||||
extern bfd_boolean plugin_notice (struct bfd_link_info *info,
|
||||
const char *name, bfd *abfd,
|
||||
asection *section, bfd_vma value);
|
||||
|
||||
/* Multiple-definition bfd linker callback hook. */
|
||||
extern 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);
|
||||
|
||||
#endif /* !def GLD_PLUGIN_H */
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
#...
|
||||
.*: symbol `func' definition: 0, visibility: 0, resolution: 2
|
||||
.*: symbol `func1' definition: 0, visibility: 1, resolution: 3
|
||||
.*: symbol `func2' definition: 0, visibility: 2, resolution: 3
|
||||
.*: symbol `func3' definition: 0, visibility: 3, resolution: 3
|
||||
#pass
|
|
@ -26,5 +26,6 @@ hook called: claim_file tmpdir/func.o \[@0/.* CLAIMED
|
|||
hook called: claim_file tmpdir/text.o \[@0/.* not claimed
|
||||
#...
|
||||
hook called: all symbols read.
|
||||
`func' referenced in section `\.text' of tmpdir/main.o: defined in discarded section .*
|
||||
hook called: cleanup.
|
||||
#...
|
||||
|
|
|
@ -30,5 +30,6 @@ hook called: claim_file tmpdir/text.o \[@0/.* not claimed
|
|||
hook called: all symbols read.
|
||||
Sym: '_?func' Resolution: LDPR_PREVAILING_DEF
|
||||
Sym: '_?func2' Resolution: LDPR_PREVAILING_DEF_IRONLY
|
||||
`func' referenced in section `\.text' of tmpdir/main.o: defined in discarded section .*
|
||||
hook called: cleanup.
|
||||
#...
|
||||
|
|
|
@ -152,8 +152,8 @@ set plugin_extra_elf_tests [list \
|
|||
-plugin-opt sym:${_}func2::0:2:0 \
|
||||
-plugin-opt sym:${_}func3::0:3:0 \
|
||||
-plugin-opt dumpresolutions \
|
||||
$testobjfiles $libs" "" "" {{ld plugin-ignore.d} \
|
||||
{readelf -s plugin-vis-1.d}} "main.x" ] \
|
||||
-plugin-opt add:tmpdir/func.o \
|
||||
$testobjfiles $libs --verbose=2" "" "" {{ld plugin-12.d}} "main.x" ] \
|
||||
]
|
||||
|
||||
if { !$can_compile || $failed_compile } {
|
||||
|
|
Loading…
Reference in New Issue