bfd/
[deliverable/binutils-gdb.git] / gas / config / tc-i386.c
index 183e244a25f63e010c83c0f8efcc73cc28d6ac1f..df3a35b39fbe13b76f8519e614fe29e9668c61e3 100644 (file)
@@ -17,8 +17,8 @@
 
    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).
@@ -305,6 +305,7 @@ static int allow_naked_reg = 0;
    leave, push, and pop instructions so that gcc has the same stack
    frame as in 32 bit mode.  */
 static char stackop_size = '\0';
+static void handle_large_common (int small ATTRIBUTE_UNUSED);
 
 /* Non-zero to optimize code alignment.  */
 int optimize_align_code = 1;
@@ -324,7 +325,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;
@@ -429,12 +430,16 @@ static const arch_entry cpu_arch[] = {
   {"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 }
 };
 
@@ -463,6 +468,9 @@ const pseudo_typeS md_pseudo_table[] =
   {"att_syntax", set_intel_syntax, 0},
   {"file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0},
   {"loc", dwarf2_directive_loc, 0},
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+  {"largecomm", handle_large_common, 0},
+#endif
 #ifdef TE_PE
   {"secrel32", pe_directive_secrel, 0},
 #endif
@@ -1008,6 +1016,7 @@ md_begin ()
     operand_chars['?'] = '?';
 #endif
     digit_chars['-'] = '-';
+    mnemonic_chars['-'] = '-';
     identifier_chars['_'] = '_';
     identifier_chars['.'] = '.';
 
@@ -1016,7 +1025,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);
@@ -1199,34 +1208,63 @@ pt (t)
 
 #endif /* DEBUG386 */
 \f
-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;
+         }
+      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;
@@ -1239,8 +1277,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 ();
@@ -1257,7 +1295,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
@@ -1291,8 +1329,11 @@ 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;
@@ -1398,13 +1439,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,
@@ -1605,8 +1651,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));
@@ -1614,7 +1661,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"));
@@ -1629,6 +1676,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))
@@ -1764,12 +1820,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;
@@ -2023,16 +2091,16 @@ optimize_imm ()
            switch (guess_suffix)
              {
              case QWORD_MNEM_SUFFIX:
-               i.types[op] = Imm64 | Imm32S;
+               i.types[op] &= Imm64 | Imm32S;
                break;
              case LONG_MNEM_SUFFIX:
-               i.types[op] = Imm32;
+               i.types[op] &= Imm32;
                break;
              case WORD_MNEM_SUFFIX:
-               i.types[op] = Imm16;
+               i.types[op] &= Imm16;
                break;
              case BYTE_MNEM_SUFFIX:
-               i.types[op] = Imm8 | Imm8S;
+               i.types[op] &= Imm8 | Imm8S;
                break;
              }
            break;
@@ -2047,37 +2115,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;
       }
 }
 
@@ -2810,8 +2895,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
@@ -3320,23 +3407,23 @@ output_insn ()
       char *p;
       unsigned char *q;
 
-      /* All opcodes on i386 have either 1 or 2 bytes, PadLock instructions
-        have 3 bytes.  We may use one more higher byte to specify a prefix
-        the instruction requires.  */
-      if ((i.tm.cpu_flags & CpuPadLock) != 0
-         && (i.tm.base_opcode & 0xff000000) != 0)
-        {
-         unsigned int prefix;
-         prefix = (i.tm.base_opcode >> 24) & 0xff;
-
-         if (prefix != REPE_PREFIX_OPCODE
-             || i.prefix[LOCKREP_PREFIX] != REPE_PREFIX_OPCODE)
-           add_prefix (prefix);
+      /* 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);
        }
-      else
-       if ((i.tm.cpu_flags & CpuPadLock) == 0
-           && (i.tm.base_opcode & 0xff0000) != 0)
-         add_prefix ((i.tm.base_opcode >> 16) & 0xff);
 
       /* The prefix bytes.  */
       for (q = i.prefix;
@@ -3357,13 +3444,7 @@ output_insn ()
        }
       else
        {
-         if ((i.tm.cpu_flags & CpuPadLock) != 0)
-           {
-             p = frag_more (3);
-             *p++ = (i.tm.base_opcode >> 16) & 0xff;
-           }
-         else
-           p = frag_more (2);
+         p = frag_more (2);
 
          /* Put out high byte first: can't use md_number_to_chars!  */
          *p++ = (i.tm.base_opcode >> 8) & 0xff;
@@ -3488,14 +3569,16 @@ output_disp (insn_start_frag, insn_start_off)
 
              p = frag_more (size);
              reloc_type = reloc (size, pcrel, sign, i.reloc[n]);
-             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;
 
@@ -3512,10 +3595,10 @@ 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 (flag_code != CODE_64BIT)
+                   reloc_type = BFD_RELOC_386_GOTPC;
+                 else
+                   reloc_type = BFD_RELOC_X86_64_GOTPC32;
                  i.op[n].disps->X_add_number += add;
                }
              fix_new_exp (frag_now, p - frag_now->fr_literal, size,
@@ -3567,7 +3650,8 @@ output_imm (insn_start_frag, insn_start_off)
              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))
                {
@@ -3623,7 +3707,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
@@ -3647,10 +3732,10 @@ 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 (flag_code != CODE_64BIT)
+                   reloc_type = BFD_RELOC_386_GOTPC;
+                 else
+                   reloc_type = BFD_RELOC_X86_64_GOTPC32;
                  i.op[n].imms->X_add_number += add;
                }
              fix_new_exp (frag_now, p - frag_now->fr_literal, size,
@@ -3660,9 +3745,9 @@ output_imm (insn_start_frag, insn_start_off)
     }
 }
 \f
