* config/tc-i386.h (tc_comment_chars): Define.
[deliverable/binutils-gdb.git] / gas / config / tc-i386.c
index 4823ee7954610ed77106680a55900a1e3fcfed01..26121907fb2a7d173ac0bb5d2557281a4907fdcb 100644 (file)
@@ -1,6 +1,6 @@
 /* i386.c -- Assemble code for the Intel 80386
    Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003
+   2000, 2001, 2002, 2003, 2004, 2005
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
    You should have received a copy of the GNU General Public License
    along with GAS; see the file COPYING.  If not, write to the Free
-   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.  */
+   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
 
 /* Intel 80386 machine specific gas.
    Written by Eliot Dresselhaus (eliot@mgm.mit.edu).
    x86_64 support by Jan Hubicka (jh@suse.cz)
+   VIA PadLock support by Michal Ludvig (mludvig@suse.cz)
    Bugs & suggestions are completely welcome.  This is free software.
    Please help us make it better.  */
 
@@ -32,6 +33,7 @@
 #include "dwarf2dbg.h"
 #include "dw2gencfi.h"
 #include "opcode/i386.h"
+#include "elf/x86-64.h"
 
 #ifndef REGISTER_WARNINGS
 #define REGISTER_WARNINGS 1
 #define SCALE1_WHEN_NO_INDEX 1
 #endif
 
-#ifdef BFD_ASSEMBLER
-#define RELOC_ENUM enum bfd_reloc_code_real
-#else
-#define RELOC_ENUM int
-#endif
-
 #ifndef DEFAULT_ARCH
 #define DEFAULT_ARCH "i386"
 #endif
@@ -81,6 +77,10 @@ static void set_code_flag PARAMS ((int));
 static void set_16bit_gcc_code_flag PARAMS ((int));
 static void set_intel_syntax PARAMS ((int));
 static void set_cpu_arch PARAMS ((int));
+#ifdef TE_PE
+static void pe_directive_secrel PARAMS ((int));
+#endif
+static void signed_cons PARAMS ((int));
 static char *output_invalid PARAMS ((int c));
 static int i386_operand PARAMS ((char *operand_string));
 static int i386_intel_operand PARAMS ((char *operand_string, int got_a_float));
@@ -112,6 +112,9 @@ static void output_disp PARAMS ((fragS *insn_start_frag,
 #ifndef I386COFF
 static void s_bss PARAMS ((int));
 #endif
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+static void handle_large_common (int small ATTRIBUTE_UNUSED);
+#endif
 
 static const char *default_arch = DEFAULT_ARCH;
 
@@ -155,7 +158,7 @@ struct _i386_insn
 #define Operand_PCrel 1
 
     /* Relocation type for operand */
-    RELOC_ENUM reloc[MAX_OPERANDS];
+    enum bfd_reloc_code_real reloc[MAX_OPERANDS];
 
     /* BASE_REG, INDEX_REG, and LOG2_SCALE_FACTOR are used to encode
        the base index byte below.  */
@@ -184,22 +187,33 @@ typedef struct _i386_insn i386_insn;
 
 /* List of chars besides those in app.c:symbol_chars that can start an
    operand.  Used to prevent the scrubber eating vital white-space.  */
+const char extra_symbol_chars[] = "*%-(["
 #ifdef LEX_AT
-const char extra_symbol_chars[] = "*%-(@[";
-#else
-const char extra_symbol_chars[] = "*%-([";
+       "@"
 #endif
+#ifdef LEX_QM
+       "?"
+#endif
+       ;
 
 #if (defined (TE_I386AIX)                              \
      || ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF))        \
         && !defined (TE_LINUX)                         \
+        && !defined (TE_NETWARE)                       \
         && !defined (TE_FreeBSD)                       \
         && !defined (TE_NetBSD)))
 /* This array holds the chars that always start a comment.  If the
-   pre-processor is disabled, these aren't very useful.  */
-const char comment_chars[] = "#/";
+   pre-processor is disabled, these aren't very useful.  The option
+   --divide will remove '/' from this list.  */
+const char *i386_comment_chars = "#/";
+#define SVR4_COMMENT_CHARS 1
 #define PREFIX_SEPARATOR '\\'
 
+#else
+const char *i386_comment_chars = "#";
+#define PREFIX_SEPARATOR '/'
+#endif
+
 /* This array holds the chars that only start a comment at the beginning of
    a line.  If the line seems to have the form '# 123 filename'
    .line and .file directives will appear in the pre-processed output.
@@ -208,16 +222,7 @@ const char comment_chars[] = "#/";
    #NO_APP at the beginning of its output.
    Also note that comments started like this one will always work if
    '/' isn't otherwise defined.  */
-const char line_comment_chars[] = "#";
-
-#else
-/* Putting '/' here makes it impossible to use the divide operator.
-   However, we need it for compatibility with SVR4 systems.  */
-const char comment_chars[] = "#";
-#define PREFIX_SEPARATOR '/'
-
-const char line_comment_chars[] = "/#";
-#endif
+const char line_comment_chars[] = "#/";
 
 const char line_separator_chars[] = ";";
 
@@ -245,7 +250,7 @@ static char digit_chars[256];
 #define is_identifier_char(x) (identifier_chars[(unsigned char) x])
 #define is_digit_char(x) (digit_chars[(unsigned char) x])
 
-/* All non-digit non-letter charcters that may occur in an operand.  */
+/* All non-digit non-letter characters that may occur in an operand.  */
 static char operand_special_chars[] = "%$-+(,)*._~/<>|&^!:[@]";
 
 /* md_assemble() always leaves the strings it's passed unaltered.  To
@@ -281,6 +286,7 @@ enum flag_code {
 #define NUM_FLAG_CODE ((int) CODE_64BIT + 1)
 
 static enum flag_code flag_code;
+static unsigned int object_64bit;
 static int use_rela_relocations = 0;
 
 /* The names used to print error messages.  */
@@ -303,11 +309,15 @@ static int allow_naked_reg = 0;
    frame as in 32 bit mode.  */
 static char stackop_size = '\0';
 
+/* Non-zero to optimize code alignment.  */
+int optimize_align_code = 1;
+
 /* Non-zero to quieten some warnings.  */
 static int quiet_warnings = 0;
 
 /* CPU name.  */
 static const char *cpu_arch_name = NULL;
+static const char *cpu_sub_arch_name = NULL;
 
 /* CPU feature flags.  */
 static unsigned int cpu_arch_flags = CpuUnknownFlags | CpuNo64;
@@ -317,7 +327,7 @@ static unsigned int cpu_arch_flags = CpuUnknownFlags | CpuNo64;
 static unsigned int no_cond_jump_promotion = 0;
 
 /* Pre-defined "_GLOBAL_OFFSET_TABLE_".  */
-symbolS *GOT_symbol;
+static symbolS *GOT_symbol;
 
 /* The dwarf2 return column, adjusted for 32 or 64 bit.  */
 unsigned int x86_dwarf2_return_column;
@@ -410,14 +420,28 @@ static const arch_entry cpu_arch[] = {
   {"i286",     Cpu086|Cpu186|Cpu286 },
   {"i386",     Cpu086|Cpu186|Cpu286|Cpu386 },
   {"i486",     Cpu086|Cpu186|Cpu286|Cpu386|Cpu486 },
-  {"i586",     Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuMMX },
-  {"i686",     Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX|CpuSSE },
-  {"pentium",  Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuMMX },
-  {"pentiumpro",Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX|CpuSSE },
-  {"pentium4", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX|CpuSSE|CpuSSE2 },
-  {"k6",       Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuK6|CpuMMX|Cpu3dnow },
-  {"athlon",   Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuAthlon|CpuMMX|Cpu3dnow },
-  {"sledgehammer",Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuAthlon|CpuSledgehammer|CpuMMX|Cpu3dnow|CpuSSE|CpuSSE2 },
+  {"i586",     Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586 },
+  {"i686",     Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686 },
+  {"pentium",  Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586 },
+  {"pentiumpro",Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686 },
+  {"pentiumii",        Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX },
+  {"pentiumiii",Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX|CpuMMX2|CpuSSE },
+  {"pentium4", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX|CpuMMX2|CpuSSE|CpuSSE2 },
+  {"prescott", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuPNI },
+  {"k6",       Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuK6|CpuMMX },
+  {"k6_2",     Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuK6|CpuMMX|Cpu3dnow },
+  {"athlon",   Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuAthlon|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA },
+  {"sledgehammer",Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuAthlon|CpuSledgehammer|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2 },
+  {"opteron",  Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuAthlon|CpuSledgehammer|CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA|CpuSSE|CpuSSE2 },
+  {".mmx",     CpuMMX },
+  {".sse",     CpuMMX|CpuMMX2|CpuSSE },
+  {".sse2",    CpuMMX|CpuMMX2|CpuSSE|CpuSSE2 },
+  {".sse3",    CpuMMX|CpuMMX2|CpuSSE|CpuSSE2|CpuSSE3 },
+  {".3dnow",   CpuMMX|Cpu3dnow },
+  {".3dnowa",  CpuMMX|CpuMMX2|Cpu3dnow|Cpu3dnowA },
+  {".padlock", CpuPadLock },
+  {".pacifica",        CpuSVME },
+  {".svme",    CpuSVME },
   {NULL, 0 }
 };
 
@@ -436,6 +460,7 @@ const pseudo_typeS md_pseudo_table[] =
   {"dfloat", float_cons, 'd'},
   {"tfloat", float_cons, 'x'},
   {"value", cons, 2},
+  {"slong", signed_cons, 4},
   {"noopt", s_ignore, 0},
   {"optim", s_ignore, 0},
   {"code16gcc", set_16bit_gcc_code_flag, CODE_16BIT},
@@ -444,8 +469,16 @@ const pseudo_typeS md_pseudo_table[] =
   {"code64", set_code_flag, CODE_64BIT},
   {"intel_syntax", set_intel_syntax, 1},
   {"att_syntax", set_intel_syntax, 0},
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+  {"largecomm", handle_large_common, 0},
+#else
   {"file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0},
   {"loc", dwarf2_directive_loc, 0},
+  {"loc_mark_labels", dwarf2_directive_loc_mark_labels, 0},
+#endif
+#ifdef TE_PE
+  {"secrel32", pe_directive_secrel, 0},
+#endif
   {0, 0, 0}
 };
 
@@ -773,7 +806,7 @@ set_16bit_gcc_code_flag (new_code_flag)
   flag_code = new_code_flag;
   cpu_arch_flags &= ~(Cpu64 | CpuNo64);
   cpu_arch_flags |= (flag_code == CODE_64BIT ? Cpu64 : CpuNo64);
-  stackop_size = 'l';
+  stackop_size = LONG_MNEM_SUFFIX;
 }
 
 static void
@@ -802,17 +835,13 @@ set_intel_syntax (syntax_flag)
   intel_syntax = syntax_flag;
 
   if (ask_naked_reg == 0)
-    {
-#ifdef BFD_ASSEMBLER
-      allow_naked_reg = (intel_syntax
-                        && (bfd_get_symbol_leading_char (stdoutput) != '\0'));
-#else
-      /* Conservative default.  */
-      allow_naked_reg = 0;
-#endif
-    }
+    allow_naked_reg = (intel_syntax
+                      && (bfd_get_symbol_leading_char (stdoutput) != '\0'));
   else
     allow_naked_reg = (ask_naked_reg < 0);
+
+  identifier_chars['%'] = intel_syntax && allow_naked_reg ? '%' : 0;
+  identifier_chars['$'] = intel_syntax ? '$' : 0;
 }
 
 static void
@@ -831,10 +860,22 @@ set_cpu_arch (dummy)
        {
          if (strcmp (string, cpu_arch[i].name) == 0)
            {
-             cpu_arch_name = cpu_arch[i].name;
-             cpu_arch_flags = (cpu_arch[i].flags
-                               | (flag_code == CODE_64BIT ? Cpu64 : CpuNo64));
-             break;
+             if (*string != '.')
+               {
+                 cpu_arch_name = cpu_arch[i].name;
+                 cpu_sub_arch_name = NULL;
+                 cpu_arch_flags = (cpu_arch[i].flags
+                                   | (flag_code == CODE_64BIT ? Cpu64 : CpuNo64));
+                 break;
+               }
+             if ((cpu_arch_flags | cpu_arch[i].flags) != cpu_arch_flags)
+               {
+                 cpu_sub_arch_name = cpu_arch[i].name;
+                 cpu_arch_flags |= cpu_arch[i].flags;
+               }
+             *input_line_pointer = e;
+             demand_empty_rest_of_line ();
+             return;
            }
        }
       if (!cpu_arch[i].name)
@@ -865,7 +906,6 @@ set_cpu_arch (dummy)
   demand_empty_rest_of_line ();
 }
 
-#ifdef BFD_ASSEMBLER
 unsigned long
 i386_mach ()
 {
@@ -876,7 +916,6 @@ i386_mach ()
   else
     as_fatal (_("Unknown architecture"));
 }
-#endif
 \f
 void
 md_begin ()
@@ -976,8 +1015,13 @@ md_begin ()
 
 #ifdef LEX_AT
     identifier_chars['@'] = '@';
+#endif
+#ifdef LEX_QM
+    identifier_chars['?'] = '?';
+    operand_chars['?'] = '?';
 #endif
     digit_chars['-'] = '-';
+    mnemonic_chars['-'] = '-';
     identifier_chars['_'] = '_';
     identifier_chars['.'] = '.';
 
