+
+ if (po->flags & OPF_CJMP) {
+ gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
+ regmask_save, regmask_dst, regmask_dep, has_ret);
+ }
+ else {
+ i = po->bt_i - 1;
+ }
+ continue;
+ }
+
+ if (po->flags & OPF_FARG)
+ /* (just calculate register deps) */;
+ else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
+ {
+ reg = po->operand[0].reg;
+ if (reg < 0)
+ ferr(po, "reg not set for push?\n");
+
+ if (po->flags & OPF_RSAVE) {
+ regmask_save |= 1 << reg;
+ continue;
+ }
+ if (po->flags & OPF_DONE)
+ continue;
+
+ depth = 0;
+ ret = scan_for_pop(i + 1, opcnt,
+ po->operand[0].name, i + opcnt * 2, 0, &depth, 0);
+ if (ret == 1) {
+ regmask_save |= 1 << reg;
+ po->flags |= OPF_RMD;
+ scan_for_pop(i + 1, opcnt,
+ po->operand[0].name, i + opcnt * 3, 0, &depth, 1);
+ continue;
+ }
+ }
+ else if (po->flags & OPF_RMD)
+ continue;
+ else if (po->op == OP_CALL) {
+ po->regmask_dst |= 1 << xAX;
+
+ dep = hg_fp_find_dep(fp, po->operand[0].name);
+ if (dep != NULL)
+ dep->regmask_live = regmask_save | regmask_dst;
+ }
+ else if (po->op == OP_RET) {
+ if (po->operand_cnt > 0) {
+ fp->is_stdcall = 1;
+ if (fp->argc_stack >= 0
+ && fp->argc_stack != po->operand[0].val / 4)
+ ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
+ fp->argc_stack = po->operand[0].val / 4;
+ }
+ }
+
+ if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
+ if (po->op == OP_CALL) {
+ j = i;
+ ret = 1;
+ }
+ else {
+ struct parsed_opr opr = { 0, };
+ opr.type = OPT_REG;
+ opr.reg = xAX;
+ j = -1;
+ from_caller = 0;
+ ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
+ }
+
+ if (ret == -1 && from_caller) {
+ // unresolved eax - probably void func
+ *has_ret = 0;
+ }
+ else {
+ if (ops[j].op == OP_CALL) {
+ dep = hg_fp_find_dep(fp, po->operand[0].name);
+ if (dep != NULL)
+ dep->ret_dep = 1;
+ else
+ *has_ret = 1;
+ }
+ else
+ *has_ret = 1;
+ }
+ }
+
+ l = regmask_save | regmask_dst;
+ if (g_bp_frame && !(po->flags & OPF_EBP_S))
+ l |= 1 << xBP;
+
+ l = po->regmask_src & ~l;
+#if 0
+ if (l)
+ fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
+ l, regmask_dst, regmask_save, po->flags);
+#endif
+ *regmask_dep |= l;
+ regmask_dst |= po->regmask_dst;
+
+ if (po->flags & OPF_TAIL)
+ return;
+ }
+}
+
+static void gen_hdr(const char *funcn, int opcnt)
+{
+ int save_arg_vars[MAX_ARG_GRP] = { 0, };
+ unsigned char cbits[MAX_OPS / 8];
+ const struct parsed_proto *pp_c;
+ struct parsed_proto *pp;
+ struct func_prototype *fp;
+ struct parsed_data *pd;
+ struct parsed_op *po;
+ const char *tmpname;
+ int regmask_dummy = 0;
+ int regmask_dep;
+ int max_bp_offset = 0;
+ int has_ret;
+ int i, j, l, ret;
+
+ if ((hg_fp_cnt & 0xff) == 0) {
+ hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
+ my_assert_not(hg_fp, NULL);
+ memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
+ }
+
+ fp = &hg_fp[hg_fp_cnt];
+ snprintf(fp->name, sizeof(fp->name), "%s", funcn);
+ fp->id = hg_fp_cnt;
+ fp->argc_stack = -1;
+ hg_fp_cnt++;
+
+ // perhaps already in seed header?
+ fp->pp = proto_parse(g_fhdr, funcn, 1);
+ if (fp->pp != NULL) {
+ fp->argc_stack = fp->pp->argc_stack;
+ fp->is_stdcall = fp->pp->is_stdcall;
+ fp->regmask_dep = get_pp_arg_regmask(fp->pp);
+ fp->has_ret = !IS(fp->pp->ret_type.name, "void");
+ return;
+ }
+
+ g_bp_frame = g_sp_frame = g_stack_fsz = 0;
+ g_stack_frame_used = 0;
+
+ // pass1:
+ // - handle ebp/esp frame, remove ops related to it
+ scan_prologue_epilogue(opcnt);
+
+ // pass2:
+ // - collect calls
+ // - resolve all branches
+ for (i = 0; i < opcnt; i++)
+ {
+ po = &ops[i];
+ po->bt_i = -1;
+ po->btj = NULL;
+
+ if (po->flags & (OPF_RMD|OPF_DONE))
+ continue;
+
+ if (po->op == OP_CALL) {
+ tmpname = opr_name(po, 0);
+ pp = NULL;
+ if (po->operand[0].type == OPT_LABEL) {
+ hg_fp_add_dep(fp, tmpname);
+
+ // perhaps a call to already known func?
+ pp_c = proto_parse(g_fhdr, tmpname, 1);
+ if (pp_c != NULL)
+ pp = proto_clone(pp_c);
+ }
+ else if (po->datap != NULL) {
+ pp = calloc(1, sizeof(*pp));
+ my_assert_not(pp, NULL);
+
+ ret = parse_protostr(po->datap, pp);
+ if (ret < 0)
+ ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
+ free(po->datap);
+ po->datap = NULL;
+ }
+ if (pp != NULL && pp->is_noreturn)
+ po->flags |= OPF_TAIL;