Fix bug disassmbling binary files for non-octet byte targets.
[deliverable/binutils-gdb.git] / gas / config / tc-i386.c
index 8e3cae700842bd6fde80251415e9e21af8905780..638bbd041459c95b562bb2d4e74b31d77ff2708e 100644 (file)
@@ -1,5 +1,5 @@
 /* i386.c -- Assemble code for the Intel 80386
-   Copyright (C) 1989, 91, 92, 93, 94, 95, 96, 97, 98, 1999
+   Copyright (C) 1989, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000
    Free Software Foundation.
 
    This file is part of GAS, the GNU Assembler.
 #include "subsegs.h"
 #include "opcode/i386.h"
 
-#ifndef TC_RELOC
-#define TC_RELOC(X,Y) (Y)
-#endif
-
 #ifndef REGISTER_WARNINGS
 #define REGISTER_WARNINGS 1
 #endif
 #define false 0
 
 static unsigned int mode_from_disp_size PARAMS ((unsigned int));
-static int fits_in_signed_byte PARAMS ((long));
-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 fits_in_signed_byte PARAMS ((offsetT));
+static int fits_in_unsigned_byte PARAMS ((offsetT));
+static int fits_in_unsigned_word PARAMS ((offsetT));
+static int fits_in_signed_word PARAMS ((offsetT));
+static int smallest_imm_type PARAMS ((offsetT));
+static offsetT offset_in_range PARAMS ((offsetT, int));
 static int add_prefix PARAMS ((unsigned int));
 static void set_16bit_code_flag PARAMS ((int));
 static void set_16bit_gcc_code_flag PARAMS((int));
@@ -74,6 +71,13 @@ static bfd_reloc_code_real_type reloc
 /* 'md_assemble ()' gathers together information and puts it into a
    i386_insn. */
 
+union i386_op
+  {
+    expressionS *disps;
+    expressionS *imms;
+    const reg_entry *regs;
+  };
+
 struct _i386_insn
   {
     /* TM holds the template for the insn were currently assembling. */
@@ -83,8 +87,6 @@ struct _i386_insn
        (e.g. 'l' for 'movl')  */
     char suffix;
 
-    /* Operands are coded with OPERANDS, TYPES, DISPS, IMMS, and REGS. */
-
     /* OPERANDS gives the number of given operands. */
     unsigned int operands;
 
@@ -94,12 +96,12 @@ struct _i386_insn
     unsigned int reg_operands, disp_operands, mem_operands, imm_operands;
 
     /* TYPES [i] is the type (see above #defines) which tells us how to
-       search through DISPS [i] & IMMS [i] & REGS [i] for the required
-       operand.  */
+       use OP[i] for the corresponding operand.  */
     unsigned int types[MAX_OPERANDS];
 
-    /* Displacements (if given) for each operand. */
-    expressionS *disps[MAX_OPERANDS];
+    /* Displacement expression, immediate expression, or register for each
+       operand.  */
+    union i386_op op[MAX_OPERANDS];
 
     /* Relocation type for operand */
 #ifdef BFD_ASSEMBLER
@@ -108,12 +110,6 @@ struct _i386_insn
     int disp_reloc[MAX_OPERANDS];
 #endif
 
-    /* Immediate operands (if given) for each operand. */
-    expressionS *imms[MAX_OPERANDS];
-
-    /* Register operands (if given) for each operand. */
-    const reg_entry *regs[MAX_OPERANDS];
-
     /* BASE_REG, INDEX_REG, and LOG2_SCALE_FACTOR are used to encode
        the base index byte below.  */
     const reg_entry *base_reg;
@@ -232,12 +228,13 @@ static int allow_naked_reg = 0;  /* 1 if register prefix % not required */
 
 static char stackop_size = '\0';  /* Used in 16 bit gcc mode to add an l
                                     suffix to call, ret, enter, leave, push,
-                                    and pop instructions.  */
+                                    and pop instructions so that gcc has the
+                                    same stack frame as in 32 bit mode.  */
 
 /* Interface to relax_segment.
    There are 2 relax states for 386 jump insns: one for conditional &
-   one for unconditional jumps.  This is because the these two types
-   of jumps add different sizes to frags when we're figuring out what
+   one for unconditional jumps.  This is because these two types of
+   jumps add different sizes to frags when we're figuring out what
    sort of jump to choose to reach a given label.  */
 
 /* types */
@@ -414,35 +411,35 @@ mode_from_disp_size (t)
 
 static INLINE int
 fits_in_signed_byte (num)
-     long num;
+     offsetT num;
 {
   return (num >= -128) && (num <= 127);
 }                              /* fits_in_signed_byte() */
 
 static INLINE int
 fits_in_unsigned_byte (num)
-     long num;
+     offsetT num;
 {
   return (num & 0xff) == num;
 }                              /* fits_in_unsigned_byte() */
 
 static INLINE int
 fits_in_unsigned_word (num)
-     long num;
+     offsetT num;
 {
   return (num & 0xffff) == num;
 }                              /* fits_in_unsigned_word() */
 
 static INLINE int
 fits_in_signed_word (num)
-     long num;
+     offsetT num;
 {
   return (-32768 <= num) && (num <= 32767);
 }                              /* fits_in_signed_word() */
 
 static int
 smallest_imm_type (num)
-     long num;
+     offsetT num;
 {
 #if 0
   /* This code is disabled because all the Imm1 forms in the opcode table
@@ -463,6 +460,36 @@ smallest_imm_type (num)
          : (Imm32));
 }                              /* smallest_imm_type() */
 
+static offsetT
+offset_in_range (val, size)
+     offsetT val;
+     int size;
+{
+  bfd_vma mask;
+
+  switch (size)
+    {
+    case 1: mask = ((bfd_vma) 1 <<  8) - 1; break;
+    case 2: mask = ((bfd_vma) 1 << 16) - 1; break;
+    case 4: mask = ((bfd_vma) 1 << 32) - 1; break;
+    default: abort();
+    }
+
+  /* If BFD64, sign extend val.  */
+  if ((val & ~ (((bfd_vma) 1 << 32) - 1)) == 0)
+    val = (val ^ ((bfd_vma) 1 << 31)) - ((bfd_vma) 1 << 31);
+
+  if ((val & ~ mask) != 0 && (val & ~ mask) != ~ mask)
+    {
+      char buf1[40], buf2[40];
+
+      sprint_value (buf1, val);
+      sprint_value (buf2, val & mask);
+      as_warn (_("%s shortened to %s"), buf1, buf2);
+    }
+  return val & mask;
+}
+
 /* Returns 0 if attempting to add a prefix where one from the same
    class already exists, 1 if non rep/repne added, 2 if rep/repne
    added.  */
@@ -553,7 +580,7 @@ set_intel_syntax (syntax_flag)
       else if (strcmp(string, "noprefix") == 0)
        ask_naked_reg = -1;
       else
-       as_bad (_("Bad argument to syntax directive."));
+       as_bad (_("bad argument to syntax directive."));
       *input_line_pointer = e;
     }
   demand_empty_rest_of_line ();
@@ -760,11 +787,11 @@ pi (line, x)
       fprintf (stdout, "\n");
       if (x->types[i]
          & (Reg | SReg2 | SReg3 | Control | Debug | Test | RegMMX | RegXMM))
-       fprintf (stdout, "%s\n", x->regs[i]->reg_name);
+       fprintf (stdout, "%s\n", x->op[i].regs->reg_name);
       if (x->types[i] & Imm)
-       pe (x->imms[i]);
+       pe (x->op[i].imms);
       if (x->types[i] & Disp)
-       pe (x->disps[i]);
+       pe (x->op[i].disps);
     }
 }
 
@@ -891,7 +918,7 @@ tc_i386_force_relocation (fixp)
   return 0;
 #else
   /* For COFF */
-  return fixp->fx_r_type==7;
+  return fixp->fx_r_type == 7;
 #endif
 }
 
@@ -915,7 +942,7 @@ reloc (size, pcrel, other)
        case 2: return BFD_RELOC_16_PCREL;
        case 4: return BFD_RELOC_32_PCREL;
        }
-      as_bad (_("Can not do %d byte pc-relative relocation"), size);
+      as_bad (_("can not do %d byte pc-relative relocation"), size);
     }
   else
     {
@@ -925,7 +952,7 @@ reloc (size, pcrel, other)
        case 2: return BFD_RELOC_16;
        case 4: return BFD_RELOC_32;
        }
-      as_bad (_("Can not do %d byte relocation"), size);
+      as_bad (_("can not do %d byte relocation"), size);
     }
 
   return BFD_RELOC_NONE;