@@ -986,7 +1030,7 @@ md_begin ()
   }
 
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
-  if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+  if (IS_ELF)
     {
       record_alignment (text_section, 2);
       record_alignment (data_section, 2);
@@ -1169,35 +1213,68 @@ pt (t)
 
 #endif /* DEBUG386 */
 \f
-#ifdef BFD_ASSEMBLER
-static bfd_reloc_code_real_type reloc
-  PARAMS ((int, int, int, bfd_reloc_code_real_type));
-
 static bfd_reloc_code_real_type
-reloc (size, pcrel, sign, other)
-     int size;
-     int pcrel;
-     int sign;
-     bfd_reloc_code_real_type other;
+reloc (unsigned int size,
+     int pcrel,
+     int sign,
+     bfd_reloc_code_real_type other)
 {
   if (other != NO_RELOC)
-    return other;
+    {
+      reloc_howto_type *reloc;
+
+      if (size == 8)
+       switch (other)
+         {
+           case BFD_RELOC_X86_64_TPOFF32:
+             other = BFD_RELOC_X86_64_TPOFF64;
+             break;
+           case BFD_RELOC_X86_64_DTPOFF32:
+             other = BFD_RELOC_X86_64_DTPOFF64;
+             break;
+           default:
+             break;
+         }
+
+      /* Sign-checking 4-byte relocations in 16-/32-bit code is pointless.  */
+      if (size == 4 && flag_code != CODE_64BIT)
+       sign = -1;
+
+      reloc = bfd_reloc_type_lookup (stdoutput, other);
+      if (!reloc)
+       as_bad (_("unknown relocation (%u)"), other);
+      else if (size != bfd_get_reloc_size (reloc))
+       as_bad (_("%u-byte relocation cannot be applied to %u-byte field"),
+               bfd_get_reloc_size (reloc),
+               size);
+      else if (pcrel && !reloc->pc_relative)
+       as_bad (_("non-pc-relative relocation for pc-relative field"));
+      else if ((reloc->complain_on_overflow == complain_overflow_signed
+               && !sign)
+              || (reloc->complain_on_overflow == complain_overflow_unsigned
+               && sign > 0))
+       as_bad (_("relocated field and relocation type differ in signedness"));
+      else
+       return other;
+      return NO_RELOC;
+    }
 
   if (pcrel)
     {
       if (!sign)
-       as_bad (_("There are no unsigned pc-relative relocations"));
+       as_bad (_("there are no unsigned pc-relative relocations"));
       switch (size)
        {
        case 1: return BFD_RELOC_8_PCREL;
        case 2: return BFD_RELOC_16_PCREL;
        case 4: return BFD_RELOC_32_PCREL;
+       case 8: return BFD_RELOC_64_PCREL;
        }
-      as_bad (_("can not do %d byte pc-relative relocation"), size);
+      as_bad (_("cannot do %u byte pc-relative relocation"), size);
     }
   else
     {
-      if (sign)
+      if (sign > 0)
        switch (size)
          {
          case 4: return BFD_RELOC_X86_64_32S;
@@ -1210,8 +1287,8 @@ reloc (size, pcrel, sign, other)
          case 4: return BFD_RELOC_32;
          case 8: return BFD_RELOC_64;
          }
-      as_bad (_("can not do %s %d byte relocation"),
-             sign ? "signed" : "unsigned", size);
+      as_bad (_("cannot do %s %u byte relocation"),
+             sign > 0 ? "signed" : "unsigned", size);
     }
 
   abort ();
@@ -1228,7 +1305,7 @@ tc_i386_fix_adjustable (fixP)
      fixS *fixP ATTRIBUTE_UNUSED;
 {
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
-  if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+  if (!IS_ELF)
     return 1;
 
   /* Don't adjust pc-relative references to merge sections in 64-bit
@@ -1238,6 +1315,12 @@ tc_i386_fix_adjustable (fixP)
       && fixP->fx_pcrel)
     return 0;
 
+  /* The x86_64 GOTPCREL are represented as 32bit PCrel relocations
+     and changed later by validate_fix.  */
+  if (GOT_symbol && fixP->fx_subsy == GOT_symbol
+      && fixP->fx_r_type == BFD_RELOC_32_PCREL)
+    return 0;
+
   /* adjust_reloc_syms doesn't know about the GOT.  */
   if (fixP->fx_r_type == BFD_RELOC_386_GOTOFF
       || fixP->fx_r_type == BFD_RELOC_386_PLT32
@@ -1256,42 +1339,17 @@ tc_i386_fix_adjustable (fixP)
       || fixP->fx_r_type == BFD_RELOC_X86_64_TLSGD
       || fixP->fx_r_type == BFD_RELOC_X86_64_TLSLD
       || fixP->fx_r_type == BFD_RELOC_X86_64_DTPOFF32
+      || fixP->fx_r_type == BFD_RELOC_X86_64_DTPOFF64
       || fixP->fx_r_type == BFD_RELOC_X86_64_GOTTPOFF
       || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF32
+      || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF64
+      || fixP->fx_r_type == BFD_RELOC_X86_64_GOTOFF64
       || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
       || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
     return 0;
 #endif
   return 1;
 }
-#else
-#define reloc(SIZE,PCREL,SIGN,OTHER)   0
-#define BFD_RELOC_8                    0
-#define BFD_RELOC_16                   0
-#define BFD_RELOC_32                   0
-#define BFD_RELOC_8_PCREL              0
-#define BFD_RELOC_16_PCREL             0
-#define BFD_RELOC_32_PCREL             0
-#define BFD_RELOC_386_PLT32            0
-#define BFD_RELOC_386_GOT32            0
-#define BFD_RELOC_386_GOTOFF           0
-#define BFD_RELOC_386_TLS_GD           0
-#define BFD_RELOC_386_TLS_LDM          0
-#define BFD_RELOC_386_TLS_LDO_32       0
-#define BFD_RELOC_386_TLS_IE_32                0
-#define BFD_RELOC_386_TLS_IE           0
-#define BFD_RELOC_386_TLS_GOTIE                0
-#define BFD_RELOC_386_TLS_LE_32                0
-#define BFD_RELOC_386_TLS_LE           0
-#define BFD_RELOC_X86_64_PLT32         0
-#define BFD_RELOC_X86_64_GOT32         0
-#define BFD_RELOC_X86_64_GOTPCREL      0
-#define BFD_RELOC_X86_64_TLSGD         0
-#define BFD_RELOC_X86_64_TLSLD         0
-#define BFD_RELOC_X86_64_DTPOFF32      0
-#define BFD_RELOC_X86_64_GOTTPOFF      0
-#define BFD_RELOC_X86_64_TPOFF32       0
-#endif
 
 static int intel_float_operand PARAMS ((const char *mnemonic));
 
@@ -1299,13 +1357,54 @@ static int
 intel_float_operand (mnemonic)
      const char *mnemonic;
 {
-  if (mnemonic[0] == 'f' && mnemonic[1] == 'i')
-    return 2;
-
-  if (mnemonic[0] == 'f')
-    return 1;
+  /* Note that the value returned is meaningful only for opcodes with (memory)
+     operands, hence the code here is free to improperly handle opcodes that
+     have no operands (for better performance and smaller code). */
+
+  if (mnemonic[0] != 'f')
+    return 0; /* non-math */
+
+  switch (mnemonic[1])
+    {
+    /* fclex, fdecstp, fdisi, femms, feni, fincstp, finit, fsetpm, and
+       the fs segment override prefix not currently handled because no
+       call path can make opcodes without operands get here */
+    case 'i':
+      return 2 /* integer op */;
+    case 'l':
+      if (mnemonic[2] == 'd' && (mnemonic[3] == 'c' || mnemonic[3] == 'e'))
+       return 3; /* fldcw/fldenv */
+      break;
+    case 'n':
+      if (mnemonic[2] != 'o' /* fnop */)
+       return 3; /* non-waiting control op */
+      break;
+    case 'r':
+      if (mnemonic[2] == 's')
+       return 3; /* frstor/frstpm */
+      break;
+    case 's':
+      if (mnemonic[2] == 'a')
+       return 3; /* fsave */
+      if (mnemonic[2] == 't')
+       {
+         switch (mnemonic[3])
+           {
+           case 'c': /* fstcw */
+           case 'd': /* fstdw */
+           case 'e': /* fstenv */
+           case 's': /* fsts[gw] */
+             return 3;
+           }
+       }
+      break;
+    case 'x':
+      if (mnemonic[2] == 'r' || mnemonic[2] == 's')
+       return 0; /* fxsave/fxrstor are not really math ops */
+      break;
+    }
 
-  return 0;
+  return 1;
 }
 
 /* This is the guts of the machine-dependent assembler.  LINE points to a
@@ -1350,13 +1449,18 @@ md_assemble (line)
      have two immediate operands.  */
   if (intel_syntax && i.operands > 1
       && (strcmp (mnemonic, "bound") != 0)
+      && (strcmp (mnemonic, "invlpga") != 0)
       && !((i.types[0] & Imm) && (i.types[1] & Imm)))
     swap_operands ();
 
   if (i.imm_operands)
     optimize_imm ();
 
-  if (i.disp_operands)
+  /* Don't optimize displacement for movabs since it only takes 64bit
+     displacement.  */
+  if (i.disp_operands
+      && (flag_code != CODE_64BIT
+         || strcmp (mnemonic, "movabs") != 0))
     optimize_disp ();
 
   /* Next, we find a template that matches the given insn,
@@ -1377,7 +1481,20 @@ md_assemble (line)
         "word ptr" or "byte ptr" on the source operand, but we'll use
         the suffix later to choose the destination register.  */
       if ((i.tm.base_opcode & ~9) == 0x0fb6)
-       i.suffix = 0;
+       {
+         if (i.reg_operands < 2
+             && !i.suffix
+             && (~i.tm.opcode_modifier
+                 & (No_bSuf
+                    | No_wSuf
+                    | No_lSuf
+                    | No_sSuf
+                    | No_xSuf
+                    | No_qSuf)))
+           as_bad (_("ambiguous operand size for `%s'"), i.tm.name);
+
+         i.suffix = 0;
+       }
     }
 
   if (i.tm.opcode_modifier & FWait)
@@ -1410,13 +1527,28 @@ md_assemble (line)
 
   if (i.tm.opcode_modifier & ImmExt)
     {
+      expressionS *exp;
+
+      if ((i.tm.cpu_flags & CpuPNI) && i.operands > 0)
+       {
+         /* These Intel Prescott New Instructions have the fixed
+            operands with an opcode suffix which is coded in the same
+            place as an 8-bit immediate field would be. Here we check
+            those operands and remove them afterwards.  */
+         unsigned int x;
+
+         for (x = 0; x < i.operands; x++)
+           if (i.op[x].regs->reg_num != x)
+             as_bad (_("can't use register '%%%s' as operand %d in '%s'."),
+                       i.op[x].regs->reg_name, x + 1, i.tm.name);
+         i.operands = 0;
+       }
+
       /* These AMD 3DNow! and Intel Katmai New Instructions have an
         opcode suffix which is coded in the same place as an 8-bit
         immediate field would be.  Here we fake an 8-bit immediate
         operand from the opcode suffix stored in tm.extension_opcode.  */
 
-      expressionS *exp;
-
       assert (i.imm_operands == 0 && i.operands <= 2 && 2 < MAX_OPERANDS);
 
       exp = &im_expressions[i.imm_operands++];
@@ -1481,7 +1613,7 @@ md_assemble (line)
            {
              /* In case it is "hi" register, give up.  */
              if (i.op[x].regs->reg_num > 3)
-               as_bad (_("can't encode register '%%%s' in an instruction requiring REX prefix.\n"),
+               as_bad (_("can't encode register '%%%s' in an instruction requiring REX prefix."),
                        i.op[x].regs->reg_name);
 
              /* Otherwise it is equivalent to the extended register.
@@ -1508,6 +1640,8 @@ parse_insn (line, mnemonic)
   char *l = line;
   char *token_start = l;
   char *mnem_p;
+  int supported;
+  const template *t;
 
   /* Non-zero if we found a prefix only acceptable with string insns.  */
   const char *expecting_string_instruction = NULL;
@@ -1527,8 +1661,9 @@ parse_insn (line, mnemonic)
        }
       if (!is_space_char (*l)
          && *l != END_OF_INSN
-         && *l != PREFIX_SEPARATOR
-         && *l != ',')
+         && (intel_syntax
+             || (*l != PREFIX_SEPARATOR
+                 && *l != ',')))
        {
          as_bad (_("invalid character %s in mnemonic"),
                  output_invalid (*l));
@@ -1536,7 +1671,7 @@ parse_insn (line, mnemonic)
        }
       if (token_start == l)
        {
-         if (*l == PREFIX_SEPARATOR)
+         if (!intel_syntax && *l == PREFIX_SEPARATOR)
            as_bad (_("expecting prefix; got nothing"));
          else
            as_bad (_("expecting mnemonic; got nothing"));
@@ -1551,6 +1686,15 @@ parse_insn (line, mnemonic)
          && current_templates
          && (current_templates->start->opcode_modifier & IsPrefix))
        {
+         if (current_templates->start->cpu_flags
+             & (flag_code != CODE_64BIT ? Cpu64 : CpuNo64))
+           {
+             as_bad ((flag_code != CODE_64BIT
+                      ? _("`%s' is only supported in 64-bit mode")
+                      : _("`%s' is not supported in 64-bit mode")),
+                     current_templates->start->name);
+             return NULL;
+           }
          /* If we are in 16-bit mode, do not allow addr16 or data16.
             Similarly, in 32-bit mode, do not allow addr32 or data32.  */
          if ((current_templates->start->opcode_modifier & (Size16 | Size32))
@@ -1584,6 +1728,9 @@ parse_insn (line, mnemonic)
       switch (mnem_p[-1])
        {
        case WORD_MNEM_SUFFIX:
+         if (intel_syntax && (intel_float_operand (mnemonic) & 2))
+           i.suffix = SHORT_MNEM_SUFFIX;
+         else
        case BYTE_MNEM_SUFFIX:
        case QWORD_MNEM_SUFFIX:
          i.suffix = mnem_p[-1];
@@ -1604,7 +1751,7 @@ parse_insn (line, mnemonic)
        case 'd':
          if (intel_syntax)
            {
-             if (intel_float_operand (mnemonic))
+             if (intel_float_operand (mnemonic) == 1)
                i.suffix = SHORT_MNEM_SUFFIX;
              else
                i.suffix = LONG_MNEM_SUFFIX;
@@ -1653,11 +1800,29 @@ parse_insn (line, mnemonic)
     }
 
   /* Check if instruction is supported on specified architecture.  */
-  if ((current_templates->start->cpu_flags & ~(Cpu64 | CpuNo64))
-      & ~(cpu_arch_flags & ~(Cpu64 | CpuNo64)))
+  supported = 0;
+  for (t = current_templates->start; t < current_templates->end; ++t)
+    {
+      if (!((t->cpu_flags & ~(Cpu64 | CpuNo64))
+           & ~(cpu_arch_flags & ~(Cpu64 | CpuNo64))))
+         supported |= 1;
+      if (!(t->cpu_flags & (flag_code == CODE_64BIT ? CpuNo64 : Cpu64)))
+         supported |= 2;
+    }
+  if (!(supported & 2))
+    {
+      as_bad (flag_code == CODE_64BIT
+             ? _("`%s' is not supported in 64-bit mode")
+             : _("`%s' is only supported in 64-bit mode"),
+             current_templates->start->name);
+      return NULL;
+    }
+  if (!(supported & 1))
     {
-      as_warn (_("`%s' is not supported on `%s'"),
-              current_templates->start->name, cpu_arch_name);
+      as_warn (_("`%s' is not supported on `%s%s'"),
+              current_templates->start->name,
+              cpu_arch_name,
+              cpu_sub_arch_name ? cpu_sub_arch_name : "");
     }
   else if ((Cpu386 & ~cpu_arch_flags) && (flag_code != CODE_16BIT))
     {
@@ -1665,12 +1830,24 @@ parse_insn (line, mnemonic)
     }
 
   /* Check for rep/repne without a string instruction.  */
-  if (expecting_string_instruction
-      && !(current_templates->start->opcode_modifier & IsString))
+  if (expecting_string_instruction)
     {
-      as_bad (_("expecting string instruction after `%s'"),
-             expecting_string_instruction);
-      return NULL;
+      static templates override;
+
+      for (t = current_templates->start; t < current_templates->end; ++t)
+       if (t->opcode_modifier & IsString)
+         break;
+      if (t >= current_templates->end)
+       {
+         as_bad (_("expecting string instruction after `%s'"),
+               expecting_string_instruction);
+         return NULL;
+       }
+      for (override.start = t; t < current_templates->end; ++t)
+       if (!(t->opcode_modifier & IsString))
+         break;
+      override.end = t;
+      current_templates = &override;
     }
 
   return l;
@@ -1801,7 +1978,7 @@ swap_operands ()
 {
   union i386_op temp_op;
   unsigned int temp_type;
-  RELOC_ENUM temp_reloc;
+  enum bfd_reloc_code_real temp_reloc;
   int xchg1 = 0;
   int xchg2 = 0;
 
@@ -1920,24 +2097,36 @@ optimize_imm ()
 
            /* Symbols and expressions.  */
          default:
-           /* Convert symbolic operand to proper sizes for matching.  */
-           switch (guess_suffix)
-             {
-             case QWORD_MNEM_SUFFIX:
-               i.types[op] = Imm64 | Imm32S;
-               break;
-             case LONG_MNEM_SUFFIX:
-               i.types[op] = Imm32 | Imm64;
-               break;
-             case WORD_MNEM_SUFFIX:
-               i.types[op] = Imm16 | Imm32 | Imm64;
-               break;
-               break;
-             case BYTE_MNEM_SUFFIX:
-               i.types[op] = Imm8 | Imm8S | Imm16 | Imm32S | Imm32;
-               break;
-               break;
-             }
+           /* Convert symbolic operand to proper sizes for matching, but don't
+              prevent matching a set of insns that only supports sizes other
+              than those matching the insn suffix.  */
+           {
+             unsigned int mask, allowed = 0;
+             const template *t;
+
+             for (t = current_templates->start; t < current_templates->end; ++t)
+               allowed |= t->operand_types[op];
+             switch (guess_suffix)
+               {
+               case QWORD_MNEM_SUFFIX:
+                 mask = Imm64 | Imm32S;
+                 break;
+               case LONG_MNEM_SUFFIX:
+                 mask = Imm32;
+                 break;
+               case WORD_MNEM_SUFFIX:
+                 mask = Imm16;
+                 break;
+               case BYTE_MNEM_SUFFIX:
+                 mask = Imm8;
+                 break;
+               default:
+                 mask = 0;
+                 break;
+               }
+               if (mask & allowed)
+                 i.types[op] &= mask;
+           }
            break;
          }
       }
@@ -1950,37 +2139,54 @@ optimize_disp ()
   int op;
 
   for (op = i.operands; --op >= 0;)
-    if ((i.types[op] & Disp) && i.op[op].disps->X_op == O_constant)
+    if (i.types[op] & Disp)
       {
-       offsetT disp = i.op[op].disps->X_add_number;
-
-       if (i.types[op] & Disp16)
+       if (i.op[op].disps->X_op == O_constant)
          {
-           /* 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.  */
+           offsetT disp = i.op[op].disps->X_add_number;
 
-           disp = (((disp & 0xffff) ^ 0x8000) - 0x8000);
-         }
-       else if (i.types[op] & Disp32)
-         {
-           /* We know this operand is at most 32 bits, so convert to a
-              signed 32 bit number before trying to see whether it will
-              fit in an even smaller size.  */
-           disp &= (((offsetT) 2 << 31) - 1);
-           disp = (disp ^ ((offsetT) 1 << 31)) - ((addressT) 1 << 31);
-         }
-       if (flag_code == CODE_64BIT)
-         {
-           if (fits_in_signed_long (disp))
-             i.types[op] |= Disp32S;
-           if (fits_in_unsigned_long (disp))
-             i.types[op] |= Disp32;
+           if ((i.types[op] & Disp16)
+               && (disp & ~(offsetT) 0xffff) == 0)
+             {
+               /* If this operand is at most 16 bits, convert
+                  to a signed 16 bit number and don't use 64bit
+                  displacement.  */
+               disp = (((disp & 0xffff) ^ 0x8000) - 0x8000);
+               i.types[op] &= ~Disp64;
+             }
+           if ((i.types[op] & Disp32)
+               && (disp & ~(((offsetT) 2 << 31) - 1)) == 0)
+             {
+               /* If this operand is at most 32 bits, convert
+                  to a signed 32 bit number and don't use 64bit
+                  displacement.  */
+               disp &= (((offsetT) 2 << 31) - 1);
+               disp = (disp ^ ((offsetT) 1 << 31)) - ((addressT) 1 << 31);
+               i.types[op] &= ~Disp64;
+             }
+           if (!disp && (i.types[op] & BaseIndex))
+             {
+               i.types[op] &= ~Disp;
+               i.op[op].disps = 0;
+               i.disp_operands--;
+             }
+           else if (flag_code == CODE_64BIT)
+             {
+               if (fits_in_signed_long (disp))
+                 {
+                   i.types[op] &= ~Disp64;
+                   i.types[op] |= Disp32S;
+                 }
+               if (fits_in_unsigned_long (disp))
+                 i.types[op] |= Disp32;
+             }
+           if ((i.types[op] & (Disp32 | Disp32S | Disp16))
+               && fits_in_signed_byte (disp))
+             i.types[op] |= Disp8;
          }
-       if ((i.types[op] & (Disp32 | Disp32S | Disp16))
-           && fits_in_signed_byte (disp))
-         i.types[op] |= Disp8;
+       else
+         /* We only support 64bit displacement on constants.  */
+         i.types[op] &= ~Disp64;
       }
 }
 
@@ -2023,9 +2229,19 @@ match_template ()
                              : (i.suffix == LONG_DOUBLE_MNEM_SUFFIX
                                 ? No_xSuf : 0))))));
 
-  for (t = current_templates->start;
-       t < current_templates->end;
-       t++)
+  t = current_templates->start;
+  if (i.suffix == QWORD_MNEM_SUFFIX
+      && flag_code != CODE_64BIT
+      && (intel_syntax
+         ? !(t->opcode_modifier & IgnoreSize)
+           && !intel_float_operand (t->name)
+         : intel_float_operand (t->name) != 2)
+      && (!(t->operand_types[0] & (RegMMX | RegXMM))
+         || !(t->operand_types[t->operands > 1] & (RegMMX | RegXMM)))
+      && (t->base_opcode != 0x0fc7
+         || t->extension_opcode != 1 /* cmpxchg8b */))
+    t = current_templates->end;
+  for (; t < current_templates->end; t++)
     {
       /* Must have right number of operands.  */
       if (i.operands != t->operands)
@@ -2034,11 +2250,7 @@ match_template ()
       /* Check the suffix, except for some instructions in intel mode.  */
       if ((t->opcode_modifier & suffix_check)
          && !(intel_syntax
-              && (t->opcode_modifier & IgnoreSize))
-         && !(intel_syntax
-              && t->base_opcode == 0xd9
-              && (t->extension_opcode == 5          /* 0xd9,5 "fldcw"  */
-                  || t->extension_opcode == 7)))  /* 0xd9,7 "f{n}stcw"  */
+              && (t->opcode_modifier & IgnoreSize)))
        continue;
 
       /* Do not verify operands when there are none.  */
@@ -2192,7 +2404,7 @@ check_string ()
 }
 
 static int
-process_suffix ()
+process_suffix (void)
 {
   /* If matched instruction specifies an explicit instruction mnemonic
      suffix, use it.  */
@@ -2215,6 +2427,7 @@ process_suffix ()
             Destination register type is more significant than source
             register type.  */
          int op;
+
          for (op = i.operands; --op >= 0;)
            if ((i.types[op] & Reg)
                && !(i.tm.operand_types[op] & InOutPortReg))
@@ -2252,20 +2465,72 @@ process_suffix ()
       else
        abort ();
     }
-  else if ((i.tm.opcode_modifier & DefaultSize) && !i.suffix)
+  else if ((i.tm.opcode_modifier & DefaultSize)
+          && !i.suffix
+          /* exclude fldenv/frstor/fsave/fstenv */
+          && (i.tm.opcode_modifier & No_sSuf))
     {
       i.suffix = stackop_size;
     }
+  else if (intel_syntax
+          && !i.suffix
+          && ((i.tm.operand_types[0] & JumpAbsolute)
+           || (i.tm.opcode_modifier & (JumpByte|JumpInterSegment))
+           || (i.tm.base_opcode == 0x0f01 /* [ls][gi]dt */
+               && i.tm.extension_opcode <= 3)))
+    {
+      switch (flag_code)
+       {
+       case CODE_64BIT:
+         if (!(i.tm.opcode_modifier & No_qSuf))
+           {
+             i.suffix = QWORD_MNEM_SUFFIX;
+             break;
+           }
+       case CODE_32BIT:
+         if (!(i.tm.opcode_modifier & No_lSuf))
+           i.suffix = LONG_MNEM_SUFFIX;
+         break;
+       case CODE_16BIT:
+         if (!(i.tm.opcode_modifier & No_wSuf))
+           i.suffix = WORD_MNEM_SUFFIX;
+         break;
+       }
+    }
 
