* config/tc-i386.c (i386_intel_operand): Always call i386_index_check
[deliverable/binutils-gdb.git] / gas / config / tc-i386.c
index bb1d512c77b6b311b4d73b960d2a91a506fb10bf..9f511ab42dc738aa1ef746a8b1cb632090631138 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
+   2000, 2001, 2002, 2003
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
@@ -30,6 +30,7 @@
 #include "safe-ctype.h"
 #include "subsegs.h"
 #include "dwarf2dbg.h"
+#include "dw2gencfi.h"
 #include "opcode/i386.h"
 
 #ifndef REGISTER_WARNINGS
@@ -104,8 +105,10 @@ static void output_insn PARAMS ((void));
 static void output_branch PARAMS ((void));
 static void output_jump PARAMS ((void));
 static void output_interseg_jump PARAMS ((void));
-static void output_imm PARAMS ((void));
-static void output_disp PARAMS ((void));
+static void output_imm PARAMS ((fragS *insn_start_frag,
+                               offsetT insn_start_off));
+static void output_disp PARAMS ((fragS *insn_start_frag,
+                                offsetT insn_start_off));
 #ifndef I386COFF
 static void s_bss PARAMS ((int));
 #endif
@@ -205,7 +208,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[] = "";
+const char line_comment_chars[] = "#";
 
 #else
 /* Putting '/' here makes it impossible to use the divide operator.
@@ -213,7 +216,7 @@ const char line_comment_chars[] = "";
 const char comment_chars[] = "#";
 #define PREFIX_SEPARATOR '/'
 
-const char line_comment_chars[] = "/";
+const char line_comment_chars[] = "/#";
 #endif
 
 const char line_separator_chars[] = ";";
@@ -300,6 +303,9 @@ 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;
 
@@ -316,6 +322,12 @@ static unsigned int no_cond_jump_promotion = 0;
 /* Pre-defined "_GLOBAL_OFFSET_TABLE_".  */
 symbolS *GOT_symbol;
 
+/* The dwarf2 return column, adjusted for 32 or 64 bit.  */
+unsigned int x86_dwarf2_return_column;
+
+/* The dwarf2 data alignment, adjusted for 32 or 64 bit.  */
+int x86_cie_data_alignment;
+
 /* Interface to relax_segment.
    There are 3 major relax states for 386 jump insns because the
    different types of jumps add different sizes to frags when we're
@@ -435,7 +447,7 @@ const pseudo_typeS md_pseudo_table[] =
   {"code64", set_code_flag, CODE_64BIT},
   {"intel_syntax", set_intel_syntax, 1},
   {"att_syntax", set_intel_syntax, 0},
-  {"file", dwarf2_directive_file, 0},
+  {"file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0},
   {"loc", dwarf2_directive_loc, 0},
   {0, 0, 0}
 };
@@ -521,26 +533,45 @@ i386_align_code (fragP, count)
     f32_15, f32_15, f32_15, f32_15, f32_15, f32_15, f32_15
   };
 
-  /* ??? We can't use these fillers for x86_64, since they often kills the
-     upper halves.  Solve later.  */
-  if (flag_code == CODE_64BIT)
-    count = 1;
+  if (count <= 0 || count > 15)
+    return;
 
-  if (count > 0 && count <= 15)
+  /* The recommended way to pad 64bit code is to use NOPs preceded by
+     maximally four 0x66 prefixes.  Balance the size of nops.  */
+  if (flag_code == CODE_64BIT)
     {
-      if (flag_code == CODE_16BIT)
+      int i;
+      int nnops = (count + 3) / 4;
+      int len = count / nnops;
+      int remains = count - nnops * len;
+      int pos = 0;
+
+      for (i = 0; i < remains; i++)
        {
-         memcpy (fragP->fr_literal + fragP->fr_fix,
-                 f16_patt[count - 1], count);
-         if (count > 8)
-           /* Adjust jump offset.  */
-           fragP->fr_literal[fragP->fr_fix + 1] = count - 2;
+         memset (fragP->fr_literal + fragP->fr_fix + pos, 0x66, len);
+         fragP->fr_literal[fragP->fr_fix + pos + len] = 0x90;
+         pos += len + 1;
+       }
+      for (; i < nnops; i++)
+       {
+         memset (fragP->fr_literal + fragP->fr_fix + pos, 0x66, len - 1);
+         fragP->fr_literal[fragP->fr_fix + pos + len - 1] = 0x90;
+         pos += len;
        }
-      else
-       memcpy (fragP->fr_literal + fragP->fr_fix,
-               f32_patt[count - 1], count);
-      fragP->fr_var = count;
     }
