Bug 18992 - Linking a library implicitly using relative DT_RPATH does not work
Summary: Linking a library implicitly using relative DT_RPATH does not work
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.24
: P2 normal
Target Milestone: ---
Assignee: Alan Modra
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-09-22 22:55 UTC by Jethro Beekman
Modified: 2016-12-29 11:35 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed: 2015-09-23 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jethro Beekman 2015-09-22 22:55:09 UTC
I have a shared library ./dir/liba.so and a shared library ./libb.so with DT_RPATH "dir" and DT_NEEDED "liba.so". Now, if I compile an executable with -L. -lb, I get: "warning: liba.so, needed by ./libb.so, not found (try using -rpath or -rpath-link)". It works when using an absolute DT_RPATH or when using gold. The resulting binary works with a relative RPATH.

Here's a test case:

===> a.c <===

void a() {}

===> b.c <===

extern void a();
void b() {a();}

===> main.c <===

extern void b();
void main() {b();}

$ mkdir dir
$ gcc -fPIC -shared a.c -o dir/liba.so
# Make libb with relative RPATH
$ gcc -fPIC -shared -Ldir -Wl,-rpath,dir b.c -la -o libb.so
# Fail linking in relative-RPATH libb with ld.bfd
$ gcc main.c -L. -Wl,-rpath,. -lb -o main
/usr/bin/ld.bfd.real: warning: liba.so, needed by ./libb.so, not found (try using -rpath or -rpath-link)
./libb.so: undefined reference to `a'
collect2: error: ld returned 1 exit status
# Succeed linking in relative-RPATH libb with gold
$ gcc main.c -fuse-ld=gold -L. -Wl,-rpath,. -lb -o main
# Run binary with relative-RPATH libb
$ ./main
# Make libb with absolute RPATH
$ gcc -fPIC -shared -Ldir -Wl,-rpath,$(pwd)/dir b.c -la -o libb.so
# Succeed linking in absolute-RPATH libb with ld.bfd
$ gcc main.c -L. -Wl,-rpath,. -lb -o main
# Run binary with absolute-RPATH libb
$ ./main
# Make libb with relative RPATH
$ gcc -fPIC -shared -Ldir -Wl,-rpath,dir b.c -la -o libb.so
# Run binary with relative-RPATH libb
$ ./main
Comment 1 Jonathan Wakely 2015-09-22 22:58:53 UTC
(In reply to Jethro Beekman from comment #0)
> $ gcc main.c -L. -Wl,-rpath,. -lb -o main
> /usr/bin/ld.bfd.real: warning: liba.so, needed by ./libb.so, not found (try
> using -rpath or -rpath-link)
> ./libb.so: undefined reference to `a'
> collect2: error: ld returned 1 exit status

I asked the reporter to file this bug, but I've just tried it with binutils-2.25-9.fc22.x86_64 and don't see this warning.
Comment 2 Jethro Beekman 2015-09-22 23:18:24 UTC
I tried this on a variety of OS'es, including various versions of Debian, Ubuntu, RHEL and SunOS and so far I can only reproduce this on Ubuntu 14.04.
Comment 3 Mike Frysinger 2015-09-23 02:26:44 UTC
are you using gold there ?  compare `ld --version | head -1`.
Comment 4 Alan Modra 2015-09-23 06:08:21 UTC
This will be because your linker is configured with a sysroot, and is prepending the sysroot to relative paths.  I'm guessing --with-sysroot=/
Comment 5 Jethro Beekman 2015-09-23 06:30:11 UTC
This indeed seems to be the case. In particular, on Ubuntu 14.04, this patch is not applied: http://apt-browse.org/browse/debian/wheezy/main/all/binutils-source/2.22-8/file/usr/src/binutils/patches/158_ld_system_root.patch . It is applied on all other versions of Debian/Ubuntu I have tested. On all these OS'es, the linker is invoked with --sysroot=/ but it only has any effect on Ubuntu 14.04, and from the strace log I can indeed see that the linker tries to access /dir/liba.so.

I don't think the sysroot should be prepended to relative paths. Here's a patch to fix:

diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em
index 682f5e5..a70b138 100644
--- a/ld/emultempl/elf32.em
+++ b/ld/emultempl/elf32.em
@@ -1282,9 +1282,12 @@ fragment <<EOF
 	  rp = bfd_elf_get_runpath_list (link_info.output_bfd, &link_info);
 	  for (; !found && rp != NULL; rp = rp->next)
 	    {
-	      char *tmpname = gld${EMULATION_NAME}_add_sysroot (rp->name);
+	      char *tmpname = NULL, *name;
+	      if (rp->name[0] == '/')
+	        tmpname = gld${EMULATION_NAME}_add_sysroot (rp->name);
+		  name = tmpname ? tmpname : rp->name;
 	      found = (rp->by == l->by
-		       && gld${EMULATION_NAME}_search_needed (tmpname,
+		       && gld${EMULATION_NAME}_search_needed (name,
 							      &n,
 							      force));
 	      free (tmpname);
Comment 6 Sourceware Commits 2015-09-24 13:39:01 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=3074964fcfff45aef4584b84550eeef84f902fc4

commit 3074964fcfff45aef4584b84550eeef84f902fc4
Author: Alan Modra <amodra@gmail.com>
Date:   Thu Sep 24 13:13:57 2015 +0930

    Relative DT_RPATH/DT_RUNPATH vs. sysroot capable ld.
    
    This fixes two problems.  First, the --sysroot option wasn't available
    with a ld configured without --with-sysroot, a historical accident.
    This led to people configuring binutils with --with-sysroot=/ in order
    to enable sysroot support, which exposes a case where ld wrongly
    prepends the sysroot to a relative path.
    
    	PR ld/18992
    	* ldmain.c (main): Always enable --sysroot.
    	* emultempl/elf32.em (gld${EMULATION_NAME}_after_open): Don't
    	prepend sysroot to relative rpath/runpath.
Comment 7 Alan Modra 2016-12-29 11:35:03 UTC
Fixed a while ago.