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]

[PATCH] Add plugin interface to LD [6/4] Add archive support to plugin interface.


    Hello everyone,


  And here is the final part of this patch series (for now, anyway - bugs will
probably need fixing later, but I won't discover them until I start playing
with the LTO plugin).  It allows plugins to deal with library archives, by
offering each of the individual archive members chosen for adding into the
link to the plugins via the API "claim files" hook.

  This one isn't as neat as the other patches.  I couldn't see any way to use
the existing functionality of the linker "add_archive_element" callback to
supply an alternative BFD with its own set of symbols from the IR, so I had to
extend BFD to make this possible.  And I didn't want to change the interface
of add_archive_element, since it's one of the few actual public interfaces of
libbfd, and we don't have any versioning.

  So that led me to take a somewhat ugly solution: I added a new member to
struct areltdata, and use that to communicate between libbfd and the linker
callback.  The member gets zeroed immediately before calling the callback, and
if on return it has been set to point to a BFD, the symbols from that BFD are
added to the linker hash table instead of the archive element's own symbols.
It's not ideal, but I think it's OK enough; there are only so many places from
which BFD calls the hook.  If anyone has a better idea how to implement this,
I'm all ears.  Otherwise, OK?


  bfd/ChangeLog:

	* aoutx.h (aout_link_check_ar_symbols): Clear arelt_substitute_bfd
	before calling add_archive_element callback.
	(aout_link_check_archive_element): Handle arelt_substitute_bfd if it
	was set during add_archive_element callback.
	* cofflink.c (coff_link_check_ar_symbols): Clear arelt_substitute_bfd
	before calling add_archive_element callback.
	(coff_link_check_archive_element): Handle arelt_substitute_bfd if it
	was set during add_archive_element callback.
	* ecoff.c (read_ext_syms_and_strs): New function holds symbol-reading
	code factored-out from ecoff_link_check_archive_element.
	(reread_ext_syms_and_strs): Clear old symbols and call it.
	(ecoff_link_check_archive_element): Clear arelt_substitute_bfd before
	calling add_archive_element callback and handle the substitution if
	the callback sets it.
	(ecoff_link_add_archive_symbols): Likewise.
	* elflink.c (elf_link_add_archive_symbols): Likewise.
	* libbfd-in.h (struct areltdata): Add new substitute_bfd member.
	(arelt_substitute_bfd): Add new accessor macro for it.
	* libbfd.h: Regenerate.
	* linker.c (generic_link_check_archive_element): Clear
	arelt_substitute_bfd before calling add_archive_element callback and
	handle the substitution if the callback sets it.
	* pdp11.c (aout_link_check_ar_symbols): Clear arelt_substitute_bfd
	before calling add_archive_element callback.
	(aout_link_check_archive_element): Handle arelt_substitute_bfd if it
	was set during add_archive_element callback.
	* vms-alpha.c (alpha_vms_link_add_archive_symbols): Clear
	arelt_substitute_bfd before calling add_archive_element callback and
	handle the substitution if the callback sets it.
	* xcofflink.c (xcoff_link_check_dynamic_ar_symbols): Clear
	arelt_substitute_bfd before calling add_archive_element callback.
	(xcoff_link_check_ar_symbols): Likewise.
	(xcoff_link_check_archive_element): Handle arelt_substitute_bfd if it
	was set during add_archive_element callback.

  ld/ChangeLog:

	* ldlang.c (load_symbols): Clear arelt_substitute_bfd before calling
	add_archive_element callback and handle the substitution if the
	callback sets it.
	* ldmain.c (add_archive_element)[ENABLE_PLUGINS]: Offer the archive
	member to the plugins and if claimed set arelt_substitute_bfd to point
	to the dummy IR-only BFD.

  ld/testsuite/ChangeLog:

	* ld-plugin/plugin-10.d: New dump test control script.
	* ld-plugin/plugin-11.d: Likewise.
	* ld-plugin/plugin.exp: Run them.

  include/ChangeLog:

	* include/bfdlink.h (struct_bfd_link_callbacks): Document new
	facility for add_archive_element callback to indicate a replacement
	bfd to be added to the hash table in place of the original element.


(As before, tested on i686-pc-cygwin and i686-pc-linux-gnu.)


    cheers,
      DaveK