-  /* Change the opcode based on the operand size given by i.suffix;
-     We need not change things for byte insns.  */
-
-  if (!i.suffix && (i.tm.opcode_modifier & W))
+  if (!i.suffix)
     {
-      as_bad (_("no instruction mnemonic suffix given and no register operands; can't size instruction"));
-      return 0;
+      if (!intel_syntax)
+       {
+         if (i.tm.opcode_modifier & W)
+           {
+             as_bad (_("no instruction mnemonic suffix given and no register operands; can't size instruction"));
+             return 0;
+           }
+       }
+      else
+       {
+         unsigned int suffixes = ~i.tm.opcode_modifier
+                                 & (No_bSuf
+                                    | No_wSuf
+                                    | No_lSuf
+                                    | No_sSuf
+                                    | No_xSuf
+                                    | No_qSuf);
+
+         if ((i.tm.opcode_modifier & W)
+             || ((suffixes & (suffixes - 1))
+                 && !(i.tm.opcode_modifier & (DefaultSize | IgnoreSize))))
+           {
+             as_bad (_("ambiguous operand size for `%s'"), i.tm.name);
+             return 0;
+           }
+       }
     }
 
+  /* Change the opcode based on the operand size given by i.suffix;
+     We don't need to change things for byte insns.  */
+
   if (i.suffix && i.suffix != BYTE_MNEM_SUFFIX)
     {
       /* It's not a byte, select word/dword operation.  */
@@ -2281,12 +2546,14 @@ process_suffix ()
         size prefix, except for instructions that will ignore this
         prefix anyway.  */
       if (i.suffix != QWORD_MNEM_SUFFIX
-         && !(i.tm.opcode_modifier & IgnoreSize)
+         && i.suffix != LONG_DOUBLE_MNEM_SUFFIX
+         && !(i.tm.opcode_modifier & (IgnoreSize | FloatMF))
          && ((i.suffix == LONG_MNEM_SUFFIX) == (flag_code == CODE_16BIT)
              || (flag_code == CODE_64BIT
                  && (i.tm.opcode_modifier & JumpByte))))
        {
          unsigned int prefix = DATA_PREFIX_OPCODE;
+
          if (i.tm.opcode_modifier & JumpByte) /* jcxz, loop */
            prefix = ADDR_PREFIX_OPCODE;
 
@@ -2302,19 +2569,18 @@ process_suffix ()
 
       /* Size floating point instruction.  */
       if (i.suffix == LONG_MNEM_SUFFIX)
-       {
-         if (i.tm.opcode_modifier & FloatMF)
-           i.tm.base_opcode ^= 4;
-       }
+       if (i.tm.opcode_modifier & FloatMF)
+         i.tm.base_opcode ^= 4;
     }
 
   return 1;
 }
 
 static int
