Bug 22150 - [2.29 Regression] ld.bfd keeps a version reference in .gnu.version_r for symbols which are optimized out
Summary: [2.29 Regression] ld.bfd keeps a version reference in .gnu.version_r for symb...
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.29
: P2 normal
Target Milestone: 2.30
Assignee: Alan Modra
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-09-18 13:33 UTC by Matthias Klose
Modified: 2017-09-22 14:09 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Matthias Klose 2017-09-18 13:33:32 UTC
[forwarded from https://launchpad.net/bugs/1715641]

test files at https://people.canonical.com/~doko/tmp/lp1715641.tar.xz

feel free to call that a regression or behavior change ;) ... This is seen when building NetworkManager using ld 2.29 using glibc 2.26, the dpkg-shlibs tool not seeing a versioned dependency on a glibc 2.26 symbol, and then the packaging tools declaring NetworkManager be ready for use with glibc 2.24, and then the dynamic loader complaining with 

# ldd /usr/sbin/NetworkManager
/usr/sbin/NetworkManager: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.25' not found (required by /usr/sbin/NetworkManager)

The behaviour change between ld 2.28 and ld 2.29 seems to be

$ readelf -V NetworkManager-ld-2.28 | fgrep GLIBC_2.25
$ readelf -V NetworkManager-ld-2.29 | fgrep GLIBC_2.25
  0x0170:   Name: GLIBC_2.25  Flags: none  Version: 11

$ readelf -V NetworkManager-gold-2.28 | fgrep GLIBC_2.25
  000:   0 (*local*)       2 (GLIBC_2.25)    d (CURL_GNUTLS_3)   d (CURL_GNUTLS_3)
  0x0010:   Name: GLIBC_2.25  Flags: none  Version: 2
$ readelf -V NetworkManager-gold-2.29 | fgrep GLIBC_2.25
  000:   0 (*local*)       2 (GLIBC_2.25)    d (CURL_GNUTLS_3)   d (CURL_GNUTLS_3)
  0x0010:   Name: GLIBC_2.25  Flags: none  Version: 2

$ objdump -T NetworkManager-ld-2.29|grep GLIBC_2.25
$ objdump -T NetworkManager-gold-2.29|grep GLIBC_2.25
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.25  __explicit_bzero_chk

There is no behavior change in gold, and gold correctly marks the symbol as undefined. ld-2.28 otoh is able to detect that the symbol isn't used, doesn't emit a reference, but in 2.29 it keeps a reference in the .gnu.version_r section. Is this expected behavior?

