public:
ScriptParser(StringRef S, bool B) : ScriptParserBase(S), IsUnderSysroot(B) {}
- void run();
+ void readLinkerScript();
+ void readVersionScript();
private:
void addFile(StringRef Path);
Expr readTernary(Expr Cond);
Expr readParenExpr();
+ // For parsing version script.
+ void readExtern(std::vector<SymbolVersion> *Globals);
+ void readVersion(StringRef VerStr);
+ void readGlobal(StringRef VerStr);
+ void readLocal();
+
const static StringMap<Handler> Cmd;
ScriptConfiguration &Opt = *ScriptConfig;
StringSaver Saver = {ScriptConfig->Alloc};
{"SECTIONS", &ScriptParser::readSections},
{";", &ScriptParser::readNothing}};
-void ScriptParser::run() {
+void ScriptParser::readVersionScript() {
+ StringRef Msg = "anonymous version definition is used in "
+ "combination with other version definitions";
+ if (skip("{")) {
+ readVersion("");
+ if (!atEOF())
+ setError(Msg);
+ return;
+ }
+
+ while (!atEOF() && !Error) {
+ StringRef VerStr = next();
+ if (VerStr == "{") {
+ setError(Msg);
+ return;
+ }
+ expect("{");
+ readVersion(VerStr);
+ }
+}
+
+void ScriptParser::readLinkerScript() {
while (!atEOF()) {
StringRef Tok = next();
if (Handler Fn = Cmd.lookup(Tok))
return Ret;
}
+void ScriptParser::readVersion(StringRef VerStr) {
+ // Identifiers start at 2 because 0 and 1 are reserved
+ // for VER_NDX_LOCAL and VER_NDX_GLOBAL constants.
+ size_t VersionId = Config->VersionDefinitions.size() + 2;
+ Config->VersionDefinitions.push_back({VerStr, VersionId});
+
+ if (skip("global:") || peek() != "local:")
+ readGlobal(VerStr);
+ if (skip("local:"))
+ readLocal();
+ expect("}");
+
+ // Each version may have a parent version. For example, "Ver2" defined as
+ // "Ver2 { global: foo; local: *; } Ver1;" has "Ver1" as a parent. This
+ // version hierarchy is, probably against your instinct, purely for human; the
+ // runtime doesn't care about them at all. In LLD, we simply skip the token.
+ if (!VerStr.empty() && peek() != ";")
+ next();
+ expect(";");
+}
+
+void ScriptParser::readLocal() {
+ Config->DefaultSymbolVersion = VER_NDX_LOCAL;
+ expect("*");
+ expect(";");
+}
+
+void ScriptParser::readExtern(std::vector<SymbolVersion> *Globals) {
+ expect("C++");
+ expect("{");
+
+ for (;;) {
+ if (peek() == "}" || Error)
+ break;
+ Globals->push_back({next(), true});
+ expect(";");
+ }
+
+ expect("}");
+ expect(";");
+}
+
+void ScriptParser::readGlobal(StringRef VerStr) {
+ std::vector<SymbolVersion> *Globals;
+ if (VerStr.empty())
+ Globals = &Config->VersionScriptGlobals;
+ else
+ Globals = &Config->VersionDefinitions.back().Globals;
+
+ for (;;) {
+ if (skip("extern"))
+ readExtern(Globals);
+
+ StringRef Cur = peek();
+ if (Cur == "}" || Cur == "local:" || Error)
+ return;
+ next();
+ Globals->push_back({Cur, false});
+ expect(";");
+ }
+}
+
static bool isUnderSysroot(StringRef Path) {
if (Config->Sysroot == "")
return false;
return false;
}
-// Entry point.
void elf::readLinkerScript(MemoryBufferRef MB) {
StringRef Path = MB.getBufferIdentifier();
- ScriptParser(MB.getBuffer(), isUnderSysroot(Path)).run();
+ ScriptParser(MB.getBuffer(), isUnderSysroot(Path)).readLinkerScript();
+}
+
+void elf::readVersionScript(MemoryBufferRef MB) {
+ ScriptParser(MB.getBuffer(), false).readVersionScript();
}
template class elf::LinkerScript<ELF32LE>;
void elf::parseDynamicList(MemoryBufferRef MB) {
DynamicListParser(MB.getBuffer()).run();
}
-
-// Parse the --version-script argument. We currently only accept the following
-// version script syntax:
-//
-// { [ global: symbol1; symbol2; [...]; symbolN; ] local: *; };
-//
-// No wildcards are supported, other than for the local entry. Symbol versioning
-// is also not supported.
-
-namespace {
-class VersionScriptParser final : public ScriptParserBase {
-public:
- VersionScriptParser(StringRef S) : ScriptParserBase(S) {}
-
- void run();
-
-private:
- void parseExtern(std::vector<SymbolVersion> *Globals);
- void parseVersion(StringRef VerStr);
- void parseGlobal(StringRef VerStr);
- void parseLocal();
-};
-} // end anonymous namespace
-
-void VersionScriptParser::parseVersion(StringRef VerStr) {
- // Identifiers start at 2 because 0 and 1 are reserved
- // for VER_NDX_LOCAL and VER_NDX_GLOBAL constants.
- size_t VersionId = Config->VersionDefinitions.size() + 2;
- Config->VersionDefinitions.push_back({VerStr, VersionId});
-
- if (skip("global:") || peek() != "local:")
- parseGlobal(VerStr);
- if (skip("local:"))
- parseLocal();
- expect("}");
-
- // Each version may have a parent version. For example, "Ver2" defined as
- // "Ver2 { global: foo; local: *; } Ver1;" has "Ver1" as a parent. This
- // version hierarchy is, probably against your instinct, purely for human; the
- // runtime doesn't care about them at all. In LLD, we simply skip the token.
- if (!VerStr.empty() && peek() != ";")
- next();
- expect(";");
-}
-
-void VersionScriptParser::parseLocal() {
- Config->DefaultSymbolVersion = VER_NDX_LOCAL;
- expect("*");
- expect(";");
-}
-
-void VersionScriptParser::parseExtern(std::vector<SymbolVersion> *Globals) {
- expect("C++");
- expect("{");
-
- for (;;) {
- if (peek() == "}" || Error)
- break;
- Globals->push_back({next(), true});
- expect(";");
- }
-
- expect("}");
- expect(";");
-}
-
-void VersionScriptParser::parseGlobal(StringRef VerStr) {
- std::vector<SymbolVersion> *Globals;
- if (VerStr.empty())
- Globals = &Config->VersionScriptGlobals;
- else
- Globals = &Config->VersionDefinitions.back().Globals;
-
- for (;;) {
- if (skip("extern"))
- parseExtern(Globals);
-
- StringRef Cur = peek();
- if (Cur == "}" || Cur == "local:" || Error)
- return;
- next();
- Globals->push_back({Cur, false});
- expect(";");
- }
-}
-
-void VersionScriptParser::run() {
- StringRef Msg = "anonymous version definition is used in "
- "combination with other version definitions";
- if (skip("{")) {
- parseVersion("");
- if (!atEOF())
- setError(Msg);
- return;
- }
-
- while (!atEOF() && !Error) {
- StringRef VerStr = next();
- if (VerStr == "{") {
- setError(Msg);
- return;
- }
- expect("{");
- parseVersion(VerStr);
- }
-}
-
-void elf::parseVersionScript(MemoryBufferRef MB) {
- VersionScriptParser(MB.getBuffer()).run();
-}