diff options
author | Alan Modra <amodra@gmail.com> | 2017-09-02 11:08:05 +0930 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2017-09-02 17:39:04 +0930 |
commit | 1fa4ec6ae707402c6b61cde33cfe4bdeafd53f82 (patch) | |
tree | 2db8c41ce002aebac5440e5a6349d1c4a3a91517 /ld/ldlang.c | |
parent | ad71ce8de7dba823f5fc478e6d5eba03f1a2e822 (diff) | |
download | gdb-1fa4ec6ae707402c6b61cde33cfe4bdeafd53f82.zip gdb-1fa4ec6ae707402c6b61cde33cfe4bdeafd53f82.tar.gz gdb-1fa4ec6ae707402c6b61cde33cfe4bdeafd53f82.tar.bz2 |
LTO rescan archives
ld ought to be more clever about where it puts LTO recompiled objects.
Ideally the recompiled objects ought to be ordered to the same place
their IR objects were, and files extracted from archives on the second
pass ought to go in the same place as they would if extracted on the
first pass. This patch addresses the archive problem. Without this
fix, objects extracted from archives might be placed after the crt
files intended to go at the end of an executable or shared library,
possibly causing exception handling failures.
* ldlang.h (lang_input_statement_type): Expand comments.
(LANG_FOR_EACH_INPUT_STATEMENT): Rewrite without casts.
* ldlang.c (lang_for_each_input_file): Likewise.
(load_symbols): Set usrdata for archives.
(find_rescan_insertion): New function.
(lang_process): Trim off and reinsert entries added to file chain
when rescanning archives for LTO.
* ldmain.c (add_archive_element): Set my_archive input_statement
next pointer to last element added.
Diffstat (limited to 'ld/ldlang.c')
-rw-r--r-- | ld/ldlang.c | 79 |
1 files changed, 77 insertions, 2 deletions
diff --git a/ld/ldlang.c b/ld/ldlang.c index 96de2e2..4cb7e3f 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -2834,6 +2834,7 @@ load_symbols (lang_input_statement_type *entry, case bfd_archive: check_excluded_libs (entry->the_bfd); + entry->the_bfd->usrdata = entry; if (entry->flags.whole_archive) { bfd *member = NULL; @@ -6543,9 +6544,9 @@ lang_for_each_input_file (void (*func) (lang_input_statement_type *)) { lang_input_statement_type *f; - for (f = (lang_input_statement_type *) input_file_chain.head; + for (f = &input_file_chain.head->input_statement; f != NULL; - f = (lang_input_statement_type *) f->next_real_file) + f = &f->next_real_file->input_statement) func (f); } @@ -6942,6 +6943,51 @@ find_replacements_insert_point (void) return lastobject; } +/* Find where to insert ADD, an archive element or shared library + added during a rescan. */ + +static lang_statement_union_type ** +find_rescan_insertion (lang_input_statement_type *add) +{ + bfd *add_bfd = add->the_bfd; + lang_input_statement_type *f; + lang_input_statement_type *last_loaded = NULL; + lang_input_statement_type *before = NULL; + lang_statement_union_type **iter = NULL; + + if (add_bfd->my_archive != NULL) + add_bfd = add_bfd->my_archive; + + /* First look through the input file chain, to find an object file + before the one we've rescanned. Normal object files always + appear on both the input file chain and the file chain, so this + lets us get quickly to somewhere near the correct place on the + file chain if it is full of archive elements. Archives don't + appear on the file chain, but if an element has been extracted + then their input_statement->next points at it. */ + for (f = &input_file_chain.head->input_statement; + f != NULL; + f = &f->next_real_file->input_statement) + { + if (f->the_bfd == add_bfd) + { + before = last_loaded; + if (f->next != NULL) + return &f->next->input_statement.next; + } + if (f->the_bfd != NULL && f->next != NULL) + last_loaded = f; + } + + for (iter = before ? &before->next : &file_chain.head->input_statement.next; + *iter != NULL; + iter = &(*iter)->input_statement.next) + if ((*iter)->input_statement.the_bfd->my_archive == NULL) + break; + + return iter; +} + /* 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.) */ @@ -7112,7 +7158,36 @@ lang_process (void) lang_list_insert_after (&file_chain, &files, &file_chain.head); /* Rescan archives in case new undefined symbols have appeared. */ + files = file_chain; open_input_bfds (statement_list.head, OPEN_BFD_RESCAN); + lang_list_remove_tail (&file_chain, &files); + while (files.head != NULL) + { + lang_statement_union_type **insert; + lang_statement_union_type **iter, *temp; + bfd *my_arch; + + insert = find_rescan_insertion (&files.head->input_statement); + /* All elements from an archive can be added at once. */ + iter = &files.head->input_statement.next; + my_arch = files.head->input_statement.the_bfd->my_archive; + if (my_arch != NULL) + for (; *iter != NULL; iter = &(*iter)->input_statement.next) + if ((*iter)->input_statement.the_bfd->my_archive != my_arch) + break; + temp = *insert; + *insert = files.head; + files.head = *iter; + *iter = temp; + if (my_arch != NULL) + { + lang_input_statement_type *parent = my_arch->usrdata; + if (parent != NULL) + parent->next = (lang_statement_union_type *) + ((char *) iter + - offsetof (lang_input_statement_type, next)); + } + } } } #endif /* ENABLE_PLUGINS */ |