public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* Fix PR997, gas listings breakage
@ 2006-04-04  8:03 Alan Modra
  0 siblings, 0 replies; only message in thread
From: Alan Modra @ 2006-04-04  8:03 UTC (permalink / raw)
  To: binutils

Turning on gas listings can break perfectly good assembly.  See the
PR for an example and analysis.   This patch mends some of the damage.

Except when listings are turned on, the frag list traversal will
terminate fairly quickly so there shouldn't be a noticeable slowdown
due to the extra processing here.

	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.

Index: gas/frags.c
===================================================================
RCS file: /cvs/src/src/gas/frags.c,v
retrieving revision 1.18
diff -u -p -r1.18 frags.c
--- gas/frags.c	10 May 2005 15:10:04 -0000	1.18
+++ gas/frags.c	4 Apr 2006 07:18:32 -0000
@@ -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: gas/frags.h
===================================================================
RCS file: /cvs/src/src/gas/frags.h,v
retrieving revision 1.20
diff -u -p -r1.20 frags.h
--- gas/frags.h	8 Jul 2005 05:57:20 -0000	1.20
+++ gas/frags.h	4 Apr 2006 07:18:32 -0000
@@ -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 */
Index: gas/expr.c
===================================================================
RCS file: /cvs/src/src/gas/expr.c,v
retrieving revision 1.64
diff -u -p -r1.64 expr.c
--- gas/expr.c	22 Dec 2005 17:05:40 -0000	1.64
+++ gas/expr.c	4 Apr 2006 08:02:27 -0000
@@ -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 highe
   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 highe
       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 *express
   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 *express
 	 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 *express
 	    return 0;
 	}
 
+      right += frag_off / OCTETS_PER_BYTE;
       switch (op)
 	{
 	case O_add:			left += right; break;

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2006-04-04  8:03 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-04-04  8:03 Fix PR997, gas listings breakage Alan Modra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).