+  else
+    if (flag_code == CODE_16BIT)
+      {
+       memcpy (fragP->fr_literal + fragP->fr_fix,
+               f16_patt[count - 1], count);
+       if (count > 8)
+         /* Adjust jump offset.  */
+         fragP->fr_literal[fragP->fr_fix + 1] = count - 2;
+      }
+    else
+      memcpy (fragP->fr_literal + fragP->fr_fix,
+             f32_patt[count - 1], count);
+  fragP->fr_var = count;
 }
 
 static INLINE unsigned int
@@ -965,6 +996,17 @@ md_begin ()
       record_alignment (bss_section, 2);
     }
 #endif
+
+  if (flag_code == CODE_64BIT)
+    {
+      x86_dwarf2_return_column = 16;
+      x86_cie_data_alignment = -8;
+    }
+  else
+    {
+      x86_dwarf2_return_column = 8;
+      x86_cie_data_alignment = -4;
+    }
 }
 
 void
@@ -1130,21 +1172,6 @@ pt (t)
 
 #endif /* DEBUG386 */
 \f
-int
-tc_i386_force_relocation (fixp)
-     struct fix *fixp;
-{
-#ifdef BFD_ASSEMBLER
-  if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
-      || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
-    return 1;
-  return 0;
-#else
-  /* For COFF.  */
-  return fixp->fx_r_type == 7;
-#endif
-}
-
 #ifdef BFD_ASSEMBLER
 static bfd_reloc_code_real_type reloc
   PARAMS ((int, int, int, bfd_reloc_code_real_type));
@@ -1201,44 +1228,72 @@ reloc (size, pcrel, sign, other)
 
 int
 tc_i386_fix_adjustable (fixP)