@@ -953,6 +980,7 @@ tc_i386_fix_adjustable (fixP)
   if (fixP->fx_r_type == BFD_RELOC_386_GOTOFF
       || fixP->fx_r_type == BFD_RELOC_386_PLT32
       || fixP->fx_r_type == BFD_RELOC_386_GOT32
+      || fixP->fx_r_type == BFD_RELOC_RVA
       || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
       || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
     return 0;
@@ -977,7 +1005,7 @@ intel_float_operand (mnemonic)
      char *mnemonic;
 {
   if (mnemonic[0] == 'f' && mnemonic[1] =='i')
-    return 0;
+    return 2;
 
   if (mnemonic[0] == 'f')
     return 1;
@@ -1092,20 +1120,17 @@ md_assemble (line)
        /* See if we can get a match by trimming off a suffix.  */
        switch (mnem_p[-1])
          {
-         case DWORD_MNEM_SUFFIX:
          case WORD_MNEM_SUFFIX:
          case BYTE_MNEM_SUFFIX:
          case SHORT_MNEM_SUFFIX:
-#if LONG_MNEM_SUFFIX != DWORD_MNEM_SUFFIX
          case LONG_MNEM_SUFFIX:
-#endif
            i.suffix = mnem_p[-1];
            mnem_p[-1] = '\0';
            current_templates = hash_find (op_hash, mnemonic);
            break;
 
          /* Intel Syntax */
-         case INTEL_DWORD_MNEM_SUFFIX:
+         case DWORD_MNEM_SUFFIX:
            if (intel_syntax)
              {
                i.suffix = mnem_p[-1];
@@ -1254,9 +1279,8 @@ md_assemble (line)
      with the template operand types. */
 
 #define MATCH(overlap, given, template) \
-  ((overlap) \
-   && ((given) & BaseIndex) == ((overlap) & BaseIndex) \
-   && ((given) & JumpAbsolute) == ((template) & JumpAbsolute))
+  ((overlap & ~JumpAbsolute) \
+   && ((given) & (BaseIndex|JumpAbsolute)) == ((overlap) & (BaseIndex|JumpAbsolute)))
 
   /* If given types r0 and r1 are registers they must be of the same type
      unless the expected operand type register overlap is null.
@@ -1272,16 +1296,17 @@ md_assemble (line)
     unsigned int found_reverse_match;
     int suffix_check;
 
-    /* All intel opcodes have reversed operands except for BOUND and ENTER */
-    if (intel_syntax
-       && (strcmp (mnemonic, "enter") != 0)
+    /* All intel opcodes have reversed operands except for "bound" and
+       "enter".  We also don't reverse intersegment "jmp" and "call"
+       instructions with 2 immediate operands so that the immediate segment
+       precedes the offset, as it does when in AT&T mode.  "enter" and the
+       intersegment "jmp" and "call" instructions are the only ones that
+       have two immediate operands.  */
+    if (intel_syntax && i.operands > 1
        && (strcmp (mnemonic, "bound") != 0)
-       && (strncmp (mnemonic, "fsub", 4) !=0)
-       && (strncmp (mnemonic, "fdiv", 4) !=0))
+       && !((i.types[0] & Imm) && (i.types[1] & Imm)))
       {
-       const reg_entry *temp_reg = NULL;
-       expressionS *temp_disp = NULL;
-       expressionS *temp_imm = NULL;
+       union i386_op temp_op;
        unsigned int temp_type;
        int xchg1 = 0;
        int xchg2 = 0;
@@ -1296,62 +1321,79 @@ md_assemble (line)
            xchg1 = 0;
            xchg2 = 2;
          }
-
-       if (i.operands > 1)
+       temp_type = i.types[xchg2];
+       i.types[xchg2] = i.types[xchg1];
+       i.types[xchg1] = temp_type;
+       temp_op = i.op[xchg2];
+       i.op[xchg2] = i.op[xchg1];
+       i.op[xchg1] = temp_op;
+
+       if (i.mem_operands == 2)
          {
-           temp_type = i.types[xchg2];
-           if (temp_type & (Reg | FloatReg))
-             temp_reg = i.regs[xchg2];
-           else if (temp_type & Imm)
-             temp_imm = i.imms[xchg2];
-           else if (temp_type & Disp)
-             temp_disp = i.disps[xchg2];
-
-           i.types[xchg2] = i.types[xchg1];
-
-           if (i.types[xchg1] & (Reg | FloatReg))
-             {
-               i.regs[xchg2] = i.regs[xchg1];
-               i.regs[xchg1] = NULL;
-             }
-           else if (i.types[xchg2] & Imm)
-             {
-               i.imms[xchg2] = i.imms[xchg1];
-               i.imms[xchg1] = NULL;
-             }
-           else if (i.types[xchg2] & Disp)
-             {
-               i.disps[xchg2] = i.disps[xchg1];
-               i.disps[xchg1] = NULL;
-             }
+           const seg_entry *temp_seg;
+           temp_seg = i.seg[0];
+           i.seg[0] = i.seg[1];
+           i.seg[1] = temp_seg;
+         }
+      }
 
-           if (temp_type & (Reg | FloatReg))
-             {
-               i.regs[xchg1] = temp_reg;
-               if (! (i.types[xchg1] & (Reg | FloatReg)))
-                 i.regs[xchg2] = NULL;
-             }
-           else if (temp_type & Imm)
-             {
-               i.imms[xchg1] = temp_imm;
-               if (! (i.types[xchg1] & Imm))
-                 i.imms[xchg2] = NULL;
-             }
-           else if (temp_type & Disp)
-             {
-               i.disps[xchg1] = temp_disp;
-               if (! (i.types[xchg1] & Disp))
-                 i.disps[xchg2] = NULL;
-             }
+    if (i.imm_operands)
+      {
+       /* Try to ensure constant immediates are represented in the smallest
+          opcode possible.  */
+       char guess_suffix = 0;
+       int op;
 
-           i.types[xchg1] = temp_type;
+       if (i.suffix)
+         guess_suffix = i.suffix;
+       else if (i.reg_operands)
+         {
+           /* Figure out a suffix from the last register operand specified.
+              We can't do this properly yet, ie. excluding InOutPortReg,
+              but the following works for instructions with immediates.
+              In any case, we can't set i.suffix yet.  */
+           for (op = i.operands; --op >= 0; )
+             if (i.types[op] & Reg)
+               {
+                 if (i.types[op] & Reg8)
+                   guess_suffix = BYTE_MNEM_SUFFIX;
+                 else if (i.types[op] & Reg16)
+                   guess_suffix = WORD_MNEM_SUFFIX;
+                 break;
+               }
          }
-       if (!strcmp(mnemonic,"jmp")
-           || !strcmp (mnemonic, "call"))
-         if ((i.types[0] & Reg) || i.types[0] & BaseIndex)
-           i.types[0] |= JumpAbsolute;
+       else if (flag_16bit_code ^ (i.prefix[DATA_PREFIX] != 0))
+         guess_suffix = WORD_MNEM_SUFFIX;
 
+       for (op = i.operands; --op >= 0; )
+         if ((i.types[op] & Imm)
+             && i.op[op].imms->X_op == O_constant)
+           {
+             /* If a suffix is given, this operand may be shortened.  */
+             switch (guess_suffix)
+               {
+               case WORD_MNEM_SUFFIX:
+                 i.types[op] |= Imm16;
+                 break;
+               case BYTE_MNEM_SUFFIX:
+                 i.types[op] |= Imm16 | Imm8 | Imm8S;
+                 break;
+               }
+
+             /* If this operand is at most 16 bits, convert it to a
+                signed 16 bit number before trying to see whether it will
+                fit in an even smaller size.  This allows a 16-bit operand
+                such as $0xffe0 to be recognised as within Imm8S range.  */
+             if ((i.types[op] & Imm16)
+                 && (i.op[op].imms->X_add_number & ~(offsetT)0xffff) == 0)
+               {
+                 i.op[op].imms->X_add_number =
+                   (((i.op[op].imms->X_add_number & 0xffff) ^ 0x8000) - 0x8000);
+               }
+             i.types[op] |= smallest_imm_type ((long) i.op[op].imms->X_add_number);
+           }
       }
+
     overlap0 = 0;
     overlap1 = 0;
     overlap2 = 0;
@@ -1364,7 +1406,7 @@ md_assemble (line)
                          ? No_sSuf
                          : (i.suffix == LONG_MNEM_SUFFIX
                             ? No_lSuf
-                            : (i.suffix == INTEL_DWORD_MNEM_SUFFIX
+                            : (i.suffix == DWORD_MNEM_SUFFIX
                                ? No_dSuf
                                : (i.suffix == LONG_DOUBLE_MNEM_SUFFIX ? No_xSuf : 0))))));
 
@@ -1376,16 +1418,12 @@ md_assemble (line)
        if (i.operands != t->operands)
          continue;
 
-       /* For some opcodes, don't check the suffix */
-       if (intel_syntax)
-         {
-           if (strcmp (t->name, "fnstcw")
-               && strcmp (t->name, "fldcw")
-               && (t->opcode_modifier & suffix_check))
-             continue;
-         }
-       /* Must not have disallowed suffix. */
-       else if ((t->opcode_modifier & suffix_check))
+       /* Check the suffix, except for some instructions in intel mode.  */
+       if ((t->opcode_modifier & suffix_check)
+           && !(intel_syntax
+                && t->base_opcode == 0xd9
+                && (t->extension_opcode == 5   /* 0xd9,5 "fldcw"  */
+                    || t->extension_opcode == 7))) /* 0xd9,7 "f{n}stcw"  */
          continue;
 
        else if (!t->operands)
@@ -1459,6 +1497,12 @@ md_assemble (line)
        return;
       }
 
