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; @@ -701,9 +714,10 @@ // Symbol themselves might know their versions because symbols // can contain versions in the form of @. // Let them parse their names. - if (!Config->VersionDefinitions.empty()) - for (Symbol *Sym : SymVector) - Sym->body()->parseSymbolVersion(); + // @@ will also be used to resolve references to . + for (Symbol *Sym : SymVector) + if (Sym->body()->parseSymbolVersion()) + resolve(Sym->body()->getName(), Sym); // Handle edge cases first. handleAnonymousVersion(); Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -70,7 +70,7 @@ bool isPreemptible() const; StringRef getName() const { return Name; } uint8_t getVisibility() const { return StOther & 0x3; } - void parseSymbolVersion(); + bool parseSymbolVersion(); bool isInGot() const { return GotIndex != -1U; } bool isInPlt() const { return PltIndex != -1U; } Index: ELF/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -222,21 +222,22 @@ // If a symbol name contains '@', the characters after that is // a symbol version name. This function parses that. -void SymbolBody::parseSymbolVersion() { +// Returns true if symbol version is default. +bool SymbolBody::parseSymbolVersion() { StringRef S = getName(); size_t Pos = S.find('@'); if (Pos == 0 || Pos == StringRef::npos) - return; + return false; StringRef Verstr = S.substr(Pos + 1); if (Verstr.empty()) - return; + return false; // Truncate the symbol name so that it doesn't include the version string. Name = {S.data(), Pos}; // If this is not in this DSO, it is not a definition. if (!isInCurrentDSO()) - return; + return false; // '@@' in a symbol name means the default version. // It is usually the most recent one. @@ -252,11 +253,14 @@ symbol()->VersionId = Ver.Id; else symbol()->VersionId = Ver.Id | VERSYM_HIDDEN; - return; + return IsDefault; } // It is an error if the specified version is not defined. - error(toString(File) + ": symbol " + S + " has undefined version " + Verstr); + if (Config->Shared) + error(toString(File) + ": symbol " + S + " has undefined version " + + Verstr); + return IsDefault; } Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, 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,15 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: not ld.lld %t.o -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,10 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t + +.global _start +.global bar +.symver _start, bar@@VERSION +_start: + jmp bar