{
static const char *dword_types[] = {
"int", "_DWORD", "UINT_PTR", "DWORD",
- "WPARAM", "LPARAM", "UINT",
- "HIMC",
+ "WPARAM", "LPARAM", "UINT", "__int32",
+ "LONG", "HIMC",
};
static const char *word_types[] = {
"uint16_t", "int16_t", "_WORD",
static const char *byte_types[] = {
"uint8_t", "int8_t", "char",
"unsigned __int8", "__int8", "BYTE", "_BYTE",
- "_UNKNOWN",
+ "CHAR", "_UNKNOWN",
};
const char *n;
int i;
ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
i + 1, offset, g_func_pp->arg[i].type.name);
}
- if (popr->is_ptr && popr->lmod != OPLM_DWORD)
- ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
+ // can't check this because msvc likes to reuse
+ // arg space for scratch..
+ //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
+ // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
}
else
{
}
// scan for positive, constant esp adjust
-static int scan_for_esp_adjust(int i, int opcnt, int *adj)
+static int scan_for_esp_adjust(int i, int opcnt, int *adj,
+ int *multipath)
{
const struct parsed_proto *pp;
struct parsed_op *po;
int first_pop = -1;
- *adj = 0;
+
+ *adj = *multipath = 0;
for (; i < opcnt; i++) {
po = &ops[i];
if (g_labels[i][0] != 0)
- break;
+ *multipath = 1;
if (po->op == OP_ADD && po->operand[0].reg == xSP) {
if (po->operand[1].type != OPT_CONST)
*adj += lmod_bytes(po, po->operand[0].lmod);
}
else if (po->flags & (OPF_JMP|OPF_TAIL)) {
+ if (po->op == OP_JMP && po->btj == NULL) {
+ i = po->bt_i - 1;
+ continue;
+ }
if (po->op != OP_CALL)
break;
if (po->operand[0].type != OPT_LABEL)
pp = calloc(1, sizeof(*pp));
my_assert_not(pp, NULL);
pp->is_fptr = 1;
- ret = scan_for_esp_adjust(i + 1, opcnt, &j);
+ ret = scan_for_esp_adjust(i + 1, opcnt, &j, &l);
if (ret < 0) {
if (!g_allow_regfunc)
ferr(po, "non-__cdecl indirect call unhandled yet\n");
// look for and make use of esp adjust
ret = -1;
if (!pp->is_stdcall && pp->argc_stack > 0)
- ret = scan_for_esp_adjust(i + 1, opcnt, &j);
+ ret = scan_for_esp_adjust(i + 1, opcnt, &j, &l);
if (ret >= 0) {
if (pp->is_vararg) {
if (j / 4 < pp->argc_stack)
ret++;
}
}
- else {
+ else if (!l) {
// a bit of a hack, but deals with use of
// single adj for multiple calls
ops[ret].operand[1].val -= j;
if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
pfomask = 1 << pfo;
}
- else if (tmp_op->op == OP_SCAS) {
+ else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
pfomask = 1 << pfo;
}
- else if (tmp_op->op == OP_CMPS) {
- pfomask = 1 << PFO_Z;
- }
else {
// see if we'll be able to handle based on op result
if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
pfomask = po->pfomask;
+ if (po->flags & (OPF_REPZ|OPF_REPNZ)) {
+ // we need initial flags for ecx=0 case..
+ if (i > 0 && ops[i - 1].op == OP_XOR
+ && IS(ops[i - 1].operand[0].name,
+ ops[i - 1].operand[1].name))
+ {
+ fprintf(fout, " cond_z = ");
+ if (pfomask & (1 << PFO_C))
+ fprintf(fout, "cond_c = ");
+ fprintf(fout, "0;\n");
+ }
+ else if (last_arith_dst != NULL) {
+ out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
+ out_test_for_cc(buf1, sizeof(buf1), po, PFO_Z, 0,
+ last_arith_dst->lmod, buf3);
+ fprintf(fout, " cond_z = %s;\n", buf1);
+ }
+ else
+ ferr(po, "missing initial ZF\n");
+ }
+
switch (po->op)
{
case OP_MOV:
l = (po->flags & OPF_DF) ? '-' : '+';
if (po->flags & OPF_REP) {
fprintf(fout,
- " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
+ " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d) {\n",
l, j, l, j);
+ if (pfomask & (1 << PFO_C)) {
+ // ugh..
+ fprintf(fout,
+ " cond_c = %sedi < %sesi;\n", buf1, buf1);
+ pfomask &= ~(1 << PFO_C);
+ }
fprintf(fout,
" if ((cond_z = (%sedi == %sesi)) %s 0)\n",
buf1, buf1, (po->flags & OPF_REPZ) ? "==" : "!=");
fprintf(fout,
- " break;");
+ " break;\n"
+ " }");
snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
(po->flags & OPF_REPZ) ? "e" : "ne");
}