[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