[lld] [LLD] Add support for statically resolved vendor-specific RISCV relocations. (PR #181802)

via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 17 03:22:57 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lld

Author: Owen Anderson (resistor)

<details>
<summary>Changes</summary>

This is a re-land, with updates for feedback, of https://github.com/llvm/llvm-project/pull/169273
The original commit message is reproduced below the line.

The primary feedback addressed in this updated version is further effort to ensure that changes are
localized in RISCV.cpp as much as possible. Integral to this was a realization that the vendor
relocations iterator is not strictly required for this change, and hence its removal. Other, more
specific, feedback regarding the removal or relocation of other elements has also been addressed.

---

Original Commit Message:

This is achieved by using some of the bits of RelType to tag vendor namespaces.
This change also adds a relocation iterator for RISCV that folds vendor namespaces
into the RelType of the following relocation.

This patch is extracted from the implementation of RISCV vendor-specific relocations
in the CHERIoT LLVM downstream: https://github.com/CHERIoT-Platform/llvm-project/commit/3d6d6f7d9480b590731cbcf4b4817e1fa3049854


---
Full diff: https://github.com/llvm/llvm-project/pull/181802.diff


4 Files Affected:

- (modified) lld/ELF/Arch/RISCV.cpp (+64-11) 
- (modified) lld/ELF/Target.cpp (+5-1) 
- (modified) lld/ELF/Target.h (+1) 
- (modified) lld/test/ELF/riscv-vendor-relocations.s (+13-3) 


``````````diff
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 85f49c9260565..f89624342d292 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -68,12 +68,26 @@ class RISCV final : public TargetInfo {
 
 } // end anonymous namespace
 
+// Bit 8 of RelType is used to indicate linker-internal relocations that are
+// not vendor-specific.
 // These are internal relocation numbers for GP/X0 relaxation. They aren't part
 // of the psABI spec.
-#define INTERNAL_R_RISCV_GPREL_I 256
-#define INTERNAL_R_RISCV_GPREL_S 257
-#define INTERNAL_R_RISCV_X0REL_I 258
-#define INTERNAL_R_RISCV_X0REL_S 259
+constexpr uint32_t INTERNAL_R_RISCV_GPREL_I = 256;
+constexpr uint32_t INTERNAL_R_RISCV_GPREL_S = 257;
+constexpr uint32_t INTERNAL_R_RISCV_X0REL_I = 258;
+constexpr uint32_t INTERNAL_R_RISCV_X0REL_S = 259;
+
+// Bits 9 -> 31 of RelType are used to indicate vendor-specific relocations.
+constexpr uint32_t INTERNAL_RISCV_VENDOR_MASK = 0xFFFFFFFF << 9;
+constexpr uint32_t INTERNAL_RISCV_VENDOR_QUALCOMM = 1 << 9;
+constexpr uint32_t INTERNAL_RISCV_VENDOR_ANDES = 2 << 9;
+
+static uint32_t getRISCVVendorRelMarker(StringRef rvVendor) {
+  return StringSwitch<uint32_t>(rvVendor)
+      .Case("QUALCOMM", INTERNAL_RISCV_VENDOR_QUALCOMM)
+      .Case("ANDES", INTERNAL_RISCV_VENDOR_ANDES)
+      .Default(0);
+}
 
 const uint64_t dtpOffset = 0x800;
 
@@ -344,8 +358,15 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
   case R_RISCV_SUB_ULEB128:
     return RE_RISCV_LEB128;
   default:
-    Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation (" << type.v
-             << ") against symbol " << &s;
+    if (type.v & INTERNAL_RISCV_VENDOR_MASK) {
+      Err(ctx) << getErrorLoc(ctx, loc)
+               << "unsupported vendor-specific relocation " << type
+               << " against symbol " << &s;
+      return R_NONE;
+    }
+    Err(ctx) << getErrorLoc(ctx, loc) << "unknown relocation ("
+             << (type.v & ~INTERNAL_RISCV_VENDOR_MASK) << ") against symbol "
+             << &s;
     return R_NONE;
   }
 }
@@ -370,12 +391,19 @@ void RISCV::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
       rvVendor = sym.getName();
       continue;
     } else if (!rvVendor.empty()) {
-      Err(ctx) << getErrorLoc(ctx, loc)
-               << "unknown vendor-specific relocation (" << type.v
-               << ") in namespace '" << rvVendor << "' against symbol '" << &sym
-               << "'";
+      uint32_t VendorFlag = getRISCVVendorRelMarker(rvVendor);
+      if (!VendorFlag) {
+        Err(ctx) << getErrorLoc(ctx, loc)
+                 << "unknown vendor-specific relocation (" << type.v
+                 << ") in namespace '" << rvVendor << "' against symbol '"
+                 << &sym << "'";
+        rvVendor = "";
+        continue;
+      }
+
       rvVendor = "";
-      continue;
+      assert((type.v < 256) && "Out of range relocation detected!");
+      type.v |= VendorFlag;
     }
 
     rs.scan<ELFT, RelTy>(it, type, rs.getAddend<ELFT>(*it, type));
