[2/2] LoongArch: bfd: Add counter to get real relax region

Message ID 20230711084931.18978-2-hejinyang@loongson.cn
State Unresolved
Headers
Series [1/2] LoongArch: bfd: Remove elf_seg_map condition in loongarch_elf_relax_section |

Checks

Context Check Description
snail/binutils-gdb-check warning Git am fail log

Commit Message

Jinyang He July 11, 2023, 8:49 a.m. UTC
  The relax action, loongarch_relax_pcala_addi and loongarch_relax_align,
may reduce the pc value of later instructions. Add counter to count
the number of bytes or instructions deleted. And recalculate the relax
region in loongarch_relax_pcala_addi.

bfd/ChangeLog:

	* elfnn-loongarch.c (loongarch_elf_relax_section): Add vars
	to count the deleted instructions and the maximum number of
	instructions that may be deleted due to R_LARCH_ALIGN.
	(loongarch_relax_pcala_addi): Adjust the relax decision range.

ld/ChangeLog:

	* testsuite/ld-loongarch-elf/relax.exp: Add test.
	* testsuite/ld-loongarch-elf/relax-edge1.s: New test.
	* testsuite/ld-loongarch-elf/relax-edge2.s: New test.
	* testsuite/ld-loongarch-elf/relax-edge1.dd: New test.
	* testsuite/ld-loongarch-elf/relax-edge2.dd: New test.
---
 bfd/elfnn-loongarch.c                        | 31 +++++++++++++++-----
 ld/testsuite/ld-loongarch-elf/relax-edge1.dd |  6 ++++
 ld/testsuite/ld-loongarch-elf/relax-edge1.s  | 25 ++++++++++++++++
 ld/testsuite/ld-loongarch-elf/relax-edge2.dd |  8 +++++
 ld/testsuite/ld-loongarch-elf/relax-edge2.s  | 15 ++++++++++
 ld/testsuite/ld-loongarch-elf/relax.exp      | 20 +++++++++++++
 6 files changed, 98 insertions(+), 7 deletions(-)
 create mode 100644 ld/testsuite/ld-loongarch-elf/relax-edge1.dd
 create mode 100644 ld/testsuite/ld-loongarch-elf/relax-edge1.s
 create mode 100644 ld/testsuite/ld-loongarch-elf/relax-edge2.dd
 create mode 100644 ld/testsuite/ld-loongarch-elf/relax-edge2.s
  

Patch

diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index 01f349a24..52f8ab764 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -3700,16 +3700,19 @@  loongarch_relax_delete_bytes (bfd *abfd,
 /* Relax pcalau12i,addi.d => pcaddi.  */
 static bool
 loongarch_relax_pcala_addi (bfd *abfd, asection *sec,
-		       Elf_Internal_Rela *rel_hi, bfd_vma symval)
+		       Elf_Internal_Rela *rel_hi, bfd_vma symval,
+		       uint32_t align_max_deleted, uint32_t *pcnt_deleted)
 {
   bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
   Elf_Internal_Rela *rel_lo = rel_hi + 2;
   uint32_t pca = bfd_get (32, abfd, contents + rel_hi->r_offset);
   uint32_t add = bfd_get (32, abfd, contents + rel_lo->r_offset);
   uint32_t rd = pca & 0x1f;
-  bfd_vma pc = sec_addr (sec) + rel_hi->r_offset;
+  bfd_vma pc = sec_addr (sec) + rel_hi->r_offset - *pcnt_deleted * 4;
   const uint32_t addi_d = 0x02c00000;
   const uint32_t pcaddi = 0x18000000;
+  bfd_signed_vma low = (bfd_signed_vma)(int32_t)0xffe00000;
+  bfd_signed_vma high = (bfd_signed_vma)(int32_t)0x1ffffc - align_max_deleted;
 
   /* Is pcalau12i + addi.d insns?  */
   if ((ELFNN_R_TYPE (rel_lo->r_info) != R_LARCH_PCALA_LO12)
@@ -3722,8 +3725,8 @@  loongarch_relax_pcala_addi (bfd *abfd, asection *sec,
       || (((add >> 5) & 0x1f) != rd)
       /* Can be relaxed to pcaddi?  */
       || (symval & 0x3) /* 4 bytes align.  */
-      || ((bfd_signed_vma)(symval - pc) < (bfd_signed_vma)(int32_t)0xffe00000)
-      || ((bfd_signed_vma)(symval - pc) > (bfd_signed_vma)(int32_t)0x1ffffc))
+      || ((bfd_signed_vma)(symval - pc) < low)
+      || ((bfd_signed_vma)(symval - pc) > high))
     return false;
 
   pca = pcaddi | rd;
@@ -3734,6 +3737,7 @@  loongarch_relax_pcala_addi (bfd *abfd, asection *sec,
 				 R_LARCH_PCREL20_S2);
   rel_lo->r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel_hi->r_info),
 				 R_LARCH_DELETE);
+  (*pcnt_deleted) += 1;
 
   return true;
 }
