diff options
author | Alan Modra <amodra@gmail.com> | 2001-03-30 02:19:36 +0000 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2001-03-30 02:19:36 +0000 |
commit | e46d99eb07bc0e366152fe2e69c613a15496e347 (patch) | |
tree | 55c79a36f0269e43402893bb90316d29a865e26f /gas/write.c | |
parent | bee723322c56ee34f9f511e901171e8ebfe5d22e (diff) | |
download | gdb-e46d99eb07bc0e366152fe2e69c613a15496e347.zip gdb-e46d99eb07bc0e366152fe2e69c613a15496e347.tar.gz gdb-e46d99eb07bc0e366152fe2e69c613a15496e347.tar.bz2 |
Multi-pass relaxation machinery.
Diffstat (limited to 'gas/write.c')
-rw-r--r-- | gas/write.c | 82 |
1 files changed, 61 insertions, 21 deletions
diff --git a/gas/write.c b/gas/write.c index b94c05e..ea4b082 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) |