Index: lld/trunk/ELF/LinkerScript.h =================================================================== --- lld/trunk/ELF/LinkerScript.h +++ lld/trunk/ELF/LinkerScript.h @@ -19,6 +19,8 @@ namespace lld { namespace elf { +bool matchStr(StringRef S, StringRef T); + // Parses a linker script. Calling this function updates // Config and ScriptConfig. void readLinkerScript(MemoryBufferRef MB); Index: lld/trunk/ELF/LinkerScript.cpp =================================================================== --- lld/trunk/ELF/LinkerScript.cpp +++ lld/trunk/ELF/LinkerScript.cpp @@ -35,8 +35,6 @@ ScriptConfiguration *elf::ScriptConfig; -static bool matchStr(StringRef S, StringRef T); - // This is an operator-precedence parser to parse and evaluate // a linker script expression. For each linker script arithmetic // expression (e.g. ". = . + 0x1000"), a new instance of ExprParser @@ -291,7 +289,7 @@ // Returns true if S matches T. S can contain glob meta-characters. // The asterisk ('*') matches zero or more characters, and the question // mark ('?') matches one character. -static bool matchStr(StringRef S, StringRef T) { +bool elf::matchStr(StringRef S, StringRef T) { for (;;) { if (S.empty()) return T.empty(); Index: lld/trunk/ELF/SymbolTable.h =================================================================== --- lld/trunk/ELF/SymbolTable.h +++ lld/trunk/ELF/SymbolTable.h @@ -88,6 +88,7 @@ void wrap(StringRef Name); private: + std::vector findAll(StringRef Pattern); std::pair insert(StringRef Name); std::pair insert(StringRef Name, uint8_t Type, uint8_t Visibility, bool CanOmitFromDynSym, Index: lld/trunk/ELF/SymbolTable.cpp =================================================================== --- lld/trunk/ELF/SymbolTable.cpp +++ lld/trunk/ELF/SymbolTable.cpp @@ -17,6 +17,7 @@ #include "SymbolTable.h" #include "Config.h" #include "Error.h" +#include "LinkerScript.h" #include "Symbols.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/Support/StringSaver.h" @@ -457,6 +458,21 @@ } template +std::vector SymbolTable::findAll(StringRef Pattern) { + // Fast-path. Fallback to find() if Pattern doesn't contain any wildcard + // characters. + bool HasWildcards = (Pattern.find_first_of("?*") != StringRef::npos); + if (!HasWildcards) + return {find(Pattern)}; + + std::vector Result; + for (auto &It : Symtab) + if (matchStr(Pattern, It.first.Val)) + Result.push_back(SymVector[It.second]->body()); + return Result; +} + +template void SymbolTable::addLazyArchive( ArchiveFile *F, const llvm::object::Archive::Symbol Sym) { Symbol *S; @@ -556,18 +572,19 @@ size_t I = 2; for (Version &V : Config->SymbolVersions) { for (StringRef Name : V.Globals) { - SymbolBody *B = find(Name); - if (!B || B->isUndefined()) { - if (Config->NoUndefinedVersion) - error("version script assignment of " + V.Name + " to symbol " + - Name + " failed: symbol not defined"); - continue; + for (SymbolBody *B : findAll(Name)) { + if (!B || B->isUndefined()) { + if (Config->NoUndefinedVersion) + error("version script assignment of " + V.Name + " to symbol " + + Name + " failed: symbol not defined"); + continue; + } + + if (B->symbol()->VersionId != VER_NDX_GLOBAL && + B->symbol()->VersionId != VER_NDX_LOCAL) + warning("duplicate symbol " + Name + " in version script"); + B->symbol()->VersionId = I; } - - if (B->symbol()->VersionId != VER_NDX_GLOBAL && - B->symbol()->VersionId != VER_NDX_LOCAL) - warning("duplicate symbol " + Name + " in version script"); - B->symbol()->VersionId = I; } ++I; } Index: lld/trunk/test/ELF/version-wildcard.test =================================================================== --- lld/trunk/test/ELF/version-wildcard.test +++ lld/trunk/test/ELF/version-wildcard.test @@ -0,0 +1,65 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "VERSION_1.0{ \ +# RUN: global: foo*; \ +# RUN: local: *; };" > %t.script +# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so +# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s + +# CHECK: DynamicSymbols [ +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: @ +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Local +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Undefined +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: foo1@@VERSION_1.0 +# CHECK-NEXT: Value: 0x1000 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .text +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: foo2@@VERSION_1.0 +# CHECK-NEXT: Value: 0x1001 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .text +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: foo3@@VERSION_1.0 +# CHECK-NEXT: Value: 0x1007 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: .text +# CHECK-NEXT: } +# CHECK-NEXT: ] + +.globl foo1 +foo1: + ret + +.globl foo2 +foo2: + call foo1@PLT + ret + +.globl foo3 +foo3: + call foo2@PLT + ret + +.globl _start +_start: + ret