X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-i386.c;h=f382a73a3908c85573a235322ecce8ef4f1137f0;hb=39d911fc3c6519799ca1af4365d4b56f9d71ca94;hp=50f9cb47ea39cd03908658a51fbdc0b776825203;hpb=00923338dec84505addaf9cdeca2e9c844757824;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 50f9cb47ea..f382a73a39 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -1,5 +1,5 @@ /* tc-i386.c -- Assemble code for the Intel 80386 - Copyright (C) 1989-2015 Free Software Foundation, Inc. + Copyright (C) 1989-2016 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -33,12 +33,6 @@ #include "elf/x86-64.h" #include "opcodes/i386-init.h" -#ifdef TE_LINUX -/* Default to compress debug sections for Linux. */ -enum compressed_debug_section_type flag_compress_debug - = COMPRESS_DEBUG_ZLIB; -#endif - #ifndef REGISTER_WARNINGS #define REGISTER_WARNINGS 1 #endif @@ -524,6 +518,11 @@ static enum x86_elf_abi x86_elf_abi = I386_ABI; static int use_big_obj = 0; #endif +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) +/* 1 if generating code for a shared library. */ +static int shared = 0; +#endif + /* 1 for intel syntax, 0 if att syntax. */ static int intel_syntax = 0; @@ -553,6 +552,15 @@ static int allow_index_reg = 0; specified explicitly. */ static int omit_lock_prefix = 0; +/* 1 if the assembler should encode lfence, mfence, and sfence as + "lock addl $0, (%{re}sp)". */ +static int avoid_fence = 0; + +/* 1 if the assembler should generate relax relocations. */ + +static int generate_relax_relocations + = DEFAULT_GENERATE_X86_RELAX_RELOCATIONS; + static enum check_kind { check_none = 0, @@ -767,6 +775,8 @@ static const arch_entry cpu_arch[] = CPU_L1OM_FLAGS, 0, 0 }, { STRING_COMMA_LEN ("k1om"), PROCESSOR_K1OM, CPU_K1OM_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("iamcu"), PROCESSOR_IAMCU, + CPU_IAMCU_FLAGS, 0, 0 }, { STRING_COMMA_LEN ("k6"), PROCESSOR_K6, CPU_K6_FLAGS, 0, 0 }, { STRING_COMMA_LEN ("k6_2"), PROCESSOR_K6, @@ -790,7 +800,7 @@ static const arch_entry cpu_arch[] = { STRING_COMMA_LEN ("bdver4"), PROCESSOR_BD, CPU_BDVER4_FLAGS, 0, 0 }, { STRING_COMMA_LEN ("znver1"), PROCESSOR_ZNVER, - CPU_ZNVER1_FLAGS, 0, 0 }, + CPU_ZNVER1_FLAGS, 0, 0 }, { STRING_COMMA_LEN ("btver1"), PROCESSOR_BT, CPU_BTVER1_FLAGS, 0, 0 }, { STRING_COMMA_LEN ("btver2"), PROCESSOR_BT, @@ -947,6 +957,10 @@ static const arch_entry cpu_arch[] = CPU_AVX512VBMI_FLAGS, 0, 0 }, { STRING_COMMA_LEN (".clzero"), PROCESSOR_UNKNOWN, CPU_CLZERO_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".mwaitx"), PROCESSOR_UNKNOWN, + CPU_MWAITX_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".ospke"), PROCESSOR_UNKNOWN, + CPU_OSPKE_FLAGS, 0, 0 }, }; #ifdef I386COFF @@ -1051,95 +1065,95 @@ i386_align_code (fragS *fragP, int count) /* Various efficient no-op patterns for aligning code labels. Note: Don't try to assemble the instructions in the comments. 0L and 0w are not legal. */ - static const char f32_1[] = + static const unsigned char f32_1[] = {0x90}; /* nop */ - static const char f32_2[] = + static const unsigned char f32_2[] = {0x66,0x90}; /* xchg %ax,%ax */ - static const char f32_3[] = + static const unsigned char f32_3[] = {0x8d,0x76,0x00}; /* leal 0(%esi),%esi */ - static const char f32_4[] = + static const unsigned char f32_4[] = {0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */ - static const char f32_5[] = + static const unsigned char f32_5[] = {0x90, /* nop */ 0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */ - static const char f32_6[] = + static const unsigned char f32_6[] = {0x8d,0xb6,0x00,0x00,0x00,0x00}; /* leal 0L(%esi),%esi */ - static const char f32_7[] = + static const unsigned char f32_7[] = {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */ - static const char f32_8[] = + static const unsigned char f32_8[] = {0x90, /* nop */ 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */ - static const char f32_9[] = + static const unsigned char f32_9[] = {0x89,0xf6, /* movl %esi,%esi */ 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ - static const char f32_10[] = + static const unsigned char f32_10[] = {0x8d,0x76,0x00, /* leal 0(%esi),%esi */ 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ - static const char f32_11[] = + static const unsigned char f32_11[] = {0x8d,0x74,0x26,0x00, /* leal 0(%esi,1),%esi */ 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ - static const char f32_12[] = + static const unsigned char f32_12[] = {0x8d,0xb6,0x00,0x00,0x00,0x00, /* leal 0L(%esi),%esi */ 0x8d,0xbf,0x00,0x00,0x00,0x00}; /* leal 0L(%edi),%edi */ - static const char f32_13[] = + static const unsigned char f32_13[] = {0x8d,0xb6,0x00,0x00,0x00,0x00, /* leal 0L(%esi),%esi */ 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ - static const char f32_14[] = + static const unsigned char f32_14[] = {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00, /* leal 0L(%esi,1),%esi */ 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ - static const char f16_3[] = + static const unsigned char f16_3[] = {0x8d,0x74,0x00}; /* lea 0(%esi),%esi */ - static const char f16_4[] = + static const unsigned char f16_4[] = {0x8d,0xb4,0x00,0x00}; /* lea 0w(%si),%si */ - static const char f16_5[] = + static const unsigned char f16_5[] = {0x90, /* nop */ 0x8d,0xb4,0x00,0x00}; /* lea 0w(%si),%si */ - static const char f16_6[] = + static const unsigned char f16_6[] = {0x89,0xf6, /* mov %si,%si */ 0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */ - static const char f16_7[] = + static const unsigned char f16_7[] = {0x8d,0x74,0x00, /* lea 0(%si),%si */ 0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */ - static const char f16_8[] = + static const unsigned char f16_8[] = {0x8d,0xb4,0x00,0x00, /* lea 0w(%si),%si */ 0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */ - static const char jump_31[] = + static const unsigned char jump_31[] = {0xeb,0x1d,0x90,0x90,0x90,0x90,0x90, /* jmp .+31; lotsa nops */ 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90, 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90}; - static const char *const f32_patt[] = { + static const unsigned char *const f32_patt[] = { f32_1, f32_2, f32_3, f32_4, f32_5, f32_6, f32_7, f32_8, f32_9, f32_10, f32_11, f32_12, f32_13, f32_14 }; - static const char *const f16_patt[] = { + static const unsigned char *const f16_patt[] = { f32_1, f32_2, f16_3, f16_4, f16_5, f16_6, f16_7, f16_8 }; /* nopl (%[re]ax) */ - static const char alt_3[] = + static const unsigned char alt_3[] = {0x0f,0x1f,0x00}; /* nopl 0(%[re]ax) */ - static const char alt_4[] = + static const unsigned char alt_4[] = {0x0f,0x1f,0x40,0x00}; /* nopl 0(%[re]ax,%[re]ax,1) */ - static const char alt_5[] = + static const unsigned char alt_5[] = {0x0f,0x1f,0x44,0x00,0x00}; /* nopw 0(%[re]ax,%[re]ax,1) */ - static const char alt_6[] = + static const unsigned char alt_6[] = {0x66,0x0f,0x1f,0x44,0x00,0x00}; /* nopl 0L(%[re]ax) */ - static const char alt_7[] = + static const unsigned char alt_7[] = {0x0f,0x1f,0x80,0x00,0x00,0x00,0x00}; /* nopl 0L(%[re]ax,%[re]ax,1) */ - static const char alt_8[] = + static const unsigned char alt_8[] = {0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; /* nopw 0L(%[re]ax,%[re]ax,1) */ - static const char alt_9[] = + static const unsigned char alt_9[] = {0x66,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; /* nopw %cs:0L(%[re]ax,%[re]ax,1) */ - static const char alt_10[] = + static const unsigned char alt_10[] = {0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; - static const char *const alt_patt[] = { + static const unsigned char *const alt_patt[] = { f32_1, f32_2, alt_3, alt_4, alt_5, alt_6, alt_7, alt_8, alt_9, alt_10 }; @@ -1177,7 +1191,7 @@ i386_align_code (fragS *fragP, int count) } else { - const char *const *patt = NULL; + const unsigned char *const *patt = NULL; if (fragP->tc_frag_data.isa == PROCESSOR_UNKNOWN) { @@ -1213,6 +1227,7 @@ i386_align_code (fragS *fragP, int count) case PROCESSOR_I486: case PROCESSOR_PENTIUM: case PROCESSOR_PENTIUMPRO: + case PROCESSOR_IAMCU: case PROCESSOR_GENERIC32: patt = f32_patt; break; @@ -1231,6 +1246,7 @@ i386_align_code (fragS *fragP, int count) case PROCESSOR_I386: case PROCESSOR_I486: case PROCESSOR_PENTIUM: + case PROCESSOR_IAMCU: case PROCESSOR_K6: case PROCESSOR_ATHLON: case PROCESSOR_K8: @@ -1464,6 +1480,20 @@ cpu_flags_and_not (i386_cpu_flags x, i386_cpu_flags y) return x; } +static int +valid_iamcu_cpu_flags (const i386_cpu_flags *flags) +{ + if (cpu_arch_isa == PROCESSOR_IAMCU) + { + static const i386_cpu_flags iamcu_flags = CPU_IAMCU_COMPAT_FLAGS; + i386_cpu_flags compat_flags; + compat_flags = cpu_flags_and_not (*flags, iamcu_flags); + return cpu_flags_all_zero (&compat_flags); + } + else + return 1; +} + #define CPU_FLAGS_ARCH_MATCH 0x1 #define CPU_FLAGS_64BIT_MATCH 0x2 #define CPU_FLAGS_AES_MATCH 0x4 @@ -1850,6 +1880,9 @@ register_number (const reg_entry *r) if (r->reg_flags & RegRex) nr += 8; + if (r->reg_flags & RegVRex) + nr += 16; + return nr; } @@ -2173,8 +2206,8 @@ set_intel_syntax (int syntax_flag) SKIP_WHITESPACE (); if (!is_end_of_line[(unsigned char) *input_line_pointer]) { - char *string = input_line_pointer; - int e = get_symbol_end (); + char *string; + int e = get_symbol_name (&string); if (strcmp (string, "prefix") == 0) ask_naked_reg = 1; @@ -2182,7 +2215,7 @@ set_intel_syntax (int syntax_flag) ask_naked_reg = -1; else as_bad (_("bad argument to syntax directive.")); - *input_line_pointer = e; + (void) restore_line_pointer (e); } demand_empty_rest_of_line (); @@ -2234,8 +2267,8 @@ set_check (int what) if (!is_end_of_line[(unsigned char) *input_line_pointer]) { - char *string = input_line_pointer; - int e = get_symbol_end (); + char *string; + int e = get_symbol_name (&string); if (strcmp (string, "none") == 0) *kind = check_none; @@ -2245,7 +2278,7 @@ set_check (int what) *kind = check_error; else as_bad (_("bad argument to %s_check directive."), str); - *input_line_pointer = e; + (void) restore_line_pointer (e); } else as_bad (_("missing argument for %s_check directive"), str); @@ -2273,6 +2306,11 @@ check_cpu_arch_compatible (const char *name ATTRIBUTE_UNUSED, arch = default_arch; } + /* If we are targeting Intel MCU, we must enable it. */ + if (get_elf_backend_data (stdoutput)->elf_machine_code != EM_IAMCU + || new_flag.bitfield.cpuiamcu) + return; + /* 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) @@ -2294,8 +2332,8 @@ set_cpu_arch (int dummy ATTRIBUTE_UNUSED) if (!is_end_of_line[(unsigned char) *input_line_pointer]) { - char *string = input_line_pointer; - int e = get_symbol_end (); + char *string; + int e = get_symbol_name (&string); unsigned int j; i386_cpu_flags flags; @@ -2336,7 +2374,11 @@ set_cpu_arch (int dummy ATTRIBUTE_UNUSED) else flags = cpu_flags_and_not (cpu_arch_flags, cpu_arch[j].flags); - if (!cpu_flags_equal (&flags, &cpu_arch_flags)) + + if (!valid_iamcu_cpu_flags (&flags)) + as_fatal (_("`%s' isn't valid for Intel MCU"), + cpu_arch[j].name); + else if (!cpu_flags_equal (&flags, &cpu_arch_flags)) { if (cpu_sub_arch_name) { @@ -2351,7 +2393,7 @@ set_cpu_arch (int dummy ATTRIBUTE_UNUSED) cpu_arch_flags = flags; cpu_arch_isa_flags = flags; } - *input_line_pointer = e; + (void) restore_line_pointer (e); demand_empty_rest_of_line (); return; } @@ -2368,8 +2410,11 @@ set_cpu_arch (int dummy ATTRIBUTE_UNUSED) if (*input_line_pointer == ',' && !is_end_of_line[(unsigned char) input_line_pointer[1]]) { - char *string = ++input_line_pointer; - int e = get_symbol_end (); + char *string; + char e; + + ++input_line_pointer; + e = get_symbol_name (&string); if (strcmp (string, "nojumps") == 0) no_cond_jump_promotion = 1; @@ -2378,7 +2423,7 @@ set_cpu_arch (int dummy ATTRIBUTE_UNUSED) else as_bad (_("no such architecture modifier: `%s'"), string); - *input_line_pointer = e; + (void) restore_line_pointer (e); } demand_empty_rest_of_line (); @@ -2401,6 +2446,13 @@ i386_arch (void) as_fatal (_("Intel K1OM is 64bit ELF only")); return bfd_arch_k1om; } + else if (cpu_arch_isa == PROCESSOR_IAMCU) + { + if (OUTPUT_FLAVOR != bfd_target_elf_flavour + || flag_code == CODE_64BIT) + as_fatal (_("Intel MCU is 32bit ELF only")); + return bfd_arch_iamcu; + } else return bfd_arch_i386; } @@ -2429,8 +2481,18 @@ i386_mach (void) else return bfd_mach_x64_32; } - else if (!strcmp (default_arch, "i386")) - return bfd_mach_i386_i386; + else if (!strcmp (default_arch, "i386") + || !strcmp (default_arch, "iamcu")) + { + if (cpu_arch_isa == PROCESSOR_IAMCU) + { + if (OUTPUT_FLAVOR != bfd_target_elf_flavour) + as_fatal (_("Intel MCU is 32bit ELF only")); + return bfd_mach_i386_iamcu; + } + else + return bfd_mach_i386_i386; + } else as_fatal (_("unknown architecture")); } @@ -2880,6 +2942,7 @@ tc_i386_fix_adjustable (fixS *fixP ATTRIBUTE_UNUSED) || fixP->fx_r_type == BFD_RELOC_386_GOTOFF || fixP->fx_r_type == BFD_RELOC_386_PLT32 || fixP->fx_r_type == BFD_RELOC_386_GOT32 + || fixP->fx_r_type == BFD_RELOC_386_GOT32X || fixP->fx_r_type == BFD_RELOC_386_TLS_GD || fixP->fx_r_type == BFD_RELOC_386_TLS_LDM || fixP->fx_r_type == BFD_RELOC_386_TLS_LDO_32 @@ -2893,6 +2956,8 @@ tc_i386_fix_adjustable (fixS *fixP ATTRIBUTE_UNUSED) || fixP->fx_r_type == BFD_RELOC_X86_64_PLT32 || fixP->fx_r_type == BFD_RELOC_X86_64_GOT32 || fixP->fx_r_type == BFD_RELOC_X86_64_GOTPCREL + || fixP->fx_r_type == BFD_RELOC_X86_64_GOTPCRELX + || fixP->fx_r_type == BFD_RELOC_X86_64_REX_GOTPCRELX || fixP->fx_r_type == BFD_RELOC_X86_64_TLSGD || fixP->fx_r_type == BFD_RELOC_X86_64_TLSLD || fixP->fx_r_type == BFD_RELOC_X86_64_DTPOFF32 @@ -3298,6 +3363,34 @@ process_immext (void) i.operands = 0; } + if (i.tm.cpu_flags.bitfield.cpumwaitx && i.operands > 0) + { + /* MONITORX/MWAITX instructions have fixed operands with an opcode + suffix which is coded in the same place as an 8-bit immediate + field would be. + Here we check those operands and remove them afterwards. */ + unsigned int x; + + if (i.operands != 3) + abort(); + + for (x = 0; x < 2; x++) + if (register_number (i.op[x].regs) != x) + goto bad_register_operand; + + /* Check for third operand for mwaitx/monitorx insn. */ + if (register_number (i.op[x].regs) + != (x + (i.tm.extension_opcode == 0xfb))) + { +bad_register_operand: + as_bad (_("can't use register '%s%s' as operand %d in '%s'."), + register_prefix, i.op[x].regs->reg_name, x+1, + i.tm.name); + } + + i.operands = 0; + } + /* These AMD 3DNow! and SSE2 instructions have an opcode suffix which is coded in the same place as an 8-bit immediate field would be. Here we fake an 8-bit immediate operand from the @@ -3888,14 +3981,14 @@ parse_operands (char *l, const char *mnemonic) /* Skip optional white space before operand. */ if (is_space_char (*l)) ++l; - if (!is_operand_char (*l) && *l != END_OF_INSN) + if (!is_operand_char (*l) && *l != END_OF_INSN && *l != '"') { as_bad (_("invalid character %s before operand %d"), output_invalid (*l), i.operands + 1); return NULL; } - token_start = l; /* after white space */ + token_start = l; /* After white space. */ paren_not_balanced = 0; while (paren_not_balanced || *l != ',') { @@ -3914,7 +4007,7 @@ parse_operands (char *l, const char *mnemonic) else break; /* we are done */ } - else if (!is_operand_char (*l) && !is_space_char (*l)) + else if (!is_operand_char (*l) && !is_space_char (*l) && *l != '"') { as_bad (_("invalid character %s in operand %d"), output_invalid (*l), @@ -4137,6 +4230,8 @@ optimize_imm (void) i.op[op].imms->X_add_number = (((i.op[op].imms->X_add_number & 0xffff) ^ 0x8000) - 0x8000); } +#ifdef BFD64 + /* Store 32-bit immediate in 64-bit for 64-bit BFD. */ if ((i.types[op].bitfield.imm32) && ((i.op[op].imms->X_add_number & ~(((offsetT) 2 << 31) - 1)) == 0)) @@ -4145,6 +4240,7 @@ optimize_imm (void) ^ ((offsetT) 1 << 31)) - ((offsetT) 1 << 31)); } +#endif i.types[op] = operand_type_or (i.types[op], smallest_imm_type (i.op[op].imms->X_add_number)); @@ -4225,6 +4321,8 @@ optimize_disp (void) op_disp = (((op_disp & 0xffff) ^ 0x8000) - 0x8000); i.types[op].bitfield.disp64 = 0; } +#ifdef BFD64 + /* Optimize 64-bit displacement to 32-bit for 64-bit BFD. */ if (i.types[op].bitfield.disp32 && (op_disp & ~(((offsetT) 2 << 31) - 1)) == 0) { @@ -4235,6 +4333,7 @@ optimize_disp (void) op_disp = (op_disp ^ ((offsetT) 1 << 31)) - ((addressT) 1 << 31); i.types[op].bitfield.disp64 = 0; } +#endif if (!op_disp && i.types[op].bitfield.baseindex) { i.types[op].bitfield.disp8 = 0; @@ -4476,7 +4575,9 @@ check_VecOperands (const insn_template *t) && i.op[op].disps->X_op == O_constant) { offsetT value = i.op[op].disps->X_add_number; - int vec_disp8_ok = fits_in_vec_disp8 (value); + int vec_disp8_ok + = (i.disp_encoding != disp_encoding_32bit + && fits_in_vec_disp8 (value)); if (t->operand_types [op].bitfield.vec_disp8) { if (vec_disp8_ok) @@ -4715,6 +4816,10 @@ match_template (void) } } + /* Force 0x8b encoding for "mov foo@GOT, %eax". */ + if (i.reloc[0] == BFD_RELOC_386_GOT32 && t->base_opcode == 0xa0) + continue; + /* We check register size if needed. */ check_register = t->opcode_modifier.checkregsize; overlap0 = operand_type_and (i.types[0], operand_types[0]); @@ -6865,6 +6970,22 @@ output_insn (void) unsigned int j; unsigned int prefix; + if (avoid_fence + && i.tm.base_opcode == 0xfae + && i.operands == 1 + && i.imm_operands == 1 + && (i.op[0].imms->X_add_number == 0xe8 + || i.op[0].imms->X_add_number == 0xf0 + || i.op[0].imms->X_add_number == 0xf8)) + { + /* Encode lfence, mfence, and sfence as + f0 83 04 24 00 lock addl $0x0, (%{re}sp). */ + offsetT val = 0x240483f0ULL; + p = frag_more (5); + md_number_to_chars (p, val, 5); + return; + } + /* Some processors fail on LOCK prefix. This options makes assembler ignore LOCK prefix and serves as a workaround. */ if (omit_lock_prefix) @@ -7081,6 +7202,7 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off) int size = disp_size (n); int sign = i.types[n].bitfield.disp32s; int pcrel = (i.flags[n] & Operand_PCrel) != 0; + fixS *fixP; /* We can't have 8 bit displacement here. */ gas_assert (!i.types[n].bitfield.disp8); @@ -7149,8 +7271,39 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off) insn, and that is taken care of in other code. */ reloc_type = BFD_RELOC_X86_64_GOTPC32; } - fix_new_exp (frag_now, p - frag_now->fr_literal, size, - i.op[n].disps, pcrel, reloc_type); + fixP = fix_new_exp (frag_now, p - frag_now->fr_literal, + size, i.op[n].disps, pcrel, + reloc_type); + /* Check for "call/jmp *mem", "mov mem, %reg", + "test %reg, mem" and "binop mem, %reg" where binop + is one of adc, add, and, cmp, or, sbb, sub, xor + instructions. Always generate R_386_GOT32X for + "sym*GOT" operand in 32-bit mode. */ + if ((generate_relax_relocations + || (!object_64bit + && i.rm.mode == 0 + && i.rm.regmem == 5)) + && (i.rm.mode == 2 + || (i.rm.mode == 0 && i.rm.regmem == 5)) + && ((i.operands == 1 + && i.tm.base_opcode == 0xff + && (i.rm.reg == 2 || i.rm.reg == 4)) + || (i.operands == 2 + && (i.tm.base_opcode == 0x8b + || i.tm.base_opcode == 0x85 + || (i.tm.base_opcode & 0xc7) == 0x03)))) + { + if (object_64bit) + { + fixP->fx_tcbit = i.rex != 0; + if (i.base_reg + && (i.base_reg->reg_num == RegRip + || i.base_reg->reg_num == RegEip)) + fixP->fx_tcbit2 = 1; + } + else + fixP->fx_tcbit2 = 1; + } } } } @@ -8558,6 +8711,7 @@ i386_att_operand (char *operand_string) } else if (is_digit_char (*op_string) || is_identifier_char (*op_string) + || *op_string == '"' || *op_string == '(') { /* This is a memory reference of some sort. */ @@ -8772,6 +8926,40 @@ i386_frag_max_var (fragS *frag) return TYPE_FROM_RELAX_STATE (frag->fr_subtype) == UNCOND_JUMP ? 4 : 5; } +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) +static int +elf_symbol_resolved_in_segment_p (symbolS *fr_symbol, offsetT fr_var) +{ + /* STT_GNU_IFUNC symbol must go through PLT. */ + if ((symbol_get_bfdsym (fr_symbol)->flags + & BSF_GNU_INDIRECT_FUNCTION) != 0) + return 0; + + if (!S_IS_EXTERNAL (fr_symbol)) + /* Symbol may be weak or local. */ + return !S_IS_WEAK (fr_symbol); + + /* Global symbols with non-default visibility can't be preempted. */ + if (ELF_ST_VISIBILITY (S_GET_OTHER (fr_symbol)) != STV_DEFAULT) + return 1; + + if (fr_var != NO_RELOC) + switch ((enum bfd_reloc_code_real) fr_var) + { + case BFD_RELOC_386_PLT32: + case BFD_RELOC_X86_64_PLT32: + /* Symbol with PLT relocatin may be preempted. */ + return 0; + default: + abort (); + } + + /* Global symbols with default visibility in a shared library may be + preempted by another definition. */ + return !shared; +} +#endif + /* md_estimate_size_before_relax() Called just before relax() for rs_machine_dependent frags. The x86 @@ -8795,10 +8983,8 @@ md_estimate_size_before_relax (fragS *fragP, segT segment) if (S_GET_SEGMENT (fragP->fr_symbol) != segment #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) || (IS_ELF - && (S_IS_EXTERNAL (fragP->fr_symbol) - || S_IS_WEAK (fragP->fr_symbol) - || ((symbol_get_bfdsym (fragP->fr_symbol)->flags - & BSF_GNU_INDIRECT_FUNCTION)))) + && !elf_symbol_resolved_in_segment_p (fragP->fr_symbol, + fragP->fr_var)) #endif #if defined (OBJ_COFF) && defined (TE_PE) || (OUTPUT_FLAVOR == bfd_target_coff_flavour @@ -9194,7 +9380,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) md_number_to_chars (p, value, fixP->fx_size); } -char * +const char * md_atof (int type, char *litP, int *sizeP) { /* This outputs the LITTLENUMs in REVERSE order; @@ -9360,7 +9546,7 @@ parse_register (char *reg_string, char **end_op) symbolS *symbolP; input_line_pointer = reg_string; - c = get_symbol_end (); + c = get_symbol_name (®_string); symbolP = symbol_find (reg_string); if (symbolP && S_GET_SEGMENT (symbolP) == reg_section) { @@ -9466,8 +9652,13 @@ const char *md_shortopts = "qn"; #define OPTION_MEVEXLIG (OPTION_MD_BASE + 16) #define OPTION_MEVEXWIG (OPTION_MD_BASE + 17) #define OPTION_MBIG_OBJ (OPTION_MD_BASE + 18) -#define OPTION_OMIT_LOCK_PREFIX (OPTION_MD_BASE + 19) +#define OPTION_MOMIT_LOCK_PREFIX (OPTION_MD_BASE + 19) #define OPTION_MEVEXRCIG (OPTION_MD_BASE + 20) +#define OPTION_MSHARED (OPTION_MD_BASE + 21) +#define OPTION_MAMD64 (OPTION_MD_BASE + 22) +#define OPTION_MINTEL64 (OPTION_MD_BASE + 23) +#define OPTION_MFENCE_AS_LOCK_ADD (OPTION_MD_BASE + 24) +#define OPTION_MRELAX_RELOCATIONS (OPTION_MD_BASE + 25) struct option md_longopts[] = { @@ -9478,6 +9669,7 @@ struct option md_longopts[] = #endif #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) {"x32", no_argument, NULL, OPTION_X32}, + {"mshared", no_argument, NULL, OPTION_MSHARED}, #endif {"divide", no_argument, NULL, OPTION_DIVIDE}, {"march", required_argument, NULL, OPTION_MARCH}, @@ -9497,14 +9689,18 @@ struct option md_longopts[] = # if defined (TE_PE) || defined (TE_PEP) {"mbig-obj", no_argument, NULL, OPTION_MBIG_OBJ}, #endif - {"momit-lock-prefix", required_argument, NULL, OPTION_OMIT_LOCK_PREFIX}, + {"momit-lock-prefix", required_argument, NULL, OPTION_MOMIT_LOCK_PREFIX}, + {"mfence-as-lock-add", required_argument, NULL, OPTION_MFENCE_AS_LOCK_ADD}, + {"mrelax-relocations", required_argument, NULL, OPTION_MRELAX_RELOCATIONS}, {"mevexrcig", required_argument, NULL, OPTION_MEVEXRCIG}, + {"mamd64", no_argument, NULL, OPTION_MAMD64}, + {"mintel64", no_argument, NULL, OPTION_MINTEL64}, {NULL, no_argument, NULL, 0} }; size_t md_longopts_size = sizeof (md_longopts); int -md_parse_option (int c, char *arg) +md_parse_option (int c, const char *arg) { unsigned int j; char *arch, *next; @@ -9538,6 +9734,10 @@ md_parse_option (int c, char *arg) /* -s: On i386 Solaris, this tells the native assembler to use .stab instead of .stab.excl. We always use .stab anyhow. */ break; + + case OPTION_MSHARED: + shared = 1; + break; #endif #if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \ || defined (TE_PE) || defined (TE_PEP) || defined (OBJ_MACH_O)) @@ -9647,7 +9847,10 @@ md_parse_option (int c, char *arg) else flags = cpu_flags_and_not (cpu_arch_flags, cpu_arch[j].flags); - if (!cpu_flags_equal (&flags, &cpu_arch_flags)) + + if (!valid_iamcu_cpu_flags (&flags)) + as_fatal (_("`%s' isn't valid for Intel MCU"), arch); + else if (!cpu_flags_equal (&flags, &cpu_arch_flags)) { if (cpu_sub_arch_name) { @@ -9799,7 +10002,7 @@ md_parse_option (int c, char *arg) break; #endif - case OPTION_OMIT_LOCK_PREFIX: + case OPTION_MOMIT_LOCK_PREFIX: if (strcasecmp (arg, "yes") == 0) omit_lock_prefix = 1; else if (strcasecmp (arg, "no") == 0) @@ -9808,6 +10011,38 @@ md_parse_option (int c, char *arg) as_fatal (_("invalid -momit-lock-prefix= option: `%s'"), arg); break; + case OPTION_MFENCE_AS_LOCK_ADD: + if (strcasecmp (arg, "yes") == 0) + avoid_fence = 1; + else if (strcasecmp (arg, "no") == 0) + avoid_fence = 0; + else + as_fatal (_("invalid -mfence-as-lock-add= option: `%s'"), arg); + break; + + case OPTION_MRELAX_RELOCATIONS: + if (strcasecmp (arg, "yes") == 0) + generate_relax_relocations = 1; + else if (strcasecmp (arg, "no") == 0) + generate_relax_relocations = 0; + else + as_fatal (_("invalid -mrelax-relocations= option: `%s'"), arg); + break; + + case OPTION_MAMD64: + cpu_arch_flags.bitfield.cpuamd64 = 1; + cpu_arch_flags.bitfield.cpuintel64 = 0; + cpu_arch_isa_flags.bitfield.cpuamd64 = 1; + cpu_arch_isa_flags.bitfield.cpuintel64 = 0; + break; + + case OPTION_MINTEL64: + cpu_arch_flags.bitfield.cpuamd64 = 0; + cpu_arch_flags.bitfield.cpuintel64 = 1; + cpu_arch_isa_flags.bitfield.cpuamd64 = 0; + cpu_arch_isa_flags.bitfield.cpuintel64 = 1; + break; + default: return 0; } @@ -9964,6 +10199,8 @@ md_show_usage (FILE *stream) -mold-gcc support old (<= 2.8.1) versions of gcc\n")); fprintf (stream, _("\ -madd-bnd-prefix add BND prefix for all valid branches\n")); + fprintf (stream, _("\ + -mshared disable branch optimization for shared code\n")); # if defined (TE_PE) || defined (TE_PEP) fprintf (stream, _("\ -mbig-obj generate big object files\n")); @@ -9971,6 +10208,17 @@ md_show_usage (FILE *stream) fprintf (stream, _("\ -momit-lock-prefix=[no|yes]\n\ strip all lock prefixes\n")); + fprintf (stream, _("\ + -mfence-as-lock-add=[no|yes]\n\ + encode lfence, mfence and sfence as\n\ + lock addl $0x0, (%%{re}sp)\n")); + fprintf (stream, _("\ + -mrelax-relocations=[no|yes]\n\ + generate relax relocations\n")); + fprintf (stream, _("\ + -mamd64 accept only AMD64 ISA\n")); + fprintf (stream, _("\ + -mintel64 accept only Intel64 ISA\n")); } #if ((defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT)) \ @@ -9992,6 +10240,27 @@ i386_target_format (void) } else if (!strcmp (default_arch, "i386")) update_code_flag (CODE_32BIT, 1); + else if (!strcmp (default_arch, "iamcu")) + { + update_code_flag (CODE_32BIT, 1); + if (cpu_arch_isa == PROCESSOR_UNKNOWN) + { + static const i386_cpu_flags iamcu_flags = CPU_IAMCU_FLAGS; + cpu_arch_name = "iamcu"; + cpu_sub_arch_name = NULL; + cpu_arch_flags = iamcu_flags; + cpu_arch_isa = PROCESSOR_IAMCU; + cpu_arch_isa_flags = iamcu_flags; + if (!cpu_arch_tune_set) + { + cpu_arch_tune = cpu_arch_isa; + cpu_arch_tune_flags = cpu_arch_isa_flags; + } + } + else + as_fatal (_("Intel MCU doesn't support `%s' architecture"), + cpu_arch_name); + } else as_fatal (_("unknown architecture")); @@ -10055,6 +10324,12 @@ i386_target_format (void) as_fatal (_("Intel K1OM is 64bit only")); return ELF_TARGET_K1OM_FORMAT; } + else if (cpu_arch_isa == PROCESSOR_IAMCU) + { + if (x86_elf_abi != I386_ABI) + as_fatal (_("Intel MCU is 32bit only")); + return ELF_TARGET_IAMCU_FORMAT; + } else return format; } @@ -10114,7 +10389,7 @@ md_section_align (segT segment ATTRIBUTE_UNUSED, valueT size) int align; align = bfd_get_section_alignment (stdoutput, segment); - size = ((size + (1 << align) - 1) & ((valueT) -1 << align)); + size = ((size + (1 << align) - 1) & (-((valueT) 1 << align))); } #endif @@ -10152,23 +10427,41 @@ s_bss (int ignore ATTRIBUTE_UNUSED) void i386_validate_fix (fixS *fixp) { - if (fixp->fx_subsy && fixp->fx_subsy == GOT_symbol) + if (fixp->fx_subsy) { - if (fixp->fx_r_type == BFD_RELOC_32_PCREL) - { - if (!object_64bit) - abort (); - fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL; - } - else + if (fixp->fx_subsy == GOT_symbol) { - if (!object_64bit) - fixp->fx_r_type = BFD_RELOC_386_GOTOFF; + if (fixp->fx_r_type == BFD_RELOC_32_PCREL) + { + if (!object_64bit) + abort (); +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + if (fixp->fx_tcbit2) + fixp->fx_r_type = (fixp->fx_tcbit + ? BFD_RELOC_X86_64_REX_GOTPCRELX + : BFD_RELOC_X86_64_GOTPCRELX); + else +#endif + fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL; + } else - fixp->fx_r_type = BFD_RELOC_X86_64_GOTOFF64; + { + if (!object_64bit) + fixp->fx_r_type = BFD_RELOC_386_GOTOFF; + else + fixp->fx_r_type = BFD_RELOC_X86_64_GOTOFF64; + } + fixp->fx_subsy = 0; } - fixp->fx_subsy = 0; } +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + else if (!object_64bit) + { + if (fixp->fx_r_type == BFD_RELOC_386_GOT32 + && fixp->fx_tcbit2) + fixp->fx_r_type = BFD_RELOC_386_GOT32X; + } +#endif } arelent * @@ -10202,8 +10495,11 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) case BFD_RELOC_X86_64_PLT32: case BFD_RELOC_X86_64_GOT32: case BFD_RELOC_X86_64_GOTPCREL: + case BFD_RELOC_X86_64_GOTPCRELX: + case BFD_RELOC_X86_64_REX_GOTPCRELX: case BFD_RELOC_386_PLT32: case BFD_RELOC_386_GOT32: + case BFD_RELOC_386_GOT32X: case BFD_RELOC_386_GOTOFF: case BFD_RELOC_386_GOTPC: case BFD_RELOC_386_TLS_GD: @@ -10355,6 +10651,8 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) case BFD_RELOC_X86_64_PLT32: case BFD_RELOC_X86_64_GOT32: case BFD_RELOC_X86_64_GOTPCREL: + case BFD_RELOC_X86_64_GOTPCRELX: + case BFD_RELOC_X86_64_REX_GOTPCRELX: case BFD_RELOC_X86_64_TLSGD: case BFD_RELOC_X86_64_TLSLD: case BFD_RELOC_X86_64_GOTTPOFF: @@ -10485,7 +10783,7 @@ tc_pe_dwarf2_emit_offset (symbolS *symbol, unsigned int size) /* For ELF on x86-64, add support for SHF_X86_64_LARGE. */ bfd_vma -x86_64_section_letter (int letter, char **ptr_msg) +x86_64_section_letter (int letter, const char **ptr_msg) { if (flag_code == CODE_64BIT) {