diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index 024c5d4cd96..4e6ef4f61c7 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -3852,11 +3852,21 @@ loongarch_relax_align (bfd *abfd, asection *sec,
 			bfd_vma symval)
 {
   bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
-  bfd_vma alignment = 1, pos;
-  while (alignment <= rel->r_addend)
-    alignment *= 2;
+  bfd_vma alignment = 1, pos, max = 0, addend;
 
-  symval -= rel->r_addend;
+  int index = ELFNN_R_SYM (rel->r_info);
+  if (index > 0)
+    {
+      alignment = 1 << (rel->r_addend & 0xff);
+      max = rel->r_addend >> 8;
+    }
+  else
+    while (alignment <= rel->r_addend)
+      alignment *= 2;
+
+  addend = alignment - 4;
+
+  symval -= addend;
   bfd_vma aligned_addr = ((symval - 1) & ~(alignment - 1)) + alignment;
   bfd_vma nop_bytes = aligned_addr - symval;
 
@@ -3864,22 +3874,25 @@ loongarch_relax_align (bfd *abfd, asection *sec,
   sec->sec_flg0 = true;
 
   /* Make sure there are enough NOPs to actually achieve the alignment.  */
-  if (rel->r_addend < nop_bytes)
+  if (addend < nop_bytes)
     {
       _bfd_error_handler
 	(_("%pB(%pA+%#" PRIx64 "): %" PRId64 " bytes required for alignment "
 	   "to %" PRId64 "-byte boundary, but only %" PRId64 " present"),
 	 abfd, sym_sec, (uint64_t) rel->r_offset,
-	 (int64_t) nop_bytes, (int64_t) alignment, (int64_t) rel->r_addend);
+	 (int64_t) nop_bytes, (int64_t) alignment, (int64_t) addend);
       bfd_set_error (bfd_error_bad_value);
       return false;
     }
 
-  /* Delete the reloc.  */
   rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
 
+  if (max > 0 && nop_bytes > max)
+    return loongarch_relax_delete_bytes (abfd, sec, rel->r_offset,
+					  addend, link_info);
+
   /* If the number of NOPs is already correct, there's nothing to do.  */
-  if (nop_bytes == rel->r_addend)
+  if (nop_bytes == addend)
     return true;
 
   /* Write as many LOONGARCH NOPs as we need.  */
@@ -3888,7 +3901,7 @@ loongarch_relax_align (bfd *abfd, asection *sec,
 
   /* Delete the excess NOPs.  */
   return loongarch_relax_delete_bytes (abfd, sec, rel->r_offset + nop_bytes,
-				   rel->r_addend - nop_bytes, link_info);
+					addend - nop_bytes, link_info);
 }
 
 static bool
@@ -3939,6 +3952,7 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
       asection *sym_sec;
       bfd_vma symval;
       unsigned long r_symndx = ELFNN_R_SYM (rel->r_info);
+      unsigned long r_type = ELFNN_R_TYPE (rel->r_info);
       bool local_got = false;
       char symtype;
       struct elf_link_hash_entry *h = NULL;
@@ -3950,7 +3964,7 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
 	  if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
 	    continue;
 
-	  if (sym->st_shndx == SHN_UNDEF)
+	  if (sym->st_shndx == SHN_UNDEF  || R_LARCH_ALIGN == r_type)
 	    {
 	      sym_sec = sec;
 	      symval = rel->r_offset;
@@ -4005,12 +4019,21 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
 	   if (symtype != STT_SECTION)
 	     symval += rel->r_addend;
 	}
+      /* For R_LARCH_ALIGN, symval is sec_addr(sym_sec) + rel->r_offset
+	 + (alingmeng - 4).
+	 If r_symndx is 0, alignmeng-4 is r_addend.
+	 If r_symndx > 0, alignment-4 is 2^(r_addend & 0xff)-4.  */
+      if (R_LARCH_ALIGN == r_type)
+	if (r_symndx > 0)
+	  symval += ((1 << (rel->r_addend & 0xff)) - 4);
+	else
+	  symval += rel->r_addend;
       else
 	symval += rel->r_addend;
 
       symval += sec_addr (sym_sec);
 
