Fri Jun 5 23:27:04 1998 Alan Modra <alan@spri.levels.unisa.edu.au>

* config/tc-i386.c (mode_from_disp_size): Disp16 is mode 2.
	(i386_operand): Simplify checks for valid base/index combinations.
	Disallow `in 4(%dx),%al'.

	* config/tc-i386.c (struct _i386_insn): Make regs, base_reg, and
	index_reg const.
	(add_prefix): Change parameter from char to int.

	* config/tc-i386.h (Ugh): Define opcode modifier.
	* config/tc-i386.c (md_assemble): Print warnings for Ugh insns.

	* config/tc-i386.c (md_assemble): Rewrite MATCH and
	CONSISTENT_REGISTER_MATCH macros to check register types more
	thoroughly.  Check for illegal suffix/operand combinations
	when matching insns with operands.  Handle new `s' suffix, and
	associated FloatMF opcode modifier for float insns with memory
	operands.
	* config/tc-i386.h (FloatMF): Define new opcode modifier.
	(No_sSuf, No_bSuf, No_wSuf, No_lSuf): Likewise.
	(SHORT_OPCODE_SUFFIX, LONG_OPCODE_SUFFIX): Define.
	* config/tc-i386.c: Rename WORD_PREFIX_OPCODE to
	DATA_PREFIX_OPCODE throughout.

	* config/tc-i386.c (REGISTER_WARNINGS): Define.
	(md_assemble): Rewrite suffix/register operand checking code to be
	more thorough.  Remove Abs8,16,32.  Change occurrences of Mem to
	AnyMem, the better to grep.
	(pi): Remove Abs.
	(i386_operand): Don't set Mem bits in i.types[this_operand] when
	given a memory operand.  Don't set Abs bits either.
	(type_names): Remove Mem*, Abs*.
	* config/tc-i386.h (Mem8, Mem16, Mem32, Abs8, Abs16, Abs32): Don't
	define opcode_modifiers as these cases are handled by Disp8,
	Disp16, Disp32 and suffix checks.
	(COMES_IN_BOTH_DIRECTIONS): Remove.
	(FloatR): Define. It's OK to share the bit with ReverseRegRegmem.

	* config/tc-i386.c (md_assemble): Don't emit operand size prefix
	if IgnoreDataSize modifier given.  Remove ShortformW modifier
	test.  Add test for ShortForm in W base_opcode modification.
	Merge Seg2ShortForm and Seg3ShortForm code.
	* config/tc-i386.h (ShortFormW): Remove.
	(IgnoreDataSize): Define.
This commit is contained in:
Ian Lance Taylor
1998-06-06 03:42:14 +00:00
parent 40afcc4cd4
commit 73a8be66ca
3 changed files with 395 additions and 261 deletions

View File

@ -1,3 +1,49 @@
Fri Jun 5 23:27:04 1998 Alan Modra <alan@spri.levels.unisa.edu.au>
* config/tc-i386.c (mode_from_disp_size): Disp16 is mode 2.
(i386_operand): Simplify checks for valid base/index combinations.
Disallow `in 4(%dx),%al'.
* config/tc-i386.c (struct _i386_insn): Make regs, base_reg, and
index_reg const.
(add_prefix): Change parameter from char to int.
* config/tc-i386.h (Ugh): Define opcode modifier.
* config/tc-i386.c (md_assemble): Print warnings for Ugh insns.
* config/tc-i386.c (md_assemble): Rewrite MATCH and
CONSISTENT_REGISTER_MATCH macros to check register types more
thoroughly. Check for illegal suffix/operand combinations
when matching insns with operands. Handle new `s' suffix, and
associated FloatMF opcode modifier for float insns with memory
operands.
* config/tc-i386.h (FloatMF): Define new opcode modifier.
(No_sSuf, No_bSuf, No_wSuf, No_lSuf): Likewise.
(SHORT_OPCODE_SUFFIX, LONG_OPCODE_SUFFIX): Define.
* config/tc-i386.c: Rename WORD_PREFIX_OPCODE to
DATA_PREFIX_OPCODE throughout.
* config/tc-i386.c (REGISTER_WARNINGS): Define.
(md_assemble): Rewrite suffix/register operand checking code to be
more thorough. Remove Abs8,16,32. Change occurrences of Mem to
AnyMem, the better to grep.
(pi): Remove Abs.
(i386_operand): Don't set Mem bits in i.types[this_operand] when
given a memory operand. Don't set Abs bits either.
(type_names): Remove Mem*, Abs*.
* config/tc-i386.h (Mem8, Mem16, Mem32, Abs8, Abs16, Abs32): Don't
define opcode_modifiers as these cases are handled by Disp8,
Disp16, Disp32 and suffix checks.
(COMES_IN_BOTH_DIRECTIONS): Remove.
(FloatR): Define. It's OK to share the bit with ReverseRegRegmem.
* config/tc-i386.c (md_assemble): Don't emit operand size prefix
if IgnoreDataSize modifier given. Remove ShortformW modifier
test. Add test for ShortForm in W base_opcode modification.
Merge Seg2ShortForm and Seg3ShortForm code.
* config/tc-i386.h (ShortFormW): Remove.
(IgnoreDataSize): Define.
Fri Jun 5 10:50:53 1998 Nick Clifton <nickc@cygnus.com> Fri Jun 5 10:50:53 1998 Nick Clifton <nickc@cygnus.com>
* config/tc-d30v.c (md_assemble): Store previous segment state * config/tc-d30v.c (md_assemble): Store previous segment state

View File

