[v1] LoongArch: gas: Ignore .align if it is at the start of a section

Message ID 20240320100718.3033397-1-mengqinggang@loongson.cn
State New
Headers
Series [v1] LoongArch: gas: Ignore .align if it is at the start of a section |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Testing passed
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_binutils_check--master-arm success Testing passed

Commit Message

mengqinggang March 20, 2024, 10:07 a.m. UTC
  Ignore .align if it is at the start of a section, the section alignment
can ensure correct alignment.
---
 gas/config/tc-loongarch.c                     | 105 ++++++++++++++----
 .../gas/loongarch/relax-align-first.d         |  12 ++
 .../gas/loongarch/relax-align-first.s         |   7 ++
 .../ld-loongarch-elf/relax-align-first.d      |  15 +++
 .../ld-loongarch-elf/relax-align-first.s      |  13 +++
 ld/testsuite/ld-loongarch-elf/relax.exp       |   1 +
 6 files changed, 133 insertions(+), 20 deletions(-)
 create mode 100644 gas/testsuite/gas/loongarch/relax-align-first.d
 create mode 100644 gas/testsuite/gas/loongarch/relax-align-first.s
 create mode 100644 ld/testsuite/ld-loongarch-elf/relax-align-first.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/relax-align-first.s
  

Comments

H.J. Lu March 20, 2024, 11:08 a.m. UTC | #1
On Wed, Mar 20, 2024 at 3:08 AM mengqinggang <mengqinggang@loongson.cn> wrote:
>
> Ignore .align if it is at the start of a section, the section alignment
> can ensure correct alignment.

What happens when the section is aligned at 8 bytes and .align is aligned to
16 bytes?
  
Xi Ruoyao March 20, 2024, 12:53 p.m. UTC | #2
On Wed, 2024-03-20 at 04:08 -0700, H.J. Lu wrote:
> On Wed, Mar 20, 2024 at 3:08 AM mengqinggang <mengqinggang@loongson.cn> wrote:
> > 
> > Ignore .align if it is at the start of a section, the section alignment
> > can ensure correct alignment.
> 
> What happens when the section is aligned at 8 bytes and .align is aligned to
> 16 bytes?

If it happens we should increase the section alignment to 16, or we were
silently generating broken output and we had a bug anyway...
  
mengqinggang March 21, 2024, 1:34 a.m. UTC | #3
在 2024/3/20 下午8:53, Xi Ruoyao 写道:
> On Wed, 2024-03-20 at 04:08 -0700, H.J. Lu wrote:
>> On Wed, Mar 20, 2024 at 3:08 AM mengqinggang <mengqinggang@loongson.cn> wrote:
>>> Ignore .align if it is at the start of a section, the section alignment
>>> can ensure correct alignment.
>> What happens when the section is aligned at 8 bytes and .align is aligned to
>> 16 bytes?

According to my understanding, section alignment is the maximum 
alignment within section.
And, can we set the alignment of a section separately?


> If it happens we should increase the section alignment to 16, or we were
> silently generating broken output and we had a bug anyway...
>
  

Patch

diff --git a/gas/config/tc-loongarch.c b/gas/config/tc-loongarch.c
index 30aefce36fd..b009186e66f 100644
--- a/gas/config/tc-loongarch.c
+++ b/gas/config/tc-loongarch.c
@@ -128,6 +128,11 @@  static bool call36 = 0;
 #define RELAX_BRANCH_ENCODE(x) \
   (BFD_RELOC_LARCH_B16 == (x) ? RELAX_BRANCH_16 : RELAX_BRANCH_21)
 
+#define ALIGN_MAX_ADDEND(n, max) ((max << 8) | n)
+#define ALIGN_MAX_NOP_BYTES(addend) ((1 << (addend & 0xff)) - 4)
+#define FRAG_AT_START_OF_SECTION(frag)	\
+  (0 == frag->fr_address && 0 == frag->fr_fix)
+
 enum options
 {
   OPTION_IGNORE = OPTION_MD_BASE,
@@ -1647,11 +1652,22 @@  md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     }
 }
 
