From 99630778988bcd5195fc056fbd013d32d1362d5a Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Tue, 4 Apr 2006 08:04:57 +0000 Subject: [PATCH] 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. --- gas/ChangeLog | 8 ++++++++ gas/expr.c | 18 ++++++++++++----- gas/frags.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++- gas/frags.h | 4 +++- 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 + + 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 * 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 */ -- 2.34.1