[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