-check_byte_reg ()
+check_byte_reg (void)
 {
   int op;
+
   for (op = i.operands; --op >= 0;)
     {
       /* If this is an eight bit register, it's OK.  If it's the 16 or
@@ -2332,14 +2598,7 @@ check_byte_reg ()
              || i.tm.base_opcode == 0xfbf))
        continue;
 
-      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 maybe should be
-            allowed.  */
-         && (i.tm.operand_types[op] & (Reg8 | InOutPortReg))
-#endif
-         )
+      if ((i.types[op] & WordReg) && i.op[op].regs->reg_num < 4)
        {
          /* Prohibit these changes in the 64bit mode, since the
             lowering is more complicated.  */
@@ -2509,7 +2768,7 @@ finalize_imm ()
   unsigned int overlap0, overlap1, overlap2;
 
   overlap0 = i.types[0] & i.tm.operand_types[0];
-  if ((overlap0 & (Imm8 | Imm8S | Imm16 | Imm32 | Imm32S))
+  if ((overlap0 & (Imm8 | Imm8S | Imm16 | Imm32 | Imm32S | Imm64))
       && overlap0 != Imm8 && overlap0 != Imm8S
       && overlap0 != Imm16 && overlap0 != Imm32S
       && overlap0 != Imm32 && overlap0 != Imm64)
@@ -2542,7 +2801,7 @@ finalize_imm ()
   i.types[0] = overlap0;
 
   overlap1 = i.types[1] & i.tm.operand_types[1];
-  if ((overlap1 & (Imm8 | Imm8S | Imm16 | Imm32S | Imm32))
+  if ((overlap1 & (Imm8 | Imm8S | Imm16 | Imm32S | Imm32 | Imm64))
       && overlap1 != Imm8 && overlap1 != Imm8S
       && overlap1 != Imm16 && overlap1 != Imm32S
       && overlap1 != Imm32 && overlap1 != Imm64)
@@ -2660,8 +2919,10 @@ process_operands ()
       default_seg = &ds;
     }
 
-  if (i.tm.base_opcode == 0x8d /* lea */ && i.seg[0] && !quiet_warnings)
-    as_warn (_("segment override on `lea' is ineffectual"));
+  if ((i.tm.base_opcode == 0x8d /* lea */
+       || (i.tm.cpu_flags & CpuSVME))
+      && i.seg[0] && !quiet_warnings)
+    as_warn (_("segment override on `%s' is ineffectual"), i.tm.name);
 
   /* If a segment was explicitly specified, and the specified segment
      is not the default, use an opcode prefix to select it.  If we
@@ -2718,6 +2979,13 @@ build_modrm_byte ()
          if ((i.op[source].regs->reg_flags & RegRex) != 0)
            i.rex |= REX_EXTX;
        }
+      if (flag_code != CODE_64BIT && (i.rex & (REX_EXTX | REX_EXTZ)))
+       {
+         if (!((i.types[0] | i.types[1]) & Control))
+           abort ();
+         i.rex &= ~(REX_EXTX | REX_EXTZ);
+         add_prefix (LOCK_PREFIX_OPCODE);
+       }
     }
   else
     {                  /* If it's not 2 reg operands...  */
@@ -2738,21 +3006,7 @@ build_modrm_byte ()
              if (i.index_reg == 0)
                {
                  /* Operand is just <disp>  */
-                 if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0)
-                     && (flag_code != CODE_64BIT))
-                   {
-                     i.rm.regmem = NO_BASE_REGISTER_16;
-                     i.types[op] &= ~Disp;
-                     i.types[op] |= Disp16;
-                   }
-                 else if (flag_code != CODE_64BIT
-                          || (i.prefix[ADDR_PREFIX] != 0))
-                   {
-                     i.rm.regmem = NO_BASE_REGISTER;
-                     i.types[op] &= ~Disp;
-                     i.types[op] |= Disp32;
-                   }
-                 else
+                 if (flag_code == CODE_64BIT)
                    {
                      /* 64bit mode overwrites the 32bit absolute
                         addressing by RIP relative addressing and
@@ -2761,8 +3015,17 @@ build_modrm_byte ()
                      i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
                      i.sib.base = NO_BASE_REGISTER;
                      i.sib.index = NO_INDEX_REGISTER;
-                     i.types[op] &= ~Disp;
-                     i.types[op] |= Disp32S;
+                     i.types[op] = ((i.prefix[ADDR_PREFIX] == 0) ? Disp32S : Disp32);
+                   }
+                 else if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0))
+                   {
+                     i.rm.regmem = NO_BASE_REGISTER_16;
+                     i.types[op] = Disp16;
+                   }
+                 else
+                   {
+                     i.rm.regmem = NO_BASE_REGISTER;
+                     i.types[op] = Disp32;
                    }
                }
              else /* !i.base_reg && i.index_reg  */
@@ -2784,9 +3047,11 @@ build_modrm_byte ()
          else if (i.base_reg->reg_type == BaseIndex)
            {
              i.rm.regmem = NO_BASE_REGISTER;
-             i.types[op] &= ~Disp;
+             i.types[op] &= ~ Disp;
              i.types[op] |= Disp32S;
              i.flags[op] = Operand_PCrel;
+             if (! i.disp_operands)
+               fake_zero_displacement = 1;
            }
          else if (i.base_reg->reg_type & Reg16)
            {
@@ -2822,12 +3087,8 @@ build_modrm_byte ()
            {
              if (flag_code == CODE_64BIT
                  && (i.types[op] & Disp))
-               {
-                 if (i.types[op] & Disp8)
-                   i.types[op] = Disp8 | Disp32S;
-                 else
-                   i.types[op] = Disp32S;
-               }
+               i.types[op] = (i.types[op] & Disp8) | (i.prefix[ADDR_PREFIX] == 0 ? Disp32S : Disp32);
+
              i.rm.regmem = i.base_reg->reg_num;
              if ((i.base_reg->reg_flags & RegRex) != 0)
                i.rex |= REX_EXTZ;
@@ -3143,7 +3404,6 @@ output_interseg_jump ()
   md_number_to_chars (p + size, (valueT) i.op[0].imms->X_add_number, 2);
 }
 
-
 static void
 output_insn ()
 {
@@ -3171,10 +3431,23 @@ output_insn ()
       char *p;
       unsigned char *q;
 
-      /* All opcodes on i386 have either 1 or 2 bytes.  We may use third
-        byte for the SSE instructions to specify a prefix they require.  */
-      if (i.tm.base_opcode & 0xff0000)
-       add_prefix ((i.tm.base_opcode >> 16) & 0xff);
+      /* All opcodes on i386 have either 1 or 2 bytes.  We may use one
+        more higher byte to specify a prefix the instruction
+        requires.  */
+      if ((i.tm.base_opcode & 0xff0000) != 0)
+       {
+         if ((i.tm.cpu_flags & CpuPadLock) != 0)
+           {
+             unsigned int prefix;
+             prefix = (i.tm.base_opcode >> 16) & 0xff;
+
+             if (prefix != REPE_PREFIX_OPCODE
+                 || i.prefix[LOCKREP_PREFIX] != REPE_PREFIX_OPCODE)
+               add_prefix (prefix);
+           }
+         else
+           add_prefix ((i.tm.base_opcode >> 16) & 0xff);
+       }
 
       /* The prefix bytes.  */
       for (q = i.prefix;
@@ -3196,6 +3469,7 @@ output_insn ()
       else
        {
          p = frag_more (2);
+
          /* Put out high byte first: can't use md_number_to_chars!  */
          *p++ = (i.tm.base_opcode >> 8) & 0xff;
          *p = i.tm.base_opcode & 0xff;
@@ -3275,7 +3549,7 @@ output_disp (insn_start_frag, insn_start_off)
            }
          else
            {
-             RELOC_ENUM reloc_type;
+             enum bfd_reloc_code_real reloc_type;
              int size = 4;
              int sign = 0;
              int pcrel = (i.flags[n] & Operand_PCrel) != 0;
@@ -3319,15 +3593,16 @@ output_disp (insn_start_frag, insn_start_off)
 
              p = frag_more (size);
              reloc_type = reloc (size, pcrel, sign, i.reloc[n]);
-#ifdef BFD_ASSEMBLER
-             if (reloc_type == BFD_RELOC_32
-                 && GOT_symbol
+             if (GOT_symbol
                  && GOT_symbol == i.op[n].disps->X_add_symbol
-                 && (i.op[n].disps->X_op == O_symbol
-                     || (i.op[n].disps->X_op == O_add
-                         && ((symbol_get_value_expression
-                              (i.op[n].disps->X_op_symbol)->X_op)
-                             == O_subtract))))
+                 && (((reloc_type == BFD_RELOC_32
+                       || reloc_type == BFD_RELOC_X86_64_32S)
+                      && (i.op[n].disps->X_op == O_symbol
+                          || (i.op[n].disps->X_op == O_add
+                              && ((symbol_get_value_expression
+                                   (i.op[n].disps->X_op_symbol)->X_op)
+                                  == O_subtract))))
+                     || reloc_type == BFD_RELOC_32_PCREL))
                {
                  offsetT add;
 
@@ -3344,13 +3619,12 @@ output_disp (insn_start_frag, insn_start_off)
                      add += p - frag_now->fr_literal;
                    }
 
-                 /* We don't support dynamic linking on x86-64 yet.  */
-                 if (flag_code == CODE_64BIT)
-                   abort ();
-                 reloc_type = BFD_RELOC_386_GOTPC;
+                 if (!object_64bit)
+                   reloc_type = BFD_RELOC_386_GOTPC;
+                 else
+                   reloc_type = BFD_RELOC_X86_64_GOTPC32;
                  i.op[n].disps->X_add_number += add;
                }
-#endif
              fix_new_exp (frag_now, p - frag_now->fr_literal, size,
                           i.op[n].disps, pcrel, reloc_type);
            }
@@ -3395,12 +3669,13 @@ output_imm (insn_start_frag, insn_start_off)
                 Need a 32-bit fixup (don't support 8bit
                 non-absolute imms).  Try to support other
                 sizes ...  */
-             RELOC_ENUM reloc_type;
+             enum bfd_reloc_code_real reloc_type;
              int size = 4;
              int sign = 0;
 
              if ((i.types[n] & (Imm32S))
-                 && i.suffix == QWORD_MNEM_SUFFIX)
+                 && (i.suffix == QWORD_MNEM_SUFFIX
+                     || (!i.suffix && (i.tm.opcode_modifier & No_lSuf))))
                sign = 1;
              if (i.types[n] & (Imm8 | Imm8S | Imm16 | Imm64))
                {
@@ -3413,7 +3688,7 @@ output_imm (insn_start_frag, insn_start_off)
 
              p = frag_more (size);
              reloc_type = reloc (size, 0, sign, i.reloc[n]);
-#ifdef BFD_ASSEMBLER
+
              /*   This is tough to explain.  We end up with this one if we
               * have operands that look like
               * "_GLOBAL_OFFSET_TABLE_+[.-.L284]".  The goal here is to
@@ -3456,7 +3731,8 @@ output_imm (insn_start_frag, insn_start_off)
               * since the expression is not pcrel, I felt it would be
               * confusing to do it this way.  */
 
-             if (reloc_type == BFD_RELOC_32
+             if ((reloc_type == BFD_RELOC_32
+                  || reloc_type == BFD_RELOC_X86_64_32S)
                  && GOT_symbol
                  && GOT_symbol == i.op[n].imms->X_add_symbol
                  && (i.op[n].imms->X_op == O_symbol
@@ -3480,13 +3756,12 @@ output_imm (insn_start_frag, insn_start_off)
                      add += p - frag_now->fr_literal;
                    }
 
-                 /* We don't support dynamic linking on x86-64 yet.  */
-                 if (flag_code == CODE_64BIT)
-                   abort ();
-                 reloc_type = BFD_RELOC_386_GOTPC;
+                 if (!object_64bit)
+                   reloc_type = BFD_RELOC_386_GOTPC;
+                 else
+                   reloc_type = BFD_RELOC_X86_64_GOTPC32;
                  i.op[n].imms->X_add_number += add;
                }
-#endif
              fix_new_exp (frag_now, p - frag_now->fr_literal, size,
                           i.op[n].imms, 0, reloc_type);
            }
@@ -3494,9 +3769,35 @@ output_imm (insn_start_frag, insn_start_off)
     }
 }
 \f
-#ifndef LEX_AT
-static char *lex_got PARAMS ((RELOC_ENUM *, int *));
+/* x86_cons_fix_new is called via the expression parsing code when a
+   reloc is needed.  We use this hook to get the correct .got reloc.  */
+static enum bfd_reloc_code_real got_reloc = NO_RELOC;
+static int cons_sign = -1;
+
+void
+x86_cons_fix_new (fragS *frag,
+     unsigned int off,
+     unsigned int len,
+     expressionS *exp)
+{
+  enum bfd_reloc_code_real r = reloc (len, 0, cons_sign, got_reloc);
+
+  got_reloc = NO_RELOC;
 
+#ifdef TE_PE
+  if (exp->X_op == O_secrel)
+    {
+      exp->X_op = O_symbol;
+      r = BFD_RELOC_32_SECREL;
+    }
+#endif
+
+  fix_new_exp (frag, off, len, exp, 0, r);
+}
+
+#if (!defined (OBJ_ELF) && !defined (OBJ_MAYBE_ELF)) || defined (LEX_AT)
+# define lex_got(reloc, adjust, types) NULL
+#else
 /* Parse operands of the form
    <symbol>@GOTOFF+<nnn>
    and similar .plt or .got references.
@@ -3507,32 +3808,35 @@ static char *lex_got PARAMS ((RELOC_ENUM *, int *));
    is non-null set it to the length of the string we removed from the
    input line.  Otherwise return NULL.  */
 static char *
-lex_got (reloc, adjust)
-     RELOC_ENUM *reloc;
-     int *adjust;
+lex_got (enum bfd_reloc_code_real *reloc,
+     int *adjust,
+     unsigned int *types)
 {
-  static const char * const mode_name[NUM_FLAG_CODE] = { "32", "16", "64" };
   static const struct {
     const char *str;
-    const RELOC_ENUM rel[NUM_FLAG_CODE];
+    const enum bfd_reloc_code_real rel[2];
+    const unsigned int types64;
   } gotrel[] = {
-    { "PLT",      { BFD_RELOC_386_PLT32,      0, BFD_RELOC_X86_64_PLT32    } },
-    { "GOTOFF",   { BFD_RELOC_386_GOTOFF,     0, 0                         } },
-    { "GOTPCREL", { 0,                        0, BFD_RELOC_X86_64_GOTPCREL } },
-    { "TLSGD",    { BFD_RELOC_386_TLS_GD,     0, BFD_RELOC_X86_64_TLSGD    } },
-    { "TLSLDM",   { BFD_RELOC_386_TLS_LDM,    0, 0                         } },
-    { "TLSLD",    { 0,                        0, BFD_RELOC_X86_64_TLSLD    } },
-    { "GOTTPOFF", { BFD_RELOC_386_TLS_IE_32,  0, BFD_RELOC_X86_64_GOTTPOFF } },
-    { "TPOFF",    { BFD_RELOC_386_TLS_LE_32,  0, BFD_RELOC_X86_64_TPOFF32  } },
-    { "NTPOFF",   { BFD_RELOC_386_TLS_LE,     0, 0                         } },
-    { "DTPOFF",   { BFD_RELOC_386_TLS_LDO_32, 0, BFD_RELOC_X86_64_DTPOFF32 } },
-    { "GOTNTPOFF",{ BFD_RELOC_386_TLS_GOTIE,  0, 0                         } },
-    { "INDNTPOFF",{ BFD_RELOC_386_TLS_IE,     0, 0                         } },
-    { "GOT",      { BFD_RELOC_386_GOT32,      0, BFD_RELOC_X86_64_GOT32    } }
+    { "PLT",      { BFD_RELOC_386_PLT32,      BFD_RELOC_X86_64_PLT32    }, Imm32|Imm32S|Disp32 },
+    { "GOTOFF",   { BFD_RELOC_386_GOTOFF,     BFD_RELOC_X86_64_GOTOFF64 }, Imm64|Disp64 },
+    { "GOTPCREL", { 0,                        BFD_RELOC_X86_64_GOTPCREL }, Imm32|Imm32S|Disp32 },
+    { "TLSGD",    { BFD_RELOC_386_TLS_GD,     BFD_RELOC_X86_64_TLSGD    }, Imm32|Imm32S|Disp32 },
+    { "TLSLDM",   { BFD_RELOC_386_TLS_LDM,    0                         }, 0 },
+    { "TLSLD",    { 0,                        BFD_RELOC_X86_64_TLSLD    }, Imm32|Imm32S|Disp32 },
+    { "GOTTPOFF", { BFD_RELOC_386_TLS_IE_32,  BFD_RELOC_X86_64_GOTTPOFF }, Imm32|Imm32S|Disp32 },
+    { "TPOFF",    { BFD_RELOC_386_TLS_LE_32,  BFD_RELOC_X86_64_TPOFF32  }, Imm32|Imm32S|Imm64|Disp32|Disp64 },
+    { "NTPOFF",   { BFD_RELOC_386_TLS_LE,     0                         }, 0 },
+    { "DTPOFF",   { BFD_RELOC_386_TLS_LDO_32, BFD_RELOC_X86_64_DTPOFF32 }, Imm32|Imm32S|Imm64|Disp32|Disp64 },
+    { "GOTNTPOFF",{ BFD_RELOC_386_TLS_GOTIE,  0                         }, 0 },
+    { "INDNTPOFF",{ BFD_RELOC_386_TLS_IE,     0                         }, 0 },
+    { "GOT",      { BFD_RELOC_386_GOT32,      BFD_RELOC_X86_64_GOT32    }, Imm32|Imm32S|Disp32 }
   };
   char *cp;
   unsigned int j;
 
+  if (!IS_ELF)
+    return NULL;
+
   for (cp = input_line_pointer; *cp != '@'; cp++)
     if (is_end_of_line[(unsigned char) *cp])
       return NULL;
@@ -3544,15 +3848,23 @@ lex_got (reloc, adjust)
       len = strlen (gotrel[j].str);
       if (strncasecmp (cp + 1, gotrel[j].str, len) == 0)
        {
-         if (gotrel[j].rel[(unsigned int) flag_code] != 0)
+         if (gotrel[j].rel[object_64bit] != 0)
            {
              int first, second;
              char *tmpbuf, *past_reloc;
 
-             *reloc = gotrel[j].rel[(unsigned int) flag_code];
+             *reloc = gotrel[j].rel[object_64bit];
              if (adjust)
                *adjust = len;
 
+             if (types)
+               {
+                 if (flag_code != CODE_64BIT)
+                   *types = Imm32|Disp32;
+                 else
+                   *types = gotrel[j].types64;
+               }
+
              if (GOT_symbol == NULL)
                GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
 
@@ -3580,8 +3892,8 @@ lex_got (reloc, adjust)
              return tmpbuf;
            }
 
-         as_bad (_("@%s reloc is not supported in %s bit mode"),
-                 gotrel[j].str, mode_name[(unsigned int) flag_code]);
+         as_bad (_("@%s reloc is not supported with %d-bit output format"),
+                 gotrel[j].str, 1 << (5 + object_64bit));
          return NULL;
        }
     }
@@ -3590,28 +3902,12 @@ lex_got (reloc, adjust)
   return NULL;
 }
 
-/* x86_cons_fix_new is called via the expression parsing code when a
-   reloc is needed.  We use this hook to get the correct .got reloc.  */
-static RELOC_ENUM got_reloc = NO_RELOC;
-
-void
-x86_cons_fix_new (frag, off, len, exp)
-     fragS *frag;
-     unsigned int off;
-     unsigned int len;
-     expressionS *exp;
-{
-  RELOC_ENUM r = reloc (len, 0, 0, got_reloc);
-  got_reloc = NO_RELOC;
-  fix_new_exp (frag, off, len, exp, 0, r);
-}
-
 void
 x86_cons (exp, size)
      expressionS *exp;
      int size;
 {
-  if (size == 4)
+  if (size == 4 || (object_64bit && size == 8))
     {
       /* Handle @GOTOFF and the like in an expression.  */
       char *save;
@@ -3619,7 +3915,7 @@ x86_cons (exp, size)
       int adjust;
 
       save = input_line_pointer;
-      gotfree_input_line = lex_got (&got_reloc, &adjust);
+      gotfree_input_line = lex_got (&got_reloc, &adjust, NULL);
       if (gotfree_input_line)
        input_line_pointer = gotfree_input_line;
 
@@ -3641,18 +3937,47 @@ x86_cons (exp, size)
 }
 #endif
 
-static int i386_immediate PARAMS ((char *));
-
-static int
-i386_immediate (imm_start)
-     char *imm_start;
+static void signed_cons (int size)
 {
-  char *save_input_line_pointer;
-#ifndef LEX_AT
-  char *gotfree_input_line;
+  if (flag_code == CODE_64BIT)
+    cons_sign = 1;
+  cons (size);
+  cons_sign = -1;
+}
+
+#ifdef TE_PE
+static void
+pe_directive_secrel (dummy)
+     int dummy ATTRIBUTE_UNUSED;
+{
+  expressionS exp;
+
+  do
+    {
+      expression (&exp);
+      if (exp.X_op == O_symbol)
+       exp.X_op = O_secrel;
+
+      emit_expr (&exp, 4);
+    }
+  while (*input_line_pointer++ == ',');
+
+  input_line_pointer--;
+  demand_empty_rest_of_line ();
+}
 #endif
+
+static int i386_immediate PARAMS ((char *));
+
+static int
+i386_immediate (imm_start)
+     char *imm_start;
+{
+  char *save_input_line_pointer;
+  char *gotfree_input_line;
   segT exp_seg = 0;
   expressionS *exp;
+  unsigned int types = ~0U;
 
   if (i.imm_operands == MAX_IMMEDIATE_OPERANDS)
     {
@@ -3669,11 +3994,9 @@ i386_immediate (imm_start)
   save_input_line_pointer = input_line_pointer;
   input_line_pointer = imm_start;
 
-#ifndef LEX_AT
-  gotfree_input_line = lex_got (&i.reloc[this_operand], NULL);
+  gotfree_input_line = lex_got (&i.reloc[this_operand], NULL, &types);
   if (gotfree_input_line)
     input_line_pointer = gotfree_input_line;
-#endif
 
   exp_seg = expression (exp);
 
@@ -3682,10 +4005,8 @@ i386_immediate (imm_start)
     as_bad (_("junk `%s' after expression"), input_line_pointer);
 
   input_line_pointer = save_input_line_pointer;
-#ifndef LEX_AT
   if (gotfree_input_line)
     free (gotfree_input_line);
-#endif
 
   if (exp->X_op == O_absent || exp->X_op == O_big)
     {
@@ -3707,25 +4028,15 @@ i386_immediate (imm_start)
          exp->X_add_number = (exp->X_add_number ^ ((addressT) 1 << 31)) - ((addressT) 1 << 31);
     }
 #if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
-  else if (1
-#ifdef BFD_ASSEMBLER
-          && OUTPUT_FLAVOR == bfd_target_aout_flavour
-#endif
+  else if (OUTPUT_FLAVOR == bfd_target_aout_flavour
           && exp_seg != absolute_section
           && exp_seg != text_section
           && exp_seg != data_section
           && exp_seg != bss_section
           && exp_seg != undefined_section
-#ifdef BFD_ASSEMBLER
-          && !bfd_is_com_section (exp_seg)
-#endif
-          )
+          && !bfd_is_com_section (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
@@ -3735,6 +4046,7 @@ i386_immediate (imm_start)
         determined later, depending on destination register,
         suffix, or the default for the section.  */
       i.types[this_operand] |= Imm8 | Imm16 | Imm32 | Imm32S | Imm64;
+      i.types[this_operand] &= types;
     }
 
   return 1;
@@ -3754,7 +4066,6 @@ i386_scale (scale)
 
   switch (val)
     {
-    case 0:
     case 1:
       i.log2_scale_factor = 0;
       break;
@@ -3768,10 +4079,16 @@ i386_scale (scale)
       i.log2_scale_factor = 3;
       break;
     default:
-      as_bad (_("expecting scale factor of 1, 2, 4, or 8: got `%s'"),
-             scale);
-      input_line_pointer = save;
-      return NULL;
+      {
+       char sep = *input_line_pointer;
+
+       *input_line_pointer = '\0';
+       as_bad (_("expecting scale factor of 1, 2, 4, or 8: got `%s'"),
+               scale);
+       *input_line_pointer = sep;
+       input_line_pointer = save;
+       return NULL;
+      }
     }
   if (i.log2_scale_factor != 0 && i.index_reg == 0)
     {
@@ -3796,18 +4113,45 @@ i386_displacement (disp_start, disp_end)
   expressionS *exp;
   segT exp_seg = 0;
   char *save_input_line_pointer;
-#ifndef LEX_AT
   char *gotfree_input_line;
-#endif
-  int bigdisp = Disp32;
+  int bigdisp, override;
+  unsigned int types = Disp;
 
+  if ((i.types[this_operand] & JumpAbsolute)
+      || !(current_templates->start->opcode_modifier & (Jump | JumpDword)))
+    {
+      bigdisp = Disp32;
+      override = (i.prefix[ADDR_PREFIX] != 0);
+    }
+  else
+    {
+      /* For PC-relative branches, the width of the displacement
+        is dependent upon data size, not address size.  */
+      bigdisp = 0;
+      override = (i.prefix[DATA_PREFIX] != 0);
+    }
   if (flag_code == CODE_64BIT)
     {
-      if (i.prefix[ADDR_PREFIX] == 0)
-       bigdisp = Disp64;
+      if (!bigdisp)
+       bigdisp = (override || i.suffix == WORD_MNEM_SUFFIX)
+                 ? Disp16
+                 : Disp32S | Disp32;
+      else if (!override)
+       bigdisp = Disp64 | Disp32S | Disp32;
+    }
+  else
+    {
+      if (!bigdisp)
+       {
+         if (!override)
+           override = (i.suffix == (flag_code != CODE_16BIT
+                                    ? WORD_MNEM_SUFFIX
+                                    : LONG_MNEM_SUFFIX));
+         bigdisp = Disp32;
+       }
+      if ((flag_code == CODE_16BIT) ^ override)
+       bigdisp = Disp16;
     }
-  else if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0))
-    bigdisp = Disp16;
   i.types[this_operand] |= bigdisp;
 
   exp = &disp_expressions[i.disp_operands];
@@ -3861,11 +4205,9 @@ i386_displacement (disp_start, disp_end)
       *displacement_string_end = '0';
     }
 #endif
-#ifndef LEX_AT
-  gotfree_input_line = lex_got (&i.reloc[this_operand], NULL);
+  gotfree_input_line = lex_got (&i.reloc[this_operand], NULL, &types);
   if (gotfree_input_line)
     input_line_pointer = gotfree_input_line;
-#endif
 
   exp_seg = expression (exp);
 
@@ -3877,17 +4219,15 @@ i386_displacement (disp_start, disp_end)
 #endif
   RESTORE_END_STRING (disp_end);
   input_line_pointer = save_input_line_pointer;
-#ifndef LEX_AT
   if (gotfree_input_line)
     free (gotfree_input_line);
-#endif
 
-#ifdef BFD_ASSEMBLER
   /* We do this to make sure that the section symbol is in
      the symbol table.  We will ultimately change the relocation
      to be relative to the beginning of the section.  */
   if (i.reloc[this_operand] == BFD_RELOC_386_GOTOFF
-      || i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL)
+      || i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL
+      || i.reloc[this_operand] == BFD_RELOC_X86_64_GOTOFF64)
     {
       if (exp->X_op != O_symbol)
        {
@@ -3905,10 +4245,11 @@ i386_displacement (disp_start, disp_end)
       exp->X_op_symbol = GOT_symbol;
       if (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL)
        i.reloc[this_operand] = BFD_RELOC_32_PCREL;
+      else if (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTOFF64)
+       i.reloc[this_operand] = BFD_RELOC_64;
       else
        i.reloc[this_operand] = BFD_RELOC_32;
     }
-#endif
 
   if (exp->X_op == O_absent || exp->X_op == O_big)
     {
@@ -3923,29 +4264,22 @@ i386_displacement (disp_start, disp_end)
 
 #if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
   if (exp->X_op != O_constant
-#ifdef BFD_ASSEMBLER
       && OUTPUT_FLAVOR == bfd_target_aout_flavour
-#endif
       && exp_seg != absolute_section
       && exp_seg != text_section
       && exp_seg != data_section
       && exp_seg != bss_section
       && exp_seg != undefined_section
-#ifdef BFD_ASSEMBLER
-      && !bfd_is_com_section (exp_seg)
-#endif
-      )
+      && !bfd_is_com_section (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
-  else if (flag_code == CODE_64BIT)
-    i.types[this_operand] |= Disp32S | Disp32;
+
+  if (!(i.types[this_operand] & ~Disp))
+    i.types[this_operand] &= types;
+
   return 1;
 }
 
@@ -3965,30 +4299,41 @@ i386_index_check (operand_string)
  tryprefix:
 #endif
   ok = 1;
-  if (flag_code == CODE_64BIT)
-    {
-      if (i.prefix[ADDR_PREFIX] == 0)
-       {
-         /* 64bit checks.  */
-         if ((i.base_reg
-              && ((i.base_reg->reg_type & Reg64) == 0)
-                  && (i.base_reg->reg_type != BaseIndex
-                      || i.index_reg))
-             || (i.index_reg
-                 && ((i.index_reg->reg_type & (Reg64 | BaseIndex))
-                     != (Reg64 | BaseIndex))))
-           ok = 0;
-       }
+  if ((current_templates->start->cpu_flags & CpuSVME)
+      && current_templates->end[-1].operand_types[0] == AnyMem)
+    {
+      /* Memory operands of SVME insns are special in that they only allow
+        rAX as their memory address and ignore any segment override.  */
+      unsigned RegXX;
+
+      /* SKINIT is even more restrictive: it always requires EAX.  */
+      if (strcmp (current_templates->start->name, "skinit") == 0)
+       RegXX = Reg32;
+      else if (flag_code == CODE_64BIT)
+       RegXX = i.prefix[ADDR_PREFIX] == 0 ? Reg64 : Reg32;
       else
-       {
-         /* 32bit checks.  */
-         if ((i.base_reg
-              && (i.base_reg->reg_type & (Reg32 | RegRex)) != Reg32)
-             || (i.index_reg
-                 && ((i.index_reg->reg_type & (Reg32 | BaseIndex | RegRex))
-                     != (Reg32 | BaseIndex))))
-           ok = 0;
-       }
+       RegXX = (flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0)
+               ? Reg16
+               : Reg32;
+      if (!i.base_reg
+         || !(i.base_reg->reg_type & Acc)
+         || !(i.base_reg->reg_type & RegXX)
+         || i.index_reg
+         || (i.types[0] & Disp))
+       ok = 0;
+    }
+  else if (flag_code == CODE_64BIT)
+     {
+       unsigned RegXX = (i.prefix[ADDR_PREFIX] == 0 ? Reg64 : Reg32);
+
+       if ((i.base_reg
+           && ((i.base_reg->reg_type & RegXX) == 0)
+           && (i.base_reg->reg_type != BaseIndex
+               || i.index_reg))
+          || (i.index_reg
+              && ((i.index_reg->reg_type & (RegXX | BaseIndex))
+                  != (RegXX | BaseIndex))))
+        ok = 0;
     }
   else
     {
@@ -4021,8 +4366,7 @@ i386_index_check (operand_string)
   if (!ok)
     {
 #if INFER_ADDR_PREFIX
-      if (flag_code != CODE_64BIT
-         && i.prefix[ADDR_PREFIX] == 0 && stackop_size != '\0')
+      if (i.prefix[ADDR_PREFIX] == 0)
        {
          i.prefix[ADDR_PREFIX] = ADDR_PREFIX_OPCODE;
          i.prefixes += 1;
@@ -4031,7 +4375,7 @@ i386_index_check (operand_string)
             FIXME.  There doesn't seem to be any real need for separate
             Disp16 and Disp32 flags.  The same goes for Imm16 and Imm32.
             Removing them would probably clean up the code quite a lot.  */
-         if (i.types[this_operand] & (Disp16 | Disp32))
+         if (flag_code != CODE_64BIT && (i.types[this_operand] & (Disp16 | Disp32)))
             i.types[this_operand] ^= (Disp16 | Disp32);
          fudged = 1;
          goto tryprefix;
@@ -4044,9 +4388,8 @@ i386_index_check (operand_string)
        as_bad (_("`%s' is not a valid %s bit base/index expression"),
                operand_string,
                flag_code_names[flag_code]);
-      return 0;
     }
-  return 1;
+  return ok;
 }
 
 /* Parse OPERAND_STRING into the i386_insn structure I.  Returns non-zero
@@ -4074,8 +4417,7 @@ i386_operand (operand_string)
     }
 
   /* Check if operand is a register.  */
-  if ((*op_string == REGISTER_PREFIX || allow_naked_reg)
-      && (r = parse_register (op_string, &end_op)) != NULL)
+  if ((r = parse_register (op_string, &end_op)) != NULL)
     {
       /* Check for a segment override by searching for ':' after a
         segment register.  */
@@ -4213,8 +4555,7 @@ i386_operand (operand_string)
            ++base_string;
 
          if (*base_string == ','
-             || ((*base_string == REGISTER_PREFIX || allow_naked_reg)
-                 && (i.base_reg = parse_register (base_string, &end_op)) != NULL))
+             || ((i.base_reg = parse_register (base_string, &end_op)) != NULL))
            {
              displacement_string_end = temp_string;
 
@@ -4234,8 +4575,7 @@ i386_operand (operand_string)
                  if (is_space_char (*base_string))
                    ++base_string;
 
-                 if ((*base_string == REGISTER_PREFIX || allow_naked_reg)
-                     && (i.index_reg = parse_register (base_string, &end_op)) != NULL)
+                 if ((i.index_reg = parse_register (base_string, &end_op)) != NULL)
                    {
                      base_string = end_op;
                      if (is_space_char (*base_string))
@@ -4360,7 +4700,7 @@ md_estimate_size_before_relax (fragP, segment)
      shared library.  */
   if (S_GET_SEGMENT (fragP->fr_symbol) != segment
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
-      || (OUTPUT_FLAVOR == bfd_target_elf_flavour
+      || (IS_ELF
          && (S_IS_EXTERNAL (fragP->fr_symbol)
              || S_IS_WEAK (fragP->fr_symbol)))
 #endif
@@ -4369,7 +4709,7 @@ md_estimate_size_before_relax (fragP, segment)
       /* Symbol is undefined in this segment, or we need to keep a
         reloc so that weak symbols can be overridden.  */
       int size = (fragP->fr_subtype & CODE16) ? 2 : 4;
-      RELOC_ENUM reloc_type;
+      enum bfd_reloc_code_real reloc_type;
       unsigned char *opcode;
       int old_fr_fix;
 
@@ -4468,19 +4808,11 @@ md_estimate_size_before_relax (fragP, segment)
    Out:        Any fixSs and constants are set up.
        Caller will turn frag into a ".space 0".  */
 
-#ifndef BFD_ASSEMBLER
-void
-md_convert_frag (headers, sec, fragP)
-     object_headers *headers ATTRIBUTE_UNUSED;
-     segT sec ATTRIBUTE_UNUSED;
-     fragS *fragP;
-#else
 void
 md_convert_frag (abfd, sec, fragP)
      bfd *abfd ATTRIBUTE_UNUSED;
      segT sec ATTRIBUTE_UNUSED;
      fragS *fragP;
-#endif
 {
   unsigned char *opcode;
   unsigned char *where_to_put_displacement = NULL;
@@ -4568,9 +4900,6 @@ int md_short_jump_size = 2;
 /* Size of dword displacement jmp.  */
 int md_long_jump_size = 5;
 
-/* Size of relocation record.  */
-const int md_reloc_size = 8;
-
 void
 md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
      char *ptr;
@@ -4608,7 +4937,7 @@ md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
    we are handling.  */
 
 void
-md_apply_fix3 (fixP, valP, seg)
+md_apply_fix (fixP, valP, seg)
      /* The fix we're to put in.  */
      fixS *fixP;
      /* Pointer to the value of the bits.  */
@@ -4619,7 +4948,7 @@ md_apply_fix3 (fixP, valP, seg)
   char *p = fixP->fx_where + fixP->fx_frag->fr_literal;
   valueT value = *valP;
 
-#if defined (BFD_ASSEMBLER) && !defined (TE_Mach)
+#if !defined (TE_Mach)
   if (fixP->fx_pcrel)
     {
       switch (fixP->fx_r_type)
@@ -4627,7 +4956,11 @@ md_apply_fix3 (fixP, valP, seg)
        default:
          break;
 
+       case BFD_RELOC_64:
+         fixP->fx_r_type = BFD_RELOC_64_PCREL;
+         break;
        case BFD_RELOC_32:
+       case BFD_RELOC_X86_64_32S:
          fixP->fx_r_type = BFD_RELOC_32_PCREL;
          break;
        case BFD_RELOC_16:
@@ -4641,6 +4974,7 @@ md_apply_fix3 (fixP, valP, seg)
 
   if (fixP->fx_addsy != NULL
       && (fixP->fx_r_type == BFD_RELOC_32_PCREL
+         || fixP->fx_r_type == BFD_RELOC_64_PCREL
          || fixP->fx_r_type == BFD_RELOC_16_PCREL
          || fixP->fx_r_type == BFD_RELOC_8_PCREL)
       && !use_rela_relocations)
@@ -4650,7 +4984,7 @@ md_apply_fix3 (fixP, valP, seg)
         subtract the current location (for partial_inplace, PC relative
         relocations); see more below.  */
 #ifndef OBJ_AOUT
-      if (OUTPUT_FLAVOR == bfd_target_elf_flavour
+      if (IS_ELF
 #ifdef TE_PE
          || OUTPUT_FLAVOR == bfd_target_coff_flavour
 #endif
@@ -4658,7 +4992,7 @@ 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)
+      if (IS_ELF)
        {
          segT sym_seg = S_GET_SEGMENT (fixP->fx_addsy);
 
@@ -4676,18 +5010,18 @@ md_apply_fix3 (fixP, valP, seg)
        }
 #endif
 #if defined (OBJ_COFF) && defined (TE_PE)
-      /* For some reason, the PE format does not store a section
-        address offset for a PC relative symbol.  */
-      if (S_GET_SEGMENT (fixP->fx_addsy) != seg)
+      /* For some reason, the PE format does not store a
+        section address offset for a PC relative symbol.  */
+      if (S_GET_SEGMENT (fixP->fx_addsy) != seg
+         || S_IS_WEAK (fixP->fx_addsy))
        value += md_pcrel_from (fixP);
 #endif
     }
 
   /* Fix a few things - the dynamic linker expects certain values here,
-     and we must not dissappoint it.  */
+     and we must not disappoint it.  */
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
-  if (OUTPUT_FLAVOR == bfd_target_elf_flavour
-      && fixP->fx_addsy)
+  if (IS_ELF && fixP->fx_addsy)
     switch (fixP->fx_r_type)
       {
       case BFD_RELOC_386_PLT32:
@@ -4711,7 +5045,9 @@ md_apply_fix3 (fixP, valP, seg)
       case BFD_RELOC_386_TLS_LDO_32:
       case BFD_RELOC_386_TLS_LE_32:
       case BFD_RELOC_X86_64_DTPOFF32:
+      case BFD_RELOC_X86_64_DTPOFF64:
       case BFD_RELOC_X86_64_TPOFF32:
+      case BFD_RELOC_X86_64_TPOFF64:
        S_SET_THREAD_LOCAL (fixP->fx_addsy);
        break;
 
@@ -4730,12 +5066,11 @@ md_apply_fix3 (fixP, valP, seg)
       }
 #endif /* defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)  */
   *valP = value;
-#endif /* defined (BFD_ASSEMBLER) && !defined (TE_Mach)  */
+#endif /* !defined (TE_Mach)  */
 
   /* Are we finished with this relocation now?  */
   if (fixP->fx_addsy == NULL)
     fixP->fx_done = 1;
-#ifdef BFD_ASSEMBLER
   else if (use_rela_relocations)
     {
       fixP->fx_no_overflow = 1;
@@ -4743,7 +5078,7 @@ md_apply_fix3 (fixP, valP, seg)
       fixP->fx_addnumber = value;
       value = 0;
     }
-#endif
+
   md_number_to_chars (p, value, fixP->fx_size);
 }
 \f
@@ -4801,7 +5136,7 @@ md_atof (type, litP, sizeP)
   return 0;
 }
 \f
-char output_invalid_buf[8];
+static char output_invalid_buf[8];
 
 static char *
 output_invalid (c)
@@ -4817,9 +5152,7 @@ output_invalid (c)
 /* REG_STRING starts *before* REGISTER_PREFIX.  */
 
 static const reg_entry *
-parse_register (reg_string, end_op)
-     char *reg_string;
-     char **end_op;
+parse_real_register (char *reg_string, char **end_op)
 {
   char *s = reg_string;
   char *p;
@@ -4879,28 +5212,104 @@ parse_register (reg_string, end_op)
     }
 
   if (r != NULL
-      && (r->reg_flags & (RegRex64 | RegRex)) != 0
+      && ((r->reg_flags & (RegRex64 | RegRex)) | (r->reg_type & Reg64)) != 0
+      && (r->reg_type != Control || !(cpu_arch_flags & CpuSledgehammer))
       && flag_code != CODE_64BIT)
+    return (const reg_entry *) NULL;
+
+  return r;
+}
+
+/* REG_STRING starts *before* REGISTER_PREFIX.  */
+
+static const reg_entry *
+parse_register (char *reg_string, char **end_op)
+{
+  const reg_entry *r;
+
+  if (*reg_string == REGISTER_PREFIX || allow_naked_reg)
+    r = parse_real_register (reg_string, end_op);
+  else
+    r = NULL;
+  if (!r)
     {
-      return (const reg_entry *) NULL;
-    }
+      char *save = input_line_pointer;
+      char c;
+      symbolS *symbolP;
 
+      input_line_pointer = reg_string;
+      c = get_symbol_end ();
+      symbolP = symbol_find (reg_string);
+      if (symbolP && S_GET_SEGMENT (symbolP) == reg_section)
+       {
+         const expressionS *e = symbol_get_value_expression (symbolP);
+
+         know (e->X_op == O_register);
+         know (e->X_add_number >= 0 && (valueT) e->X_add_number < ARRAY_SIZE (i386_regtab));
+         r = i386_regtab + e->X_add_number;
+         *end_op = input_line_pointer;
+       }
+      *input_line_pointer = c;
+      input_line_pointer = save;
+    }
   return r;
 }
+
+int
+i386_parse_name (char *name, expressionS *e, char *nextcharP)
+{
+  const reg_entry *r;
+  char *end = input_line_pointer;
+
+  *end = *nextcharP;
+  r = parse_register (name, &input_line_pointer);
+  if (r && end <= input_line_pointer)
+    {
+      *nextcharP = *input_line_pointer;
+      *input_line_pointer = 0;
+      e->X_op = O_register;
+      e->X_add_number = r - i386_regtab;
+      return 1;
+    }
+  input_line_pointer = end;
+  *end = 0;
+  return 0;
+}
+
+void
+md_operand (expressionS *e)
+{
+  if (*input_line_pointer == REGISTER_PREFIX)
+    {
+      char *end;
+      const reg_entry *r = parse_real_register (input_line_pointer, &end);
+
+      if (r)
+       {
+         e->X_op = O_register;
+         e->X_add_number = r - i386_regtab;
+         input_line_pointer = end;
+       }
+    }
+}
+
 \f
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
-const char *md_shortopts = "kVQ:sq";
+const char *md_shortopts = "kVQ:sqn";
 #else
-const char *md_shortopts = "q";
+const char *md_shortopts = "qn";
 #endif
 
-struct option md_longopts[] = {
 #define OPTION_32 (OPTION_MD_BASE + 0)
+#define OPTION_64 (OPTION_MD_BASE + 1)
+#define OPTION_DIVIDE (OPTION_MD_BASE + 2)
+
+struct option md_longopts[] = {
   {"32", no_argument, NULL, OPTION_32},
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
-#define OPTION_64 (OPTION_MD_BASE + 1)
   {"64", no_argument, NULL, OPTION_64},
 #endif
+  {"divide", no_argument, NULL, OPTION_DIVIDE},
   {NULL, no_argument, NULL, 0}
 };
 size_t md_longopts_size = sizeof (md_longopts);
@@ -4912,6 +5321,10 @@ md_parse_option (c, arg)
 {
   switch (c)
     {
+    case 'n':
+      optimize_align_code = 0;
+      break;
+
     case 'q':
       quiet_warnings = 1;
       break;
@@ -4958,6 +5371,23 @@ md_parse_option (c, arg)
       default_arch = "i386";
       break;
 
+    case OPTION_DIVIDE:
+#ifdef SVR4_COMMENT_CHARS
+      {
+       char *n, *t;
+       const char *s;
+
+       n = (char *) xmalloc (strlen (i386_comment_chars) + 1);
+       t = n;
+       for (s = i386_comment_chars; *s != '\0'; s++)
+         if (*s != '/')
+           *t++ = *s;
+       *t = '\0';
+       i386_comment_chars = n;
+      }
+#endif
+      break;
+
     default:
       return 0;
     }
@@ -4972,16 +5402,24 @@ md_show_usage (stream)
   fprintf (stream, _("\
   -Q                      ignored\n\
   -V                      print assembler version number\n\
-  -k                      ignored\n\
-  -q                      quieten some warnings\n\
+  -k                      ignored\n"));
+#endif
+  fprintf (stream, _("\
+  -n                      Do not optimize code alignment\n\
+  -q                      quieten some warnings\n"));
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+  fprintf (stream, _("\
   -s                      ignored\n"));
+#endif
+#ifdef SVR4_COMMENT_CHARS
+  fprintf (stream, _("\
+  --divide                do not treat `/' as a comment character\n"));
 #else
   fprintf (stream, _("\
-  -q                      quieten some warnings\n"));
+  --divide                ignored\n"));
 #endif
 }
 
-#ifdef BFD_ASSEMBLER
 #if ((defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT)) \
      || defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF))
 
@@ -5010,7 +5448,10 @@ i386_target_format ()
     case bfd_target_elf_flavour:
       {
        if (flag_code == CODE_64BIT)
-         use_rela_relocations = 1;
+         {
+           object_64bit = 1;
+           use_rela_relocations = 1;
+         }
        return flag_code == CODE_64BIT ? "elf64-x86-64" : ELF_TARGET_FORMAT;
       }
 #endif
@@ -5025,8 +5466,7 @@ i386_target_format ()
 #if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF))
 void i386_elf_emit_arch_note ()
 {
-  if (OUTPUT_FLAVOR == bfd_target_elf_flavour
-      && cpu_arch_name != NULL)
+  if (IS_ELF && cpu_arch_name != NULL)
     {
       char *p;
       asection *seg = now_seg;
@@ -5063,7 +5503,6 @@ void i386_elf_emit_arch_note ()
     }
 }
 #endif
-#endif /* BFD_ASSEMBLER  */
 \f
 symbolS *
 md_undefined_symbol (name)
@@ -5093,7 +5532,6 @@ md_section_align (segment, size)
      segT segment ATTRIBUTE_UNUSED;
      valueT size;
 {
-#ifdef BFD_ASSEMBLER
 #if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT))
   if (OUTPUT_FLAVOR == bfd_target_aout_flavour)
     {
@@ -5107,7 +5545,6 @@ md_section_align (segment, size)
       align = bfd_get_section_alignment (stdoutput, segment);
       size = ((size + (1 << align) - 1) & ((valueT) -1 << align));
     }
-#endif
 #endif
 
   return size;
@@ -5132,6 +5569,10 @@ s_bss (ignore)
 {
   int temp;
 
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+  if (IS_ELF)
+    obj_elf_section_change_hook ();
+#endif
   temp = get_absolute_expression ();
   subseg_set (bss_section, (subsegT) temp);
   demand_empty_rest_of_line ();
@@ -5139,26 +5580,24 @@ s_bss (ignore)
 
 #endif
 
-#ifdef BFD_ASSEMBLER
-
 void
 i386_validate_fix (fixp)
      fixS *fixp;
 {
   if (fixp->fx_subsy && fixp->fx_subsy == GOT_symbol)
     {
-      /* GOTOFF relocation are nonsense in 64bit mode.  */
       if (fixp->fx_r_type == BFD_RELOC_32_PCREL)
        {
-         if (flag_code != CODE_64BIT)
+         if (!object_64bit)
            abort ();
          fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL;
        }
       else
        {
-         if (flag_code == CODE_64BIT)
-           abort ();
-         fixp->fx_r_type = BFD_RELOC_386_GOTOFF;
+         if (!object_64bit)
+           fixp->fx_r_type = BFD_RELOC_386_GOTOFF;
+         else
+           fixp->fx_r_type = BFD_RELOC_X86_64_GOTOFF64;
        }
       fixp->fx_subsy = 0;
     }
@@ -5189,17 +5628,30 @@ tc_gen_reloc (section, fixp)
     case BFD_RELOC_386_TLS_GOTIE:
     case BFD_RELOC_386_TLS_LE_32:
     case BFD_RELOC_386_TLS_LE:
-    case BFD_RELOC_X86_64_32S:
     case BFD_RELOC_X86_64_TLSGD:
     case BFD_RELOC_X86_64_TLSLD:
     case BFD_RELOC_X86_64_DTPOFF32:
+    case BFD_RELOC_X86_64_DTPOFF64:
     case BFD_RELOC_X86_64_GOTTPOFF:
     case BFD_RELOC_X86_64_TPOFF32:
+    case BFD_RELOC_X86_64_TPOFF64:
+    case BFD_RELOC_X86_64_GOTOFF64:
+    case BFD_RELOC_X86_64_GOTPC32:
     case BFD_RELOC_RVA:
     case BFD_RELOC_VTABLE_ENTRY:
     case BFD_RELOC_VTABLE_INHERIT:
+#ifdef TE_PE
+    case BFD_RELOC_32_SECREL:
+#endif
       code = fixp->fx_r_type;
       break;
+    case BFD_RELOC_X86_64_32S:
+      if (!fixp->fx_pcrel)
+       {
+         /* Don't turn BFD_RELOC_X86_64_32S into BFD_RELOC_32.  */
+         code = fixp->fx_r_type;
+         break;
+       }
     default:
       if (fixp->fx_pcrel)
        {
@@ -5214,6 +5666,9 @@ tc_gen_reloc (section, fixp)
            case 1: code = BFD_RELOC_8_PCREL;  break;
            case 2: code = BFD_RELOC_16_PCREL; break;
            case 4: code = BFD_RELOC_32_PCREL; break;
+#ifdef BFD64
+           case 8: code = BFD_RELOC_64_PCREL; break;
+#endif
            }
        }
       else
@@ -5237,14 +5692,16 @@ tc_gen_reloc (section, fixp)
       break;
     }
 
-  if (code == BFD_RELOC_32
+  if ((code == BFD_RELOC_32
+       || code == BFD_RELOC_32_PCREL
+       || code == BFD_RELOC_X86_64_32S)
       && GOT_symbol
       && fixp->fx_addsy == GOT_symbol)
     {
-      /* We don't support GOTPC on 64bit targets.  */
-      if (flag_code == CODE_64BIT)
-       abort ();
-      code = BFD_RELOC_386_GOTPC;
+      if (!object_64bit)
+       code = BFD_RELOC_386_GOTPC;
+      else
+       code = BFD_RELOC_X86_64_GOTPC32;
     }
 
   rel = (arelent *) xmalloc (sizeof (arelent));
@@ -5252,6 +5709,7 @@ tc_gen_reloc (section, fixp)
   *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
 
   rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
+
   if (!use_rela_relocations)
     {
       /* HACK: Since i386 ELF uses Rel instead of Rela, encode the
@@ -5300,73 +5758,6 @@ tc_gen_reloc (section, fixp)
   return rel;
 }
 
-#else /* !BFD_ASSEMBLER  */
-
-#if (defined(OBJ_AOUT) | defined(OBJ_BOUT))
-void
-tc_aout_fix_to_chars (where, fixP, segment_address_in_file)
-     char *where;
-     fixS *fixP;
-     relax_addressT segment_address_in_file;
-{
-  /* In:  length of relocation (or of address) in chars: 1, 2 or 4.
-     Out: GNU LD relocation length code: 0, 1, or 2.  */
-
-  static const unsigned char nbytes_r_length[] = { 42, 0, 1, 42, 2 };
-  long r_symbolnum;
-
-  know (fixP->fx_addsy != NULL);
-
-  md_number_to_chars (where,
-                     (valueT) (fixP->fx_frag->fr_address
-                               + fixP->fx_where - segment_address_in_file),
-                     4);
-
-  r_symbolnum = (S_IS_DEFINED (fixP->fx_addsy)
-                ? S_GET_TYPE (fixP->fx_addsy)
-                : fixP->fx_addsy->sy_number);
-
-  where[6] = (r_symbolnum >> 16) & 0x0ff;
-  where[5] = (r_symbolnum >> 8) & 0x0ff;
-  where[4] = r_symbolnum & 0x0ff;
-  where[7] = ((((!S_IS_DEFINED (fixP->fx_addsy)) << 3) & 0x08)
-             | ((nbytes_r_length[fixP->fx_size] << 1) & 0x06)
-             | (((fixP->fx_pcrel << 0) & 0x01) & 0x0f));
-}
-
-#endif /* OBJ_AOUT or OBJ_BOUT.  */
-
-#if defined (I386COFF)
-
-short
-tc_coff_fix2rtype (fixP)
-     fixS *fixP;
-{
-  if (fixP->fx_r_type == R_IMAGEBASE)
-    return R_IMAGEBASE;
-
-  return (fixP->fx_pcrel ?
-         (fixP->fx_size == 1 ? R_PCRBYTE :
-          fixP->fx_size == 2 ? R_PCRWORD :
-          R_PCRLONG) :
-         (fixP->fx_size == 1 ? R_RELBYTE :
-          fixP->fx_size == 2 ? R_RELWORD :
-          R_DIR32));
-}
-
-int
-tc_coff_sizemachdep (frag)
-     fragS *frag;
-{
-  if (frag->fr_next)
-    return (frag->fr_next->fr_address - frag->fr_address);
-  else
-    return 0;
-}
-
-#endif /* I386COFF  */
-
-#endif /* !BFD_ASSEMBLER  */
 \f
 /* Parse operands using Intel syntax. This implements a recursive descent
    parser based on the BNF grammar published in Appendix B of the MASM 6.1
@@ -5387,11 +5778,13 @@ tc_coff_sizemachdep (frag)
 
     alpha              [a-zA-Z]
 
+    binOp              & | AND | \| | OR | ^ | XOR
+
     byteRegister       AL | AH | BL | BH | CL | CH | DL | DH
 
     constant           digits [[ radixOverride ]]
 
-    dataType           BYTE | WORD | DWORD | QWORD | XWORD
+    dataType           BYTE | WORD | DWORD | FWORD | QWORD | TBYTE | OWORD | XMMWORD
 
     digits             decdigit
                        | digits decdigit
@@ -5399,13 +5792,21 @@ tc_coff_sizemachdep (frag)
 
     decdigit           [0-9]
 
-    e05                        e05 addOp e06
+    e04                        e04 addOp e05
+                       | e05
+
+    e05                        e05 binOp e06
                        | e06
 
     e06                        e06 mulOp e09
                        | e09
 
     e09                        OFFSET e10
+                       | SHORT e10
+                       | + e10
+                       | - e10
+                       | ~ e10
+                       | NOT e10
                        | e09 PTR e10
                        | e09 : e10
                        | e10
@@ -5421,8 +5822,8 @@ tc_coff_sizemachdep (frag)
                        | $
                        | register
 
- => expr               SHORT e05
-                       | e05
+ => expr               expr cmpOp e04
+                       | e04
 
     gpRegister         AX | EAX | BX | EBX | CX | ECX | DX | EDX
                        | BP | EBP | SP | ESP | DI | EDI | SI | ESI
@@ -5434,7 +5835,7 @@ tc_coff_sizemachdep (frag)
                        | id alpha
                        | id decdigit
 
-    mulOp              * | / | MOD
+    mulOp              * | / | % | MOD | << | SHL | >> | SHR
 
     quote              " | '
 
@@ -5444,7 +5845,7 @@ tc_coff_sizemachdep (frag)
 
     segmentRegister    CS | DS | ES | FS | GS | SS
 
-    specialRegister    CR0 | CR2 | CR3
+    specialRegister    CR0 | CR2 | CR3 | CR4
                        | DR0 | DR1 | DR2 | DR3 | DR6 | DR7
                        | TR3 | TR4 | TR5 | TR6 | TR7
 
@@ -5452,12 +5853,19 @@ tc_coff_sizemachdep (frag)
     done by calling parse_register) and eliminate immediate left recursion
     to implement a recursive-descent parser.
 
-    expr       SHORT e05
-               | e05
+    expr       e04 expr'
+
+    expr'      cmpOp e04 expr'
+               | Empty
+
+    e04                e05 e04'
+
+    e04'       addOp e05 e04'
+               | Empty
 
     e05                e06 e05'
 
-    e05'       addOp e06 e05'
+    e05'       binOp e06 e05'
                | Empty
 
     e06                e09 e06'
@@ -5466,6 +5874,11 @@ tc_coff_sizemachdep (frag)
                | Empty
 
     e09                OFFSET e10 e09'
+               | SHORT e10'
+               | + e10'
+               | - e10'
+               | ~ e10'
+               | NOT e10'
                | e10 e09'
 
     e09'       PTR e10 e09'
@@ -5482,8 +5895,11 @@ tc_coff_sizemachdep (frag)
                | BYTE
                | WORD
                | DWORD
+               | FWORD
                | QWORD
-               | XWORD
+               | TBYTE
+               | OWORD
+               | XMMWORD
                | .
                | $
                | register
@@ -5498,8 +5914,11 @@ struct intel_parser_s
     int got_a_float;           /* Whether the operand is a float.  */
     int op_modifier;           /* Operand modifier.  */
     int is_mem;                        /* 1 if operand is memory reference.  */
+    int in_offset;                     /* >=1 if parsing operand of offset.  */
+    int in_bracket;                    /* >=1 if parsing operand in brackets.  */
     const reg_entry *reg;      /* Last register reference found.  */
     char *disp;                        /* Displacement string being built.  */
+    char *next_operand;                /* Resume point when splitting operands.  */
   };
 
 static struct intel_parser_s intel_parser;
@@ -5521,28 +5940,30 @@ static struct intel_token cur_token, prev_token;
 #define T_REG          2
 #define T_BYTE         3
 #define T_WORD         4
-#define        T_DWORD         5
-#define T_QWORD                6
-#define T_XWORD                7
+#define T_DWORD                5
+#define T_FWORD                6
+#define T_QWORD                7
+#define T_TBYTE                8
+#define T_XMMWORD      9
 #undef  T_SHORT
-#define T_SHORT                8
-#define T_OFFSET       9
-#define T_PTR          10
-#define T_ID           11
+#define T_SHORT                10
+#define T_OFFSET       11
+#define T_PTR          12
+#define T_ID           13
+#define T_SHL          14
+#define T_SHR          15
 
 /* Prototypes for intel parser functions.  */
 static int intel_match_token   PARAMS ((int code));
 static void intel_get_token    PARAMS ((void));
 static void intel_putback_token        PARAMS ((void));
 static int intel_expr          PARAMS ((void));
+static int intel_e04           PARAMS ((void));
 static int intel_e05           PARAMS ((void));
-static int intel_e05_1         PARAMS ((void));
 static int intel_e06           PARAMS ((void));
-static int intel_e06_1         PARAMS ((void));
 static int intel_e09           PARAMS ((void));
-static int intel_e09_1         PARAMS ((void));
+static int intel_bracket_expr  PARAMS ((void));
 static int intel_e10           PARAMS ((void));
-static int intel_e10_1         PARAMS ((void));
 static int intel_e11           PARAMS ((void));
 
 static int
@@ -5553,34 +5974,42 @@ i386_intel_operand (operand_string, got_a_float)
   int ret;
   char *p;
 
-  /* Initialize token holders.  */
-  cur_token.code = prev_token.code = T_NIL;
-  cur_token.reg = prev_token.reg = NULL;
-  cur_token.str = prev_token.str = NULL;
-
-  /* Initialize parser structure.  */
-  p = intel_parser.op_string = (char *) malloc (strlen (operand_string) + 1);
-  if (p == NULL)
-    abort ();
-  strcpy (intel_parser.op_string, operand_string);
-  intel_parser.got_a_float = got_a_float;
-  intel_parser.op_modifier = -1;
-  intel_parser.is_mem = 0;
-  intel_parser.reg = NULL;
-  intel_parser.disp = (char *) malloc (strlen (operand_string) + 1);
-  if (intel_parser.disp == NULL)
-    abort ();
-  intel_parser.disp[0] = '\0';
-
-  /* Read the first token and start the parser.  */
-  intel_get_token ();
-  ret = intel_expr ();
-
-  if (ret)
+  p = intel_parser.op_string = xstrdup (operand_string);
+  intel_parser.disp = (char *) xmalloc (strlen (operand_string) + 1);
+
+  for (;;)
     {
+      /* Initialize token holders.  */
+      cur_token.code = prev_token.code = T_NIL;
+      cur_token.reg = prev_token.reg = NULL;
+      cur_token.str = prev_token.str = NULL;
+
+      /* Initialize parser structure.  */
+      intel_parser.got_a_float = got_a_float;
+      intel_parser.op_modifier = 0;
+      intel_parser.is_mem = 0;
+      intel_parser.in_offset = 0;
+      intel_parser.in_bracket = 0;
+      intel_parser.reg = NULL;
+      intel_parser.disp[0] = '\0';
+      intel_parser.next_operand = NULL;
+
+      /* Read the first token and start the parser.  */
+      intel_get_token ();
+      ret = intel_expr ();
+
+      if (!ret)
+       break;
+
+      if (cur_token.code != T_NIL)
+       {
+         as_bad (_("invalid operand for '%s' ('%s' unexpected)"),
+                 current_templates->start->name, cur_token.str);
+         ret = 0;
+       }
       /* If we found a memory reference, hand it over to i386_displacement
         to fill in the rest of the operand fields.  */
-      if (intel_parser.is_mem)
+      else if (intel_parser.is_mem)
        {
          if ((i.mem_operands == 1
               && (current_templates->start->opcode_modifier & IsString) == 0)
@@ -5595,17 +6024,46 @@ i386_intel_operand (operand_string, got_a_float)
              char *s = intel_parser.disp;
              i.mem_operands++;
 
+             if (!quiet_warnings && intel_parser.is_mem < 0)
+               /* See the comments in intel_bracket_expr.  */
+               as_warn (_("Treating `%s' as memory reference"), operand_string);
+
              /* Add the displacement expression.  */
              if (*s != '\0')
-               ret = i386_displacement (s, s + strlen (s))
-                     && i386_index_check (s);
+               ret = i386_displacement (s, s + strlen (s));
+             if (ret)
+               {
+                 /* Swap base and index in 16-bit memory operands like
+                    [si+bx]. Since i386_index_check is also used in AT&T
+                    mode we have to do that here.  */
+                 if (i.base_reg
+                     && i.index_reg
+                     && (i.base_reg->reg_type & Reg16)
+                     && (i.index_reg->reg_type & Reg16)
+                     && i.base_reg->reg_num >= 6
+                     && i.index_reg->reg_num < 6)
+                   {
+                     const reg_entry *base = i.index_reg;
+
+                     i.index_reg = i.base_reg;
+                     i.base_reg = base;
+                   }
+                 ret = i386_index_check (operand_string);
+               }
            }
        }
 
       /* Constant and OFFSET expressions are handled by i386_immediate.  */
-      else if (intel_parser.op_modifier == OFFSET_FLAT
+      else if ((intel_parser.op_modifier & (1 << T_OFFSET))
               || intel_parser.reg == NULL)
        ret = i386_immediate (intel_parser.disp);
+
+      if (intel_parser.next_operand && this_operand >= MAX_OPERANDS - 1)
+        ret = 0;
+      if (!ret || !intel_parser.next_operand)
+       break;
+      intel_parser.op_string = intel_parser.next_operand;
+      this_operand = i.operands++;
     }
 
   free (p);
@@ -5614,50 +6072,81 @@ i386_intel_operand (operand_string, got_a_float)
   return ret;
 }
 
-/* expr        SHORT e05
-       | e05  */
+#define NUM_ADDRESS_REGS (!!i.base_reg + !!i.index_reg)
+
+/* expr        e04 expr'
+
+   expr'  cmpOp e04 expr'
+       | Empty  */
 static int
 intel_expr ()
 {
-  /* expr  SHORT e05  */
-  if (cur_token.code == T_SHORT)
+  /* XXX Implement the comparison operators.  */
+  return intel_e04 ();
+}
+
+/* e04 e05 e04'
+
+   e04'        addOp e05 e04'
+       | Empty  */
+static int
+intel_e04 ()
+{
+  int nregs = -1;
+
+  for (;;)
     {
-      intel_parser.op_modifier = SHORT;
-      intel_match_token (T_SHORT);
+      if (!intel_e05())
+       return 0;
 
-      return (intel_e05 ());
-    }
+      if (nregs >= 0 && NUM_ADDRESS_REGS > nregs)
+       i.base_reg = i386_regtab + REGNAM_AL; /* al is invalid as base */
 
-  /* expr  e05  */
-  else
-    return intel_e05 ();
+      if (cur_token.code == '+')
+       nregs = -1;
+      else if (cur_token.code == '-')
+       nregs = NUM_ADDRESS_REGS;
+      else
+       return 1;
+
+      strcat (intel_parser.disp, cur_token.str);
+      intel_match_token (cur_token.code);
+    }
 }
 
 /* e05 e06 e05'
 
-   e05'        addOp e06 e05'
+   e05'        binOp e06 e05'
        | Empty  */
 static int
 intel_e05 ()
 {
-  return (intel_e06 () && intel_e05_1 ());
-}
+  int nregs = ~NUM_ADDRESS_REGS;
 
-static int
-intel_e05_1 ()
-{
-  /* e05'  addOp e06 e05'  */
-  if (cur_token.code == '+' || cur_token.code == '-')
+  for (;;)
     {
-      strcat (intel_parser.disp, cur_token.str);
+      if (!intel_e06())
+       return 0;
+
+      if (cur_token.code == '&' || cur_token.code == '|' || cur_token.code == '^')
+       {
+         char str[2];
+
+         str[0] = cur_token.code;
+         str[1] = 0;
+         strcat (intel_parser.disp, str);
+       }
+      else
+       break;
+
       intel_match_token (cur_token.code);
 
-      return (intel_e06 () && intel_e05_1 ());
+      if (nregs < 0)
+       nregs = ~nregs;
     }
-
-  /* e05'  Empty  */
-  else
-    return 1;
+  if (nregs >= 0 && NUM_ADDRESS_REGS > nregs)
+    i.base_reg = i386_regtab + REGNAM_AL + 1; /* cl is invalid as base */
+  return 1;
 }
 
 /* e06 e09 e06'
@@ -5667,27 +6156,44 @@ intel_e05_1 ()
 static int
 intel_e06 ()
 {
-  return (intel_e09 () && intel_e06_1 ());
-}
+  int nregs = ~NUM_ADDRESS_REGS;
 
-static int
-intel_e06_1 ()
-{
-  /* e06'  mulOp e09 e06'  */
-  if (cur_token.code == '*' || cur_token.code == '/')
+  for (;;)
     {
-      strcat (intel_parser.disp, cur_token.str);
-      intel_match_token (cur_token.code);
+      if (!intel_e09())
+       return 0;
 
-      return (intel_e09 () && intel_e06_1 ());
-    }
+      if (cur_token.code == '*' || cur_token.code == '/' || cur_token.code == '%')
+       {
+         char str[2];
 
-  /* e06'  Empty  */
-  else
-    return 1;
+         str[0] = cur_token.code;
+         str[1] = 0;
+         strcat (intel_parser.disp, str);
+       }
+      else if (cur_token.code == T_SHL)
+       strcat (intel_parser.disp, "<<");
+      else if (cur_token.code == T_SHR)
+       strcat (intel_parser.disp, ">>");
+      else
+       break;
+
+     intel_match_token (cur_token.code);
+
+      if (nregs < 0)
+       nregs = ~nregs;
+    }
+  if (nregs >= 0 && NUM_ADDRESS_REGS > nregs)
+    i.base_reg = i386_regtab + REGNAM_AL + 2; /* dl is invalid as base */
+  return 1;
 }
 
-/* e09 OFFSET e10 e09'
+/* e09 OFFSET e09
+       | SHORT e09
+       | + e09
+       | - e09
+       | ~ e09
+       | NOT e09
        | e10 e09'
 
    e09'        PTR e10 e09'
@@ -5696,82 +6202,287 @@ intel_e06_1 ()
 static int
 intel_e09 ()
 {
-  /* e09  OFFSET e10 e09'  */
-  if (cur_token.code == T_OFFSET)
+  int nregs = ~NUM_ADDRESS_REGS;
+  int in_offset = 0;
+
+  for (;;)
     {
-      intel_parser.is_mem = 0;
-      intel_parser.op_modifier = OFFSET_FLAT;
-      intel_match_token (T_OFFSET);
+      /* Don't consume constants here.  */
+      if (cur_token.code == '+' || cur_token.code == '-')
+       {
+         /* Need to look one token ahead - if the next token
+            is a constant, the current token is its sign.  */
+         int next_code;
 
-      return (intel_e10 () && intel_e09_1 ());
-    }
+         intel_match_token (cur_token.code);
+         next_code = cur_token.code;
+         intel_putback_token ();
+         if (next_code == T_CONST)
+           break;
+       }
 
-  /* e09  e10 e09'  */
-  else
-    return (intel_e10 () && intel_e09_1 ());
-}
+      /* e09  OFFSET e09  */
+      if (cur_token.code == T_OFFSET)
+       {
+         if (!in_offset++)
+           ++intel_parser.in_offset;
+       }
 
-static int
-intel_e09_1 ()
-{
-  /* e09'  PTR e10 e09' */
-  if (cur_token.code == T_PTR)
-    {
-      if (prev_token.code == T_BYTE)
-       i.suffix = BYTE_MNEM_SUFFIX;
+      /* e09  SHORT e09  */
+      else if (cur_token.code == T_SHORT)
+       intel_parser.op_modifier |= 1 << T_SHORT;
 
-      else if (prev_token.code == T_WORD)
+      /* e09  + e09  */
+      else if (cur_token.code == '+')
+       strcat (intel_parser.disp, "+");
+
+      /* e09  - e09
+             | ~ e09
+             | NOT e09  */
+      else if (cur_token.code == '-' || cur_token.code == '~')
        {
-         if (intel_parser.got_a_float == 2)    /* "fi..." */
-           i.suffix = SHORT_MNEM_SUFFIX;
-         else
-           i.suffix = WORD_MNEM_SUFFIX;
+         char str[2];
+
+         if (nregs < 0)
+           nregs = ~nregs;
+         str[0] = cur_token.code;
+         str[1] = 0;
+         strcat (intel_parser.disp, str);
        }
 
-      else if (prev_token.code == T_DWORD)
+      /* e09  e10 e09'  */
+      else
+       break;
+
+      intel_match_token (cur_token.code);
+    }
+
+  for (;;)
+    {
+      if (!intel_e10 ())
+       return 0;
+
+      /* e09'  PTR e10 e09' */
+      if (cur_token.code == T_PTR)
        {
-         if (intel_parser.got_a_float == 1)    /* "f..." */
-           i.suffix = SHORT_MNEM_SUFFIX;
+         char suffix;
+
+         if (prev_token.code == T_BYTE)
+           suffix = BYTE_MNEM_SUFFIX;
+
+         else if (prev_token.code == T_WORD)
+           {
+             if (current_templates->start->name[0] == 'l'
+                 && current_templates->start->name[2] == 's'
+                 && current_templates->start->name[3] == 0)
+               suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */
+             else if (intel_parser.got_a_float == 2)   /* "fi..." */
+               suffix = SHORT_MNEM_SUFFIX;
+             else
+               suffix = WORD_MNEM_SUFFIX;
+           }
+
+         else if (prev_token.code == T_DWORD)
+           {
+             if (current_templates->start->name[0] == 'l'
+                 && current_templates->start->name[2] == 's'
+                 && current_templates->start->name[3] == 0)
+               suffix = WORD_MNEM_SUFFIX;
+             else if (flag_code == CODE_16BIT
+                      && (current_templates->start->opcode_modifier
+                          & (Jump | JumpDword)))
+               suffix = LONG_DOUBLE_MNEM_SUFFIX;
+             else if (intel_parser.got_a_float == 1)   /* "f..." */
+               suffix = SHORT_MNEM_SUFFIX;
+             else
+               suffix = LONG_MNEM_SUFFIX;
+           }
+
+         else if (prev_token.code == T_FWORD)
+           {
+             if (current_templates->start->name[0] == 'l'
+                 && current_templates->start->name[2] == 's'
+                 && current_templates->start->name[3] == 0)
+               suffix = LONG_MNEM_SUFFIX;
+             else if (!intel_parser.got_a_float)
+               {
+                 if (flag_code == CODE_16BIT)
+                   add_prefix (DATA_PREFIX_OPCODE);
+                 suffix = LONG_DOUBLE_MNEM_SUFFIX;
+               }
+             else
+               suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */
+           }
+
+         else if (prev_token.code == T_QWORD)
+           {
+             if (intel_parser.got_a_float == 1)        /* "f..." */
+               suffix = LONG_MNEM_SUFFIX;
+             else
+               suffix = QWORD_MNEM_SUFFIX;
+           }
+
+         else if (prev_token.code == T_TBYTE)
+           {
+             if (intel_parser.got_a_float == 1)
+               suffix = LONG_DOUBLE_MNEM_SUFFIX;
+             else
+               suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */
+           }
+
+         else if (prev_token.code == T_XMMWORD)
+           {
+             /* XXX ignored for now, but accepted since gcc uses it */
+             suffix = 0;
+           }
+
          else
-           i.suffix = LONG_MNEM_SUFFIX;
+           {
+             as_bad (_("Unknown operand modifier `%s'"), prev_token.str);
+             return 0;
+           }
+
+         /* Operands for jump/call using 'ptr' notation denote absolute
+            addresses.  */
+         if (current_templates->start->opcode_modifier & (Jump | JumpDword))
+           i.types[this_operand] |= JumpAbsolute;
+
+         if (current_templates->start->base_opcode == 0x8d /* lea */)
+           ;
+         else if (!i.suffix)
+           i.suffix = suffix;
+         else if (i.suffix != suffix)
+           {
+             as_bad (_("Conflicting operand modifiers"));
+             return 0;
+           }
+
        }
 
-      else if (prev_token.code == T_QWORD)
+      /* e09'  : e10 e09'  */
+      else if (cur_token.code == ':')
        {
-         if (intel_parser.got_a_float == 1)    /* "f..." */
-           i.suffix = LONG_MNEM_SUFFIX;
-         else
-           i.suffix = QWORD_MNEM_SUFFIX;
+         if (prev_token.code != T_REG)
+           {
+             /* While {call,jmp} SSSS:OOOO is MASM syntax only when SSSS is a
+                segment/group identifier (which we don't have), using comma
+                as the operand separator there is even less consistent, since
+                there all branches only have a single operand.  */
+             if (this_operand != 0
+                 || intel_parser.in_offset
+                 || intel_parser.in_bracket
+                 || (!(current_templates->start->opcode_modifier
+                       & (Jump|JumpDword|JumpInterSegment))
+                     && !(current_templates->start->operand_types[0]
+                          & JumpAbsolute)))
+               return intel_match_token (T_NIL);
+             /* Remember the start of the 2nd operand and terminate 1st
+                operand here.
+                XXX This isn't right, yet (when SSSS:OOOO is right operand of
+                another expression), but it gets at least the simplest case
+                (a plain number or symbol on the left side) right.  */
+             intel_parser.next_operand = intel_parser.op_string;
+             *--intel_parser.op_string = '\0';
+             return intel_match_token (':');
+           }
        }
 
-      else if (prev_token.code == T_XWORD)
-       i.suffix = LONG_DOUBLE_MNEM_SUFFIX;
-
+      /* e09'  Empty  */
       else
+       break;
+
+      intel_match_token (cur_token.code);
+
+    }
+
+  if (in_offset)
+    {
+      --intel_parser.in_offset;
+      if (nregs < 0)
+       nregs = ~nregs;
+      if (NUM_ADDRESS_REGS > nregs)
        {
-         as_bad (_("Unknown operand modifier `%s'\n"), prev_token.str);
+         as_bad (_("Invalid operand to `OFFSET'"));
          return 0;
        }
+      intel_parser.op_modifier |= 1 << T_OFFSET;
+    }
 
-      intel_match_token (T_PTR);
+  if (nregs >= 0 && NUM_ADDRESS_REGS > nregs)
+    i.base_reg = i386_regtab + REGNAM_AL + 3; /* bl is invalid as base */
+  return 1;
+}
 
-      return (intel_e10 () && intel_e09_1 ());
-    }
+static int
+intel_bracket_expr ()
+{
+  int was_offset = intel_parser.op_modifier & (1 << T_OFFSET);
+  const char *start = intel_parser.op_string;
+  int len;
+
+  if (i.op[this_operand].regs)
+    return intel_match_token (T_NIL);
 
-  /* e09  : e10 e09'  */
-  else if (cur_token.code == ':')
+  intel_match_token ('[');
+
+  /* Mark as a memory operand only if it's not already known to be an
+     offset expression.  If it's an offset expression, we need to keep
+     the brace in.  */
+  if (!intel_parser.in_offset)
     {
-      /* Mark as a memory operand only if it's not already known to be an
-        offset expression.  */
-      if (intel_parser.op_modifier != OFFSET_FLAT)
-       intel_parser.is_mem = 1;
+      ++intel_parser.in_bracket;
 
-      return (intel_match_token (':') && intel_e10 () && intel_e09_1 ());
-    }
+      /* Operands for jump/call inside brackets denote absolute addresses.  */
+      if (current_templates->start->opcode_modifier & (Jump | JumpDword))
+       i.types[this_operand] |= JumpAbsolute;
 
-  /* e09'  Empty  */
+      /* Unfortunately gas always diverged from MASM in a respect that can't
+        be easily fixed without risking to break code sequences likely to be
+        encountered (the testsuite even check for this): MASM doesn't consider
+        an expression inside brackets unconditionally as a memory reference.
+        When that is e.g. a constant, an offset expression, or the sum of the
+        two, this is still taken as a constant load. gas, however, always
+        treated these as memory references. As a compromise, we'll try to make
+        offset expressions inside brackets work the MASM way (since that's
+        less likely to be found in real world code), but make constants alone
+        continue to work the traditional gas way. In either case, issue a
+        warning.  */
+      intel_parser.op_modifier &= ~was_offset;
+    }
   else
-    return 1;
+      strcat (intel_parser.disp, "[");
+
+  /* Add a '+' to the displacement string if necessary.  */
+  if (*intel_parser.disp != '\0'
+      && *(intel_parser.disp + strlen (intel_parser.disp) - 1) != '+')
+    strcat (intel_parser.disp, "+");
+
+  if (intel_expr ()
+      && (len = intel_parser.op_string - start - 1,
+         intel_match_token (']')))
+    {
+      /* Preserve brackets when the operand is an offset expression.  */
+      if (intel_parser.in_offset)
+       strcat (intel_parser.disp, "]");
+      else
+       {
+         --intel_parser.in_bracket;
+         if (i.base_reg || i.index_reg)
+           intel_parser.is_mem = 1;
+         if (!intel_parser.is_mem)
+           {
+             if (!(intel_parser.op_modifier & (1 << T_OFFSET)))
+               /* Defer the warning until all of the operand was parsed.  */
+               intel_parser.is_mem = -1;
+             else if (!quiet_warnings)
+               as_warn (_("`[%.*s]' taken to mean just `%.*s'"), len, start, len, start);
+           }
+       }
+      intel_parser.op_modifier |= was_offset;
+
+      return 1;
+    }
+  return 0;
 }
 
 /* e10 e11 e10'
@@ -5781,45 +6492,16 @@ intel_e09_1 ()
 static int
 intel_e10 ()
 {
-  return (intel_e11 () && intel_e10_1 ());
-}
+  if (!intel_e11 ())
+    return 0;
 
-static int
-intel_e10_1 ()
-{
-  /* e10'  [ expr ]  e10'  */
-  if (cur_token.code == '[')
+  while (cur_token.code == '[')
     {
-      intel_match_token ('[');
-
-      /* Mark as a memory operand only if it's not already known to be an
-        offset expression.  If it's an offset expression, we need to keep
-        the brace in.  */
-      if (intel_parser.op_modifier != OFFSET_FLAT)
-       intel_parser.is_mem = 1;
-      else
-       strcat (intel_parser.disp, "[");
-
-      /* Add a '+' to the displacement string if necessary.  */
-      if (*intel_parser.disp != '\0'
-         && *(intel_parser.disp + strlen (intel_parser.disp) - 1) != '+')
-       strcat (intel_parser.disp, "+");
-
-      if (intel_expr () && intel_match_token (']'))
-       {
-         /* Preserve brackets when the operand is an offset expression.  */
-         if (intel_parser.op_modifier == OFFSET_FLAT)
-           strcat (intel_parser.disp, "]");
-
-         return intel_e10_1 ();
-       }
-      else
+      if (!intel_bracket_expr ())
        return 0;
     }
 
-  /* e10'  Empty  */
-  else
-    return 1;
+  return 1;
 }
 
 /* e11 ( expr )
@@ -5827,8 +6509,11 @@ intel_e10_1 ()
        | BYTE
        | WORD
        | DWORD
+       | FWORD
        | QWORD
-       | XWORD
+       | TBYTE
+       | OWORD
+       | XMMWORD
        | $
        | .
        | register
@@ -5837,9 +6522,10 @@ intel_e10_1 ()
 static int
 intel_e11 ()
 {
-  /* e11  ( expr ) */
-  if (cur_token.code == '(')
+  switch (cur_token.code)
     {
+    /* e11  ( expr ) */
+    case '(':
       intel_match_token ('(');
       strcat (intel_parser.disp, "(");
 
@@ -5848,292 +6534,284 @@ intel_e11 ()
          strcat (intel_parser.disp, ")");
          return 1;
        }
-      else
-       return 0;
-    }
-
-  /* e11  [ expr ] */
-  else if (cur_token.code == '[')
-    {
-      intel_match_token ('[');
-
-      /* Mark as a memory operand only if it's not already known to be an
-        offset expression.  If it's an offset expression, we need to keep
-        the brace in.  */
-      if (intel_parser.op_modifier != OFFSET_FLAT)
-       intel_parser.is_mem = 1;
-      else
-       strcat (intel_parser.disp, "[");
-
-      /* Operands for jump/call inside brackets denote absolute addresses.  */
-      if (current_templates->start->opcode_modifier & Jump
-         || current_templates->start->opcode_modifier & JumpDword
-         || current_templates->start->opcode_modifier & JumpByte
-         || current_templates->start->opcode_modifier & JumpInterSegment)
-       i.types[this_operand] |= JumpAbsolute;
-
-      /* Add a '+' to the displacement string if necessary.  */
-      if (*intel_parser.disp != '\0'
-         && *(intel_parser.disp + strlen (intel_parser.disp) - 1) != '+')
-       strcat (intel_parser.disp, "+");
-
-      if (intel_expr () && intel_match_token (']'))
-       {
-         /* Preserve brackets when the operand is an offset expression.  */
-         if (intel_parser.op_modifier == OFFSET_FLAT)
-           strcat (intel_parser.disp, "]");
-
-         return 1;
-       }
-      else
-       return 0;
-    }
-
-  /* e11  BYTE
-         | WORD
-         | DWORD
-         | QWORD
-         | XWORD  */
-  else if (cur_token.code == T_BYTE
-          || cur_token.code == T_WORD
-          || cur_token.code == T_DWORD
-          || cur_token.code == T_QWORD
-          || cur_token.code == T_XWORD)
-    {
-      intel_match_token (cur_token.code);
+      return 0;
 
-      return 1;
-    }
+    /* e11  [ expr ] */
+    case '[':
+      return intel_bracket_expr ();
 
-  /* e11  $
-         | .  */
-  else if (cur_token.code == '$' || cur_token.code == '.')
-    {
+    /* e11  $
+           | .  */
+    case '.':
       strcat (intel_parser.disp, cur_token.str);
       intel_match_token (cur_token.code);
 
       /* Mark as a memory operand only if it's not already known to be an
         offset expression.  */
-      if (intel_parser.op_modifier != OFFSET_FLAT)
+      if (!intel_parser.in_offset)
        intel_parser.is_mem = 1;
 
       return 1;
-    }
 
-  /* e11  register  */
-  else if (cur_token.code == T_REG)
-    {
-      const reg_entry *reg = intel_parser.reg = cur_token.reg;
+    /* e11  register  */
+    case T_REG:
+      {
+       const reg_entry *reg = intel_parser.reg = cur_token.reg;
 
-      intel_match_token (T_REG);
+       intel_match_token (T_REG);
 
-      /* Check for segment change.  */
-      if (cur_token.code == ':')
-       {
-         if (reg->reg_type & (SReg2 | SReg3))
-           {
-             switch (reg->reg_num)
-               {
-               case 0:
-                 i.seg[i.mem_operands] = &es;
-                 break;
-               case 1:
-                 i.seg[i.mem_operands] = &cs;
-                 break;
-               case 2:
-                 i.seg[i.mem_operands] = &ss;
-                 break;
-               case 3:
-                 i.seg[i.mem_operands] = &ds;
-                 break;
-               case 4:
-                 i.seg[i.mem_operands] = &fs;
-                 break;
-               case 5:
-                 i.seg[i.mem_operands] = &gs;
-                 break;
-               }
-           }
-         else
-           {
-             as_bad (_("`%s' is not a valid segment register"), reg->reg_name);
-             return 0;
-           }
-       }
+       /* Check for segment change.  */
+       if (cur_token.code == ':')
+         {
+           if (!(reg->reg_type & (SReg2 | SReg3)))
+             {
+               as_bad (_("`%s' is not a valid segment register"), reg->reg_name);
+               return 0;
+             }
+           else if (i.seg[i.mem_operands])
+             as_warn (_("Extra segment override ignored"));
+           else
+             {
+               if (!intel_parser.in_offset)
+                 intel_parser.is_mem = 1;
+               switch (reg->reg_num)
+                 {
+                 case 0:
+                   i.seg[i.mem_operands] = &es;
+                   break;
+                 case 1:
+                   i.seg[i.mem_operands] = &cs;
+                   break;
+                 case 2:
+                   i.seg[i.mem_operands] = &ss;
+                   break;
+                 case 3:
+                   i.seg[i.mem_operands] = &ds;
+                   break;
+                 case 4:
+                   i.seg[i.mem_operands] = &fs;
+                   break;
+                 case 5:
+                   i.seg[i.mem_operands] = &gs;
+                   break;
+                 }
+             }
+         }
 
-      /* Not a segment register. Check for register scaling.  */
-      else if (cur_token.code == '*')
-       {
-         if (!intel_parser.is_mem)
-           {
-             as_bad (_("Register scaling only allowed in memory operands."));
-             return 0;
-           }
+       /* Not a segment register. Check for register scaling.  */
+       else if (cur_token.code == '*')
+         {
+           if (!intel_parser.in_bracket)
+             {
+               as_bad (_("Register scaling only allowed in memory operands"));
+               return 0;
+             }
 
-         /* What follows must be a valid scale.  */
-         if (intel_match_token ('*')
-             && strchr ("01248", *cur_token.str))
-           {
-             i.index_reg = reg;
-             i.types[this_operand] |= BaseIndex;
+           if (reg->reg_type & Reg16) /* Disallow things like [si*1]. */
+             reg = i386_regtab + REGNAM_AX + 4; /* sp is invalid as index */
+           else if (i.index_reg)
+             reg = i386_regtab + REGNAM_EAX + 4; /* esp is invalid as index */
 
-             /* Set the scale after setting the register (otherwise,
-                i386_scale will complain)  */
-             i386_scale (cur_token.str);
-             intel_match_token (T_CONST);
-           }
-         else
-           {
-             as_bad (_("expecting scale factor of 1, 2, 4, or 8: got `%s'"),
-                     cur_token.str);
-             return 0;
-           }
-       }
+           /* What follows must be a valid scale.  */
+           intel_match_token ('*');
+           i.index_reg = reg;
+           i.types[this_operand] |= BaseIndex;
 
-      /* No scaling. If this is a memory operand, the register is either a
-        base register (first occurrence) or an index register (second
-        occurrence).  */
-      else if (intel_parser.is_mem && !(reg->reg_type & (SReg2 | SReg3)))
-       {
-         if (i.base_reg && i.index_reg)
-           {
-             as_bad (_("Too many register references in memory operand.\n"));
+           /* Set the scale after setting the register (otherwise,
+              i386_scale will complain)  */
+           if (cur_token.code == '+' || cur_token.code == '-')
+             {
+               char *str, sign = cur_token.code;
+               intel_match_token (cur_token.code);
+               if (cur_token.code != T_CONST)
+                 {
+                   as_bad (_("Syntax error: Expecting a constant, got `%s'"),
+                           cur_token.str);
+                   return 0;
+                 }
+               str = (char *) xmalloc (strlen (cur_token.str) + 2);
+               strcpy (str + 1, cur_token.str);
+               *str = sign;
+               if (!i386_scale (str))
+                 return 0;
+               free (str);
+             }
+           else if (!i386_scale (cur_token.str))
              return 0;
-           }
-
-         if (i.base_reg == NULL)
-           i.base_reg = reg;
-         else
-           i.index_reg = reg;
+           intel_match_token (cur_token.code);
+         }
 
-         i.types[this_operand] |= BaseIndex;
-       }
+       /* No scaling. If this is a memory operand, the register is either a
+          base register (first occurrence) or an index register (second
+          occurrence).  */
+       else if (intel_parser.in_bracket && !(reg->reg_type & (SReg2 | SReg3)))
+         {
 
-      /* Offset modifier. Add the register to the displacement string to be
-        parsed as an immediate expression after we're done.  */
-      else if (intel_parser.op_modifier == OFFSET_FLAT)
-       strcat (intel_parser.disp, reg->reg_name);
+           if (!i.base_reg)
+             i.base_reg = reg;
+           else if (!i.index_reg)
+             i.index_reg = reg;
+           else
+             {
+               as_bad (_("Too many register references in memory operand"));
+               return 0;
+             }
 
-      /* It's neither base nor index nor offset.  */
-      else
-       {
-         i.types[this_operand] |= reg->reg_type & ~BaseIndex;
-         i.op[this_operand].regs = reg;
-         i.reg_operands++;
-       }
+           i.types[this_operand] |= BaseIndex;
+         }
 
-      /* Since registers are not part of the displacement string (except
-        when we're parsing offset operands), we may need to remove any
-        preceding '+' from the displacement string.  */
-      if (*intel_parser.disp != '\0'
-         && intel_parser.op_modifier != OFFSET_FLAT)
-       {
-         char *s = intel_parser.disp;
-         s += strlen (s) - 1;
-         if (*s == '+')
-           *s = '\0';
-       }
+       /* It's neither base nor index.  */
+       else if (!intel_parser.in_offset && !intel_parser.is_mem)
+         {
+           i.types[this_operand] |= reg->reg_type & ~BaseIndex;
+           i.op[this_operand].regs = reg;
+           i.reg_operands++;
+         }
+       else
+         {
+           as_bad (_("Invalid use of register"));
+           return 0;
+         }
 
-      return 1;
-    }
+       /* Since registers are not part of the displacement string (except
+          when we're parsing offset operands), we may need to remove any
+          preceding '+' from the displacement string.  */
+       if (*intel_parser.disp != '\0'
+           && !intel_parser.in_offset)
+         {
+           char *s = intel_parser.disp;
+           s += strlen (s) - 1;
+           if (*s == '+')
+             *s = '\0';
+         }
 
-  /* e11  id  */
-  else if (cur_token.code == T_ID)
-    {
-      /* Add the identifier to the displacement string.  */
-      strcat (intel_parser.disp, cur_token.str);
-      intel_match_token (T_ID);
+       return 1;
+      }
 
-      /* The identifier represents a memory reference only if it's not
-        preceded by an offset modifier.  */
-      if (intel_parser.op_modifier != OFFSET_FLAT)
-       intel_parser.is_mem = 1;
+    /* e11  BYTE
+           | WORD
+           | DWORD
+           | FWORD
+           | QWORD
+           | TBYTE
+           | OWORD
+           | XMMWORD  */
+    case T_BYTE:
+    case T_WORD:
+    case T_DWORD:
+    case T_FWORD:
+    case T_QWORD:
+    case T_TBYTE:
+    case T_XMMWORD:
+      intel_match_token (cur_token.code);
 
-      return 1;
-    }
+      if (cur_token.code == T_PTR)
+       return 1;
 
-  /* e11  constant  */
-  else if (cur_token.code == T_CONST
-          || cur_token.code == '-'
-          || cur_token.code == '+')
-    {
-      char *save_str;
+      /* It must have been an identifier.  */
+      intel_putback_token ();
+      cur_token.code = T_ID;
+      /* FALLTHRU */
 
-      /* Allow constants that start with `+' or `-'.  */
-      if (cur_token.code == '-' || cur_token.code == '+')
+    /* e11  id
+           | constant  */
+    case T_ID:
+      if (!intel_parser.in_offset && intel_parser.is_mem <= 0)
        {
-         strcat (intel_parser.disp, cur_token.str);
-         intel_match_token (cur_token.code);
-         if (cur_token.code != T_CONST)
-           {
-             as_bad (_("Syntax error. Expecting a constant. Got `%s'.\n"),
-                     cur_token.str);
-             return 0;
-           }
-       }
+         symbolS *symbolP;
 
-      save_str = (char *) malloc (strlen (cur_token.str) + 1);
-      if (save_str == NULL)
-       abort ();
-      strcpy (save_str, cur_token.str);
+         /* The identifier represents a memory reference only if it's not
+            preceded by an offset modifier and if it's not an equate.  */
+         symbolP = symbol_find(cur_token.str);
+         if (!symbolP || S_GET_SEGMENT(symbolP) != absolute_section)
+           intel_parser.is_mem = 1;
+       }
+       /* FALLTHRU */
 
-      /* Get the next token to check for register scaling.  */
-      intel_match_token (cur_token.code);
+    case T_CONST:
+    case '-':
+    case '+':
+      {
+       char *save_str, sign = 0;
 
-      /* Check if this constant is a scaling factor for an index register.  */
-      if (cur_token.code == '*')
-       {
-         if (intel_match_token ('*') && cur_token.code == T_REG)
-           {
-             if (!intel_parser.is_mem)
-               {
-                 as_bad (_("Register scaling only allowed in memory operands."));
-                 return 0;
-               }
+       /* Allow constants that start with `+' or `-'.  */
+       if (cur_token.code == '-' || cur_token.code == '+')
+         {
+           sign = cur_token.code;
+           intel_match_token (cur_token.code);
+           if (cur_token.code != T_CONST)
+             {
+               as_bad (_("Syntax error: Expecting a constant, got `%s'"),
+                       cur_token.str);
+               return 0;
+             }
+         }
 
-             /* The constant is followed by `* reg', so it must be
-                a valid scale.  */
-             if (strchr ("01248", *save_str))
-               {
-                 i.index_reg = cur_token.reg;
-                 i.types[this_operand] |= BaseIndex;
-
-                 /* Set the scale after setting the register (otherwise,
-                    i386_scale will complain)  */
-                 i386_scale (save_str);
-                 intel_match_token (T_REG);
-
-                 /* Since registers are not part of the displacement
-                    string, we may need to remove any preceding '+' from
-                    the displacement string.  */
-                 if (*intel_parser.disp != '\0')
-                   {
-                     char *s = intel_parser.disp;
-                     s += strlen (s) - 1;
-                     if (*s == '+')
-                       *s = '\0';
-                   }
+       save_str = (char *) xmalloc (strlen (cur_token.str) + 2);
+       strcpy (save_str + !!sign, cur_token.str);
+       if (sign)
+         *save_str = sign;
 
-                 free (save_str);
+       /* Get the next token to check for register scaling.  */
+       intel_match_token (cur_token.code);
 
-                 return 1;
-               }
-             else
-               return 0;
-           }
+       /* Check if this constant is a scaling factor for an index register.  */
+       if (cur_token.code == '*')
+         {
+           if (intel_match_token ('*') && cur_token.code == T_REG)
+             {
+               const reg_entry *reg = cur_token.reg;
+
+               if (!intel_parser.in_bracket)
+                 {
+                   as_bad (_("Register scaling only allowed in memory operands"));
+                   return 0;
+                 }
+
+               if (reg->reg_type & Reg16) /* Disallow things like [1*si]. */
+                 reg = i386_regtab + REGNAM_AX + 4; /* sp is invalid as index */
+               else if (i.index_reg)
+                 reg = i386_regtab + REGNAM_EAX + 4; /* esp is invalid as index */
+
+               /* The constant is followed by `* reg', so it must be
+                  a valid scale.  */
+               i.index_reg = reg;
+               i.types[this_operand] |= BaseIndex;
+
+               /* Set the scale after setting the register (otherwise,
+                  i386_scale will complain)  */
+               if (!i386_scale (save_str))
+                 return 0;
+               intel_match_token (T_REG);
+
+               /* Since registers are not part of the displacement
+                  string, we may need to remove any preceding '+' from
+                  the displacement string.  */
+               if (*intel_parser.disp != '\0')
+                 {
+                   char *s = intel_parser.disp;
+                   s += strlen (s) - 1;
+                   if (*s == '+')
+                     *s = '\0';
+                 }
+
+               free (save_str);
+
+               return 1;
+             }
 
-         /* The constant was not used for register scaling. Since we have
-            already consumed the token following `*' we now need to put it
-            back in the stream.  */
-         else
+           /* The constant was not used for register scaling. Since we have
+              already consumed the token following `*' we now need to put it
+              back in the stream.  */
            intel_putback_token ();
-       }
+         }
 
-      /* Add the constant to the displacement string.  */
-      strcat (intel_parser.disp, save_str);
-      free (save_str);
+       /* Add the constant to the displacement string.  */
+       strcat (intel_parser.disp, save_str);
+       free (save_str);
 
-      return 1;
+       return 1;
+      }
     }
 
   as_bad (_("Unrecognized token '%s'"), cur_token.str);
@@ -6153,7 +6831,7 @@ intel_match_token (code)
     }
   else
     {
-      as_bad (_("Unexpected token `%s'\n"), cur_token.str);
+      as_bad (_("Unexpected token `%s'"), cur_token.str);
       return 0;
     }
 }
