diff options
-rw-r--r-- | gas/ChangeLog | 15 | ||||
-rw-r--r-- | gas/expr.c | 67 | ||||
-rw-r--r-- | gas/expr.h | 5 | ||||
-rw-r--r-- | gas/read.c | 15 | ||||
-rw-r--r-- | gas/testsuite/ChangeLog | 15 | ||||
-rw-r--r-- | gas/testsuite/gas/all/gas.exp | 5 | ||||
-rw-r--r-- | gas/testsuite/gas/all/sleb128-2.d | 7 | ||||
-rw-r--r-- | gas/testsuite/gas/all/sleb128-2.s | 13 | ||||
-rw-r--r-- | gas/testsuite/gas/all/sleb128-3.d | 7 | ||||
-rw-r--r-- | gas/testsuite/gas/all/sleb128-3.s | 4 | ||||
-rw-r--r-- | gas/testsuite/gas/all/sleb128-4.d | 7 | ||||
-rw-r--r-- | gas/testsuite/gas/all/sleb128-4.s | 13 | ||||
-rw-r--r-- | gas/testsuite/gas/all/sleb128-5.d | 7 | ||||
-rw-r--r-- | gas/testsuite/gas/all/sleb128-5.s | 13 | ||||
-rw-r--r-- | gas/testsuite/gas/all/sleb128-7.d | 7 | ||||
-rw-r--r-- | gas/testsuite/gas/all/sleb128-7.s | 19 |
16 files changed, 202 insertions, 17 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index 4419429..ca37956 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,18 @@ +2013-04-10 Julian Brown <julian@codesourcery.com> + + * read.c (convert_to_bignum): Add sign parameter. Use it + instead of X_unsigned to determine sign of resulting bignum. + (emit_expr): Pass extra argument to convert_to_bignum. + (emit_leb128_expr): Use X_extrabit instead of X_unsigned. Pass + X_extrabit to convert_to_bignum. + (parse_bitfield_cons): Set X_extrabit. + * expr.c (make_expr_symbol, expr_build_uconstant, operand): + Initialise X_extrabit field as appropriate. + (add_to_result): New. + (subtract_from_result): New. + (expr): Use above. + * expr.h (expressionS): Add X_extrabit field. + 2013-04-10 Jan Beulich <jbeulich@suse.com> * gas/config/tc-arm.c (encode_arm_addr_mode_3): Only reject base @@ -90,6 +90,7 @@ make_expr_symbol (expressionS *expressionP) zero.X_op = O_constant; zero.X_add_number = 0; zero.X_unsigned = 0; + zero.X_extrabit = 0; clean_up_expression (&zero); expressionP = &zero; } @@ -161,6 +162,7 @@ expr_build_uconstant (offsetT value) e.X_op = O_constant; e.X_add_number = value; e.X_unsigned = 1; + e.X_extrabit = 0; return make_expr_symbol (&e); } @@ -732,6 +734,7 @@ operand (expressionS *expressionP, enum expr_mode mode) something like ``.quad 0x80000000'' is not sign extended even though it appears negative if valueT is 32 bits. */ expressionP->X_unsigned = 1; + expressionP->X_extrabit = 0; /* Digits, assume it is a bignum. */ @@ -1026,6 +1029,8 @@ operand (expressionS *expressionP, enum expr_mode mode) This is compatible with other people's assemblers. Sigh. */ expressionP->X_unsigned = 0; + if (expressionP->X_add_number) + expressionP->X_extrabit ^= 1; } else if (c == '~' || c == '"') expressionP->X_add_number = ~ expressionP->X_add_number; @@ -1078,6 +1083,7 @@ operand (expressionS *expressionP, enum expr_mode mode) expressionP->X_add_number = i >= expressionP->X_add_number; expressionP->X_op = O_constant; expressionP->X_unsigned = 1; + expressionP->X_extrabit = 0; } } else if (expressionP->X_op != O_illegal @@ -1717,6 +1723,42 @@ operatorf (int *num_chars) /* NOTREACHED */ } +/* Implement "word-size + 1 bit" addition for + {resultP->X_extrabit:resultP->X_add_number} + {rhs_highbit:amount}. This + is used so that the full range of unsigned word values and the full range of + signed word values can be represented in an O_constant expression, which is + useful e.g. for .sleb128 directives. */ + +static void +add_to_result (expressionS *resultP, offsetT amount, int rhs_highbit) +{ + valueT ures = resultP->X_add_number; + valueT uamount = amount; + + resultP->X_add_number += amount; + + resultP->X_extrabit ^= rhs_highbit; + + if (ures + uamount < ures) + resultP->X_extrabit ^= 1; +} + +/* Similarly, for subtraction. */ + +static void +subtract_from_result (expressionS *resultP, offsetT amount, int rhs_highbit) +{ + valueT ures = resultP->X_add_number; + valueT uamount = amount; + + resultP->X_add_number -= amount; + + resultP->X_extrabit ^= rhs_highbit; + + if (ures < uamount) + resultP->X_extrabit ^= 1; +} + /* Parse an expression. */ segT @@ -1832,7 +1874,7 @@ expr (int rankarg, /* Larger # is higher rank. */ && (md_register_arithmetic || resultP->X_op != O_register)) { /* X + constant. */ - resultP->X_add_number += right.X_add_number; + add_to_result (resultP, right.X_add_number, right.X_extrabit); } /* This case comes up in PIC code. */ else if (op_left == O_subtract @@ -1850,10 +1892,11 @@ expr (int rankarg, /* Larger # is higher rank. */ symbol_get_frag (right.X_add_symbol), &frag_off)) { - resultP->X_add_number -= right.X_add_number; - resultP->X_add_number -= frag_off / OCTETS_PER_BYTE; - resultP->X_add_number += (S_GET_VALUE (resultP->X_add_symbol) - - S_GET_VALUE (right.X_add_symbol)); + offsetT symval_diff = S_GET_VALUE (resultP->X_add_symbol) + - S_GET_VALUE (right.X_add_symbol); + subtract_from_result (resultP, right.X_add_number, right.X_extrabit); + subtract_from_result (resultP, frag_off / OCTETS_PER_BYTE, 0); + add_to_result (resultP, symval_diff, symval_diff < 0); resultP->X_op = O_constant; resultP->X_add_symbol = 0; } @@ -1861,7 +1904,7 @@ expr (int rankarg, /* Larger # is higher rank. */ && (md_register_arithmetic || resultP->X_op != O_register)) { /* X - constant. */ - resultP->X_add_number -= right.X_add_number; + subtract_from_result (resultP, right.X_add_number, right.X_extrabit); } else if (op_left == O_add && resultP->X_op == O_constant && (md_register_arithmetic || right.X_op != O_register)) @@ -1870,7 +1913,7 @@ expr (int rankarg, /* Larger # is higher rank. */ resultP->X_op = right.X_op; resultP->X_add_symbol = right.X_add_symbol; resultP->X_op_symbol = right.X_op_symbol; - resultP->X_add_number += right.X_add_number; + add_to_result (resultP, right.X_add_number, right.X_extrabit); retval = rightseg; } else if (resultP->X_op == O_constant && right.X_op == O_constant) @@ -1910,7 +1953,9 @@ expr (int rankarg, /* Larger # is higher rank. */ /* Constant + constant (O_add) is handled by the previous if statement for constant + X, so is omitted here. */ - case O_subtract: resultP->X_add_number -= v; break; + case O_subtract: + subtract_from_result (resultP, v, 0); + break; case O_eq: resultP->X_add_number = resultP->X_add_number == v ? ~ (offsetT) 0 : 0; @@ -1954,10 +1999,11 @@ expr (int rankarg, /* Larger # is higher rank. */ resultP->X_op = op_left; resultP->X_op_symbol = right.X_add_symbol; if (op_left == O_add) - resultP->X_add_number += right.X_add_number; + add_to_result (resultP, right.X_add_number, right.X_extrabit); else if (op_left == O_subtract) { - resultP->X_add_number -= right.X_add_number; + subtract_from_result (resultP, right.X_add_number, + right.X_extrabit); if (retval == rightseg && SEG_NORMAL (retval) && !S_FORCE_RELOC (resultP->X_add_symbol, 0) @@ -1977,6 +2023,7 @@ expr (int rankarg, /* Larger # is higher rank. */ resultP->X_op = op_left; resultP->X_add_number = 0; resultP->X_unsigned = 1; + resultP->X_extrabit = 0; } if (retval != rightseg) @@ -136,6 +136,11 @@ typedef struct expressionS { when performing arithmetic on these values). FIXME: This field is not set very reliably. */ unsigned int X_unsigned : 1; + /* This is used to implement "word size + 1 bit" arithmetic, so that e.g. + expressions used with .sleb128 directives can use the full range available + for an unsigned word, but can also properly represent all values of a + signed word. */ + unsigned int X_extrabit : 1; /* 7 additional bits can be defined if needed. */ @@ -1306,10 +1306,10 @@ read_a_source_file (char *name) } /* 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. */ + Take the sign of the number from SIGN rather than X_add_number. */ static void -convert_to_bignum (expressionS *exp) +convert_to_bignum (expressionS *exp, int sign) { valueT value; unsigned int i; @@ -1322,8 +1322,8 @@ convert_to_bignum (expressionS *exp) } /* 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; + if ((exp->X_add_number < 0) == !sign) + generic_bignum[i++] = sign ? LITTLENUM_MASK : 0; exp->X_op = O_big; exp->X_add_number = i; } @@ -4250,7 +4250,7 @@ emit_expr (expressionS *exp, unsigned int nbytes) if (op == O_constant && nbytes > sizeof (valueT)) { extra_digit = exp->X_unsigned ? 0 : -1; - convert_to_bignum (exp); + convert_to_bignum (exp, !exp->X_unsigned); op = O_big; } @@ -4544,6 +4544,7 @@ parse_bitfield_cons (exp, nbytes) exp->X_add_number = value; exp->X_op = O_constant; exp->X_unsigned = 1; + exp->X_extrabit = 0; } } @@ -5103,12 +5104,12 @@ emit_leb128_expr (expressionS *exp, int sign) } else if (op == O_constant && sign - && (exp->X_add_number < 0) != !exp->X_unsigned) + && (exp->X_add_number < 0) == !exp->X_extrabit) { /* 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); + convert_to_bignum (exp, exp->X_extrabit); op = O_big; } diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index 9f8c2a4..5db53c8 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,18 @@ +2013-04-10 Julian Brown <julian@codesourcery.com> + + * gas/all/sleb128-2.s: New test. + * gas/all/sleb128-3.s: Likewise. + * gas/all/sleb128-4.s: Likewise. + * gas/all/sleb128-5.s: Likewise. + * gas/all/sleb128-7.s: Likewise. + * gas/all/sleb128-2.d: New. + * gas/all/sleb128-3.d: New. + * gas/all/sleb123-4.d: New. + * gas/all/sleb123-5.d: New. + * gas/all/sleb123-7.d: New. + * gas/all/gas.exp (sleb128-2, sleb128-3, sleb128-4, sleb128-5) + (sleb128-7): Run new tests. + 2013-04-10 Jan Beulich <jbeulich@suse.com> * gas/testsuite/gas/arm/ldst-pc.s: Add index, non-writeback diff --git a/gas/testsuite/gas/all/gas.exp b/gas/testsuite/gas/all/gas.exp index 72db9cc..c85d918 100644 --- a/gas/testsuite/gas/all/gas.exp +++ b/gas/testsuite/gas/all/gas.exp @@ -369,6 +369,11 @@ if { ![istarget "bfin-*-*"] } then { run_dump_test assign } run_dump_test sleb128 +run_dump_test sleb128-2 +run_dump_test sleb128-3 +run_dump_test sleb128-4 +run_dump_test sleb128-5 +run_dump_test sleb128-7 # .byte is 32 bits on tic4x, and .p2align isn't supported on tic54x # .space is different on hppa*-hpux. diff --git a/gas/testsuite/gas/all/sleb128-2.d b/gas/testsuite/gas/all/sleb128-2.d new file mode 100644 index 0000000..f3d052d --- /dev/null +++ b/gas/testsuite/gas/all/sleb128-2.d @@ -0,0 +1,7 @@ +#objdump : -s -j .data +#name : .sleb128 tests (2) + +.*: .* + +Contents of section \.data: + .* 7d2a.* diff --git a/gas/testsuite/gas/all/sleb128-2.s b/gas/testsuite/gas/all/sleb128-2.s new file mode 100644 index 0000000..49c52af --- /dev/null +++ b/gas/testsuite/gas/all/sleb128-2.s @@ -0,0 +1,13 @@ +.text +.globl foo +foo: +.L1: +.byte 0 +.byte 0 +.byte 0 +.L2: + +.data +bar: +.sleb128 .L1 - .L2 +.byte 42 diff --git a/gas/testsuite/gas/all/sleb128-3.d b/gas/testsuite/gas/all/sleb128-3.d new file mode 100644 index 0000000..ffb3a26 --- /dev/null +++ b/gas/testsuite/gas/all/sleb128-3.d @@ -0,0 +1,7 @@ +#objdump : -s -j .data +#name : .sleb128 tests (3) + +.*: .* + +Contents of section \.data: + .* 9c7f2a.* diff --git a/gas/testsuite/gas/all/sleb128-3.s b/gas/testsuite/gas/all/sleb128-3.s new file mode 100644 index 0000000..8aa8026 --- /dev/null +++ b/gas/testsuite/gas/all/sleb128-3.s @@ -0,0 +1,4 @@ +.data +bar: +.sleb128 100 - 200 +.byte 42 diff --git a/gas/testsuite/gas/all/sleb128-4.d b/gas/testsuite/gas/all/sleb128-4.d new file mode 100644 index 0000000..80c99ab --- /dev/null +++ b/gas/testsuite/gas/all/sleb128-4.d @@ -0,0 +1,7 @@ +#objdump : -s -j .data +#name : .sleb128 tests (4) + +.*: .* + +Contents of section \.data: + .* 83808080 082a.* diff --git a/gas/testsuite/gas/all/sleb128-4.s b/gas/testsuite/gas/all/sleb128-4.s new file mode 100644 index 0000000..a2d9d82 --- /dev/null +++ b/gas/testsuite/gas/all/sleb128-4.s @@ -0,0 +1,13 @@ +.text +.globl foo +foo: +.L1: +.byte 0 +.byte 0 +.byte 0 +.L2: + +.data +bar: +.sleb128 .L2 - .L1 + (1 << 31) +.byte 42 diff --git a/gas/testsuite/gas/all/sleb128-5.d b/gas/testsuite/gas/all/sleb128-5.d new file mode 100644 index 0000000..1e39242 --- /dev/null +++ b/gas/testsuite/gas/all/sleb128-5.d @@ -0,0 +1,7 @@ +#objdump : -s -j .data +#name : .sleb128 tests (5) + +.*: .* + +Contents of section \.data: + .* 012a.* diff --git a/gas/testsuite/gas/all/sleb128-5.s b/gas/testsuite/gas/all/sleb128-5.s new file mode 100644 index 0000000..64e5793 --- /dev/null +++ b/gas/testsuite/gas/all/sleb128-5.s @@ -0,0 +1,13 @@ +.text +.globl foo +foo: +.L1: +.byte 0 +.byte 0 +.byte 0 +.L2: + +.data +bar: +.sleb128 .L1 - .L2 + 4 +.byte 42 diff --git a/gas/testsuite/gas/all/sleb128-7.d b/gas/testsuite/gas/all/sleb128-7.d new file mode 100644 index 0000000..805ee4d --- /dev/null +++ b/gas/testsuite/gas/all/sleb128-7.d @@ -0,0 +1,7 @@ +#objdump : -s -j .data +#name : .sleb128 tests (7) + +.*: .* + +Contents of section \.data: + .* cb012ac5 012acb01 2ac5012a.* diff --git a/gas/testsuite/gas/all/sleb128-7.s b/gas/testsuite/gas/all/sleb128-7.s new file mode 100644 index 0000000..323689b --- /dev/null +++ b/gas/testsuite/gas/all/sleb128-7.s @@ -0,0 +1,19 @@ +.text +.globl foo +foo: +.L1: +.byte 0 +.byte 0 +.byte 0 +.L2: + +.data +bar: +.sleb128 200+(.L2 - .L1) +.byte 42 +.sleb128 200+(.L1 - .L2) +.byte 42 +.sleb128 (.L2 - .L1)+200 +.byte 42 +.sleb128 (.L1 - .L2)+200 +.byte 42 |