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;