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

View 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;
}

View 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];
};

View 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;

View 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)

View 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));