This adjusts equate handling by
authorNick Clifton <nickc@redhat.com>
Tue, 11 Oct 2005 11:16:17 +0000 (11:16 +0000)
committerNick Clifton <nickc@redhat.com>
Tue, 11 Oct 2005 11:16:17 +0000 (11:16 +0000)
- 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.

44 files changed:
gas/ChangeLog
gas/as.c
gas/cond.c
gas/config/tc-arc.c
gas/config/tc-ia64.h
gas/config/tc-m32r.c
gas/config/tc-m32r.h
gas/config/tc-mips.c
gas/config/tc-mmix.h
gas/config/tc-mn10300.c
gas/config/tc-mn10300.h
gas/config/tc-ppc.h
gas/config/tc-sh.c
gas/config/tc-sh.h
gas/config/tc-sh64.c
gas/config/tc-sh64.h
gas/config/tc-tic54x.h
gas/doc/as.texinfo
gas/dw2gencfi.c
gas/expr.c
gas/expr.h
gas/read.c
gas/struc-symbol.h
gas/symbols.c
gas/symbols.h
gas/testsuite/ChangeLog
gas/testsuite/gas/all/assign-bad.s [new file with mode: 0644]
gas/testsuite/gas/all/assign-ok.s [new file with mode: 0644]
gas/testsuite/gas/all/cond.d [deleted file]
gas/testsuite/gas/all/cond.l [new file with mode: 0644]
gas/testsuite/gas/all/cond.s
gas/testsuite/gas/all/equ-bad.s [new file with mode: 0644]
gas/testsuite/gas/all/equ-ok.s [new file with mode: 0644]
gas/testsuite/gas/all/equiv1.s [new file with mode: 0644]
gas/testsuite/gas/all/equiv2.s [new file with mode: 0644]
gas/testsuite/gas/all/eqv-bad.s [new file with mode: 0644]
gas/testsuite/gas/all/eqv-ok.s [new file with mode: 0644]
gas/testsuite/gas/all/eval.d [new file with mode: 0644]
gas/testsuite/gas/all/eval.s [new file with mode: 0644]
gas/testsuite/gas/all/forward.d [new file with mode: 0644]
gas/testsuite/gas/all/forward.s [new file with mode: 0644]
gas/testsuite/gas/all/gas.exp
gas/testsuite/gas/all/redef.d [new file with mode: 0644]
gas/testsuite/gas/all/redef.s [new file with mode: 0644]

index 64dd1551331a03ea5a6134dd8e49ea14bef0ff82..16d67b59f7ff5d0a1877e4e58675ef0f0e5aba34 100644 (file)
@@ -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.
index 07f76924cb97ef22d0b47994772f16f00c4fdc13..10e20e3995c25656915494b0d77dbfe88abe10c1 100644 (file)
--- 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;
 
index 8cd98c2a2d291128a65332494ff5bbf2813de23e..e791b11881a97cce7e5f545c52ada681881dfce3 100644 (file)
@@ -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"));
 
index 0dd0ac72925409ff8e0db8e0d529f2f0402b6361..b33256f6f08bcec622079b95e05fba303d226e26 100644 (file)
@@ -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);
index f322fbf16fc1882ac7ee1f896639b6fcfc3b5485..c17494beb16bdb294133b6252569a774bbf20218 100644 (file)
@@ -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)
index 54452c5433b823e9be86a6833fba532761a429b2..51b160a98f76b2f4a29fbe627acb0f1fe9f3d0d9 100644 (file)
@@ -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);
index eb03495e808b12fee9e3ed168604e90df448f1c4..69fe9453cc36b640a9faf468f0068016b52b5763 100644 (file)
@@ -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.  */
index 2ce3415073b5932ac05b82750b983b7a050d1c90..6e061052cf2f8d2eb3969f895d96d55de125d978 100644 (file)
@@ -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;
index f755995185f994297d6992fe187303b6e0b7eb9e..61bc881d12686d1dd1515f948bdebd0b31eeea99 100644 (file)
@@ -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])                           \
index 8849d1c2b52d89780d0c58470cc8121353101915..963b1b6b209a60b2b6aae8ccb069828aaaa5aca4 100644 (file)
@@ -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);
index ad41df493ef67319bcbc2471315970ad40ff10f3..dff663d29adf6ba6d591b996614018e295fcef63 100644 (file)
           && 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))
