* write.c (relax_segment): Add pass count arg. Don't error on
authorAlan Modra <amodra@gmail.com>
Sun, 7 May 2006 23:03:48 +0000 (23:03 +0000)
committerAlan Modra <amodra@gmail.com>
Sun, 7 May 2006 23:03:48 +0000 (23:03 +0000)
negative org/space on first two passes.
(relax_seg_info): New struct.
(relax_seg, write_object_file): Adjust.
* write.h (relax_segment): Update prototype.

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

index 76386d751f75955187dd27b83a33f1b7e57bb91b..669e4cc14efcb1cafb06165661143a4a60da06bd 100644 (file)
@@ -1,3 +1,11 @@
+2006-05-08  Alan Modra  <amodra@bigpond.net.au>
+
+       * write.c (relax_segment): Add pass count arg.  Don't error on
+       negative org/space on first two passes.
+       (relax_seg_info): New struct.
+       (relax_seg, write_object_file): Adjust.
+       * write.h (relax_segment): Update prototype.
+
 2006-05-05  Julian Brown  <julian@codesourcery.com>
 
        * config/tc-arm.c (parse_vfp_reg_list): Improve register bounds
index 93b157fff1105553798a4740963c0286cb261022..9e28a6f5492bacee00e89457bd42524e30423d5e 100644 (file)
@@ -512,19 +512,21 @@ cvt_frag_to_fill (segT sec ATTRIBUTE_UNUSED, fragS *fragP)
 #endif
 }
 
-static void relax_seg (bfd *, asection *, PTR);
+struct relax_seg_info
+{
+  int pass;
+  int changed;
+};
 
 static void
-relax_seg (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, PTR xxx)
+relax_seg (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *xxx)
 {
   segment_info_type *seginfo = seg_info (sec);
+  struct relax_seg_info *info = (struct relax_seg_info *) xxx;
 
   if (seginfo && seginfo->frchainP
-      && relax_segment (seginfo->frchainP->frch_root, sec))
-    {
-      int *result = (int *) xxx;
-      *result = 1;
-    }
+      && relax_segment (seginfo->frchainP->frch_root, sec, info->pass))
+    info->changed = 1;
 }
 
 static void size_seg (bfd *, asection *, PTR);
@@ -1206,6 +1208,7 @@ subsegs_finish (void)
 void
 write_object_file (void)
 {
+  struct relax_seg_info rsi;
 #ifndef WORKING_DOT_WORD
   fragS *fragP;                        /* Track along all frags.  */
 #endif
@@ -1264,10 +1267,9 @@ write_object_file (void)
       merge_data_into_text ();
     }
 
+  rsi.pass = 0;
   while (1)
     {
-      int changed;
-
 #ifndef WORKING_DOT_WORD
       /* We need to reset the markers in the broken word list and
         associated frags between calls to relax_segment (via
@@ -1288,9 +1290,10 @@ write_object_file (void)
        }
 #endif
 
-      changed = 0;
-      bfd_map_over_sections (stdoutput, relax_seg, &changed);
-      if (!changed)
+      rsi.changed = 0;
+      bfd_map_over_sections (stdoutput, relax_seg, &rsi);
+      rsi.pass++;
+      if (!rsi.changed)
        break;
     }
 
@@ -1721,7 +1724,7 @@ relax_align (register relax_addressT address,     /* Address now.  */
    addresses.  */
 
 int
-relax_segment (struct frag *segment_frag_root, segT segment)
+relax_segment (struct frag *segment_frag_root, segT segment, int pass)
 {
   unsigned long frag_count;
   struct frag *fragP;
@@ -1835,6 +1838,7 @@ relax_segment (struct frag *segment_frag_root, segT segment)
     if (max_iterations < frag_count)
       max_iterations = frag_count;
 
+    ret = 0;
     do
       {
        stretch = 0;
@@ -1964,6 +1968,26 @@ relax_segment (struct frag *segment_frag_root, segT segment)
                  growth = target - after;
                  if (growth < 0)
                    {
+                     growth = 0;
+
+                     /* Don't error on first few frag relax passes.
+                        The symbol might be an expression involving
+                        symbol values from other sections.  If those
+                        sections have not yet been processed their
+                        frags will all have zero addresses, so we
+                        will calculate incorrect values for them.  The
+                        number of passes we allow before giving an
+                        error is somewhat arbitrary.  It should be at
+                        least one, with larger values requiring
+                        increasingly contrived dependencies between
+                        frags to trigger a false error.  */
+                     if (pass < 2)
+                       {
+                         /* Force another pass.  */
+                         ret = 1;
+                         break;
+                       }
+
                      /* Growth may be negative, but variable part of frag
                         cannot have fewer than 0 chars.  That is, we can't
                         .org backwards.  */
@@ -1976,7 +2000,7 @@ relax_segment (struct frag *segment_frag_root, segT segment)
                      fragP->fr_subtype = 0;
                      fragP->fr_offset = 0;
                      fragP->fr_fix = after - was_address;
-                     growth = stretch;
+                     break;
                    }
 
                  /* This is an absolute growth factor  */
@@ -2002,6 +2026,14 @@ relax_segment (struct frag *segment_frag_root, segT segment)
                      }
                    else if (amount < 0)
                      {
+                       /* Don't error on first few frag relax passes.
+                          See rs_org comment for a longer explanation.  */
+                       if (pass < 2)
+                         {
+                           ret = 1;
+                           break;
+                         }
+
                        as_warn_where (fragP->fr_file, fragP->fr_line,
                                       _(".space or .fill with negative value, ignored"));
                        fragP->fr_symbol = 0;
@@ -2063,7 +2095,6 @@ relax_segment (struct frag *segment_frag_root, segT segment)
                segment_name (segment));
   }
 
-  ret = 0;
   for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next)
     if (fragP->last_fr_address != fragP->fr_address)
       {
index 77ce75e5c68ac96b3968d5f7b1cf7ce02744734e..1f9b72dbf265d3abbabb2d7b2a162c6cabc42363 100644 (file)
@@ -1,6 +1,6 @@
 /* write.h
    Copyright 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001,
-   2002, 2003, 2005 Free Software Foundation, Inc.
+   2002, 2003, 2005, 2006 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -156,7 +156,7 @@ extern int get_recorded_alignment (segT seg);
 extern void subsegs_finish (void);
 extern void write_object_file (void);
 extern long relax_frag (segT, fragS *, long);
-extern int relax_segment (struct frag * seg_frag_root, segT seg_type);
+extern int relax_segment (struct frag *, segT, int);
 extern void number_to_chars_littleendian (char *, valueT, int);
 extern void number_to_chars_bigendian (char *, valueT, int);
 extern fixS *fix_new