diff options
-rw-r--r-- | lld/ELF/InputFiles.cpp | 22 | ||||
-rw-r--r-- | lld/ELF/Symbols.cpp | 4 | ||||
-rw-r--r-- | lld/test/ELF/undefined-versioned-symbol.s | 74 |
3 files changed, 94 insertions, 6 deletions
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index bd9f25873c8..abe90445b6b 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -651,6 +651,8 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() { VersymIndex = Versym->vs_index; ++Versym; } + bool Hidden = VersymIndex & VERSYM_HIDDEN; + VersymIndex = VersymIndex & ~VERSYM_HIDDEN; StringRef Name = check(Sym.getName(this->StringTable)); if (Sym.isUndefined()) { @@ -658,15 +660,23 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() { continue; } - if (Versym) { - // Ignore local symbols and non-default versions. - if (VersymIndex == VER_NDX_LOCAL || (VersymIndex & VERSYM_HIDDEN)) - continue; - } + // Ignore local symbols. + if (Versym && VersymIndex == VER_NDX_LOCAL) + continue; const Elf_Verdef *V = VersymIndex == VER_NDX_GLOBAL ? nullptr : Verdefs[VersymIndex]; - elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V); + + if (!Hidden) + elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V); + + // Also add the symbol with the versioned name to handle undefined symbols + // with explicit versions. + if (V) { + StringRef VerName = this->StringTable.data() + V->getAux()->vda_name; + Name = Saver.save(Twine(Name) + "@" + VerName); + elf::Symtab<ELFT>::X->addShared(this, Name, Sym, V); + } } } diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index 72bcff4e0f4..f3edafaf4b7 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -202,6 +202,10 @@ void SymbolBody::parseSymbolVersion() { // Truncate the symbol name so that it doesn't include the version string. Name = {S.data(), Pos}; + // If this is an undefined or shared symbol it is not a definition. + if (isUndefined() || isShared()) + return; + // '@@' in a symbol name means the default version. // It is usually the most recent one. bool IsDefault = (Verstr[0] == '@'); diff --git a/lld/test/ELF/undefined-versioned-symbol.s b/lld/test/ELF/undefined-versioned-symbol.s new file mode 100644 index 00000000000..4e0957f2550 --- /dev/null +++ b/lld/test/ELF/undefined-versioned-symbol.s @@ -0,0 +1,74 @@ +// REQUIRES: x86 +// RUN: echo ".data; \ +// RUN: .quad \"basename\"; \ +// RUN: .quad \"basename@FBSD_1.0\"; \ +// RUN: .quad \"basename@FBSD_1.1\" " > %t.s +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %t.s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o +// RUN: echo "FBSD_1.0 { local: *; }; FBSD_1.1 { };" > %t2.ver +// RUN: ld.lld --shared --version-script %t2.ver %t2.o -o %t2.so +// RUN: echo "LIBPKG_1.3 { };" > %t.ver +// RUN: ld.lld --shared %t.o --version-script %t.ver %t2.so -o %t.so +// RUN: llvm-readobj --dyn-symbols -r --expand-relocs %t.so | FileCheck %s + +// Test that each relocation points to the correct version. + +// CHECK: Section ({{.*}}) .rela.dyn { +// CHECK-NEXT: Relocation { +// CHECK-NEXT: Offset: 0x2000 +// CHECK-NEXT: Type: R_X86_64_64 (1) +// CHECK-NEXT: Symbol: basename (1) +// CHECK-NEXT: Addend: 0x0 +// CHECK-NEXT: } +// CHECK-NEXT: Relocation { +// CHECK-NEXT: Offset: 0x2008 +// CHECK-NEXT: Type: R_X86_64_64 (1) +// CHECK-NEXT: Symbol: basename (2) +// CHECK-NEXT: Addend: 0x0 +// CHECK-NEXT: } +// CHECK-NEXT: Relocation { +// CHECK-NEXT: Offset: 0x2010 +// CHECK-NEXT: Type: R_X86_64_64 (1) +// CHECK-NEXT: Symbol: basename (3) +// CHECK-NEXT: Addend: 0x0 +// CHECK-NEXT: } +// CHECK-NEXT: } + + +// CHECK: DynamicSymbols [ +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: +// CHECK-NEXT: Value: +// CHECK-NEXT: Size: +// CHECK-NEXT: Binding: +// CHECK-NEXT: Type: +// CHECK-NEXT: Other: +// CHECK-NEXT: Section: +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: basename@FBSD_1.1 +// CHECK-NEXT: Value: +// CHECK-NEXT: Size: +// CHECK-NEXT: Binding: +// CHECK-NEXT: Type: +// CHECK-NEXT: Other: +// CHECK-NEXT: Section: +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: basename@FBSD_1.0 +// CHECK-NEXT: Value: +// CHECK-NEXT: Size: +// CHECK-NEXT: Binding: +// CHECK-NEXT: Type: +// CHECK-NEXT: Other: +// CHECK-NEXT: Section: +// CHECK-NEXT: } +// CHECK-NEXT: Symbol { +// CHECK-NEXT: Name: basename@FBSD_1.1 + + +.global "basename@FBSD_1.0" +"basename@FBSD_1.0": + +.global "basename@@FBSD_1.1" +"basename@@FBSD_1.1": |