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
This commit is contained in:
Michael J. Spencer
2012-12-08 00:47:36 +00:00
parent 7141554858
commit 9ff4be240a
16 changed files with 1020 additions and 5 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -1,3 +1,4 @@
add_subdirectory(Core)
add_subdirectory(Driver)
add_subdirectory(Passes)
add_subdirectory(ReaderWriter)

View File

@@ -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
)

View File

@@ -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">;

14
lld/lib/Driver/Driver.cpp Normal file
View File

@@ -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() {}

180
lld/lib/Driver/Drivers.cpp Normal file
View File

@@ -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);
}

View File

@@ -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>;

View File

@@ -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";
}

14
lld/lib/Driver/Target.cpp Normal file
View File

@@ -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() {}

View File

@@ -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>();
}

View File

@@ -2,5 +2,9 @@ add_lld_executable(lld
lld.cpp
)
target_link_libraries(lld
lldDriver
)
install(TARGETS lld
RUNTIME DESTINATION bin)

View File

@@ -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;
}