-#ifndef LEX_AT
-static char *lex_got PARAMS ((enum bfd_reloc_code_real *, int *));
-
+#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.
@@ -3673,32 +3758,36 @@ static char *lex_got PARAMS ((enum bfd_reloc_code_real *, 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)
-     enum bfd_reloc_code_real *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 enum bfd_reloc_code_real rel[NUM_FLAG_CODE];
+    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,      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 }
   };
   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;
@@ -3719,6 +3808,14 @@ lex_got (reloc, adjust)
              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);
 
@@ -3767,7 +3864,7 @@ x86_cons_fix_new (frag, off, len, exp)
      unsigned int len;
      expressionS *exp;
 {
-  enum bfd_reloc_code_real r = reloc (len, 0, 0, got_reloc);
+  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);
 }
@@ -3777,7 +3874,7 @@ x86_cons (exp, size)
      expressionS *exp;
      int size;
 {
-  if (size == 4)
+  if (size == 4 || (flag_code == CODE_64BIT && size == 8))
     {
       /* Handle @GOTOFF and the like in an expression.  */
       char *save;
@@ -3785,7 +3882,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;
 
@@ -3816,7 +3913,7 @@ x86_pe_cons_fix_new (frag, off, len, exp)
      unsigned int len;
      expressionS *exp;
 {
-  enum bfd_reloc_code_real r = reloc (len, 0, 0, NO_RELOC);
+  enum bfd_reloc_code_real r = reloc (len, 0, -1, NO_RELOC);
 
   if (exp->X_op == O_secrel)
     {
@@ -3856,11 +3953,10 @@ i386_immediate (imm_start)
      char *imm_start;
 {
   char *save_input_line_pointer;
-#ifndef LEX_AT
   char *gotfree_input_line;
-#endif
   segT exp_seg = 0;
   expressionS *exp;
+  unsigned int types = ~0U;
 
   if (i.imm_operands == MAX_IMMEDIATE_OPERANDS)
     {
@@ -3877,11 +3973,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);
 
@@ -3890,10 +3984,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)
     {
@@ -3933,6 +4025,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;
@@ -3999,15 +4092,14 @@ 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;
+  unsigned int types = Disp;
 
   if (flag_code == CODE_64BIT)
     {
       if (i.prefix[ADDR_PREFIX] == 0)
-       bigdisp = Disp64;
+       bigdisp = Disp64 | Disp32S | Disp32;
     }
   else if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0))
     bigdisp = Disp16;
@@ -4064,11 +4156,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);
 
@@ -4080,16 +4170,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
 
   /* 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)
        {
@@ -4107,6 +4196,8 @@ 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;
     }
@@ -4136,8 +4227,10 @@ i386_displacement (disp_start, disp_end)
       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;
 }
 
@@ -4157,7 +4250,30 @@ i386_index_check (operand_string)
  tryprefix:
 #endif
   ok = 1;
-   if (flag_code == CODE_64BIT)
+  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
+       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);
 
@@ -4538,7 +4654,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
@@ -4778,7 +4894,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.  */
@@ -4797,6 +4913,9 @@ 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;
@@ -4812,6 +4931,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)
@@ -4821,7 +4941,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
@@ -4829,7 +4949,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);
 
@@ -4861,8 +4981,7 @@ md_apply_fix3 (fixP, valP, seg)
   /* Fix a few things - the dynamic linker expects certain values here,
      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:
@@ -4886,7 +5005,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;
 
@@ -4975,7 +5096,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)
@@ -5203,8 +5324,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;
@@ -5324,7 +5444,6 @@ i386_validate_fix (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)
@@ -5333,9 +5452,10 @@ i386_validate_fix (fixp)
        }
       else
        {
-         if (flag_code == CODE_64BIT)
-           abort ();
-         fixp->fx_r_type = BFD_RELOC_386_GOTOFF;
+         if (flag_code != CODE_64BIT)
+           fixp->fx_r_type = BFD_RELOC_386_GOTOFF;
+         else
+           fixp->fx_r_type = BFD_RELOC_X86_64_GOTOFF64;
        }
       fixp->fx_subsy = 0;
     }
@@ -5369,8 +5489,12 @@ tc_gen_reloc (section, fixp)
     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:
@@ -5379,6 +5503,13 @@ tc_gen_reloc (section, fixp)
 #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)
        {
@@ -5393,6 +5524,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
@@ -5416,14 +5550,14 @@ tc_gen_reloc (section, fixp)
       break;
     }
 
-  if (code == BFD_RELOC_32
+  if ((code == BFD_RELOC_32 || code == BFD_RELOC_32_PCREL)
       && 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 (flag_code != CODE_64BIT)
+       code = BFD_RELOC_386_GOTPC;
+      else
+       code = BFD_RELOC_X86_64_GOTPC32;
     }
 
   rel = (arelent *) xmalloc (sizeof (arelent));
@@ -6774,21 +6908,36 @@ 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"
     };
-  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"
     };
-  char **regnames;
+  const char *const *regnames;
 
   if (flag_code == CODE_64BIT)
     {
@@ -6802,7 +6951,8 @@ tc_x86_regname_to_dw2regnum (const char *regname)
     }
 
   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;
@@ -6844,3 +6994,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 */
This page took 0.038015 seconds and 4 git commands to generate.