X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=ld%2Fplugin.c;h=b455af6d6762321200f37a7103619271b99779b2;hb=0381901e629115f5f0d92a27fe74b1814f6f389a;hp=28236f2404b7cfd68cc04243c6a938d7ec5144dd;hpb=f4b78d1898203363e7f551497b6231d0f891d6f9;p=deliverable%2Fbinutils-gdb.git diff --git a/ld/plugin.c b/ld/plugin.c index 28236f2404..b455af6d67 100644 --- a/ld/plugin.c +++ b/ld/plugin.c @@ -1,5 +1,5 @@ /* Plugin control for the GNU linker. - Copyright (C) 2010-2015 Free Software Foundation, Inc. + Copyright (C) 2010-2020 Free Software Foundation, Inc. This file is part of the GNU Binutils. @@ -21,17 +21,32 @@ #include "sysdep.h" #include "libiberty.h" #include "bfd.h" +#if BFD_SUPPORTS_PLUGINS #include "bfdlink.h" #include "bfdver.h" +#include "ctf-api.h" #include "ld.h" #include "ldmain.h" #include "ldmisc.h" #include "ldexp.h" #include "ldlang.h" #include "ldfile.h" -#include "plugin.h" #include "plugin-api.h" +#include "../bfd/plugin.h" +#include "plugin.h" #include "elf-bfd.h" +#if HAVE_MMAP +# include +# ifndef MAP_FAILED +# define MAP_FAILED ((void *) -1) +# endif +# ifndef PROT_READ +# define PROT_READ 0 +# endif +# ifndef MAP_PRIVATE +# define MAP_PRIVATE 0 +# endif +#endif #include #if !(defined(errno) || defined(_MSC_VER) && defined(_INC_ERRNO)) extern int errno; @@ -76,13 +91,22 @@ typedef struct plugin bfd_boolean cleanup_done; } plugin_t; +typedef struct view_buffer +{ + char *addr; + size_t filesize; + off_t offset; +} view_buffer_t; + /* The internal version of struct ld_plugin_input_file with a BFD pointer. */ typedef struct plugin_input_file { bfd *abfd; + view_buffer_t view_buffer; char *name; int fd; + bfd_boolean use_mmap; off_t offset; off_t filesize; } plugin_input_file_t; @@ -116,6 +140,11 @@ static struct bfd_link_callbacks plugin_callbacks; its own newly-added input files and libs to claim. */ bfd_boolean no_more_claiming = FALSE; +#if HAVE_MMAP && HAVE_GETPAGESIZE +/* Page size used by mmap. */ +static off_t plugin_pagesize; +#endif + /* List of tags to set in the constant leading part of the tv array. */ static const enum ld_plugin_tag tv_header_tags[] = { @@ -147,6 +176,8 @@ static bfd_boolean plugin_notice (struct bfd_link_info *, struct bfd_link_hash_entry *, bfd *, asection *, bfd_vma, flagword); +static bfd_cleanup plugin_object_p (bfd *); + #if !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H) #define RTLD_NOW 0 /* Dummy value. */ @@ -207,13 +238,26 @@ void plugin_opt_plugin (const char *plugin) { plugin_t *newplug; + plugin_t *curplug = plugins_list; newplug = xmalloc (sizeof *newplug); memset (newplug, 0, sizeof *newplug); newplug->name = plugin; newplug->dlhandle = dlopen (plugin, RTLD_NOW); if (!newplug->dlhandle) - einfo (_("%P%F: %s: error loading plugin: %s\n"), plugin, dlerror ()); + einfo (_("%F%P: %s: error loading plugin: %s\n"), plugin, dlerror ()); + + /* Check if plugin has been loaded already. */ + while (curplug) + { + if (newplug->dlhandle == curplug->dlhandle) + { + einfo (_("%P: %s: duplicated plugin\n"), plugin); + free (newplug); + return; + } + curplug = curplug->next; + } /* Chain on end, so when we run list it is in command-line order. */ *plugins_tail_chain_ptr = newplug; @@ -265,17 +309,24 @@ static bfd * plugin_get_ir_dummy_bfd (const char *name, bfd *srctemplate) { bfd *abfd; + bfd_boolean bfd_plugin_target; bfd_use_reserved_id = 1; + bfd_plugin_target = bfd_plugin_target_p (srctemplate->xvec); abfd = bfd_create (concat (name, IRONLY_SUFFIX, (const char *) NULL), - srctemplate); + bfd_plugin_target ? link_info.output_bfd : srctemplate); 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)) + if (!bfd_make_writable (abfd)) + goto report_error; + if (!bfd_plugin_target) + { + bfd_set_arch_info (abfd, bfd_get_arch_info (srctemplate)); + bfd_set_gp_size (abfd, bfd_get_gp_size (srctemplate)); + if (!bfd_copy_private_bfd_data (srctemplate, abfd)) + goto report_error; + } { flagword flags; @@ -286,7 +337,8 @@ plugin_get_ir_dummy_bfd (const char *name, bfd *srctemplate) return abfd; } } - einfo (_("could not create dummy IR bfd: %F%E\n")); + report_error: + einfo (_("%F%P: could not create dummy IR bfd: %E\n")); return NULL; } @@ -353,12 +405,6 @@ asymbol_from_plugin_symbol (bfd *abfd, asymbol *asym, flags = BSF_GLOBAL; section = bfd_com_section_ptr; asym->value = ldsym->size; - /* For ELF targets, set alignment of common symbol to 1. */ - if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) - { - ((elf_symbol_type *) asym)->internal_elf_sym.st_shndx = SHN_COMMON; - ((elf_symbol_type *) asym)->internal_elf_sym.st_value = 1; - } break; default: @@ -367,19 +413,27 @@ asymbol_from_plugin_symbol (bfd *abfd, asymbol *asym, asym->flags = flags; asym->section = section; - /* Visibility only applies on ELF targets. */ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) { elf_symbol_type *elfsym = elf_symbol_from (abfd, asym); unsigned char visibility; if (!elfsym) - einfo (_("%P%F: %s: non-ELF symbol in ELF BFD!\n"), asym->name); + einfo (_("%F%P: %s: non-ELF symbol in ELF BFD!\n"), asym->name); + + if (ldsym->def == LDPK_COMMON) + { + elfsym->internal_elf_sym.st_shndx = SHN_COMMON; + elfsym->internal_elf_sym.st_value = 1; + } + switch (ldsym->visibility) { default: - einfo (_("%P%F: unknown ELF symbol visibility: %d!\n"), + einfo (_("%F%P: unknown ELF symbol visibility: %d!\n"), ldsym->visibility); + return LDPS_ERR; + case LDPV_DEFAULT: visibility = STV_DEFAULT; break; @@ -393,9 +447,7 @@ asymbol_from_plugin_symbol (bfd *abfd, asymbol *asym, visibility = STV_HIDDEN; break; } - elfsym->internal_elf_sym.st_other - = (visibility | (elfsym->internal_elf_sym.st_other - & ~ELF_ST_VISIBILITY (-1))); + elfsym->internal_elf_sym.st_other |= visibility; } return LDPS_OK; @@ -475,35 +527,80 @@ get_input_file (const void *handle, struct ld_plugin_input_file *file) static enum ld_plugin_status get_view (const void *handle, const void **viewp) { - const plugin_input_file_t *input = handle; + plugin_input_file_t *input = (plugin_input_file_t *) handle; char *buffer; - size_t size; + size_t size = input->filesize; + off_t offset = input->offset; +#if HAVE_MMAP && HAVE_GETPAGESIZE + off_t bias; +#endif ASSERT (called_plugin); - if (lseek (input->fd, input->offset, SEEK_SET) < 0) - return LDPS_ERR; + /* FIXME: einfo should support %lld. */ + if ((off_t) size != input->filesize) + einfo (_("%F%P: unsupported input file size: %s (%ld bytes)\n"), + input->name, (long) input->filesize); - size = input->filesize; - buffer = bfd_alloc (input->abfd, size); - if (buffer == NULL) - return LDPS_ERR; - *viewp = buffer; + /* Check the cached view buffer. */ + if (input->view_buffer.addr != NULL + && input->view_buffer.filesize == size + && input->view_buffer.offset == offset) + { + *viewp = input->view_buffer.addr; + return LDPS_OK; + } - do + input->view_buffer.filesize = size; + input->view_buffer.offset = offset; + +#if HAVE_MMAP +# if HAVE_GETPAGESIZE + bias = offset % plugin_pagesize; + offset -= bias; + size += bias; +# endif + buffer = mmap (NULL, size, PROT_READ, MAP_PRIVATE, input->fd, offset); + if (buffer != MAP_FAILED) + { + input->use_mmap = TRUE; +# if HAVE_GETPAGESIZE + buffer += bias; +# endif + } + else +#endif { - ssize_t got = read (input->fd, buffer, size); - if (got == 0) - break; - else if (got > 0) + char *p; + + input->use_mmap = FALSE; + + if (lseek (input->fd, offset, SEEK_SET) < 0) + return LDPS_ERR; + + buffer = bfd_alloc (input->abfd, size); + if (buffer == NULL) + return LDPS_ERR; + + p = buffer; + do { - buffer += got; - size -= got; + ssize_t got = read (input->fd, p, size); + if (got == 0) + break; + else if (got > 0) + { + p += got; + size -= got; + } + else if (errno != EINTR) + return LDPS_ERR; } - else if (errno != EINTR) - return LDPS_ERR; + while (size > 0); } - while (size > 0); + + input->view_buffer.addr = buffer; + *viewp = buffer; return LDPS_OK; } @@ -512,10 +609,13 @@ get_view (const void *handle, const void **viewp) static enum ld_plugin_status release_input_file (const void *handle) { - const plugin_input_file_t *input = handle; + plugin_input_file_t *input = (plugin_input_file_t *) handle; ASSERT (called_plugin); if (input->fd != -1) - close (input->fd); + { + close (input->fd); + input->fd = -1; + } return LDPS_OK; } @@ -525,11 +625,11 @@ static inline bfd_boolean is_visible_from_outside (struct ld_plugin_symbol *lsym, struct bfd_link_hash_entry *blhe) { - struct bfd_sym_chain *sym; - - if (link_info.relocatable) + if (bfd_link_relocatable (&link_info)) return TRUE; - if (link_info.export_dynamic || !link_info.executable) + if (blhe->non_ir_ref_dynamic + || link_info.export_dynamic + || bfd_link_dll (&link_info)) { /* Check if symbol is hidden by version script. */ if (bfd_hide_sym_by_version (link_info.version_info, @@ -556,14 +656,76 @@ is_visible_from_outside (struct ld_plugin_symbol *lsym, || lsym->visibility == LDPV_PROTECTED); } - for (sym = &entry_symbol; sym != NULL; sym = sym->next) - if (sym->name - && strcmp (sym->name, blhe->root.string) == 0) - return TRUE; - return FALSE; } +/* Return LTO kind string name that corresponds to IDX enum value. */ +static const char * +get_lto_kind (unsigned int idx) +{ + static char buffer[64]; + const char *lto_kind_str[5] = + { + "DEF", + "WEAKDEF", + "UNDEF", + "WEAKUNDEF", + "COMMON" + }; + + if (idx < ARRAY_SIZE (lto_kind_str)) + return lto_kind_str [idx]; + + sprintf (buffer, _("unknown LTO kind value %x"), idx); + return buffer; +} + +/* Return LTO resolution string name that corresponds to IDX enum value. */ +static const char * +get_lto_resolution (unsigned int idx) +{ + static char buffer[64]; + static const char *lto_resolution_str[10] = + { + "UNKNOWN", + "UNDEF", + "PREVAILING_DEF", + "PREVAILING_DEF_IRONLY", + "PREEMPTED_REG", + "PREEMPTED_IR", + "RESOLVED_IR", + "RESOLVED_EXEC", + "RESOLVED_DYN", + "PREVAILING_DEF_IRONLY_EXP", + }; + + if (idx < ARRAY_SIZE (lto_resolution_str)) + return lto_resolution_str [idx]; + + sprintf (buffer, _("unknown LTO resolution value %x"), idx); + return buffer; +} + +/* Return LTO visibility string name that corresponds to IDX enum value. */ +static const char * +get_lto_visibility (unsigned int idx) +{ + static char buffer[64]; + const char *lto_visibility_str[4] = + { + "DEFAULT", + "PROTECTED", + "INTERNAL", + "HIDDEN" + }; + + if (idx < ARRAY_SIZE (lto_visibility_str)) + return lto_visibility_str [idx]; + + sprintf (buffer, _("unknown LTO visibility value %x"), idx); + return buffer; +} + /* Get the symbol resolution info for a plugin-claimed input file. */ static enum ld_plugin_status get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms, @@ -579,16 +741,52 @@ get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms, struct bfd_link_hash_entry *blhe; asection *owner_sec; int res; + struct bfd_link_hash_entry *h + = bfd_link_hash_lookup (link_info.hash, syms[n].name, + FALSE, FALSE, TRUE); + enum { wrap_none, wrapper, wrapped } wrap_status = wrap_none; - if (syms[n].def != LDPK_UNDEF) - blhe = bfd_link_hash_lookup (link_info.hash, syms[n].name, - FALSE, FALSE, TRUE); + if (syms[n].def != LDPK_UNDEF && syms[n].def != LDPK_WEAKUNDEF) + { + blhe = h; + if (blhe && link_info.wrap_hash != NULL) + { + /* Check if a symbol is a wrapper symbol. */ + struct bfd_link_hash_entry *unwrap + = unwrap_hash_lookup (&link_info, (bfd *) abfd, blhe); + if (unwrap && unwrap != h) + wrap_status = wrapper; + } + } else - blhe = bfd_wrapped_link_hash_lookup (link_info.output_bfd, &link_info, - syms[n].name, FALSE, FALSE, TRUE); + { + blhe = bfd_wrapped_link_hash_lookup (link_info.output_bfd, + &link_info, syms[n].name, + FALSE, FALSE, TRUE); + /* Check if a symbol is a wrapped symbol. */ + if (blhe && blhe != h) + wrap_status = wrapped; + } if (!blhe) { - res = LDPR_UNKNOWN; + /* The plugin is called to claim symbols in an archive element + from plugin_object_p. But those symbols aren't needed to + create output. They are defined and referenced only within + IR. */ + switch (syms[n].def) + { + default: + abort (); + case LDPK_UNDEF: + case LDPK_WEAKUNDEF: + res = LDPR_UNDEF; + break; + case LDPK_DEF: + case LDPK_WEAKDEF: + case LDPK_COMMON: + res = LDPR_PREVAILING_DEF_IRONLY; + break; + } goto report_symbol; } @@ -604,7 +802,7 @@ get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms, && blhe->type != bfd_link_hash_common) { /* We should not have a new, indirect or warning symbol here. */ - einfo ("%P%F: %s: plugin symbol table corrupt (sym type %d)\n", + einfo (_("%F%P: %s: plugin symbol table corrupt (sym type %d)\n"), called_plugin->name, blhe->type); } @@ -654,9 +852,11 @@ get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms, /* We need to know if the sym is referenced from non-IR files. Or even potentially-referenced, perhaps in a future final link if this is a partial one, perhaps dynamically at load-time if the - symbol is externally visible. */ - if (blhe->non_ir_ref) + symbol is externally visible. Also check for wrapper symbol. */ + if (blhe->non_ir_ref_regular || wrap_status == wrapper) res = LDPR_PREVAILING_DEF; + else if (wrap_status == wrapped) + res = LDPR_RESOLVED_IR; else if (is_visible_from_outside (&syms[n], blhe)) res = def_ironly_exp; } @@ -664,10 +864,12 @@ get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms, report_symbol: syms[n].resolution = res; if (report_plugin_symbols) - einfo (_("%P: %B: symbol `%s' " - "definition: %d, visibility: %d, resolution: %d\n"), + einfo (_("%P: %pB: symbol `%s' " + "definition: %s, visibility: %s, resolution: %s\n"), abfd, syms[n].name, - syms[n].def, syms[n].visibility, res); + get_lto_kind (syms[n].def), + get_lto_visibility (syms[n].visibility), + get_lto_resolution (res)); } return LDPS_OK; } @@ -688,10 +890,14 @@ get_symbols_v2 (const void *handle, int nsyms, struct ld_plugin_symbol *syms) static enum ld_plugin_status add_input_file (const char *pathname) { + lang_input_statement_type *is; + ASSERT (called_plugin); - if (!lang_add_input_file (xstrdup (pathname), lang_input_file_is_file_enum, - NULL)) + is = lang_add_input_file (xstrdup (pathname), lang_input_file_is_file_enum, + NULL); + if (!is) return LDPS_ERR; + is->flags.lto_output = 1; return LDPS_OK; } @@ -699,10 +905,14 @@ add_input_file (const char *pathname) static enum ld_plugin_status add_input_library (const char *pathname) { + lang_input_statement_type *is; + ASSERT (called_plugin); - if (!lang_add_input_file (xstrdup (pathname), lang_input_file_is_l_enum, - NULL)) + is = lang_add_input_file (xstrdup (pathname), lang_input_file_is_l_enum, + NULL); + if (!is) return LDPS_ERR; + is->flags.lto_output = 1; return LDPS_OK; } @@ -730,18 +940,24 @@ message (int level, const char *format, ...) putchar ('\n'); break; case LDPL_WARNING: - vfinfo (stdout, format, args, TRUE); - putchar ('\n'); + { + char *newfmt = concat (_("%P: warning: "), format, "\n", + (const char *) NULL); + vfinfo (stdout, newfmt, args, TRUE); + free (newfmt); + } break; case LDPL_FATAL: case LDPL_ERROR: default: { - char *newfmt = ACONCAT ((level == LDPL_FATAL ? "%P%F: " : "%P%X: ", - format, "\n", (const char *) NULL)); + char *newfmt = concat (level == LDPL_FATAL ? "%F" : "%X", + _("%P: error: "), format, "\n", + (const char *) NULL); fflush (stdout); vfinfo (stderr, newfmt, args, TRUE); fflush (stderr); + free (newfmt); } break; } @@ -776,11 +992,10 @@ set_tv_header (struct ld_plugin_tv *tv) TVU(val) = major * 100 + minor; break; case LDPT_LINKER_OUTPUT: - TVU(val) = (link_info.relocatable - ? LDPO_REL - : (link_info.executable - ? (link_info.pie ? LDPO_PIE : LDPO_EXEC) - : LDPO_DYN)); + TVU(val) = (bfd_link_relocatable (&link_info) ? LDPO_REL + : bfd_link_pde (&link_info) ? LDPO_EXEC + : bfd_link_pie (&link_info) ? LDPO_PIE + : LDPO_DYN); break; case LDPT_OUTPUT_NAME: TVU(string) = output_filename; @@ -882,14 +1097,14 @@ plugin_load_plugins (void) if (!onloadfn) onloadfn = (ld_plugin_onload) dlsym (curplug->dlhandle, "_onload"); if (!onloadfn) - einfo (_("%P%F: %s: error loading plugin: %s\n"), + einfo (_("%F%P: %s: error loading plugin: %s\n"), curplug->name, dlerror ()); set_tv_plugin_args (curplug, &my_tv[tv_header_size]); called_plugin = curplug; rv = (*onloadfn) (my_tv); called_plugin = NULL; if (rv != LDPS_OK) - einfo (_("%P%F: %s: plugin error: %d\n"), curplug->name, rv); + einfo (_("%F%P: %s: plugin error: %d\n"), curplug->name, rv); curplug = curplug->next; } @@ -903,6 +1118,12 @@ plugin_load_plugins (void) link_info.notice_all = TRUE; link_info.lto_plugin_active = TRUE; link_info.callbacks = &plugin_callbacks; + + register_ld_plugin_object_p (plugin_object_p); + +#if HAVE_MMAP && HAVE_GETPAGESIZE + plugin_pagesize = getpagesize (); +#endif } /* Call 'claim file' hook for all plugins. */ @@ -911,13 +1132,12 @@ plugin_call_claim_file (const struct ld_plugin_input_file *file, int *claimed) { plugin_t *curplug = plugins_list; *claimed = FALSE; - if (no_more_claiming) - return 0; while (curplug && !*claimed) { if (curplug->claim_file_handler) { enum ld_plugin_status rv; + called_plugin = curplug; rv = (*curplug->claim_file_handler) (file, claimed); called_plugin = NULL; @@ -929,73 +1149,148 @@ plugin_call_claim_file (const struct ld_plugin_input_file *file, int *claimed) return plugin_error_p () ? -1 : 0; } -void -plugin_maybe_claim (struct ld_plugin_input_file *file, - lang_input_statement_type *entry) +/* Duplicates a character string with memory attached to ABFD. */ + +static char * +plugin_strdup (bfd *abfd, const char *str) { - int claimed = 0; + size_t strlength; + char *copy; + strlength = strlen (str) + 1; + copy = bfd_alloc (abfd, strlength); + if (copy == NULL) + einfo (_("%F%P: plugin_strdup failed to allocate memory: %s\n"), + bfd_get_error ()); + memcpy (copy, str, strlength); + return copy; +} + +static void +plugin_cleanup (bfd *abfd ATTRIBUTE_UNUSED) +{ +} + +static bfd_cleanup +plugin_object_p (bfd *ibfd) +{ + int claimed; plugin_input_file_t *input; - size_t namelength; + struct ld_plugin_input_file file; + bfd *abfd; + + /* Don't try the dummy object file. */ + if ((ibfd->flags & BFD_PLUGIN) != 0) + return NULL; + + if (ibfd->plugin_format != bfd_plugin_unknown) + { + if (ibfd->plugin_format == bfd_plugin_yes) + return plugin_cleanup; + else + return NULL; + } /* We create a dummy BFD, initially empty, to house whatever symbols the plugin may want to add. */ - bfd *abfd = plugin_get_ir_dummy_bfd (entry->the_bfd->filename, - entry->the_bfd); + abfd = plugin_get_ir_dummy_bfd (bfd_get_filename (ibfd), ibfd); input = bfd_alloc (abfd, sizeof (*input)); if (input == NULL) - einfo (_("%P%F: plugin failed to allocate memory for input: %s\n"), + einfo (_("%F%P: plugin failed to allocate memory for input: %s\n"), bfd_get_error ()); - input->abfd = abfd; - input->fd = file->fd; - input->offset = file->offset; - input->filesize = file->filesize; - namelength = strlen (entry->the_bfd->filename) + 1; - input->name = bfd_alloc (abfd, namelength); - if (input->name == NULL) - einfo (_("%P%F: plugin failed to allocate memory for input filename: %s\n"), - bfd_get_error ()); - memcpy (input->name, entry->the_bfd->filename, namelength); + if (!bfd_plugin_open_input (ibfd, &file)) + return NULL; - file->handle = input; + if (file.name == bfd_get_filename (ibfd)) + { + /* We must copy filename attached to ibfd if it is not an archive + member since it may be freed by bfd_close below. */ + file.name = plugin_strdup (abfd, file.name); + } - if (plugin_call_claim_file (file, &claimed)) - einfo (_("%P%F: %s: plugin reported error claiming file\n"), + file.handle = input; + input->abfd = abfd; + input->view_buffer.addr = NULL; + input->view_buffer.filesize = 0; + input->view_buffer.offset = 0; + input->fd = file.fd; + input->use_mmap = FALSE; + input->offset = file.offset; + input->filesize = file.filesize; + input->name = plugin_strdup (abfd, bfd_get_filename (ibfd)); + + claimed = 0; + + if (plugin_call_claim_file (&file, &claimed)) + einfo (_("%F%P: %s: plugin reported error claiming file\n"), plugin_error_plugin ()); - if (bfd_check_format (entry->the_bfd, bfd_object)) + if (input->fd != -1 && !bfd_plugin_target_p (ibfd->xvec)) { - /* FIXME: fd belongs to us, not the plugin. IR for GCC plugin, - which doesn't need fd after plugin_call_claim_file, is - stored in bfd_object file. Since GCC plugin before GCC 5 - doesn't call release_input_file, we close it here. IR for - LLVM plugin, which needs fd after plugin_call_claim_file and - calls release_input_file after it is done, is stored in - non-bfd_object file. This scheme doesn't work when a plugin - needs fd and its IR is stored in bfd_object file. */ - close (file->fd); + /* FIXME: fd belongs to us, not the plugin. GCC plugin, which + doesn't need fd after plugin_call_claim_file, doesn't use + BFD plugin target vector. Since GCC plugin doesn't call + release_input_file, we close it here. LLVM plugin, which + needs fd after plugin_call_claim_file and calls + release_input_file after it is done, uses BFD plugin target + vector. This scheme doesn't work when a plugin needs fd and + doesn't use BFD plugin target vector neither. */ + close (input->fd); input->fd = -1; } if (claimed) { - /* Discard the real file's BFD and substitute the dummy one. */ - - /* BFD archive handling caches elements so we can't call - bfd_close for archives. */ - if (entry->the_bfd->my_archive == NULL) - bfd_close (entry->the_bfd); - entry->the_bfd = abfd; - entry->flags.claimed = TRUE; - bfd_make_readable (entry->the_bfd); + ibfd->plugin_format = bfd_plugin_yes; + ibfd->plugin_dummy_bfd = abfd; + bfd_make_readable (abfd); + abfd->no_export = ibfd->no_export; + return plugin_cleanup; } else { +#if HAVE_MMAP + if (input->use_mmap) + { + /* If plugin didn't claim the file, unmap the buffer. */ + char *addr = input->view_buffer.addr; + off_t size = input->view_buffer.filesize; +# if HAVE_GETPAGESIZE + off_t bias = input->view_buffer.offset % plugin_pagesize; + size += bias; + addr -= bias; +# endif + munmap (addr, size); + } +#endif + /* If plugin didn't claim the file, we don't need the dummy bfd. Can't avoid speculatively creating it, alas. */ + ibfd->plugin_format = bfd_plugin_no; bfd_close_all_done (abfd); - entry->flags.claimed = FALSE; + return NULL; + } +} + +void +plugin_maybe_claim (lang_input_statement_type *entry) +{ + ASSERT (entry->header.type == lang_input_statement_enum); + if (plugin_object_p (entry->the_bfd)) + { + bfd *abfd = entry->the_bfd->plugin_dummy_bfd; + + /* Discard the real file's BFD and substitute the dummy one. */ + + /* We can't call bfd_close on archives. BFD archive handling + caches elements, and add_archive_element keeps pointers to + the_bfd and the_bfd->filename in a lang_input_statement_type + linker script statement. */ + if (entry->the_bfd->my_archive == NULL) + bfd_close (entry->the_bfd); + entry->the_bfd = abfd; + entry->flags.claimed = 1; } } @@ -1050,9 +1345,10 @@ plugin_call_cleanup (void) /* 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. Mark those - referenced from a non-IR file with non_ir_ref. We have to - notice_all symbols, because we won't necessarily know until later - which ones will be contributed by IR files. */ + referenced from a non-IR file with non_ir_ref_regular or + non_ir_ref_dynamic as appropriate. We have to notice_all symbols, + because we won't necessarily know until later which ones will be + contributed by IR files. */ static bfd_boolean plugin_notice (struct bfd_link_info *info, struct bfd_link_hash_entry *h, @@ -1067,6 +1363,7 @@ plugin_notice (struct bfd_link_info *info, if (h != NULL) { bfd *sym_bfd; + bfd_boolean ref = FALSE; if (h->type == bfd_link_hash_warning) h = h->u.i.link; @@ -1082,13 +1379,17 @@ plugin_notice (struct bfd_link_info *info, { /* ??? Some of this is questionable. See comments in _bfd_generic_link_add_one_symbol for case IND. */ - if (h->type != bfd_link_hash_new) + if (h->type != bfd_link_hash_new + || inh->type == bfd_link_hash_new) { - h->non_ir_ref = TRUE; - inh->non_ir_ref = TRUE; + if ((abfd->flags & DYNAMIC) == 0) + inh->non_ir_ref_regular = TRUE; + else + inh->non_ir_ref_dynamic = TRUE; } - else if (inh->type == bfd_link_hash_new) - inh->non_ir_ref = TRUE; + + if (h->type != bfd_link_hash_new) + ref = TRUE; } /* Nothing to do here for warning symbols. */ @@ -1103,20 +1404,36 @@ plugin_notice (struct bfd_link_info *info, else if (bfd_is_und_section (section)) { /* Replace the undefined dummy bfd with the real one. */ - if ((h->type == bfd_link_hash_undefined - || h->type == bfd_link_hash_undefweak) - && (h->u.undef.abfd == NULL - || (h->u.undef.abfd->flags & BFD_PLUGIN) != 0)) - h->u.undef.abfd = abfd; - h->non_ir_ref = TRUE; + if ((h->type == bfd_link_hash_undefined + || h->type == bfd_link_hash_undefweak) + && (h->u.undef.abfd == NULL + || (h->u.undef.abfd->flags & BFD_PLUGIN) != 0)) + h->u.undef.abfd = abfd; + ref = TRUE; } - /* Otherwise, it must be a new def. Ensure any symbol defined - in an IR dummy BFD takes on a new value from a real BFD. - Weak symbols are not normally overridden by a new weak - definition, and strong symbols will normally cause multiple - definition errors. Avoid this by making the symbol appear - to be undefined. */ + + /* A common symbol should be merged with other commons or + defs with the same name. In particular, a common ought + to be overridden by a def in a -flto object. In that + sense a common is also a ref. */ + else if (bfd_is_com_section (section)) + { + if (h->type == bfd_link_hash_common + && is_ir_dummy_bfd (sym_bfd = h->u.c.p->section->owner)) + { + h->type = bfd_link_hash_undefweak; + h->u.undef.abfd = sym_bfd; + } + ref = TRUE; + } + + /* Otherwise, it must be a new def. + Ensure any symbol defined in an IR dummy BFD takes on a + new value from a real BFD. Weak symbols are not normally + overridden by a new weak definition, and strong symbols + will normally cause multiple definition errors. Avoid + this by making the symbol appear to be undefined. */ else if (((h->type == bfd_link_hash_defweak || h->type == bfd_link_hash_defined) && is_ir_dummy_bfd (sym_bfd = h->u.def.section->owner)) @@ -1126,6 +1443,14 @@ plugin_notice (struct bfd_link_info *info, h->type = bfd_link_hash_undefweak; h->u.undef.abfd = sym_bfd; } + + if (ref) + { + if ((abfd->flags & DYNAMIC) == 0) + h->non_ir_ref_regular = TRUE; + else + h->non_ir_ref_dynamic = TRUE; + } } /* Continue with cref/nocrossref/trace-sym processing. */ @@ -1138,3 +1463,4 @@ plugin_notice (struct bfd_link_info *info, abfd, section, value, flags); return TRUE; } +#endif /* BFD_SUPPORTS_PLUGINS */