[ELF][PPC64] Implement IPLT code sequence for non-preemptible IFUNC
Non-preemptible IFUNC are placed in in.iplt (.glink on EM_PPC64). If there is a non-GOT non-PLT relocation, for pointer equality, we change the type of the symbol from STT_IFUNC and STT_FUNC and bind it to the .glink entry. On EM_386, EM_X86_64, EM_ARM, and EM_AARCH64, the PLT code sequence loads the address from its associated .got.plt slot. An IPLT also has an associated .got.plt slot and can use the same code sequence. On EM_PPC64, the PLT code sequence is actually a bl instruction in .glink . It jumps to `__glink_PLTresolve` (the PLT header). and `__glink_PLTresolve` computes the .plt slot (relocated by R_PPC64_JUMP_SLOT). An IPLT does not have an associated R_PPC64_JUMP_SLOT, so we cannot use `bl` in .iplt . Instead, create a call stub which has a similar code sequence as PPC64PltCallStub. We don't save the TOC pointer, so such scenarios will not work: a function pointer to a non-preemptible ifunc, which resolves to a function defined in another DSO. This is the restriction described by https://sourceware.org/glibc/wiki/GNU_IFUNC (though on many architectures it works in practice): Requirement (a): Resolver must be defined in the same translation unit as the implementations. If an ifunc is taken address but not called, technically we don't need an entry for it, but we currently do that. This patch makes // clang -fuse-ld=lld -fno-pie -no-pie a.c // clang -fuse-ld=lld -fPIE -pie a.c #include <stdio.h> static void impl(void) { puts("meow"); } void thefunc(void) __attribute__((ifunc("resolver"))); void *resolver(void) { return &impl; } int main(void) { thefunc(); void (*theptr)(void) = &thefunc; theptr(); } work on Linux glibc and FreeBSD. Calling a function pointer pointing to a Non-preemptible IFUNC never worked before. Differential Revision: https://reviews.llvm.org/D71509
Loading
Please sign in to comment