This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Multi-pass relaxation part 2


Here's the machinery to relax over all sections until nothing more
changes.  This is the bit that's likely to break things, I'm afraid.
Please test all ports you can.  Bug reports welcome.

	* 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.

Alan Modra
-- 
Linuxcare

Index: gas/frags.h
===================================================================
RCS file: /cvs/src/src/gas/frags.h,v
retrieving revision 1.10
diff -u -p -r1.10 frags.h
--- frags.h	2001/03/20 03:12:01	1.10
+++ frags.h	2001/03/30 01:28:32
@@ -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
@@ -85,10 +93,6 @@ struct frag {
 #ifdef TC_FRAG_TYPE
   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: gas/symbols.c
===================================================================
RCS file: /cvs/src/src/gas/symbols.c,v
retrieving revision 1.19
diff -u -p -r1.19 symbols.c
--- symbols.c	2001/03/08 23:24:22	1.19
+++ symbols.c	2001/03/30 01:28:42
@@ -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: gas/write.c
===================================================================
RCS file: /cvs/src/src/gas/write.c,v
retrieving revision 1.29
diff -u -p -r1.29 write.c
--- write.c	2001/03/23 18:15:49	1.29
+++ write.c	2001/03/30 01:29:08
@@ -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 
 #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, segmen
     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, segmen
 
 	      case rs_org:
 		{
-		  long target = offset;
-		  long after;
+		  addressT target = offset;
+		  addressT after;
 
 		  if (symbolP)
 		    {
@@ -2447,17 +2483,21 @@ relax_segment (segment_frag_root, segmen
 	    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: gas/write.h
===================================================================
RCS file: /cvs/src/src/gas/write.h,v
retrieving revision 1.5
diff -u -p -r1.5 write.h
--- write.h	2001/03/08 23:24:22	1.5
+++ write.h	2001/03/30 01:29:09
@@ -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
 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));


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]