X-Git-Url: http://drtracing.org/?a=blobdiff_plain;ds=sidebyside;f=gas%2Fconfig%2Ftc-i386.c;h=9e83a4d0a469f8fdf3252b5c9a22cb01b0eb1db3;hb=8729a6f6a5148fb4dcb280a95dc0bdc35f02b96e;hp=7d170f491dace71f8d60f4506a874f4ed3f3276f;hpb=922d8de8c1bd5cbaa9eadd77437daea021864c1d;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 7d170f491d..9e83a4d0a4 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -1,6 +1,7 @@ /* 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, 2009 + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, + 2012 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -59,14 +60,15 @@ 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. */ + REP_PREFIX, LOCK_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 */ +#define REP_PREFIX 4 +#define LOCK_PREFIX 5 +#define REX_PREFIX 6 /* must come last. */ +#define MAX_PREFIXES 7 /* max prefixes per opcode */ /* we define the syntax here (modulo base,index,scale syntax) */ #define REGISTER_PREFIX '%' @@ -97,8 +99,8 @@ */ typedef struct { - const template *start; - const template *end; + const insn_template *start; + const insn_template *end; } templates; @@ -127,11 +129,15 @@ sib_byte; typedef struct { const char *name; /* arch name */ + unsigned int len; /* arch string length */ enum processor_type type; /* arch type */ i386_cpu_flags flags; /* cpu feature flags */ + unsigned int skip; /* show_arch should skip this. */ + unsigned int negated; /* turn off indicated flags. */ } arch_entry; +static void update_code_flag (int, int); static void set_code_flag (int); static void set_16bit_gcc_code_flag (int); static void set_intel_syntax (int); @@ -159,7 +165,7 @@ static void swap_operands (void); static void swap_2_operands (int, int); static void optimize_imm (void); static void optimize_disp (void); -static const template *match_template (void); +static const insn_template *match_template (void); static int check_string (void); static int process_suffix (void); static int check_byte_reg (void); @@ -201,10 +207,26 @@ union i386_op const reg_entry *regs; }; +enum i386_error + { + operand_size_mismatch, + operand_type_mismatch, + register_type_mismatch, + number_of_operands_mismatch, + invalid_instruction_suffix, + bad_imm4, + old_gcc_only, + unsupported_with_intel_mnemonic, + unsupported_syntax, + unsupported, + invalid_vsib_address, + unsupported_vector_index_register + }; + struct _i386_insn { /* TM holds the template for the insn were currently assembling. */ - template tm; + insn_template tm; /* SUFFIX holds the instruction size suffix for byte, word, dword or qword, if given. */ @@ -256,7 +278,13 @@ struct _i386_insn vex_prefix vex; /* Swap operand in encoding. */ - unsigned int swap_operand : 1; + unsigned int swap_operand; + + /* Force 32bit displacement in encoding. */ + unsigned int disp32_encoding; + + /* Error message. */ + enum i386_error error; }; typedef struct _i386_insn i386_insn; @@ -278,6 +306,7 @@ const char extra_symbol_chars[] = "*%-([" && !defined (TE_LINUX) \ && !defined (TE_NETWARE) \ && !defined (TE_FreeBSD) \ + && !defined (TE_DragonFly) \ && !defined (TE_NetBSD))) /* This array holds the chars that always start a comment. If the pre-processor is disabled, these aren't very useful. The option @@ -364,8 +393,24 @@ enum flag_code { static enum flag_code flag_code; static unsigned int object_64bit; +static unsigned int disallow_64bit_reloc; static int use_rela_relocations = 0; +#if ((defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT)) \ + || defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \ + || defined (TE_PE) || defined (TE_PEP) || defined (OBJ_MACH_O)) + +/* The ELF ABI to use. */ +enum x86_elf_abi +{ + I386_ABI, + X86_64_ABI, + X86_64_X32_ABI +}; + +static enum x86_elf_abi x86_elf_abi = I386_ABI; +#endif + /* The names used to print error messages. */ static const char *flag_code_names[] = { @@ -445,6 +490,13 @@ static unsigned int no_cond_jump_promotion = 0; /* Encode SSE instructions with VEX prefix. */ static unsigned int sse2avx; +/* Encode scalar AVX instructions with specific vector length. */ +static enum + { + vex128 = 0, + vex256 + } avxscalar; + /* Pre-defined "_GLOBAL_OFFSET_TABLE_". */ static symbolS *GOT_symbol; @@ -535,120 +587,172 @@ 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 }, - { "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 }, + /* Do not replace the first two entries - i386_target_format() + relies on them being there in this order. */ + { STRING_COMMA_LEN ("generic32"), PROCESSOR_GENERIC32, + CPU_GENERIC32_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("generic64"), PROCESSOR_GENERIC64, + CPU_GENERIC64_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("i8086"), PROCESSOR_UNKNOWN, + CPU_NONE_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("i186"), PROCESSOR_UNKNOWN, + CPU_I186_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("i286"), PROCESSOR_UNKNOWN, + CPU_I286_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("i386"), PROCESSOR_I386, + CPU_I386_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("i486"), PROCESSOR_I486, + CPU_I486_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("i586"), PROCESSOR_PENTIUM, + CPU_I586_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("i686"), PROCESSOR_PENTIUMPRO, + CPU_I686_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("pentium"), PROCESSOR_PENTIUM, + CPU_I586_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("pentiumpro"), PROCESSOR_PENTIUMPRO, + CPU_PENTIUMPRO_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("pentiumii"), PROCESSOR_PENTIUMPRO, + CPU_P2_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("pentiumiii"),PROCESSOR_PENTIUMPRO, + CPU_P3_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("pentium4"), PROCESSOR_PENTIUM4, + CPU_P4_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("prescott"), PROCESSOR_NOCONA, + CPU_CORE_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("nocona"), PROCESSOR_NOCONA, + CPU_NOCONA_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("yonah"), PROCESSOR_CORE, + CPU_CORE_FLAGS, 1, 0 }, + { STRING_COMMA_LEN ("core"), PROCESSOR_CORE, + CPU_CORE_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("merom"), PROCESSOR_CORE2, + CPU_CORE2_FLAGS, 1, 0 }, + { STRING_COMMA_LEN ("core2"), PROCESSOR_CORE2, + CPU_CORE2_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("corei7"), PROCESSOR_COREI7, + CPU_COREI7_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("l1om"), PROCESSOR_L1OM, + CPU_L1OM_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("k1om"), PROCESSOR_K1OM, + CPU_K1OM_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("k6"), PROCESSOR_K6, + CPU_K6_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("k6_2"), PROCESSOR_K6, + CPU_K6_2_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("athlon"), PROCESSOR_ATHLON, + CPU_ATHLON_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("sledgehammer"), PROCESSOR_K8, + CPU_K8_FLAGS, 1, 0 }, + { STRING_COMMA_LEN ("opteron"), PROCESSOR_K8, + CPU_K8_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("k8"), PROCESSOR_K8, + CPU_K8_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("amdfam10"), PROCESSOR_AMDFAM10, + CPU_AMDFAM10_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("bdver1"), PROCESSOR_BD, + CPU_BDVER1_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("bdver2"), PROCESSOR_BD, + CPU_BDVER2_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".8087"), PROCESSOR_UNKNOWN, + CPU_8087_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".287"), PROCESSOR_UNKNOWN, + CPU_287_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".387"), PROCESSOR_UNKNOWN, + CPU_387_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".no87"), PROCESSOR_UNKNOWN, + CPU_ANY87_FLAGS, 0, 1 }, + { STRING_COMMA_LEN (".mmx"), PROCESSOR_UNKNOWN, + CPU_MMX_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".nommx"), PROCESSOR_UNKNOWN, + CPU_3DNOWA_FLAGS, 0, 1 }, + { STRING_COMMA_LEN (".sse"), PROCESSOR_UNKNOWN, + CPU_SSE_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".sse2"), PROCESSOR_UNKNOWN, + CPU_SSE2_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".sse3"), PROCESSOR_UNKNOWN, + CPU_SSE3_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".ssse3"), PROCESSOR_UNKNOWN, + CPU_SSSE3_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".sse4.1"), PROCESSOR_UNKNOWN, + CPU_SSE4_1_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".sse4.2"), PROCESSOR_UNKNOWN, + CPU_SSE4_2_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".sse4"), PROCESSOR_UNKNOWN, + CPU_SSE4_2_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".nosse"), PROCESSOR_UNKNOWN, + CPU_ANY_SSE_FLAGS, 0, 1 }, + { STRING_COMMA_LEN (".avx"), PROCESSOR_UNKNOWN, + CPU_AVX_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".avx2"), PROCESSOR_UNKNOWN, + CPU_AVX2_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".noavx"), PROCESSOR_UNKNOWN, + CPU_ANY_AVX_FLAGS, 0, 1 }, + { STRING_COMMA_LEN (".vmx"), PROCESSOR_UNKNOWN, + CPU_VMX_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".vmfunc"), PROCESSOR_UNKNOWN, + CPU_VMFUNC_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".smx"), PROCESSOR_UNKNOWN, + CPU_SMX_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".xsave"), PROCESSOR_UNKNOWN, + CPU_XSAVE_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".xsaveopt"), PROCESSOR_UNKNOWN, + CPU_XSAVEOPT_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".aes"), PROCESSOR_UNKNOWN, + CPU_AES_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".pclmul"), PROCESSOR_UNKNOWN, + CPU_PCLMUL_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".clmul"), PROCESSOR_UNKNOWN, + CPU_PCLMUL_FLAGS, 1, 0 }, + { STRING_COMMA_LEN (".fsgsbase"), PROCESSOR_UNKNOWN, + CPU_FSGSBASE_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".rdrnd"), PROCESSOR_UNKNOWN, + CPU_RDRND_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".f16c"), PROCESSOR_UNKNOWN, + CPU_F16C_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".bmi2"), PROCESSOR_UNKNOWN, + CPU_BMI2_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".fma"), PROCESSOR_UNKNOWN, + CPU_FMA_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".fma4"), PROCESSOR_UNKNOWN, + CPU_FMA4_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".xop"), PROCESSOR_UNKNOWN, + CPU_XOP_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".lwp"), PROCESSOR_UNKNOWN, + CPU_LWP_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".movbe"), PROCESSOR_UNKNOWN, + CPU_MOVBE_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".ept"), PROCESSOR_UNKNOWN, + CPU_EPT_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".lzcnt"), PROCESSOR_UNKNOWN, + CPU_LZCNT_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".invpcid"), PROCESSOR_UNKNOWN, + CPU_INVPCID_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".clflush"), PROCESSOR_UNKNOWN, + CPU_CLFLUSH_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".nop"), PROCESSOR_UNKNOWN, + CPU_NOP_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".syscall"), PROCESSOR_UNKNOWN, + CPU_SYSCALL_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".rdtscp"), PROCESSOR_UNKNOWN, + CPU_RDTSCP_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".3dnow"), PROCESSOR_UNKNOWN, + CPU_3DNOW_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".3dnowa"), PROCESSOR_UNKNOWN, + CPU_3DNOWA_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".padlock"), PROCESSOR_UNKNOWN, + CPU_PADLOCK_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".pacifica"), PROCESSOR_UNKNOWN, + CPU_SVME_FLAGS, 1, 0 }, + { STRING_COMMA_LEN (".svme"), PROCESSOR_UNKNOWN, + CPU_SVME_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".sse4a"), PROCESSOR_UNKNOWN, + CPU_SSE4A_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".abm"), PROCESSOR_UNKNOWN, + CPU_ABM_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".bmi"), PROCESSOR_UNKNOWN, + CPU_BMI_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".tbm"), PROCESSOR_UNKNOWN, + CPU_TBM_FLAGS, 0, 0 }, }; #ifdef I386COFF @@ -934,10 +1038,11 @@ i386_align_code (fragS *fragP, int count) 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. + PROCESSOR_AMDFAM10, and PROCESSOR_BD, alt_short_patt + will be used. When -mtune= isn't used, alt_long_patt will be used if - cpu_arch_isa_flags has Cpu686. Otherwise, f32_patt will + cpu_arch_isa_flags has CpuNop. Otherwise, f32_patt will be used. When -march= or .arch is used, we can't use anything beyond @@ -967,18 +1072,19 @@ 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 (fragP->tc_frag_data.isa_flags.bitfield.cpui686) + optimize with nops. */ + if (fragP->tc_frag_data.isa_flags.bitfield.cpunop) patt = alt_long_patt; else patt = f32_patt; break; - case PROCESSOR_PENTIUMPRO: case PROCESSOR_PENTIUM4: case PROCESSOR_NOCONA: case PROCESSOR_CORE: case PROCESSOR_CORE2: case PROCESSOR_COREI7: + case PROCESSOR_L1OM: + case PROCESSOR_K1OM: case PROCESSOR_GENERIC64: patt = alt_long_patt; break; @@ -986,11 +1092,13 @@ i386_align_code (fragS *fragP, int count) case PROCESSOR_ATHLON: case PROCESSOR_K8: case PROCESSOR_AMDFAM10: + case PROCESSOR_BD: patt = alt_short_patt; break; case PROCESSOR_I386: case PROCESSOR_I486: case PROCESSOR_PENTIUM: + case PROCESSOR_PENTIUMPRO: case PROCESSOR_GENERIC32: patt = f32_patt; break; @@ -1013,10 +1121,11 @@ i386_align_code (fragS *fragP, int count) case PROCESSOR_ATHLON: case PROCESSOR_K8: case PROCESSOR_AMDFAM10: + case PROCESSOR_BD: case PROCESSOR_GENERIC32: /* We use cpu_arch_isa_flags to check if we CAN optimize - for Cpu686. */ - if (fragP->tc_frag_data.isa_flags.bitfield.cpui686) + with nops. */ + if (fragP->tc_frag_data.isa_flags.bitfield.cpunop) patt = alt_short_patt; else patt = f32_patt; @@ -1027,7 +1136,9 @@ i386_align_code (fragS *fragP, int count) case PROCESSOR_CORE: case PROCESSOR_CORE2: case PROCESSOR_COREI7: - if (fragP->tc_frag_data.isa_flags.bitfield.cpui686) + case PROCESSOR_L1OM: + case PROCESSOR_K1OM: + if (fragP->tc_frag_data.isa_flags.bitfield.cpunop) patt = alt_long_patt; else patt = f32_patt; @@ -1042,8 +1153,16 @@ i386_align_code (fragS *fragP, int count) { /* If the padding is less than 15 bytes, we use the normal ones. Otherwise, we use a jump instruction and adjust - its offset. */ - if (count < 15) + its offset. */ + int limit; + + /* For 64bit, the limit is 3 bytes. */ + if (flag_code == CODE_64BIT + && fragP->tc_frag_data.isa_flags.bitfield.cpulm) + limit = 3; + else + limit = 15; + if (count < limit) memcpy (fragP->fr_literal + fragP->fr_fix, patt[count - 1], count); else @@ -1228,6 +1347,24 @@ cpu_flags_or (i386_cpu_flags x, i386_cpu_flags y) return x; } +static INLINE i386_cpu_flags +cpu_flags_and_not (i386_cpu_flags x, i386_cpu_flags y) +{ + switch (ARRAY_SIZE (x.array)) + { + case 3: + x.array [2] &= ~y.array [2]; + case 2: + x.array [1] &= ~y.array [1]; + case 1: + x.array [0] &= ~y.array [0]; + break; + default: + abort (); + } + return x; +} + #define CPU_FLAGS_ARCH_MATCH 0x1 #define CPU_FLAGS_64BIT_MATCH 0x2 #define CPU_FLAGS_AES_MATCH 0x4 @@ -1243,7 +1380,7 @@ cpu_flags_or (i386_cpu_flags x, i386_cpu_flags y) /* Return CPU flags match bits. */ static int -cpu_flags_match (const template *t) +cpu_flags_match (const insn_template *t) { i386_cpu_flags x = t->cpu_flags; int match = cpu_flags_check_cpu64 (x) ? CPU_FLAGS_64BIT_MATCH : 0; @@ -1373,6 +1510,7 @@ static const i386_operand_type imm64 = OPERAND_TYPE_IMM64; static const i386_operand_type imm16_32 = OPERAND_TYPE_IMM16_32; static const i386_operand_type imm16_32s = OPERAND_TYPE_IMM16_32S; static const i386_operand_type imm16_32_32s = OPERAND_TYPE_IMM16_32_32S; +static const i386_operand_type vec_imm4 = OPERAND_TYPE_VEC_IMM4; enum operand_type { @@ -1427,7 +1565,7 @@ operand_type_check (i386_operand_type t, enum operand_type c) operand J for instruction template T. */ static INLINE int -match_reg_size (const template *t, unsigned int j) +match_reg_size (const insn_template *t, unsigned int j) { return !((i.types[j].bitfield.byte && !t->operand_types[j].bitfield.byte) @@ -1443,7 +1581,7 @@ match_reg_size (const template *t, unsigned int j) instruction template T. */ static INLINE int -match_mem_size (const template *t, unsigned int j) +match_mem_size (const insn_template *t, unsigned int j) { return (match_reg_size (t, j) && !((i.types[j].bitfield.unspecified @@ -1462,7 +1600,7 @@ match_mem_size (const template *t, unsigned int j) instruction template T. */ static INLINE int -operand_size_match (const template *t) +operand_size_match (const insn_template *t) { unsigned int j; int match = 1; @@ -1493,9 +1631,14 @@ operand_size_match (const template *t) } } - if (match - || (!t->opcode_modifier.d && !t->opcode_modifier.floatd)) + if (match) return match; + else if (!t->opcode_modifier.d && !t->opcode_modifier.floatd) + { +mismatch: + i.error = operand_size_mismatch; + return 0; + } /* Check reverse. */ gas_assert (i.operands == 2); @@ -1505,17 +1648,11 @@ operand_size_match (const template *t) { if (t->operand_types[j].bitfield.acc && !match_reg_size (t, j ? 0 : 1)) - { - match = 0; - break; - } + goto mismatch; if (i.types[j].bitfield.mem && !match_mem_size (t, j ? 0 : 1)) - { - match = 0; - break; - } + goto mismatch; } return match; @@ -1538,10 +1675,15 @@ operand_type_match (i386_operand_type overlap, temp.bitfield.xmmword = 0; temp.bitfield.ymmword = 0; if (operand_type_all_zero (&temp)) - return 0; + goto mismatch; - return (given.bitfield.baseindex == overlap.bitfield.baseindex - && given.bitfield.jumpabsolute == overlap.bitfield.jumpabsolute); + if (given.bitfield.baseindex == overlap.bitfield.baseindex + && given.bitfield.jumpabsolute == overlap.bitfield.jumpabsolute) + return 1; + +mismatch: + i.error = operand_type_mismatch; + return 0; } /* If given types g0 and g1 are registers they must be of the same type @@ -1584,10 +1726,15 @@ operand_type_register_match (i386_operand_type m0, t1.bitfield.reg64 = 1; } - return (!(t0.bitfield.reg8 & t1.bitfield.reg8) - && !(t0.bitfield.reg16 & t1.bitfield.reg16) - && !(t0.bitfield.reg32 & t1.bitfield.reg32) - && !(t0.bitfield.reg64 & t1.bitfield.reg64)); + if (!(t0.bitfield.reg8 & t1.bitfield.reg8) + && !(t0.bitfield.reg16 & t1.bitfield.reg16) + && !(t0.bitfield.reg32 & t1.bitfield.reg32) + && !(t0.bitfield.reg64 & t1.bitfield.reg64)) + return 1; + + i.error = register_type_mismatch; + + return 0; } static INLINE unsigned int @@ -1648,6 +1795,12 @@ fits_in_unsigned_long (offsetT num ATTRIBUTE_UNUSED) #endif } /* fits_in_unsigned_long() */ +static INLINE int +fits_in_imm4 (offsetT num) +{ + return (num & 0xf) == num; +} + static i386_operand_type smallest_imm_type (offsetT num) { @@ -1718,10 +1871,13 @@ offset_in_range (offsetT val, int size) default: abort (); } - /* If BFD64, sign extend val. */ - if (!use_rela_relocations) +#ifdef BFD64 + /* If BFD64, sign extend val for 32bit address mode. */ + if (flag_code != CODE_64BIT + || i.prefix[ADDR_PREFIX]) if ((val & ~(((addressT) 2 << 31) - 1)) == 0) val = (val ^ ((addressT) 1 << 31)) - ((addressT) 1 << 31); +#endif if ((val & ~mask) != 0 && (val & ~mask) != ~mask) { @@ -1734,13 +1890,26 @@ offset_in_range (offsetT val, int size) return val & mask; } -/* Returns 0 if attempting to add a prefix where one from the same - class already exists, 1 if non rep/repne added, 2 if rep/repne - added. */ -static int +enum PREFIX_GROUP +{ + PREFIX_EXIST = 0, + PREFIX_LOCK, + PREFIX_REP, + PREFIX_OTHER +}; + +/* Returns + a. PREFIX_EXIST if attempting to add a prefix where one from the + same class already exists. + b. PREFIX_LOCK if lock prefix is added. + c. PREFIX_REP if rep/repne prefix is added. + d. PREFIX_OTHER if other prefix is added. + */ + +static enum PREFIX_GROUP add_prefix (unsigned int prefix) { - int ret = 1; + enum PREFIX_GROUP ret = PREFIX_OTHER; unsigned int q; if (prefix >= REX_OPCODE && prefix < REX_OPCODE + 16 @@ -1749,7 +1918,7 @@ add_prefix (unsigned int prefix) if ((i.prefix[REX_PREFIX] & prefix & REX_W) || ((i.prefix[REX_PREFIX] & (REX_R | REX_X | REX_B)) && (prefix & (REX_R | REX_X | REX_B)))) - ret = 0; + ret = PREFIX_EXIST; q = REX_PREFIX; } else @@ -1770,10 +1939,13 @@ add_prefix (unsigned int prefix) case REPNE_PREFIX_OPCODE: case REPE_PREFIX_OPCODE: - ret = 2; - /* fall thru */ + q = REP_PREFIX; + ret = PREFIX_REP; + break; + case LOCK_PREFIX_OPCODE: - q = LOCKREP_PREFIX; + q = LOCK_PREFIX; + ret = PREFIX_LOCK; break; case FWAIT_OPCODE: @@ -1789,7 +1961,7 @@ add_prefix (unsigned int prefix) break; } if (i.prefix[q] != 0) - ret = 0; + ret = PREFIX_EXIST; } if (ret) @@ -1805,9 +1977,11 @@ add_prefix (unsigned int prefix) } static void -set_code_flag (int value) +update_code_flag (int value, int check) { - flag_code = value; + PRINTF_LIKE ((*as_error)); + + flag_code = (enum flag_code) value; if (flag_code == CODE_64BIT) { cpu_arch_flags.bitfield.cpu64 = 1; @@ -1820,19 +1994,35 @@ set_code_flag (int value) } if (value == CODE_64BIT && !cpu_arch_flags.bitfield.cpulm ) { - as_bad (_("64bit mode not supported on this CPU.")); + if (check) + as_error = as_fatal; + else + as_error = as_bad; + (*as_error) (_("64bit mode not supported on `%s'."), + cpu_arch_name ? cpu_arch_name : default_arch); } if (value == CODE_32BIT && !cpu_arch_flags.bitfield.cpui386) { - as_bad (_("32bit mode not supported on this CPU.")); + if (check) + as_error = as_fatal; + else + as_error = as_bad; + (*as_error) (_("32bit mode not supported on `%s'."), + cpu_arch_name ? cpu_arch_name : default_arch); } stackop_size = '\0'; } +static void +set_code_flag (int value) +{ + update_code_flag (value, 0); +} + static void set_16bit_gcc_code_flag (int new_code_flag) { - flag_code = new_code_flag; + flag_code = (enum flag_code) new_code_flag; if (flag_code != CODE_16BIT) abort (); cpu_arch_flags.bitfield.cpu64 = 0; @@ -1915,6 +2105,40 @@ set_sse_check (int dummy ATTRIBUTE_UNUSED) demand_empty_rest_of_line (); } +static void +check_cpu_arch_compatible (const char *name ATTRIBUTE_UNUSED, + i386_cpu_flags new_flag ATTRIBUTE_UNUSED) +{ +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + static const char *arch; + + /* Intel LIOM is only supported on ELF. */ + if (!IS_ELF) + return; + + if (!arch) + { + /* Use cpu_arch_name if it is set in md_parse_option. Otherwise + use default_arch. */ + arch = cpu_arch_name; + if (!arch) + arch = default_arch; + } + + /* If we are targeting Intel L1OM, we must enable it. */ + if (get_elf_backend_data (stdoutput)->elf_machine_code != EM_L1OM + || new_flag.bitfield.cpul1om) + return; + + /* If we are targeting Intel K1OM, we must enable it. */ + if (get_elf_backend_data (stdoutput)->elf_machine_code != EM_K1OM + || new_flag.bitfield.cpuk1om) + return; + + as_bad (_("`%s' is not supported on `%s'"), name, arch); +#endif +} + static void set_cpu_arch (int dummy ATTRIBUTE_UNUSED) { @@ -1924,18 +2148,20 @@ set_cpu_arch (int dummy ATTRIBUTE_UNUSED) { char *string = input_line_pointer; int e = get_symbol_end (); - unsigned int i; + unsigned int j; i386_cpu_flags flags; - for (i = 0; i < ARRAY_SIZE (cpu_arch); i++) + for (j = 0; j < ARRAY_SIZE (cpu_arch); j++) { - if (strcmp (string, cpu_arch[i].name) == 0) + if (strcmp (string, cpu_arch[j].name) == 0) { + check_cpu_arch_compatible (string, cpu_arch[j].flags); + if (*string != '.') { - cpu_arch_name = cpu_arch[i].name; + cpu_arch_name = cpu_arch[j].name; cpu_sub_arch_name = NULL; - cpu_arch_flags = cpu_arch[i].flags; + cpu_arch_flags = cpu_arch[j].flags; if (flag_code == CODE_64BIT) { cpu_arch_flags.bitfield.cpu64 = 1; @@ -1946,8 +2172,8 @@ set_cpu_arch (int dummy ATTRIBUTE_UNUSED) cpu_arch_flags.bitfield.cpu64 = 0; cpu_arch_flags.bitfield.cpuno64 = 1; } - cpu_arch_isa = cpu_arch[i].type; - cpu_arch_isa_flags = cpu_arch[i].flags; + cpu_arch_isa = cpu_arch[j].type; + cpu_arch_isa_flags = cpu_arch[j].flags; if (!cpu_arch_tune_set) { cpu_arch_tune = cpu_arch_isa; @@ -1956,28 +2182,33 @@ set_cpu_arch (int dummy ATTRIBUTE_UNUSED) break; } - flags = cpu_flags_or (cpu_arch_flags, - cpu_arch[i].flags); + if (!cpu_arch[j].negated) + flags = cpu_flags_or (cpu_arch_flags, + cpu_arch[j].flags); + else + flags = cpu_flags_and_not (cpu_arch_flags, + cpu_arch[j].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, + cpu_arch[j].name, (const char *) NULL); free (name); } else - cpu_sub_arch_name = xstrdup (cpu_arch[i].name); + cpu_sub_arch_name = xstrdup (cpu_arch[j].name); cpu_arch_flags = flags; + cpu_arch_isa_flags = flags; } *input_line_pointer = e; demand_empty_rest_of_line (); return; } } - if (i >= ARRAY_SIZE (cpu_arch)) + if (j >= ARRAY_SIZE (cpu_arch)) as_bad (_("no such architecture: `%s'"), string); *input_line_pointer = e; @@ -2005,19 +2236,59 @@ set_cpu_arch (int dummy ATTRIBUTE_UNUSED) demand_empty_rest_of_line (); } +enum bfd_architecture +i386_arch (void) +{ + if (cpu_arch_isa == PROCESSOR_L1OM) + { + if (OUTPUT_FLAVOR != bfd_target_elf_flavour + || flag_code != CODE_64BIT) + as_fatal (_("Intel L1OM is 64bit ELF only")); + return bfd_arch_l1om; + } + else if (cpu_arch_isa == PROCESSOR_K1OM) + { + if (OUTPUT_FLAVOR != bfd_target_elf_flavour + || flag_code != CODE_64BIT) + as_fatal (_("Intel K1OM is 64bit ELF only")); + return bfd_arch_k1om; + } + else + return bfd_arch_i386; +} + unsigned long -i386_mach () +i386_mach (void) { - if (!strcmp (default_arch, "x86_64")) - return bfd_mach_x86_64; + if (!strncmp (default_arch, "x86_64", 6)) + { + if (cpu_arch_isa == PROCESSOR_L1OM) + { + if (OUTPUT_FLAVOR != bfd_target_elf_flavour + || default_arch[6] != '\0') + as_fatal (_("Intel L1OM is 64bit ELF only")); + return bfd_mach_l1om; + } + else if (cpu_arch_isa == PROCESSOR_K1OM) + { + if (OUTPUT_FLAVOR != bfd_target_elf_flavour + || default_arch[6] != '\0') + as_fatal (_("Intel K1OM is 64bit ELF only")); + return bfd_mach_k1om; + } + else if (default_arch[6] == '\0') + return bfd_mach_x86_64; + else + return bfd_mach_x64_32; + } else if (!strcmp (default_arch, "i386")) return bfd_mach_i386_i386; else - as_fatal (_("Unknown architecture")); + as_fatal (_("unknown architecture")); } void -md_begin () +md_begin (void) { const char *hash_err; @@ -2025,7 +2296,7 @@ md_begin () op_hash = hash_new (); { - const template *optab; + const insn_template *optab; templates *core_optab; /* Setup for loop. */ @@ -2047,7 +2318,7 @@ md_begin () (void *) core_optab); if (hash_err) { - as_fatal (_("Internal Error: Can't hash %s: %s"), + as_fatal (_("internal Error: Can't hash %s: %s"), (optab - 1)->name, hash_err); } @@ -2069,7 +2340,7 @@ md_begin () { hash_err = hash_insert (reg_hash, regtab->reg_name, (void *) regtab); if (hash_err) - as_fatal (_("Internal Error: Can't hash %s: %s"), + as_fatal (_("internal Error: Can't hash %s: %s"), regtab->reg_name, hash_err); } @@ -2140,7 +2411,12 @@ md_begin () if (flag_code == CODE_64BIT) { +#if defined (OBJ_COFF) && defined (TE_PE) + x86_dwarf2_return_column = (OUTPUT_FLAVOR == bfd_target_coff_flavour + ? 32 : 16); +#else x86_dwarf2_return_column = 16; +#endif x86_cie_data_alignment = -8; } else @@ -2160,7 +2436,7 @@ i386_print_statistics (FILE *file) #ifdef DEBUG386 /* Debugging routines for md_assemble. */ -static void pte (template *); +static void pte (insn_template *); static void pt (i386_operand_type); static void pe (expressionS *); static void ps (symbolS *); @@ -2168,7 +2444,7 @@ static void ps (symbolS *); static void pi (char *line, i386_insn *x) { - unsigned int i; + unsigned int j; fprintf (stdout, "%s: template ", line); pte (&x->tm); @@ -2185,35 +2461,35 @@ pi (char *line, i386_insn *x) (x->rex & REX_R) != 0, (x->rex & REX_X) != 0, (x->rex & REX_B) != 0); - for (i = 0; i < x->operands; i++) + for (j = 0; j < x->operands; j++) { - fprintf (stdout, " #%d: ", i + 1); - pt (x->types[i]); + fprintf (stdout, " #%d: ", j + 1); + pt (x->types[j]); fprintf (stdout, "\n"); - if (x->types[i].bitfield.reg8 - || x->types[i].bitfield.reg16 - || x->types[i].bitfield.reg32 - || 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 - || x->types[i].bitfield.debug - || x->types[i].bitfield.test) - fprintf (stdout, "%s\n", x->op[i].regs->reg_name); - if (operand_type_check (x->types[i], imm)) - pe (x->op[i].imms); - if (operand_type_check (x->types[i], disp)) - pe (x->op[i].disps); + if (x->types[j].bitfield.reg8 + || x->types[j].bitfield.reg16 + || x->types[j].bitfield.reg32 + || x->types[j].bitfield.reg64 + || x->types[j].bitfield.regmmx + || x->types[j].bitfield.regxmm + || x->types[j].bitfield.regymm + || x->types[j].bitfield.sreg2 + || x->types[j].bitfield.sreg3 + || x->types[j].bitfield.control + || x->types[j].bitfield.debug + || x->types[j].bitfield.test) + fprintf (stdout, "%s\n", x->op[j].regs->reg_name); + if (operand_type_check (x->types[j], imm)) + pe (x->op[j].imms); + if (operand_type_check (x->types[j], disp)) + pe (x->op[j].disps); } } static void -pte (template *t) +pte (insn_template *t) { - unsigned int i; + unsigned int j; fprintf (stdout, " %d operands ", t->operands); fprintf (stdout, "opcode %x ", t->base_opcode); if (t->extension_opcode != None) @@ -2223,10 +2499,10 @@ pte (template *t) if (t->opcode_modifier.w) fprintf (stdout, "W"); fprintf (stdout, "\n"); - for (i = 0; i < t->operands; i++) + for (j = 0; j < t->operands; j++) { - fprintf (stdout, " #%d type ", i + 1); - pt (t->operand_types[i]); + fprintf (stdout, " #%d type ", j + 1); + pt (t->operand_types[j]); fprintf (stdout, "\n"); } } @@ -2326,7 +2602,7 @@ reloc (unsigned int size, { if (other != NO_RELOC) { - reloc_howto_type *reloc; + reloc_howto_type *rel; if (size == 8) switch (other) @@ -2354,21 +2630,21 @@ reloc (unsigned int size, } /* Sign-checking 4-byte relocations in 16-/32-bit code is pointless. */ - if (size == 4 && flag_code != CODE_64BIT) + if (size == 4 && (flag_code != CODE_64BIT || disallow_64bit_reloc)) sign = -1; - reloc = bfd_reloc_type_lookup (stdoutput, other); - if (!reloc) + rel = bfd_reloc_type_lookup (stdoutput, other); + if (!rel) as_bad (_("unknown relocation (%u)"), other); - else if (size != bfd_get_reloc_size (reloc)) + else if (size != bfd_get_reloc_size (rel)) as_bad (_("%u-byte relocation cannot be applied to %u-byte field"), - bfd_get_reloc_size (reloc), + bfd_get_reloc_size (rel), size); - else if (pcrel && !reloc->pc_relative) + else if (pcrel && !rel->pc_relative) as_bad (_("non-pc-relative relocation for pc-relative field")); - else if ((reloc->complain_on_overflow == complain_overflow_signed + else if ((rel->complain_on_overflow == complain_overflow_signed && !sign) - || (reloc->complain_on_overflow == complain_overflow_unsigned + || (rel->complain_on_overflow == complain_overflow_unsigned && sign > 0)) as_bad (_("relocated field and relocation type differ in signedness")); else @@ -2466,10 +2742,6 @@ 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; } @@ -2530,7 +2802,7 @@ intel_float_operand (const char *mnemonic) /* Build the VEX prefix. */ static void -build_vex_prefix (const template *t) +build_vex_prefix (const insn_template *t) { unsigned int register_specifier; unsigned int implied_prefix; @@ -2551,7 +2823,7 @@ build_vex_prefix (const template *t) operand. */ if (!i.swap_operand && i.operands == i.reg_operands - && i.tm.opcode_modifier.vex0f + && i.tm.opcode_modifier.vexopcode == VEX0F && i.tm.opcode_modifier.s && i.rex == REX_B) { @@ -2577,7 +2849,10 @@ build_vex_prefix (const template *t) i.tm = t[1]; } - vector_length = i.tm.opcode_modifier.vex256 ? 1 : 0; + if (i.tm.opcode_modifier.vex == VEXScalar) + vector_length = avxscalar; + else + vector_length = i.tm.opcode_modifier.vex == VEX256 ? 1 : 0; switch ((i.tm.base_opcode >> 8) & 0xff) { @@ -2598,7 +2873,8 @@ build_vex_prefix (const template *t) } /* Use 2-byte VEX prefix if possible. */ - if (i.tm.opcode_modifier.vex0f + if (i.tm.opcode_modifier.vexopcode == VEX0F + && i.tm.opcode_modifier.vexw != VEXW1 && (i.rex & (REX_W | REX_X | REX_B)) == 0) { /* 2-byte VEX prefix. */ @@ -2619,17 +2895,37 @@ build_vex_prefix (const template *t) /* 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; + + switch (i.tm.opcode_modifier.vexopcode) + { + case VEX0F: + m = 0x1; + i.vex.bytes[0] = 0xc4; + break; + case VEX0F38: + m = 0x2; + i.vex.bytes[0] = 0xc4; + break; + case VEX0F3A: + m = 0x3; + i.vex.bytes[0] = 0xc4; + break; + case XOP08: + m = 0x8; + i.vex.bytes[0] = 0x8f; + break; + case XOP09: + m = 0x9; + i.vex.bytes[0] = 0x8f; + break; + case XOP0A: + m = 0xa; + i.vex.bytes[0] = 0x8f; + break; + default: + abort (); + } /* The high 3 bits of the second VEX byte are 1's compliment of RXB bits from REX. */ @@ -2637,12 +2933,12 @@ build_vex_prefix (const template *t) /* Check the REX.W bit. */ w = (i.rex & REX_W) ? 1 : 0; - if (i.tm.opcode_modifier.vexw0 || i.tm.opcode_modifier.vexw1) + if (i.tm.opcode_modifier.vexw) { if (w) abort (); - if (i.tm.opcode_modifier.vexw1) + if (i.tm.opcode_modifier.vexw == VEXW1) w = 1; } @@ -2706,7 +3002,7 @@ md_assemble (char *line) { unsigned int j; char mnemonic[MAX_MNEM_SIZE]; - const template *t; + const insn_template *t; /* Initialize globals. */ memset (&i, '\0', sizeof (i)); @@ -2757,6 +3053,7 @@ md_assemble (char *line) /* Don't optimize displacement for movabs since it only takes 64bit displacement. */ if (i.disp_operands + && !i.disp32_encoding && (flag_code != CODE_64BIT || strcmp (mnemonic, "movabs") != 0)) optimize_disp (); @@ -2802,6 +3099,18 @@ md_assemble (char *line) if (!add_prefix (FWAIT_OPCODE)) return; + /* Check for lock without a lockable instruction. Destination operand + must be memory unless it is xchg (0x86). */ + if (i.prefix[LOCK_PREFIX] + && (!i.tm.opcode_modifier.islockable + || i.mem_operands == 0 + || (i.tm.base_opcode != 0x86 + && !operand_type_check (i.types[i.operands - 1], anymem)))) + { + as_bad (_("expecting lockable instruction after `lock'")); + return; + } + /* Check string instruction segment overrides. */ if (i.tm.opcode_modifier.isstring && i.mem_operands != 0) { @@ -2813,6 +3122,10 @@ md_assemble (char *line) 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 ()) @@ -2821,12 +3134,15 @@ md_assemble (char *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--; + /* 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 @@ -2848,8 +3164,12 @@ md_assemble (char *line) 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) + /* Handle conversion of 'int $3' --> special int3 insn. XOP or FMA4 + instructions may define INT_OPCODE as well, so avoid this corner + case for those instructions that use MODRM. */ + if (i.tm.base_opcode == INT_OPCODE + && !i.tm.opcode_modifier.modrm + && i.op[0].imms->X_add_number == 3) { i.tm.base_opcode = INT3_OPCODE; i.imm_operands = 0; @@ -2920,7 +3240,7 @@ parse_insn (char *line, char *mnemonic) char *token_start = l; char *mnem_p; int supported; - const template *t; + const insn_template *t; char *dot_p = NULL; /* Non-zero if we found a prefix only acceptable with string insns. */ @@ -2961,7 +3281,7 @@ parse_insn (char *line, char *mnemonic) } /* Look up instruction (or prefix) via hash table. */ - current_templates = hash_find (op_hash, mnemonic); + current_templates = (const templates *) hash_find (op_hash, mnemonic); if (*l != END_OF_INSN && (!is_space_char (*l) || l[1] != END_OF_INSN) @@ -2991,11 +3311,13 @@ parse_insn (char *line, char *mnemonic) /* Add prefix, checking for repeated prefixes. */ switch (add_prefix (current_templates->start->base_opcode)) { - case 0: + case PREFIX_EXIST: return NULL; - case 2: + case PREFIX_REP: expecting_string_instruction = current_templates->start->name; break; + default: + break; } /* Skip past PREFIX_SEPARATOR and reset token_start. */ token_start = ++l; @@ -3006,14 +3328,20 @@ parse_insn (char *line, char *mnemonic) if (!current_templates) { - /* Check if we should swap operand in encoding. */ + /* Check if we should swap operand or force 32bit displacement in + encoding. */ if (mnem_p - 2 == dot_p && dot_p[1] == 's') i.swap_operand = 1; + else if (mnem_p - 4 == dot_p + && dot_p[1] == 'd' + && dot_p[2] == '3' + && dot_p[3] == '2') + i.disp32_encoding = 1; else goto check_suffix; mnem_p = dot_p; *dot_p = '\0'; - current_templates = hash_find (op_hash, mnemonic); + current_templates = (const templates *) hash_find (op_hash, mnemonic); } if (!current_templates) @@ -3030,7 +3358,8 @@ check_suffix: case QWORD_MNEM_SUFFIX: i.suffix = mnem_p[-1]; mnem_p[-1] = '\0'; - current_templates = hash_find (op_hash, mnemonic); + current_templates = (const templates *) hash_find (op_hash, + mnemonic); break; case SHORT_MNEM_SUFFIX: case LONG_MNEM_SUFFIX: @@ -3038,7 +3367,8 @@ check_suffix: { i.suffix = mnem_p[-1]; mnem_p[-1] = '\0'; - current_templates = hash_find (op_hash, mnemonic); + current_templates = (const templates *) hash_find (op_hash, + mnemonic); } break; @@ -3051,7 +3381,8 @@ check_suffix: else i.suffix = LONG_MNEM_SUFFIX; mnem_p[-1] = '\0'; - current_templates = hash_find (op_hash, mnemonic); + current_templates = (const templates *) hash_find (op_hash, + mnemonic); } break; } @@ -3424,7 +3755,7 @@ optimize_imm (void) than those matching the insn suffix. */ { i386_operand_type mask, allowed; - const template *t; + const insn_template *t; operand_type_set (&mask, 0); operand_type_set (&allowed, 0); @@ -3472,28 +3803,28 @@ optimize_disp (void) { if (i.op[op].disps->X_op == O_constant) { - offsetT disp = i.op[op].disps->X_add_number; + offsetT op_disp = i.op[op].disps->X_add_number; if (i.types[op].bitfield.disp16 - && (disp & ~(offsetT) 0xffff) == 0) + && (op_disp & ~(offsetT) 0xffff) == 0) { /* If this operand is at most 16 bits, convert to a signed 16 bit number and don't use 64bit displacement. */ - disp = (((disp & 0xffff) ^ 0x8000) - 0x8000); + op_disp = (((op_disp & 0xffff) ^ 0x8000) - 0x8000); i.types[op].bitfield.disp64 = 0; } if (i.types[op].bitfield.disp32 - && (disp & ~(((offsetT) 2 << 31) - 1)) == 0) + && (op_disp & ~(((offsetT) 2 << 31) - 1)) == 0) { /* If this operand is at most 32 bits, convert to a signed 32 bit number and don't use 64bit displacement. */ - disp &= (((offsetT) 2 << 31) - 1); - disp = (disp ^ ((offsetT) 1 << 31)) - ((addressT) 1 << 31); + op_disp &= (((offsetT) 2 << 31) - 1); + op_disp = (op_disp ^ ((offsetT) 1 << 31)) - ((addressT) 1 << 31); i.types[op].bitfield.disp64 = 0; } - if (!disp && i.types[op].bitfield.baseindex) + if (!op_disp && i.types[op].bitfield.baseindex) { i.types[op].bitfield.disp8 = 0; i.types[op].bitfield.disp16 = 0; @@ -3505,18 +3836,19 @@ optimize_disp (void) } else if (flag_code == CODE_64BIT) { - if (fits_in_signed_long (disp)) + if (fits_in_signed_long (op_disp)) { i.types[op].bitfield.disp64 = 0; i.types[op].bitfield.disp32s = 1; } - if (fits_in_unsigned_long (disp)) + if (i.prefix[ADDR_PREFIX] + && fits_in_unsigned_long (op_disp)) i.types[op].bitfield.disp32 = 1; } if ((i.types[op].bitfield.disp32 || i.types[op].bitfield.disp32s || i.types[op].bitfield.disp16) - && fits_in_signed_byte (disp)) + && fits_in_signed_byte (op_disp)) i.types[op].bitfield.disp8 = 1; } else if (i.reloc[op] == BFD_RELOC_386_TLS_DESC_CALL @@ -3536,11 +3868,69 @@ optimize_disp (void) } } -static const template * +/* Check if operands are valid for the instruction. */ + +static int +check_VecOperands (const insn_template *t) +{ + /* Without VSIB byte, we can't have a vector register for index. */ + if (!t->opcode_modifier.vecsib + && i.index_reg + && (i.index_reg->reg_type.bitfield.regxmm + || i.index_reg->reg_type.bitfield.regymm)) + { + i.error = unsupported_vector_index_register; + return 1; + } + + /* For VSIB byte, we need a vector register for index and no PC + relative addressing is allowed. */ + if (t->opcode_modifier.vecsib + && (!i.index_reg + || !((t->opcode_modifier.vecsib == VecSIB128 + && i.index_reg->reg_type.bitfield.regxmm) + || (t->opcode_modifier.vecsib == VecSIB256 + && i.index_reg->reg_type.bitfield.regymm)) + || (i.base_reg && i.base_reg->reg_num == RegRip))) + { + i.error = invalid_vsib_address; + return 1; + } + + return 0; +} + +/* Check if operands are valid for the instruction. Update VEX + operand types. */ + +static int +VEX_check_operands (const insn_template *t) +{ + if (!t->opcode_modifier.vex) + return 0; + + /* Only check VEX_Imm4, which must be the first operand. */ + if (t->operand_types[0].bitfield.vec_imm4) + { + if (i.op[0].imms->X_op != O_constant + || !fits_in_imm4 (i.op[0].imms->X_add_number)) + { + i.error = bad_imm4; + return 1; + } + + /* Turn off Imm8 so that update_imm won't complain. */ + i.types[0] = vec_imm4; + } + + return 0; +} + +static const insn_template * match_template (void) { /* Points to template once we've found it. */ - const template *t; + const insn_template *t; i386_operand_type overlap0, overlap1, overlap2, overlap3; i386_operand_type overlap4; unsigned int found_reverse_match; @@ -3572,34 +3962,41 @@ match_template (void) else if (i.suffix == LONG_DOUBLE_MNEM_SUFFIX) suffix_check.no_ldsuf = 1; + /* Must have right number of operands. */ + i.error = number_of_operands_mismatch; + for (t = current_templates->start; t < current_templates->end; t++) { addr_prefix_disp = -1; - /* Must have right number of operands. */ if (i.operands != t->operands) continue; /* Check processor support. */ + i.error = unsupported; found_cpu_match = (cpu_flags_match (t) == CPU_FLAGS_PERFECT_MATCH); if (!found_cpu_match) continue; /* Check old gcc support. */ + i.error = old_gcc_only; if (!old_gcc && t->opcode_modifier.oldgcc) continue; /* Check AT&T mnemonic. */ + i.error = unsupported_with_intel_mnemonic; if (intel_mnemonic && t->opcode_modifier.attmnemonic) continue; - /* Check AT&T syntax Intel syntax. */ + /* Check AT&T/Intel syntax. */ + i.error = unsupported_syntax; if ((intel_syntax && t->opcode_modifier.attsyntax) || (!intel_syntax && t->opcode_modifier.intelsyntax)) continue; /* Check the suffix, except for some instructions in intel mode. */ + i.error = invalid_instruction_suffix; if ((!intel_syntax || !t->opcode_modifier.ignoresize) && ((t->opcode_modifier.no_bsuf && suffix_check.no_bsuf) || (t->opcode_modifier.no_wsuf && suffix_check.no_wsuf) @@ -3699,9 +4096,8 @@ match_template (void) } } - /* We check register size only if size of operands can be - encoded the canonical way. */ - check_register = t->opcode_modifier.w; + /* We check register size if needed. */ + check_register = t->opcode_modifier.checkregsize; overlap0 = operand_type_and (i.types[0], operand_types[0]); switch (t->operands) { @@ -3840,6 +4236,14 @@ check_reverse: continue; } + /* Check if vector operands are valid. */ + if (check_VecOperands (t)) + continue; + + /* Check if VEX operands are valid. */ + if (VEX_check_operands (t)) + continue; + /* We've found a match; break out of loop. */ break; } @@ -3847,12 +4251,50 @@ check_reverse: if (t == current_templates->end) { /* We found no match. */ - 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); + const char *err_msg; + switch (i.error) + { + default: + abort (); + case operand_size_mismatch: + err_msg = _("operand size mismatch"); + break; + case operand_type_mismatch: + err_msg = _("operand type mismatch"); + break; + case register_type_mismatch: + err_msg = _("register type mismatch"); + break; + case number_of_operands_mismatch: + err_msg = _("number of operands mismatch"); + break; + case invalid_instruction_suffix: + err_msg = _("invalid instruction suffix"); + break; + case bad_imm4: + err_msg = _("Imm4 isn't the first operand"); + break; + case old_gcc_only: + err_msg = _("only supported with old gcc"); + break; + case unsupported_with_intel_mnemonic: + err_msg = _("unsupported with Intel mnemonic"); + break; + case unsupported_syntax: + err_msg = _("unsupported syntax"); + break; + case unsupported: + err_msg = _("unsupported"); + break; + case invalid_vsib_address: + err_msg = _("invalid VSIB address"); + break; + case unsupported_vector_index_register: + err_msg = _("unsupported vector index register"); + break; + } + as_bad (_("%s for `%s'"), err_msg, + current_templates->start->name); return NULL; } @@ -4007,12 +4449,20 @@ process_suffix (void) } else if (i.suffix == BYTE_MNEM_SUFFIX) { - if (!check_byte_reg ()) + if (intel_syntax + && i.tm.opcode_modifier.ignoresize + && i.tm.opcode_modifier.no_bsuf) + i.suffix = 0; + else if (!check_byte_reg ()) return 0; } else if (i.suffix == LONG_MNEM_SUFFIX) { - if (!check_long_reg ()) + if (intel_syntax + && i.tm.opcode_modifier.ignoresize + && i.tm.opcode_modifier.no_lsuf) + i.suffix = 0; + else if (!check_long_reg ()) return 0; } else if (i.suffix == QWORD_MNEM_SUFFIX) @@ -4026,7 +4476,11 @@ process_suffix (void) } else if (i.suffix == WORD_MNEM_SUFFIX) { - if (!check_word_reg ()) + if (intel_syntax + && i.tm.opcode_modifier.ignoresize + && i.tm.opcode_modifier.no_wsuf) + i.suffix = 0; + else if (!check_word_reg ()) return 0; } else if (i.suffix == XMMWORD_MNEM_SUFFIX @@ -4204,10 +4658,6 @@ check_byte_reg (void) if (i.types[op].bitfield.reg8) continue; - /* Don't generate this warning if not needed. */ - if (intel_syntax && i.tm.opcode_modifier.byteokintel) - continue; - /* crc32 doesn't generate this warning. */ if (i.tm.base_opcode == 0xf20f38f0) continue; @@ -4222,7 +4672,7 @@ check_byte_reg (void) if (flag_code == CODE_64BIT && !i.tm.operand_types[op].bitfield.inoutportreg) { - as_bad (_("Incorrect register `%s%s' used with `%c' suffix"), + as_bad (_("incorrect register `%s%s' used with `%c' suffix"), register_prefix, i.op[op].regs->reg_name, i.suffix); return 0; @@ -4297,7 +4747,7 @@ check_long_reg (void) lowering is more complicated. */ if (flag_code == CODE_64BIT) { - as_bad (_("Incorrect register `%s%s' used with `%c' suffix"), + as_bad (_("incorrect register `%s%s' used with `%c' suffix"), register_prefix, i.op[op].regs->reg_name, i.suffix); return 0; @@ -4326,7 +4776,7 @@ check_long_reg (void) } else { - as_bad (_("Incorrect register `%s%s' used with `%c' suffix"), + as_bad (_("incorrect register `%s%s' used with `%c' suffix"), register_prefix, i.op[op].regs->reg_name, i.suffix); return 0; @@ -4372,7 +4822,7 @@ check_qword_reg (void) } else { - as_bad (_("Incorrect register `%s%s' used with `%c' suffix"), + as_bad (_("incorrect register `%s%s' used with `%c' suffix"), register_prefix, i.op[op].regs->reg_name, i.suffix); return 0; @@ -4410,7 +4860,7 @@ check_word_reg (void) lowering is more complicated. */ if (flag_code == CODE_64BIT) { - as_bad (_("Incorrect register `%s%s' used with `%c' suffix"), + as_bad (_("incorrect register `%s%s' used with `%c' suffix"), register_prefix, i.op[op].regs->reg_name, i.suffix); return 0; @@ -4431,9 +4881,7 @@ 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 @@ -4497,14 +4945,19 @@ 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]); - gas_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; } @@ -4512,13 +4965,14 @@ finalize_imm (void) static int bad_implicit_operand (int xmm) { - const char *reg = xmm ? "xmm0" : "ymm0"; + const char *ireg = xmm ? "xmm0" : "ymm0"; + if (intel_syntax) as_bad (_("the last operand of `%s' must be `%s%s'"), - i.tm.name, register_prefix, reg); + i.tm.name, register_prefix, ireg); else as_bad (_("the first operand of `%s' must be `%s%s'"), - i.tm.name, register_prefix, reg); + i.tm.name, register_prefix, ireg); return 0; } @@ -4530,17 +4984,15 @@ process_operands (void) unnecessary segment overrides. */ const seg_entry *default_seg = 0; - if (i.tm.opcode_modifier.sse2avx - && (i.tm.opcode_modifier.vexnds - || i.tm.opcode_modifier.vexndd)) + if (i.tm.opcode_modifier.sse2avx && i.tm.opcode_modifier.vexvvvv) { - unsigned int dup = i.operands; - unsigned int dest = dup - 1; + unsigned int dupl = i.operands; + unsigned int dest = dupl - 1; unsigned int j; /* The destination must be an xmm register. */ gas_assert (i.reg_operands - && MAX_OPERANDS > dup + && MAX_OPERANDS > dupl && operand_type_equal (&i.types[dest], ®xmm)); if (i.tm.opcode_modifier.firstxmm0) @@ -4550,7 +5002,7 @@ process_operands (void) if (i.op[0].regs->reg_num != 0) return bad_implicit_operand (1); - if (i.tm.opcode_modifier.vex3sources) + if (i.tm.opcode_modifier.vexsources == VEX3SOURCES) { /* Keep xmm0 for instructions with VEX prefix and 3 sources. */ @@ -4571,8 +5023,9 @@ process_operands (void) } else if (i.tm.opcode_modifier.implicit1stxmm0) { - gas_assert ((MAX_OPERANDS - 1) > dup - && i.tm.opcode_modifier.vex3sources); + gas_assert ((MAX_OPERANDS - 1) > dupl + && (i.tm.opcode_modifier.vexsources + == VEX3SOURCES)); /* Add the implicit xmm0 for instructions with VEX prefix and 3 sources. */ @@ -4591,11 +5044,11 @@ process_operands (void) i.reg_operands += 2; i.tm.operands += 2; - dup++; + dupl++; dest++; - i.op[dup] = i.op[dest]; - i.types[dup] = i.types[dest]; - i.tm.operand_types[dup] = i.tm.operand_types[dest]; + i.op[dupl] = i.op[dest]; + i.types[dupl] = i.types[dest]; + i.tm.operand_types[dupl] = i.tm.operand_types[dest]; } else { @@ -4604,9 +5057,9 @@ duplicate: 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]; + i.op[dupl] = i.op[dest]; + i.types[dupl] = i.types[dest]; + i.tm.operand_types[dupl] = i.tm.operand_types[dest]; } if (i.tm.opcode_modifier.immext) @@ -4754,67 +5207,130 @@ build_modrm_byte (void) /* The first operand of instructions with VEX prefix and 3 sources must be VEX_Imm4. */ - vex_3_sources = i.tm.opcode_modifier.vex3sources; + vex_3_sources = i.tm.opcode_modifier.vexsources == VEX3SOURCES; if (vex_3_sources) { - unsigned int nds, reg; + unsigned int nds, reg_slot; + expressionS *exp; if (i.tm.opcode_modifier.veximmext - && i.tm.opcode_modifier.immext) - { - dest = i.operands - 2; - gas_assert (dest == 3); - } + && i.tm.opcode_modifier.immext) + { + dest = i.operands - 2; + gas_assert (dest == 3); + } else - dest = i.operands - 1; + 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. */ + /* There are 2 kinds of instructions: + 1. 5 operands: 4 register operands or 3 register operands + plus 1 memory operand plus one Vec_Imm4 operand, VexXDS, and + VexW0 or VexW1. The destination must be either XMM or YMM + register. + 2. 4 operands: 4 register operands or 3 register operands + plus 1 memory operand, VexXDS, 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; - } + || (i.reg_operands == 3 && i.mem_operands == 1)) + && i.tm.opcode_modifier.vexvvvv == VEXXDS + && (i.tm.opcode_modifier.veximmext + || (i.imm_operands == 1 + && i.types[0].bitfield.vec_imm4 + && (i.tm.opcode_modifier.vexw == VEXW0 + || i.tm.opcode_modifier.vexw == VEXW1) + && (operand_type_equal (&i.tm.operand_types[dest], ®xmm) + || operand_type_equal (&i.tm.operand_types[dest], ®ymm))))); + + if (i.imm_operands == 0) + { + /* When there is no immediate operand, generate an 8bit + immediate operand to encode the first operand. */ + 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.vexw == VEXW1) + { + source = 0; + reg_slot = 1; + } + else + { + source = 1; + reg_slot = 0; + } + + /* FMA swaps REG and NDS. */ + if (i.tm.cpu_flags.bitfield.cpufma) + { + unsigned int tmp; + tmp = reg_slot; + reg_slot = nds; + nds = tmp; + } + + gas_assert (operand_type_equal (&i.tm.operand_types[reg_slot], + ®xmm) + || operand_type_equal (&i.tm.operand_types[reg_slot], + ®ymm)); + exp->X_op = O_constant; + exp->X_add_number + = ((i.op[reg_slot].regs->reg_num + + ((i.op[reg_slot].regs->reg_flags & RegRex) ? 8 : 0)) + << 4); + } 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); + { + unsigned int imm_slot; + + if (i.tm.opcode_modifier.vexw == VEXW0) + { + /* If VexW0 is set, the third operand is the source and + the second operand is encoded in the immediate + operand. */ + source = 2; + reg_slot = 1; + } + else + { + /* VexW1 is set, the second operand is the source and + the third operand is encoded in the immediate + operand. */ + source = 1; + reg_slot = 2; + } + + if (i.tm.opcode_modifier.immext) + { + /* When ImmExt is set, the immdiate byte is the last + operand. */ + imm_slot = i.operands - 1; + source--; + reg_slot--; + } + else + { + imm_slot = 0; + + /* Turn on Imm8 so that output_imm will generate it. */ + i.types[imm_slot].bitfield.imm8 = 1; + } + + gas_assert (operand_type_equal (&i.tm.operand_types[reg_slot], + ®xmm) + || operand_type_equal (&i.tm.operand_types[reg_slot], + ®ymm)); + i.op[imm_slot].imms->X_add_number + |= ((i.op[reg_slot].regs->reg_num + + ((i.op[reg_slot].regs->reg_flags & RegRex) ? 8 : 0)) + << 4); + } + + gas_assert (operand_type_equal (&i.tm.operand_types[nds], ®xmm) + || operand_type_equal (&i.tm.operand_types[nds], + ®ymm)); i.vex.register_specifier = i.op[nds].regs; } else @@ -4828,9 +5344,9 @@ build_modrm_byte (void) a instruction with VEX prefix and 3 sources. */ if (i.mem_operands == 0 && ((i.reg_operands == 2 - && !i.tm.opcode_modifier.vexndd) + && i.tm.opcode_modifier.vexvvvv <= VEXXDS) || (i.reg_operands == 3 - && i.tm.opcode_modifier.vexnds) + && i.tm.opcode_modifier.vexvvvv == VEXXDS) || (i.reg_operands == 4 && vex_3_sources))) { switch (i.operands) @@ -4845,7 +5361,7 @@ build_modrm_byte (void) is an instruction with VexNDS. */ gas_assert (i.imm_operands == 1 || (i.imm_operands == 0 - && (i.tm.opcode_modifier.vexnds + && (i.tm.opcode_modifier.vexvvvv == VEXXDS || i.types[0].bitfield.shiftcount))); if (operand_type_check (i.types[0], imm) || i.types[0].bitfield.shiftcount) @@ -4864,19 +5380,19 @@ build_modrm_byte (void) gas_assert ((i.imm_operands == 2 && i.types[0].bitfield.imm8 && i.types[1].bitfield.imm8) - || (i.tm.opcode_modifier.vexnds + || (i.tm.opcode_modifier.vexvvvv == VEXXDS && i.imm_operands == 1 && (i.types[0].bitfield.imm8 || i.types[i.operands - 1].bitfield.imm8))); - if (i.tm.opcode_modifier.vexnds) + if (i.imm_operands == 2) + source = 2; + else { if (i.types[0].bitfield.imm8) source = 1; else source = 0; } - else - source = 2; break; case 5: break; @@ -4888,19 +5404,37 @@ build_modrm_byte (void) { dest = source + 1; - if (i.tm.opcode_modifier.vexnds) + if (i.tm.opcode_modifier.vexvvvv == VEXXDS) { /* 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]; + source operand must be 32/64bit integer, 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; + unsigned int vvvv; + + /* Check register-only source operand when two source + operands are swapped. */ + if (!i.tm.operand_types[source].bitfield.baseindex + && i.tm.operand_types[dest].bitfield.baseindex) + { + vvvv = source; + source = dest; + } + else + vvvv = dest; + + op = i.tm.operand_types[vvvv]; op.bitfield.regmem = 0; if ((dest + 1) >= i.operands - || (!operand_type_equal (&op, ®xmm) + || (op.bitfield.reg32 != 1 + && !op.bitfield.reg64 != 1 + && !operand_type_equal (&op, ®xmm) && !operand_type_equal (&op, ®ymm))) abort (); - i.vex.register_specifier = i.op[dest].regs; + i.vex.register_specifier = i.op[vvvv].regs; dest++; } } @@ -4954,15 +5488,53 @@ build_modrm_byte (void) break; gas_assert (op < i.operands); + if (i.tm.opcode_modifier.vecsib) + { + if (i.index_reg->reg_num == RegEiz + || i.index_reg->reg_num == RegRiz) + abort (); + + i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; + if (!i.base_reg) + { + i.sib.base = NO_BASE_REGISTER; + i.sib.scale = i.log2_scale_factor; + i.types[op].bitfield.disp8 = 0; + i.types[op].bitfield.disp16 = 0; + i.types[op].bitfield.disp64 = 0; + if (flag_code != CODE_64BIT) + { + /* Must be 32 bit */ + i.types[op].bitfield.disp32 = 1; + i.types[op].bitfield.disp32s = 0; + } + else + { + i.types[op].bitfield.disp32 = 0; + i.types[op].bitfield.disp32s = 1; + } + } + i.sib.index = i.index_reg->reg_num; + if ((i.index_reg->reg_flags & RegRex) != 0) + i.rex |= REX_X; + } + default_seg = &ds; if (i.base_reg == 0) { i.rm.mode = 0; if (!i.disp_operands) - fake_zero_displacement = 1; + { + fake_zero_displacement = 1; + /* Instructions with VSIB byte need 32bit displacement + if there is no base register. */ + if (i.tm.opcode_modifier.vecsib) + i.types[op].bitfield.disp32 = 1; + } if (i.index_reg == 0) { + gas_assert (!i.tm.opcode_modifier.vecsib); /* Operand is just */ if (flag_code == CODE_64BIT) { @@ -4988,8 +5560,9 @@ build_modrm_byte (void) i.types[op] = disp32; } } - else /* !i.base_reg && i.index_reg */ + else if (!i.tm.opcode_modifier.vecsib) { + /* !i.base_reg && i.index_reg */ if (i.index_reg->reg_num == RegEiz || i.index_reg->reg_num == RegRiz) i.sib.index = NO_INDEX_REGISTER; @@ -5020,6 +5593,7 @@ build_modrm_byte (void) else if (i.base_reg->reg_num == RegRip || i.base_reg->reg_num == RegEip) { + gas_assert (!i.tm.opcode_modifier.vecsib); i.rm.regmem = NO_BASE_REGISTER; i.types[op].bitfield.disp8 = 0; i.types[op].bitfield.disp16 = 0; @@ -5032,6 +5606,7 @@ build_modrm_byte (void) } else if (i.base_reg->reg_type.bitfield.reg16) { + gas_assert (!i.tm.opcode_modifier.vecsib); switch (i.base_reg->reg_num) { case 3: /* (%bx) */ @@ -5075,7 +5650,8 @@ build_modrm_byte (void) i.types[op].bitfield.disp32 = 1; } - i.rm.regmem = i.base_reg->reg_num; + if (!i.tm.opcode_modifier.vecsib) + i.rm.regmem = i.base_reg->reg_num; if ((i.base_reg->reg_flags & RegRex) != 0) i.rex |= REX_B; i.sib.base = i.base_reg->reg_num; @@ -5097,6 +5673,7 @@ build_modrm_byte (void) i.sib.scale = i.log2_scale_factor; if (i.index_reg == 0) { + gas_assert (!i.tm.opcode_modifier.vecsib); /* (%esp) becomes two byte modrm with no index register. We've already stored the code for esp in i.rm.regmem ie. ESCAPE_TO_TWO_BYTE_ADDRESSING. @@ -5104,7 +5681,7 @@ build_modrm_byte (void) extra modrm byte. */ i.sib.index = NO_INDEX_REGISTER; } - else + else if (!i.tm.opcode_modifier.vecsib) { if (i.index_reg->reg_num == RegEiz || i.index_reg->reg_num == RegRiz) @@ -5144,11 +5721,56 @@ build_modrm_byte (void) else mem = ~0; + if (i.tm.opcode_modifier.vexsources == XOP2SOURCES) + { + if (operand_type_check (i.types[0], imm)) + i.vex.register_specifier = NULL; + else + { + /* VEX.vvvv encodes one of the sources when the first + operand is not an immediate. */ + if (i.tm.opcode_modifier.vexw == VEXW0) + i.vex.register_specifier = i.op[0].regs; + else + i.vex.register_specifier = i.op[1].regs; + } + + /* Destination is a XMM register encoded in the ModRM.reg + and VEX.R bit. */ + i.rm.reg = i.op[2].regs->reg_num; + if ((i.op[2].regs->reg_flags & RegRex) != 0) + i.rex |= REX_R; + + /* ModRM.rm and VEX.B encodes the other source. */ + if (!i.mem_operands) + { + i.rm.mode = 3; + + if (i.tm.opcode_modifier.vexw == VEXW0) + i.rm.regmem = i.op[1].regs->reg_num; + else + i.rm.regmem = i.op[0].regs->reg_num; + + if ((i.op[1].regs->reg_flags & RegRex) != 0) + i.rex |= REX_B; + } + } + else if (i.tm.opcode_modifier.vexvvvv == VEXLWP) + { + i.vex.register_specifier = i.op[2].regs; + if (!i.mem_operands) + { + i.rm.mode = 3; + i.rm.regmem = i.op[1].regs->reg_num; + if ((i.op[1].regs->reg_flags & RegRex) != 0) + i.rex |= REX_B; + } + } /* 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 careful to make sure that segment/control/debug/test/MMX registers are coded into the i.rm.reg field. */ - if (i.reg_operands) + else if (i.reg_operands) { unsigned int op; unsigned int vex_reg = ~0; @@ -5170,7 +5792,7 @@ build_modrm_byte (void) if (vex_3_sources) op = dest; - else if (i.tm.opcode_modifier.vexnds) + else if (i.tm.opcode_modifier.vexvvvv == VEXXDS) { /* For instructions with VexNDS, the register-only source operand is encoded in VEX prefix. */ @@ -5183,47 +5805,73 @@ build_modrm_byte (void) } else { - vex_reg = op + 1; - gas_assert (vex_reg < i.operands); + /* Check register-only source operand when two source + operands are swapped. */ + if (!i.tm.operand_types[op].bitfield.baseindex + && i.tm.operand_types[op + 1].bitfield.baseindex) + { + vex_reg = op; + op += 2; + gas_assert (mem == (vex_reg + 1) + && op < i.operands); + } + else + { + vex_reg = op + 1; + gas_assert (vex_reg < i.operands); + } } } - else if (i.tm.opcode_modifier.vexndd) + else if (i.tm.opcode_modifier.vexvvvv == VEXNDD) { - /* For instructions with VexNDD, there should be - no memory operand and the register destination + /* For instructions with VexNDD, the register destination is encoded in VEX prefix. */ - gas_assert (i.mem_operands == 0 - && (op + 2) == i.operands); - vex_reg = op + 1; + if (i.mem_operands == 0) + { + /* There is no memory operand. */ + gas_assert ((op + 2) == i.operands); + vex_reg = op + 1; + } + else + { + /* There are only 2 operands. */ + gas_assert (op < 2 && i.operands == 2); + vex_reg = 1; + } } else gas_assert (op < i.operands); if (vex_reg != (unsigned int) ~0) { - gas_assert (i.reg_operands == 2); + i386_operand_type *type = &i.tm.operand_types[vex_reg]; - if (!operand_type_equal (&i.tm.operand_types[vex_reg], - & regxmm) - && !operand_type_equal (&i.tm.operand_types[vex_reg], - ®ymm)) + if (type->bitfield.reg32 != 1 + && type->bitfield.reg64 != 1 + && !operand_type_equal (type, ®xmm) + && !operand_type_equal (type, ®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) + /* Don't set OP operand twice. */ + if (vex_reg != op) { - 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; + /* 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 @@ -5244,15 +5892,15 @@ static void output_branch (void) { char *p; + int size; int code16; int prefix; relax_substateT subtype; symbolS *sym; offsetT off; - code16 = 0; - if (flag_code == CODE_16BIT) - code16 = CODE16; + code16 = flag_code == CODE_16BIT ? CODE16 : 0; + size = i.disp32_encoding ? BIG : SMALL; prefix = 0; if (i.prefix[DATA_PREFIX] != 0) @@ -5295,11 +5943,11 @@ output_branch (void) *p = i.tm.base_opcode; if ((unsigned char) *p == JUMP_PC_RELATIVE) - subtype = ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL); + subtype = ENCODE_RELAX_STATE (UNCOND_JUMP, size); else if (cpu_arch_flags.bitfield.cpui386) - subtype = ENCODE_RELAX_STATE (COND_JUMP, SMALL); + subtype = ENCODE_RELAX_STATE (COND_JUMP, size); else - subtype = ENCODE_RELAX_STATE (COND_JUMP86, SMALL); + subtype = ENCODE_RELAX_STATE (COND_JUMP86, size); subtype |= code16; sym = i.op[0].disps->X_add_symbol; @@ -5499,7 +6147,7 @@ output_insn (void) { check_prefix: if (prefix != REPE_PREFIX_OPCODE - || (i.prefix[LOCKREP_PREFIX] + || (i.prefix[REP_PREFIX] != REPE_PREFIX_OPCODE)) add_prefix (prefix); } @@ -5881,7 +6529,8 @@ x86_cons_fix_new (fragS *frag, unsigned int off, unsigned int len, fix_new_exp (frag, off, len, exp, 0, r); } -#if (!defined (OBJ_ELF) && !defined (OBJ_MAYBE_ELF)) || defined (LEX_AT) +#if !(defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || defined (OBJ_MACH_O)) \ + || defined (LEX_AT) # define lex_got(reloc, adjust, types) NULL #else /* Parse operands of the form @@ -5894,7 +6543,7 @@ x86_cons_fix_new (fragS *frag, unsigned int off, unsigned int len, is non-null set it to the length of the string we removed from the input line. Otherwise return NULL. */ static char * -lex_got (enum bfd_reloc_code_real *reloc, +lex_got (enum bfd_reloc_code_real *rel, int *adjust, i386_operand_type *types) { @@ -5905,67 +6554,69 @@ lex_got (enum bfd_reloc_code_real *reloc, and adjust the reloc according to the real size in reloc(). */ static const struct { const char *str; + int len; const enum bfd_reloc_code_real rel[2]; const i386_operand_type types64; } gotrel[] = { - { "PLTOFF", { 0, - BFD_RELOC_X86_64_PLTOFF64 }, + { STRING_COMMA_LEN ("PLTOFF"), { _dummy_first_bfd_reloc_code_real, + BFD_RELOC_X86_64_PLTOFF64 }, OPERAND_TYPE_IMM64 }, - { "PLT", { BFD_RELOC_386_PLT32, - BFD_RELOC_X86_64_PLT32 }, + { STRING_COMMA_LEN ("PLT"), { BFD_RELOC_386_PLT32, + BFD_RELOC_X86_64_PLT32 }, OPERAND_TYPE_IMM32_32S_DISP32 }, - { "GOTPLT", { 0, - BFD_RELOC_X86_64_GOTPLT64 }, + { STRING_COMMA_LEN ("GOTPLT"), { _dummy_first_bfd_reloc_code_real, + BFD_RELOC_X86_64_GOTPLT64 }, OPERAND_TYPE_IMM64_DISP64 }, - { "GOTOFF", { BFD_RELOC_386_GOTOFF, - BFD_RELOC_X86_64_GOTOFF64 }, + { STRING_COMMA_LEN ("GOTOFF"), { BFD_RELOC_386_GOTOFF, + BFD_RELOC_X86_64_GOTOFF64 }, OPERAND_TYPE_IMM64_DISP64 }, - { "GOTPCREL", { 0, - BFD_RELOC_X86_64_GOTPCREL }, + { STRING_COMMA_LEN ("GOTPCREL"), { _dummy_first_bfd_reloc_code_real, + BFD_RELOC_X86_64_GOTPCREL }, OPERAND_TYPE_IMM32_32S_DISP32 }, - { "TLSGD", { BFD_RELOC_386_TLS_GD, - BFD_RELOC_X86_64_TLSGD }, + { STRING_COMMA_LEN ("TLSGD"), { BFD_RELOC_386_TLS_GD, + BFD_RELOC_X86_64_TLSGD }, OPERAND_TYPE_IMM32_32S_DISP32 }, - { "TLSLDM", { BFD_RELOC_386_TLS_LDM, - 0 }, + { STRING_COMMA_LEN ("TLSLDM"), { BFD_RELOC_386_TLS_LDM, + _dummy_first_bfd_reloc_code_real }, OPERAND_TYPE_NONE }, - { "TLSLD", { 0, - BFD_RELOC_X86_64_TLSLD }, + { STRING_COMMA_LEN ("TLSLD"), { _dummy_first_bfd_reloc_code_real, + BFD_RELOC_X86_64_TLSLD }, OPERAND_TYPE_IMM32_32S_DISP32 }, - { "GOTTPOFF", { BFD_RELOC_386_TLS_IE_32, - BFD_RELOC_X86_64_GOTTPOFF }, + { STRING_COMMA_LEN ("GOTTPOFF"), { BFD_RELOC_386_TLS_IE_32, + BFD_RELOC_X86_64_GOTTPOFF }, OPERAND_TYPE_IMM32_32S_DISP32 }, - { "TPOFF", { BFD_RELOC_386_TLS_LE_32, - BFD_RELOC_X86_64_TPOFF32 }, + { STRING_COMMA_LEN ("TPOFF"), { BFD_RELOC_386_TLS_LE_32, + BFD_RELOC_X86_64_TPOFF32 }, OPERAND_TYPE_IMM32_32S_64_DISP32_64 }, - { "NTPOFF", { BFD_RELOC_386_TLS_LE, - 0 }, + { STRING_COMMA_LEN ("NTPOFF"), { BFD_RELOC_386_TLS_LE, + _dummy_first_bfd_reloc_code_real }, OPERAND_TYPE_NONE }, - { "DTPOFF", { BFD_RELOC_386_TLS_LDO_32, - BFD_RELOC_X86_64_DTPOFF32 }, - + { STRING_COMMA_LEN ("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 }, + { STRING_COMMA_LEN ("GOTNTPOFF"),{ BFD_RELOC_386_TLS_GOTIE, + _dummy_first_bfd_reloc_code_real }, OPERAND_TYPE_NONE }, - { "INDNTPOFF",{ BFD_RELOC_386_TLS_IE, - 0 }, + { STRING_COMMA_LEN ("INDNTPOFF"),{ BFD_RELOC_386_TLS_IE, + _dummy_first_bfd_reloc_code_real }, OPERAND_TYPE_NONE }, - { "GOT", { BFD_RELOC_386_GOT32, - BFD_RELOC_X86_64_GOT32 }, + { STRING_COMMA_LEN ("GOT"), { BFD_RELOC_386_GOT32, + BFD_RELOC_X86_64_GOT32 }, OPERAND_TYPE_IMM32_32S_64_DISP32 }, - { "TLSDESC", { BFD_RELOC_386_TLS_GOTDESC, - BFD_RELOC_X86_64_GOTPC32_TLSDESC }, + { STRING_COMMA_LEN ("TLSDESC"), { BFD_RELOC_386_TLS_GOTDESC, + BFD_RELOC_X86_64_GOTPC32_TLSDESC }, OPERAND_TYPE_IMM32_32S_DISP32 }, - { "TLSCALL", { BFD_RELOC_386_TLS_DESC_CALL, - BFD_RELOC_X86_64_TLSDESC_CALL }, + { STRING_COMMA_LEN ("TLSCALL"), { BFD_RELOC_386_TLS_DESC_CALL, + BFD_RELOC_X86_64_TLSDESC_CALL }, OPERAND_TYPE_IMM32_32S_DISP32 }, }; char *cp; unsigned int j; +#if defined (OBJ_MAYBE_ELF) if (!IS_ELF) return NULL; +#endif for (cp = input_line_pointer; *cp != '@'; cp++) if (is_end_of_line[(unsigned char) *cp] || *cp == ',') @@ -5973,9 +6624,7 @@ lex_got (enum bfd_reloc_code_real *reloc, for (j = 0; j < ARRAY_SIZE (gotrel); j++) { - int len; - - len = strlen (gotrel[j].str); + int len = gotrel[j].len; if (strncasecmp (cp + 1, gotrel[j].str, len) == 0) { if (gotrel[j].rel[object_64bit] != 0) @@ -5983,7 +6632,7 @@ lex_got (enum bfd_reloc_code_real *reloc, int first, second; char *tmpbuf, *past_reloc; - *reloc = gotrel[j].rel[object_64bit]; + *rel = gotrel[j].rel[object_64bit]; if (adjust) *adjust = len; @@ -6014,7 +6663,7 @@ lex_got (enum bfd_reloc_code_real *reloc, /* Allocate and copy string. The trailing NUL shouldn't be necessary, but be safe. */ - tmpbuf = xmalloc (first + second + 2); + tmpbuf = (char *) xmalloc (first + second + 2); memcpy (tmpbuf, input_line_pointer, first); if (second != 0 && *past_reloc != ' ') /* Replace the relocation token with ' ', so that @@ -6034,18 +6683,20 @@ lex_got (enum bfd_reloc_code_real *reloc, /* Might be a symbol version string. Don't as_bad here. */ return NULL; } +#endif void x86_cons (expressionS *exp, int size) { intel_syntax = -intel_syntax; + exp->X_md = 0; if (size == 4 || (object_64bit && size == 8)) { /* Handle @GOTOFF and the like in an expression. */ char *save; char *gotfree_input_line; - int adjust; + int adjust = 0; save = input_line_pointer; gotfree_input_line = lex_got (&got_reloc, &adjust, NULL); @@ -6084,9 +6735,9 @@ x86_cons (expressionS *exp, int size) if (intel_syntax) i386_intel_simplify (exp); } -#endif -static void signed_cons (int size) +static void +signed_cons (int size) { if (flag_code == CODE_64BIT) cons_sign = 1; @@ -6096,8 +6747,7 @@ static void signed_cons (int size) #ifdef TE_PE static void -pe_directive_secrel (dummy) - int dummy ATTRIBUTE_UNUSED; +pe_directive_secrel (int dummy ATTRIBUTE_UNUSED) { expressionS exp; @@ -6171,16 +6821,17 @@ i386_finalize_immediate (segT exp_seg ATTRIBUTE_UNUSED, expressionS *exp, { 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); + if (imm_start) + as_bad (_("missing or invalid immediate expression `%s'"), + imm_start); return 0; } else if (exp->X_op == O_constant) { /* Size it properly later. */ i.types[this_operand].bitfield.imm64 = 1; - /* If BFD64, sign extend val. */ - if (!use_rela_relocations + /* If not 64bit, sign extend val. */ + if (flag_code != CODE_64BIT && (exp->X_add_number & ~(((addressT) 2 << 31) - 1)) == 0) exp->X_add_number = (exp->X_add_number ^ ((addressT) 1 << 31)) - ((addressT) 1 << 31); @@ -6200,7 +6851,8 @@ i386_finalize_immediate (segT exp_seg ATTRIBUTE_UNUSED, expressionS *exp, #endif else if (!intel_syntax && exp->X_op == O_register) { - as_bad (_("illegal immediate register operand %s"), imm_start); + if (imm_start) + as_bad (_("illegal immediate register operand %s"), imm_start); return 0; } else @@ -6434,7 +7086,8 @@ i386_finalize_displacement (segT exp_seg ATTRIBUTE_UNUSED, expressionS *exp, goto inv_disp; if (S_IS_LOCAL (exp->X_add_symbol) - && S_GET_SEGMENT (exp->X_add_symbol) != undefined_section) + && S_GET_SEGMENT (exp->X_add_symbol) != undefined_section + && S_GET_SEGMENT (exp->X_add_symbol) != expr_section) section_symbol (S_GET_SEGMENT (exp->X_add_symbol)); exp->X_op = O_subtract; exp->X_op_symbol = GOT_symbol; @@ -6456,6 +7109,25 @@ i386_finalize_displacement (segT exp_seg ATTRIBUTE_UNUSED, expressionS *exp, ret = 0; } + else if (flag_code == CODE_64BIT + && !i.prefix[ADDR_PREFIX] + && exp->X_op == O_constant) + { + /* Since displacement is signed extended to 64bit, don't allow + disp32 and turn off disp32s if they are out of range. */ + i.types[this_operand].bitfield.disp32 = 0; + if (!fits_in_signed_long (exp->X_add_number)) + { + i.types[this_operand].bitfield.disp32s = 0; + if (i.types[this_operand].bitfield.baseindex) + { + as_bad (_("0x%lx out range of signed 32bit displacement"), + (long) exp->X_add_number); + ret = 0; + } + } + } + #if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT)) else if (exp->X_op != O_constant && OUTPUT_FLAVOR == bfd_target_aout_flavour @@ -6573,6 +7245,8 @@ i386_index_check (const char *operand_string) || i.base_reg->reg_num != (i.prefix[ADDR_PREFIX] == 0 ? RegRip : RegEip))) || (i.index_reg + && !(i.index_reg->reg_type.bitfield.regxmm + || i.index_reg->reg_type.bitfield.regymm) && (!i.index_reg->reg_type.bitfield.baseindex || (i.prefix[ADDR_PREFIX] == 0 && i.index_reg->reg_num != RegRiz @@ -6606,6 +7280,8 @@ i386_index_check (const char *operand_string) if ((i.base_reg && !i.base_reg->reg_type.bitfield.reg32) || (i.index_reg + && !i.index_reg->reg_type.bitfield.regxmm + && !i.index_reg->reg_type.bitfield.regymm && ((!i.index_reg->reg_type.bitfield.reg32 && i.index_reg->reg_num != RegEiz) || !i.index_reg->reg_type.bitfield.baseindex))) @@ -6963,9 +7639,7 @@ i386_att_operand (char *operand_string) returned value. */ int -md_estimate_size_before_relax (fragP, segment) - fragS *fragP; - segT segment; +md_estimate_size_before_relax (fragS *fragP, segT segment) { /* We've already got fragP->fr_subtype right; all we have to do is check for un-relaxable symbols. On an ELF system, we can't relax @@ -6975,7 +7649,9 @@ 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 @@ -6991,7 +7667,7 @@ md_estimate_size_before_relax (fragP, segment) int old_fr_fix; if (fragP->fr_var != NO_RELOC) - reloc_type = fragP->fr_var; + reloc_type = (enum bfd_reloc_code_real) fragP->fr_var; else if (size == 2) reloc_type = BFD_RELOC_16_PCREL; else @@ -7086,10 +7762,8 @@ md_estimate_size_before_relax (fragP, segment) Caller will turn frag into a ".space 0". */ void -md_convert_frag (abfd, sec, fragP) - bfd *abfd ATTRIBUTE_UNUSED; - segT sec ATTRIBUTE_UNUSED; - fragS *fragP; +md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec ATTRIBUTE_UNUSED, + fragS *fragP) { unsigned char *opcode; unsigned char *where_to_put_displacement = NULL; @@ -7186,21 +7860,17 @@ md_convert_frag (abfd, sec, fragP) fragP->fr_fix += extension; } -/* Apply a fixup (fixS) to segment data, once it has been determined +/* Apply a fixup (fixP) to segment data, once it has been determined by our caller that we have all the info we need to fix it up. + Parameter valP is the pointer to the value of the bits. + On the 386, immediates, displacements, and data pointers are all in the same (little-endian) format, so we don't need to care about which we are handling. */ void -md_apply_fix (fixP, valP, seg) - /* The fix we're to put in. */ - fixS *fixP; - /* Pointer to the value of the bits. */ - valueT *valP; - /* Segment fix is from. */ - segT seg ATTRIBUTE_UNUSED; +md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) { char *p = fixP->fx_where + fixP->fx_frag->fr_literal; valueT value = *valP; @@ -7256,7 +7926,7 @@ md_apply_fix (fixP, valP, seg) if ((sym_seg == seg || (symbol_section_p (fixP->fx_addsy) && sym_seg != absolute_section)) - && !TC_FORCE_RELOCATION (fixP)) + && !generic_force_reloc (fixP)) { /* Yes, we add the values in twice. This is because bfd_install_relocation subtracts them out again. I think @@ -7440,7 +8110,7 @@ parse_real_register (char *reg_string, char **end_op) if (*s == ')') { *end_op = s + 1; - r = hash_find (reg_hash, "st(0)"); + r = (const reg_entry *) hash_find (reg_hash, "st(0)"); know (r); return r + fpr; } @@ -7464,6 +8134,12 @@ parse_real_register (char *reg_string, char **end_op) && !cpu_arch_flags.bitfield.cpui386) return (const reg_entry *) NULL; + if (r->reg_type.bitfield.floatreg + && !cpu_arch_flags.bitfield.cpu8087 + && !cpu_arch_flags.bitfield.cpu287 + && !cpu_arch_flags.bitfield.cpu387) + return (const reg_entry *) NULL; + if (r->reg_type.bitfield.regmmx && !cpu_arch_flags.bitfield.cpummx) return (const reg_entry *) NULL; @@ -7606,13 +8282,18 @@ const char *md_shortopts = "qn"; #define OPTION_MOLD_GCC (OPTION_MD_BASE + 9) #define OPTION_MSSE2AVX (OPTION_MD_BASE + 10) #define OPTION_MSSE_CHECK (OPTION_MD_BASE + 11) +#define OPTION_MAVXSCALAR (OPTION_MD_BASE + 12) +#define OPTION_X32 (OPTION_MD_BASE + 13) struct option md_longopts[] = { {"32", no_argument, NULL, OPTION_32}, #if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \ - || defined (TE_PE) || defined (TE_PEP)) + || defined (TE_PE) || defined (TE_PEP) || defined (OBJ_MACH_O)) {"64", no_argument, NULL, OPTION_64}, +#endif +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + {"x32", no_argument, NULL, OPTION_X32}, #endif {"divide", no_argument, NULL, OPTION_DIVIDE}, {"march", required_argument, NULL, OPTION_MARCH}, @@ -7624,6 +8305,7 @@ struct option md_longopts[] = {"mold-gcc", no_argument, NULL, OPTION_MOLD_GCC}, {"msse2avx", no_argument, NULL, OPTION_MSSE2AVX}, {"msse-check", required_argument, NULL, OPTION_MSSE_CHECK}, + {"mavxscalar", required_argument, NULL, OPTION_MAVXSCALAR}, {NULL, no_argument, NULL, 0} }; size_t md_longopts_size = sizeof (md_longopts); @@ -7631,7 +8313,7 @@ size_t md_longopts_size = sizeof (md_longopts); int md_parse_option (int c, char *arg) { - unsigned int i; + unsigned int j; char *arch, *next; switch (c) @@ -7665,7 +8347,7 @@ md_parse_option (int c, char *arg) break; #endif #if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \ - || defined (TE_PE) || defined (TE_PEP)) + || defined (TE_PE) || defined (TE_PEP) || defined (OBJ_MACH_O)) case OPTION_64: { const char **list, **l; @@ -7675,18 +8357,41 @@ md_parse_option (int c, char *arg) if (CONST_STRNEQ (*l, "elf64-x86-64") || strcmp (*l, "coff-x86-64") == 0 || strcmp (*l, "pe-x86-64") == 0 - || strcmp (*l, "pei-x86-64") == 0) + || strcmp (*l, "pei-x86-64") == 0 + || strcmp (*l, "mach-o-x86-64") == 0) { default_arch = "x86_64"; break; } if (*l == NULL) - as_fatal (_("No compiled in support for x86_64")); + as_fatal (_("no compiled in support for x86_64")); free (list); } break; #endif +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + case OPTION_X32: + if (IS_ELF) + { + const char **list, **l; + + list = bfd_target_list (); + for (l = list; *l != NULL; l++) + if (CONST_STRNEQ (*l, "elf32-x86-64")) + { + default_arch = "x86_64:32"; + break; + } + if (*l == NULL) + as_fatal (_("no compiled in support for 32bit x86_64")); + free (list); + } + else + as_fatal (_("32bit x86_64 is only supported for ELF")); + break; +#endif + case OPTION_32: default_arch = "i386"; break; @@ -7713,20 +8418,23 @@ md_parse_option (int c, char *arg) do { if (*arch == '.') - as_fatal (_("Invalid -march= option: `%s'"), arg); + as_fatal (_("invalid -march= option: `%s'"), arg); next = strchr (arch, '+'); if (next) *next++ = '\0'; - for (i = 0; i < ARRAY_SIZE (cpu_arch); i++) + for (j = 0; j < ARRAY_SIZE (cpu_arch); j++) { - if (strcmp (arch, cpu_arch [i].name) == 0) + if (strcmp (arch, cpu_arch [j].name) == 0) { /* Processor. */ - cpu_arch_name = cpu_arch[i].name; + if (! cpu_arch[j].flags.bitfield.cpui386) + continue; + + cpu_arch_name = cpu_arch[j].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; + cpu_arch_flags = cpu_arch[j].flags; + cpu_arch_isa = cpu_arch[j].type; + cpu_arch_isa_flags = cpu_arch[j].flags; if (!cpu_arch_tune_set) { cpu_arch_tune = cpu_arch_isa; @@ -7734,33 +8442,39 @@ md_parse_option (int c, char *arg) } break; } - else if (*cpu_arch [i].name == '.' - && strcmp (arch, cpu_arch [i].name + 1) == 0) + else if (*cpu_arch [j].name == '.' + && strcmp (arch, cpu_arch [j].name + 1) == 0) { /* ISA entension. */ i386_cpu_flags flags; - flags = cpu_flags_or (cpu_arch_flags, - cpu_arch[i].flags); + + if (!cpu_arch[j].negated) + flags = cpu_flags_or (cpu_arch_flags, + cpu_arch[j].flags); + else + flags = cpu_flags_and_not (cpu_arch_flags, + cpu_arch[j].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, + cpu_arch[j].name, (const char *) NULL); free (name); } else - cpu_sub_arch_name = xstrdup (cpu_arch[i].name); + cpu_sub_arch_name = xstrdup (cpu_arch[j].name); cpu_arch_flags = flags; + cpu_arch_isa_flags = flags; } break; } } - if (i >= ARRAY_SIZE (cpu_arch)) - as_fatal (_("Invalid -march= option: `%s'"), arg); + if (j >= ARRAY_SIZE (cpu_arch)) + as_fatal (_("invalid -march= option: `%s'"), arg); arch = next; } @@ -7769,19 +8483,19 @@ md_parse_option (int c, char *arg) case OPTION_MTUNE: if (*arg == '.') - as_fatal (_("Invalid -mtune= option: `%s'"), arg); - for (i = 0; i < ARRAY_SIZE (cpu_arch); i++) + as_fatal (_("invalid -mtune= option: `%s'"), arg); + for (j = 0; j < ARRAY_SIZE (cpu_arch); j++) { - if (strcmp (arg, cpu_arch [i].name) == 0) + if (strcmp (arg, cpu_arch [j].name) == 0) { cpu_arch_tune_set = 1; - cpu_arch_tune = cpu_arch [i].type; - cpu_arch_tune_flags = cpu_arch[i].flags; + cpu_arch_tune = cpu_arch [j].type; + cpu_arch_tune_flags = cpu_arch[j].flags; break; } } - if (i >= ARRAY_SIZE (cpu_arch)) - as_fatal (_("Invalid -mtune= option: `%s'"), arg); + if (j >= ARRAY_SIZE (cpu_arch)) + as_fatal (_("invalid -mtune= option: `%s'"), arg); break; case OPTION_MMNEMONIC: @@ -7790,7 +8504,7 @@ md_parse_option (int c, char *arg) else if (strcasecmp (arg, "intel") == 0) intel_mnemonic = 1; else - as_fatal (_("Invalid -mmnemonic= option: `%s'"), arg); + as_fatal (_("invalid -mmnemonic= option: `%s'"), arg); break; case OPTION_MSYNTAX: @@ -7799,7 +8513,7 @@ md_parse_option (int c, char *arg) else if (strcasecmp (arg, "intel") == 0) intel_syntax = 1; else - as_fatal (_("Invalid -msyntax= option: `%s'"), arg); + as_fatal (_("invalid -msyntax= option: `%s'"), arg); break; case OPTION_MINDEX_REG: @@ -7826,7 +8540,16 @@ md_parse_option (int c, char *arg) else if (strcasecmp (arg, "none") == 0) sse_check = sse_check_none; else - as_fatal (_("Invalid -msse-check= option: `%s'"), arg); + as_fatal (_("invalid -msse-check= option: `%s'"), arg); + break; + + case OPTION_MAVXSCALAR: + if (strcasecmp (arg, "128") == 0) + avxscalar = vex128; + else if (strcasecmp (arg, "256") == 0) + avxscalar = vex256; + else + as_fatal (_("invalid -mavxscalar= option: `%s'"), arg); break; default: @@ -7835,9 +8558,87 @@ md_parse_option (int c, char *arg) return 1; } +#define MESSAGE_TEMPLATE \ +" " + +static void +show_arch (FILE *stream, int ext, int check) +{ + static char message[] = MESSAGE_TEMPLATE; + char *start = message + 27; + char *p; + int size = sizeof (MESSAGE_TEMPLATE); + int left; + const char *name; + int len; + unsigned int j; + + p = start; + left = size - (start - message); + for (j = 0; j < ARRAY_SIZE (cpu_arch); j++) + { + /* Should it be skipped? */ + if (cpu_arch [j].skip) + continue; + + name = cpu_arch [j].name; + len = cpu_arch [j].len; + if (*name == '.') + { + /* It is an extension. Skip if we aren't asked to show it. */ + if (ext) + { + name++; + len--; + } + else + continue; + } + else if (ext) + { + /* It is an processor. Skip if we show only extension. */ + continue; + } + else if (check && ! cpu_arch[j].flags.bitfield.cpui386) + { + /* It is an impossible processor - skip. */ + continue; + } + + /* Reserve 2 spaces for ", " or ",\0" */ + left -= len + 2; + + /* Check if there is any room. */ + if (left >= 0) + { + if (p != start) + { + *p++ = ','; + *p++ = ' '; + } + p = mempcpy (p, name, len); + } + else + { + /* Output the current message now and start a new one. */ + *p++ = ','; + *p = '\0'; + fprintf (stream, "%s\n", message); + p = start; + left = size - (start - message) - len - 2; + + gas_assert (left >= 0); + + p = mempcpy (p, name, len); + } + } + + *p = '\0'; + fprintf (stream, "%s\n", message); +} + void -md_show_usage (stream) - FILE *stream; +md_show_usage (FILE *stream) { #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) fprintf (stream, _("\ @@ -7855,7 +8656,7 @@ md_show_usage (stream) #if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \ || defined (TE_PE) || defined (TE_PEP)) fprintf (stream, _("\ - --32/--64 generate 32bit/64bit code\n")); + --32/--64/--x32 generate 32bit/64bit/x32 code\n")); #endif #ifdef SVR4_COMMENT_CHARS fprintf (stream, _("\ @@ -7866,28 +8667,23 @@ md_show_usage (stream) #endif fprintf (stream, _("\ -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")); + generate code for CPU and EXTENSION, CPU is one of:\n")); + show_arch (stream, 0, 1); 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")); + EXTENSION is combination of:\n")); + show_arch (stream, 1, 0); + fprintf (stream, _("\ + -mtune=CPU optimize for CPU, CPU is one of:\n")); + show_arch (stream, 0, 0); fprintf (stream, _("\ -msse2avx encode SSE instructions with VEX prefix\n")); fprintf (stream, _("\ -msse-check=[none|error|warning]\n\ check SSE instructions\n")); fprintf (stream, _("\ + -mavxscalar=[128|256] encode scalar AVX instructions with specific vector\n\ + length\n")); + fprintf (stream, _("\ -mmnemonic=[att|intel] use AT&T/Intel mnemonic\n")); fprintf (stream, _("\ -msyntax=[att|intel] use AT&T/Intel syntax\n")); @@ -7908,82 +8704,90 @@ md_show_usage (stream) const char * i386_target_format (void) { - if (!strcmp (default_arch, "x86_64")) + if (!strncmp (default_arch, "x86_64", 6)) { - set_code_flag (CODE_64BIT); - 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; - 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.cpuclflush = 1; - cpu_arch_isa_flags.bitfield.cpummx= 1; - cpu_arch_isa_flags.bitfield.cpusse = 1; - cpu_arch_isa_flags.bitfield.cpusse2 = 1; - } - if (cpu_flags_all_zero (&cpu_arch_tune_flags)) - { - cpu_arch_tune_flags.bitfield.cpui186 = 1; - cpu_arch_tune_flags.bitfield.cpui286 = 1; - cpu_arch_tune_flags.bitfield.cpui386 = 1; - 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.cpuclflush = 1; - cpu_arch_tune_flags.bitfield.cpummx= 1; - cpu_arch_tune_flags.bitfield.cpusse = 1; - cpu_arch_tune_flags.bitfield.cpusse2 = 1; - } + update_code_flag (CODE_64BIT, 1); + if (default_arch[6] == '\0') + x86_elf_abi = X86_64_ABI; + else + x86_elf_abi = X86_64_X32_ABI; } else if (!strcmp (default_arch, "i386")) - { - set_code_flag (CODE_32BIT); - 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 (cpu_flags_all_zero (&cpu_arch_tune_flags)) - { - cpu_arch_tune_flags.bitfield.cpui186 = 1; - cpu_arch_tune_flags.bitfield.cpui286 = 1; - cpu_arch_tune_flags.bitfield.cpui386 = 1; - } - } + update_code_flag (CODE_32BIT, 1); else - as_fatal (_("Unknown architecture")); + as_fatal (_("unknown architecture")); + + if (cpu_flags_all_zero (&cpu_arch_isa_flags)) + cpu_arch_isa_flags = cpu_arch[flag_code == CODE_64BIT].flags; + if (cpu_flags_all_zero (&cpu_arch_tune_flags)) + cpu_arch_tune_flags = cpu_arch[flag_code == CODE_64BIT].flags; + switch (OUTPUT_FLAVOR) { -#if defined (TE_PE) || defined (TE_PEP) - case bfd_target_coff_flavour: - return flag_code == CODE_64BIT ? "pe-x86-64" : "pe-i386"; -#endif -#ifdef OBJ_MAYBE_AOUT +#if defined (OBJ_MAYBE_AOUT) || defined (OBJ_AOUT) case bfd_target_aout_flavour: return AOUT_TARGET_FORMAT; #endif -#ifdef OBJ_MAYBE_COFF +#if defined (OBJ_MAYBE_COFF) || defined (OBJ_COFF) +# if defined (TE_PE) || defined (TE_PEP) + case bfd_target_coff_flavour: + return flag_code == CODE_64BIT ? "pe-x86-64" : "pe-i386"; +# elif defined (TE_GO32) + case bfd_target_coff_flavour: + return "coff-go32"; +# else case bfd_target_coff_flavour: return "coff-i386"; +# endif #endif #if defined (OBJ_MAYBE_ELF) || defined (OBJ_ELF) case bfd_target_elf_flavour: { - if (flag_code == CODE_64BIT) + const char *format; + + switch (x86_elf_abi) { + default: + format = ELF_TARGET_FORMAT; + break; + case X86_64_ABI: + use_rela_relocations = 1; object_64bit = 1; + format = ELF_TARGET_FORMAT64; + break; + case X86_64_X32_ABI: use_rela_relocations = 1; + object_64bit = 1; + disallow_64bit_reloc = 1; + format = ELF_TARGET_FORMAT32; + break; + } + if (cpu_arch_isa == PROCESSOR_L1OM) + { + if (x86_elf_abi != X86_64_ABI) + as_fatal (_("Intel L1OM is 64bit only")); + return ELF_TARGET_L1OM_FORMAT; + } + if (cpu_arch_isa == PROCESSOR_K1OM) + { + if (x86_elf_abi != X86_64_ABI) + as_fatal (_("Intel K1OM is 64bit only")); + return ELF_TARGET_K1OM_FORMAT; } - return flag_code == CODE_64BIT ? ELF_TARGET_FORMAT64 : ELF_TARGET_FORMAT; + else + return 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"; + if (flag_code == CODE_64BIT) + { + use_rela_relocations = 1; + object_64bit = 1; + return "mach-o-x86-64"; + } + else + return "mach-o-i386"; #endif default: abort (); @@ -8036,8 +8840,7 @@ i386_elf_emit_arch_note (void) #endif symbolS * -md_undefined_symbol (name) - char *name; +md_undefined_symbol (char *name) { if (name[0] == GLOBAL_OFFSET_TABLE_NAME[0] && name[1] == GLOBAL_OFFSET_TABLE_NAME[1] @@ -8059,9 +8862,7 @@ md_undefined_symbol (name) /* Round up a section size to the appropriate boundary. */ valueT -md_section_align (segment, size) - segT segment ATTRIBUTE_UNUSED; - valueT size; +md_section_align (segT segment ATTRIBUTE_UNUSED, valueT size) { #if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT)) if (OUTPUT_FLAVOR == bfd_target_aout_flavour) @@ -8132,9 +8933,7 @@ i386_validate_fix (fixS *fixp) } arelent * -tc_gen_reloc (section, fixp) - asection *section ATTRIBUTE_UNUSED; - fixS *fixp; +tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) { arelent *rel; bfd_reloc_code_real_type code; @@ -8269,6 +9068,26 @@ tc_gen_reloc (section, fixp) /* Use the rela in 64bit mode. */ else { + if (disallow_64bit_reloc) + switch (code) + { + case BFD_RELOC_X86_64_DTPOFF64: + case BFD_RELOC_X86_64_TPOFF64: + case BFD_RELOC_64_PCREL: + case BFD_RELOC_X86_64_GOTOFF64: + case BFD_RELOC_X86_64_GOT64: + case BFD_RELOC_X86_64_GOTPCREL64: + case BFD_RELOC_X86_64_GOTPC64: + case BFD_RELOC_X86_64_GOTPLT64: + case BFD_RELOC_X86_64_PLTOFF64: + as_bad_where (fixp->fx_file, fixp->fx_line, + _("cannot represent relocation type %s in x32 mode"), + bfd_get_reloc_code_name (code)); + break; + default: + break; + } + if (!fixp->fx_pcrel) rel->addend = fixp->fx_offset; else @@ -8360,6 +9179,16 @@ tc_x86_frame_initial_instructions (void) cfi_add_CFA_offset (x86_dwarf2_return_column, x86_cie_data_alignment); } +int +x86_dwarf2_addr_size (void) +{ +#if defined (OBJ_MAYBE_ELF) || defined (OBJ_ELF) + if (x86_elf_abi == X86_64_X32_ABI) + return 4; +#endif + return bfd_arch_bits_per_address (stdoutput) / 8; +} + int i386_elf_section_type (const char *str, size_t len) { @@ -8384,12 +9213,12 @@ i386_solaris_fix_up_eh_frame (segT sec) void tc_pe_dwarf2_emit_offset (symbolS *symbol, unsigned int size) { - expressionS expr; + expressionS exp; - expr.X_op = O_secrel; - expr.X_add_symbol = symbol; - expr.X_add_number = 0; - emit_expr (&expr, size); + exp.X_op = O_secrel; + exp.X_add_symbol = symbol; + exp.X_add_number = 0; + emit_expr (&exp, size); } #endif @@ -8404,10 +9233,10 @@ x86_64_section_letter (int letter, char **ptr_msg) if (letter == 'l') return SHF_X86_64_LARGE; - *ptr_msg = _("Bad .section directive: want a,l,w,x,M,S,G,T in string"); + *ptr_msg = _("bad .section directive: want a,l,w,x,M,S,G,T in string"); } else - *ptr_msg = _("Bad .section directive: want a,w,x,M,S,G,T in string"); + *ptr_msg = _("bad .section directive: want a,w,x,M,S,G,T in string"); return -1; }