-     fixS *fixP;
+     fixS *fixP ATTRIBUTE_UNUSED;
 {
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
-  /* Prevent all adjustments to global symbols, or else dynamic
-     linking will not work correctly.  */
-  if (S_IS_EXTERNAL (fixP->fx_addsy)
-      || S_IS_WEAK (fixP->fx_addsy)
-      /* Don't adjust pc-relative references to merge sections in 64-bit
-        mode.  */
-      || (use_rela_relocations
-         && (S_GET_SEGMENT (fixP->fx_addsy)->flags & SEC_MERGE) != 0
-         && fixP->fx_pcrel))
+  if (OUTPUT_FLAVOR != bfd_target_elf_flavour)
+    return 1;
+
+  /* Don't adjust pc-relative references to merge sections in 64-bit
+     mode.  */
+  if (use_rela_relocations
+      && (S_GET_SEGMENT (fixP->fx_addsy)->flags & SEC_MERGE) != 0
+      && fixP->fx_pcrel)
     return 0;
-#endif
+
   /* 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
       || fixP->fx_r_type == BFD_RELOC_386_GOT32
+      || fixP->fx_r_type == BFD_RELOC_386_TLS_GD
+      || fixP->fx_r_type == BFD_RELOC_386_TLS_LDM
+      || fixP->fx_r_type == BFD_RELOC_386_TLS_LDO_32
+      || fixP->fx_r_type == BFD_RELOC_386_TLS_IE_32
+      || fixP->fx_r_type == BFD_RELOC_386_TLS_IE
+      || fixP->fx_r_type == BFD_RELOC_386_TLS_GOTIE
+      || fixP->fx_r_type == BFD_RELOC_386_TLS_LE_32
+      || fixP->fx_r_type == BFD_RELOC_386_TLS_LE
       || fixP->fx_r_type == BFD_RELOC_X86_64_PLT32
       || fixP->fx_r_type == BFD_RELOC_X86_64_GOT32
       || fixP->fx_r_type == BFD_RELOC_X86_64_GOTPCREL
+      || 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_GOTTPOFF
+      || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF32
       || 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));
@@ -1314,11 +1369,19 @@ md_assemble (line)
   if (!match_template ())
     return;
 
-  /* Undo SYSV386_COMPAT brokenness when in Intel mode.  See i386.h  */
-  if (SYSV386_COMPAT
-      && intel_syntax
-      && (i.tm.base_opcode & 0xfffffde0) == 0xdce0)
-    i.tm.base_opcode ^= FloatR;
+  if (intel_syntax)
+    {
+      /* Undo SYSV386_COMPAT brokenness when in Intel mode.  See i386.h  */
+      if (SYSV386_COMPAT
+         && (i.tm.base_opcode & 0xfffffde0) == 0xdce0)
+       i.tm.base_opcode ^= FloatR;
+
+      /* Zap movzx and movsx suffix.  The suffix may have been set from
+        "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.tm.opcode_modifier & FWait)
     if (!add_prefix (FWAIT_OPCODE))
@@ -1350,13 +1413,28 @@ md_assemble (line)
 
   if (i.tm.opcode_modifier & ImmExt)
     {
+      expressionS *exp;
+
+      if ((i.tm.cpu_flags & CpuPNI) && i.operands > 0)
+       {
+         /* These Intel Precott 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++];
@@ -2206,18 +2284,6 @@ process_suffix ()
       return 0;
     }
 
-  /* For movzx and movsx, need to check the register type.  */
-  if (intel_syntax
-      && (i.tm.base_opcode == 0xfb6 || i.tm.base_opcode == 0xfbe)
-      && i.suffix == BYTE_MNEM_SUFFIX)
-    {
-      unsigned int prefix = DATA_PREFIX_OPCODE;
-
-      if ((i.op[1].regs->reg_type & Reg16) != 0)
-       if (!add_prefix (prefix))
-         return 0;
-    }
-
   if (i.suffix && i.suffix != BYTE_MNEM_SUFFIX)
     {
       /* It's not a byte, select word/dword operation.  */
@@ -2233,8 +2299,10 @@ process_suffix ()
         size prefix, except for instructions that will ignore this
         prefix anyway.  */
       if (i.suffix != QWORD_MNEM_SUFFIX
-         && (i.suffix == LONG_MNEM_SUFFIX) == (flag_code == CODE_16BIT)
-         && !(i.tm.opcode_modifier & IgnoreSize))
+         && !(i.tm.opcode_modifier & IgnoreSize)
+         && ((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 */
@@ -2244,25 +2312,11 @@ process_suffix ()
            return 0;
        }
 
-      if (i.suffix != QWORD_MNEM_SUFFIX && (flag_code == CODE_64BIT)
-         && !(i.tm.opcode_modifier & IgnoreSize)
-         && (i.tm.opcode_modifier & JumpByte))
-       {
-         if (!add_prefix (ADDR_PREFIX_OPCODE))
-           return 0;
-       }
-
       /* Set mode64 for an operand.  */
       if (i.suffix == QWORD_MNEM_SUFFIX
+         && flag_code == CODE_64BIT
          && (i.tm.opcode_modifier & NoRex64) == 0)
-       {
-         i.rex |= REX_MODE64;
-         if (flag_code < CODE_64BIT)
-           {
-             as_bad (_("64bit operations available only in 64bit modes."));
-             return 0;
-           }
-       }
+       i.rex |= REX_MODE64;
 
       /* Size floating point instruction.  */
       if (i.suffix == LONG_MNEM_SUFFIX)
@@ -2596,9 +2650,8 @@ process_operands ()
   else if (i.tm.opcode_modifier & Modrm)
     {
       /* The opcode is completed (modulo i.tm.extension_opcode which
-        must be put into the modrm byte).
-        Now, we make the modrm & index base bytes based on all the
-        info we've collected.  */
+        must be put into the modrm byte).  Now, we make the modrm and
+        index base bytes based on all the info we've collected.  */
 
       default_seg = build_modrm_byte ();
     }
@@ -2625,12 +2678,14 @@ process_operands ()
       default_seg = &ds;
     }
 
-  /* If a segment was explicitly specified,
-     and the specified segment is not the default,
-     use an opcode prefix to select it.
-     If we never figured out what the default segment is,
-     then default_seg will be zero at this point,
-     and the specified segment prefix will always be used.  */
+  if (i.tm.base_opcode == 0x8d /* lea */ && i.seg[0] && !quiet_warnings)
+    as_warn (_("segment override on `lea' is ineffectual"));
+
+  /* If a segment was explicitly specified, and the specified segment
+     is not the default, use an opcode prefix to select it.  If we
+     never figured out what the default segment is, then default_seg
+     will be zero at this point, and the specified segment prefix will
+     always be used.  */
   if ((i.seg[0]) && (i.seg[0] != default_seg))
     {
       if (!add_prefix (i.seg[0]->seg_prefix))
@@ -2981,6 +3036,7 @@ output_jump ()
 {
   char *p;
   int size;
+  fixS *fixP;
 
   if (i.tm.opcode_modifier & JumpByte)
     {
@@ -3031,8 +3087,14 @@ output_jump ()
   p = frag_more (1 + size);
   *p++ = i.tm.base_opcode;
 
-  fix_new_exp (frag_now, p - frag_now->fr_literal, size,
-              i.op[0].disps, 1, reloc (size, 1, 1, i.reloc[0]));
+  fixP = fix_new_exp (frag_now, p - frag_now->fr_literal, size,
+                     i.op[0].disps, 1, reloc (size, 1, 1, i.reloc[0]));
+
+  /* All jumps handled here are signed, but don't use a signed limit
+     check for 32 and 16 bit jumps as we want to allow wrap around at
+     4G and 64k respectively.  */
+  if (size == 1)
+    fixP->fx_signed = 1;
 }
 
 static void
@@ -3099,14 +3161,21 @@ output_interseg_jump ()
   md_number_to_chars (p + size, (valueT) i.op[0].imms->X_add_number, 2);
 }
 
+
 static void
 output_insn ()
 {
+  fragS *insn_start_frag;
+  offsetT insn_start_off;
+
   /* Tie dwarf2 debug info to the address at the start of the insn.
      We can't do this after the insn has been output as the current
      frag may have been closed off.  eg. by frag_var.  */
   dwarf2_emit_insn (0);
 
+  insn_start_frag = frag_now;
+  insn_start_off = frag_now_fix ();
+
   /* Output jumps.  */
   if (i.tm.opcode_modifier & Jump)
     output_branch ();
@@ -3177,10 +3246,10 @@ output_insn ()
        }
 
       if (i.disp_operands)
-       output_disp ();
+       output_disp (insn_start_frag, insn_start_off);
 
       if (i.imm_operands)
-       output_imm ();
+       output_imm (insn_start_frag, insn_start_off);
     }
 
 #ifdef DEBUG386
@@ -3192,7 +3261,9 @@ output_insn ()
 }
 
 static void
-output_disp ()
+output_disp (insn_start_frag, insn_start_off)
+    fragS *insn_start_frag;
+    offsetT insn_start_off;
 {
   char *p;
   unsigned int n;
@@ -3222,6 +3293,7 @@ output_disp ()
            }
          else
            {
+             RELOC_ENUM reloc_type;
              int size = 4;
              int sign = 0;
              int pcrel = (i.flags[n] & Operand_PCrel) != 0;
@@ -3264,16 +3336,50 @@ output_disp ()
                }
 
              p = frag_more (size);
+             reloc_type = reloc (size, pcrel, sign, i.reloc[n]);
+#ifdef BFD_ASSEMBLER
+             if (reloc_type == BFD_RELOC_32
+                 && 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))))
+               {
+                 offsetT add;
+
+                 if (insn_start_frag == frag_now)
+                   add = (p - frag_now->fr_literal) - insn_start_off;
+                 else
+                   {
+                     fragS *fr;
+
+                     add = insn_start_frag->fr_fix - insn_start_off;
+                     for (fr = insn_start_frag->fr_next;
+                          fr && fr != frag_now; fr = fr->fr_next)
+                       add += fr->fr_fix;
+                     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;
+                 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 (size, pcrel, sign, i.reloc[n]));
+                          i.op[n].disps, pcrel, reloc_type);
            }
        }
     }
 }
 
 static void
