[lld] r176309 - Add basic linker script parsing.

Michael J. Spencer bigcheesegs at gmail.com
Thu Feb 28 16:03:36 PST 2013


Author: mspencer
Date: Thu Feb 28 18:03:36 2013
New Revision: 176309

URL: http://llvm.org/viewvc/llvm-project?rev=176309&view=rev
Log:
Add basic linker script parsing.

Added:
    lld/trunk/include/lld/ReaderWriter/LinkerScript.h
    lld/trunk/include/lld/ReaderWriter/ReaderLinkerScript.h
    lld/trunk/lib/ReaderWriter/LinkerScript.cpp
    lld/trunk/lib/ReaderWriter/ReaderLinkerScript.cpp
    lld/trunk/test/linker-script.test
    lld/trunk/utils/CMakeLists.txt
    lld/trunk/utils/linker-script-test/
    lld/trunk/utils/linker-script-test/CMakeLists.txt
    lld/trunk/utils/linker-script-test/linker-script-test.cpp
Modified:
    lld/trunk/CMakeLists.txt
    lld/trunk/include/lld/Core/Error.h
    lld/trunk/include/lld/Core/File.h
    lld/trunk/include/lld/ReaderWriter/ELFTargetInfo.h
    lld/trunk/lib/Core/Error.cpp
    lld/trunk/lib/ReaderWriter/CMakeLists.txt
    lld/trunk/lib/ReaderWriter/ELF/ELFTargetInfo.cpp
    lld/trunk/test/CMakeLists.txt

Modified: lld/trunk/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/CMakeLists.txt?rev=176309&r1=176308&r2=176309&view=diff
==============================================================================
--- lld/trunk/CMakeLists.txt (original)
+++ lld/trunk/CMakeLists.txt Thu Feb 28 18:03:36 2013
@@ -141,6 +141,7 @@ install(DIRECTORY include/
 
 add_subdirectory(lib)
 add_subdirectory(tools)
+add_subdirectory(utils)
 
 add_subdirectory(test)
 

Modified: lld/trunk/include/lld/Core/Error.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/Error.h?rev=176309&r1=176308&r2=176309&view=diff
==============================================================================
--- lld/trunk/include/lld/Core/Error.h (original)
+++ lld/trunk/include/lld/Core/Error.h Thu Feb 28 18:03:36 2013
@@ -59,6 +59,16 @@ inline llvm::error_code make_error_code(
   return llvm::error_code(static_cast<int>(e), yaml_reader_category());
 }
 
+const llvm::error_category &linker_script_reader_category();
+
+enum class linker_script_reader_error {
+  success = 0,
+  parse_error
+};
+
+inline llvm::error_code make_error_code(linker_script_reader_error e) {
+  return llvm::error_code(static_cast<int>(e), linker_script_reader_category());
+}
 } // end namespace lld
 
 namespace llvm {
@@ -71,6 +81,8 @@ template <> struct is_error_code_enum<ll
 template <>
 struct is_error_code_enum<lld::yaml_reader_error::_> : true_type { };
 
+template <>
+struct is_error_code_enum<lld::linker_script_reader_error> : true_type { };
 } // end namespace llvm
 
 #endif

Modified: lld/trunk/include/lld/Core/File.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/File.h?rev=176309&r1=176308&r2=176309&view=diff
==============================================================================
--- lld/trunk/include/lld/Core/File.h (original)
+++ lld/trunk/include/lld/Core/File.h Thu Feb 28 18:03:36 2013
@@ -44,6 +44,7 @@ public:
     kindObject,            ///< object file (.o)
     kindSharedLibrary,     ///< shared library (.so)
     kindArchiveLibrary,    ///< archive (.a)
+    kindLinkerScript,      ///< linker script
   };
 
   /// \brief Returns file kind.  Need for dyn_cast<> on File objects.

Modified: lld/trunk/include/lld/ReaderWriter/ELFTargetInfo.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/ELFTargetInfo.h?rev=176309&r1=176308&r2=176309&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/ELFTargetInfo.h (original)
+++ lld/trunk/include/lld/ReaderWriter/ELFTargetInfo.h Thu Feb 28 18:03:36 2013
@@ -92,7 +92,8 @@ public:
 
 protected:
   std::unique_ptr<TargetHandlerBase> _targetHandler;
