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 @@ -671,9 +671,20 @@ void PPC64::writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr, int32_t index, unsigned relOff) const { - int32_t offset = pltHeaderSize + index * pltEntrySize; - // bl __glink_PLTresolve - write32(buf, 0x48000000 | ((-offset) & 0x03FFFFFc)); + if (index < 0) { + int64_t offset = gotPltEntryAddr - getPPC64TocBase(); + uint16_t offHa = (offset + 0x8000) >> 16; + uint16_t offLo = offset & 0xffff; + + write32(buf + 0, 0x3d820000 | offHa); // addis r12, r2, OffHa + write32(buf + 4, 0xe98c0000 | offLo); // ld r12, OffLo(r12) + write32(buf + 8, 0x7d8903a6); // mtctr r12 + write32(buf + 12, 0x4e800420); // bctr + } else { + int32_t offset = pltHeaderSize + index * pltEntrySize; + // bl __glink_PLTresolve + write32(buf, 0x48000000 | ((-offset) & 0x03FFFFFc)); + } } static std::pair toAddr16Rel(RelType type, uint64_t val) { diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -2481,7 +2481,8 @@ unsigned relOff = relSec->entsize * i + pltOff; uint64_t got = b->getGotPltVA(); uint64_t plt = this->getVA() + off; - target->writePlt(buf + off, got, plt, b->pltIndex, relOff); + int index = isIplt ? -1 : (int)b->pltIndex; + target->writePlt(buf + off, got, plt, index, relOff); off += target->pltEntrySize; } } @@ -2492,6 +2493,8 @@ } size_t PltSection::getSize() const { + if (config->emachine == EM_PPC64 && isIplt) + return entries.size() * 16; return headerSize + entries.size() * target->pltEntrySize; }