-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[LLD][SPARC] Implement enough functionality to run non-trivial 64-bit programs #137919
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-lld-elf @llvm/pr-subscribers-lld Author: Alex Rønne Petersen (alexrp) ChangesTogether with #137915, this allows the Zig test suite to link and run for I haven't had time to write any tests for this yet, unfortunately. But the changes are straightforward enough that they should be reviewable at least, and as mentioned, real and non-trivial programs actually work with this. (Note: I've verified locally that LLD builds and passes all tests with this, but the build will fail for this PR due to a dependency on #137916 which adds Patch is 27.12 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/137919.diff 11 Files Affected:
diff --git a/lld/ELF/Arch/SPARCV9.cpp b/lld/ELF/Arch/SPARCV9.cpp
index b594b6677f3ad..0fbad791d89b7 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_MIPS_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 9d36071e1532f..18725a172f8fd 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -1247,9 +1247,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 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 <class PltSection, class GotPltSection>
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<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) {
@@ -2510,7 +2527,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 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<OutputSection *> outputSections);
+void tlsSymbolUpdate(Ctx &ctx);
+bool needsTLSSymbol(ArrayRef<OutputSection *> 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;
+ re...
[truncated]
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
(On a trip with limited computer access. Response may be delayed)
Tests are required to make this PR acceptable. You might git log lld/ELF/Arch/PPC.cpp/RISCV.cpp and check how I added initial tests for PPC and PIC RISCV. |
cc @koachan |
5dafba1
to
6fae4bb
Compare
0062bef
to
de511b1
Compare
… programs. This allows the Zig test suite to link and run for sparc64-linux, both with glibc and without any libc. This patch incorporates portions of the abandoned https://reviews.llvm.org/D102985 which I came across while working on this. Co-authored-by: LemonBoy <thatlemon@gmail.com>
Together with #137915, this allows the Zig test suite to link and run for
sparc64-linux
, both with glibc and without any libc. This patch incorporates portions of the abandoned https://reviews.llvm.org/D102985 which I came across while working on this. (Thanks @LemonBoy! I've added you as co-author.)I haven't had time to write any tests for this yet, unfortunately. But the changes are straightforward enough that they should be reviewable at least, and as mentioned, real and non-trivial programs actually work with this.