| Summary: | /usr/bin/ld (GNU ld 2.9.1) ignores rpath in shared libraries | ||
|---|---|---|---|
| Product: | Base System | Reporter: | Bjoern Fischer <bfischer> |
| Component: | gnu | Assignee: | David E. O'Brien <obrien> |
| Status: | Closed FIXED | ||
| Severity: | Affects Only Me | CC: | bfischer |
| Priority: | Normal | ||
| Version: | 4.0-STABLE | ||
| Hardware: | Any | ||
| OS: | Any | ||
Responsible Changed From-To: freebsd-bugs->obrien David has been working with binutils quite a bit. State Changed From-To: open->closed Binutils has been updated to 2.10.0. |
GNU ld ignores the rpath compiled into shared libraries when going through the needed list at link time. Imagine following scenario: library libA: /vol/foo/lib/libA.so needed: libB.so rpath: /vol/bar/lib library libB: /vol/bar/lib/libB.so Now one links a binary against libA: gcc -o foobar foobar.o -L/vol/foo/lib -R/vol/foo/lib -lA The above will fail because ld won't find libB.so at link time. The ld error message suggests that one should use -rpath to fix this. This is even worse: With -rpath /vol/bar/lib the path is hardcoded into the resulting binary, which is nonsense. You want to use -rpath-link. But generally you should not need to specify the location of libB.so at all, since libA.so is fully self contained and the runtime linker will find all libraries needed for the foobar executable w/o /vol/bar/lib in it's rpath. Fix: I don't know the proper method for changes in /usr/src/contrib/. so I changed everything in place. Maybe the changes should be moved to /usr/src/gnu/. making source imports easier. The changes were promoted to the GNU maintainers and it is probable that this or a similiar fix will be incorporated into the next binutils release. BTW: What is the common policy, how well tested should submitted patches be? I did a buildworld and some tests for the new feature. --- ./contrib/binutils/bfd/elflink.h 2000/04/16 17:11:15 1.1 +++ ./contrib/binutils/bfd/elflink.h 2000/04/16 20:40:13 @@ -852,6 +852,8 @@ Elf_External_Dyn *extdynend; int elfsec; unsigned long link; + int pass; + char *rpath = NULL; dynbuf = (Elf_External_Dyn *) bfd_malloc ((size_t) s->_raw_size); if (dynbuf == NULL) @@ -866,43 +868,78 @@ goto error_return; link = elf_elfsections (abfd)[elfsec]->sh_link; - extdyn = dynbuf; - extdynend = extdyn + s->_raw_size / sizeof (Elf_External_Dyn); - for (; extdyn < extdynend; extdyn++) + /* pass0: Look for rpath tag and save the value. + pass1: Look for soname and needed tags. + Reference rpath in each bfd_link_needed_list entry. */ + for (pass = 0; pass <= 1; pass++) { - Elf_Internal_Dyn dyn; - elf_swap_dyn_in (abfd, extdyn, &dyn); - if (dyn.d_tag == DT_SONAME) + extdyn = dynbuf; + extdynend = extdyn + s->_raw_size / sizeof (Elf_External_Dyn); + for (; extdyn < extdynend; extdyn++) { - name = bfd_elf_string_from_elf_section (abfd, link, - dyn.d_un.d_val); - if (name == NULL) - goto error_return; - } - if (dyn.d_tag == DT_NEEDED) - { - struct bfd_link_needed_list *n, **pn; - char *fnm, *anm; + Elf_Internal_Dyn dyn; + + elf_swap_dyn_in (abfd, extdyn, &dyn); - 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)->needed; - *pn != NULL; - pn = &(*pn)->next) - ; - *pn = n; + if (pass == 0) + { + if (dyn.d_tag == DT_RPATH) + { + /* DT_RPATH is not expected to occur more than + once in a dynamic section. */ + if (rpath == NULL) + { + char *string; + + string = + bfd_elf_string_from_elf_section (abfd, link, + dyn.d_un.d_val); + rpath = bfd_alloc (abfd, strlen(string) + 1); + if (rpath == NULL) + goto error_return; + strcpy (rpath, string); + } + } + } + else /* pass != 0 */ + { + + if (dyn.d_tag == DT_SONAME) + { + name = bfd_elf_string_from_elf_section (abfd, link, + dyn.d_un.d_val); + if (name == NULL) + goto error_return; + } + if (dyn.d_tag == DT_NEEDED) + { + 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->rpath = rpath; + n->next = NULL; + for (pn = &elf_hash_table (info)->needed; + *pn != NULL; + pn = &(*pn)->next) + ; + *pn = n; + } + } /* pass == 0 */ } } --- ./contrib/binutils/ld/emultempl/elf32.em 2000/04/14 23:05:41 1.1 +++ ./contrib/binutils/ld/emultempl/elf32.em 2000/04/16 20:43:46 @@ -340,7 +340,8 @@ /* 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 + command line rpath_link, hardcompiled rpath in shared objects, + command line 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. @@ -355,6 +356,8 @@ if (gld${EMULATION_NAME}_search_needed (command_line.rpath_link, l->name, force)) + break; + if (gld${EMULATION_NAME}_search_needed (l->rpath, l->name, force)) break; if (gld${EMULATION_NAME}_search_needed (command_line.rpath, l->name, force)) --- ./gnu/usr.bin/binutils/libbfd/i386/bfd.h 2000/04/15 11:14:30 1.1 +++ ./gnu/usr.bin/binutils/libbfd/i386/bfd.h 2000/04/16 17:51:09 @@ -598,6 +598,7 @@ { struct bfd_link_needed_list *next; bfd *by; + const char *rpath; const char *name; }; How-To-Repeat: See description.