There is a bug in NetworkManager as well, as it defines a backup for the explicit_bzero function which is new in glibc 2.25, but it fails to define that for explicit_bzero_chk which is used when building with -D_FORTIFY_SOURCE.
Comment 1 Matthias Klose 2017-09-18 13:38:59 UTC
seems to be not target specific
Comment 2 H.J. Lu 2017-09-18 20:56:39 UTC
Is this against ld or gold?  If it is against ld, please provide a testcase
for ld, not for gold.  link.sh uses gold, not ld.
Comment 3 Matthias Klose 2017-09-18 21:31:57 UTC
it is against ld. forgot to reset the link script after generating the binaries with the four linker variants.
Comment 4 H.J. Lu 2017-09-18 21:35:17 UTC
(In reply to Matthias Klose from comment #3)
> it is against ld. forgot to reset the link script after generating the
> binaries with the four linker variants.

It doesn't work with ld:

ld.bfd: warning: libpcre.so.3, needed by libglib-2.0.so.0, not found (try using -rpath or -rpath-link)
ld.bfd: warning: libunistring.so.0, needed by libpsl.so.5, not found (try using -rpath or -rpath-link)
ld.bfd: warning: librtmp.so.1, needed by libcurl-gnutls.so.4.4.0, not found (try using -rpath or -rpath-link)
libglib-2.0.so.0: undefined reference to `pcre_fullinfo'
libcurl-gnutls.so.4.4.0: undefined reference to `ldap_sasl_bind@OPENLDAP_2.4_2'
libcurl-gnutls.so.4.4.0: undefined reference to `ldap_get_dn_ber@OPENLDAP_2.4_2'
libcurl-gnutls.so.4.4.0: undefined reference to `ber_sockbuf_add_io@OPENLDAP_2.4_2'
libcurl-gnutls.so.4.4.0: undefined reference to `ldap_unbind_ext@OPENLDAP_2.4_2'
libcurl-gnutls.so.4.4.0: undefined reference to `ldap_get_attribute_ber@OPENLDAP_2.4_2'
libcurl-gnutls.so.4.4.0: undefined reference to `RTMP_SetBufferMS'
libcurl-gnutls.so.4.4.0: undefined reference to `ldap_parse_result@OPENLDAP_2.4_2'
libcurl-gnutls.so.4.4.0: undefined reference to `RTMP_Init'
libcurl-gnutls.so.4.4.0: undefined reference to `RTMP_Connect1'
libcurl-gnutls.so.4.4.0: undefined reference to `ldap_set_option@OPENLDAP_2.4_2'
libcurl-gnutls.so.4.4.0: undefined reference to `RTMP_SetupURL'
libcurl-gnutls.so.4.4.0: undefined reference to `ldap_abandon_ext@OPENLDAP_2.4_2'
libcurl-gnutls.so.4.4.0: undefined reference to `ldap_msgfree@OPENLDAP_2.4_2'
libcurl-gnutls.so.4.4.0: undefined reference to `ldap_result@OPENLDAP_2.4_2'
libglib-2.0.so.0: undefined reference to `pcre_get_stringtable_entries'
libglib-2.0.so.0: undefined reference to `pcre_get_stringnumber'
libcurl-gnutls.so.4.4.0: undefined reference to `ldap_search_ext@OPENLDAP_2.4_2'
//lib64/libresolv.so.2: undefined reference to `__res_maybe_init@GLIBC_PRIVATE'
libcurl-gnutls.so.4.4.0: undefined reference to `ldap_get_option@OPENLDAP_2.4_2'
libcurl-gnutls.so.4.4.0: undefined reference to `ber_memfree@OPENLDAP_2.4_2'
libglib-2.0.so.0: undefined reference to `pcre_config'
libglib-2.0.so.0: undefined reference to `pcre_compile2'
libcurl-gnutls.so.4.4.0: undefined reference to `RTMP_Write'
libgnutls.so.30: undefined reference to `nettle_secp_192r1@HOGWEED_4'
libcurl-gnutls.so.4.4.0: undefined reference to `ldap_memfree@OPENLDAP_2.4_2'
libglib-2.0.so.0: undefined reference to `pcre_free'
libcurl-gnutls.so.4.4.0: undefined reference to `ldap_pvt_url_scheme2proto@OPENLDAP_2.4_2'
libcurl-gnutls.so.4.4.0: undefined reference to `RTMP_ConnectStream'
libselinux.so.1: undefined reference to `pcre_free_study'
libcurl-gnutls.so.4.4.0: undefined reference to `ldap_next_message@OPENLDAP_2.4_2'
libcurl-gnutls.so.4.4.0: undefined reference to `RTMP_Close'
libcurl-gnutls.so.4.4.0: undefined reference to `ber_free@OPENLDAP_2.4_2'
libglib-2.0.so.0: undefined reference to `pcre_exec'
libgnutls.so.30: undefined reference to `nettle_secp_224r1@HOGWEED_4'
libcurl-gnutls.so.4.4.0: undefined reference to `ldap_err2string@OPENLDAP_2.4_2'
libcurl-gnutls.so.4.4.0: undefined reference to `ldap_init_fd@OPENLDAP_2.4_2'
libselinux.so.1: undefined reference to `pcre_compile'
libcurl-gnutls.so.4.4.0: undefined reference to `ldap_msgtype@OPENLDAP_2.4_2'
libglib-2.0.so.0: undefined reference to `pcre_study'
libcurl-gnutls.so.4.4.0: undefined reference to `RTMP_Free'
libcurl-gnutls.so.4.4.0: undefined reference to `ldap_free_urldesc@OPENLDAP_2.4_2'
libcurl-gnutls.so.4.4.0: undefined reference to `ldap_url_parse@OPENLDAP_2.4_2'
libcurl-gnutls.so.4.4.0: undefined reference to `RTMP_Read'
libcurl-gnutls.so.4.4.0: undefined reference to `RTMP_Alloc'
libglib-2.0.so.0: undefined reference to `pcre_dfa_exec'
libselinux.so.1: undefined reference to `pcre_version'
libcurl-gnutls.so.4.4.0: undefined reference to `ldap_first_message@OPENLDAP_2.4_2'
Comment 5 Alan Modra 2017-09-18 22:54:15 UTC
The testcase needs -rpath=. to search . first for dependent libraries not mentioned on the command line, and these libraries are missing:
libblkid.so.1
libgpg-error.so.0
libkrb5.so.3
libk5crypto.so.3
libcom_err.so.2
libkrb5support.so.0
libsasl2.so.2
libgssapi.so.3
libkeyutils.so.1
libheimntlm.so.0
libkrb5.so.26
libasn1.so.8
libhcrypto.so.4
libroken.so.18
libwind.so.0
libheimbase.so.1
libhx509.so.5
libsqlite3.so.0
libcrypt.so.1

If I use my Ubuntu 16.04 system libs for the above, then I see
./libgssapi_krb5.so.2: undefined reference to `k5_os_mutex_unlock@krb5support_0_MIT'
./libgssapi_krb5.so.2: undefined reference to `k5_os_mutex_init@krb5support_0_MIT'
./libgssapi_krb5.so.2: undefined reference to `k5_os_mutex_lock@krb5support_0_MIT'
./libgssapi_krb5.so.2: undefined reference to `k5_once@krb5support_0_MIT'
./libgssapi_krb5.so.2: undefined reference to `k5_os_mutex_destroy@krb5support_0_MIT'
Comment 6 Matthias Klose 2017-09-18 22:56:33 UTC
sorry, I updated the test tarball.

Alan, this is artful (both release and proposed pockets enabled).
Comment 7 Alan Modra 2017-09-18 23:55:49 UTC
OK, so I can work around the missing symbols with --allow-shlib-undefined, and reproduce the problem.  The changed behaviour is due to running elf_gc_sweep_symbol after setting version refs.  ie. the fix for pr20828, git commit 902e9fc76a.

With 2.29, __explicit_bzero_chk@@GLIBC_2.25 triggers the GLIBC_2.25 version ref.  With 2.28 that symbol has dynindx set to -1 by elf_gc_sweep_symbol before version refs are calculated.
Comment 8 Alan Modra 2017-09-19 01:05:27 UTC
I think this can be fixed by running elf_gc_sweep_symbol before we calculate version refs, but leaving it after version defs.
Comment 9 Sourceware Commits 2017-09-19 05:08:26 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:

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

commit 3d13f3e9bda5aada68915f5d958f731ae79ed41d
Author: Alan Modra <amodra@gmail.com>
Date:   Tue Sep 19 11:59:30 2017 +0930

    PR22150, ld keeps a version reference for gc'd symbols
    
    elf_gc_sweep_symbol should run after verdefs are calculated, since
    the verdef code creates symbols for the versions.  However,
    elf_gc_sweep_symbol needs to run before verrefs so as to not emit
    useless verrefs for symbols that are gc'd.
    
    I've also removed a _bfd_elf_link_renumber_dynsyms calls added by
    Maciej after I fussed about it when reviewing.  On further examination
    the call appears to be unnecessary.  Looking at renumber_dynsyms also
    made me realize that the test to exclude .gnu.version has been wrong
    since 2016-04-26 (git commit d5486c4372), so fix that too.
    
    	PR 22150
    	* elflink.c (bfd_elf_size_dynamic_sections): Garbage collect
    	symbols before calculating verrefs.  Don't renumber dynsyms
    	after gc.  Exclude .gnu.version when zero or one dynsym.
    	Localize some vars and reindent.
Comment 10 Sourceware Commits 2017-09-19 07:15:57 UTC
The binutils-2_29-branch branch has been updated by Alan Modra <amodra@sourceware.org>:

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

commit c01ee74d3ad56a25272dfd5607ce4a807223e7e5
Author: Alan Modra <amodra@gmail.com>
Date:   Tue Sep 19 11:59:30 2017 +0930

    PR22150, ld keeps a version reference for gc'd symbols
    
    elf_gc_sweep_symbol should run after verdefs are calculated, since
    the verdef code creates symbols for the versions.  However,
    elf_gc_sweep_symbol needs to run before verrefs so as to not emit
    useless verrefs for symbols that are gc'd.
    
    I've also removed a _bfd_elf_link_renumber_dynsyms calls added by
    Maciej after I fussed about it when reviewing.  On further examination
    the call appears to be unnecessary.  Looking at renumber_dynsyms also
    made me realize that the test to exclude .gnu.version has been wrong
    since 2016-04-26 (git commit d5486c4372), so fix that too.
    
    	PR 22150
    	* elflink.c (bfd_elf_size_dynamic_sections): Garbage collect
    	symbols before calculating verrefs.  Don't renumber dynsyms
    	after gc.  Exclude .gnu.version when zero or one dynsym.
    	Localize some vars and reindent.
    
    (cherry picked from commit 3d13f3e9bda5aada68915f5d958f731ae79ed41d)
Comment 11 Alan Modra 2017-09-19 07:54:45 UTC
Should be fixed now
Comment 12 Sourceware Commits 2017-09-22 14:07:02 UTC
The master branch has been updated by H.J. Lu <hjl@sourceware.org>:

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

commit be2b629f6427812a24f38802ba1c472a2cbfab7d
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Fri Sep 22 06:58:48 2017 -0700

    Add a test for PR ld/22150
    
    	PR ld/22150
    	* testsuite/ld-elf/pr22150.vd: New file.
    	* testsuite/ld-elf/pr22150.ver: Likewise.
    	* testsuite/ld-elf/pr22150a.s: Likewise.
    	* testsuite/ld-elf/pr22150b.s: Likewise.
    	* testsuite/ld-elf/shared.exp: Run PR ld/22150 tests.