diff options
| author | Rui Ueyama <ruiu@google.com> | 2017-03-09 19:23:00 +0000 |
|---|---|---|
| committer | Rui Ueyama <ruiu@google.com> | 2017-03-09 19:23:00 +0000 |
| commit | f5fce486797d49b82660fef841b57d49c007dab1 (patch) | |
| tree | 0276436a6638320e31093b02477bee82cedd8368 | |
| parent | fe267a37f49a0614e2710be91468942a75102313 (diff) | |
| download | bcm5719-llvm-f5fce486797d49b82660fef841b57d49c007dab1.tar.gz bcm5719-llvm-f5fce486797d49b82660fef841b57d49c007dab1.zip | |
Handle ":" as a regular token character in linker scripts.
This is an alternative to https://reviews.llvm.org/D30500 to simplify the
version definition parser and allow ":" in symbol names.
Differential Revision: https://reviews.llvm.org/D30722
llvm-svn: 297402
| -rw-r--r-- | lld/ELF/Config.h | 5 | ||||
| -rw-r--r-- | lld/ELF/LinkerScript.cpp | 113 | ||||
| -rw-r--r-- | lld/ELF/ScriptLexer.cpp | 29 | ||||
| -rw-r--r-- | lld/ELF/ScriptLexer.h | 3 | ||||
| -rw-r--r-- | lld/test/ELF/version-script-extern-wildcards-anon.s | 12 |
5 files changed, 97 insertions, 65 deletions
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index ef184d508d2..c176946c841 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -59,11 +59,10 @@ struct SymbolVersion { // 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<SymbolVersion> 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. diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 0e60c2769ed..b4f6f1fe0eb 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -1055,8 +1055,9 @@ private: std::vector<SymbolVersion> readVersionExtern(); void readAnonymousDeclaration(); void readVersionDeclaration(StringRef VerStr); - std::vector<SymbolVersion> readSymbols(); - void readLocals(); + + std::pair<std::vector<SymbolVersion>, std::vector<SymbolVersion>> + readSymbols(); ScriptConfiguration &Opt = *ScriptConfig; bool IsUnderSysroot; @@ -1918,50 +1919,49 @@ unsigned ScriptParser::readPhdrType() { 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<SymbolVersion> Locals; + std::vector<SymbolVersion> Globals; + std::tie(Locals, Globals) = readSymbols(); -void ScriptParser::readLocals() { - if (!consume("local")) - return; - expect(":"); - std::vector<SymbolVersion> Locals = readSymbols(); 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); } + + for (SymbolVersion V : Globals) + Config->VersionScriptGlobals.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<SymbolVersion> Locals; + std::vector<SymbolVersion> Globals; + std::tie(Locals, Globals) = 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" @@ -1973,23 +1973,35 @@ void ScriptParser::readVersionDeclaration(StringRef VerStr) { expect(";"); } -// Reads a list of symbols for a versions cript. -std::vector<SymbolVersion> ScriptParser::readSymbols() { - std::vector<SymbolVersion> 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<SymbolVersion>, std::vector<SymbolVersion>> +ScriptParser::readSymbols() { + std::vector<SymbolVersion> Locals; + std::vector<SymbolVersion> Globals; + std::vector<SymbolVersion> *V = &Globals; + + while (!Error) { + if (consume("}")) + break; + if (consumeLabel("local")) { + V = &Locals; + continue; + } + if (consumeLabel("global")) { + V = &Globals; 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<SymbolVersion> 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 {Locals, Globals}; } // Reads an "extern C++" directive, e.g., @@ -2010,7 +2022,6 @@ std::vector<SymbolVersion> ScriptParser::readVersionExtern() { } expect("}"); - expect(";"); return Ret; } diff --git a/lld/ELF/ScriptLexer.cpp b/lld/ELF/ScriptLexer.cpp index fa77df59583..86720de3527 100644 --- a/lld/ELF/ScriptLexer.cpp +++ b/lld/ELF/ScriptLexer.cpp @@ -124,7 +124,7 @@ void ScriptLexer::tokenize(MemoryBufferRef MB) { // 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 @@ bool ScriptLexer::atEOF() { return Error || Tokens.size() == Pos; } // Split a given string as an expression. // This function returns "3", "*" and "5" for "3*5" for example. static std::vector<StringRef> 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,14 +229,11 @@ StringRef ScriptLexer::next() { 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; } @@ -248,6 +245,18 @@ bool ScriptLexer::consume(StringRef Tok) { return false; } +// Consumes Tok followed by ":". Space is allowed between Tok and ":". +bool ScriptLexer::consumeLabel(StringRef Tok) { + if (consume((Tok + ":").str())) + 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) { diff --git a/lld/ELF/ScriptLexer.h b/lld/ELF/ScriptLexer.h index 14f61d6f251..64d6d920486 100644 --- a/lld/ELF/ScriptLexer.h +++ b/lld/ELF/ScriptLexer.h @@ -28,10 +28,11 @@ public: static StringRef skipSpace(StringRef S); bool atEOF(); StringRef next(); - StringRef peek(unsigned N = 0); + StringRef peek(); void skip(); bool consume(StringRef Tok); void expect(StringRef Expect); + bool consumeLabel(StringRef Tok); std::string getCurrentLocation(); std::vector<MemoryBufferRef> MBs; diff --git a/lld/test/ELF/version-script-extern-wildcards-anon.s b/lld/test/ELF/version-script-extern-wildcards-anon.s index 790d985e2b0..5ba2f7d21bd 100644 --- a/lld/test/ELF/version-script-extern-wildcards-anon.s +++ b/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 @@ _Z3bari: _Z3zedi: .global _Z3bazi _Z3bazi: +.global _ZSt3qux +_ZSt3qux: |

