/* 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.
#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
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)
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;
}
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. */
--- /dev/null
+#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