From e46d99eb07bc0e366152fe2e69c613a15496e347 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Fri, 30 Mar 2001 02:19:36 +0000 Subject: [PATCH] Multi-pass relaxation machinery. --- gas/ChangeLog | 19 ++++++++++++ gas/dwarf2dbg.c | 4 +-- gas/frags.h | 20 +++++++----- gas/symbols.c | 12 ++++++-- gas/write.c | 82 ++++++++++++++++++++++++++++++++++++------------- gas/write.h | 4 ++- 6 files changed, 107 insertions(+), 34 deletions(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index 71c790f52bb..10403a532c7 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,5 +1,24 @@ 2001-03-30 Alan Modra + * 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. diff --git a/gas/dwarf2dbg.c b/gas/dwarf2dbg.c index bc37e7e0eb4..87075423a70 100644 --- a/gas/dwarf2dbg.c +++ b/gas/dwarf2dbg.c @@ -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; } diff --git a/gas/frags.h b/gas/frags.h index e4cb0509dbc..df259b8fe55 100644 --- a/gas/frags.h +++ b/gas/frags.h @@ -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]; }; diff --git a/gas/symbols.c b/gas/symbols.c index b983ddbb466..913686cd8c5 100644 --- a/gas/symbols.c +++ b/gas/symbols.c @@ -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; diff --git a/gas/write.c b/gas/write.c index b94c05eed71..ea4b0820f31 100644 --- a/gas/write.c +++ b/gas/write.c @@ -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) diff --git a/gas/write.h b/gas/write.h index 5bab7a21214..451215d7e81 100644 --- a/gas/write.h +++ b/gas/write.h @@ -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)); -- 2.30.2