Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -990,6 +990,7 @@ void readVersionDeclaration(StringRef VerStr); void readGlobal(StringRef VerStr); void readLocal(StringRef VerStr); + void readSymbols(std::vector &V); ScriptConfiguration &Opt = *ScriptConfig; bool IsUnderSysroot; @@ -1806,6 +1807,20 @@ expect(";"); } +void ScriptParser::readSymbols(std::vector &V) { + for (;;) { + if (consume("extern")) + readVersionExtern(&V); + + StringRef Cur = peek(); + if (Cur == "}" || Cur == "local:" || Error) + return; + skip(); + V.push_back({unquote(Cur), false, hasWildcard(Cur)}); + expect(";"); + } +} + void ScriptParser::readLocal(StringRef VerStr) { if (consume("*")) { Config->DefaultSymbolVersion = VER_NDX_LOCAL; @@ -1816,15 +1831,10 @@ if (VerStr.empty()) setError("locals list for anonymous version is not supported"); - std::vector &Locals = Config->VersionDefinitions.back().Locals; - while (!Error && peek() != "}") { - StringRef Tok = next(); - Locals.push_back({unquote(Tok), false, hasWildcard(Tok)}); - expect(";"); - } + readSymbols(Config->VersionDefinitions.back().Locals); } -void ScriptParser::readVersionExtern(std::vector *Globals) { +void ScriptParser::readVersionExtern(std::vector *V) { expect("\"C++\""); expect("{"); @@ -1832,7 +1842,7 @@ if (peek() == "}" || Error) break; bool HasWildcard = !peek().startswith("\"") && hasWildcard(peek()); - Globals->push_back({unquote(next()), true, HasWildcard}); + V->push_back({unquote(next()), true, HasWildcard}); expect(";"); } @@ -1841,23 +1851,10 @@ } void ScriptParser::readGlobal(StringRef VerStr) { - std::vector *Globals; if (VerStr.empty()) - Globals = &Config->VersionScriptGlobals; + readSymbols(Config->VersionScriptGlobals); else - Globals = &Config->VersionDefinitions.back().Globals; - - for (;;) { - if (consume("extern")) - readVersionExtern(Globals); - - StringRef Cur = peek(); - if (Cur == "}" || Cur == "local:" || Error) - return; - skip(); - Globals->push_back({unquote(Cur), false, hasWildcard(Cur)}); - expect(";"); - } + readSymbols(Config->VersionDefinitions.back().Globals); } static bool isUnderSysroot(StringRef Path) { Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -699,26 +699,26 @@ // Each version definition has a glob pattern, and all symbols that match // with the pattern get that version. + auto assignVersion = [&](SymbolVersion &Ver, size_t Version, + StringRef VerName) { + if (Ver.HasWildcards) + return; + + if (Ver.IsExternCpp) { + for (SymbolBody *B : findDemangled(Ver.Name)) + setVersionId(B, VerName, Ver.Name, Version); + return; + } + setVersionId(find(Ver.Name), VerName, Ver.Name, Version); + }; + // First, we assign versions to exact matching symbols, // i.e. version definitions not containing any glob meta-characters. for (VersionDefinition &V : Config->VersionDefinitions) { - for (SymbolVersion Ver : V.Globals) { - if (Ver.HasWildcards) - continue; - - StringRef N = Ver.Name; - if (Ver.IsExternCpp) { - for (SymbolBody *B : findDemangled(N)) - setVersionId(B, V.Name, N, V.Id); - continue; - } - setVersionId(find(N), V.Name, N, V.Id); - } - for (SymbolVersion Ver : V.Locals) { - if (Ver.HasWildcards) - continue; - setVersionId(find(Ver.Name), V.Name, Ver.Name, VER_NDX_LOCAL); - } + for (SymbolVersion Sym : V.Globals) + assignVersion(Sym, V.Id, V.Name); + for (SymbolVersion Sym : V.Locals) + assignVersion(Sym, VER_NDX_LOCAL, "'local'"); } // Next, we assign versions to fuzzy matching symbols, Index: test/ELF/version-script-locals-extern.s =================================================================== --- test/ELF/version-script-locals-extern.s +++ test/ELF/version-script-locals-extern.s @@ -0,0 +1,45 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "FOO { local: extern \"C++\" { \"abb(int)\"; }; };" > %t.script +# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so +# RUN: llvm-readobj -V %t.so | FileCheck %s --check-prefix=ABB +# ABB: Symbols [ +# ABB-NEXT: Symbol { +# ABB-NEXT: Version: 0 +# ABB-NEXT: Name: @ +# ABB-NEXT: } +# ABB-NEXT: Symbol { +# ABB-NEXT: Version: 1 +# ABB-NEXT: Name: _Z3abci@ +# ABB-NEXT: } +# ABB-NEXT: ] + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "FOO { local: extern \"C++\" { abb*; }; };" > %t.script +# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so +# RUN: llvm-readobj -V %t.so | FileCheck %s --check-prefix=ABB + +# RUN: echo "FOO { local: extern \"C++\" { abc*; }; };" > %t.script +# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so +# RUN: llvm-readobj -V %t.so | FileCheck %s --check-prefix=ABC +# ABC: Symbols [ +# ABC-NEXT: Symbol { +# ABC-NEXT: Version: 0 +# ABC-NEXT: Name: @ +# ABC-NEXT: } +# ABC-NEXT: Symbol { +# ABC-NEXT: Version: 1 +# ABC-NEXT: Name: _Z3abbi@ +# ABC-NEXT: } +# ABC-NEXT: ] + +.globl _Z3abbi +.type _Z3abbi,@function +_Z3abbi: +retq + +.globl _Z3abci +.type _Z3abci,@function +_Z3abci: +retq Index: test/ELF/version-script-locals.s =================================================================== --- test/ELF/version-script-locals.s +++ test/ELF/version-script-locals.s @@ -28,11 +28,6 @@ # MIX-NOT: foo2 # MIX-NOT: foo3 -# RUN: echo "VERSION_1.0 { global: *; local: extern \"C++\" { foo*; } };" > %t.script -# RUN: not ld.lld --version-script %t.script -shared %t.o -o %t.so 2>&1 \ -# RUN: | FileCheck --check-prefix=EXTERNERR %s -# EXTERNERR: ; expected, but got "C++" - .globl foo1 foo1: ret Index: test/ELF/version-script-noundef.s =================================================================== --- test/ELF/version-script-noundef.s +++ test/ELF/version-script-noundef.s @@ -11,6 +11,11 @@ # RUN: %t.o -o %t.so 2>&1 | FileCheck -check-prefix=ERR2 %s # ERR2: version script assignment of VERSION_1.0 to symbol und failed: symbol not defined +# RUN: echo "VERSION_1.0 { local: und; };" > %t3.script +# RUN: not ld.lld --version-script %t3.script -shared --no-undefined-version \ +# RUN: %t.o -o %t.so 2>&1 | FileCheck -check-prefix=ERR3 %s +# ERR3: version script assignment of 'local' to symbol und failed: symbol not defined + .text .globl foo .type foo,@function