index 7b6126a4ddd9d26ceaac91c0dd2bb68aea586cba..f7c2da619cbc8311d67f7c2b9186f39e715e9639 100644 (file)
@@ -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)
index 0b294e0685ad2e8219c12f6282de8efe20912bf5..acf62aef21d643947ecf64ef2cf22934a130a23f 100644 (file)
@@ -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);
index 69b82b229dbbad0f5d069b4cf0a263b9e4b88c01..a812036fcd51aa585cb19c27f1e2b36122ae97c5 100644 (file)
@@ -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))
index 7964579268db3906bf1540c55993b122bafb806b..74330612e43afb158b4f8d88207f272deeddb1fe 100644 (file)
@@ -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
index 8af9b95fe94e5f7e9fece4c10eee2bedc09d8246..21f5d59f4c566a127a8edede760c710008bd508e 100644 (file)
@@ -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
index 4d9b2c8de8c7ca7e2a9b917a937990506b1ec0a5..7476500e79be133f266fedf3afadd423fdd1c062 100644 (file)
@@ -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);
index 1d9ae0c269f7523851a947167d3f3f713f40e27f..2b3e4c25a0dbbb68e95e2bb71c1c1e1879a14844 100644 (file)
@@ -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}
index 65be298d0f8a527cb93a92800443e216e357e69c..9601b30d778ca17bab73f1c51475887c9bbe07c3 100644 (file)
@@ -415,7 +415,7 @@ cfi_parse_reg (void)
     }
 #endif
 