@ -38,6 +38,10 @@
#define TC_RELOC(X,Y) (Y) #define TC_RELOC(X,Y) (Y)
#endif #endif
#ifndef REGISTER_WARNINGS
#define REGISTER_WARNINGS 1
#endif
#ifndef SCALE1_WHEN_NO_INDEX #ifndef SCALE1_WHEN_NO_INDEX
/* Specifying a scale factor besides 1 when there is no index is /* Specifying a scale factor besides 1 when there is no index is
futile. eg. `mov (%ebx,2),%al' does exactly the same as futile. eg. `mov (%ebx,2),%al' does exactly the same as
@ -52,7 +56,7 @@ static int fits_in_unsigned_byte PARAMS ((long));
static int fits_in_unsigned_word PARAMS ((long)); static int fits_in_unsigned_word PARAMS ((long));
static int fits_in_signed_word PARAMS ((long)); static int fits_in_signed_word PARAMS ((long));
static int smallest_imm_type PARAMS ((long)); static int smallest_imm_type PARAMS ((long));
static int add_prefix PARAMS ((unsigned char)); static int add_prefix PARAMS ((unsigned int));
static void set_16bit_code_flag PARAMS ((int)); static void set_16bit_code_flag PARAMS ((int));
#ifdef BFD_ASSEMBLER #ifdef BFD_ASSEMBLER
static bfd_reloc_code_real_type reloc static bfd_reloc_code_real_type reloc
@ -66,8 +70,10 @@ struct _i386_insn
{ {
/* TM holds the template for the insn were currently assembling. */ /* TM holds the template for the insn were currently assembling. */
template tm; template tm;
/* SUFFIX holds the opcode suffix (e.g. 'l' for 'movl') if given. */ /* SUFFIX holds the opcode suffix (e.g. 'l' for 'movl') if given. */
char suffix; char suffix;
/* Operands are coded with OPERANDS, TYPES, DISPS, IMMS, and REGS. */ /* Operands are coded with OPERANDS, TYPES, DISPS, IMMS, and REGS. */
/* OPERANDS gives the number of given operands. */ /* OPERANDS gives the number of given operands. */
@ -97,12 +103,12 @@ struct _i386_insn
expressionS *imms[MAX_OPERANDS]; expressionS *imms[MAX_OPERANDS];
/* Register operands (if given) for each operand. */ /* Register operands (if given) for each operand. */
reg_entry *regs[MAX_OPERANDS]; const reg_entry *regs[MAX_OPERANDS];
/* BASE_REG, INDEX_REG, and LOG2_SCALE_FACTOR are used to encode /* BASE_REG, INDEX_REG, and LOG2_SCALE_FACTOR are used to encode
the base index byte below. */ the base index byte below. */
reg_entry *base_reg; const reg_entry *base_reg;
reg_entry *index_reg; const reg_entry *index_reg;
unsigned int log2_scale_factor; unsigned int log2_scale_factor;
/* SEG gives the seg_entries of this insn. They are zero unless /* SEG gives the seg_entries of this insn. They are zero unless
@ -115,7 +121,7 @@ struct _i386_insn
unsigned char prefix[MAX_PREFIXES]; unsigned char prefix[MAX_PREFIXES];
/* RM and BI are the modrm byte and the base index byte where the /* RM and BI are the modrm byte and the base index byte where the
addressing modes of this insn are encoded. */ addressing modes of this insn are encoded. */
modrm_byte rm; modrm_byte rm;
base_index_byte bi; base_index_byte bi;
@ -363,7 +369,7 @@ static INLINE unsigned long
mode_from_disp_size (t) mode_from_disp_size (t)
unsigned long t; unsigned long t;
{ {
return (t & Disp8) ? 1 : (t & Disp32) ? 2 : 0; return (t & Disp8) ? 1 : (t & (Disp16|Disp32)) ? 2 : 0;
} }
#if 0 #if 0
@ -436,13 +442,16 @@ smallest_imm_type (num)
added. */ added. */
static int static int
add_prefix (prefix) add_prefix (prefix)
unsigned char prefix; unsigned int prefix;
{ {
int ret = 1; int ret = 1;
int q; int q;
switch (prefix) switch (prefix)
{ {
default:
abort ();
case CS_PREFIX_OPCODE: case CS_PREFIX_OPCODE:
case DS_PREFIX_OPCODE: case DS_PREFIX_OPCODE:
case ES_PREFIX_OPCODE: case ES_PREFIX_OPCODE:
@ -468,8 +477,9 @@ add_prefix (prefix)
q = ADDR_PREFIX; q = ADDR_PREFIX;
break; break;
case WORD_PREFIX_OPCODE: case DATA_PREFIX_OPCODE:
q = DATA_PREFIX; q = DATA_PREFIX;
break;
} }
if (i.prefix[q]) if (i.prefix[q])
@ -702,7 +712,7 @@ pi (line, x)
fprintf (stdout, "%s\n", x->regs[i]->reg_name); fprintf (stdout, "%s\n", x->regs[i]->reg_name);
if (x->types[i] & Imm) if (x->types[i] & Imm)
pe (x->imms[i]); pe (x->imms[i]);
if (x->types[i] & (Disp | Abs)) if (x->types[i] & Disp)
pe (x->disps[i]); pe (x->disps[i]);
} }
} }
@ -776,27 +786,21 @@ type_names[] =
{ Imm8S, "i8s" }, { Imm8S, "i8s" },
{ Imm16, "i16" }, { Imm16, "i16" },
{ Imm32, "i32" }, { Imm32, "i32" },
{ Mem8, "Mem8" }, { Imm1, "i1" },
{ Mem16, "Mem16" },
{ Mem32, "Mem32" },
{ BaseIndex, "BaseIndex" }, { BaseIndex, "BaseIndex" },
{ Abs8, "Abs8" },
{ Abs16, "Abs16" },
{ Abs32, "Abs32" },
{ Disp8, "d8" }, { Disp8, "d8" },
{ Disp16, "d16" }, { Disp16, "d16" },
{ Disp32, "d32" }, { Disp32, "d32" },
{ SReg2, "SReg2" },
{ SReg3, "SReg3" },
{ Acc, "Acc" },
{ InOutPortReg, "InOutPortReg" }, { InOutPortReg, "InOutPortReg" },
{ ShiftCount, "ShiftCount" }, { ShiftCount, "ShiftCount" },
{ Imm1, "i1" },
{ Control, "control reg" }, { Control, "control reg" },
{ Test, "test reg" }, { Test, "test reg" },
{ Debug, "debug reg" }, { Debug, "debug reg" },
{ FloatReg, "FReg" }, { FloatReg, "FReg" },
{ FloatAcc, "FAcc" }, { FloatAcc, "FAcc" },
{ SReg2, "SReg2" },
{ SReg3, "SReg3" },
{ Acc, "Acc" },
{ JumpAbsolute, "Jump Absolute" }, { JumpAbsolute, "Jump Absolute" },
{ RegMMX, "rMMX" }, { RegMMX, "rMMX" },
{ EsSeg, "es" }, { EsSeg, "es" },
@ -961,7 +965,8 @@ md_assemble (line)
/* add prefix, checking for repeated prefixes */ /* add prefix, checking for repeated prefixes */
switch (add_prefix (prefix->prefix_code)) switch (add_prefix (prefix->prefix_code))
{ {
case 0: return; case 0:
return;
case 2: case 2:
expecting_string_instruction = prefix->prefix_name; expecting_string_instruction = prefix->prefix_name;
break; break;
@ -990,6 +995,10 @@ md_assemble (line)
case DWORD_OPCODE_SUFFIX: case DWORD_OPCODE_SUFFIX:
case WORD_OPCODE_SUFFIX: case WORD_OPCODE_SUFFIX:
case BYTE_OPCODE_SUFFIX: case BYTE_OPCODE_SUFFIX:
case SHORT_OPCODE_SUFFIX:
#if LONG_OPCODE_SUFFIX != DWORD_OPCODE_SUFFIX
case LONG_OPCODE_SUFFIX:
#endif
token_start[last_index] = '\0'; token_start[last_index] = '\0';
current_templates = (templates *) hash_find (op_hash, token_start); current_templates = (templates *) hash_find (op_hash, token_start);
token_start[last_index] = last_char; token_start[last_index] = last_char;
@ -1005,8 +1014,8 @@ md_assemble (line)
RESTORE_END_STRING (l); RESTORE_END_STRING (l);
/* check for rep/repne without a string instruction */ /* check for rep/repne without a string instruction */
if (expecting_string_instruction && if (expecting_string_instruction
!(current_templates->start->opcode_modifier & IsString)) && !(current_templates->start->opcode_modifier & IsString))
{ {
as_bad (_("expecting string instruction after `%s'"), as_bad (_("expecting string instruction after `%s'"),
expecting_string_instruction); expecting_string_instruction);
@ -1112,42 +1121,46 @@ md_assemble (line)
making sure the overlap of the given operands types is consistent making sure the overlap of the given operands types is consistent
with the template operand types. */ with the template operand types. */
#define MATCH(overlap,given_type) \ #define MATCH(overlap, given, template) \
(overlap \ ((overlap) \
&& ((overlap & (JumpAbsolute|BaseIndex|Mem8)) \ && (((overlap) & (JumpAbsolute|BaseIndex)) \
== (given_type & (JumpAbsolute|BaseIndex|Mem8)))) == ((given) & (JumpAbsolute|BaseIndex))))
/* If given types r0 and r1 are registers they must be of the same type
unless the expected operand type register overlap is null.
Note that Acc in a template matches every size of reg. */
#define CONSISTENT_REGISTER_MATCH(m0, g0, t0, m1, g1, t1) \
( ((g0) & Reg) == 0 || ((g1) & Reg) == 0 || \
((g0) & Reg) == ((g1) & Reg) || \
((((m0) & Acc) ? Reg : (t0)) & (((m1) & Acc) ? Reg : (t1)) & Reg) == 0 )
/* If m0 and m1 are register matches they must be consistent
with the expected operand types t0 and t1.
That is, if both m0 & m1 are register matches
i.e. ( ((m0 & (Reg)) && (m1 & (Reg)) ) ?
then, either 1. or 2. must be true:
1. the expected operand type register overlap is null:
(t0 & t1 & Reg) == 0
AND
the given register overlap is null:
(m0 & m1 & Reg) == 0
2. the expected operand type register overlap == the given
operand type overlap: (t0 & t1 & m0 & m1 & Reg).
*/
#define CONSISTENT_REGISTER_MATCH(m0, m1, t0, t1) \
( ((m0 & (Reg)) && (m1 & (Reg))) ? \
( ((t0 & t1 & (Reg)) == 0 && (m0 & m1 & (Reg)) == 0) || \
((t0 & t1) & (m0 & m1) & (Reg)) \
) : 1)
{ {
register unsigned int overlap0, overlap1; register unsigned int overlap0, overlap1;
expressionS *exp; expressionS *exp;
unsigned int overlap2; unsigned int overlap2;
unsigned int found_reverse_match; unsigned int found_reverse_match;
int suffix_check;
overlap0 = 0;
overlap1 = 0;
overlap2 = 0;
found_reverse_match = 0;
suffix_check = (i.suffix == BYTE_OPCODE_SUFFIX
? No_bSuf
: (i.suffix == WORD_OPCODE_SUFFIX
? No_wSuf
: (i.suffix == SHORT_OPCODE_SUFFIX
? No_sSuf
: (i.suffix == LONG_OPCODE_SUFFIX ? No_lSuf : 0))));
overlap0 = overlap1 = overlap2 = found_reverse_match = 0;
for (t = current_templates->start; for (t = current_templates->start;
t < current_templates->end; t < current_templates->end;
t++) t++)
{ {
/* must have right number of operands */ /* Must have right number of operands, and must not have
if (i.operands != t->operands) disallowed suffix. */
if (i.operands != t->operands || (t->opcode_modifier & suffix_check))
continue; continue;
else if (!t->operands) else if (!t->operands)
break; /* 0 operands always matches */ break; /* 0 operands always matches */
@ -1156,50 +1169,55 @@ md_assemble (line)
switch (t->operands) switch (t->operands)
{ {
case 1: case 1:
if (!MATCH (overlap0, i.types[0])) if (!MATCH (overlap0, i.types[0], t->operand_types[0]))
continue; continue;
break; break;
case 2: case 2:
case 3: case 3:
overlap1 = i.types[1] & t->operand_types[1]; overlap1 = i.types[1] & t->operand_types[1];
if (!MATCH (overlap0, i.types[0]) || if (!MATCH (overlap0, i.types[0], t->operand_types[0])
!MATCH (overlap1, i.types[1]) || || !MATCH (overlap1, i.types[1], t->operand_types[1])
!CONSISTENT_REGISTER_MATCH (overlap0, overlap1, || !CONSISTENT_REGISTER_MATCH (overlap0, i.types[0],
t->operand_types[0], t->operand_types[0],
t->operand_types[1])) overlap1, i.types[1],
t->operand_types[1]))
{ {
/* check if other direction is valid ... */ /* check if other direction is valid ... */
if (!(t->opcode_modifier & COMES_IN_BOTH_DIRECTIONS)) if ((t->opcode_modifier & (D|FloatD)) == 0)
continue; continue;
/* try reversing direction of operands */ /* try reversing direction of operands */
overlap0 = i.types[0] & t->operand_types[1]; overlap0 = i.types[0] & t->operand_types[1];
overlap1 = i.types[1] & t->operand_types[0]; overlap1 = i.types[1] & t->operand_types[0];
if (!MATCH (overlap0, i.types[0]) || if (!MATCH (overlap0, i.types[0], t->operand_types[1])
!MATCH (overlap1, i.types[1]) || || !MATCH (overlap1, i.types[1], t->operand_types[0])
!CONSISTENT_REGISTER_MATCH (overlap0, overlap1, || !CONSISTENT_REGISTER_MATCH (overlap0, i.types[0],
t->operand_types[1], t->operand_types[1],
t->operand_types[0])) overlap1, i.types[1],
t->operand_types[0]))
{ {
/* does not match either direction */ /* does not match either direction */
continue; continue;
} }
/* found a reverse match here -- slip through */ /* found_reverse_match holds which of D or FloatDR
/* found_reverse_match holds which of D or FloatD we've found */ we've found. */
found_reverse_match = t->opcode_modifier & COMES_IN_BOTH_DIRECTIONS; found_reverse_match = t->opcode_modifier & (D|FloatDR);
} /* endif: not forward match */ break;
/* found either forward/reverse 2 operand match here */ }
/* found a forward 2 operand match here */
if (t->operands == 3) if (t->operands == 3)
{ {
/* Here we make use of the fact that there are no
reverse match 3 operand instructions, and all 3
operand instructions only need to be checked for
register consistency between operands 2 and 3. */
overlap2 = i.types[2] & t->operand_types[2]; overlap2 = i.types[2] & t->operand_types[2];
if (!MATCH (overlap2, i.types[2]) || if (!MATCH (overlap2, i.types[2], t->operand_types[2])
!CONSISTENT_REGISTER_MATCH (overlap0, overlap2, || !CONSISTENT_REGISTER_MATCH (overlap1, i.types[1],
t->operand_types[0], t->operand_types[1],
t->operand_types[2]) || overlap2, i.types[2],
!CONSISTENT_REGISTER_MATCH (overlap1, overlap2, t->operand_types[2]))
t->operand_types[1],
t->operand_types[2]))
continue; continue;
} }
/* found either forward/reverse 2 or 3 operand match here: /* found either forward/reverse 2 or 3 operand match here:
@ -1216,23 +1234,23 @@ md_assemble (line)
/* Copy the template we found. */ /* Copy the template we found. */
i.tm = *t; i.tm = *t;
if (i.tm.opcode_modifier & FWait)
if (! add_prefix (FWAIT_OPCODE))
return;
if (found_reverse_match) if (found_reverse_match)
{ {
i.tm.operand_types[0] = t->operand_types[1]; i.tm.operand_types[0] = t->operand_types[1];
i.tm.operand_types[1] = t->operand_types[0]; i.tm.operand_types[1] = t->operand_types[0];
} }
if (i.tm.opcode_modifier & FWait)
if (! add_prefix (FWAIT_OPCODE))
return;
/* Check string instruction segment overrides */ /* Check string instruction segment overrides */
if ((i.tm.opcode_modifier & IsString) != 0 && i.mem_operands != 0) if ((i.tm.opcode_modifier & IsString) != 0 && i.mem_operands != 0)
{ {
int mem_op = (i.types[0] & Mem) ? 0 : 1; int mem_op = (i.types[0] & AnyMem) ? 0 : 1;
if ((i.tm.operand_types[mem_op] & EsSeg) != 0) if ((i.tm.operand_types[mem_op] & EsSeg) != 0)
{ {
if (i.seg[0] != (seg_entry *) 0 && i.seg[0] != (seg_entry *) &es) if (i.seg[0] != NULL && i.seg[0] != &es)
{ {
as_bad (_("`%s' operand %d must use `%%es' segment"), as_bad (_("`%s' operand %d must use `%%es' segment"),
i.tm.name, i.tm.name,
@ -1247,7 +1265,7 @@ md_assemble (line)
} }
else if ((i.tm.operand_types[mem_op + 1] & EsSeg) != 0) else if ((i.tm.operand_types[mem_op + 1] & EsSeg) != 0)
{ {
if (i.seg[1] != (seg_entry *) 0 && i.seg[1] != (seg_entry *) &es) if (i.seg[1] != NULL && i.seg[1] != &es)
{ {
as_bad (_("`%s' operand %d must use `%%es' segment"), as_bad (_("`%s' operand %d must use `%%es' segment"),
i.tm.name, i.tm.name,
@ -1257,69 +1275,130 @@ md_assemble (line)
} }
} }
/* If the matched instruction specifies an explicit opcode suffix, /* If matched instruction specifies an explicit opcode suffix, use
use it - and make sure none has already been specified. */ it. */
if (i.tm.opcode_modifier & (Data16|Data32)) if (i.tm.opcode_modifier & (Data16|Data32))
{ {
if (i.suffix)
{
as_bad (_("extraneous opcode suffix given"));
return;
}
if (i.tm.opcode_modifier & Data16) if (i.tm.opcode_modifier & Data16)
i.suffix = WORD_OPCODE_SUFFIX; i.suffix = WORD_OPCODE_SUFFIX;
else else
i.suffix = DWORD_OPCODE_SUFFIX; i.suffix = DWORD_OPCODE_SUFFIX;
} }
else if (i.reg_operands)
/* If there's no opcode suffix we try to invent one based on register
operands. */
if (!i.suffix && i.reg_operands)
{ {
/* We take i.suffix from the LAST register operand specified. This /* If there's no opcode suffix we try to invent one based on
assumes that the last register operands is the destination register register operands. */
operand. */ if (!i.suffix)
int op;
for (op = 0; op < MAX_OPERANDS; op++)
if (i.types[op] & Reg)
{
i.suffix = ((i.types[op] & Reg8) ? BYTE_OPCODE_SUFFIX :
(i.types[op] & Reg16) ? WORD_OPCODE_SUFFIX :
DWORD_OPCODE_SUFFIX);
}
}
else if (i.suffix != 0
&& i.reg_operands != 0
&& (i.types[i.operands - 1] & Reg) != 0)
{
int bad;
/* If the last operand is a register, make sure it is
compatible with the suffix. */
bad = 0;
switch (i.suffix)
{ {
default: /* We take i.suffix from the last register operand specified,
abort (); Destination register type is more significant than source
case BYTE_OPCODE_SUFFIX: register type. */
/* If this is an eight bit register, it's OK. If it's the int op;
16 or 32 bit version of an eight bit register, we will for (op = i.operands; --op >= 0; )
just use the low portion, and that's OK too. */ if (i.types[op] & Reg)
if ((i.types[i.operands - 1] & Reg8) == 0 {
&& i.regs[i.operands - 1]->reg_num >= 4) i.suffix = ((i.types[op] & Reg8) ? BYTE_OPCODE_SUFFIX :
bad = 1; (i.types[op] & Reg16) ? WORD_OPCODE_SUFFIX :
break; DWORD_OPCODE_SUFFIX);
case WORD_OPCODE_SUFFIX: break;
case DWORD_OPCODE_SUFFIX: }
/* We don't insist on the presence or absence of the e
prefix on the register, but we reject eight bit
registers. */
if ((i.types[i.operands - 1] & Reg8) != 0)
bad = 1;
} }
if (bad) else if (i.suffix == BYTE_OPCODE_SUFFIX)
as_bad (_("register does not match opcode suffix")); {
int op;
for (op = i.operands; --op >= 0; )
{
/* If this is an eight bit register, it's OK. If it's
the 16 or 32 bit version of an eight bit register,
we will just use the low portion, and that's OK too. */
if (i.types[op] & Reg8)
continue;
if ((i.types[op] & WordReg) && i.regs[op]->reg_num < 4
#if 0
/* Check that the template allows eight bit regs
This kills insns such as `orb $1,%edx', which
maybe should be allowed. */
&& (i.tm.operand_types[op] & (Reg8|InOutPortReg))
#endif
)
{
#if REGISTER_WARNINGS
if ((i.tm.operand_types[op] & InOutPortReg) == 0)
as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"),
(i.regs[op] - (i.types[op] & Reg16 ? 8 : 16))->reg_name,
i.regs[op]->reg_name,
i.suffix);
#endif
continue;
}
/* Any other register is bad */
if (i.types[op] & (Reg | RegMMX | Control | Debug | Test
| FloatReg | FloatAcc | SReg2 | SReg3))
{
as_bad (_("`%%%s' not allowed with `%s%c'"),
i.regs[op]->reg_name,
i.tm.name,
i.suffix);
return;
}
}
}
else if (i.suffix == DWORD_OPCODE_SUFFIX)
{
int op;
for (op = i.operands; --op >= 0; )
/* Reject eight bit registers, except where the template
requires them. (eg. movzb) */
if ((i.types[op] & Reg8) != 0
&& (i.tm.operand_types[op] & (Reg16|Reg32|Acc)) != 0)
{
as_bad (_("`%%%s' not allowed with `%s%c'"),
i.regs[op]->reg_name,
i.tm.name,
i.suffix);
return;
}
#if REGISTER_WARNINGS
/* Warn if the e prefix on a general reg is missing. */
else if ((i.types[op] & Reg16) != 0
&& (i.tm.operand_types[op] & (Reg32|Acc)) != 0)
{
as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"),
(i.regs[op] + 8)->reg_name,
i.regs[op]->reg_name,
i.suffix);
}
#endif
}
else if (i.suffix == WORD_OPCODE_SUFFIX)
{
int op;
for (op = i.operands; --op >= 0; )
/* Reject eight bit registers, except where the template
requires them. (eg. movzb) */
if ((i.types[op] & Reg8) != 0
&& (i.tm.operand_types[op] & (Reg16|Reg32|Acc)) != 0)
{
as_bad (_("`%%%s' not allowed with `%s%c'"),
i.regs[op]->reg_name,
i.tm.name,
i.suffix);
return;
}
#if REGISTER_WARNINGS
/* Warn if the e prefix on a general reg is present. */
else if ((i.types[op] & Reg32) != 0
&& (i.tm.operand_types[op] & (Reg16|Acc)) != 0)
{
as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"),
(i.regs[op] - 8)->reg_name,
i.regs[op]->reg_name,
i.suffix);
}
#endif
}
else
abort();
} }
/* Make still unresolved immediate matches conform to size of immediate /* Make still unresolved immediate matches conform to size of immediate
@ -1377,18 +1456,32 @@ md_assemble (line)
{ {
/* Select between byte and word/dword operations. */ /* Select between byte and word/dword operations. */
if (i.tm.opcode_modifier & W) if (i.tm.opcode_modifier & W)
i.tm.base_opcode |= W;
/* Now select between word & dword operations via the operand
size prefix. */
if ((i.suffix == WORD_OPCODE_SUFFIX) ^ flag_16bit_code)
{ {
unsigned char prefix = WORD_PREFIX_OPCODE; if (i.tm.opcode_modifier & ShortForm)
i.tm.base_opcode |= 8;
else
i.tm.base_opcode |= 1;
}
/* Now select between word & dword operations via the operand
size prefix, except for instructions that will ignore this
prefix anyway. */
if ((i.suffix == DWORD_OPCODE_SUFFIX
|| i.suffix == LONG_OPCODE_SUFFIX) == flag_16bit_code
&& !(i.tm.opcode_modifier & IgnoreDataSize))
{
unsigned int prefix = DATA_PREFIX_OPCODE;
if (i.tm.opcode_modifier & JumpByte) /* jcxz, loop */ if (i.tm.opcode_modifier & JumpByte) /* jcxz, loop */
prefix = ADDR_PREFIX_OPCODE; prefix = ADDR_PREFIX_OPCODE;
if (! add_prefix (prefix)) if (! add_prefix (prefix))
return; return;
} }
/* Size floating point instruction. */
if (i.suffix == LONG_OPCODE_SUFFIX)
{
if (i.tm.opcode_modifier & FloatMF)
i.tm.base_opcode ^= 4;
}
} }
/* For insns with operands there are more diddles to do to the opcode. */ /* For insns with operands there are more diddles to do to the opcode. */
@ -1427,14 +1520,24 @@ md_assemble (line)
unsigned int op = (i.types[0] & (Reg | FloatReg)) ? 0 : 1; unsigned int op = (i.types[0] & (Reg | FloatReg)) ? 0 : 1;
/* Register goes in low 3 bits of opcode. */ /* Register goes in low 3 bits of opcode. */
i.tm.base_opcode |= i.regs[op]->reg_num; i.tm.base_opcode |= i.regs[op]->reg_num;
} if ((i.tm.opcode_modifier & Ugh) != 0)
else if (i.tm.opcode_modifier & ShortFormW) {
{ /* Warn about some common errors, but press on regardless.
/* Short form with 0x8 width bit. Register is always dest. operand */ The first case can be generated by gcc (<= 2.8.1). */
i.tm.base_opcode |= i.regs[1]->reg_num; if (i.operands == 2)
if (i.suffix == WORD_OPCODE_SUFFIX || {
i.suffix == DWORD_OPCODE_SUFFIX) /* reversed arguments on faddp, fsubp, etc. */
i.tm.base_opcode |= 0x8; as_warn (_("translating to `%s %%%s,%%%s'"), i.tm.name,
i.regs[1]->reg_name,
i.regs[0]->reg_name);
}
else
{
/* extraneous `l' suffix on fp insn */
as_warn (_("translating to `%s %%%s'"), i.tm.name,
i.regs[0]->reg_name);
}
}
} }
else if (i.tm.opcode_modifier & Modrm) else if (i.tm.opcode_modifier & Modrm)
{ {
@ -1468,7 +1571,7 @@ md_assemble (line)
were given in the reverse order. */ were given in the reverse order. */
if (i.tm.opcode_modifier & ReverseRegRegmem) if (i.tm.opcode_modifier & ReverseRegRegmem)
{ {
reg_entry *tmp = i.regs[source]; const reg_entry *tmp = i.regs[source];
i.regs[source] = i.regs[dest]; i.regs[source] = i.regs[dest];
i.regs[dest] = tmp; i.regs[dest] = tmp;
} }
@ -1495,9 +1598,9 @@ md_assemble (line)
if (i.mem_operands) if (i.mem_operands)
{ {
unsigned int fake_zero_displacement = 0; unsigned int fake_zero_displacement = 0;
unsigned int op = ((i.types[0] & Mem) unsigned int op = ((i.types[0] & AnyMem)
? 0 ? 0
: (i.types[1] & Mem) ? 1 : 2); : (i.types[1] & AnyMem) ? 1 : 2);
default_seg = &ds; default_seg = &ds;
@ -1617,25 +1720,16 @@ md_assemble (line)
if (i.rm.mode != 3) if (i.rm.mode != 3)
uses_mem_addrmode = 1; uses_mem_addrmode = 1;
} }
else if (i.tm.opcode_modifier & Seg2ShortForm) else if (i.tm.opcode_modifier & (Seg2ShortForm | Seg3ShortForm))
{ {
if (i.tm.base_opcode == POP_SEG_SHORT && i.regs[0]->reg_num == 1) if (i.tm.base_opcode == POP_SEG_SHORT && i.regs[0]->reg_num == 1)
{ {
as_bad (_("you can't `pop %%cs' on the 386.")); as_bad (_("you can't `pop %%cs'"));
return; return;
} }
i.tm.base_opcode |= (i.regs[0]->reg_num << 3); i.tm.base_opcode |= (i.regs[0]->reg_num << 3);
} }
else if (i.tm.opcode_modifier & Seg3ShortForm) else if ((i.tm.base_opcode & ~(D|W)) == MOV_AX_DISP32)
{
/* 'push %fs' is 0x0fa0; 'pop %fs' is 0x0fa1.
'push %gs' is 0x0fa8; 'pop %fs' is 0x0fa9.
So, only if i.regs[0]->reg_num == 5 (%gs) do we need
to change the opcode. */
if (i.regs[0]->reg_num == 5)
i.tm.base_opcode |= 0x08;
}
else if ((i.tm.base_opcode & ~DW) == MOV_AX_DISP32)
{ {
/* This is a special non-modrm instruction /* This is a special non-modrm instruction
that addresses memory with a 32-bit displacement mode anyway, that addresses memory with a 32-bit displacement mode anyway,
@ -1671,6 +1765,11 @@ md_assemble (line)
return; return;
} }
} }
else if ((i.tm.opcode_modifier & Ugh) != 0)
{
/* UnixWare fsub no args is alias for fsubp, fadd -> faddp, etc */
as_warn (_("translating to `%sp'"), i.tm.name);
}
} }
/* Handle conversion of 'int $3' --> special int3 insn. */ /* Handle conversion of 'int $3' --> special int3 insn. */
@ -1738,7 +1837,7 @@ md_assemble (line)
{ {
if (flag_16bit_code) if (flag_16bit_code)
{ {
FRAG_APPEND_1_CHAR (WORD_PREFIX_OPCODE); FRAG_APPEND_1_CHAR (DATA_PREFIX_OPCODE);
insn_size += 1; insn_size += 1;
} }
@ -1763,24 +1862,23 @@ md_assemble (line)
{ {
int size = (i.tm.opcode_modifier & JumpByte) ? 1 : 4; int size = (i.tm.opcode_modifier & JumpByte) ? 1 : 4;
unsigned long n = i.disps[0]->X_add_number; unsigned long n = i.disps[0]->X_add_number;
unsigned char *q;
if (size == 1) /* then this is a loop or jecxz type instruction */ if (size == 1) /* then this is a loop or jecxz type instruction */
{ {
if (i.prefix[ADDR_PREFIX]) if (i.prefix[ADDR_PREFIX])
{ {
FRAG_APPEND_1_CHAR (ADDR_PREFIX_OPCODE); FRAG_APPEND_1_CHAR (ADDR_PREFIX_OPCODE);
i.prefixes -= 1;
insn_size += 1; insn_size += 1;
i.prefixes -= 1;
} }
} }
if (i.prefixes != 0) if (i.prefixes != 0)
as_warn (_("skipping prefixes on this instruction")); as_warn (_("skipping prefixes on this instruction"));
if ((size == 4) && (flag_16bit_code)) if (size == 4 && flag_16bit_code)
{ {
FRAG_APPEND_1_CHAR (WORD_PREFIX_OPCODE); FRAG_APPEND_1_CHAR (DATA_PREFIX_OPCODE);
insn_size += 1; insn_size += 1;
} }
@ -1805,8 +1903,8 @@ md_assemble (line)
md_number_to_chars (p, (valueT) n, size); md_number_to_chars (p, (valueT) n, size);
if (size == 1 && !fits_in_signed_byte (n)) if (size == 1 && !fits_in_signed_byte (n))
{ {
as_bad (_("loop/jecx only takes byte displacement; %lu shortened to %d"), as_bad (_("`%s' only takes byte displacement; %lu shortened to %d"),
n, *p); i.tm.name, n, *p);
} }
} }
else else
@ -1823,7 +1921,7 @@ md_assemble (line)
if (flag_16bit_code) if (flag_16bit_code)
{ {
FRAG_APPEND_1_CHAR (WORD_PREFIX_OPCODE); FRAG_APPEND_1_CHAR (DATA_PREFIX_OPCODE);
insn_size += 1; insn_size += 1;
} }
@ -1900,8 +1998,9 @@ md_assemble (line)
| i.rm.reg << 3 | i.rm.reg << 3
| i.rm.mode << 6), | i.rm.mode << 6),
1); 1);
/* If i.rm.regmem == ESP (4) && i.rm.mode != Mode 3 (Register mode) /* If i.rm.regmem == ESP (4)
==> need second modrm byte. */ && i.rm.mode != (Register mode)
==> need second modrm byte. */
if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING
&& i.rm.mode != 3) && i.rm.mode != 3)
{ {
@ -1925,7 +2024,7 @@ md_assemble (line)
{ {
if (i.disps[n]->X_op == O_constant) if (i.disps[n]->X_op == O_constant)
{ {
if (i.types[n] & (Disp8 | Abs8)) if (i.types[n] & Disp8)
{ {
p = frag_more (1); p = frag_more (1);
insn_size += 1; insn_size += 1;
@ -1933,7 +2032,7 @@ md_assemble (line)
(valueT) i.disps[n]->X_add_number, (valueT) i.disps[n]->X_add_number,
1); 1);
} }
else if (i.types[n] & (Disp16 | Abs16)) else if (i.types[n] & Disp16)
{ {
p = frag_more (2); p = frag_more (2);
insn_size += 2; insn_size += 2;
@ -1942,7 +2041,7 @@ md_assemble (line)
2); 2);
} }
else else
{ /* Disp32|Abs32 */ { /* Disp32 */
p = frag_more (4); p = frag_more (4);
insn_size += 4; insn_size += 4;
md_number_to_chars (p, md_number_to_chars (p,
@ -2223,21 +2322,6 @@ i386_operand (operand_string)
return 0; return 0;
} }
/* Determine type of memory operand from opcode_suffix;
no opcode suffix implies general memory references. */
switch (i.suffix)
{
case BYTE_OPCODE_SUFFIX:
i.types[this_operand] |= Mem8;
break;
case WORD_OPCODE_SUFFIX:
i.types[this_operand] |= Mem16;
break;
case DWORD_OPCODE_SUFFIX:
default:
i.types[this_operand] |= Mem32;
}
/* Check for base index form. We detect the base index form by /* Check for base index form. We detect the base index form by
looking for an ')' at the end of the operand, searching looking for an ')' at the end of the operand, searching
for the '(' matching it, and finding a REGISTER_PREFIX or ',' for the '(' matching it, and finding a REGISTER_PREFIX or ','
@ -2483,13 +2567,14 @@ i386_operand (operand_string)
input_line_pointer); input_line_pointer);
RESTORE_END_STRING (displacement_string_end); RESTORE_END_STRING (displacement_string_end);
input_line_pointer = save_input_line_pointer; input_line_pointer = save_input_line_pointer;
#if 0 /* this is handled in expr */
#if 0 /* this is handled in expr. */
if (exp->X_op == O_absent) if (exp->X_op == O_absent)
{ {
/* missing expr becomes absolute 0 */ /* missing expr becomes absolute 0 */
as_bad (_("missing or invalid displacement `%s' taken as 0"), as_bad (_("missing or invalid displacement `%s' taken as 0"),
operand_string); operand_string);
i.types[this_operand] |= (Disp | Abs); i.types[this_operand] |= Disp;
exp->X_op = O_constant; exp->X_op = O_constant;
exp->X_add_number = 0; exp->X_add_number = 0;
exp->X_add_symbol = (symbolS *) 0; exp->X_add_symbol = (symbolS *) 0;
@ -2519,24 +2604,25 @@ i386_operand (operand_string)
} }
/* Special case for (%dx) while doing input/output op. */ /* Special case for (%dx) while doing input/output op. */
if (i.base_reg && if (i.base_reg
i.base_reg->reg_type == (Reg16 | InOutPortReg) && && i.base_reg->reg_type == (Reg16 | InOutPortReg)
i.index_reg == 0 && && i.index_reg == 0
i.log2_scale_factor == 0 && && i.log2_scale_factor == 0
i.seg[i.mem_operands] == 0) && i.seg[i.mem_operands] == 0
&& (i.types[this_operand] & Disp) == 0)
{ {
i.types[this_operand] = InOutPortReg; i.types[this_operand] = InOutPortReg;
return 1; return 1;
} }
/* Make sure the memory operand we've been dealt is valid. */ /* Make sure the memory operand we've been dealt is valid. */
if ((i.base_reg && (i.base_reg->reg_type & BaseIndex) == 0) if ((i.base_reg
|| (i.index_reg && ((i.index_reg->reg_type & BaseIndex) == 0 && (i.base_reg->reg_type & Reg32) == 0)
|| i.index_reg->reg_num == ESP_REG_NUM)) || (i.index_reg
|| (i.base_reg && i.index_reg && ((i.index_reg->reg_type & (Reg32|BaseIndex))
&& (i.base_reg->reg_type & i.index_reg->reg_type & Reg) == 0)) != (Reg32|BaseIndex))))
{ {
as_bad (_("`%s' is not a valid base/index expression"), as_bad (_("`%s' is not a valid %s bit base/index expression"),
operand_string); operand_string, "32");
return 0; return 0;
} }
i.mem_operands++; i.mem_operands++;
@ -2574,8 +2660,8 @@ md_estimate_size_before_relax (fragP, segment)
old_fr_fix = fragP->fr_fix; old_fr_fix = fragP->fr_fix;
opcode = (unsigned char *) fragP->fr_opcode; opcode = (unsigned char *) fragP->fr_opcode;
/* We've already got fragP->fr_subtype right; all we have to do is check /* We've already got fragP->fr_subtype right; all we have to do is
for un-relaxable symbols. */ check for un-relaxable symbols. */
if (S_GET_SEGMENT (fragP->fr_symbol) != segment) if (S_GET_SEGMENT (fragP->fr_symbol) != segment)
{ {
/* symbol is undefined in this segment */ /* symbol is undefined in this segment */
@ -2585,7 +2671,7 @@ md_estimate_size_before_relax (fragP, segment)
opcode[0] = 0xe9; /* dword disp jmp */ opcode[0] = 0xe9; /* dword disp jmp */
fragP->fr_fix += 4; fragP->fr_fix += 4;
fix_new (fragP, old_fr_fix, 4, fix_new (fragP, old_fr_fix, 4,
fragP->fr_symbol, fragP->fr_symbol,
fragP->fr_offset, 1, fragP->fr_offset, 1,
(GOT_symbol && /* Not quite right - we should switch on (GOT_symbol && /* Not quite right - we should switch on
presence of @PLT, but I cannot see how presence of @PLT, but I cannot see how
@ -2677,14 +2763,14 @@ md_convert_frag (abfd, sec, fragP)
case ENCODE_RELAX_STATE (COND_JUMP, WORD): case ENCODE_RELAX_STATE (COND_JUMP, WORD):
opcode[1] = TWO_BYTE_OPCODE_ESCAPE; opcode[1] = TWO_BYTE_OPCODE_ESCAPE;
opcode[2] = opcode[0] + 0x10; opcode[2] = opcode[0] + 0x10;
opcode[0] = WORD_PREFIX_OPCODE; opcode[0] = DATA_PREFIX_OPCODE;
extension = 4; /* 3 opcode + 2 displacement */ extension = 4; /* 3 opcode + 2 displacement */
where_to_put_displacement = &opcode[3]; where_to_put_displacement = &opcode[3];
break; break;
case ENCODE_RELAX_STATE (UNCOND_JUMP, WORD): case ENCODE_RELAX_STATE (UNCOND_JUMP, WORD):
opcode[1] = 0xe9; opcode[1] = 0xe9;
opcode[0] = WORD_PREFIX_OPCODE; opcode[0] = DATA_PREFIX_OPCODE;
extension = 3; /* 2 opcode + 2 displacement */ extension = 3; /* 2 opcode + 2 displacement */
where_to_put_displacement = &opcode[2]; where_to_put_displacement = &opcode[2];
break; break;
@ -3153,7 +3239,7 @@ tc_gen_reloc (section, fixp)
arelent *rel; arelent *rel;
bfd_reloc_code_real_type code; bfd_reloc_code_real_type code;
switch(fixp->fx_r_type) switch (fixp->fx_r_type)
{ {
case BFD_RELOC_386_PLT32: case BFD_RELOC_386_PLT32:
case BFD_RELOC_386_GOT32: case BFD_RELOC_386_GOT32:
@ -3177,7 +3263,10 @@ tc_gen_reloc (section, fixp)
fixp->fx_size); fixp->fx_size);
else else
as_bad (_("Can not do %d byte relocation"), fixp->fx_size); as_bad (_("Can not do %d byte relocation"), fixp->fx_size);
code = BFD_RELOC_32;
break;
} }
break;
} }
#undef MAP #undef MAP
#undef F #undef F

View File

@ -195,10 +195,12 @@ extern int tc_coff_sizemachdep PARAMS ((fragS *frag));
/* index_base_byte.base for no base register addressing */ /* index_base_byte.base for no base register addressing */
#define NO_BASE_REGISTER EBP_REG_NUM #define NO_BASE_REGISTER EBP_REG_NUM
/* these are the att as opcode suffixes, making movl --> mov, for example */ /* these are the opcode suffixes, making movl --> mov, for example */
#define DWORD_OPCODE_SUFFIX 'l' #define DWORD_OPCODE_SUFFIX 'l'
#define WORD_OPCODE_SUFFIX 'w' #define WORD_OPCODE_SUFFIX 'w'
#define BYTE_OPCODE_SUFFIX 'b' #define BYTE_OPCODE_SUFFIX 'b'
#define SHORT_OPCODE_SUFFIX 's'
#define LONG_OPCODE_SUFFIX 'l'
/* modrm.mode = REGMEM_FIELD_HAS_REG when a register is in there */ /* modrm.mode = REGMEM_FIELD_HAS_REG when a register is in there */
#define REGMEM_FIELD_HAS_REG 0x3/* always = 0x3 */ #define REGMEM_FIELD_HAS_REG 0x3/* always = 0x3 */
@ -235,44 +237,41 @@ extern int tc_coff_sizemachdep PARAMS ((fragS *frag));
#define Disp8 0x200 /* 8 bit displacement */ #define Disp8 0x200 /* 8 bit displacement */
#define Disp16 0x400 /* 16 bit displacement */ #define Disp16 0x400 /* 16 bit displacement */
#define Disp32 0x800 /* 32 bit displacement */ #define Disp32 0x800 /* 32 bit displacement */
/* Mem8,16,32 are used to limit the allowed sizes of memory operands */
#define Mem8 0x1000
#define Mem16 0x2000
#define Mem32 0x4000
/* specials */ /* specials */
#define InOutPortReg 0x10000 /* register to hold in/out port addr = dx */ #define InOutPortReg 0x1000 /* register to hold in/out port addr = dx */
#define ShiftCount 0x20000 /* register to hold shift cound = cl */ #define ShiftCount 0x2000 /* register to hold shift cound = cl */
#define Control 0x40000 /* Control register */ #define Control 0x4000 /* Control register */
#define Debug 0x80000 /* Debug register */ #define Debug 0x8000 /* Debug register */
#define Test 0x100000 /* Test register */ #define Test 0x10000 /* Test register */
#define FloatReg 0x200000 /* Float register */ #define FloatReg 0x20000 /* Float register */
#define FloatAcc 0x400000 /* Float stack top %st(0) */ #define FloatAcc 0x40000 /* Float stack top %st(0) */
#define SReg2 0x800000 /* 2 bit segment register */ #define SReg2 0x80000 /* 2 bit segment register */
#define SReg3 0x1000000 /* 3 bit segment register */ #define SReg3 0x100000 /* 3 bit segment register */
#define Acc 0x2000000 /* Accumulator %al or %ax or %eax */ #define Acc 0x200000 /* Accumulator %al or %ax or %eax */
#define JumpAbsolute 0x4000000 #define JumpAbsolute 0x400000
#define Abs8 0x8000000 #define RegMMX 0x800000 /* MMX register */
#define Abs16 0x10000000 #define EsSeg 0x1000000 /* String insn operand with fixed es segment */
#define Abs32 0x20000000
#define RegMMX 0x40000000 /* MMX register */
#define EsSeg 0x80000000 /* String insn operand with fixed es segment */
#define Reg (Reg8|Reg16|Reg32) /* gen'l register */ #define Reg (Reg8|Reg16|Reg32) /* gen'l register */
#define WordReg (Reg16|Reg32) #define WordReg (Reg16|Reg32)
#define ImplicitRegister (InOutPortReg|ShiftCount|Acc|FloatAcc)
#define Imm (Imm8|Imm8S|Imm16|Imm32) /* gen'l immediate */ #define Imm (Imm8|Imm8S|Imm16|Imm32) /* gen'l immediate */
#define Disp (Disp8|Disp16|Disp32) /* General displacement */ #define Disp (Disp8|Disp16|Disp32) /* General displacement */
#define Mem (Mem8|Mem16|Mem32|Disp|BaseIndex) /* General memory */ #define AnyMem (Disp|BaseIndex) /* General memory */
#define WordMem (Mem16|Mem32|Disp|BaseIndex) /* The following aliases are defined because the opcode table
#define ByteMem (Mem8|Disp|BaseIndex) carefully specifies the allowed memory types for each instruction.
#define ImplicitRegister (InOutPortReg|ShiftCount|Acc|FloatAcc) At the moment we can only tell a memory reference size by the
#define Abs (Abs8|Abs16|Abs32) instruction suffix, so there's not much point in defining Mem8,
Mem16, Mem32 and Mem64 opcode modifiers - We might as well just use
#define Byte (Reg8|Imm8|Imm8S) the suffix directly to check memory operands. */
#define Word (Reg16|Imm16) #define LLongMem AnyMem /* 64 bits (or more) */
#define DWord (Reg32|Imm32) #define LongMem AnyMem /* 32 bit memory ref */
#define ShortMem AnyMem /* 16 bit memory ref */
#define WordMem AnyMem /* 16 or 32 bit memory ref */
#define ByteMem AnyMem /* 8 bit memory ref */
#define SMALLEST_DISP_TYPE(num) \ #define SMALLEST_DISP_TYPE(num) \
fits_in_signed_byte(num) ? (Disp8|Disp32|Abs8|Abs32) : (Disp32|Abs32) (fits_in_signed_byte(num) ? (Disp8|Disp32) : Disp32)
typedef struct typedef struct
{ {
@ -282,7 +281,8 @@ typedef struct
/* how many operands */ /* how many operands */
unsigned int operands; unsigned int operands;
/* base_opcode is the fundamental opcode byte with a optional prefix(es). */ /* base_opcode is the fundamental opcode byte without optional
prefix(es). */
unsigned int base_opcode; unsigned int base_opcode;
/* extension_opcode is the 3 bit extension for group <n> insns. /* extension_opcode is the 3 bit extension for group <n> insns.
@ -297,33 +297,32 @@ typedef struct
/* opcode_modifier bits: */ /* opcode_modifier bits: */
#define W 0x1 /* set if operands can be words or dwords #define W 0x1 /* set if operands can be words or dwords
encoded the canonical way: MUST BE 0x1 */ encoded the canonical way */
#define D 0x2 /* D = 0 if Reg --> Regmem; #define D 0x2 /* D = 0 if Reg --> Regmem;
D = 1 if Regmem --> Reg: MUST BE 0x2 */ D = 1 if Regmem --> Reg: MUST BE 0x2 */
#define Modrm 0x4 #define Modrm 0x4
#define ReverseRegRegmem 0x8 #define ReverseRegRegmem 0x8 /* swap reg,regmem fields for 2 reg case */
#define FloatR 0x8 /* src/dest swap for floats: MUST BE 0x8 */
#define ShortForm 0x10 /* register is in low 3 bits of opcode */ #define ShortForm 0x10 /* register is in low 3 bits of opcode */
#define ShortFormW 0x20 /* ShortForm and W bit is 0x8 */ #define FloatMF 0x20 /* FP insn memory format bit, sized by 0x4 */
#define Seg2ShortForm 0x40 /* encoding of load segment reg insns */ #define Jump 0x40 /* special case for jump insns. */
#define Seg3ShortForm 0x80 /* fs/gs segment register insns. */ #define JumpDword 0x80 /* call and jump */
#define Jump 0x100 /* special case for jump insns. */ #define JumpByte 0x100 /* loop and jecxz */
#define JumpInterSegment 0x200 /* special case for intersegment leaps/calls */ #define JumpInterSegment 0x200 /* special case for intersegment leaps/calls */
#define FloatD 0x400 /* direction for float insns: MUST BE 0x400 */ #define FloatD 0x400 /* direction for float insns: MUST BE 0x400 */
#define JumpByte 0x800 #define Seg2ShortForm 0x800 /* encoding of load segment reg insns */
#define JumpDword 0x1000 #define Seg3ShortForm 0x1000 /* fs/gs segment register insns. */
#define FWait 0x2000 /* instruction needs FWAIT */ #define Data16 0x2000 /* needs data prefix if in 32-bit mode */
#define Data16 0x4000 /* needs data prefix if in 32-bit mode */ #define Data32 0x4000 /* needs data prefix if in 16-bit mode */
#define Data32 0x8000 /* needs data prefix if in 16-bit mode */ #define IgnoreDataSize 0x8000 /* instruction ignores operand size prefix */
#define IsString 0x100000 /* quick test for string instructions */ #define No_bSuf 0x10000 /* b suffix on instruction illegal */
#define regKludge 0x200000 /* fake an extra reg operand for clr, imul */ #define No_wSuf 0x20000 /* w suffix on instruction illegal */
#define No_lSuf 0x40000 /* l suffix on instruction illegal */
#define DW (D|W) /* shorthand */ #define No_sSuf 0x80000 /* s suffix on instruction illegal */
#define FWait 0x100000 /* instruction needs FWAIT */
/* (opcode_modifier & COMES_IN_BOTH_DIRECTIONS) indicates that the #define IsString 0x200000 /* quick test for string instructions */
source and destination operands can be reversed by setting either #define regKludge 0x400000 /* fake an extra reg operand for clr, imul */
the D (for integer insns) or the FloatD (for floating insns) bit #define Ugh 0x80000000 /* deprecated fp insn, gets a warning */
in base_opcode. */
#define COMES_IN_BOTH_DIRECTIONS (D|FloatD)
/* operand_types[i] describes the type of operand i. This is made /* operand_types[i] describes the type of operand i. This is made
by OR'ing together all of the possible type masks. (e.g. by OR'ing together all of the possible type masks. (e.g.