* expr.c (expr): Move code setting "retval" to the end of the loop,
authorAlan Modra <amodra@gmail.com>
Sun, 9 Sep 2001 14:01:17 +0000 (14:01 +0000)
committerAlan Modra <amodra@gmail.com>
Sun, 9 Sep 2001 14:01:17 +0000 (14:01 +0000)
and rearrange for efficiency.  For "PIC code" subtraction, use
"rightseg" rather than recalculating.  For "symbol OP symbol"
subtract, set "retval" to absolute_section if symbols in same
section.
* symbols.c (resolve_symbol_value): Resolve "sym +/- expr" to an
O_symbol.  Simplify a +/- b code.  Allow equality and non-equality
comparisons on symbols from any section.  Allow other comparison
operators as for subtraction.
(symbol_equated_reloc_p): New predicate function.
* symbols.h (symbol_equated_reloc_p): Declare.
* write.c (adjust_reloc_syms): Use symbol_equated_reloc_p.
(write_relocs): Likewise.
(write_object_file): Likewise.
(relax_segment <rs_machine_dependent>): Ensure segment for
expression syms is set correctly.
* config/tc-mips.c (md_estimate_size_before_relax): Likewise.
* config/tc-i386.c (md_assemble <Output jumps>): Don't lose part
of a complex expression when setting up frag_var.

gas/ChangeLog
gas/config/tc-i386.c
gas/config/tc-mips.c
gas/expr.c
gas/symbols.c
gas/symbols.h
gas/write.c

index 0c27bef..8f25096 100644 (file)
@@ -1,3 +1,25 @@
+2001-09-09  Alan Modra  <amodra@bigpond.net.au>
+
+       * expr.c (expr): Move code setting "retval" to the end of the loop,
+       and rearrange for efficiency.  For "PIC code" subtraction, use
+       "rightseg" rather than recalculating.  For "symbol OP symbol"
+       subtract, set "retval" to absolute_section if symbols in same
+       section.
+       * symbols.c (resolve_symbol_value): Resolve "sym +/- expr" to an
+       O_symbol.  Simplify a +/- b code.  Allow equality and non-equality
+       comparisons on symbols from any section.  Allow other comparison
+       operators as for subtraction.
+       (symbol_equated_reloc_p): New predicate function.
+       * symbols.h (symbol_equated_reloc_p): Declare.
+       * write.c (adjust_reloc_syms): Use symbol_equated_reloc_p.
+       (write_relocs): Likewise.
+       (write_object_file): Likewise.
+       (relax_segment <rs_machine_dependent>): Ensure segment for
+       expression syms is set correctly.
+       * config/tc-mips.c (md_estimate_size_before_relax): Likewise.
+       * config/tc-i386.c (md_assemble <Output jumps>): Don't lose part
+       of a complex expression when setting up frag_var.
+
 2001-09-07  Richard Henderson  <rth@redhat.com>
 
        * config/tc-alpha.c (alpha_reloc_op_tag): Replace need_seq with
index 275b3e6..739ed58 100644 (file)
@@ -2741,6 +2741,9 @@ md_assemble (line)
       {
        int code16;
        int prefix;
+       relax_substateT subtype;
+       symbolS *sym;
+       offsetT off;
 
        code16 = 0;
        if (flag_code == CODE_16BIT)
@@ -2785,19 +2788,29 @@ md_assemble (line)
        if (i.prefix[REX_PREFIX])
          *p++ = i.prefix[REX_PREFIX];
        *p = i.tm.base_opcode;
-       /* 1 possible extra opcode + displacement go in var part.
+
+       if ((unsigned char) *p == JUMP_PC_RELATIVE)
+         subtype = ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL);
+       else if ((cpu_arch_flags & Cpu386) != 0)
+         subtype = ENCODE_RELAX_STATE (COND_JUMP, SMALL);
+       else
+         subtype = ENCODE_RELAX_STATE (COND_JUMP86, SMALL);
+       subtype |= code16;
+
+       sym = i.op[0].disps->X_add_symbol;
+       off = i.op[0].disps->X_add_number;
+
+       if (i.op[0].disps->X_op != O_constant
+           && i.op[0].disps->X_op != O_symbol)
+         {
+           /* Handle complex expressions.  */
+           sym = make_expr_symbol (i.op[0].disps);
+           off = 0;
+         }
+
+       /* 1 possible extra opcode + 4 byte displacement go in var part.
           Pass reloc in fr_var.  */
