diff --git a/lld/ELF/Arch/PPC.cpp b/lld/ELF/Arch/PPC.cpp --- 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,7 @@ uint64_t pltEntryAddr) const override { llvm_unreachable("should call writePPC32GlinkSection() instead"); } + void writeIplt(uint8_t *buf, const Symbol &s, 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 +146,7 @@ gotPltHeaderEntriesNum = 0; pltHeaderSize = 64; // size of PLTresolve in .glink pltEntrySize = 4; - ipltEntrySize = 4; + ipltEntrySize = 16; needsThunks = true; @@ -158,6 +160,13 @@ write32(trapInstr.data(), 0x7fe00008); } +void PPC::writeIplt(uint8_t *buf, const Symbol &s, + uint64_t /*pltEntryAddr*/) const { + // In -pie or -shared mode, assume r30 points to .got2+0x8000, and use a + // .got2.plt_pic32. thunk. + writePPC32PltCallStub(buf, s.getGotPltVA(), s.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.h b/lld/ELF/Thunks.h --- 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 @@ // 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/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp --- a/lld/ELF/Thunks.cpp +++ b/lld/ELF/Thunks.cpp @@ -707,13 +707,13 @@ return dyn_cast(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 @@ // The stub loads an address relative to r30 (.got2+Addend). Addend is // almost always 0x8000. The address of .got2 is different 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) { + writePPC32PltCallStub(buf, destination.getGotPltVA(), file, addend); +} + void PPC32PltCallStub::addSymbols(ThunkSection &isec) { std::string buf; raw_string_ostream os(buf); diff --git a/lld/test/ELF/ppc32-gnu-ifunc-nonpreemptable.s b/lld/test/ELF/ppc32-ifunc-nonpreemptible-nopic.s rename from lld/test/ELF/ppc32-gnu-ifunc-nonpreemptable.s rename to lld/test/ELF/ppc32-ifunc-nonpreemptible-nopic.s --- a/lld/test/ELF/ppc32-gnu-ifunc-nonpreemptable.s +++ b/lld/test/ELF/ppc32-ifunc-nonpreemptible-nopic.s @@ -1,5 +1,4 @@ -# 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 @@ -8,16 +7,17 @@ # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s # RELOC: .rela.dyn { -# RELOC-NEXT: 0x10020108 R_PPC_IRELATIVE - 0x100100E0 +# RELOC-NEXT: 0x10020114 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 +25,14 @@ # CHECK-NEXT: addi 9, 9, 256 # CHECK-EMPTY: # CHECK-NEXT: 00000000.plt_call32.func: -## 0x10020108 = 65536*4098+264 +## 0x10020114 = 65536*4098+276 # CHECK-NEXT: lis 11, 4098 -# CHECK-NEXT: lwz 11, 264(11) +# CHECK-NEXT: lwz 11, 276(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-gnu-ifunc-nonpreemptable.s b/lld/test/ELF/ppc32-ifunc-nonpreemptible-pic.s rename from lld/test/ELF/ppc32-gnu-ifunc-nonpreemptable.s rename to lld/test/ELF/ppc32-ifunc-nonpreemptible-pic.s --- a/lld/test/ELF/ppc32-gnu-ifunc-nonpreemptable.s +++ b/lld/test/ELF/ppc32-ifunc-nonpreemptible-pic.s @@ -1,46 +1,46 @@ -# 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: 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: 0x10020108 R_PPC_IRELATIVE - 0x100100E0 +# RELOC-NEXT: 0x30240 R_PPC_RELATIVE - 0x101A8 +# RELOC-NEXT: 0x30244 R_PPC_IRELATIVE - 0x10188 # RELOC-NEXT: } -# SYM: 10010100 0 FUNC GLOBAL DEFAULT {{.*}} func -# HEX: 0x10020104 10010100 +# SYM: 000101a8 0 FUNC GLOBAL DEFAULT {{.*}} func +# HEX: 0x00030240 00000000 .section .got2,"aw" .long func -# CHECK: func_resolver: -# CHECK-NEXT: 100100e0: blr +# CHECK: Disassembly of section .text: +# CHECK: .text: +# CHECK-NEXT: 10188: blr # CHECK: _start: # CHECK-NEXT: bl .+12 -# CHECK-NEXT: lis 9, 4097 -# CHECK-NEXT: addi 9, 9, 256 +# CHECK-NEXT: lis 9, 1 +# CHECK-NEXT: addi 9, 9, 424 # CHECK-EMPTY: -# CHECK-NEXT: 00000000.plt_call32.func: -## 0x10020108 = 65536*4098+264 -# CHECK-NEXT: lis 11, 4098 -# CHECK-NEXT: lwz 11, 264(11) +# 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: -.globl func_resolver -.type func_resolver, @function -func_resolver: blr .globl _start _start: - bl func + bl func+0x8000@plt lis 9, func@ha la 9, func@l(9)