>From afb802cf1036582f77f0560f0c39453e1237e593 Mon Sep 17 00:00:00 2001
From: Dave Korn <dave.korn.cygwin@gmail.com>
Date: Mon, 27 Sep 2010 00:25:28 +0100
Subject: [PATCH] Add archive support to plugin interface.

  bfd/ChangeLog:

	* aoutx.h (aout_link_check_ar_symbols): Clear arelt_substitute_bfd
	before calling add_archive_element callback.
	(aout_link_check_archive_element): Handle arelt_substitute_bfd if it
	was set during add_archive_element callback.
	* cofflink.c (coff_link_check_ar_symbols): Clear arelt_substitute_bfd
	before calling add_archive_element callback.
	(coff_link_check_archive_element): Handle arelt_substitute_bfd if it
	was set during add_archive_element callback.
	* ecoff.c (read_ext_syms_and_strs): New function holds symbol-reading
	code factored-out from ecoff_link_check_archive_element.
	(reread_ext_syms_and_strs): Clear old symbols and call it.
	(ecoff_link_check_archive_element): Clear arelt_substitute_bfd before
	calling add_archive_element callback and handle the substitution if
	the callback sets it.
	(ecoff_link_add_archive_symbols): Likewise.
	* elflink.c (elf_link_add_archive_symbols): Likewise.
	* libbfd-in.h (struct areltdata): Add new substitute_bfd member.
	(arelt_substitute_bfd): Add new accessor macro for it.
	* libbfd.h: Regenerate.
	* linker.c (generic_link_check_archive_element): Clear
	arelt_substitute_bfd before calling add_archive_element callback and
	handle the substitution if the callback sets it.
	* pdp11.c (aout_link_check_ar_symbols): Clear arelt_substitute_bfd
	before calling add_archive_element callback.
	(aout_link_check_archive_element): Handle arelt_substitute_bfd if it
	was set during add_archive_element callback.
	* vms-alpha.c (alpha_vms_link_add_archive_symbols): Clear
	arelt_substitute_bfd before calling add_archive_element callback and
	handle the substitution if the callback sets it.
	* xcofflink.c (xcoff_link_check_dynamic_ar_symbols): Clear
	arelt_substitute_bfd before calling add_archive_element callback.
	(xcoff_link_check_ar_symbols): Likewise.
	(xcoff_link_check_archive_element): Handle arelt_substitute_bfd if it
	was set during add_archive_element callback.

  ld/ChangeLog:

	* ldlang.c (load_symbols): Clear arelt_substitute_bfd before calling
	add_archive_element callback and handle the substitution if the
	callback sets it.
	* ldmain.c (add_archive_element)[ENABLE_PLUGINS]: Offer the archive
	member to the plugins and if claimed set arelt_substitute_bfd to point
	to the dummy IR-only BFD.

  ld/testsuite/ChangeLog:

	* ld-plugin/plugin-10.d: New dump test control script.
	* ld-plugin/plugin-11.d: Likewise.
	* ld-plugin/plugin.exp: Run them.

  include/ChangeLog:

	* include/bfdlink.h (struct_bfd_link_callbacks): Document new
	facility for add_archive_element callback to indicate a replacement
	bfd to be added to the hash table in place of the original element.
---
 bfd/aoutx.h                        |   11 ++++-
 bfd/cofflink.c                     |   11 ++++-
 bfd/ecoff.c                        |   96 ++++++++++++++++++++++++++---------
 bfd/elflink.c                      |    6 ++-
 bfd/libbfd-in.h                    |    3 +
 bfd/libbfd.h                       |    3 +
 bfd/linker.c                       |   46 ++++++++++++++---
 bfd/pdp11.c                        |   10 +++-
 bfd/vms-alpha.c                    |    6 ++-
 bfd/xcofflink.c                    |   10 +++-
 include/bfdlink.h                  |    4 +-
 ld/ldlang.c                        |    7 ++-
 ld/ldmain.c                        |   62 ++++++++++++++++++++++-
 ld/testsuite/ld-plugin/plugin-10.d |   36 +++++++++++++
 ld/testsuite/ld-plugin/plugin-11.d |   40 +++++++++++++++
 ld/testsuite/ld-plugin/plugin.exp  |   28 ++++++++++
 16 files changed, 336 insertions(+), 43 deletions(-)

diff --git a/bfd/aoutx.h b/bfd/aoutx.h
index 11598a0..41fda49 100644
--- a/bfd/aoutx.h
+++ b/bfd/aoutx.h
@@ -3304,6 +3304,7 @@ aout_link_check_ar_symbols (bfd *abfd,
 		continue;
 	    }
 
+	  arelt_substitute_bfd (abfd) = NULL;
 	  if (! (*info->callbacks->add_archive_element) (info, abfd, name))
 	    return FALSE;
 	  *pneeded = TRUE;
