/* expr.c -operands, expressions-
- Copyright (C) 1987-2019 Free Software Foundation, Inc.
+ Copyright (C) 1987-2021 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
#include "as.h"
#include "safe-ctype.h"
-#ifdef HAVE_LIMITS_H
#include <limits.h>
-#endif
#ifndef CHAR_BIT
#define CHAR_BIT 8
#endif
-bfd_boolean literal_prefix_dollar_hex = FALSE;
+bool literal_prefix_dollar_hex = false;
-static void floating_constant (expressionS * expressionP);
-static valueT generic_bignum_to_int32 (void);
-#ifdef BFD64
-static valueT generic_bignum_to_int64 (void);
-#endif
-static void integer_constant (int radix, expressionS * expressionP);
-static void mri_char_constant (expressionS *);
static void clean_up_expression (expressionS * expressionP);
-static segT operand (expressionS *, enum expr_mode);
-static operatorT operatorf (int *);
/* We keep a mapping of expression symbols to file positions, so that
we can provide better error messages. */
: expressionP->X_op == O_register
? reg_section
: expr_section),
- 0, &zero_address_frag);
+ &zero_address_frag, 0);
symbol_set_value_expression (symbolP, expressionP);
if (expressionP->X_op == O_constant)
return 0;
}
+
+/* Look up a previously used .startof. / .sizeof. symbol, or make a fresh
+ one. */
+
+static symbolS *
+symbol_lookup_or_make (const char *name, bool start)
+{
+ static symbolS **seen[2];
+ static unsigned int nr_seen[2];
+ char *buf = concat (start ? ".startof." : ".sizeof.", name, NULL);
+ symbolS *symbolP;
+ unsigned int i;
+
+ for (i = 0; i < nr_seen[start]; ++i)
+ {
+ symbolP = seen[start][i];
+
+ if (! symbolP)
+ break;
+
+ name = S_GET_NAME (symbolP);
+ if ((symbols_case_sensitive
+ ? strcasecmp (buf, name)
+ : strcmp (buf, name)) == 0)
+ {
+ free (buf);
+ return symbolP;
+ }
+ }
+
+ symbolP = symbol_make (buf);
+ free (buf);
+
+ if (i >= nr_seen[start])
+ {
+ unsigned int nr = (i + 1) * 2;
+
+ seen[start] = XRESIZEVEC (symbolS *, seen[start], nr);
+ nr_seen[start] = nr;
+ memset (&seen[start][i + 1], 0, (nr - i - 1) * sizeof(seen[0][0]));
+ }
+
+ seen[start][i] = symbolP;
+
+ return symbolP;
+}
\f
/* Utilities for building expressions.
Since complex expressions are recorded as symbols for use in other
expressionP->X_add_number = -1;
}
-static valueT
+uint32_t
generic_bignum_to_int32 (void)
{
- valueT number =
- ((generic_bignum[1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS)
- | (generic_bignum[0] & LITTLENUM_MASK);
- number &= 0xffffffff;
- return number;
+ return ((((uint32_t) generic_bignum[1] & LITTLENUM_MASK)
+ << LITTLENUM_NUMBER_OF_BITS)
+ | ((uint32_t) generic_bignum[0] & LITTLENUM_MASK));
}
-#ifdef BFD64
-static valueT
+uint64_t
generic_bignum_to_int64 (void)
{
- valueT number =
- ((((((((valueT) generic_bignum[3] & LITTLENUM_MASK)
- << LITTLENUM_NUMBER_OF_BITS)
- | ((valueT) generic_bignum[2] & LITTLENUM_MASK))
- << LITTLENUM_NUMBER_OF_BITS)
- | ((valueT) generic_bignum[1] & LITTLENUM_MASK))
- << LITTLENUM_NUMBER_OF_BITS)
- | ((valueT) generic_bignum[0] & LITTLENUM_MASK));
- return number;
+ return ((((((((uint64_t) generic_bignum[3] & LITTLENUM_MASK)
+ << LITTLENUM_NUMBER_OF_BITS)
+ | ((uint64_t) generic_bignum[2] & LITTLENUM_MASK))
+ << LITTLENUM_NUMBER_OF_BITS)
+ | ((uint64_t) generic_bignum[1] & LITTLENUM_MASK))
+ << LITTLENUM_NUMBER_OF_BITS)
+ | ((uint64_t) generic_bignum[0] & LITTLENUM_MASK));
}
-#endif
static void
integer_constant (int radix, expressionS *expressionP)
expressionP);
break;
- case '$':
- if (literal_prefix_dollar_hex)
- {
- /* $L is the start of a local label, not a hex constant. */
- if (* input_line_pointer == 'L')
- goto isname;
- integer_constant (16, expressionP);
- }
- else
- {
- goto isname;
- }
- break;
-
#ifdef LITERAL_PREFIXPERCENT_BIN
case '%':
integer_constant (2, expressionP);
expressionP->X_extrabit ^= 1;
}
else if (c == '~' || c == '"')
- expressionP->X_add_number = ~ expressionP->X_add_number;
+ {
+ expressionP->X_add_number = ~ expressionP->X_add_number;
+ expressionP->X_extrabit ^= 1;
+ }
else if (c == '!')
- expressionP->X_add_number = ! expressionP->X_add_number;
+ {
+ expressionP->X_add_number = ! expressionP->X_add_number;
+ expressionP->X_unsigned = 1;
+ expressionP->X_extrabit = 0;
+ }
}
else if (expressionP->X_op == O_big
&& expressionP->X_add_number <= 0
}
break;
-#if defined (DOLLAR_DOT) || defined (TC_M68K)
+#if !defined (DOLLAR_DOT) && !defined (TC_M68K)
+ case '$':
+ if (literal_prefix_dollar_hex)
+ {
+ /* $L is the start of a local label, not a hex constant. */
+ if (* input_line_pointer == 'L')
+ goto isname;
+ integer_constant (16, expressionP);
+ }
+ else
+ {
+ goto isname;
+ }
+ break;
+#else
case '$':
/* '$' is the program counter when in MRI mode, or when
DOLLAR_DOT is defined. */
as_bad (_("syntax error in .startof. or .sizeof."));
else
{
- char *buf;
-
++input_line_pointer;
SKIP_WHITESPACE ();
c = get_symbol_name (& name);
break;
}
- buf = concat (start ? ".startof." : ".sizeof.", name,
- (char *) NULL);
- symbolP = symbol_make (buf);
- free (buf);
-
expressionP->X_op = O_symbol;
- expressionP->X_add_symbol = symbolP;
+ expressionP->X_add_symbol = symbol_lookup_or_make (name, start);
expressionP->X_add_number = 0;
*input_line_pointer = c;
valueT ures = resultP->X_add_number;
valueT uamount = amount;
- resultP->X_add_number += amount;
+ resultP->X_add_number += uamount;
resultP->X_extrabit ^= rhs_highbit;
valueT ures = resultP->X_add_number;
valueT uamount = amount;
- resultP->X_add_number -= amount;
+ resultP->X_add_number -= uamount;
resultP->X_extrabit ^= rhs_highbit;
case O_multiply: resultP->X_add_number *= v; break;
case O_divide: resultP->X_add_number /= v; break;
case O_modulus: resultP->X_add_number %= v; break;
- case O_left_shift: resultP->X_add_number <<= v; break;
+ case O_left_shift:
+ /* We always use unsigned shifts. According to the ISO
+ C standard, left shift of a signed type having a
+ negative value is undefined behaviour, and right
+ shift of a signed type having negative value is
+ implementation defined. Left shift of a signed type
+ when the result overflows is also undefined
+ behaviour. So don't trigger ubsan warnings or rely
+ on characteristics of the compiler. */
+ resultP->X_add_number
+ = (valueT) resultP->X_add_number << (valueT) v;
+ break;
case O_right_shift:
- /* We always use unsigned shifts, to avoid relying on
- characteristics of the compiler used to compile gas. */
- resultP->X_add_number =
- (offsetT) ((valueT) resultP->X_add_number >> (valueT) v);
+ resultP->X_add_number
+ = (valueT) resultP->X_add_number >> (valueT) v;
break;
case O_bit_inclusive_or: resultP->X_add_number |= v; break;
case O_bit_or_not: resultP->X_add_number |= ~v; break;
}
else if (c == '"')
{
- bfd_boolean backslash_seen;
+ bool backslash_seen;
* ilp_return = input_line_pointer;
do