+    if (!intel_syntax
+       && (i.types[0] & JumpAbsolute) != (t->operand_types[0] & JumpAbsolute))
+      {
+       as_warn (_("indirect %s without `*'"), t->name);
+      }
+
     if ((t->opcode_modifier & (IsPrefix|IgnoreSize)) == (IsPrefix|IgnoreSize))
       {
        /* Warn them that a data or address size prefix doesn't affect
@@ -1470,10 +1514,21 @@ md_assemble (line)
     i.tm = *t;
     if (found_reverse_match)
       {
+       /* If we found a reverse match we must alter the opcode
+          direction bit.  found_reverse_match holds bits to change
+          (different for int & float insns).  */
+
+       i.tm.base_opcode ^= found_reverse_match;
+
        i.tm.operand_types[0] = t->operand_types[1];
        i.tm.operand_types[1] = t->operand_types[0];
       }
 
+    /* Undo SYSV386_COMPAT brokenness when in Intel mode.  See i386.h  */
+     if (SYSV386_COMPAT
+        && intel_syntax
+        && (i.tm.base_opcode & 0xfffffde0) == 0xdce0)
+       i.tm.base_opcode ^= FloatR;
 
     if (i.tm.opcode_modifier & FWait)
       if (! add_prefix (FWAIT_OPCODE))
@@ -1517,7 +1572,7 @@ md_assemble (line)
        if (i.tm.opcode_modifier & Size16)
          i.suffix = WORD_MNEM_SUFFIX;
        else
-         i.suffix = DWORD_MNEM_SUFFIX;
+         i.suffix = LONG_MNEM_SUFFIX;
       }
     else if (i.reg_operands)
       {
@@ -1530,11 +1585,12 @@ md_assemble (line)
               register type.  */
            int op;
            for (op = i.operands; --op >= 0; )
-             if (i.types[op] & Reg)
+             if ((i.types[op] & Reg)
+                 && !(i.tm.operand_types[op] & InOutPortReg))
                {
                  i.suffix = ((i.types[op] & Reg8) ? BYTE_MNEM_SUFFIX :
                              (i.types[op] & Reg16) ? WORD_MNEM_SUFFIX :
-                             DWORD_MNEM_SUFFIX);
+                             LONG_MNEM_SUFFIX);
                  break;
                }
          }
@@ -1557,7 +1613,7 @@ md_assemble (line)
                        || i.tm.base_opcode == 0xfbf))
                  continue;
 
-               if ((i.types[op] & WordReg) && i.regs[op]->reg_num < 4
+               if ((i.types[op] & WordReg) && i.op[op].regs->reg_num < 4
 #if 0
                    /* Check that the template allows eight bit regs
                       This kills insns such as `orb $1,%edx', which
@@ -1569,8 +1625,8 @@ md_assemble (line)
 #if REGISTER_WARNINGS
                    if ((i.tm.operand_types[op] & InOutPortReg) == 0)
                      as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"),
-                              (i.regs[op] - (i.types[op] & Reg16 ? 8 : 16))->reg_name,
-                              i.regs[op]->reg_name,
+                              (i.op[op].regs - (i.types[op] & Reg16 ? 8 : 16))->reg_name,
+                              i.op[op].regs->reg_name,
                               i.suffix);
 #endif
                    continue;
@@ -1582,14 +1638,14 @@ md_assemble (line)
                                   | FloatReg | FloatAcc))
                  {
                    as_bad (_("`%%%s' not allowed with `%s%c'"),
-                           i.regs[op]->reg_name,
+                           i.op[op].regs->reg_name,
                            i.tm.name,
                            i.suffix);
                    return;
                  }
              }
          }
-       else if (i.suffix == DWORD_MNEM_SUFFIX)
+       else if (i.suffix == LONG_MNEM_SUFFIX)
          {
            int op;
            for (op = i.operands; --op >= 0; )
@@ -1599,7 +1655,7 @@ md_assemble (line)
                  && (i.tm.operand_types[op] & (Reg16|Reg32|Acc)) != 0)
                {
                  as_bad (_("`%%%s' not allowed with `%s%c'"),
-                         i.regs[op]->reg_name,
+                         i.op[op].regs->reg_name,
                          i.tm.name,
                          i.suffix);
                  return;
@@ -1610,8 +1666,8 @@ md_assemble (line)
                       && (i.tm.operand_types[op] & (Reg32|Acc)) != 0)
                {
                  as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"),
-                          (i.regs[op] + 8)->reg_name,
-                          i.regs[op]->reg_name,
+                          (i.op[op].regs + 8)->reg_name,
+                          i.op[op].regs->reg_name,
                           i.suffix);
                }
 #endif
@@ -1626,7 +1682,7 @@ md_assemble (line)
                  && (i.tm.operand_types[op] & (Reg16|Reg32|Acc)) != 0)
                {
                  as_bad (_("`%%%s' not allowed with `%s%c'"),
-                         i.regs[op]->reg_name,
+                         i.op[op].regs->reg_name,
                          i.tm.name,
                          i.suffix);
                  return;
@@ -1637,8 +1693,8 @@ md_assemble (line)
                       && (i.tm.operand_types[op] & (Reg16|Acc)) != 0)
                {
                  as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"),
-                          (i.regs[op] - 8)->reg_name,
-                          i.regs[op]->reg_name,
+                          (i.op[op].regs - 8)->reg_name,
+                          i.op[op].regs->reg_name,
                           i.suffix);
                }
 #endif
@@ -1725,7 +1781,7 @@ md_assemble (line)
        {
          unsigned int prefix = DATA_PREFIX_OPCODE;
 
-         if ((i.regs[1]->reg_type & Reg16) != 0)
+         if ((i.op[1].regs->reg_type & Reg16) != 0)
            if (!add_prefix (prefix))
              return;
        }
@@ -1743,8 +1799,7 @@ md_assemble (line)
        /* Now select between word & dword operations via the operand
           size prefix, except for instructions that will ignore this
           prefix anyway.  */
-       if (((intel_syntax && (i.suffix == INTEL_DWORD_MNEM_SUFFIX))
-            || i.suffix == DWORD_MNEM_SUFFIX
+       if (((intel_syntax && (i.suffix == DWORD_MNEM_SUFFIX))
             || i.suffix == LONG_MNEM_SUFFIX) == flag_16bit_code
            && !(i.tm.opcode_modifier & IgnoreSize))
          {
@@ -1757,7 +1812,7 @@ md_assemble (line)
          }
        /* Size floating point instruction.  */
        if (i.suffix == LONG_MNEM_SUFFIX
-           || (intel_syntax && i.suffix == INTEL_DWORD_MNEM_SUFFIX))
+           || (intel_syntax && i.suffix == DWORD_MNEM_SUFFIX))
          {
            if (i.tm.opcode_modifier & FloatMF)
              i.tm.base_opcode ^= 4;
@@ -1773,10 +1828,10 @@ md_assemble (line)
 
        expressionS *exp;
 
-       assert(i.imm_operands == 0 && i.operands <= 2);
+       assert(i.imm_operands == 0 && i.operands <= 2 && 2 < MAX_OPERANDS);
 
        exp = &im_expressions[i.imm_operands++];
-       i.imms[i.operands] = exp;
+       i.op[i.operands].imms = exp;
        i.types[i.operands++] = Imm8;
        exp->X_op = O_constant;
        exp->X_add_number = i.tm.extension_opcode;
@@ -1791,12 +1846,6 @@ md_assemble (line)
           This is only for optimizing out unnecessary segment overrides.  */
        const seg_entry *default_seg = 0;
 
-       /* If we found a reverse match we must alter the opcode
-          direction bit.  found_reverse_match holds bits to change
-          (different for int & float insns).  */
-
-       i.tm.base_opcode ^= found_reverse_match;
-
        /* The imul $imm, %reg instruction is converted into
           imul $imm, %reg, %reg, and the clr %reg instruction
           is converted into xor %reg, %reg.  */
@@ -1804,7 +1853,9 @@ md_assemble (line)
          {
            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];
+           assert (i.op[first_reg_op+1].regs == 0);
+           i.op[first_reg_op+1].regs = i.op[first_reg_op].regs;
+           i.types[first_reg_op+1] = i.types[first_reg_op];
            i.reg_operands = 2;
          }
 
@@ -1813,7 +1864,7 @@ md_assemble (line)
            /* The register or float register operand is in operand 0 or 1. */
            unsigned int op = (i.types[0] & (Reg | FloatReg)) ? 0 : 1;
            /* Register goes in low 3 bits of opcode. */
-           i.tm.base_opcode |= i.regs[op]->reg_num;
+           i.tm.base_opcode |= i.op[op].regs->reg_num;
            if ((i.tm.opcode_modifier & Ugh) != 0)
              {
                /* Warn about some common errors, but press on regardless.
@@ -1822,14 +1873,14 @@ md_assemble (line)
                  {
                    /* reversed arguments on faddp, fsubp, etc. */
                    as_warn (_("translating to `%s %%%s,%%%s'"), i.tm.name,
-                            i.regs[1]->reg_name,
-                            i.regs[0]->reg_name);
+                            i.op[1].regs->reg_name,
+                            i.op[0].regs->reg_name);
                  }
                else
                  {
                    /* extraneous `l' suffix on fp insn */
                    as_warn (_("translating to `%s %%%s'"), i.tm.name,
-                            i.regs[0]->reg_name);
+                            i.op[0].regs->reg_name);
                  }
              }
          }
