Index: lld/ELF/Config.h =================================================================== --- lld/ELF/Config.h +++ lld/ELF/Config.h @@ -59,11 +59,10 @@ // This struct contains symbols version definition that // can be found in version script if it is used for link. struct VersionDefinition { - VersionDefinition(llvm::StringRef Name, uint16_t Id) : Name(Name), Id(Id) {} llvm::StringRef Name; - uint16_t Id; + uint16_t Id = 0; std::vector Globals; - size_t NameOff; // Offset in string table. + size_t NameOff = 0; // Offset in the string table }; // This struct contains the global configuration for the linker. Index: lld/ELF/LinkerScript.cpp =================================================================== --- lld/ELF/LinkerScript.cpp +++ lld/ELF/LinkerScript.cpp @@ -1073,8 +1073,9 @@ std::vector readVersionExtern(); void readAnonymousDeclaration(); void readVersionDeclaration(StringRef VerStr); - std::vector readSymbols(); - void readLocals(); + + std::pair, std::vector> + readSymbols(); ScriptConfiguration &Opt = *ScriptConfig; bool IsUnderSysroot; @@ -1936,50 +1937,47 @@ return Ret; } -// Reads a list of symbols, e.g. "{ global: foo; bar; local: *; };". +// Reads an anonymous version declaration. void ScriptParser::readAnonymousDeclaration() { - // Read global symbols first. "global:" is default, so if there's - // no label, we assume global symbols. - if (peek() != "local") { - if (consume("global")) - expect(":"); - for (SymbolVersion V : readSymbols()) - Config->VersionScriptGlobals.push_back(V); - } - readLocals(); - expect("}"); - expect(";"); -} + std::vector Globals; + std::vector Locals; + std::tie(Globals, Locals) = readSymbols(); -void ScriptParser::readLocals() { - if (!consume("local")) - return; - expect(":"); - std::vector Locals = readSymbols(); + for (SymbolVersion V : Globals) + Config->VersionScriptGlobals.push_back(V); for (SymbolVersion V : Locals) { - if (V.Name == "*") { + if (V.Name == "*") Config->DefaultSymbolVersion = VER_NDX_LOCAL; - continue; - } - Config->VersionScriptLocals.push_back(V); + else + Config->VersionScriptLocals.push_back(V); } + expect(";"); } -// Reads a list of symbols, e.g. "VerStr { global: foo; bar; local: *; };". +// Reads a non-anonymous version definition, +// e.g. "VerStr { global: foo; bar; local: *; };". void ScriptParser::readVersionDeclaration(StringRef VerStr) { - // Identifiers start at 2 because 0 and 1 are reserved - // for VER_NDX_LOCAL and VER_NDX_GLOBAL constants. - uint16_t VersionId = Config->VersionDefinitions.size() + 2; - Config->VersionDefinitions.push_back({VerStr, VersionId}); - - // Read global symbols. - if (peek() != "local") { - if (consume("global")) - expect(":"); - Config->VersionDefinitions.back().Globals = readSymbols(); - } - readLocals(); - expect("}"); + // Read a symbol list. + std::vector Globals; + std::vector Locals; + std::tie(Globals, Locals) = readSymbols(); + + for (SymbolVersion V : Locals) { + if (V.Name == "*") + Config->DefaultSymbolVersion = VER_NDX_LOCAL; + else + Config->VersionScriptLocals.push_back(V); + } + + // Create a new version definition and add that to the global symbols. + VersionDefinition Ver; + Ver.Name = VerStr; + Ver.Globals = Globals; + + // User-defined version number starts from 2 because 0 and 1 are + // reserved for VER_NDX_LOCAL and VER_NDX_GLOBAL, respectively. + Ver.Id = Config->VersionDefinitions.size() + 2; + Config->VersionDefinitions.push_back(Ver); // Each version may have a parent version. For example, "Ver2" // defined as "Ver2 { global: foo; local: *; } Ver1;" has "Ver1" @@ -1991,23 +1989,35 @@ expect(";"); } -// Reads a list of symbols for a versions cript. -std::vector ScriptParser::readSymbols() { - std::vector Ret; - for (;;) { - if (consume("extern")) { - for (SymbolVersion V : readVersionExtern()) - Ret.push_back(V); +// Reads a list of symbols, e.g. "{ global: foo; bar; local: *; };". +std::pair, std::vector> +ScriptParser::readSymbols() { + std::vector Globals; + std::vector Locals; + std::vector *V = &Globals; + + while (!Error) { + if (consume("}")) + break; + if (consumeLabel("global")) { + V = &Globals; + continue; + } + if (consumeLabel("local")) { + V = &Locals; continue; } - if (peek() == "}" || (peek() == "local" && peek(1) == ":") || Error) - break; - StringRef Tok = next(); - Ret.push_back({unquote(Tok), false, hasWildcard(Tok)}); + if (consume("extern")) { + std::vector Ext = readVersionExtern(); + V->insert(V->end(), Ext.begin(), Ext.end()); + } else { + StringRef Tok = next(); + V->push_back({unquote(Tok), false, hasWildcard(Tok)}); + } expect(";"); } - return Ret; + return {Globals, Locals}; } // Reads an "extern C++" directive, e.g., @@ -2028,7 +2038,6 @@ } expect("}"); - expect(";"); return Ret; } Index: lld/ELF/ScriptLexer.h =================================================================== --- lld/ELF/ScriptLexer.h +++ lld/ELF/ScriptLexer.h @@ -28,10 +28,11 @@ static StringRef skipSpace(StringRef S); bool atEOF(); StringRef next(); - StringRef peek(unsigned N = 0); + StringRef peek(); void skip(); - bool consume(StringRef Tok); + bool consume(const Twine &Tok); void expect(StringRef Expect); + bool consumeLabel(StringRef Tok); std::string getCurrentLocation(); std::vector MBs; Index: lld/ELF/ScriptLexer.cpp =================================================================== --- lld/ELF/ScriptLexer.cpp +++ lld/ELF/ScriptLexer.cpp @@ -124,7 +124,7 @@ // so that you can write "file-name.cpp" as one bare token, for example. size_t Pos = S.find_first_not_of( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - "0123456789_.$/\\~=+[]*?-!<>^"); + "0123456789_.$/\\~=+[]*?-!<>^:"); // A character that cannot start a word (which is usually a // punctuation) forms a single character token. @@ -169,7 +169,7 @@ // Split a given string as an expression. // This function returns "3", "*" and "5" for "3*5" for example. static std::vector tokenizeExpr(StringRef S) { - StringRef Ops = "+-*/"; // List of operators + StringRef Ops = "+-*/:"; // List of operators // Quoted strings are literal strings, so we don't want to split it. if (S.startswith("\"")) @@ -229,25 +229,34 @@ return Tokens[Pos++]; } -StringRef ScriptLexer::peek(unsigned N) { - StringRef Tok; - for (unsigned I = 0; I <= N; ++I) { - Tok = next(); - if (Error) - return ""; - } - Pos = Pos - N - 1; +StringRef ScriptLexer::peek() { + StringRef Tok = next(); + if (Error) + return ""; + Pos = Pos - 1; return Tok; } -bool ScriptLexer::consume(StringRef Tok) { - if (peek() == Tok) { +bool ScriptLexer::consume(const Twine &Tok) { + if (peek() == Tok.str()) { skip(); return true; } return false; } +// Consumes Tok followed by ":". Space is allowed between Tok and ":". +bool ScriptLexer::consumeLabel(StringRef Tok) { + if (consume(Tok + ":")) + return true; + if (Tokens.size() >= Pos + 2 && Tokens[Pos] == Tok && + Tokens[Pos + 1] == ":") { + Pos += 2; + return true; + } + return false; +} + void ScriptLexer::skip() { (void)next(); } void ScriptLexer::expect(StringRef Expect) { Index: lld/test/ELF/version-script-extern-wildcards-anon.s =================================================================== --- lld/test/ELF/version-script-extern-wildcards-anon.s +++ lld/test/ELF/version-script-extern-wildcards-anon.s @@ -7,6 +7,7 @@ # RUN: extern "C++" { \ # RUN: "foo(int)"; \ # RUN: z*; \ +# RUN: std::q*; \ # RUN: }; \ # RUN: local: *; \ # RUN: }; ' > %t.script @@ -50,6 +51,15 @@ # CHECK-NEXT: Other: # CHECK-NEXT: Section: # CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: _ZSt3qux +# CHECK-NEXT: Value: +# CHECK-NEXT: Size: +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: +# CHECK-NEXT: Other: +# CHECK-NEXT: Section: +# CHECK-NEXT: } # CHECK-NEXT: ] .global _Z3fooi @@ -60,3 +70,5 @@ _Z3zedi: .global _Z3bazi _Z3bazi: +.global _ZSt3qux +_ZSt3qux: