summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Modra <amodra@bigpond.net.au>2001-03-30 02:19:36 +0000
committerAlan Modra <amodra@bigpond.net.au>2001-03-30 02:19:36 +0000
commiteb1e36c3f47b779c445bba53e8325ff7fdc211d4 (patch)
treeb03fecd04335ec3ba03118a279b226c0b36ee72d
parent9c2ccf7ced01cf7332f2b2ed699b06d679b56930 (diff)
downloadbinutils-redhat-eb1e36c3f47b779c445bba53e8325ff7fdc211d4.tar.gz
Multi-pass relaxation machinery.
-rw-r--r--gas/ChangeLog19
-rw-r--r--gas/dwarf2dbg.c4
-rw-r--r--gas/frags.h20
-rw-r--r--gas/symbols.c12
-rw-r--r--gas/write.c82
-rw-r--r--gas/write.h4
6 files changed, 107 insertions, 34 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 71c790f52b..10403a532c 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -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.
diff --git a/gas/dwarf2dbg.c b/gas/dwarf2dbg.c
index bc37e7e0eb..87075423a7 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 e4cb0509db..df259b8fe5 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 b983ddbb46..913686cd8c 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 b94c05eed7..ea4b0820f3 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 5bab7a2121..451215d7e8 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));