diff --git a/lld/ELF/Arch/SPARCV9.cpp b/lld/ELF/Arch/SPARCV9.cpp index b594b6677f3ad..5e9b27928641c 100644 --- a/lld/ELF/Arch/SPARCV9.cpp +++ b/lld/ELF/Arch/SPARCV9.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "OutputSections.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" @@ -24,10 +25,17 @@ class SPARCV9 final : public TargetInfo { 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 @@ -36,9 +44,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; @@ -48,35 +63,73 @@ 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_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; @@ -84,73 +137,148 @@ RelExpr SPARCV9::getRelExpr(RelType type, const Symbol &s, } } +RelType SPARCV9::getDynRel(RelType type) const { + if (type == symbolicRel) + 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: @@ -159,21 +287,90 @@ 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 + 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 a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index e8acdbefa32bb..b113e7e5d58ab 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1247,9 +1247,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 a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 52c472bb89caf..1120439733824 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -806,6 +806,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 a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 277acb26987bc..be2c5f2a62ac3 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -884,12 +884,21 @@ static void addRelativeReloc(Ctx &ctx, InputSectionBase &isec, template static void addPltEntry(Ctx &ctx, PltSection &plt, GotPltSection &gotPlt, RelocationBaseSection &rel, RelType type, Symbol &sym) { - plt.addEntry(sym); - gotPlt.addEntry(sym); - rel.addReloc({type, &gotPlt, sym.getGotPltOffset(ctx), - sym.isPreemptible ? DynamicReloc::AgainstSymbol - : DynamicReloc::AddendOnlyWithTargetVA, - sym, 0, R_ABS}); + DynamicReloc::Kind reloc = sym.isPreemptible + ? DynamicReloc::AgainstSymbol + : DynamicReloc::AddendOnlyWithTargetVA; + + if (ctx.target->usesGotPlt) { + plt.addEntry(sym); + gotPlt.addEntry(sym); + // The relocation is applied to the .got.plt entry. + rel.addReloc( + {type, &gotPlt, sym.getGotPltOffset(ctx), reloc, sym, 0, R_ABS}); + } else { + plt.addEntry(sym); + // The relocation is applied to the .plt entry. + rel.addReloc({type, &plt, sym.getPltOffset(ctx), reloc, sym, 0, R_ABS}); + } } void elf::addGotEntry(Ctx &ctx, Symbol &sym) { @@ -1053,25 +1062,32 @@ void RelocationScanner::processAux(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); } } @@ -1382,12 +1398,13 @@ unsigned RelocationScanner::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; @@ -2492,11 +2509,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) { @@ -2510,7 +2527,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 a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h index d2a77bc953109..a166af8f8c1d9 100644 --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -58,6 +58,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, @@ -160,8 +161,8 @@ void reportUndefinedSymbols(Ctx &); 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); class ThunkSection; class Thunk; diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index fe7ba370c9f5d..e64237a250a7a 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -174,6 +174,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 a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index 64f2f6eaa8d09..9a3e4da3ba565 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -204,6 +204,7 @@ class Symbol { 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 a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 2531227cb99b7..64f6f435d8a6e 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1499,6 +1499,7 @@ DynamicSection::computeContents() { addInt(DT_RISCV_VARIANT_CC, 0); [[fallthrough]]; default: + assert(ctx.target->usesGotPlt); addInSec(DT_PLTGOT, *ctx.in.gotPlt); break; } @@ -1727,9 +1728,14 @@ 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; + } } } @@ -2613,8 +2619,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) { @@ -4933,10 +4941,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 a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index c90ef8505aadd..26634ca8e9e98 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -150,6 +150,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; +} + void TargetInfo::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const { const unsigned bits = ctx.arg.is64 ? 64 : 32; uint64_t secAddr = sec.getOutputSection()->addr; diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index fd1e5d33c438a..cbfb2c9c192e1 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -120,7 +120,8 @@ class TargetInfo { 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; @@ -146,6 +147,8 @@ class TargetInfo { // 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 @@ -170,6 +173,8 @@ class TargetInfo { 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 a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index e2aebff20e174..cbe63038ba556 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -613,7 +613,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()) return ctx.arg.zNow; if (ctx.in.relroPadding && sec == ctx.in.relroPadding->getParent()) @@ -835,10 +835,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; } @@ -1514,9 +1518,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); @@ -1995,10 +1999,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});