This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Commit: Allow bignums to specify byte values


Hi Guys,

  I am checking in the patch below to fix a problem with gas's parsing
  of .byte values that are so large that they need a bignum to hold
  them.  (This can happen in particular with negative byte values
  generated by the compiler, if the compiler insists upon generating
  large hex values for all constants.  *cough* RX port *cough*).

  The problem was that the code that checks for a bignum overflowing the
  data container into which it is being placed had no code to handle the
  special case of a single byte.  Since a byte is smaller than the
  LITTLENUM type, extra care must taken to mask and check the top bits
  of the first generic_bignum array entry.

  Anyway the patch takes care of this problem, and a small, related
  problem in the RX parser, which means that the RX assembler can now
  properly handle bignum constants generated by gcc, even if the
  assembler is running on a 32-bit host.

  The patch includes a small testcase to make sure that the
  functionality continues to work.

  Tested with lots and lots of different toolchains.

Cheers
  Nick

gas/ChangeLog
2016-03-16  Nick Clifton  <nickc@redhat.com>

	* read.c (emit_expr_with_reloc): Add code check a bignum with
	nbytes == 1.
	* config/rx/rx-parse.y (rx_intop): Accept bignum values for sizes
	other than 32-bits.
	* testsuite/gas/elf/bignum.s: New test source file.
	* testsuite/gas/elf/bignum.d: New test driver file.
	* testsuite/gas/elf/elf.exp: Run the new test.

diff --git a/gas/config/rx-parse.y b/gas/config/rx-parse.y
index 3bd37d0..c0e3217 100644
--- a/gas/config/rx-parse.y
+++ b/gas/config/rx-parse.y
@@ -1494,9 +1494,14 @@ rx_intop (expressionS exp, int nbits, int opbits)
   long v;
   long mask, msb;
 
-  if (exp.X_op == O_big && nbits == 32)
-      return 1;
-  if (exp.X_op != O_constant)
+  if (exp.X_op == O_big)
+    {
+      if (nbits == 32)
+	return 1;
+      if (exp.X_add_number == -1)
+	return 0;
+    }
+  else if (exp.X_op != O_constant)
     return 0;
   v = exp.X_add_number;
 
diff --git a/gas/read.c b/gas/read.c
index 8f5dfff..ea6d9f6 100644
--- a/gas/read.c
+++ b/gas/read.c
@@ -4411,7 +4411,8 @@ emit_expr_with_reloc (expressionS *exp,
       if ((get & mask) != 0
 	  && ((get & mask) != mask
 	      || (get & hibit) == 0))
-	{		/* Leading bits contain both 0s & 1s.  */
+	{
+	  /* Leading bits contain both 0s & 1s.  */
 #if defined (BFD64) && BFD_HOST_64BIT_LONG_LONG
 #ifndef __MSVCRT__
 	  as_warn (_("value 0x%llx truncated to 0x%llx"),
@@ -4437,16 +4438,34 @@ emit_expr_with_reloc (expressionS *exp,
       if (nbytes < size)
 	{
 	  int i = nbytes / CHARS_PER_LITTLENUM;
+
 	  if (i != 0)
 	    {
 	      LITTLENUM_TYPE sign = 0;
 	      if ((generic_bignum[--i]
 		   & (1 << (LITTLENUM_NUMBER_OF_BITS - 1))) != 0)
 		sign = ~(LITTLENUM_TYPE) 0;
+
 	      while (++i < exp->X_add_number)
 		if (generic_bignum[i] != sign)
 		  break;
 	    }
+	  else if (nbytes == 1)
+	    {
+	      /* We have nbytes == 1 and CHARS_PER_LITTLENUM == 2 (probably).
+		 Check that bits 8.. of generic_bignum[0] match bit 7
+		 and that they match all of generic_bignum[1..exp->X_add_number].  */
+	      LITTLENUM_TYPE sign = (generic_bignum[0] & (1 << 7)) ? -1 : 0;
+	      LITTLENUM_TYPE himask = LITTLENUM_MASK & ~ 0xFF;
+
+	      if ((generic_bignum[0] & himask) == (sign & himask))
+		{
+		  while (++i < exp->X_add_number)
+		    if (generic_bignum[i] != sign)
+		      break;
+		}
+	    }
+
 	  if (i < exp->X_add_number)
 	    as_warn (_("bignum truncated to %d bytes"), nbytes);
 	  size = nbytes;
diff --git a/gas/testsuite/gas/elf/elf.exp b/gas/testsuite/gas/elf/elf.exp
index fb5619d..bde875b 100644
--- a/gas/testsuite/gas/elf/elf.exp
+++ b/gas/testsuite/gas/elf/elf.exp
@@ -226,9 +226,10 @@ if { [is_elf_format] } then {
 
     run_dump_test "strtab"
 
-load_lib gas-dg.exp
-dg-init
-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/err-*.s $srcdir/$subdir/warn-*.s]] "" ""
-dg-finish
+    run_dump_test "bignums"
     
+    load_lib gas-dg.exp
+    dg-init
+    dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/err-*.s $srcdir/$subdir/warn-*.s]] "" ""
+    dg-finish
 }
--- /dev/null	2016-03-16 07:56:33.305964920 +0000
+++ gas/testsuite/gas/elf/bignums.s	2016-03-16 10:44:09.735911644 +0000
@@ -0,0 +1,23 @@
+	.data
+
+	# On a 64-bit host the two values below will be read into a simple
+	# 64-bit field in the expressionS structure and the type will be set
+	# to O_constant.  On a 32-bit host however they will read into the
+	# generic_bignum array and the type set to O_bignum.  Either way they
+	# should both evaluate without errors.
+	#
+	# Note - some targets place .hword values on a 16-bit boundary, so we
+	# declare a second, zero, .byte value in order to make the data
+	# consistent across all targets.
+
+	.byte  0xffffffffffffff98, 0
+	.hword 0xffffffffffff9876
+
+	# Check that on 64-bit hosts real bignum values also work.
+
+	.byte  0xffffffffffffffffffffffffffffff98, 0
+	.hword 0xffffffffffffffffffffffffffff9876
+
+	# Also check a ridiculously long bignum value.
+
+	.byte  0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff98, 0
--- /dev/null	2016-03-16 07:56:33.305964920 +0000
+++ gas/testsuite/gas/elf/bignums.d	2016-03-16 10:33:47.415141541 +0000
@@ -0,0 +1,14 @@
+#readelf: -x .data
+#name: bignum byte values
+#not-target: rx-*
+# The RX target sometimes calls its data section D_1.
+# 
+# Test that 8-bit and 16-bit constants can be specified via bignums.
+# 
+# Note - we should really apply this test to all targets, not just
+# ELF based ones, but we need a tool that can dump the data section
+# in a fixed format and readelf fits the bill.
+
+Hex dump of section .*:
+  0x00000000 9800(7698|9876) 9800(7698|9876) 9800.*
+#pass

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]