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:
parent
40afcc4cd4
commit
73a8be66ca
@ -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>
|
||||
|
||||
* config/tc-d30v.c (md_assemble): Store previous segment state
|
||||
|
@ -38,6 +38,10 @@
|
||||
#define TC_RELOC(X,Y) (Y)
|
||||
#endif
|
||||
|
||||
#ifndef REGISTER_WARNINGS
|
||||
#define REGISTER_WARNINGS 1
|
||||
#endif
|
||||
|
||||
#ifndef SCALE1_WHEN_NO_INDEX
|
||||
/* Specifying a scale factor besides 1 when there is no index is
|
||||
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_signed_word 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));
|
||||
#ifdef BFD_ASSEMBLER
|
||||
static bfd_reloc_code_real_type reloc
|
||||
@ -66,8 +70,10 @@ struct _i386_insn
|
||||
{
|
||||
/* TM holds the template for the insn were currently assembling. */
|
||||
template tm;
|
||||
|
||||
/* SUFFIX holds the opcode suffix (e.g. 'l' for 'movl') if given. */
|
||||
char suffix;
|
||||
|
||||
/* Operands are coded with OPERANDS, TYPES, DISPS, IMMS, and REGS. */
|
||||
|
||||
/* OPERANDS gives the number of given operands. */
|
||||
@ -97,12 +103,12 @@ struct _i386_insn
|
||||
expressionS *imms[MAX_OPERANDS];
|
||||
|
||||
/* 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
|
||||
the base index byte below. */
|
||||
reg_entry *base_reg;
|
||||
reg_entry *index_reg;
|
||||
const reg_entry *base_reg;
|
||||
const reg_entry *index_reg;
|
||||
unsigned int log2_scale_factor;
|
||||
|
||||
/* SEG gives the seg_entries of this insn. They are zero unless
|
||||
@ -115,7 +121,7 @@ struct _i386_insn
|
||||
unsigned char prefix[MAX_PREFIXES];
|
||||
|
||||
/* 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;
|
||||
base_index_byte bi;
|
||||
@ -363,7 +369,7 @@ static INLINE unsigned long
|
||||
mode_from_disp_size (t)
|
||||
unsigned long t;
|
||||
{
|
||||
return (t & Disp8) ? 1 : (t & Disp32) ? 2 : 0;
|
||||
return (t & Disp8) ? 1 : (t & (Disp16|Disp32)) ? 2 : 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
@ -436,13 +442,16 @@ smallest_imm_type (num)
|
||||
added. */
|
||||
static int
|
||||
add_prefix (prefix)
|
||||
unsigned char prefix;
|
||||
unsigned int prefix;
|
||||
{
|
||||
int ret = 1;
|
||||
int q;
|
||||
|
||||
switch (prefix)
|
||||
{
|
||||
default:
|
||||
abort ();
|
||||
|
||||
case CS_PREFIX_OPCODE:
|
||||
case DS_PREFIX_OPCODE:
|
||||
case ES_PREFIX_OPCODE:
|
||||
@ -468,8 +477,9 @@ add_prefix (prefix)
|
||||
q = ADDR_PREFIX;
|
||||
break;
|
||||
|
||||
case WORD_PREFIX_OPCODE:
|
||||
case DATA_PREFIX_OPCODE:
|
||||
q = DATA_PREFIX;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i.prefix[q])
|
||||
@ -702,7 +712,7 @@ pi (line, x)
|
||||
fprintf (stdout, "%s\n", x->regs[i]->reg_name);
|
||||
if (x->types[i] & Imm)
|
||||
pe (x->imms[i]);
|
||||
if (x->types[i] & (Disp | Abs))
|
||||
if (x->types[i] & Disp)
|
||||
pe (x->disps[i]);
|
||||
}
|
||||
}
|
||||
@ -776,27 +786,21 @@ type_names[] =
|
||||
{ Imm8S, "i8s" },
|
||||
{ Imm16, "i16" },
|
||||
{ Imm32, "i32" },
|
||||
{ Mem8, "Mem8" },
|
||||
{ Mem16, "Mem16" },
|
||||
{ Mem32, "Mem32" },
|
||||
{ Imm1, "i1" },
|
||||
{ BaseIndex, "BaseIndex" },
|
||||
{ Abs8, "Abs8" },
|
||||
{ Abs16, "Abs16" },
|
||||
{ Abs32, "Abs32" },
|
||||
{ Disp8, "d8" },
|
||||
{ Disp16, "d16" },
|
||||
{ Disp32, "d32" },
|
||||
{ SReg2, "SReg2" },
|
||||
{ SReg3, "SReg3" },
|
||||
{ Acc, "Acc" },
|
||||
{ InOutPortReg, "InOutPortReg" },
|
||||
{ ShiftCount, "ShiftCount" },
|
||||
{ Imm1, "i1" },
|
||||
{ Control, "control reg" },
|
||||
{ Test, "test reg" },
|
||||
{ Debug, "debug reg" },
|
||||
{ FloatReg, "FReg" },
|
||||
{ FloatAcc, "FAcc" },
|
||||
{ SReg2, "SReg2" },
|
||||
{ SReg3, "SReg3" },
|
||||
{ Acc, "Acc" },
|
||||
{ JumpAbsolute, "Jump Absolute" },
|
||||
{ RegMMX, "rMMX" },
|
||||
{ EsSeg, "es" },
|
||||
@ -961,7 +965,8 @@ md_assemble (line)
|
||||
/* add prefix, checking for repeated prefixes */
|
||||
switch (add_prefix (prefix->prefix_code))
|
||||
{
|
||||
case 0: return;
|
||||
case 0:
|
||||
return;
|
||||
case 2:
|
||||
expecting_string_instruction = prefix->prefix_name;
|
||||
break;
|
||||
@ -990,6 +995,10 @@ md_assemble (line)
|
||||
case DWORD_OPCODE_SUFFIX:
|
||||
case WORD_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';
|
||||
current_templates = (templates *) hash_find (op_hash, token_start);
|
||||
token_start[last_index] = last_char;
|
||||
@ -1005,8 +1014,8 @@ md_assemble (line)
|
||||
RESTORE_END_STRING (l);
|
||||
|
||||
/* check for rep/repne without a string instruction */
|
||||
if (expecting_string_instruction &&
|
||||
!(current_templates->start->opcode_modifier & IsString))
|
||||
if (expecting_string_instruction
|
||||
&& !(current_templates->start->opcode_modifier & IsString))
|
||||
{
|
||||
as_bad (_("expecting string instruction after `%s'"),
|
||||
expecting_string_instruction);
|
||||
@ -1112,42 +1121,46 @@ md_assemble (line)
|
||||
making sure the overlap of the given operands types is consistent
|
||||
with the template operand types. */
|
||||
|
||||
#define MATCH(overlap,given_type) \
|
||||
(overlap \
|
||||
&& ((overlap & (JumpAbsolute|BaseIndex|Mem8)) \
|
||||
== (given_type & (JumpAbsolute|BaseIndex|Mem8))))
|
||||
#define MATCH(overlap, given, template) \
|
||||
((overlap) \
|
||||
&& (((overlap) & (JumpAbsolute|BaseIndex)) \
|
||||
== ((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;
|
||||
expressionS *exp;
|
||||
unsigned int overlap2;
|
||||
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;
|
||||
t < current_templates->end;
|
||||
t++)
|
||||
{
|
||||
/* must have right number of operands */
|
||||
if (i.operands != t->operands)
|
||||
/* Must have right number of operands, and must not have
|
||||
disallowed suffix. */
|
||||
if (i.operands != t->operands || (t->opcode_modifier & suffix_check))
|
||||
continue;
|
||||
else if (!t->operands)
|
||||
break; /* 0 operands always matches */
|
||||
@ -1156,50 +1169,55 @@ md_assemble (line)
|
||||
switch (t->operands)
|
||||
{
|
||||
case 1:
|
||||
if (!MATCH (overlap0, i.types[0]))
|
||||
if (!MATCH (overlap0, i.types[0], t->operand_types[0]))
|
||||
continue;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
overlap1 = i.types[1] & t->operand_types[1];
|
||||
if (!MATCH (overlap0, i.types[0]) ||
|
||||
!MATCH (overlap1, i.types[1]) ||
|
||||
!CONSISTENT_REGISTER_MATCH (overlap0, overlap1,
|
||||
t->operand_types[0],
|
||||
t->operand_types[1]))
|
||||
if (!MATCH (overlap0, i.types[0], t->operand_types[0])
|
||||
|| !MATCH (overlap1, i.types[1], t->operand_types[1])
|
||||
|| !CONSISTENT_REGISTER_MATCH (overlap0, i.types[0],
|
||||
t->operand_types[0],
|
||||
overlap1, i.types[1],
|
||||
t->operand_types[1]))
|
||||
{
|
||||
|
||||
/* check if other direction is valid ... */
|
||||
if (!(t->opcode_modifier & COMES_IN_BOTH_DIRECTIONS))
|
||||
if ((t->opcode_modifier & (D|FloatD)) == 0)
|
||||
continue;
|
||||
|
||||
/* try reversing direction of operands */
|
||||
overlap0 = i.types[0] & t->operand_types[1];
|
||||
overlap1 = i.types[1] & t->operand_types[0];
|
||||
if (!MATCH (overlap0, i.types[0]) ||
|
||||
!MATCH (overlap1, i.types[1]) ||
|
||||
!CONSISTENT_REGISTER_MATCH (overlap0, overlap1,
|
||||
t->operand_types[1],
|
||||
t->operand_types[0]))
|
||||
if (!MATCH (overlap0, i.types[0], t->operand_types[1])
|
||||
|| !MATCH (overlap1, i.types[1], t->operand_types[0])
|
||||
|| !CONSISTENT_REGISTER_MATCH (overlap0, i.types[0],
|
||||
t->operand_types[1],
|
||||
overlap1, i.types[1],
|
||||
t->operand_types[0]))
|
||||
{
|
||||
/* does not match either direction */
|
||||
continue;
|
||||
}
|
||||
/* found a reverse match here -- slip through */
|
||||
/* found_reverse_match holds which of D or FloatD we've found */
|
||||
found_reverse_match = t->opcode_modifier & COMES_IN_BOTH_DIRECTIONS;
|
||||
} /* endif: not forward match */
|
||||
/* found either forward/reverse 2 operand match here */
|
||||
/* found_reverse_match holds which of D or FloatDR
|
||||
we've found. */
|
||||
found_reverse_match = t->opcode_modifier & (D|FloatDR);
|
||||
break;
|
||||
}
|
||||
/* found a forward 2 operand match here */
|
||||
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];
|
||||
if (!MATCH (overlap2, i.types[2]) ||
|
||||
!CONSISTENT_REGISTER_MATCH (overlap0, overlap2,
|
||||
t->operand_types[0],
|
||||
t->operand_types[2]) ||
|
||||
!CONSISTENT_REGISTER_MATCH (overlap1, overlap2,
|
||||
t->operand_types[1],
|
||||
t->operand_types[2]))
|
||||
if (!MATCH (overlap2, i.types[2], t->operand_types[2])
|
||||
|| !CONSISTENT_REGISTER_MATCH (overlap1, i.types[1],
|
||||
t->operand_types[1],
|
||||
overlap2, i.types[2],
|
||||
t->operand_types[2]))
|
||||
continue;
|
||||
}
|
||||
/* found either forward/reverse 2 or 3 operand match here:
|
||||
@ -1216,23 +1234,23 @@ md_assemble (line)
|
||||
|
||||
/* Copy the template we found. */
|
||||
i.tm = *t;
|
||||
if (i.tm.opcode_modifier & FWait)
|
||||
if (! add_prefix (FWAIT_OPCODE))
|
||||
return;
|
||||
|
||||
if (found_reverse_match)
|
||||
{
|
||||
i.tm.operand_types[0] = t->operand_types[1];
|
||||
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 */
|
||||
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.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"),
|
||||
i.tm.name,
|
||||
@ -1247,7 +1265,7 @@ md_assemble (line)
|
||||
}
|
||||
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"),
|
||||
i.tm.name,
|
||||
@ -1257,69 +1275,130 @@ md_assemble (line)
|
||||
}
|
||||
}
|
||||
|
||||
/* If the matched instruction specifies an explicit opcode suffix,
|
||||
use it - and make sure none has already been specified. */
|
||||
/* If matched instruction specifies an explicit opcode suffix, use
|
||||
it. */
|
||||
if (i.tm.opcode_modifier & (Data16|Data32))
|
||||
{
|
||||
if (i.suffix)
|
||||
{
|
||||
as_bad (_("extraneous opcode suffix given"));
|
||||
return;
|
||||
}
|
||||
if (i.tm.opcode_modifier & Data16)
|
||||
i.suffix = WORD_OPCODE_SUFFIX;
|
||||
else
|
||||
i.suffix = DWORD_OPCODE_SUFFIX;
|
||||
}
|
||||
|
||||
/* If there's no opcode suffix we try to invent one based on register
|
||||
operands. */
|
||||
if (!i.suffix && i.reg_operands)
|
||||
else if (i.reg_operands)
|
||||
{
|
||||
/* We take i.suffix from the LAST register operand specified. This
|
||||
assumes that the last register operands is the destination register
|
||||
operand. */
|
||||
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)
|
||||
/* If there's no opcode suffix we try to invent one based on
|
||||
register operands. */
|
||||
if (!i.suffix)
|
||||
{
|
||||
default:
|
||||
abort ();
|
||||
case BYTE_OPCODE_SUFFIX:
|
||||
/* 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[i.operands - 1] & Reg8) == 0
|
||||
&& i.regs[i.operands - 1]->reg_num >= 4)
|
||||
bad = 1;
|
||||
break;
|
||||
case WORD_OPCODE_SUFFIX:
|
||||
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;
|
||||
/* We take i.suffix from the last register operand specified,
|
||||
Destination register type is more significant than source
|
||||
register type. */
|
||||
int op;
|
||||
for (op = i.operands; --op >= 0; )
|
||||
if (i.types[op] & Reg)
|
||||
{
|
||||
i.suffix = ((i.types[op] & Reg8) ? BYTE_OPCODE_SUFFIX :
|
||||
(i.types[op] & Reg16) ? WORD_OPCODE_SUFFIX :
|
||||
DWORD_OPCODE_SUFFIX);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bad)
|
||||
as_bad (_("register does not match opcode suffix"));
|
||||
else if (i.suffix == BYTE_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
|
||||
@ -1377,18 +1456,32 @@ md_assemble (line)
|
||||
{
|
||||
/* Select between byte and word/dword operations. */
|
||||
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 */
|
||||
prefix = ADDR_PREFIX_OPCODE;
|
||||
|
||||
if (! add_prefix (prefix))
|
||||
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. */
|
||||
@ -1427,14 +1520,24 @@ md_assemble (line)
|
||||
unsigned int op = (i.types[0] & (Reg | FloatReg)) ? 0 : 1;
|
||||
/* Register goes in low 3 bits of opcode. */
|
||||
i.tm.base_opcode |= i.regs[op]->reg_num;
|
||||
}
|
||||
else if (i.tm.opcode_modifier & ShortFormW)
|
||||
{
|
||||
/* Short form with 0x8 width bit. Register is always dest. operand */
|
||||
i.tm.base_opcode |= i.regs[1]->reg_num;
|
||||
if (i.suffix == WORD_OPCODE_SUFFIX ||
|
||||
i.suffix == DWORD_OPCODE_SUFFIX)
|
||||
i.tm.base_opcode |= 0x8;
|
||||
if ((i.tm.opcode_modifier & Ugh) != 0)
|
||||
{
|
||||
/* Warn about some common errors, but press on regardless.
|
||||
The first case can be generated by gcc (<= 2.8.1). */
|
||||
if (i.operands == 2)
|
||||
{
|
||||
/* reversed arguments on faddp, fsubp, etc. */
|
||||
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)
|
||||
{
|
||||
@ -1468,7 +1571,7 @@ md_assemble (line)
|
||||
were given in the reverse order. */
|
||||
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[dest] = tmp;
|
||||
}
|
||||
@ -1495,9 +1598,9 @@ md_assemble (line)
|
||||
if (i.mem_operands)
|
||||
{
|
||||
unsigned int fake_zero_displacement = 0;
|
||||
unsigned int op = ((i.types[0] & Mem)
|
||||
unsigned int op = ((i.types[0] & AnyMem)
|
||||
? 0
|
||||
: (i.types[1] & Mem) ? 1 : 2);
|
||||
: (i.types[1] & AnyMem) ? 1 : 2);
|
||||
|
||||
default_seg = &ds;
|
||||
|
||||
@ -1617,25 +1720,16 @@ md_assemble (line)
|
||||
if (i.rm.mode != 3)
|
||||
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)
|
||||
{
|
||||
as_bad (_("you can't `pop %%cs' on the 386."));
|
||||
as_bad (_("you can't `pop %%cs'"));
|
||||
return;
|
||||
}
|
||||
i.tm.base_opcode |= (i.regs[0]->reg_num << 3);
|
||||
}
|
||||
else if (i.tm.opcode_modifier & Seg3ShortForm)
|
||||
{
|
||||
/* '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)
|
||||
else if ((i.tm.base_opcode & ~(D|W)) == MOV_AX_DISP32)
|
||||
{
|
||||
/* This is a special non-modrm instruction
|
||||
that addresses memory with a 32-bit displacement mode anyway,
|
||||
@ -1671,6 +1765,11 @@ md_assemble (line)
|
||||
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. */
|
||||
@ -1738,7 +1837,7 @@ md_assemble (line)
|
||||
{
|
||||
if (flag_16bit_code)
|
||||
{
|
||||
FRAG_APPEND_1_CHAR (WORD_PREFIX_OPCODE);
|
||||
FRAG_APPEND_1_CHAR (DATA_PREFIX_OPCODE);
|
||||
insn_size += 1;
|
||||
}
|
||||
|
||||
@ -1763,24 +1862,23 @@ md_assemble (line)
|
||||
{
|
||||
int size = (i.tm.opcode_modifier & JumpByte) ? 1 : 4;
|
||||
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 (i.prefix[ADDR_PREFIX])
|
||||
{
|
||||
FRAG_APPEND_1_CHAR (ADDR_PREFIX_OPCODE);
|
||||
i.prefixes -= 1;
|
||||
insn_size += 1;
|
||||
i.prefixes -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (i.prefixes != 0)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1805,8 +1903,8 @@ md_assemble (line)
|
||||
md_number_to_chars (p, (valueT) n, size);
|
||||
if (size == 1 && !fits_in_signed_byte (n))
|
||||
{
|
||||
as_bad (_("loop/jecx only takes byte displacement; %lu shortened to %d"),
|
||||
n, *p);
|
||||
as_bad (_("`%s' only takes byte displacement; %lu shortened to %d"),
|
||||
i.tm.name, n, *p);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1823,7 +1921,7 @@ md_assemble (line)
|
||||
|
||||
if (flag_16bit_code)
|
||||
{
|
||||
FRAG_APPEND_1_CHAR (WORD_PREFIX_OPCODE);
|
||||
FRAG_APPEND_1_CHAR (DATA_PREFIX_OPCODE);
|
||||
insn_size += 1;
|
||||
}
|
||||
|
||||
@ -1900,8 +1998,9 @@ md_assemble (line)
|
||||
| i.rm.reg << 3
|
||||
| i.rm.mode << 6),
|
||||
1);
|
||||
/* If i.rm.regmem == ESP (4) && i.rm.mode != Mode 3 (Register mode)
|
||||
==> need second modrm byte. */
|
||||
/* If i.rm.regmem == ESP (4)
|
||||
&& i.rm.mode != (Register mode)
|
||||
==> need second modrm byte. */
|
||||
if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING
|
||||
&& i.rm.mode != 3)
|
||||
{
|
||||
@ -1925,7 +2024,7 @@ md_assemble (line)
|
||||
{
|
||||
if (i.disps[n]->X_op == O_constant)
|
||||
{
|
||||
if (i.types[n] & (Disp8 | Abs8))
|
||||
if (i.types[n] & Disp8)
|
||||
{
|
||||
p = frag_more (1);
|
||||
insn_size += 1;
|
||||
@ -1933,7 +2032,7 @@ md_assemble (line)
|
||||
(valueT) i.disps[n]->X_add_number,
|
||||
1);
|
||||
}
|
||||
else if (i.types[n] & (Disp16 | Abs16))
|
||||
else if (i.types[n] & Disp16)
|
||||
{
|
||||
p = frag_more (2);
|
||||
insn_size += 2;
|
||||
@ -1942,7 +2041,7 @@ md_assemble (line)
|
||||
2);
|
||||
}
|
||||
else
|
||||
{ /* Disp32|Abs32 */
|
||||
{ /* Disp32 */
|
||||
p = frag_more (4);
|
||||
insn_size += 4;
|
||||
md_number_to_chars (p,
|
||||
@ -2223,21 +2322,6 @@ i386_operand (operand_string)
|
||||
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
|
||||
looking for an ')' at the end of the operand, searching
|
||||
for the '(' matching it, and finding a REGISTER_PREFIX or ','
|
||||
@ -2483,13 +2567,14 @@ i386_operand (operand_string)
|
||||
input_line_pointer);
|
||||
RESTORE_END_STRING (displacement_string_end);
|
||||
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)
|
||||
{
|
||||
/* missing expr becomes absolute 0 */
|
||||
as_bad (_("missing or invalid displacement `%s' taken as 0"),
|
||||
operand_string);
|
||||
i.types[this_operand] |= (Disp | Abs);
|
||||
i.types[this_operand] |= Disp;
|
||||
exp->X_op = O_constant;
|
||||
exp->X_add_number = 0;
|
||||
exp->X_add_symbol = (symbolS *) 0;
|
||||
@ -2519,24 +2604,25 @@ i386_operand (operand_string)
|
||||
}
|
||||
|
||||
/* Special case for (%dx) while doing input/output op. */
|
||||
if (i.base_reg &&
|
||||
i.base_reg->reg_type == (Reg16 | InOutPortReg) &&
|
||||
i.index_reg == 0 &&
|
||||
i.log2_scale_factor == 0 &&
|
||||
i.seg[i.mem_operands] == 0)
|
||||
if (i.base_reg
|
||||
&& i.base_reg->reg_type == (Reg16 | InOutPortReg)
|
||||
&& i.index_reg == 0
|
||||
&& i.log2_scale_factor == 0
|
||||
&& i.seg[i.mem_operands] == 0
|
||||
&& (i.types[this_operand] & Disp) == 0)
|
||||
{
|
||||
i.types[this_operand] = InOutPortReg;
|
||||
return 1;
|
||||
}
|
||||
/* Make sure the memory operand we've been dealt is valid. */
|
||||
if ((i.base_reg && (i.base_reg->reg_type & BaseIndex) == 0)
|
||||
|| (i.index_reg && ((i.index_reg->reg_type & BaseIndex) == 0
|
||||
|| i.index_reg->reg_num == ESP_REG_NUM))
|
||||
|| (i.base_reg && i.index_reg
|
||||
&& (i.base_reg->reg_type & i.index_reg->reg_type & Reg) == 0))
|
||||
/* Make sure the memory operand we've been dealt is valid. */
|
||||
if ((i.base_reg
|
||||
&& (i.base_reg->reg_type & Reg32) == 0)
|
||||
|| (i.index_reg
|
||||
&& ((i.index_reg->reg_type & (Reg32|BaseIndex))
|
||||
!= (Reg32|BaseIndex))))
|
||||
{
|
||||
as_bad (_("`%s' is not a valid base/index expression"),
|
||||
operand_string);
|
||||
as_bad (_("`%s' is not a valid %s bit base/index expression"),
|
||||
operand_string, "32");
|
||||
return 0;
|
||||
}
|
||||
i.mem_operands++;
|
||||
@ -2574,8 +2660,8 @@ md_estimate_size_before_relax (fragP, segment)
|
||||
|
||||
old_fr_fix = fragP->fr_fix;
|
||||
opcode = (unsigned char *) fragP->fr_opcode;
|
||||
/* We've already got fragP->fr_subtype right; all we have to do is check
|
||||
for un-relaxable symbols. */
|
||||
/* We've already got fragP->fr_subtype right; all we have to do is
|
||||
check for un-relaxable symbols. */
|
||||
if (S_GET_SEGMENT (fragP->fr_symbol) != segment)
|
||||
{
|
||||
/* symbol is undefined in this segment */
|
||||
@ -2585,7 +2671,7 @@ md_estimate_size_before_relax (fragP, segment)
|
||||
opcode[0] = 0xe9; /* dword disp jmp */
|
||||
fragP->fr_fix += 4;
|
||||
fix_new (fragP, old_fr_fix, 4,
|
||||
fragP->fr_symbol,
|
||||
fragP->fr_symbol,
|
||||
fragP->fr_offset, 1,
|
||||
(GOT_symbol && /* Not quite right - we should switch on
|
||||
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):
|
||||
opcode[1] = TWO_BYTE_OPCODE_ESCAPE;
|
||||
opcode[2] = opcode[0] + 0x10;
|
||||
opcode[0] = WORD_PREFIX_OPCODE;
|
||||
opcode[0] = DATA_PREFIX_OPCODE;
|
||||
extension = 4; /* 3 opcode + 2 displacement */
|
||||
where_to_put_displacement = &opcode[3];
|
||||
break;
|
||||
|
||||
case ENCODE_RELAX_STATE (UNCOND_JUMP, WORD):
|
||||
opcode[1] = 0xe9;
|
||||
opcode[0] = WORD_PREFIX_OPCODE;
|
||||
opcode[0] = DATA_PREFIX_OPCODE;
|
||||
extension = 3; /* 2 opcode + 2 displacement */
|
||||
where_to_put_displacement = &opcode[2];
|
||||
break;
|
||||
@ -3153,7 +3239,7 @@ tc_gen_reloc (section, fixp)
|
||||
arelent *rel;
|
||||
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_GOT32:
|
||||
@ -3177,7 +3263,10 @@ tc_gen_reloc (section, fixp)
|
||||
fixp->fx_size);
|
||||
else
|
||||
as_bad (_("Can not do %d byte relocation"), fixp->fx_size);
|
||||
code = BFD_RELOC_32;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#undef MAP
|
||||
#undef F
|
||||
|
@ -195,10 +195,12 @@ extern int tc_coff_sizemachdep PARAMS ((fragS *frag));
|
||||
/* index_base_byte.base for no base register addressing */
|
||||
#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 WORD_OPCODE_SUFFIX 'w'
|
||||
#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 */
|
||||
#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 Disp16 0x400 /* 16 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 */
|
||||
#define InOutPortReg 0x10000 /* register to hold in/out port addr = dx */
|
||||
#define ShiftCount 0x20000 /* register to hold shift cound = cl */
|
||||
#define Control 0x40000 /* Control register */
|
||||
#define Debug 0x80000 /* Debug register */
|
||||
#define Test 0x100000 /* Test register */
|
||||
#define FloatReg 0x200000 /* Float register */
|
||||
#define FloatAcc 0x400000 /* Float stack top %st(0) */
|
||||
#define SReg2 0x800000 /* 2 bit segment register */
|
||||
#define SReg3 0x1000000 /* 3 bit segment register */
|
||||
#define Acc 0x2000000 /* Accumulator %al or %ax or %eax */
|
||||
#define JumpAbsolute 0x4000000
|
||||
#define Abs8 0x8000000
|
||||
#define Abs16 0x10000000
|
||||
#define Abs32 0x20000000
|
||||
#define RegMMX 0x40000000 /* MMX register */
|
||||
#define EsSeg 0x80000000 /* String insn operand with fixed es segment */
|
||||
#define InOutPortReg 0x1000 /* register to hold in/out port addr = dx */
|
||||
#define ShiftCount 0x2000 /* register to hold shift cound = cl */
|
||||
#define Control 0x4000 /* Control register */
|
||||
#define Debug 0x8000 /* Debug register */
|
||||
#define Test 0x10000 /* Test register */
|
||||
#define FloatReg 0x20000 /* Float register */
|
||||
#define FloatAcc 0x40000 /* Float stack top %st(0) */
|
||||
#define SReg2 0x80000 /* 2 bit segment register */
|
||||
#define SReg3 0x100000 /* 3 bit segment register */
|
||||
#define Acc 0x200000 /* Accumulator %al or %ax or %eax */
|
||||
#define JumpAbsolute 0x400000
|
||||
#define RegMMX 0x800000 /* MMX register */
|
||||
#define EsSeg 0x1000000 /* String insn operand with fixed es segment */
|
||||
|
||||
#define Reg (Reg8|Reg16|Reg32) /* gen'l register */
|
||||
#define WordReg (Reg16|Reg32)
|
||||
#define ImplicitRegister (InOutPortReg|ShiftCount|Acc|FloatAcc)
|
||||
#define Imm (Imm8|Imm8S|Imm16|Imm32) /* gen'l immediate */
|
||||
#define Disp (Disp8|Disp16|Disp32) /* General displacement */
|
||||
#define Mem (Mem8|Mem16|Mem32|Disp|BaseIndex) /* General memory */
|
||||
#define WordMem (Mem16|Mem32|Disp|BaseIndex)
|
||||
#define ByteMem (Mem8|Disp|BaseIndex)
|
||||
#define ImplicitRegister (InOutPortReg|ShiftCount|Acc|FloatAcc)
|
||||
#define Abs (Abs8|Abs16|Abs32)
|
||||
|
||||
#define Byte (Reg8|Imm8|Imm8S)
|
||||
#define Word (Reg16|Imm16)
|
||||
#define DWord (Reg32|Imm32)
|
||||
#define AnyMem (Disp|BaseIndex) /* General memory */
|
||||
/* The following aliases are defined because the opcode table
|
||||
carefully specifies the allowed memory types for each instruction.
|
||||
At the moment we can only tell a memory reference size by the
|
||||
instruction suffix, so there's not much point in defining Mem8,
|
||||
Mem16, Mem32 and Mem64 opcode modifiers - We might as well just use
|
||||
the suffix directly to check memory operands. */
|
||||
#define LLongMem AnyMem /* 64 bits (or more) */
|
||||
#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) \
|
||||
fits_in_signed_byte(num) ? (Disp8|Disp32|Abs8|Abs32) : (Disp32|Abs32)
|
||||
(fits_in_signed_byte(num) ? (Disp8|Disp32) : Disp32)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -282,7 +281,8 @@ typedef struct
|
||||
/* how many 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;
|
||||
|
||||
/* extension_opcode is the 3 bit extension for group <n> insns.
|
||||
@ -297,33 +297,32 @@ typedef struct
|
||||
|
||||
/* opcode_modifier bits: */
|
||||
#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;
|
||||
D = 1 if Regmem --> Reg: MUST BE 0x2 */
|
||||
#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 ShortFormW 0x20 /* ShortForm and W bit is 0x8 */
|
||||
#define Seg2ShortForm 0x40 /* encoding of load segment reg insns */
|
||||
#define Seg3ShortForm 0x80 /* fs/gs segment register insns. */
|
||||
#define Jump 0x100 /* special case for jump insns. */
|
||||
#define FloatMF 0x20 /* FP insn memory format bit, sized by 0x4 */
|
||||
#define Jump 0x40 /* special case for jump insns. */
|
||||
#define JumpDword 0x80 /* call and jump */
|
||||
#define JumpByte 0x100 /* loop and jecxz */
|
||||
#define JumpInterSegment 0x200 /* special case for intersegment leaps/calls */
|
||||
#define FloatD 0x400 /* direction for float insns: MUST BE 0x400 */
|
||||
#define JumpByte 0x800
|
||||
#define JumpDword 0x1000
|
||||
#define FWait 0x2000 /* instruction needs FWAIT */
|
||||
#define Data16 0x4000 /* needs data prefix if in 32-bit mode */
|
||||
#define Data32 0x8000 /* needs data prefix if in 16-bit mode */
|
||||
#define IsString 0x100000 /* quick test for string instructions */
|
||||
#define regKludge 0x200000 /* fake an extra reg operand for clr, imul */
|
||||
|
||||
#define DW (D|W) /* shorthand */
|
||||
|
||||
/* (opcode_modifier & COMES_IN_BOTH_DIRECTIONS) indicates that the
|
||||
source and destination operands can be reversed by setting either
|
||||
the D (for integer insns) or the FloatD (for floating insns) bit
|
||||
in base_opcode. */
|
||||
#define COMES_IN_BOTH_DIRECTIONS (D|FloatD)
|
||||
#define Seg2ShortForm 0x800 /* encoding of load segment reg insns */
|
||||
#define Seg3ShortForm 0x1000 /* fs/gs segment register insns. */
|
||||
#define Data16 0x2000 /* needs data prefix if in 32-bit mode */
|
||||
#define Data32 0x4000 /* needs data prefix if in 16-bit mode */
|
||||
#define IgnoreDataSize 0x8000 /* instruction ignores operand size prefix */
|
||||
#define No_bSuf 0x10000 /* b suffix on instruction illegal */
|
||||
#define No_wSuf 0x20000 /* w suffix on instruction illegal */
|
||||
#define No_lSuf 0x40000 /* l suffix on instruction illegal */
|
||||
#define No_sSuf 0x80000 /* s suffix on instruction illegal */
|
||||
#define FWait 0x100000 /* instruction needs FWAIT */
|
||||
#define IsString 0x200000 /* quick test for string instructions */
|
||||
#define regKludge 0x400000 /* fake an extra reg operand for clr, imul */
|
||||
#define Ugh 0x80000000 /* deprecated fp insn, gets a warning */
|
||||
|
||||
/* operand_types[i] describes the type of operand i. This is made
|
||||
by OR'ing together all of the possible type masks. (e.g.
|
||||
|
Loading…
Reference in New Issue
Block a user