[lld] r231928 - LinkerScript: Add parsing of the MEMORY command

Meador Inge meadori at codesourcery.com
Wed Mar 11 08:34:45 PDT 2015


Author: meadori
Date: Wed Mar 11 10:34:44 2015
New Revision: 231928

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

This patch implements parsing of the GNU ld MEMORY command [1].
The command and the memory block definitions are parsed as
specified (including the slightly strange "o" and "l" keywords).
Evaluation will be added at a later point in time.

[1] https://sourceware.org/binutils/docs-2.25/ld/MEMORY.html

Added:
    lld/trunk/test/LinkerScript/memory-empty.test
    lld/trunk/test/LinkerScript/memory-missing-attrs.test
    lld/trunk/test/LinkerScript/memory-missing-length.test
    lld/trunk/test/LinkerScript/memory-missing-name.test
    lld/trunk/test/LinkerScript/memory-missing-origin.test
    lld/trunk/test/LinkerScript/memory-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=231928&r1=231927&r2=231928&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/LinkerScript.h (original)
+++ lld/trunk/include/lld/ReaderWriter/LinkerScript.h Wed Mar 11 10:34:44 2015
@@ -77,6 +77,9 @@ public:
     kw_hidden,
     kw_input,
     kw_keep,
+    kw_length,
+    kw_memory,
+    kw_origin,
     kw_provide,
     kw_provide_hidden,
     kw_only_if_ro,
@@ -154,6 +157,7 @@ public:
     Group,
     Input,
     InputSectionsCmd,
+    Memory,
     Output,
     OutputArch,
     OutputFormat,
@@ -798,6 +802,46 @@ private:
   llvm::ArrayRef<const Command *> _sectionsCommands;
 };
 
