Bug 18703 - Symbol version and Version script incompatibility with BFD ld
Summary: Symbol version and Version script incompatibility with BFD ld
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: gold (show other bugs)
Version: 2.26
: P2 normal
Target Milestone: ---
Assignee: Cary Coutant
URL:
Keywords:
: 13521 (view as bug list)
Depends on:
Blocks: 12261 13521
  Show dependency treegraph
 
Reported: 2015-07-21 22:18 UTC by Sriraman Tallam
Modified: 2015-09-07 16:52 UTC (History)
7 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 Sriraman Tallam 2015-07-21 22:18:18 UTC
Here is a simple example to reproduce the problem:

foo.cc
======

extern "C"
int foo() {
  return 0;
}

__asm__ (".symver foo, foo@VERS_1.1");


foo.map
=======

VERS_1.1 {
  global:
	foo;
};


Now, use BFD linker:

$ g++ -B<path to bfd linker> foo.cc -fPIC -shared -Wl,--version-script=./foo.map -o libfoo.so

$ nm libfoo.so | grep foo
0000000000000700 T foo@VERS_1.1

The symbol is versioned.

Now, use gold linker and repeat:

$ g++ -B<path to gold linker> foo.cc -fPIC -shared -Wl,--version-script=./foo.map -o libfoo.so

$ nm libfoo.so | grep foo
0000000000000740 T foo

The symbol is not versioned.

This affects building libgcc_s.so in trunk GCC with gold as symbol __cpu_indicator_init is versioned in the exact manner as described.
Comment 1 Cary Coutant 2015-07-21 23:33:42 UTC
You're looking at the linker symbol table with nm. (And nm does not show versioning information from the .gnu.version* sections.)

When I build this with gold, readelf -Vs shows:

Symbol table '.dynsym' contains 13 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     2: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTab
     3: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@GLIBC_2.2.5 (3)
     4: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
     5: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
     6: 00000000000006f5    11 FUNC    GLOBAL DEFAULT   12 foo@@VERS_1.1
     7: 0000000000002018     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
     8: 0000000000002019     0 NOTYPE  GLOBAL DEFAULT  ABS _end
     9: 00000000000005c0     0 FUNC    GLOBAL DEFAULT   10 _init
    10: 0000000000002018     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    11: 0000000000000700     0 FUNC    GLOBAL DEFAULT   13 _fini
    12: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  ABS VERS_1.1

...

Version symbols section '.gnu.version' contains 13 entries:
 Addr: 0000000000000458  Offset: 0x000458  Link: 2 (.dynsym)
  000:   0 (*local*)       0 (*local*)       0 (*local*)       3 (GLIBC_2.2.5)
  004:   0 (*local*)       0 (*local*)       2 (VERS_1.1)      1 (*global*)   
  008:   1 (*global*)      1 (*global*)      1 (*global*)      1 (*global*)   
  00c:   2 (VERS_1.1)   

Version definition section '.gnu.version_d' contains 2 entries:
  Addr: 0x0000000000000474  Offset: 0x000474  Link: 3 (.dynstr)  000000: Rev: 1  Flags: BASE   Index: 1  Cnt: 1  Name: ver1.so
  0x001c: Rev: 1  Flags: none  Index: 2  Cnt: 1  Name: VERS_1.1

Version needs section '.gnu.version_r' contains 1 entries:
 Addr: 0x00000000000004ac  Offset: 0x0004ac  Link: 3 (.dynstr)
  000000: Version: 1  File: libc.so.6  Cnt: 1
  0x0010:   Name: GLIBC_2.2.5  Flags: none  Version: 3

I think this is working as intended, although comparing with Gnu ld output, I see that gold defines it as a default version ("@@") where Gnu ld does not. I'm not sure what the logic ought to be for that. Without the __asm__ in the .c file, Gnu ld also makes it a default version.
Comment 2 Sriraman Tallam 2015-07-21 23:51:08 UTC
On Tue, Jul 21, 2015 at 11:03 AM, ccoutant at gmail dot com
<sourceware-bugzilla@sourceware.org> wrote:
> https://sourceware.org/bugzilla/show_bug.cgi?id=18703
>
> --- Comment #1 from Cary Coutant <ccoutant at gmail dot com> ---
> You're looking at the linker symbol table with nm. (And nm does not show
> versioning information from the .gnu.version* sections.)
>
> When I build this with gold, readelf -Vs shows:
>
> Symbol table '.dynsym' contains 13 entries:
>    Num:    Value          Size Type    Bind   Vis      Ndx Name
>      0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
>      1: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
>      2: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND
> _ITM_deregisterTMCloneTab
>      3: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND
> __cxa_finalize@GLIBC_2.2.5 (3)
>      4: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND
> _ITM_registerTMCloneTable
>      5: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
>      6: 00000000000006f5    11 FUNC    GLOBAL DEFAULT   12 foo@@VERS_1.1
>      7: 0000000000002018     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
>      8: 0000000000002019     0 NOTYPE  GLOBAL DEFAULT  ABS _end
>      9: 00000000000005c0     0 FUNC    GLOBAL DEFAULT   10 _init
>     10: 0000000000002018     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
>     11: 0000000000000700     0 FUNC    GLOBAL DEFAULT   13 _fini
>     12: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  ABS VERS_1.1
>
> ...
>
> Version symbols section '.gnu.version' contains 13 entries:
>  Addr: 0000000000000458  Offset: 0x000458  Link: 2 (.dynsym)
>   000:   0 (*local*)       0 (*local*)       0 (*local*)       3 (GLIBC_2.2.5)
>   004:   0 (*local*)       0 (*local*)       2 (VERS_1.1)      1 (*global*)
>   008:   1 (*global*)      1 (*global*)      1 (*global*)      1 (*global*)
>   00c:   2 (VERS_1.1)
>
> Version definition section '.gnu.version_d' contains 2 entries:
>   Addr: 0x0000000000000474  Offset: 0x000474  Link: 3 (.dynstr)  000000: Rev: 1
>  Flags: BASE   Index: 1  Cnt: 1  Name: ver1.so
>   0x001c: Rev: 1  Flags: none  Index: 2  Cnt: 1  Name: VERS_1.1
>
> Version needs section '.gnu.version_r' contains 1 entries:
>  Addr: 0x00000000000004ac  Offset: 0x0004ac  Link: 3 (.dynstr)
>   000000: Version: 1  File: libc.so.6  Cnt: 1
>   0x0010:   Name: GLIBC_2.2.5  Flags: none  Version: 3
>
> I think this is working as intended, although comparing with Gnu ld output, I
> see that gold defines it as a default version ("@@") where Gnu ld does not. I'm
> not sure what the logic ought to be for that. Without the __asm__ in the .c
> file, Gnu ld also makes it a default version.

