mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-29 10:32:47 +00:00
[RuntimeDyld] Add support for MachO __jump_table and __pointers sections, and
SECTDIFF relocations on 32-bit x86. This fixes several of the MCJIT regression test failures that show up on 32-bit builds. <rdar://problem/16886294> git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@208635 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
6124834147
commit
b572bc1ccf
@ -111,6 +111,9 @@ public:
|
||||
basic_symbol_iterator symbol_begin_impl() const override;
|
||||
basic_symbol_iterator symbol_end_impl() const override;
|
||||
|
||||
// MachO specific.
|
||||
basic_symbol_iterator getSymbolByIndex(unsigned Index) const;
|
||||
|
||||
section_iterator section_begin() const override;
|
||||
section_iterator section_end() const override;
|
||||
|
||||
|
@ -144,12 +144,14 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectImage *InputObject) {
|
||||
bool IsCommon = Flags & SymbolRef::SF_Common;
|
||||
if (IsCommon) {
|
||||
// Add the common symbols to a list. We'll allocate them all below.
|
||||
uint32_t Align;
|
||||
Check(I->getAlignment(Align));
|
||||
uint64_t Size = 0;
|
||||
Check(I->getSize(Size));
|
||||
CommonSize += Size + Align;
|
||||
CommonSymbols[*I] = CommonSymbolInfo(Size, Align);
|
||||
if (!GlobalSymbolTable.count(Name)) {
|
||||
uint32_t Align;
|
||||
Check(I->getAlignment(Align));
|
||||
uint64_t Size = 0;
|
||||
Check(I->getSize(Size));
|
||||
CommonSize += Size + Align;
|
||||
CommonSymbols[*I] = CommonSymbolInfo(Size, Align);
|
||||
}
|
||||
} else {
|
||||
if (SymType == object::SymbolRef::ST_Function ||
|
||||
SymType == object::SymbolRef::ST_Data ||
|
||||
@ -177,7 +179,7 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectImage *InputObject) {
|
||||
|
||||
// Allocate common symbols
|
||||
if (CommonSize != 0)
|
||||
emitCommonSymbols(*Obj, CommonSymbols, CommonSize, LocalSymbols);
|
||||
emitCommonSymbols(*Obj, CommonSymbols, CommonSize, GlobalSymbolTable);
|
||||
|
||||
// Parse and process relocations
|
||||
DEBUG(dbgs() << "Parse relocations:\n");
|
||||
@ -205,7 +207,7 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectImage *InputObject) {
|
||||
}
|
||||
|
||||
// Give the subclasses a chance to tie-up any loose ends.
|
||||
finalizeLoad(LocalSections);
|
||||
finalizeLoad(*Obj, LocalSections);
|
||||
|
||||
return Obj.release();
|
||||
}
|
||||
@ -587,6 +589,8 @@ uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr) {
|
||||
*Addr = 0xFF; // jmp
|
||||
*(Addr+1) = 0x25; // rip
|
||||
// 32-bit PC-relative address of the GOT entry will be stored at Addr+2
|
||||
} else if (Arch == Triple::x86) {
|
||||
*Addr = 0xE9; // 32-bit pc-relative jump.
|
||||
}
|
||||
return Addr;
|
||||
}
|
||||
|
@ -1397,7 +1397,8 @@ uint64_t RuntimeDyldELF::findGOTEntry(uint64_t LoadAddress, uint64_t Offset) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RuntimeDyldELF::finalizeLoad(ObjSectionToIDMap &SectionMap) {
|
||||
void RuntimeDyldELF::finalizeLoad(ObjectImage &ObjImg,
|
||||
ObjSectionToIDMap &SectionMap) {
|
||||
// If necessary, allocate the global offset table
|
||||
if (MemMgr) {
|
||||
// Allocate the GOT if necessary
|
||||
|
@ -116,7 +116,8 @@ public:
|
||||
bool isCompatibleFile(const object::ObjectFile *Buffer) const override;
|
||||
void registerEHFrames() override;
|
||||
void deregisterEHFrames() override;
|
||||
void finalizeLoad(ObjSectionToIDMap &SectionMap) override;
|
||||
void finalizeLoad(ObjectImage &ObjImg,
|
||||
ObjSectionToIDMap &SectionMap) override;
|
||||
virtual ~RuntimeDyldELF();
|
||||
|
||||
static ObjectImage *createObjectImage(ObjectBuffer *InputBuffer);
|
||||
|
@ -90,9 +90,17 @@ public:
|
||||
/// used to make a relocation section relative instead of symbol relative.
|
||||
int64_t Addend;
|
||||
|
||||
struct SectionPair {
|
||||
uint32_t SectionA;
|
||||
uint32_t SectionB;
|
||||
};
|
||||
|
||||
/// SymOffset - Section offset of the relocation entry's symbol (used for GOT
|
||||
/// lookup).
|
||||
uint64_t SymOffset;
|
||||
union {
|
||||
uint64_t SymOffset;
|
||||
SectionPair Sections;
|
||||
};
|
||||
|
||||
/// True if this is a PCRel relocation (MachO specific).
|
||||
bool IsPCRel;
|
||||
@ -113,6 +121,16 @@ public:
|
||||
bool IsPCRel, unsigned Size)
|
||||
: SectionID(id), Offset(offset), RelType(type), Addend(addend),
|
||||
SymOffset(0), IsPCRel(IsPCRel), Size(Size) {}
|
||||
|
||||
RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend,
|
||||
unsigned SectionA, uint64_t SectionAOffset, unsigned SectionB,
|
||||
uint64_t SectionBOffset, bool IsPCRel, unsigned Size)
|
||||
: SectionID(id), Offset(offset), RelType(type),
|
||||
Addend(SectionAOffset - SectionBOffset + addend), IsPCRel(IsPCRel),
|
||||
Size(Size) {
|
||||
Sections.SectionA = SectionA;
|
||||
Sections.SectionB = SectionB;
|
||||
}
|
||||
};
|
||||
|
||||
class RelocationValueRef {
|
||||
@ -373,7 +391,7 @@ public:
|
||||
|
||||
virtual void deregisterEHFrames();
|
||||
|
||||
virtual void finalizeLoad(ObjSectionToIDMap &SectionMap) {}
|
||||
virtual void finalizeLoad(ObjectImage &ObjImg, ObjSectionToIDMap &SectionMap) {}
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
@ -23,6 +23,8 @@ namespace llvm {
|
||||
|
||||
static unsigned char *processFDE(unsigned char *P, intptr_t DeltaForText,
|
||||
intptr_t DeltaForEH) {
|
||||
DEBUG(dbgs() << "Processing FDE: Delta for text: " << DeltaForText
|
||||
<< ", Delta for EH: " << DeltaForEH << "\n");
|
||||
uint32_t Length = *((uint32_t *)P);
|
||||
P += 4;
|
||||
unsigned char *Ret = P + Length;
|
||||
@ -88,7 +90,8 @@ void RuntimeDyldMachO::registerEHFrames() {
|
||||
UnregisteredEHFrameSections.clear();
|
||||
}
|
||||
|
||||
void RuntimeDyldMachO::finalizeLoad(ObjSectionToIDMap &SectionMap) {
|
||||
void RuntimeDyldMachO::finalizeLoad(ObjectImage &ObjImg,
|
||||
ObjSectionToIDMap &SectionMap) {
|
||||
unsigned EHFrameSID = RTDYLD_INVALID_SECTION_ID;
|
||||
unsigned TextSID = RTDYLD_INVALID_SECTION_ID;
|
||||
unsigned ExceptTabSID = RTDYLD_INVALID_SECTION_ID;
|
||||
@ -103,6 +106,12 @@ void RuntimeDyldMachO::finalizeLoad(ObjSectionToIDMap &SectionMap) {
|
||||
TextSID = i->second;
|
||||
else if (Name == "__gcc_except_tab")
|
||||
ExceptTabSID = i->second;
|
||||
else if (Name == "__jump_table")
|
||||
populateJumpTable(cast<MachOObjectFile>(*ObjImg.getObjectFile()),
|
||||
Section, i->second);
|
||||
else if (Name == "__pointers")
|
||||
populatePointersSection(cast<MachOObjectFile>(*ObjImg.getObjectFile()),
|
||||
Section, i->second);
|
||||
}
|
||||
UnregisteredEHFrameSections.push_back(
|
||||
EHFrameRelatedSections(EHFrameSID, TextSID, ExceptTabSID));
|
||||
@ -182,7 +191,14 @@ bool RuntimeDyldMachO::resolveI386Relocation(const RelocationEntry &RE,
|
||||
return applyRelocationValue(LocalAddress, Value + RE.Addend,
|
||||
1 << RE.Size);
|
||||
case MachO::GENERIC_RELOC_SECTDIFF:
|
||||
case MachO::GENERIC_RELOC_LOCAL_SECTDIFF:
|
||||
case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: {
|
||||
uint64_t SectionABase = Sections[RE.Sections.SectionA].LoadAddress;
|
||||
uint64_t SectionBBase = Sections[RE.Sections.SectionB].LoadAddress;
|
||||
assert((Value == SectionABase || Value == SectionBBase) &&
|
||||
"Unexpected SECTDIFF relocation value.");
|
||||
Value = SectionABase - SectionBBase + RE.Addend;
|
||||
return applyRelocationValue(LocalAddress, Value, 1 << RE.Size);
|
||||
}
|
||||
case MachO::GENERIC_RELOC_PB_LA_PTR:
|
||||
return Error("Relocation type not implemented yet!");
|
||||
}
|
||||
@ -319,6 +335,157 @@ bool RuntimeDyldMachO::resolveARM64Relocation(const RelocationEntry &RE,
|
||||
return false;
|
||||
}
|
||||
|
||||
void RuntimeDyldMachO::populateJumpTable(MachOObjectFile &Obj,
|
||||
const SectionRef &JTSection,
|
||||
unsigned JTSectionID) {
|
||||
assert(!Obj.is64Bit() &&
|
||||
"__jump_table section not supported in 64-bit MachO.");
|
||||
|
||||
MachO::dysymtab_command DySymTabCmd = Obj.getDysymtabLoadCommand();
|
||||
MachO::section Sec32 = Obj.getSection(JTSection.getRawDataRefImpl());
|
||||
uint32_t JTSectionSize = Sec32.size;
|
||||
unsigned FirstIndirectSymbol = Sec32.reserved1;
|
||||
unsigned JTEntrySize = Sec32.reserved2;
|
||||
unsigned NumJTEntries = JTSectionSize / JTEntrySize;
|
||||
uint8_t* JTSectionAddr = getSectionAddress(JTSectionID);
|
||||
unsigned JTEntryOffset = 0;
|
||||
|
||||
assert((JTSectionSize % JTEntrySize) == 0 &&
|
||||
"Jump-table section does not contain a whole number of stubs?");
|
||||
|
||||
for (unsigned i = 0; i < NumJTEntries; ++i) {
|
||||
unsigned SymbolIndex =
|
||||
Obj.getIndirectSymbolTableEntry(DySymTabCmd, FirstIndirectSymbol + i);
|
||||
symbol_iterator SI = Obj.getSymbolByIndex(SymbolIndex);
|
||||
StringRef IndirectSymbolName;
|
||||
SI->getName(IndirectSymbolName);
|
||||
uint8_t* JTEntryAddr = JTSectionAddr + JTEntryOffset;
|
||||
createStubFunction(JTEntryAddr);
|
||||
RelocationEntry RE(JTSectionID, JTEntryOffset + 1,
|
||||
MachO::GENERIC_RELOC_VANILLA, 0, true, 2);
|
||||
addRelocationForSymbol(RE, IndirectSymbolName);
|
||||
JTEntryOffset += JTEntrySize;
|
||||
}
|
||||
}
|
||||
|
||||
void RuntimeDyldMachO::populatePointersSection(MachOObjectFile &Obj,
|
||||
const SectionRef &PTSection,
|
||||
unsigned PTSectionID) {
|
||||
assert(!Obj.is64Bit() &&
|
||||
"__pointers section not supported in 64-bit MachO.");
|
||||
|
||||
MachO::dysymtab_command DySymTabCmd = Obj.getDysymtabLoadCommand();
|
||||
MachO::section Sec32 = Obj.getSection(PTSection.getRawDataRefImpl());
|
||||
uint32_t PTSectionSize = Sec32.size;
|
||||
unsigned FirstIndirectSymbol = Sec32.reserved1;
|
||||
const unsigned PTEntrySize = 4;
|
||||
unsigned NumPTEntries = PTSectionSize / PTEntrySize;
|
||||
unsigned PTEntryOffset = 0;
|
||||
|
||||
assert((PTSectionSize % PTEntrySize) == 0 &&
|
||||
"Pointers section does not contain a whole number of stubs?");
|
||||
|
||||
DEBUG(dbgs() << "Populating __pointers, Section ID " << PTSectionID
|
||||
<< ", " << NumPTEntries << " entries, "
|
||||
<< PTEntrySize << " bytes each:\n");
|
||||
|
||||
for (unsigned i = 0; i < NumPTEntries; ++i) {
|
||||
unsigned SymbolIndex =
|
||||
Obj.getIndirectSymbolTableEntry(DySymTabCmd, FirstIndirectSymbol + i);
|
||||
symbol_iterator SI = Obj.getSymbolByIndex(SymbolIndex);
|
||||
StringRef IndirectSymbolName;
|
||||
SI->getName(IndirectSymbolName);
|
||||
DEBUG(dbgs() << " " << IndirectSymbolName << ": index " << SymbolIndex
|
||||
<< ", PT offset: " << PTEntryOffset << "\n");
|
||||
RelocationEntry RE(PTSectionID, PTEntryOffset,
|
||||
MachO::GENERIC_RELOC_VANILLA, 0, false, 2);
|
||||
addRelocationForSymbol(RE, IndirectSymbolName);
|
||||
PTEntryOffset += PTEntrySize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
section_iterator getSectionByAddress(const MachOObjectFile &Obj,
|
||||
uint64_t Addr) {
|
||||
section_iterator SI = Obj.section_begin();
|
||||
section_iterator SE = Obj.section_end();
|
||||
|
||||
for (; SI != SE; ++SI) {
|
||||
uint64_t SAddr, SSize;
|
||||
SI->getAddress(SAddr);
|
||||
SI->getSize(SSize);
|
||||
if ((Addr >= SAddr) && (Addr < SAddr + SSize))
|
||||
return SI;
|
||||
}
|
||||
|
||||
return SE;
|
||||
}
|
||||
|
||||
relocation_iterator RuntimeDyldMachO::processSECTDIFFRelocation(
|
||||
unsigned SectionID,
|
||||
relocation_iterator RelI,
|
||||
ObjectImage &Obj,
|
||||
ObjSectionToIDMap &ObjSectionToID) {
|
||||
const MachOObjectFile *MachO =
|
||||
static_cast<const MachOObjectFile*>(Obj.getObjectFile());
|
||||
MachO::any_relocation_info RE =
|
||||
MachO->getRelocation(RelI->getRawDataRefImpl());
|
||||
|
||||
SectionEntry &Section = Sections[SectionID];
|
||||
uint32_t RelocType = MachO->getAnyRelocationType(RE);
|
||||
bool IsPCRel = MachO->getAnyRelocationPCRel(RE);
|
||||
unsigned Size = MachO->getAnyRelocationLength(RE);
|
||||
uint64_t Offset;
|
||||
RelI->getOffset(Offset);
|
||||
uint8_t *LocalAddress = Section.Address + Offset;
|
||||
unsigned NumBytes = 1 << Size;
|
||||
int64_t Addend = 0;
|
||||
memcpy(&Addend, LocalAddress, NumBytes);
|
||||
|
||||
++RelI;
|
||||
MachO::any_relocation_info RE2 =
|
||||
MachO->getRelocation(RelI->getRawDataRefImpl());
|
||||
|
||||
uint32_t AddrA = MachO->getScatteredRelocationValue(RE);
|
||||
section_iterator SAI = getSectionByAddress(*MachO, AddrA);
|
||||
assert(SAI != MachO->section_end() && "Can't find section for address A");
|
||||
uint64_t SectionABase;
|
||||
SAI->getAddress(SectionABase);
|
||||
uint64_t SectionAOffset = AddrA - SectionABase;
|
||||
SectionRef SectionA = *SAI;
|
||||
bool IsCode;
|
||||
SectionA.isText(IsCode);
|
||||
uint32_t SectionAID = findOrEmitSection(Obj, SectionA, IsCode,
|
||||
ObjSectionToID);
|
||||
|
||||
uint32_t AddrB = MachO->getScatteredRelocationValue(RE2);
|
||||
section_iterator SBI = getSectionByAddress(*MachO, AddrB);
|
||||
assert(SBI != MachO->section_end() && "Can't find seciton for address B");
|
||||
uint64_t SectionBBase;
|
||||
SBI->getAddress(SectionBBase);
|
||||
uint64_t SectionBOffset = AddrB - SectionBBase;
|
||||
SectionRef SectionB = *SBI;
|
||||
uint32_t SectionBID = findOrEmitSection(Obj, SectionB, IsCode,
|
||||
ObjSectionToID);
|
||||
|
||||
if (Addend != AddrA - AddrB)
|
||||
Error("Unexpected SECTDIFF relocation addend.");
|
||||
|
||||
DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA << ", AddrB: " << AddrB
|
||||
<< ", Addend: " << Addend << ", SectionA ID: "
|
||||
<< SectionAID << ", SectionAOffset: " << SectionAOffset
|
||||
<< ", SectionB ID: " << SectionBID << ", SectionBOffset: "
|
||||
<< SectionBOffset << "\n");
|
||||
RelocationEntry R(SectionID, Offset, RelocType, 0,
|
||||
SectionAID, SectionAOffset, SectionBID, SectionBOffset,
|
||||
IsPCRel, Size);
|
||||
|
||||
addRelocationForSection(R, SectionAID);
|
||||
addRelocationForSection(R, SectionBID);
|
||||
|
||||
return RelI;
|
||||
}
|
||||
|
||||
relocation_iterator RuntimeDyldMachO::processRelocationRef(
|
||||
unsigned SectionID, relocation_iterator RelI, ObjectImage &Obj,
|
||||
ObjSectionToIDMap &ObjSectionToID, const SymbolTableMap &Symbols,
|
||||
@ -336,8 +503,13 @@ relocation_iterator RuntimeDyldMachO::processRelocationRef(
|
||||
// only needs to be reapplied if symbols move relative to one another.
|
||||
// Note: This will fail horribly where the relocations *do* need to be
|
||||
// applied, but that was already the case.
|
||||
if (MachO->isRelocationScattered(RE))
|
||||
if (MachO->isRelocationScattered(RE)) {
|
||||
if (RelType == MachO::GENERIC_RELOC_SECTDIFF ||
|
||||
RelType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)
|
||||
return processSECTDIFFRelocation(SectionID, RelI, Obj, ObjSectionToID);
|
||||
|
||||
return ++RelI;
|
||||
}
|
||||
|
||||
RelocationValueRef Value;
|
||||
SectionEntry &Section = Sections[SectionID];
|
||||
|
@ -46,6 +46,14 @@ private:
|
||||
bool resolveARMRelocation(const RelocationEntry &RE, uint64_t Value);
|
||||
bool resolveARM64Relocation(const RelocationEntry &RE, uint64_t Value);
|
||||
|
||||
// Populate stubs in __jump_table section.
|
||||
void populateJumpTable(MachOObjectFile &Obj, const SectionRef &JTSection,
|
||||
unsigned JTSectionID);
|
||||
|
||||
// Populate __pointers section.
|
||||
void populatePointersSection(MachOObjectFile &Obj, const SectionRef &PTSection,
|
||||
unsigned PTSectionID);
|
||||
|
||||
unsigned getMaxStubSize() override {
|
||||
if (Arch == Triple::arm || Arch == Triple::thumb)
|
||||
return 8; // 32-bit instruction and 32-bit address
|
||||
@ -57,6 +65,12 @@ private:
|
||||
|
||||
unsigned getStubAlignment() override { return 1; }
|
||||
|
||||
relocation_iterator processSECTDIFFRelocation(
|
||||
unsigned SectionID,
|
||||
relocation_iterator RelI,
|
||||
ObjectImage &ObjImg,
|
||||
ObjSectionToIDMap &ObjSectionToID);
|
||||
|
||||
struct EHFrameRelatedSections {
|
||||
EHFrameRelatedSections()
|
||||
: EHFrameSID(RTDYLD_INVALID_SECTION_ID),
|
||||
@ -85,7 +99,8 @@ public:
|
||||
bool isCompatibleFormat(const ObjectBuffer *Buffer) const override;
|
||||
bool isCompatibleFile(const object::ObjectFile *Obj) const override;
|
||||
void registerEHFrames() override;
|
||||
void finalizeLoad(ObjSectionToIDMap &SectionMap) override;
|
||||
void finalizeLoad(ObjectImage &ObjImg,
|
||||
ObjSectionToIDMap &SectionMap) override;
|
||||
|
||||
static ObjectImage *createObjectImage(ObjectBuffer *InputBuffer) {
|
||||
return new ObjectImageCommon(InputBuffer);
|
||||
|
@ -1158,13 +1158,7 @@ error_code MachOObjectFile::getLibraryPath(DataRefImpl LibData,
|
||||
}
|
||||
|
||||
basic_symbol_iterator MachOObjectFile::symbol_begin_impl() const {
|
||||
DataRefImpl DRI;
|
||||
if (!SymtabLoadCmd)
|
||||
return basic_symbol_iterator(SymbolRef(DRI, this));
|
||||
|
||||
MachO::symtab_command Symtab = getSymtabLoadCommand();
|
||||
DRI.p = reinterpret_cast<uintptr_t>(getPtr(this, Symtab.symoff));
|
||||
return basic_symbol_iterator(SymbolRef(DRI, this));
|
||||
return getSymbolByIndex(0);
|
||||
}
|
||||
|
||||
basic_symbol_iterator MachOObjectFile::symbol_end_impl() const {
|
||||
@ -1182,6 +1176,20 @@ basic_symbol_iterator MachOObjectFile::symbol_end_impl() const {
|
||||
return basic_symbol_iterator(SymbolRef(DRI, this));
|
||||
}
|
||||
|
||||
basic_symbol_iterator MachOObjectFile::getSymbolByIndex(unsigned Index) const {
|
||||
DataRefImpl DRI;
|
||||
if (!SymtabLoadCmd)
|
||||
return basic_symbol_iterator(SymbolRef(DRI, this));
|
||||
|
||||
MachO::symtab_command Symtab = getSymtabLoadCommand();
|
||||
assert(Index < Symtab.nsyms && "Requested symbol index is out of range.");
|
||||
unsigned SymbolTableEntrySize =
|
||||
is64Bit() ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);
|
||||
DRI.p = reinterpret_cast<uintptr_t>(getPtr(this, Symtab.symoff));
|
||||
DRI.p += Index * SymbolTableEntrySize;
|
||||
return basic_symbol_iterator(SymbolRef(DRI, this));
|
||||
}
|
||||
|
||||
section_iterator MachOObjectFile::section_begin() const {
|
||||
DataRefImpl DRI;
|
||||
return section_iterator(SectionRef(DRI, this));
|
||||
|
Loading…
Reference in New Issue
Block a user