| Index: third_party/yasm/patched-yasm/modules/arch/x86/x86id.c
|
| ===================================================================
|
| --- third_party/yasm/patched-yasm/modules/arch/x86/x86id.c (revision 71129)
|
| +++ third_party/yasm/patched-yasm/modules/arch/x86/x86id.c (working copy)
|
| @@ -26,7 +26,7 @@
|
| */
|
| #include <ctype.h>
|
| #include <util.h>
|
| -RCSID("$Id: x86id.c 2130 2008-10-07 05:38:11Z peter $");
|
| +RCSID("$Id: x86id.c 2279 2010-01-19 07:57:43Z peter $");
|
|
|
| #include <libyasm.h>
|
| #include <libyasm/phash.h>
|
| @@ -53,21 +53,18 @@
|
|
|
| /* GAS suffix flags for instructions */
|
| enum x86_gas_suffix_flags {
|
| - NONE = 0,
|
| - SUF_B = 1<<0,
|
| - SUF_W = 1<<1,
|
| - SUF_L = 1<<2,
|
| - SUF_Q = 1<<3,
|
| - SUF_S = 1<<4,
|
| - SUF_MASK = SUF_B|SUF_W|SUF_L|SUF_Q|SUF_S,
|
| + SUF_Z = 1<<0, /* no suffix */
|
| + SUF_B = 1<<1,
|
| + SUF_W = 1<<2,
|
| + SUF_L = 1<<3,
|
| + SUF_Q = 1<<4,
|
| + SUF_S = 1<<5,
|
| + SUF_MASK = SUF_Z|SUF_B|SUF_W|SUF_L|SUF_Q|SUF_S,
|
|
|
| /* Flags only used in x86_insn_info */
|
| - GAS_ONLY = 1<<5, /* Only available in GAS mode */
|
| - GAS_ILLEGAL = 1<<6, /* Illegal in GAS mode */
|
| - GAS_NO_REV = 1<<7, /* Don't reverse operands in GAS mode */
|
| -
|
| - /* Flags only used in insnprefix_parse_data */
|
| - WEAK = 1<<5 /* Relaxed operand mode for GAS */
|
| + GAS_ONLY = 1<<6, /* Only available in GAS mode */
|
| + GAS_ILLEGAL = 1<<7, /* Illegal in GAS mode */
|
| + GAS_NO_REV = 1<<8 /* Don't reverse operands in GAS mode */
|
| };
|
|
|
| /* Miscellaneous flag tests for instructions */
|
| @@ -114,9 +111,7 @@
|
| */
|
| OPT_MemrAX = 25,
|
| /* EAX memory operand only (EA) [special case for SVM skinit opcode] */
|
| - OPT_MemEAX = 26,
|
| - /* SIMDReg with value equal to operand 0 SIMDReg */
|
| - OPT_SIMDRegMatch0 = 27
|
| + OPT_MemEAX = 26
|
| };
|
|
|
| enum x86_operand_size {
|
| @@ -164,18 +159,17 @@
|
| OPA_JmpFar = 10,
|
| /* ea operand only sets address size (no actual ea field) */
|
| OPA_AdSizeEA = 11,
|
| - OPA_DREX = 12, /* operand data goes into DREX "dest" field */
|
| - OPA_VEX = 13, /* operand data goes into VEX "vvvv" field */
|
| - /* operand data goes into BOTH VEX "vvvv" field and ea field */
|
| - OPA_EAVEX = 14,
|
| - /* operand data goes into BOTH VEX "vvvv" field and spare field */
|
| - OPA_SpareVEX = 15,
|
| + OPA_VEX = 12, /* operand data goes into VEX/XOP "vvvv" field */
|
| + /* operand data goes into BOTH VEX/XOP "vvvv" field and ea field */
|
| + OPA_EAVEX = 13,
|
| + /* operand data goes into BOTH VEX/XOP "vvvv" field and spare field */
|
| + OPA_SpareVEX = 14,
|
| /* operand data goes into upper 4 bits of immediate byte (VEX is4 field) */
|
| - OPA_VEXImmSrc = 16,
|
| + OPA_VEXImmSrc = 15,
|
| /* operand data goes into bottom 4 bits of immediate byte
|
| * (currently only VEX imz2 field)
|
| */
|
| - OPA_VEXImm = 17
|
| + OPA_VEXImm = 16
|
| };
|
|
|
| enum x86_operand_post_action {
|
| @@ -236,10 +230,10 @@
|
|
|
| typedef struct x86_insn_info {
|
| /* GAS suffix flags */
|
| - unsigned int gas_flags:8; /* Enabled for these GAS suffixes */
|
| + unsigned int gas_flags:9; /* Enabled for these GAS suffixes */
|
|
|
| - /* Tests against BITS==64 and AVX */
|
| - unsigned int misc_flags:6;
|
| + /* Tests against BITS==64, AVX, and XOP */
|
| + unsigned int misc_flags:5;
|
|
|
| /* The CPU feature flags needed to execute this instruction. This is OR'ed
|
| * with arch-specific data[2]. This combined value is compared with
|
| @@ -277,17 +271,11 @@
|
| * 01: 66
|
| * 10: F3
|
| * 11: F2
|
| + * 0x80 - 0x8F indicate a XOP prefix, with the four LSBs holding "WLpp":
|
| + * same meanings as VEX prefix.
|
| */
|
| unsigned char special_prefix;
|
|
|
| - /* The DREX base byte value (almost). The only bit kept from this
|
| - * value is the OC0 bit (0x08). The MSB (0x80) of this value indicates
|
| - * if the DREX byte needs to be present in the instruction.
|
| - */
|
| -#define NEED_DREX_MASK 0x80
|
| -#define DREX_OC0_MASK 0x08
|
| - unsigned char drex_oc0;
|
| -
|
| /* The length of the basic opcode */
|
| unsigned char opcode_len;
|
|
|
| @@ -327,10 +315,10 @@
|
| unsigned int mode_bits:8;
|
|
|
| /* Suffix flags */
|
| - unsigned int suffix:8;
|
| + unsigned int suffix:9;
|
|
|
| /* Tests against BITS==64 and AVX */
|
| - unsigned int misc_flags:6;
|
| + unsigned int misc_flags:5;
|
|
|
| /* Parser enabled at the time of parsing the instruction */
|
| unsigned int parser:2;
|
| @@ -394,9 +382,11 @@
|
| const x86_insn_info *info)
|
| {
|
| x86_id_insn *id_insn = (x86_id_insn *)bc->contents;
|
| + unsigned char *mod_data = id_insn->mod_data;
|
| unsigned int mode_bits = id_insn->mode_bits;
|
| x86_jmpfar *jmpfar;
|
| yasm_insn_operand *op;
|
| + unsigned int i;
|
|
|
| jmpfar = yasm_xmalloc(sizeof(x86_jmpfar));
|
| x86_finalize_common(&jmpfar->common, info, mode_bits);
|
| @@ -422,9 +412,44 @@
|
| || yasm_value_finalize_expr(&jmpfar->segment, e, prev_bc, 16))
|
| yasm_error_set(YASM_ERROR_TOO_COMPLEX,
|
| N_("jump target expression too complex"));
|
| + } else if (yasm_insn_op_next(op)) {
|
| + /* Two operand form (gas) */
|
| + yasm_insn_operand *op2 = yasm_insn_op_next(op);
|
| + if (yasm_value_finalize_expr(&jmpfar->segment, op->data.val, prev_bc,
|
| + 16))
|
| + yasm_error_set(YASM_ERROR_TOO_COMPLEX,
|
| + N_("jump target segment too complex"));
|
| + if (yasm_value_finalize_expr(&jmpfar->offset, op2->data.val, prev_bc,
|
| + 0))
|
| + yasm_error_set(YASM_ERROR_TOO_COMPLEX,
|
| + N_("jump target offset too complex"));
|
| + if (op2->size == OPS_BITS)
|
| + jmpfar->common.opersize = (unsigned char)mode_bits;
|
| } else
|
| yasm_internal_error(N_("didn't get FAR expression in jmpfar"));
|
|
|
| + /* Apply modifiers */
|
| + for (i=0; i<NELEMS(info->modifiers); i++) {
|
| + switch (info->modifiers[i]) {
|
| + case MOD_Gap:
|
| + break;
|
| + case MOD_Op0Add:
|
| + jmpfar->opcode.opcode[0] += mod_data[i];
|
| + break;
|
| + case MOD_Op1Add:
|
| + jmpfar->opcode.opcode[1] += mod_data[i];
|
| + break;
|
| + case MOD_Op2Add:
|
| + jmpfar->opcode.opcode[2] += mod_data[i];
|
| + break;
|
| + case MOD_Op1AddSp:
|
| + jmpfar->opcode.opcode[1] += mod_data[i]<<3;
|
| + break;
|
| + default:
|
| + break;
|
| + }
|
| + }
|
| +
|
| yasm_x86__bc_apply_prefixes((x86_common *)jmpfar, NULL,
|
| info->def_opersize_64,
|
| id_insn->insn.num_prefixes,
|
| @@ -614,7 +639,7 @@
|
| continue;
|
|
|
| /* Match suffix (if required) */
|
| - if (suffix != 0 && suffix != WEAK
|
| + if (id_insn->parser == X86_PARSER_GAS
|
| && ((suffix & SUF_MASK) & (gas_flags & SUF_MASK)) == 0)
|
| continue;
|
|
|
| @@ -667,7 +692,6 @@
|
| if (op->type == YASM_INSN__OPERAND_MEMORY)
|
| break;
|
| /*@fallthrough@*/
|
| - case OPT_SIMDRegMatch0:
|
| case OPT_SIMDReg:
|
| if (op->type != YASM_INSN__OPERAND_REG)
|
| mismatch = 1;
|
| @@ -682,9 +706,6 @@
|
| break;
|
| }
|
| }
|
| - if (!mismatch && info_ops[i].type == OPT_SIMDRegMatch0 &&
|
| - bypass != 7 && op->data.reg != use_ops[0]->data.reg)
|
| - mismatch = 1;
|
| break;
|
| case OPT_SegReg:
|
| if (op->type != YASM_INSN__OPERAND_SEGREG)
|
| @@ -839,7 +860,7 @@
|
|
|
| /* Check operand size */
|
| size = size_lookup[info_ops[i].size];
|
| - if (suffix != 0) {
|
| + if (id_insn->parser == X86_PARSER_GAS) {
|
| /* Require relaxed operands for GAS mode (don't allow
|
| * per-operand sizing).
|
| */
|
| @@ -881,7 +902,8 @@
|
| break;
|
|
|
| /* Check for 64-bit effective address size in NASM mode */
|
| - if (suffix == 0 && op->type == YASM_INSN__OPERAND_MEMORY) {
|
| + if (id_insn->parser != X86_PARSER_GAS &&
|
| + op->type == YASM_INSN__OPERAND_MEMORY) {
|
| if (info_ops[i].eas64) {
|
| if (op->data.ea->disp.size != 64)
|
| mismatch = 1;
|
| @@ -1005,8 +1027,6 @@
|
| unsigned char im_len;
|
| unsigned char im_sign;
|
| unsigned char spare;
|
| - unsigned char drex;
|
| - unsigned char *pdrex;
|
| unsigned char vexdata, vexreg;
|
| unsigned int i;
|
| unsigned int size_lookup[] = {0, 8, 16, 32, 64, 80, 128, 256, 0};
|
| @@ -1099,19 +1119,18 @@
|
| insn->def_opersize_64 = info->def_opersize_64;
|
| insn->special_prefix = info->special_prefix;
|
| spare = info->spare;
|
| - drex = info->drex_oc0 & DREX_OC0_MASK;
|
| vexdata = 0;
|
| vexreg = 0;
|
| im_len = 0;
|
| im_sign = 0;
|
| insn->postop = X86_POSTOP_NONE;
|
| insn->rex = 0;
|
| - pdrex = (info->drex_oc0 & NEED_DREX_MASK) ? &drex : NULL;
|
|
|
| - /* Move VEX data (stored in special prefix) to separate location to
|
| + /* Move VEX/XOP data (stored in special prefix) to separate location to
|
| * allow overriding of special prefix by modifiers.
|
| */
|
| - if ((insn->special_prefix & 0xF0) == 0xC0) {
|
| + if ((insn->special_prefix & 0xF0) == 0xC0 ||
|
| + (insn->special_prefix & 0xF0) == 0x80) {
|
| vexdata = insn->special_prefix;
|
| insn->special_prefix = 0;
|
| }
|
| @@ -1199,7 +1218,7 @@
|
| insn->x86_ea =
|
| yasm_x86__ea_create_reg(insn->x86_ea,
|
| (unsigned long)op->data.reg, &insn->rex,
|
| - pdrex, mode_bits);
|
| + mode_bits);
|
| break;
|
| case YASM_INSN__OPERAND_SEGREG:
|
| yasm_internal_error(
|
| @@ -1236,8 +1255,7 @@
|
| yasm_internal_error(N_("invalid operand conversion"));
|
| insn->x86_ea =
|
| yasm_x86__ea_create_reg(insn->x86_ea,
|
| - (unsigned long)op->data.reg, &insn->rex, pdrex,
|
| - mode_bits);
|
| + (unsigned long)op->data.reg, &insn->rex, mode_bits);
|
| vexreg = op->data.reg & 0xF;
|
| break;
|
| case OPA_Imm:
|
| @@ -1265,8 +1283,8 @@
|
| if (op->type == YASM_INSN__OPERAND_SEGREG)
|
| spare = (unsigned char)(op->data.reg&7);
|
| else if (op->type == YASM_INSN__OPERAND_REG) {
|
| - if (yasm_x86__set_rex_from_reg(&insn->rex, pdrex,
|
| - &spare, op->data.reg, mode_bits, X86_REX_R))
|
| + if (yasm_x86__set_rex_from_reg(&insn->rex, &spare,
|
| + op->data.reg, mode_bits, X86_REX_R))
|
| return;
|
| } else
|
| yasm_internal_error(N_("invalid operand conversion"));
|
| @@ -1274,16 +1292,16 @@
|
| case OPA_SpareVEX:
|
| if (op->type != YASM_INSN__OPERAND_REG)
|
| yasm_internal_error(N_("invalid operand conversion"));
|
| - if (yasm_x86__set_rex_from_reg(&insn->rex, pdrex,
|
| - &spare, op->data.reg, mode_bits, X86_REX_R))
|
| + if (yasm_x86__set_rex_from_reg(&insn->rex, &spare,
|
| + op->data.reg, mode_bits, X86_REX_R))
|
| return;
|
| vexreg = op->data.reg & 0xF;
|
| break;
|
| case OPA_Op0Add:
|
| if (op->type == YASM_INSN__OPERAND_REG) {
|
| unsigned char opadd;
|
| - if (yasm_x86__set_rex_from_reg(&insn->rex, pdrex,
|
| - &opadd, op->data.reg, mode_bits, X86_REX_B))
|
| + if (yasm_x86__set_rex_from_reg(&insn->rex, &opadd,
|
| + op->data.reg, mode_bits, X86_REX_B))
|
| return;
|
| insn->opcode.opcode[0] += opadd;
|
| } else
|
| @@ -1292,8 +1310,8 @@
|
| case OPA_Op1Add:
|
| if (op->type == YASM_INSN__OPERAND_REG) {
|
| unsigned char opadd;
|
| - if (yasm_x86__set_rex_from_reg(&insn->rex, pdrex,
|
| - &opadd, op->data.reg, mode_bits, X86_REX_B))
|
| + if (yasm_x86__set_rex_from_reg(&insn->rex, &opadd,
|
| + op->data.reg, mode_bits, X86_REX_B))
|
| return;
|
| insn->opcode.opcode[1] += opadd;
|
| } else
|
| @@ -1304,10 +1322,10 @@
|
| insn->x86_ea =
|
| yasm_x86__ea_create_reg(insn->x86_ea,
|
| (unsigned long)op->data.reg, &insn->rex,
|
| - pdrex, mode_bits);
|
| + mode_bits);
|
| if (!insn->x86_ea ||
|
| - yasm_x86__set_rex_from_reg(&insn->rex, pdrex,
|
| - &spare, op->data.reg, mode_bits, X86_REX_R)) {
|
| + yasm_x86__set_rex_from_reg(&insn->rex, &spare,
|
| + op->data.reg, mode_bits, X86_REX_R)) {
|
| if (insn->x86_ea)
|
| yasm_xfree(insn->x86_ea);
|
| yasm_xfree(insn);
|
| @@ -1340,13 +1358,6 @@
|
| yasm_x86__ea_destroy(op->data.ea);
|
| break;
|
| }
|
| - case OPA_DREX:
|
| - if (op->type == YASM_INSN__OPERAND_REG) {
|
| - drex &= 0x0F;
|
| - drex |= (op->data.reg << 4) & 0xF0;
|
| - } else
|
| - yasm_internal_error(N_("invalid operand conversion"));
|
| - break;
|
| case OPA_VEX:
|
| if (op->type != YASM_INSN__OPERAND_REG)
|
| yasm_internal_error(N_("invalid operand conversion"));
|
| @@ -1441,9 +1452,7 @@
|
| }
|
|
|
| if (insn->x86_ea) {
|
| - yasm_x86__ea_init(insn->x86_ea, spare, drex,
|
| - (unsigned int)(info->drex_oc0 & NEED_DREX_MASK),
|
| - prev_bc);
|
| + yasm_x86__ea_init(insn->x86_ea, spare, prev_bc);
|
| for (i=0; i<id_insn->insn.num_segregs; i++)
|
| yasm_ea_set_segreg(&insn->x86_ea->ea, id_insn->insn.segregs[i]);
|
| } else if (id_insn->insn.num_segregs > 0 && insn->special_prefix == 0) {
|
| @@ -1513,8 +1522,7 @@
|
| * opcode 0 being a mov instruction!
|
| */
|
| insn->x86_ea = yasm_x86__ea_create_reg(insn->x86_ea,
|
| - (unsigned long)insn->opcode.opcode[0]-0xB8, &rex_temp,
|
| - NULL, 64);
|
| + (unsigned long)insn->opcode.opcode[0]-0xB8, &rex_temp, 64);
|
|
|
| /* Make the imm32s form permanent. */
|
| insn->opcode.opcode[0] = insn->opcode.opcode[1];
|
| @@ -1526,31 +1534,46 @@
|
| break;
|
| }
|
|
|
| - /* Convert to VEX prefixes if requested.
|
| - * To save space in the insn structure, the VEX prefix is written into
|
| + /* Convert to VEX/XOP prefixes if requested.
|
| + * To save space in the insn structure, the VEX/XOP prefix is written into
|
| * special_prefix and the first 2 bytes of the instruction are set to
|
| - * the second two VEX bytes. During calc_len() it may be shortened to
|
| - * one VEX byte (this can only be done after knowledge of REX value).
|
| + * the second two VEX/XOP bytes. During calc_len() it may be shortened to
|
| + * one VEX byte (this can only be done after knowledge of REX value); this
|
| + * further optimization is not possible for XOP.
|
| */
|
| if (vexdata) {
|
| + int xop = ((vexdata & 0xF0) == 0x80);
|
| unsigned char vex1 = 0xE0; /* R=X=B=1, mmmmm=0 */
|
| unsigned char vex2;
|
| - /* Look at the first bytes of the opcode to see what leading bytes
|
| - * to encode in the VEX mmmmm field. Leave R=X=B=1 for now.
|
| - */
|
| - if (insn->opcode.opcode[0] != 0x0F)
|
| - yasm_internal_error(N_("first opcode byte of VEX must be 0x0F"));
|
|
|
| - if (insn->opcode.opcode[1] == 0x38)
|
| - vex1 |= 0x02; /* implied 0x0F 0x38 */
|
| - else if (insn->opcode.opcode[1] == 0x3A)
|
| - vex1 |= 0x03; /* implied 0x0F 0x3A */
|
| - else {
|
| - /* Originally a 0F-only opcode; move opcode byte back one position
|
| - * to make room for VEX prefix.
|
| + if (xop) {
|
| + /* Look at the first bytes of the opcode for the XOP mmmmm field.
|
| + * Leave R=X=B=1 for now.
|
| */
|
| + if (insn->opcode.opcode[0] != 0x08 &&
|
| + insn->opcode.opcode[0] != 0x09)
|
| + yasm_internal_error(N_("first opcode byte of XOP must be 0x08 or 0x09"));
|
| + vex1 |= insn->opcode.opcode[0];
|
| + /* Move opcode byte back one byte to make room for XOP prefix. */
|
| insn->opcode.opcode[2] = insn->opcode.opcode[1];
|
| - vex1 |= 0x01; /* implied 0x0F */
|
| + } else {
|
| + /* Look at the first bytes of the opcode to see what leading bytes
|
| + * to encode in the VEX mmmmm field. Leave R=X=B=1 for now.
|
| + */
|
| + if (insn->opcode.opcode[0] != 0x0F)
|
| + yasm_internal_error(N_("first opcode byte of VEX must be 0x0F"));
|
| +
|
| + if (insn->opcode.opcode[1] == 0x38)
|
| + vex1 |= 0x02; /* implied 0x0F 0x38 */
|
| + else if (insn->opcode.opcode[1] == 0x3A)
|
| + vex1 |= 0x03; /* implied 0x0F 0x3A */
|
| + else {
|
| + /* Originally a 0F-only opcode; move opcode byte back one
|
| + * position to make room for VEX prefix.
|
| + */
|
| + insn->opcode.opcode[2] = insn->opcode.opcode[1];
|
| + vex1 |= 0x01; /* implied 0x0F */
|
| + }
|
| }
|
|
|
| /* Check for update of special prefix by modifiers */
|
| @@ -1580,7 +1603,7 @@
|
| (vexdata & 0x7)); /* Lpp */
|
|
|
| /* Save to special_prefix and opcode */
|
| - insn->special_prefix = 0xC4; /* VEX prefix */
|
| + insn->special_prefix = xop ? 0x8F : 0xC4; /* VEX/XOP prefix */
|
| insn->opcode.opcode[0] = vex1;
|
| insn->opcode.opcode[1] = vex2;
|
| insn->opcode.len = 3; /* two prefix bytes and 1 opcode byte */
|
| @@ -1730,7 +1753,7 @@
|
| lcaseid[i] = tolower(id[i]);
|
| lcaseid[id_len] = '\0';
|
|
|
| - switch (arch_x86->parser) {
|
| + switch (PARSER(arch_x86)) {
|
| case X86_PARSER_NASM:
|
| pdata = insnprefix_nasm_find(lcaseid, id_len);
|
| break;
|
| @@ -1770,7 +1793,8 @@
|
| id_insn->mode_bits = arch_x86->mode_bits;
|
| id_insn->suffix = 0;
|
| id_insn->misc_flags = 0;
|
| - id_insn->parser = arch_x86->parser;
|
| + id_insn->parser = PARSER(arch_x86);
|
| +
|
| id_insn->force_strict = arch_x86->force_strict != 0;
|
| id_insn->default_rel = arch_x86->default_rel != 0;
|
| *bc = yasm_bc_create_common(&x86_id_insn_callback, id_insn, line);
|
| @@ -1801,7 +1825,7 @@
|
| id_insn->mode_bits = arch_x86->mode_bits;
|
| id_insn->suffix = pdata->flags;
|
| id_insn->misc_flags = pdata->misc_flags;
|
| - id_insn->parser = arch_x86->parser;
|
| + id_insn->parser = PARSER(arch_x86);
|
| id_insn->force_strict = arch_x86->force_strict != 0;
|
| id_insn->default_rel = arch_x86->default_rel != 0;
|
| *bc = yasm_bc_create_common(&x86_id_insn_callback, id_insn, line);
|
| @@ -1862,9 +1886,9 @@
|
| id_insn->mod_data[2] = 0;
|
| id_insn->num_info = NELEMS(empty_insn);
|
| id_insn->mode_bits = arch_x86->mode_bits;
|
| - id_insn->suffix = 0;
|
| + id_insn->suffix = (PARSER(arch_x86) == X86_PARSER_GAS) ? SUF_Z : 0;
|
| id_insn->misc_flags = 0;
|
| - id_insn->parser = arch_x86->parser;
|
| + id_insn->parser = PARSER(arch_x86);
|
| id_insn->force_strict = arch_x86->force_strict != 0;
|
| id_insn->default_rel = arch_x86->default_rel != 0;
|
|
|
|
|