aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ld/ChangeLog12
-rw-r--r--ld/ldlang.c79
-rw-r--r--ld/ldlang.h14
-rw-r--r--ld/ldmain.c5
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. */