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.”
Created attachment 6120 [details] DSO with versioned and unversioned lzma_code symbol (Debian liblzma5 5.1.1alpha+20110809-3)
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
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?
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.
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.
Have you tried this with a gold built from HEAD? I think that the patches for PR 18703 also fix this bug.
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
> 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
Closing. *** This bug has been marked as a duplicate of bug 18703 ***