diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 040d5560cdf..dfc9e8aceaa 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -7377,6 +7377,8 @@ enum bfd_reloc_code_real
   BFD_RELOC_LARCH_TLS_DTPREL64,
   BFD_RELOC_LARCH_TLS_TPREL32,
   BFD_RELOC_LARCH_TLS_TPREL64,
+  BFD_RELOC_LARCH_TLS_DESC32,
+  BFD_RELOC_LARCH_TLS_DESC64,
   BFD_RELOC_LARCH_MARK_LA,
   BFD_RELOC_LARCH_MARK_PCREL,
   BFD_RELOC_LARCH_SOP_PUSH_PCREL,
@@ -7460,6 +7462,16 @@ enum bfd_reloc_code_real
   BFD_RELOC_LARCH_ADD_ULEB128,
   BFD_RELOC_LARCH_SUB_ULEB128,
   BFD_RELOC_LARCH_64_PCREL,
+  BFD_RELOC_LARCH_TLS_DESC_PC_HI20,
+  BFD_RELOC_LARCH_TLS_DESC_LD_PC_LO12,
+  BFD_RELOC_LARCH_TLS_DESC_ADD_PC_LO12,
+  BFD_RELOC_LARCH_TLS_DESC64_PC_LO20,
+  BFD_RELOC_LARCH_TLS_DESC64_PC_HI12,
+  BFD_RELOC_LARCH_TLS_DESC_HI20,
+  BFD_RELOC_LARCH_TLS_DESC_LO12,
+  BFD_RELOC_LARCH_TLS_DESC64_LO20,
+  BFD_RELOC_LARCH_TLS_DESC64_HI12,
+  BFD_RELOC_LARCH_TLS_DESC_CALL,
   BFD_RELOC_UNUSED
 };
 typedef enum bfd_reloc_code_real bfd_reloc_code_real_type;
diff --git a/bfd/elfxx-loongarch.c b/bfd/elfxx-loongarch.c
index 7f298c08fd3..c2df8f05562 100644
--- a/bfd/elfxx-loongarch.c
+++ b/bfd/elfxx-loongarch.c
@@ -293,8 +293,40 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
 	 NULL,				  /* adjust_reloc_bits */
 	 NULL),				  /* larch_reloc_type_name */
 
-  LOONGARCH_EMPTY_HOWTO (13),
-  LOONGARCH_EMPTY_HOWTO (14),
+  LOONGARCH_HOWTO (R_LARCH_TLS_DESC32,	  /* type (13).  */
+	 0,				  /* rightshift.  */
+	 4,				  /* size.  */
+	 32,				  /* bitsize.  */
+	 false,				  /* pc_relative.  */
+	 0,				  /* bitpos.  */
+	 complain_overflow_dont,	  /* complain_on_overflow.  */
+	 bfd_elf_generic_reloc,		  /* special_function.  */
+	 "R_LARCH_TLS_DESC32",		  /* name.  */
+	 false,				  /* partial_inplace.  */
+	 0,				  /* src_mask.  */
+	 ALL_ONES,		  	  /* dst_mask.  */
+	 false,				  /* pcrel_offset.  */
+	 BFD_RELOC_LARCH_TLS_DESC32,	  /* bfd_reloc_code_real_type.  */
+	 NULL,				  /* adjust_reloc_bits.  */
+	 NULL),				  /* larch_reloc_type_name.  */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_DESC64,	  /* type (14).  */
+	 0,				  /* rightshift.  */
+	 4,				  /* size.  */
+	 64,				  /* bitsize.  */
+	 false,				  /* pc_relative.  */
+	 0,				  /* bitpos.  */
+	 complain_overflow_dont,	  /* complain_on_overflow.  */
+	 bfd_elf_generic_reloc,		  /* special_function.  */
+	 "R_LARCH_TLS_DESC64",		  /* name.  */
+	 false,				  /* partial_inplace.  */
+	 0,				  /* src_mask.  */
+	 ALL_ONES,			  /* dst_mask.  */
+	 false,				  /* pcrel_offset.  */
+	 BFD_RELOC_LARCH_TLS_DESC64,	  /* bfd_reloc_code_real_type.  */
+	 NULL,				  /* adjust_reloc_bits.  */
+	 NULL),				  /* larch_reloc_type_name.  */
+
   LOONGARCH_EMPTY_HOWTO (15),
   LOONGARCH_EMPTY_HOWTO (16),
   LOONGARCH_EMPTY_HOWTO (17),
