diff --git a/bfd/elflink.c b/bfd/elflink.c index 99b7ca1..c2bf9c3 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -5054,7 +5054,9 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info) goto error_return; if (! bfd_check_format (element, bfd_object)) - goto error_return; + /* goto error_return; */ + /* this might be an object understood only by an LTO plugin */ + bfd_elf_make_object (element); /* Doublecheck that we have not included this object already--it should be impossible, but there may be diff --git a/ld/ldfile.c b/ld/ldfile.c index 16baef8..159a60c 100644 --- a/ld/ldfile.c +++ b/ld/ldfile.c @@ -38,6 +38,7 @@ #ifdef ENABLE_PLUGINS #include "plugin-api.h" #include "plugin.h" +#include "elf-bfd.h" #endif /* ENABLE_PLUGINS */ bfd_boolean ldfile_assumed_script = FALSE; @@ -124,6 +125,7 @@ bfd_boolean ldfile_try_open_bfd (const char *attempt, lang_input_statement_type *entry) { + int is_obj = 0; entry->the_bfd = bfd_openr (attempt, entry->target); if (verbose) @@ -168,6 +170,34 @@ ldfile_try_open_bfd (const char *attempt, { if (! bfd_check_format (check, bfd_object)) { +#ifdef ENABLE_PLUGINS + if (check == entry->the_bfd + && bfd_get_error () == bfd_error_file_not_recognized + && ! ldemul_unrecognized_file (entry)) + { + if (plugin_active_plugins_p () + && !no_more_claiming) + { + int fd = open (attempt, O_RDONLY | O_BINARY); + if (fd >= 0) + { + struct ld_plugin_input_file file; + + bfd_elf_make_object (entry->the_bfd); + + file.name = attempt; + file.offset = 0; + file.filesize = lseek (fd, 0, SEEK_END); + file.fd = fd; + plugin_maybe_claim (&file, entry); + + if (entry->flags.claimed) + return TRUE; + } + } + } +#endif /* ENABLE_PLUGINS */ + if (check == entry->the_bfd && entry->flags.search_dirs && bfd_get_error () == bfd_error_file_not_recognized @@ -303,7 +333,9 @@ success: bfd_object that it sets the bfd's arch and mach, which 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) + if (((is_obj = bfd_check_format (entry->the_bfd, bfd_object)) + || (bfd_get_format(entry->the_bfd) == bfd_unknown + && bfd_get_error () == bfd_error_file_not_recognized)) && plugin_active_plugins_p () && !no_more_claiming) { @@ -312,6 +344,9 @@ success: { struct ld_plugin_input_file file; + if (!is_obj) + bfd_elf_make_object (entry->the_bfd); + file.name = attempt; file.offset = 0; file.filesize = lseek (fd, 0, SEEK_END); diff --git a/ld/ldlang.h b/ld/ldlang.h index 2dbec5a..8f05f75 100644 --- a/ld/ldlang.h +++ b/ld/ldlang.h @@ -305,6 +305,8 @@ typedef struct lang_input_statement_struct const char *target; struct lang_input_statement_flags flags; + + struct ld_plugin_input_file *plugin_input_file; } lang_input_statement_type; typedef struct diff --git a/ld/plugin.c b/ld/plugin.c index 0d5339f..024e109 100644 --- a/ld/plugin.c +++ b/ld/plugin.c @@ -36,6 +36,8 @@ #include #endif +#include + /* Report plugin symbols. */ bfd_boolean report_plugin_symbols; @@ -114,6 +116,7 @@ static const enum ld_plugin_tag tv_header_tags[] = LDPT_REGISTER_CLEANUP_HOOK, LDPT_ADD_SYMBOLS, LDPT_GET_INPUT_FILE, + LDPT_GET_VIEW, LDPT_RELEASE_INPUT_FILE, LDPT_GET_SYMBOLS, LDPT_GET_SYMBOLS_V2, @@ -429,19 +432,75 @@ add_symbols (void *handle, int nsyms, const struct ld_plugin_symbol *syms) /* Get the input file information with an open (possibly re-opened) file descriptor. */ static enum ld_plugin_status -get_input_file (const void *handle ATTRIBUTE_UNUSED, - struct ld_plugin_input_file *file ATTRIBUTE_UNUSED) +get_input_file (const void *handle, + struct ld_plugin_input_file *file) { + bfd *abfd = (bfd*) handle; + struct ld_plugin_input_file *f; + ASSERT (called_plugin); - return LDPS_ERR; + + if (!abfd->usrdata) + return LDPS_BAD_HANDLE; + f = ((lang_input_statement_type *)(abfd->usrdata))->plugin_input_file; + if (!f) + return LDPS_BAD_HANDLE; + + if (f->fd < 0) + f->fd = open (f->name, O_RDONLY | O_BINARY); + memcpy(file, f, sizeof(struct ld_plugin_input_file)); + + return LDPS_OK; } -/* Release the input file. */ static enum ld_plugin_status -release_input_file (const void *handle ATTRIBUTE_UNUSED) +get_view (const void *handle, const void **viewp) { + bfd *abfd = (bfd*) handle; + struct ld_plugin_input_file *f; + off_t map_offset, offset_diff; + ASSERT (called_plugin); - return LDPS_ERR; + + if (!abfd->usrdata) + return LDPS_BAD_HANDLE; + f = ((lang_input_statement_type *)(abfd->usrdata))->plugin_input_file; + if (!f || f->fd <= 0) + return LDPS_BAD_HANDLE; + + map_offset = f->offset & ~(sysconf(_SC_PAGE_SIZE) - 1); + offset_diff = f->offset - map_offset; + /* FIXME: We leak this? */ + *viewp = (const void*) + (((char *) mmap(NULL, f->filesize + offset_diff, PROT_READ, MAP_PRIVATE, + f->fd, map_offset)) + offset_diff); + if (!*viewp) + return LDPS_ERR; + + return LDPS_OK; +} + +/* Release the input file. */ +static enum ld_plugin_status +release_input_file (const void *handle) +{ + bfd *abfd = (bfd*) handle; + struct ld_plugin_input_file *f; + + ASSERT (called_plugin); + + if (!abfd->usrdata) + return LDPS_BAD_HANDLE; + f = ((lang_input_statement_type *)(abfd->usrdata))->plugin_input_file; + if (!f) + return LDPS_BAD_HANDLE; + + if (f->fd >= 0) { + close(f->fd); + f->fd = -1; + } + + return LDPS_OK; } /* Return TRUE if a defined symbol might be reachable from outside the @@ -724,6 +783,9 @@ set_tv_header (struct ld_plugin_tv *tv) case LDPT_GET_INPUT_FILE: TVU(get_input_file) = get_input_file; break; + case LDPT_GET_VIEW: + TVU(get_view) = get_view; + break; case LDPT_RELEASE_INPUT_FILE: TVU(release_input_file) = release_input_file; break; @@ -867,9 +929,21 @@ plugin_maybe_claim (struct ld_plugin_input_file *file, the plugin may want to add. */ file->handle = plugin_get_ir_dummy_bfd (entry->the_bfd->filename, entry->the_bfd); + + /* The plugin might call get_view on the provided handle, + prepare for that. */ + lang_input_statement_type dummy_entry; + memset(&dummy_entry, 0, sizeof (lang_input_statement_type)); + dummy_entry.plugin_input_file = file; + ((bfd *) file->handle)->usrdata = &dummy_entry; + if (plugin_call_claim_file (file, &claimed)) einfo (_("%P%F: %s: plugin reported error claiming file\n"), plugin_error_plugin ()); + + /* Make sure the dummy_entry is not used outside of this scope. */ + ((bfd *) file->handle)->usrdata = NULL; + /* fd belongs to us, not the plugin; but we don't need it. */ close (file->fd); if (claimed) @@ -883,6 +957,17 @@ plugin_maybe_claim (struct ld_plugin_input_file *file, entry->the_bfd = file->handle; entry->flags.claimed = TRUE; bfd_make_readable (entry->the_bfd); + + /* Save a copy of the input file information for use by get_input_file + * later. */ + /* FIXME: We leak this? */ + entry->plugin_input_file = (struct ld_plugin_input_file *) + xcalloc (1, sizeof (struct ld_plugin_input_file)); + memcpy(entry->plugin_input_file, file, + sizeof (struct ld_plugin_input_file)); + entry->plugin_input_file->fd = -1; + entry->plugin_input_file->name = xstrdup(file->name); + entry->plugin_input_file->handle = entry->the_bfd; } else {