aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-i386.c
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@airs.com>1998-06-03 22:28:28 +0000
committerIan Lance Taylor <ian@airs.com>1998-06-03 22:28:28 +0000
commitec1e6bb85062e3a37030ca591f0e87af9ef74f2e (patch)
treed8284a76109cfae2fe2d8b2cdbb0a33c5cea479e /gas/config/tc-i386.c
parent2edb8195a9145f4283383fc66f56159d22b2b8e4 (diff)
downloadfsf-binutils-gdb-ec1e6bb85062e3a37030ca591f0e87af9ef74f2e.zip
fsf-binutils-gdb-ec1e6bb85062e3a37030ca591f0e87af9ef74f2e.tar.gz
fsf-binutils-gdb-ec1e6bb85062e3a37030ca591f0e87af9ef74f2e.tar.bz2
Wed Jun 3 18:21:56 1998 Alan Modra <alan@spri.levels.unisa.edu.au>
* config/tc-i386.c (SCALE1_WHEN_NO_INDEX): Define. (ebp, esp): Remove static variables. (MATCH): Remove test for InOutPortReg. (i386_operand): Properly handle InOutPortReg here instead. Disallows `inb (%dx,2)', `inb %es:(%dx)' and `mov (%dx),%ax' (md_assemble): Simplify and correct modrm and sib generation. (i386_operand): Add warning for scale without index. Rewrite checks for valid base/index combinations.
Diffstat (limited to 'gas/config/tc-i386.c')
-rw-r--r--gas/config/tc-i386.c220
1 files changed, 96 insertions, 124 deletions
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 9178ef5..a08ec9f 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -38,6 +38,14 @@
#define TC_RELOC(X,Y) (Y)
#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
+ `mov (%ebx),%al'. To slavishly follow what the programmer
+ specified, set SCALE1_WHEN_NO_INDEX to 0. */
+#define SCALE1_WHEN_NO_INDEX 1
+#endif
+
static unsigned long mode_from_disp_size PARAMS ((unsigned long));
static int fits_in_signed_byte PARAMS ((long));
static int fits_in_unsigned_byte PARAMS ((long));
@@ -102,10 +110,9 @@ struct _i386_insn
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. */
- /* richfix: really unsigned? */
- unsigned char prefix[MAX_PREFIXES];
+ PREFIXES is the number of prefix opcodes. */
unsigned int prefixes;
+ unsigned char prefix[MAX_PREFIXES];
/* Wait prefix needs to come before any other prefixes, so handle
it specially. wait_prefix will hold the opcode modifier flag
@@ -189,9 +196,6 @@ 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. */
-static reg_entry *ebp, *esp;
-
static int this_operand; /* current operand we are working on */
static int flag_do_long_jump; /* FIXME what does this do? */
@@ -609,9 +613,6 @@ md_begin ()
}
}
- esp = (reg_entry *) hash_find (reg_hash, "esp");
- ebp = (reg_entry *) hash_find (reg_hash, "ebp");
-
/* initialize reg_hash hash table */
prefix_hash = hash_new ();
{
@@ -967,7 +968,6 @@ md_assemble (line)
else
{
/* This opcode's got a prefix. */
- unsigned int q;
prefix_entry *prefix;
if (l == token_start)
@@ -1143,11 +1143,9 @@ md_assemble (line)
with the template operand types. */
#define MATCH(overlap,given_type) \
- (overlap && \
- (((overlap & (JumpAbsolute|BaseIndex|Mem8)) \
- == (given_type & (JumpAbsolute|BaseIndex|Mem8))) \
- || (overlap == InOutPortReg)))
-
+ (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.
@@ -1524,85 +1522,72 @@ md_assemble (line)
? 0
: (i.types[1] & Mem) ? 1 : 2);
- /* Encode memory operand into modrm byte and base index
- byte. */
+ default_seg = &ds;
- if (i.base_reg == esp && !i.index_reg)
- {
- /* <disp>(%esp) becomes two byte modrm with no index
- register. */
- i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
- i.rm.mode = mode_from_disp_size (i.types[op]);
- i.bi.base = ESP_REG_NUM;
- i.bi.index = NO_INDEX_REGISTER;
- i.bi.scale = 0; /* Must be zero! */
- }
- else if (i.base_reg == ebp && !i.index_reg)
+ if (! i.base_reg)
{
- if (!(i.types[op] & Disp))
+ i.rm.mode = 0;
+ if (! i.disp_operands)
+ fake_zero_displacement = 1;
+ if (! i.index_reg)
{
- /* Must fake a zero byte displacement. There is
- no direct way to code '(%ebp)' directly. */
- fake_zero_displacement = 1;
- /* fake_zero_displacement code does not set this. */
- i.types[op] |= Disp8;
- }
- i.rm.mode = mode_from_disp_size (i.types[op]);
- i.rm.regmem = EBP_REG_NUM;
- }
- else if (!i.base_reg && (i.types[op] & BaseIndex))
- {
- /* There are three cases here.
- Case 1: '<32bit disp>(,1)' -- indirect absolute.
- (Same as cases 2 & 3 with NO index register)
- Case 2: <32bit disp> (,<index>) -- no base register with disp
- Case 3: (, <index>) --- no base register;
- no disp (must add 32bit 0 disp). */
- i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
- i.rm.mode = 0; /* 32bit mode */
- i.bi.base = NO_BASE_REGISTER;
- i.types[op] &= ~Disp;
- i.types[op] |= Disp32; /* Must be 32bit! */
- if (i.index_reg)
- { /* case 2 or case 3 */
- i.bi.index = i.index_reg->reg_num;
- i.bi.scale = i.log2_scale_factor;
- if (i.disp_operands == 0)
- fake_zero_displacement = 1; /* case 3 */
+ /* Operand is just <disp> */
+ i.rm.regmem = NO_BASE_REGISTER;
+ i.types[op] &= ~Disp;
+ i.types[op] |= Disp32;
}
else
{
- i.bi.index = NO_INDEX_REGISTER;
- i.bi.scale = 0;
+ i.bi.index = i.index_reg->reg_num;
+ i.bi.base = NO_BASE_REGISTER;
+ i.bi.scale = i.log2_scale_factor;
+ i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
+ i.types[op] &= ~Disp;
+ i.types[op] |= Disp32; /* Must be 32 bit */
}
}
- else if (i.disp_operands && !i.base_reg && !i.index_reg)
+ else /* i.base_reg */
{
- /* Operand is just <32bit disp> */
- i.rm.regmem = EBP_REG_NUM;
- i.rm.mode = 0;
- i.types[op] &= ~Disp;
- i.types[op] |= Disp32;
- }
- else
- {
- /* It's not a special case; rev'em up. */
i.rm.regmem = i.base_reg->reg_num;
- i.rm.mode = mode_from_disp_size (i.types[op]);
- if (i.index_reg)
+ i.bi.base = i.base_reg->reg_num;
+ if (i.base_reg->reg_num == EBP_REG_NUM)
{
- i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
- i.bi.base = i.base_reg->reg_num;
- i.bi.index = i.index_reg->reg_num;
- i.bi.scale = i.log2_scale_factor;
- if (i.base_reg == ebp && i.disp_operands == 0)
- { /* pace */
+ default_seg = &ss;
+ if (i.disp_operands == 0)
+ {
fake_zero_displacement = 1;
i.types[op] |= Disp8;
- i.rm.mode = mode_from_disp_size (i.types[op]);
}
}
+ else if (i.base_reg->reg_num == ESP_REG_NUM)
+ {
+ default_seg = &ss;
+ }
+ i.bi.scale = i.log2_scale_factor;
+ if (! i.index_reg)
+ {
+ /* <disp>(%esp) becomes two byte modrm
+ with no index register. We've already
+ stored the code for esp in i.rm.regmem
+ ie. ESCAPE_TO_TWO_BYTE_ADDRESSING. Any
+ base register besides %esp will not use
+ the extra modrm byte. */
+ i.bi.index = NO_INDEX_REGISTER;
+#if ! SCALE1_WHEN_NO_INDEX
+ /* Another case where we force the second
+ modrm byte. */
+ if (i.log2_scale_factor)
+ i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
+#endif
+ }
+ else
+ {
+ i.bi.index = i.index_reg->reg_num;
+ i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
+ }
+ i.rm.mode = mode_from_disp_size (i.types[op]);
}
+
if (fake_zero_displacement)
{
/* Fakes a zero displacement assuming that i.types[op]
@@ -1614,24 +1599,6 @@ md_assemble (line)
exp->X_add_symbol = (symbolS *) 0;
exp->X_op_symbol = (symbolS *) 0;
}
-
- /* Find the default segment for the memory operand.
- Used to optimize out explicit segment specifications. */
- if (i.seg[0])
- {
- unsigned int seg_index;
-
- if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING)
- {
- seg_index = (i.rm.mode << 3) | i.bi.base;
- default_seg = two_byte_segment_defaults[seg_index];
- }
- else
- {
- seg_index = (i.rm.mode << 3) | i.rm.regmem;
- default_seg = one_byte_segment_defaults[seg_index];
- }
- }
}
/* Fill in i.rm.reg or i.rm.regmem field with register
@@ -1984,7 +1951,8 @@ md_assemble (line)
1);
/* If i.rm.regmem == ESP (4) && i.rm.mode != Mode 3 (Register mode)
==> need second modrm byte. */
- if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING && i.rm.mode != 3)
+ if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING
+ && i.rm.mode != 3)
{
p = frag_more (1);
insn_size += 1;
@@ -2202,7 +2170,7 @@ i386_operand (operand_string)
}
goto do_memory_reference;
}
- i.types[this_operand] |= r->reg_type;
+ i.types[this_operand] |= r->reg_type & ~BaseIndex;
i.regs[this_operand] = r;
i.reg_operands++;
}
@@ -2292,7 +2260,7 @@ i386_operand (operand_string)
{
/* This is a memory reference of some sort. */
register char *base_string;
- unsigned int found_base_index_form;
+ int found_base_index_form;
do_memory_reference:
if ((i.mem_operands == 1
@@ -2303,7 +2271,6 @@ i386_operand (operand_string)
current_templates->start->name);
return 0;
}
- i.mem_operands++;
/* Determine type of memory operand from opcode_suffix;
no opcode suffix implies general memory references. */
@@ -2453,6 +2420,14 @@ i386_operand (operand_string)
as_bad (_("expecting scale factor of 1, 2, 4, 8; got %d"), num);
return 0;
}
+ if (num != 1 && ! i.index_reg)
+ {
+ as_warn (_("scale factor of %d without an index register"),
+ num);
+#if SCALE1_WHEN_NO_INDEX
+ i.log2_scale_factor = 0;
+#endif
+ }
}
else
{
@@ -2588,35 +2563,28 @@ i386_operand (operand_string)
}
}
- /* Make sure the memory operand we've been dealt is valid. */
- if (i.base_reg && i.index_reg &&
- !(i.base_reg->reg_type & i.index_reg->reg_type & Reg))
+ /* 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)
{
- as_bad (_("register size mismatch in (base,index,scale) expression"));
- return 0;
- }
- /*
- * 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.types[this_operand] |= InOutPortReg;
+ i.types[this_operand] = InOutPortReg;
return 1;
}
- if ((i.base_reg && (i.base_reg->reg_type & Reg32) == 0) ||
- (i.index_reg && (i.index_reg->reg_type & Reg32) == 0))
- {
- as_bad (_("base/index register must be 32 bit register"));
- return 0;
- }
- if (i.index_reg && i.index_reg == esp)
+ /* 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))
{
- as_bad (_("`%%s' may not be used as an index register"),
- esp->reg_name);
+ as_bad (_("`%s' is not a valid base/index expression"),
+ operand_string);
return 0;
}
+ i.mem_operands++;
}
else
{ /* it's not a memory operand; argh! */
@@ -2867,7 +2835,11 @@ md_apply_fix3 (fixP, valp, seg)
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
if (OUTPUT_FLAVOR == bfd_target_elf_flavour
&& (S_GET_SEGMENT (fixP->fx_addsy) == seg
- || (fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) != 0))
+ || (fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) != 0)
+ && ! S_IS_EXTERNAL (fixP->fx_addsy)
+ && ! S_IS_WEAK (fixP->fx_addsy)
+ && S_IS_DEFINED (fixP->fx_addsy)
+ && ! S_IS_COMMON (fixP->fx_addsy))
{
/* Yes, we add the values in twice. This is because
bfd_perform_relocation subtracts them out again. I think