bfd/
[deliverable/binutils-gdb.git] / gas / write.c
index a90ee9df44474508d1bb70b6980861cdf585149e..2b084e3a01f08d3ed0e4f205104305c3731184a7 100644 (file)
@@ -1,6 +1,6 @@
 /* write.c - emit .o file
    Copyright 1986, 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
@@ -379,7 +379,7 @@ chain_frchains_together_1 (segT section, struct frchain *frchp)
   fragS dummy, *prev_frag = &dummy;
   fixS fix_dummy, *prev_fix = &fix_dummy;
 
-  for (; frchp && frchp->frch_seg == section; frchp = frchp->frch_next)
+  for (; frchp; frchp = frchp->frch_next)
     {
       prev_frag->fr_next = frchp->frch_root;
       prev_frag = frchp->frch_last;
@@ -394,6 +394,7 @@ chain_frchains_together_1 (segT section, struct frchain *frchp)
        }
     }
   assert (prev_frag->fr_type != 0);
+  assert (prev_frag != &dummy);
   prev_frag->fr_next = 0;
   return prev_frag;
 }
@@ -512,19 +513,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);
@@ -678,18 +681,11 @@ adjust_reloc_syms (bfd *abfd ATTRIBUTE_UNUSED,
 
        /* If this symbol is equated to an undefined or common symbol,
           convert the fixup to being against that symbol.  */
-       if (symbol_equated_reloc_p (sym))
+       if (symbol_equated_reloc_p (sym)
+           || S_IS_WEAKREFR (sym))
          {
-           symbolS *new_sym
-             = symbol_get_value_expression (sym)->X_add_symbol;
-           const char *name = S_GET_NAME (sym);
-           if (!S_IS_COMMON (new_sym)
-               && !TC_FAKE_LABEL (name)
-               && (!S_IS_EXTERNAL (sym) || S_IS_LOCAL (sym)))
-             as_bad (_("Local symbol `%s' can't be equated to undefined symbol `%s'"),
-                     name, S_GET_NAME (new_sym));
            fixp->fx_offset += symbol_get_value_expression (sym)->X_add_number;
-           sym = new_sym;
+           sym = symbol_get_value_expression (sym)->X_add_symbol;
            fixp->fx_addsy = sym;
          }
 
@@ -1019,11 +1015,8 @@ write_contents (bfd *abfd ATTRIBUTE_UNUSED,
                                        f->fr_literal, (file_ptr) offset,
                                        (bfd_size_type) f->fr_fix);
          if (!x)
-           {
-             bfd_perror (stdoutput->filename);
-             as_perror (_("FATAL: Can't write %s"), stdoutput->filename);
-             exit (EXIT_FAILURE);
-           }
+           as_fatal (_("can't write %s: %s"), stdoutput->filename,
+                     bfd_errmsg (bfd_get_error ()));
          offset += f->fr_fix;
        }
       fill_literal = f->fr_literal + f->fr_fix;
@@ -1043,12 +1036,8 @@ write_contents (bfd *abfd ATTRIBUTE_UNUSED,
                                                (file_ptr) offset,
                                                (bfd_size_type) fill_size);
                  if (!x)
-                   {
-                     bfd_perror (stdoutput->filename);
-                     as_perror (_("FATAL: Can't write %s"),
-                                stdoutput->filename);
-                     exit (EXIT_FAILURE);
-                   }
+                   as_fatal (_("can't write %s: %s"), stdoutput->filename,
+                             bfd_errmsg (bfd_get_error ()));
                  offset += fill_size;
                }
            }
@@ -1143,8 +1132,7 @@ set_symtab (void)
    of the section.  This allows proper nop-filling at the end of
    code-bearing sections.  */
 #define SUB_SEGMENT_ALIGN(SEG, FRCHAIN)                                        \
-  (!(FRCHAIN)->frch_next || (FRCHAIN)->frch_next->frch_seg != (SEG)    \
-   ? get_recorded_alignment (SEG) : 0)
+  (!(FRCHAIN)->frch_next ? get_recorded_alignment (SEG) : 0)
 #else
 #define SUB_SEGMENT_ALIGN(SEG, FRCHAIN) 0
 #endif
