diff --git a/gas/testsuite/gas/loongarch/tlsdesc_32.d b/gas/testsuite/gas/loongarch/tlsdesc_32.d
new file mode 100644
index 00000000000..ad1e32666b5
--- /dev/null
+++ b/gas/testsuite/gas/loongarch/tlsdesc_32.d
@@ -0,0 +1,26 @@
+#as:
+#objdump: -dr
+#skip: loongarch64-*-*
+
+.*:[    ]+file format .*
+
+
+Disassembly of section .text:
+
+00000000.* <.*>:
+[ 	]+0:[ 	]+1a000004[ 	]+pcalau12i[ 	]+\$a0,[ 	]+0
+[ 	]+0:[ 	]+R_LARCH_TLS_DESC_PC_HI20[ 	]+var
+[ 	]+4:[ 	]+28800085[ 	]+ld.w[ 	]+\$a1,[ 	]+\$a0,[ 	]+0
+[ 	]+4:[ 	]+R_LARCH_TLS_DESC_LD_PC_LO12[ 	]+var
+[ 	]+8:[ 	]+02800084[ 	]+addi.w[ 	]+\$a0,[ 	]+\$a0,[ 	]+0
+[ 	]+8:[ 	]+R_LARCH_TLS_DESC_ADD_PC_LO12[ 	]+var
+[ 	]+c:[ 	]+4c0000a4[ 	]+jirl[ 	]+\$a0,[ 	]+\$a1,[ 	]+0
+[ 	]+c:[ 	]+R_LARCH_TLS_DESC_CALL[ 	]+var
+[ 	]+10:[ 	]+1a000004[ 	]+pcalau12i[ 	]+\$a0,[ 	]+0
+[ 	]+10:[ 	]+R_LARCH_TLS_DESC_PC_HI20[ 	]+var
+[ 	]+14:[ 	]+28800085[ 	]+ld.w[ 	]+\$a1,[ 	]+\$a0,[ 	]+0
+[ 	]+14:[ 	]+R_LARCH_TLS_DESC_LD_PC_LO12[ 	]+var
+[ 	]+18:[ 	]+02800084[ 	]+addi.w[ 	]+\$a0,[ 	]+\$a0,[ 	]+0
+[ 	]+18:[ 	]+R_LARCH_TLS_DESC_ADD_PC_LO12[ 	]+var
+[ 	]+1c:[ 	]+4c0000a1[ 	]+jirl[ 	]+\$ra,[ 	]+\$a1,[ 	]+0
+[ 	]+1c:[ 	]+R_LARCH_TLS_DESC_CALL[ 	]+var
diff --git a/gas/testsuite/gas/loongarch/tlsdesc_32.s b/gas/testsuite/gas/loongarch/tlsdesc_32.s
new file mode 100644
index 00000000000..98a89ee36fd
--- /dev/null
+++ b/gas/testsuite/gas/loongarch/tlsdesc_32.s
@@ -0,0 +1,12 @@
+.L1:
+	# R_LARCH_TLSDESC_HI20 var
+	pcalau12i       $a0,%desc_pc_hi20(var)
+	# R_LARCH_TLSDESC_LD_PC_LO12 var
+        ld.w    $a1,$a0,%desc_ld_pc_lo12(var)
+	# R_LARCH_TLSDESC_ADD_PC_LO12 var
+	addi.w  $a0,$a0,%desc_add_pc_lo12(var)
+	# R_LARCH_TLSDESC_CALL var
+	jirl    $a0,$a1,%desc_call(var)
+
+	# test macro
+	la.tls.desc	$a0,var
diff --git a/gas/testsuite/gas/loongarch/tlsdesc_64.d b/gas/testsuite/gas/loongarch/tlsdesc_64.d
new file mode 100644
index 00000000000..703ffc0e483
--- /dev/null
+++ b/gas/testsuite/gas/loongarch/tlsdesc_64.d
@@ -0,0 +1,26 @@
+#as:
+#objdump: -dr
+#skip: loongarch32-*-*
+
+.*:[    ]+file format .*
+
+
+Disassembly of section .text:
+
+00000000.* <.*>:
+[ 	]+0:[ 	]+1a000004[ 	]+pcalau12i[ 	]+\$a0,[ 	]+0
+[ 	]+0:[ 	]+R_LARCH_TLS_DESC_PC_HI20[ 	]+var
+[ 	]+4:[ 	]+28c00085[ 	]+ld.d[ 	]+\$a1,[ 	]+\$a0,[ 	]+0
+[ 	]+4:[ 	]+R_LARCH_TLS_DESC_LD_PC_LO12[ 	]+var
+[ 	]+8:[ 	]+02c00084[ 	]+addi.d[ 	]+\$a0,[ 	]+\$a0,[ 	]+0
+[ 	]+8:[ 	]+R_LARCH_TLS_DESC_ADD_PC_LO12[ 	]+var
+[ 	]+c:[ 	]+4c0000a1[ 	]+jirl[ 	]+\$ra,[ 	]+\$a1,[ 	]+0
+[ 	]+c:[ 	]+R_LARCH_TLS_DESC_CALL[ 	]+var
+[ 	]+10:[ 	]+1a000004[ 	]+pcalau12i[ 	]+\$a0,[ 	]+0
+[ 	]+10:[ 	]+R_LARCH_TLS_DESC_PC_HI20[ 	]+var
+[ 	]+14:[ 	]+28c00085[ 	]+ld.d[ 	]+\$a1,[ 	]+\$a0,[ 	]+0
+[ 	]+14:[ 	]+R_LARCH_TLS_DESC_LD_PC_LO12[ 	]+var
+[ 	]+18:[ 	]+02c00084[ 	]+addi.d[ 	]+\$a0,[ 	]+\$a0,[ 	]+0
+[ 	]+18:[ 	]+R_LARCH_TLS_DESC_ADD_PC_LO12[ 	]+var
+[ 	]+1c:[ 	]+4c0000a1[ 	]+jirl[ 	]+\$ra,[ 	]+\$a1,[ 	]+0
+[ 	]+1c:[ 	]+R_LARCH_TLS_DESC_CALL[ 	]+var
diff --git a/gas/testsuite/gas/loongarch/tlsdesc_64.s b/gas/testsuite/gas/loongarch/tlsdesc_64.s
new file mode 100644
index 00000000000..fb24abe2d1f
--- /dev/null
+++ b/gas/testsuite/gas/loongarch/tlsdesc_64.s
@@ -0,0 +1,12 @@
+.L1:
+	# R_LARCH_TLSDESC_HI20 var
+	pcalau12i       $a0,%desc_pc_hi20(var)
+	# R_LARCH_TLSDESC_LD_PC_LO12 var
+        ld.d    $a1,$a0,%desc_ld_pc_lo12(var)
+	# R_LARCH_TLSDESC_ADD_PC_LO12 var
+	addi.d  $a0,$a0,%desc_add_pc_lo12(var)
+	# R_LARCH_TLSDESC_CALL var
+	jirl    $ra,$a1,%desc_call(var)
+
+	# test macro
+	la.tls.desc	$a0,var
diff --git a/gas/testsuite/gas/loongarch/tlsdesc_large_abs.d b/gas/testsuite/gas/loongarch/tlsdesc_large_abs.d
new file mode 100644
index 00000000000..4a2947a41ae
--- /dev/null
+++ b/gas/testsuite/gas/loongarch/tlsdesc_large_abs.d
@@ -0,0 +1,21 @@
+#as:
+#objdump: -dr
+#skip: loongarch32-*-*
+
+.*:[    ]+file format .*
+
+
+Disassembly of section .text:
+
+00000000.* <.*>:
+[ 	]+0:[ 	]+14000004[ 	]+lu12i.w[ 	]+\$a0,[ 	]+0
+[ 	]+0:[ 	]+R_LARCH_TLS_DESC_HI20[ 	]+var
+[ 	]+4:[ 	]+03800084[ 	]+ori[ 	]+\$a0,[ 	]+\$a0,[ 	]+0x0
+[ 	]+4:[ 	]+R_LARCH_TLS_DESC_LO12[ 	]+var
+[ 	]+8:[ 	]+16000004[ 	]+lu32i.d[ 	]+\$a0,[ 	]+0
+[ 	]+8:[ 	]+R_LARCH_TLS_DESC64_LO20[ 	]+var
+[ 	]+c:[ 	]+03000084[ 	]+lu52i.d[ 	]+\$a0,[ 	]+\$a0,[ 	]+0
+[ 	]+c:[ 	]+R_LARCH_TLS_DESC64_HI12[ 	]+var
+[ 	]+10:[ 	]+28c00085[ 	]+ld.d[ 	]+\$a1,[ 	]+\$a0,[ 	]+0
+[ 	]+14:[ 	]+4c0000a1[ 	]+jirl[ 	]+\$ra,[ 	]+\$a1,[ 	]+0
+[ 	]+14:[ 	]+R_LARCH_TLS_DESC_CALL[ 	]+var
diff --git a/gas/testsuite/gas/loongarch/tlsdesc_large_abs.s b/gas/testsuite/gas/loongarch/tlsdesc_large_abs.s
new file mode 100644
index 00000000000..ed33857fc22
--- /dev/null
+++ b/gas/testsuite/gas/loongarch/tlsdesc_large_abs.s
@@ -0,0 +1,9 @@
+.L1:
+	.global var
+	#TLSDESC large abs
+	lu12i.w		$a0,%desc_hi20(var)
+	ori		$a0,$a0,%desc_lo12(var)
+	lu32i.d		$a0,%desc64_lo20(var)
+	lu52i.d		$a0,$a0,%desc64_hi12(var)
+	ld.d		$a1,$a0,0
+	jirl		$ra,$a1,%desc_call(var)
diff --git a/gas/testsuite/gas/loongarch/tlsdesc_large_pc.d b/gas/testsuite/gas/loongarch/tlsdesc_large_pc.d
new file mode 100644
index 00000000000..81333806f8c
--- /dev/null
+++ b/gas/testsuite/gas/loongarch/tlsdesc_large_pc.d
@@ -0,0 +1,34 @@
+#as:
+#objdump: -dr
+#skip: loongarch32-*-*
+
+.*:[    ]+file format .*
+
+
+Disassembly of section .text:
+
+00000000.* <.*>:
+[ 	]+0:[ 	]+1a000004[ 	]+pcalau12i[ 	]+\$a0,[ 	]+0
+[ 	]+0:[ 	]+R_LARCH_TLS_DESC_PC_HI20[ 	]+var
+[ 	]+4:[ 	]+02c00005[ 	]+li.d[ 	]+\$a1,[ 	]+0
+[ 	]+4:[ 	]+R_LARCH_TLS_DESC_ADD_PC_LO12[ 	]+var
+[ 	]+8:[ 	]+16000005[ 	]+lu32i.d[ 	]+\$a1,[ 	]+0
+[ 	]+8:[ 	]+R_LARCH_TLS_DESC64_PC_LO20[ 	]+var
+[ 	]+c:[ 	]+030000a5[ 	]+lu52i.d[ 	]+\$a1,[ 	]+\$a1,[ 	]+0
+[ 	]+c:[ 	]+R_LARCH_TLS_DESC64_PC_HI12[ 	]+var
+[ 	]+10:[ 	]+00109484[ 	]+add.d[ 	]+\$a0,[ 	]+\$a0,[ 	]+\$a1
+[ 	]+14:[ 	]+28c00085[ 	]+ld.d[ 	]+\$a1,[ 	]+\$a0,[ 	]+0
+[ 	]+18:[ 	]+4c0000a1[ 	]+jirl[ 	]+\$ra,[ 	]+\$a1,[ 	]+0
+[ 	]+18:[ 	]+R_LARCH_TLS_DESC_CALL[ 	]+var
+[ 	]+1c:[ 	]+1a000004[ 	]+pcalau12i[ 	]+\$a0,[ 	]+0
+[ 	]+1c:[ 	]+R_LARCH_TLS_DESC_PC_HI20[ 	]+var
+[ 	]+20:[ 	]+02c00005[ 	]+li.d[ 	]+\$a1,[ 	]+0
+[ 	]+20:[ 	]+R_LARCH_TLS_DESC_ADD_PC_LO12[ 	]+var
+[ 	]+24:[ 	]+16000005[ 	]+lu32i.d[ 	]+\$a1,[ 	]+0
+[ 	]+24:[ 	]+R_LARCH_TLS_DESC64_PC_LO20[ 	]+var
+[ 	]+28:[ 	]+030000a5[ 	]+lu52i.d[ 	]+\$a1,[ 	]+\$a1,[ 	]+0
+[ 	]+28:[ 	]+R_LARCH_TLS_DESC64_PC_HI12[ 	]+var
+[ 	]+2c:[ 	]+00109484[ 	]+add.d[ 	]+\$a0,[ 	]+\$a0,[ 	]+\$a1
+[ 	]+30:[ 	]+28c00085[ 	]+ld.d[ 	]+\$a1,[ 	]+\$a0,[ 	]+0
+[ 	]+34:[ 	]+4c0000a1[ 	]+jirl[ 	]+\$ra,[ 	]+\$a1,[ 	]+0
+[ 	]+34:[ 	]+R_LARCH_TLS_DESC_CALL[ 	]+var
diff --git a/gas/testsuite/gas/loongarch/tlsdesc_large_pc.s b/gas/testsuite/gas/loongarch/tlsdesc_large_pc.s
new file mode 100644
index 00000000000..a396060bf28
--- /dev/null
+++ b/gas/testsuite/gas/loongarch/tlsdesc_large_pc.s
@@ -0,0 +1,16 @@
+.L1:
+	# R_LARCH_TLS_DESC_HI20 var
+	pcalau12i       $a0,%desc_pc_hi20(var)
+	# R_LARCH_TLS_DESC_ADD_PC_LO12
+	addi.d		$a1,$zero,%desc_add_pc_lo12(var)
+	# R_LARCH_TLS_DESC64_PC_LO20
+	lu32i.d		$a1,%desc64_pc_lo20(var)
+	# R_LARCH_TLS_DESC64_PC_HI12
+	lu52i.d		$a1,$a1,%desc64_pc_hi12(var)
+	add.d		$a0,$a0,$a1
+	ld.d		$a1,$a0,0
+	# R_LARCH_TLS_DESC
+	jirl		$ra,$a1,%desc_call(var)
+
+	# test macro
+	la.tls.desc	$a0,$a1,var
diff --git a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
index b95cc53e597..f72cc523486 100644
--- a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
+++ b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
@@ -32,6 +32,7 @@ if [istarget "loongarch64-*-*"] {
     run_dump_test "syscall"
     run_dump_test "disas-jirl"
     run_dump_test "local-ifunc-reloc"
+    run_dump_test "tls-relax-desc-le"
 }
 
 if [istarget "loongarch32-*-*"] {
@@ -55,4 +56,19 @@ if [istarget "loongarch64-*-*"] {
 	      "64_pcrel" \
 	  ] \
       ]
