gas 0f handling
[deliverable/binutils-gdb.git] / gas / expr.c
index 53952b56fa100020ad979bc17f21500d0f7cb7eb..f8acd4129b46f4726ad0ce43f6fabd9cfb88ca1a 100644 (file)
@@ -1,7 +1,5 @@
 /* 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.
+   Copyright (C) 1987-2015 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -29,7 +27,6 @@
 
 #include "as.h"
 #include "safe-ctype.h"
-#include "obstack.h"
 
 #ifdef HAVE_LIMITS_H
 #include <limits.h>
@@ -90,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;
     }
@@ -126,7 +124,7 @@ make_expr_symbol (expressionS *expressionP)
 int
 expr_symbol_where (symbolS *sym, 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)
     {
@@ -161,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);
 }
 
@@ -172,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));
 }
 \f
 /* Build any floating-point literal here.
@@ -286,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;
@@ -705,7 +710,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;
     }
 }
@@ -732,6 +737,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.  */
 
@@ -832,32 +838,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':
@@ -875,48 +877,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':
@@ -959,10 +948,7 @@ operand (expressionS *expressionP, enum expr_mode mode)
 #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 != ']'))
@@ -1024,11 +1010,14 @@ operand (expressionS *expressionP, enum expr_mode mode)
            /* 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;
@@ -1081,6 +1070,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
@@ -1325,7 +1315,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);
@@ -1373,8 +1365,13 @@ operand (expressionS *expressionP, enum expr_mode mode)
   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)
     {
@@ -1713,6 +1710,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.  */
+
+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
@@ -1731,7 +1764,10 @@ expr (int rankarg,               /* Larger # is higher rank.  */
 
   /* 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);
 
@@ -1742,7 +1778,7 @@ expr (int rankarg,                /* Larger # is higher rank.  */
   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.  */
 
@@ -1825,7 +1861,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
@@ -1835,16 +1871,19 @@ expr (int rankarg,              /* Larger # is higher rank.  */
 #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;
        }
@@ -1852,7 +1891,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))
@@ -1861,7 +1900,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)
@@ -1901,7 +1940,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;
@@ -1945,11 +1986,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;
@@ -1965,20 +2010,32 @@ 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)
        {
-         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"));
        }
 
@@ -2010,7 +2067,7 @@ resolve_expression (expressionS *expressionP)
   valueT left, right;
   segT seg_left, seg_right;
   fragS *frag_left, *frag_right;
-  bfd_vma frag_off;
+  offsetT frag_off;
 
   switch (op)
     {
This page took 0.029054 seconds and 4 git commands to generate.