From e5604d797e394c370128dc06e702a14f11f3e8a5 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Wed, 19 Jan 2005 11:53:53 +0000 Subject: [PATCH] * read.c (convert_to_bignum): New function, split out from... (emit_expr): ...here. Handle the case where X_add_number is positive and the input value is negative. (output_big_sleb128): Fix setting of continuation bit. Check whether the final byte needs to be sign-extended. Fix size-shrinking loop. (emit_leb128_expr): When generating a signed leb128, see whether the sign of an O_constant's X_add_number matches the sign of the input value. Use a bignum if not. --- gas/ChangeLog | 11 ++++ gas/read.c | 103 +++++++++++++++++++++----------- gas/testsuite/ChangeLog | 6 ++ gas/testsuite/gas/all/gas.exp | 3 + gas/testsuite/gas/all/quad.d | 12 ++++ gas/testsuite/gas/all/quad.s | 12 ++++ gas/testsuite/gas/all/sleb128.d | 57 ++++++++++++++++++ gas/testsuite/gas/all/sleb128.s | 22 +++++++ 8 files changed, 191 insertions(+), 35 deletions(-) create mode 100644 gas/testsuite/gas/all/quad.d create mode 100644 gas/testsuite/gas/all/quad.s create mode 100644 gas/testsuite/gas/all/sleb128.d create mode 100644 gas/testsuite/gas/all/sleb128.s diff --git a/gas/ChangeLog b/gas/ChangeLog index c0f8ca46579..a833acd9b19 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,14 @@ +2005-01-19 Richard Sandiford + + * read.c (convert_to_bignum): New function, split out from... + (emit_expr): ...here. Handle the case where X_add_number is + positive and the input value is negative. + (output_big_sleb128): Fix setting of continuation bit. Check whether + the final byte needs to be sign-extended. Fix size-shrinking loop. + (emit_leb128_expr): When generating a signed leb128, see whether the + sign of an O_constant's X_add_number matches the sign of the input + value. Use a bignum if not. + 2005-01-17 Andrew Stubbs * tc-sh.c (md_begin,md_parse_option): Change arch_sh1_up to diff --git a/gas/read.c b/gas/read.c index e6cee541114..e04e00c865f 100644 --- a/gas/read.c +++ b/gas/read.c @@ -1,6 +1,7 @@ /* read.c - read a source file - Copyright 1986, 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, - 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -1082,6 +1083,29 @@ read_a_source_file (char *name) #endif } +/* Convert O_constant expression EXP into the equivalent O_big representation. + Take the sign of the number from X_unsigned rather than X_add_number. */ + +static void +convert_to_bignum (expressionS *exp) +{ + valueT value; + unsigned int i; + + value = exp->X_add_number; + for (i = 0; i < sizeof (exp->X_add_number) / CHARS_PER_LITTLENUM; i++) + { + generic_bignum[i] = value & LITTLENUM_MASK; + value >>= LITTLENUM_NUMBER_OF_BITS; + } + /* Add a sequence of sign bits if the top bit of X_add_number is not + the sign of the original value. */ + if ((exp->X_add_number < 0) != !exp->X_unsigned) + generic_bignum[i++] = exp->X_unsigned ? 0 : LITTLENUM_MASK; + exp->X_op = O_big; + exp->X_add_number = i; +} + /* For most MRI pseudo-ops, the line actually ends at the first nonquoted space. This function looks for that point, stuffs a null in, and sets *STOPCP to the character that used to be there, and @@ -3541,22 +3565,9 @@ emit_expr (expressionS *exp, unsigned int nbytes) pass to md_number_to_chars, handle it as a bignum. */ if (op == O_constant && nbytes > sizeof (valueT)) { - valueT val; - int gencnt; - - if (!exp->X_unsigned && exp->X_add_number < 0) - extra_digit = (valueT) -1; - val = (valueT) exp->X_add_number; - gencnt = 0; - do - { - generic_bignum[gencnt] = val & LITTLENUM_MASK; - val >>= LITTLENUM_NUMBER_OF_BITS; - ++gencnt; - } - while (val != 0); - op = exp->X_op = O_big; - exp->X_add_number = gencnt; + extra_digit = exp->X_unsigned ? 0 : -1; + convert_to_bignum (exp); + op = O_big; } if (op == O_constant) @@ -4276,36 +4287,48 @@ output_big_sleb128 (char *p, LITTLENUM_TYPE *bignum, int size) unsigned byte; /* Strip leading sign extensions off the bignum. */ - while (size > 0 && bignum[size - 1] == (LITTLENUM_TYPE) -1) + while (size > 1 + && bignum[size - 1] == LITTLENUM_MASK + && bignum[size - 2] > LITTLENUM_MASK / 2) size--; do { - if (loaded < 7 && size > 0) - { - val |= (*bignum << loaded); - loaded += 8 * CHARS_PER_LITTLENUM; - size--; - bignum++; - } - - byte = val & 0x7f; - loaded -= 7; - val >>= 7; + /* OR in the next part of the littlenum. */ + val |= (*bignum << loaded); + loaded += LITTLENUM_NUMBER_OF_BITS; + size--; + bignum++; - if (size == 0) + /* Add bytes until there are less than 7 bits left in VAL + or until every non-sign bit has been written. */ + do { - if ((val == 0 && (byte & 0x40) == 0) - || (~(val | ~(((valueT) 1 << loaded) - 1)) == 0 - && (byte & 0x40) != 0)) + byte = val & 0x7f; + loaded -= 7; + val >>= 7; + if (size > 0 + || val != ((byte & 0x40) == 0 ? 0 : ((valueT) 1 << loaded) - 1)) byte |= 0x80; + + if (orig) + *p = byte; + p++; } + while ((byte & 0x80) != 0 && loaded >= 7); + } + while (size > 0); + /* Mop up any left-over bits (of which there will be less than 7). */ + if ((byte & 0x80) != 0) + { + /* Sign-extend VAL. */ + if (val & (1 << (loaded - 1))) + val |= ~0 << loaded; if (orig) - *p = byte; + *p = val & 0x7f; p++; } - while (byte & 0x80); return p - orig; } @@ -4384,6 +4407,16 @@ emit_leb128_expr (expressionS *exp, int sign) as_warn (_("register value used as expression")); op = O_constant; } + else if (op == O_constant + && sign + && (exp->X_add_number < 0) != !exp->X_unsigned) + { + /* We're outputting a signed leb128 and the sign of X_add_number + doesn't reflect the sign of the original value. Convert EXP + to a correctly-extended bignum instead. */ + convert_to_bignum (exp); + op = O_big; + } /* Let check_eh_frame know that data is being emitted. nbytes == -1 is a signal that this is leb128 data. It shouldn't optimize this away. */ diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index e1eab3b8157..e070cf33a3e 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2005-01-19 Richard Sandiford + + * gas/all/sleb128.[sd]: New test. + * gas/all/quad.[sd]: New test. + * gas/all/gas.exp: Run them. + 2005-01-17 Andrew Stubbs * gas/sh/arch/arch.exp: Correct the email address. diff --git a/gas/testsuite/gas/all/gas.exp b/gas/testsuite/gas/all/gas.exp index 966c1120356..6f196fa7929 100644 --- a/gas/testsuite/gas/all/gas.exp +++ b/gas/testsuite/gas/all/gas.exp @@ -195,6 +195,9 @@ if { [istarget "i*86-*-*pe*"] \ gas_test "fastcall.s" "" "" "fastcall labels" } +run_dump_test sleb128 +run_dump_test quad + load_lib gas-dg.exp dg-init dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/err-*.s $srcdir/$subdir/warn-*.s]] "" "" diff --git a/gas/testsuite/gas/all/quad.d b/gas/testsuite/gas/all/quad.d new file mode 100644 index 00000000000..c3a758d1f09 --- /dev/null +++ b/gas/testsuite/gas/all/quad.d @@ -0,0 +1,12 @@ +#objdump : -s -j .data +#name : .quad tests + +.*: .* + +Contents of section .data: + 0000 (00000000 76543210 00000000 80000000|10325476 00000000 00000080 00000000) .* + 0010 (00000000 87654321 00000000 ffffffff|21436587 00000000 ffffffff 00000000) .* + 0020 (ffffffff 89abcdf0 ffffffff 80000000|f0cdab89 ffffffff 00000080 ffffffff) .* + 0030 (ffffffff 789abcdf ffffffff 00000001|dfbc9a78 ffffffff 01000000 ffffffff) .* + 0040 (01234567 89abcdef fedcba98 76543211|efcdab89 67452301 11325476 98badcfe) .* +#pass diff --git a/gas/testsuite/gas/all/quad.s b/gas/testsuite/gas/all/quad.s new file mode 100644 index 00000000000..af250cda3db --- /dev/null +++ b/gas/testsuite/gas/all/quad.s @@ -0,0 +1,12 @@ + .data + .quad 0x76543210 + .quad 0x80000000 + .quad 0x87654321 + .quad 0xffffffff + .quad -0x76543210 + .quad -0x80000000 + .quad -0x87654321 + .quad -0xffffffff + + .quad 0x123456789abcdef + .quad -0x123456789abcdef diff --git a/gas/testsuite/gas/all/sleb128.d b/gas/testsuite/gas/all/sleb128.d new file mode 100644 index 00000000000..eaff63d622f --- /dev/null +++ b/gas/testsuite/gas/all/sleb128.d @@ -0,0 +1,57 @@ +#objdump : -s -j .data +#name : .sleb128 tests + +.*: .* + +Contents of section .data: +# +# 0x76543210 : 000_0111 0110_010 1_0100_00 11_0010_0 001_0000 +# 0x80000000 : 000_1000 0000_000 0_0000_00 00_0000_0 000_0000 +# 0x87654321 : 000_1000 0111_011 0_0101_01 00_0011_0 010_0001 +# 0xffffffff : ..................................... 111_1111 +# + 0000 90e4d0b2 07808080 8008a186 95bb08ff .* +# +# 0xffffffff : 000_1111 1111_111 1_1111_11 11_1111_1 ........ +# -0x76543210 : 111_1000 1001_101 0_1011_11 00_1101_1 111_0000 +# -0x80000000 : 111_1000 0000_000 0_0000_00 00_0000_0 000_0000 +# -0x87654321 : ........................... 11_1100_1 101_1111 +# + 0010 ffffff0f f09bafcd 78808080 8078dff9 .* +# +# -0x87654321 : 111_0111 1000_100 1_1010_10 .................. +# -0xffffffff : 111_0000 0000_000 0_0000_00 00_0000_0 000_0001 +# 789abcdef : 111_1000 1001_101 0_1011_11 00_1101_1 110_1111 +# 0x123456 : ........ 0010_001 1_0100_01 01_0110_0 +# + 0020 eac47781 80808070 ef9bafcd f8acd191 .* +# +# 0x123456 : 000_0001 ............................ +# 789abcdef : 000_0111 0110_010 1_0100_00 11_0010_0 001_0001 +# -0x123456 : 111_1110 1101_110 0_1011_10 01_1001_1 +# fffffffff : 000_0000 0000_000 0_0000_00 00_0000_0 000_0001 +# -0x7ff : ......... 00_0000_0 +# + 0030 0191e4d0 b287d3ae ee7e8180 80808080 .* +# +# -0x7ff : 1_1000_00 ......... +# 000000000 : 000_0000 0000_000 0_0000_00 00_0000_0 000_0000 +# -0x800 : 1_1000_00 00_0000_0 +# fffffffff : 000_0000 0000_000 0_0000_00 00_0000_0 000_0001 +# -0x7ffffff : .................. 0000_000 0_0000_00 00_0000_0 +# + 0040 60808080 80808060 81808080 80808080 .* +# +# -0x7ffffff : 11_1111_1 000_0000 ............................ +# 000000000 : 000_0000 0000_000 0_0000_00 00_0000_0 000_0000 +# -0x8000000 : 11_1111_1 000_0000 0000_000 0_0000_00 00_0000_0 +# -0x100000000 : ........ 0000_000 0_0000_00 00_0000_0 000_0000 +# + 0050 807f8080 80808080 8080807f 80808080 .* +# +# -0x100000000 : 111_0000 ..................................... +# 000000000 : 000_0000 0000_000 0_0000_00 00_0000_0 000_0000 +# -0x1000 : 1_0000_00 00_0000_0 +# + 0060 70808080 80808040 00000000 00000000 .* +#pass diff --git a/gas/testsuite/gas/all/sleb128.s b/gas/testsuite/gas/all/sleb128.s new file mode 100644 index 00000000000..e8997ca175d --- /dev/null +++ b/gas/testsuite/gas/all/sleb128.s @@ -0,0 +1,22 @@ + .data + .sleb128 0x76543210 + .sleb128 0x80000000 + .sleb128 0x87654321 + .sleb128 0xffffffff + .sleb128 -0x76543210 + .sleb128 -0x80000000 + .sleb128 -0x87654321 + .sleb128 -0xffffffff + + .sleb128 0x123456789abcdef + .sleb128 -0x123456789abcdef + + .sleb128 -0x7fffffffffff + .sleb128 -0x800000000000 + .sleb128 -0x7fffffffffffffff + .sleb128 -0x8000000000000000 + + .sleb128 -0x100000000 + .sleb128 -0x1000000000000 + + .fill 32 -- 2.30.2