OP_JECXZ,
OP_JCC,
OP_SCC,
+ // x87
+ // mmx
+ OP_EMMS,
};
enum opr_type {
OPLM_BYTE,
OPLM_WORD,
OPLM_DWORD,
+ OPLM_QWORD,
};
#define MAX_OPERANDS 3
printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
dump_op(op_), ##__VA_ARGS__)
-#define MAX_REGS 8
-
-const char *regs_r32[] = { "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp" };
+const char *regs_r32[] = {
+ "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
+ // not r32, but list here for easy parsing and printing
+ "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
+};
const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
PFO_LE, // e ZF=1||SF!=OF
};
+#define PFOB_O (1 << PFO_O)
+#define PFOB_C (1 << PFO_C)
+#define PFOB_Z (1 << PFO_Z)
+#define PFOB_S (1 << PFO_S)
+
static const char *parsed_flag_op_names[] = {
"o", "c", "z", "be", "s", "p", "l", "le"
};
int reg;
reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
+ if (reg >= 8) {
+ *reg_lmod = OPLM_QWORD;
+ return reg;
+ }
if (reg >= 0) {
*reg_lmod = OPLM_DWORD;
return reg;
opr->lmod = OPLM_BYTE;
return 1;
}
+ if (!strncmp(opr->name, "qword_", 6)) {
+ opr->lmod = OPLM_QWORD;
+ return 1;
+ }
return 0;
}
opr->lmod = OPLM_WORD;
else if (IS(words[w], "byte"))
opr->lmod = OPLM_BYTE;
+ else if (IS(words[w], "qword"))
+ opr->lmod = OPLM_QWORD;
else
aerr("type parsing failed\n");
w += 2;
{ "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
{ "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
{ "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
+ // x87
+ // mmx
+ { "emms", OP_EMMS, 0, 0, OPF_DATA },
+ { "movq", OP_MOV, 2, 2, OPF_DATA },
};
static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
enum opr_lenmod lmod)
{
switch (lmod) {
+ case OPLM_QWORD:
+ return "u64";
case OPLM_DWORD:
return "u32";
case OPLM_WORD:
enum opr_lenmod lmod)
{
switch (lmod) {
+ case OPLM_QWORD:
+ return "";
case OPLM_DWORD:
return "";
case OPLM_WORD:
enum opr_lenmod lmod)
{
switch (lmod) {
+ case OPLM_QWORD:
+ return "*(u64 *)";
case OPLM_DWORD:
return "*(u32 *)";
case OPLM_WORD:
enum opr_lenmod lmod)
{
switch (lmod) {
+ case OPLM_QWORD:
+ return "(s64)";
case OPLM_DWORD:
return "(s32)";
case OPLM_WORD:
static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
{
switch (lmod) {
+ case OPLM_QWORD:
+ return 8;
case OPLM_DWORD:
return 4;
case OPLM_WORD:
static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
{
- if ((unsigned int)popr->reg >= MAX_REGS)
+ if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
ferr(po, "invalid reg: %d\n", popr->reg);
return regs_r32[popr->reg];
}
ferr(po, "lea from reg?\n");
switch (popr->lmod) {
+ case OPLM_QWORD:
+ snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
+ break;
case OPLM_DWORD:
snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
break;
switch (popr->type) {
case OPT_REG:
switch (popr->lmod) {
+ case OPLM_QWORD:
+ snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
+ break;
case OPLM_DWORD:
snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
break;
char buf1[256], buf2[256];
enum opr_lenmod lmod;
- if (po->operand[0].lmod != po->operand[1].lmod)
+ if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
po->operand[0].lmod, po->operand[1].lmod);
lmod = po->operand[0].lmod;
}
out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
- out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_use, 0);
+ if (po->op == OP_DEC)
+ snprintf(buf2, sizeof(buf2), "1");
+ else
+ out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_use, 0);
switch (pfo) {
case PFO_C:
buf1, is_inv ? ">=" : "<", buf2);
break;
- case PFO_LE:
+ case PFO_LE: // !g
snprintf(buf, buf_size, "(%s %s %s)",
buf1, is_inv ? ">" : "<=", buf2);
break;
regmask_now = regmask & ~regmask_arg;
regmask_now &= ~(1 << xSP);
- if (regmask_now) {
+ if (regmask_now & 0x00ff) {
for (reg = 0; reg < 8; reg++) {
if (regmask_now & (1 << reg)) {
fprintf(fout, " u32 %s", regs_r32[reg]);
}
}
}
+ if (regmask_now & 0xff00) {
+ for (reg = 8; reg < 16; reg++) {
+ if (regmask_now & (1 << reg)) {
+ fprintf(fout, " mmxr %s", regs_r32[reg]);
+ if (regmask_init & (1 << reg))
+ fprintf(fout, " = { 0, }");
+ fprintf(fout, ";\n");
+ had_decl = 1;
+ }
+ }
+ }
if (regmask_save) {
for (reg = 0; reg < 8; reg++) {
strcat(g_comment, "bsf");
break;
- case OP_INC:
case OP_DEC:
+ if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
+ for (j = 0; j <= PFO_LE; j++) {
+ if (!(pfomask & (1 << j)))
+ continue;
+ if (j == PFO_Z || j == PFO_S || j == PFO_C)
+ continue;
+
+ out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
+ fprintf(fout, " cond_%s = %s;\n",
+ parsed_flag_op_names[j], buf1);
+ pfomask &= ~(1 << j);
+ }
+ }
+ // fallthrough
+
+ case OP_INC:
+ if (pfomask & (1 << PFO_C))
+ // carry is unaffected by inc/dec.. wtf?
+ ferr(po, "carry propagation needed\n");
+
out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
if (po->operand[0].type == OPT_REG) {
strcpy(buf2, po->op == OP_INC ? "++" : "--");
no_output = 1;
break;
+ // mmx
+ case OP_EMMS:
+ strcpy(g_comment, "(emms)");
+ break;
+
default:
no_output = 1;
ferr(po, "unhandled op type %d, flags %x\n",
g_eqs[g_eqcnt].lmod = OPLM_WORD;
else if (IS(words[2], "byte"))
g_eqs[g_eqcnt].lmod = OPLM_BYTE;
+ else if (IS(words[2], "qword"))
+ g_eqs[g_eqcnt].lmod = OPLM_QWORD;
else
aerr("bad lmod: '%s'\n", words[2]);