@@ -1862,13 +1913,13 @@ md_assemble (line)
                   destination in the i.rm.reg field.  */
                if ((i.tm.operand_types[dest] & AnyMem) == 0)
                  {
-                   i.rm.reg = i.regs[dest]->reg_num;
-                   i.rm.regmem = i.regs[source]->reg_num;
+                   i.rm.reg = i.op[dest].regs->reg_num;
+                   i.rm.regmem = i.op[source].regs->reg_num;
                  }
                else
                  {
-                   i.rm.reg = i.regs[source]->reg_num;
-                   i.rm.regmem = i.regs[dest]->reg_num;
+                   i.rm.reg = i.op[source].regs->reg_num;
+                   i.rm.regmem = i.op[dest].regs->reg_num;
                  }
              }
            else
@@ -1991,8 +2042,9 @@ md_assemble (line)
                           holds the correct displacement size. */
                        expressionS *exp;
 
+                       assert (i.op[op].disps == 0);
                        exp = &disp_expressions[i.disp_operands++];
-                       i.disps[op] = exp;
+                       i.op[op].disps = exp;
                        exp->X_op = O_constant;
                        exp->X_add_number = 0;
                        exp->X_add_symbol = (symbolS *) 0;
@@ -2022,9 +2074,9 @@ md_assemble (line)
                    /* If there is an extension opcode to put here, the
                       register number must be put into the regmem field. */
                    if (i.tm.extension_opcode != None)
-                     i.rm.regmem = i.regs[op]->reg_num;
+                     i.rm.regmem = i.op[op].regs->reg_num;
                    else
-                     i.rm.reg = i.regs[op]->reg_num;
+                     i.rm.reg = i.op[op].regs->reg_num;
 
                    /* 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
@@ -2040,12 +2092,12 @@ md_assemble (line)
          }
        else if (i.tm.opcode_modifier & (Seg2ShortForm | Seg3ShortForm))
          {
-           if (i.tm.base_opcode == POP_SEG_SHORT && i.regs[0]->reg_num == 1)
+           if (i.tm.base_opcode == POP_SEG_SHORT && i.op[0].regs->reg_num == 1)
              {
                as_bad (_("you can't `pop %%cs'"));
                return;
              }
-           i.tm.base_opcode |= (i.regs[0]->reg_num << 3);
+           i.tm.base_opcode |= (i.op[0].regs->reg_num << 3);
          }
        else if ((i.tm.base_opcode & ~(D|W)) == MOV_AX_DISP32)
          {
@@ -2078,12 +2130,22 @@ md_assemble (line)
   }
 
   /* Handle conversion of 'int $3' --> special int3 insn. */
-  if (i.tm.base_opcode == INT_OPCODE && i.imms[0]->X_add_number == 3)
+  if (i.tm.base_opcode == INT_OPCODE && i.op[0].imms->X_add_number == 3)
     {
       i.tm.base_opcode = INT3_OPCODE;
       i.imm_operands = 0;
     }
 
+  if ((i.tm.opcode_modifier & (Jump | JumpByte | JumpDword))
+      && i.op[0].disps->X_op == O_constant)
+    {
+      /* Convert "jmp constant" (and "call constant") to a jump (call) to
+        the absolute address given by the constant.  Since ix86 jumps and
+        calls are pc relative, we need to generate a reloc.  */
+      i.op[0].disps->X_add_symbol = &abs_symbol;
+      i.op[0].disps->X_op = O_symbol;
+    }
+
   /* We are ready to output the insn. */
   {
     register char *p;
@@ -2091,96 +2153,60 @@ md_assemble (line)
     /* Output jumps. */
     if (i.tm.opcode_modifier & Jump)
       {
-       long n = (long) i.disps[0]->X_add_number;
-       int prefix = (i.prefix[DATA_PREFIX] != 0);
-       int code16 = 0;
+       int size;
+       int code16;
+       int prefix;
 
-       if (prefix)
+       code16 = 0;
+       if (flag_16bit_code)
+         code16 = CODE16;
+
+       prefix = 0;
+       if (i.prefix[DATA_PREFIX])
          {
+           prefix = 1;
            i.prefixes -= 1;
-           code16 = CODE16;
+           code16 ^= CODE16;
          }
-       if (flag_16bit_code)
-         code16 ^= CODE16;
 
-       if (!intel_syntax && (i.prefixes != 0))
-         as_warn (_("skipping prefixes on this instruction"));
+       size = 4;
+       if (code16)
+         size = 2;
 
-       if (i.disps[0]->X_op == O_constant)
-         {
-           if (fits_in_signed_byte (n))
-             {
-               insn_size += 2;
-               p = frag_more (2);
-               p[0] = i.tm.base_opcode;
-               p[1] = n;
-             }
-           else
-             {
-               /* Use 16-bit jumps only for 16-bit code,
-                  because text segments are limited to 64K anyway;
-                  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 = code16 ? 2 : 4;
-               if (code16 && !fits_in_signed_word (n))
-                 {
-                   as_bad (_("16-bit jump out of range"));
-                   return;
-                 }
+       if (i.prefixes != 0 && !intel_syntax)
+         as_warn (_("skipping prefixes on this instruction"));
 
-               if (i.tm.base_opcode == JUMP_PC_RELATIVE)
-                 {             /* pace */
-                   /* unconditional jump */
-                   insn_size += prefix + 1 + jmp_size;
-                   p = frag_more (prefix + 1 + jmp_size);
-                   if (prefix)
-                     *p++ = DATA_PREFIX_OPCODE;
-                   *p++ = (char) 0xe9;
-                   md_number_to_chars (p, (valueT) n, jmp_size);
-                 }
-               else
-                 {
-                   /* conditional jump */
-                   insn_size += prefix + 2 + jmp_size;
-                   p = frag_more (prefix + 2 + jmp_size);
-                   if (prefix)
-                     *p++ = DATA_PREFIX_OPCODE;
-                   *p++ = TWO_BYTE_OPCODE_ESCAPE;
-                   *p++ = i.tm.base_opcode + 0x10;
-                   md_number_to_chars (p, (valueT) n, jmp_size);
-                 }
-             }
-         }
-       else
-         {
-           int size = code16 ? 2 : 4;
-
-           /* It's a symbol; end frag & setup for relax.
-              Make sure there are more than 6 chars left in the current frag;
-              if not we'll have to start a new one. */
-           frag_grow (prefix + 1 + 2 + size);
-           insn_size += 1 + prefix;
-           p = frag_more (1 + prefix);
-           if (prefix)
-             *p++ = DATA_PREFIX_OPCODE;
-           *p = i.tm.base_opcode;
-           frag_var (rs_machine_dependent,
-                     prefix + 2 + size, /* 2 opcode/prefix + displacement */
-                     1,
-                     ((unsigned char) *p == JUMP_PC_RELATIVE
-                      ? ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL) | code16
-                      : ENCODE_RELAX_STATE (COND_JUMP, SMALL) | code16),
-                     i.disps[0]->X_add_symbol,
-                     (offsetT) n, p);
-         }
+       /* It's always a symbol;  End frag & setup for relax.
+          Make sure there is enough room in this frag for the largest
+          instruction we may generate in md_convert_frag.  This is 2
+          bytes for the opcode and room for the prefix and largest
+          displacement.  */
+       frag_grow (prefix + 2 + size);
+       insn_size += prefix + 1;
+       /* Prefix and 1 opcode byte go in fr_fix.  */
+       p = frag_more (prefix + 1);
+       if (prefix)
+         *p++ = DATA_PREFIX_OPCODE;
+       *p = i.tm.base_opcode;
+       /* 1 possible extra opcode + displacement go in fr_var.  */
+       frag_var (rs_machine_dependent,
+                 1 + size,
+                 1,
+                 ((unsigned char) *p == JUMP_PC_RELATIVE
+                  ? ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL) | code16
+                  : ENCODE_RELAX_STATE (COND_JUMP, SMALL) | code16),
+                 i.op[0].disps->X_add_symbol,
+                 i.op[0].disps->X_add_number,
+                 p);
       }
     else if (i.tm.opcode_modifier & (JumpByte | JumpDword))
       {
-       int size = (i.tm.opcode_modifier & JumpByte) ? 1 : 4;
-       long n = (long) i.disps[0]->X_add_number;
+       int size;
 
-       if (size == 1) /* then this is a loop or jecxz type instruction */
+       if (i.tm.opcode_modifier & JumpByte)
          {
+           /* This is a loop or jecxz type instruction.  */
+           size = 1;
            if (i.prefix[ADDR_PREFIX])
              {
                insn_size += 1;
@@ -2190,23 +2216,26 @@ md_assemble (line)
          }
        else
          {
-           int code16 = 0;
+           int code16;
+
+           code16 = 0;
+           if (flag_16bit_code)
+             code16 = CODE16;
 
            if (i.prefix[DATA_PREFIX])
              {
                insn_size += 1;
                FRAG_APPEND_1_CHAR (DATA_PREFIX_OPCODE);
                i.prefixes -= 1;
-               code16 = CODE16;
+               code16 ^= CODE16;
              }
-           if (flag_16bit_code)
-             code16 ^= CODE16;
 
+           size = 4;
            if (code16)
              size = 2;
          }
 
-       if (!intel_syntax && (i.prefixes != 0))
+       if (i.prefixes != 0 && !intel_syntax)
          as_warn (_("skipping prefixes on this instruction"));
 
        if (fits_in_unsigned_byte (i.tm.base_opcode))
@@ -2216,57 +2245,39 @@ md_assemble (line)
          }
        else
          {
-           insn_size += 2 + size;      /* opcode can be at most two bytes */
+           /* opcode can be at most two bytes */
+           insn_size += 2 + size;
            p = frag_more (2 + size);
            *p++ = (i.tm.base_opcode >> 8) & 0xff;
          }
        *p++ = i.tm.base_opcode & 0xff;
 
-       if (i.disps[0]->X_op == O_constant)
-         {
-           if (size == 1 && !fits_in_signed_byte (n))
-             {
-               as_bad (_("`%s' only takes byte displacement; %ld shortened to %d"),
-                       i.tm.name, n, *p);
-             }
-           else if (size == 2 && !fits_in_signed_word (n))
-             {
-               as_bad (_("16-bit jump out of range"));
-               return;
-             }
-           md_number_to_chars (p, (valueT) n, size);
-         }
-       else
-         {
-           fix_new_exp (frag_now, p - frag_now->fr_literal, size,
-                        i.disps[0], 1, reloc (size, 1, i.disp_reloc[0]));
-
-         }
+       fix_new_exp (frag_now, p - frag_now->fr_literal, size,
+                    i.op[0].disps, 1, reloc (size, 1, i.disp_reloc[0]));
       }
     else if (i.tm.opcode_modifier & JumpInterSegment)
       {
        int size;
-       int reloc_type;
-       int prefix = i.prefix[DATA_PREFIX] != 0;
-       int code16 = 0;
+       int prefix;
+       int code16;
 
-       if (prefix)
+       code16 = 0;
+       if (flag_16bit_code)
+         code16 = CODE16;
+
+       prefix = 0;
+       if (i.prefix[DATA_PREFIX])
          {
-           code16 = CODE16;
+           prefix = 1;
            i.prefixes -= 1;
+           code16 ^= CODE16;
          }
-       if (flag_16bit_code)
-         code16 ^= CODE16;
 
        size = 4;
-       reloc_type = BFD_RELOC_32;
        if (code16)
-         {
-           size = 2;
-           reloc_type = BFD_RELOC_16;
-         }
+         size = 2;
 
-       if (!intel_syntax && (i.prefixes != 0))
+       if (i.prefixes != 0 && !intel_syntax)
          as_warn (_("skipping prefixes on this instruction"));
 
        insn_size += prefix + 1 + 2 + size;  /* 1 opcode; 2 segment; offset */
@@ -2274,24 +2285,26 @@ md_assemble (line)
        if (prefix)
          *p++ = DATA_PREFIX_OPCODE;
        *p++ = i.tm.base_opcode;
-       if (i.imms[1]->X_op == O_constant)
+       if (i.op[1].imms->X_op == O_constant)
          {
-           long n = (long) i.imms[1]->X_add_number;
+           offsetT n = i.op[1].imms->X_add_number;
 
-           if (size == 2 && !fits_in_unsigned_word (n))
+           if (size == 2
+               && !fits_in_unsigned_word (n)
+               && !fits_in_signed_word (n))
              {
                as_bad (_("16-bit jump out of range"));
                return;
              }
-           md_number_to_chars (p, (valueT) n, size);
+           md_number_to_chars (p, n, size);
          }
        else
          fix_new_exp (frag_now, p - frag_now->fr_literal, size,
-                      i.imms[1], 0, reloc_type);
-       if (i.imms[0]->X_op != O_constant)
+                      i.op[1].imms, 0, reloc (size, 0, i.disp_reloc[0]));
+       if (i.op[0].imms->X_op != O_constant)
          as_bad (_("can't handle non absolute segment in `%s'"),
                  i.tm.name);
