void readVersionDeclaration(StringRef VerStr);
void readGlobal(StringRef VerStr);
void readLocal(StringRef VerStr);
+ void readSymbols(std::vector<SymbolVersion> &V);
ScriptConfiguration &Opt = *ScriptConfig;
bool IsUnderSysroot;
expect(";");
}
+void ScriptParser::readSymbols(std::vector<SymbolVersion> &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;
if (VerStr.empty())
setError("locals list for anonymous version is not supported");
- std::vector<SymbolVersion> &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<SymbolVersion> *Globals) {
+void ScriptParser::readVersionExtern(std::vector<SymbolVersion> *V) {
expect("\"C++\"");
expect("{");
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(";");
}
}
void ScriptParser::readGlobal(StringRef VerStr) {
- std::vector<SymbolVersion> *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) {
StringRef Name, uint16_t Version) {
if (!Body || Body->isUndefined()) {
if (Config->NoUndefinedVersion)
- error("version script assignment of " + VersionName + " to symbol " +
+ error("version script assignment of '" + VersionName + "' to symbol " +
Name + " failed: symbol not defined");
return;
}
// 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,
--- /dev/null
+# 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
# 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
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
# RUN: not ld.lld --version-script %t.script -shared --no-undefined-version \
# RUN: %t.o -o %t.so 2>&1 | FileCheck -check-prefix=ERR1 %s
-# ERR1: version script assignment of VERSION_1.0 to symbol bar failed: symbol not defined
+# ERR1: version script assignment of 'VERSION_1.0' to symbol bar failed: symbol not defined
# RUN: echo "VERSION_1.0 { global: und; };" > %t2.script
# RUN: not ld.lld --version-script %t2.script -shared --no-undefined-version \
# 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
+# 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