diff --git a/include/lld/ReaderWriter/LinkerScript.h b/include/lld/ReaderWriter/LinkerScript.h index be22bf3..d49c294 100644 --- a/include/lld/ReaderWriter/LinkerScript.h +++ b/include/lld/ReaderWriter/LinkerScript.h @@ -74,6 +74,9 @@ public: kw_group, kw_hidden, kw_keep, + kw_length, + kw_memory, + kw_origin, kw_provide, kw_provide_hidden, kw_only_if_ro, @@ -149,6 +152,7 @@ public: Entry, Group, InputSectionsCmd, + Memory, OutputArch, OutputFormat, OutputSectionDescription, @@ -279,6 +283,72 @@ private: StringRef _entryName; }; +struct MemoryAttributes { +public: + explicit MemoryAttributes(StringRef attr, bool negated = false) + : _attr(attr), _negated(negated) {} + + StringRef getAttrString() { return _attr; }; + bool isNegated() { return _negated; }; +private: + StringRef _attr; + bool _negated; +}; + +struct MemoryEntry { +public: + explicit MemoryEntry(StringRef regionName, MemoryAttributes attrs, + StringRef origin, StringRef length) + : _regionName(regionName), _attrs(attrs), _origin(origin), + _length(length) {} + + StringRef getRegionName() { return _regionName; }; + MemoryAttributes getAttributes() { return _attrs; }; + StringRef getOrigin() { return _origin; }; + StringRef getLength() { return _length; }; + + // dump() ? + +private: + StringRef _regionName; + MemoryAttributes _attrs; + StringRef _origin; + StringRef _length; +}; + +/// Represents all the contents of the MEMORY {} construct. +class Memory: public Command { +public: + explicit Memory(std::vector entries) + : Command(Kind::Memory), _entries(entries) {} + + static bool classof(const Command *c) { + return c->getKind() == Kind::Memory; + } + + void dump(raw_ostream &os) const override { + os << "MEMORY {" << "\n"; + for (MemoryEntry *entry: _entries) { + os << entry->getRegionName() << " " << "("; + MemoryAttributes ma = entry->getAttributes(); + if (ma.isNegated()) + os << "!"; + os << ma.getAttrString() << ") : "; + os << "ORIGIN = " << entry->getOrigin() << ", "; + os << "LENGTH = " << entry->getLength() << "\n"; + } + os << "}" << "\n"; + } + + std::vector getEntries() { return _entries; } + void addEntry(MemoryEntry *entry) { + _entries.push_back(entry); + } + +private: + std::vector _entries; +}; + class SearchDir : public Command { public: explicit SearchDir(StringRef searchPath) @@ -861,6 +931,14 @@ private: Group *parseGroup(); bool parseAsNeeded(std::vector &paths); + /// Parse Memory attributes. + MemoryAttributes *parseMemoryAttributes(); + /// Parse Memory entry description. + MemoryEntry *parseMemoryEntryDescription(); + /// Parse the MEMORY linker script command. + /// Example: XXXFIXME. + Memory *parseMemory(); + /// Parse the ENTRY linker script command. /// Example: /// diff --git a/lib/ReaderWriter/LinkerScript.cpp b/lib/ReaderWriter/LinkerScript.cpp index 3984408..57eb580 100644 --- a/lib/ReaderWriter/LinkerScript.cpp +++ b/lib/ReaderWriter/LinkerScript.cpp @@ -64,11 +64,14 @@ void Token::dump(raw_ostream &os) const { CASE(kw_exclude_file) CASE(kw_group) CASE(kw_hidden) + CASE(kw_length) + CASE(kw_memory) CASE(kw_keep) CASE(kw_provide) CASE(kw_provide_hidden) CASE(kw_only_if_ro) CASE(kw_only_if_rw) + CASE(kw_origin) CASE(kw_output_arch) CASE(kw_output_format) CASE(kw_overlay) @@ -512,9 +515,16 @@ void Lexer::lex(Token &tok) { .Case("EXCLUDE_FILE", Token::kw_exclude_file) .Case("GROUP", Token::kw_group) .Case("HIDDEN", Token::kw_hidden) + .Case("LENGTH", Token::kw_length) + .Case("len", Token::kw_length) + .Case("l", Token::kw_length) + .Case("MEMORY", Token::kw_memory) .Case("KEEP", Token::kw_keep) .Case("ONLY_IF_RO", Token::kw_only_if_ro) .Case("ONLY_IF_RW", Token::kw_only_if_rw) + .Case("ORIGIN", Token::kw_origin) + .Case("org", Token::kw_origin) + .Case("o", Token::kw_origin) .Case("OUTPUT_ARCH", Token::kw_output_arch) .Case("OUTPUT_FORMAT", Token::kw_output_format) .Case("OVERLAY", Token::kw_overlay) @@ -933,6 +943,12 @@ LinkerScript *Parser::parse() { _script._commands.push_back(entry); break; } + case Token::kw_memory: { + Memory *memory = parseMemory(); + if (!memory) + return nullptr; + break; + } case Token::kw_search_dir: { SearchDir *searchDir = parseSearchDir(); if (!searchDir) @@ -1347,6 +1363,84 @@ Entry *Parser::parseEntry() { return new (_alloc) Entry(entryName); } +MemoryAttributes *Parser::parseMemoryAttributes() { + StringRef attribute_string; + bool negated = false; + if (!expectAndConsume(Token::l_paren, "expected (")) + return nullptr; + + // If there's a !, it's at the beginning. + if (isNextToken(Token::exclaim)) { + consumeToken(); + negated = true; + } + switch (_tok._kind) { + case Token::identifier: + attribute_string = _tok._range; + break; + case Token::exclaim: + llvm_unreachable("unexpected !"); + default: + llvm_unreachable("Invalid token."); + } + consumeToken(); + if (!expectAndConsume(Token::r_paren, "expected )")) + return nullptr; + return new (_alloc) MemoryAttributes(attribute_string, negated); +} + +MemoryEntry *Parser::parseMemoryEntryDescription() { + MemoryAttributes *attr; + + consumeToken(); + StringRef regionName(_tok._range); + + // Attributes are optional. + if (isNextToken(Token::l_paren)) + attr = parseMemoryAttributes(); + + if (!expectAndConsume(Token::colon, "expected :")) + return nullptr; + if (!expectAndConsume(Token::kw_origin, "expected ORIGIN/org/o")) + return nullptr; + if (!expectAndConsume(Token::equal, "expected =")) + return nullptr; + StringRef origin(_tok._range); + if (!expectAndConsume(Token::number, "expected number")) + return nullptr; + + if (!expectAndConsume(Token::comma, "expected ,")) + return nullptr; + if (!expectAndConsume(Token::kw_length, "expect LENGTH/len/l")) + return nullptr; + if (!expectAndConsume(Token::equal, "expect =")) + return nullptr; + StringRef length(_tok._range); + if (!expectAndConsume(Token::number, "expect number")) + return nullptr; + return new (_alloc) MemoryEntry(regionName, *attr, origin, length); +} + +// Parse MEMORY construct. +Memory *Parser::parseMemory() { + std::vector entries; + assert(_tok._kind == Token::kw_memory && "Expected MEMORY!"); + consumeToken(); + if (!expectAndConsume(Token::l_brace, "expected {")) + return nullptr; + do { + if (_tok._kind != Token::identifier) { + error(_tok, "Expected identifier in MEMORY"); + return nullptr; + } + MemoryEntry *m_entry = parseMemoryEntryDescription(); + entries.push_back(m_entry); + } while (!isNextToken(Token::r_brace)); + if (!expectAndConsume(Token::r_brace, "expected }")) + return nullptr; + return new (_alloc) Memory(entries); +} + // Parse SEARCH_DIR(ident) SearchDir *Parser::parseSearchDir() { assert(_tok._kind == Token::kw_search_dir && "Expected SEARCH_DIR!");