hanchenye-llvm-project/lld/lib/ReaderWriter/CoreLinkingContext.cpp

277 lines
7.6 KiB
C++
Raw Normal View History

//===- lib/ReaderWriter/CoreLinkingContext.cpp ----------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lld/ReaderWriter/CoreLinkingContext.h"
#include "lld/Core/Pass.h"
#include "lld/Core/PassManager.h"
#include "lld/Passes/LayoutPass.h"
#include "lld/Passes/RoundTripYAMLPass.h"
#include "lld/ReaderWriter/Simple.h"
#include "llvm/ADT/ArrayRef.h"
using namespace lld;
namespace {
/// \brief Simple atom created by the stubs pass.
class TestingStubAtom : public DefinedAtom {
public:
TestingStubAtom(const File &F, const Atom &) : _file(F) {
static uint32_t lastOrdinal = 0;
_ordinal = lastOrdinal++;
}
virtual const File &file() const { return _file; }
virtual StringRef name() const { return StringRef(); }
virtual uint64_t ordinal() const { return _ordinal; }
virtual uint64_t size() const { return 0; }
virtual Scope scope() const { return DefinedAtom::scopeLinkageUnit; }
virtual Interposable interposable() const { return DefinedAtom::interposeNo; }
virtual Merge merge() const { return DefinedAtom::mergeNo; }
virtual ContentType contentType() const { return DefinedAtom::typeStub; }
virtual Alignment alignment() const { return Alignment(0, 0); }
virtual SectionChoice sectionChoice() const {
return DefinedAtom::sectionBasedOnContent;
}
virtual StringRef customSectionName() const { return StringRef(); }
virtual SectionPosition sectionPosition() const { return sectionPositionAny; }
virtual DeadStripKind deadStrip() const {
return DefinedAtom::deadStripNormal;
}
virtual ContentPermissions permissions() const {
return DefinedAtom::permR_X;
}
virtual bool isAlias() const { return false; }
virtual ArrayRef<uint8_t> rawContent() const { return ArrayRef<uint8_t>(); }
virtual reference_iterator begin() const {
return reference_iterator(*this, nullptr);
}
virtual reference_iterator end() const {
return reference_iterator(*this, nullptr);
}
virtual const Reference *derefIterator(const void *iter) const {
return nullptr;
}
virtual void incrementIterator(const void *&iter) const {}
private:
const File &_file;
uint32_t _ordinal;
};
/// \brief Simple atom created by the GOT pass.
class TestingGOTAtom : public DefinedAtom {
public:
TestingGOTAtom(const File &F, const Atom &) : _file(F) {
static uint32_t lastOrdinal = 0;
_ordinal = lastOrdinal++;
}
virtual const File &file() const { return _file; }
virtual StringRef name() const { return StringRef(); }
virtual uint64_t ordinal() const { return _ordinal; }
virtual uint64_t size() const { return 0; }
virtual Scope scope() const { return DefinedAtom::scopeLinkageUnit; }
virtual Interposable interposable() const { return DefinedAtom::interposeNo; }
virtual Merge merge() const { return DefinedAtom::mergeNo; }
virtual ContentType contentType() const { return DefinedAtom::typeGOT; }
virtual Alignment alignment() const { return Alignment(3, 0); }
virtual SectionChoice sectionChoice() const {
return DefinedAtom::sectionBasedOnContent;
}
virtual StringRef customSectionName() const { return StringRef(); }
virtual SectionPosition sectionPosition() const { return sectionPositionAny; }
virtual DeadStripKind deadStrip() const {
return DefinedAtom::deadStripNormal;
}
virtual ContentPermissions permissions() const {
return DefinedAtom::permRW_;
}
virtual bool isAlias() const { return false; }
virtual ArrayRef<uint8_t> rawContent() const { return ArrayRef<uint8_t>(); }
virtual reference_iterator begin() const {
return reference_iterator(*this, nullptr);
}
virtual reference_iterator end() const {
return reference_iterator(*this, nullptr);
}
virtual const Reference *derefIterator(const void *iter) const {
return nullptr;
}
virtual void incrementIterator(const void *&iter) const {}
private:
const File &_file;
uint32_t _ordinal;
};
class TestingPassFile : public SimpleFile {
public:
TestingPassFile(const LinkingContext &ctx) : SimpleFile("Testing pass") {}
virtual void addAtom(const Atom &atom) {
if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&atom))
_definedAtoms._atoms.push_back(defAtom);
else
llvm_unreachable("atom has unknown definition kind");
}
virtual DefinedAtomRange definedAtoms() {
return range<std::vector<const DefinedAtom *>::iterator>(
_definedAtoms._atoms.begin(), _definedAtoms._atoms.end());
}
virtual const atom_collection<DefinedAtom> &defined() const {
return _definedAtoms;
}
virtual const atom_collection<UndefinedAtom> &undefined() const {
return _undefinedAtoms;
}
virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const {
return _sharedLibraryAtoms;
}
virtual const atom_collection<AbsoluteAtom> &absolute() const {
return _absoluteAtoms;
}
private:
atom_collection_vector<DefinedAtom> _definedAtoms;
atom_collection_vector<UndefinedAtom> _undefinedAtoms;
atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
};
class TestingStubsPass : public StubsPass {
public:
TestingStubsPass(const LinkingContext &ctx) : _file(TestingPassFile(ctx)) {}
virtual bool noTextRelocs() { return true; }
[lld] Introduce registry and Reference kind tuple The main changes are in: include/lld/Core/Reference.h include/lld/ReaderWriter/Reader.h Everything else is details to support the main change. 1) Registration based Readers Previously, lld had a tangled interdependency with all the Readers. It would have been impossible to make a streamlined linker (say for a JIT) which just supported one file format and one architecture (no yaml, no archives, etc). The old model also required a LinkingContext to read an object file, which would have made .o inspection tools awkward. The new model is that there is a global Registry object. You programmatically register the Readers you want with the registry object. Whenever you need to read/parse a file, you ask the registry to do it, and the registry tries each registered reader. For ease of use with the existing lld code base, there is one Registry object inside the LinkingContext object. 2) Changing kind value to be a tuple Beside Readers, the registry also keeps track of the mapping for Reference Kind values to and from strings. Along with that, this patch also fixes an ambiguity with the previous Reference::Kind values. The problem was that we wanted to reuse existing relocation type values as Reference::Kind values. But then how can the YAML write know how to convert a value to a string? The fix is to change the 32-bit Reference::Kind into a tuple with an 8-bit namespace (e.g. ELF, COFFF, etc), an 8-bit architecture (e.g. x86_64, PowerPC, etc), and a 16-bit value. This tuple system allows conversion to and from strings with no ambiguities. llvm-svn: 197727
2013-12-20 05:58:00 +08:00
virtual bool isCallSite(const Reference &ref) {
if (ref.kindNamespace() != Reference::KindNamespace::testing)
return false;
return (ref.kindValue() == CoreLinkingContext::TEST_RELOC_CALL32);
}
virtual const DefinedAtom *getStub(const Atom &target) {
const DefinedAtom *result = new TestingStubAtom(_file, target);
_file.addAtom(*result);
return result;
}
virtual void addStubAtoms(MutableFile &mergedFile) {
for (const DefinedAtom *stub : _file.defined()) {
mergedFile.addAtom(*stub);
}
}
private:
TestingPassFile _file;
};
class TestingGOTPass : public GOTPass {
public:
TestingGOTPass(const LinkingContext &ctx) : _file(TestingPassFile(ctx)) {}
virtual bool noTextRelocs() { return true; }
[lld] Introduce registry and Reference kind tuple The main changes are in: include/lld/Core/Reference.h include/lld/ReaderWriter/Reader.h Everything else is details to support the main change. 1) Registration based Readers Previously, lld had a tangled interdependency with all the Readers. It would have been impossible to make a streamlined linker (say for a JIT) which just supported one file format and one architecture (no yaml, no archives, etc). The old model also required a LinkingContext to read an object file, which would have made .o inspection tools awkward. The new model is that there is a global Registry object. You programmatically register the Readers you want with the registry object. Whenever you need to read/parse a file, you ask the registry to do it, and the registry tries each registered reader. For ease of use with the existing lld code base, there is one Registry object inside the LinkingContext object. 2) Changing kind value to be a tuple Beside Readers, the registry also keeps track of the mapping for Reference Kind values to and from strings. Along with that, this patch also fixes an ambiguity with the previous Reference::Kind values. The problem was that we wanted to reuse existing relocation type values as Reference::Kind values. But then how can the YAML write know how to convert a value to a string? The fix is to change the 32-bit Reference::Kind into a tuple with an 8-bit namespace (e.g. ELF, COFFF, etc), an 8-bit architecture (e.g. x86_64, PowerPC, etc), and a 16-bit value. This tuple system allows conversion to and from strings with no ambiguities. llvm-svn: 197727
2013-12-20 05:58:00 +08:00
virtual bool isGOTAccess(const Reference &ref, bool &canBypassGOT) {
if (ref.kindNamespace() != Reference::KindNamespace::testing)
return false;
switch (ref.kindValue()) {
case CoreLinkingContext::TEST_RELOC_GOT_LOAD32:
canBypassGOT = true;
return true;
case CoreLinkingContext::TEST_RELOC_GOT_USE32:
canBypassGOT = false;
return true;
}
return false;
}
virtual void updateReferenceToGOT(const Reference *ref, bool targetIsNowGOT) {
const_cast<Reference *>(ref)->setKindValue(
targetIsNowGOT ? CoreLinkingContext::TEST_RELOC_PCREL32
: CoreLinkingContext::TEST_RELOC_LEA32_WAS_GOT);
}
virtual const DefinedAtom *makeGOTEntry(const Atom &target) {
return new TestingGOTAtom(_file, target);
}
private:
TestingPassFile _file;
};
} // anonymous namespace
CoreLinkingContext::CoreLinkingContext() {}
bool CoreLinkingContext::validateImpl(raw_ostream &) {
_writer = createWriterYAML(*this);
return true;
}
void CoreLinkingContext::addPasses(PassManager &pm) {
for (StringRef name : _passNames) {
if (name.equals("layout"))
pm.add(std::unique_ptr<Pass>(new LayoutPass(registry())));
else if (name.equals("GOT"))
pm.add(std::unique_ptr<Pass>(new TestingGOTPass(*this)));
else if (name.equals("stubs"))
pm.add(std::unique_ptr<Pass>(new TestingStubsPass(*this)));
else
llvm_unreachable("bad pass name");
}
}
Writer &CoreLinkingContext::writer() const { return *_writer; }