OPF_EBP_S = (1 << 13), /* ebp used as scratch here, not BP */
OPF_DF = (1 << 14), /* DF flag set */
OPF_ATAIL = (1 << 15), /* tail call with reused arg frame */
- OPF_32BIT = (1 << 16), /* 32bit division */
+ OPF_32BIT = (1 << 16), /* enough to do 32bit for this op */
OPF_LOCK = (1 << 17), /* op has lock prefix */
OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
OPF_DONE = (1 << 19), /* already fully handled by analysis */
static int g_stack_clear_start; // in dwords
static int g_stack_clear_len;
static int g_regmask_init;
+static int g_regmask_rm;
static int g_skip_func;
static int g_allow_regfunc;
static int g_allow_user_icall;
// fallthrough
case OP_MUL:
// singleop mul
- op->regmask_src |= op->regmask_dst;
- op->regmask_dst = (1 << xDX) | (1 << xAX);
if (op->operand[0].lmod == OPLM_UNSPEC)
op->operand[0].lmod = OPLM_DWORD;
+ op->regmask_src = mxAX | op->regmask_dst;
+ op->regmask_dst = mxAX;
+ if (op->operand[0].lmod != OPLM_BYTE)
+ op->regmask_dst |= mxDX;
break;
case OP_DIV:
case OP_IDIV:
// we could set up operands for edx:eax, but there is no real need to
// (see is_opr_modified())
- op->regmask_src |= op->regmask_dst;
- op->regmask_dst = (1 << xDX) | (1 << xAX);
if (op->operand[0].lmod == OPLM_UNSPEC)
op->operand[0].lmod = OPLM_DWORD;
+ op->regmask_src = mxAX | op->regmask_dst;
+ op->regmask_dst = mxAX;
+ if (op->operand[0].lmod != OPLM_BYTE) {
+ op->regmask_src |= mxDX;
+ op->regmask_dst |= mxDX;
+ }
break;
case OP_SHL:
break;
case OP_CALL:
+ // needed because of OPF_DATA
+ op->regmask_src = op->regmask_dst;
// trashed regs must be explicitly detected later
op->regmask_dst = 0;
break;
}
// declare normal registers
- regmask_now = regmask & ~regmask_arg;
+ regmask_now = regmask & ~regmask_arg & ~g_regmask_rm;
regmask_now &= ~(1 << xSP);
if (regmask_now & 0x00ff) {
for (reg = 0; reg < 8; reg++) {
int has_ret:3; // -1, 0, 1: unresolved, no, yes
unsigned int dep_resolved:1;
unsigned int is_stdcall:1;
+ unsigned int eax_pass:1; // returns without touching eax
struct func_proto_dep *dep_func;
int dep_func_cnt;
const struct parsed_proto *pp; // seed pp, if any
if (ret != 1 && from_caller) {
// unresolved eax - probably void func
*has_ret = 0;
+ fp->eax_pass = 1;
}
else {
if (j >= 0 && ops[j].op == OP_CALL) {
}
// pass4:
- // - remove dead labels
// - handle push <const>/pop pairs
for (i = 0; i < opcnt; i++)
{
- if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
- free(g_labels[i]);
- g_labels[i] = NULL;
- }
-
po = &ops[i];
if (po->flags & (OPF_RMD|OPF_DONE))
continue;
argc_normal++;
regmask_dep = 0;
}
- else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
- && (regmask_dep & ~(mxCX | mxDX)) == 0)
+ else if ((regmask_dep == (mxCX | mxDX)
+ && (fp->is_stdcall || fp->argc_stack == 0))
+ || (regmask_dep == mxCX && fp->argc_stack == 0))
{
fprintf(fout, " __fastcall ");
if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
// adjust functions referenced from data segment
do_func_refs_from_data();
+ // final adjustments
+ for (i = 0; i < hg_fp_cnt; i++) {
+ if (hg_fp[i].eax_pass && (hg_fp[i].regmask_dep & mxAX))
+ hg_fp[i].has_ret = 1;
+ }
+
// note: messes up .proto ptr, don't use
//qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
int pi = 0;
int i, j;
int ret, len;
- char *p;
+ char *p, *p2;
int wordc;
for (arg = 1; arg < argc; arg++) {
static const char *attrs[] = {
"clear_sf",
"clear_regmask",
+ "rm_regmask",
};
// parse manual attribute-list comment
else if (i == 1)
// clear_regmask=<mask>
ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
+ else if (i == 2)
+ // rm_regmask=<mask>
+ ret = sscanf(p, "=%x%n", &g_regmask_rm, &j) + 1;
if (ret < 2) {
anote("unparsed attr value: %s\n", p);
break;
// allow asm patches in comments
if (*p == ';') {
+ // skip IDA's forced non-removable comment
+ if (!IS_START(p, "; sct") && (p2 = strchr(p + 1, ';')))
+ p = p2;
+ }
+ if (*p == ';' && IS_START(p, "; sct")) {
if (IS_START(p, "; sctpatch:")) {
p = sskip(p + 11);
if (*p == 0 || *p == ';')
g_stack_clear_start = 0;
g_stack_clear_len = 0;
g_regmask_init = 0;
+ g_regmask_rm = 0;
skip_warned = 0;
g_skip_func = 0;
g_func[0] = 0;