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.
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 *));
#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));
#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;
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;
else
size = 0;
+ flags = bfd_get_section_flags (abfd, sec);
+
if (size > 0 && ! seginfo->bss)
flags |= SEC_HAS_CONTENTS;
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. */
#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
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 ();
/* 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. */
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
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)
{
case rs_org:
{
- long target = offset;
- long after;
+ addressT target = offset;
+ addressT after;
if (symbolP)
{
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))
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)