RISC-V: Don't segfault for two regs in auipc or lui.

Message ID 20181211004155.22068-1-jimw@sifive.com
State New
Headers show
  • RISC-V: Don't segfault for two regs in auipc or lui.
Related show

Commit Message

Jim Wilson Dec. 11, 2018, 12:41 a.m.
This fixes two problems with the handling of auipc and lui.  The first problem
is that we get a segfault if we parse a register operand.  This is because
the my_getSmallExpression function isn't setting expr_end as documented when
there is a register operand.  I also expanded the comment to explain why we
need to accept a register operand here.  The second problem is that we were
missing a check for the 'u' operand code to reject register operands.  I
handled this the same way as the existing 'B' operand code for consistency.
I also add a testcase for the instructions that were causing a segfault to
verify that they now give an illegal operand error.

This was tested cross for riscv{32,64}-{elf,linux} with binutils and gcc
builds and checks.  There were no regressions.



	PR gas/23954
	* config/tc-riscv.c (my_getSmallExpression): Expand comment for
	register support.  Set expr_end if parse a register.
	(riscv_ip) <'u'>: Break if imm_expr is not a symbol or constant.
	* testsuite/gas/riscv/auipc-parsing.d: New.
	* testsuite/gas/riscv/auipc-parsing.l: New.
	* testsuite/gas/riscv/auipc-parsing.s: New.
 gas/config/tc-riscv.c                   | 9 ++++++++-
 gas/testsuite/gas/riscv/auipc-parsing.d | 3 +++
 gas/testsuite/gas/riscv/auipc-parsing.l | 3 +++
 gas/testsuite/gas/riscv/auipc-parsing.s | 3 +++
 4 files changed, 17 insertions(+), 1 deletion(-)
 create mode 100644 gas/testsuite/gas/riscv/auipc-parsing.d
 create mode 100644 gas/testsuite/gas/riscv/auipc-parsing.l
 create mode 100644 gas/testsuite/gas/riscv/auipc-parsing.s



diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index 9e2035b109..f164134470 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -1263,11 +1263,15 @@  my_getSmallExpression (expressionS *ep, bfd_reloc_code_real_type *reloc,
   unsigned crux_depth, str_depth, regno;
   char *crux;
-  /* First, check for integer registers.  */
+  /* First, check for integer registers.  No callers can accept a reg, but
+     we need to avoid accidentally creating a useless undefined symbol below,
+     if this is an instruction pattern that can't match.  A glibc build fails
+     if this is removed.  */
   if (reg_lookup (&str, RCLASS_GPR, &regno))
       ep->X_op = O_register;
       ep->X_add_number = regno;
+      expr_end = str;
       return 0;
@@ -1940,6 +1944,9 @@  branch:
 		  *imm_reloc = BFD_RELOC_RISCV_HI20;
 		  imm_expr->X_add_number <<= RISCV_IMM_BITS;
+	      /* The 'u' format specifier must be a symbol or a constant.  */
+	      if (imm_expr->X_op != O_symbol && imm_expr->X_op != O_constant)
+	        break;
 	      s = expr_end;
diff --git a/gas/testsuite/gas/riscv/auipc-parsing.d b/gas/testsuite/gas/riscv/auipc-parsing.d
new file mode 100644
index 0000000000..a91102cec7
--- /dev/null
+++ b/gas/testsuite/gas/riscv/auipc-parsing.d
@@ -0,0 +1,3 @@ 
+#source: auipc-parsing.s
+#error_output: auipc-parsing.l
diff --git a/gas/testsuite/gas/riscv/auipc-parsing.l b/gas/testsuite/gas/riscv/auipc-parsing.l
new file mode 100644
index 0000000000..df41e0e2f9
--- /dev/null
+++ b/gas/testsuite/gas/riscv/auipc-parsing.l
@@ -0,0 +1,3 @@ 
+.*: Assembler messages:
+.*: Error: illegal operands `auipc x8,x9'
+.*: Error: illegal operands `lui x10,x11'
diff --git a/gas/testsuite/gas/riscv/auipc-parsing.s b/gas/testsuite/gas/riscv/auipc-parsing.s
new file mode 100644
index 0000000000..f580869cbe
--- /dev/null
+++ b/gas/testsuite/gas/riscv/auipc-parsing.s
@@ -0,0 +1,3 @@ 
+# Don't accept a register for 'u' operands.
+	auipc	x8,x9
+	lui	x10,x11