-output_imm ()
+output_imm (insn_start_frag, insn_start_off)
+    fragS *insn_start_frag;
+    offsetT insn_start_off;
 {
   char *p;
   unsigned int n;
@@ -3326,6 +3432,48 @@ output_imm ()
              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
+              * obtain the absolute address of the GOT, and it is strongly
+              * preferable from a performance point of view to avoid using
+              * a runtime relocation for this.  The actual sequence of
+              * instructions often look something like:
+              *
+              *        call    .L66
+              * .L66:
+              *        popl    %ebx
+              *        addl    $_GLOBAL_OFFSET_TABLE_+[.-.L66],%ebx
+              *
+              *   The call and pop essentially return the absolute address
+              * of the label .L66 and store it in %ebx.  The linker itself
+              * will ultimately change the first operand of the addl so
+              * that %ebx points to the GOT, but to keep things simple, the
+              * .o file must have this operand set so that it generates not
+              * the absolute address of .L66, but the absolute address of
+              * itself.  This allows the linker itself simply treat a GOTPC
+              * relocation as asking for a pcrel offset to the GOT to be
+              * added in, and the addend of the relocation is stored in the
+              * operand field for the instruction itself.
+              *
+              *   Our job here is to fix the operand so that it would add
+              * the correct offset so that %ebx would point to itself.  The
+              * thing that is tricky is that .-.L66 will point to the
+              * beginning of the instruction, so we need to further modify
+              * the operand so that it will point to itself.  There are
+              * other cases where you have something like:
+              *
+              *        .long   $_GLOBAL_OFFSET_TABLE_+[.-.L66]
+              *
+              * and here no correction would be required.  Internally in
+              * the assembler we treat operands of this form as not being
+              * pcrel since the '.' is explicitly mentioned, and I wonder
+              * whether it would simplify matters to do it this way.  Who
+              * knows.  In earlier versions of the PIC patches, the
+              * pcrel_adjust field was used to store the correction, but
+              * since the expression is not pcrel, I felt it would be
+              * confusing to do it this way.  */
+
              if (reloc_type == BFD_RELOC_32
                  && GOT_symbol
                  && GOT_symbol == i.op[n].imms->X_add_symbol
@@ -3335,11 +3483,26 @@ output_imm ()
                               (i.op[n].imms->X_op_symbol)->X_op)
                              == O_subtract))))
                {
+                 offsetT add;
+
+                 if (insn_start_frag == frag_now)
+                   add = (p - frag_now->fr_literal) - insn_start_off;
+                 else
+                   {
+                     fragS *fr;
+
+                     add = insn_start_frag->fr_fix - insn_start_off;
+                     for (fr = insn_start_frag->fr_next;
+                          fr && fr != frag_now; fr = fr->fr_next)
+                       add += fr->fr_fix;
+                     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;
-                 i.op[n].imms->X_add_number += 3;
+                 i.op[n].imms->X_add_number += add;
                }
 #endif
              fix_new_exp (frag_now, p - frag_now->fr_literal, size,
@@ -3371,10 +3534,19 @@ lex_got (reloc, adjust)
     const char *str;
     const RELOC_ENUM rel[NUM_FLAG_CODE];
   } 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 } },
