Bug 13521 - ld.gold prefers unversioned symbol over default version
Summary: ld.gold prefers unversioned symbol over default version
Status: RESOLVED DUPLICATE of bug 18703
Alias: None
Product: binutils
Classification: Unclassified
Component: gold (show other bugs)
Version: 2.24
: P2 normal
Target Milestone: ---
Assignee: Cary Coutant
URL:
Keywords:
Depends on: 18703
Blocks:
  Show dependency treegraph
 
Reported: 2011-12-20 07:13 UTC by Jonathan Nieder
Modified: 2015-09-07 16:52 UTC (History)
2 users (show)

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


Attachments
simple object with reference to lzma_code before linking (417 bytes, application/x-object)
2011-12-20 07:13 UTC, Jonathan Nieder
Details
DSO with versioned and unversioned lzma_code symbol (Debian liblzma5 5.1.1alpha+20110809-3) (71.19 KB, application/octet-stream)
2011-12-20 07:14 UTC, Jonathan Nieder
Details
output from "ld.gold -o output.gold test.o liblzma.so.5.0.0", which should refer to the versioned symbol but refers to the unversioned symbol instead (867 bytes, application/octet-stream)
2011-12-20 07:17 UTC, Jonathan Nieder
Details
attachment-48859-0.html (744 bytes, text/html)
2015-09-02 18:57 UTC, Jason Gunthorpe
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Jonathan Nieder 2011-12-20 07:13:00 UTC
Created attachment 6119 [details]
simple object with reference to lzma_code before linking

The ld manual (section VERSION) explains how to allow multiple versions of the same function to appear in a given shared library[1].

Debian liblzma5 5.1.1alpha+20110809-3 does that.  It provides two versions of the lzma_code function --- an unversioned compatibility symbol and a versioned symbol:

| $ eu-readelf -s /usr/lib/x86_64-linux-gnu/liblzma.so.5.0.0 | grep lzma_code
|    32: 00000000000030f0    142 FUNC    GLOBAL DEFAULT       13 lzma_code
|    33: 0000000000003020    202 FUNC    GLOBAL DEFAULT       13 lzma_code@@XZ_5.0

When I link to the library using ld.bfd, the versioned symbol is preferred, as I'd expect[2]:

| $ ld.bfd -o test.bfd test.o -llzma
| ld.bfd: warning: cannot find entry symbol _start; defaulting to 0000000000400270
| $ eu-readelf -s test.bfd | grep lzma_code
|     1: 0000000000000000      0 FUNC    GLOBAL DEFAULT    UNDEF lzma_code@XZ_5.0 (2)
|    17: 0000000000000000      0 FUNC    GLOBAL DEFAULT    UNDEF lzma_code@@XZ_5.0

By contrast, ld.gold seems to prefer the unversioned symbol.

| $ ld.gold -o test.gold test.o -llzma
| $ eu-readelf -s test.gold | grep lzma_code
|     1: 0000000000000000      0 FUNC    GLOBAL DEFAULT    UNDEF lzma_code
|     5: 0000000000000000      0 FUNC    GLOBAL DEFAULT    UNDEF lzma_code

Reproducible with binutils 2.22 and with a current snapshot of HEAD (3d38152c, 2011-12-19).  Known problem?  Any hints for tracking it down?

[1] “The second GNU extension is to allow multiple versions of the same function to appear in a given shared library. In this way you can make an incompatible change to an interface without increasing the major version number of the shared library, while still allowing applications linked against the old interface to continue to function.

“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'.”

[2] “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 1 Jonathan Nieder 2011-12-20 07:14:36 UTC
Created attachment 6120 [details]
DSO with versioned and unversioned lzma_code symbol (Debian liblzma5 5.1.1alpha+20110809-3)
Comment 2 Jonathan Nieder 2011-12-20 07:17:03 UTC
Created attachment 6121 [details]
output from "ld.gold -o output.gold test.o liblzma.so.5.0.0", which should refer to the versioned symbol but refers to the unversioned symbol instead
Comment 3 Jonathan Nieder 2012-01-07 23:18:15 UTC
Bug causes spurious references to the wrong version of symbols (namely the unversioned symbol), meaning ld.gold produces output and exits with status 0 but the resulting binaries are actually mislinked. ld.bfd copes fine. Report includes a testcase. What can I do to help move this forward?
Comment 4 Ian Lance Taylor 2012-01-09 01:54:39 UTC
See PR 12261 for a related issue.  I think the problem is more complex than you are describing.  I would be happy to hear otherwise.

