mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +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:
parent
f9d8e0e32a
commit
1ea899cc1a
@ -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,11 +274,12 @@ 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();
|
||||||
}
|
}
|
||||||
|
26
test/ExecutionEngine/RuntimeDyld/X86/COFF_x86_64_IMGREL.s
Normal file
26
test/ExecutionEngine/RuntimeDyld/X86/COFF_x86_64_IMGREL.s
Normal 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)
|
Loading…
x
Reference in New Issue
Block a user