Nuts. Checked in wrong version of previous patch. Fixed.
[deliverable/binutils-gdb.git] / gas / config / tc-i386.c
index da2bf4852ef54d92acc05da76d68bc8b9154960d..275b3e6c439d6ccef86aa3f5ccc2157d2cc16d6f 100644 (file)
@@ -1,5 +1,6 @@
 /* i386.c -- Assemble code for the Intel 80386
-   Copyright (C) 1989, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000, 2001
+   Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000, 2001
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
@@ -69,6 +70,9 @@ static void set_cpu_arch PARAMS ((int));
 #ifdef BFD_ASSEMBLER
 static bfd_reloc_code_real_type reloc
   PARAMS ((int, int, int, bfd_reloc_code_real_type));
+#define RELOC_ENUM enum bfd_reloc_code_real
+#else
+#define RELOC_ENUM int
 #endif
 
 #ifndef DEFAULT_ARCH
@@ -116,11 +120,7 @@ struct _i386_insn
 #define Operand_PCrel 1
 
     /* Relocation type for operand */
-#ifdef BFD_ASSEMBLER
-    enum bfd_reloc_code_real disp_reloc[MAX_OPERANDS];
-#else
-    int disp_reloc[MAX_OPERANDS];
-#endif
+    RELOC_ENUM reloc[MAX_OPERANDS];
 
     /* BASE_REG, INDEX_REG, and LOG2_SCALE_FACTOR are used to encode
        the base index byte below.  */
@@ -157,7 +157,7 @@ const char extra_symbol_chars[] = "*%-(";
 
 /* This array holds the chars that always start a comment.  If the
    pre-processor is disabled, these aren't very useful.  */
-#if defined (TE_I386AIX) || ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) && ! defined (TE_LINUX) && !defined(TE_FreeBSD))
+#if defined (TE_I386AIX) || ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) && ! defined (TE_LINUX) && !defined(TE_FreeBSD) && !defined(TE_NetBSD))
 /* Putting '/' here makes it impossible to use the divide operator.
    However, we need it for compatibility with SVR4 systems.  */
 const char comment_chars[] = "#/";
@@ -175,7 +175,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.  */
-#if defined (TE_I386AIX) || ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) && ! defined (TE_LINUX) && !defined(TE_FreeBSD))
+#if defined (TE_I386AIX) || ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) && ! defined (TE_LINUX) && !defined(TE_FreeBSD) && !defined(TE_NetBSD))
 const char line_comment_chars[] = "";
 #else
 const char line_comment_chars[] = "/";
@@ -240,6 +240,7 @@ enum flag_code {
        CODE_32BIT,
        CODE_16BIT,
        CODE_64BIT };
+#define NUM_FLAG_CODE ((int) CODE_64BIT + 1)
 
 static enum flag_code flag_code;
 static int use_rela_relocations = 0;
@@ -273,15 +274,20 @@ static const char *cpu_arch_name = NULL;
 /* CPU feature flags.  */
 static unsigned int cpu_arch_flags = CpuUnknownFlags|CpuNo64;
 
+/* If set, conditional jumps are not automatically promoted to handle
+   larger than a byte offset.  */
+static unsigned int no_cond_jump_promotion = 0;
+
 /* Interface to relax_segment.
-   There are 2 relax states for 386 jump insns: one for conditional &
-   one for unconditional jumps.  This is because these two types of
-   jumps add different sizes to frags when we're figuring out what
-   sort of jump to choose to reach a given label.  */
+   There are 3 major relax states for 386 jump insns because the
+   different types of jumps add different sizes to frags when we're
+   figuring out what sort of jump to choose to reach a given label.  */
 
 /* Types.  */
+#define UNCOND_JUMP 0
 #define COND_JUMP 1
-#define UNCOND_JUMP 2
+#define COND_JUMP86 2
+
 /* Sizes.  */
 #define CODE16 1
 #define SMALL  0
@@ -297,10 +303,12 @@ static unsigned int cpu_arch_flags = CpuUnknownFlags|CpuNo64;
 #endif
 #endif
 
-#define ENCODE_RELAX_STATE(type,size) \
-  ((relax_substateT) ((type<<2) | (size)))
-#define SIZE_FROM_RELAX_STATE(s) \
-    ( (((s) & 0x3) == BIG ? 4 : (((s) & 0x3) == BIG16 ? 2 : 1)) )
+#define ENCODE_RELAX_STATE(type, size) \
+  ((relax_substateT) (((type) << 2) | (size)))
+#define TYPE_FROM_RELAX_STATE(s) \
+  ((s) >> 2)
+#define DISP_SIZE_FROM_RELAX_STATE(s) \
+    ((((s) & 3) == BIG ? 4 : (((s) & 3) == BIG16 ? 2 : 1)))
 
 /* This table is used by relax_frag to promote short jumps to long
    ones where necessary.  SMALL (short) jumps may be promoted to BIG
@@ -315,31 +323,38 @@ const relax_typeS md_relax_table[] =
   /* The fields are:
      1) most positive reach of this state,
      2) most negative reach of this state,
-     3) how many bytes this mode will add to the size of the current frag
+     3) how many bytes this mode will have in the variable part of the frag
      4) which index into the table to try if we can't fit into this one.  */
-  {1, 1, 0, 0},
-  {1, 1, 0, 0},
-  {1, 1, 0, 0},
-  {1, 1, 0, 0},
-
-  {127 + 1, -128 + 1, 0, ENCODE_RELAX_STATE (COND_JUMP, BIG)},
-  {127 + 1, -128 + 1, 0, ENCODE_RELAX_STATE (COND_JUMP, BIG16)},
-  /* dword conditionals adds 4 bytes to frag:
-     1 extra opcode byte, 3 extra displacement bytes.  */
+
+  /* UNCOND_JUMP states.  */
+  {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (UNCOND_JUMP, BIG)},
+  {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (UNCOND_JUMP, BIG16)},
+  /* dword jmp adds 4 bytes to frag:
+     0 extra opcode bytes, 4 displacement bytes.  */
   {0, 0, 4, 0},
-  /* word conditionals add 2 bytes to frag:
-     1 extra opcode byte, 1 extra displacement byte.  */
+  /* word jmp adds 2 byte2 to frag:
+     0 extra opcode bytes, 2 displacement bytes.  */
   {0, 0, 2, 0},
 
-  {127 + 1, -128 + 1, 0, ENCODE_RELAX_STATE (UNCOND_JUMP, BIG)},
-  {127 + 1, -128 + 1, 0, ENCODE_RELAX_STATE (UNCOND_JUMP, BIG16)},
-  /* dword jmp adds 3 bytes to frag:
-     0 extra opcode bytes, 3 extra displacement bytes.  */
+  /* COND_JUMP states.  */
+  {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP, BIG)},
+  {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP, BIG16)},
+  /* dword conditionals adds 5 bytes to frag:
+     1 extra opcode byte, 4 displacement bytes.  */
+  {0, 0, 5, 0},
+  /* word conditionals add 3 bytes to frag:
+     1 extra opcode byte, 2 displacement bytes.  */
   {0, 0, 3, 0},
-  /* word jmp adds 1 byte to frag:
-     0 extra opcode bytes, 1 extra displacement byte.  */
-  {0, 0, 1, 0}
 