-    { "GOT",      { BFD_RELOC_386_GOT32,  0, BFD_RELOC_X86_64_GOT32    } }
+    { "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    } }
   };
   char *cp;
   unsigned int j;
@@ -3557,6 +3729,7 @@ i386_immediate (imm_start)
 #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
@@ -3771,10 +3944,15 @@ i386_displacement (disp_start, disp_end)
 #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)
+      && exp_seg != undefined_section
+#ifdef BFD_ASSEMBLER
+      && !bfd_is_com_section (exp_seg)
+#endif
+      )
     {
 #ifdef BFD_ASSEMBLER
       as_bad (_("unimplemented segment %s in operand"), exp_seg->name);
@@ -4200,8 +4378,9 @@ 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)
-      || S_IS_EXTERNAL (fragP->fr_symbol)
-      || S_IS_WEAK (fragP->fr_symbol)
+      || (OUTPUT_FLAVOR == bfd_target_elf_flavour
+         && (S_IS_EXTERNAL (fragP->fr_symbol)
+             || S_IS_WEAK (fragP->fr_symbol)))
 #endif
       )
     {
@@ -4235,10 +4414,8 @@ md_estimate_size_before_relax (fragP, segment)
          break;
 
        case COND_JUMP86:
-         if (no_cond_jump_promotion)
-           goto relax_guess;
-
-         if (size == 2)
+         if (size == 2
+             && (!no_cond_jump_promotion || fragP->fr_var != NO_RELOC))
            {
              /* Negate the condition, and branch past an
                 unconditional jump.  */
@@ -4258,8 +4435,18 @@ md_estimate_size_before_relax (fragP, segment)
          /* Fall through.  */
 
        case COND_JUMP:
-         if (no_cond_jump_promotion)
-           goto relax_guess;
+         if (no_cond_jump_promotion && fragP->fr_var == NO_RELOC)
+           {
+             fixS *fixP;
+
+             fragP->fr_fix += 1;
+             fixP = fix_new (fragP, old_fr_fix, 1,
+                             fragP->fr_symbol,
+                             fragP->fr_offset, 1,
+                             BFD_RELOC_8_PCREL);
+             fixP->fx_signed = 1;
+             break;
+           }
 
          /* This changes the byte-displacement jump 0x7N
             to the (d)word-displacement jump 0x0f,0x8N.  */
@@ -4281,7 +4468,6 @@ md_estimate_size_before_relax (fragP, segment)
       return fragP->fr_fix - old_fr_fix;
     }
 
- relax_guess:
   /* Guess size depending on current relax state.  Initially the relax
      state will correspond to a short jump and we return 1, because
      the variable part of the frag (the branch offset) is one byte
@@ -4444,12 +4630,12 @@ md_apply_fix3 (fixP, valP, seg)
      /* The fix we're to put in.  */
      fixS *fixP;
      /* Pointer to the value of the bits.  */
-     valueT * valP;
+     valueT *valP;
      /* Segment fix is from.  */
      segT seg ATTRIBUTE_UNUSED;
 {
   char *p = fixP->fx_where + fixP->fx_frag->fr_literal;
-  valueT value = * valP;
+  valueT value = *valP;
 
 #if defined (BFD_ASSEMBLER) && !defined (TE_Mach)
   if (fixP->fx_pcrel)
@@ -4471,15 +4657,16 @@ md_apply_fix3 (fixP, valP, seg)
        }
     }
 
