PATCH: 2 stage BFD linker for LTO plugin

H.J. Lu hjl.tools@gmail.com
Sat Dec 4 06:07:00 GMT 2010


On Fri, Dec 3, 2010 at 6:34 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
> On Fri, Dec 3, 2010 at 6:23 PM, Dave Korn <dave.korn.cygwin@gmail.com> wrote:
>> On 04/12/2010 01:24, H.J. Lu wrote:
>>
>>> I checked in a patch to implement stage 2 linking. Everything
>>> seems to work, including "gcc -static ... -lm".
>>
>>  Any chance you could send a complete diff?
>>
>
> I will submit a complete diff after I fix a few corner cases.
> In the meantime, you can clone my git tree and do a "git diff".
>

Hi,

This patch implements 2 stage BFD linker for LTO plugin.
It works with current LTO API on all cases I tested.

Known issue:  --whole-archive will call plugin on archives with IR
in stage 2 linking. But ld never calls plugin to get back object files.
I will try to avoid it in a follow up patch.

OK for trunk?

Thanks.

-- 
H.J.
---
bfd/

2010-12-03  H.J. Lu  <hongjiu.lu@intel.com>

	PR driver/42690
	* bfd.c (BFD_PLUGIN): New.
	(BFD_FLAGS_SAVED): Add BFD_PLUGIN.
	(BFD_FLAGS_FOR_BFD_USE_MASK): Likewise.

	* bfd-in2.h: Regenerated.

ld/

2010-12-03  H.J. Lu  <hongjiu.lu@intel.com>

	PR driver/42690
	* ldfile.c (ldfile_try_open_bfd): Turn on BFD_PLUGIN and set
	claimed to false on non-object files and unclaimed object files.
	Set stage1.

	* ldlang.c (cmdline_list): New.
	(cmdline_next_claimed_output): Likewise.
	(cmdline_list_init): Likewise.
	(cmdline_get_stage2_input_files): Likewise.
	(debug_cmdline_list): Likewise.
	(cmdline_list_append): Likewise.
	(cmdline_set_next_claimed_output): Likewise.
	(cmdline_list_insert_claimed_output): Likewise.
	(new_afile): Set stage1 to FALSE;
	(lang_init): Call cmdline_list_init.
	(lang_process): Call plugin_active_plugins_p to check plugin
	support.  Check cmdline_next_claimed_output before opening
	stage 2 input.  Call debug_cmdline_list if trace_file_tries
	is set.  Call cmdline_get_stage2_input_files to get stage 2
	input files.

	* ldlang.h (lang_input_statement_struct): Add stage1.
	(cmdline_enum_type): New.
	(cmdline_header_type): Likewise.
	(cmdline_input_statement_type): Likewise.
	(cmdline_claimed_output_type): Likewise.
	(cmdline_union_type): Likewise.
	(cmdline_list_type): Likewise.
	(cmdline_list_append): Likewise.
	(cmdline_list_insert_claimed_output): Likewise.
	(cmdline_set_next_claimed_output): Likewise.

	* lexsup.c (parse_args): Call cmdline_list_append if needed.

	* plugin.c (plugin_opt_plugin_arg): Ignore -pass-through=.
	(add_input_file): Replace lang_add_input_file with
	cmdline_list_insert_claimed_output.
	(add_input_library): Likewise.

ld/testsuite/

2010-12-03  H.J. Lu  <hongjiu.lu@intel.com>

	PR driver/42690
	* ld-plugin/func1i.c: New.
	* ld-plugin/func2.c: Likewise.
	* ld-plugin/func2h.c: Likewise.
	* ld-plugin/func3p.c: Likewise.

	* ld-plugin/plugin.exp: Add object files for symbols claimed
	or created by testplugin.
	* ld-plugin/plugin-7.d: Updated.
	* ld-plugin/plugin-8.d: Likewise.
	* ld-plugin/plugin-9.d: Likewise.
-------------- next part --------------
bfd/

2010-12-03  H.J. Lu  <hongjiu.lu@intel.com>

	PR driver/42690
	* bfd.c (BFD_PLUGIN): New.
	(BFD_FLAGS_SAVED): Add BFD_PLUGIN.
	(BFD_FLAGS_FOR_BFD_USE_MASK): Likewise.

	* bfd-in2.h: Regenerated.

ld/