-       frag_var (rs_machine_dependent,
-                 1 + 4,
-                 i.reloc[0],
-                 ((unsigned char) *p == JUMP_PC_RELATIVE
-                  ? ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL) | code16
-                  : ((cpu_arch_flags & Cpu386) != 0
-                     ? ENCODE_RELAX_STATE (COND_JUMP, SMALL) | code16
-                     : ENCODE_RELAX_STATE (COND_JUMP86, SMALL) | code16)),
-                 i.op[0].disps->X_add_symbol,
-                 i.op[0].disps->X_add_number,
-                 p);
+       frag_var (rs_machine_dependent, 5, i.reloc[0], subtype, sym, off, p);
       }
     else if (i.tm.opcode_modifier & (JumpByte | JumpDword))
       {
index 0855af0..f9b5811 100644 (file)
@@ -11143,8 +11143,7 @@ md_estimate_size_before_relax (fragp, segtype)
       sym = fragp->fr_symbol;
 
       /* Handle the case of a symbol equated to another symbol.  */
-      while (symbol_equated_p (sym)
-            && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym)))
+      while (symbol_equated_reloc_p (sym))
        {
          symbolS *n;
 
index 4258868..4f7f225 100644 (file)
@@ -1699,21 +1699,6 @@ expr (rankarg, resultP)
            }
        }
 
-      if (retval == undefined_section)
-       {
-         if (SEG_NORMAL (rightseg))
-           retval = rightseg;
-       }
-      else if (! SEG_NORMAL (retval))
-       retval = rightseg;
-      else if (SEG_NORMAL (rightseg)
-              && retval != rightseg
-#ifdef DIFF_EXPR_OK
-              && op_left != O_subtract
-#endif
-              )
-       as_bad (_("operation combines symbols in different segments"));
-
       op_right = operator (&op_chars);
 
       know (op_right == O_illegal
@@ -1769,8 +1754,7 @@ expr (rankarg, resultP)
               && resultP->X_op == O_symbol
               && (symbol_get_frag (right.X_add_symbol)
                   == symbol_get_frag (resultP->X_add_symbol))
-              && SEG_NORMAL (S_GET_SEGMENT (right.X_add_symbol)))
-
+              && SEG_NORMAL (rightseg))
        {
          resultP->X_add_number -= right.X_add_number;
          resultP->X_add_number += (S_GET_VALUE (resultP->X_add_symbol)
@@ -1865,7 +1849,14 @@ expr (rankarg, resultP)
          if (op_left == O_add)
            resultP->X_add_number += right.X_add_number;
          else if (op_left == O_subtract)
-           resultP->X_add_number -= right.X_add_number;
+           {
+             resultP->X_add_number -= right.X_add_number;
+             if (retval == rightseg && SEG_NORMAL (retval))
+               {
+                 retval = absolute_section;
+                 rightseg = absolute_section;
+               }
+           }
        }
       else
        {
@@ -1877,6 +1868,21 @@ expr (rankarg, resultP)
          resultP->X_unsigned = 1;
        }
 
+      if (retval != rightseg)
+       {
+         if (! SEG_NORMAL (retval))
+           {
+             if (retval != undefined_section || SEG_NORMAL (rightseg))
+               retval = rightseg;
+           }
+         else if (SEG_NORMAL (rightseg)
+#ifdef DIFF_EXPR_OK
+                  && op_left != O_subtract
+#endif
+                  )
+           as_bad (_("operation combines symbols in different segments"));
+       }
+
       op_left = op_right;
     }                          /* While next operator is >= this rank.  */
 
index 1f4e988..201b03e 100644 (file)
@@ -914,13 +914,16 @@ resolve_symbol_value (symp)
        case O_symbol:
        case O_symbol_rva:
          left = resolve_symbol_value (add_symbol);
-       do_symbol:
+         seg_left = S_GET_SEGMENT (add_symbol);
+         if (finalize_syms)
+           symp->sy_value.X_op_symbol = NULL;
 
+       do_symbol:
          if (symp->sy_mri_common)
            {
              /* This is a symbol inside an MRI common section.  The
-                 relocation routines are going to handle it specially.
-                 Don't change the value.  */
+                relocation routines are going to handle it specially.
+                Don't change the value.  */
              resolved = symbol_resolved_p (add_symbol);
              break;
            }
@@ -933,31 +936,51 @@ resolve_symbol_value (symp)
              copy_symbol_attributes (symp, add_symbol);
            }
 
