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>
* config/tc-d30v.c (md_assemble): Store previous segment state

View File

@ -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

View File

@ -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.