2010-12-03  H.J. Lu  <hongjiu.lu@intel.com>

	* ldfile.c (ldfile_try_open_bfd): Turn on BFD_PLUGIN and set
	claimed to false on non-object files and unclaimed object files.
	Set stage1.

	* ldlang.c (cmdline_list): New.
	(cmdline_next_claimed_output): Likewise.
	(cmdline_list_init): Likewise.
	(cmdline_get_stage2_input_files): Likewise.
	(debug_cmdline_list): Likewise.
	(cmdline_list_append): Likewise.
	(cmdline_set_next_claimed_output): Likewise.
	(cmdline_list_insert_claimed_output): Likewise.
	(new_afile): Set stage1 to FALSE;
	(lang_init): Call cmdline_list_init.
	(lang_process): Call plugin_active_plugins_p to check plugin
	support.  Check cmdline_next_claimed_output before opening
	stage 2 input.  Call debug_cmdline_list if trace_file_tries
	is set.  Call cmdline_get_stage2_input_files to get stage 2
	input files.

	* ldlang.h (lang_input_statement_struct): Add stage1.
	(cmdline_enum_type): New.
	(cmdline_header_type): Likewise.
	(cmdline_input_statement_type): Likewise.
	(cmdline_claimed_output_type): Likewise.
	(cmdline_union_type): Likewise.
	(cmdline_list_type): Likewise.
	(cmdline_list_append): Likewise.
	(cmdline_list_insert_claimed_output): Likewise.
	(cmdline_set_next_claimed_output): Likewise.

	* lexsup.c (parse_args): Call cmdline_list_append if needed.

	* plugin.c (plugin_opt_plugin_arg): Ignore -pass-through=.
	(add_input_file): Replace lang_add_input_file with
	cmdline_list_insert_claimed_output.
	(add_input_library): Likewise.

ld/testsuite/

2010-12-03  H.J. Lu  <hongjiu.lu@intel.com>

	PR driver/42690
	* ld-plugin/func1i.c: New.
	* ld-plugin/func2.c: Likewise.
	* ld-plugin/func2h.c: Likewise.
	* ld-plugin/func3p.c: Likewise.

	* ld-plugin/plugin.exp: Add object files for symbols claimed
	or created by testplugin.
	* ld-plugin/plugin-7.d: Updated.
	* ld-plugin/plugin-8.d: Likewise.
	* ld-plugin/plugin-9.d: Likewise.

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index e7805b6..10dbe83 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -5085,14 +5085,17 @@ struct bfd
   /* Decompress sections in this BFD.  */
 #define BFD_DECOMPRESS 0x10000
 
+  /* This BFD has been processed by the linker plugin.  */
+#define BFD_PLUGIN 0x20000
+
   /* Flags bits to be saved in bfd_preserve_save.  */
 #define BFD_FLAGS_SAVED \
-  (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS)
+  (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_PLUGIN)
 
   /* Flags bits which are for BFD use only.  */
 #define BFD_FLAGS_FOR_BFD_USE_MASK \
   (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
-   | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT)
+   | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT | BFD_PLUGIN)
 
   /* Currently my_archive is tested before adding origin to
      anything. I believe that this can become always an add of
diff --git a/bfd/bfd.c b/bfd/bfd.c
index a9ce7cc..7265156 100644
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -157,14 +157,17 @@ CODE_FRAGMENT
 .  {* Decompress sections in this BFD.  *}
 .#define BFD_DECOMPRESS 0x10000
 .
+.  {* This BFD has been processed by the linker plugin.  *}
+.#define BFD_PLUGIN 0x20000
+.
 .  {* Flags bits to be saved in bfd_preserve_save.  *}
 .#define BFD_FLAGS_SAVED \
-.  (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS)
+.  (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_PLUGIN)
 .
 .  {* Flags bits which are for BFD use only.  *}
 .#define BFD_FLAGS_FOR_BFD_USE_MASK \
 .  (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
-.   | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT)
+.   | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT | BFD_PLUGIN)
 .
 .  {* Currently my_archive is tested before adding origin to
 .     anything. I believe that this can become always an add of
diff --git a/ld/ldfile.c b/ld/ldfile.c
index 3d9feb5..3737db9 100644
--- a/ld/ldfile.c
+++ b/ld/ldfile.c
@@ -312,46 +312,63 @@ success:
      bfd_object that it sets the bfd's arch and mach, which
      will be needed when and if we want to bfd_create a new
      one using this one as a template.  */