+  /* COND_JUMP86 states.  */
+  {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP86, BIG)},
+  {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP86, BIG16)},
+  /* dword conditionals adds 5 bytes to frag:
+     1 extra opcode byte, 4 displacement bytes.  */
+  {0, 0, 5, 0},
+  /* word conditionals add 4 bytes to frag:
+     1 displacement byte and a 3 byte long branch insn.  */
+  {0, 0, 4, 0}
 };
 
 static const arch_entry cpu_arch[] = {
@@ -644,7 +659,7 @@ add_prefix (prefix)
 
 static void
 set_code_flag (value)
-     int  value;
+     int value;
 {
   flag_code = value;
   cpu_arch_flags &= ~(Cpu64 | CpuNo64);
@@ -726,7 +741,8 @@ set_cpu_arch (dummy)
          if (strcmp (string, cpu_arch[i].name) == 0)
            {
              cpu_arch_name = cpu_arch[i].name;
-             cpu_arch_flags = cpu_arch[i].flags | (flag_code == CODE_64BIT ? Cpu64 : CpuNo64);
+             cpu_arch_flags = (cpu_arch[i].flags
+                               | (flag_code == CODE_64BIT ? Cpu64 : CpuNo64));
              break;
            }
        }
@@ -738,6 +754,23 @@ set_cpu_arch (dummy)
   else
     as_bad (_("missing cpu architecture"));
 
+  no_cond_jump_promotion = 0;
+  if (*input_line_pointer == ','
+      && ! is_end_of_line[(unsigned char) input_line_pointer[1]])
+    {
+      char *string = ++input_line_pointer;
+      int e = get_symbol_end ();
+
+      if (strcmp (string, "nojumps") == 0)
+       no_cond_jump_promotion = 1;
+      else if (strcmp (string, "jumps") == 0)
+       ;
+      else
+       as_bad (_("no such architecture modifier: `%s'"), string);
+
+      *input_line_pointer = e;
+    }
+
   demand_empty_rest_of_line ();
 }
 
@@ -778,6 +811,19 @@ static struct hash_control *op_hash;
 /* Hash table for register lookup.  */
 static struct hash_control *reg_hash;
 \f
+#ifdef BFD_ASSEMBLER
+unsigned long
+i386_mach ()
+{
+  if (!strcmp (default_arch, "x86_64"))
+    return bfd_mach_x86_64;
+  else if (!strcmp (default_arch, "i386"))
+    return bfd_mach_i386_i386;
+  else
+    as_fatal (_("Unknown architecture"));
+}
+#endif
+\f
 void
 md_begin ()
 {
@@ -1085,7 +1131,7 @@ reloc (size, pcrel, sign, other)
   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;
@@ -1097,7 +1143,7 @@ reloc (size, pcrel, sign, other)
   else
     {
       if (sign)
-        switch (size)
+       switch (size)
          {
          case 4: return BFD_RELOC_X86_64_32S;
          }
@@ -1113,7 +1159,7 @@ reloc (size, pcrel, sign, other)
              sign ? "signed" : "unsigned", size);
     }
 
-  abort();
+  abort ();
   return BFD_RELOC_NONE;
 }
 
@@ -1139,6 +1185,7 @@ tc_i386_fix_adjustable (fixP)
       || fixP->fx_r_type == BFD_RELOC_386_GOT32
       || 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_VTABLE_INHERIT
       || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
     return 0;
@@ -1184,9 +1231,6 @@ md_assemble (line)
   /* Points to template once we've found it.  */
   const template *t;
 
-  /* Count the size of the instruction generated.  */
-  int insn_size = 0;
-
   int j;
 
   char mnemonic[MAX_MNEM_SIZE];
@@ -1194,7 +1238,7 @@ md_assemble (line)
   /* Initialize globals.  */
   memset (&i, '\0', sizeof (i));
   for (j = 0; j < MAX_OPERANDS; j++)
-    i.disp_reloc[j] = NO_RELOC;
+    i.reloc[j] = NO_RELOC;
   memset (disp_expressions, '\0', sizeof (disp_expressions));
   memset (im_expressions, '\0', sizeof (im_expressions));
   save_stack_p = save_stack;
@@ -1225,7 +1269,8 @@ md_assemble (line)
          }
        if (!is_space_char (*l)
            && *l != END_OF_INSN
-           && *l != PREFIX_SEPARATOR)
+           && *l != PREFIX_SEPARATOR
+           && *l != ',')
          {
            as_bad (_("invalid character %s in mnemonic"),
                    output_invalid (*l));
@@ -1316,6 +1361,38 @@ md_assemble (line)
          }
       }
 
