Download raw body.
OpenBSD/spac64 by LLVM toolchain
tech@,
Here a diff which allows me to build OpenBSD/spac64 by llvm toolchain.
My test cycle from clean snapshot was:
1. Rebuild clang / lld
cd /usr/src/gnu/usr.bin/clang
doas make clean
doas -u build make CC=clang CXX=clang++ -j8
doas make install
2. Rebuild clang / lld as system compiler
cd /usr/src/share/mk
doas make install
cd /usr/src/gnu/usr.bin/clang
doas make clean
doas -u build make CC=clang CXX=clang++ LD=ld.lld -j8
doas make install
3. Rebuild the system itself
cd /usr/src
doas make build -j8
doas make install
4. Rebuild kernel
cd /usr/src/sys/arch/sparc64/compile/GENERIC.MP
doas make clean
doas -u build make config
doas -u make
doas make install
It boots and seems to works, but I haven't tried to build ports.
The medium size diff which is based on
https://github.com/llvm/llvm-project/pull/137919
Index: gnu/llvm/lld/ELF/Driver.cpp
===================================================================
RCS file: /cvs/src/gnu/llvm/lld/ELF/Driver.cpp,v
diff -u -p -r1.24 Driver.cpp
--- gnu/llvm/lld/ELF/Driver.cpp 29 May 2026 11:06:20 -0000 1.24
+++ gnu/llvm/lld/ELF/Driver.cpp 1 Jul 2026 12:05:26 -0000
@@ -1316,9 +1316,10 @@ static SmallVector<StringRef, 0> getSymb
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());
Index: gnu/llvm/lld/ELF/InputSection.cpp
===================================================================
RCS file: /cvs/src/gnu/llvm/lld/ELF/InputSection.cpp,v
diff -u -p -r1.8 InputSection.cpp
--- gnu/llvm/lld/ELF/InputSection.cpp 29 May 2026 11:06:20 -0000 1.8
+++ gnu/llvm/lld/ELF/InputSection.cpp 1 Jul 2026 12:05:26 -0000
@@ -838,6 +838,7 @@ uint64_t InputSectionBase::getRelocTarge
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: gnu/llvm/lld/ELF/Relocations.cpp
===================================================================
RCS file: /cvs/src/gnu/llvm/lld/ELF/Relocations.cpp,v
diff -u -p -r1.11 Relocations.cpp
--- gnu/llvm/lld/ELF/Relocations.cpp 29 May 2026 11:06:20 -0000 1.11
+++ gnu/llvm/lld/ELF/Relocations.cpp 1 Jul 2026 12:05:26 -0000
@@ -770,14 +770,18 @@ static void addRelativeReloc(Ctx &ctx, I
template <class PltSection, class GotPltSection>
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)
- rel.addReloc(
- {type, &gotPlt, sym.getGotPltOffset(ctx), true, sym, 0, R_ADDEND});
- else
+ 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), false, sym, 0, R_ABS});
+ {type, &plt, sym.getPltOffset(ctx), !!sym.isPreemptible, sym, 0, expr});
+ }
}
void elf::addGotEntry(Ctx &ctx, Symbol &sym) {
@@ -945,25 +949,32 @@ void RelocScan::process(RelExpr expr, Re
// 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);
}
}
@@ -1236,12 +1247,13 @@ unsigned RelocScan::handleTlsRelocation(
// 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;
@@ -2233,11 +2245,11 @@ bool ThunkCreator::createThunks(uint32_t
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<OutputSection *> 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<OutputSection *> outputSections) {
bool needTlsSymbol = false;
forEachInputSectionDescription(
outputSections, [&](OutputSection *os, InputSectionDescription *isd) {
@@ -2251,7 +2263,7 @@ bool elf::hexagonNeedsTLSSymbol(ArrayRef
return needTlsSymbol;
}
-void elf::hexagonTLSSymbolUpdate(Ctx &ctx) {
+void elf::tlsSymbolUpdate(Ctx &ctx) {
Symbol *sym = ctx.symtab->find("__tls_get_addr");
if (!sym)
return;
Index: gnu/llvm/lld/ELF/Relocations.h
===================================================================
RCS file: /cvs/src/gnu/llvm/lld/ELF/Relocations.h,v
diff -u -p -r1.1.1.6 Relocations.h
--- gnu/llvm/lld/ELF/Relocations.h 29 May 2026 11:05:55 -0000 1.1.1.6
+++ gnu/llvm/lld/ELF/Relocations.h 1 Jul 2026 12:05:26 -0000
@@ -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,8 +172,8 @@ bool maybeReportUndefined(Ctx &, Undefin
void postScanRelocations(Ctx &ctx);
void addGotEntry(Ctx &ctx, Symbol &sym);
-void hexagonTLSSymbolUpdate(Ctx &ctx);
-bool hexagonNeedsTLSSymbol(ArrayRef<OutputSection *> outputSections);
+void tlsSymbolUpdate(Ctx &ctx);
+bool needsTLSSymbol(ArrayRef<OutputSection *> outputSections);
bool isAbsolute(const Symbol &sym);
Index: gnu/llvm/lld/ELF/Symbols.cpp
===================================================================
RCS file: /cvs/src/gnu/llvm/lld/ELF/Symbols.cpp,v
diff -u -p -r1.7 Symbols.cpp
--- gnu/llvm/lld/ELF/Symbols.cpp 29 May 2026 11:06:20 -0000 1.7
+++ gnu/llvm/lld/ELF/Symbols.cpp 1 Jul 2026 12:05:26 -0000
@@ -173,6 +173,12 @@ uint64_t Symbol::getGotPltOffset(Ctx &ct
ctx.target->gotEntrySize;
}
+uint64_t Symbol::getPltOffset(Ctx &ctx) const {
+ if (isInIplt)
+ return getPltIdx(ctx) * ctx.target->ipltEntrySize;
+ return ctx.in.plt->headerSize + getPltIdx(ctx) * ctx.target->pltEntrySize;
+}
+
uint64_t Symbol::getPltVA(Ctx &ctx) const {
uint64_t outVA = isInIplt ? ctx.in.iplt->getVA() +
getPltIdx(ctx) * ctx.target->ipltEntrySize
Index: gnu/llvm/lld/ELF/Symbols.h
===================================================================
RCS file: /cvs/src/gnu/llvm/lld/ELF/Symbols.h,v
diff -u -p -r1.8 Symbols.h
--- gnu/llvm/lld/ELF/Symbols.h 29 May 2026 11:06:20 -0000 1.8
+++ gnu/llvm/lld/ELF/Symbols.h 1 Jul 2026 12:05:26 -0000
@@ -207,6 +207,7 @@ 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;
Index: gnu/llvm/lld/ELF/SyntheticSections.cpp
===================================================================
RCS file: /cvs/src/gnu/llvm/lld/ELF/SyntheticSections.cpp,v
diff -u -p -r1.10 SyntheticSections.cpp
--- gnu/llvm/lld/ELF/SyntheticSections.cpp 29 May 2026 11:06:20 -0000 1.10
+++ gnu/llvm/lld/ELF/SyntheticSections.cpp 1 Jul 2026 12:05:26 -0000
@@ -1505,6 +1505,7 @@ DynamicSection<ELFT>::computeContents()
addInt(DT_RISCV_VARIANT_CC, 0);
[[fallthrough]];
default:
+ assert(ctx.target->usesGotPlt);
addInSec(DT_PLTGOT, *ctx.in.gotPlt);
break;
}
@@ -1720,14 +1721,31 @@ void RelocationBaseSection::finalizeCont
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();
+ if (ctx.arg.emachine == EM_SPARCV9 && type == R_SPARC_UA64 &&
+ needsDynSymIndex() && !sym->isPreemptible) {
+ if (r_offset % 8 != 0) {
+ Err(ctx) << "R_SPARC_UA64 relocation at offset " << r_offset
+ << " against non-preemptible symbol " << sym
+ << " is not 8-byte aligned";
+ } else {
+ type = ctx.target->relativeRel;
+ isAgainstSymbol = false;
+ expr = R_ABS;
+ }
+ }
r_sym = getSymIndex(symt);
addend = computeAddend(ctx);
isFinal = true; // Catch errors
@@ -2609,8 +2627,10 @@ PltSection::PltSection(Ctx &ctx)
// The PLT needs to be writable on SPARC as the dynamic linker will
// modify the instructions in the PLT entries.
- if (ctx.arg.emachine == EM_SPARCV9)
+ if (ctx.arg.emachine == EM_SPARCV9) {
this->flags |= SHF_WRITE;
+ addralign = 256;
+ }
}
void PltSection::writeTo(uint8_t *buf) {
@@ -4882,10 +4902,12 @@ template <class ELFT> void elf::createSy
// _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.
Index: gnu/llvm/lld/ELF/Target.cpp
===================================================================
RCS file: /cvs/src/gnu/llvm/lld/ELF/Target.cpp,v
diff -u -p -r1.1.1.6 Target.cpp
--- gnu/llvm/lld/ELF/Target.cpp 29 May 2026 11:05:55 -0000 1.1.1.6
+++ gnu/llvm/lld/ELF/Target.cpp 1 Jul 2026 12:05:26 -0000
@@ -158,6 +158,12 @@ RelExpr TargetInfo::adjustGotPcExpr(RelT
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: gnu/llvm/lld/ELF/Target.h
===================================================================
RCS file: /cvs/src/gnu/llvm/lld/ELF/Target.h,v
diff -u -p -r1.1.1.6 Target.h
--- gnu/llvm/lld/ELF/Target.h 29 May 2026 11:05:55 -0000 1.1.1.6
+++ gnu/llvm/lld/ELF/Target.h 1 Jul 2026 12:05:26 -0000
@@ -135,7 +135,8 @@ 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 +163,8 @@ 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 +189,8 @@ 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: gnu/llvm/lld/ELF/Writer.cpp
===================================================================
RCS file: /cvs/src/gnu/llvm/lld/ELF/Writer.cpp,v
diff -u -p -r1.10 Writer.cpp
--- gnu/llvm/lld/ELF/Writer.cpp 29 May 2026 11:06:20 -0000 1.10
+++ gnu/llvm/lld/ELF/Writer.cpp 1 Jul 2026 12:05:26 -0000
@@ -625,7 +625,7 @@ static bool isRelroSection(Ctx &ctx, con
// 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 (ctx.target->usesGotPlt && sec == ctx.in.gotPlt->getParent())
#ifndef __OpenBSD__
return ctx.arg.zNow;
#else
@@ -863,10 +863,14 @@ template <class ELFT> void Writer<ELFT>:
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<InputSection>(ctx.in.mipsGot.get())
: cast<InputSection>(ctx.in.got.get());
+ }
ctx.sym.globalOffsetTable->section = sec;
}
@@ -1544,9 +1548,9 @@ template <class ELFT> void Writer<ELFT>:
};
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);
@@ -2042,10 +2046,10 @@ template <class ELFT> void Writer<ELFT>:
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});
@@ -2311,6 +2315,10 @@ static bool needsPtLoad(OutputSection *s
static uint64_t computeFlags(Ctx &ctx, uint64_t flags) {
if (ctx.arg.omagic)
return PF_R | PF_W | PF_X;
+#ifdef __OpenBSD__
+ 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;
Index: gnu/llvm/lld/ELF/Arch/SPARCV9.cpp
===================================================================
RCS file: /cvs/src/gnu/llvm/lld/ELF/Arch/SPARCV9.cpp,v
diff -u -p -r1.1.1.5 SPARCV9.cpp
--- gnu/llvm/lld/ELF/Arch/SPARCV9.cpp 29 May 2026 11:05:55 -0000 1.1.1.5
+++ gnu/llvm/lld/ELF/Arch/SPARCV9.cpp 1 Jul 2026 12:05:26 -0000
@@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
+#include "OutputSections.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
@@ -23,10 +24,17 @@ public:
SPARCV9(Ctx &);
RelExpr getRelExpr(RelType type, const Symbol &s,
const uint8_t *loc) const override;
+ RelType getDynRel(RelType type) const override;
+ void writeGotHeader(uint8_t *buf) const override;
void writePlt(uint8_t *buf, const Symbol &sym,
uint64_t pltEntryAddr) 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:
+ void relaxGot(uint8_t *loc, const Relocation &rel, uint64_t val) const;
};
} // namespace
@@ -35,9 +43,16 @@ SPARCV9::SPARCV9(Ctx &ctx) : TargetInfo(
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 +62,74 @@ SPARCV9::SPARCV9(Ctx &ctx) : TargetInfo(
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 +137,148 @@ RelExpr SPARCV9::getRelExpr(RelType type
}
}
+RelType SPARCV9::getDynRel(RelType type) const {
+ if (type == symbolicRel || type == R_SPARC_UA64)
+ return type;
+ return R_SPARC_NONE;
+}
+
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_22:
- // V-imm22
- checkUInt(ctx, loc, val, 22, rel);
- write32be(loc, (read32be(loc) & ~0x003fffff) | (val & 0x003fffff));
+ case R_SPARC_WDISP22:
+ // V-disp22
+ checkIntUInt(ctx, loc, val, 24, rel);
+ write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 2) & 0x003fffff));
break;
- case R_SPARC_GOT22:
- case R_SPARC_PC22:
- case R_SPARC_LM22:
- // T-imm22
+ 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_HI22:
+ case R_SPARC_22:
// V-imm22
- checkUInt(ctx, loc, val >> 10, 22, rel);
- write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
+ checkUInt(ctx, loc, val, 22, rel);
+ write32be(loc, (read32be(loc) & ~0x003fffff) | (val & 0x003fffff));
break;
- case R_SPARC_WDISP19:
- // V-disp19
- checkInt(ctx, loc, val, 21, rel);
- write32be(loc, (read32be(loc) & ~0x0007ffff) | ((val >> 2) & 0x0007ffff));
+ 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_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,19 +287,89 @@ void SPARCV9::relocate(uint8_t *loc, con
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");
}
+}
+
+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)
+ write32(ctx, buf, ctx.mainPart->dynamic->getVA());
}
void SPARCV9::writePlt(uint8_t *buf, const Symbol & /*sym*/,
Index: share/mk/bsd.own.mk
===================================================================
RCS file: /cvs/src/share/mk/bsd.own.mk,v
diff -u -p -r1.216 bsd.own.mk
--- share/mk/bsd.own.mk 17 Nov 2025 16:06:09 -0000 1.216
+++ share/mk/bsd.own.mk 1 Jul 2026 12:05:26 -0000
@@ -16,8 +16,8 @@ SKEY?= yes
YP?= yes
CLANG_ARCH=aarch64 amd64 arm i386 mips64 mips64el powerpc powerpc64 riscv64 sparc64
-GCC4_ARCH=alpha hppa m88k sh sparc64
-LLD_ARCH=aarch64 amd64 arm i386 powerpc powerpc64 riscv64
+GCC4_ARCH=alpha hppa m88k sh
+LLD_ARCH=aarch64 amd64 arm i386 powerpc powerpc64 riscv64 sparc64
LLDB_ARCH=aarch64 amd64
# Can't use ${CLANG_ARCH} ${GCC4_ARCH} below because of sparc64
Index: sys/arch/sparc64/conf/Makefile.sparc64
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/conf/Makefile.sparc64,v
diff -u -p -r1.113 Makefile.sparc64
--- sys/arch/sparc64/conf/Makefile.sparc64 5 May 2025 20:43:32 -0000 1.113
+++ sys/arch/sparc64/conf/Makefile.sparc64 1 Jul 2026 12:05:26 -0000
@@ -122,12 +122,16 @@ ioconf.o: ioconf.c
ld.script: ${_machdir}/conf/ld.script
cp ${_machdir}/conf/ld.script $@
+gapdummy.o:
+ echo '__asm(".section .rodata,\"a\"");' > gapdummy.c
+ ${CC} -c ${CFLAGS} ${CPPFLAGS} gapdummy.c -o $@
+
makegap.sh:
cp $S/conf/makegap.sh $@
-MAKE_GAP = LD="${LD}" sh makegap.sh 0x00000000
+MAKE_GAP = LD="${LD}" sh makegap.sh 0x00000000 gapdummy.o
-gap.o: Makefile makegap.sh vers.o
+gap.o: Makefile makegap.sh gapdummy.o vers.o
${MAKE_GAP}
vers.o: ${SYSTEM_DEP:Ngap.o}
@@ -136,7 +140,7 @@ vers.o: ${SYSTEM_DEP:Ngap.o}
clean:
rm -f *bsd *bsd.gdb *.[dio] [a-z]*.s assym.* \
- gap.link ld.script lorder makegap.sh param.c
+ gap.link gapdummy.c ld.script lorder makegap.sh param.c
cleandir: clean
rm -f Makefile *.h ioconf.c options machine ${_mach} vers.c
Index: sys/arch/sparc64/stand/bootblk/genassym.sh
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/stand/bootblk/genassym.sh,v
diff -u -p -r1.4 genassym.sh
--- sys/arch/sparc64/stand/bootblk/genassym.sh 2 Apr 2020 06:06:22 -0000 1.4
+++ sys/arch/sparc64/stand/bootblk/genassym.sh 1 Jul 2026 12:05:26 -0000
@@ -164,9 +164,9 @@ $0 ~ /^endif/ {
printf("printf(\"#define " $2 " %%ld\\n\", (%s)" value ");\n", type);
else if (fcode) {
if (doing_member)
- printf("__asm(\"XYZZY : %s d# %%%s0 + ;\" : : \"%s\" (%s));\n", $2, asmprint, asmtype, value);
+ printf("__asm(\".ascii \\\"XYZZY : %s d# %%%s0 + ;\\\"\" : : \"%s\" (%s));\n", $2, asmprint, asmtype, value);
else
- printf("__asm(\"XYZZY d# %%%s0 constant %s\" : : \"%s\" (%s));\n", asmprint, $2, asmtype, value);
+ printf("__asm(\".ascii \\\"XYZZY d# %%%s0 constant %s\\\"\" : : \"%s\" (%s));\n", asmprint, $2, asmtype, value);
} else
printf("__asm(\"XYZZY %s %%%s0\" : : \"%s\" (%s));\n", $2, asmprint, asmtype, value);
next;
@@ -204,7 +204,7 @@ elif [ "$fcode" = 1 ]; then
# Kill all of the "#" and "$" modifiers; locore.s already
# prepends the correct "constant" modifier.
"$@" -S "${genassym_temp}/assym.c" -o - | sed -e 's/\$//g' | \
- sed -n 's/.*XYZZY//gp'
+ sed -n 's/.*\.ascii[[:space:]]*"XYZZY\([^"]*\)".*/\1/p'
else
# Kill all of the "#" and "$" modifiers; locore.s already
# prepends the correct "constant" modifier.
--
wbr, Kirill
OpenBSD/spac64 by LLVM toolchain