-  if (bfd_check_format (entry->the_bfd, bfd_object)
-      && plugin_active_plugins_p ())
+  if (plugin_active_plugins_p ())
     {
-      int fd = open (attempt, O_RDONLY | O_BINARY);
-      if (fd >= 0)
+      if (bfd_check_format (entry->the_bfd, bfd_object))
 	{
-	  struct ld_plugin_input_file file;
-	  int claimed = 0;
-
-	  file.name = attempt;
-	  file.offset = 0;
-	  file.filesize = lseek (fd, 0, SEEK_END);
-	  file.fd = fd;
-	  /* We create a dummy BFD, initially empty, to house
-	     whatever symbols the plugin may want to add.  */
-	  file.handle = plugin_get_ir_dummy_bfd (attempt, entry->the_bfd);
-	  if (plugin_call_claim_file (&file, &claimed))
-	    einfo (_("%P%F: %s: plugin reported error claiming file\n"),
-		   plugin_error_plugin ());
-	  /* fd belongs to us, not the plugin; but we don't need it.  */
-	  close (fd);
-	  if (claimed)
+	  int fd = open (attempt, O_RDONLY | O_BINARY);
+	  if (fd >= 0)
 	    {
-	      /* Discard the real file's BFD and substitute the dummy one.  */
-	      bfd_close (entry->the_bfd);
-	      entry->the_bfd = file.handle;
-	      entry->claimed = TRUE;
-	      bfd_make_readable (entry->the_bfd);
-	    }
-	  else
-	    {
-	      /* If plugin didn't claim the file, we don't need the dummy
-		 bfd.  Can't avoid speculatively creating it, alas.  */
-	      bfd_close_all_done (file.handle);
-	      entry->claimed = FALSE;
+	      struct ld_plugin_input_file file;
+	      int claimed = 0;
+
+	      file.name = attempt;
+	      file.offset = 0;
+	      file.filesize = lseek (fd, 0, SEEK_END);
+	      file.fd = fd;
+	      /* We create a dummy BFD, initially empty, to house
+		 whatever symbols the plugin may want to add.  */
+	      file.handle = plugin_get_ir_dummy_bfd (attempt,
+						     entry->the_bfd);
+	      if (plugin_call_claim_file (&file, &claimed))
+		einfo (_("%P%F: %s: plugin reported error claiming file\n"),
+		       plugin_error_plugin ());
+	      /* fd belongs to us, not the plugin; but we don't need it.  */
+	      close (fd);
+	      if (claimed)
+		{
+		  /* Discard the real file's BFD and substitute the
+		    dummy one.  */
+		  bfd_close (entry->the_bfd);
+		  entry->the_bfd = file.handle;
+		  entry->claimed = TRUE;
+		  bfd_make_readable (entry->the_bfd);
+		  cmdline_set_next_claimed_output ();
+		}
+	      else
+		{
+		  /* If plugin didn't claim the file, we don't need the
+		     dummy bfd.  Can't avoid speculatively creating it,
+		     alas.  */
+		  bfd_close_all_done (file.handle);
+		  /* Mark this input has been processed by plugin.  */
+		  entry->the_bfd->flags |= BFD_PLUGIN;
+		  entry->claimed = FALSE;
+		}
 	    }
 	}
+      else 
+	{
+	  /* Mark this input has been processed by plugin.  */
+	  entry->the_bfd->flags |= BFD_PLUGIN;
+	  entry->claimed = FALSE;
+	}
     }
 #endif /* ENABLE_PLUGINS */
 
+  /* Stage 1 is done.  */
+  entry->stage1 = TRUE;
+
   /* It opened OK, the format checked out, and the plugins have had
      their chance to claim it, so this is success.  */
   return TRUE;
diff --git a/ld/ldlang.c b/ld/ldlang.c
index f74c1b5..458d856 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -70,6 +70,8 @@ static lang_statement_list_type *stat_save[10];
 static lang_statement_list_type **stat_save_ptr = &stat_save[0];
 static struct unique_sections *unique_section_list;
 static bfd_boolean ldlang_sysrooted_script = FALSE;
+static cmdline_list_type cmdline_list;
+static cmdline_union_type **cmdline_next_claimed_output;
 
 /* Forward declarations.  */
 static void exp_init_os (etree_type *);
@@ -90,6 +92,9 @@ static void lang_record_phdrs (void);
 static void lang_do_version_exports_section (void);
 static void lang_finalize_version_expr_head
   (struct bfd_elf_version_expr_head *);
+static void cmdline_list_init (void);
+static void cmdline_get_stage2_input_files (void);
+static void debug_cmdline_list (void);
 
 /* Exported variables.  */
 const char *output_target;
