[lld] Enough LLD changes to bootstrap OpenBSD on sparc64 (PR #207609)
Kirill A. Korinsky via llvm-commits
llvm-commits at lists.llvm.org
Sun Aug 2 04:01:23 PDT 2026
https://github.com/catap updated https://github.com/llvm/llvm-project/pull/207609
>From a7d79ba943ef5e5f9de7f7d1a2570a59923511df Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill at korins.ky>
Date: Mon, 27 Jul 2026 12:08:53 +0200
Subject: [PATCH 1/2] [lld][ELF][SPARC] Canonicalize absolute dynamic
relocations
Co-authored-by: LemonBoy <thatlemon at gmail.com>
---
lld/ELF/Arch/SPARCV9.cpp | 60 +++++++++++++++++++++++-
lld/ELF/Relocations.cpp | 17 +++++--
lld/ELF/SyntheticSections.cpp | 1 +
lld/ELF/SyntheticSections.h | 5 ++
lld/ELF/Target.h | 2 +
lld/test/ELF/sparcv9-abs-pic.s | 8 ++--
lld/test/ELF/sparcv9-ua-dynrel.s | 80 ++++++++++++++++++++++++++++++++
7 files changed, 164 insertions(+), 9 deletions(-)
create mode 100644 lld/test/ELF/sparcv9-ua-dynrel.s
diff --git a/lld/ELF/Arch/SPARCV9.cpp b/lld/ELF/Arch/SPARCV9.cpp
index 7797990571def..eb948cbd366fe 100644
--- a/lld/ELF/Arch/SPARCV9.cpp
+++ b/lld/ELF/Arch/SPARCV9.cpp
@@ -27,6 +27,7 @@ class SPARCV9 final : public TargetInfo {
const uint8_t *loc) const override;
RelType getDynRel(RelType type) const override;
int64_t getImplicitAddend(const uint8_t *buf, 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;
@@ -83,8 +84,17 @@ RelExpr SPARCV9::getRelExpr(RelType type, const Symbol &s,
}
RelType SPARCV9::getDynRel(RelType type) const {
- if (type == R_SPARC_64)
+ 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;
}
@@ -92,6 +102,7 @@ int64_t SPARCV9::getImplicitAddend(const uint8_t *buf, RelType type) const {
switch (type) {
case R_SPARC_64:
case R_SPARC_GLOB_DAT:
+ case R_SPARC_RELATIVE:
return read64be(buf);
default:
InternalErr(ctx, buf) << "cannot read addend for relocation " << type;
@@ -99,6 +110,52 @@ int64_t SPARCV9::getImplicitAddend(const uint8_t *buf, RelType type) const {
}
}
+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,
unsigned shard) {
@@ -311,6 +368,7 @@ void SPARCV9::relocate(uint8_t *loc, const Relocation &rel,
write32be(loc, (read32be(loc) & ~0x000003ff) | (val & 0x000003ff));
break;
case R_SPARC_64:
+ case R_SPARC_RELATIVE:
case R_SPARC_DISP64:
case R_SPARC_UA64:
// V-xword64
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 4addf28bbffac..9c707dfa2e51f 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -995,10 +995,17 @@ 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);
- if (oneof<R_GOT, RE_LOONGARCH_GOT>(expr) ||
- ((rel == ctx.target->symbolicRel ||
- (ctx.arg.emachine == EM_AARCH64 && type == R_AARCH64_AUTH_ABS64)) &&
- !sym.isPreemptible)) {
+ bool useRelative =
+ (rel == ctx.target->symbolicRel ||
+ (ctx.arg.emachine == EM_AARCH64 && type == R_AARCH64_AUTH_ABS64)) &&
+ !sym.isPreemptible;
+ bool isSparcAbsReloc =
+ ctx.arg.emachine == EM_SPARCV9 &&
+ (type == R_SPARC_16 || type == R_SPARC_32 || type == R_SPARC_64 ||
+ type == R_SPARC_UA16 || type == R_SPARC_UA32 || type == R_SPARC_UA64);
+ if (isSparcAbsReloc)
+ useRelative = false;
+ if (oneof<R_GOT, RE_LOONGARCH_GOT>(expr) || useRelative) {
addRelativeReloc<true>(ctx, *sec, offset, sym, addend, expr, type, shard);
return;
}
@@ -1024,6 +1031,8 @@ void RelocScan::processAux(RelExpr expr, RelType type, uint64_t offset,
}
}
ctx.in.relaDyn->addSymbolReloc(rel, *sec, offset, sym, addend, type);
+ if (isSparcAbsReloc && !sym.isPreemptible && ctx.arg.writeAddends)
+ sec->addReloc({expr, type, offset, addend, &sym});
// MIPS ABI turns using of GOT and dynamic relocations inside out.
// While regular ABI uses dynamic relocations to fill up GOT entries
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 6bac881446fd0..60a89dff2a22b 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -1534,6 +1534,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 19d4461348f3f..57820525a7c78 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -439,6 +439,11 @@ class DynamicReloc {
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 174e389db155d..3224c02c52e5f 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 @@ class TargetInfo {
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-abs-pic.s b/lld/test/ELF/sparcv9-abs-pic.s
index 7513fcb8ecee6..4e0186b530af4 100644
--- a/lld/test/ELF/sparcv9-abs-pic.s
+++ b/lld/test/ELF/sparcv9-abs-pic.s
@@ -9,15 +9,15 @@
## R_SPARC_64 is an absolute relocation type.
## In PIC mode, it creates a relative relocation if the symbol is non-preemptable.
-# NM: 0000000000300350 d b
+# NM: 0000000000300340 d b
# RELOC: .rela.dyn {
-# RELOC-NEXT: 0x300350 R_SPARC_RELATIVE - 0x300350
-# RELOC-NEXT: 0x300348 R_SPARC_64 a 0x0
+# RELOC-NEXT: 0x300340 R_SPARC_RELATIVE - 0x300340
+# RELOC-NEXT: 0x300338 R_SPARC_64 a 0x0
# RELOC-NEXT: }
# HEX: Contents of section .data:
-# HEX-NEXT: 300348 00000000 00000000 00000000 00300350
+# HEX-NEXT: 300338 00000000 00000000 00000000 00300340
.globl a, b
.hidden b
diff --git a/lld/test/ELF/sparcv9-ua-dynrel.s b/lld/test/ELF/sparcv9-ua-dynrel.s
new file mode 100644
index 0000000000000..4f58f95852312
--- /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
>From 450c7ba7a6beaf1ec264523fa2d7563b47fe9bce Mon Sep 17 00:00:00 2001
From: "Kirill A. Korinsky" <kirill at korins.ky>
Date: Mon, 27 Jul 2026 12:09:31 +0200
Subject: [PATCH 2/2] [lld][ELF][SPARC] Support large PLTs
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.
---
lld/ELF/Arch/SPARCV9.cpp | 73 +++++++++++++++++++++++-
lld/ELF/Symbols.cpp | 2 +-
lld/ELF/SyntheticSections.cpp | 16 +++---
lld/ELF/Target.h | 5 ++
lld/ELF/Writer.cpp | 10 +++-
lld/test/ELF/Inputs/sparcv9-large-plt.py | 6 ++
lld/test/ELF/sparcv9-large-plt.s | 11 ++++
lld/test/ELF/sparcv9-plt.s | 30 +++++-----
8 files changed, 123 insertions(+), 30 deletions(-)
create mode 100644 lld/test/ELF/Inputs/sparcv9-large-plt.py
create mode 100644 lld/test/ELF/sparcv9-large-plt.s
diff --git a/lld/ELF/Arch/SPARCV9.cpp b/lld/ELF/Arch/SPARCV9.cpp
index eb948cbd366fe..2270673af82a8 100644
--- a/lld/ELF/Arch/SPARCV9.cpp
+++ b/lld/ELF/Arch/SPARCV9.cpp
@@ -11,6 +11,8 @@
#include "SyntheticSections.h"
#include "Target.h"
#include "llvm/Support/Endian.h"
+#include <algorithm>
+#include <cassert>
using namespace llvm;
using namespace llvm::object;
@@ -20,6 +22,13 @@ using namespace lld;
using namespace lld::elf;
namespace {
+constexpr uint32_t firstLargePltIndex = 32768 - 4;
+constexpr uint32_t pltLargeEntriesPerBlock = 160;
+constexpr uint32_t pltLargeCodeSize = 24;
+constexpr uint32_t pltLargePointerSize = 8;
+constexpr uint32_t pltLargeBlockSize =
+ pltLargeEntriesPerBlock * (pltLargeCodeSize + pltLargePointerSize);
+
class SPARCV9 final : public TargetInfo {
public:
SPARCV9(Ctx &);
@@ -29,8 +38,11 @@ class SPARCV9 final : public TargetInfo {
int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;
void finalizeDynamicReloc(DynamicReloc &rel) const override;
void writeGotHeader(uint8_t *buf) const override;
+ uint64_t getPltEntryOffset(uint32_t pltIdx,
+ uint64_t headerSize) const override;
void writePlt(uint8_t *buf, const Symbol &sym,
uint64_t pltEntryAddr) const override;
+ void finalizePlt(uint8_t *buf) const override;
template <class ELFT, class RelTy>
void scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels,
unsigned shard);
@@ -39,6 +51,9 @@ class SPARCV9 final : public TargetInfo {
}
void relocate(uint8_t *loc, const Relocation &rel,
uint64_t val) const override;
+
+private:
+ uint64_t getLargePltPointerOffset(uint32_t pltIdx) const;
};
} // namespace
@@ -137,6 +152,15 @@ static bool getSparcAbsRelocPair(RelType type, RelType &aligned,
}
void SPARCV9::finalizeDynamicReloc(DynamicReloc &rel) const {
+ if (rel.type == R_SPARC_JMP_SLOT && rel.inputSec == ctx.in.plt.get()) {
+ uint32_t pltIdx = rel.sym->getPltIdx(ctx);
+ if (pltIdx >= firstLargePltIndex) {
+ uint64_t off = getPltEntryOffset(pltIdx, ctx.in.plt->headerSize);
+ rel.r_offset = ctx.in.plt->getVA() + getLargePltPointerOffset(pltIdx);
+ rel.addend = -static_cast<int64_t>(ctx.in.plt->getVA() + off + 4);
+ }
+ }
+
RelType aligned = R_SPARC_NONE, unaligned = R_SPARC_NONE;
uint64_t alignment = 1;
if (!getSparcAbsRelocPair(rel.type, aligned, unaligned, alignment))
@@ -462,8 +486,47 @@ void SPARCV9::writeGotHeader(uint8_t *buf) const {
write64be(buf, ctx.in.dynamic->getVA());
}
-void SPARCV9::writePlt(uint8_t *buf, const Symbol & /*sym*/,
+uint64_t SPARCV9::getPltEntryOffset(uint32_t pltIdx,
+ uint64_t headerSize) const {
+ if (pltIdx < firstLargePltIndex)
+ return headerSize + uint64_t{pltIdx} * pltEntrySize;
+
+ uint32_t largeIdx = pltIdx - firstLargePltIndex;
+ return headerSize + uint64_t{firstLargePltIndex} * pltEntrySize +
+ largeIdx / pltLargeEntriesPerBlock * pltLargeBlockSize +
+ largeIdx % pltLargeEntriesPerBlock * pltLargeCodeSize;
+}
+
+uint64_t SPARCV9::getLargePltPointerOffset(uint32_t pltIdx) const {
+ assert(pltIdx >= firstLargePltIndex);
+ uint32_t largeIdx = pltIdx - firstLargePltIndex;
+ uint32_t entriesBeforeBlock =
+ largeIdx / pltLargeEntriesPerBlock * pltLargeEntriesPerBlock;
+ uint32_t indexInBlock = largeIdx % pltLargeEntriesPerBlock;
+ uint64_t largeEntries = ctx.in.plt->getNumEntries() - firstLargePltIndex;
+ uint64_t entriesInBlock = std::min<uint64_t>(
+ pltLargeEntriesPerBlock, largeEntries - entriesBeforeBlock);
+ uint64_t blockOffset = getPltEntryOffset(
+ firstLargePltIndex + entriesBeforeBlock, ctx.in.plt->headerSize);
+
+ return blockOffset + entriesInBlock * pltLargeCodeSize +
+ indexInBlock * pltLargePointerSize;
+}
+
+void SPARCV9::writePlt(uint8_t *buf, const Symbol &sym,
uint64_t pltEntryAddr) const {
+ uint64_t off = pltEntryAddr - ctx.in.plt->getVA();
+ if (sym.getPltIdx(ctx) >= firstLargePltIndex) {
+ uint64_t ptrOff = getLargePltPointerOffset(sym.getPltIdx(ctx));
+ write32be(buf, 0x8a10000f);
+ write32be(buf + 4, 0x40000002);
+ write32be(buf + 8, 0x01000000);
+ write32be(buf + 12, 0xc25be000 | ((ptrOff - (off + 4)) & 0x1fff));
+ write32be(buf + 16, 0x83c3c001);
+ write32be(buf + 20, 0x9e100005);
+ return;
+ }
+
const uint8_t pltData[] = {
0x03, 0x00, 0x00, 0x00, // sethi (. - .PLT0), %g1
0x30, 0x68, 0x00, 0x00, // ba,a %xcc, .PLT1
@@ -476,9 +539,15 @@ void SPARCV9::writePlt(uint8_t *buf, const Symbol & /*sym*/,
};
memcpy(buf, pltData, sizeof(pltData));
- uint64_t off = pltEntryAddr - ctx.in.plt->getVA();
relocateNoSym(buf, R_SPARC_22, off);
relocateNoSym(buf + 4, R_SPARC_WDISP19, -(off + 4 - pltEntrySize));
}
+void SPARCV9::finalizePlt(uint8_t *buf) const {
+ for (uint32_t i = firstLargePltIndex; i < ctx.in.plt->getNumEntries(); ++i) {
+ uint64_t off = getPltEntryOffset(i, ctx.in.plt->headerSize);
+ write64be(buf + getLargePltPointerOffset(i), -(off + 4));
+ }
+}
+
void elf::setSPARCV9TargetInfo(Ctx &ctx) { ctx.target.reset(new SPARCV9(ctx)); }
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index 951041466cec5..d8beac37130a1 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -185,7 +185,7 @@ uint64_t Symbol::getGotPltOffset(Ctx &ctx) const {
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;
+ return ctx.target->getPltEntryOffset(getPltIdx(ctx), ctx.in.plt->headerSize);
}
uint64_t Symbol::getPltVA(Ctx &ctx) const {
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 60a89dff2a22b..5772a4a38c0c9 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -2429,20 +2429,21 @@ 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) {
// At beginning of PLT, we have code to call the dynamic
// linker to resolve dynsyms at runtime. Write such code.
ctx.target->writePltHeader(buf);
- size_t off = headerSize;
-
for (const Symbol *sym : entries) {
+ size_t off = sym->getPltOffset(ctx);
ctx.target->writePlt(buf + off, *sym, getVA() + off);
- off += ctx.target->pltEntrySize;
}
+ ctx.target->finalizePlt(buf);
}
void PltSection::addEntry(Symbol &sym) {
@@ -2465,11 +2466,8 @@ bool PltSection::isNeeded() const {
void PltSection::addSymbols() {
ctx.target->addPltHeaderSymbols(*this);
- size_t off = headerSize;
- for (size_t i = 0; i < entries.size(); ++i) {
- ctx.target->addPltSymbols(*this, off);
- off += ctx.target->pltEntrySize;
- }
+ for (const Symbol *sym : entries)
+ ctx.target->addPltSymbols(*this, sym->getPltOffset(ctx));
}
IpltSection::IpltSection(Ctx &ctx)
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index 3224c02c52e5f..4a9bbb3053735 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -50,8 +50,13 @@ class TargetInfo {
// they are called. This function writes that code.
virtual void writePltHeader(uint8_t *buf) const {}
+ virtual uint64_t getPltEntryOffset(uint32_t pltIdx,
+ uint64_t headerSize) const {
+ return headerSize + uint64_t{pltIdx} * pltEntrySize;
+ }
virtual void writePlt(uint8_t *buf, const Symbol &sym,
uint64_t pltEntryAddr) const {}
+ virtual void finalizePlt(uint8_t *buf) const {}
virtual void writeIplt(uint8_t *buf, const Symbol &sym,
uint64_t pltEntryAddr) const {
// All but PPC32 and PPC64 use the same format for .plt and .iplt entries.
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 8cf88cd99cf8a..1a685bae1e3f6 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -602,7 +602,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())
@@ -844,10 +844,14 @@ template <class ELFT> void Writer<ELFT>::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<InputSection>(ctx.in.mipsGot.get())
: cast<InputSection>(ctx.in.got.get());
+ }
ctx.sym.globalOffsetTable->section = sec;
}
diff --git a/lld/test/ELF/Inputs/sparcv9-large-plt.py b/lld/test/ELF/Inputs/sparcv9-large-plt.py
new file mode 100644
index 0000000000000..84f74af5e96e4
--- /dev/null
+++ b/lld/test/ELF/Inputs/sparcv9-large-plt.py
@@ -0,0 +1,6 @@
+import sys
+
+count = int(sys.argv[1])
+for i in range(count):
+ print(f"call foo{i}")
+ print(" nop")
diff --git a/lld/test/ELF/sparcv9-large-plt.s b/lld/test/ELF/sparcv9-large-plt.s
new file mode 100644
index 0000000000000..97d1822d30ace
--- /dev/null
+++ b/lld/test/ELF/sparcv9-large-plt.s
@@ -0,0 +1,11 @@
+# REQUIRES: sparc
+# RUN: %python %S/Inputs/sparcv9-large-plt.py 32766 > %t.s
+# RUN: llvm-mc --position-independent -filetype=obj -triple=sparcv9 %t.s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-readelf -SW -r %t.so | FileCheck %s
+
+# CHECK-NOT: .got.plt
+# CHECK: .plt PROGBITS [[#%x,PLT:]] {{[0-9a-f]+}} 100040
+# CHECK-NOT: .got.plt
+# CHECK: [[#%x,PLT + 0x100030]] {{.*}} R_SPARC_JMP_SLOT {{.*}} foo32764
+# CHECK: [[#%x,PLT + 0x100038]] {{.*}} R_SPARC_JMP_SLOT {{.*}} foo32765
diff --git a/lld/test/ELF/sparcv9-plt.s b/lld/test/ELF/sparcv9-plt.s
index b63c57a6574fa..4f1616aa20892 100644
--- a/lld/test/ELF/sparcv9-plt.s
+++ b/lld/test/ELF/sparcv9-plt.s
@@ -11,38 +11,38 @@
## so .plt is writable and DT_PLTGOT points at it, and .rela.plt names .plt in
## its sh_info.
# CHECK: [ 5] .rela.plt RELA {{[0-9a-f]+}} {{[0-9a-f]+}} 000048 18 AI 1 7 8
-# CHECK: [ 7] .plt PROGBITS 0000000000300320 {{[0-9a-f]+}} 0000e0 00 WAX
-# CHECK: (PLTGOT) 0x300320
+# CHECK: [ 7] .plt PROGBITS 0000000000300400 {{[0-9a-f]+}} 0000e0 00 WAX 0 0 256
+# CHECK: (PLTGOT) 0x300400
## R_SPARC_JMP_SLOT applies to the PLT entry rather than to a .got.plt slot.
# CHECK: Relocation section '.rela.plt' {{.*}} contains 3 entries:
-# CHECK: 00000000003003a0 {{.*}} R_SPARC_JMP_SLOT {{.*}} weak + 0
-# CHECK-NEXT: 00000000003003c0 {{.*}} R_SPARC_JMP_SLOT {{.*}} bar + 0
-# CHECK-NEXT: 00000000003003e0 {{.*}} R_SPARC_JMP_SLOT {{.*}} foo + 0
+# CHECK: 0000000000300480 {{.*}} R_SPARC_JMP_SLOT {{.*}} weak + 0
+# CHECK-NEXT: 00000000003004a0 {{.*}} R_SPARC_JMP_SLOT {{.*}} bar + 0
+# CHECK-NEXT: 00000000003004c0 {{.*}} R_SPARC_JMP_SLOT {{.*}} foo + 0
# CHECK: 0000000000000000 0 FUNC WEAK DEFAULT UND weak
# CHECK-NEXT: 0000000000000000 0 FUNC GLOBAL DEFAULT UND bar
-# CHECK-NEXT: 00000000003003e0 0 FUNC GLOBAL DEFAULT UND foo
+# CHECK-NEXT: 00000000003004c0 0 FUNC GLOBAL DEFAULT UND foo
# DIS: <_start>:
-# DIS-NEXT: call 0x3003c0
+# DIS-NEXT: call 0x3004a0
# DIS-NEXT: nop
-# DIS-NEXT: call 0x3003a0
+# DIS-NEXT: call 0x300480
# DIS-NEXT: nop
## The four reserved entries are left zeroed, as GNU ld leaves them. The
## dynamic linker writes the resolver code into .PLT0 and .PLT1 at startup.
-# DIS: 0000000000300320 <.plt>:
+# DIS: 0000000000300400 <.plt>:
# DIS-COUNT-32: unimp 0
## Each entry puts its own offset from .plt into %g1 and branches to .PLT1,
## which the dynamic linker redirects to the resolver.
-# DIS-NEXT: 3003a0: 03 00 00 80 sethi 128, %g1
-# DIS-NEXT: 30 6f ff e7 ba,a %xcc, 0x300340
-# DIS: 3003c0: 03 00 00 a0 sethi 160, %g1
-# DIS-NEXT: 30 6f ff df ba,a %xcc, 0x300340
-# DIS: 3003e0: 03 00 00 c0 sethi 192, %g1
-# DIS-NEXT: 30 6f ff d7 ba,a %xcc, 0x300340
+# DIS-NEXT: 300480: 03 00 00 80 sethi 128, %g1
+# DIS-NEXT: 30 6f ff e7 ba,a %xcc, 0x300420
+# DIS: 3004a0: 03 00 00 a0 sethi 160, %g1
+# DIS-NEXT: 30 6f ff df ba,a %xcc, 0x300420
+# DIS: 3004c0: 03 00 00 c0 sethi 192, %g1
+# DIS-NEXT: 30 6f ff d7 ba,a %xcc, 0x300420
#--- a.s
.globl _start
More information about the llvm-commits
mailing list