+/* Before relax, return the fixed size of a frag to calculate address.  */
+
 int
 md_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED,
 			       asection *segtype ATTRIBUTE_UNUSED)
 {
-  return (fragp->fr_var = 4);
+  if (RELAX_BRANCH (fragp->fr_subtype))
+    return (fragp->fr_var = 4);
+  else /* R_LARCH_ALIGN */
+    if (FRAG_AT_START_OF_SECTION (fragp))
+      return (fragp->fr_var = 0);
+    else
+      if (NULL == fragp->fr_symbol)
+	return (fragp->fr_var = fragp->fr_offset);
+      else
+	return (fragp->fr_var = ALIGN_MAX_NOP_BYTES (fragp->fr_offset));
 }
 
 /* Translate internal representation of relocation info to BFD target
@@ -1767,8 +1783,7 @@  bool
 loongarch_frag_align_code (int n, int max)
 {
   char *nops;
-  symbolS *s;
-  expressionS ex;
+  symbolS *s = NULL;
 
   bfd_vma insn_alignment = 4;
   bfd_vma bytes = (bfd_vma) 1 << n;
@@ -1783,8 +1798,6 @@  loongarch_frag_align_code (int n, int max)
   if (!LARCH_opts.relax)
     return false;
 
-  nops = frag_more (worst_case_bytes);
-
   /* If max <= 0, ignore max.
      If max >= worst_case_bytes, max has no effect.
      Similar to gas/write.c relax_segment function rs_align_code case:
@@ -1795,21 +1808,22 @@  loongarch_frag_align_code (int n, int max)
       if (s == NULL)
 	s = (symbolS *)local_symbol_make (".Lla-relax-align", now_seg,
 					  &zero_address_frag, 0);
-      ex.X_add_symbol = s;
-      ex.X_op = O_symbol;
-      ex.X_add_number = (max << 8) | n;
-    }
-  else
-    {
-      ex.X_op = O_constant;
-      ex.X_add_number = worst_case_bytes;
     }
 
+  frag_grow (worst_case_bytes);
+  /* Use relaxable frag for .align.
+     If .align at the start of section, do nothing. Section alignment can
+     ensure correct alignment.
+     If .align is not at the start of a section, reserve NOP instructions
+     and R_LARCH_ALIGN relocation.  */
+  nops = frag_var (rs_machine_dependent, worst_case_bytes, worst_case_bytes,
+		   rs_align_code, s,
+		   s ? (bfd_vma) ALIGN_MAX_ADDEND (n, max) : worst_case_bytes,
+		   NULL);
+
+  /* Default write NOP for aligned bytes.  */
   loongarch_make_nops (nops, worst_case_bytes);
 
-  fix_new_exp (frag_now, nops - frag_now->fr_literal, 0,
-	       &ex, false, BFD_RELOC_LARCH_ALIGN);
-
   /* We need to start a new frag after the alignment which may be removed by
      the linker, to prevent the assembler from computing static offsets.
      This is necessary to get correct EH info.  */
@@ -1976,6 +1990,20 @@  loongarch_relax_frag (asection *sec ATTRIBUTE_UNUSED,
       fragp->fr_var = loongarch_relaxed_branch_length (fragp, sec, true);
       return fragp->fr_var - old_var;
     }
+  else if (rs_align_code == fragp->fr_subtype)
+    {
+      offsetT old_var = fragp->fr_var;
+      /* If .align at the start of a section, do nothing. Section alignment
+       * can ensure correct alignment.  */
+      if (FRAG_AT_START_OF_SECTION (fragp))
+	fragp->fr_var = 0;
+      else
+	if (NULL == fragp->fr_symbol)
+	  fragp->fr_var = fragp->fr_offset;
+	else
+	  fragp->fr_var = ALIGN_MAX_NOP_BYTES (fragp->fr_offset);
+      return fragp->fr_var - old_var;
+    }
   return 0;
 }
 
@@ -2051,13 +2079,50 @@  loongarch_convert_frag_branch (fragS *fragp)
   fragp->fr_fix += fragp->fr_var;
 }
 
