From 9e2278f567e4ddeb7180ef4e0b3b24e4b087d703 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Sun, 17 Apr 2011 23:15:13 +0000 Subject: [PATCH] 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. --- bfd/bfd-in2.h | 7 +- bfd/bfd.c | 7 +- bfd/elflink.c | 5 + bfd/opncls.c | 2 +- ld/ldfile.c | 3 +- ld/ldlang.c | 111 ++++++++------- ld/ldmain.c | 30 +--- ld/plugin.c | 213 +++++++++++++++++------------ ld/plugin.h | 17 +-- ld/testsuite/ld-plugin/plugin-12.d | 6 + ld/testsuite/ld-plugin/plugin-7.d | 1 + ld/testsuite/ld-plugin/plugin-8.d | 1 + ld/testsuite/ld-plugin/plugin.exp | 4 +- 13 files changed, 223 insertions(+), 184 deletions(-) create mode 100644 ld/testsuite/ld-plugin/plugin-12.d diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index e7c410dc4ff..2c795b6cbbd 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -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 diff --git a/bfd/bfd.c b/bfd/bfd.c index 77582ec82fe..c729d631703 100644 --- a/bfd/bfd.c +++ b/bfd/bfd.c @@ -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 diff --git a/bfd/elflink.c b/bfd/elflink.c index 9ccc841da21..22755038052 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -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; diff --git a/bfd/opncls.c b/bfd/opncls.c index 3597daee01f..40432000c0a 100644 --- a/bfd/opncls.c +++ b/bfd/opncls.c @@ -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; diff --git a/ld/ldfile.c b/ld/ldfile.c index 5bbe1d8447e..96a3856e4a3 100644 --- a/ld/ldfile.c +++ b/ld/ldfile.c @@ -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) diff --git a/ld/ldlang.c b/ld/ldlang.c index 08bfa60f69d..2c07fa4d358 100644 --- a/ld/ldlang.c +++ b/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 diff --git a/ld/ldmain.c b/ld/ldmain.c index 005a8940690..52a4b04830a 100644 --- a/ld/ldmain.c +++ b/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); diff --git a/ld/plugin.c b/ld/plugin.c index 6a14f22a4b5..07f3afe9981 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); } diff --git a/ld/plugin.h b/ld/plugin.h index 6ba8fa89c9c..7b39e729ea9 100644 --- a/ld/plugin.h +++ b/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 */ diff --git a/ld/testsuite/ld-plugin/plugin-12.d b/ld/testsuite/ld-plugin/plugin-12.d new file mode 100644 index 00000000000..10d772553d8 --- /dev/null +++ b/ld/testsuite/ld-plugin/plugin-12.d @@ -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 diff --git a/ld/testsuite/ld-plugin/plugin-7.d b/ld/testsuite/ld-plugin/plugin-7.d index 75f25e01b27..ba0ed946641 100644 --- a/ld/testsuite/ld-plugin/plugin-7.d +++ b/ld/testsuite/ld-plugin/plugin-7.d @@ -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. #... diff --git a/ld/testsuite/ld-plugin/plugin-8.d b/ld/testsuite/ld-plugin/plugin-8.d index e72b0392c03..8411c313e9b 100644 --- a/ld/testsuite/ld-plugin/plugin-8.d +++ b/ld/testsuite/ld-plugin/plugin-8.d @@ -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. #... diff --git a/ld/testsuite/ld-plugin/plugin.exp b/ld/testsuite/ld-plugin/plugin.exp index 8952f1dec26..02319bfb1a0 100644 --- a/ld/testsuite/ld-plugin/plugin.exp +++ b/ld/testsuite/ld-plugin/plugin.exp @@ -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 } { -- 2.30.2