Download raw body.
lld: add MIPS lazy binding stubs
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?
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<SyntheticSection> mipsOptions;
std::unique_ptr<SyntheticSection> mipsReginfo;
std::unique_ptr<MipsRldMapSection> mipsRldMap;
+ std::unique_ptr<MipsStubsSection> mipsStubs;
std::unique_ptr<SyntheticSection> partEnd;
std::unique_ptr<SyntheticSection> partIndex;
std::unique_ptr<PltSection> 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<Undefined>(*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<Symbol *, size_t> &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<GotEntry, size_t> &p : g.local16)
write(p.second, p.first.first, p.first.second);
+ auto writeGlobal = [&](size_t i, const Symbol *s) {
+ if (std::optional<uint64_t> 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<Symbol *, size_t> &p : g.global)
- write(p.second, p.first, 0);
+ writeGlobal(p.second, p.first);
for (const std::pair<Symbol *, size_t> &p : g.relocs)
- write(p.second, p.first, 0);
+ writeGlobal(p.second, p.first);
for (const std::pair<Symbol *, size_t> &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<uint64_t>
+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 <class ELFT> 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<uint64_t> 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 <class ELFT> void elf::createSy
add(*ctx.in.plt);
ctx.in.iplt = std::make_unique<IpltSection>(ctx);
add(*ctx.in.iplt);
+
+ if (ctx.arg.emachine == EM_MIPS && !ctx.arg.relocatable && ctx.hasDynsym) {
+ ctx.in.mipsStubs = std::make_unique<MipsStubsSection>(ctx);
+ add(*ctx.in.mipsStubs);
+ }
if (ctx.arg.andFeatures || ctx.aarch64PauthAbiCoreInfo) {
ctx.in.gnuProperty = std::make_unique<GnuPropertySection>(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<uint64_t> 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<const Symbol *, 0> entries;
+ llvm::DenseMap<const Symbol *, uint32_t> 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 <class ELFT> void Writer<ELFT>:
}
}
+ 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 <class ELFT> MIPS<ELFT>::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 <class ELFT>
template <class RelTy>
void MIPS<ELFT>::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
@@ -639,6 +681,21 @@ void MIPS<ELFT>::scanSectionImpl(InputSe
if (sym.isUndefined() && symIdx != 0 &&
rs.maybeReportUndefined(cast<Undefined>(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<ELFT>(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 <class ELFT> MIPS<ELFT>::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 <class ELFT>
+ template <class RelTy>
+ void MIPS<ELFT>::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
+@@ -639,6 +681,21 @@ void MIPS<ELFT>::scanSectionImpl(InputSectionBase &sec
+ if (sym.isUndefined() && symIdx != 0 &&
+ rs.maybeReportUndefined(cast<Undefined>(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<ELFT>(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<uint64_t> 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<SyntheticSection> mipsOptions;
+ std::unique_ptr<SyntheticSection> mipsReginfo;
+ std::unique_ptr<MipsRldMapSection> mipsRldMap;
++ std::unique_ptr<MipsStubsSection> mipsStubs;
+ std::unique_ptr<SyntheticSection> partEnd;
+ std::unique_ptr<SyntheticSection> partIndex;
+ std::unique_ptr<PltSection> 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<Undefined>(*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<OutputSection
+@@ -2221,7 +2270,7 @@ bool elf::hexagonNeedsTLSSymbol(ArrayRef<OutputSection
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<ELFT>::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<Symbol *, size_t> &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<GotEntry, size_t> &p : g.local16)
+ write(p.second, p.first.first, p.first.second);
++ auto writeGlobal = [&](size_t i, const Symbol *s) {
++ if (std::optional<uint64_t> 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<Symbol *, size_t> &p : g.global)
+- write(p.second, p.first, 0);
++ writeGlobal(p.second, p.first);
+ for (const std::pair<Symbol *, size_t> &p : g.relocs)
+- write(p.second, p.first, 0);
++ writeGlobal(p.second, p.first);
+ for (const std::pair<Symbol *, size_t> &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<uint64_t>
++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<ELFT>::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<S
+@@ -2337,6 +2409,9 @@ template <class ELFT> void SymbolTableSection<ELFT>::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<uint64_t> 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<S
// 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 <class ELFT> void elf::createSyntheticSection
+@@ -4878,10 +4959,12 @@ template <class ELFT> 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 <class ELFT> void elf::createSyntheticSection
+@@ -4905,10 +4988,21 @@ template <class ELFT> void elf::createSyntheticSection
+ ctx.in.iplt = std::make_unique<IpltSection>(ctx);
+ add(*ctx.in.iplt);
+
++ if (ctx.arg.emachine == EM_MIPS && !ctx.arg.relocatable && ctx.hasDynsym) {
++ ctx.in.mipsStubs = std::make_unique<MipsStubsSection>(ctx);
++ add(*ctx.in.mipsStubs);
++ }
++
+ if (ctx.arg.andFeatures || ctx.aarch64PauthAbiCoreInfo) {
ctx.in.gnuProperty = std::make_unique<GnuPropertySection>(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<uint64_t> 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<const Symbol *, 0> entries;
++ llvm::DenseMap<const Symbol *, uint32_t> 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 <class ELFT> void Writer<ELFT>::finalizeSecti
+@@ -2001,8 +2016,11 @@ template <class ELFT> void Writer<ELFT>::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 <class ELFT> void Writer<ELFT>::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<ELFT>::createPhdrs(Partition &part) {
+@@ -2454,34 +2481,22 @@ Writer<ELFT>::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<ELFT>::createPhdrs(Partition &part) {
+@@ -2493,7 +2508,19 @@ Writer<ELFT>::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 <class ELFT> void Writer<ELFT>::fixSectionAli
+@@ -2587,6 +2614,31 @@ template <class ELFT> void Writer<ELFT>::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 <class ELFT> void Writer<ELFT>::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 <class ELFT> MIPS<ELFT>::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 <class ELFT>
+ template <class RelTy>
+ void MIPS<ELFT>::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels,
+@@ -698,6 +740,21 @@ void MIPS<ELFT>::scanSectionImpl(InputSectionBase &sec
+ if (sym.isUndefined() && symIdx != 0 &&
+ rs.maybeReportUndefined(cast<Undefined>(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<ELFT>(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<uint64_t> 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<SyntheticSection> mipsOptions;
+ std::unique_ptr<SyntheticSection> mipsReginfo;
+ std::unique_ptr<SyntheticSection> mipsRldMap;
++ std::unique_ptr<MipsStubsSection> mipsStubs;
+ std::unique_ptr<SyntheticSection> ppc32Got2;
+ // Non-SHF_ALLOC sections
+ std::unique_ptr<SyntheticSection> 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<Undefined>(*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<ELFT>::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<uint64_t> 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<uint64_t>
++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<ELFT>::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<S
+@@ -2133,6 +2209,9 @@ template <class ELFT> void SymbolTableSection<ELFT>::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<uint64_t> 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<S
// 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 <class ELFT> void elf::createSyntheticSection
+@@ -4527,10 +4611,12 @@ template <class ELFT> 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 <class ELFT> void elf::createSyntheticSection
+@@ -4548,10 +4634,21 @@ template <class ELFT> void elf::createSyntheticSection
+ ctx.in.iplt = std::make_unique<IpltSection>(ctx);
+ add(*ctx.in.iplt);
+
++ if (ctx.arg.emachine == EM_MIPS && !ctx.arg.relocatable && ctx.hasDynsym) {
++ ctx.in.mipsStubs = std::make_unique<MipsStubsSection>(ctx);
++ add(*ctx.in.mipsStubs);
++ }
++
+ if (ctx.arg.andFeatures || ctx.aarch64PauthAbiCoreInfo) {
ctx.in.gnuProperty = std::make_unique<GnuPropertySection>(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<uint64_t> 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<const Symbol *, 0> entries;
++ llvm::DenseMap<const Symbol *, uint32_t> 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 <class ELFT> void Writer<ELFT>::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<std::unique_ptr<PhdrEntry>, 0> Writer<ELFT
+@@ -2378,34 +2405,22 @@ SmallVector<std::unique_ptr<PhdrEntry>, 0> Writer<ELFT
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<std::unique_ptr<PhdrEntry>, 0> Writer<ELFT
+@@ -2417,7 +2432,19 @@ SmallVector<std::unique_ptr<PhdrEntry>, 0> Writer<ELFT
// 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 <class ELFT> void Writer<ELFT>::fixSectionAli
+@@ -2501,6 +2528,31 @@ template <class ELFT> void Writer<ELFT>::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 <class ELFT> void Writer<ELFT>::assignFileOffsets() {
ctx.out.programHeaders->offset = ctx.out.elfHeader->size;
uint64_t off = ctx.out.elfHeader->size + ctx.out.programHeaders->size;
--
wbr, Kirill
lld: add MIPS lazy binding stubs