This is the mail archive of the binutils@sources.redhat.com 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]

Patch: Re: bug in ld -rpath ??


On Fri, Aug 18, 2000 at 11:27:35AM -0400, Robert E. Brown wrote:
> 
> I am having trouble using the "-rpath" switch to GNU ld.  I assume that it
> should work like the "-R" switch to the Solaris linker, but it does not
> appear to.  Here is an example.  I create a shared library called liba.so
> that refers to another shared library, libused_by_a.so.  When I create
> liba.so, I use the -rpath switch to ld, so that liba.so "knows" where to
> find libused_by_a.so.  On Solaris, both the run-time dynamic linker and ld
> use this information whenever I link with liba.so.  The GNU linker, however,
> seems to ignore the rpath information embedded in liba.so when I link with it.
> 
> Here are two transcripts.  The first is on Solaris, the second on a machine
> running Linux 6.0 with gcc 2.95.2 and binutils 2.10 installed.  On Solaris,
> my use of liba.so succeeds, but with GNU ld it fails.
> 
> Does GNU ld have a broken "-rpath" switch, or is GNU ld behaving as you
> intend?  If the bug only appears in the 2.10 binutils release, is it safe to
> use an earlier linker with gcc version 2.95.2?
> 

I see it as a bug. Here is a patch. Any comments?


H.J.
----
2000-08-18  H.J. Lu  <hjl@gnu.org>

	* elf-bfd.h (elf_link_hash_table): Add runpath.

	* bfd-in.h (bfd_elf_get_runpath_list): New prototype.

	* elf.c (_bfd_elf_link_hash_table_init): Initialize the
	"runpath" field to NULL.
	(bfd_elf_get_runpath_list): New function.

	* elflink.h (elf_link_add_object_symbols): Record DT_RPATH and
	DT_RUNPATH entries.

Index: bfd/elf-bfd.h
===================================================================
RCS file: /work/cvs/gnu/binutils/bfd/elf-bfd.h,v
retrieving revision 1.2
diff -u -p -r1.2 elf-bfd.h
--- bfd/elf-bfd.h	2000/07/19 00:30:54	1.2
+++ bfd/elf-bfd.h	2000/08/18 17:27:06
@@ -243,6 +243,9 @@ struct elf_link_hash_table
   PTR stab_info;
   /* A linked list of local symbols to be added to .dynsym.  */
   struct elf_link_local_dynamic_entry *dynlocal;
+  /* A linked list of DT_RPATH/DT_RUNPATH names found in dynamic
+     objects included in the link.  */
+  struct bfd_link_needed_list *runpath;
 };
 
 /* Look up an entry in an ELF linker hash table.  */
Index: bfd/bfd-in.h
===================================================================
RCS file: /work/cvs/gnu/binutils/bfd/bfd-in.h,v
retrieving revision 1.14
diff -u -p -r1.14 bfd-in.h
--- bfd/bfd-in.h	2000/08/16 02:37:52	1.14
+++ bfd/bfd-in.h	2000/08/18 17:28:03
@@ -629,6 +629,8 @@ extern boolean bfd_elf64_size_dynamic_se
 extern void bfd_elf_set_dt_needed_name PARAMS ((bfd *, const char *));
 extern void bfd_elf_set_dt_needed_soname PARAMS ((bfd *, const char *));
 extern const char *bfd_elf_get_dt_soname PARAMS ((bfd *));
