From: Mark Kettenis Subject: Re: lld: add MIPS lazy binding stubs To: Kirill A. Korinsky Cc: tech@openbsd.org, semarie@openbsd.org, robert@openbsd.org Date: Mon, 02 Nov 2026 07:51:50 +0100 > Date: Sun, 01 Nov 2026 23:42:39 +0100 > From: Kirill A. Korinsky > > tech@, > > here a diff for base llvm and both 22 and 23 in ports to implement lazy > binding in LLD for mips64 which is based on visa@'s sketch diff. > > regress/libexec/ld.so/lazy is passed, and visa@ tested it on his device. > > This diff was backported to uptream as > https://github.com/llvm/llvm-project/pull/237790 > > Ok? Given the upstream review of that diff, I think we shouldn't rush ahead with this. I don't think we want to carry a significant local diff like thise ~forever... I don't have the cycles available right now to understand the .MIPS.stubs stuff and look into the suggested rtld changes. But we probably should investigate the suggestions being made. > Index: src/gnu/llvm/lld/ELF/Config.h > =================================================================== > RCS file: /home/cvs/src/gnu/llvm/lld/ELF/Config.h,v > diff -u -p -r1.7 Config.h > --- src/gnu/llvm/lld/ELF/Config.h 29 May 2026 11:06:20 -0000 1.7 > +++ src/gnu/llvm/lld/ELF/Config.h 1 Nov 2026 20:37:58 -0000 > @@ -65,6 +65,7 @@ class InputSection; > class IpltSection; > class MipsGotSection; > class MipsRldMapSection; > +class MipsStubsSection; > class PPC32Got2Section; > class PPC64LongBranchTargetSection; > class PltSection; > @@ -592,6 +593,7 @@ struct InStruct { > std::unique_ptr mipsOptions; > std::unique_ptr mipsReginfo; > std::unique_ptr mipsRldMap; > + std::unique_ptr mipsStubs; > std::unique_ptr partEnd; > std::unique_ptr partIndex; > std::unique_ptr plt; > Index: src/gnu/llvm/lld/ELF/Relocations.cpp > =================================================================== > RCS file: /home/cvs/src/gnu/llvm/lld/ELF/Relocations.cpp,v > diff -u -p -r1.12 Relocations.cpp > --- src/gnu/llvm/lld/ELF/Relocations.cpp 30 Jul 2026 19:28:37 -0000 1.12 > +++ src/gnu/llvm/lld/ELF/Relocations.cpp 1 Nov 2026 20:37:58 -0000 > @@ -1442,6 +1442,8 @@ void RelocScan::scanEhSection(EhInputSec > if (sym->isUndefined() && > maybeReportUndefined(cast(*sym), offset)) > continue; > + if (ctx.arg.emachine == EM_MIPS) > + sym->setFlags(NO_MIPS_STUB); > process(r.expr, r.type, offset, *sym, r.addend); > } > } > Index: src/gnu/llvm/lld/ELF/Symbols.h > =================================================================== > RCS file: /home/cvs/src/gnu/llvm/lld/ELF/Symbols.h,v > diff -u -p -r1.9 Symbols.h > --- src/gnu/llvm/lld/ELF/Symbols.h 30 Jul 2026 19:28:37 -0000 1.9 > +++ src/gnu/llvm/lld/ELF/Symbols.h 1 Nov 2026 20:37:58 -0000 > @@ -55,6 +55,8 @@ enum { > NEEDS_GOT_NONAUTH = 1 << 10, > NEEDS_TLSDESC_AUTH = 1 << 11, > NEEDS_TLSDESC_NONAUTH = 1 << 12, > + HAS_MIPS_CALL_RELOC = 1 << 13, > + NO_MIPS_STUB = 1 << 14, > }; > > // The base class for real symbol classes. > Index: src/gnu/llvm/lld/ELF/SyntheticSections.cpp > =================================================================== > RCS file: /home/cvs/src/gnu/llvm/lld/ELF/SyntheticSections.cpp,v > diff -u -p -r1.11 SyntheticSections.cpp > --- src/gnu/llvm/lld/ELF/SyntheticSections.cpp 30 Jul 2026 19:28:37 -0000 1.11 > +++ src/gnu/llvm/lld/ELF/SyntheticSections.cpp 1 Nov 2026 20:37:58 -0000 > @@ -1095,8 +1095,10 @@ void MipsGotSection::build() { > if (&got == primGot) > continue; > > - // Dynamic relocations for "global" entries. > + // A lazy stub requires the primary GOT's resolver slots and $gp. > + // Calls through secondary GOTs must be resolved eagerly. > for (const std::pair &p : got.global) { > + p.first->setFlags(NO_MIPS_STUB); > uint64_t offset = p.second * ctx.arg.wordsize; > ctx.mainPart->relaDyn->addSymbolReloc(ctx.target->relativeRel, *this, > offset, *p.first); > @@ -1177,13 +1179,21 @@ void MipsGotSection::writeTo(uint8_t *bu > // http://web.archive.org/web/20190324223224/https://www.linux-mips.org/wiki/NPTL > for (const std::pair &p : g.local16) > write(p.second, p.first.first, p.first.second); > + auto writeGlobal = [&](size_t i, const Symbol *s) { > + if (std::optional va = > + ctx.in.mipsStubs ? ctx.in.mipsStubs->getStubVA(*s) > + : std::nullopt) > + write(i, nullptr, *va); > + else > + write(i, s, 0); > + }; > // Write VA to the primary GOT only. For secondary GOTs that > // will be done by REL32 dynamic relocations. > if (&g == &gots.front()) > for (const std::pair &p : g.global) > - write(p.second, p.first, 0); > + writeGlobal(p.second, p.first); > for (const std::pair &p : g.relocs) > - write(p.second, p.first, 0); > + writeGlobal(p.second, p.first); > for (const std::pair &p : g.tls) > write(p.second, p.first, > p.first->isPreemptible || ctx.arg.shared ? 0 : -0x7000); > @@ -1202,6 +1212,54 @@ void MipsGotSection::writeTo(uint8_t *bu > } > } > > +MipsStubsSection::MipsStubsSection(Ctx &ctx) > + : SyntheticSection(ctx, ".MIPS.stubs", SHT_PROGBITS, > + SHF_ALLOC | SHF_EXECINSTR, ctx.arg.wordsize) {} > + > +void MipsStubsSection::addSymbols() { > + // microMIPS stubs are not implemented. > + if (isMicroMips(ctx)) > + return; > + for (Symbol *sym : ctx.symtab->getSymbols()) { > + if (!sym->isPreemptible || !(sym->isUndefined() || sym->isShared()) || > + !sym->isFunc() || !sym->hasFlag(HAS_MIPS_CALL_RELOC) || > + sym->hasFlag(NO_MIPS_STUB) || sym->hasFlag(NEEDS_PLT)) > + continue; > + entries.push_back(sym); > + } > + > + // Include the full stub size in GOT page counts before GOT layout. > + // Removing secondary GOT candidates later can only shrink this size. > + stubSize = ctx.mainPart->dynSymTab->getNumSymbols() > 0x10000 > + ? stubBigSize > + : stubNormalSize; > +} > + > +std::optional > +MipsStubsSection::getStubVA(const Symbol &sym) const { > + if (!getParent()) > + return std::nullopt; > + auto it = indices.find(&sym); > + if (it == indices.end()) > + return std::nullopt; > + return getVA() + it->second * stubSize; > +} > + > +void MipsStubsSection::finalizeContents() { > + llvm::erase_if(entries, [&](const Symbol *sym) { > + return sym->hasFlag(NO_MIPS_STUB) || !sym->isInGot(ctx); > + }); > + for (size_t i = 0; i != entries.size(); ++i) > + indices[entries[i]] = i; > +} > + > +void MipsStubsSection::writeTo(uint8_t *buf) { > + for (const Symbol *sym : entries) { > + writeMipsStub(ctx, buf, sym->dynsymIndex, stubSize == stubBigSize); > + buf += stubSize; > + } > +} > + > // On PowerPC the .plt section is used to hold the table of function addresses > // instead of the .got.plt, and the type is SHT_NOBITS similar to a .bss > // section. I don't know why we have a BSS style type for the section but it is > @@ -2351,6 +2409,9 @@ template void SymbolTableSe > Symbol *sym = ent.sym; > if (sym->isInPlt(ctx) && sym->hasFlag(NEEDS_COPY)) > eSym->st_other |= STO_MIPS_PLT; > + if (type == SHT_DYNSYM && ctx.in.mipsStubs) > + if (std::optional va = ctx.in.mipsStubs->getStubVA(*sym)) > + eSym->st_value = *va; > if (isMicroMips(ctx)) { > // We already set the less-significant bit for symbols > // marked by the `STO_MIPS_MICROMIPS` flag and for microMIPS PLT > @@ -4926,6 +4987,11 @@ template void elf::createSy > add(*ctx.in.plt); > ctx.in.iplt = std::make_unique(ctx); > add(*ctx.in.iplt); > + > + if (ctx.arg.emachine == EM_MIPS && !ctx.arg.relocatable && ctx.hasDynsym) { > + ctx.in.mipsStubs = std::make_unique(ctx); > + add(*ctx.in.mipsStubs); > + } > > if (ctx.arg.andFeatures || ctx.aarch64PauthAbiCoreInfo) { > ctx.in.gnuProperty = std::make_unique(ctx); > Index: src/gnu/llvm/lld/ELF/SyntheticSections.h > =================================================================== > RCS file: /home/cvs/src/gnu/llvm/lld/ELF/SyntheticSections.h,v > diff -u -p -r1.6 SyntheticSections.h > --- src/gnu/llvm/lld/ELF/SyntheticSections.h 30 Jul 2026 19:28:37 -0000 1.6 > +++ src/gnu/llvm/lld/ELF/SyntheticSections.h 1 Nov 2026 20:37:58 -0000 > @@ -1202,6 +1202,24 @@ public: > void writeTo(uint8_t *buf) override {} > }; > > +class MipsStubsSection final : public SyntheticSection { > + static constexpr size_t stubNormalSize = 16; > + static constexpr size_t stubBigSize = 20; > +public: > + MipsStubsSection(Ctx &); > + void addSymbols(); > + std::optional getStubVA(const Symbol &sym) const; > + size_t getSize() const override { return entries.size() * stubSize; } > + bool isNeeded() const override { return !entries.empty(); } > + void finalizeContents() override; > + void writeTo(uint8_t *buf) override; > + > +private: > + SmallVector entries; > + llvm::DenseMap indices; > + size_t stubSize = stubNormalSize; > +}; > + > // Representation of the combined .ARM.Exidx input sections. We process these > // as a SyntheticSection like .eh_frame as we need to merge duplicate entries > // and add terminating sentinel entries. > Index: src/gnu/llvm/lld/ELF/Target.h > =================================================================== > RCS file: /home/cvs/src/gnu/llvm/lld/ELF/Target.h,v > diff -u -p -r1.2 Target.h > --- src/gnu/llvm/lld/ELF/Target.h 30 Jul 2026 19:28:37 -0000 1.2 > +++ src/gnu/llvm/lld/ELF/Target.h 1 Nov 2026 20:37:58 -0000 > @@ -247,6 +247,7 @@ uint64_t getMipsPageAddr(uint64_t addr); > bool isMipsN32Abi(Ctx &, const InputFile &f); > bool isMicroMips(Ctx &); > bool isMipsR6(Ctx &); > +void writeMipsStub(Ctx &, uint8_t *buf, uint32_t dynsymIndex, bool big); > > void writePPC32GlinkSection(Ctx &, uint8_t *buf, size_t numEntries); > > Index: src/gnu/llvm/lld/ELF/Writer.cpp > =================================================================== > RCS file: /home/cvs/src/gnu/llvm/lld/ELF/Writer.cpp,v > diff -u -p -r1.12 Writer.cpp > --- src/gnu/llvm/lld/ELF/Writer.cpp 20 Aug 2026 14:39:18 -0000 1.12 > +++ src/gnu/llvm/lld/ELF/Writer.cpp 1 Nov 2026 20:37:58 -0000 > @@ -2016,8 +2016,11 @@ template void Writer: > } > } > > + if (ctx.in.mipsStubs) > + ctx.in.mipsStubs->addSymbols(); > if (ctx.in.mipsGot) > ctx.in.mipsGot->build(); > + finalizeSynthetic(ctx, ctx.in.mipsStubs.get()); > > removeUnusedSyntheticSections(ctx); > ctx.script->diagnoseOrphanHandling(); > Index: src/gnu/llvm/lld/ELF/Arch/Mips.cpp > =================================================================== > RCS file: /home/cvs/src/gnu/llvm/lld/ELF/Arch/Mips.cpp,v > diff -u -p -r1.1.1.6 Mips.cpp > --- src/gnu/llvm/lld/ELF/Arch/Mips.cpp 29 May 2026 11:05:55 -0000 1.1.1.6 > +++ src/gnu/llvm/lld/ELF/Arch/Mips.cpp 1 Nov 2026 20:37:58 -0000 > @@ -48,6 +48,41 @@ uint64_t elf::getMipsPageAddr(uint64_t a > return (addr + 0x8000) & ~0xffff; > } > > +void elf::writeMipsStub(Ctx &ctx, uint8_t *buf, uint32_t dynsymIndex, > + bool big) { > + if (dynsymIndex > 0x7fffffff) { > + ErrAlways(ctx) << "MIPS lazy-binding stub dynamic symbol index " > + << dynsymIndex << " exceeds 31 bits"; > + return; > + } > + > + const uint32_t load = ctx.arg.is64 ? 0xdf998010 // ld $25, -0x7ff0($28) > + : 0x8f998010; // lw $25, -0x7ff0($28) > + const uint32_t lui = 0x3c180000 | ((dynsymIndex >> 16) & 0x7fff); > + const uint32_t jalr = ctx.arg.zHazardplt ? 0x0320fc09 : 0x0320f809; > + uint32_t loadIndex; > + if (big) > + loadIndex = 0x37180000 | (dynsymIndex & 0xffff); // ori $24, $24, idx > + else if (dynsymIndex & ~0x7fff) > + loadIndex = 0x34180000 | (dynsymIndex & 0xffff); // ori $24, $0, idx > + else > + loadIndex = (ctx.arg.is64 ? 0x64180000 : 0x24180000) | // [d]addiu $24, > + dynsymIndex; // $0, idx > + > + if (big) { > + write32(ctx, buf, load); > + write32(ctx, buf + 4, 0x03e07825); // move $15, $31 > + write32(ctx, buf + 8, lui); > + write32(ctx, buf + 12, jalr); // jalr[.hb] $25 > + write32(ctx, buf + 16, loadIndex); // delay slot > + } else { > + write32(ctx, buf, load); > + write32(ctx, buf + 4, 0x03e07825); // move $15, $31 > + write32(ctx, buf + 8, jalr); // jalr[.hb] $25 > + write32(ctx, buf + 12, loadIndex); // delay slot > + } > +} > + > template MIPS::MIPS(Ctx &ctx) : TargetInfo(ctx) { > gotPltHeaderEntriesNum = 2; > defaultMaxPageSize = 65536; > @@ -609,6 +644,13 @@ static RelType getMipsPairType(RelType t > } > } > > +static bool isCallReloc(RelType type) { > + return type == R_MIPS_CALL16 || > + type == R_MIPS_CALL_HI16 || type == R_MIPS_CALL_LO16 || > + type == R_MICROMIPS_CALL16 || > + type == R_MICROMIPS_CALL_HI16 || type == R_MICROMIPS_CALL_LO16; > +} > + > template > template > void MIPS::scanSectionImpl(InputSectionBase &sec, Relocs rels) { > @@ -639,6 +681,21 @@ void MIPS::scanSectionImpl(InputSe > if (sym.isUndefined() && symIdx != 0 && > rs.maybeReportUndefined(cast(sym), offset)) > continue; > + > + // In a shared object, turn untyped undefined symbols with a call > + // relocation into function symbols so that the dynamic linker handles > + // them correctly. > + if (ctx.arg.shared && sym.isUndefined() && symIdx != 0 && > + sym.type == STT_NOTYPE && isCallReloc(type.v & 0xff)) > + sym.type = STT_FUNC; > + > + if (symIdx != 0) { > + uint32_t baseType = type.v & 0xff; > + if (isCallReloc(baseType)) > + sym.setFlags(HAS_MIPS_CALL_RELOC); > + else if (baseType != R_MIPS_JALR && baseType != R_MICROMIPS_JALR) > + sym.setFlags(NO_MIPS_STUB); > + } > > auto addend = rs.getAddend(rel, type); > if (expr == RE_MIPS_GOTREL && sym.isLocal()) { > Index: ports/devel/llvm/22/Makefile > =================================================================== > RCS file: /home/cvs/ports/devel/llvm/22/Makefile,v > diff -u -p -r1.28 Makefile > --- ports/devel/llvm/22/Makefile 16 Sep 2026 01:03:57 -0000 1.28 > +++ ports/devel/llvm/22/Makefile 1 Nov 2026 21:04:16 -0000 > @@ -2,7 +2,7 @@ LLVM_MAJOR = 22 > LLVM_VERSION = ${LLVM_MAJOR}.1.8 > LLVM_PKGSPEC = >=22,<23 > > -REVISION = 10 > +REVISION = 11 > > SHARED_LIBS += LLVM 0.0 \ > LTO 0.0 \ > Index: ports/devel/llvm/22/patches/patch-lld_ELF_Arch_Mips_cpp > =================================================================== > RCS file: ports/devel/llvm/22/patches/patch-lld_ELF_Arch_Mips_cpp > diff -N ports/devel/llvm/22/patches/patch-lld_ELF_Arch_Mips_cpp > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ ports/devel/llvm/22/patches/patch-lld_ELF_Arch_Mips_cpp 1 Nov 2026 21:01:39 -0000 > @@ -0,0 +1,81 @@ > +Index: lld/ELF/Arch/Mips.cpp > +--- lld/ELF/Arch/Mips.cpp.orig > ++++ lld/ELF/Arch/Mips.cpp > +@@ -48,6 +48,41 @@ uint64_t elf::getMipsPageAddr(uint64_t addr) { > + return (addr + 0x8000) & ~0xffff; > + } > + > ++void elf::writeMipsStub(Ctx &ctx, uint8_t *buf, uint32_t dynsymIndex, > ++ bool big) { > ++ if (dynsymIndex > 0x7fffffff) { > ++ ErrAlways(ctx) << "MIPS lazy-binding stub dynamic symbol index " > ++ << dynsymIndex << " exceeds 31 bits"; > ++ return; > ++ } > ++ > ++ const uint32_t load = ctx.arg.is64 ? 0xdf998010 // ld $25, -0x7ff0($28) > ++ : 0x8f998010; // lw $25, -0x7ff0($28) > ++ const uint32_t lui = 0x3c180000 | ((dynsymIndex >> 16) & 0x7fff); > ++ const uint32_t jalr = ctx.arg.zHazardplt ? 0x0320fc09 : 0x0320f809; > ++ uint32_t loadIndex; > ++ if (big) > ++ loadIndex = 0x37180000 | (dynsymIndex & 0xffff); // ori $24, $24, idx > ++ else if (dynsymIndex & ~0x7fff) > ++ loadIndex = 0x34180000 | (dynsymIndex & 0xffff); // ori $24, $0, idx > ++ else > ++ loadIndex = (ctx.arg.is64 ? 0x64180000 : 0x24180000) | // [d]addiu $24, > ++ dynsymIndex; // $0, idx > ++ > ++ if (big) { > ++ write32(ctx, buf, load); > ++ write32(ctx, buf + 4, 0x03e07825); // move $15, $31 > ++ write32(ctx, buf + 8, lui); > ++ write32(ctx, buf + 12, jalr); // jalr[.hb] $25 > ++ write32(ctx, buf + 16, loadIndex); // delay slot > ++ } else { > ++ write32(ctx, buf, load); > ++ write32(ctx, buf + 4, 0x03e07825); // move $15, $31 > ++ write32(ctx, buf + 8, jalr); // jalr[.hb] $25 > ++ write32(ctx, buf + 12, loadIndex); // delay slot > ++ } > ++} > ++ > + template MIPS::MIPS(Ctx &ctx) : TargetInfo(ctx) { > + gotPltHeaderEntriesNum = 2; > + defaultMaxPageSize = 65536; > +@@ -609,6 +644,13 @@ static RelType getMipsPairType(RelType type, bool isLo > + } > + } > + > ++static bool isCallReloc(RelType type) { > ++ return type == R_MIPS_CALL16 || > ++ type == R_MIPS_CALL_HI16 || type == R_MIPS_CALL_LO16 || > ++ type == R_MICROMIPS_CALL16 || > ++ type == R_MICROMIPS_CALL_HI16 || type == R_MICROMIPS_CALL_LO16; > ++} > ++ > + template > + template > + void MIPS::scanSectionImpl(InputSectionBase &sec, Relocs rels) { > +@@ -639,6 +681,21 @@ void MIPS::scanSectionImpl(InputSectionBase &sec > + if (sym.isUndefined() && symIdx != 0 && > + rs.maybeReportUndefined(cast(sym), offset)) > + continue; > ++ > ++ // In a shared object, turn untyped undefined symbols with a call > ++ // relocation into function symbols so that the dynamic linker handles > ++ // them correctly. > ++ if (ctx.arg.shared && sym.isUndefined() && symIdx != 0 && > ++ sym.type == STT_NOTYPE && isCallReloc(type.v & 0xff)) > ++ sym.type = STT_FUNC; > ++ > ++ if (symIdx != 0) { > ++ uint32_t baseType = type.v & 0xff; > ++ if (isCallReloc(baseType)) > ++ sym.setFlags(HAS_MIPS_CALL_RELOC); > ++ else if (baseType != R_MIPS_JALR && baseType != R_MICROMIPS_JALR) > ++ sym.setFlags(NO_MIPS_STUB); > ++ } > + > + auto addend = rs.getAddend(rel, type); > + if (expr == RE_MIPS_GOTREL && sym.isLocal()) { > Index: ports/devel/llvm/22/patches/patch-lld_ELF_Config_h > =================================================================== > RCS file: /home/cvs/ports/devel/llvm/22/patches/patch-lld_ELF_Config_h,v > diff -u -p -r1.1.1.1 patch-lld_ELF_Config_h > --- ports/devel/llvm/22/patches/patch-lld_ELF_Config_h 25 Feb 2026 13:31:42 -0000 1.1.1.1 > +++ ports/devel/llvm/22/patches/patch-lld_ELF_Config_h 1 Nov 2026 21:01:39 -0000 > @@ -1,7 +1,15 @@ > Index: lld/ELF/Config.h > --- lld/ELF/Config.h.orig > +++ lld/ELF/Config.h > -@@ -443,8 +443,13 @@ struct Config { > +@@ -65,6 +65,7 @@ class InputSection; > + class IpltSection; > + class MipsGotSection; > + class MipsRldMapSection; > ++class MipsStubsSection; > + class PPC32Got2Section; > + class PPC64LongBranchTargetSection; > + class PltSection; > +@@ -443,8 +444,13 @@ struct Config { > ELFKind ekind = ELFNoneKind; > uint16_t emachine = llvm::ELF::EM_NONE; > std::optional imageBase; > @@ -15,7 +23,15 @@ Index: lld/ELF/Config.h > uint64_t mipsGotSize; > uint64_t zStackSize; > unsigned ltoPartitions; > -@@ -632,6 +637,9 @@ struct Ctx : CommonLinkerContext { > +@@ -587,6 +593,7 @@ struct InStruct { > + std::unique_ptr mipsOptions; > + std::unique_ptr mipsReginfo; > + std::unique_ptr mipsRldMap; > ++ std::unique_ptr mipsStubs; > + std::unique_ptr partEnd; > + std::unique_ptr partIndex; > + std::unique_ptr plt; > +@@ -632,6 +639,9 @@ struct Ctx : CommonLinkerContext { > struct ElfSym { > // __bss_start > Defined *bss; > Index: ports/devel/llvm/22/patches/patch-lld_ELF_Relocations_cpp > =================================================================== > RCS file: /home/cvs/ports/devel/llvm/22/patches/patch-lld_ELF_Relocations_cpp,v > diff -u -p -r1.3 patch-lld_ELF_Relocations_cpp > --- ports/devel/llvm/22/patches/patch-lld_ELF_Relocations_cpp 30 Jul 2026 19:28:03 -0000 1.3 > +++ ports/devel/llvm/22/patches/patch-lld_ELF_Relocations_cpp 1 Nov 2026 21:01:39 -0000 > @@ -161,7 +161,16 @@ Index: lld/ELF/Relocations.cpp > (ctx.arg.emachine != EM_LOONGARCH || execOptimizeInLoongArch) && > !(isRISCV && expr != R_TLSDESC_PC && expr != R_TLSDESC_CALL) && > !sec->file->ppc64DisableTLSRelax; > -@@ -1555,10 +1605,7 @@ void elf::postScanRelocations(Ctx &ctx) { > +@@ -1392,6 +1442,8 @@ void RelocScan::scanEhSection(EhInputSection &s) { > + if (sym->isUndefined() && > + maybeReportUndefined(cast(*sym), offset)) > + continue; > ++ if (ctx.arg.emachine == EM_MIPS) > ++ sym->setFlags(NO_MIPS_STUB); > + process(r.expr, r.type, offset, *sym, r.addend); > + } > + } > +@@ -1555,10 +1607,7 @@ void elf::postScanRelocations(Ctx &ctx) { > } else { > assert(sym.isFunc() && sym.hasFlag(NEEDS_PLT)); > if (!sym.isDefined()) { > @@ -173,7 +182,7 @@ Index: lld/ELF/Relocations.cpp > sym.setFlags(NEEDS_COPY); > if (ctx.arg.emachine == EM_PPC) { > // PPC32 canonical PLT entries are at the beginning of .glink > -@@ -2203,11 +2250,11 @@ bool ThunkCreator::createThunks(uint32_t pass, > +@@ -2203,11 +2252,11 @@ bool ThunkCreator::createThunks(uint32_t pass, > return addressesChanged; > } > > @@ -190,7 +199,7 @@ Index: lld/ELF/Relocations.cpp > bool needTlsSymbol = false; > forEachInputSectionDescription( > outputSections, [&](OutputSection *os, InputSectionDescription *isd) { > -@@ -2221,7 +2268,7 @@ bool elf::hexagonNeedsTLSSymbol(ArrayRef +@@ -2221,7 +2270,7 @@ bool elf::hexagonNeedsTLSSymbol(ArrayRef return needTlsSymbol; > } > > Index: ports/devel/llvm/22/patches/patch-lld_ELF_Symbols_cpp > =================================================================== > RCS file: /home/cvs/ports/devel/llvm/22/patches/patch-lld_ELF_Symbols_cpp,v > diff -u -p -r1.2 patch-lld_ELF_Symbols_cpp > --- ports/devel/llvm/22/patches/patch-lld_ELF_Symbols_cpp 30 Jul 2026 19:28:03 -0000 1.2 > +++ ports/devel/llvm/22/patches/patch-lld_ELF_Symbols_cpp 1 Nov 2026 21:01:39 -0000 > @@ -1,5 +1,3 @@ > -XXX SymbolUnion > - > Index: lld/ELF/Symbols.cpp > --- lld/ELF/Symbols.cpp.orig > +++ lld/ELF/Symbols.cpp > Index: ports/devel/llvm/22/patches/patch-lld_ELF_Symbols_h > =================================================================== > RCS file: /home/cvs/ports/devel/llvm/22/patches/patch-lld_ELF_Symbols_h,v > diff -u -p -r1.5 patch-lld_ELF_Symbols_h > --- ports/devel/llvm/22/patches/patch-lld_ELF_Symbols_h 30 Jul 2026 19:28:03 -0000 1.5 > +++ ports/devel/llvm/22/patches/patch-lld_ELF_Symbols_h 1 Nov 2026 21:01:39 -0000 > @@ -1,7 +1,16 @@ > Index: lld/ELF/Symbols.h > --- lld/ELF/Symbols.h.orig > +++ lld/ELF/Symbols.h > -@@ -148,6 +148,9 @@ class Symbol { (public) > +@@ -55,6 +55,8 @@ enum { > + NEEDS_GOT_NONAUTH = 1 << 10, > + NEEDS_TLSDESC_AUTH = 1 << 11, > + NEEDS_TLSDESC_NONAUTH = 1 << 12, > ++ HAS_MIPS_CALL_RELOC = 1 << 13, > ++ NO_MIPS_STUB = 1 << 14, > + }; > + > + // The base class for real symbol classes. > +@@ -148,6 +150,9 @@ class Symbol { (public) > LLVM_PREFERRED_TYPE(bool) > uint8_t hasVersionSuffix : 1; > > @@ -11,7 +20,7 @@ Index: lld/ELF/Symbols.h > // Symbol visibility. This is the computed minimum visibility of all > // observed non-DSO symbols. > uint8_t visibility() const { return stOther & 3; } > -@@ -204,6 +207,7 @@ class Symbol { (public) > +@@ -204,6 +209,7 @@ class Symbol { (public) > uint64_t getGotVA(Ctx &) const; > uint64_t getGotPltOffset(Ctx &) const; > uint64_t getGotPltVA(Ctx &) const; > @@ -19,7 +28,7 @@ Index: lld/ELF/Symbols.h > uint64_t getPltVA(Ctx &) const; > uint64_t getSize() const; > OutputSection *getOutputSection() const; > -@@ -244,7 +248,7 @@ class Symbol { (public) > +@@ -244,7 +250,7 @@ class Symbol { (public) > : file(file), nameData(name.data()), nameSize(name.size()), type(type), > binding(binding), stOther(stOther), symbolKind(k), isPreemptible(false), > isUsedInRegularObj(false), used(false), isExported(false), > @@ -28,7 +37,7 @@ Index: lld/ELF/Symbols.h > isInIplt(false), gotInIgot(false), folded(false), > archSpecificBit(false), scriptDefined(false), dsoDefined(false), > dsoProtected(false), versionScriptAssigned(false), thunkAccessed(false), > -@@ -540,6 +544,8 @@ void reportDuplicate(Ctx &, const Symbol &sym, const I > +@@ -540,6 +546,8 @@ void reportDuplicate(Ctx &, const Symbol &sym, const I > void maybeWarnUnorderableSymbol(Ctx &, const Symbol *sym); > bool computeIsPreemptible(Ctx &, const Symbol &sym); > void parseVersionAndComputeIsPreemptible(Ctx &); > Index: ports/devel/llvm/22/patches/patch-lld_ELF_SyntheticSections_cpp > =================================================================== > RCS file: /home/cvs/ports/devel/llvm/22/patches/patch-lld_ELF_SyntheticSections_cpp,v > diff -u -p -r1.2 patch-lld_ELF_SyntheticSections_cpp > --- ports/devel/llvm/22/patches/patch-lld_ELF_SyntheticSections_cpp 30 Jul 2026 19:28:03 -0000 1.2 > +++ ports/devel/llvm/22/patches/patch-lld_ELF_SyntheticSections_cpp 1 Nov 2026 21:01:39 -0000 > @@ -1,7 +1,98 @@ > Index: lld/ELF/SyntheticSections.cpp > --- lld/ELF/SyntheticSections.cpp.orig > +++ lld/ELF/SyntheticSections.cpp > -@@ -1505,6 +1505,7 @@ DynamicSection::computeContents() { > +@@ -1095,8 +1095,10 @@ void MipsGotSection::build() { > + if (&got == primGot) > + continue; > + > +- // Dynamic relocations for "global" entries. > ++ // A lazy stub requires the primary GOT's resolver slots and $gp. > ++ // Calls through secondary GOTs must be resolved eagerly. > + for (const std::pair &p : got.global) { > ++ p.first->setFlags(NO_MIPS_STUB); > + uint64_t offset = p.second * ctx.arg.wordsize; > + ctx.mainPart->relaDyn->addSymbolReloc(ctx.target->relativeRel, *this, > + offset, *p.first); > +@@ -1177,13 +1179,21 @@ void MipsGotSection::writeTo(uint8_t *buf) { > + // http://web.archive.org/web/20190324223224/https://www.linux-mips.org/wiki/NPTL > + for (const std::pair &p : g.local16) > + write(p.second, p.first.first, p.first.second); > ++ auto writeGlobal = [&](size_t i, const Symbol *s) { > ++ if (std::optional va = > ++ ctx.in.mipsStubs ? ctx.in.mipsStubs->getStubVA(*s) > ++ : std::nullopt) > ++ write(i, nullptr, *va); > ++ else > ++ write(i, s, 0); > ++ }; > + // Write VA to the primary GOT only. For secondary GOTs that > + // will be done by REL32 dynamic relocations. > + if (&g == &gots.front()) > + for (const std::pair &p : g.global) > +- write(p.second, p.first, 0); > ++ writeGlobal(p.second, p.first); > + for (const std::pair &p : g.relocs) > +- write(p.second, p.first, 0); > ++ writeGlobal(p.second, p.first); > + for (const std::pair &p : g.tls) > + write(p.second, p.first, > + p.first->isPreemptible || ctx.arg.shared ? 0 : -0x7000); > +@@ -1202,6 +1212,54 @@ void MipsGotSection::writeTo(uint8_t *buf) { > + } > + } > + > ++MipsStubsSection::MipsStubsSection(Ctx &ctx) > ++ : SyntheticSection(ctx, ".MIPS.stubs", SHT_PROGBITS, > ++ SHF_ALLOC | SHF_EXECINSTR, ctx.arg.wordsize) {} > ++ > ++void MipsStubsSection::addSymbols() { > ++ // microMIPS stubs are not implemented. > ++ if (isMicroMips(ctx)) > ++ return; > ++ for (Symbol *sym : ctx.symtab->getSymbols()) { > ++ if (!sym->isPreemptible || !(sym->isUndefined() || sym->isShared()) || > ++ !sym->isFunc() || !sym->hasFlag(HAS_MIPS_CALL_RELOC) || > ++ sym->hasFlag(NO_MIPS_STUB) || sym->hasFlag(NEEDS_PLT)) > ++ continue; > ++ entries.push_back(sym); > ++ } > ++ > ++ // Include the full stub size in GOT page counts before GOT layout. > ++ // Removing secondary GOT candidates later can only shrink this size. > ++ stubSize = ctx.mainPart->dynSymTab->getNumSymbols() > 0x10000 > ++ ? stubBigSize > ++ : stubNormalSize; > ++} > ++ > ++std::optional > ++MipsStubsSection::getStubVA(const Symbol &sym) const { > ++ if (!getParent()) > ++ return std::nullopt; > ++ auto it = indices.find(&sym); > ++ if (it == indices.end()) > ++ return std::nullopt; > ++ return getVA() + it->second * stubSize; > ++} > ++ > ++void MipsStubsSection::finalizeContents() { > ++ llvm::erase_if(entries, [&](const Symbol *sym) { > ++ return sym->hasFlag(NO_MIPS_STUB) || !sym->isInGot(ctx); > ++ }); > ++ for (size_t i = 0; i != entries.size(); ++i) > ++ indices[entries[i]] = i; > ++} > ++ > ++void MipsStubsSection::writeTo(uint8_t *buf) { > ++ for (const Symbol *sym : entries) { > ++ writeMipsStub(ctx, buf, sym->dynsymIndex, stubSize == stubBigSize); > ++ buf += stubSize; > ++ } > ++} > ++ > + // On PowerPC the .plt section is used to hold the table of function addresses > + // instead of the .got.plt, and the type is SHT_NOBITS similar to a .bss > + // section. I don't know why we have a BSS style type for the section but it is > +@@ -1505,6 +1563,7 @@ DynamicSection::computeContents() { > addInt(DT_RISCV_VARIANT_CC, 0); > [[fallthrough]]; > default: > @@ -9,7 +100,7 @@ Index: lld/ELF/SyntheticSections.cpp > addInSec(DT_PLTGOT, *ctx.in.gotPlt); > break; > } > -@@ -1720,14 +1721,20 @@ void RelocationBaseSection::finalizeContents() { > +@@ -1720,14 +1779,20 @@ void RelocationBaseSection::finalizeContents() { > else > getParent()->link = 0; > > @@ -33,7 +124,7 @@ Index: lld/ELF/SyntheticSections.cpp > r_sym = getSymIndex(symt); > addend = computeAddend(ctx); > isFinal = true; // Catch errors > -@@ -2176,12 +2183,12 @@ void SymbolTableBaseSection::finalizeContents() { > +@@ -2176,12 +2241,12 @@ void SymbolTableBaseSection::finalizeContents() { > return; > } > > @@ -50,7 +141,7 @@ Index: lld/ELF/SyntheticSections.cpp > > if (getPartition(ctx).gnuHashTab) { > // NB: It also sorts Symbols to meet the GNU hash table requirements. > -@@ -2201,7 +2208,7 @@ void SymbolTableBaseSection::finalizeContents() { > +@@ -2201,7 +2266,7 @@ void SymbolTableBaseSection::finalizeContents() { > > // The ELF spec requires that all local symbols precede global symbols, so we > // sort symbol entries in this function. (For .dynsym, we don't do that because > @@ -59,7 +150,7 @@ Index: lld/ELF/SyntheticSections.cpp > // > // Aside from above, we put local symbols in groups starting with the STT_FILE > // symbol. That is convenient for purpose of identifying where are local symbols > -@@ -2235,6 +2242,13 @@ void SymbolTableBaseSection::addSymbol(Symbol *b) { > +@@ -2235,6 +2300,13 @@ void SymbolTableBaseSection::addSymbol(Symbol *b) { > symbols.push_back({b, strTabSec.addString(b->getName(), false)}); > } > > @@ -73,7 +164,17 @@ Index: lld/ELF/SyntheticSections.cpp > size_t SymbolTableBaseSection::getSymbolIndex(const Symbol &sym) { > if (this == ctx.mainPart->dynSymTab.get()) > return sym.dynsymIndex; > -@@ -2508,7 +2522,8 @@ void GnuHashTableSection::addSymbols(SmallVectorImpl +@@ -2337,6 +2409,9 @@ template void SymbolTableSection::w > + Symbol *sym = ent.sym; > + if (sym->isInPlt(ctx) && sym->hasFlag(NEEDS_COPY)) > + eSym->st_other |= STO_MIPS_PLT; > ++ if (type == SHT_DYNSYM && ctx.in.mipsStubs) > ++ if (std::optional va = ctx.in.mipsStubs->getStubVA(*sym)) > ++ eSym->st_value = *va; > + if (isMicroMips(ctx)) { > + // We already set the less-significant bit for symbols > + // marked by the `STO_MIPS_MICROMIPS` flag and for microMIPS PLT > +@@ -2508,7 +2583,8 @@ void GnuHashTableSection::addSymbols(SmallVectorImpl // its type correctly. > auto mid = > std::stable_partition(v.begin(), v.end(), [&](const SymbolTableEntry &s) { > @@ -83,7 +184,7 @@ Index: lld/ELF/SyntheticSections.cpp > }); > > // We chose load factor 4 for the on-disk hash table. For each hash > -@@ -2574,6 +2589,8 @@ void HashTableSection::writeTo(uint8_t *buf) { > +@@ -2574,6 +2650,8 @@ void HashTableSection::writeTo(uint8_t *buf) { > > for (const SymbolTableEntry &s : symTab->getSymbols()) { > Symbol *sym = s.sym; > @@ -92,7 +193,7 @@ Index: lld/ELF/SyntheticSections.cpp > StringRef name = sym->getName(); > unsigned i = sym->dynsymIndex; > uint32_t hash = hashSysV(name) % numSymbols; > -@@ -2602,23 +2619,29 @@ PltSection::PltSection(Ctx &ctx) > +@@ -2602,23 +2680,29 @@ PltSection::PltSection(Ctx &ctx) > if ((ctx.arg.emachine == EM_386 || ctx.arg.emachine == EM_X86_64) && > (ctx.arg.andFeatures & GNU_PROPERTY_X86_FEATURE_1_IBT)) > name = ".plt.sec"; > @@ -125,7 +226,7 @@ Index: lld/ELF/SyntheticSections.cpp > } > > void PltSection::addEntry(Symbol &sym) { > -@@ -2641,11 +2664,8 @@ bool PltSection::isNeeded() const { > +@@ -2641,11 +2725,8 @@ bool PltSection::isNeeded() const { > void PltSection::addSymbols() { > ctx.target->addPltHeaderSymbols(*this); > > @@ -139,7 +240,7 @@ Index: lld/ELF/SyntheticSections.cpp > } > > IpltSection::IpltSection(Ctx &ctx) > -@@ -4878,10 +4898,12 @@ template void elf::createSyntheticSection > +@@ -4878,10 +4959,12 @@ template void elf::createSyntheticSection > // _GLOBAL_OFFSET_TABLE_ is defined relative to either .got.plt or .got. Treat > // it as a relocation and ensure the referenced section is created. > if (ctx.sym.globalOffsetTable && ctx.arg.emachine != EM_MIPS) { > @@ -154,7 +255,16 @@ Index: lld/ELF/SyntheticSections.cpp > } > > // We always need to add rel[a].plt to output if it has entries. > -@@ -4909,6 +4931,12 @@ template void elf::createSyntheticSection > +@@ -4905,10 +4988,21 @@ template void elf::createSyntheticSection > + ctx.in.iplt = std::make_unique(ctx); > + add(*ctx.in.iplt); > + > ++ if (ctx.arg.emachine == EM_MIPS && !ctx.arg.relocatable && ctx.hasDynsym) { > ++ ctx.in.mipsStubs = std::make_unique(ctx); > ++ add(*ctx.in.mipsStubs); > ++ } > ++ > + if (ctx.arg.andFeatures || ctx.aarch64PauthAbiCoreInfo) { > ctx.in.gnuProperty = std::make_unique(ctx); > add(*ctx.in.gnuProperty); > } > Index: ports/devel/llvm/22/patches/patch-lld_ELF_SyntheticSections_h > =================================================================== > RCS file: /home/cvs/ports/devel/llvm/22/patches/patch-lld_ELF_SyntheticSections_h,v > diff -u -p -r1.2 patch-lld_ELF_SyntheticSections_h > --- ports/devel/llvm/22/patches/patch-lld_ELF_SyntheticSections_h 30 Jul 2026 19:28:03 -0000 1.2 > +++ ports/devel/llvm/22/patches/patch-lld_ELF_SyntheticSections_h 1 Nov 2026 21:01:39 -0000 > @@ -29,7 +29,32 @@ Index: lld/ELF/SyntheticSections.h > > StringTableSection &strTabSec; > > -@@ -1462,7 +1469,11 @@ void addVerneed(Ctx &, Symbol &ss); > +@@ -1195,6 +1202,24 @@ class MipsRldMapSection final : public SyntheticSectio > + void writeTo(uint8_t *buf) override {} > + }; > + > ++class MipsStubsSection final : public SyntheticSection { > ++ static constexpr size_t stubNormalSize = 16; > ++ static constexpr size_t stubBigSize = 20; > ++public: > ++ MipsStubsSection(Ctx &); > ++ void addSymbols(); > ++ std::optional getStubVA(const Symbol &sym) const; > ++ size_t getSize() const override { return entries.size() * stubSize; } > ++ bool isNeeded() const override { return !entries.empty(); } > ++ void finalizeContents() override; > ++ void writeTo(uint8_t *buf) override; > ++ > ++private: > ++ SmallVector entries; > ++ llvm::DenseMap indices; > ++ size_t stubSize = stubNormalSize; > ++}; > ++ > + // Representation of the combined .ARM.Exidx input sections. We process these > + // as a SyntheticSection like .eh_frame as we need to merge duplicate entries > + // and add terminating sentinel entries. > +@@ -1462,7 +1487,11 @@ void addVerneed(Ctx &, Symbol &ss); > // placed in it. > struct PhdrEntry { > PhdrEntry(Ctx &ctx, unsigned type, unsigned flags) > Index: ports/devel/llvm/22/patches/patch-lld_ELF_Target_h > =================================================================== > RCS file: /home/cvs/ports/devel/llvm/22/patches/patch-lld_ELF_Target_h,v > diff -u -p -r1.1 patch-lld_ELF_Target_h > --- ports/devel/llvm/22/patches/patch-lld_ELF_Target_h 30 Jul 2026 19:28:03 -0000 1.1 > +++ ports/devel/llvm/22/patches/patch-lld_ELF_Target_h 1 Nov 2026 21:01:39 -0000 > @@ -61,3 +61,11 @@ Index: lld/ELF/Target.h > > protected: > // On FreeBSD x86_64 the first page cannot be mmaped. > +@@ -233,6 +247,7 @@ uint64_t getMipsPageAddr(uint64_t addr); > + bool isMipsN32Abi(Ctx &, const InputFile &f); > + bool isMicroMips(Ctx &); > + bool isMipsR6(Ctx &); > ++void writeMipsStub(Ctx &, uint8_t *buf, uint32_t dynsymIndex, bool big); > + > + void writePPC32GlinkSection(Ctx &, uint8_t *buf, size_t numEntries); > + > Index: ports/devel/llvm/22/patches/patch-lld_ELF_Writer_cpp > =================================================================== > RCS file: /home/cvs/ports/devel/llvm/22/patches/patch-lld_ELF_Writer_cpp,v > diff -u -p -r1.3 patch-lld_ELF_Writer_cpp > --- ports/devel/llvm/22/patches/patch-lld_ELF_Writer_cpp 20 Aug 2026 14:38:00 -0000 1.3 > +++ ports/devel/llvm/22/patches/patch-lld_ELF_Writer_cpp 1 Nov 2026 21:01:39 -0000 > @@ -85,7 +85,19 @@ Index: lld/ELF/Writer.cpp > > if (ctx.arg.randomizeSectionPadding) > randomizeSectionPadding(ctx); > -@@ -2031,10 +2046,10 @@ template void Writer::finalizeSecti > +@@ -2001,8 +2016,11 @@ template void Writer::finalizeSecti > + } > + } > + > ++ if (ctx.in.mipsStubs) > ++ ctx.in.mipsStubs->addSymbols(); > + if (ctx.in.mipsGot) > + ctx.in.mipsGot->build(); > ++ finalizeSynthetic(ctx, ctx.in.mipsStubs.get()); > + > + removeUnusedSyntheticSections(ctx); > + ctx.script->diagnoseOrphanHandling(); > +@@ -2031,10 +2049,10 @@ template void Writer::finalizeSecti > sec->addrExpr = [=] { return i->second; }; > } > > @@ -99,7 +111,7 @@ Index: lld/ELF/Writer.cpp > Symbol *sym = > ctx.symtab->addSymbol(Undefined{ctx.internalFile, "__tls_get_addr", > STB_GLOBAL, STV_DEFAULT, STT_NOTYPE}); > -@@ -2300,6 +2315,15 @@ static bool needsPtLoad(OutputSection *sec) { > +@@ -2300,6 +2318,15 @@ static bool needsPtLoad(OutputSection *sec) { > static uint64_t computeFlags(Ctx &ctx, uint64_t flags) { > if (ctx.arg.omagic) > return PF_R | PF_W | PF_X; > @@ -115,7 +127,7 @@ Index: lld/ELF/Writer.cpp > if (ctx.arg.executeOnly && (flags & PF_X)) > return flags & ~PF_R; > return flags; > -@@ -2454,34 +2478,22 @@ Writer::createPhdrs(Partition &part) { > +@@ -2454,34 +2481,22 @@ Writer::createPhdrs(Partition &part) { > addHdr(PT_GNU_EH_FRAME, part.ehFrameHdr->getParent()->getPhdrFlags()) > ->add(part.ehFrameHdr->getParent()); > > @@ -163,7 +175,7 @@ Index: lld/ELF/Writer.cpp > // PT_OPENBSD_NOBTCFI is an OpenBSD-specific header to mark that the > // executable is expected to violate branch-target CFI checks. > if (ctx.arg.zNoBtCfi) > -@@ -2493,7 +2505,19 @@ Writer::createPhdrs(Partition &part) { > +@@ -2493,7 +2508,19 @@ Writer::createPhdrs(Partition &part) { > // OpenBSD. > if (ctx.arg.zWxneeded) > addHdr(PT_OPENBSD_WXNEEDED, PF_X); > @@ -183,7 +195,7 @@ Index: lld/ELF/Writer.cpp > if (OutputSection *cmd = findSection(ctx, ".note.gnu.property", partNo)) > addHdr(PT_GNU_PROPERTY, PF_R)->add(cmd); > > -@@ -2587,6 +2611,31 @@ template void Writer::fixSectionAli > +@@ -2587,6 +2614,31 @@ template void Writer::fixSectionAli > } > }; > > @@ -215,7 +227,7 @@ Index: lld/ELF/Writer.cpp > for (Partition &part : ctx.partitions) { > prev = nullptr; > for (auto &p : part.phdrs) > -@@ -2651,6 +2700,16 @@ static std::string rangeToString(uint64_t addr, uint64 > +@@ -2651,6 +2703,16 @@ static std::string rangeToString(uint64_t addr, uint64 > template void Writer::assignFileOffsets() { > ctx.out.programHeaders->offset = ctx.out.elfHeader->size; > uint64_t off = ctx.out.elfHeader->size + ctx.out.programHeaders->size; > Index: ports/devel/llvm/23/patches/patch-lld_ELF_Arch_Mips_cpp > =================================================================== > RCS file: ports/devel/llvm/23/patches/patch-lld_ELF_Arch_Mips_cpp > diff -N ports/devel/llvm/23/patches/patch-lld_ELF_Arch_Mips_cpp > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ ports/devel/llvm/23/patches/patch-lld_ELF_Arch_Mips_cpp 1 Nov 2026 21:13:24 -0000 > @@ -0,0 +1,81 @@ > +Index: lld/ELF/Arch/Mips.cpp > +--- lld/ELF/Arch/Mips.cpp.orig > ++++ lld/ELF/Arch/Mips.cpp > +@@ -94,6 +94,41 @@ uint64_t elf::getMipsPageAddr(uint64_t addr) { > + return (addr + 0x8000) & ~0xffff; > + } > + > ++void elf::writeMipsStub(Ctx &ctx, uint8_t *buf, uint32_t dynsymIndex, > ++ bool big) { > ++ if (dynsymIndex > 0x7fffffff) { > ++ ErrAlways(ctx) << "MIPS lazy-binding stub dynamic symbol index " > ++ << dynsymIndex << " exceeds 31 bits"; > ++ return; > ++ } > ++ > ++ const uint32_t load = ctx.arg.is64 ? 0xdf998010 // ld $25, -0x7ff0($28) > ++ : 0x8f998010; // lw $25, -0x7ff0($28) > ++ const uint32_t lui = 0x3c180000 | ((dynsymIndex >> 16) & 0x7fff); > ++ const uint32_t jalr = ctx.arg.zHazardplt ? 0x0320fc09 : 0x0320f809; > ++ uint32_t loadIndex; > ++ if (big) > ++ loadIndex = 0x37180000 | (dynsymIndex & 0xffff); // ori $24, $24, idx > ++ else if (dynsymIndex & ~0x7fff) > ++ loadIndex = 0x34180000 | (dynsymIndex & 0xffff); // ori $24, $0, idx > ++ else > ++ loadIndex = (ctx.arg.is64 ? 0x64180000 : 0x24180000) | // [d]addiu $24, > ++ dynsymIndex; // $0, idx > ++ > ++ if (big) { > ++ write32(ctx, buf, load); > ++ write32(ctx, buf + 4, 0x03e07825); // move $15, $31 > ++ write32(ctx, buf + 8, lui); > ++ write32(ctx, buf + 12, jalr); // jalr[.hb] $25 > ++ write32(ctx, buf + 16, loadIndex); // delay slot > ++ } else { > ++ write32(ctx, buf, load); > ++ write32(ctx, buf + 4, 0x03e07825); // move $15, $31 > ++ write32(ctx, buf + 8, jalr); // jalr[.hb] $25 > ++ write32(ctx, buf + 12, loadIndex); // delay slot > ++ } > ++} > ++ > + template MIPS::MIPS(Ctx &ctx) : TargetInfo(ctx) { > + gotPltHeaderEntriesNum = 2; > + defaultMaxPageSize = 65536; > +@@ -668,6 +703,13 @@ static RelType getMipsPairType(RelType type, bool isLo > + } > + } > + > ++static bool isCallReloc(RelType type) { > ++ return type == R_MIPS_CALL16 || > ++ type == R_MIPS_CALL_HI16 || type == R_MIPS_CALL_LO16 || > ++ type == R_MICROMIPS_CALL16 || > ++ type == R_MICROMIPS_CALL_HI16 || type == R_MICROMIPS_CALL_LO16; > ++} > ++ > + template > + template > + void MIPS::scanSectionImpl(InputSectionBase &sec, Relocs rels, > +@@ -698,6 +740,21 @@ void MIPS::scanSectionImpl(InputSectionBase &sec > + if (sym.isUndefined() && symIdx != 0 && > + rs.maybeReportUndefined(cast(sym), offset)) > + continue; > ++ > ++ // In a shared object, turn untyped undefined symbols with a call > ++ // relocation into function symbols so that the dynamic linker handles > ++ // them correctly. > ++ if (ctx.arg.shared && sym.isUndefined() && symIdx != 0 && > ++ sym.type == STT_NOTYPE && isCallReloc(type.v & 0xff)) > ++ sym.type = STT_FUNC; > ++ > ++ if (symIdx != 0) { > ++ uint32_t baseType = type.v & 0xff; > ++ if (isCallReloc(baseType)) > ++ sym.setFlags(HAS_MIPS_CALL_RELOC); > ++ else if (baseType != R_MIPS_JALR && baseType != R_MICROMIPS_JALR) > ++ sym.setFlags(NO_MIPS_STUB); > ++ } > + > + auto addend = rs.getAddend(rel, type); > + if (expr == RE_MIPS_GOTREL && sym.isLocal()) { > Index: ports/devel/llvm/23/patches/patch-lld_ELF_Config_h > =================================================================== > RCS file: /home/cvs/ports/devel/llvm/23/patches/patch-lld_ELF_Config_h,v > diff -u -p -r1.1.1.1 patch-lld_ELF_Config_h > --- ports/devel/llvm/23/patches/patch-lld_ELF_Config_h 22 Sep 2026 03:34:34 -0000 1.1.1.1 > +++ ports/devel/llvm/23/patches/patch-lld_ELF_Config_h 1 Nov 2026 21:13:22 -0000 > @@ -1,7 +1,15 @@ > Index: lld/ELF/Config.h > --- lld/ELF/Config.h.orig > +++ lld/ELF/Config.h > -@@ -476,8 +476,13 @@ struct Config { > +@@ -71,6 +71,7 @@ class IpltSection; > + class MemtagAndroidNote; > + class MemtagGlobalDescriptors; > + class MipsGotSection; > ++class MipsStubsSection; > + class PPC64LongBranchTargetSection; > + class PackageMetadataNote; > + class PltSection; > +@@ -476,8 +477,13 @@ struct Config { > ELFKind ekind = ELFNoneKind; > uint16_t emachine = llvm::ELF::EM_NONE; > std::optional imageBase; > @@ -15,7 +23,15 @@ Index: lld/ELF/Config.h > uint64_t mipsGotSize; > uint64_t zStackSize; > unsigned ltoPartitions; > -@@ -676,6 +681,9 @@ struct Ctx : CommonLinkerContext { > +@@ -636,6 +642,7 @@ struct InStruct { > + std::unique_ptr mipsOptions; > + std::unique_ptr mipsReginfo; > + std::unique_ptr mipsRldMap; > ++ std::unique_ptr mipsStubs; > + std::unique_ptr ppc32Got2; > + // Non-SHF_ALLOC sections > + std::unique_ptr debugNames; > +@@ -676,6 +683,9 @@ struct Ctx : CommonLinkerContext { > struct ElfSym { > // __bss_start > Defined *bss; > Index: ports/devel/llvm/23/patches/patch-lld_ELF_Relocations_cpp > =================================================================== > RCS file: /home/cvs/ports/devel/llvm/23/patches/patch-lld_ELF_Relocations_cpp,v > diff -u -p -r1.2 patch-lld_ELF_Relocations_cpp > --- ports/devel/llvm/23/patches/patch-lld_ELF_Relocations_cpp 23 Sep 2026 12:14:28 -0000 1.2 > +++ ports/devel/llvm/23/patches/patch-lld_ELF_Relocations_cpp 1 Nov 2026 21:13:22 -0000 > @@ -134,7 +134,16 @@ Index: lld/ELF/Relocations.cpp > ctx.in.relaDyn->addSymbolReloc(rel, *sec, offset, sym, addend, type); > > // MIPS ABI turns using of GOT and dynamic relocations inside out. > -@@ -1317,10 +1363,7 @@ void elf::postScanRelocations(Ctx &ctx) { > +@@ -1167,6 +1213,8 @@ void RelocScan::scanEhSection(EhInputSection &s) { > + if (sym->isUndefined() && > + maybeReportUndefined(cast(*sym), offset)) > + continue; > ++ if (ctx.arg.emachine == EM_MIPS) > ++ sym->setFlags(NO_MIPS_STUB); > + process(r.expr, r.type, offset, *sym, r.addend); > + } > + } > +@@ -1317,10 +1365,7 @@ void elf::postScanRelocations(Ctx &ctx) { > } else { > assert(sym.isFunc() && sym.hasFlag(NEEDS_PLT)); > if (!sym.isDefined()) { > Index: ports/devel/llvm/23/patches/patch-lld_ELF_Symbols_h > =================================================================== > RCS file: /home/cvs/ports/devel/llvm/23/patches/patch-lld_ELF_Symbols_h,v > diff -u -p -r1.1.1.1 patch-lld_ELF_Symbols_h > --- ports/devel/llvm/23/patches/patch-lld_ELF_Symbols_h 22 Sep 2026 03:34:35 -0000 1.1.1.1 > +++ ports/devel/llvm/23/patches/patch-lld_ELF_Symbols_h 1 Nov 2026 21:13:22 -0000 > @@ -1,7 +1,16 @@ > Index: lld/ELF/Symbols.h > --- lld/ELF/Symbols.h.orig > +++ lld/ELF/Symbols.h > -@@ -142,6 +142,9 @@ class Symbol { (public) > +@@ -59,6 +59,8 @@ enum { > + NEEDS_GOT_NONAUTH = 1 << 10, > + NEEDS_TLSDESC_AUTH = 1 << 11, > + NEEDS_TLSDESC_NONAUTH = 1 << 12, > ++ HAS_MIPS_CALL_RELOC = 1 << 13, > ++ NO_MIPS_STUB = 1 << 14, > + }; > + > + // The base class for real symbol classes. > +@@ -142,6 +144,9 @@ class Symbol { (public) > LLVM_PREFERRED_TYPE(bool) > uint8_t hasVersionSuffix : 1; > > @@ -11,7 +20,7 @@ Index: lld/ELF/Symbols.h > // Symbol visibility. This is the computed minimum visibility of all > // observed non-DSO symbols. > uint8_t visibility() const { return stOther & 3; } > -@@ -198,6 +201,7 @@ class Symbol { (public) > +@@ -198,6 +203,7 @@ class Symbol { (public) > uint64_t getGotVA(Ctx &) const; > uint64_t getGotPltOffset(Ctx &) const; > uint64_t getGotPltVA(Ctx &) const; > @@ -19,7 +28,7 @@ Index: lld/ELF/Symbols.h > uint64_t getPltVA(Ctx &) const; > uint64_t getSize() const; > OutputSection *getOutputSection() const; > -@@ -238,7 +242,7 @@ class Symbol { (public) > +@@ -238,7 +244,7 @@ class Symbol { (public) > : file(file), nameData(name.data()), nameSize(name.size()), type(type), > binding(binding), stOther(stOther), symbolKind(k), isPreemptible(false), > isUsedInRegularObj(false), isExported(false), ltoCanOmit(false), > @@ -28,7 +37,7 @@ Index: lld/ELF/Symbols.h > gotInIgot(false), folded(false), archSpecificBit(false), > scriptDefined(false), dsoDefined(false), dsoProtected(false), > versionScriptAssigned(false), thunkAccessed(false), > -@@ -534,6 +538,8 @@ void reportDuplicate(Ctx &, const Symbol &sym, const I > +@@ -534,6 +540,8 @@ void reportDuplicate(Ctx &, const Symbol &sym, const I > void maybeWarnUnorderableSymbol(Ctx &, const Symbol *sym); > bool computeIsPreemptible(Ctx &, const Symbol &sym); > void parseVersionAndComputeIsPreemptible(Ctx &); > Index: ports/devel/llvm/23/patches/patch-lld_ELF_SyntheticSections_cpp > =================================================================== > RCS file: /home/cvs/ports/devel/llvm/23/patches/patch-lld_ELF_SyntheticSections_cpp,v > diff -u -p -r1.2 patch-lld_ELF_SyntheticSections_cpp > --- ports/devel/llvm/23/patches/patch-lld_ELF_SyntheticSections_cpp 23 Sep 2026 12:14:28 -0000 1.2 > +++ ports/devel/llvm/23/patches/patch-lld_ELF_SyntheticSections_cpp 1 Nov 2026 21:13:22 -0000 > @@ -1,7 +1,89 @@ > Index: lld/ELF/SyntheticSections.cpp > --- lld/ELF/SyntheticSections.cpp.orig > +++ lld/ELF/SyntheticSections.cpp > -@@ -1310,6 +1310,7 @@ DynamicSection::computeContents() { > +@@ -934,9 +934,13 @@ void MipsGotSection::build() { > + uint64_t offset = p.second * ctx.arg.wordsize; > + if (&got == primGot) > + addConstant({R_ABS, ctx.target->relativeRel, offset, 0, p.first}); > +- else > ++ else { > ++ // A lazy stub requires the primary GOT's resolver slots and $gp. > ++ // Calls through secondary GOTs must be resolved eagerly. > ++ p.first->setFlags(NO_MIPS_STUB); > + ctx.in.relaDyn->addSymbolReloc(ctx.target->relativeRel, *this, offset, > + *p.first); > ++ } > + } > + // Relocation-only entries exist as dummy entries for dynamic symbols that > + // aren't otherwise in the primary GOT, as the ABI requires an entry for > +@@ -1013,8 +1017,66 @@ void MipsGotSection::writeTo(uint8_t *buf) { > + writeUint(ctx, buf + ctx.arg.wordsize, > + (uint64_t)1 << (ctx.arg.wordsize * 8 - 1)); > + ctx.target->relocateAlloc(*this, buf); > ++ > ++ if (!ctx.in.mipsStubs || gots.empty()) > ++ return; > ++ auto writeStubAddresses = [&](const auto &entries) { > ++ for (const auto &[sym, index] : entries) > ++ if (std::optional va = ctx.in.mipsStubs->getStubVA(*sym)) > ++ writeUint(ctx, buf + index * ctx.arg.wordsize, *va); > ++ }; > ++ writeStubAddresses(gots.front().global); > ++ writeStubAddresses(gots.front().relocs); > + } > + > ++MipsStubsSection::MipsStubsSection(Ctx &ctx) > ++ : SyntheticSection(ctx, ".MIPS.stubs", SHT_PROGBITS, > ++ SHF_ALLOC | SHF_EXECINSTR, ctx.arg.wordsize) {} > ++ > ++void MipsStubsSection::addSymbols() { > ++ // microMIPS stubs are not implemented. > ++ if (isMicroMips(ctx)) > ++ return; > ++ for (Symbol *sym : ctx.symtab->getSymbols()) { > ++ if (!sym->isPreemptible || !(sym->isUndefined() || sym->isShared()) || > ++ !sym->isFunc() || !sym->hasFlag(HAS_MIPS_CALL_RELOC) || > ++ sym->hasFlag(NO_MIPS_STUB) || sym->hasFlag(NEEDS_PLT)) > ++ continue; > ++ entries.push_back(sym); > ++ } > ++ > ++ // Include the full stub size in GOT page counts before GOT layout. > ++ // Removing secondary GOT candidates later can only shrink this size. > ++ stubSize = ctx.in.dynSymTab->getNumSymbols() > 0x10000 > ++ ? stubBigSize > ++ : stubNormalSize; > ++} > ++ > ++std::optional > ++MipsStubsSection::getStubVA(const Symbol &sym) const { > ++ if (!getParent()) > ++ return std::nullopt; > ++ auto it = indices.find(&sym); > ++ if (it == indices.end()) > ++ return std::nullopt; > ++ return getVA() + it->second * stubSize; > ++} > ++ > ++void MipsStubsSection::finalizeContents() { > ++ llvm::erase_if(entries, [&](const Symbol *sym) { > ++ return sym->hasFlag(NO_MIPS_STUB) || !sym->isInGot(ctx); > ++ }); > ++ for (size_t i = 0; i != entries.size(); ++i) > ++ indices[entries[i]] = i; > ++} > ++ > ++void MipsStubsSection::writeTo(uint8_t *buf) { > ++ for (const Symbol *sym : entries) { > ++ writeMipsStub(ctx, buf, sym->dynsymIndex, stubSize == stubBigSize); > ++ buf += stubSize; > ++ } > ++} > ++ > + // On PowerPC the .plt section is used to hold the table of function addresses > + // instead of the .got.plt, and the type is SHT_NOBITS similar to a .bss > + // section. I don't know why we have a BSS style type for the section but it is > +@@ -1310,6 +1372,7 @@ DynamicSection::computeContents() { > addInt(DT_RISCV_VARIANT_CC, 0); > [[fallthrough]]; > default: > @@ -9,7 +91,7 @@ Index: lld/ELF/SyntheticSections.cpp > addInSec(DT_PLTGOT, *ctx.in.gotPlt); > break; > } > -@@ -1521,14 +1522,20 @@ void RelocationBaseSection::finalizeContents() { > +@@ -1521,14 +1584,20 @@ void RelocationBaseSection::finalizeContents() { > else > getParent()->link = 0; > > @@ -33,7 +115,7 @@ Index: lld/ELF/SyntheticSections.cpp > r_sym = getSymIndex(symt); > addend = computeAddend(ctx); > isFinal = true; // Catch errors > -@@ -1981,12 +1988,12 @@ void SymbolTableBaseSection::finalizeContents() { > +@@ -1981,12 +2050,12 @@ void SymbolTableBaseSection::finalizeContents() { > return; > } > > @@ -50,7 +132,7 @@ Index: lld/ELF/SyntheticSections.cpp > > if (ctx.in.gnuHashTab) { > // NB: It also sorts Symbols to meet the GNU hash table requirements. > -@@ -2005,7 +2012,7 @@ void SymbolTableBaseSection::finalizeContents() { > +@@ -2005,7 +2074,7 @@ void SymbolTableBaseSection::finalizeContents() { > > // The ELF spec requires that all local symbols precede global symbols, so we > // sort symbol entries in this function. (For .dynsym, we don't do that because > @@ -59,7 +141,7 @@ Index: lld/ELF/SyntheticSections.cpp > // > // Aside from above, we put local symbols in groups starting with the STT_FILE > // symbol. That is convenient for purpose of identifying where are local symbols > -@@ -2039,6 +2046,13 @@ void SymbolTableBaseSection::addSymbol(Symbol *b) { > +@@ -2039,6 +2108,13 @@ void SymbolTableBaseSection::addSymbol(Symbol *b) { > symbols.push_back({b, strTabSec.addString(b->getName(), false)}); > } > > @@ -73,7 +155,17 @@ Index: lld/ELF/SyntheticSections.cpp > size_t SymbolTableBaseSection::getSymbolIndex(const Symbol &sym) { > if (this == ctx.in.dynSymTab.get()) > return sym.dynsymIndex; > -@@ -2303,7 +2317,7 @@ void GnuHashTableSection::addSymbols(SmallVectorImpl +@@ -2133,6 +2209,9 @@ template void SymbolTableSection::w > + Symbol *sym = ent.sym; > + if (sym->isInPlt(ctx) && sym->hasFlag(NEEDS_COPY)) > + eSym->st_other |= STO_MIPS_PLT; > ++ if (type == SHT_DYNSYM && ctx.in.mipsStubs) > ++ if (std::optional va = ctx.in.mipsStubs->getStubVA(*sym)) > ++ eSym->st_value = *va; > + if (isMicroMips(ctx)) { > + // We already set the less-significant bit for symbols > + // marked by the `STO_MIPS_MICROMIPS` flag and for microMIPS PLT > +@@ -2303,7 +2382,7 @@ void GnuHashTableSection::addSymbols(SmallVectorImpl // its type correctly. > auto mid = > std::stable_partition(v.begin(), v.end(), [&](const SymbolTableEntry &s) { > @@ -82,7 +174,7 @@ Index: lld/ELF/SyntheticSections.cpp > }); > > // We chose load factor 4 for the on-disk hash table. For each hash > -@@ -2369,6 +2383,8 @@ void HashTableSection::writeTo(uint8_t *buf) { > +@@ -2369,6 +2448,8 @@ void HashTableSection::writeTo(uint8_t *buf) { > > for (const SymbolTableEntry &s : symTab->getSymbols()) { > Symbol *sym = s.sym; > @@ -91,7 +183,7 @@ Index: lld/ELF/SyntheticSections.cpp > StringRef name = sym->getName(); > unsigned i = sym->dynsymIndex; > uint32_t hash = hashSysV(name) % numSymbols; > -@@ -2397,23 +2413,29 @@ PltSection::PltSection(Ctx &ctx) > +@@ -2397,23 +2478,29 @@ PltSection::PltSection(Ctx &ctx) > if ((ctx.arg.emachine == EM_386 || ctx.arg.emachine == EM_X86_64) && > (ctx.arg.andFeatures & GNU_PROPERTY_X86_FEATURE_1_IBT)) > name = ".plt.sec"; > @@ -124,7 +216,7 @@ Index: lld/ELF/SyntheticSections.cpp > } > > void PltSection::addEntry(Symbol &sym) { > -@@ -2436,11 +2458,8 @@ bool PltSection::isNeeded() const { > +@@ -2436,11 +2523,8 @@ bool PltSection::isNeeded() const { > void PltSection::addSymbols() { > ctx.target->addPltHeaderSymbols(*this); > > @@ -138,7 +230,7 @@ Index: lld/ELF/SyntheticSections.cpp > } > > IpltSection::IpltSection(Ctx &ctx) > -@@ -4527,10 +4546,12 @@ template void elf::createSyntheticSection > +@@ -4527,10 +4611,12 @@ template void elf::createSyntheticSection > // _GLOBAL_OFFSET_TABLE_ is defined relative to either .got.plt or .got. Treat > // it as a relocation and ensure the referenced section is created. > if (ctx.sym.globalOffsetTable && ctx.arg.emachine != EM_MIPS) { > @@ -153,7 +245,16 @@ Index: lld/ELF/SyntheticSections.cpp > } > > // We always need to add rel[a].plt to output if it has entries. > -@@ -4552,6 +4573,12 @@ template void elf::createSyntheticSection > +@@ -4548,10 +4634,21 @@ template void elf::createSyntheticSection > + ctx.in.iplt = std::make_unique(ctx); > + add(*ctx.in.iplt); > + > ++ if (ctx.arg.emachine == EM_MIPS && !ctx.arg.relocatable && ctx.hasDynsym) { > ++ ctx.in.mipsStubs = std::make_unique(ctx); > ++ add(*ctx.in.mipsStubs); > ++ } > ++ > + if (ctx.arg.andFeatures || ctx.aarch64PauthAbiCoreInfo) { > ctx.in.gnuProperty = std::make_unique(ctx); > add(*ctx.in.gnuProperty); > } > Index: ports/devel/llvm/23/patches/patch-lld_ELF_SyntheticSections_h > =================================================================== > RCS file: /home/cvs/ports/devel/llvm/23/patches/patch-lld_ELF_SyntheticSections_h,v > diff -u -p -r1.3 patch-lld_ELF_SyntheticSections_h > --- ports/devel/llvm/23/patches/patch-lld_ELF_SyntheticSections_h 10 Oct 2026 09:09:22 -0000 1.3 > +++ ports/devel/llvm/23/patches/patch-lld_ELF_SyntheticSections_h 1 Nov 2026 21:13:22 -0000 > @@ -29,7 +29,32 @@ Index: lld/ELF/SyntheticSections.h > > StringTableSection &strTabSec; > > -@@ -1329,7 +1336,11 @@ void addVerneed(Ctx &, Symbol &ss); > +@@ -1136,6 +1143,24 @@ class MergeNoTailSection final : public MergeSynthetic > + size_t shardOffsets[numShards]; > + }; > + > ++class MipsStubsSection final : public SyntheticSection { > ++ static constexpr size_t stubNormalSize = 16; > ++ static constexpr size_t stubBigSize = 20; > ++public: > ++ MipsStubsSection(Ctx &); > ++ void addSymbols(); > ++ std::optional getStubVA(const Symbol &sym) const; > ++ size_t getSize() const override { return entries.size() * stubSize; } > ++ bool isNeeded() const override { return !entries.empty(); } > ++ void finalizeContents() override; > ++ void writeTo(uint8_t *buf) override; > ++ > ++private: > ++ SmallVector entries; > ++ llvm::DenseMap indices; > ++ size_t stubSize = stubNormalSize; > ++}; > ++ > + // Representation of the combined .ARM.Exidx input sections. We process these > + // as a SyntheticSection like .eh_frame as we need to merge duplicate entries > + // and add terminating sentinel entries. > +@@ -1329,7 +1354,11 @@ void addVerneed(Ctx &, Symbol &ss); > // placed in it. > struct PhdrEntry { > PhdrEntry(Ctx &ctx, unsigned type, unsigned flags) > Index: ports/devel/llvm/23/patches/patch-lld_ELF_Target_h > =================================================================== > RCS file: /home/cvs/ports/devel/llvm/23/patches/patch-lld_ELF_Target_h,v > diff -u -p -r1.1 patch-lld_ELF_Target_h > --- ports/devel/llvm/23/patches/patch-lld_ELF_Target_h 23 Sep 2026 12:14:28 -0000 1.1 > +++ ports/devel/llvm/23/patches/patch-lld_ELF_Target_h 1 Nov 2026 21:13:22 -0000 > @@ -61,3 +61,11 @@ Index: lld/ELF/Target.h > > protected: > // On FreeBSD x86_64 the first page cannot be mmaped. > +@@ -243,6 +257,7 @@ uint64_t getMipsPageAddr(uint64_t addr); > + bool isMipsN32Abi(Ctx &, const InputFile &f); > + bool isMicroMips(Ctx &); > + bool isMipsR6(Ctx &); > ++void writeMipsStub(Ctx &, uint8_t *buf, uint32_t dynsymIndex, bool big); > + > + void writePPC32GlinkSection(Ctx &, uint8_t *buf, size_t numEntries); > + > Index: ports/devel/llvm/23/patches/patch-lld_ELF_Writer_cpp > =================================================================== > RCS file: /home/cvs/ports/devel/llvm/23/patches/patch-lld_ELF_Writer_cpp,v > diff -u -p -r1.3 patch-lld_ELF_Writer_cpp > --- ports/devel/llvm/23/patches/patch-lld_ELF_Writer_cpp 25 Oct 2026 07:38:37 -0000 1.3 > +++ ports/devel/llvm/23/patches/patch-lld_ELF_Writer_cpp 1 Nov 2026 21:13:22 -0000 > @@ -72,7 +72,19 @@ Index: lld/ELF/Writer.cpp > // Setup MIPS _gp_disp/__gnu_local_gp symbols which should > // be equal to the _gp symbol's value. > if (ctx.sym.mipsGp) { > -@@ -2247,6 +2262,15 @@ static bool needsPtLoad(OutputSection *sec) { > +@@ -1968,8 +1983,11 @@ template void Writer::finalizeSecti > + > + } > + > ++ if (ctx.in.mipsStubs) > ++ ctx.in.mipsStubs->addSymbols(); > + if (ctx.in.mipsGot) > + ctx.in.mipsGot->build(); > ++ finalizeSynthetic(ctx, ctx.in.mipsStubs.get()); > + > + removeUnusedSyntheticSections(ctx); > + ctx.script->diagnoseOrphanHandling(); > +@@ -2247,6 +2265,15 @@ static bool needsPtLoad(OutputSection *sec) { > static uint64_t computeFlags(Ctx &ctx, uint64_t flags) { > if (ctx.arg.omagic) > return PF_R | PF_W | PF_X; > @@ -88,7 +100,7 @@ Index: lld/ELF/Writer.cpp > if (ctx.arg.executeOnly && (flags & PF_X)) > return flags & ~PF_R; > return flags; > -@@ -2378,34 +2402,22 @@ SmallVector, 0> Writer +@@ -2378,34 +2405,22 @@ SmallVector, 0> Writer addHdr(PT_GNU_EH_FRAME, ctx.in.ehFrameHdr->getParent()->getPhdrFlags()) > ->add(ctx.in.ehFrameHdr->getParent()); > > @@ -136,7 +148,7 @@ Index: lld/ELF/Writer.cpp > // PT_OPENBSD_NOBTCFI is an OpenBSD-specific header to mark that the > // executable is expected to violate branch-target CFI checks. > if (ctx.arg.zNoBtCfi) > -@@ -2417,7 +2429,19 @@ SmallVector, 0> Writer +@@ -2417,7 +2432,19 @@ SmallVector, 0> Writer // OpenBSD. > if (ctx.arg.zWxneeded) > addHdr(PT_OPENBSD_WXNEEDED, PF_X); > @@ -156,7 +168,7 @@ Index: lld/ELF/Writer.cpp > if (OutputSection *cmd = findSection(ctx, ".note.gnu.property")) > addHdr(PT_GNU_PROPERTY, PF_R)->add(cmd); > > -@@ -2501,6 +2525,31 @@ template void Writer::fixSectionAli > +@@ -2501,6 +2528,31 @@ template void Writer::fixSectionAli > } > }; > > @@ -188,7 +200,7 @@ Index: lld/ELF/Writer.cpp > prev = nullptr; > for (auto &ph : ctx.phdrs) > if (ph->p_type == PT_LOAD && ph->firstSec) { > -@@ -2563,6 +2612,16 @@ static std::string rangeToString(uint64_t addr, uint64 > +@@ -2563,6 +2615,16 @@ static std::string rangeToString(uint64_t addr, uint64 > template void Writer::assignFileOffsets() { > ctx.out.programHeaders->offset = ctx.out.elfHeader->size; > uint64_t off = ctx.out.elfHeader->size + ctx.out.programHeaders->size; > > > -- > wbr, Kirill > >