* configure.tgt (i386-*-gnu*): Set em=gnu.
[external/binutils.git] / gas / config / tc-i386.c
index 514ff4b..1828c48 100644 (file)
@@ -80,6 +80,7 @@ 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));
@@ -111,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;
 
@@ -194,15 +198,23 @@ const char extra_symbol_chars[] = "*%-(["
 
 #if (defined (TE_I386AIX)                              \
      || ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF))        \
+        && !defined (TE_GNU)                           \
         && !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.
@@ -211,16 +223,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[] = ";";
 
@@ -284,6 +287,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.  */
@@ -457,6 +461,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},
@@ -465,8 +470,13 @@ 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
@@ -1226,6 +1236,11 @@ reloc (unsigned int size,
            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);
@@ -2083,22 +2098,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;
-               break;
-             case WORD_MNEM_SUFFIX:
-               i.types[op] &= Imm16;
-               break;
-             case BYTE_MNEM_SUFFIX:
-               i.types[op] &= Imm8 | Imm8S;
-               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;
          }
       }
@@ -3591,7 +3620,7 @@ output_disp (insn_start_frag, insn_start_off)
                      add += p - frag_now->fr_literal;
                    }
 
-                 if (flag_code != CODE_64BIT)
+                 if (!object_64bit)
                    reloc_type = BFD_RELOC_386_GOTPC;
                  else
                    reloc_type = BFD_RELOC_X86_64_GOTPC32;
@@ -3728,7 +3757,7 @@ output_imm (insn_start_frag, insn_start_off)
                      add += p - frag_now->fr_literal;
                    }
 
-                 if (flag_code != CODE_64BIT)
+                 if (!object_64bit)
                    reloc_type = BFD_RELOC_386_GOTPC;
                  else
                    reloc_type = BFD_RELOC_X86_64_GOTPC32;
@@ -3741,6 +3770,32 @@ output_imm (insn_start_frag, insn_start_off)
     }
 }
 \f
+/* 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
@@ -3758,25 +3813,24 @@ 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 enum bfd_reloc_code_real 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    }, Imm32|Imm32S|Disp32 },
-    { "GOTOFF",   { BFD_RELOC_386_GOTOFF,     0, BFD_RELOC_X86_64_GOTOFF64 }, Imm64|Disp64 },
-    { "GOTPCREL", { 0,                        0, BFD_RELOC_X86_64_GOTPCREL }, Imm32|Imm32S|Disp32 },
-    { "TLSGD",    { BFD_RELOC_386_TLS_GD,     0, BFD_RELOC_X86_64_TLSGD    }, Imm32|Imm32S|Disp32 },
-    { "TLSLDM",   { BFD_RELOC_386_TLS_LDM,    0, 0                         }, 0 },
-    { "TLSLD",    { 0,                        0, BFD_RELOC_X86_64_TLSLD    }, Imm32|Imm32S|Disp32 },
-    { "GOTTPOFF", { BFD_RELOC_386_TLS_IE_32,  0, BFD_RELOC_X86_64_GOTTPOFF }, Imm32|Imm32S|Disp32 },
-    { "TPOFF",    { BFD_RELOC_386_TLS_LE_32,  0, BFD_RELOC_X86_64_TPOFF32  }, Imm32|Imm32S|Imm64|Disp32|Disp64 },
-    { "NTPOFF",   { BFD_RELOC_386_TLS_LE,     0, 0                         }, 0 },
-    { "DTPOFF",   { BFD_RELOC_386_TLS_LDO_32, 0, BFD_RELOC_X86_64_DTPOFF32 }, Imm32|Imm32S|Imm64|Disp32|Disp64 },
-    { "GOTNTPOFF",{ BFD_RELOC_386_TLS_GOTIE,  0, 0                         }, 0 },
-    { "INDNTPOFF",{ BFD_RELOC_386_TLS_IE,     0, 0                         }, 0 },
-    { "GOT",      { BFD_RELOC_386_GOT32,      0, BFD_RELOC_X86_64_GOT32    }, Imm32|Imm32S|Disp32 }
+    { "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;
@@ -3795,12 +3849,12 @@ lex_got (enum bfd_reloc_code_real *reloc,
       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;
 
@@ -3839,8 +3893,8 @@ lex_got (enum bfd_reloc_code_real *reloc,
              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;
        }
     }
@@ -3849,28 +3903,12 @@ lex_got (enum bfd_reloc_code_real *reloc,
   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 enum bfd_reloc_code_real got_reloc = NO_RELOC;
-
-void
-x86_cons_fix_new (frag, off, len, exp)
-     fragS *frag;
-     unsigned int off;
-     unsigned int len;
-     expressionS *exp;
-{
-  enum bfd_reloc_code_real r = reloc (len, 0, -1, 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 || (flag_code == CODE_64BIT && size == 8))
+  if (size == 4 || (object_64bit && size == 8))
     {
       /* Handle @GOTOFF and the like in an expression.  */
       char *save;
