This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Commit: Allow bignums to specify byte values
- From: Nick Clifton <nickc at redhat dot com>
- To: binutils at sourceware dot org
- Date: Wed, 16 Mar 2016 11:33:20 +0000
- Subject: Commit: Allow bignums to specify byte values
- Authentication-results: sourceware.org; auth=none
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