+    if (current_templates->start->opcode_modifier & (Jump | JumpByte))
+      {
+       /* Check for a branch hint.  We allow ",pt" and ",pn" for
+          predict taken and predict not taken respectively.
+          I'm not sure that branch hints actually do anything on loop
+          and jcxz insns (JumpByte) for current Pentium4 chips.  They
+          may work in the future and it doesn't hurt to accept them
+          now.  */
+       if (l[0] == ',' && l[1] == 'p')
+         {
+           if (l[2] == 't')
+             {
+               if (! add_prefix (DS_PREFIX_OPCODE))
+                 return;
+               l += 3;
+             }
+           else if (l[2] == 'n')
+             {
+               if (! add_prefix (CS_PREFIX_OPCODE))
+                 return;
+               l += 3;
+             }
+         }
+      }
+    /* Any other comma loses.  */
+    if (*l == ',')
+      {
+       as_bad (_("invalid character %s in mnemonic"),
+               output_invalid (*l));
+       return;
+      }
+
     /* Check if instruction is supported on specified architecture.  */
     if (cpu_arch_flags != 0)
       {
@@ -1494,11 +1571,7 @@ md_assemble (line)
       {
        union i386_op temp_op;
        unsigned int temp_type;
-#ifdef BFD_ASSEMBLER
-       enum bfd_reloc_code_real temp_reloc;
-#else
-       int temp_reloc;
-#endif
+       RELOC_ENUM temp_reloc;
        int xchg1 = 0;
        int xchg2 = 0;
 
@@ -1518,9 +1591,9 @@ md_assemble (line)
        temp_op = i.op[xchg2];
        i.op[xchg2] = i.op[xchg1];
        i.op[xchg1] = temp_op;
-       temp_reloc = i.disp_reloc[xchg2];
-       i.disp_reloc[xchg2] = i.disp_reloc[xchg1];
-       i.disp_reloc[xchg1] = temp_reloc;
+       temp_reloc = i.reloc[xchg2];
+       i.reloc[xchg2] = i.reloc[xchg1];
+       i.reloc[xchg1] = temp_reloc;
 
        if (i.mem_operands == 2)
          {
@@ -1567,7 +1640,7 @@ md_assemble (line)
          if (i.types[op] & Imm)
            {
              switch (i.op[op].imms->X_op)
-               {
+               {
                  case O_constant:
                    /* If a suffix is given, this operand may be shortened.  */
                    switch (guess_suffix)
@@ -1583,12 +1656,13 @@ md_assemble (line)
                        break;
                      }
 
-                   /* If this operand is at most 16 bits, convert it to a
-                      signed 16 bit number before trying to see whether it will
-                      fit in an even smaller size.  This allows a 16-bit operand
-                      such as $0xffe0 to be recognised as within Imm8S range.  */
+                   /* If this operand is at most 16 bits, convert it
+                      to a signed 16 bit number before trying to see
+                      whether it will fit in an even smaller size.
+                      This allows a 16-bit operand such as $0xffe0 to
+                      be recognised as within Imm8S range.  */
                    if ((i.types[op] & Imm16)
-                       && (i.op[op].imms->X_add_number & ~(offsetT)0xffff) == 0)
+                       && (i.op[op].imms->X_add_number & ~(offsetT) 0xffff) == 0)
                      {
                        i.op[op].imms->X_add_number =
                          (((i.op[op].imms->X_add_number & 0xffff) ^ 0x8000) - 0x8000);
@@ -1606,7 +1680,7 @@ md_assemble (line)
                    break;
                  case O_absent:
                  case O_register:
-                   abort();
+                   abort ();
                  /* Symbols and expressions.  */
                  default:
                    /* Convert symbolic operand to proper sizes for matching.  */
@@ -1639,7 +1713,7 @@ md_assemble (line)
 
        for (op = i.operands; --op >= 0;)
          if ((i.types[op] & Disp)
-             && i.op[op].imms->X_op == O_constant)
+             && i.op[op].disps->X_op == O_constant)
            {
              offsetT disp = i.op[op].disps->X_add_number;
 
@@ -1714,7 +1788,7 @@ md_assemble (line)
              continue;
            /* We've found a match; break out of loop.  */
            break;
-          }
+         }
 
        overlap0 = i.types[0] & t->operand_types[0];
        switch (t->operands)
@@ -1822,10 +1896,10 @@ md_assemble (line)
       }
 
     /* 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 (SYSV386_COMPAT
+       && intel_syntax
+       && (i.tm.base_opcode & 0xfffffde0) == 0xdce0)
+      i.tm.base_opcode ^= FloatR;
 
     if (i.tm.opcode_modifier & FWait)
       if (! add_prefix (FWAIT_OPCODE))
@@ -1865,7 +1939,7 @@ md_assemble (line)
     if (i.reg_operands && flag_code < CODE_64BIT)
       {
        int op;
-       for (op = i.operands; --op >= 0; )
+       for (op = i.operands; --op >= 0;)
          if ((i.types[op] & Reg)
              && (i.op[op].regs->reg_flags & (RegRex64|RegRex)))
            {
@@ -1947,7 +2021,10 @@ md_assemble (line)
                    if (!quiet_warnings
                        && (i.tm.operand_types[op] & InOutPortReg) == 0)
                      as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"),
-                              (i.op[op].regs - (i.types[op] & Reg16 ? 8 : 16))->reg_name,
+                              (i.op[op].regs
+                               + (i.types[op] & Reg16
+                                  ? REGNAM_AL - REGNAM_AX
+                                  : REGNAM_AL - REGNAM_EAX))->reg_name,
                               i.op[op].regs->reg_name,
                               i.suffix);
 #endif
@@ -1997,7 +2074,7 @@ md_assemble (line)
 #if REGISTER_WARNINGS
                  else
                    as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"),
-                            (i.op[op].regs + 8)->reg_name,
+                            (i.op[op].regs + REGNAM_EAX - REGNAM_AX)->reg_name,
                             i.op[op].regs->reg_name,
                             i.suffix);
 #endif
@@ -2068,7 +2145,7 @@ md_assemble (line)
                  else
 #if REGISTER_WARNINGS
                    as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"),
-                            (i.op[op].regs - 8)->reg_name,
+                            (i.op[op].regs + REGNAM_AX - REGNAM_EAX)->reg_name,
                             i.op[op].regs->reg_name,
                             i.suffix);
 #endif
@@ -2088,7 +2165,7 @@ md_assemble (line)
        given in i.suffix.  Note: overlap2 cannot be an immediate!  */
     if ((overlap0 & (Imm8 | Imm8S | Imm16 | Imm32 | Imm32S))
        && overlap0 != Imm8 && overlap0 != Imm8S
-        && overlap0 != Imm16 && overlap0 != Imm32S
+       && overlap0 != Imm16 && overlap0 != Imm32S
        && overlap0 != Imm32 && overlap0 != Imm64)
       {
        if (i.suffix)
@@ -2114,7 +2191,7 @@ md_assemble (line)
       }
     if ((overlap1 & (Imm8 | Imm8S | Imm16 | Imm32S | Imm32))
        && overlap1 != Imm8 && overlap1 != Imm8S
-        && overlap1 != Imm16 && overlap1 != Imm32S
+       && overlap1 != Imm16 && overlap1 != Imm32S
        && overlap1 != Imm32 && overlap1 != Imm64)
       {
        if (i.suffix)
@@ -2207,8 +2284,8 @@ md_assemble (line)
            i.rex.mode64 = 1;
            if (flag_code < CODE_64BIT)
              {
-                as_bad (_("64bit operations available only in 64bit modes."));
-                return;
+               as_bad (_("64bit operations available only in 64bit modes."));
+               return;
              }
          }
 
@@ -2267,7 +2344,7 @@ md_assemble (line)
            /* Register goes in low 3 bits of opcode.  */
            i.tm.base_opcode |= i.op[op].regs->reg_num;
            if (i.op[op].regs->reg_flags & RegRex)
-             i.rex.extZ=1;
+             i.rex.extZ = 1;
            if (!quiet_warnings && (i.tm.opcode_modifier & Ugh) != 0)
              {
                /* Warn about some common errors, but press on regardless.
@@ -2319,18 +2396,18 @@ md_assemble (line)
                    i.rm.reg = i.op[dest].regs->reg_num;
                    i.rm.regmem = i.op[source].regs->reg_num;
                    if (i.op[dest].regs->reg_flags & RegRex)
-                     i.rex.extX=1;
+                     i.rex.extX = 1;
                    if (i.op[source].regs->reg_flags & RegRex)
-                     i.rex.extZ=1;
+                     i.rex.extZ = 1;
                  }
                else
                  {
                    i.rm.reg = i.op[source].regs->reg_num;
                    i.rm.regmem = i.op[dest].regs->reg_num;
                    if (i.op[dest].regs->reg_flags & RegRex)
-                     i.rex.extZ=1;
+                     i.rex.extZ = 1;
                    if (i.op[source].regs->reg_flags & RegRex)
-                     i.rex.extX=1;
+                     i.rex.extX = 1;
                  }
              }
            else
@@ -2366,9 +2443,11 @@ md_assemble (line)
                              }
                            else
                              {
-                               /* 64bit mode overwrites the 32bit absolute addressing
-                                  by RIP relative addressing and absolute addressing
-                                  is encoded by one of the redundant SIB forms.  */
+                               /* 64bit mode overwrites the 32bit
+                                  absolute addressing by RIP relative
+                                  addressing and absolute addressing
+                                  is encoded by one of the redundant
+                                  SIB forms.  */
 
                                i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
                                i.sib.base = NO_BASE_REGISTER;
@@ -2389,7 +2468,7 @@ md_assemble (line)
                            else
                              i.types[op] |= Disp32S;
                            if (i.index_reg->reg_flags & RegRex)
-                             i.rex.extY=1;
+                             i.rex.extY = 1;
                          }
                      }
                    /* RIP addressing for 64bit mode.  */
@@ -2442,7 +2521,7 @@ md_assemble (line)
                          }
                        i.rm.regmem = i.base_reg->reg_num;
                        if (i.base_reg->reg_flags & RegRex)
-                         i.rex.extZ=1;
+                         i.rex.extZ = 1;
                        i.sib.base = i.base_reg->reg_num;
                        /* x86-64 ignores REX prefix bit here to avoid
                           decoder complications.  */
@@ -2481,7 +2560,7 @@ md_assemble (line)
                            i.sib.index = i.index_reg->reg_num;
                            i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING;
                            if (i.index_reg->reg_flags & RegRex)
-                             i.rex.extY=1;
+                             i.rex.extY = 1;
                          }
                        i.rm.mode = mode_from_disp_size (i.types[op]);
                      }
@@ -2527,13 +2606,13 @@ md_assemble (line)
                      {
                        i.rm.regmem = i.op[op].regs->reg_num;
                        if (i.op[op].regs->reg_flags & RegRex)
-                         i.rex.extZ=1;
+                         i.rex.extZ = 1;
                      }
                    else
                      {
                        i.rm.reg = i.op[op].regs->reg_num;
                        if (i.op[op].regs->reg_flags & RegRex)
-                         i.rex.extX=1;
+                         i.rex.extX = 1;
                      }
 
                    /* Now, if no memory operand has set i.rm.mode = 0, 1, 2
@@ -2620,7 +2699,7 @@ md_assemble (line)
          && ((i.types[0] & Reg8) || (i.types[1] & Reg8))))
     {
       int x;
-      i.rex.empty=1;
+      i.rex.empty = 1;
       for (x = 0; x < 2; x++)
        {
          /* Look for 8bit operand that does use old registers.  */
@@ -2652,10 +2731,14 @@ md_assemble (line)
   {
     register char *p;
 
+    /* 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);
+
     /* Output jumps.  */
     if (i.tm.opcode_modifier & Jump)
       {
-       int size;
        int code16;
        int prefix;
 
@@ -2670,16 +2753,19 @@ md_assemble (line)
            i.prefixes -= 1;
            code16 ^= CODE16;
          }
+       /* Pentium4 branch hints.  */
+       if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE /* not taken */
+           || i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE /* taken */)
+         {
+           prefix++;
+           i.prefixes--;
+         }
        if (i.prefix[REX_PREFIX])
          {
            prefix++;
-           i.prefixes --;
+           i.prefixes--;
          }
 