@@ -6190,9 +6868,7 @@ intel_get_token ()
 
   /* The new token cannot be larger than the remainder of the operand
      string.  */
-  new_token.str = (char *) malloc (strlen (intel_parser.op_string) + 1);
-  if (new_token.str == NULL)
-    abort ();
+  new_token.str = (char *) xmalloc (strlen (intel_parser.op_string) + 1);
   new_token.str[0] = '\0';
 
   if (strchr ("0123456789", *intel_parser.op_string))
@@ -6214,26 +6890,15 @@ intel_get_token ()
        new_token.code = T_ID;
     }
 
-  else if (strchr ("+-/*:[]()", *intel_parser.op_string))
+  else if ((reg = parse_register (intel_parser.op_string, &end_op)) != NULL)
     {
-      new_token.code = *intel_parser.op_string;
-      new_token.str[0] = *intel_parser.op_string;
-      new_token.str[1] = '\0';
-    }
+      size_t len = end_op - intel_parser.op_string;
 
-  else if ((*intel_parser.op_string == REGISTER_PREFIX || allow_naked_reg)
-          && ((reg = parse_register (intel_parser.op_string, &end_op)) != NULL))
-    {
       new_token.code = T_REG;
       new_token.reg = reg;
 
-      if (*intel_parser.op_string == REGISTER_PREFIX)
-       {
-         new_token.str[0] = REGISTER_PREFIX;
-         new_token.str[1] = '\0';
-       }
-
-      strcat (new_token.str, reg->reg_name);
+      memcpy (new_token.str, intel_parser.op_string, len);
+      new_token.str[len] = '\0';
     }
 
   else if (is_identifier_char (*intel_parser.op_string))
