Skip to content

Commit 2ce1ea8

Browse files
committedMar 11, 2015
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 llvm-svn: 231928
1 parent c04b6f2 commit 2ce1ea8

File tree

8 files changed

+370
-0
lines changed

8 files changed

+370
-0
lines changed
 

‎lld/include/lld/ReaderWriter/LinkerScript.h

+55
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ class Token {
7777
kw_hidden,
7878
kw_input,
7979
kw_keep,
80+
kw_length,
81+
kw_memory,
82+
kw_origin,
8083
kw_provide,
8184
kw_provide_hidden,
8285
kw_only_if_ro,
@@ -154,6 +157,7 @@ class Command {
154157
Group,
155158
Input,
156159
InputSectionsCmd,
160+
Memory,
157161
Output,
158162
OutputArch,
159163
OutputFormat,
@@ -798,6 +802,46 @@ class Sections : public Command {
798802
llvm::ArrayRef<const Command *> _sectionsCommands;
799803
};
800804

805+
/// Represents a single memory block definition in a MEMORY {} command.
806+
class MemoryBlock {
807+
public:
808+
MemoryBlock(StringRef name, StringRef attr,
809+
const Expression *origin, const Expression *length)
810+
: _name(name), _attr(attr), _origin(origin), _length(length) {}
811+
812+
void dump(raw_ostream &os) const;
813+
814+
private:
815+
StringRef _name;
816+
StringRef _attr;
817+
const Expression *_origin;
818+
const Expression *_length;
819+
};
820+
821+
/// Represents all the contents of the MEMORY {} command.
822+
class Memory : public Command {
823+
public:
824+
Memory(Parser &ctx,
825+
const SmallVectorImpl<const MemoryBlock *> &blocks)
826+
: Command(ctx, Kind::Memory) {
827+
size_t numBlocks = blocks.size();
828+
const MemoryBlock **blocksStart =
829+
getAllocator().Allocate<const MemoryBlock *>(numBlocks);
830+
std::copy(std::begin(blocks), std::end(blocks), blocksStart);
831+
_blocks = llvm::makeArrayRef(blocksStart, numBlocks);
832+
}
833+
834+
static bool classof(const Command *c) {
835+
return c->getKind() == Kind::Memory;
836+
}
837+
838+
void dump(raw_ostream &os) const override;
839+
840+
private:
841+
llvm::ArrayRef<const MemoryBlock *> _blocks;
842+
};
843+
844+
801845
/// Stores the parse tree of a linker script.
802846
class LinkerScript {
803847
public:
@@ -1066,6 +1110,17 @@ class Parser {
10661110
///
10671111
Sections *parseSections();
10681112

1113+
/// Parse the MEMORY linker script command.
1114+
/// Example:
1115+
///
1116+
/// MEMORY {
1117+
/// ^~~~ parseMemory()
1118+
/// ram (rwx) : ORIGIN = 0x20000000, LENGTH = 96K
1119+
/// rom (rx) : ORIGIN = 0x0, LENGTH = 256K
1120+
/// }
1121+
///
1122+
Memory *parseMemory();
1123+
10691124
private:
10701125
// Owns the entire linker script AST nodes
10711126
llvm::BumpPtrAllocator _alloc;

‎lld/lib/ReaderWriter/LinkerScript.cpp

+120
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ void Token::dump(raw_ostream &os) const {
6666
CASE(kw_hidden)
6767
CASE(kw_input)
6868
CASE(kw_keep)
69+
CASE(kw_length)
70+
CASE(kw_memory)
71+
CASE(kw_origin)
6972
CASE(kw_provide)
7073
CASE(kw_provide_hidden)
7174
CASE(kw_only_if_ro)
@@ -468,8 +471,15 @@ void Lexer::lex(Token &tok) {
468471
.Case("HIDDEN", Token::kw_hidden)
469472
.Case("INPUT", Token::kw_input)
470473
.Case("KEEP", Token::kw_keep)
474+
.Case("LENGTH", Token::kw_length)
475+
.Case("l", Token::kw_length)
476+
.Case("len", Token::kw_length)
477+
.Case("MEMORY", Token::kw_memory)
471478
.Case("ONLY_IF_RO", Token::kw_only_if_ro)
472479
.Case("ONLY_IF_RW", Token::kw_only_if_rw)
480+
.Case("ORIGIN", Token::kw_origin)
481+
.Case("o", Token::kw_origin)
482+
.Case("org", Token::kw_origin)
473483
.Case("OUTPUT", Token::kw_output)
474484
.Case("OUTPUT_ARCH", Token::kw_output_arch)
475485
.Case("OUTPUT_FORMAT", Token::kw_output_format)
@@ -916,6 +926,32 @@ void Sections::dump(raw_ostream &os) const {
916926
os << "}\n";
917927
}
918928

929+
// Memory functions
930+
void MemoryBlock::dump(raw_ostream &os) const {
931+
os << _name;
932+
933+
if (!_attr.empty())
934+
os << " (" << _attr << ")";
935+
936+
os << " : ";
937+
938+
os << "ORIGIN = ";
939+
_origin->dump(os);
940+
os << ", ";
941+
942+
os << "LENGTH = ";
943+
_length->dump(os);
944+
}
945+
946+
void Memory::dump(raw_ostream &os) const {
947+
os << "MEMORY\n{\n";
948+
for (auto &block : _blocks) {
949+
block->dump(os);
950+
os << "\n";
951+
}
952+
os << "}\n";
953+
}
954+
919955
// Parser functions
920956
std::error_code Parser::parse() {
921957
// Get the first token.
@@ -998,6 +1034,13 @@ std::error_code Parser::parse() {
9981034
_script._commands.push_back(cmd);
9991035
break;
10001036
}
1037+
case Token::kw_memory: {
1038+
const Command *cmd = parseMemory();
1039+
if (!cmd)
1040+
return LinkerScriptReaderError::parse_error;
1041+
_script._commands.push_back(cmd);
1042+
break;
1043+
}
10011044
default:
10021045
// Unexpected.
10031046
error(_tok, "expected linker script command");
@@ -1975,5 +2018,82 @@ Sections *Parser::parseSections() {
19752018
return new (_alloc) Sections(*this, sectionsCommands);
19762019
}
19772020

2021+
Memory *Parser::parseMemory() {
2022+
assert(_tok._kind == Token::kw_memory && "Expected MEMORY!");
2023+
consumeToken();
2024+
if (!expectAndConsume(Token::l_brace, "expected {"))
2025+
return nullptr;
2026+
SmallVector<const MemoryBlock *, 8> blocks;
2027+
2028+
bool unrecognizedToken = false;
2029+
// Parse zero or more memory block descriptors.
2030+
while (!unrecognizedToken) {
2031+
if (_tok._kind == Token::identifier) {
2032+
StringRef name;
2033+
StringRef attrs;
2034+
const Expression *origin = nullptr;
2035+
const Expression *length = nullptr;
2036+
2037+
name = _tok._range;
2038+
consumeToken();
2039+
2040+
// Parse optional memory region attributes.
2041+
if (_tok._kind == Token::l_paren) {
2042+
consumeToken();
2043+
2044+
if (_tok._kind != Token::identifier) {
2045+
error(_tok, "Expected memory attribute string.");
2046+
return nullptr;
2047+
}
2048+
attrs = _tok._range;
2049+
consumeToken();
2050+
2051+
if (!expectAndConsume(Token::r_paren, "expected )"))
2052+
return nullptr;
2053+
}
2054+
2055+
if (!expectAndConsume(Token::colon, "expected :"))
2056+
return nullptr;
2057+
2058+
// Parse the ORIGIN (base address of memory block).
2059+
if (!expectAndConsume(Token::kw_origin, "expected ORIGIN"))
2060+
return nullptr;
2061+
2062+
if (!expectAndConsume(Token::equal, "expected ="))
2063+
return nullptr;
2064+
2065+
origin = parseExpression();
2066+
if (!origin)
2067+
return nullptr;
2068+
2069+
if (!expectAndConsume(Token::comma, "expected ,"))
2070+
return nullptr;
2071+
2072+
// Parse the LENGTH (length of memory block).
2073+
if (!expectAndConsume(Token::kw_length, "expected LENGTH"))
2074+
return nullptr;
2075+
2076+
if (!expectAndConsume(Token::equal, "expected ="))
2077+
return nullptr;
2078+
2079+
length = parseExpression();
2080+
if (!length)
2081+
return nullptr;
2082+
2083+
MemoryBlock *block =
2084+
new (_alloc) MemoryBlock(name, attrs, origin, length);
2085+
blocks.push_back(block);
2086+
} else {
2087+
unrecognizedToken = true;
2088+
}
2089+
}
2090+
if (!expectAndConsume(
2091+
Token::r_brace,
2092+
"expected memory block definition."))
2093+
return nullptr;
2094+
2095+
return new (_alloc) Memory(*this, blocks);
2096+
}
2097+
19782098
} // end namespace script
19792099
} // end namespace lld
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
RUN: linker-script-test %s | FileCheck %s
3+
*/
4+
5+
MEMORY
6+
{
7+
}
8+
9+
/*
10+
CHECK: kw_memory: MEMORY
11+
CHECK: l_brace: {
12+
CHECK: r_brace: }
13+
CHECK: eof:
14+
CHECK: MEMORY
15+
CHECK: {
16+
CHECK: }
17+
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
RUN: linker-script-test %s 2> %t | FileCheck %s
3+
RUN: FileCheck -input-file %t -check-prefix=CHECK-ERR %s
4+
*/
5+
6+
MEMORY
7+
{
8+
ram () : ORIGIN = 0x20000000, LENGTH = 128M
9+
/*
10+
CHECK-ERR: [[@LINE-2]]:8: error: Expected memory attribute string.
11+
CHECK-ERR-NEXT: {{^ ram \(\) : ORIGIN = 0x20000000, LENGTH = 128M}}
12+
CHECK-ERR-NEXT: {{^ \^}}
13+
*/
14+
}
15+
16+
/*
17+
CHECK: kw_memory: MEMORY
18+
CHECK: l_brace: {
19+
CHECK: identifier: ram
20+
CHECK: l_paren: (
21+
CHECK: r_paren: )
22+
CHECK: colon: :
23+
CHECK: kw_origin: ORIGIN
24+
CHECK: equal: =
25+
CHECK: number: 0x20000000
26+
CHECK: comma: ,
27+
CHECK: kw_length: LENGTH
28+
CHECK: equal: =
29+
CHECK: number: 128M
30+
CHECK: r_brace: }
31+
CHECK: eof:
32+
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
RUN: linker-script-test %s 2> %t | FileCheck %s
3+
RUN: FileCheck -input-file %t -check-prefix=CHECK-ERR %s
4+
*/
5+
6+
MEMORY
7+
{
8+
ram (rwx) : ORIGIN = 0x20000000,
9+
}
10+
/*
11+
CHECK-ERR: [[@LINE-2]]:1: error: expected LENGTH
12+
CHECK-ERR-NEXT: {{^}}}
13+
CHECK-ERR-NEXT: {{^\^}}
14+
*/
15+
16+
/*
17+
CHECK: kw_memory: MEMORY
18+
CHECK: l_brace: {
19+
CHECK: identifier: ram
20+
CHECK: l_paren: (
21+
CHECK: identifier: rwx
22+
CHECK: r_paren: )
23+
CHECK: colon: :
24+
CHECK: kw_origin: ORIGIN
25+
CHECK: equal: =
26+
CHECK: number: 0x20000000
27+
CHECK: r_brace: }
28+
CHECK: eof:
29+
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
RUN: linker-script-test %s 2> %t | FileCheck %s
3+
RUN: FileCheck -input-file %t -check-prefix=CHECK-ERR %s
4+
*/
5+
6+
MEMORY
7+
{
8+
(rwx) : ORIGIN = 0x20000000, LENGTH = 128M
9+
/*
10+
CHECK-ERR: [[@LINE-2]]:3: error: expected memory block definition.
11+
CHECK-ERR-NEXT: {{^ \(rwx\) : ORIGIN = 0x20000000, LENGTH = 128M}}
12+
CHECK-ERR-NEXT: {{^ \^}}
13+
*/
14+
}
15+
16+
/*
17+
CHECK: kw_memory: MEMORY
18+
CHECK: l_brace: {
19+
CHECK: l_paren: (
20+
CHECK: r_paren: )
21+
CHECK: colon: :
22+
CHECK: kw_origin: ORIGIN
23+
CHECK: equal: =
24+
CHECK: number: 0x20000000
25+
CHECK: comma: ,
26+
CHECK: kw_length: LENGTH
27+
CHECK: equal: =
28+
CHECK: number: 128M
29+
CHECK: r_brace: }
30+
CHECK: eof:
31+
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
RUN: linker-script-test %s 2> %t | FileCheck %s
3+
RUN: FileCheck -input-file %t -check-prefix=CHECK-ERR %s
4+
*/
5+
6+
MEMORY
7+
{
8+
ram (rwx) : LENGTH = 128M
9+
/*
10+
CHECK-ERR: [[@LINE-2]]:15: error: expected ORIGIN
11+
CHECK-ERR-NEXT: {{^ ram \(rwx\) : LENGTH = 128M}}
12+
CHECK-ERR-NEXT: {{^ \^}}
13+
*/
14+
15+
}
16+
17+
/*
18+
CHECK: kw_memory: MEMORY
19+
CHECK: l_brace: {
20+
CHECK: identifier: ram
21+
CHECK: l_paren: (
22+
CHECK: identifier: rwx
23+
CHECK: r_paren: )
24+
CHECK: colon: :
25+
CHECK: kw_length: LENGTH
26+
CHECK: equal: =
27+
CHECK: number: 128M
28+
CHECK: r_brace: }
29+
CHECK: eof:
30+
*/

0 commit comments

Comments
 (0)
Please sign in to comment.