return -1;
}
+static void patch_esp_adjust(struct parsed_op *po, int adj)
+{
+ ferr_assert(po, po->op == OP_ADD);
+ ferr_assert(po, IS(opr_name(po, 0), "esp"));
+ ferr_assert(po, po->operand[1].type == OPT_CONST);
+
+ // this is a bit of a hack, but deals with use of
+ // single adj for multiple calls
+ po->operand[1].val -= adj;
+ po->flags |= OPF_RMD;
+ if (po->operand[1].val == 0)
+ po->flags |= OPF_DONE;
+ ferr_assert(po, (int)po->operand[1].val >= 0);
+}
+
// scan for positive, constant esp adjust
+// multipath case is preliminary
static int scan_for_esp_adjust(int i, int opcnt,
- int adj_expect, int *adj, int *multipath)
+ int adj_expect, int *adj, int *is_multipath, int do_update)
{
struct parsed_op *po;
int first_pop = -1;
- *adj = *multipath = 0;
+ *adj = *is_multipath = 0;
for (; i < opcnt && *adj < adj_expect; i++) {
if (g_labels[i] != NULL)
- *multipath = 1;
+ *is_multipath = 1;
po = &ops[i];
if (po->flags & OPF_DONE)
*adj += po->operand[1].val;
if (*adj & 3)
ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
+ if (do_update) {
+ if (!*is_multipath)
+ patch_esp_adjust(po, adj_expect);
+ else
+ po->flags |= OPF_RMD;
+ }
return i;
}
else if (po->op == OP_PUSH) {
if (first_pop == -1 && *adj >= 0)
first_pop = i;
}
+ if (do_update && *adj >= 0) {
+ po->flags |= OPF_RMD;
+ if (!*is_multipath)
+ po->flags |= OPF_DONE;
+ }
+
*adj += lmod_bytes(po, po->operand[0].lmod);
}
else if (po->flags & (OPF_JMP|OPF_TAIL)) {
*adj_i = ret = -1;
if (!pp->is_stdcall && pp->argc_stack > 0)
ret = scan_for_esp_adjust(i + 1, opcnt,
- pp->argc_stack * 4, &adj, &multipath);
+ pp->argc_stack * 4, &adj, &multipath, 0);
if (ret >= 0) {
if (pp->argc_stack > adj / 4)
return NULL;
return pp;
}
-static void patch_esp_adjust(struct parsed_op *po, int adj)
-{
- ferr_assert(po, po->op == OP_ADD);
- ferr_assert(po, IS(opr_name(po, 0), "esp"));
- ferr_assert(po, po->operand[1].type == OPT_CONST);
-
- // this is a bit of a hack, but deals with use of
- // single adj for multiple calls
- po->operand[1].val -= adj;
- po->flags |= OPF_RMD;
- if (po->operand[1].val == 0)
- po->flags |= OPF_DONE;
- ferr_assert(po, (int)po->operand[1].val >= 0);
-}
-
static struct parsed_proto *process_call(int i, int opcnt)
{
struct parsed_op *po = &ops[i];
my_assert_not(pp, NULL);
pp->is_fptr = 1;
- ret = scan_for_esp_adjust(i + 1, opcnt, 32*4, &adj, &multipath);
+ ret = scan_for_esp_adjust(i + 1, opcnt,
+ 32*4, &adj, &multipath, 0);
if (ret < 0 || adj < 0) {
if (!g_allow_regfunc)
ferr(po, "non-__cdecl indirect call unhandled yet\n");
ret = -1;
if (!pp->is_stdcall && pp->argc_stack > 0)
ret = scan_for_esp_adjust(i + 1, opcnt,
- pp->argc_stack * 4, &adj, &multipath);
+ pp->argc_stack * 4, &adj, &multipath, 0);
if (ret >= 0) {
if (pp->is_vararg) {
if (adj / 4 < pp->argc_stack) {
tmpname, pp->argc_stack * 4, adj);
}
- ops[ret].flags |= OPF_RMD;
- if (ops[ret].op == OP_POP) {
- if (adj > 4) {
- // deal with multi-pop stack adjust
- adj = pp->argc_stack;
- while (ops[ret].op == OP_POP && adj > 0 && ret < opcnt) {
- ops[ret].flags |= OPF_RMD | OPF_DONE;
- adj--;
- ret++;
- }
- }
- }
- else if (!multipath)
- patch_esp_adjust(&ops[ret], pp->argc_stack * 4);
+ scan_for_esp_adjust(i + 1, opcnt,
+ pp->argc_stack * 4, &adj, &multipath, 1);
}
else if (pp->is_vararg)
ferr(po, "missing esp_adjust for vararg func '%s'\n",
// pass4:
// - process calls
+ // - handle push <const>/pop pairs
for (i = 0; i < opcnt; i++)
{
po = &ops[i];
if (strstr(pp->ret_type.name, "int64"))
need_tmp64 = 1;
}
+ 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);
}
// pass5:
continue;
}
}
- else if (po->operand[0].type == OPT_CONST) {
- scan_for_pop_const(i, opcnt);
- }
}
if (po->op == OP_STD) {