aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@airs.com>1998-04-21 21:08:39 +0000
committerIan Lance Taylor <ian@airs.com>1998-04-21 21:08:39 +0000
commit4498e3d641de103d13590ab9b687591c0b08c0fe (patch)
tree3935e0e072f4f2d55b9a52a4a85aee76796a1184 /gas
parentd0f44984d1a2357701684af5d3748c6482bf1e86 (diff)
downloadgdb-4498e3d641de103d13590ab9b687591c0b08c0fe.zip
gdb-4498e3d641de103d13590ab9b687591c0b08c0fe.tar.gz
gdb-4498e3d641de103d13590ab9b687591c0b08c0fe.tar.bz2
Tue Apr 21 17:01:22 1998 Alan Modra <alan@spri.levels.unisa.edu.au>
* config/tc-i386.c (check_prefix): New static function, split out from md_assemble. (struct _i386_insn): Add wait_prefix field. (md_assemble): Remove wait_prefix local variable. Use check_prefix when adding a prefix. * config/tc-i386.c (current_templates): New static variable. (md_assemble): Remove current_templates local variable. (md_assemble, i386_operand): Improve error and warning messages in many places. Add RESTORE_END_STRING in many places before error return. Clarify some comments. * config/tc-i386.c (struct _i386_insn): Change seg field to a two element array. (md_assemble): Parse string instruction operands, looking for segment override prefixes. Check for invalid segment prefixes on string instruction. (i386_operand): i.seg[] and max mem_operand changes for string insns. * config/tc-i386.h (EsSeg): Define. * config/tc-i386.h (regKludge): Define. (iclrKludge, imulKludge): Don't define. * config/tc-i386.c (md_assemble): Merge imulKludge and iclrKludge code. Move ReverseRegRegmem fudges into Modrm case. Reorder opcode_modifier checks to look for more common cases first. Add default_seg for IsString case.
Diffstat (limited to 'gas')
-rw-r--r--gas/ChangeLog30
-rw-r--r--gas/config/tc-i386.c420
-rw-r--r--gas/config/tc-i386.h139
3 files changed, 370 insertions, 219 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index c422f7d..f89e2c7 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,33 @@
+Tue Apr 21 17:01:22 1998 Alan Modra <alan@spri.levels.unisa.edu.au>
+
+ * config/tc-i386.c (check_prefix): New static function, split out
+ from md_assemble.
+ (struct _i386_insn): Add wait_prefix field.
+ (md_assemble): Remove wait_prefix local variable. Use
+ check_prefix when adding a prefix.
+
+ * config/tc-i386.c (current_templates): New static variable.
+ (md_assemble): Remove current_templates local variable.
+ (md_assemble, i386_operand): Improve error and warning messages in
+ many places. Add RESTORE_END_STRING in many places before error
+ return. Clarify some comments.
+
+ * config/tc-i386.c (struct _i386_insn): Change seg field to a two
+ element array.
+ (md_assemble): Parse string instruction operands, looking for
+ segment override prefixes. Check for invalid segment prefixes on
+ string instruction.
+ (i386_operand): i.seg[] and max mem_operand changes for string
+ insns.
+ * config/tc-i386.h (EsSeg): Define.
+
+ * config/tc-i386.h (regKludge): Define.
+ (iclrKludge, imulKludge): Don't define.
+ * config/tc-i386.c (md_assemble): Merge imulKludge and iclrKludge
+ code. Move ReverseRegRegmem fudges into Modrm case. Reorder
+ opcode_modifier checks to look for more common cases first. Add
+ default_seg for IsString case.
+
Tue Apr 21 16:18:12 1998 Ian Lance Taylor <ian@cygnus.com>
* configure.in: Call AM_PROG_LEX rather than AC_PROG_LEX and
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 427d2c6..10c97f5 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -44,6 +44,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 check_prefix PARAMS ((int));
static void set_16bit_code_flag PARAMS ((int));
#ifdef BFD_ASSEMBLER
static bfd_reloc_code_real_type reloc
@@ -96,9 +97,9 @@ struct _i386_insn
reg_entry *index_reg;
unsigned int log2_scale_factor;
- /* SEG gives the seg_entry of this insn. It is equal to zero unless
- an explicit segment override is given. */
- const seg_entry *seg; /* segment for memory operands (if given) */
+ /* SEG gives the seg_entries of this insn. They are zero unless
+ explicit segment overrides are given. */
+ const seg_entry *seg[2]; /* segments for memory operands (if given) */
/* PREFIX holds all the given prefix opcodes (usually null).
PREFIXES is the size of PREFIX. */
@@ -106,7 +107,12 @@ struct _i386_insn
unsigned char prefix[MAX_PREFIXES];
unsigned int prefixes;
- /* RM and IB are the modrm byte and the base index byte where the
+ /* Wait prefix needs to come before any other prefixes, so handle
+ it specially. wait_prefix will hold the opcode modifier flag
+ FWait if a wait prefix is given. */
+ int wait_prefix;
+
+ /* RM and BI are the modrm byte and the base index byte where the
addressing modes of this insn are encoded. */
modrm_byte rm;
@@ -179,10 +185,13 @@ static char *save_stack_p; /* stack pointer */
/* The instruction we're assembling. */
static i386_insn i;
+/* Possible templates for current insn. */
+static templates *current_templates;
+
/* Per instruction expressionS buffers: 2 displacements & 2 immediate max. */
static expressionS disp_expressions[2], im_expressions[2];
-/* pointers to ebp & esp entries in reg_hash hash table */
+/* Pointers to ebp & esp entries in reg_hash hash table. */
static reg_entry *ebp, *esp;
static int this_operand; /* current operand we are working on */
@@ -232,8 +241,9 @@ const relax_typeS md_relax_table[] =
{1, 1, 0, 0},
{1, 1, 0, 0},
- /* For now we don't use word displacement jumps; they may be
- untrustworthy. */
+ /* For now we don't use word displacement jumps; they will not work
+ for destination addresses > 0xFFFF, since they clear the upper 16
+ bits of %eip. */
{127 + 1, -128 + 1, 0, ENCODE_RELAX_STATE (COND_JUMP, DWORD)},
/* word conditionals add 3 bytes to frag:
2 opcode prefix; 1 displacement bytes */
@@ -348,7 +358,7 @@ static reg_entry *parse_register PARAMS ((char *reg_string));
static void s_bss PARAMS ((int));
#endif
-symbolS *GOT_symbol; /* Pre-defined "__GLOBAL_OFFSET_TABLE" */
+symbolS *GOT_symbol; /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
static INLINE unsigned long
mode_from_disp_size (t)
@@ -422,6 +432,81 @@ smallest_imm_type (num)
: (Imm32));
} /* smallest_imm_type() */
+static int
+check_prefix (prefix)
+ int prefix;
+{
+ int q;
+
+ for (q = 0; q < i.prefixes; q++)
+ {
+ switch (prefix)
+ {
+ case CS_PREFIX_OPCODE:
+ case DS_PREFIX_OPCODE:
+ case ES_PREFIX_OPCODE:
+ case FS_PREFIX_OPCODE:
+ case GS_PREFIX_OPCODE:
+ case SS_PREFIX_OPCODE:
+ switch (i.prefix[q])
+ {
+ case CS_PREFIX_OPCODE:
+ case DS_PREFIX_OPCODE:
+ case ES_PREFIX_OPCODE:
+ case FS_PREFIX_OPCODE:
+ case GS_PREFIX_OPCODE:
+ case SS_PREFIX_OPCODE:
+ as_bad ("same type of prefix used twice");
+ return 0;
+ }
+ break;
+
+ case REPNE:
+ case REPE:
+ switch (i.prefix[q])
+ {
+ case REPNE:
+ case REPE:
+ as_bad ("same type of prefix used twice");
+ return 0;
+ }
+ break;
+
+ case FWAIT_OPCODE:
+ if (i.wait_prefix != 0)
+ {
+ as_bad ("same type of prefix used twice");
+ return 0;
+ }
+ break;
+
+ default:
+ if (i.prefix[q] == prefix)
+ {
+ as_bad ("same type of prefix used twice");
+ return 0;
+ }
+ }
+ }
+
+ if (i.prefixes == MAX_PREFIXES && prefix != FWAIT_OPCODE)
+ {
+ char *p = "another"; /* paranoia */
+
+ for (q = 0;
+ q < sizeof (i386_prefixtab) / sizeof (i386_prefixtab[0]);
+ q++)
+ if (i386_prefixtab[q].prefix_code == prefix)
+ p = i386_prefixtab[q].prefix_name;
+
+ as_bad ("%d prefixes given and `%%%s' prefix gives too many",
+ MAX_PREFIXES, p);
+ return 0;
+ }
+
+ return 1;
+}
+
static void
set_16bit_code_flag (new_16bit_code_flag)
int new_16bit_code_flag;
@@ -736,10 +821,12 @@ type_names[] =
{ Imm1, "i1" },
{ Control, "control reg" },
{ Test, "test reg" },
+ { Debug, "debug reg" },
{ FloatReg, "FReg" },
{ FloatAcc, "FAcc" },
{ JumpAbsolute, "Jump Absolute" },
{ RegMMX, "rMMX" },
+ { EsSeg, "es" },
{ 0, "" }
};
@@ -840,9 +927,6 @@ md_assemble (line)
/* Count the size of the instruction generated. */
int insn_size = 0;
- /* Possible templates for current insn */
- templates *current_templates = (templates *) 0;
-
int j;
/* Initialize globals. */
@@ -861,8 +945,8 @@ md_assemble (line)
/* 1 if operand is pending after ','. */
unsigned int expecting_operand = 0;
- /* 1 if we found a prefix only acceptable with string insns. */
- unsigned int expecting_string_instruction = 0;
+ /* Non-zero if we found a prefix only acceptable with string insns. */
+ const char *expecting_string_instruction = NULL;
/* Non-zero if operand parens not balanced. */
unsigned int paren_not_balanced;
char *token_start = l;
@@ -894,26 +978,26 @@ md_assemble (line)
prefix = (prefix_entry *) hash_find (prefix_hash, token_start);
if (!prefix)
{
- as_bad ("no such opcode prefix ('%s')", token_start);
+ as_bad ("no such opcode prefix `%s'", token_start);
+ RESTORE_END_STRING (l);
return;
}
RESTORE_END_STRING (l);
/* check for repeated prefix */
- for (q = 0; q < i.prefixes; q++)
- if (i.prefix[q] == prefix->prefix_code)
- {
- as_bad ("same prefix used twice; you don't really want this!");
- return;
- }
- if (i.prefixes == MAX_PREFIXES)
+ if (! check_prefix (prefix->prefix_code))
+ return;
+ if (prefix->prefix_code == FWAIT_OPCODE)
{
- as_bad ("too many opcode prefixes");
- return;
+ i.wait_prefix = FWait;
+ }
+ else
+ {
+ i.prefix[i.prefixes++] = prefix->prefix_code;
+ if (prefix->prefix_code == REPE
+ || prefix->prefix_code == REPNE)
+ expecting_string_instruction = prefix->prefix_name;
}
- i.prefix[i.prefixes++] = prefix->prefix_code;
- if (prefix->prefix_code == REPE || prefix->prefix_code == REPNE)
- expecting_string_instruction = 1;
- /* skip past PREFIX_SEPERATOR and reset token_start */
+ /* Skip past PREFIX_SEPARATOR and reset token_start. */
token_start = ++l;
}
}
@@ -921,6 +1005,7 @@ md_assemble (line)
if (token_start == l)
{
as_bad ("expecting opcode; got nothing");
+ RESTORE_END_STRING (l);
return;
}
@@ -944,6 +1029,7 @@ md_assemble (line)
if (!current_templates)
{
as_bad ("no such 386 instruction: `%s'", token_start);
+ RESTORE_END_STRING (l);
return;
}
}
@@ -951,21 +1037,15 @@ md_assemble (line)
/* check for rep/repne without a string instruction */
if (expecting_string_instruction &&
- !IS_STRING_INSTRUCTION (current_templates->
- start->base_opcode))
+ !(current_templates->start->opcode_modifier & IsString))
{
- as_bad ("expecting string instruction after rep/repne");
+ as_bad ("expecting string instruction after `%s'",
+ expecting_string_instruction);
return;
}
/* There may be operands to parse. */
- if (*l != END_OF_INSN &&
- /* For string instructions, we ignore any operands if given. This
- kludges, for example, 'rep/movsb %ds:(%esi), %es:(%edi)' where
- the operands are always going to be the same, and are not really
- encoded in machine code. */
- !IS_STRING_INSTRUCTION (current_templates->
- start->base_opcode))
+ if (*l != END_OF_INSN)
{
/* parse operands */
do
@@ -1162,12 +1242,14 @@ md_assemble (line)
} /* for (t = ... */
if (t == current_templates->end)
{ /* we found no match */
- as_bad ("operands given don't match any known 386 instruction");
+ as_bad ("suffix or operands invalid for `%s'",
+ current_templates->start->name);
return;
}
- /* Copy the template we found (we may change it!). */
+ /* Copy the template we found. */
i.tm = *t;
+ i.tm.opcode_modifier |= i.wait_prefix;
if (found_reverse_match)
{
@@ -1175,6 +1257,37 @@ md_assemble (line)
i.tm.operand_types[1] = t->operand_types[0];
}
+ /* 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;
+ if ((i.tm.operand_types[mem_op+0] & EsSeg) != 0)
+ {
+ if (i.seg[0] != (seg_entry *) 0 && i.seg[0] != (seg_entry *) &es)
+ {
+ as_bad ("`%s' %s operand must use `%%es' segment",
+ i.tm.name,
+ ordinal_names[mem_op+0]);
+ return;
+ }
+ /* There's only ever one segment override allowed per instruction.
+ This instruction possibly has a legal segment override on the
+ second operand, so copy the segment to where non-string
+ instructions store it, allowing common code. */
+ i.seg[0] = i.seg[1];
+ }
+ else if ((i.tm.operand_types[mem_op+1] & EsSeg) != 0)
+ {
+ if (i.seg[1] != (seg_entry *) 0 && i.seg[1] != (seg_entry *) &es)
+ {
+ as_bad ("`%s' %s operand must use `%%es' segment",
+ i.tm.name,
+ ordinal_names[mem_op+1]);
+ return;
+ }
+ }
+ }
+
/* If the matched instruction specifies an explicit opcode suffix,
use it - and make sure none has already been specified. */
if (i.tm.opcode_modifier & (Data16|Data32))
@@ -1300,12 +1413,8 @@ md_assemble (line)
operand size prefix. */
if ((i.suffix == WORD_OPCODE_SUFFIX) ^ flag_16bit_code)
{
- if (i.prefixes == MAX_PREFIXES)
- {
- as_bad ("%d prefixes given and data size prefix gives too many prefixes",
- MAX_PREFIXES);
- return;
- }
+ if (! check_prefix (WORD_PREFIX_OPCODE))
+ return;
i.prefix[i.prefixes++] = WORD_PREFIX_OPCODE;
}
}
@@ -1327,41 +1436,19 @@ md_assemble (line)
found_reverse_match holds bit to set (different for int &
float insns). */
- if (found_reverse_match)
- {
- i.tm.base_opcode |= found_reverse_match;
- }
+ i.tm.base_opcode ^= found_reverse_match;
/* The imul $imm, %reg instruction is converted into
- imul $imm, %reg, %reg. */
- if (i.tm.opcode_modifier & imulKludge)
- {
- /* Pretend we saw the 3 operand case. */
- i.regs[2] = i.regs[1];
- i.reg_operands = 2;
- }
-
- /* The clr %reg instruction is converted into xor %reg, %reg. */
- if (i.tm.opcode_modifier & iclrKludge)
+ imul $imm, %reg, %reg, and the clr %reg instruction
+ is converted into xor %reg, %reg. */
+ if (i.tm.opcode_modifier & regKludge)
{
- i.regs[1] = i.regs[0];
+ unsigned int first_reg_op = (i.types[0] & Reg) ? 0 : 1;
+ /* Pretend we saw the extra register operand. */
+ i.regs[first_reg_op+1] = i.regs[first_reg_op];
i.reg_operands = 2;
}
- /* Certain instructions expect the destination to be in the i.rm.reg
- field. This is by far the exceptional case. For these
- instructions, if the source operand is a register, we must reverse
- the i.rm.reg and i.rm.regmem fields. We accomplish this by faking
- that the two register operands were given in the reverse order. */
- if ((i.tm.opcode_modifier & ReverseRegRegmem) && i.reg_operands == 2)
- {
- unsigned int first_reg_operand = (i.types[0] & Reg) ? 0 : 1;
- unsigned int second_reg_operand = first_reg_operand + 1;
- reg_entry *tmp = i.regs[first_reg_operand];
- i.regs[first_reg_operand] = i.regs[second_reg_operand];
- i.regs[second_reg_operand] = tmp;
- }
-
if (i.tm.opcode_modifier & ShortForm)
{
/* The register or float register operand is in operand 0 or 1. */
@@ -1377,32 +1464,6 @@ md_assemble (line)
i.suffix == DWORD_OPCODE_SUFFIX)
i.tm.base_opcode |= 0x8;
}
- else if (i.tm.opcode_modifier & Seg2ShortForm)
- {
- if (i.tm.base_opcode == POP_SEG_SHORT && i.regs[0]->reg_num == 1)
- {
- as_bad ("you can't 'pop cs' on the 386.");
- 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)
- {
- /* This is a special non-modrm instruction
- that addresses memory with a 32-bit displacement mode anyway,
- and thus requires an address-size prefix if in 16-bit mode. */
- uses_mem_addrmode = 1;
- default_seg = &ds;
- }
else if (i.tm.opcode_modifier & Modrm)
{
/* The opcode is completed (modulo i.tm.extension_opcode which
@@ -1425,10 +1486,25 @@ md_assemble (line)
| RegMMX))
? 0 : 1);
dest = source + 1;
+
+ /* Certain instructions expect the destination to be
+ in the i.rm.reg field. This is by far the
+ exceptional case. For these instructions, if the
+ source operand is a register, we must reverse the
+ i.rm.reg and i.rm.regmem fields. We accomplish
+ this by pretending that the two register operands
+ were given in the reverse order. */
+ if (i.tm.opcode_modifier & ReverseRegRegmem)
+ {
+ reg_entry *tmp = i.regs[source];
+ i.regs[source] = i.regs[dest];
+ i.regs[dest] = tmp;
+ }
+
i.rm.mode = 3;
/* We must be careful to make sure that all
segment/control/test/debug/MMX registers go into
- the i.rm.reg field (despite the whether they are
+ the i.rm.reg field (despite whether they are
source or destination operands). */
if (i.regs[dest]->reg_type
& (SReg2 | SReg3 | Control | Debug | Test | RegMMX))
@@ -1447,7 +1523,9 @@ md_assemble (line)
if (i.mem_operands)
{
unsigned int fake_zero_displacement = 0;
- unsigned int op = (i.types[0] & Mem) ? 0 : ((i.types[1] & Mem) ? 1 : 2);
+ unsigned int op = ((i.types[0] & Mem)
+ ? 0
+ : (i.types[1] & Mem) ? 1 : 2);
/* Encode memory operand into modrm byte and base index
byte. */
@@ -1540,10 +1618,9 @@ md_assemble (line)
exp->X_op_symbol = (symbolS *) 0;
}
- /* Find the default segment for the memory
- operand. Used to optimize out explicit segment
- specifications. */
- if (i.seg && (t->opcode_modifier & LinearAddress) == 0)
+ /* Find the default segment for the memory operand.
+ Used to optimize out explicit segment specifications. */
+ if (i.seg[0])
{
unsigned int seg_index;
@@ -1586,7 +1663,7 @@ md_assemble (line)
/* Now, if no memory operand has set i.rm.mode = 0, 1, 2
we must set it to 3 to indicate this is a register
- operand int the regmem field */
+ operand in the regmem field. */
if (!i.mem_operands)
i.rm.mode = 3;
}
@@ -1599,18 +1676,46 @@ md_assemble (line)
if (i.rm.mode != 3)
uses_mem_addrmode = 1;
}
+ else if (i.tm.opcode_modifier & Seg2ShortForm)
+ {
+ if (i.tm.base_opcode == POP_SEG_SHORT && i.regs[0]->reg_num == 1)
+ {
+ as_bad ("you can't `pop %%cs' on the 386.");
+ 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)
+ {
+ /* This is a special non-modrm instruction
+ that addresses memory with a 32-bit displacement mode anyway,
+ and thus requires an address-size prefix if in 16-bit mode. */
+ uses_mem_addrmode = 1;
+ default_seg = &ds;
+ }
+ else if ((i.tm.opcode_modifier & IsString) != 0)
+ {
+ /* For the string instructions that allow a segment override
+ on one of their operands, the default segment is ds. */
+ default_seg = &ds;
+ }
/* GAS currently doesn't support 16-bit memory addressing modes at all,
so if we're writing 16-bit code and using a memory addressing mode,
always spew out an address size prefix. */
if (uses_mem_addrmode && flag_16bit_code)
{
- if (i.prefixes == MAX_PREFIXES)
- {
- as_bad ("%d prefixes given and address size override gives too many prefixes",
- MAX_PREFIXES);
- return;
- }
+ if (! check_prefix (ADDR_PREFIX_OPCODE))
+ return;
i.prefix[i.prefixes++] = ADDR_PREFIX_OPCODE;
}
@@ -1620,15 +1725,11 @@ md_assemble (line)
If we never figured out what the default segment is,
then default_seg will be zero at this point,
and the specified segment prefix will always be used. */
- if ((i.seg) && (i.seg != default_seg))
+ if ((i.seg[0]) && (i.seg[0] != default_seg))
{
- if (i.prefixes == MAX_PREFIXES)
- {
- as_bad ("%d prefixes given and %s segment override gives too many prefixes",
- MAX_PREFIXES, i.seg->seg_name);
- return;
- }
- i.prefix[i.prefixes++] = i.seg->seg_prefix;
+ if (! check_prefix (i.seg[0]->seg_prefix))
+ return;
+ i.prefix[i.prefixes++] = i.seg[0]->seg_prefix;
}
}
}
@@ -1649,6 +1750,9 @@ md_assemble (line)
{
unsigned long n = i.disps[0]->X_add_number;
+ if (i.prefixes != 0)
+ as_warn ("skipping prefixes on this instruction");
+
if (i.disps[0]->X_op == O_constant)
{
if (fits_in_signed_byte (n))
@@ -1661,10 +1765,10 @@ md_assemble (line)
else
{ /* It's an absolute word/dword displacement. */
- /* Use only 16-bit jumps for 16-bit code,
+ /* Use 16-bit jumps only for 16-bit code,
because text segments are limited to 64K anyway;
- use only 32-bit jumps for 32-bit code,
- because they're faster. */
+ Use 32-bit jumps for 32-bit code, because they're faster,
+ and a 16-bit jump will clear the top 16 bits of %eip. */
int jmp_size = flag_16bit_code ? 2 : 4;
if (flag_16bit_code && !fits_in_signed_word (n))
{
@@ -1795,6 +1899,9 @@ md_assemble (line)
}
else if (i.tm.opcode_modifier & JumpInterSegment)
{
+ if (i.prefixes != 0)
+ as_warn ("skipping prefixes on this instruction");
+
if (flag_16bit_code)
{
FRAG_APPEND_1_CHAR (WORD_PREFIX_OPCODE);
@@ -1818,7 +1925,16 @@ md_assemble (line)
/* Output normal instructions here. */
unsigned char *q;
- /* First the prefix bytes. */
+ /* Hack for fwait. It must come before any prefixes, as it
+ really is an instruction rather than a prefix. */
+ if ((i.tm.opcode_modifier & FWait) != 0)
+ {
+ p = frag_more (1);
+ insn_size += 1;
+ md_number_to_chars (p, (valueT) FWAIT_OPCODE, 1);
+ }
+
+ /* The prefix bytes. */
for (q = i.prefix; q < i.prefix + i.prefixes; q++)
{
p = frag_more (1);
@@ -2045,7 +2161,7 @@ i386_operand (operand_string)
register reg_entry *r;
if (!(r = parse_register (op_string)))
{
- as_bad ("bad register name ('%s')", op_string);
+ as_bad ("bad register name `%s'", op_string);
return 0;
}
/* Check for segment override, rather than segment register by
@@ -2055,22 +2171,22 @@ i386_operand (operand_string)
switch (r->reg_num)
{
case 0:
- i.seg = (seg_entry *) & es;
+ i.seg[i.mem_operands] = (seg_entry *) & es;
break;
case 1:
- i.seg = (seg_entry *) & cs;
+ i.seg[i.mem_operands] = (seg_entry *) & cs;
break;
case 2:
- i.seg = (seg_entry *) & ss;
+ i.seg[i.mem_operands] = (seg_entry *) & ss;
break;
case 3:
- i.seg = (seg_entry *) & ds;
+ i.seg[i.mem_operands] = (seg_entry *) & ds;
break;
case 4:
- i.seg = (seg_entry *) & fs;
+ i.seg[i.mem_operands] = (seg_entry *) & fs;
break;
case 5:
- i.seg = (seg_entry *) & gs;
+ i.seg[i.mem_operands] = (seg_entry *) & gs;
break;
}
op_string += 4; /* skip % <x> s : */
@@ -2078,7 +2194,7 @@ i386_operand (operand_string)
if (!is_digit_char (*op_string) && !is_identifier_char (*op_string)
&& *op_string != '(' && *op_string != ABSOLUTE_PREFIX)
{
- as_bad ("bad memory operand after segment override");
+ as_bad ("bad memory operand `%s'", op_string);
return 0;
}
/* Handle case of %es:*foo. */
@@ -2118,7 +2234,7 @@ i386_operand (operand_string)
in certain cases. Oddly, the code in question turns out
to work correctly anyhow, so we make this just a warning
until those versions of gcc are obsolete. */
- as_warn ("warning: unrecognized characters `%s' in expression",
+ as_warn ("unrecognized characters `%s' in expression",
input_line_pointer);
}
input_line_pointer = save_input_line_pointer;
@@ -2126,7 +2242,7 @@ i386_operand (operand_string)
if (exp->X_op == O_absent)
{
/* missing or bad expr becomes absolute 0 */
- as_bad ("missing or invalid immediate expression '%s' taken as 0",
+ as_bad ("missing or invalid immediate expression `%s' taken as 0",
operand_string);
exp->X_op = O_constant;
exp->X_add_number = 0;
@@ -2182,9 +2298,12 @@ i386_operand (operand_string)
unsigned int found_base_index_form;
do_memory_reference:
- if (i.mem_operands == MAX_MEMORY_OPERANDS)
+ if ((i.mem_operands == 1
+ && (current_templates->start->opcode_modifier & IsString) == 0)
+ || i.mem_operands == 2)
{
- as_bad ("more than 1 memory reference in instruction");
+ as_bad ("too many memory references for `%s'",
+ current_templates->start->name);
return 0;
}
i.mem_operands++;
@@ -2260,14 +2379,15 @@ i386_operand (operand_string)
base_string++;
if (base_string == base_reg_name + 1)
{
- as_bad ("can't find base register name after '(%c'",
+ as_bad ("can't find base register name after `(%c'",
REGISTER_PREFIX);
return 0;
}
END_STRING_AND_SAVE (base_string);
if (!(i.base_reg = parse_register (base_reg_name)))
{
- as_bad ("bad base register name ('%s')", base_reg_name);
+ as_bad ("bad base register name `%s'", base_reg_name);
+ RESTORE_END_STRING (base_string);
return 0;
}
RESTORE_END_STRING (base_string);
@@ -2278,7 +2398,7 @@ i386_operand (operand_string)
OR ')' ==> end. (scale factor = 1) */
if (*base_string != ',' && *base_string != ')')
{
- as_bad ("expecting ',' or ')' after base register in `%s'",
+ as_bad ("expecting `,' or `)' after base register in `%s'",
operand_string);
return 0;
}
@@ -2291,7 +2411,8 @@ i386_operand (operand_string)
END_STRING_AND_SAVE (base_string);
if (!(i.index_reg = parse_register (index_reg_name)))
{
- as_bad ("bad index register name ('%s')", index_reg_name);
+ as_bad ("bad index register name `%s'", index_reg_name);
+ RESTORE_END_STRING (base_string);
return 0;
}
RESTORE_END_STRING (base_string);
@@ -2305,14 +2426,15 @@ i386_operand (operand_string)
base_string++;
if (base_string == num_string)
{
- as_bad ("can't find a scale factor after ','");
+ as_bad ("can't find a scale factor after `,'");
return 0;
}
END_STRING_AND_SAVE (base_string);
/* We've got a scale factor. */
if (!sscanf (num_string, "%d", &num))
{
- as_bad ("can't parse scale factor from '%s'", num_string);
+ as_bad ("can't parse scale factor from `%s'", num_string);
+ RESTORE_END_STRING (base_string);
return 0;
}
RESTORE_END_STRING (base_string);
@@ -2339,7 +2461,7 @@ i386_operand (operand_string)
{
if (!i.index_reg && *base_string == ',')
{
- as_bad ("expecting index register or scale factor after ','; got '%c'",
+ as_bad ("expecting index register or scale factor after `,'; got '%c'",
*(base_string + 1));
return 0;
}
@@ -2407,7 +2529,7 @@ i386_operand (operand_string)
*cp = '@';
}
else
- as_bad ("Bad reloc specifier '%s' in expression", cp + 1);
+ as_bad ("Bad reloc specifier `%s' in expression", cp + 1);
input_line_pointer = tmpbuf;
}
@@ -2433,13 +2555,13 @@ i386_operand (operand_string)
#endif
if (*input_line_pointer)
- as_bad ("Ignoring junk '%s' after expression", input_line_pointer);
+ as_bad ("Ignoring junk `%s' after expression", input_line_pointer);
RESTORE_END_STRING (displacement_string_end);
input_line_pointer = save_input_line_pointer;
if (exp->X_op == O_absent)
{
/* missing expr becomes absolute 0 */
- as_bad ("missing or invalid displacement '%s' taken as 0",
+ as_bad ("missing or invalid displacement `%s' taken as 0",
operand_string);
i.types[this_operand] |= (Disp | Abs);
exp->X_op = O_constant;
@@ -2493,13 +2615,13 @@ i386_operand (operand_string)
}
if (i.index_reg && i.index_reg == esp)
{
- as_bad ("%s may not be used as an index register", esp->reg_name);
+ as_bad ("`%%s' may not be used as an index register", esp->reg_name);
return 0;
}
}
else
{ /* it's not a memory operand; argh! */
- as_bad ("invalid char %s begining %s operand '%s'",
+ as_bad ("invalid char %s begining %s operand `%s'",
output_invalid (*op_string), ordinal_names[this_operand],
op_string);
return 0;
diff --git a/gas/config/tc-i386.h b/gas/config/tc-i386.h
index 2fc3605..6d4f6b4 100644
--- a/gas/config/tc-i386.h
+++ b/gas/config/tc-i386.h
@@ -157,7 +157,7 @@ extern int tc_coff_sizemachdep PARAMS ((fragS *frag));
#define MAX_OPERANDS 3 /* max operands per insn */
#define MAX_PREFIXES 5 /* max prefixes per opcode */
#define MAX_IMMEDIATE_OPERANDS 2/* max immediates per insn */
-#define MAX_MEMORY_OPERANDS 2 /* max memory ref per insn (lcall uses 2) */
+#define MAX_MEMORY_OPERANDS 2 /* max memory refs per insn (string ops) */
/* we define the syntax here (modulo base,index,scale syntax) */
#define REGISTER_PREFIX '%'
@@ -198,52 +198,58 @@ extern int tc_coff_sizemachdep PARAMS ((fragS *frag));
Operands are classified so that we can match given operand types with
the opcode table in i386-opcode.h.
*/
-#define Unknown 0x0
/* register */
-#define Reg8 0x1 /* 8 bit reg */
-#define Reg16 0x2 /* 16 bit reg */
-#define Reg32 0x4 /* 32 bit reg */
-#define Reg (Reg8|Reg16|Reg32) /* gen'l register */
-#define WordReg (Reg16|Reg32) /* for push/pop operands */
+#define Reg8 0x1 /* 8 bit reg */
+#define Reg16 0x2 /* 16 bit reg */
+#define Reg32 0x4 /* 32 bit reg */
/* immediate */
-#define Imm8 0x8 /* 8 bit immediate */
-#define Imm8S 0x10 /* 8 bit immediate sign extended */
-#define Imm16 0x20 /* 16 bit immediate */
-#define Imm32 0x40 /* 32 bit immediate */
-#define Imm1 0x80 /* 1 bit immediate */
-#define ImmUnknown Imm32 /* for unknown expressions */
-#define Imm (Imm8|Imm8S|Imm16|Imm32) /* gen'l immediate */
+#define Imm8 0x8 /* 8 bit immediate */
+#define Imm8S 0x10 /* 8 bit immediate sign extended */
+#define Imm16 0x20 /* 16 bit immediate */
+#define Imm32 0x40 /* 32 bit immediate */
+#define Imm1 0x80 /* 1 bit immediate */
/* memory */
-#define Disp8 0x200 /* 8 bit displacement (for jumps) */
-#define Disp16 0x400 /* 16 bit displacement */
-#define Disp32 0x800 /* 32 bit displacement */
-#define Disp (Disp8|Disp16|Disp32) /* General displacement */
-#define DispUnknown Disp32 /* for unknown size displacements */
-#define Mem8 0x1000
-#define Mem16 0x2000
-#define Mem32 0x4000
-#define BaseIndex 0x8000
-#define Mem (Disp|Mem8|Mem16|Mem32|BaseIndex) /* General memory */
-#define WordMem (Mem16|Mem32|Disp|BaseIndex)
-#define ByteMem (Mem8|Disp|BaseIndex)
+#define BaseIndex 0x100
+/* Disp8,16,32 are used in different ways, depending on the
+ instruction. For jumps, they specify the size of the PC relative
+ displacement, for baseindex type instructions, they specify the
+ size of the offset relative to the base register, and for memory
+ offset instructions such as `mov 1234,%al' they specify the size of
+ the offset relative to the segment base. */
+#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 ImplicitRegister (InOutPortReg|ShiftCount|Acc|FloatAcc)
+#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 0x08000000
-#define Abs16 0x10000000
-#define Abs32 0x20000000
-#define Abs (Abs8|Abs16|Abs32)
-#define RegMMX 0x40000000 /* MMX register */
+#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 Reg (Reg8|Reg16|Reg32) /* gen'l register */
+#define WordReg (Reg16|Reg32)
+#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)
@@ -274,35 +280,28 @@ typedef struct
unsigned int opcode_modifier;
/* opcode_modifier bits: */
-#define W 0x1 /* set if operands are words or dwords */
-#define D 0x2 /* D = 0 if Reg --> Regmem; D = 1 if Regmem --> Reg */
- /* direction flag for floating insns: MUST BE 0x400 */
-#define FloatD 0x400
- /* shorthand */
-#define DW (D|W)
-#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 W 0x1 /* set if operands can be words or dwords
+ encoded the canonical way: MUST BE 0x1 */
+#define D 0x2 /* D = 0 if Reg --> Regmem;
+ D = 1 if Regmem --> Reg: MUST BE 0x2 */
+#define Modrm 0x4
+#define ReverseRegRegmem 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 JumpInterSegment 0x200 /* special case for intersegment leaps/calls */
- /* 0x400 CANNOT BE USED since it's already used by FloatD above */
-#define DONT_USE 0x400
-#define NoModrm 0x800
-#define Modrm 0x1000
-#define imulKludge 0x2000
-#define JumpByte 0x4000
-#define JumpDword 0x8000
-#define ReverseRegRegmem 0x10000
-#define Data16 0x20000 /* needs data prefix if in 32-bit mode */
-#define Data32 0x40000 /* needs data prefix if in 16-bit mode */
-#define iclrKludge 0x80000 /* used to convert clr to xor */
-#define LinearAddress 0x100000 /* uses linear address (no segment) */
-
- /* (opcode_modifier & COMES_IN_ALL_SIZES) is true if the
- instuction comes in byte, word, and dword sizes and is encoded into
- machine code in the canonical way. */
-#define COMES_IN_ALL_SIZES (W)
+#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