+
+  run_ld_link_tests \
+      [list \
+	  [list \
+	      "tls-desc" \
+	      "-shared -fPIC" "" \
+	      "" \
+	      {tls-desc.s} \
+	      [list \
+		  [list objdump -drj.text tls-desc.dd] \
+		  [list readelf -rWs tls-desc.rd] \
+	      ] \
+	      "tls-desc" \
+	  ] \
+      ]
 }
diff --git a/ld/testsuite/ld-loongarch-elf/tls-desc.dd b/ld/testsuite/ld-loongarch-elf/tls-desc.dd
new file mode 100644
index 00000000000..23ca5a352be
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/tls-desc.dd
@@ -0,0 +1,74 @@
+#source: tls-desc.s
+#as:
+#ld: -shared -fPIC
+#objdump: -drj.text
+#skip: loongarch32-*-*
+
+.*:[    ]+file format .*
+
+
+Disassembly of section .text:
+
+00000000.* <.*>:
+[ 	]+4f0:[ 	]+1a0000ac[ 	]+pcalau12i[ 	]+\$t0,[ 	]+5
+[ 	]+4f4:[ 	]+02e1c184[ 	]+addi.d[ 	]+\$a0,[ 	]+\$t0,[ 	]+-1936
+[ 	]+4f8:[ 	]+57ffebff[ 	]+bl[ 	]+-24[ 	]+#[ 	]+4e0[ 	]+<__tls_get_addr@plt>
+[ 	]+4fc:[ 	]+1a0000ac[ 	]+pcalau12i[ 	]+\$t0,[ 	]+5
+[ 	]+500:[ 	]+28e2018c[ 	]+ld.d[ 	]+\$t0,[ 	]+\$t0,[ 	]+-1920
+[ 	]+504:[ 	]+1a0000ac[ 	]+pcalau12i[ 	]+\$t0,[ 	]+5
+[ 	]+508:[ 	]+02e0a184[ 	]+addi.d[ 	]+\$a0,[ 	]+\$t0,[ 	]+-2008
+[ 	]+50c:[ 	]+57ffd7ff[ 	]+bl[ 	]+-44[ 	]+#[ 	]+4e0[ 	]+<__tls_get_addr@plt>
+[ 	]+510:[ 	]+1a0000a4[ 	]+pcalau12i[ 	]+\$a0,[ 	]+5
+[ 	]+514:[ 	]+28e0e085[ 	]+ld.d[ 	]+\$a1,[ 	]+\$a0,[ 	]+-1992
+[ 	]+518:[ 	]+02e0e084[ 	]+addi.d[ 	]+\$a0,[ 	]+\$a0,[ 	]+-1992
+[ 	]+51c:[ 	]+4c0000a1[ 	]+jirl[ 	]+\$ra,[ 	]+\$a1,[ 	]+0
+[ 	]+520:[ 	]+1a0000a4[ 	]+pcalau12i[ 	]+\$a0,[ 	]+5
+[ 	]+524:[ 	]+28e04085[ 	]+ld.d[ 	]+\$a1,[ 	]+\$a0,[ 	]+-2032
+[ 	]+528:[ 	]+02e04084[ 	]+addi.d[ 	]+\$a0,[ 	]+\$a0,[ 	]+-2032
+[ 	]+52c:[ 	]+4c0000a1[ 	]+jirl[ 	]+\$ra,[ 	]+\$a1,[ 	]+0
+[ 	]+530:[ 	]+1a0000ac[ 	]+pcalau12i[ 	]+\$t0,[ 	]+5
+[ 	]+534:[ 	]+28e0818c[ 	]+ld.d[ 	]+\$t0,[ 	]+\$t0,[ 	]+-2016
+[ 	]+538:[ 	]+1a0000ac[ 	]+pcalau12i[ 	]+\$t0,[ 	]+5
+[ 	]+53c:[ 	]+02e12184[ 	]+addi.d[ 	]+\$a0,[ 	]+\$t0,[ 	]+-1976
+[ 	]+540:[ 	]+57ffa3ff[ 	]+bl[ 	]+-96[ 	]+#[ 	]+4e0[ 	]+<__tls_get_addr@plt>
+[ 	]+544:[ 	]+1a0000a4[ 	]+pcalau12i[ 	]+\$a0,[ 	]+5
+[ 	]+548:[ 	]+28e16085[ 	]+ld.d[ 	]+\$a1,[ 	]+\$a0,[ 	]+-1960
+[ 	]+54c:[ 	]+02e16084[ 	]+addi.d[ 	]+\$a0,[ 	]+\$a0,[ 	]+-1960
+[ 	]+550:[ 	]+4c0000a1[ 	]+jirl[ 	]+\$ra,[ 	]+\$a1,[ 	]+0
+[ 	]+554:[ 	]+1a0000ac[ 	]+pcalau12i[ 	]+\$t0,[ 	]+5
+[ 	]+558:[ 	]+28e1a18c[ 	]+ld.d[ 	]+\$t0,[ 	]+\$t0,[ 	]+-1944
+
+.*0000055c[ 	]+<fun_lo>:
+[ 	]+55c:[ 	]+1a00008c[ 	]+pcalau12i[ 	]+\$t0,[ 	]+4
+[ 	]+560:[ 	]+28de618c[ 	]+ld.d[ 	]+\$t0,[ 	]+\$t0,[ 	]+1944
+[ 	]+564:[ 	]+1a00008c[ 	]+pcalau12i[ 	]+\$t0,[ 	]+4
+[ 	]+568:[ 	]+02de2184[ 	]+addi.d[ 	]+\$a0,[ 	]+\$t0,[ 	]+1928
+[ 	]+56c:[ 	]+57ff77ff[ 	]+bl[ 	]+-140[ 	]+#[ 	]+4e0[ 	]+<__tls_get_addr@plt>
+[ 	]+570:[ 	]+1a000084[ 	]+pcalau12i[ 	]+\$a0,[ 	]+4
+[ 	]+574:[ 	]+28dec085[ 	]+ld.d[ 	]+\$a1,[ 	]+\$a0,[ 	]+1968
+[ 	]+578:[ 	]+02dec084[ 	]+addi.d[ 	]+\$a0,[ 	]+\$a0,[ 	]+1968
+[ 	]+57c:[ 	]+4c0000a1[ 	]+jirl[ 	]+\$ra,[ 	]+\$a1,[ 	]+0
+[ 	]+580:[ 	]+1a00008c[ 	]+pcalau12i[ 	]+\$t0,[ 	]+4
+[ 	]+584:[ 	]+02de8184[ 	]+addi.d[ 	]+\$a0,[ 	]+\$t0,[ 	]+1952
+[ 	]+588:[ 	]+57ff5bff[ 	]+bl[ 	]+-168[ 	]+#[ 	]+4e0[ 	]+<__tls_get_addr@plt>
+[ 	]+58c:[ 	]+1a000084[ 	]+pcalau12i[ 	]+\$a0,[ 	]+4
+[ 	]+590:[ 	]+28df0085[ 	]+ld.d[ 	]+\$a1,[ 	]+\$a0,[ 	]+1984
+[ 	]+594:[ 	]+02df0084[ 	]+addi.d[ 	]+\$a0,[ 	]+\$a0,[ 	]+1984
+[ 	]+598:[ 	]+4c0000a1[ 	]+jirl[ 	]+\$ra,[ 	]+\$a1,[ 	]+0
+[ 	]+59c:[ 	]+1a00008c[ 	]+pcalau12i[ 	]+\$t0,[ 	]+4
+[ 	]+5a0:[ 	]+28df418c[ 	]+ld.d[ 	]+\$t0,[ 	]+\$t0,[ 	]+2000
+[ 	]+5a4:[ 	]+1a000084[ 	]+pcalau12i[ 	]+\$a0,[ 	]+4
+[ 	]+5a8:[ 	]+28dfa085[ 	]+ld.d[ 	]+\$a1,[ 	]+\$a0,[ 	]+2024
+[ 	]+5ac:[ 	]+02dfa084[ 	]+addi.d[ 	]+\$a0,[ 	]+\$a0,[ 	]+2024
+[ 	]+5b0:[ 	]+4c0000a1[ 	]+jirl[ 	]+\$ra,[ 	]+\$a1,[ 	]+0
+[ 	]+5b4:[ 	]+1a00008c[ 	]+pcalau12i[ 	]+\$t0,[ 	]+4
+[ 	]+5b8:[ 	]+02df6184[ 	]+addi.d[ 	]+\$a0,[ 	]+\$t0,[ 	]+2008
+[ 	]+5bc:[ 	]+57ff27ff[ 	]+bl[ 	]+-220[ 	]+#[ 	]+4e0[ 	]+<__tls_get_addr@plt>
+[ 	]+5c0:[ 	]+1a00008c[ 	]+pcalau12i[ 	]+\$t0,[ 	]+4
+[ 	]+5c4:[ 	]+28dfe18c[ 	]+ld.d[ 	]+\$t0,[ 	]+\$t0,[ 	]+2040
+
+.*000005c8[ 	]+<fun_external>:
+[ 	]+5c8:[ 	]+1a0000a4[ 	]+pcalau12i[ 	]+\$a0,[ 	]+5
+[ 	]+5cc:[ 	]+28e00085[ 	]+ld.d[ 	]+\$a1,[ 	]+\$a0,[ 	]+-2048
+[ 	]+5d0:[ 	]+02e00084[ 	]+addi.d[ 	]+\$a0,[ 	]+\$a0,[ 	]+-2048
+[ 	]+5d4:[ 	]+4c0000a1[ 	]+jirl[ 	]+\$ra,[ 	]+\$a1,[ 	]+0
diff --git a/ld/testsuite/ld-loongarch-elf/tls-desc.rd b/ld/testsuite/ld-loongarch-elf/tls-desc.rd
new file mode 100644
index 00000000000..38c27dbc4b5
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/tls-desc.rd
@@ -0,0 +1,79 @@
+#as:
+#ld: -shared -fPIC
+#readelf: -rWs
+#skip: loongarch32-*-*
+
+Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 22 entries:
+    Offset             Info             Type               Symbol's Value  Symbol's Name \+ Addend
+0+4788  +[0-9a-f]+ R_LARCH_TLS_DTPMOD64                      0
+0+4798  +[0-9a-f]+ R_LARCH_TLS_TPREL64                       20
+0+47a0  +[0-9a-f]+ R_LARCH_TLS_DTPMOD64                      0
+0+47b0  +[0-9a-f]+ R_LARCH_TLS_DESC64                        28
+0+47c0  +[0-9a-f]+ R_LARCH_TLS_DESC64                        30
+0+47d0  +[0-9a-f]+ R_LARCH_TLS_TPREL64                       30
+0+47d8  +[0-9a-f]+ R_LARCH_TLS_DTPMOD64                      0
+0+47e8  +[0-9a-f]+ R_LARCH_TLS_DESC64                        38
+0+47f8  +[0-9a-f]+ R_LARCH_TLS_TPREL64                       38
+0+4800  +[0-9a-f]+ R_LARCH_TLS_DESC64     +[0-9a-f]+ sH1 \+ 0
+0+4810  +[0-9a-f]+ R_LARCH_TLS_DESC64     +[0-9a-f]+ gl3 \+ 0
+0+4820  +[0-9a-f]+ R_LARCH_TLS_TPREL64    +[0-9a-f]+ gl3 \+ 0
+0+4828  +[0-9a-f]+ R_LARCH_TLS_DTPMOD64   +[0-9a-f]+ gl2 \+ 0
+0+4830  +[0-9a-f]+ R_LARCH_TLS_DTPREL64   +[0-9a-f]+ gl2 \+ 0
+0+4838  +[0-9a-f]+ R_LARCH_TLS_DESC64     +[0-9a-f]+ gl2 \+ 0
+0+4848  +[0-9a-f]+ R_LARCH_TLS_DTPMOD64   +[0-9a-f]+ gl4 \+ 0
+0+4850  +[0-9a-f]+ R_LARCH_TLS_DTPREL64   +[0-9a-f]+ gl4 \+ 0
+0+4858  +[0-9a-f]+ R_LARCH_TLS_DESC64     +[0-9a-f]+ gl4 \+ 0
+0+4868  +[0-9a-f]+ R_LARCH_TLS_TPREL64    +[0-9a-f]+ gl4 \+ 0
+0+4870  +[0-9a-f]+ R_LARCH_TLS_DTPMOD64   +[0-9a-f]+ gl1 \+ 0
+0+4878  +[0-9a-f]+ R_LARCH_TLS_DTPREL64   +[0-9a-f]+ gl1 \+ 0
+0+4880  +[0-9a-f]+ R_LARCH_TLS_TPREL64    +[0-9a-f]+ gl1 \+ 0
+
+Relocation section '.rela.plt' at offset 0x[0-9a-f]+ contains 1 entry:
+    Offset             Info             Type               Symbol's Value  Symbol's Name \+ Addend
+0+4778  +[0-9a-f]+ R_LARCH_JUMP_SLOT      +[0-9a-f]+ __tls_get_addr \+ 0
+
+Symbol table '.dynsym' contains 9 entries:
+   Num:    Value          Size Type    Bind   Vis      Ndx Name
+     0: +[0-9a-f]+     0 NOTYPE  LOCAL  DEFAULT  UND 
+     1: +[0-9a-f]+     0 SECTION LOCAL  DEFAULT    8 .text
+     2: +[0-9a-f]+     0 SECTION LOCAL  DEFAULT    9 .tdata
+     3: +[0-9a-f]+     0 TLS     GLOBAL DEFAULT  UND sH1
+     4: +[0-9a-f]+     0 NOTYPE  GLOBAL DEFAULT  UND __tls_get_addr
+     5: +[0-9a-f]+     0 TLS     GLOBAL DEFAULT    9 gl3
+     6: +[0-9a-f]+     0 TLS     GLOBAL DEFAULT    9 gl4
+     7: +[0-9a-f]+     0 TLS     GLOBAL DEFAULT    9 gl1
+     8: +[0-9a-f]+     0 TLS     GLOBAL DEFAULT    9 gl2
+
+Symbol table '.symtab' contains 31 entries:
+   Num:    Value          Size Type    Bind   Vis      Ndx Name
+     0: +[0-9a-f]+     0 NOTYPE  LOCAL  DEFAULT  UND 
+     1: +[0-9a-f]+     0 SECTION LOCAL  DEFAULT    1 .hash
+     2: +[0-9a-f]+     0 SECTION LOCAL  DEFAULT    2 .gnu.hash
+     3: +[0-9a-f]+     0 SECTION LOCAL  DEFAULT    3 .dynsym
+     4: +[0-9a-f]+     0 SECTION LOCAL  DEFAULT    4 .dynstr
+     5: +[0-9a-f]+     0 SECTION LOCAL  DEFAULT    5 .rela.dyn
+     6: +[0-9a-f]+     0 SECTION LOCAL  DEFAULT    6 .rela.plt
+     7: +[0-9a-f]+     0 SECTION LOCAL  DEFAULT    7 .plt
+     8: +[0-9a-f]+     0 SECTION LOCAL  DEFAULT    8 .text
+     9: +[0-9a-f]+     0 SECTION LOCAL  DEFAULT    9 .tdata
+    10: +[0-9a-f]+     0 SECTION LOCAL  DEFAULT   10 .dynamic
+    11: +[0-9a-f]+     0 SECTION LOCAL  DEFAULT   11 .got.plt
+    12: +[0-9a-f]+     0 SECTION LOCAL  DEFAULT   12 .got
+    13: +[0-9a-f]+     0 FILE    LOCAL  DEFAULT  ABS tls-desc.o
+    14: +[0-9a-f]+     0 TLS     LOCAL  DEFAULT    9 lo1
+    15: +[0-9a-f]+     0 TLS     LOCAL  DEFAULT    9 lo2
+    16: +[0-9a-f]+     0 TLS     LOCAL  DEFAULT    9 lo3
+    17: +[0-9a-f]+     0 TLS     LOCAL  DEFAULT    9 lo4
+    18: +[0-9a-f]+     0 NOTYPE  LOCAL  DEFAULT    8 fun_gl1
+    19: +[0-9a-f]+     0 NOTYPE  LOCAL  DEFAULT    8 fun_lo
+    20: +[0-9a-f]+     0 NOTYPE  LOCAL  DEFAULT    8 fun_external
+    21: +[0-9a-f]+     0 FILE    LOCAL  DEFAULT  ABS 
+    22: +[0-9a-f]+     0 OBJECT  LOCAL  DEFAULT  ABS _DYNAMIC
+    23: +[0-9a-f]+     0 OBJECT  LOCAL  DEFAULT  ABS _PROCEDURE_LINKAGE_TABLE_
+    24: +[0-9a-f]+     0 OBJECT  LOCAL  DEFAULT  ABS _GLOBAL_OFFSET_TABLE_
+    25: +[0-9a-f]+     0 TLS     GLOBAL DEFAULT  UND sH1
+    26: +[0-9a-f]+     0 TLS     GLOBAL DEFAULT    9 gl3
+    27: +[0-9a-f]+     0 TLS     GLOBAL DEFAULT    9 gl2
+    28: +[0-9a-f]+     0 TLS     GLOBAL DEFAULT    9 gl4
+    29: +[0-9a-f]+     0 NOTYPE  GLOBAL DEFAULT  UND __tls_get_addr
+    30: +[0-9a-f]+     0 TLS     GLOBAL DEFAULT    9 gl1
diff --git a/ld/testsuite/ld-loongarch-elf/tls-desc.s b/ld/testsuite/ld-loongarch-elf/tls-desc.s
new file mode 100644
index 00000000000..322adc11139
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/tls-desc.s
@@ -0,0 +1,102 @@
+	.data
+	.section	.tdata,"awT",@progbits
+	.global gl1, gl2, gl3, gl4
+gl1:	.dword 1
+gl2:	.dword 2
+gl3:	.dword 3
+gl4:	.dword 4
+lo1:	.dword 10
+lo2:	.dword 20
+lo3:	.dword 30
+lo4:	.dword 40
+	.text
+# Access global symbol
+fun_gl1:
+	# GD + IE
+	pcalau12i	$t0,%gd_pc_hi20(gl1)
+	addi.d	$a0,$t0,%got_pc_lo12(gl1)
+	bl	%plt(__tls_get_addr)
+
+	pcalau12i       $t0,%ie_pc_hi20(gl1)
+        ld.d    $t0,$t0,%ie_pc_lo12(gl1)
+
+	# GD + DESC
+	pcalau12i	$t0,%gd_pc_hi20(gl2)
+	addi.d	$a0,$t0,%got_pc_lo12(gl2)
+	bl	%plt(__tls_get_addr)
+
+	pcalau12i       $a0,%desc_pc_hi20(gl2)
+        ld.d    $a1,$a0,%desc_ld_pc_lo12(gl2)
+        addi.d  $a0,$a0,%desc_add_pc_lo12(gl2)
+        jirl    $ra,$a1,%desc_call(gl2)
+
+	# DESC + IE
+	pcalau12i       $a0,%desc_pc_hi20(gl3)
+        ld.d    $a1,$a0,%desc_ld_pc_lo12(gl3)
+        addi.d  $a0,$a0,%desc_add_pc_lo12(gl3)
+        jirl    $ra,$a1,%desc_call(gl3)
+
+	pcalau12i       $t0,%ie_pc_hi20(gl3)
+        ld.d    $t0,$t0,%ie_pc_lo12(gl3)
+
+
+	# GD + DESC + IE
+	pcalau12i	$t0,%gd_pc_hi20(gl4)
+	addi.d	$a0,$t0,%got_pc_lo12(gl4)
+	bl	%plt(__tls_get_addr)
+
+	pcalau12i       $a0,%desc_pc_hi20(gl4)
+        ld.d    $a1,$a0,%desc_ld_pc_lo12(gl4)
+        addi.d  $a0,$a0,%desc_add_pc_lo12(gl4)
+        jirl    $ra,$a1,%desc_call(gl4)
+
+	pcalau12i       $t0,%ie_pc_hi20(gl4)
+        ld.d    $t0,$t0,%ie_pc_lo12(gl4)
+
+# Access local symbol
+fun_lo:
+	# IE + GD
+	pcalau12i       $t0,%ie_pc_hi20(lo1)
+        ld.d    $t0,$t0,%ie_pc_lo12(lo1)
+
+	pcalau12i	$t0,%gd_pc_hi20(lo1)
+	addi.d	$a0,$t0,%got_pc_lo12(lo1)
+	bl	%plt(__tls_get_addr)
+
+	# DESC + GD
+	pcalau12i       $a0,%desc_pc_hi20(lo2)
+        ld.d    $a1,$a0,%desc_ld_pc_lo12(lo2)
+        addi.d  $a0,$a0,%desc_add_pc_lo12(lo2)
+        jirl    $ra,$a1,%desc_call(lo2)
+
+	pcalau12i	$t0,%gd_pc_hi20(lo2)
+	addi.d	$a0,$t0,%got_pc_lo12(lo2)
+	bl	%plt(__tls_get_addr)
+
+	# DESC + IE
+	pcalau12i       $a0,%desc_pc_hi20(lo3)
+        ld.d    $a1,$a0,%desc_ld_pc_lo12(lo3)
+        addi.d  $a0,$a0,%desc_add_pc_lo12(lo3)
+        jirl    $ra,$a1,%desc_call(lo3)
+
+	pcalau12i       $t0,%ie_pc_hi20(lo3)
+        ld.d    $t0,$t0,%ie_pc_lo12(lo3)
+
+	# DESC + GD + IE
+	pcalau12i       $a0,%desc_pc_hi20(lo4)
+        ld.d    $a1,$a0,%desc_ld_pc_lo12(lo4)
+        addi.d  $a0,$a0,%desc_add_pc_lo12(lo4)
+        jirl    $ra,$a1,%desc_call(lo4)
+
+	pcalau12i	$t0,%gd_pc_hi20(lo4)
+	addi.d	$a0,$t0,%got_pc_lo12(lo4)
+	bl	%plt(__tls_get_addr)
+
+	pcalau12i       $t0,%ie_pc_hi20(lo4)
+        ld.d    $t0,$t0,%ie_pc_lo12(lo4)
+# Access external undef symbol
+fun_external:
+	pcalau12i       $a0,%desc_pc_hi20(sH1)
+        ld.d    $a1,$a0,%desc_ld_pc_lo12(sH1)
+        addi.d  $a0,$a0,%desc_add_pc_lo12(sH1)
+        jirl    $ra,$a1,%desc_call(sH1)
diff --git a/ld/testsuite/ld-loongarch-elf/tls-relax-desc-le.d b/ld/testsuite/ld-loongarch-elf/tls-relax-desc-le.d
new file mode 100644
index 00000000000..844d54f725c
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/tls-relax-desc-le.d
@@ -0,0 +1,15 @@
+#as:
+#ld: -e 0x0 -static
+#objdump: -drj.text
+#skip: loongarch32-*-*
+
+.*:[    ]+file format .*
+
+
+Disassembly of section .text:
+
+.*1200000e8 <.*>:
+[ 	]+1200000e8:[ 	]+14000004[ 	]+lu12i.w[ 	]+\$a0,[ 	]+0
+[ 	]+1200000ec:[ 	]+03800084[ 	]+ori[ 	]+\$a0,[ 	]+\$a0,[ 	]+0x0
+[ 	]+1200000f0:[ 	]+03400000[ 	]+nop.*
+[ 	]+1200000f4:[ 	]+03400000[ 	]+nop.*
diff --git a/ld/testsuite/ld-loongarch-elf/tls-relax-desc-le.s b/ld/testsuite/ld-loongarch-elf/tls-relax-desc-le.s
new file mode 100644
index 00000000000..09a86586760
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/tls-relax-desc-le.s
@@ -0,0 +1,8 @@
+	.section .tdata
+var:
+	.word 4
+	.text
+	pcalau12i       $a0,%desc_pc_hi20(var)
+	ld.d    $a1,$a0,%desc_ld_pc_lo12(var)
+	addi.d  $a0,$a0,%desc_add_pc_lo12(var)
+	jirl    $ra,$a1,%desc_call(var)