-         /* If we have equated this symbol to an undefined symbol, we
-             keep X_op set to O_symbol, and we don't change
-             X_add_number.  This permits the routine which writes out
-             relocation to detect this case, and convert the
-             relocation to be against the symbol to which this symbol
-             is equated.  */
+         /* If we have equated this symbol to an undefined or common
+            symbol, keep X_op set to O_symbol, and don't change
+            X_add_number.  This permits the routine which writes out
+            relocation to detect this case, and convert the
+            relocation to be against the symbol to which this symbol
+            is equated.  */
          if (! S_IS_DEFINED (add_symbol) || S_IS_COMMON (add_symbol))
            {
              if (finalize_syms)
                {
-                 final_seg = S_GET_SEGMENT (add_symbol);
                  symp->sy_value.X_op = O_symbol;
                  symp->sy_value.X_add_symbol = add_symbol;
                  symp->sy_value.X_add_number = final_val;
+                 /* Use X_op_symbol as a flag.  */
+                 symp->sy_value.X_op_symbol = add_symbol;
+                 final_seg = seg_left;
                }
              final_val = 0;
              resolved = symbol_resolved_p (add_symbol);
              symp->sy_resolving = 0;
              goto exit_dont_set_value;
            }
+         else if (finalize_syms && final_seg == expr_section
+                  && seg_left != expr_section)
+           {
+             /* If the symbol is an expression symbol, do similarly
+                as for undefined and common syms above.  Handles
+                "sym +/- expr" where "expr" cannot be evaluated
+                immediately, and we want relocations to be against
+                "sym", eg. because it is weak.  */
+             symp->sy_value.X_op = O_symbol;
+             symp->sy_value.X_add_symbol = add_symbol;
+             symp->sy_value.X_add_number = final_val;
+             symp->sy_value.X_op_symbol = add_symbol;
+             final_seg = seg_left;
+             final_val += symp->sy_frag->fr_address + left;
+             resolved = symbol_resolved_p (add_symbol);
+             symp->sy_resolving = 0;
+             goto exit_dont_set_value;
+           }
          else
            {
              final_val += symp->sy_frag->fr_address + left;
              if (final_seg == expr_section || final_seg == undefined_section)
-               final_seg = S_GET_SEGMENT (add_symbol);
+               final_seg = seg_left;
            }
 
          resolved = symbol_resolved_p (add_symbol);
@@ -1008,42 +1031,49 @@ resolve_symbol_value (symp)
 
          /* Simplify addition or subtraction of a constant by folding the
             constant into X_add_number.  */
-         if (op == O_add || op == O_subtract)
+         if (op == O_add)
            {
              if (seg_right == absolute_section)
                {
-                 if (op == O_add)
-                   final_val += right;
-                 else
-                   final_val -= right;
-                 op = O_symbol;
-                 op_symbol = NULL;
+                 final_val += right;
                  goto do_symbol;
                }
-             else if (seg_left == absolute_section && op == O_add)
+             else if (seg_left == absolute_section)
                {
-                 op = O_symbol;
                  final_val += left;
                  add_symbol = op_symbol;
                  left = right;
-                 op_symbol = NULL;
+                 seg_left = seg_right;
+                 goto do_symbol;
+               }
+           }
+         else if (op == O_subtract)
+           {
+             if (seg_right == absolute_section)
+               {
+                 final_val -= right;
                  goto do_symbol;
                }
            }
 
-         /* Subtraction is 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.  This will probably need to be changed
-            for an object file format which supports arbitrary
-            expressions, such as IEEE-695.  */
-         /* Don't emit messages unless we're finalizing the symbol value,
+         /* 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.  This will
+            probably need to be changed for an object file format which
+            supports arbitrary expressions, such as IEEE-695.
+
+            Don't emit messages unless we're finalizing the symbol value,
             otherwise we may get the same message multiple times.  */
