Multi-pass relaxation machinery.

This commit is contained in:
Alan Modra
2001-03-30 02:19:36 +00:00
parent bee723322c
commit e46d99eb07
6 changed files with 107 additions and 34 deletions

View File

@ -1,5 +1,24 @@
2001-03-30 Alan Modra <alan@linuxcare.com.au> 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 * config/tc-sh.c (md_estimate_size_before_relax): Add extra
do-nothing cases to switch to avoid abort on a second relaxation do-nothing cases to switch to avoid abort on a second relaxation
pass, and tidy code a little. pass, and tidy code a little.

View File

@ -324,7 +324,7 @@ dwarf2_directive_file (dummy)
int dummy ATTRIBUTE_UNUSED; int dummy ATTRIBUTE_UNUSED;
{ {
offsetT num; offsetT num;
const char *filename; char *filename;
int filename_len; int filename_len;
/* Continue to accept a bare string and pass it off. */ /* 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) 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; return;
} }

View File

@ -43,8 +43,9 @@ struct obstack;
struct frag { struct frag {
/* Object file address (as an octet offset). */ /* Object file address (as an octet offset). */
addressT fr_address; addressT fr_address;
/* Chain forward; ascending address order. Rooted in frch_root. */ /* When relaxing multiple times, remember the address the frag had
struct frag *fr_next; in the last relax pass. */
addressT last_fr_address;
/* (Fixed) number of octets we know we have. May be 0. */ /* (Fixed) number of octets we know we have. May be 0. */
offsetT fr_fix; offsetT fr_fix;
@ -52,12 +53,19 @@ struct frag {
The generic frag handling code no longer makes any use of fr_var. */ The generic frag handling code no longer makes any use of fr_var. */
offsetT fr_var; offsetT fr_var;
/* For variable-length tail. */ /* For variable-length tail. */
symbolS *fr_symbol;
/* For variable-length tail. */
offsetT fr_offset; offsetT fr_offset;
/* For variable-length tail. */
symbolS *fr_symbol;
/* Points to opcode low addr byte, for relaxation. */ /* Points to opcode low addr byte, for relaxation. */
char *fr_opcode; 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 #ifndef NO_LISTING
struct list_info_struct *line; struct list_info_struct *line;
#endif #endif
@ -86,10 +94,6 @@ struct frag {
TC_FRAG_TYPE tc_frag_data; TC_FRAG_TYPE tc_frag_data;
#endif #endif
/* Where the frag was created, or where it became a variant frag. */
char *fr_file;
unsigned int fr_line;
/* Data begins here. */ /* Data begins here. */
char fr_literal[1]; char fr_literal[1];
}; };

View File

@ -866,6 +866,10 @@ resolve_symbol_value (symp, finalize)
resolved = 0; resolved = 0;
final_seg = S_GET_SEGMENT (symp); 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) if (symp->sy_resolving)
{ {
@ -1182,7 +1186,7 @@ resolve_local_symbol (key, value)
PTR value; PTR value;
{ {
if (value != NULL) if (value != NULL)
resolve_symbol_value (value, 1); resolve_symbol_value (value, finalize_syms);
} }
#endif #endif
@ -1574,7 +1578,11 @@ S_GET_VALUE (s)
#endif #endif
if (!s->sy_resolved && s->sy_value.X_op != O_constant) 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) if (s->sy_value.X_op != O_constant)
{ {
static symbolS *recur; static symbolS *recur;

View File

@ -61,6 +61,11 @@ extern CONST int md_short_jump_size;
extern CONST int md_long_jump_size; extern CONST int md_long_jump_size;
#endif #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; int symbol_table_frozen;
void print_fixup PARAMS ((fixS *)); void print_fixup PARAMS ((fixS *));
@ -122,7 +127,6 @@ static fragS *chain_frchains_together_1 PARAMS ((segT, struct frchain *));
#ifdef BFD_ASSEMBLER #ifdef BFD_ASSEMBLER
static void chain_frchains_together PARAMS ((bfd *, segT, PTR)); static void chain_frchains_together PARAMS ((bfd *, segT, PTR));
static void cvt_frag_to_fill PARAMS ((segT, fragS *)); 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 adjust_reloc_syms PARAMS ((bfd *, asection *, PTR));
static void write_relocs PARAMS ((bfd *, asection *, PTR)); static void write_relocs PARAMS ((bfd *, asection *, PTR));
static void write_contents 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) */ #endif /* defined (BFD_ASSEMBLER) || !defined (BFD) */
#ifdef BFD_ASSEMBLER #ifdef BFD_ASSEMBLER
static void relax_seg PARAMS ((bfd *, asection *, PTR));
static void 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; bfd *abfd;
asection *sec; asection *sec;
PTR xxx ATTRIBUTE_UNUSED; PTR xxx ATTRIBUTE_UNUSED;
@ -611,12 +633,9 @@ relax_and_size_seg (abfd, sec, xxx)
subseg_change (sec, 0); subseg_change (sec, 0);
flags = bfd_get_section_flags (abfd, sec);
seginfo = seg_info (sec); seginfo = seg_info (sec);
if (seginfo && seginfo->frchainP) if (seginfo && seginfo->frchainP)
{ {
relax_segment (seginfo->frchainP->frch_root, sec);
for (fragp = seginfo->frchainP->frch_root; fragp; fragp = fragp->fr_next) for (fragp = seginfo->frchainP->frch_root; fragp; fragp = fragp->fr_next)
cvt_frag_to_fill (sec, fragp); cvt_frag_to_fill (sec, fragp);
for (fragp = seginfo->frchainP->frch_root; for (fragp = seginfo->frchainP->frch_root;
@ -629,6 +648,8 @@ relax_and_size_seg (abfd, sec, xxx)
else else
size = 0; size = 0;
flags = bfd_get_section_flags (abfd, sec);
if (size > 0 && ! seginfo->bss) if (size > 0 && ! seginfo->bss)
flags |= SEC_HAS_CONTENTS; flags |= SEC_HAS_CONTENTS;
@ -739,10 +760,10 @@ adjust_reloc_syms (abfd, sec, xxx)
symbols, though, since they are not in the regular symbol symbols, though, since they are not in the regular symbol
table. */ table. */
if (sym != NULL) if (sym != NULL)
resolve_symbol_value (sym, 1); resolve_symbol_value (sym, finalize_syms);
if (fixp->fx_subsy != NULL) 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 /* If this symbol is equated to an undefined symbol, convert
the fixup to being against that symbol. */ the fixup to being against that symbol. */
@ -1519,11 +1540,23 @@ write_object_file ()
#endif #endif
#ifdef BFD_ASSEMBLER #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 #else
relax_and_size_all_segments (); relax_and_size_all_segments ();
#endif /* BFD_ASSEMBLER */ #endif /* BFD_ASSEMBLER */
/* Relaxation has completed. Freeze all syms. */
finalize_syms = 2;
#if defined (BFD_ASSEMBLER) && defined (OBJ_COFF) && defined (TE_GO32) #if defined (BFD_ASSEMBLER) && defined (OBJ_COFF) && defined (TE_GO32)
/* Now that the segments have their final sizes, run through the /* 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 sections and set their vma and lma. !BFD gas sets them, and BFD gas
@ -1842,7 +1875,7 @@ write_object_file ()
symbolS *symp; symbolS *symp;
for (symp = symbol_rootP; symp; symp = symbol_next (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 (); resolve_local_symbol_values ();
@ -1890,7 +1923,7 @@ write_object_file ()
/* Do it again, because adjust_reloc_syms might introduce /* Do it again, because adjust_reloc_syms might introduce
more symbols. They'll probably only be section symbols, more symbols. They'll probably only be section symbols,
but they'll still need to have the values computed. */ 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 /* Skip symbols which were equated to undefined or common
symbols. */ symbols. */
@ -2141,13 +2174,15 @@ relax_align (address, alignment)
these frag addresses may not be the same as final object-file these frag addresses may not be the same as final object-file
addresses. */ addresses. */
void int
relax_segment (segment_frag_root, segment) relax_segment (segment_frag_root, segment)
struct frag *segment_frag_root; struct frag *segment_frag_root;
segT segment; segT segment;
{ {
register struct frag *fragP; register struct frag *fragP;
register relax_addressT address; register relax_addressT address;
int ret;
#if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER) #if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER)
know (segment == SEG_DATA || segment == SEG_TEXT || segment == SEG_BSS); know (segment == SEG_DATA || segment == SEG_TEXT || segment == SEG_BSS);
#endif #endif
@ -2229,14 +2264,15 @@ relax_segment (segment_frag_root, segment)
long stretch; /* May be any size, 0 or negative. */ long stretch; /* May be any size, 0 or negative. */
/* Cumulative number of addresses we have relaxed this pass. /* Cumulative number of addresses we have relaxed this pass.
We may have relaxed more than one address. */ 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 /* 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, grew, and another shrank. If a branch instruction doesn't fit anymore,
we could be scrod. */ we could be scrod. */
do do
{ {
stretch = stretched = 0; stretch = 0;
stretched = 0;
for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next) for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next)
{ {
@ -2345,8 +2381,8 @@ relax_segment (segment_frag_root, segment)
case rs_org: case rs_org:
{ {
long target = offset; addressT target = offset;
long after; addressT after;
if (symbolP) if (symbolP)
{ {
@ -2447,17 +2483,21 @@ relax_segment (segment_frag_root, segment)
if (growth) if (growth)
{ {
stretch += growth; stretch += growth;
stretched++; stretched = 1;
} }
} /* For each frag in the segment. */ } /* For each frag in the segment. */
} }
while (stretched); /* Until nothing further to relax. */ while (stretched); /* Until nothing further to relax. */
} /* do_relax */ } /* do_relax */
/* We now have valid fr_address'es for each frag. */ ret = 0;
for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next)
/* All fr_address's are correct, relative to their own segment. if (fragP->last_fr_address != fragP->fr_address)
We have made all the fixS we will ever make. */ {
fragP->last_fr_address = fragP->fr_address;
ret = 1;
}
return ret;
} }
#if defined (BFD_ASSEMBLER) || (!defined (BFD) && !defined (OBJ_VMS)) #if defined (BFD_ASSEMBLER) || (!defined (BFD) && !defined (OBJ_VMS))
@ -2544,7 +2584,7 @@ fixup_segment (fixP, this_segment_type)
if (sub_symbolP) 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 || add_symbol_segment == absolute_section)
{ {
if (add_symbolP != NULL) if (add_symbolP != NULL)

View File

@ -157,6 +157,8 @@ struct fix
typedef struct fix fixS; typedef struct fix fixS;
extern int finalize_syms;
#ifndef BFD_ASSEMBLER #ifndef BFD_ASSEMBLER
extern char *next_object_file_charP; 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 subsegs_finish PARAMS ((void));
extern void write_object_file PARAMS ((void)); extern void write_object_file PARAMS ((void));
extern long relax_frag PARAMS ((segT, fragS *, long)); 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)); PARAMS ((struct frag * seg_frag_root, segT seg_type));
extern void number_to_chars_littleendian PARAMS ((char *, valueT, int)); extern void number_to_chars_littleendian PARAMS ((char *, valueT, int));