@@ -1003,6 +1008,7 @@ new_afile (const char *name,
   lang_has_input_file = TRUE;
   p->target = target;
   p->sysrooted = FALSE;
+  p->stage1 = FALSE;
 
   if (file_type == lang_input_file_is_l_enum
       && name[0] == ':' && name[1] != '\0')
@@ -1177,6 +1183,8 @@ lang_init (void)
 
   output_section_statement_table_init ();
 
+  cmdline_list_init ();
+
   lang_list_init (stat_ptr);
 
   lang_list_init (&input_file_chain);
@@ -6419,21 +6427,67 @@ lang_process (void)
   open_input_bfds (statement_list.head, FALSE);
 
 #ifdef ENABLE_PLUGINS
+  /* We call plugin_active_plugins_p () to check any plugin errors
+     from plugin_call_all_symbols_read ().  */
+  if (plugin_active_plugins_p ())
     {
+      bfd *p;
       union lang_statement_union **listend;
-      /* Now all files are read, let the plugin(s) decide if there
-	 are any more to be added to the link before we call the
+      /* Now all files are read, get outputs from input files claimed
+	 by plugin(s) and prepare for stage 2 linking before we call the
 	 emulation's after_open hook.  */
       listend = statement_list.tail;
       ASSERT (!*listend);
       if (plugin_call_all_symbols_read ())
 	einfo (_("%P%F: %s: plugin reported error after all symbols read\n"),
 	       plugin_error_plugin ());
-      /* If any new files were added, they will be on the end of the
-	 statement list, and we can open them now by getting open_input_bfds
-	 to carry on from where it ended last time.  */
-      if (*listend)
-	open_input_bfds (*listend, FALSE);
+
+      if (cmdline_next_claimed_output)
+	{
+	  if (trace_file_tries)
+	    debug_cmdline_list ();
+
+	  /* Get stage 2 input files.  */
+	  cmdline_get_stage2_input_files ();
+
+	  /* Must have stage 2 inputs.  */
+	  ASSERT (*listend);
+
+	  /* Exclude all sections in input bfd files processed by the
+	     plugin.  */
+	  for (p = link_info.input_bfds; p != (bfd *) NULL;
+	       p = p->link_next)
+	    {
+	      bfd *abfd = bfd_my_archive (p);
+	      if (!abfd)
+		abfd = p;
+	      if ((abfd->flags & BFD_PLUGIN) != 0)
+		{
+		  asection *sec;
+		  for (sec = p->sections; sec != NULL; sec = sec->next)
+		    sec->flags |= SEC_EXCLUDE;
+		}
+	    }
+
+	  /* Free the old already linked table and create a new one.  */
+	  bfd_section_already_linked_table_free ();
+	  if (!bfd_section_already_linked_table_init ())
+	    einfo (_("%P%F: Failed to create hash table\n"));
+
+	  /* Free the old hash table and create a new one.  */
+	  bfd_link_hash_table_free (link_info.output_bfd,
+				    link_info.hash);
+	  link_info.hash
+	    = bfd_link_hash_table_create (link_info.output_bfd);
+	  if (link_info.hash == NULL)
+	    einfo (_("%P%F: can not create hash table: %E\n"));
+
+	  /* When stage 2 input files are added, they will be on the
+	     end of the statement list, and we can open them now by
+	     getting open_input_bfds to carry on from where it ended
+	     last time.  */
+	  open_input_bfds (*listend, FALSE);
+	}
     }
 #endif /* ENABLE_PLUGINS */
 
@@ -7853,3 +7907,153 @@ lang_append_dynamic_list_cpp_new (void)
 
   lang_append_dynamic_list (dynamic);
 }
