X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-i386-intel.c;h=aefdc2a9c7cb4f5968143fee1864e7f5dbdd31f5;hb=5c111e376966558968049df5839776067729d3c8;hp=e7a53889e534519724afded650fe60fa6c9c84c3;hpb=ee86248ceef0286d7b2b074a88718176ebd6ada6;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-i386-intel.c b/gas/config/tc-i386-intel.c index e7a53889e5..aefdc2a9c7 100644 --- a/gas/config/tc-i386-intel.c +++ b/gas/config/tc-i386-intel.c @@ -1,5 +1,5 @@ /* tc-i386.c -- Assemble Intel syntax code for ix86/x86-64 - Copyright 2009 + Copyright 2009, 2010 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -23,6 +23,8 @@ static struct { operatorT op_modifier; /* Operand modifier. */ int is_mem; /* 1 if operand is memory reference. */ + int is_indirect; /* 1 if operand is indirect reference. */ + int has_offset; /* 1 if operand has offset. */ unsigned int in_offset; /* >=1 if processing operand of offset. */ unsigned int in_bracket; /* >=1 if processing operand in brackets. */ unsigned int in_scale; /* >=1 if processing multipication operand @@ -37,35 +39,35 @@ intel_state; /* offset X_add_symbol */ #define O_offset O_md32 +/* offset X_add_symbol */ +#define O_short O_md31 +/* near ptr X_add_symbol */ +#define O_near_ptr O_md30 +/* far ptr X_add_symbol */ +#define O_far_ptr O_md29 /* byte ptr X_add_symbol */ -#define O_byte_ptr O_md31 +#define O_byte_ptr O_md28 /* word ptr X_add_symbol */ -#define O_word_ptr O_md30 +#define O_word_ptr O_md27 /* dword ptr X_add_symbol */ -#define O_dword_ptr O_md29 +#define O_dword_ptr O_md26 /* qword ptr X_add_symbol */ -#define O_qword_ptr O_md28 +#define O_qword_ptr O_md25 /* oword ptr X_add_symbol */ -#define O_oword_ptr O_md27 +#define O_oword_ptr O_md24 /* fword ptr X_add_symbol */ -#define O_fword_ptr O_md26 +#define O_fword_ptr O_md23 /* tbyte ptr X_add_symbol */ -#define O_tbyte_ptr O_md25 +#define O_tbyte_ptr O_md22 /* xmmword ptr X_add_symbol */ -#define O_xmmword_ptr O_md24 +#define O_xmmword_ptr O_md21 /* ymmword ptr X_add_symbol */ -#define O_ymmword_ptr O_md23 -/* near ptr X_add_symbol */ -#define O_near_ptr O_md22 -/* far ptr X_add_symbol */ -#define O_far_ptr O_md21 -/* offset X_add_symbol */ -#define O_short O_md20 +#define O_ymmword_ptr O_md20 static struct { const char *name; - operatorT operator; + operatorT op; unsigned int operands; } const i386_operators[] = @@ -91,7 +93,7 @@ const i386_operators[] = static struct { const char *name; - operatorT operator; + operatorT op; unsigned short sz[3]; } const i386_types[] = @@ -153,33 +155,33 @@ operatorT i386_operator (const char *name, unsigned int operands, char *pc) } for (j = 0; i386_operators[j].name; ++j) - if (strcasecmp(i386_operators[j].name, name) == 0) + if (strcasecmp (i386_operators[j].name, name) == 0) { if (i386_operators[j].operands && i386_operators[j].operands != operands) return O_illegal; - return i386_operators[j].operator; + return i386_operators[j].op; } for (j = 0; i386_types[j].name; ++j) - if (strcasecmp(i386_types[j].name, name) == 0) + if (strcasecmp (i386_types[j].name, name) == 0) break; if (i386_types[j].name && *pc == ' ') { - char *name = ++input_line_pointer; + char *pname = ++input_line_pointer; char c = get_symbol_end (); - if (strcasecmp (name, "ptr") == 0) + if (strcasecmp (pname, "ptr") == 0) { - name[-1] = *pc; + pname[-1] = *pc; *pc = c; if (intel_syntax > 0 || operands != 1) return O_illegal; - return i386_types[j].operator; + return i386_types[j].op; } *input_line_pointer = c; - input_line_pointer = name - 1; + input_line_pointer = pname - 1; } return O_absent; @@ -187,13 +189,19 @@ operatorT i386_operator (const char *name, unsigned int operands, char *pc) static int i386_intel_parse_name (const char *name, expressionS *e) { - unsigned int i; + unsigned int j; + + if (! strcmp (name, "$")) + { + current_location (e); + return 1; + } - for (i = 0; i386_types[i].name; ++i) - if (strcasecmp(i386_types[i].name, name) == 0) + for (j = 0; i386_types[j].name; ++j) + if (strcasecmp(i386_types[j].name, name) == 0) { e->X_op = O_constant; - e->X_add_number = i386_types[i].sz[flag_code]; + e->X_add_number = i386_types[j].sz[flag_code]; e->X_add_symbol = NULL; e->X_op_symbol = NULL; return 1; @@ -202,12 +210,14 @@ static int i386_intel_parse_name (const char *name, expressionS *e) return 0; } -static INLINE int i386_intel_check (const reg_entry *reg, +static INLINE int i386_intel_check (const reg_entry *rreg, const reg_entry *base, - const reg_entry *index) + const reg_entry *iindex) { - if ((this_operand >= 0 && reg != i.op[this_operand].regs) - || base != intel_state.base || index != intel_state.index) + if ((this_operand >= 0 + && rreg != i.op[this_operand].regs) + || base != intel_state.base + || iindex != intel_state.index) { as_bad (_("invalid use of register")); return 0; @@ -217,21 +227,83 @@ static INLINE int i386_intel_check (const reg_entry *reg, static INLINE void i386_intel_fold (expressionS *e, symbolS *sym) { + expressionS *exp = symbol_get_value_expression (sym); if (S_GET_SEGMENT (sym) == absolute_section) { offsetT val = e->X_add_number; - *e = *symbol_get_value_expression (sym); + *e = *exp; e->X_add_number += val; } else { + if (exp->X_op == O_symbol + && strcmp (S_GET_NAME (exp->X_add_symbol), + GLOBAL_OFFSET_TABLE_NAME) == 0) + sym = exp->X_add_symbol; e->X_add_symbol = sym; e->X_op_symbol = NULL; e->X_op = O_symbol; } } +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.index + && (i386_regtab[reg_num].reg_type.bitfield.regxmm + || i386_regtab[reg_num].reg_type.bitfield.regymm)) + intel_state.index = 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) + { + if (intel_state.in_scale + || i386_regtab[reg_num].reg_type.bitfield.baseindex) + intel_state.index = i386_regtab + reg_num; + else + { + /* Convert base to index and make ESP/RSP the base. */ + intel_state.index = intel_state.base; + intel_state.base = i386_regtab + reg_num; + } + } + else + { + /* esp is invalid as index */ + intel_state.index = i386_regtab + REGNAM_EAX + ESP_REG_NUM; + } + return 2; +} + static int i386_intel_simplify (expressionS *); static INLINE int i386_intel_simplify_symbol(symbolS *sym) @@ -248,9 +320,10 @@ static INLINE int i386_intel_simplify_symbol(symbolS *sym) static int i386_intel_simplify (expressionS *e) { - const reg_entry *reg = this_operand >= 0 ? i.op[this_operand].regs : NULL; + const reg_entry *the_reg = (this_operand >= 0 + ? i.op[this_operand].regs : NULL); const reg_entry *base = intel_state.base; - const reg_entry *index = intel_state.index; + const reg_entry *state_index = intel_state.index; int ret; if (!intel_syntax) @@ -262,8 +335,9 @@ static int i386_intel_simplify (expressionS *e) if (e->X_add_symbol) { if (!i386_intel_simplify_symbol (e->X_add_symbol) - || !i386_intel_check(reg, intel_state.base, intel_state.index)) - return 0;; + || !i386_intel_check(the_reg, intel_state.base, + intel_state.index)) + return 0; } if (!intel_state.in_offset) ++intel_state.in_bracket; @@ -279,10 +353,11 @@ static int i386_intel_simplify (expressionS *e) break; case O_offset: + intel_state.has_offset = 1; ++intel_state.in_offset; ret = i386_intel_simplify_symbol (e->X_add_symbol); --intel_state.in_offset; - if (!ret || !i386_intel_check(reg, base, index)) + if (!ret || !i386_intel_check(the_reg, base, state_index)) return 0; i386_intel_fold (e, e->X_add_symbol); return ret; @@ -302,7 +377,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 (symbol_get_value_expression (e->X_add_symbol)->X_op + == O_register) { as_bad (_("invalid use of register")); return 0; @@ -313,53 +389,21 @@ 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 (symbol_get_value_expression (e->X_op_symbol)->X_op + == O_register) { as_bad (_("invalid use of register")); return 0; } if (!i386_intel_simplify_symbol (e->X_op_symbol) - || !i386_intel_check(reg, intel_state.base, intel_state.index)) + || !i386_intel_check(the_reg, intel_state.base, + intel_state.index)) return 0; if (!intel_state.in_offset) intel_state.seg = e->X_add_symbol; 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) { @@ -410,31 +454,55 @@ static int i386_intel_simplify (expressionS *e) break; default: /* esp is invalid as index */ - intel_state.index = i386_regtab + REGNAM_EAX + 4; + intel_state.index = i386_regtab + REGNAM_EAX + ESP_REG_NUM; break; } break; } + goto fallthrough; + + 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)) +fallthrough: + if (e->X_add_symbol + && !i386_intel_simplify_symbol (e->X_add_symbol)) return 0; if (e->X_op == O_add || e->X_op == O_subtract) { base = intel_state.base; - index = intel_state.index; + state_index = intel_state.index; } - if (!i386_intel_check (reg, base, index) - || (e->X_op_symbol && !i386_intel_simplify_symbol (e->X_op_symbol)) - || !i386_intel_check (reg, - e->X_op != O_add ? base : intel_state.base, - e->X_op != O_add ? index : intel_state.index)) + if (!i386_intel_check (the_reg, base, state_index) + || (e->X_op_symbol + && !i386_intel_simplify_symbol (e->X_op_symbol)) + || !i386_intel_check (the_reg, + (e->X_op != O_add + ? base : intel_state.base), + (e->X_op != O_add + ? state_index : intel_state.index))) return 0; break; } - if (this_operand >= 0 && e->X_op == O_symbol && !intel_state.in_offset) + if (this_operand >= 0 + && e->X_op == O_symbol + && !intel_state.in_offset) { segT seg = S_GET_SEGMENT (e->X_add_symbol); @@ -464,13 +532,15 @@ i386_intel_operand (char *operand_string, int got_a_float) /* Initialize state structure. */ intel_state.op_modifier = O_absent; intel_state.is_mem = 0; + intel_state.is_indirect = 0; + intel_state.has_offset = 0; intel_state.base = NULL; intel_state.index = NULL; intel_state.seg = NULL; operand_type_set (&intel_state.reloc_types, ~0); - assert (!intel_state.in_offset); - assert (!intel_state.in_bracket); - assert (!intel_state.in_scale); + gas_assert (!intel_state.in_offset); + gas_assert (!intel_state.in_bracket); + gas_assert (!intel_state.in_scale); saved_input_line_pointer = input_line_pointer; input_line_pointer = buf = xstrdup (operand_string); @@ -492,13 +562,20 @@ i386_intel_operand (char *operand_string, int got_a_float) as_bad (_("invalid expression")); ret = 0; } + else if (!intel_state.has_offset + && input_line_pointer > buf + && *(input_line_pointer - 1) == ']') + { + intel_state.is_mem |= 1; + intel_state.is_indirect = 1; + } input_line_pointer = saved_input_line_pointer; free (buf); - assert (!intel_state.in_offset); - assert (!intel_state.in_bracket); - assert (!intel_state.in_scale); + gas_assert (!intel_state.in_offset); + gas_assert (!intel_state.in_bracket); + gas_assert (!intel_state.in_scale); if (!ret) return 0; @@ -619,7 +696,9 @@ i386_intel_operand (char *operand_string, int got_a_float) || current_templates->start->opcode_modifier.jumpdword || current_templates->start->opcode_modifier.jumpintersegment) { - if (i.op[this_operand].regs || intel_state.base || intel_state.index + if (i.op[this_operand].regs + || intel_state.base + || intel_state.index || intel_state.is_mem > 1) i.types[this_operand].bitfield.jumpabsolute = 1; else @@ -637,7 +716,11 @@ i386_intel_operand (char *operand_string, int got_a_float) { intel_state.is_mem = 1; if (intel_state.op_modifier == O_absent) - break; + { + if (intel_state.is_indirect == 1) + i.types[this_operand].bitfield.jumpabsolute = 1; + break; + } as_bad (_("cannot infer the segment part of the operand")); return 0; } @@ -698,17 +781,65 @@ i386_intel_operand (char *operand_string, int got_a_float) temp = i.op[this_operand].regs->reg_type; temp.bitfield.baseindex = 0; - i.types[this_operand] = operand_type_or (i.types[this_operand], temp); + i.types[this_operand] = operand_type_or (i.types[this_operand], + temp); i.types[this_operand].bitfield.unspecified = 0; ++i.reg_operands; } - else if (intel_state.base || intel_state.index || intel_state.seg + else if (intel_state.base + || intel_state.index + || intel_state.seg || intel_state.is_mem) { /* Memory operand. */ if (i.mem_operands >= 2 - !current_templates->start->opcode_modifier.isstring) { + /* Handle + + call 0x9090,0x90909090 + lcall 0x9090,0x90909090 + jmp 0x9090,0x90909090 + ljmp 0x9090,0x90909090 + */ + + if ((current_templates->start->opcode_modifier.jumpintersegment + || current_templates->start->opcode_modifier.jumpdword + || current_templates->start->opcode_modifier.jump) + && this_operand == 1 + && intel_state.seg == NULL + && i.mem_operands == 1 + && i.disp_operands == 1 + && intel_state.op_modifier == O_absent) + { + /* Try to process the first operand as immediate, */ + this_operand = 0; + if (i386_finalize_immediate (exp_seg, i.op[0].imms, + intel_state.reloc_types, + NULL)) + { + this_operand = 1; + expP = &im_expressions[0]; + i.op[this_operand].imms = expP; + *expP = exp; + + /* Try to process the second operand as immediate, */ + if (i386_finalize_immediate (exp_seg, expP, + intel_state.reloc_types, + NULL)) + { + i.mem_operands = 0; + i.disp_operands = 0; + i.imm_operands = 2; + i.types[0].bitfield.mem = 0; + i.types[0].bitfield.disp16 = 0; + i.types[0].bitfield.disp32 = 0; + i.types[0].bitfield.disp32s = 0; + return 1; + } + } + } + as_bad (_("too many memory references for `%s'"), current_templates->start->name); return 0; @@ -718,8 +849,10 @@ i386_intel_operand (char *operand_string, int got_a_float) memcpy (expP, &exp, sizeof(exp)); resolve_expression (expP); - if (expP->X_op != O_constant || expP->X_add_number - || (!intel_state.base && !intel_state.index)) + if (expP->X_op != O_constant + || expP->X_add_number + || (!intel_state.base + && !intel_state.index)) { i.op[this_operand].disps = expP; i.disp_operands++;