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]

Re: Patch: Re: bug in ld -rpath ??


On Tue, Aug 22, 2000 at 09:55:47AM +0200, Mark Kettenis wrote:
> 
> I find those two message pretty incomprehensible, especially if it is
> possible that they do not immediately follow eachother.  I think it
> would be better if the order was reversed, i.e.
> 
>    libused_by_a.so needed by a/liba.so
>    found libused_by_a.so at /home/hjl/bugs/gas/rpath/a/../u/libused_by_a.so
> 

It now displays:

libused_by_a.so needed by a/liba.so
found libused_by_a.so at /home/hjl/bugs/gas/rpath/a/../u/libused_by_a.so

> I think it would be a good idea to mention how the DSO was found
> (i.e. -rpath, -rpath-link, DT_RPATH, LD_RUN_PATH, standard search
> directories) like the GNU ld.so does.  That would be a big help in
> resolving problems with conflicting search dirs.  I don't know if this
> is easy to implement though.

It is documented in ld.texinfo. I have added DT_RPATH/DT_RUNPATH.

Here is the patch. There are 2 things I'd like to mention:

1. DT_RPATH/DT_RUNPATH are only used to search for DSOs needed by the
DSO where DT_RPATH/DT_RUNPATH come from:

	found = (rp->by == l->by
		 && gld${EMULATION_NAME}_search_needed (rp->name,
							l->name,
							force));

It follows the ld.so closer than -rpath/-rpath-link.

2. I think -rpath should be used for native linker only. My patch
doesn't address that. I can provide a separate patch after we finish
this one

Thanks.

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.
	* bfd-in2.h: Rebuilt.

	* 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/bfd-in2.h
