/* tc-i386.c -- Assemble code for the Intel 80386
- Copyright (C) 1989-2015 Free Software Foundation, Inc.
+ Copyright (C) 1989-2016 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
#include "elf/x86-64.h"
#include "opcodes/i386-init.h"
-#ifdef TE_LINUX
-/* Default to compress debug sections for Linux. */
-enum compressed_debug_section_type flag_compress_debug
- = COMPRESS_DEBUG_GABI_ZLIB;
-#endif
-
#ifndef REGISTER_WARNINGS
#define REGISTER_WARNINGS 1
#endif
specified explicitly. */
static int omit_lock_prefix = 0;
+/* 1 if the assembler should encode lfence, mfence, and sfence as
+ "lock addl $0, (%{re}sp)". */
+static int avoid_fence = 0;
+
+/* 1 if the assembler should generate relax relocations. */
+
+static int generate_relax_relocations
+ = DEFAULT_GENERATE_X86_RELAX_RELOCATIONS;
+
static enum check_kind
{
check_none = 0,
CPU_CLZERO_FLAGS, 0, 0 },
{ STRING_COMMA_LEN (".mwaitx"), PROCESSOR_UNKNOWN,
CPU_MWAITX_FLAGS, 0, 0 },
+ { STRING_COMMA_LEN (".ospke"), PROCESSOR_UNKNOWN,
+ CPU_OSPKE_FLAGS, 0, 0 },
};
#ifdef I386COFF
/* Various efficient no-op patterns for aligning code labels.
Note: Don't try to assemble the instructions in the comments.
0L and 0w are not legal. */
- static const char f32_1[] =
+ static const unsigned char f32_1[] =
{0x90}; /* nop */
- static const char f32_2[] =
+ static const unsigned char f32_2[] =
{0x66,0x90}; /* xchg %ax,%ax */
- static const char f32_3[] =
+ static const unsigned char f32_3[] =
{0x8d,0x76,0x00}; /* leal 0(%esi),%esi */
- static const char f32_4[] =
+ static const unsigned char f32_4[] =
{0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */
- static const char f32_5[] =
+ static const unsigned char f32_5[] =
{0x90, /* nop */
0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */
- static const char f32_6[] =
+ static const unsigned char f32_6[] =
{0x8d,0xb6,0x00,0x00,0x00,0x00}; /* leal 0L(%esi),%esi */
- static const char f32_7[] =
+ static const unsigned char f32_7[] =
{0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */
- static const char f32_8[] =
+ static const unsigned char f32_8[] =
{0x90, /* nop */
0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */
- static const char f32_9[] =
+ static const unsigned char f32_9[] =
{0x89,0xf6, /* movl %esi,%esi */
0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */
- static const char f32_10[] =
+ static const unsigned char f32_10[] =
{0x8d,0x76,0x00, /* leal 0(%esi),%esi */
0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */
- static const char f32_11[] =
+ static const unsigned char f32_11[] =
{0x8d,0x74,0x26,0x00, /* leal 0(%esi,1),%esi */
0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */
- static const char f32_12[] =
+ static const unsigned char f32_12[] =
{0x8d,0xb6,0x00,0x00,0x00,0x00, /* leal 0L(%esi),%esi */
0x8d,0xbf,0x00,0x00,0x00,0x00}; /* leal 0L(%edi),%edi */
- static const char f32_13[] =
+ static const unsigned char f32_13[] =
{0x8d,0xb6,0x00,0x00,0x00,0x00, /* leal 0L(%esi),%esi */
0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */
- static const char f32_14[] =
+ static const unsigned char f32_14[] =
{0x8d,0xb4,0x26,0x00,0x00,0x00,0x00, /* leal 0L(%esi,1),%esi */
0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */
- static const char f16_3[] =
+ static const unsigned char f16_3[] =
{0x8d,0x74,0x00}; /* lea 0(%esi),%esi */
- static const char f16_4[] =
+ static const unsigned char f16_4[] =
{0x8d,0xb4,0x00,0x00}; /* lea 0w(%si),%si */
- static const char f16_5[] =
+ static const unsigned char f16_5[] =
{0x90, /* nop */
0x8d,0xb4,0x00,0x00}; /* lea 0w(%si),%si */
- static const char f16_6[] =
+ static const unsigned char f16_6[] =
{0x89,0xf6, /* mov %si,%si */
0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */
- static const char f16_7[] =
+ static const unsigned char f16_7[] =
{0x8d,0x74,0x00, /* lea 0(%si),%si */
0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */
- static const char f16_8[] =
+ static const unsigned char f16_8[] =
{0x8d,0xb4,0x00,0x00, /* lea 0w(%si),%si */
0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */
- static const char jump_31[] =
+ static const unsigned char jump_31[] =
{0xeb,0x1d,0x90,0x90,0x90,0x90,0x90, /* jmp .+31; lotsa nops */
0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,
0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,
0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90};
- static const char *const f32_patt[] = {
+ static const unsigned char *const f32_patt[] = {
f32_1, f32_2, f32_3, f32_4, f32_5, f32_6, f32_7, f32_8,
f32_9, f32_10, f32_11, f32_12, f32_13, f32_14
};
- static const char *const f16_patt[] = {
+ static const unsigned char *const f16_patt[] = {
f32_1, f32_2, f16_3, f16_4, f16_5, f16_6, f16_7, f16_8
};
/* nopl (%[re]ax) */
- static const char alt_3[] =
+ static const unsigned char alt_3[] =
{0x0f,0x1f,0x00};
/* nopl 0(%[re]ax) */
- static const char alt_4[] =
+ static const unsigned char alt_4[] =
{0x0f,0x1f,0x40,0x00};
/* nopl 0(%[re]ax,%[re]ax,1) */
- static const char alt_5[] =
+ static const unsigned char alt_5[] =
{0x0f,0x1f,0x44,0x00,0x00};
/* nopw 0(%[re]ax,%[re]ax,1) */
- static const char alt_6[] =
+ static const unsigned char alt_6[] =
{0x66,0x0f,0x1f,0x44,0x00,0x00};
/* nopl 0L(%[re]ax) */
- static const char alt_7[] =
+ static const unsigned char alt_7[] =
{0x0f,0x1f,0x80,0x00,0x00,0x00,0x00};
/* nopl 0L(%[re]ax,%[re]ax,1) */
- static const char alt_8[] =
+ static const unsigned char alt_8[] =
{0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
/* nopw 0L(%[re]ax,%[re]ax,1) */
- static const char alt_9[] =
+ static const unsigned char alt_9[] =
{0x66,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
/* nopw %cs:0L(%[re]ax,%[re]ax,1) */
- static const char alt_10[] =
+ static const unsigned char alt_10[] =
{0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
- static const char *const alt_patt[] = {
+ static const unsigned char *const alt_patt[] = {
f32_1, f32_2, alt_3, alt_4, alt_5, alt_6, alt_7, alt_8,
alt_9, alt_10
};
}
else
{
- const char *const *patt = NULL;
+ const unsigned char *const *patt = NULL;
if (fragP->tc_frag_data.isa == PROCESSOR_UNKNOWN)
{
if (r->reg_flags & RegRex)
nr += 8;
+ if (r->reg_flags & RegVRex)
+ nr += 16;
+
return nr;
}
|| 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_GOT32X
|| 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_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_GOTPCRELX
+ || fixP->fx_r_type == BFD_RELOC_X86_64_REX_GOTPCRELX
|| 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
i.op[op].imms->X_add_number =
(((i.op[op].imms->X_add_number & 0xffff) ^ 0x8000) - 0x8000);
}
+#ifdef BFD64
+ /* Store 32-bit immediate in 64-bit for 64-bit BFD. */
if ((i.types[op].bitfield.imm32)
&& ((i.op[op].imms->X_add_number & ~(((offsetT) 2 << 31) - 1))
== 0))
^ ((offsetT) 1 << 31))
- ((offsetT) 1 << 31));
}
+#endif
i.types[op]
= operand_type_or (i.types[op],
smallest_imm_type (i.op[op].imms->X_add_number));
op_disp = (((op_disp & 0xffff) ^ 0x8000) - 0x8000);
i.types[op].bitfield.disp64 = 0;
}
+#ifdef BFD64
+ /* Optimize 64-bit displacement to 32-bit for 64-bit BFD. */
if (i.types[op].bitfield.disp32
&& (op_disp & ~(((offsetT) 2 << 31) - 1)) == 0)
{
op_disp = (op_disp ^ ((offsetT) 1 << 31)) - ((addressT) 1 << 31);
i.types[op].bitfield.disp64 = 0;
}
+#endif
if (!op_disp && i.types[op].bitfield.baseindex)
{
i.types[op].bitfield.disp8 = 0;
}
}
+ /* Force 0x8b encoding for "mov foo@GOT, %eax". */
+ if (i.reloc[0] == BFD_RELOC_386_GOT32 && t->base_opcode == 0xa0)
+ continue;
+
/* We check register size if needed. */
check_register = t->opcode_modifier.checkregsize;
overlap0 = operand_type_and (i.types[0], operand_types[0]);
unsigned int j;
unsigned int prefix;
+ if (avoid_fence
+ && i.tm.base_opcode == 0xfae
+ && i.operands == 1
+ && i.imm_operands == 1
+ && (i.op[0].imms->X_add_number == 0xe8
+ || i.op[0].imms->X_add_number == 0xf0
+ || i.op[0].imms->X_add_number == 0xf8))
+ {
+ /* Encode lfence, mfence, and sfence as
+ f0 83 04 24 00 lock addl $0x0, (%{re}sp). */
+ offsetT val = 0x240483f0ULL;
+ p = frag_more (5);
+ md_number_to_chars (p, val, 5);
+ return;
+ }
+
/* Some processors fail on LOCK prefix. This options makes
assembler ignore LOCK prefix and serves as a workaround. */
if (omit_lock_prefix)
int size = disp_size (n);
int sign = i.types[n].bitfield.disp32s;
int pcrel = (i.flags[n] & Operand_PCrel) != 0;
+ fixS *fixP;
/* We can't have 8 bit displacement here. */
gas_assert (!i.types[n].bitfield.disp8);
insn, and that is taken care of in other code. */
reloc_type = BFD_RELOC_X86_64_GOTPC32;
}
- fix_new_exp (frag_now, p - frag_now->fr_literal, size,
- i.op[n].disps, pcrel, reloc_type);
+ fixP = fix_new_exp (frag_now, p - frag_now->fr_literal,
+ size, i.op[n].disps, pcrel,
+ reloc_type);
+ /* Check for "call/jmp *mem", "mov mem, %reg",
+ "test %reg, mem" and "binop mem, %reg" where binop
+ is one of adc, add, and, cmp, or, sbb, sub, xor
+ instructions. Always generate R_386_GOT32X for
+ "sym*GOT" operand in 32-bit mode. */
+ if ((generate_relax_relocations
+ || (!object_64bit
+ && i.rm.mode == 0
+ && i.rm.regmem == 5))
+ && (i.rm.mode == 2
+ || (i.rm.mode == 0 && i.rm.regmem == 5))
+ && ((i.operands == 1
+ && i.tm.base_opcode == 0xff
+ && (i.rm.reg == 2 || i.rm.reg == 4))
+ || (i.operands == 2
+ && (i.tm.base_opcode == 0x8b
+ || i.tm.base_opcode == 0x85
+ || (i.tm.base_opcode & 0xc7) == 0x03))))
+ {
+ if (object_64bit)
+ {
+ fixP->fx_tcbit = i.rex != 0;
+ if (i.base_reg
+ && (i.base_reg->reg_num == RegRip
+ || i.base_reg->reg_num == RegEip))
+ fixP->fx_tcbit2 = 1;
+ }
+ else
+ fixP->fx_tcbit2 = 1;
+ }
}
}
}
#define OPTION_MEVEXLIG (OPTION_MD_BASE + 16)
#define OPTION_MEVEXWIG (OPTION_MD_BASE + 17)
#define OPTION_MBIG_OBJ (OPTION_MD_BASE + 18)
-#define OPTION_OMIT_LOCK_PREFIX (OPTION_MD_BASE + 19)
+#define OPTION_MOMIT_LOCK_PREFIX (OPTION_MD_BASE + 19)
#define OPTION_MEVEXRCIG (OPTION_MD_BASE + 20)
#define OPTION_MSHARED (OPTION_MD_BASE + 21)
#define OPTION_MAMD64 (OPTION_MD_BASE + 22)
#define OPTION_MINTEL64 (OPTION_MD_BASE + 23)
+#define OPTION_MFENCE_AS_LOCK_ADD (OPTION_MD_BASE + 24)
+#define OPTION_MRELAX_RELOCATIONS (OPTION_MD_BASE + 25)
struct option md_longopts[] =
{
# if defined (TE_PE) || defined (TE_PEP)
{"mbig-obj", no_argument, NULL, OPTION_MBIG_OBJ},
#endif
- {"momit-lock-prefix", required_argument, NULL, OPTION_OMIT_LOCK_PREFIX},
+ {"momit-lock-prefix", required_argument, NULL, OPTION_MOMIT_LOCK_PREFIX},
+ {"mfence-as-lock-add", required_argument, NULL, OPTION_MFENCE_AS_LOCK_ADD},
+ {"mrelax-relocations", required_argument, NULL, OPTION_MRELAX_RELOCATIONS},
{"mevexrcig", required_argument, NULL, OPTION_MEVEXRCIG},
{"mamd64", no_argument, NULL, OPTION_MAMD64},
{"mintel64", no_argument, NULL, OPTION_MINTEL64},
size_t md_longopts_size = sizeof (md_longopts);
int
-md_parse_option (int c, char *arg)
+md_parse_option (int c, const char *arg)
{
unsigned int j;
char *arch, *next;
break;
#endif
- case OPTION_OMIT_LOCK_PREFIX:
+ case OPTION_MOMIT_LOCK_PREFIX:
if (strcasecmp (arg, "yes") == 0)
omit_lock_prefix = 1;
else if (strcasecmp (arg, "no") == 0)
as_fatal (_("invalid -momit-lock-prefix= option: `%s'"), arg);
break;
+ case OPTION_MFENCE_AS_LOCK_ADD:
+ if (strcasecmp (arg, "yes") == 0)
+ avoid_fence = 1;
+ else if (strcasecmp (arg, "no") == 0)
+ avoid_fence = 0;
+ else
+ as_fatal (_("invalid -mfence-as-lock-add= option: `%s'"), arg);
+ break;
+
+ case OPTION_MRELAX_RELOCATIONS:
+ if (strcasecmp (arg, "yes") == 0)
+ generate_relax_relocations = 1;
+ else if (strcasecmp (arg, "no") == 0)
+ generate_relax_relocations = 0;
+ else
+ as_fatal (_("invalid -mrelax-relocations= option: `%s'"), arg);
+ break;
+
case OPTION_MAMD64:
cpu_arch_flags.bitfield.cpuamd64 = 1;
cpu_arch_flags.bitfield.cpuintel64 = 0;
-momit-lock-prefix=[no|yes]\n\
strip all lock prefixes\n"));
fprintf (stream, _("\
+ -mfence-as-lock-add=[no|yes]\n\
+ encode lfence, mfence and sfence as\n\
+ lock addl $0x0, (%%{re}sp)\n"));
+ fprintf (stream, _("\
+ -mrelax-relocations=[no|yes]\n\
+ generate relax relocations\n"));
+ fprintf (stream, _("\
-mamd64 accept only AMD64 ISA\n"));
fprintf (stream, _("\
-mintel64 accept only Intel64 ISA\n"));
int align;
align = bfd_get_section_alignment (stdoutput, segment);
- size = ((size + (1 << align) - 1) & ((valueT) -1 << align));
+ size = ((size + (1 << align) - 1) & (-((valueT) 1 << align)));
}
#endif
void
i386_validate_fix (fixS *fixp)
{
- if (fixp->fx_subsy && fixp->fx_subsy == GOT_symbol)
+ if (fixp->fx_subsy)
{
- if (fixp->fx_r_type == BFD_RELOC_32_PCREL)
- {
- if (!object_64bit)
- abort ();
- fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL;
- }
- else
+ if (fixp->fx_subsy == GOT_symbol)
{
- if (!object_64bit)
- fixp->fx_r_type = BFD_RELOC_386_GOTOFF;
+ if (fixp->fx_r_type == BFD_RELOC_32_PCREL)
+ {
+ if (!object_64bit)
+ abort ();
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+ if (fixp->fx_tcbit2)
+ fixp->fx_r_type = (fixp->fx_tcbit
+ ? BFD_RELOC_X86_64_REX_GOTPCRELX
+ : BFD_RELOC_X86_64_GOTPCRELX);
+ else
+#endif
+ fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL;
+ }
else
- fixp->fx_r_type = BFD_RELOC_X86_64_GOTOFF64;
+ {
+ if (!object_64bit)
+ fixp->fx_r_type = BFD_RELOC_386_GOTOFF;
+ else
+ fixp->fx_r_type = BFD_RELOC_X86_64_GOTOFF64;
+ }
+ fixp->fx_subsy = 0;
}
- fixp->fx_subsy = 0;
}
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+ else if (!object_64bit)
+ {
+ if (fixp->fx_r_type == BFD_RELOC_386_GOT32
+ && fixp->fx_tcbit2)
+ fixp->fx_r_type = BFD_RELOC_386_GOT32X;
+ }
+#endif
}
arelent *
case BFD_RELOC_X86_64_PLT32:
case BFD_RELOC_X86_64_GOT32:
case BFD_RELOC_X86_64_GOTPCREL:
+ case BFD_RELOC_X86_64_GOTPCRELX:
+ case BFD_RELOC_X86_64_REX_GOTPCRELX:
case BFD_RELOC_386_PLT32:
case BFD_RELOC_386_GOT32:
+ case BFD_RELOC_386_GOT32X:
case BFD_RELOC_386_GOTOFF:
case BFD_RELOC_386_GOTPC:
case BFD_RELOC_386_TLS_GD:
case BFD_RELOC_X86_64_PLT32:
case BFD_RELOC_X86_64_GOT32:
case BFD_RELOC_X86_64_GOTPCREL:
+ case BFD_RELOC_X86_64_GOTPCRELX:
+ case BFD_RELOC_X86_64_REX_GOTPCRELX:
case BFD_RELOC_X86_64_TLSGD:
case BFD_RELOC_X86_64_TLSLD:
case BFD_RELOC_X86_64_GOTTPOFF: