diff options
Diffstat (limited to 'gas/config/tc-i386.c')
-rw-r--r-- | gas/config/tc-i386.c | 227 |
1 files changed, 106 insertions, 121 deletions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 04640d2..f7d488c 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -425,14 +425,6 @@ enum x86_elf_abi static enum x86_elf_abi x86_elf_abi = I386_ABI; #endif -/* The names used to print error messages. */ -static const char *flag_code_names[] = - { - "32", - "16", - "64" - }; - /* 1 for intel syntax, 0 if att syntax. */ static int intel_syntax = 0; @@ -7420,14 +7412,55 @@ i386_finalize_displacement (segT exp_seg ATTRIBUTE_UNUSED, expressionS *exp, static int i386_index_check (const char *operand_string) { - int ok; const char *kind = "base/index"; + enum flag_code addr_mode; + + if (i.prefix[ADDR_PREFIX]) + addr_mode = flag_code == CODE_32BIT ? CODE_16BIT : CODE_32BIT; + else + { + addr_mode = flag_code; + #if INFER_ADDR_PREFIX - int fudged = 0; + if (i.mem_operands == 0) + { + /* Infer address prefix from the first memory operand. */ + const reg_entry *addr_reg = i.base_reg; + + if (addr_reg == NULL) + addr_reg = i.index_reg; - tryprefix: + if (addr_reg) + { + if (addr_reg->reg_num == RegEip + || addr_reg->reg_num == RegEiz + || addr_reg->reg_type.bitfield.reg32) + addr_mode = CODE_32BIT; + else if (flag_code != CODE_64BIT + && addr_reg->reg_type.bitfield.reg16) + addr_mode = CODE_16BIT; + + if (addr_mode != flag_code) + { + i.prefix[ADDR_PREFIX] = ADDR_PREFIX_OPCODE; + i.prefixes += 1; + /* Change the size of any displacement too. At most one + of Disp16 or Disp32 is set. + FIXME. There doesn't seem to be any real need for + separate Disp16 and Disp32 flags. The same goes for + Imm16 and Imm32. Removing them would probably clean + up the code quite a lot. */ + if (flag_code != CODE_64BIT + && (i.types[this_operand].bitfield.disp16 + || i.types[this_operand].bitfield.disp32)) + i.types[this_operand] + = operand_type_xor (i.types[this_operand], disp16_32); + } + } + } #endif - ok = 1; + } + if (current_templates->start->opcode_modifier.isstring && !current_templates->start->opcode_modifier.immext && (current_templates->end[-1].opcode_modifier.isstring @@ -7435,7 +7468,14 @@ i386_index_check (const char *operand_string) { /* Memory operands of string insns are special in that they only allow a single register (rDI, rSI, or rBX) as their memory address. */ - unsigned int expected; + const reg_entry *expected_reg; + static const char *di_si[][2] = + { + { "esi", "edi" }, + { "si", "di" }, + { "rsi", "rdi" } + }; + static const char *bx[] = { "ebx", "bx", "rbx" }; kind = "string address"; @@ -7448,77 +7488,70 @@ i386_index_check (const char *operand_string) && current_templates->end[-1].operand_types[1] .bitfield.baseindex)) type = current_templates->end[-1].operand_types[1]; - expected = type.bitfield.esseg ? 7 /* rDI */ : 6 /* rSI */; + expected_reg = hash_find (reg_hash, + di_si[addr_mode][type.bitfield.esseg]); + } else - expected = 3 /* rBX */; + expected_reg = hash_find (reg_hash, bx[addr_mode]); - if (!i.base_reg || i.index_reg + if (i.base_reg != expected_reg + || i.index_reg || operand_type_check (i.types[this_operand], disp)) - ok = -1; - else if (!(flag_code == CODE_64BIT - ? i.prefix[ADDR_PREFIX] - ? i.base_reg->reg_type.bitfield.reg32 - : i.base_reg->reg_type.bitfield.reg64 - : (flag_code == CODE_16BIT) ^ !i.prefix[ADDR_PREFIX] - ? i.base_reg->reg_type.bitfield.reg32 - : i.base_reg->reg_type.bitfield.reg16)) - ok = 0; - else if (register_number (i.base_reg) != expected) - ok = -1; - - if (ok < 0) - { - unsigned int j; - - for (j = 0; j < i386_regtab_size; ++j) - if ((flag_code == CODE_64BIT - ? i.prefix[ADDR_PREFIX] - ? i386_regtab[j].reg_type.bitfield.reg32 - : i386_regtab[j].reg_type.bitfield.reg64 - : (flag_code == CODE_16BIT) ^ !i.prefix[ADDR_PREFIX] - ? i386_regtab[j].reg_type.bitfield.reg32 - : i386_regtab[j].reg_type.bitfield.reg16) - && register_number(i386_regtab + j) == expected) - break; - gas_assert (j < i386_regtab_size); + { + /* The second memory operand must have the same size as + the first one. */ + if (i.mem_operands + && i.base_reg + && !((addr_mode == CODE_64BIT + && i.base_reg->reg_type.bitfield.reg64) + || (addr_mode == CODE_32BIT + ? i.base_reg->reg_type.bitfield.reg32 + : i.base_reg->reg_type.bitfield.reg16))) + goto bad_address; + as_warn (_("`%s' is not valid here (expected `%c%s%s%c')"), operand_string, intel_syntax ? '[' : '(', register_prefix, - i386_regtab[j].reg_name, + expected_reg->reg_name, intel_syntax ? ']' : ')'); - ok = 1; - } - } - else if (flag_code == CODE_64BIT) - { - if ((i.base_reg - && ((i.prefix[ADDR_PREFIX] == 0 - && !i.base_reg->reg_type.bitfield.reg64) - || (i.prefix[ADDR_PREFIX] - && !i.base_reg->reg_type.bitfield.reg32)) - && (i.index_reg - || i.base_reg->reg_num != - (i.prefix[ADDR_PREFIX] == 0 ? RegRip : RegEip))) - || (i.index_reg - && !(i.index_reg->reg_type.bitfield.regxmm - || i.index_reg->reg_type.bitfield.regymm) - && (!i.index_reg->reg_type.bitfield.baseindex - || (i.prefix[ADDR_PREFIX] == 0 - && i.index_reg->reg_num != RegRiz - && !i.index_reg->reg_type.bitfield.reg64 - ) - || (i.prefix[ADDR_PREFIX] - && i.index_reg->reg_num != RegEiz - && !i.index_reg->reg_type.bitfield.reg32)))) - ok = 0; + return 1; + } + else + return 1; + +bad_address: + as_bad (_("`%s' is not a valid %s expression"), + operand_string, kind); + return 0; } else { - if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0)) + if (addr_mode != CODE_16BIT) + { + /* 32-bit/64-bit checks. */ + if ((i.base_reg + && (addr_mode == CODE_64BIT + ? !i.base_reg->reg_type.bitfield.reg64 + : !i.base_reg->reg_type.bitfield.reg32) + && (i.index_reg + || (i.base_reg->reg_num + != (addr_mode == CODE_64BIT ? RegRip : RegEip)))) + || (i.index_reg + && !i.index_reg->reg_type.bitfield.regxmm + && !i.index_reg->reg_type.bitfield.regymm + && ((addr_mode == CODE_64BIT + ? !(i.index_reg->reg_type.bitfield.reg64 + || i.index_reg->reg_num == RegRiz) + : !(i.index_reg->reg_type.bitfield.reg32 + || i.index_reg->reg_num == RegEiz)) + || !i.index_reg->reg_type.bitfield.baseindex))) + goto bad_address; + } + else { - /* 16bit checks. */ + /* 16-bit checks. */ if ((i.base_reg && (!i.base_reg->reg_type.bitfield.reg16 || !i.base_reg->reg_type.bitfield.baseindex)) @@ -7529,58 +7562,10 @@ i386_index_check (const char *operand_string) && i.base_reg->reg_num < 6 && i.index_reg->reg_num >= 6 && i.log2_scale_factor == 0)))) - ok = 0; - } - else - { - /* 32bit checks. */ - if ((i.base_reg - && !i.base_reg->reg_type.bitfield.reg32) - || (i.index_reg - && !i.index_reg->reg_type.bitfield.regxmm - && !i.index_reg->reg_type.bitfield.regymm - && ((!i.index_reg->reg_type.bitfield.reg32 - && i.index_reg->reg_num != RegEiz) - || !i.index_reg->reg_type.bitfield.baseindex))) - ok = 0; + goto bad_address; } } - if (!ok) - { -#if INFER_ADDR_PREFIX - if (!i.mem_operands && !i.prefix[ADDR_PREFIX]) - { - i.prefix[ADDR_PREFIX] = ADDR_PREFIX_OPCODE; - i.prefixes += 1; - /* Change the size of any displacement too. At most one of - Disp16 or Disp32 is set. - FIXME. There doesn't seem to be any real need for separate - Disp16 and Disp32 flags. The same goes for Imm16 and Imm32. - Removing them would probably clean up the code quite a lot. */ - if (flag_code != CODE_64BIT - && (i.types[this_operand].bitfield.disp16 - || i.types[this_operand].bitfield.disp32)) - i.types[this_operand] - = operand_type_xor (i.types[this_operand], disp16_32); - fudged = 1; - goto tryprefix; - } - if (fudged) - as_bad (_("`%s' is not a valid %s expression"), - operand_string, - kind); - else -#endif - as_bad (_("`%s' is not a valid %s-bit %s expression"), - operand_string, - flag_code_names[i.prefix[ADDR_PREFIX] - ? flag_code == CODE_32BIT - ? CODE_16BIT - : CODE_32BIT - : flag_code], - kind); - } - return ok; + return 1; } /* Parse OPERAND_STRING into the i386_insn structure I. Returns zero |