This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Patch: Re: bug in ld -rpath ??
- To: "Robert E. Brown" <brownb at jany dot gs dot com>
- Subject: Patch: Re: bug in ld -rpath ??
- From: "H . J . Lu" <hjl at lucon dot org>
- Date: Fri, 18 Aug 2000 11:25:11 -0700
- Cc: binutils at sourceware dot cygnus dot com
- References: <200008181527.LAA09776@vole.jany.gs.com>
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)
{