@@ -3840,6 +3844,7 @@  loongarch_elf_relax_section (bfd *abfd, asection *sec,
   struct bfd_elf_section_data *data = elf_section_data (sec);
   Elf_Internal_Rela *relocs;
   *again = false;
+  uint32_t cnt_deleted = 0, align_max_deleted = 0;
 
   if (bfd_link_relocatable (info)
       || sec->sec_flg0
@@ -3881,6 +3886,7 @@  loongarch_elf_relax_section (bfd *abfd, asection *sec,
       bool local_got = false;
       char symtype;
       struct elf_link_hash_entry *h = NULL;
+      bool relaxed = false;
 
       if (r_symndx < symtab_hdr->sh_info)
 	{
@@ -3954,6 +3960,8 @@  loongarch_elf_relax_section (bfd *abfd, asection *sec,
 	case R_LARCH_ALIGN:
 	  if (2 == info->relax_pass)
 	    loongarch_relax_align (abfd, sec, sym_sec, info, rel, symval);
+	  else if (0 == info->relax_pass)
+	    align_max_deleted += rel->r_addend;
 	  break;
 	case R_LARCH_DELETE:
 	  if (info->relax_pass == 1)
@@ -3961,23 +3969,32 @@  loongarch_elf_relax_section (bfd *abfd, asection *sec,
 	      loongarch_relax_delete_bytes (abfd, sec, rel->r_offset, 4, info);
 	      rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
 	    }
+	  else if (0 == info->relax_pass)
+	    cnt_deleted += 1;
 	  break;
 	case R_LARCH_PCALA_HI20:
 	  if (info->relax_pass == 0)
 	    {
 	      if (i + 4 > sec->reloc_count)
 		break;
-	      loongarch_relax_pcala_addi (abfd, sec, rel, symval);
+	      relaxed = loongarch_relax_pcala_addi (abfd, sec, rel, symval,
+						    align_max_deleted, &cnt_deleted);
+	      /* Skip the next R_LARCH_{RELAX, PCALA_LO12, RELAX} relocs. */
+	      if (relaxed)
+		i += 3;
 	    }
 	  break;
 	case R_LARCH_GOT_PC_HI20:
-	  if (local_got)
+	  if (info->relax_pass == 0 && local_got)
 	    {
 	      if (i + 4 > sec->reloc_count)
 		break;
 	      if (loongarch_relax_pcala_ld (abfd, sec, rel))
 		{
-		  loongarch_relax_pcala_addi (abfd, sec, rel, symval);
+		  relaxed = loongarch_relax_pcala_addi (abfd, sec, rel, symval,
+							align_max_deleted, &cnt_deleted);
+		  if (relaxed)
+		    i += 3;
 		}
 	    }
 	  break;
diff --git a/ld/testsuite/ld-loongarch-elf/relax-edge1.dd b/ld/testsuite/ld-loongarch-elf/relax-edge1.dd
new file mode 100644
index 000000000..92836e679
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relax-edge1.dd
@@ -0,0 +1,6 @@ 
+#...
+.*pcaddi.*
+.*pcalau12i.*
+.*addi.*
+.*pcaddi.*
+#pass
diff --git a/ld/testsuite/ld-loongarch-elf/relax-edge1.s b/ld/testsuite/ld-loongarch-elf/relax-edge1.s
new file mode 100644
index 000000000..df16c1384
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relax-edge1.s
@@ -0,0 +1,25 @@ 
+  .data
+  .type obj1, @object
+obj1:
+  .word 0
+  .size obj1, .-obj1
+
+  .space 8
+
+  .type obj2, @object
+obj2:
+  .word 0
+  .size obj2, .-obj2
+
+  .text
+main:
+  la.local $a0, obj1
+  la.local $a0, obj3
+  la.local $a0, obj2
+
+  .bss
+  .space 0x4
+  .type obj3, @object
+obj3:
+  .word 0
+  .size obj3, .-obj3
diff --git a/ld/testsuite/ld-loongarch-elf/relax-edge2.dd b/ld/testsuite/ld-loongarch-elf/relax-edge2.dd
new file mode 100644
index 000000000..5610cc8ed
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relax-edge2.dd
@@ -0,0 +1,8 @@ 
+#...
+.*nop.*
+.*nop.*
+.*nop.*
+.*nop.*
+.*pcalau12i.*
+.*addi.*
+#pass
diff --git a/ld/testsuite/ld-loongarch-elf/relax-edge2.s b/ld/testsuite/ld-loongarch-elf/relax-edge2.s
new file mode 100644
index 000000000..c2a42e705
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relax-edge2.s
@@ -0,0 +1,15 @@ 
+  .text
+main:
+  nop
+  nop
+  nop
+  nop
+  .align 4
+  la.local $a0, obj1
+
+  .data
+  .space 0x10
+  .type obj1, @object
+obj1:
+  .word 0
+  .size obj1, .-obj1
diff --git a/ld/testsuite/ld-loongarch-elf/relax.exp b/ld/testsuite/ld-loongarch-elf/relax.exp
index d2bb967c6..19ade4970 100644
--- a/ld/testsuite/ld-loongarch-elf/relax.exp
+++ b/ld/testsuite/ld-loongarch-elf/relax.exp
@@ -43,6 +43,26 @@  if [istarget loongarch64-*-*] {
 	      ] \
 	      "relax" \
 	  ] \
+	  [list \
+	      "relax-edge1" \
+	      "-e 0 -Ttext 0x400000 -Tdata 0x200000 -Tbss 0x600000" "" \
+	      "" \
+	      {relax-edge1.s} \
+	      [list \
+		  [list objdump -d relax-edge1.dd] \
+	      ] \
+	      "relax-edge1" \
+	  ] \
+	  [list \
+	      "relax-edge2" \
+	      "-e 0 -Ttext 0x400000 -Tdata 0x600000" "" \
+	      "" \
+	      {relax-edge2.s} \
+	      [list \
+		  [list objdump -d relax-edge2.dd] \
+	      ] \
+	      "relax-edge2" \
+	  ] \
       ]
 
   set objdump_flags "-s -j .data"