@@ -1547,6 +1579,179 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
 	 NULL,					/* adjust_reloc_bits */
 	 NULL),					/* larch_reloc_type_name */
 
+  /* TLS_DESC PCREL.  */
+  LOONGARCH_HOWTO (R_LARCH_TLS_DESC_PC_HI20,	/* type (110).  */
+	 12,					/* rightshift.  */
+	 4,					/* size.  */
+	 20,					/* bitsize.  */
+	 true,					/* pc_relative.  */
+	 5,					/* bitpos.  */
+	 complain_overflow_signed,		/* complain_on_overflow.  */
+	 bfd_elf_generic_reloc,			/* special_function.  */
+	 "R_LARCH_TLS_DESC_PC_HI20",		/* name.  */
+	 false,					/* partial_inplace.  */
+	 0,					/* src_mask.  */
+	 0x1ffffe0,				/* dst_mask.  */
+	 false,					/* pcrel_offset.  */
+	 BFD_RELOC_LARCH_TLS_DESC_PC_HI20,	/* bfd_reloc_code_real_type.  */
+	 reloc_bits,				/* adjust_reloc_bits.  */
+	 "desc_pc_hi20"),			/* larch_reloc_type_name.  */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_DESC_LD_PC_LO12,	/* type (111).  */
+	 0,					/* rightshift.  */
+	 4,					/* size.  */
+	 12,					/* bitsize.  */
+	 true,					/* pc_relative.  */
+	 10,					/* bitpos.  */
+	 complain_overflow_signed,		/* complain_on_overflow.  */
+	 bfd_elf_generic_reloc,			/* special_function.  */
+	 "R_LARCH_TLS_DESC_LD_PC_LO12",		/* name.  */
+	 false,					/* partial_inplace.  */
+	 0,					/* src_mask.  */
+	 0x3ffc00,				/* dst_mask.  */
+	 false,					/* pcrel_offset.  */
+	 BFD_RELOC_LARCH_TLS_DESC_LD_PC_LO12,	/* bfd_reloc_code_real_type.  */
+	 reloc_bits,				/* adjust_reloc_bits.  */
+	 "desc_ld_pc_lo12"),			/* larch_reloc_type_name.  */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_DESC_ADD_PC_LO12,/* type (112).  */
+	 0,					/* rightshift.  */
+	 4,					/* size.  */
+	 12,					/* bitsize.  */
+	 true,					/* pc_relative.  */
+	 10,					/* bitpos.  */
+	 complain_overflow_signed,		/* complain_on_overflow.  */
+	 bfd_elf_generic_reloc,			/* special_function.  */
+	 "R_LARCH_TLS_DESC_ADD_PC_LO12",	/* name.  */
+	 false,					/* partial_inplace.  */
+	 0,					/* src_mask.  */
+	 0x3ffc00,				/* dst_mask.  */
+	 false,					/* pcrel_offset.  */
+	 BFD_RELOC_LARCH_TLS_DESC_ADD_PC_LO12,	/* bfd_reloc_code_real_type.  */
+	 reloc_bits,				/* adjust_reloc_bits.  */
+	 "desc_add_pc_lo12"),			/* larch_reloc_type_name.  */
+
+  /* TLS_DESC64 LARGE PCREL.  */
+  LOONGARCH_HOWTO (R_LARCH_TLS_DESC64_PC_LO20, /* type (113).  */
+	32,				       /* rightshift.  */
+	4,				       /* size.  */
+	20,				       /* bitsize.  */
+	true,				       /* pc_relative.  */
+	5,				       /* bitpos.  */
+	complain_overflow_signed,	       /* complain_on_overflow.  */
+	bfd_elf_generic_reloc,		       /* special_function.  */
+	"R_LARCH_TLS_DESC64_PC_LO20",	       /* name.  */
+	false,				       /* partial_inplace.  */
+	0,				       /* src_mask.  */
+	0x1ffffe0,			       /* dst_mask.  */
+	false,				       /* pcrel_offset.  */
+	BFD_RELOC_LARCH_TLS_DESC64_PC_LO20,    /* bfd_reloc_code_real_type.  */
+	reloc_bits,			       /* adjust_reloc_bits.  */
+	"desc64_pc_lo20"),		       /* larch_reloc_type_name.  */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_DESC64_PC_HI12, /* type (114).  */
+	52,				       /* rightshift.  */
+	4,				       /* size.  */
+	12,				       /* bitsize.  */
+	true,				       /* pc_relative.  */
+	10,				       /* bitpos.  */
+	complain_overflow_signed,	       /* complain_on_overflow.  */
+	bfd_elf_generic_reloc,		       /* special_function.  */
+	"R_LARCH_TLS_DESC64_PC_HI12",	       /* name.  */
+	false,				       /* partial_inplace.  */
+	0,				       /* src_mask.  */
+	0x3ffc00,			       /* dst_mask.  */
+	false,				       /* pcrel_offset.  */
+	BFD_RELOC_LARCH_TLS_DESC64_PC_HI12,    /* bfd_reloc_code_real_type.  */
+	reloc_bits,			       /* adjust_reloc_bits.  */
+	"desc64_pc_hi12"),		       /* larch_reloc_type_name.  */
+
+  /* TLS_DESC ABS.  */
+  LOONGARCH_HOWTO (R_LARCH_TLS_DESC_HI20,	/* type (115).  */
+	 12,					/* rightshift.  */
+	 4,					/* size.  */
+	 20,					/* bitsize.  */
+	 false,					/* pc_relative.  */
+	 5,					/* bitpos.  */
+	 complain_overflow_signed,		/* complain_on_overflow.  */
+	 bfd_elf_generic_reloc,			/* special_function.  */
+	 "R_LARCH_TLS_DESC_HI20",		/* name.  */
+	 false,					/* partial_inplace.  */
+	 0,					/* src_mask.  */
+	 0x1ffffe0,				/* dst_mask.  */
+	 false,					/* pcrel_offset.  */
+	 BFD_RELOC_LARCH_TLS_DESC_HI20,		/* bfd_reloc_code_real_type.  */
+	 reloc_bits,				/* adjust_reloc_bits.  */
+	 "desc_hi20"),				/* larch_reloc_type_name.  */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_DESC_LO12,	/* type (116).  */
+	 0,					/* rightshift.  */
+	 4,					/* size.  */
+	 12,					/* bitsize.  */
+	 false,					/* pc_relative.  */
+	 10,					/* bitpos.  */
+	 complain_overflow_signed,		/* complain_on_overflow.  */
+	 bfd_elf_generic_reloc,			/* special_function.  */
+	 "R_LARCH_TLS_DESC_LO12",		/* name.  */
+	 false,					/* partial_inplace.  */
+	 0,					/* src_mask.  */
+	 0x3ffc00,				/* dst_mask.  */
+	 false,					/* pcrel_offset.  */
+	 BFD_RELOC_LARCH_TLS_DESC_LO12,		/* bfd_reloc_code_real_type.  */
+	 reloc_bits,				/* adjust_reloc_bits.  */
+	 "desc_lo12"),				/* larch_reloc_type_name.  */
+
+  /* TLS_DESC64 LARGE ABS.  */
+  LOONGARCH_HOWTO (R_LARCH_TLS_DESC64_LO20,    /* type (117).  */
+	32,				       /* rightshift.  */
+	4,				       /* size.  */
+	20,				       /* bitsize.  */
+	false,				       /* pc_relative.  */
+	5,				       /* bitpos.  */
+	complain_overflow_signed,	       /* complain_on_overflow.  */
+	bfd_elf_generic_reloc,		       /* special_function.  */
+	"R_LARCH_TLS_DESC64_LO20",	       /* name.  */
+	false,				       /* partial_inplace.  */
+	0,				       /* src_mask.  */
+	0x1ffffe0,			       /* dst_mask.  */
+	false,				       /* pcrel_offset.  */
+	BFD_RELOC_LARCH_TLS_DESC64_LO20,       /* bfd_reloc_code_real_type.  */
+	reloc_bits,			       /* adjust_reloc_bits.  */
+	"desc64_lo20"),			       /* larch_reloc_type_name.  */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_DESC64_HI12,    /* type (118).  */
+	52,				       /* rightshift.  */
+	4,				       /* size.  */
+	12,				       /* bitsize.  */
+	false,				       /* pc_relative.  */
+	10,				       /* bitpos.  */
+	complain_overflow_signed,	       /* complain_on_overflow.  */
+	bfd_elf_generic_reloc,		       /* special_function.  */
+	"R_LARCH_TLS_DESC64_HI12",	       /* name.  */
+	false,				       /* partial_inplace.  */
+	0,				       /* src_mask.  */
+	0x3ffc00,			       /* dst_mask.  */
+	false,				       /* pcrel_offset.  */
+	BFD_RELOC_LARCH_TLS_DESC64_HI12,       /* bfd_reloc_code_real_type.  */
+	reloc_bits,			       /* adjust_reloc_bits.  */
+	"desc64_hi12"),			       /* larch_reloc_type_name.  */
+
+  LOONGARCH_HOWTO (R_LARCH_TLS_DESC_CALL,	/* type (119).  */
+	 0,					/* rightshift.  */
+	 4,					/* size.  */
+	 0,					/* bitsize.  */
+	 false,					/* pc_relative.  */
+	 0,					/* bitpos.  */
+	 complain_overflow_dont,		/* complain_on_overflow.  */
+	 bfd_elf_generic_reloc,			/* special_function.  */
+	 "R_LARCH_TLS_DESC_CALL",		/* name.  */
+	 false,					/* partial_inplace.  */
+	 0,					/* src_mask.  */
+	 0,					/* dst_mask.  */
+	 false,					/* pcrel_offset.  */
+	 BFD_RELOC_LARCH_TLS_DESC_CALL,		/* bfd_reloc_code_real_type.  */
+	 NULL,					/* adjust_reloc_bits.  */
+	 "desc_call"),				/* larch_reloc_type_name.  */
 };
 
 reloc_howto_type *
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index cc432677a81..65ede521601 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -3516,6 +3516,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_LARCH_TLS_DTPREL64",
   "BFD_RELOC_LARCH_TLS_TPREL32",
   "BFD_RELOC_LARCH_TLS_TPREL64",