===================================================================
RCS file: /work/cvs/gnu/binutils/bfd/bfd-in2.h,v
retrieving revision 1.42
diff -u -p -r1.42 bfd-in2.h
--- bfd/bfd-in2.h	2000/08/16 02:37:52	1.42
+++ bfd/bfd-in2.h	2000/08/18 17:50:13
@@ -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: bfd/elflink.h
===================================================================
RCS file: /work/cvs/gnu/binutils/bfd/elflink.h,v
retrieving revision 1.40
diff -u -p -r1.40 elflink.h
--- bfd/elflink.h	2000/08/18 07:03:38	1.40
+++ bfd/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-21  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 for native linker. Display the needed DSO if
	trace_file_tries is non-zero.
	(gld${EMULATION_NAME}_try_needed): Report the needed DSO found
	if trace_file_tries is non-zero.

	* ld.texinfo: Document the usage of DT_RPATH/DT_RUNPATH.
	* News: Mention it.

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/22 14:27:11
@@ -254,6 +254,7 @@ gld${EMULATION_NAME}_try_needed (name, f
      int force;
 {
   bfd *abfd;
+  const char *soname;
 
   abfd = bfd_openr (name, bfd_get_target (output_bfd));
   if (abfd == NULL)
@@ -337,6 +338,17 @@ cat >>e${EMULATION_NAME}.c <<EOF
 
   if (bfd_stat (abfd, &global_stat) != 0)
     einfo ("%F%P:%B: bfd_stat failed: %E\n", abfd);
+
+  /* First strip off everything before the last '/'.  */
+  soname = strrchr (abfd->filename, '/');
+  if (soname)
+    soname++;
+  else
+    soname = abfd->filename;
+
+  if (trace_file_tries)
+    info_msg (_("found %s at %s\n"), soname, name);
+
   global_found = false;
   lang_for_each_input_file (gld${EMULATION_NAME}_stat_needed);
   if (global_found)
@@ -350,17 +362,10 @@ cat >>e${EMULATION_NAME}.c <<EOF
      DT_NEEDED entry for this file.  */
   bfd_elf_set_dt_needed_name (abfd, "");
 
-  /* First strip off everything before the last '/'.  */
-  name = strrchr (abfd->filename, '/');
-  if (name)
-    name++;
-  else
-    name = abfd->filename;
-
   /* Tell the ELF backend that the output file needs a DT_NEEDED
      entry for this file if it is used to resolve the reference in
      a regular object.  */
-  bfd_elf_set_dt_needed_soname (abfd, name);
+  bfd_elf_set_dt_needed_soname (abfd, soname);
 
   /* Add this file into the symbol table.  */
   if (! bfd_link_add_symbols (abfd, &link_info))
@@ -565,11 +570,34 @@ static void
 gld${EMULATION_NAME}_after_open ()
 {
   struct bfd_link_needed_list *needed, *l;
+EOF
+if [ "x${host}" = "x${target}" ] ; then
+  case " ${EMULATION_LIBPATH} " in
+  *" ${EMULATION_NAME} "*)
+cat >>e${EMULATION_NAME}.c <<EOF
+  struct bfd_link_needed_list *run_path;
+EOF
+  ;;
+  esac
+fi
+cat >>e${EMULATION_NAME}.c <<EOF
 
   /* We only need to worry about this when doing a final link.  */
   if (link_info.relocateable || link_info.shared)
     return;
 
+EOF
+if [ "x${host}" = "x${target}" ] ; then
+  case " ${EMULATION_LIBPATH} " in
+  *" ${EMULATION_NAME} "*)
+cat >>e${EMULATION_NAME}.c <<EOF
+  run_path = bfd_elf_get_runpath_list (output_bfd, &link_info);
+EOF
+  ;;
+  esac
+fi
+cat >>e${EMULATION_NAME}.c <<EOF
+
   /* Get the list of files which appear in DT_NEEDED entries in
      dynamic objects included in the link (often there will be none).
      For each such file, we want to track down the corresponding
@@ -584,6 +612,18 @@ gld${EMULATION_NAME}_after_open ()
     {
       struct bfd_link_needed_list *ll;
       int force;
+EOF
+if [ "x${host}" = "x${target}" ] ; then
+  case " ${EMULATION_LIBPATH} " in
+  *" ${EMULATION_NAME} "*)
+cat >>e${EMULATION_NAME}.c <<EOF
+      struct bfd_link_needed_list *rp;
+      int found;
+EOF
+  ;;
+  esac
+fi
+cat >>e${EMULATION_NAME}.c <<EOF
 
       /* If we've already seen this file, skip it.  */
       for (ll = needed; ll != l; ll = ll->next)
@@ -599,12 +639,16 @@ gld${EMULATION_NAME}_after_open ()
       if (global_found)
 	continue;
 
+      if (trace_file_tries)
+	info_msg (_("%s needed by %B\n"), l->name, l->by);
+
       /* We need to find this file and include the symbol table.  We
 	 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 (native only), 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
@@ -637,6 +681,18 @@ cat >>e${EMULATION_NAME}.c <<EOF
 	  lib_path = (const char *) getenv ("LD_LIBRARY_PATH");
 	  if (gld${EMULATION_NAME}_search_needed (lib_path, l->name, force))
 	    break;
+
+	  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;
+
 EOF
   ;;
   esac
Index: ld/ld.texinfo
===================================================================
RCS file: /work/cvs/gnu/binutils/ld/ld.texinfo,v
retrieving revision 1.6
diff -u -p -r1.6 ld.texinfo
--- ld/ld.texinfo	2000/07/20 23:35:25	1.6
+++ ld/ld.texinfo	2000/08/22 06:36:11
@@ -1101,6 +1101,11 @@ directories specified using @code{-L} op
 For a native linker, the contents of the environment variable
 @code{LD_LIBRARY_PATH}.
 @item
+For a native ELF linker, the directories in @code{DT_RUNPATH} or
+@code{DT_RPATH} of a shared library are searched for shared
+libraries needed by it. The @code{DT_RPATH} entries are ignored if
+@code{DT_RUNPATH} entries exist.
+@item
 The default directories, normally @file{/lib} and @file{/usr/lib}.
 @item
 For a native linker on an ELF system, if the file @file{/etc/ld.so.conf}
Index: ld/NEWS
===================================================================
RCS file: /work/cvs/gnu/binutils/ld/NEWS,v
retrieving revision 1.7
diff -u -p -r1.7 NEWS
--- ld/NEWS	2000/08/16 02:37:53	1.7
+++ ld/NEWS	2000/08/22 06:35:56
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* The native ELF linker now searches the directories in DT_RUNPATH or
+  DT_RPATH of a shared library for shared libraries needed by it.
+
 * TI C54x support, by Timothy Wall.
 
 * Added command line switch --section-start to set the start address of any

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