PR gas/12049
authorAlan Modra <amodra@gmail.com>
Tue, 19 Oct 2010 12:00:33 +0000 (12:00 +0000)
committerAlan Modra <amodra@gmail.com>
Tue, 19 Oct 2010 12:00:33 +0000 (12:00 +0000)
* 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.

gas/ChangeLog
gas/frags.h
gas/write.c

index ac328477afa27af35e3e7ca6d09a960c51c98caa..905ba0d3471a29d78e250949c019011d80aa9d35 100644 (file)
@@ -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
index a14e3a25541d3069ba85175983b36b07520d11f0..650ea5ed6a5617a12d99e012aed4763c7419bbdd 100644 (file)
@@ -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;
index 71ac63562c9d5e28a346aa124e77114afd9acbda..62f196c0de556f2d66d7d837346cb09d6aa936f2 100644 (file)
@@ -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: