forked from OSchip/llvm-project
[lld][LinkingContext] Atoms created from command line options should be available in YAML
This adds an API to the LinkingContext for flavors to add Internal files containing atoms that need to appear in the YAML output as well, when -emit-yaml switch is used. Flavors can add more internal files for other options that are needed. llvm-svn: 189718
This commit is contained in:
parent
2c4f8b7ee8
commit
d26c8e3463
|
@ -53,7 +53,7 @@ public:
|
|||
|
||||
/// Name of symbol linker should use as "entry point" to program,
|
||||
/// usually "main" or "start".
|
||||
StringRef entrySymbolName() const { return _entrySymbolName; }
|
||||
virtual StringRef entrySymbolName() const { return _entrySymbolName; }
|
||||
|
||||
/// Whether core linking should remove Atoms not reachable by following
|
||||
/// References from the entry point Atom or from all global scope Atoms
|
||||
|
@ -184,9 +184,7 @@ public:
|
|||
// Set the entry symbol name. You may also need to call addDeadStripRoot() for
|
||||
// the symbol if your platform supports dead-stripping, so that the symbol
|
||||
// will not be removed from the output.
|
||||
void setEntrySymbolName(StringRef name) {
|
||||
// Entry function have to be resolved as an undefined symbol.
|
||||
addInitialUndefinedSymbol(name);
|
||||
virtual void setEntrySymbolName(StringRef name) {
|
||||
_entrySymbolName = name;
|
||||
}
|
||||
|
||||
|
@ -234,6 +232,12 @@ public:
|
|||
typedef StringRefVector::iterator StringRefVectorIter;
|
||||
typedef StringRefVector::const_iterator StringRefVectorConstIter;
|
||||
|
||||
/// Create linker internal files containing atoms for the linker to include
|
||||
/// during link. Flavors can override this function in their LinkingContext
|
||||
/// to add more internal files. These internal files are positioned before
|
||||
/// the actual input files.
|
||||
virtual std::vector<std::unique_ptr<lld::File> > createInternalFiles();
|
||||
|
||||
/// Return the list of undefined symbols that are specified in the
|
||||
/// linker command line, using the -u option.
|
||||
range<const StringRef *> initialUndefinedSymbols() const {
|
||||
|
@ -320,6 +324,12 @@ protected:
|
|||
/// Abstract method to lazily instantiate the Writer.
|
||||
virtual Writer &writer() const = 0;
|
||||
|
||||
/// Method to create a internal file for the entry symbol
|
||||
virtual std::unique_ptr<File> createEntrySymbolFile();
|
||||
|
||||
/// Method to create a internal file for an undefined symbol
|
||||
virtual std::unique_ptr<File> createUndefinedSymbolFile();
|
||||
|
||||
StringRef _outputPath;
|
||||
StringRef _entrySymbolName;
|
||||
bool _deadStrip;
|
||||
|
@ -338,6 +348,7 @@ protected:
|
|||
std::unique_ptr<Reader> _yamlReader;
|
||||
StringRefVector _initialUndefinedSymbols;
|
||||
std::unique_ptr<InputGraph> _inputGraph;
|
||||
llvm::BumpPtrAllocator _allocator;
|
||||
|
||||
private:
|
||||
/// Validate the subclass bits. Only called by validate.
|
||||
|
|
|
@ -34,19 +34,18 @@ class LinkingContext;
|
|||
/// 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
|
||||
/// to do when it processes the option.
|
||||
/// Each InputElement that is part of the Graph has an Ordinal value
|
||||
/// associated with it. The ordinal value is needed for the Writer to figure out
|
||||
/// the relative position of the arguments that appeared in the Command Line.
|
||||
/// InputElements have a weight function that can be used to determine the
|
||||
/// weight of the file, for statistical purposes.
|
||||
class InputGraph {
|
||||
public:
|
||||
typedef std::vector<std::unique_ptr<InputElement> > InputElementVectorT;
|
||||
typedef InputElementVectorT::iterator InputElementIterT;
|
||||
typedef std::vector<std::unique_ptr<File> > FileVectorT;
|
||||
typedef FileVectorT::iterator FileIterT;
|
||||
|
||||
/// \brief Initialize the inputgraph
|
||||
InputGraph() : _ordinal(0), _numElements(0), _numFiles(0) {}
|
||||
|
@ -66,16 +65,27 @@ public:
|
|||
/// Total number of InputElements
|
||||
virtual int64_t numElements() const { return _numElements; }
|
||||
|
||||
/// Total number of Internal files
|
||||
virtual int64_t numInternalFiles() const { return _internalFiles.size(); }
|
||||
|
||||
/// \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(); }
|
||||
virtual void addInternalFile(std::vector<std::unique_ptr<File> > inputFiles) {
|
||||
for (auto &ai : inputFiles)
|
||||
_internalFiles.push_back(std::move(ai));
|
||||
}
|
||||
|
||||
InputElementIterT end() { return _inputArgs.end(); }
|
||||
range<FileIterT> internalFiles() {
|
||||
return make_range(_internalFiles.begin(), _internalFiles.end());
|
||||
}
|
||||
|
||||
range<InputElementIterT> inputElements() {
|
||||
return make_range(_inputArgs.begin(), _inputArgs.end());
|
||||
}
|
||||
|
||||
/// \brief Validate the input graph
|
||||
virtual bool validate();
|
||||
|
@ -90,6 +100,8 @@ public:
|
|||
private:
|
||||
// Input arguments
|
||||
InputElementVectorT _inputArgs;
|
||||
// Extra Input files
|
||||
FileVectorT _internalFiles;
|
||||
// Ordinals
|
||||
int64_t _ordinal;
|
||||
// Total number of InputElements
|
||||
|
@ -103,9 +115,9 @@ private:
|
|||
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
|
||||
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
|
||||
|
@ -147,9 +159,9 @@ 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
|
||||
enum class ControlKind : uint8_t{
|
||||
Simple, // Represents a simple control node
|
||||
Group // Represents a type associated with ControlNodes
|
||||
};
|
||||
|
||||
ControlNode(ControlNode::ControlKind controlKind =
|
||||
|
|
|
@ -10,9 +10,11 @@
|
|||
#ifndef LLD_READER_WRITER_ELF_LINKER_CONTEXT_H
|
||||
#define LLD_READER_WRITER_ELF_LINKER_CONTEXT_H
|
||||
|
||||
#include "lld/Core/LinkingContext.h"
|
||||
#include "lld/Core/PassManager.h"
|
||||
#include "lld/Core/Pass.h"
|
||||
#include "lld/Core/LinkingContext.h"
|
||||
#include "lld/Core/range.h"
|
||||
|
||||
#include "lld/ReaderWriter/Reader.h"
|
||||
#include "lld/ReaderWriter/Writer.h"
|
||||
|
||||
|
@ -38,11 +40,11 @@ public:
|
|||
class ELFLinkingContext : public LinkingContext {
|
||||
public:
|
||||
enum class OutputMagic : uint8_t {
|
||||
DEFAULT, // The default mode, no specific magic set
|
||||
NMAGIC, // Disallow shared libraries and dont align sections
|
||||
// PageAlign Data, Mark Text Segment/Data segment RW
|
||||
OMAGIC // Disallow shared libraries and dont align sections,
|
||||
// Mark Text Segment/Data segment RW
|
||||
DEFAULT, // The default mode, no specific magic set
|
||||
NMAGIC, // Disallow shared libraries and dont align sections
|
||||
// PageAlign Data, Mark Text Segment/Data segment RW
|
||||
OMAGIC // Disallow shared libraries and dont align sections,
|
||||
// Mark Text Segment/Data segment RW
|
||||
};
|
||||
llvm::Triple getTriple() const { return _triple; }
|
||||
virtual bool is64Bits() const;
|
||||
|
@ -154,6 +156,9 @@ public:
|
|||
StringRef searchLibrary(StringRef libName,
|
||||
const std::vector<StringRef> &searchPath) const;
|
||||
|
||||
/// Get the entry symbol name
|
||||
virtual StringRef entrySymbolName() const;
|
||||
|
||||
private:
|
||||
ELFLinkingContext() LLVM_DELETED_FUNCTION;
|
||||
|
||||
|
@ -162,6 +167,9 @@ protected:
|
|||
|
||||
virtual Writer &writer() const;
|
||||
|
||||
/// Method to create a internal file for an undefined symbol
|
||||
virtual std::unique_ptr<File> createUndefinedSymbolFile();
|
||||
|
||||
uint16_t _outputFileType; // e.g ET_EXEC
|
||||
llvm::Triple _triple;
|
||||
std::unique_ptr<TargetHandlerBase> _targetHandler;
|
||||
|
|
|
@ -122,6 +122,13 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Method to create a internal file for the entry symbol
|
||||
virtual std::unique_ptr<File> createEntrySymbolFile();
|
||||
|
||||
/// Method to create a internal file for an undefined symbol
|
||||
virtual std::unique_ptr<File> createUndefinedSymbolFile();
|
||||
|
||||
private:
|
||||
// The start address for the program. The default value for the executable is
|
||||
// 0x400000, but can be altered using -base command line option.
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "lld/Core/LinkingContext.h"
|
||||
#include "lld/Core/InputFiles.h"
|
||||
#include "lld/ReaderWriter/Writer.h"
|
||||
#include "lld/ReaderWriter/Simple.h"
|
||||
|
||||
#include "llvm/ADT/Triple.h"
|
||||
|
||||
|
@ -50,6 +52,39 @@ void LinkingContext::addImplicitFiles(InputFiles &inputs) const {
|
|||
this->writer().addFiles(inputs);
|
||||
}
|
||||
|
||||
std::unique_ptr<File> LinkingContext::createEntrySymbolFile() {
|
||||
if (entrySymbolName().empty())
|
||||
return nullptr;
|
||||
std::unique_ptr<SimpleFile> entryFile(
|
||||
new SimpleFile(*this, "command line option -entry"));
|
||||
entryFile->addAtom(
|
||||
*(new (_allocator) SimpleUndefinedAtom(*entryFile, entrySymbolName())));
|
||||
return std::move(entryFile);
|
||||
}
|
||||
|
||||
std::unique_ptr<File> LinkingContext::createUndefinedSymbolFile() {
|
||||
if (_initialUndefinedSymbols.empty())
|
||||
return nullptr;
|
||||
std::unique_ptr<SimpleFile> undefinedSymFile(
|
||||
new SimpleFile(*this, "command line option -u"));
|
||||
for (auto undefSymStr : _initialUndefinedSymbols)
|
||||
undefinedSymFile->addAtom(*(new (_allocator) SimpleUndefinedAtom(
|
||||
*undefinedSymFile, undefSymStr)));
|
||||
return std::move(undefinedSymFile);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<File> > LinkingContext::createInternalFiles() {
|
||||
std::vector<std::unique_ptr<File> > result;
|
||||
std::unique_ptr<File> internalFile;
|
||||
internalFile = createEntrySymbolFile();
|
||||
if (internalFile)
|
||||
result.push_back(std::move(internalFile));
|
||||
internalFile = createUndefinedSymbolFile();
|
||||
if (internalFile)
|
||||
result.push_back(std::move(internalFile));
|
||||
return result;
|
||||
}
|
||||
|
||||
void LinkingContext::addPasses(PassManager &pm) const {}
|
||||
|
||||
} // end namespace lld
|
||||
|
|
|
@ -52,7 +52,7 @@ bool Driver::link(const LinkingContext &context, raw_ostream &diagnostics) {
|
|||
std::atomic<bool> fail(false);
|
||||
TaskGroup tg;
|
||||
std::vector<std::unique_ptr<LinkerInput> > linkerInputs;
|
||||
for (auto &ie : inputGraph) {
|
||||
for (auto &ie : inputGraph.inputElements()) {
|
||||
if (ie->kind() == InputElement::Kind::File) {
|
||||
FileNode *fileNode = (llvm::dyn_cast<FileNode>)(ie.get());
|
||||
linkerInputs.push_back(std::move(fileNode->createLinkerInput(context)));
|
||||
|
@ -79,6 +79,10 @@ bool Driver::link(const LinkingContext &context, raw_ostream &diagnostics) {
|
|||
return true;
|
||||
|
||||
InputFiles inputs;
|
||||
|
||||
for (auto &f : inputGraph.internalFiles())
|
||||
inputs.appendFile(*f.get());
|
||||
|
||||
for (auto &f : files)
|
||||
inputs.appendFiles(f);
|
||||
|
||||
|
|
|
@ -289,6 +289,8 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
|
|||
return true;
|
||||
}
|
||||
|
||||
inputGraph->addInternalFile(ctx->createInternalFiles());
|
||||
|
||||
if (ctx->outputYAML())
|
||||
inputGraph->dump(diagnostics);
|
||||
|
||||
|
|
|
@ -471,6 +471,11 @@ bool WinLinkDriver::parse(int argc, const char *argv[],
|
|||
return true;
|
||||
}
|
||||
|
||||
// A list of undefined symbols will be added to the input
|
||||
// file list to force the core linker to try to resolve
|
||||
// the undefined symbols.
|
||||
inputGraph.addInternalFile(ctx.createInternalFiles());
|
||||
|
||||
// If /out option was not specified, the default output file name is
|
||||
// constructed by replacing an extension of the first input file
|
||||
// with ".exe".
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "lld/ReaderWriter/ELFLinkingContext.h"
|
||||
|
||||
#include "File.h"
|
||||
#include "TargetHandler.h"
|
||||
#include "Targets.h"
|
||||
|
||||
|
@ -22,6 +23,17 @@
|
|||
#include "llvm/Support/Path.h"
|
||||
|
||||
namespace lld {
|
||||
|
||||
class CommandLineUndefinedAtom : public SimpleUndefinedAtom {
|
||||
public:
|
||||
CommandLineUndefinedAtom(const File &f, StringRef name)
|
||||
: SimpleUndefinedAtom(f, name) {}
|
||||
|
||||
virtual CanBeNull canBeNull() const {
|
||||
return CanBeNull::canBeNullAtBuildtime;
|
||||
}
|
||||
};
|
||||
|
||||
ELFLinkingContext::ELFLinkingContext(
|
||||
llvm::Triple triple, std::unique_ptr<TargetHandlerBase> targetHandler)
|
||||
: _outputFileType(elf::ET_EXEC), _triple(triple),
|
||||
|
@ -29,8 +41,7 @@ ELFLinkingContext::ELFLinkingContext(
|
|||
_isStaticExecutable(false), _outputYAML(false), _noInhibitExec(false),
|
||||
_mergeCommonStrings(false), _runLayoutPass(true),
|
||||
_useShlibUndefines(false), _dynamicLinkerArg(false),
|
||||
_noAllowDynamicLibraries(false),
|
||||
_outputMagic(OutputMagic::DEFAULT) {}
|
||||
_noAllowDynamicLibraries(false), _outputMagic(OutputMagic::DEFAULT) {}
|
||||
|
||||
bool ELFLinkingContext::is64Bits() const { return getTriple().isArch64Bit(); }
|
||||
|
||||
|
@ -59,11 +70,13 @@ uint16_t ELFLinkingContext::getOutputMachine() const {
|
|||
}
|
||||
}
|
||||
|
||||
bool ELFLinkingContext::validateImpl(raw_ostream &diagnostics) {
|
||||
if (_outputFileType == elf::ET_EXEC && _entrySymbolName.empty()) {
|
||||
_entrySymbolName = "_start";
|
||||
}
|
||||
StringRef ELFLinkingContext::entrySymbolName() const {
|
||||
if (_outputFileType == elf::ET_EXEC && _entrySymbolName.empty())
|
||||
return "_start";
|
||||
return _entrySymbolName;
|
||||
}
|
||||
|
||||
bool ELFLinkingContext::validateImpl(raw_ostream &diagnostics) {
|
||||
_elfReader = createReaderELF(*this);
|
||||
_linkerScriptReader.reset(new ReaderLinkerScript(*this));
|
||||
_writer = _outputYAML ? createWriterYAML(*this) : createWriterELF(*this);
|
||||
|
@ -157,4 +170,15 @@ StringRef ELFLinkingContext::searchLibrary(
|
|||
return libName;
|
||||
}
|
||||
|
||||
std::unique_ptr<File> ELFLinkingContext::createUndefinedSymbolFile() {
|
||||
if (_initialUndefinedSymbols.empty())
|
||||
return nullptr;
|
||||
std::unique_ptr<SimpleFile> undefinedSymFile(
|
||||
new SimpleFile(*this, "command line option -u"));
|
||||
for (auto undefSymStr : _initialUndefinedSymbols)
|
||||
undefinedSymFile->addAtom(*(new (_allocator) CommandLineUndefinedAtom(
|
||||
*undefinedSymFile, undefSymStr)));
|
||||
return std::move(undefinedSymFile);
|
||||
}
|
||||
|
||||
} // end namespace lld
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
//===- lib/ReaderWriter/ELF/ExecutableAtoms.h -----------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_READER_WRITER_ELF_EXECUTABLE_ATOM_H
|
||||
#define LLD_READER_WRITER_ELF_EXECUTABLE_ATOM_H
|
||||
|
||||
#include "Atoms.h"
|
||||
#include "File.h"
|
||||
|
||||
#include "lld/Core/DefinedAtom.h"
|
||||
#include "lld/Core/File.h"
|
||||
#include "lld/Core/Reference.h"
|
||||
#include "lld/Core/UndefinedAtom.h"
|
||||
#include "lld/ReaderWriter/Writer.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
/// \brief All atoms are owned by a File. To add linker specific atoms
|
||||
/// the atoms need to be inserted to a file called (CRuntimeFile) which
|
||||
/// are basically additional symbols required by libc and other runtime
|
||||
/// libraries part of executing a program. This class provides support
|
||||
/// for adding absolute symbols and undefined symbols
|
||||
template <class ELFT> class CRuntimeFile : public ELFFile<ELFT> {
|
||||
public:
|
||||
typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
|
||||
CRuntimeFile(const ELFLinkingContext &context, StringRef name = "C runtime")
|
||||
: ELFFile<ELFT>(context, name) {}
|
||||
|
||||
/// \brief add a global absolute atom
|
||||
virtual void addAbsoluteAtom(StringRef symbolName) {
|
||||
Elf_Sym *symbol = new (_allocator.Allocate<Elf_Sym>()) Elf_Sym;
|
||||
symbol->st_name = 0;
|
||||
symbol->st_value = 0;
|
||||
symbol->st_shndx = llvm::ELF::SHN_ABS;
|
||||
symbol->setBindingAndType(llvm::ELF::STB_GLOBAL,
|
||||
llvm::ELF::STT_OBJECT);
|
||||
symbol->st_other = llvm::ELF::STV_DEFAULT;
|
||||
symbol->st_size = 0;
|
||||
auto *newAtom =
|
||||
new (_allocator) ELFAbsoluteAtom<ELFT>(*this, symbolName, symbol, -1);
|
||||
_absoluteAtoms._atoms.push_back(newAtom);
|
||||
}
|
||||
|
||||
/// \brief add an undefined atom
|
||||
virtual void addUndefinedAtom(StringRef symbolName) {
|
||||
assert(!symbolName.empty() && "UndefinedAtoms must have a name");
|
||||
Elf_Sym *symbol = new (_allocator) Elf_Sym;
|
||||
symbol->st_name = 0;
|
||||
symbol->st_value = 0;
|
||||
symbol->st_shndx = llvm::ELF::SHN_UNDEF;
|
||||
symbol->st_other = llvm::ELF::STV_DEFAULT;
|
||||
symbol->st_size = 0;
|
||||
auto *newAtom =
|
||||
new (_allocator) ELFUndefinedAtom<ELFT>(*this, symbolName, symbol);
|
||||
_undefinedAtoms._atoms.push_back(newAtom);
|
||||
}
|
||||
|
||||
virtual const File::atom_collection<DefinedAtom> &defined() const {
|
||||
return _definedAtoms;
|
||||
}
|
||||
|
||||
virtual const File::atom_collection<UndefinedAtom> &undefined() const {
|
||||
return _undefinedAtoms;
|
||||
}
|
||||
|
||||
virtual const File::atom_collection<SharedLibraryAtom> &sharedLibrary() const {
|
||||
return _sharedLibraryAtoms;
|
||||
}
|
||||
|
||||
virtual const File::atom_collection<AbsoluteAtom> &absolute() const {
|
||||
return _absoluteAtoms;
|
||||
}
|
||||
|
||||
// cannot add atoms to C Runtime file
|
||||
virtual void addAtom(const Atom &) {
|
||||
llvm_unreachable("cannot add atoms to Runtime files");
|
||||
}
|
||||
|
||||
protected:
|
||||
llvm::BumpPtrAllocator _allocator;
|
||||
File::atom_collection_vector<DefinedAtom> _definedAtoms;
|
||||
File::atom_collection_vector<UndefinedAtom> _undefinedAtoms;
|
||||
File::atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
|
||||
File::atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
|
||||
};
|
||||
} // end namespace elf
|
||||
} // end namespace lld
|
||||
|
||||
#endif
|
|
@ -737,6 +737,79 @@ private:
|
|||
/// \brief the cached options relevant while reading the ELF File
|
||||
bool _doStringsMerge : 1;
|
||||
};
|
||||
|
||||
/// \brief All atoms are owned by a File. To add linker specific atoms
|
||||
/// the atoms need to be inserted to a file called (CRuntimeFile) which
|
||||
/// are basically additional symbols required by libc and other runtime
|
||||
/// libraries part of executing a program. This class provides support
|
||||
/// for adding absolute symbols and undefined symbols
|
||||
template <class ELFT> class CRuntimeFile : public ELFFile<ELFT> {
|
||||
public:
|
||||
typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
|
||||
CRuntimeFile(const ELFLinkingContext &context, StringRef name = "C runtime")
|
||||
: ELFFile<ELFT>(context, name) {}
|
||||
|
||||
/// \brief add a global absolute atom
|
||||
virtual Atom *addAbsoluteAtom(StringRef symbolName) {
|
||||
assert(!symbolName.empty() && "AbsoluteAtoms must have a name");
|
||||
Elf_Sym *symbol = new (_allocator) Elf_Sym;
|
||||
symbol->st_name = 0;
|
||||
symbol->st_value = 0;
|
||||
symbol->st_shndx = llvm::ELF::SHN_ABS;
|
||||
symbol->setBindingAndType(llvm::ELF::STB_GLOBAL, llvm::ELF::STT_OBJECT);
|
||||
symbol->st_other = llvm::ELF::STV_DEFAULT;
|
||||
symbol->st_size = 0;
|
||||
auto *newAtom =
|
||||
new (_allocator) ELFAbsoluteAtom<ELFT>(*this, symbolName, symbol, -1);
|
||||
_absoluteAtoms._atoms.push_back(newAtom);
|
||||
return newAtom;
|
||||
}
|
||||
|
||||
/// \brief add an undefined atom
|
||||
virtual Atom *addUndefinedAtom(StringRef symbolName) {
|
||||
assert(!symbolName.empty() && "UndefinedAtoms must have a name");
|
||||
Elf_Sym *symbol = new (_allocator) Elf_Sym;
|
||||
symbol->st_name = 0;
|
||||
symbol->st_value = 0;
|
||||
symbol->st_shndx = llvm::ELF::SHN_UNDEF;
|
||||
symbol->st_other = llvm::ELF::STV_DEFAULT;
|
||||
symbol->st_size = 0;
|
||||
auto *newAtom =
|
||||
new (_allocator) ELFUndefinedAtom<ELFT>(*this, symbolName, symbol);
|
||||
_undefinedAtoms._atoms.push_back(newAtom);
|
||||
return newAtom;
|
||||
}
|
||||
|
||||
virtual const File::atom_collection<DefinedAtom> &defined() const {
|
||||
return _definedAtoms;
|
||||
}
|
||||
|
||||
virtual const File::atom_collection<UndefinedAtom> &undefined() const {
|
||||
return _undefinedAtoms;
|
||||
}
|
||||
|
||||
virtual const File::atom_collection<SharedLibraryAtom> &
|
||||
sharedLibrary() const {
|
||||
return _sharedLibraryAtoms;
|
||||
}
|
||||
|
||||
virtual const File::atom_collection<AbsoluteAtom> &absolute() const {
|
||||
return _absoluteAtoms;
|
||||
}
|
||||
|
||||
// cannot add atoms to C Runtime file
|
||||
virtual void addAtom(const Atom &) {
|
||||
llvm_unreachable("cannot add atoms to Runtime files");
|
||||
}
|
||||
|
||||
protected:
|
||||
llvm::BumpPtrAllocator _allocator;
|
||||
File::atom_collection_vector<DefinedAtom> _definedAtoms;
|
||||
File::atom_collection_vector<UndefinedAtom> _undefinedAtoms;
|
||||
File::atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
|
||||
File::atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
|
||||
};
|
||||
|
||||
} // end namespace elf
|
||||
} // end namespace lld
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#ifndef LLD_READER_WRITER_ELF_HEXAGON_EXECUTABLE_ATOM_H
|
||||
#define LLD_READER_WRITER_ELF_HEXAGON_EXECUTABLE_ATOM_H
|
||||
|
||||
#include "ExecutableAtoms.h"
|
||||
#include "File.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
|
|
|
@ -17,25 +17,15 @@
|
|||
#include "llvm/ADT/StringSet.h"
|
||||
|
||||
#include "DefaultLayout.h"
|
||||
#include "File.h"
|
||||
#include "TargetLayout.h"
|
||||
#include "ExecutableAtoms.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
using namespace llvm;
|
||||
using namespace llvm::object;
|
||||
|
||||
template<class ELFT>
|
||||
class OutputELFWriter;
|
||||
|
||||
/// \brief This acts as a internal file that the linker uses to add
|
||||
/// undefined symbols that are defined by using the linker options such
|
||||
/// as -u, or --defsym option.
|
||||
template <class ELFT> class LinkerInternalFile : public CRuntimeFile<ELFT> {
|
||||
public:
|
||||
LinkerInternalFile(const ELFLinkingContext &context)
|
||||
: CRuntimeFile<ELFT>(context, "Linker Internal File") {};
|
||||
};
|
||||
template <class ELFT> class OutputELFWriter;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// OutputELFWriter Class
|
||||
|
@ -123,7 +113,6 @@ protected:
|
|||
LLD_UNIQUE_BUMP_PTR(HashSection<ELFT>) _hashTable;
|
||||
llvm::StringSet<> _soNeeded;
|
||||
/// @}
|
||||
LinkerInternalFile<ELFT> _linkerInternalFile;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -131,8 +120,7 @@ protected:
|
|||
//===----------------------------------------------------------------------===//
|
||||
template <class ELFT>
|
||||
OutputELFWriter<ELFT>::OutputELFWriter(const ELFLinkingContext &context)
|
||||
: _context(context), _targetHandler(context.getTargetHandler<ELFT>()),
|
||||
_linkerInternalFile(context) {
|
||||
: _context(context), _targetHandler(context.getTargetHandler<ELFT>()) {
|
||||
_layout = &_targetHandler.targetLayout();
|
||||
}
|
||||
|
||||
|
@ -238,12 +226,6 @@ template <class ELFT>
|
|||
void OutputELFWriter<ELFT>::addFiles(InputFiles &inputFiles) {
|
||||
// Add all input Files that are defined by the target
|
||||
_targetHandler.addFiles(inputFiles);
|
||||
// Add all symbols that are specified by the -u option
|
||||
// as part of the command line argument to lld
|
||||
for (auto ai : _context.initialUndefinedSymbols())
|
||||
_linkerInternalFile.addUndefinedAtom(ai);
|
||||
// Make the linker internal file to be the first file
|
||||
inputFiles.prependFile(_linkerInternalFile);
|
||||
}
|
||||
|
||||
template <class ELFT> void OutputELFWriter<ELFT>::createDefaultSections() {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
|
||||
/// \brief x86-64 internal references.
|
||||
enum {
|
||||
/// \brief The 32 bit index of the relocation in the got this reference refers
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#define LLD_READER_WRITER_ELF_X86_64_TARGET_HANDLER_H
|
||||
|
||||
#include "DefaultTargetHandler.h"
|
||||
#include "File.h"
|
||||
#include "X86_64RelocationHandler.h"
|
||||
#include "TargetLayout.h"
|
||||
|
||||
|
|
|
@ -111,23 +111,5 @@ private:
|
|||
MemberFile _memberFile;
|
||||
};
|
||||
|
||||
/// An instance of UndefinedSymbolFile has a list of undefined symbols
|
||||
/// specified by "/include" command line option. This will be added to the
|
||||
/// input file list to force the core linker to try to resolve the undefined
|
||||
/// symbols.
|
||||
class UndefinedSymbolFile : public SimpleFile {
|
||||
public:
|
||||
UndefinedSymbolFile(const LinkingContext &ctx)
|
||||
: SimpleFile(ctx, "Linker Internal File") {
|
||||
for (StringRef symbol : ctx.initialUndefinedSymbols()) {
|
||||
UndefinedAtom *atom = new (_alloc) coff::COFFUndefinedAtom(*this, symbol);
|
||||
addAtom(*atom);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::BumpPtrAllocator _alloc;
|
||||
};
|
||||
|
||||
} // end namespace coff
|
||||
} // end namespace lld
|
||||
|
|
|
@ -53,11 +53,28 @@ bool PECOFFLinkingContext::validateImpl(raw_ostream &diagnostics) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void PECOFFLinkingContext::addImplicitFiles(InputFiles &files) const {
|
||||
// Add a pseudo file for "/include" linker option.
|
||||
auto *undefFile = new (_alloc) coff::UndefinedSymbolFile(*this);
|
||||
files.prependFile(*undefFile);
|
||||
std::unique_ptr<File> PECOFFLinkingContext::createEntrySymbolFile() {
|
||||
if (entrySymbolName().empty())
|
||||
return nullptr;
|
||||
std::unique_ptr<SimpleFile> entryFile(
|
||||
new SimpleFile(*this, "command line option /entry"));
|
||||
entryFile->addAtom(
|
||||
*(new (_allocator) SimpleUndefinedAtom(*entryFile, entrySymbolName())));
|
||||
return std::move(entryFile);
|
||||
}
|
||||
|
||||
std::unique_ptr<File> PECOFFLinkingContext::createUndefinedSymbolFile() {
|
||||
if (_initialUndefinedSymbols.empty())
|
||||
return nullptr;
|
||||
std::unique_ptr<SimpleFile> undefinedSymFile(
|
||||
new SimpleFile(*this, "command line option /c (or) /include"));
|
||||
for (auto undefSymStr : _initialUndefinedSymbols)
|
||||
undefinedSymFile->addAtom(*(new (_allocator) SimpleUndefinedAtom(
|
||||
*undefinedSymFile, undefSymStr)));
|
||||
return std::move(undefinedSymFile);
|
||||
}
|
||||
|
||||
void PECOFFLinkingContext::addImplicitFiles(InputFiles &files) const {
|
||||
auto *linkerFile = new (_alloc) coff::LinkerGeneratedSymbolFile(*this);
|
||||
files.appendFile(*linkerFile);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
RUN: lld -flavor gnu -L%p/../elf/Inputs -lfnarchive -emit-yaml 2> %t.err
|
||||
RUN: lld -flavor gnu -L%p/../elf/Inputs -lfnarchive -emit-yaml --noinhibit-exec 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: lld -flavor gnu -L%p/../elf/Inputs --whole-archive -lfnarchive -emit-yaml --noinhibit-exec 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: lld -flavor gnu -L%p/../elf/Inputs --whole-archive --as-needed -lfnarchive -emit-yaml --noinhibit-exec 2> %t2.err
|
||||
RUN: FileCheck %s -check-prefix="ASNEEDED" < %t2.err
|
||||
|
||||
CHECK: Name : {{[^ ]+}}elf/Inputs{{[\\/]}}libfnarchive.a
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
RUN: lld -flavor gnu -target hexagon %p/Inputs/use-shared.hexagon \
|
||||
RUN: -emit-yaml -o %t2
|
||||
RUN: -emit-yaml --noinhibit-exec -o %t2
|
||||
RUN: FileCheck %s < %t2
|
||||
|
||||
CHECK: - name: fn3
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# Any typeZeroFill content wouldnot have space reserved in the file to store
|
||||
# its content
|
||||
|
||||
RUN: lld -flavor gnu -target x86_64 %p/Inputs/largebss.o -emit-yaml | FileCheck %s
|
||||
RUN: lld -flavor gnu -target x86_64 %p/Inputs/largebss.o -emit-yaml --noinhibit-exec | FileCheck %s
|
||||
|
||||
|
||||
CHECK: - name: largecommon
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
RUN: lld -flavor gnu -target hexagon -static -emit-yaml %p/Inputs/branch-test.hexagon %p/Inputs/target-test.hexagon | FileCheck %s -check-prefix hexagon-yaml
|
||||
RUN: lld -flavor gnu -target hexagon -e target -o %t1 %p/Inputs/branch-test.hexagon %p/Inputs/target-test.hexagon
|
||||
RUN: lld -flavor gnu -target hexagon -static -emit-yaml \
|
||||
RUN: %p/Inputs/branch-test.hexagon %p/Inputs/target-test.hexagon --noinhibit-exec | FileCheck %s -check-prefix hexagon-yaml
|
||||
RUN: lld -flavor gnu -target hexagon -e target -o %t1 \
|
||||
RUN: %p/Inputs/branch-test.hexagon %p/Inputs/target-test.hexagon --noinhibit-exec
|
||||
RUN: llvm-readobj -h %t1 | FileCheck -check-prefix=hexagon-readobj %s
|
||||
|
||||
hexagon-yaml: - name: back
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# The test checks for mergeable strings that appear in the object file
|
||||
RUN: lld -flavor gnu --merge-strings -emit-yaml %p/Inputs/constants-merge.x86-64 | FileCheck -check-prefix=mergeAtoms %s
|
||||
RUN: lld -flavor gnu --merge-strings -emit-yaml %p/Inputs/constants-merge.x86-64 --noinhibit-exec | FileCheck -check-prefix=mergeAtoms %s
|
||||
|
||||
mergeAtoms: - ref-name: [[CONSTANT:[-a-zA-Z0-9_]+]]
|
||||
mergeAtoms: type: constant
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# ELF files can have mergeable strings which are global!, treat them as global
|
||||
# defined atoms
|
||||
RUN: lld -flavor gnu -emit-yaml %p/Inputs/globalconst.o.x86-64 \
|
||||
RUN: | FileCheck -check-prefix=globalatoms %s
|
||||
RUN: --noinhibit-exec | FileCheck -check-prefix=globalatoms %s
|
||||
|
||||
globalatoms: - name: mystr
|
||||
globalatoms: scope: global
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
RUN: lld -flavor gnu -target hexagon -emit-yaml %p/Inputs/quickdata-test.elf-hexagon \
|
||||
RUN: | FileCheck %s -check-prefix hexagon
|
||||
RUN: --noinhibit-exec | FileCheck %s -check-prefix hexagon
|
||||
|
||||
hexagon: - name: ac1
|
||||
hexagon: scope: global
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
# RUN: /include:sym1 /include:sym2 -- %t.obj 2> %t1
|
||||
# RUN: FileCheck %s < %t1
|
||||
|
||||
CHECK: Undefined Symbol: Linker Internal File : sym1
|
||||
CHECK: Undefined Symbol: Linker Internal File : sym2
|
||||
CHECK: Undefined Symbol: command line option /c (or) /include : sym1
|
||||
CHECK: Undefined Symbol: command line option /c (or) /include : sym2
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# RUN: lld -flavor gnu -u undefinedsymbol -e entrysymbol %s -emit-yaml \
|
||||
# RUN: --noinhibit-exec | FileCheck %s
|
||||
|
||||
#
|
||||
# Test that we are able to add undefined atoms from the command line
|
||||
#
|
||||
|
||||
---
|
||||
absolute-atoms:
|
||||
- name: putchar
|
||||
value: 0xFFFF0040
|
||||
|
||||
- name: reset
|
||||
value: 0xFFFF0080
|
||||
|
||||
...
|
||||
|
||||
|
||||
# CHECK: undefined-atoms:
|
||||
# CHECK: - name: entrysymbol
|
||||
# CHECK: - name: undefinedsymbol
|
||||
# CHECK: can-be-null: at-buildtime
|
|
@ -55,8 +55,6 @@ TEST_F(WinLinkParserTest, Basic) {
|
|||
EXPECT_TRUE(_context.isTerminalServerAware());
|
||||
EXPECT_TRUE(_context.getDynamicBaseEnabled());
|
||||
EXPECT_TRUE(_context.deadStrip());
|
||||
EXPECT_FALSE(_context.initialUndefinedSymbols().empty());
|
||||
EXPECT_EQ("_start", _context.initialUndefinedSymbols()[0]);
|
||||
}
|
||||
|
||||
TEST_F(WinLinkParserTest, UnixStyleOption) {
|
||||
|
|
Loading…
Reference in New Issue