Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -1796,14 +1796,19 @@ setError("locals list for anonymous version is not supported"); std::vector &Locals = Config->VersionDefinitions.back().Locals; - while (!Error && peek() != "}") { + for (;;) { + if (consume("extern")) + readExtern(&Locals); + StringRef Cur = peek(); + if (Cur == "}" || Error) + return; StringRef Tok = next(); Locals.push_back({unquote(Tok), false, hasWildcard(Tok)}); expect(";"); } } -void ScriptParser::readExtern(std::vector *Globals) { +void ScriptParser::readExtern(std::vector *V) { expect("\"C++\""); expect("{"); @@ -1811,7 +1816,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(";"); } Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -608,10 +608,14 @@ } static bool hasExternCpp() { - for (VersionDefinition &V : Config->VersionDefinitions) + for (VersionDefinition &V : Config->VersionDefinitions) { for (SymbolVersion Sym : V.Globals) if (Sym.IsExternCpp) return true; + for (SymbolVersion Sym : V.Locals) + if (Sym.IsExternCpp) + return true; + } return false; } @@ -685,26 +689,25 @@ if (hasExternCpp()) Demangled = getDemangledSyms(); + auto assignVersion = [&](SymbolVersion &Sym, size_t Version, + StringRef VerName) { + if (Sym.HasWildcards) + return; + if (Sym.IsExternCpp) { + for (SymbolBody *B : findDemangled(Demangled, Sym.Name)) + setVersionId(B, VerName, Sym.Name, Version); + return; + } + setVersionId(find(Sym.Name), VerName, Sym.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 Sym : V.Globals) { - if (Sym.HasWildcards) - continue; - - StringRef N = Sym.Name; - if (Sym.IsExternCpp) { - for (SymbolBody *B : findDemangled(Demangled, N)) - setVersionId(B, V.Name, N, V.Id); - continue; - } - setVersionId(find(N), V.Name, N, V.Id); - } - for (SymbolVersion Sym : V.Locals) { - if (Sym.HasWildcards) - continue; - setVersionId(find(Sym.Name), V.Name, Sym.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