@@ -6245,8 +6910,8 @@ intel_get_token ()
         Otherwise, it's operator '.' followed by an expression.  */
       if ((*q == '.' || *q == '$') && !is_identifier_char (*(q + 1)))
        {
-         new_token.code = *q;
-         new_token.str[0] = *q;
+         new_token.code = '.';
+         new_token.str[0] = '.';
          new_token.str[1] = '\0';
        }
       else
@@ -6255,7 +6920,28 @@ intel_get_token ()
            *p++ = *q++;
          *p = '\0';
 
-         if (strcasecmp (new_token.str, "BYTE") == 0)
+         if (strcasecmp (new_token.str, "NOT") == 0)
+           new_token.code = '~';
+
+         else if (strcasecmp (new_token.str, "MOD") == 0)
+           new_token.code = '%';
+
+         else if (strcasecmp (new_token.str, "AND") == 0)
+           new_token.code = '&';
+
+         else if (strcasecmp (new_token.str, "OR") == 0)
+           new_token.code = '|';
+
+         else if (strcasecmp (new_token.str, "XOR") == 0)
+           new_token.code = '^';
+
+         else if (strcasecmp (new_token.str, "SHL") == 0)
+           new_token.code = T_SHL;
+
+         else if (strcasecmp (new_token.str, "SHR") == 0)
+           new_token.code = T_SHR;
+
+         else if (strcasecmp (new_token.str, "BYTE") == 0)
            new_token.code = T_BYTE;
 
          else if (strcasecmp (new_token.str, "WORD") == 0)