@@ -3331,6 +3332,7 @@ aout_link_check_ar_symbols (bfd *abfd,
 			 outside BFD.  We assume that we should link
 			 in the object file.  This is done for the -u
 			 option in the linker.  */
+		      arelt_substitute_bfd (abfd) = NULL;
 		      if (! (*info->callbacks->add_archive_element) (info,
 								     abfd,
 								     name))
@@ -3381,6 +3383,7 @@ aout_link_check_ar_symbols (bfd *abfd,
 	     it if the current link symbol is common.  */
 	  if (h->type == bfd_link_hash_undefined)
 	    {
+	      arelt_substitute_bfd (abfd) = NULL;
 	      if (! (*info->callbacks->add_archive_element) (info, abfd, name))
 		return FALSE;
 	      *pneeded = TRUE;
@@ -3410,7 +3413,13 @@ aout_link_check_archive_element (bfd *abfd,
 
   if (*pneeded)
     {
-      if (! aout_link_add_symbols (abfd, info))
+      /* Potentially, the add_archive_element hook may have set a
+	 substitute BFD for us in the areltdata struct.  */
+      if (arelt_substitute_bfd (abfd)
+	  && !aout_get_external_symbols (arelt_substitute_bfd (abfd)))
+	return FALSE;
+      if (! aout_link_add_symbols (arelt_substitute_bfd (abfd)
+			? arelt_substitute_bfd (abfd) : abfd, info))
 	return FALSE;
     }
 
diff --git a/bfd/cofflink.c b/bfd/cofflink.c
index a29b687..b6e095c 100644
--- a/bfd/cofflink.c
+++ b/bfd/cofflink.c
@@ -243,6 +243,7 @@ coff_link_check_ar_symbols (bfd *abfd,
 	  if (h != (struct bfd_link_hash_entry *) NULL
 	      && h->type == bfd_link_hash_undefined)
 	    {
+	      arelt_substitute_bfd (abfd) = NULL;
 	      if (! (*info->callbacks->add_archive_element) (info, abfd, name))
 		return FALSE;
 	      *pneeded = TRUE;
@@ -273,8 +274,16 @@ coff_link_check_archive_element (bfd *abfd,
   if (! coff_link_check_ar_symbols (abfd, info, pneeded))
     return FALSE;
 
+  /* Potentially, the add_archive_element hook may have set a
+     substitute BFD for us in the areltdata struct.  */
   if (*pneeded
-      && ! coff_link_add_symbols (abfd, info))
+      && arelt_substitute_bfd (abfd)
+      && ! _bfd_coff_get_external_symbols (arelt_substitute_bfd (abfd)))
+    return FALSE;
+
+  if (*pneeded
+      && ! coff_link_add_symbols (arelt_substitute_bfd (abfd)
+			? arelt_substitute_bfd (abfd) : abfd, info))
     return FALSE;
 
   if ((! info->keep_memory || ! *pneeded)
diff --git a/bfd/ecoff.c b/bfd/ecoff.c
index af9d7d6..ec36734 100644
--- a/bfd/ecoff.c
+++ b/bfd/ecoff.c
@@ -3509,6 +3509,58 @@ ecoff_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
   return FALSE;
 }
 
+/* Factored out from ecoff_link_check_archive_element.  */
+
+static bfd_boolean
+read_ext_syms_and_strs (HDRR **symhdr, bfd_size_type *external_ext_size,
+	bfd_size_type *esize, void **external_ext, char **ssext, bfd *abfd,
+	const struct ecoff_backend_data * const backend)
+{
+  if (! ecoff_slurp_symbolic_header (abfd))
+    return FALSE;
+
+  /* If there are no symbols, we don't want it.  */
+  if (bfd_get_symcount (abfd) == 0)
+    return TRUE;
+
+  *symhdr = &ecoff_data (abfd)->debug_info.symbolic_header;
+
+  *external_ext_size = backend->debug_swap.external_ext_size;
+  *esize = (*symhdr)->iextMax * *external_ext_size;
+  *external_ext = bfd_malloc (*esize);
+  if (*external_ext == NULL && *esize != 0)
+    return FALSE;
+
+  if (bfd_seek (abfd, (file_ptr) (*symhdr)->cbExtOffset, SEEK_SET) != 0
+      || bfd_bread (*external_ext, *esize, abfd) != *esize)
+    return FALSE;
+
+  *ssext = (char *) bfd_malloc ((bfd_size_type) (*symhdr)->issExtMax);
+  if (*ssext == NULL && (*symhdr)->issExtMax != 0)
+    return FALSE;
+
+  if (bfd_seek (abfd, (file_ptr) (*symhdr)->cbSsExtOffset, SEEK_SET) != 0
+      || (bfd_bread (*ssext, (bfd_size_type) (*symhdr)->issExtMax, abfd)
+	  != (bfd_size_type) (*symhdr)->issExtMax))
+    return FALSE;
+  return TRUE;
+}
+
+static bfd_boolean
+reread_ext_syms_and_strs (HDRR **symhdr, bfd_size_type *external_ext_size,
+	bfd_size_type *esize, void **external_ext, char **ssext, bfd *abfd,
+	const struct ecoff_backend_data * const backend)
+{
+  if (*external_ext != NULL)
+    free (*external_ext);
+  *external_ext = NULL;
+  if (*ssext != NULL)
+    free (*ssext);
+  *ssext = NULL;
+  return read_ext_syms_and_strs (symhdr, external_ext_size, esize,
+				external_ext, ssext, abfd, backend);
+}
+
 /* This is called if we used _bfd_generic_link_add_archive_symbols
    because we were not dealing with an ECOFF archive.  */
 
@@ -3530,35 +3582,15 @@ ecoff_link_check_archive_element (bfd *abfd,
 
   *pneeded = FALSE;
 
-  if (! ecoff_slurp_symbolic_header (abfd))
+  /* Read in the external symbols and external strings.  */
+  if (!read_ext_syms_and_strs (&symhdr, &external_ext_size, &esize,
+	&external_ext, &ssext, abfd, backend))
     goto error_return;
 
   /* If there are no symbols, we don't want it.  */
   if (bfd_get_symcount (abfd) == 0)
     goto successful_return;
 
-  symhdr = &ecoff_data (abfd)->debug_info.symbolic_header;
-
-  /* Read in the external symbols and external strings.  */
-  external_ext_size = backend->debug_swap.external_ext_size;
-  esize = symhdr->iextMax * external_ext_size;
-  external_ext = bfd_malloc (esize);
-  if (external_ext == NULL && esize != 0)
-    goto error_return;
-
-  if (bfd_seek (abfd, (file_ptr) symhdr->cbExtOffset, SEEK_SET) != 0
-      || bfd_bread (external_ext, esize, abfd) != esize)
-    goto error_return;
-
-  ssext = (char *) bfd_malloc ((bfd_size_type) symhdr->issExtMax);
-  if (ssext == NULL && symhdr->issExtMax != 0)
-    goto error_return;
-
-  if (bfd_seek (abfd, (file_ptr) symhdr->cbSsExtOffset, SEEK_SET) != 0
-      || (bfd_bread (ssext, (bfd_size_type) symhdr->issExtMax, abfd)
-	  != (bfd_size_type) symhdr->issExtMax))
-    goto error_return;
-
   /* Look through the external symbols to see if they define some
      symbol that is currently undefined.  */
   ext_ptr = (char *) external_ext;
@@ -3612,9 +3644,19 @@ ecoff_link_check_archive_element (bfd *abfd,
 	continue;
 
       /* Include this element.  */
+      arelt_substitute_bfd (abfd) = NULL;
       if (! (*info->callbacks->add_archive_element) (info, abfd, name))
 	goto error_return;
-      if (! ecoff_link_add_externals (abfd, info, external_ext, ssext))
+      /* Potentially, the add_archive_element hook may have set a
+	 substitute BFD for us in the areltdata struct.  However
+	 I don't think that can work here without reloading the
+	 external symbols.  */
+      if (arelt_substitute_bfd (abfd)
+	  && !reread_ext_syms_and_strs (&symhdr, &external_ext_size, &esize,
+				&external_ext, &ssext, abfd, backend))
+	goto error_return;
+      if (! ecoff_link_add_externals (arelt_substitute_bfd (abfd)
+	    ? arelt_substitute_bfd (abfd) : abfd, info, external_ext, ssext))
 	goto error_return;
 
       *pneeded = TRUE;
@@ -3777,9 +3819,13 @@ ecoff_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
       /* Unlike the generic linker, we know that this element provides
 	 a definition for an undefined symbol and we know that we want
 	 to include it.  We don't need to check anything.  */
+      arelt_substitute_bfd (element) = NULL;
       if (! (*info->callbacks->add_archive_element) (info, element, name))
 	return FALSE;
-      if (! ecoff_link_add_object_symbols (element, info))
+      /* Potentially, the add_archive_element hook may have set a
+	 substitute BFD for us in the areltdata struct.  */
+      if (! ecoff_link_add_object_symbols (arelt_substitute_bfd  (element)
+			? arelt_substitute_bfd (element) : element, info))
 	return FALSE;
 
       pundef = &(*pundef)->u.undef.next;
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 1446885..b3a12ee 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -5088,10 +5088,14 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
 
 	  undefs_tail = info->hash->undefs_tail;
 
+	  arelt_substitute_bfd (element) = NULL;
 	  if (! (*info->callbacks->add_archive_element) (info, element,
 							 symdef->name))
 	    goto error_return;
-	  if (! bfd_link_add_symbols (element, info))
+	  /* Potentially, the add_archive_element hook may have set a
+	     substitute BFD for us in the areltdata struct.  */
+	  if (! bfd_link_add_symbols (arelt_substitute_bfd (element)
+			? arelt_substitute_bfd (element) : element, info))
 	    goto error_return;
 
 	  /* If there are any new undefined symbols, we need to make
diff --git a/bfd/libbfd-in.h b/bfd/libbfd-in.h
index b5b614c..e097aaa 100644
--- a/bfd/libbfd-in.h
+++ b/bfd/libbfd-in.h
@@ -94,9 +94,12 @@ struct areltdata {
   unsigned int extra_size;	/* BSD4.4: extra bytes after the header.  */
   char *filename;		/* null-terminated */
   file_ptr origin;		/* for element of a thin archive */
+  bfd *substitute_bfd;		/* used by linker's add_archive_element hook.  */
 };
 
 #define arelt_size(bfd) (((struct areltdata *)((bfd)->arelt_data))->parsed_size)
+#define arelt_substitute_bfd(bfd)	\
+		(((struct areltdata *)((bfd)->arelt_data))->substitute_bfd)
 
 extern void *bfd_malloc
   (bfd_size_type);
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index fb95c40..82a3d4d 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -99,9 +99,12 @@ struct areltdata {
   unsigned int extra_size;	/* BSD4.4: extra bytes after the header.  */
   char *filename;		/* null-terminated */
   file_ptr origin;		/* for element of a thin archive */
+  bfd *substitute_bfd;		/* used by linker's add_archive_element hook.  */
 };
 
 #define arelt_size(bfd) (((struct areltdata *)((bfd)->arelt_data))->parsed_size)
+#define arelt_substitute_bfd(bfd)	\
+		(((struct areltdata *)((bfd)->arelt_data))->substitute_bfd)
 
 extern void *bfd_malloc
   (bfd_size_type);
diff --git a/bfd/linker.c b/bfd/linker.c
index 76bc70a..a43e1e5 100644
--- a/bfd/linker.c
+++ b/bfd/linker.c
@@ -223,7 +223,10 @@ SUBSUBSECTION
 	archive and decide which elements of the archive should be
 	included in the link.  For each such element it must call the
 	<<add_archive_element>> linker callback, and it must add the
-	symbols from the object file to the linker hash table.
+	symbols from the object file to the linker hash table.  (The
+	callback may in fact indicate that a replacement BFD should be
+	used, in which case they symbols from that BFD should be added
+	to the linker hash table instead.)
 
 @findex _bfd_generic_link_add_archive_symbols
 	In most cases the work of looking through the symbols in the
@@ -241,11 +244,18 @@ SUBSUBSECTION
 	<<_bfd_generic_link_add_archive_symbols>> must read the
 	symbols of the archive element and decide whether the archive
 	element should be included in the link.  If the element is to
-	be included, the <<add_archive_element>> linker callback
-	routine must be called with the element as an argument, and
-	the elements symbols must be added to the linker hash table
-	just as though the element had itself been passed to the
-	<<_bfd_link_add_symbols>> function.
+	be included, it must clear the <<substitute_bfd>> field in the
+	element's BFD's <<struct areltdata>> (by using the accessor
+	macro <<arelt_substitute_bfd>>) and then call out to the
+	<<add_archive_element>> linker callback.  This callback is
+	called with the element as an argument, and if it indicates no
+	error on returning, the element's symbols must be added to the
+	linker hash table just as though the element had itself been
+	passed to the <<_bfd_link_add_symbols>> function.  Optionally,
+	the callback may set the <<substitute_bfd>> field to point to
+	a replacement BFD, in which case the symbols from that BFD are
+	to be added to the linker hash table in place of the original
+	element's symbols.
 
 	When the a.out <<_bfd_link_add_symbols>> function receives an
 	archive, it calls <<_bfd_generic_link_add_archive_symbols>>
@@ -957,8 +967,14 @@ archive_hash_table_init
    included.  CHECKFN should set *PNEEDED to TRUE if the object file
    should be included, and must also call the bfd_link_info
    add_archive_element callback function and handle adding the symbols
-   to the global hash table.  CHECKFN should only return FALSE if some
-   sort of error occurs.
+   to the global hash table.  Before calling add_archive_element,
+   CHECKFN must set arelt_substitute_bfd to NULL on the BFD being
+   checked, and if it is non-NULL after the callback returns, CHECKFN
+   must add the symbols from the replacement BFD that it now points to
+   into the global hash table, rather than the object file's original
+   symbols.  (This functionality is used to support the linker plugin
+   architecture.)  CHECKFN should only return FALSE if some sort of
+   error occurs.
 
    For some formats, such as a.out, it is possible to look through an
    object file but not actually include it in the link.  The
@@ -1215,9 +1231,18 @@ generic_link_check_archive_element (bfd *abfd,
 	  asymbol **symbols;
 
 	  /* This object file defines this symbol, so pull it in.  */
+	  arelt_substitute_bfd (abfd) = NULL;
 	  if (! (*info->callbacks->add_archive_element) (info, abfd,
 							 bfd_asymbol_name (p)))
 	    return FALSE;
+	  /* Potentially, the add_archive_element hook may have set a
+	     substitute BFD for us in the areltdata struct.  */
+	  if (arelt_substitute_bfd (abfd))
+	    {
+	      abfd = arelt_substitute_bfd (abfd);
+	      if (!bfd_generic_link_read_symbols (abfd))
+		return FALSE;
+	    }
 	  symcount = _bfd_generic_link_get_symcount (abfd);
 	  symbols = _bfd_generic_link_get_symbols (abfd);
 	  if (! generic_link_add_symbol_list (abfd, info, symcount,
@@ -1241,9 +1266,14 @@ generic_link_check_archive_element (bfd *abfd,
 	      /* This symbol was created as undefined from outside
 		 BFD.  We assume that we should link in the object
 		 file.  This is for the -u option in the linker.  */
+	      arelt_substitute_bfd (abfd) = NULL;
 	      if (! (*info->callbacks->add_archive_element)
 		  (info, abfd, bfd_asymbol_name (p)))
 		return FALSE;
+	      /* Potentially, the add_archive_element hook may have set a
+		 substitute BFD for us in the areltdata struct.  But no
+		 symbols are going to get registered by anything we're
+		 returning to from here.  */
 	      *pneeded = TRUE;
 	      return TRUE;
 	    }
diff --git a/bfd/pdp11.c b/bfd/pdp11.c
index 1a7694c..9983020 100644
--- a/bfd/pdp11.c
+++ b/bfd/pdp11.c
@@ -2600,6 +2600,7 @@ aout_link_check_ar_symbols (bfd *abfd,
 	     but not if it is defined in the .text section.  That
 	     seems a bit crazy to me, and I haven't implemented it.
 	     However, it might be correct.  */
+	  arelt_substitute_bfd (abfd) = NULL;
 	  if (! (*info->callbacks->add_archive_element) (info, abfd, name))
 	    return FALSE;
 	  *pneeded = TRUE;
@@ -2627,6 +2628,7 @@ aout_link_check_ar_symbols (bfd *abfd,
 			 outside BFD.  We assume that we should link
 			 in the object file.  This is done for the -u
 			 option in the linker.  */
+		      arelt_substitute_bfd (abfd) = NULL;
 		      if (! (*info->callbacks->add_archive_element)
 			  (info, abfd, name))
 			return FALSE;
@@ -2688,7 +2690,13 @@ aout_link_check_archive_element (bfd *abfd,
 
   if (*pneeded)
     {
-      if (! aout_link_add_symbols (abfd, info))
+      /* Potentially, the add_archive_element hook may have set a
+	 substitute BFD for us in the areltdata struct.  */
+      if (arelt_substitute_bfd (abfd)
+	  && ! aout_get_external_symbols (arelt_substitute_bfd (abfd)))
+	return FALSE;
+      if (! aout_link_add_symbols (arelt_substitute_bfd (abfd)
+			? arelt_substitute_bfd (abfd) : abfd, info))
 	return FALSE;
     }
 
diff --git a/bfd/vms-alpha.c b/bfd/vms-alpha.c
index 5d38d1d..e736fe7 100644
--- a/bfd/vms-alpha.c
+++ b/bfd/vms-alpha.c
@@ -8277,10 +8277,14 @@ alpha_vms_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
       /* Unlike the generic linker, we know that this element provides
 	 a definition for an undefined symbol and we know that we want
 	 to include it.  We don't need to check anything.  */
+      arelt_substitute_bfd (element) = NULL;
       if (! (*info->callbacks->add_archive_element) (info, element,
                                                      h->root.string))
 	return FALSE;
-      if (! alpha_vms_link_add_object_symbols (element, info))
+      /* Potentially, the add_archive_element hook may have set a
+	 substitute BFD for us in the areltdata struct.  */
+      if (! alpha_vms_link_add_object_symbols (arelt_substitute_bfd (element)
+			? arelt_substitute_bfd (element) : element, info))
 	return FALSE;
 
       orig_element->archive_pass = pass;
diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c
index 30923cf..cf2cd01 100644
--- a/bfd/xcofflink.c
+++ b/bfd/xcofflink.c
@@ -2291,6 +2291,7 @@ xcoff_link_check_dynamic_ar_symbols (bfd *abfd,
 	  && (((struct xcoff_link_hash_entry *) h)->flags
 	      & XCOFF_DEF_DYNAMIC) == 0)
 	{
+	  arelt_substitute_bfd (abfd) = NULL;
 	  if (! (*info->callbacks->add_archive_element) (info, abfd, name))
 	    return FALSE;
 	  *pneeded = TRUE;
@@ -2361,6 +2362,7 @@ xcoff_link_check_ar_symbols (bfd *abfd,
 		  || (((struct xcoff_link_hash_entry *) h)->flags
 		      & XCOFF_DEF_DYNAMIC) == 0))
 	    {
+	      arelt_substitute_bfd (abfd) = NULL;
 	      if (! (*info->callbacks->add_archive_element) (info, abfd, name))
 		return FALSE;
 	      *pneeded = TRUE;
@@ -2396,7 +2398,13 @@ xcoff_link_check_archive_element (bfd *abfd,
 
   if (*pneeded)
     {
-      if (! xcoff_link_add_symbols (abfd, info))
+      /* Potentially, the add_archive_element hook may have set a
+	 substitute BFD for us in the areltdata struct.  */
+      if (arelt_substitute_bfd (abfd)
+	  && !_bfd_coff_get_external_symbols (arelt_substitute_bfd (abfd)))
+	return FALSE;
+      if (! xcoff_link_add_symbols (arelt_substitute_bfd (abfd)
+			? arelt_substitute_bfd (abfd) : abfd, info))
 	return FALSE;
       if (info->keep_memory)
 	keep_syms_p = TRUE;
diff --git a/include/bfdlink.h b/include/bfdlink.h
index af3c5c4..9154cc5 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -481,7 +481,9 @@ struct bfd_link_callbacks
   /* A function which is called when an object is added from an
      archive.  ABFD is the archive element being added.  NAME is the
      name of the symbol which caused the archive element to be pulled
-     in.  */
+     in.  This function may set arelt_substitute_bfd(ABFD) to point to
+     an alternative BFD from which symbols should in fact be added in
+     place of the original BFD's symbols.  */
   bfd_boolean (*add_archive_element)
     (struct bfd_link_info *, bfd *abfd, const char *name);
   /* A function which is called when a symbol is found with multiple
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 1310852..b161eb0 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -40,6 +40,7 @@
 #include "fnmatch.h"
 #include "demangle.h"
 #include "hashtab.h"
+#include "libbfd.h"
 #ifdef ENABLE_PLUGINS
 #include "plugin.h"
 #endif /* ENABLE_PLUGINS */
@@ -2706,11 +2707,15 @@ load_symbols (lang_input_statement_type *entry,
 		  loaded = FALSE;
 		}
 
+	      arelt_substitute_bfd (member) = NULL;
 	      if (! ((*link_info.callbacks->add_archive_element)
 		     (&link_info, member, "--whole-archive")))
 		abort ();
 
-	      if (! bfd_link_add_symbols (member, &link_info))
+	      /* Potentially, the add_archive_element hook may have set a
+		 substitute BFD for us in the areltdata struct.  */
+	      if (! bfd_link_add_symbols (arelt_substitute_bfd (member)
+			? arelt_substitute_bfd (member) : member, &link_info))
 		{
 		  einfo (_("%F%B: could not read symbols: %E\n"), member);
 		  loaded = FALSE;
diff --git a/ld/ldmain.c b/ld/ldmain.c
index f1d6697..0cc0ef9 100644
--- a/ld/ldmain.c
+++ b/ld/ldmain.c
@@ -42,6 +42,8 @@
 #include "ldctor.h"
 #ifdef ENABLE_PLUGINS
 #include "plugin.h"
+#include "plugin-api.h"
+#include "libbfd.h"
 #endif /* ENABLE_PLUGINS */
 
 /* Somewhere above, sys/stat.h got included.  */
@@ -793,6 +795,10 @@ add_archive_element (struct bfd_link_info *info,
 		     const char *name)
 {
   lang_input_statement_type *input;
+#ifdef ENABLE_PLUGINS
+  lang_input_statement_type orig_input;
+  int fildes;
+#endif /* ENABLE_PLUGINS */
 
   input = (lang_input_statement_type *)
       xcalloc (1, sizeof (lang_input_statement_type));
@@ -800,6 +806,53 @@ add_archive_element (struct bfd_link_info *info,
   input->local_sym_name = abfd->filename;
   input->the_bfd = abfd;
 
+#ifdef ENABLE_PLUGINS
+  /* Save the original data for trace files/tries below.  */
+  orig_input = *input;
+  /* We must offer this archive member to the plugins to claim.  */
+  fildes = bfd_my_archive (abfd) != NULL
+		? open (bfd_my_archive (abfd)->filename, O_RDONLY
+# ifdef O_BINARY
+						  | O_BINARY
+# endif /* O_BINARY */
+			)
+		: -1;
+  if (fildes >= 0)
+    {
+      struct ld_plugin_input_file file;
+      int claimed = 0;
+      /* Offset and filesize must refer to the individual archive
+	 member, not the whole file, and must exclude the header.
+	 Fortunately for us, that is how the data is stored in the
+	 origin field of the bfd and in the arelt_data.  */
+      file.name = bfd_my_archive (abfd)->filename;
+      file.offset = abfd->origin;
+      file.filesize = arelt_size (abfd);
+      file.fd = fildes;
+      /* We create a dummy BFD, initially empty, to house
+	 whatever symbols the plugin may want to add.  */
+      file.handle = plugin_get_ir_dummy_bfd (abfd->filename, abfd);
+      if (plugin_call_claim_file (&file, &claimed))
+	einfo (_("%P%F: %s: plugin reported error claiming file\n"),
+		plugin_error_plugin ());
+      if (claimed)
+	{
+	  /* Substitute the dummy BFD.  */
+	  input->the_bfd = file.handle;
+	  input->claimed = TRUE;
+	  bfd_make_readable (input->the_bfd);
+	  arelt_substitute_bfd (abfd) = input->the_bfd;
+	}
+      else
+	{
+	  /* Abandon the dummy BFD.  */
+	  bfd_close_all_done (file.handle);
+	  close (fildes);
+	  input->claimed = FALSE;
+	}
+    }
+#endif /* ENABLE_PLUGINS */
+
   ldlang_add_file (input);
 
   if (config.map_file != NULL)
@@ -880,8 +933,13 @@ add_archive_element (struct bfd_link_info *info,
     }
 
   if (trace_files || trace_file_tries)
-    info_msg ("%I\n", input);
-
+    info_msg ("%I\n",
+#ifdef ENABLE_PLUGINS
+	&orig_input
+#else
+	input
+#endif /* ENABLE_PLUGINS */
+	);
   return TRUE;
 }
 
diff --git a/ld/testsuite/ld-plugin/plugin-10.d b/ld/testsuite/ld-plugin/plugin-10.d
new file mode 100644
index 0000000..7e3c3bb
--- /dev/null
+++ b/ld/testsuite/ld-plugin/plugin-10.d
@@ -0,0 +1,36 @@
+Hello from testplugin.
+tv\[0\]: LDPT_MESSAGE func@0x.*
+tv\[1\]: LDPT_API_VERSION value        0x1 \(1\)
+tv\[2\]: LDPT_GNU_LD_VERSION value       0x.*
+tv\[3\]: LDPT_LINKER_OUTPUT value        0x1 \(1\)
+tv\[4\]: LDPT_OUTPUT_NAME 'tmpdir/main.x'
+tv\[5\]: LDPT_REGISTER_CLAIM_FILE_HOOK func@0x.*
+tv\[6\]: LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK func@0x.*
+tv\[7\]: LDPT_REGISTER_CLEANUP_HOOK func@0x.*
+tv\[8\]: LDPT_ADD_SYMBOLS func@0x.*
+tv\[9\]: LDPT_GET_INPUT_FILE func@0x.*
+tv\[10\]: LDPT_RELEASE_INPUT_FILE func@0x.*
+tv\[11\]: LDPT_GET_SYMBOLS func@0x.*
+tv\[12\]: LDPT_ADD_INPUT_FILE func@0x.*
+tv\[13\]: LDPT_ADD_INPUT_LIBRARY func@0x.*
+tv\[14\]: LDPT_SET_EXTRA_LIBRARY_PATH func@0x.*
+tv\[15\]: LDPT_OPTION 'registerclaimfile'
+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_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\)
+#...
+hook called: claim_file tmpdir/main.o \[@0/.* not claimed
+hook called: claim_file tmpdir/func.o \[@0/.* CLAIMED
+#...
+hook called: claim_file tmpdir/libtext.a \[@.* not claimed
+#...
+hook called: all symbols read.
+Sym: '_?func' Resolution: LDPR_PREVAILING_DEF
+Sym: '_?func2' Resolution: LDPR_PREVAILING_DEF_IRONLY
+hook called: cleanup.
+#...
diff --git a/ld/testsuite/ld-plugin/plugin-11.d b/ld/testsuite/ld-plugin/plugin-11.d
new file mode 100644
index 0000000..927cffd
--- /dev/null
+++ b/ld/testsuite/ld-plugin/plugin-11.d
@@ -0,0 +1,40 @@
+Hello from testplugin.
+tv\[0\]: LDPT_MESSAGE func@0x.*
+tv\[1\]: LDPT_API_VERSION value        0x1 \(1\)
+tv\[2\]: LDPT_GNU_LD_VERSION value       0x.*
+tv\[3\]: LDPT_LINKER_OUTPUT value        0x1 \(1\)
+tv\[4\]: LDPT_OUTPUT_NAME 'tmpdir/main.x'
+tv\[5\]: LDPT_REGISTER_CLAIM_FILE_HOOK func@0x.*
+tv\[6\]: LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK func@0x.*
+tv\[7\]: LDPT_REGISTER_CLEANUP_HOOK func@0x.*
+tv\[8\]: LDPT_ADD_SYMBOLS func@0x.*
+tv\[9\]: LDPT_GET_INPUT_FILE func@0x.*
+tv\[10\]: LDPT_RELEASE_INPUT_FILE func@0x.*
+tv\[11\]: LDPT_GET_SYMBOLS func@0x.*
+tv\[12\]: LDPT_ADD_INPUT_FILE func@0x.*
+tv\[13\]: LDPT_ADD_INPUT_LIBRARY func@0x.*
+tv\[14\]: LDPT_SET_EXTRA_LIBRARY_PATH func@0x.*
+tv\[15\]: LDPT_OPTION 'registerclaimfile'
+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_OPTION 'sym:_?func2::0:0:0'
+tv\[21\]: LDPT_OPTION 'dumpresolutions'
+tv\[22\]: LDPT_OPTION 'add:tmpdir/func.o'
+tv\[23\]: LDPT_OPTION 'claim:tmpdir/libtext.a'
+tv\[24\]: LDPT_OPTION 'sym:_?text::0:0:0'
+tv\[25\]: LDPT_OPTION 'add:tmpdir/text.o'
+tv\[26\]: LDPT_NULL value        0x0 \(0\)
+#...
+hook called: claim_file tmpdir/main.o \[@0/.* not claimed
+hook called: claim_file tmpdir/func.o \[@0/.* CLAIMED
+#...
+hook called: claim_file tmpdir/libtext.a \[@.* CLAIMED
+#...
+hook called: all symbols read.
+Sym: '_?func' Resolution: LDPR_PREVAILING_DEF
+Sym: '_?func2' Resolution: LDPR_PREVAILING_DEF_IRONLY
+Sym: '_?text' Resolution: LDPR_PREVAILING_DEF
+hook called: cleanup.
+#...
diff --git a/ld/testsuite/ld-plugin/plugin.exp b/ld/testsuite/ld-plugin/plugin.exp
index 6072e3b..ab8cbe1 100644
--- a/ld/testsuite/ld-plugin/plugin.exp
+++ b/ld/testsuite/ld-plugin/plugin.exp
@@ -45,6 +45,7 @@ set plugin_path "$base_dir/$lt_objdir/$plugin_name"
 verbose "Full plugin path $plugin_path" 2
 
 set testobjfiles "$HOSTING_CRT0 tmpdir/main.o tmpdir/func.o tmpdir/text.o"
+set testobjfiles_notext "$HOSTING_CRT0 tmpdir/main.o tmpdir/func.o"
 set libs "$LIBS $HOSTING_LIBS"
 
 set regclm "-plugin-arg registerclaimfile"
@@ -108,6 +109,26 @@ set plugin_tests [list \
     $testobjfiles $libs" "" "" {{ld plugin-9.d}} "main.x" ] \
 ]
 
+set plugin_lib_tests [list \
+    [list "plugin ignore lib" "-plugin $plugin_path $regclm \
+			$regas $regcln -plugin-arg claim:tmpdir/func.o \
+			-plugin-arg sym:${_}func::0:0:0 \
+			-plugin-arg sym:${_}func2::0:0:0 \
+			-plugin-arg dumpresolutions \
+			-plugin-arg add:tmpdir/func.o \
+    $testobjfiles_notext -Ltmpdir -ltext $libs" "" "" {{ld plugin-10.d}} "main.x" ] \
+    [list "plugin claimfile replace lib" "-plugin $plugin_path $regclm \
+			$regas $regcln -plugin-arg claim:tmpdir/func.o \
+			-plugin-arg sym:${_}func::0:0:0 \
+			-plugin-arg sym:${_}func2::0:0:0 \
+			-plugin-arg dumpresolutions \
+			-plugin-arg add:tmpdir/func.o \
+			-plugin-arg claim:tmpdir/libtext.a \
+			-plugin-arg sym:${_}text::0:0:0 \
+			-plugin-arg add:tmpdir/text.o \
+    $testobjfiles_notext -Ltmpdir -ltext $libs" "" "" {{ld plugin-11.d}} "main.x" ] \
+]
+
 set plugin_extra_elf_tests [list \
     [list "plugin set symbol visibility" "-plugin $plugin_path $regclm \
 			$regas $regcln -plugin-arg claim:tmpdir/func.o \
@@ -138,3 +159,10 @@ if { [is_elf_format] } {
     run_ld_link_tests $plugin_extra_elf_tests
 }
 
+if ![ar_simple_create $ar "" "tmpdir/libtext.a" "tmpdir/text.o"] {
+    foreach testitem $plugin_lib_tests {
+	unresolved [lindex $testitem 0]
+    }
+} else {
+    run_ld_link_tests $plugin_lib_tests
+}

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