[lld] r232110 - LinkerScript: Add parsing of the EXTERN command

Meador Inge meadori at codesourcery.com
Thu Mar 12 14:55:51 PDT 2015


Author: meadori
Date: Thu Mar 12 16:55:50 2015
New Revision: 232110

URL: http://llvm.org/viewvc/llvm-project?rev=232110&view=rev
Log:
LinkerScript: Add parsing of the EXTERN command

This patch implements parsing of the GNU ld EXTERN command [1].
Evaluation will be added at a later point in time.

[1] https://sourceware.org/binutils/docs/ld/Miscellaneous-Commands.html#Miscellaneous-Commands

Added:
    lld/trunk/test/LinkerScript/extern-bad-symbol.test
    lld/trunk/test/LinkerScript/extern-empty.test
    lld/trunk/test/LinkerScript/extern-valid.test
Modified:
    lld/trunk/include/lld/ReaderWriter/LinkerScript.h
    lld/trunk/lib/ReaderWriter/LinkerScript.cpp

Modified: lld/trunk/include/lld/ReaderWriter/LinkerScript.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/LinkerScript.h?rev=232110&r1=232109&r2=232110&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/LinkerScript.h (original)
+++ lld/trunk/include/lld/ReaderWriter/LinkerScript.h Thu Mar 12 16:55:50 2015
@@ -73,6 +73,7 @@ public:
     kw_discard,
     kw_entry,
     kw_exclude_file,
+    kw_extern,
     kw_group,
     kw_hidden,
     kw_input,
