aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gas/ChangeLog46
-rw-r--r--gas/config/tc-i386.c505
-rw-r--r--gas/config/tc-i386.h105
3 files changed, 395 insertions, 261 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 178c2e7..35a1387 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -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
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 9de4f9e..0a393e2 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -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))))
-
- /* 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)
+#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 )
+
{
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;
+ }
+ }
+ 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;
+ }
+ }
}
- if (bad)
- as_bad (_("register does not match opcode suffix"));
+ 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;
+ {
+ 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. */
- if ((i.suffix == WORD_OPCODE_SUFFIX) ^ flag_16bit_code)
+ 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 char prefix = WORD_PREFIX_OPCODE;
+ 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
diff --git a/gas/config/tc-i386.h b/gas/config/tc-i386.h
index 1c09dbc..34c8bb7 100644
--- a/gas/config/tc-i386.h
+++ b/gas/config/tc-i386.h
@@ -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.