-       md_number_to_chars (p + size, (valueT) i.imms[0]->X_add_number, 2);
+       md_number_to_chars (p + size, (valueT) i.op[0].imms->X_add_number, 2);
       }
     else
       {
@@ -2377,48 +2390,38 @@ md_assemble (line)
 
            for (n = 0; n < i.operands; n++)
              {
-               if (i.disps[n])
+               if (i.types[n] & Disp)
                  {
-                   if (i.disps[n]->X_op == O_constant)
+                   if (i.op[n].disps->X_op == O_constant)
                      {
-                       int size = 4;
-                       long val = (long) i.disps[n]->X_add_number;
+                       int size;
+                       offsetT val;
 
+                       size = 4;
                        if (i.types[n] & (Disp8 | Disp16))
                          {
-                           long mask;
-
                            size = 2;
-                           mask = ~ (long) 0xffff;
                            if (i.types[n] & Disp8)
-                             {
-                               size = 1;
-                               mask = ~ (long) 0xff;
-                             }
-
-                           if ((val & mask) != 0 && (val & mask) != mask)
-                             as_warn (_("%ld shortened to %ld"),
-                                      val, val & ~mask);
+                             size = 1;
                          }
+                       val = offset_in_range (i.op[n].disps->X_add_number,
+                                              size);
                        insn_size += size;
                        p = frag_more (size);
-                       md_number_to_chars (p, (valueT) val, size);
-                     }
-                   else if (i.types[n] & Disp32)
-                     {
-                       insn_size += 4;
-                       p = frag_more (4);
-                       fix_new_exp (frag_now, p - frag_now->fr_literal, 4,
-                                    i.disps[n], 0,
-                                    TC_RELOC (i.disp_reloc[n], BFD_RELOC_32));
+                       md_number_to_chars (p, val, size);
                      }
                    else
-                     { /* must be Disp16 */
-                       insn_size += 2;
-                       p = frag_more (2);
-                       fix_new_exp (frag_now, p - frag_now->fr_literal, 2,
-                                    i.disps[n], 0,
-                                    TC_RELOC (i.disp_reloc[n], BFD_RELOC_16));
+                     {
+                       int size = 4;
+
+                       if (i.types[n] & Disp16)
+                         size = 2;
+
+                       insn_size += size;
+                       p = frag_more (size);
+                       fix_new_exp (frag_now, p - frag_now->fr_literal, size,
+                                    i.op[n].disps, 0,
+                                    reloc (size, 0, i.disp_reloc[n]));
                      }
                  }
              }
@@ -2431,66 +2434,62 @@ md_assemble (line)
 
            for (n = 0; n < i.operands; n++)
              {
-               if (i.imms[n])
+               if (i.types[n] & Imm)
                  {
-                   if (i.imms[n]->X_op == O_constant)
+                   if (i.op[n].imms->X_op == O_constant)
                      {
-                       int size = 4;
-                       long val = (long) i.imms[n]->X_add_number;
+                       int size;
+                       offsetT val;
 
+                       size = 4;
                        if (i.types[n] & (Imm8 | Imm8S | Imm16))
                          {
-                           long mask;
-
                            size = 2;
-                           mask = ~ (long) 0xffff;
                            if (i.types[n] & (Imm8 | Imm8S))
-                             {
-                               size = 1;
-                               mask = ~ (long) 0xff;
-                             }
-                           if ((val & mask) != 0 && (val & mask) != mask)
-                             as_warn (_("%ld shortened to %ld"),
-                                      val, val & ~mask);
+                             size = 1;
                          }
+                       val = offset_in_range (i.op[n].imms->X_add_number,
+                                              size);
                        insn_size += size;
                        p = frag_more (size);
-                       md_number_to_chars (p, (valueT) val, size);
+                       md_number_to_chars (p, val, size);
                      }
                    else
                      {         /* not absolute_section */
                        /* Need a 32-bit fixup (don't support 8bit
-                          non-absolute ims).  Try to support other
+                          non-absolute imms).  Try to support other
                           sizes ... */
-                       int r_type;
-                       int size;
-                       int pcrel = 0;
+#ifdef BFD_ASSEMBLER
+                       enum bfd_reloc_code_real reloc_type;
+#else
+                       int reloc_type;
+#endif
+                       int size = 4;
 
-                       if (i.types[n] & (Imm8 | Imm8S))
-                         size = 1;
-                       else if (i.types[n] & Imm16)
+                       if (i.types[n] & Imm16)
                          size = 2;
-                       else
-                         size = 4;
+                       else if (i.types[n] & (Imm8 | Imm8S))
+                         size = 1;
+
                        insn_size += size;
                        p = frag_more (size);
-                       r_type = reloc (size, 0, i.disp_reloc[0]);
+                       reloc_type = reloc (size, 0, i.disp_reloc[0]);
 #ifdef BFD_ASSEMBLER
-                       if (r_type == BFD_RELOC_32
+                       if (reloc_type == BFD_RELOC_32
                            && GOT_symbol
-                           && GOT_symbol == i.imms[n]->X_add_symbol
-                           && (i.imms[n]->X_op == O_symbol
-                               || (i.imms[n]->X_op == O_add
+                           && GOT_symbol == i.op[n].imms->X_add_symbol
+                           && (i.op[n].imms->X_op == O_symbol
+                               || (i.op[n].imms->X_op == O_add
                                    && ((symbol_get_value_expression
-                                        (i.imms[n]->X_op_symbol)->X_op)
+                                        (i.op[n].imms->X_op_symbol)->X_op)
                                        == O_subtract))))
                          {
-                           r_type = BFD_RELOC_386_GOTPC;
-                           i.imms[n]->X_add_number += 3;
+                           reloc_type = BFD_RELOC_386_GOTPC;
+                           i.op[n].imms->X_add_number += 3;
                          }
 #endif
                        fix_new_exp (frag_now, p - frag_now->fr_literal, size,
-                                    i.imms[n], pcrel, r_type);
+                                    i.op[n].imms, 0, reloc_type);
                      }
                  }
              }
@@ -2518,12 +2517,12 @@ i386_immediate (imm_start)
 
   if (i.imm_operands == MAX_IMMEDIATE_OPERANDS)
     {
-      as_bad (_("Only 1 or 2 immediate operands are allowed"));
+      as_bad (_("only 1 or 2 immediate operands are allowed"));
       return 0;
     }
 
   exp = &im_expressions[i.imm_operands++];
-  i.imms[this_operand] = exp;
+  i.op[this_operand].imms = exp;
 
   if (is_space_char (*imm_start))
     ++imm_start;
@@ -2571,7 +2570,7 @@ i386_immediate (imm_start)
            len = 3;
          }
        else
-         as_bad (_("Bad reloc specifier in expression"));
+         as_bad (_("bad reloc specifier in expression"));
 
        /* Replace the relocation token with ' ', so that errors like
           foo@GOTOFF1 will be detected.  */
@@ -2589,43 +2588,31 @@ i386_immediate (imm_start)
 
   SKIP_WHITESPACE ();
   if (*input_line_pointer)
-    as_bad (_("Ignoring junk `%s' after expression"), input_line_pointer);
+    as_bad (_("ignoring junk `%s' after expression"), input_line_pointer);
 
   input_line_pointer = save_input_line_pointer;
 
-  if (exp->X_op == O_absent)
+  if (exp->X_op == O_absent || exp->X_op == O_big)
     {
       /* 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"),
              imm_start);
       exp->X_op = O_constant;
       exp->X_add_number = 0;
       exp->X_add_symbol = (symbolS *) 0;
       exp->X_op_symbol = (symbolS *) 0;
-      i.types[this_operand] |= Imm;
     }
-  else if (exp->X_op == O_constant)
-    {
-      int bigimm = Imm32;
-      if (flag_16bit_code ^ (i.prefix[DATA_PREFIX] != 0))
-       bigimm = Imm16;
 
-      i.types[this_operand] |=
-       (bigimm | smallest_imm_type ((long) exp->X_add_number));
-
-      /* If a suffix is given, this operand may be shortended. */
-      switch (i.suffix)
-       {
-       case WORD_MNEM_SUFFIX:
-         i.types[this_operand] |= Imm16;
-         break;
-       case BYTE_MNEM_SUFFIX:
-         i.types[this_operand] |= Imm16 | Imm8 | Imm8S;
-         break;
-       }
+  if (exp->X_op == O_constant)
+    {
+      i.types[this_operand] |= Imm32;  /* Size it properly later.  */
     }
-#ifdef OBJ_AOUT
-  else if (exp_seg != text_section
+#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
+  else if (
+#ifdef BFD_ASSEMBLER
+          OUTPUT_FLAVOR == bfd_target_aout_flavour &&
+#endif
+          exp_seg != text_section
           && exp_seg != data_section
           && exp_seg != bss_section
           && exp_seg != undefined_section
@@ -2634,7 +2621,11 @@ i386_immediate (imm_start)
 #endif
           )
     {
-      as_bad (_("Unimplemented segment type %d in operand"), exp_seg);
+#ifdef BFD_ASSEMBLER
+      as_bad (_("unimplemented segment %s in operand"), exp_seg->name);
+#else
+      as_bad (_("unimplemented segment type %d in operand"), exp_seg);
+#endif
       return 0;
     }
 #endif
@@ -2709,8 +2700,7 @@ i386_displacement (disp_start, disp_end)
   i.types[this_operand] |= bigdisp;
 
   exp = &disp_expressions[i.disp_operands];
-  i.disps[this_operand] = exp;
-  i.disp_reloc[this_operand] = NO_RELOC;
+  i.op[this_operand].disps = exp;
   i.disp_operands++;
   save_input_line_pointer = input_line_pointer;
   input_line_pointer = disp_start;
@@ -2801,7 +2791,7 @@ i386_displacement (disp_start, disp_end)
            len = 3;
          }
        else
-         as_bad (_("Bad reloc specifier in expression"));
+         as_bad (_("bad reloc specifier in expression"));
 
        /* Replace the relocation token with ' ', so that errors like
           foo@GOTOFF1 will be detected.  */
@@ -2835,7 +2825,7 @@ i386_displacement (disp_start, disp_end)
 
   SKIP_WHITESPACE ();
   if (*input_line_pointer)
-    as_bad (_("Ignoring junk `%s' after expression"),
+    as_bad (_("ignoring junk `%s' after expression"),
            input_line_pointer);
 #if GCC_ASM_O_HACK
   RESTORE_END_STRING (disp_end + 1);
@@ -2843,18 +2833,45 @@ i386_displacement (disp_start, disp_end)
   RESTORE_END_STRING (disp_end);
   input_line_pointer = save_input_line_pointer;
 
+  if (exp->X_op == O_absent || exp->X_op == O_big)
+    {
+      /* missing or bad expr becomes absolute 0 */
+      as_bad (_("missing or invalid displacement expression `%s' taken as 0"),
+             disp_start);
+      exp->X_op = O_constant;
+      exp->X_add_number = 0;
+      exp->X_add_symbol = (symbolS *) 0;
+      exp->X_op_symbol = (symbolS *) 0;
+    }
+
   if (exp->X_op == O_constant)
     {
+      if (i.types[this_operand] & Disp16)
+       {
+         /* We know this operand is at most 16 bits, so convert to a
+            signed 16 bit number before trying to see whether it will
+            fit in an even smaller size.  */
+         exp->X_add_number =
+           (((exp->X_add_number & 0xffff) ^ 0x8000) - 0x8000);
+       }
       if (fits_in_signed_byte (exp->X_add_number))
        i.types[this_operand] |= Disp8;
     }
-#ifdef OBJ_AOUT
-  else if (exp_seg != text_section
+#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
+  else if (
+#ifdef BFD_ASSEMBLER
+          OUTPUT_FLAVOR == bfd_target_aout_flavour &&
+#endif
+          exp_seg != text_section
           && exp_seg != data_section
           && exp_seg != bss_section
           && exp_seg != undefined_section)
     {
-      as_bad (_ ("Unimplemented segment type %d in operand"), exp_seg);
+#ifdef BFD_ASSEMBLER
+      as_bad (_("unimplemented segment %s in operand"), exp_seg->name);
+#else
+      as_bad (_("unimplemented segment type %d in operand"), exp_seg);
+#endif
       return 0;
     }
 #endif
@@ -2877,24 +2894,27 @@ i386_operand_modifier (op_string, got_a_float)
     }
   else if (!strncasecmp (*op_string, "WORD PTR", 8))
     {
-      i.suffix = WORD_MNEM_SUFFIX;
+      if (got_a_float == 2)    /* "fi..." */
+       i.suffix = SHORT_MNEM_SUFFIX;
+      else
+       i.suffix = WORD_MNEM_SUFFIX;
       *op_string += 8;
       return WORD_PTR;
     }
 
   else if (!strncasecmp (*op_string, "DWORD PTR", 9))
     {
-      if (got_a_float)
+      if (got_a_float == 1)    /* "f..." */
        i.suffix = SHORT_MNEM_SUFFIX;
       else
-       i.suffix = DWORD_MNEM_SUFFIX;
+       i.suffix = LONG_MNEM_SUFFIX;
       *op_string += 9;
       return DWORD_PTR;
     }
 
   else if (!strncasecmp (*op_string, "QWORD PTR", 9))
     {
-      i.suffix = INTEL_DWORD_MNEM_SUFFIX;
+      i.suffix = DWORD_MNEM_SUFFIX;
       *op_string += 9;
       return QWORD_PTR;
     }
@@ -2941,10 +2961,10 @@ build_displacement_string (initial_disp, op_string)
 
   temp_string[0] = '\0';
   tc = end_of_operand_string = strchr (op_string, '[');
-  if ( initial_disp && !end_of_operand_string)
+  if (initial_disp && !end_of_operand_string)
     {
       strcpy (temp_string, op_string);
-      return (temp_string);
+      return temp_string;
     }
 
   /* Build the whole displacement string */
@@ -3067,24 +3087,24 @@ i386_index_check (operand_string)
 
  tryprefix:
 #endif
-  if (flag_16bit_code ^ (i.prefix[ADDR_PREFIX] != 0) ?
+  if (flag_16bit_code ^ (i.prefix[ADDR_PREFIX] != 0)
       /* 16 bit mode checks */
-      ((i.base_reg
-       && ((i.base_reg->reg_type & (Reg16|BaseIndex))
-           != (Reg16|BaseIndex)))
-       || (i.index_reg
-          && (((i.index_reg->reg_type & (Reg16|BaseIndex))
-               != (Reg16|BaseIndex))
-              || ! (i.base_reg
-                    && i.base_reg->reg_num < 6
-                    && i.index_reg->reg_num >= 6
-                    && i.log2_scale_factor == 0)))) :
+      ((i.base_reg
+         && ((i.base_reg->reg_type & (Reg16|BaseIndex))
+             != (Reg16|BaseIndex)))
+        || (i.index_reg
+            && (((i.index_reg->reg_type & (Reg16|BaseIndex))
+                 != (Reg16|BaseIndex))
+                || ! (i.base_reg
+                      && i.base_reg->reg_num < 6
+                      && i.index_reg->reg_num >= 6
+                      && i.log2_scale_factor == 0))))
       /* 32 bit mode checks */
-      ((i.base_reg
-       && (i.base_reg->reg_type & Reg32) == 0)
-       || (i.index_reg
-          && ((i.index_reg->reg_type & (Reg32|BaseIndex))
-              != (Reg32|BaseIndex)))))
+      ((i.base_reg
+         && (i.base_reg->reg_type & Reg32) == 0)
+        || (i.index_reg
+            && ((i.index_reg->reg_type & (Reg32|BaseIndex))
+                != (Reg32|BaseIndex)))))
     {
 #if INFER_ADDR_PREFIX
       if (i.prefix[ADDR_PREFIX] == 0 && stackop_size != '\0')
@@ -3102,11 +3122,11 @@ i386_index_check (operand_string)
          fudged = 1;
          goto tryprefix;
        }
-#endif
       if (fudged)
        as_bad (_("`%s' is not a valid base/index expression"),
                operand_string);
       else
+#endif
        as_bad (_("`%s' is not a valid %s bit base/index expression"),
                operand_string,
                flag_16bit_code ^ (i.prefix[ADDR_PREFIX] != 0) ? "16" : "32");
@@ -3133,11 +3153,10 @@ i386_intel_memory_operand (operand_string)
       return 0;
     }
 
-  /* Look for displacement preceding open bracket */
+  /* First check for a segment override.  */
   if (*op_string != '[')
     {
       char *end_seg;
-      char *temp_string;
 
       end_seg = strchr (op_string, ':');
       if (end_seg)
@@ -3146,13 +3165,25 @@ i386_intel_memory_operand (operand_string)
            return 0;
          op_string = end_seg + 1;
        }
+    }
 
-      temp_string = build_displacement_string (true, op_string);
+  /* Look for displacement preceding open bracket */
+  if (*op_string != '[')
+    {
+      char *temp_string;
 
-      if (i.disp_operands == 0 &&
-         !i386_displacement (temp_string, temp_string + strlen (temp_string)))
+      if (i.disp_operands)
        return 0;
 
+      temp_string = build_displacement_string (true, op_string);
+
+      if (!i386_displacement (temp_string, temp_string + strlen (temp_string)))
+       {
+         free (temp_string);
+         return 0;
+       }
+      free (temp_string);
+
       end_of_operand_string = strchr (op_string, '[');
       if (!end_of_operand_string)
        end_of_operand_string = op_string + strlen (op_string);
@@ -3209,14 +3240,23 @@ i386_intel_memory_operand (operand_string)
          else if (is_digit_char (*op_string)
                   || *op_string == '+' || *op_string == '-')
            {
+             char *temp_str;
+
+             if (i.disp_operands != 0)
+               return 0;
+
              temp_string = build_displacement_string (false, op_string);
 
-             if (*temp_string == '+')
-               ++temp_string;
+             temp_str = temp_string;
+             if (*temp_str == '+')
+               ++temp_str;
 
-             if (i.disp_operands == 0 &&
-                 !i386_displacement (temp_string, temp_string + strlen (temp_string)))
-               return 0;
+             if (!i386_displacement (temp_str, temp_str + strlen (temp_str)))
+               {
+                 free (temp_string);
+                 return 0;
+               }
+             free (temp_string);
 
              ++op_string;
              end_of_operand_string = op_string;
@@ -3324,7 +3364,7 @@ i386_intel_operand (operand_string, got_a_float)
 
            }
          i.types[this_operand] |= r->reg_type & ~BaseIndex;
-         i.regs[this_operand] = r;
+         i.op[this_operand].regs = r;
          i.reg_operands++;
        }
       else if (*op_string == REGISTER_PREFIX)
@@ -3423,11 +3463,11 @@ i386_operand (operand_string)
        }
       if (*op_string)
        {
-         as_bad (_("Junk `%s' after register"), op_string);
+         as_bad (_("junk `%s' after register"), op_string);
          return 0;
        }
       i.types[this_operand] |= r->reg_type & ~BaseIndex;
-      i.regs[this_operand] = r;
+      i.op[this_operand].regs = r;
       i.reg_operands++;
     }
   else if (*op_string == REGISTER_PREFIX)
