1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

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
This commit is contained in:
Frederich Munch 2018-02-21 17:18:20 +00:00
parent f9d8e0e32a
commit 1ea899cc1a
2 changed files with 120 additions and 21 deletions

View File

@ -30,15 +30,33 @@ private:
// unregisteredEH frame sections with the memory manager. // unregisteredEH frame sections with the memory manager.
SmallVector<SID, 2> UnregisteredEHFrameSections; SmallVector<SID, 2> UnregisteredEHFrameSections;
SmallVector<SID, 2> RegisteredEHFrameSections; 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: public:
RuntimeDyldCOFFX86_64(RuntimeDyld::MemoryManager &MM, RuntimeDyldCOFFX86_64(RuntimeDyld::MemoryManager &MM,
JITSymbolResolver &Resolver) JITSymbolResolver &Resolver)
: RuntimeDyldCOFF(MM, Resolver) {} : RuntimeDyldCOFF(MM, Resolver), ImageBase(0) {}
unsigned getMaxStubSize() override { unsigned getStubAlignment() override { return 1; }
return 6; // 2-byte jmp instruction + 32-bit relative address
} // 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 // The target location for the relocation is described by RE.SectionID and
// RE.Offset. RE.SectionID can be used to find the SectionEntry. Each // RE.Offset. RE.SectionID can be used to find the SectionEntry. Each
@ -85,13 +103,17 @@ public:
} }
case COFF::IMAGE_REL_AMD64_ADDR32NB: { case COFF::IMAGE_REL_AMD64_ADDR32NB: {
// Note ADDR32NB requires a well-established notion of // ADDR32NB requires an offset less than 2GB from 'ImageBase'.
// image base. This address must be less than or equal // The MemoryManager can make sure this is always true by forcing the
// to every section's load address, and all sections must be // memory layout to be: CodeSection < ReadOnlySection < ReadWriteSection.
// within a 32 bit offset from the base. const uint64_t ImageBase = getImageBase();
// if (Value < ImageBase || ((Value - ImageBase) > UINT32_MAX)) {
// For now we just set these to zero. llvm::errs() << "IMAGE_REL_AMD64_ADDR32NB relocation requires an"
writeBytesUnaligned(0, Target, 4); << "ordered section layout.\n";
write32BitOffset(Target, 0, 0);
} else {
write32BitOffset(Target, RE.Addend, Value - ImageBase);
}
break; 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> Expected<relocation_iterator>
processRelocationRef(unsigned SectionID, processRelocationRef(unsigned SectionID,
relocation_iterator RelI, relocation_iterator RelI,
@ -131,6 +198,11 @@ public:
SectionEntry &Section = Sections[SectionID]; SectionEntry &Section = Sections[SectionID];
uintptr_t ObjTarget = Section.getObjAddress() + Offset; uintptr_t ObjTarget = Section.getObjAddress() + Offset;
Expected<StringRef> TargetNameOrErr = Symbol->getName();
if (!TargetNameOrErr)
return TargetNameOrErr.takeError();
StringRef TargetName = *TargetNameOrErr;
switch (RelType) { switch (RelType) {
case COFF::IMAGE_REL_AMD64_REL32: case COFF::IMAGE_REL_AMD64_REL32:
@ -142,6 +214,11 @@ public:
case COFF::IMAGE_REL_AMD64_ADDR32NB: { case COFF::IMAGE_REL_AMD64_ADDR32NB: {
uint8_t *Displacement = (uint8_t *)ObjTarget; uint8_t *Displacement = (uint8_t *)ObjTarget;
Addend = readBytesUnaligned(Displacement, 4); Addend = readBytesUnaligned(Displacement, 4);
if (IsExtern)
std::tie(Offset, RelType, Addend) = generateRelocationStub(
SectionID, TargetName, Offset, RelType, Addend, Stubs);
break; break;
} }
@ -155,11 +232,6 @@ public:
break; break;
} }
Expected<StringRef> TargetNameOrErr = Symbol->getName();
if (!TargetNameOrErr)
return TargetNameOrErr.takeError();
StringRef TargetName = *TargetNameOrErr;
DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
<< " RelType: " << RelType << " TargetName: " << TargetName << " RelType: " << RelType << " TargetName: " << TargetName
<< " Addend " << Addend << "\n"); << " Addend " << Addend << "\n");
@ -183,7 +255,6 @@ public:
return ++RelI; return ++RelI;
} }
unsigned getStubAlignment() override { return 1; }
void registerEHFrames() override { void registerEHFrames() override {
for (auto const &EHFrameSID : UnregisteredEHFrameSections) { for (auto const &EHFrameSID : UnregisteredEHFrameSections) {
uint8_t *EHFrameAddr = Sections[EHFrameSID].getAddress(); uint8_t *EHFrameAddr = Sections[EHFrameSID].getAddress();
@ -194,6 +265,7 @@ public:
} }
UnregisteredEHFrameSections.clear(); UnregisteredEHFrameSections.clear();
} }
Error finalizeLoad(const ObjectFile &Obj, Error finalizeLoad(const ObjectFile &Obj,
ObjSectionToIDMap &SectionMap) override { ObjSectionToIDMap &SectionMap) override {
// Look for and record the EH frame section IDs. // Look for and record the EH frame section IDs.
@ -202,12 +274,13 @@ public:
StringRef Name; StringRef Name;
if (auto EC = Section.getName(Name)) if (auto EC = Section.getName(Name))
return errorCodeToError(EC); return errorCodeToError(EC);
// Note unwind info is split across .pdata and .xdata, so this
// may not be sufficiently general for all users. // Note unwind info is stored in .pdata but often points to .xdata
if (Name == ".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); UnregisteredEHFrameSections.push_back(SectionPair.second);
} }
}
return Error::success(); return Error::success();
} }
}; };

View File

@ -0,0 +1,26 @@
# RUN: rm -rf %t && mkdir -p %t
# RUN: llvm-mc -triple=x86_64-pc-win32 -filetype=obj -o %t/COFF_x86_64_IMGREL.o %s
# RUN: llvm-rtdyld -triple=x86_64-pc-win32 -verify -check=%s %t/COFF_x86_64_IMGREL.o
.text
.def F;
.scl 2;
.type 32;
.endef
.globl __constdata
.section .rdata, "dr", discard, __constdata
.align 8
__constdata:
.quad 0
.text
.globl F
.align 16, 0x90
F: # @F
# rtdyld-check: decode_operand(inst1, 3) = section_addr(COFF_x86_64_IMGREL.o, .text)+0
inst1:
mov %ebx, F@IMGREL
# rtdyld-check: decode_operand(inst2, 3) = section_addr(COFF_x86_64_IMGREL.o, .rdata)+5
inst2:
mov %ebx, (__constdata@imgrel+5)