+extern struct bfd_link_needed_list *bfd_elf_get_runpath_list
+  PARAMS ((bfd *, struct bfd_link_info *));
 
 /* Return an upper bound on the number of bytes required to store a
    copy of ABFD's program header table entries.  Return -1 if an error
Index: bfd/elf.c
===================================================================
RCS file: /work/cvs/gnu/binutils/bfd/elf.c,v
retrieving revision 1.32
diff -u -p -r1.32 elf.c
--- bfd/elf.c	2000/08/04 18:22:46	1.32
+++ bfd/elf.c	2000/08/18 18:11:26
@@ -1007,6 +1007,7 @@ _bfd_elf_link_hash_table_init (table, ab
   table->dynstr = NULL;
   table->bucketcount = 0;
   table->needed = NULL;
+  table->runpath = NULL;
   table->hgot = NULL;
   table->stab_info = NULL;
   table->dynlocal = NULL;
@@ -1071,6 +1072,19 @@ bfd_elf_get_needed_list (abfd, info)
   if (info->hash->creator->flavour != bfd_target_elf_flavour)
     return NULL;
   return elf_hash_table (info)->needed;
+}
+
+/* Get the list of DT_RPATH/DT_RUNPATH entries for a link.  This is a
+   hook for the linker ELF emulation code.  */
+
+struct bfd_link_needed_list *
+bfd_elf_get_runpath_list (abfd, info)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     struct bfd_link_info *info;
+{
+  if (info->hash->creator->flavour != bfd_target_elf_flavour)
+    return NULL;
+  return elf_hash_table (info)->runpath;
 }
 
 /* Get the name actually used for a dynamic object for a link.  This
Index: elflink.h
===================================================================
RCS file: /work/cvs/gnu/binutils/bfd/elflink.h,v
retrieving revision 1.40
diff -u -p -r1.40 elflink.h
--- elflink.h	2000/08/18 07:03:38	1.40
+++ elflink.h	2000/08/18 18:23:14
@@ -1112,6 +1112,8 @@ elf_link_add_object_symbols (abfd, info)
 	  Elf_External_Dyn *extdynend;
 	  int elfsec;
 	  unsigned long link;
+	  int rpath;
+	  int runpath;
 
 	  dynbuf = (Elf_External_Dyn *) bfd_malloc ((size_t) s->_raw_size);
 	  if (dynbuf == NULL)
@@ -1145,6 +1147,8 @@ elf_link_add_object_symbols (abfd, info)
 
 	  extdyn = dynbuf;
 	  extdynend = extdyn + s->_raw_size / sizeof (Elf_External_Dyn);
+	  rpath = 0;
+	  runpath = 0;
 	  for (; extdyn < extdynend; extdyn++)
 	    {
 	      Elf_Internal_Dyn dyn;
@@ -1180,6 +1184,73 @@ elf_link_add_object_symbols (abfd, info)
 		       pn = &(*pn)->next)
 		    ;
 		  *pn = n;
+		}
+	      if (dyn.d_tag == DT_RUNPATH)
+		{
+		  struct bfd_link_needed_list *n, **pn;
+		  char *fnm, *anm;
+
+		  /* When we see DT_RPATH before DT_RUNPATH, we have
+		     to free runpath. */
+		  if (rpath && elf_hash_table (info)->runpath)
+		    {
+		      struct bfd_link_needed_list *nn;
+		      for (n = elf_hash_table (info)->runpath;
+			   n != NULL; n = nn)
+			{
+			  nn = n->next;
+			  bfd_release (abfd, n);
+			}
+		      bfd_release (abfd, elf_hash_table (info)->runpath);
+		      elf_hash_table (info)->runpath = NULL;
+		    }
+
+		  n = ((struct bfd_link_needed_list *)
+		       bfd_alloc (abfd, sizeof (struct bfd_link_needed_list)));
+		  fnm = bfd_elf_string_from_elf_section (abfd, link,
+							 dyn.d_un.d_val);
+		  if (n == NULL || fnm == NULL)
+		    goto error_return;
+		  anm = bfd_alloc (abfd, strlen (fnm) + 1);
+		  if (anm == NULL)
+		    goto error_return;
+		  strcpy (anm, fnm);
+		  n->name = anm;
+		  n->by = abfd;
+		  n->next = NULL;
+		  for (pn = &elf_hash_table (info)->runpath;
+		       *pn != NULL;
+		       pn = &(*pn)->next)
+		    ;
+		  *pn = n;
+		  runpath = 1;
+		  rpath = 0;
+		}
+	      /* Ignore DT_RPATH if we have seen DT_RUNPATH. */
+	      if (!runpath && dyn.d_tag == DT_RPATH)
+	        {
+		  struct bfd_link_needed_list *n, **pn;
+		  char *fnm, *anm;
+
+		  n = ((struct bfd_link_needed_list *)
+		       bfd_alloc (abfd, sizeof (struct bfd_link_needed_list)));
+		  fnm = bfd_elf_string_from_elf_section (abfd, link,
+							 dyn.d_un.d_val);
+		  if (n == NULL || fnm == NULL)
+		    goto error_return;
+		  anm = bfd_alloc (abfd, strlen (fnm) + 1);
+		  if (anm == NULL)
+		    goto error_return;
+		  strcpy (anm, fnm);
+		  n->name = anm;
+		  n->by = abfd;
+		  n->next = NULL;
+		  for (pn = &elf_hash_table (info)->runpath;
+		       *pn != NULL;
+		       pn = &(*pn)->next)
+		    ;
+		  *pn = n;
+		  rpath = 1;
 		}
 	    }
 
