diff options
author | Ulrich Weigand <ulrich.weigand@de.ibm.com> | 2014-07-20 23:53:14 +0000 |
---|---|---|
committer | Ulrich Weigand <ulrich.weigand@de.ibm.com> | 2014-07-20 23:53:14 +0000 |
commit | 752b5c9e6efe3d081862e531290f0552447dc0c0 (patch) | |
tree | ca9184dd1e6f3faa99d7fad35c7a393e94adaccd /llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp | |
parent | 8658f17eef9abaa71ebcfa7e238dd0fb473fe500 (diff) | |
download | bcm5719-llvm-752b5c9e6efe3d081862e531290f0552447dc0c0.tar.gz bcm5719-llvm-752b5c9e6efe3d081862e531290f0552447dc0c0.zip |
[PowerPC] ELFv2 dynamic loader support
This patch enables the new ELFv2 ABI in the runtime dynamic loader.
The loader has to implement the following features:
- In the ELFv2 ABI, do not look up a function descriptor in .opd, but
instead use the local entry point when resolving a direct call.
- Update the TOC restore code to use the new TOC slot linkage area
offset.
- Create PLT stubs appropriate for the ELFv2 ABI.
Note that this patch also adds common-code changes. These are necessary
because the loader must check the newly added ELF flags: the e_flags
header bits encoding the ABI version, and the st_other symbol table
entry bits encoding the local entry point offset. There is currently
no way to access these, so I've added ObjectFile::getPlatformFlags and
SymbolRef::getOther accessors.
Reviewed by Hal Finkel.
llvm-svn: 213491
Diffstat (limited to 'llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp')
-rw-r--r-- | llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp | 34 |
1 files changed, 22 insertions, 12 deletions
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp index f761c1d8e1d..d86a7513068 100644 --- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp +++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp @@ -517,7 +517,8 @@ void RuntimeDyldImpl::addRelocationForSymbol(const RelocationEntry &RE, } } -uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr) { +uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr, + unsigned AbiVariant) { if (Arch == Triple::aarch64 || Arch == Triple::aarch64_be || Arch == Triple::arm64 || Arch == Triple::arm64_be) { // This stub has to be able to access the full address space, @@ -561,22 +562,31 @@ uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr) { *StubAddr = NopInstr; return Addr; } else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le) { - // PowerPC64 stub: the address points to a function descriptor - // instead of the function itself. Load the function address - // on r11 and sets it to control register. Also loads the function - // TOC in r2 and environment pointer to r11. + // Depending on which version of the ELF ABI is in use, we need to + // generate one of two variants of the stub. They both start with + // the same sequence to load the target address into r12. writeInt32BE(Addr, 0x3D800000); // lis r12, highest(addr) writeInt32BE(Addr+4, 0x618C0000); // ori r12, higher(addr) writeInt32BE(Addr+8, 0x798C07C6); // sldi r12, r12, 32 writeInt32BE(Addr+12, 0x658C0000); // oris r12, r12, h(addr) writeInt32BE(Addr+16, 0x618C0000); // ori r12, r12, l(addr) - writeInt32BE(Addr+20, 0xF8410028); // std r2, 40(r1) - writeInt32BE(Addr+24, 0xE96C0000); // ld r11, 0(r12) - writeInt32BE(Addr+28, 0xE84C0008); // ld r2, 0(r12) - writeInt32BE(Addr+32, 0x7D6903A6); // mtctr r11 - writeInt32BE(Addr+36, 0xE96C0010); // ld r11, 16(r2) - writeInt32BE(Addr+40, 0x4E800420); // bctr - + if (AbiVariant == 2) { + // PowerPC64 stub ELFv2 ABI: The address points to the function itself. + // The address is already in r12 as required by the ABI. Branch to it. + writeInt32BE(Addr+20, 0xF8410018); // std r2, 24(r1) + writeInt32BE(Addr+24, 0x7D8903A6); // mtctr r12 + writeInt32BE(Addr+28, 0x4E800420); // bctr + } else { + // PowerPC64 stub ELFv1 ABI: The address points to a function descriptor. + // Load the function address on r11 and sets it to control register. Also + // loads the function TOC in r2 and environment pointer to r11. + writeInt32BE(Addr+20, 0xF8410028); // std r2, 40(r1) + writeInt32BE(Addr+24, 0xE96C0000); // ld r11, 0(r12) + writeInt32BE(Addr+28, 0xE84C0008); // ld r2, 0(r12) + writeInt32BE(Addr+32, 0x7D6903A6); // mtctr r11 + writeInt32BE(Addr+36, 0xE96C0010); // ld r11, 16(r2) + writeInt32BE(Addr+40, 0x4E800420); // bctr + } return Addr; } else if (Arch == Triple::systemz) { writeInt16BE(Addr, 0xC418); // lgrl %r1,.+8 |