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.
This commit is contained in:
Ian Lance Taylor 1998-04-21 21:08:39 +00:00
parent d0f44984d1
commit 4498e3d641
3 changed files with 369 additions and 218 deletions

View file

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

View file

@ -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!");
if (! check_prefix (prefix->prefix_code))
return;
}
if (i.prefixes == MAX_PREFIXES)
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 = 1;
/* skip past PREFIX_SEPERATOR and reset token_start */
if (prefix->prefix_code == REPE
|| prefix->prefix_code == REPNE)
expecting_string_instruction = prefix->prefix_name;
}
/* 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);
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)
imul $imm, %reg, %reg, and the clr %reg instruction
is converted into xor %reg, %reg. */
if (i.tm.opcode_modifier & regKludge)
{
/* Pretend we saw the 3 operand case. */
i.regs[2] = i.regs[1];
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;
}
/* The clr %reg instruction is converted into xor %reg, %reg. */
if (i.tm.opcode_modifier & iclrKludge)
{
i.regs[1] = i.regs[0];
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);
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);
if (! check_prefix (i.seg[0]->seg_prefix))
return;
}
i.prefix[i.prefixes++] = i.seg->seg_prefix;
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;

View file

@ -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,34 +198,31 @@ 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 */
/* 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 */
/* memory */
#define Disp8 0x200 /* 8 bit displacement (for jumps) */
#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 */
#define Disp (Disp8|Disp16|Disp32) /* General displacement */
#define DispUnknown Disp32 /* for unknown size displacements */
/* Mem8,16,32 are used to limit the allowed sizes of memory operands */
#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)
/* specials */
#define InOutPortReg 0x10000 /* register to hold in/out port addr = dx */
#define ShiftCount 0x20000 /* register to hold shift cound = cl */
@ -237,13 +234,22 @@ extern int tc_coff_sizemachdep PARAMS ((fragS *frag));
#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 JumpAbsolute 0x4000000
#define Abs8 0x08000000
#define Abs8 0x8000000
#define Abs16 0x10000000
#define Abs32 0x20000000
#define Abs (Abs8|Abs16|Abs32)
#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 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) */
#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 */
/* (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 DW (D|W) /* shorthand */
/* (opcode_modifier & COMES_IN_BOTH_DIRECTIONS) indicates that the
source and destination operands can be reversed by setting either