diff options
165 files changed, 3008 insertions, 1696 deletions
diff --git a/lld/docs/Driver.rst b/lld/docs/Driver.rst index b65ff94f771..c96cd952a92 100644 --- a/lld/docs/Driver.rst +++ b/lld/docs/Driver.rst @@ -16,18 +16,18 @@ Overview ======== The lld driver is designed to support a number of different command line -interfaces. The main interfaces we plan to support are binutils ld, Apple's -ld64, and Microsoft's link.exe. +interfaces. The main interfaces we plan to support are binutils' ld, Apple's +ld, and Microsoft's link.exe. Flavors ------- Each of these different interfaces is referred to as a flavor. There is also an -extra flavor for ``lld -core``. This is equivalent to ``-cc1`` in clang. -The current flavors are. +extra flavor "core" which is used to exercise the core functionality of the +linker it the test suite. -* ld -* ld64 +* gnu +* darwin * link * core @@ -39,70 +39,41 @@ order, so the second overrides the first. The first is to symlink :program:`lld` as :program:`lld-{flavor}` or just :program:`{flavor}`. You can also specify it as the first command line argument using ``-flavor``:: - $ lld -flavor ld + $ lld -flavor gnu There is a shortcut for ``-flavor core`` as ``-core``. -Argument translation and lld -core ----------------------------------- -Due to the different driver flavors and the need to write portable tests, there -is ``lld -core``. Driver flavors translate options into ``lld -core`` options. -These options are then forwarded to ``lld -core`` to run the actual link. The -options passed to ``lld -core`` can be seen by passing ``-###`` to any driver -flavor. - -Targets -------- - -The ``-target <llvm-triple>`` option can be passed to any driver flavor to -link for a specific target. You can also prefix the :program:`lld` symlink with -a target triple to default to that target. If neither of these is set, the -default target is the target LLVM was configured for. - -Adding an Option -================ +Adding an Option to an existing Flavor +====================================== #. Add the option to the desired :file:`lib/Driver/{flavor}Options.td`. -#. If there is no ``lld -core`` option, add the option to - :file:`lib/Driver/CoreOptions.td`. All ``lld -core`` start with a single - - and if they have a value, it is joined with a =. ``lld -core`` options should - have sensible, non-abbreviated names and should be shared between flavors - where possible. +#. Add to :cpp:class:`lld::FlavorTargetInfo` a getter and setter method + for the option. + +#. Modify :cpp:func:`lld::FlavorDriver::parse` in :file: + `lib/Driver/{Flavor}Driver.cpp` to call the targetInfo setter + for corresponding to the option. -#. Modify the ``{flavor}Driver::transform`` function to transform the added - option into one or more core options. +#. Modify {Flavor}Reader and {Flavor}Writer to use the new targtInfo option. -#. Add the option to :cpp:class:`lld::LinkerOptions` in - :file:`include/lld/Driver/LinkerOptions.h` and modify the move constructor to - move the option value. - -#. Modify :cpp:func:`lld::parseCoreArgs` in :file:`lib/Driver/Drivers.cpp` to - fill the :cpp:class:`lld::LinkerOptions` with the new option. - -#. Modify lld to use the new option. Adding a Flavor =============== #. Add an entry for the flavor in :file:`include/lld/Driver/Driver.h` to - :cpp:class:`lld::Driver::Flavor`. + :cpp:class:`lld::UniversalDriver::Flavor`. -#. Add an entry in :file:`tools/lld/lld.cpp` to - :cpp:func:`lld::Driver::strToFlavor`. This allows the - flavor to be selected via symlink and :option:`-flavor`. +#. Add an entry in :file:`lib/Driver/UniversalDriver.cpp` to + :cpp:func:`lld::Driver::strToFlavor` and + :cpp:func:`lld::UniversalDriver::link`. + This allows the flavor to be selected via symlink and :option:`-flavor`. #. Add a tablegen file called :file:`lib/Driver/{flavor}Options.td` that describes the options. If the options are a superset of another driver, that driver's td file can simply be included. The :file:`{flavor}Options.td` file must also be added to :file:`lib/Driver/CMakeLists.txt`. -#. Add a ``{flavor}::{flavor}OptTable`` as a subclass of - :cpp:class:`llvm::opt::OptTable` in :file:`lib/Driver/Drivers.cpp`. - #. Add a ``{flavor}Driver`` as a subclass of :cpp:class:`lld::Driver` - in :file:`lib/Driver/Drivers.cpp`. It must have a :cpp:func:`transform` - function which takes argc/argv and returns a ``lld -core`` ArgList. - -#. Modify :cpp:func:`Driver::create` to create an instance of the new driver. + in :file:`lib/Driver/{flavor}Driver.cpp`. diff --git a/lld/include/lld/Core/ArchiveLibraryFile.h b/lld/include/lld/Core/ArchiveLibraryFile.h index a21a166cda8..9bfc5da915d 100644 --- a/lld/include/lld/Core/ArchiveLibraryFile.h +++ b/lld/include/lld/Core/ArchiveLibraryFile.h @@ -42,7 +42,6 @@ protected: : File(path, kindArchiveLibrary), _targetInfo(ti) { } -private: const TargetInfo &_targetInfo; }; diff --git a/lld/include/lld/Core/LinkerOptions.h b/lld/include/lld/Core/LinkerOptions.h deleted file mode 100644 index 9eea90bce2a..00000000000 --- a/lld/include/lld/Core/LinkerOptions.h +++ /dev/null @@ -1,169 +0,0 @@ -//===- lld/Core/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_CORE_LINKER_OPTIONS_H -#define LLD_CORE_LINKER_OPTIONS_H - -#include "lld/Core/LLVM.h" - -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/ErrorOr.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/MemoryBuffer.h" - -#include <memory> -#include <vector> - -namespace lld { -/// \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) : _file(file) {} - - LinkerInput(std::unique_ptr<llvm::MemoryBuffer> buffer) - : _buffer(std::move(buffer)), _file(_buffer->getBufferIdentifier()) { - } - - 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); - return *this; - } - - 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; - } - - StringRef getPath() const { - return _file; - } - - std::unique_ptr<llvm::MemoryBuffer> takeBuffer() { - getBuffer(); - return std::move(_buffer); - } - -private: - mutable std::unique_ptr<llvm::MemoryBuffer> _buffer; - std::string _file; -}; - -enum OutputKind { - Invalid, - StaticExecutable, - DynamicExecutable, - Relocatable, - Shared, - SharedStubs, - Core, - DebugSymbols, - Bundle, - Preload, -}; - -struct LinkerOptions { - LinkerOptions() - : _baseAddress(0) - , _outputKind(OutputKind::Invalid) - , _outputCommands(false) - , _outputYAML(false) - , _noInhibitExec(true) - , _deadStrip(false) - , _globalsAreDeadStripRoots(false) - , _searchArchivesToOverrideTentativeDefinitions(false) - , _searchSharedLibrariesToOverrideTentativeDefinitions(false) - , _warnIfCoalesableAtomsHaveDifferentCanBeNull(false) - , _warnIfCoalesableAtomsHaveDifferentLoadName(false) - , _forceLoadArchives(false) - , _textRelocations(false) - , _relocatable(false) {} - - // This exists because MSVC doesn't support = default :( - LinkerOptions(LinkerOptions && other) - : _input(std::move(other._input)), - _inputSearchPaths(std::move(other._inputSearchPaths)), - _llvmArgs(std::move(other._llvmArgs)), - _deadStripRoots(std::move(other._deadStripRoots)), - _target(std::move(other._target)), - _outputPath(std::move(other._outputPath)), - _entrySymbol(std::move(other._entrySymbol)), - _baseAddress(other._baseAddress), _outputKind(other._outputKind), - _outputCommands(other._outputCommands), _outputYAML(other._outputYAML), - _noInhibitExec(other._noInhibitExec), _deadStrip(other._deadStrip), - _globalsAreDeadStripRoots(other._globalsAreDeadStripRoots), - _searchArchivesToOverrideTentativeDefinitions( - other._searchArchivesToOverrideTentativeDefinitions), - _searchSharedLibrariesToOverrideTentativeDefinitions( - other._searchSharedLibrariesToOverrideTentativeDefinitions), - _warnIfCoalesableAtomsHaveDifferentCanBeNull( - other._warnIfCoalesableAtomsHaveDifferentCanBeNull), - _warnIfCoalesableAtomsHaveDifferentLoadName( - other._warnIfCoalesableAtomsHaveDifferentLoadName), - _forceLoadArchives(other._forceLoadArchives), - _textRelocations(other._textRelocations), - _relocatable(other._relocatable) {} - - std::vector<LinkerInput> _input; - std::vector<std::string> _inputSearchPaths; - std::vector<std::string> _llvmArgs; - std::vector<std::string> _deadStripRoots; - std::string _target; - std::string _outputPath; - std::string _entrySymbol; - uint64_t _baseAddress; - OutputKind _outputKind:4; - /// \brief -### - unsigned _outputCommands : 1; - unsigned _outputYAML : 1; - unsigned _noInhibitExec : 1; - unsigned _deadStrip : 1; - unsigned _globalsAreDeadStripRoots : 1; - unsigned _searchArchivesToOverrideTentativeDefinitions : 1; - unsigned _searchSharedLibrariesToOverrideTentativeDefinitions : 1; - unsigned _warnIfCoalesableAtomsHaveDifferentCanBeNull : 1; - unsigned _warnIfCoalesableAtomsHaveDifferentLoadName : 1; - unsigned _forceLoadArchives : 1; - unsigned _textRelocations : 1; - unsigned _relocatable : 1; - unsigned _mergeCommonStrings: 1; - -private: - LinkerOptions(const LinkerOptions&) LLVM_DELETED_FUNCTION; -}; -} - -#endif diff --git a/lld/include/lld/Core/Resolver.h b/lld/include/lld/Core/Resolver.h index 0d73100504a..8ea08b1cb8c 100644 --- a/lld/include/lld/Core/Resolver.h +++ b/lld/include/lld/Core/Resolver.h @@ -42,7 +42,7 @@ public: virtual void doFile(const File&); /// @brief do work of merging and resolving and return list - void resolve(); + bool resolve(); MutableFile& resultFile() { return _result; @@ -54,7 +54,7 @@ private: void resolveUndefines(); void updateReferences(); void deadStripOptimize(); - void checkUndefines(bool final); + bool checkUndefines(bool final); void removeCoalescedAwayAtoms(); void checkDylibSymbolCollisions(); void linkTimeOptimize(); diff --git a/lld/include/lld/Core/TargetInfo.h b/lld/include/lld/Core/TargetInfo.h index ef2326d38e7..9c26e5bfbbc 100644 --- a/lld/include/lld/Core/TargetInfo.h +++ b/lld/include/lld/Core/TargetInfo.h @@ -6,82 +6,328 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// -/// \file -/// -/// Interface for target specific information to be used be readers, writers, -/// and the resolver. -/// -//===----------------------------------------------------------------------===// #ifndef LLD_CORE_TARGET_INFO_H #define LLD_CORE_TARGET_INFO_H #include "lld/Core/Error.h" #include "lld/Core/LLVM.h" +#include "lld/Core/Reference.h" + +#include "lld/Driver/LinkerInput.h" +#include "lld/ReaderWriter/Reader.h" -#include "llvm/Support/DataTypes.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/raw_ostream.h" #include <string> +#include <vector> namespace llvm { class Triple; } namespace lld { -class LinkerInput; -struct LinkerOptions; class PassManager; -class Reader; +class File; class Writer; +class InputFiles; -class TargetInfo { -protected: - TargetInfo(const LinkerOptions &lo) : _options(lo) {} - +/// \brief The TargetInfo class encapsulates "what and how" to link. +/// +/// The base class TargetInfo contains the options needed by core linking. +/// Subclasses of TargetInfo have additional options needed by specific Readers +/// and Writers. For example, ELFTargetInfo has methods that supplies options +/// to the ELF Reader and Writer. +/// +/// \todo Consider renaming to something like "LinkingOptions". +class TargetInfo : public Reader { public: virtual ~TargetInfo(); - const LinkerOptions &getLinkerOptions() const { return _options; } + /// \name Methods needed by core linking + /// @{ + + /// Name of symbol linker should use as "entry point" to program, + /// usually "main" or "start". + StringRef entrySymbolName() const { + return _entrySymbolName; + } + + /// Whether core linking should remove Atoms not reachable by following + /// References from the entry point Atom or from all global scope Atoms + /// if globalsAreDeadStripRoots() is true. + bool deadStrip() const { + return _deadStrip; + } + + /// Only used if deadStrip() returns true. Means all global scope Atoms + /// should be marked live (along with all Atoms they reference). Usually + /// this method returns false for main executables, but true for dynamic + /// shared libraries. + bool globalsAreDeadStripRoots() const { + assert(_deadStrip && "only applicable when deadstripping enabled"); + return _globalsAreDeadStripRoots; + } + + /// Only used if deadStrip() returns true. This method returns the names + /// of DefinedAtoms that should be marked live (along with all Atoms they + /// reference). Only Atoms with scope scopeLinkageUnit or scopeGlobal can + /// be kept live using this method. + const std::vector<StringRef> &deadStripRoots() const { + return _deadStripRoots; + } - llvm::Triple getTriple() const; - virtual bool is64Bits() const; - virtual bool isLittleEndian() const; + /// Archive files (aka static libraries) are normally lazily loaded. That is, + /// object files within an archive are only loaded and linked in, if the + /// object file contains a DefinedAtom which will replace an existing + /// UndefinedAtom. If this method returns true, core linking will actively + /// load every member object file from every archive. + bool forceLoadAllArchives() const { + return _forceLoadAllArchives; + } + + /// Archive files (aka static libraries) are normally lazily loaded. That is, + /// object files within an archive are only loaded and linked in, if the + /// object file contains a DefinedAtom which will replace an existing + /// UndefinedAtom. If this method returns true, core linking will also look + /// for archive members to replace existing tentative definitions in addition + /// to replacing undefines. Note: a "tentative definition" (also called a + /// "common" symbols) is a C (but not C++) concept. They are modeled in lld + /// as a DefinedAtom with merge() of mergeAsTentative. + bool searchArchivesToOverrideTentativeDefinitions() const { + return _searchArchivesToOverrideTentativeDefinitions; + } + + /// Normally core linking will turn a tentative definition into a real + /// definition if not replaced by a real DefinedAtom from some object file. + /// If this method returns true, core linking will search all supplied + /// dynamic shared libraries for symbol names that match remaining tentative + /// definitions. If any are found, the corresponding tentative definition + /// atom is replaced with SharedLibraryAtom. + bool searchSharedLibrariesToOverrideTentativeDefinitions() const { + return _searchSharedLibrariesToOverrideTentativeDefinitions; + } + + /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a + /// SharedLibraryAtom for the link to be successful. This method controls + /// whether core linking prints out a list of remaining UndefinedAtoms. + /// + /// \todo This should be a method core linking calls with a list of the + /// UndefinedAtoms so that different drivers can format the error message + /// as needed. + bool printRemainingUndefines() const { + return _printRemainingUndefines; + } + + /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a + /// SharedLibraryAtom for the link to be successful. This method controls + /// whether core linking considers remaining undefines to be an error. + bool allowRemainingUndefines() const { + return _allowRemainingUndefines; + } + + /// In the lld model, a SharedLibraryAtom is a proxy atom for something + /// that will be found in a dynamic shared library when the program runs. + /// A SharedLibraryAtom optionally contains the name of the shared library + /// in which to find the symbol name at runtime. Core linking may merge + /// two SharedLibraryAtom with the same name. If this method returns true, + /// when merging core linking will also verify that they both have the same + /// loadName() and if not print a warning. + /// + /// \todo This should be a method core linking calls so that drivers can + /// format the warning as needed. + bool warnIfCoalesableAtomsHaveDifferentLoadName() const { + return _warnIfCoalesableAtomsHaveDifferentLoadName; + } + + /// In C/C++ you can mark a function's prototype with + /// __attribute__((weak_import)) or __attribute__((weak)) to say the function + /// may not be available at runtime and/or build time and in which case its + /// address will evaluate to NULL. In lld this is modeled using the + /// UndefinedAtom::canBeNull() method. During core linking, UndefinedAtom + /// with the same name are automatically merged. If this method returns + /// true, core link also verfies that the canBeNull() value for merged + /// UndefinedAtoms are the same and warns if not. + /// + /// \todo This should be a method core linking calls so that drivers can + /// format the warning as needed. + bool warnIfCoalesableAtomsHaveDifferentCanBeNull() const { + return _warnIfCoalesableAtomsHaveDifferentCanBeNull; + } + + /// If true, core linking will write the path to each input file to stdout + /// (i.e. llvm::outs()) as it is used. This is used to implement the -t + /// linker option. + /// + /// \todo This should be a method core linking calls so that drivers can + /// format the line as needed. + bool logInputFiles() const { + return _logInputFiles; + } + + /// Parts of LLVM use global variables which are bound to command line + /// options (see llvm::cl::Options). This method returns "command line" + /// options which are used to configure LLVM's command line settings. + /// For instance the -debug-only XXX option can be used to dynamically + /// trace different parts of LLVM and lld. + const std::vector<const char*> &llvmOptions() const { + return _llvmOptions; + } + + /// This method returns the sequence of input files for core linking to + /// process. + /// + /// \todo Consider moving this out of TargetInfo so that the same TargetInfo + /// object can be reused for different links. + const std::vector<LinkerInput> &inputFiles() const { + return _inputFiles; + } + /// @} + + + /// \name Methods used by Drivers to configure TargetInfo + /// @{ + void setOutputPath(StringRef str) { _outputPath = str; } + void setEntrySymbolName(StringRef name) { _entrySymbolName = name; } + void setDeadStripping(bool enable) { _deadStrip = enable; } + void setGlobalsAreDeadStripRoots(bool v) { _globalsAreDeadStripRoots = v; } + void setSearchArchivesToOverrideTentativeDefinitions(bool search) { + _searchArchivesToOverrideTentativeDefinitions = search; + } + void setSearchSharedLibrariesToOverrideTentativeDefinitions(bool search) { + _searchSharedLibrariesToOverrideTentativeDefinitions = search; + } + void setWarnIfCoalesableAtomsHaveDifferentCanBeNull(bool warn) { + _warnIfCoalesableAtomsHaveDifferentCanBeNull = warn; + } + void setWarnIfCoalesableAtomsHaveDifferentLoadName(bool warn) { + _warnIfCoalesableAtomsHaveDifferentLoadName = warn; + } + void setForceLoadAllArchives(bool force) { + _forceLoadAllArchives = force; + } + void setPrintRemainingUndefines(bool print) { + _printRemainingUndefines = print; + } + void setAllowRemainingUndefines(bool allow) { + _allowRemainingUndefines = allow; + } + void setLogInputFiles(bool log) { + _logInputFiles = log; + } + void appendInputFile(StringRef path) { + _inputFiles.emplace_back(LinkerInput(path)); + } + void appendInputFile(std::unique_ptr<llvm::MemoryBuffer> buffer) { + _inputFiles.emplace_back(LinkerInput(std::move(buffer))); + } + void appendLLVMOption(const char *opt) { + _llvmOptions.push_back(opt); + } + + /// After all set* methods are called, the Driver calls this method + /// to validate that there are no missing options or invalid combinations + /// of options. If there is a problem, a description of the problem + /// is written to the supplied stream. + /// + /// \returns true if there is an error with the current settings. + virtual bool validate(raw_ostream &diagnostics) = 0; - virtual uint64_t getPageSize() const = 0; - virtual StringRef getEntry() const; + /// @} + /// \name Methods used by Driver::link() + /// @{ + + /// Returns the file system path to which the linked output should be written. + /// + /// \todo To support in-memory linking, we need an abstraction that allows + /// the linker to write to an in-memory buffer. + StringRef outputPath() const { + return _outputPath; + } + + /// Abstract method to parse a supplied input file buffer into one or + /// more lld::File objects. Subclasses of TargetInfo must implement this + /// method. + /// + /// \param inputBuff This is an in-memory read-only copy of the input file. + /// If the resulting lld::File object will contain pointers into + /// this memory buffer, the lld::File object should take ownership + /// of the buffer. Otherwise core linking will maintain ownership of the + /// buffer and delete it at some point. + /// + /// \param [out] result The instantiated lld::File object is returned here. + /// The \p result is a vector because some input files parse into more than + /// one lld::File (e.g. YAML). + virtual error_code parseFile(std::unique_ptr<MemoryBuffer> &inputBuff, + std::vector<std::unique_ptr<File>> &result) const = 0; + + /// This is a wrapper around parseFile() where the input file is specified + /// by file system path. The default implementation reads the input file + /// into a memory buffer and calls parseFile(). + /// + /// \param path This is the file system path to the input file. + /// \param [out] result The instantiated lld::File object is returned here. + virtual error_code readFile(StringRef path, + std::vector<std::unique_ptr<File>> &result) const; - virtual void addPasses(PassManager &pm) const {} + + /// This method is called by core linking to give the Writer a chance + /// to add file format specific "files" to set of files to be linked. This is + /// how file format specific atoms can be added to the link. + virtual void addImplicitFiles(InputFiles&) const; + + /// This method is called by core linking to build the list of Passes to be + /// run on the merged/linked graph of all input files. + virtual void addPasses(PassManager &pm) const; - /// \brief Get a reference to a Reader for the given input. + /// Calls through to the writeFile() method on the specified Writer. /// - /// Will always return the same object for the same input. - virtual ErrorOr<Reader &> getReader(const LinkerInput &input) const = 0; + /// \param linkedFile This is the merged/linked graph of all input file Atoms. + virtual error_code writeFile(const File &linkedFile) const; - /// \brief Get the writer. - virtual ErrorOr<Writer &> getWriter() const = 0; + /// @} + + + /// \name Methods needed by YAML I/O and error messages to convert Kind values + /// to and from strings. + /// @{ + + /// Abstract method to parse a kind name string into an integral + /// Reference::Kind + virtual ErrorOr<Reference::Kind> relocKindFromString(StringRef str) const = 0; + + /// Abstract method to return the name for a given integral + /// Reference::Kind. + virtual ErrorOr<std::string> stringFromRelocKind(Reference::Kind k) const = 0; + + /// @} - // TODO: Split out to TargetRelocationInfo. - virtual ErrorOr<int32_t> relocKindFromString(StringRef str) const { - int32_t val; - if (str.getAsInteger(10, val)) - return llvm::make_error_code(llvm::errc::invalid_argument); - return val; - } - virtual ErrorOr<std::string> stringFromRelocKind(int32_t kind) const { - std::string s; - llvm::raw_string_ostream str(s); - str << kind; - str.flush(); - return s; - } protected: - const LinkerOptions &_options; + TargetInfo(); // Must be subclassed + + /// Abstract method to lazily instantiate the Writer. + virtual Writer &writer() const = 0; + + + StringRef _outputPath; + StringRef _entrySymbolName; + bool _deadStrip; + bool _globalsAreDeadStripRoots; + bool _searchArchivesToOverrideTentativeDefinitions; + bool _searchSharedLibrariesToOverrideTentativeDefinitions; + bool _warnIfCoalesableAtomsHaveDifferentCanBeNull; + bool _warnIfCoalesableAtomsHaveDifferentLoadName; + bool _forceLoadAllArchives; + bool _printRemainingUndefines; + bool _allowRemainingUndefines; + bool _logInputFiles; + std::vector<StringRef> _deadStripRoots; + std::vector<LinkerInput> _inputFiles; + std::vector<const char*> _llvmOptions; }; } // end namespace lld diff --git a/lld/include/lld/Driver/Driver.h b/lld/include/lld/Driver/Driver.h index f3dcadb46b6..8259e71bd8c 100644 --- a/lld/include/lld/Driver/Driver.h +++ b/lld/include/lld/Driver/Driver.h @@ -9,9 +9,8 @@ /// /// \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. +/// Interface for Drivers which convert command line arguments into +/// TargetInfo objects, then perform the link. /// //===----------------------------------------------------------------------===// @@ -20,48 +19,111 @@ #include "lld/Core/LLVM.h" -#include "llvm/Option/ArgList.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/raw_ostream.h" #include <memory> -#include <string> +#include <vector> namespace lld { -struct LinkerOptions; +class TargetInfo; +class CoreTargetInfo; +class MachOTargetInfo; +class ELFTargetInfo; -/// \brief Base class for all Drivers. +/// Base class for all Drivers. class Driver { protected: - Driver(StringRef defaultTargetTriple) - : _defaultTargetTriple(defaultTargetTriple) {} - std::string _defaultTargetTriple; + /// Performs link using specified options. + static bool link(const TargetInfo &targetInfo, + raw_ostream &diagnostics = llvm::errs()); +private: + Driver() LLVM_DELETED_FUNCTION; +}; + +/// Driver for "universal" lld tool which can mimic any linker command line +/// parsing once it figures out which command line flavor to use. +class UniversalDriver : public Driver { public: + /// Determine flavor and pass control to Driver for that flavor. + static bool link(int argc, const char *argv[]); + +private: + UniversalDriver() LLVM_DELETED_FUNCTION; + enum class Flavor { invalid, - ld, - link, - ld64, - core + gnu_ld, // -flavor gnu + win_link, // -flavor link + darwin_ld, // -flavor darwin + core // -flavor core OR -core }; - virtual ~Driver(); + static Flavor selectFlavor(std::vector<const char*> &args); + static Flavor strToFlavor(StringRef str); +}; + + +/// Driver for gnu/binutil 'ld' command line options. +class GnuLdDriver : public Driver { +public: + /// Parses command line arguments same as gnu/binutils ld and performs link. + /// Returns true iff an error occurred. + static bool linkELF(int argc, const char *argv[], + raw_ostream &diagnostics = llvm::errs()); + + /// Uses gnu/binutils style ld command line options to fill in options struct. + /// Returns true iff there was an error. + static std::unique_ptr<ELFTargetInfo> parse(int argc, const char *argv[], + raw_ostream &diagnostics = llvm::errs()); + +private: + static llvm::Triple getDefaultTarget(const char *progName); + + GnuLdDriver() LLVM_DELETED_FUNCTION; +}; + + +/// Driver for darwin/ld64 'ld' command line options. +class DarwinLdDriver : public Driver { +public: + /// Parses command line arguments same as darwin's ld and performs link. + /// Returns true iff there was an error. + static bool linkMachO(int argc, const char *argv[], + raw_ostream &diagnostics = llvm::errs()); + + /// Uses darwin style ld command line options to update targetInfo object. + /// Returns true iff there was an error. + static bool parse(int argc, const char *argv[], MachOTargetInfo &info, + raw_ostream &diagnostics = llvm::errs()); +private: + DarwinLdDriver() LLVM_DELETED_FUNCTION; +}; - virtual std::unique_ptr<llvm::opt::DerivedArgList> - transform(llvm::ArrayRef<const char *> 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); +/// Driver for lld unit tests +class CoreDriver : public Driver { +public: + + /// Parses command line arguments same as lld-core and performs link. + /// Returns true iff there was an error. + static bool link(int argc, const char *argv[], + raw_ostream &diagnostics = llvm::errs()); + + /// Uses lld-core command line options to fill in options struct. + /// Returns true iff there was an error. + static bool parse(int argc, const char *argv[], CoreTargetInfo &info, + raw_ostream &diagnostics = llvm::errs()); + +private: + CoreDriver() LLVM_DELETED_FUNCTION; }; -std::unique_ptr<llvm::opt::ArgList> -parseCoreArgs(llvm::ArrayRef<const char *> args); -LinkerOptions generateOptions(const llvm::opt::ArgList &args); + + } // end namespace lld #endif diff --git a/lld/include/lld/Driver/LinkerInput.h b/lld/include/lld/Driver/LinkerInput.h new file mode 100644 index 00000000000..cb3437212a0 --- /dev/null +++ b/lld/include/lld/Driver/LinkerInput.h @@ -0,0 +1,93 @@ +//===- lld/Core/LinkerInput.h - Files to be linked ------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// All linker options needed by core linking. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_LINKER_INPUT_H +#define LLD_CORE_LINKER_INPUT_H + +#include "lld/Core/LLVM.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" + +#include <memory> +#include <vector> + +namespace lld { + +/// \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) : _file(file) {} + + LinkerInput(std::unique_ptr<llvm::MemoryBuffer> buffer) + : _buffer(std::move(buffer)), _file(_buffer->getBufferIdentifier()) { + } + + 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); + return *this; + } + + 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; + } + + StringRef getPath() const { + return _file; + } + + std::unique_ptr<llvm::MemoryBuffer> takeBuffer() { + getBuffer(); + return std::move(_buffer); + } + +private: + mutable std::unique_ptr<llvm::MemoryBuffer> _buffer; + std::string _file; +}; + + + +} // namespace lld + +#endif diff --git a/lld/include/lld/Driver/LinkerInvocation.h b/lld/include/lld/Driver/LinkerInvocation.h deleted file mode 100644 index 7a1b56a6d6e..00000000000 --- a/lld/include/lld/Driver/LinkerInvocation.h +++ /dev/null @@ -1,34 +0,0 @@ -//===- 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/Core/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/ReaderWriter/CoreTargetInfo.h b/lld/include/lld/ReaderWriter/CoreTargetInfo.h new file mode 100644 index 00000000000..a0dd01702bf --- /dev/null +++ b/lld/include/lld/ReaderWriter/CoreTargetInfo.h @@ -0,0 +1,53 @@ +//===- lld/ReaderWriter/CoreTargetInfo.h ---------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_CORE_TARGET_INFO_H +#define LLD_READER_WRITER_CORE_TARGET_INFO_H + +#include "lld/Core/TargetInfo.h" +#include "lld/ReaderWriter/Reader.h" +#include "lld/ReaderWriter/Writer.h" + +#include "llvm/Support/ErrorHandling.h" + +namespace lld { + +class CoreTargetInfo : public TargetInfo { +public: + CoreTargetInfo(); + + virtual bool validate(raw_ostream &diagnostics) { + return false; + } + + virtual void addPasses(PassManager &pm) const; + virtual ErrorOr<Reference::Kind> relocKindFromString(StringRef str) const; + virtual ErrorOr<std::string> stringFromRelocKind(Reference::Kind kind) const; + + + virtual error_code parseFile(std::unique_ptr<MemoryBuffer> &mb, + std::vector<std::unique_ptr<File>> &result) const; + + + void addPassNamed(StringRef name) { + _passNames.push_back(name); + } + +protected: + virtual Writer &writer() const; + +private: + mutable std::unique_ptr<Reader> _reader; + mutable std::unique_ptr<Writer> _writer; + std::vector<StringRef> _passNames; +}; + +} // end namespace lld + +#endif diff --git a/lld/include/lld/ReaderWriter/ELFTargetInfo.h b/lld/include/lld/ReaderWriter/ELFTargetInfo.h index 07f6a468f60..eb453d41f2f 100644 --- a/lld/include/lld/ReaderWriter/ELFTargetInfo.h +++ b/lld/include/lld/ReaderWriter/ELFTargetInfo.h @@ -10,13 +10,13 @@ #ifndef LLD_READER_WRITER_ELF_TARGET_INFO_H #define LLD_READER_WRITER_ELF_TARGET_INFO_H -#include "lld/Core/LinkerOptions.h" #include "lld/Core/PassManager.h" #include "lld/Core/Pass.h" #include "lld/Core/TargetInfo.h" #include "lld/ReaderWriter/Reader.h" #include "lld/ReaderWriter/Writer.h" +#include "llvm/ADT/Triple.h" #include "llvm/Object/ELF.h" #include "llvm/Support/ELF.h" @@ -34,15 +34,16 @@ public: }; class ELFTargetInfo : public TargetInfo { -protected: - ELFTargetInfo(const LinkerOptions &lo); - public: - uint16_t getOutputType() const; + llvm::Triple getTriple() const { return _triple; } + virtual bool is64Bits() const; + virtual bool isLittleEndian() const; + virtual uint64_t getPageSize() const { return 0x1000; } + uint16_t getOutputType() const { return _outputFileType; } uint16_t getOutputMachine() const; - - virtual StringRef getEntry() const; - virtual uint64_t getBaseAddress() const { return _options._baseAddress; } + bool outputYAML() const { return _outputYAML; } + bool mergeCommonStrings() const { return _mergeCommonStrings; } + virtual uint64_t getBaseAddress() const { return _baseAddress; } /// \brief Does this relocation belong in the dynamic relocation table? /// @@ -54,6 +55,13 @@ public: const Reference &) const { return false; } + virtual bool validate(raw_ostream &diagnostics); + + + virtual error_code parseFile(std::unique_ptr<MemoryBuffer> &mb, + std::vector<std::unique_ptr<File>> &result) const; + + static std::unique_ptr<ELFTargetInfo> create(llvm::Triple); /// \brief Does this relocation belong in the dynamic plt relocation table? /// @@ -71,16 +79,7 @@ public: } /// \brief Does the output have dynamic sections. - bool isDynamic() const { - return _options._outputKind == OutputKind::DynamicExecutable || - _options._outputKind == OutputKind::Shared; - } - - virtual ErrorOr<Reader &> getReader(const LinkerInput &input) const; - - virtual ErrorOr<Writer &> getWriter() const; - - static std::unique_ptr<ELFTargetInfo> create(const LinkerOptions &lo); + bool isDynamic() const; template <typename ELFT> lld::elf::TargetHandler<ELFT> &getTargetHandler() const { @@ -90,11 +89,39 @@ public: virtual void addPasses(PassManager &pm) const; + void setTriple(llvm::Triple trip) { _triple = trip; } + void setOutputFileType(uint32_t type) { _outputFileType = type; } + void setOutputYAML(bool v) { _outputYAML = v; } + void setNoInhibitExec(bool v) { _noInhibitExec = v; } + void setIsStaticExecutable(bool v) { _isStaticExecutable = v; } + void setMergeCommonStrings(bool v) { _mergeCommonStrings = v; } + void appendSearchPath(StringRef dirPath) { + _inputSearchPaths.push_back(dirPath); + } + /// Searches directories then calls appendInputFile() + bool appendLibrary(StringRef libName); + protected: + ELFTargetInfo() = delete; + ELFTargetInfo(llvm::Triple); + + virtual Writer &writer() const; + + uint16_t _outputFileType; // e.g ET_EXEC + llvm::Triple _triple; std::unique_ptr<TargetHandlerBase> _targetHandler; - mutable std::unique_ptr<Reader> _elfReader; - mutable std::unique_ptr<Reader> _linkerScriptReader; - mutable std::unique_ptr<Writer> _writer; + uint64_t _baseAddress; + bool _isStaticExecutable; + bool _outputYAML; + bool _noInhibitExec; + bool _mergeCommonStrings; + bool _runLayoutPass; + std::vector<StringRef> _inputSearchPaths; + llvm::BumpPtrAllocator _extraStrings; + mutable std::unique_ptr<Reader> _elfReader; + mutable std::unique_ptr<Reader> _yamlReader; + mutable std::unique_ptr<Writer> _writer; + mutable std::unique_ptr<Reader> _linkerScriptReader; }; } // end namespace lld diff --git a/lld/include/lld/ReaderWriter/MachOTargetInfo.h b/lld/include/lld/ReaderWriter/MachOTargetInfo.h index 7e8927bfd7d..db5ab3e70d9 100644 --- a/lld/include/lld/ReaderWriter/MachOTargetInfo.h +++ b/lld/include/lld/ReaderWriter/MachOTargetInfo.h @@ -11,35 +11,96 @@ #define LLD_READER_WRITER_MACHO_TARGET_INFO_H #include "lld/Core/TargetInfo.h" +#include "lld/ReaderWriter/Reader.h" +#include "lld/ReaderWriter/Writer.h" #include "llvm/Support/ErrorHandling.h" -#include <memory> - namespace lld { -class MachOTargetInfo : public TargetInfo { -protected: - MachOTargetInfo(const LinkerOptions &lo) : TargetInfo(lo) {} +namespace mach_o { + class KindHandler; // defined in lib. this header is in include. +} + +class MachOTargetInfo : public TargetInfo { public: + MachOTargetInfo(); + ~MachOTargetInfo(); + + virtual void addPasses(PassManager &pm) const; + virtual ErrorOr<Reference::Kind> relocKindFromString(StringRef str) const; + virtual ErrorOr<std::string> stringFromRelocKind(Reference::Kind kind) const; + virtual bool validate(raw_ostream &diagnostics); + + virtual error_code parseFile(std::unique_ptr<MemoryBuffer> &mb, + std::vector<std::unique_ptr<File>> &result) const; + uint32_t getCPUType() const; uint32_t getCPUSubType() const; bool addEntryPointLoadCommand() const; bool addUnixThreadLoadCommand() const; + bool outputTypeHasEntry() const; - virtual uint64_t getPageZeroSize() const = 0; - - virtual ErrorOr<Reader &> getReader(const LinkerInput &input) const { - llvm_unreachable("Unimplemented!"); + virtual uint64_t pageZeroSize() const { + return _pageZeroSize; } + + mach_o::KindHandler &kindHandler() const; + + uint32_t outputFileType() const { return _outputFileType; } + + enum Arch { + arch_unknown, + arch_x86, + arch_x86_64, + arch_armv6, + arch_armv7, + arch_armv7s, + }; + + enum class OS { + macOSX, + iOS, + iOS_simulator + }; - virtual ErrorOr<Writer &> getWriter() const { - llvm_unreachable("Unimplemented!"); - } + Arch arch() const { return _arch; } + + void setOutputFileType(uint32_t type) { _outputFileType = type; } + void setArch(Arch arch) { _arch = arch; } + bool setOS(OS os, StringRef minOSVersion); + +private: + virtual Writer &writer() const; + + /// 32-bit packed encoding of "X.Y.Z" where nibbles are xxxx.yy.zz. + struct PackedVersion { + PackedVersion(StringRef); + static bool parse(StringRef, PackedVersion&); + bool operator<(const PackedVersion&) const; + bool operator>=(const PackedVersion&) const; + bool operator==(const PackedVersion&) const; + private: + PackedVersion(uint32_t v) : _value(v) { } - static std::unique_ptr<MachOTargetInfo> create(const LinkerOptions &lo); + uint32_t _value; + }; + + bool minOS(StringRef mac, StringRef iOS) const; + + uint32_t _outputFileType; // e.g MH_EXECUTE + bool _outputFileTypeStatic; // Disambiguate static vs dynamic prog + Arch _arch; + OS _os; + PackedVersion _osMinVersion; + uint64_t _pageZeroSize; + mutable std::unique_ptr<mach_o::KindHandler> _kindHandler; + mutable std::unique_ptr<Reader> _machoReader; + mutable std::unique_ptr<Reader> _yamlReader; + mutable std::unique_ptr<Writer> _writer; }; + } // end namespace lld #endif diff --git a/lld/include/lld/ReaderWriter/Reader.h b/lld/include/lld/ReaderWriter/Reader.h index 228184bb2ef..133dc05e677 100644 --- a/lld/include/lld/ReaderWriter/Reader.h +++ b/lld/include/lld/ReaderWriter/Reader.h @@ -11,7 +11,6 @@ #define LLD_READERWRITER_READER_H #include "lld/Core/LLVM.h" -#include "lld/Core/TargetInfo.h" #include <functional> #include <memory> @@ -21,7 +20,7 @@ namespace lld { class ELFTargetInfo; class File; class LinkerInput; -struct LinkerOptions; +class TargetInfo; /// \brief An abstract class for reading object files, library files, and /// executable files. @@ -34,30 +33,27 @@ public: /// \brief Parse a file given its file system path and create a File object. virtual error_code readFile(StringRef path, - std::vector<std::unique_ptr<File>> &result); + std::vector<std::unique_ptr<File>> &result) const; /// \brief Parse a supplied buffer (already filled with the contents of a /// file) and create a File object. /// /// On success, the resulting File object takes ownership of the MemoryBuffer. - virtual error_code parseFile(std::unique_ptr<MemoryBuffer> mb, - std::vector<std::unique_ptr<File>> &result) = 0; + virtual error_code parseFile(std::unique_ptr<MemoryBuffer> &mb, + std::vector<std::unique_ptr<File>> &result) const = 0; protected: // only concrete subclasses can be instantiated Reader(const TargetInfo &ti) - : _targetInfo(ti), _options(ti.getLinkerOptions()) {} + : _targetInfo(ti) {} const TargetInfo &_targetInfo; - const LinkerOptions &_options; }; typedef ErrorOr<Reader &> ReaderFunc(const LinkerInput &); -std::unique_ptr<Reader> createReaderELF(const ELFTargetInfo &, - std::function<ReaderFunc>); -std::unique_ptr<Reader> createReaderMachO(const TargetInfo &, - std::function<ReaderFunc>); +std::unique_ptr<Reader> createReaderELF(const ELFTargetInfo &); +std::unique_ptr<Reader> createReaderMachO(const TargetInfo &); std::unique_ptr<Reader> createReaderNative(const TargetInfo &); std::unique_ptr<Reader> createReaderPECOFF(const TargetInfo &, std::function<ReaderFunc>); diff --git a/lld/include/lld/ReaderWriter/ReaderArchive.h b/lld/include/lld/ReaderWriter/ReaderArchive.h index 9420c847349..c1e8cd7335f 100644 --- a/lld/include/lld/ReaderWriter/ReaderArchive.h +++ b/lld/include/lld/ReaderWriter/ReaderArchive.h @@ -29,19 +29,17 @@ class TargetInfo; /// \brief ReaderArchive is a class for reading archive libraries class ReaderArchive : public Reader { public: - ReaderArchive(const TargetInfo &ti, - std::function<ErrorOr<Reader&> (const LinkerInput &)> getReader) - : Reader(ti), - _getReader(getReader) {} + ReaderArchive(const TargetInfo &ti, const Reader &memberReader) + : Reader(ti) { + } /// \brief Returns a vector of Files that are contained in the archive file /// pointed to by the Memorybuffer - error_code parseFile(std::unique_ptr<llvm::MemoryBuffer> mb, - std::vector<std::unique_ptr<File>> &result); + error_code parseFile(std::unique_ptr<llvm::MemoryBuffer> &mb, + std::vector<std::unique_ptr<File>> &result) const; private: - std::function<ErrorOr<Reader&> (const LinkerInput &)> _getReader; - std::unique_ptr<llvm::object::Archive> _archive; + mutable std::unique_ptr<llvm::object::Archive> _archive; }; } // end namespace lld diff --git a/lld/include/lld/ReaderWriter/ReaderLinkerScript.h b/lld/include/lld/ReaderWriter/ReaderLinkerScript.h index 9482f3b6d15..0dfa5d3c20a 100644 --- a/lld/include/lld/ReaderWriter/ReaderLinkerScript.h +++ b/lld/include/lld/ReaderWriter/ReaderLinkerScript.h @@ -21,19 +21,15 @@ class TargetInfo; /// \brief ReaderLinkerScript is a class for reading linker scripts class ReaderLinkerScript : public Reader { public: - ReaderLinkerScript( - const TargetInfo &ti, - std::function<ErrorOr<Reader &>(const LinkerInput &)> getReader) - : Reader(ti), _getReader(getReader) {} + ReaderLinkerScript(const TargetInfo &ti) + : Reader(ti) {} /// \brief Returns a vector of Files that are contained in the archive file /// pointed to by the Memorybuffer - error_code parseFile(std::unique_ptr<llvm::MemoryBuffer> mb, - std::vector<std::unique_ptr<File>> &result); - -private: - std::function<ErrorOr<Reader &>(const LinkerInput &)> _getReader; + error_code parseFile(std::unique_ptr<llvm::MemoryBuffer> &mb, + std::vector<std::unique_ptr<File>> &result) const; }; + } // end namespace lld #endif diff --git a/lld/include/lld/ReaderWriter/Simple.h b/lld/include/lld/ReaderWriter/Simple.h index a88c0cb55a4..fd25f10f7fe 100644 --- a/lld/include/lld/ReaderWriter/Simple.h +++ b/lld/include/lld/ReaderWriter/Simple.h @@ -171,7 +171,11 @@ private: class SimpleUndefinedAtom : public UndefinedAtom { public: - SimpleUndefinedAtom(const File &f, StringRef name) : _file(f), _name(name) {} + SimpleUndefinedAtom(const File &f, StringRef name) + : _file(f) + , _name(name) { + assert(!name.empty() && "UndefinedAtoms must have a name"); + } /// file - returns the File that produced/owns this Atom virtual const class File &file() const { return _file; } diff --git a/lld/lib/Core/Resolver.cpp b/lld/lib/Core/Resolver.cpp index 6d3880f31d3..d5e747fc0de 100644 --- a/lld/lib/Core/Resolver.cpp +++ b/lld/lib/Core/Resolver.cpp @@ -10,7 +10,6 @@ #include "lld/Core/Atom.h" #include "lld/Core/File.h" #include "lld/Core/InputFiles.h" -#include "lld/Core/LinkerOptions.h" #include "lld/Core/LLVM.h" #include "lld/Core/Resolver.h" #include "lld/Core/SymbolTable.h" @@ -129,7 +128,7 @@ void Resolver::doDefinedAtom(const DefinedAtom &atom) { // tell symbol table _symbolTable.add(atom); - if (_targetInfo.getLinkerOptions()._deadStrip) { + if (_targetInfo.deadStrip()) { // add to set of dead-strip-roots, all symbols that // the compiler marks as don't strip if (atom.deadStrip() == DefinedAtom::deadStripNever) @@ -182,11 +181,11 @@ void Resolver::addAtoms(const std::vector<const DefinedAtom*>& newAtoms) { // ask symbol table if any definitionUndefined atoms still exist // if so, keep searching libraries until no more atoms being added void Resolver::resolveUndefines() { - const bool searchArchives = _targetInfo.getLinkerOptions(). - _searchArchivesToOverrideTentativeDefinitions; - const bool searchSharedLibs = _targetInfo.getLinkerOptions(). - _searchSharedLibrariesToOverrideTentativeDefinitions; - + const bool searchArchives = + _targetInfo.searchArchivesToOverrideTentativeDefinitions(); + const bool searchSharedLibs = + _targetInfo.searchSharedLibrariesToOverrideTentativeDefinitions(); + // keep looping until no more undefines were added in last loop unsigned int undefineGenCount = 0xFFFFFFFF; while (undefineGenCount != _symbolTable.size()) { @@ -259,14 +258,14 @@ void Resolver::markLive(const Atom &atom) { // remove all atoms not actually used void Resolver::deadStripOptimize() { // only do this optimization with -dead_strip - if (!_targetInfo.getLinkerOptions()._deadStrip) + if (!_targetInfo.deadStrip()) return; // clear liveness on all atoms _liveAtoms.clear(); // By default, shared libraries are built with all globals as dead strip roots - if (_targetInfo.getLinkerOptions()._globalsAreDeadStripRoots) { + if (_targetInfo.globalsAreDeadStripRoots()) { for ( const Atom *atom : _atoms ) { const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom); if (defAtom == nullptr) @@ -277,7 +276,7 @@ void Resolver::deadStripOptimize() { } // Or, use list of names that are dead stip roots. - for (const StringRef &name : _targetInfo.getLinkerOptions()._deadStripRoots) { + for (const StringRef &name : _targetInfo.deadStripRoots()) { const Atom *symAtom = _symbolTable.findByName(name); assert(symAtom->definition() != Atom::definitionUndefined); _deadStripRoots.insert(symAtom); @@ -295,15 +294,15 @@ void Resolver::deadStripOptimize() { // error out if some undefines remain -void Resolver::checkUndefines(bool final) { +bool Resolver::checkUndefines(bool final) { // when using LTO, undefines are checked after bitcode is optimized if (_haveLLVMObjs && !final) - return; + return false; // build vector of remaining undefined symbols std::vector<const UndefinedAtom *> undefinedAtoms; _symbolTable.undefines(undefinedAtoms); - if (_targetInfo.getLinkerOptions()._deadStrip) { + if (_targetInfo.deadStrip()) { // When dead code stripping, we don't care if dead atoms are undefined. undefinedAtoms.erase(std::remove_if( undefinedAtoms.begin(), undefinedAtoms.end(), @@ -311,21 +310,25 @@ void Resolver::checkUndefines(bool final) { } // error message about missing symbols - if (!undefinedAtoms.empty() && - (!_targetInfo.getLinkerOptions()._noInhibitExec || - _targetInfo.getLinkerOptions()._outputKind == OutputKind::Relocatable)) { + if (!undefinedAtoms.empty()) { // FIXME: need diagonstics interface for writing error messages - bool isError = false; + bool foundUndefines = false; for (const UndefinedAtom *undefAtom : undefinedAtoms) { if (undefAtom->canBeNull() == UndefinedAtom::canBeNullNever) { - llvm::errs() << "Undefined Symbol: " << undefAtom->file().path() - << " : " << undefAtom->name() << "\n"; - isError = true; + foundUndefines = true; + if (_targetInfo.printRemainingUndefines()) { + llvm::errs() << "Undefined Symbol: " << undefAtom->file().path() + << " : " << undefAtom->name() << "\n"; + } } } - if (isError) - llvm::report_fatal_error("symbol(s) not found"); + if (foundUndefines) { + if (_targetInfo.printRemainingUndefines()) + llvm::errs() << "symbol(s) not found\n"; + return true; + } } + return false; } @@ -357,16 +360,20 @@ void Resolver::linkTimeOptimize() { // FIX ME } -void Resolver::resolve() { +bool Resolver::resolve() { this->buildInitialAtomList(); this->resolveUndefines(); this->updateReferences(); this->deadStripOptimize(); - this->checkUndefines(false); + if (this->checkUndefines(false)) { + if (!_targetInfo.allowRemainingUndefines()) + return true; + } this->removeCoalescedAwayAtoms(); this->checkDylibSymbolCollisions(); this->linkTimeOptimize(); this->_result.addAtoms(_atoms); + return false; } void Resolver::MergedFile::addAtom(const Atom& atom) { diff --git a/lld/lib/Core/SymbolTable.cpp b/lld/lib/Core/SymbolTable.cpp index 36e52d8ed07..4ded5a62597 100644 --- a/lld/lib/Core/SymbolTable.cpp +++ b/lld/lib/Core/SymbolTable.cpp @@ -13,7 +13,6 @@ #include "lld/Core/DefinedAtom.h" #include "lld/Core/File.h" #include "lld/Core/InputFiles.h" -#include "lld/Core/LinkerOptions.h" #include "lld/Core/LLVM.h" #include "lld/Core/Resolver.h" #include "lld/Core/SharedLibraryAtom.h" @@ -184,8 +183,7 @@ void SymbolTable::addByName(const Atom & newAtom) { useNew = false; } else { - if (_targetInfo.getLinkerOptions(). - _warnIfCoalesableAtomsHaveDifferentCanBeNull) { + if (_targetInfo.warnIfCoalesableAtomsHaveDifferentCanBeNull()) { // FIXME: need diagonstics interface for writing warning messages llvm::errs() << "lld warning: undefined symbol " << existingUndef->name() @@ -210,8 +208,7 @@ void SymbolTable::addByName(const Atom & newAtom) { bool sameName = curShLib->loadName().equals(newShLib->loadName()); if ( !sameName ) { useNew = false; - if (_targetInfo.getLinkerOptions(). - _warnIfCoalesableAtomsHaveDifferentLoadName) { + if (_targetInfo.warnIfCoalesableAtomsHaveDifferentLoadName()) { // FIXME: need diagonstics interface for writing warning messages llvm::errs() << "lld warning: shared library symbol " << curShLib->name() @@ -223,8 +220,7 @@ void SymbolTable::addByName(const Atom & newAtom) { } else if ( ! sameNullness ) { useNew = false; - if (_targetInfo.getLinkerOptions(). - _warnIfCoalesableAtomsHaveDifferentCanBeNull) { + if (_targetInfo.warnIfCoalesableAtomsHaveDifferentCanBeNull()) { // FIXME: need diagonstics interface for writing warning messages llvm::errs() << "lld warning: shared library symbol " << curShLib->name() diff --git a/lld/lib/Core/TargetInfo.cpp b/lld/lib/Core/TargetInfo.cpp index da834fb2c9c..05d7ffa5989 100644 --- a/lld/lib/Core/TargetInfo.cpp +++ b/lld/lib/Core/TargetInfo.cpp @@ -8,28 +8,49 @@ //===----------------------------------------------------------------------===// #include "lld/Core/TargetInfo.h" - -#include "lld/Core/LinkerOptions.h" +#include "lld/ReaderWriter/Writer.h" #include "llvm/ADT/Triple.h" namespace lld { + +TargetInfo::TargetInfo() + : Reader(*this) + , _deadStrip(false) + , _globalsAreDeadStripRoots(false) + , _searchArchivesToOverrideTentativeDefinitions(false) + , _searchSharedLibrariesToOverrideTentativeDefinitions(false) + , _warnIfCoalesableAtomsHaveDifferentCanBeNull(false) + , _warnIfCoalesableAtomsHaveDifferentLoadName(false) + , _forceLoadAllArchives(false) + , _printRemainingUndefines(true) + , _allowRemainingUndefines(false) +{ +} + TargetInfo::~TargetInfo() {} -llvm::Triple TargetInfo::getTriple() const { - return llvm::Triple(llvm::Triple::normalize(_options._target)); + +error_code TargetInfo::readFile(StringRef path, + std::vector<std::unique_ptr<File>> &result) const { + OwningPtr<llvm::MemoryBuffer> opmb; + if (error_code ec = llvm::MemoryBuffer::getFileOrSTDIN(path, opmb)) + return ec; + + std::unique_ptr<MemoryBuffer> mb(opmb.take()); + return this->parseFile(mb, result); } -bool TargetInfo::is64Bits() const { - return getTriple().isArch64Bit(); +error_code TargetInfo::writeFile(const File &linkedFile) const { + return this->writer().writeFile(linkedFile, _outputPath); } -bool TargetInfo::isLittleEndian() const { - // TODO: Do this properly. It is not defined purely by arch. - return true; +void TargetInfo::addImplicitFiles(InputFiles& inputs) const { + this->writer().addFiles(inputs); } -StringRef TargetInfo::getEntry() const { - return _options._entrySymbol; +void TargetInfo::addPasses(PassManager &pm) const { } + + } // end namespace lld diff --git a/lld/lib/Driver/CMakeLists.txt b/lld/lib/Driver/CMakeLists.txt index 13e6298b9a2..30aa26aa9f1 100644 --- a/lld/lib/Driver/CMakeLists.txt +++ b/lld/lib/Driver/CMakeLists.txt @@ -2,12 +2,16 @@ 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) +set(LLVM_TARGET_DEFINITIONS DarwinOptions.td) +tablegen(LLVM DarwinOptions.inc -gen-opt-parser-defs) add_public_tablegen_target(DriverOptionsTableGen) add_lld_library(lldDriver + CoreDriver.cpp + DarwinLdDriver.cpp Driver.cpp - Drivers.cpp - LinkerInvocation.cpp + GnuLdDriver.cpp + UniversalDriver.cpp ) add_dependencies(lldDriver DriverOptionsTableGen) diff --git a/lld/lib/Driver/CoreDriver.cpp b/lld/lib/Driver/CoreDriver.cpp new file mode 100644 index 00000000000..a4fb2166a4b --- /dev/null +++ b/lld/lib/Driver/CoreDriver.cpp @@ -0,0 +1,158 @@ +//===- lib/Driver/CoreDriver.cpp ------------------------------------------===// +// +// 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" +#include "lld/ReaderWriter/CoreTargetInfo.h" +#include "lld/ReaderWriter/Reader.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/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Signals.h" + +using namespace lld; + +namespace { + +// Create enum with OPT_xxx values for each option in DarwinOptions.td +enum CoreOpt { + OPT_INVALID = 0, +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, HELP, META) \ + OPT_##ID, +#include "CoreOptions.inc" + LastOption +#undef OPTION +}; + +// Create prefix string literals used in CoreOptions.td +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +#include "CoreOptions.inc" +#undef PREFIX + +// Create table mapping all options defined in CoreOptions.td +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 +}; + +// Create OptTable class for parsing actual command line arguments +class CoreOptTable : public llvm::opt::OptTable { +public: + CoreOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){} +}; + + + +} // namespace anonymous + + +namespace lld { + +bool CoreDriver::link(int argc, const char *argv[], raw_ostream &diagnostics) { + CoreTargetInfo info; + if (parse(argc, argv, info)) + return true; + + return Driver::link(info); +} + + +bool CoreDriver::parse(int argc, const char *argv[], + CoreTargetInfo &info, raw_ostream &diagnostics) { + // Parse command line options using CoreOptions.td + std::unique_ptr<llvm::opt::InputArgList> parsedArgs; + CoreOptTable table; + unsigned missingIndex; + unsigned missingCount; + parsedArgs.reset(table.ParseArgs(&argv[1], &argv[argc], + missingIndex, missingCount)); + if (missingCount) { + diagnostics << "error: missing arg value for '" + << parsedArgs->getArgString(missingIndex) + << "' expected " << missingCount << " argument(s).\n"; + return true; + } + + for (auto it = parsedArgs->filtered_begin(OPT_UNKNOWN), + ie = parsedArgs->filtered_end(); it != ie; ++it) { + diagnostics << "warning: ignoring unknown argument: " + << (*it)->getAsString(*parsedArgs) << "\n"; + } + + + // Handle -e xxx + if (llvm::opt::Arg *entry = parsedArgs->getLastArg(OPT_entry)) + info.setEntrySymbolName(entry->getValue()); + + // Handle -o xxx + if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_output)) + info.setOutputPath(outpath->getValue()); + else + info.setOutputPath("-"); + + // Handle --dead_strip + if (parsedArgs->getLastArg(OPT_dead_strip)) + info.setDeadStripping(true); + else + info.setDeadStripping(false); + + // Handle --keep-globals + if (parsedArgs->getLastArg(OPT_keep_globals)) + info.setGlobalsAreDeadStripRoots(true); + else + info.setGlobalsAreDeadStripRoots(false); + + // Handle --undefines-are-errors + if (parsedArgs->getLastArg(OPT_undefines_are_errors)) { + info.setPrintRemainingUndefines(true); + info.setAllowRemainingUndefines(false); + } + else { + info.setPrintRemainingUndefines(false); + info.setAllowRemainingUndefines(true); + } + + // Handle --commons-search-archives + if (parsedArgs->getLastArg(OPT_commons_search_archives)) + info.setSearchArchivesToOverrideTentativeDefinitions(true); + else + info.setSearchArchivesToOverrideTentativeDefinitions(false); + + // Handle --add-pass xxx option + for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_add_pass), + ie = parsedArgs->filtered_end(); + it != ie; ++it) { + info.addPassNamed((*it)->getValue()); + } + + // Handle input files + for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_INPUT), + ie = parsedArgs->filtered_end(); + it != ie; ++it) { + info.appendInputFile((*it)->getValue()); + } + + return false; +} + +} // namespace lld + diff --git a/lld/lib/Driver/CoreOptions.td b/lld/lib/Driver/CoreOptions.td index 8a53fd35cbe..df7cb41737d 100644 --- a/lld/lib/Driver/CoreOptions.td +++ b/lld/lib/Driver/CoreOptions.td @@ -1,22 +1,15 @@ include "llvm/Option/OptParser.td" -def core : Flag<["-"], "core">; -def flavor : Separate<["-"], "flavor">; -def target : Separate<["-"], "target">, HelpText<"Target triple to link for">; -def mllvm : Separate<["-"], "mllvm">, HelpText<"Options to pass to LLVM">; - -def output : Joined<["-"], "output=">; -def entry : Joined<["-"], "entry=">; -def input_search_path : Joined<["-"], "input-search-path=">; -def output_type : Joined<["-"], "output-type=">; -def relocatable : Flag<["-"], "relocatable">; +def output : Separate<["-"], "o">; +def entry : Separate<["-"], "e">; -def OCTOTHORPE_OCTOTHORPE_OCTOTHORPE : Flag<["-"], "###">; +def dead_strip : Flag<["--"], "dead-strip">; +def undefines_are_errors : Flag<["--"], "undefines-are-errors">; +def keep_globals : Flag<["--"], "keep-globals">; +def commons_search_archives : Flag<["--"], "commons-search-archives">; -def emit_yaml : Flag<["-"], "emit-yaml">; +def add_pass : Separate<["--"], "add-pass">; -def noinhibit_exec : Flag<["-"], "noinhibit-exec">, - HelpText<"Retain the executable output file whenever it is still usable">; +def target : Separate<["-"], "target">, HelpText<"Target triple to link for">; +def mllvm : Separate<["-"], "mllvm">, HelpText<"Options to pass to LLVM">; -def merge_strings : Flag<["-"], "merge-strings">, - HelpText<"Merge common strings across mergeable sections">; diff --git a/lld/lib/Driver/DarwinLdDriver.cpp b/lld/lib/Driver/DarwinLdDriver.cpp new file mode 100644 index 00000000000..1dbe5dfec0d --- /dev/null +++ b/lld/lib/Driver/DarwinLdDriver.cpp @@ -0,0 +1,197 @@ +//===- lib/Driver/DarwinLdDriver.cpp --------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// Concrete instance of the Driver for darwin's ld. +/// +//===----------------------------------------------------------------------===// + +#include "lld/Driver/Driver.h" +#include "lld/ReaderWriter/MachOTargetInfo.h" +#include "../ReaderWriter/MachO/MachOFormat.hpp" + +#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/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Signals.h" + + +namespace { + +// Create enum with OPT_xxx values for each option in DarwinOptions.td +enum DarwinOpt { + OPT_INVALID = 0, +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, HELP, META) \ + OPT_##ID, +#include "DarwinOptions.inc" + LastOption +#undef OPTION +}; + +// Create prefix string literals used in DarwinOptions.td +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +#include "DarwinOptions.inc" +#undef PREFIX + +// Create table mapping all options defined in DarwinOptions.td +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 "DarwinOptions.inc" +#undef OPTION +}; + +// Create OptTable class for parsing actual command line arguments +class DarwinLdOptTable : public llvm::opt::OptTable { +public: + DarwinLdOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){} +}; + + +} // namespace anonymous + +namespace lld { + +bool DarwinLdDriver::linkMachO(int argc, const char *argv[], + raw_ostream &diagnostics) { + MachOTargetInfo info; + if (parse(argc, argv, info, diagnostics)) + return true; + + return link(info, diagnostics); +} + + + +bool DarwinLdDriver::parse(int argc, const char *argv[], + MachOTargetInfo &info, raw_ostream &diagnostics) { + // Parse command line options using DarwinOptions.td + std::unique_ptr<llvm::opt::InputArgList> parsedArgs; + DarwinLdOptTable table; + unsigned missingIndex; + unsigned missingCount; + parsedArgs.reset(table.ParseArgs(&argv[1], &argv[argc], + missingIndex, missingCount)); + if (missingCount) { + diagnostics << "error: missing arg value for '" + << parsedArgs->getArgString(missingIndex) + << "' expected " << missingCount << " argument(s).\n"; + return true; + } + + for (auto it = parsedArgs->filtered_begin(OPT_UNKNOWN), + ie = parsedArgs->filtered_end(); it != ie; ++it) { + diagnostics << "warning: ignoring unknown argument: " + << (*it)->getAsString(*parsedArgs) << "\n"; + } + + // Figure out output kind ( -dylib, -r, -bundle, -preload, or -static ) + if ( llvm::opt::Arg *kind = parsedArgs->getLastArg(OPT_dylib, OPT_relocatable, + OPT_bundle, OPT_static, OPT_preload)) { + switch (kind->getOption().getID()) { + case OPT_dylib: + info.setOutputFileType(mach_o::MH_DYLIB); + break; + case OPT_relocatable: + info.setPrintRemainingUndefines(false); + info.setAllowRemainingUndefines(true); + info.setOutputFileType(mach_o::MH_OBJECT); + break; + case OPT_bundle: + info.setOutputFileType(mach_o::MH_BUNDLE); + break; + case OPT_static: + info.setOutputFileType(mach_o::MH_EXECUTE); + break; + case OPT_preload: + info.setOutputFileType(mach_o::MH_PRELOAD); + break; + } + } + + // Handle -e xxx + if (llvm::opt::Arg *entry = parsedArgs->getLastArg(OPT_entry)) + info.setEntrySymbolName(entry->getValue()); + + // Handle -o xxx + if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_output)) + info.setOutputPath(outpath->getValue()); + + // Handle -dead_strip + if (parsedArgs->getLastArg(OPT_dead_strip)) + info.setDeadStripping(true); + + // Handle -arch xxx + if (llvm::opt::Arg *archStr = parsedArgs->getLastArg(OPT_arch)) { + info.setArch(llvm::StringSwitch<MachOTargetInfo::Arch>(archStr->getValue()) + .Case("x86_64", MachOTargetInfo::arch_x86_64) + .Case("i386", MachOTargetInfo::arch_x86) + .Case("armv6", MachOTargetInfo::arch_armv6) + .Case("armv7", MachOTargetInfo::arch_armv7) + .Case("armv7s", MachOTargetInfo::arch_armv7s) + .Default(MachOTargetInfo::arch_unknown)); + } + + // Handle -macosx_version_min or -ios_version_min + if (llvm::opt::Arg *minOS = parsedArgs->getLastArg( + OPT_macosx_version_min, + OPT_ios_version_min, + OPT_ios_simulator_version_min)) { + switch (minOS->getOption().getID()) { + case OPT_macosx_version_min: + if (info.setOS(MachOTargetInfo::OS::macOSX, minOS->getValue())) { + diagnostics << "error: malformed macosx_version_min value\n"; + return true; + } + break; + case OPT_ios_version_min: + if (info.setOS(MachOTargetInfo::OS::iOS, minOS->getValue())) { + diagnostics << "error: malformed ios_version_min value\n"; + return true; + } + break; + case OPT_ios_simulator_version_min: + if (info.setOS(MachOTargetInfo::OS::iOS_simulator, minOS->getValue())) { + diagnostics << "error: malformed ios_simulator_version_min value\n"; + return true; + } + break; + } + } + else { + // No min-os version on command line, check environment variables + + } + + // Handle input files + for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_INPUT), + ie = parsedArgs->filtered_end(); + it != ie; ++it) { + info.appendInputFile((*it)->getValue()); + } + + return false; +} + + +} // namespace lld + + diff --git a/lld/lib/Driver/DarwinOptions.td b/lld/lib/Driver/DarwinOptions.td new file mode 100644 index 00000000000..b51d97d5602 --- /dev/null +++ b/lld/lib/Driver/DarwinOptions.td @@ -0,0 +1,30 @@ +include "llvm/Option/OptParser.td" + +// output kinds +def relocatable : Flag<["-"], "r">, HelpText<"create relocatable output">; +def static : Flag<["-"], "static">; +def dynamic : Flag<["-"], "dynamic">; +def dylib : Flag<["-"], "dylib">; +def bundle : Flag<["-"], "bundle">; +def execute : Flag<["-"], "execute">; +def preload : Flag<["-"], "preload">; + +// linking options +def dead_strip : Flag<["-"], "dead_strip">; +def entry : Separate<["-"], "e">, HelpText<"entry symbol name">; +def mllvm : Separate<["-"], "mllvm">, HelpText<"Options to pass to LLVM">; +def arch : Separate<["-"], "arch">, HelpText<"architecture">; +def macosx_version_min : Separate<["-"], "macosx_version_min">, + HelpText<"min Mac OS X version">; +def ios_version_min : Separate<["-"], "ios_version_min">, + HelpText<"min iOS version">; +def ios_simulator_version_min : Separate<["-"], "ios_simulator_version_min">, + HelpText<"min iOS simulator version">; + +// search options +def L : Joined<["-"], "L">; + +// inputs and outputs +def output : Separate<["-"], "o">, HelpText<"output file name">; + + diff --git a/lld/lib/Driver/Driver.cpp b/lld/lib/Driver/Driver.cpp index 5f7f4e6f555..cb3c611c2ce 100644 --- a/lld/lib/Driver/Driver.cpp +++ b/lld/lib/Driver/Driver.cpp @@ -8,7 +8,81 @@ //===----------------------------------------------------------------------===// #include "lld/Driver/Driver.h" +#include "lld/Core/LLVM.h" +#include "lld/Core/InputFiles.h" +#include "lld/Core/Resolver.h" +#include "lld/Core/PassManager.h" +#include "lld/ReaderWriter/Reader.h" +#include "lld/ReaderWriter/Writer.h" -using namespace lld; +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/Arg.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + +namespace lld { + +/// This is where the link is actually performed. +bool Driver::link(const TargetInfo &targetInfo, raw_ostream &diagnostics) { + // Honor -mllvm + if (!targetInfo.llvmOptions().empty()) { + unsigned numArgs = targetInfo.llvmOptions().size(); + const char **args = new const char*[numArgs + 2]; + args[0] = "lld (LLVM option parsing)"; + for (unsigned i = 0; i != numArgs; ++i) + args[i + 1] = targetInfo.llvmOptions()[i]; + args[numArgs + 1] = 0; + llvm::cl::ParseCommandLineOptions(numArgs + 1, args); + } + + // Read inputs + InputFiles inputs; + for (const auto &input : targetInfo.inputFiles()) { + std::vector<std::unique_ptr<File>> files; + if (targetInfo.logInputFiles()) + llvm::outs() << input.getPath() << "\n"; + + error_code ec = targetInfo.readFile(input.getPath(), files); + if (ec) { + diagnostics << "Failed to read file: " << input.getPath() << ": " + << ec.message() << "\n"; + return true; + } + inputs.appendFiles(files); + } + + // Give target a chance to add files. + targetInfo.addImplicitFiles(inputs); + + // assign an ordinal to each file so sort() can preserve command line order + inputs.assignFileOrdinals(); + + // Do core linking. + Resolver resolver(targetInfo, inputs); + if (resolver.resolve()) { + if (!targetInfo.allowRemainingUndefines()) + return true; + } + MutableFile &merged = resolver.resultFile(); + + // Run passes on linked atoms. + PassManager pm; + targetInfo.addPasses(pm); + pm.runOnFile(merged); + + // Give linked atoms to Writer to generate output file. + if (error_code ec = targetInfo.writeFile(merged)) { + diagnostics << "Failed to write file '" << targetInfo.outputPath() + << "': " << ec.message() << "\n"; + return true; + } + + return false; +} + + +} // namespace -Driver::~Driver() {} diff --git a/lld/lib/Driver/Drivers.cpp b/lld/lib/Driver/Drivers.cpp deleted file mode 100644 index d2c1b732046..00000000000 --- a/lld/lib/Driver/Drivers.cpp +++ /dev/null @@ -1,303 +0,0 @@ -//===- 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/Core/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/FileSystem.h" -#include "llvm/Support/Path.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 LLVM_FINAL : public Driver { -public: - LDDriver(StringRef defaultTargetTriple) : Driver(defaultTargetTriple) {} - - virtual std::unique_ptr<llvm::opt::DerivedArgList> - transform(llvm::ArrayRef<const char *> 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>(); - } - - for (llvm::opt::arg_iterator it = _inputArgs->filtered_begin(ld::OPT_UNKNOWN), - ie = _inputArgs->filtered_end(); - it != ie; ++it) { - llvm::errs() << "warning: ignoring unknown argument: " - << (*it)->getAsString(*_inputArgs) << "\n"; - } - - std::unique_ptr<llvm::opt::DerivedArgList> newArgs( - new llvm::opt::DerivedArgList(*_inputArgs)); - - bool isOutputDynamic = false; - - if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_target)) { - newArgs->AddSeparateArg( A, _core.getOption(core::OPT_target) - , A->getValue()); - } 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()); - - 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_static)) - newArgs->AddJoinedArg(A, _core.getOption(core::OPT_output_type), - newArgs->MakeArgString("static")); - else { - newArgs->AddJoinedArg(nullptr, _core.getOption(core::OPT_output_type), - newArgs->MakeArgString("dynamic")); - isOutputDynamic = true; - } - - if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_relocatable)) - newArgs->AddFlagArg(A, _core.getOption(core::OPT_relocatable)); - - if (llvm::opt::Arg *A = - _inputArgs->getLastArg(ld::OPT_OCTOTHORPE_OCTOTHORPE_OCTOTHORPE)) - newArgs->AddFlagArg(A, _core.getOption( - core::OPT_OCTOTHORPE_OCTOTHORPE_OCTOTHORPE)); - - if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_emit_yaml)) - newArgs->AddFlagArg(A, _core.getOption(core::OPT_emit_yaml)); - - if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_noinhibit_exec)) - newArgs->AddFlagArg(A, _core.getOption(core::OPT_noinhibit_exec)); - - if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_merge_strings)) - newArgs->AddFlagArg(A, _core.getOption(core::OPT_merge_strings)); - - // Copy search paths. - for (llvm::opt::arg_iterator it = _inputArgs->filtered_begin(ld::OPT_L), - ie = _inputArgs->filtered_end(); - it != ie; ++it) { - newArgs->AddPositionalArg( - *it, _core.getOption(core::OPT_input_search_path), (*it)->getValue()); - _inputSearchPaths.push_back((*it)->getValue()); - } - - // Copy input args. - for (llvm::opt::arg_iterator it = _inputArgs->filtered_begin(ld::OPT_INPUT, - ld::OPT_l), - ie = _inputArgs->filtered_end(); - it != ie; ++it) { - StringRef inputPath; - if ((*it)->getOption().getID() == ld::OPT_l) { - StringRef libName = (*it)->getValue(); - SmallString<128> p; - for (const auto &path : _inputSearchPaths) { - if (isOutputDynamic) { - p = path; - llvm::sys::path::append(p, Twine("lib") + libName + ".so"); - if (llvm::sys::fs::exists(p.str())) { - inputPath = newArgs->MakeArgString(p); - break; - } - } - p = path; - llvm::sys::path::append(p, Twine("lib") + libName + ".a"); - if (llvm::sys::fs::exists(p.str())) { - inputPath = newArgs->MakeArgString(p); - break; - } - } - if (inputPath.empty()) - llvm_unreachable("Failed to lookup library!"); - } else - inputPath = (*it)->getValue(); - newArgs->AddPositionalArg(*it, _core.getOption(core::OPT_INPUT), - inputPath); - } - - // Copy mllvm - for (llvm::opt::arg_iterator it = _inputArgs->filtered_begin(ld::OPT_mllvm), - ie = _inputArgs->filtered_end(); - it != ie; ++it) { - newArgs->AddPositionalArg(*it, _core.getOption(core::OPT_mllvm), - (*it)->getValue()); - } - - return std::move(newArgs); - } - -private: - std::unique_ptr<llvm::opt::InputArgList> _inputArgs; - core::CoreOptTable _core; - ld::LDOptTable _opt; - // Local cache of search paths so we can do lookups on -l. - std::vector<std::string> _inputSearchPaths; -}; - -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: - break; - } - llvm_unreachable("Unsupported flavor"); -} - -std::unique_ptr<llvm::opt::ArgList> -lld::parseCoreArgs(llvm::ArrayRef<const char *> args) { - core::CoreOptTable core; - unsigned missingIndex, missingCount; - std::unique_ptr<llvm::opt::ArgList> list( - core.ParseArgs( args.begin(), args.end(), missingIndex, missingCount)); - - if (missingCount) { - llvm::errs() << "error: missing arg value for '" - << list->getArgString(missingIndex) - << "' expected " << missingCount << " argument(s).\n"; - return std::unique_ptr<llvm::opt::ArgList>(); - } - - bool hasUnknown = false; - for (llvm::opt::arg_iterator it = list->filtered_begin(ld::OPT_UNKNOWN), - ie = list->filtered_end(); - it != ie; ++it) { - llvm::errs() << "error: ignoring unknown argument: " - << (*it)->getAsString(*list) << "\n"; - hasUnknown = true; - } - if (hasUnknown) - return std::unique_ptr<llvm::opt::ArgList>(); - - return list; -} - -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())); - } - - StringRef outputType = args.getLastArgValue(core::OPT_output_type); - ret._outputKind = llvm::StringSwitch<OutputKind>(outputType) - .Case("static", OutputKind::StaticExecutable) - .Case("dynamic", OutputKind::DynamicExecutable) - .Case("relocatable", OutputKind::Relocatable) - .Case("shared", OutputKind::Shared) - .Case("stubs", OutputKind::SharedStubs) - .Case("core", OutputKind::Core) - .Case("debug-symbols", OutputKind::DebugSymbols) - .Case("bundle", OutputKind::Bundle) - .Case("preload", OutputKind::Preload) - .Default(OutputKind::Invalid); - - ret._inputSearchPaths = args.getAllArgValues(core::OPT_input_search_path); - ret._llvmArgs = args.getAllArgValues(core::OPT_mllvm); - ret._target = llvm::Triple::normalize(args.getLastArgValue(core::OPT_target)); - ret._outputPath = args.getLastArgValue(core::OPT_output); - ret._entrySymbol = args.getLastArgValue(core::OPT_entry); - if (args.hasArg(core::OPT_relocatable)) - ret._outputKind = OutputKind::Relocatable; - ret._outputCommands = args.hasArg(core::OPT_OCTOTHORPE_OCTOTHORPE_OCTOTHORPE); - ret._outputYAML = args.hasArg(core::OPT_emit_yaml); - ret._noInhibitExec = args.hasArg(core::OPT_noinhibit_exec); - ret._mergeCommonStrings = args.hasArg(core::OPT_merge_strings); - - return std::move(ret); -} diff --git a/lld/lib/Driver/GnuLdDriver.cpp b/lld/lib/Driver/GnuLdDriver.cpp new file mode 100644 index 00000000000..55e38580029 --- /dev/null +++ b/lld/lib/Driver/GnuLdDriver.cpp @@ -0,0 +1,241 @@ +//===- lib/Driver/GnuLdDriver.cpp -----------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// Concrete instance of the Driver for GNU's ld. +/// +//===----------------------------------------------------------------------===// + +#include "lld/Driver/Driver.h" +#include "lld/ReaderWriter/ELFTargetInfo.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Signals.h" + +using namespace lld; + + +namespace { + +// Create enum with OPT_xxx values for each option in LDOptions.td +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 +}; + +// Create prefix string literals used in LDOptions.td +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +#include "LDOptions.inc" +#undef PREFIX + +// Create table mapping all options defined in LDOptions.td +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 +}; + + +// Create OptTable class for parsing actual command line arguments +class GnuLdOptTable : public llvm::opt::OptTable { +public: + GnuLdOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){} +}; + +} // namespace + + + +bool GnuLdDriver::linkELF(int argc, const char *argv[], + raw_ostream &diagnostics) { + std::unique_ptr<ELFTargetInfo> options(parse(argc, argv, diagnostics)); + if (!options) + return true; + + return link(*options, diagnostics); +} + + +std::unique_ptr<ELFTargetInfo> GnuLdDriver::parse(int argc, const char *argv[], + raw_ostream &diagnostics) { + // Parse command line options using LDOptions.td + std::unique_ptr<llvm::opt::InputArgList> parsedArgs; + GnuLdOptTable table; + unsigned missingIndex; + unsigned missingCount; + parsedArgs.reset(table.ParseArgs(&argv[1], &argv[argc], + missingIndex, missingCount)); + if (missingCount) { + diagnostics << "error: missing arg value for '" + << parsedArgs->getArgString(missingIndex) + << "' expected " << missingCount << " argument(s).\n"; + return nullptr; + } + + for (auto it = parsedArgs->filtered_begin(OPT_UNKNOWN), + ie = parsedArgs->filtered_end(); it != ie; ++it) { + diagnostics << "warning: ignoring unknown argument: " + << (*it)->getAsString(*parsedArgs) << "\n"; + } + + // Handle --help + if (parsedArgs->getLastArg(OPT_help)) { + table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false); + return nullptr; + } + + // Use -target or use default target triple to instantiate TargetInfo + llvm::Triple triple; + if (llvm::opt::Arg *trip = parsedArgs->getLastArg(OPT_target)) + triple = llvm::Triple(trip->getValue()); + else + triple = getDefaultTarget(argv[0]); + std::unique_ptr<ELFTargetInfo> options(ELFTargetInfo::create(triple)); + + if (!options) { + diagnostics << "unknown target triple\n"; + return nullptr; + } + + // Handle -e xxx + if (llvm::opt::Arg *entry = parsedArgs->getLastArg(OPT_entry)) + options->setEntrySymbolName(entry->getValue()); + + // Handle -emit-yaml + if (parsedArgs->getLastArg(OPT_emit_yaml)) + options->setOutputYAML(true); + + // Handle -o xxx + if (llvm::opt::Arg *output = parsedArgs->getLastArg(OPT_output)) + options->setOutputPath(output->getValue()); + else if (options->outputYAML()) + options->setOutputPath("-"); // yaml writes to stdout by default + else + options->setOutputPath("a.out"); + + // Handle -r, -shared, or -static + if ( llvm::opt::Arg *kind = parsedArgs->getLastArg(OPT_relocatable, + OPT_shared, + OPT_static)) { + switch (kind->getOption().getID()) { + case OPT_relocatable: + options->setOutputFileType(llvm::ELF::ET_REL); + options->setPrintRemainingUndefines(false); + options->setAllowRemainingUndefines(true); + break; + case OPT_shared: + options->setOutputFileType(llvm::ELF::ET_DYN); + break; + case OPT_static: + options->setOutputFileType(llvm::ELF::ET_EXEC); + options->setIsStaticExecutable(true); + break; + } + } + else { + options->setOutputFileType(llvm::ELF::ET_EXEC); + options->setIsStaticExecutable(false); + } + + // Handle --noinhibit-exec + if (parsedArgs->getLastArg(OPT_noinhibit_exec)) + options->setAllowRemainingUndefines(true); + + // Handle --force-load + if (parsedArgs->getLastArg(OPT_force_load)) + options->setForceLoadAllArchives(true); + + // Handle --merge-strings + if (parsedArgs->getLastArg(OPT_merge_strings)) + options->setMergeCommonStrings(true); + + // Handle -t + if (parsedArgs->getLastArg(OPT_t)) + options->setLogInputFiles(true); + + // Handle -Lxxx + for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_L), + ie = parsedArgs->filtered_end(); + it != ie; ++it) { + options->appendSearchPath((*it)->getValue()); + } + + // Copy mllvm + for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_mllvm), + ie = parsedArgs->filtered_end(); + it != ie; ++it) { + options->appendLLVMOption((*it)->getValue()); + } + + // Handle input files (full paths and -lxxx) + for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_INPUT,OPT_l), + ie = parsedArgs->filtered_end(); + it != ie; ++it) { + switch ((*it)->getOption().getID()) { + case OPT_INPUT: + options->appendInputFile((*it)->getValue()); + break; + case OPT_l: + if (options->appendLibrary((*it)->getValue())) { + diagnostics << "Failed to find library for " + << (*it)->getValue() << "\n"; + return nullptr; + } + break; + default: + llvm_unreachable("input option type not handled"); + } + } + + // Validate the combination of options used. + if (options->validate(diagnostics)) + return nullptr; + + return options; +} + + +/// Get the default target triple based on either the program name +/// (e.g. "x86-ibm-linux-lld") or the primary target llvm was configured for. +llvm::Triple GnuLdDriver::getDefaultTarget(const char *progName) { + SmallVector<StringRef, 4> components; + llvm::SplitString(llvm::sys::path::stem(progName), components, "-"); + // If has enough parts to be start with a triple. + if (components.size() >= 4) { + llvm::Triple triple(components[0], components[1], components[2], + components[3]); + // If first component looks like an arch. + if (triple.getArch() != llvm::Triple::UnknownArch) + return triple; + } + + // Fallback to use whatever default triple llvm was configured for. + return llvm::Triple(llvm::sys::getDefaultTargetTriple()); +} + diff --git a/lld/lib/Driver/LDOptions.td b/lld/lib/Driver/LDOptions.td index 516d487b41a..47e8a3cf78a 100644 --- a/lld/lib/Driver/LDOptions.td +++ b/lld/lib/Driver/LDOptions.td @@ -1,27 +1,29 @@ include "llvm/Option/OptParser.td" -def flavor : Separate<["-"], "flavor">; -def target : Separate<["-"], "target">, HelpText<"Target triple to link for">; +def target : Separate<["-"], "target">, + MetaVarName<"<triple>">, + HelpText<"Target triple to link for">; + def mllvm : Separate<["-"], "mllvm">, HelpText<"Options to pass to LLVM">; -def entry : Joined<["--"], "entry=">; +def entry : Joined<["--"], "entry=">, + HelpText<"Name of entry point symbol">; def entry_e : Separate<["-"], "e">, Alias<entry>; -def output : Joined<["--"], "output=">; -def output_e : Separate<["-"], "o">, Alias<output>; - +def output : Separate<["-"], "o">, + MetaVarName<"<path>">, + HelpText<"Path to file to write output">; + def relocatable : Flag<["--"], "relocatable">; def relocatable_r : Flag<["-"], "r">, Alias<relocatable>; def dynamic_linker : Separate<["-"], "dynamic-linker">; -def OCTOTHORPE_OCTOTHORPE_OCTOTHORPE : Flag<["-"], "###">; - -def emit_yaml : Flag<["-"], "emit-yaml">; def m : Separate<["-"], "m">; def z : Separate<["-"], "z">; +def t : Flag<["-"], "t">; def rpath : Separate<["-"], "rpath">; def soname : Separate<["-"], "soname">; @@ -32,12 +34,25 @@ def end_group : Flag<["--"], "end-group">; def build_id : Flag<["--"], "build-id">; def eh_frame_hdr : Flag<["--"], "eh-frame-hdr">; -def L : Joined<["-"], "L">; -def l : Joined<["-"], "l">; +def help : Flag<["--"], "help">; + +def L : Joined<["-"], "L">, + MetaVarName<"<dir>">, + HelpText<"Directory to search for libraries">; +def l : Joined<["-"], "l">, + MetaVarName<"<libName>">, + HelpText<"Root name of library to use">; def hash_style : Joined <["--"], "hash-style=">; def noinhibit_exec : Flag<["--"], "noinhibit-exec">, HelpText<"Retain the executable output file whenever it is still usable">; -def merge_strings : Flag<["-"], "merge-strings">, +def merge_strings : Flag<["--"], "merge-strings">, HelpText<"Merge common strings across mergeable sections">; + + +// extensions +def emit_yaml : Flag<["-"], "emit-yaml">, + HelpText<"Write YAML instead of ELF">; +def force_load : Flag<["--"], "force-load">, + HelpText<"Force load of all members in all static libraries">; diff --git a/lld/lib/Driver/LinkerInvocation.cpp b/lld/lib/Driver/LinkerInvocation.cpp deleted file mode 100644 index 21662774bd9..00000000000 --- a/lld/lib/Driver/LinkerInvocation.cpp +++ /dev/null @@ -1,98 +0,0 @@ -//===- 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/PassManager.h" -#include "lld/Core/Resolver.h" -#include "lld/ReaderWriter/ELFTargetInfo.h" -#include "lld/ReaderWriter/Reader.h" -#include "lld/ReaderWriter/Writer.h" - -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/raw_ostream.h" - -using namespace lld; - -namespace { -std::unique_ptr<TargetInfo> createTargetInfo(const LinkerOptions &lo) { - return ELFTargetInfo::create(lo); -} -} - -void LinkerInvocation::operator()() { - // Honor -mllvm - if (!_options._llvmArgs.empty()) { - unsigned NumArgs = _options._llvmArgs.size(); - const char **Args = new const char*[NumArgs + 2]; - Args[0] = "lld (LLVM option parsing)"; - for (unsigned i = 0; i != NumArgs; ++i) - Args[i + 1] = _options._llvmArgs[i].c_str(); - Args[NumArgs + 1] = 0; - llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args); - } - - // Create target. - std::unique_ptr<TargetInfo> targetInfo(createTargetInfo(_options)); - - if (!targetInfo) { - llvm::errs() << "Failed to create target for " << _options._target - << "\n"; - return; - } - - // Read inputs - InputFiles inputs; - for (const auto &input : _options._input) { - auto reader = targetInfo->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->parseFile(std::unique_ptr<MemoryBuffer>(MemoryBuffer::getMemBuffer(buffer->getBuffer(), buffer->getBufferIdentifier())), files)) { - llvm::errs() << "Failed to read file: " << input.getPath() << ": " - << ec.message() << "\n"; - return; - } - inputs.appendFiles(files); - } - inputs.assignFileOrdinals(); - - auto writer = targetInfo->getWriter(); - - // Give writer a chance to add files - writer->addFiles(inputs); - - Resolver resolver(*targetInfo, inputs); - resolver.resolve(); - MutableFile &merged = resolver.resultFile(); - - PassManager pm; - targetInfo->addPasses(pm); - pm.runOnFile(merged); - - 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/UniversalDriver.cpp b/lld/lib/Driver/UniversalDriver.cpp new file mode 100644 index 00000000000..5164f9da69c --- /dev/null +++ b/lld/lib/Driver/UniversalDriver.cpp @@ -0,0 +1,109 @@ +//===- lib/Driver/UniversalDriver.cpp -------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// Concrete instance of the Driver for darwin's ld. +/// +//===----------------------------------------------------------------------===// + +#include "lld/Driver/Driver.h" +#include "lld/ReaderWriter/MachOTargetInfo.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Signals.h" + +#include <memory> + +namespace lld { + + +bool UniversalDriver::link(int argc, const char *argv[]) { + // Convert argv[] C-array to vector. + std::vector<const char *> args; + args.assign(&argv[0], &argv[argc]); + + // Determine flavor of link based on command name or -flavor argument. + // Note: 'args' is modified to remove -flavor option. + Flavor flavor = selectFlavor(args); + + // Switch to appropriate driver. + switch (flavor) { + case Flavor::gnu_ld: + return GnuLdDriver::linkELF(args.size(), &args[0]); + case Flavor::darwin_ld: + return DarwinLdDriver::linkMachO(args.size(), &args[0]); + case Flavor::core: + return CoreDriver::link(args.size(), &args[0]); + case Flavor::win_link: + llvm_unreachable("Unsupported flavor"); + case Flavor::invalid: + return true; + } +} + + + + + +/// Pick the flavor of driver to use based on the command line and +/// host environment. +UniversalDriver::Flavor UniversalDriver::selectFlavor( + std::vector<const char*> &args) { + // -core as first arg is shorthand for -flavor core. + if (args.size() >= 1 && StringRef(args[1]) == "-core") { + args.erase(args.begin() + 1); + return Flavor::core; + } + // Handle -flavor as first arg. + if (args.size() >= 2 && StringRef(args[1]) == "-flavor") { + Flavor flavor = strToFlavor(args[2]); + args.erase(args.begin() + 1); + args.erase(args.begin() + 1); + if (flavor == Flavor::invalid) + llvm::errs() << "error: '" << args[2] << "' invalid value for -flavor.\n"; + return flavor; + } + + // Check if flavor is at end of program name (e.g. "lld-gnu"); + SmallVector<StringRef, 3> components; + llvm::SplitString(args[0], components, "-"); + Flavor flavor = strToFlavor(components.back()); + + // If flavor still undetermined, then error out. + if (flavor == Flavor::invalid) + llvm::errs() << "error: failed to determine driver flavor from program name" + " '" << args[0] << "'.\n"; + return flavor; +} + +/// Maps flavor strings to Flavor enum values. +UniversalDriver::Flavor UniversalDriver::strToFlavor(StringRef str) { + return llvm::StringSwitch<Flavor>(str) + .Case("gnu", Flavor::gnu_ld) + .Case("darwin", Flavor::darwin_ld) + .Case("link", Flavor::win_link) + .Case("core", Flavor::core) + .Case("ld", Flavor::gnu_ld) // deprecated + .Default(Flavor::invalid); +} + + +} // namespace lld diff --git a/lld/lib/Passes/LayoutPass.cpp b/lld/lib/Passes/LayoutPass.cpp index f6bf980006d..6edbcadbcbf 100644 --- a/lld/lib/Passes/LayoutPass.cpp +++ b/lld/lib/Passes/LayoutPass.cpp @@ -11,6 +11,7 @@ #define DEBUG_TYPE "LayoutPass" #include "lld/Passes/LayoutPass.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/Debug.h" @@ -435,6 +436,29 @@ void LayoutPass::perform(MutableFile &mergedFile) { // Build override maps buildOrdinalOverrideMap(atomRange); + DEBUG_WITH_TYPE("layout", llvm::dbgs() << "unsorted atoms:\n"); + for ( const DefinedAtom *atom : atomRange ) { + DEBUG_WITH_TYPE("layout", llvm::dbgs() + << " file=" << atom->file().path() + << ", name=" << atom->name() + << ", size=" << atom->size() + << ", type=" << atom->contentType() + << ", ordinal=" << atom->ordinal() + << "\n"); + } + // sort the atoms std::sort(atomRange.begin(), atomRange.end(), _compareAtoms); + + DEBUG_WITH_TYPE("layout", llvm::dbgs() << "sorted atoms:\n"); + for ( const DefinedAtom *atom : atomRange ) { + DEBUG_WITH_TYPE("layout", llvm::dbgs() + << " file=" << atom->file().path() + << ", name=" << atom->name() + << ", size=" << atom->size() + << ", type=" << atom->contentType() + << ", ordinal=" << atom->ordinal() + << "\n"); + } + } diff --git a/lld/lib/ReaderWriter/CMakeLists.txt b/lld/lib/ReaderWriter/CMakeLists.txt index 2ad3165ece6..fa3e71e8a37 100644 --- a/lld/lib/ReaderWriter/CMakeLists.txt +++ b/lld/lib/ReaderWriter/CMakeLists.txt @@ -6,6 +6,7 @@ add_subdirectory(Native) add_subdirectory(PECOFF) add_subdirectory(YAML) add_lld_library(lldReaderWriter + CoreTargetInfo.cpp LinkerScript.cpp Reader.cpp ReaderArchive.cpp diff --git a/lld/lib/ReaderWriter/CoreTargetInfo.cpp b/lld/lib/ReaderWriter/CoreTargetInfo.cpp new file mode 100644 index 00000000000..18da8378090 --- /dev/null +++ b/lld/lib/ReaderWriter/CoreTargetInfo.cpp @@ -0,0 +1,395 @@ +//===- lib/ReaderWriter/CoreTargetInfo.cpp --------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/ReaderWriter/CoreTargetInfo.h" + +#include "lld/Core/Pass.h" +#include "lld/Core/PassManager.h" +#include "lld/Passes/LayoutPass.h" + +#include "llvm/ADT/ArrayRef.h" + + +using namespace lld; + +namespace { + +/// \brief Simple atom created by the stubs pass. +class TestingStubAtom : public DefinedAtom { +public: + TestingStubAtom(const File &F, const Atom&) : _file(F) { + static uint32_t lastOrdinal = 0; + _ordinal = lastOrdinal++; + } + + virtual const File &file() const { + return _file; + } + + virtual StringRef name() const { + return StringRef(); + } + + virtual uint64_t ordinal() const { + return _ordinal; + } + + virtual uint64_t size() const { + return 0; + } + + virtual Scope scope() const { + return DefinedAtom::scopeLinkageUnit; + } + + virtual Interposable interposable() const { + return DefinedAtom::interposeNo; + } + + virtual Merge merge() const { + return DefinedAtom::mergeNo; + } + + virtual ContentType contentType() const { + return DefinedAtom::typeStub; + } + + virtual Alignment alignment() const { + return Alignment(0, 0); + } + + virtual SectionChoice sectionChoice() const { + return DefinedAtom::sectionBasedOnContent; + } + + virtual StringRef customSectionName() const { + return StringRef(); + } + + virtual SectionPosition sectionPosition() const { + return sectionPositionAny; + } + + virtual DeadStripKind deadStrip() const { + return DefinedAtom::deadStripNormal; + } + + virtual ContentPermissions permissions() const { + return DefinedAtom::permR_X; + } + + virtual bool isThumb() const { + return false; + } + + virtual bool isAlias() const { + return false; + } + + virtual ArrayRef<uint8_t> rawContent() const { + return ArrayRef<uint8_t>(); + } + + virtual reference_iterator begin() const { + return reference_iterator(*this, nullptr); + } + + virtual reference_iterator end() const { + return reference_iterator(*this, nullptr); + } + + virtual const Reference *derefIterator(const void *iter) const { + return nullptr; + } + + virtual void incrementIterator(const void *&iter) const { + } + +private: + const File &_file; + uint32_t _ordinal; +}; + +/// \brief Simple atom created by the GOT pass. +class TestingGOTAtom : public DefinedAtom { +public: + TestingGOTAtom(const File &F, const Atom&) : _file(F) { + static uint32_t lastOrdinal = 0; + _ordinal = lastOrdinal++; + } + + virtual const File &file() const { + return _file; + } + + virtual StringRef name() const { + return StringRef(); + } + + virtual uint64_t ordinal() const { + return _ordinal; + } + + virtual uint64_t size() const { + return 0; + } + + virtual Scope scope() const { + return DefinedAtom::scopeLinkageUnit; + } + + virtual Interposable interposable() const { + return DefinedAtom::interposeNo; + } + + virtual Merge merge() const { + return DefinedAtom::mergeNo; + } + + virtual ContentType contentType() const { + return DefinedAtom::typeGOT; + } + + virtual Alignment alignment() const { + return Alignment(3, 0); + } + + virtual SectionChoice sectionChoice() const { + return DefinedAtom::sectionBasedOnContent; + } + + virtual StringRef customSectionName() const { + return StringRef(); + } + + virtual SectionPosition sectionPosition() const { + return sectionPositionAny; + } + + virtual DeadStripKind deadStrip() const { + return DefinedAtom::deadStripNormal; + } + + virtual ContentPermissions permissions() const { + return DefinedAtom::permRW_; + } + + virtual bool isThumb() const { + return false; + } + + virtual bool isAlias() const { + return false; + } + + virtual ArrayRef<uint8_t> rawContent() const { + return ArrayRef<uint8_t>(); + } + + virtual reference_iterator begin() const { + return reference_iterator(*this, nullptr); + } + + virtual reference_iterator end() const { + return reference_iterator(*this, nullptr); + } + + virtual const Reference *derefIterator(const void *iter) const { + return nullptr; + } + + virtual void incrementIterator(const void *&iter) const { + } + +private: + const File &_file; + uint32_t _ordinal; +}; + +class TestingPassFile : public MutableFile { +public: + TestingPassFile(const TargetInfo &ti) : MutableFile(ti, "Testing pass") {} + + virtual void addAtom(const Atom &atom) { + if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&atom)) + _definedAtoms._atoms.push_back(defAtom); + else + llvm_unreachable("atom has unknown definition kind"); + } + + virtual DefinedAtomRange definedAtoms() { + return range<std::vector<const DefinedAtom*>::iterator>( + _definedAtoms._atoms.begin(), _definedAtoms._atoms.end()); + } + + virtual const atom_collection<DefinedAtom> &defined() const { + return _definedAtoms; + } + virtual const atom_collection<UndefinedAtom> &undefined() const { + return _undefinedAtoms; + } + virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const { + return _sharedLibraryAtoms; + } + virtual const atom_collection<AbsoluteAtom> &absolute() const { + return _absoluteAtoms; + } + +private: + atom_collection_vector<DefinedAtom> _definedAtoms; + atom_collection_vector<UndefinedAtom> _undefinedAtoms; + atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms; + atom_collection_vector<AbsoluteAtom> _absoluteAtoms; +}; + +struct TestingKindMapping { + const char *string; + int32_t value; + bool isBranch; + bool isGotLoad; + bool isGotUse; +}; + +// +// Table of fixup kinds in YAML documents used for testing +// +const TestingKindMapping sKinds[] = { + {"in-group", -3, false, false, false}, + {"layout-after", -2, false, false, false}, + {"layout-before", -1, false, false, false}, + {"call32", 2, true, false, false}, + {"pcrel32", 3, false, false, false}, + {"gotLoad32", 7, false, true, true}, + {"gotUse32", 9, false, false, true}, + {"lea32wasGot", 8, false, false, false}, + {nullptr, 0, false, false, false} + }; + +class TestingStubsPass : public StubsPass { +public: + TestingStubsPass(const TargetInfo &ti) : _file(TestingPassFile(ti)) + {} + + virtual bool noTextRelocs() { + return true; + } + + virtual bool isCallSite(int32_t kind) { + for (const TestingKindMapping *p = sKinds; p->string != nullptr; ++p) { + if (kind == p->value) + return p->isBranch; + } + return false; + } + + virtual const DefinedAtom *getStub(const Atom &target) { + const DefinedAtom *result = new TestingStubAtom(_file, target); + _file.addAtom(*result); + return result; + } + + virtual void addStubAtoms(MutableFile &mergedFile) { + for (const DefinedAtom *stub : _file.defined() ) { + mergedFile.addAtom(*stub); + } + } + +private: + TestingPassFile _file; +}; + +class TestingGOTPass : public GOTPass { +public: + TestingGOTPass(const TargetInfo &ti) : _file(TestingPassFile(ti)) + {} + + virtual bool noTextRelocs() { + return true; + } + + virtual bool isGOTAccess(int32_t kind, bool &canBypassGOT) { + for (const TestingKindMapping *p = sKinds; p->string != nullptr; ++p) { + if (kind == p->value) { + canBypassGOT = p->isGotLoad; + return p->isGotUse || p->isGotLoad; + } + } + return false; + } + + virtual void updateReferenceToGOT(const Reference *ref, bool targetIsNowGOT) { + if (targetIsNowGOT) + const_cast<Reference*>(ref)->setKind(3); // pcrel32 + else + const_cast<Reference*>(ref)->setKind(8); // lea32wasGot + } + + virtual const DefinedAtom *makeGOTEntry(const Atom &target) { + return new TestingGOTAtom(_file, target); + } + +private: + TestingPassFile _file; +}; + +} // anonymous namespace + + +CoreTargetInfo::CoreTargetInfo() { +} + + +void CoreTargetInfo::addPasses(PassManager &pm) const { + for (StringRef name : _passNames) { + if ( name.equals("layout") ) + pm.add(std::unique_ptr<Pass>((new LayoutPass()))); + else if ( name.equals("GOT") ) + pm.add(std::unique_ptr<Pass>(new TestingGOTPass(*this))); + else if ( name.equals("stubs") ) + pm.add(std::unique_ptr<Pass>(new TestingStubsPass(*this))); + else + llvm_unreachable("bad pass name"); + } +} + + +error_code CoreTargetInfo::parseFile(std::unique_ptr<MemoryBuffer> &mb, + std::vector<std::unique_ptr<File>> &result) const { + if (!_reader) + _reader = createReaderYAML(*this); + return _reader->parseFile(mb,result); +} + +Writer &CoreTargetInfo::writer() const { + if (!_writer) + _writer = createWriterYAML(*this); + return *_writer; +} + + +ErrorOr<Reference::Kind> +CoreTargetInfo::relocKindFromString(StringRef str) const { + for (const TestingKindMapping *p = sKinds; p->string != nullptr; ++p) { + if (str.equals(p->string)) + return p->value; + } + return make_error_code(yaml_reader_error::illegal_value); +} + +ErrorOr<std::string> +CoreTargetInfo::stringFromRelocKind(Reference::Kind kind) const { + for (const TestingKindMapping *p = sKinds; p->string != nullptr; ++p) { + if (kind == p->value) + return std::string(p->string); + } + return make_error_code(yaml_reader_error::illegal_value); +} + + + diff --git a/lld/lib/ReaderWriter/ELF/Atoms.h b/lld/lib/ReaderWriter/ELF/Atoms.h index c5f66bcdedf..28501d9b231 100644 --- a/lld/lib/ReaderWriter/ELF/Atoms.h +++ b/lld/lib/ReaderWriter/ELF/Atoms.h @@ -512,7 +512,8 @@ public: const Elf_Shdr *section, llvm::ArrayRef<uint8_t> contentData, uint64_t offset) : _owningFile(file), _sectionName(sectionName), _section(section), - _contentData(contentData), _offset(offset) {} + _contentData(contentData), _offset(offset) { + } virtual const class ELFFile<ELFT> &file() const { return _owningFile; diff --git a/lld/lib/ReaderWriter/ELF/DefaultLayout.h b/lld/lib/ReaderWriter/ELF/DefaultLayout.h index 73a4c163143..8c520ff4f7e 100644 --- a/lld/lib/ReaderWriter/ELF/DefaultLayout.h +++ b/lld/lib/ReaderWriter/ELF/DefaultLayout.h @@ -16,7 +16,6 @@ #include "SectionChunks.h" #include "SegmentChunks.h" -#include "lld/Core/LinkerOptions.h" #include "lld/Core/STDExtras.h" #include "llvm/ADT/ArrayRef.h" @@ -28,6 +27,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Format.h" #include <map> #include <tuple> @@ -667,7 +667,6 @@ DefaultLayout<ELFT>::assignVirtualAddress() { } firstLoadSegment->prepend(_programHeader); firstLoadSegment->prepend(_header); - bool newSegmentHeaderAdded = true; while (true) { for (auto si : _segments) { diff --git a/lld/lib/ReaderWriter/ELF/DefaultTargetHandler.h b/lld/lib/ReaderWriter/ELF/DefaultTargetHandler.h index c6426724f25..c019df1baed 100644 --- a/lld/lib/ReaderWriter/ELF/DefaultTargetHandler.h +++ b/lld/lib/ReaderWriter/ELF/DefaultTargetHandler.h @@ -13,7 +13,6 @@ #include "DefaultLayout.h" #include "TargetHandler.h" -#include "lld/Core/LinkerOptions.h" #include "lld/ReaderWriter/ELFTargetInfo.h" #include "llvm/ADT/Triple.h" diff --git a/lld/lib/ReaderWriter/ELF/ELFTargetInfo.cpp b/lld/lib/ReaderWriter/ELF/ELFTargetInfo.cpp index 3395609979c..338096d3a2c 100644 --- a/lld/lib/ReaderWriter/ELF/ELFTargetInfo.cpp +++ b/lld/lib/ReaderWriter/ELF/ELFTargetInfo.cpp @@ -12,41 +12,38 @@ #include "TargetHandler.h" #include "Targets.h" -#include "lld/Core/LinkerOptions.h" #include "lld/Passes/LayoutPass.h" #include "lld/ReaderWriter/ReaderLinkerScript.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/ELF.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" namespace lld { -ELFTargetInfo::ELFTargetInfo(const LinkerOptions &lo) : TargetInfo(lo) {} - -uint16_t ELFTargetInfo::getOutputType() const { - switch (_options._outputKind) { - case OutputKind::StaticExecutable: - case OutputKind::DynamicExecutable: - return llvm::ELF::ET_EXEC; - case OutputKind::Relocatable: - return llvm::ELF::ET_REL; - case OutputKind::Shared: - return llvm::ELF::ET_DYN; - case OutputKind::Core: - return llvm::ELF::ET_CORE; - case OutputKind::SharedStubs: - case OutputKind::DebugSymbols: - case OutputKind::Bundle: - case OutputKind::Preload: - break; - case OutputKind::Invalid: - llvm_unreachable("Invalid output kind!"); - } - llvm_unreachable("Unhandled OutputKind"); +ELFTargetInfo::ELFTargetInfo(llvm::Triple triple) + : _outputFileType(elf::ET_EXEC) + , _triple(triple) + , _baseAddress(0) + , _isStaticExecutable(false) + , _outputYAML(false) + , _noInhibitExec(false) + , _mergeCommonStrings(false) + , _runLayoutPass(true) { +} + +bool ELFTargetInfo::is64Bits() const { + return getTriple().isArch64Bit(); +} + +bool ELFTargetInfo::isLittleEndian() const { + // TODO: Do this properly. It is not defined purely by arch. + return true; } void ELFTargetInfo::addPasses(PassManager &pm) const { - pm.add(std::unique_ptr<Pass>(new LayoutPass())); + if (_runLayoutPass) + pm.add(std::unique_ptr<Pass>(new LayoutPass())); } uint16_t ELFTargetInfo::getOutputMachine() const { @@ -64,31 +61,63 @@ uint16_t ELFTargetInfo::getOutputMachine() const { } } -ErrorOr<Reader &> ELFTargetInfo::getReader(const LinkerInput &input) const { - DEBUG_WITH_TYPE("inputs", llvm::dbgs() << input.getPath() << "\n"); - auto buffer = input.getBuffer(); - if (!buffer) - return error_code(buffer); - auto magic = llvm::sys::fs::identify_magic(buffer->getBuffer()); - // Assume unknown file types are linker scripts. - if (magic == llvm::sys::fs::file_magic::unknown) { - if (!_linkerScriptReader) - _linkerScriptReader.reset(new ReaderLinkerScript( - *this, - std::bind(&ELFTargetInfo::getReader, this, std::placeholders::_1))); - return *_linkerScriptReader; +bool ELFTargetInfo::validate(raw_ostream &diagnostics) { + if (_outputFileType == elf::ET_EXEC) { + if (_entrySymbolName.empty()) { + _entrySymbolName = "_start"; + } + } + + if (_inputFiles.empty()) { + diagnostics << "No input files\n"; + return true; + } + + + return false; +} + + +bool ELFTargetInfo::isDynamic() const { + switch (_outputFileType) { + case llvm::ELF::ET_EXEC: + if (_isStaticExecutable) + return false; + else + return true; + case llvm::ELF::ET_DYN: + return true; } + return false; +} - // Assume anything else is an ELF file. + +error_code ELFTargetInfo::parseFile(std::unique_ptr<MemoryBuffer> &mb, + std::vector<std::unique_ptr<File>> &result) const { if (!_elfReader) - _elfReader = createReaderELF(*this, std::bind(&ELFTargetInfo::getReader, - this, std::placeholders::_1)); - return *_elfReader; + _elfReader = createReaderELF(*this); + error_code ec = _elfReader->parseFile(mb, result); + if (ec) { + // Not an ELF file, check file extension to see if it might be yaml + StringRef path = mb->getBufferIdentifier(); + if ( path.endswith(".objtxt") ) { + if (!_yamlReader) + _yamlReader = createReaderYAML(*this); + ec = _yamlReader->parseFile(mb, result); + } + if (ec) { + // Not a yaml file, assume it is a linkerscript + if (!_linkerScriptReader) + _linkerScriptReader.reset(new ReaderLinkerScript(*this)); + ec = _linkerScriptReader->parseFile(mb, result); + } + } + return ec; } -ErrorOr<Writer &> ELFTargetInfo::getWriter() const { +Writer &ELFTargetInfo::writer() const { if (!_writer) { - if (_options._outputYAML) + if (_outputYAML) _writer = createWriterYAML(*this); else _writer = createWriterELF(*this); @@ -96,27 +125,40 @@ ErrorOr<Writer &> ELFTargetInfo::getWriter() const { return *_writer; } -std::unique_ptr<ELFTargetInfo> ELFTargetInfo::create(const LinkerOptions &lo) { - switch (llvm::Triple(llvm::Triple::normalize(lo._target)).getArch()) { + +std::unique_ptr<ELFTargetInfo> ELFTargetInfo::create(llvm::Triple triple) { + switch (triple.getArch()) { case llvm::Triple::x86: - return std::unique_ptr<ELFTargetInfo>(new lld::elf::X86TargetInfo(lo)); + return std::unique_ptr<ELFTargetInfo>(new lld::elf::X86TargetInfo(triple)); case llvm::Triple::x86_64: return std::unique_ptr< - ELFTargetInfo>(new lld::elf::X86_64TargetInfo(lo)); + ELFTargetInfo>(new lld::elf::X86_64TargetInfo(triple)); case llvm::Triple::hexagon: return std::unique_ptr< - ELFTargetInfo>(new lld::elf::HexagonTargetInfo(lo)); + ELFTargetInfo>(new lld::elf::HexagonTargetInfo(triple)); case llvm::Triple::ppc: - return std::unique_ptr<ELFTargetInfo>(new lld::elf::PPCTargetInfo(lo)); + return std::unique_ptr<ELFTargetInfo>(new lld::elf::PPCTargetInfo(triple)); default: return std::unique_ptr<ELFTargetInfo>(); } } -StringRef ELFTargetInfo::getEntry() const { - if (!_options._entrySymbol.empty()) - return _options._entrySymbol; - return "_start"; +bool ELFTargetInfo::appendLibrary(StringRef libName) { + SmallString<128> fullPath; + for (StringRef dir : _inputSearchPaths) { + // FIXME: need to handle other extensions, like .so + fullPath.assign(dir); + llvm::sys::path::append(fullPath, Twine("lib") + libName + ".a"); + StringRef pathref = fullPath.str(); + unsigned pathlen = pathref.size(); + if (llvm::sys::fs::exists(pathref)) { + char *x = _extraStrings.Allocate<char>(pathlen); + memcpy(x, pathref.data(), pathlen); + appendInputFile(StringRef(x,pathlen)); + return false; + } + } + return true; } } // end namespace lld diff --git a/lld/lib/ReaderWriter/ELF/ExecutableAtoms.h b/lld/lib/ReaderWriter/ELF/ExecutableAtoms.h index 4216cd5fb5b..d2ecbb2a903 100644 --- a/lld/lib/ReaderWriter/ELF/ExecutableAtoms.h +++ b/lld/lib/ReaderWriter/ELF/ExecutableAtoms.h @@ -49,6 +49,7 @@ public: /// \brief add an undefined atom virtual void addUndefinedAtom(StringRef symbolName) { + assert(!symbolName.empty() && "UndefinedAtoms must have a name"); Elf_Sym *symbol = new (_allocator) Elf_Sym; symbol->st_name = 0; symbol->st_value = 0; diff --git a/lld/lib/ReaderWriter/ELF/ExecutableWriter.h b/lld/lib/ReaderWriter/ELF/ExecutableWriter.h index fc0bde043b8..6bc283d701d 100644 --- a/lld/lib/ReaderWriter/ELF/ExecutableWriter.h +++ b/lld/lib/ReaderWriter/ELF/ExecutableWriter.h @@ -46,7 +46,7 @@ private: /// absolute symbols template<class ELFT> void ExecutableWriter<ELFT>::addDefaultAtoms() { - _runtimeFile.addUndefinedAtom(this->_targetInfo.getEntry()); + _runtimeFile.addUndefinedAtom(this->_targetInfo.entrySymbolName()); _runtimeFile.addAbsoluteAtom("__bss_start"); _runtimeFile.addAbsoluteAtom("__bss_end"); _runtimeFile.addAbsoluteAtom("_end"); diff --git a/lld/lib/ReaderWriter/ELF/File.h b/lld/lib/ReaderWriter/ELF/File.h index cbc2fff9895..a4c712420c9 100644 --- a/lld/lib/ReaderWriter/ELF/File.h +++ b/lld/lib/ReaderWriter/ELF/File.h @@ -143,7 +143,7 @@ public: // Sections that have merge string property std::vector<const Elf_Shdr *> mergeStringSections; - bool doStringsMerge = _elfTargetInfo.getLinkerOptions()._mergeCommonStrings; + bool doStringsMerge = _elfTargetInfo.mergeCommonStrings(); // Handle: SHT_REL and SHT_RELA sections: // Increment over the sections, when REL/RELA section types are found add diff --git a/lld/lib/ReaderWriter/ELF/HeaderChunks.h b/lld/lib/ReaderWriter/ELF/HeaderChunks.h index fe8efddfb0d..64400dc26d0 100644 --- a/lld/lib/ReaderWriter/ELF/HeaderChunks.h +++ b/lld/lib/ReaderWriter/ELF/HeaderChunks.h @@ -18,6 +18,7 @@ #include "llvm/Support/ELF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/Format.h" /// \brief An Header represents the Elf[32/64]_Ehdr structure at the /// start of an ELF executable file. @@ -98,10 +99,10 @@ public: FindPhdr(uint64_t type, uint64_t flags, uint64_t flagsClear) : _type(type) , _flags(flags) - , _flagsClear(flagsClear) - {} + , _flagsClear(flagsClear) { + } - bool operator()(const Elf_Phdr *j) const { + bool operator()(const llvm::object::Elf_Phdr_Impl<ELFT> *j) const { return ((j->p_type == _type) && ((j->p_flags & _flags) == _flags) && (!(j->p_flags & _flagsClear))); diff --git a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationFunctions.h b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationFunctions.h index b0ee2e440e9..a02caa74595 100644 --- a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationFunctions.h +++ b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonRelocationFunctions.h @@ -29,7 +29,8 @@ typedef struct { sizeof(insn_encodings_v4) / sizeof(Instruction)) /// \brief finds the scatter Bits that need to be used to apply relocations -uint32_t findBitMask(uint32_t insn, Instruction *encodings, int32_t numInsns) { +inline uint32_t +findBitMask(uint32_t insn, Instruction *encodings, int32_t numInsns) { for (int32_t i = 0; i < numInsns ; i++) { if (((insn & 0xc000) == 0) && !(encodings[i].isDuplex)) continue; diff --git a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp index d7c15d410a3..cc928e6b379 100644 --- a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp +++ b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.cpp @@ -212,8 +212,7 @@ public: } // end anonymous namespace void elf::HexagonTargetInfo::addPasses(PassManager &pm) const { - if (_options._outputKind == OutputKind::DynamicExecutable || - _options._outputKind == OutputKind::Shared) + if (isDynamic()) pm.add(std::unique_ptr<Pass>(new DynamicGOTPLTPass(*this))); ELFTargetInfo::addPasses(pm); } diff --git a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetInfo.cpp b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetInfo.cpp index ddba886525d..49d91434fde 100644 --- a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetInfo.cpp +++ b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetInfo.cpp @@ -22,8 +22,8 @@ using namespace lld; #define LLD_CASE(name) .Case(#name, llvm::ELF::name) -ErrorOr<int32_t> elf::HexagonTargetInfo::relocKindFromString( - StringRef str) const { +ErrorOr<Reference::Kind> +elf::HexagonTargetInfo::relocKindFromString(StringRef str) const { int32_t ret = llvm::StringSwitch<int32_t>(str) LLD_CASE(R_HEX_NONE) LLD_CASE(R_HEX_B22_PCREL) diff --git a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetInfo.h b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetInfo.h index ca8fb94d30d..82f4c6b5ce5 100644 --- a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetInfo.h +++ b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetInfo.h @@ -12,7 +12,6 @@ #include "HexagonTargetHandler.h" -#include "lld/Core/LinkerOptions.h" #include "lld/ReaderWriter/ELFTargetInfo.h" #include "llvm/Object/ELF.h" @@ -23,15 +22,14 @@ namespace elf { class HexagonTargetInfo LLVM_FINAL : public ELFTargetInfo { public: - HexagonTargetInfo(const LinkerOptions &lo) : ELFTargetInfo(lo) { + HexagonTargetInfo(llvm::Triple triple) + : ELFTargetInfo(triple) { _targetHandler = std::unique_ptr<TargetHandlerBase>( new HexagonTargetHandler(*this)); } - virtual uint64_t getPageSize() const { return 0x1000; } - - virtual ErrorOr<int32_t> relocKindFromString(StringRef str) const; - virtual ErrorOr<std::string> stringFromRelocKind(int32_t kind) const; + virtual ErrorOr<Reference::Kind> relocKindFromString(StringRef str) const; + virtual ErrorOr<std::string> stringFromRelocKind(Reference::Kind kind) const; virtual void addPasses(PassManager &) const; diff --git a/lld/lib/ReaderWriter/ELF/OutputELFWriter.h b/lld/lib/ReaderWriter/ELF/OutputELFWriter.h index 2cc81dd1462..40f14bb5f03 100644 --- a/lld/lib/ReaderWriter/ELF/OutputELFWriter.h +++ b/lld/lib/ReaderWriter/ELF/OutputELFWriter.h @@ -345,7 +345,7 @@ error_code OutputELFWriter<ELFT>::writeFile(const File &file, StringRef path) { _Header->e_shnum(_shdrtab->numHeaders()); _Header->e_shstrndx(_shstrtab->ordinal()); uint64_t virtualAddr = 0; - _layout->findAtomAddrByName(_targetInfo.getEntry(), virtualAddr); + _layout->findAtomAddrByName(_targetInfo.entrySymbolName(), virtualAddr); _Header->e_entry(virtualAddr); // HACK: We have to write out the header and program header here even though diff --git a/lld/lib/ReaderWriter/ELF/PPC/PPCTargetInfo.cpp b/lld/lib/ReaderWriter/ELF/PPC/PPCTargetInfo.cpp index e69de29bb2d..337b02f4c2a 100644 --- a/lld/lib/ReaderWriter/ELF/PPC/PPCTargetInfo.cpp +++ b/lld/lib/ReaderWriter/ELF/PPC/PPCTargetInfo.cpp @@ -0,0 +1,36 @@ +#include "PPCTargetInfo.h" + +#include "lld/Core/LLVM.h" + +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/ErrorOr.h" + +using namespace lld; + +#define LLD_CASE(name) .Case(#name, llvm::ELF::name) + +ErrorOr<Reference::Kind> elf::PPCTargetInfo::relocKindFromString( + StringRef str) const { + int32_t ret = llvm::StringSwitch<int32_t>(str) + LLD_CASE(R_PPC_NONE) + LLD_CASE(R_PPC_ADDR32) + .Default(-1); + + if (ret == -1) + return make_error_code(yaml_reader_error::illegal_value); + return ret; +} + +#undef LLD_CASE + +#define LLD_CASE(name) case llvm::ELF::name: return std::string(#name); + +ErrorOr<std::string> +elf::PPCTargetInfo::stringFromRelocKind(Reference::Kind kind) const { + switch (kind) { + LLD_CASE(R_PPC_NONE) + LLD_CASE(R_PPC_ADDR32) + } + + return make_error_code(yaml_reader_error::illegal_value); +} diff --git a/lld/lib/ReaderWriter/ELF/PPC/PPCTargetInfo.h b/lld/lib/ReaderWriter/ELF/PPC/PPCTargetInfo.h index 97ba655d4ab..077767695c9 100644 --- a/lld/lib/ReaderWriter/ELF/PPC/PPCTargetInfo.h +++ b/lld/lib/ReaderWriter/ELF/PPC/PPCTargetInfo.h @@ -12,7 +12,6 @@ #include "PPCTargetHandler.h" -#include "lld/Core/LinkerOptions.h" #include "lld/ReaderWriter/ELFTargetInfo.h" #include "llvm/Object/ELF.h" @@ -22,14 +21,15 @@ namespace lld { namespace elf { class PPCTargetInfo LLVM_FINAL : public ELFTargetInfo { public: - PPCTargetInfo(const LinkerOptions &lo) : ELFTargetInfo(lo) { + PPCTargetInfo(llvm::Triple triple) + : ELFTargetInfo(triple) { _targetHandler = std::unique_ptr<TargetHandlerBase>( new PPCTargetHandler(*this)); } virtual bool isLittleEndian() const { return false; } - - virtual uint64_t getPageSize() const { return 0x1000; } + virtual ErrorOr<Reference::Kind> relocKindFromString(StringRef str) const; + virtual ErrorOr<std::string> stringFromRelocKind(Reference::Kind kind) const; }; } // elf diff --git a/lld/lib/ReaderWriter/ELF/Reader.cpp b/lld/lib/ReaderWriter/ELF/Reader.cpp index be2fedb239b..cb6e9cde00f 100644 --- a/lld/lib/ReaderWriter/ELF/Reader.cpp +++ b/lld/lib/ReaderWriter/ELF/Reader.cpp @@ -78,12 +78,12 @@ namespace elf { /// memory buffer for ELF class and bit width class ELFReader : public Reader { public: - ELFReader(const ELFTargetInfo &ti, std::function<ReaderFunc> read) - : lld::Reader(ti), _elfTargetInfo(ti), _readerArchive(ti, read) { + ELFReader(const ELFTargetInfo &ti) + : lld::Reader(ti), _elfTargetInfo(ti), _readerArchive(ti, *this) { } - error_code parseFile(std::unique_ptr<MemoryBuffer> mb, - std::vector<std::unique_ptr<File> > &result) { + error_code parseFile(std::unique_ptr<MemoryBuffer> &mb, + std::vector<std::unique_ptr<File> > &result) const { using llvm::object::ELFType; llvm::sys::LLVMFileType fileType = llvm::sys::IdentifyFileType(mb->getBufferStart(), @@ -112,10 +112,10 @@ public: break; } case llvm::sys::Archive_FileType: - ec = _readerArchive.parseFile(std::move(mb), result); + ec = _readerArchive.parseFile(mb, result); break; default: - llvm_unreachable("not supported format"); + return llvm::make_error_code(llvm::errc::executable_format_error); break; } @@ -131,8 +131,7 @@ private: }; } // end namespace elf -std::unique_ptr<Reader> createReaderELF(const ELFTargetInfo &eti, - std::function<ReaderFunc> read) { - return std::unique_ptr<Reader>(new elf::ELFReader(eti, std::move(read))); +std::unique_ptr<Reader> createReaderELF(const ELFTargetInfo &targetinfo) { + return std::unique_ptr<Reader>(new elf::ELFReader(targetinfo)); } } // end namespace lld diff --git a/lld/lib/ReaderWriter/ELF/SectionChunks.h b/lld/lib/ReaderWriter/ELF/SectionChunks.h index 2bca266fe2d..8237529629f 100644 --- a/lld/lib/ReaderWriter/ELF/SectionChunks.h +++ b/lld/lib/ReaderWriter/ELF/SectionChunks.h @@ -603,13 +603,13 @@ public: /// \brief Get the symbol table index for an Atom. If it's not in the symbol /// table, return STN_UNDEF. uint32_t getSymbolTableIndex(const Atom *a) const { - auto se = std::find_if(_symbolTable.begin(), _symbolTable.end(), + auto entry = std::find_if(_symbolTable.begin(), _symbolTable.end(), [=](const SymbolEntry &se) { return se._atom == a; }); - if (se == _symbolTable.end()) + if (entry == _symbolTable.end()) return STN_UNDEF; - return std::distance(_symbolTable.begin(), se); + return std::distance(_symbolTable.begin(), entry); } virtual void finalize() { finalize(true); } diff --git a/lld/lib/ReaderWriter/ELF/TargetHandler.h b/lld/lib/ReaderWriter/ELF/TargetHandler.h index ebdb203c0da..ab30c3636e7 100644 --- a/lld/lib/ReaderWriter/ELF/TargetHandler.h +++ b/lld/lib/ReaderWriter/ELF/TargetHandler.h @@ -19,7 +19,6 @@ #include "Layout.h" #include "lld/Core/InputFiles.h" -#include "lld/Core/LinkerOptions.h" #include "lld/Core/LLVM.h" #include "lld/Core/TargetInfo.h" #include "lld/ReaderWriter/ELFTargetInfo.h" diff --git a/lld/lib/ReaderWriter/ELF/Writer.cpp b/lld/lib/ReaderWriter/ELF/Writer.cpp index 6e2744ea1f3..a174ef0c051 100644 --- a/lld/lib/ReaderWriter/ELF/Writer.cpp +++ b/lld/lib/ReaderWriter/ELF/Writer.cpp @@ -1,4 +1,4 @@ -//===- lib/ReaderWriter/ELF/Writer.cpp ------------------------------------===// +//===- lib/ReaderWriter/ELF/WriterELF.cpp ---------------------------------===// // // The LLVM Linker // @@ -6,53 +6,63 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -#include "ExecutableWriter.h" + +#include "lld/ReaderWriter/Writer.h" + #include "DynamicLibraryWriter.h" +#include "ExecutableWriter.h" + using namespace llvm; using namespace llvm::object; - namespace lld { -std::unique_ptr<Writer> createWriterELF(const ELFTargetInfo &TI) { +std::unique_ptr<Writer> createWriterELF(const ELFTargetInfo &info) { using llvm::object::ELFType; // Set the default layout to be the static executable layout // We would set the layout to a dynamic executable layout // if we came across any shared libraries in the process - const LinkerOptions &options = TI.getLinkerOptions(); - - if ((options._outputKind == OutputKind::StaticExecutable) || - (options._outputKind == OutputKind::DynamicExecutable)) { - if (!TI.is64Bits() && TI.isLittleEndian()) - return std::unique_ptr<Writer>(new - elf::ExecutableWriter<ELFType<support::little, 4, false>>(TI)); - else if (TI.is64Bits() && TI.isLittleEndian()) - return std::unique_ptr<Writer>(new - elf::ExecutableWriter<ELFType<support::little, 8, true>>(TI)); - else if (!TI.is64Bits() && !TI.isLittleEndian()) - return std::unique_ptr<Writer>(new - elf::ExecutableWriter<ELFType<support::big, 4, false>>(TI)); - else if (TI.is64Bits() && !TI.isLittleEndian()) - return std::unique_ptr<Writer>(new - elf::ExecutableWriter<ELFType<support::big, 8, true>>(TI)); - llvm_unreachable("Invalid Options!"); - } else if (options._outputKind == OutputKind::Shared) { - if (!TI.is64Bits() && TI.isLittleEndian()) - return std::unique_ptr<Writer>(new - elf::DynamicLibraryWriter<ELFType<support::little, 4, false>>(TI)); - else if (TI.is64Bits() && TI.isLittleEndian()) - return std::unique_ptr<Writer>(new - elf::DynamicLibraryWriter<ELFType<support::little, 8, true>>(TI)); - else if (!TI.is64Bits() && !TI.isLittleEndian()) - return std::unique_ptr<Writer>(new - elf::DynamicLibraryWriter<ELFType<support::big, 4, false>>(TI)); - else if (TI.is64Bits() && !TI.isLittleEndian()) - return std::unique_ptr<Writer>(new - elf::DynamicLibraryWriter<ELFType<support::big, 8, true>>(TI)); - llvm_unreachable("Invalid Options!"); + switch(info.getOutputType()) { + case llvm::ELF::ET_EXEC: + if (info.is64Bits()) { + if (info.isLittleEndian()) + return std::unique_ptr<Writer>(new + elf::ExecutableWriter<ELFType<support::little, 8, true>>(info)); + else + return std::unique_ptr<Writer>(new + elf::ExecutableWriter<ELFType<support::big, 8, true>>(info)); + } else { + if (info.isLittleEndian()) + return std::unique_ptr<Writer>(new + elf::ExecutableWriter<ELFType<support::little, 4, false>>(info)); + else + return std::unique_ptr<Writer>(new + elf::ExecutableWriter<ELFType<support::big, 4, false>>(info)); + } + break; + case llvm::ELF::ET_DYN: + if (info.is64Bits()) { + if (info.isLittleEndian()) + return std::unique_ptr<Writer>(new + elf::DynamicLibraryWriter<ELFType<support::little, 8, true>>(info)); + else + return std::unique_ptr<Writer>(new + elf::DynamicLibraryWriter<ELFType<support::big, 8, true>>(info)); + } else { + if (info.isLittleEndian()) + return std::unique_ptr<Writer>(new + elf::DynamicLibraryWriter<ELFType<support::little, 4, false>>(info)); + else + return std::unique_ptr<Writer>(new + elf::DynamicLibraryWriter<ELFType<support::big, 4, false>>(info)); + } + break; + case llvm::ELF::ET_REL: + llvm_unreachable("TODO: support -r mode"); + default: + llvm_unreachable("unsupported output type"); } - else - llvm_unreachable("unsupported options"); -} } + +} // namespace lld diff --git a/lld/lib/ReaderWriter/ELF/Writer.h b/lld/lib/ReaderWriter/ELF/Writer.h index 7e67c31369d..20b330ed739 100644 --- a/lld/lib/ReaderWriter/ELF/Writer.h +++ b/lld/lib/ReaderWriter/ELF/Writer.h @@ -28,7 +28,7 @@ public: virtual void buildChunks(const File &file) = 0; /// \brief Writes the chunks into the output file specified by path - virtual error_code writeFile(const File &File, StringRef path) = 0; + virtual error_code writeFile(const File &file, StringRef path) = 0; /// \brief Get the virtual address of \p atom after layout. virtual uint64_t addressOfAtom(const Atom *atom) = 0; diff --git a/lld/lib/ReaderWriter/ELF/X86/X86TargetInfo.cpp b/lld/lib/ReaderWriter/ELF/X86/X86TargetInfo.cpp index e69de29bb2d..8a0737c5fc8 100644 --- a/lld/lib/ReaderWriter/ELF/X86/X86TargetInfo.cpp +++ b/lld/lib/ReaderWriter/ELF/X86/X86TargetInfo.cpp @@ -0,0 +1,36 @@ +#include "X86TargetInfo.h" + +#include "lld/Core/LLVM.h" + +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/ErrorOr.h" + +using namespace lld; + +#define LLD_CASE(name) .Case(#name, llvm::ELF::name) + +ErrorOr<Reference::Kind> elf::X86TargetInfo::relocKindFromString( + StringRef str) const { + int32_t ret = llvm::StringSwitch<int32_t>(str) + LLD_CASE(R_386_NONE) + LLD_CASE(R_386_PC32) + .Default(-1); + + if (ret == -1) + return make_error_code(yaml_reader_error::illegal_value); + return ret; +} + +#undef LLD_CASE + +#define LLD_CASE(name) case llvm::ELF::name: return std::string(#name); + +ErrorOr<std::string> +elf::X86TargetInfo::stringFromRelocKind(Reference::Kind kind) const { + switch (kind) { + LLD_CASE(R_386_NONE) + LLD_CASE(R_386_PC32) + } + + return make_error_code(yaml_reader_error::illegal_value); +} diff --git a/lld/lib/ReaderWriter/ELF/X86/X86TargetInfo.h b/lld/lib/ReaderWriter/ELF/X86/X86TargetInfo.h index c66a42f78d6..00007afbdf0 100644 --- a/lld/lib/ReaderWriter/ELF/X86/X86TargetInfo.h +++ b/lld/lib/ReaderWriter/ELF/X86/X86TargetInfo.h @@ -12,7 +12,6 @@ #include "X86TargetHandler.h" -#include "lld/Core/LinkerOptions.h" #include "lld/ReaderWriter/ELFTargetInfo.h" #include "llvm/Object/ELF.h" @@ -22,12 +21,14 @@ namespace lld { namespace elf { class X86TargetInfo LLVM_FINAL : public ELFTargetInfo { public: - X86TargetInfo(const LinkerOptions &lo) : ELFTargetInfo(lo) { + X86TargetInfo(llvm::Triple triple) + : ELFTargetInfo(triple) { _targetHandler = std::unique_ptr<TargetHandlerBase>( new X86TargetHandler(*this)); } - virtual uint64_t getPageSize() const { return 0x1000; } + virtual ErrorOr<Reference::Kind> relocKindFromString(StringRef str) const; + virtual ErrorOr<std::string> stringFromRelocKind(Reference::Kind kind) const; }; } // end namespace elf } // end namespace lld diff --git a/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetInfo.cpp b/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetInfo.cpp index bb6236e109e..cad8dd2809f 100644 --- a/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetInfo.cpp +++ b/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetInfo.cpp @@ -399,18 +399,29 @@ public: } // end anon namespace void elf::X86_64TargetInfo::addPasses(PassManager &pm) const { - if (_options._outputKind == OutputKind::StaticExecutable) - pm.add(std::unique_ptr<Pass>(new StaticGOTPLTPass(*this))); - else if (_options._outputKind == OutputKind::DynamicExecutable || - _options._outputKind == OutputKind::Shared) + switch (_outputFileType) { + case llvm::ELF::ET_EXEC: + if (_isStaticExecutable) + pm.add(std::unique_ptr<Pass>(new StaticGOTPLTPass(*this))); + else + pm.add(std::unique_ptr<Pass>(new DynamicGOTPLTPass(*this))); + break; + case llvm::ELF::ET_DYN: pm.add(std::unique_ptr<Pass>(new DynamicGOTPLTPass(*this))); + break; + case llvm::ELF::ET_REL: + break; + default: + llvm_unreachable("Unhandled output file type"); + } ELFTargetInfo::addPasses(pm); } + #define LLD_CASE(name) .Case(#name, llvm::ELF::name) -ErrorOr<int32_t> elf::X86_64TargetInfo::relocKindFromString( - StringRef str) const { +ErrorOr<Reference::Kind> +elf::X86_64TargetInfo::relocKindFromString(StringRef str) const { int32_t ret = llvm::StringSwitch<int32_t>(str) LLD_CASE(R_X86_64_NONE) LLD_CASE(R_X86_64_64) @@ -462,8 +473,8 @@ ErrorOr<int32_t> elf::X86_64TargetInfo::relocKindFromString( #define LLD_CASE(name) case llvm::ELF::name: return std::string(#name); -ErrorOr<std::string> elf::X86_64TargetInfo::stringFromRelocKind( - int32_t kind) const { +ErrorOr<std::string> +elf::X86_64TargetInfo::stringFromRelocKind(Reference::Kind kind) const { switch (kind) { LLD_CASE(R_X86_64_NONE) LLD_CASE(R_X86_64_64) diff --git a/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetInfo.h b/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetInfo.h index 11adab4ecfc..4c8afa065df 100644 --- a/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetInfo.h +++ b/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetInfo.h @@ -12,7 +12,6 @@ #include "X86_64TargetHandler.h" -#include "lld/Core/LinkerOptions.h" #include "lld/ReaderWriter/ELFTargetInfo.h" #include "llvm/Object/ELF.h" @@ -29,19 +28,18 @@ enum { class X86_64TargetInfo LLVM_FINAL : public ELFTargetInfo { public: - X86_64TargetInfo(const LinkerOptions &lo) : ELFTargetInfo(lo) { + X86_64TargetInfo(llvm::Triple triple) + : ELFTargetInfo(triple) { _targetHandler = std::unique_ptr<TargetHandlerBase>(new X86_64TargetHandler(*this)); } - virtual uint64_t getPageSize() const { return 0x1000; } - virtual void addPasses(PassManager &) const; virtual uint64_t getBaseAddress() const { - if (_options._baseAddress == 0) + if (_baseAddress == 0) return 0x400000; - return _options._baseAddress; + return _baseAddress; } virtual bool isDynamicRelocation(const DefinedAtom &, @@ -66,8 +64,8 @@ public: } } - virtual ErrorOr<int32_t> relocKindFromString(StringRef str) const; - virtual ErrorOr<std::string> stringFromRelocKind(int32_t kind) const; + virtual ErrorOr<Reference::Kind> relocKindFromString(StringRef str) const; + virtual ErrorOr<std::string> stringFromRelocKind(Reference::Kind kind) const; }; } // end namespace elf diff --git a/lld/lib/ReaderWriter/MachO/ExecutableAtoms.hpp b/lld/lib/ReaderWriter/MachO/ExecutableAtoms.hpp index de8d5214e43..54dcb69de91 100644 --- a/lld/lib/ReaderWriter/MachO/ExecutableAtoms.hpp +++ b/lld/lib/ReaderWriter/MachO/ExecutableAtoms.hpp @@ -29,13 +29,13 @@ namespace mach_o { class CRuntimeFile : public SimpleFile { public: CRuntimeFile(const MachOTargetInfo &ti) - : SimpleFile(ti, "C runtime"), _undefMain(*this, "_main") { + : SimpleFile(ti, "C runtime"), _undefMain(*this, ti.entrySymbolName()) { // only main executables need _main - if (ti.getLinkerOptions()._outputKind == OutputKind::StaticExecutable || - ti.getLinkerOptions()._outputKind == OutputKind::DynamicExecutable) + if (ti.outputFileType() == MH_EXECUTE) { this->addAtom(_undefMain); + } } - + private: SimpleUndefinedAtom _undefMain; }; diff --git a/lld/lib/ReaderWriter/MachO/MachOFormat.hpp b/lld/lib/ReaderWriter/MachO/MachOFormat.hpp index 2010a7f87da..41b432a16ec 100644 --- a/lld/lib/ReaderWriter/MachO/MachOFormat.hpp +++ b/lld/lib/ReaderWriter/MachO/MachOFormat.hpp @@ -40,12 +40,14 @@ enum { CPU_SUBTYPE_X86_ALL = 0x00000003, CPU_SUBTYPE_X86_64_ALL = 0x00000003, CPU_SUBTYPE_ARM_V6 = 0x00000006, - CPU_SUBTYPE_ARM_V7 = 0x00000009 + CPU_SUBTYPE_ARM_V7 = 0x00000009, + CPU_SUBTYPE_ARM_V7S = 0x0000000B }; enum { MH_OBJECT = 0x1, MH_EXECUTE = 0x2, + MH_PRELOAD = 0x5, MH_DYLIB = 0x6, MH_DYLINKER = 0x7, MH_BUNDLE = 0x8, @@ -494,7 +496,7 @@ public: // in-memory matches on-disk, so copy first fields followed by path ::memcpy(to, (uint8_t*)&cmd, 24); ::memcpy(&to[24], _loadPath.data(), _loadPath.size()); - ::memset(&to[12+_loadPath.size()], 0, cmdsize-(12+_loadPath.size())); + ::memset(&to[24+_loadPath.size()], 0, cmdsize-(24+_loadPath.size())); } } diff --git a/lld/lib/ReaderWriter/MachO/MachOTargetInfo.cpp b/lld/lib/ReaderWriter/MachO/MachOTargetInfo.cpp index 0b2d0772294..f60f32ea43c 100644 --- a/lld/lib/ReaderWriter/MachO/MachOTargetInfo.cpp +++ b/lld/lib/ReaderWriter/MachO/MachOTargetInfo.cpp @@ -10,83 +10,244 @@ #include "lld/ReaderWriter/MachOTargetInfo.h" #include "GOTPass.hpp" #include "StubsPass.hpp" +#include "ReferenceKinds.h" +#include "MachOFormat.hpp" -#include "lld/Core/LinkerOptions.h" #include "lld/Core/PassManager.h" +#include "lld/ReaderWriter/Reader.h" +#include "lld/ReaderWriter/Writer.h" #include "lld/Passes/LayoutPass.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" -#include "llvm/Support/MachO.h" + +using lld::mach_o::KindHandler; + namespace lld { + + +MachOTargetInfo::PackedVersion::PackedVersion(StringRef str) { + if (parse(str, *this)) + llvm_unreachable("bad version string"); +} + +/// Construct 32-bit PackedVersion from string "X.Y.Z" where +/// bits are xxxx.yy.zz. Largest number is 65535.255.255 +bool MachOTargetInfo::PackedVersion::parse(StringRef str, + MachOTargetInfo::PackedVersion &result) { + result._value = 0; + + if (str.empty()) + return false; + + SmallVector<StringRef, 3> parts; + llvm::SplitString(str, parts, "."); + + unsigned long long num; + if (llvm::getAsUnsignedInteger(parts[0], 10, num)) + return true; + if (num > 65535) + return true; + result._value = num << 16; + + if (parts.size() > 1) { + if (llvm::getAsUnsignedInteger(parts[1], 10, num)) + return true; + if (num > 255) + return true; + result._value |= (num << 8); + } + + if (parts.size() > 2) { + if (llvm::getAsUnsignedInteger(parts[2], 10, num)) + return true; + if (num > 255) + return true; + result._value |= num; + } + + return false; +} + +bool MachOTargetInfo::PackedVersion::operator<( + const PackedVersion &rhs) const { + return _value < rhs._value; +} + +bool MachOTargetInfo::PackedVersion::operator>=( + const PackedVersion &rhs) const { + return _value >= rhs._value; +} + +bool MachOTargetInfo::PackedVersion::operator==( + const PackedVersion &rhs) const { + return _value == rhs._value; +} + + +MachOTargetInfo::MachOTargetInfo() + : _outputFileType(mach_o::MH_EXECUTE) + , _outputFileTypeStatic(false) + , _arch(arch_unknown) + , _os(OS::macOSX) + , _osMinVersion("0.0") + , _pageZeroSize(0x1000) + , _kindHandler(nullptr) { +} + + +MachOTargetInfo::~MachOTargetInfo() { +} + uint32_t MachOTargetInfo::getCPUType() const { - switch (getTriple().getArch()) { - case llvm::Triple::x86: - return llvm::MachO::CPUTypeI386; - case llvm::Triple::x86_64: - return llvm::MachO::CPUTypeX86_64; - case llvm::Triple::arm: - return llvm::MachO::CPUTypeARM; - default: + switch (_arch) { + case MachOTargetInfo::arch_x86: + return mach_o::CPU_TYPE_I386; + case MachOTargetInfo::arch_x86_64: + return mach_o::CPU_TYPE_X86_64; + case MachOTargetInfo::arch_armv6: + case MachOTargetInfo::arch_armv7: + case MachOTargetInfo::arch_armv7s: + return mach_o::CPU_TYPE_ARM; + case MachOTargetInfo::arch_unknown: llvm_unreachable("Unknown arch type"); } } uint32_t MachOTargetInfo::getCPUSubType() const { - switch (getTriple().getArch()) { - case llvm::Triple::x86: - return llvm::MachO::CPUSubType_I386_ALL; - case llvm::Triple::x86_64: - return llvm::MachO::CPUSubType_X86_64_ALL; - case llvm::Triple::arm: - return llvm::MachO::CPUSubType_ARM_ALL; - default: + switch (_arch) { + case MachOTargetInfo::arch_x86: + return mach_o::CPU_SUBTYPE_X86_ALL; + case MachOTargetInfo::arch_x86_64: + return mach_o::CPU_SUBTYPE_X86_64_ALL; + case MachOTargetInfo::arch_armv6: + return mach_o::CPU_SUBTYPE_ARM_V6; + case MachOTargetInfo::arch_armv7: + return mach_o::CPU_SUBTYPE_ARM_V7; + case MachOTargetInfo::arch_armv7s: + return mach_o::CPU_SUBTYPE_ARM_V7S; + case MachOTargetInfo::arch_unknown: llvm_unreachable("Unknown arch type"); } } -bool MachOTargetInfo::addEntryPointLoadCommand() const { - switch (_options._outputKind) { - case OutputKind::StaticExecutable: - case OutputKind::DynamicExecutable: + +bool MachOTargetInfo::outputTypeHasEntry() const { + switch (_outputFileType) { + case mach_o::MH_EXECUTE: + case mach_o::MH_DYLINKER: + case mach_o::MH_PRELOAD: return true; default: return false; } } + +bool MachOTargetInfo::minOS(StringRef mac, StringRef iOS) const { + switch (_os) { + case OS::macOSX: + return (_osMinVersion >= PackedVersion(mac)); + case OS::iOS: + case OS::iOS_simulator: + return (_osMinVersion >= PackedVersion(iOS)); + } + llvm_unreachable("target not configured for iOS or MacOSX"); +} + +bool MachOTargetInfo::addEntryPointLoadCommand() const { + if ((_outputFileType == mach_o::MH_EXECUTE) && !_outputFileTypeStatic) { + return minOS("10.8", "6.0"); + } + return false; +} + bool MachOTargetInfo::addUnixThreadLoadCommand() const { - switch (_options._outputKind) { - case OutputKind::StaticExecutable: - case OutputKind::DynamicExecutable: + switch (_outputFileType) { + case mach_o::MH_EXECUTE: + if (_outputFileTypeStatic) + return true; + else + return !minOS("10.8", "6.0"); + break; + case mach_o::MH_DYLINKER: + case mach_o::MH_PRELOAD: return true; default: return false; } } -class GenericMachOTargetInfo LLVM_FINAL : public MachOTargetInfo { -public: - GenericMachOTargetInfo(const LinkerOptions &lo) : MachOTargetInfo(lo) {} +bool MachOTargetInfo::validate(raw_ostream &diagnostics) { + if ((_outputFileType == mach_o::MH_EXECUTE) && _entrySymbolName.empty()) { + if (_outputFileTypeStatic) { + _entrySymbolName = "start"; + } + else { + // If targeting newer OS, use _main + if (addEntryPointLoadCommand()) + _entrySymbolName = "_main"; - virtual uint64_t getPageSize() const { return 0x1000; } - virtual uint64_t getPageZeroSize() const { return getPageSize(); } - - virtual StringRef getEntry() const { - if (!_options._entrySymbol.empty()) - return _options._entrySymbol; - return "_main"; + // If targeting older OS, use start (in crt1.o) + if (addUnixThreadLoadCommand()) + _entrySymbolName = "start"; + } } - virtual void addPasses(PassManager &pm) const { - pm.add(std::unique_ptr<Pass>(new mach_o::GOTPass)); - pm.add(std::unique_ptr<Pass>(new mach_o::StubsPass(*this))); - pm.add(std::unique_ptr<Pass>(new LayoutPass())); + return false; +} + +bool MachOTargetInfo::setOS(OS os, StringRef minOSVersion) { + _os = os; + return PackedVersion::parse(minOSVersion, _osMinVersion); +} + +void MachOTargetInfo::addPasses(PassManager &pm) const { + pm.add(std::unique_ptr<Pass>(new mach_o::GOTPass)); + pm.add(std::unique_ptr<Pass>(new mach_o::StubsPass(*this))); + pm.add(std::unique_ptr<Pass>(new LayoutPass())); +} + + + +error_code MachOTargetInfo::parseFile(std::unique_ptr<MemoryBuffer> &mb, + std::vector<std::unique_ptr<File>> &result) const { +// if (!_machoReader) +// _machoReader = createReaderMachO(*this); +// error_code ec = _machoReader->parseFile(mb,result); +// if (ec) { + if (!_yamlReader) + _yamlReader = createReaderYAML(*this); + return _yamlReader->parseFile(mb,result); +// } + + return error_code::success(); +} + + +Writer &MachOTargetInfo::writer() const { + if (!_writer) { + _writer = createWriterMachO(*this); } -}; + return *_writer; +} + +KindHandler &MachOTargetInfo::kindHandler() const { + if (!_kindHandler) + _kindHandler = KindHandler::create(_arch); + return *_kindHandler; +} -std::unique_ptr<MachOTargetInfo> -MachOTargetInfo::create(const LinkerOptions &lo) { - return std::unique_ptr<MachOTargetInfo>(new GenericMachOTargetInfo(lo)); +ErrorOr<Reference::Kind> +MachOTargetInfo::relocKindFromString(StringRef str) const { + return kindHandler().stringToKind(str); + } + +ErrorOr<std::string> +MachOTargetInfo::stringFromRelocKind(Reference::Kind kind) const { + return std::string(kindHandler().kindToString(kind)); } + + } // end namespace lld diff --git a/lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp b/lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp index d2fb6177f4f..d2ad3a23b67 100644 --- a/lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp +++ b/lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp @@ -10,6 +10,7 @@ #include "ReferenceKinds.h" + #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" @@ -29,14 +30,17 @@ KindHandler::KindHandler() { KindHandler::~KindHandler() { } -KindHandler *KindHandler::makeHandler(llvm::Triple::ArchType arch) { +std::unique_ptr<mach_o::KindHandler> KindHandler::create( + MachOTargetInfo::Arch arch) { switch( arch ) { - case llvm::Triple::x86_64: - return new KindHandler_x86_64(); - case llvm::Triple::x86: - return new KindHandler_x86(); - case llvm::Triple::arm: - return new KindHandler_arm(); + case MachOTargetInfo::arch_x86_64: + return std::unique_ptr<mach_o::KindHandler>(new KindHandler_x86_64()); + case MachOTargetInfo::arch_x86: + return std::unique_ptr<mach_o::KindHandler>(new KindHandler_x86()); + case MachOTargetInfo::arch_armv6: + case MachOTargetInfo::arch_armv7: + case MachOTargetInfo::arch_armv7s: + return std::unique_ptr<mach_o::KindHandler>(new KindHandler_arm()); default: llvm_unreachable("Unknown arch"); } diff --git a/lld/lib/ReaderWriter/MachO/ReferenceKinds.h b/lld/lib/ReaderWriter/MachO/ReferenceKinds.h index 1fce85ff4e9..a9bf0e658c8 100644 --- a/lld/lib/ReaderWriter/MachO/ReferenceKinds.h +++ b/lld/lib/ReaderWriter/MachO/ReferenceKinds.h @@ -10,6 +10,7 @@ #include "lld/Core/LLVM.h" #include "lld/Core/Reference.h" +#include "lld/ReaderWriter/MachOTargetInfo.h" #include "llvm/ADT/Triple.h" @@ -29,7 +30,7 @@ class KindHandler { public: typedef Reference::Kind Kind; - static KindHandler *makeHandler(llvm::Triple::ArchType arch); + static std::unique_ptr<mach_o::KindHandler> create(MachOTargetInfo::Arch); virtual ~KindHandler(); virtual Kind stringToKind(StringRef str) = 0; virtual StringRef kindToString(Kind) = 0; diff --git a/lld/lib/ReaderWriter/MachO/StubsPass.hpp b/lld/lib/ReaderWriter/MachO/StubsPass.hpp index 64524945625..558fe13e91c 100644 --- a/lld/lib/ReaderWriter/MachO/StubsPass.hpp +++ b/lld/lib/ReaderWriter/MachO/StubsPass.hpp @@ -13,7 +13,6 @@ #include "llvm/ADT/DenseMap.h" #include "lld/Core/DefinedAtom.h" -#include "lld/Core/LinkerOptions.h" #include "lld/Core/SharedLibraryAtom.h" #include "lld/Core/File.h" #include "lld/Core/Reference.h" @@ -31,7 +30,7 @@ class StubsPass : public lld::StubsPass { public: StubsPass(const MachOTargetInfo &ti) : _targetInfo(ti) - , _kindHandler(KindHandler::makeHandler(_targetInfo.getTriple().getArch())) + , _kindHandler(_targetInfo.kindHandler()) , _file(ti) , _helperCommonAtom(nullptr) , _helperCacheAtom(nullptr) @@ -39,11 +38,11 @@ public: } virtual bool noTextRelocs() { - return !_targetInfo.getLinkerOptions()._textRelocations; + return true; } virtual bool isCallSite(int32_t kind) { - return _kindHandler->isCallSite(kind); + return _kindHandler.isCallSite(kind); } virtual const DefinedAtom* getStub(const Atom& target) { @@ -60,15 +59,17 @@ public: } const DefinedAtom* makeStub(const Atom& target) { - switch (_targetInfo.getTriple().getArch()) { - case llvm::Triple::x86_64: + switch (_targetInfo.arch()) { + case MachOTargetInfo::arch_x86_64: return makeStub_x86_64(target); - case llvm::Triple::x86: + case MachOTargetInfo::arch_x86: return makeStub_x86(target); - case llvm::Triple::arm: + case MachOTargetInfo::arch_armv6: + case MachOTargetInfo::arch_armv7: + case MachOTargetInfo::arch_armv7s: return makeStub_arm(target); default: - llvm_unreachable("Unknown arch"); + llvm_unreachable("Unknown mach-o arch"); } } @@ -153,7 +154,7 @@ private: }; const MachOTargetInfo &_targetInfo; - KindHandler *_kindHandler; + mach_o::KindHandler &_kindHandler; File _file; llvm::DenseMap<const Atom*, const DefinedAtom*> _targetToStub; std::vector<const DefinedAtom*> _lazyPointers; diff --git a/lld/lib/ReaderWriter/MachO/WriterMachO.cpp b/lld/lib/ReaderWriter/MachO/WriterMachO.cpp index b0e5fd290e4..e91a3d945c9 100644 --- a/lld/lib/ReaderWriter/MachO/WriterMachO.cpp +++ b/lld/lib/ReaderWriter/MachO/WriterMachO.cpp @@ -28,7 +28,6 @@ #include "lld/Core/DefinedAtom.h" #include "lld/Core/File.h" #include "lld/Core/InputFiles.h" -#include "lld/Core/LinkerOptions.h" #include "lld/Core/Reference.h" #include "lld/Core/SharedLibraryAtom.h" #include "lld/ReaderWriter/MachOTargetInfo.h" @@ -155,7 +154,6 @@ public: uint64_t loadCommandsSize(); private: - uint32_t filetype(OutputKind); uint32_t magic(uint32_t cpuType); mach_header _mh; @@ -350,7 +348,7 @@ public: uint64_t *segStartAddr, uint64_t *segEndAddr); const std::vector<Chunk*> chunks() { return _chunks; } - KindHandler *kindHandler() { return _referenceKindHandler; } + mach_o::KindHandler &kindHandler() { return _referenceKindHandler; } bool use64BitMachO() const; @@ -372,7 +370,7 @@ private: typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress; const MachOTargetInfo &_targetInfo; - KindHandler *_referenceKindHandler; + mach_o::KindHandler &_referenceKindHandler; CRuntimeFile _cRuntimeFile; LoadCommandsChunk *_loadCommandsChunk; LoadCommandPaddingChunk *_paddingChunk; @@ -580,7 +578,7 @@ void SectionChunk::write(uint8_t *chunkBuffer) { if ( ref->target() != nullptr ) targetAddress = _writer.addressOfAtom(ref->target()); uint64_t fixupAddress = _writer.addressOfAtom(atomInfo.atom) + offset; - _writer.kindHandler()->applyFixup(ref->kind(), ref->addend(), + _writer.kindHandler().applyFixup(ref->kind(), ref->addend(), &atomContent[offset], fixupAddress, targetAddress); } } @@ -596,7 +594,7 @@ MachHeaderChunk::MachHeaderChunk(const MachOTargetInfo &ti, const File &file) { _mh.magic = this->magic(ti.getCPUType()); _mh.cputype = ti.getCPUType(); _mh.cpusubtype = ti.getCPUSubType(); - _mh.filetype = this->filetype(ti.getLinkerOptions()._outputKind); + _mh.filetype = ti.outputFileType(); _mh.ncmds = 0; _mh.sizeofcmds = 0; _mh.flags = 0; @@ -638,30 +636,6 @@ uint32_t MachHeaderChunk::magic(uint32_t cpuType) { return 0; } -uint32_t MachHeaderChunk::filetype(OutputKind kind) { - switch ( kind ) { - case OutputKind::StaticExecutable: - case OutputKind::DynamicExecutable: - return MH_EXECUTE; - case OutputKind::Relocatable: - return MH_OBJECT; - case OutputKind::Shared: - return MH_DYLIB; - case OutputKind::SharedStubs: - return MH_DYLIB_STUB; - case OutputKind::Bundle: - return MH_BUNDLE; - case OutputKind::Preload: - case OutputKind::DebugSymbols: - case OutputKind::Core: - break; - case OutputKind::Invalid: - llvm_unreachable("Invalid output kind!"); - } - llvm_unreachable("file OutputKind not supported"); - return 0; -} - //===----------------------------------------------------------------------===// @@ -719,7 +693,7 @@ uint32_t LoadCommandsChunk::permissionsFromSections( void LoadCommandsChunk::computeSize(const lld::File &file) { const bool is64 = _writer.use64BitMachO(); // Main executables have a __PAGEZERO segment. - uint64_t pageZeroSize = _targetInfo.getPageZeroSize(); + uint64_t pageZeroSize = _targetInfo.pageZeroSize(); if ( pageZeroSize != 0 ) { assert(is64 || (pageZeroSize < 0xFFFFFFFF)); segment_command* pzSegCmd = new segment_command(0, is64); @@ -1032,7 +1006,7 @@ void BindingInfoChunk::computeSize(const lld::File &file, const SharedLibraryAtom *shlTarget = dyn_cast<SharedLibraryAtom>(target); if ( shlTarget != nullptr ) { - assert(_writer.kindHandler()->isPointer(ref->kind())); + assert(_writer.kindHandler().isPointer(ref->kind())); targetName = shlTarget->name(); ordinal = 1; // FIXME } @@ -1099,14 +1073,14 @@ const char* LazyBindingInfoChunk::info() { void LazyBindingInfoChunk::updateHelper(const DefinedAtom *lazyPointerAtom, uint32_t offset) { for (const Reference *ref : *lazyPointerAtom ) { - if ( ! _writer.kindHandler()->isPointer(ref->kind() ) ) + if ( ! _writer.kindHandler().isPointer(ref->kind() ) ) continue; const Atom *targ = ref->target(); const DefinedAtom *helperAtom = dyn_cast<DefinedAtom>(targ); assert(helperAtom != nullptr); // Found helper atom. Search it for Reference that is lazy immediate value. for (const Reference *href : *helperAtom ) { - if ( _writer.kindHandler()->isLazyImmediate(href->kind()) ) { + if ( _writer.kindHandler().isLazyImmediate(href->kind()) ) { (const_cast<Reference*>(href))->setAddend(offset); return; } @@ -1156,7 +1130,7 @@ void LazyBindingInfoChunk::computeSize(const lld::File &file, int flags = 0; StringRef name; for (const Reference *ref : *lazyPointerAtom ) { - if ( _writer.kindHandler()->isLazyTarget(ref->kind()) ) { + if ( _writer.kindHandler().isLazyTarget(ref->kind()) ) { const Atom *shlib = ref->target(); assert(shlib != nullptr); name = shlib->name(); @@ -1301,7 +1275,7 @@ uint32_t SymbolStringsChunk::stringIndex(StringRef str) { MachOWriter::MachOWriter(const MachOTargetInfo &ti) : _targetInfo(ti), - _referenceKindHandler(KindHandler::makeHandler(ti.getTriple().getArch())), + _referenceKindHandler(ti.kindHandler()), _cRuntimeFile(ti), _bindingInfo(nullptr), _lazyBindingInfo(nullptr), _symbolTableChunk(nullptr), _stringsChunk(nullptr), _entryAtom(nullptr), @@ -1392,17 +1366,14 @@ void MachOWriter::addLinkEditChunk(LinkEditChunk *chunk) { void MachOWriter::buildAtomToAddressMap() { DEBUG_WITH_TYPE("WriterMachO-layout", llvm::dbgs() << "assign atom addresses:\n"); - const bool lookForEntry = _targetInfo.getLinkerOptions()._outputKind == - OutputKind::StaticExecutable || - _targetInfo.getLinkerOptions()._outputKind == - OutputKind::DynamicExecutable; + const bool lookForEntry = _targetInfo.outputTypeHasEntry(); for (SectionChunk *chunk : _sectionChunks ) { for (const SectionChunk::AtomInfo &info : chunk->atoms() ) { _atomToAddress[info.atom] = chunk->address() + info.offsetInSection; if ( lookForEntry && (info.atom->contentType() == DefinedAtom::typeCode) && (info.atom->size() != 0) - && info.atom->name() == _targetInfo.getEntry()) { + && info.atom->name() == _targetInfo.entrySymbolName()) { _entryAtom = info.atom; } DEBUG_WITH_TYPE("WriterMachO-layout", llvm::dbgs() @@ -1425,7 +1396,7 @@ void MachOWriter::assignFileOffsets() { DEBUG_WITH_TYPE("WriterMachO-layout", llvm::dbgs() << "assign file offsets:\n"); uint64_t offset = 0; - uint64_t address = _targetInfo.getPageZeroSize(); + uint64_t address = _targetInfo.pageZeroSize(); for ( Chunk *chunk : _chunks ) { if ( chunk->segmentName().equals("__LINKEDIT") ) { _linkEditStartOffset = Chunk::alignTo(offset, 12); @@ -1463,7 +1434,7 @@ void MachOWriter::findSegment(StringRef segmentName, uint32_t *segIndex, const uint64_t kInvalidAddress = (uint64_t)(-1); StringRef lastSegName("__TEXT"); *segIndex = 0; - if ( _targetInfo.getPageZeroSize() != 0 ) { + if ( _targetInfo.pageZeroSize() != 0 ) { *segIndex = 1; } *segStartAddr = kInvalidAddress; @@ -1487,7 +1458,17 @@ void MachOWriter::findSegment(StringRef segmentName, uint32_t *segIndex, } bool MachOWriter::use64BitMachO() const { - return _targetInfo.getTriple().isArch64Bit(); + switch (_targetInfo.arch()) { + case MachOTargetInfo::arch_x86_64: + return true; + case MachOTargetInfo::arch_x86: + case MachOTargetInfo::arch_armv6: + case MachOTargetInfo::arch_armv7: + case MachOTargetInfo::arch_armv7s: + return false; + default: + llvm_unreachable("Unknown mach-o arch"); + } } diff --git a/lld/lib/ReaderWriter/Native/ReaderNative.cpp b/lld/lib/ReaderWriter/Native/ReaderNative.cpp index 1255a22ee27..ac3cf3bfe41 100644 --- a/lld/lib/ReaderWriter/Native/ReaderNative.cpp +++ b/lld/lib/ReaderWriter/Native/ReaderNative.cpp @@ -916,8 +916,8 @@ public: : lld::Reader(ti) {} virtual error_code parseFile( - std::unique_ptr<MemoryBuffer> mb, - std::vector<std::unique_ptr<lld::File> > &result) { + std::unique_ptr<MemoryBuffer> &mb, + std::vector<std::unique_ptr<lld::File> > &result) const { return File::make(_targetInfo, mb, mb->getBufferIdentifier(), result); } }; diff --git a/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp b/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp index 9b33dafccbc..b752a794117 100644 --- a/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp +++ b/lld/lib/ReaderWriter/PECOFF/ReaderCOFF.cpp @@ -369,8 +369,8 @@ class ReaderCOFF : public Reader { public: ReaderCOFF(const TargetInfo &ti) : Reader(ti) {} - error_code parseFile(std::unique_ptr<MemoryBuffer> mb, - std::vector<std::unique_ptr<File> > &result) { + error_code parseFile(std::unique_ptr<MemoryBuffer> &mb, + std::vector<std::unique_ptr<File> > &result) const { llvm::error_code ec; std::unique_ptr<File> f(new FileCOFF(_targetInfo, std::move(mb), ec)); if (ec) { diff --git a/lld/lib/ReaderWriter/Reader.cpp b/lld/lib/ReaderWriter/Reader.cpp index 17ee4f3023d..9f08ed27436 100644 --- a/lld/lib/ReaderWriter/Reader.cpp +++ b/lld/lib/ReaderWriter/Reader.cpp @@ -19,12 +19,12 @@ Reader::~Reader() { } error_code Reader::readFile(StringRef path, - std::vector<std::unique_ptr<File>> &result) { + std::vector<std::unique_ptr<File>> &result) const { OwningPtr<llvm::MemoryBuffer> opmb; if (error_code ec = llvm::MemoryBuffer::getFileOrSTDIN(path, opmb)) return ec; std::unique_ptr<MemoryBuffer> mb(opmb.take()); - return this->parseFile(std::move(mb), result); + return this->parseFile(mb, result); } } // end namespace lld diff --git a/lld/lib/ReaderWriter/ReaderArchive.cpp b/lld/lib/ReaderWriter/ReaderArchive.cpp index 370348b8990..d3287dd429d 100644 --- a/lld/lib/ReaderWriter/ReaderArchive.cpp +++ b/lld/lib/ReaderWriter/ReaderArchive.cpp @@ -10,7 +10,6 @@ #include "lld/ReaderWriter/ReaderArchive.h" #include "lld/Core/ArchiveLibraryFile.h" -#include "lld/Core/LinkerOptions.h" #include "llvm/ADT/Hashing.h" #include "llvm/Object/ObjectFile.h" @@ -46,8 +45,10 @@ public: OwningPtr<MemoryBuffer> buff; if (ci->getMemoryBuffer(buff, true)) return nullptr; - LinkerInput li(std::unique_ptr<MemoryBuffer>(buff.take())); - if (_getReader(li)->parseFile(li.takeBuffer(), result)) + std::unique_ptr<MemoryBuffer> mb(buff.take()); + if (_targetInfo.logInputFiles()) + llvm::outs() << buff->getBufferIdentifier() << "\n"; + if (_targetInfo.parseFile(mb, result)) return nullptr; assert(result.size() == 1); @@ -121,8 +122,7 @@ protected: } private: - std::function<ErrorOr<Reader&> (const LinkerInput &)> _getReader; - std::unique_ptr<llvm::object::Archive> _archive; + std::unique_ptr<llvm::object::Archive> _archive; atom_collection_vector<DefinedAtom> _definedAtoms; atom_collection_vector<UndefinedAtom> _undefinedAtoms; atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms; @@ -132,10 +132,8 @@ private: public: /// only subclasses of ArchiveLibraryFile can be instantiated FileArchive(const TargetInfo &ti, - std::function<ErrorOr<Reader &>(const LinkerInput &)> getReader, std::unique_ptr<llvm::MemoryBuffer> mb, error_code &ec) - : ArchiveLibraryFile(ti, mb->getBufferIdentifier()), - _getReader(getReader) { + : ArchiveLibraryFile(ti, mb->getBufferIdentifier()) { std::unique_ptr<llvm::object::Archive> archive_obj( new llvm::object::Archive(mb.release(), ec)); if (ec) @@ -155,16 +153,17 @@ public: } } - std::unordered_map<StringRef, llvm::object::Archive::child_iterator> _symbolMemberMap; + std::unordered_map<StringRef, + llvm::object::Archive::child_iterator> _symbolMemberMap; }; // class FileArchive // Returns a vector of Files that are contained in the archive file // pointed to by the MemoryBuffer -error_code ReaderArchive::parseFile(std::unique_ptr<llvm::MemoryBuffer> mb, - std::vector<std::unique_ptr<File>> &result){ +error_code ReaderArchive::parseFile(std::unique_ptr<llvm::MemoryBuffer> &mb, + std::vector<std::unique_ptr<File>> &result) const { error_code ec; - if (_options._forceLoadArchives) { + if (_targetInfo.forceLoadAllArchives()) { _archive.reset(new llvm::object::Archive(mb.release(), ec)); if (ec) return ec; @@ -174,13 +173,15 @@ error_code ReaderArchive::parseFile(std::unique_ptr<llvm::MemoryBuffer> mb, OwningPtr<MemoryBuffer> buff; if ((ec = mf->getMemoryBuffer(buff, true))) return ec; - LinkerInput li(std::unique_ptr<MemoryBuffer>(buff.take())); - if ((ec = _getReader(li)->parseFile(li.takeBuffer(), result))) + std::unique_ptr<MemoryBuffer> mbc(buff.take()); + if (_targetInfo.logInputFiles()) + llvm::outs() << buff->getBufferIdentifier() << "\n"; + if ((ec = _targetInfo.parseFile(mbc, result))) return ec; } } else { std::unique_ptr<File> f; - f.reset(new FileArchive(_targetInfo, _getReader, std::move(mb), ec)); + f.reset(new FileArchive(_targetInfo, std::move(mb), ec)); if (ec) return ec; diff --git a/lld/lib/ReaderWriter/ReaderLinkerScript.cpp b/lld/lib/ReaderWriter/ReaderLinkerScript.cpp index 4beb32a3bc6..646f97e7f46 100644 --- a/lld/lib/ReaderWriter/ReaderLinkerScript.cpp +++ b/lld/lib/ReaderWriter/ReaderLinkerScript.cpp @@ -11,7 +11,6 @@ #include "lld/Core/Error.h" #include "lld/Core/File.h" -#include "lld/Core/LinkerOptions.h" #include "lld/ReaderWriter/LinkerScript.h" using namespace lld; @@ -81,8 +80,8 @@ private: namespace lld { error_code -ReaderLinkerScript::parseFile(std::unique_ptr<llvm::MemoryBuffer> mb, - std::vector<std::unique_ptr<File> > &result) { +ReaderLinkerScript::parseFile(std::unique_ptr<llvm::MemoryBuffer> &mb, + std::vector<std::unique_ptr<File> > &result) const { auto lsf = LinkerScriptFile::create(_targetInfo, std::move(mb)); if (!lsf) return lsf; @@ -91,10 +90,7 @@ ReaderLinkerScript::parseFile(std::unique_ptr<llvm::MemoryBuffer> mb, for (const auto &c : ls->_commands) { if (auto group = dyn_cast<Group>(c)) for (const auto &path : group->getPaths()) { - auto reader = _getReader(LinkerInput(path._path)); - if (!reader) - return reader; - if (error_code ec = reader->readFile(path._path, result)) + if (error_code ec = _targetInfo.readFile(path._path, result)) return ec; } } diff --git a/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp b/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp index c2945f719f7..5100d3a1547 100644 --- a/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp +++ b/lld/lib/ReaderWriter/YAML/ReaderWriterYAML.cpp @@ -288,16 +288,44 @@ struct ScalarTraits<RefKind> { llvm::raw_ostream &out) { assert(ctxt != nullptr); ContextInfo *info = reinterpret_cast<ContextInfo*>(ctxt); - auto relocStr = info->_targetInfo.stringFromRelocKind(value); - out << (relocStr ? *relocStr : "<unknown>"); - } + switch (value) { + case lld::Reference::kindLayoutAfter: + out << "layout-after"; + break; + case lld::Reference::kindLayoutBefore: + out << "layout-before"; + break; + case lld::Reference::kindInGroup: + out << "in-group"; + break; + default: + if (auto relocStr = info->_targetInfo.stringFromRelocKind(value)) + out << *relocStr; + else + out << "<unknown>"; + break; + } + } static StringRef input(StringRef scalar, void *ctxt, RefKind &value) { assert(ctxt != nullptr); ContextInfo *info = reinterpret_cast<ContextInfo*>(ctxt); auto relocKind = info->_targetInfo.relocKindFromString(scalar); - if (!relocKind) + if (!relocKind) { + if (scalar.equals("layout-after")) { + value = lld::Reference::kindLayoutAfter; + return StringRef(); + } + if (scalar.equals("layout-before")) { + value = lld::Reference::kindLayoutBefore; + return StringRef(); + } + if (scalar.equals("in-group")) { + value = lld::Reference::kindInGroup; + return StringRef(); + } return "Invalid relocation kind"; + } value = *relocKind; return StringRef(); } @@ -1314,8 +1342,8 @@ class ReaderYAML : public Reader { public: ReaderYAML(const TargetInfo &ti) : Reader(ti) {} - error_code parseFile(std::unique_ptr<MemoryBuffer> mb, - std::vector<std::unique_ptr<File>> &result) { + error_code parseFile(std::unique_ptr<MemoryBuffer> &mb, + std::vector<std::unique_ptr<File>> &result) const { // Note: we do not take ownership of the MemoryBuffer. That is // because yaml may produce multiple File objects, so there is no // *one* File to take ownership. Therefore, the yaml File objects diff --git a/lld/test/CMakeLists.txt b/lld/test/CMakeLists.txt index 516f333f3c4..2ce4969165e 100644 --- a/lld/test/CMakeLists.txt +++ b/lld/test/CMakeLists.txt @@ -18,7 +18,7 @@ configure_lit_site_cfg( if ( NOT LLD_BUILT_STANDALONE ) set(LLD_TEST_DEPS - lld-core lld-test.deps + lld-test.deps FileCheck not llvm-nm lld llvm-objdump llvm-readobj linker-script-test @@ -68,7 +68,7 @@ else() ${LIT_ARGS} ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Running lld regression tests" - DEPENDS lld-core lld-test.deps + DEPENDS lld-test.deps ) set_target_properties(check-lld PROPERTIES FOLDER "lld tests") endif() diff --git a/lld/test/Driver/lib-search.test b/lld/test/Driver/lib-search.test index 94a369331c3..cd266986603 100644 --- a/lld/test/Driver/lib-search.test +++ b/lld/test/Driver/lib-search.test @@ -1,6 +1,6 @@ -RUN: lld -flavor ld -### -L%p/../elf/Inputs b.o -lfnarchive 2>&1 \ -RUN: | FileCheck %s +RUN: not lld -flavor gnu -t -L%p/../elf/Inputs -lfnarchive 2> %t.err \ +RUN: | FileCheck %s + +# run linker with -t mode to dump full paths to input files -CHECK: -input-search-path={{[^ ]+}}elf/Inputs -CHECK: b.o CHECK: {{[^ ]+}}elf/Inputs{{[\\/]}}libfnarchive.a diff --git a/lld/test/Driver/trivial-driver.test b/lld/test/Driver/trivial-driver.test index 06d0cac73f0..304d171d414 100644 --- a/lld/test/Driver/trivial-driver.test +++ b/lld/test/Driver/trivial-driver.test @@ -1,4 +1,5 @@ -RUN: lld -flavor ld -### -target i686-linux -e adena -o out.a 2>&1 \ -RUN: | FileCheck %s +RUN: lld -flavor gnu --help | FileCheck %s -CHECK: -target i686-linux -entry=adena -output=out.a +CHECK: -L +CHECK: -emit-yaml +CHECK: --noinhibit-exec diff --git a/lld/test/absolute-basic.objtxt b/lld/test/absolute-basic.objtxt index 19772881340..b13e2ac1d0a 100644 --- a/lld/test/absolute-basic.objtxt +++ b/lld/test/absolute-basic.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Test that absolute symbols are parsed and preserved diff --git a/lld/test/absolute-local.objtxt b/lld/test/absolute-local.objtxt index e9324255cec..1ba4c7f0432 100644 --- a/lld/test/absolute-local.objtxt +++ b/lld/test/absolute-local.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Test that absolute symbols with local scope do not cause name conflict diff --git a/lld/test/archive-basic.objtxt b/lld/test/archive-basic.objtxt index 80d945457f8..c93310762bd 100644 --- a/lld/test/archive-basic.objtxt +++ b/lld/test/archive-basic.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Tests archives in YAML. Tests that an undefined in a regular file will load diff --git a/lld/test/archive-chain.objtxt b/lld/test/archive-chain.objtxt index 286b60da22a..191b8520654 100644 --- a/lld/test/archive-chain.objtxt +++ b/lld/test/archive-chain.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Tests that an undefine in one archive can force a load from another archive. diff --git a/lld/test/archive-tentdef-search.objtxt b/lld/test/archive-tentdef-search.objtxt index 730bf59e0d4..f1802a19372 100644 --- a/lld/test/archive-tentdef-search.objtxt +++ b/lld/test/archive-tentdef-search.objtxt @@ -1,8 +1,8 @@ -# RUN: lld-core -commons-search-archives=false %s | FileCheck -check-prefix=CHK1 %s -# RUN: lld-core -commons-search-archives=true %s | FileCheck -check-prefix=CHK2 %s +# RUN: lld -core %s | FileCheck -check-prefix=CHK1 %s +# RUN: lld -core --commons-search-archives %s | FileCheck -check-prefix=CHK2 %s # -# Tests that -commons_search_archives cause core linker to look for overrides +# Tests that -commons-search-archives cause core linker to look for overrides # of tentative definition in archives, and that not using that option # does not search. # diff --git a/lld/test/auto-hide-coalesce.objtxt b/lld/test/auto-hide-coalesce.objtxt index 8d621b75400..24b2e1c4e65 100644 --- a/lld/test/auto-hide-coalesce.objtxt +++ b/lld/test/auto-hide-coalesce.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Tests auto-hide bit during coalescing diff --git a/lld/test/constants-coalesce.objtxt b/lld/test/constants-coalesce.objtxt index da388e50fe3..e64783720a7 100644 --- a/lld/test/constants-coalesce.objtxt +++ b/lld/test/constants-coalesce.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Test that duplicate merge-by-content anonymous constants are coalesced diff --git a/lld/test/cstring-coalesce.objtxt b/lld/test/cstring-coalesce.objtxt index 5723299c110..914740933ff 100644 --- a/lld/test/cstring-coalesce.objtxt +++ b/lld/test/cstring-coalesce.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Test that duplicate c-strings are coalesced diff --git a/lld/test/custom-section.objtxt b/lld/test/custom-section.objtxt index f92b3fdc91f..faf4f4310d1 100644 --- a/lld/test/custom-section.objtxt +++ b/lld/test/custom-section.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Test that custom sections are preserved diff --git a/lld/test/darwin/hello-world.objtxt b/lld/test/darwin/hello-world.objtxt index 0d96c0746b0..24a496e73e2 100644 --- a/lld/test/darwin/hello-world.objtxt +++ b/lld/test/darwin/hello-world.objtxt @@ -1,5 +1,5 @@ -# RUN: lld-core -writer=mach-o -stubs-pass %s -o %t && llvm-nm %t | FileCheck %s - +# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t && \ +# RUN: llvm-nm %t | FileCheck %s # # Test that hello-world can be linked into a mach-o executable # @@ -14,10 +14,10 @@ defined-atoms: 31, C0, 5D, C3 ] references: - offset: 7 - kind: pcrel32 + kind: ripRel32 target: LC1 - offset: 12 - kind: call32 + kind: branch32 target: _printf - ref-name: LC1 diff --git a/lld/test/dead-strip-attributes.objtxt b/lld/test/dead-strip-attributes.objtxt index a5d21b67245..dcb35a21e26 100644 --- a/lld/test/dead-strip-attributes.objtxt +++ b/lld/test/dead-strip-attributes.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Test that dead strip attributes are preserved diff --git a/lld/test/dead-strip-basic.objtxt b/lld/test/dead-strip-basic.objtxt index 206e3d8d673..94af8e2b1df 100644 --- a/lld/test/dead-strip-basic.objtxt +++ b/lld/test/dead-strip-basic.objtxt @@ -1,5 +1,5 @@ -# RUN: lld-core -dead-strip=true %s | FileCheck -check-prefix=CHK1 %s -# RUN: lld-core -dead-strip=false %s | FileCheck -check-prefix=CHK2 %s +# RUN: lld -core --dead-strip %s | FileCheck -check-prefix=CHK1 %s +# RUN: lld -core %s | FileCheck -check-prefix=CHK2 %s # # Test that -dead-strip removes unreachable code and data diff --git a/lld/test/dead-strip-globals.objtxt b/lld/test/dead-strip-globals.objtxt index 234600b3a13..568eb71511d 100644 --- a/lld/test/dead-strip-globals.objtxt +++ b/lld/test/dead-strip-globals.objtxt @@ -1,5 +1,5 @@ -# RUN: lld-core -dead-strip -keep-globals=true %s | FileCheck -check-prefix=CHK1 %s -# RUN: lld-core -dead-strip -keep-globals=false %s | FileCheck -check-prefix=CHK2 %s +# RUN: lld -core --dead-strip --keep-globals %s | FileCheck -check-prefix=CHK1 %s +# RUN: lld -core --dead-strip %s | FileCheck -check-prefix=CHK2 %s # # Test that -keep-globals prevents -dead-strip from removing globals. diff --git a/lld/test/elf/Hexagon/dynlib-data.test b/lld/test/elf/Hexagon/dynlib-data.test index 4626531f28c..76eb19a8d60 100644 --- a/lld/test/elf/Hexagon/dynlib-data.test +++ b/lld/test/elf/Hexagon/dynlib-data.test @@ -1,5 +1,5 @@ -RUN: lld -core -target hexagon %p/Inputs/dynobj-data.o \ -RUN: -output=%t -output=%t -noinhibit-exec -output-type=shared +RUN: lld -flavor gnu -target hexagon %p/Inputs/dynobj-data.o \ +RUN: -o %t --noinhibit-exec -shared RUN: llvm-objdump -s %t > %t1 RUN: FileCheck -check-prefix=CHECKRELOCS %s < %t1 diff --git a/lld/test/elf/Hexagon/dynlib-gotoff.test b/lld/test/elf/Hexagon/dynlib-gotoff.test index 7273ed4e2a6..1bff8fe4422 100644 --- a/lld/test/elf/Hexagon/dynlib-gotoff.test +++ b/lld/test/elf/Hexagon/dynlib-gotoff.test @@ -1,5 +1,5 @@ -RUN: lld -core -target hexagon %p/Inputs/dynobj.o \ -RUN: -output=%t -emit-yaml -noinhibit-exec -output-type=shared +RUN: lld -flavor gnu -target hexagon %p/Inputs/dynobj.o \ +RUN: -o %t -emit-yaml -shared --noinhibit-exec RUN: FileCheck -check-prefix=CHECKGOTPLT %s < %t - name: __got0 @@ -71,7 +71,7 @@ CHECKGOTPLT: - name: .text CHECKGOTPLT: alignment: 2^2 CHECKGOTPLT: section-name: .text CHECKGOTPLT: references: -CHECKGOTPLT: - kind: <unknown> +CHECKGOTPLT: - kind: layout-after CHECKGOTPLT: offset: 0 CHECKGOTPLT: target: fn2 CHECKGOTPLT: - name: fn2 diff --git a/lld/test/elf/Hexagon/dynlib-hash.test b/lld/test/elf/Hexagon/dynlib-hash.test index dd7979e4ed5..289d55e8a99 100644 --- a/lld/test/elf/Hexagon/dynlib-hash.test +++ b/lld/test/elf/Hexagon/dynlib-hash.test @@ -1,5 +1,5 @@ -RUN: lld -core -target hexagon %p/Inputs/dynobj.o \ -RUN: -output=%t -output=%t -noinhibit-exec -output-type=shared +RUN: lld -flavor gnu -target hexagon %p/Inputs/dynobj.o \ +RUN: -o %t --noinhibit-exec -shared RUN: llvm-objdump -s %t > %t1 RUN: FileCheck -check-prefix=CHECKHASH %s < %t1 diff --git a/lld/test/elf/Hexagon/dynlib-syms.test b/lld/test/elf/Hexagon/dynlib-syms.test index 621ce4165a0..1297937e875 100644 --- a/lld/test/elf/Hexagon/dynlib-syms.test +++ b/lld/test/elf/Hexagon/dynlib-syms.test @@ -1,5 +1,5 @@ -RUN: lld -core -target hexagon %p/Inputs/dynobj.o \ -RUN: -output=%t -output=%t -noinhibit-exec -output-type=shared +RUN: lld -flavor gnu -target hexagon %p/Inputs/dynobj.o \ +RUN: -o %t --noinhibit-exec -shared RUN: llvm-nm -n -s %t > %t1 RUN: FileCheck -check-prefix=CHECKSYMS %s < %t1 diff --git a/lld/test/elf/Hexagon/dynlib.test b/lld/test/elf/Hexagon/dynlib.test index 6d062260dd9..53d72d51d46 100644 --- a/lld/test/elf/Hexagon/dynlib.test +++ b/lld/test/elf/Hexagon/dynlib.test @@ -1,5 +1,4 @@ -RUN: lld -core -target hexagon %p/Inputs/use-shared.hexagon \ -RUN: -output=%t1 -output-type=shared +RUN: lld -flavor gnu -target hexagon %p/Inputs/use-shared.hexagon -shared -o %t1 RUN: llvm-readobj -dyn-symbols %t1 > %t2 RUN: FileCheck -check-prefix=DYNSYMS %s < %t2 diff --git a/lld/test/elf/Hexagon/hexagon-got-plt-order.test b/lld/test/elf/Hexagon/hexagon-got-plt-order.test index 366d67abe88..7600ebe59fc 100644 --- a/lld/test/elf/Hexagon/hexagon-got-plt-order.test +++ b/lld/test/elf/Hexagon/hexagon-got-plt-order.test @@ -1,5 +1,4 @@ -RUN: lld -core -target hexagon %p/Inputs/got-plt-order.o \ -RUN: -output=%t -noinhibit-exec -output-type=shared +RUN: lld -flavor gnu -target hexagon %p/Inputs/got-plt-order.o -o %t -shared RUN: llvm-objdump -section-headers %t | FileCheck %s CHECK: .got diff --git a/lld/test/elf/Hexagon/hexagon-plt-setup.test b/lld/test/elf/Hexagon/hexagon-plt-setup.test index 0e36169bd60..91989c618cb 100644 --- a/lld/test/elf/Hexagon/hexagon-plt-setup.test +++ b/lld/test/elf/Hexagon/hexagon-plt-setup.test @@ -1,15 +1,15 @@ -RUN: lld -core -target hexagon %p/Inputs/use-shared.hexagon \ -RUN: -emit-yaml -output=%t2 -noinhibit-exec -output-type=dynamic +RUN: lld -flavor gnu -target hexagon %p/Inputs/use-shared.hexagon \ +RUN: -emit-yaml -o %t2 RUN: FileCheck %s < %t2 CHECK: - name: fn3 CHECK: references: CHECK: - kind: R_HEX_B22_PCREL CHECK: offset: 4 - target: __plt_fn1 + target: CHECK: - kind: R_HEX_B22_PCREL CHECK: offset: 8 - target: __plt_fn2 -CHECK: - kind: <unknown> + target: +CHECK: - kind: layout-before CHECK: offset: 0 CHECK: target: fn1 diff --git a/lld/test/elf/Hexagon/rela-order.test b/lld/test/elf/Hexagon/rela-order.test index b3f4ce066f8..2f3814add0c 100644 --- a/lld/test/elf/Hexagon/rela-order.test +++ b/lld/test/elf/Hexagon/rela-order.test @@ -1,5 +1,5 @@ -RUN: lld -core -target hexagon %p/Inputs/dynobj.o \ -RUN: -output=%t -noinhibit-exec -output-type=shared +RUN: lld -flavor gnu -target hexagon %p/Inputs/dynobj.o -shared \ +RUN: --noinhibit-exec -o %t RUN: llvm-objdump -section-headers %t | FileCheck %s CHECK: .dynsym diff --git a/lld/test/elf/Hexagon/sda-base.test b/lld/test/elf/Hexagon/sda-base.test index 5db1dc381f2..0bab92abf68 100644 --- a/lld/test/elf/Hexagon/sda-base.test +++ b/lld/test/elf/Hexagon/sda-base.test @@ -1,4 +1,4 @@ -RUN: lld-core -arch hexagon -reader ELF %p/Inputs/sda-base.o -writer ELF -o %t1 +RUN: lld -flavor gnu -target hexagon %p/Inputs/sda-base.o -o %t1 --noinhibit-exec RUN: llvm-nm -n %t1 | FileCheck %s -check-prefix=sdabase -sdabase: 00001000 A _SDA_BASE_ +sdabase: 00002000 A _SDA_BASE_ diff --git a/lld/test/elf/X86_64/dynlib-nointerp-section.test b/lld/test/elf/X86_64/dynlib-nointerp-section.test index e41a781f0f4..dca3d925b38 100644 --- a/lld/test/elf/X86_64/dynlib-nointerp-section.test +++ b/lld/test/elf/X86_64/dynlib-nointerp-section.test @@ -1,5 +1,4 @@ -RUN: lld -core -target x86_64 %p/Inputs/no-interp-section.o -output=%t \ -RUN: -noinhibit-exec -output-type=shared +RUN: lld -flavor gnu -target x86_64 %p/Inputs/no-interp-section.o -o %t -shared RUN: llvm-objdump -section-headers %t | FileCheck %s CHECK-NOT: .interp diff --git a/lld/test/elf/X86_64/multi-weak-override.test b/lld/test/elf/X86_64/multi-weak-override.test index 8332a75ffc6..176bedaac32 100644 --- a/lld/test/elf/X86_64/multi-weak-override.test +++ b/lld/test/elf/X86_64/multi-weak-override.test @@ -1,15 +1,16 @@ # Test for weak symbol getting overridden -RUN: lld-core -reader ELF -writer ELF -arch x86_64 %p/Inputs/multi-weak.o \ -RUN: %p/Inputs/multi-ovrd.o -o %t +RUN: lld -flavor gnu -target x86_64 %p/Inputs/multi-weak.o \ +RUN: %p/Inputs/multi-ovrd.o -o %t -e main --noinhibit-exec RUN: llvm-nm -n %t | FileCheck -check-prefix=WEAKORDER %s -RUN: lld-core -reader ELF -arch x86_64 %p/Inputs/multi-weak.o \ -RUN: %p/Inputs/multi-ovrd.o -layout-pass=true -o %t2 +RUN: lld -flavor gnu -target x86_64 %p/Inputs/multi-weak.o \ +RUN: %p/Inputs/multi-ovrd.o -emit-yaml -o %t2 --noinhibit-exec RUN: FileCheck -check-prefix=WEAKATOMSORDER %s < %t2 -WEAKORDER: 0040011c T f -WEAKORDER: 0040012c T g +WEAKORDER: 0040020c T f +WEAKORDER: 0040021c T g WEAKATOMSORDER: - ref-name: L002 WEAKATOMSORDER: - ref-name: L003 WEAKATOMSORDER: - name: f WEAKATOMSORDER: - name: g + diff --git a/lld/test/elf/X86_64/multi-weak-syms-order.test b/lld/test/elf/X86_64/multi-weak-syms-order.test index f5376d8c230..ce6983fd037 100644 --- a/lld/test/elf/X86_64/multi-weak-syms-order.test +++ b/lld/test/elf/X86_64/multi-weak-syms-order.test @@ -1,19 +1,19 @@ # Test for weak symbol getting overridden -RUN: lld-core -reader ELF -writer ELF -arch x86_64 %p/Inputs/multi-weak.o \ -RUN: -o %t +RUN: lld -flavor gnu -target x86_64 %p/Inputs/multi-weak.o -o %t --noinhibit-exec RUN: llvm-nm -n %t | FileCheck -check-prefix=WEAKORDER %s -RUN: lld-core -reader ELF -arch x86_64 %p/Inputs/multi-weak.o \ -RUN: -layout-pass=true -o %t2 +RUN: lld -flavor gnu -target x86_64 %p/Inputs/multi-weak.o -o %t2 -emit-yaml --noinhibit-exec RUN: FileCheck -check-prefix=WEAKATOMSORDER %s < %t2 -WEAKORDER: 004000c0 T fn -WEAKORDER: 004000cb T .text -WEAKORDER: 004000cb T f -WEAKORDER: 004000db T .text -WEAKORDER: 004000db T g -WEAKORDER: 004000eb T main +WEAKORDER: 004001b0 T fn +WEAKORDER: 004001bb T .text +WEAKORDER: 004001bb T f +WEAKORDER: 004001cb T .text +WEAKORDER: 004001cb T g +WEAKORDER: 004001db T main WEAKATOMSORDER: - name: f WEAKATOMSORDER: - ref-name: L004 WEAKATOMSORDER: - name: g WEAKATOMSORDER: - ref-name: L005 + + diff --git a/lld/test/elf/X86_64/weak-override.test b/lld/test/elf/X86_64/weak-override.test index ba04fb6c102..4da3b4ef37c 100644 --- a/lld/test/elf/X86_64/weak-override.test +++ b/lld/test/elf/X86_64/weak-override.test @@ -1,12 +1,12 @@ # Test for weak symbol getting overridden -RUN: lld-core -reader ELF -writer ELF -arch x86_64 %p/Inputs/weak.o \ -RUN: %p/Inputs/ovrd.o -o %t +RUN: lld -flavor gnu -target x86_64 %p/Inputs/weak.o %p/Inputs/ovrd.o \ +RUN: -o %t --noinhibit-exec RUN: llvm-nm %t | FileCheck -check-prefix=WEAKORDER %s -RUN: lld-core -reader ELF -arch x86_64 %p/Inputs/weak.o \ -RUN: %p/Inputs/ovrd.o -layout-pass=true -o %t2 +RUN: lld -flavor gnu -target x86_64 %p/Inputs/weak.o \ +RUN: %p/Inputs/ovrd.o -o %t2 -emit-yaml --noinhibit-exec RUN: FileCheck -check-prefix=WEAKATOMSORDER %s < %t2 -WEAKORDER: 004000fc T f +WEAKORDER: 004001ec T f WEAKATOMSORDER: - name: .text WEAKATOMSORDER: references: @@ -34,7 +34,7 @@ WEAKATOMSORDER: scope: global WEAKATOMSORDER: content: [ 55, 48, 89, E5, B8, 00, 00, 00, 00, E8, 00, 00, WEAKATOMSORDER: 00, 00, B8, 00, 00, 00, 00, 5D, C3 ] WEAKATOMSORDER: references: -WEAKATOMSORDER: - kind: call32 +WEAKATOMSORDER: - kind: R_X86_64_PC32 WEAKATOMSORDER: offset: 10 WEAKATOMSORDER: target: f WEAKATOMSORDER: addend: -4 diff --git a/lld/test/elf/X86_64/weak-zero-sized.test b/lld/test/elf/X86_64/weak-zero-sized.test index 4ba2c0fc614..2e9eaf868dd 100644 --- a/lld/test/elf/X86_64/weak-zero-sized.test +++ b/lld/test/elf/X86_64/weak-zero-sized.test @@ -1,12 +1,12 @@ # Test for zero sized weak atoms, there is only a single weak atom -RUN: lld-core -reader ELF -writer ELF -arch x86_64 %p/Inputs/weak-zero-sized.o \ -RUN: -o %t +RUN: lld -flavor gnu -target x86_64 %p/Inputs/weak-zero-sized.o -o %t \ +RUN: --noinhibit-exec RUN: llvm-nm %t | FileCheck -check-prefix=WEAKORDER %s -RUN: lld-core -reader ELF -arch x86_64 %p/Inputs/weak-zero-sized.o \ -RUN: -layout-pass=true -o %t2 +RUN: lld -flavor gnu -target x86_64 %p/Inputs/weak-zero-sized.o \ +RUN: -emit-yaml -o %t2 --noinhibit-exec RUN: FileCheck -check-prefix=WEAKATOMSORDER %s < %t2 -WEAKORDER: 004000b0 T _start +WEAKORDER: 004001a4 T _start WEAKATOMSORDER: - name: .text WEAKATOMSORDER: alignment: 2^2 diff --git a/lld/test/elf/abs.objtxt b/lld/test/elf/abs.objtxt index 1466831d35f..fb208e1e98c 100644 --- a/lld/test/elf/abs.objtxt +++ b/lld/test/elf/abs.objtxt @@ -9,7 +9,7 @@ # built using: "gcc -m32" # -RUN: lld-core -reader ELF %p/Inputs/abs-test.i386 | FileCheck -check-prefix=YAML %s +RUN: lld -flavor gnu -emit-yaml -r %p/Inputs/abs-test.i386 | FileCheck -check-prefix=YAML %s YAML: absolute-atoms: YAML: - name: absLocalSymbol diff --git a/lld/test/elf/archive-elf-forceload.objtxt b/lld/test/elf/archive-elf-forceload.objtxt index 331cb995663..1c2bc385a89 100644 --- a/lld/test/elf/archive-elf-forceload.objtxt +++ b/lld/test/elf/archive-elf-forceload.objtxt @@ -23,7 +23,9 @@ # } # gcc -c main.c fn.c fn1.c -RUN: lld-core -reader ELF %p/Inputs/mainobj.x86_64 %p/Inputs/libfnarchive.a -force-load | FileCheck -check-prefix FORCELOAD %s +RUN: lld -flavor gnu -target x86_64-linux -e main %p/Inputs/mainobj.x86_64 \ +RUN: %p/Inputs/libfnarchive.a --force-load -emit-yaml \ +RUN: | FileCheck -check-prefix FORCELOAD %s FORCELOAD: defined-atoms: FORCELOAD: - name: fn1 diff --git a/lld/test/elf/archive-elf.objtxt b/lld/test/elf/archive-elf.objtxt index 57d8f90be84..fb377faf5d0 100644 --- a/lld/test/elf/archive-elf.objtxt +++ b/lld/test/elf/archive-elf.objtxt @@ -23,7 +23,7 @@ # } # gcc -c main.c fn.c fn1.c -RUN: lld-core -reader ELF %p/Inputs/mainobj.x86_64 %p/Inputs/libfnarchive.a | FileCheck -check-prefix NOFORCELOAD %s +RUN: lld -flavor gnu -emit-yaml -r %p/Inputs/mainobj.x86_64 %p/Inputs/libfnarchive.a | FileCheck -check-prefix NOFORCELOAD %s NOFORCELOAD: defined-atoms: NOFORCELOAD: - name: fn diff --git a/lld/test/elf/branch.objtxt b/lld/test/elf/branch.objtxt index aa1f5a4c9f3..7110840d621 100644 --- a/lld/test/elf/branch.objtxt +++ b/lld/test/elf/branch.objtxt @@ -1,24 +1,19 @@ -RUN: lld-core -arch hexagon -reader ELF %p/Inputs/branch-test.hexagon %p/Inputs/target-test.hexagon | FileCheck %s -check-prefix hexagon-yaml -RUN: lld-core -arch hexagon -reader ELF -writer ELF -o %t1 %p/Inputs/branch-test.hexagon %p/Inputs/target-test.hexagon +RUN: lld -flavor gnu -target hexagon -static -emit-yaml %p/Inputs/branch-test.hexagon %p/Inputs/target-test.hexagon | FileCheck %s -check-prefix hexagon-yaml +RUN: lld -flavor gnu -target hexagon -e target -o %t1 %p/Inputs/branch-test.hexagon %p/Inputs/target-test.hexagon RUN: elf-dump %t1 | FileCheck -check-prefix=hexagon-elfdump %s hexagon-yaml: - name: back hexagon-yaml: scope: global hexagon-yaml: content: [ 00, C0, 00, 7F, 00, C0, 00, 5A, 00, 00, 00, 00, hexagon-yaml: 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 ] -hexagon-yaml: section-choice: custom-required -hexagon-yaml: section-name: .text - hexagon-yaml: references: -hexagon-yaml: - kind: -hexagon-yaml: offset: 4 -hexagon-yaml: target: target +hexagon-yaml: - kind: +hexagon-yaml: offset: 4 +hexagon-yaml: target: target hexagon-yaml: - name: target hexagon-yaml: scope: global hexagon-yaml: content: [ 00, C0, 00, 5A ] -hexagon-yaml: section-choice: custom-required -hexagon-yaml: section-name: .text hexagon-yaml: references: hexagon-yaml: - kind: hexagon-yaml: offset: 0 diff --git a/lld/test/elf/check.objtxt b/lld/test/elf/check.objtxt index f16f1d7a1a1..337c81a59bb 100644 --- a/lld/test/elf/check.objtxt +++ b/lld/test/elf/check.objtxt @@ -1,7 +1,17 @@ -RUN: lld-core -reader ELF %p/Inputs/object-test.elf-i386 | FileCheck %s -check-prefix ELF-i386 -RUN: lld-core -arch hexagon -reader ELF %p/Inputs/object-test.elf-hexagon | FileCheck %s -check-prefix ELF-hexagon +RUN: lld -flavor gnu -target i386 -e global_func --noinhibit-exec -emit-yaml %p/Inputs/object-test.elf-i386 | FileCheck %s -check-prefix ELF-i386 +RUN: lld -flavor gnu -target hexagon -e global_func --noinhibit-exec -emit-yaml %p/Inputs/object-test.elf-hexagon | FileCheck %s -check-prefix ELF-hexagon ELF-i386:defined-atoms: +ELF-i386: - name: tentative +ELF-i386: scope: global +ELF-i386: type: zero-fill +ELF-i386: merge: as-tentative + +ELF-i386: - name: common_symbol +ELF-i386: scope: global +ELF-i386: type: zero-fill +ELF-i386: merge: as-tentative + ELF-i386: - name: global_func ELF-i386: scope: global ELF-i386: content: [ 55, 89, E5, 83, EC, 18, C7, 04, 24, 00, 00, 00, @@ -36,16 +46,6 @@ ELF-i386: content: [ 55, 89, E5, 5D, C3 ] ELF-i386: section-choice: custom-required ELF-i386: section-name: special_section -ELF-i386: - name: tentative -ELF-i386: scope: global -ELF-i386: type: zero-fill -ELF-i386: merge: as-tentative - -ELF-i386: - name: common_symbol -ELF-i386: scope: global -ELF-i386: type: zero-fill -ELF-i386: merge: as-tentative - ELF-i386:undefined-atoms: ELF-i386: - name: puts @@ -53,7 +53,17 @@ ELF-i386:absolute-atoms: ELF-i386: - name: sample.c ELF-i386: value: 0x0 -ELF-hexagon:atoms: +ELF-hexagon:defined-atoms: +ELF-hexagon: - name: tentative +ELF-hexagon: scope: global +ELF-hexagon: type: zero-fill +ELF-hexagon: merge: as-tentative + +ELF-hexagon: - name: common_symbol +ELF-hexagon: scope: global +ELF-hexagon: type: zero-fill +ELF-hexagon: merge: as-tentative + ELF-hexagon: - name: global_func ELF-hexagon: scope: global ELF-hexagon: content: [ 00, C0, 9D, A0, 00, 40, 00, 00, 00, C0, 00, 78, @@ -88,16 +98,6 @@ ELF-hexagon: content: [ 00, C0, 9D, A0, 1E, C0, 1E, 96 ] ELF-hexagon: section-choice: custom-required ELF-hexagon: section-name: special_section -ELF-hexagon: - name: tentative -ELF-hexagon: scope: global -ELF-hexagon: type: zero-fill -ELF-hexagon: merge: as-tentative - -ELF-hexagon: - name: common_symbol -ELF-hexagon: scope: global -ELF-hexagon: type: zero-fill -ELF-hexagon: merge: as-tentative - ELF-hexagon: undefined-atoms: ELF-hexagon: - name: puts diff --git a/lld/test/elf/common.test b/lld/test/elf/common.test index 85810e43f14..46fcfe39d48 100644 --- a/lld/test/elf/common.test +++ b/lld/test/elf/common.test @@ -1,5 +1,5 @@ -RUN: lld -core -target x86_64-linux -output=%t %p/Inputs/relocs.x86-64 \ -RUN: -output-type=static +RUN: lld -flavor gnu -target x86_64-linux -o %t %p/Inputs/relocs.x86-64 \ +RUN: -e _start -static RUN: llvm-readobj -t %t | FileCheck %s CHECK: Symbol { diff --git a/lld/test/elf/dynamic-segorder.test b/lld/test/elf/dynamic-segorder.test index 57fa661f289..b09249ae228 100644 --- a/lld/test/elf/dynamic-segorder.test +++ b/lld/test/elf/dynamic-segorder.test @@ -1,6 +1,5 @@ -RUN: lld -core -target x86_64-linux %p/Inputs/tls.x86-64 \ -RUN: %p/Inputs/shared.so-x86-64 -output=%t -entry=main \ -RUN: -output-type=dynamic +RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/tls.x86-64 \ +RUN: %p/Inputs/shared.so-x86-64 -o %t -e main RUN: llvm-objdump -p %t | FileCheck %s CHECK: PHDR diff --git a/lld/test/elf/dynamic.test b/lld/test/elf/dynamic.test index fa2e5d7174a..b3c16989a6d 100644 --- a/lld/test/elf/dynamic.test +++ b/lld/test/elf/dynamic.test @@ -1,26 +1,26 @@ -RUN: lld -core -target x86_64-linux %p/Inputs/use-shared.x86-64 \ -RUN: %p/Inputs/shared.so-x86-64 -output=%t -entry=main \ -RUN: -output-type=dynamic -RUN: lld -core -target x86_64-linux %p/Inputs/use-shared.x86-64 \ -RUN: %p/Inputs/shared.so-x86-64 -emit-yaml -output=%t2 -noinhibit-exec \ -RUN: -output-type=dynamic +RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/use-shared.x86-64 \ +RUN: %p/Inputs/shared.so-x86-64 -o %t -e main +RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/use-shared.x86-64 \ +RUN: %p/Inputs/shared.so-x86-64 -emit-yaml -o %t2 --noinhibit-exec RUN: llvm-objdump -p %t >> %t2 RUN: llvm-readobj -s -dyn-symbols -dynamic-table %t >> %t2 RUN: FileCheck %s < %t2 CHECK: type: got -CHECK: R_X86_64_JUMP_SLOT +CHECK: references: +CHECK: kind: R_X86_64_JUMP_SLOT CHECK: name: main CHECK: kind: R_X86_64_PC32 -CHECK: target: [[PLTNAME:[-a-zA-Z0-9_]+]] +CHECK: offset: 18 +CHECK: target: [[PLTNAME:[-a-zA-Z0-9_]+]] CHECK: name: [[PLTNAME]] CHECK: type: stub CHECK: shared-library-atoms: -CHECK: name: foo -CHECK: load-name: shared.so-x86-64 +CHECK: name: foo +CHECK: load-name: shared.so-x86-64 CHECK: PHDR off 0x{{0+}}40 CHECK: INTERP diff --git a/lld/test/elf/entry.objtxt b/lld/test/elf/entry.objtxt index 66422bceba9..1cc600cd655 100644 --- a/lld/test/elf/entry.objtxt +++ b/lld/test/elf/entry.objtxt @@ -8,12 +8,12 @@ # } # -# RUN: lld-core -reader YAML %s -writer ELF --entry=_entrypoint -o %t1 +# RUN: lld -flavor gnu %s -e _entrypoint --noinhibit-exec -o %t1 # RUN: llvm-nm -n %t1 | FileCheck %s # -# CHECK: 00000080 T main -# CHECK: 00001000 A _end -# CHECK: 00001000 A end +# CHECK: 004001b0 T main +# CHECK: 00401000 A _end +# CHECK: 00401000 A end # CHECK: U _entrypoint defined-atoms: @@ -52,6 +52,6 @@ defined-atoms: section-name: .eh_frame permissions: r-- references: - - kind: call32 + - kind: R_X86_64_PC32 offset: 32 target: .text diff --git a/lld/test/elf/gotpcrel.test b/lld/test/elf/gotpcrel.test index 42300ba6710..a2a87b0fddc 100644 --- a/lld/test/elf/gotpcrel.test +++ b/lld/test/elf/gotpcrel.test @@ -1,6 +1,6 @@ -RUN: lld -core -target x86_64-linux -output=- -entry=main -output-type=static \ -RUN: %p/Inputs/gotpcrel.x86-64 -emit-yaml -noinhibit-exec \ -RUN: | FileCheck %s -check-prefix=YAML +RUN: lld -flavor gnu -target x86_64-linux -static -e main -emit-yaml \ +RUN: --noinhibit-exec %p/Inputs/gotpcrel.x86-64 \ +RUN: | FileCheck %s -check-prefix=YAML YAML: name: [[NULLGOT:[a-zA-Z0-9_]+]] YAML: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ] @@ -11,7 +11,11 @@ YAML: kind: R_X86_64_64 YAML: target: main YAML: name: main -YAML: kind: R_X86_64_PC32 -YAML: target: [[NULLGOT]] -YAML: kind: R_X86_64_PC32 -YAML: target: [[MAINGOT]] +YAML: references: +YAML: kind: R_X86_64_PC32 +YAML: offset: 3 +YAML: target: [[NULLGOT]] +YAML: kind: R_X86_64_PC32 +YAML: offset: 10 +YAML: target: [[MAINGOT]] + diff --git a/lld/test/elf/hexagon-quickdata-sort.test b/lld/test/elf/hexagon-quickdata-sort.test index 952ed6ed4d7..199cb9d1afc 100644 --- a/lld/test/elf/hexagon-quickdata-sort.test +++ b/lld/test/elf/hexagon-quickdata-sort.test @@ -1,12 +1,12 @@ -RUN: lld-core -arch hexagon -reader ELF %p/Inputs/quickdata-sort-test.o.elf-hexagon -writer ELF -o %t1 +RUN: lld -flavor gnu -target hexagon %p/Inputs/quickdata-sort-test.o.elf-hexagon -o %t1 --noinhibit-exec RUN: llvm-nm -n %t1 | FileCheck %s -check-prefix=quickdataSort -quickdataSort: 00001000 D A1 -quickdataSort: 00001001 D AA1 -quickdataSort: 00001002 D B1 -quickdataSort: 00001004 D BB1 -quickdataSort: 00001008 D C1 -quickdataSort: 0000100c D CC1 -quickdataSort: 00001010 D D1 -quickdataSort: 00001018 D DD1 +quickdataSort: 00002000 D A1 +quickdataSort: 00002001 D AA1 +quickdataSort: 00002002 D B1 +quickdataSort: 00002004 D BB1 +quickdataSort: 00002008 D C1 +quickdataSort: 0000200c D CC1 +quickdataSort: 00002010 D D1 +quickdataSort: 00002018 D DD1 diff --git a/lld/test/elf/hexagon-quickdata-sortcommon.test b/lld/test/elf/hexagon-quickdata-sortcommon.test index eb66da56265..f7b2d063545 100644 --- a/lld/test/elf/hexagon-quickdata-sortcommon.test +++ b/lld/test/elf/hexagon-quickdata-sortcommon.test @@ -1,16 +1,17 @@ -RUN: lld-core -arch hexagon -reader ELF %p/Inputs/quickdata-sortcommon-test.o.elf-hexagon -writer ELF -o %t1 +RUN: lld -flavor gnu -target hexagon -o %t1 --noinhibit-exec \ +RUN: %p/Inputs/quickdata-sortcommon-test.o.elf-hexagon RUN: llvm-nm -n %t1 | FileCheck %s -check-prefix=quickdataSortCommon -quickdataSortCommon: 00001000 D A1 -quickdataSortCommon: 00001001 D AA1 -quickdataSortCommon: 00001002 D AAA1 -quickdataSortCommon: 00001004 D B1 -quickdataSortCommon: 00001006 D BB1 -quickdataSortCommon: 00001008 D BBB1 -quickdataSortCommon: 0000100c D C1 -quickdataSortCommon: 00001010 D CC1 -quickdataSortCommon: 00001014 D CCC1 -quickdataSortCommon: 00001018 D D1 -quickdataSortCommon: 00001020 D DD1 -quickdataSortCommon: 00001028 D DDD1 +quickdataSortCommon: 00002000 D A1 +quickdataSortCommon: 00002001 D AA1 +quickdataSortCommon: 00002002 D AAA1 +quickdataSortCommon: 00002004 D B1 +quickdataSortCommon: 00002006 D BB1 +quickdataSortCommon: 00002008 D BBB1 +quickdataSortCommon: 0000200c D C1 +quickdataSortCommon: 00002010 D CC1 +quickdataSortCommon: 00002014 D CCC1 +quickdataSortCommon: 00002018 D D1 +quickdataSortCommon: 00002020 D DD1 +quickdataSortCommon: 00002028 D DDD1 diff --git a/lld/test/elf/ifunc.test b/lld/test/elf/ifunc.test index a1c55f29d2a..e67cfbf7910 100644 --- a/lld/test/elf/ifunc.test +++ b/lld/test/elf/ifunc.test @@ -1,42 +1,51 @@ -RUN: lld -core -target x86_64-linux -emit-yaml -output=- -output-type=static \ -RUN: %p/Inputs/ifunc.x86-64 -noinhibit-exec | FileCheck %s +RUN: lld -flavor gnu -target x86_64-linux -emit-yaml -r \ +RUN: %p/Inputs/ifunc.x86-64 | FileCheck %s -RUN: lld -core -target x86_64-linux -emit-yaml -output=- -output-type=static \ -RUN: %p/Inputs/ifunc.x86-64 -noinhibit-exec %p/Inputs/ifunc.cpp.x86-64 \ +RUN: lld -flavor gnu -target x86_64-linux -emit-yaml --noinhibit-exec \ +RUN: %p/Inputs/ifunc.x86-64 %p/Inputs/ifunc.cpp.x86-64 \ RUN: | FileCheck %s --check-prefix=PLT -RUN: lld -core -target x86_64-linux -output=%t %p/Inputs/ifunc.x86-64 \ -RUN: -entry=main -output-type=static %p/Inputs/ifunc.cpp.x86-64 \ +RUN: lld -flavor gnu -target x86_64-linux -o %t %p/Inputs/ifunc.x86-64 \ +RUN: -e main -static %p/Inputs/ifunc.cpp.x86-64 \ RUN: && llvm-objdump -d -s %t| FileCheck %s --check-prefix=BIN + +PLT: defined-atoms: + // Make sure there's a got entry with a IRELATIVE relocation. PLT: type: got -PLT: kind: R_X86_64_IRELATIVE -PLT: target: hey +PLT: references: +PLT: kind: R_X86_64_IRELATIVE +PLT: target: hey -PLT: name: plt +PLT: name: plt PLT: scope: global -PLT: kind: R_X86_64_PC32 -PLT: target: [[PLTNAME:[-a-zA-Z0-9_]+]] - +PLT: references: +PLT: kind: R_X86_64_PC32 +PLT: target: [[PLTNAME:[-a-zA-Z0-9_]+]] +PLT: kind: layout-before +PLT: target: __hey_1 PLT: name: main PLT: scope: global -PLT: references -PLT: kind: R_X86_64_PC32 -PLT: target: [[PLTNAME]] - -CHECK: name: hey -CHECK: scope: global -CHECK: type: resolver +PLT: references: +PLT: kind: R_X86_64_PC32 +PLT: target: [[PLTNAME]] // Make sure the target of main's relocation is a stub with a PC32 relocation. // This relocation is to the got atom, but you can't really write that check in // FileCheck. -PLT: name: [[PLTNAME]] +PLT: name: PLT: type: stub PLT: references -PLT: kind: R_X86_64_PC32 +PLT: kind: R_X86_64_PC32 + +CHECK: name: hey +CHECK: scope: global +CHECK: type: resolver + +// This is a horribly brittle test. We need a way to do arithmetic on captured +// variables. BIN: {{[0-9a-f]+}}: ff 25 {{[0-9a-f]+}} {{[0-9a-f]+}} 00 00 jmpq *{{[0-9]+}}(%rip) BIN: .got.plt: BIN-NEXT: {{[0-9a-f]+}} 00000000 00000000 diff --git a/lld/test/elf/init_array.test b/lld/test/elf/init_array.test index 0fa926f1295..1acf4a7e7a2 100644 --- a/lld/test/elf/init_array.test +++ b/lld/test/elf/init_array.test @@ -1,5 +1,5 @@ -RUN: lld -core -target x86_64-linux -output=%t %p/Inputs/init_array.x86-64 \ -RUN: -output-type=static +RUN: lld -flavor gnu -target x86_64-linux -o %t %p/Inputs/init_array.x86-64 \ +RUN: -e __init_array_start RUN: llvm-objdump -t -section-headers %t | FileCheck %s CHECK: .init_array {{[0-9]+}} [[ADDR:[0-9]+]] diff --git a/lld/test/elf/mergeatoms.objtxt b/lld/test/elf/mergeatoms.objtxt index 82761caede4..f2aadefaf57 100644 --- a/lld/test/elf/mergeatoms.objtxt +++ b/lld/test/elf/mergeatoms.objtxt @@ -1,5 +1,5 @@ -RUN: lld-core -merge-strings=true -reader ELF -writer ELF \ -RUN: -o %t1 %p/Inputs/foo.o.x86-64 %p/Inputs/bar.o.x86-64 +RUN: lld -flavor gnu --merge-strings -o %t1 \ +RUN: %p/Inputs/foo.o.x86-64 %p/Inputs/bar.o.x86-64 -e bar1 RUN: llvm-objdump -s %t1 | FileCheck -check-prefix=mergeAtoms %s -mergeAtoms: 0074 62617200 666f6f00 bar.foo. +mergeAtoms: 62617200 666f6f00 bar.foo. diff --git a/lld/test/elf/mergeconstants.objtxt b/lld/test/elf/mergeconstants.objtxt index 75284ac37e2..d9cf4dd912b 100644 --- a/lld/test/elf/mergeconstants.objtxt +++ b/lld/test/elf/mergeconstants.objtxt @@ -1,4 +1,4 @@ -RUN: lld-core -merge-strings=true -reader ELF %p/Inputs/constants-merge.x86-64 | FileCheck -check-prefix=mergeAtoms %s +RUN: lld -flavor gnu --merge-strings -emit-yaml %p/Inputs/constants-merge.x86-64 | FileCheck -check-prefix=mergeAtoms %s mergeAtoms: - name: foo mergeAtoms: scope: global @@ -8,7 +8,7 @@ mergeAtoms: alignment: 2^3 mergeAtoms: section-choice: custom-required mergeAtoms: section-name: .data mergeAtoms: references: -mergeAtoms: - kind: <unknown> +mergeAtoms: - kind: R_X86_64_64 mergeAtoms: offset: 3 mergeAtoms: target: L001 mergeAtoms: - kind: layout-before diff --git a/lld/test/elf/mergeglobalatoms.test b/lld/test/elf/mergeglobalatoms.test index 10d70363b4b..7831b719cd5 100644 --- a/lld/test/elf/mergeglobalatoms.test +++ b/lld/test/elf/mergeglobalatoms.test @@ -1,6 +1,7 @@ # ELF files can have mergeable strings which are global!, treat them as global # defined atoms -RUN: lld-core -merge-strings=true -reader ELF %p/Inputs/globalconst.o.x86-64 | FileCheck -check-prefix=globalatoms %s +RUN: lld -flavor gnu -emit-yaml %p/Inputs/globalconst.o.x86-64 \ +RUN: | FileCheck -check-prefix=globalatoms %s globalatoms: - name: mystr globalatoms: scope: global diff --git a/lld/test/elf/phdr.objtxt b/lld/test/elf/phdr.objtxt index 5b6bdf45798..7e26f45af94 100644 --- a/lld/test/elf/phdr.objtxt +++ b/lld/test/elf/phdr.objtxt @@ -1,20 +1,40 @@ -RUN: lld-core -reader ELF -writer ELF -o %t1 %p/Inputs/phdr.i386 -RUN: elf-dump %t1 | FileCheck -check-prefix=ED %s +RUN: lld -flavor gnu -target i386-linux -o %t1 -e main %p/Inputs/phdr.i386 \ +RUN: | elf-dump %t1 | FileCheck -check-prefix=ED %s +RUN: lld -flavor gnu -target x86_64-linux -o %t1 -e _start %p/Inputs/relocs.x86-64 -static \ +RUN: && llvm-objdump -p %t1 | FileCheck %s -check-prefix=X86_64 -RUN: lld -core -target x86_64-linux -output=%t1 %p/Inputs/relocs.x86-64 \ -RUN: -output-type=static && llvm-objdump -p %t1 \ -RUN: | FileCheck %s -check-prefix=X86_64 +ED: # Program Header 0 +ED: (('p_type', 0x00000006) +ED: ('p_flags', 0x00000005) +ED: ('p_offset', 0x00000034) +ED: ('p_vaddr', 0x00000034) +ED: ('p_paddr', 0x00000034) +ED: ('p_filesz', 0x000000c0) +ED: ('p_memsz', 0x000000c0) +ED: ('p_align', 0x00000008) +ED: ), +ED: # Program Header 1 +ED: (('p_type', 0x00000003) +ED: ('p_flags', 0x00000004) +ED: ('p_offset', 0x000000f4) +ED: ('p_vaddr', 0x000000f4) +ED: ('p_paddr', 0x000000f4) +ED: ('p_filesz', 0x0000001c) +ED: ('p_memsz', 0x0000001c) +ED: ('p_align', 0x00000001) +ED: ), +ED: # Program Header 2 ED: (('p_type', 0x00000001) ED: ('p_flags', 0x00000005) ED: ('p_offset', 0x00000000) ED: ('p_vaddr', 0x00000000) ED: ('p_paddr', 0x00000000) -ED: ('p_filesz', 0x00000144) -ED: ('p_memsz', 0x00000144) +ED: ('p_filesz', 0x00000214) +ED: ('p_memsz', 0x00000214) ED: ('p_align', 0x00001000) ED: ), -ED: # Program Header 1 +ED: # Program Header 3 ED: (('p_type', 0x00000001) ED: ('p_flags', 0x00000006) ED: ('p_offset', 0x00001000) @@ -24,7 +44,7 @@ ED: ('p_filesz', 0x00000104) ED: ('p_memsz', 0x00000004) ED: ('p_align', 0x00001000) ED: ), -ED: # Program Header 2 +ED: # Program Header 4 ED: (('p_type', 0x00000001) ED: ('p_flags', 0x00000006) ED: ('p_offset', 0x00004000) @@ -34,5 +54,16 @@ ED: ('p_filesz', 0x00000004) ED: ('p_memsz', 0x00004008) ED: ('p_align', 0x00001000) ED: ), +ED: # Program Header 5 +ED: (('p_type', 0x00000002) +ED: ('p_flags', 0x00000004) +ED: ('p_offset', 0x000001e4) +ED: ('p_vaddr', 0x000001e4) +ED: ('p_paddr', 0x000001e4) +ED: ('p_filesz', 0x00000030) +ED: ('p_memsz', 0x00000030) +ED: ('p_align', 0x00000004) +ED: ), -X86_64: vaddr 0x0000000000400000 +X86_64: LOAD off 0x0000000000000000 +X86_64: LOAD off 0x0000000000001000 diff --git a/lld/test/elf/ppc.objtxt b/lld/test/elf/ppc.objtxt index d3b9344eeca..398e35143ab 100644 --- a/lld/test/elf/ppc.objtxt +++ b/lld/test/elf/ppc.objtxt @@ -1,4 +1,4 @@ -RUN: lld-core -reader ELF -writer ELF -arch ppc -endian big %p/Inputs/branch-test.ppc %p/Inputs/target-test.ppc -o %t1 +RUN: lld -flavor gnu -target powerpc %p/Inputs/branch-test.ppc %p/Inputs/target-test.ppc -o %t1 --noinhibit-exec RUN: elf-dump %t1 | FileCheck -check-prefix=ppc-elfdump %s ppc-elfdump: ('e_indent[EI_CLASS]', 0x01) diff --git a/lld/test/elf/quickdata.test b/lld/test/elf/quickdata.test index 5a121924907..4ec21a924cc 100644 --- a/lld/test/elf/quickdata.test +++ b/lld/test/elf/quickdata.test @@ -1,4 +1,5 @@ -RUN: lld-core -arch hexagon -reader ELF %p/Inputs/quickdata-test.elf-hexagon | FileCheck %s -check-prefix hexagon +RUN: lld -flavor gnu -target hexagon -emit-yaml %p/Inputs/quickdata-test.elf-hexagon \ +RUN: | FileCheck %s -check-prefix hexagon hexagon: - name: init hexagon: scope: global diff --git a/lld/test/elf/reloc.objtxt b/lld/test/elf/reloc.objtxt index 1afbcba076f..03c9b3f93fc 100644 --- a/lld/test/elf/reloc.objtxt +++ b/lld/test/elf/reloc.objtxt @@ -1,45 +1,10 @@ -RUN: lld-core -merge-strings=true -reader ELF %p/Inputs/reloc-test.elf-i386 | FileCheck %s -check-prefix ELF-i386 +RUN: lld -flavor gnu --merge-strings -r -emit-yaml %p/Inputs/reloc-test.elf-i386 | FileCheck %s -check-prefix ELF-i386 ELF-i386: defined-atoms: -ELF-i386: - ref-name: L000 +ELF-i386: - ref-name: [[STRNAME:[-a-zA-Z0-9_]+]] ELF-i386: type: constant ELF-i386: content: [ 68, 65, 6C, 6C, 6F, 20, 77, 6F, 72, 6C, 64, 00 ] ELF-i386: merge: by-content -ELF-i386: section-choice: custom-required -ELF-i386: section-name: .rodata.str1.1 -ELF-i386: - type: constant -ELF-i386: content: [ 00 ] -ELF-i386: merge: by-content -ELF-i386: section-choice: custom-required -ELF-i386: section-name: .comment -ELF-i386: - type: constant -ELF-i386: content: [ 47, 43, 43, 3A, 20, 28, 47, 4E, 55, 29, 20, 34, -ELF-i386: 2E, 37, 2E, 30, 00 ] -ELF-i386: merge: by-content -ELF-i386: section-choice: custom-required -ELF-i386: section-name: .comment -ELF-i386: - name: .text -ELF-i386: alignment: 2^2 -ELF-i386: section-choice: custom-required -ELF-i386: section-name: .text -ELF-i386: - name: .data -ELF-i386: type: data -ELF-i386: alignment: 2^2 -ELF-i386: section-choice: custom-required -ELF-i386: section-name: .data -ELF-i386: - name: .bss -ELF-i386: type: zero-fill -ELF-i386: alignment: 2^2 -ELF-i386: section-choice: custom-required -ELF-i386: section-name: .bss -ELF-i386: - name: .text.startup -ELF-i386: alignment: 2^4 -ELF-i386: section-choice: custom-required -ELF-i386: section-name: .text.startup -ELF-i386: references: -ELF-i386: - kind: layout-after -ELF-i386: offset: 0 -ELF-i386: target: main ELF-i386: - name: main ELF-i386: scope: global ELF-i386: content: [ 55, 89, E5, 83, E4, F0, 83, EC, 10, C7, 04, 24, @@ -49,34 +14,16 @@ ELF-i386: alignment: 2^4 ELF-i386: section-choice: custom-required ELF-i386: section-name: .text.startup ELF-i386: references: -ELF-i386: - kind: <unknown> +ELF-i386: - kind: R_X86_64_64 ELF-i386: offset: 12 -ELF-i386: target: L000 -ELF-i386: - kind: call32 +ELF-i386: target: [[STRNAME]] +ELF-i386: - kind: R_X86_64_PC32 ELF-i386: offset: 17 ELF-i386: target: puts ELF-i386: addend: 252 ELF-i386: - kind: layout-before ELF-i386: offset: 0 ELF-i386: target: .text.startup -ELF-i386: - name: .note.GNU-stack -ELF-i386: section-choice: custom-required -ELF-i386: section-name: .note.GNU-stack -ELF-i386: permissions: r-- -ELF-i386: - name: .eh_frame -ELF-i386: content: [ 14, 00, 00, 00, 00, 00, 00, 00, 01, 7A, 52, 00, -ELF-i386: 01, 7C, 08, 01, 1B, 0C, 04, 04, 88, 01, 00, 00, -ELF-i386: 1C, 00, 00, 00, 1C, 00, 00, 00, 00, 00, 00, 00, -ELF-i386: 19, 00, 00, 00, 00, 41, 0E, 08, 85, 02, 42, 0D, -ELF-i386: 05, 55, C5, 0C, 04, 04, 00, 00 ] -ELF-i386: alignment: 2^2 -ELF-i386: section-choice: custom-required -ELF-i386: section-name: .eh_frame -ELF-i386: permissions: r-- -ELF-i386: references: -ELF-i386: - kind: call32 -ELF-i386: offset: 32 -ELF-i386: target: .text.startup ELF-i386: undefined-atoms: ELF-i386: - name: puts ELF-i386: absolute-atoms: diff --git a/lld/test/elf/rodata.objtxt b/lld/test/elf/rodata.objtxt index e6dcfeef51e..af48210e1ac 100644 --- a/lld/test/elf/rodata.objtxt +++ b/lld/test/elf/rodata.objtxt @@ -1,9 +1,9 @@ -RUN: lld-core -reader ELF -writer ELF -o %t1 %p/Inputs/rodata-test.i386 + +RUN: lld -flavor gnu -target i386 -o %t1 %p/Inputs/rodata-test.i386 --noinhibit-exec RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=i386 %s -RUN: lld-core -arch hexagon -reader ELF -writer ELF -o %t2 \ -RUN: %p/Inputs/rodata-test.hexagon +RUN: lld -flavor gnu -target hexagon -o %t2 %p/Inputs/rodata-test.hexagon --noinhibit-exec RUN: llvm-objdump -section-headers %t2 | FileCheck -check-prefix=hexagon %s -i386: 1 .rodata 00000004 0000000000000074 DATA +i386: .rodata 00000004 0000000000000111 DATA -hexagon: 1 .rodata 00000004 0000000000000074 DATA +hexagon: .rodata 00000004 0000000000000111 DATA diff --git a/lld/test/elf/rodata.test b/lld/test/elf/rodata.test index 9195484114c..dfe6985c073 100644 --- a/lld/test/elf/rodata.test +++ b/lld/test/elf/rodata.test @@ -1,5 +1,5 @@ -RUN: lld -core -target x86_64-linux -output=%t %p/Inputs/constdata.x86-64 \ -RUN: -output-type=static +RUN: lld -flavor gnu -target x86_64-linux -o %t %p/Inputs/constdata.x86-64 \ +RUN: -static -e _start RUN: llvm-objdump -s %t | FileCheck %s CHECK: Hellooooooooo diff --git a/lld/test/elf/sections.objtxt b/lld/test/elf/sections.objtxt index 7f687aa011b..784d8610855 100644 --- a/lld/test/elf/sections.objtxt +++ b/lld/test/elf/sections.objtxt @@ -1,4 +1,5 @@ -RUN: lld-core -reader ELF -writer ELF -o %t1 %p/Inputs/section-test.i386 +RUN: lld -flavor gnu -target i386 -o %t1 %p/Inputs/section-test.i386 \ +RUN: -static -e baz RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=OBJDUMP %s RUN: llvm-readobj -h -s -t %t1 | FileCheck -check-prefix=READOBJ %s diff --git a/lld/test/elf/symbols.objtxt b/lld/test/elf/symbols.objtxt index 18910ec870f..3fcc7841160 100644 --- a/lld/test/elf/symbols.objtxt +++ b/lld/test/elf/symbols.objtxt @@ -14,14 +14,13 @@ #} # -RUN: lld-core -reader ELF %p/Inputs/writersyms.o -writer ELF -o %t1 +RUN: lld -flavor gnu -target i386 -e main %p/Inputs/writersyms.o -o %t1 RUN: llvm-nm -n %t1 | FileCheck -check-prefix CHECKSYMS %s CHECKSYMS: 00000000 a 1.c -CHECKSYMS: 00000074 T main +CHECKSYMS: 00000114 T main CHECKSYMS: 00001000 A __bss_start CHECKSYMS: 00001000 B a CHECKSYMS: 00001004 A __bss_end CHECKSYMS: 00001004 A _end CHECKSYMS: 00001004 A end -CHECKSYMS: U _start diff --git a/lld/test/elf/tls.test b/lld/test/elf/tls.test index c3efdca0aa3..d18c6fccfac 100644 --- a/lld/test/elf/tls.test +++ b/lld/test/elf/tls.test @@ -1,31 +1,33 @@ -RUN: lld -core -target x86_64-linux %p/Inputs/tls.x86-64 -output=- \ -RUN: -noinhibit-exec -entry=main -emit-yaml -output-type=static \ -RUN: | FileCheck %s -check-prefix=YAML +RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/tls.x86-64 -static \ +RUN: -emit-yaml --noinhibit-exec | FileCheck %s -check-prefix=YAML -RUN: lld -core -target x86_64-linux %p/Inputs/tls.x86-64 -output=%t \ -RUN: -noinhibit-exec -entry=main -output-type=static && llvm-objdump -d %t \ -RUN: | FileCheck %s +RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/tls.x86-64 -output=%t \ +RUN: --noinhibit-exec -e main -static && llvm-objdump -d %t | FileCheck %s // Verify that the TLS accesses have the correct offsets. -YAML: type: got -YAML: kind: R_X86_64_TPOFF64 -YAML: target: tls2 - -YAML: name: main -YAML: kind: R_X86_64_TPOFF32 -YAML: offset: 9 -YAML: target: tls1 -YAML: kind: R_X86_64_TPOFF32 -YAML: offset: 17 -YAML: target: tls0 -YAML: kind: R_X86_64_TPOFF32 -YAML: offset: 25 -YAML: target: tls2 - -YAML: name: GOTTPOFF -YAML: kind: R_X86_64_PC32 -YAML: target: [[GOTNAME:[a-zA-Z0-9_]+]] +YAML: defined-atoms: +YAML: type: got +YAML: references: +YAML: kind: R_X86_64_TPOFF64 +YAML: target: tls2 + +YAML: name: main +YAML: references: +YAML: kind: R_X86_64_TPOFF32 +YAML: offset: 9 +YAML: target: tls1 +YAML: kind: R_X86_64_TPOFF32 +YAML: offset: 17 +YAML: target: tls0 +YAML: kind: R_X86_64_TPOFF32 +YAML: offset: 25 +YAML: target: tls2 + +YAML: name: GOTTPOFF +YAML: kind: R_X86_64_PC32 +YAML: target: [[GOTNAME:[a-zA-Z0-9_]+]] + // main CHECK: addl %fs:-4 diff --git a/lld/test/elf/x86-64-dynamic-relocs.test b/lld/test/elf/x86-64-dynamic-relocs.test index c1ddad72bb2..ee86ab2ac87 100644 --- a/lld/test/elf/x86-64-dynamic-relocs.test +++ b/lld/test/elf/x86-64-dynamic-relocs.test @@ -1,5 +1,5 @@ -RUN: lld -core -target x86_64-linux %p/Inputs/relocs-dynamic.x86-64 -emit-yaml \ -RUN: -output=- -noinhibit-exec -output-type=dynamic | FileCheck %s +RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/relocs-dynamic.x86-64 \ +RUN: -emit-yaml --noinhibit-exec | FileCheck %s path: <linker-internal> defined-atoms: diff --git a/lld/test/elf/x86-64-dynamic.test b/lld/test/elf/x86-64-dynamic.test index 21688b4bffe..5a3b02c74e4 100644 --- a/lld/test/elf/x86-64-dynamic.test +++ b/lld/test/elf/x86-64-dynamic.test @@ -1,47 +1,10 @@ -RUN: lld -core -target x86_64-linux %p/Inputs/use-shared.x86-64 \ -RUN: %p/Inputs/shared.so-x86-64 -emit-yaml -output=%t1 -noinhibit-exec \ -RUN: -output-type=dynamic +RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/use-shared.x86-64 \ +RUN: %p/Inputs/shared.so-x86-64 -emit-yaml -o %t1 --noinhibit-exec RUN: FileCheck %s < %t1 // Don't check the GOT and PLT names as they are only present in assert builds. - - name: __got_null -CHECK: type: got -CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ] -CHECK: alignment: 2^3 -CHECK: section-choice: custom-required -CHECK: section-name: .got.plt -CHECK: permissions: rw- - - name: __got0 -CHECK: type: got -CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ] -CHECK: alignment: 2^3 -CHECK: section-choice: custom-required -CHECK: section-name: .got.plt -CHECK: permissions: rw- - - name: __got1 -CHECK: type: got -CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ] -CHECK: alignment: 2^3 -CHECK: section-choice: custom-required -CHECK: section-name: .got.plt -CHECK: permissions: rw- - - name: __got_foo -CHECK: type: got -CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ] -CHECK: alignment: 2^3 -CHECK: section-choice: custom-required -CHECK: section-name: .got.plt -CHECK: permissions: rw- -CHECK: references: -CHECK: - kind: R_X86_64_JUMP_SLOT -CHECK: offset: 0 -CHECK: target: foo -CHECK: - kind: R_X86_64_64 -CHECK: offset: 0 - target: __plt_foo -CHECK: addend: 6 - - name: __got_i +CHECK: name: [[GOTNAME:[-a-zA-Z0-9_]+]] CHECK: type: got CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ] CHECK: section-choice: custom-required @@ -57,11 +20,11 @@ CHECK: scope: global CHECK: references: CHECK: - kind: R_X86_64_PC32 CHECK: offset: 18 - target: __plt_foo + target: [[PLTNAME:[-a-zA-Z0-9_]+]] CHECK: addend: -4 -CHECK: - kind: R_X86_64_PC32 +CHECK: - kind: R_X86_64_PC32 CHECK: offset: 25 - target: __got_i + target: [[GOTNAME]] CHECK: addend: -4 - name: .PLT0 @@ -80,7 +43,7 @@ CHECK: - kind: R_X86_64_PC32 CHECK: offset: 8 target: __got1 CHECK: addend: -4 - - name: __plt_foo + - name: [[PLTNAME]] CHECK: type: stub CHECK: content: [ FF, 25, 00, 00, 00, 00, 68, 00, 00, 00, 00, E9, CHECK: 00, 00, 00, 00 ] @@ -100,6 +63,7 @@ CHECK: offset: 12 target: .PLT0 CHECK: addend: -4 + CHECK:shared-library-atoms: CHECK: - name: foo CHECK: load-name: shared.so-x86-64 diff --git a/lld/test/elf/x86.objtxt b/lld/test/elf/x86.objtxt index 386da17bf64..3a7a7fe2363 100644 --- a/lld/test/elf/x86.objtxt +++ b/lld/test/elf/x86.objtxt @@ -18,13 +18,13 @@ # # Assembled with: "as --32" -RUN: lld-core -reader ELF -arch=i386 %p/Inputs/reloc-xb.x86 %p/Inputs/reloc-xt.x86 | FileCheck %s -check-prefix x86-yaml +RUN: lld -flavor gnu -target i386 -e back -emit-yaml %p/Inputs/reloc-xb.x86 %p/Inputs/reloc-xt.x86 | FileCheck %s -check-prefix x86-yaml x86-yaml: - name: back x86-yaml: scope: global x86-yaml: content: [ E8, FC, FF, FF, FF ] x86-yaml: references: -x86-yaml: - kind: call32 +x86-yaml: - kind: R_386_PC32 x86-yaml: offset: 1 x86-yaml: target: target @@ -32,7 +32,7 @@ x86-yaml: - name: target x86-yaml: scope: global x86-yaml: content: [ E8, FC, FF, FF, FF ] x86-yaml: references: -x86-yaml: - kind: call32 +x86-yaml: - kind: R_386_PC32 x86-yaml: offset: 1 x86-yaml: target: back diff --git a/lld/test/elf/x86_64-kinds.test b/lld/test/elf/x86_64-kinds.test index 41de35be17a..33e24b66781 100644 --- a/lld/test/elf/x86_64-kinds.test +++ b/lld/test/elf/x86_64-kinds.test @@ -1,8 +1,8 @@ -RUN: lld -core -target x86_64-linux -output=%t1 %p/Inputs/relocs.x86-64 \ -RUN: -output-type=static +RUN: lld -flavor gnu -target x86_64-linux -o %t1 %p/Inputs/relocs.x86-64 \ +RUN: -e _start -static RUN: llvm-objdump -d %t1 | FileCheck %s -check-prefix=RELOCS -RUN: lld -core -target x86_64-linux -output=- -emit-yaml -output-type=static \ +RUN: lld -flavor gnu -target x86_64-linux -emit-yaml -e _start -static \ RUN: %p/Inputs/relocs.x86-64 | FileCheck %s -check-prefix=X86_64 RELOCS: ELF64-x86-64 diff --git a/lld/test/empty.objtxt b/lld/test/empty.objtxt index 92427ff7ba3..a78a3bfbd5c 100644 --- a/lld/test/empty.objtxt +++ b/lld/test/empty.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Test that an empty file is handled properly diff --git a/lld/test/error-atom-attribute.objtxt b/lld/test/error-atom-attribute.objtxt index 9355a18d045..dfcf176a874 100644 --- a/lld/test/error-atom-attribute.objtxt +++ b/lld/test/error-atom-attribute.objtxt @@ -1,4 +1,4 @@ -# RUN: not lld-core %s 2> %t.err +# RUN: not lld -core %s 2> %t.err # RUN: FileCheck < %t.err %s # diff --git a/lld/test/error-atom-content-byte-value.objtxt b/lld/test/error-atom-content-byte-value.objtxt index 42fe53376b0..601161ee74d 100644 --- a/lld/test/error-atom-content-byte-value.objtxt +++ b/lld/test/error-atom-content-byte-value.objtxt @@ -1,4 +1,4 @@ -# RUN: not lld-core %s 2> %t.err +# RUN: not lld -core %s 2> %t.err # RUN: FileCheck < %t.err %s # diff --git a/lld/test/error-atom-content-bytes.objtxt b/lld/test/error-atom-content-bytes.objtxt index f887da56953..49ada258c99 100644 --- a/lld/test/error-atom-content-bytes.objtxt +++ b/lld/test/error-atom-content-bytes.objtxt @@ -1,4 +1,4 @@ -# RUN: not lld-core %s 2> %t.err +# RUN: not lld -core %s 2> %t.err # RUN: FileCheck < %t.err %s # diff --git a/lld/test/error-atom-type.objtxt b/lld/test/error-atom-type.objtxt index aae1ffff862..533df5704f6 100644 --- a/lld/test/error-atom-type.objtxt +++ b/lld/test/error-atom-type.objtxt @@ -1,4 +1,4 @@ -# RUN: not lld-core %s 2> %t.err +# RUN: not lld -core %s 2> %t.err # RUN: FileCheck < %t.err %s # diff --git a/lld/test/error-atom-undefined-wrong-attribue.objtxt b/lld/test/error-atom-undefined-wrong-attribue.objtxt index b5a117fac7f..694b3c7915a 100644 --- a/lld/test/error-atom-undefined-wrong-attribue.objtxt +++ b/lld/test/error-atom-undefined-wrong-attribue.objtxt @@ -1,4 +1,4 @@ -# RUN: not lld-core %s 2> %t.err +# RUN: not lld -core %s 2> %t.err # RUN: FileCheck < %t.err %s # diff --git a/lld/test/error-file-attribute.objtxt b/lld/test/error-file-attribute.objtxt index 3a3997f0d63..f189c596f26 100644 --- a/lld/test/error-file-attribute.objtxt +++ b/lld/test/error-file-attribute.objtxt @@ -1,4 +1,4 @@ -# RUN: not lld-core %s 2> %t.err +# RUN: not lld -core %s 2> %t.err # RUN: FileCheck < %t.err %s # diff --git a/lld/test/error-fixup-attribute.objtxt b/lld/test/error-fixup-attribute.objtxt index 560ef96a77e..f856e21c1f8 100644 --- a/lld/test/error-fixup-attribute.objtxt +++ b/lld/test/error-fixup-attribute.objtxt @@ -1,4 +1,4 @@ -# RUN: not lld-core %s 2> %t.err +# RUN: not lld -core %s 2> %t.err # RUN: FileCheck < %t.err %s # @@ -11,7 +11,7 @@ defined-atoms: scope: hidden references: - offset: 3 - kind: 3 + kind: pcrel32 weasel: bar addend: 100 diff --git a/lld/test/error-fixup-target.objtxt b/lld/test/error-fixup-target.objtxt index f6c37fb8de7..c89f8db5fa6 100644 --- a/lld/test/error-fixup-target.objtxt +++ b/lld/test/error-fixup-target.objtxt @@ -1,4 +1,4 @@ -# RUN: not lld-core %s 2> %t.err +# RUN: not lld -core %s 2> %t.err # RUN: FileCheck < %t.err %s # @@ -11,10 +11,10 @@ defined-atoms: scope: hidden references: - offset: 3 - kind: 3 + kind: pcrel32 target: bar - offset: 5 - kind: 3 + kind: pcrel32 target: baz undefined-atoms: diff --git a/lld/test/fixups-addend.objtxt b/lld/test/fixups-addend.objtxt index c812f584ef7..24af91ffa7c 100644 --- a/lld/test/fixups-addend.objtxt +++ b/lld/test/fixups-addend.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Test addends in references @@ -12,11 +12,11 @@ defined-atoms: 48, 8D, 3D, 00, 00, 00, 00 ] references: - offset: 3 - kind: 3 + kind: pcrel32 target: bar addend: 100 - offset: 10 - kind: 3 + kind: pcrel32 target: bar addend: -50 @@ -26,11 +26,11 @@ defined-atoms: 48, 8D, 3D, 00, 00, 00, 00 ] references: - offset: 3 - kind: 3 + kind: pcrel32 target: bar addend: 8000000000 - offset: 10 - kind: 3 + kind: pcrel32 target: bar addend: -50 diff --git a/lld/test/fixups-dup-named.objtxt b/lld/test/fixups-dup-named.objtxt index e66297a2432..38ca56ebca5 100644 --- a/lld/test/fixups-dup-named.objtxt +++ b/lld/test/fixups-dup-named.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Test references referencing multiple atoms that have the same name @@ -11,10 +11,10 @@ defined-atoms: content: [ E8, 00, 00, 00, 00, E8, 00, 00, 00, 00 ] references: - offset: 1 - kind: 3 + kind: pcrel32 target: bar_1 - offset: 6 - kind: 3 + kind: pcrel32 target: bar_2 - name: bar diff --git a/lld/test/fixups-named.objtxt b/lld/test/fixups-named.objtxt index 61d16ebf71d..7eebb06e372 100644 --- a/lld/test/fixups-named.objtxt +++ b/lld/test/fixups-named.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Test references to simple named atoms @@ -12,10 +12,10 @@ defined-atoms: E8, 00, 00, 00, 00 ] references: - offset: 1 - kind: 3 + kind: pcrel32 target: bar - offset: 6 - kind: 3 + kind: pcrel32 target: baz - name: baz diff --git a/lld/test/fixups-unnamed.objtxt b/lld/test/fixups-unnamed.objtxt index 2c3d7aa09d9..3ca0b30fdcd 100644 --- a/lld/test/fixups-unnamed.objtxt +++ b/lld/test/fixups-unnamed.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Test references to unnamed atoms @@ -12,10 +12,10 @@ defined-atoms: 48, 8D, 3D, 00, 00, 00, 00 ] references: - offset: 3 - kind: 3 + kind: pcrel32 target: LC1 - offset: 10 - kind: 3 + kind: pcrel32 target: LC2 diff --git a/lld/test/ingroup-test-big.objtxt b/lld/test/ingroup-test-big.objtxt index 09ba08e7474..d0b2c46d770 100644 --- a/lld/test/ingroup-test-big.objtxt +++ b/lld/test/ingroup-test-big.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core -layout-pass=true %s | FileCheck %s -check-prefix=CHKORDER +# RUN: lld -core --add-pass layout %s | FileCheck %s -check-prefix=CHKORDER --- defined-atoms: diff --git a/lld/test/ingroup-test-loop.objtxt b/lld/test/ingroup-test-loop.objtxt index 2bdcc624a61..7bed173f35b 100644 --- a/lld/test/ingroup-test-loop.objtxt +++ b/lld/test/ingroup-test-loop.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core -layout-pass=true %s | FileCheck %s -check-prefix=CHKORDER +# RUN: lld -core --add-pass layout %s | FileCheck %s -check-prefix=CHKORDER --- defined-atoms: diff --git a/lld/test/ingroup-test-with-layout-after.objtxt b/lld/test/ingroup-test-with-layout-after.objtxt index e2555cb4661..6a8bac28a6c 100644 --- a/lld/test/ingroup-test-with-layout-after.objtxt +++ b/lld/test/ingroup-test-with-layout-after.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core -layout-pass=true %s | FileCheck %s -check-prefix=CHKORDER +# RUN: lld -core --add-pass layout %s | FileCheck %s -check-prefix=CHKORDER --- defined-atoms: diff --git a/lld/test/ingroup-test.objtxt b/lld/test/ingroup-test.objtxt index b4dd32becb4..6ebbb815485 100644 --- a/lld/test/ingroup-test.objtxt +++ b/lld/test/ingroup-test.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core -layout-pass=true %s | FileCheck %s -check-prefix=CHKORDER +# RUN: lld -core --add-pass layout %s | FileCheck %s -check-prefix=CHKORDER --- defined-atoms: diff --git a/lld/test/inline-coalesce.objtxt b/lld/test/inline-coalesce.objtxt index 218967e7d08..6df9d0e7a49 100644 --- a/lld/test/inline-coalesce.objtxt +++ b/lld/test/inline-coalesce.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Test that non-inlined inlined functions are silently coalesced diff --git a/lld/test/layoutafter-test.objtxt b/lld/test/layoutafter-test.objtxt index 3ce3fcb567e..7d5ca3ac5d6 100644 --- a/lld/test/layoutafter-test.objtxt +++ b/lld/test/layoutafter-test.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core -layout-pass=true %s | FileCheck %s -check-prefix=CHKORDER +# RUN: lld -core -layout-pass=true %s | FileCheck %s -check-prefix=CHKORDER --- defined-atoms: diff --git a/lld/test/layoutbefore-test.objtxt b/lld/test/layoutbefore-test.objtxt index d5aa7608092..ed1afe76119 100644 --- a/lld/test/layoutbefore-test.objtxt +++ b/lld/test/layoutbefore-test.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core -layout-pass=true %s | FileCheck %s -check-prefix=CHKORDER +# RUN: lld -core --add-pass layout %s | FileCheck %s -check-prefix=CHKORDER --- defined-atoms: diff --git a/lld/test/multiple-def-error.objtxt b/lld/test/multiple-def-error.objtxt index 62281e889d1..62defbd52bc 100644 --- a/lld/test/multiple-def-error.objtxt +++ b/lld/test/multiple-def-error.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s 2>&1 | FileCheck %s +# RUN: lld -core %s 2>&1 | FileCheck %s # # Test that multiple definitions cause an error diff --git a/lld/test/pass-got-basic.objtxt b/lld/test/pass-got-basic.objtxt index 45ba1550cfe..6f0d4f2bcec 100644 --- a/lld/test/pass-got-basic.objtxt +++ b/lld/test/pass-got-basic.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s -got-pass | FileCheck %s +# RUN: lld -core %s --add-pass GOT | FileCheck %s # # Test that GOT pass instantiates GOT entires and alters references diff --git a/lld/test/pass-stubs-basic.objtxt b/lld/test/pass-stubs-basic.objtxt index 29279f29e78..8203755fc85 100644 --- a/lld/test/pass-stubs-basic.objtxt +++ b/lld/test/pass-stubs-basic.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s -stubs-pass | FileCheck %s +# RUN: lld -core %s --add-pass stubs | FileCheck %s # # Test that stubs pass adds stubs and rebinds call sites to the stub diff --git a/lld/test/permissions.objtxt b/lld/test/permissions.objtxt index b17c50ef223..fd07f29a6ff 100644 --- a/lld/test/permissions.objtxt +++ b/lld/test/permissions.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Test permissions for known content types are implicit, but can be overridden. diff --git a/lld/test/section-position.objtxt b/lld/test/section-position.objtxt index 4a7c830e111..675c1edc0d5 100644 --- a/lld/test/section-position.objtxt +++ b/lld/test/section-position.objtxt @@ -1,5 +1,5 @@ -# RUN: lld-core -layout-pass=true %s | FileCheck %s -check-prefix=CHKORDER -# RUN: lld-core -layout-pass=false %s | FileCheck %s -check-prefix=CHKUNORD +# RUN: lld -core --add-pass layout %s | FileCheck %s -check-prefix=CHKORDER +# RUN: lld -core %s | FileCheck %s -check-prefix=CHKUNORD # # Test that atoms with section position requirements are sorted properly. diff --git a/lld/test/shared-library-basic.objtxt b/lld/test/shared-library-basic.objtxt index bcdf04d3176..be76d0e4162 100644 --- a/lld/test/shared-library-basic.objtxt +++ b/lld/test/shared-library-basic.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Test that shared-library symbols are parsed and preserved diff --git a/lld/test/shared-library-coalesce.objtxt b/lld/test/shared-library-coalesce.objtxt index 04102487919..5c860ccc043 100644 --- a/lld/test/shared-library-coalesce.objtxt +++ b/lld/test/shared-library-coalesce.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Test that shared library symbols preserve their attributes and merge properly diff --git a/lld/test/tent-merge.objtxt b/lld/test/tent-merge.objtxt index 18d6f56662a..8ad46d40ae1 100644 --- a/lld/test/tent-merge.objtxt +++ b/lld/test/tent-merge.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Test that a tentative definition and a regular global are merged into diff --git a/lld/test/undef-coalesce-error.objtxt b/lld/test/undef-coalesce-error.objtxt index bbf6d1db765..7c82f1a8346 100644 --- a/lld/test/undef-coalesce-error.objtxt +++ b/lld/test/undef-coalesce-error.objtxt @@ -1,6 +1,6 @@ -# RUN: not lld-core -undefines-are-errors %s 2> %t.err +# RUN: not lld -core --undefines-are-errors %s 2> %t.err # RUN: FileCheck -check-prefix=CHECKERR < %t.err %s -# RUN: lld-core -undefines-are-errors=false %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Test that -undefines-are-errors triggers and error diff --git a/lld/test/undef-coalesce.objtxt b/lld/test/undef-coalesce.objtxt index 08e1cf80a53..8a9f502ab1a 100644 --- a/lld/test/undef-coalesce.objtxt +++ b/lld/test/undef-coalesce.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Test that undefined symbols are coalesced with other undefined symbols diff --git a/lld/test/undef-weak-coalesce.objtxt b/lld/test/undef-weak-coalesce.objtxt index 7a324e0166d..daf6ee0eb87 100644 --- a/lld/test/undef-weak-coalesce.objtxt +++ b/lld/test/undef-weak-coalesce.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Test that undefined symbols preserve their attributes and merge properly diff --git a/lld/test/weak-coalesce.objtxt b/lld/test/weak-coalesce.objtxt index fdeae89a386..550c10cfa46 100644 --- a/lld/test/weak-coalesce.objtxt +++ b/lld/test/weak-coalesce.objtxt @@ -1,4 +1,4 @@ -# RUN: lld-core %s | FileCheck %s +# RUN: lld -core %s | FileCheck %s # # Test that weak definitions are coalesced away in favor of a regular definition diff --git a/lld/tools/CMakeLists.txt b/lld/tools/CMakeLists.txt index 4880ad1021f..c4b58cdda97 100644 --- a/lld/tools/CMakeLists.txt +++ b/lld/tools/CMakeLists.txt @@ -1,2 +1 @@ add_subdirectory(lld) -add_subdirectory(lld-core) diff --git a/lld/tools/lld-core/CMakeLists.txt b/lld/tools/lld-core/CMakeLists.txt index f83d34afe98..8b8a84ab92f 100644 --- a/lld/tools/lld-core/CMakeLists.txt +++ b/lld/tools/lld-core/CMakeLists.txt @@ -12,6 +12,7 @@ target_link_libraries(lld-core lldReaderWriter lldYAML lldCore + lldDriver LLVMObject LLVMSupport ) diff --git a/lld/tools/lld-core/lld-core.cpp b/lld/tools/lld-core/lld-core.cpp index ddc8ec11471..22388ef36bd 100644 --- a/lld/tools/lld-core/lld-core.cpp +++ b/lld/tools/lld-core/lld-core.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "lld/Core/Atom.h" -#include "lld/Core/LinkerOptions.h" #include "lld/Core/LLVM.h" #include "lld/Core/Pass.h" #include "lld/Core/PassManager.h" @@ -101,7 +100,7 @@ cmdLineEntryPoint("entry", enum WriteChoice { - writeYAML, writeMachO, writePECOFF, writeELF + writeYAML, writePECOFF, writeELF }; llvm::cl::opt<WriteChoice> @@ -109,7 +108,6 @@ writeSelected("writer", llvm::cl::desc("Select writer"), llvm::cl::values( clEnumValN(writeYAML, "YAML", "link assuming YAML format"), - clEnumValN(writeMachO, "mach-o", "link as darwin would"), clEnumValN(writePECOFF, "PECOFF", "link as windows would"), clEnumValN(writeELF, "ELF", "link as linux would"), clEnumValEnd), @@ -162,10 +160,12 @@ llvm::cl::opt<endianChoice> endianSelected( class TestingTargetInfo : public TargetInfo { public: - TestingTargetInfo(const LinkerOptions &lo, bool stubs, bool got, bool layout) - : TargetInfo(lo), _doStubs(stubs), _doGOT(got), _doLayout(layout) { + TestingTargetInfo(bool stubs, bool got, bool layout) + : _doStubs(stubs), _doGOT(got), _doLayout(layout) { } + llvm::Triple getTriple() const { return llvm::Triple("x86_64"); } + virtual uint64_t getPageSize() const { return 0x1000; } virtual void addPasses(PassManager &pm) const { @@ -225,38 +225,37 @@ int main(int argc, char *argv[]) { // if no output path specified, write to stdout if (cmdLineOutputFilePath.empty()) cmdLineOutputFilePath.assign("-"); - - LinkerOptions lo; +#if 0 + ELFLinkerOptions lo; lo._noInhibitExec = !cmdLineUndefinesIsError; lo._searchArchivesToOverrideTentativeDefinitions = cmdLineCommonsSearchArchives; lo._deadStrip = cmdLineDeadStrip; lo._globalsAreDeadStripRoots = cmdLineGlobalsNotDeadStrip; lo._forceLoadArchives = cmdLineForceLoad; - lo._outputKind = OutputKind::StaticExecutable; lo._entrySymbol = cmdLineEntryPoint; lo._mergeCommonStrings = cmdLineDoMergeStrings; +#endif + llvm::Triple targetTriple; switch (archSelected) { case i386: - lo._target = "i386"; + targetTriple = llvm::Triple("i386"); break; case x86_64: - lo._target = "x86_64"; + targetTriple = llvm::Triple("x86_64"); break; case hexagon: - lo._target = "hexagon"; + targetTriple = llvm::Triple("hexagon"); break; case ppc: - lo._target = "powerpc"; + targetTriple = llvm::Triple("powerpc"); break; } - - TestingTargetInfo tti(lo, cmdLineDoStubsPass, cmdLineDoGotPass, + TestingTargetInfo tti(cmdLineDoStubsPass, cmdLineDoGotPass, cmdLineDoLayoutPass); - std::unique_ptr<ELFTargetInfo> eti = ELFTargetInfo::create(lo); - std::unique_ptr<MachOTargetInfo> mti = MachOTargetInfo::create(lo); + std::unique_ptr<ELFTargetInfo> eti = ELFTargetInfo::create(targetTriple.getArch()); std::unique_ptr<Writer> writer; const TargetInfo *ti = 0; switch ( writeSelected ) { @@ -264,10 +263,6 @@ int main(int argc, char *argv[]) { writer = createWriterYAML(tti); ti = &tti; break; - case writeMachO: - writer = createWriterMachO(*mti); - ti = mti.get(); - break; case writePECOFF: writer = createWriterPECOFF(tti); ti = &tti; diff --git a/lld/tools/lld/lld.cpp b/lld/tools/lld/lld.cpp index 70c1ac8c2a5..6f7a9337ed6 100644 --- a/lld/tools/lld/lld.cpp +++ b/lld/tools/lld/lld.cpp @@ -16,136 +16,25 @@ #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) { +/// Universal linker main(). This linker eumulates the gnu, darwin, or +/// windows linker based on the tool name or if the first argument is +/// -flavor. +int main(int argc, const char *argv[]) { + // Standard set up, so program fails gracefully. 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; + llvm::PrettyStackTraceProgram stackPrinter(argc, argv); + llvm::llvm_shutdown_obj shutdown; - 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 *>(argv + 1, argv + argc)); - } else { - coreArgs = parseCoreArgs( - llvm::ArrayRef<const char *>(argv + 1, argv + argc)); - } - - if (!coreArgs) + if (UniversalDriver::link(argc, argv)) return 1; - - LinkerOptions lo(generateOptions(*coreArgs)); - - if (lo._outputCommands) { - for (auto arg : *coreArgs) { - llvm::outs() << arg->getAsString(*coreArgs) << " "; - } - llvm::outs() << "\n"; - - // Don't do the link if we are just outputting commands. + else return 0; - } - - LinkerInvocation invocation(lo); - invocation(); - - return 0; } |