diff options
-rw-r--r-- | lld/ELF/SymbolTable.cpp | 24 | ||||
-rw-r--r-- | lld/ELF/Symbols.cpp | 7 | ||||
-rw-r--r-- | lld/test/ELF/version-script-symver.s | 9 |
3 files changed, 35 insertions, 5 deletions
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index 0b5450b071f..d75b89f1752 100644 --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -712,15 +712,31 @@ void SymbolTable<ELFT>::assignWildcardVersion(SymbolVersion Ver, B->symbol()->VersionId = VersionId; } +static bool isDefaultVersion(SymbolBody *B) { + return B->isInCurrentDSO() && B->getName().find("@@") != StringRef::npos; +} + // This function processes version scripts by updating VersionId // member of symbols. template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() { // Symbol themselves might know their versions because symbols // can contain versions in the form of <name>@<version>. - // Let them parse their names. - if (!Config->VersionDefinitions.empty()) - for (Symbol *Sym : SymVector) - Sym->body()->parseSymbolVersion(); + // Let them parse and update their names to exclude version suffix. + for (Symbol *Sym : SymVector) { + SymbolBody *Body = Sym->body(); + bool IsDefault = isDefaultVersion(Body); + Body->parseSymbolVersion(); + + if (!IsDefault) + continue; + + // <name>@@<version> means the symbol is the default version. If that's the + // case, the symbol is not used only to resolve <name> of version <version> + // but also undefined unversioned symbols with name <name>. + SymbolBody *S = find(Body->getName()); + if (S && S->isUndefined()) + S->copy(Body); + } // Handle edge cases first. handleAnonymousVersion(); diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index e8cd662c69a..148acfb8d1f 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -272,7 +272,12 @@ void SymbolBody::parseSymbolVersion() { } // It is an error if the specified version is not defined. - error(toString(File) + ": symbol " + S + " has undefined version " + Verstr); + // Usually version script is not provided when linking executable, + // but we may still want to override a versioned symbol from DSO, + // so we do not report error in this case. + if (Config->Shared) + error(toString(File) + ": symbol " + S + " has undefined version " + + Verstr); } Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, diff --git a/lld/test/ELF/version-script-symver.s b/lld/test/ELF/version-script-symver.s new file mode 100644 index 00000000000..0a4eddd46ce --- /dev/null +++ b/lld/test/ELF/version-script-symver.s @@ -0,0 +1,9 @@ +# 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 |