-  expression (&exp);
+  expression_and_evaluate (&exp);
   switch (exp.X_op)
     {
     case O_register:
index fff0fde707539911ecc0ad35e8fc8cd97978c76f..32de0f7394b1f7287c92b2dc9d540913fecdeb78 100644 (file)
@@ -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;
+}
 \f
 /* 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;
 }
index ddd1ce3ac37f8c71db4b80920c4fffd9aed6b8ed..6b88d0dfe43cde22ec689df6861d4df4f532f04c 100644 (file)
@@ -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 *);
index 8e4e1bce60d3cabfc229d39c293d9a4f8a900340..00f676f223ef9a6d6973f372f9d038239358f90c 100644 (file)
@@ -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)
     {
index 0b2d52064998e6d399d91cbfad142960a71892b0..2326ee4f06fb9bd968fc70b73261472c831851e7 100644 (file)
@@ -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
index 49d546d8332fb00712279150a9352dc4b8bfb193..78ec954f9b555ae8ed342aa3bd5c65170fab2365 100644 (file)
@@ -537,6 +537,94 @@ symbol_make (const char *name)
   return (symbolP);
 }
 
+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)
 {
@@ -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 *
index 3d029fffe987801604bb7aad3443a221e060b8e2..c20f4d733029184b571b15b7308f916376807c7a 100644 (file)
@@ -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
index ab3ce313cec53fbe7827279a697e9cc4acee3de5..5ed3d1093a66045c695252e9a1de9576c3f77245 100644 (file)
@@ -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 (file)
index 0000000..3c7a2d7
--- /dev/null
@@ -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 (file)
index 0000000..fb8e06f
--- /dev/null
@@ -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.d
deleted file mode 100644 (file)
index e13ac90..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-# This should match the output of gas -alc cond.s.
-
-.*cond.s.*
-
-
-   1[  ]+.if   0
-   8[  ]+.else
-   9[  ]+.if   1
-  10[  ]+.endc
-  11 0000 0[02] ?00 ?00 ?0[02][        ]+.long[        ]+2
-  12[  ]+.if   0
-  14[  ]+.else
-  15 0004 0[04] ?00 ?00 ?0[04][        ]+.long[        ]+4
-  16[  ]+.endc
-  17[  ]+.endc
-  18[  ]+
-  19[  ]+.if   0
-  21[  ]+.elseif       1
-  22[  ]+.if   0
-  24[  ]+.elseif       1
-  25 0008 0[07] ?00 ?00 ?0[07][        ]+.long[        ]+7
-  26[  ]+.endif
-  27[  ]+.elseif       1
-  29[  ]+.else
-  31[  ]+.endif
-[      ]*[1-9][0-9]*[  ]+
-[      ]*[1-9][0-9]*[  ]+\.macro[      ]+m[    ]+x,[   ]*y[    ]*
-#...
-[      ]*[1-9][0-9]*[  ]+\.endm[       ]*
-[      ]*[1-9][0-9]*[  ]+[0-9a-f]+[048c] FF ?FF ?FF ?FF[       ]+m[    ]+,[    ]*
-[      ]*[1-9][0-9]*[  ]+FF ?FF ?FF ?FF[       ]*
-[      ]*[1-9][0-9]*[  ]+[0-9a-f]+[048c] FF ?FF ?FF ?FF[       ]+m[    ]+,[    ]*10[   ]*
-[      ]*[1-9][0-9]*[  ]+0[0A] ?00 ?00 ?0[0A][         ]*
-[      ]*[1-9][0-9]*[  ]+[0-9a-f]+[048c] 0[0B] ?00 ?00 ?0[0B][         ]+m[    ]+11,[  ]*
-[      ]*[1-9][0-9]*[  ]+FF ?FF ?FF ?FF[       ]*
-[      ]*[1-9][0-9]*[  ]+[0-9a-f]+[048c] 0[0C] ?00 ?00 ?0[0C][         ]+m[    ]+12,[  ]*13[   ]*
-[      ]*[1-9][0-9]*[  ]+0[0D] ?00 ?00 ?0[0D][         ]*
-[      ]*[1-9][0-9]*[  ]+
-[      ]*[1-9][0-9]*[  ]+.*\.p2align 5,0
-#pass
diff --git a/gas/testsuite/gas/all/cond.l b/gas/testsuite/gas/all/cond.l
new file mode 100644 (file)
index 0000000..a103d8d
--- /dev/null
@@ -0,0 +1,46 @@
+# This should match the output of gas -alc cond.s.
+
+.*cond.s.*
+
+
+   1[  ]+.if   0
+   8[  ]+.else
+   9[  ]+.if   1
+  10[  ]+.endc
+  11 0000 0[02] ?00 ?00 ?0[02][        ]+.long[        ]+2
+  12[  ]+.if   0
+  14[  ]+.else
+  15 0004 0[04] ?00 ?00 ?0[04][        ]+.long[        ]+4
+  16[  ]+.endc
+  17[  ]+.endc
+  18[  ]+
+  19[  ]+.if   0
+  21[  ]+.elseif       1
+  22[  ]+.if   0
+  24[  ]+.elseif       1
+  25 0008 0[07] ?00 ?00 ?0[07][        ]+.long[        ]+7
+  26[  ]+.endif
+  27[  ]+.elseif       1
+  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[       ]*
+[      ]*[1-9][0-9]*[  ]+[0-9a-f]+[048c] FF ?FF ?FF ?FF[       ]+m[    ]+,[    ]*
+[      ]*[1-9][0-9]*[  ]+FF ?FF ?FF ?FF[       ]*
+[      ]*[1-9][0-9]*[  ]+[0-9a-f]+[048c] FF ?FF ?FF ?FF[       ]+m[    ]+,[    ]*10[   ]*
+[      ]*[1-9][0-9]*[  ]+0[0A] ?00 ?00 ?0[0A][         ]*
+[      ]*[1-9][0-9]*[  ]+[0-9a-f]+[048c] 0[0B] ?00 ?00 ?0[0B][         ]+m[    ]+11,[  ]*
+[      ]*[1-9][0-9]*[  ]+FF ?FF ?FF ?FF[       ]*
+[      ]*[1-9][0-9]*[  ]+[0-9a-f]+[048c] 0[0C] ?00 ?00 ?0[0C][         ]+m[    ]+12,[  ]*13[   ]*
+[      ]*[1-9][0-9]*[  ]+0[0D] ?00 ?00 ?0[0D][         ]*
+[      ]*[1-9][0-9]*[  ]+
+[      ]*[1-9][0-9]*[  ]+.*\.p2align 5,0
+#pass
index b8136ba224f700b3c8e4d6504715f1408c045f08..2737d1ff298ae8c6a002d4c8a1324d102d367258 100644 (file)
        .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 (file)
index 0000000..4e3f931
--- /dev/null
@@ -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 (file)
index 0000000..c620e97
--- /dev/null
@@ -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 (file)
index 0000000..cd59bda
--- /dev/null
@@ -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 (file)
index 0000000..c533af7
--- /dev/null
@@ -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 (file)
index 0000000..66172b3
--- /dev/null
@@ -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 (file)
index 0000000..2fe13d5
--- /dev/null
@@ -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 (file)
index 0000000..9a7e9e8
--- /dev/null
@@ -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 (file)
index 0000000..14efe94
--- /dev/null
@@ -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 (file)
index 0000000..8e45201
--- /dev/null
@@ -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 (file)
index 0000000..d51103c
--- /dev/null
@@ -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
index 2a9aeb7d89863cbb0551715f0c9fde30c41f8b76..a5a8f4b1b3d39f79489f24d60d95726f561dd6b1 100644 (file)
@@ -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 (file)
index 0000000..fed1998
--- /dev/null
@@ -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 (file)
index 0000000..896c460
--- /dev/null
@@ -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