This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
RFC: Don't output symbol version requirement for non-DT_NEEDED libs
- From: Alan Modra <amodra at gmail dot com>
- To: binutils at sourceware dot org, libc-alpha at sourceware dot org
- Date: Thu, 27 Nov 2014 18:46:45 +1030
- Subject: RFC: Don't output symbol version requirement for non-DT_NEEDED libs
- Authentication-results: sourceware.org; auth=none
This is a fix for
Inconsistency detected by ld.so: dl-version.c: 224: _dl_check_map_versions: Assertion `needed != ((void *)0)' failed!
a situation that can arise with weak references to versioned symbols
in dependent libraries.
Consider this testcase, a main that calls a weak "f", linked against a
shared library liba.so that has a dependency on libb.so where "f" is
defined as a versioned symbol. A later revision of liba.so defines
"f" itself, without the version, and doesn't link against libb.so.
A further revision of liba.so doesn't link against libb.so and also
doesn't define "f".
cat > lib.c <<EOF
int f (void) { return 1; }
EOF
cat > lib.map <<EOF
FOO { global: f; };
EOF
cat > main.c <<EOF
int f (void) __attribute__ ((weak));
int main (void) { return f ? f() : 0; }
EOF
cat > empty.c <<EOF
EOF
gcc -o libb.so -shared -fPIC -Wl,-soname,libb.so,--version-script,lib.map lib.c
gcc -o liba.so.1 -shared -fPIC -Wl,--no-as-needed,-soname,liba.so -L. -lb
gcc -o liba.so.2 -shared -fPIC -Wl,-soname,liba.so lib.c
gcc -o liba.so.3 -shared -fPIC -Wl,-soname,liba.so empty.c
ln -sfn liba.so.1 liba.so
gcc -o pr16452 -fPIC main.c -Wl,--no-as-needed,--rpath,. -L. -la
./pr16452
echo $?
ln -sfn liba.so.2 liba.so
./pr16452
echo $?
ln -sfn liba.so.3 liba.so
./pr16452
echo $?
Currently the script output is
1
Inconsistency detected by ld.so: dl-version.c: 224: _dl_check_map_versions: Assertion `needed != ((void *)0)' failed!
127
Inconsistency detected by ld.so: dl-version.c: 224: _dl_check_map_versions: Assertion `needed != ((void *)0)' failed!
127
The problem here is that since binutils-2.22 we've defaulted to
--no-copy-dt-needed-entries (which was a good change despite the
number of bugreports it has generated). So libb.so is not listed as
DT_NEEDED in the executable. However, a version FOO from libb.so *is*
added to the executable, specifying that it came from libb.so. When
we use rev 2 or 3 of liba.so, no libb.so is loaded and the version
check fails to find the required library.
You could argue that it's wrong for ld.so to complain about a weak
symbol version, but the ld.so check isn't being done against symbols.
ld.so is looking at .gnu.version_r, the version requirements
themselves, each possibly used by multiple symbols..
You might also argue that it's a user problem that f lost its version
in rev 2 of the testcase. However this might be because liba.so is a
user library without any versioning and in rev 2, liba.so was linked
against a static libb. (Typical libb in real life is libpthread.)
So, absent someone implementing a glibc fix, how about we just drop
the symbol versioning for weak symbols, when their defining library
won't be in DT_NEEDED? Note that if "f" above was a strong symbol,
ld will still complain with "./libb.so: error adding symbols: DSO
missing from command line".
PR 16452
* elflink.c (_bfd_elf_link_find_version_dependencies): Exclude
symbols from libraries that won't be listed in DT_NEEDED.
(elf_link_output_extsym): Don't output verdefs for such symbols.
diff --git a/bfd/elflink.c b/bfd/elflink.c
index c8068c0..c964a98 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -1832,7 +1832,9 @@ _bfd_elf_link_find_version_dependencies (struct elf_link_hash_entry *h,
if (!h->def_dynamic
|| h->def_regular
|| h->dynindx == -1
- || h->verinfo.verdef == NULL)
+ || h->verinfo.verdef == NULL
+ || (elf_dyn_lib_class (h->verinfo.verdef->vd_bfd)
+ & (DYN_AS_NEEDED | DYN_DT_NEEDED | DYN_NO_NEEDED)))
return TRUE;
/* See if we already know about this version. */
@@ -9050,7 +9052,9 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
if (!h->def_regular)
{
- if (h->verinfo.verdef == NULL)
+ if (h->verinfo.verdef == NULL
+ || (elf_dyn_lib_class (h->verinfo.verdef->vd_bfd)
+ & (DYN_AS_NEEDED | DYN_DT_NEEDED | DYN_NO_NEEDED)))
iversym.vs_vers = 0;
else
iversym.vs_vers = h->verinfo.verdef->vd_exp_refno + 1;
--
Alan Modra
Australia Development Lab, IBM