+
+static void
+cmdline_list_init (void)
+{
+  cmdline_list.tail = &cmdline_list.head;
+}
+
+/* Append a cmmand line option to cmdline_list.  */
+
+void
+cmdline_list_append (cmdline_enum_type type, void *data)
+{
+  cmdline_union_type *new_opt;
+
+  new_opt = (cmdline_union_type *) stat_alloc (sizeof (*new_opt));
+  new_opt->header.type = type;
+  new_opt->header.next = NULL;
+  *cmdline_list.tail = new_opt;
+  cmdline_list.tail = &new_opt->header.next;
+  if (type == cmdline_is_lang_input_statement_enum)
+    new_opt->input_statement.input = (lang_input_statement_type *) data;
+}
+
+/* Set cmdline_next_claimed_output.  */
+
+void
+cmdline_set_next_claimed_output (void)
+{
+  if (!cmdline_next_claimed_output)
+    {
+      cmdline_union_type *c;
+      cmdline_next_claimed_output = &cmdline_list.head;
+      for (c = cmdline_list.head; c != NULL; c = c->header.next)
+	if (c->header.type == cmdline_is_lang_input_statement_enum
+	    && !c->input_statement.input->stage1)
+	  {
+	    cmdline_next_claimed_output = &c->header.next;
+	    break;
+	  }
+    }
+}
+
+/* Insert claimed output after cmdline_next_claimed_output.  */
+
+void
+cmdline_list_insert_claimed_output (const char *output)
+{
+  cmdline_union_type *new_opt, *next;
+
+  new_opt = (cmdline_union_type *) stat_alloc (sizeof (*new_opt));
+  new_opt->header.type = cmdline_is_claimed_output_enum;
+  new_opt->claimed_output.output = output;
+
+  next = *cmdline_next_claimed_output;
+  *cmdline_next_claimed_output = new_opt;
+  new_opt->header.next = next;
+  if (cmdline_list.tail == cmdline_next_claimed_output)
+    {
+      cmdline_next_claimed_output = &new_opt->header.next;
+      cmdline_list.tail = cmdline_next_claimed_output;
+    }
+  else
+    cmdline_next_claimed_output = &new_opt->header.next;
+}
+
+/* Get stage 2 input files.  */
+
+static void
+cmdline_get_stage2_input_files (void)
+{
+  cmdline_union_type *c;
+  int ingroup = 0;
+
+  for (c = cmdline_list.head; c != NULL; c = c->header.next)
+    switch (c->header.type)
+      {
+      default:
+	abort ();
+      case cmdline_is_lang_input_statement_enum:
+	if (!c->input_statement.input->claimed)
+	  {
+	    lang_input_statement_type *input;
+	    input = lang_add_input_file (c->input_statement.input->filename,
+					 lang_input_file_is_file_enum,
+					 NULL);
+	    input->add_DT_NEEDED_for_dynamic
+	      = c->input_statement.input->add_DT_NEEDED_for_dynamic;
+	    input->add_DT_NEEDED_for_regular
+	      = c->input_statement.input->add_DT_NEEDED_for_regular;
+	    input->whole_archive
+	      = c->input_statement.input->whole_archive;
+	  }
+	break;
+      case cmdline_is_claimed_output_enum:
+	lang_add_input_file (c->claimed_output.output,
+			     lang_input_file_is_file_enum, NULL);
+	break;
+      case cmdline_is_enter_group_enum:
+	lang_enter_group ();
+	ingroup++;
+	break;
+      case cmdline_is_leave_group_enum:
+	lang_leave_group ();
+	ingroup--;
+	break;
+      }
+
+  while (ingroup)
+    {
+      lang_leave_group ();
+      ingroup--;
+    }
+}
+
+static void
+debug_cmdline_list (void)
+{
+  cmdline_union_type *c;
+
+  printf (_("Stage 2 command line:\n "));
+
+  for (c = cmdline_list.head; c != NULL; c = c->header.next)
+    switch (c->header.type)
+      {
+      default:
+	abort ();
+      case cmdline_is_lang_input_statement_enum:
+	if (!c->input_statement.input->claimed)
+	  {
+	    if (c->input_statement.input->the_bfd
+		&& (bfd_get_format (c->input_statement.input->the_bfd)
+		    == bfd_archive))
+	      printf (" %s", (c->input_statement.input->whole_archive
+			      ? "--whole-archive" : "--no-whole-archive"));
+	    printf (" %s", c->input_statement.input->filename);
+	  }
+	break;
+      case cmdline_is_claimed_output_enum:
+	printf (" %s", c->claimed_output.output);
+	break;
+      case cmdline_is_enter_group_enum:
+	printf (" --start-group");
+	break;
+      case cmdline_is_leave_group_enum:
+	printf (" --end-group");
+	break;
+      }
+
+  printf ("\n");
+}
diff --git a/ld/ldlang.h b/ld/ldlang.h
index 0b7b43b..d0aea1d 100644
--- a/ld/ldlang.h
+++ b/ld/ldlang.h
@@ -279,6 +279,9 @@ typedef struct lang_input_statement_struct
   /* Whether to include the entire contents of an archive.  */
   unsigned int whole_archive : 1;
 
+  /* Set if the file has been processed in stage 1 .  */
+  unsigned int stage1 : 1;
+
   /* Set when bfd opening is successful.  */
   unsigned int loaded : 1;
 
@@ -650,4 +653,47 @@ extern bfd_boolean
 ldlang_override_segment_assignment
   (struct bfd_link_info *, bfd *, asection *, asection *, bfd_boolean);
 
