Index: Makefile =================================================================== RCS file: /home/cvs/ports/devel/llvm/22/Makefile,v diff -u -p -r1.21 Makefile --- Makefile 25 Jul 2026 20:07:48 -0000 1.21 +++ Makefile 29 Jul 2026 19:24:27 -0000 @@ -2,7 +2,7 @@ LLVM_MAJOR = 22 LLVM_VERSION = ${LLVM_MAJOR}.1.8 LLVM_PKGSPEC = >=22,<23 -REVISION = 3 +REVISION = 4 SHARED_LIBS += LLVM 0.0 \ LTO 0.0 \ Index: patches/patch-lld_ELF_Arch_SPARCV9_cpp =================================================================== RCS file: patches/patch-lld_ELF_Arch_SPARCV9_cpp diff -N patches/patch-lld_ELF_Arch_SPARCV9_cpp --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-lld_ELF_Arch_SPARCV9_cpp 29 Jul 2026 19:22:39 -0000 @@ -0,0 +1,597 @@ +Index: lld/ELF/Arch/SPARCV9.cpp +--- lld/ELF/Arch/SPARCV9.cpp.orig ++++ lld/ELF/Arch/SPARCV9.cpp +@@ -6,10 +6,14 @@ + // + //===----------------------------------------------------------------------===// + ++#include "OutputSections.h" + #include "Symbols.h" + #include "SyntheticSections.h" + #include "Target.h" ++#include "llvm/ADT/DenseMap.h" + #include "llvm/Support/Endian.h" ++#include ++#include + + using namespace llvm; + using namespace llvm::support::endian; +@@ -18,15 +22,39 @@ using namespace lld; + using namespace lld::elf; + + namespace { ++constexpr uint32_t firstLargePltIndex = 32768 - 4; ++constexpr uint32_t pltLargeEntriesPerBlock = 160; ++constexpr uint32_t pltLargeCodeSize = 24; ++constexpr uint32_t pltLargePointerSize = 8; ++constexpr uint32_t pltLargeBlockSize = ++ pltLargeEntriesPerBlock * (pltLargeCodeSize + pltLargePointerSize); ++ + class SPARCV9 final : public TargetInfo { + public: + SPARCV9(Ctx &); + RelExpr getRelExpr(RelType type, const Symbol &s, + const uint8_t *loc) const override; ++ RelType getDynRel(RelType type) const override; ++ void prepareDynamicReloc(RelType type, const Symbol &sym, ++ InputSectionBase &sec) override; ++ void finalizeDynamicReloc(DynamicReloc &rel) const override; ++ void writeGotHeader(uint8_t *buf) const override; ++ uint64_t getPltEntryOffset(uint32_t pltIdx, ++ uint64_t headerSize) const override; + void writePlt(uint8_t *buf, const Symbol &sym, + uint64_t pltEntryAddr) const override; ++ void finalizePlt(uint8_t *buf) const override; + void relocate(uint8_t *loc, const Relocation &rel, + uint64_t val) const override; ++ RelExpr adjustGotOffExpr(RelType type, const Symbol &sym, int64_t addend, ++ const uint8_t *loc) const override; ++ ++private: ++ uint64_t getLargePltPointerOffset(uint32_t pltIdx) const; ++ void relaxGot(uint8_t *loc, const Relocation &rel, uint64_t val) const; ++ ++ DenseMap, Defined *> ++ dynamicSectionSymbols; + }; + } // namespace + +@@ -35,9 +63,16 @@ SPARCV9::SPARCV9(Ctx &ctx) : TargetInfo(ctx) { + gotRel = R_SPARC_GLOB_DAT; + pltRel = R_SPARC_JMP_SLOT; + relativeRel = R_SPARC_RELATIVE; ++ iRelativeRel = R_SPARC_IRELATIVE; + symbolicRel = R_SPARC_64; ++ tlsGotRel = R_SPARC_TLS_TPOFF64; ++ tlsModuleIndexRel = R_SPARC_TLS_DTPMOD64; ++ tlsOffsetRel = R_SPARC_TLS_DTPOFF64; ++ ++ gotHeaderEntriesNum = 1; + pltEntrySize = 32; + pltHeaderSize = 4 * pltEntrySize; ++ usesGotPlt = false; + + defaultCommonPageSize = 8192; + defaultMaxPageSize = 0x100000; +@@ -47,35 +82,74 @@ SPARCV9::SPARCV9(Ctx &ctx) : TargetInfo(ctx) { + RelExpr SPARCV9::getRelExpr(RelType type, const Symbol &s, + const uint8_t *loc) const { + switch (type) { ++ case R_SPARC_NONE: ++ return R_NONE; ++ case R_SPARC_8: ++ case R_SPARC_16: + case R_SPARC_32: ++ case R_SPARC_HI22: ++ case R_SPARC_13: ++ case R_SPARC_LO10: + case R_SPARC_UA32: + case R_SPARC_64: +- case R_SPARC_UA64: +- case R_SPARC_H44: +- case R_SPARC_M44: +- case R_SPARC_L44: + case R_SPARC_HH22: + case R_SPARC_HM10: + case R_SPARC_LM22: +- case R_SPARC_HI22: +- case R_SPARC_LO10: ++ case R_SPARC_HIX22: ++ case R_SPARC_LOX10: ++ case R_SPARC_H44: ++ case R_SPARC_M44: ++ case R_SPARC_L44: ++ case R_SPARC_UA64: ++ case R_SPARC_UA16: + return R_ABS; +- case R_SPARC_PC10: +- case R_SPARC_PC22: ++ case R_SPARC_DISP8: ++ case R_SPARC_DISP16: + case R_SPARC_DISP32: + case R_SPARC_WDISP30: ++ case R_SPARC_WDISP22: ++ case R_SPARC_PC10: ++ case R_SPARC_PC22: ++ case R_SPARC_WDISP16: ++ case R_SPARC_WDISP19: ++ case R_SPARC_DISP64: + return R_PC; + case R_SPARC_GOT10: +- return R_GOT_OFF; ++ case R_SPARC_GOT13: + case R_SPARC_GOT22: ++ case R_SPARC_GOTDATA_OP_HIX22: ++ case R_SPARC_GOTDATA_OP_LOX10: ++ case R_SPARC_GOTDATA_OP: + return R_GOT_OFF; + case R_SPARC_WPLT30: ++ case R_SPARC_TLS_GD_CALL: ++ case R_SPARC_TLS_LDM_CALL: + return R_PLT_PC; +- case R_SPARC_NONE: +- return R_NONE; ++ case R_SPARC_TLS_GD_HI22: ++ case R_SPARC_TLS_GD_LO10: ++ return R_TLSGD_GOT; ++ case R_SPARC_TLS_GD_ADD: ++ case R_SPARC_TLS_LDM_ADD: ++ case R_SPARC_TLS_LDO_ADD: ++ case R_SPARC_TLS_IE_LD: ++ case R_SPARC_TLS_IE_LDX: ++ case R_SPARC_TLS_IE_ADD: ++ return R_NONE; // TODO: Relax TLS relocations. ++ case R_SPARC_TLS_LDM_HI22: ++ case R_SPARC_TLS_LDM_LO10: ++ return R_TLSLD_GOT; ++ case R_SPARC_TLS_LDO_HIX22: ++ case R_SPARC_TLS_LDO_LOX10: ++ return R_DTPREL; ++ case R_SPARC_TLS_IE_HI22: ++ case R_SPARC_TLS_IE_LO10: ++ return R_GOT; + case R_SPARC_TLS_LE_HIX22: + case R_SPARC_TLS_LE_LOX10: + return R_TPREL; ++ case R_SPARC_GOTDATA_HIX22: ++ case R_SPARC_GOTDATA_LOX10: ++ return R_GOTREL; + default: + Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v + << ") against symbol " << &s; +@@ -83,73 +157,255 @@ RelExpr SPARCV9::getRelExpr(RelType type, const Symbol + } + } + ++RelType SPARCV9::getDynRel(RelType type) const { ++ switch (type) { ++ case R_SPARC_16: ++ case R_SPARC_32: ++ case R_SPARC_64: ++ case R_SPARC_UA16: ++ case R_SPARC_UA32: ++ case R_SPARC_UA64: ++ return type; ++ default: ++ break; ++ } ++ return R_SPARC_NONE; ++} ++ ++static bool getSparcAbsRelocPair(RelType type, RelType &aligned, ++ RelType &unaligned, uint64_t &alignment) { ++ switch (type) { ++ case R_SPARC_16: ++ case R_SPARC_UA16: ++ aligned = R_SPARC_16; ++ unaligned = R_SPARC_UA16; ++ alignment = 2; ++ return true; ++ case R_SPARC_32: ++ case R_SPARC_UA32: ++ aligned = R_SPARC_32; ++ unaligned = R_SPARC_UA32; ++ alignment = 4; ++ return true; ++ case R_SPARC_64: ++ case R_SPARC_UA64: ++ aligned = R_SPARC_64; ++ unaligned = R_SPARC_UA64; ++ alignment = 8; ++ return true; ++ default: ++ return false; ++ } ++} ++ ++void SPARCV9::prepareDynamicReloc(RelType type, const Symbol &sym, ++ InputSectionBase &sec) { ++ if (auto *eh = dyn_cast(&sec)) { ++ SyntheticSection *parent = eh->getParent(); ++ parent->flags |= sec.flags & SHF_WRITE; ++ parent->getParent()->flags |= sec.flags & SHF_WRITE; ++ } ++ ++ RelType aligned = R_SPARC_NONE, unaligned = R_SPARC_NONE; ++ uint64_t alignment = 1; ++ if (!getSparcAbsRelocPair(type, aligned, unaligned, alignment) || ++ sym.isPreemptible) ++ return; ++ ++ OutputSection *osec = sym.getOutputSection(); ++ if (!osec) ++ return; ++ ++ Partition &part = sec.getPartition(ctx); ++ unsigned partition = part.getNumber(ctx); ++ auto key = std::make_pair(osec, partition); ++ if (dynamicSectionSymbols.contains(key)) ++ return; ++ ++ Defined *sectionSym = ++ makeDefined(ctx, ctx.internalFile, "", STB_LOCAL, STV_DEFAULT, ++ STT_SECTION, 0, 0, osec); ++ sectionSym->partition = partition; ++ part.dynSymTab->addLocalSectionSymbol(sectionSym); ++ dynamicSectionSymbols[key] = sectionSym; ++} ++ ++void SPARCV9::finalizeDynamicReloc(DynamicReloc &rel) const { ++ // scanEhSection records an offset relative to the merged .eh_frame. ++ if (auto *eh = dyn_cast(rel.inputSec)) { ++ rel.inputSec = eh->getParent(); ++ rel.r_offset = rel.inputSec->getVA(rel.offsetInSec); ++ } ++ ++ if (rel.type == R_SPARC_JMP_SLOT && rel.inputSec == ctx.in.plt.get()) { ++ uint32_t pltIdx = rel.sym->getPltIdx(ctx); ++ if (pltIdx >= firstLargePltIndex) { ++ uint64_t off = ++ getPltEntryOffset(pltIdx, ctx.in.plt->headerSize); ++ rel.r_offset = ++ ctx.in.plt->getVA() + getLargePltPointerOffset(pltIdx); ++ rel.addend = -static_cast(ctx.in.plt->getVA() + off + 4); ++ } ++ } ++ ++ RelType aligned = R_SPARC_NONE, unaligned = R_SPARC_NONE; ++ uint64_t alignment = 1; ++ if (!getSparcAbsRelocPair(rel.type, aligned, unaligned, alignment)) ++ return; ++ ++ rel.type = rel.r_offset % alignment == 0 ? aligned : unaligned; ++ if (!rel.needsDynSymIndex() || rel.sym->isPreemptible) ++ return; ++ ++ if (rel.type == R_SPARC_64) { ++ rel.convertToRelative(relativeRel); ++ return; ++ } ++ ++ OutputSection *osec = rel.sym->getOutputSection(); ++ unsigned partition = rel.inputSec->getPartition(ctx).getNumber(ctx); ++ auto it = dynamicSectionSymbols.find(std::make_pair(osec, partition)); ++ assert(it != dynamicSectionSymbols.end()); ++ rel.addend = rel.sym->getVA(ctx, rel.addend); ++ rel.sym = it->second; ++} ++ + void SPARCV9::relocate(uint8_t *loc, const Relocation &rel, + uint64_t val) const { ++ switch (rel.expr) { ++ case R_RELAX_GOT_OFF: ++ return relaxGot(loc, rel, val); ++ default: ++ break; ++ } ++ + switch (rel.type) { ++ case R_SPARC_8: ++ // V-byte8 ++ checkUInt(ctx, loc, val, 8, rel); ++ *loc = val; ++ break; ++ case R_SPARC_16: ++ case R_SPARC_UA16: ++ // V-half16 ++ checkUInt(ctx, loc, val, 16, rel); ++ write16be(loc, val); ++ break; + case R_SPARC_32: + case R_SPARC_UA32: + // V-word32 + checkUInt(ctx, loc, val, 32, rel); + write32be(loc, val); + break; ++ case R_SPARC_DISP8: ++ // V-byte8 ++ checkIntUInt(ctx, loc, val, 8, rel); ++ *loc = val; ++ break; ++ case R_SPARC_DISP16: ++ // V-half16 ++ checkIntUInt(ctx, loc, val, 16, rel); ++ write16be(loc, val); ++ break; + case R_SPARC_DISP32: + // V-disp32 +- checkInt(ctx, loc, val, 32, rel); ++ checkIntUInt(ctx, loc, val, 32, rel); + write32be(loc, val); + break; + case R_SPARC_WDISP30: + case R_SPARC_WPLT30: ++ case R_SPARC_TLS_GD_CALL: ++ case R_SPARC_TLS_LDM_CALL: + // V-disp30 +- checkInt(ctx, loc, val, 32, rel); ++ checkIntUInt(ctx, loc, val, 32, rel); + write32be(loc, (read32be(loc) & ~0x3fffffff) | ((val >> 2) & 0x3fffffff)); + break; ++ case R_SPARC_WDISP22: ++ // V-disp22 ++ checkIntUInt(ctx, loc, val, 24, rel); ++ write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 2) & 0x003fffff)); ++ break; ++ case R_SPARC_HI22: // Only T-imm22 on 32-bit, despite binutils behavior. ++ // V-imm22 ++ checkUInt(ctx, loc, val, 32, rel); ++ write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff)); ++ break; + case R_SPARC_22: + // V-imm22 + checkUInt(ctx, loc, val, 22, rel); + write32be(loc, (read32be(loc) & ~0x003fffff) | (val & 0x003fffff)); + break; +- case R_SPARC_GOT22: +- case R_SPARC_PC22: +- case R_SPARC_LM22: +- // T-imm22 +- write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff)); ++ case R_SPARC_13: ++ case R_SPARC_GOT13: ++ // V-simm13 ++ checkIntUInt(ctx, loc, val, 13, rel); ++ write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x00001fff)); + break; +- case R_SPARC_HI22: +- // V-imm22 +- checkUInt(ctx, loc, val >> 10, 22, rel); +- write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff)); +- break; +- case R_SPARC_WDISP19: +- // V-disp19 +- checkInt(ctx, loc, val, 21, rel); +- write32be(loc, (read32be(loc) & ~0x0007ffff) | ((val >> 2) & 0x0007ffff)); +- break; ++ case R_SPARC_LO10: + case R_SPARC_GOT10: + case R_SPARC_PC10: +- // T-simm10 ++ case R_SPARC_TLS_GD_LO10: ++ case R_SPARC_TLS_LDM_LO10: ++ case R_SPARC_TLS_IE_LO10: ++ // T-simm13 + write32be(loc, (read32be(loc) & ~0x000003ff) | (val & 0x000003ff)); + break; +- case R_SPARC_LO10: ++ case R_SPARC_TLS_LDO_LOX10: + // T-simm13 + write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff)); + break; ++ case R_SPARC_GOT22: ++ case R_SPARC_LM22: ++ case R_SPARC_TLS_GD_HI22: ++ case R_SPARC_TLS_LDM_HI22: ++ case R_SPARC_TLS_LDO_HIX22: // Not V-simm22, despite binutils behavior. ++ case R_SPARC_TLS_IE_HI22: ++ // T-(s)imm22 ++ write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff)); ++ break; ++ case R_SPARC_PC22: ++ // V-disp22 ++ checkIntUInt(ctx, loc, val, 32, rel); ++ write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff)); ++ break; + case R_SPARC_64: ++ case R_SPARC_DISP64: + case R_SPARC_UA64: + // V-xword64 + write64be(loc, val); + break; + case R_SPARC_HH22: + // V-imm22 +- checkUInt(ctx, loc, val >> 42, 22, rel); + write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 42) & 0x003fffff)); + break; + case R_SPARC_HM10: + // T-simm13 +- write32be(loc, (read32be(loc) & ~0x00001fff) | ((val >> 32) & 0x000003ff)); ++ write32be(loc, (read32be(loc) & ~0x000003ff) | ((val >> 32) & 0x000003ff)); + break; ++ case R_SPARC_WDISP16: ++ // V-d2/disp14 ++ checkIntUInt(ctx, loc, val, 18, rel); ++ write32be(loc, (read32be(loc) & ~0x0303fff) | (((val >> 2) & 0xc000) << 6) | ++ ((val >> 2) & 0x00003fff)); ++ break; ++ case R_SPARC_WDISP19: ++ // V-disp19 ++ checkIntUInt(ctx, loc, val, 21, rel); ++ write32be(loc, (read32be(loc) & ~0x0007ffff) | ((val >> 2) & 0x0007ffff)); ++ break; ++ case R_SPARC_HIX22: ++ // V-imm22 ++ checkUInt(ctx, loc, ~val, 32, rel); ++ write32be(loc, (read32be(loc) & ~0x003fffff) | ((~val >> 10) & 0x003fffff)); ++ break; ++ case R_SPARC_LOX10: ++ case R_SPARC_TLS_LE_LOX10: ++ // T-simm13 ++ write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff) | 0x1c00); ++ break; + case R_SPARC_H44: + // V-imm22 +- checkUInt(ctx, loc, val >> 22, 22, rel); ++ checkUInt(ctx, loc, val, 44, rel); + write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 22) & 0x003fffff)); + break; + case R_SPARC_M44: +@@ -158,23 +414,134 @@ void SPARCV9::relocate(uint8_t *loc, const Relocation + break; + case R_SPARC_L44: + // T-imm13 +- write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x00000fff)); ++ write32be(loc, (read32be(loc) & ~0x00000fff) | (val & 0x00000fff)); + break; +- case R_SPARC_TLS_LE_HIX22: ++ case R_SPARC_TLS_GD_ADD: ++ case R_SPARC_TLS_LDM_ADD: ++ case R_SPARC_TLS_LDO_ADD: ++ case R_SPARC_TLS_IE_LD: ++ case R_SPARC_TLS_IE_LDX: ++ case R_SPARC_TLS_IE_ADD: ++ // None ++ break; ++ case R_SPARC_TLS_LE_HIX22: // Not V-imm2, despite binutils behavior. + // T-imm22 + write32be(loc, (read32be(loc) & ~0x003fffff) | ((~val >> 10) & 0x003fffff)); + break; +- case R_SPARC_TLS_LE_LOX10: +- // T-simm13 +- write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff) | 0x1C00); ++ case R_SPARC_GOTDATA_HIX22: ++ // V-imm22 ++ checkUInt(ctx, loc, ((int64_t)val < 0 ? ~val : val), 32, rel); ++ write32be(loc, (read32be(loc) & ~0x003fffff) | ++ ((((int64_t)val < 0 ? ~val : val) >> 10) & 0x003fffff)); + break; ++ case R_SPARC_GOTDATA_OP_HIX22: // Not V-imm22, despite binutils behavior. ++ // Non-relaxed case. ++ // T-imm22 ++ write32be(loc, (read32be(loc) & ~0x003fffff) | ++ ((((int64_t)val < 0 ? ~val : val) >> 10) & 0x003fffff)); ++ break; ++ case R_SPARC_GOTDATA_LOX10: ++ case R_SPARC_GOTDATA_OP_LOX10: // Non-relaxed case. ++ // T-imm13 ++ write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff) | ++ ((int64_t)val < 0 ? 0x1c00 : 0)); ++ break; ++ case R_SPARC_GOTDATA_OP: // Non-relaxed case. ++ // word32 ++ // Nothing needs to be done in the non-relaxed case. ++ break; + default: + llvm_unreachable("unknown relocation"); + } + } + +-void SPARCV9::writePlt(uint8_t *buf, const Symbol & /*sym*/, ++RelExpr SPARCV9::adjustGotOffExpr(RelType type, const Symbol &sym, ++ int64_t addend, const uint8_t *loc) const { ++ switch (type) { ++ case R_SPARC_GOTDATA_OP_HIX22: ++ case R_SPARC_GOTDATA_OP_LOX10: ++ case R_SPARC_GOTDATA_OP: ++ if (sym.isLocal()) ++ return R_RELAX_GOT_OFF; ++ ++ [[fallthrough]]; ++ default: ++ return R_GOT_OFF; ++ } ++} ++ ++void SPARCV9::relaxGot(uint8_t *loc, const Relocation &rel, ++ uint64_t val) const { ++ switch (rel.type) { ++ case R_SPARC_GOTDATA_OP_HIX22: // Not V-imm22, despite binutils behavior. ++ // T-imm22 ++ write32be(loc, (read32be(loc) & ~0x003fffff) | ++ ((((int64_t)val < 0 ? ~val : val) >> 10) & 0x003fffff)); ++ break; ++ case R_SPARC_GOTDATA_OP_LOX10: ++ // T-imm13 ++ write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff) | ++ ((int64_t)val < 0 ? 0x1c00 : 0)); ++ break; ++ case R_SPARC_GOTDATA_OP: ++ // word32 ++ // ldx [%rs1 + %rs2], %rd -> add %rs1, %rs2, %rd ++ write32be(loc, (read32be(loc) & 0x3e07c01f) | 0x80000000); ++ break; ++ default: ++ llvm_unreachable("unknown relocation"); ++ } ++} ++ ++void SPARCV9::writeGotHeader(uint8_t *buf) const { ++ // _GLOBAL_OFFSET_TABLE_[0] = _DYNAMIC when a dynamic section exists. ++ if (ctx.mainPart->dynamic) ++ write64(ctx, buf, ctx.mainPart->dynamic->getVA()); ++} ++ ++uint64_t SPARCV9::getPltEntryOffset(uint32_t pltIdx, ++ uint64_t headerSize) const { ++ if (pltIdx < firstLargePltIndex) ++ return headerSize + uint64_t{pltIdx} * pltEntrySize; ++ ++ uint32_t largeIdx = pltIdx - firstLargePltIndex; ++ return headerSize + uint64_t{firstLargePltIndex} * pltEntrySize + ++ largeIdx / pltLargeEntriesPerBlock * pltLargeBlockSize + ++ largeIdx % pltLargeEntriesPerBlock * pltLargeCodeSize; ++} ++ ++uint64_t SPARCV9::getLargePltPointerOffset(uint32_t pltIdx) const { ++ assert(pltIdx >= firstLargePltIndex); ++ uint32_t largeIdx = pltIdx - firstLargePltIndex; ++ uint32_t entriesBeforeBlock = ++ largeIdx / pltLargeEntriesPerBlock * pltLargeEntriesPerBlock; ++ uint32_t indexInBlock = largeIdx % pltLargeEntriesPerBlock; ++ uint64_t largeEntries = ctx.in.plt->getNumEntries() - firstLargePltIndex; ++ uint64_t entriesInBlock = ++ std::min(pltLargeEntriesPerBlock, ++ largeEntries - entriesBeforeBlock); ++ uint64_t blockOffset = getPltEntryOffset( ++ firstLargePltIndex + entriesBeforeBlock, ctx.in.plt->headerSize); ++ ++ return blockOffset + entriesInBlock * pltLargeCodeSize + ++ indexInBlock * pltLargePointerSize; ++} ++ ++void SPARCV9::writePlt(uint8_t *buf, const Symbol &sym, + uint64_t pltEntryAddr) const { ++ uint64_t off = pltEntryAddr - ctx.in.plt->getVA(); ++ if (sym.getPltIdx(ctx) >= firstLargePltIndex) { ++ uint64_t ptrOff = getLargePltPointerOffset(sym.getPltIdx(ctx)); ++ write32be(buf, 0x8a10000f); // mov %o7, %g5 ++ write32be(buf + 4, 0x40000002); // call .+8 ++ write32be(buf + 8, 0x01000000); // nop ++ write32be(buf + 12, ++ 0xc25be000 | ((ptrOff - (off + 4)) & 0x1fff)); ++ write32be(buf + 16, 0x83c3c001); // jmpl %o7+%g1, %g1 ++ write32be(buf + 20, 0x9e100005); // mov %g5, %o7 ++ return; ++ } ++ + const uint8_t pltData[] = { + 0x03, 0x00, 0x00, 0x00, // sethi (. - .PLT0), %g1 + 0x30, 0x68, 0x00, 0x00, // ba,a %xcc, .PLT1 +@@ -187,9 +554,15 @@ void SPARCV9::writePlt(uint8_t *buf, const Symbol & /* + }; + memcpy(buf, pltData, sizeof(pltData)); + +- uint64_t off = pltEntryAddr - ctx.in.plt->getVA(); + relocateNoSym(buf, R_SPARC_22, off); + relocateNoSym(buf + 4, R_SPARC_WDISP19, -(off + 4 - pltEntrySize)); ++} ++ ++void SPARCV9::finalizePlt(uint8_t *buf) const { ++ for (uint32_t i = firstLargePltIndex; i < ctx.in.plt->getNumEntries(); ++i) { ++ uint64_t off = getPltEntryOffset(i, ctx.in.plt->headerSize); ++ write64be(buf + getLargePltPointerOffset(i), -(off + 4)); ++ } + } + + void elf::setSPARCV9TargetInfo(Ctx &ctx) { ctx.target.reset(new SPARCV9(ctx)); } Index: patches/patch-lld_ELF_Driver_cpp =================================================================== RCS file: /home/cvs/ports/devel/llvm/22/patches/patch-lld_ELF_Driver_cpp,v diff -u -p -r1.2 patch-lld_ELF_Driver_cpp --- patches/patch-lld_ELF_Driver_cpp 2 Apr 2026 09:15:11 -0000 1.2 +++ patches/patch-lld_ELF_Driver_cpp 29 Jul 2026 19:22:39 -0000 @@ -33,7 +33,21 @@ Index: lld/ELF/Driver.cpp if (ctx.arg.emachine != EM_AARCH64 && ctx.arg.emachine != EM_ARM && ctx.arg.zExecuteOnlyReport != ReportPolicy::None) ErrAlways(ctx) -@@ -1420,8 +1434,6 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &a +@@ -1302,9 +1316,10 @@ static SmallVector getSymbolOrderingFile + + static bool getIsRela(Ctx &ctx, opt::InputArgList &args) { + // The psABI specifies the default relocation entry format. +- bool rela = is_contained({EM_AARCH64, EM_AMDGPU, EM_HEXAGON, EM_LOONGARCH, +- EM_PPC, EM_PPC64, EM_RISCV, EM_S390, EM_X86_64}, +- ctx.arg.emachine); ++ bool rela = ++ is_contained({EM_AARCH64, EM_AMDGPU, EM_HEXAGON, EM_LOONGARCH, EM_PPC, ++ EM_PPC64, EM_RISCV, EM_S390, EM_SPARCV9, EM_X86_64}, ++ ctx.arg.emachine); + // If -z rel or -z rela is specified, use the last option. + for (auto *arg : args.filtered(OPT_z)) { + StringRef s(arg->getValue()); +@@ -1420,8 +1435,6 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &a ctx.e.errorHandlingScript = args.getLastArgValue(OPT_error_handling_script); @@ -42,7 +56,7 @@ Index: lld/ELF/Driver.cpp ctx.arg.exportDynamic = args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false) || args.hasArg(OPT_shared); -@@ -1442,8 +1454,15 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &a +@@ -1442,8 +1455,15 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &a ctx.arg.icf = getICF(args); ctx.arg.ignoreDataAddressEquality = args.hasArg(OPT_ignore_data_address_equality); @@ -58,7 +72,7 @@ Index: lld/ELF/Driver.cpp ctx.arg.init = args.getLastArgValue(OPT_init, "_init"); ctx.arg.ltoAAPipeline = args.getLastArgValue(OPT_lto_aa_pipeline); ctx.arg.ltoCSProfileGenerate = args.hasArg(OPT_lto_cs_profile_generate); -@@ -1512,7 +1531,12 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &a +@@ -1512,7 +1532,12 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &a ctx.arg.outputFile = args.getLastArgValue(OPT_o); if (auto *arg = args.getLastArg(OPT_package_metadata)) parsePackageMetadata(ctx, *arg); @@ -71,7 +85,7 @@ Index: lld/ELF/Driver.cpp ctx.arg.printIcfSections = args.hasFlag(OPT_print_icf_sections, OPT_no_print_icf_sections, false); if (auto *arg = -@@ -1604,7 +1628,11 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &a +@@ -1604,7 +1629,11 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &a ctx.arg.trace = args.hasArg(OPT_trace); ctx.arg.undefined = args::getStrings(args, OPT_undefined); ctx.arg.undefinedVersion = @@ -83,7 +97,7 @@ Index: lld/ELF/Driver.cpp ctx.arg.unique = args.hasArg(OPT_unique); ctx.arg.useAndroidRelrTags = args.hasFlag( OPT_use_android_relr_tags, OPT_no_use_android_relr_tags, false); -@@ -1851,9 +1879,9 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &a +@@ -1851,9 +1880,9 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &a << arg->getValue() << "'"; parallel::strategy = hardware_concurrency(threads); ctx.arg.thinLTOJobs = v; @@ -96,7 +110,7 @@ Index: lld/ELF/Driver.cpp } if (auto *arg = args.getLastArg(OPT_thinlto_jobs_eq)) ctx.arg.thinLTOJobs = arg->getValue(); -@@ -2070,6 +2098,23 @@ static void setConfigs(Ctx &ctx, opt::InputArgList &ar +@@ -2070,6 +2099,23 @@ static void setConfigs(Ctx &ctx, opt::InputArgList &ar ErrAlways(ctx) << "cannot open --why-extract= file " << ctx.arg.whyExtract << ": " << e.message(); } @@ -120,7 +134,7 @@ Index: lld/ELF/Driver.cpp } static bool isFormatBinary(Ctx &ctx, StringRef s) { -@@ -2234,7 +2279,7 @@ void LinkerDriver::inferMachineType() { +@@ -2234,7 +2280,7 @@ void LinkerDriver::inferMachineType() { } // Parse -z max-page-size=. The default value is defined by @@ -129,7 +143,7 @@ Index: lld/ELF/Driver.cpp static uint64_t getMaxPageSize(Ctx &ctx, opt::InputArgList &args) { uint64_t val = args::getZOptionValue(args, OPT_z, "max-page-size", ctx.target->defaultMaxPageSize); -@@ -2252,7 +2297,7 @@ static uint64_t getMaxPageSize(Ctx &ctx, opt::InputArg +@@ -2252,7 +2298,7 @@ static uint64_t getMaxPageSize(Ctx &ctx, opt::InputArg } // Parse -z common-page-size=. The default value is defined by @@ -138,7 +152,7 @@ Index: lld/ELF/Driver.cpp static uint64_t getCommonPageSize(Ctx &ctx, opt::InputArgList &args) { uint64_t val = args::getZOptionValue(args, OPT_z, "common-page-size", ctx.target->defaultCommonPageSize); -@@ -2272,6 +2317,16 @@ static uint64_t getCommonPageSize(Ctx &ctx, opt::Input +@@ -2272,6 +2318,16 @@ static uint64_t getCommonPageSize(Ctx &ctx, opt::Input return val; } @@ -155,7 +169,7 @@ Index: lld/ELF/Driver.cpp // Parses --image-base option. static std::optional getImageBase(Ctx &ctx, opt::InputArgList &args) { // Because we are using `ctx.arg.maxPageSize` here, this function has to be -@@ -3435,6 +3490,11 @@ template void LinkerDriver::link(opt::Inp +@@ -3435,6 +3491,11 @@ template void LinkerDriver::link(opt::Inp // optimizations such as DATA_SEGMENT_ALIGN in linker scripts. LLD's use of it // is limited to writing trap instructions on the last executable segment. ctx.arg.commonPageSize = getCommonPageSize(ctx, args); Index: patches/patch-lld_ELF_InputFiles_cpp =================================================================== RCS file: /home/cvs/ports/devel/llvm/22/patches/patch-lld_ELF_InputFiles_cpp,v diff -u -p -r1.2 patch-lld_ELF_InputFiles_cpp --- patches/patch-lld_ELF_InputFiles_cpp 2 Jun 2026 13:16:58 -0000 1.2 +++ patches/patch-lld_ELF_InputFiles_cpp 29 Jul 2026 19:22:39 -0000 @@ -43,7 +43,66 @@ Index: lld/ELF/InputFiles.cpp break; case SHT_LLVM_LTO: // Discard .llvm.lto in a relocatable link that does not use the bitcode. -@@ -1565,6 +1586,9 @@ template void SharedFile::parse() { +@@ -1192,7 +1213,20 @@ InputSectionBase *ObjFile::createInputSection(ui + + // Initialize symbols. symbols is a parallel array to the corresponding ELF + // symbol table. ++// ++// LLVM's SPARC assembler and OpenBSD ld.so do not implement application ++// register metadata. Accept GCC scratch declarations, but keep them out of ++// ordinary symbol resolution. + template ++static bool isSparcRegister(const Ctx &ctx, const typename ELFT::Sym &sym) { ++ return ctx.arg.emachine == EM_SPARCV9 && sym.getType() == STT_SPARC_REGISTER; ++} ++ ++static bool isSparcScratchRegister(uint64_t value) { ++ return value == 2 || value == 3 || value == 6 || value == 7; ++} ++ ++template + void ObjFile::initializeSymbols(const object::ELFFile &obj) { + ArrayRef eSyms = this->getELFSyms(); + if (!symbols) +@@ -1200,14 +1234,25 @@ void ObjFile::initializeSymbols(const object::EL + + // Some entries have been filled by LazyObjFile. + auto *symtab = ctx.symtab.get(); +- for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i) +- if (!symbols[i]) +- symbols[i] = symtab->insert(CHECK2(eSyms[i].getName(stringTable), this)); ++ for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i) { ++ const Elf_Sym &eSym = eSyms[i]; ++ if (isSparcRegister(ctx, eSym)) { ++ StringRef name = CHECK2(eSym.getName(stringTable), this); ++ if (eSym.getBinding() != STB_GLOBAL || eSym.st_shndx != SHN_UNDEF || ++ !name.empty() || !isSparcScratchRegister(eSym.st_value)) ++ Err(ctx) << this << ": unsupported SPARC register declaration"; ++ symbols[i] = ctx.dummySym; ++ } else if (!symbols[i]) { ++ symbols[i] = symtab->insert(CHECK2(eSym.getName(stringTable), this)); ++ } ++ } + + // Perform symbol resolution on non-local symbols. + SmallVector undefineds; + for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i) { + const Elf_Sym &eSym = eSyms[i]; ++ if (isSparcRegister(ctx, eSym)) ++ continue; + uint32_t secIdx = eSym.st_shndx; + if (secIdx == SHN_UNDEF) { + undefineds.push_back(i); +@@ -1307,6 +1352,8 @@ template void ObjFile::postParse() + ArrayRef eSyms = this->getELFSyms(); + for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i) { + const Elf_Sym &eSym = eSyms[i]; ++ if (isSparcRegister(ctx, eSym)) ++ continue; + Symbol &sym = *symbols[i]; + uint32_t secIdx = eSym.st_shndx; + uint8_t binding = eSym.getBinding(); +@@ -1565,6 +1612,9 @@ template void SharedFile::parse() { const ELFFile obj = this->getObj(); ArrayRef sections = getELFShdrs(); @@ -53,7 +112,7 @@ Index: lld/ELF/InputFiles.cpp const Elf_Shdr *versymSec = nullptr; const Elf_Shdr *verdefSec = nullptr; const Elf_Shdr *verneedSec = nullptr; -@@ -1588,6 +1612,13 @@ template void SharedFile::parse() { +@@ -1588,7 +1638,14 @@ template void SharedFile::parse() { case SHT_GNU_verneed: verneedSec = &sec; break; @@ -63,7 +122,18 @@ Index: lld/ELF/InputFiles.cpp + CHECK2(obj.template getSectionContentsAsArray(sec), this); + parseGNUWarning(ctx, name, data, sec.sh_size); + break; -+ } } ++ } } + if (versymSec && numSymbols == 0) { +@@ -1659,6 +1716,9 @@ template void SharedFile::parse() { + ArrayRef syms = this->getGlobalELFSyms(); + for (size_t i = 0, e = syms.size(); i != e; ++i) { + const Elf_Sym &sym = syms[i]; ++ // A SPARC register declaration is DSO metadata, not a symbol dependency. ++ if (isSparcRegister(ctx, sym)) ++ continue; + + // ELF spec requires that all local symbols precede weak or global + // symbols in each symbol table, and the index of first non-local symbol Index: patches/patch-lld_ELF_InputSection_cpp =================================================================== RCS file: patches/patch-lld_ELF_InputSection_cpp diff -N patches/patch-lld_ELF_InputSection_cpp --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-lld_ELF_InputSection_cpp 29 Jul 2026 19:22:39 -0000 @@ -0,0 +1,11 @@ +Index: lld/ELF/InputSection.cpp +--- lld/ELF/InputSection.cpp.orig ++++ lld/ELF/InputSection.cpp +@@ -838,6 +838,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, + return ctx.in.gotPlt->getVA() + a - p; + case R_GOTREL: + case RE_PPC64_RELAX_TOC: ++ case R_RELAX_GOT_OFF: + return r.sym->getVA(ctx, a) - ctx.in.got->getVA(); + case R_GOTPLTREL: + return r.sym->getVA(ctx, a) - ctx.in.gotPlt->getVA(); Index: 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.2 patch-lld_ELF_Relocations_cpp --- patches/patch-lld_ELF_Relocations_cpp 6 May 2026 12:47:03 -0000 1.2 +++ patches/patch-lld_ELF_Relocations_cpp 29 Jul 2026 19:22:39 -0000 @@ -31,17 +31,171 @@ Index: lld/ELF/Relocations.cpp // Construct a message in the following format. // // >>> defined in /home/alice/src/foo.o -@@ -681,6 +704,13 @@ bool RelocScan::maybeReportUndefined(Undefined &sym, u - // .got2 +@@ -147,8 +170,9 @@ bool lld::elf::needsGot(RelExpr expr) { + static bool isRelExpr(RelExpr expr) { + return oneof(expr); ++ R_RELAX_GOT_OFF, R_RELAX_GOT_PC, RE_RISCV_PC_INDIRECT, ++ RE_PPC64_RELAX_GOT_PC, RE_LOONGARCH_PAGE_PC, ++ RE_LOONGARCH_PC_INDIRECT>(expr); + } + + static RelExpr toPlt(RelExpr expr) { +@@ -682,6 +706,13 @@ bool RelocScan::maybeReportUndefined(Undefined &sym, u if (sym.discardedSecIdx != 0 && (sec->name == ".got2" || sec->name == ".toc")) return false; -+ + +#ifdef __OpenBSD__ + // GCC (at least 8 and 11) can produce a ".gcc_except_table" with relocations + // to discarded sections on riscv64 + if (sym.discardedSecIdx != 0 && sec->name == ".gcc_except_table") + return false; +#endif - ++ bool isWarning = (ctx.arg.unresolvedSymbols == UnresolvedPolicy::Warn && canBeExternal) || + ctx.arg.noinhibitExec; +@@ -740,14 +771,18 @@ static void addRelativeReloc(Ctx &ctx, InputSectionBas + template + static void addPltEntry(Ctx &ctx, PltSection &plt, GotPltSection &gotPlt, + RelocationBaseSection &rel, RelType type, Symbol &sym) { ++ RelExpr expr = sym.isPreemptible ? R_ADDEND : R_ABS; + plt.addEntry(sym); +- gotPlt.addEntry(sym); +- if (sym.isPreemptible) ++ if (ctx.target->usesGotPlt) { ++ gotPlt.addEntry(sym); ++ // The relocation is applied to the .got.plt entry. ++ rel.addReloc({type, &gotPlt, sym.getGotPltOffset(ctx), !!sym.isPreemptible, ++ sym, 0, expr}); ++ } else { ++ // The relocation is applied to the .plt entry. + rel.addReloc( +- {type, &gotPlt, sym.getGotPltOffset(ctx), true, sym, 0, R_ADDEND}); +- else +- rel.addReloc( +- {type, &gotPlt, sym.getGotPltOffset(ctx), false, sym, 0, R_ABS}); ++ {type, &plt, sym.getPltOffset(ctx), !!sym.isPreemptible, sym, 0, expr}); ++ } + } + + void elf::addGotEntry(Ctx &ctx, Symbol &sym) { +@@ -915,25 +950,32 @@ void RelocScan::process(RelExpr expr, RelType type, ui + // indirection. + const bool isIfunc = sym.isGnuIFunc(); + if (!sym.isPreemptible && (!isIfunc || ctx.arg.zIfuncNoplt)) { +- if (expr != R_GOT_PC) { ++ if (expr != R_GOT_PC && expr != R_GOT_OFF) { + // The 0x8000 bit of r_addend of R_PPC_PLTREL24 is used to choose call + // stub type. It should be ignored if optimized to R_PC. + if (ctx.arg.emachine == EM_PPC && expr == RE_PPC32_PLTREL) + addend &= ~0x8000; + // R_HEX_GD_PLT_B22_PCREL (call a@GDPLT) is transformed into + // call __tls_get_addr even if the symbol is non-preemptible. ++ // Same deal for R_SPARC_TLS_LDM_CALL (call x@TLSPLT). + if (!(ctx.arg.emachine == EM_HEXAGON && + (type == R_HEX_GD_PLT_B22_PCREL || + type == R_HEX_GD_PLT_B22_PCREL_X || +- type == R_HEX_GD_PLT_B32_PCREL_X))) ++ type == R_HEX_GD_PLT_B32_PCREL_X)) && ++ !(ctx.arg.emachine == EM_SPARCV9 && type == R_SPARC_TLS_LDM_CALL)) + expr = fromPlt(expr); + } else if (!isAbsoluteValue(sym) || + (type == R_PPC64_PCREL_OPT && ctx.arg.emachine == EM_PPC64)) { +- expr = ctx.target->adjustGotPcExpr(type, addend, +- sec->content().data() + offset); +- // If the target adjusted the expression to R_RELAX_GOT_PC, we may end up ++ if (expr == R_GOT_PC) ++ expr = ctx.target->adjustGotPcExpr(type, addend, ++ sec->content().data() + offset); ++ else if (expr == R_GOT_OFF) ++ expr = ctx.target->adjustGotOffExpr(type, sym, addend, ++ sec->content().data() + offset); ++ ++ // If the target adjusted the expression to R_RELAX_GOT_*, we may end up + // needing the GOT if we can't relax everything. +- if (expr == R_RELAX_GOT_PC) ++ if (expr == R_RELAX_GOT_PC || expr == R_RELAX_GOT_OFF) + ctx.in.got->hasGotOffRel.store(true, std::memory_order_relaxed); + } + } +@@ -992,8 +1034,14 @@ void RelocScan::process(RelExpr expr, RelType type, ui + (isa(sec) && ctx.arg.emachine != EM_MIPS)); + if (canWrite) { + RelType rel = ctx.target->getDynRel(type); +- if (oneof(expr) || +- (rel == ctx.target->symbolicRel && !sym.isPreemptible)) { ++ bool useRelative = ++ rel == ctx.target->symbolicRel && !sym.isPreemptible; ++ if (ctx.arg.emachine == EM_SPARCV9 && ++ (type == R_SPARC_16 || type == R_SPARC_32 || type == R_SPARC_64 || ++ type == R_SPARC_UA16 || type == R_SPARC_UA32 || ++ type == R_SPARC_UA64)) ++ useRelative = false; ++ if (oneof(expr) || useRelative) { + addRelativeReloc(ctx, *sec, offset, sym, addend, expr, type); + return; + } +@@ -1036,6 +1084,7 @@ void RelocScan::process(RelExpr expr, RelType type, ui + return; + } + } ++ ctx.target->prepareDynamicReloc(rel, sym, *sec); + part.relaDyn->addSymbolReloc(rel, *sec, offset, sym, addend, type); + + // MIPS ABI turns using of GOT and dynamic relocations inside out. +@@ -1206,12 +1255,13 @@ unsigned RelocScan::handleTlsRelocation(RelExpr expr, + + // ARM, Hexagon, LoongArch and RISC-V do not support GD/LD to IE/LE + // optimizations. ++ // SPARC support for GD/LD to IE/LE optimizations is not yet implemented. + // RISC-V supports TLSDESC to IE/LE optimizations. + // For PPC64, if the file has missing R_PPC64_TLSGD/R_PPC64_TLSLD, disable + // optimization as well. + bool execOptimize = + !ctx.arg.shared && ctx.arg.emachine != EM_ARM && +- ctx.arg.emachine != EM_HEXAGON && ++ ctx.arg.emachine != EM_HEXAGON && ctx.arg.emachine != EM_SPARCV9 && + (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) { + } else { + assert(sym.isFunc() && sym.hasFlag(NEEDS_PLT)); + if (!sym.isDefined()) { +- replaceWithDefined(ctx, sym, *ctx.in.plt, +- ctx.target->pltHeaderSize + +- ctx.target->pltEntrySize * sym.getPltIdx(ctx), +- 0); ++ replaceWithDefined(ctx, sym, *ctx.in.plt, sym.getPltOffset(ctx), 0); + 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, + return addressesChanged; + } + +-// The following aid in the conversion of call x@GDPLT to call __tls_get_addr +-// hexagonNeedsTLSSymbol scans for relocations would require a call to +-// __tls_get_addr. +-// hexagonTLSSymbolUpdate rebinds the relocation to __tls_get_addr. +-bool elf::hexagonNeedsTLSSymbol(ArrayRef outputSections) { ++// The following aid in the conversion of call x@GDPLT (Hexagon) and ++// call x@TLSPLT (SPARC) to call __tls_get_addr. needsTLSSymbol scans ++// for relocations that would require a call to __tls_get_addr. ++// tlsSymbolUpdate rebinds the relocation to __tls_get_addr. ++bool elf::needsTLSSymbol(ArrayRef outputSections) { + bool needTlsSymbol = false; + forEachInputSectionDescription( + outputSections, [&](OutputSection *os, InputSectionDescription *isd) { +@@ -2221,7 +2268,7 @@ bool elf::hexagonNeedsTLSSymbol(ArrayReffind("__tls_get_addr"); + if (!sym) + return; Index: patches/patch-lld_ELF_Relocations_h =================================================================== RCS file: /home/cvs/ports/devel/llvm/22/patches/patch-lld_ELF_Relocations_h,v diff -u -p -r1.1 patch-lld_ELF_Relocations_h --- patches/patch-lld_ELF_Relocations_h 6 May 2026 12:47:03 -0000 1.1 +++ patches/patch-lld_ELF_Relocations_h 29 Jul 2026 19:22:39 -0000 @@ -1,13 +1,27 @@ Index: lld/ELF/Relocations.h --- lld/ELF/Relocations.h.orig +++ lld/ELF/Relocations.h -@@ -176,6 +176,9 @@ bool hexagonNeedsTLSSymbol(ArrayRef o +@@ -61,6 +61,7 @@ enum RelExpr { + R_PLT_GOTPLT, + R_PLT_GOTREL, + R_RELAX_HINT, ++ R_RELAX_GOT_OFF, + R_RELAX_GOT_PC, + R_RELAX_GOT_PC_NOPIC, + R_RELAX_TLS_GD_TO_IE, +@@ -171,10 +172,13 @@ bool maybeReportUndefined(Ctx &, Undefined &sym, Input + void postScanRelocations(Ctx &ctx); + void addGotEntry(Ctx &ctx, Symbol &sym); - bool isAbsolute(const Symbol &sym); +-void hexagonTLSSymbolUpdate(Ctx &ctx); +-bool hexagonNeedsTLSSymbol(ArrayRef outputSections); ++void tlsSymbolUpdate(Ctx &ctx); ++bool needsTLSSymbol(ArrayRef outputSections); + bool isAbsolute(const Symbol &sym); ++ +void reportGNUWarning(Ctx &ctx, Symbol &sym, InputSectionBase &sec, + uint64_t offset); -+ + class ThunkSection; class Thunk; - class InputSectionDescription; Index: 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.1.1.1 patch-lld_ELF_Symbols_cpp --- patches/patch-lld_ELF_Symbols_cpp 25 Feb 2026 13:31:43 -0000 1.1.1.1 +++ patches/patch-lld_ELF_Symbols_cpp 29 Jul 2026 19:22:39 -0000 @@ -12,3 +12,26 @@ Index: lld/ELF/Symbols.cpp template struct AssertSymbol { static_assert(std::is_trivially_destructible(), +@@ -173,11 +173,20 @@ uint64_t Symbol::getGotPltOffset(Ctx &ctx) const { + ctx.target->gotEntrySize; + } + ++uint64_t Symbol::getPltOffset(Ctx &ctx) const { ++ if (isInIplt) ++ return getPltIdx(ctx) * ctx.target->ipltEntrySize; ++ return ctx.target->getPltEntryOffset(getPltIdx(ctx), ++ ctx.in.plt->headerSize); ++} ++ + uint64_t Symbol::getPltVA(Ctx &ctx) const { + uint64_t outVA = isInIplt ? ctx.in.iplt->getVA() + + getPltIdx(ctx) * ctx.target->ipltEntrySize +- : ctx.in.plt->getVA() + ctx.in.plt->headerSize + +- getPltIdx(ctx) * ctx.target->pltEntrySize; ++ : ctx.in.plt->getVA() + ++ ctx.target->getPltEntryOffset( ++ getPltIdx(ctx), ++ ctx.in.plt->headerSize); + + // While linking microMIPS code PLT code are always microMIPS + // code. Set the less-significant bit to track that fact. Index: 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.4 patch-lld_ELF_Symbols_h --- patches/patch-lld_ELF_Symbols_h 10 Jul 2026 06:50:19 -0000 1.4 +++ patches/patch-lld_ELF_Symbols_h 29 Jul 2026 19:22:39 -0000 @@ -11,7 +11,15 @@ 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; } -@@ -244,7 +247,7 @@ class Symbol { (public) +@@ -204,6 +207,7 @@ class Symbol { (public) + uint64_t getGotVA(Ctx &) const; + uint64_t getGotPltOffset(Ctx &) const; + uint64_t getGotPltVA(Ctx &) const; ++ uint64_t getPltOffset(Ctx &) const; + uint64_t getPltVA(Ctx &) const; + uint64_t getSize() const; + OutputSection *getOutputSection() const; +@@ -244,7 +248,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), @@ -20,7 +28,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 +543,8 @@ void reportDuplicate(Ctx &, const Symbol &sym, const I +@@ -540,6 +544,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: 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.1.1.1 patch-lld_ELF_SyntheticSections_cpp --- patches/patch-lld_ELF_SyntheticSections_cpp 25 Feb 2026 13:31:43 -0000 1.1.1.1 +++ patches/patch-lld_ELF_SyntheticSections_cpp 29 Jul 2026 19:22:39 -0000 @@ -1,7 +1,98 @@ Index: lld/ELF/SyntheticSections.cpp --- lld/ELF/SyntheticSections.cpp.orig +++ lld/ELF/SyntheticSections.cpp -@@ -2602,6 +2602,10 @@ PltSection::PltSection(Ctx &ctx) +@@ -1505,6 +1505,7 @@ DynamicSection::computeContents() { + addInt(DT_RISCV_VARIANT_CC, 0); + [[fallthrough]]; + default: ++ assert(ctx.target->usesGotPlt); + addInSec(DT_PLTGOT, *ctx.in.gotPlt); + break; + } +@@ -1720,14 +1721,20 @@ void RelocationBaseSection::finalizeContents() { + else + getParent()->link = 0; + +- if (ctx.in.relaPlt.get() == this && ctx.in.gotPlt->getParent()) { +- getParent()->flags |= ELF::SHF_INFO_LINK; +- getParent()->info = ctx.in.gotPlt->getParent()->sectionIndex; ++ if (ctx.in.relaPlt.get() == this) { ++ if (ctx.target->usesGotPlt && ctx.in.gotPlt->getParent()) { ++ getParent()->flags |= ELF::SHF_INFO_LINK; ++ getParent()->info = ctx.in.gotPlt->getParent()->sectionIndex; ++ } else if (ctx.in.plt->getParent()) { ++ getParent()->flags |= ELF::SHF_INFO_LINK; ++ getParent()->info = ctx.in.plt->getParent()->sectionIndex; ++ } + } + } + + void DynamicReloc::finalize(Ctx &ctx, SymbolTableBaseSection *symt) { + r_offset = getOffset(); ++ ctx.target->finalizeDynamicReloc(*this); + r_sym = getSymIndex(symt); + addend = computeAddend(ctx); + isFinal = true; // Catch errors +@@ -2176,12 +2183,12 @@ void SymbolTableBaseSection::finalizeContents() { + return; + } + +- // If it is a .dynsym, there should be no local symbols, but we need +- // to do a few things for the dynamic linker. ++ // If it is a .dynsym, we need to do a few things for the dynamic linker. + + // Section's Info field has the index of the first non-local symbol. +- // Because the first symbol entry is a null entry, 1 is the first. +- getParent()->info = 1; ++ // Because the first symbol entry is a null entry, add one to the number of ++ // local symbols. ++ getParent()->info = numLocalDynamicSymbols + 1; + + if (getPartition(ctx).gnuHashTab) { + // NB: It also sorts Symbols to meet the GNU hash table requirements. +@@ -2201,7 +2208,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 +-// symbols for dynamic linking are inherently all globals.) ++// local symbols are inserted before global symbols.) + // + // 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) { + symbols.push_back({b, strTabSec.addString(b->getName(), false)}); + } + ++void SymbolTableBaseSection::addLocalSectionSymbol(Symbol *b) { ++ assert(this->type == SHT_DYNSYM && b->isLocal() && b->isSection()); ++ symbols.insert(symbols.begin() + numLocalDynamicSymbols, ++ {b, strTabSec.addString(b->getName(), false)}); ++ ++numLocalDynamicSymbols; ++} ++ + size_t SymbolTableBaseSection::getSymbolIndex(const Symbol &sym) { + if (this == ctx.mainPart->dynSymTab.get()) + return sym.dynsymIndex; +@@ -2508,7 +2522,8 @@ void GnuHashTableSection::addSymbols(SmallVectorImplisDefined() || s.sym->partition != partition; ++ return s.sym->isLocal() || !s.sym->isDefined() || ++ s.sym->partition != partition; + }); + + // We chose load factor 4 for the on-disk hash table. For each hash +@@ -2574,6 +2589,8 @@ void HashTableSection::writeTo(uint8_t *buf) { + + for (const SymbolTableEntry &s : symTab->getSymbols()) { + Symbol *sym = s.sym; ++ if (sym->isLocal()) ++ continue; + StringRef name = sym->getName(); + unsigned i = sym->dynsymIndex; + uint32_t hash = hashSysV(name) % numSymbols; +@@ -2602,23 +2619,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"; @@ -12,7 +103,58 @@ Index: lld/ELF/SyntheticSections.cpp // The PLT needs to be writable on SPARC as the dynamic linker will // modify the instructions in the PLT entries. -@@ -4909,6 +4913,12 @@ template void elf::createSyntheticSection +- if (ctx.arg.emachine == EM_SPARCV9) ++ if (ctx.arg.emachine == EM_SPARCV9) { + this->flags |= SHF_WRITE; ++ addralign = 256; ++ } + } + + void PltSection::writeTo(uint8_t *buf) { + // At beginning of PLT, we have code to call the dynamic + // linker to resolve dynsyms at runtime. Write such code. + ctx.target->writePltHeader(buf); +- size_t off = headerSize; + + for (const Symbol *sym : entries) { ++ size_t off = sym->getPltOffset(ctx); + ctx.target->writePlt(buf + off, *sym, getVA() + off); +- off += ctx.target->pltEntrySize; + } ++ ctx.target->finalizePlt(buf); + } + + void PltSection::addEntry(Symbol &sym) { +@@ -2641,11 +2664,8 @@ bool PltSection::isNeeded() const { + void PltSection::addSymbols() { + ctx.target->addPltHeaderSymbols(*this); + +- size_t off = headerSize; +- for (size_t i = 0; i < entries.size(); ++i) { +- ctx.target->addPltSymbols(*this, off); +- off += ctx.target->pltEntrySize; +- } ++ for (const Symbol *sym : entries) ++ ctx.target->addPltSymbols(*this, sym->getPltOffset(ctx)); + } + + IpltSection::IpltSection(Ctx &ctx) +@@ -4878,10 +4898,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) { +- if (ctx.target->gotBaseSymInGotPlt) ++ if (ctx.target->gotBaseSymInGotPlt) { ++ assert(ctx.target->usesGotPlt); + ctx.in.gotPlt->hasGotPltOffRel = true; +- else ++ } else { + ctx.in.got->hasGotOffRel = true; ++ } + } + + // We always need to add rel[a].plt to output if it has entries. +@@ -4909,6 +4931,12 @@ template void elf::createSyntheticSection ctx.in.gnuProperty = std::make_unique(ctx); add(*ctx.in.gnuProperty); } Index: 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.1.1.1 patch-lld_ELF_SyntheticSections_h --- patches/patch-lld_ELF_SyntheticSections_h 25 Feb 2026 13:31:43 -0000 1.1.1.1 +++ patches/patch-lld_ELF_SyntheticSections_h 29 Jul 2026 19:22:39 -0000 @@ -1,7 +1,35 @@ Index: lld/ELF/SyntheticSections.h --- lld/ELF/SyntheticSections.h.orig +++ lld/ELF/SyntheticSections.h -@@ -1462,7 +1462,11 @@ void addVerneed(Ctx &, Symbol &ss); +@@ -433,6 +433,11 @@ class DynamicReloc { (public) + uint64_t getOffset() const; + uint32_t getSymIndex(SymbolTableBaseSection *symTab) const; + bool needsDynSymIndex() const { return isAgainstSymbol; } ++ void convertToRelative(RelType relativeRel) { ++ type = relativeRel; ++ isAgainstSymbol = false; ++ expr = R_ABS; ++ } + + /// Computes the addend of the dynamic relocation. Note that this is not the + /// same as the #addend member variable as it may also include the symbol +@@ -661,6 +666,7 @@ class SymbolTableBaseSection : public SyntheticSection + void finalizeContents() override; + size_t getSize() const override { return getNumSymbols() * entsize; } + void addSymbol(Symbol *sym); ++ void addLocalSectionSymbol(Symbol *sym); + unsigned getNumSymbols() const { return symbols.size() + 1; } + size_t getSymbolIndex(const Symbol &sym); + ArrayRef getSymbols() const { return symbols; } +@@ -670,6 +676,7 @@ class SymbolTableBaseSection : public SyntheticSection + + // A vector of symbols and their string table offsets. + SmallVector symbols; ++ size_t numLocalDynamicSymbols = 0; + + StringTableSection &strTabSec; + +@@ -1462,7 +1469,11 @@ void addVerneed(Ctx &, Symbol &ss); // placed in it. struct PhdrEntry { PhdrEntry(Ctx &ctx, unsigned type, unsigned flags) Index: patches/patch-lld_ELF_Target_cpp =================================================================== RCS file: patches/patch-lld_ELF_Target_cpp diff -N patches/patch-lld_ELF_Target_cpp --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-lld_ELF_Target_cpp 29 Jul 2026 19:22:39 -0000 @@ -0,0 +1,16 @@ +Index: lld/ELF/Target.cpp +--- lld/ELF/Target.cpp.orig ++++ lld/ELF/Target.cpp +@@ -158,6 +158,12 @@ RelExpr TargetInfo::adjustGotPcExpr(RelType type, int6 + return R_GOT_PC; + } + ++RelExpr TargetInfo::adjustGotOffExpr(RelType type, const Symbol &sym, ++ int64_t addend, ++ const uint8_t *data) const { ++ return R_GOT_OFF; ++} ++ + static void relocateImpl(const TargetInfo &target, InputSectionBase &sec, + uint64_t secAddr, uint8_t *buf) { + auto &ctx = target.ctx; Index: patches/patch-lld_ELF_Target_h =================================================================== RCS file: patches/patch-lld_ELF_Target_h diff -N patches/patch-lld_ELF_Target_h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-lld_ELF_Target_h 29 Jul 2026 19:22:39 -0000 @@ -0,0 +1,63 @@ +Index: lld/ELF/Target.h +--- lld/ELF/Target.h.orig ++++ lld/ELF/Target.h +@@ -22,6 +22,7 @@ + namespace lld { + namespace elf { + class Defined; ++class DynamicReloc; + class InputFile; + class Symbol; + template struct Relocs; +@@ -35,6 +36,9 @@ class TargetInfo { (public) + virtual RelExpr getRelExpr(RelType type, const Symbol &s, + const uint8_t *loc) const = 0; + virtual RelType getDynRel(RelType type) const { return 0; } ++ virtual void prepareDynamicReloc(RelType type, const Symbol &sym, ++ InputSectionBase &sec) {} ++ virtual void finalizeDynamicReloc(DynamicReloc &rel) const {} + virtual void writeGotPltHeader(uint8_t *buf) const {} + virtual void writeGotHeader(uint8_t *buf) const {} + virtual void writeGotPlt(uint8_t *buf, const Symbol &s) const {} +@@ -47,8 +51,13 @@ class TargetInfo { (public) + // they are called. This function writes that code. + virtual void writePltHeader(uint8_t *buf) const {} + ++ virtual uint64_t getPltEntryOffset(uint32_t pltIdx, ++ uint64_t headerSize) const { ++ return headerSize + uint64_t{pltIdx} * pltEntrySize; ++ } + virtual void writePlt(uint8_t *buf, const Symbol &sym, + uint64_t pltEntryAddr) const {} ++ virtual void finalizePlt(uint8_t *buf) const {} + virtual void writeIplt(uint8_t *buf, const Symbol &sym, + uint64_t pltEntryAddr) const { + // All but PPC32 and PPC64 use the same format for .plt and .iplt entries. +@@ -135,7 +144,8 @@ class TargetInfo { (public) + + uint64_t getImageBase() const; + +- // True if _GLOBAL_OFFSET_TABLE_ is relative to .got.plt, false if .got. ++ // True if _GLOBAL_OFFSET_TABLE_ is relative to .got.plt, false if .got. If ++ // true, usesGotPlt must also be true. + bool gotBaseSymInGotPlt = false; + + static constexpr RelType noneRel = 0; +@@ -162,6 +172,8 @@ class TargetInfo { (public) + // On PPC ELF V2 abi, the first entry in the .got is the .TOC. + unsigned gotHeaderEntriesNum = 0; + ++ bool usesGotPlt = true; ++ + // On PPC ELF V2 abi, the dynamic section needs DT_PPC64_OPT (DT_LOPROC + 3) + // to be set to 0x2 if there can be multiple TOC's. Although we do not emit + // multiple TOC's, there can be a mix of TOC and NOTOC addressing which +@@ -186,6 +198,8 @@ class TargetInfo { (public) + virtual RelExpr adjustTlsExpr(RelType type, RelExpr expr) const; + virtual RelExpr adjustGotPcExpr(RelType type, int64_t addend, + const uint8_t *loc) const; ++ virtual RelExpr adjustGotOffExpr(RelType type, const Symbol &sym, ++ int64_t addend, const uint8_t *loc) const; + + protected: + // On FreeBSD x86_64 the first page cannot be mmaped. Index: 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.1.1.1 patch-lld_ELF_Writer_cpp --- patches/patch-lld_ELF_Writer_cpp 25 Feb 2026 13:31:43 -0000 1.1.1.1 +++ patches/patch-lld_ELF_Writer_cpp 29 Jul 2026 19:22:39 -0000 @@ -18,10 +18,12 @@ Index: lld/ELF/Writer.cpp (ctx.arg.discard == DiscardPolicy::Locals || (sym.section && (sym.section->flags & SHF_MERGE)))) return false; -@@ -625,7 +626,11 @@ static bool isRelroSection(Ctx &ctx, const OutputSecti +@@ -624,8 +625,12 @@ static bool isRelroSection(Ctx &ctx, const OutputSecti + // by default resolved lazily, so we usually cannot put it into RELRO. // However, if "-z now" is given, the lazy symbol resolution is // disabled, which enables us to put it into RELRO. - if (sec == ctx.in.gotPlt->getParent()) +- if (sec == ctx.in.gotPlt->getParent()) ++ if (ctx.target->usesGotPlt && sec == ctx.in.gotPlt->getParent()) +#ifndef __OpenBSD__ return ctx.arg.zNow; +#else @@ -43,7 +45,24 @@ Index: lld/ELF/Writer.cpp return abiAgnostic || abiSpecific; } -@@ -927,6 +935,9 @@ template void Writer::setReservedSy +@@ -855,10 +863,14 @@ template void Writer::setReservedSy + if (ctx.sym.globalOffsetTable) { + // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention usually + // to the start of the .got or .got.plt section. +- InputSection *sec = ctx.in.gotPlt.get(); +- if (!ctx.target->gotBaseSymInGotPlt) ++ InputSection *sec; ++ if (ctx.target->gotBaseSymInGotPlt) { ++ assert(ctx.target->usesGotPlt); ++ sec = ctx.in.gotPlt.get(); ++ } else { + sec = ctx.in.mipsGot ? cast(ctx.in.mipsGot.get()) + : cast(ctx.in.got.get()); ++ } + ctx.sym.globalOffsetTable->section = sec; + } + +@@ -927,6 +939,9 @@ template void Writer::setReservedSy ctx.sym.bss->section = sbss ? sbss : findSection(ctx, ".bss"); } @@ -53,7 +72,50 @@ 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) { -@@ -2454,34 +2465,22 @@ Writer::createPhdrs(Partition &part) { +@@ -1533,9 +1548,9 @@ template void Writer::finalizeAddre + }; + finalizeOrderDependentContent(); + +- // Converts call x@GDPLT to call __tls_get_addr +- if (ctx.arg.emachine == EM_HEXAGON) +- hexagonTLSSymbolUpdate(ctx); ++ // Converts call x@GDPLT/x@TLSPLT to call __tls_get_addr. ++ if (ctx.arg.emachine == EM_HEXAGON || ctx.arg.emachine == EM_SPARCV9) ++ tlsSymbolUpdate(ctx); + + if (ctx.arg.randomizeSectionPadding) + randomizeSectionPadding(ctx); +@@ -2031,10 +2046,10 @@ template void Writer::finalizeSecti + sec->addrExpr = [=] { return i->second; }; + } + +- // With the ctx.outputSections available check for GDPLT relocations ++ // With the ctx.outputSections available check for GDPLT/TLSPLT relocations + // and add __tls_get_addr symbol if needed. +- if (ctx.arg.emachine == EM_HEXAGON && +- hexagonNeedsTLSSymbol(ctx.outputSections)) { ++ if ((ctx.arg.emachine == EM_HEXAGON || ctx.arg.emachine == EM_SPARCV9) && ++ needsTLSSymbol(ctx.outputSections)) { + 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) { + static uint64_t computeFlags(Ctx &ctx, uint64_t flags) { + if (ctx.arg.omagic) + return PF_R | PF_W | PF_X; ++#ifdef __OpenBSD__ ++ // The sparc64 static PIE startup code reads an instruction from .text to ++ // locate _DYNAMIC before applying relocations. ++ if (ctx.arg.emachine == EM_SPARCV9 && ctx.arg.pie && !ctx.arg.shared && ++ ctx.sharedFiles.empty() && (flags & PF_X)) ++ return flags | PF_R; ++ if (ctx.arg.emachine == EM_SPARCV9 && (flags & PF_X) && (flags & PF_W)) ++ return flags; ++#endif + if (ctx.arg.executeOnly && (flags & PF_X)) + return flags & ~PF_R; + return flags; +@@ -2454,34 +2478,22 @@ Writer::createPhdrs(Partition &part) { addHdr(PT_GNU_EH_FRAME, part.ehFrameHdr->getParent()->getPhdrFlags()) ->add(part.ehFrameHdr->getParent()); @@ -101,7 +163,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 +2492,19 @@ Writer::createPhdrs(Partition &part) { +@@ -2493,7 +2505,19 @@ Writer::createPhdrs(Partition &part) { // OpenBSD. if (ctx.arg.zWxneeded) addHdr(PT_OPENBSD_WXNEEDED, PF_X); @@ -121,7 +183,7 @@ Index: lld/ELF/Writer.cpp if (OutputSection *cmd = findSection(ctx, ".note.gnu.property", partNo)) addHdr(PT_GNU_PROPERTY, PF_R)->add(cmd); -@@ -2586,6 +2597,31 @@ template void Writer::fixSectionAli +@@ -2586,6 +2610,31 @@ template void Writer::fixSectionAli }; } }; Index: patches/patch-llvm_include_llvm_BinaryFormat_ELF_h =================================================================== RCS file: patches/patch-llvm_include_llvm_BinaryFormat_ELF_h diff -N patches/patch-llvm_include_llvm_BinaryFormat_ELF_h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-llvm_include_llvm_BinaryFormat_ELF_h 29 Jul 2026 19:22:39 -0000 @@ -0,0 +1,13 @@ +Index: llvm/include/llvm/BinaryFormat/ELF.h +--- llvm/include/llvm/BinaryFormat/ELF.h.orig ++++ llvm/include/llvm/BinaryFormat/ELF.h +@@ -1426,6 +1426,9 @@ enum { + STT_LOPROC = 13, // Lowest processor-specific symbol type + STT_HIPROC = 15, // Highest processor-specific symbol type + ++ // SPARC symbol types ++ STT_SPARC_REGISTER = 13, ++ + // AMDGPU symbol types + STT_AMDGPU_HSA_KERNEL = 10 + }; Index: patches/patch-llvm_lib_Target_Sparc_AsmParser_SparcAsmParser_cpp =================================================================== RCS file: patches/patch-llvm_lib_Target_Sparc_AsmParser_SparcAsmParser_cpp diff -N patches/patch-llvm_lib_Target_Sparc_AsmParser_SparcAsmParser_cpp --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-llvm_lib_Target_Sparc_AsmParser_SparcAsmParser_cpp 29 Jul 2026 19:22:39 -0000 @@ -0,0 +1,76 @@ +Index: llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +--- llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp.orig ++++ llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +@@ -39,6 +39,7 @@ + #include + #include + #include ++#include + + using namespace llvm; + +@@ -81,6 +82,7 @@ class SparcAsmParser : public MCTargetAsmParser { + bool parseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) override; + ParseStatus parseDirective(AsmToken DirectiveID) override; ++ bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) override; + + unsigned validateTargetOperandClass(MCParsedAsmOperand &Op, + unsigned Kind) override; +@@ -1044,7 +1046,28 @@ ParseStatus SparcAsmParser::parseDirective(AsmToken Di + Parser.eatToEndOfStatement(); + return ParseStatus::Success; + } ++ if (IDVal == ".seg") { ++ std::string Name; ++ if (Parser.parseEscapedString(Name) || Parser.parseEOL()) ++ return ParseStatus::Failure; + ++ MCSection *Section; ++ uint32_t Subsection = 0; ++ const MCObjectFileInfo *MCOFI = getContext().getObjectFileInfo(); ++ if (Name == "text") { ++ Section = MCOFI->getTextSection(); ++ } else if (Name == "data" || Name == "data1") { ++ Section = MCOFI->getDataSection(); ++ Subsection = Name == "data1" ? 1 : 0; ++ } else if (Name == "bss") { ++ Section = MCOFI->getBSSSection(); ++ } else { ++ return Error(DirectiveID.getLoc(), "unknown segment type"); ++ } ++ getStreamer().switchSection(Section, Subsection); ++ return ParseStatus::Success; ++ } ++ + // Let the MC layer to handle other directives. + return ParseStatus::NoMatch; + } +@@ -1686,7 +1709,9 @@ SparcAsmParser::adjustPICRelocation(uint16_t RelType, + // actually a %pc10 or %pc22 relocation. Otherwise, they are interpreted + // as %got10 or %got22 relocation. + +- if (getContext().getObjectFileInfo()->isPositionIndependent()) { ++ int64_t AbsoluteValue; ++ if (getContext().getObjectFileInfo()->isPositionIndependent() && ++ !subExpr->evaluateAsAbsolute(AbsoluteValue)) { + switch (RelType) { + default: break; + case ELF::R_SPARC_LO10: +@@ -1744,6 +1769,16 @@ bool SparcAsmParser::matchSparcAsmModifiers(const MCEx + + EVal = adjustPICRelocation(VK, subExpr); + return true; ++} ++ ++bool SparcAsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { ++ if (Parser.getTok().is(AsmToken::Percent)) { ++ Parser.Lex(); ++ if (matchSparcAsmModifiers(Res, EndLoc)) ++ return false; ++ return true; ++ } ++ return Parser.parsePrimaryExpr(Res, EndLoc, nullptr); + } + + bool SparcAsmParser::isPossibleExpression(const AsmToken &Token) { Index: patches/patch-llvm_lib_Target_Sparc_SparcISelLowering_cpp =================================================================== RCS file: patches/patch-llvm_lib_Target_Sparc_SparcISelLowering_cpp diff -N patches/patch-llvm_lib_Target_Sparc_SparcISelLowering_cpp --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-llvm_lib_Target_Sparc_SparcISelLowering_cpp 29 Jul 2026 19:22:39 -0000 @@ -0,0 +1,57 @@ +Index: llvm/lib/Target/Sparc/SparcISelLowering.cpp +--- llvm/lib/Target/Sparc/SparcISelLowering.cpp.orig ++++ llvm/lib/Target/Sparc/SparcISelLowering.cpp +@@ -1202,16 +1202,43 @@ SparcTargetLowering::LowerCall_32(TargetLowering::Call + // this table could be generated automatically from RegInfo. + Register SparcTargetLowering::getRegisterByName(const char* RegName, LLT VT, + const MachineFunction &MF) const { +- Register Reg = StringSwitch(RegName) +- .Case("i0", SP::I0).Case("i1", SP::I1).Case("i2", SP::I2).Case("i3", SP::I3) +- .Case("i4", SP::I4).Case("i5", SP::I5).Case("i6", SP::I6).Case("i7", SP::I7) +- .Case("o0", SP::O0).Case("o1", SP::O1).Case("o2", SP::O2).Case("o3", SP::O3) +- .Case("o4", SP::O4).Case("o5", SP::O5).Case("o6", SP::O6).Case("o7", SP::O7) +- .Case("l0", SP::L0).Case("l1", SP::L1).Case("l2", SP::L2).Case("l3", SP::L3) +- .Case("l4", SP::L4).Case("l5", SP::L5).Case("l6", SP::L6).Case("l7", SP::L7) +- .Case("g0", SP::G0).Case("g1", SP::G1).Case("g2", SP::G2).Case("g3", SP::G3) +- .Case("g4", SP::G4).Case("g5", SP::G5).Case("g6", SP::G6).Case("g7", SP::G7) +- .Default(0); ++ StringRef Name(RegName); ++ Name.consume_front("%"); ++ ++ Register Reg = StringSwitch(Name) ++ .Cases({"r24", "i0"}, SP::I0) ++ .Cases({"r25", "i1"}, SP::I1) ++ .Cases({"r26", "i2"}, SP::I2) ++ .Cases({"r27", "i3"}, SP::I3) ++ .Cases({"r28", "i4"}, SP::I4) ++ .Cases({"r29", "i5"}, SP::I5) ++ .Cases({"r30", "i6", "fp"}, SP::I6) ++ .Cases({"r31", "i7"}, SP::I7) ++ .Cases({"r8", "o0"}, SP::O0) ++ .Cases({"r9", "o1"}, SP::O1) ++ .Cases({"r10", "o2"}, SP::O2) ++ .Cases({"r11", "o3"}, SP::O3) ++ .Cases({"r12", "o4"}, SP::O4) ++ .Cases({"r13", "o5"}, SP::O5) ++ .Cases({"r14", "o6", "sp"}, SP::O6) ++ .Cases({"r15", "o7"}, SP::O7) ++ .Cases({"r16", "l0"}, SP::L0) ++ .Cases({"r17", "l1"}, SP::L1) ++ .Cases({"r18", "l2"}, SP::L2) ++ .Cases({"r19", "l3"}, SP::L3) ++ .Cases({"r20", "l4"}, SP::L4) ++ .Cases({"r21", "l5"}, SP::L5) ++ .Cases({"r22", "l6"}, SP::L6) ++ .Cases({"r23", "l7"}, SP::L7) ++ .Cases({"r0", "g0"}, SP::G0) ++ .Cases({"r1", "g1"}, SP::G1) ++ .Cases({"r2", "g2"}, SP::G2) ++ .Cases({"r3", "g3"}, SP::G3) ++ .Cases({"r4", "g4"}, SP::G4) ++ .Cases({"r5", "g5"}, SP::G5) ++ .Cases({"r6", "g6"}, SP::G6) ++ .Cases({"r7", "g7"}, SP::G7) ++ .Default(0); + + // If we're directly referencing register names + // (e.g in GCC C extension `register int r asm("g1");`),