aboutsummaryrefslogtreecommitdiff
path: root/gas/symbols.c
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2005-10-11 11:16:17 +0000
committerNick Clifton <nickc@redhat.com>2005-10-11 11:16:17 +0000
commit9497f5ac6bc10bdd65ea471787619bde1edca77d (patch)
tree7f36b3cb6f0d84b058dfba51242bd900edde9503 /gas/symbols.c
parent1334d4d50c52bc295dace4982442369838f478b3 (diff)
downloadfsf-binutils-gdb-9497f5ac6bc10bdd65ea471787619bde1edca77d.zip
fsf-binutils-gdb-9497f5ac6bc10bdd65ea471787619bde1edca77d.tar.gz
fsf-binutils-gdb-9497f5ac6bc10bdd65ea471787619bde1edca77d.tar.bz2
This adjusts equate handling by
- allowing true forward references (which will always assume the referenced symbols have at the point of use) through the new .eqv pseudo-op and the new == operator - disallowing changing .equiv-generated equates (so that the protection this provides is both forward and backward) - snapshotting equates when their value gets changed so that previous uses don't get affected by the new value. - allowing expressions in places where absolute expressions (or register names) are needed which were not completely resolvable at the point of their definition but which are fully resolvable at the point of use In addition it fixes PR/288.
Diffstat (limited to 'gas/symbols.c')
-rw-r--r--gas/symbols.c185
1 files changed, 185 insertions, 0 deletions
diff --git a/gas/symbols.c b/gas/symbols.c
index 49d546d..78ec954 100644
--- a/gas/symbols.c
+++ b/gas/symbols.c
@@ -538,6 +538,94 @@ symbol_make (const char *name)
}
symbolS *
+symbol_clone (symbolS *orgsymP, int replace)
+{
+ symbolS *newsymP;
+
+ /* Running local_symbol_convert on a clone that's not the one currently
+ in local_hash would incorrectly replace the hash entry. Thus the
+ symbol must be converted here. Note that the rest of the function
+ depends on not encountering an unconverted symbol. */
+ if (LOCAL_SYMBOL_CHECK (orgsymP))
+ orgsymP = local_symbol_convert ((struct local_symbol *) orgsymP);
+
+ know (S_IS_DEFINED (orgsymP));
+
+ newsymP = obstack_alloc (&notes, sizeof (*newsymP));
+ *newsymP = *orgsymP;
+
+ if (replace)
+ {
+ if (symbol_rootP == orgsymP)
+ symbol_rootP = newsymP;
+ else if (orgsymP->sy_previous)
+ {
+ orgsymP->sy_previous->sy_next = newsymP;
+ orgsymP->sy_previous = NULL;
+ }
+ if (symbol_lastP == orgsymP)
+ symbol_lastP = newsymP;
+ else if (orgsymP->sy_next)
+ orgsymP->sy_next->sy_previous = newsymP;
+ orgsymP->sy_next = NULL;
+ debug_verify_symchain (symbol_rootP, symbol_lastP);
+
+ symbol_table_insert (newsymP);
+ }
+
+ return newsymP;
+}
+
+/* Referenced symbols, if they are forward references, need to be cloned
+ (without replacing the original) so that the value of the referenced
+ symbols at the point of use . */
+
+#undef symbol_clone_if_forward_ref
+symbolS *
+symbol_clone_if_forward_ref (symbolS *symbolP, int is_forward)
+{
+ if (symbolP && !LOCAL_SYMBOL_CHECK (symbolP))
+ {
+ symbolS *add_symbol = symbolP->sy_value.X_add_symbol;
+ symbolS *op_symbol = symbolP->sy_value.X_op_symbol;
+
+ if (symbolP->sy_forward_ref)
+ is_forward = 1;
+
+ if (is_forward)
+ {
+ /* assign_symbol() clones volatile symbols; pre-existing expressions
+ hold references to the original instance, but want the current
+ value. Just repeat the lookup. */
+ if (add_symbol && S_IS_VOLATILE (add_symbol))
+ add_symbol = symbol_find_exact (S_GET_NAME (add_symbol));
+ if (op_symbol && S_IS_VOLATILE (op_symbol))
+ op_symbol = symbol_find_exact (S_GET_NAME (op_symbol));
+ }
+
+ /* Re-using sy_resolving here, as this routine cannot get called from
+ symbol resolution code. */
+ if (symbolP->bsym->section == expr_section && !symbolP->sy_resolving)
+ {
+ symbolP->sy_resolving = 1;
+ add_symbol = symbol_clone_if_forward_ref (add_symbol, is_forward);
+ op_symbol = symbol_clone_if_forward_ref (op_symbol, is_forward);
+ symbolP->sy_resolving = 0;
+ }
+
+ if (symbolP->sy_forward_ref
+ || add_symbol != symbolP->sy_value.X_add_symbol
+ || op_symbol != symbolP->sy_value.X_op_symbol)
+ symbolP = symbol_clone (symbolP, 0);
+
+ symbolP->sy_value.X_add_symbol = add_symbol;
+ symbolP->sy_value.X_op_symbol = op_symbol;
+ }
+
+ return symbolP;
+}
+
+symbolS *
symbol_temp_new (segT seg, valueT ofs, fragS *frag)
{
return symbol_new (FAKE_LABEL_NAME, seg, ofs, frag);
@@ -1189,6 +1277,71 @@ resolve_local_symbol_values (void)
hash_traverse (local_hash, resolve_local_symbol);
}
+/* Obtain the current value of a symbol without changing any
+ sub-expressions used. */
+
+int
+snapshot_symbol (symbolS *symbolP, valueT *valueP, segT *segP, fragS **fragPP)
+{
+ if (LOCAL_SYMBOL_CHECK (symbolP))
+ {
+ struct local_symbol *locsym = (struct local_symbol *) symbolP;
+
+ *valueP = locsym->lsy_value;
+ *segP = locsym->lsy_section;
+ *fragPP = local_symbol_get_frag (locsym);
+ }
+ else
+ {
+ expressionS expr = symbolP->sy_value;
+
+ if (!symbolP->sy_resolved && expr.X_op != O_illegal)
+ {
+ int resolved;
+
+ if (symbolP->sy_resolving)
+ return 0;
+ symbolP->sy_resolving = 1;
+ resolved = resolve_expression (&expr);
+ symbolP->sy_resolving = 0;
+ if (!resolved)
+ return 0;
+
+ switch (expr.X_op)
+ {
+ case O_constant:
+ case O_register:
+ /* This check wouldn't be needed if pseudo_set() didn't set
+ symbols equated to bare symbols to undefined_section. */
+ if (symbolP->bsym->section != undefined_section
+ || symbolP->sy_value.X_op != O_symbol)
+ break;
+ /* Fall thru. */
+ case O_symbol:
+ case O_symbol_rva:
+ symbolP = expr.X_add_symbol;
+ break;
+ default:
+ return 0;
+ }
+ }
+
+ *valueP = expr.X_add_number;
+ *segP = symbolP->bsym->section;
+ *fragPP = symbolP->sy_frag;
+
+ if (*segP == expr_section)
+ switch (expr.X_op)
+ {
+ case O_constant: *segP = absolute_section; break;
+ case O_register: *segP = reg_section; break;
+ default: break;
+ }
+ }
+
+ return 1;
+}
+
/* Dollar labels look like a number followed by a dollar sign. Eg, "42$".
They are *really* local. That is, they go out of scope whenever we see a
label that isn't local. Also, like fb labels, there can be multiple
@@ -1747,6 +1900,22 @@ S_IS_STABD (symbolS *s)
return S_GET_NAME (s) == 0;
}
+int
+S_IS_VOLATILE (const symbolS *s)
+{
+ if (LOCAL_SYMBOL_CHECK (s))
+ return 0;
+ return s->sy_volatile;
+}
+
+int
+S_IS_FORWARD_REF (const symbolS *s)
+{
+ if (LOCAL_SYMBOL_CHECK (s))
+ return 0;
+ return s->sy_forward_ref;
+}
+
const char *
S_GET_NAME (symbolS *s)
{
@@ -1872,6 +2041,22 @@ S_SET_NAME (symbolS *s, const char *name)
s->bsym->name = name;
}
+void
+S_SET_VOLATILE (symbolS *s)
+{
+ if (LOCAL_SYMBOL_CHECK (s))
+ s = local_symbol_convert ((struct local_symbol *) s);
+ s->sy_volatile = 1;
+}
+
+void
+S_SET_FORWARD_REF (symbolS *s)
+{
+ if (LOCAL_SYMBOL_CHECK (s))
+ s = local_symbol_convert ((struct local_symbol *) s);
+ s->sy_forward_ref = 1;
+}
+
/* Return the previous symbol in a chain. */
symbolS *