diff options
Diffstat (limited to 'ld/plugin.c')
-rw-r--r-- | ld/plugin.c | 213 |
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); } |