@@ -6264,11 +6950,20 @@ intel_get_token ()
          else if (strcasecmp (new_token.str, "DWORD") == 0)
            new_token.code = T_DWORD;
 
+         else if (strcasecmp (new_token.str, "FWORD") == 0)
+           new_token.code = T_FWORD;
+
          else if (strcasecmp (new_token.str, "QWORD") == 0)
            new_token.code = T_QWORD;
 
-         else if (strcasecmp (new_token.str, "XWORD") == 0)
-           new_token.code = T_XWORD;
+         else if (strcasecmp (new_token.str, "TBYTE") == 0
+                  /* XXX remove (gcc still uses it) */
+                  || strcasecmp (new_token.str, "XWORD") == 0)
+           new_token.code = T_TBYTE;
+
+         else if (strcasecmp (new_token.str, "XMMWORD") == 0
+                  || strcasecmp (new_token.str, "OWORD") == 0)
+           new_token.code = T_XMMWORD;
 
          else if (strcasecmp (new_token.str, "PTR") == 0)
            new_token.code = T_PTR;
@@ -6289,15 +6984,37 @@ intel_get_token ()
 
          /* ??? This is not mentioned in the MASM grammar.  */
          else if (strcasecmp (new_token.str, "FLAT") == 0)
-           new_token.code = T_OFFSET;
+           {
+             new_token.code = T_OFFSET;
+             if (*q == ':')
+               strcat (new_token.str, ":");
+             else
+               as_bad (_("`:' expected"));
+           }
 
          else
            new_token.code = T_ID;
        }
     }
 
