[PATCH 2.5/4 v2] GAS: Make new fake labels when cloning a symbol
Maciej W. Rozycki
macro@codesourcery.com
Fri Oct 29 14:38:00 GMT 2010
Hi,
Equated symbols (defined with .eqv) aka forward references are defined to
reevaluate the expression they are defined to whenever they are referred
to. This does not happen for the special "dot" symbol -- the value
calculated the first time the equated symbol has been used is then used
over and over again.
The reason is each time a reference to the "dot" symbol is made a special
fake label is created. This label is then recorded in the chain of
symbols the equated symbol is defined to and never reevaluated. The
solution is to create a new fake label each time the equated symbol is
used.
Overall with symbol definitions like this:
.data
.eqv fnord, .
.eqv foobar, fnord + 4
.eqv foobaz, foobar - 16
.word 0
.word fnord
.word fnord
.word foobaz
.word foobaz
the "dot" symbol would only be calculated once, with the second .word
directive, i.e. both the second and the third word emitted would have the
same value (address of the second word).
This would also cause "foobaz" to be calculated (as a forward reference)
with the third .eqv directive and then cloned each time when used with
.word. Howeved "foobar" would only be calculated with the second and the
third .eqv directive, but not with the .word directives, thus fixed at
the value of the first rather than each use.
In the end data emitted would be:
0, 0, 0, -12, -12
as if .set was used, rather than:
0, 4, 8, 0, 4
as expected.
To address the concerns you had with version 1.5 of this change:
> The first patch looks generally good otherwise, so hopefully any
> changes are just a mopping-up exercise. I'm still uneasy about the
> second patch though. Can you justify why the new test for "." is safe?
>
> An alternative might be to model "." as a single forward-reference
> symbol whose value is redefined before each instruction. I think
> that's what its semantics actually are. There would then be a
> single global symbol that represents ".", and that is marked as a
> forward reference. symbol_clone_if_forward_ref would return
> symbol_temp_new_now for that symbol, rather than go through
> the usual cloning process.
That sounded like a brilliant idea to me, so I have implemented it. I
have created a special dot_symbol tracking symbol for this purpose. It
has to be an external symbol so that GAS doesn't attempt to turn it
into the so called converted symbol, so it has to be initialised pretty
late in the game, when output BFD has already been opened, making
symbol_begin() an unsuitable place to do that. I have thus created
dot_symbol_init() to do all the necessary bits and even gave it the name
of "." that might surprise everyone. The name should never be reached
though, because "." is trapped as a special case throughout GAS.
Of all the other changes I think only bits in read_a_source_file()
require further explanation. As I discovered there are places in GAS that
refer to a symbol's segment early on, long before it is resolved, for the
purpose of validation relative expressions (generally address
subtraction). Rather than just setting the segment only I reused the
existing symbol_set_value_now() helper that completely updates the symbol,
making dot_symbol truly track the current location.
A nice effect of this arrangement (or actually the second statement of
this form that immediately follows the parser loop, unless .end has been
used) is that at the end of assembly dot_symbol points to just at the end
of generated output. As all equated symbols are actually recorded in the
generated object's symbol table just as ordinary ones, their values are
calculated according to the expression they have been equated to at the
final symbol resolution stage. For symbols that have been equated to an
expression involving the special dot symbol this means the final recorded
value will be based on the final value of the location counter -- just as
you'd expect by the semantics of the equation operation. :)
Where applicable I have placed the relevant calls before calls to target
hooks so that they are presented with a consistent world.
2010-10-29 Maciej W. Rozycki <macro@codesourcery.com>
gas/
* symbols.h (dot_symbol): New declaration.
(dot_symbol_init): New prototype.
* symbols.c (dot_symbol): New variable.
(dot_symbol_init): New function.
(symbol_clone_if_forward_ref): Create a new temporary symbol
when trying to clone dot_symbol.
* expr.c (current_location): Refer to dot_symbol instead of
making a new temporary symbol.
* read.c (read_a_source_file): Update dot_symbol as we go.
* as.c (main): Call dot_symbol_init.
OK to apply?
Maciej
binutils-gas-dot.diff
Index: binutils-fsf-trunk-quilt/gas/symbols.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/gas/symbols.c 2010-10-29 09:07:10.000000000 +0100
+++ binutils-fsf-trunk-quilt/gas/symbols.c 2010-10-29 09:07:10.000000000 +0100
@@ -48,6 +48,7 @@ static struct hash_control *local_hash;
symbolS *symbol_rootP;
symbolS *symbol_lastP;
symbolS abs_symbol;
+symbolS dot_symbol;
#ifdef DEBUG_SYMS
#define debug_verify_symchain verify_symbol_chain
@@ -658,8 +659,13 @@ symbol_clone_if_forward_ref (symbolS *sy
|| add_symbol != symbolP->sy_value.X_add_symbol
|| op_symbol != symbolP->sy_value.X_op_symbol)
{
- symbolP = symbol_clone (symbolP, 0);
- symbolP->sy_resolving = 0;
+ if (symbolP != &dot_symbol)
+ {
+ symbolP = symbol_clone (symbolP, 0);
+ symbolP->sy_resolving = 0;
+ }
+ else
+ symbolP = symbol_temp_new_now ();
}
symbolP->sy_value.X_add_symbol = add_symbol;
@@ -2749,6 +2755,17 @@ symbol_begin (void)
if (LOCAL_LABELS_FB)
fb_label_init ();
}
+
+void
+dot_symbol_init (void)
+{
+ dot_symbol.bsym = bfd_make_empty_symbol (stdoutput);
+ if (dot_symbol.bsym == NULL)
+ as_fatal ("bfd_make_empty_symbol: %s", bfd_errmsg (bfd_get_error ()));
+ S_SET_NAME (&dot_symbol, ".");
+ S_SET_FORWARD_REF (&dot_symbol);
+ dot_symbol.sy_value.X_op = O_constant;
+}
int indent_level;
Index: binutils-fsf-trunk-quilt/gas/expr.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/gas/expr.c 2010-10-29 09:07:10.000000000 +0100
+++ binutils-fsf-trunk-quilt/gas/expr.c 2010-10-29 09:07:10.000000000 +0100
@@ -705,7 +705,7 @@ current_location (expressionS *expressio
else
{
expressionp->X_op = O_symbol;
- expressionp->X_add_symbol = symbol_temp_new_now ();
+ expressionp->X_add_symbol = &dot_symbol;
expressionp->X_add_number = 0;
}
}
Index: binutils-fsf-trunk-quilt/gas/symbols.h
===================================================================
--- binutils-fsf-trunk-quilt.orig/gas/symbols.h 2010-10-29 09:07:06.000000000 +0100
+++ binutils-fsf-trunk-quilt/gas/symbols.h 2010-10-29 09:07:10.000000000 +0100
@@ -28,6 +28,7 @@ extern symbolS *symbol_rootP; /* all the
extern symbolS *symbol_lastP; /* last struct symbol we made, or NULL */
extern symbolS abs_symbol;
+extern symbolS dot_symbol;
extern int symbol_table_frozen;
@@ -60,6 +61,7 @@ symbolS *symbol_temp_make (void);
symbolS *colon (const char *sym_name);
void local_colon (int n);
void symbol_begin (void);
+void dot_symbol_init (void);
void symbol_print_statistics (FILE *);
void symbol_table_insert (symbolS * symbolP);
valueT resolve_symbol_value (symbolS *);
Index: binutils-fsf-trunk-quilt/gas/read.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/gas/read.c 2010-10-29 09:07:06.000000000 +0100
+++ binutils-fsf-trunk-quilt/gas/read.c 2010-10-29 09:07:10.000000000 +0100
@@ -629,6 +629,7 @@ read_a_source_file (char *name)
was_new_line = is_end_of_line[(unsigned char) input_line_pointer[-1]];
if (was_new_line)
{
+ symbol_set_value_now (&dot_symbol);
#ifdef md_start_line_hook
md_start_line_hook ();
#endif
@@ -1128,6 +1129,7 @@ read_a_source_file (char *name)
md_after_pass_hook ();
#endif
}
+ symbol_set_value_now (&dot_symbol);
quit:
Index: binutils-fsf-trunk-quilt/gas/as.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/gas/as.c 2010-10-29 09:07:06.000000000 +0100
+++ binutils-fsf-trunk-quilt/gas/as.c 2010-10-29 09:07:10.000000000 +0100
@@ -1181,6 +1181,8 @@ main (int argc, char ** argv)
output_file_create (out_file_name);
gas_assert (stdoutput != 0);
+ dot_symbol_init ();
+
#ifdef tc_init_after_args
tc_init_after_args ();
#endif
More information about the Binutils
mailing list