Enough LLD changes to bootstrap OpenBSD on sparc64#207609
Conversation
|
@llvm/pr-subscribers-lld-elf Author: Kirill A. Korinsky (catap) ChangesThis PR consumes #137919, adds my bits from https://github.com/catap/OpenBSD-src/tree/sparc64 which I had used to actually build OpenBSD by using LLVM toolchain. It also contains a bit of tests. I do not tried to build OpenBSD by exactly this branch, but it looks close enough and I had resolved only one conflicts which was introduced by 3be67c7 Patch is 31.03 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/207609.diff 18 Files Affected:
diff --git a/lld/ELF/Arch/SPARCV9.cpp b/lld/ELF/Arch/SPARCV9.cpp
index 405be69a8f572..1847fb295ab41 100644
--- a/lld/ELF/Arch/SPARCV9.cpp
+++ b/lld/ELF/Arch/SPARCV9.cpp
@@ -6,7 +6,9 @@
//
//===----------------------------------------------------------------------===//
+#include "InputFiles.h"
#include "RelocScan.h"
+#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
@@ -25,6 +27,8 @@ 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;
template <class ELFT, class RelTy>
@@ -34,6 +38,12 @@ class SPARCV9 final : public TargetInfo {
}
void relocate(uint8_t *loc, const Relocation &rel,
uint64_t val) const override;
+ void finalizeRelocScan() 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
@@ -42,9 +52,15 @@ 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;
@@ -72,6 +88,12 @@ 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;
+}
+
template <class ELFT, class RelTy>
void SPARCV9::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
RelocScan rs(ctx, &sec);
@@ -89,21 +111,33 @@ void SPARCV9::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
RelExpr expr;
switch (type) {
case R_SPARC_NONE:
+ 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:
continue;
// Absolute relocations:
+ 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:
expr = R_ABS;
break;
@@ -111,20 +145,38 @@ void SPARCV9::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
case R_SPARC_WPLT30:
rs.processR_PLT_PC(type, offset, addend, sym);
continue;
+ case R_SPARC_TLS_GD_CALL:
+ case R_SPARC_TLS_LDM_CALL:
+ sec.addReloc({R_PLT_PC, type, offset, addend, &sym});
+ continue;
// PC-relative relocations:
- 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:
rs.processR_PC(type, offset, addend, sym);
continue;
// GOT relocations:
case R_SPARC_GOT10:
+ 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:
expr = R_GOT_OFF;
break;
+ case R_SPARC_GOTDATA_HIX22:
+ case R_SPARC_GOTDATA_LOX10:
+ expr = R_GOTREL;
+ break;
// TLS LE relocations:
case R_SPARC_TLS_LE_HIX22:
@@ -133,6 +185,25 @@ void SPARCV9::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
continue;
expr = R_TPREL;
break;
+ case R_SPARC_TLS_GD_HI22:
+ case R_SPARC_TLS_GD_LO10:
+ sym.setFlags(NEEDS_TLSGD);
+ sec.addReloc({R_TLSGD_GOT, type, offset, addend, &sym});
+ continue;
+ case R_SPARC_TLS_LDM_HI22:
+ case R_SPARC_TLS_LDM_LO10:
+ ctx.needsTlsLd.store(true, std::memory_order_relaxed);
+ sec.addReloc({R_TLSLD_GOT, type, offset, addend, &sym});
+ continue;
+ case R_SPARC_TLS_LDO_HIX22:
+ case R_SPARC_TLS_LDO_LOX10:
+ expr = R_DTPREL;
+ break;
+ case R_SPARC_TLS_IE_HI22:
+ case R_SPARC_TLS_IE_LO10:
+ sym.setFlags(NEEDS_TLSIE);
+ sec.addReloc({R_GOT, type, offset, addend, &sym});
+ continue;
default:
Err(ctx) << getErrorLoc(ctx, sec.content().data() + offset)
@@ -146,71 +217,139 @@ void SPARCV9::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
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_WDISP22:
+ // V-disp22
+ checkIntUInt(ctx, loc, val, 24, rel);
+ write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 2) & 0x003fffff));
+ break;
+ case R_SPARC_HI22:
+ // V-imm22
+ checkUInt(ctx, loc, val, 32, rel);
+ write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
+ break;
case R_SPARC_22:
// V-imm22
checkUInt(ctx, loc, val, 22, rel);
write32be(loc, (read32be(loc) & ~0x003fffff) | (val & 0x003fffff));
break;
+ 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:
+ 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_GOT22:
- case R_SPARC_PC22:
case R_SPARC_LM22:
+ case R_SPARC_TLS_GD_HI22:
+ case R_SPARC_TLS_LDM_HI22:
+ case R_SPARC_TLS_LDO_HIX22:
+ case R_SPARC_TLS_IE_HI22:
// T-imm22
write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
break;
- case R_SPARC_HI22:
- // V-imm22
- checkUInt(ctx, loc, val >> 10, 22, rel);
+ case R_SPARC_PC22:
+ // V-disp22
+ checkIntUInt(ctx, loc, val, 32, rel);
write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
break;
- case R_SPARC_WDISP19:
- // V-disp19
- checkInt(ctx, loc, val, 21, rel);
- write32be(loc, (read32be(loc) & ~0x0007ffff) | ((val >> 2) & 0x0007ffff));
- break;
- case R_SPARC_GOT10:
- case R_SPARC_PC10:
- // T-simm10
- write32be(loc, (read32be(loc) & ~0x000003ff) | (val & 0x000003ff));
- break;
- case R_SPARC_LO10:
- // T-simm13
- write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff));
- 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:
+ case R_SPARC_GOTDATA_LOX10:
+ case R_SPARC_GOTDATA_OP_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:
@@ -219,21 +358,110 @@ 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_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:
break;
case R_SPARC_TLS_LE_HIX22:
// T-imm22
write32be(loc, (read32be(loc) & ~0x003fffff) | ((~val >> 10) & 0x003fffff));
break;
- case R_SPARC_TLS_LE_LOX10:
+ case R_SPARC_TLS_LDO_LOX10:
// T-simm13
- write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff) | 0x1C00);
+ write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff));
+ break;
+ 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:
+ // T-imm22
+ write32be(loc, (read32be(loc) & ~0x003fffff) |
+ ((((int64_t)val < 0 ? ~val : val) >> 10) & 0x003fffff));
+ break;
+ case R_SPARC_GOTDATA_OP:
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:
+ // 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:
+ // 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 {
+ write64be(buf, ctx.in.dynamic->getVA());
+}
+
+static bool isTlsCall(RelType type) {
+ return type == R_SPARC_TLS_GD_CALL || type == R_SPARC_TLS_LDM_CALL;
+}
+
+void SPARCV9::finalizeRelocScan() {
+ Symbol *tga = nullptr;
+
+ for (ELFFileBase *file : ctx.objectFiles) {
+ for (InputSectionBase *s : file->getSections()) {
+ auto *isec = dyn_cast_or_null<InputSection>(s);
+ if (!isec || !isec->isLive())
+ continue;
+ for (Relocation &rel : isec->relocs()) {
+ if (rel.expr != R_PLT_PC || !isTlsCall(rel.type))
+ continue;
+ if (!tga) {
+ tga = ctx.symtab->addSymbol(Undefined{ctx.internalFile,
+ "__tls_get_addr", STB_GLOBAL,
+ STV_DEFAULT, STT_FUNC});
+ tga->isUsedInRegularObj = true;
+ tga->isPreemptible = true;
+ tga->setFlags(NEEDS_PLT | USED);
+ }
+ rel.sym = tga;
+ }
+ }
+ }
+}
+
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 7ec7dfcae6bca..a2552a1ae1ab7 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -1318,9 +1318,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 c78800787d27e..c26425bbc4a7b 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -833,6 +833,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
case R_GOTPLTONLY_PC:
return ctx.in.gotPlt->getVA() + a - p;
case R_GOTREL:
+ 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 0d45236e6d11e..cd8d3634e9d33 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -145,7 +145,7 @@ bool lld::elf::needsGot(RelExpr expr) {
static bool isRelExpr(RelExpr expr) {
return oneof<R_PC, R_GOTREL, R_GOTPLTREL, RE_ARM_PCA, RE_MIPS_GOTREL,
RE_PPC64_CALL, RE_AARCH64_PAGE_PC, R_RELAX_GOT_PC,
- RE_RISCV_PC_INDIRECT, RE_LOONGARCH_PAGE_PC,
+ R_RELAX_GOT_OFF, RE_RISCV_PC_INDIRECT, RE_LOONGARCH_PAGE_PC,
RE_LOONGARCH_PC_INDIRECT>(expr);
}
@@ -747,14 +747,16 @@ 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
- rel.addReloc(
- {type, &gotPlt, sym.getGotPltOffset(ctx), false, sym, 0, R_ABS});
+ if (ctx.target->usesGotPlt) {
+ gotPlt.addEntry(sym);
+ rel.addReloc({type, &gotPlt, sym.getGotPltOffset(ctx), sym.isPreemptible,
+ sym, 0, expr});
+ } else {
+ rel.addReloc({type, &plt, sym.getPltOffset(ctx), sym.isPreemptible, sym, 0,
+ expr});
+ }
}
void elf::addGotEntry(Ctx &ctx, Symbol &sym) {
@@ -920,14 +922,19 @@ void RelocScan::process(RelExpr expr, RelType type, uint64_t offset,
// indirection.
const bool isIfunc = sym.isGnuIFunc();
if (!sym.isPreemptible && !isIfunc) {
- if (expr != R_GOT_PC) {
+ if (expr != R_GOT_PC && expr != R_GOT_OFF) {
expr = fromPlt(expr);
} else if (!isAbsoluteOrTls(sym)) {
- 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
+ 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);
}
}
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index abc62bf01a421..210ef5efb4a07 100644
--- a/lld/ELF/Relocations.h
+++ b/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,
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index 7bad4ceccec33..67e07b840cb82 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -181,6 +181,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 b7d0b13ae476c..0893776882dc6 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -198,6 +198,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 b9a42590dc8e7..aa5fabe9f9cbc 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -1523,14 +1523,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, SymbolTableBaseSect...
[truncated]
|
|
@llvm/pr-subscribers-lld Author: Kirill A. Korinsky (catap) ChangesThis PR consumes #137919, adds my bits from https://github.com/catap/OpenBSD-src/tree/sparc64 which I had used to actually build OpenBSD by using LLVM toolchain. It also contains a bit of tests. I do not tried to build OpenBSD by exactly this branch, but it looks close enough and I had resolved only one conflicts which was introduced by 3be67c7 Patch is 31.03 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/207609.diff 18 Files Affected:
diff --git a/lld/ELF/Arch/SPARCV9.cpp b/lld/ELF/Arch/SPARCV9.cpp
index 405be69a8f572..1847fb295ab41 100644
--- a/lld/ELF/Arch/SPARCV9.cpp
+++ b/lld/ELF/Arch/SPARCV9.cpp
@@ -6,7 +6,9 @@
//
//===----------------------------------------------------------------------===//
+#include "InputFiles.h"
#include "RelocScan.h"
+#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
@@ -25,6 +27,8 @@ 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;
template <class ELFT, class RelTy>
@@ -34,6 +38,12 @@ class SPARCV9 final : public TargetInfo {
}
void relocate(uint8_t *loc, const Relocation &rel,
uint64_t val) const override;
+ void finalizeRelocScan() 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
@@ -42,9 +52,15 @@ 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;
@@ -72,6 +88,12 @@ 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;
+}
+
template <class ELFT, class RelTy>
void SPARCV9::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
RelocScan rs(ctx, &sec);
@@ -89,21 +111,33 @@ void SPARCV9::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
RelExpr expr;
switch (type) {
case R_SPARC_NONE:
+ 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:
continue;
// Absolute relocations:
+ 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:
expr = R_ABS;
break;
@@ -111,20 +145,38 @@ void SPARCV9::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
case R_SPARC_WPLT30:
rs.processR_PLT_PC(type, offset, addend, sym);
continue;
+ case R_SPARC_TLS_GD_CALL:
+ case R_SPARC_TLS_LDM_CALL:
+ sec.addReloc({R_PLT_PC, type, offset, addend, &sym});
+ continue;
// PC-relative relocations:
- 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:
rs.processR_PC(type, offset, addend, sym);
continue;
// GOT relocations:
case R_SPARC_GOT10:
+ 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:
expr = R_GOT_OFF;
break;
+ case R_SPARC_GOTDATA_HIX22:
+ case R_SPARC_GOTDATA_LOX10:
+ expr = R_GOTREL;
+ break;
// TLS LE relocations:
case R_SPARC_TLS_LE_HIX22:
@@ -133,6 +185,25 @@ void SPARCV9::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
continue;
expr = R_TPREL;
break;
+ case R_SPARC_TLS_GD_HI22:
+ case R_SPARC_TLS_GD_LO10:
+ sym.setFlags(NEEDS_TLSGD);
+ sec.addReloc({R_TLSGD_GOT, type, offset, addend, &sym});
+ continue;
+ case R_SPARC_TLS_LDM_HI22:
+ case R_SPARC_TLS_LDM_LO10:
+ ctx.needsTlsLd.store(true, std::memory_order_relaxed);
+ sec.addReloc({R_TLSLD_GOT, type, offset, addend, &sym});
+ continue;
+ case R_SPARC_TLS_LDO_HIX22:
+ case R_SPARC_TLS_LDO_LOX10:
+ expr = R_DTPREL;
+ break;
+ case R_SPARC_TLS_IE_HI22:
+ case R_SPARC_TLS_IE_LO10:
+ sym.setFlags(NEEDS_TLSIE);
+ sec.addReloc({R_GOT, type, offset, addend, &sym});
+ continue;
default:
Err(ctx) << getErrorLoc(ctx, sec.content().data() + offset)
@@ -146,71 +217,139 @@ void SPARCV9::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
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_WDISP22:
+ // V-disp22
+ checkIntUInt(ctx, loc, val, 24, rel);
+ write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 2) & 0x003fffff));
+ break;
+ case R_SPARC_HI22:
+ // V-imm22
+ checkUInt(ctx, loc, val, 32, rel);
+ write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
+ break;
case R_SPARC_22:
// V-imm22
checkUInt(ctx, loc, val, 22, rel);
write32be(loc, (read32be(loc) & ~0x003fffff) | (val & 0x003fffff));
break;
+ 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:
+ 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_GOT22:
- case R_SPARC_PC22:
case R_SPARC_LM22:
+ case R_SPARC_TLS_GD_HI22:
+ case R_SPARC_TLS_LDM_HI22:
+ case R_SPARC_TLS_LDO_HIX22:
+ case R_SPARC_TLS_IE_HI22:
// T-imm22
write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
break;
- case R_SPARC_HI22:
- // V-imm22
- checkUInt(ctx, loc, val >> 10, 22, rel);
+ case R_SPARC_PC22:
+ // V-disp22
+ checkIntUInt(ctx, loc, val, 32, rel);
write32be(loc, (read32be(loc) & ~0x003fffff) | ((val >> 10) & 0x003fffff));
break;
- case R_SPARC_WDISP19:
- // V-disp19
- checkInt(ctx, loc, val, 21, rel);
- write32be(loc, (read32be(loc) & ~0x0007ffff) | ((val >> 2) & 0x0007ffff));
- break;
- case R_SPARC_GOT10:
- case R_SPARC_PC10:
- // T-simm10
- write32be(loc, (read32be(loc) & ~0x000003ff) | (val & 0x000003ff));
- break;
- case R_SPARC_LO10:
- // T-simm13
- write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff));
- 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:
+ case R_SPARC_GOTDATA_LOX10:
+ case R_SPARC_GOTDATA_OP_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:
@@ -219,21 +358,110 @@ 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_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:
break;
case R_SPARC_TLS_LE_HIX22:
// T-imm22
write32be(loc, (read32be(loc) & ~0x003fffff) | ((~val >> 10) & 0x003fffff));
break;
- case R_SPARC_TLS_LE_LOX10:
+ case R_SPARC_TLS_LDO_LOX10:
// T-simm13
- write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff) | 0x1C00);
+ write32be(loc, (read32be(loc) & ~0x00001fff) | (val & 0x000003ff));
+ break;
+ 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:
+ // T-imm22
+ write32be(loc, (read32be(loc) & ~0x003fffff) |
+ ((((int64_t)val < 0 ? ~val : val) >> 10) & 0x003fffff));
+ break;
+ case R_SPARC_GOTDATA_OP:
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:
+ // 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:
+ // 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 {
+ write64be(buf, ctx.in.dynamic->getVA());
+}
+
+static bool isTlsCall(RelType type) {
+ return type == R_SPARC_TLS_GD_CALL || type == R_SPARC_TLS_LDM_CALL;
+}
+
+void SPARCV9::finalizeRelocScan() {
+ Symbol *tga = nullptr;
+
+ for (ELFFileBase *file : ctx.objectFiles) {
+ for (InputSectionBase *s : file->getSections()) {
+ auto *isec = dyn_cast_or_null<InputSection>(s);
+ if (!isec || !isec->isLive())
+ continue;
+ for (Relocation &rel : isec->relocs()) {
+ if (rel.expr != R_PLT_PC || !isTlsCall(rel.type))
+ continue;
+ if (!tga) {
+ tga = ctx.symtab->addSymbol(Undefined{ctx.internalFile,
+ "__tls_get_addr", STB_GLOBAL,
+ STV_DEFAULT, STT_FUNC});
+ tga->isUsedInRegularObj = true;
+ tga->isPreemptible = true;
+ tga->setFlags(NEEDS_PLT | USED);
+ }
+ rel.sym = tga;
+ }
+ }
+ }
+}
+
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 7ec7dfcae6bca..a2552a1ae1ab7 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -1318,9 +1318,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 c78800787d27e..c26425bbc4a7b 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -833,6 +833,7 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
case R_GOTPLTONLY_PC:
return ctx.in.gotPlt->getVA() + a - p;
case R_GOTREL:
+ 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 0d45236e6d11e..cd8d3634e9d33 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -145,7 +145,7 @@ bool lld::elf::needsGot(RelExpr expr) {
static bool isRelExpr(RelExpr expr) {
return oneof<R_PC, R_GOTREL, R_GOTPLTREL, RE_ARM_PCA, RE_MIPS_GOTREL,
RE_PPC64_CALL, RE_AARCH64_PAGE_PC, R_RELAX_GOT_PC,
- RE_RISCV_PC_INDIRECT, RE_LOONGARCH_PAGE_PC,
+ R_RELAX_GOT_OFF, RE_RISCV_PC_INDIRECT, RE_LOONGARCH_PAGE_PC,
RE_LOONGARCH_PC_INDIRECT>(expr);
}
@@ -747,14 +747,16 @@ 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
- rel.addReloc(
- {type, &gotPlt, sym.getGotPltOffset(ctx), false, sym, 0, R_ABS});
+ if (ctx.target->usesGotPlt) {
+ gotPlt.addEntry(sym);
+ rel.addReloc({type, &gotPlt, sym.getGotPltOffset(ctx), sym.isPreemptible,
+ sym, 0, expr});
+ } else {
+ rel.addReloc({type, &plt, sym.getPltOffset(ctx), sym.isPreemptible, sym, 0,
+ expr});
+ }
}
void elf::addGotEntry(Ctx &ctx, Symbol &sym) {
@@ -920,14 +922,19 @@ void RelocScan::process(RelExpr expr, RelType type, uint64_t offset,
// indirection.
const bool isIfunc = sym.isGnuIFunc();
if (!sym.isPreemptible && !isIfunc) {
- if (expr != R_GOT_PC) {
+ if (expr != R_GOT_PC && expr != R_GOT_OFF) {
expr = fromPlt(expr);
} else if (!isAbsoluteOrTls(sym)) {
- 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
+ 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);
}
}
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index abc62bf01a421..210ef5efb4a07 100644
--- a/lld/ELF/Relocations.h
+++ b/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,
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index 7bad4ceccec33..67e07b840cb82 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -181,6 +181,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 b7d0b13ae476c..0893776882dc6 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -198,6 +198,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 b9a42590dc8e7..aa5fabe9f9cbc 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -1523,14 +1523,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, SymbolTableBaseSect...
[truncated]
|
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
|
The reason why I was in favour of splitting this up is that some of the changes are straightforward and can be landed quickly, but others are more invasive (or, skimming this patch, look incorrect, e.g. the GOT relaxation code looks odd to me, but I'd need to remind myself of the details first). Landing the simple stuff first cuts down on the size of the diff that keeps being reviewed/amended/etc. |
🪟 Windows x64 Test Results
✅ The build succeeded and all tests passed. |
🐧 Linux x64 Test Results
✅ The build succeeded and all tests passed. |
|
@jrtc27 probably, buthere a lot of changes and all of them, let say accumulated near a few places of code. Extracting them one-by-one will make rebase quite painful. |
daf0bff to
d122eb6
Compare
|
@jrtc27 I can try to create smaller commits if you think it can make review easy |
|
Here it is. I hope I haven't broke anything. We can discuss it and I'll cherry-pick agreed commits and rebase that branch. Not sure that I can make them smaller. |
|
It's not about the number of commits in the PR, it's about this being a single PR. In LLVM, 1 PR is 1 commit when merged (and the commit message is taken from the PR description), so anything that should be a separate commit that undergoes its own independent review needs to go in its own PR. See https://llvm.org/docs/GitHub.html. |
But is it really a rule that must be strictly enforced? I think it makes more sense to split up the changes and still land them with one commit. |
|
If it is going to be merged, I don't mind open 18 PR one by one, but I think it should be discussed and agreed before. |
There was a problem hiding this comment.
I don't mind combining multiple sparc64-related changes into a single commit, provided we ensure thorough test coverage.
When I added the initial ppc32 and riscv ports in 2019, I spent a lot of time curating a small but comprehensive set of tests. You should consolidate the abs-* tests into one file, and do the same for the plt-* tests. There are other test improvements that should be done - which is going to painful if you split this into multiple patches.
| # CHECK: R_SPARC_RELATIVE | ||
| # CHECK-NOT: R_SPARC_UA64 | ||
|
|
||
| # ERR: R_SPARC_UA64 relocation at offset {{[0-9]+}} against non-preemptible symbol local is not 8-byte aligned |
There was a problem hiding this comment.
All error message should include error: . See newly added negative tests
| (ctx.arg.andFeatures & GNU_PROPERTY_X86_FEATURE_1_IBT)) | ||
| name = ".plt.sec"; | ||
|
|
||
| // The PLT needs to be writable on SPARC as the dynamic linker will |
There was a problem hiding this comment.
I am surprised OpenBSD allows this. Will you introduce a Secure PLT ABI?
|
@MaskRay sorry, I used full diff to make this PR which includes OpenBSD specific things. A new version addressed all your remarks, and I have drop that PLT-related changes. |
292bacd to
4ca1593
Compare
It doesn't have to be literally perfect, but try to find / shake out what you can find from ports build. |
|
@brad0 so far the major issue in ports is lang/gcc/15, which I think I had addressed locally and I need some time to rebuild everything and test. After that beast is over, I'll re-reviwe all my local changes to verify which can be upstreamed and which is openbsd specific. Meanwhile, I had backported / extracted as separated and small PR a few bugfixes already, I think it is out of scope from this PR because it is LLD orinted: |
|
@brad0 here rebase and push with a few more bits: To be clear: this PR plus:
Is re-implemetation to current LLVM the code from https://github.com/catap/OpenBSD-src/tree/sparc64 without OpenBSD specific bits and which is llvm-22 based. I tested only OpenBSD specific branch and it actually allows me to build whole system with clang lld default toolchain, and a kernel which boots on sparc64 and it was retested on one more sparc64 machine. Resutled system builds gcc-15 and roughly half of ports collection is built by ingoing bulk. |
|
Ok, I think I had spoted one more missed bit. Here it is. |
ff57c13 to
0409073
Compare
| @@ -0,0 +1,33 @@ | |||
| # REQUIRES: x86 | |||
There was a problem hiding this comment.
This .eh_frame fix is generic and should be extracted
| EhFrameSection &eh = *ctx.in.ehFrame; | ||
| sec->parent = &eh; | ||
| eh.addralign = std::max(eh.addralign, sec->addralign); | ||
| eh.flags |= sec->flags & SHF_WRITE; |
There was a problem hiding this comment.
This is really backward. Can you change compilers to not use absolute FDE/personality encodings, allowing .eh_frame to be readonly (like every other arch)?
I don't think we want to take this.
There was a problem hiding this comment.
Hm, we currently do this for CHERI too, because we seal our return capabilities and therefore can't just do pointer arithmetic on them to get to a landing pad like you normally would with relative offsets. That is a bit ugly for various reasons though, not just requiring it to be relro rather than read-only, so we've talked about having a separate table of such capabilities that gets indexed by .eh_frame. But that's not what we do today. And to be honest, even if the input on non-CHERI is unnecessary, given it's little burden to support and is valid, should we not?
| symbols.push_back({b, strTabSec.addString(b->getName(), false)}); | ||
| } | ||
|
|
||
| void SymbolTableBaseSection::addLocalSectionSymbol(Symbol *b) { |
There was a problem hiding this comment.
I don't think we want to take support for the legacy local dynamic symbol (this and ctx.target->prepareDynamicReloc).
Every other 64-bit arch (aarch64,x86-64,riscv64, etc) doesn't allow sub-pointer-width absolute reloc that would have to become dynamic. You should fix your code instead.
Also, we really don't need one synthesized STT_SECTION dynamic symbol per output section needing dynamic relocs ( DenseMap<OutputSection *, Defined *> dynamicSectionSymbols;), just one shared STT_SECTION dynamic symbol.
|
@MaskRay dropped pointed commit. |
e9ab538 to
3307d97
Compare
|
Rebased and added one more piece which is heavy depeneded to this branch: support large PLTs. This issue was discovered by ongoing bulk build of openbsd ports. |
| @@ -0,0 +1,11 @@ | |||
| # REQUIRES: sparc | |||
There was a problem hiding this comment.
Unneeded as a separate file. I am folding this into sparcv9-reloc-got.s
| @@ -0,0 +1,67 @@ | |||
| # REQUIRES: sparc | |||
There was a problem hiding this comment.
Drop after rebase. I've split the tests into sparcv9-reloc-{,pc,range}.s
|
@MaskRay here it is. |
| @@ -0,0 +1,14 @@ | |||
| # REQUIRES: sparc | |||
There was a problem hiding this comment.
This is redundant - other tests check .rela.dyn
| // If the target adjusted the expression to an optimizable form, we may | ||
| // end up needing the GOT if we can't optimize everything. | ||
| if (expr == R_RELAX_GOT_PC || expr == R_RELAX_GOT_PC_NOPIC) | ||
| if (expr == R_GOT_PC) |
There was a problem hiding this comment.
I'll take over GOTDATA relocations. We can implement GOTDATA_OP without touching the generic code.
Co-authored-by: LemonBoy <thatlemon@gmail.com> Co-authored-by: Alex Rønne Petersen <alex@alexrp.com>
Co-authored-by: LemonBoy <thatlemon@gmail.com>
Co-authored-by: LemonBoy <thatlemon@gmail.com> Co-authored-by: Alex Rønne Petersen <alex@alexrp.com>
Co-authored-by: LemonBoy <thatlemon@gmail.com> Co-authored-by: Alex Rønne Petersen <alex@alexrp.com>
Co-authored-by: LemonBoy <thatlemon@gmail.com> Co-authored-by: Alex Rønne Petersen <alex@alexrp.com>
SPARC V9 switches to a block-based PLT layout after the first 32768 ABI entries. Emit its large entries and apply JMP_SLOT relocations directly to .plt. This avoids R_SPARC_WDISP19 overflow when a short PLT entry can no longer reach .PLT1.
|
@MaskRay here it is. |
This PR consumes #137919, adds my bits from https://github.com/catap/OpenBSD-src/tree/sparc64 which I had used to actually build OpenBSD by using LLVM toolchain.
It also contains a bit of tests.
I do not tried to build OpenBSD by exactly this branch, but it looks close enough and I had resolved only one conflicts which was introduced by 3be67c7