+  else if (strchr ("+-/*%|&^:[]()~", *intel_parser.op_string))
+    {
+      new_token.code = *intel_parser.op_string;
+      new_token.str[0] = *intel_parser.op_string;
+      new_token.str[1] = '\0';
+    }
+
+  else if (strchr ("<>", *intel_parser.op_string)
+          && *intel_parser.op_string == *(intel_parser.op_string + 1))
+    {
+      new_token.code = *intel_parser.op_string == '<' ? T_SHL : T_SHR;
+      new_token.str[0] = *intel_parser.op_string;
+      new_token.str[1] = *intel_parser.op_string;
+      new_token.str[2] = '\0';
+    }
+
   else
-    as_bad (_("Unrecognized token `%s'\n"), intel_parser.op_string);
+    as_bad (_("Unrecognized token `%s'"), intel_parser.op_string);
 
   intel_parser.op_string += strlen (new_token.str);
   cur_token = new_token;
@@ -6308,8 +7025,11 @@ intel_get_token ()
 static void
 intel_putback_token ()
 {
-  intel_parser.op_string -= strlen (cur_token.str);
-  free (cur_token.str);
+  if (cur_token.code != T_NIL)
+    {
+      intel_parser.op_string -= strlen (cur_token.str);
+      free (cur_token.str);
+    }
   cur_token = prev_token;
 
   /* Forget prev_token.  */
@@ -6323,35 +7043,59 @@ tc_x86_regname_to_dw2regnum (const char *regname)
 {
   unsigned int regnum;
   unsigned int regnames_count;
-  char *regnames_32[] =
+  static const char *const regnames_32[] =
     {
       "eax", "ecx", "edx", "ebx",
       "esp", "ebp", "esi", "edi",
-      "eip"
+      "eip", "eflags", NULL,
+      "st0", "st1", "st2", "st3",
+      "st4", "st5", "st6", "st7",
+      NULL, NULL,
+      "xmm0", "xmm1", "xmm2", "xmm3",
+      "xmm4", "xmm5", "xmm6", "xmm7",
+      "mm0", "mm1", "mm2", "mm3",
+      "mm4", "mm5", "mm6", "mm7",
+      "fcw", "fsw", "mxcsr",
+      "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL,
+      "tr", "ldtr"
     };
-  char *regnames_64[] =
+  static const char *const regnames_64[] =
     {
-      "rax", "rbx", "rcx", "rdx",
-      "rdi", "rsi", "rbp", "rsp",
-      "r8", "r9", "r10", "r11",
+      "rax", "rdx", "rcx", "rbx",
+      "rsi", "rdi", "rbp", "rsp",
+      "r8",  "r9",  "r10", "r11",
       "r12", "r13", "r14", "r15",
-      "rip"
+      "rip",
+      "xmm0",  "xmm1",  "xmm2",  "xmm3",
+      "xmm4",  "xmm5",  "xmm6",  "xmm7",
+      "xmm8",  "xmm9",  "xmm10", "xmm11",
+      "xmm12", "xmm13", "xmm14", "xmm15",
+      "st0", "st1", "st2", "st3",
+      "st4", "st5", "st6", "st7",
+      "mm0", "mm1", "mm2", "mm3",
+      "mm4", "mm5", "mm6", "mm7",
+      "rflags",
+      "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL,
+      "fs.base", "gs.base", NULL, NULL,
+      "tr", "ldtr",
+      "mxcsr", "fcw", "fsw"
     };
-  char **regnames;
+  const char *const *regnames;
 
   if (flag_code == CODE_64BIT)
     {
       regnames = regnames_64;
-      regnames_count = sizeof (regnames_64);
+      regnames_count = ARRAY_SIZE (regnames_64);
     }
   else
     {
       regnames = regnames_32;
-      regnames_count = sizeof (regnames_32);
+      regnames_count = ARRAY_SIZE (regnames_32);
     }
 
   for (regnum = 0; regnum < regnames_count; regnum++)
-    if (strcmp (regname, regnames[regnum]) == 0)
+    if (regnames[regnum] != NULL
+       && strcmp (regname, regnames[regnum]) == 0)
       return regnum;
 
   return -1;
@@ -6369,3 +7113,95 @@ tc_x86_frame_initial_instructions (void)
   cfi_add_CFA_def_cfa (sp_regno, -x86_cie_data_alignment);
   cfi_add_CFA_offset (x86_dwarf2_return_column, x86_cie_data_alignment);
 }
+
+int
+i386_elf_section_type (const char *str, size_t len)
+{
+  if (flag_code == CODE_64BIT
+      && len == sizeof ("unwind") - 1
+      && strncmp (str, "unwind", 6) == 0)
+    return SHT_X86_64_UNWIND;
+
+  return -1;
+}
+
+#ifdef TE_PE
+void
+tc_pe_dwarf2_emit_offset (symbolS *symbol, unsigned int size)
+{
+  expressionS expr;
+
+  expr.X_op = O_secrel;
+  expr.X_add_symbol = symbol;
+  expr.X_add_number = 0;
+  emit_expr (&expr, size);
+}
+#endif
+
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+/* For ELF on x86-64, add support for SHF_X86_64_LARGE.  */
+
+int
+x86_64_section_letter (int letter, char **ptr_msg)
+{
+  if (flag_code == CODE_64BIT)
+    {
+      if (letter == 'l')
+       return SHF_X86_64_LARGE;
+
+      *ptr_msg = _("Bad .section directive: want a,l,w,x,M,S,G,T in string");
+     }
+  else
+   *ptr_msg = _("Bad .section directive: want a,w,x,M,S,G,T in string");
+  return -1;
+}
+
+int
+x86_64_section_word (char *str, size_t len)
+{
+  if (len == 5 && flag_code == CODE_64BIT && strncmp (str, "large", 5) == 0)
+    return SHF_X86_64_LARGE;
+
+  return -1;
+}
+
+static void
+handle_large_common (int small ATTRIBUTE_UNUSED)
+{
+  if (flag_code != CODE_64BIT)
+    {
+      s_comm_internal (0, elf_common_parse);
+      as_warn (_(".largecomm supported only in 64bit mode, producing .comm"));
+    }
+  else
+    {
+      static segT lbss_section;
+      asection *saved_com_section_ptr = elf_com_section_ptr;
+      asection *saved_bss_section = bss_section;
+
+      if (lbss_section == NULL)
+       {
+         flagword applicable;
+         segT seg = now_seg;
+         subsegT subseg = now_subseg;
+
+         /* The .lbss section is for local .largecomm symbols.  */
+         lbss_section = subseg_new (".lbss", 0);
+         applicable = bfd_applicable_section_flags (stdoutput);
+         bfd_set_section_flags (stdoutput, lbss_section,
+                                applicable & SEC_ALLOC);
+         seg_info (lbss_section)->bss = 1;
+
+         subseg_set (seg, subseg);
+       }
+
+      elf_com_section_ptr = &_bfd_elf_large_com_section;
+      bss_section = lbss_section;
+
+      s_comm_internal (0, elf_common_parse);
+
+      elf_com_section_ptr = saved_com_section_ptr;
+      bss_section = saved_bss_section;
+    }
+}
+#endif /* OBJ_ELF || OBJ_MAYBE_ELF */
This page took 0.124182 seconds and 4 git commands to generate.