From e44104b001aab770b17bbbb00f5c676d1fe830e3 Mon Sep 17 00:00:00 2001 From: Shankar Easwaran Date: Wed, 21 Aug 2013 22:57:10 +0000 Subject: [PATCH] add InputGraph functionality llvm-svn: 188958 --- lld/include/lld/Core/File.h | 3 + lld/include/lld/Core/LinkingContext.h | 9 +- lld/include/lld/Driver/CoreInputGraph.h | 52 ++ lld/include/lld/Driver/DarwinInputGraph.h | 53 ++ lld/include/lld/Driver/Driver.h | 7 +- lld/include/lld/Driver/GnuLDInputGraph.h | 103 ++++ lld/include/lld/Driver/InputGraph.h | 245 ++++++++++ lld/include/lld/Driver/LinkerInput.h | 28 +- lld/include/lld/Driver/WinLinkInputGraph.h | 80 +++ .../lld/ReaderWriter/ELFLinkingContext.h | 10 +- .../lld/ReaderWriter}/MachOFormat.hpp | 220 ++++----- .../lld/ReaderWriter/PECOFFLinkingContext.h | 14 +- lld/lib/Driver/CMakeLists.txt | 1 + lld/lib/Driver/CoreDriver.cpp | 145 +++--- lld/lib/Driver/DarwinLdDriver.cpp | 110 +++-- lld/lib/Driver/Driver.cpp | 22 +- lld/lib/Driver/GnuLdDriver.cpp | 275 ++++++----- lld/lib/Driver/InputGraph.cpp | 56 +++ lld/lib/Driver/LDOptions.td | 14 +- lld/lib/Driver/WinLinkDriver.cpp | 461 ++++++++---------- .../ReaderWriter/ELF/ELFLinkingContext.cpp | 21 +- .../MachO/MachOLinkingContext.cpp | 7 +- lld/lib/ReaderWriter/MachO/WriterMachO.cpp | 7 +- .../PECOFF/PECOFFLinkingContext.cpp | 50 +- lld/lib/ReaderWriter/ReaderLinkerScript.cpp | 2 +- lld/test/Driver/libsearch-inputGraph.test | 34 ++ lld/test/elf/X86_64/nmagic.test | 2 +- lld/test/elf/X86_64/omagic.test | 2 +- lld/test/elf/archive-elf-forceload.objtxt | 2 +- .../DriverTests/DarwinLdDriverTest.cpp | 2 +- lld/unittests/DriverTests/DriverTest.h | 7 +- 31 files changed, 1333 insertions(+), 711 deletions(-) create mode 100644 lld/include/lld/Driver/CoreInputGraph.h create mode 100644 lld/include/lld/Driver/DarwinInputGraph.h create mode 100644 lld/include/lld/Driver/GnuLDInputGraph.h create mode 100644 lld/include/lld/Driver/InputGraph.h create mode 100644 lld/include/lld/Driver/WinLinkInputGraph.h rename lld/{lib/ReaderWriter/MachO => include/lld/ReaderWriter}/MachOFormat.hpp (84%) create mode 100644 lld/lib/Driver/InputGraph.cpp create mode 100644 lld/test/Driver/libsearch-inputGraph.test diff --git a/lld/include/lld/Core/File.h b/lld/include/lld/Core/File.h index 0ac16f0f61a3..dcb1f6a5c830 100644 --- a/lld/include/lld/Core/File.h +++ b/lld/include/lld/Core/File.h @@ -23,6 +23,9 @@ #include namespace lld { + +class LinkingContext; + /// Every Atom is owned by some File. A common scenario is for a single /// object file (.o) to be parsed by some reader and produce a single /// File object that represents the content of that object file. diff --git a/lld/include/lld/Core/LinkingContext.h b/lld/include/lld/Core/LinkingContext.h index 6a15add00aa0..3ae0ec5abbf0 100644 --- a/lld/include/lld/Core/LinkingContext.h +++ b/lld/include/lld/Core/LinkingContext.h @@ -15,6 +15,7 @@ #include "lld/Core/range.h" #include "lld/Core/Reference.h" +#include "lld/Driver/InputGraph.h" #include "lld/Driver/LinkerInput.h" #include "lld/ReaderWriter/Reader.h" @@ -33,6 +34,7 @@ class PassManager; class File; class Writer; class InputFiles; +class InputGraph; /// \brief The LinkingContext class encapsulates "what and how" to link. /// @@ -173,7 +175,7 @@ public: const std::vector &inputFiles() const { return _inputFiles; } /// @} - /// \name Methods used by Drivers to configure LinkingContext + /// \name Methods used by Drivers to configure TargetInfo /// @{ void setOutputPath(StringRef str) { _outputPath = str; } void setEntrySymbolName(StringRef name) { _entrySymbolName = name; } @@ -207,6 +209,10 @@ public: _inputFiles.emplace_back(LinkerInput(std::move(buffer))); } void appendLLVMOption(const char *opt) { _llvmOptions.push_back(opt); } + virtual void setInputGraph(std::unique_ptr inputGraph) { + _inputGraph = std::move(inputGraph); + } + virtual InputGraph &inputGraph() const { return *_inputGraph; } /// This method adds undefined symbols specified by the -u option to the /// to the list of undefined symbols known to the linker. This option @@ -324,6 +330,7 @@ protected: std::vector _llvmOptions; std::unique_ptr _yamlReader; StringRefVector _initialUndefinedSymbols; + std::unique_ptr _inputGraph; private: /// Validate the subclass bits. Only called by validate. diff --git a/lld/include/lld/Driver/CoreInputGraph.h b/lld/include/lld/Driver/CoreInputGraph.h new file mode 100644 index 000000000000..a89f3b700ee5 --- /dev/null +++ b/lld/include/lld/Driver/CoreInputGraph.h @@ -0,0 +1,52 @@ +//===- lld/Driver/CoreInputGraph.h - Files to be linked for CORE linking---==// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// Handles Options for CORE linking and provides InputElements +/// for the CORE linker +/// +//===----------------------------------------------------------------------===// + +#ifndef LLD_CORE_INPUT_GRAPH_H +#define LLD_CORE_INPUT_GRAPH_H + +#include "lld/Driver/InputGraph.h" +#include "lld/ReaderWriter/CoreLinkingContext.h" + +#include + +namespace lld { + +/// \brief Represents a CORE File +class COREFileNode : public FileNode { +public: + COREFileNode(CoreLinkingContext &ctx, StringRef path) + : FileNode(path), _ctx(ctx) {} + + static inline bool classof(const InputElement *a) { + return a->kind() == InputElement::Kind::File; + } + + virtual std::unique_ptr + createLinkerInput(const lld::LinkingContext &); + + /// \brief validates the Input Element + virtual bool validate() { return true; } + + /// \brief Dump the Input Element + virtual bool dump(raw_ostream &) { return true; } + +private: + const CoreLinkingContext &_ctx; +}; + +} // namespace lld + +#endif diff --git a/lld/include/lld/Driver/DarwinInputGraph.h b/lld/include/lld/Driver/DarwinInputGraph.h new file mode 100644 index 000000000000..f64a6f9c5cde --- /dev/null +++ b/lld/include/lld/Driver/DarwinInputGraph.h @@ -0,0 +1,53 @@ +//===- lld/Driver/DarwinInputGraph.h - Files to be linked for MachO +// linking---===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// Handles Options for MachO linking and provides InputElements +/// for MachO linker +/// +//===----------------------------------------------------------------------===// + +#ifndef LLD_MachO_INPUT_GRAPH_H +#define LLD_MachO_INPUT_GRAPH_H + +#include "lld/Driver/InputGraph.h" +#include "lld/ReaderWriter/MachOLinkingContext.h" + +#include + +namespace lld { + +/// \brief Represents a MachO File +class MachOFileNode : public FileNode { +public: + MachOFileNode(MachOLinkingContext &ctx, StringRef path) + : FileNode(path), _ctx(ctx) {} + + static inline bool classof(const InputElement *a) { + return a->kind() == InputElement::Kind::File; + } + + virtual std::unique_ptr + createLinkerInput(const lld::LinkingContext &); + + /// \brief validates the Input Element + virtual bool validate() { return true; } + + /// \brief Dump the Input Element + virtual bool dump(raw_ostream &) { return true; } + +private: + const MachOLinkingContext &_ctx; +}; + +} // namespace lld + +#endif diff --git a/lld/include/lld/Driver/Driver.h b/lld/include/lld/Driver/Driver.h index 6f35b6b1137c..e7c4caf40513 100644 --- a/lld/include/lld/Driver/Driver.h +++ b/lld/include/lld/Driver/Driver.h @@ -18,6 +18,7 @@ #define LLD_DRIVER_DRIVER_H #include "lld/Core/LLVM.h" +#include "lld/Driver/InputGraph.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/raw_ostream.h" @@ -36,7 +37,7 @@ class ELFLinkingContext; class Driver { protected: - /// Performs link using specified options. + /// Performs link using specified options static bool link(const LinkingContext &context, raw_ostream &diagnostics = llvm::errs()); @@ -44,7 +45,6 @@ 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 { @@ -133,9 +133,6 @@ private: CoreDriver() LLVM_DELETED_FUNCTION; }; - - - } // end namespace lld #endif diff --git a/lld/include/lld/Driver/GnuLDInputGraph.h b/lld/include/lld/Driver/GnuLDInputGraph.h new file mode 100644 index 000000000000..ea69fd1e62d9 --- /dev/null +++ b/lld/include/lld/Driver/GnuLDInputGraph.h @@ -0,0 +1,103 @@ +//===- lld/Driver/GnuLDInputGraph.h - Files to be linked for ELF linking---===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// Handles Options for the GNU style linker for ELF and provides InputElements +/// for the GNU style linker for ELF +/// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_INPUT_GRAPH_H +#define LLD_ELF_INPUT_GRAPH_H + +#include "lld/Driver/InputGraph.h" +#include "lld/ReaderWriter/ELFLinkingContext.h" + +namespace lld { + +/// \brief Represents a ELF File +class ELFFileNode : public FileNode { +public: + ELFFileNode(ELFLinkingContext &ctx, StringRef path, + bool isWholeArchive = false, bool asNeeded = false, + std::vector searchPath = { "" }) + : FileNode(path), _elfLinkingContext(ctx), + _isWholeArchive(isWholeArchive), _asNeeded(asNeeded) { + std::copy(searchPath.begin(), searchPath.end(), + std::back_inserter(_libraryPaths)); + } + + static inline bool classof(const InputElement *a) { + return a->kind() == InputElement::Kind::File; + } + + virtual StringRef path(const LinkingContext &ctx) const; + + virtual std::unique_ptr + createLinkerInput(const lld::LinkingContext &); + + /// \brief validates the Input Element + virtual bool validate() { return true; } + + /// \brief Dump the Input Element + virtual bool dump(raw_ostream &diagnostics) { + diagnostics << "Name : " << path(_elfLinkingContext) << "\n"; + diagnostics << "Type : " + << "ELF File" + << "\n"; + diagnostics << "Ordinal : " << getOrdinal() << "\n"; + diagnostics << "Attributes : " + << "\n"; + diagnostics << " - wholeArchive : " + << ((_isWholeArchive) ? "true" : "false") << "\n"; + diagnostics << " - asNeeded : " << ((_asNeeded) ? "true" : "false") + << "\n"; + diagnostics << " contextPath : " << ((_libraryPaths.size()) ? "" : "None") + << "\n"; + for (auto path : _libraryPaths) + diagnostics << " - " << path << "\n"; + return true; + } + +private: + ELFLinkingContext &_elfLinkingContext; + bool _isWholeArchive : 1; + bool _asNeeded : 1; + std::vector _libraryPaths; +}; + +/// \brief Represents a ELF control node +class ELFGroup : public Group { +public: + ELFGroup(ELFLinkingContext &ctx) : Group(), _elfLinkingContext(ctx) {} + + static inline bool classof(const InputElement *a) { + return a->kind() == InputElement::Kind::Control; + } + + virtual std::unique_ptr + createLinkerInput(const lld::LinkingContext &) { + // FIXME : create a linker input to handle groups + return nullptr; + } + + /// \brief Validate the options + virtual bool validate() { return true; } + + /// \brief Dump the ELFGroup + virtual bool dump(llvm::raw_ostream &) { return true; } + +private: + ELFLinkingContext &_elfLinkingContext; +}; + +} // namespace lld + +#endif diff --git a/lld/include/lld/Driver/InputGraph.h b/lld/include/lld/Driver/InputGraph.h new file mode 100644 index 000000000000..e6f32e586bd1 --- /dev/null +++ b/lld/include/lld/Driver/InputGraph.h @@ -0,0 +1,245 @@ +//===- lld/Core/InputGraph.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 +/// +/// Inputs to the linker in the form of a Graph. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLD_INPUTGRAPH_H +#define LLD_INPUTGRAPH_H + +#include "lld/Core/File.h" +#include "lld/Core/LLVM.h" +#include "lld/Driver/LinkerInput.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include + +namespace lld { + +class InputElement; +class LinkingContext; + +/// \brief The inputs to the linker are represented by an InputGraph. The +/// nodes in the input graph contains Input elements. The InputElements are +/// either Input Files or Control Options. The Input Files represent each Input +/// File to the linker and the control option specify what the linker needs +/// to do when it processes the option. Each InputElement that is part of the +/// Graph has also an Ordinal value associated with it. The ordinal value is +/// needed for components to figure out the relative position of the arguments +/// that appeared in the Command Line. One such example is adding the list of +/// dynamic dynamic libraries to the DT_NEEDED list with the ELF Flavor. The +/// InputElements also have a weight function that can be used to determine the +/// weight of the file, for statistical purposes. The InputGraph also would +/// contain a set of General options that are processed by the linker, which +/// control the output +class InputGraph { +public: + typedef std::vector > InputElementVectorT; + typedef InputElementVectorT::iterator InputElementIterT; + + /// \brief Initialize the inputgraph + InputGraph() : _ordinal(0), _numElements(0), _numFiles(0) {} + + /// \brief Adds a node into the InputGraph + virtual bool addInputElement(std::unique_ptr); + + /// \brief Set Ordinals for all the InputElements that form the InputGraph + virtual bool assignOrdinals(); + + /// Destructor + virtual ~InputGraph() {} + + /// Total number of InputFiles + virtual int64_t numFiles() const { return _numFiles; } + + /// Total number of InputElements + virtual int64_t numElements() const { return _numElements; } + + /// \brief Do postprocessing of the InputGraph if there is a need for the + /// to provide additional information to the user, also rearranges + /// InputElements by their ordinals. If an user wants to place an input file + /// at the desired position, the user can do that + virtual void doPostProcess(); + + /// \brief Iterators + InputElementIterT begin() { return _inputArgs.begin(); } + + InputElementIterT end() { return _inputArgs.end(); } + + /// \brief Validate the input graph + virtual bool validate(); + + /// \brief Dump the input Graph + virtual bool dump(raw_ostream &diagnostics = llvm::errs()); + + InputElement &operator[](uint32_t index) const { + return (*_inputArgs[index]); + } + +private: + // Input arguments + InputElementVectorT _inputArgs; + // Ordinals + int64_t _ordinal; + // Total number of InputElements + int64_t _numElements; + // Total number of FileNodes + int64_t _numFiles; +}; + +/// \brief This describes each element in the InputGraph. The Kind +/// determines what the current node contains. +class InputElement { +public: + /// Each input element in the graph can be a File or a control + enum class Kind : uint8_t { + Control, // Represents a type associated with ControlNodes + File, // Represents a type associated with File Nodes + }; + + /// \brief Initialize the Input Element, The ordinal value of an input Element + /// is initially set to -1, if the user wants to override its ordinal, + /// let the user do it + InputElement(Kind type, int64_t ordinal = -1) + : _kind(type), _ordinal(-1), _weight(0) {} + + virtual ~InputElement() {} + + /// Return the Element Type for an Input Element + virtual Kind kind() const { return _kind; } + + virtual void setOrdinal(int64_t ordinal) { + if (_ordinal != -1) + _ordinal = ordinal; + } + + virtual int64_t getOrdinal() const { return _ordinal; } + + virtual int64_t weight() const { return 0; } + + virtual void setWeight() { return; } + + /// \brief validates the Input Element + virtual bool validate() = 0; + + /// \brief Dump the Input Element + virtual bool dump(raw_ostream &diagnostics) = 0; + +private: + Kind _kind; + int64_t _ordinal; + int64_t _weight; +}; + +/// \brief The Control class represents a control node in the InputGraph +class ControlNode : public InputElement { +public: + /// A control node could be of several types supported by InputGraph + /// Future kinds of Control node could be added + enum class ControlKind : uint8_t { + Simple, // Represents a simple control node + Group // Represents a type associated with ControlNodes + }; + + ControlNode(ControlNode::ControlKind controlKind = + ControlNode::ControlKind::Simple, + int64_t _ordinal = -1) + : InputElement(InputElement::Kind::Control, _ordinal), + _controlKind(controlKind) {} + + virtual ~ControlNode() {} + + /// \brief Return the kind of control node + virtual ControlNode::ControlKind controlKind() { return _controlKind; } + + /// \brief Process control start/exit + virtual bool processControlEnter() { return true; } + + /// \brief Process control start/exit + virtual bool processControlExit() { return true; } + + /// Process the input Elemenet + virtual bool processInputElement(std::unique_ptr element) = 0; + + /// \brief Casting support + static inline bool classof(const InputElement *a) { + return a->kind() == InputElement::Kind::Control; + } + + /// Does the control node have any more elements + bool hasMoreElements() const { return (_elements.size() != 0); } + + /// \brief Iterators to iterate the + InputGraph::InputElementIterT begin() { return _elements.begin(); } + + InputGraph::InputElementIterT end() { return _elements.end(); } + + /// \brief Create a lld::File node from the FileNode + virtual std::unique_ptr + createLinkerInput(const LinkingContext &targetInfo) = 0; + +private: + ControlKind _controlKind; + +protected: + InputGraph::InputElementVectorT _elements; +}; + +/// \brief Represents an Input file in the graph +class FileNode : public InputElement { +public: + FileNode(StringRef path, int64_t ordinal = -1) + : InputElement(InputElement::Kind::File, ordinal), _path(path) {} + + virtual StringRef path(const LinkingContext &) const { return _path; } + + virtual ~FileNode() {} + + /// \brief Casting support + static inline bool classof(const InputElement *a) { + return a->kind() == InputElement::Kind::File; + } + + /// \brief Create a lld::File node from the FileNode + virtual std::unique_ptr + createLinkerInput(const LinkingContext &targetInfo) = 0; + +protected: + StringRef _path; +}; + +/// \brief A Control node which contains a group of InputElements +/// This affects the resolver so that it resolves undefined symbols +/// in the group completely before looking at other input files that +/// follow the group +class Group : public ControlNode { +public: + Group() : ControlNode(ControlNode::ControlKind::Group) {} + + static inline bool classof(const InputElement *a) { + return a->kind() == InputElement::Kind::Control; + } + + virtual bool processInputElement(std::unique_ptr element) { + _elements.push_back(std::move(element)); + return true; + } + + virtual std::unique_ptr + createLinkerInput(const lld::LinkingContext &) = 0; +}; + +} // namespace lld + +#endif // LLD_INPUTGRAPH_H diff --git a/lld/include/lld/Driver/LinkerInput.h b/lld/include/lld/Driver/LinkerInput.h index 8fa53b09a932..63fa112de0fd 100644 --- a/lld/include/lld/Driver/LinkerInput.h +++ b/lld/include/lld/Driver/LinkerInput.h @@ -45,15 +45,16 @@ class LinkerInput { LinkerInput(const LinkerInput &) LLVM_DELETED_FUNCTION; public: - explicit LinkerInput(StringRef file) : _file(file) {} + explicit LinkerInput(StringRef file) + : _file(file), _isForceLoad(false), _asNeeded(false) {} explicit LinkerInput(std::unique_ptr buffer) - : _buffer(std::move(buffer)), _file(_buffer->getBufferIdentifier()) { - } + : _buffer(std::move(buffer)), _file(_buffer->getBufferIdentifier()), + _isForceLoad(false), _asNeeded(false) {} LinkerInput(LinkerInput &&other) - : _buffer(std::move(other._buffer)), _file(std::move(other._file)) { - } + : _buffer(std::move(other._buffer)), _file(std::move(other._file)), + _isForceLoad(other.isForceLoad()), _asNeeded(other.asNeeded()) {} LinkerInput &operator=(LinkerInput &&rhs) { _buffer = std::move(rhs._buffer); @@ -81,13 +82,26 @@ public: return std::move(_buffer); } + /// \brief forceLoad is a positional option which when set, requires all + /// members in an archive to be force loaded + void setForceLoad(bool forceLoad) { _isForceLoad = forceLoad; } + + bool isForceLoad() const { return _isForceLoad; } + + /// \brief asneeded is a positional option which when set for a file + /// makes the file to be needed at runtime only if its resolving + /// undefined symbols + void setAsNeeded(bool asNeeded) { _asNeeded = asNeeded; } + + bool asNeeded() const { return _asNeeded; } + private: mutable std::unique_ptr _buffer; std::string _file; + bool _isForceLoad : 1; + bool _asNeeded : 1; }; - - } // namespace lld #endif diff --git a/lld/include/lld/Driver/WinLinkInputGraph.h b/lld/include/lld/Driver/WinLinkInputGraph.h new file mode 100644 index 000000000000..07f77d5b9ebd --- /dev/null +++ b/lld/include/lld/Driver/WinLinkInputGraph.h @@ -0,0 +1,80 @@ +//===- lld/Driver/WinLinkInputGraph.h - Files to be linked for PECOFF +// linking---===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// Handles Options for PECOFF linking and provides InputElements +/// for PECOFF linker +/// +//===----------------------------------------------------------------------===// + +#ifndef LLD_PECOFF_INPUT_GRAPH_H +#define LLD_PECOFF_INPUT_GRAPH_H + +#include "lld/Driver/InputGraph.h" +#include "lld/ReaderWriter/PECOFFLinkingContext.h" + +#include + +namespace lld { + +/// \brief Represents a PECOFF File +class PECOFFFileNode : public FileNode { +public: + PECOFFFileNode(PECOFFLinkingContext &ctx, StringRef path) + : FileNode(path), _ctx(ctx) {} + + static inline bool classof(const InputElement *a) { + return a->kind() == InputElement::Kind::File; + } + + virtual StringRef path(const LinkingContext &ctx) const; + + virtual std::unique_ptr + createLinkerInput(const lld::LinkingContext &); + + /// \brief validates the Input Element + virtual bool validate() { return true; } + + /// \brief Dump the Input Element + virtual bool dump(raw_ostream &) { return true; } + +private: + const PECOFFLinkingContext &_ctx; +}; + +/// \brief Represents a PECOFF Library File +class PECOFFLibraryNode : public FileNode { +public: + PECOFFLibraryNode(PECOFFLinkingContext &ctx, StringRef path) + : FileNode(path), _ctx(ctx) {} + + static inline bool classof(const InputElement *a) { + return a->kind() == InputElement::Kind::File; + } + + virtual StringRef path(const LinkingContext &ctx) const; + + virtual std::unique_ptr + createLinkerInput(const lld::LinkingContext &); + + /// \brief validates the Input Element + virtual bool validate() { return true; } + + /// \brief Dump the Input Element + virtual bool dump(raw_ostream &) { return true; } + +private: + const PECOFFLinkingContext &_ctx; +}; + +} // namespace lld + +#endif diff --git a/lld/include/lld/ReaderWriter/ELFLinkingContext.h b/lld/include/lld/ReaderWriter/ELFLinkingContext.h index 6de2fbdb29e7..a7cd19d0435d 100644 --- a/lld/include/lld/ReaderWriter/ELFLinkingContext.h +++ b/lld/include/lld/ReaderWriter/ELFLinkingContext.h @@ -150,11 +150,9 @@ public: /// \brief Disallow dynamic libraries during linking virtual void setNoAllowDynamicLibraries() { _noAllowDynamicLibraries = true; } - void appendSearchPath(StringRef dirPath) { - _inputSearchPaths.push_back(dirPath); - } - /// Searches directories then calls appendInputFile() - bool appendLibrary(StringRef libName); + /// Searches directories for a match on the input File + StringRef searchLibrary(StringRef libName, + const std::vector &searchPath) const; private: ELFLinkingContext() LLVM_DELETED_FUNCTION; @@ -178,7 +176,7 @@ protected: bool _noAllowDynamicLibraries; OutputMagic _outputMagic; StringRefVector _inputSearchPaths; - llvm::BumpPtrAllocator _extraStrings; + mutable llvm::BumpPtrAllocator _alloc; std::unique_ptr _elfReader; std::unique_ptr _writer; std::unique_ptr _linkerScriptReader; diff --git a/lld/lib/ReaderWriter/MachO/MachOFormat.hpp b/lld/include/lld/ReaderWriter/MachOFormat.hpp similarity index 84% rename from lld/lib/ReaderWriter/MachO/MachOFormat.hpp rename to lld/include/lld/ReaderWriter/MachOFormat.hpp index 41b432a16ec3..3d27a3193a99 100644 --- a/lld/lib/ReaderWriter/MachO/MachOFormat.hpp +++ b/lld/include/lld/ReaderWriter/MachOFormat.hpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // -// This file contains all the structs and constants needed to write a +// This file contains all the structs and constants needed to write a // mach-o final linked image. The names of the structs and constants // are the same as in the darwin native header so // they will be familiar to anyone who has used that header. @@ -25,9 +25,9 @@ namespace lld { namespace mach_o { -enum { +enum { MH_MAGIC = 0xfeedface, - MH_MAGIC_64 = 0xfeedfacf + MH_MAGIC_64 = 0xfeedfacf }; enum { @@ -62,24 +62,24 @@ enum { // class mach_header { public: - uint32_t magic; + uint32_t magic; uint32_t cputype; - uint32_t cpusubtype; - uint32_t filetype; - uint32_t ncmds; - uint32_t sizeofcmds; - uint32_t flags; - uint32_t reserved; - + uint32_t cpusubtype; + uint32_t filetype; + uint32_t ncmds; + uint32_t sizeofcmds; + uint32_t flags; + uint32_t reserved; + uint64_t size() { return (magic == 0xfeedfacf) ? 32 : 28; } - + void copyTo(uint8_t *to, bool swap=false) { ::memcpy(to, (char*)&magic, this->size()); } - - void recordLoadCommand(const class load_command *lc); + + void recordLoadCommand(const class load_command *lc); }; @@ -101,14 +101,14 @@ class load_command { public: const uint32_t cmd; // type of load command const uint32_t cmdsize; // length of load command including this header - + load_command(uint32_t cmdNumber, uint32_t sz, bool is64, bool align=false) : cmd(cmdNumber), cmdsize(pointerAlign(sz, is64, align)) { } - + virtual ~load_command() { } - + virtual void copyTo(uint8_t *to, bool swap=false) = 0; private: // Load commands must be pointer-size aligned. Most load commands are @@ -168,7 +168,7 @@ enum { S_NON_LAZY_SYMBOL_POINTERS= 0x00000006, S_LAZY_SYMBOL_POINTERS = 0x00000007, S_SYMBOL_STUBS = 0x00000008, - + // Other bits in section.flags S_ATTR_PURE_INSTRUCTIONS = 0x80000000, S_ATTR_SOME_INSTRUCTIONS = 0x00000400 @@ -177,32 +177,32 @@ enum { // section record for 32-bit architectures struct section { - char sectname[16]; - char segname[16]; - uint32_t addr; - uint32_t size; - uint32_t offset; - uint32_t align; - uint32_t reloff; - uint32_t nreloc; - uint32_t flags; + char sectname[16]; + char segname[16]; + uint32_t addr; + uint32_t size; + uint32_t offset; + uint32_t align; + uint32_t reloff; + uint32_t nreloc; + uint32_t flags; uint32_t reserved1; - uint32_t reserved2; + uint32_t reserved2; }; // section record for 64-bit architectures struct section_64 { - char sectname[16]; - char segname[16]; - uint64_t addr; - uint64_t size; - uint32_t offset; - uint32_t align; - uint32_t reloff; - uint32_t nreloc; - uint32_t flags; + char sectname[16]; + char segname[16]; + uint64_t addr; + uint64_t size; + uint32_t offset; + uint32_t align; + uint32_t reloff; + uint32_t nreloc; + uint32_t flags; uint32_t reserved1; - uint32_t reserved2; + uint32_t reserved2; uint32_t reserved3; }; @@ -210,35 +210,35 @@ struct section_64 { // // A segment load command has a fixed set of fields followed by an 'nsect' // array of section records. The in-memory object uses a pointer to -// a dynamically allocated array of sections. +// a dynamically allocated array of sections. // class segment_command : public load_command { public: - char segname[16]; - uint64_t vmaddr; - uint64_t vmsize; - uint64_t fileoff; - uint64_t filesize; - uint32_t maxprot; - uint32_t initprot; - uint32_t nsects; - uint32_t flags; + char segname[16]; + uint64_t vmaddr; + uint64_t vmsize; + uint64_t fileoff; + uint64_t filesize; + uint32_t maxprot; + uint32_t initprot; + uint32_t nsects; + uint32_t flags; section_64 *sections; - + segment_command(unsigned sectCount, bool is64) - : load_command((is64 ? LC_SEGMENT_64 : LC_SEGMENT), + : load_command((is64 ? LC_SEGMENT_64 : LC_SEGMENT), (is64 ? (72 + sectCount*80) : (56 + sectCount*68)), is64), - vmaddr(0), vmsize(0), fileoff(0), filesize(0), + vmaddr(0), vmsize(0), fileoff(0), filesize(0), maxprot(0), initprot(0), nsects(sectCount), flags(0) { sections = new section_64[sectCount]; this->nsects = sectCount; } - + ~segment_command() { delete sections; } - + void copyTo(uint8_t *to, bool swap) { if ( swap ) { assert(0 && "non-native endianness not supported yet"); @@ -284,8 +284,8 @@ private: ::memcpy(&to[offset], &value32, sizeof(uint32_t)); } - bool is64() { - return (cmd == LC_SEGMENT_64); + bool is64() { + return (cmd == LC_SEGMENT_64); } }; @@ -303,8 +303,8 @@ public: private: StringRef _name; public: - dylinker_command(StringRef path, bool is64) - : load_command(LC_LOAD_DYLINKER,12 + path.size(), is64, true), + dylinker_command(StringRef path, bool is64) + : load_command(LC_LOAD_DYLINKER,12 + path.size(), is64, true), name_offset(12), _name(path) { } @@ -330,48 +330,48 @@ public: // class symtab_command : public load_command { public: - uint32_t symoff; - uint32_t nsyms; - uint32_t stroff; - uint32_t strsize; + uint32_t symoff; + uint32_t nsyms; + uint32_t stroff; + uint32_t strsize; - symtab_command(bool is64) - : load_command(LC_SYMTAB, 24, is64), + symtab_command(bool is64) + : load_command(LC_SYMTAB, 24, is64), symoff(0), nsyms(0), stroff(0), strsize(0) { } - + virtual void copyTo(uint8_t *to, bool swap=false) { if ( swap ) { assert(0 && "non-native endianness not supported yet"); } else { - // in-memory matches on-disk, so copy fields + // in-memory matches on-disk, so copy fields ::memcpy(to, (uint8_t*)&cmd, 24); } } - + }; // // The entry_point_command load command holds the offset to the function -// _main in a dynamic executable. +// _main in a dynamic executable. // class entry_point_command : public load_command { public: - uint64_t entryoff; - uint64_t stacksize; + uint64_t entryoff; + uint64_t stacksize; - entry_point_command(bool is64) + entry_point_command(bool is64) : load_command(LC_MAIN, 24, is64), entryoff(0), stacksize(0) { } - + virtual void copyTo(uint8_t *to, bool swap=false) { if ( swap ) { assert(0 && "non-native endianness not supported yet"); } else { - // in-memory matches on-disk, so copy fields + // in-memory matches on-disk, so copy fields ::memcpy(to, (uint8_t*)&cmd, 24); } } @@ -391,7 +391,7 @@ private: uint8_t *_registerArray; public: - thread_command(uint32_t cpuType, bool is64) + thread_command(uint32_t cpuType, bool is64) : load_command(LC_UNIXTHREAD, 16+registersBufferSize(cpuType), is64), fields_count(registersBufferSize(cpuType)/4), _cpuType(cpuType) { switch ( cpuType ) { @@ -411,19 +411,19 @@ public: ::calloc(registersBufferSize(cpuType), 1)); assert(_registerArray); } - + virtual void copyTo(uint8_t *to, bool swap=false) { if ( swap ) { assert(0 && "non-native endianness not supported yet"); } else { - // in-memory matches on-disk, so copy fixed fields + // in-memory matches on-disk, so copy fixed fields ::memcpy(to, (uint8_t*)&cmd, 16); // that register array ::memcpy(&to[16], _registerArray, registersBufferSize(_cpuType)); } } - + void setPC(uint64_t pc) { uint32_t *regs32 = reinterpret_cast(_registerArray); uint64_t *regs64 = reinterpret_cast(_registerArray); @@ -441,9 +441,9 @@ public: assert(0 && "unsupported cpu type"); } } - + virtual ~thread_command() { - ::free(_registerArray); + ::free(_registerArray); } private: @@ -459,9 +459,9 @@ private: assert(0 && "unsupported cpu type"); return 0; } - - - + + + }; @@ -475,19 +475,19 @@ private: struct dylib_command : public load_command { uint32_t name_offset; uint32_t timestamp; - uint32_t current_version; + uint32_t current_version; uint32_t compatibility_version; -private: +private: StringRef _loadPath; public: - - dylib_command(StringRef path, bool is64) - : load_command(LC_LOAD_DYLIB, 24 + path.size(), is64, true), - name_offset(24), timestamp(0), + + dylib_command(StringRef path, bool is64) + : load_command(LC_LOAD_DYLIB, 24 + path.size(), is64, true), + name_offset(24), timestamp(0), current_version(0x10000), compatibility_version(0x10000), _loadPath(path) { } - + virtual void copyTo(uint8_t *to, bool swap=false) { if ( swap ) { assert(0 && "non-native endianness not supported yet"); @@ -508,30 +508,30 @@ public: // of information needed by dyld to prepare the image for execution. // struct dyld_info_command : public load_command { - uint32_t rebase_off; - uint32_t rebase_size; - uint32_t bind_off; - uint32_t bind_size; - uint32_t weak_bind_off; - uint32_t weak_bind_size; + uint32_t rebase_off; + uint32_t rebase_size; + uint32_t bind_off; + uint32_t bind_size; + uint32_t weak_bind_off; + uint32_t weak_bind_size; uint32_t lazy_bind_off; - uint32_t lazy_bind_size; - uint32_t export_off; - uint32_t export_size; + uint32_t lazy_bind_size; + uint32_t export_off; + uint32_t export_size; - dyld_info_command(bool is64) - : load_command(LC_DYLD_INFO_ONLY, 48, is64), + dyld_info_command(bool is64) + : load_command(LC_DYLD_INFO_ONLY, 48, is64), rebase_off(0), rebase_size(0), - bind_off(0), bind_size(0), weak_bind_off(0), weak_bind_size(0), + bind_off(0), bind_size(0), weak_bind_off(0), weak_bind_size(0), lazy_bind_off(0), lazy_bind_size(0), export_off(0), export_size(0) { } - + virtual void copyTo(uint8_t *to, bool swap=false) { if ( swap ) { assert(0 && "non-native endianness not supported yet"); } else { - // in-memory matches on-disk, so copy fields + // in-memory matches on-disk, so copy fields ::memcpy(to, (uint8_t*)&cmd, 48); } } @@ -585,23 +585,23 @@ enum { class nlist { public: - uint32_t n_strx; - uint8_t n_type; - uint8_t n_sect; - uint16_t n_desc; - uint64_t n_value; - + uint32_t n_strx; + uint8_t n_type; + uint8_t n_sect; + uint16_t n_desc; + uint64_t n_value; + static unsigned size(bool is64) { return (is64 ? 16 : 12); } - + void copyTo(uint8_t *to, bool is64, bool swap=false) { if ( swap ) { assert(0 && "non-native endianness not supported yet"); } else { if ( is64 ) { - // in-memory matches on-disk, so just copy whole struct + // in-memory matches on-disk, so just copy whole struct ::memcpy(to, (uint8_t*)&n_strx, 16); } else { diff --git a/lld/include/lld/ReaderWriter/PECOFFLinkingContext.h b/lld/include/lld/ReaderWriter/PECOFFLinkingContext.h index 71121260a2a5..0683286144ea 100644 --- a/lld/include/lld/ReaderWriter/PECOFFLinkingContext.h +++ b/lld/include/lld/ReaderWriter/PECOFFLinkingContext.h @@ -37,6 +37,9 @@ public: int minorVersion; }; + /// \brief Casting support + static inline bool classof(const LinkingContext *info) { return true; } + virtual error_code parseFile(std::unique_ptr &mb, std::vector > &result) const; @@ -56,8 +59,7 @@ public: return _inputSearchPaths; } - void appendInputFileOrLibrary(std::string path); - void appendLibraryFile(StringRef path); + StringRef searchLibraryFile(StringRef path) const; void setBaseAddress(uint64_t addr) { _baseAddress = addr; } uint64_t getBaseAddress() const { return _baseAddress; } @@ -93,13 +95,19 @@ public: virtual ErrorOr relocKindFromString(StringRef str) const; virtual ErrorOr stringFromRelocKind(Reference::Kind kind) const; - StringRef allocateString(const StringRef &ref) { + StringRef allocateString(StringRef ref) { char *x = _alloc.Allocate(ref.size() + 1); memcpy(x, ref.data(), ref.size()); x[ref.size()] = '\0'; return x; } + virtual bool hasInputGraph() { + if (_inputGraph) + return true; + return false; + } + private: // The start address for the program. The default value for the executable is // 0x400000, but can be altered using -base command line option. diff --git a/lld/lib/Driver/CMakeLists.txt b/lld/lib/Driver/CMakeLists.txt index 11d288809a19..bea845bf764c 100644 --- a/lld/lib/Driver/CMakeLists.txt +++ b/lld/lib/Driver/CMakeLists.txt @@ -9,6 +9,7 @@ tablegen(LLVM WinLinkOptions.inc -gen-opt-parser-defs) add_public_tablegen_target(DriverOptionsTableGen) add_lld_library(lldDriver + InputGraph.cpp CoreDriver.cpp DarwinLdDriver.cpp Driver.cpp diff --git a/lld/lib/Driver/CoreDriver.cpp b/lld/lib/Driver/CoreDriver.cpp index c0869b790f61..9e4ca1228e04 100644 --- a/lld/lib/Driver/CoreDriver.cpp +++ b/lld/lib/Driver/CoreDriver.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "lld/Driver/Driver.h" +#include "lld/Driver/CoreInputGraph.h" #include "lld/ReaderWriter/CoreLinkingContext.h" #include "lld/ReaderWriter/Reader.h" @@ -61,103 +62,105 @@ public: CoreOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){} }; - - } // namespace anonymous namespace lld { +std::unique_ptr +COREFileNode::createLinkerInput(const LinkingContext &info) { + return std::unique_ptr(new LinkerInput(path(info))); +} + bool CoreDriver::link(int argc, const char *argv[], raw_ostream &diagnostics) { CoreLinkingContext info; if (parse(argc, argv, info)) return true; - + return Driver::link(info); } -bool CoreDriver::parse(int argc, const char *argv[], CoreLinkingContext &info, +bool CoreDriver::parse(int argc, const char *argv[], CoreLinkingContext &ctx, raw_ostream &diagnostics) { // Parse command line options using CoreOptions.td std::unique_ptr parsedArgs; CoreOptTable table; unsigned missingIndex; unsigned missingCount; - parsedArgs.reset(table.ParseArgs(&argv[1], &argv[argc], - missingIndex, 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"; + 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"; - } - - // Copy mllvm - for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_mllvm), - ie = parsedArgs->filtered_end(); - it != ie; ++it) { - info.appendLLVMOption((*it)->getValue()); - } - - // 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); + std::unique_ptr inputGraph(new InputGraph()); + + // Set default options + ctx.setOutputPath("-"); + ctx.setDeadStripping(false); + ctx.setGlobalsAreDeadStripRoots(false); + ctx.setPrintRemainingUndefines(false); + ctx.setAllowRemainingUndefines(true); + ctx.setSearchArchivesToOverrideTentativeDefinitions(false); + + // Process all the arguments and create Input Elements + for (auto inputArg : *parsedArgs) { + switch (inputArg->getOption().getID()) { + case OPT_mllvm: + ctx.appendLLVMOption(inputArg->getValue()); + break; + + case OPT_entry: + ctx.setEntrySymbolName(inputArg->getValue()); + break; + + case OPT_output: + ctx.setOutputPath(inputArg->getValue()); + break; + + case OPT_dead_strip: + ctx.setDeadStripping(true); + break; + + case OPT_keep_globals: + ctx.setGlobalsAreDeadStripRoots(true); + break; + + case OPT_undefines_are_errors: + ctx.setPrintRemainingUndefines(true); + ctx.setAllowRemainingUndefines(false); + break; + + case OPT_commons_search_archives: + ctx.setSearchArchivesToOverrideTentativeDefinitions(true); + break; + + case OPT_add_pass: + ctx.addPassNamed(inputArg->getValue()); + break; + + case OPT_INPUT: { + inputGraph->addInputElement(std::unique_ptr( + new COREFileNode(ctx, inputArg->getValue()))); + } break; + + default: + break; + } } - // 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()); + if (!inputGraph->numFiles()) { + diagnostics << "No input files\n"; + return true; } - // 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; + ctx.setInputGraph(std::move(inputGraph)); + + // Validate the combination of options used. + return ctx.validate(diagnostics); } } // namespace lld diff --git a/lld/lib/Driver/DarwinLdDriver.cpp b/lld/lib/Driver/DarwinLdDriver.cpp index 2e3d695d12f8..90469d89731c 100644 --- a/lld/lib/Driver/DarwinLdDriver.cpp +++ b/lld/lib/Driver/DarwinLdDriver.cpp @@ -14,9 +14,9 @@ //===----------------------------------------------------------------------===// #include "lld/Driver/Driver.h" +#include "lld/Driver/DarwinInputGraph.h" #include "lld/ReaderWriter/MachOLinkingContext.h" -#include "../ReaderWriter/MachO/MachOFormat.hpp" - +#include "lld/ReaderWriter/MachOFormat.hpp" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" @@ -71,31 +71,35 @@ public: namespace lld { -bool DarwinLdDriver::linkMachO(int argc, const char *argv[], - raw_ostream &diagnostics) { - MachOLinkingContext info; - if (parse(argc, argv, info, diagnostics)) +std::unique_ptr +MachOFileNode::createLinkerInput(const LinkingContext &ctx) { + return std::unique_ptr(new LinkerInput(path(ctx))); +} + +bool DarwinLdDriver::linkMachO(int argc, const char *argv[], + raw_ostream &diagnostics) { + MachOLinkingContext ctx; + if (parse(argc, argv, ctx, diagnostics)) return true; - if ( info.doNothing() ) + if (ctx.doNothing()) return false; - - return link(info, diagnostics); + + return link(ctx, diagnostics); } bool DarwinLdDriver::parse(int argc, const char *argv[], - MachOLinkingContext &info, - raw_ostream &diagnostics) { + MachOLinkingContext &ctx, raw_ostream &diagnostics) { // Parse command line options using DarwinOptions.td std::unique_ptr parsedArgs; DarwinLdOptTable table; unsigned missingIndex; unsigned missingCount; - parsedArgs.reset(table.ParseArgs(&argv[1], &argv[argc], - missingIndex, 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"; + diagnostics << "error: missing arg value for '" + << parsedArgs->getArgString(missingIndex) << "' expected " + << missingCount << " argument(s).\n"; return true; } @@ -104,52 +108,52 @@ bool DarwinLdDriver::parse(int argc, const char *argv[], 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); - info.setGlobalsAreDeadStripRoots(true); + ctx.setOutputFileType(mach_o::MH_DYLIB); + ctx.setGlobalsAreDeadStripRoots(true); break; case OPT_relocatable: - info.setPrintRemainingUndefines(false); - info.setAllowRemainingUndefines(true); - info.setOutputFileType(mach_o::MH_OBJECT); + ctx.setPrintRemainingUndefines(false); + ctx.setAllowRemainingUndefines(true); + ctx.setOutputFileType(mach_o::MH_OBJECT); break; case OPT_bundle: - info.setOutputFileType(mach_o::MH_BUNDLE); + ctx.setOutputFileType(mach_o::MH_BUNDLE); break; case OPT_static: - info.setOutputFileType(mach_o::MH_EXECUTE); + ctx.setOutputFileType(mach_o::MH_EXECUTE); break; case OPT_preload: - info.setOutputFileType(mach_o::MH_PRELOAD); + ctx.setOutputFileType(mach_o::MH_PRELOAD); break; } } - + // Handle -e xxx if (llvm::opt::Arg *entry = parsedArgs->getLastArg(OPT_entry)) - info.setEntrySymbolName(entry->getValue()); + ctx.setEntrySymbolName(entry->getValue()); // Handle -o xxx if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_output)) - info.setOutputPath(outpath->getValue()); - + ctx.setOutputPath(outpath->getValue()); + // Handle -dead_strip if (parsedArgs->getLastArg(OPT_dead_strip)) - info.setDeadStripping(true); - + ctx.setDeadStripping(true); + // Handle -all_load if (parsedArgs->getLastArg(OPT_all_load)) - info.setForceLoadAllArchives(true); - + ctx.setForceLoadAllArchives(true); + // Handle -arch xxx if (llvm::opt::Arg *archStr = parsedArgs->getLastArg(OPT_arch)) { - info.setArch(MachOLinkingContext::archFromName(archStr->getValue())); - if (info.arch() == MachOLinkingContext::arch_unknown) { + ctx.setArch(MachOLinkingContext::archFromName(archStr->getValue())); + if (ctx.arch() == MachOLinkingContext::arch_unknown) { diagnostics << "error: unknown arch named '" << archStr->getValue() << "'\n"; return true; @@ -163,20 +167,20 @@ bool DarwinLdDriver::parse(int argc, const char *argv[], OPT_ios_simulator_version_min)) { switch (minOS->getOption().getID()) { case OPT_macosx_version_min: - if (info.setOS(MachOLinkingContext::OS::macOSX, minOS->getValue())) { + if (ctx.setOS(MachOLinkingContext::OS::macOSX, minOS->getValue())) { diagnostics << "error: malformed macosx_version_min value\n"; return true; } break; case OPT_ios_version_min: - if (info.setOS(MachOLinkingContext::OS::iOS, minOS->getValue())) { + if (ctx.setOS(MachOLinkingContext::OS::iOS, minOS->getValue())) { diagnostics << "error: malformed ios_version_min value\n"; return true; } break; case OPT_ios_simulator_version_min: - if (info.setOS(MachOLinkingContext::OS::iOS_simulator, - minOS->getValue())) { + if (ctx.setOS(MachOLinkingContext::OS::iOS_simulator, + minOS->getValue())) { diagnostics << "error: malformed ios_simulator_version_min value\n"; return true; } @@ -185,34 +189,32 @@ bool DarwinLdDriver::parse(int argc, const char *argv[], } else { // No min-os version on command line, check environment variables - } - + + std::unique_ptr inputGraph(new InputGraph()); + // 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()); - } - - // Handle -help - if (parsedArgs->getLastArg(OPT_help)) { - table.PrintHelp(llvm::outs(), argv[0], "LLVM Darwin Linker", false); - // If only -help on command line, don't try to do any linking - if ( argc == 2 ) { - info.setDoNothing(true); - return false; - } + inputGraph->addInputElement(std::unique_ptr( + new MachOFileNode(ctx, (*it)->getValue()))); } + if (!inputGraph->numFiles()) { + diagnostics << "No input files\n"; + return true; + } + + ctx.setInputGraph(std::move(inputGraph)); + // Validate the combination of options used. - if (info.validate(diagnostics)) + if (ctx.validate(diagnostics)) return true; return false; } - } // namespace lld diff --git a/lld/lib/Driver/Driver.cpp b/lld/lib/Driver/Driver.cpp index d76bbdd31d4e..ae20f84c973f 100644 --- a/lld/lib/Driver/Driver.cpp +++ b/lld/lib/Driver/Driver.cpp @@ -40,21 +40,31 @@ bool Driver::link(const LinkingContext &context, raw_ostream &diagnostics) { args[numArgs + 1] = 0; llvm::cl::ParseCommandLineOptions(numArgs + 1, args); } + InputGraph &inputGraph = context.inputGraph(); + if (!inputGraph.numFiles()) + return true; // Read inputs ScopedTask readTask(getDefaultDomain(), "Read Args"); - std::vector> > files( - context.inputFiles().size()); + std::vector > > files( + inputGraph.numFiles()); size_t index = 0; std::atomic fail(false); TaskGroup tg; - for (const auto &input : context.inputFiles()) { + std::vector > linkerInputs; + for (auto &ie : inputGraph) { + if (ie->kind() == InputElement::Kind::File) { + FileNode *fileNode = (llvm::dyn_cast)(ie.get()); + linkerInputs.push_back(std::move(fileNode->createLinkerInput(context))); + } + } + for (const auto &input : linkerInputs) { if (context.logInputFiles()) - llvm::outs() << input.getPath() << "\n"; + llvm::outs() << input->getPath() << "\n"; tg.spawn([ &, index]{ - if (error_code ec = context.readFile(input.getPath(), files[index])) { - diagnostics << "Failed to read file: " << input.getPath() << ": " + if (error_code ec = context.readFile(input->getPath(), files[index])) { + diagnostics << "Failed to read file: " << input->getPath() << ": " << ec.message() << "\n"; fail = true; return; diff --git a/lld/lib/Driver/GnuLdDriver.cpp b/lld/lib/Driver/GnuLdDriver.cpp index 01c7c489b1a4..96fa31905fc5 100644 --- a/lld/lib/Driver/GnuLdDriver.cpp +++ b/lld/lib/Driver/GnuLdDriver.cpp @@ -14,7 +14,7 @@ //===----------------------------------------------------------------------===// #include "lld/Driver/Driver.h" -#include "lld/ReaderWriter/ELFLinkingContext.h" +#include "lld/Driver/GnuLDInputGraph.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" @@ -71,10 +71,20 @@ public: } // namespace +std::unique_ptr +ELFFileNode::createLinkerInput(const LinkingContext &ctx) { + std::unique_ptr inputFile(new LinkerInput(path(ctx))); + inputFile->setAsNeeded(_asNeeded); + inputFile->setForceLoad(_isWholeArchive); + return std::move(inputFile); +} +StringRef ELFFileNode::path(const LinkingContext &) const { + return _elfLinkingContext.searchLibrary(_path, _libraryPaths); +} bool GnuLdDriver::linkELF(int argc, const char *argv[], - raw_ostream &diagnostics) { + raw_ostream &diagnostics) { std::unique_ptr options; bool error = parse(argc, argv, options, diagnostics); if (error) @@ -93,6 +103,7 @@ bool GnuLdDriver::parse(int argc, const char *argv[], GnuLdOptTable table; unsigned missingIndex; unsigned missingCount; + parsedArgs.reset( table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount)); if (missingCount) { @@ -102,13 +113,6 @@ bool GnuLdDriver::parse(int argc, const char *argv[], 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 --help if (parsedArgs->getLastArg(OPT_help)) { table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false); @@ -121,154 +125,181 @@ bool GnuLdDriver::parse(int argc, const char *argv[], triple = llvm::Triple(trip->getValue()); else triple = getDefaultTarget(argv[0]); - std::unique_ptr options(ELFLinkingContext::create(triple)); + std::unique_ptr ctx(ELFLinkingContext::create(triple)); - if (!options) { + if (!ctx) { diagnostics << "unknown target triple\n"; return true; } - // Handle -e xxx - if (llvm::opt::Arg *entry = parsedArgs->getLastArg(OPT_entry)) - options->setEntrySymbolName(entry->getValue()); + std::unique_ptr inputGraph(new InputGraph()); + std::stack controlNodeStack; - // Handle -emit-yaml - if (parsedArgs->getLastArg(OPT_emit_yaml)) - options->setOutputYAML(true); + // Positional options for an Input File + std::vector searchPath; + bool isWholeArchive = false; + bool asNeeded = false; + bool _outputOptionSet = false; - // 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"); + // Create a dynamic executable by default + ctx->setOutputFileType(llvm::ELF::ET_EXEC); + ctx->setIsStaticExecutable(false); + ctx->setAllowShlibUndefines(false); + ctx->setUseShlibUndefines(true); - // 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); + // Set the output file to be a.out + ctx->setOutputPath("a.out"); + + // Process all the arguments and create Input Elements + for (auto inputArg : *parsedArgs) { + switch (inputArg->getOption().getID()) { + case OPT_mllvm: + ctx->appendLLVMOption(inputArg->getValue()); break; - case OPT_shared: - options->setOutputFileType(llvm::ELF::ET_DYN); - options->setAllowShlibUndefines(true); - options->setUseShlibUndefines(false); + case OPT_relocatable: + ctx->setOutputFileType(llvm::ELF::ET_REL); + ctx->setPrintRemainingUndefines(false); + ctx->setAllowRemainingUndefines(true); break; case OPT_static: - options->setOutputFileType(llvm::ELF::ET_EXEC); - options->setIsStaticExecutable(true); + ctx->setOutputFileType(llvm::ELF::ET_EXEC); + ctx->setIsStaticExecutable(true); + break; + case OPT_shared: + ctx->setOutputFileType(llvm::ELF::ET_DYN); + ctx->setAllowShlibUndefines(true); + ctx->setUseShlibUndefines(false); + break; + case OPT_entry: + ctx->setEntrySymbolName(inputArg->getValue()); break; - } - } else { - options->setOutputFileType(llvm::ELF::ET_EXEC); - options->setIsStaticExecutable(false); - options->setAllowShlibUndefines(false); - options->setUseShlibUndefines(true); - } - // Handle --noinhibit-exec - if (parsedArgs->getLastArg(OPT_noinhibit_exec)) - options->setAllowRemainingUndefines(true); + case OPT_output: + _outputOptionSet = true; + ctx->setOutputPath(inputArg->getValue()); + break; - // Handle --force-load - if (parsedArgs->getLastArg(OPT_force_load)) - options->setForceLoadAllArchives(true); + case OPT_noinhibit_exec: + ctx->setAllowRemainingUndefines(true); + break; - // Handle --merge-strings - if (parsedArgs->getLastArg(OPT_merge_strings)) - options->setMergeCommonStrings(true); + case OPT_merge_strings: + ctx->setMergeCommonStrings(true); + break; - // Handle -t - if (parsedArgs->getLastArg(OPT_t)) - options->setLogInputFiles(true); + case OPT_all_load: + ctx->setForceLoadAllArchives(true); + break; - // Handle --no-allow-shlib-undefined - if (parsedArgs->getLastArg(OPT_no_allow_shlib_undefs)) - options->setAllowShlibUndefines(false); + case OPT_t: + ctx->setLogInputFiles(true); + break; - // Handle --allow-shlib-undefined - if (parsedArgs->getLastArg(OPT_allow_shlib_undefs)) - options->setAllowShlibUndefines(true); + case OPT_no_allow_shlib_undefs: + ctx->setAllowShlibUndefines(false); + break; - // Handle --use-shlib-undefs - if (parsedArgs->getLastArg(OPT_use_shlib_undefs)) - options->setUseShlibUndefines(true); + case OPT_allow_shlib_undefs: + ctx->setAllowShlibUndefines(true); + break; - // Handle --dynamic-linker - if (llvm::opt::Arg *dynamicLinker = - parsedArgs->getLastArg(OPT_dynamic_linker)) - options->setInterpreter(dynamicLinker->getValue()); + case OPT_use_shlib_undefs: + ctx->setUseShlibUndefines(true); + break; - // Handle NMAGIC - if (parsedArgs->getLastArg(OPT_nmagic)) - options->setOutputMagic(ELFLinkingContext::OutputMagic::NMAGIC); + case OPT_dynamic_linker: + ctx->setInterpreter(inputArg->getValue()); + break; - // Handle OMAGIC - if (parsedArgs->getLastArg(OPT_omagic)) - options->setOutputMagic(ELFLinkingContext::OutputMagic::OMAGIC); + case OPT_nmagic: + ctx->setOutputMagic(ELFLinkingContext::OutputMagic::NMAGIC); + ctx->setIsStaticExecutable(true); + break; - // Handle --no-omagic - if (parsedArgs->getLastArg(OPT_no_omagic)) { - options->setOutputMagic(ELFLinkingContext::OutputMagic::DEFAULT); - options->setNoAllowDynamicLibraries(); - } + case OPT_omagic: + ctx->setOutputMagic(ELFLinkingContext::OutputMagic::OMAGIC); + ctx->setIsStaticExecutable(true); + break; - // If either of the options NMAGIC/OMAGIC have been set, make the executable - // static - if (!options->allowLinkWithDynamicLibraries()) - options->setIsStaticExecutable(true); + case OPT_no_omagic: + ctx->setOutputMagic(ELFLinkingContext::OutputMagic::DEFAULT); + ctx->setNoAllowDynamicLibraries(); + break; - // Handle -u, --undefined option - for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_u), - ie = parsedArgs->filtered_end(); - it != ie; ++it) { - options->addInitialUndefinedSymbol((*it)->getValue()); - } + case OPT_u: + ctx->addInitialUndefinedSymbol(inputArg->getValue()); + break; - // Handle -Lxxx - for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_L), - ie = parsedArgs->filtered_end(); - it != ie; ++it) { - options->appendSearchPath((*it)->getValue()); - } + case OPT_emit_yaml: + if (!_outputOptionSet) + ctx->setOutputPath("-"); + ctx->setOutputYAML(true); + break; - // Copy mllvm - for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_mllvm), - ie = parsedArgs->filtered_end(); - it != ie; ++it) { - options->appendLLVMOption((*it)->getValue()); - } + case OPT_no_whole_archive: + isWholeArchive = false; + break; + case OPT_whole_archive: + isWholeArchive = true; + break; + case OPT_as_needed: + asNeeded = true; + break; + case OPT_no_as_needed: + asNeeded = false; + break; + case OPT_L: + searchPath.push_back(inputArg->getValue()); + break; + + case OPT_start_group: { + std::unique_ptr controlStart(new ELFGroup(*ctx)); + controlNodeStack.push(controlStart.get()); + (llvm::dyn_cast)(controlNodeStack.top()) + ->processControlEnter(); + inputGraph->addInputElement(std::move(controlStart)); + } break; + + case OPT_end_group: + (llvm::dyn_cast)(controlNodeStack.top()) + ->processControlExit(); + controlNodeStack.pop(); + return false; - // 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 true; - } - break; + case OPT_l: { + std::unique_ptr inputFile = + std::move(std::unique_ptr( + new ELFFileNode(*ctx, inputArg->getValue(), isWholeArchive, + asNeeded, searchPath))); + if (controlNodeStack.empty()) + inputGraph->addInputElement(std::move(inputFile)); + else + (llvm::dyn_cast)(controlNodeStack.top()) + ->processInputElement(std::move(inputFile)); + } break; + default: - llvm_unreachable("input option type not handled"); - } + break; + } // end switch on option ID + } // end for + + if (!inputGraph->numFiles()) { + diagnostics << "No input files\n"; + return true; } + if (ctx->outputYAML()) + inputGraph->dump(diagnostics); + // Validate the combination of options used. - if (options->validate(diagnostics)) + if (ctx->validate(diagnostics)) return true; - context.swap(options); + ctx->setInputGraph(std::move(inputGraph)); + + context.swap(ctx); + return false; } diff --git a/lld/lib/Driver/InputGraph.cpp b/lld/lib/Driver/InputGraph.cpp new file mode 100644 index 000000000000..001cfed4e271 --- /dev/null +++ b/lld/lib/Driver/InputGraph.cpp @@ -0,0 +1,56 @@ +//===- lib/Driver/InputGraph.cpp ------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "lld/Driver/InputGraph.h" + +using namespace lld; + +namespace { +bool sortInputElements(const std::unique_ptr &a, + const std::unique_ptr &b) { + return a->getOrdinal() < b->getOrdinal(); +} +} + +bool InputGraph::addInputElement(std::unique_ptr ie) { + switch (ie->kind()) { + case InputElement::Kind::Control: + ++_numElements; + break; + case InputElement::Kind::File: + ++_numElements; + ++_numFiles; + break; + } + _inputArgs.push_back(std::move(ie)); + return true; +} + +bool InputGraph::assignOrdinals() { + for (auto &ie : _inputArgs) + ie->setOrdinal(++_ordinal); + return true; +} + +void InputGraph::doPostProcess() { + std::stable_sort(_inputArgs.begin(), _inputArgs.end(), sortInputElements); +} + +bool InputGraph::validate() { + for (auto &ie : _inputArgs) + if (!ie->validate()) + return false; + return true; +} + +bool InputGraph::dump(raw_ostream &diagnostics) { + for (auto &ie : _inputArgs) + if (!ie->dump(diagnostics)) + return false; + return true; +} diff --git a/lld/lib/Driver/LDOptions.td b/lld/lib/Driver/LDOptions.td index e941d547c9b1..8f5a87996df9 100644 --- a/lld/lib/Driver/LDOptions.td +++ b/lld/lib/Driver/LDOptions.td @@ -80,8 +80,18 @@ def undefined : Separate<["--"], "undefined">, Alias; def u_equal : Joined<["-"], "u=">, Alias; def undefined_equal : Joined<["--"], "undefined=">, Alias; +def as_needed : Flag<["--"], "as-needed">, + HelpText<"This option affects ELF DT_NEEDED tags for dynamic libraries mentioned on the command line">; +def no_as_needed : Flag<["--"], "no-as-needed">, + HelpText<"This option restores the default behavior of adding DT_NEEDED entries">; + // 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">; +def whole_archive: Flag<["--"], "whole-archive">, + HelpText<"Force load of all members in a static library">; +def no_whole_archive: Flag<["--"], "no-whole-archive">, + HelpText<"Restores the default behavior of loading archive members">; + +def all_load : Flag<["-"], "all_load">, + HelpText<"Forces all members of all static libraries to be loaded">; diff --git a/lld/lib/Driver/WinLinkDriver.cpp b/lld/lib/Driver/WinLinkDriver.cpp index 54dbe8432927..d863aa733629 100644 --- a/lld/lib/Driver/WinLinkDriver.cpp +++ b/lld/lib/Driver/WinLinkDriver.cpp @@ -17,15 +17,16 @@ #include #include +#include "lld/Driver/Driver.h" +#include "lld/Driver/WinLinkInputGraph.h" +#include "lld/ReaderWriter/PECOFFLinkingContext.h" + #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Option/Arg.h" #include "llvm/Option/Option.h" #include "llvm/Support/Path.h" -#include "lld/Driver/Driver.h" -#include "lld/ReaderWriter/PECOFFLinkingContext.h" - namespace lld { namespace { @@ -62,135 +63,6 @@ public: WinLinkOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){} }; -// Displays error message if the given version does not match with -// /^\d+$/. -bool checkNumber(StringRef version, const char *errorMessage, - raw_ostream &diagnostics) { - if (version.str().find_first_not_of("0123456789") != std::string::npos - || version.empty()) { - diagnostics << "error: " << errorMessage << version << "\n"; - return false; - } - return true; -} - -// Parse an argument for /base, /stack or /heap. The expected string -// is "[,]". -bool parseMemoryOption(const StringRef &arg, raw_ostream &diagnostics, - uint64_t &reserve, uint64_t &commit) { - StringRef reserveStr, commitStr; - llvm::tie(reserveStr, commitStr) = arg.split(','); - if (!checkNumber(reserveStr, "invalid size: ", diagnostics)) - return false; - reserve = atoi(reserveStr.str().c_str()); - if (!commitStr.empty()) { - if (!checkNumber(commitStr, "invalid size: ", diagnostics)) - return false; - commit = atoi(commitStr.str().c_str()); - } - return true; -} - -// Parse /base command line option. The argument for the parameter is in the -// form of "
[:]". -bool parseBaseOption(PECOFFLinkingContext &context, const StringRef &arg, - raw_ostream &diagnostics) { - // Size should be set to SizeOfImage field in the COFF header, and if it's - // smaller than the actual size, the linker should warn about that. Currently - // we just ignore the value of size parameter. - uint64_t addr, size; - if (!parseMemoryOption(arg, diagnostics, addr, size)) - return false; - // It's an error if the base address is not multiple of 64K. - if (addr & 0xffff) { - diagnostics << "Base address have to be multiple of 64K, but got " - << addr << "\n"; - return false; - } - context.setBaseAddress(addr); - return true; -} - -// Parse /stack command line option -bool parseStackOption(PECOFFLinkingContext &context, const StringRef &arg, - raw_ostream &diagnostics) { - uint64_t reserve; - uint64_t commit = context.getStackCommit(); - if (!parseMemoryOption(arg, diagnostics, reserve, commit)) - return false; - context.setStackReserve(reserve); - context.setStackCommit(commit); - return true; -} - -// Parse /heap command line option. -bool parseHeapOption(PECOFFLinkingContext &context, const StringRef &arg, - raw_ostream &diagnostics) { - uint64_t reserve; - uint64_t commit = context.getHeapCommit(); - if (!parseMemoryOption(arg, diagnostics, reserve, commit)) - return false; - context.setHeapReserve(reserve); - context.setHeapCommit(commit); - return true; -} - -// Returns subsystem type for the given string. -llvm::COFF::WindowsSubsystem stringToWinSubsystem(StringRef str) { - std::string arg(str.lower()); - return llvm::StringSwitch(arg) - .Case("windows", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI) - .Case("console", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI) - .Default(llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN); -} - -bool parseMinOSVersion(PECOFFLinkingContext &context, - const StringRef &osVersion, raw_ostream &diagnostics) { - StringRef majorVersion, minorVersion; - llvm::tie(majorVersion, minorVersion) = osVersion.split('.'); - if (minorVersion.empty()) - minorVersion = "0"; - if (!checkNumber(majorVersion, "invalid OS major version: ", diagnostics)) - return false; - if (!checkNumber(minorVersion, "invalid OS minor version: ", diagnostics)) - return false; - PECOFFLinkingContext::OSVersion minOSVersion( - atoi(majorVersion.str().c_str()), atoi(minorVersion.str().c_str())); - context.setMinOSVersion(minOSVersion); - return true; -} - -// Parse /subsystem command line option. The form of /subsystem is -// "subsystem_name[,majorOSVersion[.minorOSVersion]]". -bool parseSubsystemOption(PECOFFLinkingContext &context, std::string arg, - raw_ostream &diagnostics) { - StringRef subsystemStr, osVersionStr; - llvm::tie(subsystemStr, osVersionStr) = StringRef(arg).split(','); - - // Parse optional OS version if exists. - if (!osVersionStr.empty()) - if (!parseMinOSVersion(context, osVersionStr, diagnostics)) - return false; - - // Parse subsystem name. - llvm::COFF::WindowsSubsystem subsystem = stringToWinSubsystem(subsystemStr); - if (subsystem == llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN) { - diagnostics << "error: unknown subsystem name: " << subsystemStr << "\n"; - return false; - } - context.setSubsystem(subsystem); - return true; -} - -// Replace a file extension with ".exe". If the given file has no -// extension, just add ".exe". -StringRef getDefaultOutputFileName(PECOFFLinkingContext &context, - StringRef path) { - SmallString<128> smallStr = path; - llvm::sys::path::replace_extension(smallStr, ".exe"); - return context.allocateString(smallStr.str()); -} - // Split the given string with spaces. std::vector splitArgList(std::string str) { std::stringstream stream(str); @@ -210,6 +82,26 @@ std::vector splitPathList(StringRef str) { return std::move(ret); } +// Parse an argument for /base, /stack or /heap. The expected string +// is "[,]". +bool parseMemoryOption(StringRef arg, uint64_t &reserve, uint64_t &commit) { + StringRef reserveStr, commitStr; + llvm::tie(reserveStr, commitStr) = arg.split(','); + if (reserveStr.getAsInteger(0, reserve)) + return true; + if (!commitStr.empty() && (commitStr.getAsInteger(0, commit))) + return true; + return false; +} + +// Returns subsystem type for the given string. +llvm::COFF::WindowsSubsystem stringToWinSubsystem(StringRef str) { + return llvm::StringSwitch(str.lower()) + .Case("windows", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI) + .Case("console", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI) + .Default(llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN); +} + // Handle /failifmatch option. bool handleFailIfMismatchOption(StringRef option, std::map &mustMatch, @@ -218,26 +110,16 @@ bool handleFailIfMismatchOption(StringRef option, llvm::tie(key, value) = option.split('='); if (key.empty() || value.empty()) { diagnostics << "error: malformed /failifmatch option: " << option << "\n"; - return false; + return true; } auto it = mustMatch.find(key); if (it != mustMatch.end() && it->second != value) { diagnostics << "error: mismatch detected: '" << it->second << "' and '" << value << "' for key '" << key << "'\n"; - return false; + return true; } mustMatch[key] = value; - return true; -} - -// Add ".lib" extension if the path does not already have the extension to mimic -// link.exe behavior. -StringRef canonicalizeImportLibraryPath(PECOFFLinkingContext &context, - StringRef path) { - std::string s(path.lower()); - if (StringRef(s).endswith(".lib")) - return path; - return context.allocateString(std::string(path).append(".lib")); + return false; } // Process "LINK" environment variable. If defined, the value of the variable @@ -299,6 +181,29 @@ std::unique_ptr parseArgs(int argc, const char *argv[], } // namespace +std::unique_ptr +PECOFFFileNode::createLinkerInput(const LinkingContext &ctx) { + return std::unique_ptr(new LinkerInput(path(ctx))); +} + +std::unique_ptr +PECOFFLibraryNode::createLinkerInput(const LinkingContext &ctx) { + return std::unique_ptr(new LinkerInput(path(ctx))); +} + +StringRef PECOFFFileNode::path(const LinkingContext &) const { + if (_path.endswith(".lib")) + return _ctx.searchLibraryFile(_path); + if (llvm::sys::path::extension(_path).empty()) + return (_path.str() + ".obj"); + return _path; +} + +StringRef PECOFFLibraryNode::path(const LinkingContext &) const { + if (!_path.endswith(".lib")) + return _ctx.searchLibraryFile(_path.str() + ".lib"); + return _ctx.searchLibraryFile(_path); +} bool WinLinkDriver::linkPECOFF(int argc, const char *argv[], raw_ostream &diagnostics) { @@ -311,14 +216,19 @@ bool WinLinkDriver::linkPECOFF(int argc, const char *argv[], } bool WinLinkDriver::parse(int argc, const char *argv[], - PECOFFLinkingContext &context, - raw_ostream &diagnostics) { + PECOFFLinkingContext &ctx, raw_ostream &diagnostics) { + std::map failIfMismatchMap; // Parse the options. std::unique_ptr parsedArgs = parseArgs( argc, argv, diagnostics); if (!parsedArgs) return true; + if (!ctx.hasInputGraph()) + ctx.setInputGraph(std::unique_ptr(new InputGraph())); + + InputGraph &inputGraph = ctx.inputGraph(); + // handle /help if (parsedArgs->getLastArg(OPT_help)) { WinLinkOptTable table; @@ -326,75 +236,6 @@ bool WinLinkDriver::parse(int argc, const char *argv[], return true; } - // Copy -mllvm - for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_mllvm), - ie = parsedArgs->filtered_end(); - it != ie; ++it) { - context.appendLLVMOption((*it)->getValue()); - } - - // handle /base - if (llvm::opt::Arg *arg = parsedArgs->getLastArg(OPT_base)) - if (!parseBaseOption(context, arg->getValue(), diagnostics)) - return true; - - // handle /stack - if (llvm::opt::Arg *arg = parsedArgs->getLastArg(OPT_stack)) - if (!parseStackOption(context, arg->getValue(), diagnostics)) - return true; - - // handle /heap - if (llvm::opt::Arg *arg = parsedArgs->getLastArg(OPT_heap)) - if (!parseHeapOption(context, arg->getValue(), diagnostics)) - return true; - - // handle /subsystem - if (llvm::opt::Arg *arg = parsedArgs->getLastArg(OPT_subsystem)) - if (!parseSubsystemOption(context, arg->getValue(), diagnostics)) - return true; - - // handle /entry - if (llvm::opt::Arg *arg = parsedArgs->getLastArg(OPT_entry)) - context.setEntrySymbolName(arg->getValue()); - - // handle /libpath - for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_libpath), - ie = parsedArgs->filtered_end(); - it != ie; ++it) { - context.appendInputSearchPath((*it)->getValue()); - } - - // handle /force - if (parsedArgs->getLastArg(OPT_force)) - context.setAllowRemainingUndefines(true); - - // handle /nxcompat:no - if (parsedArgs->getLastArg(OPT_no_nxcompat)) - context.setNxCompat(false); - - // handle /largeaddressaware - if (parsedArgs->getLastArg(OPT_largeaddressaware)) - context.setLargeAddressAware(true); - - // handle /fixed - if (parsedArgs->getLastArg(OPT_fixed)) - context.setBaseRelocationEnabled(false); - - // handle /tsaware:no - if (parsedArgs->getLastArg(OPT_no_tsaware)) - context.setTerminalServerAware(false); - - // handle /include - for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_incl), - ie = parsedArgs->filtered_end(); - it != ie; ++it) { - context.addInitialUndefinedSymbol((*it)->getValue()); - } - - // handle /out - if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_out)) - context.setOutputPath(outpath->getValue()); - // handle /defaultlib std::vector defaultLibs; for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_defaultlib), @@ -403,29 +244,143 @@ bool WinLinkDriver::parse(int argc, const char *argv[], defaultLibs.push_back((*it)->getValue()); } - // Handle /failifmismatch. /failifmismatch is the hidden linker option behind - // the scenes of "detect_mismatch" pragma. If the compiler finds "#pragma - // detect_mismatch(name, value)", it outputs "/failifmismatch:name=value" to - // the .drectve section of the resultant object file. The linker raises an - // error if conflicting /failmismatch options are given. Conflicting options - // are the options with the same key but with different values. - // - // This feature is used to prevent inconsistent object files from linking. - std::map mustMatch; - for (llvm::opt::arg_iterator - it = parsedArgs->filtered_begin(OPT_failifmismatch), - ie = parsedArgs->filtered_end(); - it != ie; ++it) { - if (!handleFailIfMismatchOption((*it)->getValue(), mustMatch, diagnostics)) - return true; - } + // Process all the arguments and create Input Elements + for (auto inputArg : *parsedArgs) { + switch (inputArg->getOption().getID()) { + case OPT_mllvm: + ctx.appendLLVMOption(inputArg->getValue()); + break; - // Add input files - std::vector inputPaths; - for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_INPUT), - ie = parsedArgs->filtered_end(); - it != ie; ++it) { - inputPaths.push_back((*it)->getValue()); + case OPT_base: + // Parse /base command line option. The argument for the parameter is in + // the + // form of "
[:]". + uint64_t addr, size; + // Size should be set to SizeOfImage field in the COFF header, and if + // it's smaller than the actual size, the linker should warn about that. + // Currently we just ignore the value of size parameter. + if (parseMemoryOption(inputArg->getValue(), addr, size)) + return true; + // It's an error if the base address is not multiple of 64K. + // TODO: move this to validation of LinkingContext + if (addr & 0xffff) { + diagnostics << "Base address have to be multiple of 64K, but got " + << addr << "\n"; + return true; + } + ctx.setBaseAddress(addr); + break; + case OPT_stack: { + // Parse /stack command line option + uint64_t reserve; + uint64_t commit = ctx.getStackCommit(); + if (parseMemoryOption(inputArg->getValue(), reserve, commit)) + return true; + ctx.setStackReserve(reserve); + ctx.setStackCommit(commit); + } break; + case OPT_heap: { + // Parse /heap command line option + uint64_t reserve; + uint64_t commit = ctx.getHeapCommit(); + if (parseMemoryOption(inputArg->getValue(), reserve, commit)) + return true; + ctx.setHeapReserve(reserve); + ctx.setHeapCommit(commit); + } break; + case OPT_subsystem: { + // Parse /subsystem command line option. The form of /subsystem is + // "subsystem_name[,majorOSVersion[.minorOSVersion]]". + StringRef subsystemStr, osVersion; + llvm::tie(subsystemStr, osVersion) = + StringRef(inputArg->getValue()).split(','); + if (!osVersion.empty()) { + StringRef majorVersion, minorVersion; + llvm::tie(majorVersion, minorVersion) = osVersion.split('.'); + if (minorVersion.empty()) + minorVersion = "0"; + int32_t major, minor; + if (majorVersion.getAsInteger(0, major)) + return true; + if (minorVersion.getAsInteger(0, minor)) + return true; + ctx.setMinOSVersion(PECOFFLinkingContext::OSVersion(major, minor)); + } + // Parse subsystem name. + llvm::COFF::WindowsSubsystem subsystem = + stringToWinSubsystem(subsystemStr); + if (subsystem == llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN) { + diagnostics << "error: unknown subsystem name: " << subsystemStr + << "\n"; + return true; + } + ctx.setSubsystem(subsystem); + } break; + + case OPT_failifmismatch: + if (handleFailIfMismatchOption(inputArg->getValue(), failIfMismatchMap, + diagnostics)) + return true; + break; + + case OPT_entry: + // handle /entry + ctx.setEntrySymbolName(inputArg->getValue()); + break; + + case OPT_libpath: + // handle /libpath + ctx.appendInputSearchPath(inputArg->getValue()); + break; + + case OPT_force: + // handle /force + ctx.setAllowRemainingUndefines(true); + break; + + case OPT_no_nxcompat: + // handle /nxcompat:no + ctx.setNxCompat(false); + break; + + case OPT_largeaddressaware: + // handle /largeaddressaware + ctx.setLargeAddressAware(true); + break; + + case OPT_fixed: + // handle /fixed + ctx.setBaseRelocationEnabled(false); + break; + + case OPT_tsaware: + // handle /tsaware + ctx.setTerminalServerAware(true); + break; + + case OPT_no_tsaware: + // handle /tsaware:no + ctx.setTerminalServerAware(false); + break; + + case OPT_incl: + // handle /incl + ctx.addInitialUndefinedSymbol(inputArg->getValue()); + break; + + case OPT_out: + // handle /out + ctx.setOutputPath(inputArg->getValue()); + break; + + case OPT_INPUT: { + inputGraph.addInputElement(std::unique_ptr( + new PECOFFFileNode(ctx, inputArg->getValue()))); + } break; + + default: + break; + } } // Arguments after "--" are interpreted as filenames even if they @@ -433,27 +388,33 @@ bool WinLinkDriver::parse(int argc, const char *argv[], // but useful for us to test lld on Unix. if (llvm::opt::Arg *dashdash = parsedArgs->getLastArg(OPT_DASH_DASH)) { for (const StringRef value : dashdash->getValues()) - inputPaths.push_back(value); + inputGraph.addInputElement( + std::unique_ptr(new PECOFFFileNode(ctx, value))); } - // Add input files specified via the command line. - for (const StringRef path : inputPaths) - context.appendInputFileOrLibrary(path); + // Add ".lib" extension if the path does not already have the extension to + // mimic link.exe behavior. + for (auto defaultLibPath : defaultLibs) + inputGraph.addInputElement(std::unique_ptr( + new PECOFFLibraryNode(ctx, defaultLibPath))); - // Add the library files specified by /defaultlib option. The files - // specified by the option should have lower precedence than the other files - // added above, which is important for link.exe compatibility. - for (const StringRef path : defaultLibs) - context.appendLibraryFile(canonicalizeImportLibraryPath(context, path)); + if (!inputGraph.numFiles()) { + diagnostics << "No input files\n"; + return true; + } // If /out option was not specified, the default output file name is // constructed by replacing an extension of the first input file // with ".exe". - if (context.outputPath().empty() && !inputPaths.empty()) - context.setOutputPath(getDefaultOutputFileName(context, inputPaths[0])); + if (ctx.outputPath().empty()) { + SmallString<128> firstInputFilePath = + (llvm::dyn_cast(&((inputGraph)[0])))->path(ctx); + (llvm::sys::path::replace_extension(firstInputFilePath, ".exe")); + ctx.setOutputPath(firstInputFilePath.str()); + } // Validate the combination of options used. - return context.validate(diagnostics); + return ctx.validate(diagnostics); } } // namespace lld diff --git a/lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp b/lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp index c1b16c267a13..e19a4be573b9 100644 --- a/lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp +++ b/lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp @@ -64,11 +64,6 @@ bool ELFLinkingContext::validateImpl(raw_ostream &diagnostics) { _entrySymbolName = "_start"; } - if (_inputFiles.empty()) { - diagnostics << "No input files\n"; - return true; - } - _elfReader = createReaderELF(*this); _linkerScriptReader.reset(new ReaderLinkerScript(*this)); _writer = _outputYAML ? createWriterYAML(*this) : createWriterELF(*this); @@ -131,10 +126,11 @@ ELFLinkingContext::create(llvm::Triple triple) { } } -bool ELFLinkingContext::appendLibrary(StringRef libName) { +StringRef ELFLinkingContext::searchLibrary( + StringRef libName, const std::vector &searchPath) const { bool foundFile = false; StringRef pathref; - for (StringRef dir : _inputSearchPaths) { + for (StringRef dir : searchPath) { // Search for dynamic library if (!_isStaticExecutable) { SmallString<128> dynlibPath; @@ -155,15 +151,10 @@ bool ELFLinkingContext::appendLibrary(StringRef libName) { foundFile = true; } } - if (foundFile) { - unsigned pathlen = pathref.size(); - char *x = _extraStrings.Allocate(pathlen); - memcpy(x, pathref.data(), pathlen); - appendInputFile(StringRef(x, pathlen)); - return false; - } + if (foundFile) + return (*(new (_alloc) std::string(pathref.str()))); } - return true; + return libName; } } // end namespace lld diff --git a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp index 1594ba55f994..7c80ffe8e2cc 100644 --- a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp +++ b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp @@ -8,10 +8,10 @@ //===----------------------------------------------------------------------===// #include "lld/ReaderWriter/MachOLinkingContext.h" +#include "lld/ReaderWriter/MachOFormat.hpp" #include "GOTPass.hpp" #include "StubsPass.hpp" #include "ReferenceKinds.h" -#include "MachOFormat.hpp" #include "lld/Core/PassManager.h" #include "lld/ReaderWriter/Reader.h" @@ -205,11 +205,6 @@ bool MachOLinkingContext::addUnixThreadLoadCommand() const { } bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) { - if (_inputFiles.empty()) { - diagnostics << "no object files specified\n"; - return true; - } - if ((_outputFileType == mach_o::MH_EXECUTE) && _entrySymbolName.empty()) { if (_outputFileTypeStatic) { _entrySymbolName = "start"; diff --git a/lld/lib/ReaderWriter/MachO/WriterMachO.cpp b/lld/lib/ReaderWriter/MachO/WriterMachO.cpp index ad55b287a22d..a4fa214cea48 100644 --- a/lld/lib/ReaderWriter/MachO/WriterMachO.cpp +++ b/lld/lib/ReaderWriter/MachO/WriterMachO.cpp @@ -31,12 +31,12 @@ #include "lld/Core/Reference.h" #include "lld/Core/SharedLibraryAtom.h" #include "lld/ReaderWriter/MachOLinkingContext.h" +#include "lld/ReaderWriter/MachOFormat.hpp" #include #include #include -#include "MachOFormat.hpp" #include "ReferenceKinds.h" #include "ExecutableAtoms.hpp" @@ -568,8 +568,9 @@ 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(), - &atomContent[offset], fixupAddress, targetAddress); + _writer.kindHandler().applyFixup(ref->kind(), ref->addend(), + &atomContent[offset], fixupAddress, + targetAddress); } } } diff --git a/lld/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp b/lld/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp index 4dbb5d70a46f..9f0b1430c364 100644 --- a/lld/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp +++ b/lld/lib/ReaderWriter/PECOFF/PECOFFLinkingContext.cpp @@ -25,13 +25,7 @@ namespace lld { -namespace { -bool containDirectoryName(StringRef path) { - SmallString<128> smallStr = StringRef(path); - llvm::sys::path::remove_filename(smallStr); - return !smallStr.str().empty(); -} -} // anonymous namespace +namespace {} // anonymous namespace error_code PECOFFLinkingContext::parseFile( std::unique_ptr &mb, @@ -40,11 +34,6 @@ error_code PECOFFLinkingContext::parseFile( } bool PECOFFLinkingContext::validateImpl(raw_ostream &diagnostics) { - if (_inputFiles.empty()) { - diagnostics << "No input files\n"; - return true; - } - if (_stackReserve < _stackCommit) { diagnostics << "Invalid stack size: reserve size must be equal to or " << "greater than commit size, but got " << _stackCommit @@ -73,45 +62,20 @@ void PECOFFLinkingContext::addImplicitFiles(InputFiles &files) const { files.appendFile(*linkerFile); } -/// Append the given file to the input file list. The file must be an object -/// file or an import library file. -void PECOFFLinkingContext::appendInputFileOrLibrary(std::string path) { - StringRef ext = llvm::sys::path::extension(path); - // This is an import library file. Look for the library file in the search - // paths, unless the path contains a directory name. - if (ext.equals_lower(".lib")) { - if (containDirectoryName(path)) { - appendInputFile(path); - return; - } - appendLibraryFile(path); - return; - } - // This is an object file otherwise. Add ".obj" extension if the given path - // name has no file extension. - if (ext.empty()) - path.append(".obj"); - appendInputFile(allocateString(path)); -} - /// Try to find the input library file from the search paths and append it to /// the input file list. Returns true if the library file is found. -void PECOFFLinkingContext::appendLibraryFile(StringRef filename) { +StringRef PECOFFLinkingContext::searchLibraryFile(StringRef filename) const { // Current directory always takes precedence over the search paths. - if (llvm::sys::fs::exists(filename)) { - appendInputFile(filename); - return; - } + if (llvm::sys::path::is_absolute(filename) || llvm::sys::fs::exists(filename)) + return filename; // Iterate over the search paths. for (StringRef dir : _inputSearchPaths) { SmallString<128> path = dir; llvm::sys::path::append(path, filename); - if (llvm::sys::fs::exists(path.str())) { - appendInputFile(allocateString(path.str())); - return; - } + if (llvm::sys::fs::exists(path.str())) + return (*(new (_alloc) std::string(path.str()))); } - appendInputFile(filename); + return filename; } Writer &PECOFFLinkingContext::writer() const { return *_writer; } diff --git a/lld/lib/ReaderWriter/ReaderLinkerScript.cpp b/lld/lib/ReaderWriter/ReaderLinkerScript.cpp index 4e16ac86398b..e7f1ad98fdf8 100644 --- a/lld/lib/ReaderWriter/ReaderLinkerScript.cpp +++ b/lld/lib/ReaderWriter/ReaderLinkerScript.cpp @@ -87,7 +87,7 @@ error_code ReaderLinkerScript::parseFile( const LinkerScript *ls = (*lsf)->getScript(); result.push_back(std::move(*lsf)); for (const auto &c : ls->_commands) { - if (auto group = dyn_cast(c)) + if (auto group = dyn_cast(c)) for (const auto &path : group->getPaths()) { if (error_code ec = _context.readFile(path._path, result)) return ec; diff --git a/lld/test/Driver/libsearch-inputGraph.test b/lld/test/Driver/libsearch-inputGraph.test new file mode 100644 index 000000000000..45510ffc2ebf --- /dev/null +++ b/lld/test/Driver/libsearch-inputGraph.test @@ -0,0 +1,34 @@ +RUN: lld -flavor gnu -L%p/../elf/Inputs -lfnarchive -emit-yaml 2> %t.err +RUN: FileCheck %s < %t.err +RUN: lld -flavor gnu -L%p/../elf/Inputs --whole-archive -lfnarchive -emit-yaml 2> %t1.err +RUN: FileCheck %s -check-prefix="WHOLEARCHIVE" < %t1.err +RUN: lld -flavor gnu -L%p/../elf/Inputs --whole-archive --as-needed -lfnarchive -emit-yaml 2> %t2.err +RUN: FileCheck %s -check-prefix="ASNEEDED" < %t2.err + +CHECK: Name : {{[^ ]+}}elf/Inputs{{[\\/]}}libfnarchive.a +CHECK: Type : ELF File +CHECK: Ordinal : -1 +CHECK: Attributes : +CHECK: - wholeArchive : false +CHECK: - asNeeded : false +CHECK: contextPath : +CHECK: - {{[^ ]+}}elf/Inputs + +WHOLEARCHIVE: Name : {{[^ ]+}}elf/Inputs{{[\\/]}}libfnarchive.a +WHOLEARCHIVE: Type : ELF File +WHOLEARCHIVE: Ordinal : -1 +WHOLEARCHIVE: Attributes : +WHOLEARCHIVE: - wholeArchive : true +WHOLEARCHIVE: - asNeeded : false +WHOLEARCHIVE: contextPath : +WHOLEARCHIVE: - {{[^ ]+}}elf/Inputs + +ASNEEDED: Name : {{[^ ]+}}elf/Inputs{{[\\/]}}libfnarchive.a +ASNEEDED: Type : ELF File +ASNEEDED: Ordinal : -1 +ASNEEDED: Attributes : +ASNEEDED: - wholeArchive : true +ASNEEDED: - asNeeded : true +ASNEEDED: contextPath : +ASNEEDED: - {{[^ ]+}}elf/Inputs + diff --git a/lld/test/elf/X86_64/nmagic.test b/lld/test/elf/X86_64/nmagic.test index 1a1163f58e67..8ca081aefd6e 100644 --- a/lld/test/elf/X86_64/nmagic.test +++ b/lld/test/elf/X86_64/nmagic.test @@ -2,7 +2,7 @@ # PT_LOAD, PT_TLS # The data segment should be aligned to a page boundary RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/nmagic.o \ -RUN: --noinhibit-exec -o %t --nmagic +RUN: --noinhibit-exec -o %t --nmagic -static RUN: llvm-readobj -sections %t | FileCheck -check-prefix=NMAGICSECTIONS %s RUN: llvm-readobj -program-headers %t | FileCheck -check-prefix=NMAGICPROGRAMHEADERS %s diff --git a/lld/test/elf/X86_64/omagic.test b/lld/test/elf/X86_64/omagic.test index ec84a810ad8b..e5f220c75aa6 100644 --- a/lld/test/elf/X86_64/omagic.test +++ b/lld/test/elf/X86_64/omagic.test @@ -2,7 +2,7 @@ # PT_LOAD, PT_TLS # The data segment should not be aligned to a page boundary RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/nmagic.o \ -RUN: --noinhibit-exec -o %t --omagic +RUN: --noinhibit-exec -o %t --omagic -static RUN: llvm-readobj -sections %t | FileCheck -check-prefix=OMAGICSECTIONS %s RUN: llvm-readobj -program-headers %t | FileCheck -check-prefix=OMAGICPROGRAMHEADERS %s diff --git a/lld/test/elf/archive-elf-forceload.objtxt b/lld/test/elf/archive-elf-forceload.objtxt index 1c2bc385a899..a8200a4bc2ed 100644 --- a/lld/test/elf/archive-elf-forceload.objtxt +++ b/lld/test/elf/archive-elf-forceload.objtxt @@ -24,7 +24,7 @@ # gcc -c main.c fn.c fn1.c 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: %p/Inputs/libfnarchive.a -all_load -emit-yaml \ RUN: | FileCheck -check-prefix FORCELOAD %s FORCELOAD: defined-atoms: diff --git a/lld/unittests/DriverTests/DarwinLdDriverTest.cpp b/lld/unittests/DriverTests/DarwinLdDriverTest.cpp index de1b306b25d3..2fb4df3612f4 100644 --- a/lld/unittests/DriverTests/DarwinLdDriverTest.cpp +++ b/lld/unittests/DriverTests/DarwinLdDriverTest.cpp @@ -15,7 +15,7 @@ #include "DriverTest.h" #include "lld/ReaderWriter/MachOLinkingContext.h" -#include "../../lib/ReaderWriter/MachO/MachOFormat.hpp" +#include "lld/ReaderWriter/MachOFormat.hpp" using namespace llvm; using namespace lld; diff --git a/lld/unittests/DriverTests/DriverTest.h b/lld/unittests/DriverTests/DriverTest.h index 1090828ddd09..0ad191855289 100644 --- a/lld/unittests/DriverTests/DriverTest.h +++ b/lld/unittests/DriverTests/DriverTest.h @@ -30,11 +30,14 @@ protected: std::string &errorMessage() { return _errorMessage; } // Convenience method for getting number of input files. - int inputFileCount() { return linkingContext()->inputFiles().size(); } + int inputFileCount() { return linkingContext()->inputGraph().numFiles(); } // Convenience method for getting i'th input files name. std::string inputFile(unsigned index) { - return linkingContext()->inputFiles()[index].getPath().str(); + const InputElement &inputElement = linkingContext()->inputGraph()[index]; + if (inputElement.kind() == InputElement::Kind::File) + return (llvm::dyn_cast(&inputElement))->path(*linkingContext()); + assert(0 && "not handling other types of input files"); } // For unit tests to call driver with various command lines.