-  mutable std::unique_ptr<Reader> _reader;
+  mutable std::unique_ptr<Reader> _elfReader;
+  mutable std::unique_ptr<Reader> _linkerScriptReader;
   mutable std::unique_ptr<Writer> _writer;
 };
 } // end namespace lld

Added: lld/trunk/include/lld/ReaderWriter/LinkerScript.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/LinkerScript.h?rev=176309&view=auto
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/LinkerScript.h (added)
+++ lld/trunk/include/lld/ReaderWriter/LinkerScript.h Thu Feb 28 18:03:36 2013
@@ -0,0 +1,202 @@
+//===- ReaderWriter/LinkerScript.h ----------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Linker script parser.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_LINKER_SCRIPT_H
+#define LLD_READER_WRITER_LINKER_SCRIPT_H
+
+#include "lld/Core/LLVM.h"
+
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/system_error.h"
+
+namespace lld {
+namespace script {
+class Token {
+public:
+  enum Kind {
+    unknown,
+    eof,
+    identifier,
+    l_paren,
+    r_paren,
+    kw_group,
+    kw_output_format,
+    kw_as_needed
+  };
+
+  Token() : _kind(unknown) {}
+  Token(StringRef range, Kind kind) : _range(range), _kind(kind) {}
+
+  void dump(llvm::raw_ostream &os) const;
+
+  StringRef _range;
+  Kind _kind;
+};
+
+class Lexer {
+public:
+  Lexer(std::unique_ptr<llvm::MemoryBuffer> mb) : _buffer(mb->getBuffer()) {
+    _sourceManager.AddNewSourceBuffer(mb.release(), llvm::SMLoc());
+  }
+
+  void lex(Token &tok);
+
+  const llvm::SourceMgr &getSourceMgr() const { return _sourceManager; }
+
+private:
+  bool canStartName(char c) const;
+  bool canContinueName(char c) const;
+  void skipWhitespace();
+
+  Token _current;
+  /// \brief The current buffer state.
+  StringRef _buffer;
+  // Lexer owns the input files.
+  llvm::SourceMgr _sourceManager;
+};
+
+class Command {
+public:
+  enum class Kind {
+    OutputFormat,
+    Group,
+  };
+
+  Kind getKind() const { return _kind; }
+
+  virtual void dump(llvm::raw_ostream &os) const = 0;
+
+protected:
+  Command(Kind k) : _kind(k) {}
+
+private:
+  Kind _kind;
+};
+
+class OutputFormat : public Command {
+public:
+  OutputFormat(StringRef format)
+      : Command(Kind::OutputFormat), _format(format) {}
+
+  static bool classof(const Command *c) {
+    return c->getKind() == Kind::OutputFormat;
+  }
+
+  virtual void dump(llvm::raw_ostream &os) const {
+    os << "OUTPUT_FORMAT(" << getFormat() << ")\n";
+  }
+
+  StringRef getFormat() const { return _format; }
+
+private:
+  StringRef _format;
+};
+
+struct Path {
+  StringRef _path;
+  bool _asNeeded;
+
+  Path() : _asNeeded(false) {}
+  Path(StringRef path, bool asNeeded = false)
+      : _path(path), _asNeeded(asNeeded) {}
+};
+
+class Group : public Command {
+public:
+  template <class RangeT> Group(RangeT range) : Command(Kind::Group) {
+    using std::begin;
+    using std::end;
+    std::copy(begin(range), end(range), std::back_inserter(_paths));
+  }
+
+  static bool classof(const Command *c) { return c->getKind() == Kind::Group; }
+
+  virtual void dump(llvm::raw_ostream &os) const {
+    os << "GROUP(";
+    bool first = true;
+    for (const auto &path : getPaths()) {
+      if (!first)
+        os << " ";
+      else
+        first = false;
+      if (path._asNeeded)
+        os << "AS_NEEDED(";
+      os << path._path;
+      if (path._asNeeded)
+        os << ")";
+    }
+    os << ")\n";
+  }
+
+  const std::vector<Path> &getPaths() const { return _paths; }
+
+private:
+  std::vector<Path> _paths;
+};
+
+class LinkerScript {
+public:
+  void dump(llvm::raw_ostream &os) const {
+    for (const auto &c : _commands)
+      c->dump(os);
+  }
+
+  std::vector<Command *> _commands;
+};
+
+class Parser {
+public:
+  Parser(Lexer &lex) : _lex(lex) {}
+
+  LinkerScript *parse();
+
+private:
+  void consumeToken() { _lex.lex(_tok); }
+
+  void error(const Token &tok, Twine msg) {
+    _lex.getSourceMgr()
+        .PrintMessage(llvm::SMLoc::getFromPointer(tok._range.data()),
+                      llvm::SourceMgr::DK_Error, msg);
+  }
+
+  bool expectAndConsume(Token::Kind kind, Twine msg) {
+    if (_tok._kind != kind) {
+      error(_tok, msg);
+      return false;
+    }
+    consumeToken();
+    return true;
+  }
+
+  OutputFormat *parseOutputFormat();
+
+  Group *parseGroup();
+
+  bool parseAsNeeded(std::vector<Path> &paths);
+
+private:
+  llvm::BumpPtrAllocator _alloc;
+  LinkerScript _script;
+  Lexer &_lex;
+  Token _tok;
+};
+} // end namespace script
+} // end namespace lld
+
+#endif

