summaryrefslogtreecommitdiffstats
path: root/llvm/lib/ExecutionEngine/RuntimeDyld
diff options
context:
space:
mode:
authorFrederich Munch <colsebas@hotmail.com>2018-02-21 17:18:20 +0000
committerFrederich Munch <colsebas@hotmail.com>2018-02-21 17:18:20 +0000
commit33ef594c58990d04cc16b3138279b1fb0451ce23 (patch)
treef9eef5e8ef81aa4a32e55ca786dd87eaf9aeb44d /llvm/lib/ExecutionEngine/RuntimeDyld
parent650f639d333853356d7b7bfdef4145e276640351 (diff)
downloadbcm5719-llvm-33ef594c58990d04cc16b3138279b1fb0451ce23.tar.gz
bcm5719-llvm-33ef594c58990d04cc16b3138279b1fb0451ce23.zip
Handle IMAGE_REL_AMD64_ADDR32NB in RuntimeDyldCOFF
Summary: IMAGE_REL_AMD64_ADDR32NB relocations are currently set to zero in all cases. This patch sets the relocation to the correct value when possible and shows an error when not. Reviewers: enderby, lhames, compnerd Reviewed By: compnerd Subscribers: LepelTsmok, compnerd, martell, llvm-commits Differential Revision: https://reviews.llvm.org/D30709 llvm-svn: 325700
Diffstat (limited to 'llvm/lib/ExecutionEngine/RuntimeDyld')
-rw-r--r--llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h115
1 files changed, 94 insertions, 21 deletions
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h b/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h
index 7cbb4385415..dc2adc6cb2a 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h
+++ b/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,51 @@ 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()) {
+ 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 {
+ 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 +198,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 +214,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,11 +232,6 @@ 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");
@@ -183,7 +255,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 +265,7 @@ public:
}
UnregisteredEHFrameSections.clear();
}
+
Error finalizeLoad(const ObjectFile &Obj,
ObjSectionToIDMap &SectionMap) override {
// Look for and record the EH frame section IDs.
@@ -202,11 +274,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();
}
OpenPOWER on IntegriCloud