[lld] [lld] Add infrastructure for handling RISCV vendor-specific relocations. (PR #159987)

Owen Anderson via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 14 07:43:58 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] [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



More information about the llvm-commits mailing list