-      switch (ELFNN_R_TYPE (rel->r_info))
+      switch (r_type)
 	{
 	case R_LARCH_ALIGN:
 	  if (1 == info->relax_pass)
diff --git a/gas/config/tc-loongarch.c b/gas/config/tc-loongarch.c
index 59232832cf7..99c0ac47418 100644
--- a/gas/config/tc-loongarch.c
+++ b/gas/config/tc-loongarch.c
@@ -1648,12 +1648,14 @@ loongarch_make_nops (char *buf, bfd_vma bytes)
    the correct alignment now because of other linker relaxations.  */
 
 bool
-loongarch_frag_align_code (int n)
+loongarch_frag_align_code (int n, int max)
 {
   bfd_vma bytes = (bfd_vma) 1 << n;
   bfd_vma insn_alignment = 4;
   bfd_vma worst_case_bytes = bytes - insn_alignment;
   char *nops;
+
+  symbolS *s;
   expressionS ex;
 
   /* If we are moving to a smaller alignment than the instruction size, then no
@@ -1667,8 +1669,13 @@ loongarch_frag_align_code (int n)
 
   nops = frag_more (worst_case_bytes);
 
-  ex.X_op = O_constant;
-  ex.X_add_number = worst_case_bytes;
+  s = symbol_find (".Lla-relax-align");
+  if (s == NULL)
+     s = colon (".Lla-relax-align");
+  ex.X_add_symbol = s;
+
+  ex.X_op = O_symbol;
+  ex.X_add_number = (max << 8) | n;
 
   loongarch_make_nops (nops, worst_case_bytes);
 
diff --git a/gas/config/tc-loongarch.h b/gas/config/tc-loongarch.h
index 4afa38422d6..194ee107c0a 100644
--- a/gas/config/tc-loongarch.h
+++ b/gas/config/tc-loongarch.h
@@ -49,11 +49,11 @@ extern int loongarch_relax_frag (asection *, struct frag *, long);
 #define md_undefined_symbol(name) (0)
 #define md_operand(x)
 
-extern bool loongarch_frag_align_code (int);
+extern bool loongarch_frag_align_code (int, int);
 #define md_do_align(N, FILL, LEN, MAX, LABEL)				\
   if ((N) != 0 && !(FILL) && !need_pass_2 && subseg_text_p (now_seg))	\
     {									\
-      if (loongarch_frag_align_code (N))				\
+      if (loongarch_frag_align_code (N, MAX))				\
 	goto LABEL;							\
     }
 
diff --git a/gas/testsuite/gas/loongarch/relax_align.d b/gas/testsuite/gas/loongarch/relax_align.d
index 1810eb4cae7..d870e983bb6 100644
--- a/gas/testsuite/gas/loongarch/relax_align.d
+++ b/gas/testsuite/gas/loongarch/relax_align.d
@@ -1,4 +1,4 @@
-#as:
+#as: --no-warn
 #objdump: -dr
 #skip: loongarch32-*-*
 
@@ -7,20 +7,31 @@
 
 Disassembly of section .text:
 
-00000000.* <L1>:
-[ 	]+0:[ 	]+1a000004[ 	]+pcalau12i[ 	]+\$a0,[ 	]+0
-[ 	]+0:[ 	]+R_LARCH_PCALA_HI20[ 	]+L1
-[ 	]+0:[ 	]+R_LARCH_RELAX[ 	]+\*ABS\*
-[ 	]+4:[ 	]+02c00084[ 	]+addi\.d[ 	]+\$a0,[ 	]+\$a0,[ 	]+0
-[ 	]+4:[ 	]+R_LARCH_PCALA_LO12[ 	]+L1
-[ 	]+4:[ 	]+R_LARCH_RELAX[ 	]+\*ABS\*
-[ 	]+8:[ 	]+03400000[ 	]+nop[ 	]+
-[ 	]+8:[ 	]+R_LARCH_ALIGN[ 	]+\*ABS\*\+0xc
-[ 	]+c:[ 	]+03400000[ 	]+nop[ 	]+
-[ 	]+10:[ 	]+03400000[ 	]+nop[ 	]+
-[ 	]+14:[ 	]+1a000004[ 	]+pcalau12i[ 	]+\$a0,[ 	]+0
-[ 	]+14:[ 	]+R_LARCH_PCALA_HI20[ 	]+L1
-[ 	]+14:[ 	]+R_LARCH_RELAX[ 	]+\*ABS\*
-[ 	]+18:[ 	]+02c00084[ 	]+addi\.d[ 	]+\$a0,[ 	]+\$a0,[ 	]+0
-[ 	]+18:[ 	]+R_LARCH_PCALA_LO12[ 	]+L1
-[ 	]+18:[ 	]+R_LARCH_RELAX[ 	]+\*ABS\*
+.* <.Lla-relax-align-0x14>:
+[ 	]+0:[ 	]+1a000004[ 	]+pcalau12i[ 	]+\$a0, 0
+[ 	]+0: R_LARCH_PCALA_HI20[ 	]+L1
+[ 	]+0: R_LARCH_RELAX[ 	]+\*ABS\*
+[ 	]+4:[ 	]+02c00084[ 	]+addi.d[ 	]+\$a0, \$a0, 0
+[ 	]+4: R_LARCH_PCALA_LO12[ 	]+L1
+[ 	]+4: R_LARCH_RELAX[ 	]+\*ABS\*
+[ 	]+8:[ 	]+03400000[ 	]+nop.*
+[ 	]+8: R_LARCH_ALIGN[ 	]+.Lla-relax-align\+0x4
+[ 	]+c:[ 	]+03400000[ 	]+nop.*
+[ 	]+10:[ 	]+03400000[ 	]+nop.*
+0000000000000014 <.Lla-relax-align>:
+[ 	]+14:[ 	]+1a000004[ 	]+pcalau12i[ 	]+\$a0, 0
+[ 	]+14: R_LARCH_PCALA_HI20[ 	]+L1
+[ 	]+14: R_LARCH_RELAX[ 	]+\*ABS\*
+[ 	]+18:[ 	]+02c00084[ 	]+addi.d[ 	]+\$a0, \$a0, 0
+[ 	]+18: R_LARCH_PCALA_LO12[ 	]+L1
+[ 	]+18: R_LARCH_RELAX[ 	]+\*ABS\*
+[ 	]+1c:[ 	]+03400000[ 	]+nop.*
+[ 	]+1c: R_LARCH_ALIGN[ 	]+.Lla-relax-align\+0x404
+[ 	]+20:[ 	]+03400000[ 	]+nop.*
+[ 	]+24:[ 	]+03400000[ 	]+nop.*
+[ 	]+28:[ 	]+1a000004[ 	]+pcalau12i[ 	]+\$a0, 0
+[ 	]+28: R_LARCH_PCALA_HI20[ 	]+L1
+[ 	]+28: R_LARCH_RELAX[ 	]+\*ABS\*
+[ 	]+2c:[ 	]+02c00084[ 	]+addi.d[ 	]+\$a0, \$a0, 0
+[ 	]+2c: R_LARCH_PCALA_LO12[ 	]+L1
+[ 	]+2c: R_LARCH_RELAX[ 	]+\*ABS\*
diff --git a/gas/testsuite/gas/loongarch/relax_align.s b/gas/testsuite/gas/loongarch/relax_align.s
index 3880d783e79..c0177c88fc1 100644
--- a/gas/testsuite/gas/loongarch/relax_align.s
+++ b/gas/testsuite/gas/loongarch/relax_align.s
@@ -1,5 +1,7 @@
   .text
-L1:
+.L1:
   la.local $a0, L1
   .align 4
   la.local $a0, L1
+  .align 4, , 4
+  la.local $a0, L1
diff --git a/ld/testsuite/ld-loongarch-elf/relax-align.dd b/ld/testsuite/ld-loongarch-elf/relax-align.dd
index 5fce2255dda..37fdab18fab 100644
--- a/ld/testsuite/ld-loongarch-elf/relax-align.dd
+++ b/ld/testsuite/ld-loongarch-elf/relax-align.dd
@@ -1,7 +1,8 @@
 #...
 .*pcaddi.*
-.*pcaddi.*
 .*nop.*
+.*pcaddi.*
 .*nop.*
-.*0:.*pcaddi.*
+.*pcaddi.*
+.*pcaddi.*
 #pass
diff --git a/ld/testsuite/ld-loongarch-elf/relax-align.s b/ld/testsuite/ld-loongarch-elf/relax-align.s
index 9617c02d8e5..66dfea8f2c9 100644
--- a/ld/testsuite/ld-loongarch-elf/relax-align.s
+++ b/ld/testsuite/ld-loongarch-elf/relax-align.s
@@ -4,6 +4,9 @@
   .text
 L1:
   la.local $a0, L1
+  .align 3
   la.local $a0, L1
-  .align 4
+  .align 3, ,4
+  la.local $a0, L1
+  .align 3, ,2
   la.local $a0, L1
diff --git a/ld/testsuite/ld-loongarch-elf/relax.exp b/ld/testsuite/ld-loongarch-elf/relax.exp
index 24d79ed5c20..77323d8d7a3 100644
--- a/ld/testsuite/ld-loongarch-elf/relax.exp
+++ b/ld/testsuite/ld-loongarch-elf/relax.exp
@@ -121,7 +121,7 @@ if [istarget loongarch64-*-*] {
 	  [list \
 	      "loongarch relax-align" \
 	      "-e 0x0 -z relro" "" \
-	      "" \
+	      "--no-warn" \
 	      {relax-align.s} \
 	      [list \
 		  [list objdump -d relax-align.dd] \