-  /* This is a hack.  There should be a better way to handle this.
-     This covers for the fact that bfd_install_relocation will
-     subtract the current location (for partial_inplace, PC relative
-     relocations); see more below.  */
-  if ((fixP->fx_r_type == BFD_RELOC_32_PCREL
-       || fixP->fx_r_type == BFD_RELOC_16_PCREL
-       || fixP->fx_r_type == BFD_RELOC_8_PCREL)
-      && fixP->fx_addsy && !use_rela_relocations)
+  if (fixP->fx_addsy != NULL
+      && (fixP->fx_r_type == BFD_RELOC_32_PCREL
+         || fixP->fx_r_type == BFD_RELOC_16_PCREL
+         || fixP->fx_r_type == BFD_RELOC_8_PCREL)
+      && !use_rela_relocations)
     {
+      /* This is a hack.  There should be a better way to handle this.
+        This covers for the fact that bfd_install_relocation will
+        subtract the current location (for partial_inplace, PC relative
+        relocations); see more below.  */
 #ifndef OBJ_AOUT
       if (OUTPUT_FLAVOR == bfd_target_elf_flavour
 #ifdef TE_PE
@@ -4491,19 +4678,16 @@ md_apply_fix3 (fixP, valP, seg)
 #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
       if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
        {
-         segT fseg = S_GET_SEGMENT (fixP->fx_addsy);
+         segT sym_seg = S_GET_SEGMENT (fixP->fx_addsy);
 
-         if ((fseg == seg
+         if ((sym_seg == seg
               || (symbol_section_p (fixP->fx_addsy)
-                  && fseg != absolute_section))
-             && !S_IS_EXTERNAL (fixP->fx_addsy)
-             && !S_IS_WEAK (fixP->fx_addsy)
-             && S_IS_DEFINED (fixP->fx_addsy)
-             && !S_IS_COMMON (fixP->fx_addsy))
+                  && sym_seg != absolute_section))
+             && !generic_force_reloc (fixP))
            {
              /* Yes, we add the values in twice.  This is because
-                bfd_perform_relocation subtracts them out again.  I think
-                bfd_perform_relocation is broken, but I don't dare change
+                bfd_install_relocation subtracts them out again.  I think
+                bfd_install_relocation is broken, but I don't dare change
                 it.  FIXME.  */
              value += fixP->fx_where + fixP->fx_frag->fr_address;
            }
@@ -4530,55 +4714,29 @@ md_apply_fix3 (fixP, valP, seg)
           runtime we merely add the offset to the actual PLT entry.  */
        value = -4;
        break;
-      case BFD_RELOC_386_GOTPC:
-
-/*   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 obtain the absolute address of the GOT, and it is strongly
- * preferable from a performance point of view to avoid using a runtime
- * relocation for this.  The actual sequence of instructions often look
- * something like:
- *
- *     call    .L66
- * .L66:
- *     popl    %ebx
- *     addl    $_GLOBAL_OFFSET_TABLE_+[.-.L66],%ebx
- *
- *   The call and pop essentially return the absolute address of
- * the label .L66 and store it in %ebx.  The linker itself will
- * ultimately change the first operand of the addl so that %ebx points to
- * the GOT, but to keep things simple, the .o file must have this operand
- * set so that it generates not the absolute address of .L66, but the
- * absolute address of itself.  This allows the linker itself simply
- * treat a GOTPC relocation as asking for a pcrel offset to the GOT to be
- * added in, and the addend of the relocation is stored in the operand
- * field for the instruction itself.
- *
- *   Our job here is to fix the operand so that it would add the correct
- * offset so that %ebx would point to itself.  The thing that is tricky is
- * that .-.L66 will point to the beginning of the instruction, so we need
- * to further modify the operand so that it will point to itself.
- * There are other cases where you have something like:
- *
- *     .long   $_GLOBAL_OFFSET_TABLE_+[.-.L66]
- *
- * and here no correction would be required.  Internally in the assembler
- * we treat operands of this form as not being pcrel since the '.' is
- * explicitly mentioned, and I wonder whether it would simplify matters
- * to do it this way.  Who knows.  In earlier versions of the PIC patches,
- * the pcrel_adjust field was used to store the correction, but since the
- * expression is not pcrel, I felt it would be confusing to do it this
- * way.  */
-
-       value -= 1;
+
+      case BFD_RELOC_386_TLS_GD:
+      case BFD_RELOC_386_TLS_LDM:
+      case BFD_RELOC_386_TLS_IE_32:
+      case BFD_RELOC_386_TLS_IE:
+      case BFD_RELOC_386_TLS_GOTIE:
+      case BFD_RELOC_X86_64_TLSGD:
+      case BFD_RELOC_X86_64_TLSLD:
+      case BFD_RELOC_X86_64_GOTTPOFF:
+       value = 0; /* Fully resolved at runtime.  No addend.  */
+       /* Fallthrough */
+      case BFD_RELOC_386_TLS_LE:
+      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_TPOFF32:
+       S_SET_THREAD_LOCAL (fixP->fx_addsy);
        break;
+
       case BFD_RELOC_386_GOT32:
       case BFD_RELOC_X86_64_GOT32:
        value = 0; /* Fully resolved at runtime.  No addend.  */
        break;
-      case BFD_RELOC_386_GOTOFF:
-      case BFD_RELOC_X86_64_GOTPCREL:
-       break;
 
       case BFD_RELOC_VTABLE_INHERIT:
       case BFD_RELOC_VTABLE_ENTRY:
@@ -4589,11 +4747,11 @@ md_apply_fix3 (fixP, valP, seg)
        break;
       }
 #endif /* defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)  */
-  * valP = value;
+  *valP = value;
 #endif /* defined (BFD_ASSEMBLER) && !defined (TE_Mach)  */
 
   /* Are we finished with this relocation now?  */
-  if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
+  if (fixP->fx_addsy == NULL)
     fixP->fx_done = 1;
 #ifdef BFD_ASSEMBLER
   else if (use_rela_relocations)
@@ -4749,9 +4907,9 @@ parse_register (reg_string, end_op)
 }
 \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[] = {
@@ -4772,6 +4930,10 @@ md_parse_option (c, arg)
 {
   switch (c)
     {
+    case 'n':
+      optimize_align_code = 0;
+      break;
+
     case 'q':
       quiet_warnings = 1;
       break;
@@ -4833,10 +4995,12 @@ md_show_usage (stream)
   -Q                      ignored\n\
   -V                      print assembler version number\n\
   -k                      ignored\n\
+  -n                      Do not optimize code alignment\n\
   -q                      quieten some warnings\n\
   -s                      ignored\n"));
 #else
   fprintf (stream, _("\
+  -n                      Do not optimize code alignment\n\
   -q                      quieten some warnings\n"));
 #endif
 }
@@ -4871,7 +5035,7 @@ i386_target_format ()
       {
        if (flag_code == CODE_64BIT)
          use_rela_relocations = 1;
-       return flag_code == CODE_64BIT ? "elf64-x86-64" : "elf32-i386";
+       return flag_code == CODE_64BIT ? "elf64-x86-64" : ELF_TARGET_FORMAT;
       }
 #endif
     default:
@@ -5041,7 +5205,20 @@ tc_gen_reloc (section, fixp)
     case BFD_RELOC_386_GOT32:
     case BFD_RELOC_386_GOTOFF:
     case BFD_RELOC_386_GOTPC:
+    case BFD_RELOC_386_TLS_GD:
+    case BFD_RELOC_386_TLS_LDM:
+    case BFD_RELOC_386_TLS_LDO_32:
+    case BFD_RELOC_386_TLS_IE_32:
+    case BFD_RELOC_386_TLS_IE:
+    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_GOTTPOFF:
+    case BFD_RELOC_X86_64_TPOFF32:
     case BFD_RELOC_RVA:
     case BFD_RELOC_VTABLE_ENTRY:
     case BFD_RELOC_VTABLE_INHERIT:
@@ -5106,10 +5283,7 @@ tc_gen_reloc (section, fixp)
       if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
        rel->address = fixp->fx_offset;
 
-      if (fixp->fx_pcrel)
-       rel->addend = fixp->fx_addnumber;
-      else
-       rel->addend = 0;
+      rel->addend = 0;
     }
   /* Use the rela in 64bit mode.  */
   else
@@ -5122,6 +5296,9 @@ tc_gen_reloc (section, fixp)
          case BFD_RELOC_X86_64_PLT32:
          case BFD_RELOC_X86_64_GOT32:
          case BFD_RELOC_X86_64_GOTPCREL:
+         case BFD_RELOC_X86_64_TLSGD:
+         case BFD_RELOC_X86_64_TLSLD:
+         case BFD_RELOC_X86_64_GOTTPOFF:
            rel->addend = fixp->fx_offset - fixp->fx_size;
            break;
          default:
@@ -5444,8 +5621,9 @@ i386_intel_operand (operand_string, got_a_float)
 
              /* 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)
+               ret = i386_index_check (operand_string);
            }
        }
 
@@ -6164,3 +6342,55 @@ intel_putback_token ()
   prev_token.reg = NULL;
   prev_token.str = NULL;
 }
+
+int
+tc_x86_regname_to_dw2regnum (const char *regname)
+{
+  unsigned int regnum;
+  unsigned int regnames_count;
+  char *regnames_32[] =
+    {
+      "eax", "ecx", "edx", "ebx",
+      "esp", "ebp", "esi", "edi",
+      "eip"
+    };
+  char *regnames_64[] =
+    {
+      "rax", "rbx", "rcx", "rdx",
+      "rdi", "rsi", "rbp", "rsp",
+      "r8", "r9", "r10", "r11",
+      "r12", "r13", "r14", "r15",
+      "rip"
+    };
+  char **regnames;
+
+  if (flag_code == CODE_64BIT)
+    {
+      regnames = regnames_64;
+      regnames_count = ARRAY_SIZE (regnames_64);
+    }
+  else
+    {
+      regnames = regnames_32;
+      regnames_count = ARRAY_SIZE (regnames_32);
+    }
+
+  for (regnum = 0; regnum < regnames_count; regnum++)
+    if (strcmp (regname, regnames[regnum]) == 0)
+      return regnum;
+
+  return -1;
+}
+
+void
+tc_x86_frame_initial_instructions (void)
+{
+  static unsigned int sp_regno;
+
+  if (!sp_regno)
+    sp_regno = tc_x86_regname_to_dw2regnum (flag_code == CODE_64BIT
+                                           ? "rsp" : "esp");
+
+  cfi_add_CFA_def_cfa (sp_regno, -x86_cie_data_alignment);
+  cfi_add_CFA_offset (x86_dwarf2_return_column, x86_cie_data_alignment);
+}
This page took 0.035098 seconds and 4 git commands to generate.