summaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2006-04-04 08:04:57 +0000
committerAlan Modra <amodra@gmail.com>2006-04-04 08:04:57 +0000
commit99630778988bcd5195fc056fbd013d32d1362d5a (patch)
tree2dcd9e309b7a988ed9fbe72ea53005e3a2d38b2d /gas
parentbb3af66b415e4c7b92894d0aca52119b05d728ec (diff)
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.
Diffstat (limited to 'gas')
-rw-r--r--gas/ChangeLog8
-rw-r--r--gas/expr.c18
-rw-r--r--gas/frags.c54
-rw-r--r--gas/frags.h4
4 files changed, 77 insertions, 7 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 9d08f29080..fadd3e0fe1 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -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
diff --git a/gas/expr.c b/gas/expr.c
index 3ae1bcc581..69f0aaccdb 100644
--- a/gas/expr.c
+++ b/gas/expr.c
@@ -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;
diff --git a/gas/frags.c b/gas/frags.c
index 6dae8bc9c2..cfd183fb3d 100644
--- a/gas/frags.c
+++ b/gas/frags.c
@@ -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;
+}
diff --git a/gas/frags.h b/gas/frags.h
index e6c6170919..880446763a 100644
--- a/gas/frags.h
+++ b/gas/frags.h
@@ -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 */