/* tc-i386.c -- Assemble code for the Intel 80386
- Copyright (C) 1989-2022 Free Software Foundation, Inc.
+ Copyright (C) 1989-2023 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
#include "subsegs.h"
#include "dwarf2dbg.h"
#include "dw2gencfi.h"
+#include "gen-sframe.h"
+#include "sframe.h"
#include "elf/x86-64.h"
#include "opcodes/i386-init.h"
#include <limits.h>
#define SHORT_MNEM_SUFFIX 's'
#define LONG_MNEM_SUFFIX 'l'
#define QWORD_MNEM_SUFFIX 'q'
-/* 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'
+#define OPERAND_TYPE_NONE { .bitfield = { .class = ClassNone } }
+
/* This matches the C -> StaticRounding alias in the opcode table. */
#define commutative staticrounding
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 const char *parse_insn (const char *, char *);
static char *parse_operands (char *, const char *);
static void swap_operands (void);
static void swap_2_operands (unsigned int, unsigned int);
unsupported_with_intel_mnemonic,
unsupported_syntax,
unsupported,
+ unsupported_on_arch,
+ unsupported_64bit,
invalid_sib_address,
invalid_vsib_address,
invalid_vector_register_set,
explicit segment overrides are given. */
const reg_entry *seg[2];
- /* Copied first memory operand string, for re-checking. */
- char *memop1_string;
-
/* PREFIX holds all the given prefix opcodes (usually null).
PREFIXES is the number of prefix opcodes. */
unsigned int prefixes;
/* 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
{
{ 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[] = "*%-([{}"
#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 unwind info. */
+unsigned int x86_sframe_cfa_fp_reg;
+unsigned int x86_sframe_cfa_ra_reg;
+
#endif
/* 1 for intel syntax,
ARCH (generic32, GENERIC32, GENERIC32, false),
ARCH (generic64, GENERIC64, GENERIC64, false),
ARCH (i8086, UNKNOWN, NONE, false),
- ARCH (i186, UNKNOWN, I186, false),
- ARCH (i286, UNKNOWN, I286, false),
- ARCH (i386, I386, I386, false),
- ARCH (i486, I486, I486, false),
- ARCH (i586, PENTIUM, I586, false),
- ARCH (i686, PENTIUMPRO, I686, false),
- ARCH (pentium, PENTIUM, I586, 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 (i686, PENTIUMPRO, 686, false),
+ ARCH (pentium, PENTIUM, 586, false),
ARCH (pentiumpro, PENTIUMPRO, PENTIUMPRO, false),
ARCH (pentiumii, PENTIUMPRO, P2, false),
ARCH (pentiumiii, PENTIUMPRO, P3, false),
ARCH (znver1, ZNVER, ZNVER1, false),
ARCH (znver2, ZNVER, ZNVER2, false),
ARCH (znver3, ZNVER, ZNVER3, false),
+ ARCH (znver4, ZNVER, ZNVER4, false),
ARCH (btver1, BT, BTVER1, false),
ARCH (btver2, BT, BTVER2, false),
- SUBARCH (8087, 8087, ANY_X87, false),
- SUBARCH (87, NONE, ANY_X87, false), /* Disable only! */
+ 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, ANY_CMOV, 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 (avx512dq, AVX512DQ, ANY_AVX512DQ, false),
SUBARCH (avx512bw, AVX512BW, ANY_AVX512BW, false),
SUBARCH (avx512vl, AVX512VL, ANY_AVX512VL, false),
- SUBARCH (vmx, VMX, VMX, false),
- SUBARCH (vmfunc, VMFUNC, VMFUNC, false),
+ SUBARCH (vmx, VMX, ANY_VMX, false),
+ SUBARCH (vmfunc, VMFUNC, ANY_VMFUNC, false),
SUBARCH (smx, SMX, SMX, false),
- SUBARCH (xsave, XSAVE, XSAVE, false),
- SUBARCH (xsaveopt, XSAVEOPT, XSAVEOPT, false),
- SUBARCH (xsavec, XSAVEC, XSAVEC, false),
- SUBARCH (xsaves, XSAVES, XSAVES, false),
- SUBARCH (aes, AES, AES, false),
- SUBARCH (pclmul, PCLMUL, PCLMUL, false),
- SUBARCH (clmul, PCLMUL, PCLMUL, true),
+ 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, PCLMUL, ANY_PCLMUL, false),
+ SUBARCH (clmul, PCLMUL, ANY_PCLMUL, true),
SUBARCH (fsgsbase, FSGSBASE, FSGSBASE, false),
SUBARCH (rdrnd, RDRND, RDRND, false),
- SUBARCH (f16c, F16C, F16C, false),
+ SUBARCH (f16c, F16C, ANY_F16C, false),
SUBARCH (bmi2, BMI2, BMI2, false),
- SUBARCH (fma, FMA, FMA, false),
- SUBARCH (fma4, FMA4, FMA4, false),
- SUBARCH (xop, XOP, XOP, false),
- SUBARCH (lwp, LWP, LWP, 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 (ept, EPT, EPT, 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, RTM, 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, 3DNOW, false),
- SUBARCH (3dnowa, 3DNOWA, 3DNOWA, false),
+ SUBARCH (3dnow, 3DNOW, ANY_3DNOW, false),
+ SUBARCH (3dnowa, 3DNOWA, ANY_3DNOWA, false),
SUBARCH (padlock, PADLOCK, PADLOCK, false),
- SUBARCH (pacifica, SVME, SVME, true),
- SUBARCH (svme, SVME, SVME, false),
- SUBARCH (sse4a, SSE4A, SSE4A, 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 (rdseed, RDSEED, RDSEED, false),
SUBARCH (prfchw, PRFCHW, PRFCHW, false),
SUBARCH (smap, SMAP, SMAP, false),
- SUBARCH (mpx, MPX, MPX, false),
- SUBARCH (sha, SHA, SHA, 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 (avx_vnni, AVX_VNNI, ANY_AVX_VNNI, false),
SUBARCH (clzero, CLZERO, CLZERO, false),
SUBARCH (mwaitx, MWAITX, MWAITX, false),
- SUBARCH (ospke, OSPKE, OSPKE, false),
+ SUBARCH (ospke, OSPKE, ANY_OSPKE, false),
SUBARCH (rdpid, RDPID, RDPID, false),
SUBARCH (ptwrite, PTWRITE, PTWRITE, false),
- SUBARCH (ibt, IBT, ANY_IBT, false),
- SUBARCH (shstk, SHSTK, ANY_SHSTK, false),
- SUBARCH (gfni, GFNI, GFNI, false),
- SUBARCH (vaes, VAES, VAES, false),
- SUBARCH (vpclmulqdq, VPCLMULQDQ, VPCLMULQDQ, false),
+ SUBARCH (ibt, IBT, IBT, false),
+ SUBARCH (shstk, SHSTK, SHSTK, false),
+ SUBARCH (gfni, GFNI, ANY_GFNI, false),
+ SUBARCH (vaes, VAES, ANY_VAES, false),
+ SUBARCH (vpclmulqdq, VPCLMULQDQ, ANY_VPCLMULQDQ, false),
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, AMX_FP16, false),
+ SUBARCH (amx_fp16, AMX_FP16, ANY_AMX_FP16, false),
SUBARCH (amx_tile, AMX_TILE, ANY_AMX_TILE, false),
- SUBARCH (movdiri, MOVDIRI, ANY_MOVDIRI, false),
- SUBARCH (movdir64b, MOVDIR64B, ANY_MOVDIR64B, false),
+ SUBARCH (movdiri, MOVDIRI, MOVDIRI, false),
+ SUBARCH (movdir64b, MOVDIR64B, MOVDIR64B, false),
SUBARCH (avx512_bf16, AVX512_BF16, ANY_AVX512_BF16, false),
SUBARCH (avx512_vp2intersect, AVX512_VP2INTERSECT,
ANY_AVX512_VP2INTERSECT, false),
- SUBARCH (tdx, TDX, ANY_TDX, false),
- SUBARCH (enqcmd, ENQCMD, ANY_ENQCMD, false),
- SUBARCH (serialize, SERIALIZE, ANY_SERIALIZE, false),
+ 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, SEV_ES, 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, ANY_UINTR, false),
- SUBARCH (hreset, HRESET, ANY_HRESET, false),
+ SUBARCH (uintr, UINTR, UINTR, false),
+ SUBARCH (hreset, HRESET, HRESET, false),
SUBARCH (avx512_fp16, AVX512_FP16, ANY_AVX512_FP16, false),
SUBARCH (prefetchi, PREFETCHI, PREFETCHI, false),
SUBARCH (avx_ifma, AVX_IFMA, ANY_AVX_IFMA, false),
SUBARCH (avx_vnni_int8, AVX_VNNI_INT8, ANY_AVX_VNNI_INT8, false),
- SUBARCH (cmpccxadd, CMPCCXADD, ANY_CMPCCXADD, false),
- SUBARCH (wrmsrns, WRMSRNS, ANY_WRMSRNS, false),
- SUBARCH (msrlist, MSRLIST, ANY_MSRLIST, false),
+ SUBARCH (cmpccxadd, CMPCCXADD, CMPCCXADD, false),
+ SUBARCH (wrmsrns, WRMSRNS, WRMSRNS, false),
+ SUBARCH (msrlist, MSRLIST, MSRLIST, false),
+ SUBARCH (avx_ne_convert, AVX_NE_CONVERT, ANY_AVX_NE_CONVERT, false),
+ SUBARCH (rao_int, RAO_INT, RAO_INT, false),
+ SUBARCH (rmpquery, RMPQUERY, ANY_RMPQUERY, false),
};
#undef SUBARCH
return x;
}
-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 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 anydisp = {
+ .bitfield = { .disp8 = 1, .disp16 = 1, .disp32 = 1, .disp64 = 1 }
+};
enum operand_type
{
|| (i.types[given].bitfield.dword
&& !t->operand_types[wanted].bitfield.dword)
|| (i.types[given].bitfield.qword
- && !t->operand_types[wanted].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));
}
{
if (i.types[j].bitfield.class != Reg
&& i.types[j].bitfield.class != RegSIMD
- && t->opcode_modifier.anysize)
+ && t->opcode_modifier.operandconstraint == ANY_SIZE)
continue;
if (t->operand_types[j].bitfield.class == Reg
/* If given types g0 and g1 are registers they must be of the same type
unless the expected operand type register overlap is null.
- Some Intel syntax memory operand size checking also happens here. */
+ Intel syntax sized memory operands are also checked here. */
static INLINE int
operand_type_register_match (i386_operand_type g0,
{
if (g0.bitfield.class != Reg
&& g0.bitfield.class != RegSIMD
- && (!operand_type_check (g0, anymem)
- || g0.bitfield.unspecified
- || (t0.bitfield.class != Reg
- && t0.bitfield.class != RegSIMD)))
+ && (g0.bitfield.unspecified
+ || !operand_type_check (g0, anymem)))
return 1;
if (g1.bitfield.class != Reg
&& g1.bitfield.class != RegSIMD
- && (!operand_type_check (g1, anymem)
- || g1.bitfield.unspecified
- || (t1.bitfield.class != Reg
- && t1.bitfield.class != RegSIMD)))
+ && (g1.bitfield.unspecified
+ || !operand_type_check (g1, anymem)))
return 1;
if (g0.bitfield.byte == g1.bitfield.byte
as_fatal (_("unknown architecture"));
}
\f
+#include "opcodes/i386-tbl.h"
+
void
md_begin (void)
{
op_hash = str_htab_create ();
{
- const insn_template *optab;
- templates *core_optab;
-
- /* Setup for loop. */
- optab = i386_optab;
- core_optab = notes_alloc (sizeof (*core_optab));
- 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;
- if (str_hash_insert (op_hash, (optab - 1)->name, core_optab, 0))
- as_fatal (_("duplicate %s"), (optab - 1)->name);
-
- if (optab->name == NULL)
- break;
- core_optab = notes_alloc (sizeof (*core_optab));
- core_optab->start = optab;
- }
- }
+ const insn_template *const *sets = i386_op_sets;
+ const insn_template *const *end = sets + ARRAY_SIZE (i386_op_sets) - 1;
+
+ /* Type checks to compensate for the conversion through void * which
+ occurs during hash table insertion / lookup. */
+ (void) sizeof (sets == ¤t_templates->start);
+ (void) sizeof (end == ¤t_templates->end);
+ for (; sets < end; ++sets)
+ if (str_hash_insert (op_hash, (*sets)->name, sets, 0))
+ as_fatal (_("duplicate %s"), (*sets)->name);
}
/* Initialize reg_hash hash table. */
x86_dwarf2_return_column = 16;
#endif
x86_cie_data_alignment = -8;
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+ x86_sframe_cfa_sp_reg = 7;
+ x86_sframe_cfa_fp_reg = 6;
+#endif
}
else
{
}
const type_names[] =
{
- { OPERAND_TYPE_REG8, "r8" },
- { OPERAND_TYPE_REG16, "r16" },
- { OPERAND_TYPE_REG32, "r32" },
- { OPERAND_TYPE_REG64, "r64" },
- { OPERAND_TYPE_ACC8, "acc8" },
- { OPERAND_TYPE_ACC16, "acc16" },
- { OPERAND_TYPE_ACC32, "acc32" },
- { OPERAND_TYPE_ACC64, "acc64" },
- { 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_DISP64, "d64" },
- { 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_SREG, "SReg" },
- { OPERAND_TYPE_REGMMX, "rMMX" },
- { OPERAND_TYPE_REGXMM, "rXMM" },
- { OPERAND_TYPE_REGYMM, "rYMM" },
- { OPERAND_TYPE_REGZMM, "rZMM" },
- { OPERAND_TYPE_REGTMM, "rTMM" },
- { OPERAND_TYPE_REGMASK, "Mask reg" },
+ { { .bitfield = { .class = Reg, .byte = 1 } }, "r8" },
+ { { .bitfield = { .class = Reg, .word = 1 } }, "r16" },
+ { { .bitfield = { .class = Reg, .dword = 1 } }, "r32" },
+ { { .bitfield = { .class = Reg, .qword = 1 } }, "r64" },
+ { { .bitfield = { .instance = Accum, .byte = 1 } }, "acc8" },
+ { { .bitfield = { .instance = Accum, .word = 1 } }, "acc16" },
+ { { .bitfield = { .instance = Accum, .dword = 1 } }, "acc32" },
+ { { .bitfield = { .instance = Accum, .qword = 1 } }, "acc64" },
+ { { .bitfield = { .imm8 = 1 } }, "i8" },
+ { { .bitfield = { .imm8s = 1 } }, "i8s" },
+ { { .bitfield = { .imm16 = 1 } }, "i16" },
+ { { .bitfield = { .imm32 = 1 } }, "i32" },
+ { { .bitfield = { .imm32s = 1 } }, "i32s" },
+ { { .bitfield = { .imm64 = 1 } }, "i64" },
+ { { .bitfield = { .imm1 = 1 } }, "i1" },
+ { { .bitfield = { .baseindex = 1 } }, "BaseIndex" },
+ { { .bitfield = { .disp8 = 1 } }, "d8" },
+ { { .bitfield = { .disp16 = 1 } }, "d16" },
+ { { .bitfield = { .disp32 = 1 } }, "d32" },
+ { { .bitfield = { .disp64 = 1 } }, "d64" },
+ { { .bitfield = { .instance = RegD, .word = 1 } }, "InOutPortReg" },
+ { { .bitfield = { .instance = RegC, .byte = 1 } }, "ShiftCount" },
+ { { .bitfield = { .class = RegCR } }, "control reg" },
+ { { .bitfield = { .class = RegTR } }, "test reg" },
+ { { .bitfield = { .class = RegDR } }, "debug reg" },
+ { { .bitfield = { .class = Reg, .tbyte = 1 } }, "FReg" },
+ { { .bitfield = { .instance = Accum, .tbyte = 1 } }, "FAcc" },
+ { { .bitfield = { .class = SReg } }, "SReg" },
+ { { .bitfield = { .class = RegMMX } }, "rMMX" },
+ { { .bitfield = { .class = RegSIMD, .xmmword = 1 } }, "rXMM" },
+ { { .bitfield = { .class = RegSIMD, .ymmword = 1 } }, "rYMM" },
+ { { .bitfield = { .class = RegSIMD, .zmmword = 1 } }, "rZMM" },
+ { { .bitfield = { .class = RegSIMD, .tmmword = 1 } }, "rTMM" },
+ { { .bitfield = { .class = RegMask } }, "Mask reg" },
};
static void
exp = &im_expressions[i.imm_operands++];
i.op[i.operands].imms = exp;
- i.types[i.operands] = imm8;
+ i.types[i.operands].bitfield.imm8 = 1;
i.operands++;
exp->X_op = O_constant;
exp->X_add_number = i.tm.extension_opcode;
movq $imm31, %r64 -> movl $imm31, %r32
movq $imm32, %r64 -> movl $imm32, %r32
*/
- i.tm.opcode_modifier.norex64 = 1;
+ i.tm.opcode_modifier.size = SIZE32;
+ if (i.imm_operands)
+ {
+ i.types[0].bitfield.imm32 = 1;
+ i.types[0].bitfield.imm32s = 0;
+ i.types[0].bitfield.imm64 = 0;
+ }
+ else
+ {
+ i.types[0].bitfield.dword = 1;
+ i.types[0].bitfield.qword = 0;
+ }
+ i.types[1].bitfield.dword = 1;
+ i.types[1].bitfield.qword = 0;
if (i.tm.base_opcode == 0xb8 || (i.tm.base_opcode | 1) == 0xc7)
{
/* Handle
i.tm.operand_types[0].bitfield.imm32 = 1;
i.tm.operand_types[0].bitfield.imm32s = 0;
i.tm.operand_types[0].bitfield.imm64 = 0;
- i.types[0].bitfield.imm32 = 1;
- i.types[0].bitfield.imm32s = 0;
- i.types[0].bitfield.imm64 = 0;
- i.types[1].bitfield.dword = 1;
- i.types[1].bitfield.qword = 0;
if ((i.tm.base_opcode | 1) == 0xc7)
{
/* Handle
{
/* Anysize insns: lea, invlpg, clflush, prefetch*, bndmk, bndcl, bndcu,
bndcn, bndstx, bndldx, clflushopt, clwb, cldemote. */
- if (i.tm.opcode_modifier.anysize)
+ if (i.tm.opcode_modifier.operandconstraint == ANY_SIZE)
return 0;
/* pop. */
}
}
+/* Helper for md_assemble() to decide whether to prepare for a possible 2nd
+ parsing pass. Instead of introducing a rarely use new insn attribute this
+ utilizes a common pattern between affected templates. It is deemed
+ acceptable that this will lead to unnecessary pass 2 preparations in a
+ limited set of cases. */
+static INLINE bool may_need_pass2 (const insn_template *t)
+{
+ return t->opcode_modifier.sse2avx
+ /* Note that all SSE2AVX templates have at least one operand. */
+ ? t->operand_types[t->operands - 1].bitfield.class == RegSIMD
+ : (t->opcode_modifier.opcodespace == SPACE_0F
+ && (t->base_opcode | 1) == 0xbf)
+ || (t->opcode_modifier.opcodespace == SPACE_BASE
+ && t->base_opcode == 0x63);
+}
+
/* 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. */
md_assemble (char *line)
{
unsigned int j;
- char mnemonic[MAX_MNEM_SIZE], mnem_suffix;
+ char mnemonic[MAX_MNEM_SIZE], mnem_suffix = 0, *copy = NULL;
+ const char *end, *pass1_mnem = NULL;
+ enum i386_error pass1_err = 0;
const insn_template *t;
/* Initialize globals. */
+ current_templates = NULL;
+ retry:
memset (&i, '\0', sizeof (i));
i.rounding.type = rc_none;
for (j = 0; j < MAX_OPERANDS; j++)
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;
+ end = parse_insn (line, mnemonic);
+ if (end == NULL)
+ {
+ if (pass1_mnem != NULL)
+ goto match_error;
+ if (i.error != no_error)
+ {
+ gas_assert (current_templates != NULL);
+ if (may_need_pass2 (current_templates->start) && !i.suffix)
+ goto no_match;
+ /* No point in trying a 2nd pass - it'll only find the same suffix
+ again. */
+ mnem_suffix = i.suffix;
+ goto match_error;
+ }
+ return;
+ }
+ if (may_need_pass2 (current_templates->start))
+ {
+ /* Make a copy of the full line in case we need to retry. */
+ copy = xstrdup (line);
+ }
+ line += end - line;
mnem_suffix = i.suffix;
line = parse_operands (line, mnemonic);
this_operand = -1;
- xfree (i.memop1_string);
- i.memop1_string = NULL;
if (line == NULL)
- return;
+ {
+ free (copy);
+ 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", "enter",
"invlpg*", "monitor*", "mwait*", "tpause", "umwait", "pvalidate",
- "rmpadjust", and "rmpupdate". We also don't reverse intersegment "jmp"
- and "call" instructions with 2 immediate operands so that the immediate
- segment precedes the offset consistently in Intel and AT&T modes. */
+ "rmpadjust", "rmpupdate", and "rmpquery". We also don't reverse
+ intersegment "jmp" and "call" instructions with 2 immediate operands so
+ that the immediate segment precedes the offset consistently in Intel and
+ AT&T modes. */
if (intel_syntax
&& i.operands > 1
&& (strcmp (mnemonic, "bound") != 0)
&& !startswith (mnemonic, "rmp")
&& (strcmp (mnemonic, "tpause") != 0)
&& (strcmp (mnemonic, "umwait") != 0)
- && !(operand_type_check (i.types[0], imm)
+ && !(i.operands == 2
+ && operand_type_check (i.types[0], imm)
&& operand_type_check (i.types[1], imm)))
swap_operands ();
with the template operand types. */
if (!(t = match_template (mnem_suffix)))
- return;
+ {
+ const char *err_msg;
+
+ if (copy && !mnem_suffix)
+ {
+ line = copy;
+ copy = NULL;
+ no_match:
+ pass1_err = i.error;
+ pass1_mnem = current_templates->start->name;
+ goto retry;
+ }
+
+ /* If a non-/only-64bit template (group) was found in pass 1, and if
+ _some_ template (group) was found in pass 2, squash pass 1's
+ error. */
+ if (pass1_err == unsupported_64bit)
+ pass1_mnem = NULL;
+
+ match_error:
+ free (copy);
+
+ switch (pass1_mnem ? pass1_err : 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 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'"),
+ pass1_mnem ? pass1_mnem : current_templates->start->name);
+ return;
+ case unsupported_on_arch:
+ as_bad (_("`%s' is not supported on `%s%s'"),
+ pass1_mnem ? pass1_mnem : current_templates->start->name,
+ cpu_arch_name ? cpu_arch_name : default_arch,
+ cpu_sub_arch_name ? cpu_sub_arch_name : "");
+ return;
+ case unsupported_64bit:
+ if (ISLOWER (mnem_suffix))
+ {
+ if (flag_code == CODE_64BIT)
+ as_bad (_("`%s%c' is not supported in 64-bit mode"),
+ pass1_mnem ? pass1_mnem : current_templates->start->name,
+ mnem_suffix);
+ else
+ as_bad (_("`%s%c' is only supported in 64-bit mode"),
+ pass1_mnem ? pass1_mnem : current_templates->start->name,
+ mnem_suffix);
+ }
+ else
+ {
+ if (flag_code == CODE_64BIT)
+ as_bad (_("`%s' is not supported in 64-bit mode"),
+ pass1_mnem ? pass1_mnem : current_templates->start->name);
+ else
+ as_bad (_("`%s' is only supported in 64-bit mode"),
+ pass1_mnem ? pass1_mnem : current_templates->start->name);
+ }
+
+ return;
+ case invalid_sib_address:
+ err_msg = _("invalid SIB address");
+ break;
+ 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 invalid_tmm_register_set:
+ err_msg = _("all tmm registers must be distinct");
+ break;
+ case invalid_dest_and_src_register_set:
+ err_msg = _("destination and source 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_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 invalid_register_operand:
+ err_msg = _("invalid register operand");
+ break;
+ }
+ as_bad (_("%s for `%s'"), err_msg,
+ pass1_mnem ? pass1_mnem : current_templates->start->name);
+ return;
+ }
+
+ free (copy);
if (sse_check != check_none
/* The opcode space check isn't strictly needed; it's there only to
return;
}
- /* Check for data size prefix on VEX/XOP/EVEX encoded and SIMD insns. */
- if (i.prefix[DATA_PREFIX]
- && (is_any_vex_encoding (&i.tm)
- || i.tm.operand_types[i.imm_operands].bitfield.class >= RegMMX
- || i.tm.operand_types[i.imm_operands + 1].bitfield.class >= RegMMX))
+ if (is_any_vex_encoding (&i.tm)
+ || i.tm.operand_types[i.imm_operands].bitfield.class >= RegMMX
+ || i.tm.operand_types[i.imm_operands + 1].bitfield.class >= RegMMX)
{
- as_bad (_("data size prefix invalid with `%s'"), i.tm.name);
- return;
+ /* Check for data size prefix on VEX/XOP/EVEX encoded and SIMD insns. */
+ if (i.prefix[DATA_PREFIX])
+ {
+ as_bad (_("data size prefix invalid with `%s'"), i.tm.name);
+ return;
+ }
+
+ /* Don't allow e.g. KMOV in TLS code sequences. */
+ for (j = i.imm_operands; j < i.operands; ++j)
+ switch (i.reloc[j])
+ {
+ case BFD_RELOC_386_TLS_GOTIE:
+ case BFD_RELOC_386_TLS_LE_32:
+ case BFD_RELOC_X86_64_GOTTPOFF:
+ case BFD_RELOC_X86_64_TLSLD:
+ as_bad (_("TLS relocation cannot be used with `%s'"), i.tm.name);
+ return;
+ default:
+ break;
+ }
}
/* Check if HLE prefix is OK. */
i.disp_operands = 0;
}
+ /* The memory operand of (%dx) should be only used with input/output
+ instructions (base opcodes: 0x6c, 0x6e, 0xec, 0xee). */
+ if (i.input_output_operand
+ && ((i.tm.base_opcode | 0x82) != 0xee
+ || i.tm.opcode_modifier.opcodespace != SPACE_BASE))
+ {
+ as_bad (_("input/output port address isn't allowed with `%s'"),
+ i.tm.name);
+ return;
+ }
+
if (optimize && !i.no_optimize && i.tm.opcode_modifier.optimize)
optimize_encoding ();
if (!process_operands ())
return;
}
- else if (!quiet_warnings && i.tm.opcode_modifier.ugh)
+ else if (!quiet_warnings && i.tm.opcode_modifier.operandconstraint == UGH)
{
/* UnixWare fsub no args is alias for fsubp, fadd -> faddp, etc. */
as_warn (_("translating to `%sp'"), i.tm.name);
last_insn.kind = last_insn_other;
}
-static char *
-parse_insn (char *line, char *mnemonic)
+/* The Q suffix is generally valid only in 64-bit mode, with very few
+ exceptions: fild, fistp, fisttp, and cmpxchg8b. Note that for fild
+ and fisttp only one of their two templates is matched below: That's
+ sufficient since other relevant attributes are the same between both
+ respective templates. */
+static INLINE bool q_suffix_allowed(const insn_template *t)
+{
+ return flag_code == CODE_64BIT
+ || (t->opcode_modifier.opcodespace == SPACE_BASE
+ && t->base_opcode == 0xdf
+ && (t->extension_opcode & 1)) /* fild / fistp / fisttp */
+ || (t->opcode_modifier.opcodespace == SPACE_0F
+ && t->base_opcode == 0xc7
+ && t->opcode_modifier.opcodeprefix == PREFIX_NONE
+ && t->extension_opcode == 1) /* cmpxchg8b */;
+}
+
+static const char *
+parse_insn (const char *line, char *mnemonic)
{
- char *l = line;
- char *token_start = l;
+ const char *l = line, *token_start = l;
char *mnem_p;
+ bool pass1 = !current_templates;
int supported;
const insn_template *t;
char *dot_p = NULL;
current_templates = (const templates *) str_hash_find (op_hash, mnemonic);
}
- if (!current_templates)
+ if (!current_templates || !pass1)
{
+ current_templates = NULL;
+
check_suffix:
if (mnem_p > mnemonic)
{
current_templates
= (const templates *) str_hash_find (op_hash, mnemonic);
}
+ /* For compatibility reasons accept MOVSD and CMPSD without
+ operands even in AT&T mode. */
+ else if (*l == END_OF_INSN
+ || (is_space_char (*l) && l[1] == END_OF_INSN))
+ {
+ mnem_p[-1] = '\0';
+ current_templates
+ = (const templates *) str_hash_find (op_hash, mnemonic);
+ if (current_templates != NULL
+ /* MOVS or CMPS */
+ && (current_templates->start->base_opcode | 2) == 0xa6
+ && current_templates->start->opcode_modifier.opcodespace
+ == SPACE_BASE
+ && mnem_p[-2] == 's')
+ {
+ as_warn (_("found `%sd'; assuming `%sl' was meant"),
+ mnemonic, mnemonic);
+ i.suffix = LONG_MNEM_SUFFIX;
+ }
+ else
+ {
+ current_templates = NULL;
+ mnem_p[-1] = 'd';
+ }
+ }
break;
}
}
if (!current_templates)
{
- as_bad (_("no such instruction: `%s'"), token_start);
+ if (pass1)
+ as_bad (_("no such instruction: `%s'"), token_start);
return NULL;
}
}
for (t = current_templates->start; t < current_templates->end; ++t)
{
supported |= cpu_flags_match (t);
+
+ if (i.suffix == QWORD_MNEM_SUFFIX && !q_suffix_allowed (t))
+ supported &= ~CPU_FLAGS_64BIT_MATCH;
+
if (supported == CPU_FLAGS_PERFECT_MATCH)
return l;
}
- 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);
- else
- 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 : "");
+ if (pass1)
+ {
+ if (supported & CPU_FLAGS_64BIT_MATCH)
+ i.error = unsupported_on_arch;
+ else
+ i.error = unsupported_64bit;
+ }
return NULL;
}
}
/* Check if default mask is allowed. */
- if (t->opcode_modifier.nodefmask
+ if (t->opcode_modifier.operandconstraint == NO_DEFAULT_MASK
&& (!i.mask.reg || i.mask.reg->reg_num == 0))
{
i.error = no_default_mask;
/* For some special instructions require that destination must be distinct
from source registers. */
- if (t->opcode_modifier.distinctdest)
+ if (t->opcode_modifier.operandconstraint == DISTINCT_DEST)
{
unsigned int dest_reg = i.operands - 1;
if (operand_type_all_zero (&overlap))
goto bad_broadcast;
- if (t->opcode_modifier.checkregsize)
+ if (t->opcode_modifier.checkoperandsize)
{
unsigned int j;
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, size_match, check_register, errline = __LINE__;
found_reverse_match = 0;
addr_prefix_disp = -1;
- /* Prepare for mnemonic suffix check. */
- memset (&suffix_check, 0, sizeof (suffix_check));
- switch (mnem_suffix)
- {
- case BYTE_MNEM_SUFFIX:
- suffix_check.no_bsuf = 1;
- break;
- case WORD_MNEM_SUFFIX:
- suffix_check.no_wsuf = 1;
- break;
- case SHORT_MNEM_SUFFIX:
- suffix_check.no_ssuf = 1;
- break;
- case LONG_MNEM_SUFFIX:
- suffix_check.no_lsuf = 1;
- break;
- case QWORD_MNEM_SUFFIX:
- suffix_check.no_qsuf = 1;
- break;
- default:
- /* NB: In Intel syntax, normally we can check for memory operand
- size when there is no mnemonic suffix. But jmp and call have
- 2 different encodings with Dword memory operand size, one with
- No_ldSuf and the other without. i.suffix is set to
- LONG_DOUBLE_MNEM_SUFFIX to skip the one with No_ldSuf. */
- if (i.suffix == LONG_DOUBLE_MNEM_SUFFIX)
- suffix_check.no_ldsuf = 1;
- }
-
for (t = current_templates->start; t < current_templates->end; t++)
{
addr_prefix_disp = -1;
/* Check the suffix. */
specific_error = progress (invalid_instruction_suffix);
- if ((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))
+ if ((t->opcode_modifier.no_bsuf && mnem_suffix == BYTE_MNEM_SUFFIX)
+ || (t->opcode_modifier.no_wsuf && mnem_suffix == WORD_MNEM_SUFFIX)
+ || (t->opcode_modifier.no_lsuf && mnem_suffix == LONG_MNEM_SUFFIX)
+ || (t->opcode_modifier.no_ssuf && mnem_suffix == SHORT_MNEM_SUFFIX)
+ || (t->opcode_modifier.no_qsuf && mnem_suffix == QWORD_MNEM_SUFFIX))
continue;
specific_error = progress (operand_size_mismatch);
if (i.jumpabsolute && t->opcode_modifier.jump != JUMP_ABSOLUTE)
continue;
+ /* In Intel syntax, normally we can check for memory operand size when
+ there is no mnemonic suffix. But jmp and call have 2 different
+ encodings with Dword memory operand size. Skip the "near" one
+ (permitting a register operand) when "far" was requested. */
+ if (i.far_branch
+ && t->opcode_modifier.jump == JUMP_ABSOLUTE
+ && t->operand_types[0].bitfield.class == Reg)
+ continue;
+
for (j = 0; j < MAX_OPERANDS; j++)
operand_types[j] = t->operand_types[j];
- /* In general, don't allow
- - 64-bit operands outside of 64-bit mode,
- - 32-bit operands on pre-386. */
+ /* In general, don't allow 32-bit operands on pre-386. */
specific_error = progress (mnem_suffix ? invalid_instruction_suffix
: operand_size_mismatch);
j = i.imm_operands + (t->operands > i.imm_operands + 1);
- if (((i.suffix == QWORD_MNEM_SUFFIX
- && flag_code != CODE_64BIT
- && !(t->opcode_modifier.opcodespace == SPACE_0F
- && t->base_opcode == 0xc7
- && t->opcode_modifier.opcodeprefix == PREFIX_NONE
- && t->extension_opcode == 1) /* cmpxchg8b */)
- || (i.suffix == LONG_MNEM_SUFFIX
- && !cpu_arch_flags.bitfield.cpui386))
+ if (i.suffix == LONG_MNEM_SUFFIX
+ && !cpu_arch_flags.bitfield.cpui386
&& (intel_syntax
? (t->opcode_modifier.mnemonicsize != IGNORESIZE
&& !intel_float_operand (t->name))
}
}
- switch (i.reloc[0])
- {
- case BFD_RELOC_386_GOT32:
- /* Force 0x8b encoding for "mov foo@GOT, %eax". */
- if (t->base_opcode == 0xa0
- && t->opcode_modifier.opcodespace == SPACE_BASE)
- continue;
- break;
- case BFD_RELOC_386_TLS_GOTIE:
- case BFD_RELOC_386_TLS_LE_32:
- case BFD_RELOC_X86_64_GOTTPOFF:
- case BFD_RELOC_X86_64_TLSLD:
- /* Don't allow KMOV in TLS code sequences. */
- if (t->opcode_modifier.vex)
- continue;
- break;
- default:
- break;
- }
-
/* We check register size if needed. */
- if (t->opcode_modifier.checkregsize)
+ if (t->opcode_modifier.checkoperandsize)
{
check_register = (1 << t->operands) - 1;
if (i.broadcast.type || i.broadcast.bytes)
&& t->opcode_modifier.opcodespace == SPACE_BASE
&& i.types[0].bitfield.instance == Accum
&& i.types[0].bitfield.dword
- && i.types[1].bitfield.instance == Accum
- && i.types[1].bitfield.dword)
- continue;
- /* xrelease mov %eax, <disp> is another special case. It must not
- match the accumulator-only encoding of mov. */
- if (flag_code != CODE_64BIT
- && i.hle_prefix
- && t->base_opcode == 0xa0
- && t->opcode_modifier.opcodespace == SPACE_BASE
- && i.types[0].bitfield.instance == Accum
- && (i.flags[1] & Operand_Mem))
+ && i.types[1].bitfield.instance == Accum)
continue;
+
+ if (t->base_opcode == MOV_AX_DISP32
+ && t->opcode_modifier.opcodespace == SPACE_BASE)
+ {
+ /* Force 0x8b encoding for "mov foo@GOT, %eax". */
+ if (i.reloc[0] == BFD_RELOC_386_GOT32)
+ continue;
+
+ /* xrelease mov %eax, <disp> is another special case. It must not
+ match the accumulator-only encoding of mov. */
+ if (i.hle_prefix)
+ continue;
+ }
/* Fall through. */
case 3:
specific_error = progress (i.error);
continue;
}
- /* found_reverse_match holds which of D or FloatR
+ /* found_reverse_match holds which variant of D
we've found. */
if (!t->opcode_modifier.d)
found_reverse_match = 0;
else if (operand_types[0].bitfield.tbyte)
- found_reverse_match = Opcode_FloatD;
+ {
+ if (t->opcode_modifier.operandconstraint != UGH)
+ found_reverse_match = Opcode_FloatD;
+ /* FSUB{,R} and FDIV{,R} may need a 2nd bit flipped. */
+ if ((t->base_opcode & 0x20)
+ && (intel_syntax || intel_mnemonic))
+ found_reverse_match |= Opcode_FloatR;
+ }
else if (t->opcode_modifier.vexsources)
{
found_reverse_match = Opcode_VexW;
|| (t->base_opcode | 7) != 0x27))
found_reverse_match = (t->base_opcode & 0xee) != 0x6e
? Opcode_ExtD : Opcode_SIMD_IntD;
- else
+ else if (!t->opcode_modifier.commutative)
found_reverse_match = Opcode_D;
- if (t->opcode_modifier.floatr)
- found_reverse_match |= Opcode_FloatR;
+ else
+ found_reverse_match = ~0;
}
else
{
if (t == current_templates->end)
{
/* We found no match. */
- const char *err_msg;
- switch (specific_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 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_sib_address:
- err_msg = _("invalid SIB address");
- break;
- 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 invalid_tmm_register_set:
- err_msg = _("all tmm registers must be distinct");
- break;
- case invalid_dest_and_src_register_set:
- err_msg = _("destination and source 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_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 invalid_register_operand:
- err_msg = _("invalid register operand");
- break;
- }
- as_bad (_("%s for `%s'"), err_msg,
- current_templates->start->name);
+ i.error = specific_error;
return NULL;
}
i.tm.base_opcode ^= found_reverse_match;
- i.tm.operand_types[0] = operand_types[i.operands - 1];
- i.tm.operand_types[i.operands - 1] = operand_types[0];
-
/* Certain SIMD insns have their load forms specified in the opcode
table, and hence we need to _set_ RegMem instead of clearing it.
We need to avoid setting the bit though on insns like KMOVW. */
= i.tm.opcode_modifier.modrm && i.tm.opcode_modifier.d
&& i.tm.operands > 2U - i.tm.opcode_modifier.sse2avx
&& !i.tm.opcode_modifier.regmem;
+
+ /* Fall through. */
+ case ~0:
+ i.tm.operand_types[0] = operand_types[i.operands - 1];
+ i.tm.operand_types[i.operands - 1] = operand_types[0];
break;
case Opcode_VexW:
i.suffix = QWORD_MNEM_SUFFIX;
else if (i.reg_operands
&& (i.operands > 1 || i.types[0].bitfield.class == Reg)
- && !i.tm.opcode_modifier.addrprefixopreg)
+ && i.tm.opcode_modifier.operandconstraint != ADDR_PREFIX_OP_REG)
{
unsigned int numop = i.operands;
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 (flag_code == CODE_64BIT && !i.tm.opcode_modifier.no_qsuf)
need rex64. */
&& ! (i.operands == 2
&& i.tm.base_opcode == 0x90
- && i.tm.extension_opcode == None
+ && i.tm.opcode_modifier.opcodespace == SPACE_BASE
&& i.types[0].bitfield.instance == Accum
&& i.types[0].bitfield.qword
- && i.types[1].bitfield.instance == Accum
- && i.types[1].bitfield.qword))
+ && i.types[1].bitfield.instance == Accum))
i.rex |= REX_W;
break;
break;
}
- if (i.tm.opcode_modifier.addrprefixopreg)
+ if (i.tm.opcode_modifier.operandconstraint == ADDR_PREFIX_OP_REG)
{
gas_assert (!i.suffix);
gas_assert (i.reg_operands);
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 (overlap.bitfield.imm8
+ + overlap.bitfield.imm8s
+ + overlap.bitfield.imm16
+ + overlap.bitfield.imm32
+ + overlap.bitfield.imm32s
+ + overlap.bitfield.imm64 > 1)
+ {
+ static const i386_operand_type imm16 = { .bitfield = { .imm16 = 1 } };
+ static const i386_operand_type imm32 = { .bitfield = { .imm32 = 1 } };
+ static const i386_operand_type imm32s = { .bitfield = { .imm32s = 1 } };
+ static const i386_operand_type imm16_32 = { .bitfield =
+ { .imm16 = 1, .imm32 = 1 }
+ };
+ static const i386_operand_type imm16_32s = { .bitfield =
+ { .imm16 = 1, .imm32s = 1 }
+ };
+ static const i386_operand_type imm16_32_32s = { .bitfield =
+ { .imm16 = 1, .imm32 = 1, .imm32s = 1 }
+ };
+
if (i.suffix)
{
i386_operand_type temp;
else if (i.prefix[DATA_PREFIX])
overlap = operand_type_and (overlap,
flag_code != CODE_16BIT ? imm16 : imm32);
- 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))
+ if (overlap.bitfield.imm8
+ + overlap.bitfield.imm8s
+ + overlap.bitfield.imm16
+ + overlap.bitfield.imm32
+ + overlap.bitfield.imm32s
+ + overlap.bitfield.imm64 != 1)
{
as_bad (_("no instruction mnemonic suffix given; "
"can't determine immediate size"));
if (i.tm.opcode_modifier.sse2avx && i.tm.opcode_modifier.vexvvvv)
{
+ static const i386_operand_type regxmm = {
+ .bitfield = { .class = RegSIMD, .xmmword = 1 }
+ };
unsigned int dupl = i.operands;
unsigned int dest = dupl - 1;
unsigned int j;
}
}
}
- else if (i.tm.opcode_modifier.implicit1stxmm0)
+ else if (i.tm.opcode_modifier.operandconstraint == IMPLICIT_1ST_XMM0)
{
gas_assert ((MAX_OPERANDS - 1) > dupl
&& (i.tm.opcode_modifier.vexsources
i.reg_operands--;
i.tm.operands--;
}
- else if (i.tm.opcode_modifier.implicitquadgroup)
+ else if (i.tm.opcode_modifier.operandconstraint == IMPLICIT_QUAD_GROUP)
{
unsigned int regnum, first_reg_in_group, last_reg_in_group;
register_prefix, i.op[1].regs->reg_name, last_reg_in_group,
i.tm.name);
}
- else if (i.tm.opcode_modifier.regkludge)
+ else if (i.tm.opcode_modifier.operandconstraint == REG_KLUDGE)
{
/* The imul $imm, %reg instruction is converted into
imul $imm, %reg, %reg, and the clr %reg instruction
{
/* The register or float register operand is in operand
0 or 1. */
- unsigned int op = i.tm.operand_types[0].bitfield.class != Reg;
+ const reg_entry *r = i.op[0].regs;
+ if (i.imm_operands
+ || (r->reg_type.bitfield.instance == Accum && i.op[1].regs))
+ r = i.op[1].regs;
/* 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.tm.base_opcode |= r->reg_num;
+ if ((r->reg_flags & RegRex) != 0)
i.rex |= REX_B;
- if (!quiet_warnings && i.tm.opcode_modifier.ugh)
+ if (!quiet_warnings && i.tm.opcode_modifier.operandconstraint == 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
+ /* Warn about some common errors, but press on regardless. */
+ if (i.operands != 2)
{
/* 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.op[0].regs->reg_type.bitfield.instance != Accum)
+ {
+ /* Reversed arguments on faddp or fmulp. */
+ 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);
+ }
}
}
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.types[i.operands].bitfield.imm8 = 1;
i.operands++;
gas_assert (i.tm.operand_types[reg_slot].bitfield.class == RegSIMD);
unsigned int vvvv;
/* Swap two source operands if needed. */
- if (i.tm.opcode_modifier.swapsources)
+ if (i.tm.opcode_modifier.operandconstraint == SWAP_SOURCES)
{
vvvv = source;
source = dest;
if (seg && subseg)
subseg_set (seg, subseg);
}
+
+bool
+x86_support_sframe_p (void)
+{
+ /* At this time, SFrame unwind is supported for AMD64 ABI only. */
+ return (x86_elf_abi == X86_64_ABI);
+}
+
+bool
+x86_sframe_ra_tracking_p (void)
+{
+ /* In AMD64, return address is always stored on the stack at a fixed offset
+ from the CFA (provided via x86_sframe_cfa_ra_offset ()).
+ Do not track explicitly via an SFrame Frame Row Entry. */
+ return false;
+}
+
+offsetT
+x86_sframe_cfa_ra_offset (void)
+{
+ gas_assert (x86_elf_abi == X86_64_ABI);
+ return (offsetT) -8;
+}
+
+unsigned char
+x86_sframe_get_abi_arch (void)
+{
+ unsigned char sframe_abi_arch = 0;
+
+ if (x86_support_sframe_p ())
+ {
+ gas_assert (!target_big_endian);
+ sframe_abi_arch = SFRAME_ABI_AMD64_ENDIAN_LITTLE;
+ }
+
+ return sframe_abi_arch;
+}
+
#endif
static unsigned int
}
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 },
- OPERAND_TYPE_IMM32_64, false },
+ { .bitfield = { .imm32 = 1, .imm64 = 1 } }, false },
#endif
{ STRING_COMMA_LEN ("PLTOFF"), { _dummy_first_bfd_reloc_code_real,
BFD_RELOC_X86_64_PLTOFF64 },
- OPERAND_TYPE_IMM64, true },
+ { .bitfield = { .imm64 = 1 } }, true },
{ STRING_COMMA_LEN ("PLT"), { BFD_RELOC_386_PLT32,
BFD_RELOC_X86_64_PLT32 },
OPERAND_TYPE_IMM32_32S_DISP32, false },
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
+
};
char *cp;
unsigned int j;
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);
+ {
+ static const i386_operand_type disp16_32 = {
+ .bitfield = { .disp16 = 1, .disp32 = 1 }
+ };
+
+ i.types[this_operand]
+ = operand_type_xor (i.types[this_operand], disp16_32);
+ }
}
}
}
{
const char *kind = "base/index";
enum flag_code addr_mode = i386_addressing_mode ();
- const insn_template *t = current_templates->start;
+ const insn_template *t = current_templates->end - 1;
- if (t->opcode_modifier.isstring
- && !t->cpu_flags.bitfield.cpupadlock
- && (current_templates->end[-1].opcode_modifier.isstring
- || i.mem_operands))
+ if (t->opcode_modifier.isstring)
{
/* Memory operands of string insns are special in that they only allow
a single register (rDI, rSI, or rBX) as their memory address. */
if (t->opcode_modifier.prefixok == PrefixRep)
{
- int es_op = current_templates->end[-1].opcode_modifier.isstring
- - IS_STRING_ES_OP0;
+ int es_op = t->opcode_modifier.isstring - IS_STRING_ES_OP0;
int op = 0;
- if (!current_templates->end[-1].operand_types[0].bitfield.baseindex
+ if (!t->operand_types[0].bitfield.baseindex
|| ((!i.mem_operands != !intel_syntax)
- && current_templates->end[-1].operand_types[1]
- .bitfield.baseindex))
+ && t->operand_types[1].bitfield.baseindex))
op = 1;
expected_reg
= (const reg_entry *) str_hash_find (reg_hash,
}
else
{
+ t = current_templates->start;
+
if (addr_mode != CODE_16BIT)
{
/* 32-bit/64-bit checks. */
return 1;
}
-/* Only string instructions can have a second memory operand, so
- reduce current_templates to just those if it contains any. */
-static int
-maybe_adjust_templates (void)
-{
- const insn_template *t;
-
- gas_assert (i.mem_operands == 1);
-
- for (t = current_templates->start; t < current_templates->end; ++t)
- if (t->opcode_modifier.isstring)
- break;
-
- if (t < current_templates->end)
- {
- static templates aux_templates;
- bool recheck;
-
- aux_templates.start = t;
- for (; t < current_templates->end; ++t)
- if (!t->opcode_modifier.isstring)
- break;
- aux_templates.end = t;
-
- /* Determine whether to re-check the first memory operand. */
- recheck = (aux_templates.start != current_templates->start
- || t != current_templates->end);
-
- current_templates = &aux_templates;
-
- if (recheck)
- {
- i.mem_operands = 0;
- if (i.memop1_string != NULL
- && i386_index_check (i.memop1_string) == 0)
- return 0;
- i.mem_operands = 1;
- }
- }
-
- return 1;
-}
-
static INLINE bool starts_memory_operand (char c)
{
return ISDIGIT (c)
char *displacement_string_end;
do_memory_reference:
- if (i.mem_operands == 1 && !maybe_adjust_templates ())
- return 0;
- 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 ','
&& !operand_type_check (i.types[this_operand], disp))
{
i.types[this_operand] = i.base_reg->reg_type;
+ i.input_output_operand = true;
return 1;
}
if (i386_index_check (operand_string) == 0)
return 0;
i.flags[this_operand] |= Operand_Mem;
- if (i.mem_operands == 0)
- i.memop1_string = xstrdup (operand_string);
i.mem_operands++;
}
else