RISC-V: Fix .align handling when .option norelax.

Message ID 20180524173740.10307-1-jimw@sifive.com
State New
Headers show
Series
  • RISC-V: Fix .align handling when .option norelax.
Related show

Commit Message

Jim Wilson May 24, 2018, 5:37 p.m.
This fixes a bug with alignment when relaxation is turned off.  There were
several problems with the previous code.  It was inserting null bytes into
the code.  It wasn't properly aligning to values larger than 8 bytes.  It
could crash with a divide by zero exception.  Fixing this required rewriting
the code a bit.  I now emit up to 3 bytes of alignment in the fixed part of a
frag, and then a 4 byte nop in the variable part of a frag which will be
repeated as many times as necessary.  I'm also adding testcases to verify the
change.

This was tested with cross riscv{32,64}-{elf,linux} testsuite runs, and a
native riscv64-linux testsuite run.  I also tested with a gcc build and
testsuite run with a gcc hacked to disable relaxation.

Committed

Jim

	gas/
	PR gas/23219
	* config/tc-riscv.c (riscv_frag_align_code): Move frag_more call after
	!riscv_opts.relax check.
	(riscv_handle_align): Rewrite !riscv_opts.relax support.
	* config/tc-riscv (MAX_MEM_FOR_RS_ALIGN_CODE): Update.
	* testsuite/gas/riscv/no-relax-align.d: New
	* testsuite/gas/riscv/no-relax-align.s: New
	* testsuite/gas/riscv/no-relax-align-2.d: New
	* testsuite/gas/riscv/no-relax-align-2.s: New
---
 gas/config/tc-riscv.c                      | 30 +++++++++++++++++++++---------
 gas/config/tc-riscv.h                      |  2 +-
 gas/testsuite/gas/riscv/no-relax-align-2.d | 19 +++++++++++++++++++
 gas/testsuite/gas/riscv/no-relax-align-2.s |  5 +++++
 gas/testsuite/gas/riscv/no-relax-align.d   | 13 +++++++++++++
 gas/testsuite/gas/riscv/no-relax-align.s   |  4 ++++
 6 files changed, 63 insertions(+), 10 deletions(-)
 create mode 100644 gas/testsuite/gas/riscv/no-relax-align-2.d
 create mode 100644 gas/testsuite/gas/riscv/no-relax-align-2.s
 create mode 100644 gas/testsuite/gas/riscv/no-relax-align.d
 create mode 100644 gas/testsuite/gas/riscv/no-relax-align.s

-- 
2.14.1

Patch

diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index 43ae21fcb1..a0ea87a3fa 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -2756,12 +2756,12 @@  riscv_frag_align_code (int n)
   if (bytes <= insn_alignment)
     return TRUE;
 
-  nops = frag_more (worst_case_bytes);
-
   /* When not relaxing, riscv_handle_align handles code alignment.  */
   if (!riscv_opts.relax)
     return FALSE;
 
+  nops = frag_more (worst_case_bytes);
+
   ex.X_op = O_constant;
   ex.X_add_number = worst_case_bytes;
 
@@ -2784,15 +2784,27 @@  riscv_handle_align (fragS *fragP)
       /* When relaxing, riscv_frag_align_code handles code alignment.  */
       if (!riscv_opts.relax)
 	{
-	  bfd_signed_vma count = fragP->fr_next->fr_address
-				 - fragP->fr_address - fragP->fr_fix;
-
-	  if (count <= 0)
+	  bfd_signed_vma bytes = (fragP->fr_next->fr_address
+				  - fragP->fr_address - fragP->fr_fix);
+	  /* We have 4 byte uncompressed nops.  */
+	  bfd_signed_vma size = 4;
+	  bfd_signed_vma excess = bytes % size;
+	  char *p = fragP->fr_literal + fragP->fr_fix;
+
+	  if (bytes <= 0)
 	    break;
 
-	  count &= MAX_MEM_FOR_RS_ALIGN_CODE;
-	  riscv_make_nops (fragP->fr_literal + fragP->fr_fix, count);
-	  fragP->fr_var = count;
+	  /* Insert zeros or compressed nops to get 4 byte alignment.  */
+	  if (excess)
+	    {
+	      riscv_make_nops (p, excess);
+	      fragP->fr_fix += excess;
+	      p += excess;
+	    }
+
+	  /* Insert variable number of 4 byte uncompressed nops.  */
+	  riscv_make_nops (p, size);
+	  fragP->fr_var = size;
 	}
       break;
 
