/* tc-i386.c -- Assemble code for the Intel 80386
Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
static void set_code_flag (int);
static void set_16bit_gcc_code_flag (int);
static void set_intel_syntax (int);
+static void set_intel_mnemonic (int);
static void set_allow_index_reg (int);
static void set_cpu_arch (int);
#ifdef TE_PE
#endif
static void signed_cons (int);
static char *output_invalid (int c);
-static int i386_operand (char *);
+static int i386_att_operand (char *);
static int i386_intel_operand (char *, int);
static const reg_entry *parse_register (char *, char **);
static char *parse_insn (char *, char *);
CODE_32BIT,
CODE_16BIT,
CODE_64BIT };
-#define NUM_FLAG_CODE ((int) CODE_64BIT + 1)
static enum flag_code flag_code;
static unsigned int object_64bit;
0 if att syntax. */
static int intel_syntax = 0;
+/* 1 for intel mnemonic,
+ 0 if att mnemonic. */
+static int intel_mnemonic = !SYSV386_COMPAT;
+
+/* 1 if support old (<= 2.8.1) versions of gcc. */
+static int old_gcc = OLDGCC_COMPAT;
+
/* 1 if register prefix % not required. */
static int allow_naked_reg = 0;
-/* 1 if fake index register, eiz/riz, is allowed . */
+/* 1 if pseudo index register, eiz/riz, is allowed . */
static int allow_index_reg = 0;
/* Register prefix used for error message. */
/* CPU feature flags. */
static i386_cpu_flags cpu_arch_flags = CPU_UNKNOWN_FLAGS;
-/* Bitwise NOT of cpu_arch_flags. */
-static i386_cpu_flags cpu_arch_flags_not;
-
/* If we have selected a cpu we are generating instructions for. */
static int cpu_arch_tune_set = 0;
{"code64", set_code_flag, CODE_64BIT},
{"intel_syntax", set_intel_syntax, 1},
{"att_syntax", set_intel_syntax, 0},
+ {"intel_mnemonic", set_intel_mnemonic, 1},
+ {"att_mnemonic", set_intel_mnemonic, 0},
{"allow_index_reg", set_allow_index_reg, 1},
{"disallow_index_reg", set_allow_index_reg, 0},
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
}
static INLINE i386_cpu_flags
-cpu_flags_not (i386_cpu_flags x)
-{
- switch (ARRAY_SIZE (x.array))
- {
- case 3:
- x.array [2] = ~x.array [2];
- case 2:
- x.array [1] = ~x.array [1];
- case 1:
- x.array [0] = ~x.array [0];
- break;
- default:
- abort ();
- }
-
-#ifdef CpuUnused
- x.bitfield.unused = 0;
-#endif
-
- return x;
-}
-
-static INLINE i386_cpu_flags
cpu_flags_and (i386_cpu_flags x, i386_cpu_flags y)
{
switch (ARRAY_SIZE (x.array))
return x;
}
+/* Return 3 if there is a perfect match, 2 if compatible with 64bit,
+ 1 if compatible with arch, 0 if there is no match. */
+
static int
cpu_flags_match (i386_cpu_flags x)
{
- i386_cpu_flags not = cpu_arch_flags_not;
-
- not.bitfield.cpu64 = 1;
- not.bitfield.cpuno64 = 1;
+ int overlap = cpu_flags_check_cpu64 (x) ? 2 : 0;
x.bitfield.cpu64 = 0;
x.bitfield.cpuno64 = 0;
- not = cpu_flags_and (x, not);
- return UINTS_ALL_ZERO (not);
+ if (UINTS_ALL_ZERO (x))
+ overlap |= 1;
+ else
+ {
+ i386_cpu_flags cpu = cpu_arch_flags;
+
+ cpu.bitfield.cpu64 = 0;
+ cpu.bitfield.cpuno64 = 0;
+ cpu = cpu_flags_and (x, cpu);
+ overlap |= UINTS_ALL_ZERO (cpu) ? 0 : 1;
+ }
+ return overlap;
}
static INLINE i386_operand_type
{
cpu_arch_flags.bitfield.cpu64 = 1;
cpu_arch_flags.bitfield.cpuno64 = 0;
- cpu_arch_flags_not.bitfield.cpu64 = 0;
- cpu_arch_flags_not.bitfield.cpuno64 = 1;
}
else
{
cpu_arch_flags.bitfield.cpu64 = 0;
cpu_arch_flags.bitfield.cpuno64 = 1;
- cpu_arch_flags_not.bitfield.cpu64 = 1;
- cpu_arch_flags_not.bitfield.cpuno64 = 0;
}
if (value == CODE_64BIT && !cpu_arch_flags.bitfield.cpulm )
{
abort ();
cpu_arch_flags.bitfield.cpu64 = 0;
cpu_arch_flags.bitfield.cpuno64 = 1;
- cpu_arch_flags_not.bitfield.cpu64 = 1;
- cpu_arch_flags_not.bitfield.cpuno64 = 0;
stackop_size = LONG_MNEM_SUFFIX;
}
}
static void
+set_intel_mnemonic (int mnemonic_flag)
+{
+ intel_mnemonic = mnemonic_flag;
+}
+
+static void
set_allow_index_reg (int flag)
{
allow_index_reg = flag;
cpu_arch_flags.bitfield.cpu64 = 0;
cpu_arch_flags.bitfield.cpuno64 = 1;
}
- cpu_arch_flags_not = cpu_flags_not (cpu_arch_flags);
cpu_arch_isa = cpu_arch[i].type;
cpu_arch_isa_flags = cpu_arch[i].flags;
if (!cpu_arch_tune_set)
{
cpu_sub_arch_name = cpu_arch[i].name;
cpu_arch_flags = flags;
- cpu_arch_flags_not = cpu_flags_not (cpu_arch_flags);
}
*input_line_pointer = e;
demand_empty_rest_of_line ();
{
const char *hash_err;
- cpu_arch_flags_not = cpu_flags_not (cpu_arch_flags);
-
/* Initialize op_hash hash table. */
op_hash = hash_new ();
if (intel_syntax)
{
- /* Undo SYSV386_COMPAT brokenness when in Intel mode. See i386.h */
- if (SYSV386_COMPAT
- && (i.tm.base_opcode & 0xfffffde0) == 0xdce0)
- i.tm.base_opcode ^= Opcode_FloatR;
-
/* Zap movzx and movsx suffix. The suffix may have been set from
"word ptr" or "byte ptr" on the source operand, but we'll use
the suffix later to choose the destination register. */
|| !i.tm.opcode_modifier.no_wsuf
|| !i.tm.opcode_modifier.no_lsuf
|| !i.tm.opcode_modifier.no_ssuf
- || !i.tm.opcode_modifier.no_xsuf
+ || !i.tm.opcode_modifier.no_ldsuf
|| !i.tm.opcode_modifier.no_qsuf))
as_bad (_("ambiguous operand size for `%s'"), i.tm.name);
supported = 0;
for (t = current_templates->start; t < current_templates->end; ++t)
{
- if (cpu_flags_match (t->cpu_flags))
- supported |= 1;
- if (cpu_flags_check_cpu64 (t->cpu_flags))
- supported |= 2;
+ supported |= cpu_flags_match (t->cpu_flags);
+ if (supported == 3)
+ goto skip;
}
+
if (!(supported & 2))
{
as_bad (flag_code == CODE_64BIT
}
if (!(supported & 1))
{
- as_warn (_("`%s' is not supported on `%s%s'"),
- current_templates->start->name,
- cpu_arch_name,
- cpu_sub_arch_name ? cpu_sub_arch_name : "");
+ as_bad (_("`%s' is not supported on `%s%s'"),
+ current_templates->start->name, cpu_arch_name,
+ cpu_sub_arch_name ? cpu_sub_arch_name : "");
+ return NULL;
}
- else if (!cpu_arch_flags.bitfield.cpui386
+
+skip:
+ if (!cpu_arch_flags.bitfield.cpui386
&& (flag_code != CODE_16BIT))
{
as_warn (_("use .code16 to ensure correct addressing mode"));
i386_intel_operand (token_start,
intel_float_operand (mnemonic));
else
- operand_ok = i386_operand (token_start);
+ operand_ok = i386_att_operand (token_start);
RESTORE_END_STRING (l);
if (!operand_ok)
i386_operand_type operand_types [MAX_OPERANDS];
int addr_prefix_disp;
unsigned int j;
- i386_cpu_flags overlap;
+ unsigned int found_cpu_match;
+ unsigned int check_register;
#if MAX_OPERANDS != 4
# error "MAX_OPERANDS must be 4."
else if (i.suffix == QWORD_MNEM_SUFFIX)
suffix_check.no_qsuf = 1;
else if (i.suffix == LONG_DOUBLE_MNEM_SUFFIX)
- suffix_check.no_xsuf = 1;
+ suffix_check.no_ldsuf = 1;
+ else if (i.suffix == XMMWORD_MNEM_SUFFIX)
+ suffix_check.xmmword = 1;
for (t = current_templates->start; t < current_templates->end; t++)
{
if (i.operands != t->operands)
continue;
+ /* Check old gcc support. */
+ if (!old_gcc && t->opcode_modifier.oldgcc)
+ continue;
+
+ /* Check AT&T mnemonic. */
+ if (intel_mnemonic && t->opcode_modifier.attmnemonic)
+ continue;
+
+ /* Check Intel syntax. */
+ if (intel_syntax && t->opcode_modifier.attsyntax)
+ continue;
+
/* Check the suffix, except for some instructions in intel mode. */
- if (((t->opcode_modifier.no_bsuf & suffix_check.no_bsuf)
- || (t->opcode_modifier.no_wsuf & suffix_check.no_wsuf)
- || (t->opcode_modifier.no_lsuf & suffix_check.no_lsuf)
- || (t->opcode_modifier.no_ssuf & suffix_check.no_ssuf)
- || (t->opcode_modifier.no_qsuf & suffix_check.no_qsuf)
- || (t->opcode_modifier.no_xsuf & suffix_check.no_xsuf))
- && !(intel_syntax && t->opcode_modifier.ignoresize))
+ if ((!intel_syntax || !t->opcode_modifier.ignoresize)
+ && ((t->opcode_modifier.no_bsuf && suffix_check.no_bsuf)
+ || (t->opcode_modifier.no_wsuf && suffix_check.no_wsuf)
+ || (t->opcode_modifier.no_lsuf && suffix_check.no_lsuf)
+ || (t->opcode_modifier.no_ssuf && suffix_check.no_ssuf)
+ || (t->opcode_modifier.no_qsuf && suffix_check.no_qsuf)
+ || (t->opcode_modifier.no_ldsuf && suffix_check.no_ldsuf)))
+ continue;
+
+ /* Check the memory size in Intel mode when it is provided if
+ needed. */
+ if (intel_syntax
+ && i.suffix
+ && t->opcode_modifier.checksize
+ && (!t->opcode_modifier.byte || !suffix_check.no_bsuf)
+ && (!t->opcode_modifier.word || !suffix_check.no_wsuf)
+ && (!t->opcode_modifier.dword || !suffix_check.no_lsuf)
+ && (!t->opcode_modifier.qword || !suffix_check.no_qsuf)
+ && (!t->opcode_modifier.xmmword || !suffix_check.xmmword))
continue;
for (j = 0; j < MAX_OPERANDS; j++)
/* Do not verify operands when there are none. */
else
{
- overlap = cpu_flags_and (t->cpu_flags, cpu_arch_flags_not);
+ found_cpu_match = cpu_flags_match (t->cpu_flags) == 3;
if (!t->operands)
{
- if (!UINTS_ALL_ZERO (overlap))
+ if (!found_cpu_match)
continue;
/* We've found a match; break out of loop. */
break;
}
}
+ /* We check register size only if size of operands can be
+ encoded the canonical way. */
+ check_register = t->opcode_modifier.w;
overlap0 = operand_type_and (i.types[0], operand_types[0]);
switch (t->operands)
{
overlap1 = operand_type_and (i.types[1], operand_types[1]);
if (!operand_type_match (overlap0, i.types[0])
|| !operand_type_match (overlap1, i.types[1])
- /* monitor in SSE3 is a very special case. The first
- register and the second register may have different
- sizes. The same applies to crc32 in SSE4.2. It is
- also true for invlpga, vmload, vmrun and vmsave in
- SVME. */
- || !((t->base_opcode == 0x0f01
- && (t->extension_opcode == 0xc8
- || t->extension_opcode == 0xd8
- || t->extension_opcode == 0xda
- || t->extension_opcode == 0xdb
- || t->extension_opcode == 0xdf))
- || t->base_opcode == 0xf20f38f1
- || operand_type_register_match (overlap0, i.types[0],
+ || (check_register
+ && !operand_type_register_match (overlap0, i.types[0],
operand_types[0],
overlap1, i.types[1],
operand_types[1])))
overlap1 = operand_type_and (i.types[1], operand_types[0]);
if (!operand_type_match (overlap0, i.types[0])
|| !operand_type_match (overlap1, i.types[1])
- || !operand_type_register_match (overlap0, i.types[0],
- operand_types[1],
- overlap1, i.types[1],
- operand_types[0]))
+ || (check_register
+ && !operand_type_register_match (overlap0,
+ i.types[0],
+ operand_types[1],
+ overlap1,
+ i.types[1],
+ operand_types[0])))
{
/* Does not match either direction. */
continue;
{
case 4:
if (!operand_type_match (overlap3, i.types[3])
- || !operand_type_register_match (overlap2,
- i.types[2],
- operand_types[2],
- overlap3,
- i.types[3],
- operand_types[3]))
+ || (check_register
+ && !operand_type_register_match (overlap2,
+ i.types[2],
+ operand_types[2],
+ overlap3,
+ i.types[3],
+ operand_types[3])))
continue;
case 3:
/* Here we make use of the fact that there are no
operand instructions only need to be checked for
register consistency between operands 2 and 3. */
if (!operand_type_match (overlap2, i.types[2])
- || !operand_type_register_match (overlap1,
- i.types[1],
- operand_types[1],
- overlap2,
- i.types[2],
- operand_types[2]))
+ || (check_register
+ && !operand_type_register_match (overlap1,
+ i.types[1],
+ operand_types[1],
+ overlap2,
+ i.types[2],
+ operand_types[2])))
continue;
break;
}
/* Found either forward/reverse 2, 3 or 4 operand match here:
slip through to break. */
}
- if (!UINTS_ALL_ZERO (overlap))
+ if (!found_cpu_match)
{
found_reverse_match = 0;
continue;
}
else if (i.suffix == QWORD_MNEM_SUFFIX)
{
- if (!check_qword_reg ())
+ if (intel_syntax
+ && i.tm.opcode_modifier.ignoresize
+ && i.tm.opcode_modifier.no_qsuf)
+ i.suffix = 0;
+ else if (!check_qword_reg ())
return 0;
}
else if (i.suffix == WORD_MNEM_SUFFIX)
if (!check_word_reg ())
return 0;
}
+ else if (i.suffix == XMMWORD_MNEM_SUFFIX)
+ {
+ /* Skip if the instruction has x suffix. match_template
+ should check if it is a valid suffix. */
+ }
else if (intel_syntax && i.tm.opcode_modifier.ignoresize)
/* Do nothing if the instruction is going to ignore the prefix. */
;
suffixes |= 1 << 1;
if (!i.tm.opcode_modifier.no_lsuf)
suffixes |= 1 << 2;
- if (!i.tm.opcode_modifier.no_lsuf)
+ if (!i.tm.opcode_modifier.no_ldsuf)
suffixes |= 1 << 3;
if (!i.tm.opcode_modifier.no_ssuf)
suffixes |= 1 << 4;
/* Change the opcode based on the operand size given by i.suffix;
We don't need to change things for byte insns. */
- if (i.suffix && i.suffix != BYTE_MNEM_SUFFIX)
+ if (i.suffix
+ && i.suffix != BYTE_MNEM_SUFFIX
+ && i.suffix != XMMWORD_MNEM_SUFFIX)
{
/* It's not a byte, select word/dword operation. */
if (i.tm.opcode_modifier.w)
/* Now select between word & dword operations via the operand
size prefix, except for instructions that will ignore this
prefix anyway. */
- if (i.tm.base_opcode == 0x0f01
- && (i.tm.extension_opcode == 0xc8
- || i.tm.extension_opcode == 0xd8
- || i.tm.extension_opcode == 0xda
- || i.tm.extension_opcode == 0xdb
- || i.tm.extension_opcode == 0xdf))
- {
- /* monitor in SSE3 is a very special case. The default size
- of AX is the size of mode. The address size override
- prefix will change the size of AX. It is also true for
- invlpga, vmload, vmrun and vmsave in SVME. */
+ if (i.tm.opcode_modifier.addrprefixop0)
+ {
+ /* The address size override prefix changes the size of the
+ first operand. */
if ((flag_code == CODE_32BIT
&& i.op->regs[0].reg_type.bitfield.reg16)
|| (flag_code != CODE_32BIT
if (i.types[op].bitfield.reg8)
continue;
- /* movzx, movsx, pextrb and pinsrb should not generate this
- warning. */
- if (intel_syntax
- && (i.tm.base_opcode == 0xfb7
- || i.tm.base_opcode == 0xfb6
- || i.tm.base_opcode == 0x63
- || i.tm.base_opcode == 0xfbe
- || i.tm.base_opcode == 0xfbf
- || i.tm.base_opcode == 0x660f3a14
- || i.tm.base_opcode == 0x660f3a20))
+ /* Don't generate this warning if not needed. */
+ if (intel_syntax && i.tm.opcode_modifier.byteokintel)
continue;
/* crc32 doesn't generate this warning. */
|| i.tm.operand_types[op].bitfield.acc))
{
if (intel_syntax
- && i.tm.base_opcode == 0xf30f2d
+ && i.tm.opcode_modifier.toqword
&& !i.types[0].bitfield.regxmm)
{
- /* cvtss2si converts DWORD memory to Reg64. We want
- REX byte. */
+ /* Convert to QWORD. We want REX byte. */
i.suffix = QWORD_MNEM_SUFFIX;
}
else
/* Prohibit these changes in the 64bit mode, since the
lowering is more complicated. */
if (intel_syntax
- && i.tm.base_opcode == 0xf20f2d
+ && i.tm.opcode_modifier.todword
&& !i.types[0].bitfield.regxmm)
{
- /* cvtsd2si converts QWORD memory to Reg32. We don't want
- REX byte. */
+ /* Convert to DWORD. We don't want REX byte. */
i.suffix = LONG_MNEM_SUFFIX;
}
else
static void
process_drex (void)
{
- i.drex.modrm_reg = None;
- i.drex.modrm_regmem = None;
+ i.drex.modrm_reg = 0;
+ i.drex.modrm_regmem = 0;
/* SSE5 4 operand instructions must have the destination the same as
one of the inputs. Figure out the destination register and cache
|| i.tm.opcode_modifier.drexc)
process_drex ();
- /* The imul $imm, %reg instruction is converted into
- imul $imm, %reg, %reg, and the clr %reg instruction
- is converted into xor %reg, %reg. */
- if (i.tm.opcode_modifier.regkludge)
- {
- if (i.tm.cpu_flags.bitfield.cpusse4_1)
- {
- /* The first operand in instruction blendvpd, blendvps and
- pblendvb in SSE4.1 is implicit and must be xmm0. */
- assert (i.operands == 3
- && i.reg_operands >= 2
- && UINTS_EQUAL (i.types[0], regxmm));
- if (i.op[0].regs->reg_num != 0)
- {
- if (intel_syntax)
- as_bad (_("the last operand of `%s' must be `%sxmm0'"),
- i.tm.name, register_prefix);
- else
- as_bad (_("the first operand of `%s' must be `%sxmm0'"),
- i.tm.name, register_prefix);
- return 0;
- }
- i.op[0] = i.op[1];
- i.op[1] = i.op[2];
- i.types[0] = i.types[1];
- i.types[1] = i.types[2];
- i.operands--;
- i.reg_operands--;
-
- /* We need to adjust fields in i.tm since they are used by
- build_modrm_byte. */
- i.tm.operand_types [0] = i.tm.operand_types [1];
- i.tm.operand_types [1] = i.tm.operand_types [2];
- i.tm.operands--;
- }
- else
- {
- unsigned int first_reg_op;
-
- if (operand_type_check (i.types[0], reg))
- first_reg_op = 0;
- else
- first_reg_op = 1;
- /* Pretend we saw the extra register operand. */
- assert (i.reg_operands == 1
- && i.op[first_reg_op + 1].regs == 0);
- i.op[first_reg_op + 1].regs = i.op[first_reg_op].regs;
- i.types[first_reg_op + 1] = i.types[first_reg_op];
- i.operands++;
- i.reg_operands++;
- }
+ if (i.tm.opcode_modifier.firstxmm0)
+ {
+ unsigned int j;
+
+ /* The first operand is implicit and must be xmm0. */
+ assert (i.reg_operands && UINTS_EQUAL (i.types[0], regxmm));
+ if (i.op[0].regs->reg_num != 0)
+ {
+ if (intel_syntax)
+ as_bad (_("the last operand of `%s' must be `%sxmm0'"),
+ i.tm.name, register_prefix);
+ else
+ as_bad (_("the first operand of `%s' must be `%sxmm0'"),
+ i.tm.name, register_prefix);
+ return 0;
+ }
+
+ for (j = 1; j < i.operands; j++)
+ {
+ i.op[j - 1] = i.op[j];
+ i.types[j - 1] = i.types[j];
+
+ /* We need to adjust fields in i.tm since they are used by
+ build_modrm_byte. */
+ i.tm.operand_types [j - 1] = i.tm.operand_types [j];
+ }
+
+ i.operands--;
+ i.reg_operands--;
+ i.tm.operands--;
+ }
+ else if (i.tm.opcode_modifier.regkludge)
+ {
+ /* The imul $imm, %reg instruction is converted into
+ imul $imm, %reg, %reg, and the clr %reg instruction
+ is converted into xor %reg, %reg. */
+
+ unsigned int first_reg_op;
+
+ if (operand_type_check (i.types[0], reg))
+ first_reg_op = 0;
+ else
+ first_reg_op = 1;
+ /* Pretend we saw the extra register operand. */
+ assert (i.reg_operands == 1
+ && i.op[first_reg_op + 1].regs == 0);
+ i.op[first_reg_op + 1].regs = i.op[first_reg_op].regs;
+ i.types[first_reg_op + 1] = i.types[first_reg_op];
+ i.operands++;
+ i.reg_operands++;
}
if (i.tm.opcode_modifier.shortform)
source = 0;
break;
case 4:
- /* When there are 4 operands, the first two must be immediate
- operands. The source operand will be the 3rd one. */
+ /* When there are 4 operands, the first two must be 8bit
+ immediate operands. The source operand will be the 3rd
+ one. */
assert (i.imm_operands == 2
- && operand_type_check (i.types[0], imm)
- && operand_type_check (i.types[1], imm));
+ && i.types[0].bitfield.imm8
+ && i.types[1].bitfield.imm8);
source = 2;
break;
default:
}
}
/* RIP addressing for 64bit mode. */
- else if (i.base_reg->reg_num == RegRip)
+ else if (i.base_reg->reg_num == RegRip ||
+ i.base_reg->reg_num == RegEip)
{
i.rm.regmem = NO_BASE_REGISTER;
i.types[op].bitfield.disp8 = 0;
/* Output normal instructions here. */
char *p;
unsigned char *q;
+ unsigned int j;
unsigned int prefix;
switch (i.tm.opcode_length)
}
/* The prefix bytes. */
- for (q = i.prefix;
- q < i.prefix + sizeof (i.prefix) / sizeof (i.prefix[0]);
- q++)
- {
- if (*q)
- {
- p = frag_more (1);
- md_number_to_chars (p, (valueT) *q, 1);
- }
- }
+ for (j = ARRAY_SIZE (i.prefix), q = i.prefix; j > 0; j--, q++)
+ if (*q)
+ FRAG_APPEND_1_CHAR (*q);
/* Now the opcode; be careful about word order here! */
if (i.tm.opcode_length == 1)
/* Now the modrm byte and sib byte (if present). */
if (i.tm.opcode_modifier.modrm)
{
- p = frag_more (1);
- md_number_to_chars (p,
- (valueT) (i.rm.regmem << 0
- | i.rm.reg << 3
- | i.rm.mode << 6),
- 1);
+ FRAG_APPEND_1_CHAR ((i.rm.regmem << 0
+ | i.rm.reg << 3
+ | i.rm.mode << 6));
/* If i.rm.regmem == ESP (4)
&& i.rm.mode != (Register mode)
&& not 16 bit
if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING
&& i.rm.mode != 3
&& !(i.base_reg && i.base_reg->reg_type.bitfield.reg16))
- {
- p = frag_more (1);
- md_number_to_chars (p,
- (valueT) (i.sib.base << 0
- | i.sib.index << 3
- | i.sib.scale << 6),
- 1);
- }
+ FRAG_APPEND_1_CHAR ((i.sib.base << 0
+ | i.sib.index << 3
+ | i.sib.scale << 6));
}
/* Write the DREX byte if needed. */
if (is_end_of_line[(unsigned char) *cp] || *cp == ',')
return NULL;
- for (j = 0; j < sizeof (gotrel) / sizeof (gotrel[0]); j++)
+ for (j = 0; j < ARRAY_SIZE (gotrel); j++)
{
int len;
|| (i.prefix[ADDR_PREFIX]
&& !i.base_reg->reg_type.bitfield.reg32))
&& (i.index_reg
- || i.base_reg->reg_num != RegRip))
+ || i.base_reg->reg_num !=
+ (i.prefix[ADDR_PREFIX] == 0 ? RegRip : RegEip)))
|| (i.index_reg
&& (!i.index_reg->reg_type.bitfield.baseindex
|| (i.prefix[ADDR_PREFIX] == 0
on error. */
static int
-i386_operand (char *operand_string)
+i386_att_operand (char *operand_string)
{
const reg_entry *r;
char *end_op;
fragP->fr_fix += extension;
}
\f
-/* Size of byte displacement jmp. */
-int md_short_jump_size = 2;
-
-/* Size of dword displacement jmp. */
-int md_long_jump_size = 5;
-
-void
-md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
- char *ptr;
- addressT from_addr, to_addr;
- fragS *frag ATTRIBUTE_UNUSED;
- symbolS *to_symbol ATTRIBUTE_UNUSED;
-{
- offsetT offset;
-
- offset = to_addr - (from_addr + 2);
- /* Opcode for byte-disp jump. */
- md_number_to_chars (ptr, (valueT) 0xeb, 1);
- md_number_to_chars (ptr + 1, (valueT) offset, 1);
-}
-
-void
-md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
- char *ptr;
- addressT from_addr, to_addr;
- fragS *frag ATTRIBUTE_UNUSED;
- symbolS *to_symbol ATTRIBUTE_UNUSED;
-{
- offsetT offset;
-
- offset = to_addr - (from_addr + 5);
- md_number_to_chars (ptr, (valueT) 0xe9, 1);
- md_number_to_chars (ptr + 1, (valueT) offset, 4);
-}
-\f
/* Apply a fixup (fixS) to segment data, once it has been determined
by our caller that we have all the info we need to fix it up.
md_number_to_chars (p, value, fixP->fx_size);
}
\f
-#define MAX_LITTLENUMS 6
-
-/* Turn the string pointed to by litP into a floating point constant
- of type TYPE, and emit the appropriate bytes. The number of
- LITTLENUMS emitted is stored in *SIZEP. An error message is
- returned, or NULL on OK. */
-
char *
-md_atof (type, litP, sizeP)
- int type;
- char *litP;
- int *sizeP;
+md_atof (int type, char *litP, int *sizeP)
{
- int prec;
- LITTLENUM_TYPE words[MAX_LITTLENUMS];
- LITTLENUM_TYPE *wordP;
- char *t;
-
- switch (type)
- {
- case 'f':
- case 'F':
- prec = 2;
- break;
-
- case 'd':
- case 'D':
- prec = 4;
- break;
-
- case 'x':
- case 'X':
- prec = 5;
- break;
-
- default:
- *sizeP = 0;
- return _("Bad call to md_atof ()");
- }
- t = atof_ieee (input_line_pointer, type, words);
- if (t)
- input_line_pointer = t;
-
- *sizeP = prec * sizeof (LITTLENUM_TYPE);
- /* This loops outputs the LITTLENUMs in REVERSE order; in accord with
- the bigendian 386. */
- for (wordP = words + prec - 1; prec--;)
- {
- md_number_to_chars (litP, (valueT) (*wordP--), sizeof (LITTLENUM_TYPE));
- litP += sizeof (LITTLENUM_TYPE);
- }
- return 0;
+ /* This outputs the LITTLENUMs in REVERSE order;
+ in accord with the bigendian 386. */
+ return ieee_md_atof (type, litP, sizeP, FALSE);
}
\f
static char output_invalid_buf[sizeof (unsigned char) * 2 + 6];
#define OPTION_DIVIDE (OPTION_MD_BASE + 2)
#define OPTION_MARCH (OPTION_MD_BASE + 3)
#define OPTION_MTUNE (OPTION_MD_BASE + 4)
+#define OPTION_MMNEMONIC (OPTION_MD_BASE + 5)
+#define OPTION_MSYNTAX (OPTION_MD_BASE + 6)
+#define OPTION_MINDEX_REG (OPTION_MD_BASE + 7)
+#define OPTION_MNAKED_REG (OPTION_MD_BASE + 8)
+#define OPTION_MOLD_GCC (OPTION_MD_BASE + 9)
struct option md_longopts[] =
{
{"divide", no_argument, NULL, OPTION_DIVIDE},
{"march", required_argument, NULL, OPTION_MARCH},
{"mtune", required_argument, NULL, OPTION_MTUNE},
+ {"mmnemonic", required_argument, NULL, OPTION_MMNEMONIC},
+ {"msyntax", required_argument, NULL, OPTION_MSYNTAX},
+ {"mindex-reg", no_argument, NULL, OPTION_MINDEX_REG},
+ {"mnaked-reg", no_argument, NULL, OPTION_MNAKED_REG},
+ {"mold-gcc", no_argument, NULL, OPTION_MOLD_GCC},
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
as_fatal (_("Invalid -mtune= option: `%s'"), arg);
break;
+ case OPTION_MMNEMONIC:
+ if (strcasecmp (arg, "att") == 0)
+ intel_mnemonic = 0;
+ else if (strcasecmp (arg, "intel") == 0)
+ intel_mnemonic = 1;
+ else
+ as_fatal (_("Invalid -mmnemonic= option: `%s'"), arg);
+ break;
+
+ case OPTION_MSYNTAX:
+ if (strcasecmp (arg, "att") == 0)
+ intel_syntax = 0;
+ else if (strcasecmp (arg, "intel") == 0)
+ intel_syntax = 1;
+ else
+ as_fatal (_("Invalid -msyntax= option: `%s'"), arg);
+ break;
+
+ case OPTION_MINDEX_REG:
+ allow_index_reg = 1;
+ break;
+
+ case OPTION_MNAKED_REG:
+ allow_naked_reg = 1;
+ break;
+
+ case OPTION_MOLD_GCC:
+ old_gcc = 1;
+ break;
+
default:
return 0;
}
-march=CPU/-mtune=CPU generate code/optimize for CPU, where CPU is one of:\n\
i386, i486, pentium, pentiumpro, pentium4, nocona,\n\
core, core2, k6, athlon, k8, generic32, generic64\n"));
-
+ fprintf (stream, _("\
+ -mmnemonic=[att|intel] use AT&T/Intel mnemonic\n"));
+ fprintf (stream, _("\
+ -msyntax=[att|intel] use AT&T/Intel syntax\n"));
+ fprintf (stream, _("\
+ -mindex-reg support pseudo index registers\n"));
+ fprintf (stream, _("\
+ -mnaked-reg don't require `%%' prefix for registers\n"));
+ fprintf (stream, _("\
+ -mold-gcc support old (<= 2.8.1) versions of gcc\n"));
}
#if ((defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT)) \
else if (prev_token.code == T_XMMWORD)
{
- /* XXX ignored for now, but accepted since gcc uses it */
- suffix = 0;
+ suffix = XMMWORD_MNEM_SUFFIX;
}
else