PATCH: Fix [BUG] runpath broken for .so's in ld

H. J. Lu hjl@lucon.org
Thu Oct 17 00:08:00 GMT 2002


On Tue, Oct 15, 2002 at 01:19:09PM -0700, Kenny Simpson wrote:
> The runpath of a shared object is not always being
> searched when linking an executable.
> 
> The behavior I'm seeing is the following:
>   I have an external library (libext1.so), which lives
> in ~/ext1.
>   A shared library (libfoo.so) is created which links
> against libext.so and records a DT_RUNPATH for ~/ext1.
>   Another shared library (libbar.so) is created with a
> DT_RUNPATH for some other directory (ext2/libext2.so).
>   I attempt to create a binary (baz) that links
> against libfoo, and libbar.
>   The link fails as libext1 cannot be found.
> 
> Just to codify the above:
> 
> mkdir ext1;
> mkdir ext2;
> 
> dummy.c:
>         /* empty */
> 
> main.c:
>         int main() { return 0; }
> 
> Makefile:
>         ext1/libext1.so: dummy.c
>                 gcc -shared dummy.c -o $@
> 
>         ext2/libext2.so: dummy.c
>                 gcc -shared dummy.c -o $@
> 
>         libfoo.so: ext1/libext1.so
>                 gcc -shared -Lext1 -Wl,-rpath,ext1
> -Wl,--enable-new-dtags -lext1 -o $@
> 
>         libbar.so: ext2/libext2.so
>                 gcc -shared -Lext2 -Wl,-rpath,ext2
> -Wl,--enable-new-dtags -lext2 -o $@
> 
>         baz: main.c libbar.so libfoo.so
>                 gcc main.c -L. -Wl,-rpath,. -lfoo
> -lbar -o $@
> 
> make baz
> 

Thanks for your bug repart. It will be nice to provide a tar file so that I don't
have to recreate each file by hand. Here is a patch. It is late. Alan, could you
please double check it? Also please check my patch still works right for the bug

http://sources.redhat.com/ml/binutils/2000-08/msg00242.html

tried to fix.

Thanks.


H.J.
-------------- next part --------------
2002-10-16  H.J. Lu <hjl@gnu.org>

	* elflink.h (elf_link_add_object_symbols): Correctly handle DT_RPATH and
	DT_RUNPATH.

--- bfd/elflink.h.runpath	Sat Oct 12 08:44:36 2002
+++ bfd/elflink.h	Thu Oct 17 00:03:53 2002
@@ -1298,6 +1298,7 @@ elf_link_add_object_symbols (abfd, info)
       const char *name;
       bfd_size_type oldsize;
       bfd_size_type strindex;
+      struct bfd_link_needed_list *rpath = NULL, *runpath = NULL;
 
       /* Find the name to use in a DT_NEEDED entry that refers to this
 	 object.  If the object has a DT_SONAME entry, we use it.
@@ -1327,8 +1328,6 @@ elf_link_add_object_symbols (abfd, info)
 	  Elf_External_Dyn *extdynend;
 	  int elfsec;
 	  unsigned long shlink;
-	  int rpath;
-	  int runpath;
 
 	  dynbuf = (Elf_External_Dyn *) bfd_malloc (s->_raw_size);
 	  if (dynbuf == NULL)
@@ -1345,8 +1344,6 @@ 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;
@@ -1390,13 +1387,6 @@ elf_link_add_object_symbols (abfd, info)
 		  char *fnm, *anm;
 		  unsigned int tagv = dyn.d_un.d_val;
 
-		  /* When we see DT_RPATH before DT_RUNPATH, we have
-		     to clear runpath.  Do _NOT_ bfd_release, as that
-		     frees all more recently bfd_alloc'd blocks as
-		     well.  */
-		  if (rpath && hash_table->runpath)
-		    hash_table->runpath = NULL;
-
 		  amt = sizeof (struct bfd_link_needed_list);
 		  n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt);
 		  fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
@@ -1410,13 +1400,11 @@ elf_link_add_object_symbols (abfd, info)
 		  n->name = anm;
 		  n->by = abfd;
 		  n->next = NULL;
-		  for (pn = & hash_table->runpath;
+		  for (pn = & 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)
@@ -1442,18 +1430,32 @@ elf_link_add_object_symbols (abfd, info)
 		  n->name = anm;
 		  n->by = abfd;
 		  n->next = NULL;
-		  for (pn = & hash_table->runpath;
+		  for (pn = & rpath;
 		       *pn != NULL;
 		       pn = &(*pn)->next)
 		    ;
 		  *pn = n;
-		  rpath = 1;
 		}
 	    }
 
 	  free (dynbuf);
 	}
 
+      /* DT_RUNPATH overrides DT_RPATH.  Do _NOT_ bfd_release, as that
+	 frees all more recently bfd_alloc'd blocks as well.  */
+      if (runpath)
+	rpath = runpath;
+
+      if (rpath)
+	{
+	  struct bfd_link_needed_list **pn;
+	  for (pn = & hash_table->runpath;
+	       *pn != NULL;
+	       pn = &(*pn)->next)
+	    ;
+	  *pn = rpath;
+	}
+
       /* We do not want to include any of the sections in a dynamic
 	 object in the output file.  We hack by simply clobbering the
 	 list of sections in the BFD.  This could be handled more


More information about the Binutils mailing list