[llvm] [JITLink][RISC-V] Support R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128 for… (PR #153778)

Zhijin Zeng via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 20 00:19:40 PDT 2025


https://github.com/zengdage updated https://github.com/llvm/llvm-project/pull/153778

>From ed2f249da6d5297fa1d2c4ca9bfb5e1d26252db7 Mon Sep 17 00:00:00 2001
From: Zhijin Zeng <zhijin.zeng at spacemit.com>
Date: Wed, 13 Aug 2025 11:33:38 +0800
Subject: [PATCH] [JITLink][RISC-V] Support
 R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128 for JITLink (#153775)

---
 .../llvm/ExecutionEngine/JITLink/riscv.h      | 12 ++++++
 llvm/include/llvm/Support/LEB128.h            | 12 ++++++
 .../lib/ExecutionEngine/JITLink/ELF_riscv.cpp | 41 ++++++++++++++++++-
 llvm/lib/ExecutionEngine/JITLink/riscv.cpp    |  4 ++
 .../JITLink/RISCV/ELF_reloc_uleb128.s         | 21 ++++++++++
 5 files changed, 88 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/ExecutionEngine/JITLink/RISCV/ELF_reloc_uleb128.s

diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/riscv.h b/llvm/include/llvm/ExecutionEngine/JITLink/riscv.h
index fcc99787c8e12..9786f5cde3615 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/riscv.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/riscv.h
@@ -221,6 +221,18 @@ enum EdgeKind_riscv : Edge::Kind {
   /// Fixup expression:
   ///   Fixup <- Fixup - Target + Addend
   NegDelta32,
+
+  /// Set ULEB128-encoded value
+  ///
+  /// Fixup expression:
+  ///   Fixup <- Target + Addend
+  R_RISCV_SET_ULEB128,
+
+  /// Subtract from ULEB128-encoded value
+  ///
+  /// Fixup expression:
+  ///   Fixup <- V - Target - Addend
+  R_RISCV_SUB_ULEB128,
 };
 
 /// Returns a string name for the given riscv edge. For debugging purposes
diff --git a/llvm/include/llvm/Support/LEB128.h b/llvm/include/llvm/Support/LEB128.h
index 6102c1dc1b952..5ee234ba86d56 100644
--- a/llvm/include/llvm/Support/LEB128.h
+++ b/llvm/include/llvm/Support/LEB128.h
@@ -221,6 +221,18 @@ inline uint64_t decodeULEB128AndIncUnsafe(const uint8_t *&p) {
   return decodeULEB128AndInc(p, nullptr);
 }
 
+/// Overwrite a ULEB128 value and keep the original length.
+///
+/// Copy from lld/ELF/Target.h.
+inline uint64_t overwriteULEB128(uint8_t *bufLoc, uint64_t val) {
+  while (*bufLoc & 0x80) {
+    *bufLoc++ = 0x80 | (val & 0x7f);
+    val >>= 7;
+  }
+  *bufLoc = val;
+  return val;
+}
+
 enum class LEB128Sign { Unsigned, Signed };
 
 template <LEB128Sign Sign, typename T, typename U = char,
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp
index 71a0f14368ac6..0dc97104610bb 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_riscv.cpp
@@ -154,18 +154,22 @@ class ELFJITLinker_riscv : public JITLinker<ELFJITLinker_riscv> {
                      std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig)
       : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {
     JITLinkerBase::getPassConfig().PostAllocationPasses.push_back(
-        [this](LinkGraph &G) { return gatherRISCVPCRelHi20(G); });
+        [this](LinkGraph &G) { return gatherRISCVPairs(G); });
   }
 
 private:
   DenseMap<std::pair<const Block *, orc::ExecutorAddrDiff>, const Edge *>
       RelHi20;
+  DenseMap<std::pair<const Block *, orc::ExecutorAddrDiff>, const Edge *>
+      SetULEB128;
 
-  Error gatherRISCVPCRelHi20(LinkGraph &G) {
+  Error gatherRISCVPairs(LinkGraph &G) {
     for (Block *B : G.blocks())
       for (Edge &E : B->edges())
         if (E.getKind() == R_RISCV_PCREL_HI20)
           RelHi20[{B, E.getOffset()}] = &E;
+        else if (E.getKind() == R_RISCV_SET_ULEB128)
+          SetULEB128[{B, E.getOffset()}] = &E;
 
     return Error::success();
   }
@@ -189,6 +193,20 @@ class ELFJITLinker_riscv : public JITLinker<ELFJITLinker_riscv> {
                                     "for LO12 PCREL relocation type");
   }
 
+  Expected<const Edge &> getRISCVSetULEB128(const Block &B,
+                                            const Edge &E) const {
+    using namespace riscv;
+    assert(E.getKind() == R_RISCV_SUB_ULEB128 &&
+           "Can only have pair relocation for R_RISCV_SUB_ULEB128");
+
+    auto It = SetULEB128.find({&B, E.getOffset()});
+    if (It != SetULEB128.end())
+      return *It->second;
+
+    return make_error<JITLinkError>(
+        "No RISCV_SET_ULEB128 relocation type be found");
+  }
+
   Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {
     using namespace riscv;
     using namespace llvm::support;
@@ -467,6 +485,21 @@ class ELFJITLinker_riscv : public JITLinker<ELFJITLinker_riscv> {
       *(little32_t *)FixupPtr = static_cast<uint32_t>(Value);
       break;
     }
+    case R_RISCV_SET_ULEB128:
+      break;
+    case R_RISCV_SUB_ULEB128: {
+      auto SetULEB128 = getRISCVSetULEB128(B, E);
+      if (!SetULEB128)
+        return SetULEB128.takeError();
+      uint64_t Value = SetULEB128->getTarget().getAddress() +
+                       SetULEB128->getAddend() - E.getTarget().getAddress() -
+                       E.getAddend();
+      if (overwriteULEB128(reinterpret_cast<uint8_t *>(FixupPtr), Value) >=
+          0x80)
+        return make_error<StringError>("ULEB128 value exceeds available space",
+                                       inconvertibleErrorCode());
+      break;
+    }
     }
     return Error::success();
   }
