blob: 4739a6d0c21a1717b1507fc206bab7a0476a6c4c [file] [log] [blame]
/* tc-i386.c -- Assemble code for the Intel 80386
Copyright (C) 1989-2024 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 "scfi.h"
#include "gen-sframe.h"
#include "sframe.h"
#include "elf/x86-64.h"
#include "opcodes/i386-init.h"
#include "opcodes/i386-mnem.h"
#include <limits.h>
#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 END_OF_INSN '\0'
#define OPERAND_TYPE_NONE { .bitfield = { .class = ClassNone } }
/* This matches the C -> StaticRounding alias in the opcode table. */
#define commutative staticrounding
/*
'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:8; /* arch string length */
bool skip:1; /* show_arch should skip this. */
enum processor_type type; /* arch type */
enum { vsz_none, vsz_set, vsz_reset } vsz; /* vector size control */
i386_cpu_flags enable; /* cpu feature enable flags */
i386_cpu_flags disable; /* cpu feature disable flags */
}
arch_entry;
/* Modes for parse_insn() to operate in. */
enum parse_mode {
parse_all,
parse_prefix,
parse_pseudo_prefix,
};
static void update_code_flag (int, int);
static void s_insn (int);
static void s_noopt (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);
static void pe_directive_secidx (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 (const char *, char **);
static const char *parse_insn (const char *, char *, enum parse_mode);
static char *parse_operands (char *, const char *);
static void swap_operands (void);
static void swap_2_operands (unsigned int, unsigned int);
static enum i386_flag_code i386_addressing_mode (void);
static void optimize_imm (void);
static bool optimize_disp (const insn_template *t);
static const insn_template *match_template (char);
static int check_string (void);
static int process_suffix (const insn_template *);
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 reg_entry *build_modrm_byte (void);
static void output_insn (const struct last_insn *);
static void output_imm (fragS *, offsetT);
static void output_disp (fragS *, offsetT);
#ifdef OBJ_AOUT
static void s_bss (int);
#endif
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
static void handle_large_common (int small ATTRIBUTE_UNUSED);
/* GNU_PROPERTY_X86_ISA_1_USED. */
static unsigned int x86_isa_1_used;
/* GNU_PROPERTY_X86_FEATURE_2_USED. */
static unsigned int x86_feature_2_used;
/* Generate x86 used ISA and feature properties. */
static unsigned int x86_used_note = DEFAULT_X86_USED_NOTE;
#endif
static const char *default_arch = DEFAULT_ARCH;
/* parse_register() returns this when a register alias cannot be used. */
static const reg_entry bad_reg = { "<bad>", OPERAND_TYPE_NONE, 0, 0,
{ Dw2Inval, Dw2Inval } };
static const reg_entry *reg_eax;
static const reg_entry *reg_ds;
static const reg_entry *reg_es;
static const reg_entry *reg_ss;
static const reg_entry *reg_st0;
static const reg_entry *reg_k0;
/* 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
{
no_error, /* Must be first. */
operand_size_mismatch,
operand_type_mismatch,
register_type_mismatch,
number_of_operands_mismatch,
invalid_instruction_suffix,
bad_imm4,
unsupported_with_intel_mnemonic,
unsupported_syntax,
unsupported_EGPR_for_addressing,
unsupported_nf,
unsupported,
unsupported_on_arch,
unsupported_64bit,
no_vex_encoding,
no_evex_encoding,
invalid_sib_address,
invalid_vsib_address,
invalid_vector_register_set,
invalid_tmm_register_set,
invalid_dest_and_src_register_set,
invalid_dest_register_set,
invalid_pseudo_prefix,
unsupported_vector_index_register,
unsupported_broadcast,
broadcast_needed,
unsupported_masking,
mask_not_on_destination,
no_default_mask,
unsupported_rc_sae,
unsupported_vector_size,
unsupported_rsp_register,
internal_error,
};
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;
/* OPCODE_LENGTH holds the number of base opcode bytes. */
unsigned char opcode_length;
/* 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
#define Operand_Mem 2
#define Operand_Signed 4 /* .insn only */
/* 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 reg_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];
/* .insn allows for reserved opcode spaces. */
unsigned char insn_opcode_space;
/* .insn also allows (requires) specifying immediate size. */
unsigned char imm_bits[MAX_OPERANDS];
/* Register is in low 3 bits of opcode. */
bool short_form;
/* The operand to a branch insn indicates an absolute branch. */
bool jumpabsolute;
/* The operand to a branch insn indicates a far branch. */
bool far_branch;
/* There is a memory operand of (%dx) which should be only used
with input/output instructions. */
bool input_output_operand;
/* Extended states. */
enum
{
/* Use MMX state. */
xstate_mmx = 1 << 0,
/* Use XMM state. */
xstate_xmm = 1 << 1,
/* Use YMM state. */
xstate_ymm = 1 << 2 | xstate_xmm,
/* Use ZMM state. */
xstate_zmm = 1 << 3 | xstate_ymm,
/* Use TMM state. */
xstate_tmm = 1 << 4,
/* Use MASK state. */
xstate_mask = 1 << 5
} xstate;
/* Has GOTPC or TLS relocation. */
bool has_gotpc_tls_reloc;
/* 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;
rex_byte rex2;
sib_byte sib;
vex_prefix vex;
/* Masking attributes.
The struct describes masking, applied to OPERAND in the instruction.
REG is a pointer to the corresponding mask register. ZEROING tells
whether merging or zeroing mask is used. */
struct Mask_Operation
{
const reg_entry *reg;
unsigned int zeroing;
/* The operand where this operation is associated. */
unsigned int operand;
} mask;
/* Rounding control and SAE attributes. */
struct RC_Operation
{
enum rc_type
{
rc_none = -1,
rne,
rd,
ru,
rz,
saeonly
} type;
/* In Intel syntax the operand modifier form is supposed to be used, but
we continue to accept the immediate forms as well. */
bool modifier;
} rounding;
/* Broadcasting attributes.
The struct describes broadcasting, applied to OPERAND. TYPE is
expresses the broadcast factor. */
struct Broadcast_Operation
{
/* Type of broadcast: {1to2}, {1to4}, {1to8}, {1to16} or {1to32}. */
unsigned int type;
/* Index of broadcasted operand. */
unsigned int operand;
/* Number of bytes to broadcast. */
unsigned int bytes;
} broadcast;
/* Compressed disp8*N attribute. */
unsigned int memshift;
/* SCC = EVEX.[SC3,SC2,SC1,SC0]. */
unsigned int scc;
/* Store 4 bits of EVEX.[OF,SF,ZF,CF]. */
#define OSZC_CF 1
#define OSZC_ZF 2
#define OSZC_SF 4
#define OSZC_OF 8
unsigned int oszc_flags;
/* Invert the condition encoded in a base opcode. */
bool invert_cond;
/* REP prefix. */
const char *rep_prefix;
/* HLE prefix. */
const char *hle_prefix;
/* Have BND prefix. */
const char *bnd_prefix;
/* Have NOTRACK prefix. */
const char *notrack_prefix;
/* Error message. */
enum i386_error error;
};
typedef struct _i386_insn i386_insn;
/* Pseudo-prefix recording state, separate from i386_insn. */
static struct pseudo_prefixes {
/* How to encode instructions. */
enum {
encoding_default = 0,
encoding_vex,
encoding_vex3,
encoding_egpr, /* REX2 or EVEX. */
encoding_evex,
encoding_evex512,
encoding_error
} encoding;
/* Prefer load or store in encoding. */
enum {
dir_encoding_default = 0,
dir_encoding_load,
dir_encoding_store,
dir_encoding_swap
} dir_encoding;
/* Prefer 8bit, 16bit, 32bit displacement in encoding. */
enum {
disp_encoding_default = 0,
disp_encoding_8bit,
disp_encoding_16bit,
disp_encoding_32bit
} disp_encoding;
/* Prefer the REX byte in encoding. */
bool rex_encoding;
/* Prefer the REX2 prefix in encoding. */
bool rex2_encoding;
/* No CSPAZO flags update. */
bool has_nf;
/* Disable instruction size optimization. */
bool no_optimize;
} pp;
/* 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") },
};
/* To be indexed by segment register number. */
static const unsigned char i386_seg_prefixes[] = {
ES_PREFIX_OPCODE,
CS_PREFIX_OPCODE,
SS_PREFIX_OPCODE,
DS_PREFIX_OPCODE,
FS_PREFIX_OPCODE,
GS_PREFIX_OPCODE
};
/* 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 (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) \
&& !defined (TE_GNU) \
&& !defined (TE_LINUX) \
&& !defined (TE_Haiku) \
&& !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[] = "fFdDxXhHbB";
/* Tables for lexical analysis. */
static char mnemonic_chars[256];
static char register_chars[256];
static char operand_chars[256];
/* Lexical macros. */
#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) == ' ')
/* All non-digit non-letter characters that may occur in an operand and
which aren't already in extra_symbol_chars[]. */
static const 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 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;
/* Are we processing a .insn directive? */
#define dot_insn() (i.tm.mnem_off == MN__insn)
enum i386_flag_code i386_flag_code;
#define flag_code i386_flag_code /* Permit to continue using original name. */
static unsigned int object_64bit;
static unsigned int disallow_64bit_reloc;
static int use_rela_relocations = 0;
/* __tls_get_addr/___tls_get_addr symbol for TLS. */
static const char *tls_get_addr;
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
/* 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
#if defined (TE_PE) || defined (TE_PEP)
/* Use big object file format. */
static int use_big_obj = 0;
#endif
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
/* 1 if generating code for a shared library. */
static int shared = 0;
unsigned int x86_sframe_cfa_sp_reg;
/* The other CFA base register for SFrame stack trace info. */
unsigned int x86_sframe_cfa_fp_reg;
static ginsnS *x86_ginsn_new (const symbolS *, enum ginsn_gen_mode);
#endif
/* 1 for intel syntax,
0 if att syntax. */
static int intel_syntax = 0;
static enum x86_64_isa
{
amd64 = 1, /* AMD64 ISA. */
intel64 /* Intel64 ISA. */
} isa64;
/* 1 for intel mnemonic,
0 if att mnemonic. */
static int intel_mnemonic = !SYSV386_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-transferring
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;
/* 1 if the assembler should ignore LOCK prefix, even if it was
specified explicitly. */
static int omit_lock_prefix = 0;
/* 1 if the assembler should encode lfence, mfence, and sfence as
"lock addl $0, (%{re}sp)". */
static int avoid_fence = 0;
/* 1 if lfence should be inserted after every load. */
static int lfence_after_load = 0;
/* Non-zero if lfence should be inserted before indirect branch. */
static enum lfence_before_indirect_branch_kind
{
lfence_branch_none = 0,
lfence_branch_register,
lfence_branch_memory,
lfence_branch_all
}
lfence_before_indirect_branch;
/* Non-zero if lfence should be inserted before ret. */
static enum lfence_before_ret_kind
{
lfence_before_ret_none = 0,
lfence_before_ret_not,
lfence_before_ret_or,
lfence_before_ret_shl
}
lfence_before_ret;
/* 1 if the assembler should generate relax relocations. */
static int generate_relax_relocations
= DEFAULT_GENERATE_X86_RELAX_RELOCATIONS;
static enum check_kind
{
check_none = 0,
check_warning,
check_error
}
sse_check, operand_check = check_warning;
/* Non-zero if branches should be aligned within power of 2 boundary. */
static int align_branch_power = 0;
/* Types of branches to align. */
enum align_branch_kind
{
align_branch_none = 0,
align_branch_jcc = 1,
align_branch_fused = 2,
align_branch_jmp = 3,
align_branch_call = 4,
align_branch_indirect = 5,
align_branch_ret = 6
};
/* Type bits of branches to align. */
enum align_branch_bit
{
align_branch_jcc_bit = 1 << align_branch_jcc,
align_branch_fused_bit = 1 << align_branch_fused,
align_branch_jmp_bit = 1 << align_branch_jmp,
align_branch_call_bit = 1 << align_branch_call,
align_branch_indirect_bit = 1 << align_branch_indirect,
align_branch_ret_bit = 1 << align_branch_ret
};
static unsigned int align_branch = (align_branch_jcc_bit
| align_branch_fused_bit
| align_branch_jmp_bit);
/* Types of condition jump used by macro-fusion. */
enum mf_jcc_kind
{
mf_jcc_jo = 0, /* base opcode 0x70 */
mf_jcc_jc, /* base opcode 0x72 */
mf_jcc_je, /* base opcode 0x74 */
mf_jcc_jna, /* base opcode 0x76 */
mf_jcc_js, /* base opcode 0x78 */
mf_jcc_jp, /* base opcode 0x7a */
mf_jcc_jl, /* base opcode 0x7c */
mf_jcc_jle, /* base opcode 0x7e */
};
/* Types of compare flag-modifying insntructions used by macro-fusion. */
enum mf_cmp_kind
{
mf_cmp_test_and, /* test/cmp */
mf_cmp_alu_cmp, /* add/sub/cmp */
mf_cmp_incdec /* inc/dec */
};
/* The maximum padding size for fused jcc. CMP like instruction can
be 9 bytes and jcc can be 6 bytes. Leave room just in case for
prefixes. */
#define MAX_FUSED_JCC_PADDING_SIZE 20
/* The maximum number of prefixes added for an instruction. */
static unsigned int align_branch_prefix_size = 5;
/* Optimization:
1. Clear the REX_W bit with register operand if possible.
2. Above plus use 128bit vector instruction to clear the full vector
register.
*/
static int optimize = 0;
/* Optimization:
1. Clear the REX_W bit with register operand if possible.
2. Above plus use 128bit vector instruction to clear the full vector
register.
3. Above plus optimize "test{q,l,w} $imm8,%r{64,32,16}" to
"testb $imm7,%r8".
*/
static int optimize_for_space = 0;
/* 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;
/* Guard to avoid repeated warnings about non-16-bit code on 16-bit CPUs. */
static bool pre_386_16bit_warned;
/* CPU name. */
static const char *cpu_arch_name = NULL;
static char *cpu_sub_arch_name = NULL;
/* CPU feature flags. */
i386_cpu_flags cpu_arch_flags = CPU_UNKNOWN_FLAGS;
/* ISA extensions available in 64-bit mode only. */
static const i386_cpu_flags cpu_64_flags = CPU_ANY_64_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 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 bool no_cond_jump_promotion = false;
/* This will be set from an expression parser hook if there's any
applicable operator involved in an expression. */
static enum {
expr_operator_none,
expr_operator_present,
expr_large_value,
} expr_mode;
/* Encode SSE instructions with VEX prefix. */
static unsigned int sse2avx;
/* Encode aligned vector move as unaligned vector move. */
static unsigned int use_unaligned_vector_move;
/* Maximum permitted vector size. */
#define VSZ128 0
#define VSZ256 1
#define VSZ512 2
#define VSZ_DEFAULT VSZ512
static unsigned int vector_size = VSZ_DEFAULT;
/* Encode scalar AVX instructions with specific vector length. */
static enum
{
vex128 = 0,
vex256
} avxscalar;
/* Encode VEX WIG instructions with specific vex.w. */
static enum
{
vexw0 = 0,
vexw1
} vexwig;
/* 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;
/* Value to encode in EVEX RC bits, for SAE-only instructions. */
static enum rc_type evexrcig = rne;
/* 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.
BRANCH_PADDING, BRANCH_PREFIX and FUSED_JCC_PADDING are used to align
branches which are handled by md_estimate_size_before_relax() and
i386_generic_table_relax_frag(). */
/* Types. */
#define UNCOND_JUMP 0
#define COND_JUMP 1
#define COND_JUMP86 2
#define BRANCH_PADDING 3
#define BRANCH_PREFIX 4
#define FUSED_JCC_PADDING 5
/* 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}
};
#define ARCH(n, t, f, s) \
{ STRING_COMMA_LEN (#n), s, PROCESSOR_ ## t, vsz_none, CPU_ ## f ## _FLAGS, \
CPU_NONE_FLAGS }
#define SUBARCH(n, e, d, s) \
{ STRING_COMMA_LEN (#n), s, PROCESSOR_NONE, vsz_none, CPU_ ## e ## _FLAGS, \
CPU_ ## d ## _FLAGS }
#define VECARCH(n, e, d, v) \
{ STRING_COMMA_LEN (#n), false, PROCESSOR_NONE, vsz_ ## v, \
CPU_ ## e ## _FLAGS, CPU_ ## d ## _FLAGS }
static const arch_entry cpu_arch[] =
{
/* Do not replace the first two entries - i386_target_format() and
set_cpu_arch() rely on them being there in this order. */
ARCH (generic32, GENERIC32, GENERIC32, false),
ARCH (generic64, GENERIC64, GENERIC64, false),
ARCH (i8086, UNKNOWN, NONE, false),
ARCH (i186, UNKNOWN, 186, false),
ARCH (i286, UNKNOWN, 286, false),
ARCH (i386, I386, 386, false),
ARCH (i486, I486, 486, false),
ARCH (i586, PENTIUM, 586, false),
ARCH (pentium, PENTIUM, 586, false),
ARCH (i686, I686, 686, false),
ARCH (pentiumpro, PENTIUMPRO, PENTIUMPRO, false),
ARCH (pentiumii, PENTIUMPRO, P2, false),
ARCH (pentiumiii, PENTIUMPRO, P3, false),
ARCH (pentium4, PENTIUM4, P4, false),
ARCH (prescott, NOCONA, CORE, false),
ARCH (nocona, NOCONA, NOCONA, false),
ARCH (yonah, CORE, CORE, true),
ARCH (core, CORE, CORE, false),
ARCH (merom, CORE2, CORE2, true),
ARCH (core2, CORE2, CORE2, false),
ARCH (corei7, COREI7, COREI7, false),
ARCH (iamcu, IAMCU, IAMCU, false),
ARCH (k6, K6, K6, false),
ARCH (k6_2, K6, K6_2, false),
ARCH (athlon, ATHLON, ATHLON, false),
ARCH (sledgehammer, K8, K8, true),
ARCH (opteron, K8, K8, false),
ARCH (k8, K8, K8, false),
ARCH (amdfam10, AMDFAM10, AMDFAM10, false),
ARCH (bdver1, BD, BDVER1, false),
ARCH (bdver2, BD, BDVER2, false),
ARCH (bdver3, BD, BDVER3, false),
ARCH (bdver4, BD, BDVER4, false),
ARCH (znver1, ZNVER, ZNVER1, false),
ARCH (znver2, ZNVER, ZNVER2, false),
ARCH (znver3, ZNVER, ZNVER3, false),
ARCH (znver4, ZNVER, ZNVER4, false),
ARCH (znver5, ZNVER, ZNVER5, false),
ARCH (btver1, BT, BTVER1, false),
ARCH (btver2, BT, BTVER2, false),
SUBARCH (8087, 8087, ANY_8087, false),
SUBARCH (87, NONE, ANY_8087, false), /* Disable only! */
SUBARCH (287, 287, ANY_287, false),
SUBARCH (387, 387, ANY_387, false),
SUBARCH (687, 687, ANY_687, false),
SUBARCH (cmov, CMOV, CMOV, false),
SUBARCH (fxsr, FXSR, ANY_FXSR, false),
SUBARCH (mmx, MMX, ANY_MMX, false),
SUBARCH (sse, SSE, ANY_SSE, false),
SUBARCH (sse2, SSE2, ANY_SSE2, false),
SUBARCH (sse3, SSE3, ANY_SSE3, false),
SUBARCH (sse4a, SSE4A, ANY_SSE4A, false),
SUBARCH (ssse3, SSSE3, ANY_SSSE3, false),
SUBARCH (sse4.1, SSE4_1, ANY_SSE4_1, false),
SUBARCH (sse4.2, SSE4_2, ANY_SSE4_2, false),
SUBARCH (sse4, SSE4_2, ANY_SSE4_1, false),
VECARCH (avx, AVX, ANY_AVX, reset),
VECARCH (avx2, AVX2, ANY_AVX2, reset),
VECARCH (avx512f, AVX512F, ANY_AVX512F, reset),
VECARCH (avx512cd, AVX512CD, ANY_AVX512CD, reset),
VECARCH (avx512er, AVX512ER, ANY_AVX512ER, reset),
VECARCH (avx512pf, AVX512PF, ANY_AVX512PF, reset),
VECARCH (avx512dq, AVX512DQ, ANY_AVX512DQ, reset),
VECARCH (avx512bw, AVX512BW, ANY_AVX512BW, reset),
VECARCH (avx512vl, AVX512VL, ANY_AVX512VL, reset),
SUBARCH (monitor, MONITOR, MONITOR, false),
SUBARCH (vmx, VMX, ANY_VMX, false),
SUBARCH (vmfunc, VMFUNC, ANY_VMFUNC, false),
SUBARCH (smx, SMX, SMX, false),
SUBARCH (xsave, XSAVE, ANY_XSAVE, false),
SUBARCH (xsaveopt, XSAVEOPT, ANY_XSAVEOPT, false),
SUBARCH (xsavec, XSAVEC, ANY_XSAVEC, false),
SUBARCH (xsaves, XSAVES, ANY_XSAVES, false),
SUBARCH (aes, AES, ANY_AES, false),
SUBARCH (pclmul, PCLMULQDQ, ANY_PCLMULQDQ, false),
SUBARCH (clmul, PCLMULQDQ, ANY_PCLMULQDQ, true),
SUBARCH (fsgsbase, FSGSBASE, FSGSBASE, false),
SUBARCH (rdrnd, RDRND, RDRND, false),
SUBARCH (f16c, F16C, ANY_F16C, false),
SUBARCH (bmi2, BMI2, BMI2, false),
SUBARCH (fma, FMA, ANY_FMA, false),
SUBARCH (fma4, FMA4, ANY_FMA4, false),
SUBARCH (xop, XOP, ANY_XOP, false),
SUBARCH (lwp, LWP, ANY_LWP, false),
SUBARCH (movbe, MOVBE, MOVBE, false),
SUBARCH (cx16, CX16, CX16, false),
SUBARCH (lahf_sahf, LAHF_SAHF, LAHF_SAHF, false),
SUBARCH (ept, EPT, ANY_EPT, false),
SUBARCH (lzcnt, LZCNT, LZCNT, false),
SUBARCH (popcnt, POPCNT, POPCNT, false),
SUBARCH (hle, HLE, HLE, false),
SUBARCH (rtm, RTM, ANY_RTM, false),
SUBARCH (tsx, TSX, TSX, false),
SUBARCH (invpcid, INVPCID, INVPCID, false),
SUBARCH (clflush, CLFLUSH, CLFLUSH, false),
SUBARCH (nop, NOP, NOP, false),
SUBARCH (syscall, SYSCALL, SYSCALL, false),
SUBARCH (rdtscp, RDTSCP, RDTSCP, false),
SUBARCH (3dnow, 3DNOW, ANY_3DNOW, false),
SUBARCH (3dnowa, 3DNOWA, ANY_3DNOWA, false),
SUBARCH (padlock, PADLOCK, PADLOCK, false),
SUBARCH (pacifica, SVME, ANY_SVME, true),
SUBARCH (svme, SVME, ANY_SVME, false),
SUBARCH (abm, ABM, ABM, false),
SUBARCH (bmi, BMI, BMI, false),
SUBARCH (tbm, TBM, TBM, false),
SUBARCH (adx, ADX, ADX, false),
SUBARCH (rdseed, RDSEED, RDSEED, false),
SUBARCH (prfchw, PRFCHW, PRFCHW, false),
SUBARCH (smap, SMAP, SMAP, false),
SUBARCH (mpx, MPX, ANY_MPX, false),
SUBARCH (sha, SHA, ANY_SHA, false),
SUBARCH (clflushopt, CLFLUSHOPT, CLFLUSHOPT, false),
SUBARCH (prefetchwt1, PREFETCHWT1, PREFETCHWT1, false),
SUBARCH (se1, SE1, SE1, false),
SUBARCH (clwb, CLWB, CLWB, false),
VECARCH (avx512ifma, AVX512IFMA, ANY_AVX512IFMA, reset),
VECARCH (avx512vbmi, AVX512VBMI, ANY_AVX512VBMI, reset),
VECARCH (avx512_4fmaps, AVX512_4FMAPS, ANY_AVX512_4FMAPS, reset),
VECARCH (avx512_4vnniw, AVX512_4VNNIW, ANY_AVX512_4VNNIW, reset),
VECARCH (avx512_vpopcntdq, AVX512_VPOPCNTDQ, ANY_AVX512_VPOPCNTDQ, reset),
VECARCH (avx512_vbmi2, AVX512_VBMI2, ANY_AVX512_VBMI2, reset),
VECARCH (avx512_vnni, AVX512_VNNI, ANY_AVX512_VNNI, reset),
VECARCH (avx512_bitalg, AVX512_BITALG, ANY_AVX512_BITALG, reset),
VECARCH (avx_vnni, AVX_VNNI, ANY_AVX_VNNI, reset),
SUBARCH (clzero, CLZERO, CLZERO, false),
SUBARCH (mwaitx, MWAITX, MWAITX, false),
SUBARCH (ospke, OSPKE, ANY_OSPKE, false),
SUBARCH (rdpid, RDPID, RDPID, false),
SUBARCH (ptwrite, PTWRITE, PTWRITE, false),
SUBARCH (ibt, IBT, IBT, false),
SUBARCH (shstk, SHSTK, SHSTK, false),
SUBARCH (gfni, GFNI, ANY_GFNI, false),
VECARCH (vaes, VAES, ANY_VAES, reset),
VECARCH (vpclmulqdq, VPCLMULQDQ, ANY_VPCLMULQDQ, reset),
SUBARCH (wbnoinvd, WBNOINVD, WBNOINVD, false),
SUBARCH (pconfig, PCONFIG, PCONFIG, false),
SUBARCH (waitpkg, WAITPKG, WAITPKG, false),
SUBARCH (cldemote, CLDEMOTE, CLDEMOTE, false),
SUBARCH (amx_int8, AMX_INT8, ANY_AMX_INT8, false),
SUBARCH (amx_bf16, AMX_BF16, ANY_AMX_BF16, false),
SUBARCH (amx_fp16, AMX_FP16, ANY_AMX_FP16, false),
SUBARCH (amx_complex, AMX_COMPLEX, ANY_AMX_COMPLEX, false),
SUBARCH (amx_tile, AMX_TILE, ANY_AMX_TILE, false),
SUBARCH (movdiri, MOVDIRI, MOVDIRI, false),
SUBARCH (movdir64b, MOVDIR64B, MOVDIR64B, false),
VECARCH (avx512_bf16, AVX512_BF16, ANY_AVX512_BF16, reset),
VECARCH (avx512_vp2intersect, AVX512_VP2INTERSECT,
ANY_AVX512_VP2INTERSECT, reset),
SUBARCH (tdx, TDX, TDX, false),
SUBARCH (enqcmd, ENQCMD, ENQCMD, false),
SUBARCH (serialize, SERIALIZE, SERIALIZE, false),
SUBARCH (rdpru, RDPRU, RDPRU, false),
SUBARCH (mcommit, MCOMMIT, MCOMMIT, false),
SUBARCH (sev_es, SEV_ES, ANY_SEV_ES, false),
SUBARCH (tsxldtrk, TSXLDTRK, ANY_TSXLDTRK, false),
SUBARCH (kl, KL, ANY_KL, false),
SUBARCH (widekl, WIDEKL, ANY_WIDEKL, false),
SUBARCH (uintr, UINTR, UINTR, false),
SUBARCH (hreset, HRESET, HRESET, false),
VECARCH (avx512_fp16, AVX512_FP16, ANY_AVX512_FP16, reset),
SUBARCH (prefetchi, PREFETCHI, PREFETCHI, false),
VECARCH (avx_ifma, AVX_IFMA, ANY_AVX_IFMA, reset),
VECARCH (avx_vnni_int8, AVX_VNNI_INT8, ANY_AVX_VNNI_INT8, reset),
SUBARCH (cmpccxadd, CMPCCXADD, CMPCCXADD, false),
SUBARCH (wrmsrns, WRMSRNS, WRMSRNS, false),
SUBARCH (msrlist, MSRLIST, MSRLIST, false),
VECARCH (avx_ne_convert, AVX_NE_CONVERT, ANY_AVX_NE_CONVERT, reset),
SUBARCH (rao_int, RAO_INT, RAO_INT, false),
SUBARCH (rmpquery, RMPQUERY, ANY_RMPQUERY, false),
SUBARCH (fred, FRED, ANY_FRED, false),
SUBARCH (lkgs, LKGS, ANY_LKGS, false),
VECARCH (avx_vnni_int16, AVX_VNNI_INT16, ANY_AVX_VNNI_INT16, reset),
VECARCH (sha512, SHA512, ANY_SHA512, reset),
VECARCH (sm3, SM3, ANY_SM3, reset),
VECARCH (sm4, SM4, ANY_SM4, reset),
SUBARCH (pbndkb, PBNDKB, PBNDKB, false),
VECARCH (avx10.1, AVX10_1, ANY_AVX512F, set),
SUBARCH (user_msr, USER_MSR, USER_MSR, false),
SUBARCH (apx_f, APX_F, APX_F, false),
VECARCH (avx10.2, AVX10_2, ANY_AVX10_2, set),
};
#undef SUBARCH
#undef ARCH
#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},
#ifdef OBJ_AOUT
{"bss", s_bss, 0},
#endif
#ifdef I386COFF
{"lcomm", pe_lcomm, 1},
#endif
{"ffloat", float_cons, 'f'},
{"dfloat", float_cons, 'd'},
{"tfloat", float_cons, 'x'},
{"hfloat", float_cons, 'h'},
{"bfloat16", float_cons, 'b'},
{"value", cons, 2},
{"slong", signed_cons, 4},
{"insn", s_insn, 0},
{"noopt", s_noopt, 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},
#ifdef BFD64
{"code64", set_code_flag, CODE_64BIT},
#endif
{"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", 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},
{"secidx", pe_directive_secidx, 0},
#endif
{0, 0, 0}
};
/* For interface with expression (). */
extern char *input_line_pointer;
/* Hash table for instruction mnemonic lookup. */
static htab_t op_hash;
/* Hash table for register lookup. */
static htab_t reg_hash;
static const struct
{
const char *str;
unsigned int len;
const enum bfd_reloc_code_real rel[2];
const i386_operand_type types64;
bool need_GOT_symbol;
}
gotrel[] =
{
#define OPERAND_TYPE_IMM32_32S_DISP32 { .bitfield = \
{ .imm32 = 1, .imm32s = 1, .disp32 = 1 } }
#define OPERAND_TYPE_IMM32_32S_64_DISP32 { .bitfield = \
{ .imm32 = 1, .imm32s = 1, .imm64 = 1, .disp32 = 1 } }
#define OPERAND_TYPE_IMM32_32S_64_DISP32_64 { .bitfield = \
{ .imm32 = 1, .imm32s = 1, .imm64 = 1, .disp32 = 1, .disp64 = 1 } }
#define OPERAND_TYPE_IMM64_DISP64 { .bitfield = \
{ .imm64 = 1, .disp64 = 1 } }
#ifndef TE_PE
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
{ STRING_COMMA_LEN ("SIZE"), { BFD_RELOC_SIZE32,
BFD_RELOC_SIZE32 },
{ .bitfield = { .imm32 = 1, .imm64 = 1 } }, false },
#endif
{ STRING_COMMA_LEN ("PLTOFF"), { _dummy_first_bfd_reloc_code_real,
BFD_RELOC_X86_64_PLTOFF64 },
{ .bitfield = { .imm64 = 1 } }, true },
{ STRING_COMMA_LEN ("PLT"), { BFD_RELOC_386_PLT32,
BFD_RELOC_X86_64_PLT32 },
OPERAND_TYPE_IMM32_32S_DISP32, false },
{ STRING_COMMA_LEN ("GOTPLT"), { _dummy_first_bfd_reloc_code_real,
BFD_RELOC_X86_64_GOTPLT64 },
OPERAND_TYPE_IMM64_DISP64, true },
{ STRING_COMMA_LEN ("GOTOFF"), { BFD_RELOC_386_GOTOFF,
BFD_RELOC_X86_64_GOTOFF64 },
OPERAND_TYPE_IMM64_DISP64, true },
{ STRING_COMMA_LEN ("GOTPCREL"), { _dummy_first_bfd_reloc_code_real,
BFD_RELOC_X86_64_GOTPCREL },
OPERAND_TYPE_IMM32_32S_DISP32, true },
{ STRING_COMMA_LEN ("TLSGD"), { BFD_RELOC_386_TLS_GD,
BFD_RELOC_X86_64_TLSGD },
OPERAND_TYPE_IMM32_32S_DISP32, true },
{ STRING_COMMA_LEN ("TLSLDM"), { BFD_RELOC_386_TLS_LDM,
_dummy_first_bfd_reloc_code_real },
OPERAND_TYPE_NONE, true },
{ STRING_COMMA_LEN ("TLSLD"), { _dummy_first_bfd_reloc_code_real,
BFD_RELOC_X86_64_TLSLD },
OPERAND_TYPE_IMM32_32S_DISP32, true },
{ STRING_COMMA_LEN ("GOTTPOFF"), { BFD_RELOC_386_TLS_IE_32,
BFD_RELOC_X86_64_GOTTPOFF },
OPERAND_TYPE_IMM32_32S_DISP32, true },
{ STRING_COMMA_LEN ("TPOFF"), { BFD_RELOC_386_TLS_LE_32,
BFD_RELOC_X86_64_TPOFF32 },
OPERAND_TYPE_IMM32_32S_64_DISP32_64, true },
{ STRING_COMMA_LEN ("NTPOFF"), { BFD_RELOC_386_TLS_LE,
_dummy_first_bfd_reloc_code_real },
OPERAND_TYPE_NONE, true },
{ STRING_COMMA_LEN ("DTPOFF"), { BFD_RELOC_386_TLS_LDO_32,
BFD_RELOC_X86_64_DTPOFF32 },
OPERAND_TYPE_IMM32_32S_64_DISP32_64, true },
{ STRING_COMMA_LEN ("GOTNTPOFF"),{ BFD_RELOC_386_TLS_GOTIE,
_dummy_first_bfd_reloc_code_real },
OPERAND_TYPE_NONE, true },
{ STRING_COMMA_LEN ("INDNTPOFF"),{ BFD_RELOC_386_TLS_IE,
_dummy_first_bfd_reloc_code_real },
OPERAND_TYPE_NONE, true },
{ STRING_COMMA_LEN ("GOT"), { BFD_RELOC_386_GOT32,
BFD_RELOC_X86_64_GOT32 },
OPERAND_TYPE_IMM32_32S_64_DISP32, true },
{ STRING_COMMA_LEN ("TLSDESC"), { BFD_RELOC_386_TLS_GOTDESC,
BFD_RELOC_X86_64_GOTPC32_TLSDESC },
OPERAND_TYPE_IMM32_32S_DISP32, true },
{ STRING_COMMA_LEN ("TLSCALL"), { BFD_RELOC_386_TLS_DESC_CALL,
BFD_RELOC_X86_64_TLSDESC_CALL },
OPERAND_TYPE_IMM32_32S_DISP32, true },
#else /* TE_PE */
{ STRING_COMMA_LEN ("SECREL32"), { BFD_RELOC_32_SECREL,
BFD_RELOC_32_SECREL },
OPERAND_TYPE_IMM32_32S_64_DISP32_64, false },
#endif
#undef OPERAND_TYPE_IMM32_32S_DISP32
#undef OPERAND_TYPE_IMM32_32S_64_DISP32
#undef OPERAND_TYPE_IMM32_32S_64_DISP32_64
#undef OPERAND_TYPE_IMM64_DISP64
};
/* 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 unsigned char f32_1[] =
{0x90}; /* nop */
static const unsigned char f32_2[] =
{0x66,0x90}; /* xchg %ax,%ax */
static const unsigned char f32_3[] =
{0x8d,0x76,0x00}; /* leal 0(%esi),%esi */
#define f32_4 (f32_5 + 1) /* leal 0(%esi,%eiz),%esi */
static const unsigned char f32_5[] =
{0x2e,0x8d,0x74,0x26,0x00}; /* leal %cs:0(%esi,%eiz),%esi */
static const unsigned char f32_6[] =
{0x8d,0xb6,0x00,0x00,0x00,0x00}; /* leal 0L(%esi),%esi */
#define f32_7 (f32_8 + 1) /* leal 0L(%esi,%eiz),%esi */
static const unsigned char f32_8[] =
{0x2e,0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal %cs:0L(%esi,%eiz),%esi */
static const unsigned char f64_3[] =
{0x48,0x89,0xf6}; /* mov %rsi,%rsi */
static const unsigned char f64_4[] =
{0x48,0x8d,0x76,0x00}; /* lea 0(%rsi),%rsi */
#define f64_5 (f64_6 + 1) /* lea 0(%rsi,%riz),%rsi */
static const unsigned char f64_6[] =
{0x2e,0x48,0x8d,0x74,0x26,0x00}; /* lea %cs:0(%rsi,%riz),%rsi */
static const unsigned char f64_7[] =
{0x48,0x8d,0xb6,0x00,0x00,0x00,0x00}; /* lea 0L(%rsi),%rsi */
#define f64_8 (f64_9 + 1) /* lea 0L(%rsi,%riz),%rsi */
static const unsigned char f64_9[] =
{0x2e,0x48,0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* lea %cs:0L(%rsi,%riz),%rsi */
#define f16_2 (f64_3 + 1) /* mov %si,%si */
static const unsigned char f16_3[] =
{0x8d,0x74,0x00}; /* lea 0(%si),%si */
#define f16_4 (f16_5 + 1) /* lea 0W(%si),%si */
static const unsigned char f16_5[] =
{0x2e,0x8d,0xb4,0x00,0x00}; /* lea %cs:0W(%si),%si */
static const unsigned char jump_disp8[] =
{0xeb}; /* jmp disp8 */
static const unsigned char jump32_disp32[] =
{0xe9}; /* jmp disp32 */
static const unsigned char jump16_disp32[] =
{0x66,0xe9}; /* jmp disp32 */
/* 32-bit NOPs patterns. */
static const unsigned char *const f32_patt[] = {
f32_1, f32_2, f32_3, f32_4, f32_5, f32_6, f32_7, f32_8
};
/* 64-bit NOPs patterns. */
static const unsigned char *const f64_patt[] = {
f32_1, f32_2, f64_3, f64_4, f64_5, f64_6, f64_7, f64_8, f64_9
};
/* 16-bit NOPs patterns. */
static const unsigned char *const f16_patt[] = {
f32_1, f16_2, f16_3, f16_4, f16_5
};
/* nopl (%[re]ax) */
static const unsigned char alt_3[] =
{0x0f,0x1f,0x00};
/* nopl 0(%[re]ax) */
static const unsigned char alt_4[] =
{0x0f,0x1f,0x40,0x00};
/* nopl 0(%[re]ax,%[re]ax,1) */
#define alt_5 (alt_6 + 1)
/* nopw 0(%[re]ax,%[re]ax,1) */
static const unsigned char alt_6[] =
{0x66,0x0f,0x1f,0x44,0x00,0x00};
/* nopl 0L(%[re]ax) */
static const unsigned char alt_7[] =
{0x0f,0x1f,0x80,0x00,0x00,0x00,0x00};
/* nopl 0L(%[re]ax,%[re]ax,1) */
#define alt_8 (alt_9 + 1)
/* nopw 0L(%[re]ax,%[re]ax,1) */
static const unsigned char alt_9[] =
{0x66,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
/* nopw %cs:0L(%[re]ax,%[re]ax,1) */
#define alt_10 (alt_11 + 1)
/* data16 nopw %cs:0L(%eax,%eax,1) */
static const unsigned char alt_11[] =
{0x66,0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
/* 32-bit and 64-bit NOPs patterns. */
static const unsigned char *const alt_patt[] = {
f32_1, f32_2, alt_3, alt_4, alt_5, alt_6, alt_7, alt_8,
alt_9, alt_10, alt_11
};
#define alt64_9 (alt64_15 + 6) /* nopq 0L(%rax,%rax,1) */
#define alt64_10 (alt64_15 + 5) /* cs nopq 0L(%rax,%rax,1) */
/* data16 cs nopq 0L(%rax,%rax,1) */
#define alt64_11 (alt64_15 + 4)
/* data16 data16 cs nopq 0L(%rax,%rax,1) */
#define alt64_12 (alt64_15 + 3)
/* data16 data16 data16 cs nopq 0L(%rax,%rax,1) */
#define alt64_13 (alt64_15 + 2)
/* data16 data16 data16 data16 cs nopq 0L(%rax,%rax,1) */
#define alt64_14 (alt64_15 + 1)
/* data16 data16 data16 data16 data16 cs nopq 0L(%rax,%rax,1) */
static const unsigned char alt64_15[] =
{0x66,0x66,0x66,0x66,0x66,0x2e,0x48,
0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00};
/* Long 64-bit NOPs patterns. */
static const unsigned char *const alt64_patt[] = {
f32_1, f32_2, alt_3, alt_4, alt_5, alt_6, alt_7, alt_8,
alt64_9, alt64_10, alt64_11,alt64_12, alt64_13, alt64_14, alt64_15
};
/* Genenerate COUNT bytes of NOPs to WHERE from PATT with the maximum
size of a single NOP instruction MAX_SINGLE_NOP_SIZE. */
static void
i386_output_nops (char *where, const unsigned char *const *patt,
int count, int max_single_nop_size)
{
/* Place the longer NOP first. */
int last;
int offset;
const unsigned char *nops;
if (max_single_nop_size < 1)
{
as_fatal (_("i386_output_nops called to generate nops of at most %d bytes!"),
max_single_nop_size);
return;
}
nops = patt[max_single_nop_size - 1];
last = count % max_single_nop_size;
count -= last;
for (offset = 0; offset < count; offset += max_single_nop_size)
memcpy (where + offset, nops, max_single_nop_size);
if (last)
{
nops = patt[last - 1];
memcpy (where + offset, nops, last);
}
}
static INLINE int
fits_in_imm7 (offsetT num)
{
return (num & 0x7f) == num;
}
static INLINE int
fits_in_imm31 (offsetT num)
{
return (num & 0x7fffffff) == num;
}
/* Genenerate COUNT bytes of NOPs to WHERE with the maximum size of a
single NOP instruction LIMIT. */
void
i386_generate_nops (fragS *fragP, char *where, offsetT count, int limit)
{
const unsigned char *const *patt = NULL;
int max_single_nop_size;
/* Maximum number of NOPs before switching to jump over NOPs. */
int max_number_of_nops;
switch (fragP->fr_type)
{
case rs_fill_nop:
case rs_align_code:
break;
case rs_machine_dependent:
/* Allow NOP padding for jumps and calls. */
if (TYPE_FROM_RELAX_STATE (fragP->fr_subtype) == BRANCH_PADDING
|| TYPE_FROM_RELAX_STATE (fragP->fr_subtype) == FUSED_JCC_PADDING)
break;
/* Fall through. */
default:
return;
}
/* We need to decide which NOP sequence to use for 32bit and
64bit. When -mtune= is used:
1. For PROCESSOR_I?86, PROCESSOR_PENTIUM, PROCESSOR_IAMCU, and
PROCESSOR_GENERIC32, f32_patt will be used.
2. For the rest, alt_patt will be used.
When -mtune= isn't used, alt_patt will be used if
cpu_arch_isa_flags has CpuNop. Otherwise, f32_patt/f64_patt will
be used.
When -march= or .arch is used, we can't use anything beyond
cpu_arch_isa_flags. */
if (fragP->tc_frag_data.code == CODE_16BIT)
{
patt = f16_patt;
max_single_nop_size = sizeof (f16_patt) / sizeof (f16_patt[0]);
/* Limit number of NOPs to 2 in 16-bit mode. */
max_number_of_nops = 2;
}
else
{
patt = fragP->tc_frag_data.code == CODE_64BIT ? f64_patt : f32_patt;
if (fragP->tc_frag_data.isa == PROCESSOR_UNKNOWN)
{
/* PROCESSOR_UNKNOWN means that all ISAs may be used, unless
explicitly disabled. */
switch (fragP->tc_frag_data.tune)
{
case PROCESSOR_UNKNOWN:
/* We use cpu_arch_isa_flags to check if we SHOULD
optimize with nops. */
if (fragP->tc_frag_data.isanop)
patt = alt_patt;
break;
case PROCESSOR_CORE:
case PROCESSOR_CORE2:
case PROCESSOR_COREI7:
if (fragP->tc_frag_data.cpunop)
{
if (fragP->tc_frag_data.code == CODE_64BIT)
patt = alt64_patt;
else
patt = alt_patt;
}
break;
case PROCESSOR_PENTIUMPRO:
case PROCESSOR_PENTIUM4:
case PROCESSOR_NOCONA:
case PROCESSOR_GENERIC64:
case PROCESSOR_K6:
case PROCESSOR_ATHLON:
case PROCESSOR_K8:
case PROCESSOR_AMDFAM10:
case PROCESSOR_BD:
case PROCESSOR_ZNVER:
case PROCESSOR_BT:
if (fragP->tc_frag_data.cpunop)
patt = alt_patt;
break;
case PROCESSOR_I386:
case PROCESSOR_I486:
case PROCESSOR_PENTIUM:
case PROCESSOR_I686:
case PROCESSOR_IAMCU:
case PROCESSOR_GENERIC32:
break;
case PROCESSOR_NONE:
abort ();
}
}
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;
default:
/* We use cpu_arch_isa_flags to check if we CAN optimize
with nops. */
if (fragP->tc_frag_data.isanop)
patt = alt_patt;
break;
case PROCESSOR_NONE:
abort ();
}
}
if (patt != alt_patt && patt != alt64_patt)
{
max_single_nop_size = patt == f32_patt ? ARRAY_SIZE (f32_patt)
: ARRAY_SIZE (f64_patt);
/* Limit number of NOPs to 2 for older processors. */
max_number_of_nops = 2;
}
else
{
max_single_nop_size = patt == alt_patt
? ARRAY_SIZE (alt_patt)
: ARRAY_SIZE (alt64_patt);
/* Limit number of NOPs to 7 for newer processors. */
max_number_of_nops = 7;
}
}
if (limit == 0)
limit = max_single_nop_size;
if (fragP->fr_type == rs_fill_nop)
{
/* Output NOPs for .nop directive. */
if (limit > max_single_nop_size)
{
as_bad_where (fragP->fr_file, fragP->fr_line,
_("invalid single nop size: %d "
"(expect within [0, %d])"),
limit, max_single_nop_size);
return;
}
}
else if (fragP->fr_type != rs_machine_dependent)
fragP->fr_var = count;
/* Emit a plain NOP first when the last thing we saw may not have been
a proper instruction (e.g. a stand-alone prefix or .byte). */
if (!fragP->tc_frag_data.last_insn_normal)
{
*where++ = 0x90;
--count;
}
if ((count / max_single_nop_size) > max_number_of_nops)
{
/* Generate jump over NOPs. */
offsetT disp = count - 2;
if (fits_in_imm7 (disp))
{
/* Use "jmp disp8" if possible. */
count = disp;
where[0] = jump_disp8[0];
where[1] = count;
where += 2;
}
else
{
unsigned int size_of_jump;
if (flag_code == CODE_16BIT)
{
where[0] = jump16_disp32[0];
where[1] = jump16_disp32[1];
size_of_jump = 2;
}
else
{
where[0] = jump32_disp32[0];
size_of_jump = 1;
}
count -= size_of_jump + 4;
if (!fits_in_imm31 (count))
{
as_bad_where (fragP->fr_file, fragP->fr_line,
_("jump over nop padding out of range"));
return;
}
md_number_to_chars (where + size_of_jump, count, 4);
where += size_of_jump + 4;
}
}
/* Generate multiple NOPs. */
i386_output_nops (where, patt, count, limit);
}
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;
/* Fall through. */
case 2:
if (x->array[1])
return 0;
/* Fall through. */
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;
/* Fall through. */
case 2:
x->array[1] = v;
/* Fall through. */
case 1:
x->array[0] = v;
/* Fall through. */
break;
default:
abort ();
}
x->bitfield.class = ClassNone;
x->bitfield.instance = InstanceNone;
}
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;
/* Fall through. */
case 2:
if (x->array[1] != y->array[1])
return 0;
/* Fall through. */
case 1:
return x->array[0] == y->array[0];
break;
default:
abort ();
}
}
static INLINE bool
_is_cpu (const i386_cpu_attr *a, enum i386_cpu cpu)
{
switch (cpu)
{
case Cpu287: return a->bitfield.cpu287;
case Cpu387: return a->bitfield.cpu387;
case Cpu3dnow: return a->bitfield.cpu3dnow;
case Cpu3dnowA: return a->bitfield.cpu3dnowa;
case CpuAVX: return a->bitfield.cpuavx;
case CpuHLE: return a->bitfield.cpuhle;
case CpuAVX512F: return a->bitfield.cpuavx512f;
case CpuAVX512VL: return a->bitfield.cpuavx512vl;
case CpuAPX_F: return a->bitfield.cpuapx_f;
case Cpu64: return a->bitfield.cpu64;
case CpuNo64: return a->bitfield.cpuno64;
default:
gas_assert (cpu < CpuAttrEnums);
}
return a->bitfield.isa == cpu + 1u;
}
static INLINE bool
is_cpu (const insn_template *t, enum i386_cpu cpu)
{
return _is_cpu(&t->cpu, cpu);
}
static INLINE bool
maybe_cpu (const insn_template *t, enum i386_cpu cpu)
{
return _is_cpu(&t->cpu_any, cpu);
}
static i386_cpu_flags cpu_flags_from_attr (i386_cpu_attr a)
{
const unsigned int bps = sizeof (a.array[0]) * CHAR_BIT;
i386_cpu_flags f = { .array[0] = 0 };
switch (ARRAY_SIZE (a.array))
{
case 1:
f.array[CpuAttrEnums / bps]
#ifndef WORDS_BIGENDIAN
|= (a.array[0] >> CpuIsaBits) << (CpuAttrEnums % bps);
#else
|= (a.array[0] << CpuIsaBits) >> (CpuAttrEnums % bps);
#endif
if (CpuMax / bps > CpuAttrEnums / bps)
f.array[CpuAttrEnums / bps + 1]
#ifndef WORDS_BIGENDIAN
= (a.array[0] >> CpuIsaBits) >> (bps - CpuAttrEnums % bps);
#else
= (a.array[0] << CpuIsaBits) << (bps - CpuAttrEnums % bps);
#endif
break;
default:
abort ();
}
if (a.bitfield.isa)
#ifndef WORDS_BIGENDIAN
f.array[(a.bitfield.isa - 1) / bps] |= 1u << ((a.bitfield.isa - 1) % bps);
#else
f.array[(a.bitfield.isa - 1) / bps] |= 1u << (~(a.bitfield.isa - 1) % bps);
#endif
return f;
}
static INLINE int
cpu_flags_all_zero (const union i386_cpu_flags *x)
{
switch (ARRAY_SIZE(x->array))
{
case 5:
if (x->array[4])
return 0;
/* Fall through. */
case 4:
if (x->array[3])
return 0;
/* Fall through. */
case 3:
if (x->array[2])
return 0;
/* Fall through. */
case 2:
if (x->array[1])
return 0;
/* Fall through. */
case 1:
return !x->array[0];
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 5:
if (x->array[4] != y->array[4])
return 0;
/* Fall through. */
case 4:
if (x->array[3] != y->array[3])
return 0;
/* Fall through. */
case 3:
if (x->array[2] != y->array[2])
return 0;
/* Fall through. */
case 2:
if (x->array[1] != y->array[1])
return 0;
/* Fall through. */
case 1:
return x->array[0] == y->array[0];
break;
default:
abort ();
}
}
static INLINE int
cpu_flags_check_cpu64 (const insn_template *t)
{
return flag_code == CODE_64BIT
? !t->cpu.bitfield.cpuno64
: !t->cpu.bitfield.cpu64;
}
static INLINE i386_cpu_flags
cpu_flags_and (i386_cpu_flags x, i386_cpu_flags y)
{
switch (ARRAY_SIZE (x.array))
{
case 5:
x.array [4] &= y.array [4];
/* Fall through. */
case 4:
x.array [3] &= y.array [3];
/* Fall through. */
case 3:
x.array [2] &= y.array [2];
/* Fall through. */
case 2:
x.array [1] &= y.array [1];
/* Fall through. */
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 5:
x.array [4] |= y.array [4];
/* Fall through. */
case 4:
x.array [3] |= y.array [3];
/* Fall through. */
case 3:
x.array [2] |= y.array [2];
/* Fall through. */
case 2:
x.array [1] |= y.array [1];
/* Fall through. */
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 5:
x.array [4] &= ~y.array [4];
/* Fall through. */
case 4:
x.array [3] &= ~y.array [3];
/* Fall through. */
case 3:
x.array [2] &= ~y.array [2];
/* Fall through. */
case 2:
x.array [1] &= ~y.array [1];
/* Fall through. */
case 1:
x.array [0] &= ~y.array [0];
break;
default:
abort ();
}
return x;
}
static const i386_cpu_flags avx512 = CPU_ANY_AVX512F_FLAGS;
static INLINE bool need_evex_encoding (const insn_template *t)
{
return pp.encoding == encoding_evex
|| pp.encoding == encoding_evex512
|| pp.has_nf
|| (t->opcode_modifier.vex && pp.encoding == encoding_egpr)
|| i.mask.reg;
}
#define CPU_FLAGS_ARCH_MATCH 0x1
#define CPU_FLAGS_64BIT_MATCH 0x2
#define CPU_FLAGS_PERFECT_MATCH \
(CPU_FLAGS_ARCH_MATCH | CPU_FLAGS_64BIT_MATCH)
static INLINE bool set_oszc_flags (unsigned int oszc_shift)
{
if (i.oszc_flags & oszc_shift)
{
as_bad (_("same oszc flag used twice"));
return false;
}
i.oszc_flags |= oszc_shift;
return true;
}
/* Handle SCC OSZC flags. */
static int
check_Scc_OszcOperations (const char *l)
{
const char *suffix_string = l;
while (is_space_char (*suffix_string))
suffix_string++;
/* If {oszc flags} is absent, just return. */
if (*suffix_string != '{')
return 0;
/* Skip '{'. */
suffix_string++;
/* Parse 'dfv='. */
while (is_space_char (*suffix_string))
suffix_string++;
if (strncasecmp (suffix_string, "dfv", 3) == 0)
suffix_string += 3;
else
{
as_bad (_("unrecognized pseudo-suffix"));
return -1;
}
while (is_space_char (*suffix_string))
suffix_string++;
if (*suffix_string == '=')
suffix_string++;
else
{
as_bad (_("unrecognized pseudo-suffix"));
return -1;
}
/* Parse 'of, sf, zf, cf}'. */
while (*suffix_string)
{
while (is_space_char (*suffix_string))
suffix_string++;
/* Return for '{dfv=}'. */
if (*suffix_string == '}')
return suffix_string + 1 - l;
if (strncasecmp (suffix_string, "of", 2) == 0)
{
if (!set_oszc_flags (OSZC_OF))
return -1;
}
else if (strncasecmp (suffix_string, "sf", 2) == 0)
{
if (!set_oszc_flags (OSZC_SF))
return -1;
}
else if (strncasecmp (suffix_string, "zf", 2) == 0)
{
if (!set_oszc_flags (OSZC_ZF))
return -1;
}
else if (strncasecmp (suffix_string, "cf", 2) == 0)
{
if (!set_oszc_flags (OSZC_CF))
return -1;
}
else
{
as_bad (_("unrecognized oszc flags or illegal `,' in pseudo-suffix"));
return -1;
}
suffix_string += 2;
while (is_space_char (*suffix_string))
suffix_string++;
if (*suffix_string == '}')
return ++suffix_string - l;
if (*suffix_string != ',')
break;
suffix_string ++;
}
as_bad (_("missing `}' or `,' in pseudo-suffix"));
return -1;
}
/* Return CPU flags match bits. */
static int
cpu_flags_match (const insn_template *t)
{
i386_cpu_flags cpu, active, all = cpu_flags_from_attr (t->cpu);
i386_cpu_flags any = cpu_flags_from_attr (t->cpu_any);
int match = cpu_flags_check_cpu64 (t) ? CPU_FLAGS_64BIT_MATCH : 0;
all.bitfield.cpu64 = 0;
all.bitfield.cpuno64 = 0;
gas_assert (!any.bitfield.cpu64);
gas_assert (!any.bitfield.cpuno64);
if (cpu_flags_all_zero (&all) && cpu_flags_all_zero (&any))
{
/* This instruction is available on all archs. */
return match | CPU_FLAGS_ARCH_MATCH;
}
/* This instruction is available only on some archs. */
/* Dual VEX/EVEX templates may need stripping of one of the flags. */
if (t->opcode_modifier.vex && t->opcode_modifier.evex)
{
/* Dual AVX/AVX512 templates need to retain AVX512* only if we already
know that EVEX encoding will be needed. */
if ((any.bitfield.cpuavx || any.bitfield.cpuavx2 || any.bitfield.cpufma)
&& (any.bitfield.cpuavx512f || any.bitfield.cpuavx512vl))
{
if (need_evex_encoding (t))
{
any.bitfield.cpuavx = 0;
any.bitfield.cpuavx2 = 0;
any.bitfield.cpufma = 0;
}
/* need_evex_encoding(t) isn't reliable before operands were
parsed. */
else if (i.operands)
{
any.bitfield.cpuavx512f = 0;
any.bitfield.cpuavx512vl = 0;
}
}
/* Dual non-APX/APX templates need massaging from what APX_F() in the
opcode table has produced. While the direct transformation of the
incoming cpuid&(cpuid|APX_F) would be to cpuid&(cpuid) / cpuid&(APX_F)
respectively, it's cheaper to move to just cpuid / cpuid&APX_F
instead. */
if (any.bitfield.cpuapx_f
&& (any.bitfield.cpubmi || any.bitfield.cpubmi2
|| any.bitfield.cpuavx512f || any.bitfield.cpuavx512bw
|| any.bitfield.cpuavx512dq || any.bitfield.cpuamx_tile
|| any.bitfield.cpucmpccxadd || any.bitfield.cpuuser_msr))
{
/* These checks (verifying that APX_F() was properly used in the
opcode table entry) make sure there's no need for an "else" to
the "if()" below. */
gas_assert (!cpu_flags_all_zero (&all));
cpu = cpu_flags_and (all, any);
gas_assert (cpu_flags_equal (&cpu, &all));
if (need_evex_encoding (t))
all = any;
memset (&any, 0, sizeof (any));
}
}
if (flag_code != CODE_64BIT)
active = cpu_flags_and_not (cpu_arch_flags, cpu_64_flags);
else
active = cpu_arch_flags;
cpu = cpu_flags_and (all, active);
if (cpu_flags_equal (&cpu, &all))
{
/* AVX and AVX2 present at the same time express an operand size
dependency - strip AVX2 for the purposes here. The operand size
dependent check occurs in check_vecOperands(). */
if (any.bitfield.cpuavx && any.bitfield.cpuavx2)
any.bitfield.cpuavx2 = 0;
cpu = cpu_flags_and (any, active);
if (cpu_flags_all_zero (&any) || !cpu_flags_all_zero (&cpu))
match |= CPU_FLAGS_ARCH_MATCH;
}
return match;
}
static INLINE i386_operand_type
operand_type_and (i386_operand_type x, i386_operand_type y)
{
if (x.bitfield.class != y.bitfield.class)
x.bitfield.class = ClassNone;
if (x.bitfield.instance != y.bitfield.instance)
x.bitfield.instance = InstanceNone;
switch (ARRAY_SIZE (x.array))
{
case 3:
x.array [2] &= y.array [2];
/* Fall through. */
case 2:
x.array [1] &= y.array [1];
/* Fall through. */
case 1:
x.array [0] &= y.array [0];
break;
default:
abort ();
}
return x;
}
static INLINE i386_operand_type
operand_type_and_not (i386_operand_type x, i386_operand_type y)
{
gas_assert (y.bitfield.class == ClassNone);
gas_assert (y.bitfield.instance == InstanceNone);
switch (ARRAY_SIZE (x.array))
{
case 3:
x.array [2] &= ~y.array [2];
/* Fall through. */
case 2:
x.array [1] &= ~y.array [1];
/* Fall through. */
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)
{
gas_assert (x.bitfield.class == ClassNone ||
y.bitfield.class == ClassNone ||
x.bitfield.class == y.bitfield.class);
gas_assert (x.bitfield.instance == InstanceNone ||
y.bitfield.instance == InstanceNone ||
x.bitfield.instance == y.bitfield.instance);
switch (ARRAY_SIZE (x.array))
{
case 3:
x.array [2] |= y.array [2];
/* Fall through. */
case 2:
x.array [1] |= y.array [1];
/* Fall through. */
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)
{
gas_assert (y.bitfield.class == ClassNone);
gas_assert (y.bitfield.instance == InstanceNone);
switch (ARRAY_SIZE (x.array))
{
case 3:
x.array [2] ^= y.array [2];
/* Fall through. */
case 2:
x.array [1] ^= y.array [1];
/* Fall through. */
case 1:
x.array [0] ^= y.array [0];
break;
default:
abort ();
}
return x;
}
static const i386_operand_type anydisp = {
.bitfield = { .disp8 = 1, .disp16 = 1, .disp32 = 1, .disp64 = 1 }
};
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.class == Reg;
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.disp64);
case anymem:
return (t.bitfield.disp8
|| t.bitfield.disp16
|| t.bitfield.disp32
|| t.bitfield.disp64
|| t.bitfield.baseindex);
default:
abort ();
}
return 0;
}
/* Return 1 if there is no conflict in 8bit/16bit/32bit/64bit/80bit size
between operand GIVEN and opeand WANTED for instruction template T. */
static INLINE int
match_operand_size (const insn_template *t, unsigned int wanted,
unsigned int given)
{
return !((i.types[given].bitfield.byte
&& !t->operand_types[wanted].bitfield.byte)
|| (i.types[given].bitfield.word
&& !t->operand_types[wanted].bitfield.word)
|| (i.types[given].bitfield.dword
&& !t->operand_types[wanted].bitfield.dword)
|| (i.types[given].bitfield.qword
&& (!t->operand_types[wanted].bitfield.qword
/* Don't allow 64-bit (memory) operands outside of 64-bit
mode, when they're used where a 64-bit GPR could also
be used. Checking is needed for Intel Syntax only. */
|| (intel_syntax
&& flag_code != CODE_64BIT
&& (t->operand_types[wanted].bitfield.class == Reg
|| t->operand_types[wanted].bitfield.class == Accum
|| t->opcode_modifier.isstring))))
|| (i.types[given].bitfield.tbyte
&& !t->operand_types[wanted].bitfield.tbyte));
}
/* Return 1 if there is no conflict in SIMD register between operand
GIVEN and opeand WANTED for instruction template T. */
static INLINE int
match_simd_size (const insn_template *t, unsigned int wanted,
unsigned int given)
{
return !((i.types[given].bitfield.xmmword
&& !t->operand_types[wanted].bitfield.xmmword)
|| (i.types[given].bitfield.ymmword
&& !t->operand_types[wanted].bitfield.ymmword)
|| (i.types[given].bitfield.zmmword
&& !t->operand_types[wanted].bitfield.zmmword)
|| (i.types[given].bitfield.tmmword
&& !t->operand_types[wanted].bitfield.tmmword));
}
/* Return 1 if there is no conflict in any size between operand GIVEN
and opeand WANTED for instruction template T. */
static INLINE int
match_mem_size (const insn_template *t, unsigned int wanted,
unsigned int given)
{
return (match_operand_size (t, wanted, given)
&& !((i.types[given].bitfield.unspecified
&& !i.broadcast.type
&& !i.broadcast.bytes
&& !t->operand_types[wanted].bitfield.unspecified)
|| (i.types[given].bitfield.fword
&& !t->operand_types[wanted].bitfield.fword)
/* For scalar opcode templates to allow register and memory
operands at the same time, some special casing is needed
here. Also for v{,p}broadcast*, {,v}pmov{s,z}*, and
down-conversion vpmov*. */
|| ((t->operand_types[wanted].bitfield.class == RegSIMD
&& t->operand_types[wanted].bitfield.byte
+ t->operand_types[wanted].bitfield.word
+ t->operand_types[wanted].bitfield.dword
+ t->operand_types[wanted].bitfield.qword
> !!t->opcode_modifier.broadcast)
? (i.types[given].bitfield.xmmword
|| i.types[given].bitfield.ymmword
|| i.types[given].bitfield.zmmword)
: !match_simd_size(t, wanted, given))));
}
/* Return value has MATCH_STRAIGHT set if there is no size conflict on any
operands for instruction template T, and it has MATCH_REVERSE set if there
is no size conflict on any operands for the template with operands reversed
(and the template allows for reversing in the first place). */
#define MATCH_STRAIGHT 1
#define MATCH_REVERSE 2
static INLINE unsigned int
operand_size_match (const insn_template *t)
{
unsigned int j, match = MATCH_STRAIGHT;
/* Don't check non-absolute jump instructions. */
if (t->opcode_modifier.jump
&& t->opcode_modifier.jump != JUMP_ABSOLUTE)
return match;
/* Check memory and accumulator operand size. */
for (j = 0; j < i.operands; j++)
{
if (i.types[j].bitfield.class != Reg
&& i.types[j].bitfield.class != RegSIMD
&& t->opcode_modifier.operandconstraint == ANY_SIZE)
continue;
if (t->operand_types[j].bitfield.class == Reg
&& !match_operand_size (t, j, j))
{
match = 0;
break;
}
if (t->operand_types[j].bitfield.class == RegSIMD
&& !match_simd_size (t, j, j))
{
match = 0;
break;
}
if (t->operand_types[j].bitfield.instance == Accum
&& (!match_operand_size (t, j, j) || !match_simd_size (t, j, j)))
{
match = 0;
break;
}
if ((i.flags[j] & Operand_Mem) && !match_mem_size (t, j, j))
{
match = 0;
break;
}
}
if (!t->opcode_modifier.d)
return match;
/* Check reverse. */
gas_assert (i.operands >= 2);
for (j = 0; j < i.operands; j++)
{
unsigned int given = i.operands - j - 1;
/* For FMA4 and XOP insns VEX.W controls just the first two
register operands. And APX_F insns just swap the two source operands,
with the 3rd one being the destination. */
if (is_cpu (t, CpuFMA4) || is_cpu (t, CpuXOP)
|| is_cpu (t, CpuAPX_F))
given = j < 2 ? 1 - j : j;
if (t->operand_types[j].bitfield.class == Reg
&& !match_operand_size (t, j, given))
return match;
if (t->operand_types[j].bitfield.class == RegSIMD
&& !match_simd_size (t, j, given))
return match;
if (t->operand_types[j].bitfield.instance == Accum
&& (!match_operand_size (t, j, given)
|| !match_simd_size (t, j, given)))
return match;
if ((i.flags[given] & Operand_Mem) && !match_mem_size (t, j, given))
return match;
}
return match | MATCH_REVERSE;
}
static INLINE int
operand_type_match (i386_operand_type overlap,
i386_operand_type given)
{
i386_operand_type temp = overlap;
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;
temp.bitfield.tmmword = 0;
if (operand_type_all_zero (&temp))
goto mismatch;
if (given.bitfield.baseindex == overlap.bitfield.baseindex)
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.
Intel syntax sized memory operands are also checked here. */
static INLINE int
operand_type_register_match (i386_operand_type g0,
i386_operand_type t0,
i386_operand_type g1,
i386_operand_type t1)
{
if (g0.bitfield.class != Reg
&& g0.bitfield.class != RegSIMD
&& (g0.bitfield.unspecified
|| !operand_type_check (g0, anymem)))
return 1;
if (g1.bitfield.class != Reg
&& g1.bitfield.class != RegSIMD
&& (g1.bitfield.unspecified
|| !operand_type_check (g1, anymem)))
return 1;
if (g0.bitfield.byte == g1.bitfield.byte
&& g0.bitfield.word == g1.bitfield.word
&& g0.bitfield.dword == g1.bitfield.dword
&& g0.bitfield.qword == g1.bitfield.qword
&& g0.bitfield.xmmword == g1.bitfield.xmmword
&& g0.bitfield.ymmword == g1.bitfield.ymmword
&& g0.bitfield.zmmword == g1.bitfield.zmmword)
return 1;
/* If expectations overlap in no more than a single size, all is fine. */
g0 = operand_type_and (t0, t1);
if (g0.bitfield.byte
+ g0.bitfield.word
+ g0.bitfield.dword
+ g0.bitfield.qword
+ g0.bitfield.xmmword
+ g0.bitfield.ymmword
+ g0.bitfield.zmmword <= 1)
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;
if (r->reg_flags & (RegVRex | RegRex2))
nr += 16;
return nr;
}
static INLINE unsigned int
mode_from_disp_size (i386_operand_type t)
{
if (t.bitfield.disp8)
return 1;
else if (t.bitfield.disp16
|| t.bitfield.disp32)
return 2;
else
return 0;
}
static INLINE int
fits_in_signed_byte (addressT num)
{
return num + 0x80 <= 0xff;
}
static INLINE int
fits_in_unsigned_byte (addressT num)
{
return num <= 0xff;
}
static INLINE int
fits_in_unsigned_word (addressT num)
{
return num <= 0xffff;
}
static INLINE int
fits_in_signed_word (addressT num)
{
return num + 0x8000 <= 0xffff;
}
static INLINE int
fits_in_signed_long (addressT num ATTRIBUTE_UNUSED)
{
#ifndef BFD64
return 1;
#else
return num + 0x80000000 <= 0xffffffff;
#endif
} /* fits_in_signed_long() */
static INLINE int
fits_in_unsigned_long (addressT num ATTRIBUTE_UNUSED)
{
#ifndef BFD64
return 1;
#else
return num <= 0xffffffff;
#endif
} /* fits_in_unsigned_long() */
static INLINE valueT extend_to_32bit_address (addressT num)
{
#ifdef BFD64
if (fits_in_unsigned_long(num))
return (num ^ ((addressT) 1 << 31)) - ((addressT) 1 << 31);
if (!fits_in_signed_long (num))
return num & 0xffffffff;
#endif
return num;
}
static INLINE int
fits_in_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)
{
/* Despite the name, check for imm3 if we're dealing with EVEX. */
return (num & (pp.encoding != encoding_evex
&& pp.encoding != encoding_egpr ? 0xf : 7)) == 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))
{
if (fits_in_unsigned_byte (num))
t.bitfield.imm8 = 1;
t.bitfield.imm8s = 1;
t.bitfield.imm16 = 1;
if (flag_code != CODE_64BIT || fits_in_unsigned_long (num))
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;
if (flag_code != CODE_64BIT || fits_in_unsigned_long (num))
t.bitfield.imm32 = 1;
t.bitfield.imm32s = 1;
}
else if (fits_in_signed_long (num))
{
if (flag_code != CODE_64BIT || fits_in_unsigned_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;
#ifdef BFD64
case 4: mask = ((addressT) 1 << 32) - 1; break;
#endif
case sizeof (val): return val;
default: abort ();
}
if ((val & ~mask) != 0 && (-val & ~mask) != 0)
as_warn (_("0x%" PRIx64 " shortened to 0x%" PRIx64),
(uint64_t) val, (uint64_t) (val & mask));
return val & mask;
}
static INLINE const char *insn_name (const insn_template *t)
{
return &i386_mnemonics[t->mnem_off];
}
enum PREFIX_GROUP
{
PREFIX_EXIST = 0,
PREFIX_LOCK,
PREFIX_REP,
PREFIX_DS,
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_DS if ds prefix is added.
e. 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] & prefix & REX_R)
|| (i.prefix[REX_PREFIX] & prefix & REX_X)
|| (i.prefix[REX_PREFIX] & prefix & REX_B))
ret = PREFIX_EXIST;
q = REX_PREFIX;
}
else
{
switch (prefix)
{
default:
abort ();
case DS_PREFIX_OPCODE:
ret = PREFIX_DS;
/* Fall through. */
case CS_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)) = check ? as_fatal : as_bad;
if (value == CODE_64BIT && !cpu_arch_flags.bitfield.cpu64 )
{
as_error (_("64bit mode not supported on `%s'."),
cpu_arch_name ? cpu_arch_name : default_arch);
return;
}
if (value == CODE_32BIT && !cpu_arch_flags.bitfield.cpui386)
{
as_error (_("32bit mode not supported on `%s'."),
cpu_arch_name ? cpu_arch_name : default_arch);
return;
}
flag_code = (enum flag_code) value;
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 ();
stackop_size = LONG_MNEM_SUFFIX;
}
static void
_set_intel_syntax (int syntax_flag)
{
intel_syntax = syntax_flag;
expr_set_rank (O_full_ptr, syntax_flag ? 10 : 0);
register_prefix = allow_naked_reg ? "" : "%";
}
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;
int e = get_symbol_name (&string);
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."));
(void) restore_line_pointer (e);
}
demand_empty_rest_of_line ();
if (ask_naked_reg == 0)
allow_naked_reg = (syntax_flag
&& (bfd_get_symbol_leading_char (stdoutput) != '\0'));
else
allow_naked_reg = (ask_naked_reg < 0);
_set_intel_syntax (syntax_flag);
}
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;
int e = get_symbol_name (&string);
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);
(void) restore_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 MCU 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;
}