@@ -3900,26 +3938,15 @@ x86_cons (exp, size)
 }
 #endif
 
-#ifdef TE_PE
-
-void
-x86_pe_cons_fix_new (frag, off, len, exp)
-     fragS *frag;
-     unsigned int off;
-     unsigned int len;
-     expressionS *exp;
+static void signed_cons (int size)
 {
-  enum bfd_reloc_code_real r = reloc (len, 0, -1, NO_RELOC);
-
-  if (exp->X_op == O_secrel)
-    {
-      exp->X_op = O_symbol;
-      r = BFD_RELOC_32_SECREL;
-    }
-
-  fix_new_exp (frag, off, len, exp, 0, r);
+  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;
@@ -3939,7 +3966,6 @@ pe_directive_secrel (dummy)
   input_line_pointer--;
   demand_empty_rest_of_line ();
 }
-
 #endif
 
 static int i386_immediate PARAMS ((char *));
@@ -4089,16 +4115,44 @@ i386_displacement (disp_start, disp_end)
   segT exp_seg = 0;
   char *save_input_line_pointer;
   char *gotfree_input_line;
-  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)
+      if (!bigdisp)
+       bigdisp = (override || i.suffix == WORD_MNEM_SUFFIX)
+                 ? Disp16
+                 : Disp32S | Disp32;
+      else if (!override)
        bigdisp = Disp64 | Disp32S | Disp32;
     }
-  else if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0))
-    bigdisp = Disp16;
+  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;
+    }
   i.types[this_operand] |= bigdisp;
 
   exp = &disp_expressions[i.disp_operands];
@@ -4364,8 +4418,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.  */
@@ -4503,8 +4556,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;
 
@@ -4524,8 +4576,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))
@@ -4850,9 +4901,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;
@@ -4966,10 +5014,7 @@ md_apply_fix (fixP, valP, 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
-#if defined(BFD_ASSEMBLER) || defined(S_IS_WEAK)
-         || S_IS_WEAK (fixP->fx_addsy)
-#endif
-         )
+         || S_IS_WEAK (fixP->fx_addsy))
        value += md_pcrel_from (fixP);
 #endif
     }
@@ -5108,9 +5153,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;
@@ -5177,6 +5220,80 @@ parse_register (reg_string, end_op)
 
   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)
+    {
+      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:sqn";
@@ -5184,13 +5301,16 @@ const char *md_shortopts = "kVQ:sqn";
 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);
@@ -5252,6 +5372,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;
     }
@@ -5266,14 +5403,21 @@ md_show_usage (stream)
   fprintf (stream, _("\
   -Q                      ignored\n\
   -V                      print assembler version number\n\
-  -k                      ignored\n\
+  -k                      ignored\n"));
+#endif
+  fprintf (stream, _("\
   -n                      Do not optimize code alignment\n\
-  -q                      quieten some warnings\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, _("\
-  -n                      Do not optimize code alignment\n\
-  -q                      quieten some warnings\n"));
+  --divide                ignored\n"));
 #endif
 }
 
@@ -5305,7 +5449,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
@@ -5442,13 +5589,13 @@ i386_validate_fix (fixp)
     {
       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)
+         if (!object_64bit)
            fixp->fx_r_type = BFD_RELOC_386_GOTOFF;
          else
            fixp->fx_r_type = BFD_RELOC_X86_64_GOTOFF64;
@@ -5546,11 +5693,13 @@ tc_gen_reloc (section, fixp)
       break;
     }
 
