This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

LTO rescan archives


On Fri, Sep 01, 2017 at 10:37:57AM +0930, Alan Modra wrote:
> For ld, we ought to be
> more clever about where we put things after the plugin adds the LTO
> recompiled objects.  Ideally the recompiled objects ought to be
> ordered to 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 implements the reordering for archive elements extracted when
rescanning.  Testing in progress.

	* 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.

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.  */

-- 
Alan Modra
Australia Development Lab, IBM


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]