summaryrefslogtreecommitdiffstats
path: root/lld
diff options
context:
space:
mode:
authorMichael J. Spencer <bigcheesegs@gmail.com>2012-12-08 00:47:36 +0000
committerMichael J. Spencer <bigcheesegs@gmail.com>2012-12-08 00:47:36 +0000
commit9ff4be240a3cfc19ac0b4215967626a9ea2b04d0 (patch)
tree5bbe2de0dd41e39d8d56e317b14a5704a370bfe7 /lld
parent7141554858d2d857aab0ac15474a5a631efe526c (diff)
downloadbcm5719-llvm-9ff4be240a3cfc19ac0b4215967626a9ea2b04d0.tar.gz
bcm5719-llvm-9ff4be240a3cfc19ac0b4215967626a9ea2b04d0.zip
Add the core architecture for the lld driver.
This includes selecting which driver to emulate, option parsing, invocation building, and running the link. This currently only supports a very basic subset of ld for x86_64-linux. lld -flavor ld obj.o -o obj or symlink lld as (ld , link, ld64, core) to get the desired behavior without -flavor. llvm-svn: 169659
Diffstat (limited to 'lld')
-rw-r--r--lld/include/lld/Core/ErrorOr.h213
-rw-r--r--lld/include/lld/Driver/Driver.h64
-rw-r--r--lld/include/lld/Driver/LinkerInvocation.h34
-rw-r--r--lld/include/lld/Driver/LinkerOptions.h126
-rw-r--r--lld/include/lld/Driver/Target.h46
-rw-r--r--lld/lib/CMakeLists.txt1
-rw-r--r--lld/lib/Driver/CMakeLists.txt29
-rw-r--r--lld/lib/Driver/CoreOptions.td7
-rw-r--r--lld/lib/Driver/Driver.cpp14
-rw-r--r--lld/lib/Driver/Drivers.cpp180
-rw-r--r--lld/lib/Driver/LDOptions.td13
-rw-r--r--lld/lib/Driver/LinkerInvocation.cpp70
-rw-r--r--lld/lib/Driver/Target.cpp14
-rw-r--r--lld/lib/Driver/Targets.cpp75
-rw-r--r--lld/tools/lld/CMakeLists.txt4
-rw-r--r--lld/tools/lld/lld.cpp135
16 files changed, 1020 insertions, 5 deletions
diff --git a/lld/include/lld/Core/ErrorOr.h b/lld/include/lld/Core/ErrorOr.h
new file mode 100644
index 00000000000..403b4a51aaf
--- /dev/null
+++ b/lld/include/lld/Core/ErrorOr.h
@@ -0,0 +1,213 @@
+//===- lld/Core/ErrorOr.h - Error Smart Pointer ---------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// Provides ErrorOr<T> smart pointer.
+///
+/// This should be moved to LLVMSupport when someone has time to make it c++03.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_CORE_ERROR_OR_H
+#define LLD_CORE_ERROR_OR_H
+
+#include "llvm/Support/AlignOf.h"
+#include "llvm/Support/system_error.h"
+
+#include <cassert>
+#include <type_traits>
+
+namespace lld {
+template<class T>
+class ErrorOrBase {
+ static const bool isRef = std::is_reference<T>::value;
+ typedef std::reference_wrapper<typename std::remove_reference<T>::type> wrap;
+
+public:
+ typedef typename
+ std::conditional< isRef
+ , wrap
+ , T
+ >::type storage_type;
+
+private:
+ typedef T &reference;
+ typedef typename std::remove_reference<T>::type *pointer;
+
+ ErrorOrBase(const ErrorOrBase&) LLVM_DELETED_FUNCTION;
+ ErrorOrBase &operator =(const ErrorOrBase&) LLVM_DELETED_FUNCTION;
+ ErrorOrBase(ErrorOrBase &&other) LLVM_DELETED_FUNCTION;
+ ErrorOrBase &operator =(ErrorOrBase &&other) LLVM_DELETED_FUNCTION;
+
+public:
+ ErrorOrBase() : _error(llvm::make_error_code(llvm::errc::invalid_argument)) {}
+
+ ErrorOrBase(llvm::error_code ec) {
+ if (!_error)
+ get()->~storage_type();
+ _error = ec;
+ }
+
+ ErrorOrBase(T t) : _error(llvm::error_code::success()) {
+ new (get()) storage_type(t);
+ }
+
+ ~ErrorOrBase() {
+ if (!_error)
+ get()->~storage_type();
+ }
+
+ /// \brief Return false if there is an error.
+ operator bool() {
+ return !_error;
+ }
+
+ operator llvm::error_code() {
+ return _error;
+ }
+
+ operator reference() {
+ return *get();
+ }
+
+ pointer operator ->() {
+ return toPointer(get());
+ }
+
+ reference operator *() {
+ return *get();
+ }
+
+private:
+ pointer toPointer(pointer t) {
+ return t;
+ }
+
+ pointer toPointer(wrap *t) {
+ return &t->get();
+ }
+
+protected:
+ storage_type *get() {
+ assert(!_error && "T not valid!");
+ return reinterpret_cast<storage_type*>(_t.buffer);
+ }
+
+ llvm::error_code _error;
+ llvm::AlignedCharArrayUnion<storage_type> _t;
+};
+
+/// \brief Represents either an error or a value T.
+///
+/// ErrorOr<T> is a pointer-like class that represents the result of an
+/// operation. The result is either an error, or a value of type T. This is
+/// designed to emulate the usage of returning a pointer where nullptr indicates
+/// failure. However instead of just knowing that the operation failed, we also
+/// have an error_code that describes why it failed.
+///
+/// It is used like the following.
+/// \code
+/// ErrorOr<Buffer> getBuffer();
+/// void handleError(error_code ec);
+///
+/// auto buffer = getBuffer();
+/// if (!buffer)
+/// handleError(buffer);
+/// buffer->write("adena");
+/// \endcode
+///
+/// An implicit conversion to bool provides a way to check if there was an
+/// error. The unary * and -> operators provide pointer like access to the
+/// value. Accessing the value when there is an error has undefined behavior.
+///
+/// When T is a reference type the behaivor is slightly different. The reference
+/// is held in a std::reference_wrapper<std::remove_reference<T>::type>, and
+/// there is special handling to make operator -> work as if T was not a
+/// reference.
+///
+/// T cannot be a rvalue reference.
+template<class T,
+ bool isMoveable =
+ std::is_move_constructible<typename ErrorOrBase<T>::storage_type>::value>
+class ErrorOr;
+
+template<class T>
+class ErrorOr<T, true> : public ErrorOrBase<T> {
+ ErrorOr(const ErrorOr &other) LLVM_DELETED_FUNCTION;
+ ErrorOr &operator =(const ErrorOr &other) LLVM_DELETED_FUNCTION;
+public:
+ ErrorOr(llvm::error_code ec) : ErrorOrBase<T>(ec) {}
+ ErrorOr(T t) : ErrorOrBase<T>(t) {}
+ ErrorOr(ErrorOr &&other) : ErrorOrBase<T>() {
+ // Get the other value.
+ if (!other._error)
+ new (this->get())
+ typename ErrorOrBase<T>::storage_type(std::move(*other.get()));
+
+ // Get the other error.
+ this->_error = other._error;
+
+ // Make sure other doesn't try to delete its storage.
+ other._error = llvm::make_error_code(llvm::errc::invalid_argument);
+ }
+
+ ErrorOr &operator =(ErrorOr &&other) {
+ // Delete any existing value.
+ if (!this->_error)
+ this->get()->~storage_type();
+
+ // Get the other value.
+ if (!other._error)
+ new (this->get())
+ typename ErrorOrBase<T>::storage_type(std::move(*other.get()));
+
+ // Get the other error.
+ this->_error = other._error;
+
+ // Make sure other doesn't try to delete its storage.
+ other._error = llvm::make_error_code(llvm::errc::invalid_argument);
+ }
+};
+
+template<class T>
+class ErrorOr<T, false> : public ErrorOrBase<T> {
+ static_assert(std::is_copy_constructible<T>::value,
+ "T must be copy or move constructible!");
+
+ ErrorOr(ErrorOr &&other) LLVM_DELETED_FUNCTION;
+ ErrorOr &operator =(ErrorOr &&other) LLVM_DELETED_FUNCTION;
+public:
+ ErrorOr(llvm::error_code ec) : ErrorOrBase<T>(ec) {}
+ ErrorOr(T t) : ErrorOrBase<T>(t) {}
+ ErrorOr(const ErrorOr &other) : ErrorOrBase<T>() {
+ // Get the other value.
+ if (!other._error)
+ new (this->get()) typename ErrorOrBase<T>::storage_type(*other.get());
+
+ // Get the other error.
+ this->_error = other._error;
+ }
+
+ ErrorOr &operator =(const ErrorOr &other) {
+ // Delete any existing value.
+ if (!this->_error)
+ this->get()->~storage_type();
+
+ // Get the other value.
+ if (!other._error)
+ new (this->get()) typename ErrorOrBase<T>::storage_type(*other.get());
+
+ // Get the other error.
+ this->_error = other._error;
+ }
+};
+}
+
+#endif
diff --git a/lld/include/lld/Driver/Driver.h b/lld/include/lld/Driver/Driver.h
new file mode 100644
index 00000000000..d2ff7b45396
--- /dev/null
+++ b/lld/include/lld/Driver/Driver.h
@@ -0,0 +1,64 @@
+//===- lld/Driver/Driver.h - Linker Driver Emulator -----------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// Interface and factory for creating a specific driver emulator. A Driver is
+/// used to transform command line arguments into command line arguments for
+/// core. Core arguments are used to generate a LinkerOptions object.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_DRIVER_DRIVER_H
+#define LLD_DRIVER_DRIVER_H
+
+#include "lld/Core/LLVM.h"
+
+#include "llvm/Option/ArgList.h"
+
+#include <memory>
+#include <string>
+
+namespace lld {
+struct LinkerOptions;
+
+/// \brief Base class for all Drivers.
+class Driver {
+protected:
+ Driver(StringRef defaultTargetTriple)
+ : _defaultTargetTriple(defaultTargetTriple) {}
+
+ std::string _defaultTargetTriple;
+
+public:
+ enum class Flavor {
+ invalid,
+ ld,
+ link,
+ ld64,
+ core
+ };
+
+ virtual ~Driver();
+
+ virtual std::unique_ptr<llvm::opt::DerivedArgList>
+ transform(llvm::ArrayRef<const char *const> args) = 0;
+
+ /// \param flavor driver flavor to create.
+ /// \param defaultTargetTriple target triple as determined by the program name
+ /// or host. May be overridden by -target.
+ /// \returns the created driver.
+ static std::unique_ptr<Driver> create(Flavor flavor,
+ StringRef defaultTargetTriple);
+};
+
+LinkerOptions generateOptions(const llvm::opt::ArgList &args);
+} // end namespace lld
+
+#endif
diff --git a/lld/include/lld/Driver/LinkerInvocation.h b/lld/include/lld/Driver/LinkerInvocation.h
new file mode 100644
index 00000000000..d543ebb9d52
--- /dev/null
+++ b/lld/include/lld/Driver/LinkerInvocation.h
@@ -0,0 +1,34 @@
+//===- lld/Driver/LinkerInvocation.h - Linker Invocation ------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// Drives the actual link.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_DRIVER_LINKER_INVOCATION_H
+#define LLD_DRIVER_LINKER_INVOCATION_H
+
+#include "lld/Driver/LinkerOptions.h"
+
+namespace lld {
+class LinkerInvocation {
+public:
+ LinkerInvocation(const LinkerOptions &lo) : _options(lo) {}
+
+ /// \brief Perform the link.
+ void operator()();
+
+private:
+ const LinkerOptions &_options;
+};
+}
+
+#endif
diff --git a/lld/include/lld/Driver/LinkerOptions.h b/lld/include/lld/Driver/LinkerOptions.h
new file mode 100644
index 00000000000..801c401c176
--- /dev/null
+++ b/lld/include/lld/Driver/LinkerOptions.h
@@ -0,0 +1,126 @@
+//===- lld/Driver/LinkerOptions.h - Linker Options ------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// All linker options to be provided to a LinkerInvocation.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_DRIVER_LINKER_OPTIONS_H
+#define LLD_DRIVER_LINKER_OPTIONS_H
+
+#include "lld/Core/ErrorOr.h"
+#include "lld/Core/LLVM.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+#include <memory>
+
+namespace lld {
+enum class InputKind {
+ Unknown,
+ YAML,
+ Native,
+ Object,
+ LLVM,
+ Script
+};
+
+class LinkerInput {
+ LinkerInput(const LinkerInput &) LLVM_DELETED_FUNCTION;
+
+public:
+ LinkerInput(StringRef file, InputKind kind = InputKind::Unknown)
+ : _file(file)
+ , _kind(kind) {}
+
+ LinkerInput(llvm::MemoryBuffer *buffer, InputKind kind = InputKind::Unknown)
+ : _buffer(buffer)
+ , _file(_buffer->getBufferIdentifier())
+ , _kind(kind) {}
+
+ LinkerInput(LinkerInput &&other)
+ : _buffer(std::move(other._buffer))
+ , _file(std::move(other._file))
+ , _kind(other._kind) {}
+
+ ErrorOr<llvm::MemoryBuffer&> getBuffer() const {
+ if (!_buffer) {
+ llvm::OwningPtr<llvm::MemoryBuffer> buf;
+ if (error_code ec = llvm::MemoryBuffer::getFileOrSTDIN(_file, buf))
+ return ec;
+ _buffer.reset(buf.take());
+ }
+
+ return *_buffer;
+ }
+
+ ErrorOr<InputKind> getKind() const {
+ if (_kind == InputKind::Unknown) {
+ _kind = llvm::StringSwitch<InputKind>(getPath())
+ .EndsWith(".objtxt", InputKind::YAML)
+ .EndsWith(".yaml", InputKind::YAML)
+ .Default(InputKind::Unknown);
+
+ if (_kind != InputKind::Unknown)
+ return _kind;
+
+ auto buf = getBuffer();
+ if (!buf)
+ return error_code(buf);
+
+ llvm::sys::fs::file_magic magic =
+ llvm::sys::fs::identify_magic(buf->getBuffer());
+
+ switch (magic) {
+ case llvm::sys::fs::file_magic::elf_relocatable:
+ _kind = InputKind::Object;
+ break;
+ }
+ }
+
+ return _kind;
+ }
+
+ StringRef getPath() const {
+ return _file;
+ }
+
+private:
+ mutable std::unique_ptr<llvm::MemoryBuffer> _buffer;
+ std::string _file;
+ mutable InputKind _kind;
+};
+
+struct LinkerOptions {
+ LinkerOptions() {}
+ LinkerOptions(LinkerOptions &&other)
+ : _input(std::move(other._input))
+ , _target(std::move(other._target))
+ , _outputPath(std::move(other._outputPath))
+ , _entrySymbol(std::move(other._entrySymbol))
+ , _relocatable(other._relocatable) {}
+
+ std::vector<LinkerInput> _input;
+ std::string _target;
+ std::string _outputPath;
+ std::string _entrySymbol;
+ unsigned _relocatable : 1;
+
+private:
+ LinkerOptions(const LinkerOptions&) LLVM_DELETED_FUNCTION;
+};
+}
+
+#endif
diff --git a/lld/include/lld/Driver/Target.h b/lld/include/lld/Driver/Target.h
new file mode 100644
index 00000000000..5b06aee8c16
--- /dev/null
+++ b/lld/include/lld/Driver/Target.h
@@ -0,0 +1,46 @@
+//===- lld/Driver/Target.h - Linker Target Abstraction --------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// Interface and factory for creating a specific Target. A Target is used to
+/// encapsulate all of the target specific configurations for the linker.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_DRIVER_TARGET_H
+#define LLD_DRIVER_TARGET_H
+
+#include "lld/ReaderWriter/Reader.h"
+#include "lld/ReaderWriter/Writer.h"
+#include "lld/Driver/LinkerOptions.h"
+
+namespace lld {
+/// \brief Represents a specific target.
+class Target {
+public:
+ Target(const LinkerOptions &lo) : _options(lo) {}
+ virtual ~Target();
+
+ /// \brief Get a reference to a Reader for the given input.
+ ///
+ /// Will always return the same object for the same input.
+ virtual ErrorOr<lld::Reader&> getReader(const LinkerInput &input) = 0;
+
+ /// \brief Get the writer.
+ virtual ErrorOr<lld::Writer&> getWriter() = 0;
+
+ static std::unique_ptr<Target> create(const LinkerOptions&);
+
+protected:
+ const LinkerOptions &_options;
+};
+}
+
+#endif
diff --git a/lld/lib/CMakeLists.txt b/lld/lib/CMakeLists.txt
index 6a0bf989e0a..3a714e7b3b3 100644
--- a/lld/lib/CMakeLists.txt
+++ b/lld/lib/CMakeLists.txt
@@ -1,3 +1,4 @@
add_subdirectory(Core)
+add_subdirectory(Driver)
add_subdirectory(Passes)
add_subdirectory(ReaderWriter)
diff --git a/lld/lib/Driver/CMakeLists.txt b/lld/lib/Driver/CMakeLists.txt
new file mode 100644
index 00000000000..83b3953042f
--- /dev/null
+++ b/lld/lib/Driver/CMakeLists.txt
@@ -0,0 +1,29 @@
+set(LLVM_TARGET_DEFINITIONS LDOptions.td)
+tablegen(LLVM LDOptions.inc -gen-opt-parser-defs)
+set(LLVM_TARGET_DEFINITIONS CoreOptions.td)
+tablegen(LLVM CoreOptions.inc -gen-opt-parser-defs)
+add_public_tablegen_target(DriverOptionsTableGen)
+
+add_lld_library(lldDriver
+ Driver.cpp
+ Drivers.cpp
+ LinkerInvocation.cpp
+ Target.cpp
+ Targets.cpp
+ )
+
+add_dependencies(lldDriver DriverOptionsTableGen)
+
+target_link_libraries(lldDriver
+ lldPasses
+ lldMachO
+ lldPECOFF
+ lldELF
+ lldNative
+ lldReaderWriter
+ lldYAML
+ lldCore
+ LLVMObject
+ LLVMOption
+ LLVMSupport
+ )
diff --git a/lld/lib/Driver/CoreOptions.td b/lld/lib/Driver/CoreOptions.td
new file mode 100644
index 00000000000..b1c8acd40e9
--- /dev/null
+++ b/lld/lib/Driver/CoreOptions.td
@@ -0,0 +1,7 @@
+include "llvm/Option/OptParser.td"
+
+def target : Separate<["-"], "target">, HelpText<"Target triple to link for">;
+
+def output : Joined<["-"], "output=">;
+def entry : Joined<["-"], "entry=">;
+def relocatable : Flag<["-"], "relocatable">;
diff --git a/lld/lib/Driver/Driver.cpp b/lld/lib/Driver/Driver.cpp
new file mode 100644
index 00000000000..5f7f4e6f555
--- /dev/null
+++ b/lld/lib/Driver/Driver.cpp
@@ -0,0 +1,14 @@
+//===- lib/Driver/Driver.cpp - Linker Driver Emulator ---------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Driver/Driver.h"
+
+using namespace lld;
+
+Driver::~Driver() {}
diff --git a/lld/lib/Driver/Drivers.cpp b/lld/lib/Driver/Drivers.cpp
new file mode 100644
index 00000000000..b664765b198
--- /dev/null
+++ b/lld/lib/Driver/Drivers.cpp
@@ -0,0 +1,180 @@
+//===- lib/Driver/Drivers.cpp - Linker Driver Emulators -------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// Concrete instances of the Driver interface.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/Driver/Driver.h"
+
+#include "lld/Driver/LinkerOptions.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace lld;
+
+namespace core {
+enum ID {
+ OPT_INVALID = 0,
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, HELP, META) \
+ OPT_##ID,
+#include "CoreOptions.inc"
+ LastOption
+#undef OPTION
+};
+
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "CoreOptions.inc"
+#undef PREFIX
+
+static const llvm::opt::OptTable::Info InfoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR) \
+ { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS },
+#include "CoreOptions.inc"
+#undef OPTION
+};
+
+class CoreOptTable : public llvm::opt::OptTable {
+public:
+ CoreOptTable() : OptTable(InfoTable, llvm::array_lengthof(InfoTable)){}
+};
+}
+
+namespace ld {
+enum LDOpt {
+ OPT_INVALID = 0,
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, HELP, META) \
+ OPT_##ID,
+#include "LDOptions.inc"
+ LastOption
+#undef OPTION
+};
+
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "LDOptions.inc"
+#undef PREFIX
+
+static const llvm::opt::OptTable::Info InfoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR) \
+ { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS },
+#include "LDOptions.inc"
+#undef OPTION
+};
+
+class LDOptTable : public llvm::opt::OptTable {
+public:
+ LDOptTable() : OptTable(InfoTable, llvm::array_lengthof(InfoTable)){}
+};
+}
+
+class LDDriver final : public Driver {
+public:
+ LDDriver(StringRef defaultTargetTriple) : Driver(defaultTargetTriple) {}
+
+ virtual std::unique_ptr<llvm::opt::DerivedArgList>
+ transform(llvm::ArrayRef<const char *const> args) {
+ assert(!_inputArgs && "transform may only be called once!");
+
+ unsigned missingIndex, missingCount;
+ _inputArgs.reset(_opt.ParseArgs( args.begin(), args.end()
+ , missingIndex, missingCount));
+
+ if (missingCount) {
+ llvm::errs() << "error: missing arg value for '"
+ << _inputArgs->getArgString(missingIndex)
+ << "' expected " << missingCount << " argument(s).\n";
+ return std::unique_ptr<llvm::opt::DerivedArgList>();
+ }
+
+ std::unique_ptr<llvm::opt::DerivedArgList> newArgs(
+ new llvm::opt::DerivedArgList(*_inputArgs));
+
+ if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_target)) {
+ llvm::errs() << A->getValue() << "\n";
+ newArgs->AddSeparateArg( A, _core.getOption(core::OPT_target)
+ , A->getValue());
+ llvm::errs() << A->getValue() << "\n";
+ } else {
+ assert(!_defaultTargetTriple.empty() && "Got empty target triple!");
+ newArgs->AddSeparateArg(nullptr, _core.getOption(core::OPT_target)
+ , _defaultTargetTriple);
+ }
+
+ if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_entry))
+ newArgs->AddJoinedArg(A, _core.getOption(core::OPT_entry), A->getValue());
+ else
+ newArgs->AddJoinedArg(nullptr, _core.getOption(core::OPT_entry), "start");
+
+ if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_output))
+ newArgs->AddJoinedArg(A, _core.getOption(core::OPT_output),
+ A->getValue());
+ else
+ newArgs->AddJoinedArg(nullptr, _core.getOption(core::OPT_output),
+ "a.out");
+
+ if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_relocatable))
+ newArgs->AddFlagArg(A, _core.getOption(core::OPT_relocatable));
+
+ // Copy input args.
+ for (llvm::opt::arg_iterator it = _inputArgs->filtered_begin(ld::OPT_INPUT),
+ ie = _inputArgs->filtered_end();
+ it != ie; ++it) {
+ newArgs->AddPositionalArg(*it, _core.getOption(core::OPT_INPUT),
+ (*it)->getValue());
+ }
+
+ return std::move(newArgs);
+ }
+
+private:
+ std::unique_ptr<llvm::opt::InputArgList> _inputArgs;
+ core::CoreOptTable _core;
+ ld::LDOptTable _opt;
+};
+
+std::unique_ptr<Driver> Driver::create( Driver::Flavor flavor
+ , StringRef defaultTargetTriple) {
+ switch (flavor) {
+ case Flavor::ld:
+ return std::unique_ptr<Driver>(new LDDriver(defaultTargetTriple));
+ case Flavor::core:
+ case Flavor::ld64:
+ case Flavor::link:
+ case Flavor::invalid:
+ llvm_unreachable("Unsupported flavor");
+ }
+}
+
+LinkerOptions lld::generateOptions(const llvm::opt::ArgList &args) {
+ LinkerOptions ret;
+
+ for (llvm::opt::arg_iterator it = args.filtered_begin(ld::OPT_INPUT),
+ ie = args.filtered_end();
+ it != ie; ++it) {
+ ret._input.push_back(LinkerInput((*it)->getValue(), InputKind::Object));
+ }
+
+ ret._target = llvm::Triple::normalize(args.getLastArgValue(core::OPT_target));
+ ret._outputPath = args.getLastArgValue(core::OPT_output);
+ ret._entrySymbol = args.getLastArgValue(core::OPT_entry);
+ ret._relocatable = args.hasArg(core::OPT_relocatable);
+
+ return std::move(ret);
+}
diff --git a/lld/lib/Driver/LDOptions.td b/lld/lib/Driver/LDOptions.td
new file mode 100644
index 00000000000..87a50262ccc
--- /dev/null
+++ b/lld/lib/Driver/LDOptions.td
@@ -0,0 +1,13 @@
+include "llvm/Option/OptParser.td"
+
+def flavor : Separate<["-"], "flavor">;
+def target : Separate<["-"], "target">, HelpText<"Target triple to link for">;
+
+def entry : Joined<["--"], "entry=">;
+def entry_e : Separate<["-"], "e">, Alias<entry>;
+
+def output : Joined<["--"], "output=">;
+def output_e : Separate<["-"], "o">, Alias<output>;
+
+def relocatable : Flag<["--"], "relocatable">;
+def relocatable_r : Flag<["-"], "r">, Alias<relocatable>;
diff --git a/lld/lib/Driver/LinkerInvocation.cpp b/lld/lib/Driver/LinkerInvocation.cpp
new file mode 100644
index 00000000000..08581655c76
--- /dev/null
+++ b/lld/lib/Driver/LinkerInvocation.cpp
@@ -0,0 +1,70 @@
+//===- lib/Driver/LinkerInvocation.cpp - Linker Invocation ----------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Driver/LinkerInvocation.h"
+
+#include "lld/Core/InputFiles.h"
+#include "lld/Core/Resolver.h"
+#include "lld/Driver/Target.h"
+
+#include "llvm/Support/raw_ostream.h"
+
+using namespace lld;
+
+void LinkerInvocation::operator()() {
+ // Create target.
+ std::unique_ptr<Target> target(Target::create(_options));
+
+ if (!target) {
+ llvm::errs() << "Failed to create target for " << _options._target
+ << "\n";
+ return;
+ }
+
+ // Read inputs
+ InputFiles inputs;
+ for (const auto &input : _options._input) {
+ auto reader = target->getReader(input);
+ if (error_code ec = reader) {
+ llvm::errs() << "Failed to get reader for: " << input.getPath() << ": "
+ << ec.message() << "\n";
+ return;
+ }
+
+ auto buffer = input.getBuffer();
+ if (error_code ec = buffer) {
+ llvm::errs() << "Failed to read file: " << input.getPath() << ": "
+ << ec.message() << "\n";
+ return;
+ }
+
+ std::vector<std::unique_ptr<File>> files;
+ if (llvm::error_code ec = reader->readFile(
+ buffer->getBufferIdentifier(), files)) {
+ llvm::errs() << "Failed to read file: " << input.getPath() << ": "
+ << ec.message() << "\n";
+ return;
+ }
+ inputs.appendFiles(files);
+ }
+
+ ResolverOptions ro;
+ Resolver resolver(ro, inputs);
+ resolver.resolve();
+ File &merged = resolver.resultFile();
+
+ auto writer = target->getWriter();
+ if (error_code ec = writer) {
+ llvm::errs() << "Failed to get writer: " << ec.message() << ".\n";
+ return;
+ }
+
+ if (error_code ec = writer->writeFile(merged, _options._outputPath))
+ llvm::errs() << "Failed to write file: " << ec.message() << "\n";
+ }
diff --git a/lld/lib/Driver/Target.cpp b/lld/lib/Driver/Target.cpp
new file mode 100644
index 00000000000..8b90ebffd51
--- /dev/null
+++ b/lld/lib/Driver/Target.cpp
@@ -0,0 +1,14 @@
+//===- lib/Driver/Target.cpp - Linker Target Abstraction ------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Driver/Target.h"
+
+using namespace lld;
+
+Target::~Target() {}
diff --git a/lld/lib/Driver/Targets.cpp b/lld/lib/Driver/Targets.cpp
new file mode 100644
index 00000000000..de4ca31e8f0
--- /dev/null
+++ b/lld/lib/Driver/Targets.cpp
@@ -0,0 +1,75 @@
+//===- lib/Driver/Targets.cpp - Linker Targets ----------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// Concrete instances of the Target interface.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/Driver/Target.h"
+
+#include "lld/ReaderWriter/ReaderArchive.h"
+#include "lld/ReaderWriter/ReaderELF.h"
+#include "lld/ReaderWriter/ReaderYAML.h"
+#include "lld/ReaderWriter/WriterELF.h"
+
+#include "llvm/ADT/Triple.h"
+
+using namespace lld;
+
+class X86LinuxTarget final : public Target {
+public:
+ X86LinuxTarget(const LinkerOptions &lo) : Target(lo) {
+ _readerELF.reset(createReaderELF(_roe, _roa));
+ _readerYAML.reset(createReaderYAML(_roy));
+ _writer.reset(createWriterELF(_woe));
+ }
+
+ virtual ErrorOr<lld::Reader&> getReader(const LinkerInput &input) {
+ auto kind = input.getKind();
+ if (!kind)
+ return error_code(kind);
+
+ if (*kind == InputKind::YAML)
+ return *_readerYAML;
+
+ if (*kind == InputKind::Object)
+ return *_readerELF;
+
+ return llvm::make_error_code(llvm::errc::invalid_argument);
+ }
+
+ virtual ErrorOr<lld::Writer&> getWriter() {
+ return *_writer;
+ }
+
+private:
+ lld::ReaderOptionsELF _roe;
+ lld::ReaderOptionsArchive _roa;
+ struct : lld::ReaderOptionsYAML {
+ virtual Reference::Kind kindFromString(StringRef kindName) const {
+ int k;
+ if (kindName.getAsInteger(0, k))
+ k = 0;
+ return k;
+ }
+ } _roy;
+ lld::WriterOptionsELF _woe;
+
+ std::unique_ptr<lld::Reader> _readerELF, _readerYAML;
+ std::unique_ptr<lld::Writer> _writer;
+};
+
+std::unique_ptr<Target> Target::create(const LinkerOptions &lo) {
+ llvm::Triple t(lo._target);
+ if (t.getOS() == llvm::Triple::Linux && t.getArch() == llvm::Triple::x86_64)
+ return std::unique_ptr<Target>(new X86LinuxTarget(lo));
+ return std::unique_ptr<Target>();
+}
diff --git a/lld/tools/lld/CMakeLists.txt b/lld/tools/lld/CMakeLists.txt
index ee0b47e4b1a..d6a2b1cc64e 100644
--- a/lld/tools/lld/CMakeLists.txt
+++ b/lld/tools/lld/CMakeLists.txt
@@ -2,5 +2,9 @@ add_lld_executable(lld
lld.cpp
)
+target_link_libraries(lld
+ lldDriver
+ )
+
install(TARGETS lld
RUNTIME DESTINATION bin)
diff --git a/lld/tools/lld/lld.cpp b/lld/tools/lld/lld.cpp
index 74329b60a85..c4670b77469 100644
--- a/lld/tools/lld/lld.cpp
+++ b/lld/tools/lld/lld.cpp
@@ -1,4 +1,4 @@
-//===- tools/lld/lld.cpp - Linker Driver Dispatcher ---------------------===//
+//===- tools/lld/lld.cpp - Linker Driver Dispatcher -----------------------===//
//
// The LLVM Linker
//
@@ -6,12 +6,137 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-//
-// This is the entry point to the lld driver. This is a thin wrapper which
-// dispatches to the given platform specific driver.
-//
+///
+/// \file
+///
+/// This is the entry point to the lld driver. This is a thin wrapper which
+/// dispatches to the given platform specific driver.
+///
//===----------------------------------------------------------------------===//
+#include "lld/Core/LLVM.h"
+#include "lld/Driver/Driver.h"
+#include "lld/Driver/LinkerInvocation.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Signals.h"
+
+using namespace lld;
+
+Driver::Flavor strToFlavor(StringRef str) {
+ return llvm::StringSwitch<Driver::Flavor>(str)
+ .Case("ld", Driver::Flavor::ld)
+ .Case("link", Driver::Flavor::link)
+ .Case("ld64", Driver::Flavor::ld64)
+ .Case("core", Driver::Flavor::core)
+ .Default(Driver::Flavor::invalid);
+}
+
+struct ProgramNameParts {
+ StringRef _target;
+ StringRef _flavor;
+};
+
+ProgramNameParts parseProgramName(StringRef programName) {
+ SmallVector<StringRef, 3> components;
+ llvm::SplitString(programName, components, "-");
+ ProgramNameParts ret;
+
+ using std::begin;
+ using std::end;
+
+ // Erase any lld components.
+ components.erase(std::remove(components.begin(), components.end(), "lld"),
+ components.end());
+
+ // Find the flavor component.
+ auto flIter = std::find_if(components.begin(), components.end(),
+ [](StringRef str) -> bool {
+ return strToFlavor(str) != Driver::Flavor::invalid;
+ });
+
+ if (flIter != components.end()) {
+ ret._flavor = *flIter;
+ components.erase(flIter);
+ }
+
+ // Any remaining component must be the target.
+ if (components.size() == 1)
+ ret._target = components[0];
+
+ return ret;
+}
+
+/// \brief Pick the flavor of driver to use based on the command line and
+/// host environment.
+Driver::Flavor selectFlavor(int argc, const char * const * const argv) {
+ if (argc >= 2 && StringRef(argv[1]) == "-core")
+ return Driver::Flavor::core;
+ if (argc >= 3 && StringRef(argv[1]) == "-flavor") {
+ Driver::Flavor flavor = strToFlavor(argv[2]);
+ if (flavor == Driver::Flavor::invalid)
+ llvm::errs() << "error: '" << argv[2] << "' invalid value for -flavor.\n";
+ return flavor;
+ }
+
+ Driver::Flavor flavor = strToFlavor(
+ parseProgramName(llvm::sys::path::stem(argv[0]))._flavor);
+
+ if (flavor == Driver::Flavor::invalid)
+ llvm::errs() << "error: failed to determine driver flavor from program name"
+ " '" << argv[0] << "'.\n";
+ return flavor;
+}
+
+/// \brief Get the default target triple based on either the program name or
+/// the primary target llvm was configured for.
+std::string getDefaultTarget(int argc, const char *const *const argv) {
+ std::string ret = parseProgramName(llvm::sys::path::stem(argv[0]))._target;
+ if (ret.empty())
+ ret = llvm::sys::getDefaultTargetTriple();
+ return ret;
+}
+
int main(int argc, char **argv) {
+ llvm::sys::PrintStackTraceOnErrorSignal();
+ llvm::PrettyStackTraceProgram X(argc, argv);
+ llvm::llvm_shutdown_obj Y;
+
+ Driver::Flavor iHazAFlavor = selectFlavor(argc, argv);
+ if (iHazAFlavor == Driver::Flavor::invalid)
+ return 1;
+
+ std::unique_ptr<llvm::opt::ArgList> coreArgs;
+ std::unique_ptr<Driver> driver;
+ if (iHazAFlavor != Driver::Flavor::core) {
+ // Transform to core arguments.
+ driver = Driver::create(iHazAFlavor, getDefaultTarget(argc, argv));
+ coreArgs = driver->transform(
+ llvm::ArrayRef<const char *const>(argv + 1, argv + argc));
+ }
+
+ if (!coreArgs)
+ return 1;
+
+ for (auto arg : *coreArgs) {
+ llvm::outs() << arg->getAsString(*coreArgs) << " ";
+ }
+ llvm::outs() << "\n";
+
+ LinkerOptions lo(generateOptions(*coreArgs));
+ LinkerInvocation invocation(lo);
+ invocation();
+
return 0;
}
OpenPOWER on IntegriCloud