+typedef enum
+{
+  cmdline_is_lang_input_statement_enum,
+  cmdline_is_claimed_output_enum,
+  cmdline_is_enter_group_enum,
+  cmdline_is_leave_group_enum,
+} cmdline_enum_type;
+
+typedef struct cmdlin_header_struct
+{
+  union cmdline_union *next;
+  cmdline_enum_type type;
+} cmdline_header_type;
+
+typedef struct cmdline_input_statement_struct
+{
+  cmdline_header_type header;
+  lang_input_statement_type *input;
+} cmdline_input_statement_type;
+
+typedef struct cmdline_claimed_output_struct
+{
+  cmdline_header_type header;
+  const char *output;
+} cmdline_claimed_output_type;
+
+typedef union cmdline_union
+{
+  cmdline_header_type header;
+  cmdline_input_statement_type input_statement;
+  cmdline_claimed_output_type claimed_output;
+} cmdline_union_type;
+
+typedef struct cmdline_list
+{
+  cmdline_union_type *head;
+  cmdline_union_type **tail;
+} cmdline_list_type;
+
+extern void cmdline_list_append (cmdline_enum_type, void *);
+extern void cmdline_list_insert_claimed_output (const char *);
+extern void cmdline_set_next_claimed_output (void);
+
 #endif
diff --git a/ld/lexsup.c b/ld/lexsup.c
index b6274f8..f3d8684 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -720,6 +720,7 @@ parse_args (unsigned argc, char **argv)
     {
       int longind;
       int optc;
+      lang_input_statement_type *input;
 
       /* Using last_optind lets us avoid calling ldemul_parse_args
 	 multiple times on a single option, which would lead to
@@ -758,7 +759,10 @@ parse_args (unsigned argc, char **argv)
 	  einfo (_("%P%F: use the --help option for usage information\n"));
 
 	case 1:			/* File name.  */
-	  lang_add_input_file (optarg, lang_input_file_is_file_enum, NULL);
+	  input = lang_add_input_file (optarg,
+				       lang_input_file_is_file_enum, NULL);
+	  cmdline_list_append (cmdline_is_lang_input_statement_enum,
+			       input);
 	  break;
 
 	case OPTION_IGNORE:
@@ -915,7 +919,10 @@ parse_args (unsigned argc, char **argv)
 	  ldfile_add_library_path (optarg, TRUE);
 	  break;
 	case 'l':
-	  lang_add_input_file (optarg, lang_input_file_is_l_enum, NULL);
+	  input = lang_add_input_file (optarg,
+				       lang_input_file_is_l_enum, NULL);
+	  cmdline_list_append (cmdline_is_lang_input_statement_enum,
+			       input);
 	  break;
 	case 'M':
 	  config.map_filename = "-";
@@ -1100,9 +1107,11 @@ parse_args (unsigned argc, char **argv)
 	    if (stat (optarg, &s) >= 0
 		&& ! S_ISDIR (s.st_mode))
 	      {
-		lang_add_input_file (optarg,
-				     lang_input_file_is_symbols_only_enum,
-				     NULL);
+		input = lang_add_input_file (optarg,
+					     lang_input_file_is_symbols_only_enum,
+					     NULL);
+		cmdline_list_append (cmdline_is_lang_input_statement_enum,
+				     input);
 		break;
 	      }
 	  }
@@ -1484,6 +1493,7 @@ parse_args (unsigned argc, char **argv)
 	  break;
 	case '(':
 	  lang_enter_group ();
+	  cmdline_list_append (cmdline_is_enter_group_enum, NULL);
 	  ingroup++;
 	  break;
 	case ')':
@@ -1491,6 +1501,7 @@ parse_args (unsigned argc, char **argv)
 	    einfo (_("%P%F: group ended before it began (--help for usage)\n"));
 
 	  lang_leave_group ();
+	  cmdline_list_append (cmdline_is_leave_group_enum, NULL);
 	  ingroup--;
 	  break;
 
diff --git a/ld/plugin.c b/ld/plugin.c
index 6afc14b..c321996 100644
--- a/ld/plugin.c
+++ b/ld/plugin.c
@@ -211,6 +211,17 @@ plugin_opt_plugin_arg (const char *arg)
   if (!last_plugin)
     return set_plugin_error (_("<no plugin>"));
 
+  /* Ignore -pass-through= from GCC driver.  */
+  if (*arg == '-')
+    {
+      const char *p;
+      for (p = arg + 1; p; p++)
+	if (*p != '-')
+	  break;
+      if (strncmp (p, "pass-through=", 13) == 0)
+	return 0;
+    }
+
   newarg = xmalloc (sizeof *newarg);
   newarg->arg = arg;
   newarg->next = NULL;
@@ -520,9 +531,7 @@ static enum ld_plugin_status
 add_input_file (const char *pathname)
 {
   ASSERT (called_plugin);
-  if (!lang_add_input_file (xstrdup (pathname), lang_input_file_is_file_enum,
-			    NULL))
-    return LDPS_ERR;
+  cmdline_list_insert_claimed_output (xstrdup (pathname));
   return LDPS_OK;
 }
 