+  "BFD_RELOC_LARCH_TLS_DESC32",
+  "BFD_RELOC_LARCH_TLS_DESC64",
   "BFD_RELOC_LARCH_MARK_LA",
   "BFD_RELOC_LARCH_MARK_PCREL",
   "BFD_RELOC_LARCH_SOP_PUSH_PCREL",
@@ -3599,6 +3601,16 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_LARCH_ADD_ULEB128",
   "BFD_RELOC_LARCH_SUB_ULEB128",
   "BFD_RELOC_LARCH_64_PCREL",
+  "BFD_RELOC_LARCH_TLS_DESC_PC_HI20",
+  "BFD_RELOC_LARCH_TLS_DESC_LD_PC_LO12",
+  "BFD_RELOC_LARCH_TLS_DESC_ADD_PC_LO12",
+  "BFD_RELOC_LARCH_TLS_DESC64_PC_LO20",
+  "BFD_RELOC_LARCH_TLS_DESC64_PC_HI12",
+  "BFD_RELOC_LARCH_TLS_DESC_HI20",
+  "BFD_RELOC_LARCH_TLS_DESC_LO12",
+  "BFD_RELOC_LARCH_TLS_DESC64_LO20",
+  "BFD_RELOC_LARCH_TLS_DESC64_HI12",
+  "BFD_RELOC_LARCH_TLS_DESC_CALL",
  "@@overflow: BFD_RELOC_UNUSED@@",
 };
 #endif
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 93ebad879e0..e5717e60416 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -8111,6 +8111,10 @@ ENUMX
   BFD_RELOC_LARCH_TLS_TPREL32
 ENUMX
   BFD_RELOC_LARCH_TLS_TPREL64
