From: Kirill A. Korinsky Subject: Re: OpenBSD/spac64 by LLVM toolchain To: tech@openbsd.org Date: Thu, 09 Jul 2026 13:46:17 +0200 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 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 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 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) { @@ -2251,7 +2263,7 @@ bool elf::hexagonNeedsTLSSymbol(ArrayRef 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 outputSections); +void tlsSymbolUpdate(Ctx &ctx); +bool needsTLSSymbol(ArrayRef 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::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 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 void Writer::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(ctx.in.mipsGot.get()) : cast(ctx.in.got.get()); + } ctx.sym.globalOffsetTable->section = sec; } @@ -1544,9 +1548,9 @@ template void Writer::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 void Writer::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