diff --git a/gas/config/tc-riscv.h b/gas/config/tc-riscv.h
index a4f40e6284..5e59740e38 100644
--- a/gas/config/tc-riscv.h
+++ b/gas/config/tc-riscv.h
@@ -62,7 +62,7 @@  extern bfd_boolean riscv_frag_align_code (int);
 extern void riscv_handle_align (fragS *);
 #define HANDLE_ALIGN riscv_handle_align
 
-#define MAX_MEM_FOR_RS_ALIGN_CODE 7
+#define MAX_MEM_FOR_RS_ALIGN_CODE (3 + 4)
 
 /* The ISA of the target may change based on command-line arguments.  */
 #define TARGET_FORMAT riscv_target_format()
diff --git a/gas/testsuite/gas/riscv/no-relax-align-2.d b/gas/testsuite/gas/riscv/no-relax-align-2.d
new file mode 100644
index 0000000000..7407b495a8
--- /dev/null
+++ b/gas/testsuite/gas/riscv/no-relax-align-2.d
@@ -0,0 +1,19 @@ 
+#as:
+#objdump: -dr
+
+.*:[ 	]+file format .*
+
+
+Disassembly of section .text:
+
+0+000 <.text>:
+[ 	]+0:[ 	]+0000[ 	]+unimp
+[ 	]+2:[ 	]+0001[ 	]+nop
+[ 	]+4:[ 	]+00000013[ 	]+nop
+[ 	]+8:[ 	]+00000013[ 	]+nop
+[ 	]+c:[ 	]+00000013[ 	]+nop
+[ 	]+10:[ 	]+0001[ 	]+nop
+[ 	]+12:[ 	]+0001[ 	]+nop
+[ 	]+14:[ 	]+00000013[ 	]+nop
+[ 	]+18:[ 	]+00000013[ 	]+nop
+[ 	]+1c:[ 	]+00000013[ 	]+nop
diff --git a/gas/testsuite/gas/riscv/no-relax-align-2.s b/gas/testsuite/gas/riscv/no-relax-align-2.s
new file mode 100644
index 0000000000..ccd353ddcf
--- /dev/null
+++ b/gas/testsuite/gas/riscv/no-relax-align-2.s
@@ -0,0 +1,5 @@ 
+	.option norelax
+	.option rvc
+	.byte 0
+	.align 4
+	nop
diff --git a/gas/testsuite/gas/riscv/no-relax-align.d b/gas/testsuite/gas/riscv/no-relax-align.d
new file mode 100644
index 0000000000..ced07d3c83
--- /dev/null
+++ b/gas/testsuite/gas/riscv/no-relax-align.d
@@ -0,0 +1,13 @@ 
+#as:
+#objdump: -dr
+
+.*:[ 	]+file format .*
+
+
+Disassembly of section .text:
+
+0+000 <.text>:
+[ 	]+0:[ 	]+00000013[ 	]+nop
+[ 	]+4:[ 	]+00000013[ 	]+nop
+[ 	]+8:[ 	]+00000013[ 	]+nop
+[ 	]+c:[ 	]+00000013[ 	]+nop
diff --git a/gas/testsuite/gas/riscv/no-relax-align.s b/gas/testsuite/gas/riscv/no-relax-align.s
new file mode 100644
index 0000000000..23b43e0a4c
--- /dev/null
+++ b/gas/testsuite/gas/riscv/no-relax-align.s
@@ -0,0 +1,4 @@ 
+	.option norelax
+	.align 4
+	nop
+	nop