-       size = 4;
-       if (code16)
-         size = 2;
-
        if (i.prefixes != 0 && !intel_syntax)
          as_warn (_("skipping prefixes on this instruction"));
 
@@ -2688,23 +2774,27 @@ md_assemble (line)
           instruction we may generate in md_convert_frag.  This is 2
           bytes for the opcode and room for the prefix and largest
           displacement.  */
-       frag_grow (prefix + 2 + size);
-       insn_size += prefix + 1;
+       frag_grow (prefix + 2 + 4);
        /* Prefix and 1 opcode byte go in fr_fix.  */
        p = frag_more (prefix + 1);
        if (i.prefix[DATA_PREFIX])
          *p++ = DATA_PREFIX_OPCODE;
+       if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE
+           || i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE)
+         *p++ = i.prefix[SEG_PREFIX];
        if (i.prefix[REX_PREFIX])
          *p++ = i.prefix[REX_PREFIX];
        *p = i.tm.base_opcode;
        /* 1 possible extra opcode + displacement go in var part.
           Pass reloc in fr_var.  */
        frag_var (rs_machine_dependent,
-                 1 + size,
-                 i.disp_reloc[0],
+                 1 + 4,
+                 i.reloc[0],
                  ((unsigned char) *p == JUMP_PC_RELATIVE
                   ? ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL) | code16
-                  : ENCODE_RELAX_STATE (COND_JUMP, SMALL) | code16),
+                  : ((cpu_arch_flags & Cpu386) != 0
+                     ? ENCODE_RELAX_STATE (COND_JUMP, SMALL) | code16
+                     : ENCODE_RELAX_STATE (COND_JUMP86, SMALL) | code16)),
                  i.op[0].disps->X_add_symbol,
                  i.op[0].disps->X_add_number,
                  p);
@@ -2719,10 +2809,16 @@ md_assemble (line)
            size = 1;
            if (i.prefix[ADDR_PREFIX])
              {
-               insn_size += 1;
                FRAG_APPEND_1_CHAR (ADDR_PREFIX_OPCODE);
                i.prefixes -= 1;
              }
+           /* Pentium4 branch hints.  */
+           if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE /* not taken */
+               || i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE /* taken */)
+             {
+               FRAG_APPEND_1_CHAR (i.prefix[SEG_PREFIX]);
+               i.prefixes--;
+             }
          }
        else
          {
@@ -2734,7 +2830,6 @@ md_assemble (line)
 
            if (i.prefix[DATA_PREFIX])
              {
-               insn_size += 1;
                FRAG_APPEND_1_CHAR (DATA_PREFIX_OPCODE);
                i.prefixes -= 1;
                code16 ^= CODE16;
@@ -2748,29 +2843,17 @@ md_assemble (line)
        if (i.prefix[REX_PREFIX])
          {
            FRAG_APPEND_1_CHAR (i.prefix[REX_PREFIX]);
-           insn_size++;
            i.prefixes -= 1;
          }
 
        if (i.prefixes != 0 && !intel_syntax)
          as_warn (_("skipping prefixes on this instruction"));
 
-       if (fits_in_unsigned_byte (i.tm.base_opcode))
-         {
-           insn_size += 1 + size;
-           p = frag_more (1 + size);
-         }
-       else
-         {
-           /* Opcode can be at most two bytes.  */
-           insn_size += 2 + size;
-           p = frag_more (2 + size);
-           *p++ = (i.tm.base_opcode >> 8) & 0xff;
-         }
-       *p++ = i.tm.base_opcode & 0xff;
+       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.disp_reloc[0]));
+                    i.op[0].disps, 1, reloc (size, 1, 1, i.reloc[0]));
       }
     else if (i.tm.opcode_modifier & JumpInterSegment)
       {
@@ -2803,7 +2886,6 @@ md_assemble (line)
          as_warn (_("skipping prefixes on this instruction"));
 
        /* 1 opcode; 2 segment; offset  */
-       insn_size += prefix + 1 + 2 + size;
        p = frag_more (prefix + 1 + 2 + size);
 
        if (i.prefix[DATA_PREFIX])
@@ -2828,7 +2910,7 @@ md_assemble (line)
          }
        else
          fix_new_exp (frag_now, p - frag_now->fr_literal, size,
-                      i.op[1].imms, 0, reloc (size, 0, 0, i.disp_reloc[0]));
+                      i.op[1].imms, 0, reloc (size, 0, 0, i.reloc[1]));
        if (i.op[0].imms->X_op != O_constant)
          as_bad (_("can't handle non absolute segment in `%s'"),
                  i.tm.name);
@@ -2851,7 +2933,6 @@ md_assemble (line)
          {
            if (*q)
              {
-               insn_size += 1;
                p = frag_more (1);
                md_number_to_chars (p, (valueT) *q, 1);
              }
@@ -2860,12 +2941,10 @@ md_assemble (line)
        /* Now the opcode; be careful about word order here!  */
        if (fits_in_unsigned_byte (i.tm.base_opcode))
          {
-           insn_size += 1;
            FRAG_APPEND_1_CHAR (i.tm.base_opcode);
          }
        else
          {
-           insn_size += 2;
            p = frag_more (2);
            /* Put out high byte first: can't use md_number_to_chars!  */
            *p++ = (i.tm.base_opcode >> 8) & 0xff;
@@ -2875,7 +2954,6 @@ md_assemble (line)
        /* Now the modrm byte and sib byte (if present).  */
        if (i.tm.opcode_modifier & Modrm)
          {
-           insn_size += 1;
            p = frag_more (1);
            md_number_to_chars (p,
                                (valueT) (i.rm.regmem << 0
@@ -2890,7 +2968,6 @@ md_assemble (line)
                && i.rm.mode != 3
                && !(i.base_reg && (i.base_reg->reg_type & Reg16) != 0))
              {
-               insn_size += 1;
                p = frag_more (1);
                md_number_to_chars (p,
                                    (valueT) (i.sib.base << 0
@@ -2924,7 +3001,6 @@ md_assemble (line)
                          }
                        val = offset_in_range (i.op[n].disps->X_add_number,
                                               size);
-                       insn_size += size;
                        p = frag_more (size);
                        md_number_to_chars (p, val, size);
                      }
@@ -2957,25 +3033,24 @@ md_assemble (line)
                                }
                            /* We should find the immediate.  */
                            if (n1 == i.operands)
-                             abort();
+                             abort ();
                            i.op[n].disps->X_add_number -= imm_size;
                          }
 
                        if (i.types[n] & Disp32S)
                          sign = 1;
 
-                       if (i.types[n] & (Disp16 | Disp64))
+                       if (i.types[n] & (Disp16 | Disp64))
                          {
                            size = 2;
                            if (i.types[n] & Disp64)
                              size = 8;
                          }
 
-                       insn_size += size;
                        p = frag_more (size);
                        fix_new_exp (frag_now, p - frag_now->fr_literal, size,
                                     i.op[n].disps, pcrel,
-                                    reloc (size, pcrel, sign, i.disp_reloc[n]));
+                                    reloc (size, pcrel, sign, i.reloc[n]));
                      }
                  }
              }
@@ -3006,7 +3081,6 @@ md_assemble (line)
                          }
                        val = offset_in_range (i.op[n].imms->X_add_number,
                                               size);
-                       insn_size += size;
                        p = frag_more (size);
                        md_number_to_chars (p, val, size);
                      }
@@ -3016,11 +3090,7 @@ md_assemble (line)
                           Need a 32-bit fixup (don't support 8bit
                           non-absolute imms).  Try to support other
                           sizes ...  */
-#ifdef BFD_ASSEMBLER
-                       enum bfd_reloc_code_real reloc_type;
-#else
-                       int reloc_type;
-#endif
+                       RELOC_ENUM reloc_type;
                        int size = 4;
                        int sign = 0;
 
