X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-i386.c;h=d00424a9f6f59446c143b408a8ddd661e368e3d5;hb=bc0844aee76db3dd663d7776e257a0fd15330d0e;hp=7d37b9c355008a1b473fa05e9359ee5f68047a29;hpb=321fd21e2f555303014e567a9f738b764f23e8cd;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 7d37b9c355..d00424a9f6 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -1,6 +1,6 @@ /* tc-i386.c -- Assemble code for the Intel 80386 Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -55,19 +55,103 @@ #endif #endif +/* Prefixes will be emitted in the order defined below. + WAIT_PREFIX must be the first prefix since FWAIT is really is an + instruction, and so must come before any prefixes. + The preferred prefix order is SEG_PREFIX, ADDR_PREFIX, DATA_PREFIX, + LOCKREP_PREFIX. */ +#define WAIT_PREFIX 0 +#define SEG_PREFIX 1 +#define ADDR_PREFIX 2 +#define DATA_PREFIX 3 +#define LOCKREP_PREFIX 4 +#define REX_PREFIX 5 /* must come last. */ +#define MAX_PREFIXES 6 /* max prefixes per opcode */ + +/* we define the syntax here (modulo base,index,scale syntax) */ +#define REGISTER_PREFIX '%' +#define IMMEDIATE_PREFIX '$' +#define ABSOLUTE_PREFIX '*' + +/* these are the instruction mnemonic suffixes in AT&T syntax or + memory operand size in Intel syntax. */ +#define WORD_MNEM_SUFFIX 'w' +#define BYTE_MNEM_SUFFIX 'b' +#define SHORT_MNEM_SUFFIX 's' +#define LONG_MNEM_SUFFIX 'l' +#define QWORD_MNEM_SUFFIX 'q' +#define XMMWORD_MNEM_SUFFIX 'x' +#define YMMWORD_MNEM_SUFFIX 'y' +/* Intel Syntax. Use a non-ascii letter since since it never appears + in instructions. */ +#define LONG_DOUBLE_MNEM_SUFFIX '\1' + +#define END_OF_INSN '\0' + +/* + 'templates' is for grouping together 'template' structures for opcodes + of the same name. This is only used for storing the insns in the grand + ole hash table of insns. + The templates themselves start at START and range up to (but not including) + END. + */ +typedef struct +{ + const template *start; + const template *end; +} +templates; + +/* 386 operand encoding bytes: see 386 book for details of this. */ +typedef struct +{ + unsigned int regmem; /* codes register or memory operand */ + unsigned int reg; /* codes register operand (or extended opcode) */ + unsigned int mode; /* how to interpret regmem & reg */ +} +modrm_byte; + +/* x86-64 extension prefix. */ +typedef int rex_byte; + +/* 386 opcode byte to code indirect addressing. */ +typedef struct +{ + unsigned base; + unsigned index; + unsigned scale; +} +sib_byte; + +/* x86 arch names, types and features */ +typedef struct +{ + const char *name; /* arch name */ + enum processor_type type; /* arch type */ + i386_cpu_flags flags; /* cpu feature flags */ +} +arch_entry; + static void set_code_flag (int); static void set_16bit_gcc_code_flag (int); static void set_intel_syntax (int); static void set_intel_mnemonic (int); static void set_allow_index_reg (int); +static void set_sse_check (int); static void set_cpu_arch (int); #ifdef TE_PE static void pe_directive_secrel (int); #endif static void signed_cons (int); static char *output_invalid (int c); +static int i386_finalize_immediate (segT, expressionS *, i386_operand_type, + const char *); +static int i386_finalize_displacement (segT, expressionS *, i386_operand_type, + const char *); static int i386_att_operand (char *); static int i386_intel_operand (char *, int); +static int i386_intel_simplify (expressionS *); +static int i386_intel_parse_name (const char *, expressionS *); static const reg_entry *parse_register (char *, char **); static char *parse_insn (char *, char *); static char *parse_operands (char *, const char *); @@ -75,7 +159,7 @@ static void swap_operands (void); static void swap_2_operands (int, int); static void optimize_imm (void); static void optimize_disp (void); -static int match_template (void); +static const template *match_template (void); static int check_string (void); static int process_suffix (void); static int check_byte_reg (void); @@ -83,7 +167,6 @@ static int check_long_reg (void); static int check_qword_reg (void); static int check_word_reg (void); static int finalize_imm (void); -static void process_drex (void); static int process_operands (void); static const seg_entry *build_modrm_byte (void); static void output_insn (void); @@ -98,6 +181,16 @@ static void handle_large_common (int small ATTRIBUTE_UNUSED); static const char *default_arch = DEFAULT_ARCH; +/* VEX prefix. */ +typedef struct +{ + /* VEX prefix is either 2 byte or 3 byte. */ + unsigned char bytes[3]; + unsigned int length; + /* Destination or source register specifier. */ + const reg_entry *register_specifier; +} vex_prefix; + /* 'md_assemble ()' gathers together information and puts it into a i386_insn. */ @@ -156,13 +249,14 @@ struct _i386_insn unsigned char prefix[MAX_PREFIXES]; /* RM and SIB are the modrm byte and the sib byte where the - addressing modes of this insn are encoded. DREX is the byte - added by the SSE5 instructions. */ - + addressing modes of this insn are encoded. */ modrm_byte rm; rex_byte rex; sib_byte sib; - drex_byte drex; + vex_prefix vex; + + /* Swap operand in encoding. */ + unsigned int swap_operand : 1; }; typedef struct _i386_insn i386_insn; @@ -258,7 +352,7 @@ static expressionS disp_expressions[MAX_MEMORY_OPERANDS]; static expressionS im_expressions[MAX_IMMEDIATE_OPERANDS]; /* Current operand we are working on. */ -static int this_operand; +static int this_operand = -1; /* We support four different modes. FLAG_CODE variable is used to distinguish these. */ @@ -291,12 +385,23 @@ static int intel_mnemonic = !SYSV386_COMPAT; /* 1 if support old (<= 2.8.1) versions of gcc. */ static int old_gcc = OLDGCC_COMPAT; +/* 1 if pseudo registers are permitted. */ +static int allow_pseudo_reg = 0; + /* 1 if register prefix % not required. */ static int allow_naked_reg = 0; /* 1 if pseudo index register, eiz/riz, is allowed . */ static int allow_index_reg = 0; +static enum + { + sse_check_none = 0, + sse_check_warning, + sse_check_error + } +sse_check; + /* Register prefix used for error message. */ static const char *register_prefix = "%"; @@ -313,7 +418,7 @@ static int quiet_warnings = 0; /* CPU name. */ static const char *cpu_arch_name = NULL; -static const char *cpu_sub_arch_name = NULL; +static char *cpu_sub_arch_name = NULL; /* CPU feature flags. */ static i386_cpu_flags cpu_arch_flags = CPU_UNKNOWN_FLAGS; @@ -322,21 +427,24 @@ static i386_cpu_flags cpu_arch_flags = CPU_UNKNOWN_FLAGS; static int cpu_arch_tune_set = 0; /* Cpu we are generating instructions for. */ -static enum processor_type cpu_arch_tune = PROCESSOR_UNKNOWN; +enum processor_type cpu_arch_tune = PROCESSOR_UNKNOWN; /* CPU feature flags of cpu we are generating instructions for. */ static i386_cpu_flags cpu_arch_tune_flags; /* CPU instruction set architecture used. */ -static enum processor_type cpu_arch_isa = PROCESSOR_UNKNOWN; +enum processor_type cpu_arch_isa = PROCESSOR_UNKNOWN; /* CPU feature flags of instruction set architecture used. */ -static i386_cpu_flags cpu_arch_isa_flags; +i386_cpu_flags cpu_arch_isa_flags; /* If set, conditional jumps are not automatically promoted to handle larger than a byte offset. */ static unsigned int no_cond_jump_promotion = 0; +/* Encode SSE instructions with VEX prefix. */ +static unsigned int sse2avx; + /* Pre-defined "_GLOBAL_OFFSET_TABLE_". */ static symbolS *GOT_symbol; @@ -427,94 +535,164 @@ const relax_typeS md_relax_table[] = static const arch_entry cpu_arch[] = { - {"generic32", PROCESSOR_GENERIC32, - CPU_GENERIC32_FLAGS }, - {"generic64", PROCESSOR_GENERIC64, - CPU_GENERIC64_FLAGS }, - {"i8086", PROCESSOR_UNKNOWN, - CPU_NONE_FLAGS }, - {"i186", PROCESSOR_UNKNOWN, - CPU_I186_FLAGS }, - {"i286", PROCESSOR_UNKNOWN, - CPU_I286_FLAGS }, - {"i386", PROCESSOR_I386, - CPU_I386_FLAGS }, - {"i486", PROCESSOR_I486, - CPU_I486_FLAGS }, - {"i586", PROCESSOR_PENTIUM, - CPU_I586_FLAGS }, - {"i686", PROCESSOR_PENTIUMPRO, - CPU_I686_FLAGS }, - {"pentium", PROCESSOR_PENTIUM, - CPU_I586_FLAGS }, - {"pentiumpro",PROCESSOR_PENTIUMPRO, - CPU_I686_FLAGS }, - {"pentiumii", PROCESSOR_PENTIUMPRO, - CPU_P2_FLAGS }, - {"pentiumiii",PROCESSOR_PENTIUMPRO, - CPU_P3_FLAGS }, - {"pentium4", PROCESSOR_PENTIUM4, - CPU_P4_FLAGS }, - {"prescott", PROCESSOR_NOCONA, - CPU_CORE_FLAGS }, - {"nocona", PROCESSOR_NOCONA, - CPU_NOCONA_FLAGS }, - {"yonah", PROCESSOR_CORE, - CPU_CORE_FLAGS }, - {"core", PROCESSOR_CORE, - CPU_CORE_FLAGS }, - {"merom", PROCESSOR_CORE2, - CPU_CORE2_FLAGS }, - {"core2", PROCESSOR_CORE2, - CPU_CORE2_FLAGS }, - {"k6", PROCESSOR_K6, - CPU_K6_FLAGS }, - {"k6_2", PROCESSOR_K6, - CPU_K6_2_FLAGS }, - {"athlon", PROCESSOR_ATHLON, - CPU_ATHLON_FLAGS }, - {"sledgehammer", PROCESSOR_K8, - CPU_K8_FLAGS }, - {"opteron", PROCESSOR_K8, - CPU_K8_FLAGS }, - {"k8", PROCESSOR_K8, - CPU_K8_FLAGS }, - {"amdfam10", PROCESSOR_AMDFAM10, - CPU_AMDFAM10_FLAGS }, - {".mmx", PROCESSOR_UNKNOWN, - CPU_MMX_FLAGS }, - {".sse", PROCESSOR_UNKNOWN, - CPU_SSE_FLAGS }, - {".sse2", PROCESSOR_UNKNOWN, - CPU_SSE2_FLAGS }, - {".sse3", PROCESSOR_UNKNOWN, - CPU_SSE3_FLAGS }, - {".ssse3", PROCESSOR_UNKNOWN, - CPU_SSSE3_FLAGS }, - {".sse4.1", PROCESSOR_UNKNOWN, - CPU_SSE4_1_FLAGS }, - {".sse4.2", PROCESSOR_UNKNOWN, - CPU_SSE4_2_FLAGS }, - {".sse4", PROCESSOR_UNKNOWN, - CPU_SSE4_2_FLAGS }, - {".3dnow", PROCESSOR_UNKNOWN, - CPU_3DNOW_FLAGS }, - {".3dnowa", PROCESSOR_UNKNOWN, - CPU_3DNOWA_FLAGS }, - {".padlock", PROCESSOR_UNKNOWN, - CPU_PADLOCK_FLAGS }, - {".pacifica", PROCESSOR_UNKNOWN, - CPU_SVME_FLAGS }, - {".svme", PROCESSOR_UNKNOWN, - CPU_SVME_FLAGS }, - {".sse4a", PROCESSOR_UNKNOWN, - CPU_SSE4A_FLAGS }, - {".abm", PROCESSOR_UNKNOWN, - CPU_ABM_FLAGS }, - {".sse5", PROCESSOR_UNKNOWN, - CPU_SSE5_FLAGS }, + { "generic32", PROCESSOR_GENERIC32, + CPU_GENERIC32_FLAGS }, + { "generic64", PROCESSOR_GENERIC64, + CPU_GENERIC64_FLAGS }, + { "i8086", PROCESSOR_UNKNOWN, + CPU_NONE_FLAGS }, + { "i186", PROCESSOR_UNKNOWN, + CPU_I186_FLAGS }, + { "i286", PROCESSOR_UNKNOWN, + CPU_I286_FLAGS }, + { "i386", PROCESSOR_I386, + CPU_I386_FLAGS }, + { "i486", PROCESSOR_I486, + CPU_I486_FLAGS }, + { "i586", PROCESSOR_PENTIUM, + CPU_I586_FLAGS }, + { "i686", PROCESSOR_PENTIUMPRO, + CPU_I686_FLAGS }, + { "pentium", PROCESSOR_PENTIUM, + CPU_I586_FLAGS }, + { "pentiumpro", PROCESSOR_PENTIUMPRO, + CPU_I686_FLAGS }, + { "pentiumii", PROCESSOR_PENTIUMPRO, + CPU_P2_FLAGS }, + { "pentiumiii",PROCESSOR_PENTIUMPRO, + CPU_P3_FLAGS }, + { "pentium4", PROCESSOR_PENTIUM4, + CPU_P4_FLAGS }, + { "prescott", PROCESSOR_NOCONA, + CPU_CORE_FLAGS }, + { "nocona", PROCESSOR_NOCONA, + CPU_NOCONA_FLAGS }, + { "yonah", PROCESSOR_CORE, + CPU_CORE_FLAGS }, + { "core", PROCESSOR_CORE, + CPU_CORE_FLAGS }, + { "merom", PROCESSOR_CORE2, + CPU_CORE2_FLAGS }, + { "core2", PROCESSOR_CORE2, + CPU_CORE2_FLAGS }, + { "corei7", PROCESSOR_COREI7, + CPU_COREI7_FLAGS }, + { "k6", PROCESSOR_K6, + CPU_K6_FLAGS }, + { "k6_2", PROCESSOR_K6, + CPU_K6_2_FLAGS }, + { "athlon", PROCESSOR_ATHLON, + CPU_ATHLON_FLAGS }, + { "sledgehammer", PROCESSOR_K8, + CPU_K8_FLAGS }, + { "opteron", PROCESSOR_K8, + CPU_K8_FLAGS }, + { "k8", PROCESSOR_K8, + CPU_K8_FLAGS }, + { "amdfam10", PROCESSOR_AMDFAM10, + CPU_AMDFAM10_FLAGS }, + { ".mmx", PROCESSOR_UNKNOWN, + CPU_MMX_FLAGS }, + { ".sse", PROCESSOR_UNKNOWN, + CPU_SSE_FLAGS }, + { ".sse2", PROCESSOR_UNKNOWN, + CPU_SSE2_FLAGS }, + { ".sse3", PROCESSOR_UNKNOWN, + CPU_SSE3_FLAGS }, + { ".ssse3", PROCESSOR_UNKNOWN, + CPU_SSSE3_FLAGS }, + { ".sse4.1", PROCESSOR_UNKNOWN, + CPU_SSE4_1_FLAGS }, + { ".sse4.2", PROCESSOR_UNKNOWN, + CPU_SSE4_2_FLAGS }, + { ".sse4", PROCESSOR_UNKNOWN, + CPU_SSE4_2_FLAGS }, + { ".avx", PROCESSOR_UNKNOWN, + CPU_AVX_FLAGS }, + { ".vmx", PROCESSOR_UNKNOWN, + CPU_VMX_FLAGS }, + { ".smx", PROCESSOR_UNKNOWN, + CPU_SMX_FLAGS }, + { ".xsave", PROCESSOR_UNKNOWN, + CPU_XSAVE_FLAGS }, + { ".aes", PROCESSOR_UNKNOWN, + CPU_AES_FLAGS }, + { ".pclmul", PROCESSOR_UNKNOWN, + CPU_PCLMUL_FLAGS }, + { ".clmul", PROCESSOR_UNKNOWN, + CPU_PCLMUL_FLAGS }, + { ".fma", PROCESSOR_UNKNOWN, + CPU_FMA_FLAGS }, + { ".fma4", PROCESSOR_UNKNOWN, + CPU_FMA4_FLAGS }, + { ".movbe", PROCESSOR_UNKNOWN, + CPU_MOVBE_FLAGS }, + { ".ept", PROCESSOR_UNKNOWN, + CPU_EPT_FLAGS }, + { ".clflush", PROCESSOR_UNKNOWN, + CPU_CLFLUSH_FLAGS }, + { ".syscall", PROCESSOR_UNKNOWN, + CPU_SYSCALL_FLAGS }, + { ".rdtscp", PROCESSOR_UNKNOWN, + CPU_RDTSCP_FLAGS }, + { ".3dnow", PROCESSOR_UNKNOWN, + CPU_3DNOW_FLAGS }, + { ".3dnowa", PROCESSOR_UNKNOWN, + CPU_3DNOWA_FLAGS }, + { ".padlock", PROCESSOR_UNKNOWN, + CPU_PADLOCK_FLAGS }, + { ".pacifica", PROCESSOR_UNKNOWN, + CPU_SVME_FLAGS }, + { ".svme", PROCESSOR_UNKNOWN, + CPU_SVME_FLAGS }, + { ".sse4a", PROCESSOR_UNKNOWN, + CPU_SSE4A_FLAGS }, + { ".abm", PROCESSOR_UNKNOWN, + CPU_ABM_FLAGS }, }; +#ifdef I386COFF +/* Like s_lcomm_internal in gas/read.c but the alignment string + is allowed to be optional. */ + +static symbolS * +pe_lcomm_internal (int needs_align, symbolS *symbolP, addressT size) +{ + addressT align = 0; + + SKIP_WHITESPACE (); + + if (needs_align + && *input_line_pointer == ',') + { + align = parse_align (needs_align - 1); + + if (align == (addressT) -1) + return NULL; + } + else + { + if (size >= 8) + align = 3; + else if (size >= 4) + align = 2; + else if (size >= 2) + align = 1; + else + align = 0; + } + + bss_alloc (symbolP, size, align); + return symbolP; +} + +static void +pe_lcomm (int needs_align) +{ + s_comm_internal (needs_align * 2, pe_lcomm_internal); +} +#endif + const pseudo_typeS md_pseudo_table[] = { #if !defined(OBJ_AOUT) && !defined(USE_ALIGN_PTWO) @@ -525,6 +703,8 @@ const pseudo_typeS md_pseudo_table[] = {"arch", set_cpu_arch, 0}, #ifndef I386COFF {"bss", s_bss, 0}, +#else + {"lcomm", pe_lcomm, 1}, #endif {"ffloat", float_cons, 'f'}, {"dfloat", float_cons, 'd'}, @@ -543,6 +723,7 @@ const pseudo_typeS md_pseudo_table[] = {"att_mnemonic", set_intel_mnemonic, 0}, {"allow_index_reg", set_allow_index_reg, 1}, {"disallow_index_reg", set_allow_index_reg, 0}, + {"sse_check", set_sse_check, 0}, #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) {"largecomm", handle_large_common, 0}, #else @@ -750,8 +931,8 @@ i386_align_code (fragS *fragP, int count) 1. For PROCESSOR_I386, PROCESSOR_I486, PROCESSOR_PENTIUM and PROCESSOR_GENERIC32, f32_patt will be used. 2. For PROCESSOR_PENTIUMPRO, PROCESSOR_PENTIUM4, PROCESSOR_NOCONA, - PROCESSOR_CORE, PROCESSOR_CORE2, and PROCESSOR_GENERIC64, - alt_long_patt will be used. + PROCESSOR_CORE, PROCESSOR_CORE2, PROCESSOR_COREI7, and + PROCESSOR_GENERIC64, alt_long_patt will be used. 3. For PROCESSOR_ATHLON, PROCESSOR_K6, PROCESSOR_K8 and PROCESSOR_AMDFAM10, alt_short_patt will be used. @@ -779,7 +960,7 @@ i386_align_code (fragS *fragP, int count) { const char *const *patt = NULL; - if (cpu_arch_isa == PROCESSOR_UNKNOWN) + if (fragP->tc_frag_data.isa == PROCESSOR_UNKNOWN) { /* PROCESSOR_UNKNOWN means that all ISAs may be used. */ switch (cpu_arch_tune) @@ -787,7 +968,7 @@ i386_align_code (fragS *fragP, int count) case PROCESSOR_UNKNOWN: /* We use cpu_arch_isa_flags to check if we SHOULD optimize for Cpu686. */ - if (cpu_arch_isa_flags.bitfield.cpui686) + if (fragP->tc_frag_data.isa_flags.bitfield.cpui686) patt = alt_long_patt; else patt = f32_patt; @@ -797,6 +978,7 @@ i386_align_code (fragS *fragP, int count) case PROCESSOR_NOCONA: case PROCESSOR_CORE: case PROCESSOR_CORE2: + case PROCESSOR_COREI7: case PROCESSOR_GENERIC64: patt = alt_long_patt; break; @@ -816,10 +998,10 @@ i386_align_code (fragS *fragP, int count) } else { - switch (cpu_arch_tune) + switch (fragP->tc_frag_data.tune) { case PROCESSOR_UNKNOWN: - /* When cpu_arch_isa is net, cpu_arch_tune shouldn't be + /* When cpu_arch_isa is set, cpu_arch_tune shouldn't be PROCESSOR_UNKNOWN. */ abort (); break; @@ -834,7 +1016,7 @@ i386_align_code (fragS *fragP, int count) case PROCESSOR_GENERIC32: /* We use cpu_arch_isa_flags to check if we CAN optimize for Cpu686. */ - if (cpu_arch_isa_flags.bitfield.cpui686) + if (fragP->tc_frag_data.isa_flags.bitfield.cpui686) patt = alt_short_patt; else patt = f32_patt; @@ -844,7 +1026,8 @@ i386_align_code (fragS *fragP, int count) case PROCESSOR_NOCONA: case PROCESSOR_CORE: case PROCESSOR_CORE2: - if (cpu_arch_isa_flags.bitfield.cpui686) + case PROCESSOR_COREI7: + if (fragP->tc_frag_data.isa_flags.bitfield.cpui686) patt = alt_long_patt; else patt = f32_patt; @@ -893,34 +1076,34 @@ i386_align_code (fragS *fragP, int count) } static INLINE int -uints_all_zero (const unsigned int *x, unsigned int size) +operand_type_all_zero (const union i386_operand_type *x) { - switch (size) + switch (ARRAY_SIZE(x->array)) { case 3: - if (x[2]) + if (x->array[2]) return 0; case 2: - if (x[1]) + if (x->array[1]) return 0; case 1: - return !x[0]; + return !x->array[0]; default: abort (); } } static INLINE void -uints_set (unsigned int *x, unsigned int v, unsigned int size) +operand_type_set (union i386_operand_type *x, unsigned int v) { - switch (size) + switch (ARRAY_SIZE(x->array)) { case 3: - x[2] = v; + x->array[2] = v; case 2: - x[1] = v; + x->array[1] = v; case 1: - x[0] = v; + x->array[0] = v; break; default: abort (); @@ -928,33 +1111,79 @@ uints_set (unsigned int *x, unsigned int v, unsigned int size) } static INLINE int -uints_equal (const unsigned int *x, const unsigned int *y, - unsigned int size) +operand_type_equal (const union i386_operand_type *x, + const union i386_operand_type *y) { - switch (size) + switch (ARRAY_SIZE(x->array)) { case 3: - if (x[2] != y [2]) + if (x->array[2] != y->array[2]) return 0; case 2: - if (x[1] != y [1]) + if (x->array[1] != y->array[1]) return 0; case 1: - return x[0] == y [0]; + return x->array[0] == y->array[0]; + break; + default: + abort (); + } +} + +static INLINE int +cpu_flags_all_zero (const union i386_cpu_flags *x) +{ + switch (ARRAY_SIZE(x->array)) + { + case 3: + if (x->array[2]) + return 0; + case 2: + if (x->array[1]) + return 0; + case 1: + return !x->array[0]; + default: + abort (); + } +} + +static INLINE void +cpu_flags_set (union i386_cpu_flags *x, unsigned int v) +{ + switch (ARRAY_SIZE(x->array)) + { + case 3: + x->array[2] = v; + case 2: + x->array[1] = v; + case 1: + x->array[0] = v; break; default: abort (); } } -#define UINTS_ALL_ZERO(x) \ - uints_all_zero ((x).array, ARRAY_SIZE ((x).array)) -#define UINTS_SET(x, v) \ - uints_set ((x).array, v, ARRAY_SIZE ((x).array)) -#define UINTS_CLEAR(x) \ - uints_set ((x).array, 0, ARRAY_SIZE ((x).array)) -#define UINTS_EQUAL(x, y) \ - uints_equal ((x).array, (y).array, ARRAY_SIZE ((x).array)) +static INLINE int +cpu_flags_equal (const union i386_cpu_flags *x, + const union i386_cpu_flags *y) +{ + switch (ARRAY_SIZE(x->array)) + { + case 3: + if (x->array[2] != y->array[2]) + return 0; + case 2: + if (x->array[1] != y->array[1]) + return 0; + case 1: + return x->array[0] == y->array[0]; + break; + default: + abort (); + } +} static INLINE int cpu_flags_check_cpu64 (i386_cpu_flags f) @@ -999,29 +1228,71 @@ cpu_flags_or (i386_cpu_flags x, i386_cpu_flags y) return x; } -/* Return 3 if there is a perfect match, 2 if compatible with 64bit, - 1 if compatible with arch, 0 if there is no match. */ +#define CPU_FLAGS_ARCH_MATCH 0x1 +#define CPU_FLAGS_64BIT_MATCH 0x2 +#define CPU_FLAGS_AES_MATCH 0x4 +#define CPU_FLAGS_PCLMUL_MATCH 0x8 +#define CPU_FLAGS_AVX_MATCH 0x10 + +#define CPU_FLAGS_32BIT_MATCH \ + (CPU_FLAGS_ARCH_MATCH | CPU_FLAGS_AES_MATCH \ + | CPU_FLAGS_PCLMUL_MATCH | CPU_FLAGS_AVX_MATCH) +#define CPU_FLAGS_PERFECT_MATCH \ + (CPU_FLAGS_32BIT_MATCH | CPU_FLAGS_64BIT_MATCH) + +/* Return CPU flags match bits. */ static int -cpu_flags_match (i386_cpu_flags x) +cpu_flags_match (const template *t) { - int overlap = cpu_flags_check_cpu64 (x) ? 2 : 0; + i386_cpu_flags x = t->cpu_flags; + int match = cpu_flags_check_cpu64 (x) ? CPU_FLAGS_64BIT_MATCH : 0; x.bitfield.cpu64 = 0; x.bitfield.cpuno64 = 0; - if (UINTS_ALL_ZERO (x)) - overlap |= 1; + if (cpu_flags_all_zero (&x)) + { + /* This instruction is available on all archs. */ + match |= CPU_FLAGS_32BIT_MATCH; + } else { + /* This instruction is available only on some archs. */ i386_cpu_flags cpu = cpu_arch_flags; cpu.bitfield.cpu64 = 0; cpu.bitfield.cpuno64 = 0; cpu = cpu_flags_and (x, cpu); - overlap |= UINTS_ALL_ZERO (cpu) ? 0 : 1; + if (!cpu_flags_all_zero (&cpu)) + { + if (x.bitfield.cpuavx) + { + /* We only need to check AES/PCLMUL/SSE2AVX with AVX. */ + if (cpu.bitfield.cpuavx) + { + /* Check SSE2AVX. */ + if (!t->opcode_modifier.sse2avx|| sse2avx) + { + match |= (CPU_FLAGS_ARCH_MATCH + | CPU_FLAGS_AVX_MATCH); + /* Check AES. */ + if (!x.bitfield.cpuaes || cpu.bitfield.cpuaes) + match |= CPU_FLAGS_AES_MATCH; + /* Check PCLMUL. */ + if (!x.bitfield.cpupclmul + || cpu.bitfield.cpupclmul) + match |= CPU_FLAGS_PCLMUL_MATCH; + } + } + else + match |= CPU_FLAGS_ARCH_MATCH; + } + else + match |= CPU_FLAGS_32BIT_MATCH; + } } - return overlap; + return match; } static INLINE i386_operand_type @@ -1081,6 +1352,8 @@ operand_type_xor (i386_operand_type x, i386_operand_type y) static const i386_operand_type acc32 = OPERAND_TYPE_ACC32; static const i386_operand_type acc64 = OPERAND_TYPE_ACC64; static const i386_operand_type control = OPERAND_TYPE_CONTROL; +static const i386_operand_type inoutportreg + = OPERAND_TYPE_INOUTPORTREG; static const i386_operand_type reg16_inoutportreg = OPERAND_TYPE_REG16_INOUTPORTREG; static const i386_operand_type disp16 = OPERAND_TYPE_DISP16; @@ -1090,6 +1363,7 @@ static const i386_operand_type disp16_32 = OPERAND_TYPE_DISP16_32; static const i386_operand_type anydisp = OPERAND_TYPE_ANYDISP; static const i386_operand_type regxmm = OPERAND_TYPE_REGXMM; +static const i386_operand_type regymm = OPERAND_TYPE_REGYMM; static const i386_operand_type imm8 = OPERAND_TYPE_IMM8; static const i386_operand_type imm8s = OPERAND_TYPE_IMM8S; static const i386_operand_type imm16 = OPERAND_TYPE_IMM16; @@ -1145,6 +1419,8 @@ operand_type_check (i386_operand_type t, enum operand_type c) default: abort (); } + + return 0; } /* Return 1 if there is no conflict in 8bit/16bit/32bit/64bit on @@ -1177,7 +1453,9 @@ match_mem_size (const template *t, unsigned int j) || (i.types[j].bitfield.tbyte && !t->operand_types[j].bitfield.tbyte) || (i.types[j].bitfield.xmmword - && !t->operand_types[j].bitfield.xmmword))); + && !t->operand_types[j].bitfield.xmmword) + || (i.types[j].bitfield.ymmword + && !t->operand_types[j].bitfield.ymmword))); } /* Return 1 if there is no size conflict on any operands for @@ -1220,7 +1498,7 @@ operand_size_match (const template *t) return match; /* Check reverse. */ - assert (i.operands == 2); + gas_assert (i.operands == 2); match = 1; for (j = 0; j < 2; j++) @@ -1258,7 +1536,8 @@ operand_type_match (i386_operand_type overlap, temp.bitfield.qword = 0; temp.bitfield.tbyte = 0; temp.bitfield.xmmword = 0; - if (UINTS_ALL_ZERO (temp)) + temp.bitfield.ymmword = 0; + if (operand_type_all_zero (&temp)) return 0; return (given.bitfield.baseindex == overlap.bitfield.baseindex @@ -1373,8 +1652,8 @@ static i386_operand_type smallest_imm_type (offsetT num) { i386_operand_type t; - - UINTS_CLEAR (t); + + operand_type_set (&t, 0); t.bitfield.imm64 = 1; if (cpu_arch_tune != PROCESSOR_I486 && num == 1) @@ -1591,6 +1870,8 @@ set_intel_syntax (int syntax_flag) else allow_naked_reg = (ask_naked_reg < 0); + expr_set_rank (O_full_ptr, syntax_flag ? 10 : 0); + identifier_chars['%'] = intel_syntax && allow_naked_reg ? '%' : 0; identifier_chars['$'] = intel_syntax ? '$' : 0; register_prefix = allow_naked_reg ? "" : "%"; @@ -1608,6 +1889,32 @@ set_allow_index_reg (int flag) allow_index_reg = flag; } +static void +set_sse_check (int dummy ATTRIBUTE_UNUSED) +{ + SKIP_WHITESPACE (); + + if (!is_end_of_line[(unsigned char) *input_line_pointer]) + { + char *string = input_line_pointer; + int e = get_symbol_end (); + + if (strcmp (string, "none") == 0) + sse_check = sse_check_none; + else if (strcmp (string, "warning") == 0) + sse_check = sse_check_warning; + else if (strcmp (string, "error") == 0) + sse_check = sse_check_error; + else + as_bad (_("bad argument to sse_check directive.")); + *input_line_pointer = e; + } + else + as_bad (_("missing argument for sse_check directive")); + + demand_empty_rest_of_line (); +} + static void set_cpu_arch (int dummy ATTRIBUTE_UNUSED) { @@ -1651,9 +1958,18 @@ set_cpu_arch (int dummy ATTRIBUTE_UNUSED) flags = cpu_flags_or (cpu_arch_flags, cpu_arch[i].flags); - if (!UINTS_EQUAL (flags, cpu_arch_flags)) + if (!cpu_flags_equal (&flags, &cpu_arch_flags)) { - cpu_sub_arch_name = cpu_arch[i].name; + if (cpu_sub_arch_name) + { + char *name = cpu_sub_arch_name; + cpu_sub_arch_name = concat (name, + cpu_arch[i].name, + (const char *) NULL); + free (name); + } + else + cpu_sub_arch_name = xstrdup (cpu_arch[i].name); cpu_arch_flags = flags; } *input_line_pointer = e; @@ -1728,7 +2044,7 @@ md_begin () core_optab->end = optab; hash_err = hash_insert (op_hash, (optab - 1)->name, - (PTR) core_optab); + (void *) core_optab); if (hash_err) { as_fatal (_("Internal Error: Can't hash %s: %s"), @@ -1751,7 +2067,7 @@ md_begin () for (regtab = i386_regtab; regtab_size--; regtab++) { - hash_err = hash_insert (reg_hash, regtab->reg_name, (PTR) regtab); + hash_err = hash_insert (reg_hash, regtab->reg_name, (void *) regtab); if (hash_err) as_fatal (_("Internal Error: Can't hash %s: %s"), regtab->reg_name, @@ -1803,6 +2119,7 @@ md_begin () operand_chars['?'] = '?'; #endif digit_chars['-'] = '-'; + mnemonic_chars['_'] = '_'; mnemonic_chars['-'] = '-'; mnemonic_chars['.'] = '.'; identifier_chars['_'] = '_'; @@ -1868,8 +2185,6 @@ pi (char *line, i386_insn *x) (x->rex & REX_R) != 0, (x->rex & REX_X) != 0, (x->rex & REX_B) != 0); - fprintf (stdout, " drex: reg %d rex 0x%x\n", - x->drex.reg, x->drex.rex); for (i = 0; i < x->operands; i++) { fprintf (stdout, " #%d: ", i + 1); @@ -1881,6 +2196,7 @@ pi (char *line, i386_insn *x) || x->types[i].bitfield.reg64 || x->types[i].bitfield.regmmx || x->types[i].bitfield.regxmm + || x->types[i].bitfield.regymm || x->types[i].bitfield.sreg2 || x->types[i].bitfield.sreg3 || x->types[i].bitfield.control @@ -1981,6 +2297,7 @@ const type_names[] = { OPERAND_TYPE_JUMPABSOLUTE, "Jump Absolute" }, { OPERAND_TYPE_REGMMX, "rMMX" }, { OPERAND_TYPE_REGXMM, "rXMM" }, + { OPERAND_TYPE_REGYMM, "rYMM" }, { OPERAND_TYPE_ESSEG, "es" }, }; @@ -1993,7 +2310,7 @@ pt (i386_operand_type t) for (j = 0; j < ARRAY_SIZE (type_names); j++) { a = operand_type_and (t, type_names[j].mask); - if (!UINTS_ALL_ZERO (a)) + if (!operand_type_all_zero (&a)) fprintf (stdout, "%s, ", type_names[j].name); } fflush (stdout); @@ -2091,8 +2408,7 @@ reloc (unsigned int size, sign > 0 ? "signed" : "unsigned", size); } - abort (); - return BFD_RELOC_NONE; + return NO_RELOC; } /* Here we decide which fixups can be adjusted to make them relative to @@ -2150,6 +2466,10 @@ tc_i386_fix_adjustable (fixS *fixP ATTRIBUTE_UNUSED) || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) return 0; + + if (fixP->fx_addsy != NULL + && symbol_get_bfdsym (fixP->fx_addsy)->flags & BSF_GNU_INDIRECT_FUNCTION) + return 0; #endif return 1; } @@ -2207,16 +2527,186 @@ intel_float_operand (const char *mnemonic) return 1; } +/* Build the VEX prefix. */ + +static void +build_vex_prefix (const template *t) +{ + unsigned int register_specifier; + unsigned int implied_prefix; + unsigned int vector_length; + + /* Check register specifier. */ + if (i.vex.register_specifier) + { + register_specifier = i.vex.register_specifier->reg_num; + if ((i.vex.register_specifier->reg_flags & RegRex)) + register_specifier += 8; + register_specifier = ~register_specifier & 0xf; + } + else + register_specifier = 0xf; + + /* Use 2-byte VEX prefix by swappping destination and source + operand. */ + if (!i.swap_operand + && i.operands == i.reg_operands + && i.tm.opcode_modifier.vex0f + && i.tm.opcode_modifier.s + && i.rex == REX_B) + { + unsigned int xchg = i.operands - 1; + union i386_op temp_op; + i386_operand_type temp_type; + + temp_type = i.types[xchg]; + i.types[xchg] = i.types[0]; + i.types[0] = temp_type; + temp_op = i.op[xchg]; + i.op[xchg] = i.op[0]; + i.op[0] = temp_op; + + gas_assert (i.rm.mode == 3); + + i.rex = REX_R; + xchg = i.rm.regmem; + i.rm.regmem = i.rm.reg; + i.rm.reg = xchg; + + /* Use the next insn. */ + i.tm = t[1]; + } + + vector_length = i.tm.opcode_modifier.vex256 ? 1 : 0; + + switch ((i.tm.base_opcode >> 8) & 0xff) + { + case 0: + implied_prefix = 0; + break; + case DATA_PREFIX_OPCODE: + implied_prefix = 1; + break; + case REPE_PREFIX_OPCODE: + implied_prefix = 2; + break; + case REPNE_PREFIX_OPCODE: + implied_prefix = 3; + break; + default: + abort (); + } + + /* Use 2-byte VEX prefix if possible. */ + if (i.tm.opcode_modifier.vex0f + && (i.rex & (REX_W | REX_X | REX_B)) == 0) + { + /* 2-byte VEX prefix. */ + unsigned int r; + + i.vex.length = 2; + i.vex.bytes[0] = 0xc5; + + /* Check the REX.R bit. */ + r = (i.rex & REX_R) ? 0 : 1; + i.vex.bytes[1] = (r << 7 + | register_specifier << 3 + | vector_length << 2 + | implied_prefix); + } + else + { + /* 3-byte VEX prefix. */ + unsigned int m, w; + + if (i.tm.opcode_modifier.vex0f) + m = 0x1; + else if (i.tm.opcode_modifier.vex0f38) + m = 0x2; + else if (i.tm.opcode_modifier.vex0f3a) + m = 0x3; + else + abort (); + + i.vex.length = 3; + i.vex.bytes[0] = 0xc4; + + /* The high 3 bits of the second VEX byte are 1's compliment + of RXB bits from REX. */ + i.vex.bytes[1] = (~i.rex & 0x7) << 5 | m; + + /* Check the REX.W bit. */ + w = (i.rex & REX_W) ? 1 : 0; + if (i.tm.opcode_modifier.vexw0 || i.tm.opcode_modifier.vexw1) + { + if (w) + abort (); + + if (i.tm.opcode_modifier.vexw1) + w = 1; + } + + i.vex.bytes[2] = (w << 7 + | register_specifier << 3 + | vector_length << 2 + | implied_prefix); + } +} + +static void +process_immext (void) +{ + expressionS *exp; + + if (i.tm.cpu_flags.bitfield.cpusse3 && i.operands > 0) + { + /* SSE3 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%s' as operand %d in '%s'."), + register_prefix, i.op[x].regs->reg_name, x + 1, + i.tm.name); + + i.operands = 0; + } + + /* These AMD 3DNow! and SSE2 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. + + AVX instructions also use this encoding, for some of + 3 argument instructions. */ + + gas_assert (i.imm_operands == 0 + && (i.operands <= 2 + || (i.tm.opcode_modifier.vex + && i.operands <= 4))); + + exp = &im_expressions[i.imm_operands++]; + i.op[i.operands].imms = exp; + i.types[i.operands] = imm8; + i.operands++; + exp->X_op = O_constant; + exp->X_add_number = i.tm.extension_opcode; + i.tm.extension_opcode = None; +} + /* This is the guts of the machine-dependent assembler. LINE points to a machine dependent instruction. This function is supposed to emit the frags/bytes it assembles to. */ void -md_assemble (line) - char *line; +md_assemble (char *line) { unsigned int j; char mnemonic[MAX_MNEM_SIZE]; + const template *t; /* Initialize globals. */ memset (&i, '\0', sizeof (i)); @@ -2235,6 +2725,7 @@ md_assemble (line) return; line = parse_operands (line, mnemonic); + this_operand = -1; if (line == NULL) return; @@ -2274,9 +2765,23 @@ md_assemble (line) making sure the overlap of the given operands types is consistent with the template operand types. */ - if (!match_template ()) + if (!(t = match_template ())) return; + if (sse_check != sse_check_none + && !i.tm.opcode_modifier.noavx + && (i.tm.cpu_flags.bitfield.cpusse + || i.tm.cpu_flags.bitfield.cpusse2 + || i.tm.cpu_flags.bitfield.cpusse3 + || i.tm.cpu_flags.bitfield.cpussse3 + || i.tm.cpu_flags.bitfield.cpusse4_1 + || i.tm.cpu_flags.bitfield.cpusse4_2)) + { + (sse_check == sse_check_warning + ? as_warn + : as_bad) (_("SSE instruction `%s' is used"), i.tm.name); + } + /* Zap movzx and movsx suffix. The suffix has been set from "word ptr" or "byte ptr" on the source operand in Intel syntax or extracted from mnemonic in AT&T syntax. But we'll use @@ -2287,7 +2792,7 @@ md_assemble (line) there is no suffix, the default will be byte extension. */ if (i.reg_operands != 2 && !i.suffix - && intel_syntax) + && intel_syntax) as_bad (_("ambiguous operand size for `%s'"), i.tm.name); i.suffix = 0; @@ -2302,11 +2807,16 @@ md_assemble (line) { if (!check_string ()) return; + i.disp_operands = 0; } if (!process_suffix ()) return; + /* Update operand types. */ + for (j = 0; j < i.operands; j++) + i.types[j] = operand_type_and (i.types[j], i.tm.operand_types[j]); + /* Make still unresolved immediate matches conform to size of immediate given in i.suffix. */ if (!finalize_imm ()) @@ -2315,56 +2825,20 @@ md_assemble (line) if (i.types[0].bitfield.imm1) i.imm_operands = 0; /* kludge for shift insns. */ - for (j = 0; j < 3; j++) - if (i.types[j].bitfield.inoutportreg - || i.types[j].bitfield.shiftcount - || i.types[j].bitfield.acc - || i.types[j].bitfield.floatacc) - i.reg_operands--; - - if (i.tm.opcode_modifier.immext) - { - expressionS *exp; - - if (i.tm.cpu_flags.bitfield.cpusse3 && i.operands > 0) - { - /* Streaming SIMD extensions 3 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%s' as operand %d in '%s'."), - register_prefix, - 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. - SSE5 also uses this encoding, for some of its 3 argument - instructions. */ - - assert (i.imm_operands == 0 - && (i.operands <= 2 - || (i.tm.cpu_flags.bitfield.cpusse5 - && i.operands <= 3))); - - exp = &im_expressions[i.imm_operands++]; - i.op[i.operands].imms = exp; - UINTS_CLEAR (i.types[i.operands]); - i.types[i.operands].bitfield.imm8 = 1; - i.operands++; - exp->X_op = O_constant; - exp->X_add_number = i.tm.extension_opcode; - i.tm.extension_opcode = None; - } + /* We only need to check those implicit registers for instructions + with 3 operands or less. */ + if (i.operands <= 3) + for (j = 0; j < i.operands; j++) + if (i.types[j].bitfield.inoutportreg + || i.types[j].bitfield.shiftcount + || i.types[j].bitfield.acc + || i.types[j].bitfield.floatacc) + i.reg_operands--; + + /* ImmExt should be processed after SSE2AVX. */ + if (!i.tm.opcode_modifier.sse2avx + && i.tm.opcode_modifier.immext) + process_immext (); /* For insns with operands there are more diddles to do to the opcode. */ if (i.operands) @@ -2378,6 +2852,9 @@ md_assemble (line) as_warn (_("translating to `%sp'"), i.tm.name); } + if (i.tm.opcode_modifier.vex) + build_vex_prefix (t); + /* Handle conversion of 'int $3' --> special int3 insn. */ if (i.tm.base_opcode == INT_OPCODE && i.op[0].imms->X_add_number == 3) { @@ -2436,14 +2913,7 @@ md_assemble (line) } } - /* If the instruction has the DREX attribute (aka SSE5), don't emit a - REX prefix. */ - if (i.tm.opcode_modifier.drex || i.tm.opcode_modifier.drexc) - { - i.drex.rex = i.rex; - i.rex = 0; - } - else if (i.rex != 0) + if (i.rex != 0) add_prefix (REX_OPCODE | i.rex); /* We are ready to output the insn. */ @@ -2458,6 +2928,7 @@ parse_insn (char *line, char *mnemonic) char *mnem_p; int supported; const template *t; + char *dot_p = NULL; /* Non-zero if we found a prefix only acceptable with string insns. */ const char *expecting_string_instruction = NULL; @@ -2467,6 +2938,8 @@ parse_insn (char *line, char *mnemonic) mnem_p = mnemonic; while ((*mnem_p = mnemonic_chars[(unsigned char) *l]) != 0) { + if (*mnem_p == '.') + dot_p = mnem_p; mnem_p++; if (mnem_p >= mnemonic + MAX_MNEM_SIZE) { @@ -2540,6 +3013,19 @@ parse_insn (char *line, char *mnemonic) if (!current_templates) { + /* Check if we should swap operand in encoding. */ + if (mnem_p - 2 == dot_p && dot_p[1] == 's') + i.swap_operand = 1; + else + goto check_suffix; + mnem_p = dot_p; + *dot_p = '\0'; + current_templates = hash_find (op_hash, mnemonic); + } + + if (!current_templates) + { +check_suffix: /* See if we can get a match by trimming off a suffix. */ switch (mnem_p[-1]) { @@ -2620,12 +3106,12 @@ parse_insn (char *line, char *mnemonic) supported = 0; for (t = current_templates->start; t < current_templates->end; ++t) { - supported |= cpu_flags_match (t->cpu_flags); - if (supported == 3) + supported |= cpu_flags_match (t); + if (supported == CPU_FLAGS_PERFECT_MATCH) goto skip; } - if (!(supported & 2)) + if (!(supported & CPU_FLAGS_64BIT_MATCH)) { as_bad (flag_code == CODE_64BIT ? _("`%s' is not supported in 64-bit mode") @@ -2633,10 +3119,11 @@ parse_insn (char *line, char *mnemonic) current_templates->start->name); return NULL; } - if (!(supported & 1)) + if (supported != CPU_FLAGS_PERFECT_MATCH) { as_bad (_("`%s' is not supported on `%s%s'"), - current_templates->start->name, cpu_arch_name, + current_templates->start->name, + cpu_arch_name ? cpu_arch_name : default_arch, cpu_sub_arch_name ? cpu_sub_arch_name : ""); return NULL; } @@ -2814,6 +3301,7 @@ swap_operands (void) { switch (i.operands) { + case 5: case 4: swap_2_operands (1, i.operands - 2); case 3: @@ -2851,7 +3339,7 @@ optimize_imm (void) In any case, we can't set i.suffix yet. */ for (op = i.operands; --op >= 0;) if (i.types[op].bitfield.reg8) - { + { guess_suffix = BYTE_MNEM_SUFFIX; break; } @@ -2945,8 +3433,8 @@ optimize_imm (void) i386_operand_type mask, allowed; const template *t; - UINTS_CLEAR (mask); - UINTS_CLEAR (allowed); + operand_type_set (&mask, 0); + operand_type_set (&allowed, 0); for (t = current_templates->start; t < current_templates->end; @@ -2972,7 +3460,7 @@ optimize_imm (void) break; } allowed = operand_type_and (mask, allowed); - if (!UINTS_ALL_ZERO (allowed)) + if (!operand_type_all_zero (&allowed)) i.types[op] = operand_type_and (i.types[op], mask); } break; @@ -3055,12 +3543,13 @@ optimize_disp (void) } } -static int +static const template * match_template (void) { /* Points to template once we've found it. */ const template *t; i386_operand_type overlap0, overlap1, overlap2, overlap3; + i386_operand_type overlap4; unsigned int found_reverse_match; i386_opcode_modifier suffix_check; i386_operand_type operand_types [MAX_OPERANDS]; @@ -3069,8 +3558,8 @@ match_template (void) unsigned int found_cpu_match; unsigned int check_register; -#if MAX_OPERANDS != 4 -# error "MAX_OPERANDS must be 4." +#if MAX_OPERANDS != 5 +# error "MAX_OPERANDS must be 5." #endif found_reverse_match = 0; @@ -3099,7 +3588,8 @@ match_template (void) continue; /* Check processor support. */ - found_cpu_match = cpu_flags_match (t->cpu_flags) == 3; + found_cpu_match = (cpu_flags_match (t) + == CPU_FLAGS_PERFECT_MATCH); if (!found_cpu_match) continue; @@ -3140,13 +3630,28 @@ match_template (void) && !intel_float_operand (t->name)) : intel_float_operand (t->name) != 2) && ((!operand_types[0].bitfield.regmmx - && !operand_types[0].bitfield.regxmm) + && !operand_types[0].bitfield.regxmm + && !operand_types[0].bitfield.regymm) || (!operand_types[t->operands > 1].bitfield.regmmx - && !!operand_types[t->operands > 1].bitfield.regxmm)) + && !!operand_types[t->operands > 1].bitfield.regxmm + && !!operand_types[t->operands > 1].bitfield.regymm)) && (t->base_opcode != 0x0fc7 || t->extension_opcode != 1 /* cmpxchg8b */)) continue; + /* In general, don't allow 32-bit operands on pre-386. */ + else if (i.suffix == LONG_MNEM_SUFFIX + && !cpu_arch_flags.bitfield.cpui386 + && (intel_syntax + ? (!t->opcode_modifier.ignoresize + && !intel_float_operand (t->name)) + : intel_float_operand (t->name) != 2) + && ((!operand_types[0].bitfield.regmmx + && !operand_types[0].bitfield.regxmm) + || (!operand_types[t->operands > 1].bitfield.regmmx + && !!operand_types[t->operands > 1].bitfield.regxmm))) + continue; + /* Do not verify operands when there are none. */ else { @@ -3218,11 +3723,25 @@ match_template (void) zero-extend %eax to %rax. */ if (flag_code == CODE_64BIT && t->base_opcode == 0x90 - && UINTS_EQUAL (i.types [0], acc32) - && UINTS_EQUAL (i.types [1], acc32)) + && operand_type_equal (&i.types [0], &acc32) + && operand_type_equal (&i.types [1], &acc32)) continue; + if (i.swap_operand) + { + /* If we swap operand in encoding, we either match + the next one or reverse direction of operands. */ + if (t->opcode_modifier.s) + continue; + else if (t->opcode_modifier.d) + goto check_reverse; + } + case 3: + /* If we swap operand in encoding, we match the next one. */ + if (i.swap_operand && t->opcode_modifier.s) + continue; case 4: + case 5: overlap1 = operand_type_and (i.types[1], operand_types[1]); if (!operand_type_match (overlap0, i.types[0]) || !operand_type_match (overlap1, i.types[1]) @@ -3236,6 +3755,7 @@ match_template (void) if (!t->opcode_modifier.d && !t->opcode_modifier.floatd) continue; +check_reverse: /* Try reversing direction of operands. */ overlap0 = operand_type_and (i.types[0], operand_types[1]); overlap1 = operand_type_and (i.types[1], operand_types[0]); @@ -3268,6 +3788,9 @@ match_template (void) /* Found a forward 2 operand match here. */ switch (t->operands) { + case 5: + overlap4 = operand_type_and (i.types[4], + operand_types[4]); case 4: overlap3 = operand_type_and (i.types[3], operand_types[3]); @@ -3279,6 +3802,15 @@ match_template (void) switch (t->operands) { + case 5: + if (!operand_type_match (overlap4, i.types[4]) + || !operand_type_register_match (overlap3, + i.types[3], + operand_types[3], + overlap4, + i.types[4], + operand_types[4])) + continue; case 4: if (!operand_type_match (overlap3, i.types[3]) || (check_register @@ -3314,6 +3846,7 @@ match_template (void) found_reverse_match = 0; continue; } + /* We've found a match; break out of loop. */ break; } @@ -3321,9 +3854,13 @@ match_template (void) if (t == current_templates->end) { /* We found no match. */ - as_bad (_("suffix or operands invalid for `%s'"), - current_templates->start->name); - return 0; + if (intel_syntax) + as_bad (_("ambiguous operand size or operands invalid for `%s'"), + current_templates->start->name); + else + as_bad (_("suffix or operands invalid for `%s'"), + current_templates->start->name); + return NULL; } if (!quiet_warnings) @@ -3363,7 +3900,7 @@ match_template (void) i.tm.operand_types[1] = operand_types[0]; } - return 1; + return t; } static int @@ -3374,9 +3911,10 @@ check_string (void) { if (i.seg[0] != NULL && i.seg[0] != &es) { - as_bad (_("`%s' operand %d must use `%%es' segment"), + as_bad (_("`%s' operand %d must use `%ses' segment"), i.tm.name, - mem_op + 1); + mem_op + 1, + register_prefix); return 0; } /* There's only ever one segment override allowed per instruction. @@ -3389,9 +3927,10 @@ check_string (void) { if (i.seg[1] != NULL && i.seg[1] != &es) { - as_bad (_("`%s' operand %d must use `%%es' segment"), + as_bad (_("`%s' operand %d must use `%ses' segment"), i.tm.name, - mem_op + 2); + mem_op + 2, + register_prefix); return 0; } } @@ -3497,9 +4036,10 @@ process_suffix (void) if (!check_word_reg ()) return 0; } - else if (i.suffix == XMMWORD_MNEM_SUFFIX) + else if (i.suffix == XMMWORD_MNEM_SUFFIX + || i.suffix == YMMWORD_MNEM_SUFFIX) { - /* Skip if the instruction has x suffix. match_template + /* Skip if the instruction has x/y suffix. match_template should check if it is a valid suffix. */ } else if (intel_syntax && i.tm.opcode_modifier.ignoresize) @@ -3556,7 +4096,7 @@ process_suffix (void) else { unsigned int suffixes; - + suffixes = !i.tm.opcode_modifier.no_bsuf; if (!i.tm.opcode_modifier.no_wsuf) suffixes |= 1 << 1; @@ -3586,7 +4126,8 @@ process_suffix (void) if (i.suffix && i.suffix != BYTE_MNEM_SUFFIX - && i.suffix != XMMWORD_MNEM_SUFFIX) + && i.suffix != XMMWORD_MNEM_SUFFIX + && i.suffix != YMMWORD_MNEM_SUFFIX) { /* It's not a byte, select word/dword operation. */ if (i.tm.opcode_modifier.w) @@ -3638,8 +4179,8 @@ process_suffix (void) if (! (i.operands == 2 && i.tm.base_opcode == 0x90 && i.tm.extension_opcode == None - && UINTS_EQUAL (i.types [0], acc64) - && UINTS_EQUAL (i.types [1], acc64)) + && operand_type_equal (&i.types [0], &acc64) + && operand_type_equal (&i.types [1], &acc64)) && ! (i.operands == 1 && i.tm.base_opcode == 0xfc7 && i.tm.extension_opcode == 1 @@ -3713,6 +4254,7 @@ check_byte_reg (void) || i.types[op].bitfield.reg64 || i.types[op].bitfield.regmmx || i.types[op].bitfield.regxmm + || i.types[op].bitfield.regymm || i.types[op].bitfield.sreg2 || i.types[op].bitfield.sreg3 || i.types[op].bitfield.control @@ -3896,28 +4438,26 @@ check_word_reg (void) static int update_imm (unsigned int j) { - i386_operand_type overlap; - - overlap = operand_type_and (i.types[j], i.tm.operand_types[j]); + i386_operand_type overlap = i.types[j]; if ((overlap.bitfield.imm8 || overlap.bitfield.imm8s || overlap.bitfield.imm16 || overlap.bitfield.imm32 || overlap.bitfield.imm32s || overlap.bitfield.imm64) - && !UINTS_EQUAL (overlap, imm8) - && !UINTS_EQUAL (overlap, imm8s) - && !UINTS_EQUAL (overlap, imm16) - && !UINTS_EQUAL (overlap, imm32) - && !UINTS_EQUAL (overlap, imm32s) - && !UINTS_EQUAL (overlap, imm64)) + && !operand_type_equal (&overlap, &imm8) + && !operand_type_equal (&overlap, &imm8s) + && !operand_type_equal (&overlap, &imm16) + && !operand_type_equal (&overlap, &imm32) + && !operand_type_equal (&overlap, &imm32s) + && !operand_type_equal (&overlap, &imm64)) { if (i.suffix) { i386_operand_type temp; - UINTS_CLEAR (temp); - if (i.suffix == BYTE_MNEM_SUFFIX) + operand_type_set (&temp, 0); + if (i.suffix == BYTE_MNEM_SUFFIX) { temp.bitfield.imm8 = overlap.bitfield.imm8; temp.bitfield.imm8s = overlap.bitfield.imm8s; @@ -3933,22 +4473,21 @@ update_imm (unsigned int j) temp.bitfield.imm32 = overlap.bitfield.imm32; overlap = temp; } - else if (UINTS_EQUAL (overlap, imm16_32_32s) - || UINTS_EQUAL (overlap, imm16_32) - || UINTS_EQUAL (overlap, imm16_32s)) + else if (operand_type_equal (&overlap, &imm16_32_32s) + || operand_type_equal (&overlap, &imm16_32) + || operand_type_equal (&overlap, &imm16_32s)) { - UINTS_CLEAR (overlap); if ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0)) - overlap.bitfield.imm16 = 1; + overlap = imm16; else - overlap.bitfield.imm32s = 1; + overlap = imm32s; } - if (!UINTS_EQUAL (overlap, imm8) - && !UINTS_EQUAL (overlap, imm8s) - && !UINTS_EQUAL (overlap, imm16) - && !UINTS_EQUAL (overlap, imm32) - && !UINTS_EQUAL (overlap, imm32s) - && !UINTS_EQUAL (overlap, imm64)) + if (!operand_type_equal (&overlap, &imm8) + && !operand_type_equal (&overlap, &imm8s) + && !operand_type_equal (&overlap, &imm16) + && !operand_type_equal (&overlap, &imm32) + && !operand_type_equal (&overlap, &imm32s) + && !operand_type_equal (&overlap, &imm64)) { as_bad (_("no instruction mnemonic suffix given; " "can't determine immediate size")); @@ -3963,378 +4502,136 @@ update_imm (unsigned int j) static int finalize_imm (void) { - unsigned int j; + unsigned int j, n; - for (j = 0; j < 2; j++) - if (update_imm (j) == 0) - return 0; + /* Update the first 2 immediate operands. */ + n = i.operands > 2 ? 2 : i.operands; + if (n) + { + for (j = 0; j < n; j++) + if (update_imm (j) == 0) + return 0; - i.types[2] = operand_type_and (i.types[2], i.tm.operand_types[2]); - assert (operand_type_check (i.types[2], imm) == 0); + /* The 3rd operand can't be immediate operand. */ + gas_assert (operand_type_check (i.types[2], imm) == 0); + } return 1; } -static void -process_drex (void) -{ - i.drex.modrm_reg = 0; - i.drex.modrm_regmem = 0; - - /* SSE5 4 operand instructions must have the destination the same as - one of the inputs. Figure out the destination register and cache - it away in the drex field, and remember which fields to use for - the modrm byte. */ - if (i.tm.opcode_modifier.drex - && i.tm.opcode_modifier.drexv - && i.operands == 4) - { - i.tm.extension_opcode = None; - - /* Case 1: 4 operand insn, dest = src1, src3 = register. */ - if (i.types[0].bitfield.regxmm != 0 - && i.types[1].bitfield.regxmm != 0 - && i.types[2].bitfield.regxmm != 0 - && i.types[3].bitfield.regxmm != 0 - && i.op[0].regs->reg_num == i.op[3].regs->reg_num - && i.op[0].regs->reg_flags == i.op[3].regs->reg_flags) - { - /* Clear the arguments that are stored in drex. */ - UINTS_CLEAR (i.types[0]); - UINTS_CLEAR (i.types[3]); - i.reg_operands -= 2; - - /* There are two different ways to encode a 4 operand - instruction with all registers that uses OC1 set to - 0 or 1. Favor setting OC1 to 0 since this mimics the - actions of other SSE5 assemblers. Use modrm encoding 2 - for register/register. Include the high order bit that - is normally stored in the REX byte in the register - field. */ - i.tm.extension_opcode = DREX_X1_XMEM_X2_X1; - i.drex.modrm_reg = 2; - i.drex.modrm_regmem = 1; - i.drex.reg = (i.op[3].regs->reg_num - + ((i.op[3].regs->reg_flags & RegRex) ? 8 : 0)); - } - - /* Case 2: 4 operand insn, dest = src1, src3 = memory. */ - else if (i.types[0].bitfield.regxmm != 0 - && i.types[1].bitfield.regxmm != 0 - && (i.types[2].bitfield.regxmm - || operand_type_check (i.types[2], anymem)) - && i.types[3].bitfield.regxmm != 0 - && i.op[0].regs->reg_num == i.op[3].regs->reg_num - && i.op[0].regs->reg_flags == i.op[3].regs->reg_flags) - { - /* clear the arguments that are stored in drex */ - UINTS_CLEAR (i.types[0]); - UINTS_CLEAR (i.types[3]); - i.reg_operands -= 2; - - /* Specify the modrm encoding for memory addressing. Include - the high order bit that is normally stored in the REX byte - in the register field. */ - i.tm.extension_opcode = DREX_X1_X2_XMEM_X1; - i.drex.modrm_reg = 1; - i.drex.modrm_regmem = 2; - i.drex.reg = (i.op[3].regs->reg_num - + ((i.op[3].regs->reg_flags & RegRex) ? 8 : 0)); - } - - /* Case 3: 4 operand insn, dest = src1, src2 = memory. */ - else if (i.types[0].bitfield.regxmm != 0 - && operand_type_check (i.types[1], anymem) != 0 - && i.types[2].bitfield.regxmm != 0 - && i.types[3].bitfield.regxmm != 0 - && i.op[0].regs->reg_num == i.op[3].regs->reg_num - && i.op[0].regs->reg_flags == i.op[3].regs->reg_flags) - { - /* Clear the arguments that are stored in drex. */ - UINTS_CLEAR (i.types[0]); - UINTS_CLEAR (i.types[3]); - i.reg_operands -= 2; - - /* Specify the modrm encoding for memory addressing. Include - the high order bit that is normally stored in the REX byte - in the register field. */ - i.tm.extension_opcode = DREX_X1_XMEM_X2_X1; - i.drex.modrm_reg = 2; - i.drex.modrm_regmem = 1; - i.drex.reg = (i.op[3].regs->reg_num - + ((i.op[3].regs->reg_flags & RegRex) ? 8 : 0)); - } +static int +bad_implicit_operand (int xmm) +{ + const char *reg = xmm ? "xmm0" : "ymm0"; + if (intel_syntax) + as_bad (_("the last operand of `%s' must be `%s%s'"), + i.tm.name, register_prefix, reg); + else + as_bad (_("the first operand of `%s' must be `%s%s'"), + i.tm.name, register_prefix, reg); + return 0; +} - /* Case 4: 4 operand insn, dest = src3, src2 = register. */ - else if (i.types[0].bitfield.regxmm != 0 - && i.types[1].bitfield.regxmm != 0 - && i.types[2].bitfield.regxmm != 0 - && i.types[3].bitfield.regxmm != 0 - && i.op[2].regs->reg_num == i.op[3].regs->reg_num - && i.op[2].regs->reg_flags == i.op[3].regs->reg_flags) - { - /* clear the arguments that are stored in drex */ - UINTS_CLEAR (i.types[2]); - UINTS_CLEAR (i.types[3]); - i.reg_operands -= 2; - - /* There are two different ways to encode a 4 operand - instruction with all registers that uses OC1 set to - 0 or 1. Favor setting OC1 to 0 since this mimics the - actions of other SSE5 assemblers. Use modrm encoding - 2 for register/register. Include the high order bit that - is normally stored in the REX byte in the register - field. */ - i.tm.extension_opcode = DREX_XMEM_X1_X2_X2; - i.drex.modrm_reg = 1; - i.drex.modrm_regmem = 0; - - /* Remember the register, including the upper bits */ - i.drex.reg = (i.op[3].regs->reg_num - + ((i.op[3].regs->reg_flags & RegRex) ? 8 : 0)); - } +static int +process_operands (void) +{ + /* Default segment register this instruction will use for memory + accesses. 0 means unknown. This is only for optimizing out + unnecessary segment overrides. */ + const seg_entry *default_seg = 0; - /* Case 5: 4 operand insn, dest = src3, src2 = memory. */ - else if (i.types[0].bitfield.regxmm != 0 - && (i.types[1].bitfield.regxmm - || operand_type_check (i.types[1], anymem)) - && i.types[2].bitfield.regxmm != 0 - && i.types[3].bitfield.regxmm != 0 - && i.op[2].regs->reg_num == i.op[3].regs->reg_num - && i.op[2].regs->reg_flags == i.op[3].regs->reg_flags) - { - /* Clear the arguments that are stored in drex. */ - UINTS_CLEAR (i.types[2]); - UINTS_CLEAR (i.types[3]); - i.reg_operands -= 2; - - /* Specify the modrm encoding and remember the register - including the bits normally stored in the REX byte. */ - i.tm.extension_opcode = DREX_X1_XMEM_X2_X2; - i.drex.modrm_reg = 0; - i.drex.modrm_regmem = 1; - i.drex.reg = (i.op[3].regs->reg_num - + ((i.op[3].regs->reg_flags & RegRex) ? 8 : 0)); - } + if (i.tm.opcode_modifier.sse2avx + && (i.tm.opcode_modifier.vexnds + || i.tm.opcode_modifier.vexndd)) + { + unsigned int dup = i.operands; + unsigned int dest = dup - 1; + unsigned int j; - /* Case 6: 4 operand insn, dest = src3, src1 = memory. */ - else if (operand_type_check (i.types[0], anymem) != 0 - && i.types[1].bitfield.regxmm != 0 - && i.types[2].bitfield.regxmm != 0 - && i.types[3].bitfield.regxmm != 0 - && i.op[2].regs->reg_num == i.op[3].regs->reg_num - && i.op[2].regs->reg_flags == i.op[3].regs->reg_flags) - { - /* clear the arguments that are stored in drex */ - UINTS_CLEAR (i.types[2]); - UINTS_CLEAR (i.types[3]); - i.reg_operands -= 2; - - /* Specify the modrm encoding and remember the register - including the bits normally stored in the REX byte. */ - i.tm.extension_opcode = DREX_XMEM_X1_X2_X2; - i.drex.modrm_reg = 1; - i.drex.modrm_regmem = 0; - i.drex.reg = (i.op[3].regs->reg_num - + ((i.op[3].regs->reg_flags & RegRex) ? 8 : 0)); - } + /* The destination must be an xmm register. */ + gas_assert (i.reg_operands + && MAX_OPERANDS > dup + && operand_type_equal (&i.types[dest], ®xmm)); - else - as_bad (_("Incorrect operands for the '%s' instruction"), - i.tm.name); - } - - /* SSE5 instructions with the DREX byte where the only memory operand - is in the 2nd argument, and the first and last xmm register must - match, and is encoded in the DREX byte. */ - else if (i.tm.opcode_modifier.drex - && !i.tm.opcode_modifier.drexv - && i.operands == 4) - { - /* Case 1: 4 operand insn, dest = src1, src3 = reg/mem. */ - if (i.types[0].bitfield.regxmm != 0 - && (i.types[1].bitfield.regxmm - || operand_type_check(i.types[1], anymem)) - && i.types[2].bitfield.regxmm != 0 - && i.types[3].bitfield.regxmm != 0 - && i.op[0].regs->reg_num == i.op[3].regs->reg_num - && i.op[0].regs->reg_flags == i.op[3].regs->reg_flags) + if (i.tm.opcode_modifier.firstxmm0) { - /* clear the arguments that are stored in drex */ - UINTS_CLEAR (i.types[0]); - UINTS_CLEAR (i.types[3]); - i.reg_operands -= 2; - - /* Specify the modrm encoding and remember the register - including the high bit normally stored in the REX - byte. */ - i.drex.modrm_reg = 2; - i.drex.modrm_regmem = 1; - i.drex.reg = (i.op[3].regs->reg_num - + ((i.op[3].regs->reg_flags & RegRex) ? 8 : 0)); - } - - else - as_bad (_("Incorrect operands for the '%s' instruction"), - i.tm.name); - } - - /* SSE5 3 operand instructions that the result is a register, being - either operand can be a memory operand, using OC0 to note which - one is the memory. */ - else if (i.tm.opcode_modifier.drex - && i.tm.opcode_modifier.drexv - && i.operands == 3) - { - i.tm.extension_opcode = None; + /* The first operand is implicit and must be xmm0. */ + gas_assert (operand_type_equal (&i.types[0], ®xmm)); + if (i.op[0].regs->reg_num != 0) + return bad_implicit_operand (1); - /* Case 1: 3 operand insn, src1 = register. */ - if (i.types[0].bitfield.regxmm != 0 - && i.types[1].bitfield.regxmm != 0 - && i.types[2].bitfield.regxmm != 0) - { - /* Clear the arguments that are stored in drex. */ - UINTS_CLEAR (i.types[2]); - i.reg_operands--; - - /* Specify the modrm encoding and remember the register - including the high bit normally stored in the REX byte. */ - i.tm.extension_opcode = DREX_XMEM_X1_X2; - i.drex.modrm_reg = 1; - i.drex.modrm_regmem = 0; - i.drex.reg = (i.op[2].regs->reg_num - + ((i.op[2].regs->reg_flags & RegRex) ? 8 : 0)); + if (i.tm.opcode_modifier.vex3sources) + { + /* Keep xmm0 for instructions with VEX prefix and 3 + sources. */ + goto duplicate; + } + else + { + /* We remove the first xmm0 and keep the number of + operands unchanged, which in fact duplicates the + destination. */ + for (j = 1; j < i.operands; j++) + { + i.op[j - 1] = i.op[j]; + i.types[j - 1] = i.types[j]; + i.tm.operand_types[j - 1] = i.tm.operand_types[j]; + } + } } - - /* Case 2: 3 operand insn, src1 = memory. */ - else if (operand_type_check (i.types[0], anymem) != 0 - && i.types[1].bitfield.regxmm != 0 - && i.types[2].bitfield.regxmm != 0) + else if (i.tm.opcode_modifier.implicit1stxmm0) { - /* Clear the arguments that are stored in drex. */ - UINTS_CLEAR (i.types[2]); - i.reg_operands--; - - /* Specify the modrm encoding and remember the register - including the high bit normally stored in the REX - byte. */ - i.tm.extension_opcode = DREX_XMEM_X1_X2; - i.drex.modrm_reg = 1; - i.drex.modrm_regmem = 0; - i.drex.reg = (i.op[2].regs->reg_num - + ((i.op[2].regs->reg_flags & RegRex) ? 8 : 0)); - } + gas_assert ((MAX_OPERANDS - 1) > dup + && i.tm.opcode_modifier.vex3sources); - /* Case 3: 3 operand insn, src2 = memory. */ - else if (i.types[0].bitfield.regxmm != 0 - && operand_type_check (i.types[1], anymem) != 0 - && i.types[2].bitfield.regxmm != 0) - { - /* Clear the arguments that are stored in drex. */ - UINTS_CLEAR (i.types[2]); - i.reg_operands--; - - /* Specify the modrm encoding and remember the register - including the high bit normally stored in the REX byte. */ - i.tm.extension_opcode = DREX_X1_XMEM_X2; - i.drex.modrm_reg = 0; - i.drex.modrm_regmem = 1; - i.drex.reg = (i.op[2].regs->reg_num - + ((i.op[2].regs->reg_flags & RegRex) ? 8 : 0)); - } + /* Add the implicit xmm0 for instructions with VEX prefix + and 3 sources. */ + for (j = i.operands; j > 0; j--) + { + i.op[j] = i.op[j - 1]; + i.types[j] = i.types[j - 1]; + i.tm.operand_types[j] = i.tm.operand_types[j - 1]; + } + i.op[0].regs + = (const reg_entry *) hash_find (reg_hash, "xmm0"); + i.types[0] = regxmm; + i.tm.operand_types[0] = regxmm; - else - as_bad (_("Incorrect operands for the '%s' instruction"), - i.tm.name); - } + i.operands += 2; + i.reg_operands += 2; + i.tm.operands += 2; - /* SSE5 4 operand instructions that are the comparison instructions - where the first operand is the immediate value of the comparison - to be done. */ - else if (i.tm.opcode_modifier.drexc != 0 && i.operands == 4) - { - /* Case 1: 4 operand insn, src1 = reg/memory. */ - if (operand_type_check (i.types[0], imm) != 0 - && (i.types[1].bitfield.regxmm - || operand_type_check (i.types[1], anymem)) - && i.types[2].bitfield.regxmm != 0 - && i.types[3].bitfield.regxmm != 0) - { - /* clear the arguments that are stored in drex */ - UINTS_CLEAR (i.types[3]); - i.reg_operands--; - - /* Specify the modrm encoding and remember the register - including the high bit normally stored in the REX byte. */ - i.drex.modrm_reg = 2; - i.drex.modrm_regmem = 1; - i.drex.reg = (i.op[3].regs->reg_num - + ((i.op[3].regs->reg_flags & RegRex) ? 8 : 0)); + dup++; + dest++; + i.op[dup] = i.op[dest]; + i.types[dup] = i.types[dest]; + i.tm.operand_types[dup] = i.tm.operand_types[dest]; } - - /* Case 2: 3 operand insn with ImmExt that places the - opcode_extension as an immediate argument. This is used for - all of the varients of comparison that supplies the appropriate - value as part of the instruction. */ - else if ((i.types[0].bitfield.regxmm - || operand_type_check (i.types[0], anymem)) - && i.types[1].bitfield.regxmm != 0 - && i.types[2].bitfield.regxmm != 0 - && operand_type_check (i.types[3], imm) != 0) + else { - /* clear the arguments that are stored in drex */ - UINTS_CLEAR (i.types[2]); - i.reg_operands--; - - /* Specify the modrm encoding and remember the register - including the high bit normally stored in the REX byte. */ - i.drex.modrm_reg = 1; - i.drex.modrm_regmem = 0; - i.drex.reg = (i.op[2].regs->reg_num - + ((i.op[2].regs->reg_flags & RegRex) ? 8 : 0)); +duplicate: + i.operands++; + i.reg_operands++; + i.tm.operands++; + + i.op[dup] = i.op[dest]; + i.types[dup] = i.types[dest]; + i.tm.operand_types[dup] = i.tm.operand_types[dest]; } - else - as_bad (_("Incorrect operands for the '%s' instruction"), - i.tm.name); + if (i.tm.opcode_modifier.immext) + process_immext (); } - - else if (i.tm.opcode_modifier.drex - || i.tm.opcode_modifier.drexv - || i.tm.opcode_modifier.drexc) - as_bad (_("Internal error for the '%s' instruction"), i.tm.name); -} - -static int -process_operands (void) -{ - /* Default segment register this instruction will use for memory - accesses. 0 means unknown. This is only for optimizing out - unnecessary segment overrides. */ - const seg_entry *default_seg = 0; - - /* Handle all of the DREX munging that SSE5 needs. */ - if (i.tm.opcode_modifier.drex - || i.tm.opcode_modifier.drexv - || i.tm.opcode_modifier.drexc) - process_drex (); - - if (i.tm.opcode_modifier.firstxmm0) + else if (i.tm.opcode_modifier.firstxmm0) { unsigned int j; - /* The first operand is implicit and must be xmm0. */ - assert (i.reg_operands && UINTS_EQUAL (i.types[0], regxmm)); + /* The first operand is implicit and must be xmm0/ymm0. */ + gas_assert (i.reg_operands + && (operand_type_equal (&i.types[0], ®xmm) + || operand_type_equal (&i.types[0], ®ymm))); if (i.op[0].regs->reg_num != 0) - { - if (intel_syntax) - as_bad (_("the last operand of `%s' must be `%sxmm0'"), - i.tm.name, register_prefix); - else - as_bad (_("the first operand of `%s' must be `%sxmm0'"), - i.tm.name, register_prefix); - return 0; - } + return bad_implicit_operand (i.types[0].bitfield.regxmm); for (j = 1; j < i.operands; j++) { @@ -4363,8 +4660,8 @@ process_operands (void) else first_reg_op = 1; /* Pretend we saw the extra register operand. */ - assert (i.reg_operands == 1 - && i.op[first_reg_op + 1].regs == 0); + gas_assert (i.reg_operands == 1 + && i.op[first_reg_op + 1].regs == 0); i.op[first_reg_op + 1].regs = i.op[first_reg_op].regs; i.types[first_reg_op + 1] = i.types[first_reg_op]; i.operands++; @@ -4379,7 +4676,7 @@ process_operands (void) if (i.tm.base_opcode == POP_SEG_SHORT && i.op[0].regs->reg_num == 1) { - as_bad (_("you can't `pop %%cs'")); + as_bad (_("you can't `pop %scs'"), register_prefix); return 0; } i.tm.base_opcode |= (i.op[0].regs->reg_num << 3); @@ -4388,15 +4685,15 @@ process_operands (void) } else { - /* The register or float register operand is in operand + /* The register or float register operand is in operand 0 or 1. */ unsigned int op; - - if (i.types[0].bitfield.floatreg - || operand_type_check (i.types[0], reg)) - op = 0; - else - op = 1; + + if (i.types[0].bitfield.floatreg + || operand_type_check (i.types[0], reg)) + op = 0; + else + op = 1; /* 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) != 0) @@ -4409,8 +4706,8 @@ process_operands (void) { /* Reversed arguments on faddp, fsubp, etc. */ as_warn (_("translating to `%s %s%s,%s%s'"), i.tm.name, - register_prefix, i.op[1].regs->reg_name, - register_prefix, i.op[0].regs->reg_name); + register_prefix, i.op[!intel_syntax].regs->reg_name, + register_prefix, i.op[intel_syntax].regs->reg_name); } else { @@ -4462,34 +4759,90 @@ static const seg_entry * build_modrm_byte (void) { const seg_entry *default_seg = 0; + unsigned int source, dest; + int vex_3_sources; - /* SSE5 4 operand instructions are encoded in such a way that one of - the inputs must match the destination register. Process_drex hides - the 3rd argument in the drex field, so that by the time we get - here, it looks to GAS as if this is a 2 operand instruction. */ - if ((i.tm.opcode_modifier.drex - || i.tm.opcode_modifier.drexv - || i.tm.opcode_modifier.drexc) - && i.reg_operands == 2) + /* The first operand of instructions with VEX prefix and 3 sources + must be VEX_Imm4. */ + vex_3_sources = i.tm.opcode_modifier.vex3sources; + if (vex_3_sources) { - const reg_entry *reg = i.op[i.drex.modrm_reg].regs; - const reg_entry *regmem = i.op[i.drex.modrm_regmem].regs; + unsigned int nds, reg; - i.rm.reg = reg->reg_num; - i.rm.regmem = regmem->reg_num; - i.rm.mode = 3; - if ((reg->reg_flags & RegRex) != 0) - i.rex |= REX_R; - if ((regmem->reg_flags & RegRex) != 0) - i.rex |= REX_B; + if (i.tm.opcode_modifier.veximmext + && i.tm.opcode_modifier.immext) + { + dest = i.operands - 2; + gas_assert (dest == 3); + } + else + dest = i.operands - 1; + nds = dest - 1; + + /* This instruction must have 4 register operands + or 3 register operands plus 1 memory operand. + It must have VexNDS and VexImmExt. */ + gas_assert ((i.reg_operands == 4 + || (i.reg_operands == 3 && i.mem_operands == 1)) + && i.tm.opcode_modifier.vexnds + && i.tm.opcode_modifier.veximmext + && (operand_type_equal (&i.tm.operand_types[dest], ®xmm) + || operand_type_equal (&i.tm.operand_types[dest], ®ymm))); + + /* Generate an 8bit immediate operand to encode the register + operand. */ + expressionS *exp = &im_expressions[i.imm_operands++]; + i.op[i.operands].imms = exp; + i.types[i.operands] = imm8; + i.operands++; + /* If VexW1 is set, the first operand is the source and + the second operand is encoded in the immediate operand. */ + if (i.tm.opcode_modifier.vexw1) + { + source = 0; + reg = 1; + } + else + { + source = 1; + reg = 0; + } + /* FMA4 swaps REG and NDS. */ + if (i.tm.cpu_flags.bitfield.cpufma4) + { + unsigned int tmp; + tmp = reg; + reg = nds; + nds = tmp; + } + gas_assert ((operand_type_equal (&i.tm.operand_types[reg], ®xmm) + || operand_type_equal (&i.tm.operand_types[reg], + ®ymm)) + && (operand_type_equal (&i.tm.operand_types[nds], ®xmm) + || operand_type_equal (&i.tm.operand_types[nds], + ®ymm))); + exp->X_op = O_constant; + exp->X_add_number + = ((i.op[reg].regs->reg_num + + ((i.op[reg].regs->reg_flags & RegRex) ? 8 : 0)) << 4); + i.vex.register_specifier = i.op[nds].regs; } + else + source = dest = 0; /* i.reg_operands MUST be the number of real register operands; - implicit registers do not count. */ - else if (i.reg_operands == 2) + implicit registers do not count. If there are 3 register + operands, it must be a instruction with VexNDS. For a + instruction with VexNDD, the destination register is encoded + in VEX prefix. If there are 4 register operands, it must be + a instruction with VEX prefix and 3 sources. */ + if (i.mem_operands == 0 + && ((i.reg_operands == 2 + && !i.tm.opcode_modifier.vexndd) + || (i.reg_operands == 3 + && i.tm.opcode_modifier.vexnds) + || (i.reg_operands == 4 && vex_3_sources))) { - unsigned int source, dest; - switch (i.operands) { case 2: @@ -4498,10 +4851,12 @@ build_modrm_byte (void) case 3: /* When there are 3 operands, one of them may be immediate, which may be the first or the last operand. Otherwise, - the first operand must be shift count register (cl). */ - assert (i.imm_operands == 1 - || (i.imm_operands == 0 - && i.types[0].bitfield.shiftcount)); + the first operand must be shift count register (cl) or it + is an instruction with VexNDS. */ + gas_assert (i.imm_operands == 1 + || (i.imm_operands == 0 + && (i.tm.opcode_modifier.vexnds + || i.types[0].bitfield.shiftcount))); if (operand_type_check (i.types[0], imm) || i.types[0].bitfield.shiftcount) source = 1; @@ -4511,17 +4866,54 @@ build_modrm_byte (void) case 4: /* When there are 4 operands, the first two must be 8bit immediate operands. The source operand will be the 3rd - one. */ - assert (i.imm_operands == 2 - && i.types[0].bitfield.imm8 - && i.types[1].bitfield.imm8); - source = 2; + one. + + For instructions with VexNDS, if the first operand + an imm8, the source operand is the 2nd one. If the last + operand is imm8, the source operand is the first one. */ + gas_assert ((i.imm_operands == 2 + && i.types[0].bitfield.imm8 + && i.types[1].bitfield.imm8) + || (i.tm.opcode_modifier.vexnds + && i.imm_operands == 1 + && (i.types[0].bitfield.imm8 + || i.types[i.operands - 1].bitfield.imm8))); + if (i.tm.opcode_modifier.vexnds) + { + if (i.types[0].bitfield.imm8) + source = 1; + else + source = 0; + } + else + source = 2; + break; + case 5: break; default: abort (); } - dest = source + 1; + if (!vex_3_sources) + { + dest = source + 1; + + if (i.tm.opcode_modifier.vexnds) + { + /* For instructions with VexNDS, the register-only + source operand must be XMM or YMM register. It is + encoded in VEX prefix. We need to clear RegMem bit + before calling operand_type_equal. */ + i386_operand_type op = i.tm.operand_types[dest]; + op.bitfield.regmem = 0; + if ((dest + 1) >= i.operands + || (!operand_type_equal (&op, ®xmm) + && !operand_type_equal (&op, ®ymm))) + abort (); + i.vex.register_specifier = i.op[dest].regs; + dest++; + } + } i.rm.mode = 3; /* One of the register operands will be encoded in the i.tm.reg @@ -4560,24 +4952,17 @@ build_modrm_byte (void) } else { /* If it's not 2 reg operands... */ + unsigned int mem; + if (i.mem_operands) { unsigned int fake_zero_displacement = 0; unsigned int op; - /* This has been precalculated for SSE5 instructions - that have a DREX field earlier in process_drex. */ - if (i.tm.opcode_modifier.drex - || i.tm.opcode_modifier.drexv - || i.tm.opcode_modifier.drexc) - op = i.drex.modrm_regmem; - else - { - for (op = 0; op < i.operands; op++) - if (operand_type_check (i.types[op], anymem)) - break; - assert (op < i.operands); - } + for (op = 0; op < i.operands; op++) + if (operand_type_check (i.types[op], anymem)) + break; + gas_assert (op < i.operands); default_seg = &ds; @@ -4691,7 +5076,7 @@ build_modrm_byte (void) && operand_type_check (i.types[op], disp)) { i386_operand_type temp; - UINTS_CLEAR (temp); + operand_type_set (&temp, 0); temp.bitfield.disp8 = i.types[op].bitfield.disp8; i.types[op] = temp; if (i.prefix[ADDR_PREFIX] == 0) @@ -4755,7 +5140,7 @@ build_modrm_byte (void) holds the correct displacement size. */ expressionS *exp; - assert (i.op[op].disps == 0); + gas_assert (i.op[op].disps == 0); exp = &disp_expressions[i.disp_operands++]; i.op[op].disps = exp; exp->X_op = O_constant; @@ -4763,7 +5148,11 @@ build_modrm_byte (void) exp->X_add_symbol = (symbolS *) 0; exp->X_op_symbol = (symbolS *) 0; } + + mem = op; } + else + mem = ~0; /* Fill in i.rm.reg or i.rm.regmem field with register operand (if any) based on i.tm.extension_opcode. Again, we must be @@ -4772,51 +5161,80 @@ build_modrm_byte (void) if (i.reg_operands) { unsigned int op; + unsigned int vex_reg = ~0; + + for (op = 0; op < i.operands; op++) + if (i.types[op].bitfield.reg8 + || i.types[op].bitfield.reg16 + || i.types[op].bitfield.reg32 + || i.types[op].bitfield.reg64 + || i.types[op].bitfield.regmmx + || i.types[op].bitfield.regxmm + || i.types[op].bitfield.regymm + || i.types[op].bitfield.sreg2 + || i.types[op].bitfield.sreg3 + || i.types[op].bitfield.control + || i.types[op].bitfield.debug + || i.types[op].bitfield.test) + break; - /* This has been precalculated for SSE5 instructions - that have a DREX field earlier in process_drex. */ - if (i.tm.opcode_modifier.drex - || i.tm.opcode_modifier.drexv - || i.tm.opcode_modifier.drexc) - { - op = i.drex.modrm_reg; - i.rm.reg = i.op[op].regs->reg_num; - if ((i.op[op].regs->reg_flags & RegRex) != 0) - i.rex |= REX_R; - } - else + if (vex_3_sources) + op = dest; + else if (i.tm.opcode_modifier.vexnds) { - for (op = 0; op < i.operands; op++) - if (i.types[op].bitfield.reg8 - || i.types[op].bitfield.reg16 - || i.types[op].bitfield.reg32 - || i.types[op].bitfield.reg64 - || i.types[op].bitfield.regmmx - || i.types[op].bitfield.regxmm - || i.types[op].bitfield.sreg2 - || i.types[op].bitfield.sreg3 - || i.types[op].bitfield.control - || i.types[op].bitfield.debug - || i.types[op].bitfield.test) - break; + /* For instructions with VexNDS, the register-only + source operand is encoded in VEX prefix. */ + gas_assert (mem != (unsigned int) ~0); - assert (op < i.operands); - - /* If there is an extension opcode to put here, the - register number must be put into the regmem field. */ - if (i.tm.extension_opcode != None) + if (op > mem) { - i.rm.regmem = i.op[op].regs->reg_num; - if ((i.op[op].regs->reg_flags & RegRex) != 0) - i.rex |= REX_B; + vex_reg = op++; + gas_assert (op < i.operands); } else { - i.rm.reg = i.op[op].regs->reg_num; - if ((i.op[op].regs->reg_flags & RegRex) != 0) - i.rex |= REX_R; + vex_reg = op + 1; + gas_assert (vex_reg < i.operands); } } + else if (i.tm.opcode_modifier.vexndd) + { + /* For instructions with VexNDD, there should be + no memory operand and the register destination + is encoded in VEX prefix. */ + gas_assert (i.mem_operands == 0 + && (op + 2) == i.operands); + vex_reg = op + 1; + } + else + gas_assert (op < i.operands); + + if (vex_reg != (unsigned int) ~0) + { + gas_assert (i.reg_operands == 2); + + if (!operand_type_equal (&i.tm.operand_types[vex_reg], + & regxmm) + && !operand_type_equal (&i.tm.operand_types[vex_reg], + ®ymm)) + abort (); + i.vex.register_specifier = i.op[vex_reg].regs; + } + + /* If there is an extension opcode to put here, the + register number must be put into the regmem field. */ + if (i.tm.extension_opcode != None) + { + i.rm.regmem = i.op[op].regs->reg_num; + if ((i.op[op].regs->reg_flags & RegRex) != 0) + i.rex |= REX_B; + } + else + { + i.rm.reg = i.op[op].regs->reg_num; + if ((i.op[op].regs->reg_flags & RegRex) != 0) + i.rex |= REX_R; + } /* Now, if no memory operand has set i.rm.mode = 0, 1, 2 we must set it to 3 to indicate this is a register operand @@ -4826,10 +5244,7 @@ build_modrm_byte (void) } /* Fill in i.rm.reg field with extension opcode (if any). */ - if (i.tm.extension_opcode != None - && !(i.tm.opcode_modifier.drex - || i.tm.opcode_modifier.drexv - || i.tm.opcode_modifier.drexc)) + if (i.tm.extension_opcode != None) i.rm.reg = i.tm.extension_opcode; } return default_seg; @@ -5073,40 +5488,71 @@ output_insn (void) unsigned int j; unsigned int prefix; - switch (i.tm.opcode_length) + /* Since the VEX prefix contains the implicit prefix, we don't + need the explicit prefix. */ + if (!i.tm.opcode_modifier.vex) { - case 3: - if (i.tm.base_opcode & 0xff000000) - { - prefix = (i.tm.base_opcode >> 24) & 0xff; - goto check_prefix; - } - break; - case 2: - if ((i.tm.base_opcode & 0xff0000) != 0) + switch (i.tm.opcode_length) { - prefix = (i.tm.base_opcode >> 16) & 0xff; - if (i.tm.cpu_flags.bitfield.cpupadlock) + case 3: + if (i.tm.base_opcode & 0xff000000) + { + prefix = (i.tm.base_opcode >> 24) & 0xff; + goto check_prefix; + } + break; + case 2: + if ((i.tm.base_opcode & 0xff0000) != 0) { + prefix = (i.tm.base_opcode >> 16) & 0xff; + if (i.tm.cpu_flags.bitfield.cpupadlock) + { check_prefix: - if (prefix != REPE_PREFIX_OPCODE - || i.prefix[LOCKREP_PREFIX] != REPE_PREFIX_OPCODE) + if (prefix != REPE_PREFIX_OPCODE + || (i.prefix[LOCKREP_PREFIX] + != REPE_PREFIX_OPCODE)) + add_prefix (prefix); + } + else add_prefix (prefix); } - else - add_prefix (prefix); + break; + case 1: + break; + default: + abort (); } - break; - case 1: - break; - default: - abort (); + + /* The prefix bytes. */ + for (j = ARRAY_SIZE (i.prefix), q = i.prefix; j > 0; j--, q++) + if (*q) + FRAG_APPEND_1_CHAR (*q); } - /* The prefix bytes. */ - for (j = ARRAY_SIZE (i.prefix), q = i.prefix; j > 0; j--, q++) - if (*q) - FRAG_APPEND_1_CHAR (*q); + if (i.tm.opcode_modifier.vex) + { + for (j = 0, q = i.prefix; j < ARRAY_SIZE (i.prefix); j++, q++) + if (*q) + switch (j) + { + case REX_PREFIX: + /* REX byte is encoded in VEX prefix. */ + break; + case SEG_PREFIX: + case ADDR_PREFIX: + FRAG_APPEND_1_CHAR (*q); + break; + default: + /* There should be no other prefixes for instructions + with VEX prefix. */ + abort (); + } + + /* Now the VEX prefix. */ + p = frag_more (i.vex.length); + for (j = 0; j < i.vex.length; j++) + p[j] = i.vex.bytes[j]; + } /* Now the opcode; be careful about word order here! */ if (i.tm.opcode_length == 1) @@ -5132,13 +5578,6 @@ check_prefix: /* Put out high byte first: can't use md_number_to_chars! */ *p++ = (i.tm.base_opcode >> 8) & 0xff; *p = i.tm.base_opcode & 0xff; - - /* On SSE5, encode the OC1 bit in the DREX field if this - encoding has multiple formats. */ - if (i.tm.opcode_modifier.drex - && i.tm.opcode_modifier.drexv - && DREX_OC1 (i.tm.extension_opcode)) - *p |= DREX_OC1_MASK; } /* Now the modrm byte and sib byte (if present). */ @@ -5159,20 +5598,6 @@ check_prefix: | i.sib.scale << 6)); } - /* Write the DREX byte if needed. */ - if (i.tm.opcode_modifier.drex || i.tm.opcode_modifier.drexc) - { - p = frag_more (1); - *p = (((i.drex.reg & 0xf) << 4) | (i.drex.rex & 0x7)); - - /* Encode the OC0 bit if this encoding has multiple - formats. */ - if ((i.tm.opcode_modifier.drex - || i.tm.opcode_modifier.drexv) - && DREX_OC0 (i.tm.extension_opcode)) - *p |= DREX_OC0_MASK; - } - if (i.disp_operands) output_disp (insn_start_frag, insn_start_off); @@ -5246,7 +5671,7 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off) int pcrel = (i.flags[n] & Operand_PCrel) != 0; /* We can't have 8 bit displacement here. */ - assert (!i.types[n].bitfield.disp8); + gas_assert (!i.types[n].bitfield.disp8); /* The PC relative address is computed relative to the instruction boundary, so in case immediate @@ -5261,12 +5686,12 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off) { /* Only one immediate is allowed for PC relative address. */ - assert (sz == 0); + gas_assert (sz == 0); sz = imm_size (n1); i.op[n].disps->X_add_number -= sz; } /* We should find the immediate. */ - assert (sz != 0); + gas_assert (sz != 0); } p = frag_more (size); @@ -5528,7 +5953,7 @@ lex_got (enum bfd_reloc_code_real *reloc, OPERAND_TYPE_NONE }, { "DTPOFF", { BFD_RELOC_386_TLS_LDO_32, BFD_RELOC_X86_64_DTPOFF32 }, - + OPERAND_TYPE_IMM32_32S_64_DISP32_64 }, { "GOTNTPOFF",{ BFD_RELOC_386_TLS_GOTIE, 0 }, @@ -5623,6 +6048,8 @@ lex_got (enum bfd_reloc_code_real *reloc, void x86_cons (expressionS *exp, int size) { + intel_syntax = -intel_syntax; + if (size == 4 || (object_64bit && size == 8)) { /* Handle @GOTOFF and the like in an expression. */ @@ -5661,6 +6088,11 @@ x86_cons (expressionS *exp, int size) } else expression (exp); + + intel_syntax = -intel_syntax; + + if (intel_syntax) + i386_intel_simplify (exp); } #endif @@ -5703,7 +6135,7 @@ i386_immediate (char *imm_start) expressionS *exp; i386_operand_type types; - UINTS_SET (types, ~0); + operand_type_set (&types, ~0); if (i.imm_operands == MAX_IMMEDIATE_OPERANDS) { @@ -5733,14 +6165,21 @@ i386_immediate (char *imm_start) input_line_pointer = save_input_line_pointer; if (gotfree_input_line) - free (gotfree_input_line); + { + free (gotfree_input_line); + + if (exp->X_op == O_constant || exp->X_op == O_register) + exp->X_op = O_illegal; + } + + return i386_finalize_immediate (exp_seg, exp, types, imm_start); +} - if (exp->X_op == O_absent - || exp->X_op == O_illegal - || exp->X_op == O_big - || (gotfree_input_line - && (exp->X_op == O_constant - || exp->X_op == O_register))) +static int +i386_finalize_immediate (segT exp_seg ATTRIBUTE_UNUSED, expressionS *exp, + i386_operand_type types, const char *imm_start) +{ + if (exp->X_op == O_absent || exp->X_op == O_illegal || exp->X_op == O_big) { as_bad (_("missing or invalid immediate expression `%s'"), imm_start); @@ -5855,7 +6294,7 @@ i386_displacement (char *disp_start, char *disp_end) return 0; } - UINTS_CLEAR (bigdisp); + operand_type_set (&bigdisp, 0); if ((i.types[this_operand].bitfield.jumpabsolute) || (!current_templates->start->opcode_modifier.jump && !current_templates->start->opcode_modifier.jumpdword)) @@ -5973,8 +6412,26 @@ i386_displacement (char *disp_start, char *disp_end) #endif input_line_pointer = save_input_line_pointer; if (gotfree_input_line) - free (gotfree_input_line); - ret = 1; + { + free (gotfree_input_line); + + if (exp->X_op == O_constant || exp->X_op == O_register) + exp->X_op = O_illegal; + } + + ret = i386_finalize_displacement (exp_seg, exp, types, disp_start); + + RESTORE_END_STRING (disp_end); + + return ret; +} + +static int +i386_finalize_displacement (segT exp_seg ATTRIBUTE_UNUSED, expressionS *exp, + i386_operand_type types, const char *disp_start) +{ + i386_operand_type bigdisp; + int ret = 1; /* We do this to make sure that the section symbol is in the symbol table. We will ultimately change the relocation @@ -6001,10 +6458,7 @@ i386_displacement (char *disp_start, char *disp_end) else if (exp->X_op == O_absent || exp->X_op == O_illegal - || exp->X_op == O_big - || (gotfree_input_line - && (exp->X_op == O_constant - || exp->X_op == O_register))) + || exp->X_op == O_big) { inv_disp: as_bad (_("missing or invalid displacement expression `%s'"), @@ -6027,8 +6481,6 @@ i386_displacement (char *disp_start, char *disp_end) } #endif - RESTORE_END_STRING (disp_end); - /* Check if this is a displacement only operand. */ bigdisp = i.types[this_operand]; bigdisp.bitfield.disp8 = 0; @@ -6036,7 +6488,7 @@ i386_displacement (char *disp_start, char *disp_end) bigdisp.bitfield.disp32 = 0; bigdisp.bitfield.disp32s = 0; bigdisp.bitfield.disp64 = 0; - if (UINTS_ALL_ZERO (bigdisp)) + if (operand_type_all_zero (&bigdisp)) i.types[this_operand] = operand_type_and (i.types[this_operand], types); @@ -6050,13 +6502,77 @@ static int i386_index_check (const char *operand_string) { int ok; + const char *kind = "base/index"; #if INFER_ADDR_PREFIX int fudged = 0; tryprefix: #endif ok = 1; - if (flag_code == CODE_64BIT) + if (current_templates->start->opcode_modifier.isstring + && !current_templates->start->opcode_modifier.immext + && (current_templates->end[-1].opcode_modifier.isstring + || i.mem_operands)) + { + /* Memory operands of string insns are special in that they only allow + a single register (rDI, rSI, or rBX) as their memory address. */ + unsigned int expected; + + kind = "string address"; + + if (current_templates->start->opcode_modifier.w) + { + i386_operand_type type = current_templates->end[-1].operand_types[0]; + + if (!type.bitfield.baseindex + || ((!i.mem_operands != !intel_syntax) + && current_templates->end[-1].operand_types[1] + .bitfield.baseindex)) + type = current_templates->end[-1].operand_types[1]; + expected = type.bitfield.esseg ? 7 /* rDI */ : 6 /* rSI */; + } + else + expected = 3 /* rBX */; + + if (!i.base_reg || i.index_reg + || operand_type_check (i.types[this_operand], disp)) + ok = -1; + else if (!(flag_code == CODE_64BIT + ? i.prefix[ADDR_PREFIX] + ? i.base_reg->reg_type.bitfield.reg32 + : i.base_reg->reg_type.bitfield.reg64 + : (flag_code == CODE_16BIT) ^ !i.prefix[ADDR_PREFIX] + ? i.base_reg->reg_type.bitfield.reg32 + : i.base_reg->reg_type.bitfield.reg16)) + ok = 0; + else if (i.base_reg->reg_num != expected) + ok = -1; + + if (ok < 0) + { + unsigned int j; + + for (j = 0; j < i386_regtab_size; ++j) + if ((flag_code == CODE_64BIT + ? i.prefix[ADDR_PREFIX] + ? i386_regtab[j].reg_type.bitfield.reg32 + : i386_regtab[j].reg_type.bitfield.reg64 + : (flag_code == CODE_16BIT) ^ !i.prefix[ADDR_PREFIX] + ? i386_regtab[j].reg_type.bitfield.reg32 + : i386_regtab[j].reg_type.bitfield.reg16) + && i386_regtab[j].reg_num == expected) + break; + gas_assert (j < i386_regtab_size); + as_warn (_("`%s' is not valid here (expected `%c%s%s%c')"), + operand_string, + intel_syntax ? '[' : '(', + register_prefix, + i386_regtab[j].reg_name, + intel_syntax ? ']' : ')'); + ok = 1; + } + } + else if (flag_code == CODE_64BIT) { if ((i.base_reg && ((i.prefix[ADDR_PREFIX] == 0 @@ -6109,7 +6625,7 @@ i386_index_check (const char *operand_string) if (!ok) { #if INFER_ADDR_PREFIX - if (i.prefix[ADDR_PREFIX] == 0) + if (!i.mem_operands && !i.prefix[ADDR_PREFIX]) { i.prefix[ADDR_PREFIX] = ADDR_PREFIX_OPCODE; i.prefixes += 1; @@ -6127,18 +6643,24 @@ i386_index_check (const char *operand_string) goto tryprefix; } if (fudged) - as_bad (_("`%s' is not a valid base/index expression"), - operand_string); + as_bad (_("`%s' is not a valid %s expression"), + operand_string, + kind); else #endif - as_bad (_("`%s' is not a valid %s bit base/index expression"), + as_bad (_("`%s' is not a valid %s-bit %s expression"), operand_string, - flag_code_names[flag_code]); + flag_code_names[i.prefix[ADDR_PREFIX] + ? flag_code == CODE_32BIT + ? CODE_16BIT + : CODE_32BIT + : flag_code], + kind); } return ok; } -/* Parse OPERAND_STRING into the i386_insn structure I. Returns non-zero +/* Parse OPERAND_STRING into the i386_insn structure I. Returns zero on error. */ static int @@ -6409,14 +6931,14 @@ i386_att_operand (char *operand_string) /* Special case for (%dx) while doing input/output op. */ if (i.base_reg - && UINTS_EQUAL (i.base_reg->reg_type, reg16_inoutportreg) + && operand_type_equal (&i.base_reg->reg_type, + ®16_inoutportreg) && i.index_reg == 0 && i.log2_scale_factor == 0 && i.seg[i.mem_operands] == 0 && !operand_type_check (i.types[this_operand], disp)) { - UINTS_CLEAR (i.types[this_operand]); - i.types[this_operand].bitfield.inoutportreg = 1; + i.types[this_operand] = inoutportreg; return 1; } @@ -6463,7 +6985,13 @@ md_estimate_size_before_relax (fragP, segment) #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || (IS_ELF && (S_IS_EXTERNAL (fragP->fr_symbol) - || S_IS_WEAK (fragP->fr_symbol))) + || S_IS_WEAK (fragP->fr_symbol) + || ((symbol_get_bfdsym (fragP->fr_symbol)->flags + & BSF_GNU_INDIRECT_FUNCTION)))) +#endif +#if defined (OBJ_COFF) && defined (TE_PE) + || (OUTPUT_FLAVOR == bfd_target_coff_flavour + && S_IS_WEAK (fragP->fr_symbol)) #endif ) { @@ -6740,7 +7268,7 @@ md_apply_fix (fixP, valP, seg) if ((sym_seg == seg || (symbol_section_p (fixP->fx_addsy) && sym_seg != absolute_section)) - && !generic_force_reloc (fixP)) + && !TC_FORCE_RELOCATION (fixP)) { /* Yes, we add the values in twice. This is because bfd_install_relocation subtracts them out again. I think @@ -6758,6 +7286,12 @@ md_apply_fix (fixP, valP, seg) value += md_pcrel_from (fixP); #endif } +#if defined (OBJ_COFF) && defined (TE_PE) + if (fixP->fx_addsy != NULL && S_IS_WEAK (fixP->fx_addsy)) + { + value -= S_GET_VALUE (fixP->fx_addsy); + } +#endif /* Fix a few things - the dynamic linker expects certain values here, and we must not disappoint it. */ @@ -6821,6 +7355,16 @@ md_apply_fix (fixP, valP, seg) /* Are we finished with this relocation now? */ if (fixP->fx_addsy == NULL) fixP->fx_done = 1; +#if defined (OBJ_COFF) && defined (TE_PE) + else if (fixP->fx_addsy != NULL && S_IS_WEAK (fixP->fx_addsy)) + { + fixP->fx_done = 0; + /* Remember value for tc_gen_reloc. */ + fixP->fx_addnumber = value; + /* Clear out the frag for now. */ + value = 0; + } +#endif else if (use_rela_relocations) { fixP->fx_no_overflow = 1; @@ -6918,20 +7462,44 @@ parse_real_register (char *reg_string, char **end_op) } } + if (r == NULL || allow_pseudo_reg) + return r; + + if (operand_type_all_zero (&r->reg_type)) + return (const reg_entry *) NULL; + + if ((r->reg_type.bitfield.reg32 + || r->reg_type.bitfield.sreg3 + || r->reg_type.bitfield.control + || r->reg_type.bitfield.debug + || r->reg_type.bitfield.test) + && !cpu_arch_flags.bitfield.cpui386) + return (const reg_entry *) NULL; + + if (r->reg_type.bitfield.regmmx && !cpu_arch_flags.bitfield.cpummx) + return (const reg_entry *) NULL; + + if (r->reg_type.bitfield.regxmm && !cpu_arch_flags.bitfield.cpusse) + return (const reg_entry *) NULL; + + if (r->reg_type.bitfield.regymm && !cpu_arch_flags.bitfield.cpuavx) + return (const reg_entry *) NULL; + /* Don't allow fake index register unless allow_index_reg isn't 0. */ - if (r != NULL - && !allow_index_reg + if (!allow_index_reg && (r->reg_num == RegEiz || r->reg_num == RegRiz)) return (const reg_entry *) NULL; - if (r != NULL - && ((r->reg_flags & (RegRex64 | RegRex)) - || r->reg_type.bitfield.reg64) + if (((r->reg_flags & (RegRex64 | RegRex)) + || r->reg_type.bitfield.reg64) && (!cpu_arch_flags.bitfield.cpulm - || !UINTS_EQUAL (r->reg_type, control)) + || !operand_type_equal (&r->reg_type, &control)) && flag_code != CODE_64BIT) return (const reg_entry *) NULL; + if (r->reg_type.bitfield.sreg3 && r->reg_num == RegFlat && !intel_syntax) + return (const reg_entry *) NULL; + return r; } @@ -6989,23 +7557,45 @@ i386_parse_name (char *name, expressionS *e, char *nextcharP) } input_line_pointer = end; *end = 0; - return 0; + return intel_syntax ? i386_intel_parse_name (name, e) : 0; } void md_operand (expressionS *e) { - if (*input_line_pointer == REGISTER_PREFIX) - { - char *end; - const reg_entry *r = parse_real_register (input_line_pointer, &end); + char *end; + const reg_entry *r; + switch (*input_line_pointer) + { + case REGISTER_PREFIX: + r = parse_real_register (input_line_pointer, &end); if (r) { e->X_op = O_register; e->X_add_number = r - i386_regtab; input_line_pointer = end; } + break; + + case '[': + gas_assert (intel_syntax); + end = input_line_pointer++; + expression (e); + if (*input_line_pointer == ']') + { + ++input_line_pointer; + e->X_op_symbol = make_expr_symbol (e); + e->X_add_symbol = NULL; + e->X_add_number = 0; + e->X_op = O_index; + } + else + { + e->X_op = O_absent; + input_line_pointer = end; + } + break; } } @@ -7026,11 +7616,14 @@ const char *md_shortopts = "qn"; #define OPTION_MINDEX_REG (OPTION_MD_BASE + 7) #define OPTION_MNAKED_REG (OPTION_MD_BASE + 8) #define OPTION_MOLD_GCC (OPTION_MD_BASE + 9) +#define OPTION_MSSE2AVX (OPTION_MD_BASE + 10) +#define OPTION_MSSE_CHECK (OPTION_MD_BASE + 11) struct option md_longopts[] = { {"32", no_argument, NULL, OPTION_32}, -#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || defined(TE_PEP) +#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \ + || defined (TE_PE) || defined (TE_PEP)) {"64", no_argument, NULL, OPTION_64}, #endif {"divide", no_argument, NULL, OPTION_DIVIDE}, @@ -7041,6 +7634,8 @@ struct option md_longopts[] = {"mindex-reg", no_argument, NULL, OPTION_MINDEX_REG}, {"mnaked-reg", no_argument, NULL, OPTION_MNAKED_REG}, {"mold-gcc", no_argument, NULL, OPTION_MOLD_GCC}, + {"msse2avx", no_argument, NULL, OPTION_MSSE2AVX}, + {"msse-check", required_argument, NULL, OPTION_MSSE_CHECK}, {NULL, no_argument, NULL, 0} }; size_t md_longopts_size = sizeof (md_longopts); @@ -7049,6 +7644,7 @@ int md_parse_option (int c, char *arg) { unsigned int i; + char *arch, *next; switch (c) { @@ -7080,7 +7676,8 @@ md_parse_option (int c, char *arg) .stab instead of .stab.excl. We always use .stab anyhow. */ break; #endif -#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || defined(TE_PEP) +#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \ + || defined (TE_PE) || defined (TE_PEP)) case OPTION_64: { const char **list, **l; @@ -7124,25 +7721,63 @@ md_parse_option (int c, char *arg) break; case OPTION_MARCH: - if (*arg == '.') - as_fatal (_("Invalid -march= option: `%s'"), arg); - for (i = 0; i < ARRAY_SIZE (cpu_arch); i++) - { - if (strcmp (arg, cpu_arch [i].name) == 0) + arch = xstrdup (arg); + do + { + if (*arch == '.') + as_fatal (_("Invalid -march= option: `%s'"), arg); + next = strchr (arch, '+'); + if (next) + *next++ = '\0'; + for (i = 0; i < ARRAY_SIZE (cpu_arch); i++) { - cpu_arch_isa = cpu_arch[i].type; - cpu_arch_isa_flags = cpu_arch[i].flags; - if (!cpu_arch_tune_set) + if (strcmp (arch, cpu_arch [i].name) == 0) { - cpu_arch_tune = cpu_arch_isa; - cpu_arch_tune_flags = cpu_arch_isa_flags; + /* Processor. */ + cpu_arch_name = cpu_arch[i].name; + cpu_sub_arch_name = NULL; + cpu_arch_flags = cpu_arch[i].flags; + cpu_arch_isa = cpu_arch[i].type; + cpu_arch_isa_flags = cpu_arch[i].flags; + if (!cpu_arch_tune_set) + { + cpu_arch_tune = cpu_arch_isa; + cpu_arch_tune_flags = cpu_arch_isa_flags; + } + break; } - break; - } - } - if (i >= ARRAY_SIZE (cpu_arch)) - as_fatal (_("Invalid -march= option: `%s'"), arg); - break; + else if (*cpu_arch [i].name == '.' + && strcmp (arch, cpu_arch [i].name + 1) == 0) + { + /* ISA entension. */ + i386_cpu_flags flags; + flags = cpu_flags_or (cpu_arch_flags, + cpu_arch[i].flags); + if (!cpu_flags_equal (&flags, &cpu_arch_flags)) + { + if (cpu_sub_arch_name) + { + char *name = cpu_sub_arch_name; + cpu_sub_arch_name = concat (name, + cpu_arch[i].name, + (const char *) NULL); + free (name); + } + else + cpu_sub_arch_name = xstrdup (cpu_arch[i].name); + cpu_arch_flags = flags; + } + break; + } + } + + if (i >= ARRAY_SIZE (cpu_arch)) + as_fatal (_("Invalid -march= option: `%s'"), arg); + + arch = next; + } + while (next != NULL ); + break; case OPTION_MTUNE: if (*arg == '.') @@ -7191,6 +7826,21 @@ md_parse_option (int c, char *arg) old_gcc = 1; break; + case OPTION_MSSE2AVX: + sse2avx = 1; + break; + + case OPTION_MSSE_CHECK: + if (strcasecmp (arg, "error") == 0) + sse_check = sse_check_error; + else if (strcasecmp (arg, "warning") == 0) + sse_check = sse_check_warning; + else if (strcasecmp (arg, "none") == 0) + sse_check = sse_check_none; + else + as_fatal (_("Invalid -msse-check= option: `%s'"), arg); + break; + default: return 0; } @@ -7214,7 +7864,8 @@ md_show_usage (stream) fprintf (stream, _("\ -s ignored\n")); #endif -#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || defined(TE_PEP) +#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \ + || defined (TE_PE) || defined (TE_PEP)) fprintf (stream, _("\ --32/--64 generate 32bit/64bit code\n")); #endif @@ -7226,9 +7877,28 @@ md_show_usage (stream) --divide ignored\n")); #endif fprintf (stream, _("\ - -march=CPU/-mtune=CPU generate code/optimize for CPU, where CPU is one of:\n\ - i386, i486, pentium, pentiumpro, pentium4, nocona,\n\ - core, core2, k6, athlon, k8, generic32, generic64\n")); + -march=CPU[,+EXTENSION...]\n\ + generate code for CPU and EXTENSION, CPU is one of:\n\ + i8086, i186, i286, i386, i486, pentium, pentiumpro,\n\ + pentiumii, pentiumiii, pentium4, prescott, nocona,\n\ + core, core2, corei7, k6, k6_2, athlon, k8, amdfam10,\n\ + generic32, generic64\n\ + EXTENSION is combination of:\n\ + mmx, sse, sse2, sse3, ssse3, sse4.1, sse4.2, sse4,\n\ + avx, vmx, smx, xsave, movbe, ept, aes, pclmul, fma,\n\ + clflush, syscall, rdtscp, 3dnow, 3dnowa, sse4a,\n\ + svme, abm, padlock, fma4\n")); + fprintf (stream, _("\ + -mtune=CPU optimize for CPU, CPU is one of:\n\ + i8086, i186, i286, i386, i486, pentium, pentiumpro,\n\ + pentiumii, pentiumiii, pentium4, prescott, nocona,\n\ + core, core2, corei7, k6, k6_2, athlon, k8, amdfam10,\n\ + generic32, generic64\n")); + fprintf (stream, _("\ + -msse2avx encode SSE instructions with VEX prefix\n")); + fprintf (stream, _("\ + -msse-check=[none|error|warning]\n\ + check SSE instructions\n")); fprintf (stream, _("\ -mmnemonic=[att|intel] use AT&T/Intel mnemonic\n")); fprintf (stream, _("\ @@ -7242,7 +7912,8 @@ md_show_usage (stream) } #if ((defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT)) \ - || defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || defined (TE_PEP)) + || defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \ + || defined (TE_PE) || defined (TE_PEP) || defined (OBJ_MACH_O)) /* Pick the target format to use. */ @@ -7252,7 +7923,7 @@ i386_target_format (void) if (!strcmp (default_arch, "x86_64")) { set_code_flag (CODE_64BIT); - if (UINTS_ALL_ZERO (cpu_arch_isa_flags)) + if (cpu_flags_all_zero (&cpu_arch_isa_flags)) { cpu_arch_isa_flags.bitfield.cpui186 = 1; cpu_arch_isa_flags.bitfield.cpui286 = 1; @@ -7260,13 +7931,12 @@ i386_target_format (void) cpu_arch_isa_flags.bitfield.cpui486 = 1; cpu_arch_isa_flags.bitfield.cpui586 = 1; cpu_arch_isa_flags.bitfield.cpui686 = 1; - cpu_arch_isa_flags.bitfield.cpup4 = 1; + cpu_arch_isa_flags.bitfield.cpuclflush = 1; cpu_arch_isa_flags.bitfield.cpummx= 1; - cpu_arch_isa_flags.bitfield.cpummx2 = 1; cpu_arch_isa_flags.bitfield.cpusse = 1; cpu_arch_isa_flags.bitfield.cpusse2 = 1; } - if (UINTS_ALL_ZERO (cpu_arch_tune_flags)) + if (cpu_flags_all_zero (&cpu_arch_tune_flags)) { cpu_arch_tune_flags.bitfield.cpui186 = 1; cpu_arch_tune_flags.bitfield.cpui286 = 1; @@ -7274,9 +7944,8 @@ i386_target_format (void) cpu_arch_tune_flags.bitfield.cpui486 = 1; cpu_arch_tune_flags.bitfield.cpui586 = 1; cpu_arch_tune_flags.bitfield.cpui686 = 1; - cpu_arch_tune_flags.bitfield.cpup4 = 1; + cpu_arch_tune_flags.bitfield.cpuclflush = 1; cpu_arch_tune_flags.bitfield.cpummx= 1; - cpu_arch_tune_flags.bitfield.cpummx2 = 1; cpu_arch_tune_flags.bitfield.cpusse = 1; cpu_arch_tune_flags.bitfield.cpusse2 = 1; } @@ -7284,13 +7953,13 @@ i386_target_format (void) else if (!strcmp (default_arch, "i386")) { set_code_flag (CODE_32BIT); - if (UINTS_ALL_ZERO (cpu_arch_isa_flags)) + if (cpu_flags_all_zero (&cpu_arch_isa_flags)) { cpu_arch_isa_flags.bitfield.cpui186 = 1; cpu_arch_isa_flags.bitfield.cpui286 = 1; cpu_arch_isa_flags.bitfield.cpui386 = 1; } - if (UINTS_ALL_ZERO (cpu_arch_tune_flags)) + if (cpu_flags_all_zero (&cpu_arch_tune_flags)) { cpu_arch_tune_flags.bitfield.cpui186 = 1; cpu_arch_tune_flags.bitfield.cpui286 = 1; @@ -7301,10 +7970,9 @@ i386_target_format (void) as_fatal (_("Unknown architecture")); switch (OUTPUT_FLAVOR) { -#ifdef TE_PEP +#if defined (TE_PE) || defined (TE_PEP) case bfd_target_coff_flavour: - return flag_code == CODE_64BIT ? COFF_TARGET_FORMAT : "coff-i386"; - break; + return flag_code == CODE_64BIT ? "pe-x86-64" : "pe-i386"; #endif #ifdef OBJ_MAYBE_AOUT case bfd_target_aout_flavour: @@ -7324,6 +7992,10 @@ i386_target_format (void) } return flag_code == CODE_64BIT ? ELF_TARGET_FORMAT64 : ELF_TARGET_FORMAT; } +#endif +#if defined (OBJ_MACH_O) + case bfd_target_mach_o_flavour: + return flag_code == CODE_64BIT ? "mach-o-x86-64" : "mach-o-i386"; #endif default: abort (); @@ -7599,7 +8271,11 @@ tc_gen_reloc (section, fixp) vtable entry to be used in the relocation's section offset. */ if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) rel->address = fixp->fx_offset; - +#if defined (OBJ_COFF) && defined (TE_PE) + else if (fixp->fx_addsy && S_IS_WEAK (fixp->fx_addsy)) + rel->addend = fixp->fx_addnumber - (S_GET_VALUE (fixp->fx_addsy) * 2); + else +#endif rel->addend = 0; } /* Use the rela in 64bit mode. */ @@ -7637,1389 +8313,62 @@ tc_gen_reloc (section, fixp) bfd_get_reloc_code_name (code)); /* Set howto to a garbage value so that we can keep going. */ rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32); - assert (rel->howto != NULL); + gas_assert (rel->howto != NULL); } return rel; } - -/* Parse operands using Intel syntax. This implements a recursive descent - parser based on the BNF grammar published in Appendix B of the MASM 6.1 - Programmer's Guide. - - FIXME: We do not recognize the full operand grammar defined in the MASM - documentation. In particular, all the structure/union and - high-level macro operands are missing. - - Uppercase words are terminals, lower case words are non-terminals. - Objects surrounded by double brackets '[[' ']]' are optional. Vertical - bars '|' denote choices. Most grammar productions are implemented in - functions called 'intel_'. - - Initial production is 'expr'. - - addOp + | - - - alpha [a-zA-Z] - - binOp & | AND | \| | OR | ^ | XOR - - byteRegister AL | AH | BL | BH | CL | CH | DL | DH - - constant digits [[ radixOverride ]] - - dataType BYTE | WORD | DWORD | FWORD | QWORD | TBYTE | OWORD | XMMWORD - - digits decdigit - | digits decdigit - | digits hexdigit - - decdigit [0-9] - - e04 e04 addOp e05 - | e05 - - e05 e05 binOp e06 - | e06 - - e06 e06 mulOp e09 - | e09 - - e09 OFFSET e10 - | SHORT e10 - | + e10 - | - e10 - | ~ e10 - | NOT e10 - | e09 PTR e10 - | e09 : e10 - | e10 - - e10 e10 [ expr ] - | e11 - - e11 ( expr ) - | [ expr ] - | constant - | dataType - | id - | $ - | register - - => expr expr cmpOp e04 - | e04 - - gpRegister AX | EAX | BX | EBX | CX | ECX | DX | EDX - | BP | EBP | SP | ESP | DI | EDI | SI | ESI - - hexdigit a | b | c | d | e | f - | A | B | C | D | E | F - - id alpha - | id alpha - | id decdigit - - mulOp * | / | % | MOD | << | SHL | >> | SHR - - quote " | ' - - register specialRegister - | gpRegister - | byteRegister - - segmentRegister CS | DS | ES | FS | GS | SS - - specialRegister CR0 | CR2 | CR3 | CR4 - | DR0 | DR1 | DR2 | DR3 | DR6 | DR7 - | TR3 | TR4 | TR5 | TR6 | TR7 - - We simplify the grammar in obvious places (e.g., register parsing is - done by calling parse_register) and eliminate immediate left recursion - to implement a recursive-descent parser. - - expr e04 expr' - - expr' cmpOp e04 expr' - | Empty - - e04 e05 e04' - - e04' addOp e05 e04' - | Empty - - e05 e06 e05' - - e05' binOp e06 e05' - | Empty - - e06 e09 e06' - - e06' mulOp e09 e06' - | Empty - - e09 OFFSET e10 e09' - | SHORT e10' - | + e10' - | - e10' - | ~ e10' - | NOT e10' - | e10 e09' - - e09' PTR e10 e09' - | : e10 e09' - | Empty - - e10 e11 e10' - - e10' [ expr ] e10' - | Empty - - e11 ( expr ) - | [ expr ] - | BYTE - | WORD - | DWORD - | FWORD - | QWORD - | TBYTE - | OWORD - | XMMWORD - | . - | $ - | register - | id - | constant */ - -/* Parsing structure for the intel syntax parser. Used to implement the - semantic actions for the operand grammar. */ -struct intel_parser_s - { - char *op_string; /* The string being parsed. */ - int got_a_float; /* Whether the operand is a float. */ - int op_modifier; /* Operand modifier. */ - int is_mem; /* 1 if operand is memory reference. */ - int in_offset; /* >=1 if parsing operand of offset. */ - int in_bracket; /* >=1 if parsing operand in brackets. */ - const reg_entry *reg; /* Last register reference found. */ - char *disp; /* Displacement string being built. */ - char *next_operand; /* Resume point when splitting operands. */ - }; - -static struct intel_parser_s intel_parser; - -/* Token structure for parsing intel syntax. */ -struct intel_token - { - int code; /* Token code. */ - const reg_entry *reg; /* Register entry for register tokens. */ - char *str; /* String representation. */ - }; - -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 -#define T_CONST 1 -#define T_REG 2 -#define T_BYTE 3 -#define T_WORD 4 -#define T_DWORD 5 -#define T_FWORD 6 -#define T_QWORD 7 -#define T_TBYTE 8 -#define T_XMMWORD 9 -#undef T_SHORT -#define T_SHORT 10 -#define T_OFFSET 11 -#define T_PTR 12 -#define T_ID 13 -#define T_SHL 14 -#define T_SHR 15 - -/* Prototypes for intel parser functions. */ -static int intel_match_token (int); -static void intel_putback_token (void); -static void intel_get_token (void); -static int intel_expr (void); -static int intel_e04 (void); -static int intel_e05 (void); -static int intel_e06 (void); -static int intel_e09 (void); -static int intel_e10 (void); -static int intel_e11 (void); - -static int -i386_intel_operand (char *operand_string, int got_a_float) -{ - int ret; - char *p; - - p = intel_parser.op_string = xstrdup (operand_string); - intel_parser.disp = (char *) xmalloc (strlen (operand_string) + 1); - - for (;;) - { - /* Initialize token holders. */ - cur_token.code = prev_token.code = T_NIL; - cur_token.reg = prev_token.reg = NULL; - cur_token.str = prev_token.str = NULL; - - /* Initialize parser structure. */ - intel_parser.got_a_float = got_a_float; - intel_parser.op_modifier = 0; - intel_parser.is_mem = 0; - intel_parser.in_offset = 0; - intel_parser.in_bracket = 0; - intel_parser.reg = NULL; - intel_parser.disp[0] = '\0'; - intel_parser.next_operand = NULL; - - /* Read the first token and start the parser. */ - intel_get_token (); - ret = intel_expr (); - - if (!ret) - break; - - if (cur_token.code != T_NIL) - { - as_bad (_("invalid operand for '%s' ('%s' unexpected)"), - current_templates->start->name, cur_token.str); - ret = 0; - } - /* If we found a memory reference, hand it over to i386_displacement - to fill in the rest of the operand fields. */ - else if (intel_parser.is_mem) - { - if ((i.mem_operands == 1 - && !current_templates->start->opcode_modifier.isstring) - || i.mem_operands == 2) - { - as_bad (_("too many memory references for '%s'"), - current_templates->start->name); - ret = 0; - } - else - { - char *s = intel_parser.disp; - i.types[this_operand].bitfield.mem = 1; - i.mem_operands++; - - if (!quiet_warnings && intel_parser.is_mem < 0) - /* See the comments in intel_bracket_expr. */ - as_warn (_("Treating `%s' as memory reference"), operand_string); - - /* Add the displacement expression. */ - if (*s != '\0') - ret = i386_displacement (s, s + strlen (s)); - if (ret) - { - /* Swap base and index in 16-bit memory operands like - [si+bx]. Since i386_index_check is also used in AT&T - mode we have to do that here. */ - if (i.base_reg - && i.index_reg - && i.base_reg->reg_type.bitfield.reg16 - && i.index_reg->reg_type.bitfield.reg16 - && i.base_reg->reg_num >= 6 - && i.index_reg->reg_num < 6) - { - const reg_entry *base = i.index_reg; - - i.index_reg = i.base_reg; - i.base_reg = base; - } - ret = i386_index_check (operand_string); - } - } - } - - /* Constant and OFFSET expressions are handled by i386_immediate. */ - else if ((intel_parser.op_modifier & (1 << T_OFFSET)) - || intel_parser.reg == NULL) - ret = i386_immediate (intel_parser.disp); - - if (intel_parser.next_operand && this_operand >= MAX_OPERANDS - 1) - ret = 0; - if (!ret || !intel_parser.next_operand) - break; - intel_parser.op_string = intel_parser.next_operand; - this_operand = i.operands++; - i.types[this_operand].bitfield.unspecified = 1; - } - - free (p); - free (intel_parser.disp); - - return ret; -} - -#define NUM_ADDRESS_REGS (!!i.base_reg + !!i.index_reg) - -/* expr e04 expr' - - expr' cmpOp e04 expr' - | Empty */ -static int -intel_expr (void) -{ - /* XXX Implement the comparison operators. */ - return intel_e04 (); -} - -/* e04 e05 e04' - - e04' addOp e05 e04' - | Empty */ -static int -intel_e04 (void) -{ - int nregs = -1; - - for (;;) - { - if (!intel_e05()) - return 0; - - if (nregs >= 0 && NUM_ADDRESS_REGS > nregs) - i.base_reg = i386_regtab + REGNAM_AL; /* al is invalid as base */ - - if (cur_token.code == '+') - nregs = -1; - else if (cur_token.code == '-') - nregs = NUM_ADDRESS_REGS; - else - return 1; - - strcat (intel_parser.disp, cur_token.str); - intel_match_token (cur_token.code); - } -} - -/* e05 e06 e05' +#include "tc-i386-intel.c" - e05' binOp e06 e05' - | Empty */ -static int -intel_e05 (void) +void +tc_x86_parse_to_dw2regnum (expressionS *exp) { - int nregs = ~NUM_ADDRESS_REGS; - - for (;;) - { - if (!intel_e06()) - return 0; - - if (cur_token.code == '&' - || cur_token.code == '|' - || cur_token.code == '^') - { - char str[2]; - - str[0] = cur_token.code; - str[1] = 0; - strcat (intel_parser.disp, str); - } - else - break; + int saved_naked_reg; + char saved_register_dot; - intel_match_token (cur_token.code); - - if (nregs < 0) - nregs = ~nregs; - } - if (nregs >= 0 && NUM_ADDRESS_REGS > nregs) - i.base_reg = i386_regtab + REGNAM_AL + 1; /* cl is invalid as base */ - return 1; -} - -/* e06 e09 e06' - - e06' mulOp e09 e06' - | Empty */ -static int -intel_e06 (void) -{ - int nregs = ~NUM_ADDRESS_REGS; + saved_naked_reg = allow_naked_reg; + allow_naked_reg = 1; + saved_register_dot = register_chars['.']; + register_chars['.'] = '.'; + allow_pseudo_reg = 1; + expression_and_evaluate (exp); + allow_pseudo_reg = 0; + register_chars['.'] = saved_register_dot; + allow_naked_reg = saved_naked_reg; - for (;;) + if (exp->X_op == O_register && exp->X_add_number >= 0) { - if (!intel_e09()) - return 0; - - if (cur_token.code == '*' - || cur_token.code == '/' - || cur_token.code == '%') + if ((addressT) exp->X_add_number < i386_regtab_size) { - char str[2]; - - str[0] = cur_token.code; - str[1] = 0; - strcat (intel_parser.disp, str); + exp->X_op = O_constant; + exp->X_add_number = i386_regtab[exp->X_add_number] + .dw2_regnum[flag_code >> 1]; } - else if (cur_token.code == T_SHL) - strcat (intel_parser.disp, "<<"); - else if (cur_token.code == T_SHR) - strcat (intel_parser.disp, ">>"); else - break; - - intel_match_token (cur_token.code); - - if (nregs < 0) - nregs = ~nregs; + exp->X_op = O_illegal; } - if (nregs >= 0 && NUM_ADDRESS_REGS > nregs) - i.base_reg = i386_regtab + REGNAM_AL + 2; /* dl is invalid as base */ - return 1; } -/* e09 OFFSET e09 - | SHORT e09 - | + e09 - | - e09 - | ~ e09 - | NOT e09 - | e10 e09' - - e09' PTR e10 e09' - | : e10 e09' - | Empty */ -static int -intel_e09 (void) -{ - int nregs = ~NUM_ADDRESS_REGS; - int in_offset = 0; - - for (;;) - { - /* Don't consume constants here. */ - if (cur_token.code == '+' || cur_token.code == '-') - { - /* Need to look one token ahead - if the next token - is a constant, the current token is its sign. */ - int next_code; - - intel_match_token (cur_token.code); - next_code = cur_token.code; - intel_putback_token (); - if (next_code == T_CONST) - break; - } - - /* e09 OFFSET e09 */ - if (cur_token.code == T_OFFSET) - { - if (!in_offset++) - ++intel_parser.in_offset; - } - - /* e09 SHORT e09 */ - else if (cur_token.code == T_SHORT) - intel_parser.op_modifier |= 1 << T_SHORT; - - /* e09 + e09 */ - else if (cur_token.code == '+') - strcat (intel_parser.disp, "+"); - - /* e09 - e09 - | ~ e09 - | NOT e09 */ - else if (cur_token.code == '-' || cur_token.code == '~') - { - char str[2]; - - if (nregs < 0) - nregs = ~nregs; - str[0] = cur_token.code; - str[1] = 0; - strcat (intel_parser.disp, str); - } - - /* e09 e10 e09' */ - else - break; - - intel_match_token (cur_token.code); - } - - for (;;) - { - if (!intel_e10 ()) - return 0; - - /* e09' PTR e10 e09' */ - if (cur_token.code == T_PTR) - { - char suffix; - - if (prev_token.code == T_BYTE) - { - suffix = BYTE_MNEM_SUFFIX; - i.types[this_operand].bitfield.byte = 1; - } - - else if (prev_token.code == T_WORD) - { - if (current_templates->start->name[0] == 'l' - && current_templates->start->name[2] == 's' - && current_templates->start->name[3] == 0) - suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */ - else if (intel_parser.got_a_float == 2) /* "fi..." */ - suffix = SHORT_MNEM_SUFFIX; - else - suffix = WORD_MNEM_SUFFIX; - i.types[this_operand].bitfield.word = 1; - } - - else if (prev_token.code == T_DWORD) - { - if (current_templates->start->name[0] == 'l' - && current_templates->start->name[2] == 's' - && current_templates->start->name[3] == 0) - suffix = WORD_MNEM_SUFFIX; - else if (flag_code == CODE_16BIT - && (current_templates->start->opcode_modifier.jump - || current_templates->start->opcode_modifier.jumpdword)) - suffix = LONG_DOUBLE_MNEM_SUFFIX; - else if (intel_parser.got_a_float == 1) /* "f..." */ - suffix = SHORT_MNEM_SUFFIX; - else - suffix = LONG_MNEM_SUFFIX; - i.types[this_operand].bitfield.dword = 1; - } - - else if (prev_token.code == T_FWORD) - { - if (current_templates->start->name[0] == 'l' - && current_templates->start->name[2] == 's' - && current_templates->start->name[3] == 0) - suffix = LONG_MNEM_SUFFIX; - else if (!intel_parser.got_a_float) - { - if (flag_code == CODE_16BIT) - add_prefix (DATA_PREFIX_OPCODE); - suffix = LONG_DOUBLE_MNEM_SUFFIX; - } - else - suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */ - i.types[this_operand].bitfield.fword = 1; - } - - else if (prev_token.code == T_QWORD) - { - if (intel_parser.got_a_float == 1) /* "f..." */ - suffix = LONG_MNEM_SUFFIX; - else - suffix = QWORD_MNEM_SUFFIX; - i.types[this_operand].bitfield.qword = 1; - } - - else if (prev_token.code == T_TBYTE) - { - if (intel_parser.got_a_float == 1) - suffix = LONG_DOUBLE_MNEM_SUFFIX; - else - suffix = BYTE_MNEM_SUFFIX; /* so it will cause an error */ - } - - else if (prev_token.code == T_XMMWORD) - { - suffix = XMMWORD_MNEM_SUFFIX; - i.types[this_operand].bitfield.xmmword = 1; - } - - else - { - as_bad (_("Unknown operand modifier `%s'"), prev_token.str); - return 0; - } - - i.types[this_operand].bitfield.unspecified = 0; - - /* Operands for jump/call using 'ptr' notation denote absolute - addresses. */ - if (current_templates->start->opcode_modifier.jump - || current_templates->start->opcode_modifier.jumpdword) - i.types[this_operand].bitfield.jumpabsolute = 1; - - if (current_templates->start->base_opcode == 0x8d /* lea */) - ; - else if (!i.suffix) - i.suffix = suffix; - else if (i.suffix != suffix) - { - as_bad (_("Conflicting operand modifiers")); - return 0; - } - - } - - /* e09' : e10 e09' */ - else if (cur_token.code == ':') - { - if (prev_token.code != T_REG) - { - /* While {call,jmp} SSSS:OOOO is MASM syntax only when SSSS is a - segment/group identifier (which we don't have), using comma - as the operand separator there is even less consistent, since - there all branches only have a single operand. */ - if (this_operand != 0 - || intel_parser.in_offset - || intel_parser.in_bracket - || (!current_templates->start->opcode_modifier.jump - && !current_templates->start->opcode_modifier.jumpdword - && !current_templates->start->opcode_modifier.jumpintersegment - && !current_templates->start->operand_types[0].bitfield.jumpabsolute)) - return intel_match_token (T_NIL); - /* Remember the start of the 2nd operand and terminate 1st - operand here. - XXX This isn't right, yet (when SSSS:OOOO is right operand of - another expression), but it gets at least the simplest case - (a plain number or symbol on the left side) right. */ - intel_parser.next_operand = intel_parser.op_string; - *--intel_parser.op_string = '\0'; - return intel_match_token (':'); - } - } - - /* e09' Empty */ - else - break; - - intel_match_token (cur_token.code); - - } - - if (in_offset) - { - --intel_parser.in_offset; - if (nregs < 0) - nregs = ~nregs; - if (NUM_ADDRESS_REGS > nregs) - { - as_bad (_("Invalid operand to `OFFSET'")); - return 0; - } - intel_parser.op_modifier |= 1 << T_OFFSET; - } - - if (nregs >= 0 && NUM_ADDRESS_REGS > nregs) - i.base_reg = i386_regtab + REGNAM_AL + 3; /* bl is invalid as base */ - return 1; -} - -static int -intel_bracket_expr (void) -{ - int was_offset = intel_parser.op_modifier & (1 << T_OFFSET); - const char *start = intel_parser.op_string; - int len; - - if (i.op[this_operand].regs) - return intel_match_token (T_NIL); - - intel_match_token ('['); - - /* Mark as a memory operand only if it's not already known to be an - offset expression. If it's an offset expression, we need to keep - the brace in. */ - if (!intel_parser.in_offset) - { - ++intel_parser.in_bracket; - - /* Operands for jump/call inside brackets denote absolute addresses. */ - if (current_templates->start->opcode_modifier.jump - || current_templates->start->opcode_modifier.jumpdword) - i.types[this_operand].bitfield.jumpabsolute = 1; - - /* Unfortunately gas always diverged from MASM in a respect that can't - be easily fixed without risking to break code sequences likely to be - encountered (the testsuite even check for this): MASM doesn't consider - an expression inside brackets unconditionally as a memory reference. - When that is e.g. a constant, an offset expression, or the sum of the - two, this is still taken as a constant load. gas, however, always - treated these as memory references. As a compromise, we'll try to make - offset expressions inside brackets work the MASM way (since that's - less likely to be found in real world code), but make constants alone - continue to work the traditional gas way. In either case, issue a - warning. */ - intel_parser.op_modifier &= ~was_offset; - } - else - strcat (intel_parser.disp, "["); - - /* Add a '+' to the displacement string if necessary. */ - if (*intel_parser.disp != '\0' - && *(intel_parser.disp + strlen (intel_parser.disp) - 1) != '+') - strcat (intel_parser.disp, "+"); - - if (intel_expr () - && (len = intel_parser.op_string - start - 1, - intel_match_token (']'))) - { - /* Preserve brackets when the operand is an offset expression. */ - if (intel_parser.in_offset) - strcat (intel_parser.disp, "]"); - else - { - --intel_parser.in_bracket; - if (i.base_reg || i.index_reg) - intel_parser.is_mem = 1; - if (!intel_parser.is_mem) - { - if (!(intel_parser.op_modifier & (1 << T_OFFSET))) - /* Defer the warning until all of the operand was parsed. */ - intel_parser.is_mem = -1; - else if (!quiet_warnings) - as_warn (_("`[%.*s]' taken to mean just `%.*s'"), - len, start, len, start); - } - } - intel_parser.op_modifier |= was_offset; - - return 1; - } - return 0; -} - -/* e10 e11 e10' - - e10' [ expr ] e10' - | Empty */ -static int -intel_e10 (void) -{ - if (!intel_e11 ()) - return 0; - - while (cur_token.code == '[') - { - if (!intel_bracket_expr ()) - return 0; - } - - return 1; -} - -/* e11 ( expr ) - | [ expr ] - | BYTE - | WORD - | DWORD - | FWORD - | QWORD - | TBYTE - | OWORD - | XMMWORD - | $ - | . - | register - | id - | constant */ -static int -intel_e11 (void) -{ - switch (cur_token.code) - { - /* e11 ( expr ) */ - case '(': - intel_match_token ('('); - strcat (intel_parser.disp, "("); - - if (intel_expr () && intel_match_token (')')) - { - strcat (intel_parser.disp, ")"); - return 1; - } - return 0; - - /* e11 [ expr ] */ - case '[': - return intel_bracket_expr (); - - /* e11 $ - | . */ - case '.': - strcat (intel_parser.disp, cur_token.str); - intel_match_token (cur_token.code); - - /* Mark as a memory operand only if it's not already known to be an - offset expression. */ - if (!intel_parser.in_offset) - intel_parser.is_mem = 1; - - return 1; - - /* e11 register */ - case T_REG: - { - const reg_entry *reg = intel_parser.reg = cur_token.reg; - - intel_match_token (T_REG); - - /* Check for segment change. */ - if (cur_token.code == ':') - { - if (!reg->reg_type.bitfield.sreg2 - && !reg->reg_type.bitfield.sreg3) - { - as_bad (_("`%s' is not a valid segment register"), - reg->reg_name); - return 0; - } - else if (i.seg[i.mem_operands]) - as_warn (_("Extra segment override ignored")); - else - { - if (!intel_parser.in_offset) - intel_parser.is_mem = 1; - switch (reg->reg_num) - { - case 0: - i.seg[i.mem_operands] = &es; - break; - case 1: - i.seg[i.mem_operands] = &cs; - break; - case 2: - i.seg[i.mem_operands] = &ss; - break; - case 3: - i.seg[i.mem_operands] = &ds; - break; - case 4: - i.seg[i.mem_operands] = &fs; - break; - case 5: - i.seg[i.mem_operands] = &gs; - break; - } - } - } - - /* Not a segment register. Check for register scaling. */ - else if (cur_token.code == '*') - { - if (!intel_parser.in_bracket) - { - as_bad (_("Register scaling only allowed in memory operands")); - return 0; - } - - if (reg->reg_type.bitfield.reg16) /* Disallow things like [si*1]. */ - reg = i386_regtab + REGNAM_AX + 4; /* sp is invalid as index */ - else if (i.index_reg) - reg = i386_regtab + REGNAM_EAX + 4; /* esp is invalid as index */ - - /* What follows must be a valid scale. */ - intel_match_token ('*'); - i.index_reg = reg; - i.types[this_operand].bitfield.baseindex = 1; - - /* Set the scale after setting the register (otherwise, - i386_scale will complain) */ - if (cur_token.code == '+' || cur_token.code == '-') - { - char *str, sign = cur_token.code; - intel_match_token (cur_token.code); - if (cur_token.code != T_CONST) - { - as_bad (_("Syntax error: Expecting a constant, got `%s'"), - cur_token.str); - return 0; - } - str = (char *) xmalloc (strlen (cur_token.str) + 2); - strcpy (str + 1, cur_token.str); - *str = sign; - if (!i386_scale (str)) - return 0; - free (str); - } - else if (!i386_scale (cur_token.str)) - return 0; - intel_match_token (cur_token.code); - } - - /* No scaling. If this is a memory operand, the register is either a - base register (first occurrence) or an index register (second - occurrence). */ - else if (intel_parser.in_bracket) - { - - if (!i.base_reg) - i.base_reg = reg; - else if (!i.index_reg) - i.index_reg = reg; - else - { - as_bad (_("Too many register references in memory operand")); - return 0; - } - - i.types[this_operand].bitfield.baseindex = 1; - } - - /* It's neither base nor index. */ - else if (!intel_parser.in_offset && !intel_parser.is_mem) - { - i386_operand_type temp = reg->reg_type; - temp.bitfield.baseindex = 0; - i.types[this_operand] = operand_type_or (i.types[this_operand], - temp); - i.types[this_operand].bitfield.unspecified = 0; - i.op[this_operand].regs = reg; - i.reg_operands++; - } - else - { - as_bad (_("Invalid use of register")); - return 0; - } - - /* Since registers are not part of the displacement string (except - when we're parsing offset operands), we may need to remove any - preceding '+' from the displacement string. */ - if (*intel_parser.disp != '\0' - && !intel_parser.in_offset) - { - char *s = intel_parser.disp; - s += strlen (s) - 1; - if (*s == '+') - *s = '\0'; - } - - return 1; - } - - /* e11 BYTE - | WORD - | DWORD - | FWORD - | QWORD - | TBYTE - | OWORD - | XMMWORD */ - case T_BYTE: - case T_WORD: - case T_DWORD: - case T_FWORD: - case T_QWORD: - case T_TBYTE: - case T_XMMWORD: - intel_match_token (cur_token.code); - - if (cur_token.code == T_PTR) - return 1; - - /* It must have been an identifier. */ - intel_putback_token (); - cur_token.code = T_ID; - /* FALLTHRU */ - - /* e11 id - | constant */ - case T_ID: - if (!intel_parser.in_offset && intel_parser.is_mem <= 0) - { - symbolS *symbolP; - - /* The identifier represents a memory reference only if it's not - preceded by an offset modifier and if it's not an equate. */ - symbolP = symbol_find(cur_token.str); - if (!symbolP || S_GET_SEGMENT(symbolP) != absolute_section) - intel_parser.is_mem = 1; - } - /* FALLTHRU */ - - case T_CONST: - case '-': - case '+': - { - char *save_str, sign = 0; - - /* Allow constants that start with `+' or `-'. */ - if (cur_token.code == '-' || cur_token.code == '+') - { - sign = cur_token.code; - intel_match_token (cur_token.code); - if (cur_token.code != T_CONST) - { - as_bad (_("Syntax error: Expecting a constant, got `%s'"), - cur_token.str); - return 0; - } - } - - save_str = (char *) xmalloc (strlen (cur_token.str) + 2); - strcpy (save_str + !!sign, cur_token.str); - if (sign) - *save_str = sign; - - /* Get the next token to check for register scaling. */ - intel_match_token (cur_token.code); - - /* Check if this constant is a scaling factor for an - index register. */ - if (cur_token.code == '*') - { - if (intel_match_token ('*') && cur_token.code == T_REG) - { - const reg_entry *reg = cur_token.reg; - - if (!intel_parser.in_bracket) - { - as_bad (_("Register scaling only allowed " - "in memory operands")); - return 0; - } - - /* Disallow things like [1*si]. - sp and esp are invalid as index. */ - if (reg->reg_type.bitfield.reg16) - reg = i386_regtab + REGNAM_AX + 4; - else if (i.index_reg) - reg = i386_regtab + REGNAM_EAX + 4; - - /* The constant is followed by `* reg', so it must be - a valid scale. */ - i.index_reg = reg; - i.types[this_operand].bitfield.baseindex = 1; - - /* Set the scale after setting the register (otherwise, - i386_scale will complain) */ - if (!i386_scale (save_str)) - return 0; - intel_match_token (T_REG); - - /* Since registers are not part of the displacement - string, we may need to remove any preceding '+' from - the displacement string. */ - if (*intel_parser.disp != '\0') - { - char *s = intel_parser.disp; - s += strlen (s) - 1; - if (*s == '+') - *s = '\0'; - } - - free (save_str); - - return 1; - } - - /* The constant was not used for register scaling. Since we have - already consumed the token following `*' we now need to put it - back in the stream. */ - intel_putback_token (); - } - - /* Add the constant to the displacement string. */ - strcat (intel_parser.disp, save_str); - free (save_str); - - return 1; - } - } - - as_bad (_("Unrecognized token '%s'"), cur_token.str); - return 0; -} - -/* Match the given token against cur_token. If they match, read the next - token from the operand string. */ -static int -intel_match_token (int code) -{ - if (cur_token.code == code) - { - intel_get_token (); - return 1; - } - else - { - as_bad (_("Unexpected token `%s'"), cur_token.str); - return 0; - } -} - -/* Read a new token from intel_parser.op_string and store it in cur_token. */ -static void -intel_get_token (void) +void +tc_x86_frame_initial_instructions (void) { - char *end_op; - const reg_entry *reg; - struct intel_token new_token; - - new_token.code = T_NIL; - new_token.reg = NULL; - new_token.str = NULL; - - /* Free the memory allocated to the previous token and move - cur_token to prev_token. */ - if (prev_token.str) - free (prev_token.str); - - prev_token = cur_token; - - /* Skip whitespace. */ - while (is_space_char (*intel_parser.op_string)) - intel_parser.op_string++; + static unsigned int sp_regno[2]; - /* Return an empty token if we find nothing else on the line. */ - if (*intel_parser.op_string == '\0') + if (!sp_regno[flag_code >> 1]) { - cur_token = new_token; - return; - } - - /* The new token cannot be larger than the remainder of the operand - string. */ - new_token.str = (char *) xmalloc (strlen (intel_parser.op_string) + 1); - new_token.str[0] = '\0'; - - if (strchr ("0123456789", *intel_parser.op_string)) - { - char *p = new_token.str; - char *q = intel_parser.op_string; - new_token.code = T_CONST; - - /* Allow any kind of identifier char to encompass floating point and - hexadecimal numbers. */ - while (is_identifier_char (*q)) - *p++ = *q++; - *p = '\0'; + char *saved_input = input_line_pointer; + char sp[][4] = {"esp", "rsp"}; + expressionS exp; - /* Recognize special symbol names [0-9][bf]. */ - if (strlen (intel_parser.op_string) == 2 - && (intel_parser.op_string[1] == 'b' - || intel_parser.op_string[1] == 'f')) - new_token.code = T_ID; + input_line_pointer = sp[flag_code >> 1]; + tc_x86_parse_to_dw2regnum (&exp); + gas_assert (exp.X_op == O_constant); + sp_regno[flag_code >> 1] = exp.X_add_number; + input_line_pointer = saved_input; } - else if ((reg = parse_register (intel_parser.op_string, &end_op)) != NULL) - { - size_t len = end_op - intel_parser.op_string; - - new_token.code = T_REG; - new_token.reg = reg; - - memcpy (new_token.str, intel_parser.op_string, len); - new_token.str[len] = '\0'; - } - - else if (is_identifier_char (*intel_parser.op_string)) - { - char *p = new_token.str; - char *q = intel_parser.op_string; - - /* A '.' or '$' followed by an identifier char is an identifier. - Otherwise, it's operator '.' followed by an expression. */ - if ((*q == '.' || *q == '$') && !is_identifier_char (*(q + 1))) - { - new_token.code = '.'; - new_token.str[0] = '.'; - new_token.str[1] = '\0'; - } - else - { - while (is_identifier_char (*q) || *q == '@') - *p++ = *q++; - *p = '\0'; - - if (strcasecmp (new_token.str, "NOT") == 0) - new_token.code = '~'; - - else if (strcasecmp (new_token.str, "MOD") == 0) - new_token.code = '%'; - - else if (strcasecmp (new_token.str, "AND") == 0) - new_token.code = '&'; - - else if (strcasecmp (new_token.str, "OR") == 0) - new_token.code = '|'; - - else if (strcasecmp (new_token.str, "XOR") == 0) - new_token.code = '^'; - - else if (strcasecmp (new_token.str, "SHL") == 0) - new_token.code = T_SHL; - - else if (strcasecmp (new_token.str, "SHR") == 0) - new_token.code = T_SHR; - - else if (strcasecmp (new_token.str, "BYTE") == 0) - new_token.code = T_BYTE; - - else if (strcasecmp (new_token.str, "WORD") == 0) - new_token.code = T_WORD; - - else if (strcasecmp (new_token.str, "DWORD") == 0) - new_token.code = T_DWORD; - - else if (strcasecmp (new_token.str, "FWORD") == 0) - new_token.code = T_FWORD; - - else if (strcasecmp (new_token.str, "QWORD") == 0) - new_token.code = T_QWORD; - - else if (strcasecmp (new_token.str, "TBYTE") == 0 - /* XXX remove (gcc still uses it) */ - || strcasecmp (new_token.str, "XWORD") == 0) - new_token.code = T_TBYTE; - - else if (strcasecmp (new_token.str, "XMMWORD") == 0 - || strcasecmp (new_token.str, "OWORD") == 0) - new_token.code = T_XMMWORD; - - else if (strcasecmp (new_token.str, "PTR") == 0) - new_token.code = T_PTR; - - else if (strcasecmp (new_token.str, "SHORT") == 0) - new_token.code = T_SHORT; - - else if (strcasecmp (new_token.str, "OFFSET") == 0) - { - new_token.code = T_OFFSET; - - /* ??? This is not mentioned in the MASM grammar but gcc - makes use of it with -mintel-syntax. OFFSET may be - followed by FLAT: */ - if (strncasecmp (q, " FLAT:", 6) == 0) - strcat (new_token.str, " FLAT:"); - } - - /* ??? This is not mentioned in the MASM grammar. */ - else if (strcasecmp (new_token.str, "FLAT") == 0) - { - new_token.code = T_OFFSET; - if (*q == ':') - strcat (new_token.str, ":"); - else - as_bad (_("`:' expected")); - } - - else - new_token.code = T_ID; - } - } - - else if (strchr ("+-/*%|&^:[]()~", *intel_parser.op_string)) - { - new_token.code = *intel_parser.op_string; - new_token.str[0] = *intel_parser.op_string; - new_token.str[1] = '\0'; - } - - else if (strchr ("<>", *intel_parser.op_string) - && *intel_parser.op_string == *(intel_parser.op_string + 1)) - { - new_token.code = *intel_parser.op_string == '<' ? T_SHL : T_SHR; - new_token.str[0] = *intel_parser.op_string; - new_token.str[1] = *intel_parser.op_string; - new_token.str[2] = '\0'; - } - - else - as_bad (_("Unrecognized token `%s'"), intel_parser.op_string); - - intel_parser.op_string += strlen (new_token.str); - cur_token = new_token; -} - -/* Put cur_token back into the token stream and make cur_token point to - prev_token. */ -static void -intel_putback_token (void) -{ - if (cur_token.code != T_NIL) - { - intel_parser.op_string -= strlen (cur_token.str); - free (cur_token.str); - } - cur_token = prev_token; - - /* Forget prev_token. */ - prev_token.code = T_NIL; - prev_token.reg = NULL; - prev_token.str = NULL; -} - -int -tc_x86_regname_to_dw2regnum (char *regname) -{ - unsigned int regnum; - unsigned int regnames_count; - static const char *const regnames_32[] = - { - "eax", "ecx", "edx", "ebx", - "esp", "ebp", "esi", "edi", - "eip", "eflags", NULL, - "st0", "st1", "st2", "st3", - "st4", "st5", "st6", "st7", - NULL, NULL, - "xmm0", "xmm1", "xmm2", "xmm3", - "xmm4", "xmm5", "xmm6", "xmm7", - "mm0", "mm1", "mm2", "mm3", - "mm4", "mm5", "mm6", "mm7", - "fcw", "fsw", "mxcsr", - "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL, - "tr", "ldtr" - }; - static const char *const regnames_64[] = - { - "rax", "rdx", "rcx", "rbx", - "rsi", "rdi", "rbp", "rsp", - "r8", "r9", "r10", "r11", - "r12", "r13", "r14", "r15", - "rip", - "xmm0", "xmm1", "xmm2", "xmm3", - "xmm4", "xmm5", "xmm6", "xmm7", - "xmm8", "xmm9", "xmm10", "xmm11", - "xmm12", "xmm13", "xmm14", "xmm15", - "st0", "st1", "st2", "st3", - "st4", "st5", "st6", "st7", - "mm0", "mm1", "mm2", "mm3", - "mm4", "mm5", "mm6", "mm7", - "rflags", - "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL, - "fs.base", "gs.base", NULL, NULL, - "tr", "ldtr", - "mxcsr", "fcw", "fsw" - }; - const char *const *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 (regnames[regnum] != NULL - && 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_def_cfa (sp_regno[flag_code >> 1], -x86_cie_data_alignment); cfi_add_CFA_offset (x86_dwarf2_return_column, x86_cie_data_alignment); } @@ -9034,6 +8383,15 @@ i386_elf_section_type (const char *str, size_t len) return -1; } +#ifdef TE_SOLARIS +void +i386_solaris_fix_up_eh_frame (segT sec) +{ + if (flag_code == CODE_64BIT) + elf_section_type (sec) = SHT_X86_64_UNWIND; +} +#endif + #ifdef TE_PE void tc_pe_dwarf2_emit_offset (symbolS *symbol, unsigned int size) @@ -9050,7 +8408,7 @@ tc_pe_dwarf2_emit_offset (symbolS *symbol, unsigned int size) #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) /* For ELF on x86-64, add support for SHF_X86_64_LARGE. */ -int +bfd_vma x86_64_section_letter (int letter, char **ptr_msg) { if (flag_code == CODE_64BIT) @@ -9065,7 +8423,7 @@ x86_64_section_letter (int letter, char **ptr_msg) return -1; } -int +bfd_vma x86_64_section_word (char *str, size_t len) { if (len == 5 && flag_code == CODE_64BIT && CONST_STRNEQ (str, "large"))