Multi-pass relaxation machinery.
authorAlan Modra <amodra@gmail.com>
Fri, 30 Mar 2001 02:19:36 +0000 (02:19 +0000)
committerAlan Modra <amodra@gmail.com>
Fri, 30 Mar 2001 02:19:36 +0000 (02:19 +0000)
gas/ChangeLog
gas/dwarf2dbg.c
gas/frags.h
gas/symbols.c
gas/write.c
gas/write.h

index 71c790f..10403a5 100644 (file)
@@ -1,5 +1,24 @@
 2001-03-30  Alan Modra  <alan@linuxcare.com.au>
 
+       * frags.h (struct frag): Add last_fr_address.  Reorder fields for
+       better packing.
+       * symbols.c (resolve_symbol_value): Don't fix expression values
+       until relaxation is complete.
+       (resolve_local_symbol): Pass `finalize_syms' to resolve_symbol_value.
+       (S_GET_VALUE): Likewise, and return unresolved expression value.
+       * write.c (finalize_syms): New.
+       (relax_and_size_seg): Split into..
+       (relax_seg): New function, returns 1 if anything changed..
+       (size_seg): And the remainder of relax_and_size_seg.
+       (fixup_segment): Arrange for final resolution of sym values.
+       (adjust_reloc_syms): Likewise.
+       (write_object_file): Likewise, and repeatedly call relax_seg until
+       nothing more changes.
+       (relax_segment): Return 1 if anything changed.  Use correct types
+       for rs_org `target' and `after'.
+       * write.h (finalize_syms): Declare.
+       (relax_segment): Update prototype.
+
        * config/tc-sh.c (md_estimate_size_before_relax): Add extra
        do-nothing cases to switch to avoid abort on a second relaxation
        pass, and tidy code a little.
