aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-i386.c
diff options
context:
space:
mode:
Diffstat (limited to 'gas/config/tc-i386.c')
-rw-r--r--gas/config/tc-i386.c227
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