diff options
| -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) +*/  | 

