This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Fix PR997, gas listings breakage
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: binutils at sourceware dot org
- Date: Tue, 4 Apr 2006 17:33:13 +0930
- Subject: Fix PR997, gas listings breakage
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