Support R_SPARC_WDISP10 and R_SPARC_H34.
[external/binutils.git] / gas / expr.c
index 4517bc6..0563b5b 100644 (file)
@@ -1,6 +1,6 @@
 /* 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
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2011
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
@@ -45,7 +45,6 @@ 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 operatorf (int *);
@@ -173,7 +172,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.
@@ -695,7 +694,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)
@@ -706,7 +705,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;
     }
 }
@@ -960,10 +959,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 != ']'))
@@ -1057,6 +1053,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)
                    {
@@ -1067,14 +1072,12 @@ 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;
              }
          }
        else if (expressionP->X_op != O_illegal
@@ -1319,7 +1322,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);
@@ -1367,8 +1372,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)
     {
@@ -1829,7 +1839,9 @@ 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),
@@ -1943,7 +1955,10 @@ expr (int rankarg,               /* Larger # is higher rank.  */
          else if (op_left == O_subtract)
            {
              resultP->X_add_number -= right.X_add_number;
-             if (retval == rightseg && SEG_NORMAL (retval))
+             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;
@@ -1963,16 +1978,27 @@ expr (int rankarg,              /* Larger # is higher rank.  */
 
       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"));
        }