@@ -3036,9 +3106,8 @@ md_assemble (line)
                              size = 8;
                          }
 
-                       insn_size += size;
                        p = frag_more (size);
-                       reloc_type = reloc (size, 0, sign, i.disp_reloc[0]);
+                       reloc_type = reloc (size, 0, sign, i.reloc[n]);
 #ifdef BFD_ASSEMBLER
                        if (reloc_type == BFD_RELOC_32
                            && GOT_symbol
@@ -3051,7 +3120,7 @@ md_assemble (line)
                          {
                            /* We don't support dynamic linking on x86-64 yet.  */
                            if (flag_code == CODE_64BIT)
-                             abort();
+                             abort ();
                            reloc_type = BFD_RELOC_386_GOTPC;
                            i.op[n].imms->X_add_number += 3;
                          }
@@ -3064,8 +3133,6 @@ md_assemble (line)
          }
       }
 
-    dwarf2_emit_insn (insn_size);
-
 #ifdef DEBUG386
     if (flag_debug)
       {
@@ -3075,6 +3142,144 @@ md_assemble (line)
   }
 }
 \f
+#ifndef LEX_AT
+static char *lex_got PARAMS ((RELOC_ENUM *, int *));
+
+/* Parse operands of the form
+   <symbol>@GOTOFF+<nnn>
+   and similar .plt or .got references.
+
+   If we find one, set up the correct relocation in RELOC and copy the
+   input string, minus the `@GOTOFF' into a malloc'd buffer for
+   parsing by the calling routine.  Return this buffer, and if ADJUST
+   is non-null set it to the length of the string we removed from the
+   input line.  Otherwise return NULL.  */
+static char *
+lex_got (reloc, adjust)
+     RELOC_ENUM *reloc;
+     int *adjust;
+{
+  static const char * const mode_name[NUM_FLAG_CODE] = { "32", "16", "64" };
+  static const struct {
+    const char *str;
+    const RELOC_ENUM rel[NUM_FLAG_CODE];
+  } 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    } }
+  };
+  char *cp;
+  unsigned int j;
+
+  for (cp = input_line_pointer; *cp != '@'; cp++)
+    if (is_end_of_line[(unsigned char) *cp])
+      return NULL;
+
+  for (j = 0; j < sizeof (gotrel) / sizeof (gotrel[0]); j++)
+    {
+      int len;
+
+      len = strlen (gotrel[j].str);
+      if (strncasecmp (cp + 1, gotrel[j].str, len) == 0)
+       {
+         if (gotrel[j].rel[(unsigned int) flag_code] != 0)
+           {
+             int first, second;
+             char *tmpbuf, *past_reloc;
+
+             *reloc = gotrel[j].rel[(unsigned int) flag_code];
+             if (adjust)
+               *adjust = len;
+
+             if (GOT_symbol == NULL)
+               GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
+
+             /* Replace the relocation token with ' ', so that
+                errors like foo@GOTOFF1 will be detected.  */
+
+             /* The length of the first part of our input line.  */
+             first = cp - input_line_pointer;
+
+             /* The second part goes from after the reloc token until
+                (and including) an end_of_line char.  Don't use strlen
+                here as the end_of_line char may not be a NUL.  */
+             past_reloc = cp + 1 + len;
+             for (cp = past_reloc; !is_end_of_line[(unsigned char) *cp++]; )
+               ;
+             second = cp - past_reloc;
+
+             /* Allocate and copy string.  The trailing NUL shouldn't
+                be necessary, but be safe.  */
+             tmpbuf = xmalloc (first + second + 2);
+             memcpy (tmpbuf, input_line_pointer, first);
+             tmpbuf[first] = ' ';
+             memcpy (tmpbuf + first + 1, past_reloc, second);
+             tmpbuf[first + second + 1] = '\0';
+             return tmpbuf;
+           }
+
+         as_bad (_("@%s reloc is not supported in %s bit mode"),
+                 gotrel[j].str, mode_name[(unsigned int) flag_code]);
+         return NULL;
+       }
+    }
+
+  /* Might be a symbol version string.  Don't as_bad here.  */
+  return NULL;
+}
+
+/* x86_cons_fix_new is called via the expression parsing code when a
+   reloc is needed.  We use this hook to get the correct .got reloc.  */
+static RELOC_ENUM got_reloc = NO_RELOC;
+
+void
+x86_cons_fix_new (frag, off, len, exp)
+     fragS *frag;
+     unsigned int off;
+     unsigned int len;
+     expressionS *exp;
+{
+  RELOC_ENUM r = reloc (len, 0, 0, got_reloc);
+  got_reloc = NO_RELOC;
+  fix_new_exp (frag, off, len, exp, 0, r);
+}
+
+void
+x86_cons (exp, size)
+     expressionS *exp;
+     int size;
+{
+  if (size == 4)
+    {
+      /* Handle @GOTOFF and the like in an expression.  */
+      char *save;
+      char *gotfree_input_line;
+      int adjust;
+
+      save = input_line_pointer;
+      gotfree_input_line = lex_got (&got_reloc, &adjust);
+      if (gotfree_input_line)
+       input_line_pointer = gotfree_input_line;
+
+      expression (exp);
+
+      if (gotfree_input_line)
+       {
+         /* expression () has merrily parsed up to the end of line,
+            or a comma - in the wrong buffer.  Transfer how far
+            input_line_pointer has moved to the right buffer.  */
+         input_line_pointer = (save
+                               + (input_line_pointer - gotfree_input_line)
+                               + adjust);
+         free (gotfree_input_line);
+       }
+    }
+  else
+    expression (exp);
+}
+#endif
+
 static int i386_immediate PARAMS ((char *));
 
 static int
@@ -3082,6 +3287,9 @@ 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;
 
@@ -3101,80 +3309,22 @@ i386_immediate (imm_start)
   input_line_pointer = imm_start;
 
 #ifndef LEX_AT
-  {
-    /* We can have operands of the form
-         <symbol>@GOTOFF+<nnn>
-       Take the easy way out here and copy everything
-       into a temporary buffer...  */
-    register char *cp;
-
-    cp = strchr (input_line_pointer, '@');
-    if (cp != NULL)
-      {
-       char *tmpbuf;
-       int len = 0;
-       int first;
-
-       /* GOT relocations are not supported in 16 bit mode.  */
-       if (flag_code == CODE_16BIT)
-         as_bad (_("GOT relocations not supported in 16 bit mode"));
-
-       if (GOT_symbol == NULL)
-         GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
-
-       if (strncmp (cp + 1, "PLT", 3) == 0)
-         {
-           if (flag_code == CODE_64BIT)
-             i.disp_reloc[this_operand] = BFD_RELOC_X86_64_PLT32;
-           else
-             i.disp_reloc[this_operand] = BFD_RELOC_386_PLT32;
-           len = 3;
-         }
-       else if (strncmp (cp + 1, "GOTOFF", 6) == 0)
-         {
-           if (flag_code == CODE_64BIT)
-             as_bad ("GOTOFF relocations are unsupported in 64bit mode.");
-           i.disp_reloc[this_operand] = BFD_RELOC_386_GOTOFF;
-           len = 6;
-         }
-       else if (strncmp (cp + 1, "GOTPCREL", 8) == 0)
-         {
-           if (flag_code == CODE_64BIT)
-             i.disp_reloc[this_operand] = BFD_RELOC_X86_64_GOTPCREL;
-           else
-             as_bad ("GOTPCREL relocations are supported only in 64bit mode.");
-           len = 8;
-         }
-       else if (strncmp (cp + 1, "GOT", 3) == 0)
-         {
-           if (flag_code == CODE_64BIT)
-             i.disp_reloc[this_operand] = BFD_RELOC_X86_64_GOT32;
-           else
-             i.disp_reloc[this_operand] = BFD_RELOC_386_GOT32;
-           len = 3;
-         }
-       else
-         as_bad (_("bad reloc specifier in expression"));
-
-       /* Replace the relocation token with ' ', so that errors like
-          foo@GOTOFF1 will be detected.  */
-       first = cp - input_line_pointer;
-       tmpbuf = (char *) alloca (strlen (input_line_pointer));
-       memcpy (tmpbuf, input_line_pointer, first);
-       tmpbuf[first] = ' ';
-       strcpy (tmpbuf + first + 1, cp + 1 + len);
-       input_line_pointer = tmpbuf;
-      }
-  }
+  gotfree_input_line = lex_got (&i.reloc[this_operand], NULL);
+  if (gotfree_input_line)
+    input_line_pointer = gotfree_input_line;
 #endif
 
   exp_seg = expression (exp);
 
   SKIP_WHITESPACE ();
   if (*input_line_pointer)
