aboutsummaryrefslogtreecommitdiff
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
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.
-rw-r--r--gas/ChangeLog62
-rw-r--r--gas/as.c2
-rw-r--r--gas/cond.c4
-rw-r--r--gas/config/tc-arc.c2
-rw-r--r--gas/config/tc-ia64.h2
-rw-r--r--gas/config/tc-m32r.c9
-rw-r--r--gas/config/tc-m32r.h6
-rw-r--r--gas/config/tc-mips.c3
-rw-r--r--gas/config/tc-mmix.h2
-rw-r--r--gas/config/tc-mn10300.c7
-rw-r--r--gas/config/tc-mn10300.h7
-rw-r--r--gas/config/tc-ppc.h2
-rw-r--r--gas/config/tc-sh.c9
-rw-r--r--gas/config/tc-sh.h7
-rw-r--r--gas/config/tc-sh64.c9
-rw-r--r--gas/config/tc-sh64.h9
-rw-r--r--gas/config/tc-tic54x.h2
-rw-r--r--gas/doc/as.texinfo14
-rw-r--r--gas/dw2gencfi.c2
-rw-r--r--gas/expr.c222
-rw-r--r--gas/expr.h15
-rw-r--r--gas/read.c66
-rw-r--r--gas/struc-symbol.h6
-rw-r--r--gas/symbols.c185
-rw-r--r--gas/symbols.h9
-rw-r--r--gas/testsuite/ChangeLog19
-rw-r--r--gas/testsuite/gas/all/assign-bad.s2
-rw-r--r--gas/testsuite/gas/all/assign-ok.s3
-rw-r--r--gas/testsuite/gas/all/cond.l (renamed from gas/testsuite/gas/all/cond.d)6
-rw-r--r--gas/testsuite/gas/all/cond.s8
-rw-r--r--gas/testsuite/gas/all/equ-bad.s2
-rw-r--r--gas/testsuite/gas/all/equ-ok.s2
-rw-r--r--gas/testsuite/gas/all/equiv1.s5
-rw-r--r--gas/testsuite/gas/all/equiv2.s6
-rw-r--r--gas/testsuite/gas/all/eqv-bad.s2
-rw-r--r--gas/testsuite/gas/all/eqv-ok.s1
-rw-r--r--gas/testsuite/gas/all/eval.d8
-rw-r--r--gas/testsuite/gas/all/eval.s48
-rw-r--r--gas/testsuite/gas/all/forward.d8
-rw-r--r--gas/testsuite/gas/all/forward.s44
-rw-r--r--gas/testsuite/gas/all/gas.exp54
-rw-r--r--gas/testsuite/gas/all/redef.d8
-rw-r--r--gas/testsuite/gas/all/redef.s11
43 files changed, 834 insertions, 66 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 64dd155..16d67b5 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,65 @@
+2005-10-11 Jan Beulich <jbeulich@novell.com>
+
+ * expr.h (enum expr_mode): New.
+ (expression): Pass thrid argument to expr.
+ (expression_and_evaluate): New.
+ (deferred_expression): New.
+ (expr): Add third parameter.
+ (resolve_expression): New.
+ * struc-symbol.h (struct symbol): New members sy_volatile and
+ sy_forward_ref.
+ * symbols.c, symbols.h (symbol_clone): New.
+ (symbol_clone_if_forward_ref): New.
+ (snapshot_symbol): New.
+ (S_IS_VOLATILE): New.
+ (S_IS_FORWARD_REF): New.
+ (S_SET_VOLATILE): New.
+ (S_SET_FORWARD_REF): New.
+ * as.c (macro_expr): Use expression_and_evaluate.
+ * cond.c (s_if): Likewise.
+ (s_elseif): Likewise.
+ * dw2gencfi.c (cfi_parse_reg): Likewise.
+ * expr.c (operand): Add second parameter. Optionally call
+ deferred_expression. Pass mode argument to itself and md_parse_name.
+ Check mode before trying to evaluate symbol. Call
+ symbol_clone_if_forward_ref for both operands.
+ (expr): Add thrid parameter. Pass mode to operand and itself.
+ Optionally call resolve_expression.
+ (resolve_expression): New.
+ (get_single_number): Pass second argument to operand.
+ * read.c (potable): New entry for .eqv.
+ (read_a_source_file): Handle new == operator.
+ (get_absolute_expr): Use expression_and_evaluate.
+ (s_lsym): Likewise.
+ (assign_symbol): Rename second parameter. Call symbol_clone on
+ legal and illegal redefinition. Call S_SET_VOLATILE and
+ S_SET_FORWARD_REF depending on mode.
+ (s_set): Update description.
+ (s_space): Call resolve_expression.
+ (pseudo_set): Optionally call deferred_expression. Check
+ S_IS_FORWARD_REF before trying to simplify/resolve an expression.
+ (equals): Handle ==.
+ * config/tc-ia64.h (md_parse_name): Add mode parameter.
+ * config/tc-arc.c (arc_parse_cons_expression): Likewise.
+ * config/tc-m32r.h (md_parse_name): Likewise.
+ (m32r_parse_name): Likewise.
+ * config/tc-mmix.h (md_parse_name): Likewise.
+ * config/tc-mn10300.h (md_parse_name): Likewise.
+ (mn10300_parse_name): Likewise.
+ * config/tc-ppc.h (md_parse_name): Likewise.
+ * config/tc-sh.h (md_parse_name): Likewise.
+ (sh_parse_name): Likewise.
+ * config/tc-sh64.h (md_parse_name): Likewise.
+ (sh64_consume_datalabel): Likewise.
+ * config/tc-tic54x.h (md_parse_name): Likewise.
+ * config/tc-m32r.c (m32r_parse_name): Add mode parameter. Check it
+ before trying to evaluate symbol.
+ * config/tc-mn10300.c (mn10300_parse_name): Likewise.
+ * config/tc-sh.c (sh_parse_name): Likewise.
+ * config/tc-sh64.c (sh64_consume_datalabel): Add mode parameter. Pass
+ second argument to operandf. Pass mode parameter to sh_parse_name.
+ * doc/as.texinfo: Document .eqv and the == assignment operator.
+
2005-10-10 Ian Lance Taylor <ian@airs.com>
* Makefile.am (EXTRA_DIST): Remove bfin-lex.l and bfin-defs.h.
diff --git a/gas/as.c b/gas/as.c
index 07f7692..10e20e3 100644
--- a/gas/as.c
+++ b/gas/as.c
@@ -940,7 +940,7 @@ macro_expr (const char *emsg, int idx, sb *in, int *val)
hold = input_line_pointer;
input_line_pointer = in->ptr + idx;
- expression (&ex);
+ expression_and_evaluate (&ex);
idx = input_line_pointer - in->ptr;
input_line_pointer = hold;
diff --git a/gas/cond.c b/gas/cond.c
index 8cd98c2..e791b11 100644
--- a/gas/cond.c
+++ b/gas/cond.c
@@ -144,7 +144,7 @@ s_if (int arg)
}
else
{
- expression (&operand);
+ expression_and_evaluate (&operand);
if (operand.X_op != O_constant)
as_bad (_("non-constant expression in \".if\" statement"));
}
@@ -340,7 +340,7 @@ s_elseif (int arg)
/* Leading whitespace is part of operand. */
SKIP_WHITESPACE ();
- expression (&operand);
+ expression_and_evaluate (&operand);
if (operand.X_op != O_constant)
as_bad (_("non-constant expression in \".elseif\" statement"));
diff --git a/gas/config/tc-arc.c b/gas/config/tc-arc.c
index 0dd0ac7..b33256f 100644
--- a/gas/config/tc-arc.c
+++ b/gas/config/tc-arc.c
@@ -1214,7 +1214,7 @@ arc_parse_cons_expression (expressionS *exp,
code_symbol_fix = 1;
strcpy (p, "; ");
}
- expr (0, exp);
+ expression_and_evaluate (exp);
if (code_symbol_fix)
{
arc_code_symbol (exp);
diff --git a/gas/config/tc-ia64.h b/gas/config/tc-ia64.h
index f322fbf..c17494b 100644
--- a/gas/config/tc-ia64.h
+++ b/gas/config/tc-ia64.h
@@ -129,7 +129,7 @@ extern void ia64_convert_frag (fragS *);
#define tc_frob_symbol(s,p) p |= ia64_frob_symbol (s)
#endif /* TE_HPUX */
#define md_flush_pending_output() ia64_flush_pending_output ()
-#define md_parse_name(s,e,c) ia64_parse_name (s, e, c)
+#define md_parse_name(s,e,m,c) ia64_parse_name (s, e, c)
#define tc_canonicalize_symbol_name(s) ia64_canonicalize_symbol_name (s)
#define tc_canonicalize_section_name(s) ia64_canonicalize_symbol_name (s)
#define md_optimize_expr(l,o,r) ia64_optimize_expr (l, o, r)
diff --git a/gas/config/tc-m32r.c b/gas/config/tc-m32r.c
index 54452c5..51b160a 100644
--- a/gas/config/tc-m32r.c
+++ b/gas/config/tc-m32r.c
@@ -2370,7 +2370,10 @@ m32r_end_of_match (char *cont, char *what)
}
int
-m32r_parse_name (char const *name, expressionS *exprP, char *nextcharP)
+m32r_parse_name (char const *name,
+ expressionS *exprP,
+ enum expr_mode mode,
+ char *nextcharP)
{
char *next = input_line_pointer;
char *next_end;
@@ -2391,13 +2394,13 @@ m32r_parse_name (char const *name, expressionS *exprP, char *nextcharP)
/* If we have an absolute symbol or a
reg, then we know its value now. */
segment = S_GET_SEGMENT (exprP->X_add_symbol);
- if (segment == absolute_section)
+ if (mode != expr_defer && segment == absolute_section)
{
exprP->X_op = O_constant;
exprP->X_add_number = S_GET_VALUE (exprP->X_add_symbol);
exprP->X_add_symbol = NULL;
}
- else if (segment == reg_section)
+ else if (mode != expr_defer && segment == reg_section)
{
exprP->X_op = O_register;
exprP->X_add_number = S_GET_VALUE (exprP->X_add_symbol);
diff --git a/gas/config/tc-m32r.h b/gas/config/tc-m32r.h
index eb03495..69fe945 100644
--- a/gas/config/tc-m32r.h
+++ b/gas/config/tc-m32r.h
@@ -121,9 +121,9 @@ extern void m32r_flush_pending_output (void);
#define elf_tc_final_processing m32r_elf_final_processing
extern void m32r_elf_final_processing (void);
-#define md_parse_name(name, exprP, nextcharP) \
- m32r_parse_name ((name), (exprP), (nextcharP))
-extern int m32r_parse_name (char const *, expressionS *, char *);
+#define md_parse_name(name, exprP, mode, nextcharP) \
+ m32r_parse_name ((name), (exprP), (mode), (nextcharP))
+extern int m32r_parse_name (char const *, expressionS *, enum expr_mode, char *);
/* This is used to construct expressions out of @GOTOFF, @PLT and @GOT
symbols. The relocation type is stored in X_md. */
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index 2ce3415..6e06105 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -2312,7 +2312,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr,
else if (mips_opts.mips16
&& ! ip->use_extend
&& *reloc_type != BFD_RELOC_MIPS16_JMP)
- {
+ {
if ((pinfo & INSN_UNCOND_BRANCH_DELAY) == 0)
/* Make sure there is enough room to swap this instruction with
a following jump instruction. */
@@ -8547,7 +8547,6 @@ do_msbd:
s_reset = s;
if (s[0] == '$')
{
-
if (ISDIGIT (s[1]))
{
++s;
diff --git a/gas/config/tc-mmix.h b/gas/config/tc-mmix.h
index f755995..61bc881 100644
--- a/gas/config/tc-mmix.h
+++ b/gas/config/tc-mmix.h
@@ -70,7 +70,7 @@ extern char *mmix_current_prefix;
The [DVWIOUZX]_Handler symbols are provided when-used. */
extern int mmix_gnu_syntax;
-#define md_parse_name(name, exp, cpos) \
+#define md_parse_name(name, exp, mode, cpos) \
(! mmix_gnu_syntax \
&& (name[0] == '@' \
? (! is_part_of_name (name[1]) \
diff --git a/gas/config/tc-mn10300.c b/gas/config/tc-mn10300.c
index 8849d1c..963b1b6 100644
--- a/gas/config/tc-mn10300.c
+++ b/gas/config/tc-mn10300.c
@@ -2743,9 +2743,10 @@ mn10300_end_of_match (cont, what)
}
int
-mn10300_parse_name (name, exprP, nextcharP)
+mn10300_parse_name (name, exprP, mode, nextcharP)
char const *name;
expressionS *exprP;
+ enum expr_mode mode;
char *nextcharP;
{
char *next = input_line_pointer;
@@ -2765,13 +2766,13 @@ mn10300_parse_name (name, exprP, nextcharP)
/* If we have an absolute symbol or a reg,
then we know its value now. */
segment = S_GET_SEGMENT (exprP->X_add_symbol);
- if (segment == absolute_section)
+ if (mode != expr_defer && segment == absolute_section)
{
exprP->X_op = O_constant;
exprP->X_add_number = S_GET_VALUE (exprP->X_add_symbol);
exprP->X_add_symbol = NULL;
}
- else if (segment == reg_section)
+ else if (mode != expr_defer && segment == reg_section)
{
exprP->X_op = O_register;
exprP->X_add_number = S_GET_VALUE (exprP->X_add_symbol);
diff --git a/gas/config/tc-mn10300.h b/gas/config/tc-mn10300.h
index ad41df4..dff663d 100644
--- a/gas/config/tc-mn10300.h
+++ b/gas/config/tc-mn10300.h
@@ -36,9 +36,10 @@
&& S_IS_DEFINED ((FIX)->fx_addsy) \
&& ! S_IS_COMMON ((FIX)->fx_addsy))))
-#define md_parse_name(name, exprP, nextcharP) \
- mn10300_parse_name ((name), (exprP), (nextcharP))
-int mn10300_parse_name PARAMS ((char const *, expressionS *, char *));
+#define md_parse_name(name, exprP, mode, nextcharP) \
+ mn10300_parse_name ((name), (exprP), (mode), (nextcharP))
+int mn10300_parse_name PARAMS ((char const *, expressionS *,
+ enum expr_mode, char *));
#define TC_CONS_FIX_NEW(FRAG, OFF, LEN, EXP) \
mn10300_cons_fix_new ((FRAG), (OFF), (LEN), (EXP))
diff --git a/gas/config/tc-ppc.h b/gas/config/tc-ppc.h
index 7b6126a..f7c2da6 100644
--- a/gas/config/tc-ppc.h
+++ b/gas/config/tc-ppc.h
@@ -245,7 +245,7 @@ extern int ppc_force_relocation PARAMS ((struct fix *));
#define MD_PCREL_FROM_SECTION(FIX, SEC) md_pcrel_from_section(FIX, SEC)
extern long md_pcrel_from_section PARAMS ((struct fix *, segT));
-#define md_parse_name(name, exp, c) ppc_parse_name (name, exp)
+#define md_parse_name(name, exp, mode, c) ppc_parse_name (name, exp)
extern int ppc_parse_name PARAMS ((const char *, struct expressionS *));
#define md_operand(x)
diff --git a/gas/config/tc-sh.c b/gas/config/tc-sh.c
index 0b294e0..acf62ae 100644
--- a/gas/config/tc-sh.c
+++ b/gas/config/tc-sh.c
@@ -4295,7 +4295,10 @@ sh_end_of_match (char *cont, char *what)
}
int
-sh_parse_name (char const *name, expressionS *exprP, char *nextcharP)
+sh_parse_name (char const *name,
+ expressionS *exprP,
+ enum expr_mode mode,
+ char *nextcharP)
{
char *next = input_line_pointer;
char *next_end;
@@ -4314,13 +4317,13 @@ sh_parse_name (char const *name, expressionS *exprP, char *nextcharP)
/* If we have an absolute symbol or a reg, then we know its
value now. */
segment = S_GET_SEGMENT (exprP->X_add_symbol);
- if (segment == absolute_section)
+ if (mode != expr_defer && segment == absolute_section)
{
exprP->X_op = O_constant;
exprP->X_add_number = S_GET_VALUE (exprP->X_add_symbol);
exprP->X_add_symbol = NULL;
}
- else if (segment == reg_section)
+ else if (mode != expr_defer && segment == reg_section)
{
exprP->X_op = O_register;
exprP->X_add_number = S_GET_VALUE (exprP->X_add_symbol);
diff --git a/gas/config/tc-sh.h b/gas/config/tc-sh.h
index 69b82b2..a812036 100644
--- a/gas/config/tc-sh.h
+++ b/gas/config/tc-sh.h
@@ -206,9 +206,10 @@ extern bfd_boolean sh_fix_adjustable (struct fix *);
((FIX)->fx_r_type == BFD_RELOC_32_PLT_PCREL \
|| (sh_relax && SWITCH_TABLE (FIX)))
-#define md_parse_name(name, exprP, nextcharP) \
- sh_parse_name ((name), (exprP), (nextcharP))
-int sh_parse_name (char const *name, expressionS *exprP, char *nextchar);
+#define md_parse_name(name, exprP, mode, nextcharP) \
+ sh_parse_name ((name), (exprP), (mode), (nextcharP))
+int sh_parse_name (char const *name, expressionS *exprP,
+ enum expr_mode mode, char *nextchar);
#define TC_CONS_FIX_NEW(FRAG, OFF, LEN, EXP) \
sh_cons_fix_new ((FRAG), (OFF), (LEN), (EXP))
diff --git a/gas/config/tc-sh64.c b/gas/config/tc-sh64.c
index 7964579..7433061 100644
--- a/gas/config/tc-sh64.c
+++ b/gas/config/tc-sh64.c
@@ -3244,8 +3244,9 @@ sh64_frob_label (symbolS *symp)
symbol hook. */
int
-sh64_consume_datalabel (const char *name, expressionS *exp, char *cp,
- segT (*operandf) (expressionS *))
+sh64_consume_datalabel (const char *name, expressionS *exp,
+ enum expr_mode mode, char *cp,
+ segT (*operandf) (expressionS *, enum expr_mode))
{
static int parsing_datalabel = 0;
@@ -3258,7 +3259,7 @@ sh64_consume_datalabel (const char *name, expressionS *exp, char *cp,
*input_line_pointer = *cp;
parsing_datalabel = 1;
- (*operandf) (exp);
+ (*operandf) (exp, expr_normal);
parsing_datalabel = save_parsing_datalabel;
if (exp->X_op == O_symbol || exp->X_op == O_PIC_reloc)
@@ -3331,7 +3332,7 @@ sh64_consume_datalabel (const char *name, expressionS *exp, char *cp,
return 1;
}
- return sh_parse_name (name, exp, cp);
+ return sh_parse_name (name, exp, mode, cp);
}
/* This function is called just before symbols are being output. It
diff --git a/gas/config/tc-sh64.h b/gas/config/tc-sh64.h
index 8af9b95..21f5d59 100644
--- a/gas/config/tc-sh64.h
+++ b/gas/config/tc-sh64.h
@@ -124,10 +124,11 @@ extern int sh64_target_mach (void);
expression, since we have handled it ourselves. FIXME: What we really
need is a new GAS infrastructure feature: md_qualifier. */
#undef md_parse_name
-#define md_parse_name(NAME, EXP, CP) \
- sh64_consume_datalabel (NAME, EXP, CP, operand)
-extern int sh64_consume_datalabel (const char *, expressionS *, char *,
- segT (*) (expressionS *));
+#define md_parse_name(NAME, EXP, MODE, CP) \
+ sh64_consume_datalabel (NAME, EXP, MODE, CP, operand)
+extern int sh64_consume_datalabel (const char *, expressionS *,
+ enum expr_mode, char *,
+ segT (*) (expressionS *, enum expr_mode));
/* Saying "$" is the same as saying ".". */
#define DOLLAR_DOT
diff --git a/gas/config/tc-tic54x.h b/gas/config/tc-tic54x.h
index 4d9b2c8..7476500 100644
--- a/gas/config/tc-tic54x.h
+++ b/gas/config/tc-tic54x.h
@@ -83,7 +83,7 @@ extern void tic54x_number_to_chars (char *, valueT, int);
extern void tic54x_adjust_symtab (void);
#define tc_unrecognized_line(ch) tic54x_unrecognized_line(ch)
extern int tic54x_unrecognized_line (int ch);
-#define md_parse_name(s,e,c) tic54x_parse_name(s,e)
+#define md_parse_name(s,e,m,c) tic54x_parse_name(s,e)
extern int tic54x_parse_name (char *name, expressionS *e);
#define md_undefined_symbol(s) tic54x_undefined_symbol(s)
extern symbolS *tic54x_undefined_symbol (char *name);
diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo
index 1d9ae0c..2b3e4c2 100644
--- a/gas/doc/as.texinfo
+++ b/gas/doc/as.texinfo
@@ -3119,7 +3119,9 @@ provides a special directive @code{.label} for defining labels more flexibly.
A symbol can be given an arbitrary value by writing a symbol, followed
by an equals sign @samp{=}, followed by an expression
(@pxref{Expressions}). This is equivalent to using the @code{.set}
-directive. @xref{Set,,@code{.set}}.
+directive. @xref{Set,,@code{.set}}. In the same way, using a double
+equals sign @samp{=}@samp{=} here represents an equivalent of the
+@code{.eqv} directive. @xref{Eqv,,@code{.eqv}}.
@node Symbol Names
@section Symbol Names
@@ -3716,6 +3718,7 @@ Some machine configurations provide additional directives.
* Endif:: @code{.endif}
* Equ:: @code{.equ @var{symbol}, @var{expression}}
* Equiv:: @code{.equiv @var{symbol}, @var{expression}}
+* Eqv:: @code{.eqv @var{symbol}, @var{expression}}
* Err:: @code{.err}
* Error:: @code{.error @var{string}}
* Exitm:: @code{.exitm}
@@ -4283,6 +4286,15 @@ Except for the contents of the error message, this is roughly equivalent to
.endif
.equ SYM,VAL
@end smallexample
+plus it protects the symbol from later redefinition.
+
+@node Eqv
+@section @code{.eqv @var{symbol}, @var{expression}}
+@cindex @code{eqv} directive
+The @code{.eqv} directive is like @code{.equiv}, but no attempt is made to
+evaluate the expression or any part of it immediately. Instead each time
+the resulting symbol is used in an expression, a snapshot of its current
+value is taken.
@node Err
@section @code{.err}
diff --git a/gas/dw2gencfi.c b/gas/dw2gencfi.c
index 65be298..9601b30 100644
--- a/gas/dw2gencfi.c
+++ b/gas/dw2gencfi.c
@@ -415,7 +415,7 @@ cfi_parse_reg (void)
}
#endif
- expression (&exp);
+ expression_and_evaluate (&exp);
switch (exp.X_op)
{
case O_register:
diff --git a/gas/expr.c b/gas/expr.c
index fff0fde..32de0f7 100644
--- a/gas/expr.c
+++ b/gas/expr.c
@@ -41,7 +41,7 @@ static void integer_constant (int radix, expressionS * expressionP);
static void mri_char_constant (expressionS *);
static void current_location (expressionS *);
static void clean_up_expression (expressionS * expressionP);
-static segT operand (expressionS *);
+static segT operand (expressionS *, enum expr_mode);
static operatorT operator (int *);
extern const char EXP_CHARS[], FLT_CHARS[];
@@ -708,7 +708,7 @@ current_location (expressionS *expressionp)
Input_line_pointer->(next non-blank) char after operand. */
static segT
-operand (expressionS *expressionP)
+operand (expressionS *expressionP, enum expr_mode mode)
{
char c;
symbolS *symbolP; /* Points to symbol. */
@@ -944,7 +944,10 @@ operand (expressionS *expressionP)
case '[':
#endif
/* Didn't begin with digit & not a name. */
- segment = expression (expressionP);
+ if (mode != expr_defer)
+ segment = expression (expressionP);
+ else
+ segment = deferred_expression (expressionP);
/* expression () will pass trailing whitespace. */
if ((c == '(' && *input_line_pointer != ')')
|| (c == '[' && *input_line_pointer != ']'))
@@ -1002,7 +1005,7 @@ operand (expressionS *expressionP)
if (0 && (c == '-' || c == '+') && *input_line_pointer == c)
goto target_op;
- operand (expressionP);
+ operand (expressionP, mode);
if (expressionP->X_op == O_constant)
{
/* input_line_pointer -> char after operand. */
@@ -1214,7 +1217,7 @@ operand (expressionS *expressionP)
specially in certain contexts. If a name always has a
specific value, it can often be handled by simply
entering it in the symbol table. */
- if (md_parse_name (name, expressionP, &c))
+ if (md_parse_name (name, expressionP, mode, &c))
{
*input_line_pointer = c;
break;
@@ -1265,12 +1268,12 @@ operand (expressionS *expressionP)
/* If we have an absolute symbol or a reg, then we know its
value now. */
segment = S_GET_SEGMENT (symbolP);
- if (segment == absolute_section)
+ if (mode != expr_defer && segment == absolute_section)
{
expressionP->X_op = O_constant;
expressionP->X_add_number = S_GET_VALUE (symbolP);
}
- else if (segment == reg_section)
+ else if (mode != expr_defer && segment == reg_section)
{
expressionP->X_op = O_register;
expressionP->X_add_number = S_GET_VALUE (symbolP);
@@ -1314,6 +1317,9 @@ operand (expressionS *expressionP)
if (expressionP->X_add_symbol)
symbol_mark_used (expressionP->X_add_symbol);
+ expressionP->X_add_symbol = symbol_clone_if_forward_ref (expressionP->X_add_symbol);
+ expressionP->X_op_symbol = symbol_clone_if_forward_ref (expressionP->X_op_symbol);
+
switch (expressionP->X_op)
{
default:
@@ -1625,7 +1631,8 @@ operator (int *num_chars)
segT
expr (int rankarg, /* Larger # is higher rank. */
- expressionS *resultP /* Deliver result here. */)
+ expressionS *resultP, /* Deliver result here. */
+ enum expr_mode mode /* Controls behavior. */)
{
operator_rankT rank = (operator_rankT) rankarg;
segT retval;
@@ -1640,7 +1647,7 @@ expr (int rankarg, /* Larger # is higher rank. */
if (rank == 0)
dot_value = frag_now_fix ();
- retval = operand (resultP);
+ retval = operand (resultP, mode);
/* operand () gobbles spaces. */
know (*input_line_pointer != ' ');
@@ -1652,7 +1659,7 @@ expr (int rankarg, /* Larger # is higher rank. */
input_line_pointer += op_chars; /* -> after operator. */
- rightseg = expr (op_rank[(int) op_left], &right);
+ rightseg = expr (op_rank[(int) op_left], &right, mode);
if (right.X_op == O_absent)
{
as_warn (_("missing operand; zero assumed"));
@@ -1867,8 +1874,201 @@ expr (int rankarg, /* Larger # is higher rank. */
if (resultP->X_add_symbol)
symbol_mark_used (resultP->X_add_symbol);
+ if (rank == 0 && mode == expr_evaluate)
+ resolve_expression (resultP);
+
return resultP->X_op == O_constant ? absolute_section : retval;
}
+
+/* Resolve an expression without changing any symbols/sub-expressions
+ used. */
+
+int
+resolve_expression (expressionS *expressionP)
+{
+ /* Help out with CSE. */
+ valueT final_val = expressionP->X_add_number;
+ symbolS *add_symbol = expressionP->X_add_symbol;
+ symbolS *op_symbol = expressionP->X_op_symbol;
+ operatorT op = expressionP->X_op;
+ valueT left, right;
+ segT seg_left, seg_right;
+ fragS *frag_left, *frag_right;
+
+ switch (op)
+ {
+ default:
+ return 0;
+
+ case O_constant:
+ case O_register:
+ left = 0;
+ break;
+
+ case O_symbol:
+ case O_symbol_rva:
+ if (!snapshot_symbol (add_symbol, &left, &seg_left, &frag_left))
+ return 0;
+
+ break;
+
+ case O_uminus:
+ case O_bit_not:
+ case O_logical_not:
+ if (!snapshot_symbol (add_symbol, &left, &seg_left, &frag_left))
+ return 0;
+
+ if (seg_left != absolute_section)
+ return 0;
+
+ if (op == O_logical_not)
+ left = !left;
+ else if (op == O_uminus)
+ left = -left;
+ else
+ left = ~left;
+ op = O_constant;
+ break;
+
+ case O_multiply:
+ case O_divide:
+ case O_modulus:
+ case O_left_shift:
+ case O_right_shift:
+ case O_bit_inclusive_or:
+ case O_bit_or_not:
+ case O_bit_exclusive_or:
+ case O_bit_and:
+ case O_add:
+ case O_subtract:
+ case O_eq:
+ case O_ne:
+ case O_lt:
+ case O_le:
+ case O_ge:
+ case O_gt:
+ case O_logical_and:
+ case O_logical_or:
+ if (!snapshot_symbol (add_symbol, &left, &seg_left, &frag_left)
+ || !snapshot_symbol (op_symbol, &right, &seg_right, &frag_right))
+ return 0;
+
+ /* Simplify addition or subtraction of a constant by folding the
+ constant into X_add_number. */
+ if (op == O_add)
+ {
+ if (seg_right == absolute_section)
+ {
+ final_val += right;
+ op = O_symbol;
+ break;
+ }
+ else if (seg_left == absolute_section)
+ {
+ final_val += left;
+ left = right;
+ seg_left = seg_right;
+ expressionP->X_add_symbol = expressionP->X_op_symbol;
+ op = O_symbol;
+ break;
+ }
+ }
+ else if (op == O_subtract)
+ {
+ if (seg_right == absolute_section)
+ {
+ final_val -= right;
+ op = O_symbol;
+ break;
+ }
+ }
+
+ /* Equality and non-equality tests are permitted on anything.
+ Subtraction, and other comparison operators are permitted if
+ both operands are in the same section. Otherwise, both
+ operands must be absolute. We already handled the case of
+ addition or subtraction of a constant above. */
+ if (!(seg_left == absolute_section
+ && seg_right == absolute_section)
+ && !(op == O_eq || op == O_ne)
+ && !((op == O_subtract
+ || op == O_lt || op == O_le || op == O_ge || op == O_gt)
+ && seg_left == seg_right
+ && (finalize_syms || frag_left == frag_right)
+ && ((seg_left != undefined_section
+ && seg_left != reg_section)
+ || add_symbol == op_symbol)))
+ return 0;
+
+ switch (op)
+ {
+ case O_add: left += right; break;
+ case O_subtract: left -= right; break;
+ case O_multiply: left *= right; break;
+ case O_divide:
+ if (right == 0)
+ return 0;
+ left = (offsetT) left / (offsetT) right;
+ break;
+ case O_modulus:
+ if (right == 0)
+ return 0;
+ left = (offsetT) left % (offsetT) right;
+ break;
+ case O_left_shift: left <<= right; break;
+ case O_right_shift: left >>= right; break;
+ case O_bit_inclusive_or: left |= right; break;
+ case O_bit_or_not: left |= ~right; break;
+ case O_bit_exclusive_or: left ^= right; break;
+ case O_bit_and: left &= right; break;
+ case O_eq:
+ case O_ne:
+ left = (left == right
+ && seg_left == seg_right
+ && (finalize_syms || frag_left == frag_right)
+ && ((seg_left != undefined_section
+ && seg_left != reg_section)
+ || add_symbol == op_symbol)
+ ? ~ (valueT) 0 : 0);
+ if (op == O_ne)
+ left = ~left;
+ break;
+ case O_lt:
+ left = (offsetT) left < (offsetT) right ? ~ (valueT) 0 : 0;
+ break;
+ case O_le:
+ left = (offsetT) left <= (offsetT) right ? ~ (valueT) 0 : 0;
+ break;
+ case O_ge:
+ left = (offsetT) left >= (offsetT) right ? ~ (valueT) 0 : 0;
+ break;
+ case O_gt:
+ left = (offsetT) left > (offsetT) right ? ~ (valueT) 0 : 0;
+ break;
+ case O_logical_and: left = left && right; break;
+ case O_logical_or: left = left || right; break;
+ default: abort ();
+ }
+
+ op = O_constant;
+ break;
+ }
+
+ if (op == O_symbol)
+ {
+ if (seg_left == absolute_section)
+ op = O_constant;
+ else if (seg_left == reg_section && final_val == 0)
+ op = O_register;
+ }
+ expressionP->X_op = op;
+
+ if (op == O_constant || op == O_register)
+ final_val += left;
+ expressionP->X_add_number = final_val;
+
+ return 1;
+}
/* This lives here because it belongs equally in expr.c & read.c.
expr.c is just a branch office read.c anyway, and putting it
@@ -1905,6 +2105,6 @@ unsigned int
get_single_number (void)
{
expressionS exp;
- operand (&exp);
+ operand (&exp, expr_normal);
return exp.X_add_number;
}
diff --git a/gas/expr.h b/gas/expr.h
index ddd1ce3..6b88d0d 100644
--- a/gas/expr.h
+++ b/gas/expr.h
@@ -143,8 +143,17 @@ typedef struct expressionS {
unsigned short X_md;
} expressionS;
+enum expr_mode
+{
+ expr_evaluate,
+ expr_normal,
+ expr_defer
+};
+
/* "result" should be type (expressionS *). */
-#define expression(result) expr (0, result)
+#define expression(result) expr (0, result, expr_normal)
+#define expression_and_evaluate(result) expr (0, result, expr_evaluate)
+#define deferred_expression(result) expr (0, result, expr_defer)
/* If an expression is O_big, look here for its value. These common
data may be clobbered whenever expr() is called. */
@@ -160,10 +169,12 @@ typedef char operator_rankT;
extern char get_symbol_end (void);
extern void expr_begin (void);
extern void expr_set_precedence (void);
-extern segT expr (int rank, expressionS * resultP);
+extern segT expr (int, expressionS *, enum expr_mode);
extern unsigned int get_single_number (void);
extern symbolS *make_expr_symbol (expressionS * expressionP);
extern int expr_symbol_where (symbolS *, char **, unsigned int *);
extern symbolS *expr_build_uconstant (offsetT);
extern symbolS *expr_build_dot (void);
+
+int resolve_expression (expressionS *);
diff --git a/gas/read.c b/gas/read.c
index 8e4e1bc..00f676f 100644
--- a/gas/read.c
+++ b/gas/read.c
@@ -323,6 +323,7 @@ static const pseudo_typeS potable[] = {
/* endef */
{"equ", s_set, 0},
{"equiv", s_set, 1},
+ {"eqv", s_set, -1},
{"err", s_err, 0},
{"error", s_errwarn, 1},
{"exitm", s_mexit, 0},
@@ -441,7 +442,7 @@ static const pseudo_typeS potable[] = {
static offsetT
get_absolute_expr (expressionS *exp)
{
- expression (exp);
+ expression_and_evaluate (exp);
if (exp->X_op != O_constant)
{
if (exp->X_op != O_absent)
@@ -787,6 +788,14 @@ read_a_source_file (char *name)
/* Input_line_pointer->after ':'. */
SKIP_WHITESPACE ();
}
+ else if (input_line_pointer[1] == '='
+ && (c == '='
+ || ((c == ' ' || c == '\t')
+ && input_line_pointer[2] == '=')))
+ {
+ equals (s, -1);
+ demand_empty_rest_of_line ();
+ }
else if ((c == '='
|| ((c == ' ' || c == '\t')
&& input_line_pointer[1] == '='))
@@ -2210,7 +2219,7 @@ s_lsym (int ignore ATTRIBUTE_UNUSED)
}
input_line_pointer++;
- expression (&exp);
+ expression_and_evaluate (&exp);
if (exp.X_op != O_constant
&& exp.X_op != O_register)
@@ -2743,7 +2752,7 @@ end_repeat (int extra)
}
static void
-assign_symbol (char *name, int no_reassign)
+assign_symbol (char *name, int mode)
{
symbolS *symbolP;
@@ -2784,18 +2793,37 @@ assign_symbol (char *name, int no_reassign)
#endif
}
- /* Permit register names to be redefined. */
- if (no_reassign
- && S_IS_DEFINED (symbolP)
- && S_GET_SEGMENT (symbolP) != reg_section)
- as_bad (_("symbol `%s' is already defined"), name);
+ if (S_IS_DEFINED (symbolP))
+ {
+ /* Permit register names to be redefined. */
+ if ((mode != 0 || !S_IS_VOLATILE (symbolP))
+ && S_GET_SEGMENT (symbolP) != reg_section)
+ {
+ as_bad (_("symbol `%s' is already defined"), name);
+ symbolP = symbol_clone (symbolP, 0);
+ }
+ /* If the symbol is volatile, copy the symbol and replace the
+ original with the copy, so that previous uses of the symbol will
+ retain the value of the symbol at the point of use. */
+ else if (S_IS_VOLATILE (symbolP)
+ /* This could be avoided when the symbol wasn't used so far, but
+ the comment in struc-symbol.h says this flag isn't reliable. */
+ && (1 || symbol_used_p (symbolP)))
+ symbolP = symbol_clone (symbolP, 1);
+ }
+
+ if (mode == 0)
+ S_SET_VOLATILE (symbolP);
+ else if (mode < 0)
+ S_SET_FORWARD_REF (symbolP);
pseudo_set (symbolP);
}
-/* Handle the .equ, .equiv and .set directives. If EQUIV is 1, then
- this is .equiv, and it is an error if the symbol is already
- defined. */
+/* Handle the .equ, .equiv, .eqv, and .set directives. If EQUIV is 1,
+ then this is .equiv, and it is an error if the symbol is already
+ defined. If EQUIV is -1, the symbol additionally is a forward
+ reference. */
void
s_set (int equiv)
@@ -2917,6 +2945,7 @@ s_space (int mult)
|| val.X_add_number > 0xff
|| (mult != 0 && mult != 1 && val.X_add_number != 0))
{
+ resolve_expression (&exp);
if (exp.X_op != O_constant)
as_bad (_("unsupported variable size or fill value"));
else
@@ -2932,6 +2961,9 @@ s_space (int mult)
}
else
{
+ if (now_seg == absolute_section || mri_common_symbol != NULL)
+ resolve_expression (&exp);
+
if (exp.X_op == O_constant)
{
long repeat;
@@ -3185,7 +3217,10 @@ pseudo_set (symbolS *symbolP)
know (symbolP); /* NULL pointer is logic error. */
- (void) expression (&exp);
+ if (!S_IS_FORWARD_REF (symbolP))
+ (void) expression (&exp);
+ else
+ (void) deferred_expression (&exp);
if (exp.X_op == O_illegal)
as_bad (_("illegal expression"));
@@ -3199,6 +3234,7 @@ pseudo_set (symbolS *symbolP)
as_bad (_("floating point number invalid"));
}
else if (exp.X_op == O_subtract
+ && !S_IS_FORWARD_REF (symbolP)
&& SEG_NORMAL (S_GET_SEGMENT (exp.X_add_symbol))
&& (symbol_get_frag (exp.X_add_symbol)
== symbol_get_frag (exp.X_op_symbol)))
@@ -3245,7 +3281,7 @@ pseudo_set (symbolS *symbolP)
*symbol_X_add_number (symbolP) += exp.X_add_number;
break;
}
- else if (seg != undefined_section)
+ else if (!S_IS_FORWARD_REF (symbolP) && seg != undefined_section)
{
symbolS *s = exp.X_add_symbol;
@@ -4838,6 +4874,8 @@ equals (char *sym_name, int reassign)
input_line_pointer++;
if (*input_line_pointer == '=')
input_line_pointer++;
+ if (reassign < 0 && *input_line_pointer == '=')
+ input_line_pointer++;
while (*input_line_pointer == ' ' || *input_line_pointer == '\t')
input_line_pointer++;
@@ -4845,7 +4883,7 @@ equals (char *sym_name, int reassign)
if (flag_mri)
stop = mri_comment_field (&stopc);
- assign_symbol (sym_name, !reassign);
+ assign_symbol (sym_name, reassign >= 0 ? !reassign : reassign);
if (flag_mri)
{
diff --git a/gas/struc-symbol.h b/gas/struc-symbol.h
index 0b2d520..2326ee4 100644
--- a/gas/struc-symbol.h
+++ b/gas/struc-symbol.h
@@ -60,6 +60,12 @@ struct symbol
a symbol is used in backend routines. */
unsigned int sy_used : 1;
+ /* Whether the symbol can be re-defined. */
+ unsigned int sy_volatile : 1;
+
+ /* Whether the symbol is a forward reference. */
+ unsigned int sy_forward_ref : 1;
+
/* This is set if the symbol is defined in an MRI common section.
We handle such sections as single common symbols, so symbols
defined within them must be treated specially by the relocation
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 *
diff --git a/gas/symbols.h b/gas/symbols.h
index 3d029ff..c20f4d7 100644
--- a/gas/symbols.h
+++ b/gas/symbols.h
@@ -44,6 +44,10 @@ symbolS *symbol_new (const char *name, segT segment, valueT value,
fragS * frag);
symbolS *symbol_create (const char *name, segT segment, valueT value,
fragS * frag);
+symbolS *symbol_clone (symbolS *, int);
+#undef symbol_clone_if_forward_ref
+symbolS *symbol_clone_if_forward_ref (symbolS *, int);
+#define symbol_clone_if_forward_ref(s) symbol_clone_if_forward_ref (s, 0)
symbolS *symbol_temp_new (segT, valueT, fragS *);
symbolS *symbol_temp_new_now (void);
symbolS *symbol_temp_make (void);
@@ -55,6 +59,7 @@ void symbol_print_statistics (FILE *);
void symbol_table_insert (symbolS * symbolP);
valueT resolve_symbol_value (symbolS *);
void resolve_local_symbol_values (void);
+int snapshot_symbol (symbolS *, valueT *, segT *, fragS **);
void print_symbol_value (symbolS *);
void print_expr (expressionS *);
@@ -84,6 +89,8 @@ extern int S_FORCE_RELOC (symbolS *, int);
extern int S_IS_DEBUG (symbolS *);
extern int S_IS_LOCAL (symbolS *);
extern int S_IS_STABD (symbolS *);
+extern int S_IS_VOLATILE (const symbolS *);
+extern int S_IS_FORWARD_REF (const symbolS *);
extern const char *S_GET_NAME (symbolS *);
extern segT S_GET_SEGMENT (symbolS *);
extern void S_SET_SEGMENT (symbolS *, segT);
@@ -92,6 +99,8 @@ extern void S_SET_NAME (symbolS *, const char *);
extern void S_CLEAR_EXTERNAL (symbolS *);
extern void S_SET_WEAK (symbolS *);
extern void S_SET_THREAD_LOCAL (symbolS *);
+extern void S_SET_VOLATILE (symbolS *);
+extern void S_SET_FORWARD_REF (symbolS *);
#ifndef WORKING_DOT_WORD
struct broken_word
diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog
index ab3ce31..5ed3d10 100644
--- a/gas/testsuite/ChangeLog
+++ b/gas/testsuite/ChangeLog
@@ -1,3 +1,22 @@
+2005-10-11 Jan Beulich <jbeulich@novell.com>
+
+ * gas/all/cond.s: Add test for resolution of fully resolvable
+ forward references in .if/.endif.
+ * gas/all/cond.d: Rename to:
+ * gas/all/cond.l: New.
+ * gas/all/assign-bad.s: New.
+ * gas/all/assign-ok.s: New.
+ * gas/all/equ-bad.s: New.
+ * gas/all/equ-ok.s: New.
+ * gas/all/equiv1.s: New.
+ * gas/all/equiv2.s: New.
+ * gas/all/eqv-bad.s: New.
+ * gas/all/eqv-ok.s: New.
+ * gas/all/eval.[sd]: New.
+ * gas/all/forward.[sd]: New.
+ * gas/all/redef.[sd]: New.
+ * gas/all/gas.exp: Run new tests, but xfail equiv1 (PR/1387).
+
2005-10-10 Nick Clifton <nickc@redhat.com>
* gas/sh/reg-prefix.s: Use mov.l instruction in preference to
diff --git a/gas/testsuite/gas/all/assign-bad.s b/gas/testsuite/gas/all/assign-bad.s
new file mode 100644
index 0000000..3c7a2d7
--- /dev/null
+++ b/gas/testsuite/gas/all/assign-bad.s
@@ -0,0 +1,2 @@
+ yyy == 3
+ yyy == 4
diff --git a/gas/testsuite/gas/all/assign-ok.s b/gas/testsuite/gas/all/assign-ok.s
new file mode 100644
index 0000000..fb8e06f
--- /dev/null
+++ b/gas/testsuite/gas/all/assign-ok.s
@@ -0,0 +1,3 @@
+ xxx = 1
+ xxx = 2
+ yyy == 3
diff --git a/gas/testsuite/gas/all/cond.d b/gas/testsuite/gas/all/cond.l
index e13ac90..a103d8d 100644
--- a/gas/testsuite/gas/all/cond.d
+++ b/gas/testsuite/gas/all/cond.l
@@ -24,6 +24,12 @@
29[ ]+.else
31[ ]+.endif
[ ]*[1-9][0-9]*[ ]+
+[ ]*[1-9][0-9]*[ ]+\.equiv[ ]+x,[ ]*y[ ]*
+[ ]*[1-9][0-9]*[ ]+\.equiv[ ]+y,[ ]*0[ ]*
+[ ]*[1-9][0-9]*[ ]+\.if[ ]+x[ ]*
+[ ]*[1-9][0-9]*[ ]+\.elseif[ ]+x[ ]*
+[ ]*[1-9][0-9]*[ ]+\.endif[ ]*
+[ ]*[1-9][0-9]*[ ]+
[ ]*[1-9][0-9]*[ ]+\.macro[ ]+m[ ]+x,[ ]*y[ ]*
#...
[ ]*[1-9][0-9]*[ ]+\.endm[ ]*
diff --git a/gas/testsuite/gas/all/cond.s b/gas/testsuite/gas/all/cond.s
index b8136ba..2737d1f 100644
--- a/gas/testsuite/gas/all/cond.s
+++ b/gas/testsuite/gas/all/cond.s
@@ -30,6 +30,14 @@
.long 9
.endif
+ .equiv x, y
+ .equiv y, 0
+ .if x
+ .err
+ .elseif x
+ .err
+ .endif
+
.macro m x, y
.ifb \x
.long -1
diff --git a/gas/testsuite/gas/all/equ-bad.s b/gas/testsuite/gas/all/equ-bad.s
new file mode 100644
index 0000000..4e3f931
--- /dev/null
+++ b/gas/testsuite/gas/all/equ-bad.s
@@ -0,0 +1,2 @@
+ .equ x, 1
+ .eqv x, 2
diff --git a/gas/testsuite/gas/all/equ-ok.s b/gas/testsuite/gas/all/equ-ok.s
new file mode 100644
index 0000000..c620e97
--- /dev/null
+++ b/gas/testsuite/gas/all/equ-ok.s
@@ -0,0 +1,2 @@
+ .equ x, 1
+ .equ x, 2
diff --git a/gas/testsuite/gas/all/equiv1.s b/gas/testsuite/gas/all/equiv1.s
new file mode 100644
index 0000000..cd59bda
--- /dev/null
+++ b/gas/testsuite/gas/all/equiv1.s
@@ -0,0 +1,5 @@
+;# Re-definition of an already .equiv-ed symbol (to another symbol).
+;# The assembler should reject this.
+ .equiv x, y
+ .equiv y, 1
+ .equiv x, 0
diff --git a/gas/testsuite/gas/all/equiv2.s b/gas/testsuite/gas/all/equiv2.s
new file mode 100644
index 0000000..c533af7
--- /dev/null
+++ b/gas/testsuite/gas/all/equiv2.s
@@ -0,0 +1,6 @@
+;# Re-definition of an already .equiv-ed symbol (to an expression).
+;# The assembler should reject this.
+ .equiv x, y-z
+ .equiv y, 1
+ .equiv z, 1
+ .equiv x, 1
diff --git a/gas/testsuite/gas/all/eqv-bad.s b/gas/testsuite/gas/all/eqv-bad.s
new file mode 100644
index 0000000..66172b3
--- /dev/null
+++ b/gas/testsuite/gas/all/eqv-bad.s
@@ -0,0 +1,2 @@
+ .eqv x, 1
+ .eqv x, 2
diff --git a/gas/testsuite/gas/all/eqv-ok.s b/gas/testsuite/gas/all/eqv-ok.s
new file mode 100644
index 0000000..2fe13d5
--- /dev/null
+++ b/gas/testsuite/gas/all/eqv-ok.s
@@ -0,0 +1 @@
+ .eqv x, 1
diff --git a/gas/testsuite/gas/all/eval.d b/gas/testsuite/gas/all/eval.d
new file mode 100644
index 0000000..9a7e9e8
--- /dev/null
+++ b/gas/testsuite/gas/all/eval.d
@@ -0,0 +1,8 @@
+#objdump: -s -j .data
+#name: evaluation of simple expressions
+
+.*: .*
+
+Contents of section .data:
+ 0000 01010101 010101.. ........ ........ ................
+#pass
diff --git a/gas/testsuite/gas/all/eval.s b/gas/testsuite/gas/all/eval.s
new file mode 100644
index 0000000..14efe94
--- /dev/null
+++ b/gas/testsuite/gas/all/eval.s
@@ -0,0 +1,48 @@
+.equ zero, 0
+.equ one, 1
+.equ two, 2
+
+
+ .data
+
+ .if two > one
+ .byte one
+ .else
+ .byte two
+ .endif
+
+ .if one == one
+ .byte one
+ .else
+ .byte two
+ .endif
+
+ .if one < two
+ .byte one
+ .else
+ .byte two
+ .endif
+
+ .if one <> two
+ .byte one
+ .else
+ .byte two
+ .endif
+
+ .if one != two
+ .byte one
+ .else
+ .byte two
+ .endif
+
+ .if one <= two
+ .byte one
+ .else
+ .byte two
+ .endif
+
+ .if two >= one
+ .byte one
+ .else
+ .byte two
+ .endif
diff --git a/gas/testsuite/gas/all/forward.d b/gas/testsuite/gas/all/forward.d
new file mode 100644
index 0000000..8e45201
--- /dev/null
+++ b/gas/testsuite/gas/all/forward.d
@@ -0,0 +1,8 @@
+#objdump: -s -j .data
+#name: forward references
+
+.*: .*
+
+Contents of section .data:
+ 0000 01020304 ff0203fc 01020304 ff0203fc ................
+#pass
diff --git a/gas/testsuite/gas/all/forward.s b/gas/testsuite/gas/all/forward.s
new file mode 100644
index 0000000..d51103c
--- /dev/null
+++ b/gas/testsuite/gas/all/forward.s
@@ -0,0 +1,44 @@
+ .equiv two, 2*one
+ .equiv minus_one, -one
+ .equ one, 1
+ .equiv three, 3*one
+ .eqv four, 4*one
+
+ .data
+
+ .if two > one
+ .byte one
+ .byte two
+ .endif
+
+ .if four > one
+ .byte three
+ .byte four
+ .endif
+
+ .equ one, -1
+ .byte one
+ .byte two
+
+ .if four < one
+ .byte three
+ .byte four
+ .endif
+
+ .equ one, -minus_one
+ .byte one
+ .byte two
+
+ .if four > one
+ .byte three
+ .byte four
+ .endif
+
+ .equ one, minus_one
+ .byte one
+ .byte two
+
+ .if four < one
+ .byte three
+ .byte four
+ .endif
diff --git a/gas/testsuite/gas/all/gas.exp b/gas/testsuite/gas/all/gas.exp
index 2a9aeb7..a5a8f4b 100644
--- a/gas/testsuite/gas/all/gas.exp
+++ b/gas/testsuite/gas/all/gas.exp
@@ -34,6 +34,56 @@ if ![istarget hppa*-*-*] then {
gas_test_error "diff1.s" "" "difference of two undefined symbols"
}
+# PR/1387
+setup_xfail "*-*-*"
+gas_test_error "equiv1.s" "" ".equiv for symbol already set to another one"
+gas_test_error "equiv2.s" "" ".equiv for symbol already set to an expression"
+
+# .equ works differently on some targets.
+case $target_triplet in {
+ { hppa*-*-* } { }
+ { *c54x*-*-* } { }
+ default {
+ gas_test "equ-ok.s" "" "" ".equ for symbol already set"
+ gas_test_error "equ-bad.s" "" ".equ for symbol already set through .eqv"
+ }
+}
+
+gas_test "eqv-ok.s" "" "" ".eqv support"
+gas_test_error "eqv-bad.s" "" ".eqv for symbol already set"
+
+gas_test "assign-ok.s" "" "" "== assignment support"
+gas_test_error "assign-bad.s" "" "== assignment for symbol already set"
+
+# .equ works differently on some targets.
+# linkrelax-ing prevents most forward references from working.
+case $target_triplet in {
+ { crx*-*-* } { }
+ { h8300*-*-* } { }
+ { hppa*-*-* } { }
+ { mn10\[23\]00*-*-* } { }
+ { *c54x*-*-* } { }
+ default {
+ # Some targets don't manage to resolve BFD_RELOC_8 for constants.
+ setup_xfail "alpha*-*-*" "avr-*-*" "*c30*-*-*" "*c4x*-*-*" \
+ "d\[13\]0v*-*-*" "i860-*-*" "mips*-*-*" "msp430-*-*" \
+ "pdp11-*-*" "sparc*-*-*" "xtensa-*-*"
+ run_dump_test forward
+ }
+}
+
+# .set works differently on some targets.
+case $target_triplet in {
+ { alpha*-*-* } { }
+ { iq2000*-*-* } { }
+ { mips*-*-* } { }
+ { *c54x*-*-* } { }
+ default {
+ setup_xfail "*c30*-*-*" "*c4x*-*-*" "pdp11-*-*"
+ run_dump_test redef
+ }
+}
+
proc do_comment {} {
set testname "comment.s: comments in listings"
set x1 0
@@ -129,6 +179,8 @@ case $target_triplet in {
# character (it is allowed to be a line comment character).
if [string match "" [lindex [gas_run excl.s "-o /dev/null" ""] 0]] {
run_dump_test altmac2
+ # Similarly this test does not work when ! is a line seperator.
+ run_dump_test eval
}
}
}
@@ -162,7 +214,7 @@ proc test_cond {} {
send_log "$comp_output\n"
fail $testname
} else {
- if { [regexp_diff dump.out $srcdir/$subdir/cond.d] } {
+ if { [regexp_diff dump.out $srcdir/$subdir/cond.l] } {
fail $testname
} else {
pass $testname
diff --git a/gas/testsuite/gas/all/redef.d b/gas/testsuite/gas/all/redef.d
new file mode 100644
index 0000000..fed1998
--- /dev/null
+++ b/gas/testsuite/gas/all/redef.d
@@ -0,0 +1,8 @@
+#objdump: -s -j .data
+#name: .equ redefinitions
+
+.*: .*
+
+Contents of section .data:
+ 0000 00000000 0[04]00000[04] 0[08]00000[08] 0[0c]00000[0c][ ]+................[ ]*
+#pass
diff --git a/gas/testsuite/gas/all/redef.s b/gas/testsuite/gas/all/redef.s
new file mode 100644
index 0000000..896c460
--- /dev/null
+++ b/gas/testsuite/gas/all/redef.s
@@ -0,0 +1,11 @@
+ .data
+_start:
+ .set x, .-_start
+ .long x
+ .balign 4
+ .set x, .-_start
+ .long x
+ .set x, .-_start
+ .long x
+ .set x, .-_start
+ .long x