From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 19622 invoked by alias); 4 Apr 2006 08:03:18 -0000 Received: (qmail 19614 invoked by uid 22791); 4 Apr 2006 08:03:17 -0000 X-Spam-Check-By: sourceware.org Received: from CPE-144-136-172-108.sa.bigpond.net.au (HELO grove.modra.org) (144.136.172.108) by sourceware.org (qpsmtpd/0.31) with ESMTP; Tue, 04 Apr 2006 08:03:16 +0000 Received: by bubble.grove.modra.org (Postfix, from userid 500) id 4E6561DD483; Tue, 4 Apr 2006 17:33:13 +0930 (CST) Date: Tue, 04 Apr 2006 08:03:00 -0000 From: Alan Modra To: binutils@sourceware.org Subject: Fix PR997, gas listings breakage Message-ID: <20060404080313.GI9418@bubble.grove.modra.org> Mail-Followup-To: binutils@sourceware.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4i X-IsSubscribed: yes Mailing-List: contact binutils-help@sourceware.org; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: binutils-owner@sourceware.org X-SW-Source: 2006-04/txt/msg00030.txt.bz2 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