Bug 18720

Summary: No symbol version section for versioned symbol `foo@FOO'
Product: binutils Reporter: H.J. Lu <hjl.tools>
Component: ldAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED FIXED    
Severity: normal CC: ccoutant
Priority: P2    
Version: 2.26   
Target Milestone: 2.26   
Host: Target:
Build: Last reconfirmed:
Bug Depends on:    
Bug Blocks: 19553    

Description H.J. Lu 2015-07-25 15:48:16 UTC
[hjl@gnu-tools-1 plt-2]$ cat indirect3a.c
extern void bar (void);
extern void foo (void);

__attribute__ ((noinline, noclone))
int
foo_p (void)
{
  return (long) &foo == 0x12345678 ? 1 : 0;
}

int
main (void)
{
  foo ();
  foo_p ();
  bar ();
  return 0;
}
[hjl@gnu-tools-1 plt-2]$ cat indirect3b.c
#include <stdio.h>

void
foo (void)
{
  printf ("MAIN\n");
}

asm (".symver foo,foo@FOO");
[hjl@gnu-tools-1 plt-2]$ cat indirect3c.c
#include <stdio.h>

extern void foo (void);

void
foo (void)
{
  printf ("DSO\n");
}

void
bar (void)
{
  foo ();
}
[hjl@gnu-tools-1 plt-2]$ make
gcc -B./ -fPIC -O2 -c -o indirect3a.o indirect3a.c
gcc -B./ -fPIC -O2 -c -o indirect3b.o indirect3b.c
gcc -B./ -fPIC -O2 -fPIC  -c -o indirect3c.o indirect3c.c
gcc -B./ -shared -o libindirect3c.so indirect3c.o
gcc -B./ -o x indirect3a.o indirect3b.o libindirect3c.so -Wl,-R.
./ld: x: No symbol version section for versioned symbol `foo@FOO'
./ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status
Makefile:22: recipe for target 'x' failed
make: *** [x] Error 1
[hjl@gnu-tools-1 plt-2]$
Comment 1 Cary Coutant 2015-07-27 16:00:02 UTC
With my proposed fix for gas (see PR 18703 comment #12), indirect3b.o would not have the stray unversioned definition for foo, and ld would work just fine as is.

https://sourceware.org/bugzilla/show_bug.cgi?id=18703#c12

With your testcase, gold binds to the unversioned foo in indirect3b.o, and the resulting binary prints "MAIN" twice. With the patched assembler, both gold and ld print "DSO" twice.
Comment 2 H.J. Lu 2015-07-27 16:35:45 UTC
(In reply to Cary Coutant from comment #1)
> With my proposed fix for gas (see PR 18703 comment #12), indirect3b.o would
> not have the stray unversioned definition for foo, and ld would work just
> fine as is.
> 
> https://sourceware.org/bugzilla/show_bug.cgi?id=18703#c12
> 
> With your testcase, gold binds to the unversioned foo in indirect3b.o, and
> the resulting binary prints "MAIN" twice. With the patched assembler, both
> gold and ld print "DSO" twice.

I tried your gas change:

diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
index 78dc6d9..8668be0 100644
--- a/gas/config/obj-elf.c
+++ b/gas/config/obj-elf.c
@@ -2182,6 +2182,11 @@ elf_frob_symbol (symbolS *symp, int *puntp)
         memmove (&p[2], &p[3], l);
         S_SET_NAME (symp, sy_obj->versioned_name);
       }
+    else if (strncmp (S_GET_NAME (symp), sy_obj->versioned_name,
+            strlen (S_GET_NAME (symp))) == 0)
+      {
+        S_SET_NAME (symp, sy_obj->versioned_name);
+      }
     else
       {
         symbolS *symp2;

on master branch on Linux/x86-64 and got:

FAIL: ELF symbol versioning
FAIL: Indirect symbol 1a: : local symbol `foo' in tmpdir/indirect1b.o is referenced by DSO
FAIL: Indirect symbol 1a: : final link failed: Bad value
FAIL: Indirect symbol 1b: : local symbol `foo' in tmpdir/indirect1b.o is referenced by DSO
FAIL: Indirect symbol 1b: : final link failed: Bad value
FAIL: Run with libindirect3c.so 1
FAIL: Run with libindirect3c.so 2
FAIL: Run with libindirect3c.so 3
FAIL: Run with libindirect3c.so 4
FAIL: vers24a
FAIL: vers24b
FAIL: ELF symbol versioning
FAIL: symver symver1

Do you those failures?
Comment 3 Sourceware Commits 2015-08-07 12:08:49 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=6e33951edcbed1fd803beabcde2af3b252b92164

commit 6e33951edcbed1fd803beabcde2af3b252b92164
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Fri Aug 7 05:04:21 2015 -0700

    Properly merge hidden versioned symbol
    
    The hidden versioned symbol can only be merged with the versioned
    symbol with the same symbol version.  _bfd_elf_merge_symbol should
    check the symbol version before merging the new hidden versioned
    symbol with the existing symbol.  _bfd_elf_link_hash_copy_indirect can't
    copy any references to the hidden versioned symbol.   We need to
    bind a symbol locally when linking executable if it is locally defined,
    hidden versioned, not referenced by shared library and not exported.
    
    bfd/
    
    	PR ld/18720
    	* elflink.c (_bfd_elf_merge_symbol): Add a parameter to indicate
    	if the new symbol matches the existing one.  The new hidden
    	versioned symbol matches the existing symbol if they have the
    	same symbol version. Update the existing symbol only if they
    	match.
    	(_bfd_elf_add_default_symbol): Update call to
    	_bfd_elf_merge_symbol.
    	(_bfd_elf_link_assign_sym_version): Don't set the hidden field
    	here.
    	(elf_link_add_object_symbols): Override a definition only if the
    	new symbol matches the existing one.
    	(_bfd_elf_link_hash_copy_indirect): Don't copy any references to
    	the hidden versioned symbol.
    	(elf_link_output_extsym): Bind a symbol locally when linking
    	executable if it is locally defined, hidden versioned, not
    	referenced by shared library and not exported.  Turn on
    	VERSYM_HIDDEN only if the hidden vesioned symbol is defined
    	locally.
    
    ld/testsuite/
    
    	PR ld/18720
    	* ld-elf/indirect.exp: Run tests for PR ld/18720.
    	* ld-elf/pr18720.out: New file.
    	* ld-elf/pr18720a.c: Likewise.
    	* ld-elf/pr18720b.c: Likewise.
    	* ld-elf/pr18720c.c: Likewise.
Comment 4 H.J. Lu 2015-08-07 12:49:23 UTC
Fixed.
Comment 5 Sourceware Commits 2016-11-28 16:05:12 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=4deb8f714d555a2f530e37c3e7af32bc42fdda58

commit 4deb8f714d555a2f530e37c3e7af32bc42fdda58
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Mon Nov 28 08:03:46 2016 -0800

    Properly hide hidden versioned symbol in executable
    
    A hidden versioned symbol in executable should be forced local if it is
    locally defined, not referenced by shared library and not exported.  We
    must do it before _bfd_elf_link_renumber_dynsyms.
    
    bfd/
    
    	* elflink.c (_bfd_elf_fix_symbol_flags): Hide hidden versioned
    	symbol in executable.
    	(elf_link_output_extsym): Don't change bind from global to
    	local when linking executable.
    
    ld/
    
    	* testsuite/ld-elf/indirect.exp: Add a test for PR 18720.
    	* testsuite/ld-elf/pr18720.rd: New file.
Comment 6 Sourceware Commits 2016-12-29 13:33:28 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:

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

commit e81830c5c61a8665c098189d069cc68b0df113d3
Author: Alan Modra <amodra@gmail.com>
Date:   Thu Dec 29 22:49:41 2016 +1030

    link_hash_copy_indirect and symbol flags
    
    A while ago HJ fixed PR ld/18720 with commit 6e33951ed, which, among
    other things, modified _bfd_elf_link_hash_copy_indirect to not copy
    ref_dynamic, ref_regular, ref_regular_nonweak, non_got_ref, needs_plt
    and pointer_equality_needed when setting up an indirect non-versioned
    symbol pointing to a non-default versioned symbol.  I didn't notice at
    the time, but the pr18720 testcase fails on hppa-linux with
    "internal error, aborting at binutils-gdb-2.28/bfd/elf32-hppa.c:3933
    in elf32_hppa_relocate_section".
    
    Now hppa-linux creates entries in the plt even for local functions, if
    they are referenced using plabel (function pointer) relocations.   So
    needs_plt is set for foo when processing pr18720a.o.  When the aliases
    in pr28720b.o are processed, we get an indirection from foo to
    foo@FOO, but don't copy needs_plt.  Since foo@FOO is the "real" symbol
    that is used after that point, no plt entry is made for foo and we
    bomb when relocating the plabel.
    
    As shown by the hppa-linux scenario, needs_plt should be copied even
    for non-default versioned symbols.  I believe all of the others ought
    to be copied too, with the exception of ref_dynamic.  Not copying
    ref_dynamic is right because if a shared lib references "foo" it
    should not be satisfied by any non-default version "foo@FOO".
    
    	* elflink.c (_bfd_elf_link_hash_copy_indirect): Only omit
    	copying one flag, ref_dynamic, when versioned_hidden.
    	* elf64-ppc.c (ppc64_elf_copy_indirect_symbol): Likewise.
    	* elf32-hppa.c (elf32_hppa_copy_indirect_symbol): Use same
    	logic for copying weakdef flags.  Copy plabel flag and merge
    	tls_type.
    	* elf32-i386.c (elf_i386_copy_indirect_symbol): Use same logic
    	for copying weakdef flags.
    	* elf32-ppc.c (ppc_elf_copy_indirect_symbol): Likewise.
    	* elf32-s390.c (elf_s390_copy_indirect_symbol): Likewise.
    	* elf32-sh.c (sh_elf_copy_indirect_symbol): Likewise.
    	* elf64-s390.c (elf_s390_copy_indirect_symbol): Likewise.
    	* elfnn-ia64.c (elfNN_ia64_hash_copy_indirect): Likewise.
    	* elf64-x86-64.c (elf_x86_64_copy_indirect_symbol): Likewise.
    	Simplify.
Comment 7 Sourceware Commits 2016-12-30 00:41:12 UTC
The binutils-2_28-branch branch has been updated by Alan Modra <amodra@sourceware.org>:

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

commit de1f27ad53e4bcc3aa47209cdb5f32eb1fc41a76
Author: Alan Modra <amodra@gmail.com>
Date:   Thu Dec 29 22:49:41 2016 +1030

    link_hash_copy_indirect and symbol flags
    
    A while ago HJ fixed PR ld/18720 with commit 6e33951ed, which, among
    other things, modified _bfd_elf_link_hash_copy_indirect to not copy
    ref_dynamic, ref_regular, ref_regular_nonweak, non_got_ref, needs_plt
    and pointer_equality_needed when setting up an indirect non-versioned
    symbol pointing to a non-default versioned symbol.  I didn't notice at
    the time, but the pr18720 testcase fails on hppa-linux with
    "internal error, aborting at binutils-gdb-2.28/bfd/elf32-hppa.c:3933
    in elf32_hppa_relocate_section".
    
    Now hppa-linux creates entries in the plt even for local functions, if
    they are referenced using plabel (function pointer) relocations.   So
    needs_plt is set for foo when processing pr18720a.o.  When the aliases
    in pr28720b.o are processed, we get an indirection from foo to
    foo@FOO, but don't copy needs_plt.  Since foo@FOO is the "real" symbol
    that is used after that point, no plt entry is made for foo and we
    bomb when relocating the plabel.
    
    As shown by the hppa-linux scenario, needs_plt should be copied even
    for non-default versioned symbols.  I believe all of the others ought
    to be copied too, with the exception of ref_dynamic.  Not copying
    ref_dynamic is right because if a shared lib references "foo" it
    should not be satisfied by any non-default version "foo@FOO".
    
    	* elflink.c (_bfd_elf_link_hash_copy_indirect): Only omit
    	copying one flag, ref_dynamic, when versioned_hidden.
    	* elf64-ppc.c (ppc64_elf_copy_indirect_symbol): Likewise.
    	* elf32-hppa.c (elf32_hppa_copy_indirect_symbol): Use same
    	logic for copying weakdef flags.  Copy plabel flag and merge
    	tls_type.
    	* elf32-i386.c (elf_i386_copy_indirect_symbol): Use same logic
    	for copying weakdef flags.
    	* elf32-ppc.c (ppc_elf_copy_indirect_symbol): Likewise.
    	* elf32-s390.c (elf_s390_copy_indirect_symbol): Likewise.
    	* elf32-sh.c (sh_elf_copy_indirect_symbol): Likewise.
    	* elf64-s390.c (elf_s390_copy_indirect_symbol): Likewise.
    	* elfnn-ia64.c (elfNN_ia64_hash_copy_indirect): Likewise.
    	* elf64-x86-64.c (elf_x86_64_copy_indirect_symbol): Likewise.
    	Simplify.