@@ -3440,7 +3480,7 @@ i386_operand (operand_string)
       ++op_string;
       if (i.types[this_operand] & JumpAbsolute)
        {
-         as_bad (_("Immediate operand illegal with absolute jump"));
+         as_bad (_("immediate operand illegal with absolute jump"));
          return 0;
        }
       if (!i386_immediate (op_string))
@@ -3654,7 +3694,24 @@ md_estimate_size_before_relax (fragP, segment)
       /* symbol is undefined in this segment */
       int code16 = fragP->fr_subtype & CODE16;
       int size = code16 ? 2 : 4;
-      int pcrel_reloc = code16 ? BFD_RELOC_16_PCREL : BFD_RELOC_32_PCREL;
+#ifdef BFD_ASSEMBLER
+      enum bfd_reloc_code_real reloc_type;
+#else
+      int reloc_type;
+#endif
+
+      if (GOT_symbol /* Not quite right - we should switch on presence of
+                       @PLT, but I cannot see how to get to that from
+                       here.  We should have done this in md_assemble to
+                       really get it right all of the time, but I think it
+                       does not matter that much, as this will be right
+                       most of the time. ERY  */
+         && S_GET_SEGMENT(fragP->fr_symbol) == undefined_section)
+       reloc_type = BFD_RELOC_386_PLT32;
+      else if (code16)
+       reloc_type = BFD_RELOC_16_PCREL;
+      else
+       reloc_type = BFD_RELOC_32_PCREL;
 
       switch (opcode[0])
        {
@@ -3664,31 +3721,19 @@ md_estimate_size_before_relax (fragP, segment)
          fix_new (fragP, old_fr_fix, size,
                   fragP->fr_symbol,
                   fragP->fr_offset, 1,
-                  (GOT_symbol && /* Not quite right - we should switch on
-                                    presence of @PLT, but I cannot see how
-                                    to get to that from here.  We should have
-                                    done this in md_assemble to really
-                                    get it right all of the time, but I
-                                    think it does not matter that much, as
-                                    this will be right most of the time. ERY*/
-                   S_GET_SEGMENT(fragP->fr_symbol) == undefined_section)
-                  ? BFD_RELOC_386_PLT32 : pcrel_reloc);
+                  reloc_type);
          break;
 
        default:
          /* This changes the byte-displacement jump 0x7N
-            to the dword-displacement jump 0x0f8N.  */
+            to the dword-displacement jump 0x0f,0x8N.  */
          opcode[1] = opcode[0] + 0x10;
