diff options
Diffstat (limited to 'lld')
| -rw-r--r-- | lld/include/lld/ReaderWriter/LinkerScript.h | 32 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/LinkerScript.cpp | 46 | ||||
| -rw-r--r-- | lld/test/LinkerScript/extern-bad-symbol.test | 22 | ||||
| -rw-r--r-- | lld/test/LinkerScript/extern-empty.test | 19 | ||||
| -rw-r--r-- | lld/test/LinkerScript/extern-valid.test | 29 |
5 files changed, 148 insertions, 0 deletions
diff --git a/lld/include/lld/ReaderWriter/LinkerScript.h b/lld/include/lld/ReaderWriter/LinkerScript.h index ada267cb84f..5c74ae1d3f1 100644 --- a/lld/include/lld/ReaderWriter/LinkerScript.h +++ b/lld/include/lld/ReaderWriter/LinkerScript.h @@ -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; diff --git a/lld/lib/ReaderWriter/LinkerScript.cpp b/lld/lib/ReaderWriter/LinkerScript.cpp index 26ed59549d0..e264c5c0d2a 100644 --- a/lld/lib/ReaderWriter/LinkerScript.cpp +++ b/lld/lib/ReaderWriter/LinkerScript.cpp @@ -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 diff --git a/lld/test/LinkerScript/extern-bad-symbol.test b/lld/test/LinkerScript/extern-bad-symbol.test new file mode 100644 index 00000000000..279a7cc2056 --- /dev/null +++ b/lld/test/LinkerScript/extern-bad-symbol.test @@ -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: +*/ diff --git a/lld/test/LinkerScript/extern-empty.test b/lld/test/LinkerScript/extern-empty.test new file mode 100644 index 00000000000..a5e1ece084d --- /dev/null +++ b/lld/test/LinkerScript/extern-empty.test @@ -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: +*/ diff --git a/lld/test/LinkerScript/extern-valid.test b/lld/test/LinkerScript/extern-valid.test new file mode 100644 index 00000000000..764b4668a34 --- /dev/null +++ b/lld/test/LinkerScript/extern-valid.test @@ -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) +*/ |

