Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -721,9 +721,19 @@ // 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(); + // Below we resolve references to symbols that have default version. We use + // additional temp vector because addRegular() call may change SymVector. + std::vector DefaultV; + for (Symbol *Sym : SymVector) + if (Sym->body()->parseSymbolVersion()) + DefaultV.push_back(cast(Sym->body())); + + // @@ means symbol has 'default' version. We should use it to + // resolve references to . + for (DefinedRegular *D : DefaultV) + if (find(D->getName())) + addRegular(D->getName(), D->StOther, D->Type, D->Value, D->Size, + D->symbol()->Binding, D->Section, D->File); // 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,21 @@ // If a symbol name contains '@', the characters after that is // a symbol version name. This function parses that. -void SymbolBody::parseSymbolVersion() { +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 +252,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 at {{.*}}.o +# CHECK-NEXT: >>> defined at {{.*}}.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