Rafael, As I mentioned earlier on IRC, the current trunk LLVM plugin requires get_view and get/release_input_file (which had not previously been the case). I've attached a version of the patch that also provides an implementation of those functions.
-Hal ----- Original Message ----- > From: "Hal Finkel" <hfin...@anl.gov> > To: "Rafael Espíndola" <rafael.espind...@gmail.com> > Cc: "Renato Golin" <renato.go...@linaro.org>, "gcc" <gcc@gcc.gnu.org>, "Jan > Hubicka" <hubi...@ucw.cz> > Sent: Tuesday, February 11, 2014 4:35:59 PM > Subject: Re: LLVM collaboration? > > ----- Original Message ----- > > From: "Rafael Espíndola" <rafael.espind...@gmail.com> > > To: "Jan Hubicka" <hubi...@ucw.cz> > > Cc: "Renato Golin" <renato.go...@linaro.org>, "gcc" > > <gcc@gcc.gnu.org>, "Hal Finkel" <hfin...@anl.gov> > > Sent: Tuesday, February 11, 2014 3:38:40 PM > > Subject: Re: Fwd: LLVM collaboration? > > > > > My reading of bfd/plugin.c is that it basically walks the > > > directory > > > and looks > > > for first plugin that returns OK for onload. (that is always the > > > case for > > > GCC/LLVM plugins). So if I instlal GCC and llvm plugin there it > > > will > > > depend who will end up being first and only that plugin will be > > > used. > > > > > > We need multiple plugin support as suggested by the directory > > > name > > > ;) > > > > > > Also it sems that currently plugin is not used if file is ELF for > > > ar/nm/ranlib > > > (as mentioned by Markus) and also GNU-ld seems to choke on LLVM > > > object files > > > even if it has plugin. > > > > > > This probably needs ot be sanitized. > > > > CCing Hal Finkel. He got this to work some time ago. Not sure if he > > ever ported the patches to bfd trunk. > > I have a patch for binutils 2.24 (attached -- I think this works, I > hand isolated it from my BG/Q patchset). I would not consider it to > be of upstream quality, but I'd obviously appreciate any assistance > on making everything clean and proper ;) > > -Hal > > > > > >> For OS X the situation is a bit different. There instead of a > > >> plugin > > >> the linker loads a library: libLTO.dylib. When doing LTO with a > > >> newer > > >> llvm, one needs to set DYLD_LIBRARY_PATH. I think I proposed > > >> setting > > >> that from clang some time ago, but I don't remember the outcome. > > >> > > >> In theory GCC could implement a libLTO.dylib and set > > >> DYLD_LIBRARY_PATH. The gold/bfd plugin that LLVM uses is > > >> basically > > >> a > > >> API mapping the other way, so the job would be inverting it. The > > >> LTO > > >> model ld64 is a bit more strict about knowing all symbol > > >> definitions > > >> and uses (including inline asm), so there would be work to be > > >> done > > >> to > > >> cover that, but the simple cases shouldn't be too hard. > > > > > > I would not care that much about symbols in asm definitions to > > > start with. > > > Even if we will force users to non-LTO those object files, it > > > would > > > be an > > > improvement over what we have now. > > > > > > One problem is that we need a volunteer to implement the reverse > > > glue > > > (libLTO->plugin API), since I do not have an OS X box (well, have > > > an old G5, > > > but even that is quite far from me right now) > > > > > > Why complete symbol tables are required? Can't ld64 be changed to > > > ignore > > > unresolved symbols in the first stage just like gold/gnu-ld does? > > > > I am not sure about this. My *guess* is that it does dead stripping > > computation before asking libLTO for the object file. I noticed the > > issue while trying to LTO firefox some time ago. > > > > Cheers, > > Rafael > > > > -- > Hal Finkel > Assistant Computational Scientist > Leadership Computing Facility > Argonne National Laboratory > -- Hal Finkel Assistant Computational Scientist Leadership Computing Facility Argonne National Laboratory
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 <windows.h> #endif +#include <sys/mman.h> + /* 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 {