diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index b2caa5fc3e1..b727c933e13 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -155,6 +155,27 @@ struct loongarch_elf_link_hash_table
   ((R_TYPE) == R_LARCH_TLS_IE_PC_HI20 \
    || (R_TYPE) == R_LARCH_TLS_IE_PC_LO12)
 
+/* If TLS GD/IE need dynamic relocations, INDX will be the dynamic indx,
+   and set NEED_RELOC to true used in allocate_dynrelocs and
+   loongarch_elf_relocate_section for TLS GD/IE.  */
+#define LARCH_TLS_GD_IE_NEED_DYN_RELOC(INFO, DYN, H, INDX, NEED_RELOC) \
+  do \
+    { \
+      if ((H) != NULL \
+	  && (H)->dynindx != -1 \
+	  && WILL_CALL_FINISH_DYNAMIC_SYMBOL ((DYN), \
+				    bfd_link_pic (INFO), (H))) \
+      (INDX) = (H)->dynindx; \
+      if (((H) == NULL \
+	    || ELF_ST_VISIBILITY ((H)->other) == STV_DEFAULT \
+	    || (H)->root.type != bfd_link_hash_undefweak) \
+	    && (!bfd_link_executable (INFO) \
+	      || (INDX) != 0)) \
+      (NEED_RELOC) = true; \
+    } \
+    while (0)
+
+
 /* Generate a PLT header.  */
 
 static bool
