mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 03:33:20 +01:00
AArch64: add stubs to support long function calls on MCJIT
As with global accesses, external functions could exist anywhere in memory. Therefore the stub must create a complete 64-bit address. This patch implements the fragment as (roughly): movz x16, #:abs_g3:somefunc movk x16, #:abs_g2_nc:somefunc movk x16, #:abs_g1_nc:somefunc movk x16, #:abs_g0_nc:somefunc br x16 In principle we could save 4 bytes by using a literal-load instead, but it is unclear that would be more efficient and can only be tested when real hardware is readily available. This allows (for example) the MCJIT test 2003-05-07-ArgumentTest to pass on AArch64. llvm-svn: 181133
This commit is contained in:
parent
71cd109478
commit
41e94642a9
@ -336,7 +336,25 @@ void RuntimeDyldImpl::addRelocationForSymbol(const RelocationEntry &RE,
|
||||
}
|
||||
|
||||
uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr) {
|
||||
if (Arch == Triple::arm) {
|
||||
if (Arch == Triple::aarch64) {
|
||||
// This stub has to be able to access the full address space,
|
||||
// since symbol lookup won't necessarily find a handy, in-range,
|
||||
// PLT stub for functions which could be anywhere.
|
||||
uint32_t *StubAddr = (uint32_t*)Addr;
|
||||
|
||||
// Stub can use ip0 (== x16) to calculate address
|
||||
*StubAddr = 0xd2e00010; // movz ip0, #:abs_g3:<addr>
|
||||
StubAddr++;
|
||||
*StubAddr = 0xf2c00010; // movk ip0, #:abs_g2_nc:<addr>
|
||||
StubAddr++;
|
||||
*StubAddr = 0xf2a00010; // movk ip0, #:abs_g1_nc:<addr>
|
||||
StubAddr++;
|
||||
*StubAddr = 0xf2800010; // movk ip0, #:abs_g0_nc:<addr>
|
||||
StubAddr++;
|
||||
*StubAddr = 0xd61f0200; // br ip0
|
||||
|
||||
return Addr;
|
||||
} else if (Arch == Triple::arm) {
|
||||
// TODO: There is only ARM far stub now. We should add the Thumb stub,
|
||||
// and stubs for branches Thumb - ARM and ARM - Thumb.
|
||||
uint32_t *StubAddr = (uint32_t*)Addr;
|
||||
|
@ -296,6 +296,19 @@ void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section,
|
||||
*TargetPtr = static_cast<uint32_t>(Result & 0xffffffffU);
|
||||
break;
|
||||
}
|
||||
case ELF::R_AARCH64_CALL26: // fallthrough
|
||||
case ELF::R_AARCH64_JUMP26: {
|
||||
// Operation: S+A-P. Set Call or B immediate value to bits fff_fffc of the
|
||||
// calculation.
|
||||
uint64_t BranchImm = Value + Addend - FinalAddress;
|
||||
|
||||
// "Check that -2^27 <= result < 2^27".
|
||||
assert(-(1LL << 27) <= static_cast<int64_t>(BranchImm) &&
|
||||
static_cast<int64_t>(BranchImm) < (1LL << 27));
|
||||
// Immediate goes in bits 25:0 of B and BL.
|
||||
*TargetPtr |= static_cast<uint32_t>(BranchImm & 0xffffffcU) >> 2;
|
||||
break;
|
||||
}
|
||||
case ELF::R_AARCH64_MOVW_UABS_G3: {
|
||||
uint64_t Result = Value + Addend;
|
||||
// Immediate goes in bits 20:5 of MOVZ/MOVK instruction
|
||||
@ -775,7 +788,56 @@ void RuntimeDyldELF::processRelocationRef(unsigned SectionID,
|
||||
DEBUG(dbgs() << "\t\tSectionID: " << SectionID
|
||||
<< " Offset: " << Offset
|
||||
<< "\n");
|
||||
if (Arch == Triple::arm &&
|
||||
if (Arch == Triple::aarch64 &&
|
||||
(RelType == ELF::R_AARCH64_CALL26 ||
|
||||
RelType == ELF::R_AARCH64_JUMP26)) {
|
||||
// This is an AArch64 branch relocation, need to use a stub function.
|
||||
DEBUG(dbgs() << "\t\tThis is an AArch64 branch relocation.");
|
||||
SectionEntry &Section = Sections[SectionID];
|
||||
|
||||
// Look for an existing stub.
|
||||
StubMap::const_iterator i = Stubs.find(Value);
|
||||
if (i != Stubs.end()) {
|
||||
resolveRelocation(Section, Offset,
|
||||
(uint64_t)Section.Address + i->second, RelType, 0);
|
||||
DEBUG(dbgs() << " Stub function found\n");
|
||||
} else {
|
||||
// Create a new stub function.
|
||||
DEBUG(dbgs() << " Create a new stub function\n");
|
||||
Stubs[Value] = Section.StubOffset;
|
||||
uint8_t *StubTargetAddr = createStubFunction(Section.Address +
|
||||
Section.StubOffset);
|
||||
|
||||
RelocationEntry REmovz_g3(SectionID,
|
||||
StubTargetAddr - Section.Address,
|
||||
ELF::R_AARCH64_MOVW_UABS_G3, Value.Addend);
|
||||
RelocationEntry REmovk_g2(SectionID,
|
||||
StubTargetAddr - Section.Address + 4,
|
||||
ELF::R_AARCH64_MOVW_UABS_G2_NC, Value.Addend);
|
||||
RelocationEntry REmovk_g1(SectionID,
|
||||
StubTargetAddr - Section.Address + 8,
|
||||
ELF::R_AARCH64_MOVW_UABS_G1_NC, Value.Addend);
|
||||
RelocationEntry REmovk_g0(SectionID,
|
||||
StubTargetAddr - Section.Address + 12,
|
||||
ELF::R_AARCH64_MOVW_UABS_G0_NC, Value.Addend);
|
||||
|
||||
if (Value.SymbolName) {
|
||||
addRelocationForSymbol(REmovz_g3, Value.SymbolName);
|
||||
addRelocationForSymbol(REmovk_g2, Value.SymbolName);
|
||||
addRelocationForSymbol(REmovk_g1, Value.SymbolName);
|
||||
addRelocationForSymbol(REmovk_g0, Value.SymbolName);
|
||||
} else {
|
||||
addRelocationForSection(REmovz_g3, Value.SectionID);
|
||||
addRelocationForSection(REmovk_g2, Value.SectionID);
|
||||
addRelocationForSection(REmovk_g1, Value.SectionID);
|
||||
addRelocationForSection(REmovk_g0, Value.SectionID);
|
||||
}
|
||||
resolveRelocation(Section, Offset,
|
||||
(uint64_t)Section.Address + Section.StubOffset,
|
||||
RelType, 0);
|
||||
Section.StubOffset += getMaxStubSize();
|
||||
}
|
||||
} else if (Arch == Triple::arm &&
|
||||
(RelType == ELF::R_ARM_PC24 ||
|
||||
RelType == ELF::R_ARM_CALL ||
|
||||
RelType == ELF::R_ARM_JUMP24)) {
|
||||
|
@ -166,6 +166,8 @@ protected:
|
||||
Triple::ArchType Arch;
|
||||
|
||||
inline unsigned getMaxStubSize() {
|
||||
if (Arch == Triple::aarch64)
|
||||
return 20; // movz; movk; movk; movk; br
|
||||
if (Arch == Triple::arm || Arch == Triple::thumb)
|
||||
return 8; // 32-bit instruction and 32-bit address
|
||||
else if (Arch == Triple::mipsel || Arch == Triple::mips)
|
||||
|
Loading…
Reference in New Issue
Block a user