diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp --- a/lld/ELF/Arch/PPC64.cpp +++ b/lld/ELF/Arch/PPC64.cpp @@ -202,6 +202,8 @@ void writePltHeader(uint8_t *buf) const override; void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, int32_t index) const override; + void writeIplt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, + int32_t index) const override; void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; void writeGotHeader(uint8_t *buf) const override; bool needsThunk(RelExpr expr, RelType type, const InputFile *file, @@ -297,7 +299,7 @@ iRelativeRel = R_PPC64_IRELATIVE; symbolicRel = R_PPC64_ADDR64; pltEntrySize = 4; - ipltEntrySize = 4; + ipltEntrySize = 20; // PPC64PltCallStub::size gotBaseSymInGotPlt = false; gotHeaderEntriesNum = 1; gotPltHeaderEntriesNum = 2; @@ -676,6 +678,20 @@ write32(buf, 0x48000000 | ((-offset) & 0x03FFFFFc)); } +void PPC64::writeIplt(uint8_t *buf, uint64_t gotPltEntryAddr, + uint64_t pltEntryAddr, int32_t index) const { + int64_t offset = gotPltEntryAddr - getPPC64TocBase(); + uint16_t offHa = (offset + 0x8000) >> 16; + uint16_t offLo = offset & 0xffff; + + // The code sequence is the same as PPC64PltCallStub. + write32(buf + 0, 0xf8410018); // std r2,24(r1) + write32(buf + 4, 0x3d820000 | offHa); // addis r12, r2, OffHa + write32(buf + 8, 0xe98c0000 | offLo); // ld r12, OffLo(r12) + write32(buf + 12, 0x7d8903a6); // mtctr r12 + write32(buf + 16, 0x4e800420); // bctr +} + static std::pair toAddr16Rel(RelType type, uint64_t val) { // Relocations relative to the toc-base need to be adjusted by the Toc offset. uint64_t tocBiasedVal = val - ppc64TocOffset; diff --git a/lld/test/ELF/ppc64-ifunc.s b/lld/test/ELF/ppc64-ifunc.s --- a/lld/test/ELF/ppc64-ifunc.s +++ b/lld/test/ELF/ppc64-ifunc.s @@ -14,23 +14,23 @@ # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s # RUN: llvm-readobj -r %t | FileCheck --check-prefix=REL %s -# NM-DAG: 0000000010028248 d .TOC. +# NM-DAG: 0000000010028268 d .TOC. # NM-DAG: 00000000100101f8 T ifunc # NM-DAG: 00000000100101fc T ifunc2 -# SECTIONS: .plt NOBITS 0000000010030250 000250 000010 00 WA 0 0 8 +# SECTIONS: .plt NOBITS 0000000010030270 000270 000010 00 WA 0 0 8 # __plt_ifunc - . = 0x10010218 - 0x10010208 = 16 # __plt_ifunc2 - . = 0x1001022c - 0x10010210 = 28 # CHECK: _start: # CHECK-NEXT: addis 2, 12, 2 -# CHECK-NEXT: addi 2, 2, -32696 +# CHECK-NEXT: addi 2, 2, -32664 # CHECK-NEXT: 10010208: bl .+16 # CHECK-NEXT: ld 2, 24(1) # CHECK-NEXT: 10010210: bl .+28 # CHECK-NEXT: ld 2, 24(1) -# .plt[0] - .TOC. = 0x10030250 - 0x10028248 = (1<<16) - 32760 +# .plt[0] - .TOC. = 0x10030270 - 0x10028268 = (1<<16) - 32760 # CHECK: __plt_ifunc: # CHECK-NEXT: std 2, 24(1) # CHECK-NEXT: addis 12, 2, 1 @@ -38,7 +38,7 @@ # CHECK-NEXT: mtctr 12 # CHECK-NEXT: bctr -# .plt[1] - .TOC. = 0x10030250+8 - 0x10028248 = (1<<16) - 32752 +# .plt[1] - .TOC. = 0x10030270+8 - 0x10028248 = (1<<16) - 32752 # CHECK: __plt_ifunc2: # CHECK-NEXT: std 2, 24(1) # CHECK-NEXT: addis 12, 2, 1 @@ -49,8 +49,8 @@ ## Check that we emit 2 R_PPC64_IRELATIVE in .rela.dyn. ## glibc powerpc64 does not eagerly resolve R_PPC64_IRELATIVE if they are in .rela.plt. # REL: .rela.dyn { -# REL-NEXT: 0x10030250 R_PPC64_IRELATIVE - 0x100101F8 -# REL-NEXT: 0x10030258 R_PPC64_IRELATIVE - 0x100101FC +# REL-NEXT: 0x10030270 R_PPC64_IRELATIVE - 0x100101F8 +# REL-NEXT: 0x10030278 R_PPC64_IRELATIVE - 0x100101FC # REL-NEXT: } .type ifunc STT_GNU_IFUNC diff --git a/lld/test/ELF/ppc64-toc-relax-ifunc.s b/lld/test/ELF/ppc64-toc-relax-ifunc.s --- a/lld/test/ELF/ppc64-toc-relax-ifunc.s +++ b/lld/test/ELF/ppc64-toc-relax-ifunc.s @@ -14,12 +14,12 @@ ## to the address of the canonical PLT is fixed. # SEC: .text PROGBITS 00000000100101e0 -# SEC: .plt NOBITS 00000000100301f8 +# SEC: .plt NOBITS 0000000010030208 # SEC: 00000000100101e8 0 FUNC GLOBAL DEFAULT 3 ifunc ## .toc[0] stores the address of the canonical PLT. # HEX: section '.toc': -# HEX-NEXT: 0x100201f0 e8010110 00000000 +# HEX-NEXT: 0x10020200 e8010110 00000000 # REL: .rela.dyn { # REL-NEXT: 0x100301f8 R_PPC64_IRELATIVE - 0x100101e8