-    as_bad (_("ignoring junk `%s' after expression"), input_line_pointer);
+    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)
     {
@@ -3228,35 +3378,38 @@ i386_immediate (imm_start)
   return 1;
 }
 
-static int i386_scale PARAMS ((char *));
+static char *i386_scale PARAMS ((char *));
 
-static int
+static char *
 i386_scale (scale)
      char *scale;
 {
-  if (!isdigit (*scale))
-    goto bad_scale;
+  offsetT val;
+  char *save = input_line_pointer;
 
-  switch (*scale)
+  input_line_pointer = scale;
+  val = get_absolute_expression ();
+
+  switch (val)
     {
-    case '0':
-    case '1':
+    case 0:
+    case 1:
       i.log2_scale_factor = 0;
       break;
-    case '2':
+    case 2:
       i.log2_scale_factor = 1;
       break;
-    case '4':
+    case 4:
       i.log2_scale_factor = 2;
       break;
-    case '8':
+    case 8:
       i.log2_scale_factor = 3;
       break;
     default:
-    bad_scale:
       as_bad (_("expecting scale factor of 1, 2, 4, or 8: got `%s'"),
              scale);
-      return 0;
+      input_line_pointer = save;
+      return NULL;
     }
   if (i.log2_scale_factor != 0 && ! i.index_reg)
     {
@@ -3266,7 +3419,9 @@ i386_scale (scale)
       i.log2_scale_factor = 0;
 #endif
     }
-  return 1;
+  scale = input_line_pointer;
+  input_line_pointer = save;
+  return scale;
 }
 
 static int i386_displacement PARAMS ((char *, char *));
@@ -3279,6 +3434,9 @@ i386_displacement (disp_start, disp_end)
   register expressionS *exp;
   segT exp_seg = 0;
   char *save_input_line_pointer;
+#ifndef LEX_AT
+  char *gotfree_input_line;
+#endif
   int bigdisp = Disp32;
 
   if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0))
@@ -3339,101 +3497,54 @@ i386_displacement (disp_start, disp_end)
     }
 #endif
 #ifndef LEX_AT
-  {
-    /* We can have operands of the form
-         <symbol>@GOTOFF+<nnn>
-       Take the easy way out here and copy everything
-       into a temporary buffer...  */
-    register char *cp;
-
-    cp = strchr (input_line_pointer, '@');
-    if (cp != NULL)
-      {
-       char *tmpbuf;
-       int len = 0;
-       int first;
-
-       /* GOT relocations are not supported in 16 bit mode.  */
-       if (flag_code == CODE_16BIT)
-         as_bad (_("GOT relocations not supported in 16 bit mode"));
-
-       if (GOT_symbol == NULL)
-         GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
-
-       if (strncmp (cp + 1, "PLT", 3) == 0)
-         {
-           if (flag_code == CODE_64BIT)
-             i.disp_reloc[this_operand] = BFD_RELOC_X86_64_PLT32;
-           else
-             i.disp_reloc[this_operand] = BFD_RELOC_386_PLT32;
-           len = 3;
-         }
-       else if (strncmp (cp + 1, "GOTOFF", 6) == 0)
-         {
-           if (flag_code == CODE_64BIT)
-             as_bad ("GOTOFF relocation is not supported in 64bit mode.");
-           i.disp_reloc[this_operand] = BFD_RELOC_386_GOTOFF;
-           len = 6;
-         }
-       else if (strncmp (cp + 1, "GOTPCREL", 8) == 0)
-         {
-           if (flag_code != CODE_64BIT)
-             as_bad ("GOTPCREL relocation is supported only in 64bit mode.");
-           i.disp_reloc[this_operand] = BFD_RELOC_X86_64_GOTPCREL;
-           len = 8;
-         }
-       else if (strncmp (cp + 1, "GOT", 3) == 0)
-         {
-           if (flag_code == CODE_64BIT)
-             i.disp_reloc[this_operand] = BFD_RELOC_X86_64_GOT32;
-           else
-             i.disp_reloc[this_operand] = BFD_RELOC_386_GOT32;
-           len = 3;
-         }
-       else
-         as_bad (_("bad reloc specifier in expression"));
-
-       /* Replace the relocation token with ' ', so that errors like
-          foo@GOTOFF1 will be detected.  */
-       first = cp - input_line_pointer;
-       tmpbuf = (char *) alloca (strlen (input_line_pointer));
-       memcpy (tmpbuf, input_line_pointer, first);
-       tmpbuf[first] = ' ';
-       strcpy (tmpbuf + first + 1, cp + 1 + len);
-       input_line_pointer = tmpbuf;
-      }
-  }
+  gotfree_input_line = lex_got (&i.reloc[this_operand], NULL);
+  if (gotfree_input_line)
+    input_line_pointer = gotfree_input_line;
 #endif
 
   exp_seg = expression (exp);
 
+  SKIP_WHITESPACE ();
+  if (*input_line_pointer)
+    as_bad (_("junk `%s' after expression"), input_line_pointer);
+#if GCC_ASM_O_HACK
+  RESTORE_END_STRING (disp_end + 1);
+#endif
+  RESTORE_END_STRING (disp_end);
+  input_line_pointer = save_input_line_pointer;
+#ifndef LEX_AT
+  if (gotfree_input_line)
+    free (gotfree_input_line);
+#endif
+
 #ifdef BFD_ASSEMBLER
   /* We do this to make sure that the section symbol is in
      the symbol table.  We will ultimately change the relocation
      to be relative to the beginning of the section.  */
-  if (i.disp_reloc[this_operand] == BFD_RELOC_386_GOTOFF
-      || i.disp_reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL)
+  if (i.reloc[this_operand] == BFD_RELOC_386_GOTOFF
+      || i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL)
     {
-      if (S_IS_LOCAL(exp->X_add_symbol)
+      if (exp->X_op != O_symbol)
+       {
+         as_bad (_("bad expression used with @%s"),
+                 (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL
+                  ? "GOTPCREL"
+                  : "GOTOFF"));
+         return 0;
+       }
+
+      if (S_IS_LOCAL (exp->X_add_symbol)
          && S_GET_SEGMENT (exp->X_add_symbol) != undefined_section)
        section_symbol (S_GET_SEGMENT (exp->X_add_symbol));
-      assert (exp->X_op == O_symbol);
       exp->X_op = O_subtract;
       exp->X_op_symbol = GOT_symbol;
-      i.disp_reloc[this_operand] = BFD_RELOC_32;
+      if (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL)
+        i.reloc[this_operand] = BFD_RELOC_32_PCREL;
+      else
+        i.reloc[this_operand] = BFD_RELOC_32;
     }
 #endif
 
-  SKIP_WHITESPACE ();
-  if (*input_line_pointer)
-    as_bad (_("ignoring junk `%s' after expression"),
-           input_line_pointer);
-#if GCC_ASM_O_HACK
-  RESTORE_END_STRING (disp_end + 1);
-#endif
-  RESTORE_END_STRING (disp_end);
-  input_line_pointer = save_input_line_pointer;
-
   if (exp->X_op == O_absent || exp->X_op == O_big)
     {
       /* Missing or bad expr becomes absolute 0.  */
@@ -3468,7 +3579,7 @@ i386_displacement (disp_start, disp_end)
   return 1;
 }
 
-static int i386_index_check PARAMS((const char *));
+static int i386_index_check PARAMS ((const char *));
 
 /* Make sure the memory operand we've been dealt is valid.
    Return 1 on success, 0 on a failure.  */
@@ -3514,14 +3625,14 @@ i386_index_check (operand_string)
            ok = 0;
        }
       else
