blob: 0646260405689c982a8f3c49d00f967abdc2fd92 [file] [log] [blame]
Index: lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp
===================================================================
--- lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp (revision 152265)
+++ lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp (working copy)
@@ -24,7 +24,8 @@
bool RuntimeDyldMachO::
resolveRelocation(uint8_t *LocalAddress,
uint64_t FinalAddress,
- uint64_t Value,
+ uint64_t FinalSource1,
+ uint64_t FinalSource2,
bool isPCRel,
unsigned Type,
unsigned Size,
@@ -32,10 +33,20 @@
// This just dispatches to the proper target specific routine.
switch (CPUType) {
default: llvm_unreachable("Unsupported CPU type!");
+ case mach::CTM_i386:
+ return resolveI386Relocation(LocalAddress,
+ FinalAddress,
+ FinalSource1,
+ FinalSource2,
+ isPCRel,
+ Type,
+ Size,
+ Addend);
case mach::CTM_x86_64:
return resolveX86_64Relocation(LocalAddress,
FinalAddress,
- (uintptr_t)Value,
+ FinalSource1,
+ FinalSource2,
isPCRel,
Type,
Size,
@@ -43,7 +54,8 @@
case mach::CTM_ARM:
return resolveARMRelocation(LocalAddress,
FinalAddress,
- (uintptr_t)Value,
+ FinalSource1,
+ FinalSource2,
isPCRel,
Type,
Size,
@@ -52,19 +64,52 @@
}
bool RuntimeDyldMachO::
+resolveI386Relocation(uint8_t *LocalAddress,
+ uint64_t FinalAddress,
+ uint64_t FinalSource1,
+ uint64_t FinalSource2,
+ bool isPCRel,
+ unsigned Type,
+ unsigned Size,
+ int64_t Addend) {
+ int64_t ValueToWrite = Addend;
+
+ switch (Type) {
+ default:
+ llvm_unreachable("Invalid relocation type!");
+ case macho::RIT_Vanilla:
+ ValueToWrite += FinalSource1;
+ break;
+ case macho::RIT_Difference:
+ case macho::RIT_Generic_LocalDifference:
+ case macho::RIT_Generic_PreboundLazyPointer:
+ ValueToWrite += FinalSource1;
+ ValueToWrite -= FinalSource2;
+ break;
+ }
+
+ if (isPCRel)
+ ValueToWrite -= FinalAddress + 4; // see resolveX86_64Relocation
+
+ uint8_t *p = LocalAddress;
+ for (unsigned i = 0; i < Size; ++i) {
+ *p++ = (uint8_t)(ValueToWrite & 0xff);
+ ValueToWrite >>= 8;
+ }
+
+ return false;
+}
+
+bool RuntimeDyldMachO::
resolveX86_64Relocation(uint8_t *LocalAddress,
uint64_t FinalAddress,
- uint64_t Value,
+ uint64_t FinalSource1,
+ uint64_t FinalSource2,
bool isPCRel,
unsigned Type,
unsigned Size,
int64_t Addend) {
- // If the relocation is PC-relative, the value to be encoded is the
- // pointer difference.
- if (isPCRel)
- // FIXME: It seems this value needs to be adjusted by 4 for an effective PC
- // address. Is that expected? Only for branches, perhaps?
- Value -= FinalAddress + 4;
+ int64_t ValueToWrite = Addend;
switch(Type) {
default:
@@ -74,41 +119,53 @@
case macho::RIT_X86_64_Signed4:
case macho::RIT_X86_64_Signed:
case macho::RIT_X86_64_Unsigned:
- case macho::RIT_X86_64_Branch: {
- Value += Addend;
- // Mask in the target value a byte at a time (we don't have an alignment
- // guarantee for the target address, so this is safest).
- uint8_t *p = (uint8_t*)LocalAddress;
- for (unsigned i = 0; i < Size; ++i) {
- *p++ = (uint8_t)Value;
- Value >>= 8;
- }
- return false;
- }
+ case macho::RIT_X86_64_Branch:
+ ValueToWrite += FinalSource1;
+ break;
case macho::RIT_X86_64_GOTLoad:
case macho::RIT_X86_64_GOT:
case macho::RIT_X86_64_Subtractor:
case macho::RIT_X86_64_TLV:
return Error("Relocation type not implemented yet!");
}
+
+ // If the relocation is PC-relative, the value to be encoded is the
+ // pointer difference.
+ if (isPCRel)
+ // FIXME: It seems this value needs to be adjusted by 4 for an effective PC
+ // address. Is that expected? Only for branches, perhaps?
+ ValueToWrite -= FinalAddress + 4;
+
+ // Mask in the target value a byte at a time (we don't have an alignment
+ // guarantee for the target address, so this is safest).
+ uint8_t *p = (uint8_t*)LocalAddress;
+ for (unsigned i = 0; i < Size; ++i) {
+ *p++ = (uint8_t)(ValueToWrite & 0xff);
+ ValueToWrite >>= 8;
+ }
+
+ return false;
}
bool RuntimeDyldMachO::
resolveARMRelocation(uint8_t *LocalAddress,
uint64_t FinalAddress,
- uint64_t Value,
+ uint64_t FinalSource1,
+ uint64_t FinalSource2,
bool isPCRel,
unsigned Type,
unsigned Size,
int64_t Addend) {
+ int64_t ValueToWrite = Addend;
+
// If the relocation is PC-relative, the value to be encoded is the
// pointer difference.
if (isPCRel) {
- Value -= FinalAddress;
+ ValueToWrite -= FinalAddress;
// ARM PCRel relocations have an effective-PC offset of two instructions
// (four bytes in Thumb mode, 8 bytes in ARM mode).
// FIXME: For now, assume ARM mode.
- Value -= 8;
+ ValueToWrite -= 8;
}
switch(Type) {
@@ -119,8 +176,8 @@
// guarantee for the target address, so this is safest).
uint8_t *p = (uint8_t*)LocalAddress;
for (unsigned i = 0; i < Size; ++i) {
- *p++ = (uint8_t)Value;
- Value >>= 8;
+ *p++ = (uint8_t)(ValueToWrite & 0xff);
+ ValueToWrite >>= 8;
}
break;
}
@@ -129,15 +186,15 @@
// 32-bit aligned, so we can do it all at once.
uint32_t *p = (uint32_t*)LocalAddress;
// The low two bits of the value are not encoded.
- Value >>= 2;
+ ValueToWrite >>= 2;
// Mask the value to 24 bits.
- Value &= 0xffffff;
+ ValueToWrite &= 0xffffff;
// FIXME: If the destination is a Thumb function (and the instruction
// is a non-predicated BL instruction), we need to change it to a BLX
// instruction instead.
// Insert the value into the instruction.
- *p = (*p & ~0xffffff) | Value;
+ *p = (*p & ~0xffffff) | ValueToWrite;
break;
}
case macho::RIT_ARM_ThumbBranch22Bit:
@@ -153,6 +210,29 @@
return false;
}
+static bool
+ResolveSectionAndOffset(const MachOObject *Obj,
+ SmallVectorImpl<unsigned> &SectionMap,
+ const MachOObject::LoadCommandInfo *SegmentLCI,
+ InMemoryStruct<macho::SegmentLoadCommand> &SegmentLC,
+ uint64_t Address,
+ unsigned &SectionID,
+ uint64_t &Offset)
+{
+ for (unsigned SI = 0, SE = SegmentLC->NumSections; SI < SE; ++SI) {
+ InMemoryStruct<macho::Section> CandidateSection;
+ Obj->ReadSection(*SegmentLCI, SI, CandidateSection);
+ if (Address >= CandidateSection->Address &&
+ Address < CandidateSection->Address + CandidateSection->Size) {
+ SectionID = SectionMap[SI];
+ Offset = Address - CandidateSection->Address;
+ return true;
+ }
+ }
+
+ return false;
+}
+
bool RuntimeDyldMachO::
loadSegment32(const MachOObject *Obj,
const MachOObject::LoadCommandInfo *SegmentLCI,
@@ -210,6 +290,7 @@
// Process the relocations for each section we're loading.
Relocations.grow(Relocations.size() + SegmentLC->NumSections);
+ RelocationSources.grow(RelocationSources.size() + SegmentLC->NumSections);
for (unsigned SectNum = 0; SectNum != SegmentLC->NumSections; ++SectNum) {
InMemoryStruct<macho::Section> Sect;
Obj->ReadSection(*SegmentLCI, SectNum, Sect);
@@ -218,51 +299,135 @@
for (unsigned j = 0; j != Sect->NumRelocationTableEntries; ++j) {
InMemoryStruct<macho::RelocationEntry> RE;
Obj->ReadRelocationEntry(Sect->RelocationTableOffset, j, RE);
- if (RE->Word0 & macho::RF_Scattered)
- return Error("NOT YET IMPLEMENTED: scattered relocations.");
- // Word0 of the relocation is the offset into the section where the
- // relocation should be applied. We need to translate that into an
- // offset into a function since that's our atom.
- uint32_t Offset = RE->Word0;
- bool isExtern = (RE->Word1 >> 27) & 1;
-
- // FIXME: Get the relocation addend from the target address.
- // FIXME: VERY imporant for internal relocations.
-
- // Figure out the source symbol of the relocation. If isExtern is true,
- // this relocation references the symbol table, otherwise it references
- // a section in the same object, numbered from 1 through NumSections
- // (SectionBases is [0, NumSections-1]).
- uint32_t SourceNum = RE->Word1 & 0xffffff; // 24-bit value
- if (!isExtern) {
- assert(SourceNum > 0 && "Invalid relocation section number!");
- unsigned SectionID = SectionMap[SourceNum - 1];
+ if (RE->Word0 & macho::RF_Scattered) {
+ // The lower 24 bits of Word0 of the scattered relocation is the offset
+ // into the section where the relocation should be applied, i.e., the
+ // current section.
+ uint32_t OffsetInTarget = RE->Word0 & 0x00ffffff;
unsigned TargetID = SectionMap[SectNum];
- DEBUG(dbgs() << "Internal relocation at Section #"
- << TargetID << " + " << Offset
- << " from Section #"
- << SectionID << " (Word1: "
- << format("0x%x", RE->Word1) << ")\n");
-
- // Store the relocation information. It will get resolved when
- // the section addresses are assigned.
- Relocations[SectionID].push_back(RelocationEntry(TargetID,
- Offset,
- RE->Word1,
- 0 /*Addend*/));
+ // Word1 of the scattered relocation is a file offset which needs to
+ // be resolved into Section+Offset form. This gives the address of the
+ // source.
+ unsigned Source1ID;
+ uint64_t Source1Offset;
+ if (!ResolveSectionAndOffset(Obj,
+ SectionMap,
+ SegmentLCI,
+ SegmentLC,
+ RE->Word1,
+ Source1ID,
+ Source1Offset))
+ return Error("couldn't find scattered relocation value in sections");
+ // This relocation may have a paired relocation entry. If it does, set
+ // the source/offset information for it correctly.
+ unsigned Source2ID = SectionOffset::NoSectionID;
+ uint64_t Source2Offset = 0;
+ if (j + 1 < Sect->NumRelocationTableEntries) {
+ InMemoryStruct<macho::RelocationEntry> PairRE;
+ Obj->ReadRelocationEntry(Sect->RelocationTableOffset, j+1, PairRE);
+ if ((PairRE->Word0 & macho::RF_Scattered) &&
+ ((PairRE->Word0 & 0x0f000000) >> 24) == macho::RIT_Pair) {
+ if (!ResolveSectionAndOffset(Obj,
+ SectionMap,
+ SegmentLCI,
+ SegmentLC,
+ PairRE->Word1,
+ Source2ID,
+ Source2Offset))
+ return Error("couldn't find scattered relocation value in sections");
+ ++j;
+ }
+ }
+ if (Source2ID == SectionOffset::NoSectionID)
+ DEBUG(dbgs() << "Scattered relocation at Section #"
+ << TargetID << " + " << OffsetInTarget
+ << " from Section #" << Source1ID
+ << "+" << Source1Offset
+ << " (Word0: "
+ << format("0x%x", RE->Word0) << ")\n");
+ else
+ DEBUG(dbgs() << "Scattered relocation at Section #"
+ << TargetID << " + " << OffsetInTarget
+ << " from Section #" << Source1ID
+ << "+" << Source1Offset
+ << " and Section #" << Source2ID
+ << "+" << Source2Offset
+ << " (Word0: "
+ << format("0x%x", RE->Word0) << ")\n");
+ uint32_t RelocationIndex = Relocations[TargetID].size();
+ // FIXME: Get the relocation addend from the target address.
+ // FIXME: VERY imporant for internal relocations.
+ RelocationEntry TranslatedRE(OffsetInTarget,
+ Source1ID,
+ Source1Offset,
+ Source2ID,
+ Source2Offset,
+ RE->Word1,
+ 0 /*Addend*/);
+ Relocations[TargetID].push_back(TranslatedRE);
+ RelocationSources[Source1ID].push_back(RelocationSource(TargetID,
+ RelocationIndex,
+ 0));
+ if (Source2ID != SectionOffset::NoSectionID)
+ RelocationSources[Source2ID].push_back(RelocationSource(TargetID,
+ RelocationIndex,
+ 1));
} else {
- StringRef SourceName = SymbolNames[SourceNum];
-
- // Now store the relocation information. Associate it with the source
- // symbol. Just add it to the unresolved list and let the general
- // path post-load resolve it if we know where the symbol is.
- UnresolvedRelocations[SourceName].push_back(RelocationEntry(SectNum,
- Offset,
- RE->Word1,
- 0 /*Addend*/));
- DEBUG(dbgs() << "Relocation at Section #" << SectNum << " + " << Offset
- << " from '" << SourceName << "(Word1: "
- << format("0x%x", RE->Word1) << ")\n");
+ // Word0 of the relocation is the offset into the section where the
+ // relocation should be applied, i.e., the current section. We need
+ // to translate that into an offset into a function since that's our atom.
+ uint32_t OffsetInTarget = RE->Word0;
+ bool isExtern = (RE->Word1 >> 27) & 1;
+
+ // FIXME: Get the relocation addend from the target address.
+ // FIXME: VERY imporant for internal relocations.
+
+ // Figure out the source symbol of the relocation. If isExtern is true,
+ // this relocation references the symbol table, otherwise it references
+ // a section in the same object, numbered from 1 through NumSections
+ // (SectionBases is [0, NumSections-1]).
+ uint32_t SourceNum_OneBased = RE->Word1 & 0xffffff; // 24-bit value
+ if (!isExtern) {
+ assert(SourceNum_OneBased > 0 && "Invalid relocation section number!");
+ unsigned SourceID = SectionMap[SourceNum_OneBased - 1];
+ unsigned TargetID = SectionMap[SectNum];
+ DEBUG(dbgs() << "Internal relocation at Section #"
+ << TargetID << " + " << OffsetInTarget
+ << " from Section #"
+ << SourceID << " (Word1: "
+ << format("0x%x", RE->Word1) << ")\n");
+
+ // Store the relocation information. It will get resolved when
+ // the section addresses are assigned.
+ uint32_t RelocationIndex = Relocations[TargetID].size();
+ Relocations[TargetID].push_back(RelocationEntry(OffsetInTarget,
+ SourceID,
+ SectionOffset::NoSectionID,
+ RE->Word1,
+ 0 /*Addend*/));
+ RelocationSources[SourceID].push_back(RelocationSource(TargetID,
+ RelocationIndex,
+ 0));
+ } else {
+ StringRef SourceName = SymbolNames[SourceNum_OneBased];
+
+ // Now store the relocation information. Associate it with the source
+ // symbol. Just add it to the unresolved list and let the general
+ // path post-load resolve it if we know where the symbol is.
+ unsigned TargetID = SectionMap[SectNum];
+ uint32_t RelocationIndex = Relocations[TargetID].size();
+ Relocations[TargetID].push_back(RelocationEntry(OffsetInTarget,
+ SectionOffset::UnresolvedSourceID,
+ SectionOffset::NoSectionID,
+ RE->Word1,
+ 0 /*Addend*/));
+ UnresolvedRelocations[SourceName].push_back(RelocationSource(TargetID,
+ RelocationIndex,
+ 0));
+ DEBUG(dbgs() << "Relocation at Section #" << SectNum << " + " << OffsetInTarget
+ << " from '" << SourceName << "' (Word1: "
+ << format("0x%x", RE->Word1) << ")\n");
+ }
}
}
}
@@ -332,6 +497,7 @@
// Process the relocations for each section we're loading.
Relocations.grow(Relocations.size() + Segment64LC->NumSections);
+ RelocationSources.grow(RelocationSources.size() + Segment64LC->NumSections);
for (unsigned SectNum = 0; SectNum != Segment64LC->NumSections; ++SectNum) {
InMemoryStruct<macho::Section64> Sect;
Obj->ReadSection64(*SegmentLCI, SectNum, Sect);
@@ -341,11 +507,11 @@
InMemoryStruct<macho::RelocationEntry> RE;
Obj->ReadRelocationEntry(Sect->RelocationTableOffset, j, RE);
if (RE->Word0 & macho::RF_Scattered)
- return Error("NOT YET IMPLEMENTED: scattered relocations.");
+ return Error("scattered relocations don't exist on 64-bit platforms");
// Word0 of the relocation is the offset into the section where the
// relocation should be applied. We need to translate that into an
// offset into a function since that's our atom.
- uint32_t Offset = RE->Word0;
+ uint32_t OffsetInTarget = RE->Word0;
bool isExtern = (RE->Word1 >> 27) & 1;
// FIXME: Get the relocation addend from the target address.
@@ -355,34 +521,45 @@
// this relocation references the symbol table, otherwise it references
// a section in the same object, numbered from 1 through NumSections
// (SectionBases is [0, NumSections-1]).
- uint32_t SourceNum = RE->Word1 & 0xffffff; // 24-bit value
+ uint32_t SourceNum_OneBased = RE->Word1 & 0xffffff; // 24-bit value
if (!isExtern) {
- assert(SourceNum > 0 && "Invalid relocation section number!");
- unsigned SectionID = SectionMap[SourceNum - 1];
+ assert(SourceNum_OneBased > 0 && "Invalid relocation section number!");
+ unsigned SourceID = SectionMap[SourceNum_OneBased - 1];
unsigned TargetID = SectionMap[SectNum];
DEBUG(dbgs() << "Internal relocation at Section #"
- << TargetID << " + " << Offset
+ << TargetID << " + " << OffsetInTarget
<< " from Section #"
- << SectionID << " (Word1: "
+ << SourceID << " (Word1: "
<< format("0x%x", RE->Word1) << ")\n");
// Store the relocation information. It will get resolved when
// the section addresses are assigned.
- Relocations[SectionID].push_back(RelocationEntry(TargetID,
- Offset,
- RE->Word1,
- 0 /*Addend*/));
+ uint32_t RelocationIndex = Relocations[TargetID].size();
+ Relocations[TargetID].push_back(RelocationEntry(OffsetInTarget,
+ SourceID,
+ SectionOffset::NoSectionID,
+ RE->Word1,
+ 0 /*Addend*/));
+ RelocationSources[SourceID].push_back(RelocationSource(TargetID,
+ RelocationIndex,
+ 0));
} else {
- StringRef SourceName = SymbolNames[SourceNum];
+ StringRef SourceName = SymbolNames[SourceNum_OneBased];
// Now store the relocation information. Associate it with the source
// symbol. Just add it to the unresolved list and let the general
// path post-load resolve it if we know where the symbol is.
- UnresolvedRelocations[SourceName].push_back(RelocationEntry(SectNum,
- Offset,
- RE->Word1,
- 0 /*Addend*/));
- DEBUG(dbgs() << "Relocation at Section #" << SectNum << " + " << Offset
+ unsigned TargetID = SectionMap[SectNum];
+ uint32_t RelocationIndex = Relocations[TargetID].size();
+ Relocations[TargetID].push_back(RelocationEntry(OffsetInTarget,
+ SectionOffset::UnresolvedSourceID,
+ SectionOffset::NoSectionID,
+ RE->Word1,
+ 0 /*Addend*/));
+ UnresolvedRelocations[SourceName].push_back(RelocationSource(TargetID,
+ RelocationIndex,
+ 0));
+ DEBUG(dbgs() << "Relocation at Section #" << SectNum << " + " << OffsetInTarget
<< " from '" << SourceName << "(Word1: "
<< format("0x%x", RE->Word1) << ")\n");
}
@@ -468,18 +645,22 @@
if (Loc == SymbolTable.end())
return;
- RelocationList &Relocs = UnresolvedRelocations[Name];
+ RelocationSourceList &SourcesForSymbol = UnresolvedRelocations[Name];
DEBUG(dbgs() << "Resolving symbol '" << Name << "'\n");
- for (int i = 0, e = Relocs.size(); i != e; ++i) {
- // Change the relocation to be section relative rather than symbol
- // relative and move it to the resolved relocation list.
- RelocationEntry Entry = Relocs[i];
- Entry.Addend += Loc->second.second;
- Relocations[Loc->second.first].push_back(Entry);
+ for (int i = 0, e = SourcesForSymbol.size(); i != e; ++i) {
+ // Find the relocation entry corresponding to this source and fill
+ // in its source information with the resolved information from this
+ // symbol.
+ RelocationSource &Source = SourcesForSymbol[i];
+ RelocationEntry &Entry = Relocations[Source.SectionID][Source.Index];
+ Entry.Sources[Source.SourceIdx].Offset = Loc->second.second;
+ Entry.Sources[Source.SourceIdx].ID = Loc->second.first;
+ // Now create a relocation source in the pointed-to section.
+ RelocationSources[Loc->second.first].push_back(Source);
}
// FIXME: Keep a worklist of the relocations we've added so that we can
// resolve more selectively later.
- Relocs.clear();
+ SourcesForSymbol.clear();
}
bool RuntimeDyldMachO::loadObject(MemoryBuffer *InputBuffer) {
@@ -575,6 +756,56 @@
return false;
}
+bool RuntimeDyldMachO::resolveRelocationEntry(unsigned SectionID,
+ RelocationEntry &RE)
+{
+ uint8_t *Target = (uint8_t*)Sections[SectionID].base() + RE.Offset;
+ uint64_t FinalTarget = SectionLoadAddress[SectionID] + RE.Offset;
+
+ uint64_t FinalSource1 = 0;
+ uint64_t FinalSource2 = 0;
+
+ if (RE.Sources[0].ID == SectionOffset::UnresolvedSourceID ||
+ RE.Sources[1].ID == SectionOffset::UnresolvedSourceID)
+ return false;
+
+ FinalSource1 = SectionLoadAddress[RE.Sources[0].ID] + RE.Sources[0].Offset;
+ if (RE.Sources[1].ID != SectionOffset::NoSectionID)
+ FinalSource2 = SectionLoadAddress[RE.Sources[1].ID] + RE.Sources[1].Offset;
+
+ bool isPCRel = RE.isPCRel();
+ unsigned Type = RE.type();
+ unsigned Size = RE.length();
+
+ if (RE.Sources[1].ID == SectionOffset::NoSectionID)
+ DEBUG(dbgs() << "Resolving relocation at Section #" << SectionID
+ << " + " << RE.Offset << " (" << format("%p", Target) << ")"
+ << " from Section #" << RE.Sources[0].ID << "+" << RE.Sources[0].Offset
+ << " (" << format("0x%llx", FinalSource1) << ")"
+ << " (" << (isPCRel ? "pcrel" : "absolute")
+ << ", type: " << Type << ", Size: " << Size << ", Addend: "
+ << RE.Addend << ").\n");
+ else
+ DEBUG(dbgs() << "Resolving relocation at Section #" << SectionID
+ << " + " << RE.Offset << " (" << format("%p", Target) << ")"
+ << " from Section #" << RE.Sources[0].ID << "+" << RE.Sources[0].Offset
+ << " (" << format("0x%llx", FinalSource1) << ")"
+ << " and Section #" << RE.Sources[1].ID << "+" << RE.Sources[1].Offset
+ << " (" << format("0x%llx", FinalSource2) << ")"
+ << " (" << (isPCRel ? "pcrel" : "absolute")
+ << ", type: " << Type << ", Size: " << Size << ", Addend: "
+ << RE.Addend << ").\n");
+
+ return resolveRelocation(Target,
+ FinalTarget,
+ FinalSource1,
+ FinalSource2,
+ isPCRel,
+ Type,
+ Size,
+ RE.Addend);
+}
+
// Assign an address to a symbol name and resolve all the relocations
// associated with it.
void RuntimeDyldMachO::reassignSectionAddress(unsigned SectionID,
@@ -590,30 +821,17 @@
SectionLoadAddress[SectionID] = Addr;
- RelocationList &Relocs = Relocations[SectionID];
- for (unsigned i = 0, e = Relocs.size(); i != e; ++i) {
- RelocationEntry &RE = Relocs[i];
- uint8_t *Target = (uint8_t*)Sections[RE.SectionID].base() + RE.Offset;
- uint64_t FinalTarget = (uint64_t)SectionLoadAddress[RE.SectionID] + RE.Offset;
- bool isPCRel = (RE.Data >> 24) & 1;
- unsigned Type = (RE.Data >> 28) & 0xf;
- unsigned Size = 1 << ((RE.Data >> 25) & 3);
-
- DEBUG(dbgs() << "Resolving relocation at Section #" << RE.SectionID
- << " + " << RE.Offset << " (" << format("%p", Target) << ")"
- << " from Section #" << SectionID << " (" << format("%p", Addr) << ")"
- << "(" << (isPCRel ? "pcrel" : "absolute")
- << ", type: " << Type << ", Size: " << Size << ", Addend: "
- << RE.Addend << ").\n");
-
- resolveRelocation(Target,
- FinalTarget,
- Addr,
- isPCRel,
- Type,
- Size,
- RE.Addend);
+ RelocationList &RelocsForSection = Relocations[SectionID];
+ for (unsigned i = 0, e = RelocsForSection.size(); i != e; ++i) {
+ RelocationEntry &RE = RelocsForSection[i];
+ resolveRelocationEntry(SectionID, RE);
}
+ RelocationSourceList &SourcesForSection = RelocationSources[SectionID];
+ for (unsigned i = 0, e = SourcesForSection.size(); i != e; ++i) {
+ RelocationSource &R = SourcesForSection[i];
+ RelocationEntry &RE = Relocations[R.SectionID][R.Index];
+ resolveRelocationEntry(R.SectionID, RE);
+ }
}
bool RuntimeDyldMachO::isKnownFormat(const MemoryBuffer *InputBuffer) {
Index: lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h
===================================================================
--- lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h (revision 152265)
+++ lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h (working copy)
@@ -26,48 +26,183 @@
namespace llvm {
class RuntimeDyldMachO : public RuntimeDyldImpl {
- // For each symbol, keep a list of relocations based on it. Anytime
- // its address is reassigned (the JIT re-compiled the function, e.g.),
- // the relocations get re-resolved.
- // The symbol (or section) the relocation is sourced from is the Key
- // in the relocation list where it's stored.
+ // For each section, keep a list of relocatable pieces of data that
+ // reside in it. If the section moves, or the sections whose
+ // locations the data depends on move, re-resolve the relocations
+ // based on that movement.
+ //
+ // RelocationEntry structures correspond to one or two Mach-O
+ // relocation_info or scattered_relocation_info structures --
+ // usually one, but two iff the original has a paired structure
+ // following it.
+ //
+ // To facilitate updating a relocation when its sources move, we
+ // also keep RelocationSource structures associated with the sections
+ // whose location the data depends on.
+
+ // FIXME: Use SymbolLoc for this instead. Where should the enum live?
+ struct SectionOffset {
+ uint64_t Offset; // Offset of the location into its section.
+ unsigned ID; // The section the location is contained in.
+
+ enum {
+ NoSectionID = 0xffff0000,
+ UnresolvedSourceID = 0xffffffff
+ };
+ };
+
struct RelocationEntry {
- unsigned SectionID; // Section the relocation is contained in.
- uint64_t Offset; // Offset into the section for the relocation.
- uint32_t Data; // Second word of the raw macho relocation entry.
- int64_t Addend; // Addend encoded in the instruction itself, if any,
- // plus the offset into the source section for
- // the symbol once the relocation is resolvable.
+ SectionOffset Sources[2]; // The section/offset pairs this relocation
+ // refers to.
+ // If the original Mach-O relocation entries used
+ // relocation_info, this data is computed from
+ // r_symbolnum and the offsets are locked to 0.
+ // (The only offset is determined by the addend.)
+ // If the original Mach-O relocation entries used
+ // scattered_relocation_info, this data, including
+ // offsets, is computed by looking r_value up in
+ // the section table.
- RelocationEntry(unsigned id, uint64_t offset, uint32_t data, int64_t addend)
- : SectionID(id), Offset(offset), Data(data), Addend(addend) {}
+ uint64_t Offset; // The offset of the data to be relocated.
+ // We don't use a SectionOffset because this
+ // RelocationEntry is already associated with the
+ // proper Section.
+
+ int64_t Addend; // Addend encoded in the instruction itself, if any,
+ // plus the offset into the source section for
+ // the symbol once the relocation is resolvable.
+
+ uint32_t Data; // If the original Mach-O relocation entry was a
+ // relocation_info, the bitfield { r_symbolnum,
+ // r_pcrel, r_length, r_extern, r_type }.
+ // If the original Mach-O relocation entry was a
+ // scattered_relocation_info, the bitfield
+ // { r_address, r_type, r_length, r_pcrel,
+ // r_scattered }.
+
+ bool Scattered; // True iff this relocation is scattered.
+
+ bool isPCRel()
+ {
+ if (Scattered)
+ return (Data & 0x40000000) >> 30;
+ else
+ return (Data & 0x01000000) >> 24;
+ }
+
+ uint8_t type()
+ {
+ if (Scattered)
+ return (Data & 0x0f000000) >> 24;
+ else
+ return (Data & 0xf0000000) >> 28;
+ }
+
+ // Returns the decoded version of the length field
+ uint8_t length()
+ {
+ if (Scattered)
+ return 1 << ((Data & 0x30000000) >> 28);
+ else
+ return 1 << ((Data & 0x0e000000) >> 25);
+ }
+
+ // Used with an ordinary relocation entry, where the source_offsets are not
+ // known yet.
+ RelocationEntry(uint64_t offset, // See the Offset field.
+ unsigned source_id0, // The section ID for the first source.
+ unsigned source_id1, // The section ID for the second source.
+ uint32_t data, // See the Data field.
+ int64_t addend) // See the Addend field.
+ : Offset(offset),
+ Addend(addend),
+ Data(data),
+ Scattered(false) {
+ Sources[0].ID = source_id0;
+ Sources[0].Offset = 0;
+ Sources[1].ID = source_id1;
+ Sources[1].Offset = 0;
+ }
+
+ // Used with a scattered relocation entry, where the source_offsets can be
+ // derived from the value.
+ RelocationEntry(uint64_t offset, // See the Offset field.
+ unsigned source_id0, // The section ID for the first source.
+ uint64_t source_off0, // The offset for the first source.
+ unsigned source_id1, // The section ID for the second source.
+ uint64_t source_off1, // The offset for the second source.
+ uint32_t data, // See the Data field.
+ int64_t addend) // See the Addend field.
+ : Offset(offset),
+ Addend(addend),
+ Data(data),
+ Scattered(true) {
+ Sources[0].ID = source_id0;
+ Sources[0].Offset = source_off0;
+ Sources[1].ID = source_id1;
+ Sources[1].Offset = source_off1;
+ }
};
typedef SmallVector<RelocationEntry, 4> RelocationList;
- // Relocations to sections already loaded. Indexed by SectionID which is the
- // source of the address. The target where the address will be writen is
- // SectionID/Offset in the relocation itself.
+
+ // For each section, keep a list of sources that are used by relocations in
+ // other sections. Whenever a relocation gets created, create one or two
+ // corresponding relocation sources. Whenever relocations are re-resolved
+ // for a section, also re-resolve the relocations corresponding to that
+ // section's relocation targets.
+ struct RelocationSource {
+ unsigned SectionID; // Section whose RelocationList contains the relocation.
+ uint32_t Index : 24; // Index of the RelocatonEntry in that RelocationList.
+ uint8_t SourceIdx : 1; // Index of this source in the RelocationEntry's Sources.
+
+ RelocationSource(unsigned id,
+ uint32_t index,
+ uint8_t source_idx)
+ : SectionID(id),
+ Index(index),
+ SourceIdx(source_idx) {}
+ };
+ typedef SmallVector<RelocationSource, 4> RelocationSourceList;
+
+ // Relocations which refer to already-loaded section. Indexed by SectionID
+ // which is the section containing the relocatable data.
IndexedMap<RelocationList> Relocations;
+ // Targets corresponding to Relocations.
+ IndexedMap<RelocationSourceList> RelocationSources;
// Relocations to symbols that are not yet resolved. Must be external
// relocations by definition. Indexed by symbol name.
- StringMap<RelocationList> UnresolvedRelocations;
+ StringMap<RelocationSourceList> UnresolvedRelocations;
+ bool resolveRelocationEntry(unsigned SectionID,
+ RelocationEntry &RE);
bool resolveRelocation(uint8_t *LocalAddress,
uint64_t FinalAddress,
- uint64_t Value,
+ uint64_t FinalSource1,
+ uint64_t FinalSource2,
bool isPCRel,
unsigned Type,
unsigned Size,
int64_t Addend);
+ bool resolveI386Relocation(uint8_t *LocalAddress,
+ uint64_t FinalAddress,
+ uint64_t FinalSource1,
+ uint64_t FinalSource2,
+ bool isPCRel,
+ unsigned Type,
+ unsigned Size,
+ int64_t Addend);
bool resolveX86_64Relocation(uint8_t *LocalAddress,
uint64_t FinalAddress,
- uint64_t Value,
+ uint64_t FinalSource1,
+ uint64_t FinalSource2,
bool isPCRel,
unsigned Type,
unsigned Size,
int64_t Addend);
bool resolveARMRelocation(uint8_t *LocalAddress,
uint64_t FinalAddress,
- uint64_t Value,
+ uint64_t FinalSource1,
+ uint64_t FinalSource2,
bool isPCRel,
unsigned Type,
unsigned Size,