Index: lld/trunk/ELF/SymbolTable.cpp =================================================================== --- lld/trunk/ELF/SymbolTable.cpp +++ lld/trunk/ELF/SymbolTable.cpp @@ -460,15 +460,6 @@ // Returns a list of defined symbols that match with a given glob pattern. template std::vector SymbolTable::findAll(StringRef Pattern) { - // Fast-path. Fallback to find() if Pattern doesn't contain any wildcard - // characters. - if (Pattern.find_first_of("?*") == StringRef::npos) { - if (SymbolBody *B = find(Pattern)) - if (!B->isUndefined()) - return {B}; - return {}; - } - std::vector Res; for (auto &It : Symtab) { StringRef Name = It.first.Val; @@ -561,6 +552,10 @@ B->symbol()->ExportDynamic = true; } +static bool hasWildcard(StringRef S) { + return S.find_first_of("?*") != StringRef::npos; +} + // This function processes the --version-script option by marking all global // symbols with the VersionScriptGlobal flag, which acts as a filter on the // dynamic symbol table. @@ -574,27 +569,48 @@ return; } + if (Config->SymbolVersions.empty()) + return; + // If we have symbols version declarations, we should // assign version references for each symbol. - size_t I = 2; - for (Version &V : Config->SymbolVersions) { + // Current rules are: + // * If there is an exact match for the mangled name, we use it. + // * Otherwise, we look through the wildcard patterns. We look through the + // version tags in reverse order. We use the first match we find (the last + // matching version tag in the file). + for (size_t I = 0, E = Config->SymbolVersions.size(); I < E; ++I) { + Version &V = Config->SymbolVersions[I]; for (StringRef Name : V.Globals) { - std::vector Syms = findAll(Name); - if (Syms.empty()) { + if (hasWildcard(Name)) + continue; + + 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 : Syms) { - 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 + 2; + } + } + + for (size_t I = Config->SymbolVersions.size() - 1; I != (size_t)-1; --I) { + Version &V = Config->SymbolVersions[I]; + for (StringRef Name : V.Globals) { + if (!hasWildcard(Name)) + continue; + + for (SymbolBody *B : findAll(Name)) + if (B->symbol()->VersionId == VER_NDX_GLOBAL || + B->symbol()->VersionId == VER_NDX_LOCAL) + B->symbol()->VersionId = I + 2; } - ++I; } } Index: lld/trunk/test/ELF/version-wildcard.test =================================================================== --- lld/trunk/test/ELF/version-wildcard.test +++ lld/trunk/test/ELF/version-wildcard.test @@ -46,6 +46,55 @@ # CHECK-NEXT: } # CHECK-NEXT: ] +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "VERSION_1.0{ \ +# RUN: global: foo2; \ +# RUN: local: *; }; \ +# RUN: VERSION_2.0{ \ +# RUN: global: foo*; \ +# RUN: }; " > %t2.script +# RUN: ld.lld --version-script %t2.script -shared %t.o -o %t2.so +# RUN: llvm-readobj -dyn-symbols %t2.so | FileCheck --check-prefix=MIX %s + +# MIX: DynamicSymbols [ +# MIX-NEXT: Symbol { +# MIX-NEXT: Name: @ +# MIX-NEXT: Value: 0x0 +# MIX-NEXT: Size: 0 +# MIX-NEXT: Binding: Local +# MIX-NEXT: Type: None +# MIX-NEXT: Other: 0 +# MIX-NEXT: Section: Undefined +# MIX-NEXT: } +# MIX-NEXT: Symbol { +# MIX-NEXT: Name: foo1@@VERSION_2.0 +# MIX-NEXT: Value: 0x1000 +# MIX-NEXT: Size: 0 +# MIX-NEXT: Binding: Global +# MIX-NEXT: Type: None +# MIX-NEXT: Other: 0 +# MIX-NEXT: Section: .text +# MIX-NEXT: } +# MIX-NEXT: Symbol { +# MIX-NEXT: Name: foo2@@VERSION_1.0 +# MIX-NEXT: Value: 0x1001 +# MIX-NEXT: Size: 0 +# MIX-NEXT: Binding: Global +# MIX-NEXT: Type: None +# MIX-NEXT: Other: 0 +# MIX-NEXT: Section: .text +# MIX-NEXT: } +# MIX-NEXT: Symbol { +# MIX-NEXT: Name: foo3@@VERSION_2.0 +# MIX-NEXT: Value: 0x1007 +# MIX-NEXT: Size: 0 +# MIX-NEXT: Binding: Global +# MIX-NEXT: Type: None +# MIX-NEXT: Other: 0 +# MIX-NEXT: Section: .text +# MIX-NEXT: } +# MIX-NEXT: ] + .globl foo1 foo1: ret