Some context:

https://gcc.gnu.org/ml/gcc-patches/2015-04/msg00878.html

This was used to hide symbols __cpu_indicator_init and __cpu_model
defined in libgcc_s.so so that this symbol is always obtained from
libgcc.a. Now, this works with GNU ld and not with gold.  Isnt this an
incompatibility. If this is not well defined, is there another well
defined way of achieving the same result?

Thanks
Sri


>
> --
> You are receiving this mail because:
> You reported the bug.
Comment 3 Cary Coutant 2015-07-22 00:07:01 UTC
Sorry, I need more context than that. You've said that the symbol is
not versioned, but in fact it is. The only differences between the two
linkers that I see are:

(1) The name that appears in the linker symbol table, which shouldn't
matter to the loader at all. If this is causing a problem, can you
point to the section in the linker manual that describes the correct
behavior? I don't think gold was designed with the intent of
propagating @-style version information into the output binary. We
only use the version sections, and, as far as I know, the dynamic
loader only uses version sections.

(2) Gold defines the symbol as a default version, while Gnu ld
doesn't. If this is the problem, I'll need to understand what the
proper logic is for determining whether a symbol should be marked as
the default version.

You said this affects building libgcc_s.so in trunk, but you haven't
said what is actually failing.

-cary


On Tue, Jul 21, 2015 at 4:51 PM, tmsriram at google dot com
<sourceware-bugzilla@sourceware.org> wrote:
> https://sourceware.org/bugzilla/show_bug.cgi?id=18703
>
> --- Comment #2 from Sriraman Tallam <tmsriram at google dot com> ---
> On Tue, Jul 21, 2015 at 11:03 AM, ccoutant at gmail dot com
> <sourceware-bugzilla@sourceware.org> wrote:
>> https://sourceware.org/bugzilla/show_bug.cgi?id=18703
>>
>> --- Comment #1 from Cary Coutant <ccoutant at gmail dot com> ---
>> You're looking at the linker symbol table with nm. (And nm does not show
>> versioning information from the .gnu.version* sections.)
>>
>> When I build this with gold, readelf -Vs shows:
>>
>> Symbol table '.dynsym' contains 13 entries:
>>    Num:    Value          Size Type    Bind   Vis      Ndx Name
>>      0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
>>      1: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
>>      2: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND
>> _ITM_deregisterTMCloneTab
>>      3: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND
>> __cxa_finalize@GLIBC_2.2.5 (3)
>>      4: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND
>> _ITM_registerTMCloneTable
>>      5: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
>>      6: 00000000000006f5    11 FUNC    GLOBAL DEFAULT   12 foo@@VERS_1.1
>>      7: 0000000000002018     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
>>      8: 0000000000002019     0 NOTYPE  GLOBAL DEFAULT  ABS _end
>>      9: 00000000000005c0     0 FUNC    GLOBAL DEFAULT   10 _init
>>     10: 0000000000002018     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
>>     11: 0000000000000700     0 FUNC    GLOBAL DEFAULT   13 _fini
>>     12: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  ABS VERS_1.1
>>
>> ...
>>
>> Version symbols section '.gnu.version' contains 13 entries:
>>  Addr: 0000000000000458  Offset: 0x000458  Link: 2 (.dynsym)
>>   000:   0 (*local*)       0 (*local*)       0 (*local*)       3 (GLIBC_2.2.5)
>>   004:   0 (*local*)       0 (*local*)       2 (VERS_1.1)      1 (*global*)
>>   008:   1 (*global*)      1 (*global*)      1 (*global*)      1 (*global*)
>>   00c:   2 (VERS_1.1)
>>
>> Version definition section '.gnu.version_d' contains 2 entries:
>>   Addr: 0x0000000000000474  Offset: 0x000474  Link: 3 (.dynstr)  000000: Rev: 1
>>  Flags: BASE   Index: 1  Cnt: 1  Name: ver1.so
>>   0x001c: Rev: 1  Flags: none  Index: 2  Cnt: 1  Name: VERS_1.1
>>
>> Version needs section '.gnu.version_r' contains 1 entries:
>>  Addr: 0x00000000000004ac  Offset: 0x0004ac  Link: 3 (.dynstr)
>>   000000: Version: 1  File: libc.so.6  Cnt: 1
>>   0x0010:   Name: GLIBC_2.2.5  Flags: none  Version: 3
>>
>> I think this is working as intended, although comparing with Gnu ld output, I
>> see that gold defines it as a default version ("@@") where Gnu ld does not. I'm
>> not sure what the logic ought to be for that. Without the __asm__ in the .c
>> file, Gnu ld also makes it a default version.
>
> Some context:
>
> https://gcc.gnu.org/ml/gcc-patches/2015-04/msg00878.html
>
> This was used to hide symbols __cpu_indicator_init and __cpu_model
> defined in libgcc_s.so so that this symbol is always obtained from
> libgcc.a. Now, this works with GNU ld and not with gold.  Isnt this an
> incompatibility. If this is not well defined, is there another well
> defined way of achieving the same result?
>
> Thanks
> Sri
>
>
>>
>> --
>> You are receiving this mail because:
>> You reported the bug.
>
> --
> You are receiving this mail because:
> You are on the CC list for the bug.
> You are the assignee for the bug.
Comment 4 H.J. Lu 2015-07-22 00:10:37 UTC
(In reply to Cary Coutant from comment #1)
> I think this is working as intended, although comparing with Gnu ld output,
> I see that gold defines it as a default version ("@@") where Gnu ld does
> not. I'm not sure what the logic ought to be for that. Without the __asm__
> in the .c file, Gnu ld also makes it a default version.

From "info as":

   Another usage of the '.symver' directive is:
     .symver NAME, NAME2@@NODENAME
   In this case, the symbol NAME must exist and be defined within the
file being assembled.  It is similar to NAME2@NODENAME.  The difference
is NAME2@@NODENAME will also be used to resolve references to NAME2 by
the linker.

Linker shouldn't use foo@VERS_1.1 to resolve references to foo.
Comment 5 H.J. Lu 2015-07-22 00:12:38 UTC
From "info ld":

  To do this, you must use multiple '.symver' directives in the source
file.  Here is an example:

     __asm__(".symver original_foo,foo@");
     __asm__(".symver old_foo,foo@VERS_1.1");
     __asm__(".symver old_foo1,foo@VERS_1.2");
     __asm__(".symver new_foo,foo@@VERS_2.0");

   In this example, 'foo@' represents the symbol 'foo' bound to the
unspecified base version of the symbol.  The source file that contains
this example would define 4 C functions: 'original_foo', 'old_foo',
'old_foo1', and 'new_foo'.

   When you have multiple definitions of a given symbol, there needs to
be some way to specify a default version to which external references to
this symbol will be bound.  You can do this with the 'foo@@VERS_2.0'
type of '.symver' directive.  You can only declare one version of a
symbol as the default in this manner; otherwise you would effectively
have multiple definitions of the same symbol.
Comment 6 Cary Coutant 2015-07-22 00:35:08 UTC
>    Another usage of the '.symver' directive is:
>      .symver NAME, NAME2@@NODENAME
>    In this case, the symbol NAME must exist and be defined within the
> file being assembled.  It is similar to NAME2@NODENAME.  The difference
> is NAME2@@NODENAME will also be used to resolve references to NAME2 by
> the linker.
>
> Linker shouldn't use foo@VERS_1.1 to resolve references to foo.

Yes, I understand that much. The example given uses:

   .symver foo, foo@VERS_1.1

where the original symbol and the versioned symbol both have the same
name. This produces two symbols in the .o file named "foo":

0000000000000000 T foo
0000000000000000 T foo@VERS_1.1

With the version script, gold sees the first of those (plain "foo")
and makes it the default version (as, I think, it should). The second
one is just seen as a second declaration, but it's already been marked
the default.

If I change Sri's example to use ".symver orig_foo, foo@VERS_1.1" and
rename "foo" to "orig_foo", I get the following in the dynamic symbol
table:

     6: 0000000000000725    11 FUNC    GLOBAL DEFAULT   12 foo@VERS_1.1
     7: 0000000000000725    11 FUNC    GLOBAL DEFAULT   12 orig_foo

If it's the "@@" vs. "@" that's causing the problem, then there's your fix.

-cary
Comment 7 H.J. Lu 2015-07-22 00:53:14 UTC
(In reply to Cary Coutant from comment #6)
> >    Another usage of the '.symver' directive is:
> >      .symver NAME, NAME2@@NODENAME
> >    In this case, the symbol NAME must exist and be defined within the
> > file being assembled.  It is similar to NAME2@NODENAME.  The difference
> > is NAME2@@NODENAME will also be used to resolve references to NAME2 by
> > the linker.
> >
> > Linker shouldn't use foo@VERS_1.1 to resolve references to foo.
> 
> Yes, I understand that much. The example given uses:
> 
>    .symver foo, foo@VERS_1.1
> 
> where the original symbol and the versioned symbol both have the same
> name. This produces two symbols in the .o file named "foo":
> 
> 0000000000000000 T foo
> 0000000000000000 T foo@VERS_1.1
> 
> With the version script, gold sees the first of those (plain "foo")
> and makes it the default version (as, I think, it should). The second
> one is just seen as a second declaration, but it's already been marked
> the default.
> 

foo is versioned and only version specified is VERS_1.1, which is not
default version.  It is wrong to create a default foo without being asked
to do so.
Comment 8 Sriraman Tallam 2015-07-22 01:03:59 UTC
On Tue, Jul 21, 2015 at 5:07 PM, ccoutant at gmail dot com
<sourceware-bugzilla@sourceware.org> wrote:
> https://sourceware.org/bugzilla/show_bug.cgi?id=18703
>
> --- Comment #3 from Cary Coutant <ccoutant at gmail dot com> ---
> Sorry, I need more context than that. You've said that the symbol is
> not versioned, but in fact it is. The only differences between the two
> linkers that I see are:

Hi Cary,

   I am just learning symbol versioning after running into this bug so
apologies if I misunderstood.  The particular bug I am running into
this.  I am looking at libgcc_s.so.1 linked with GNU-ld and linked
with the gold linker.  Based on your comments, I think I understand
this a little better so let me atleast try to get explain my problem:

With GNU ld linked libgcc_s.so.1, symbol __cpu_indicator_init looks
like this in the .dynsym:

     4: 0000000000002bb0   815 FUNC    GLOBAL DEFAULT   11
__cpu_indicator_init@GCC_4.8.0

whereas with gold linked  libgcc_s.so.1, symbol __cpu_indicator_init
shows up as:

    15: 0000000000002c10   783 FUNC    GLOBAL DEFAULT   12
__cpu_indicator_init@@GCC_4.8.0

I see the extra "@" now, I almost missed it last time as I did not
know about this!

What is happening because of this subtle change is a bug with function
multi-versioning and shared objects.

foomv.cc
-----------
__attribute__((target("default")))
void foo() {
  printf("This is default\n");
}

__attribute__((target("avx")))
void foo() {
  printf("This is AVX\n");
}

int callfoo() {
  foo();
}

If I use the GNU ld linked libgcc_s.so.1,

$ g++ -fPIC -shared foomv.cc -o libfoomv.so -Wl,-z,now
-Wl,-y,__cpu_indicator_init
libgcc_s.so.1: definition of __cpu_indicator_init
libgcc.a(cpuinfo.o): definition of __cpu_indicator_init

The definition of __cpu_indicator_init always comes from libgcc.a even
if it found libgcc_s.so.1 earlier.

whereas if I use gold  linked libgcc_s.so.1

$ g++ -fPIC -shared foomv.cc -o libfoomv.so -Wl,-z,now
-Wl,-y,__cpu_indicator_init
libgcc_s.so.1: definition of __cpu_indicator_init

it uses the definition in the shared object.  The problem with this is
it creates a plt entry for __cpu_indicator_init and
__cpu_indicator_init gets called from an ifunc function before the DSO
can be relocated leading to a seg fault.

From your later comments, it does look like the difference is because
of the extra "@" added by gold to make it the default symbol.

Thanks
Sri

>
> (1) The name that appears in the linker symbol table, which shouldn't
> matter to the loader at all. If this is causing a problem, can you
> point to the section in the linker manual that describes the correct
> behavior? I don't think gold was designed with the intent of
> propagating @-style version information into the output binary. We
> only use the version sections, and, as far as I know, the dynamic
> loader only uses version sections.
>
> (2) Gold defines the symbol as a default version, while Gnu ld
> doesn't. If this is the problem, I'll need to understand what the
> proper logic is for determining whether a symbol should be marked as
> the default version.
>
> You said this affects building libgcc_s.so in trunk, but you haven't
> said what is actually failing.
>
> -cary
>
>
> On Tue, Jul 21, 2015 at 4:51 PM, tmsriram at google dot com
> <sourceware-bugzilla@sourceware.org> wrote:
>> https://sourceware.org/bugzilla/show_bug.cgi?id=18703
>>
>> --- Comment #2 from Sriraman Tallam <tmsriram at google dot com> ---
>> On Tue, Jul 21, 2015 at 11:03 AM, ccoutant at gmail dot com
>> <sourceware-bugzilla@sourceware.org> wrote:
>>> https://sourceware.org/bugzilla/show_bug.cgi?id=18703
>>>
>>> --- Comment #1 from Cary Coutant <ccoutant at gmail dot com> ---
>>> You're looking at the linker symbol table with nm. (And nm does not show
>>> versioning information from the .gnu.version* sections.)
>>>
>>> When I build this with gold, readelf -Vs shows:
>>>
>>> Symbol table '.dynsym' contains 13 entries:
>>>    Num:    Value          Size Type    Bind   Vis      Ndx Name
>>>      0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
>>>      1: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
>>>      2: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND
>>> _ITM_deregisterTMCloneTab
>>>      3: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND
>>> __cxa_finalize@GLIBC_2.2.5 (3)
>>>      4: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND
>>> _ITM_registerTMCloneTable
>>>      5: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
>>>      6: 00000000000006f5    11 FUNC    GLOBAL DEFAULT   12 foo@@VERS_1.1
>>>      7: 0000000000002018     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
>>>      8: 0000000000002019     0 NOTYPE  GLOBAL DEFAULT  ABS _end
>>>      9: 00000000000005c0     0 FUNC    GLOBAL DEFAULT   10 _init
>>>     10: 0000000000002018     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
>>>     11: 0000000000000700     0 FUNC    GLOBAL DEFAULT   13 _fini
>>>     12: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  ABS VERS_1.1
>>>
>>> ...
>>>
>>> Version symbols section '.gnu.version' contains 13 entries:
>>>  Addr: 0000000000000458  Offset: 0x000458  Link: 2 (.dynsym)
>>>   000:   0 (*local*)       0 (*local*)       0 (*local*)       3 (GLIBC_2.2.5)
>>>   004:   0 (*local*)       0 (*local*)       2 (VERS_1.1)      1 (*global*)
>>>   008:   1 (*global*)      1 (*global*)      1 (*global*)      1 (*global*)
>>>   00c:   2 (VERS_1.1)
>>>
>>> Version definition section '.gnu.version_d' contains 2 entries:
>>>   Addr: 0x0000000000000474  Offset: 0x000474  Link: 3 (.dynstr)  000000: Rev: 1
>>>  Flags: BASE   Index: 1  Cnt: 1  Name: ver1.so
>>>   0x001c: Rev: 1  Flags: none  Index: 2  Cnt: 1  Name: VERS_1.1
>>>
>>> Version needs section '.gnu.version_r' contains 1 entries:
>>>  Addr: 0x00000000000004ac  Offset: 0x0004ac  Link: 3 (.dynstr)
>>>   000000: Version: 1  File: libc.so.6  Cnt: 1
>>>   0x0010:   Name: GLIBC_2.2.5  Flags: none  Version: 3
>>>
>>> I think this is working as intended, although comparing with Gnu ld output, I
>>> see that gold defines it as a default version ("@@") where Gnu ld does not. I'm
>>> not sure what the logic ought to be for that. Without the __asm__ in the .c
>>> file, Gnu ld also makes it a default version.
>>
>> Some context:
>>
>> https://gcc.gnu.org/ml/gcc-patches/2015-04/msg00878.html
>>
>> This was used to hide symbols __cpu_indicator_init and __cpu_model
>> defined in libgcc_s.so so that this symbol is always obtained from
>> libgcc.a. Now, this works with GNU ld and not with gold.  Isnt this an
>> incompatibility. If this is not well defined, is there another well
>> defined way of achieving the same result?
>>
>> Thanks
>> Sri
>>
>>
>>>
>>> --
>>> You are receiving this mail because:
>>> You reported the bug.
>>
>> --
>> You are receiving this mail because:
>> You are on the CC list for the bug.
>> You are the assignee for the bug.
>
> --
> You are receiving this mail because:
> You reported the bug.
Comment 9 H.J. Lu 2015-07-22 01:06:10 UTC
(In reply to Sriraman Tallam from comment #8)
> 
> From your later comments, it does look like the difference is because
> of the extra "@" added by gold to make it the default symbol.
> 

Linker shouldn't add the extra "@" when being asked not to do so
explicitly.
Comment 10 Cary Coutant 2015-07-22 01:31:15 UTC
>> 0000000000000000 T foo
>> 0000000000000000 T foo@VERS_1.1
>>
>> With the version script, gold sees the first of those (plain "foo")
>> and makes it the default version (as, I think, it should). The second
>> one is just seen as a second declaration, but it's already been marked
>> the default.
>
> foo is versioned and only version specified is VERS_1.1, which is not
> default version.  It is wrong to create a default foo without being asked
> to do so.

In this example, "foo" is both unversioned and versioned. In response
to the unversioned one, gold is creating a default version, as
directed by the linker script. If "foo@VERS_1.1" were the only version
of "foo" in this file, gold would not make it a default version.

If you don't want a default version, get rid of the first,
unversioned, "foo", and gold will do what you expect.

I've played around with a bunch of different combinations, and I can't
even begin to unravel the logic behind Gnu ld's behavior when there
are multiple instances of versioned and unversioned symbols. I have no
desire to try to reproduce its behavior beyond what's described in the
documentation.

-cary
Comment 11 H.J. Lu 2015-07-22 02:13:23 UTC
(In reply to Cary Coutant from comment #10)
> 
> In this example, "foo" is both unversioned and versioned. In response
> to the unversioned one, gold is creating a default version, as
> directed by the linker script. If "foo@VERS_1.1" were the only version
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Linker script only specifies a version of VERS_1.1 and input file
has VERS_1.1 as the non-default version.  Linker shouldn't change
VERS_1.1 from non-default to default.

> of "foo" in this file, gold would not make it a default version.
> 
> If you don't want a default version, get rid of the first,
> unversioned, "foo", and gold will do what you expect.
> 
> I've played around with a bunch of different combinations, and I can't
> even begin to unravel the logic behind Gnu ld's behavior when there
> are multiple instances of versioned and unversioned symbols. I have no
> desire to try to reproduce its behavior beyond what's described in the
> documentation.

The documentation can have some improvements.  But ld.bfd behavior is
well-defined as shown by testcases in ld/testsuite/ld-elfvers.
Comment 12 Cary Coutant 2015-07-22 04:04:32 UTC
> The documentation can have some improvements.  But ld.bfd behavior is
> well-defined as shown by testcases in ld/testsuite/ld-elfvers.

If you're going to maintain that ".symver foo,foo@VER" is valid, then I think the assembler needs to be fixed so that it doesn't assume that the original name and the versioned name don't have the same base. In obj-elf.c, elf_frob_symbol seems to be written with the assumption that they are different. The following patch fixes that so that we don't get the duplicate symbol:

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;

(testsuite/gas/elf/symver.d and testsuite/gas/symver/symver1.d will also need adjusting.)

With that patch to gas, gold now has the same behavior for Sri's test case (and it also passes the vers27d1.c test case in the ld testsuite).

Shall I forward this bug to gas? As long as gas is emitting an unversioned symbol, I'm going to maintain that gold is doing the right thing in assigning it a default version.
Comment 13 H.J. Lu 2015-07-22 04:08:25 UTC
Change assembler may break existing code.  I think gold should
behave the same as ld on this.
Comment 14 H.J. Lu 2015-07-22 11:51:58 UTC
I created users/hjl/gold-test branch and added ld-elfvers/vers-gold.exp
to run ld symbol version tests with gold:

[hjl@gnu-6 ld]$ make check RUNTESTFLAGS="vers-gold.exp"
...
Running /export/gnu/import/git/sources/binutils-gdb/ld/testsuite/ld-elfvers/vers-gold.exp ...
FAIL: vers1
FAIL: vers2
FAIL: vers3
FAIL: vers6
FAIL: vers8
ERROR: tcl error sourcing library file /export/gnu/import/git/sources/binutils-gdb/ld/testsuite/lib/../ld-elfvers/vers.exp.
cp: cannot stat 'tmpdir/vers1.so': No such file or directory
cp: cannot stat 'tmpdir/vers1.so': No such file or directory
    while executing
"exec cp $tmpdir/$srclib $tmpdir/$libname.so"
    (procedure "test_strip_vers_lib" line 11)
    invoked from within
"test_strip_vers_lib "vers14" vers1.so vers14 vers1.ver vers1.dsym"
    (file "/export/gnu/import/git/sources/binutils-gdb/ld/testsuite/lib/../ld-elfvers/vers.exp" line 893)
    invoked from within
"source /export/gnu/import/git/sources/binutils-gdb/ld/testsuite/lib/../ld-elfvers/vers.exp"
    ("uplevel" body line 1)
    invoked from within
"uplevel #0 source /export/gnu/import/git/sources/binutils-gdb/ld/testsuite/lib/../ld-elfvers/vers.exp"
    invoked from within
"catch "uplevel #0 source ${dir}/${initfile}" error"
Makefile:3506: recipe for target 'check-DEJAGNU' failed
make[3]: *** [check-DEJAGNU] Error 1
make[3]: Leaving directory '/export/build/gnu/binutils-gold/build-x86_64-linux/ld'
Makefile:1852: recipe for target 'check-am' failed
make[2]: *** [check-am] Error 2
make[2]: Leaving directory '/export/build/gnu/binutils-gold/build-x86_64-linux/ld'
Makefile:1699: recipe for target 'check-recursive' failed
make[1]: *** [check-recursive] Error 1
make[1]: Leaving directory '/export/build/gnu/binutils-gold/build-x86_64-linux/ld'
Makefile:1854: recipe for target 'check' failed
make: *** [check] Error 2
[hjl@gnu-6 ld]$ 

The first failure is:

/export/build/gnu/binutils-gold/build-x86_64-linux/ld/../gold/ld-new   -o tmpdir/vers1.so --shared --no-undefined-version tmpdir/vers1.o  --version-script /export/gnu/import/git/sources/binutils-gdb/ld/testsuite/ld-elfvers/vers1.map 
Executing on host: sh -c {/export/build/gnu/binutils-gold/build-x86_64-linux/ld/../gold/ld-new   -o tmpdir/vers1.so --shared --no-undefined-version tmpdir/vers1.o  --version-script /export/gnu/import/git/sources/binutils-gdb/ld/testsuite/ld-elfvers/vers1.map  2>&1}  /dev/null ld.tmp (timeout = 300)
spawn [open ...]^M
/export/build/gnu/binutils-gold/build-x86_64-linux/ld/../gold/ld-new: error: symbol show_foo has undefined version 
/export/build/gnu/binutils-gold/build-x86_64-linux/ld/../gold/ld-new: error: symbol show_foo has undefined version 
FAIL: vers1 

I don't think you can expect gold will always generate the working output
when symbol version is used.
Comment 15 Sriraman Tallam 2015-07-22 18:09:50 UTC
On Tue, Jul 21, 2015 at 5:35 PM, ccoutant at gmail dot com
<sourceware-bugzilla@sourceware.org> wrote:
> https://sourceware.org/bugzilla/show_bug.cgi?id=18703
>
> --- Comment #6 from Cary Coutant <ccoutant at gmail dot com> ---
>>    Another usage of the '.symver' directive is:
>>      .symver NAME, NAME2@@NODENAME
>>    In this case, the symbol NAME must exist and be defined within the
>> file being assembled.  It is similar to NAME2@NODENAME.  The difference
>> is NAME2@@NODENAME will also be used to resolve references to NAME2 by
>> the linker.
>>
>> Linker shouldn't use foo@VERS_1.1 to resolve references to foo.
>
> Yes, I understand that much. The example given uses:
>
>    .symver foo, foo@VERS_1.1
>
> where the original symbol and the versioned symbol both have the same
> name. This produces two symbols in the .o file named "foo":
>
> 0000000000000000 T foo
> 0000000000000000 T foo@VERS_1.1
>
> With the version script, gold sees the first of those (plain "foo")
> and makes it the default version (as, I think, it should). The second
> one is just seen as a second declaration, but it's already been marked
> the default.
>
> If I change Sri's example to use ".symver orig_foo, foo@VERS_1.1" and
> rename "foo" to "orig_foo", I get the following in the dynamic symbol
> table:
>
>      6: 0000000000000725    11 FUNC    GLOBAL DEFAULT   12 foo@VERS_1.1
>      7: 0000000000000725    11 FUNC    GLOBAL DEFAULT   12 orig_foo
>
> If it's the "@@" vs. "@" that's causing the problem, then there's your fix.

H.J. :  Can we use Cary's idea to fix libgcc/config/i386/cpuinfo.c to
make libgcc_s.so.1 do the right thing with gold too until this issue
is resolved in some manner?

Thanks
Sri


>
> -cary
>
> --
> You are receiving this mail because:
> You reported the bug.
Comment 16 H.J. Lu 2015-07-22 18:24:46 UTC
(In reply to Sriraman Tallam from comment #15)
>
> H.J. :  Can we use Cary's idea to fix libgcc/config/i386/cpuinfo.c to
> make libgcc_s.so.1 do the right thing with gold too until this issue
> is resolved in some manner?
> 

You can pass -fuse-ld=bfd to build libgcc_s.so.1 on Linux:

diff --git a/libgcc/config/i386/t-linux b/libgcc/config/i386/t-linux
index 11bb46e..12aab16 100644
--- a/libgcc/config/i386/t-linux
+++ b/libgcc/config/i386/t-linux
@@ -3,4 +3,8 @@
 # t-slibgcc-elf-ver and t-linux
 SHLIB_MAPFILES = libgcc-std.ver $(srcdir)/config/i386/libgcc-glibc.ver
 
+# Work around gold bug:
+# https://sourceware.org/bugzilla/show_bug.cgi?id=18703
+SHLIB_LDFLAGS += -fuse-ld=bfd
+
 HOST_LIBGCC2_CFLAGS += -mlong-double-80 -DUSE_ELF_SYMVER

Or you have to make sure those symbols in both libgcc.a and libgcc.so.1
are correct.
Comment 17 Sriraman Tallam 2015-07-22 20:40:44 UTC
On Wed, Jul 22, 2015 at 11:24 AM, hjl.tools at gmail dot com
<sourceware-bugzilla@sourceware.org> wrote:
> https://sourceware.org/bugzilla/show_bug.cgi?id=18703
>
> --- Comment #16 from H.J. Lu <hjl.tools at gmail dot com> ---
> (In reply to Sriraman Tallam from comment #15)
>>
>> H.J. :  Can we use Cary's idea to fix libgcc/config/i386/cpuinfo.c to
>> make libgcc_s.so.1 do the right thing with gold too until this issue
>> is resolved in some manner?
>>
>
> You can pass -fuse-ld=bfd to build libgcc_s.so.1 on Linux:
>
> diff --git a/libgcc/config/i386/t-linux b/libgcc/config/i386/t-linux
> index 11bb46e..12aab16 100644
> --- a/libgcc/config/i386/t-linux
> +++ b/libgcc/config/i386/t-linux
> @@ -3,4 +3,8 @@
>  # t-slibgcc-elf-ver and t-linux
>  SHLIB_MAPFILES = libgcc-std.ver $(srcdir)/config/i386/libgcc-glibc.ver
>
> +# Work around gold bug:
> +# https://sourceware.org/bugzilla/show_bug.cgi?id=18703
> +SHLIB_LDFLAGS += -fuse-ld=bfd
> +
>  HOST_LIBGCC2_CFLAGS += -mlong-double-80 -DUSE_ELF_SYMVER
>
> Or you have to make sure those symbols in both libgcc.a and libgcc.so.1
> are correct.

Thanks this works.  However, i ran into another problem.  Our GCC
build does not use -fvisibility=hidden to build libgcc.a. So,
__cpu_indicator_init is GLOBAL in libgcc.a and not LOCAL.  Which means
any shared object that references __cpu_indicator_init will still
create a PLT entry for it and fail at run-time.

This is not directly related to this bug but thought I would mention
it here while we are fixing this problem.

Thanks
Sri

>
> --
> You are receiving this mail because:
> You reported the bug.
Comment 18 Cary Coutant 2015-07-22 23:39:49 UTC
Another change you can make is to remove "foo" from the version script
entirely. If foo.map is just this:

VERS_1.1 {
};

then both linkers will put "foo@VERS_1.1" into the dynamic symbol
table (no default version).

If you're going to use .symver to set the version, there's really no
point in also using a version script to do the same thing. It just
sets up a conflicting situation where different linkers might give
different behaviors.

-cary
Comment 19 Cary Coutant 2015-07-23 18:28:11 UTC
> FAIL: vers1

This is because gold does not handle "sym@" properly. Working on it.

> FAIL: vers2
> FAIL: vers3
> FAIL: vers6
> FAIL: vers8

These look like the same root problem.

> ERROR: tcl error sourcing library file
> /export/gnu/import/git/sources/binutils-gdb/ld/testsuite/lib/../ld-elfvers/
> vers.exp.
> cp: cannot stat 'tmpdir/vers1.so': No such file or directory
> cp: cannot stat 'tmpdir/vers1.so': No such file or directory
>     while executing
> "exec cp $tmpdir/$srclib $tmpdir/$libname.so"
>     (procedure "test_strip_vers_lib" line 11)
>     invoked from within
> "test_strip_vers_lib "vers14" vers1.so vers14 vers1.ver vers1.dsym"
>     (file
> "/export/gnu/import/git/sources/binutils-gdb/ld/testsuite/lib/../ld-elfvers/
> vers.exp" line 893)
>     invoked from within
> "source
> /export/gnu/import/git/sources/binutils-gdb/ld/testsuite/lib/../ld-elfvers/
> vers.exp"
>     ("uplevel" body line 1)
>     invoked from within
> "uplevel #0 source
> /export/gnu/import/git/sources/binutils-gdb/ld/testsuite/lib/../ld-elfvers/
> vers.exp"
>     invoked from within
> "catch "uplevel #0 source ${dir}/${initfile}" error"
> Makefile:3506: recipe for target 'check-DEJAGNU' failed

Not sure what this is. Looks more like a problem with the dejagnu script?
Comment 20 cvs-commit@gcc.gnu.org 2015-08-19 02:25:34 UTC
The master branch has been updated by Cary Coutant <ccoutant@sourceware.org>:

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

commit b45e00b3ed40589af75b8a36a67905ae265a20f8
Author: Cary Coutant <ccoutant@gmail.com>
Date:   Mon Jul 27 15:09:08 2015 -0700

    Fix symbol versioning problems in PR 18703.
    
    If a symbol is defined with ".symver foo,foo@VER", the assembler
    creates two symbols in the object: one unversioned, and one with
    the (non-default) version "VER". If foo is listed in a version
    script, gold would then make the first of those symbols the
    default version, and would ignore the second symbol as a
    duplicate, without making it a non-default version. While this is
    arguably reasonable behavior, it doesn't match Gnu ld behavior,
    so this patch fixes that by allowing the second definition to
    override the first by resetting the "default version" indication.
    
    Several test cases from the Gnu ld testsuite also exposed another
    related problem, where a symbol defined with ".symver foo,foo@",
    placed into a shared library, is not handled properly by gold.
    This patch also fixes that case, binding the symbol to the base
    version.
    
    gold/
    	PR gold/18703
    	* dynobj.cc (Versions::record_version): Handle symbol defined with
    	base version.
    	(Versions::symbol_section_contents): Likewise.
    	* symtab.h (Symbol::set_is_not_default): New class method.
    	(Symbol_table::resolve): Add is_default_version parameter.
    	(Symbol_table::should_override): Likewise.
    	* resolve.cc (Symbol_table::resolve): Add is_default_version parameter,
    	and pass to should_override. Adjust all callers and explicit
    	instantiations.
    	(Symbol_table::should_override): Add is_default_value parameter;
    	allow default version in a dynamic object to override existing
    	definition from same object.
    	* symtab.cc (Symbol_table::add_from_object): Handle case where same
    	symbol is defined as unversioned and non-default version in the same
    	object.
    	* testsuite/Makefile.am (ver_test_13): New test case.
    	* testsuite/Makefile.in: Regenerate.
    	* testsuite/ver_test_4.cc: Add test for symbol with base version.
    	* testsuite/ver_test_4.sh: Likewise.
    	* testsuite/ver_test_13.c: New source file.
    	* testsuite/ver_test_13.script: New version script.
    	* testsuite/ver_test_13.sh: New test case.
Comment 21 Cary Coutant 2015-08-19 03:11:42 UTC
Fixed on trunk.
Comment 22 cvs-commit@gcc.gnu.org 2015-08-26 00:54:40 UTC
The master branch has been updated by Cary Coutant <ccoutant@sourceware.org>:

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

commit 3ac0a36c297a7bb3325c6efa756cccc40572dbdb
Author: Cary Coutant <ccoutant@gmail.com>
Date:   Tue Aug 25 17:53:53 2015 -0700

    Fix regression introduced by fix for PR 18703.
    
    When a user object overrides a versioned definition in a shared object,
    it's possible to trigger an internal error because the versioned
    definition we saw didn't override the unversioned definition. This
    was introduced by the fix for PR 18703. This patch fixes the problem
    by reordering the tests so that we do not check ret->is_default()
    until we're confident that the symbol is in fact versioned.
    
    gold/
    	PR gold/18866
    	PR gold/18703
    	* symtab.cc (Symbol_table): Reorder conditions to avoid internal error.
Comment 23 Cary Coutant 2015-09-07 16:52:04 UTC
*** Bug 13521 has been marked as a duplicate of this bug. ***