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 */
+ OPF_PPUSH = (1 << 20), /* part of complex push-pop graph */
};
enum op_op {
// x87
// mmx
OP_EMMS,
- // mmx
+ // undefined
OP_UD2,
};
};
// datap:
-// OP_CALL - parser proto hint (str)
+// OP_CALL - parser proto hint (str)
// (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
-// OP_POP - points to OP_PUSH in push/pop pair
+// OP_PUSH - points to OP_POP in complex push/pop graph
+// OP_POP - points to OP_PUSH in simple push/pop pair
struct parsed_equ {
char name[64];
static int g_stack_frame_used;
static int g_stack_fsz;
static int g_ida_func_attr;
+static int g_skip_func;
static int g_allow_regfunc;
static int g_quiet_pp;
static int g_header_mode;
}
if (i == ARRAY_SIZE(op_table)) {
- anote("unhandled op: '%s'\n", words[0]);
+ if (!g_skip_func)
+ aerr("unhandled op: '%s'\n", words[0]);
i--; // OP_UD2
}
w++;
return found ? 0 : -1;
}
-static void scan_for_pop_const(int i, int opcnt)
+static void scan_for_pop_const(int i, int opcnt, int *regmask_pp)
{
+ struct parsed_op *po;
+ int is_multipath = 0;
int j;
for (j = i + 1; j < opcnt; j++) {
- if ((ops[j].flags & (OPF_JMP|OPF_TAIL|OPF_RSAVE))
- || ops[j].op == OP_PUSH || g_labels[i] != NULL)
+ po = &ops[j];
+
+ if (po->op == OP_JMP && po->btj == NULL) {
+ ferr_assert(po, po->bt_i >= 0);
+ j = po->bt_i - 1;
+ continue;
+ }
+
+ if ((po->flags & (OPF_JMP|OPF_TAIL|OPF_RSAVE))
+ || po->op == OP_PUSH)
{
break;
}
- if (ops[j].op == OP_POP && !(ops[j].flags & (OPF_RMD|OPF_DONE)))
+ if (g_labels[j] != NULL)
+ is_multipath = 1;
+
+ if (po->op == OP_POP && !(po->flags & OPF_RMD))
{
- ops[i].flags |= OPF_RMD | OPF_DONE;
- ops[j].flags |= OPF_DONE;
- ops[j].datap = &ops[i];
+ is_multipath |= !!(po->flags & OPF_PPUSH);
+ if (is_multipath) {
+ ops[i].flags |= OPF_PPUSH | OPF_DONE;
+ ops[i].datap = po;
+ po->flags |= OPF_PPUSH | OPF_DONE;
+ *regmask_pp |= 1 << po->operand[0].reg;
+ }
+ else {
+ ops[i].flags |= OPF_RMD | OPF_DONE;
+ po->flags |= OPF_DONE;
+ po->datap = &ops[i];
+ }
break;
}
}
int need_tmp64 = 0;
int had_decl = 0;
int label_pending = 0;
- int regmask_save = 0;
- int regmask_arg = 0;
- int regmask_now = 0;
- int regmask_init = 0;
- int regmask = 0;
+ int regmask_save = 0; // regs saved/restored in this func
+ int regmask_arg = 0; // regs carrying function args (fastcall, etc)
+ int regmask_now; // temp
+ int regmask_init = 0; // regs that need zero initialization
+ int regmask_pp = 0; // regs used in complex push-pop graph
+ int regmask = 0; // used regs
int pfomask = 0;
int found = 0;
int depth = 0;
}
else if (po->op == OP_PUSH && !(po->flags & OPF_FARG)
&& !(po->flags & OPF_RSAVE) && po->operand[0].type == OPT_CONST)
- scan_for_pop_const(i, opcnt);
+ scan_for_pop_const(i, opcnt, ®mask_pp);
}
// pass5:
}
}
+ // declare normal registers
regmask_now = regmask & ~regmask_arg;
regmask_now &= ~(1 << xSP);
if (regmask_now & 0x00ff) {
}
}
+ // declare push-pop temporaries
+ if (regmask_pp) {
+ for (reg = 0; reg < 8; reg++) {
+ if (regmask_pp & (1 << reg)) {
+ fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
+ had_decl = 1;
+ }
+ }
+ }
+
if (cond_vars) {
for (i = 0; i < 8; i++) {
if (cond_vars & (1 << i)) {
fprintf(fout, " s_%s = %s;", buf1, buf1);
break;
}
+ else if (po->flags & OPF_PPUSH) {
+ tmp_op = po->datap;
+ ferr_assert(po, tmp_op != NULL);
+ out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
+ fprintf(fout, " pp_%s = %s;", buf2, buf1);
+ break;
+ }
else if (g_func_pp->is_userstack) {
fprintf(fout, " *(--esp) = %s;", buf1);
break;
break;
case OP_POP:
+ out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
if (po->flags & OPF_RSAVE) {
- out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
fprintf(fout, " %s = s_%s;", buf1, buf1);
break;
}
+ else if (po->flags & OPF_PPUSH) {
+ // push/pop graph
+ ferr_assert(po, po->datap == NULL);
+ fprintf(fout, " %s = pp_%s;", buf1, buf1);
+ break;
+ }
else if (po->datap != NULL) {
// push/pop pair
tmp_op = po->datap;
- out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
fprintf(fout, " %s = %s;", buf1,
out_src_opr(buf2, sizeof(buf2),
tmp_op, &tmp_op->operand[0],
break;
}
else if (g_func_pp->is_userstack) {
- fprintf(fout, " %s = *esp++;",
- out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
+ fprintf(fout, " %s = *esp++;", buf1);
break;
}
else
continue;
if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
- scan_for_pop_const(i, opcnt);
+ scan_for_pop_const(i, opcnt, ®mask_dummy);
}
// pass4:
continue;
if (fp->pp != NULL) {
- // prefer fp for common style,
- // only use output_pp if args are complex
- for (j = 0; j < fp->pp->argc; j++) {
- if (fp->pp->arg[j].fptr != NULL)
- break;
- }
- if (j != fp->pp->argc) {
- output_pp(fout, fp->pp, OPP_ALIGN);
- fprintf(fout, ";\n");
- continue;
- }
+ // part of seed, output later
+ continue;
}
regmask_dep = fp->regmask_dep;
for (i = 0; i < hg_var_cnt; i++) {
var = &hg_vars[i];
- if (var->pp != NULL && var->pp->is_fptr) {
- fprintf(fout, "extern ");
- output_pp(fout, var->pp, 0);
- fprintf(fout, ";");
- }
+ if (var->pp != NULL)
+ // part of seed
+ continue;
else if (var->is_c_str)
fprintf(fout, "extern %-8s %s[];", "char", var->name);
else
// output function prototypes
output_hdr_fp(fout, hg_fp, hg_fp_cnt);
- // include passthrough
- fprintf(fout, "\n// for translate\n");
+ // seed passthrough
+ fprintf(fout, "\n// - seed -\n");
rewind(g_fhdr);
- while (fgets(line, sizeof(line), g_fhdr)) {
- if (IS_START(line, "//#"))
- fwrite(line, 1, strlen(line), fout);
- }
+ while (fgets(line, sizeof(line), g_fhdr))
+ fwrite(line, 1, strlen(line), fout);
}
// read a line, truncating it if it doesn't fit
do_pending_endp:
// do delayed endp processing to collect switch jumptables
if (pending_endp) {
- if (in_func && !skip_func && !end && wordc >= 2
+ if (in_func && !g_skip_func && !end && wordc >= 2
&& ((words[0][0] == 'd' && words[0][2] == 0)
|| (words[1][0] == 'd' && words[1][2] == 0)))
{
continue;
}
- if (in_func && !skip_func) {
+ if (in_func && !g_skip_func) {
if (g_header_mode)
gen_hdr(g_func, pi);
else
in_func = 0;
g_ida_func_attr = 0;
skip_warned = 0;
- skip_func = 0;
+ g_skip_func = 0;
g_func[0] = 0;
func_chunks_used = 0;
func_chunk_i = -1;
words[0], g_func);
p = words[0];
if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
- skip_func = 1;
+ g_skip_func = 1;
strcpy(g_func, words[0]);
set_label(0, words[0]);
in_func = 1;
&& ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
{
// import jump
- skip_func = 1;
+ g_skip_func = 1;
}
- if (!skip_func && func_chunks_used) {
+ if (!g_skip_func && func_chunks_used) {
// start processing chunks
struct chunk_item *ci, key = { g_func, 0 };
continue;
}
- if (!in_func || skip_func) {
- if (!skip_warned && !skip_func && g_labels[pi] != NULL) {
+ if (!in_func || g_skip_func) {
+ if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
if (verbose)
anote("skipping from '%s'\n", g_labels[pi]);
skip_warned = 1;