Date: Mon, 27 Jul 2026 16:56:03 +0000 From: Jessica Clarke <jrtc27@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: b68f2fe1932c - main - Merge commit 26bf39cdba0b from llvm-project (by Jessica Clarke): Message-ID: <6a678da3.22788.3013e684@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by jrtc27: URL: https://cgit.FreeBSD.org/src/commit/?id=b68f2fe1932cbc9809245e2c5a2db2bc0944cc5d commit b68f2fe1932cbc9809245e2c5a2db2bc0944cc5d Author: Jessica Clarke <jrtc27@FreeBSD.org> AuthorDate: 2026-07-27 16:54:04 +0000 Commit: Jessica Clarke <jrtc27@FreeBSD.org> CommitDate: 2026-07-27 16:54:04 +0000 Merge commit 26bf39cdba0b from llvm-project (by Jessica Clarke): [ELF][PowerPC] Don't assume TOC pointer is valid in IPLT entries (#207555) Unlike normal PLT entries, IPLT entries can be called indirectly even when in PIEs/DSOs, and so there's no guarantee on what's in the TOC pointer register at that time. Therefore we must emit variants of the existing code that work without it, whether r12-relative (playing the same role as MIPS's $25) in the same number of instructions, or first retrieving PC in an i386-like manner, being careful not to clobber LR. On 32-bit PowerPC even direct calls to IPLT entries face the same issue, since we'd use the TOC base of the resolver, which may not be the same as the caller, even within the same object. Normal canonical PLTs still look broken on 64-bit PowerPC as they use the TOC pointer register too, and similarly on 32-bit PowerPC for PIEs. We should probably treat these cases the same as PIE on i386 (except including PDEs for 64-bit PowerPC), where it's an error due to the use of %ebx in PLT entries. Bump LLD_FREEBSD_VERSION for this fix as otherwise an existing system linker will be deemed new enough to use and produce broken kernels for TARGET=powerpc (regardless of TARGET_ARCH/MACHINE/MACHINE_ARCH) builds. PR: 294369 MFC after: 1 week --- contrib/llvm-project/lld/ELF/Arch/PPC.cpp | 13 +++--- contrib/llvm-project/lld/ELF/Arch/PPC64.cpp | 5 ++- contrib/llvm-project/lld/ELF/Thunks.cpp | 69 +++++++++++++++++++++-------- contrib/llvm-project/lld/ELF/Thunks.h | 9 ++-- lib/clang/include/lld/Common/Version.inc | 2 +- 5 files changed, 67 insertions(+), 31 deletions(-) diff --git a/contrib/llvm-project/lld/ELF/Arch/PPC.cpp b/contrib/llvm-project/lld/ELF/Arch/PPC.cpp index 60a0a38d5f23..96f831d2cc5d 100644 --- a/contrib/llvm-project/lld/ELF/Arch/PPC.cpp +++ b/contrib/llvm-project/lld/ELF/Arch/PPC.cpp @@ -77,7 +77,7 @@ void elf::writePPC32GlinkSection(Ctx &ctx, uint8_t *buf, size_t numEntries) { if (!ctx.arg.isPic) { for (const Symbol *sym : cast<PPC32GlinkSection>(*ctx.in.plt).canonical_plts) { - writePPC32PltCallStub(ctx, buf, sym->getGotPltVA(ctx), nullptr, 0); + writePPC32PltCallStub(ctx, buf, glink, sym->getGotPltVA(ctx), nullptr, 0); buf += 16; glink += 16; } @@ -165,7 +165,7 @@ PPC::PPC(Ctx &ctx) : TargetInfo(ctx) { gotPltHeaderEntriesNum = 0; pltHeaderSize = 0; pltEntrySize = 4; - ipltEntrySize = 16; + ipltEntrySize = ctx.arg.isPic ? 32 : 16; needsThunks = true; @@ -180,10 +180,11 @@ PPC::PPC(Ctx &ctx) : TargetInfo(ctx) { } void PPC::writeIplt(uint8_t *buf, const Symbol &sym, - uint64_t /*pltEntryAddr*/) const { - // In -pie or -shared mode, assume r30 points to .got2+0x8000, and use a - // .got2.plt_pic32. thunk. - writePPC32PltCallStub(ctx, buf, sym.getGotPltVA(ctx), sym.file, 0x8000); + uint64_t pltEntryAddr) const { + // In -pie or -shared mode we can't rely on r30 for indirect calls, nor for + // direct calls with a different TOC base to the resolver. + writePPC32PltCallStub(ctx, buf, pltEntryAddr, sym.getGotPltVA(ctx), sym.file, + std::nullopt); } void PPC::writeGotHeader(uint8_t *buf) const { diff --git a/contrib/llvm-project/lld/ELF/Arch/PPC64.cpp b/contrib/llvm-project/lld/ELF/Arch/PPC64.cpp index 8e85cfab8a63..70fdbb0bbd19 100644 --- a/contrib/llvm-project/lld/ELF/Arch/PPC64.cpp +++ b/contrib/llvm-project/lld/ELF/Arch/PPC64.cpp @@ -1167,8 +1167,9 @@ void PPC64::writePlt(uint8_t *buf, const Symbol &sym, } void PPC64::writeIplt(uint8_t *buf, const Symbol &sym, - uint64_t /*pltEntryAddr*/) const { - writePPC64LoadAndBranch(ctx, buf, sym.getGotPltVA(ctx)); + uint64_t pltEntryAddr) const { + writePPC64LoadAndBranch(ctx, buf, pltEntryAddr, sym.getGotPltVA(ctx), + /*toc=*/false); } static std::pair<RelType, uint64_t> toAddr16Rel(RelType type, uint64_t val) { diff --git a/contrib/llvm-project/lld/ELF/Thunks.cpp b/contrib/llvm-project/lld/ELF/Thunks.cpp index 45b9ab9530e0..a8ed74e65189 100644 --- a/contrib/llvm-project/lld/ELF/Thunks.cpp +++ b/contrib/llvm-project/lld/ELF/Thunks.cpp @@ -1316,8 +1316,9 @@ InputSection *MicroMipsR6Thunk::getTargetInputSection() const { return dyn_cast<InputSection>(dr.section); } -void elf::writePPC32PltCallStub(Ctx &ctx, uint8_t *buf, uint64_t gotPltVA, - const InputFile *file, int64_t addend) { +void elf::writePPC32PltCallStub(Ctx &ctx, uint8_t *buf, uint64_t p, + uint64_t gotPltVA, const InputFile *file, + std::optional<int64_t> addend) { if (!ctx.arg.isPic) { write32(ctx, buf + 0, 0x3d600000 | (gotPltVA + 0x8000) >> 16); // lis r11,ha write32(ctx, buf + 4, 0x816b0000 | (uint16_t)gotPltVA); // lwz r11,l(r11) @@ -1326,34 +1327,52 @@ void elf::writePPC32PltCallStub(Ctx &ctx, uint8_t *buf, uint64_t gotPltVA, return; } uint32_t offset; - if (addend >= 0x8000) { + uint32_t reg; + uint64_t written = 0; + if (!addend) { + // We're a (position-independent) IPLT entry, so cannot assume anything + // about what value the caller left in r30 as this could be an indirect + // call. + write32(ctx, buf + 0, 0x7c0802a6); // mflr r0 + write32(ctx, buf + 4, 0x429f0005); // bcl 20, 31, 1f + write32(ctx, buf + 8, 0x7d6802a6); // 1: mflr r11 + write32(ctx, buf + 12, 0x7c0803a6); // mtlr r0 + offset = gotPltVA - p - 8; + reg = 11; + written = 16; + } else if (*addend >= 0x8000) { // 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. + reg = 30; offset = gotPltVA - (ctx.in.ppc32Got2->getParent()->getVA() + - (file->ppc32Got2 ? file->ppc32Got2->outSecOff : 0) + addend); + (file->ppc32Got2 ? file->ppc32Got2->outSecOff : 0) + *addend); } else { // The stub loads an address relative to _GLOBAL_OFFSET_TABLE_ (which is // currently the address of .got). + reg = 30; offset = gotPltVA - ctx.in.got->getVA(); } uint16_t ha = (offset + 0x8000) >> 16, l = (uint16_t)offset; if (ha == 0) { - write32(ctx, buf + 0, 0x817e0000 | l); // lwz r11,l(r30) - write32(ctx, buf + 4, 0x7d6903a6); // mtctr r11 - write32(ctx, buf + 8, 0x4e800420); // bctr - write32(ctx, buf + 12, 0x60000000); // nop + write32(ctx, buf + written + 0, + 0x81600000 | (reg << 16) | l); // lwz r11,l(r[11|30]) + write32(ctx, buf + written + 4, 0x7d6903a6); // mtctr r11 + write32(ctx, buf + written + 8, 0x4e800420); // bctr + write32(ctx, buf + written + 12, 0x60000000); // nop } else { - write32(ctx, buf + 0, 0x3d7e0000 | ha); // addis r11,r30,ha - write32(ctx, buf + 4, 0x816b0000 | l); // lwz r11,l(r11) - write32(ctx, buf + 8, 0x7d6903a6); // mtctr r11 - write32(ctx, buf + 12, 0x4e800420); // bctr + write32(ctx, buf + written + 0, + 0x3d600000 | (reg << 16) | ha); // addis r11,r[11|30],ha + write32(ctx, buf + written + 4, 0x816b0000 | l); // lwz r11,l(r11) + write32(ctx, buf + written + 8, 0x7d6903a6); // mtctr r11 + write32(ctx, buf + written + 12, 0x4e800420); // bctr } } void PPC32PltCallStub::writeTo(uint8_t *buf) { - writePPC32PltCallStub(ctx, buf, destination.getGotPltVA(ctx), file, addend); + writePPC32PltCallStub(ctx, buf, getThunkTargetSym()->getVA(ctx), + destination.getGotPltVA(ctx), file, addend); } void PPC32PltCallStub::addSymbols(ThunkSection &isec) { @@ -1402,12 +1421,22 @@ void PPC32LongThunk::writeTo(uint8_t *buf) { write32(ctx, buf + 4, 0x4e800420); // bctr } -void elf::writePPC64LoadAndBranch(Ctx &ctx, uint8_t *buf, uint64_t addr) { - uint64_t offset = addr - getPPC64TocBase(ctx); +void elf::writePPC64LoadAndBranch(Ctx &ctx, uint8_t *buf, uint64_t p, + uint64_t addr, bool toc) { + uint64_t offset; + uint32_t reg; + if (toc) { + offset = addr - getPPC64TocBase(ctx); + reg = 2; + } else { + offset = addr - p; + reg = 12; + } uint16_t offHa = (offset + 0x8000) >> 16; uint16_t offLo = offset & 0xffff; - write32(ctx, buf + 0, 0x3d820000 | offHa); // addis r12, r2, OffHa + write32(ctx, buf + 0, + 0x3d800000 | (reg << 16) | offHa); // addis r12, r[2|12], OffHa write32(ctx, buf + 4, 0xe98c0000 | offLo); // ld r12, OffLo(r12) write32(ctx, buf + 8, 0x7d8903a6); // mtctr r12 write32(ctx, buf + 12, 0x4e800420); // bctr @@ -1416,7 +1445,8 @@ void elf::writePPC64LoadAndBranch(Ctx &ctx, uint8_t *buf, uint64_t addr) { void PPC64PltCallStub::writeTo(uint8_t *buf) { // Save the TOC pointer to the save-slot reserved in the call frame. write32(ctx, buf + 0, 0xf8410018); // std r2,24(r1) - writePPC64LoadAndBranch(ctx, buf + 4, destination.getGotPltVA(ctx)); + writePPC64LoadAndBranch(ctx, buf + 4, getThunkTargetSym()->getVA(ctx) + 4, + destination.getGotPltVA(ctx)); } void PPC64PltCallStub::addSymbols(ThunkSection &isec) { @@ -1458,7 +1488,8 @@ void PPC64R2SaveStub::writeTo(uint8_t *buf) { ctx.in.ppc64LongBranchTarget->addEntry(&destination, addend); const uint64_t addr = ctx.in.ppc64LongBranchTarget->getEntryVA(&destination, addend); - writePPC64LoadAndBranch(ctx, buf + 4, addr); + writePPC64LoadAndBranch(ctx, buf + 4, getThunkTargetSym()->getVA(ctx) + 4, + addr); } } @@ -1520,7 +1551,7 @@ bool PPC64R12SetupStub::isCompatibleWith(const InputSection &isec, void PPC64LongBranchThunk::writeTo(uint8_t *buf) { uint64_t addr = ctx.in.ppc64LongBranchTarget->getEntryVA(&destination, addend); - writePPC64LoadAndBranch(ctx, buf, addr); + writePPC64LoadAndBranch(ctx, buf, getThunkTargetSym()->getVA(ctx), addr); } void PPC64LongBranchThunk::addSymbols(ThunkSection &isec) { diff --git a/contrib/llvm-project/lld/ELF/Thunks.h b/contrib/llvm-project/lld/ELF/Thunks.h index a802827ba407..7903b6ae97a0 100644 --- a/contrib/llvm-project/lld/ELF/Thunks.h +++ b/contrib/llvm-project/lld/ELF/Thunks.h @@ -83,9 +83,12 @@ std::unique_ptr<Thunk> addThunk(Ctx &, const InputSection &isec, // are restricted. std::unique_ptr<Thunk> addLandingPadThunk(Ctx &, Symbol &s, int64_t a); -void writePPC32PltCallStub(Ctx &, uint8_t *buf, uint64_t gotPltVA, - const InputFile *file, int64_t addend); -void writePPC64LoadAndBranch(Ctx &, uint8_t *buf, uint64_t addr); +// Call with addend as nullopt for an IPLT entry with no valid TOC pointer +void writePPC32PltCallStub(Ctx &, uint8_t *buf, uint64_t p, uint64_t gotPltVA, + const InputFile *file, + std::optional<int64_t> addend); +void writePPC64LoadAndBranch(Ctx &, uint8_t *buf, uint64_t p, uint64_t addr, + bool toc = true); } // namespace lld::elf diff --git a/lib/clang/include/lld/Common/Version.inc b/lib/clang/include/lld/Common/Version.inc index 0ddfb58d5ad3..2fbfe82f7063 100644 --- a/lib/clang/include/lld/Common/Version.inc +++ b/lib/clang/include/lld/Common/Version.inc @@ -1,4 +1,4 @@ // Local identifier in __FreeBSD_version style -#define LLD_FREEBSD_VERSION 1600000 +#define LLD_FREEBSD_VERSION 1600001 #define LLD_VERSION_STRING "21.1.8 (FreeBSD llvmorg-21.1.8-0-g2078da43e25a-" __XSTRING(LLD_FREEBSD_VERSION) ")"home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a678da3.22788.3013e684>
