diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 040d5560cdf..9bc6b9885ff 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -5407,6 +5407,10 @@ enum bfd_reloc_code_real
   BFD_RELOC_RISCV_TLS_DTPREL64,
   BFD_RELOC_RISCV_TLS_TPREL32,
   BFD_RELOC_RISCV_TLS_TPREL64,
+  BFD_RELOC_RISCV_TLSDESC_HI20,
+  BFD_RELOC_RISCV_TLSDESC_LOAD_LO12,
+  BFD_RELOC_RISCV_TLSDESC_ADD_LO12,
+  BFD_RELOC_RISCV_TLSDESC_CALL,
   BFD_RELOC_RISCV_ALIGN,
   BFD_RELOC_RISCV_RVC_BRANCH,
   BFD_RELOC_RISCV_RVC_JUMP,
diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index 567631e7d96..65d676b06b1 100644
--- a/bfd/elfxx-riscv.c
+++ b/bfd/elfxx-riscv.c
@@ -218,7 +218,20 @@ static reloc_howto_type howto_table[] =
 	 MINUS_ONE,			/* dst_mask */
 	 false),			/* pcrel_offset */
 
-  EMPTY_HOWTO (12),
+  HOWTO (R_RISCV_TLSDESC,		/* type */
+	 0,				/* rightshift */
+	 0,				/* size is handled by dynamic linker */
+	 0,				/* bitsize */
+	 false,				/* pc_relative */
+	 0,				/* bitpos */
+	 complain_overflow_dont,	/* complain_on_overflow */
+	 bfd_elf_generic_reloc,		/* special_function */
+	 "R_RISCV_TLSDESC",		/* name */
+	 false,				/* partial_inplace */
+	 0,				/* src_mask */
+	 MINUS_ONE,			/* dst_mask */
+	 false),			/* pcrel_offset */
+
   EMPTY_HOWTO (13),
   EMPTY_HOWTO (14),
   EMPTY_HOWTO (15),
@@ -808,6 +821,62 @@ static reloc_howto_type howto_table[] =
 	 0,				/* src_mask */
 	 0,				/* dst_mask */
 	 false),			/* pcrel_offset */
+
+  HOWTO (R_RISCV_TLSDESC_HI20,		/* type */
+	 0,				/* rightshift */
+	 4,				/* size */
+	 32,				/* bitsize */
+	 true,				/* pc_relative */
+	 0,				/* bitpos */
+	 complain_overflow_signed,	/* complain_on_overflow */
+	 bfd_elf_generic_reloc,		/* special_function */
+	 "R_RISCV_TLSDESC_HI20",	/* name */
+	 true,				/* partial_inplace */
+	 0,				/* src_mask */
+	 ENCODE_UTYPE_IMM (-1U),	/* dst_mask */
+	 false),			/* pcrel_offset */
+
+  HOWTO (R_RISCV_TLSDESC_LOAD_LO12,	/* type */
+	 0,				/* rightshift */
+	 4,				/* size */
+	 32,				/* bitsize */
+	 false,				/* pc_relative */
+	 0,				/* bitpos */
+	 complain_overflow_signed,	/* complain_on_overflow */
+	 bfd_elf_generic_reloc,		/* special_function */
+	 "R_RISCV_TLSDESC_LOAD_LO12",	/* name */
+	 false,				/* partial_inplace */
+	 0,				/* src_mask */
+	 ENCODE_ITYPE_IMM (-1U),	/* dst_mask */
+	 false),			/* pcrel_offset */
+
+  HOWTO (R_RISCV_TLSDESC_ADD_LO12,	/* type */
+	 0,				/* rightshift */
+	 4,				/* size */
+	 32,				/* bitsize */
+	 false,				/* pc_relative */
+	 0,				/* bitpos */
+	 complain_overflow_signed,	/* complain_on_overflow */
+	 bfd_elf_generic_reloc,		/* special_function */
+	 "R_RISCV_TLSDESC_ADD_LO12",	/* name */
+	 false,				/* partial_inplace */
+	 0,				/* src_mask */
+	 ENCODE_ITYPE_IMM (-1U),	/* dst_mask */
+	 false), 			/* pcrel_offset */
+
+  HOWTO (R_RISCV_TLSDESC_CALL,		/* type */
+	 0,				/* rightshift */
+	 0,				/* size */
+	 0,				/* bitsize */
+	 false,				/* pc_relative */
+	 0,				/* bitpos */
+	 complain_overflow_dont,	/* complain_on_overflow */
+	 bfd_elf_generic_reloc,		/* special_function */
+	 "R_RISCV_TLSDESC_CALL",	/* name */
+	 false,				/* partial_inplace */
+	 0,				/* src_mask */
+	 ENCODE_ITYPE_IMM (-1U),	/* dst_mask */
+	 false) 			/* pcrel_offset */
 };
 
 static reloc_howto_type howto_table_internal[] =