index bc37e7e..8707542 100644 (file)
@@ -324,7 +324,7 @@ dwarf2_directive_file (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
   offsetT num;
-  const char *filename;
+  char *filename;
   int filename_len;
 
   /* Continue to accept a bare string and pass it off.  */
@@ -347,7 +347,7 @@ dwarf2_directive_file (dummy)
 
   if (num < files_in_use && files[num].filename != 0)
     {
-      as_bad (_("File number %d already allocated"), num);
+      as_bad (_("File number %ld already allocated"), (long) num);
       return;
     }
 
index e4cb050..df259b8 100644 (file)
@@ -43,8 +43,9 @@ struct obstack;
 struct frag {
   /* Object file address (as an octet offset).  */
   addressT fr_address;
-  /* Chain forward; ascending address order.  Rooted in frch_root.  */
-  struct frag *fr_next;
+  /* When relaxing multiple times, remember the address the frag had
+     in the last relax pass.  */
+  addressT last_fr_address;
 
   /* (Fixed) number of octets we know we have.  May be 0.  */
   offsetT fr_fix;
@@ -52,12 +53,19 @@ struct frag {
      The generic frag handling code no longer makes any use of fr_var.  */
   offsetT fr_var;
   /* For variable-length tail.  */
-  symbolS *fr_symbol;
-  /* For variable-length tail.  */
   offsetT fr_offset;
+  /* For variable-length tail.  */
+  symbolS *fr_symbol;
   /* Points to opcode low addr byte, for relaxation.  */
   char *fr_opcode;
 
+  /* Chain forward; ascending address order.  Rooted in frch_root.  */
+  struct frag *fr_next;
+
+  /* Where the frag was created, or where it became a variant frag.  */
+  char *fr_file;
+  unsigned int fr_line;
+
 #ifndef NO_LISTING
   struct list_info_struct *line;
 #endif
@@ -86,10 +94,6 @@ struct frag {
   TC_FRAG_TYPE tc_frag_data;
 #endif
 
-  /* Where the frag was created, or where it became a variant frag.  */
-  char *fr_file;
-  unsigned int fr_line;
-
   /* Data begins here.  */
   char fr_literal[1];
 };
index b983ddb..913686c 100644 (file)
@@ -866,6 +866,10 @@ resolve_symbol_value (symp, finalize)
 
   resolved = 0;
   final_seg = S_GET_SEGMENT (symp);
+  /* Expressions aren't really symbols, so don't finalize their values
+     until relaxation is complete.  */
+  if (final_seg == expr_section && finalize != 2)
+    finalize = 0;
 
   if (symp->sy_resolving)
     {
@@ -1182,7 +1186,7 @@ resolve_local_symbol (key, value)
      PTR value;
 {
   if (value != NULL)
-    resolve_symbol_value (value, 1);
+    resolve_symbol_value (value, finalize_syms);
 }
 
 #endif
@@ -1574,7 +1578,11 @@ S_GET_VALUE (s)
 #endif
 
   if (!s->sy_resolved && s->sy_value.X_op != O_constant)
-    resolve_symbol_value (s, 1);
+    {
+      valueT val = resolve_symbol_value (s, finalize_syms);
+      if (finalize_syms != 2 && S_GET_SEGMENT (s) == expr_section)
+       return val;
+    }
   if (s->sy_value.X_op != O_constant)
     {
       static symbolS *recur;
index b94c05e..ea4b082 100644 (file)
@@ -61,6 +61,11 @@ extern CONST int md_short_jump_size;
 extern CONST int md_long_jump_size;
 #endif
 
+/* Used to control final evaluation of expressions that are more
+   complex than symbol + constant.  1 means set final value for simple
+   expressions, 2 means set final value for more complex expressions.  */
+int finalize_syms = 1;
+
 int symbol_table_frozen;
 void print_fixup PARAMS ((fixS *));
 
@@ -122,7 +127,6 @@ static fragS *chain_frchains_together_1 PARAMS ((segT, struct frchain *));
 #ifdef BFD_ASSEMBLER
 static void chain_frchains_together PARAMS ((bfd *, segT, PTR));
 static void cvt_frag_to_fill PARAMS ((segT, fragS *));
-static void relax_and_size_seg PARAMS ((bfd *, asection *, PTR));
 static void adjust_reloc_syms PARAMS ((bfd *, asection *, PTR));
 static void write_relocs PARAMS ((bfd *, asection *, PTR));
 static void write_contents PARAMS ((bfd *, asection *, PTR));
@@ -597,8 +601,26 @@ cvt_frag_to_fill (headersP, sec, fragP)
 #endif /* defined (BFD_ASSEMBLER) || !defined (BFD)  */
 
 #ifdef BFD_ASSEMBLER
+static void relax_seg PARAMS ((bfd *, asection *, PTR));
 static void
-relax_and_size_seg (abfd, sec, xxx)
+relax_seg (abfd, sec, xxx)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *sec;
+     PTR xxx;
+{
+  segment_info_type *seginfo = seg_info (sec);
+
+  if (seginfo && seginfo->frchainP
+      && relax_segment (seginfo->frchainP->frch_root, sec))
+    {
+      int *result = (int *) xxx;
+      *result = 1;
+    }
+}
+
+static void size_seg PARAMS ((bfd *, asection *, PTR));
+static void
+size_seg (abfd, sec, xxx)
      bfd *abfd;
      asection *sec;
      PTR xxx ATTRIBUTE_UNUSED;
@@ -611,12 +633,9 @@ relax_and_size_seg (abfd, sec, xxx)
 
   subseg_change (sec, 0);
 
-  flags = bfd_get_section_flags (abfd, sec);
-
   seginfo = seg_info (sec);
   if (seginfo && seginfo->frchainP)
     {
-      relax_segment (seginfo->frchainP->frch_root, sec);
       for (fragp = seginfo->frchainP->frch_root; fragp; fragp = fragp->fr_next)
        cvt_frag_to_fill (sec, fragp);
       for (fragp = seginfo->frchainP->frch_root;
@@ -629,6 +648,8 @@ relax_and_size_seg (abfd, sec, xxx)
   else
     size = 0;
 
+  flags = bfd_get_section_flags (abfd, sec);
+
   if (size > 0 && ! seginfo->bss)
     flags |= SEC_HAS_CONTENTS;
 
@@ -739,10 +760,10 @@ adjust_reloc_syms (abfd, sec, xxx)
           symbols, though, since they are not in the regular symbol
           table.  */
        if (sym != NULL)
-         resolve_symbol_value (sym, 1);
+         resolve_symbol_value (sym, finalize_syms);
 
        if (fixp->fx_subsy != NULL)
-         resolve_symbol_value (fixp->fx_subsy, 1);
+         resolve_symbol_value (fixp->fx_subsy, finalize_syms);
 
        /* If this symbol is equated to an undefined symbol, convert
            the fixup to being against that symbol.  */
@@ -1519,11 +1540,23 @@ write_object_file ()
 #endif
 
 #ifdef BFD_ASSEMBLER
-  bfd_map_over_sections (stdoutput, relax_and_size_seg, (char *) 0);
+  while (1)
+    {
+      int changed;
+
+      changed = 0;
+      bfd_map_over_sections (stdoutput, relax_seg, &changed);
+      if (!changed)
+       break;
+    }
+  bfd_map_over_sections (stdoutput, size_seg, (char *) 0);
 #else
   relax_and_size_all_segments ();
 #endif /* BFD_ASSEMBLER  */
 
+  /* Relaxation has completed.  Freeze all syms.  */
+  finalize_syms = 2;
+
 #if defined (BFD_ASSEMBLER) && defined (OBJ_COFF) && defined (TE_GO32)
   /* Now that the segments have their final sizes, run through the
      sections and set their vma and lma. !BFD gas sets them, and BFD gas
@@ -1842,7 +1875,7 @@ write_object_file ()
       symbolS *symp;
 
       for (symp = symbol_rootP; symp; symp = symbol_next (symp))
-       resolve_symbol_value (symp, 1);
+       resolve_symbol_value (symp, finalize_syms);
     }
   resolve_local_symbol_values ();
 
@@ -1890,7 +1923,7 @@ write_object_file ()
          /* Do it again, because adjust_reloc_syms might introduce
             more symbols.  They'll probably only be section symbols,
             but they'll still need to have the values computed.  */
-         resolve_symbol_value (symp, 1);
+         resolve_symbol_value (symp, finalize_syms);
 
          /* Skip symbols which were equated to undefined or common
              symbols.  */
@@ -2141,13 +2174,15 @@ relax_align (address, alignment)
    these frag addresses may not be the same as final object-file
    addresses.  */
 
-void
+int
 relax_segment (segment_frag_root, segment)
      struct frag *segment_frag_root;
      segT segment;
 {
   register struct frag *fragP;
   register relax_addressT address;
+  int ret;
+
 #if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER)
   know (segment == SEG_DATA || segment == SEG_TEXT || segment == SEG_BSS);
 #endif
@@ -2229,14 +2264,15 @@ relax_segment (segment_frag_root, segment)
     long stretch;      /* May be any size, 0 or negative.  */
     /* Cumulative number of addresses we have relaxed this pass.
        We may have relaxed more than one address.  */
-    long stretched;    /* Have we stretched on this pass?  */
+    int stretched;     /* Have we stretched on this pass?  */
     /* This is 'cuz stretch may be zero, when, in fact some piece of code
        grew, and another shrank.  If a branch instruction doesn't fit anymore,
        we could be scrod.  */
 
     do
       {
-       stretch = stretched = 0;
+       stretch = 0;
+       stretched = 0;
 
        for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next)
          {
@@ -2345,8 +2381,8 @@ relax_segment (segment_frag_root, segment)
 
              case rs_org:
                {
-                 long target = offset;
-                 long after;
+                 addressT target = offset;
+                 addressT after;
 
                  if (symbolP)
                    {
@@ -2447,17 +2483,21 @@ relax_segment (segment_frag_root, segment)
            if (growth)
              {
                stretch += growth;
-               stretched++;
+               stretched = 1;
              }
          }                     /* For each frag in the segment.  */
       }
     while (stretched);         /* Until nothing further to relax.  */
   }                            /* do_relax  */
 
-  /* We now have valid fr_address'es for each frag.  */
-
-  /* All fr_address's are correct, relative to their own segment.
-     We have made all the fixS we will ever make.  */
+  ret = 0;
+  for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next)
+    if (fragP->last_fr_address != fragP->fr_address)
+      {
+       fragP->last_fr_address = fragP->fr_address;
+       ret = 1;
+      }
+  return ret;
 }
 
 #if defined (BFD_ASSEMBLER) || (!defined (BFD) && !defined (OBJ_VMS))
@@ -2544,7 +2584,7 @@ fixup_segment (fixP, this_segment_type)
 
       if (sub_symbolP)
        {
-         resolve_symbol_value (sub_symbolP, 1);
+         resolve_symbol_value (sub_symbolP, finalize_syms);
          if (add_symbolP == NULL || add_symbol_segment == absolute_section)
            {
              if (add_symbolP != NULL)
index 5bab7a2..451215d 100644 (file)
@@ -157,6 +157,8 @@ struct fix
 
 typedef struct fix fixS;
 
+extern int finalize_syms;
+
 #ifndef BFD_ASSEMBLER
 extern char *next_object_file_charP;
 
@@ -182,7 +184,7 @@ extern int get_recorded_alignment PARAMS ((segT seg));
 extern void subsegs_finish PARAMS ((void));
 extern void write_object_file PARAMS ((void));
 extern long relax_frag PARAMS ((segT, fragS *, long));
-extern void relax_segment
+extern int relax_segment
   PARAMS ((struct frag * seg_frag_root, segT seg_type));
 
 extern void number_to_chars_littleendian PARAMS ((char *, valueT, int));