Re: OpenBSD/spac64 by LLVM toolchain

Kirill A. Korinsky <[email protected]>
Newsgroups gmane.os.openbsd.tech
Message-ID <[email protected]>
Here updated version of diff which should match that tb@ is testing on his
sparc64.

Also, I have excluded fixes for ld.so which I send early here:
https://marc.info/?l=openbsd-tech&m=178359162807385&w=2

diff --git gnu/llvm/lld/ELF/Arch/SPARCV9.cpp gnu/llvm/lld/ELF/Arch/SPARCV9.cpp
index 86668c50d3c..7b46ec7db59 100644
--- gnu/llvm/lld/ELF/Arch/SPARCV9.cpp
+++ gnu/llvm/lld/ELF/Arch/SPARCV9.cpp
@@ -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(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 +62,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 +137,148 @@ RelExpr SPARCV9::getRelExpr(RelType type, const Symbol &s,
   }
 }
 
+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,21 +287,91 @@ void SPARCV9::relocate(uint8_t *loc, const Relocation &rel,
     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*/,
                        uint64_t pltEntryAddr) const {
   const uint8_t pltData[] = {
diff --git gnu/llvm/lld/ELF/Driver.cpp gnu/llvm/lld/ELF/Driver.cpp
index de99ea195cf..c61cf1808af 100644
--- gnu/llvm/lld/ELF/Driver.cpp
+++ gnu/llvm/lld/ELF/Driver.cpp
@@ -1316,9 +1316,10 @@ static SmallVector<StringRef, 0> getSymbolOrderingFile(Ctx &ctx,
 
 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());
diff --git gnu/llvm/lld/ELF/InputSection.cpp gnu/llvm/lld/ELF/InputSection.cpp
index 7402c8454c0..e49c6b2230d 100644
--- gnu/llvm/lld/ELF/InputSection.cpp
+++ gnu/llvm/lld/ELF/InputSection.cpp
@@ -838,6 +838,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
     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();
diff --git gnu/llvm/lld/ELF/Relocations.cpp gnu/llvm/lld/ELF/Relocations.cpp
index 863909a9d46..4f311e56db0 100644
--- gnu/llvm/lld/ELF/Relocations.cpp
+++ gnu/llvm/lld/ELF/Relocations.cpp
@@ -770,14 +770,18 @@ static void addRelativeReloc(Ctx &ctx, InputSectionBase &isec,
 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, RelType type, uint64_t offset,
   // 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(RelExpr expr, RelType type,
 
   // 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 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<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<OutputSection *> outputSections) {
   return needTlsSymbol;
 }
 
-void elf::hexagonTLSSymbolUpdate(Ctx &ctx) {
+void elf::tlsSymbolUpdate(Ctx &ctx) {
   Symbol *sym = ctx.symtab->find("__tls_get_addr");
   if (!sym)
     return;
diff --git gnu/llvm/lld/ELF/Relocations.h gnu/llvm/lld/ELF/Relocations.h
index 05c35d03e07..c34a57f6c2e 100644
--- gnu/llvm/lld/ELF/Relocations.h
+++ gnu/llvm/lld/ELF/Relocations.h
@@ -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 &, Undefined &sym, InputSectionBase &sec,
 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);
 
diff --git gnu/llvm/lld/ELF/Symbols.cpp gnu/llvm/lld/ELF/Symbols.cpp
index 6f74421582c..71fa8a61a96 100644
--- gnu/llvm/lld/ELF/Symbols.cpp
+++ gnu/llvm/lld/ELF/Symbols.cpp
@@ -173,6 +173,12 @@ 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.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
diff --git gnu/llvm/lld/ELF/Symbols.h gnu/llvm/lld/ELF/Symbols.h
index bb9e304151d..1fbb8f1cd82 100644
--- gnu/llvm/lld/ELF/Symbols.h
+++ gnu/llvm/lld/ELF/Symbols.h
@@ -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;
diff --git gnu/llvm/lld/ELF/SyntheticSections.cpp gnu/llvm/lld/ELF/SyntheticSections.cpp
index 70dc5a53ff4..57fcfc4cf3a 100644
--- gnu/llvm/lld/ELF/SyntheticSections.cpp
+++ gnu/llvm/lld/ELF/SyntheticSections.cpp
@@ -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::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();
+  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::createSyntheticSections(Ctx &ctx) {
   // _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.
diff --git gnu/llvm/lld/ELF/Target.cpp gnu/llvm/lld/ELF/Target.cpp
index 3fc3e3f16e9..e8108ea1859 100644
--- gnu/llvm/lld/ELF/Target.cpp
+++ gnu/llvm/lld/ELF/Target.cpp
@@ -158,6 +158,12 @@ RelExpr TargetInfo::adjustGotPcExpr(RelType type, int64_t addend,
   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;
diff --git gnu/llvm/lld/ELF/Target.h gnu/llvm/lld/ELF/Target.h
index 30fcb02b43f..e867ad7e84c 100644
--- gnu/llvm/lld/ELF/Target.h
+++ gnu/llvm/lld/ELF/Target.h
@@ -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.
diff --git gnu/llvm/lld/ELF/Writer.cpp gnu/llvm/lld/ELF/Writer.cpp
index 6ab2467857e..5f611fd3d0f 100644
--- gnu/llvm/lld/ELF/Writer.cpp
+++ gnu/llvm/lld/ELF/Writer.cpp
@@ -625,7 +625,7 @@ static bool isRelroSection(Ctx &ctx, const OutputSection *sec) {
   // 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>::setReservedSymbolSections() {
   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>::finalizeAddressDependentContent() {
   };
   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>::finalizeSections() {
       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,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;
diff --git share/mk/bsd.own.mk share/mk/bsd.own.mk
index 26028b653be..bc7f12cecb9 100644
--- share/mk/bsd.own.mk
+++ share/mk/bsd.own.mk
@@ -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
diff --git sys/arch/sparc64/conf/Makefile.sparc64 sys/arch/sparc64/conf/Makefile.sparc64
index 6ef6d052de3..f694a46347e 100644
--- sys/arch/sparc64/conf/Makefile.sparc64
+++ sys/arch/sparc64/conf/Makefile.sparc64
@@ -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
diff --git sys/arch/sparc64/stand/bootblk/genassym.sh sys/arch/sparc64/stand/bootblk/genassym.sh
index 6ca7a09ffa0..7490a21d7c2 100644
--- sys/arch/sparc64/stand/bootblk/genassym.sh
+++ sys/arch/sparc64/stand/bootblk/genassym.sh
@@ -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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.