@@ -531,9 +540,7 @@ static enum ld_plugin_status
 add_input_library (const char *pathname)
 {
   ASSERT (called_plugin);
-  if (!lang_add_input_file (xstrdup (pathname), lang_input_file_is_l_enum,
-			    NULL))
-    return LDPS_ERR;
+  cmdline_list_insert_claimed_output (xstrdup (pathname));
   return LDPS_OK;
 }
 
diff --git a/ld/testsuite/ld-plugin/func1i.c b/ld/testsuite/ld-plugin/func1i.c
new file mode 100644
index 0000000..eb334a8
--- /dev/null
+++ b/ld/testsuite/ld-plugin/func1i.c
@@ -0,0 +1,8 @@
+extern int retval;
+
+int
+__attribute__ ((visibility ("internal")))
+func1 (void)
+{
+  return retval;
+}
diff --git a/ld/testsuite/ld-plugin/func2.c b/ld/testsuite/ld-plugin/func2.c
new file mode 100644
index 0000000..d233fcf
--- /dev/null
+++ b/ld/testsuite/ld-plugin/func2.c
@@ -0,0 +1,7 @@
+
+extern int retval;
+
+int func2 (void)
+{
+  return retval;
+}
diff --git a/ld/testsuite/ld-plugin/func2h.c b/ld/testsuite/ld-plugin/func2h.c
new file mode 100644
index 0000000..9398108
--- /dev/null
+++ b/ld/testsuite/ld-plugin/func2h.c
@@ -0,0 +1,8 @@
+extern int retval;
+
+int
+__attribute__ ((visibility ("hidden")))
+func2 (void)
+{
+  return retval;
+}
diff --git a/ld/testsuite/ld-plugin/func3p.c b/ld/testsuite/ld-plugin/func3p.c
new file mode 100644
index 0000000..fdba15b
--- /dev/null
+++ b/ld/testsuite/ld-plugin/func3p.c
@@ -0,0 +1,8 @@
+extern int retval;
+
+int
+__attribute__ ((visibility ("protected")))
+func3 (void)
+{
+  return retval;
+}
diff --git a/ld/testsuite/ld-plugin/plugin-7.d b/ld/testsuite/ld-plugin/plugin-7.d
index 75f25e0..ee7a6eb 100644
--- a/ld/testsuite/ld-plugin/plugin-7.d
+++ b/ld/testsuite/ld-plugin/plugin-7.d
@@ -19,7 +19,8 @@ tv\[16\]: LDPT_OPTION 'registerallsymbolsread'
 tv\[17\]: LDPT_OPTION 'registercleanup'
 tv\[18\]: LDPT_OPTION 'claim:tmpdir/func.o'
 tv\[19\]: LDPT_OPTION 'sym:_?func::0:0:0'
