diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index b2caa5fc3e1..c4babab5673 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -145,16 +145,20 @@ struct loongarch_elf_link_hash_table
 #define elf_backend_rela_normal 1
 #define elf_backend_default_execstack 0
 
-#define IS_LOONGARCH_TLS_DESC_RELOC(R_TYPE)    \
-  ((R_TYPE) == R_LARCH_TLS_DESC_PC_HI20	\
-   || (R_TYPE) == R_LARCH_TLS_DESC_PC_LO12  \
-   || (R_TYPE) == R_LARCH_TLS_DESC_LD \
-   || (R_TYPE) == R_LARCH_TLS_DESC_CALL)
-
-#define IS_LOONGARCH_TLS_IE_RELOC(R_TYPE) \
-  ((R_TYPE) == R_LARCH_TLS_IE_PC_HI20 \
+#define IS_LOONGARCH_TLS_TRANS_RELOC(R_TYPE)  \
+  ((R_TYPE) == R_LARCH_TLS_DESC_PC_HI20	      \
+   || (R_TYPE) == R_LARCH_TLS_DESC_PC_LO12    \
+   || (R_TYPE) == R_LARCH_TLS_DESC_LD	      \
+   || (R_TYPE) == R_LARCH_TLS_DESC_CALL	      \
+   || (R_TYPE) == R_LARCH_TLS_IE_PC_HI20      \
    || (R_TYPE) == R_LARCH_TLS_IE_PC_LO12)
 
+#define IS_OUTDATED_TLS_LE_RELOC(R_TYPE)  \
+  ((R_TYPE) == R_LARCH_TLS_LE_HI20	  \
+   || (R_TYPE) == R_LARCH_TLS_LE_LO12	  \
+   || (R_TYPE) == R_LARCH_TLS_LE64_LO20	  \
+   || (R_TYPE) == R_LARCH_TLS_LE64_HI12)
+
 /* Generate a PLT header.  */
 
 static bool
@@ -642,15 +646,20 @@ loongarch_reloc_got_type (unsigned int r_type)
 
 /* Return true if tls type transition can be performed.  */
 static bool
-loongarch_can_relax_tls (struct bfd_link_info *info, unsigned int r_type,
-			 struct elf_link_hash_entry *h, bfd *input_bfd,
-			 unsigned long r_symndx)
+loongarch_can_trans_tls (bfd *input_bfd,
+			 struct bfd_link_info *info,
+			 struct elf_link_hash_entry *h,
+			 const Elf_Internal_Rela *rel,
+			 unsigned int r_type)
 {
   char symbol_tls_type;
   unsigned int reloc_got_type;
+  unsigned int r_symndx = ELFNN_R_SYM (rel->r_info);
 
-  if (! (IS_LOONGARCH_TLS_DESC_RELOC (r_type)
-	 || IS_LOONGARCH_TLS_IE_RELOC (r_type)))
+  /* Only TLS DESC/IE in normal code mode will perform type
+     transition.  */
+  if (! (IS_LOONGARCH_TLS_TRANS_RELOC (r_type)
+	  && ELFNN_R_TYPE ((rel + 1)->r_info) == R_LARCH_RELAX))
     return false;
 
   symbol_tls_type = _bfd_loongarch_elf_tls_type (input_bfd, h, r_symndx);
@@ -707,11 +716,13 @@ loongarch_tls_transition_without_check (struct bfd_link_info *info,
 }
 
 static unsigned int
-loongarch_tls_transition (struct bfd_link_info *info, unsigned int r_type,
-			  struct elf_link_hash_entry *h, bfd *input_bfd,
-			  unsigned long r_symndx)
+loongarch_tls_transition (bfd *input_bfd,
+			  struct bfd_link_info *info,
+			  struct elf_link_hash_entry *h,
+			  const Elf_Internal_Rela *rel,
+			  unsigned int r_type)
 {
-  if (! loongarch_can_relax_tls (info, r_type, h, input_bfd,r_symndx))
+  if (! loongarch_can_trans_tls (input_bfd, info, h, rel, r_type))
     return r_type;
 
   return loongarch_tls_transition_without_check (info, r_type, h);
@@ -818,7 +829,7 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       int need_dynreloc = 0;
       int only_need_pcrel = 0;
 
-      r_type = loongarch_tls_transition (info, r_type, h, abfd, r_symndx);
+      r_type = loongarch_tls_transition (abfd, info, h, rel, r_type);
       switch (r_type)
 	{
 	case R_LARCH_GOT_PC_HI20:
@@ -2534,95 +2545,6 @@ loongarch_reloc_is_fatal (struct bfd_link_info *info,
       relocation += 0x100000000;			\
   })
 
-/* Transition instruction sequence to relax instruction sequence.  */
-static bool
-loongarch_tls_relax (bfd *abfd, asection *sec, Elf_Internal_Rela *rel,
-		    int r_type, struct elf_link_hash_entry *h,
-		    struct bfd_link_info *info)
-{
-  bool local_exec = bfd_link_executable (info)
-		    && SYMBOL_REFERENCES_LOCAL (info, h);
-  bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
-  unsigned long insn;
-
-  switch (r_type)
-    {
-      case R_LARCH_TLS_DESC_PC_HI20:
-	if (local_exec)
-	    /* DESC -> LE relaxation:
-	       pcalalau12i $a0,%desc_pc_hi20(var) =>
-	       lu12i.w $a0,%le_hi20(var)
-	    */
-	    bfd_put (32, abfd, LARCH_LU12I_W | LARCH_RD_A0,
-		     contents + rel->r_offset);
-
-	/* DESC -> IE relaxation:
-	   pcalalau12i $a0,%desc_pc_hi20(var) =>
-	   pcalalau12i $a0,%ie_pc_hi20(var)
-	*/
-	return true;
-
-      case R_LARCH_TLS_DESC_PC_LO12:
-	if (local_exec)
-	  {
-	    /* DESC -> LE relaxation:
-	       addi.d $a0,$a0,%desc_pc_lo12(var) =>
-	       ori  $a0,$a0,le_lo12(var)
-	    */
-	    insn = LARCH_ORI | LARCH_RD_RJ_A0;
-	    bfd_put (32, abfd, LARCH_ORI | LARCH_RD_RJ_A0,
-		     contents + rel->r_offset);
-	  }
-	else
-	  {
-	    /* DESC -> IE relaxation:
-	       addi.d $a0,$a0,%desc_pc_lo12(var) =>
-	       ld.d $a0,$a0,%%ie_pc_lo12
-	    */
-	    bfd_put (32, abfd, LARCH_LD_D | LARCH_RD_RJ_A0,
-		     contents + rel->r_offset);
-	  }
-	return true;
-
-      case R_LARCH_TLS_DESC_LD:
-      case R_LARCH_TLS_DESC_CALL:
-	/* DESC -> LE/IE relaxation:
-	   ld.d $ra,$a0,%desc_ld(var) => NOP
-	   jirl $ra,$ra,%desc_call(var) => NOP
-	*/
-	bfd_put (32, abfd, LARCH_NOP, contents + rel->r_offset);
-	return true;
-
-      case R_LARCH_TLS_IE_PC_HI20:
-	if (local_exec)
-	  {
-	    /* IE -> LE relaxation:
-	       pcalalau12i $rd,%ie_pc_hi20(var) =>
-	       lu12i.w $rd,%le_hi20(var)
-	    */
-	    insn = bfd_getl32 (contents + rel->r_offset);
-	    bfd_put (32, abfd, LARCH_LU12I_W | (insn & 0x1f),
-		     contents + rel->r_offset);
-	  }
-	return true;
-
-      case R_LARCH_TLS_IE_PC_LO12:
-	if (local_exec)
-	  {
-	    /* IE -> LE relaxation:
-	       ld.d $rd,$rj,%%ie_pc_lo12 =>
-	       ori  $rd,$rj,le_lo12(var)
-	    */
-	    insn = bfd_getl32 (contents + rel->r_offset);
-	    bfd_put (32, abfd, LARCH_ORI | (insn & 0x3ff),
-		     contents + rel->r_offset);
-	  }
-	return true;
-    }
-
-  return false;
-}
-
 
 static int
 loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
@@ -2657,7 +2579,6 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
       const char *name;
       bfd_reloc_status_type r = bfd_reloc_ok;
       bool is_ie, is_desc, is_undefweak, unresolved_reloc, defined_local;
-      unsigned int relaxed_r_type;
       bool resolved_local, resolved_dynly, resolved_to_const;
       char tls_type;
       bfd_vma relocation, off, ie_off, desc_off;
@@ -2789,16 +2710,6 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 
       BFD_ASSERT (!resolved_local || defined_local);
 
-      relaxed_r_type = loongarch_tls_transition (info, r_type, h, input_bfd, r_symndx);
-      if (relaxed_r_type != r_type)
-      {
-	howto = loongarch_elf_rtype_to_howto (input_bfd, relaxed_r_type);
-	BFD_ASSERT (howto != NULL);
-
-	if (loongarch_tls_relax (input_bfd, input_section, rel, r_type, h, info))
-	  r_type = relaxed_r_type;
-      }
-
       is_desc = false;
       is_ie = false;
       switch (r_type)
@@ -4118,6 +4029,113 @@ loongarch_relax_delete_bytes (bfd *abfd,
 
   return true;
 }
+
+/* Start perform TLS type transition.
+   Currently there are three cases of relocation handled here:
+   DESC -> IE, DEC -> LE and IE -> LE.  */
+static bool
+loongarch_tls_perform_trans (bfd *abfd, asection *sec,
+			   Elf_Internal_Rela *rel,
+			   struct elf_link_hash_entry *h,
+			   struct bfd_link_info *info)
+{
+  unsigned long insn;
+  bool local_exec = bfd_link_executable (info)
+		      && SYMBOL_REFERENCES_LOCAL (info, h);
+  bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
+  unsigned long r_type = ELFNN_R_TYPE (rel->r_info);
+  unsigned long r_symndx = ELFNN_R_SYM (rel->r_info);
+
+  switch (r_type)
+    {
+      case R_LARCH_TLS_DESC_PC_HI20:
+	if (local_exec)
+	  {
+	    /* DESC -> LE relaxation:
+	       pcalalau12i $a0,%desc_pc_hi20(var) =>
+	       lu12i.w $a0,%le_hi20(var)
+	    */
+	    bfd_put (32, abfd, LARCH_LU12I_W | LARCH_RD_A0,
+		contents + rel->r_offset);
+	    rel->r_info = ELFNN_R_INFO (r_symndx, R_LARCH_TLS_LE_HI20);
+	  }
+	else
+	  {
+	    /* DESC -> IE relaxation:
+	       pcalalau12i $a0,%desc_pc_hi20(var) =>
+	       pcalalau12i $a0,%ie_pc_hi20(var)
+	    */
+	    rel->r_info = ELFNN_R_INFO (r_symndx, R_LARCH_TLS_IE_PC_HI20);
+	  }
+	return true;
+
+      case R_LARCH_TLS_DESC_PC_LO12:
+	if (local_exec)
+	  {
+	    /* DESC -> LE relaxation:
+	       addi.d $a0,$a0,%desc_pc_lo12(var) =>
+	       ori  $a0,$a0,le_lo12(var)
+	    */
+	    insn = LARCH_ORI | LARCH_RD_RJ_A0;
+	    bfd_put (32, abfd, LARCH_ORI | LARCH_RD_RJ_A0,
+		contents + rel->r_offset);
+	    rel->r_info = ELFNN_R_INFO (r_symndx, R_LARCH_TLS_LE_LO12);
+	  }
+	else
+	  {
+	    /* DESC -> IE relaxation:
+	       addi.d $a0,$a0,%desc_pc_lo12(var) =>
+	       ld.d $a0,$a0,%ie_pc_lo12(var)
+	    */
+	    bfd_put (32, abfd, LARCH_LD_D | LARCH_RD_RJ_A0,
+		contents + rel->r_offset);
+	    rel->r_info = ELFNN_R_INFO (r_symndx, R_LARCH_TLS_IE_PC_LO12);
+	  }
+	return true;
+
+      case R_LARCH_TLS_DESC_LD:
+      case R_LARCH_TLS_DESC_CALL:
+	/* DESC -> LE/IE relaxation:
+	   ld.d $ra,$a0,%desc_ld(var) => (delete)
+	   jirl $ra,$ra,%desc_call(var) => (delete)
+	*/
+	rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
+	loongarch_relax_delete_bytes (abfd, sec, rel->r_offset, 4, info);
+	return true;
+
+      case R_LARCH_TLS_IE_PC_HI20:
+	if (local_exec)
+	  {
+	    /* IE -> LE relaxation:
+	       pcalalau12i $rd,%ie_pc_hi20(var) =>
+	       lu12i.w $rd,%le_hi20(var)
+	    */
+	    insn = bfd_getl32 (contents + rel->r_offset);
+	    bfd_put (32, abfd, LARCH_LU12I_W | (insn & 0x1f),
+		contents + rel->r_offset);
+	    rel->r_info = ELFNN_R_INFO (r_symndx, R_LARCH_TLS_LE_HI20);
+	  }
+	return true;
+
+      case R_LARCH_TLS_IE_PC_LO12:
+	if (local_exec)
+	  {
+	    /* IE -> LE relaxation:
+	       ld.d $rd,$rj,%%ie_pc_lo12(var) =>
+	       ori  $rd,$rj,le_lo12(var)
+	    */
+	    insn = bfd_getl32 (contents + rel->r_offset);
+	    bfd_put (32, abfd, LARCH_ORI | (insn & 0x3ff),
+		contents + rel->r_offset);
+	    rel->r_info = ELFNN_R_INFO (r_symndx, R_LARCH_TLS_LE_LO12);
+	  }
+	return true;
+    }
+
+  return false;
+}
+
+
 /*  Relax tls le, mainly relax the process of getting TLS le symbolic addresses.
   there are three situations in which an assembly instruction sequence needs to
   be relaxed:
@@ -4154,6 +4172,21 @@ loongarch_relax_delete_bytes (bfd *abfd,
   lu12i.w    $rd,%le_hi20_r (sym)	 ==> (instruction deleted)
   add.{w/d}  $rd,$rd,$tp,%le_add_r (sym) ==> (instruction deleted)
   addi.{w/d} $rs,$rd,%le_lo12_r (sym)    ==> addi.{w/d} $rs,$tp,%le_lo12_r (sym)
+
+
+  For relocation of all old LE instruction sequences, whether it is
+  a normal code model or an extreme code model, relaxation will be
+  performed when the relaxation conditions are met.
+
+  nomal code model:
+  lu12i.w   $rd,%le_hi20(sym)	    => (deleted)
+  ori	    $rd,$rd,le_lo12(sym)    => ori  $rd,$zero,le_lo12(sym)
+
+  extreme code model:
+  lu12i.w   $rd,%le_hi20(sym)	    => (deleted)
+  ori	    $rd,$rd,%le_lo12(sym)   => ori  $rd,$zero,le_lo12(sym)
+  lu32i.d   $rd,%le64_lo20(sym)	    => (deleted)
+  lu52i.d   $rd,$rd,%le64_hi12(sym) => (deleted)
 */
 static bool
 loongarch_relax_tls_le (bfd *abfd, asection *sec,
@@ -4165,31 +4198,56 @@ loongarch_relax_tls_le (bfd *abfd, asection *sec,
   uint32_t insn = bfd_get (32, abfd, contents + rel->r_offset);
   static uint32_t insn_rj,insn_rd;
   symval = symval - elf_hash_table (link_info)->tls_sec->vma;
-  /* Whether the symbol offset is in the interval (offset < 0x800).  */
-  if (ELFNN_R_TYPE ((rel + 1)->r_info == R_LARCH_RELAX) && (symval < 0x800))
+  /* The old LE instruction sequence can be relaxed when the symbol offset
+     is smaller than the 12-bit range.  */
+  if (ELFNN_R_TYPE ((rel + 1)->r_info) == R_LARCH_RELAX && (symval <= 0xfff))
     {
       switch (ELFNN_R_TYPE (rel->r_info))
 	{
-	case R_LARCH_TLS_LE_HI20_R:
-	case R_LARCH_TLS_LE_ADD_R:
-	  /* delete insn.  */
-	  rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
-	  loongarch_relax_delete_bytes (abfd, sec, rel->r_offset, 4, link_info);
-	  break;
-	case R_LARCH_TLS_LE_LO12_R:
-	  /* Change rj to $tp.  */
-	  insn_rj = 0x2 << 5;
-	  /* Get rd register.  */
-	  insn_rd = insn & 0x1f;
-	  /* Write symbol offset.  */
-	  symval <<= 10;
-	  /* Writes the modified instruction.  */
-	  insn = insn & 0xffc00000;
-	  insn = insn | symval | insn_rj | insn_rd;
-	  bfd_put (32, abfd, insn, contents + rel->r_offset);
-	  break;
-	default:
-	  break;
+	  /*if offset < 0x800, then perform the new le instruction
+	    sequence relax.  */
+	  case R_LARCH_TLS_LE_HI20_R:
+	  case R_LARCH_TLS_LE_ADD_R:
+	    /* delete insn.  */
+	    if (symval < 0x800)
+	      {
+		rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
+		loongarch_relax_delete_bytes (abfd, sec, rel->r_offset,
+		    4, link_info);
+	      }
+	    break;
+
+	  case R_LARCH_TLS_LE_LO12_R:
+	    if (symval < 0x800)
+	      {
+		/* Change rj to $tp.  */
+		insn_rj = 0x2 << 5;
+		/* Get rd register.  */
+		insn_rd = insn & 0x1f;
+		/* Write symbol offset.  */
+		symval <<= 10;
+		/* Writes the modified instruction.  */
+		insn = insn & 0xffc00000;
+		insn = insn | symval | insn_rj | insn_rd;
+		bfd_put (32, abfd, insn, contents + rel->r_offset);
+	      }
+	    break;
+
+	  case R_LARCH_TLS_LE_HI20:
+	  case R_LARCH_TLS_LE64_LO20:
+	  case R_LARCH_TLS_LE64_HI12:
+	    rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
+	    loongarch_relax_delete_bytes (abfd, sec, rel->r_offset,
+					  4, link_info);
+	    break;
+
+	  case R_LARCH_TLS_LE_LO12:
+	    bfd_put (32, abfd, LARCH_ORI | (insn & 0x1f),
+		    contents + rel->r_offset);
+	    break;
+
+	  default:
+	    break;
 	}
     }
   return true;
@@ -4540,7 +4598,7 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
 	 R_LARCH_CALL36: symval is the symbol address for local symbols,
 	 or the PLT entry address of the symbol. (Todo)
 	 R_LARCHL_TLS_LD/GD/DESC_PC_HI20: symval is the GOT entry address
-	 of the symbol.  */
+	 of the symbol if transition is not possible.  */
       if (r_symndx < symtab_hdr->sh_info)
 	{
 	  Elf_Internal_Sym *sym = (Elf_Internal_Sym *)symtab_hdr->contents
@@ -4550,20 +4608,17 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
 
 	  if (R_LARCH_TLS_LD_PC_HI20 == r_type
 	      || R_LARCH_TLS_GD_PC_HI20 == r_type
-	      || R_LARCH_TLS_DESC_PC_HI20 == r_type)
+	      || (R_LARCH_TLS_DESC_PC_HI20 == r_type
+		  && ! loongarch_can_trans_tls (abfd, info, h,
+						  rel, r_type)))
 	    {
-	      if (loongarch_can_relax_tls (info, r_type, h, abfd, r_symndx))
-		continue;
-	      else
-		{
-		  sym_sec = htab->elf.sgot;
-		  symval = elf_local_got_offsets (abfd)[r_symndx];
-		  char tls_type = _bfd_loongarch_elf_tls_type (abfd, h,
-								r_symndx);
-		  if (R_LARCH_TLS_DESC_PC_HI20 == r_type
-			&& GOT_TLS_GD_BOTH_P (tls_type))
-		    symval += 2 * GOT_ENTRY_SIZE;
-		}
+	      sym_sec = htab->elf.sgot;
+	      symval = elf_local_got_offsets (abfd)[r_symndx];
+	      char tls_type = _bfd_loongarch_elf_tls_type (abfd, h,
+							    r_symndx);
+	      if (R_LARCH_TLS_DESC_PC_HI20 == r_type
+		    && GOT_TLS_GD_BOTH_P (tls_type))
+		symval += 2 * GOT_ENTRY_SIZE;
 	    }
 	  else if (sym->st_shndx == SHN_UNDEF || R_LARCH_ALIGN == r_type)
 	    {
@@ -4594,20 +4649,17 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
 	     shared object.  */
 	  if (R_LARCH_TLS_LD_PC_HI20 == r_type
 	      || R_LARCH_TLS_GD_PC_HI20 == r_type
-	      || R_LARCH_TLS_DESC_PC_HI20 == r_type)
+	      || (R_LARCH_TLS_DESC_PC_HI20 == r_type
+		  && !loongarch_can_trans_tls (abfd, info, h,
+						rel, r_type)))
 	    {
-	      if (loongarch_can_relax_tls (info, r_type, h, abfd, r_symndx))
-		continue;
-	      else
-		{
-		  sym_sec = htab->elf.sgot;
-		  symval = h->got.offset;
-		  char tls_type = _bfd_loongarch_elf_tls_type (abfd, h,
-								r_symndx);
-		  if (R_LARCH_TLS_DESC_PC_HI20 == r_type
-			&& GOT_TLS_GD_BOTH_P (tls_type))
-		    symval += 2 * GOT_ENTRY_SIZE;
-		}
+	      sym_sec = htab->elf.sgot;
+	      symval = h->got.offset;
+	      char tls_type = _bfd_loongarch_elf_tls_type (abfd, h,
+							    r_symndx);
+	      if (R_LARCH_TLS_DESC_PC_HI20 == r_type
+		    && GOT_TLS_GD_BOTH_P (tls_type))
+		symval += 2 * GOT_ENTRY_SIZE;
 	    }
 	  else if ((h->root.type == bfd_link_hash_defined
 		  || h->root.type == bfd_link_hash_defweak)
@@ -4652,6 +4704,17 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
 
       symval += sec_addr (sym_sec);
 
+      /* If the conditions for tls type transition are met,
+	 type transition is performed instead of relax.
+	 DESC -> IE/LE will delete the following two extra
+	 instructions. */
+      if (IS_LOONGARCH_TLS_TRANS_RELOC (r_type)
+	  && loongarch_can_trans_tls (abfd, info, h, rel, r_type))
+	{
+	  loongarch_tls_perform_trans (abfd, sec, rel, h, info);
+	  r_type = ELFNN_R_TYPE (rel->r_info);
+	}
+
       switch (r_type)
 	{
 	case R_LARCH_ALIGN:
@@ -4670,6 +4733,10 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
 	case R_LARCH_TLS_LE_HI20_R:
 	case R_LARCH_TLS_LE_LO12_R:
 	case R_LARCH_TLS_LE_ADD_R:
+	case R_LARCH_TLS_LE_HI20:
+	case R_LARCH_TLS_LE_LO12:
+	case R_LARCH_TLS_LE64_LO20:
+	case R_LARCH_TLS_LE64_HI12:
 	  if (0 == info->relax_pass && (i + 2) <= sec->reloc_count)
 	    loongarch_relax_tls_le (abfd, sec, rel, info, symval);
 	  break;
diff --git a/gas/config/tc-loongarch.c b/gas/config/tc-loongarch.c
index e6a9901673f..e4e28cb702d 100644
--- a/gas/config/tc-loongarch.c
+++ b/gas/config/tc-loongarch.c
@@ -713,7 +713,11 @@ loongarch_args_parser_can_match_arg_helper (char esc_ch1, char esc_ch2,
 
 	      if (LARCH_opts.relax
 		    && (BFD_RELOC_LARCH_TLS_LE_HI20_R == reloc_type
-			|| BFD_RELOC_LARCH_TLS_LE_LO12_R == reloc_type))
+			|| BFD_RELOC_LARCH_TLS_LE_LO12_R == reloc_type
+			|| BFD_RELOC_LARCH_TLS_LE_HI20 == reloc_type
+			|| BFD_RELOC_LARCH_TLS_LE_LO12 == reloc_type
+			|| BFD_RELOC_LARCH_TLS_LE64_LO20 == reloc_type
+			|| BFD_RELOC_LARCH_TLS_LE64_HI12 == reloc_type))
 		{
 		  ip->reloc_info[ip->reloc_num].type = BFD_RELOC_LARCH_RELAX;
 		  ip->reloc_info[ip->reloc_num].value = const_0;
@@ -721,8 +725,12 @@ loongarch_args_parser_can_match_arg_helper (char esc_ch1, char esc_ch2,
 		}
 
 	      /* Only one register macros (used in normal code model)
-		 emit R_LARCH_RELAX.  */
+		 emit R_LARCH_RELAX.
+		 LARCH_opts.ase_labs and LARCH_opts.ase_gabs are used
+		 to generate the code model of absolute addresses, and
+		 we do not relax this code model. */
 	      if (LARCH_opts.relax && (ip->expand_from_macro & 1)
+		    && !(LARCH_opts.ase_labs | LARCH_opts.ase_gabs)
 		    && (BFD_RELOC_LARCH_PCALA_HI20 == reloc_type
 			|| BFD_RELOC_LARCH_PCALA_LO12 == reloc_type
 			|| BFD_RELOC_LARCH_GOT_PC_HI20 == reloc_type
@@ -730,7 +738,11 @@ loongarch_args_parser_can_match_arg_helper (char esc_ch1, char esc_ch2,
 			|| BFD_RELOC_LARCH_TLS_LD_PC_HI20 == reloc_type
 			|| BFD_RELOC_LARCH_TLS_GD_PC_HI20 == reloc_type
 			|| BFD_RELOC_LARCH_TLS_DESC_PC_HI20 == reloc_type
-			|| BFD_RELOC_LARCH_TLS_DESC_PC_LO12 == reloc_type))
+			|| BFD_RELOC_LARCH_TLS_DESC_PC_LO12 == reloc_type
+			|| BFD_RELOC_LARCH_TLS_DESC_LD == reloc_type
+			|| BFD_RELOC_LARCH_TLS_DESC_CALL == reloc_type
+			|| BFD_RELOC_LARCH_TLS_IE_PC_HI20 == reloc_type
+			|| BFD_RELOC_LARCH_TLS_IE_PC_LO12 == reloc_type))
 		{
 		  ip->reloc_info[ip->reloc_num].type = BFD_RELOC_LARCH_RELAX;
 		  ip->reloc_info[ip->reloc_num].value = const_0;
@@ -1077,7 +1089,11 @@ append_fixp_and_insn (struct loongarch_cl_insn *ip)
      if (symbol_get_frag (to) == symbol_get_frag (from)))
 
      For macro instructions, only the first instruction expanded from macro
-     need to start a new frag.  */
+     need to start a new frag.
+     Since the relocations of the normal code model and the extreme code model
+     of the old LE instruction sequence are the same, it is impossible to
+     distinguish which code model it is based on relocation alone, so the
+     extreme code model has to be relaxed.  */
   if (LARCH_opts.relax
       && (BFD_RELOC_LARCH_PCALA_HI20 == reloc_info[0].type
 	  || BFD_RELOC_LARCH_GOT_PC_HI20 == reloc_info[0].type
@@ -1085,7 +1101,12 @@ append_fixp_and_insn (struct loongarch_cl_insn *ip)
 	  || BFD_RELOC_LARCH_TLS_LE_ADD_R == reloc_info[0].type
 	  || BFD_RELOC_LARCH_TLS_LD_PC_HI20 == reloc_info[0].type
 	  || BFD_RELOC_LARCH_TLS_GD_PC_HI20 == reloc_info[0].type
-	  || BFD_RELOC_LARCH_TLS_DESC_PC_HI20 == reloc_info[0].type))
+	  || BFD_RELOC_LARCH_TLS_DESC_PC_HI20 == reloc_info[0].type
+	  || BFD_RELOC_LARCH_TLS_IE_PC_HI20 == reloc_info[0].type
+	  || BFD_RELOC_LARCH_TLS_LE_HI20 == reloc_info[0].type
+	  || BFD_RELOC_LARCH_TLS_LE_LO12 == reloc_info[0].type
+	  || BFD_RELOC_LARCH_TLS_LE64_LO20 == reloc_info[0].type
+	  || BFD_RELOC_LARCH_TLS_LE64_HI12 == reloc_info[0].type))
     {
       frag_wane (frag_now);
       frag_new (0);