Added: lld/trunk/include/lld/ReaderWriter/ReaderLinkerScript.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/ReaderLinkerScript.h?rev=176309&view=auto
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/ReaderLinkerScript.h (added)
+++ lld/trunk/include/lld/ReaderWriter/ReaderLinkerScript.h Thu Feb 28 18:03:36 2013
@@ -0,0 +1,39 @@
+//===- lld/ReaderWriter/ReaderLinkerScript.h ------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_READER_WRITER_READER_LINKER_SCRIPT_H
+#define LLD_READER_WRITER_READER_LINKER_SCRIPT_H
+
+#include "lld/Core/LLVM.h"
+#include "lld/ReaderWriter/Reader.h"
+
+namespace lld {
+class File;
+class LinkerInput;
+class TargetInfo;
+
+/// \brief ReaderLinkerScript is a class for reading linker scripts
+class ReaderLinkerScript : public Reader {
+public:
+  ReaderLinkerScript(
+      const TargetInfo &ti,
+      std::function<ErrorOr<Reader &>(const LinkerInput &)> getReader)
+      : Reader(ti), _getReader(getReader) {}
+
+  /// \brief Returns a vector of Files that are contained in the archive file 
+  ///        pointed to by the Memorybuffer
+  error_code parseFile(std::unique_ptr<llvm::MemoryBuffer> mb,
+                       std::vector<std::unique_ptr<File>> &result);
+
+private:
+  std::function<ErrorOr<Reader &>(const LinkerInput &)> _getReader;
+};
+} // end namespace lld
+
+#endif

Modified: lld/trunk/lib/Core/Error.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/Error.cpp?rev=176309&r1=176308&r2=176309&view=diff
==============================================================================
--- lld/trunk/lib/Core/Error.cpp (original)
+++ lld/trunk/lib/Core/Error.cpp Thu Feb 28 18:03:36 2013
@@ -51,10 +51,6 @@ const llvm::error_category &lld::native_
   return o;
 }
 
