This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Multi-pass relaxation part 2
- To: binutils at sourceware dot cygnus dot com
- Subject: Multi-pass relaxation part 2
- From: Alan Modra <alan at linuxcare dot com dot au>
- Date: Fri, 30 Mar 2001 12:17:09 +1000 (EST)
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));