From 3c7b9c2c544319e9f148ef013e8706b1e484e4d5 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Wed, 21 Apr 2010 18:09:52 +0000 Subject: Properly handle ".equ symbol, reg + NUM" in x86 Intel syntax. gas/ 2010-04-21 H.J. Lu PR gas/11509 * config/tc-i386-intel.c (i386_intel_simplify_register): New. (i386_intel_simplify): Use i386_is_register and i386_intel_simplify_register. Set X_md for O_register and check X_md for O_constant. (i386_intel_operand): Use i386_is_register. * config/tc-i386.c (i386_is_register): New. (x86_cons): Initialize the X_md field. Use i386_is_register. (parse_register): Use i386_is_register. (tc_x86_parse_to_dw2regnum): Likewise. gas/testsuite/ 2010-04-21 H.J. Lu PR gas/11509 * gas/i386/equ.s: Add tests for ".equ symbol, reg + NUM". * gas/i386/equ.d: Updated. --- gas/config/tc-i386-intel.c | 101 ++++++++++++++++++++++++++++----------------- gas/config/tc-i386.c | 16 +++++-- 2 files changed, 77 insertions(+), 40 deletions(-) (limited to 'gas/config') diff --git a/gas/config/tc-i386-intel.c b/gas/config/tc-i386-intel.c index b3cdcd3..cb99518 100644 --- a/gas/config/tc-i386-intel.c +++ b/gas/config/tc-i386-intel.c @@ -233,6 +233,49 @@ static INLINE void i386_intel_fold (expressionS *e, symbolS *sym) } } +static int +i386_intel_simplify_register (expressionS *e) +{ + int reg_num; + + if (this_operand < 0 || intel_state.in_offset) + { + as_bad (_("invalid use of register")); + return 0; + } + + if (e->X_op == O_register) + reg_num = e->X_add_number; + else + reg_num = e->X_md - 1; + + if (!intel_state.in_bracket) + { + if (i.op[this_operand].regs) + { + as_bad (_("invalid use of register")); + return 0; + } + if (i386_regtab[reg_num].reg_type.bitfield.sreg3 + && i386_regtab[reg_num].reg_num == RegFlat) + { + as_bad (_("invalid use of pseudo-register")); + return 0; + } + i.op[this_operand].regs = i386_regtab + reg_num; + } + else if (!intel_state.base && !intel_state.in_scale) + intel_state.base = i386_regtab + reg_num; + else if (!intel_state.index) + intel_state.index = i386_regtab + reg_num; + else + { + /* esp is invalid as index */ + intel_state.index = i386_regtab + REGNAM_EAX + 4; + } + return 2; +} + static int i386_intel_simplify (expressionS *); static INLINE int i386_intel_simplify_symbol(symbolS *sym) @@ -304,7 +347,8 @@ static int i386_intel_simplify (expressionS *e) intel_state.op_modifier = e->X_op; /* FALLTHROUGH */ case O_short: - if (symbol_get_value_expression (e->X_add_symbol)->X_op == O_register) + if (i386_is_register (symbol_get_value_expression (e->X_add_symbol), + 1)) { as_bad (_("invalid use of register")); return 0; @@ -315,7 +359,8 @@ static int i386_intel_simplify (expressionS *e) break; case O_full_ptr: - if (symbol_get_value_expression (e->X_op_symbol)->X_op == O_register) + if (i386_is_register (symbol_get_value_expression (e->X_op_symbol), + 1)) { as_bad (_("invalid use of register")); return 0; @@ -328,40 +373,6 @@ static int i386_intel_simplify (expressionS *e) i386_intel_fold (e, e->X_op_symbol); break; - case O_register: - if (this_operand < 0 || intel_state.in_offset) - { - as_bad (_("invalid use of register")); - return 0; - } - if (!intel_state.in_bracket) - { - if (i.op[this_operand].regs) - { - as_bad (_("invalid use of register")); - return 0; - } - if (i386_regtab[e->X_add_number].reg_type.bitfield.sreg3 - && i386_regtab[e->X_add_number].reg_num == RegFlat) - { - as_bad (_("invalid use of pseudo-register")); - return 0; - } - i.op[this_operand].regs = i386_regtab + e->X_add_number; - } - else if (!intel_state.base && !intel_state.in_scale) - intel_state.base = i386_regtab + e->X_add_number; - else if (!intel_state.index) - intel_state.index = i386_regtab + e->X_add_number; - else - { - /* esp is invalid as index */ - intel_state.index = i386_regtab + REGNAM_EAX + 4; - } - e->X_op = O_constant; - e->X_add_number = 0; - return 2; - case O_multiply: if (this_operand >= 0 && intel_state.in_bracket) { @@ -418,6 +429,22 @@ static int i386_intel_simplify (expressionS *e) break; } + + case O_register: + ret = i386_intel_simplify_register (e); + if (ret == 2) + { + gas_assert (e->X_add_number < (unsigned short) -1); + e->X_md = (unsigned short) e->X_add_number + 1; + e->X_op = O_constant; + e->X_add_number = 0; + } + return ret; + + case O_constant: + if (e->X_md) + return i386_intel_simplify_register (e); + /* FALLTHROUGH */ default: if (e->X_add_symbol && !i386_intel_simplify_symbol (e->X_add_symbol)) @@ -832,7 +859,7 @@ i386_intel_operand (char *operand_string, int got_a_float) break; intel_state.seg = expP->X_add_symbol; } - if (expP->X_op != O_register) + if (!i386_is_register (expP, 1)) { as_bad (_("segment register name expected")); return 0; diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index db50c62..1728e60 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -3534,6 +3534,15 @@ swap_operands (void) } } +static int +i386_is_register (const expressionS *e, int is_intel_syntax) +{ + return (e->X_op == O_register + || (is_intel_syntax + && e->X_op == O_constant + && e->X_md)); +} + /* Try to ensure constant immediates are represented in the smallest opcode possible. */ static void @@ -6451,6 +6460,7 @@ x86_cons (expressionS *exp, int size) { intel_syntax = -intel_syntax; + exp->X_md = 0; if (size == 4 || (object_64bit && size == 8)) { /* Handle @GOTOFF and the like in an expression. */ @@ -6477,7 +6487,7 @@ x86_cons (expressionS *exp, int size) if (exp->X_op == O_constant || exp->X_op == O_absent || exp->X_op == O_illegal - || exp->X_op == O_register + || i386_is_register (exp, intel_syntax) || exp->X_op == O_big) { char c = *input_line_pointer; @@ -7956,7 +7966,7 @@ parse_register (char *reg_string, char **end_op) { const expressionS *e = symbol_get_value_expression (symbolP); - know (e->X_op == O_register); + know (i386_is_register (e, intel_syntax)); know (e->X_add_number >= 0 && (valueT) e->X_add_number < i386_regtab_size); r = i386_regtab + e->X_add_number; @@ -8863,7 +8873,7 @@ tc_x86_parse_to_dw2regnum (expressionS *exp) register_chars['.'] = saved_register_dot; allow_naked_reg = saved_naked_reg; - if (exp->X_op == O_register && exp->X_add_number >= 0) + if (i386_is_register (exp, intel_syntax) && exp->X_add_number >= 0) { if ((addressT) exp->X_add_number < i386_regtab_size) { -- cgit v1.1