aboutsummaryrefslogtreecommitdiff
path: root/gas/write.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2001-03-30 02:19:36 +0000
committerAlan Modra <amodra@gmail.com>2001-03-30 02:19:36 +0000
commite46d99eb07bc0e366152fe2e69c613a15496e347 (patch)
tree55c79a36f0269e43402893bb90316d29a865e26f /gas/write.c
parentbee723322c56ee34f9f511e901171e8ebfe5d22e (diff)
downloadgdb-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.c82
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)