Line 1... |
Line 1... |
/* tc-i386.c -- Assemble code for the Intel 80386
|
/* tc-i386.c -- Assemble code for the Intel 80386
|
Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
|
Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
|
2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
|
|
2012
|
Free Software Foundation, Inc.
|
Free Software Foundation, Inc.
|
|
|
This file is part of GAS, the GNU Assembler.
|
This file is part of GAS, the GNU Assembler.
|
|
|
GAS is free software; you can redistribute it and/or modify
|
GAS is free software; you can redistribute it and/or modify
|
Line 57... |
Line 58... |
|
|
/* Prefixes will be emitted in the order defined below.
|
/* Prefixes will be emitted in the order defined below.
|
WAIT_PREFIX must be the first prefix since FWAIT is really is an
|
WAIT_PREFIX must be the first prefix since FWAIT is really is an
|
instruction, and so must come before any prefixes.
|
instruction, and so must come before any prefixes.
|
The preferred prefix order is SEG_PREFIX, ADDR_PREFIX, DATA_PREFIX,
|
The preferred prefix order is SEG_PREFIX, ADDR_PREFIX, DATA_PREFIX,
|
REP_PREFIX, LOCK_PREFIX. */
|
REP_PREFIX/HLE_PREFIX, LOCK_PREFIX. */
|
#define WAIT_PREFIX 0
|
#define WAIT_PREFIX 0
|
#define SEG_PREFIX 1
|
#define SEG_PREFIX 1
|
#define ADDR_PREFIX 2
|
#define ADDR_PREFIX 2
|
#define DATA_PREFIX 3
|
#define DATA_PREFIX 3
|
#define REP_PREFIX 4
|
#define REP_PREFIX 4
|
|
#define HLE_PREFIX REP_PREFIX
|
#define LOCK_PREFIX 5
|
#define LOCK_PREFIX 5
|
#define REX_PREFIX 6 /* must come last. */
|
#define REX_PREFIX 6 /* must come last. */
|
#define MAX_PREFIXES 7 /* max prefixes per opcode */
|
#define MAX_PREFIXES 7 /* max prefixes per opcode */
|
|
|
/* we define the syntax here (modulo base,index,scale syntax) */
|
/* we define the syntax here (modulo base,index,scale syntax) */
|
Line 277... |
Line 279... |
vex_prefix vex;
|
vex_prefix vex;
|
|
|
/* Swap operand in encoding. */
|
/* Swap operand in encoding. */
|
unsigned int swap_operand;
|
unsigned int swap_operand;
|
|
|
/* Force 32bit displacement in encoding. */
|
/* Prefer 8bit or 32bit displacement in encoding. */
|
unsigned int disp32_encoding;
|
enum
|
|
{
|
|
disp_encoding_default = 0,
|
|
disp_encoding_8bit,
|
|
disp_encoding_32bit
|
|
} disp_encoding;
|
|
|
|
/* Have HLE prefix. */
|
|
unsigned int have_hle;
|
|
|
/* Error message. */
|
/* Error message. */
|
enum i386_error error;
|
enum i386_error error;
|
};
|
};
|
|
|
Line 301... |
Line 311... |
|
|
#if (defined (TE_I386AIX) \
|
#if (defined (TE_I386AIX) \
|
|| ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) \
|
|| ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) \
|
&& !defined (TE_GNU) \
|
&& !defined (TE_GNU) \
|
&& !defined (TE_LINUX) \
|
&& !defined (TE_LINUX) \
|
|
&& !defined (TE_NACL) \
|
&& !defined (TE_NETWARE) \
|
&& !defined (TE_NETWARE) \
|
&& !defined (TE_FreeBSD) \
|
&& !defined (TE_FreeBSD) \
|
&& !defined (TE_DragonFly) \
|
&& !defined (TE_DragonFly) \
|
&& !defined (TE_NetBSD)))
|
&& !defined (TE_NetBSD)))
|
/* This array holds the chars that always start a comment. If the
|
/* This array holds the chars that always start a comment. If the
|
Line 686... |
Line 697... |
CPU_AVX2_FLAGS, 0, 0 },
|
CPU_AVX2_FLAGS, 0, 0 },
|
{ STRING_COMMA_LEN (".noavx"), PROCESSOR_UNKNOWN,
|
{ STRING_COMMA_LEN (".noavx"), PROCESSOR_UNKNOWN,
|
CPU_ANY_AVX_FLAGS, 0, 1 },
|
CPU_ANY_AVX_FLAGS, 0, 1 },
|
{ STRING_COMMA_LEN (".vmx"), PROCESSOR_UNKNOWN,
|
{ STRING_COMMA_LEN (".vmx"), PROCESSOR_UNKNOWN,
|
CPU_VMX_FLAGS, 0, 0 },
|
CPU_VMX_FLAGS, 0, 0 },
|
|
{ STRING_COMMA_LEN (".vmfunc"), PROCESSOR_UNKNOWN,
|
|
CPU_VMFUNC_FLAGS, 0, 0 },
|
{ STRING_COMMA_LEN (".smx"), PROCESSOR_UNKNOWN,
|
{ STRING_COMMA_LEN (".smx"), PROCESSOR_UNKNOWN,
|
CPU_SMX_FLAGS, 0, 0 },
|
CPU_SMX_FLAGS, 0, 0 },
|
{ STRING_COMMA_LEN (".xsave"), PROCESSOR_UNKNOWN,
|
{ STRING_COMMA_LEN (".xsave"), PROCESSOR_UNKNOWN,
|
CPU_XSAVE_FLAGS, 0, 0 },
|
CPU_XSAVE_FLAGS, 0, 0 },
|
{ STRING_COMMA_LEN (".xsaveopt"), PROCESSOR_UNKNOWN,
|
{ STRING_COMMA_LEN (".xsaveopt"), PROCESSOR_UNKNOWN,
|
Line 720... |
Line 733... |
CPU_MOVBE_FLAGS, 0, 0 },
|
CPU_MOVBE_FLAGS, 0, 0 },
|
{ STRING_COMMA_LEN (".ept"), PROCESSOR_UNKNOWN,
|
{ STRING_COMMA_LEN (".ept"), PROCESSOR_UNKNOWN,
|
CPU_EPT_FLAGS, 0, 0 },
|
CPU_EPT_FLAGS, 0, 0 },
|
{ STRING_COMMA_LEN (".lzcnt"), PROCESSOR_UNKNOWN,
|
{ STRING_COMMA_LEN (".lzcnt"), PROCESSOR_UNKNOWN,
|
CPU_LZCNT_FLAGS, 0, 0 },
|
CPU_LZCNT_FLAGS, 0, 0 },
|
|
{ STRING_COMMA_LEN (".hle"), PROCESSOR_UNKNOWN,
|
|
CPU_HLE_FLAGS, 0, 0 },
|
|
{ STRING_COMMA_LEN (".rtm"), PROCESSOR_UNKNOWN,
|
|
CPU_RTM_FLAGS, 0, 0 },
|
{ STRING_COMMA_LEN (".invpcid"), PROCESSOR_UNKNOWN,
|
{ STRING_COMMA_LEN (".invpcid"), PROCESSOR_UNKNOWN,
|
CPU_INVPCID_FLAGS, 0, 0 },
|
CPU_INVPCID_FLAGS, 0, 0 },
|
{ STRING_COMMA_LEN (".clflush"), PROCESSOR_UNKNOWN,
|
{ STRING_COMMA_LEN (".clflush"), PROCESSOR_UNKNOWN,
|
CPU_CLFLUSH_FLAGS, 0, 0 },
|
CPU_CLFLUSH_FLAGS, 0, 0 },
|
{ STRING_COMMA_LEN (".nop"), PROCESSOR_UNKNOWN,
|
{ STRING_COMMA_LEN (".nop"), PROCESSOR_UNKNOWN,
|
Line 2988... |
Line 3005... |
exp->X_op = O_constant;
|
exp->X_op = O_constant;
|
exp->X_add_number = i.tm.extension_opcode;
|
exp->X_add_number = i.tm.extension_opcode;
|
i.tm.extension_opcode = None;
|
i.tm.extension_opcode = None;
|
}
|
}
|
|
|
|
|
|
static int
|
|
check_hle (void)
|
|
{
|
|
switch (i.tm.opcode_modifier.hleprefixok)
|
|
{
|
|
default:
|
|
abort ();
|
|
case HLEPrefixNone:
|
|
if (i.prefix[HLE_PREFIX] == XACQUIRE_PREFIX_OPCODE)
|
|
as_bad (_("invalid instruction `%s' after `xacquire'"),
|
|
i.tm.name);
|
|
else
|
|
as_bad (_("invalid instruction `%s' after `xrelease'"),
|
|
i.tm.name);
|
|
return 0;
|
|
case HLEPrefixLock:
|
|
if (i.prefix[LOCK_PREFIX])
|
|
return 1;
|
|
if (i.prefix[HLE_PREFIX] == XACQUIRE_PREFIX_OPCODE)
|
|
as_bad (_("missing `lock' with `xacquire'"));
|
|
else
|
|
as_bad (_("missing `lock' with `xrelease'"));
|
|
return 0;
|
|
case HLEPrefixAny:
|
|
return 1;
|
|
case HLEPrefixRelease:
|
|
if (i.prefix[HLE_PREFIX] != XRELEASE_PREFIX_OPCODE)
|
|
{
|
|
as_bad (_("instruction `%s' after `xacquire' not allowed"),
|
|
i.tm.name);
|
|
return 0;
|
|
}
|
|
if (i.mem_operands == 0
|
|
|| !operand_type_check (i.types[i.operands - 1], anymem))
|
|
{
|
|
as_bad (_("memory destination needed for instruction `%s'"
|
|
" after `xrelease'"), i.tm.name);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
|
/* This is the guts of the machine-dependent assembler. LINE points to a
|
/* This is the guts of the machine-dependent assembler. LINE points to a
|
machine dependent instruction. This function is supposed to emit
|
machine dependent instruction. This function is supposed to emit
|
the frags/bytes it assembles to. */
|
the frags/bytes it assembles to. */
|
|
|
void
|
void
|
Line 3048... |
Line 3109... |
optimize_imm ();
|
optimize_imm ();
|
|
|
/* Don't optimize displacement for movabs since it only takes 64bit
|
/* Don't optimize displacement for movabs since it only takes 64bit
|
displacement. */
|
displacement. */
|
if (i.disp_operands
|
if (i.disp_operands
|
&& !i.disp32_encoding
|
&& i.disp_encoding != disp_encoding_32bit
|
&& (flag_code != CODE_64BIT
|
&& (flag_code != CODE_64BIT
|
|| strcmp (mnemonic, "movabs") != 0))
|
|| strcmp (mnemonic, "movabs") != 0))
|
optimize_disp ();
|
optimize_disp ();
|
|
|
/* Next, we find a template that matches the given insn,
|
/* Next, we find a template that matches the given insn,
|
Line 3106... |
Line 3167... |
{
|
{
|
as_bad (_("expecting lockable instruction after `lock'"));
|
as_bad (_("expecting lockable instruction after `lock'"));
|
return;
|
return;
|
}
|
}
|
|
|
|
/* Check if HLE prefix is OK. */
|
|
if (i.have_hle && !check_hle ())
|
|
return;
|
|
|
/* Check string instruction segment overrides. */
|
/* Check string instruction segment overrides. */
|
if (i.tm.opcode_modifier.isstring && i.mem_operands != 0)
|
if (i.tm.opcode_modifier.isstring && i.mem_operands != 0)
|
{
|
{
|
if (!check_string ())
|
if (!check_string ())
|
return;
|
return;
|
Line 3309... |
Line 3374... |
switch (add_prefix (current_templates->start->base_opcode))
|
switch (add_prefix (current_templates->start->base_opcode))
|
{
|
{
|
case PREFIX_EXIST:
|
case PREFIX_EXIST:
|
return NULL;
|
return NULL;
|
case PREFIX_REP:
|
case PREFIX_REP:
|
|
if (current_templates->start->cpu_flags.bitfield.cpuhle)
|
|
i.have_hle = 1;
|
|
else
|
expecting_string_instruction = current_templates->start->name;
|
expecting_string_instruction = current_templates->start->name;
|
break;
|
break;
|
default:
|
default:
|
break;
|
break;
|
}
|
}
|
Line 3327... |
Line 3395... |
{
|
{
|
/* Check if we should swap operand or force 32bit displacement in
|
/* Check if we should swap operand or force 32bit displacement in
|
encoding. */
|
encoding. */
|
if (mnem_p - 2 == dot_p && dot_p[1] == 's')
|
if (mnem_p - 2 == dot_p && dot_p[1] == 's')
|
i.swap_operand = 1;
|
i.swap_operand = 1;
|
|
else if (mnem_p - 3 == dot_p
|
|
&& dot_p[1] == 'd'
|
|
&& dot_p[2] == '8')
|
|
i.disp_encoding = disp_encoding_8bit;
|
else if (mnem_p - 4 == dot_p
|
else if (mnem_p - 4 == dot_p
|
&& dot_p[1] == 'd'
|
&& dot_p[1] == 'd'
|
&& dot_p[2] == '3'
|
&& dot_p[2] == '3'
|
&& dot_p[3] == '2')
|
&& dot_p[3] == '2')
|
i.disp32_encoding = 1;
|
i.disp_encoding = disp_encoding_32bit;
|
else
|
else
|
goto check_suffix;
|
goto check_suffix;
|
mnem_p = dot_p;
|
mnem_p = dot_p;
|
*dot_p = '\0';
|
*dot_p = '\0';
|
current_templates = (const templates *) hash_find (op_hash, mnemonic);
|
current_templates = (const templates *) hash_find (op_hash, mnemonic);
|
Line 5693... |
Line 5765... |
if (i.disp_operands
|
if (i.disp_operands
|
&& (i.reloc[op] == BFD_RELOC_386_TLS_DESC_CALL
|
&& (i.reloc[op] == BFD_RELOC_386_TLS_DESC_CALL
|
|| i.reloc[op] == BFD_RELOC_X86_64_TLSDESC_CALL))
|
|| i.reloc[op] == BFD_RELOC_X86_64_TLSDESC_CALL))
|
i.rm.mode = 0;
|
i.rm.mode = 0;
|
else
|
else
|
|
{
|
|
if (!fake_zero_displacement
|
|
&& !i.disp_operands
|
|
&& i.disp_encoding)
|
|
{
|
|
fake_zero_displacement = 1;
|
|
if (i.disp_encoding == disp_encoding_8bit)
|
|
i.types[op].bitfield.disp8 = 1;
|
|
else
|
|
i.types[op].bitfield.disp32 = 1;
|
|
}
|
i.rm.mode = mode_from_disp_size (i.types[op]);
|
i.rm.mode = mode_from_disp_size (i.types[op]);
|
}
|
}
|
|
}
|
|
|
if (fake_zero_displacement)
|
if (fake_zero_displacement)
|
{
|
{
|
/* Fakes a zero displacement assuming that i.types[op]
|
/* Fakes a zero displacement assuming that i.types[op]
|
holds the correct displacement size. */
|
holds the correct displacement size. */
|
Line 5895... |
Line 5979... |
relax_substateT subtype;
|
relax_substateT subtype;
|
symbolS *sym;
|
symbolS *sym;
|
offsetT off;
|
offsetT off;
|
|
|
code16 = flag_code == CODE_16BIT ? CODE16 : 0;
|
code16 = flag_code == CODE_16BIT ? CODE16 : 0;
|
size = i.disp32_encoding ? BIG : SMALL;
|
size = i.disp_encoding == disp_encoding_32bit ? BIG : SMALL;
|
|
|
prefix = 0;
|
prefix = 0;
|
if (i.prefix[DATA_PREFIX] != 0)
|
if (i.prefix[DATA_PREFIX] != 0)
|
{
|
{
|
prefix = 1;
|
prefix = 1;
|
Line 6014... |
Line 6098... |
}
|
}
|
|
|
if (i.prefixes != 0 && !intel_syntax)
|
if (i.prefixes != 0 && !intel_syntax)
|
as_warn (_("skipping prefixes on this instruction"));
|
as_warn (_("skipping prefixes on this instruction"));
|
|
|
p = frag_more (1 + size);
|
p = frag_more (i.tm.opcode_length + size);
|
|
switch (i.tm.opcode_length)
|
|
{
|
|
case 2:
|
|
*p++ = i.tm.base_opcode >> 8;
|
|
case 1:
|
*p++ = i.tm.base_opcode;
|
*p++ = i.tm.base_opcode;
|
|
break;
|
|
default:
|
|
abort ();
|
|
}
|
|
|
fixP = fix_new_exp (frag_now, p - frag_now->fr_literal, size,
|
fixP = fix_new_exp (frag_now, p - frag_now->fr_literal, size,
|
i.op[0].disps, 1, reloc (size, 1, 1, i.reloc[0]));
|
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
|
/* All jumps handled here are signed, but don't use a signed limit
|
Line 6524... |
Line 6617... |
#endif
|
#endif
|
|
|
fix_new_exp (frag, off, len, exp, 0, r);
|
fix_new_exp (frag, off, len, exp, 0, r);
|
}
|
}
|
|
|
#if (!defined (OBJ_ELF) && !defined (OBJ_MAYBE_ELF)) || defined (LEX_AT)
|
#if !(defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || defined (OBJ_MACH_O)) \
|
|
|| defined (LEX_AT)
|
# define lex_got(reloc, adjust, types) NULL
|
# define lex_got(reloc, adjust, types) NULL
|
#else
|
#else
|
/* Parse operands of the form
|
/* Parse operands of the form
|
<symbol>@GOTOFF+<nnn>
|
<symbol>@GOTOFF+<nnn>
|
and similar .plt or .got references.
|
and similar .plt or .got references.
|
Line 6607... |
Line 6701... |
OPERAND_TYPE_IMM32_32S_DISP32 },
|
OPERAND_TYPE_IMM32_32S_DISP32 },
|
};
|
};
|
char *cp;
|
char *cp;
|
unsigned int j;
|
unsigned int j;
|
|
|
|
#if defined (OBJ_MAYBE_ELF)
|
if (!IS_ELF)
|
if (!IS_ELF)
|
return NULL;
|
return NULL;
|
|
#endif
|
|
|
for (cp = input_line_pointer; *cp != '@'; cp++)
|
for (cp = input_line_pointer; *cp != '@'; cp++)
|
if (is_end_of_line[(unsigned char) *cp] || *cp == ',')
|
if (is_end_of_line[(unsigned char) *cp] || *cp == ',')
|
return NULL;
|
return NULL;
|
|
|
Line 8281... |
Line 8377... |
|
|
struct option md_longopts[] =
|
struct option md_longopts[] =
|
{
|
{
|
{"32", no_argument, NULL, OPTION_32},
|
{"32", no_argument, NULL, OPTION_32},
|
#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \
|
#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \
|
|| defined (TE_PE) || defined (TE_PEP))
|
|| defined (TE_PE) || defined (TE_PEP) || defined (OBJ_MACH_O))
|
{"64", no_argument, NULL, OPTION_64},
|
{"64", no_argument, NULL, OPTION_64},
|
#endif
|
#endif
|
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
|
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
|
{"x32", no_argument, NULL, OPTION_X32},
|
{"x32", no_argument, NULL, OPTION_X32},
|
#endif
|
#endif
|
Line 8339... |
Line 8435... |
/* -s: On i386 Solaris, this tells the native assembler to use
|
/* -s: On i386 Solaris, this tells the native assembler to use
|
.stab instead of .stab.excl. We always use .stab anyhow. */
|
.stab instead of .stab.excl. We always use .stab anyhow. */
|
break;
|
break;
|
#endif
|
#endif
|
#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \
|
#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \
|
|| defined (TE_PE) || defined (TE_PEP))
|
|| defined (TE_PE) || defined (TE_PEP) || defined (OBJ_MACH_O))
|
case OPTION_64:
|
case OPTION_64:
|
{
|
{
|
const char **list, **l;
|
const char **list, **l;
|
|
|
list = bfd_target_list ();
|
list = bfd_target_list ();
|
for (l = list; *l != NULL; l++)
|
for (l = list; *l != NULL; l++)
|
if (CONST_STRNEQ (*l, "elf64-x86-64")
|
if (CONST_STRNEQ (*l, "elf64-x86-64")
|
|| strcmp (*l, "coff-x86-64") == 0
|
|| strcmp (*l, "coff-x86-64") == 0
|
|| strcmp (*l, "pe-x86-64") == 0
|
|| strcmp (*l, "pe-x86-64") == 0
|
|| strcmp (*l, "pei-x86-64") == 0)
|
|| strcmp (*l, "pei-x86-64") == 0
|
|
|| strcmp (*l, "mach-o-x86-64") == 0)
|
{
|
{
|
default_arch = "x86_64";
|
default_arch = "x86_64";
|
break;
|
break;
|
}
|
}
|
if (*l == NULL)
|
if (*l == NULL)
|
Line 8771... |
Line 8868... |
return format;
|
return format;
|
}
|
}
|
#endif
|
#endif
|
#if defined (OBJ_MACH_O)
|
#if defined (OBJ_MACH_O)
|
case bfd_target_mach_o_flavour:
|
case bfd_target_mach_o_flavour:
|
return flag_code == CODE_64BIT ? "mach-o-x86-64" : "mach-o-i386";
|
if (flag_code == CODE_64BIT)
|
|
{
|
|
use_rela_relocations = 1;
|
|
object_64bit = 1;
|
|
return "mach-o-x86-64";
|
|
}
|
|
else
|
|
return "mach-o-i386";
|
#endif
|
#endif
|
default:
|
default:
|
abort ();
|
abort ();
|
return NULL;
|
return NULL;
|
}
|
}
|