-        {
+       {
          /* 32bit checks.  */
          if ((i.base_reg
               && (i.base_reg->reg_type & (Reg32 | RegRex)) != Reg32)
              || (i.index_reg
                  && ((i.index_reg->reg_type & (Reg32|BaseIndex|RegRex))
                      != (Reg32|BaseIndex))))
-          ok = 0;
+           ok = 0;
        }
     }
   if (!ok)
@@ -3662,7 +3773,7 @@ i386_operand (operand_string)
     }
   else if (is_digit_char (*op_string)
           || is_identifier_char (*op_string)
-          || *op_string == '(' )
+          || *op_string == '(')
     {
       /* This is a memory reference of some sort.  */
       char *base_string;
@@ -3752,7 +3863,7 @@ i386_operand (operand_string)
                          if (is_space_char (*base_string))
                            ++base_string;
                        }
-                     else if (*base_string != ')' )
+                     else if (*base_string != ')')
                        {
                          as_bad (_("expecting `,' or `)' after index register in `%s'"),
                                  operand_string);
@@ -3766,12 +3877,14 @@ i386_operand (operand_string)
                    }
 
                  /* Check for scale factor.  */
-                 if (isdigit ((unsigned char) *base_string))
+                 if (*base_string != ')')
                    {
-                     if (!i386_scale (base_string))
+                     char *end_scale = i386_scale (base_string);
+
+                     if (!end_scale)
                        return 0;
 
-                     ++base_string;
+                     base_string = end_scale;
                      if (is_space_char (*base_string))
                        ++base_string;
                      if (*base_string != ')')
@@ -3872,11 +3985,7 @@ md_estimate_size_before_relax (fragP, segment)
       /* Symbol is undefined in this segment, or we need to keep a
         reloc so that weak symbols can be overridden.  */
       int size = (fragP->fr_subtype & CODE16) ? 2 : 4;
-#ifdef BFD_ASSEMBLER
-      enum bfd_reloc_code_real reloc_type;
-#else
-      int reloc_type;
-#endif
+      RELOC_ENUM reloc_type;
       unsigned char *opcode;
       int old_fr_fix;
 
@@ -3890,10 +3999,10 @@ md_estimate_size_before_relax (fragP, segment)
       old_fr_fix = fragP->fr_fix;
       opcode = (unsigned char *) fragP->fr_opcode;
 
-      switch (opcode[0])
+      switch (TYPE_FROM_RELAX_STATE (fragP->fr_subtype))
        {
-       case JUMP_PC_RELATIVE:
-         /* Make jmp (0xeb) a dword displacement jump.  */
+       case UNCOND_JUMP:
+         /* Make jmp (0xeb) a (d)word displacement jump.  */
          opcode[0] = 0xe9;
          fragP->fr_fix += size;
          fix_new (fragP, old_fr_fix, size,
@@ -3902,9 +4011,35 @@ md_estimate_size_before_relax (fragP, segment)
                   reloc_type);
          break;
 
-       default:
+       case COND_JUMP86:
+         if (no_cond_jump_promotion)
+           goto relax_guess;
+
+         if (size == 2)
+           {
+             /* Negate the condition, and branch past an
+                unconditional jump.  */
+             opcode[0] ^= 1;
+             opcode[1] = 3;
+             /* Insert an unconditional jump.  */
+             opcode[2] = 0xe9;
+             /* We added two extra opcode bytes, and have a two byte
+                offset.  */
+             fragP->fr_fix += 2 + 2;
+             fix_new (fragP, old_fr_fix + 2, 2,
+                      fragP->fr_symbol,
+                      fragP->fr_offset, 1,
+                      reloc_type);
+             break;
+           }
+         /* Fall through.  */
+
+       case COND_JUMP:
+         if (no_cond_jump_promotion)
+           goto relax_guess;
+
          /* This changes the byte-displacement jump 0x7N
-            to the dword-displacement jump 0x0f,0x8N.  */
+            to the (d)word-displacement jump 0x0f,0x8N.  */
          opcode[1] = opcode[0] + 0x10;
          opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
          /* We've added an opcode byte.  */
@@ -3914,12 +4049,23 @@ md_estimate_size_before_relax (fragP, segment)
                   fragP->fr_offset, 1,
                   reloc_type);
          break;
+
+       default:
+         BAD_CASE (fragP->fr_subtype);
+         break;
        }
       frag_wane (fragP);
       return fragP->fr_fix - old_fr_fix;
     }
-  /* Guess a short jump.  */
-  return 1;
+
+ 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
+     long.  However, we can relax a section more than once and in that
+     case we must either set fr_subtype back to the unrelaxed state,
+     or return the value for the appropriate branch.  */
+  return md_relax_table[fragP->fr_subtype].rlx_length;
 }
 
 /* Called after relax() is finished.
@@ -3956,10 +4102,6 @@ md_convert_frag (abfd, sec, fragP)
 
   /* Address we want to reach in file space.  */
   target_address = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset;
-#ifdef BFD_ASSEMBLER
-  /* Not needed otherwise?  */
-  target_address += symbol_get_frag (fragP->fr_symbol)->fr_address;
-#endif
 
   /* Address opcode resides at in file space.  */
   opcode_address = fragP->fr_address + fragP->fr_fix;
@@ -3967,51 +4109,65 @@ md_convert_frag (abfd, sec, fragP)
   /* Displacement from opcode start to fill into instruction.  */
   displacement_from_opcode_start = target_address - opcode_address;
 
-  switch (fragP->fr_subtype)
+  if ((fragP->fr_subtype & BIG) == 0)
     {
-    case ENCODE_RELAX_STATE (COND_JUMP, SMALL):
-    case ENCODE_RELAX_STATE (COND_JUMP, SMALL16):
-    case ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL):
-    case ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL16):
       /* Don't have to change opcode.  */
       extension = 1;           /* 1 opcode + 1 displacement  */
       where_to_put_displacement = &opcode[1];
-      break;
+    }
+  else
+    {
+      if (no_cond_jump_promotion
+         && TYPE_FROM_RELAX_STATE (fragP->fr_subtype) != UNCOND_JUMP)
+       as_warn_where (fragP->fr_file, fragP->fr_line, _("long jump required"));
 
-    case ENCODE_RELAX_STATE (COND_JUMP, BIG):
-      extension = 5;           /* 2 opcode + 4 displacement  */
-      opcode[1] = opcode[0] + 0x10;
-      opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
-      where_to_put_displacement = &opcode[2];
-      break;
+      switch (fragP->fr_subtype)
+       {
+       case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG):
+         extension = 4;                /* 1 opcode + 4 displacement  */
+         opcode[0] = 0xe9;
+         where_to_put_displacement = &opcode[1];
+         break;
 
-    case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG):
-      extension = 4;           /* 1 opcode + 4 displacement  */
-      opcode[0] = 0xe9;
-      where_to_put_displacement = &opcode[1];
-      break;
+       case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG16):
+         extension = 2;                /* 1 opcode + 2 displacement  */
+         opcode[0] = 0xe9;
+         where_to_put_displacement = &opcode[1];
+         break;
 
-    case ENCODE_RELAX_STATE (COND_JUMP, BIG16):
-      extension = 3;           /* 2 opcode + 2 displacement  */
-      opcode[1] = opcode[0] + 0x10;
-      opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
-      where_to_put_displacement = &opcode[2];
-      break;
+       case ENCODE_RELAX_STATE (COND_JUMP, BIG):
+       case ENCODE_RELAX_STATE (COND_JUMP86, BIG):
+         extension = 5;                /* 2 opcode + 4 displacement  */
+         opcode[1] = opcode[0] + 0x10;
+         opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
+         where_to_put_displacement = &opcode[2];
+         break;
 
