#define MOD_Op1AddSp 10 /* Parameter is added as "spare" to opcode byte 2 */
/* GAS suffix flags for instructions */
-enum {
+enum x86_gas_suffix_flags {
NONE = 0,
SUF_B = 1<<0,
SUF_W = 1<<1,
/* Flags only used in insnprefix_parse_data */
WEAK = 1<<5 /* Relaxed operand mode for GAS */
-} gas_suffix_flags;
-
-/* Operand types. These are more detailed than the "general" types for all
- * architectures, as they include the size, for instance.
- * Bit Breakdown (from LSB to MSB):
- * - 5 bits = general type (must be exact match, except for =3):
- * 0 = immediate
- * 1 = any general purpose or FPU register
- * 2 = memory
- * 3 = any general purpose or FPU register OR memory
- * 4 = any MMX or XMM register
- * 5 = any MMX or XMM register OR memory
- * 6 = any segment register
- * 7 = any CR register
- * 8 = any DR register
- * 9 = any TR register
- * A = ST0
- * B = AL/AX/EAX/RAX (depending on size)
- * C = CL/CX/ECX/RCX (depending on size)
- * D = DL/DX/EDX/RDX (depending on size)
- * E = CS
- * F = DS
- * 10 = ES
- * 11 = FS
- * 12 = GS
- * 13 = SS
- * 14 = CR4
- * 15 = memory offset (an EA, but with no registers allowed)
- * [special case for MOV opcode]
- * 16 = immediate, value=1 (for special-case shift)
- * 17 = immediate, does not contain SEG:OFF (for jmp/call),
- * 18 = XMM0
- * 19 = AX/EAX/RAX memory operand only (EA)
- * [special case for SVM opcodes]
- * 20 = EAX memory operand only (EA)
- * [special case for SVM skinit opcode]
- * - 3 bits = size (user-specified, or from register size):
- * 0 = any size acceptable/no size spec acceptable (dep. on strict)
- * 1/2/3/4 = 8/16/32/64 bits (from user or reg size)
- * 5/6 = 80/128 bits (from user)
- * 7 = current BITS setting; when this is used the size matched
- * gets stored into the opersize as well.
- * - 1 bit = size implicit or explicit ("strictness" of size matching on
- * non-registers -- registers are always strictly matched):
- * 0 = user size must exactly match size above.
- * 1 = user size either unspecified or exactly match size above.
- * - 3 bits = target modification.
- * 0 = no target mod acceptable
- * 1 = NEAR
- * 2 = SHORT
- * 3 = FAR (or SEG:OFF immediate)
- * 4 = TO
- * - 1 bit = effective address size
- * 0 = any address size allowed except for 64-bit
- * 1 = only 64-bit address size allowed
- *
- * MSBs than the above are actions: what to do with the operand if the
- * instruction matches. Essentially describes what part of the output bytecode
- * gets the operand. This may require conversion (e.g. a register going into
- * an ea field). Naturally, only one of each of these may be contained in the
- * operands of a single insn_info structure.
- * - 4 bits = action:
- * 0 = does nothing (operand data is discarded)
- * 1 = operand data goes into ea field
- * 2 = operand data goes into imm field
- * 3 = operand data goes into sign-extended imm field
- * 4 = operand data goes into "spare" field
- * 5 = operand data is added to opcode byte 0
- * 6 = operand data is added to opcode byte 1
- * 7 = operand data goes into BOTH ea and spare
- * [special case for imul opcode]
- * 8 = relative jump (outputs a jmp instead of normal insn)
- * 9 = operand size goes into address size (jmp only)
- * A = far jump (outputs a farjmp instead of normal insn)
- * B = ea operand only sets address size (no actual ea field)
- * The below describes postponed actions: actions which can't be completed at
- * parse-time due to possibly dependent expressions. For these, some
- * additional data (stored in the second byte of the opcode with a one-byte
- * opcode) is passed to later stages of the assembler with flags set to
- * indicate postponed actions.
- * - 3 bits = postponed action:
- * 0 = none
- * 1 = sign-extended imm8 that could expand to a large imm16/32
- * 2 = could become a short opcode mov with bits=64 and a32 prefix
- * 3 = forced 16-bit address size (override ignored, no prefix)
- * 4 = large imm64 that can become a sign-extended imm32.
- */
-#define OPT_Imm 0x0
-#define OPT_Reg 0x1
-#define OPT_Mem 0x2
-#define OPT_RM 0x3
-#define OPT_SIMDReg 0x4
-#define OPT_SIMDRM 0x5
-#define OPT_SegReg 0x6
-#define OPT_CRReg 0x7
-#define OPT_DRReg 0x8
-#define OPT_TRReg 0x9
-#define OPT_ST0 0xA
-#define OPT_Areg 0xB
-#define OPT_Creg 0xC
-#define OPT_Dreg 0xD
-#define OPT_CS 0xE
-#define OPT_DS 0xF
-#define OPT_ES 0x10
-#define OPT_FS 0x11
-#define OPT_GS 0x12
-#define OPT_SS 0x13
-#define OPT_CR4 0x14
-#define OPT_MemOffs 0x15
-#define OPT_Imm1 0x16
-#define OPT_ImmNotSegOff 0x17
-#define OPT_XMM0 0x18
-#define OPT_MemrAX 0x19
-#define OPT_MemEAX 0x1A
-#define OPT_MASK 0x1F
-
-#define OPS_Any (0UL<<5)
-#define OPS_8 (1UL<<5)
-#define OPS_16 (2UL<<5)
-#define OPS_32 (3UL<<5)
-#define OPS_64 (4UL<<5)
-#define OPS_80 (5UL<<5)
-#define OPS_128 (6UL<<5)
-#define OPS_BITS (7UL<<5)
-#define OPS_MASK (7UL<<5)
-#define OPS_SHIFT 5
-
-#define OPS_Relaxed (1UL<<8)
-#define OPS_RMASK (1UL<<8)
-
-#define OPEAS_Not64 (0UL<<9)
-#define OPEAS_64 (1UL<<9)
-#define OPEAS_MASK (1UL<<9)
-
-#define OPTM_None (0UL<<10)
-#define OPTM_Near (1UL<<10)
-#define OPTM_Short (2UL<<10)
-#define OPTM_Far (3UL<<10)
-#define OPTM_To (4UL<<10)
-#define OPTM_MASK (7UL<<10)
-
-#define OPA_None (0UL<<13)
-#define OPA_EA (1UL<<13)
-#define OPA_Imm (2UL<<13)
-#define OPA_SImm (3UL<<13)
-#define OPA_Spare (4UL<<13)
-#define OPA_Op0Add (5UL<<13)
-#define OPA_Op1Add (6UL<<13)
-#define OPA_SpareEA (7UL<<13)
-#define OPA_JmpRel (8UL<<13)
-#define OPA_AdSizeR (9UL<<13)
-#define OPA_JmpFar (0xAUL<<13)
-#define OPA_AdSizeEA (0xBUL<<13)
-#define OPA_MASK (0xFUL<<13)
-
-#define OPAP_None (0UL<<17)
-#define OPAP_SImm8 (1UL<<17)
-#define OPAP_ShortMov (2UL<<17)
-#define OPAP_A16 (3UL<<17)
-#define OPAP_SImm32Avail (4UL<<17)
-#define OPAP_MASK (7UL<<17)
+};
+
+enum x86_operand_type {
+ OPT_Imm = 0, /* immediate */
+ OPT_Reg = 1, /* any general purpose or FPU register */
+ OPT_Mem = 2, /* memory */
+ OPT_RM = 3, /* any general purpose or FPU register OR memory */
+ OPT_SIMDReg = 4, /* any MMX or XMM register */
+ OPT_SIMDRM = 5, /* any MMX or XMM register OR memory */
+ OPT_SegReg = 6, /* any segment register */
+ OPT_CRReg = 7, /* any CR register */
+ OPT_DRReg = 8, /* any DR register */
+ OPT_TRReg = 9, /* any TR register */
+ OPT_ST0 = 10, /* ST0 */
+ OPT_Areg = 11, /* AL/AX/EAX/RAX (depending on size) */
+ OPT_Creg = 12, /* CL/CX/ECX/RCX (depending on size) */
+ OPT_Dreg = 13, /* DL/DX/EDX/RDX (depending on size) */
+ OPT_CS = 14, /* CS */
+ OPT_DS = 15, /* DS */
+ OPT_ES = 16, /* ES */
+ OPT_FS = 17, /* FS */
+ OPT_GS = 18, /* GS */
+ OPT_SS = 19, /* SS */
+ OPT_CR4 = 20, /* CR4 */
+ /* memory offset (an EA, but with no registers allowed)
+ * [special case for MOV opcode]
+ */
+ OPT_MemOffs = 21,
+ OPT_Imm1 = 22, /* immediate, value=1 (for special-case shift) */
+ /* immediate, does not contain SEG:OFF (for jmp/call) */
+ OPT_ImmNotSegOff = 23,
+ OPT_XMM0 = 24, /* XMM0 */
+ /* AX/EAX/RAX memory operand only (EA) [special case for SVM opcodes]
+ */
+ OPT_MemrAX = 25,
+ /* EAX memory operand only (EA) [special case for SVM skinit opcode] */
+ OPT_MemEAX = 26
+};
+
+enum x86_operand_size {
+ /* any size acceptable/no size spec acceptable (dep. on strict) */
+ OPS_Any = 0,
+ /* 8/16/32/64 bits (from user or reg size) */
+ OPS_8 = 1,
+ OPS_16 = 2,
+ OPS_32 = 3,
+ OPS_64 = 4,
+ /* 80/128 bits (from user) */
+ OPS_80 = 5,
+ OPS_128 = 6,
+ /* current BITS setting; when this is used the size matched
+ * gets stored into the opersize as well.
+ */
+ OPS_BITS = 7
+};
+
+enum x86_operand_targetmod {
+ OPTM_None = 0, /* no target mod acceptable */
+ OPTM_Near = 1, /* NEAR */
+ OPTM_Short = 2, /* SHORT */
+ OPTM_Far = 3, /* FAR (or SEG:OFF immediate) */
+ OPTM_To = 4 /* TO */
+};
+
+enum x86_operand_action {
+ OPA_None = 0, /* does nothing (operand data is discarded) */
+ OPA_EA = 1, /* operand data goes into ea field */
+ OPA_Imm = 2, /* operand data goes into imm field */
+ OPA_SImm = 3, /* operand data goes into sign-extended imm field */
+ OPA_Spare = 4, /* operand data goes into "spare" field */
+ OPA_Op0Add = 5, /* operand data is added to opcode byte 0 */
+ OPA_Op1Add = 6, /* operand data is added to opcode byte 1 */
+ /* operand data goes into BOTH ea and spare
+ * (special case for imul opcode)
+ */
+ OPA_SpareEA = 7,
+ /* relative jump (outputs a jmp instead of normal insn) */
+ OPA_JmpRel = 8,
+ /* operand size goes into address size (jmp only) */
+ OPA_AdSizeR = 9,
+ /* far jump (outputs a farjmp instead of normal insn) */
+ OPA_JmpFar = 10,
+ /* ea operand only sets address size (no actual ea field) */
+ OPA_AdSizeEA = 11
+};
+
+enum x86_operand_post_action {
+ OPAP_None = 0,
+ /* sign-extended imm8 that could expand to a large imm16/32 */
+ OPAP_SImm8 = 1,
+ /* could become a short opcode mov with bits=64 and a32 prefix */
+ OPAP_ShortMov = 2,
+ /* forced 16-bit address size (override ignored, no prefix) */
+ OPAP_A16 = 3,
+ /* large imm64 that can become a sign-extended imm32 */
+ OPAP_SImm32Avail = 4
+};
+
+typedef struct x86_info_operand {
+ /* Operand types. These are more detailed than the "general" types for all
+ * architectures, as they include the size, for instance.
+ */
+
+ /* general type (must be exact match, except for RM types): */
+ unsigned int type:5;
+
+ /* size (user-specified, or from register size) */
+ unsigned int size:3;
+
+ /* size implicit or explicit ("strictness" of size matching on
+ * non-registers -- registers are always strictly matched):
+ * 0 = user size must exactly match size above.
+ * 1 = user size either unspecified or exactly match size above.
+ */
+ unsigned int relaxed:1;
+
+ /* effective address size
+ * 0 = any address size allowed except for 64-bit
+ * 1 = only 64-bit address size allowed
+ */
+ unsigned int eas64:1;
+
+ /* target modification */
+ unsigned int targetmod:3;
+
+ /* Actions: what to do with the operand if the instruction matches.
+ * Essentially describes what part of the output bytecode gets the
+ * operand. This may require conversion (e.g. a register going into
+ * an ea field). Naturally, only one of each of these may be contained
+ * in the operands of a single insn_info structure.
+ */
+ unsigned int action:4;
+
+ /* Postponed actions: actions which can't be completed at
+ * parse-time due to possibly dependent expressions. For these, some
+ * additional data (stored in the second byte of the opcode with a
+ * one-byte opcode) is passed to later stages of the assembler with
+ * flags set to indicate postponed actions.
+ */
+ unsigned int post_action:3;
+} x86_info_operand;
typedef struct x86_insn_info {
/* GAS suffix flags */
jmp->target.jump_target = 1;
/* See if the user explicitly specified short/near/far. */
- switch ((int)(insn_operands[jinfo->operands_index+0] & OPTM_MASK)) {
+ switch (insn_operands[jinfo->operands_index+0].targetmod) {
case OPTM_Short:
jmp->op_sel = JMP_SHORT_FORCED;
break;
/* Check for address size setting in second operand, if present */
if (jinfo->num_operands > 1 &&
- (insn_operands[jinfo->operands_index+1] & OPA_MASK) == OPA_AdSizeR)
+ insn_operands[jinfo->operands_index+1].action == OPA_AdSizeR)
jmp->common.addrsize = (unsigned char)
- size_lookup[(insn_operands[jinfo->operands_index+1]
- & OPS_MASK)>>OPS_SHIFT];
+ size_lookup[insn_operands[jinfo->operands_index+1].size];
/* Check for address size override */
for (i=0; i<NELEMS(info->modifiers); i++) {
if (info->num_operands == 0)
continue;
- if ((insn_operands[info->operands_index+0] & OPA_MASK) != OPA_JmpRel)
+ if (insn_operands[info->operands_index+0].action != OPA_JmpRel)
continue;
if (info->opersize != jmp->common.opersize)
continue;
- switch ((int)(insn_operands[info->operands_index+0] & OPTM_MASK)) {
+ switch (insn_operands[info->operands_index+0].targetmod) {
case OPTM_Short:
x86_finalize_opcode(&jmp->shortop, info);
for (i=0; i<NELEMS(info->modifiers); i++) {
*/
for (; num_info>0 && !found; num_info--, info++) {
yasm_insn_operand *op, **use_ops;
- const unsigned long *info_ops = &insn_operands[info->operands_index];
+ const x86_info_operand *info_ops =
+ &insn_operands[info->operands_index];
unsigned int cpu0 = info->cpu0;
unsigned int cpu1 = info->cpu1;
unsigned int cpu2 = info->cpu2;
for (i = 0, op = use_ops[0]; op && i<info->num_operands && !mismatch;
op = use_ops[++i]) {
/* Check operand type */
- switch ((int)(info_ops[i] & OPT_MASK)) {
+ switch (info_ops[i].type) {
case OPT_Imm:
if (op->type != YASM_INSN__OPERAND_IMM)
mismatch = 1;
break;
case OPT_Areg:
if (op->type != YASM_INSN__OPERAND_REG ||
- ((info_ops[i] & OPS_MASK) == OPS_8 &&
+ (info_ops[i].size == OPS_8 &&
op->data.reg != (X86_REG8 | 0) &&
op->data.reg != (X86_REG8X | 0)) ||
- ((info_ops[i] & OPS_MASK) == OPS_16 &&
+ (info_ops[i].size == OPS_16 &&
op->data.reg != (X86_REG16 | 0)) ||
- ((info_ops[i] & OPS_MASK) == OPS_32 &&
+ (info_ops[i].size == OPS_32 &&
op->data.reg != (X86_REG32 | 0)) ||
- ((info_ops[i] & OPS_MASK) == OPS_64 &&
+ (info_ops[i].size == OPS_64 &&
op->data.reg != (X86_REG64 | 0)))
mismatch = 1;
break;
case OPT_Creg:
if (op->type != YASM_INSN__OPERAND_REG ||
- ((info_ops[i] & OPS_MASK) == OPS_8 &&
+ (info_ops[i].size == OPS_8 &&
op->data.reg != (X86_REG8 | 1) &&
op->data.reg != (X86_REG8X | 1)) ||
- ((info_ops[i] & OPS_MASK) == OPS_16 &&
+ (info_ops[i].size == OPS_16 &&
op->data.reg != (X86_REG16 | 1)) ||
- ((info_ops[i] & OPS_MASK) == OPS_32 &&
+ (info_ops[i].size == OPS_32 &&
op->data.reg != (X86_REG32 | 1)) ||
- ((info_ops[i] & OPS_MASK) == OPS_64 &&
+ (info_ops[i].size == OPS_64 &&
op->data.reg != (X86_REG64 | 1)))
mismatch = 1;
break;
case OPT_Dreg:
if (op->type != YASM_INSN__OPERAND_REG ||
- ((info_ops[i] & OPS_MASK) == OPS_8 &&
+ (info_ops[i].size == OPS_8 &&
op->data.reg != (X86_REG8 | 2) &&
op->data.reg != (X86_REG8X | 2)) ||
- ((info_ops[i] & OPS_MASK) == OPS_16 &&
+ (info_ops[i].size == OPS_16 &&
op->data.reg != (X86_REG16 | 2)) ||
- ((info_ops[i] & OPS_MASK) == OPS_32 &&
+ (info_ops[i].size == OPS_32 &&
op->data.reg != (X86_REG32 | 2)) ||
- ((info_ops[i] & OPS_MASK) == OPS_64 &&
+ (info_ops[i].size == OPS_64 &&
op->data.reg != (X86_REG64 | 2)))
mismatch = 1;
break;
break;
/* Check operand size */
- size = size_lookup[(info_ops[i] & OPS_MASK)>>OPS_SHIFT];
+ size = size_lookup[info_ops[i].size];
if (suffix != 0) {
/* Require relaxed operands for GAS mode (don't allow
* per-operand sizing).
/* Register size must exactly match */
if (yasm_x86__get_reg_size(op->data.reg) != size)
mismatch = 1;
- } else if (((info_ops[i] & OPT_MASK) == OPT_Imm
- || (info_ops[i] & OPT_MASK) == OPT_ImmNotSegOff
- || (info_ops[i] & OPT_MASK) == OPT_Imm1)
- && (info_ops[i] & OPS_RMASK) != OPS_Relaxed
- && (info_ops[i] & OPA_MASK) != OPA_JmpRel)
+ } else if ((info_ops[i].type == OPT_Imm
+ || info_ops[i].type == OPT_ImmNotSegOff
+ || info_ops[i].type == OPT_Imm1)
+ && !info_ops[i].relaxed
+ && info_ops[i].action != OPA_JmpRel)
mismatch = 1;
} else {
if (op->type == YASM_INSN__OPERAND_REG && op->size == 0) {
if ((bypass == 1 && i == 0) || (bypass == 2 && i == 1)
|| (bypass == 3 && i == 3))
;
- else if ((info_ops[i] & OPS_RMASK) == OPS_Relaxed) {
+ else if (info_ops[i].relaxed) {
/* Relaxed checking */
if (size != 0 && op->size != size && op->size != 0)
mismatch = 1;
/* Check for 64-bit effective address size in NASM mode */
if (suffix == 0 && op->type == YASM_INSN__OPERAND_MEMORY) {
- if ((info_ops[i] & OPEAS_MASK) == OPEAS_64) {
+ if (info_ops[i].eas64) {
if (op->data.ea->disp.size != 64)
mismatch = 1;
} else if (op->data.ea->disp.size == 64)
break;
/* Check target modifier */
- switch ((int)(info_ops[i] & OPTM_MASK)) {
+ switch (info_ops[i].targetmod) {
case OPTM_None:
if (op->targetmod != 0)
mismatch = 1;
* operands and adjust for dereferences / lack thereof.
*/
if (id_insn->parser == X86_PARSER_GAS
- && (insn_operands[info->operands_index+0] & OPA_MASK) == OPA_JmpRel) {
+ && insn_operands[info->operands_index+0].action == OPA_JmpRel) {
for (i = 0, op = ops[0]; op; op = ops[++i]) {
if (!op->deref && (op->type == YASM_INSN__OPERAND_REG
|| (op->type == YASM_INSN__OPERAND_MEMORY
}
if (id_insn->insn.num_operands > 0) {
- switch (insn_operands[info->operands_index+0] & OPA_MASK) {
+ switch (insn_operands[info->operands_index+0].action) {
case OPA_JmpRel:
/* Shortcut to JmpRel */
x86_finalize_jmp(bc, prev_bc, info);
/* Go through operands and assign */
if (id_insn->insn.num_operands > 0) {
yasm_insn_operand **use_ops = ops;
- const unsigned long *info_ops = &insn_operands[info->operands_index];
+ const x86_info_operand *info_ops =
+ &insn_operands[info->operands_index];
/* Use reversed operands in GAS mode if not otherwise specified */
if (id_insn->parser == X86_PARSER_GAS
for (i = 0, op = use_ops[0]; op && i<info->num_operands;
op = use_ops[++i]) {
- switch ((int)(info_ops[i] & OPA_MASK)) {
+ switch (info_ops[i].action) {
case OPA_None:
/* Throw away the operand contents */
switch (op->type) {
N_("invalid operand conversion"));
case YASM_INSN__OPERAND_MEMORY:
insn->x86_ea = (x86_effaddr *)op->data.ea;
- if ((info_ops[i] & OPT_MASK) == OPT_MemOffs)
+ if (info_ops[i].type == OPT_MemOffs)
/* Special-case for MOV MemOffs instruction */
yasm_x86__ea_set_disponly(insn->x86_ea);
break;
insn->x86_ea =
yasm_x86__ea_create_imm(insn->x86_ea,
op->data.val,
- size_lookup[(info_ops[i] &
- OPS_MASK)>>OPS_SHIFT]);
+ size_lookup[info_ops[i].size]);
break;
}
break;
case OPA_Imm:
if (op->type == YASM_INSN__OPERAND_IMM) {
imm = op->data.val;
- im_len = size_lookup[(info_ops[i] &
- OPS_MASK)>>OPS_SHIFT];
+ im_len = size_lookup[info_ops[i].size];
} else
yasm_internal_error(N_("invalid operand conversion"));
break;
case OPA_SImm:
if (op->type == YASM_INSN__OPERAND_IMM) {
imm = op->data.val;
- im_len = size_lookup[(info_ops[i] &
- OPS_MASK)>>OPS_SHIFT];
+ im_len = size_lookup[info_ops[i].size];
im_sign = 1;
} else
yasm_internal_error(N_("invalid operand conversion"));
yasm_internal_error(N_("unknown operand action"));
}
- if ((info_ops[i] & OPS_MASK) == OPS_BITS)
+ if (info_ops[i].size == OPS_BITS)
insn->common.opersize = (unsigned char)mode_bits;
- switch ((int)(info_ops[i] & OPAP_MASK)) {
+ switch (info_ops[i].post_action) {
case OPAP_None:
break;
case OPAP_SImm8: