summaryrefslogtreecommitdiffstats
path: root/lld/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lld/lib')
-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
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>();
+}
OpenPOWER on IntegriCloud