Sorry for not mentioning this earlier.
Comment 5 Jason Gunthorpe 2015-09-01 23:13:13 UTC
This is still an active problem. I just hit it when working with libsctp on Ubuntu Vivid:

int main(int argc,const char *argv[])
{
    printf("Here %p\n",&sctp_connectx);
}

$ gcc -fuse-ld=gold t.cc -lsctp
$ readelf -s a.out | grep -i sctp
     7: 0000000000400520     0 FUNC    GLOBAL DEFAULT  UND sctp_connectx
    36: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND sctp_connectx
$ gcc t.cc -lsctp
$ readelf -s a.out | grep -i sctp
     7: 0000000000400560     0 FUNC    GLOBAL DEFAULT  UND sctp_connectx@VERS_3 (3)
    56: 0000000000400560     0 FUNC    GLOBAL DEFAULT  UND sctp_connectx@@VERS_3

The net result is the worst possible scenario - no error, no warning, and the binary subtly doesn't work because it links to the wrong symbol.

Just like fuse and liblzma5, the author exactly followed the ld documentation and expected this stuff to work.

I'm not sure why the behaviour of lds.so is being linked to this bug. It is a good point that a shared library should not depend on this behaviour because it does not work as described in ld.so. This will impact any transition plan to introduce the symbol version. It is reasonable for gold to fail to link such shared libraries.

However that has *NOTHING* to do with linking a new executable against a library that uses that construct. GNU ld is not broken in this area and the expected link result is crystal clear - gold should choose the default symbol marked with @@, not the un-versioned one.

I have no idea how many fringe libraries are out there that followed the GNU documentation and thus can't be linked into a executable when gold is the linker. I think it is probably a good enough number that this warrants being addressed in gold.
Comment 6 Cary Coutant 2015-09-02 00:42:50 UTC
Have you tried this with a gold built from HEAD?

I think that the patches for PR 18703 also fix this bug.
Comment 7 Jason Gunthorpe 2015-09-02 18:57:31 UTC
Created attachment 8572 [details]
attachment-48859-0.html

Hi Cary,

HEAD behaves differently than the version in Vivid, but the result is not
identical to ld.

I tested c74be520ba8ed2d013d43916b923b837294343cc.

$ /tmp/binutils-gdb/build/gold/ld-new --sysroot=/ --build-id --eh-frame-hdr
-m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker
/lib64/ld-linux-x86-64.so.2 -z relro
/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/crt1.o
/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/crti.o
/usr/lib/gcc/x86_64-linux-gnu/4.9/crtbegin.o
-L/usr/lib/gcc/x86_64-linux-gnu/4.9
-L/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu
-L/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../../lib -L/lib/x86_64-linux-gnu
-L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib
-L/usr/lib/gcc/x86_64-linux-gnu/4.9/../../.. t.o -lsctp -v -lgcc
--as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s
--no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.9/crtend.o
/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/crtn.o
GNU gold (GNU Binutils 2.25.51.20150902) 1.11

$ readelf -s a.out | grep -i sctp
Symbol table '.dynsym' contains 8 entries:
     7: 0000000000400550     0 FUNC    GLOBAL DEFAULT  UND
sctp_connectx@VERS_3 (3)
Symbol table '.symtab' contains 40 entries:
    36: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND sctp_connectx

.. and with sytem ld ..
$ readelf -s a.out | grep -i sctp
Symbol table '.dynsym' contains 8 entries:
     7: 0000000000400560     0 FUNC    GLOBAL DEFAULT  UND
sctp_connectx@VERS_3 (3)
Symbol table '.symtab' contains 66 entries:
    56: 0000000000400560     0 FUNC    GLOBAL DEFAULT  UND sctp_connectx@
@VERS_3

Dynamic linking is OK - but the symtab from gold doesn't have any symbol
versions even on glibc symbols, so it is a different thing.

I think this bug can be closed, thanks

Jason
Comment 8 Cary Coutant 2015-09-07 16:50:14 UTC
> Dynamic linking is OK - but the symtab from gold doesn't have any symbol
> versions even on glibc symbols, so it is a different thing.
>
> I think this bug can be closed, thanks

That's correct -- gold does not write symbol versions to the .symtab
symbol table, but it never has, and it shouldn't be necessary.

-cary
Comment 9 Cary Coutant 2015-09-07 16:52:04 UTC
Closing.

*** This bug has been marked as a duplicate of bug 18703 ***