+ENUMX
+  BFD_RELOC_LARCH_TLS_DESC32
+ENUMX
+  BFD_RELOC_LARCH_TLS_DESC64
 ENUMX
   BFD_RELOC_LARCH_MARK_LA
 ENUMX
@@ -8292,6 +8296,31 @@ ENUMX
 ENUMX
   BFD_RELOC_LARCH_64_PCREL
 
+ENUMX
+  BFD_RELOC_LARCH_TLS_DESC_PC_HI20
+ENUMX
+  BFD_RELOC_LARCH_TLS_DESC_LD_PC_LO12
+ENUMX
+  BFD_RELOC_LARCH_TLS_DESC_ADD_PC_LO12
+
+ENUMX
+  BFD_RELOC_LARCH_TLS_DESC64_PC_LO20
+ENUMX
+  BFD_RELOC_LARCH_TLS_DESC64_PC_HI12
+
+ENUMX
+  BFD_RELOC_LARCH_TLS_DESC_HI20
+ENUMX
+  BFD_RELOC_LARCH_TLS_DESC_LO12
+
+ENUMX
+  BFD_RELOC_LARCH_TLS_DESC64_LO20
+ENUMX
+  BFD_RELOC_LARCH_TLS_DESC64_HI12
+
+ENUMX
+  BFD_RELOC_LARCH_TLS_DESC_CALL
+
 ENUMDOC
   LARCH relocations.
 
