OPF_JMP = (1 << 3), /* branches, ret and call */
OPF_CC = (1 << 4), /* uses flags */
OPF_TAIL = (1 << 5), /* ret or tail call */
- OPF_REP = (1 << 6), /* prefixed by rep */
- OPF_RSAVE = (1 << 7), /* push/pop is local reg save/load */
+ OPF_RSAVE = (1 << 6), /* push/pop is local reg save/load */
+ OPF_REP = (1 << 7), /* prefixed by rep */
+ OPF_REPZ = (1 << 8), /* rep is repe/repz */
+ OPF_REPNZ = (1 << 9), /* rep is repne/repnz */
};
enum op_op {
OP_CDQ,
OP_STOS,
OP_MOVS,
+ OP_CMPS,
OP_RET,
OP_ADD,
OP_SUB,
struct parsed_opr {
enum opr_type type;
enum opr_lenmod lmod;
- unsigned int is_ptr:1; // pointer in C
+ unsigned int is_ptr:1; // pointer in C
+ unsigned int is_array:1; // array in C
int reg;
unsigned int val;
char name[256];
struct {
union {
char *label;
- int val;
+ unsigned int val;
} u;
int bt_i;
} *d;
static int g_stack_fsz;
static int g_ida_func_attr;
#define ferr(op_, fmt, ...) do { \
- printf("error:%s:#%ld: '%s': " fmt, g_func, (op_) - ops, \
+ printf("error:%s:#%zd: '%s': " fmt, g_func, (op_) - ops, \
dump_op(op_), ##__VA_ARGS__); \
fcloseall(); \
exit(1); \
return -1;
}
-static void printf_number(char *buf, size_t buf_size, long number)
+static void printf_number(char *buf, size_t buf_size,
+ unsigned long number)
{
// output in C-friendly form
snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
return -1;
}
-static long parse_number(const char *number)
+static unsigned long parse_number(const char *number)
{
int len = strlen(number);
const char *p = number;
char *endp = NULL;
+ unsigned long ret;
int neg = 0;
int bad;
- long ret;
if (*p == '-') {
neg = 1;
if (len > 1 && *p == '0')
p++;
if (number[len - 1] == 'h') {
- ret = strtol(p, &endp, 16);
+ ret = strtoul(p, &endp, 16);
bad = (*endp != 'h');
}
else {
- ret = strtol(p, &endp, 10);
+ ret = strtoul(p, &endp, 10);
bad = (*endp != 0);
}
if (bad)
return 0;
}
-static int guess_lmod_from_c_type(struct parsed_opr *opr, const char *c_type)
+static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
+ const struct parsed_type *c_type)
{
- static const char *ptr_types[] = {
- "LPCSTR",
- };
static const char *dword_types[] = {
"int", "_DWORD", "DWORD", "HANDLE", "HWND", "HMODULE",
};
static const char *byte_types[] = {
"char", "__int8", "unsigned __int8", "BYTE",
};
+ const char *n;
int i;
- if (strchr(c_type, '*')) {
- opr->lmod = OPLM_DWORD;
- opr->is_ptr = 1;
+ if (c_type->is_ptr) {
+ *lmod = OPLM_DWORD;
return 1;
}
- for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
- if (IS(c_type, dword_types[i])) {
- opr->lmod = OPLM_DWORD;
- return 1;
- }
- }
+ n = skip_type_mod(c_type->name);
- for (i = 0; i < ARRAY_SIZE(ptr_types); i++) {
- if (IS(c_type, ptr_types[i])) {
- opr->lmod = OPLM_DWORD;
- opr->is_ptr = 1;
+ for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
+ if (IS(n, dword_types[i])) {
+ *lmod = OPLM_DWORD;
return 1;
}
}
for (i = 0; i < ARRAY_SIZE(word_types); i++) {
- if (IS(c_type, word_types[i])) {
- opr->lmod = OPLM_WORD;
+ if (IS(n, word_types[i])) {
+ *lmod = OPLM_WORD;
return 1;
}
}
for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
- if (IS(c_type, byte_types[i])) {
- opr->lmod = OPLM_BYTE;
+ if (IS(n, byte_types[i])) {
+ *lmod = OPLM_BYTE;
return 1;
}
}
- anote("unhandled C type '%s' for '%s'\n", c_type, opr->name);
return 0;
}
{
struct parsed_proto pp;
enum opr_lenmod tmplmod;
+ unsigned long number;
int ret, len;
- long number;
int wordc_in;
char *tmp;
int i;
opr->lmod = OPLM_DWORD;
opr->is_ptr = 1;
}
- else if (opr->lmod == OPLM_UNSPEC)
- guess_lmod_from_c_type(opr, pp.ret_type);
+ else if (opr->lmod == OPLM_UNSPEC) {
+ if (!guess_lmod_from_c_type(&opr->lmod, &pp.type))
+ anote("unhandled C type '%s' for '%s'\n", pp.type.name, opr->name);
+ }
+ opr->is_ptr = pp.type.is_ptr;
+ opr->is_array = pp.type.is_array;
}
proto_release(&pp);
unsigned int flags;
} pref_table[] = {
{ "rep", OPF_REP },
+ { "repe", OPF_REP|OPF_REPZ },
+ { "repz", OPF_REP|OPF_REPZ },
+ { "repne", OPF_REP|OPF_REPNZ },
+ { "repnz", OPF_REP|OPF_REPNZ },
};
static const struct {
{ "movsb",OP_MOVS, 0, 0, OPF_DATA },
{ "movsw",OP_MOVS, 0, 0, OPF_DATA },
{ "movsd",OP_MOVS, 0, 0, OPF_DATA },
+ { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
+ { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
+ { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
{ "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
{ "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
{ "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
break;
case OP_MOVS:
+ case OP_CMPS:
if (op->operand_cnt != 0)
break;
- if (IS(words[op_w], "movsb"))
+ if (words[op_w][4] == 'b')
lmod = OPLM_BYTE;
- else if (IS(words[op_w], "movsw"))
+ else if (words[op_w][4] == 'w')
lmod = OPLM_WORD;
- else if (IS(words[op_w], "movsd"))
+ else if (words[op_w][4] == 'd')
lmod = OPLM_DWORD;
op->operand_cnt = 3;
setup_reg_opr(&op->operand[0], xDI, lmod, &op->regmask_src);
op->operand[1].lmod = OPLM_BYTE;
break;
+ case OP_PUSH:
+ if (op->operand[0].lmod == OPLM_UNSPEC
+ && (op->operand[0].type == OPT_CONST
+ || op->operand[0].type == OPT_OFFSET
+ || op->operand[0].type == OPT_LABEL))
+ op->operand[0].lmod = OPLM_DWORD;
+ break;
+
+ // alignment
+ case OP_MOV:
+ if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
+ && op->operand[0].reg == xDI && op->operand[1].reg == xDI)
+ {
+ op->flags |= OPF_RMD;
+ }
+ break;
+
default:
break;
}
static void stack_frame_access(struct parsed_op *po,
enum opr_lenmod lmod, char *buf, size_t buf_size,
- const char *name, int is_src, int is_lea)
+ const char *name, const char *cast, int is_src, int is_lea)
{
+ enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
const char *prefix = "";
char ofs_reg[16] = { 0, };
struct parsed_equ *eq;
ferr(po, "offset %d (%s) doesn't map to any arg\n",
offset, bp_arg);
if (ofs_reg[0] != 0)
- ferr(po, "offset reg on arg acecss?\n");
+ ferr(po, "offset reg on arg access?\n");
for (i = arg_s = 0; i < g_func_pp.argc; i++) {
if (g_func_pp.arg[i].reg != NULL)
if (is_lea)
ferr(po, "lea to arg?\n");
- snprintf(buf, buf_size, "%sa%d", is_src ? "(u32)" : "", i + 1);
+ switch (lmod)
+ {
+ case OPLM_BYTE:
+ if (is_src && (offset & 3) == 0)
+ snprintf(buf, buf_size, "(u8)a%d", i + 1);
+ else
+ snprintf(buf, buf_size, "BYTE%d(a%d)", offset & 3, i + 1);
+ break;
+
+ case OPLM_WORD:
+ if (offset & 1)
+ ferr(po, "unaligned arg access\n");
+ if (is_src && (offset & 2) == 0)
+ snprintf(buf, buf_size, "(u16)a%d", i + 1);
+ else
+ snprintf(buf, buf_size, "%sWORD(a%d)",
+ (offset & 2) ? "HI" : "LO", i + 1);
+ break;
+
+ case OPLM_DWORD:
+ if (offset & 3)
+ ferr(po, "unaligned arg access\n");
+ if (cast[0])
+ prefix = cast;
+ else if (is_src)
+ prefix = "(u32)";
+ snprintf(buf, buf_size, "%sa%d", prefix, i + 1);
+ break;
+
+ default:
+ ferr(po, "bp_arg bad lmod: %d\n", lmod);
+ }
+
+ // common problem
+ guess_lmod_from_c_type(&tmp_lmod, &g_func_pp.arg[i].type);
+ if ((offset & 3) && tmp_lmod != OPLM_DWORD)
+ ferr(po, "bp_arg arg/w offset %d and type '%s'\n",
+ offset, g_func_pp.arg[i].type.name);
}
else {
if (g_stack_fsz == 0)
if (is_lea)
prefix = "(u32)&";
+ else
+ prefix = cast;
switch (lmod)
{
case OPLM_BYTE:
- if (ofs_reg[0] != 0)
- snprintf(buf, buf_size, "%ssf.b[%d+%s]",
- prefix, sf_ofs, ofs_reg);
- else
- snprintf(buf, buf_size, "%ssf.b[%d]",
- prefix, sf_ofs);
+ snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
+ prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
break;
+
case OPLM_WORD:
- if (ofs_reg[0] != 0)
- snprintf(buf, buf_size, "%ssf.w[%d+%s/2]",
- prefix, sf_ofs / 2, ofs_reg);
- else
- snprintf(buf, buf_size, "%ssf.w[%d]",
- prefix, sf_ofs / 2);
+ if ((sf_ofs & 1) || ofs_reg[0] != 0) {
+ // known unaligned or possibly unaligned
+ strcat(g_comment, " unaligned");
+ if (prefix[0] == 0)
+ prefix = "*(u16 *)&";
+ snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
+ prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
+ break;
+ }
+ snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
break;
+
case OPLM_DWORD:
- if (ofs_reg[0] != 0)
- snprintf(buf, buf_size, "%ssf.d[%d+%s/4]",
- prefix, sf_ofs / 4, ofs_reg);
- else
- snprintf(buf, buf_size, "%ssf.d[%d]",
- prefix, sf_ofs / 4);
+ if ((sf_ofs & 3) || ofs_reg[0] != 0) {
+ // known unaligned or possibly unaligned
+ strcat(g_comment, " unaligned");
+ if (prefix[0] == 0)
+ prefix = "*(u32 *)&";
+ snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
+ prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
+ break;
+ }
+ snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
break;
+
default:
ferr(po, "bp_stack bad lmod: %d\n", lmod);
}
}
}
+static void check_label_read_ref(struct parsed_op *po, const char *name)
+{
+ if (IS_START(name, "sub_"))
+ ferr(po, "func reference?\n");
+}
+
static char *out_src_opr(char *buf, size_t buf_size,
- struct parsed_op *po, struct parsed_opr *popr, int is_lea)
+ struct parsed_op *po, struct parsed_opr *popr, const char *cast,
+ int is_lea)
{
char tmp1[256], tmp2[256];
char expr[256];
int ret;
+ if (cast == NULL)
+ cast = "";
+
switch (popr->type) {
case OPT_REG:
if (is_lea)
switch (popr->lmod) {
case OPLM_DWORD:
- snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
+ snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
break;
case OPLM_WORD:
snprintf(buf, buf_size, "(u16)%s", opr_reg_p(po, popr));
case OPT_REGMEM:
if (parse_stack_el(popr->name, NULL)) {
stack_frame_access(po, popr->lmod, buf, buf_size,
- popr->name, 1, is_lea);
+ popr->name, cast, 1, is_lea);
break;
}
break;
}
- snprintf(buf, buf_size, "%s(%s)",
- lmod_cast_u_ptr(po, popr->lmod), expr);
+ if (cast[0] == 0)
+ cast = lmod_cast_u_ptr(po, popr->lmod);
+ snprintf(buf, buf_size, "%s(%s)", cast, expr);
break;
case OPT_LABEL:
+ check_label_read_ref(po, popr->name);
+ if (cast[0] == 0 && popr->is_ptr)
+ cast = "(u32)";
if (is_lea)
snprintf(buf, buf_size, "(u32)&%s", popr->name);
else
- snprintf(buf, buf_size, "(u32)%s", popr->name);
+ snprintf(buf, buf_size, "%s%s%s", cast, popr->name,
+ popr->is_array ? "[0]" : "");
break;
case OPT_OFFSET:
+ check_label_read_ref(po, popr->name);
+ if (cast[0] == 0)
+ cast = "(u32)";
if (is_lea)
ferr(po, "lea an offset?\n");
- snprintf(buf, buf_size, "(u32)&%s", popr->name);
+ snprintf(buf, buf_size, "%s&%s", cast, popr->name);
break;
case OPT_CONST:
if (is_lea)
ferr(po, "lea from const?\n");
- printf_number(buf, buf_size, popr->val);
+ snprintf(buf, buf_size, "%s", cast);
+ ret = strlen(buf);
+ printf_number(buf + ret, buf_size - ret, popr->val);
break;
default:
case OPT_REGMEM:
if (parse_stack_el(popr->name, NULL)) {
stack_frame_access(po, popr->lmod, buf, buf_size,
- popr->name, 0, 0);
+ popr->name, "", 0, 0);
break;
}
- return out_src_opr(buf, buf_size, po, popr, 0);
+ return out_src_opr(buf, buf_size, po, popr, NULL, 0);
case OPT_LABEL:
- snprintf(buf, buf_size, "%s", popr->name);
+ snprintf(buf, buf_size, "%s%s", popr->name,
+ popr->is_array ? "[0]" : "");
break;
default:
return buf;
}
+static char *out_src_opr_u32(char *buf, size_t buf_size,
+ struct parsed_op *po, struct parsed_opr *popr)
+{
+ return out_src_opr(buf, buf_size, po, popr, NULL, 0);
+}
+
static enum parsed_flag_op split_cond(struct parsed_op *po,
enum op_op op, int *is_inv)
{
if (po->op == OP_TEST) {
if (IS(opr_name(po, 0), opr_name(po, 1))) {
- out_src_opr(buf3, sizeof(buf3), po, &po->operand[0], 0);
+ out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
}
else {
- out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
- out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0);
+ out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
+ out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
}
out_test_for_cc(buf, buf_size, po, pfo, is_inv,
po->operand[0].lmod, buf3);
}
else if (po->op == OP_CMP) {
- out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], 0);
- out_src_opr(buf3, sizeof(buf3), po, &po->operand[1], 0);
+ out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
+ out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[1]);
out_cmp_for_cc(buf, buf_size, po, pfo, is_inv,
po->operand[0].lmod, buf2, buf3);
}
// scan for positive, constant esp adjust
static int scan_for_esp_adjust(int i, int opcnt, int *adj)
{
+ struct parsed_op *po;
+ *adj = 0;
+
for (; i < opcnt; i++) {
- if (ops[i].op == OP_ADD && ops[i].operand[0].reg == xSP) {
- if (ops[i].operand[1].type != OPT_CONST)
+ po = &ops[i];
+
+ if (po->op == OP_ADD && po->operand[0].reg == xSP) {
+ if (po->operand[1].type != OPT_CONST)
ferr(&ops[i], "non-const esp adjust?\n");
- *adj = ops[i].operand[1].val;
+ *adj += po->operand[1].val;
if (*adj & 3)
ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
return i;
}
-
- if ((ops[i].flags & (OPF_JMP|OPF_TAIL))
- || ops[i].op == OP_PUSH || ops[i].op == OP_POP)
+ else if (po->op == OP_PUSH)
+ *adj -= lmod_bytes(po, po->operand[0].lmod);
+ else if (po->op == OP_POP)
+ *adj += lmod_bytes(po, po->operand[0].lmod);
+ else if ((po->flags & (OPF_JMP|OPF_TAIL)) && po->op != OP_CALL)
return -1;
+
if (g_labels[i][0] != 0)
return -1;
}
{
struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
struct parsed_opr *last_arith_dst = NULL;
- char buf1[256], buf2[256], buf3[256];
+ char buf1[256], buf2[256], buf3[256], cast[64];
struct parsed_proto *pp, *pp_tmp;
struct parsed_data *pd;
const char *tmpname;
int cmp_result_vars = 0;
int need_mul_var = 0;
int had_decl = 0;
+ int label_pending = 0;
int regmask_save = 0;
int regmask_arg = 0;
int regmask = 0;
if (ret)
ferr(ops, "proto_parse failed for '%s'\n", funcn);
- fprintf(fout, "%s %s(", g_func_pp.ret_type, funcn);
+ fprintf(fout, "%s %s(", g_func_pp.ret_type.name, funcn);
for (i = 0; i < g_func_pp.argc; i++) {
if (i > 0)
fprintf(fout, ", ");
- fprintf(fout, "%s a%d", g_func_pp.arg[i].type, i + 1);
+ fprintf(fout, "%s a%d", g_func_pp.arg[i].type.name, i + 1);
}
fprintf(fout, ")\n{\n");
j /= 4;
if (j > ARRAY_SIZE(pp->arg))
ferr(po, "esp adjust too large?\n");
- pp->ret_type = strdup("int");
+ pp->ret_type.name = strdup("int");
pp->argc = pp->argc_stack = j;
for (arg = 0; arg < pp->argc; arg++)
- pp->arg[arg].type = strdup("int");
+ pp->arg[arg].type.name = strdup("int");
}
else {
ret = proto_parse(fhdr, tmpname, pp);
ferr(po, "proto_parse failed for call '%s'\n", tmpname);
}
- ret = scan_for_esp_adjust(i + 1, opcnt, &j);
+ // look for and make use of esp adjust
+ ret = -1;
+ if (!pp->is_stdcall)
+ ret = scan_for_esp_adjust(i + 1, opcnt, &j);
if (ret >= 0) {
+ if (pp->is_vararg) {
+ if (j / 4 < pp->argc_stack)
+ ferr(po, "esp adjust is too small: %x < %x\n",
+ j, pp->argc_stack * 4);
+ // modify pp to make it have varargs as normal args
+ arg = pp->argc;
+ pp->argc += j / 4 - pp->argc_stack;
+ for (; arg < pp->argc; arg++) {
+ pp->arg[arg].type.name = strdup("int");
+ pp->argc_stack++;
+ }
+ if (pp->argc > ARRAY_SIZE(pp->arg))
+ ferr(po, "too many args\n");
+ }
if (pp->argc_stack != j / 4)
ferr(po, "stack tracking failed: %x %x\n",
- pp->argc_stack, j);
+ pp->argc_stack * 4, j);
+
ops[ret].flags |= OPF_RMD;
+ // a bit of a hack, but deals with use of
+ // single adj for multiple calls
+ ops[ret].operand[1].val -= j;
}
+ else if (pp->is_vararg)
+ ferr(po, "missing esp_adjust for vararg func '%s'\n",
+ pp->name);
// can't call functions with non-__cdecl callbacks yet
for (arg = 0; arg < pp->argc; arg++) {
if (scan_for_mod(tmp_op, ret + 1, i) >= 0)
pfomask = 1 << pfo;
}
+ else if (tmp_op->op == OP_CMPS) {
+ pfomask = 1 << PFO_Z;
+ }
else {
if ((pfo != PFO_Z && pfo != PFO_S && pfo != PFO_P)
|| scan_for_mod_opr0(tmp_op, ret + 1, i) >= 0)
else if (po->op == OP_CALL && po->operand[0].type != OPT_LABEL) {
pp = po->datap;
my_assert_not(pp, NULL);
- fprintf(fout, " %s (*icall%d)(", pp->ret_type, i);
+ fprintf(fout, " %s (*icall%d)(", pp->ret_type.name, i);
for (j = 0; j < pp->argc; j++) {
if (j > 0)
fprintf(fout, ", ");
- fprintf(fout, "%s a%d", pp->arg[j].type, j + 1);
+ fprintf(fout, "%s a%d", pp->arg[j].type.name, j + 1);
}
fprintf(fout, ");\n");
}
}
// declare other regs - special case for eax
- if (!((regmask | regmask_arg) & 1) && !IS(g_func_pp.ret_type, "void")) {
+ if (!((regmask | regmask_arg) & 1)
+ && !IS(g_func_pp.ret_type.name, "void"))
+ {
fprintf(fout, " u32 eax = 0;\n");
had_decl = 1;
}
// output ops
for (i = 0; i < opcnt; i++)
{
- if (g_labels[i][0] != 0 && g_label_refs[i].i != -1)
+ if (g_labels[i][0] != 0 && g_label_refs[i].i != -1) {
fprintf(fout, "\n%s:\n", g_labels[i]);
+ label_pending = 1;
+ }
po = &ops[i];
if (po->flags & OPF_RMD)
else if (last_arith_dst != NULL
&& (pfo == PFO_Z || pfo == PFO_S || pfo == PFO_P))
{
- out_src_opr(buf3, sizeof(buf3), po, last_arith_dst, 0);
+ out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
out_test_for_cc(buf1, sizeof(buf1), po, pfo, is_inv,
last_arith_dst->lmod, buf3);
is_delayed = 1;
}
else if (po->datap != NULL) {
- // use preprocessed results
+ // use preprocessed flag calc results
tmp_op = po->datap;
if (!tmp_op || !(tmp_op->pfomask & (1 << pfo)))
ferr(po, "not prepared for pfo %d\n", pfo);
case OP_MOV:
assert_operand_cnt(2);
propagate_lmod(po, &po->operand[0], &po->operand[1]);
- fprintf(fout, " %s = %s%s;",
+ fprintf(fout, " %s = %s;",
out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
- po->operand[0].is_ptr ? "(void *)" : "",
- out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
+ out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
+ po->operand[0].is_ptr ? "(void *)" : "", 0));
break;
case OP_LEA:
po->operand[1].lmod = OPLM_DWORD; // always
fprintf(fout, " %s = %s;",
out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
- out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 1));
+ out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
+ NULL, 1));
break;
case OP_MOVZX:
assert_operand_cnt(2);
fprintf(fout, " %s = %s;",
out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
- out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
+ out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
break;
case OP_MOVSX:
fprintf(fout, " %s = %s%s;",
out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
buf3,
- out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
+ out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
break;
case OP_NOT:
assert_operand_cnt(2);
fprintf(fout, " %s = (s32)%s >> 31;",
out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
- out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
+ out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
strcpy(g_comment, "cdq");
break;
}
break;
+ case OP_CMPS:
+ // assumes DF=0
+ // repe ~ repeat while ZF=1
+ assert_operand_cnt(3);
+ j = lmod_bytes(po, po->operand[0].lmod);
+ strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
+ if (po->flags & OPF_REP) {
+ fprintf(fout,
+ " for (; ecx != 0; ecx--, edi += %d, esi += %d)\n",
+ j, j);
+ fprintf(fout,
+ " if ((cond_z = (%sedi == %sesi)) %s 0)\n",
+ buf1, buf1, (po->flags & OPF_REPZ) ? "==" : "!=");
+ fprintf(fout,
+ " break;");
+ snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
+ (po->flags & OPF_REPZ) ? "e" : "ne");
+ }
+ else {
+ fprintf(fout,
+ " cond_z = (%sedi = %sesi); edi += %d; esi += %d;",
+ buf1, buf1, j, j);
+ strcpy(g_comment, "cmps");
+ }
+ pfomask &= ~(1 << PFO_Z);
+ last_arith_dst = NULL;
+ delayed_flag_op = NULL;
+ break;
+
// arithmetic w/flags
case OP_ADD:
case OP_SUB:
fprintf(fout, " %s %s= %s;",
out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
op_to_c(po),
- out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
+ out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
last_arith_dst = &po->operand[0];
delayed_flag_op = NULL;
break;
out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
fprintf(fout, " %s = %s%s >> %s;", buf1,
lmod_cast_s(po, po->operand[0].lmod), buf1,
- out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
+ out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
last_arith_dst = &po->operand[0];
delayed_flag_op = NULL;
break;
fprintf(fout, " %s %s= %s + cond_c;",
out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
op_to_c(po),
- out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
+ out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
last_arith_dst = &po->operand[0];
delayed_flag_op = NULL;
break;
case OP_NEG:
out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
- out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], 0);
+ out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
fprintf(fout, " %s = -%s%s;", buf1,
lmod_cast_s(po, po->operand[0].lmod), buf2);
last_arith_dst = &po->operand[0];
assert_operand_cnt(1);
strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
fprintf(fout, " mul_tmp = %seax * %s%s;\n", buf1, buf1,
- out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], 0));
+ out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
fprintf(fout, " edx = mul_tmp >> 32;\n");
fprintf(fout, " eax = mul_tmp;");
last_arith_dst = NULL;
else
ret = scan_for_cdq_edx(i - 1);
if (ret >= 0) {
- out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
+ out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
strcpy(buf2, lmod_cast(po, po->operand[0].lmod,
po->op == OP_IDIV));
fprintf(fout, " edx = %seax %% %s%s;\n", buf2, buf2, buf1);
}
else
no_output = 1;
+ last_arith_dst = NULL;
delayed_flag_op = po;
break;
if (po->operand[0].type != OPT_LABEL)
fprintf(fout, " icall%d = (void *)%s;\n", i,
- out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0));
+ out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]));
fprintf(fout, " ");
- if (!IS(pp->ret_type, "void")) {
+ if (!IS(pp->ret_type.name, "void")) {
if (po->flags & OPF_TAIL)
fprintf(fout, "return ");
else
fprintf(fout, "eax = ");
- if (strchr(pp->ret_type, '*'))
+ if (pp->ret_type.is_ptr)
fprintf(fout, "(u32)");
}
if (arg > 0)
fprintf(fout, ", ");
- if (strchr(pp->arg[arg].type, '*'))
- fprintf(fout, "(%s)", pp->arg[arg].type);
+ cast[0] = 0;
+ if (pp->arg[arg].type.is_ptr)
+ snprintf(cast, sizeof(cast), "(%s)", pp->arg[arg].type.name);
if (pp->arg[arg].reg != NULL) {
- fprintf(fout, "%s", pp->arg[arg].reg);
+ fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
continue;
}
if (tmp_op == NULL)
ferr(po, "parsed_op missing for arg%d\n", arg);
if (tmp_op->argmask) {
- fprintf(fout, "s_a%d", arg + 1);
+ fprintf(fout, "%ss_a%d", cast, arg + 1);
}
else {
fprintf(fout, "%s",
out_src_opr(buf1, sizeof(buf1),
- tmp_op, &tmp_op->operand[0], 0));
+ tmp_op, &tmp_op->operand[0], cast, 0));
}
}
fprintf(fout, ");");
if (po->flags & OPF_TAIL) {
strcpy(g_comment, "tailcall");
- if (IS(pp->ret_type, "void"))
+ if (IS(pp->ret_type.name, "void")) {
fprintf(fout, "\n return;");
+ strcpy(g_comment, "^ tailcall");
+ }
}
delayed_flag_op = NULL;
last_arith_dst = NULL;
break;
case OP_RET:
- if (IS(g_func_pp.ret_type, "void"))
- fprintf(fout, " return;");
- else if (strchr(g_func_pp.ret_type, '*'))
+ if (IS(g_func_pp.ret_type.name, "void")) {
+ if (i != opcnt - 1 || label_pending)
+ fprintf(fout, " return;");
+ }
+ else if (g_func_pp.ret_type.is_ptr) {
fprintf(fout, " return (%s)eax;",
- g_func_pp.ret_type);
+ g_func_pp.ret_type.name);
+ }
else
fprintf(fout, " return eax;");
break;
case OP_PUSH:
if (po->argmask) {
// special case - saved func arg
- out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
+ out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
for (j = 0; j < 32; j++) {
if (po->argmask & (1 << j))
fprintf(fout, " s_a%d = %s;", j + 1, buf1);
break;
}
else if (po->flags & OPF_RSAVE) {
- out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
+ out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
fprintf(fout, " s_%s = %s;", buf1, buf1);
break;
}
case OP_POP:
if (po->flags & OPF_RSAVE) {
- out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
+ out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
fprintf(fout, " %s = s_%s;", buf1, buf1);
break;
}
break;
}
+ // some sanity checking
+ if ((po->flags & OPF_REP) && po->op != OP_STOS
+ && po->op != OP_MOVS && po->op != OP_CMPS)
+ ferr(po, "unexpected rep\n");
+ if ((po->flags & (OPF_REPZ|OPF_REPNZ)) && po->op != OP_CMPS)
+ ferr(po, "unexpected repz/repnz\n");
+
if (g_comment[0] != 0) {
fprintf(fout, " // %s", g_comment);
g_comment[0] = 0;
fprintf(fout, "\n");
if (pfomask != 0)
- ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
+ ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
// see is delayed flag stuff is still valid
if (delayed_flag_op != NULL && delayed_flag_op != po) {
if (is_opr_modified(last_arith_dst, po))
last_arith_dst = NULL;
}
+
+ label_pending = 0;
}
fprintf(fout, "}\n\n");
}
// alow asm patches in comments
- if (*p == ';' && IS_START(p, "; sctpatch: ")) {
- p = sskip(p + 12);
+ if (*p == ';' && IS_START(p, "; sctpatch:")) {
+ p = sskip(p + 11);
if (*p == 0 || *p == ';')
continue;
goto parse_words; // lame