diff options
-rw-r--r-- | gas/ChangeLog | 8 | ||||
-rw-r--r-- | gas/frags.h | 6 | ||||
-rw-r--r-- | gas/write.c | 28 |
3 files changed, 33 insertions, 9 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index ac32847..905ba0d 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,11 @@ +2010-10-19 Alan Modra <amodra@gmail.com> + + PR gas/12049 + * frags.h (struct frag): Add "region" field. + * write.c (relax_frag): Don't add "stretch" to forward reference + target if there is an intervening org or align. + (relax_segment): Set region. + 2010-10-18 Maciej W. Rozycki <macro@linux-mips.org> * config/tc-mips.c (macro)[ldd_std]: Fix the relaxation variant diff --git a/gas/frags.h b/gas/frags.h index a14e3a2..650ea5e 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, 2006, 2007 Free Software Foundation, Inc. + 2002, 2003, 2004, 2005, 2006, 2007, 2010 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -68,6 +68,10 @@ struct frag { struct list_info_struct *line; #endif + /* A serial number for a sequence of frags having at most one alignment + or org frag, and that at the tail of the sequence. */ + unsigned int region:16; + /* Flipped each relax pass so we can easily determine whether fr_address has been adjusted. */ unsigned int relax_marker:1; diff --git a/gas/write.c b/gas/write.c index 71ac635..62f196c 100644 --- a/gas/write.c +++ b/gas/write.c @@ -1,7 +1,7 @@ /* write.c - emit .o file Copyright 1986, 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, - 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 - Free Software Foundation, Inc. + 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, + 2010 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -2148,16 +2148,21 @@ relax_frag (segT segment, fragS *fragP, long stretch) || sym_frag == &zero_address_frag); target += S_GET_VALUE (symbolP); - /* If frag has yet to be reached on this pass, - assume it will move by STRETCH just as we did. - If this is not so, it will be because some frag - between grows, and that will force another pass. */ + /* If SYM_FRAG has yet to be reached on this pass, assume it + will move by STRETCH just as we did, unless there is an + alignment frag between here and SYM_FRAG. An alignment may + well absorb any STRETCH, and we don't want to choose a larger + branch insn by overestimating the needed reach of this + branch. It isn't critical to calculate TARGET exactly; We + know we'll be doing another pass if STRETCH is non-zero. */ if (stretch != 0 && sym_frag->relax_marker != fragP->relax_marker && S_GET_SEGMENT (symbolP) == segment) { - target += stretch; + if (stretch < 0 + || sym_frag->region == fragP->region) + target += stretch; } } @@ -2245,6 +2250,7 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass) unsigned long frag_count; struct frag *fragP; relax_addressT address; + int region; int ret; /* In case md_estimate_size_before_relax() wants to make fixSs. */ @@ -2253,10 +2259,12 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass) /* For each frag in segment: count and store (a 1st guess of) fr_address. */ address = 0; + region = 0; for (frag_count = 0, fragP = segment_frag_root; fragP; fragP = fragP->fr_next, frag_count ++) { + fragP->region = region; fragP->relax_marker = 0; fragP->fr_address = address; address += fragP->fr_fix; @@ -2285,12 +2293,16 @@ relax_segment (struct frag *segment_frag_root, segT segment, int pass) } address += offset; + region += 1; } break; case rs_org: - case rs_space: /* Assume .org is nugatory. It will grow with 1st relax. */ + region += 1; + break; + + case rs_space: break; case rs_machine_dependent: |