[lld] r297402 - Handle ":" as a regular token character in linker scripts.

Rui Ueyama via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 9 11:23:00 PST 2017


Author: ruiu
Date: Thu Mar  9 13:23:00 2017
New Revision: 297402

URL: http://llvm.org/viewvc/llvm-project?rev=297402&view=rev
Log:
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

Modified:
    lld/trunk/ELF/Config.h
    lld/trunk/ELF/LinkerScript.cpp
    lld/trunk/ELF/ScriptLexer.cpp
    lld/trunk/ELF/ScriptLexer.h
    lld/trunk/test/ELF/version-script-extern-wildcards-anon.s

Modified: lld/trunk/ELF/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Config.h?rev=297402&r1=297401&r2=297402&view=diff
==============================================================================
--- lld/trunk/ELF/Config.h (original)
+++ lld/trunk/ELF/Config.h Thu Mar  9 13:23:00 2017
@@ -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.

Modified: lld/trunk/ELF/LinkerScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.cpp?rev=297402&r1=297401&r2=297402&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.cpp (original)
+++ lld/trunk/ELF/LinkerScript.cpp Thu Mar  9 13:23:00 2017
@@ -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();
+  // 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);
   }
-  readLocals();
-  expect("}");
+
+  // 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::readVersionDeclaratio
   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:
   }
 
   expect("}");
-  expect(";");
   return Ret;
 }
 

Modified: lld/trunk/ELF/ScriptLexer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/ScriptLexer.cpp?rev=297402&r1=297401&r2=297402&view=diff
==============================================================================
--- lld/trunk/ELF/ScriptLexer.cpp (original)
+++ lld/trunk/ELF/ScriptLexer.cpp Thu Mar  9 13:23:00 2017
@@ -124,7 +124,7 @@ void ScriptLexer::tokenize(MemoryBufferR
     // 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
 // 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;
 }
 
@@ -246,6 +243,18 @@ bool ScriptLexer::consume(StringRef Tok)
     return true;
   }
   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(); }

Modified: lld/trunk/ELF/ScriptLexer.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/ScriptLexer.h?rev=297402&r1=297401&r2=297402&view=diff
==============================================================================
--- lld/trunk/ELF/ScriptLexer.h (original)
+++ lld/trunk/ELF/ScriptLexer.h Thu Mar  9 13:23:00 2017
@@ -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;

Modified: lld/trunk/test/ELF/version-script-extern-wildcards-anon.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/version-script-extern-wildcards-anon.s?rev=297402&r1=297401&r2=297402&view=diff
==============================================================================
--- lld/trunk/test/ELF/version-script-extern-wildcards-anon.s (original)
+++ lld/trunk/test/ELF/version-script-extern-wildcards-anon.s Thu Mar  9 13:23:00 2017
@@ -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:




More information about the llvm-commits mailing list