@@ -935,6 +1004,10 @@ static const struct elf_reloc_map riscv_reloc_map[] =
   { BFD_RELOC_RISCV_TPREL_LO12_I, R_RISCV_TPREL_LO12_I },
   { BFD_RELOC_RISCV_TLS_GOT_HI20, R_RISCV_TLS_GOT_HI20 },
   { BFD_RELOC_RISCV_TLS_GD_HI20, R_RISCV_TLS_GD_HI20 },
+  { BFD_RELOC_RISCV_TLSDESC_HI20, R_RISCV_TLSDESC_HI20 },
+  { BFD_RELOC_RISCV_TLSDESC_LOAD_LO12, R_RISCV_TLSDESC_LOAD_LO12 },
+  { BFD_RELOC_RISCV_TLSDESC_ADD_LO12, R_RISCV_TLSDESC_ADD_LO12 },
+  { BFD_RELOC_RISCV_TLSDESC_CALL, R_RISCV_TLSDESC_CALL },
   { BFD_RELOC_RISCV_ALIGN, R_RISCV_ALIGN },
   { BFD_RELOC_RISCV_RVC_BRANCH, R_RISCV_RVC_BRANCH },
   { BFD_RELOC_RISCV_RVC_JUMP, R_RISCV_RVC_JUMP },
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index cc432677a81..919b63d51a1 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -2400,6 +2400,10 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_RISCV_TLS_DTPREL64",
   "BFD_RELOC_RISCV_TLS_TPREL32",
   "BFD_RELOC_RISCV_TLS_TPREL64",
+  "BFD_RELOC_RISCV_TLSDESC_HI20",
+  "BFD_RELOC_RISCV_TLSDESC_LOAD_LO12",
+  "BFD_RELOC_RISCV_TLSDESC_ADD_LO12",
+  "BFD_RELOC_RISCV_TLSDESC_CALL",
   "BFD_RELOC_RISCV_ALIGN",
   "BFD_RELOC_RISCV_RVC_BRANCH",
   "BFD_RELOC_RISCV_RVC_JUMP",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 93ebad879e0..345f444d17a 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -4984,6 +4984,14 @@ ENUMX
   BFD_RELOC_RISCV_TLS_TPREL32
 ENUMX
   BFD_RELOC_RISCV_TLS_TPREL64
+ENUMX
+  BFD_RELOC_RISCV_TLSDESC_HI20
+ENUMX
+  BFD_RELOC_RISCV_TLSDESC_LOAD_LO12
+ENUMX
+  BFD_RELOC_RISCV_TLSDESC_ADD_LO12
+ENUMX
+  BFD_RELOC_RISCV_TLSDESC_CALL
 ENUMX
   BFD_RELOC_RISCV_ALIGN
 ENUMX
diff --git a/include/elf/riscv.h b/include/elf/riscv.h
index 56d419c665b..7f5c0407ac8 100644
--- a/include/elf/riscv.h
+++ b/include/elf/riscv.h
@@ -44,6 +44,7 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type)
   RELOC_NUMBER (R_RISCV_TLS_DTPREL64, 9)
   RELOC_NUMBER (R_RISCV_TLS_TPREL32, 10)
   RELOC_NUMBER (R_RISCV_TLS_TPREL64, 11)
+  RELOC_NUMBER (R_RISCV_TLSDESC, 12)
 
   /* Relocation types not used by the dynamic linker.  */
   RELOC_NUMBER (R_RISCV_BRANCH, 16)
@@ -90,6 +91,10 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type)
   /* Reserved 59 for R_RISCV_PLT32.  */
   RELOC_NUMBER (R_RISCV_SET_ULEB128, 60)
   RELOC_NUMBER (R_RISCV_SUB_ULEB128, 61)
+  RELOC_NUMBER (R_RISCV_TLSDESC_HI20, 62)
+  RELOC_NUMBER (R_RISCV_TLSDESC_LOAD_LO12, 63)
+  RELOC_NUMBER (R_RISCV_TLSDESC_ADD_LO12, 64)
+  RELOC_NUMBER (R_RISCV_TLSDESC_CALL, 65)
 END_RELOC_NUMBERS (R_RISCV_max)
 
 /* Internal relocations used exclusively by the relaxation pass.  */