-inline llvm::error_code make_error_code(native_reader_error e) {
-  return llvm::error_code(static_cast<int>(e), native_reader_category());
-}
-
 class _yaml_reader_error_category : public llvm::_do_message {
 public:
   virtual const char* name() const {
@@ -87,6 +83,32 @@ const llvm::error_category &lld::yaml_re
   return o;
 }
 
-inline llvm::error_code make_error_code(yaml_reader_error e) {
-  return llvm::error_code(static_cast<int>(e), yaml_reader_category());
+class _linker_script_reader_error_category : public llvm::_do_message {
+public:
+  virtual const char *name() const { return "lld.linker-script.reader"; }
+
+  virtual std::string message(int ev) const {
+    switch (ev) {
+    case static_cast<int>(linker_script_reader_error::success):
+      return "Success";
+    case static_cast<int>(linker_script_reader_error::parse_error):
+      return "Error parsing linker script";
+    default:
+      llvm_unreachable(
+          "An enumerator of linker_script_reader_error does not have a "
+          "message defined.");
+    }
+  }
+
+  virtual llvm::error_condition default_error_condition(int ev) const {
+    if (ev == static_cast<int>(linker_script_reader_error::success))
+      return llvm::errc::success;
+    return llvm::errc::invalid_argument;
+  }
+};
+
+const llvm::error_category &lld::linker_script_reader_category() {
+  static _linker_script_reader_error_category o;
+  return o;
 }
+

Modified: lld/trunk/lib/ReaderWriter/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/CMakeLists.txt?rev=176309&r1=176308&r2=176309&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/CMakeLists.txt (original)
+++ lld/trunk/lib/ReaderWriter/CMakeLists.txt Thu Feb 28 18:03:36 2013
@@ -6,9 +6,11 @@ add_subdirectory(Native)
 add_subdirectory(PECOFF)
 add_subdirectory(YAML)
 add_lld_library(lldReaderWriter
+  LinkerScript.cpp
   Reader.cpp
-  Writer.cpp
   ReaderArchive.cpp
+  ReaderLinkerScript.cpp
+  Writer.cpp
   )
 
 target_link_libraries(lldReaderWriter

Modified: lld/trunk/lib/ReaderWriter/ELF/ELFTargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ELFTargetInfo.cpp?rev=176309&r1=176308&r2=176309&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/ELFTargetInfo.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/ELFTargetInfo.cpp Thu Feb 28 18:03:36 2013
@@ -14,9 +14,11 @@
 
 #include "lld/Core/LinkerOptions.h"
 #include "lld/Passes/LayoutPass.h"
+#include "lld/ReaderWriter/ReaderLinkerScript.h"
 
 #include "llvm/ADT/Triple.h"
 #include "llvm/Support/ELF.h"
+#include "llvm/Support/FileSystem.h"
 
 namespace lld {
 ELFTargetInfo::ELFTargetInfo(const LinkerOptions &lo) : TargetInfo(lo) {}
@@ -63,10 +65,24 @@ uint16_t ELFTargetInfo::getOutputMachine
 }
 
 ErrorOr<Reader &> ELFTargetInfo::getReader(const LinkerInput &input) const {
-  if (!_reader)
-    _reader = createReaderELF(*this, std::bind(&ELFTargetInfo::getReader, this,
-                                               std::placeholders::_1));
-  return *_reader;
+  auto buffer = input.getBuffer();
+  if (!buffer)
+    return error_code(buffer);
+  auto magic = llvm::sys::fs::identify_magic(buffer->getBuffer());
+  // Assume unknown file types are linker scripts.
+  if (magic == llvm::sys::fs::file_magic::unknown) {
+    if (!_linkerScriptReader)
+      _linkerScriptReader.reset(new ReaderLinkerScript(
+          *this,
+          std::bind(&ELFTargetInfo::getReader, this, std::placeholders::_1)));
+    return *_linkerScriptReader;
+  }
+
+  // Assume anything else is an ELF file.
+  if (!_elfReader)
+    _elfReader = createReaderELF(*this, std::bind(&ELFTargetInfo::getReader,
+                                                  this, std::placeholders::_1));
+  return *_elfReader;
 }
 
 ErrorOr<Writer &> ELFTargetInfo::getWriter() const {

Added: lld/trunk/lib/ReaderWriter/LinkerScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/LinkerScript.cpp?rev=176309&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/LinkerScript.cpp (added)
+++ lld/trunk/lib/ReaderWriter/LinkerScript.cpp Thu Feb 28 18:03:36 2013
@@ -0,0 +1,270 @@
+//===- ReaderWriter/LinkerScript.cpp --------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Linker script parser.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/ReaderWriter/LinkerScript.h"
+
+namespace lld {
+namespace script {
+void Token::dump(llvm::raw_ostream &os) const {
+  switch (_kind) {
+  case Token::eof:
+    os << "eof: ";
+    break;
+  case Token::identifier:
+    os << "identifier: ";
+    break;
+  case Token::kw_as_needed:
+    os << "kw_as_needed: ";
+    break;
+  case Token::kw_group:
+    os << "kw_group: ";
+    break;
+  case Token::kw_output_format:
+    os << "kw_output_format: ";
+    break;
+  case Token::l_paren:
+    os << "l_paren: ";
+    break;
+  case Token::r_paren:
+    os << "r_paren: ";
+    break;
+  case Token::unknown:
+    os << "unknown: ";
+    break;
+  }
+  os << _range << "\n";
+}
+
+bool Lexer::canStartName(char c) const {
+  switch (c) {
+  case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
+  case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
+  case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
+  case 'V': case 'W': case 'X': case 'Y': case 'Z':
+  case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
+  case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
+  case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
+  case 'v': case 'w': case 'x': case 'y': case 'z':
+  case '_': case '.': case '$': case '/': case '\\':
+    return true;
+  default:
+    return false;
+  }
+}
+
+bool Lexer::canContinueName(char c) const {
+  switch (c) {
+  case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
+  case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
+  case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
+  case 'V': case 'W': case 'X': case 'Y': case 'Z':
+  case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
+  case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
+  case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
+  case 'v': case 'w': case 'x': case 'y': case 'z':
+  case '0': case '1': case '2': case '3': case '4': case '5': case '6':
+  case '7': case '8': case '9':
+  case '_': case '.': case '$': case '/': case '\\': case '~': case '=':
+  case '+': case ',': case '[': case ']': case '*': case '?': case '-':
+    return true;
+  default:
+    return false;
+  }
+}
+
+void Lexer::lex(Token &tok) {
+  skipWhitespace();
+  if (_buffer.empty()) {
+    tok = Token(_buffer, Token::eof);
+    return;
+  }
+  switch (_buffer[0]) {
+  case 0:
+    tok = Token(_buffer.substr(0, 1), Token::eof);
+    _buffer = _buffer.drop_front();
+    return;
+  case '(':
+    tok = Token(_buffer.substr(0, 1), Token::l_paren);
+    _buffer = _buffer.drop_front();
+    return;
+  case ')':
+    tok = Token(_buffer.substr(0, 1), Token::r_paren);
+    _buffer = _buffer.drop_front();
+    return;
+  default:
+    /// keyword or identifer.
+    if (!canStartName(_buffer[0]))
+      break;
+    auto endIter =
+        std::find_if(_buffer.begin() + 1, _buffer.end(), [=](char c) {
+      return !canContinueName(c);
+    });
+    StringRef::size_type end =
+        endIter == _buffer.end() ? StringRef::npos
+                                 : std::distance(_buffer.begin(), endIter);
+    if (end == StringRef::npos || end == 0)
+      break;
+    StringRef word = _buffer.substr(0, end);
+    Token::Kind kind = llvm::StringSwitch<Token::Kind>(word)
+      .Case("OUTPUT_FORMAT", Token::kw_output_format)
+      .Case("GROUP", Token::kw_group)
+      .Case("AS_NEEDED", Token::kw_as_needed)
+      .Default(Token::identifier);
+    tok = Token(word, kind);
+    _buffer = _buffer.drop_front(end);
+    return;
+  }
+  tok = Token(_buffer.substr(0, 1), Token::unknown);
+  _buffer = _buffer.drop_front();
+}
+
+void Lexer::skipWhitespace() {
+  while (true) {
+    if (_buffer.empty())
+      return;
+    switch (_buffer[0]) {
+    case ' ':
+    case '\r':
+    case '\n':
+    case '\t':
+      _buffer = _buffer.drop_front();
+      break;
+    // Potential comment.
+    case '/':
+      if (_buffer.size() >= 2 && _buffer[1] == '*') {
+        // Skip starting /*
+        _buffer = _buffer.drop_front(2);
+        // If the next char is also a /, it's not the end.
+        if (!_buffer.empty() && _buffer[0] == '/')
+          _buffer = _buffer.drop_front();
+
+        // Scan for /'s. We're done if it is preceeded by a *.
+        while (true) {
+          if (_buffer.empty())
+            break;
+          _buffer = _buffer.drop_front();
+          if (_buffer.data()[-1] == '/' && _buffer.data()[-2] == '*')
+            break;
+        }
+      } else
+        return;
+      break;
+    default:
+      return;
+    }
+  }
+}
+
+LinkerScript *Parser::parse() {
+  // Get the first token.
+  _lex.lex(_tok);
+  // Parse top level commands.
+  while (true) {
+    switch (_tok._kind) {
+    case Token::eof:
+      return &_script;
+    case Token::kw_output_format: {
+      auto outputFormat = parseOutputFormat();
+      if (!outputFormat)
+        return nullptr;
+      _script._commands.push_back(outputFormat);
+      break;
+    }
+    case Token::kw_group: {
+      auto group = parseGroup();
+      if (!group)
+        return nullptr;
+      _script._commands.push_back(group);
+      break;
+    }
+    case Token::kw_as_needed:
+      // Not allowed at top level.
+      return nullptr;
+    default:
+      // Unexpected.
+      return nullptr;
+    }
+  }
+
+  return nullptr;
+}
+
+OutputFormat *Parser::parseOutputFormat() {
+  assert(_tok._kind == Token::kw_output_format && "Expected OUTPUT_FORMAT!");
+  consumeToken();
+  if (!expectAndConsume(Token::l_paren, "expected ("))
+    return nullptr;
+
+  if (_tok._kind != Token::identifier) {
+    error(_tok, "Expected identifer in OUTPUT_FORMAT.");
+    return nullptr;
+  }
+
+  auto ret = new (_alloc) OutputFormat(_tok._range);
+  consumeToken();
+
+  if (!expectAndConsume(Token::r_paren, "expected )"))
+    return nullptr;
+
+  return ret;
+}
+
+Group *Parser::parseGroup() {
+  assert(_tok._kind == Token::kw_group && "Expected GROUP!");
+  consumeToken();
+  if (!expectAndConsume(Token::l_paren, "expected ("))
+    return nullptr;
+
+  std::vector<Path> paths;
+
+  while (_tok._kind == Token::identifier || _tok._kind == Token::kw_as_needed) {
+    switch (_tok._kind) {
+    case Token::identifier:
+      paths.push_back(Path(_tok._range));
+      consumeToken();
+      break;
+    case Token::kw_as_needed:
+      if (!parseAsNeeded(paths))
+        return nullptr;
+      break;
+    default:
+      llvm_unreachable("Invalid token.");
+    }
+  }
+
+  auto ret = new (_alloc) Group(paths);
+
+  if (!expectAndConsume(Token::r_paren, "expected )"))
+    return nullptr;
+
+  return ret;
+}
+
+bool Parser::parseAsNeeded(std::vector<Path> &paths) {
+  assert(_tok._kind == Token::kw_as_needed && "Expected AS_NEEDED!");
+  consumeToken();
+  if (!expectAndConsume(Token::l_paren, "expected ("))
+    return false;
+
+  while (_tok._kind == Token::identifier) {
+    paths.push_back(Path(_tok._range, true));
+    consumeToken();
+  }
+
+  if (!expectAndConsume(Token::r_paren, "expected )"))
+    return false;
+  return true;
+}
+} // end namespace script
+} // end namespace lld

Added: lld/trunk/lib/ReaderWriter/ReaderLinkerScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ReaderLinkerScript.cpp?rev=176309&view=auto
==============================================================================
--- lld/trunk/lib/ReaderWriter/ReaderLinkerScript.cpp (added)
+++ lld/trunk/lib/ReaderWriter/ReaderLinkerScript.cpp Thu Feb 28 18:03:36 2013
@@ -0,0 +1,105 @@
+//===- lib/ReaderWriter/ReaderLinkerScript.cpp ----------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/ReaderWriter/ReaderLinkerScript.h"
+
+#include "lld/Core/Error.h"
+#include "lld/Core/File.h"
+#include "lld/Core/LinkerOptions.h"
+#include "lld/ReaderWriter/LinkerScript.h"
+
+using namespace lld;
+using namespace script;
+
+namespace {
+class LinkerScriptFile : public File {
+public:
+  static ErrorOr<std::unique_ptr<LinkerScriptFile> >
+  create(const TargetInfo &ti, std::unique_ptr<llvm::MemoryBuffer> mb) {
+    std::unique_ptr<LinkerScriptFile> file(
+        new LinkerScriptFile(ti, std::move(mb)));
+    file->_script = file->_parser.parse();
+    if (!file->_script)
+      return linker_script_reader_error::parse_error;
+    return std::move(file);
+  }
+
+  virtual Kind kind() const { return kindLinkerScript; }
+
+  static inline bool classof(const File *f) {
+    return f->kind() == kindLinkerScript;
+  }
+
+  virtual void setOrdinalAndIncrement(uint64_t &ordinal) const {
+    _ordinal = ordinal++;
+  }
+
+  virtual const TargetInfo &getTargetInfo() const { return _targetInfo; }
+
+  virtual const atom_collection<DefinedAtom> &defined() const {
+    return _definedAtoms;
+  }
+
+  virtual const atom_collection<UndefinedAtom> &undefined() const {
+    return _undefinedAtoms;
+  }
+
+  virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const {
+    return _sharedLibraryAtoms;
+  }
+
+  virtual const atom_collection<AbsoluteAtom> &absolute() const {
+    return _absoluteAtoms;
+  }
+
+  const LinkerScript *getScript() {
+    return _script;
+  }
+
+private:
+  LinkerScriptFile(const TargetInfo &ti, std::unique_ptr<llvm::MemoryBuffer> mb)
+      : File(mb->getBufferIdentifier()),
+        _targetInfo(ti),
+        _lexer(std::move(mb)),
+        _parser(_lexer),
+        _script(nullptr) {}
+
+  const TargetInfo &_targetInfo;
+  atom_collection_vector<DefinedAtom> _definedAtoms;
+  atom_collection_vector<UndefinedAtom> _undefinedAtoms;
+  atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
+  atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
+  Lexer _lexer;
+  Parser _parser;
+  const LinkerScript *_script;
+};
+} // end anon namespace
+
+namespace lld {
+error_code
+ReaderLinkerScript::parseFile(std::unique_ptr<llvm::MemoryBuffer> mb,
+                              std::vector<std::unique_ptr<File> > &result) {
+  auto lsf = LinkerScriptFile::create(_targetInfo, std::move(mb));
+  if (!lsf)
+    return lsf;
+  const LinkerScript *ls = (*lsf)->getScript();
+  result.push_back(std::move(*lsf));
+  for (const auto &c : ls->_commands) {
+    if (auto group = dyn_cast<Group>(c))
+      for (const auto &path : group->getPaths()) {
+        auto reader = _getReader(LinkerInput(path._path));
+        if (!reader)
+          return reader;
+        if (error_code ec = reader->readFile(path._path, result))
+          return ec;
+      }
+  }
+  return error_code::success();
+}
+} // end namespace lld

Modified: lld/trunk/test/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/CMakeLists.txt?rev=176309&r1=176308&r2=176309&view=diff
==============================================================================
--- lld/trunk/test/CMakeLists.txt (original)
+++ lld/trunk/test/CMakeLists.txt Thu Feb 28 18:03:36 2013
@@ -21,6 +21,7 @@ if ( NOT LLD_BUILT_STANDALONE )
     lld-core lld-test.deps
     FileCheck not llvm-nm
     lld llvm-objdump llvm-readobj
+    linker-script-test
     )
   set(LLD_TEST_PARAMS
     lld_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg

Added: lld/trunk/test/linker-script.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/linker-script.test?rev=176309&view=auto
==============================================================================
--- lld/trunk/test/linker-script.test (added)
+++ lld/trunk/test/linker-script.test Thu Feb 28 18:03:36 2013
@@ -0,0 +1,24 @@
+/* RUN: linker-script-test %s | FileCheck %s
+*/
+
+OUTPUT_FORMAT(elf64-x86-64)
+GROUP ( /lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/libc_nonshared.a  AS_NEEDED ( /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ) )
+
+/*
+CHECK: kw_output_format: OUTPUT_FORMAT
+CHECK: l_paren: (
+CHECK: identifier: elf64-x86-64
+CHECK: r_paren: )
+CHECK: kw_group: GROUP
+CHECK: l_paren: (
+CHECK: identifier: /lib/x86_64-linux-gnu/libc.so.6
+CHECK: identifier: /usr/lib/x86_64-linux-gnu/libc_nonshared.a
+CHECK: kw_as_needed: AS_NEEDED
+CHECK: l_paren: (
+CHECK: identifier: /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
+CHECK: r_paren: )
+CHECK: r_paren: )
+CHECK: eof:
+CHECK: OUTPUT_FORMAT(elf64-x86-64)
+CHECK: GROUP(/lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/libc_nonshared.a AS_NEEDED(/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2))
+*/

Added: lld/trunk/utils/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/utils/CMakeLists.txt?rev=176309&view=auto
==============================================================================
--- lld/trunk/utils/CMakeLists.txt (added)
+++ lld/trunk/utils/CMakeLists.txt Thu Feb 28 18:03:36 2013
@@ -0,0 +1 @@
+add_subdirectory(linker-script-test)

Added: lld/trunk/utils/linker-script-test/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/utils/linker-script-test/CMakeLists.txt?rev=176309&view=auto
==============================================================================
--- lld/trunk/utils/linker-script-test/CMakeLists.txt (added)
+++ lld/trunk/utils/linker-script-test/CMakeLists.txt Thu Feb 28 18:03:36 2013
@@ -0,0 +1,8 @@
+add_lld_executable(linker-script-test
+  linker-script-test.cpp
+  )
+
+target_link_libraries(linker-script-test
+  LLVMSupport
+  lldReaderWriter
+  )

Added: lld/trunk/utils/linker-script-test/linker-script-test.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/utils/linker-script-test/linker-script-test.cpp?rev=176309&view=auto
==============================================================================
--- lld/trunk/utils/linker-script-test/linker-script-test.cpp (added)
+++ lld/trunk/utils/linker-script-test/linker-script-test.cpp Thu Feb 28 18:03:36 2013
@@ -0,0 +1,55 @@
+//===- utils/linker-script-test/linker-script-test.cpp --------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Tool for testing linker script parsing.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/ReaderWriter/LinkerScript.h"
+
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+
+using namespace llvm;
+using namespace lld;
+using namespace script;
+
+int main(int argc, const char **argv) {
+  llvm::sys::PrintStackTraceOnErrorSignal();
+  llvm::PrettyStackTraceProgram X(argc, argv);
+
+  {
+    llvm::OwningPtr<MemoryBuffer> mb;
+    if (error_code ec = MemoryBuffer::getFileOrSTDIN(argv[1], mb)) {
+      llvm::errs() << ec.message() << "\n";
+      return 1;
+    }
+    Lexer l(std::unique_ptr<MemoryBuffer>(mb.take()));
+    Token tok;
+    while (true) {
+      l.lex(tok);
+      tok.dump(llvm::outs());
+      if (tok._kind == Token::eof || tok._kind == Token::unknown)
+        break;
+    }
+  }
+  {
+    llvm::OwningPtr<MemoryBuffer> mb;
+    if (error_code ec = MemoryBuffer::getFileOrSTDIN(argv[1], mb)) {
+      llvm::errs() << ec.message() << "\n";
+      return 1;
+    }
+    Lexer l(std::unique_ptr<MemoryBuffer>(mb.take()));
+    Parser p(l);
+    LinkerScript *ls = p.parse();
+    if (ls)
+      ls->dump(llvm::outs());
+  }
+}





More information about the llvm-commits mailing list