parent
0dc00645a2
commit
e44104b001
|
@ -23,6 +23,9 @@
|
|||
#include <vector>
|
||||
|
||||
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.
|
||||
|
|
|
@ -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<LinkerInput> &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) {
|
||||
_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<const char *> _llvmOptions;
|
||||
std::unique_ptr<Reader> _yamlReader;
|
||||
StringRefVector _initialUndefinedSymbols;
|
||||
std::unique_ptr<InputGraph> _inputGraph;
|
||||
|
||||
private:
|
||||
/// Validate the subclass bits. Only called by validate.
|
||||
|
|
|
@ -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 <map>
|
||||
|
||||
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<lld::LinkerInput>
|
||||
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
|
|
@ -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 <map>
|
||||
|
||||
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<lld::LinkerInput>
|
||||
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
|
|
@ -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
|
||||
|
|
|
@ -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<StringRef> 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<lld::LinkerInput>
|
||||
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<StringRef> _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<lld::LinkerInput>
|
||||
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
|
|
@ -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 <memory>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
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<std::unique_ptr<InputElement> > 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<InputElement>);
|
||||
|
||||
/// \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<InputElement> 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<LinkerInput>
|
||||
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<LinkerInput>
|
||||
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<InputElement> element) {
|
||||
_elements.push_back(std::move(element));
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<lld::LinkerInput>
|
||||
createLinkerInput(const lld::LinkingContext &) = 0;
|
||||
};
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif // LLD_INPUTGRAPH_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<llvm::MemoryBuffer> 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<llvm::MemoryBuffer> _buffer;
|
||||
std::string _file;
|
||||
bool _isForceLoad : 1;
|
||||
bool _asNeeded : 1;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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 <map>
|
||||
|
||||
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<lld::LinkerInput>
|
||||
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<lld::LinkerInput>
|
||||
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
|
|
@ -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<StringRef> &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<Reader> _elfReader;
|
||||
std::unique_ptr<Writer> _writer;
|
||||
std::unique_ptr<Reader> _linkerScriptReader;
|
||||
|
|
|
@ -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 <mach-o/loader.h> 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<uint32_t*>(_registerArray);
|
||||
uint64_t *regs64 = reinterpret_cast<uint64_t*>(_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 {
|
|
@ -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<MemoryBuffer> &mb,
|
||||
std::vector<std::unique_ptr<File> > &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<Reference::Kind> relocKindFromString(StringRef str) const;
|
||||
virtual ErrorOr<std::string> stringFromRelocKind(Reference::Kind kind) const;
|
||||
|
||||
StringRef allocateString(const StringRef &ref) {
|
||||
StringRef allocateString(StringRef ref) {
|
||||
char *x = _alloc.Allocate<char>(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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<lld::LinkerInput>
|
||||
COREFileNode::createLinkerInput(const LinkingContext &info) {
|
||||
return std::unique_ptr<LinkerInput>(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<llvm::opt::InputArgList> 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> 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<InputElement>(
|
||||
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
|
||||
|
|
|
@ -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<lld::LinkerInput>
|
||||
MachOFileNode::createLinkerInput(const LinkingContext &ctx) {
|
||||
return std::unique_ptr<LinkerInput>(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<llvm::opt::InputArgList> 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> 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<InputElement>(
|
||||
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
|
||||
|
||||
|
||||
|
|
|
@ -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<std::vector<std::unique_ptr<File>> > files(
|
||||
context.inputFiles().size());
|
||||
std::vector<std::vector<std::unique_ptr<File> > > files(
|
||||
inputGraph.numFiles());
|
||||
size_t index = 0;
|
||||
std::atomic<bool> fail(false);
|
||||
TaskGroup tg;
|
||||
for (const auto &input : context.inputFiles()) {
|
||||
std::vector<std::unique_ptr<LinkerInput> > linkerInputs;
|
||||
for (auto &ie : inputGraph) {
|
||||
if (ie->kind() == InputElement::Kind::File) {
|
||||
FileNode *fileNode = (llvm::dyn_cast<FileNode>)(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;
|
||||
|
|
|
@ -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<lld::LinkerInput>
|
||||
ELFFileNode::createLinkerInput(const LinkingContext &ctx) {
|
||||
std::unique_ptr<LinkerInput> 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<ELFLinkingContext> 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<ELFLinkingContext> options(ELFLinkingContext::create(triple));
|
||||
std::unique_ptr<ELFLinkingContext> 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> inputGraph(new InputGraph());
|
||||
std::stack<InputElement *> controlNodeStack;
|
||||
|
||||
// Handle -emit-yaml
|
||||
if (parsedArgs->getLastArg(OPT_emit_yaml))
|
||||
options->setOutputYAML(true);
|
||||
// Positional options for an Input File
|
||||
std::vector<StringRef> 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<InputElement> controlStart(new ELFGroup(*ctx));
|
||||
controlNodeStack.push(controlStart.get());
|
||||
(llvm::dyn_cast<ControlNode>)(controlNodeStack.top())
|
||||
->processControlEnter();
|
||||
inputGraph->addInputElement(std::move(controlStart));
|
||||
} break;
|
||||
|
||||
case OPT_end_group:
|
||||
(llvm::dyn_cast<ControlNode>)(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<InputElement> inputFile =
|
||||
std::move(std::unique_ptr<InputElement>(
|
||||
new ELFFileNode(*ctx, inputArg->getValue(), isWholeArchive,
|
||||
asNeeded, searchPath)));
|
||||
if (controlNodeStack.empty())
|
||||
inputGraph->addInputElement(std::move(inputFile));
|
||||
else
|
||||
(llvm::dyn_cast<ControlNode>)(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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<InputElement> &a,
|
||||
const std::unique_ptr<InputElement> &b) {
|
||||
return a->getOrdinal() < b->getOrdinal();
|
||||
}
|
||||
}
|
||||
|
||||
bool InputGraph::addInputElement(std::unique_ptr<InputElement> 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;
|
||||
}
|
|
@ -80,8 +80,18 @@ def undefined : Separate<["--"], "undefined">, Alias<u>;
|
|||
def u_equal : Joined<["-"], "u=">, Alias<u>;
|
||||
def undefined_equal : Joined<["--"], "undefined=">, Alias<u>;
|
||||
|
||||
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">;
|
||||
|
|
|
@ -17,15 +17,16 @@
|
|||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
#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 "<integer>[,<integer>]".
|
||||
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 "<address>[:<size>]".
|
||||
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<llvm::COFF::WindowsSubsystem>(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<std::string> splitArgList(std::string str) {
|
||||
std::stringstream stream(str);
|
||||
|
@ -210,6 +82,26 @@ std::vector<StringRef> splitPathList(StringRef str) {
|
|||
return std::move(ret);
|
||||
}
|
||||
|
||||
// Parse an argument for /base, /stack or /heap. The expected string
|
||||
// is "<integer>[,<integer>]".
|
||||
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<llvm::COFF::WindowsSubsystem>(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<StringRef, StringRef> &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<llvm::opt::InputArgList> parseArgs(int argc, const char *argv[],
|
|||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<lld::LinkerInput>
|
||||
PECOFFFileNode::createLinkerInput(const LinkingContext &ctx) {
|
||||
return std::unique_ptr<LinkerInput>(new LinkerInput(path(ctx)));
|
||||
}
|
||||
|
||||
std::unique_ptr<lld::LinkerInput>
|
||||
PECOFFLibraryNode::createLinkerInput(const LinkingContext &ctx) {
|
||||
return std::unique_ptr<LinkerInput>(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<StringRef, StringRef> failIfMismatchMap;
|
||||
// Parse the options.
|
||||
std::unique_ptr<llvm::opt::InputArgList> parsedArgs = parseArgs(
|
||||
argc, argv, diagnostics);
|
||||
if (!parsedArgs)
|
||||
return true;
|
||||
|
||||
if (!ctx.hasInputGraph())
|
||||
ctx.setInputGraph(std::unique_ptr<InputGraph>(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<StringRef> 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<StringRef, StringRef> 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<StringRef> 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 "<address>[:<size>]".
|
||||
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<InputElement>(
|
||||
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<InputElement>(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<InputElement>(
|
||||
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<FileNode>(&((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
|
||||
|
|
|
@ -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<StringRef> &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<char>(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
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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 <vector>
|
||||
#include <map>
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<MemoryBuffer> &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; }
|
||||
|
|
|
@ -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<Group>(c))
|
||||
if (auto group = dyn_cast<lld::script::Group>(c))
|
||||
for (const auto &path : group->getPaths()) {
|
||||
if (error_code ec = _context.readFile(path._path, result))
|
||||
return ec;
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<FileNode>(&inputElement))->path(*linkingContext());
|
||||
assert(0 && "not handling other types of input files");
|
||||
}
|
||||
|
||||
// For unit tests to call driver with various command lines.
|
||||
|
|
Loading…
Reference in New Issue