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);