@@ -1154,48 +1142,58 @@ void
 subsegs_finish (void)
 {
   struct frchain *frchainP;
+  asection *s;
 
-  for (frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next)
+  for (s = stdoutput->sections; s; s = s->next)
     {
-      int alignment = 0;
-
-      subseg_set (frchainP->frch_seg, frchainP->frch_subseg);
+      segment_info_type *seginfo = seg_info (s);
+      if (!seginfo)
+       continue;
 
-      /* This now gets called even if we had errors.  In that case,
-         any alignment is meaningless, and, moreover, will look weird
-         if we are generating a listing.  */
-      if (!had_errors ())
+      for (frchainP = seginfo->frchainP;
+          frchainP != NULL;
+          frchainP = frchainP->frch_next)
        {
-         alignment = SUB_SEGMENT_ALIGN (now_seg, frchainP);
-         if ((bfd_get_section_flags (now_seg->owner, now_seg) & SEC_MERGE)
-             && now_seg->entsize)
-           {
-             unsigned int entsize = now_seg->entsize;
-             int entalign = 0;
+         int alignment = 0;
 
-             while ((entsize & 1) == 0)
+         subseg_set (s, frchainP->frch_subseg);
+
+         /* This now gets called even if we had errors.  In that case,
+            any alignment is meaningless, and, moreover, will look weird
+            if we are generating a listing.  */
+         if (!had_errors ())
+           {
+             alignment = SUB_SEGMENT_ALIGN (now_seg, frchainP);
+             if ((bfd_get_section_flags (now_seg->owner, now_seg) & SEC_MERGE)
+                 && now_seg->entsize)
                {
-                 ++entalign;
-                 entsize >>= 1;
+                 unsigned int entsize = now_seg->entsize;
+                 int entalign = 0;
+
+                 while ((entsize & 1) == 0)
+                   {
+                     ++entalign;
+                     entsize >>= 1;
+                   }
+                 if (entalign > alignment)
+                   alignment = entalign;
                }
-             if (entalign > alignment)
-               alignment = entalign;
            }
-       }
 
-      if (subseg_text_p (now_seg))
-       frag_align_code (alignment, 0);
-      else
-       frag_align (alignment, 0, 0);
+         if (subseg_text_p (now_seg))
+           frag_align_code (alignment, 0);
+         else
+           frag_align (alignment, 0, 0);
 
-      /* frag_align will have left a new frag.
-        Use this last frag for an empty ".fill".
+         /* frag_align will have left a new frag.
+            Use this last frag for an empty ".fill".
 
-        For this segment ...
-        Create a last frag. Do not leave a "being filled in frag".  */
-      frag_wane (frag_now);
-      frag_now->fr_fix = 0;
-      know (frag_now->fr_next == NULL);
+            For this segment ...
+            Create a last frag. Do not leave a "being filled in frag".  */
+         frag_wane (frag_now);
+         frag_now->fr_fix = 0;
+         know (frag_now->fr_next == NULL);
+       }
     }
 }
 
@@ -1204,6 +1202,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
@@ -1262,10 +1261,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
@@ -1286,9 +1284,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;
     }
 
@@ -1483,11 +1482,13 @@ write_object_file (void)
 
          /* Skip symbols which were equated to undefined or common
              symbols.  */
-         if (symbol_equated_reloc_p (symp))
+         if (symbol_equated_reloc_p (symp)
+             || S_IS_WEAKREFR (symp))
            {
              const char *name = S_GET_NAME (symp);
              if (S_IS_COMMON (symp)
                  && !TC_FAKE_LABEL (name)
+                 && !S_IS_WEAKREFR (symp)
                  && (!S_IS_EXTERNAL (symp) || S_IS_LOCAL (symp)))
                {
                  expressionS *e = symbol_get_value_expression (symp);
@@ -1498,12 +1499,6 @@ write_object_file (void)
              continue;
            }
 
-         /* So far, common symbols have been treated like undefined symbols.
-            Put them in the common section now.  */
-         if (S_IS_DEFINED (symp) == 0
-             && S_GET_VALUE (symp) != 0)
-           S_SET_SEGMENT (symp, bfd_com_section_ptr);
-
 #ifdef obj_frob_symbol
          obj_frob_symbol (symp, punt);
 #endif
@@ -1524,7 +1519,8 @@ write_object_file (void)
                 opposites.  Sometimes the former checks flags and the
                 latter examines the name...  */
              || (!S_IS_EXTERNAL (symp)
-                 && (punt || S_IS_LOCAL (symp))
+                 && (punt || S_IS_LOCAL (symp) ||
+                     (S_IS_WEAKREFD (symp) && ! symbol_used_p (symp)))
                  && ! symbol_used_in_reloc_p (symp)))
            {
              symbol_remove (symp, &symbol_rootP, &symbol_lastP);
@@ -1722,7 +1718,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;
@@ -1836,6 +1832,7 @@ relax_segment (struct frag *segment_frag_root, segT segment)
     if (max_iterations < frag_count)
       max_iterations = frag_count;
 
+    ret = 0;
     do
       {
        stretch = 0;
@@ -1965,6 +1962,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.  */
@@ -1977,7 +1994,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  */
@@ -2003,6 +2020,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;
@@ -2064,7 +2089,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)
       {
This page took 0.030582 seconds and 4 git commands to generate.