+/// Represents a single memory block definition in a MEMORY {} command.
+class MemoryBlock {
+public:
+  MemoryBlock(StringRef name, StringRef attr,
+              const Expression *origin, const Expression *length)
+      : _name(name), _attr(attr), _origin(origin), _length(length) {}
+
+  void dump(raw_ostream &os) const;
+
+private:
+  StringRef _name;
+  StringRef _attr;
+  const Expression *_origin;
+  const Expression *_length;
+};
+
+/// Represents all the contents of the MEMORY {} command.
+class Memory : public Command {
+public:
+  Memory(Parser &ctx,
+         const SmallVectorImpl<const MemoryBlock *> &blocks)
+      : Command(ctx, Kind::Memory) {
+    size_t numBlocks = blocks.size();
+    const MemoryBlock **blocksStart =
+        getAllocator().Allocate<const MemoryBlock *>(numBlocks);
+    std::copy(std::begin(blocks), std::end(blocks), blocksStart);
+    _blocks = llvm::makeArrayRef(blocksStart, numBlocks);
+  }
+
+  static bool classof(const Command *c) {
+    return c->getKind() == Kind::Memory;
+  }
+
+  void dump(raw_ostream &os) const override;
+
+private:
+  llvm::ArrayRef<const MemoryBlock *> _blocks;
+};
+
+
 /// Stores the parse tree of a linker script.
 class LinkerScript {
 public:
@@ -1066,6 +1110,17 @@ private:
   ///
   Sections *parseSections();
 
+  /// Parse the MEMORY linker script command.
+  /// Example:
+  ///
+  ///   MEMORY {
+  ///   ^~~~ parseMemory()
+  ///     ram (rwx) : ORIGIN = 0x20000000, LENGTH = 96K
+  ///     rom (rx)  : ORIGIN = 0x0,        LENGTH = 256K
+  ///   }
+  ///
+  Memory *parseMemory();
+
 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=231928&r1=231927&r2=231928&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/LinkerScript.cpp (original)
+++ lld/trunk/lib/ReaderWriter/LinkerScript.cpp Wed Mar 11 10:34:44 2015
@@ -66,6 +66,9 @@ void Token::dump(raw_ostream &os) const
     CASE(kw_hidden)
     CASE(kw_input)
     CASE(kw_keep)
+    CASE(kw_length)
+    CASE(kw_memory)
+    CASE(kw_origin)
     CASE(kw_provide)
     CASE(kw_provide_hidden)
     CASE(kw_only_if_ro)
@@ -468,8 +471,15 @@ void Lexer::lex(Token &tok) {
             .Case("HIDDEN", Token::kw_hidden)
             .Case("INPUT", Token::kw_input)
             .Case("KEEP", Token::kw_keep)
+            .Case("LENGTH", Token::kw_length)
+            .Case("l", Token::kw_length)
+            .Case("len", Token::kw_length)
+            .Case("MEMORY", Token::kw_memory)
             .Case("ONLY_IF_RO", Token::kw_only_if_ro)
             .Case("ONLY_IF_RW", Token::kw_only_if_rw)
+            .Case("ORIGIN", Token::kw_origin)
+            .Case("o", Token::kw_origin)
+            .Case("org", Token::kw_origin)
             .Case("OUTPUT", Token::kw_output)
             .Case("OUTPUT_ARCH", Token::kw_output_arch)
             .Case("OUTPUT_FORMAT", Token::kw_output_format)
@@ -916,6 +926,32 @@ void Sections::dump(raw_ostream &os) con
   os << "}\n";
 }
 
+// Memory functions
+void MemoryBlock::dump(raw_ostream &os) const {
+    os << _name;
+
+    if (!_attr.empty())
+      os << " (" << _attr << ")";
+
+    os << " : ";
+
+    os << "ORIGIN = ";
+    _origin->dump(os);
+    os << ", ";
+
+    os << "LENGTH = ";
+    _length->dump(os);
+}
+
+void Memory::dump(raw_ostream &os) const {
+  os << "MEMORY\n{\n";
+  for (auto &block : _blocks) {
+    block->dump(os);
+    os << "\n";
+  }
+  os << "}\n";
+}
+
 // Parser functions
 std::error_code Parser::parse() {
   // Get the first token.
@@ -998,6 +1034,13 @@ std::error_code Parser::parse() {
       _script._commands.push_back(cmd);
       break;
     }
+    case Token::kw_memory: {
+      const Command *cmd = parseMemory();
+      if (!cmd)
+        return LinkerScriptReaderError::parse_error;
+      _script._commands.push_back(cmd);
+      break;
+    }
     default:
       // Unexpected.
       error(_tok, "expected linker script command");
@@ -1975,5 +2018,82 @@ Sections *Parser::parseSections() {
   return new (_alloc) Sections(*this, sectionsCommands);
 }
 
+Memory *Parser::parseMemory() {
+  assert(_tok._kind == Token::kw_memory && "Expected MEMORY!");
+  consumeToken();
+  if (!expectAndConsume(Token::l_brace, "expected {"))
+    return nullptr;
+  SmallVector<const MemoryBlock *, 8> blocks;
+
+  bool unrecognizedToken = false;
+  // Parse zero or more memory block descriptors.
+  while (!unrecognizedToken) {
+    if (_tok._kind == Token::identifier) {
+      StringRef name;
+      StringRef attrs;
+      const Expression *origin = nullptr;
+      const Expression *length = nullptr;
+
+      name = _tok._range;
+      consumeToken();
+
+      // Parse optional memory region attributes.
+      if (_tok._kind == Token::l_paren) {
+        consumeToken();
+
+        if (_tok._kind != Token::identifier) {
+          error(_tok, "Expected memory attribute string.");
+          return nullptr;
+        }
+        attrs = _tok._range;
+        consumeToken();
+
+        if (!expectAndConsume(Token::r_paren, "expected )"))
+          return nullptr;
+      }
+
+      if (!expectAndConsume(Token::colon, "expected :"))
+        return nullptr;
+
+      // Parse the ORIGIN (base address of memory block).
+      if (!expectAndConsume(Token::kw_origin, "expected ORIGIN"))
+        return nullptr;
+
+      if (!expectAndConsume(Token::equal, "expected ="))
+        return nullptr;
+
+      origin = parseExpression();
+      if (!origin)
+        return nullptr;
+
+      if (!expectAndConsume(Token::comma, "expected ,"))
+        return nullptr;
+
+      // Parse the LENGTH (length of memory block).
+      if (!expectAndConsume(Token::kw_length, "expected LENGTH"))
+        return nullptr;
+
+      if (!expectAndConsume(Token::equal, "expected ="))
+        return nullptr;
+
+      length = parseExpression();
+      if (!length)
+        return nullptr;
+
+      MemoryBlock *block =
+          new (_alloc) MemoryBlock(name, attrs, origin, length);
+      blocks.push_back(block);
+    } else {
+      unrecognizedToken = true;
+    }
+  }
+  if (!expectAndConsume(
+          Token::r_brace,
+          "expected memory block definition."))
+    return nullptr;
+
+  return new (_alloc) Memory(*this, blocks);
+}
+
 } // end namespace script
 } // end namespace lld

