[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:
Lang Hames 2014-05-12 21:39:59 +00:00
parent 6124834147
commit b572bc1ccf
8 changed files with 245 additions and 23 deletions

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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];

View File

@ -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);

View File

@ -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));