[lld] [lld] Add infrastructure for handling RISCV vendor-specific relocations. (PR #159987)
Owen Anderson via llvm-commits
llvm-commits at lists.llvm.org
Wed Oct 22 01:11:49 PDT 2025
https://github.com/resistor updated https://github.com/llvm/llvm-project/pull/159987
>From fc463150f39b476fa73da260f75825d8f3b5fe82 Mon Sep 17 00:00:00 2001
From: Owen Anderson <resistor at mac.com>
Date: Tue, 14 Oct 2025 23:43:20 +0900
Subject: [PATCH 1/5] [lld] Add infrastructure for handling RISCV
vendor-specific relocations.
---
lld/ELF/Arch/RISCV.cpp | 83 +++++++++++++++++++++++++++++
lld/test/riscv-vendor-relocations.s | 16 ++++++
2 files changed, 99 insertions(+)
create mode 100644 lld/test/riscv-vendor-relocations.s
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index dc2ab97e9d9be..f7d570adc8b77 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -8,6 +8,7 @@
#include "InputFiles.h"
#include "OutputSections.h"
+#include "RelocScan.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
@@ -38,6 +39,10 @@ class RISCV final : public TargetInfo {
void writePltHeader(uint8_t *buf) const override;
void writePlt(uint8_t *buf, const Symbol &sym,
uint64_t pltEntryAddr) const override;
+ template <class ELFT, class RelTy>
+ void scanSectionImpl(InputSectionBase &, Relocs<RelTy>);
+ template <class ELFT> void scanSection1(InputSectionBase &);
+ void scanSection(InputSectionBase &) override;
RelType getDynRel(RelType type) const override;
RelExpr getRelExpr(RelType type, const Symbol &s,
const uint8_t *loc) const override;
@@ -278,6 +283,7 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
const uint8_t *loc) const {
switch (type) {
case R_RISCV_NONE:
+ case R_RISCV_VENDOR:
return R_NONE;
case R_RISCV_32:
case R_RISCV_64:
@@ -1476,3 +1482,80 @@ void elf::mergeRISCVAttributesSections(Ctx &ctx) {
}
void elf::setRISCVTargetInfo(Ctx &ctx) { ctx.target.reset(new RISCV(ctx)); }
+
+class RISCVRelocScan : public RelocScan {
+public:
+ StringRef rvVendor;
+
+ RISCVRelocScan(Ctx &ctx, InputSectionBase *sec = nullptr)
+ : RelocScan(ctx, sec) {}
+ template <class ELFT, class RelTy>
+ void scan(typename Relocs<RelTy>::const_iterator &it, RelType type,
+ int64_t addend);
+};
+
+template <class ELFT, class RelTy>
+void RISCVRelocScan::scan(typename Relocs<RelTy>::const_iterator &it,
+ RelType type, int64_t addend) {
+ const RelTy &rel = *it;
+ uint32_t symIndex = rel.getSymbol(false);
+ Symbol &sym = sec->getFile<ELFT>()->getSymbol(symIndex);
+
+ if (type == R_RISCV_VENDOR) {
+ if (!rvVendor.empty())
+ Err(ctx) << "found consecutive R_RISCV_VENDOR relocations";
+ rvVendor = sym.getName();
+ return;
+ } else if (!rvVendor.empty()) {
+ Err(ctx) << getErrorLoc(ctx, sec->content().data() + it->r_offset)
+ << "unknown vendor-specific relocation (" << type.v
+ << ") in vendor namespace \"" << rvVendor << "\" against symbol "
+ << &sym;
+ return;
+ }
+
+ RelocScan::scan<ELFT, RelTy>(it, type, addend);
+}
+
+template <class ELFT, class RelTy>
+void RISCV::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
+ RISCVRelocScan rs(ctx, &sec);
+ // Many relocations end up in sec.relocations.
+ sec.relocations.reserve(rels.size());
+
+ // On SystemZ, all sections need to be sorted by r_offset, to allow TLS
+ // relaxation to be handled correctly - see SystemZ::getTlsGdRelaxSkip.
+ SmallVector<RelTy, 0> storage;
+ if (ctx.arg.emachine == EM_S390)
+ rels = sortRels(rels, storage);
+
+ for (auto it = rels.begin(); it != rels.end(); ++it) {
+ auto type = it->getType(false);
+ rs.scan<ELFT, RelTy>(it, type, rs.getAddend<ELFT>(*it, type));
+ }
+
+ // Sort relocations by offset for more efficient searching for
+ // R_RISCV_PCREL_HI20, ALIGN relocations, R_PPC64_ADDR64 and the
+ // branch-to-branch optimization.
+ if (is_contained({EM_RISCV, EM_LOONGARCH}, ctx.arg.emachine) ||
+ (ctx.arg.emachine == EM_PPC64 && sec.name == ".toc") ||
+ ctx.arg.branchToBranch)
+ llvm::stable_sort(sec.relocs(),
+ [](const Relocation &lhs, const Relocation &rhs) {
+ return lhs.offset < rhs.offset;
+ });
+}
+
+template <class ELFT> void RISCV::scanSection1(InputSectionBase &sec) {
+ const RelsOrRelas<ELFT> rels = sec.template relsOrRelas<ELFT>();
+ if (rels.areRelocsCrel())
+ scanSectionImpl<ELFT>(sec, rels.crels);
+ else if (rels.areRelocsRel())
+ scanSectionImpl<ELFT>(sec, rels.rels);
+ else
+ scanSectionImpl<ELFT>(sec, rels.relas);
+}
+
+void RISCV::scanSection(InputSectionBase &sec) {
+ invokeELFT(scanSection1, sec);
+}
diff --git a/lld/test/riscv-vendor-relocations.s b/lld/test/riscv-vendor-relocations.s
new file mode 100644
index 0000000000000..9358f48104ffe
--- /dev/null
+++ b/lld/test/riscv-vendor-relocations.s
@@ -0,0 +1,16 @@
+# RUN: llvm-mc -triple riscv32 %s -filetype=obj -o %t.o
+# RUN: not ld.lld -pie %t.o -o /dev/null 2>&1 | FileCheck %s
+
+ .option exact
+
+ .global TARGET
+TARGET:
+ nop
+
+.global INVALID_VENDOR
+.reloc 1f, R_RISCV_VENDOR, INVALID_VENDOR+0
+.reloc 1f, R_RISCV_CUSTOM255, TARGET
+1:
+ nop
+
+# CHECK: error: {{.*}} unknown vendor-specific relocation (255) in vendor namespace "INVALID_VENDOR" against symbol TARGET
\ No newline at end of file
>From 6a20ab874831cbbab868301dbaee38606251ad33 Mon Sep 17 00:00:00 2001
From: Owen Anderson <resistor at mac.com>
Date: Wed, 15 Oct 2025 20:59:49 +0900
Subject: [PATCH 2/5] Update for review feedback
---
lld/ELF/Arch/RISCV.cpp | 23 +++++++----------------
lld/test/riscv-vendor-relocations.s | 4 +++-
2 files changed, 10 insertions(+), 17 deletions(-)
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index f7d570adc8b77..40965a38e4856 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -1503,7 +1503,8 @@ void RISCVRelocScan::scan(typename Relocs<RelTy>::const_iterator &it,
if (type == R_RISCV_VENDOR) {
if (!rvVendor.empty())
- Err(ctx) << "found consecutive R_RISCV_VENDOR relocations";
+ Err(ctx) << getErrorLoc(ctx, sec->content().data() + it->r_offset)
+ << "malformed consecutive R_RISCV_VENDOR relocations";
rvVendor = sym.getName();
return;
} else if (!rvVendor.empty()) {
@@ -1511,6 +1512,7 @@ void RISCVRelocScan::scan(typename Relocs<RelTy>::const_iterator &it,
<< "unknown vendor-specific relocation (" << type.v
<< ") in vendor namespace \"" << rvVendor << "\" against symbol "
<< &sym;
+ rvVendor = "";
return;
}
@@ -1523,12 +1525,6 @@ void RISCV::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
// Many relocations end up in sec.relocations.
sec.relocations.reserve(rels.size());
- // On SystemZ, all sections need to be sorted by r_offset, to allow TLS
- // relaxation to be handled correctly - see SystemZ::getTlsGdRelaxSkip.
- SmallVector<RelTy, 0> storage;
- if (ctx.arg.emachine == EM_S390)
- rels = sortRels(rels, storage);
-
for (auto it = rels.begin(); it != rels.end(); ++it) {
auto type = it->getType(false);
rs.scan<ELFT, RelTy>(it, type, rs.getAddend<ELFT>(*it, type));
@@ -1537,21 +1533,16 @@ void RISCV::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
// Sort relocations by offset for more efficient searching for
// R_RISCV_PCREL_HI20, ALIGN relocations, R_PPC64_ADDR64 and the
// branch-to-branch optimization.
- if (is_contained({EM_RISCV, EM_LOONGARCH}, ctx.arg.emachine) ||
- (ctx.arg.emachine == EM_PPC64 && sec.name == ".toc") ||
- ctx.arg.branchToBranch)
- llvm::stable_sort(sec.relocs(),
- [](const Relocation &lhs, const Relocation &rhs) {
- return lhs.offset < rhs.offset;
- });
+ llvm::stable_sort(sec.relocs(),
+ [](const Relocation &lhs, const Relocation &rhs) {
+ return lhs.offset < rhs.offset;
+ });
}
template <class ELFT> void RISCV::scanSection1(InputSectionBase &sec) {
const RelsOrRelas<ELFT> rels = sec.template relsOrRelas<ELFT>();
if (rels.areRelocsCrel())
scanSectionImpl<ELFT>(sec, rels.crels);
- else if (rels.areRelocsRel())
- scanSectionImpl<ELFT>(sec, rels.rels);
else
scanSectionImpl<ELFT>(sec, rels.relas);
}
diff --git a/lld/test/riscv-vendor-relocations.s b/lld/test/riscv-vendor-relocations.s
index 9358f48104ffe..68a6364ed18b1 100644
--- a/lld/test/riscv-vendor-relocations.s
+++ b/lld/test/riscv-vendor-relocations.s
@@ -9,8 +9,10 @@ TARGET:
.global INVALID_VENDOR
.reloc 1f, R_RISCV_VENDOR, INVALID_VENDOR+0
+.reloc 1f, R_RISCV_VENDOR, INVALID_VENDOR+0
.reloc 1f, R_RISCV_CUSTOM255, TARGET
1:
nop
-# CHECK: error: {{.*}} unknown vendor-specific relocation (255) in vendor namespace "INVALID_VENDOR" against symbol TARGET
\ No newline at end of file
+# CHECK: error: {{.*}} malformed consecutive R_RISCV_VENDOR relocations
+# CHECK: error: {{.*}} unknown vendor-specific relocation (255) in vendor namespace "INVALID_VENDOR" against symbol TARGET
>From 1b6be66b7319fb919a1faf2fbd97187599a71086 Mon Sep 17 00:00:00 2001
From: Owen Anderson <resistor at mac.com>
Date: Thu, 16 Oct 2025 10:59:10 +0900
Subject: [PATCH 3/5] Update for review feedback.
---
lld/ELF/Arch/RISCV.cpp | 63 +++++++++++++++---------------------------
1 file changed, 23 insertions(+), 40 deletions(-)
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 40965a38e4856..6b226255e345b 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -1483,56 +1483,39 @@ void elf::mergeRISCVAttributesSections(Ctx &ctx) {
void elf::setRISCVTargetInfo(Ctx &ctx) { ctx.target.reset(new RISCV(ctx)); }
-class RISCVRelocScan : public RelocScan {
-public:
- StringRef rvVendor;
-
- RISCVRelocScan(Ctx &ctx, InputSectionBase *sec = nullptr)
- : RelocScan(ctx, sec) {}
- template <class ELFT, class RelTy>
- void scan(typename Relocs<RelTy>::const_iterator &it, RelType type,
- int64_t addend);
-};
-
-template <class ELFT, class RelTy>
-void RISCVRelocScan::scan(typename Relocs<RelTy>::const_iterator &it,
- RelType type, int64_t addend) {
- const RelTy &rel = *it;
- uint32_t symIndex = rel.getSymbol(false);
- Symbol &sym = sec->getFile<ELFT>()->getSymbol(symIndex);
-
- if (type == R_RISCV_VENDOR) {
- if (!rvVendor.empty())
- Err(ctx) << getErrorLoc(ctx, sec->content().data() + it->r_offset)
- << "malformed consecutive R_RISCV_VENDOR relocations";
- rvVendor = sym.getName();
- return;
- } else if (!rvVendor.empty()) {
- Err(ctx) << getErrorLoc(ctx, sec->content().data() + it->r_offset)
- << "unknown vendor-specific relocation (" << type.v
- << ") in vendor namespace \"" << rvVendor << "\" against symbol "
- << &sym;
- rvVendor = "";
- return;
- }
-
- RelocScan::scan<ELFT, RelTy>(it, type, addend);
-}
-
template <class ELFT, class RelTy>
void RISCV::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
- RISCVRelocScan rs(ctx, &sec);
+ RelocScan rs(ctx, &sec);
// Many relocations end up in sec.relocations.
sec.relocations.reserve(rels.size());
+ StringRef rvVendor;
for (auto it = rels.begin(); it != rels.end(); ++it) {
- auto type = it->getType(false);
+ RelType type = it->getType(false);
+ uint32_t symIndex = it->getSymbol(false);
+ Symbol &sym = sec.getFile<ELFT>()->getSymbol(symIndex);
+ const uint8_t *loc = sec.content().data() + it->r_offset;
+
+ if (type == R_RISCV_VENDOR) {
+ if (!rvVendor.empty())
+ Err(ctx) << getErrorLoc(ctx, loc)
+ << "malformed consecutive R_RISCV_VENDOR relocations";
+ rvVendor = sym.getName();
+ continue;
+ } else if (!rvVendor.empty()) {
+ Err(ctx) << getErrorLoc(ctx, loc)
+ << "unknown vendor-specific relocation (" << type.v
+ << ") in vendor namespace \"" << rvVendor << "\" against symbol "
+ << &sym;
+ rvVendor = "";
+ continue;
+ }
+
rs.scan<ELFT, RelTy>(it, type, rs.getAddend<ELFT>(*it, type));
}
// Sort relocations by offset for more efficient searching for
- // R_RISCV_PCREL_HI20, ALIGN relocations, R_PPC64_ADDR64 and the
- // branch-to-branch optimization.
+ // R_RISCV_PCREL_HI20.
llvm::stable_sort(sec.relocs(),
[](const Relocation &lhs, const Relocation &rhs) {
return lhs.offset < rhs.offset;
>From a269770e6bf36e2c0976195c81d1e584d4250a8c Mon Sep 17 00:00:00 2001
From: Owen Anderson <resistor at mac.com>
Date: Mon, 20 Oct 2025 18:07:36 +0900
Subject: [PATCH 4/5] Update test for review feedback
---
lld/test/riscv-vendor-relocations.s | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lld/test/riscv-vendor-relocations.s b/lld/test/riscv-vendor-relocations.s
index 68a6364ed18b1..f78f0e3b61911 100644
--- a/lld/test/riscv-vendor-relocations.s
+++ b/lld/test/riscv-vendor-relocations.s
@@ -14,5 +14,5 @@ TARGET:
1:
nop
-# CHECK: error: {{.*}} malformed consecutive R_RISCV_VENDOR relocations
-# CHECK: error: {{.*}} unknown vendor-specific relocation (255) in vendor namespace "INVALID_VENDOR" against symbol TARGET
+# CHECK: error: {{.*}}:(.text+0x4): malformed consecutive R_RISCV_VENDOR relocations
+# CHECK: error: {{.*}}:(.text+0x4): unknown vendor-specific relocation (255) in vendor namespace "INVALID_VENDOR" against symbol TARGET
>From a1bbc9306d9fba20894f07953b5643ad1ca8cb6b Mon Sep 17 00:00:00 2001
From: Owen Anderson <resistor at mac.com>
Date: Wed, 22 Oct 2025 17:08:31 +0900
Subject: [PATCH 5/5] Update error messages per review feedback.
---
lld/ELF/Arch/RISCV.cpp | 4 ++--
lld/test/riscv-vendor-relocations.s | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 6b226255e345b..5ed89e47c672e 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -1505,8 +1505,8 @@ void RISCV::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
} else if (!rvVendor.empty()) {
Err(ctx) << getErrorLoc(ctx, loc)
<< "unknown vendor-specific relocation (" << type.v
- << ") in vendor namespace \"" << rvVendor << "\" against symbol "
- << &sym;
+ << ") in namespace '" << rvVendor << "' against symbol '" << &sym
+ << "'";
rvVendor = "";
continue;
}
diff --git a/lld/test/riscv-vendor-relocations.s b/lld/test/riscv-vendor-relocations.s
index f78f0e3b61911..6ccec528f3d40 100644
--- a/lld/test/riscv-vendor-relocations.s
+++ b/lld/test/riscv-vendor-relocations.s
@@ -15,4 +15,4 @@ TARGET:
nop
# CHECK: error: {{.*}}:(.text+0x4): malformed consecutive R_RISCV_VENDOR relocations
-# CHECK: error: {{.*}}:(.text+0x4): unknown vendor-specific relocation (255) in vendor namespace "INVALID_VENDOR" against symbol TARGET
+# CHECK: error: {{.*}}:(.text+0x4): unknown vendor-specific relocation (255) in namespace 'INVALID_VENDOR' against symbol 'TARGET'
More information about the llvm-commits
mailing list