Index: ELF/SymbolTable.h =================================================================== --- ELF/SymbolTable.h +++ ELF/SymbolTable.h @@ -87,6 +87,7 @@ void trace(StringRef Name); void wrap(StringRef Name); void alias(StringRef Alias, StringRef Name); + void resolve(StringRef Name, Symbol* Sym); private: std::vector findByVersion(SymbolVersion Ver); Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -184,6 +184,19 @@ memcpy(AliasSym->Body.buffer, Sym->Body.buffer, sizeof(AliasSym->Body)); } +template +void SymbolTable::resolve(StringRef Name, Symbol *Sym) { + SymbolBody *Body = find(Name); + if (!Body) + return; + + if (Body->isUndefined()) + memcpy(Body->symbol()->Body.buffer, Sym->Body.buffer, + sizeof(Body->symbol()->Body)); + else + reportDuplicate(Sym->body(), Sym->body()->File); +} + static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) { if (VA == STV_DEFAULT) return VB; Index: ELF/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -13,6 +13,7 @@ #include "InputSection.h" #include "OutputSections.h" #include "Strings.h" +#include "SymbolTable.h" #include "SyntheticSections.h" #include "Target.h" #include "Writer.h" @@ -220,6 +221,21 @@ return nullptr; } +static void resolve(StringRef Name, Symbol *Sym) { + switch (Config->EKind) { + case ELF32LEKind: + return Symtab::X->resolve(Name, Sym); + case ELF32BEKind: + return Symtab::X->resolve(Name, Sym); + case ELF64LEKind: + return Symtab::X->resolve(Name, Sym); + case ELF64BEKind: + return Symtab::X->resolve(Name, Sym); + default: + llvm_unreachable("unknown Config->EKind"); + } +} + // If a symbol name contains '@', the characters after that is // a symbol version name. This function parses that. void SymbolBody::parseSymbolVersion() { @@ -241,9 +257,13 @@ // '@@' in a symbol name means the default version. // It is usually the most recent one. bool IsDefault = (Verstr[0] == '@'); - if (IsDefault) + if (IsDefault) { Verstr = Verstr.substr(1); + // name@@ver should also be used to resolve references to name. + resolve(Name, this->symbol()); + } + for (VersionDefinition &Ver : Config->VersionDefinitions) { if (Ver.Name != Verstr) continue; Index: test/ELF/version-script-symver-err.s =================================================================== --- test/ELF/version-script-symver-err.s +++ test/ELF/version-script-symver-err.s @@ -0,0 +1,16 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "VERSION { global: *; };" > %t.map +# RUN: not ld.lld %t.o --version-script %t.map -o %t 2>&1 | FileCheck %s +# CHECK: error: duplicate symbol: bar +# CHECK-NEXT: >>> defined in {{.*}}.o +# CHECK-NEXT: >>> defined in {{.*}}.o + +.global _start +.global bar +.symver _start, bar@@VERSION +_start: + jmp bar + +bar: Index: test/ELF/version-script-symver.s =================================================================== --- test/ELF/version-script-symver.s +++ test/ELF/version-script-symver.s @@ -0,0 +1,11 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "VERSION { global: *; };" > %t.map +# RUN: ld.lld %t.o --version-script %t.map -o %t + +.global _start +.global bar +.symver _start, bar@@VERSION +_start: + jmp bar