2000-08-18  H.J. Lu  <hjl@gnu.org>

	* emultempl/elf32.em (gld${EMULATION_NAME}_after_open): Search
	the DT_RPATH/DT_RUNPATH entries for DT_NEEDED after
	LD_LIBRARY_PATH.

Index: ld/emultempl/elf32.em
===================================================================
RCS file: /work/cvs/gnu/binutils/ld/emultempl/elf32.em,v
retrieving revision 1.24
diff -u -p -r1.24 elf32.em
--- ld/emultempl/elf32.em	2000/08/16 02:37:53	1.24
+++ ld/emultempl/elf32.em	2000/08/18 18:13:01
@@ -564,7 +564,7 @@ cat >>e${EMULATION_NAME}.c <<EOF
 static void
 gld${EMULATION_NAME}_after_open ()
 {
-  struct bfd_link_needed_list *needed, *l;
+  struct bfd_link_needed_list *needed, *l, *run_path;
 
   /* We only need to worry about this when doing a final link.  */
   if (link_info.relocateable || link_info.shared)
@@ -580,10 +580,12 @@ gld${EMULATION_NAME}_after_open ()
      needed list can actually grow while we are stepping through this
      loop.  */
   needed = bfd_elf_get_needed_list (output_bfd, &link_info);
+  run_path = bfd_elf_get_runpath_list (output_bfd, &link_info);
   for (l = needed; l != NULL; l = l->next)
     {
-      struct bfd_link_needed_list *ll;
+      struct bfd_link_needed_list *ll, *rp;
       int force;
+      int found;
 
       /* If we've already seen this file, skip it.  */
       for (ll = needed; ll != l; ll = ll->next)
@@ -603,8 +605,9 @@ gld${EMULATION_NAME}_after_open ()
 	 want to search for the file in the same way that the dynamic
 	 linker will search.  That means that we want to use
 	 rpath_link, rpath, then the environment variable
-	 LD_LIBRARY_PATH (native only), then the linker script
-	 LIB_SEARCH_DIRS.  We do not search using the -L arguments.
+	 LD_LIBRARY_PATH (native only), then the DT_RPATH/DT_RUNPATH
+	 entries, then the linker script LIB_SEARCH_DIRS.  We do not
+	 search using the -L arguments.
 
 	 We search twice.  The first time, we skip objects which may
 	 introduce version mismatches.  The second time, we force
@@ -642,6 +645,18 @@ EOF
   esac
 fi
 cat >>e${EMULATION_NAME}.c <<EOF
+
+	  found = 0;
+	  for (rp = run_path; !found && rp != NULL; rp = rp->next)
+	    {
+	      found = (rp->by == l->by
+		       && gld${EMULATION_NAME}_search_needed (rp->name,
+							      l->name,
+							      force));
+	    }
+	  if (found)
+	    break;
+
 	  len = strlen (l->name);
 	  for (search = search_head; search != NULL; search = search->next)
 	    {

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