@@ -1263,40 +1284,24 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
       h->got.offset = s->size;
       if (tls_type & (GOT_TLS_GD | GOT_TLS_IE | GOT_TLS_GDESC))
 	{
+	  int indx = 0;
+	  bool need_reloc = false;
+	  LARCH_TLS_GD_IE_NEED_DYN_RELOC (info, dyn, h, indx,
+					need_reloc);
 	  /* TLS_GD needs two dynamic relocs and two GOT slots.  */
 	  if (tls_type & GOT_TLS_GD)
 	    {
 	      s->size += 2 * GOT_ENTRY_SIZE;
-	      if (bfd_link_executable (info))
-		{
-		  /* Link exe and not defined local.  */
-		  if (!SYMBOL_REFERENCES_LOCAL (info, h))
-		    htab->elf.srelgot->size += 2 * sizeof (ElfNN_External_Rela);
-		}
-	      else
-		{
-		  if (SYMBOL_REFERENCES_LOCAL (info, h))
-		    htab->elf.srelgot->size += sizeof (ElfNN_External_Rela);
-		  else
-		    htab->elf.srelgot->size += 2 * sizeof (ElfNN_External_Rela);
-		}
+	      if (need_reloc)
+		htab->elf.srelgot->size += 2 * sizeof (ElfNN_External_Rela);
 	    }
 
 	  /* TLS_IE needs one dynamic reloc and one GOT slot.  */
 	  if (tls_type & GOT_TLS_IE)
 	    {
 	      s->size += GOT_ENTRY_SIZE;
-
-	      if (bfd_link_executable (info))
-		{
-		  /* Link exe and not defined local.  */
-		  if (!SYMBOL_REFERENCES_LOCAL (info, h))
-		    htab->elf.srelgot->size += sizeof (ElfNN_External_Rela);
-		}
-	      else
-		{
-		  htab->elf.srelgot->size += sizeof (ElfNN_External_Rela);
-		}
+	      if (need_reloc)
+		htab->elf.srelgot->size += 2 * sizeof (ElfNN_External_Rela);
 	    }
 
 	  /* TLS_DESC needs one dynamic reloc and two GOT slot.  */
@@ -2623,6 +2628,18 @@ loongarch_tls_relax (bfd *abfd, asection *sec, Elf_Internal_Rela *rel,
   return false;
 }
 
+#define TP_OFFSET 0
+
+/* Return the relocation value for a static TLS tp-relative relocation.  */
+static bfd_vma
+tls_tpoff (struct bfd_link_info *info, bfd_vma addr)
+{
+  /* If tls_sec is NULL, we should have signalled an error already.  */
+  if (elf_hash_table (info)->tls_sec == NULL)
+    return 0;
+  return addr - elf_hash_table (info)->tls_sec->vma - TP_OFFSET;
+}
+
 
 static int
 loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
@@ -3751,53 +3768,54 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 	    {
 	      Elf_Internal_Rela rela;
 	      asection *relgot = htab->elf.srelgot;
-	      bfd_vma tls_block_off = 0;
 
-	      if (SYMBOL_REFERENCES_LOCAL (info, h))
-		{
-		  BFD_ASSERT (elf_hash_table (info)->tls_sec);
-		  tls_block_off = relocation
-		      - elf_hash_table (info)->tls_sec->vma;
-		}
+	      int indx = 0;
+	      bool need_relocs = false;
+	      LARCH_TLS_GD_IE_NEED_DYN_RELOC (info, is_dyn, h, indx, need_relocs);
 
 	      if (tls_type & GOT_TLS_GD)
 		{
-		  rela.r_offset = sec_addr (got) + got_off;
-		  rela.r_addend = 0;
-		  if (SYMBOL_REFERENCES_LOCAL (info, h))
+		  if (need_relocs)
 		    {
-		      /* Local sym, used in exec, set module id 1.  */
-		      if (bfd_link_executable (info))
-			bfd_put_NN (output_bfd, 1, got->contents + got_off);
+		      /* Dynamic resolved Module ID.  */
+		      rela.r_offset = sec_addr (got) + got_off;
+		      rela.r_addend = 0;
+		      rela.r_info = ELFNN_R_INFO (indx,R_LARCH_TLS_DTPMODNN);
+		      bfd_put_NN (output_bfd, 0, got->contents + got_off);
+		      loongarch_elf_append_rela (output_bfd, relgot, &rela);
+
+		      if (indx == 0)
+			{
+			  /* Local symbol, tp offset has been known.  */
+			  BFD_ASSERT (! unresolved_reloc);
+			  bfd_put_NN (output_bfd, tls_tpoff (info, relocation),
+			      (got->contents + got_off + GOT_ENTRY_SIZE));
+			}
 		      else
 			{
-			  rela.r_info = ELFNN_R_INFO (0, R_LARCH_TLS_DTPMODNN);
+			  /* Dynamic resolved block offset.  */
+			  bfd_put_NN (output_bfd, 0,
+			      got->contents + got_off + GOT_ENTRY_SIZE);
+			  rela.r_info = ELFNN_R_INFO (indx,
+						  R_LARCH_TLS_DTPRELNN);
+			  rela.r_offset += GOT_ENTRY_SIZE;
 			  loongarch_elf_append_rela (output_bfd, relgot, &rela);
 			}
-
-		      bfd_put_NN (output_bfd, tls_block_off,
-				  got->contents + got_off + GOT_ENTRY_SIZE);
 		    }
-		  /* Dynamic resolved.  */
 		  else
 		    {
-		      /* Dynamic relocate module id.  */
-		      rela.r_info = ELFNN_R_INFO (h->dynindx,
-						  R_LARCH_TLS_DTPMODNN);
-		      loongarch_elf_append_rela (output_bfd, relgot, &rela);
-
-		      /* Dynamic relocate offset of block.  */
-		      rela.r_offset += GOT_ENTRY_SIZE;
-		      rela.r_info = ELFNN_R_INFO (h->dynindx,
-						  R_LARCH_TLS_DTPRELNN);
-		      loongarch_elf_append_rela (output_bfd, relgot, &rela);
+		      /* In a static link or an executable link with the symbol
+			 binding locally.  Mark it as belonging to module 1.  */
+		      bfd_put_NN (output_bfd, 1, got->contents + got_off);
+		      bfd_put_NN (output_bfd, tls_tpoff (info, relocation),
+			  got->contents + got_off + GOT_ENTRY_SIZE);
 		    }
 		}
 	      if (tls_type & GOT_TLS_GDESC)
 		{
 		  /* Unless it is a static link, DESC always emits a
 		     dynamic relocation.  */
-		  int indx = h && h->dynindx != -1 ? h->dynindx : 0;
+		  indx = h && h->dynindx != -1 ? h->dynindx : 0;
 		  rela.r_offset = sec_addr (got) + got_off + desc_off;
 		  rela.r_addend = 0;
 		  if (indx == 0)
@@ -3810,28 +3828,24 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 		}
 	      if (tls_type & GOT_TLS_IE)
 		{
-		  rela.r_offset = sec_addr (got) + got_off + ie_off;
-		  if (SYMBOL_REFERENCES_LOCAL (info, h))
+		  if (need_relocs)
 		    {
-		      /* Local sym, used in exec, set module id 1.  */
-		      if (!bfd_link_executable (info))
-			{
-			  rela.r_info = ELFNN_R_INFO (0, R_LARCH_TLS_TPRELNN);
-			  rela.r_addend = tls_block_off;
-			  loongarch_elf_append_rela (output_bfd, relgot, &rela);
-			}
+		      bfd_put_NN (output_bfd, 0,
+			  got->contents + got_off + ie_off);
+		      rela.r_offset = sec_addr (got) + got_off + ie_off;
+		      rela.r_addend = 0;
 
-		      bfd_put_NN (output_bfd, tls_block_off,
-				  got->contents + got_off + ie_off);
+		      if (indx == 0)
+			rela.r_addend = tls_tpoff (info, relocation);
+		      rela.r_info = ELFNN_R_INFO (indx, R_LARCH_TLS_TPRELNN);
+		      loongarch_elf_append_rela (output_bfd, relgot, &rela);
 		    }
-		  /* Dynamic resolved.  */
 		  else
 		    {
-		      /* Dynamic relocate offset of block.  */
-		      rela.r_info = ELFNN_R_INFO (h->dynindx,
-						  R_LARCH_TLS_TPRELNN);
-		      rela.r_addend = 0;
-		      loongarch_elf_append_rela (output_bfd, relgot, &rela);
+		      /* In a static link or an executable link with the symbol
+			 bindinglocally, compute offset directly.  */
+		      bfd_put_NN (output_bfd, tls_tpoff (info, relocation),
+			  got->contents + got_off + ie_off);
 		    }
 		}
 	    }
diff --git a/ld/testsuite/ld-loongarch-elf/desc-ie.d b/ld/testsuite/ld-loongarch-elf/desc-ie.d
index 32e350507db..83ba5b5e9cb 100644
--- a/ld/testsuite/ld-loongarch-elf/desc-ie.d
+++ b/ld/testsuite/ld-loongarch-elf/desc-ie.d
@@ -7,10 +7,10 @@
 
 Disassembly of section .text:
 
-0+230 <fn1>:
- 230:	1a000084 	pcalau12i   	\$a0, 4
- 234:	28cd6084 	ld.d        	\$a0, \$a0, 856
- 238:	03400000 	nop.*
- 23c:	03400000 	nop.*
- 240:	1a000084 	pcalau12i   	\$a0, 4
- 244:	28cd6081 	ld.d        	\$ra, \$a0, 856
+[0-9a-f]+ <fn1>:
+ +[0-9a-f]+:	1a000084 	pcalau12i   	\$a0, .*
+ +[0-9a-f]+:	28cdc084 	ld.d        	\$a0, \$a0, .*
+ +[0-9a-f]+:	03400000 	nop.*
+ +[0-9a-f]+:	03400000 	nop.*
+ +[0-9a-f]+:	1a000084 	pcalau12i   	\$a0, .*
+ +[0-9a-f]+:	28cdc081 	ld.d        	\$ra, \$a0, .*
diff --git a/ld/testsuite/ld-loongarch-elf/desc-le.d b/ld/testsuite/ld-loongarch-elf/desc-le.d
index b4ca9f82eb3..78202c1acde 100644
--- a/ld/testsuite/ld-loongarch-elf/desc-le.d
+++ b/ld/testsuite/ld-loongarch-elf/desc-le.d
@@ -8,8 +8,8 @@
 
 Disassembly of section .text:
 
-0+1200000e8 <fn1>:
-   1200000e8:	14000004 	lu12i.w     	\$a0, 0
-   1200000ec:	03800084 	ori         	\$a0, \$a0, 0x0
-   1200000f0:	03400000 	nop.*
-   1200000f4:	03400000 	nop.*
+[0-9a-f]+ <fn1>:
+   +[0-9a-f]+:	14000004 	lu12i.w     	\$a0, .*
+   +[0-9a-f]+:	03800084 	ori         	\$a0, \$a0, .*
+   +[0-9a-f]+:	03400000 	nop.*
+   +[0-9a-f]+:	03400000 	nop.*
diff --git a/ld/testsuite/ld-loongarch-elf/tlsdesc-dso.d b/ld/testsuite/ld-loongarch-elf/tlsdesc-dso.d
index 453902d1622..5cfccb84ccb 100644
--- a/ld/testsuite/ld-loongarch-elf/tlsdesc-dso.d
+++ b/ld/testsuite/ld-loongarch-elf/tlsdesc-dso.d
@@ -8,49 +8,49 @@
 
 Disassembly of section .text:
 
-0+418 <fun_gl1>:
- 418:	180214c4 	pcaddi      	\$a0, 4262
- 41c:	1a000084 	pcalau12i   	\$a0, 4
- 420:	28db0084 	ld.d        	\$a0, \$a0, 1728
- 424:	180212a4 	pcaddi      	\$a0, 4245
- 428:	18021304 	pcaddi      	\$a0, 4248
- 42c:	28c00081 	ld.d        	\$ra, \$a0, 0
- 430:	4c000021 	jirl        	\$ra, \$ra, 0
- 434:	1a000084 	pcalau12i   	\$a0, 4
- 438:	28d9c084 	ld.d        	\$a0, \$a0, 1648
- 43c:	03400000 	nop.*
- 440:	03400000 	nop.*
- 444:	1a000084 	pcalau12i   	\$a0, 4
- 448:	28d9c084 	ld.d        	\$a0, \$a0, 1648
- 44c:	18021264 	pcaddi      	\$a0, 4243
- 450:	18021244 	pcaddi      	\$a0, 4242
- 454:	28c00081 	ld.d        	\$ra, \$a0, 0
- 458:	4c000021 	jirl        	\$ra, \$ra, 0
- 45c:	1a000084 	pcalau12i   	\$a0, 4
- 460:	28daa084 	ld.d        	\$a0, \$a0, 1704
+[0-9a-f]+ <fun_gl1>:
+ +[0-9a-f]+:	180214c4 	pcaddi      	\$a0, .*
+ +[0-9a-f]+:	1a000084 	pcalau12i   	\$a0, .*
+ +[0-9a-f]+:	28dc2084 	ld.d        	\$a0, \$a0, .*
+ +[0-9a-f]+:	180212a4 	pcaddi      	\$a0, .*
+ +[0-9a-f]+:	18021304 	pcaddi      	\$a0, .*
+ +[0-9a-f]+:	28c00081 	ld.d        	\$ra, \$a0, .*
+ +[0-9a-f]+:	4c000021 	jirl        	\$ra, \$ra, .*
+ +[0-9a-f]+:	1a000084 	pcalau12i   	\$a0, .*
+ +[0-9a-f]+:	28dae084 	ld.d        	\$a0, \$a0, .*
+ +[0-9a-f]+:	03400000 	nop.*
+ +[0-9a-f]+:	03400000 	nop.*
+ +[0-9a-f]+:	1a000084 	pcalau12i   	\$a0, .*
+ +[0-9a-f]+:	28dae084 	ld.d        	\$a0, \$a0, .*
+ +[0-9a-f]+:	18021264 	pcaddi      	\$a0, .*
+ +[0-9a-f]+:	18021244 	pcaddi      	\$a0, .*
+ +[0-9a-f]+:	28c00081 	ld.d        	\$ra, \$a0, .*
+ +[0-9a-f]+:	4c000021 	jirl        	\$ra, \$ra, .*
+ +[0-9a-f]+:	1a000084 	pcalau12i   	\$a0, .*
+ +[0-9a-f]+:	28dbc084 	ld.d        	\$a0, \$a0, .*
 
-0+464 <fun_lo>:
- 464:	1a000084 	pcalau12i   	\$a0, 4
- 468:	28d86084 	ld.d        	\$a0, \$a0, 1560
- 46c:	18020ce4 	pcaddi      	\$a0, 4199
- 470:	18020e04 	pcaddi      	\$a0, 4208
- 474:	28c00081 	ld.d        	\$ra, \$a0, 0
- 478:	4c000021 	jirl        	\$ra, \$ra, 0
- 47c:	18020d24 	pcaddi      	\$a0, 4201
- 480:	1a000084 	pcalau12i   	\$a0, 4
- 484:	28d90084 	ld.d        	\$a0, \$a0, 1600
- 488:	03400000 	nop.*
- 48c:	03400000 	nop.*
- 490:	1a000084 	pcalau12i   	\$a0, 4
- 494:	28d90084 	ld.d        	\$a0, \$a0, 1600
- 498:	18020d84 	pcaddi      	\$a0, 4204
- 49c:	28c00081 	ld.d        	\$ra, \$a0, 0
- 4a0:	4c000021 	jirl        	\$ra, \$ra, 0
- 4a4:	18020d24 	pcaddi      	\$a0, 4201
- 4a8:	1a000084 	pcalau12i   	\$a0, 4
- 4ac:	28d96084 	ld.d        	\$a0, \$a0, 1624
+[0-9a-f]+ <fun_lo>:
+ +[0-9a-f]+:	1a000084 	pcalau12i   	\$a0, .*
+ +[0-9a-f]+:	28d98084 	ld.d        	\$a0, \$a0, .*
+ +[0-9a-f]+:	18020ce4 	pcaddi      	\$a0, .*
+ +[0-9a-f]+:	18020e04 	pcaddi      	\$a0, .*
+ +[0-9a-f]+:	28c00081 	ld.d        	\$ra, \$a0, .*
+ +[0-9a-f]+:	4c000021 	jirl        	\$ra, \$ra, .*
+ +[0-9a-f]+:	18020d24 	pcaddi      	\$a0, .*
+ +[0-9a-f]+:	1a000084 	pcalau12i   	\$a0, .*
+ +[0-9a-f]+:	28da2084 	ld.d        	\$a0, \$a0, .*
+ +[0-9a-f]+:	03400000 	nop.*
+ +[0-9a-f]+:	03400000 	nop.*
+ +[0-9a-f]+:	1a000084 	pcalau12i   	\$a0, .*
+ +[0-9a-f]+:	28da2084 	ld.d        	\$a0, \$a0, .*
+ +[0-9a-f]+:	18020d84 	pcaddi      	\$a0, .*
+ +[0-9a-f]+:	28c00081 	ld.d        	\$ra, \$a0, .*
+ +[0-9a-f]+:	4c000021 	jirl        	\$ra, \$ra, .*
+ +[0-9a-f]+:	18020d24 	pcaddi      	\$a0, .*
+ +[0-9a-f]+:	1a000084 	pcalau12i   	\$a0, .*
+ +[0-9a-f]+:	28da8084 	ld.d        	\$a0, \$a0, .*
 
-0+4b0 <fun_external>:
- 4b0:	18020d84 	pcaddi      	\$a0, 4204
- 4b4:	28c00081 	ld.d        	\$ra, \$a0, 0
- 4b8:	4c000021 	jirl        	\$ra, \$ra, 0
+[0-9a-f]+ <fun_external>:
+ +[0-9a-f]+:	18020d84 	pcaddi      	\$a0, .*
+ +[0-9a-f]+:	28c00081 	ld.d        	\$ra, \$a0, .*
+ +[0-9a-f]+:	4c000021 	jirl        	\$ra, \$ra, .*