Added: lld/trunk/test/LinkerScript/memory-empty.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/LinkerScript/memory-empty.test?rev=231928&view=auto
==============================================================================
--- lld/trunk/test/LinkerScript/memory-empty.test (added)
+++ lld/trunk/test/LinkerScript/memory-empty.test Wed Mar 11 10:34:44 2015
@@ -0,0 +1,17 @@
+/*
+  RUN: linker-script-test %s | FileCheck %s
+*/
+
+MEMORY
+{
+}
+
+/*
+CHECK: kw_memory: MEMORY
+CHECK: l_brace: {
+CHECK: r_brace: }
+CHECK: eof:
+CHECK: MEMORY
+CHECK: {
+CHECK: }
+*/

Added: lld/trunk/test/LinkerScript/memory-missing-attrs.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/LinkerScript/memory-missing-attrs.test?rev=231928&view=auto
==============================================================================
--- lld/trunk/test/LinkerScript/memory-missing-attrs.test (added)
+++ lld/trunk/test/LinkerScript/memory-missing-attrs.test Wed Mar 11 10:34:44 2015
@@ -0,0 +1,32 @@
+/*
+  RUN: linker-script-test %s 2> %t | FileCheck %s
+  RUN: FileCheck -input-file %t -check-prefix=CHECK-ERR %s
+*/
+
+MEMORY
+{
+  ram () : ORIGIN = 0x20000000, LENGTH = 128M
+/*
+CHECK-ERR: [[@LINE-2]]:8: error: Expected memory attribute string.
+CHECK-ERR-NEXT: {{^  ram \(\) : ORIGIN = 0x20000000, LENGTH = 128M}}
+CHECK-ERR-NEXT: {{^        \^}}
+*/
+}
+
+/*
+CHECK: kw_memory: MEMORY
+CHECK: l_brace: {
+CHECK: identifier: ram
+CHECK: l_paren: (
+CHECK: r_paren: )
+CHECK: colon: :
+CHECK: kw_origin: ORIGIN
+CHECK: equal: =
+CHECK: number: 0x20000000
+CHECK: comma: ,
+CHECK: kw_length: LENGTH
+CHECK: equal: =
+CHECK: number: 128M
+CHECK: r_brace: }
+CHECK: eof:
+*/

Added: lld/trunk/test/LinkerScript/memory-missing-length.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/LinkerScript/memory-missing-length.test?rev=231928&view=auto
==============================================================================
--- lld/trunk/test/LinkerScript/memory-missing-length.test (added)
+++ lld/trunk/test/LinkerScript/memory-missing-length.test Wed Mar 11 10:34:44 2015
@@ -0,0 +1,29 @@
+/*
+  RUN: linker-script-test %s 2> %t | FileCheck %s
+  RUN: FileCheck -input-file %t -check-prefix=CHECK-ERR %s
+*/
+
+MEMORY
+{
+  ram (rwx) : ORIGIN = 0x20000000,
+}
+/*
+CHECK-ERR: [[@LINE-2]]:1: error: expected LENGTH
+CHECK-ERR-NEXT: {{^}}}
+CHECK-ERR-NEXT: {{^\^}}
+*/
+
+/*
+CHECK: kw_memory: MEMORY
+CHECK: l_brace: {
+CHECK: identifier: ram
+CHECK: l_paren: (
+CHECK: identifier: rwx
+CHECK: r_paren: )
+CHECK: colon: :
+CHECK: kw_origin: ORIGIN
+CHECK: equal: =
+CHECK: number: 0x20000000
+CHECK: r_brace: }
+CHECK: eof:
+*/

