diff --git a/lld/include/lld/Core/LinkerOptions.h b/lld/include/lld/Core/LinkerOptions.h index 968ca4e2bae2..2eba90c9ff40 100644 --- a/lld/include/lld/Core/LinkerOptions.h +++ b/lld/include/lld/Core/LinkerOptions.h @@ -29,38 +29,31 @@ #include namespace lld { -enum class InputKind { - Unknown, - YAML, - Native, - Object, - LLVM, - Script -}; - +/// \brief An input to the linker. +/// +/// This class represents an input to the linker. It create the MemoryBuffer +/// lazily when needed based on the file path. It can also take a MemoryBuffer +/// directly. +/// +/// The intent is that we only open each file once. And have strong ownership +/// semantics. class LinkerInput { LinkerInput(const LinkerInput &) LLVM_DELETED_FUNCTION; public: - LinkerInput(StringRef file, InputKind kind = InputKind::Unknown) - : _file(file) - , _kind(kind) {} + LinkerInput(StringRef file) : _file(file) {} - LinkerInput(std::unique_ptr buffer, - InputKind kind = InputKind::Unknown) - : _buffer(std::move(buffer)) - , _file(_buffer->getBufferIdentifier()) - , _kind(kind) {} + LinkerInput(std::unique_ptr buffer) + : _buffer(std::move(buffer)), _file(_buffer->getBufferIdentifier()) { + } - LinkerInput(LinkerInput &&other) - : _buffer(std::move(other._buffer)) - , _file(std::move(other._file)) - , _kind(other._kind) {} + LinkerInput(LinkerInput && other) + : _buffer(std::move(other._buffer)), _file(std::move(other._file)) { + } LinkerInput &operator=(LinkerInput &&rhs) { _buffer = std::move(rhs._buffer); _file = std::move(rhs._file); - _kind = rhs._kind; return *this; } @@ -75,33 +68,6 @@ public: return *_buffer; } - ErrorOr getKind() const { - if (_kind == InputKind::Unknown) { - _kind = llvm::StringSwitch(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; } @@ -114,7 +80,6 @@ public: private: mutable std::unique_ptr _buffer; std::string _file; - mutable InputKind _kind; }; enum OutputKind { diff --git a/lld/include/lld/Core/TargetInfo.h b/lld/include/lld/Core/TargetInfo.h index 8d7adf745a2c..ef2326d38e72 100644 --- a/lld/include/lld/Core/TargetInfo.h +++ b/lld/include/lld/Core/TargetInfo.h @@ -31,8 +31,11 @@ namespace llvm { } namespace lld { +class LinkerInput; struct LinkerOptions; class PassManager; +class Reader; +class Writer; class TargetInfo { protected: @@ -53,6 +56,14 @@ public: virtual void addPasses(PassManager &pm) const {} + /// \brief Get a reference to a Reader for the given input. + /// + /// Will always return the same object for the same input. + virtual ErrorOr getReader(const LinkerInput &input) const = 0; + + /// \brief Get the writer. + virtual ErrorOr getWriter() const = 0; + // TODO: Split out to TargetRelocationInfo. virtual ErrorOr relocKindFromString(StringRef str) const { int32_t val; diff --git a/lld/include/lld/Driver/Target.h b/lld/include/lld/Driver/Target.h deleted file mode 100644 index b30d70709e9e..000000000000 --- a/lld/include/lld/Driver/Target.h +++ /dev/null @@ -1,58 +0,0 @@ -//===- 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/Core/TargetInfo.h" - -#include "llvm/Support/ErrorOr.h" - -#include - -namespace lld { -class LinkerInput; -struct LinkerOptions; -class Reader; -class TargetInfo; -class Writer; - -/// \brief Represents a specific target. -class Target { -protected: - Target(std::unique_ptr ti) : _targetInfo(std::move(ti)) {} - -public: - virtual ~Target(); - - const TargetInfo &getTargetInfo() const { return *_targetInfo; }; - - /// \brief Get a reference to a Reader for the given input. - /// - /// Will always return the same object for the same input. - virtual ErrorOr getReader(const LinkerInput &input) = 0; - - /// \brief Get the writer. - virtual ErrorOr getWriter() = 0; - - static std::unique_ptr create(const LinkerOptions&); - -protected: - std::unique_ptr _targetInfo; -}; -} - -#endif diff --git a/lld/include/lld/ReaderWriter/ELFTargetInfo.h b/lld/include/lld/ReaderWriter/ELFTargetInfo.h index 5a28ee5d6166..058714fcf1e9 100644 --- a/lld/include/lld/ReaderWriter/ELFTargetInfo.h +++ b/lld/include/lld/ReaderWriter/ELFTargetInfo.h @@ -12,6 +12,9 @@ #include "lld/Core/LinkerOptions.h" #include "lld/Core/TargetInfo.h" +#include "lld/ReaderWriter/Reader.h" +#include "lld/ReaderWriter/Writer.h" + #include "llvm/Object/ELF.h" #include "llvm/Support/ELF.h" @@ -30,7 +33,7 @@ public: class ELFTargetInfo : public TargetInfo { protected: - ELFTargetInfo(const LinkerOptions &lo) : TargetInfo(lo) {} + ELFTargetInfo(const LinkerOptions &lo); public: uint16_t getOutputType() const; @@ -44,6 +47,10 @@ public: return false; } + virtual ErrorOr getReader(const LinkerInput &input) const; + + virtual ErrorOr getWriter() const; + static std::unique_ptr create(const LinkerOptions &lo); template @@ -54,6 +61,8 @@ public: protected: std::unique_ptr _targetHandler; + mutable std::unique_ptr _reader; + mutable std::unique_ptr _writer; }; } // end namespace lld diff --git a/lld/include/lld/ReaderWriter/MachOTargetInfo.h b/lld/include/lld/ReaderWriter/MachOTargetInfo.h index 9055316f2699..7e8927bfd7db 100644 --- a/lld/include/lld/ReaderWriter/MachOTargetInfo.h +++ b/lld/include/lld/ReaderWriter/MachOTargetInfo.h @@ -12,6 +12,8 @@ #include "lld/Core/TargetInfo.h" +#include "llvm/Support/ErrorHandling.h" + #include namespace lld { @@ -28,6 +30,14 @@ public: virtual uint64_t getPageZeroSize() const = 0; + virtual ErrorOr getReader(const LinkerInput &input) const { + llvm_unreachable("Unimplemented!"); + } + + virtual ErrorOr getWriter() const { + llvm_unreachable("Unimplemented!"); + } + static std::unique_ptr create(const LinkerOptions &lo); }; } // end namespace lld diff --git a/lld/lib/Driver/CMakeLists.txt b/lld/lib/Driver/CMakeLists.txt index 83b3953042f0..13e6298b9a2d 100644 --- a/lld/lib/Driver/CMakeLists.txt +++ b/lld/lib/Driver/CMakeLists.txt @@ -8,8 +8,6 @@ add_lld_library(lldDriver Driver.cpp Drivers.cpp LinkerInvocation.cpp - Target.cpp - Targets.cpp ) add_dependencies(lldDriver DriverOptionsTableGen) diff --git a/lld/lib/Driver/Drivers.cpp b/lld/lib/Driver/Drivers.cpp index 00085e685f93..3c143eff684d 100644 --- a/lld/lib/Driver/Drivers.cpp +++ b/lld/lib/Driver/Drivers.cpp @@ -218,7 +218,7 @@ LinkerOptions lld::generateOptions(const llvm::opt::ArgList &args) { 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._input.push_back(LinkerInput((*it)->getValue())); } ret._llvmArgs = args.getAllArgValues(core::OPT_mllvm); diff --git a/lld/lib/Driver/LinkerInvocation.cpp b/lld/lib/Driver/LinkerInvocation.cpp index 10274031e3c5..6f500516eb38 100644 --- a/lld/lib/Driver/LinkerInvocation.cpp +++ b/lld/lib/Driver/LinkerInvocation.cpp @@ -12,7 +12,7 @@ #include "lld/Core/InputFiles.h" #include "lld/Core/PassManager.h" #include "lld/Core/Resolver.h" -#include "lld/Driver/Target.h" +#include "lld/ReaderWriter/ELFTargetInfo.h" #include "lld/ReaderWriter/Reader.h" #include "lld/ReaderWriter/Writer.h" @@ -21,6 +21,12 @@ using namespace lld; +namespace { +std::unique_ptr createTargetInfo(const LinkerOptions &lo) { + return ELFTargetInfo::create(lo); +} +} + void LinkerInvocation::operator()() { // Honor -mllvm if (!_options._llvmArgs.empty()) { @@ -34,9 +40,9 @@ void LinkerInvocation::operator()() { } // Create target. - std::unique_ptr target(Target::create(_options)); + std::unique_ptr targetInfo(createTargetInfo(_options)); - if (!target) { + if (!targetInfo) { llvm::errs() << "Failed to create target for " << _options._target << "\n"; return; @@ -45,7 +51,7 @@ void LinkerInvocation::operator()() { // Read inputs InputFiles inputs; for (const auto &input : _options._input) { - auto reader = target->getReader(input); + auto reader = targetInfo->getReader(input); if (error_code ec = reader) { llvm::errs() << "Failed to get reader for: " << input.getPath() << ": " << ec.message() << "\n"; @@ -69,17 +75,17 @@ void LinkerInvocation::operator()() { inputs.appendFiles(files); } - auto writer = target->getWriter(); + auto writer = targetInfo->getWriter(); // Give writer a chance to add files writer->addFiles(inputs); - Resolver resolver(target->getTargetInfo(), inputs); + Resolver resolver(*targetInfo, inputs); resolver.resolve(); MutableFile &merged = resolver.resultFile(); PassManager pm; - target->getTargetInfo().addPasses(pm); + targetInfo->addPasses(pm); pm.runOnFile(merged); if (error_code ec = writer) { diff --git a/lld/lib/Driver/Target.cpp b/lld/lib/Driver/Target.cpp deleted file mode 100644 index 8b90ebffd510..000000000000 --- a/lld/lib/Driver/Target.cpp +++ /dev/null @@ -1,14 +0,0 @@ -//===- 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 deleted file mode 100644 index 2e2bc59d3548..000000000000 --- a/lld/lib/Driver/Targets.cpp +++ /dev/null @@ -1,92 +0,0 @@ -//===- 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/Core/LinkerOptions.h" -#include "lld/Core/TargetInfo.h" -#include "lld/ReaderWriter/Reader.h" -#include "lld/ReaderWriter/Writer.h" -#include "lld/ReaderWriter/ELFTargetInfo.h" - -#include "llvm/ADT/Triple.h" -#include "llvm/Support/raw_ostream.h" - -#include - -using namespace lld; -using namespace std::placeholders; - -class ELFTarget : public Target { -public: - ELFTarget(std::unique_ptr ti) - : Target(std::unique_ptr(ti.get())), - _elfTargetInfo(*ti.release()), _readerELF(createReaderELF( - _elfTargetInfo, std::bind(&ELFTarget::getReader, this, _1))), - _readerYAML(createReaderYAML(*_targetInfo)), - _writer(createWriterELF(_elfTargetInfo)), - _writerYAML(createWriterYAML(*_targetInfo)) { - } - - virtual ErrorOr 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 getWriter() { - return _targetInfo->getLinkerOptions()._outputYAML ? *_writerYAML - : *_writer; - } - -protected: - const ELFTargetInfo &_elfTargetInfo; - std::unique_ptr _readerELF, _readerYAML; - std::unique_ptr _writer, _writerYAML; -}; - -class X86LinuxTarget LLVM_FINAL : public ELFTarget { -public: - X86LinuxTarget(std::unique_ptr ti) - : ELFTarget(std::move(ti)) {} -}; - -class HexagonTarget LLVM_FINAL : public ELFTarget { -public: - HexagonTarget(std::unique_ptr ti) - : ELFTarget(std::move(ti)) {} -}; - -std::unique_ptr Target::create(const LinkerOptions &lo) { - llvm::Triple t(lo._target); - // Create a TargetInfo. - std::unique_ptr ti(ELFTargetInfo::create(lo)); - - // Create the Target - if (t.getOS() == llvm::Triple::Linux && (t.getArch() == llvm::Triple::x86 || - t.getArch() == llvm::Triple::x86_64)) - return std::unique_ptr(new X86LinuxTarget(std::move(ti))); - else if (t.getArch() == llvm::Triple::hexagon) - return std::unique_ptr(new HexagonTarget(std::move(ti))); - return std::unique_ptr(); -} diff --git a/lld/lib/ReaderWriter/ELF/ELFTargetInfo.cpp b/lld/lib/ReaderWriter/ELF/ELFTargetInfo.cpp index 68aa19ba8cb8..167d92c2d398 100644 --- a/lld/lib/ReaderWriter/ELF/ELFTargetInfo.cpp +++ b/lld/lib/ReaderWriter/ELF/ELFTargetInfo.cpp @@ -18,6 +18,8 @@ #include "llvm/Support/ELF.h" namespace lld { +ELFTargetInfo::ELFTargetInfo(const LinkerOptions &lo) : TargetInfo(lo) {} + uint16_t ELFTargetInfo::getOutputType() const { switch (_options._outputKind) { case OutputKind::Executable: @@ -52,6 +54,23 @@ uint16_t ELFTargetInfo::getOutputMachine() const { } } +ErrorOr ELFTargetInfo::getReader(const LinkerInput &input) const { + if (!_reader) + _reader = createReaderELF(*this, std::bind(&ELFTargetInfo::getReader, this, + std::placeholders::_1)); + return *_reader; +} + +ErrorOr ELFTargetInfo::getWriter() const { + if (!_writer) { + if (_options._outputYAML) + _writer = createWriterYAML(*this); + else + _writer = createWriterELF(*this); + } + return *_writer; +} + std::unique_ptr ELFTargetInfo::create(const LinkerOptions &lo) { switch (llvm::Triple(llvm::Triple::normalize(lo._target)).getArch()) { case llvm::Triple::x86: diff --git a/lld/tools/lld-core/lld-core.cpp b/lld/tools/lld-core/lld-core.cpp index bec87e08df1b..296d5d51a8ac 100644 --- a/lld/tools/lld-core/lld-core.cpp +++ b/lld/tools/lld-core/lld-core.cpp @@ -195,6 +195,15 @@ public: } return llvm::make_error_code(llvm::errc::invalid_argument); } + + virtual ErrorOr getReader(const LinkerInput &input) const { + llvm_unreachable("Unimplemented!"); + } + + virtual ErrorOr getWriter() const { + llvm_unreachable("Unimplemented!"); + } + private: bool _doStubs; bool _doGOT;