diff options
author | Alan Modra <amodra@gmail.com> | 2010-10-19 12:00:33 +0000 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2010-10-19 12:00:33 +0000 |
commit | e35a414d3cd7c422e39db2611a063664cee3be70 (patch) | |
tree | a6fac698c13364598d6fe58a071f776e8d34cab0 /gas/write.c | |
parent | 8c540a24cf3403ee2d92d495bde7c8ac472da1d0 (diff) | |
download | gdb-e35a414d3cd7c422e39db2611a063664cee3be70.zip gdb-e35a414d3cd7c422e39db2611a063664cee3be70.tar.gz gdb-e35a414d3cd7c422e39db2611a063664cee3be70.tar.bz2 |
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.
Diffstat (limited to 'gas/write.c')
-rw-r--r-- | gas/write.c | 28 |
1 files changed, 20 insertions, 8 deletions
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: |