#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFF86_64_H
#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFF86_64_H
#include "../RuntimeDyldCOFF.h"
#include "llvm/BinaryFormat/COFF.h"
#include "llvm/Object/COFF.h"
#define DEBUG_TYPE "dyld"
namespace llvm {
class RuntimeDyldCOFFX86_64 : public RuntimeDyldCOFF {
private:
SmallVector<SID, 2> UnregisteredEHFrameSections;
SmallVector<SID, 2> RegisteredEHFrameSections;
uint64_t ImageBase;
uint64_t getImageBase() {
if (!ImageBase) {
ImageBase = std::numeric_limits<uint64_t>::max();
for (const SectionEntry &Section : Sections)
if (Section.getLoadAddress() != 0)
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, 8, COFF::IMAGE_REL_AMD64_ADDR64),
ImageBase(0) {}
unsigned getStubAlignment() override { return 1; }
unsigned getMaxStubSize() const override { return 14; }
void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
const SectionEntry &Section = Sections[RE.SectionID];
uint8_t *Target = Section.getAddressWithOffset(RE.Offset);
switch (RE.RelType) {
case COFF::IMAGE_REL_AMD64_REL32:
case COFF::IMAGE_REL_AMD64_REL32_1:
case COFF::IMAGE_REL_AMD64_REL32_2:
case COFF::IMAGE_REL_AMD64_REL32_3:
case COFF::IMAGE_REL_AMD64_REL32_4:
case COFF::IMAGE_REL_AMD64_REL32_5: {
uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset);
uint64_t Delta = 4 + (RE.RelType - COFF::IMAGE_REL_AMD64_REL32);
Value -= FinalAddress + Delta;
uint64_t Result = Value + RE.Addend;
assert(((int64_t)Result <= INT32_MAX) && "Relocation overflow");
assert(((int64_t)Result >= INT32_MIN) && "Relocation underflow");
writeBytesUnaligned(Result, Target, 4);
break;
}
case COFF::IMAGE_REL_AMD64_ADDR32NB: {
const uint64_t ImageBase = getImageBase();
if (Value < ImageBase || ((Value - ImageBase) > UINT32_MAX))
report_fatal_error("IMAGE_REL_AMD64_ADDR32NB relocation requires an "
"ordered section layout");
else {
write32BitOffset(Target, RE.Addend, Value - ImageBase);
}
break;
}
case COFF::IMAGE_REL_AMD64_ADDR64: {
writeBytesUnaligned(Value + RE.Addend, Target, 8);
break;
}
case COFF::IMAGE_REL_AMD64_SECREL: {
assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX && "Relocation overflow");
assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN && "Relocation underflow");
writeBytesUnaligned(RE.Addend, Target, 4);
break;
}
default:
llvm_unreachable("Relocation type not implemented yet!");
break;
}
}
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;
}
const RelocationEntry RE(SectionID, Offset, RelType, Addend);
resolveRelocation(RE, Section.getLoadAddressWithOffset(StubOffset));
Addend = 0;
Offset = StubOffset + 6;
RelType = COFF::IMAGE_REL_AMD64_ADDR64;
return std::make_tuple(Offset, RelType, Addend);
}
Expected<object::relocation_iterator>
processRelocationRef(unsigned SectionID,
object::relocation_iterator RelI,
const object::ObjectFile &Obj,
ObjSectionToIDMap &ObjSectionToID,
StubMap &Stubs) override {
object::symbol_iterator Symbol = RelI->getSymbol();
if (Symbol == Obj.symbol_end())
report_fatal_error("Unknown symbol in relocation");
auto SectionOrError = Symbol->getSection();
if (!SectionOrError)
return SectionOrError.takeError();
object::section_iterator SecI = *SectionOrError;
bool IsExtern = SecI == Obj.section_end();
uint64_t RelType = RelI->getType();
uint64_t Offset = RelI->getOffset();
uint64_t Addend = 0;
SectionEntry &Section = Sections[SectionID];
uintptr_t ObjTarget = Section.getObjAddress() + Offset;
Expected<StringRef> TargetNameOrErr = Symbol->getName();
if (!TargetNameOrErr)
return TargetNameOrErr.takeError();
StringRef TargetName = *TargetNameOrErr;
unsigned TargetSectionID = 0;
uint64_t TargetOffset = 0;
if (TargetName.startswith(getImportSymbolPrefix())) {
assert(IsExtern && "DLLImport not marked extern?");
TargetSectionID = SectionID;
TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName);
TargetName = StringRef();
IsExtern = false;
} else if (!IsExtern) {
if (auto TargetSectionIDOrErr =
findOrEmitSection(Obj, *SecI, SecI->isText(), ObjSectionToID))
TargetSectionID = *TargetSectionIDOrErr;
else
return TargetSectionIDOrErr.takeError();
TargetOffset = getSymbolOffset(*Symbol);
}
switch (RelType) {
case COFF::IMAGE_REL_AMD64_REL32:
case COFF::IMAGE_REL_AMD64_REL32_1:
case COFF::IMAGE_REL_AMD64_REL32_2:
case COFF::IMAGE_REL_AMD64_REL32_3:
case COFF::IMAGE_REL_AMD64_REL32_4:
case COFF::IMAGE_REL_AMD64_REL32_5:
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;
}
case COFF::IMAGE_REL_AMD64_ADDR64: {
uint8_t *Displacement = (uint8_t *)ObjTarget;
Addend = readBytesUnaligned(Displacement, 8);
break;
}
default:
break;
}
LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset
<< " RelType: " << RelType << " TargetName: "
<< TargetName << " Addend " << Addend << "\n");
if (IsExtern) {
RelocationEntry RE(SectionID, Offset, RelType, Addend);
addRelocationForSymbol(RE, TargetName);
} else {
RelocationEntry RE(SectionID, Offset, RelType, TargetOffset + Addend);
addRelocationForSection(RE, TargetSectionID);
}
return ++RelI;
}
void registerEHFrames() override {
for (auto const &EHFrameSID : UnregisteredEHFrameSections) {
uint8_t *EHFrameAddr = Sections[EHFrameSID].getAddress();
uint64_t EHFrameLoadAddr = Sections[EHFrameSID].getLoadAddress();
size_t EHFrameSize = Sections[EHFrameSID].getSize();
MemMgr.registerEHFrames(EHFrameAddr, EHFrameLoadAddr, EHFrameSize);
RegisteredEHFrameSections.push_back(EHFrameSID);
}
UnregisteredEHFrameSections.clear();
}
Error finalizeLoad(const object::ObjectFile &Obj,
ObjSectionToIDMap &SectionMap) override {
for (const auto &SectionPair : SectionMap) {
const object::SectionRef &Section = SectionPair.first;
Expected<StringRef> NameOrErr = Section.getName();
if (!NameOrErr)
return NameOrErr.takeError();
if ((*NameOrErr) == ".pdata")
UnregisteredEHFrameSections.push_back(SectionPair.second);
}
return Error::success();
}
};
}
#undef DEBUG_TYPE
#endif