aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2018-07-30 16:33:32 +0000
committerDimitry Andric <dim@FreeBSD.org>2018-07-30 16:33:32 +0000
commit51315c45ff5643a27f9c84b816db54ee870ba29b (patch)
tree1d87443fa0e53d3e6b315ce25787e64be0906bf7 /contrib/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h
parent6dfd050075216be8538ae375a22d30db72916f7e (diff)
parenteb11fae6d08f479c0799db45860a98af528fa6e7 (diff)
Merge llvm trunk r338150, and resolve conflicts.
Notes
Notes: svn path=/projects/clang700-import/; revision=336916
Diffstat (limited to 'contrib/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h')
-rw-r--r--contrib/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h122
1 files changed, 98 insertions, 24 deletions
diff --git a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h
index 7cbb43854151..2d6e5c4aea67 100644
--- a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h
+++ b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h
@@ -30,15 +30,33 @@ private:
// unregisteredEH frame sections with the memory manager.
SmallVector<SID, 2> UnregisteredEHFrameSections;
SmallVector<SID, 2> RegisteredEHFrameSections;
+ uint64_t ImageBase;
+
+ // Fake an __ImageBase pointer by returning the section with the lowest adress
+ uint64_t getImageBase() {
+ if (!ImageBase) {
+ ImageBase = std::numeric_limits<uint64_t>::max();
+ for (const SectionEntry &Section : Sections)
+ ImageBase = std::min(ImageBase, Section.getLoadAddress());
+ }
+ return ImageBase;
+ }
+
+ void write32BitOffset(uint8_t *Target, int64_t Addend, uint64_t Delta) {
+ uint64_t Result = Addend + Delta;
+ assert(Result <= UINT32_MAX && "Relocation overflow");
+ writeBytesUnaligned(Result, Target, 4);
+ }
public:
RuntimeDyldCOFFX86_64(RuntimeDyld::MemoryManager &MM,
JITSymbolResolver &Resolver)
- : RuntimeDyldCOFF(MM, Resolver) {}
+ : RuntimeDyldCOFF(MM, Resolver), ImageBase(0) {}
- unsigned getMaxStubSize() override {
- return 6; // 2-byte jmp instruction + 32-bit relative address
- }
+ unsigned getStubAlignment() override { return 1; }
+
+ // 2-byte jmp instruction + 32-bit relative address + 64-bit absolute jump
+ unsigned getMaxStubSize() override { return 14; }
// The target location for the relocation is described by RE.SectionID and
// RE.Offset. RE.SectionID can be used to find the SectionEntry. Each
@@ -85,13 +103,17 @@ public:
}
case COFF::IMAGE_REL_AMD64_ADDR32NB: {
- // Note ADDR32NB requires a well-established notion of
- // image base. This address must be less than or equal
- // to every section's load address, and all sections must be
- // within a 32 bit offset from the base.
- //
- // For now we just set these to zero.
- writeBytesUnaligned(0, Target, 4);
+ // ADDR32NB requires an offset less than 2GB from 'ImageBase'.
+ // The MemoryManager can make sure this is always true by forcing the
+ // memory layout to be: CodeSection < ReadOnlySection < ReadWriteSection.
+ const uint64_t ImageBase = getImageBase();
+ if (Value < ImageBase || ((Value - ImageBase) > UINT32_MAX)) {
+ llvm::errs() << "IMAGE_REL_AMD64_ADDR32NB relocation requires an"
+ << "ordered section layout.\n";
+ write32BitOffset(Target, 0, 0);
+ } else {
+ write32BitOffset(Target, RE.Addend, Value - ImageBase);
+ }
break;
}
@@ -106,6 +128,52 @@ public:
}
}
+ std::tuple<uint64_t, uint64_t, uint64_t>
+ generateRelocationStub(unsigned SectionID, StringRef TargetName,
+ uint64_t Offset, uint64_t RelType, uint64_t Addend,
+ StubMap &Stubs) {
+ uintptr_t StubOffset;
+ SectionEntry &Section = Sections[SectionID];
+
+ RelocationValueRef OriginalRelValueRef;
+ OriginalRelValueRef.SectionID = SectionID;
+ OriginalRelValueRef.Offset = Offset;
+ OriginalRelValueRef.Addend = Addend;
+ OriginalRelValueRef.SymbolName = TargetName.data();
+
+ auto Stub = Stubs.find(OriginalRelValueRef);
+ if (Stub == Stubs.end()) {
+ LLVM_DEBUG(dbgs() << " Create a new stub function for "
+ << TargetName.data() << "\n");
+
+ StubOffset = Section.getStubOffset();
+ Stubs[OriginalRelValueRef] = StubOffset;
+ createStubFunction(Section.getAddressWithOffset(StubOffset));
+ Section.advanceStubOffset(getMaxStubSize());
+ } else {
+ LLVM_DEBUG(dbgs() << " Stub function found for " << TargetName.data()
+ << "\n");
+ StubOffset = Stub->second;
+ }
+
+ // FIXME: If RelType == COFF::IMAGE_REL_AMD64_ADDR32NB we should be able
+ // to ignore the __ImageBase requirement and just forward to the stub
+ // directly as an offset of this section:
+ // write32BitOffset(Section.getAddressWithOffset(Offset), 0, StubOffset);
+ // .xdata exception handler's aren't having this though.
+
+ // Resolve original relocation to stub function.
+ const RelocationEntry RE(SectionID, Offset, RelType, Addend);
+ resolveRelocation(RE, Section.getLoadAddressWithOffset(StubOffset));
+
+ // adjust relocation info so resolution writes to the stub function
+ Addend = 0;
+ Offset = StubOffset + 6;
+ RelType = COFF::IMAGE_REL_AMD64_ADDR64;
+
+ return std::make_tuple(Offset, RelType, Addend);
+ }
+
Expected<relocation_iterator>
processRelocationRef(unsigned SectionID,
relocation_iterator RelI,
@@ -131,6 +199,11 @@ public:
SectionEntry &Section = Sections[SectionID];
uintptr_t ObjTarget = Section.getObjAddress() + Offset;
+ Expected<StringRef> TargetNameOrErr = Symbol->getName();
+ if (!TargetNameOrErr)
+ return TargetNameOrErr.takeError();
+ StringRef TargetName = *TargetNameOrErr;
+
switch (RelType) {
case COFF::IMAGE_REL_AMD64_REL32:
@@ -142,6 +215,11 @@ public:
case COFF::IMAGE_REL_AMD64_ADDR32NB: {
uint8_t *Displacement = (uint8_t *)ObjTarget;
Addend = readBytesUnaligned(Displacement, 4);
+
+ if (IsExtern)
+ std::tie(Offset, RelType, Addend) = generateRelocationStub(
+ SectionID, TargetName, Offset, RelType, Addend, Stubs);
+
break;
}
@@ -155,14 +233,9 @@ public:
break;
}
- Expected<StringRef> TargetNameOrErr = Symbol->getName();
- if (!TargetNameOrErr)
- return TargetNameOrErr.takeError();
- StringRef TargetName = *TargetNameOrErr;
-
- DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
- << " RelType: " << RelType << " TargetName: " << TargetName
- << " Addend " << Addend << "\n");
+ LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
+ << " RelType: " << RelType << " TargetName: "
+ << TargetName << " Addend " << Addend << "\n");
if (IsExtern) {
RelocationEntry RE(SectionID, Offset, RelType, Addend);
@@ -183,7 +256,6 @@ public:
return ++RelI;
}
- unsigned getStubAlignment() override { return 1; }
void registerEHFrames() override {
for (auto const &EHFrameSID : UnregisteredEHFrameSections) {
uint8_t *EHFrameAddr = Sections[EHFrameSID].getAddress();
@@ -194,6 +266,7 @@ public:
}
UnregisteredEHFrameSections.clear();
}
+
Error finalizeLoad(const ObjectFile &Obj,
ObjSectionToIDMap &SectionMap) override {
// Look for and record the EH frame section IDs.
@@ -202,11 +275,12 @@ public:
StringRef Name;
if (auto EC = Section.getName(Name))
return errorCodeToError(EC);
- // Note unwind info is split across .pdata and .xdata, so this
- // may not be sufficiently general for all users.
- if (Name == ".xdata") {
+
+ // Note unwind info is stored in .pdata but often points to .xdata
+ // with an IMAGE_REL_AMD64_ADDR32NB relocation. Using a memory manager
+ // that keeps sections ordered in relation to __ImageBase is necessary.
+ if (Name == ".pdata")
UnregisteredEHFrameSections.push_back(SectionPair.second);
- }
}
return Error::success();
}