@@ -1532,3 +1560,28 @@ void elf::mergeRISCVAttributesSections(Ctx &ctx) {
 }
 
 void elf::setRISCVTargetInfo(Ctx &ctx) { ctx.target.reset(new RISCV(ctx)); }
+
+static std::optional<StringRef> getRISCVVendorString(RelType ty) {
+  if ((ty.v & INTERNAL_RISCV_VENDOR_MASK) == INTERNAL_RISCV_VENDOR_QUALCOMM)
+    return "QUALCOMM";
+  if ((ty.v & INTERNAL_RISCV_VENDOR_MASK) == INTERNAL_RISCV_VENDOR_ANDES)
+    return "ANDES";
+  return std::nullopt;
+}
+
+namespace lld::elf {
+
+std::string riscvVendorRelocToStr(RelType type) {
+  auto VendorString = getRISCVVendorString(type);
+  if (!VendorString)
+    return "Unknown";
+
+  StringRef str = getRISCVVendorRelocationTypeName(
+      type & ~INTERNAL_RISCV_VENDOR_MASK, *VendorString);
+  if (str == "Unknown")
+    return ("Unknown vendor-specific (" + Twine(type) + ")").str();
+
+  return str.str();
+}
+
+} // namespace lld::elf
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index 89e4dbeed3109..d1ec7ecc222c7 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -40,8 +40,12 @@ using namespace lld::elf;
 
 std::string elf::toStr(Ctx &ctx, RelType type) {
   StringRef s = getELFRelocationTypeName(ctx.arg.emachine, type);
-  if (s == "Unknown")
+  if (s == "Unknown") {
+    if (ctx.arg.emachine == EM_RISCV)
+      return riscvVendorRelocToStr(type);
     return ("Unknown (" + Twine(type) + ")").str();
+  }
+
   return std::string(s);
 }
 
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index 85fa683b84a6d..bc82ad3e3ff16 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -261,6 +261,7 @@ template <typename ELFT> void writeARMCmseImportLib(Ctx &);
 uint64_t getLoongArchPageDelta(uint64_t dest, uint64_t pc, RelType type);
 void riscvFinalizeRelax(int passes);
 void mergeRISCVAttributesSections(Ctx &);
+std::string riscvVendorRelocToStr(RelType type);
 void mergeHexagonAttributesSections(Ctx &);
 void addArmInputSectionMappingSymbols(Ctx &);
 void addArmSyntheticSectionMappingSymbol(Defined *);
diff --git a/lld/test/ELF/riscv-vendor-relocations.s b/lld/test/ELF/riscv-vendor-relocations.s
index b0f3c4a30d060..0257d30369792 100644
--- a/lld/test/ELF/riscv-vendor-relocations.s
+++ b/lld/test/ELF/riscv-vendor-relocations.s
@@ -9,11 +9,21 @@ TARGET:
   nop
 
 .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
+.global QUALCOMM
+.global ANDES
 1:
   nop
 
+.reloc 1b, R_RISCV_VENDOR, INVALID_VENDOR+0
+.reloc 1b, R_RISCV_VENDOR, INVALID_VENDOR+0
+.reloc 1b, R_RISCV_CUSTOM255, TARGET
 # CHECK: error: {{.*}}:(.text+0x4): malformed consecutive R_RISCV_VENDOR relocations
 # CHECK: error: {{.*}}:(.text+0x4): unknown vendor-specific relocation (255) in namespace 'INVALID_VENDOR' against symbol 'TARGET'
+.reloc 1b, R_RISCV_VENDOR, QUALCOMM+0
+.reloc 1b, R_RISCV_CUSTOM192, TARGET
+# CHECK: error: {{.*}}:(.text+0x4): unsupported vendor-specific relocation R_RISCV_QC_ABS20_U against symbol TARGET
+.reloc 1b, R_RISCV_VENDOR, ANDES+0
+.reloc 1b, R_RISCV_CUSTOM241, TARGET
+# CHECK: error: {{.*}}:(.text+0x4): unsupported vendor-specific relocation R_RISCV_NDS_BRANCH_10 against symbol TARGET
+2:
+  nop

``````````

</details>


https://github.com/llvm/llvm-project/pull/181802


More information about the llvm-commits mailing list