-         if ((seg_left != absolute_section
-              || seg_right != absolute_section)
-             && (op != O_subtract
+         if (op != O_eq && op != O_ne
+             && (seg_left != absolute_section
+                 || seg_right != absolute_section)
+             && ((op != O_subtract
+                  && op != O_lt && op != O_le && op != O_ge && op != O_gt)
                  || seg_left != seg_right
-                 || seg_left == undefined_section)
+                 || (seg_left == undefined_section
+                     && add_symbol != op_symbol))
              && finalize_syms)
            {
              char *file;
@@ -1085,7 +1115,7 @@ resolve_symbol_value (symp)
          if ((op == O_divide || op == O_modulus) && right == 0)
            {
              /* If seg_right is not absolute_section, then we've
-                 already issued a warning about using a bad symbol.  */
+                already issued a warning about using a bad symbol.  */
              if (seg_right == absolute_section && finalize_syms)
                {
                  char *file;
@@ -1114,8 +1144,15 @@ resolve_symbol_value (symp)
            case O_bit_and:             left &= right; break;
            case O_add:                 left += right; break;
            case O_subtract:            left -= right; break;
-           case O_eq:  left = left == right ? ~ (offsetT) 0 : 0; break;
-           case O_ne:  left = left != right ? ~ (offsetT) 0 : 0; break;
+           case O_eq:
+           case O_ne:
+             left = (left == right && seg_left == seg_right
+                     && (seg_left != undefined_section
+                         || add_symbol == op_symbol)
+                     ? ~ (offsetT) 0 : 0);
+             if (symp->sy_value.X_op == O_ne)
+               left = ~left;
+             break;
            case O_lt:  left = left <  right ? ~ (offsetT) 0 : 0; break;
            case O_le:  left = left <= right ? ~ (offsetT) 0 : 0; break;
            case O_ge:  left = left >= right ? ~ (offsetT) 0 : 0; break;
@@ -2146,6 +2183,24 @@ symbol_equated_p (s)
   return s->sy_value.X_op == O_symbol;
 }
 
+/* Return whether a symbol is equated to another symbol, and should be
+   treated specially when writing out relocs.  */
+
+int
+symbol_equated_reloc_p (s)
+     symbolS *s;
+{
+  if (LOCAL_SYMBOL_CHECK (s))
+    return 0;
+  /* X_op_symbol, normally not used for O_symbol, is set by
+     resolve_symbol_value to flag expression syms that have been
+     equated.  */
+  return (s->sy_value.X_op == O_symbol
+         && ((s->sy_resolved && s->sy_value.X_op_symbol != NULL)
+             || ! S_IS_DEFINED (s)
+             || S_IS_COMMON (s)));
+}
+
 /* Return whether a symbol has a constant value.  */
 
 int
index e798905..a80ca8c 100644 (file)
@@ -185,6 +185,7 @@ extern void symbol_mark_resolved PARAMS ((symbolS *));
 extern int symbol_resolved_p PARAMS ((symbolS *));
 extern int symbol_section_p PARAMS ((symbolS *));
 extern int symbol_equated_p PARAMS ((symbolS *));
+extern int symbol_equated_reloc_p PARAMS ((symbolS *));
 extern int symbol_constant_p PARAMS ((symbolS *));
 
 #ifdef BFD_ASSEMBLER
index c096eb5..14fbf04 100644 (file)
@@ -769,8 +769,7 @@ adjust_reloc_syms (abfd, sec, xxx)
 
        /* If this symbol is equated to an undefined symbol, convert
            the fixup to being against that symbol.  */
-       if (sym != NULL && symbol_equated_p (sym)
-           && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym)))
+       if (sym != NULL && symbol_equated_reloc_p (sym))
          {
            fixp->fx_offset += symbol_get_value_expression (sym)->X_add_number;
            sym = symbol_get_value_expression (sym)->X_add_symbol;
@@ -983,11 +982,10 @@ write_relocs (abfd, sec, xxx)
        }
 
       /* If this is an undefined symbol which was equated to another
-         symbol, then use generate the reloc against the latter symbol
+         symbol, then generate the reloc against the latter symbol
          rather than the former.  */
       sym = fixp->fx_addsy;
-      while (symbol_equated_p (sym)
-            && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym)))
+      while (symbol_equated_reloc_p (sym))
        {
          symbolS *n;
 
@@ -1059,8 +1057,7 @@ write_relocs (abfd, sec, xxx)
          symbol, then generate the reloc against the latter symbol
          rather than the former.  */
       sym = fixp->fx_addsy;
-      while (symbol_equated_p (sym)
-            && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym)))
+      while (symbol_equated_reloc_p (sym))
        sym = symbol_get_value_expression (sym)->X_add_symbol;
       fixp->fx_addsy = sym;
 
@@ -1960,8 +1957,7 @@ write_object_file ()
 
          /* Skip symbols which were equated to undefined or common
              symbols.  */
-         if (symbol_equated_p (symp)
-             && (! S_IS_DEFINED (symp) || S_IS_COMMON (symp)))
+         if (symbol_equated_reloc_p (symp))
            {
              symbol_remove (symp, &symbol_rootP, &symbol_lastP);
              continue;
@@ -2264,6 +2260,12 @@ relax_segment (segment_frag_root, segment)
          break;
 
        case rs_machine_dependent:
+         /* If fr_symbol is an expression, this call to
+            resolve_symbol_value sets up the correct segment, which will
+            likely be needed in md_estimate_size_before_relax.  */
+         if (fragP->fr_symbol)
+           resolve_symbol_value (fragP->fr_symbol);
+
          address += md_estimate_size_before_relax (fragP, segment);
          break;