Re: ld.so/sparc64: fix UA64 relocation mask selection and byte order
Kirill A. Korinsky <[email protected]>
| Newsgroups | gmane.os.openbsd.tech |
|---|---|
| Message-ID | <[email protected]> |
On Thu, 09 Jul 2026 17:24:32 +0200, Kirill A. Korinsky <[email protected]> wrote: > > On Thu, 09 Jul 2026 17:01:34 +0200, > Mark Kettenis <[email protected]> wrote: > > > > > Date: Thu, 09 Jul 2026 15:30:52 +0200 > > > From: Kirill A. Korinsky <[email protected]> > > > > > > On Thu, 09 Jul 2026 14:55:45 +0200, > > > Mark Kettenis <[email protected]> wrote: > > > > > > > > I think we do. These "unaligned" relocations might not work in a > > > > multi-threaded context as threads may observed a partially updated > > > > state. > > > > > > Make sense. This, actually, not that hard to change. > > > > > > Something like that should do it. > > > > And what about the UA32 and UA16 relocations? > > > > As far as I see the code of lld it do not allow UA32 and UA16 for dynamic reallocations. > Anyway, here a diff which I will include into my large clang commit to handle UA16, UA32 and UA64. This version with tests, because I still hope to upstream it. diff --git a/lld/ELF/Arch/SPARCV9.cpp b/lld/ELF/Arch/SPARCV9.cpp index 641bc1a67042..90442b774dfe 100644 --- a/lld/ELF/Arch/SPARCV9.cpp +++ b/lld/ELF/Arch/SPARCV9.cpp @@ -25,6 +25,8 @@ public: SPARCV9(Ctx &); RelExpr getRelExpr(RelType type, const Symbol &s, const uint8_t *loc) const override; + RelType getDynRel(RelType type) const override; + void finalizeDynamicReloc(DynamicReloc &rel) const override; void writeGotHeader(uint8_t *buf) const override; void writePlt(uint8_t *buf, const Symbol &sym, uint64_t pltEntryAddr) const override; @@ -59,7 +61,9 @@ SPARCV9::SPARCV9(Ctx &ctx) : TargetInfo(ctx) { RelExpr SPARCV9::getRelExpr(RelType type, const Symbol &s, const uint8_t *loc) const { switch (type) { + case R_SPARC_16: case R_SPARC_32: + case R_SPARC_UA16: case R_SPARC_UA32: case R_SPARC_64: case R_SPARC_UA64: @@ -75,6 +79,67 @@ RelExpr SPARCV9::getRelExpr(RelType type, const Symbol &s, } } +RelType SPARCV9::getDynRel(RelType type) const { + switch (type) { + case R_SPARC_16: + case R_SPARC_32: + case R_SPARC_64: + case R_SPARC_UA16: + case R_SPARC_UA32: + case R_SPARC_UA64: + return type; + default: + break; + } + return R_SPARC_NONE; +} + +static bool getSparcAbsRelocPair(RelType type, RelType &aligned, + RelType &unaligned, uint64_t &alignment) { + switch (type) { + case R_SPARC_16: + case R_SPARC_UA16: + aligned = R_SPARC_16; + unaligned = R_SPARC_UA16; + alignment = 2; + return true; + case R_SPARC_32: + case R_SPARC_UA32: + aligned = R_SPARC_32; + unaligned = R_SPARC_UA32; + alignment = 4; + return true; + case R_SPARC_64: + case R_SPARC_UA64: + aligned = R_SPARC_64; + unaligned = R_SPARC_UA64; + alignment = 8; + return true; + default: + return false; + } +} + +void SPARCV9::finalizeDynamicReloc(DynamicReloc &rel) const { + RelType aligned = R_SPARC_NONE, unaligned = R_SPARC_NONE; + uint64_t alignment = 1; + if (!getSparcAbsRelocPair(rel.type, aligned, unaligned, alignment)) + return; + + rel.type = rel.r_offset % alignment == 0 ? aligned : unaligned; + if (!rel.needsDynSymIndex() || rel.sym->isPreemptible) + return; + + if (rel.type == R_SPARC_64) { + rel.convertToRelative(relativeRel); + return; + } + + Err(ctx) << "relocation " << rel.type << " at offset " << rel.r_offset + << " against non-preemptible symbol " << rel.sym + << " cannot be converted to " << relativeRel; +} + template <class ELFT, class RelTy> void SPARCV9::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) { RelocScan rs(ctx, &sec); diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 0d45236e6d11..c76176db7842 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -991,10 +991,16 @@ void RelocScan::processAux(RelExpr expr, RelType type, uint64_t offset, (isa<EhInputSection>(sec) && ctx.arg.emachine != EM_MIPS)); if (canWrite) { RelType rel = ctx.target->getDynRel(type); + bool useRelative = + (rel == ctx.target->symbolicRel || + (ctx.arg.emachine == EM_AARCH64 && type == R_AARCH64_AUTH_ABS64)) && + !sym.isPreemptible; + if (ctx.arg.emachine == EM_SPARCV9 && + oneof<R_SPARC_16, R_SPARC_32, R_SPARC_64, R_SPARC_UA16, R_SPARC_UA32, + R_SPARC_UA64>(type)) + useRelative = false; if (oneof<R_GOT, RE_LOONGARCH_GOT>(expr) || - ((rel == ctx.target->symbolicRel || - (ctx.arg.emachine == EM_AARCH64 && type == R_AARCH64_AUTH_ABS64)) && - !sym.isPreemptible)) { + useRelative) { addRelativeReloc<true>(ctx, *sec, offset, sym, addend, expr, type); return; } diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 65d3cbbe63a7..b5432825a162 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -1527,6 +1527,7 @@ void RelocationBaseSection::finalizeContents() { void DynamicReloc::finalize(Ctx &ctx, SymbolTableBaseSection *symt) { r_offset = getOffset(); + ctx.target->finalizeDynamicReloc(*this); r_sym = getSymIndex(symt); addend = computeAddend(ctx); isFinal = true; // Catch errors diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 2b937558ea01..c95b54a347e9 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -440,6 +440,11 @@ public: uint64_t getOffset() const; uint32_t getSymIndex(SymbolTableBaseSection *symTab) const; bool needsDynSymIndex() const { return isAgainstSymbol; } + void convertToRelative(RelType relativeRel) { + type = relativeRel; + isAgainstSymbol = false; + expr = R_ABS; + } /// Computes the addend of the dynamic relocation. Note that this is not the /// same as the #addend member variable as it may also include the symbol diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index 199f76e3fe85..31bd38b1f156 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -22,6 +22,7 @@ namespace lld { namespace elf { class Defined; +class DynamicReloc; class InputFile; class Symbol; template <class RelTy> struct Relocs; @@ -37,6 +38,7 @@ public: virtual RelExpr getRelExpr(RelType type, const Symbol &s, const uint8_t *loc) const = 0; virtual RelType getDynRel(RelType type) const { return 0; } + virtual void finalizeDynamicReloc(DynamicReloc &rel) const {} virtual void writeGotPltHeader(uint8_t *buf) const {} virtual void writeGotHeader(uint8_t *buf) const {} virtual void writeGotPlt(uint8_t *buf, const Symbol &s) const {} diff --git a/lld/test/ELF/sparcv9-ua-dynrel.s b/lld/test/ELF/sparcv9-ua-dynrel.s new file mode 100644 index 000000000000..4f58f9585231 --- /dev/null +++ b/lld/test/ELF/sparcv9-ua-dynrel.s @@ -0,0 +1,80 @@ +# REQUIRES: sparc +# RUN: llvm-mc -filetype=obj -triple=sparcv9 %s -o %t.o +# RUN: ld.lld -shared %t.o -o %t.so +# RUN: llvm-readelf -r %t.so | FileCheck %s + +# RUN: llvm-mc -filetype=obj -triple=sparcv9 --defsym ERR=1 %s -o %t.err.o +# RUN: not ld.lld -shared %t.err.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR %s + +# CHECK: R_SPARC_RELATIVE +# CHECK: R_SPARC_16 {{.*}} external +# CHECK: R_SPARC_32 {{.*}} external +# CHECK: R_SPARC_64 {{.*}} external +# CHECK: R_SPARC_UA16 {{.*}} external +# CHECK: R_SPARC_UA32 {{.*}} external +# CHECK: R_SPARC_UA64 {{.*}} external + +# ERR-DAG: error: relocation R_SPARC_16 at offset {{[0-9]+}} against non-preemptible symbol local cannot be converted to R_SPARC_RELATIVE +# ERR-DAG: error: relocation R_SPARC_32 at offset {{[0-9]+}} against non-preemptible symbol local cannot be converted to R_SPARC_RELATIVE +# ERR-DAG: error: relocation R_SPARC_UA64 at offset {{[0-9]+}} against non-preemptible symbol local cannot be converted to R_SPARC_RELATIVE + +.data +.p2align 3 +aligned_local64: + .xword 0 + .reloc aligned_local64, R_SPARC_UA64, local + +.p2align 1 +aligned_external16: + .half 0 + .reloc aligned_external16, R_SPARC_UA16, external + +.p2align 2 +aligned_external32: + .word 0 + .reloc aligned_external32, R_SPARC_UA32, external + +.p2align 3 +aligned_external64: + .xword 0 + .reloc aligned_external64, R_SPARC_UA64, external + +.p2align 1 + .byte 0 +unaligned_external16: + .half 0 + .reloc unaligned_external16, R_SPARC_16, external + +.p2align 2 + .byte 0 +unaligned_external32: + .word 0 + .reloc unaligned_external32, R_SPARC_32, external + +.p2align 3 + .byte 0 +unaligned_external64: + .xword 0 + .reloc unaligned_external64, R_SPARC_64, external + +.ifdef ERR +.p2align 1 +aligned_local16: + .half 0 + .reloc aligned_local16, R_SPARC_UA16, local + +.p2align 2 +aligned_local32: + .word 0 + .reloc aligned_local32, R_SPARC_UA32, local + +.p2align 3 + .byte 0 +unaligned_local64: + .xword 0 + .reloc unaligned_local64, R_SPARC_64, local +.endif + +.hidden local +local: + .xword 0 -- wbr, Kirill