Tue Apr 21 17:01:22 1998 Alan Modra <alan@spri.levels.unisa.edu.au>
authorIan Lance Taylor <ian@airs.com>
Tue, 21 Apr 1998 21:08:39 +0000 (21:08 +0000)
committerIan Lance Taylor <ian@airs.com>
Tue, 21 Apr 1998 21:08:39 +0000 (21:08 +0000)
* 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.

gas/ChangeLog
gas/config/tc-i386.c
gas/config/tc-i386.h

index c422f7d185b164c70134b3e7b6291201e125a524..f89e2c7db51316cafb2a847f9c2228a73c9730f4 100644 (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
index 427d2c6c9f1a4006434beff38ada41d550b42175..10c97f55ca1db00d3b5e668b66aaec9e935e6239 100644 (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!");
-                 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;
index 2fc36055a3114e9550ed315a1739a8016a99c182..6d4f6b448b9409a6f7150f8df9ff24d443d716bb 100644 (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,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