-    case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG16):
-      extension = 2;           /* 1 opcode + 2 displacement  */
-      opcode[0] = 0xe9;
-      where_to_put_displacement = &opcode[1];
-      break;
+       case ENCODE_RELAX_STATE (COND_JUMP, BIG16):
+         extension = 3;                /* 2 opcode + 2 displacement  */
+         opcode[1] = opcode[0] + 0x10;
+         opcode[0] = TWO_BYTE_OPCODE_ESCAPE;
+         where_to_put_displacement = &opcode[2];
+         break;
 
-    default:
-      BAD_CASE (fragP->fr_subtype);
-      break;
+       case ENCODE_RELAX_STATE (COND_JUMP86, BIG16):
+         extension = 4;
+         opcode[0] ^= 1;
+         opcode[1] = 3;
+         opcode[2] = 0xe9;
+         where_to_put_displacement = &opcode[3];
+         break;
+
+       default:
+         BAD_CASE (fragP->fr_subtype);
+         break;
+       }
     }
+
   /* Now put displacement after opcode.  */
   md_number_to_chars ((char *) where_to_put_displacement,
                      (valueT) (displacement_from_opcode_start - extension),
-                     SIZE_FROM_RELAX_STATE (fragP->fr_subtype));
+                     DISP_SIZE_FROM_RELAX_STATE (fragP->fr_subtype));
   fragP->fr_fix += extension;
 }
 \f
@@ -4101,7 +4257,7 @@ md_apply_fix3 (fixP, valp, seg)
   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)
+      && fixP->fx_addsy && !use_rela_relocations)
     {
 #ifndef OBJ_AOUT
       if (OUTPUT_FLAVOR == bfd_target_elf_flavour
@@ -4487,9 +4643,9 @@ i386_target_format ()
 #if defined (OBJ_MAYBE_ELF) || defined (OBJ_ELF)
     case bfd_target_elf_flavour:
       {
-        if (flag_code == CODE_64BIT)
-          use_rela_relocations = 1;
-         return flag_code == CODE_64BIT ? "elf64-x86-64" : "elf32-i386";
+       if (flag_code == CODE_64BIT)
+         use_rela_relocations = 1;
+       return flag_code == CODE_64BIT ? "elf64-x86-64" : "elf32-i386";
       }
 #endif
     default:
@@ -4584,9 +4740,18 @@ i386_validate_fix (fixp)
   if (fixp->fx_subsy && fixp->fx_subsy == GOT_symbol)
     {
       /* GOTOFF relocation are nonsense in 64bit mode.  */
-      if (flag_code == CODE_64BIT)
-       abort();
-      fixp->fx_r_type = BFD_RELOC_386_GOTOFF;
+      if (fixp->fx_r_type == BFD_RELOC_32_PCREL)
+       {
+         if (flag_code != CODE_64BIT)
+           abort ();
+         fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL;
+       }
+      else
+       {
+         if (flag_code == CODE_64BIT)
+           abort ();
+         fixp->fx_r_type = BFD_RELOC_386_GOTOFF;
+       }
       fixp->fx_subsy = 0;
     }
 }
@@ -4620,8 +4785,9 @@ tc_gen_reloc (section, fixp)
          switch (fixp->fx_size)
            {
            default:
-             as_bad (_("can not do %d byte pc-relative relocation"),
-                     fixp->fx_size);
+             as_bad_where (fixp->fx_file, fixp->fx_line,
+                           _("can not do %d byte pc-relative relocation"),
+                           fixp->fx_size);
              code = BFD_RELOC_32_PCREL;
              break;
            case 1: code = BFD_RELOC_8_PCREL;  break;
@@ -4634,7 +4800,9 @@ tc_gen_reloc (section, fixp)
          switch (fixp->fx_size)
            {
            default:
-             as_bad (_("can not do %d byte relocation"), fixp->fx_size);
+             as_bad_where (fixp->fx_file, fixp->fx_line,
+                           _("can not do %d byte relocation"),
+                           fixp->fx_size);
              code = BFD_RELOC_32;
              break;
            case 1: code = BFD_RELOC_8;  break;
@@ -4652,7 +4820,7 @@ tc_gen_reloc (section, fixp)
     {
       /* We don't support GOTPC on 64bit targets.  */
       if (flag_code == CODE_64BIT)
-       abort();
+       abort ();
       code = BFD_RELOC_386_GOTPC;
     }
 
@@ -4677,20 +4845,10 @@ tc_gen_reloc (section, fixp)
   else
     {
       rel->addend = fixp->fx_offset;
-#ifdef OBJ_ELF
-      /* Ohhh, this is ugly.  The problem is that if this is a local global
-         symbol, the relocation will entirely be performed at link time, not
-         at assembly time.  bfd_perform_reloc doesn't know about this sort
-         of thing, and as a result we need to fake it out here.  */
-      if ((S_IS_EXTERN (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy))
-         && !S_IS_COMMON(fixp->fx_addsy))
-       rel->addend -= symbol_get_bfdsym (fixp->fx_addsy)->value;
-#endif
       if (fixp->fx_pcrel)
        rel->addend -= fixp->fx_size;
     }
 
-
   rel->howto = bfd_reloc_type_lookup (stdoutput, code);
   if (rel->howto == NULL)
     {
@@ -4919,7 +5077,6 @@ struct intel_token
 
 static struct intel_token cur_token, prev_token;
 
-
 /* Token codes for the intel parser. Since T_SHORT is already used
    by COFF, undefine it first to prevent a warning.  */
 #define T_NIL          -1
@@ -4965,7 +5122,7 @@ i386_intel_operand (operand_string, got_a_float)
   cur_token.str = prev_token.str = NULL;
 
   /* Initialize parser structure.  */
-  p = intel_parser.op_string = (char *)malloc (strlen (operand_string) + 1);
+  p = intel_parser.op_string = (char *) malloc (strlen (operand_string) + 1);
   if (p == NULL)
     abort ();
   strcpy (intel_parser.op_string, operand_string);
@@ -4973,7 +5130,7 @@ i386_intel_operand (operand_string, got_a_float)
   intel_parser.op_modifier = -1;
   intel_parser.is_mem = 0;
   intel_parser.reg = NULL;
-  intel_parser.disp = (char *)malloc (strlen (operand_string) + 1);
+  intel_parser.disp = (char *) malloc (strlen (operand_string) + 1);
   if (intel_parser.disp == NULL)
     abort ();
   intel_parser.disp[0] = '\0';
@@ -5250,10 +5407,10 @@ intel_e11 ()
       strcat (intel_parser.disp, "(");
 
       if (intel_expr () && intel_match_token (')'))
-         {
-           strcat (intel_parser.disp, ")");
-           return 1;
-         }
+       {
+         strcat (intel_parser.disp, ")");
+         return 1;
+       }
       else
        return 0;
     }
@@ -5460,7 +5617,7 @@ intel_e11 ()
 
   /* e11  constant  */
   else if (cur_token.code == T_CONST
-           || cur_token.code == '-'
+          || cur_token.code == '-'
           || cur_token.code == '+')
     {
       char *save_str;
@@ -5478,7 +5635,7 @@ intel_e11 ()
            }
        }
 
-      save_str = (char *)malloc (strlen (cur_token.str) + 1);
+      save_str = (char *) malloc (strlen (cur_token.str) + 1);
       if (save_str == NULL)
        abort ();
       strcpy (save_str, cur_token.str);
@@ -5550,7 +5707,7 @@ intel_e11 ()
    token from the operand string.  */
 static int
 intel_match_token (code)
-    int code;
+     int code;
 {
   if (cur_token.code == code)
     {
@@ -5596,7 +5753,7 @@ intel_get_token ()
 
   /* The new token cannot be larger than the remainder of the operand
      string.  */
-  new_token.str = (char *)malloc (strlen (intel_parser.op_string) + 1);
+  new_token.str = (char *) malloc (strlen (intel_parser.op_string) + 1);
   if (new_token.str == NULL)
     abort ();
   new_token.str[0] = '\0';
This page took 0.047737 seconds and 4 git commands to generate.