@@ -154,6 +155,7 @@ class Command {
 public:
   enum class Kind {
     Entry,
+    Extern,
     Group,
     Input,
     InputSectionsCmd,
@@ -841,6 +843,28 @@ private:
   llvm::ArrayRef<const MemoryBlock *> _blocks;
 };
 
+/// Represents an extern command.
+class Extern : public Command {
+public:
+  Extern(Parser &ctx,
+         const SmallVectorImpl<StringRef> &symbols)
+      : Command(ctx, Kind::Extern) {
+    size_t numSymbols = symbols.size();
+    StringRef *symbolsStart =
+        getAllocator().Allocate<StringRef>(numSymbols);
+    std::copy(std::begin(symbols), std::end(symbols), symbolsStart);
+    _symbols = llvm::makeArrayRef(symbolsStart, numSymbols);
+  }
+
+  static bool classof(const Command *c) {
+    return c->getKind() == Kind::Extern;
+  }
+
+  void dump(raw_ostream &os) const override;
+
+private:
+  llvm::ArrayRef<StringRef> _symbols;
+};
 
 /// Stores the parse tree of a linker script.
 class LinkerScript {
@@ -1121,6 +1145,14 @@ private:
   ///
   Memory *parseMemory();
 
+  /// Parse the EXTERN linker script command.
+  /// Example:
+  ///
+  /// EXTERN(symbol symbol ...)
+  /// ^~~~> parseExtern()
+  ///
+  Extern *parseExtern();
+
 private:
   // Owns the entire linker script AST nodes
   llvm::BumpPtrAllocator _alloc;

Modified: lld/trunk/lib/ReaderWriter/LinkerScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/LinkerScript.cpp?rev=232110&r1=232109&r2=232110&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/LinkerScript.cpp (original)
+++ lld/trunk/lib/ReaderWriter/LinkerScript.cpp Thu Mar 12 16:55:50 2015
@@ -62,6 +62,7 @@ void Token::dump(raw_ostream &os) const
     CASE(kw_discard)
     CASE(kw_entry)
     CASE(kw_exclude_file)
+    CASE(kw_extern)
     CASE(kw_group)
     CASE(kw_hidden)
     CASE(kw_input)
@@ -467,6 +468,7 @@ void Lexer::lex(Token &tok) {
             .Case("AT", Token::kw_at)
             .Case("ENTRY", Token::kw_entry)
             .Case("EXCLUDE_FILE", Token::kw_exclude_file)
+            .Case("EXTERN", Token::kw_extern)
             .Case("GROUP", Token::kw_group)
             .Case("HIDDEN", Token::kw_hidden)
             .Case("INPUT", Token::kw_input)
@@ -952,6 +954,18 @@ void Memory::dump(raw_ostream &os) const
   os << "}\n";
 }
 
+// Extern functions
+void Extern::dump(raw_ostream &os) const {
+  os << "EXTERN(";
+  for (unsigned i = 0, e = _symbols.size(); i != e; ++i) {
+    if (i)
+      os << " ";
+    os << _symbols[i];
+  }
+  os << ")\n";
+}
+
+
 // Parser functions
 std::error_code Parser::parse() {
   // Get the first token.
@@ -1041,6 +1055,13 @@ std::error_code Parser::parse() {
       _script._commands.push_back(cmd);
       break;
     }
+    case Token::kw_extern: {
+      const Command *cmd = parseExtern();
+      if (!cmd)
+        return LinkerScriptReaderError::parse_error;
+      _script._commands.push_back(cmd);
+      break;
+    }
     default:
       // Unexpected.
       error(_tok, "expected linker script command");
@@ -2095,5 +2116,30 @@ Memory *Parser::parseMemory() {
   return new (_alloc) Memory(*this, blocks);
 }
 
+Extern *Parser::parseExtern() {
+  assert(_tok._kind == Token::kw_extern && "Expected EXTERN!");
+  consumeToken();
+  if (!expectAndConsume(Token::l_paren, "expected ("))
+    return nullptr;
+
+  // Parse one or more symbols.
+  SmallVector<StringRef, 8> symbols;
+  if (_tok._kind != Token::identifier) {
+    error(_tok, "expected one or more symbols in EXTERN.");
+    return nullptr;
+  }
+  symbols.push_back(_tok._range);
+  consumeToken();
+  while (_tok._kind == Token::identifier) {
+    symbols.push_back(_tok._range);
+    consumeToken();
+  }
+
+  if (!expectAndConsume(Token::r_paren, "expected symbol in EXTERN."))
+    return nullptr;
+
+  return new (_alloc) Extern(*this, symbols);
+}
+
 } // end namespace script
 } // end namespace lld

Added: lld/trunk/test/LinkerScript/extern-bad-symbol.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/LinkerScript/extern-bad-symbol.test?rev=232110&view=auto
==============================================================================
--- lld/trunk/test/LinkerScript/extern-bad-symbol.test (added)
+++ lld/trunk/test/LinkerScript/extern-bad-symbol.test Thu Mar 12 16:55:50 2015
@@ -0,0 +1,22 @@
+/*
+  RUN: linker-script-test %s 2> %t | FileCheck %s
+  RUN: FileCheck -input-file %t -check-prefix=CHECK-ERR %s
+*/
+
+
+EXTERN(a b 3)
+/*
+CHECK-ERR: [[@LINE-2]]:12: error: expected symbol in EXTERN.
+CHECK-ERR-NEXT: {{^EXTERN\(a b 3\)}}
+CHECK-ERR-NEXT: {{^          \^}}
+*/
+
+/*
+CHECK: kw_extern: EXTERN
+CHECK: l_paren: (
+CHECK: identifier: a
+CHECK: identifier: b
+CHECK: number: 3
+CHECK: r_paren: )
+CHECK: eof:
+*/

Added: lld/trunk/test/LinkerScript/extern-empty.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/LinkerScript/extern-empty.test?rev=232110&view=auto
==============================================================================
--- lld/trunk/test/LinkerScript/extern-empty.test (added)
+++ lld/trunk/test/LinkerScript/extern-empty.test Thu Mar 12 16:55:50 2015
@@ -0,0 +1,19 @@
+/*
+  RUN: linker-script-test %s 2> %t | FileCheck %s
+  RUN: FileCheck -input-file %t -check-prefix=CHECK-ERR %s
+*/
+
+
+EXTERN()
+/*
+CHECK-ERR: [[@LINE-2]]:8: error: expected one or more symbols in EXTERN.
+CHECK-ERR-NEXT: {{^EXTERN()}}
+CHECK-ERR-NEXT: {{^     \^}}
+*/
+
+/*
+CHECK: kw_extern: EXTERN
+CHECK: l_paren: (
+CHECK: r_paren: )
+CHECK: eof:
+*/

Added: lld/trunk/test/LinkerScript/extern-valid.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/LinkerScript/extern-valid.test?rev=232110&view=auto
==============================================================================
--- lld/trunk/test/LinkerScript/extern-valid.test (added)
+++ lld/trunk/test/LinkerScript/extern-valid.test Thu Mar 12 16:55:50 2015
@@ -0,0 +1,29 @@
+/*
+  RUN: linker-script-test %s | FileCheck %s
+*/
+
+EXTERN(a)
+EXTERN(a b)
+EXTERN(_foo _bar _baz)
+
+/*
+CHECK: kw_extern: EXTERN
+CHECK: l_paren: (
+CHECK: identifier: a
+CHECK: r_paren: )
+CHECK: kw_extern: EXTERN
+CHECK: l_paren: (
+CHECK: identifier: a
+CHECK: identifier: b
+CHECK: r_paren: )
+CHECK: kw_extern: EXTERN
+CHECK: l_paren: (
+CHECK: identifier: _foo
+CHECK: identifier: _bar
+CHECK: identifier: _baz
+CHECK: r_paren: )
+CHECK: eof:
+CHECK: EXTERN(a)
+CHECK: EXTERN(a b)
+CHECK: EXTERN(_foo _bar _baz)
+*/





More information about the llvm-commits mailing list