Added: lld/trunk/test/LinkerScript/memory-missing-name.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/LinkerScript/memory-missing-name.test?rev=231928&view=auto
==============================================================================
--- lld/trunk/test/LinkerScript/memory-missing-name.test (added)
+++ lld/trunk/test/LinkerScript/memory-missing-name.test Wed Mar 11 10:34:44 2015
@@ -0,0 +1,31 @@
+/*
+  RUN: linker-script-test %s 2> %t | FileCheck %s
+  RUN: FileCheck -input-file %t -check-prefix=CHECK-ERR %s
+*/
+
+MEMORY
+{
+  (rwx) : ORIGIN = 0x20000000, LENGTH = 128M
+/*
+CHECK-ERR: [[@LINE-2]]:3: error: expected memory block definition.
+CHECK-ERR-NEXT: {{^  \(rwx\) : ORIGIN = 0x20000000, LENGTH = 128M}}
+CHECK-ERR-NEXT: {{^  \^}}
+*/
+}
+
+/*
+CHECK: kw_memory: MEMORY
+CHECK: l_brace: {
+CHECK: l_paren: (
+CHECK: r_paren: )
+CHECK: colon: :
+CHECK: kw_origin: ORIGIN
+CHECK: equal: =
+CHECK: number: 0x20000000
+CHECK: comma: ,
+CHECK: kw_length: LENGTH
+CHECK: equal: =
+CHECK: number: 128M
+CHECK: r_brace: }
+CHECK: eof:
+*/

Added: lld/trunk/test/LinkerScript/memory-missing-origin.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/LinkerScript/memory-missing-origin.test?rev=231928&view=auto
==============================================================================
--- lld/trunk/test/LinkerScript/memory-missing-origin.test (added)
+++ lld/trunk/test/LinkerScript/memory-missing-origin.test Wed Mar 11 10:34:44 2015
@@ -0,0 +1,30 @@
+/*
+  RUN: linker-script-test %s 2> %t | FileCheck %s
+  RUN: FileCheck -input-file %t -check-prefix=CHECK-ERR %s
+*/
+
+MEMORY
+{
+  ram (rwx) : LENGTH = 128M
+/*
+CHECK-ERR: [[@LINE-2]]:15: error: expected ORIGIN
+CHECK-ERR-NEXT: {{^  ram \(rwx\) : LENGTH = 128M}}
+CHECK-ERR-NEXT: {{^               \^}}
+*/
+
+}
+
+/*
+CHECK: kw_memory: MEMORY
+CHECK: l_brace: {
+CHECK: identifier: ram
+CHECK: l_paren: (
+CHECK: identifier: rwx
+CHECK: r_paren: )
+CHECK: colon: :
+CHECK: kw_length: LENGTH
+CHECK: equal: =
+CHECK: number: 128M
+CHECK: r_brace: }
+CHECK: eof:
+*/

Added: lld/trunk/test/LinkerScript/memory-valid.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/LinkerScript/memory-valid.test?rev=231928&view=auto
==============================================================================
--- lld/trunk/test/LinkerScript/memory-valid.test (added)
+++ lld/trunk/test/LinkerScript/memory-valid.test Wed Mar 11 10:34:44 2015
@@ -0,0 +1,56 @@
+/*
+  RUN: linker-script-test %s | FileCheck %s
+*/
+
+MEMORY
+{
+  ram (rwx) : ORIGIN = 0x20000000, LENGTH = 96K
+  rom (rx) : org = 0x0, len = 256K
+  boot : o = 0x1000000, l = 0x5f00
+}
+
+/*
+CHECK: kw_memory: MEMORY
+CHECK: l_brace: {
+CHECK: identifier: ram
+CHECK: l_paren: (
+CHECK: identifier: rwx
+CHECK: r_paren: )
+CHECK: colon: :
+CHECK: kw_origin: ORIGIN
+CHECK: equal: =
+CHECK: number: 0x20000000
+CHECK: comma: ,
+CHECK: kw_length: LENGTH
+CHECK: equal: =
+CHECK: number: 96K
+CHECK: identifier: rom
+CHECK: l_paren: (
+CHECK: identifier: rx
+CHECK: r_paren: )
+CHECK: colon: :
+CHECK: kw_origin: org
+CHECK: equal: =
+CHECK: number: 0x0
+CHECK: comma: ,
+CHECK: kw_length: len
+CHECK: equal: =
+CHECK: number: 256K
+CHECK: identifier: boot
+CHECK: colon: :
+CHECK: kw_origin: o
+CHECK: equal: =
+CHECK: number: 0x1000000
+CHECK: comma: ,
+CHECK: kw_length: l
+CHECK: equal: =
+CHECK: number: 0x5f00
+CHECK: r_brace: }
+CHECK: eof:
+CHECK: MEMORY
+CHECK: {
+CHECK: ram (rwx) : ORIGIN = 536870912, LENGTH = 98304
+CHECK: rom (rx) : ORIGIN = 0, LENGTH = 262144
+CHECK: boot : ORIGIN = 16777216, LENGTH = 24320
+CHECK: }
+*/





More information about the llvm-commits mailing list