PR 997
authorAlan Modra <amodra@gmail.com>
Tue, 4 Apr 2006 08:04:57 +0000 (08:04 +0000)
committerAlan Modra <amodra@gmail.com>
Tue, 4 Apr 2006 08:04:57 +0000 (08:04 +0000)
* frags.c (frag_offset_fixed_p): New function.
* frags.h (frag_offset_fixed_p): Declare.
* expr.c (expr): Use frag_offset_fixed_p when simplifying subtraction.
(resolve_expression): Likewise.

gas/ChangeLog
gas/expr.c
gas/frags.c
gas/frags.h

index 9d08f29080cb5cb3c4bcd3687d7c4659be0f656e..fadd3e0fe1c312bf2aa76215c85a5fde59b1f2bc 100644 (file)
@@ -1,3 +1,11 @@
+2006-04-04  Alan Modra  <amodra@bigpond.net.au>
+
+       PR 997
+       * frags.c (frag_offset_fixed_p): New function.
+       * frags.h (frag_offset_fixed_p): Declare.
+       * expr.c (expr): Use frag_offset_fixed_p when simplifying subtraction.
+       (resolve_expression): Likewise.
+
 2006-04-03  Sterling Augustine  <sterling@tensilica.com>
 
        * config/tc-xtensa.c (init_op_placement_info_table): Check for formats
index 3ae1bcc58191a827032b8a4a712d0b62de22ca0f..69f0aaccdb64b42da016bf5ad54aa08b35c3b22f 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
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
@@ -1662,6 +1662,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;
 
       input_line_pointer += op_chars;  /* -> after operator.  */
 
@@ -1741,12 +1742,15 @@ expr (int rankarg,              /* Larger # is higher rank.  */
       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))
+              && retval == rightseg
               && (SEG_NORMAL (rightseg)
-                  || right.X_add_symbol == resultP->X_add_symbol))
+                  || 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));
          resultP->X_op = O_constant;
@@ -1900,6 +1904,7 @@ resolve_expression (expressionS *expressionP)
   valueT left, right;
   segT seg_left, seg_right;
   fragS *frag_left, *frag_right;
+  bfd_vma frag_off;
 
   switch (op)
     {
@@ -2002,13 +2007,15 @@ resolve_expression (expressionS *expressionP)
         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)
+              && (finalize_syms
+                  || frag_offset_fixed_p (frag_left, frag_right, &frag_off))
               && (seg_left != reg_section || left == right)
               && (seg_left != undefined_section || add_symbol == op_symbol)))
        {
@@ -2068,6 +2075,7 @@ resolve_expression (expressionS *expressionP)
            return 0;
        }
 
+      right += frag_off / OCTETS_PER_BYTE;
       switch (op)
        {
        case O_add:                     left += right; break;
index 6dae8bc9c2290ea395d22330677b5c8bac71369d..cfd183fb3d41ec63d70add20111b0a97161e7430 100644 (file)
@@ -1,6 +1,6 @@
 /* frags.c - manage frags -
    Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2003, 2004
+   1999, 2000, 2001, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
@@ -383,3 +383,55 @@ frag_append_1_char (int datum)
     }
   obstack_1grow (&frchain_now->frch_obstack, datum);
 }
+
+/* Return TRUE if FRAG1 and FRAG2 have a fixed relationship between
+   their start addresses.  Set OFFSET to the difference in address
+   not already accounted for in the frag FR_ADDRESS.  */
+
+bfd_boolean
+frag_offset_fixed_p (fragS *frag1, fragS *frag2, bfd_vma *offset)
+{
+  fragS *frag;
+  bfd_vma off;
+
+  /* Start with offset initialised to difference between the two frags.
+     Prior to assigning frag addresses this will be zero.  */
+  off = frag1->fr_address - frag2->fr_address;
+  if (frag1 == frag2)
+    {
+      *offset = off;
+      return TRUE;
+    }
+
+  /* Maybe frag2 is after frag1.  */
+  frag = frag1;
+  while (frag->fr_type == rs_fill)
+    {
+      off += frag->fr_fix + frag->fr_offset * frag->fr_var;
+      frag = frag->fr_next;
+      if (frag == NULL)
+       break;
+      if (frag == frag2)
+       {
+         *offset = off;
+         return TRUE;
+       }
+    }
+
+  /* Maybe frag1 is after frag2.  */
+  frag = frag2;
+  while (frag->fr_type == rs_fill)
+    {
+      off -= frag->fr_fix + frag->fr_offset * frag->fr_var;
+      frag = frag->fr_next;
+      if (frag == NULL)
+       break;
+      if (frag == frag1)
+       {
+         *offset = off;
+         return TRUE;
+       }
+    }
+
+  return FALSE;
+}
index e6c617091916535e8d2b7341d4f7cb944141914f..880446763a4ec8e7e06b1a57a3e2c38332edfd5a 100644 (file)
@@ -1,6 +1,6 @@
 /* frags.h - Header file for the frag concept.
    Copyright 1987, 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -148,4 +148,6 @@ char *frag_var (relax_stateT type,
                offsetT offset,
                char *opcode);
 
+bfd_boolean frag_offset_fixed_p (fragS *, fragS *, bfd_vma *);
+
 #endif /* FRAGS_H */