diff --git a/gas/config/tc-loongarch.c b/gas/config/tc-loongarch.c
index d1ce111c186..b3c9a4d834c 100644
--- a/gas/config/tc-loongarch.c
+++ b/gas/config/tc-loongarch.c
@@ -682,7 +682,7 @@ loongarch_args_parser_can_match_arg_helper (char esc_ch1, char esc_ch2,
 		      esc_ch1, esc_ch2, bit_field, arg);
 
 	  if (ip->reloc_info[0].type >= BFD_RELOC_LARCH_B16
-	      && ip->reloc_info[0].type < BFD_RELOC_LARCH_64_PCREL)
+	      && ip->reloc_info[0].type <= BFD_RELOC_LARCH_TLS_DESC_CALL)
 	    {
 	      /* As we compact stack-relocs, it is no need for pop operation.
 		 But break out until here in order to check the imm field.
@@ -1268,6 +1268,15 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_LARCH_TLS_LD_HI20:
     case BFD_RELOC_LARCH_TLS_GD_PC_HI20:
     case BFD_RELOC_LARCH_TLS_GD_HI20:
+    case BFD_RELOC_LARCH_TLS_DESC_PC_HI20:
+    case BFD_RELOC_LARCH_TLS_DESC_LD_PC_LO12:
+    case BFD_RELOC_LARCH_TLS_DESC_ADD_PC_LO12:
+    case BFD_RELOC_LARCH_TLS_DESC64_PC_LO20:
+    case BFD_RELOC_LARCH_TLS_DESC64_PC_HI12:
+    case BFD_RELOC_LARCH_TLS_DESC_HI20:
+    case BFD_RELOC_LARCH_TLS_DESC_LO12:
+    case BFD_RELOC_LARCH_TLS_DESC64_LO20:
+    case BFD_RELOC_LARCH_TLS_DESC64_HI12:
       /* Add tls lo (got_lo reloc type).  */
       if (fixP->fx_addsy == NULL)
 	as_bad_where (fixP->fx_file, fixP->fx_line,
@@ -1288,6 +1297,9 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 	stack_top = 0;
       break;
 
+    case BFD_RELOC_LARCH_TLS_DESC_CALL:
+      break;
+
     case BFD_RELOC_LARCH_SOP_POP_32_S_10_5:
     case BFD_RELOC_LARCH_SOP_POP_32_S_10_12:
     case BFD_RELOC_LARCH_SOP_POP_32_U_10_12:
diff --git a/include/elf/loongarch.h b/include/elf/loongarch.h
index e31395e13d5..7018d101993 100644
--- a/include/elf/loongarch.h
+++ b/include/elf/loongarch.h
@@ -38,7 +38,8 @@ RELOC_NUMBER (R_LARCH_TLS_DTPREL64, 9)
 RELOC_NUMBER (R_LARCH_TLS_TPREL32, 10)
 RELOC_NUMBER (R_LARCH_TLS_TPREL64, 11)
 RELOC_NUMBER (R_LARCH_IRELATIVE, 12)
-
+RELOC_NUMBER (R_LARCH_TLS_DESC32, 13)
+RELOC_NUMBER (R_LARCH_TLS_DESC64, 14)
 /* Reserved for future relocs that the dynamic linker must understand.  */
 
 /* Used by the static linker for relocating .text.  */
@@ -251,6 +252,25 @@ RELOC_NUMBER (R_LARCH_SUB_ULEB128, 108)
 
 RELOC_NUMBER (R_LARCH_64_PCREL, 109)
 
+/* TLS_DESC PCREL.  */
+RELOC_NUMBER (R_LARCH_TLS_DESC_PC_HI20, 110)
+RELOC_NUMBER (R_LARCH_TLS_DESC_LD_PC_LO12, 111)
+RELOC_NUMBER (R_LARCH_TLS_DESC_ADD_PC_LO12, 112)
+
+/* TLS_DESC LARGE PCREL.  */
+RELOC_NUMBER (R_LARCH_TLS_DESC64_PC_LO20, 113)
+RELOC_NUMBER (R_LARCH_TLS_DESC64_PC_HI12, 114)
+
+/* TLS_DESC ABS.  */
+RELOC_NUMBER (R_LARCH_TLS_DESC_HI20, 115)
+RELOC_NUMBER (R_LARCH_TLS_DESC_LO12, 116)
+
+/* TLSDESC LARGE ABS.  */
+RELOC_NUMBER (R_LARCH_TLS_DESC64_LO20, 117)
+RELOC_NUMBER (R_LARCH_TLS_DESC64_HI12, 118)
+
+RELOC_NUMBER (R_LARCH_TLS_DESC_CALL, 119)
+
 END_RELOC_NUMBERS (R_LARCH_count)
 
 /* Processor specific flags for the ELF header e_flags field.  */
diff --git a/opcodes/loongarch-opc.c b/opcodes/loongarch-opc.c
index 82b88bdad2a..b650419d703 100644
--- a/opcodes/loongarch-opc.c
+++ b/opcodes/loongarch-opc.c
@@ -293,6 +293,55 @@ const char *const loongarch_x_normal_name[32] =
   &LARCH_opts.ase_lp64,		      \
   &LARCH_opts.ase_gpcr
 
+/* For TLS_DESC32 pcrel.  */
+#define INSN_LA_TLS_DESC32		\
+  "pcalau12i %1,%%desc_pc_hi20(%2);"    \
+  "ld.w $r5,%1,%%desc_ld_pc_lo12(%2);"  \
+  "addi.w %1,%1,%%desc_add_pc_lo12(%2);"\
+  "jirl $r1,$r5,%%desc_call(%2);",	\
+  &LARCH_opts.ase_ilp32,		\
+  &LARCH_opts.ase_lp64
+
+/* For TLS_DESC32 abs.  */
+#define INSN_LA_TLS_DESC32_ABS		\
+  "lu12i.w %1,%%desc_hi20(%2);"		\
+  "ori %1,%1,%%desc_lo12(%2);"		\
+  "ld.w $r5,%1,0;"			\
+  "jirl $r1,$r5,%%desc_call(%2);",	\
+  &LARCH_opts.ase_gabs,			\
+  &LARCH_opts.ase_lp64
+
+/* For TLS_DESC64 pcrel.  */
+#define INSN_LA_TLS_DESC64		\
+  "pcalau12i %1,%%desc_pc_hi20(%2);"	\
+  "ld.d $r5,%1,%%desc_ld_pc_lo12(%2);"	\
+  "addi.d %1,%1,%%desc_add_pc_lo12(%2);"\
+  "jirl $r1,$r5,%%desc_call(%2);",	\
+  &LARCH_opts.ase_lp64, 0
+
+/* For TLS_DESC64 large pcrel.  */
+#define INSN_LA_TLS_DESC64_LARGE_PCREL	 \
+  "pcalau12i %1,%%desc_pc_hi20(%3);"	 \
+  "addi.d %2,$r0,%%desc_add_pc_lo12(%3);"\
+  "lu32i.d %2,%%desc64_pc_lo20(%3);"	 \
+  "lu52i.d %2,%2,%%desc64_pc_hi12(%3);"	 \
+  "add.d %1,%1,%2;"			 \
+  "ld.d %2,%1,0;"			 \
+  "jirl $r1,%2,%%desc_call(%3);",	 \
+  &LARCH_opts.ase_lp64,			 \
+  &LARCH_opts.ase_gabs
+
+/* For TLS_DESC64 large abs.  */
+#define INSN_LA_TLS_DESC64_LARGE_ABS  \
+  "lu12i.w %1,%%desc_hi20(%2);"	      \
+  "ori %1,%1,%%desc_lo12(%2);"	      \
+  "lu32i.d %1,%%desc64_lo20(%2);"     \
+  "lu52i.d %1,%1,%%desc64_hi12(%2);"  \
+  "ld.d $r5,%1,0;"		      \
+  "jirl $r1,$r5,%%desc_call(%2);",    \
+  &LARCH_opts.ase_lp64,		      \
+  &LARCH_opts.ase_gpcr
+
 
 static struct loongarch_opcode loongarch_macro_opcodes[] =
 {
@@ -341,6 +390,11 @@ static struct loongarch_opcode loongarch_macro_opcodes[] =
   { 0, 0, "la.tls.gd",	"r,l",	  INSN_LA_TLS_GD64_LARGE_ABS,	0 },
   { 0, 0, "la.tls.gd",	"r,r,l",  INSN_LA_TLS_GD64_LARGE_PCREL,	0 },
   { 0, 0, "pcaddi",	"r,la",	  "pcaddi %1, %%pcrel_20(%2)",	&LARCH_opts.ase_ilp32, 0, 0 },
+  { 0, 0, "la.tls.desc", "r,l",   INSN_LA_TLS_DESC32, 0 },
+  { 0, 0, "la.tls.desc", "r,l",   INSN_LA_TLS_DESC32_ABS, 0 },
+  { 0, 0, "la.tls.desc", "r,l",	  INSN_LA_TLS_DESC64, 0 },
+  { 0, 0, "la.tls.desc", "r,l",   INSN_LA_TLS_DESC64_LARGE_ABS, 0 },
+  { 0, 0, "la.tls.desc", "r,r,l", INSN_LA_TLS_DESC64_LARGE_PCREL, 0 },
   { 0, 0, 0, 0, 0, 0, 0, 0 } /* Terminate the list.  */
 };
 
