mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 11:42:57 +01:00
[RuntimeDyld][PowerPC] Use global entry points for calls between sections.
Functions in different objects may use different TOCs, so calls between such functions should use the global entry point of the callee which updates the TOC pointer. This should fix a bug that the Numba developers encountered (see https://github.com/numba/numba/issues/2451). Patch by Olexa Bilaniuk. Thanks Olexa! No RuntimeDyld checker test case yet as I am not familiar enough with how RuntimeDyldELF fixes up call-sites, but I do not want to hold up landing this. I will continue to work on it and see if I can rope some powerpc experts in. llvm-svn: 329335
This commit is contained in:
parent
88942a139a
commit
b720c4f092
@ -1423,7 +1423,8 @@ RuntimeDyldELF::processRelocationRef(
|
||||
SectionEntry &Section = Sections[SectionID];
|
||||
uint8_t *Target = Section.getAddressWithOffset(Offset);
|
||||
bool RangeOverflow = false;
|
||||
if (!Value.SymbolName && SymType != SymbolRef::ST_Unknown) {
|
||||
bool IsExtern = Value.SymbolName || SymType == SymbolRef::ST_Unknown;
|
||||
if (!IsExtern) {
|
||||
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
|
||||
@ -1433,21 +1434,24 @@ RuntimeDyldELF::processRelocationRef(
|
||||
} 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();
|
||||
Value.Addend += ELF::decodePPC64LocalEntryOffset(SymOther);
|
||||
if (Value.SectionID == SectionID){
|
||||
uint8_t SymOther = Symbol->getOther();
|
||||
Value.Addend += ELF::decodePPC64LocalEntryOffset(SymOther);
|
||||
}
|
||||
}
|
||||
uint8_t *RelocTarget =
|
||||
Sections[Value.SectionID].getAddressWithOffset(Value.Addend);
|
||||
int64_t delta = static_cast<int64_t>(Target - RelocTarget);
|
||||
// If it is within 26-bits branch range, just set the branch target
|
||||
if (SignExtend64<26>(delta) == delta) {
|
||||
if (SignExtend64<26>(delta) != delta) {
|
||||
RangeOverflow = true;
|
||||
} else if ((AbiVariant != 2) ||
|
||||
(AbiVariant == 2 && Value.SectionID == SectionID)) {
|
||||
RelocationEntry RE(SectionID, Offset, RelType, Value.Addend);
|
||||
addRelocationForSection(RE, Value.SectionID);
|
||||
} else {
|
||||
RangeOverflow = true;
|
||||
}
|
||||
}
|
||||
if (Value.SymbolName || SymType == SymbolRef::ST_Unknown ||
|
||||
if (IsExtern || (AbiVariant == 2 && Value.SectionID != SectionID) ||
|
||||
RangeOverflow) {
|
||||
// It is an external symbol (either Value.SymbolName is set, or
|
||||
// SymType is SymbolRef::ST_Unknown) or out of range.
|
||||
@ -1504,10 +1508,10 @@ RuntimeDyldELF::processRelocationRef(
|
||||
RelType, 0);
|
||||
Section.advanceStubOffset(getMaxStubSize());
|
||||
}
|
||||
if (Value.SymbolName || SymType == SymbolRef::ST_Unknown) {
|
||||
if (IsExtern || (AbiVariant == 2 && Value.SectionID != SectionID)) {
|
||||
// Restore the TOC for external calls
|
||||
if (AbiVariant == 2)
|
||||
writeInt32BE(Target + 4, 0xE8410018); // ld r2,28(r1)
|
||||
writeInt32BE(Target + 4, 0xE8410018); // ld r2,24(r1)
|
||||
else
|
||||
writeInt32BE(Target + 4, 0xE8410028); // ld r2,40(r1)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user