Subject: bin/14583: binutils 2.9.1 ld doesn't pay attention to DT_RPATH
To: None <gnats-bugs@gnats.netbsd.org>
From: None <skrll@netbsd.org>
List: netbsd-bugs
Date: 11/14/2001 08:47:01
>Number: 14583
>Category: bin
>Synopsis: binutils 2.9.1 ld doesn't pay attention to DT_RPATH
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: bin-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Wed Nov 14 00:48:00 PST 2001
>Closed-Date:
>Last-Modified:
>Originator: Nick Hudson
>Release: NetBSD 1.5.1
>Organization:
None at all.
>Environment:
System: NetBSD btcl045611 1.5.1 NetBSD 1.5.1 (GENERIC_LAPTOP) #1: Sat Jun 30 20:12:19 BST 2001 nick@nthcliff:/dsk/NetBSD/NetBSD-1.5/src/sys/arch/i386/compile/GENERIC_LAPTOP i386
>Description:
If a library contains dependencies and a binary is linked against
this library then ld complains about not being able to find the
dependencies if they exist outside /usr/lib.
>How-To-Repeat:
Build (for example) qt2 from pkgsrc
$ ldd /usr/X11R6/qt2/lib/libqt.so
/usr/X11R6/qt2/lib/libqt.so:
-lGLU.1 => /usr/X11R6/lib/libGLU.so.1
-lGL.1 => /usr/X11R6/lib/libGL.so.1
-lX11.6 => /usr/X11R6/lib/libX11.so.6
-lICE.6 => /usr/X11R6/lib/libICE.so.6
-lSM.6 => /usr/X11R6/lib/libSM.so.6
-lXt.6 => /usr/X11R6/lib/libXt.so.6
-lXext.6 => /usr/X11R6/lib/libXext.so.6
-lXmu.6 => /usr/X11R6/lib/libXmu.so.6
-lm.0 => /usr/lib/libm387.so.0
-lm.0 => /usr/lib/libm.so.0
-lXrender.1 => /usr/X11R6/lib/libXrender.so.1
-lfreetype.6 => /usr/X11R6/lib/libfreetype.so.6
-lXft.1 => /usr/X11R6/lib/libXft.so.1
-lz.0 => /usr/lib/libz.so.0
-lpng.2 => /usr/pkg/lib/libpng.so.2
-ljpeg.62 => /usr/pkg/lib/libjpeg.so.62
-llcms.1 => /usr/pkg/lib/liblcms.so.1
-lmng.1 => /usr/pkg/lib/libmng.so.1
$ cat > dummy.cpp << EOF
> #include <qstring.h>
>
> int
> main()
> {
> QString s;
> }
EOF
$ g++ -c dummy.cpp -I/usr/X11R6/qt2/include
$ g++ dummy.o -lqt -L/usr/X11R6/qt2/lib -I/usr/X11R6/qt2/include -Wl,-rpath -Wl,/usr/X11R6/qt2/lib
/usr/bin/ld: warning: libGLU.so.1, needed by /usr/X11R6/qt2/lib/libqt.so, not found (try using --rpath)
/usr/bin/ld: warning: libGL.so.1, needed by /usr/X11R6/qt2/lib/libqt.so, not found (try using --rpath)
/usr/bin/ld: warning: libXmu.so.6, needed by /usr/X11R6/qt2/lib/libqt.so, not found (try using --rpath)
/usr/bin/ld: warning: libXext.so.6, needed by /usr/X11R6/qt2/lib/libqt.so, not found (try using --rpath)
/usr/bin/ld: warning: libX11.so.6, needed by /usr/X11R6/qt2/lib/libqt.so, not found (try using --rpath)
/usr/bin/ld: warning: libSM.so.6, needed by /usr/X11R6/qt2/lib/libqt.so, not found (try using --rpath)
/usr/bin/ld: warning: libICE.so.6, needed by /usr/X11R6/qt2/lib/libqt.so, not found (try using --rpath)
/usr/bin/ld: warning: libXft.so.1, needed by /usr/X11R6/qt2/lib/libqt.so, not found (try using --rpath)
/usr/bin/ld: warning: libpng.so.2, needed by /usr/X11R6/qt2/lib/libqt.so, not found (try using --rpath)
/usr/bin/ld: warning: libjpeg.so.62, needed by /usr/X11R6/qt2/lib/libqt.so, not found (try using --rpath)
/usr/bin/ld: warning: libmng.so.1, needed by /usr/X11R6/qt2/lib/libqt.so, not found (try using --rpath)
/usr/X11R6/qt2/lib/libqt.so: undefined reference to ...
>Fix:
Apply the following patch derived from binutils 2.11.3
Index: gnu/dist/bfd/bfd-in.h
===================================================================
RCS file: /cvsroot/gnusrc/gnu/dist/bfd/bfd-in.h,v
retrieving revision 1.6
diff -c -r1.6 bfd-in.h
*** gnu/dist/bfd/bfd-in.h 2000/05/04 20:34:14 1.6
--- gnu/dist/bfd/bfd-in.h 2001/11/14 08:33:27
***************
*** 622,627 ****
--- 622,629 ----
struct bfd_elf_version_tree *));
extern void bfd_elf_set_dt_needed_name 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 *));
/* SunOS shared library support routines for the linker. */
Index: gnu/dist/bfd/bfd-in2.h
===================================================================
RCS file: /cvsroot/gnusrc/gnu/dist/bfd/bfd-in2.h,v
retrieving revision 1.4
diff -c -r1.4 bfd-in2.h
*** gnu/dist/bfd/bfd-in2.h 2000/05/04 20:34:14 1.4
--- gnu/dist/bfd/bfd-in2.h 2001/11/14 08:34:11
***************
*** 622,627 ****
--- 622,629 ----
struct bfd_elf_version_tree *));
extern void bfd_elf_set_dt_needed_name 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 *));
/* SunOS shared library support routines for the linker. */
Index: gnu/dist/bfd/elf-bfd.h
===================================================================
RCS file: /cvsroot/gnusrc/gnu/dist/bfd/elf-bfd.h,v
retrieving revision 1.1.1.2
diff -c -r1.1.1.2 elf-bfd.h
*** gnu/dist/bfd/elf-bfd.h 1999/02/02 19:51:52 1.1.1.2
--- gnu/dist/bfd/elf-bfd.h 2001/11/14 08:34:28
***************
*** 184,189 ****
--- 184,192 ----
struct elf_link_hash_entry *hgot;
/* A pointer to information used to link stabs in sections. */
PTR stab_info;
+ /* 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: gnu/dist/bfd/elf.c
===================================================================
RCS file: /cvsroot/gnusrc/gnu/dist/bfd/elf.c,v
retrieving revision 1.3
diff -c -r1.3 elf.c
*** gnu/dist/bfd/elf.c 1999/07/31 20:56:12 1.3
--- gnu/dist/bfd/elf.c 2001/11/14 08:35:12
***************
*** 873,878 ****
--- 873,879 ----
table->dynstr = NULL;
table->bucketcount = 0;
table->needed = NULL;
+ table->runpath = NULL;
table->hgot = NULL;
table->stab_info = NULL;
return _bfd_link_hash_table_init (&table->root, abfd, newfunc);
***************
*** 926,931 ****
--- 927,945 ----
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;
+ 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: gnu/dist/bfd/elflink.h
===================================================================
RCS file: /cvsroot/gnusrc/gnu/dist/bfd/elflink.h,v
retrieving revision 1.4
diff -c -r1.4 elflink.h
*** gnu/dist/bfd/elflink.h 2000/06/11 23:47:57 1.4
--- gnu/dist/bfd/elflink.h 2001/11/14 08:36:15
***************
*** 851,856 ****
--- 851,858 ----
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)
***************
*** 867,872 ****
--- 869,876 ----
extdyn = dynbuf;
extdynend = extdyn + s->_raw_size / sizeof (Elf_External_Dyn);
+ rpath = 0;
+ runpath = 0;
for (; extdyn < extdynend; extdyn++)
{
Elf_Internal_Dyn dyn;
***************
*** 902,907 ****
--- 906,970 ----
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 clear runpath. Do _NOT_ bfd_release, as that
+ frees all more recently bfd_alloc'd blocks as
+ well. */
+ if (rpath && 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;
}
}
Index: gnu/dist/include/elf/common.h
===================================================================
RCS file: /cvsroot/gnusrc/gnu/dist/include/elf/common.h,v
retrieving revision 1.3
diff -c -r1.3 common.h
*** gnu/dist/include/elf/common.h 1999/02/02 20:27:18 1.3
--- gnu/dist/include/elf/common.h 2001/11/14 08:36:21
***************
*** 273,278 ****
--- 273,279 ----
#define DT_DEBUG 21
#define DT_TEXTREL 22
#define DT_JMPREL 23
+ #define DT_RUNPATH 29
/* The next four dynamic tags are used on Solaris. We support them
everywhere. */
Index: gnu/dist/ld/emultempl/elf32.em
===================================================================
RCS file: /cvsroot/gnusrc/gnu/dist/ld/emultempl/elf32.em,v
retrieving revision 1.1.1.2
diff -c -r1.1.1.2 elf32.em
*** gnu/dist/ld/emultempl/elf32.em 1999/02/02 19:53:57 1.1.1.2
--- gnu/dist/ld/emultempl/elf32.em 2001/11/14 08:36:33
***************
*** 292,297 ****
--- 292,308 ----
size_t len;
search_dirs_type *search;
+ EOF
+ if [ "x${host}" = "x${target}" ] ; then
+ if [ "x${DEFAULT_EMULATION}" = "x${EMULATION_NAME}" ] ; then
+ cat >>e${EMULATION_NAME}.c <<EOF
+ struct bfd_link_needed_list *rp;
+ int found;
+ EOF
+ fi
+ fi
+ cat >>e${EMULATION_NAME}.c <<EOF
+
if (gld${EMULATION_NAME}_search_needed (command_line.rpath_link,
l->name, force))
break;
***************
*** 313,318 ****
--- 324,342 ----
lib_path = (const char *) getenv ("LD_LIBRARY_PATH");
if (gld${EMULATION_NAME}_search_needed (lib_path, l->name, force))
break;
+
+ found = 0;
+ rp = bfd_elf_get_runpath_list (output_bfd, &link_info);
+ for (; !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
fi
fi
>Release-Note:
>Audit-Trail:
>Unformatted: