diff options
Diffstat (limited to 'lld/lib')
-rw-r--r-- | lld/lib/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lld/lib/Driver/CMakeLists.txt | 29 | ||||
-rw-r--r-- | lld/lib/Driver/CoreOptions.td | 7 | ||||
-rw-r--r-- | lld/lib/Driver/Driver.cpp | 14 | ||||
-rw-r--r-- | lld/lib/Driver/Drivers.cpp | 180 | ||||
-rw-r--r-- | lld/lib/Driver/LDOptions.td | 13 | ||||
-rw-r--r-- | lld/lib/Driver/LinkerInvocation.cpp | 70 | ||||
-rw-r--r-- | lld/lib/Driver/Target.cpp | 14 | ||||
-rw-r--r-- | lld/lib/Driver/Targets.cpp | 75 |
9 files changed, 403 insertions, 0 deletions
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>(); +} |