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.
This commit is contained in:
Nick Clifton 2005-10-11 11:16:17 +00:00
parent 1334d4d50c
commit 9497f5ac6b
43 changed files with 834 additions and 66 deletions

View 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.

View file

@ -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;

View 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"));

View 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);

View 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)

View 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);

View 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. */

View 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;

View 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]) \

View 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);

View file

@ -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))

View 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)

View 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);

View 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))

View 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

View 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

View 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);

View 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}

View file

@ -415,7 +415,7 @@ cfi_parse_reg (void)
}
#endif
expression (&exp);
expression_and_evaluate (&exp);
switch (exp.X_op)
{
case O_register:

View 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;
}
/* 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;
}

View 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 *);

View 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)
{

View 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

View 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 *

View 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

View 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

View file

@ -0,0 +1,2 @@
yyy == 3
yyy == 4

View file

@ -0,0 +1,3 @@
xxx = 1
xxx = 2
yyy == 3

View file

@ -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[ ]*

View file

@ -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

View file

@ -0,0 +1,2 @@
.equ x, 1
.eqv x, 2

View file

@ -0,0 +1,2 @@
.equ x, 1
.equ x, 2

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,2 @@
.eqv x, 1
.eqv x, 2

View file

@ -0,0 +1 @@
.eqv x, 1

View file

@ -0,0 +1,8 @@
#objdump: -s -j .data
#name: evaluation of simple expressions
.*: .*
Contents of section .data:
0000 01010101 010101.. ........ ........ ................
#pass

View file

@ -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

View file

@ -0,0 +1,8 @@
#objdump: -s -j .data
#name: forward references
.*: .*
Contents of section .data:
0000 01020304 ff0203fc 01020304 ff0203fc ................
#pass

View file

@ -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

View 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

View file

@ -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

View file

@ -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