X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Fexpr.c;h=6f8ccb823031f737e0472ff1f674e19c7d763855;hb=c7d7aea2f5fadff84eee78aaa0b1830016d26319;hp=c601b0af6986e89312ffcc6c2e018f2b328003ef;hpb=4fa6945e82654828587750f5c85ce30b88f91886;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/expr.c b/gas/expr.c index c601b0af69..6f8ccb8230 100644 --- a/gas/expr.c +++ b/gas/expr.c @@ -1,13 +1,11 @@ /* expr.c -operands, expressions- - Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005 - Free Software Foundation, Inc. + Copyright (C) 1987-2020 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) + the Free Software Foundation; either version 3, or (at your option) any later version. GAS is distributed in the hope that it will be useful, @@ -25,12 +23,19 @@ (It also gives smaller files to re-compile.) Here, "operand"s are of expressions, not instructions. */ -#include #define min(a, b) ((a) < (b) ? (a) : (b)) #include "as.h" #include "safe-ctype.h" -#include "obstack.h" + +#ifdef HAVE_LIMITS_H +#include +#endif +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif + +bfd_boolean literal_prefix_dollar_hex = FALSE; static void floating_constant (expressionS * expressionP); static valueT generic_bignum_to_int32 (void); @@ -39,12 +44,9 @@ static valueT generic_bignum_to_int64 (void); #endif static void integer_constant (int radix, expressionS * expressionP); static void mri_char_constant (expressionS *); -static void current_location (expressionS *); static void clean_up_expression (expressionS * expressionP); static segT operand (expressionS *, enum expr_mode); -static operatorT operator (int *); - -extern const char EXP_CHARS[], FLT_CHARS[]; +static operatorT operatorf (int *); /* We keep a mapping of expression symbols to file positions, so that we can provide better error messages. */ @@ -52,7 +54,7 @@ extern const char EXP_CHARS[], FLT_CHARS[]; struct expr_symbol_line { struct expr_symbol_line *next; symbolS *sym; - char *file; + const char *file; unsigned int line; }; @@ -85,6 +87,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; } @@ -96,16 +99,18 @@ make_expr_symbol (expressionS *expressionP) symbolP = symbol_create (FAKE_LABEL_NAME, (expressionP->X_op == O_constant ? absolute_section - : expr_section), + : expressionP->X_op == O_register + ? reg_section + : expr_section), 0, &zero_address_frag); symbol_set_value_expression (symbolP, expressionP); if (expressionP->X_op == O_constant) resolve_symbol_value (symbolP); - n = (struct expr_symbol_line *) xmalloc (sizeof *n); + n = XNEW (struct expr_symbol_line); n->sym = symbolP; - as_where (&n->file, &n->line); + n->file = as_where (&n->line); n->next = expr_symbol_lines; expr_symbol_lines = n; @@ -117,9 +122,9 @@ make_expr_symbol (expressionS *expressionP) the symbol. */ int -expr_symbol_where (symbolS *sym, char **pfile, unsigned int *pline) +expr_symbol_where (symbolS *sym, const char **pfile, unsigned int *pline) { - register struct expr_symbol_line *l; + struct expr_symbol_line *l; for (l = expr_symbol_lines; l != NULL; l = l->next) { @@ -154,6 +159,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); } @@ -165,7 +171,7 @@ expr_build_dot (void) expressionS e; current_location (&e); - return make_expr_symbol (&e); + return symbol_clone_if_forward_ref (make_expr_symbol (&e)); } /* Build any floating-point literal here. @@ -279,6 +285,12 @@ integer_constant (int radix, expressionS *expressionP) #define valuesize 32 #endif + if (is_end_of_line[(unsigned char) *input_line_pointer]) + { + expressionP->X_op = O_absent; + return; + } + if ((NUMBERS_WITH_SUFFIX || flag_m68k_mri) && radix == 0) { int flt = 0; @@ -403,7 +415,7 @@ integer_constant (int radix, expressionS *expressionP) if (num_little_digits > SIZE_OF_LARGE_NUMBER - 1) num_little_digits = SIZE_OF_LARGE_NUMBER - 1; - assert (num_little_digits >= 4); + gas_assert (num_little_digits >= 4); if (num_little_digits != 8) as_bad (_("a bignum with underscores must have exactly 4 words")); @@ -498,6 +510,21 @@ integer_constant (int radix, expressionS *expressionP) && input_line_pointer - 1 == suffix) c = *input_line_pointer++; +#ifndef tc_allow_U_suffix +#define tc_allow_U_suffix 1 +#endif + /* PR 19910: Look for, and ignore, a U suffix to the number. */ + if (tc_allow_U_suffix && (c == 'U' || c == 'u')) + c = * input_line_pointer++; + +#ifndef tc_allow_L_suffix +#define tc_allow_L_suffix 1 +#endif + /* PR 20732: Look for, and ignore, a L or LL suffix to the number. */ + if (tc_allow_L_suffix) + while (c == 'L' || c == 'l') + c = * input_line_pointer++; + if (small) { /* Here with number, in correct radix. c is the next char. @@ -687,7 +714,7 @@ mri_char_constant (expressionS *expressionP) /* Return an expression representing the current location. This handles the magic symbol `.'. */ -static void +void current_location (expressionS *expressionp) { if (now_seg == absolute_section) @@ -698,7 +725,7 @@ current_location (expressionS *expressionp) 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; } } @@ -725,6 +752,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. */ @@ -752,15 +780,6 @@ operand (expressionS *expressionP, enum expr_mode mode) expressionP); break; -#ifdef LITERAL_PREFIXDOLLAR_HEX - case '$': - /* $L is the start of a local label, not a hex constant. */ - if (* input_line_pointer == 'L') - goto isname; - integer_constant (16, expressionP); - break; -#endif - #ifdef LITERAL_PREFIXPERCENT_BIN case '%': integer_constant (2, expressionP); @@ -825,32 +844,28 @@ operand (expressionS *expressionP, enum expr_mode mode) break; case 'b': - if (LOCAL_LABELS_FB && ! (flag_m68k_mri || NUMBERS_WITH_SUFFIX)) + if (LOCAL_LABELS_FB && !flag_m68k_mri + && input_line_pointer[1] != '0' + && input_line_pointer[1] != '1') { - /* This code used to check for '+' and '-' here, and, in - some conditions, fall through to call - integer_constant. However, that didn't make sense, - as integer_constant only accepts digits. */ - /* Some of our code elsewhere does permit digits greater - than the expected base; for consistency, do the same - here. */ - if (input_line_pointer[1] < '0' - || input_line_pointer[1] > '9') - { - /* Parse this as a back reference to label 0. */ - input_line_pointer--; - integer_constant (10, expressionP); - break; - } - /* Otherwise, parse this as a binary number. */ + /* Parse this as a back reference to label 0. */ + input_line_pointer--; + integer_constant (10, expressionP); + break; } + /* Otherwise, parse this as a binary number. */ /* Fall through. */ case 'B': - input_line_pointer++; + if (input_line_pointer[1] == '0' + || input_line_pointer[1] == '1') + { + input_line_pointer++; + integer_constant (2, expressionP); + break; + } if (flag_m68k_mri || NUMBERS_WITH_SUFFIX) - goto default_case; - integer_constant (2, expressionP); - break; + input_line_pointer++; + goto default_case; case '0': case '1': @@ -868,48 +883,35 @@ operand (expressionS *expressionP, enum expr_mode mode) case 'f': if (LOCAL_LABELS_FB) { + int is_label = 1; + /* If it says "0f" and it could possibly be a floating point number, make it one. Otherwise, make it a local label, and try to deal with parsing the rest later. */ - if (!input_line_pointer[1] - || (is_end_of_line[0xff & input_line_pointer[1]]) - || strchr (FLT_CHARS, 'f') == NULL) - goto is_0f_label; - { - char *cp = input_line_pointer + 1; - int r = atof_generic (&cp, ".", EXP_CHARS, - &generic_floating_point_number); - switch (r) - { - case 0: - case ERROR_EXPONENT_OVERFLOW: - if (*cp == 'f' || *cp == 'b') - /* Looks like a difference expression. */ - goto is_0f_label; - else if (cp == input_line_pointer + 1) - /* No characters has been accepted -- looks like - end of operand. */ - goto is_0f_label; - else - goto is_0f_float; - default: - as_fatal (_("expr.c(operand): bad atof_generic return val %d"), - r); - } - } - - /* Okay, now we've sorted it out. We resume at one of these - two labels, depending on what we've decided we're probably - looking at. */ - is_0f_label: - input_line_pointer--; - integer_constant (10, expressionP); - break; - - is_0f_float: - /* Fall through. */ - ; + if (!is_end_of_line[(unsigned char) input_line_pointer[1]] + && strchr (FLT_CHARS, 'f') != NULL) + { + char *cp = input_line_pointer + 1; + + atof_generic (&cp, ".", EXP_CHARS, + &generic_floating_point_number); + + /* Was nothing parsed, or does it look like an + expression? */ + is_label = (cp == input_line_pointer + 1 + || (cp == input_line_pointer + 2 + && (cp[-1] == '-' || cp[-1] == '+')) + || *cp == 'f' + || *cp == 'b'); + } + if (is_label) + { + input_line_pointer--; + integer_constant (10, expressionP); + break; + } } + /* Fall through. */ case 'd': case 'D': @@ -942,19 +944,27 @@ operand (expressionS *expressionP, enum expr_mode mode) break; - case '(': #ifndef NEED_INDEX_OPERATOR case '[': +# ifdef md_need_index_operator + if (md_need_index_operator()) + goto de_fault; +# endif #endif + /* Fall through. */ + 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 != ']')) - as_bad (_("missing '%c'"), c == '(' ? ')' : ']'); + { + if (* input_line_pointer) + as_bad (_("found '%c', expected: '%c'"), + * input_line_pointer, c == '(' ? ')' : ']'); + else + as_bad (_("missing '%c'"), c == '(' ? ')' : ']'); + } else input_line_pointer++; SKIP_WHITESPACE (); @@ -971,8 +981,8 @@ operand (expressionS *expressionP, enum expr_mode mode) if (! flag_m68k_mri || *input_line_pointer != '\'') goto de_fault; ++input_line_pointer; - /* Fall through. */ #endif + /* Fall through. */ case '\'': if (! flag_m68k_mri) { @@ -993,32 +1003,34 @@ operand (expressionS *expressionP, enum expr_mode mode) /* Double quote is the bitwise not operator in MRI mode. */ if (! flag_m68k_mri) goto de_fault; - /* Fall through. */ #endif + /* Fall through. */ case '~': /* '~' is permitted to start a label on the Delta. */ if (is_name_beginner (c)) goto isname; + /* Fall through. */ case '!': case '-': case '+': { - /* Do not accept ++e or --e as +(+e) or -(-e) - Disabled, since the preprocessor removes whitespace. */ - if (0 && (c == '-' || c == '+') && *input_line_pointer == c) - goto target_op; - +#ifdef md_operator + unary: +#endif operand (expressionP, mode); if (expressionP->X_op == O_constant) { /* input_line_pointer -> char after operand. */ if (c == '-') { - expressionP->X_add_number = - expressionP->X_add_number; + expressionP->X_add_number + = - (addressT) expressionP->X_add_number; /* Notice: '-' may overflow: no warning is given. 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; @@ -1046,6 +1058,15 @@ operand (expressionS *expressionP, enum expr_mode mode) { 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) { @@ -1056,14 +1077,13 @@ operand (expressionS *expressionP, enum expr_mode mode) } 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 @@ -1087,7 +1107,21 @@ operand (expressionS *expressionP, enum expr_mode mode) } 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. */ @@ -1127,6 +1161,10 @@ operand (expressionS *expressionP, enum expr_mode mode) || input_line_pointer[1] == 'T'); input_line_pointer += start ? 8 : 7; SKIP_WHITESPACE (); + + /* Cover for the as_bad () invocations below. */ + expressionP->X_op = O_absent; + if (*input_line_pointer != '(') as_bad (_("syntax error in .startof. or .sizeof.")); else @@ -1135,14 +1173,20 @@ operand (expressionS *expressionP, enum expr_mode mode) ++input_line_pointer; SKIP_WHITESPACE (); - name = input_line_pointer; - c = get_symbol_end (); + c = get_symbol_name (& name); + if (! *name) + { + as_bad (_("expected symbol name")); + (void) restore_line_pointer (c); + if (c != ')') + ignore_rest_of_line (); + else + ++input_line_pointer; + break; + } - buf = (char *) xmalloc (strlen (name) + 10); - if (start) - sprintf (buf, ".startof.%s", name); - else - sprintf (buf, ".sizeof.%s", name); + buf = concat (start ? ".startof." : ".sizeof.", name, + (char *) NULL); symbolP = symbol_make (buf); free (buf); @@ -1151,7 +1195,7 @@ operand (expressionS *expressionP, enum expr_mode mode) expressionP->X_add_number = 0; *input_line_pointer = c; - SKIP_WHITESPACE (); + SKIP_WHITESPACE_AFTER_NAME (); if (*input_line_pointer != ')') as_bad (_("syntax error in .startof. or .sizeof.")); else @@ -1204,16 +1248,54 @@ operand (expressionS *expressionP, enum expr_mode mode) #endif default: -#ifdef TC_M68K +#if defined(md_need_index_operator) || defined(TC_M68K) de_fault: #endif - if (is_name_beginner (c)) /* Here if did not begin with a digit. */ + if (is_name_beginner (c) || c == '"') /* Here if did not begin with a digit. */ { /* Identifier begins here. This is kludged for speed, so code is repeated. */ isname: - name = --input_line_pointer; - c = get_symbol_end (); + -- input_line_pointer; + c = get_symbol_name (&name); + +#ifdef md_operator + { + operatorT op = md_operator (name, 1, &c); + + switch (op) + { + case O_uminus: + restore_line_pointer (c); + c = '-'; + goto unary; + case O_bit_not: + restore_line_pointer (c); + c = '~'; + goto unary; + case O_logical_not: + restore_line_pointer (c); + c = '!'; + goto unary; + case O_illegal: + as_bad (_("invalid use of operator \"%s\""), name); + break; + default: + break; + } + + if (op != O_absent && op != O_illegal) + { + restore_line_pointer (c); + expr (9, expressionP, mode); + expressionP->X_add_symbol = make_expr_symbol (expressionP); + expressionP->X_op_symbol = NULL; + expressionP->X_add_number = 0; + expressionP->X_op = op; + break; + } + } +#endif #ifdef md_parse_name /* This is a hook for the backend to parse certain names @@ -1222,46 +1304,7 @@ operand (expressionS *expressionP, enum expr_mode mode) entering it in the symbol table. */ if (md_parse_name (name, expressionP, mode, &c)) { - *input_line_pointer = c; - break; - } -#endif - -#ifdef TC_I960 - /* The MRI i960 assembler permits - lda sizeof code,g13 - FIXME: This should use md_parse_name. */ - if (flag_mri - && (strcasecmp (name, "sizeof") == 0 - || strcasecmp (name, "startof") == 0)) - { - int start; - char *buf; - - start = (name[1] == 't' - || name[1] == 'T'); - - *input_line_pointer = c; - SKIP_WHITESPACE (); - - name = input_line_pointer; - c = get_symbol_end (); - - buf = (char *) xmalloc (strlen (name) + 10); - if (start) - sprintf (buf, ".startof.%s", name); - else - sprintf (buf, ".sizeof.%s", name); - symbolP = symbol_make (buf); - free (buf); - - expressionP->X_op = O_symbol; - expressionP->X_add_symbol = symbolP; - expressionP->X_add_number = 0; - - *input_line_pointer = c; - SKIP_WHITESPACE (); - + restore_line_pointer (c); break; } #endif @@ -1271,7 +1314,9 @@ operand (expressionS *expressionP, enum expr_mode mode) /* 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); @@ -1287,11 +1332,11 @@ operand (expressionS *expressionP, enum expr_mode mode) expressionP->X_add_symbol = symbolP; expressionP->X_add_number = 0; } - *input_line_pointer = c; + + restore_line_pointer (c); } else { - target_op: /* Let the target try to parse it. Success is indicated by changing the X_op field to something other than O_absent and pointing input_line_pointer past the expression. If it can't parse the @@ -1313,15 +1358,20 @@ operand (expressionS *expressionP, enum expr_mode mode) /* It is more 'efficient' to clean up the expressionS when they are created. Doing it here saves lines of code. */ clean_up_expression (expressionP); - SKIP_WHITESPACE (); /* -> 1st char after operand. */ + SKIP_ALL_WHITESPACE (); /* -> 1st char after operand. */ know (*input_line_pointer != ' '); /* The PA port needs this information. */ 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) { @@ -1439,7 +1489,7 @@ static const operatorT op_encoding[256] = { 7 * / % << >> 8 unary - unary ~ */ -static operator_rankT op_rank[] = { +static operator_rankT op_rank[O_max] = { 0, /* O_illegal */ 0, /* O_absent */ 0, /* O_constant */ @@ -1470,22 +1520,6 @@ static operator_rankT op_rank[] = { 3, /* O_logical_and */ 2, /* O_logical_or */ 1, /* O_index */ - 0, /* O_md1 */ - 0, /* O_md2 */ - 0, /* O_md3 */ - 0, /* O_md4 */ - 0, /* O_md5 */ - 0, /* O_md6 */ - 0, /* O_md7 */ - 0, /* O_md8 */ - 0, /* O_md9 */ - 0, /* O_md10 */ - 0, /* O_md11 */ - 0, /* O_md12 */ - 0, /* O_md13 */ - 0, /* O_md14 */ - 0, /* O_md15 */ - 0, /* O_md16 */ }; /* Unfortunately, in MRI mode for the m68k, multiplication and @@ -1514,6 +1548,13 @@ expr_set_precedence (void) } } +void +expr_set_rank (operatorT op, operator_rankT rank) +{ + gas_assert (op >= O_md1 && op < ARRAY_SIZE (op_rank)); + op_rank[op] = rank; +} + /* Initialize the expression parser. */ void @@ -1525,7 +1566,7 @@ expr_begin (void) { expressionS e; e.X_op = O_max; - assert (e.X_op == O_max); + gas_assert (e.X_op == O_max); } } @@ -1534,7 +1575,7 @@ expr_begin (void) Does not advance INPUT_LINE_POINTER. */ static inline operatorT -operator (int *num_chars) +operatorf (int *num_chars) { int c; operatorT ret; @@ -1545,18 +1586,54 @@ operator (int *num_chars) if (is_end_of_line[c]) return O_illegal; +#ifdef md_operator + if (is_name_beginner (c)) + { + char *name; + char ec = get_symbol_name (& name); + + ret = md_operator (name, 2, &ec); + switch (ret) + { + case O_absent: + *input_line_pointer = ec; + input_line_pointer = name; + break; + case O_uminus: + case O_bit_not: + case O_logical_not: + as_bad (_("invalid use of operator \"%s\""), name); + ret = O_illegal; + /* FALLTHROUGH */ + default: + *input_line_pointer = ec; + *num_chars = input_line_pointer - name; + input_line_pointer = name; + return ret; + } + } +#endif + switch (c) { default: - return op_encoding[c]; + ret = op_encoding[c]; +#ifdef md_operator + if (ret == O_illegal) + { + char *start = input_line_pointer; + + ret = md_operator (NULL, 2, NULL); + if (ret != O_illegal) + *num_chars = input_line_pointer - start; + input_line_pointer = start; + } +#endif + return ret; case '+': case '-': - /* Do not allow a++b and a--b to be a + (+b) and a - (-b) - Disabled, since the preprocessor removes whitespace. */ - if (1 || input_line_pointer[1] != c) - return op_encoding[c]; - return O_illegal; + return op_encoding[c]; case '<': switch (input_line_pointer[1]) @@ -1633,6 +1710,42 @@ operator (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. */ + +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 @@ -1647,24 +1760,29 @@ expr (int rankarg, /* Larger # is higher rank. */ operatorT op_right; int op_chars; - know (rank >= 0); + know (rankarg >= 0); /* 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); /* operand () gobbles spaces. */ know (*input_line_pointer != ' '); - op_left = operator (&op_chars); + op_left = operatorf (&op_chars); while (op_left != O_illegal && op_rank[(int) op_left] > rank) { segT rightseg; + offsetT frag_off; input_line_pointer += op_chars; /* -> after operator. */ + right.X_md = 0; rightseg = expr (op_rank[(int) op_left], &right, mode); if (right.X_op == O_absent) { @@ -1688,12 +1806,16 @@ expr (int rankarg, /* Larger # is higher rank. */ } } - op_right = operator (&op_chars); + op_right = operatorf (&op_chars); - know (op_right == O_illegal + know (op_right == O_illegal || op_left == O_index || op_rank[(int) op_right] <= op_rank[(int) op_left]); - know ((int) op_left >= (int) O_multiply - && (int) op_left <= (int) O_index); + know ((int) op_left >= (int) O_multiply); +#ifndef md_operator + know ((int) op_left <= (int) O_index); +#else + know ((int) op_left < (int) O_max); +#endif /* input_line_pointer->after right-hand quantity. */ /* left-hand quantity in resultP. */ @@ -1723,6 +1845,13 @@ expr (int rankarg, /* Larger # is higher rank. */ right.X_op_symbol = NULL; } + if (mode == expr_defer + && ((resultP->X_add_symbol != NULL + && S_IS_FORWARD_REF (resultP->X_add_symbol)) + || (right.X_add_symbol != NULL + && S_IS_FORWARD_REF (right.X_add_symbol)))) + goto general; + /* Optimize common cases. */ #ifdef md_optimize_expr if (md_optimize_expr (resultP, op_left, &right)) @@ -1732,38 +1861,53 @@ expr (int rankarg, /* Larger # is higher rank. */ } else #endif - if (op_left == O_add && right.X_op == O_constant) +#ifndef md_register_arithmetic +# define md_register_arithmetic 1 +#endif + if (op_left == O_add && right.X_op == O_constant + && (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 && right.X_op == O_symbol && resultP->X_op == O_symbol - && (symbol_get_frag (right.X_add_symbol) - == symbol_get_frag (resultP->X_add_symbol)) - && (SEG_NORMAL (rightseg) - || right.X_add_symbol == resultP->X_add_symbol)) + && retval == rightseg +#ifdef md_allow_local_subtract + && md_allow_local_subtract (resultP, & right, rightseg) +#endif + && ((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 += (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; } - else if (op_left == O_subtract && right.X_op == O_constant) + else if (op_left == O_subtract && right.X_op == O_constant + && (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) + else if (op_left == O_add && resultP->X_op == O_constant + && (md_register_arithmetic || right.X_op != O_register)) { /* Constant + X. */ 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) @@ -1775,9 +1919,17 @@ expr (int rankarg, /* Larger # is higher rank. */ as_warn (_("division by zero")); v = 1; } + if ((valueT) v >= sizeof(valueT) * CHAR_BIT + && (op_left == O_left_shift || op_left == O_right_shift)) + { + as_warn_value_out_of_range (_("shift count"), v, 0, + sizeof(valueT) * CHAR_BIT - 1, + NULL, 0); + resultP->X_add_number = v = 0; + } switch (op_left) { - default: abort (); + default: goto general; 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; @@ -1792,8 +1944,12 @@ expr (int rankarg, /* Larger # is higher rank. */ case O_bit_or_not: resultP->X_add_number |= ~v; break; case O_bit_exclusive_or: resultP->X_add_number ^= v; break; case O_bit_and: resultP->X_add_number &= v; break; - case O_add: resultP->X_add_number += v; break; - case O_subtract: resultP->X_add_number -= v; break; + /* Constant + constant (O_add) is handled by the + previous if statement for constant + X, so is omitted + here. */ + 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; @@ -1837,11 +1993,15 @@ 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; - 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; @@ -1850,26 +2010,39 @@ expr (int rankarg, /* Larger # is higher rank. */ } else { + general: /* The general case. */ resultP->X_add_symbol = make_expr_symbol (resultP); resultP->X_op_symbol = make_expr_symbol (&right); 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")); } @@ -1895,11 +2068,13 @@ resolve_expression (expressionS *expressionP) /* Help out with CSE. */ valueT final_val = expressionP->X_add_number; symbolS *add_symbol = expressionP->X_add_symbol; + symbolS *orig_add_symbol = add_symbol; symbolS *op_symbol = expressionP->X_op_symbol; operatorT op = expressionP->X_op; valueT left, right; segT seg_left, seg_right; fragS *frag_left, *frag_right; + offsetT frag_off; switch (op) { @@ -1913,7 +2088,7 @@ resolve_expression (expressionS *expressionP) case O_symbol: case O_symbol_rva: - if (!snapshot_symbol (add_symbol, &left, &seg_left, &frag_left)) + if (!snapshot_symbol (&add_symbol, &left, &seg_left, &frag_left)) return 0; break; @@ -1921,7 +2096,7 @@ resolve_expression (expressionS *expressionP) case O_uminus: case O_bit_not: case O_logical_not: - if (!snapshot_symbol (add_symbol, &left, &seg_left, &frag_left)) + if (!snapshot_symbol (&add_symbol, &left, &seg_left, &frag_left)) return 0; if (seg_left != absolute_section) @@ -1955,8 +2130,8 @@ resolve_expression (expressionS *expressionP) case O_gt: case O_logical_and: case O_logical_or: - if (!snapshot_symbol (add_symbol, &left, &seg_left, &frag_left) - || !snapshot_symbol (op_symbol, &right, &seg_right, &frag_right)) + if (!snapshot_symbol (&add_symbol, &left, &seg_left, &frag_left) + || !snapshot_symbol (&op_symbol, &right, &seg_right, &frag_right)) return 0; /* Simplify addition or subtraction of a constant by folding the @@ -1974,7 +2149,8 @@ resolve_expression (expressionS *expressionP) final_val += left; left = right; seg_left = seg_right; - expressionP->X_add_symbol = expressionP->X_op_symbol; + add_symbol = op_symbol; + orig_add_symbol = expressionP->X_op_symbol; op = O_symbol; break; } @@ -1991,21 +2167,91 @@ resolve_expression (expressionS *expressionP) /* Equality and non-equality tests are permitted on anything. Subtraction, and other comparison operators are permitted if - both operands are in the same section. Otherwise, both - operands must be absolute. We already handled the case of - addition or subtraction of a constant above. */ + both operands are in the same section. + Shifts by constant zero are permitted on anything. + Multiplies, bit-ors, and bit-ands with constant zero are + permitted on anything. + Multiplies and divides by constant one are permitted on + anything. + Binary operations with both operands being the same register + or undefined symbol are permitted if the result doesn't depend + on the input value. + Otherwise, both operands must be absolute. We already handled + the case of addition or subtraction of a constant above. */ + frag_off = 0; if (!(seg_left == absolute_section && seg_right == absolute_section) && !(op == O_eq || op == O_ne) && !((op == O_subtract || op == O_lt || op == O_le || op == O_ge || op == O_gt) && seg_left == seg_right - && (finalize_syms || frag_left == frag_right) - && ((seg_left != undefined_section - && seg_left != reg_section) - || add_symbol == op_symbol))) - return 0; + && (finalize_syms + || frag_offset_fixed_p (frag_left, frag_right, &frag_off) + || (op == O_gt + && frag_gtoffset_p (left, frag_left, + right, frag_right, &frag_off))) + && (seg_left != reg_section || left == right) + && (seg_left != undefined_section || add_symbol == op_symbol))) + { + if ((seg_left == absolute_section && left == 0) + || (seg_right == absolute_section && right == 0)) + { + if (op == O_bit_exclusive_or || op == O_bit_inclusive_or) + { + if (!(seg_right == absolute_section && right == 0)) + { + seg_left = seg_right; + left = right; + add_symbol = op_symbol; + orig_add_symbol = expressionP->X_op_symbol; + } + op = O_symbol; + break; + } + else if (op == O_left_shift || op == O_right_shift) + { + if (!(seg_left == absolute_section && left == 0)) + { + op = O_symbol; + break; + } + } + else if (op != O_multiply + && op != O_bit_or_not && op != O_bit_and) + return 0; + } + else if (op == O_multiply + && seg_left == absolute_section && left == 1) + { + seg_left = seg_right; + left = right; + add_symbol = op_symbol; + orig_add_symbol = expressionP->X_op_symbol; + op = O_symbol; + break; + } + else if ((op == O_multiply || op == O_divide) + && seg_right == absolute_section && right == 1) + { + op = O_symbol; + break; + } + else if (!(left == right + && ((seg_left == reg_section && seg_right == reg_section) + || (seg_left == undefined_section + && seg_right == undefined_section + && add_symbol == op_symbol)))) + return 0; + else if (op == O_bit_and || op == O_bit_inclusive_or) + { + op = O_symbol; + break; + } + else if (op != O_bit_exclusive_or && op != O_bit_or_not) + return 0; + } + right += frag_off / OCTETS_PER_BYTE; switch (op) { case O_add: left += right; break; @@ -2032,8 +2278,7 @@ resolve_expression (expressionS *expressionP) left = (left == right && seg_left == seg_right && (finalize_syms || frag_left == frag_right) - && ((seg_left != undefined_section - && seg_left != reg_section) + && (seg_left != undefined_section || add_symbol == op_symbol) ? ~ (valueT) 0 : 0); if (op == O_ne) @@ -2066,6 +2311,9 @@ resolve_expression (expressionS *expressionP) op = O_constant; else if (seg_left == reg_section && final_val == 0) op = O_register; + else if (!symbol_same_p (add_symbol, orig_add_symbol)) + final_val += left; + expressionP->X_add_symbol = add_symbol; } expressionP->X_op = op; @@ -2080,31 +2328,63 @@ resolve_expression (expressionS *expressionP) expr.c is just a branch office read.c anyway, and putting it here lessens the crowd at read.c. - Assume input_line_pointer is at start of symbol name. + Assume input_line_pointer is at start of symbol name, or the + start of a double quote enclosed symbol name. Advance input_line_pointer past symbol name. - Turn that character into a '\0', returning its former value. + Turn that character into a '\0', returning its former value, + which may be the closing double quote. This allows a string compare (RMS wants symbol names to be strings) - of the symbol name. + of the symbol name. There will always be a char following symbol name, because all good lines end in end-of-line. */ char -get_symbol_end (void) +get_symbol_name (char ** ilp_return) { char c; - /* We accept \001 in a name in case this is being called with a + * ilp_return = input_line_pointer; + /* We accept FAKE_LABEL_CHAR in a name in case this is being called with a constructed string. */ - if (is_name_beginner (c = *input_line_pointer++) || c == '\001') + if (is_name_beginner (c = *input_line_pointer++) + || (input_from_string && c == FAKE_LABEL_CHAR)) { while (is_part_of_name (c = *input_line_pointer++) - || c == '\001') + || (input_from_string && c == FAKE_LABEL_CHAR)) ; if (is_name_ender (c)) c = *input_line_pointer++; } + else if (c == '"') + { + bfd_boolean backslash_seen; + + * ilp_return = input_line_pointer; + do + { + backslash_seen = c == '\\'; + c = * input_line_pointer ++; + } + while (c != 0 && (c != '"' || backslash_seen)); + + if (c == 0) + as_warn (_("missing closing '\"'")); + } *--input_line_pointer = 0; - return (c); + return c; +} + +/* Replace the NUL character pointed to by input_line_pointer + with C. If C is \" then advance past it. Return the character + now pointed to by input_line_pointer. */ + +char +restore_line_pointer (char c) +{ + * input_line_pointer = c; + if (c == '"') + c = * ++ input_line_pointer; + return c; } unsigned int