[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