-tv\[20\]: LDPT_NULL value        0x0 \(0\)
+tv\[20\]: LDPT_OPTION 'add:tmpdir/func.o'
+tv\[21\]: LDPT_NULL value        0x0 \(0\)
 #...
 hook called: claim_file tmpdir/main.o \[@0/.* not claimed
 hook called: claim_file tmpdir/func.o \[@0/.* CLAIMED
diff --git a/ld/testsuite/ld-plugin/plugin-8.d b/ld/testsuite/ld-plugin/plugin-8.d
index e72b039..a4db899 100644
--- a/ld/testsuite/ld-plugin/plugin-8.d
+++ b/ld/testsuite/ld-plugin/plugin-8.d
@@ -21,7 +21,9 @@ tv\[18\]: LDPT_OPTION 'claim:tmpdir/func.o'
 tv\[19\]: LDPT_OPTION 'sym:_?func::0:0:0'
 tv\[20\]: LDPT_OPTION 'sym:_?func2::0:0:0'
 tv\[21\]: LDPT_OPTION 'dumpresolutions'
-tv\[22\]: LDPT_NULL value        0x0 \(0\)
+tv\[22\]: LDPT_OPTION 'add:tmpdir/func.o'
+tv\[23\]: LDPT_OPTION 'add:tmpdir/func2.o'
+tv\[24\]: LDPT_NULL value        0x0 \(0\)
 #...
 hook called: claim_file tmpdir/main.o \[@0/.* not claimed
 hook called: claim_file tmpdir/func.o \[@0/.* CLAIMED
diff --git a/ld/testsuite/ld-plugin/plugin-9.d b/ld/testsuite/ld-plugin/plugin-9.d
index b74f4a6..a4db899 100644
--- a/ld/testsuite/ld-plugin/plugin-9.d
+++ b/ld/testsuite/ld-plugin/plugin-9.d
@@ -22,7 +22,8 @@ tv\[19\]: LDPT_OPTION 'sym:_?func::0:0:0'
 tv\[20\]: LDPT_OPTION 'sym:_?func2::0:0:0'
 tv\[21\]: LDPT_OPTION 'dumpresolutions'
 tv\[22\]: LDPT_OPTION 'add:tmpdir/func.o'
-tv\[23\]: LDPT_NULL value        0x0 \(0\)
+tv\[23\]: LDPT_OPTION 'add:tmpdir/func2.o'
+tv\[24\]: LDPT_NULL value        0x0 \(0\)
 #...
 hook called: claim_file tmpdir/main.o \[@0/.* not claimed
 hook called: claim_file tmpdir/func.o \[@0/.* CLAIMED
diff --git a/ld/testsuite/ld-plugin/plugin.exp b/ld/testsuite/ld-plugin/plugin.exp
index 8952f1d..665c2b4 100644
--- a/ld/testsuite/ld-plugin/plugin.exp
+++ b/ld/testsuite/ld-plugin/plugin.exp
@@ -70,6 +70,7 @@ set plugin_nm_output ""
 if { $can_compile && \
 	(![ld_compile "$CC $CFLAGS" $srcdir/$subdir/main.c tmpdir/main.o] \
 	|| ![ld_compile "$CC $CFLAGS" $srcdir/$subdir/func.c tmpdir/func.o] \
+	|| ![ld_compile "$CC $CFLAGS" $srcdir/$subdir/func2.c tmpdir/func2.o] \
 	|| ![ld_compile "$CC $CFLAGS" $srcdir/$subdir/text.c tmpdir/text.o]) } {
     # Defer fail until we have list of tests set.
     set failed_compile 1
@@ -108,12 +109,15 @@ set plugin_tests [list \
     [list "plugin claimfile replace symbol" "-plugin $plugin_path $regclm \
 			$regas $regcln -plugin-opt claim:tmpdir/func.o \
 			-plugin-opt sym:${_}func::0:0:0 \
+			-plugin-opt add:tmpdir/func.o \
     $testobjfiles $libs" "" "" {{ld plugin-7.d}} "main.x" ] \
     [list "plugin claimfile resolve symbol" "-plugin $plugin_path $regclm \
 			$regas $regcln -plugin-opt claim:tmpdir/func.o \
 			-plugin-opt sym:${_}func::0:0:0 \
 			-plugin-opt sym:${_}func2::0:0:0 \
 			-plugin-opt dumpresolutions \
+			-plugin-opt add:tmpdir/func.o \
+			-plugin-opt add:tmpdir/func2.o \
     $testobjfiles $libs" "" "" {{ld plugin-8.d}} "main.x" ] \
     [list "plugin claimfile replace file" "-plugin $plugin_path $regclm \
 			$regas $regcln -plugin-opt claim:tmpdir/func.o \
@@ -121,6 +125,7 @@ set plugin_tests [list \
 			-plugin-opt sym:${_}func2::0:0:0 \
 			-plugin-opt dumpresolutions \
 			-plugin-opt add:tmpdir/func.o \
+			-plugin-opt add:tmpdir/func2.o \
     $testobjfiles $libs" "" "" {{ld plugin-9.d}} "main.x" ] \
 ]
 
@@ -152,6 +157,10 @@ set plugin_extra_elf_tests [list \
 			-plugin-opt sym:${_}func2::0:2:0 \
 			-plugin-opt sym:${_}func3::0:3:0 \
 			-plugin-opt dumpresolutions \
+			-plugin-opt add:tmpdir/func.o \
+			-plugin-opt add:tmpdir/func1i.o \
+			-plugin-opt add:tmpdir/func2h.o \
+			-plugin-opt add:tmpdir/func3p.o \
     $testobjfiles $libs" "" "" {{ld plugin-ignore.d} \
 				{readelf -s plugin-vis-1.d}} "main.x" ] \
 ]
@@ -170,7 +179,10 @@ if { !$can_compile || $failed_compile } {
 
 run_ld_link_tests $plugin_tests
 
-if { [is_elf_format] } {
+if { [is_elf_format] \
+     && [ld_compile "$CC $CFLAGS" $srcdir/$subdir/func1i.c tmpdir/func1i.o] \
+     && [ld_compile "$CC $CFLAGS" $srcdir/$subdir/func2h.c tmpdir/func2h.o] \
+     && [ld_compile "$CC $CFLAGS" $srcdir/$subdir/func3p.c tmpdir/func3p.o] } {
     run_ld_link_tests $plugin_extra_elf_tests
 }
 


More information about the Binutils mailing list