This is the mail archive of the binutils-cvs@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]

[binutils-gdb] LTO rescan archives


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=1fa4ec6ae707402c6b61cde33cfe4bdeafd53f82

commit 1fa4ec6ae707402c6b61cde33cfe4bdeafd53f82
Author: Alan Modra <amodra@gmail.com>
Date:   Sat Sep 2 11:08:05 2017 +0930

    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.

Diff:
---
 ld/ChangeLog | 12 +++++++++
 ld/ldlang.c  | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 ld/ldlang.h  | 14 +++++++----
 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.  */


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