/* expr.c -operands, expressions-
Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009
- Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2011,
+ 2012 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
zero.X_op = O_constant;
zero.X_add_number = 0;
zero.X_unsigned = 0;
+ zero.X_extrabit = 0;
clean_up_expression (&zero);
expressionP = &zero;
}
e.X_op = O_constant;
e.X_add_number = value;
e.X_unsigned = 1;
+ e.X_extrabit = 0;
return make_expr_symbol (&e);
}
expressionS e;
current_location (&e);
- return make_expr_symbol (&e);
+ return symbol_clone_if_forward_ref (make_expr_symbol (&e));
}
\f
/* Build any floating-point literal here.
else
{
expressionp->X_op = O_symbol;
- expressionp->X_add_symbol = symbol_temp_new_now ();
+ expressionp->X_add_symbol = &dot_symbol;
expressionp->X_add_number = 0;
}
}
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. */
#endif
case '(':
/* Didn't begin with digit & not a name. */
- if (mode != expr_defer)
- segment = expression (expressionP);
- else
- segment = deferred_expression (expressionP);
+ segment = expr (0, expressionP, mode);
/* expression () will pass trailing whitespace. */
if ((c == '(' && *input_line_pointer != ')')
|| (c == '[' && *input_line_pointer != ']'))
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;
{
for (i = 0; i < expressionP->X_add_number; ++i)
generic_bignum[i] = ~generic_bignum[i];
+
+ /* Extend the bignum to at least the size of .octa. */
+ if (expressionP->X_add_number < SIZE_OF_LARGE_NUMBER)
+ {
+ expressionP->X_add_number = SIZE_OF_LARGE_NUMBER;
+ for (; i < expressionP->X_add_number; ++i)
+ generic_bignum[i] = ~(LITTLENUM_TYPE) 0;
+ }
+
if (c == '-')
for (i = 0; i < expressionP->X_add_number; ++i)
{
}
else if (c == '!')
{
- int nonzero = 0;
for (i = 0; i < expressionP->X_add_number; ++i)
- {
- if (generic_bignum[i])
- nonzero = 1;
- generic_bignum[i] = 0;
- }
- generic_bignum[0] = nonzero;
+ if (generic_bignum[i] != 0)
+ break;
+ 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
/* If we have an absolute symbol or a reg, then we know its
value now. */
segment = S_GET_SEGMENT (symbolP);
- if (mode != expr_defer && segment == absolute_section)
+ if (mode != expr_defer
+ && segment == absolute_section
+ && !S_FORCE_RELOC (symbolP, 0))
{
expressionP->X_op = O_constant;
expressionP->X_add_number = S_GET_VALUE (symbolP);
if (expressionP->X_add_symbol)
symbol_mark_used (expressionP->X_add_symbol);
- expressionP->X_add_symbol = symbol_clone_if_forward_ref (expressionP->X_add_symbol);
- expressionP->X_op_symbol = symbol_clone_if_forward_ref (expressionP->X_op_symbol);
+ if (mode != expr_defer)
+ {
+ expressionP->X_add_symbol
+ = symbol_clone_if_forward_ref (expressionP->X_add_symbol);
+ expressionP->X_op_symbol
+ = symbol_clone_if_forward_ref (expressionP->X_op_symbol);
+ }
switch (expressionP->X_op)
{
/* 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. */
+
+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. */
+
+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
/* Save the value of dot for the fixup code. */
if (rank == 0)
- dot_value = frag_now_fix ();
+ {
+ dot_value = frag_now_fix ();
+ dot_frag = frag_now;
+ }
retval = operand (resultP, mode);
while (op_left != O_illegal && op_rank[(int) op_left] > rank)
{
segT rightseg;
- bfd_vma frag_off;
+ offsetT frag_off;
input_line_pointer += op_chars; /* -> after operator. */
&& (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
#ifdef md_allow_local_subtract
&& md_allow_local_subtract (resultP, & right, rightseg)
#endif
- && (SEG_NORMAL (rightseg)
+ && ((SEG_NORMAL (rightseg)
+ && !S_FORCE_RELOC (resultP->X_add_symbol, 0)
+ && !S_FORCE_RELOC (right.X_add_symbol, 0))
|| right.X_add_symbol == resultP->X_add_symbol)
&& frag_offset_fixed_p (symbol_get_frag (resultP->X_add_symbol),
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;
}
&& (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))
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)
/* 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;
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;
- if (retval == rightseg && SEG_NORMAL (retval))
+ 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)
+ && !S_FORCE_RELOC (right.X_add_symbol, 0))
{
retval = absolute_section;
rightseg = absolute_section;
resultP->X_op = op_left;
resultP->X_add_number = 0;
resultP->X_unsigned = 1;
+ resultP->X_extrabit = 0;
}
if (retval != rightseg)
{
- if (! SEG_NORMAL (retval))
- {
- if (retval != undefined_section || SEG_NORMAL (rightseg))
- retval = rightseg;
- }
- else if (SEG_NORMAL (rightseg)
+ if (retval == undefined_section)
+ ;
+ else if (rightseg == undefined_section)
+ retval = rightseg;
+ else if (retval == expr_section)
+ ;
+ else if (rightseg == expr_section)
+ retval = rightseg;
+ else if (retval == reg_section)
+ ;
+ else if (rightseg == reg_section)
+ retval = rightseg;
+ else if (rightseg == absolute_section)
+ ;
+ else if (retval == absolute_section)
+ retval = rightseg;
#ifdef DIFF_EXPR_OK
- && op_left != O_subtract
+ else if (op_left == O_subtract)
+ ;
#endif
- )
+ else
as_bad (_("operation combines symbols in different segments"));
}
valueT left, right;
segT seg_left, seg_right;
fragS *frag_left, *frag_right;
- bfd_vma frag_off;
+ offsetT frag_off;
switch (op)
{