diff options
-rw-r--r-- | ld/ChangeLog | 12 | ||||
-rw-r--r-- | ld/ldlang.c | 79 | ||||
-rw-r--r-- | ld/ldlang.h | 14 | ||||
-rw-r--r-- | ld/ldmain.c | 5 |
4 files changed, 103 insertions, 7 deletions
diff --git a/ld/ChangeLog b/ld/ChangeLog index 2cda5e0..8ff54cc 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,15 @@ +2017-09-02 Alan Modra <amodra@gmail.com> + + * 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. + 2017-09-01 H.J. Lu <hongjiu.lu@intel.com> PR ld/22064 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 */ diff --git a/ld/ldlang.h b/ld/ldlang.h index a833672..86ef342 100644 --- a/ld/ldlang.h +++ b/ld/ldlang.h @@ -307,10 +307,14 @@ typedef struct lang_input_statement_struct struct flag_info *section_flag_list; /* Point to the next file - whatever it is, wanders up and down - archives */ + archive elements. If this input_statement is for an archive, it + won't be on file_chain (which uses this list pointer), but if + any elements have been extracted from the archive, it will point + to the input_statement for the last such element. */ union lang_statement_union *next; - /* Point to the next file, but skips archive contents. */ + /* Point to the next file, but skips archive contents. Used by + input_file_chain. */ union lang_statement_union *next_real_file; const char *target; @@ -582,9 +586,9 @@ extern asection *section_for_dot #define LANG_FOR_EACH_INPUT_STATEMENT(statement) \ lang_input_statement_type *statement; \ - for (statement = (lang_input_statement_type *) file_chain.head; \ - statement != (lang_input_statement_type *) NULL; \ - statement = (lang_input_statement_type *) statement->next) \ + for (statement = &file_chain.head->input_statement; \ + statement != NULL; \ + statement = &statement->next->input_statement) #define lang_output_section_find(NAME) \ lang_output_section_statement_lookup (NAME, 0, FALSE) diff --git a/ld/ldmain.c b/ld/ldmain.c index 2b09f20..d223587 100644 --- a/ld/ldmain.c +++ b/ld/ldmain.c @@ -793,6 +793,7 @@ add_archive_element (struct bfd_link_info *info, bfd **subsbfd ATTRIBUTE_UNUSED) { lang_input_statement_type *input; + lang_input_statement_type *parent; lang_input_statement_type orig_input; input = (lang_input_statement_type *) @@ -802,6 +803,10 @@ add_archive_element (struct bfd_link_info *info, input->local_sym_name = abfd->filename; input->the_bfd = abfd; + parent = abfd->my_archive->usrdata; + if (parent != NULL && !parent->flags.reload) + parent->next = (lang_statement_union_type *) input; + /* Save the original data for trace files/tries below, as plugins (if enabled) may possibly alter it to point to a replacement BFD, but we still want to output the original BFD filename. */ |