summaryrefslogtreecommitdiffstats
path: root/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp')
-rw-r--r--llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp31
1 files changed, 24 insertions, 7 deletions
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
index 80e489cb5da..728138ed8c1 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
@@ -1141,6 +1141,10 @@ relocation_iterator RuntimeDyldELF::processRelocationRef(
}
} else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le) {
if (RelType == ELF::R_PPC64_REL24) {
+ // Determine ABI variant in use for this object.
+ unsigned AbiVariant;
+ Obj.getObjectFile()->getPlatformFlags(AbiVariant);
+ AbiVariant &= ELF::EF_PPC64_ABI;
// A PPC branch relocation will need a stub function if the target is
// an external symbol (Symbol::ST_Unknown) or if the target address
// is not within the signed 24-bits branch address.
@@ -1148,10 +1152,18 @@ relocation_iterator RuntimeDyldELF::processRelocationRef(
uint8_t *Target = Section.Address + Offset;
bool RangeOverflow = false;
if (SymType != SymbolRef::ST_Unknown) {
- // A function call may points to the .opd entry, so the final symbol
- // value
- // in calculated based in the relocation values in .opd section.
- findOPDEntrySection(Obj, ObjSectionToID, Value);
+ if (AbiVariant != 2) {
+ // In the ELFv1 ABI, a function call may point to the .opd entry,
+ // so the final symbol value is calculated based on the relocation
+ // values in the .opd section.
+ findOPDEntrySection(Obj, ObjSectionToID, Value);
+ } else {
+ // In the ELFv2 ABI, a function symbol may provide a local entry
+ // point, which must be used for direct calls.
+ uint8_t SymOther;
+ Symbol->getOther(SymOther);
+ Value.Addend += ELF::decodePPC64LocalEntryOffset(SymOther);
+ }
uint8_t *RelocTarget = Sections[Value.SectionID].Address + Value.Addend;
int32_t delta = static_cast<int32_t>(Target - RelocTarget);
// If it is within 24-bits branch range, just set the branch target
@@ -1179,7 +1191,8 @@ relocation_iterator RuntimeDyldELF::processRelocationRef(
DEBUG(dbgs() << " Create a new stub function\n");
Stubs[Value] = Section.StubOffset;
uint8_t *StubTargetAddr =
- createStubFunction(Section.Address + Section.StubOffset);
+ createStubFunction(Section.Address + Section.StubOffset,
+ AbiVariant);
RelocationEntry RE(SectionID, StubTargetAddr - Section.Address,
ELF::R_PPC64_ADDR64, Value.Addend);
@@ -1217,9 +1230,13 @@ relocation_iterator RuntimeDyldELF::processRelocationRef(
RelType, 0);
Section.StubOffset += getMaxStubSize();
}
- if (SymType == SymbolRef::ST_Unknown)
+ if (SymType == SymbolRef::ST_Unknown) {
// Restore the TOC for external calls
- writeInt32BE(Target + 4, 0xE8410028); // ld r2,40(r1)
+ if (AbiVariant == 2)
+ writeInt32BE(Target + 4, 0xE8410018); // ld r2,28(r1)
+ else
+ writeInt32BE(Target + 4, 0xE8410028); // ld r2,40(r1)
+ }
}
} else if (RelType == ELF::R_PPC64_TOC16 ||
RelType == ELF::R_PPC64_TOC16_DS ||
OpenPOWER on IntegriCloud