[𝘀𝗽𝗿] initial version

Created using spr 1.3.4
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 1d3d179..460cccb 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -44,6 +44,7 @@
   void relocate(uint8_t *loc, const Relocation &rel,
                 uint64_t val) const override;
   void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override;
+  RelExpr adjustTlsExpr(RelType type, RelExpr expr) const override;
   bool relaxOnce(int pass) const override;
 };
 
@@ -120,6 +121,8 @@
   }
   gotRel = symbolicRel;
 
+  tlsDescRel = R_RISCV_TLSDESC_CALL;
+
   // .got[0] = _DYNAMIC
   gotHeaderEntriesNum = 1;
 
@@ -298,6 +301,13 @@
     return R_TLSGD_PC;
   case R_RISCV_TLS_GOT_HI20:
     return R_GOT_PC;
+  case R_RISCV_TLSDESC_HI20:
+    return R_TLSDESC_PC;
+  case R_RISCV_TLSDESC_LOAD_LO12:
+  case R_RISCV_TLSDESC_ADD_LO12:
+    return R_TLSDESC;
+  case R_RISCV_TLSDESC_CALL:
+    return R_TLSDESC_CALL;
   case R_RISCV_TPREL_HI20:
   case R_RISCV_TPREL_LO12_I:
   case R_RISCV_TPREL_LO12_S:
@@ -420,6 +430,7 @@
   case R_RISCV_PCREL_HI20:
   case R_RISCV_TLS_GD_HI20:
   case R_RISCV_TLS_GOT_HI20:
+  case R_RISCV_TLSDESC_HI20:
   case R_RISCV_TPREL_HI20:
   case R_RISCV_HI20: {
     uint64_t hi = val + 0x800;
@@ -430,6 +441,8 @@
 
   case R_RISCV_PCREL_LO12_I:
   case R_RISCV_TPREL_LO12_I:
+  case R_RISCV_TLSDESC_LOAD_LO12:
+  case R_RISCV_TLSDESC_ADD_LO12:
   case R_RISCV_LO12_I: {
     uint64_t hi = (val + 0x800) >> 12;
     uint64_t lo = val - (hi << 12);
@@ -557,6 +570,13 @@
   }
 }
 
+RelExpr RISCV::adjustTlsExpr(RelType type, RelExpr expr) const {
+  if (expr == R_RELAX_TLS_GD_TO_IE) {
+    return R_RELAX_TLS_GD_TO_IE_ABS;
+  }
+  return expr;
+}
+
 namespace {
 struct SymbolAnchor {
   uint64_t offset;
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 53b496b..90f55c4 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -851,6 +851,7 @@
     return sym.getSize() + a;
   case R_TLSDESC:
     return in.got->getTlsDescAddr(sym) + a;
+  case R_RISCV_TLSDESC_HI:
   case R_TLSDESC_PC:
     return in.got->getTlsDescAddr(sym) + a - p;
   case R_TLSDESC_GOTPLT:
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 20eb02b..6e67a13 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1269,7 +1269,7 @@
     return handleMipsTlsRelocation(type, sym, c, offset, addend, expr);
 
   if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
-            R_TLSDESC_GOTPLT>(expr) &&
+            R_TLSDESC_GOTPLT, R_RISCV_TLSDESC_HI>(expr) &&
       config->shared) {
     if (expr != R_TLSDESC_CALL) {
       sym.setFlags(NEEDS_TLSDESC);
@@ -1333,7 +1333,7 @@
 
   if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
             R_TLSDESC_GOTPLT, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC,
-            R_LOONGARCH_TLSGD_PAGE_PC>(expr)) {
+            R_LOONGARCH_TLSGD_PAGE_PC, R_RISCV_TLSDESC_HI>(expr)) {
     if (!toExecRelax) {
       sym.setFlags(NEEDS_TLSGD);
       c.addReloc({expr, type, offset, addend, &sym});
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index cfb9092..9a24fe8 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -103,6 +103,10 @@
   R_RISCV_ADD,
   R_RISCV_LEB128,
   R_RISCV_PC_INDIRECT,
+  R_RISCV_TLSDESC_HI,
+  R_RISCV_TLSDESC_LOAD_LO,
+  R_RISCV_TLSDESC_ADD_LO,
+  R_RISCV_TLSDESC_CALLER,
   // Same as R_PC but with page-aligned semantics.
   R_LOONGARCH_PAGE_PC,
   // Same as R_PLT_PC but with page-aligned semantics.
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index dfec5e0..34bb3da 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1950,7 +1950,8 @@
       }
     }
 
-    if (config->emachine == EM_386 || config->emachine == EM_X86_64) {
+    if (config->emachine == EM_386 || config->emachine == EM_X86_64 ||
+        config->emachine == EM_RISCV) {
       // On targets that support TLSDESC, _TLS_MODULE_BASE_ is defined in such a
       // way that:
       //
diff --git a/lld/test/ELF/riscv-tlsdesc-le.s b/lld/test/ELF/riscv-tlsdesc-le.s
new file mode 100644
index 0000000..6aa670c
--- /dev/null
+++ b/lld/test/ELF/riscv-tlsdesc-le.s
@@ -0,0 +1,43 @@
+// RUN: llvm-mc -filetype=obj -triple=riscv64-pc-linux %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so
+// RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn %t.so | FileCheck %s
+// RUN: llvm-readelf -r %t.so | FileCheck --check-prefix=REL %s
+
+//      CHECK: 00000000000012d8 <_start>:
+// CHECK-NEXT:    12d8:       auipc   a0, 1
+// CHECK-NEXT:    12dc:       ld      a1, 920(a0)
+// CHECK-NEXT:    12e0:       addi    a0, a0, 920
+// CHECK-NEXT:    12e4:       jalr    t0, a1
+// CHECK-NEXT:    12e8:       add     a0, a0, tp
+// CHECK-NEXT:    12ec:       ret
+
+//      REL: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 2 entries
+//      REL: R_RISCV_TLSDESC_CALL ffffffffffffffe8
+// REL-NEXT: R_RISCV_TLSDESC_CALL 0
+
+	.text
+	.attribute	4, 16
+	.attribute	5, "rv64i2p1"
+	.file	"<stdin>"
+	.globl	_start                              # -- Begin function _start
+	.p2align	2
+	.type	_start,@function
+_start:                                     # @_start
+# %bb.0:                                # %entry
+.Ltlsdesc_hi0:
+	auipc	a0, %tlsdesc_hi(unspecified)
+	ld	a1, %tlsdesc_load_lo(.Ltlsdesc_hi0)(a0)
+	addi	a0, a0, %tlsdesc_add_lo(.Ltlsdesc_hi0)
+	jalr	t0, 0(a1), %tlsdesc_call(.Ltlsdesc_hi0)
+	add	a0, a0, tp
+	ret
+.Lfunc_end0:
+	.size	_start, .Lfunc_end0-_start
+                                        # -- End function
+	.section	".note.GNU-stack","",@progbits
+
+        .section .tbss,"awT",@nobits
+        .p2align 2
+
+unspecified:
+        .zero    4