diff options
Diffstat (limited to 'binutils-2.25/gas/config/tc-i386.c')
-rw-r--r-- | binutils-2.25/gas/config/tc-i386.c | 10531 |
1 files changed, 10531 insertions, 0 deletions
diff --git a/binutils-2.25/gas/config/tc-i386.c b/binutils-2.25/gas/config/tc-i386.c new file mode 100644 index 00000000..32f6d48a --- /dev/null +++ b/binutils-2.25/gas/config/tc-i386.c @@ -0,0 +1,10531 @@ +/* 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, 2010, 2011, + 2012 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +/* Intel 80386 machine specific gas. + Written by Eliot Dresselhaus (eliot@mgm.mit.edu). + x86_64 support by Jan Hubicka (jh@suse.cz) + VIA PadLock support by Michal Ludvig (mludvig@suse.cz) + Bugs & suggestions are completely welcome. This is free software. + Please help us make it better. */ + +#include "as.h" +#include "safe-ctype.h" +#include "subsegs.h" +#include "dwarf2dbg.h" +#include "dw2gencfi.h" +#include "elf/x86-64.h" +#include "opcodes/i386-init.h" + +#ifndef REGISTER_WARNINGS +#define REGISTER_WARNINGS 1 +#endif + +#ifndef INFER_ADDR_PREFIX +#define INFER_ADDR_PREFIX 1 +#endif + +#ifndef DEFAULT_ARCH +#define DEFAULT_ARCH "i386" +#endif + +#ifndef INLINE +#if __GNUC__ >= 2 +#define INLINE __inline__ +#else +#define INLINE +#endif +#endif + +/* Prefixes will be emitted in the order defined below. + WAIT_PREFIX must be the first prefix since FWAIT is really is an + instruction, and so must come before any prefixes. + The preferred prefix order is SEG_PREFIX, ADDR_PREFIX, DATA_PREFIX, + REP_PREFIX/HLE_PREFIX, LOCK_PREFIX. */ +#define WAIT_PREFIX 0 +#define SEG_PREFIX 1 +#define ADDR_PREFIX 2 +#define DATA_PREFIX 3 +#define REP_PREFIX 4 +#define HLE_PREFIX REP_PREFIX +#define BND_PREFIX REP_PREFIX +#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 '%' +#define IMMEDIATE_PREFIX '$' +#define ABSOLUTE_PREFIX '*' + +/* these are the instruction mnemonic suffixes in AT&T syntax or + memory operand size in Intel syntax. */ +#define WORD_MNEM_SUFFIX 'w' +#define BYTE_MNEM_SUFFIX 'b' +#define SHORT_MNEM_SUFFIX 's' +#define LONG_MNEM_SUFFIX 'l' +#define QWORD_MNEM_SUFFIX 'q' +#define XMMWORD_MNEM_SUFFIX 'x' +#define YMMWORD_MNEM_SUFFIX 'y' +#define ZMMWORD_MNEM_SUFFIX 'z' +/* Intel Syntax. Use a non-ascii letter since since it never appears + in instructions. */ +#define LONG_DOUBLE_MNEM_SUFFIX '\1' + +#define END_OF_INSN '\0' + +/* + 'templates' is for grouping together 'template' structures for opcodes + of the same name. This is only used for storing the insns in the grand + ole hash table of insns. + The templates themselves start at START and range up to (but not including) + END. + */ +typedef struct +{ + const insn_template *start; + const insn_template *end; +} +templates; + +/* 386 operand encoding bytes: see 386 book for details of this. */ +typedef struct +{ + unsigned int regmem; /* codes register or memory operand */ + unsigned int reg; /* codes register operand (or extended opcode) */ + unsigned int mode; /* how to interpret regmem & reg */ +} +modrm_byte; + +/* x86-64 extension prefix. */ +typedef int rex_byte; + +/* 386 opcode byte to code indirect addressing. */ +typedef struct +{ + unsigned base; + unsigned index; + unsigned scale; +} +sib_byte; + +/* x86 arch names, types and features */ +typedef struct +{ + const char *name; /* arch name */ + 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); +static void set_intel_mnemonic (int); +static void set_allow_index_reg (int); +static void set_check (int); +static void set_cpu_arch (int); +#ifdef TE_PE +static void pe_directive_secrel (int); +#endif +static void signed_cons (int); +static char *output_invalid (int c); +static int i386_finalize_immediate (segT, expressionS *, i386_operand_type, + const char *); +static int i386_finalize_displacement (segT, expressionS *, i386_operand_type, + const char *); +static int i386_att_operand (char *); +static int i386_intel_operand (char *, int); +static int i386_intel_simplify (expressionS *); +static int i386_intel_parse_name (const char *, expressionS *); +static const reg_entry *parse_register (char *, char **); +static char *parse_insn (char *, char *); +static char *parse_operands (char *, const char *); +static void swap_operands (void); +static void swap_2_operands (int, int); +static void optimize_imm (void); +static void optimize_disp (void); +static const insn_template *match_template (void); +static int check_string (void); +static int process_suffix (void); +static int check_byte_reg (void); +static int check_long_reg (void); +static int check_qword_reg (void); +static int check_word_reg (void); +static int finalize_imm (void); +static int process_operands (void); +static const seg_entry *build_modrm_byte (void); +static void output_insn (void); +static void output_imm (fragS *, offsetT); +static void output_disp (fragS *, offsetT); +#ifndef I386COFF +static void s_bss (int); +#endif +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) +static void handle_large_common (int small ATTRIBUTE_UNUSED); +#endif + +static const char *default_arch = DEFAULT_ARCH; + +/* This struct describes rounding control and SAE in the instruction. */ +struct RC_Operation +{ + enum rc_type + { + rne = 0, + rd, + ru, + rz, + saeonly + } type; + int operand; +}; + +static struct RC_Operation rc_op; + +/* The struct describes masking, applied to OPERAND in the instruction. + MASK is a pointer to the corresponding mask register. ZEROING tells + whether merging or zeroing mask is used. */ +struct Mask_Operation +{ + const reg_entry *mask; + unsigned int zeroing; + /* The operand where this operation is associated. */ + int operand; +}; + +static struct Mask_Operation mask_op; + +/* The struct describes broadcasting, applied to OPERAND. FACTOR is + broadcast factor. */ +struct Broadcast_Operation +{ + /* Type of broadcast: no broadcast, {1to8}, or {1to16}. */ + int type; + + /* Index of broadcasted operand. */ + int operand; +}; + +static struct Broadcast_Operation broadcast_op; + +/* VEX prefix. */ +typedef struct +{ + /* VEX prefix is either 2 byte or 3 byte. EVEX is 4 byte. */ + unsigned char bytes[4]; + unsigned int length; + /* Destination or source register specifier. */ + const reg_entry *register_specifier; +} vex_prefix; + +/* 'md_assemble ()' gathers together information and puts it into a + i386_insn. */ + +union i386_op + { + expressionS *disps; + expressionS *imms; + 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, + invalid_vector_register_set, + unsupported_vector_index_register, + unsupported_broadcast, + broadcast_not_on_src_operand, + broadcast_needed, + unsupported_masking, + mask_not_on_destination, + no_default_mask, + unsupported_rc_sae, + rc_sae_operand_not_last_imm, + invalid_register_operand, + try_vector_disp8 + }; + +struct _i386_insn + { + /* TM holds the template for the insn were currently assembling. */ + insn_template tm; + + /* SUFFIX holds the instruction size suffix for byte, word, dword + or qword, if given. */ + char suffix; + + /* OPERANDS gives the number of given operands. */ + unsigned int operands; + + /* REG_OPERANDS, DISP_OPERANDS, MEM_OPERANDS, IMM_OPERANDS give the number + of given register, displacement, memory operands and immediate + operands. */ + unsigned int reg_operands, disp_operands, mem_operands, imm_operands; + + /* TYPES [i] is the type (see above #defines) which tells us how to + use OP[i] for the corresponding operand. */ + i386_operand_type types[MAX_OPERANDS]; + + /* Displacement expression, immediate expression, or register for each + operand. */ + union i386_op op[MAX_OPERANDS]; + + /* Flags for operands. */ + unsigned int flags[MAX_OPERANDS]; +#define Operand_PCrel 1 + + /* Relocation type for operand */ + enum bfd_reloc_code_real reloc[MAX_OPERANDS]; + + /* BASE_REG, INDEX_REG, and LOG2_SCALE_FACTOR are used to encode + the base index byte below. */ + const reg_entry *base_reg; + const reg_entry *index_reg; + unsigned int log2_scale_factor; + + /* SEG gives the seg_entries of this insn. They are zero unless + explicit segment overrides are given. */ + const seg_entry *seg[2]; + + /* PREFIX holds all the given prefix opcodes (usually null). + PREFIXES is the number of prefix opcodes. */ + unsigned int prefixes; + unsigned char prefix[MAX_PREFIXES]; + + /* RM and SIB are the modrm byte and the sib byte where the + addressing modes of this insn are encoded. */ + modrm_byte rm; + rex_byte rex; + rex_byte vrex; + sib_byte sib; + vex_prefix vex; + + /* Masking attributes. */ + struct Mask_Operation *mask; + + /* Rounding control and SAE attributes. */ + struct RC_Operation *rounding; + + /* Broadcasting attributes. */ + struct Broadcast_Operation *broadcast; + + /* Compressed disp8*N attribute. */ + unsigned int memshift; + + /* Swap operand in encoding. */ + unsigned int swap_operand; + + /* Prefer 8bit or 32bit displacement in encoding. */ + enum + { + disp_encoding_default = 0, + disp_encoding_8bit, + disp_encoding_32bit + } disp_encoding; + + /* REP prefix. */ + const char *rep_prefix; + + /* HLE prefix. */ + const char *hle_prefix; + + /* Have BND prefix. */ + const char *bnd_prefix; + + /* Need VREX to support upper 16 registers. */ + int need_vrex; + + /* Error message. */ + enum i386_error error; + }; + +typedef struct _i386_insn i386_insn; + +/* Link RC type with corresponding string, that'll be looked for in + asm. */ +struct RC_name +{ + enum rc_type type; + const char *name; + unsigned int len; +}; + +static const struct RC_name RC_NamesTable[] = +{ + { rne, STRING_COMMA_LEN ("rn-sae") }, + { rd, STRING_COMMA_LEN ("rd-sae") }, + { ru, STRING_COMMA_LEN ("ru-sae") }, + { rz, STRING_COMMA_LEN ("rz-sae") }, + { saeonly, STRING_COMMA_LEN ("sae") }, +}; + +/* List of chars besides those in app.c:symbol_chars that can start an + operand. Used to prevent the scrubber eating vital white-space. */ +const char extra_symbol_chars[] = "*%-([{" +#ifdef LEX_AT + "@" +#endif +#ifdef LEX_QM + "?" +#endif + ; + +#if (defined (TE_I386AIX) \ + || ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) \ + && !defined (TE_GNU) \ + && !defined (TE_LINUX) \ + && !defined (TE_NACL) \ + && !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 + --divide will remove '/' from this list. */ +const char *i386_comment_chars = "#/"; +#define SVR4_COMMENT_CHARS 1 +#define PREFIX_SEPARATOR '\\' + +#else +const char *i386_comment_chars = "#"; +#define PREFIX_SEPARATOR '/' +#endif + +/* This array holds the chars that only start a comment at the beginning of + a line. If the line seems to have the form '# 123 filename' + .line and .file directives will appear in the pre-processed output. + Note that input_file.c hand checks for '#' at the beginning of the + first line of the input file. This is because the compiler outputs + #NO_APP at the beginning of its output. + Also note that comments started like this one will always work if + '/' isn't otherwise defined. */ +const char line_comment_chars[] = "#/"; + +const char line_separator_chars[] = ";"; + +/* Chars that can be used to separate mant from exp in floating point + nums. */ +const char EXP_CHARS[] = "eE"; + +/* Chars that mean this number is a floating point constant + As in 0f12.456 + or 0d1.2345e12. */ +const char FLT_CHARS[] = "fFdDxX"; + +/* Tables for lexical analysis. */ +static char mnemonic_chars[256]; +static char register_chars[256]; +static char operand_chars[256]; +static char identifier_chars[256]; +static char digit_chars[256]; + +/* Lexical macros. */ +#define is_mnemonic_char(x) (mnemonic_chars[(unsigned char) x]) +#define is_operand_char(x) (operand_chars[(unsigned char) x]) +#define is_register_char(x) (register_chars[(unsigned char) x]) +#define is_space_char(x) ((x) == ' ') +#define is_identifier_char(x) (identifier_chars[(unsigned char) x]) +#define is_digit_char(x) (digit_chars[(unsigned char) x]) + +/* All non-digit non-letter characters that may occur in an operand. */ +static char operand_special_chars[] = "%$-+(,)*._~/<>|&^!:[@]"; + +/* md_assemble() always leaves the strings it's passed unaltered. To + effect this we maintain a stack of saved characters that we've smashed + with '\0's (indicating end of strings for various sub-fields of the + assembler instruction). */ +static char save_stack[32]; +static char *save_stack_p; +#define END_STRING_AND_SAVE(s) \ + do { *save_stack_p++ = *(s); *(s) = '\0'; } while (0) +#define RESTORE_END_STRING(s) \ + do { *(s) = *--save_stack_p; } while (0) + +/* The instruction we're assembling. */ +static i386_insn i; + +/* Possible templates for current insn. */ +static const templates *current_templates; + +/* Per instruction expressionS buffers: max displacements & immediates. */ +static expressionS disp_expressions[MAX_MEMORY_OPERANDS]; +static expressionS im_expressions[MAX_IMMEDIATE_OPERANDS]; + +/* Current operand we are working on. */ +static int this_operand = -1; + +/* We support four different modes. FLAG_CODE variable is used to distinguish + these. */ + +enum flag_code { + CODE_32BIT, + CODE_16BIT, + CODE_64BIT }; + +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 + +/* 1 for intel syntax, + 0 if att syntax. */ +static int intel_syntax = 0; + +/* 1 for intel mnemonic, + 0 if att mnemonic. */ +static int intel_mnemonic = !SYSV386_COMPAT; + +/* 1 if support old (<= 2.8.1) versions of gcc. */ +static int old_gcc = OLDGCC_COMPAT; + +/* 1 if pseudo registers are permitted. */ +static int allow_pseudo_reg = 0; + +/* 1 if register prefix % not required. */ +static int allow_naked_reg = 0; + +/* 1 if the assembler should add BND prefix for all control-tranferring + instructions supporting it, even if this prefix wasn't specified + explicitly. */ +static int add_bnd_prefix = 0; + +/* 1 if pseudo index register, eiz/riz, is allowed . */ +static int allow_index_reg = 0; + +static enum check_kind + { + check_none = 0, + check_warning, + check_error + } +sse_check, operand_check = check_warning; + +/* Register prefix used for error message. */ +static const char *register_prefix = "%"; + +/* Used in 16 bit gcc mode to add an l suffix to call, ret, enter, + leave, push, and pop instructions so that gcc has the same stack + frame as in 32 bit mode. */ +static char stackop_size = '\0'; + +/* Non-zero to optimize code alignment. */ +int optimize_align_code = 1; + +/* Non-zero to quieten some warnings. */ +static int quiet_warnings = 0; + +/* CPU name. */ +static const char *cpu_arch_name = NULL; +static char *cpu_sub_arch_name = NULL; + +/* CPU feature flags. */ +static i386_cpu_flags cpu_arch_flags = CPU_UNKNOWN_FLAGS; + +/* If we have selected a cpu we are generating instructions for. */ +static int cpu_arch_tune_set = 0; + +/* Cpu we are generating instructions for. */ +enum processor_type cpu_arch_tune = PROCESSOR_UNKNOWN; + +/* CPU feature flags of cpu we are generating instructions for. */ +static i386_cpu_flags cpu_arch_tune_flags; + +/* CPU instruction set architecture used. */ +enum processor_type cpu_arch_isa = PROCESSOR_UNKNOWN; + +/* CPU feature flags of instruction set architecture used. */ +i386_cpu_flags cpu_arch_isa_flags; + +/* If set, conditional jumps are not automatically promoted to handle + larger than a byte offset. */ +static unsigned int no_cond_jump_promotion = 0; + +/* Encode SSE instructions with VEX prefix. */ +static unsigned int sse2avx; + +/* Encode scalar AVX instructions with specific vector length. */ +static enum + { + vex128 = 0, + vex256 + } avxscalar; + +/* Encode scalar EVEX LIG instructions with specific vector length. */ +static enum + { + evexl128 = 0, + evexl256, + evexl512 + } evexlig; + +/* Encode EVEX WIG instructions with specific evex.w. */ +static enum + { + evexw0 = 0, + evexw1 + } evexwig; + +/* Pre-defined "_GLOBAL_OFFSET_TABLE_". */ +static symbolS *GOT_symbol; + +/* The dwarf2 return column, adjusted for 32 or 64 bit. */ +unsigned int x86_dwarf2_return_column; + +/* The dwarf2 data alignment, adjusted for 32 or 64 bit. */ +int x86_cie_data_alignment; + +/* Interface to relax_segment. + There are 3 major relax states for 386 jump insns because the + different types of jumps add different sizes to frags when we're + figuring out what sort of jump to choose to reach a given label. */ + +/* Types. */ +#define UNCOND_JUMP 0 +#define COND_JUMP 1 +#define COND_JUMP86 2 + +/* Sizes. */ +#define CODE16 1 +#define SMALL 0 +#define SMALL16 (SMALL | CODE16) +#define BIG 2 +#define BIG16 (BIG | CODE16) + +#ifndef INLINE +#ifdef __GNUC__ +#define INLINE __inline__ +#else +#define INLINE +#endif +#endif + +#define ENCODE_RELAX_STATE(type, size) \ + ((relax_substateT) (((type) << 2) | (size))) +#define TYPE_FROM_RELAX_STATE(s) \ + ((s) >> 2) +#define DISP_SIZE_FROM_RELAX_STATE(s) \ + ((((s) & 3) == BIG ? 4 : (((s) & 3) == BIG16 ? 2 : 1))) + +/* This table is used by relax_frag to promote short jumps to long + ones where necessary. SMALL (short) jumps may be promoted to BIG + (32 bit long) ones, and SMALL16 jumps to BIG16 (16 bit long). We + don't allow a short jump in a 32 bit code segment to be promoted to + a 16 bit offset jump because it's slower (requires data size + prefix), and doesn't work, unless the destination is in the bottom + 64k of the code segment (The top 16 bits of eip are zeroed). */ + +const relax_typeS md_relax_table[] = +{ + /* The fields are: + 1) most positive reach of this state, + 2) most negative reach of this state, + 3) how many bytes this mode will have in the variable part of the frag + 4) which index into the table to try if we can't fit into this one. */ + + /* UNCOND_JUMP states. */ + {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (UNCOND_JUMP, BIG)}, + {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (UNCOND_JUMP, BIG16)}, + /* dword jmp adds 4 bytes to frag: + 0 extra opcode bytes, 4 displacement bytes. */ + {0, 0, 4, 0}, + /* word jmp adds 2 byte2 to frag: + 0 extra opcode bytes, 2 displacement bytes. */ + {0, 0, 2, 0}, + + /* COND_JUMP states. */ + {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP, BIG)}, + {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP, BIG16)}, + /* dword conditionals adds 5 bytes to frag: + 1 extra opcode byte, 4 displacement bytes. */ + {0, 0, 5, 0}, + /* word conditionals add 3 bytes to frag: + 1 extra opcode byte, 2 displacement bytes. */ + {0, 0, 3, 0}, + + /* COND_JUMP86 states. */ + {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP86, BIG)}, + {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP86, BIG16)}, + /* dword conditionals adds 5 bytes to frag: + 1 extra opcode byte, 4 displacement bytes. */ + {0, 0, 5, 0}, + /* word conditionals add 4 bytes to frag: + 1 displacement byte and a 3 byte long branch insn. */ + {0, 0, 4, 0} +}; + +static const arch_entry cpu_arch[] = +{ + /* 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 ("bdver3"), PROCESSOR_BD, + CPU_BDVER3_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("bdver4"), PROCESSOR_BD, + CPU_BDVER4_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("btver1"), PROCESSOR_BT, + CPU_BTVER1_FLAGS, 0, 0 }, + { STRING_COMMA_LEN ("btver2"), PROCESSOR_BT, + CPU_BTVER2_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 (".avx512f"), PROCESSOR_UNKNOWN, + CPU_AVX512F_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".avx512cd"), PROCESSOR_UNKNOWN, + CPU_AVX512CD_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".avx512er"), PROCESSOR_UNKNOWN, + CPU_AVX512ER_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".avx512pf"), PROCESSOR_UNKNOWN, + CPU_AVX512PF_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 (".cx16"), PROCESSOR_UNKNOWN, + CPU_CX16_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 (".hle"), PROCESSOR_UNKNOWN, + CPU_HLE_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".rtm"), PROCESSOR_UNKNOWN, + CPU_RTM_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".invpcid"), PROCESSOR_UNKNOWN, + 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 }, + { STRING_COMMA_LEN (".adx"), PROCESSOR_UNKNOWN, + CPU_ADX_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".rdseed"), PROCESSOR_UNKNOWN, + CPU_RDSEED_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".prfchw"), PROCESSOR_UNKNOWN, + CPU_PRFCHW_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".smap"), PROCESSOR_UNKNOWN, + CPU_SMAP_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".mpx"), PROCESSOR_UNKNOWN, + CPU_MPX_FLAGS, 0, 0 }, + { STRING_COMMA_LEN (".sha"), PROCESSOR_UNKNOWN, + CPU_SHA_FLAGS, 0, 0 }, +}; + +#ifdef I386COFF +/* Like s_lcomm_internal in gas/read.c but the alignment string + is allowed to be optional. */ + +static symbolS * +pe_lcomm_internal (int needs_align, symbolS *symbolP, addressT size) +{ + addressT align = 0; + + SKIP_WHITESPACE (); + + if (needs_align + && *input_line_pointer == ',') + { + align = parse_align (needs_align - 1); + + if (align == (addressT) -1) + return NULL; + } + else + { + if (size >= 8) + align = 3; + else if (size >= 4) + align = 2; + else if (size >= 2) + align = 1; + else + align = 0; + } + + bss_alloc (symbolP, size, align); + return symbolP; +} + +static void +pe_lcomm (int needs_align) +{ + s_comm_internal (needs_align * 2, pe_lcomm_internal); +} +#endif + +const pseudo_typeS md_pseudo_table[] = +{ +#if !defined(OBJ_AOUT) && !defined(USE_ALIGN_PTWO) + {"align", s_align_bytes, 0}, +#else + {"align", s_align_ptwo, 0}, +#endif + {"arch", set_cpu_arch, 0}, +#ifndef I386COFF + {"bss", s_bss, 0}, +#else + {"lcomm", pe_lcomm, 1}, +#endif + {"ffloat", float_cons, 'f'}, + {"dfloat", float_cons, 'd'}, + {"tfloat", float_cons, 'x'}, + {"value", cons, 2}, + {"slong", signed_cons, 4}, + {"noopt", s_ignore, 0}, + {"optim", s_ignore, 0}, + {"code16gcc", set_16bit_gcc_code_flag, CODE_16BIT}, + {"code16", set_code_flag, CODE_16BIT}, + {"code32", set_code_flag, CODE_32BIT}, + {"code64", set_code_flag, CODE_64BIT}, + {"intel_syntax", set_intel_syntax, 1}, + {"att_syntax", set_intel_syntax, 0}, + {"intel_mnemonic", set_intel_mnemonic, 1}, + {"att_mnemonic", set_intel_mnemonic, 0}, + {"allow_index_reg", set_allow_index_reg, 1}, + {"disallow_index_reg", set_allow_index_reg, 0}, + {"sse_check", set_check, 0}, + {"operand_check", set_check, 1}, +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + {"largecomm", handle_large_common, 0}, +#else + {"file", (void (*) (int)) dwarf2_directive_file, 0}, + {"loc", dwarf2_directive_loc, 0}, + {"loc_mark_labels", dwarf2_directive_loc_mark_labels, 0}, +#endif +#ifdef TE_PE + {"secrel32", pe_directive_secrel, 0}, +#endif + {0, 0, 0} +}; + +/* For interface with expression (). */ +extern char *input_line_pointer; + +/* Hash table for instruction mnemonic lookup. */ +static struct hash_control *op_hash; + +/* Hash table for register lookup. */ +static struct hash_control *reg_hash; + +void +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[] = + {0x90}; /* nop */ + static const char f32_2[] = + {0x66,0x90}; /* xchg %ax,%ax */ + static const char f32_3[] = + {0x8d,0x76,0x00}; /* leal 0(%esi),%esi */ + static const char f32_4[] = + {0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */ + static const char f32_5[] = + {0x90, /* nop */ + 0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */ + static const char f32_6[] = + {0x8d,0xb6,0x00,0x00,0x00,0x00}; /* leal 0L(%esi),%esi */ + static const char f32_7[] = + {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */ + static const char f32_8[] = + {0x90, /* nop */ + 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */ + static const 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[] = + {0x8d,0x76,0x00, /* leal 0(%esi),%esi */ + 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ + static const 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[] = + {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[] = + {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[] = + {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[] = + {0x8d,0x74,0x00}; /* lea 0(%esi),%esi */ + static const char f16_4[] = + {0x8d,0xb4,0x00,0x00}; /* lea 0w(%si),%si */ + static const char f16_5[] = + {0x90, /* nop */ + 0x8d,0xb4,0x00,0x00}; /* lea 0w(%si),%si */ + static const char f16_6[] = + {0x89,0xf6, /* mov %si,%si */ + 0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */ + static const char f16_7[] = + {0x8d,0x74,0x00, /* lea 0(%si),%si */ + 0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */ + static const char f16_8[] = + {0x8d,0xb4,0x00,0x00, /* lea 0w(%si),%si */ + 0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */ + static const 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[] = { + 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[] = { + f32_1, f32_2, f16_3, f16_4, f16_5, f16_6, f16_7, f16_8 + }; + /* nopl (%[re]ax) */ + static const char alt_3[] = + {0x0f,0x1f,0x00}; + /* nopl 0(%[re]ax) */ + static const char alt_4[] = + {0x0f,0x1f,0x40,0x00}; + /* nopl 0(%[re]ax,%[re]ax,1) */ + static const char alt_5[] = + {0x0f,0x1f,0x44,0x00,0x00}; + /* nopw 0(%[re]ax,%[re]ax,1) */ + static const char alt_6[] = + {0x66,0x0f,0x1f,0x44,0x00,0x00}; + /* nopl 0L(%[re]ax) */ + static const char alt_7[] = + {0x0f,0x1f,0x80,0x00,0x00,0x00,0x00}; + /* nopl 0L(%[re]ax,%[re]ax,1) */ + static const char alt_8[] = + {0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; + /* nopw 0L(%[re]ax,%[re]ax,1) */ + static const 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[] = + {0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; + /* data16 + nopw %cs:0L(%[re]ax,%[re]ax,1) */ + static const char alt_long_11[] = + {0x66, + 0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; + /* data16 + data16 + nopw %cs:0L(%[re]ax,%[re]ax,1) */ + static const char alt_long_12[] = + {0x66, + 0x66, + 0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; + /* data16 + data16 + data16 + nopw %cs:0L(%[re]ax,%[re]ax,1) */ + static const char alt_long_13[] = + {0x66, + 0x66, + 0x66, + 0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; + /* data16 + data16 + data16 + data16 + nopw %cs:0L(%[re]ax,%[re]ax,1) */ + static const char alt_long_14[] = + {0x66, + 0x66, + 0x66, + 0x66, + 0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; + /* data16 + data16 + data16 + data16 + data16 + nopw %cs:0L(%[re]ax,%[re]ax,1) */ + static const char alt_long_15[] = + {0x66, + 0x66, + 0x66, + 0x66, + 0x66, + 0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; + /* nopl 0(%[re]ax,%[re]ax,1) + nopw 0(%[re]ax,%[re]ax,1) */ + static const char alt_short_11[] = + {0x0f,0x1f,0x44,0x00,0x00, + 0x66,0x0f,0x1f,0x44,0x00,0x00}; + /* nopw 0(%[re]ax,%[re]ax,1) + nopw 0(%[re]ax,%[re]ax,1) */ + static const char alt_short_12[] = + {0x66,0x0f,0x1f,0x44,0x00,0x00, + 0x66,0x0f,0x1f,0x44,0x00,0x00}; + /* nopw 0(%[re]ax,%[re]ax,1) + nopl 0L(%[re]ax) */ + static const char alt_short_13[] = + {0x66,0x0f,0x1f,0x44,0x00,0x00, + 0x0f,0x1f,0x80,0x00,0x00,0x00,0x00}; + /* nopl 0L(%[re]ax) + nopl 0L(%[re]ax) */ + static const char alt_short_14[] = + {0x0f,0x1f,0x80,0x00,0x00,0x00,0x00, + 0x0f,0x1f,0x80,0x00,0x00,0x00,0x00}; + /* nopl 0L(%[re]ax) + nopl 0L(%[re]ax,%[re]ax,1) */ + static const char alt_short_15[] = + {0x0f,0x1f,0x80,0x00,0x00,0x00,0x00, + 0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00}; + static const char *const alt_short_patt[] = { + f32_1, f32_2, alt_3, alt_4, alt_5, alt_6, alt_7, alt_8, + alt_9, alt_10, alt_short_11, alt_short_12, alt_short_13, + alt_short_14, alt_short_15 + }; + static const char *const alt_long_patt[] = { + f32_1, f32_2, alt_3, alt_4, alt_5, alt_6, alt_7, alt_8, + alt_9, alt_10, alt_long_11, alt_long_12, alt_long_13, + alt_long_14, alt_long_15 + }; + + /* Only align for at least a positive non-zero boundary. */ + if (count <= 0 || count > MAX_MEM_FOR_RS_ALIGN_CODE) + return; + + /* We need to decide which NOP sequence to use for 32bit and + 64bit. When -mtune= is used: + + 1. For PROCESSOR_I386, PROCESSOR_I486, PROCESSOR_PENTIUM and + PROCESSOR_GENERIC32, f32_patt will be used. + 2. For PROCESSOR_PENTIUMPRO, PROCESSOR_PENTIUM4, PROCESSOR_NOCONA, + PROCESSOR_CORE, PROCESSOR_CORE2, PROCESSOR_COREI7, and + PROCESSOR_GENERIC64, alt_long_patt will be used. + 3. For PROCESSOR_ATHLON, PROCESSOR_K6, PROCESSOR_K8 and + PROCESSOR_AMDFAM10, PROCESSOR_BD and PROCESSOR_BT, alt_short_patt + will be used. + + When -mtune= isn't used, alt_long_patt will be used if + cpu_arch_isa_flags has CpuNop. Otherwise, f32_patt will + be used. + + When -march= or .arch is used, we can't use anything beyond + cpu_arch_isa_flags. */ + + if (flag_code == CODE_16BIT) + { + if (count > 8) + { + memcpy (fragP->fr_literal + fragP->fr_fix, + jump_31, count); + /* Adjust jump offset. */ + fragP->fr_literal[fragP->fr_fix + 1] = count - 2; + } + else + memcpy (fragP->fr_literal + fragP->fr_fix, + f16_patt[count - 1], count); + } + else + { + const char *const *patt = NULL; + + if (fragP->tc_frag_data.isa == PROCESSOR_UNKNOWN) + { + /* PROCESSOR_UNKNOWN means that all ISAs may be used. */ + switch (cpu_arch_tune) + { + case PROCESSOR_UNKNOWN: + /* We use cpu_arch_isa_flags to check if we SHOULD + optimize with nops. */ + if (fragP->tc_frag_data.isa_flags.bitfield.cpunop) + patt = alt_long_patt; + else + patt = f32_patt; + break; + 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; + case PROCESSOR_K6: + case PROCESSOR_ATHLON: + case PROCESSOR_K8: + case PROCESSOR_AMDFAM10: + case PROCESSOR_BD: + case PROCESSOR_BT: + patt = alt_short_patt; + break; + case PROCESSOR_I386: + case PROCESSOR_I486: + case PROCESSOR_PENTIUM: + case PROCESSOR_PENTIUMPRO: + case PROCESSOR_GENERIC32: + patt = f32_patt; + break; + } + } + else + { + switch (fragP->tc_frag_data.tune) + { + case PROCESSOR_UNKNOWN: + /* When cpu_arch_isa is set, cpu_arch_tune shouldn't be + PROCESSOR_UNKNOWN. */ + abort (); + break; + + case PROCESSOR_I386: + case PROCESSOR_I486: + case PROCESSOR_PENTIUM: + case PROCESSOR_K6: + case PROCESSOR_ATHLON: + case PROCESSOR_K8: + case PROCESSOR_AMDFAM10: + case PROCESSOR_BD: + case PROCESSOR_BT: + case PROCESSOR_GENERIC32: + /* We use cpu_arch_isa_flags to check if we CAN optimize + with nops. */ + if (fragP->tc_frag_data.isa_flags.bitfield.cpunop) + patt = alt_short_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: + if (fragP->tc_frag_data.isa_flags.bitfield.cpunop) + patt = alt_long_patt; + else + patt = f32_patt; + break; + case PROCESSOR_GENERIC64: + patt = alt_long_patt; + break; + } + } + + if (patt == f32_patt) + { + /* If the padding is less than 15 bytes, we use the normal + ones. Otherwise, we use a jump instruction and adjust + 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 + { + memcpy (fragP->fr_literal + fragP->fr_fix, + jump_31, count); + /* Adjust jump offset. */ + fragP->fr_literal[fragP->fr_fix + 1] = count - 2; + } + } + else + { + /* Maximum length of an instruction is 15 byte. If the + padding is greater than 15 bytes and we don't use jump, + we have to break it into smaller pieces. */ + int padding = count; + while (padding > 15) + { + padding -= 15; + memcpy (fragP->fr_literal + fragP->fr_fix + padding, + patt [14], 15); + } + + if (padding) + memcpy (fragP->fr_literal + fragP->fr_fix, + patt [padding - 1], padding); + } + } + fragP->fr_var = count; +} + +static INLINE int +operand_type_all_zero (const union i386_operand_type *x) +{ + switch (ARRAY_SIZE(x->array)) + { + case 3: + if (x->array[2]) + return 0; + case 2: + if (x->array[1]) + return 0; + case 1: + return !x->array[0]; + default: + abort (); + } +} + +static INLINE void +operand_type_set (union i386_operand_type *x, unsigned int v) +{ + switch (ARRAY_SIZE(x->array)) + { + case 3: + x->array[2] = v; + case 2: + x->array[1] = v; + case 1: + x->array[0] = v; + break; + default: + abort (); + } +} + +static INLINE int +operand_type_equal (const union i386_operand_type *x, + const union i386_operand_type *y) +{ + switch (ARRAY_SIZE(x->array)) + { + case 3: + if (x->array[2] != y->array[2]) + return 0; + case 2: + if (x->array[1] != y->array[1]) + return 0; + case 1: + return x->array[0] == y->array[0]; + break; + default: + abort (); + } +} + +static INLINE int +cpu_flags_all_zero (const union i386_cpu_flags *x) +{ + switch (ARRAY_SIZE(x->array)) + { + case 3: + if (x->array[2]) + return 0; + case 2: + if (x->array[1]) + return 0; + case 1: + return !x->array[0]; + default: + abort (); + } +} + +static INLINE void +cpu_flags_set (union i386_cpu_flags *x, unsigned int v) +{ + switch (ARRAY_SIZE(x->array)) + { + case 3: + x->array[2] = v; + case 2: + x->array[1] = v; + case 1: + x->array[0] = v; + break; + default: + abort (); + } +} + +static INLINE int +cpu_flags_equal (const union i386_cpu_flags *x, + const union i386_cpu_flags *y) +{ + switch (ARRAY_SIZE(x->array)) + { + case 3: + if (x->array[2] != y->array[2]) + return 0; + case 2: + if (x->array[1] != y->array[1]) + return 0; + case 1: + return x->array[0] == y->array[0]; + break; + default: + abort (); + } +} + +static INLINE int +cpu_flags_check_cpu64 (i386_cpu_flags f) +{ + return !((flag_code == CODE_64BIT && f.bitfield.cpuno64) + || (flag_code != CODE_64BIT && f.bitfield.cpu64)); +} + +static INLINE i386_cpu_flags +cpu_flags_and (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; +} + +static INLINE i386_cpu_flags +cpu_flags_or (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; +} + +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 +#define CPU_FLAGS_PCLMUL_MATCH 0x8 +#define CPU_FLAGS_AVX_MATCH 0x10 + +#define CPU_FLAGS_32BIT_MATCH \ + (CPU_FLAGS_ARCH_MATCH | CPU_FLAGS_AES_MATCH \ + | CPU_FLAGS_PCLMUL_MATCH | CPU_FLAGS_AVX_MATCH) +#define CPU_FLAGS_PERFECT_MATCH \ + (CPU_FLAGS_32BIT_MATCH | CPU_FLAGS_64BIT_MATCH) + +/* Return CPU flags match bits. */ + +static int +cpu_flags_match (const insn_template *t) +{ + i386_cpu_flags x = t->cpu_flags; + int match = cpu_flags_check_cpu64 (x) ? CPU_FLAGS_64BIT_MATCH : 0; + + x.bitfield.cpu64 = 0; + x.bitfield.cpuno64 = 0; + + if (cpu_flags_all_zero (&x)) + { + /* This instruction is available on all archs. */ + match |= CPU_FLAGS_32BIT_MATCH; + } + else + { + /* This instruction is available only on some archs. */ + i386_cpu_flags cpu = cpu_arch_flags; + + cpu.bitfield.cpu64 = 0; + cpu.bitfield.cpuno64 = 0; + cpu = cpu_flags_and (x, cpu); + if (!cpu_flags_all_zero (&cpu)) + { + if (x.bitfield.cpuavx) + { + /* We only need to check AES/PCLMUL/SSE2AVX with AVX. */ + if (cpu.bitfield.cpuavx) + { + /* Check SSE2AVX. */ + if (!t->opcode_modifier.sse2avx|| sse2avx) + { + match |= (CPU_FLAGS_ARCH_MATCH + | CPU_FLAGS_AVX_MATCH); + /* Check AES. */ + if (!x.bitfield.cpuaes || cpu.bitfield.cpuaes) + match |= CPU_FLAGS_AES_MATCH; + /* Check PCLMUL. */ + if (!x.bitfield.cpupclmul + || cpu.bitfield.cpupclmul) + match |= CPU_FLAGS_PCLMUL_MATCH; + } + } + else + match |= CPU_FLAGS_ARCH_MATCH; + } + else + match |= CPU_FLAGS_32BIT_MATCH; + } + } + return match; +} + +static INLINE i386_operand_type +operand_type_and (i386_operand_type x, i386_operand_type 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; +} + +static INLINE i386_operand_type +operand_type_or (i386_operand_type x, i386_operand_type 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; +} + +static INLINE i386_operand_type +operand_type_xor (i386_operand_type x, i386_operand_type 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; +} + +static const i386_operand_type acc32 = OPERAND_TYPE_ACC32; +static const i386_operand_type acc64 = OPERAND_TYPE_ACC64; +static const i386_operand_type control = OPERAND_TYPE_CONTROL; +static const i386_operand_type inoutportreg + = OPERAND_TYPE_INOUTPORTREG; +static const i386_operand_type reg16_inoutportreg + = OPERAND_TYPE_REG16_INOUTPORTREG; +static const i386_operand_type disp16 = OPERAND_TYPE_DISP16; +static const i386_operand_type disp32 = OPERAND_TYPE_DISP32; +static const i386_operand_type disp32s = OPERAND_TYPE_DISP32S; +static const i386_operand_type disp16_32 = OPERAND_TYPE_DISP16_32; +static const i386_operand_type anydisp + = OPERAND_TYPE_ANYDISP; +static const i386_operand_type regxmm = OPERAND_TYPE_REGXMM; +static const i386_operand_type regymm = OPERAND_TYPE_REGYMM; +static const i386_operand_type regzmm = OPERAND_TYPE_REGZMM; +static const i386_operand_type regmask = OPERAND_TYPE_REGMASK; +static const i386_operand_type imm8 = OPERAND_TYPE_IMM8; +static const i386_operand_type imm8s = OPERAND_TYPE_IMM8S; +static const i386_operand_type imm16 = OPERAND_TYPE_IMM16; +static const i386_operand_type imm32 = OPERAND_TYPE_IMM32; +static const i386_operand_type imm32s = OPERAND_TYPE_IMM32S; +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; +static const i386_operand_type regbnd = OPERAND_TYPE_REGBND; +static const i386_operand_type vec_disp8 = OPERAND_TYPE_VEC_DISP8; + +enum operand_type +{ + reg, + imm, + disp, + anymem +}; + +static INLINE int +operand_type_check (i386_operand_type t, enum operand_type c) +{ + switch (c) + { + case reg: + return (t.bitfield.reg8 + || t.bitfield.reg16 + || t.bitfield.reg32 + || t.bitfield.reg64); + + case imm: + return (t.bitfield.imm8 + || t.bitfield.imm8s + || t.bitfield.imm16 + || t.bitfield.imm32 + || t.bitfield.imm32s + || t.bitfield.imm64); + + case disp: + return (t.bitfield.disp8 + || t.bitfield.disp16 + || t.bitfield.disp32 + || t.bitfield.disp32s + || t.bitfield.disp64); + + case anymem: + return (t.bitfield.disp8 + || t.bitfield.disp16 + || t.bitfield.disp32 + || t.bitfield.disp32s + || t.bitfield.disp64 + || t.bitfield.baseindex); + + default: + abort (); + } + + return 0; +} + +/* Return 1 if there is no conflict in 8bit/16bit/32bit/64bit on + operand J for instruction template T. */ + +static INLINE int +match_reg_size (const insn_template *t, unsigned int j) +{ + return !((i.types[j].bitfield.byte + && !t->operand_types[j].bitfield.byte) + || (i.types[j].bitfield.word + && !t->operand_types[j].bitfield.word) + || (i.types[j].bitfield.dword + && !t->operand_types[j].bitfield.dword) + || (i.types[j].bitfield.qword + && !t->operand_types[j].bitfield.qword)); +} + +/* Return 1 if there is no conflict in any size on operand J for + instruction template T. */ + +static INLINE int +match_mem_size (const insn_template *t, unsigned int j) +{ + return (match_reg_size (t, j) + && !((i.types[j].bitfield.unspecified + && !t->operand_types[j].bitfield.unspecified) + || (i.types[j].bitfield.fword + && !t->operand_types[j].bitfield.fword) + || (i.types[j].bitfield.tbyte + && !t->operand_types[j].bitfield.tbyte) + || (i.types[j].bitfield.xmmword + && !t->operand_types[j].bitfield.xmmword) + || (i.types[j].bitfield.ymmword + && !t->operand_types[j].bitfield.ymmword) + || (i.types[j].bitfield.zmmword + && !t->operand_types[j].bitfield.zmmword))); +} + +/* Return 1 if there is no size conflict on any operands for + instruction template T. */ + +static INLINE int +operand_size_match (const insn_template *t) +{ + unsigned int j; + int match = 1; + + /* Don't check jump instructions. */ + if (t->opcode_modifier.jump + || t->opcode_modifier.jumpbyte + || t->opcode_modifier.jumpdword + || t->opcode_modifier.jumpintersegment) + return match; + + /* Check memory and accumulator operand size. */ + for (j = 0; j < i.operands; j++) + { + if (t->operand_types[j].bitfield.anysize) + continue; + + if (t->operand_types[j].bitfield.acc && !match_reg_size (t, j)) + { + match = 0; + break; + } + + if (i.types[j].bitfield.mem && !match_mem_size (t, j)) + { + match = 0; + break; + } + } + + 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); + + match = 1; + for (j = 0; j < 2; j++) + { + if (t->operand_types[j].bitfield.acc + && !match_reg_size (t, j ? 0 : 1)) + goto mismatch; + + if (i.types[j].bitfield.mem + && !match_mem_size (t, j ? 0 : 1)) + goto mismatch; + } + + return match; +} + +static INLINE int +operand_type_match (i386_operand_type overlap, + i386_operand_type given) +{ + i386_operand_type temp = overlap; + + temp.bitfield.jumpabsolute = 0; + temp.bitfield.unspecified = 0; + temp.bitfield.byte = 0; + temp.bitfield.word = 0; + temp.bitfield.dword = 0; + temp.bitfield.fword = 0; + temp.bitfield.qword = 0; + temp.bitfield.tbyte = 0; + temp.bitfield.xmmword = 0; + temp.bitfield.ymmword = 0; + temp.bitfield.zmmword = 0; + if (operand_type_all_zero (&temp)) + goto mismatch; + + 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 + unless the expected operand type register overlap is null. + Note that Acc in a template matches every size of reg. */ + +static INLINE int +operand_type_register_match (i386_operand_type m0, + i386_operand_type g0, + i386_operand_type t0, + i386_operand_type m1, + i386_operand_type g1, + i386_operand_type t1) +{ + if (!operand_type_check (g0, reg)) + return 1; + + if (!operand_type_check (g1, reg)) + return 1; + + if (g0.bitfield.reg8 == g1.bitfield.reg8 + && g0.bitfield.reg16 == g1.bitfield.reg16 + && g0.bitfield.reg32 == g1.bitfield.reg32 + && g0.bitfield.reg64 == g1.bitfield.reg64) + return 1; + + if (m0.bitfield.acc) + { + t0.bitfield.reg8 = 1; + t0.bitfield.reg16 = 1; + t0.bitfield.reg32 = 1; + t0.bitfield.reg64 = 1; + } + + if (m1.bitfield.acc) + { + t1.bitfield.reg8 = 1; + t1.bitfield.reg16 = 1; + t1.bitfield.reg32 = 1; + t1.bitfield.reg64 = 1; + } + + 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 +register_number (const reg_entry *r) +{ + unsigned int nr = r->reg_num; + + if (r->reg_flags & RegRex) + nr += 8; + + return nr; +} + +static INLINE unsigned int +mode_from_disp_size (i386_operand_type t) +{ + if (t.bitfield.disp8 || t.bitfield.vec_disp8) + return 1; + else if (t.bitfield.disp16 + || t.bitfield.disp32 + || t.bitfield.disp32s) + return 2; + else + return 0; +} + +static INLINE int +fits_in_signed_byte (offsetT num) +{ + return (num >= -128) && (num <= 127); +} + +static INLINE int +fits_in_unsigned_byte (offsetT num) +{ + return (num & 0xff) == num; +} + +static INLINE int +fits_in_unsigned_word (offsetT num) +{ + return (num & 0xffff) == num; +} + +static INLINE int +fits_in_signed_word (offsetT num) +{ + return (-32768 <= num) && (num <= 32767); +} + +static INLINE int +fits_in_signed_long (offsetT num ATTRIBUTE_UNUSED) +{ +#ifndef BFD64 + return 1; +#else + return (!(((offsetT) -1 << 31) & num) + || (((offsetT) -1 << 31) & num) == ((offsetT) -1 << 31)); +#endif +} /* fits_in_signed_long() */ + +static INLINE int +fits_in_unsigned_long (offsetT num ATTRIBUTE_UNUSED) +{ +#ifndef BFD64 + return 1; +#else + return (num & (((offsetT) 2 << 31) - 1)) == num; +#endif +} /* fits_in_unsigned_long() */ + +static INLINE int +fits_in_vec_disp8 (offsetT num) +{ + int shift = i.memshift; + unsigned int mask; + + if (shift == -1) + abort (); + + mask = (1 << shift) - 1; + + /* Return 0 if NUM isn't properly aligned. */ + if ((num & mask)) + return 0; + + /* Check if NUM will fit in 8bit after shift. */ + return fits_in_signed_byte (num >> shift); +} + +static INLINE int +fits_in_imm4 (offsetT num) +{ + return (num & 0xf) == num; +} + +static i386_operand_type +smallest_imm_type (offsetT num) +{ + i386_operand_type t; + + operand_type_set (&t, 0); + t.bitfield.imm64 = 1; + + if (cpu_arch_tune != PROCESSOR_I486 && num == 1) + { + /* This code is disabled on the 486 because all the Imm1 forms + in the opcode table are slower on the i486. They're the + versions with the implicitly specified single-position + displacement, which has another syntax if you really want to + use that form. */ + t.bitfield.imm1 = 1; + t.bitfield.imm8 = 1; + t.bitfield.imm8s = 1; + t.bitfield.imm16 = 1; + t.bitfield.imm32 = 1; + t.bitfield.imm32s = 1; + } + else if (fits_in_signed_byte (num)) + { + t.bitfield.imm8 = 1; + t.bitfield.imm8s = 1; + t.bitfield.imm16 = 1; + t.bitfield.imm32 = 1; + t.bitfield.imm32s = 1; + } + else if (fits_in_unsigned_byte (num)) + { + t.bitfield.imm8 = 1; + t.bitfield.imm16 = 1; + t.bitfield.imm32 = 1; + t.bitfield.imm32s = 1; + } + else if (fits_in_signed_word (num) || fits_in_unsigned_word (num)) + { + t.bitfield.imm16 = 1; + t.bitfield.imm32 = 1; + t.bitfield.imm32s = 1; + } + else if (fits_in_signed_long (num)) + { + t.bitfield.imm32 = 1; + t.bitfield.imm32s = 1; + } + else if (fits_in_unsigned_long (num)) + t.bitfield.imm32 = 1; + + return t; +} + +static offsetT +offset_in_range (offsetT val, int size) +{ + addressT mask; + + switch (size) + { + case 1: mask = ((addressT) 1 << 8) - 1; break; + case 2: mask = ((addressT) 1 << 16) - 1; break; + case 4: mask = ((addressT) 2 << 31) - 1; break; +#ifdef BFD64 + case 8: mask = ((addressT) 2 << 63) - 1; break; +#endif + default: abort (); + } + +#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) + { + char buf1[40], buf2[40]; + + sprint_value (buf1, val); + sprint_value (buf2, val & mask); + as_warn (_("%s shortened to %s"), buf1, buf2); + } + return val & mask; +} + +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) +{ + enum PREFIX_GROUP ret = PREFIX_OTHER; + unsigned int q; + + if (prefix >= REX_OPCODE && prefix < REX_OPCODE + 16 + && flag_code == CODE_64BIT) + { + 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 = PREFIX_EXIST; + q = REX_PREFIX; + } + else + { + switch (prefix) + { + default: + abort (); + + case CS_PREFIX_OPCODE: + case DS_PREFIX_OPCODE: + case ES_PREFIX_OPCODE: + case FS_PREFIX_OPCODE: + case GS_PREFIX_OPCODE: + case SS_PREFIX_OPCODE: + q = SEG_PREFIX; + break; + + case REPNE_PREFIX_OPCODE: + case REPE_PREFIX_OPCODE: + q = REP_PREFIX; + ret = PREFIX_REP; + break; + + case LOCK_PREFIX_OPCODE: + q = LOCK_PREFIX; + ret = PREFIX_LOCK; + break; + + case FWAIT_OPCODE: + q = WAIT_PREFIX; + break; + + case ADDR_PREFIX_OPCODE: + q = ADDR_PREFIX; + break; + + case DATA_PREFIX_OPCODE: + q = DATA_PREFIX; + break; + } + if (i.prefix[q] != 0) + ret = PREFIX_EXIST; + } + + if (ret) + { + if (!i.prefix[q]) + ++i.prefixes; + i.prefix[q] |= prefix; + } + else + as_bad (_("same type of prefix used twice")); + + return ret; +} + +static void +update_code_flag (int value, int check) +{ + PRINTF_LIKE ((*as_error)); + + flag_code = (enum flag_code) value; + if (flag_code == CODE_64BIT) + { + cpu_arch_flags.bitfield.cpu64 = 1; + cpu_arch_flags.bitfield.cpuno64 = 0; + } + else + { + cpu_arch_flags.bitfield.cpu64 = 0; + cpu_arch_flags.bitfield.cpuno64 = 1; + } + if (value == CODE_64BIT && !cpu_arch_flags.bitfield.cpulm ) + { + 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) + { + 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 = (enum flag_code) new_code_flag; + if (flag_code != CODE_16BIT) + abort (); + cpu_arch_flags.bitfield.cpu64 = 0; + cpu_arch_flags.bitfield.cpuno64 = 1; + stackop_size = LONG_MNEM_SUFFIX; +} + +static void +set_intel_syntax (int syntax_flag) +{ + /* Find out if register prefixing is specified. */ + int ask_naked_reg = 0; + + SKIP_WHITESPACE (); + if (!is_end_of_line[(unsigned char) *input_line_pointer]) + { + char *string = input_line_pointer; + int e = get_symbol_end (); + + if (strcmp (string, "prefix") == 0) + ask_naked_reg = 1; + else if (strcmp (string, "noprefix") == 0) + ask_naked_reg = -1; + else + as_bad (_("bad argument to syntax directive.")); + *input_line_pointer = e; + } + demand_empty_rest_of_line (); + + intel_syntax = syntax_flag; + + if (ask_naked_reg == 0) + allow_naked_reg = (intel_syntax + && (bfd_get_symbol_leading_char (stdoutput) != '\0')); + else + allow_naked_reg = (ask_naked_reg < 0); + + expr_set_rank (O_full_ptr, syntax_flag ? 10 : 0); + + identifier_chars['%'] = intel_syntax && allow_naked_reg ? '%' : 0; + identifier_chars['$'] = intel_syntax ? '$' : 0; + register_prefix = allow_naked_reg ? "" : "%"; +} + +static void +set_intel_mnemonic (int mnemonic_flag) +{ + intel_mnemonic = mnemonic_flag; +} + +static void +set_allow_index_reg (int flag) +{ + allow_index_reg = flag; +} + +static void +set_check (int what) +{ + enum check_kind *kind; + const char *str; + + if (what) + { + kind = &operand_check; + str = "operand"; + } + else + { + kind = &sse_check; + str = "sse"; + } + + SKIP_WHITESPACE (); + + if (!is_end_of_line[(unsigned char) *input_line_pointer]) + { + char *string = input_line_pointer; + int e = get_symbol_end (); + + if (strcmp (string, "none") == 0) + *kind = check_none; + else if (strcmp (string, "warning") == 0) + *kind = check_warning; + else if (strcmp (string, "error") == 0) + *kind = check_error; + else + as_bad (_("bad argument to %s_check directive."), str); + *input_line_pointer = e; + } + else + as_bad (_("missing argument for %s_check directive"), str); + + 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) +{ + SKIP_WHITESPACE (); + + if (!is_end_of_line[(unsigned char) *input_line_pointer]) + { + char *string = input_line_pointer; + int e = get_symbol_end (); + unsigned int j; + i386_cpu_flags flags; + + for (j = 0; j < ARRAY_SIZE (cpu_arch); j++) + { + if (strcmp (string, cpu_arch[j].name) == 0) + { + check_cpu_arch_compatible (string, cpu_arch[j].flags); + + if (*string != '.') + { + cpu_arch_name = cpu_arch[j].name; + cpu_sub_arch_name = NULL; + cpu_arch_flags = cpu_arch[j].flags; + if (flag_code == CODE_64BIT) + { + cpu_arch_flags.bitfield.cpu64 = 1; + cpu_arch_flags.bitfield.cpuno64 = 0; + } + else + { + cpu_arch_flags.bitfield.cpu64 = 0; + cpu_arch_flags.bitfield.cpuno64 = 1; + } + 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; + cpu_arch_tune_flags = cpu_arch_isa_flags; + } + break; + } + + 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[j].name, + (const char *) NULL); + free (name); + } + else + 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 (j >= ARRAY_SIZE (cpu_arch)) + as_bad (_("no such architecture: `%s'"), string); + + *input_line_pointer = e; + } + else + as_bad (_("missing cpu architecture")); + + no_cond_jump_promotion = 0; + if (*input_line_pointer == ',' + && !is_end_of_line[(unsigned char) input_line_pointer[1]]) + { + char *string = ++input_line_pointer; + int e = get_symbol_end (); + + if (strcmp (string, "nojumps") == 0) + no_cond_jump_promotion = 1; + else if (strcmp (string, "jumps") == 0) + ; + else + as_bad (_("no such architecture modifier: `%s'"), string); + + *input_line_pointer = e; + } + + 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 (void) +{ + 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")); +} + +void +md_begin (void) +{ + const char *hash_err; + + /* Initialize op_hash hash table. */ + op_hash = hash_new (); + + { + const insn_template *optab; + templates *core_optab; + + /* Setup for loop. */ + optab = i386_optab; + core_optab = (templates *) xmalloc (sizeof (templates)); + core_optab->start = optab; + + while (1) + { + ++optab; + if (optab->name == NULL + || strcmp (optab->name, (optab - 1)->name) != 0) + { + /* different name --> ship out current template list; + add to hash table; & begin anew. */ + core_optab->end = optab; + hash_err = hash_insert (op_hash, + (optab - 1)->name, + (void *) core_optab); + if (hash_err) + { + as_fatal (_("can't hash %s: %s"), + (optab - 1)->name, + hash_err); + } + if (optab->name == NULL) + break; + core_optab = (templates *) xmalloc (sizeof (templates)); + core_optab->start = optab; + } + } + } + + /* Initialize reg_hash hash table. */ + reg_hash = hash_new (); + { + const reg_entry *regtab; + unsigned int regtab_size = i386_regtab_size; + + for (regtab = i386_regtab; regtab_size--; regtab++) + { + hash_err = hash_insert (reg_hash, regtab->reg_name, (void *) regtab); + if (hash_err) + as_fatal (_("can't hash %s: %s"), + regtab->reg_name, + hash_err); + } + } + + /* Fill in lexical tables: mnemonic_chars, operand_chars. */ + { + int c; + char *p; + + for (c = 0; c < 256; c++) + { + if (ISDIGIT (c)) + { + digit_chars[c] = c; + mnemonic_chars[c] = c; + register_chars[c] = c; + operand_chars[c] = c; + } + else if (ISLOWER (c)) + { + mnemonic_chars[c] = c; + register_chars[c] = c; + operand_chars[c] = c; + } + else if (ISUPPER (c)) + { + mnemonic_chars[c] = TOLOWER (c); + register_chars[c] = mnemonic_chars[c]; + operand_chars[c] = c; + } + else if (c == '{' || c == '}') + operand_chars[c] = c; + + if (ISALPHA (c) || ISDIGIT (c)) + identifier_chars[c] = c; + else if (c >= 128) + { + identifier_chars[c] = c; + operand_chars[c] = c; + } + } + +#ifdef LEX_AT + identifier_chars['@'] = '@'; +#endif +#ifdef LEX_QM + identifier_chars['?'] = '?'; + operand_chars['?'] = '?'; +#endif + digit_chars['-'] = '-'; + mnemonic_chars['_'] = '_'; + mnemonic_chars['-'] = '-'; + mnemonic_chars['.'] = '.'; + identifier_chars['_'] = '_'; + identifier_chars['.'] = '.'; + + for (p = operand_special_chars; *p != '\0'; p++) + operand_chars[(unsigned char) *p] = *p; + } + + 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 + { + x86_dwarf2_return_column = 8; + x86_cie_data_alignment = -4; + } +} + +void +i386_print_statistics (FILE *file) +{ + hash_print_statistics (file, "i386 opcode", op_hash); + hash_print_statistics (file, "i386 register", reg_hash); +} + +#ifdef DEBUG386 + +/* Debugging routines for md_assemble. */ +static void pte (insn_template *); +static void pt (i386_operand_type); +static void pe (expressionS *); +static void ps (symbolS *); + +static void +pi (char *line, i386_insn *x) +{ + unsigned int j; + + fprintf (stdout, "%s: template ", line); + pte (&x->tm); + fprintf (stdout, " address: base %s index %s scale %x\n", + x->base_reg ? x->base_reg->reg_name : "none", + x->index_reg ? x->index_reg->reg_name : "none", + x->log2_scale_factor); + fprintf (stdout, " modrm: mode %x reg %x reg/mem %x\n", + x->rm.mode, x->rm.reg, x->rm.regmem); + fprintf (stdout, " sib: base %x index %x scale %x\n", + x->sib.base, x->sib.index, x->sib.scale); + fprintf (stdout, " rex: 64bit %x extX %x extY %x extZ %x\n", + (x->rex & REX_W) != 0, + (x->rex & REX_R) != 0, + (x->rex & REX_X) != 0, + (x->rex & REX_B) != 0); + for (j = 0; j < x->operands; j++) + { + fprintf (stdout, " #%d: ", j + 1); + pt (x->types[j]); + fprintf (stdout, "\n"); + 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.regzmm + || 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 (insn_template *t) +{ + unsigned int j; + fprintf (stdout, " %d operands ", t->operands); + fprintf (stdout, "opcode %x ", t->base_opcode); + if (t->extension_opcode != None) + fprintf (stdout, "ext %x ", t->extension_opcode); + if (t->opcode_modifier.d) + fprintf (stdout, "D"); + if (t->opcode_modifier.w) + fprintf (stdout, "W"); + fprintf (stdout, "\n"); + for (j = 0; j < t->operands; j++) + { + fprintf (stdout, " #%d type ", j + 1); + pt (t->operand_types[j]); + fprintf (stdout, "\n"); + } +} + +static void +pe (expressionS *e) +{ + fprintf (stdout, " operation %d\n", e->X_op); + fprintf (stdout, " add_number %ld (%lx)\n", + (long) e->X_add_number, (long) e->X_add_number); + if (e->X_add_symbol) + { + fprintf (stdout, " add_symbol "); + ps (e->X_add_symbol); + fprintf (stdout, "\n"); + } + if (e->X_op_symbol) + { + fprintf (stdout, " op_symbol "); + ps (e->X_op_symbol); + fprintf (stdout, "\n"); + } +} + +static void +ps (symbolS *s) +{ + fprintf (stdout, "%s type %s%s", + S_GET_NAME (s), + S_IS_EXTERNAL (s) ? "EXTERNAL " : "", + segment_name (S_GET_SEGMENT (s))); +} + +static struct type_name + { + i386_operand_type mask; + const char *name; + } +const type_names[] = +{ + { OPERAND_TYPE_REG8, "r8" }, + { OPERAND_TYPE_REG16, "r16" }, + { OPERAND_TYPE_REG32, "r32" }, + { OPERAND_TYPE_REG64, "r64" }, + { OPERAND_TYPE_IMM8, "i8" }, + { OPERAND_TYPE_IMM8, "i8s" }, + { OPERAND_TYPE_IMM16, "i16" }, + { OPERAND_TYPE_IMM32, "i32" }, + { OPERAND_TYPE_IMM32S, "i32s" }, + { OPERAND_TYPE_IMM64, "i64" }, + { OPERAND_TYPE_IMM1, "i1" }, + { OPERAND_TYPE_BASEINDEX, "BaseIndex" }, + { OPERAND_TYPE_DISP8, "d8" }, + { OPERAND_TYPE_DISP16, "d16" }, + { OPERAND_TYPE_DISP32, "d32" }, + { OPERAND_TYPE_DISP32S, "d32s" }, + { OPERAND_TYPE_DISP64, "d64" }, + { OPERAND_TYPE_VEC_DISP8, "Vector d8" }, + { OPERAND_TYPE_INOUTPORTREG, "InOutPortReg" }, + { OPERAND_TYPE_SHIFTCOUNT, "ShiftCount" }, + { OPERAND_TYPE_CONTROL, "control reg" }, + { OPERAND_TYPE_TEST, "test reg" }, + { OPERAND_TYPE_DEBUG, "debug reg" }, + { OPERAND_TYPE_FLOATREG, "FReg" }, + { OPERAND_TYPE_FLOATACC, "FAcc" }, + { OPERAND_TYPE_SREG2, "SReg2" }, + { OPERAND_TYPE_SREG3, "SReg3" }, + { OPERAND_TYPE_ACC, "Acc" }, + { OPERAND_TYPE_JUMPABSOLUTE, "Jump Absolute" }, + { OPERAND_TYPE_REGMMX, "rMMX" }, + { OPERAND_TYPE_REGXMM, "rXMM" }, + { OPERAND_TYPE_REGYMM, "rYMM" }, + { OPERAND_TYPE_REGZMM, "rZMM" }, + { OPERAND_TYPE_REGMASK, "Mask reg" }, + { OPERAND_TYPE_ESSEG, "es" }, +}; + +static void +pt (i386_operand_type t) +{ + unsigned int j; + i386_operand_type a; + + for (j = 0; j < ARRAY_SIZE (type_names); j++) + { + a = operand_type_and (t, type_names[j].mask); + if (!operand_type_all_zero (&a)) + fprintf (stdout, "%s, ", type_names[j].name); + } + fflush (stdout); +} + +#endif /* DEBUG386 */ + +static bfd_reloc_code_real_type +reloc (unsigned int size, + int pcrel, + int sign, + bfd_reloc_code_real_type other) +{ + if (other != NO_RELOC) + { + reloc_howto_type *rel; + + if (size == 8) + switch (other) + { + case BFD_RELOC_X86_64_GOT32: + return BFD_RELOC_X86_64_GOT64; + break; + case BFD_RELOC_X86_64_PLTOFF64: + return BFD_RELOC_X86_64_PLTOFF64; + break; + case BFD_RELOC_X86_64_GOTPC32: + other = BFD_RELOC_X86_64_GOTPC64; + break; + case BFD_RELOC_X86_64_GOTPCREL: + other = BFD_RELOC_X86_64_GOTPCREL64; + break; + case BFD_RELOC_X86_64_TPOFF32: + other = BFD_RELOC_X86_64_TPOFF64; + break; + case BFD_RELOC_X86_64_DTPOFF32: + other = BFD_RELOC_X86_64_DTPOFF64; + break; + default: + break; + } + +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + if (other == BFD_RELOC_SIZE32) + { + if (size == 8) + return BFD_RELOC_SIZE64; + if (pcrel) + as_bad (_("there are no pc-relative size relocations")); + } +#endif + + /* Sign-checking 4-byte relocations in 16-/32-bit code is pointless. */ + if (size == 4 && (flag_code != CODE_64BIT || disallow_64bit_reloc)) + sign = -1; + + rel = bfd_reloc_type_lookup (stdoutput, other); + if (!rel) + as_bad (_("unknown relocation (%u)"), other); + else if (size != bfd_get_reloc_size (rel)) + as_bad (_("%u-byte relocation cannot be applied to %u-byte field"), + bfd_get_reloc_size (rel), + size); + else if (pcrel && !rel->pc_relative) + as_bad (_("non-pc-relative relocation for pc-relative field")); + else if ((rel->complain_on_overflow == complain_overflow_signed + && !sign) + || (rel->complain_on_overflow == complain_overflow_unsigned + && sign > 0)) + as_bad (_("relocated field and relocation type differ in signedness")); + else + return other; + return NO_RELOC; + } + + if (pcrel) + { + if (!sign) + as_bad (_("there are no unsigned pc-relative relocations")); + switch (size) + { + case 1: return BFD_RELOC_8_PCREL; + case 2: return BFD_RELOC_16_PCREL; + case 4: return BFD_RELOC_32_PCREL; + case 8: return BFD_RELOC_64_PCREL; + } + as_bad (_("cannot do %u byte pc-relative relocation"), size); + } + else + { + if (sign > 0) + switch (size) + { + case 4: return BFD_RELOC_X86_64_32S; + } + else + switch (size) + { + case 1: return BFD_RELOC_8; + case 2: return BFD_RELOC_16; + case 4: return BFD_RELOC_32; + case 8: return BFD_RELOC_64; + } + as_bad (_("cannot do %s %u byte relocation"), + sign > 0 ? "signed" : "unsigned", size); + } + + return NO_RELOC; +} + +/* Here we decide which fixups can be adjusted to make them relative to + the beginning of the section instead of the symbol. Basically we need + to make sure that the dynamic relocations are done correctly, so in + some cases we force the original symbol to be used. */ + +int +tc_i386_fix_adjustable (fixS *fixP ATTRIBUTE_UNUSED) +{ +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + if (!IS_ELF) + return 1; + + /* Don't adjust pc-relative references to merge sections in 64-bit + mode. */ + if (use_rela_relocations + && (S_GET_SEGMENT (fixP->fx_addsy)->flags & SEC_MERGE) != 0 + && fixP->fx_pcrel) + return 0; + + /* The x86_64 GOTPCREL are represented as 32bit PCrel relocations + and changed later by validate_fix. */ + if (GOT_symbol && fixP->fx_subsy == GOT_symbol + && fixP->fx_r_type == BFD_RELOC_32_PCREL) + return 0; + + /* Adjust_reloc_syms doesn't know about the GOT. Need to keep symbol + for size relocations. */ + if (fixP->fx_r_type == BFD_RELOC_SIZE32 + || fixP->fx_r_type == BFD_RELOC_SIZE64 + || 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_TLS_GD + || fixP->fx_r_type == BFD_RELOC_386_TLS_LDM + || fixP->fx_r_type == BFD_RELOC_386_TLS_LDO_32 + || fixP->fx_r_type == BFD_RELOC_386_TLS_IE_32 + || fixP->fx_r_type == BFD_RELOC_386_TLS_IE + || fixP->fx_r_type == BFD_RELOC_386_TLS_GOTIE + || fixP->fx_r_type == BFD_RELOC_386_TLS_LE_32 + || fixP->fx_r_type == BFD_RELOC_386_TLS_LE + || fixP->fx_r_type == BFD_RELOC_386_TLS_GOTDESC + || fixP->fx_r_type == BFD_RELOC_386_TLS_DESC_CALL + || 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_TLSGD + || fixP->fx_r_type == BFD_RELOC_X86_64_TLSLD + || fixP->fx_r_type == BFD_RELOC_X86_64_DTPOFF32 + || fixP->fx_r_type == BFD_RELOC_X86_64_DTPOFF64 + || fixP->fx_r_type == BFD_RELOC_X86_64_GOTTPOFF + || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF32 + || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF64 + || fixP->fx_r_type == BFD_RELOC_X86_64_GOTOFF64 + || fixP->fx_r_type == BFD_RELOC_X86_64_GOTPC32_TLSDESC + || fixP->fx_r_type == BFD_RELOC_X86_64_TLSDESC_CALL + || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT + || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) + return 0; +#endif + return 1; +} + +static int +intel_float_operand (const char *mnemonic) +{ + /* Note that the value returned is meaningful only for opcodes with (memory) + operands, hence the code here is free to improperly handle opcodes that + have no operands (for better performance and smaller code). */ + + if (mnemonic[0] != 'f') + return 0; /* non-math */ + + switch (mnemonic[1]) + { + /* fclex, fdecstp, fdisi, femms, feni, fincstp, finit, fsetpm, and + the fs segment override prefix not currently handled because no + call path can make opcodes without operands get here */ + case 'i': + return 2 /* integer op */; + case 'l': + if (mnemonic[2] == 'd' && (mnemonic[3] == 'c' || mnemonic[3] == 'e')) + return 3; /* fldcw/fldenv */ + break; + case 'n': + if (mnemonic[2] != 'o' /* fnop */) + return 3; /* non-waiting control op */ + break; + case 'r': + if (mnemonic[2] == 's') + return 3; /* frstor/frstpm */ + break; + case 's': + if (mnemonic[2] == 'a') + return 3; /* fsave */ + if (mnemonic[2] == 't') + { + switch (mnemonic[3]) + { + case 'c': /* fstcw */ + case 'd': /* fstdw */ + case 'e': /* fstenv */ + case 's': /* fsts[gw] */ + return 3; + } + } + break; + case 'x': + if (mnemonic[2] == 'r' || mnemonic[2] == 's') + return 0; /* fxsave/fxrstor are not really math ops */ + break; + } + + return 1; +} + +/* Build the VEX prefix. */ + +static void +build_vex_prefix (const insn_template *t) +{ + unsigned int register_specifier; + unsigned int implied_prefix; + unsigned int vector_length; + + /* Check register specifier. */ + if (i.vex.register_specifier) + { + register_specifier = + ~register_number (i.vex.register_specifier) & 0xf; + gas_assert ((i.vex.register_specifier->reg_flags & RegVRex) == 0); + } + else + register_specifier = 0xf; + + /* Use 2-byte VEX prefix by swappping destination and source + operand. */ + if (!i.swap_operand + && i.operands == i.reg_operands + && i.tm.opcode_modifier.vexopcode == VEX0F + && i.tm.opcode_modifier.s + && i.rex == REX_B) + { + unsigned int xchg = i.operands - 1; + union i386_op temp_op; + i386_operand_type temp_type; + + temp_type = i.types[xchg]; + i.types[xchg] = i.types[0]; + i.types[0] = temp_type; + temp_op = i.op[xchg]; + i.op[xchg] = i.op[0]; + i.op[0] = temp_op; + + gas_assert (i.rm.mode == 3); + + i.rex = REX_R; + xchg = i.rm.regmem; + i.rm.regmem = i.rm.reg; + i.rm.reg = xchg; + + /* Use the next insn. */ + i.tm = t[1]; + } + + 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) + { + case 0: + implied_prefix = 0; + break; + case DATA_PREFIX_OPCODE: + implied_prefix = 1; + break; + case REPE_PREFIX_OPCODE: + implied_prefix = 2; + break; + case REPNE_PREFIX_OPCODE: + implied_prefix = 3; + break; + default: + abort (); + } + + /* Use 2-byte VEX prefix if possible. */ + if (i.tm.opcode_modifier.vexopcode == VEX0F + && i.tm.opcode_modifier.vexw != VEXW1 + && (i.rex & (REX_W | REX_X | REX_B)) == 0) + { + /* 2-byte VEX prefix. */ + unsigned int r; + + i.vex.length = 2; + i.vex.bytes[0] = 0xc5; + + /* Check the REX.R bit. */ + r = (i.rex & REX_R) ? 0 : 1; + i.vex.bytes[1] = (r << 7 + | register_specifier << 3 + | vector_length << 2 + | implied_prefix); + } + else + { + /* 3-byte VEX prefix. */ + unsigned int m, w; + + i.vex.length = 3; + + 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. */ + i.vex.bytes[1] = (~i.rex & 0x7) << 5 | m; + + /* Check the REX.W bit. */ + w = (i.rex & REX_W) ? 1 : 0; + if (i.tm.opcode_modifier.vexw) + { + if (w) + abort (); + + if (i.tm.opcode_modifier.vexw == VEXW1) + w = 1; + } + + i.vex.bytes[2] = (w << 7 + | register_specifier << 3 + | vector_length << 2 + | implied_prefix); + } +} + +/* Build the EVEX prefix. */ + +static void +build_evex_prefix (void) +{ + unsigned int register_specifier; + unsigned int implied_prefix; + unsigned int m, w; + rex_byte vrex_used = 0; + + /* Check register specifier. */ + if (i.vex.register_specifier) + { + gas_assert ((i.vrex & REX_X) == 0); + + register_specifier = i.vex.register_specifier->reg_num; + if ((i.vex.register_specifier->reg_flags & RegRex)) + register_specifier += 8; + /* The upper 16 registers are encoded in the fourth byte of the + EVEX prefix. */ + if (!(i.vex.register_specifier->reg_flags & RegVRex)) + i.vex.bytes[3] = 0x8; + register_specifier = ~register_specifier & 0xf; + } + else + { + register_specifier = 0xf; + + /* Encode upper 16 vector index register in the fourth byte of + the EVEX prefix. */ + if (!(i.vrex & REX_X)) + i.vex.bytes[3] = 0x8; + else + vrex_used |= REX_X; + } + + switch ((i.tm.base_opcode >> 8) & 0xff) + { + case 0: + implied_prefix = 0; + break; + case DATA_PREFIX_OPCODE: + implied_prefix = 1; + break; + case REPE_PREFIX_OPCODE: + implied_prefix = 2; + break; + case REPNE_PREFIX_OPCODE: + implied_prefix = 3; + break; + default: + abort (); + } + + /* 4 byte EVEX prefix. */ + i.vex.length = 4; + i.vex.bytes[0] = 0x62; + + /* mmmm bits. */ + switch (i.tm.opcode_modifier.vexopcode) + { + case VEX0F: + m = 1; + break; + case VEX0F38: + m = 2; + break; + case VEX0F3A: + m = 3; + break; + default: + abort (); + break; + } + + /* The high 3 bits of the second EVEX byte are 1's compliment of RXB + bits from REX. */ + i.vex.bytes[1] = (~i.rex & 0x7) << 5 | m; + + /* The fifth bit of the second EVEX byte is 1's compliment of the + REX_R bit in VREX. */ + if (!(i.vrex & REX_R)) + i.vex.bytes[1] |= 0x10; + else + vrex_used |= REX_R; + + if ((i.reg_operands + i.imm_operands) == i.operands) + { + /* When all operands are registers, the REX_X bit in REX is not + used. We reuse it to encode the upper 16 registers, which is + indicated by the REX_B bit in VREX. The REX_X bit is encoded + as 1's compliment. */ + if ((i.vrex & REX_B)) + { + vrex_used |= REX_B; + i.vex.bytes[1] &= ~0x40; + } + } + + /* EVEX instructions shouldn't need the REX prefix. */ + i.vrex &= ~vrex_used; + gas_assert (i.vrex == 0); + + /* Check the REX.W bit. */ + w = (i.rex & REX_W) ? 1 : 0; + if (i.tm.opcode_modifier.vexw) + { + if (i.tm.opcode_modifier.vexw == VEXW1) + w = 1; + } + /* If w is not set it means we are dealing with WIG instruction. */ + else if (!w) + { + if (evexwig == evexw1) + w = 1; + } + + /* Encode the U bit. */ + implied_prefix |= 0x4; + + /* The third byte of the EVEX prefix. */ + i.vex.bytes[2] = (w << 7 | register_specifier << 3 | implied_prefix); + + /* The fourth byte of the EVEX prefix. */ + /* The zeroing-masking bit. */ + if (i.mask && i.mask->zeroing) + i.vex.bytes[3] |= 0x80; + + /* Don't always set the broadcast bit if there is no RC. */ + if (!i.rounding) + { + /* Encode the vector length. */ + unsigned int vec_length; + + switch (i.tm.opcode_modifier.evex) + { + case EVEXLIG: /* LL' is ignored */ + vec_length = evexlig << 5; + break; + case EVEX128: + vec_length = 0 << 5; + break; + case EVEX256: + vec_length = 1 << 5; + break; + case EVEX512: + vec_length = 2 << 5; + break; + default: + abort (); + break; + } + i.vex.bytes[3] |= vec_length; + /* Encode the broadcast bit. */ + if (i.broadcast) + i.vex.bytes[3] |= 0x10; + } + else + { + if (i.rounding->type != saeonly) + i.vex.bytes[3] |= 0x10 | (i.rounding->type << 5); + else + i.vex.bytes[3] |= 0x10; + } + + if (i.mask && i.mask->mask) + i.vex.bytes[3] |= i.mask->mask->reg_num; +} + +static void +process_immext (void) +{ + expressionS *exp; + + if ((i.tm.cpu_flags.bitfield.cpusse3 || i.tm.cpu_flags.bitfield.cpusvme) + && i.operands > 0) + { + /* MONITOR/MWAIT as well as SVME 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; + + for (x = 0; x < i.operands; x++) + if (register_number (i.op[x].regs) != x) + as_bad (_("can't use register '%s%s' as operand %d in '%s'."), + register_prefix, i.op[x].regs->reg_name, x + 1, + i.tm.name); + + i.operands = 0; + } + + /* These AMD 3DNow! and SSE2 instructions have an opcode suffix + which is coded in the same place as an 8-bit immediate field + would be. Here we fake an 8-bit immediate operand from the + opcode suffix stored in tm.extension_opcode. + + AVX instructions also use this encoding, for some of + 3 argument instructions. */ + + gas_assert (i.imm_operands <= 1 + && (i.operands <= 2 + || ((i.tm.opcode_modifier.vex + || i.tm.opcode_modifier.evex) + && i.operands <= 4))); + + exp = &im_expressions[i.imm_operands++]; + i.op[i.operands].imms = exp; + i.types[i.operands] = imm8; + i.operands++; + exp->X_op = O_constant; + exp->X_add_number = i.tm.extension_opcode; + i.tm.extension_opcode = None; +} + + +static int +check_hle (void) +{ + switch (i.tm.opcode_modifier.hleprefixok) + { + default: + abort (); + case HLEPrefixNone: + as_bad (_("invalid instruction `%s' after `%s'"), + i.tm.name, i.hle_prefix); + return 0; + case HLEPrefixLock: + if (i.prefix[LOCK_PREFIX]) + return 1; + as_bad (_("missing `lock' with `%s'"), i.hle_prefix); + return 0; + case HLEPrefixAny: + return 1; + case HLEPrefixRelease: + if (i.prefix[HLE_PREFIX] != XRELEASE_PREFIX_OPCODE) + { + as_bad (_("instruction `%s' after `xacquire' not allowed"), + i.tm.name); + return 0; + } + if (i.mem_operands == 0 + || !operand_type_check (i.types[i.operands - 1], anymem)) + { + as_bad (_("memory destination needed for instruction `%s'" + " after `xrelease'"), i.tm.name); + return 0; + } + return 1; + } +} + +/* This is the guts of the machine-dependent assembler. LINE points to a + machine dependent instruction. This function is supposed to emit + the frags/bytes it assembles to. */ + +void +md_assemble (char *line) +{ + unsigned int j; + char mnemonic[MAX_MNEM_SIZE]; + const insn_template *t; + + /* Initialize globals. */ + memset (&i, '\0', sizeof (i)); + for (j = 0; j < MAX_OPERANDS; j++) + i.reloc[j] = NO_RELOC; + memset (disp_expressions, '\0', sizeof (disp_expressions)); + memset (im_expressions, '\0', sizeof (im_expressions)); + save_stack_p = save_stack; + + /* First parse an instruction mnemonic & call i386_operand for the operands. + We assume that the scrubber has arranged it so that line[0] is the valid + start of a (possibly prefixed) mnemonic. */ + + line = parse_insn (line, mnemonic); + if (line == NULL) + return; + + line = parse_operands (line, mnemonic); + this_operand = -1; + if (line == NULL) + return; + + /* Now we've parsed the mnemonic into a set of templates, and have the + operands at hand. */ + + /* All intel opcodes have reversed operands except for "bound" and + "enter". We also don't reverse intersegment "jmp" and "call" + instructions with 2 immediate operands so that the immediate segment + precedes the offset, as it does when in AT&T mode. */ + if (intel_syntax + && i.operands > 1 + && (strcmp (mnemonic, "bound") != 0) + && (strcmp (mnemonic, "invlpga") != 0) + && !(operand_type_check (i.types[0], imm) + && operand_type_check (i.types[1], imm))) + swap_operands (); + + /* The order of the immediates should be reversed + for 2 immediates extrq and insertq instructions */ + if (i.imm_operands == 2 + && (strcmp (mnemonic, "extrq") == 0 + || strcmp (mnemonic, "insertq") == 0)) + swap_2_operands (0, 1); + + if (i.imm_operands) + optimize_imm (); + + /* Don't optimize displacement for movabs since it only takes 64bit + displacement. */ + if (i.disp_operands + && i.disp_encoding != disp_encoding_32bit + && (flag_code != CODE_64BIT + || strcmp (mnemonic, "movabs") != 0)) + optimize_disp (); + + /* Next, we find a template that matches the given insn, + making sure the overlap of the given operands types is consistent + with the template operand types. */ + + if (!(t = match_template ())) + return; + + if (sse_check != check_none + && !i.tm.opcode_modifier.noavx + && (i.tm.cpu_flags.bitfield.cpusse + || i.tm.cpu_flags.bitfield.cpusse2 + || i.tm.cpu_flags.bitfield.cpusse3 + || i.tm.cpu_flags.bitfield.cpussse3 + || i.tm.cpu_flags.bitfield.cpusse4_1 + || i.tm.cpu_flags.bitfield.cpusse4_2)) + { + (sse_check == check_warning + ? as_warn + : as_bad) (_("SSE instruction `%s' is used"), i.tm.name); + } + + /* Zap movzx and movsx suffix. The suffix has been set from + "word ptr" or "byte ptr" on the source operand in Intel syntax + or extracted from mnemonic in AT&T syntax. But we'll use + the destination register to choose the suffix for encoding. */ + if ((i.tm.base_opcode & ~9) == 0x0fb6) + { + /* In Intel syntax, there must be a suffix. In AT&T syntax, if + there is no suffix, the default will be byte extension. */ + if (i.reg_operands != 2 + && !i.suffix + && intel_syntax) + as_bad (_("ambiguous operand size for `%s'"), i.tm.name); + + i.suffix = 0; + } + + if (i.tm.opcode_modifier.fwait) + if (!add_prefix (FWAIT_OPCODE)) + return; + + /* Check if REP prefix is OK. */ + if (i.rep_prefix && !i.tm.opcode_modifier.repprefixok) + { + as_bad (_("invalid instruction `%s' after `%s'"), + i.tm.name, i.rep_prefix); + 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 if HLE prefix is OK. */ + if (i.hle_prefix && !check_hle ()) + return; + + /* Check BND prefix. */ + if (i.bnd_prefix && !i.tm.opcode_modifier.bndprefixok) + as_bad (_("expecting valid branch instruction after `bnd'")); + + if (i.tm.cpu_flags.bitfield.cpumpx + && flag_code == CODE_64BIT + && i.prefix[ADDR_PREFIX]) + as_bad (_("32-bit address isn't allowed in 64-bit MPX instructions.")); + + /* Insert BND prefix. */ + if (add_bnd_prefix + && i.tm.opcode_modifier.bndprefixok + && !i.prefix[BND_PREFIX]) + add_prefix (BND_PREFIX_OPCODE); + + /* Check string instruction segment overrides. */ + if (i.tm.opcode_modifier.isstring && i.mem_operands != 0) + { + if (!check_string ()) + return; + i.disp_operands = 0; + } + + if (!process_suffix ()) + return; + + /* Update operand types. */ + for (j = 0; j < i.operands; j++) + i.types[j] = operand_type_and (i.types[j], i.tm.operand_types[j]); + + /* Make still unresolved immediate matches conform to size of immediate + given in i.suffix. */ + if (!finalize_imm ()) + return; + + if (i.types[0].bitfield.imm1) + i.imm_operands = 0; /* kludge for shift insns. */ + + /* We only need to check those implicit registers for instructions + with 3 operands or less. */ + if (i.operands <= 3) + for (j = 0; j < i.operands; j++) + if (i.types[j].bitfield.inoutportreg + || i.types[j].bitfield.shiftcount + || i.types[j].bitfield.acc + || i.types[j].bitfield.floatacc) + i.reg_operands--; + + /* ImmExt should be processed after SSE2AVX. */ + if (!i.tm.opcode_modifier.sse2avx + && i.tm.opcode_modifier.immext) + process_immext (); + + /* For insns with operands there are more diddles to do to the opcode. */ + if (i.operands) + { + if (!process_operands ()) + return; + } + else if (!quiet_warnings && i.tm.opcode_modifier.ugh) + { + /* UnixWare fsub no args is alias for fsubp, fadd -> faddp, etc. */ + as_warn (_("translating to `%sp'"), i.tm.name); + } + + if (i.tm.opcode_modifier.vex) + build_vex_prefix (t); + + if (i.tm.opcode_modifier.evex) + build_evex_prefix (); + + /* 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; + } + + if ((i.tm.opcode_modifier.jump + || i.tm.opcode_modifier.jumpbyte + || i.tm.opcode_modifier.jumpdword) + && i.op[0].disps->X_op == O_constant) + { + /* Convert "jmp constant" (and "call constant") to a jump (call) to + the absolute address given by the constant. Since ix86 jumps and + calls are pc relative, we need to generate a reloc. */ + i.op[0].disps->X_add_symbol = &abs_symbol; + i.op[0].disps->X_op = O_symbol; + } + + if (i.tm.opcode_modifier.rex64) + i.rex |= REX_W; + + /* For 8 bit registers we need an empty rex prefix. Also if the + instruction already has a prefix, we need to convert old + registers to new ones. */ + + if ((i.types[0].bitfield.reg8 + && (i.op[0].regs->reg_flags & RegRex64) != 0) + || (i.types[1].bitfield.reg8 + && (i.op[1].regs->reg_flags & RegRex64) != 0) + || ((i.types[0].bitfield.reg8 + || i.types[1].bitfield.reg8) + && i.rex != 0)) + { + int x; + + i.rex |= REX_OPCODE; + for (x = 0; x < 2; x++) + { + /* Look for 8 bit operand that uses old registers. */ + if (i.types[x].bitfield.reg8 + && (i.op[x].regs->reg_flags & RegRex64) == 0) + { + /* In case it is "hi" register, give up. */ + if (i.op[x].regs->reg_num > 3) + as_bad (_("can't encode register '%s%s' in an " + "instruction requiring REX prefix."), + register_prefix, i.op[x].regs->reg_name); + + /* Otherwise it is equivalent to the extended register. + Since the encoding doesn't change this is merely + cosmetic cleanup for debug output. */ + + i.op[x].regs = i.op[x].regs + 8; + } + } + } + + if (i.rex != 0) + add_prefix (REX_OPCODE | i.rex); + + /* We are ready to output the insn. */ + output_insn (); +} + +static char * +parse_insn (char *line, char *mnemonic) +{ + char *l = line; + char *token_start = l; + char *mnem_p; + int supported; + const insn_template *t; + char *dot_p = NULL; + + while (1) + { + mnem_p = mnemonic; + while ((*mnem_p = mnemonic_chars[(unsigned char) *l]) != 0) + { + if (*mnem_p == '.') + dot_p = mnem_p; + mnem_p++; + if (mnem_p >= mnemonic + MAX_MNEM_SIZE) + { + as_bad (_("no such instruction: `%s'"), token_start); + return NULL; + } + l++; + } + if (!is_space_char (*l) + && *l != END_OF_INSN + && (intel_syntax + || (*l != PREFIX_SEPARATOR + && *l != ','))) + { + as_bad (_("invalid character %s in mnemonic"), + output_invalid (*l)); + return NULL; + } + if (token_start == l) + { + if (!intel_syntax && *l == PREFIX_SEPARATOR) + as_bad (_("expecting prefix; got nothing")); + else + as_bad (_("expecting mnemonic; got nothing")); + return NULL; + } + + /* Look up instruction (or prefix) via hash table. */ + current_templates = (const templates *) hash_find (op_hash, mnemonic); + + if (*l != END_OF_INSN + && (!is_space_char (*l) || l[1] != END_OF_INSN) + && current_templates + && current_templates->start->opcode_modifier.isprefix) + { + if (!cpu_flags_check_cpu64 (current_templates->start->cpu_flags)) + { + as_bad ((flag_code != CODE_64BIT + ? _("`%s' is only supported in 64-bit mode") + : _("`%s' is not supported in 64-bit mode")), + current_templates->start->name); + return NULL; + } + /* If we are in 16-bit mode, do not allow addr16 or data16. + Similarly, in 32-bit mode, do not allow addr32 or data32. */ + if ((current_templates->start->opcode_modifier.size16 + || current_templates->start->opcode_modifier.size32) + && flag_code != CODE_64BIT + && (current_templates->start->opcode_modifier.size32 + ^ (flag_code == CODE_16BIT))) + { + as_bad (_("redundant %s prefix"), + current_templates->start->name); + return NULL; + } + /* Add prefix, checking for repeated prefixes. */ + switch (add_prefix (current_templates->start->base_opcode)) + { + case PREFIX_EXIST: + return NULL; + case PREFIX_REP: + if (current_templates->start->cpu_flags.bitfield.cpuhle) + i.hle_prefix = current_templates->start->name; + else if (current_templates->start->cpu_flags.bitfield.cpumpx) + i.bnd_prefix = current_templates->start->name; + else + i.rep_prefix = current_templates->start->name; + break; + default: + break; + } + /* Skip past PREFIX_SEPARATOR and reset token_start. */ + token_start = ++l; + } + else + break; + } + + if (!current_templates) + { + /* 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 - 3 == dot_p + && dot_p[1] == 'd' + && dot_p[2] == '8') + i.disp_encoding = disp_encoding_8bit; + else if (mnem_p - 4 == dot_p + && dot_p[1] == 'd' + && dot_p[2] == '3' + && dot_p[3] == '2') + i.disp_encoding = disp_encoding_32bit; + else + goto check_suffix; + mnem_p = dot_p; + *dot_p = '\0'; + current_templates = (const templates *) hash_find (op_hash, mnemonic); + } + + if (!current_templates) + { +check_suffix: + /* See if we can get a match by trimming off a suffix. */ + switch (mnem_p[-1]) + { + case WORD_MNEM_SUFFIX: + if (intel_syntax && (intel_float_operand (mnemonic) & 2)) + i.suffix = SHORT_MNEM_SUFFIX; + else + case BYTE_MNEM_SUFFIX: + case QWORD_MNEM_SUFFIX: + i.suffix = mnem_p[-1]; + mnem_p[-1] = '\0'; + current_templates = (const templates *) hash_find (op_hash, + mnemonic); + break; + case SHORT_MNEM_SUFFIX: + case LONG_MNEM_SUFFIX: + if (!intel_syntax) + { + i.suffix = mnem_p[-1]; + mnem_p[-1] = '\0'; + current_templates = (const templates *) hash_find (op_hash, + mnemonic); + } + break; + + /* Intel Syntax. */ + case 'd': + if (intel_syntax) + { + if (intel_float_operand (mnemonic) == 1) + i.suffix = SHORT_MNEM_SUFFIX; + else + i.suffix = LONG_MNEM_SUFFIX; + mnem_p[-1] = '\0'; + current_templates = (const templates *) hash_find (op_hash, + mnemonic); + } + break; + } + if (!current_templates) + { + as_bad (_("no such instruction: `%s'"), token_start); + return NULL; + } + } + + if (current_templates->start->opcode_modifier.jump + || current_templates->start->opcode_modifier.jumpbyte) + { + /* Check for a branch hint. We allow ",pt" and ",pn" for + predict taken and predict not taken respectively. + I'm not sure that branch hints actually do anything on loop + and jcxz insns (JumpByte) for current Pentium4 chips. They + may work in the future and it doesn't hurt to accept them + now. */ + if (l[0] == ',' && l[1] == 'p') + { + if (l[2] == 't') + { + if (!add_prefix (DS_PREFIX_OPCODE)) + return NULL; + l += 3; + } + else if (l[2] == 'n') + { + if (!add_prefix (CS_PREFIX_OPCODE)) + return NULL; + l += 3; + } + } + } + /* Any other comma loses. */ + if (*l == ',') + { + as_bad (_("invalid character %s in mnemonic"), + output_invalid (*l)); + return NULL; + } + + /* Check if instruction is supported on specified architecture. */ + supported = 0; + for (t = current_templates->start; t < current_templates->end; ++t) + { + supported |= cpu_flags_match (t); + if (supported == CPU_FLAGS_PERFECT_MATCH) + goto skip; + } + + if (!(supported & CPU_FLAGS_64BIT_MATCH)) + { + as_bad (flag_code == CODE_64BIT + ? _("`%s' is not supported in 64-bit mode") + : _("`%s' is only supported in 64-bit mode"), + current_templates->start->name); + return NULL; + } + if (supported != CPU_FLAGS_PERFECT_MATCH) + { + as_bad (_("`%s' is not supported on `%s%s'"), + current_templates->start->name, + cpu_arch_name ? cpu_arch_name : default_arch, + cpu_sub_arch_name ? cpu_sub_arch_name : ""); + return NULL; + } + +skip: + if (!cpu_arch_flags.bitfield.cpui386 + && (flag_code != CODE_16BIT)) + { + as_warn (_("use .code16 to ensure correct addressing mode")); + } + + return l; +} + +static char * +parse_operands (char *l, const char *mnemonic) +{ + char *token_start; + + /* 1 if operand is pending after ','. */ + unsigned int expecting_operand = 0; + + /* Non-zero if operand parens not balanced. */ + unsigned int paren_not_balanced; + + while (*l != END_OF_INSN) + { + /* Skip optional white space before operand. */ + if (is_space_char (*l)) + ++l; + if (!is_operand_char (*l) && *l != END_OF_INSN) + { + as_bad (_("invalid character %s before operand %d"), + output_invalid (*l), + i.operands + 1); + return NULL; + } + token_start = l; /* after white space */ + paren_not_balanced = 0; + while (paren_not_balanced || *l != ',') + { + if (*l == END_OF_INSN) + { + if (paren_not_balanced) + { + if (!intel_syntax) + as_bad (_("unbalanced parenthesis in operand %d."), + i.operands + 1); + else + as_bad (_("unbalanced brackets in operand %d."), + i.operands + 1); + return NULL; + } + else + break; /* we are done */ + } + else if (!is_operand_char (*l) && !is_space_char (*l)) + { + as_bad (_("invalid character %s in operand %d"), + output_invalid (*l), + i.operands + 1); + return NULL; + } + if (!intel_syntax) + { + if (*l == '(') + ++paren_not_balanced; + if (*l == ')') + --paren_not_balanced; + } + else + { + if (*l == '[') + ++paren_not_balanced; + if (*l == ']') + --paren_not_balanced; + } + l++; + } + if (l != token_start) + { /* Yes, we've read in another operand. */ + unsigned int operand_ok; + this_operand = i.operands++; + i.types[this_operand].bitfield.unspecified = 1; + if (i.operands > MAX_OPERANDS) + { + as_bad (_("spurious operands; (%d operands/instruction max)"), + MAX_OPERANDS); + return NULL; + } + /* Now parse operand adding info to 'i' as we go along. */ + END_STRING_AND_SAVE (l); + + if (intel_syntax) + operand_ok = + i386_intel_operand (token_start, + intel_float_operand (mnemonic)); + else + operand_ok = i386_att_operand (token_start); + + RESTORE_END_STRING (l); + if (!operand_ok) + return NULL; + } + else + { + if (expecting_operand) + { + expecting_operand_after_comma: + as_bad (_("expecting operand after ','; got nothing")); + return NULL; + } + if (*l == ',') + { + as_bad (_("expecting operand before ','; got nothing")); + return NULL; + } + } + + /* Now *l must be either ',' or END_OF_INSN. */ + if (*l == ',') + { + if (*++l == END_OF_INSN) + { + /* Just skip it, if it's \n complain. */ + goto expecting_operand_after_comma; + } + expecting_operand = 1; + } + } + return l; +} + +static void +swap_2_operands (int xchg1, int xchg2) +{ + union i386_op temp_op; + i386_operand_type temp_type; + enum bfd_reloc_code_real temp_reloc; + + temp_type = i.types[xchg2]; + i.types[xchg2] = i.types[xchg1]; + i.types[xchg1] = temp_type; + temp_op = i.op[xchg2]; + i.op[xchg2] = i.op[xchg1]; + i.op[xchg1] = temp_op; + temp_reloc = i.reloc[xchg2]; + i.reloc[xchg2] = i.reloc[xchg1]; + i.reloc[xchg1] = temp_reloc; + + if (i.mask) + { + if (i.mask->operand == xchg1) + i.mask->operand = xchg2; + else if (i.mask->operand == xchg2) + i.mask->operand = xchg1; + } + if (i.broadcast) + { + if (i.broadcast->operand == xchg1) + i.broadcast->operand = xchg2; + else if (i.broadcast->operand == xchg2) + i.broadcast->operand = xchg1; + } + if (i.rounding) + { + if (i.rounding->operand == xchg1) + i.rounding->operand = xchg2; + else if (i.rounding->operand == xchg2) + i.rounding->operand = xchg1; + } +} + +static void +swap_operands (void) +{ + switch (i.operands) + { + case 5: + case 4: + swap_2_operands (1, i.operands - 2); + case 3: + case 2: + swap_2_operands (0, i.operands - 1); + break; + default: + abort (); + } + + if (i.mem_operands == 2) + { + const seg_entry *temp_seg; + temp_seg = i.seg[0]; + i.seg[0] = i.seg[1]; + i.seg[1] = temp_seg; + } +} + +/* Try to ensure constant immediates are represented in the smallest + opcode possible. */ +static void +optimize_imm (void) +{ + char guess_suffix = 0; + int op; + + if (i.suffix) + guess_suffix = i.suffix; + else if (i.reg_operands) + { + /* Figure out a suffix from the last register operand specified. + We can't do this properly yet, ie. excluding InOutPortReg, + but the following works for instructions with immediates. + In any case, we can't set i.suffix yet. */ + for (op = i.operands; --op >= 0;) + if (i.types[op].bitfield.reg8) + { + guess_suffix = BYTE_MNEM_SUFFIX; + break; + } + else if (i.types[op].bitfield.reg16) + { + guess_suffix = WORD_MNEM_SUFFIX; + break; + } + else if (i.types[op].bitfield.reg32) + { + guess_suffix = LONG_MNEM_SUFFIX; + break; + } + else if (i.types[op].bitfield.reg64) + { + guess_suffix = QWORD_MNEM_SUFFIX; + break; + } + } + else if ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0)) + guess_suffix = WORD_MNEM_SUFFIX; + + for (op = i.operands; --op >= 0;) + if (operand_type_check (i.types[op], imm)) + { + switch (i.op[op].imms->X_op) + { + case O_constant: + /* If a suffix is given, this operand may be shortened. */ + switch (guess_suffix) + { + case LONG_MNEM_SUFFIX: + i.types[op].bitfield.imm32 = 1; + i.types[op].bitfield.imm64 = 1; + break; + case WORD_MNEM_SUFFIX: + i.types[op].bitfield.imm16 = 1; + i.types[op].bitfield.imm32 = 1; + i.types[op].bitfield.imm32s = 1; + i.types[op].bitfield.imm64 = 1; + break; + case BYTE_MNEM_SUFFIX: + i.types[op].bitfield.imm8 = 1; + i.types[op].bitfield.imm8s = 1; + i.types[op].bitfield.imm16 = 1; + i.types[op].bitfield.imm32 = 1; + i.types[op].bitfield.imm32s = 1; + i.types[op].bitfield.imm64 = 1; + break; + } + + /* If this operand is at most 16 bits, convert it + to a signed 16 bit number before trying to see + whether it will fit in an even smaller size. + This allows a 16-bit operand such as $0xffe0 to + be recognised as within Imm8S range. */ + if ((i.types[op].bitfield.imm16) + && (i.op[op].imms->X_add_number & ~(offsetT) 0xffff) == 0) + { + i.op[op].imms->X_add_number = + (((i.op[op].imms->X_add_number & 0xffff) ^ 0x8000) - 0x8000); + } + if ((i.types[op].bitfield.imm32) + && ((i.op[op].imms->X_add_number & ~(((offsetT) 2 << 31) - 1)) + == 0)) + { + i.op[op].imms->X_add_number = ((i.op[op].imms->X_add_number + ^ ((offsetT) 1 << 31)) + - ((offsetT) 1 << 31)); + } + i.types[op] + = operand_type_or (i.types[op], + smallest_imm_type (i.op[op].imms->X_add_number)); + + /* We must avoid matching of Imm32 templates when 64bit + only immediate is available. */ + if (guess_suffix == QWORD_MNEM_SUFFIX) + i.types[op].bitfield.imm32 = 0; + break; + + case O_absent: + case O_register: + abort (); + + /* Symbols and expressions. */ + default: + /* Convert symbolic operand to proper sizes for matching, but don't + prevent matching a set of insns that only supports sizes other + than those matching the insn suffix. */ + { + i386_operand_type mask, allowed; + const insn_template *t; + + operand_type_set (&mask, 0); + operand_type_set (&allowed, 0); + + for (t = current_templates->start; + t < current_templates->end; + ++t) + allowed = operand_type_or (allowed, + t->operand_types[op]); + switch (guess_suffix) + { + case QWORD_MNEM_SUFFIX: + mask.bitfield.imm64 = 1; + mask.bitfield.imm32s = 1; + break; + case LONG_MNEM_SUFFIX: + mask.bitfield.imm32 = 1; + break; + case WORD_MNEM_SUFFIX: + mask.bitfield.imm16 = 1; + break; + case BYTE_MNEM_SUFFIX: + mask.bitfield.imm8 = 1; + break; + default: + break; + } + allowed = operand_type_and (mask, allowed); + if (!operand_type_all_zero (&allowed)) + i.types[op] = operand_type_and (i.types[op], mask); + } + break; + } + } +} + +/* Try to use the smallest displacement type too. */ +static void +optimize_disp (void) +{ + int op; + + for (op = i.operands; --op >= 0;) + if (operand_type_check (i.types[op], disp)) + { + if (i.op[op].disps->X_op == O_constant) + { + offsetT op_disp = i.op[op].disps->X_add_number; + + if (i.types[op].bitfield.disp16 + && (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. */ + op_disp = (((op_disp & 0xffff) ^ 0x8000) - 0x8000); + i.types[op].bitfield.disp64 = 0; + } + if (i.types[op].bitfield.disp32 + && (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. */ + op_disp &= (((offsetT) 2 << 31) - 1); + op_disp = (op_disp ^ ((offsetT) 1 << 31)) - ((addressT) 1 << 31); + i.types[op].bitfield.disp64 = 0; + } + if (!op_disp && i.types[op].bitfield.baseindex) + { + i.types[op].bitfield.disp8 = 0; + i.types[op].bitfield.disp16 = 0; + i.types[op].bitfield.disp32 = 0; + i.types[op].bitfield.disp32s = 0; + i.types[op].bitfield.disp64 = 0; + i.op[op].disps = 0; + i.disp_operands--; + } + else if (flag_code == CODE_64BIT) + { + if (fits_in_signed_long (op_disp)) + { + i.types[op].bitfield.disp64 = 0; + i.types[op].bitfield.disp32s = 1; + } + 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 (op_disp)) + i.types[op].bitfield.disp8 = 1; + } + else if (i.reloc[op] == BFD_RELOC_386_TLS_DESC_CALL + || i.reloc[op] == BFD_RELOC_X86_64_TLSDESC_CALL) + { + fix_new_exp (frag_now, frag_more (0) - frag_now->fr_literal, 0, + i.op[op].disps, 0, i.reloc[op]); + i.types[op].bitfield.disp8 = 0; + i.types[op].bitfield.disp16 = 0; + i.types[op].bitfield.disp32 = 0; + i.types[op].bitfield.disp32s = 0; + i.types[op].bitfield.disp64 = 0; + } + else + /* We only support 64bit displacement on constants. */ + i.types[op].bitfield.disp64 = 0; + } +} + +/* Check if operands are valid for the instruction. */ + +static int +check_VecOperands (const insn_template *t) +{ + unsigned int op; + + /* 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.index_reg->reg_type.bitfield.regzmm)) + { + i.error = unsupported_vector_index_register; + return 1; + } + + /* For VSIB byte, we need a vector register for index, and all vector + registers must be distinct. */ + if (t->opcode_modifier.vecsib) + { + if (!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) + || (t->opcode_modifier.vecsib == VecSIB512 + && i.index_reg->reg_type.bitfield.regzmm))) + { + i.error = invalid_vsib_address; + return 1; + } + + gas_assert (i.reg_operands == 2 || i.mask); + if (i.reg_operands == 2 && !i.mask) + { + gas_assert (i.types[0].bitfield.regxmm + || i.types[0].bitfield.regymm + || i.types[0].bitfield.regzmm); + gas_assert (i.types[2].bitfield.regxmm + || i.types[2].bitfield.regymm + || i.types[2].bitfield.regzmm); + if (operand_check == check_none) + return 0; + if (register_number (i.op[0].regs) + != register_number (i.index_reg) + && register_number (i.op[2].regs) + != register_number (i.index_reg) + && register_number (i.op[0].regs) + != register_number (i.op[2].regs)) + return 0; + if (operand_check == check_error) + { + i.error = invalid_vector_register_set; + return 1; + } + as_warn (_("mask, index, and destination registers should be distinct")); + } + } + + /* Check if broadcast is supported by the instruction and is applied + to the memory operand. */ + if (i.broadcast) + { + int broadcasted_opnd_size; + + /* Check if specified broadcast is supported in this instruction, + and it's applied to memory operand of DWORD or QWORD type, + depending on VecESize. */ + if (i.broadcast->type != t->opcode_modifier.broadcast + || !i.types[i.broadcast->operand].bitfield.mem + || (t->opcode_modifier.vecesize == 0 + && !i.types[i.broadcast->operand].bitfield.dword + && !i.types[i.broadcast->operand].bitfield.unspecified) + || (t->opcode_modifier.vecesize == 1 + && !i.types[i.broadcast->operand].bitfield.qword + && !i.types[i.broadcast->operand].bitfield.unspecified)) + goto bad_broadcast; + + broadcasted_opnd_size = t->opcode_modifier.vecesize ? 64 : 32; + if (i.broadcast->type == BROADCAST_1TO16) + broadcasted_opnd_size <<= 4; /* Broadcast 1to16. */ + else if (i.broadcast->type == BROADCAST_1TO8) + broadcasted_opnd_size <<= 3; /* Broadcast 1to8. */ + else + goto bad_broadcast; + + if ((broadcasted_opnd_size == 256 + && !t->operand_types[i.broadcast->operand].bitfield.ymmword) + || (broadcasted_opnd_size == 512 + && !t->operand_types[i.broadcast->operand].bitfield.zmmword)) + { + bad_broadcast: + i.error = unsupported_broadcast; + return 1; + } + } + /* If broadcast is supported in this instruction, we need to check if + operand of one-element size isn't specified without broadcast. */ + else if (t->opcode_modifier.broadcast && i.mem_operands) + { + /* Find memory operand. */ + for (op = 0; op < i.operands; op++) + if (operand_type_check (i.types[op], anymem)) + break; + gas_assert (op < i.operands); + /* Check size of the memory operand. */ + if ((t->opcode_modifier.vecesize == 0 + && i.types[op].bitfield.dword) + || (t->opcode_modifier.vecesize == 1 + && i.types[op].bitfield.qword)) + { + i.error = broadcast_needed; + return 1; + } + } + + /* Check if requested masking is supported. */ + if (i.mask + && (!t->opcode_modifier.masking + || (i.mask->zeroing + && t->opcode_modifier.masking == MERGING_MASKING))) + { + i.error = unsupported_masking; + return 1; + } + + /* Check if masking is applied to dest operand. */ + if (i.mask && (i.mask->operand != (int) (i.operands - 1))) + { + i.error = mask_not_on_destination; + return 1; + } + + /* Check if default mask is allowed. */ + if (t->opcode_modifier.nodefmask + && (!i.mask || i.mask->mask->reg_num == 0)) + { + i.error = no_default_mask; + return 1; + } + + /* Check RC/SAE. */ + if (i.rounding) + { + if ((i.rounding->type != saeonly + && !t->opcode_modifier.staticrounding) + || (i.rounding->type == saeonly + && (t->opcode_modifier.staticrounding + || !t->opcode_modifier.sae))) + { + i.error = unsupported_rc_sae; + return 1; + } + /* If the instruction has several immediate operands and one of + them is rounding, the rounding operand should be the last + immediate operand. */ + if (i.imm_operands > 1 + && i.rounding->operand != (int) (i.imm_operands - 1)) + { + i.error = rc_sae_operand_not_last_imm; + return 1; + } + } + + /* Check vector Disp8 operand. */ + if (t->opcode_modifier.disp8memshift) + { + if (i.broadcast) + i.memshift = t->opcode_modifier.vecesize ? 3 : 2; + else + i.memshift = t->opcode_modifier.disp8memshift; + + for (op = 0; op < i.operands; op++) + if (operand_type_check (i.types[op], disp) + && 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); + if (t->operand_types [op].bitfield.vec_disp8) + { + if (vec_disp8_ok) + i.types[op].bitfield.vec_disp8 = 1; + else + { + /* Vector insn can only have Vec_Disp8/Disp32 in + 32/64bit modes, and Vec_Disp8/Disp16 in 16bit + mode. */ + i.types[op].bitfield.disp8 = 0; + if (flag_code != CODE_16BIT) + i.types[op].bitfield.disp16 = 0; + } + } + else if (flag_code != CODE_16BIT) + { + /* One form of this instruction supports vector Disp8. + Try vector Disp8 if we need to use Disp32. */ + if (vec_disp8_ok && !fits_in_signed_byte (value)) + { + i.error = try_vector_disp8; + return 1; + } + } + } + } + else + i.memshift = -1; + + return 0; +} + +/* Check if operands are valid for the instruction. Update VEX + operand types. */ + +static int +VEX_check_operands (const insn_template *t) +{ + /* VREX is only valid with EVEX prefix. */ + if (i.need_vrex && !t->opcode_modifier.evex) + { + i.error = invalid_register_operand; + return 1; + } + + 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 insn_template *t; + i386_operand_type overlap0, overlap1, overlap2, overlap3; + i386_operand_type overlap4; + unsigned int found_reverse_match; + i386_opcode_modifier suffix_check; + i386_operand_type operand_types [MAX_OPERANDS]; + int addr_prefix_disp; + unsigned int j; + unsigned int found_cpu_match; + unsigned int check_register; + enum i386_error specific_error = 0; + +#if MAX_OPERANDS != 5 +# error "MAX_OPERANDS must be 5." +#endif + + found_reverse_match = 0; + addr_prefix_disp = -1; + + memset (&suffix_check, 0, sizeof (suffix_check)); + if (i.suffix == BYTE_MNEM_SUFFIX) + suffix_check.no_bsuf = 1; + else if (i.suffix == WORD_MNEM_SUFFIX) + suffix_check.no_wsuf = 1; + else if (i.suffix == SHORT_MNEM_SUFFIX) + suffix_check.no_ssuf = 1; + else if (i.suffix == LONG_MNEM_SUFFIX) + suffix_check.no_lsuf = 1; + else if (i.suffix == QWORD_MNEM_SUFFIX) + suffix_check.no_qsuf = 1; + 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; + + 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/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) + || (t->opcode_modifier.no_lsuf && suffix_check.no_lsuf) + || (t->opcode_modifier.no_ssuf && suffix_check.no_ssuf) + || (t->opcode_modifier.no_qsuf && suffix_check.no_qsuf) + || (t->opcode_modifier.no_ldsuf && suffix_check.no_ldsuf))) + continue; + + if (!operand_size_match (t)) + continue; + + for (j = 0; j < MAX_OPERANDS; j++) + operand_types[j] = t->operand_types[j]; + + /* In general, don't allow 64-bit operands in 32-bit mode. */ + if (i.suffix == QWORD_MNEM_SUFFIX + && flag_code != CODE_64BIT + && (intel_syntax + ? (!t->opcode_modifier.ignoresize + && !intel_float_operand (t->name)) + : intel_float_operand (t->name) != 2) + && ((!operand_types[0].bitfield.regmmx + && !operand_types[0].bitfield.regxmm + && !operand_types[0].bitfield.regymm + && !operand_types[0].bitfield.regzmm) + || (!operand_types[t->operands > 1].bitfield.regmmx + && !!operand_types[t->operands > 1].bitfield.regxmm + && !!operand_types[t->operands > 1].bitfield.regymm + && !!operand_types[t->operands > 1].bitfield.regzmm)) + && (t->base_opcode != 0x0fc7 + || t->extension_opcode != 1 /* cmpxchg8b */)) + continue; + + /* In general, don't allow 32-bit operands on pre-386. */ + else if (i.suffix == LONG_MNEM_SUFFIX + && !cpu_arch_flags.bitfield.cpui386 + && (intel_syntax + ? (!t->opcode_modifier.ignoresize + && !intel_float_operand (t->name)) + : intel_float_operand (t->name) != 2) + && ((!operand_types[0].bitfield.regmmx + && !operand_types[0].bitfield.regxmm) + || (!operand_types[t->operands > 1].bitfield.regmmx + && !!operand_types[t->operands > 1].bitfield.regxmm))) + continue; + + /* Do not verify operands when there are none. */ + else + { + if (!t->operands) + /* We've found a match; break out of loop. */ + break; + } + + /* Address size prefix will turn Disp64/Disp32/Disp16 operand + into Disp32/Disp16/Disp32 operand. */ + if (i.prefix[ADDR_PREFIX] != 0) + { + /* There should be only one Disp operand. */ + switch (flag_code) + { + case CODE_16BIT: + for (j = 0; j < MAX_OPERANDS; j++) + { + if (operand_types[j].bitfield.disp16) + { + addr_prefix_disp = j; + operand_types[j].bitfield.disp32 = 1; + operand_types[j].bitfield.disp16 = 0; + break; + } + } + break; + case CODE_32BIT: + for (j = 0; j < MAX_OPERANDS; j++) + { + if (operand_types[j].bitfield.disp32) + { + addr_prefix_disp = j; + operand_types[j].bitfield.disp32 = 0; + operand_types[j].bitfield.disp16 = 1; + break; + } + } + break; + case CODE_64BIT: + for (j = 0; j < MAX_OPERANDS; j++) + { + if (operand_types[j].bitfield.disp64) + { + addr_prefix_disp = j; + operand_types[j].bitfield.disp64 = 0; + operand_types[j].bitfield.disp32 = 1; + break; + } + } + break; + } + } + + /* 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) + { + case 1: + if (!operand_type_match (overlap0, i.types[0])) + continue; + break; + case 2: + /* xchg %eax, %eax is a special case. It is an aliase for nop + only in 32bit mode and we can use opcode 0x90. In 64bit + mode, we can't use 0x90 for xchg %eax, %eax since it should + zero-extend %eax to %rax. */ + if (flag_code == CODE_64BIT + && t->base_opcode == 0x90 + && operand_type_equal (&i.types [0], &acc32) + && operand_type_equal (&i.types [1], &acc32)) + continue; + if (i.swap_operand) + { + /* If we swap operand in encoding, we either match + the next one or reverse direction of operands. */ + if (t->opcode_modifier.s) + continue; + else if (t->opcode_modifier.d) + goto check_reverse; + } + + case 3: + /* If we swap operand in encoding, we match the next one. */ + if (i.swap_operand && t->opcode_modifier.s) + continue; + case 4: + case 5: + overlap1 = operand_type_and (i.types[1], operand_types[1]); + if (!operand_type_match (overlap0, i.types[0]) + || !operand_type_match (overlap1, i.types[1]) + || (check_register + && !operand_type_register_match (overlap0, i.types[0], + operand_types[0], + overlap1, i.types[1], + operand_types[1]))) + { + /* Check if other direction is valid ... */ + if (!t->opcode_modifier.d && !t->opcode_modifier.floatd) + continue; + +check_reverse: + /* Try reversing direction of operands. */ + overlap0 = operand_type_and (i.types[0], operand_types[1]); + overlap1 = operand_type_and (i.types[1], operand_types[0]); + if (!operand_type_match (overlap0, i.types[0]) + || !operand_type_match (overlap1, i.types[1]) + || (check_register + && !operand_type_register_match (overlap0, + i.types[0], + operand_types[1], + overlap1, + i.types[1], + operand_types[0]))) + { + /* Does not match either direction. */ + continue; + } + /* found_reverse_match holds which of D or FloatDR + we've found. */ + if (t->opcode_modifier.d) + found_reverse_match = Opcode_D; + else if (t->opcode_modifier.floatd) + found_reverse_match = Opcode_FloatD; + else + found_reverse_match = 0; + if (t->opcode_modifier.floatr) + found_reverse_match |= Opcode_FloatR; + } + else + { + /* Found a forward 2 operand match here. */ + switch (t->operands) + { + case 5: + overlap4 = operand_type_and (i.types[4], + operand_types[4]); + case 4: + overlap3 = operand_type_and (i.types[3], + operand_types[3]); + case 3: + overlap2 = operand_type_and (i.types[2], + operand_types[2]); + break; + } + + switch (t->operands) + { + case 5: + if (!operand_type_match (overlap4, i.types[4]) + || !operand_type_register_match (overlap3, + i.types[3], + operand_types[3], + overlap4, + i.types[4], + operand_types[4])) + continue; + case 4: + if (!operand_type_match (overlap3, i.types[3]) + || (check_register + && !operand_type_register_match (overlap2, + i.types[2], + operand_types[2], + overlap3, + i.types[3], + operand_types[3]))) + continue; + case 3: + /* Here we make use of the fact that there are no + reverse match 3 operand instructions, and all 3 + operand instructions only need to be checked for + register consistency between operands 2 and 3. */ + if (!operand_type_match (overlap2, i.types[2]) + || (check_register + && !operand_type_register_match (overlap1, + i.types[1], + operand_types[1], + overlap2, + i.types[2], + operand_types[2]))) + continue; + break; + } + } + /* Found either forward/reverse 2, 3 or 4 operand match here: + slip through to break. */ + } + if (!found_cpu_match) + { + found_reverse_match = 0; + continue; + } + + /* Check if vector and VEX operands are valid. */ + if (check_VecOperands (t) || VEX_check_operands (t)) + { + specific_error = i.error; + continue; + } + + /* We've found a match; break out of loop. */ + break; + } + + if (t == current_templates->end) + { + /* We found no match. */ + const char *err_msg; + switch (specific_error ? specific_error : 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 = _("constant doesn't fit in 4 bits"); + 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: + as_bad (_("unsupported instruction `%s'"), + current_templates->start->name); + return NULL; + case invalid_vsib_address: + err_msg = _("invalid VSIB address"); + break; + case invalid_vector_register_set: + err_msg = _("mask, index, and destination registers must be distinct"); + break; + case unsupported_vector_index_register: + err_msg = _("unsupported vector index register"); + break; + case unsupported_broadcast: + err_msg = _("unsupported broadcast"); + break; + case broadcast_not_on_src_operand: + err_msg = _("broadcast not on source memory operand"); + break; + case broadcast_needed: + err_msg = _("broadcast is needed for operand of such type"); + break; + case unsupported_masking: + err_msg = _("unsupported masking"); + break; + case mask_not_on_destination: + err_msg = _("mask not on destination operand"); + break; + case no_default_mask: + err_msg = _("default mask isn't allowed"); + break; + case unsupported_rc_sae: + err_msg = _("unsupported static rounding/sae"); + break; + case rc_sae_operand_not_last_imm: + if (intel_syntax) + err_msg = _("RC/SAE operand must precede immediate operands"); + else + err_msg = _("RC/SAE operand must follow immediate operands"); + break; + case invalid_register_operand: + err_msg = _("invalid register operand"); + break; + } + as_bad (_("%s for `%s'"), err_msg, + current_templates->start->name); + return NULL; + } + + if (!quiet_warnings) + { + if (!intel_syntax + && (i.types[0].bitfield.jumpabsolute + != operand_types[0].bitfield.jumpabsolute)) + { + as_warn (_("indirect %s without `*'"), t->name); + } + + if (t->opcode_modifier.isprefix + && t->opcode_modifier.ignoresize) + { + /* Warn them that a data or address size prefix doesn't + affect assembly of the next line of code. */ + as_warn (_("stand-alone `%s' prefix"), t->name); + } + } + + /* Copy the template we found. */ + i.tm = *t; + + if (addr_prefix_disp != -1) + i.tm.operand_types[addr_prefix_disp] + = operand_types[addr_prefix_disp]; + + if (found_reverse_match) + { + /* If we found a reverse match we must alter the opcode + direction bit. found_reverse_match holds bits to change + (different for int & float insns). */ + + i.tm.base_opcode ^= found_reverse_match; + + i.tm.operand_types[0] = operand_types[1]; + i.tm.operand_types[1] = operand_types[0]; + } + + return t; +} + +static int +check_string (void) +{ + int mem_op = operand_type_check (i.types[0], anymem) ? 0 : 1; + if (i.tm.operand_types[mem_op].bitfield.esseg) + { + if (i.seg[0] != NULL && i.seg[0] != &es) + { + as_bad (_("`%s' operand %d must use `%ses' segment"), + i.tm.name, + mem_op + 1, + register_prefix); + return 0; + } + /* There's only ever one segment override allowed per instruction. + This instruction possibly has a legal segment override on the + second operand, so copy the segment to where non-string + instructions store it, allowing common code. */ + i.seg[0] = i.seg[1]; + } + else if (i.tm.operand_types[mem_op + 1].bitfield.esseg) + { + if (i.seg[1] != NULL && i.seg[1] != &es) + { + as_bad (_("`%s' operand %d must use `%ses' segment"), + i.tm.name, + mem_op + 2, + register_prefix); + return 0; + } + } + return 1; +} + +static int +process_suffix (void) +{ + /* If matched instruction specifies an explicit instruction mnemonic + suffix, use it. */ + if (i.tm.opcode_modifier.size16) + i.suffix = WORD_MNEM_SUFFIX; + else if (i.tm.opcode_modifier.size32) + i.suffix = LONG_MNEM_SUFFIX; + else if (i.tm.opcode_modifier.size64) + i.suffix = QWORD_MNEM_SUFFIX; + else if (i.reg_operands) + { + /* If there's no instruction mnemonic suffix we try to invent one + based on register operands. */ + if (!i.suffix) + { + /* We take i.suffix from the last register operand specified, + Destination register type is more significant than source + register type. crc32 in SSE4.2 prefers source register + type. */ + if (i.tm.base_opcode == 0xf20f38f1) + { + if (i.types[0].bitfield.reg16) + i.suffix = WORD_MNEM_SUFFIX; + else if (i.types[0].bitfield.reg32) + i.suffix = LONG_MNEM_SUFFIX; + else if (i.types[0].bitfield.reg64) + i.suffix = QWORD_MNEM_SUFFIX; + } + else if (i.tm.base_opcode == 0xf20f38f0) + { + if (i.types[0].bitfield.reg8) + i.suffix = BYTE_MNEM_SUFFIX; + } + + if (!i.suffix) + { + int op; + + if (i.tm.base_opcode == 0xf20f38f1 + || i.tm.base_opcode == 0xf20f38f0) + { + /* We have to know the operand size for crc32. */ + as_bad (_("ambiguous memory operand size for `%s`"), + i.tm.name); + return 0; + } + + for (op = i.operands; --op >= 0;) + if (!i.tm.operand_types[op].bitfield.inoutportreg) + { + if (i.types[op].bitfield.reg8) + { + i.suffix = BYTE_MNEM_SUFFIX; + break; + } + else if (i.types[op].bitfield.reg16) + { + i.suffix = WORD_MNEM_SUFFIX; + break; + } + else if (i.types[op].bitfield.reg32) + { + i.suffix = LONG_MNEM_SUFFIX; + break; + } + else if (i.types[op].bitfield.reg64) + { + i.suffix = QWORD_MNEM_SUFFIX; + break; + } + } + } + } + else if (i.suffix == BYTE_MNEM_SUFFIX) + { + 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 (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) + { + if (intel_syntax + && i.tm.opcode_modifier.ignoresize + && i.tm.opcode_modifier.no_qsuf) + i.suffix = 0; + else if (!check_qword_reg ()) + return 0; + } + else if (i.suffix == WORD_MNEM_SUFFIX) + { + 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 + || i.suffix == YMMWORD_MNEM_SUFFIX + || i.suffix == ZMMWORD_MNEM_SUFFIX) + { + /* Skip if the instruction has x/y/z suffix. match_template + should check if it is a valid suffix. */ + } + else if (intel_syntax && i.tm.opcode_modifier.ignoresize) + /* Do nothing if the instruction is going to ignore the prefix. */ + ; + else + abort (); + } + else if (i.tm.opcode_modifier.defaultsize + && !i.suffix + /* exclude fldenv/frstor/fsave/fstenv */ + && i.tm.opcode_modifier.no_ssuf) + { + i.suffix = stackop_size; + } + else if (intel_syntax + && !i.suffix + && (i.tm.operand_types[0].bitfield.jumpabsolute + || i.tm.opcode_modifier.jumpbyte + || i.tm.opcode_modifier.jumpintersegment + || (i.tm.base_opcode == 0x0f01 /* [ls][gi]dt */ + && i.tm.extension_opcode <= 3))) + { + switch (flag_code) + { + case CODE_64BIT: + if (!i.tm.opcode_modifier.no_qsuf) + { + i.suffix = QWORD_MNEM_SUFFIX; + break; + } + case CODE_32BIT: + if (!i.tm.opcode_modifier.no_lsuf) + i.suffix = LONG_MNEM_SUFFIX; + break; + case CODE_16BIT: + if (!i.tm.opcode_modifier.no_wsuf) + i.suffix = WORD_MNEM_SUFFIX; + break; + } + } + + if (!i.suffix) + { + if (!intel_syntax) + { + if (i.tm.opcode_modifier.w) + { + as_bad (_("no instruction mnemonic suffix given and " + "no register operands; can't size instruction")); + return 0; + } + } + else + { + unsigned int suffixes; + + suffixes = !i.tm.opcode_modifier.no_bsuf; + if (!i.tm.opcode_modifier.no_wsuf) + suffixes |= 1 << 1; + if (!i.tm.opcode_modifier.no_lsuf) + suffixes |= 1 << 2; + if (!i.tm.opcode_modifier.no_ldsuf) + suffixes |= 1 << 3; + if (!i.tm.opcode_modifier.no_ssuf) + suffixes |= 1 << 4; + if (!i.tm.opcode_modifier.no_qsuf) + suffixes |= 1 << 5; + + /* There are more than suffix matches. */ + if (i.tm.opcode_modifier.w + || ((suffixes & (suffixes - 1)) + && !i.tm.opcode_modifier.defaultsize + && !i.tm.opcode_modifier.ignoresize)) + { + as_bad (_("ambiguous operand size for `%s'"), i.tm.name); + return 0; + } + } + } + + /* Change the opcode based on the operand size given by i.suffix; + We don't need to change things for byte insns. */ + + if (i.suffix + && i.suffix != BYTE_MNEM_SUFFIX + && i.suffix != XMMWORD_MNEM_SUFFIX + && i.suffix != YMMWORD_MNEM_SUFFIX + && i.suffix != ZMMWORD_MNEM_SUFFIX) + { + /* It's not a byte, select word/dword operation. */ + if (i.tm.opcode_modifier.w) + { + if (i.tm.opcode_modifier.shortform) + i.tm.base_opcode |= 8; + else + i.tm.base_opcode |= 1; + } + + /* Now select between word & dword operations via the operand + size prefix, except for instructions that will ignore this + prefix anyway. */ + if (i.tm.opcode_modifier.addrprefixop0) + { + /* The address size override prefix changes the size of the + first operand. */ + if ((flag_code == CODE_32BIT + && i.op->regs[0].reg_type.bitfield.reg16) + || (flag_code != CODE_32BIT + && i.op->regs[0].reg_type.bitfield.reg32)) + if (!add_prefix (ADDR_PREFIX_OPCODE)) + return 0; + } + else if (i.suffix != QWORD_MNEM_SUFFIX + && i.suffix != LONG_DOUBLE_MNEM_SUFFIX + && !i.tm.opcode_modifier.ignoresize + && !i.tm.opcode_modifier.floatmf + && ((i.suffix == LONG_MNEM_SUFFIX) == (flag_code == CODE_16BIT) + || (flag_code == CODE_64BIT + && i.tm.opcode_modifier.jumpbyte))) + { + unsigned int prefix = DATA_PREFIX_OPCODE; + + if (i.tm.opcode_modifier.jumpbyte) /* jcxz, loop */ + prefix = ADDR_PREFIX_OPCODE; + + if (!add_prefix (prefix)) + return 0; + } + + /* Set mode64 for an operand. */ + if (i.suffix == QWORD_MNEM_SUFFIX + && flag_code == CODE_64BIT + && !i.tm.opcode_modifier.norex64) + { + /* Special case for xchg %rax,%rax. It is NOP and doesn't + need rex64. cmpxchg8b is also a special case. */ + if (! (i.operands == 2 + && i.tm.base_opcode == 0x90 + && i.tm.extension_opcode == None + && operand_type_equal (&i.types [0], &acc64) + && operand_type_equal (&i.types [1], &acc64)) + && ! (i.operands == 1 + && i.tm.base_opcode == 0xfc7 + && i.tm.extension_opcode == 1 + && !operand_type_check (i.types [0], reg) + && operand_type_check (i.types [0], anymem))) + i.rex |= REX_W; + } + + /* Size floating point instruction. */ + if (i.suffix == LONG_MNEM_SUFFIX) + if (i.tm.opcode_modifier.floatmf) + i.tm.base_opcode ^= 4; + } + + return 1; +} + +static int +check_byte_reg (void) +{ + int op; + + for (op = i.operands; --op >= 0;) + { + /* If this is an eight bit register, it's OK. If it's the 16 or + 32 bit version of an eight bit register, we will just use the + low portion, and that's OK too. */ + if (i.types[op].bitfield.reg8) + continue; + + /* I/O port address operands are OK too. */ + if (i.tm.operand_types[op].bitfield.inoutportreg) + continue; + + /* crc32 doesn't generate this warning. */ + if (i.tm.base_opcode == 0xf20f38f0) + continue; + + if ((i.types[op].bitfield.reg16 + || i.types[op].bitfield.reg32 + || i.types[op].bitfield.reg64) + && i.op[op].regs->reg_num < 4 + /* Prohibit these changes in 64bit mode, since the lowering + would be more complicated. */ + && flag_code != CODE_64BIT) + { +#if REGISTER_WARNINGS + if (!quiet_warnings) + as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"), + register_prefix, + (i.op[op].regs + (i.types[op].bitfield.reg16 + ? REGNAM_AL - REGNAM_AX + : REGNAM_AL - REGNAM_EAX))->reg_name, + register_prefix, + i.op[op].regs->reg_name, + i.suffix); +#endif + continue; + } + /* Any other register is bad. */ + if (i.types[op].bitfield.reg16 + || i.types[op].bitfield.reg32 + || i.types[op].bitfield.reg64 + || i.types[op].bitfield.regmmx + || i.types[op].bitfield.regxmm + || i.types[op].bitfield.regymm + || i.types[op].bitfield.regzmm + || i.types[op].bitfield.sreg2 + || i.types[op].bitfield.sreg3 + || i.types[op].bitfield.control + || i.types[op].bitfield.debug + || i.types[op].bitfield.test + || i.types[op].bitfield.floatreg + || i.types[op].bitfield.floatacc) + { + as_bad (_("`%s%s' not allowed with `%s%c'"), + register_prefix, + i.op[op].regs->reg_name, + i.tm.name, + i.suffix); + return 0; + } + } + return 1; +} + +static int +check_long_reg (void) +{ + int op; + + for (op = i.operands; --op >= 0;) + /* Reject eight bit registers, except where the template requires + them. (eg. movzb) */ + if (i.types[op].bitfield.reg8 + && (i.tm.operand_types[op].bitfield.reg16 + || i.tm.operand_types[op].bitfield.reg32 + || i.tm.operand_types[op].bitfield.acc)) + { + as_bad (_("`%s%s' not allowed with `%s%c'"), + register_prefix, + i.op[op].regs->reg_name, + i.tm.name, + i.suffix); + return 0; + } + /* Warn if the e prefix on a general reg is missing. */ + else if ((!quiet_warnings || flag_code == CODE_64BIT) + && i.types[op].bitfield.reg16 + && (i.tm.operand_types[op].bitfield.reg32 + || i.tm.operand_types[op].bitfield.acc)) + { + /* Prohibit these changes in the 64bit mode, since the + lowering is more complicated. */ + if (flag_code == CODE_64BIT) + { + as_bad (_("incorrect register `%s%s' used with `%c' suffix"), + register_prefix, i.op[op].regs->reg_name, + i.suffix); + return 0; + } +#if REGISTER_WARNINGS + as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"), + register_prefix, + (i.op[op].regs + REGNAM_EAX - REGNAM_AX)->reg_name, + register_prefix, i.op[op].regs->reg_name, i.suffix); +#endif + } + /* Warn if the r prefix on a general reg is missing. */ + else if (i.types[op].bitfield.reg64 + && (i.tm.operand_types[op].bitfield.reg32 + || i.tm.operand_types[op].bitfield.acc)) + { + if (intel_syntax + && i.tm.opcode_modifier.toqword + && !i.types[0].bitfield.regxmm) + { + /* Convert to QWORD. We want REX byte. */ + i.suffix = QWORD_MNEM_SUFFIX; + } + else + { + as_bad (_("incorrect register `%s%s' used with `%c' suffix"), + register_prefix, i.op[op].regs->reg_name, + i.suffix); + return 0; + } + } + return 1; +} + +static int +check_qword_reg (void) +{ + int op; + + for (op = i.operands; --op >= 0; ) + /* Reject eight bit registers, except where the template requires + them. (eg. movzb) */ + if (i.types[op].bitfield.reg8 + && (i.tm.operand_types[op].bitfield.reg16 + || i.tm.operand_types[op].bitfield.reg32 + || i.tm.operand_types[op].bitfield.acc)) + { + as_bad (_("`%s%s' not allowed with `%s%c'"), + register_prefix, + i.op[op].regs->reg_name, + i.tm.name, + i.suffix); + return 0; + } + /* Warn if the e prefix on a general reg is missing. */ + else if ((i.types[op].bitfield.reg16 + || i.types[op].bitfield.reg32) + && (i.tm.operand_types[op].bitfield.reg32 + || i.tm.operand_types[op].bitfield.acc)) + { + /* Prohibit these changes in the 64bit mode, since the + lowering is more complicated. */ + if (intel_syntax + && i.tm.opcode_modifier.todword + && !i.types[0].bitfield.regxmm) + { + /* Convert to DWORD. We don't want REX byte. */ + i.suffix = LONG_MNEM_SUFFIX; + } + else + { + as_bad (_("incorrect register `%s%s' used with `%c' suffix"), + register_prefix, i.op[op].regs->reg_name, + i.suffix); + return 0; + } + } + return 1; +} + +static int +check_word_reg (void) +{ + int op; + for (op = i.operands; --op >= 0;) + /* Reject eight bit registers, except where the template requires + them. (eg. movzb) */ + if (i.types[op].bitfield.reg8 + && (i.tm.operand_types[op].bitfield.reg16 + || i.tm.operand_types[op].bitfield.reg32 + || i.tm.operand_types[op].bitfield.acc)) + { + as_bad (_("`%s%s' not allowed with `%s%c'"), + register_prefix, + i.op[op].regs->reg_name, + i.tm.name, + i.suffix); + return 0; + } + /* Warn if the e prefix on a general reg is present. */ + else if ((!quiet_warnings || flag_code == CODE_64BIT) + && i.types[op].bitfield.reg32 + && (i.tm.operand_types[op].bitfield.reg16 + || i.tm.operand_types[op].bitfield.acc)) + { + /* Prohibit these changes in the 64bit mode, since the + lowering is more complicated. */ + if (flag_code == CODE_64BIT) + { + as_bad (_("incorrect register `%s%s' used with `%c' suffix"), + register_prefix, i.op[op].regs->reg_name, + i.suffix); + return 0; + } +#if REGISTER_WARNINGS + as_warn (_("using `%s%s' instead of `%s%s' due to `%c' suffix"), + register_prefix, + (i.op[op].regs + REGNAM_AX - REGNAM_EAX)->reg_name, + register_prefix, i.op[op].regs->reg_name, i.suffix); +#endif + } + return 1; +} + +static int +update_imm (unsigned int j) +{ + i386_operand_type overlap = i.types[j]; + if ((overlap.bitfield.imm8 + || overlap.bitfield.imm8s + || overlap.bitfield.imm16 + || overlap.bitfield.imm32 + || overlap.bitfield.imm32s + || overlap.bitfield.imm64) + && !operand_type_equal (&overlap, &imm8) + && !operand_type_equal (&overlap, &imm8s) + && !operand_type_equal (&overlap, &imm16) + && !operand_type_equal (&overlap, &imm32) + && !operand_type_equal (&overlap, &imm32s) + && !operand_type_equal (&overlap, &imm64)) + { + if (i.suffix) + { + i386_operand_type temp; + + operand_type_set (&temp, 0); + if (i.suffix == BYTE_MNEM_SUFFIX) + { + temp.bitfield.imm8 = overlap.bitfield.imm8; + temp.bitfield.imm8s = overlap.bitfield.imm8s; + } + else if (i.suffix == WORD_MNEM_SUFFIX) + temp.bitfield.imm16 = overlap.bitfield.imm16; + else if (i.suffix == QWORD_MNEM_SUFFIX) + { + temp.bitfield.imm64 = overlap.bitfield.imm64; + temp.bitfield.imm32s = overlap.bitfield.imm32s; + } + else + temp.bitfield.imm32 = overlap.bitfield.imm32; + overlap = temp; + } + else if (operand_type_equal (&overlap, &imm16_32_32s) + || operand_type_equal (&overlap, &imm16_32) + || operand_type_equal (&overlap, &imm16_32s)) + { + if ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0)) + overlap = imm16; + else + overlap = imm32s; + } + if (!operand_type_equal (&overlap, &imm8) + && !operand_type_equal (&overlap, &imm8s) + && !operand_type_equal (&overlap, &imm16) + && !operand_type_equal (&overlap, &imm32) + && !operand_type_equal (&overlap, &imm32s) + && !operand_type_equal (&overlap, &imm64)) + { + as_bad (_("no instruction mnemonic suffix given; " + "can't determine immediate size")); + return 0; + } + } + i.types[j] = overlap; + + return 1; +} + +static int +finalize_imm (void) +{ + unsigned int j, n; + + /* 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; + + /* The 3rd operand can't be immediate operand. */ + gas_assert (operand_type_check (i.types[2], imm) == 0); + } + + return 1; +} + +static int +bad_implicit_operand (int xmm) +{ + 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, ireg); + else + as_bad (_("the first operand of `%s' must be `%s%s'"), + i.tm.name, register_prefix, ireg); + return 0; +} + +static int +process_operands (void) +{ + /* Default segment register this instruction will use for memory + accesses. 0 means unknown. This is only for optimizing out + unnecessary segment overrides. */ + const seg_entry *default_seg = 0; + + if (i.tm.opcode_modifier.sse2avx && i.tm.opcode_modifier.vexvvvv) + { + 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 > dupl + && operand_type_equal (&i.types[dest], ®xmm)); + + if (i.tm.opcode_modifier.firstxmm0) + { + /* The first operand is implicit and must be xmm0. */ + gas_assert (operand_type_equal (&i.types[0], ®xmm)); + if (register_number (i.op[0].regs) != 0) + return bad_implicit_operand (1); + + if (i.tm.opcode_modifier.vexsources == VEX3SOURCES) + { + /* Keep xmm0 for instructions with VEX prefix and 3 + sources. */ + goto duplicate; + } + else + { + /* We remove the first xmm0 and keep the number of + operands unchanged, which in fact duplicates the + destination. */ + for (j = 1; j < i.operands; j++) + { + i.op[j - 1] = i.op[j]; + i.types[j - 1] = i.types[j]; + i.tm.operand_types[j - 1] = i.tm.operand_types[j]; + } + } + } + else if (i.tm.opcode_modifier.implicit1stxmm0) + { + gas_assert ((MAX_OPERANDS - 1) > dupl + && (i.tm.opcode_modifier.vexsources + == VEX3SOURCES)); + + /* Add the implicit xmm0 for instructions with VEX prefix + and 3 sources. */ + for (j = i.operands; j > 0; j--) + { + i.op[j] = i.op[j - 1]; + i.types[j] = i.types[j - 1]; + i.tm.operand_types[j] = i.tm.operand_types[j - 1]; + } + i.op[0].regs + = (const reg_entry *) hash_find (reg_hash, "xmm0"); + i.types[0] = regxmm; + i.tm.operand_types[0] = regxmm; + + i.operands += 2; + i.reg_operands += 2; + i.tm.operands += 2; + + dupl++; + dest++; + i.op[dupl] = i.op[dest]; + i.types[dupl] = i.types[dest]; + i.tm.operand_types[dupl] = i.tm.operand_types[dest]; + } + else + { +duplicate: + i.operands++; + i.reg_operands++; + i.tm.operands++; + + 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) + process_immext (); + } + else if (i.tm.opcode_modifier.firstxmm0) + { + unsigned int j; + + /* The first operand is implicit and must be xmm0/ymm0/zmm0. */ + gas_assert (i.reg_operands + && (operand_type_equal (&i.types[0], ®xmm) + || operand_type_equal (&i.types[0], ®ymm) + || operand_type_equal (&i.types[0], ®zmm))); + if (register_number (i.op[0].regs) != 0) + return bad_implicit_operand (i.types[0].bitfield.regxmm); + + for (j = 1; j < i.operands; j++) + { + i.op[j - 1] = i.op[j]; + i.types[j - 1] = i.types[j]; + + /* We need to adjust fields in i.tm since they are used by + build_modrm_byte. */ + i.tm.operand_types [j - 1] = i.tm.operand_types [j]; + } + + i.operands--; + i.reg_operands--; + i.tm.operands--; + } + else if (i.tm.opcode_modifier.regkludge) + { + /* The imul $imm, %reg instruction is converted into + imul $imm, %reg, %reg, and the clr %reg instruction + is converted into xor %reg, %reg. */ + + unsigned int first_reg_op; + + if (operand_type_check (i.types[0], reg)) + first_reg_op = 0; + else + first_reg_op = 1; + /* Pretend we saw the extra register operand. */ + gas_assert (i.reg_operands == 1 + && i.op[first_reg_op + 1].regs == 0); + i.op[first_reg_op + 1].regs = i.op[first_reg_op].regs; + i.types[first_reg_op + 1] = i.types[first_reg_op]; + i.operands++; + i.reg_operands++; + } + + if (i.tm.opcode_modifier.shortform) + { + if (i.types[0].bitfield.sreg2 + || i.types[0].bitfield.sreg3) + { + if (i.tm.base_opcode == POP_SEG_SHORT + && i.op[0].regs->reg_num == 1) + { + as_bad (_("you can't `pop %scs'"), register_prefix); + return 0; + } + i.tm.base_opcode |= (i.op[0].regs->reg_num << 3); + if ((i.op[0].regs->reg_flags & RegRex) != 0) + i.rex |= REX_B; + } + else + { + /* The register or float register operand is in operand + 0 or 1. */ + unsigned int op; + + if (i.types[0].bitfield.floatreg + || operand_type_check (i.types[0], reg)) + op = 0; + else + op = 1; + /* Register goes in low 3 bits of opcode. */ + i.tm.base_opcode |= i.op[op].regs->reg_num; + if ((i.op[op].regs->reg_flags & RegRex) != 0) + i.rex |= REX_B; + if (!quiet_warnings && i.tm.opcode_modifier.ugh) + { + /* Warn about some common errors, but press on regardless. + The first case can be generated by gcc (<= 2.8.1). */ + if (i.operands == 2) + { + /* Reversed arguments on faddp, fsubp, etc. */ + as_warn (_("translating to `%s %s%s,%s%s'"), i.tm.name, + register_prefix, i.op[!intel_syntax].regs->reg_name, + register_prefix, i.op[intel_syntax].regs->reg_name); + } + else + { + /* Extraneous `l' suffix on fp insn. */ + as_warn (_("translating to `%s %s%s'"), i.tm.name, + register_prefix, i.op[0].regs->reg_name); + } + } + } + } + else if (i.tm.opcode_modifier.modrm) + { + /* The opcode is completed (modulo i.tm.extension_opcode which + must be put into the modrm byte). Now, we make the modrm and + index base bytes based on all the info we've collected. */ + + default_seg = build_modrm_byte (); + } + else if ((i.tm.base_opcode & ~0x3) == MOV_AX_DISP32) + { + default_seg = &ds; + } + else if (i.tm.opcode_modifier.isstring) + { + /* For the string instructions that allow a segment override + on one of their operands, the default segment is ds. */ + default_seg = &ds; + } + + if (i.tm.base_opcode == 0x8d /* lea */ + && i.seg[0] + && !quiet_warnings) + as_warn (_("segment override on `%s' is ineffectual"), i.tm.name); + + /* If a segment was explicitly specified, and the specified segment + is not the default, use an opcode prefix to select it. If we + never figured out what the default segment is, then default_seg + will be zero at this point, and the specified segment prefix will + always be used. */ + if ((i.seg[0]) && (i.seg[0] != default_seg)) + { + if (!add_prefix (i.seg[0]->seg_prefix)) + return 0; + } + return 1; +} + +static const seg_entry * +build_modrm_byte (void) +{ + const seg_entry *default_seg = 0; + unsigned int source, dest; + int vex_3_sources; + + /* The first operand of instructions with VEX prefix and 3 sources + must be VEX_Imm4. */ + vex_3_sources = i.tm.opcode_modifier.vexsources == VEX3SOURCES; + if (vex_3_sources) + { + 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); + } + else + dest = i.operands - 1; + nds = dest - 1; + + /* 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, YMM or + ZMM 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.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) + || operand_type_equal (&i.tm.operand_types[dest], ®zmm))))); + + 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) + || operand_type_equal (&i.tm.operand_types[reg_slot], + ®zmm)); + exp->X_op = O_constant; + exp->X_add_number = register_number (i.op[reg_slot].regs) << 4; + gas_assert ((i.op[reg_slot].regs->reg_flags & RegVRex) == 0); + } + else + { + 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) + || operand_type_equal (&i.tm.operand_types[reg_slot], + ®zmm)); + i.op[imm_slot].imms->X_add_number + |= register_number (i.op[reg_slot].regs) << 4; + gas_assert ((i.op[reg_slot].regs->reg_flags & RegVRex) == 0); + } + + gas_assert (operand_type_equal (&i.tm.operand_types[nds], ®xmm) + || operand_type_equal (&i.tm.operand_types[nds], + ®ymm) + || operand_type_equal (&i.tm.operand_types[nds], + ®zmm)); + i.vex.register_specifier = i.op[nds].regs; + } + else + source = dest = 0; + + /* i.reg_operands MUST be the number of real register operands; + implicit registers do not count. If there are 3 register + operands, it must be a instruction with VexNDS. For a + instruction with VexNDD, the destination register is encoded + in VEX prefix. If there are 4 register operands, it must be + a instruction with VEX prefix and 3 sources. */ + if (i.mem_operands == 0 + && ((i.reg_operands == 2 + && i.tm.opcode_modifier.vexvvvv <= VEXXDS) + || (i.reg_operands == 3 + && i.tm.opcode_modifier.vexvvvv == VEXXDS) + || (i.reg_operands == 4 && vex_3_sources))) + { + switch (i.operands) + { + case 2: + source = 0; + break; + case 3: + /* When there are 3 operands, one of them may be immediate, + which may be the first or the last operand. Otherwise, + the first operand must be shift count register (cl) or it + is an instruction with VexNDS. */ + gas_assert (i.imm_operands == 1 + || (i.imm_operands == 0 + && (i.tm.opcode_modifier.vexvvvv == VEXXDS + || i.types[0].bitfield.shiftcount))); + if (operand_type_check (i.types[0], imm) + || i.types[0].bitfield.shiftcount) + source = 1; + else + source = 0; + break; + case 4: + /* When there are 4 operands, the first two must be 8bit + immediate operands. The source operand will be the 3rd + one. + + For instructions with VexNDS, if the first operand + an imm8, the source operand is the 2nd one. If the last + operand is imm8, the source operand is the first one. */ + gas_assert ((i.imm_operands == 2 + && i.types[0].bitfield.imm8 + && i.types[1].bitfield.imm8) + || (i.tm.opcode_modifier.vexvvvv == VEXXDS + && i.imm_operands == 1 + && (i.types[0].bitfield.imm8 + || i.types[i.operands - 1].bitfield.imm8 + || i.rounding))); + if (i.imm_operands == 2) + source = 2; + else + { + if (i.types[0].bitfield.imm8) + source = 1; + else + source = 0; + } + break; + case 5: + if (i.tm.opcode_modifier.evex) + { + /* For EVEX instructions, when there are 5 operands, the + first one must be immediate operand. If the second one + is immediate operand, the source operand is the 3th + one. If the last one is immediate operand, the source + operand is the 2nd one. */ + gas_assert (i.imm_operands == 2 + && i.tm.opcode_modifier.sae + && operand_type_check (i.types[0], imm)); + if (operand_type_check (i.types[1], imm)) + source = 2; + else if (operand_type_check (i.types[4], imm)) + source = 1; + else + abort (); + } + break; + default: + abort (); + } + + if (!vex_3_sources) + { + dest = source + 1; + + /* RC/SAE operand could be between DEST and SRC. That happens + when one operand is GPR and the other one is XMM/YMM/ZMM + register. */ + if (i.rounding && i.rounding->operand == (int) dest) + dest++; + + if (i.tm.opcode_modifier.vexvvvv == VEXXDS) + { + /* For instructions with VexNDS, the register-only source + operand must be 32/64bit integer, XMM, YMM or ZMM + 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 + || (op.bitfield.reg32 != 1 + && !op.bitfield.reg64 != 1 + && !operand_type_equal (&op, ®xmm) + && !operand_type_equal (&op, ®ymm) + && !operand_type_equal (&op, ®zmm) + && !operand_type_equal (&op, ®mask))) + abort (); + i.vex.register_specifier = i.op[vvvv].regs; + dest++; + } + } + + i.rm.mode = 3; + /* One of the register operands will be encoded in the i.tm.reg + field, the other in the combined i.tm.mode and i.tm.regmem + fields. If no form of this instruction supports a memory + destination operand, then we assume the source operand may + sometimes be a memory operand and so we need to store the + destination in the i.rm.reg field. */ + if (!i.tm.operand_types[dest].bitfield.regmem + && operand_type_check (i.tm.operand_types[dest], anymem) == 0) + { + i.rm.reg = i.op[dest].regs->reg_num; + i.rm.regmem = i.op[source].regs->reg_num; + if ((i.op[dest].regs->reg_flags & RegRex) != 0) + i.rex |= REX_R; + if ((i.op[dest].regs->reg_flags & RegVRex) != 0) + i.vrex |= REX_R; + if ((i.op[source].regs->reg_flags & RegRex) != 0) + i.rex |= REX_B; + if ((i.op[source].regs->reg_flags & RegVRex) != 0) + i.vrex |= REX_B; + } + else + { + i.rm.reg = i.op[source].regs->reg_num; + i.rm.regmem = i.op[dest].regs->reg_num; + if ((i.op[dest].regs->reg_flags & RegRex) != 0) + i.rex |= REX_B; + if ((i.op[dest].regs->reg_flags & RegVRex) != 0) + i.vrex |= REX_B; + if ((i.op[source].regs->reg_flags & RegRex) != 0) + i.rex |= REX_R; + if ((i.op[source].regs->reg_flags & RegVRex) != 0) + i.vrex |= REX_R; + } + if (flag_code != CODE_64BIT && (i.rex & (REX_R | REX_B))) + { + if (!i.types[0].bitfield.control + && !i.types[1].bitfield.control) + abort (); + i.rex &= ~(REX_R | REX_B); + add_prefix (LOCK_PREFIX_OPCODE); + } + } + else + { /* If it's not 2 reg operands... */ + unsigned int mem; + + if (i.mem_operands) + { + unsigned int fake_zero_displacement = 0; + unsigned int op; + + for (op = 0; op < i.operands; op++) + if (operand_type_check (i.types[op], anymem)) + 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; + /* No Vec_Disp8 if there is no base. */ + i.types[op].bitfield.vec_disp8 = 0; + 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; + if ((i.index_reg->reg_flags & RegVRex) != 0) + i.vrex |= REX_X; + } + + default_seg = &ds; + + if (i.base_reg == 0) + { + i.rm.mode = 0; + if (!i.disp_operands) + { + 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 <disp> */ + if (flag_code == CODE_64BIT) + { + /* 64bit mode overwrites the 32bit absolute + addressing by RIP relative addressing and + absolute addressing is encoded by one of the + redundant SIB forms. */ + i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; + i.sib.base = NO_BASE_REGISTER; + i.sib.index = NO_INDEX_REGISTER; + i.types[op] = ((i.prefix[ADDR_PREFIX] == 0) + ? disp32s : disp32); + } + else if ((flag_code == CODE_16BIT) + ^ (i.prefix[ADDR_PREFIX] != 0)) + { + i.rm.regmem = NO_BASE_REGISTER_16; + i.types[op] = disp16; + } + else + { + i.rm.regmem = NO_BASE_REGISTER; + i.types[op] = disp32; + } + } + 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; + else + i.sib.index = i.index_reg->reg_num; + i.sib.base = NO_BASE_REGISTER; + i.sib.scale = i.log2_scale_factor; + i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; + /* No Vec_Disp8 if there is no base. */ + i.types[op].bitfield.vec_disp8 = 0; + 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; + } + if ((i.index_reg->reg_flags & RegRex) != 0) + i.rex |= REX_X; + } + } + /* RIP addressing for 64bit mode. */ + 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; + i.types[op].bitfield.disp32 = 0; + i.types[op].bitfield.disp32s = 1; + i.types[op].bitfield.disp64 = 0; + i.types[op].bitfield.vec_disp8 = 0; + i.flags[op] |= Operand_PCrel; + if (! i.disp_operands) + fake_zero_displacement = 1; + } + 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) */ + if (i.index_reg == 0) + i.rm.regmem = 7; + else /* (%bx,%si) -> 0, or (%bx,%di) -> 1 */ + i.rm.regmem = i.index_reg->reg_num - 6; + break; + case 5: /* (%bp) */ + default_seg = &ss; + if (i.index_reg == 0) + { + i.rm.regmem = 6; + if (operand_type_check (i.types[op], disp) == 0) + { + /* fake (%bp) into 0(%bp) */ + if (i.tm.operand_types[op].bitfield.vec_disp8) + i.types[op].bitfield.vec_disp8 = 1; + else + i.types[op].bitfield.disp8 = 1; + fake_zero_displacement = 1; + } + } + else /* (%bp,%si) -> 2, or (%bp,%di) -> 3 */ + i.rm.regmem = i.index_reg->reg_num - 6 + 2; + break; + default: /* (%si) -> 4 or (%di) -> 5 */ + i.rm.regmem = i.base_reg->reg_num - 6 + 4; + } + i.rm.mode = mode_from_disp_size (i.types[op]); + } + else /* i.base_reg and 32/64 bit mode */ + { + if (flag_code == CODE_64BIT + && operand_type_check (i.types[op], disp)) + { + i386_operand_type temp; + operand_type_set (&temp, 0); + temp.bitfield.disp8 = i.types[op].bitfield.disp8; + temp.bitfield.vec_disp8 + = i.types[op].bitfield.vec_disp8; + i.types[op] = temp; + if (i.prefix[ADDR_PREFIX] == 0) + i.types[op].bitfield.disp32s = 1; + else + i.types[op].bitfield.disp32 = 1; + } + + 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; + /* x86-64 ignores REX prefix bit here to avoid decoder + complications. */ + if (!(i.base_reg->reg_flags & RegRex) + && (i.base_reg->reg_num == EBP_REG_NUM + || i.base_reg->reg_num == ESP_REG_NUM)) + default_seg = &ss; + if (i.base_reg->reg_num == 5 && i.disp_operands == 0) + { + fake_zero_displacement = 1; + if (i.tm.operand_types [op].bitfield.vec_disp8) + i.types[op].bitfield.vec_disp8 = 1; + else + i.types[op].bitfield.disp8 = 1; + } + i.sib.scale = i.log2_scale_factor; + if (i.index_reg == 0) + { + gas_assert (!i.tm.opcode_modifier.vecsib); + /* <disp>(%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. + Any base register besides %esp will not use the + extra modrm byte. */ + i.sib.index = NO_INDEX_REGISTER; + } + else if (!i.tm.opcode_modifier.vecsib) + { + if (i.index_reg->reg_num == RegEiz + || i.index_reg->reg_num == RegRiz) + i.sib.index = NO_INDEX_REGISTER; + else + i.sib.index = i.index_reg->reg_num; + i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; + if ((i.index_reg->reg_flags & RegRex) != 0) + i.rex |= REX_X; + } + + if (i.disp_operands + && (i.reloc[op] == BFD_RELOC_386_TLS_DESC_CALL + || i.reloc[op] == BFD_RELOC_X86_64_TLSDESC_CALL)) + i.rm.mode = 0; + else + { + if (!fake_zero_displacement + && !i.disp_operands + && i.disp_encoding) + { + fake_zero_displacement = 1; + if (i.disp_encoding == disp_encoding_8bit) + i.types[op].bitfield.disp8 = 1; + else + i.types[op].bitfield.disp32 = 1; + } + i.rm.mode = mode_from_disp_size (i.types[op]); + } + } + + if (fake_zero_displacement) + { + /* Fakes a zero displacement assuming that i.types[op] + holds the correct displacement size. */ + expressionS *exp; + + gas_assert (i.op[op].disps == 0); + exp = &disp_expressions[i.disp_operands++]; + i.op[op].disps = exp; + exp->X_op = O_constant; + exp->X_add_number = 0; + exp->X_add_symbol = (symbolS *) 0; + exp->X_op_symbol = (symbolS *) 0; + } + + mem = op; + } + 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. */ + else if (i.reg_operands) + { + unsigned int op; + unsigned int vex_reg = ~0; + + for (op = 0; op < i.operands; op++) + if (i.types[op].bitfield.reg8 + || i.types[op].bitfield.reg16 + || i.types[op].bitfield.reg32 + || i.types[op].bitfield.reg64 + || i.types[op].bitfield.regmmx + || i.types[op].bitfield.regxmm + || i.types[op].bitfield.regymm + || i.types[op].bitfield.regbnd + || i.types[op].bitfield.regzmm + || i.types[op].bitfield.regmask + || i.types[op].bitfield.sreg2 + || i.types[op].bitfield.sreg3 + || i.types[op].bitfield.control + || i.types[op].bitfield.debug + || i.types[op].bitfield.test) + break; + + if (vex_3_sources) + op = dest; + else if (i.tm.opcode_modifier.vexvvvv == VEXXDS) + { + /* For instructions with VexNDS, the register-only + source operand is encoded in VEX prefix. */ + gas_assert (mem != (unsigned int) ~0); + + if (op > mem) + { + vex_reg = op++; + gas_assert (op < i.operands); + } + else + { + /* 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.vexvvvv == VEXNDD) + { + /* For instructions with VexNDD, the register destination + is encoded in VEX prefix. */ + 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) + { + i386_operand_type *type = &i.tm.operand_types[vex_reg]; + + if (type->bitfield.reg32 != 1 + && type->bitfield.reg64 != 1 + && !operand_type_equal (type, ®xmm) + && !operand_type_equal (type, ®ymm) + && !operand_type_equal (type, ®zmm) + && !operand_type_equal (type, ®mask)) + abort (); + + i.vex.register_specifier = i.op[vex_reg].regs; + } + + /* Don't set OP operand twice. */ + if (vex_reg != op) + { + /* 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; + if ((i.op[op].regs->reg_flags & RegVRex) != 0) + i.vrex |= 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 ((i.op[op].regs->reg_flags & RegVRex) != 0) + i.vrex |= REX_R; + } + } + + /* Now, if no memory operand has set i.rm.mode = 0, 1, 2 we + must set it to 3 to indicate this is a register operand + in the regmem field. */ + if (!i.mem_operands) + i.rm.mode = 3; + } + + /* Fill in i.rm.reg field with extension opcode (if any). */ + if (i.tm.extension_opcode != None) + i.rm.reg = i.tm.extension_opcode; + } + return default_seg; +} + +static void +output_branch (void) +{ + char *p; + int size; + int code16; + int prefix; + relax_substateT subtype; + symbolS *sym; + offsetT off; + + code16 = flag_code == CODE_16BIT ? CODE16 : 0; + size = i.disp_encoding == disp_encoding_32bit ? BIG : SMALL; + + prefix = 0; + if (i.prefix[DATA_PREFIX] != 0) + { + prefix = 1; + i.prefixes -= 1; + code16 ^= CODE16; + } + /* Pentium4 branch hints. */ + if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE /* not taken */ + || i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE /* taken */) + { + prefix++; + i.prefixes--; + } + if (i.prefix[REX_PREFIX] != 0) + { + prefix++; + i.prefixes--; + } + + /* BND prefixed jump. */ + if (i.prefix[BND_PREFIX] != 0) + { + FRAG_APPEND_1_CHAR (i.prefix[BND_PREFIX]); + i.prefixes -= 1; + } + + if (i.prefixes != 0 && !intel_syntax) + as_warn (_("skipping prefixes on this instruction")); + + /* It's always a symbol; End frag & setup for relax. + Make sure there is enough room in this frag for the largest + instruction we may generate in md_convert_frag. This is 2 + bytes for the opcode and room for the prefix and largest + displacement. */ + frag_grow (prefix + 2 + 4); + /* Prefix and 1 opcode byte go in fr_fix. */ + p = frag_more (prefix + 1); + if (i.prefix[DATA_PREFIX] != 0) + *p++ = DATA_PREFIX_OPCODE; + if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE + || i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE) + *p++ = i.prefix[SEG_PREFIX]; + if (i.prefix[REX_PREFIX] != 0) + *p++ = i.prefix[REX_PREFIX]; + *p = i.tm.base_opcode; + + if ((unsigned char) *p == JUMP_PC_RELATIVE) + subtype = ENCODE_RELAX_STATE (UNCOND_JUMP, size); + else if (cpu_arch_flags.bitfield.cpui386) + subtype = ENCODE_RELAX_STATE (COND_JUMP, size); + else + subtype = ENCODE_RELAX_STATE (COND_JUMP86, size); + subtype |= code16; + + sym = i.op[0].disps->X_add_symbol; + off = i.op[0].disps->X_add_number; + + if (i.op[0].disps->X_op != O_constant + && i.op[0].disps->X_op != O_symbol) + { + /* Handle complex expressions. */ + sym = make_expr_symbol (i.op[0].disps); + off = 0; + } + + /* 1 possible extra opcode + 4 byte displacement go in var part. + Pass reloc in fr_var. */ + frag_var (rs_machine_dependent, 5, i.reloc[0], subtype, sym, off, p); +} + +static void +output_jump (void) +{ + char *p; + int size; + fixS *fixP; + + if (i.tm.opcode_modifier.jumpbyte) + { + /* This is a loop or jecxz type instruction. */ + size = 1; + if (i.prefix[ADDR_PREFIX] != 0) + { + FRAG_APPEND_1_CHAR (ADDR_PREFIX_OPCODE); + i.prefixes -= 1; + } + /* Pentium4 branch hints. */ + if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE /* not taken */ + || i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE /* taken */) + { + FRAG_APPEND_1_CHAR (i.prefix[SEG_PREFIX]); + i.prefixes--; + } + } + else + { + int code16; + + code16 = 0; + if (flag_code == CODE_16BIT) + code16 = CODE16; + + if (i.prefix[DATA_PREFIX] != 0) + { + FRAG_APPEND_1_CHAR (DATA_PREFIX_OPCODE); + i.prefixes -= 1; + code16 ^= CODE16; + } + + size = 4; + if (code16) + size = 2; + } + + if (i.prefix[REX_PREFIX] != 0) + { + FRAG_APPEND_1_CHAR (i.prefix[REX_PREFIX]); + i.prefixes -= 1; + } + + /* BND prefixed jump. */ + if (i.prefix[BND_PREFIX] != 0) + { + FRAG_APPEND_1_CHAR (i.prefix[BND_PREFIX]); + i.prefixes -= 1; + } + + if (i.prefixes != 0 && !intel_syntax) + as_warn (_("skipping prefixes on this instruction")); + + p = frag_more (i.tm.opcode_length + size); + switch (i.tm.opcode_length) + { + case 2: + *p++ = i.tm.base_opcode >> 8; + case 1: + *p++ = i.tm.base_opcode; + break; + default: + abort (); + } + + fixP = fix_new_exp (frag_now, p - frag_now->fr_literal, size, + i.op[0].disps, 1, reloc (size, 1, 1, i.reloc[0])); + + /* All jumps handled here are signed, but don't use a signed limit + check for 32 and 16 bit jumps as we want to allow wrap around at + 4G and 64k respectively. */ + if (size == 1) + fixP->fx_signed = 1; +} + +static void +output_interseg_jump (void) +{ + char *p; + int size; + int prefix; + int code16; + + code16 = 0; + if (flag_code == CODE_16BIT) + code16 = CODE16; + + prefix = 0; + if (i.prefix[DATA_PREFIX] != 0) + { + prefix = 1; + i.prefixes -= 1; + code16 ^= CODE16; + } + if (i.prefix[REX_PREFIX] != 0) + { + prefix++; + i.prefixes -= 1; + } + + size = 4; + if (code16) + size = 2; + + if (i.prefixes != 0 && !intel_syntax) + as_warn (_("skipping prefixes on this instruction")); + + /* 1 opcode; 2 segment; offset */ + p = frag_more (prefix + 1 + 2 + size); + + if (i.prefix[DATA_PREFIX] != 0) + *p++ = DATA_PREFIX_OPCODE; + + if (i.prefix[REX_PREFIX] != 0) + *p++ = i.prefix[REX_PREFIX]; + + *p++ = i.tm.base_opcode; + if (i.op[1].imms->X_op == O_constant) + { + offsetT n = i.op[1].imms->X_add_number; + + if (size == 2 + && !fits_in_unsigned_word (n) + && !fits_in_signed_word (n)) + { + as_bad (_("16-bit jump out of range")); + return; + } + md_number_to_chars (p, n, size); + } + else + fix_new_exp (frag_now, p - frag_now->fr_literal, size, + i.op[1].imms, 0, reloc (size, 0, 0, i.reloc[1])); + if (i.op[0].imms->X_op != O_constant) + as_bad (_("can't handle non absolute segment in `%s'"), + i.tm.name); + md_number_to_chars (p + size, (valueT) i.op[0].imms->X_add_number, 2); +} + +static void +output_insn (void) +{ + fragS *insn_start_frag; + offsetT insn_start_off; + + /* Tie dwarf2 debug info to the address at the start of the insn. + We can't do this after the insn has been output as the current + frag may have been closed off. eg. by frag_var. */ + dwarf2_emit_insn (0); + + insn_start_frag = frag_now; + insn_start_off = frag_now_fix (); + + /* Output jumps. */ + if (i.tm.opcode_modifier.jump) + output_branch (); + else if (i.tm.opcode_modifier.jumpbyte + || i.tm.opcode_modifier.jumpdword) + output_jump (); + else if (i.tm.opcode_modifier.jumpintersegment) + output_interseg_jump (); + else + { + /* Output normal instructions here. */ + char *p; + unsigned char *q; + unsigned int j; + unsigned int prefix; + + /* Since the VEX/EVEX prefix contains the implicit prefix, we + don't need the explicit prefix. */ + if (!i.tm.opcode_modifier.vex && !i.tm.opcode_modifier.evex) + { + switch (i.tm.opcode_length) + { + case 3: + if (i.tm.base_opcode & 0xff000000) + { + prefix = (i.tm.base_opcode >> 24) & 0xff; + goto check_prefix; + } + break; + case 2: + if ((i.tm.base_opcode & 0xff0000) != 0) + { + prefix = (i.tm.base_opcode >> 16) & 0xff; + if (i.tm.cpu_flags.bitfield.cpupadlock) + { +check_prefix: + if (prefix != REPE_PREFIX_OPCODE + || (i.prefix[REP_PREFIX] + != REPE_PREFIX_OPCODE)) + add_prefix (prefix); + } + else + add_prefix (prefix); + } + break; + case 1: + break; + default: + abort (); + } + + /* The prefix bytes. */ + for (j = ARRAY_SIZE (i.prefix), q = i.prefix; j > 0; j--, q++) + if (*q) + FRAG_APPEND_1_CHAR (*q); + } + else + { + for (j = 0, q = i.prefix; j < ARRAY_SIZE (i.prefix); j++, q++) + if (*q) + switch (j) + { + case REX_PREFIX: + /* REX byte is encoded in VEX prefix. */ + break; + case SEG_PREFIX: + case ADDR_PREFIX: + FRAG_APPEND_1_CHAR (*q); + break; + default: + /* There should be no other prefixes for instructions + with VEX prefix. */ + abort (); + } + + /* For EVEX instructions i.vrex should become 0 after + build_evex_prefix. For VEX instructions upper 16 registers + aren't available, so VREX should be 0. */ + if (i.vrex) + abort (); + /* Now the VEX prefix. */ + p = frag_more (i.vex.length); + for (j = 0; j < i.vex.length; j++) + p[j] = i.vex.bytes[j]; + } + + /* Now the opcode; be careful about word order here! */ + if (i.tm.opcode_length == 1) + { + FRAG_APPEND_1_CHAR (i.tm.base_opcode); + } + else + { + switch (i.tm.opcode_length) + { + case 4: + p = frag_more (4); + *p++ = (i.tm.base_opcode >> 24) & 0xff; + *p++ = (i.tm.base_opcode >> 16) & 0xff; + break; + case 3: + p = frag_more (3); + *p++ = (i.tm.base_opcode >> 16) & 0xff; + break; + case 2: + p = frag_more (2); + break; + default: + abort (); + break; + } + + /* Put out high byte first: can't use md_number_to_chars! */ + *p++ = (i.tm.base_opcode >> 8) & 0xff; + *p = i.tm.base_opcode & 0xff; + } + + /* Now the modrm byte and sib byte (if present). */ + if (i.tm.opcode_modifier.modrm) + { + FRAG_APPEND_1_CHAR ((i.rm.regmem << 0 + | i.rm.reg << 3 + | i.rm.mode << 6)); + /* If i.rm.regmem == ESP (4) + && i.rm.mode != (Register mode) + && not 16 bit + ==> need second modrm byte. */ + if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING + && i.rm.mode != 3 + && !(i.base_reg && i.base_reg->reg_type.bitfield.reg16)) + FRAG_APPEND_1_CHAR ((i.sib.base << 0 + | i.sib.index << 3 + | i.sib.scale << 6)); + } + + if (i.disp_operands) + output_disp (insn_start_frag, insn_start_off); + + if (i.imm_operands) + output_imm (insn_start_frag, insn_start_off); + } + +#ifdef DEBUG386 + if (flag_debug) + { + pi ("" /*line*/, &i); + } +#endif /* DEBUG386 */ +} + +/* Return the size of the displacement operand N. */ + +static int +disp_size (unsigned int n) +{ + int size = 4; + + /* Vec_Disp8 has to be 8bit. */ + if (i.types[n].bitfield.vec_disp8) + size = 1; + else if (i.types[n].bitfield.disp64) + size = 8; + else if (i.types[n].bitfield.disp8) + size = 1; + else if (i.types[n].bitfield.disp16) + size = 2; + return size; +} + +/* Return the size of the immediate operand N. */ + +static int +imm_size (unsigned int n) +{ + int size = 4; + if (i.types[n].bitfield.imm64) + size = 8; + else if (i.types[n].bitfield.imm8 || i.types[n].bitfield.imm8s) + size = 1; + else if (i.types[n].bitfield.imm16) + size = 2; + return size; +} + +static void +output_disp (fragS *insn_start_frag, offsetT insn_start_off) +{ + char *p; + unsigned int n; + + for (n = 0; n < i.operands; n++) + { + if (i.types[n].bitfield.vec_disp8 + || operand_type_check (i.types[n], disp)) + { + if (i.op[n].disps->X_op == O_constant) + { + int size = disp_size (n); + offsetT val = i.op[n].disps->X_add_number; + + if (i.types[n].bitfield.vec_disp8) + val >>= i.memshift; + val = offset_in_range (val, size); + p = frag_more (size); + md_number_to_chars (p, val, size); + } + else + { + enum bfd_reloc_code_real reloc_type; + int size = disp_size (n); + int sign = i.types[n].bitfield.disp32s; + int pcrel = (i.flags[n] & Operand_PCrel) != 0; + + /* We can't have 8 bit displacement here. */ + gas_assert (!i.types[n].bitfield.disp8); + + /* The PC relative address is computed relative + to the instruction boundary, so in case immediate + fields follows, we need to adjust the value. */ + if (pcrel && i.imm_operands) + { + unsigned int n1; + int sz = 0; + + for (n1 = 0; n1 < i.operands; n1++) + if (operand_type_check (i.types[n1], imm)) + { + /* Only one immediate is allowed for PC + relative address. */ + gas_assert (sz == 0); + sz = imm_size (n1); + i.op[n].disps->X_add_number -= sz; + } + /* We should find the immediate. */ + gas_assert (sz != 0); + } + + p = frag_more (size); + reloc_type = reloc (size, pcrel, sign, i.reloc[n]); + if (GOT_symbol + && GOT_symbol == i.op[n].disps->X_add_symbol + && (((reloc_type == BFD_RELOC_32 + || reloc_type == BFD_RELOC_X86_64_32S + || (reloc_type == BFD_RELOC_64 + && object_64bit)) + && (i.op[n].disps->X_op == O_symbol + || (i.op[n].disps->X_op == O_add + && ((symbol_get_value_expression + (i.op[n].disps->X_op_symbol)->X_op) + == O_subtract)))) + || reloc_type == BFD_RELOC_32_PCREL)) + { + offsetT add; + + if (insn_start_frag == frag_now) + add = (p - frag_now->fr_literal) - insn_start_off; + else + { + fragS *fr; + + add = insn_start_frag->fr_fix - insn_start_off; + for (fr = insn_start_frag->fr_next; + fr && fr != frag_now; fr = fr->fr_next) + add += fr->fr_fix; + add += p - frag_now->fr_literal; + } + + if (!object_64bit) + { + reloc_type = BFD_RELOC_386_GOTPC; + i.op[n].imms->X_add_number += add; + } + else if (reloc_type == BFD_RELOC_64) + reloc_type = BFD_RELOC_X86_64_GOTPC64; + else + /* Don't do the adjustment for x86-64, as there + the pcrel addressing is relative to the _next_ + 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); + } + } + } +} + +static void +output_imm (fragS *insn_start_frag, offsetT insn_start_off) +{ + char *p; + unsigned int n; + + for (n = 0; n < i.operands; n++) + { + /* Skip SAE/RC Imm operand in EVEX. They are already handled. */ + if (i.rounding && (int) n == i.rounding->operand) + continue; + + if (operand_type_check (i.types[n], imm)) + { + if (i.op[n].imms->X_op == O_constant) + { + int size = imm_size (n); + offsetT val; + + val = offset_in_range (i.op[n].imms->X_add_number, + size); + p = frag_more (size); + md_number_to_chars (p, val, size); + } + else + { + /* Not absolute_section. + Need a 32-bit fixup (don't support 8bit + non-absolute imms). Try to support other + sizes ... */ + enum bfd_reloc_code_real reloc_type; + int size = imm_size (n); + int sign; + + if (i.types[n].bitfield.imm32s + && (i.suffix == QWORD_MNEM_SUFFIX + || (!i.suffix && i.tm.opcode_modifier.no_lsuf))) + sign = 1; + else + sign = 0; + + p = frag_more (size); + reloc_type = reloc (size, 0, sign, i.reloc[n]); + + /* This is tough to explain. We end up with this one if we + * have operands that look like + * "_GLOBAL_OFFSET_TABLE_+[.-.L284]". The goal here is to + * obtain the absolute address of the GOT, and it is strongly + * preferable from a performance point of view to avoid using + * a runtime relocation for this. The actual sequence of + * instructions often look something like: + * + * call .L66 + * .L66: + * popl %ebx + * addl $_GLOBAL_OFFSET_TABLE_+[.-.L66],%ebx + * + * The call and pop essentially return the absolute address + * of the label .L66 and store it in %ebx. The linker itself + * will ultimately change the first operand of the addl so + * that %ebx points to the GOT, but to keep things simple, the + * .o file must have this operand set so that it generates not + * the absolute address of .L66, but the absolute address of + * itself. This allows the linker itself simply treat a GOTPC + * relocation as asking for a pcrel offset to the GOT to be + * added in, and the addend of the relocation is stored in the + * operand field for the instruction itself. + * + * Our job here is to fix the operand so that it would add + * the correct offset so that %ebx would point to itself. The + * thing that is tricky is that .-.L66 will point to the + * beginning of the instruction, so we need to further modify + * the operand so that it will point to itself. There are + * other cases where you have something like: + * + * .long $_GLOBAL_OFFSET_TABLE_+[.-.L66] + * + * and here no correction would be required. Internally in + * the assembler we treat operands of this form as not being + * pcrel since the '.' is explicitly mentioned, and I wonder + * whether it would simplify matters to do it this way. Who + * knows. In earlier versions of the PIC patches, the + * pcrel_adjust field was used to store the correction, but + * since the expression is not pcrel, I felt it would be + * confusing to do it this way. */ + + if ((reloc_type == BFD_RELOC_32 + || reloc_type == BFD_RELOC_X86_64_32S + || reloc_type == BFD_RELOC_64) + && GOT_symbol + && GOT_symbol == i.op[n].imms->X_add_symbol + && (i.op[n].imms->X_op == O_symbol + || (i.op[n].imms->X_op == O_add + && ((symbol_get_value_expression + (i.op[n].imms->X_op_symbol)->X_op) + == O_subtract)))) + { + offsetT add; + + if (insn_start_frag == frag_now) + add = (p - frag_now->fr_literal) - insn_start_off; + else + { + fragS *fr; + + add = insn_start_frag->fr_fix - insn_start_off; + for (fr = insn_start_frag->fr_next; + fr && fr != frag_now; fr = fr->fr_next) + add += fr->fr_fix; + add += p - frag_now->fr_literal; + } + + if (!object_64bit) + reloc_type = BFD_RELOC_386_GOTPC; + else if (size == 4) + reloc_type = BFD_RELOC_X86_64_GOTPC32; + else if (size == 8) + reloc_type = BFD_RELOC_X86_64_GOTPC64; + i.op[n].imms->X_add_number += add; + } + fix_new_exp (frag_now, p - frag_now->fr_literal, size, + i.op[n].imms, 0, reloc_type); + } + } + } +} + +/* x86_cons_fix_new is called via the expression parsing code when a + reloc is needed. We use this hook to get the correct .got reloc. */ +static enum bfd_reloc_code_real got_reloc = NO_RELOC; +static int cons_sign = -1; + +void +x86_cons_fix_new (fragS *frag, unsigned int off, unsigned int len, + expressionS *exp) +{ + enum bfd_reloc_code_real r = reloc (len, 0, cons_sign, got_reloc); + + got_reloc = NO_RELOC; + +#ifdef TE_PE + if (exp->X_op == O_secrel) + { + exp->X_op = O_symbol; + r = BFD_RELOC_32_SECREL; + } +#endif + + fix_new_exp (frag, off, len, exp, 0, r); +} + +/* Export the ABI address size for use by TC_ADDRESS_BYTES for the + purpose of the `.dc.a' internal pseudo-op. */ + +int +x86_address_bytes (void) +{ + if ((stdoutput->arch_info->mach & bfd_mach_x64_32)) + return 4; + return stdoutput->arch_info->bits_per_address / 8; +} + +#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 + <symbol>@GOTOFF+<nnn> + and similar .plt or .got references. + + If we find one, set up the correct relocation in RELOC and copy the + input string, minus the `@GOTOFF' into a malloc'd buffer for + parsing by the calling routine. Return this buffer, and if ADJUST + 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 *rel, + int *adjust, + i386_operand_type *types) +{ + /* Some of the relocations depend on the size of what field is to + be relocated. But in our callers i386_immediate and i386_displacement + we don't yet know the operand size (this will be set by insn + matching). Hence we record the word32 relocation here, + 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[] = { +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + { STRING_COMMA_LEN ("SIZE"), { BFD_RELOC_SIZE32, + BFD_RELOC_SIZE32 }, + OPERAND_TYPE_IMM32_64 }, +#endif + { STRING_COMMA_LEN ("PLTOFF"), { _dummy_first_bfd_reloc_code_real, + BFD_RELOC_X86_64_PLTOFF64 }, + OPERAND_TYPE_IMM64 }, + { STRING_COMMA_LEN ("PLT"), { BFD_RELOC_386_PLT32, + BFD_RELOC_X86_64_PLT32 }, + OPERAND_TYPE_IMM32_32S_DISP32 }, + { STRING_COMMA_LEN ("GOTPLT"), { _dummy_first_bfd_reloc_code_real, + BFD_RELOC_X86_64_GOTPLT64 }, + OPERAND_TYPE_IMM64_DISP64 }, + { STRING_COMMA_LEN ("GOTOFF"), { BFD_RELOC_386_GOTOFF, + BFD_RELOC_X86_64_GOTOFF64 }, + OPERAND_TYPE_IMM64_DISP64 }, + { STRING_COMMA_LEN ("GOTPCREL"), { _dummy_first_bfd_reloc_code_real, + BFD_RELOC_X86_64_GOTPCREL }, + OPERAND_TYPE_IMM32_32S_DISP32 }, + { STRING_COMMA_LEN ("TLSGD"), { BFD_RELOC_386_TLS_GD, + BFD_RELOC_X86_64_TLSGD }, + OPERAND_TYPE_IMM32_32S_DISP32 }, + { STRING_COMMA_LEN ("TLSLDM"), { BFD_RELOC_386_TLS_LDM, + _dummy_first_bfd_reloc_code_real }, + OPERAND_TYPE_NONE }, + { STRING_COMMA_LEN ("TLSLD"), { _dummy_first_bfd_reloc_code_real, + BFD_RELOC_X86_64_TLSLD }, + OPERAND_TYPE_IMM32_32S_DISP32 }, + { STRING_COMMA_LEN ("GOTTPOFF"), { BFD_RELOC_386_TLS_IE_32, + BFD_RELOC_X86_64_GOTTPOFF }, + OPERAND_TYPE_IMM32_32S_DISP32 }, + { STRING_COMMA_LEN ("TPOFF"), { BFD_RELOC_386_TLS_LE_32, + BFD_RELOC_X86_64_TPOFF32 }, + OPERAND_TYPE_IMM32_32S_64_DISP32_64 }, + { STRING_COMMA_LEN ("NTPOFF"), { BFD_RELOC_386_TLS_LE, + _dummy_first_bfd_reloc_code_real }, + OPERAND_TYPE_NONE }, + { STRING_COMMA_LEN ("DTPOFF"), { BFD_RELOC_386_TLS_LDO_32, + BFD_RELOC_X86_64_DTPOFF32 }, + OPERAND_TYPE_IMM32_32S_64_DISP32_64 }, + { STRING_COMMA_LEN ("GOTNTPOFF"),{ BFD_RELOC_386_TLS_GOTIE, + _dummy_first_bfd_reloc_code_real }, + OPERAND_TYPE_NONE }, + { STRING_COMMA_LEN ("INDNTPOFF"),{ BFD_RELOC_386_TLS_IE, + _dummy_first_bfd_reloc_code_real }, + OPERAND_TYPE_NONE }, + { STRING_COMMA_LEN ("GOT"), { BFD_RELOC_386_GOT32, + BFD_RELOC_X86_64_GOT32 }, + OPERAND_TYPE_IMM32_32S_64_DISP32 }, + { STRING_COMMA_LEN ("TLSDESC"), { BFD_RELOC_386_TLS_GOTDESC, + BFD_RELOC_X86_64_GOTPC32_TLSDESC }, + OPERAND_TYPE_IMM32_32S_DISP32 }, + { 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 == ',') + return NULL; + + for (j = 0; j < ARRAY_SIZE (gotrel); j++) + { + int len = gotrel[j].len; + if (strncasecmp (cp + 1, gotrel[j].str, len) == 0) + { + if (gotrel[j].rel[object_64bit] != 0) + { + int first, second; + char *tmpbuf, *past_reloc; + + *rel = gotrel[j].rel[object_64bit]; + + if (types) + { + if (flag_code != CODE_64BIT) + { + types->bitfield.imm32 = 1; + types->bitfield.disp32 = 1; + } + else + *types = gotrel[j].types64; + } + + if (j != 0 && GOT_symbol == NULL) + GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME); + + /* The length of the first part of our input line. */ + first = cp - input_line_pointer; + + /* The second part goes from after the reloc token until + (and including) an end_of_line char or comma. */ + past_reloc = cp + 1 + len; + cp = past_reloc; + while (!is_end_of_line[(unsigned char) *cp] && *cp != ',') + ++cp; + second = cp + 1 - past_reloc; + + /* Allocate and copy string. The trailing NUL shouldn't + be necessary, but be safe. */ + tmpbuf = (char *) xmalloc (first + second + 2); + memcpy (tmpbuf, input_line_pointer, first); + if (second != 0 && *past_reloc != ' ') + /* Replace the relocation token with ' ', so that + errors like foo@GOTOFF1 will be detected. */ + tmpbuf[first++] = ' '; + else + /* Increment length by 1 if the relocation token is + removed. */ + len++; + if (adjust) + *adjust = len; + memcpy (tmpbuf + first, past_reloc, second); + tmpbuf[first + second] = '\0'; + return tmpbuf; + } + + as_bad (_("@%s reloc is not supported with %d-bit output format"), + gotrel[j].str, 1 << (5 + object_64bit)); + return NULL; + } + } + + /* Might be a symbol version string. Don't as_bad here. */ + return NULL; +} +#endif + +#ifdef TE_PE +#ifdef lex_got +#undef lex_got +#endif +/* Parse operands of the form + <symbol>@SECREL32+<nnn> + + If we find one, set up the correct relocation in RELOC and copy the + input string, minus the `@SECREL32' into a malloc'd buffer for + parsing by the calling routine. Return this buffer, and if ADJUST + is non-null set it to the length of the string we removed from the + input line. Otherwise return NULL. + + This function is copied from the ELF version above adjusted for PE targets. */ + +static char * +lex_got (enum bfd_reloc_code_real *rel ATTRIBUTE_UNUSED, + int *adjust ATTRIBUTE_UNUSED, + i386_operand_type *types ATTRIBUTE_UNUSED) +{ + static const struct + { + const char *str; + int len; + const enum bfd_reloc_code_real rel[2]; + const i386_operand_type types64; + } + gotrel[] = + { + { STRING_COMMA_LEN ("SECREL32"), { BFD_RELOC_32_SECREL, + BFD_RELOC_32_SECREL }, + OPERAND_TYPE_IMM32_32S_64_DISP32_64 }, + }; + + char *cp; + unsigned j; + + for (cp = input_line_pointer; *cp != '@'; cp++) + if (is_end_of_line[(unsigned char) *cp] || *cp == ',') + return NULL; + + for (j = 0; j < ARRAY_SIZE (gotrel); j++) + { + int len = gotrel[j].len; + + if (strncasecmp (cp + 1, gotrel[j].str, len) == 0) + { + if (gotrel[j].rel[object_64bit] != 0) + { + int first, second; + char *tmpbuf, *past_reloc; + + *rel = gotrel[j].rel[object_64bit]; + if (adjust) + *adjust = len; + + if (types) + { + if (flag_code != CODE_64BIT) + { + types->bitfield.imm32 = 1; + types->bitfield.disp32 = 1; + } + else + *types = gotrel[j].types64; + } + + /* The length of the first part of our input line. */ + first = cp - input_line_pointer; + + /* The second part goes from after the reloc token until + (and including) an end_of_line char or comma. */ + past_reloc = cp + 1 + len; + cp = past_reloc; + while (!is_end_of_line[(unsigned char) *cp] && *cp != ',') + ++cp; + second = cp + 1 - past_reloc; + + /* Allocate and copy string. The trailing NUL shouldn't + be necessary, but be safe. */ + tmpbuf = (char *) xmalloc (first + second + 2); + memcpy (tmpbuf, input_line_pointer, first); + if (second != 0 && *past_reloc != ' ') + /* Replace the relocation token with ' ', so that + errors like foo@SECLREL321 will be detected. */ + tmpbuf[first++] = ' '; + memcpy (tmpbuf + first, past_reloc, second); + tmpbuf[first + second] = '\0'; + return tmpbuf; + } + + as_bad (_("@%s reloc is not supported with %d-bit output format"), + gotrel[j].str, 1 << (5 + object_64bit)); + return NULL; + } + } + + /* Might be a symbol version string. Don't as_bad here. */ + return NULL; +} + +#endif /* TE_PE */ + +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 = 0; + + save = input_line_pointer; + gotfree_input_line = lex_got (&got_reloc, &adjust, NULL); + if (gotfree_input_line) + input_line_pointer = gotfree_input_line; + + expression (exp); + + if (gotfree_input_line) + { + /* expression () has merrily parsed up to the end of line, + or a comma - in the wrong buffer. Transfer how far + input_line_pointer has moved to the right buffer. */ + input_line_pointer = (save + + (input_line_pointer - gotfree_input_line) + + adjust); + free (gotfree_input_line); + if (exp->X_op == O_constant + || exp->X_op == O_absent + || exp->X_op == O_illegal + || exp->X_op == O_register + || exp->X_op == O_big) + { + char c = *input_line_pointer; + *input_line_pointer = 0; + as_bad (_("missing or invalid expression `%s'"), save); + *input_line_pointer = c; + } + } + } + else + expression (exp); + + intel_syntax = -intel_syntax; + + if (intel_syntax) + i386_intel_simplify (exp); +} + +static void +signed_cons (int size) +{ + if (flag_code == CODE_64BIT) + cons_sign = 1; + cons (size); + cons_sign = -1; +} + +#ifdef TE_PE +static void +pe_directive_secrel (int dummy ATTRIBUTE_UNUSED) +{ + expressionS exp; + + do + { + expression (&exp); + if (exp.X_op == O_symbol) + exp.X_op = O_secrel; + + emit_expr (&exp, 4); + } + while (*input_line_pointer++ == ','); + + input_line_pointer--; + demand_empty_rest_of_line (); +} +#endif + +/* Handle Vector operations. */ + +static char * +check_VecOperations (char *op_string, char *op_end) +{ + const reg_entry *mask; + const char *saved; + char *end_op; + + while (*op_string + && (op_end == NULL || op_string < op_end)) + { + saved = op_string; + if (*op_string == '{') + { + op_string++; + + /* Check broadcasts. */ + if (strncmp (op_string, "1to", 3) == 0) + { + int bcst_type; + + if (i.broadcast) + goto duplicated_vec_op; + + op_string += 3; + if (*op_string == '8') + bcst_type = BROADCAST_1TO8; + else if (*op_string == '1' + && *(op_string+1) == '6') + { + bcst_type = BROADCAST_1TO16; + op_string++; + } + else + { + as_bad (_("Unsupported broadcast: `%s'"), saved); + return NULL; + } + op_string++; + + broadcast_op.type = bcst_type; + broadcast_op.operand = this_operand; + i.broadcast = &broadcast_op; + } + /* Check masking operation. */ + else if ((mask = parse_register (op_string, &end_op)) != NULL) + { + /* k0 can't be used for write mask. */ + if (mask->reg_num == 0) + { + as_bad (_("`%s' can't be used for write mask"), + op_string); + return NULL; + } + + if (!i.mask) + { + mask_op.mask = mask; + mask_op.zeroing = 0; + mask_op.operand = this_operand; + i.mask = &mask_op; + } + else + { + if (i.mask->mask) + goto duplicated_vec_op; + + i.mask->mask = mask; + + /* Only "{z}" is allowed here. No need to check + zeroing mask explicitly. */ + if (i.mask->operand != this_operand) + { + as_bad (_("invalid write mask `%s'"), saved); + return NULL; + } + } + + op_string = end_op; + } + /* Check zeroing-flag for masking operation. */ + else if (*op_string == 'z') + { + if (!i.mask) + { + mask_op.mask = NULL; + mask_op.zeroing = 1; + mask_op.operand = this_operand; + i.mask = &mask_op; + } + else + { + if (i.mask->zeroing) + { + duplicated_vec_op: + as_bad (_("duplicated `%s'"), saved); + return NULL; + } + + i.mask->zeroing = 1; + + /* Only "{%k}" is allowed here. No need to check mask + register explicitly. */ + if (i.mask->operand != this_operand) + { + as_bad (_("invalid zeroing-masking `%s'"), + saved); + return NULL; + } + } + + op_string++; + } + else + goto unknown_vec_op; + + if (*op_string != '}') + { + as_bad (_("missing `}' in `%s'"), saved); + return NULL; + } + op_string++; + continue; + } + unknown_vec_op: + /* We don't know this one. */ + as_bad (_("unknown vector operation: `%s'"), saved); + return NULL; + } + + return op_string; +} + +static int +i386_immediate (char *imm_start) +{ + char *save_input_line_pointer; + char *gotfree_input_line; + segT exp_seg = 0; + expressionS *exp; + i386_operand_type types; + + operand_type_set (&types, ~0); + + if (i.imm_operands == MAX_IMMEDIATE_OPERANDS) + { + as_bad (_("at most %d immediate operands are allowed"), + MAX_IMMEDIATE_OPERANDS); + return 0; + } + + exp = &im_expressions[i.imm_operands++]; + i.op[this_operand].imms = exp; + + if (is_space_char (*imm_start)) + ++imm_start; + + save_input_line_pointer = input_line_pointer; + input_line_pointer = imm_start; + + gotfree_input_line = lex_got (&i.reloc[this_operand], NULL, &types); + if (gotfree_input_line) + input_line_pointer = gotfree_input_line; + + exp_seg = expression (exp); + + SKIP_WHITESPACE (); + + /* Handle vector operations. */ + if (*input_line_pointer == '{') + { + input_line_pointer = check_VecOperations (input_line_pointer, + NULL); + if (input_line_pointer == NULL) + return 0; + } + + if (*input_line_pointer) + as_bad (_("junk `%s' after expression"), input_line_pointer); + + input_line_pointer = save_input_line_pointer; + if (gotfree_input_line) + { + free (gotfree_input_line); + + if (exp->X_op == O_constant || exp->X_op == O_register) + exp->X_op = O_illegal; + } + + return i386_finalize_immediate (exp_seg, exp, types, imm_start); +} + +static int +i386_finalize_immediate (segT exp_seg ATTRIBUTE_UNUSED, expressionS *exp, + i386_operand_type types, const char *imm_start) +{ + if (exp->X_op == O_absent || exp->X_op == O_illegal || exp->X_op == O_big) + { + 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 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); + } +#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT)) + else if (OUTPUT_FLAVOR == bfd_target_aout_flavour + && exp_seg != absolute_section + && exp_seg != text_section + && exp_seg != data_section + && exp_seg != bss_section + && exp_seg != undefined_section + && !bfd_is_com_section (exp_seg)) + { + as_bad (_("unimplemented segment %s in operand"), exp_seg->name); + return 0; + } +#endif + else if (!intel_syntax && exp->X_op == O_register) + { + if (imm_start) + as_bad (_("illegal immediate register operand %s"), imm_start); + return 0; + } + else + { + /* This is an address. The size of the address will be + determined later, depending on destination register, + suffix, or the default for the section. */ + i.types[this_operand].bitfield.imm8 = 1; + i.types[this_operand].bitfield.imm16 = 1; + i.types[this_operand].bitfield.imm32 = 1; + i.types[this_operand].bitfield.imm32s = 1; + i.types[this_operand].bitfield.imm64 = 1; + i.types[this_operand] = operand_type_and (i.types[this_operand], + types); + } + + return 1; +} + +static char * +i386_scale (char *scale) +{ + offsetT val; + char *save = input_line_pointer; + + input_line_pointer = scale; + val = get_absolute_expression (); + + switch (val) + { + case 1: + i.log2_scale_factor = 0; + break; + case 2: + i.log2_scale_factor = 1; + break; + case 4: + i.log2_scale_factor = 2; + break; + case 8: + i.log2_scale_factor = 3; + break; + default: + { + char sep = *input_line_pointer; + + *input_line_pointer = '\0'; + as_bad (_("expecting scale factor of 1, 2, 4, or 8: got `%s'"), + scale); + *input_line_pointer = sep; + input_line_pointer = save; + return NULL; + } + } + if (i.log2_scale_factor != 0 && i.index_reg == 0) + { + as_warn (_("scale factor of %d without an index register"), + 1 << i.log2_scale_factor); + i.log2_scale_factor = 0; + } + scale = input_line_pointer; + input_line_pointer = save; + return scale; +} + +static int +i386_displacement (char *disp_start, char *disp_end) +{ + expressionS *exp; + segT exp_seg = 0; + char *save_input_line_pointer; + char *gotfree_input_line; + int override; + i386_operand_type bigdisp, types = anydisp; + int ret; + + if (i.disp_operands == MAX_MEMORY_OPERANDS) + { + as_bad (_("at most %d displacement operands are allowed"), + MAX_MEMORY_OPERANDS); + return 0; + } + + operand_type_set (&bigdisp, 0); + if ((i.types[this_operand].bitfield.jumpabsolute) + || (!current_templates->start->opcode_modifier.jump + && !current_templates->start->opcode_modifier.jumpdword)) + { + bigdisp.bitfield.disp32 = 1; + override = (i.prefix[ADDR_PREFIX] != 0); + if (flag_code == CODE_64BIT) + { + if (!override) + { + bigdisp.bitfield.disp32s = 1; + bigdisp.bitfield.disp64 = 1; + } + } + else if ((flag_code == CODE_16BIT) ^ override) + { + bigdisp.bitfield.disp32 = 0; + bigdisp.bitfield.disp16 = 1; + } + } + else + { + /* For PC-relative branches, the width of the displacement + is dependent upon data size, not address size. */ + override = (i.prefix[DATA_PREFIX] != 0); + if (flag_code == CODE_64BIT) + { + if (override || i.suffix == WORD_MNEM_SUFFIX) + bigdisp.bitfield.disp16 = 1; + else + { + bigdisp.bitfield.disp32 = 1; + bigdisp.bitfield.disp32s = 1; + } + } + else + { + if (!override) + override = (i.suffix == (flag_code != CODE_16BIT + ? WORD_MNEM_SUFFIX + : LONG_MNEM_SUFFIX)); + bigdisp.bitfield.disp32 = 1; + if ((flag_code == CODE_16BIT) ^ override) + { + bigdisp.bitfield.disp32 = 0; + bigdisp.bitfield.disp16 = 1; + } + } + } + i.types[this_operand] = operand_type_or (i.types[this_operand], + bigdisp); + + exp = &disp_expressions[i.disp_operands]; + i.op[this_operand].disps = exp; + i.disp_operands++; + save_input_line_pointer = input_line_pointer; + input_line_pointer = disp_start; + END_STRING_AND_SAVE (disp_end); + +#ifndef GCC_ASM_O_HACK +#define GCC_ASM_O_HACK 0 +#endif +#if GCC_ASM_O_HACK + END_STRING_AND_SAVE (disp_end + 1); + if (i.types[this_operand].bitfield.baseIndex + && displacement_string_end[-1] == '+') + { + /* This hack is to avoid a warning when using the "o" + constraint within gcc asm statements. + For instance: + + #define _set_tssldt_desc(n,addr,limit,type) \ + __asm__ __volatile__ ( \ + "movw %w2,%0\n\t" \ + "movw %w1,2+%0\n\t" \ + "rorl $16,%1\n\t" \ + "movb %b1,4+%0\n\t" \ + "movb %4,5+%0\n\t" \ + "movb $0,6+%0\n\t" \ + "movb %h1,7+%0\n\t" \ + "rorl $16,%1" \ + : "=o"(*(n)) : "q" (addr), "ri"(limit), "i"(type)) + + This works great except that the output assembler ends + up looking a bit weird if it turns out that there is + no offset. You end up producing code that looks like: + + #APP + movw $235,(%eax) + movw %dx,2+(%eax) + rorl $16,%edx + movb %dl,4+(%eax) + movb $137,5+(%eax) + movb $0,6+(%eax) + movb %dh,7+(%eax) + rorl $16,%edx + #NO_APP + + So here we provide the missing zero. */ + + *displacement_string_end = '0'; + } +#endif + gotfree_input_line = lex_got (&i.reloc[this_operand], NULL, &types); + if (gotfree_input_line) + input_line_pointer = gotfree_input_line; + + exp_seg = expression (exp); + + SKIP_WHITESPACE (); + if (*input_line_pointer) + as_bad (_("junk `%s' after expression"), input_line_pointer); +#if GCC_ASM_O_HACK + RESTORE_END_STRING (disp_end + 1); +#endif + input_line_pointer = save_input_line_pointer; + if (gotfree_input_line) + { + free (gotfree_input_line); + + if (exp->X_op == O_constant || exp->X_op == O_register) + exp->X_op = O_illegal; + } + + ret = i386_finalize_displacement (exp_seg, exp, types, disp_start); + + RESTORE_END_STRING (disp_end); + + return ret; +} + +static int +i386_finalize_displacement (segT exp_seg ATTRIBUTE_UNUSED, expressionS *exp, + i386_operand_type types, const char *disp_start) +{ + i386_operand_type bigdisp; + int ret = 1; + + /* We do this to make sure that the section symbol is in + the symbol table. We will ultimately change the relocation + to be relative to the beginning of the section. */ + if (i.reloc[this_operand] == BFD_RELOC_386_GOTOFF + || i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL + || i.reloc[this_operand] == BFD_RELOC_X86_64_GOTOFF64) + { + if (exp->X_op != O_symbol) + 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) != expr_section) + section_symbol (S_GET_SEGMENT (exp->X_add_symbol)); + exp->X_op = O_subtract; + exp->X_op_symbol = GOT_symbol; + if (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL) + i.reloc[this_operand] = BFD_RELOC_32_PCREL; + else if (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTOFF64) + i.reloc[this_operand] = BFD_RELOC_64; + else + i.reloc[this_operand] = BFD_RELOC_32; + } + + else if (exp->X_op == O_absent + || exp->X_op == O_illegal + || exp->X_op == O_big) + { + inv_disp: + as_bad (_("missing or invalid displacement expression `%s'"), + disp_start); + 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 + && exp_seg != absolute_section + && exp_seg != text_section + && exp_seg != data_section + && exp_seg != bss_section + && exp_seg != undefined_section + && !bfd_is_com_section (exp_seg)) + { + as_bad (_("unimplemented segment %s in operand"), exp_seg->name); + ret = 0; + } +#endif + + /* Check if this is a displacement only operand. */ + bigdisp = i.types[this_operand]; + bigdisp.bitfield.disp8 = 0; + bigdisp.bitfield.disp16 = 0; + bigdisp.bitfield.disp32 = 0; + bigdisp.bitfield.disp32s = 0; + bigdisp.bitfield.disp64 = 0; + if (operand_type_all_zero (&bigdisp)) + i.types[this_operand] = operand_type_and (i.types[this_operand], + types); + + return ret; +} + +/* Make sure the memory operand we've been dealt is valid. + Return 1 on success, 0 on a failure. */ + +static int +i386_index_check (const char *operand_string) +{ + const char *kind = "base/index"; + enum flag_code addr_mode; + + if (i.prefix[ADDR_PREFIX]) + addr_mode = flag_code == CODE_32BIT ? CODE_16BIT : CODE_32BIT; + else + { + addr_mode = flag_code; + +#if INFER_ADDR_PREFIX + if (i.mem_operands == 0) + { + /* Infer address prefix from the first memory operand. */ + const reg_entry *addr_reg = i.base_reg; + + if (addr_reg == NULL) + addr_reg = i.index_reg; + + if (addr_reg) + { + if (addr_reg->reg_num == RegEip + || addr_reg->reg_num == RegEiz + || addr_reg->reg_type.bitfield.reg32) + addr_mode = CODE_32BIT; + else if (flag_code != CODE_64BIT + && addr_reg->reg_type.bitfield.reg16) + addr_mode = CODE_16BIT; + + if (addr_mode != flag_code) + { + i.prefix[ADDR_PREFIX] = ADDR_PREFIX_OPCODE; + i.prefixes += 1; + /* Change the size of any displacement too. At most one + of Disp16 or Disp32 is set. + FIXME. There doesn't seem to be any real need for + separate Disp16 and Disp32 flags. The same goes for + Imm16 and Imm32. Removing them would probably clean + up the code quite a lot. */ + if (flag_code != CODE_64BIT + && (i.types[this_operand].bitfield.disp16 + || i.types[this_operand].bitfield.disp32)) + i.types[this_operand] + = operand_type_xor (i.types[this_operand], disp16_32); + } + } + } +#endif + } + + if (current_templates->start->opcode_modifier.isstring + && !current_templates->start->opcode_modifier.immext + && (current_templates->end[-1].opcode_modifier.isstring + || i.mem_operands)) + { + /* Memory operands of string insns are special in that they only allow + a single register (rDI, rSI, or rBX) as their memory address. */ + const reg_entry *expected_reg; + static const char *di_si[][2] = + { + { "esi", "edi" }, + { "si", "di" }, + { "rsi", "rdi" } + }; + static const char *bx[] = { "ebx", "bx", "rbx" }; + + kind = "string address"; + + if (current_templates->start->opcode_modifier.w) + { + i386_operand_type type = current_templates->end[-1].operand_types[0]; + + if (!type.bitfield.baseindex + || ((!i.mem_operands != !intel_syntax) + && current_templates->end[-1].operand_types[1] + .bitfield.baseindex)) + type = current_templates->end[-1].operand_types[1]; + expected_reg = hash_find (reg_hash, + di_si[addr_mode][type.bitfield.esseg]); + + } + else + expected_reg = hash_find (reg_hash, bx[addr_mode]); + + if (i.base_reg != expected_reg + || i.index_reg + || operand_type_check (i.types[this_operand], disp)) + { + /* The second memory operand must have the same size as + the first one. */ + if (i.mem_operands + && i.base_reg + && !((addr_mode == CODE_64BIT + && i.base_reg->reg_type.bitfield.reg64) + || (addr_mode == CODE_32BIT + ? i.base_reg->reg_type.bitfield.reg32 + : i.base_reg->reg_type.bitfield.reg16))) + goto bad_address; + + as_warn (_("`%s' is not valid here (expected `%c%s%s%c')"), + operand_string, + intel_syntax ? '[' : '(', + register_prefix, + expected_reg->reg_name, + intel_syntax ? ']' : ')'); + return 1; + } + else + return 1; + +bad_address: + as_bad (_("`%s' is not a valid %s expression"), + operand_string, kind); + return 0; + } + else + { + if (addr_mode != CODE_16BIT) + { + /* 32-bit/64-bit checks. */ + if ((i.base_reg + && (addr_mode == CODE_64BIT + ? !i.base_reg->reg_type.bitfield.reg64 + : !i.base_reg->reg_type.bitfield.reg32) + && (i.index_reg + || (i.base_reg->reg_num + != (addr_mode == CODE_64BIT ? 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.regzmm + && ((addr_mode == CODE_64BIT + ? !(i.index_reg->reg_type.bitfield.reg64 + || i.index_reg->reg_num == RegRiz) + : !(i.index_reg->reg_type.bitfield.reg32 + || i.index_reg->reg_num == RegEiz)) + || !i.index_reg->reg_type.bitfield.baseindex))) + goto bad_address; + } + else + { + /* 16-bit checks. */ + if ((i.base_reg + && (!i.base_reg->reg_type.bitfield.reg16 + || !i.base_reg->reg_type.bitfield.baseindex)) + || (i.index_reg + && (!i.index_reg->reg_type.bitfield.reg16 + || !i.index_reg->reg_type.bitfield.baseindex + || !(i.base_reg + && i.base_reg->reg_num < 6 + && i.index_reg->reg_num >= 6 + && i.log2_scale_factor == 0)))) + goto bad_address; + } + } + return 1; +} + +/* Handle vector immediates. */ + +static int +RC_SAE_immediate (const char *imm_start) +{ + unsigned int match_found, j; + const char *pstr = imm_start; + expressionS *exp; + + if (*pstr != '{') + return 0; + + pstr++; + match_found = 0; + for (j = 0; j < ARRAY_SIZE (RC_NamesTable); j++) + { + if (!strncmp (pstr, RC_NamesTable[j].name, RC_NamesTable[j].len)) + { + if (!i.rounding) + { + rc_op.type = RC_NamesTable[j].type; + rc_op.operand = this_operand; + i.rounding = &rc_op; + } + else + { + as_bad (_("duplicated `%s'"), imm_start); + return 0; + } + pstr += RC_NamesTable[j].len; + match_found = 1; + break; + } + } + if (!match_found) + return 0; + + if (*pstr++ != '}') + { + as_bad (_("Missing '}': '%s'"), imm_start); + return 0; + } + /* RC/SAE immediate string should contain nothing more. */; + if (*pstr != 0) + { + as_bad (_("Junk after '}': '%s'"), imm_start); + return 0; + } + + exp = &im_expressions[i.imm_operands++]; + i.op[this_operand].imms = exp; + + exp->X_op = O_constant; + exp->X_add_number = 0; + exp->X_add_symbol = (symbolS *) 0; + exp->X_op_symbol = (symbolS *) 0; + + i.types[this_operand].bitfield.imm8 = 1; + return 1; +} + +/* Parse OPERAND_STRING into the i386_insn structure I. Returns zero + on error. */ + +static int +i386_att_operand (char *operand_string) +{ + const reg_entry *r; + char *end_op; + char *op_string = operand_string; + + if (is_space_char (*op_string)) + ++op_string; + + /* We check for an absolute prefix (differentiating, + for example, 'jmp pc_relative_label' from 'jmp *absolute_label'. */ + if (*op_string == ABSOLUTE_PREFIX) + { + ++op_string; + if (is_space_char (*op_string)) + ++op_string; + i.types[this_operand].bitfield.jumpabsolute = 1; + } + + /* Check if operand is a register. */ + if ((r = parse_register (op_string, &end_op)) != NULL) + { + i386_operand_type temp; + + /* Check for a segment override by searching for ':' after a + segment register. */ + op_string = end_op; + if (is_space_char (*op_string)) + ++op_string; + if (*op_string == ':' + && (r->reg_type.bitfield.sreg2 + || r->reg_type.bitfield.sreg3)) + { + switch (r->reg_num) + { + case 0: + i.seg[i.mem_operands] = &es; + break; + case 1: + i.seg[i.mem_operands] = &cs; + break; + case 2: + i.seg[i.mem_operands] = &ss; + break; + case 3: + i.seg[i.mem_operands] = &ds; + break; + case 4: + i.seg[i.mem_operands] = &fs; + break; + case 5: + i.seg[i.mem_operands] = &gs; + break; + } + + /* Skip the ':' and whitespace. */ + ++op_string; + if (is_space_char (*op_string)) + ++op_string; + + if (!is_digit_char (*op_string) + && !is_identifier_char (*op_string) + && *op_string != '(' + && *op_string != ABSOLUTE_PREFIX) + { + as_bad (_("bad memory operand `%s'"), op_string); + return 0; + } + /* Handle case of %es:*foo. */ + if (*op_string == ABSOLUTE_PREFIX) + { + ++op_string; + if (is_space_char (*op_string)) + ++op_string; + i.types[this_operand].bitfield.jumpabsolute = 1; + } + goto do_memory_reference; + } + + /* Handle vector operations. */ + if (*op_string == '{') + { + op_string = check_VecOperations (op_string, NULL); + if (op_string == NULL) + return 0; + } + + if (*op_string) + { + as_bad (_("junk `%s' after register"), op_string); + return 0; + } + temp = r->reg_type; + temp.bitfield.baseindex = 0; + i.types[this_operand] = operand_type_or (i.types[this_operand], + temp); + i.types[this_operand].bitfield.unspecified = 0; + i.op[this_operand].regs = r; + i.reg_operands++; + } + else if (*op_string == REGISTER_PREFIX) + { + as_bad (_("bad register name `%s'"), op_string); + return 0; + } + else if (*op_string == IMMEDIATE_PREFIX) + { + ++op_string; + if (i.types[this_operand].bitfield.jumpabsolute) + { + as_bad (_("immediate operand illegal with absolute jump")); + return 0; + } + if (!i386_immediate (op_string)) + return 0; + } + else if (RC_SAE_immediate (operand_string)) + { + /* If it is a RC or SAE immediate, do nothing. */ + ; + } + else if (is_digit_char (*op_string) + || is_identifier_char (*op_string) + || *op_string == '(') + { + /* This is a memory reference of some sort. */ + char *base_string; + + /* Start and end of displacement string expression (if found). */ + char *displacement_string_start; + char *displacement_string_end; + char *vop_start; + + do_memory_reference: + if ((i.mem_operands == 1 + && !current_templates->start->opcode_modifier.isstring) + || i.mem_operands == 2) + { + as_bad (_("too many memory references for `%s'"), + current_templates->start->name); + return 0; + } + + /* Check for base index form. We detect the base index form by + looking for an ')' at the end of the operand, searching + for the '(' matching it, and finding a REGISTER_PREFIX or ',' + after the '('. */ + base_string = op_string + strlen (op_string); + + /* Handle vector operations. */ + vop_start = strchr (op_string, '{'); + if (vop_start && vop_start < base_string) + { + if (check_VecOperations (vop_start, base_string) == NULL) + return 0; + base_string = vop_start; + } + + --base_string; + if (is_space_char (*base_string)) + --base_string; + + /* If we only have a displacement, set-up for it to be parsed later. */ + displacement_string_start = op_string; + displacement_string_end = base_string + 1; + + if (*base_string == ')') + { + char *temp_string; + unsigned int parens_balanced = 1; + /* We've already checked that the number of left & right ()'s are + equal, so this loop will not be infinite. */ + do + { + base_string--; + if (*base_string == ')') + parens_balanced++; + if (*base_string == '(') + parens_balanced--; + } + while (parens_balanced); + + temp_string = base_string; + + /* Skip past '(' and whitespace. */ + ++base_string; + if (is_space_char (*base_string)) + ++base_string; + + if (*base_string == ',' + || ((i.base_reg = parse_register (base_string, &end_op)) + != NULL)) + { + displacement_string_end = temp_string; + + i.types[this_operand].bitfield.baseindex = 1; + + if (i.base_reg) + { + base_string = end_op; + if (is_space_char (*base_string)) + ++base_string; + } + + /* There may be an index reg or scale factor here. */ + if (*base_string == ',') + { + ++base_string; + if (is_space_char (*base_string)) + ++base_string; + + if ((i.index_reg = parse_register (base_string, &end_op)) + != NULL) + { + base_string = end_op; + if (is_space_char (*base_string)) + ++base_string; + if (*base_string == ',') + { + ++base_string; + if (is_space_char (*base_string)) + ++base_string; + } + else if (*base_string != ')') + { + as_bad (_("expecting `,' or `)' " + "after index register in `%s'"), + operand_string); + return 0; + } + } + else if (*base_string == REGISTER_PREFIX) + { + end_op = strchr (base_string, ','); + if (end_op) + *end_op = '\0'; + as_bad (_("bad register name `%s'"), base_string); + return 0; + } + + /* Check for scale factor. */ + if (*base_string != ')') + { + char *end_scale = i386_scale (base_string); + + if (!end_scale) + return 0; + + base_string = end_scale; + if (is_space_char (*base_string)) + ++base_string; + if (*base_string != ')') + { + as_bad (_("expecting `)' " + "after scale factor in `%s'"), + operand_string); + return 0; + } + } + else if (!i.index_reg) + { + as_bad (_("expecting index register or scale factor " + "after `,'; got '%c'"), + *base_string); + return 0; + } + } + else if (*base_string != ')') + { + as_bad (_("expecting `,' or `)' " + "after base register in `%s'"), + operand_string); + return 0; + } + } + else if (*base_string == REGISTER_PREFIX) + { + end_op = strchr (base_string, ','); + if (end_op) + *end_op = '\0'; + as_bad (_("bad register name `%s'"), base_string); + return 0; + } + } + + /* If there's an expression beginning the operand, parse it, + assuming displacement_string_start and + displacement_string_end are meaningful. */ + if (displacement_string_start != displacement_string_end) + { + if (!i386_displacement (displacement_string_start, + displacement_string_end)) + return 0; + } + + /* Special case for (%dx) while doing input/output op. */ + if (i.base_reg + && operand_type_equal (&i.base_reg->reg_type, + ®16_inoutportreg) + && i.index_reg == 0 + && i.log2_scale_factor == 0 + && i.seg[i.mem_operands] == 0 + && !operand_type_check (i.types[this_operand], disp)) + { + i.types[this_operand] = inoutportreg; + return 1; + } + + if (i386_index_check (operand_string) == 0) + return 0; + i.types[this_operand].bitfield.mem = 1; + i.mem_operands++; + } + else + { + /* It's not a memory operand; argh! */ + as_bad (_("invalid char %s beginning operand %d `%s'"), + output_invalid (*op_string), + this_operand + 1, + op_string); + return 0; + } + return 1; /* Normal return. */ +} + +/* Calculate the maximum variable size (i.e., excluding fr_fix) + that an rs_machine_dependent frag may reach. */ + +unsigned int +i386_frag_max_var (fragS *frag) +{ + /* The only relaxable frags are for jumps. + Unconditional jumps can grow by 4 bytes and others by 5 bytes. */ + gas_assert (frag->fr_type == rs_machine_dependent); + return TYPE_FROM_RELAX_STATE (frag->fr_subtype) == UNCOND_JUMP ? 4 : 5; +} + +/* md_estimate_size_before_relax() + + Called just before relax() for rs_machine_dependent frags. The x86 + assembler uses these frags to handle variable size jump + instructions. + + Any symbol that is now undefined will not become defined. + Return the correct fr_subtype in the frag. + Return the initial "guess for variable size of frag" to caller. + The guess is actually the growth beyond the fixed part. Whatever + we do to grow the fixed or variable part contributes to our + returned value. */ + +int +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 + an externally visible symbol, because it may be overridden by a + shared library. */ + 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)))) +#endif +#if defined (OBJ_COFF) && defined (TE_PE) + || (OUTPUT_FLAVOR == bfd_target_coff_flavour + && S_IS_WEAK (fragP->fr_symbol)) +#endif + ) + { + /* Symbol is undefined in this segment, or we need to keep a + reloc so that weak symbols can be overridden. */ + int size = (fragP->fr_subtype & CODE16) ? 2 : 4; + enum bfd_reloc_code_real reloc_type; + unsigned char *opcode; + int old_fr_fix; + + if (fragP->fr_var != NO_RELOC) + reloc_type = (enum bfd_reloc_code_real) fragP->fr_var; + else if (size == 2) + reloc_type = BFD_RELOC_16_PCREL; + else + reloc_type = BFD_RELOC_32_PCREL; + + old_fr_fix = fragP->fr_fix; + opcode = (unsigned char *) fragP->fr_opcode; + + switch (TYPE_FROM_RELAX_STATE (fragP->fr_subtype)) + { + case UNCOND_JUMP: + /* Make jmp (0xeb) a (d)word displacement jump. */ + opcode[0] = 0xe9; + fragP->fr_fix += size; + fix_new (fragP, old_fr_fix, size, + fragP->fr_symbol, + fragP->fr_offset, 1, + reloc_type); + break; + + case COND_JUMP86: + if (size == 2 + && (!no_cond_jump_promotion || fragP->fr_var != NO_RELOC)) + { + /* Negate the condition, and branch past an + unconditional jump. */ + opcode[0] ^= 1; + opcode[1] = 3; + /* Insert an unconditional jump. */ + opcode[2] = 0xe9; + /* We added two extra opcode bytes, and have a two byte + offset. */ + fragP->fr_fix += 2 + 2; + fix_new (fragP, old_fr_fix + 2, 2, + fragP->fr_symbol, + fragP->fr_offset, 1, + reloc_type); + break; + } + /* Fall through. */ + + case COND_JUMP: + if (no_cond_jump_promotion && fragP->fr_var == NO_RELOC) + { + fixS *fixP; + + fragP->fr_fix += 1; + fixP = fix_new (fragP, old_fr_fix, 1, + fragP->fr_symbol, + fragP->fr_offset, 1, + BFD_RELOC_8_PCREL); + fixP->fx_signed = 1; + break; + } + + /* This changes the byte-displacement jump 0x7N + to the (d)word-displacement jump 0x0f,0x8N. */ + opcode[1] = opcode[0] + 0x10; + opcode[0] = TWO_BYTE_OPCODE_ESCAPE; + /* We've added an opcode byte. */ + fragP->fr_fix += 1 + size; + fix_new (fragP, old_fr_fix + 1, size, + fragP->fr_symbol, + fragP->fr_offset, 1, + reloc_type); + break; + + default: + BAD_CASE (fragP->fr_subtype); + break; + } + frag_wane (fragP); + return fragP->fr_fix - old_fr_fix; + } + + /* Guess size depending on current relax state. Initially the relax + state will correspond to a short jump and we return 1, because + the variable part of the frag (the branch offset) is one byte + long. However, we can relax a section more than once and in that + case we must either set fr_subtype back to the unrelaxed state, + or return the value for the appropriate branch. */ + return md_relax_table[fragP->fr_subtype].rlx_length; +} + +/* Called after relax() is finished. + + In: Address of frag. + fr_type == rs_machine_dependent. + fr_subtype is what the address relaxed to. + + Out: Any fixSs and constants are set up. + Caller will turn frag into a ".space 0". */ + +void +md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec ATTRIBUTE_UNUSED, + fragS *fragP) +{ + unsigned char *opcode; + unsigned char *where_to_put_displacement = NULL; + offsetT target_address; + offsetT opcode_address; + unsigned int extension = 0; + offsetT displacement_from_opcode_start; + + opcode = (unsigned char *) fragP->fr_opcode; + + /* Address we want to reach in file space. */ + target_address = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset; + + /* Address opcode resides at in file space. */ + opcode_address = fragP->fr_address + fragP->fr_fix; + + /* Displacement from opcode start to fill into instruction. */ + displacement_from_opcode_start = target_address - opcode_address; + + if ((fragP->fr_subtype & BIG) == 0) + { + /* Don't have to change opcode. */ + extension = 1; /* 1 opcode + 1 displacement */ + where_to_put_displacement = &opcode[1]; + } + else + { + if (no_cond_jump_promotion + && TYPE_FROM_RELAX_STATE (fragP->fr_subtype) != UNCOND_JUMP) + as_warn_where (fragP->fr_file, fragP->fr_line, + _("long jump required")); + + switch (fragP->fr_subtype) + { + case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG): + extension = 4; /* 1 opcode + 4 displacement */ + opcode[0] = 0xe9; + where_to_put_displacement = &opcode[1]; + break; + + case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG16): + extension = 2; /* 1 opcode + 2 displacement */ + opcode[0] = 0xe9; + where_to_put_displacement = &opcode[1]; + break; + + case ENCODE_RELAX_STATE (COND_JUMP, BIG): + case ENCODE_RELAX_STATE (COND_JUMP86, BIG): + extension = 5; /* 2 opcode + 4 displacement */ + opcode[1] = opcode[0] + 0x10; + opcode[0] = TWO_BYTE_OPCODE_ESCAPE; + where_to_put_displacement = &opcode[2]; + break; + + case ENCODE_RELAX_STATE (COND_JUMP, BIG16): + extension = 3; /* 2 opcode + 2 displacement */ + opcode[1] = opcode[0] + 0x10; + opcode[0] = TWO_BYTE_OPCODE_ESCAPE; + where_to_put_displacement = &opcode[2]; + break; + + case ENCODE_RELAX_STATE (COND_JUMP86, BIG16): + extension = 4; + opcode[0] ^= 1; + opcode[1] = 3; + opcode[2] = 0xe9; + where_to_put_displacement = &opcode[3]; + break; + + default: + BAD_CASE (fragP->fr_subtype); + break; + } + } + + /* If size if less then four we are sure that the operand fits, + but if it's 4, then it could be that the displacement is larger + then -/+ 2GB. */ + if (DISP_SIZE_FROM_RELAX_STATE (fragP->fr_subtype) == 4 + && object_64bit + && ((addressT) (displacement_from_opcode_start - extension + + ((addressT) 1 << 31)) + > (((addressT) 2 << 31) - 1))) + { + as_bad_where (fragP->fr_file, fragP->fr_line, + _("jump target out of range")); + /* Make us emit 0. */ + displacement_from_opcode_start = extension; + } + /* Now put displacement after opcode. */ + md_number_to_chars ((char *) where_to_put_displacement, + (valueT) (displacement_from_opcode_start - extension), + DISP_SIZE_FROM_RELAX_STATE (fragP->fr_subtype)); + fragP->fr_fix += extension; +} + +/* 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 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) +{ + char *p = fixP->fx_where + fixP->fx_frag->fr_literal; + valueT value = *valP; + +#if !defined (TE_Mach) + if (fixP->fx_pcrel) + { + switch (fixP->fx_r_type) + { + default: + break; + + case BFD_RELOC_64: + fixP->fx_r_type = BFD_RELOC_64_PCREL; + break; + case BFD_RELOC_32: + case BFD_RELOC_X86_64_32S: + fixP->fx_r_type = BFD_RELOC_32_PCREL; + break; + case BFD_RELOC_16: + fixP->fx_r_type = BFD_RELOC_16_PCREL; + break; + case BFD_RELOC_8: + fixP->fx_r_type = BFD_RELOC_8_PCREL; + break; + } + } + + if (fixP->fx_addsy != NULL + && (fixP->fx_r_type == BFD_RELOC_32_PCREL + || fixP->fx_r_type == BFD_RELOC_64_PCREL + || fixP->fx_r_type == BFD_RELOC_16_PCREL + || fixP->fx_r_type == BFD_RELOC_8_PCREL) + && !use_rela_relocations) + { + /* This is a hack. There should be a better way to handle this. + This covers for the fact that bfd_install_relocation will + subtract the current location (for partial_inplace, PC relative + relocations); see more below. */ +#ifndef OBJ_AOUT + if (IS_ELF +#ifdef TE_PE + || OUTPUT_FLAVOR == bfd_target_coff_flavour +#endif + ) + value += fixP->fx_where + fixP->fx_frag->fr_address; +#endif +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + if (IS_ELF) + { + segT sym_seg = S_GET_SEGMENT (fixP->fx_addsy); + + if ((sym_seg == seg + || (symbol_section_p (fixP->fx_addsy) + && sym_seg != absolute_section)) + && !generic_force_reloc (fixP)) + { + /* Yes, we add the values in twice. This is because + bfd_install_relocation subtracts them out again. I think + bfd_install_relocation is broken, but I don't dare change + it. FIXME. */ + value += fixP->fx_where + fixP->fx_frag->fr_address; + } + } +#endif +#if defined (OBJ_COFF) && defined (TE_PE) + /* For some reason, the PE format does not store a + section address offset for a PC relative symbol. */ + if (S_GET_SEGMENT (fixP->fx_addsy) != seg + || S_IS_WEAK (fixP->fx_addsy)) + value += md_pcrel_from (fixP); +#endif + } +#if defined (OBJ_COFF) && defined (TE_PE) + if (fixP->fx_addsy != NULL && S_IS_WEAK (fixP->fx_addsy)) + { + value -= S_GET_VALUE (fixP->fx_addsy); + } +#endif + + /* Fix a few things - the dynamic linker expects certain values here, + and we must not disappoint it. */ +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + if (IS_ELF && fixP->fx_addsy) + switch (fixP->fx_r_type) + { + case BFD_RELOC_386_PLT32: + case BFD_RELOC_X86_64_PLT32: + /* Make the jump instruction point to the address of the operand. At + runtime we merely add the offset to the actual PLT entry. */ + value = -4; + break; + + case BFD_RELOC_386_TLS_GD: + case BFD_RELOC_386_TLS_LDM: + case BFD_RELOC_386_TLS_IE_32: + case BFD_RELOC_386_TLS_IE: + case BFD_RELOC_386_TLS_GOTIE: + case BFD_RELOC_386_TLS_GOTDESC: + case BFD_RELOC_X86_64_TLSGD: + case BFD_RELOC_X86_64_TLSLD: + case BFD_RELOC_X86_64_GOTTPOFF: + case BFD_RELOC_X86_64_GOTPC32_TLSDESC: + value = 0; /* Fully resolved at runtime. No addend. */ + /* Fallthrough */ + case BFD_RELOC_386_TLS_LE: + case BFD_RELOC_386_TLS_LDO_32: + case BFD_RELOC_386_TLS_LE_32: + case BFD_RELOC_X86_64_DTPOFF32: + case BFD_RELOC_X86_64_DTPOFF64: + case BFD_RELOC_X86_64_TPOFF32: + case BFD_RELOC_X86_64_TPOFF64: + S_SET_THREAD_LOCAL (fixP->fx_addsy); + break; + + case BFD_RELOC_386_TLS_DESC_CALL: + case BFD_RELOC_X86_64_TLSDESC_CALL: + value = 0; /* Fully resolved at runtime. No addend. */ + S_SET_THREAD_LOCAL (fixP->fx_addsy); + fixP->fx_done = 0; + return; + + case BFD_RELOC_386_GOT32: + case BFD_RELOC_X86_64_GOT32: + value = 0; /* Fully resolved at runtime. No addend. */ + break; + + case BFD_RELOC_VTABLE_INHERIT: + case BFD_RELOC_VTABLE_ENTRY: + fixP->fx_done = 0; + return; + + default: + break; + } +#endif /* defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) */ + *valP = value; +#endif /* !defined (TE_Mach) */ + + /* Are we finished with this relocation now? */ + if (fixP->fx_addsy == NULL) + fixP->fx_done = 1; +#if defined (OBJ_COFF) && defined (TE_PE) + else if (fixP->fx_addsy != NULL && S_IS_WEAK (fixP->fx_addsy)) + { + fixP->fx_done = 0; + /* Remember value for tc_gen_reloc. */ + fixP->fx_addnumber = value; + /* Clear out the frag for now. */ + value = 0; + } +#endif + else if (use_rela_relocations) + { + fixP->fx_no_overflow = 1; + /* Remember value for tc_gen_reloc. */ + fixP->fx_addnumber = value; + value = 0; + } + + md_number_to_chars (p, value, fixP->fx_size); +} + +char * +md_atof (int type, char *litP, int *sizeP) +{ + /* This outputs the LITTLENUMs in REVERSE order; + in accord with the bigendian 386. */ + return ieee_md_atof (type, litP, sizeP, FALSE); +} + +static char output_invalid_buf[sizeof (unsigned char) * 2 + 6]; + +static char * +output_invalid (int c) +{ + if (ISPRINT (c)) + snprintf (output_invalid_buf, sizeof (output_invalid_buf), + "'%c'", c); + else + snprintf (output_invalid_buf, sizeof (output_invalid_buf), + "(0x%x)", (unsigned char) c); + return output_invalid_buf; +} + +/* REG_STRING starts *before* REGISTER_PREFIX. */ + +static const reg_entry * +parse_real_register (char *reg_string, char **end_op) +{ + char *s = reg_string; + char *p; + char reg_name_given[MAX_REG_NAME_SIZE + 1]; + const reg_entry *r; + + /* Skip possible REGISTER_PREFIX and possible whitespace. */ + if (*s == REGISTER_PREFIX) + ++s; + + if (is_space_char (*s)) + ++s; + + p = reg_name_given; + while ((*p++ = register_chars[(unsigned char) *s]) != '\0') + { + if (p >= reg_name_given + MAX_REG_NAME_SIZE) + return (const reg_entry *) NULL; + s++; + } + + /* For naked regs, make sure that we are not dealing with an identifier. + This prevents confusing an identifier like `eax_var' with register + `eax'. */ + if (allow_naked_reg && identifier_chars[(unsigned char) *s]) + return (const reg_entry *) NULL; + + *end_op = s; + + r = (const reg_entry *) hash_find (reg_hash, reg_name_given); + + /* Handle floating point regs, allowing spaces in the (i) part. */ + if (r == i386_regtab /* %st is first entry of table */) + { + if (is_space_char (*s)) + ++s; + if (*s == '(') + { + ++s; + if (is_space_char (*s)) + ++s; + if (*s >= '0' && *s <= '7') + { + int fpr = *s - '0'; + ++s; + if (is_space_char (*s)) + ++s; + if (*s == ')') + { + *end_op = s + 1; + r = (const reg_entry *) hash_find (reg_hash, "st(0)"); + know (r); + return r + fpr; + } + } + /* We have "%st(" then garbage. */ + return (const reg_entry *) NULL; + } + } + + if (r == NULL || allow_pseudo_reg) + return r; + + if (operand_type_all_zero (&r->reg_type)) + return (const reg_entry *) NULL; + + if ((r->reg_type.bitfield.reg32 + || r->reg_type.bitfield.sreg3 + || r->reg_type.bitfield.control + || r->reg_type.bitfield.debug + || r->reg_type.bitfield.test) + && !cpu_arch_flags.bitfield.cpui386) + return (const reg_entry *) NULL; + + if (r->reg_type.bitfield.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; + + if (r->reg_type.bitfield.regxmm && !cpu_arch_flags.bitfield.cpusse) + return (const reg_entry *) NULL; + + if (r->reg_type.bitfield.regymm && !cpu_arch_flags.bitfield.cpuavx) + return (const reg_entry *) NULL; + + if ((r->reg_type.bitfield.regzmm || r->reg_type.bitfield.regmask) + && !cpu_arch_flags.bitfield.cpuavx512f) + return (const reg_entry *) NULL; + + /* Don't allow fake index register unless allow_index_reg isn't 0. */ + if (!allow_index_reg + && (r->reg_num == RegEiz || r->reg_num == RegRiz)) + return (const reg_entry *) NULL; + + /* Upper 16 vector register is only available with VREX in 64bit + mode. */ + if ((r->reg_flags & RegVRex)) + { + if (!cpu_arch_flags.bitfield.cpuvrex + || flag_code != CODE_64BIT) + return (const reg_entry *) NULL; + + i.need_vrex = 1; + } + + if (((r->reg_flags & (RegRex64 | RegRex)) + || r->reg_type.bitfield.reg64) + && (!cpu_arch_flags.bitfield.cpulm + || !operand_type_equal (&r->reg_type, &control)) + && flag_code != CODE_64BIT) + return (const reg_entry *) NULL; + + if (r->reg_type.bitfield.sreg3 && r->reg_num == RegFlat && !intel_syntax) + return (const reg_entry *) NULL; + + return r; +} + +/* REG_STRING starts *before* REGISTER_PREFIX. */ + +static const reg_entry * +parse_register (char *reg_string, char **end_op) +{ + const reg_entry *r; + + if (*reg_string == REGISTER_PREFIX || allow_naked_reg) + r = parse_real_register (reg_string, end_op); + else + r = NULL; + if (!r) + { + char *save = input_line_pointer; + char c; + symbolS *symbolP; + + input_line_pointer = reg_string; + c = get_symbol_end (); + symbolP = symbol_find (reg_string); + if (symbolP && S_GET_SEGMENT (symbolP) == reg_section) + { + const expressionS *e = symbol_get_value_expression (symbolP); + + know (e->X_op == O_register); + know (e->X_add_number >= 0 + && (valueT) e->X_add_number < i386_regtab_size); + r = i386_regtab + e->X_add_number; + *end_op = input_line_pointer; + } + *input_line_pointer = c; + input_line_pointer = save; + } + return r; +} + +int +i386_parse_name (char *name, expressionS *e, char *nextcharP) +{ + const reg_entry *r; + char *end = input_line_pointer; + + *end = *nextcharP; + r = parse_register (name, &input_line_pointer); + if (r && end <= input_line_pointer) + { + *nextcharP = *input_line_pointer; + *input_line_pointer = 0; + e->X_op = O_register; + e->X_add_number = r - i386_regtab; + return 1; + } + input_line_pointer = end; + *end = 0; + return intel_syntax ? i386_intel_parse_name (name, e) : 0; +} + +void +md_operand (expressionS *e) +{ + char *end; + const reg_entry *r; + + switch (*input_line_pointer) + { + case REGISTER_PREFIX: + r = parse_real_register (input_line_pointer, &end); + if (r) + { + e->X_op = O_register; + e->X_add_number = r - i386_regtab; + input_line_pointer = end; + } + break; + + case '[': + gas_assert (intel_syntax); + end = input_line_pointer++; + expression (e); + if (*input_line_pointer == ']') + { + ++input_line_pointer; + e->X_op_symbol = make_expr_symbol (e); + e->X_add_symbol = NULL; + e->X_add_number = 0; + e->X_op = O_index; + } + else + { + e->X_op = O_absent; + input_line_pointer = end; + } + break; + } +} + + +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) +const char *md_shortopts = "kVQ:sqn"; +#else +const char *md_shortopts = "qn"; +#endif + +#define OPTION_32 (OPTION_MD_BASE + 0) +#define OPTION_64 (OPTION_MD_BASE + 1) +#define OPTION_DIVIDE (OPTION_MD_BASE + 2) +#define OPTION_MARCH (OPTION_MD_BASE + 3) +#define OPTION_MTUNE (OPTION_MD_BASE + 4) +#define OPTION_MMNEMONIC (OPTION_MD_BASE + 5) +#define OPTION_MSYNTAX (OPTION_MD_BASE + 6) +#define OPTION_MINDEX_REG (OPTION_MD_BASE + 7) +#define OPTION_MNAKED_REG (OPTION_MD_BASE + 8) +#define OPTION_MOLD_GCC (OPTION_MD_BASE + 9) +#define OPTION_MSSE2AVX (OPTION_MD_BASE + 10) +#define OPTION_MSSE_CHECK (OPTION_MD_BASE + 11) +#define OPTION_MOPERAND_CHECK (OPTION_MD_BASE + 12) +#define OPTION_MAVXSCALAR (OPTION_MD_BASE + 13) +#define OPTION_X32 (OPTION_MD_BASE + 14) +#define OPTION_MADD_BND_PREFIX (OPTION_MD_BASE + 15) +#define OPTION_MEVEXLIG (OPTION_MD_BASE + 16) +#define OPTION_MEVEXWIG (OPTION_MD_BASE + 17) + +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 (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}, + {"mtune", required_argument, NULL, OPTION_MTUNE}, + {"mmnemonic", required_argument, NULL, OPTION_MMNEMONIC}, + {"msyntax", required_argument, NULL, OPTION_MSYNTAX}, + {"mindex-reg", no_argument, NULL, OPTION_MINDEX_REG}, + {"mnaked-reg", no_argument, NULL, OPTION_MNAKED_REG}, + {"mold-gcc", no_argument, NULL, OPTION_MOLD_GCC}, + {"msse2avx", no_argument, NULL, OPTION_MSSE2AVX}, + {"msse-check", required_argument, NULL, OPTION_MSSE_CHECK}, + {"moperand-check", required_argument, NULL, OPTION_MOPERAND_CHECK}, + {"mavxscalar", required_argument, NULL, OPTION_MAVXSCALAR}, + {"madd-bnd-prefix", no_argument, NULL, OPTION_MADD_BND_PREFIX}, + {"mevexlig", required_argument, NULL, OPTION_MEVEXLIG}, + {"mevexwig", required_argument, NULL, OPTION_MEVEXWIG}, + {NULL, no_argument, NULL, 0} +}; +size_t md_longopts_size = sizeof (md_longopts); + +int +md_parse_option (int c, char *arg) +{ + unsigned int j; + char *arch, *next; + + switch (c) + { + case 'n': + optimize_align_code = 0; + break; + + case 'q': + quiet_warnings = 1; + break; + +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + /* -Qy, -Qn: SVR4 arguments controlling whether a .comment section + should be emitted or not. FIXME: Not implemented. */ + case 'Q': + break; + + /* -V: SVR4 argument to print version ID. */ + case 'V': + print_version_id (); + break; + + /* -k: Ignore for FreeBSD compatibility. */ + case 'k': + break; + + case 's': + /* -s: On i386 Solaris, this tells the native assembler to use + .stab instead of .stab.excl. We always use .stab anyhow. */ + break; +#endif +#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \ + || defined (TE_PE) || defined (TE_PEP) || defined (OBJ_MACH_O)) + case OPTION_64: + { + const char **list, **l; + + list = bfd_target_list (); + for (l = list; *l != NULL; l++) + 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, "mach-o-x86-64") == 0) + { + default_arch = "x86_64"; + break; + } + if (*l == NULL) + 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; + + case OPTION_DIVIDE: +#ifdef SVR4_COMMENT_CHARS + { + char *n, *t; + const char *s; + + n = (char *) xmalloc (strlen (i386_comment_chars) + 1); + t = n; + for (s = i386_comment_chars; *s != '\0'; s++) + if (*s != '/') + *t++ = *s; + *t = '\0'; + i386_comment_chars = n; + } +#endif + break; + + case OPTION_MARCH: + arch = xstrdup (arg); + do + { + if (*arch == '.') + as_fatal (_("invalid -march= option: `%s'"), arg); + next = strchr (arch, '+'); + if (next) + *next++ = '\0'; + for (j = 0; j < ARRAY_SIZE (cpu_arch); j++) + { + if (strcmp (arch, cpu_arch [j].name) == 0) + { + /* Processor. */ + 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[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; + cpu_arch_tune_flags = cpu_arch_isa_flags; + } + break; + } + else if (*cpu_arch [j].name == '.' + && strcmp (arch, cpu_arch [j].name + 1) == 0) + { + /* ISA entension. */ + i386_cpu_flags 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[j].name, + (const char *) NULL); + free (name); + } + else + cpu_sub_arch_name = xstrdup (cpu_arch[j].name); + cpu_arch_flags = flags; + cpu_arch_isa_flags = flags; + } + break; + } + } + + if (j >= ARRAY_SIZE (cpu_arch)) + as_fatal (_("invalid -march= option: `%s'"), arg); + + arch = next; + } + while (next != NULL ); + break; + + case OPTION_MTUNE: + if (*arg == '.') + as_fatal (_("invalid -mtune= option: `%s'"), arg); + for (j = 0; j < ARRAY_SIZE (cpu_arch); j++) + { + if (strcmp (arg, cpu_arch [j].name) == 0) + { + cpu_arch_tune_set = 1; + cpu_arch_tune = cpu_arch [j].type; + cpu_arch_tune_flags = cpu_arch[j].flags; + break; + } + } + if (j >= ARRAY_SIZE (cpu_arch)) + as_fatal (_("invalid -mtune= option: `%s'"), arg); + break; + + case OPTION_MMNEMONIC: + if (strcasecmp (arg, "att") == 0) + intel_mnemonic = 0; + else if (strcasecmp (arg, "intel") == 0) + intel_mnemonic = 1; + else + as_fatal (_("invalid -mmnemonic= option: `%s'"), arg); + break; + + case OPTION_MSYNTAX: + if (strcasecmp (arg, "att") == 0) + intel_syntax = 0; + else if (strcasecmp (arg, "intel") == 0) + intel_syntax = 1; + else + as_fatal (_("invalid -msyntax= option: `%s'"), arg); + break; + + case OPTION_MINDEX_REG: + allow_index_reg = 1; + break; + + case OPTION_MNAKED_REG: + allow_naked_reg = 1; + break; + + case OPTION_MOLD_GCC: + old_gcc = 1; + break; + + case OPTION_MSSE2AVX: + sse2avx = 1; + break; + + case OPTION_MSSE_CHECK: + if (strcasecmp (arg, "error") == 0) + sse_check = check_error; + else if (strcasecmp (arg, "warning") == 0) + sse_check = check_warning; + else if (strcasecmp (arg, "none") == 0) + sse_check = check_none; + else + as_fatal (_("invalid -msse-check= option: `%s'"), arg); + break; + + case OPTION_MOPERAND_CHECK: + if (strcasecmp (arg, "error") == 0) + operand_check = check_error; + else if (strcasecmp (arg, "warning") == 0) + operand_check = check_warning; + else if (strcasecmp (arg, "none") == 0) + operand_check = check_none; + else + as_fatal (_("invalid -moperand-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; + + case OPTION_MADD_BND_PREFIX: + add_bnd_prefix = 1; + break; + + case OPTION_MEVEXLIG: + if (strcmp (arg, "128") == 0) + evexlig = evexl128; + else if (strcmp (arg, "256") == 0) + evexlig = evexl256; + else if (strcmp (arg, "512") == 0) + evexlig = evexl512; + else + as_fatal (_("invalid -mevexlig= option: `%s'"), arg); + break; + + case OPTION_MEVEXWIG: + if (strcmp (arg, "0") == 0) + evexwig = evexw0; + else if (strcmp (arg, "1") == 0) + evexwig = evexw1; + else + as_fatal (_("invalid -mevexwig= option: `%s'"), arg); + break; + + default: + return 0; + } + 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 (FILE *stream) +{ +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + fprintf (stream, _("\ + -Q ignored\n\ + -V print assembler version number\n\ + -k ignored\n")); +#endif + fprintf (stream, _("\ + -n Do not optimize code alignment\n\ + -q quieten some warnings\n")); +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + fprintf (stream, _("\ + -s ignored\n")); +#endif +#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) \ + || defined (TE_PE) || defined (TE_PEP)) + fprintf (stream, _("\ + --32/--64/--x32 generate 32bit/64bit/x32 code\n")); +#endif +#ifdef SVR4_COMMENT_CHARS + fprintf (stream, _("\ + --divide do not treat `/' as a comment character\n")); +#else + fprintf (stream, _("\ + --divide ignored\n")); +#endif + fprintf (stream, _("\ + -march=CPU[,+EXTENSION...]\n\ + generate code for CPU and EXTENSION, CPU is one of:\n")); + show_arch (stream, 0, 1); + fprintf (stream, _("\ + 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, _("\ + -moperand-check=[none|error|warning]\n\ + check operand combinations for validity\n")); + fprintf (stream, _("\ + -mavxscalar=[128|256] encode scalar AVX instructions with specific vector\n\ + length\n")); + fprintf (stream, _("\ + -mevexlig=[128|256|512] encode scalar EVEX instructions with specific vector\n\ + length\n")); + fprintf (stream, _("\ + -mevexwig=[0|1] encode EVEX instructions with specific EVEX.W value\n\ + for EVEX.W bit ignored instructions\n")); + fprintf (stream, _("\ + -mmnemonic=[att|intel] use AT&T/Intel mnemonic\n")); + fprintf (stream, _("\ + -msyntax=[att|intel] use AT&T/Intel syntax\n")); + fprintf (stream, _("\ + -mindex-reg support pseudo index registers\n")); + fprintf (stream, _("\ + -mnaked-reg don't require `%%' prefix for registers\n")); + fprintf (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")); +} + +#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)) + +/* Pick the target format to use. */ + +const char * +i386_target_format (void) +{ + if (!strncmp (default_arch, "x86_64", 6)) + { + 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")) + update_code_flag (CODE_32BIT, 1); + else + 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 (OBJ_MAYBE_AOUT) || defined (OBJ_AOUT) + case bfd_target_aout_flavour: + return AOUT_TARGET_FORMAT; +#endif +#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: + { + 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; + } + else + return format; + } +#endif +#if defined (OBJ_MACH_O) + case bfd_target_mach_o_flavour: + 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 (); + return NULL; + } +} + +#endif /* OBJ_MAYBE_ more than one */ + +#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) +void +i386_elf_emit_arch_note (void) +{ + if (IS_ELF && cpu_arch_name != NULL) + { + char *p; + asection *seg = now_seg; + subsegT subseg = now_subseg; + Elf_Internal_Note i_note; + Elf_External_Note e_note; + asection *note_secp; + int len; + + /* Create the .note section. */ + note_secp = subseg_new (".note", 0); + bfd_set_section_flags (stdoutput, + note_secp, + SEC_HAS_CONTENTS | SEC_READONLY); + + /* Process the arch string. */ + len = strlen (cpu_arch_name); + + i_note.namesz = len + 1; + i_note.descsz = 0; + i_note.type = NT_ARCH; + p = frag_more (sizeof (e_note.namesz)); + md_number_to_chars (p, (valueT) i_note.namesz, sizeof (e_note.namesz)); + p = frag_more (sizeof (e_note.descsz)); + md_number_to_chars (p, (valueT) i_note.descsz, sizeof (e_note.descsz)); + p = frag_more (sizeof (e_note.type)); + md_number_to_chars (p, (valueT) i_note.type, sizeof (e_note.type)); + p = frag_more (len + 1); + strcpy (p, cpu_arch_name); + + frag_align (2, 0, 0); + + subseg_set (seg, subseg); + } +} +#endif + +symbolS * +md_undefined_symbol (char *name) +{ + if (name[0] == GLOBAL_OFFSET_TABLE_NAME[0] + && name[1] == GLOBAL_OFFSET_TABLE_NAME[1] + && name[2] == GLOBAL_OFFSET_TABLE_NAME[2] + && strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0) + { + if (!GOT_symbol) + { + if (symbol_find (name)) + as_bad (_("GOT already in symbol table")); + GOT_symbol = symbol_new (name, undefined_section, + (valueT) 0, &zero_address_frag); + }; + return GOT_symbol; + } + return 0; +} + +/* Round up a section size to the appropriate boundary. */ + +valueT +md_section_align (segT segment ATTRIBUTE_UNUSED, valueT size) +{ +#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT)) + if (OUTPUT_FLAVOR == bfd_target_aout_flavour) + { + /* For a.out, force the section size to be aligned. If we don't do + this, BFD will align it for us, but it will not write out the + final bytes of the section. This may be a bug in BFD, but it is + easier to fix it here since that is how the other a.out targets + work. */ + int align; + + align = bfd_get_section_alignment (stdoutput, segment); + size = ((size + (1 << align) - 1) & ((valueT) -1 << align)); + } +#endif + + return size; +} + +/* On the i386, PC-relative offsets are relative to the start of the + next instruction. That is, the address of the offset, plus its + size, since the offset is always the last part of the insn. */ + +long +md_pcrel_from (fixS *fixP) +{ + return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address; +} + +#ifndef I386COFF + +static void +s_bss (int ignore ATTRIBUTE_UNUSED) +{ + int temp; + +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + if (IS_ELF) + obj_elf_section_change_hook (); +#endif + temp = get_absolute_expression (); + subseg_set (bss_section, (subsegT) temp); + demand_empty_rest_of_line (); +} + +#endif + +void +i386_validate_fix (fixS *fixp) +{ + if (fixp->fx_subsy && fixp->fx_subsy == GOT_symbol) + { + if (fixp->fx_r_type == BFD_RELOC_32_PCREL) + { + if (!object_64bit) + abort (); + fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL; + } + else + { + 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; + } +} + +arelent * +tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) +{ + arelent *rel; + bfd_reloc_code_real_type code; + + switch (fixp->fx_r_type) + { +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + case BFD_RELOC_SIZE32: + case BFD_RELOC_SIZE64: + if (S_IS_DEFINED (fixp->fx_addsy) + && !S_IS_EXTERNAL (fixp->fx_addsy)) + { + /* Resolve size relocation against local symbol to size of + the symbol plus addend. */ + valueT value = S_GET_SIZE (fixp->fx_addsy) + fixp->fx_offset; + if (fixp->fx_r_type == BFD_RELOC_SIZE32 + && !fits_in_unsigned_long (value)) + as_bad_where (fixp->fx_file, fixp->fx_line, + _("symbol size computation overflow")); + fixp->fx_addsy = NULL; + fixp->fx_subsy = NULL; + md_apply_fix (fixp, (valueT *) &value, NULL); + return NULL; + } +#endif + + case BFD_RELOC_X86_64_PLT32: + case BFD_RELOC_X86_64_GOT32: + case BFD_RELOC_X86_64_GOTPCREL: + case BFD_RELOC_386_PLT32: + case BFD_RELOC_386_GOT32: + case BFD_RELOC_386_GOTOFF: + case BFD_RELOC_386_GOTPC: + case BFD_RELOC_386_TLS_GD: + case BFD_RELOC_386_TLS_LDM: + case BFD_RELOC_386_TLS_LDO_32: + case BFD_RELOC_386_TLS_IE_32: + case BFD_RELOC_386_TLS_IE: + case BFD_RELOC_386_TLS_GOTIE: + case BFD_RELOC_386_TLS_LE_32: + case BFD_RELOC_386_TLS_LE: + case BFD_RELOC_386_TLS_GOTDESC: + case BFD_RELOC_386_TLS_DESC_CALL: + case BFD_RELOC_X86_64_TLSGD: + case BFD_RELOC_X86_64_TLSLD: + case BFD_RELOC_X86_64_DTPOFF32: + case BFD_RELOC_X86_64_DTPOFF64: + case BFD_RELOC_X86_64_GOTTPOFF: + case BFD_RELOC_X86_64_TPOFF32: + case BFD_RELOC_X86_64_TPOFF64: + case BFD_RELOC_X86_64_GOTOFF64: + case BFD_RELOC_X86_64_GOTPC32: + 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: + case BFD_RELOC_X86_64_GOTPC32_TLSDESC: + case BFD_RELOC_X86_64_TLSDESC_CALL: + case BFD_RELOC_RVA: + case BFD_RELOC_VTABLE_ENTRY: + case BFD_RELOC_VTABLE_INHERIT: +#ifdef TE_PE + case BFD_RELOC_32_SECREL: +#endif + code = fixp->fx_r_type; + break; + case BFD_RELOC_X86_64_32S: + if (!fixp->fx_pcrel) + { + /* Don't turn BFD_RELOC_X86_64_32S into BFD_RELOC_32. */ + code = fixp->fx_r_type; + break; + } + default: + if (fixp->fx_pcrel) + { + switch (fixp->fx_size) + { + default: + as_bad_where (fixp->fx_file, fixp->fx_line, + _("can not do %d byte pc-relative relocation"), + fixp->fx_size); + code = BFD_RELOC_32_PCREL; + break; + case 1: code = BFD_RELOC_8_PCREL; break; + case 2: code = BFD_RELOC_16_PCREL; break; + case 4: code = BFD_RELOC_32_PCREL; break; +#ifdef BFD64 + case 8: code = BFD_RELOC_64_PCREL; break; +#endif + } + } + else + { + switch (fixp->fx_size) + { + default: + as_bad_where (fixp->fx_file, fixp->fx_line, + _("can not do %d byte relocation"), + fixp->fx_size); + code = BFD_RELOC_32; + break; + case 1: code = BFD_RELOC_8; break; + case 2: code = BFD_RELOC_16; break; + case 4: code = BFD_RELOC_32; break; +#ifdef BFD64 + case 8: code = BFD_RELOC_64; break; +#endif + } + } + break; + } + + if ((code == BFD_RELOC_32 + || code == BFD_RELOC_32_PCREL + || code == BFD_RELOC_X86_64_32S) + && GOT_symbol + && fixp->fx_addsy == GOT_symbol) + { + if (!object_64bit) + code = BFD_RELOC_386_GOTPC; + else + code = BFD_RELOC_X86_64_GOTPC32; + } + if ((code == BFD_RELOC_64 || code == BFD_RELOC_64_PCREL) + && GOT_symbol + && fixp->fx_addsy == GOT_symbol) + { + code = BFD_RELOC_X86_64_GOTPC64; + } + + rel = (arelent *) xmalloc (sizeof (arelent)); + rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); + + rel->address = fixp->fx_frag->fr_address + fixp->fx_where; + + if (!use_rela_relocations) + { + /* HACK: Since i386 ELF uses Rel instead of Rela, encode the + vtable entry to be used in the relocation's section offset. */ + if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) + rel->address = fixp->fx_offset; +#if defined (OBJ_COFF) && defined (TE_PE) + else if (fixp->fx_addsy && S_IS_WEAK (fixp->fx_addsy)) + rel->addend = fixp->fx_addnumber - (S_GET_VALUE (fixp->fx_addsy) * 2); + else +#endif + rel->addend = 0; + } + /* Use the rela in 64bit mode. */ + 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 + switch (code) + { + case BFD_RELOC_X86_64_PLT32: + case BFD_RELOC_X86_64_GOT32: + case BFD_RELOC_X86_64_GOTPCREL: + case BFD_RELOC_X86_64_TLSGD: + case BFD_RELOC_X86_64_TLSLD: + case BFD_RELOC_X86_64_GOTTPOFF: + case BFD_RELOC_X86_64_GOTPC32_TLSDESC: + case BFD_RELOC_X86_64_TLSDESC_CALL: + rel->addend = fixp->fx_offset - fixp->fx_size; + break; + default: + rel->addend = (section->vma + - fixp->fx_size + + fixp->fx_addnumber + + md_pcrel_from (fixp)); + break; + } + } + + rel->howto = bfd_reloc_type_lookup (stdoutput, code); + if (rel->howto == NULL) + { + as_bad_where (fixp->fx_file, fixp->fx_line, + _("cannot represent relocation type %s"), + bfd_get_reloc_code_name (code)); + /* Set howto to a garbage value so that we can keep going. */ + rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32); + gas_assert (rel->howto != NULL); + } + + return rel; +} + +#include "tc-i386-intel.c" + +void +tc_x86_parse_to_dw2regnum (expressionS *exp) +{ + int saved_naked_reg; + char saved_register_dot; + + saved_naked_reg = allow_naked_reg; + allow_naked_reg = 1; + saved_register_dot = register_chars['.']; + register_chars['.'] = '.'; + allow_pseudo_reg = 1; + expression_and_evaluate (exp); + allow_pseudo_reg = 0; + register_chars['.'] = saved_register_dot; + allow_naked_reg = saved_naked_reg; + + if (exp->X_op == O_register && exp->X_add_number >= 0) + { + if ((addressT) exp->X_add_number < i386_regtab_size) + { + exp->X_op = O_constant; + exp->X_add_number = i386_regtab[exp->X_add_number] + .dw2_regnum[flag_code >> 1]; + } + else + exp->X_op = O_illegal; + } +} + +void +tc_x86_frame_initial_instructions (void) +{ + static unsigned int sp_regno[2]; + + if (!sp_regno[flag_code >> 1]) + { + char *saved_input = input_line_pointer; + char sp[][4] = {"esp", "rsp"}; + expressionS exp; + + input_line_pointer = sp[flag_code >> 1]; + tc_x86_parse_to_dw2regnum (&exp); + gas_assert (exp.X_op == O_constant); + sp_regno[flag_code >> 1] = exp.X_add_number; + input_line_pointer = saved_input; + } + + cfi_add_CFA_def_cfa (sp_regno[flag_code >> 1], -x86_cie_data_alignment); + cfi_add_CFA_offset (x86_dwarf2_return_column, x86_cie_data_alignment); +} + +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) +{ + if (flag_code == CODE_64BIT + && len == sizeof ("unwind") - 1 + && strncmp (str, "unwind", 6) == 0) + return SHT_X86_64_UNWIND; + + return -1; +} + +#ifdef TE_SOLARIS +void +i386_solaris_fix_up_eh_frame (segT sec) +{ + if (flag_code == CODE_64BIT) + elf_section_type (sec) = SHT_X86_64_UNWIND; +} +#endif + +#ifdef TE_PE +void +tc_pe_dwarf2_emit_offset (symbolS *symbol, unsigned int size) +{ + expressionS exp; + + exp.X_op = O_secrel; + exp.X_add_symbol = symbol; + exp.X_add_number = 0; + emit_expr (&exp, size); +} +#endif + +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) +/* For ELF on x86-64, add support for SHF_X86_64_LARGE. */ + +bfd_vma +x86_64_section_letter (int letter, char **ptr_msg) +{ + if (flag_code == CODE_64BIT) + { + if (letter == 'l') + return SHF_X86_64_LARGE; + + *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"); + return -1; +} + +bfd_vma +x86_64_section_word (char *str, size_t len) +{ + if (len == 5 && flag_code == CODE_64BIT && CONST_STRNEQ (str, "large")) + return SHF_X86_64_LARGE; + + return -1; +} + +static void +handle_large_common (int small ATTRIBUTE_UNUSED) +{ + if (flag_code != CODE_64BIT) + { + s_comm_internal (0, elf_common_parse); + as_warn (_(".largecomm supported only in 64bit mode, producing .comm")); + } + else + { + static segT lbss_section; + asection *saved_com_section_ptr = elf_com_section_ptr; + asection *saved_bss_section = bss_section; + + if (lbss_section == NULL) + { + flagword applicable; + segT seg = now_seg; + subsegT subseg = now_subseg; + + /* The .lbss section is for local .largecomm symbols. */ + lbss_section = subseg_new (".lbss", 0); + applicable = bfd_applicable_section_flags (stdoutput); + bfd_set_section_flags (stdoutput, lbss_section, + applicable & SEC_ALLOC); + seg_info (lbss_section)->bss = 1; + + subseg_set (seg, subseg); + } + + elf_com_section_ptr = &_bfd_elf_large_com_section; + bss_section = lbss_section; + + s_comm_internal (0, elf_common_parse); + + elf_com_section_ptr = saved_com_section_ptr; + bss_section = saved_bss_section; + } +} +#endif /* OBJ_ELF || OBJ_MAYBE_ELF */ |