[lld] fb2944b - [ELF][PPC32] Implement IPLT code sequence for non-preemptible IFUNC
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Sun Dec 29 22:45:45 PST 2019
Author: Fangrui Song
Date: 2019-12-29T22:42:53-08:00
New Revision: fb2944bd7f8ac6d7c4bccd3ac2033ba58c690038
URL: https://github.com/llvm/llvm-project/commit/fb2944bd7f8ac6d7c4bccd3ac2033ba58c690038
DIFF: https://github.com/llvm/llvm-project/commit/fb2944bd7f8ac6d7c4bccd3ac2033ba58c690038.diff
LOG: [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
Added:
lld/test/ELF/ppc32-ifunc-nonpreemptible-nopic.s
lld/test/ELF/ppc32-ifunc-nonpreemptible-pic.s
Modified:
lld/ELF/Arch/PPC.cpp
lld/ELF/Thunks.cpp
lld/ELF/Thunks.h
Removed:
lld/test/ELF/ppc32-gnu-ifunc-nonpreemptable.s
################################################################################
diff --git a/lld/ELF/Arch/PPC.cpp b/lld/ELF/Arch/PPC.cpp
index 4c0f2c17da1d..3c0b0c290b58 100644
--- a/lld/ELF/Arch/PPC.cpp
+++ b/lld/ELF/Arch/PPC.cpp
@@ -10,6 +10,7 @@
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
+#include "Thunks.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/Support/Endian.h"
@@ -35,6 +36,8 @@ class PPC final : public TargetInfo {
uint64_t pltEntryAddr) const override {
llvm_unreachable("should call writePPC32GlinkSection() instead");
}
+ void writeIplt(uint8_t *buf, const Symbol &sym,
+ uint64_t pltEntryAddr) const override;
void writeGotPlt(uint8_t *buf, const Symbol &s) const override;
bool needsThunk(RelExpr expr, RelType relocType, const InputFile *file,
uint64_t branchAddr, const Symbol &s,
@@ -144,7 +147,7 @@ PPC::PPC() {
gotPltHeaderEntriesNum = 0;
pltHeaderSize = 64; // size of PLTresolve in .glink
pltEntrySize = 4;
- ipltEntrySize = 4;
+ ipltEntrySize = 16;
needsThunks = true;
@@ -158,6 +161,13 @@ PPC::PPC() {
write32(trapInstr.data(), 0x7fe00008);
}
+void PPC::writeIplt(uint8_t *buf, const Symbol &sym,
+ uint64_t /*pltEntryAddr*/) const {
+ // In -pie or -shared mode, assume r30 points to .got2+0x8000, and use a
+ // .got2.plt_pic32. thunk.
+ writePPC32PltCallStub(buf, sym.getGotPltVA(), sym.file, 0x8000);
+}
+
void PPC::writeGotHeader(uint8_t *buf) const {
// _GLOBAL_OFFSET_TABLE_[0] = _DYNAMIC
// glibc stores _dl_runtime_resolve in _GLOBAL_OFFSET_TABLE_[1],
diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp
index 5c84fcc8dad9..446c88c92d9e 100644
--- a/lld/ELF/Thunks.cpp
+++ b/lld/ELF/Thunks.cpp
@@ -707,13 +707,13 @@ InputSection *MicroMipsR6Thunk::getTargetInputSection() const {
return dyn_cast<InputSection>(dr.section);
}
-void PPC32PltCallStub::writeTo(uint8_t *buf) {
+void writePPC32PltCallStub(uint8_t *buf, uint64_t gotPltVA,
+ const InputFile *file, int64_t addend) {
if (!config->isPic) {
- uint64_t va = destination.getGotPltVA();
- write32(buf + 0, 0x3d600000 | (va + 0x8000) >> 16); // lis r11,ha
- write32(buf + 4, 0x816b0000 | (uint16_t)va); // lwz r11,l(r11)
- write32(buf + 8, 0x7d6903a6); // mtctr r11
- write32(buf + 12, 0x4e800420); // bctr
+ write32(buf + 0, 0x3d600000 | (gotPltVA + 0x8000) >> 16); // lis r11,ha
+ write32(buf + 4, 0x816b0000 | (uint16_t)gotPltVA); // lwz r11,l(r11)
+ write32(buf + 8, 0x7d6903a6); // mtctr r11
+ write32(buf + 12, 0x4e800420); // bctr
return;
}
uint32_t offset;
@@ -721,12 +721,12 @@ void PPC32PltCallStub::writeTo(uint8_t *buf) {
// The stub loads an address relative to r30 (.got2+Addend). Addend is
// almost always 0x8000. The address of .got2 is
diff erent in another object
// file, so a stub cannot be shared.
- offset = destination.getGotPltVA() - (in.ppc32Got2->getParent()->getVA() +
- file->ppc32Got2OutSecOff + addend);
+ offset = gotPltVA - (in.ppc32Got2->getParent()->getVA() +
+ file->ppc32Got2OutSecOff + addend);
} else {
// The stub loads an address relative to _GLOBAL_OFFSET_TABLE_ (which is
// currently the address of .got).
- offset = destination.getGotPltVA() - in.got->getVA();
+ offset = gotPltVA - in.got->getVA();
}
uint16_t ha = (offset + 0x8000) >> 16, l = (uint16_t)offset;
if (ha == 0) {
@@ -742,6 +742,10 @@ void PPC32PltCallStub::writeTo(uint8_t *buf) {
}
}
+void PPC32PltCallStub::writeTo(uint8_t *buf) {
+ writePPC32PltCallStub(buf, destination.getGotPltVA(), file, addend);
+}
+
void PPC32PltCallStub::addSymbols(ThunkSection &isec) {
std::string buf;
raw_string_ostream os(buf);
diff --git a/lld/ELF/Thunks.h b/lld/ELF/Thunks.h
index e16f9a85c4c2..a8575b4cdb59 100644
--- a/lld/ELF/Thunks.h
+++ b/lld/ELF/Thunks.h
@@ -14,6 +14,7 @@
namespace lld {
namespace elf {
class Defined;
+class InputFile;
class Symbol;
class ThunkSection;
// Class to describe an instance of a Thunk.
@@ -68,6 +69,8 @@ class Thunk {
// ThunkSection.
Thunk *addThunk(const InputSection &isec, Relocation &rel);
+void writePPC32PltCallStub(uint8_t *buf, uint64_t gotPltVA,
+ const InputFile *file, int64_t addend);
void writePPC64LoadAndBranch(uint8_t *buf, int64_t offset);
} // namespace elf
diff --git a/lld/test/ELF/ppc32-gnu-ifunc-nonpreemptable.s b/lld/test/ELF/ppc32-ifunc-nonpreemptible-nopic.s
similarity index 65%
rename from lld/test/ELF/ppc32-gnu-ifunc-nonpreemptable.s
rename to lld/test/ELF/ppc32-ifunc-nonpreemptible-nopic.s
index 0bf92e3e4d72..097417d225f9 100644
--- a/lld/test/ELF/ppc32-gnu-ifunc-nonpreemptable.s
+++ b/lld/test/ELF/ppc32-ifunc-nonpreemptible-nopic.s
@@ -1,23 +1,19 @@
-# REQUIRES: ppc, asserts
-# XFAIL: *
+# REQUIRES: ppc
# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o
# RUN: ld.lld %t.o -o %t
# RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC %s
# RUN: llvm-readelf -s %t | FileCheck --check-prefix=SYM %s
-# RUN: llvm-readelf -x .got2 %t | FileCheck --check-prefix=HEX %s
# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s
# RELOC: .rela.dyn {
-# RELOC-NEXT: 0x10020108 R_PPC_IRELATIVE - 0x100100E0
+# RELOC-NEXT: 0x10020110 R_PPC_IRELATIVE - 0x100100E0
# RELOC-NEXT: }
# SYM: 10010100 0 FUNC GLOBAL DEFAULT {{.*}} func
-# HEX: 0x10020104 10010100
+# HEX: 0x10020110 10010100
-.section .got2,"aw"
-.long func
-
-# CHECK: func_resolver:
+# CHECK: Disassembly of section .text:
+# CHECK: .text:
# CHECK-NEXT: 100100e0: blr
# CHECK: _start:
# CHECK-NEXT: bl .+12
@@ -25,17 +21,14 @@
# CHECK-NEXT: addi 9, 9, 256
# CHECK-EMPTY:
# CHECK-NEXT: 00000000.plt_call32.func:
-## 0x10020108 = 65536*4098+264
+## 0x10020110 = 65536*4098+272
# CHECK-NEXT: lis 11, 4098
-# CHECK-NEXT: lwz 11, 264(11)
+# CHECK-NEXT: lwz 11, 272(11)
.text
.globl func
.type func, @gnu_indirect_function
func:
-.globl func_resolver
-.type func_resolver, @function
-func_resolver:
blr
.globl _start
diff --git a/lld/test/ELF/ppc32-ifunc-nonpreemptible-pic.s b/lld/test/ELF/ppc32-ifunc-nonpreemptible-pic.s
new file mode 100644
index 000000000000..16edee08c01d
--- /dev/null
+++ b/lld/test/ELF/ppc32-ifunc-nonpreemptible-pic.s
@@ -0,0 +1,46 @@
+# REQUIRES: ppc
+# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t.o
+# RUN: ld.lld -pie %t.o -o %t
+# RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC %s
+# RUN: llvm-readelf -s %t | FileCheck --check-prefix=SYM %s
+# RUN: llvm-readelf -x .got2 %t | FileCheck --check-prefix=HEX %s
+# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s
+
+# RELOC: .rela.dyn {
+# RELOC-NEXT: 0x30240 R_PPC_RELATIVE - 0x101A8
+# RELOC-NEXT: 0x30244 R_PPC_IRELATIVE - 0x10188
+# RELOC-NEXT: }
+
+# SYM: 000101a8 0 FUNC GLOBAL DEFAULT {{.*}} func
+# HEX: 0x00030240 00000000
+
+.section .got2,"aw"
+.long func
+
+# CHECK: Disassembly of section .text:
+# CHECK: .text:
+# CHECK-NEXT: 10188: blr
+# CHECK: _start:
+# CHECK-NEXT: bl .+12
+# CHECK-NEXT: lis 9, 1
+# CHECK-NEXT: addi 9, 9, 424
+# CHECK-EMPTY:
+# CHECK-NEXT: 00008000.got2.plt_pic32.func:
+## 0x10020114 = 65536*4098+276
+# CHECK-NEXT: lwz 11, -32764(30)
+# CHECK-NEXT: mtctr 11
+# CHECK-NEXT: bctr
+# CHECK-NEXT: nop
+
+.text
+.globl func
+.type func, @gnu_indirect_function
+func:
+ blr
+
+.globl _start
+_start:
+ bl func+0x8000 at plt
+
+ lis 9, func at ha
+ la 9, func at l(9)
More information about the llvm-commits
mailing list