-/* Relax a machine dependent frag.  This returns the amount by which
-   the current size of the frag should change.  */
+/*  Relax .align frag.  */
+
+static void
+loongarch_convert_frag_align (fragS *fragp)
+{
+  bfd_byte *buf = (bfd_byte *)fragp->fr_literal + fragp->fr_fix;
+
+  if (!FRAG_AT_START_OF_SECTION (fragp))
+    {
+      expressionS exp;
+      exp.X_op = O_symbol;
+      exp.X_add_symbol = fragp->fr_symbol;
+      exp.X_add_number = fragp->fr_offset;
+
+      unsigned long size = 0;
+      if (NULL == fragp->fr_symbol)
+	size = fragp->fr_offset;
+      else
+	size = ALIGN_MAX_NOP_BYTES (fragp->fr_offset);
+
+      fixS *fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
+				size, &exp, false, BFD_RELOC_LARCH_ALIGN);
+      fixp->fx_file = fragp->fr_file;
+      fixp->fx_line = fragp->fr_line;
+
+      buf += size;
+    }
+
+  gas_assert (buf == (bfd_byte *)fragp->fr_literal
+	      + fragp->fr_fix + fragp->fr_var);
+
+  fragp->fr_fix += fragp->fr_var;
+}
+
+/* Relax a machine dependent frag.  */
 
 void
 md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec ATTRIBUTE_UNUSED,
 		 fragS *fragp)
 {
-  gas_assert (RELAX_BRANCH (fragp->fr_subtype));
-  loongarch_convert_frag_branch (fragp);
+  gas_assert (RELAX_BRANCH (fragp->fr_subtype)
+	      || rs_align_code == fragp->fr_subtype);
+  if (RELAX_BRANCH (fragp->fr_subtype))
+    loongarch_convert_frag_branch (fragp);
+  else if (rs_align_code == fragp->fr_subtype)
+    loongarch_convert_frag_align (fragp);
 }
diff --git a/gas/testsuite/gas/loongarch/relax-align-first.d b/gas/testsuite/gas/loongarch/relax-align-first.d
new file mode 100644
index 00000000000..ec0698b6995
--- /dev/null
+++ b/gas/testsuite/gas/loongarch/relax-align-first.d
@@ -0,0 +1,12 @@ 
+#as:
+#objdump: -dr
+
+.*:[    ]+file format .*
+
+
+Disassembly of section .text:
+0* <.text>:
+[ 	]+0:[ 	]+4c000020[ 	]+ret
+Disassembly of section abc:
+0* <abc>:
+[ 	]+0:[ 	]+4c000020[ 	]+ret
diff --git a/gas/testsuite/gas/loongarch/relax-align-first.s b/gas/testsuite/gas/loongarch/relax-align-first.s
new file mode 100644
index 00000000000..a4c3d68fee3
--- /dev/null
+++ b/gas/testsuite/gas/loongarch/relax-align-first.s
@@ -0,0 +1,7 @@ 
+.text
+.align 3
+ret
+
+.section "abc", "ax"
+.align 4, ,4
+ret
diff --git a/ld/testsuite/ld-loongarch-elf/relax-align-first.d b/ld/testsuite/ld-loongarch-elf/relax-align-first.d
new file mode 100644
index 00000000000..9a4fad8ea46
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relax-align-first.d
@@ -0,0 +1,15 @@ 
+#ld: -e0
+#objdump: -d
+
+.*:[    ]+file format .*
+
+
+Disassembly of section aaa:
+0000000120000078 <aaa>:
+[ 	]+120000078:[ 	]+4c000020[ 	]+ret
+Disassembly of section bbb:
+0000000120000080 <bbb>:
+[ 	]+120000080:[ 	]+4c000020[ 	]+ret
+Disassembly of section ccc:
+0000000120000090 <__bss_start-0x4004>:
+[ 	]+120000090:[ 	]+4c000020[ 	]+ret
diff --git a/ld/testsuite/ld-loongarch-elf/relax-align-first.s b/ld/testsuite/ld-loongarch-elf/relax-align-first.s
new file mode 100644
index 00000000000..0a9115b5bcf
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relax-align-first.s
@@ -0,0 +1,13 @@ 
+# If .align at the start of a section, do not add NOP instructions
+# and do not emit R_LARCH_ALIGN relocations.
+# Section alignment can ensure correct alignment.
+.section "aaa", "ax"
+ret
+
+.section "bbb", "ax"
+.align 3
+ret
+
+.section "ccc", "ax"
+.align 4, ,4
+ret
diff --git a/ld/testsuite/ld-loongarch-elf/relax.exp b/ld/testsuite/ld-loongarch-elf/relax.exp
index 7d95a9ca41d..969918955e3 100644
--- a/ld/testsuite/ld-loongarch-elf/relax.exp
+++ b/ld/testsuite/ld-loongarch-elf/relax.exp
@@ -20,6 +20,7 @@ 
 #
 
 if [istarget loongarch64-*-*] {
+  run_dump_test "relax-align-first"
 
   if [isbuild loongarch64-*-*] {
     set testname "loongarch relax .exe build"