-  if ((code == BFD_RELOC_32 || code == BFD_RELOC_32_PCREL)
+  if ((code == BFD_RELOC_32
+       || code == BFD_RELOC_32_PCREL
+       || code == BFD_RELOC_X86_64_32S)
       && GOT_symbol
       && fixp->fx_addsy == GOT_symbol)
     {
-      if (flag_code != CODE_64BIT)
+      if (!object_64bit)
        code = BFD_RELOC_386_GOTPC;
       else
        code = BFD_RELOC_X86_64_GOTPC32;
@@ -6142,7 +6291,7 @@ intel_e09 ()
                suffix = WORD_MNEM_SUFFIX;
              else if (flag_code == CODE_16BIT
                       && (current_templates->start->opcode_modifier
-                          & (Jump|JumpDword|JumpInterSegment)))
+                          & (Jump | JumpDword)))
                suffix = LONG_DOUBLE_MNEM_SUFFIX;
              else if (intel_parser.got_a_float == 1)   /* "f..." */
                suffix = SHORT_MNEM_SUFFIX;
@@ -6194,6 +6343,11 @@ intel_e09 ()
              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)
@@ -6278,6 +6432,11 @@ intel_bracket_expr ()
   if (!intel_parser.in_offset)
     {
       ++intel_parser.in_bracket;
+
+      /* Operands for jump/call inside brackets denote absolute addresses.  */
+      if (current_templates->start->opcode_modifier & (Jump | JumpDword))
+       i.types[this_operand] |= JumpAbsolute;
+
       /* 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
@@ -6380,13 +6539,6 @@ intel_e11 ()
 
     /* e11  [ expr ] */
     case '[':
-      /* Operands for jump/call inside brackets denote absolute addresses.
-        XXX This shouldn't be needed anymore (or if it should rather live
-        in intel_bracket_expr).  */
-      if (current_templates->start->opcode_modifier
-         & (Jump|JumpDword|JumpByte|JumpInterSegment))
-       i.types[this_operand] |= JumpAbsolute;
-
       return intel_bracket_expr ();
 
     /* e11  $
@@ -6493,7 +6645,7 @@ intel_e11 ()
        /* 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)))
+       else if (intel_parser.in_bracket)
          {
 
            if (!i.base_reg)
@@ -6509,16 +6661,8 @@ intel_e11 ()
            i.types[this_operand] |= BaseIndex;
          }
 
-       /* Offset modifier. Add the register to the displacement string to be
-          parsed as an immediate expression after we're done.  */
-       else if (intel_parser.in_offset)
-         {
-           as_warn (_("Using register names in OFFSET expressions is deprecated"));
-           strcat (intel_parser.disp, reg->reg_name);
-         }
-
-       /* It's neither base nor index nor offset.  */
-       else if (!intel_parser.is_mem)
+       /* 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;
@@ -6747,19 +6891,15 @@ intel_get_token ()
        new_token.code = T_ID;
     }
 
-  else if ((*intel_parser.op_string == REGISTER_PREFIX || allow_naked_reg)
-          && ((reg = parse_register (intel_parser.op_string, &end_op)) != NULL))
+  else if ((reg = parse_register (intel_parser.op_string, &end_op)) != NULL)
     {
+      size_t len = end_op - intel_parser.op_string;
+
       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))
@@ -6915,7 +7055,10 @@ tc_x86_regname_to_dw2regnum (const char *regname)
       "xmm0", "xmm1", "xmm2", "xmm3",
       "xmm4", "xmm5", "xmm6", "xmm7",
       "mm0", "mm1", "mm2", "mm3",
-      "mm4", "mm5", "mm6", "mm7"
+      "mm4", "mm5", "mm6", "mm7",
+      "fcw", "fsw", "mxcsr",
+      "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL,
+      "tr", "ldtr"
     };
   static const char *const regnames_64[] =
     {
@@ -6931,7 +7074,12 @@ tc_x86_regname_to_dw2regnum (const char *regname)
       "st0", "st1", "st2", "st3",
       "st4", "st5", "st6", "st7",
       "mm0", "mm1", "mm2", "mm3",
-      "mm4", "mm5", "mm6", "mm7"
+      "mm4", "mm5", "mm6", "mm7",
+      "rflags",
+      "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL,
+      "fs.base", "gs.base", NULL, NULL,
+      "tr", "ldtr",
+      "mxcsr", "fcw", "fsw"
     };
   const char *const *regnames;
 
@@ -6990,3 +7138,71 @@ tc_pe_dwarf2_emit_offset (symbolS *symbol, unsigned int size)
   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 */