@@ -843,6 +876,10 @@ class ELFLinkGraphBuilder_riscv : public ELFLinkGraphBuilder<ELFT> {
       return EdgeKind_riscv::R_RISCV_32_PCREL;
     case ELF::R_RISCV_ALIGN:
       return EdgeKind_riscv::AlignRelaxable;
+    case ELF::R_RISCV_SET_ULEB128:
+      return EdgeKind_riscv::R_RISCV_SET_ULEB128;
+    case ELF::R_RISCV_SUB_ULEB128:
+      return EdgeKind_riscv::R_RISCV_SUB_ULEB128;
     }
 
     return make_error<JITLinkError>(
diff --git a/llvm/lib/ExecutionEngine/JITLink/riscv.cpp b/llvm/lib/ExecutionEngine/JITLink/riscv.cpp
index a4e4daef97fb5..9e9f4433a9fc2 100644
--- a/llvm/lib/ExecutionEngine/JITLink/riscv.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/riscv.cpp
@@ -84,6 +84,10 @@ const char *getEdgeKindName(Edge::Kind K) {
     return "AlignRelaxable";
   case NegDelta32:
     return "NegDelta32";
+  case R_RISCV_SET_ULEB128:
+    return "R_RISCV_SET_ULEB128";
+  case R_RISCV_SUB_ULEB128:
+    return "R_RISCV_SUB_ULEB128";
   }
   return getGenericEdgeKindName(K);
 }
diff --git a/llvm/test/ExecutionEngine/JITLink/RISCV/ELF_reloc_uleb128.s b/llvm/test/ExecutionEngine/JITLink/RISCV/ELF_reloc_uleb128.s
new file mode 100644
index 0000000000000..2b9f6f7d6bb37
--- /dev/null
+++ b/llvm/test/ExecutionEngine/JITLink/RISCV/ELF_reloc_uleb128.s
@@ -0,0 +1,21 @@
+# RUN: rm -rf %t && mkdir -p %t
+# RUN: llvm-mc -triple=riscv64 -filetype=obj -o %t/riscv64_reloc_uleb128.o %s
+# RUN: llvm-mc -triple=riscv32 -filetype=obj -o %t/riscv32_reloc_uleb128.o %s
+# RUN: llvm-jitlink -noexec -check %s %t/riscv64_reloc_uleb128.o
+# RUN: llvm-jitlink -noexec -check %s %t/riscv32_reloc_uleb128.o
+
+# jitlink-check: *{4}(foo+8) = 0x180
+
+.global main
+main:
+  lw a0, foo
+
+.section ".text","", at progbits
+.type foo, at function
+foo:
+  nop
+  nop
+  .reloc ., R_RISCV_SET_ULEB128, foo+129
+  .reloc ., R_RISCV_SUB_ULEB128, foo+1
+  .word 0
+  .size foo, 8



More information about the llvm-commits mailing list