-         opcode[0] = TWO_BYTE_OPCODE_ESCAPE;   /* two-byte escape */
+         opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
          fragP->fr_fix += 1 + size;    /* we've added an opcode byte */
          fix_new (fragP, old_fr_fix + 1, size,
                   fragP->fr_symbol,
                   fragP->fr_offset, 1,
-                  (GOT_symbol &&  /* Not quite right - we should switch on
-                                     presence of @PLT, but I cannot see how
-                                     to get to that from here.  ERY */
-                   S_GET_SEGMENT(fragP->fr_symbol) == undefined_section)
-                  ? BFD_RELOC_386_PLT32 : pcrel_reloc);
+                  reloc_type);
          break;
        }
       frag_wane (fragP);
@@ -3723,10 +3768,10 @@ md_convert_frag (abfd, sec, fragP)
 {
   register unsigned char *opcode;
   unsigned char *where_to_put_displacement = NULL;
-  unsigned int target_address;
-  unsigned int opcode_address;
+  offsetT target_address;
+  offsetT opcode_address;
   unsigned int extension = 0;
-  int displacement_from_opcode_start;
+  offsetT displacement_from_opcode_start;
 
   opcode = (unsigned char *) fragP->fr_opcode;
 
@@ -3802,7 +3847,7 @@ md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
      fragS *frag ATTRIBUTE_UNUSED;
      symbolS *to_symbol ATTRIBUTE_UNUSED;
 {
-  long offset;
+  offsetT offset;
 
   offset = to_addr - (from_addr + 2);
   md_number_to_chars (ptr, (valueT) 0xeb, 1);  /* opcode for byte-disp jump */
@@ -3816,7 +3861,7 @@ md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
      fragS *frag;
      symbolS *to_symbol;
 {
-  long offset;
+  offsetT offset;
 
   if (flag_do_long_jump)
     {
@@ -3888,19 +3933,24 @@ md_apply_fix3 (fixP, valp, seg)
        value += fixP->fx_where + fixP->fx_frag->fr_address;
 #endif
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
-      if (OUTPUT_FLAVOR == bfd_target_elf_flavour
-         && (S_GET_SEGMENT (fixP->fx_addsy) == seg
-             || symbol_section_p (fixP->fx_addsy))
-         && ! S_IS_EXTERNAL (fixP->fx_addsy)
-         && ! S_IS_WEAK (fixP->fx_addsy)
-         && S_IS_DEFINED (fixP->fx_addsy)
-         && ! S_IS_COMMON (fixP->fx_addsy))
+      if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
        {
-         /* Yes, we add the values in twice.  This is because
-            bfd_perform_relocation subtracts them out again.  I think
-            bfd_perform_relocation is broken, but I don't dare change
-            it.  FIXME.  */
-         value += fixP->fx_where + fixP->fx_frag->fr_address;
+         segT fseg = S_GET_SEGMENT (fixP->fx_addsy);
+
+         if ((fseg == seg
+              || (symbol_section_p (fixP->fx_addsy)
+                  && fseg != absolute_section))
+             && ! 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
+                bfd_perform_relocation is broken, but I don't dare change
+                it.  FIXME.  */
+             value += fixP->fx_where + fixP->fx_frag->fr_address;
+           }
        }
 #endif
 #if defined (OBJ_COFF) && defined (TE_PE)
@@ -3946,7 +3996,7 @@ md_apply_fix3 (fixP, valp, seg)
     case BFD_RELOC_386_PLT32:
       /* Make the jump instruction point to the address of the operand.  At
         runtime we merely add the offset to the actual PLT entry. */
-      value = 0xfffffffc;
+      value = -4;
       break;
     case BFD_RELOC_386_GOTPC:
 /*
@@ -4010,23 +4060,6 @@ md_apply_fix3 (fixP, valp, seg)
 
   return 1;
 }
-
-#if 0
-/* This is never used.  */
-long                           /* Knows about the byte order in a word. */
-md_chars_to_number (con, nbytes)
-     unsigned char con[];      /* Low order byte 1st. */
-     int nbytes;               /* Number of bytes in the input. */
-{
-  long retval;
-  for (retval = 0, con += nbytes - 1; nbytes--; con--)
-    {
-      retval <<= BITS_PER_CHAR;
-      retval |= *con;
-    }
-  return retval;
-}
-#endif /* 0 */
 \f
 
 #define MAX_LITTLENUMS 6
@@ -4083,8 +4116,6 @@ md_atof (type, litP, sizeP)
 \f
 char output_invalid_buf[8];
 
-static char * output_invalid PARAMS ((int));
-
 static char *
 output_invalid (c)
      int c;
@@ -4158,8 +4189,8 @@ parse_register (reg_string, end_op)
   return r;
 }
 \f
-#ifdef OBJ_ELF
-CONST char *md_shortopts = "kmVQ:";
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+CONST char *md_shortopts = "kmVQ:sq";
 #else
 CONST char *md_shortopts = "m";
 #endif
@@ -4193,6 +4224,16 @@ md_parse_option (c, arg)
         should be emitted or not.  FIXME: Not implemented.  */
     case 'Q':
       break;
+
+    case 's':
+      /* -s: On i386 Solaris, this tells the native assembler to use
+         .stab instead of .stab.excl.  We always use .stab anyhow.  */
+      break;
+
+    case 'q':
+      /* -q: On i386 Solaris, this tells the native assembler does
+         fewer checks.  */
+      break;
 #endif
 
     default:
@@ -4206,12 +4247,21 @@ md_show_usage (stream)
      FILE *stream;
 {
   fprintf (stream, _("\
--m                     do long jump\n"));
+  -m                     do long jump\n"));
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+  fprintf (stream, _("\
+  -V                     print assembler version number\n\
+  -k                     ignored\n\
+  -Qy, -Qn               ignored\n\
+  -q                     ignored\n\
+  -s                     ignored\n"));
+#endif
 }
 
 #ifdef BFD_ASSEMBLER
-#ifdef OBJ_MAYBE_ELF
-#ifdef OBJ_MAYBE_COFF
+#if ((defined (OBJ_MAYBE_ELF) && defined (OBJ_MAYBE_COFF)) \
+     || (defined (OBJ_MAYBE_ELF) && defined (OBJ_MAYBE_AOUT)) \
+     || (defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT)))
 
 /* Pick the target format to use.  */
 
@@ -4220,21 +4270,27 @@ i386_target_format ()
 {
   switch (OUTPUT_FLAVOR)
     {
+#ifdef OBJ_MAYBE_AOUT
+    case bfd_target_aout_flavour:
+     return AOUT_TARGET_FORMAT;
+#endif
+#ifdef OBJ_MAYBE_COFF
     case bfd_target_coff_flavour:
       return "coff-i386";
+#endif
+#ifdef OBJ_MAYBE_ELF
     case bfd_target_elf_flavour:
       return "elf32-i386";
+#endif
     default:
       abort ();
       return NULL;
     }
 }
 
-#endif /* OBJ_MAYBE_COFF */
-#endif /* OBJ_MAYBE_ELF */
+#endif /* OBJ_MAYBE_ more than one */
 #endif /* BFD_ASSEMBLER */
 \f
-/* ARGSUSED */
 symbolS *
 md_undefined_symbol (name)
      char *name;
@@ -4262,17 +4318,20 @@ md_section_align (segment, size)
      segT segment ATTRIBUTE_UNUSED;
      valueT size;
 {
-#ifdef OBJ_AOUT
 #ifdef BFD_ASSEMBLER
-  /* For a.out, force the section size to be aligned.  If we don't do
-     this, BFD will align it for us, but it will not write out the
-     final bytes of the section.  This may be a bug in BFD, but it is
-     easier to fix it here since that is how the other a.out targets
-     work.  */
-  int align;
-
-  align = bfd_get_section_alignment (stdoutput, segment);
-  size = ((size + (1 << align) - 1) & ((valueT) -1 << align));
+#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
+  if (OUTPUT_FLAVOR == bfd_target_aout_flavour)
+    {
+      /* For a.out, force the section size to be aligned.  If we don't do
+        this, BFD will align it for us, but it will not write out the
+        final bytes of the section.  This may be a bug in BFD, but it is
+        easier to fix it here since that is how the other a.out targets
+        work.  */
+      int align;
+
+      align = bfd_get_section_alignment (stdoutput, segment);
+      size = ((size + (1 << align) - 1) & ((valueT) -1 << align));
+    }
 #endif
 #endif
 
@@ -4344,7 +4403,7 @@ tc_gen_reloc (section, fixp)
          switch (fixp->fx_size)
            {
            default:
-             as_bad (_("Can not do %d byte pc-relative relocation"),
+             as_bad (_("can not do %d byte pc-relative relocation"),
                      fixp->fx_size);
              code = BFD_RELOC_32_PCREL;
              break;
@@ -4358,7 +4417,7 @@ tc_gen_reloc (section, fixp)
          switch (fixp->fx_size)
            {
            default:
-             as_bad (_("Can not do %d byte relocation"), fixp->fx_size);
+             as_bad (_("can not do %d byte relocation"), fixp->fx_size);
              code = BFD_RELOC_32;
              break;
            case 1: code = BFD_RELOC_8;  break;
@@ -4393,7 +4452,7 @@ tc_gen_reloc (section, fixp)
   if (rel->howto == NULL)
     {
       as_bad_where (fixp->fx_file, fixp->fx_line,
-                   _("Cannot represent relocation type %s"),
+                   _("cannot represent relocation type %s"),
                    bfd_get_reloc_code_name (code));
       /* Set howto to a garbage value so that we can keep going.  */
       rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
This page took 0.120319 seconds and 4 git commands to generate.