# Ensure cpus initializer string is 3 long; 0=CPU_Any
cpus_str.extend(["0", "0", "0"])
- # Number gap elements as we copy
- modnames = []
- n = 0
- for mod in self.modifiers:
- if mod == "Gap":
- modnames.append("Gap%d" % n)
- n += 1
- else:
- modnames.append(mod)
- # Order by priority
- mods = [x for x in ["Gap0", "Op2Add", "Gap1", "Op1Add", "Gap2",
- "Op0Add", "PreAdd", "SpAdd", "OpSizeR", "Imm8",
- "AdSizeR", "DOpS64R", "Op1AddSp"]
- if x in modnames]
+ mods = ["MOD_%s" % x for x in self.modifiers]
+ # Ensure mods initializer string is 3 long
+ mods.extend(["0", "0", "0"])
+ mod_str = "{" + ', '.join(mods[0:3]) + "}"
+ gas_flags = []
if self.gas_only:
- mods.append("GasOnly")
+ gas_flags.append("GAS_ONLY")
if self.gas_illegal:
- mods.append("GasIllegal")
+ gas_flags.append("GAS_ILLEGAL")
if self.gas_no_rev:
- mods.append("GasNoRev")
+ gas_flags.append("GAS_NO_REV")
if self.suffixes:
- mods.extend("GasSuf%s" % x for x in sorted(self.suffixes))
- mod_str = "|".join("MOD_%s" % x for x in mods)
+ gas_flags.extend("SUF_%s" % x for x in sorted(self.suffixes))
+ gas_flags = "|".join(gas_flags)
# Build instruction info structure initializer
- return "{ "+ ", ".join([cpus_str[0],
+ return "{ "+ ", ".join([gas_flags or "0",
+ cpus_str[0],
cpus_str[1],
cpus_str[2],
- mod_str or "0",
+ mod_str,
"%d" % (self.opersize or 0),
"%d" % (self.def_opersize_64 or 0),
self.special_prefix or "0",
if self.cpu is not None:
if len(self.cpu) > 3:
raise ValueError("too many CPUs: %s" % (self.cpu,))
-
- # Ensure CPUs initializer string is at least 3 long
cpus_str.extend("CPU_%s" % x for x in sorted(self.cpu))
# Ensure cpus initializer string is 3 long
if len(self.modifiers) > 3:
raise ValueError("too many modifiers")
+ mods_str = ["0x%02X" % x for x in self.modifiers]
# Ensure modifiers is at least 3 long
- modifiers = [x for x in self.modifiers]
- modifiers.extend([0, 0, 0])
-
- # Find longest list of modifiers in groups
- modnames = []
- for group in groups[self.groupname]:
- if group.modifiers is not None and len(group.modifiers) > len(modnames):
- # Number gap elements as we copy
- modnames = []
- n = 0
- for mod in group.modifiers:
- if mod == "Gap":
- modnames.append("Gap%d" % n)
- n += 1
- else:
- modnames.append(mod)
-
- # Match up and order by priority
- mods = dict(zip(modnames, modifiers))
-
- modifier_str = "".join(reversed(["%02X" % mods[x] for x in
- ["Gap0", "Op2Add", "Gap1", "Op1Add",
- "Gap2", "Op0Add", "PreAdd", "SpAdd",
- "OpSizeR", "Imm8", "AdSizeR", "DOpS64R",
- "Op1AddSp"] if x in mods]))
- if modifier_str:
- modifier_str = "0x" + modifier_str
- else:
- modifier_str = "0"
+ mods_str.extend(["0", "0", "0"])
return ",\t".join(["%s_insn" % self.groupname,
- "(%sUL<<8)|%d" % \
- (modifier_str, len(groups[self.groupname])),
+ "%d" % len(groups[self.groupname]),
suffix_str,
+ mods_str[0],
+ mods_str[1],
+ mods_str[2],
cpus_str[0],
cpus_str[1],
cpus_str[2]])
def __str__(self):
return ",\t".join(["NULL",
- "X86_" + self.groupname,
+ "X86_%s>>8" % self.groupname,
"0x%02X" % self.value,
+ "0",
+ "0",
+ "0",
self.only64 and "CPU_64" or "0",
"0",
"0"])
static const char *cpu_find_reverse(unsigned int cpu0, unsigned int cpu1,
unsigned int cpu2);
-/* Opcode modifiers. The opcode bytes are in "reverse" order because the
- * parameters are read from the arch-specific data in LSB->MSB order.
- * (only for asthetic reasons in the lexer code below, no practical reason).
- */
-#define MOD_Gap0 (1UL<<0) /* Eats a parameter */
-#define MOD_Op2Add (1UL<<1) /* Parameter adds to opcode byte 2 */
-#define MOD_Gap1 (1UL<<2) /* Eats a parameter */
-#define MOD_Op1Add (1UL<<3) /* Parameter adds to opcode byte 1 */
-#define MOD_Gap2 (1UL<<4) /* Eats a parameter */
-#define MOD_Op0Add (1UL<<5) /* Parameter adds to opcode byte 0 */
-#define MOD_PreAdd (1UL<<6) /* Parameter adds to "special" prefix */
-#define MOD_SpAdd (1UL<<7) /* Parameter adds to "spare" value */
-#define MOD_OpSizeR (1UL<<8) /* Parameter replaces opersize */
-#define MOD_Imm8 (1UL<<9) /* Parameter is included as immediate byte */
-#define MOD_AdSizeR (1UL<<10) /* Parameter replaces addrsize (jmp only) */
-#define MOD_DOpS64R (1UL<<11) /* Parameter replaces default 64-bit opersize */
-#define MOD_Op1AddSp (1UL<<12) /* Parameter is added as "spare" to opcode byte 2 */
-
-/* Modifiers that aren't: these are used with the GAS parser to indicate
- * special cases.
- */
-#define MOD_GasOnly (1UL<<13) /* Only available in GAS mode */
-#define MOD_GasIllegal (1UL<<14) /* Illegal in GAS mode */
-#define MOD_GasNoRev (1UL<<15) /* Don't reverse operands */
-#define MOD_GasSufB (1UL<<16) /* GAS B suffix ok */
-#define MOD_GasSufW (1UL<<17) /* GAS W suffix ok */
-#define MOD_GasSufL (1UL<<18) /* GAS L suffix ok */
-#define MOD_GasSufQ (1UL<<19) /* GAS Q suffix ok */
-#define MOD_GasSufS (1UL<<20) /* GAS S suffix ok */
-#define MOD_GasSuf_SHIFT 16
-#define MOD_GasSuf_MASK (0x1FUL<<16)
+/* Opcode modifiers. */
+#define MOD_Gap 0 /* Eats a parameter / does nothing */
+#define MOD_PreAdd 1 /* Parameter adds to "special" prefix */
+#define MOD_Op0Add 2 /* Parameter adds to opcode byte 0 */
+#define MOD_Op1Add 3 /* Parameter adds to opcode byte 1 */
+#define MOD_Op2Add 4 /* Parameter adds to opcode byte 2 */
+#define MOD_SpAdd 5 /* Parameter adds to "spare" value */
+#define MOD_OpSizeR 6 /* Parameter replaces opersize */
+#define MOD_Imm8 7 /* Parameter is included as immediate byte */
+#define MOD_AdSizeR 8 /* Parameter replaces addrsize (jmp only) */
+#define MOD_DOpS64R 9 /* Parameter replaces default 64-bit opersize */
+#define MOD_Op1AddSp 10 /* Parameter is added as "spare" to opcode byte 2 */
+
+/* GAS suffix flags for instructions */
+enum {
+ 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,
+
+ /* 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_suffix_flags;
/* Operand types. These are more detailed than the "general" types for all
* architectures, as they include the size, for instance.
#define OPAP_MASK (7UL<<17)
typedef struct x86_insn_info {
+ /* GAS suffix flags */
+ unsigned int gas_flags:8; /* Enabled for these GAS suffixes */
+
/* The CPU feature flags needed to execute this instruction. This is OR'ed
* with arch-specific data[2]. This combined value is compared with
* cpu_enabled to see if all bits set here are set in cpu_enabled--if so,
* count of insn_info structures in the instruction grouping, there can
* only be a maximum of 3 modifiers.
*/
- unsigned long modifiers;
+ unsigned char modifiers[3];
/* Operand Size */
unsigned char opersize;
wordptr cpu_enabled;
/* Modifier data */
- unsigned long mod_data;
+ unsigned char mod_data[3];
/* Number of elements in the instruction parse group */
unsigned int num_info:8;
x86_jmp *jmp;
int num_info = id_insn->num_info;
const x86_insn_info *info = id_insn->group;
- unsigned long mod_data = id_insn->mod_data;
+ unsigned char *mod_data = id_insn->mod_data;
unsigned int mode_bits = id_insn->mode_bits;
/*unsigned char suffix = id_insn->suffix;*/
yasm_insn_operand *op;
static const unsigned char size_lookup[] = {0, 8, 16, 32, 64, 80, 128, 0};
+ unsigned int i;
/* We know the target is in operand 0, but sanity check for Imm. */
op = yasm_insn_ops_first(&id_insn->insn);
& OPS_MASK)>>OPS_SHIFT];
/* Check for address size override */
- if (jinfo->modifiers & MOD_AdSizeR)
- jmp->common.addrsize = (unsigned char)(mod_data & 0xFF);
+ for (i=0; i<NELEMS(info->modifiers); i++) {
+ if (jinfo->modifiers[i] == MOD_AdSizeR)
+ jmp->common.addrsize = mod_data[i];
+ }
/* Scan through other infos for this insn looking for short/near versions.
* Needs to match opersize and number of operands, also be within CPU.
switch ((int)(insn_operands[info->operands_index+0] & OPTM_MASK)) {
case OPTM_Short:
x86_finalize_opcode(&jmp->shortop, info);
- if (info->modifiers & MOD_Op0Add)
- jmp->shortop.opcode[0] += (unsigned char)(mod_data & 0xFF);
+ for (i=0; i<NELEMS(info->modifiers); i++) {
+ if (info->modifiers[i] == MOD_Op0Add)
+ jmp->shortop.opcode[0] += mod_data[i];
+ }
break;
case OPTM_Near:
x86_finalize_opcode(&jmp->nearop, info);
- if (info->modifiers & MOD_Op1Add)
- jmp->nearop.opcode[1] += (unsigned char)(mod_data & 0xFF);
+ for (i=0; i<NELEMS(info->modifiers); i++) {
+ if (info->modifiers[i] == MOD_Op1Add)
+ jmp->nearop.opcode[1] += mod_data[i];
+ }
break;
}
}
unsigned int cpu0 = info->cpu0;
unsigned int cpu1 = info->cpu1;
unsigned int cpu2 = info->cpu2;
+ unsigned int gas_flags = info->gas_flags;
unsigned int size;
int mismatch = 0;
int i;
continue;
/* Match parser mode */
- if ((info->modifiers & MOD_GasOnly)
- && id_insn->parser != X86_PARSER_GAS)
+ if ((gas_flags & GAS_ONLY) && id_insn->parser != X86_PARSER_GAS)
continue;
- if ((info->modifiers & MOD_GasIllegal)
- && id_insn->parser == X86_PARSER_GAS)
+ if ((gas_flags & GAS_ILLEGAL) && id_insn->parser == X86_PARSER_GAS)
continue;
/* Match suffix (if required) */
- if (suffix != 0 && suffix != 0x80
- && ((suffix<<MOD_GasSuf_SHIFT) & info->modifiers) == 0)
+ if (suffix != 0 && suffix != WEAK
+ && ((suffix & SUF_MASK) & (gas_flags & SUF_MASK)) == 0)
continue;
/* Use reversed operands in GAS mode if not otherwise specified */
use_ops = ops;
- if (id_insn->parser == X86_PARSER_GAS
- && !(info->modifiers & MOD_GasNoRev))
+ if (id_insn->parser == X86_PARSER_GAS && !(gas_flags & GAS_NO_REV))
use_ops = rev_ops;
if (id_insn->insn.num_operands == 0) {
x86_id_insn *id_insn = (x86_id_insn *)bc->contents;
x86_insn *insn;
const x86_insn_info *info = id_insn->group;
- unsigned long mod_data = id_insn->mod_data;
unsigned int mode_bits = id_insn->mode_bits;
+ unsigned char *mod_data = id_insn->mod_data;
yasm_insn_operand *op, *ops[4], *rev_ops[4];
/*@null@*/ yasm_expr *imm;
unsigned char im_len;
insn->rex = 0;
/* Apply modifiers */
- if (info->modifiers & MOD_Gap0)
- mod_data >>= 8;
- if (info->modifiers & MOD_Op2Add) {
- insn->opcode.opcode[2] += (unsigned char)(mod_data & 0xFF);
- mod_data >>= 8;
- }
- if (info->modifiers & MOD_Gap1)
- mod_data >>= 8;
- if (info->modifiers & MOD_Op1Add) {
- insn->opcode.opcode[1] += (unsigned char)(mod_data & 0xFF);
- mod_data >>= 8;
- }
- if (info->modifiers & MOD_Gap2)
- mod_data >>= 8;
- if (info->modifiers & MOD_Op0Add) {
- insn->opcode.opcode[0] += (unsigned char)(mod_data & 0xFF);
- mod_data >>= 8;
- }
- if (info->modifiers & MOD_PreAdd) {
- insn->special_prefix += (unsigned char)(mod_data & 0xFF);
- mod_data >>= 8;
- }
- if (info->modifiers & MOD_SpAdd) {
- spare += (unsigned char)(mod_data & 0xFF);
- mod_data >>= 8;
- }
- if (info->modifiers & MOD_OpSizeR) {
- insn->common.opersize = (unsigned char)(mod_data & 0xFF);
- mod_data >>= 8;
- }
- if (info->modifiers & MOD_Imm8) {
- imm = yasm_expr_create_ident(yasm_expr_int(
- yasm_intnum_create_uint(mod_data & 0xFF)), bc->line);
- im_len = 8;
- mod_data >>= 8;
- }
- if (info->modifiers & MOD_DOpS64R) {
- insn->def_opersize_64 = (unsigned char)(mod_data & 0xFF);
- mod_data >>= 8;
- }
- if (info->modifiers & MOD_Op1AddSp) {
- insn->opcode.opcode[1] += (unsigned char)(mod_data & 0xFF)<<3;
- /*mod_data >>= 8;*/
+ for (i=0; i<NELEMS(info->modifiers); i++) {
+ switch (info->modifiers[i]) {
+ case MOD_Gap:
+ break;
+ case MOD_PreAdd:
+ insn->special_prefix += mod_data[i];
+ break;
+ case MOD_Op0Add:
+ insn->opcode.opcode[0] += mod_data[i];
+ break;
+ case MOD_Op1Add:
+ insn->opcode.opcode[1] += mod_data[i];
+ break;
+ case MOD_Op2Add:
+ insn->opcode.opcode[2] += mod_data[i];
+ break;
+ case MOD_SpAdd:
+ spare += mod_data[i];
+ break;
+ case MOD_OpSizeR:
+ insn->common.opersize = mod_data[i];
+ break;
+ case MOD_Imm8:
+ imm = yasm_expr_create_ident(yasm_expr_int(
+ yasm_intnum_create_uint(mod_data[i])), bc->line);
+ im_len = 8;
+ break;
+ case MOD_DOpS64R:
+ insn->def_opersize_64 = mod_data[i];
+ break;
+ case MOD_Op1AddSp:
+ insn->opcode.opcode[1] += mod_data[i]<<3;
+ break;
+ default:
+ break;
+ }
}
/* In 64-bit mode, if opersize is 64 and default is not 64,
/* Use reversed operands in GAS mode if not otherwise specified */
if (id_insn->parser == X86_PARSER_GAS
- && !(info->modifiers & MOD_GasNoRev))
+ && !(info->gas_flags & GAS_NO_REV))
use_ops = rev_ops;
for (i = 0, op = use_ops[0]; op && i<info->num_operands;
yasm_x86__bc_transform_insn(bc, insn);
}
-/* suffix flags for instructions */
-enum {
- NONE = 0,
- SUF_B = (MOD_GasSufB >> MOD_GasSuf_SHIFT),
- SUF_W = (MOD_GasSufW >> MOD_GasSuf_SHIFT),
- SUF_L = (MOD_GasSufL >> MOD_GasSuf_SHIFT),
- SUF_Q = (MOD_GasSufQ >> MOD_GasSuf_SHIFT),
- SUF_S = (MOD_GasSufS >> MOD_GasSuf_SHIFT),
- WEAK = 0x80 /* Relaxed operand mode for GAS */
-} flags;
-
/* Static parse data structure for instructions */
typedef struct insnprefix_parse_data {
const char *name;
/* instruction parse group - NULL if prefix */
/*@null@*/ const x86_insn_info *group;
- /* For instruction, modifier in upper 24 bits, number of elements in group
- * in lower 8 bits.
- * For prefix, prefix type.
+ /* For instruction, number of elements in group in lower 8 bits.
+ * For prefix, prefix type shifted right by 8.
*/
- unsigned long data1;
+ unsigned int num_info:8;
- /* For instruction, suffix flags.
+ /* For instruction, GAS suffix flags.
* For prefix, prefix value.
*/
unsigned int flags:8;
+ /* Instruction modifier data. */
+ unsigned int mod_data0:8;
+ unsigned int mod_data1:8;
+ unsigned int mod_data2:8;
+
/* CPU flags */
unsigned int cpu0:8;
unsigned int cpu1:8;
yasm_insn_initialize(&id_insn->insn);
id_insn->group = not64_insn;
id_insn->cpu_enabled = cpu_enabled;
- id_insn->mod_data = 0;
+ id_insn->mod_data[0] = 0;
+ id_insn->mod_data[1] = 0;
+ id_insn->mod_data[2] = 0;
id_insn->num_info = NELEMS(not64_insn);
id_insn->mode_bits = arch_x86->mode_bits;
id_insn->suffix = 0;
yasm_insn_initialize(&id_insn->insn);
id_insn->group = pdata->group;
id_insn->cpu_enabled = cpu_enabled;
- id_insn->mod_data = pdata->data1 >> 8;
- id_insn->num_info = pdata->data1 & 0xff;
+ id_insn->mod_data[0] = pdata->mod_data0;
+ id_insn->mod_data[1] = pdata->mod_data1;
+ id_insn->mod_data[2] = pdata->mod_data2;
+ id_insn->num_info = pdata->num_info;
id_insn->mode_bits = arch_x86->mode_bits;
id_insn->suffix = pdata->flags;
id_insn->parser = arch_x86->parser;
*bc = yasm_bc_create_common(&x86_id_insn_callback, id_insn, line);
return YASM_ARCH_INSN;
} else {
- unsigned long type = pdata->data1;
+ unsigned long type = pdata->num_info<<8;
unsigned long value = pdata->flags;
if (arch_x86->mode_bits == 64 && type == X86_OPERSIZE && value == 32) {
yasm_insn_initialize(&id_insn->insn);
id_insn->group = empty_insn;
id_insn->cpu_enabled = arch_x86->cpu_enables[arch_x86->active_cpu];
- id_insn->mod_data = 0;
+ id_insn->mod_data[0] = 0;
+ id_insn->mod_data[1] = 0;
+ 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;