From 956a6ba3fe11b9dc24212dc65a32b057077e227f Mon Sep 17 00:00:00 2001 From: Julian Brown Date: Thu, 11 Apr 2013 10:54:13 +0000 Subject: gas/ * 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. gas/testsuite/ * 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. --- gas/expr.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 10 deletions(-) (limited to 'gas/expr.c') diff --git a/gas/expr.c b/gas/expr.c index 500f93840ba..64011b497de 100644 --- a/gas/expr.c +++ b/gas/expr.c @@ -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) -- cgit v1.2.1