[ELF][PPC32] Implement IPLT code sequence for non-preemptible IFUNC
authorFangrui Song <maskray@google.com>
Tue, 17 Dec 2019 19:23:37 +0000 (11:23 -0800)
committerFangrui Song <maskray@google.com>
Mon, 30 Dec 2019 06:42:53 +0000 (22:42 -0800)
commitfb2944bd7f8ac6d7c4bccd3ac2033ba58c690038
treeab5d5d21af5073663967dd50924cbdca08dd4b79
parent45acc35ac21323bafaf5d4367df10ebc4eed35f4
[ELF][PPC32] Implement IPLT code sequence for non-preemptible IFUNC

Similar to D71509 (EM_PPC64), on EM_PPC, the IPLT code sequence should
be similar to a PLT call stub. Unlike EM_PPC64, EM_PPC -msecure-plt has
small/large PIC model differences.

* -fpic/-fpie: R_PPC_PLTREL24 r_addend=0.  The call stub loads an address relative to `_GLOBAL_OFFSET_TABLE_`.
* -fPIC/-fPIE: R_PPC_PLTREL24 r_addend=0x8000. (A partial linked object
  file may have an addend larger than 0x8000.) The call stub loads an address relative to .got2+0x8000.

Just assume large PIC model for now. This patch makes:

  // clang -fuse-ld=lld -msecure-plt -fno-pie -no-pie a.c
  // clang -fuse-ld=lld -msecure-plt -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. -fpie will crash because the compiler and the
linker do not agree on the value which r30 stores (_GLOBAL_OFFSET_TABLE_
vs .got2+0x8000).

Differential Revision: https://reviews.llvm.org/D71621
lld/ELF/Arch/PPC.cpp
lld/ELF/Thunks.cpp
lld/ELF/Thunks.h
lld/test/ELF/ppc32-ifunc-nonpreemptible-nopic.s [moved from lld/test/ELF/ppc32-gnu-ifunc-nonpreemptable.s with 65% similarity]
lld/test/ELF/ppc32-ifunc-nonpreemptible-pic.s [new file with mode: 0644]