X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=tools%2Ftranslate.c;h=ef38d730bb757ef5477ea397a2135fa6abfc6fe3;hb=a652aa9f7b2c4ddd5fac0c960e9de8f4e821827b;hp=81d2b4d5a84014f1be1652a12052856a610136d6;hpb=de50b98baf577c2ab9b9f680ea102c1dad14eb7c;p=ia32rtools.git diff --git a/tools/translate.c b/tools/translate.c index 81d2b4d..ef38d73 100644 --- a/tools/translate.c +++ b/tools/translate.c @@ -105,6 +105,7 @@ enum opr_type { OPT_CONST, }; +// must be sorted (larger len must be further in enum) enum opr_lenmod { OPLM_UNSPEC, OPLM_BYTE, @@ -119,6 +120,8 @@ struct parsed_opr { enum opr_lenmod lmod; unsigned int is_ptr:1; // pointer in C unsigned int is_array:1; // array in C + unsigned int size_mismatch:1; // type override differs from C + unsigned int size_lt:1; // type override is larger than C int reg; unsigned int val; char name[256]; @@ -141,7 +144,7 @@ struct parsed_op { // datap: // OP_CALL - ptr to parsed_proto -// (OPF_CC) - point to corresponding (OPF_FLAGS) +// (OPF_CC) - point to one of (OPF_FLAGS) that affects cc op struct parsed_equ { char name[64]; @@ -185,7 +188,7 @@ static struct parsed_equ *g_eqs; static int g_eqcnt; static char g_labels[MAX_OPS][32]; static struct label_ref g_label_refs[MAX_OPS]; -static struct parsed_proto g_func_pp; +static const struct parsed_proto *g_func_pp; static struct parsed_data *g_func_pd; static int g_func_pd_cnt; static char g_func[256]; @@ -466,12 +469,15 @@ static int guess_lmod_from_c_type(enum opr_lenmod *lmod, { static const char *dword_types[] = { "int", "_DWORD", "DWORD", "HANDLE", "HWND", "HMODULE", + "WPARAM", "UINT", }; static const char *word_types[] = { - "__int16", "unsigned __int16", + "uint16_t", "int16_t", + "unsigned __int16", "__int16", }; static const char *byte_types[] = { - "char", "__int8", "unsigned __int8", "BYTE", + "uint8_t", "int8_t", "char", + "unsigned __int8", "__int8", "BYTE", }; const char *n; int i; @@ -536,7 +542,7 @@ static int parse_operand(struct parsed_opr *opr, int *regmask, int *regmask_indirect, char words[16][256], int wordc, int w, unsigned int op_flags) { - struct parsed_proto pp; + const struct parsed_proto *pp; enum opr_lenmod tmplmod; unsigned long number; int ret, len; @@ -667,20 +673,28 @@ static int parse_operand(struct parsed_opr *opr, // most likely var in data segment opr->type = OPT_LABEL; - ret = proto_parse(g_fhdr, opr->name, &pp); - if (ret == 0) { - if (pp.is_fptr) { + pp = proto_parse(g_fhdr, opr->name); + if (pp != NULL) { + if (pp->is_fptr) { opr->lmod = OPLM_DWORD; opr->is_ptr = 1; } - else if (opr->lmod == OPLM_UNSPEC) { - if (!guess_lmod_from_c_type(&opr->lmod, &pp.type)) - anote("unhandled C type '%s' for '%s'\n", pp.type.name, opr->name); + else { + if (!guess_lmod_from_c_type(&tmplmod, &pp->type)) + anote("unhandled C type '%s' for '%s'\n", + pp->type.name, opr->name); + + if (opr->lmod == OPLM_UNSPEC) + opr->lmod = tmplmod; + else if (opr->lmod != tmplmod) { + opr->size_mismatch = 1; + if (tmplmod < opr->lmod) + opr->size_lt = 1; + } + opr->is_ptr = pp->type.is_ptr; } - opr->is_ptr = pp.type.is_ptr; - opr->is_array = pp.type.is_array; + opr->is_array = pp->type.is_array; } - proto_release(&pp); if (opr->lmod == OPLM_UNSPEC) guess_lmod_from_name(opr); @@ -1201,9 +1215,11 @@ static void stack_frame_access(struct parsed_op *po, if (offset > stack_ra) { arg_i = (offset - stack_ra - 4) / 4; - if (arg_i < 0 || arg_i >= g_func_pp.argc_stack) + if (arg_i < 0 || arg_i >= g_func_pp->argc_stack) { - if (g_func_pp.is_vararg && arg_i == g_func_pp.argc_stack && is_lea) { + if (g_func_pp->is_vararg + && arg_i == g_func_pp->argc_stack && is_lea) + { // should be va_list if (cast[0] == 0) cast = "(u32)"; @@ -1216,17 +1232,17 @@ static void stack_frame_access(struct parsed_op *po, if (ofs_reg[0] != 0) ferr(po, "offset reg on arg access?\n"); - for (i = arg_s = 0; i < g_func_pp.argc; i++) { - if (g_func_pp.arg[i].reg != NULL) + for (i = arg_s = 0; i < g_func_pp->argc; i++) { + if (g_func_pp->arg[i].reg != NULL) continue; if (arg_s == arg_i) break; arg_s++; } - if (i == g_func_pp.argc) + if (i == g_func_pp->argc) ferr(po, "arg %d not in prototype?\n", arg_i); - popr->is_ptr = g_func_pp.arg[i].type.is_ptr; + popr->is_ptr = g_func_pp->arg[i].type.is_ptr; switch (popr->lmod) { @@ -1257,11 +1273,13 @@ static void stack_frame_access(struct parsed_op *po, else if (is_src) prefix = "(u32)"; if (offset & 3) { - if (is_lea) - ferr(po, "unaligned lea?\n"); snprintf(g_comment, sizeof(g_comment), "%s unaligned", bp_arg); - snprintf(buf, buf_size, "%s(a%d >> %d)", - prefix, i + 1, (offset & 3) * 8); + if (is_lea) + snprintf(buf, buf_size, "(u32)&a%d + %d", + i + 1, offset & 3); + else + snprintf(buf, buf_size, "%s(a%d >> %d)", + prefix, i + 1, (offset & 3) * 8); } else { snprintf(buf, buf_size, "%s%sa%d", @@ -1274,10 +1292,10 @@ static void stack_frame_access(struct parsed_op *po, } // common problem - guess_lmod_from_c_type(&tmp_lmod, &g_func_pp.arg[i].type); + guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type); if ((offset & 3) && tmp_lmod != OPLM_DWORD) ferr(po, "bp_arg arg/w offset %d and type '%s'\n", - offset, g_func_pp.arg[i].type.name); + offset, g_func_pp->arg[i].type.name); } else { @@ -1406,8 +1424,14 @@ static char *out_src_opr(char *buf, size_t buf_size, check_label_read_ref(po, popr->name); if (cast[0] == 0 && popr->is_ptr) cast = "(u32)"; + if (is_lea) snprintf(buf, buf_size, "(u32)&%s", popr->name); + else if (popr->size_lt) + snprintf(buf, buf_size, "%s%s%s%s", cast, + lmod_cast_u_ptr(po, popr->lmod), + popr->is_array ? "" : "&", + popr->name); else snprintf(buf, buf_size, "%s%s%s", cast, popr->name, popr->is_array ? "[0]" : ""); @@ -1476,8 +1500,13 @@ static char *out_dst_opr(char *buf, size_t buf_size, return out_src_opr(buf, buf_size, po, popr, NULL, 0); case OPT_LABEL: - snprintf(buf, buf_size, "%s%s", popr->name, - popr->is_array ? "[0]" : ""); + if (popr->size_mismatch) + snprintf(buf, buf_size, "%s%s%s", + lmod_cast_u_ptr(po, popr->lmod), + popr->is_array ? "" : "&", popr->name); + else + snprintf(buf, buf_size, "%s%s", popr->name, + popr->is_array ? "[0]" : ""); break; default: @@ -1861,9 +1890,10 @@ static int is_any_opr_modified(const struct parsed_op *po_test, return 1; // in reality, it can wreck any register, but in decompiled C - // version it can only overwrite eax + // version it can only overwrite eax or edx:eax if (po->op == OP_CALL - && ((po_test->regmask_src | po_test->regmask_dst) & (1 << xAX))) + && ((po_test->regmask_src | po_test->regmask_dst) + & ((1 << xAX)|(1 << xDX)))) return 1; for (i = 0; i < po_test->operand_cnt; i++) @@ -1876,6 +1906,9 @@ static int is_any_opr_modified(const struct parsed_op *po_test, // scan for any po_test operand modification in range given static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt) { + if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST) + return -1; + for (; i < opcnt; i++) { if (is_any_opr_modified(po_test, &ops[i])) return i; @@ -1896,24 +1929,32 @@ static int scan_for_mod_opr0(struct parsed_op *po_test, return -1; } -static int scan_for_flag_set(int i, int *branched) +static int scan_for_flag_set(int i, int *branched, int *setters, + int *setter_cnt) { - *branched = 0; + int ret; while (i >= 0) { if (g_labels[i][0] != 0) { + *branched = 1; if (g_label_refs[i].next != NULL) return -1; if (i > 0 && LAST_OP(i - 1)) { i = g_label_refs[i].i; - *branched = 1; continue; } + ret = scan_for_flag_set(g_label_refs[i].i, branched, + setters, setter_cnt); + if (ret < 0) + return ret; } i--; - if (ops[i].flags & OPF_FLAGS) - return i; + if (ops[i].flags & OPF_FLAGS) { + setters[*setter_cnt] = i; + (*setter_cnt)++; + return 0; + } if ((ops[i].flags & OPF_JMP) && !(ops[i].flags & OPF_CC)) return -1; @@ -1994,10 +2035,11 @@ static int scan_for_esp_adjust(int i, int opcnt, int *adj) static int collect_call_args(struct parsed_op *po, int i, struct parsed_proto *pp, int *save_arg_vars, int arg, - int need_op_saving, int branched) + int need_op_saving, int may_reuse) { struct parsed_proto *pp_tmp; struct label_ref *lr; + int need_to_save_current; int ret = 0; int j; @@ -2011,14 +2053,18 @@ static int collect_call_args(struct parsed_op *po, int i, for (j = i; j >= 0 && arg < pp->argc; ) { if (g_labels[j][0] != 0) { - branched = 1; lr = &g_label_refs[j]; if (lr->next != NULL) need_op_saving = 1; - for (; lr->next; lr = lr->next) + for (; lr->next; lr = lr->next) { + if ((ops[lr->i].flags & (OPF_JMP|OPF_CC)) != OPF_JMP) + may_reuse = 1; ret |= collect_call_args(po, lr->i, pp, save_arg_vars, - arg, need_op_saving, branched); + arg, need_op_saving, may_reuse); + } + if ((ops[lr->i].flags & (OPF_JMP|OPF_CC)) != OPF_JMP) + may_reuse = 1; if (j > 0 && LAST_OP(j - 1)) { // follow last branch in reverse j = lr->i; @@ -2026,7 +2072,7 @@ static int collect_call_args(struct parsed_op *po, int i, } need_op_saving = 1; ret |= collect_call_args(po, lr->i, pp, save_arg_vars, - arg, need_op_saving, branched); + arg, need_op_saving, may_reuse); } j--; @@ -2035,7 +2081,7 @@ static int collect_call_args(struct parsed_op *po, int i, pp_tmp = ops[j].datap; if (pp_tmp == NULL) ferr(po, "arg collect hit unparsed call\n"); - if (branched && pp_tmp->argc_stack > 0) + if (may_reuse && pp_tmp->argc_stack > 0) ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n", arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack); } @@ -2046,21 +2092,19 @@ static int collect_call_args(struct parsed_op *po, int i, else if (ops[j].op == OP_POP) { ferr(po, "arg collect %d/%d hit pop\n", arg, pp->argc); } - else if (LAST_OP(j)) { - break; - } else if ((ops[j].flags & (OPF_JMP|OPF_CC)) == (OPF_JMP|OPF_CC)) { - branched = 1; + may_reuse = 1; } else if (ops[j].op == OP_PUSH && !(ops[j].flags & OPF_FARG)) { pp->arg[arg].datap = &ops[j]; + need_to_save_current = 0; if (!need_op_saving) { ret = scan_for_mod(&ops[j], j + 1, i); - need_op_saving = (ret >= 0); + need_to_save_current = (ret >= 0); } - if (need_op_saving) { + if (need_op_saving || need_to_save_current) { // mark this push as one that needs operand saving ops[j].flags &= ~OPF_RMD; if (ops[j].argnum == 0) { @@ -2074,10 +2118,10 @@ static int collect_call_args(struct parsed_op *po, int i, else if (ops[j].argnum == 0) ops[j].flags |= OPF_RMD; - // some PUSHes are reused by calls on multiple branches, + // some PUSHes are reused by different calls on other branches, // but that can't happen if we didn't branch, so they // can be removed from future searches (handles nested calls) - if (!branched) + if (!may_reuse) ops[j].flags |= OPF_FARG; // next arg @@ -2106,6 +2150,7 @@ static void add_label_ref(struct label_ref *lr, int op_i) lr_new = calloc(1, sizeof(*lr_new)); lr_new->i = op_i; + lr_new->next = lr->next; lr->next = lr_new; } @@ -2114,6 +2159,7 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op; struct parsed_opr *last_arith_dst = NULL; char buf1[256], buf2[256], buf3[256], cast[64]; + const struct parsed_proto *pp_c; struct parsed_proto *pp, *pp_tmp; struct parsed_data *pd; const char *tmpname; @@ -2122,7 +2168,6 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) int cmp_result_vars = 0; int need_mul_var = 0; int had_decl = 0; - int branched = 0; int label_pending = 0; int regmask_save = 0; int regmask_arg = 0; @@ -2139,20 +2184,20 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) g_bp_frame = g_sp_frame = g_stack_fsz = 0; - ret = proto_parse(fhdr, funcn, &g_func_pp); - if (ret) + g_func_pp = proto_parse(fhdr, funcn); + if (g_func_pp == NULL) ferr(ops, "proto_parse failed for '%s'\n", funcn); - fprintf(fout, "%s ", g_func_pp.ret_type.name); + fprintf(fout, "%s ", g_func_pp->ret_type.name); if (g_ida_func_attr & IDAFA_NORETURN) fprintf(fout, "noreturn "); fprintf(fout, "%s(", funcn); - for (i = 0; i < g_func_pp.argc; i++) { + for (i = 0; i < g_func_pp->argc; i++) { if (i > 0) fprintf(fout, ", "); - fprintf(fout, "%s a%d", g_func_pp.arg[i].type.name, i + 1); + fprintf(fout, "%s a%d", g_func_pp->arg[i].type.name, i + 1); } - if (g_func_pp.is_vararg) { + if (g_func_pp->is_vararg) { if (i > 0) fprintf(fout, ", "); fprintf(fout, "..."); @@ -2363,9 +2408,10 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) pp->arg[arg].type.name = strdup("int"); } else { - ret = proto_parse(fhdr, tmpname, pp); - if (ret) + pp_c = proto_parse(fhdr, tmpname); + if (pp_c == NULL) ferr(po, "proto_parse failed for call '%s'\n", tmpname); + pp = proto_clone(pp_c); } // look for and make use of esp adjust @@ -2410,6 +2456,9 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) } collect_call_args(po, i, pp, &save_arg_vars, 0, 0, 0); + + if (strstr(pp->ret_type.name, "int64")) + need_mul_var = 1; po->datap = pp; } } @@ -2464,33 +2513,41 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) if (po->flags & OPF_CC) { - ret = scan_for_flag_set(i, &branched); - if (ret < 0) - ferr(po, "unable to trace flag setter\n"); + int setters[16], cnt = 0, branched = 0; + + ret = scan_for_flag_set(i, &branched, setters, &cnt); + if (ret < 0 || cnt <= 0) + ferr(po, "unable to trace flag setter(s)\n"); + if (cnt > ARRAY_SIZE(setters)) + ferr(po, "too many flag setters\n"); - tmp_op = &ops[ret]; // flag setter pfo = split_cond(po, po->op, &dummy); - pfomask = 0; - - // to get nicer code, we try to delay test and cmp; - // if we can't because of operand modification, or if we - // have math op, or branch, make it calculate flags explicitly - if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP) { - if (branched || scan_for_mod(tmp_op, ret + 1, i) >= 0) - pfomask = 1 << pfo; - } - else if (tmp_op->op == OP_CMPS) { - pfomask = 1 << PFO_Z; - } - else { - if ((pfo != PFO_Z && pfo != PFO_S && pfo != PFO_P) - || scan_for_mod_opr0(tmp_op, ret + 1, i) >= 0) - pfomask = 1 << pfo; - } - if (pfomask) { - tmp_op->pfomask |= pfomask; - cmp_result_vars |= pfomask; - po->datap = tmp_op; + for (j = 0; j < cnt; j++) + { + tmp_op = &ops[setters[j]]; // flag setter + pfomask = 0; + + // to get nicer code, we try to delay test and cmp; + // if we can't because of operand modification, or if we + // have math op, or branch, make it calculate flags explicitly + if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP) { + if (branched || scan_for_mod(tmp_op, setters[j] + 1, i) >= 0) + pfomask = 1 << pfo; + } + else if (tmp_op->op == OP_CMPS) { + pfomask = 1 << PFO_Z; + } + else { + if ((pfo != PFO_Z && pfo != PFO_S && pfo != PFO_P) + || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0) + pfomask = 1 << pfo; + } + if (pfomask) { + tmp_op->pfomask |= pfomask; + cmp_result_vars |= pfomask; + // note: may overwrite, currently not a problem + po->datap = tmp_op; + } } if (po->op == OP_ADC || po->op == OP_SBB) @@ -2545,27 +2602,27 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) fprintf(fout, " union { u32 d[%d]; u16 w[%d]; u8 b[%d]; } sf;\n", (g_stack_fsz + 3) / 4, (g_stack_fsz + 1) / 2, g_stack_fsz); - if (g_func_pp.is_vararg) + if (g_func_pp->is_vararg) fprintf(fout, " va_list ap;\n"); // declare arg-registers - for (i = 0; i < g_func_pp.argc; i++) { - if (g_func_pp.arg[i].reg != NULL) { + for (i = 0; i < g_func_pp->argc; i++) { + if (g_func_pp->arg[i].reg != NULL) { reg = char_array_i(regs_r32, - ARRAY_SIZE(regs_r32), g_func_pp.arg[i].reg); + ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg); if (reg < 0) - ferr(ops, "arg '%s' is not a reg?\n", g_func_pp.arg[i].reg); + ferr(ops, "arg '%s' is not a reg?\n", g_func_pp->arg[i].reg); regmask_arg |= 1 << reg; fprintf(fout, " u32 %s = (u32)a%d;\n", - g_func_pp.arg[i].reg, i + 1); + g_func_pp->arg[i].reg, i + 1); had_decl = 1; } } // declare other regs - special case for eax if (!((regmask | regmask_arg) & 1) - && !IS(g_func_pp.ret_type.name, "void")) + && !IS(g_func_pp->ret_type.name, "void")) { fprintf(fout, " u32 eax = 0;\n"); had_decl = 1; @@ -2619,10 +2676,10 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) if (had_decl) fprintf(fout, "\n"); - if (g_func_pp.is_vararg) { - if (g_func_pp.argc_stack == 0) + if (g_func_pp->is_vararg) { + if (g_func_pp->argc_stack == 0) ferr(ops, "vararg func without stack args?\n"); - fprintf(fout, " va_start(ap, a%d);\n", g_func_pp.argc); + fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc); } // output ops @@ -2631,6 +2688,9 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) if (g_labels[i][0] != 0 && g_label_refs[i].i != -1) { fprintf(fout, "\n%s:\n", g_labels[i]); label_pending = 1; + + delayed_flag_op = NULL; + last_arith_dst = NULL; } po = &ops[i]; @@ -3026,13 +3086,22 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0])); fprintf(fout, " "); - if (!IS(pp->ret_type.name, "void")) { + if (strstr(pp->ret_type.name, "int64")) { if (po->flags & OPF_TAIL) + ferr(po, "int64 and tail?\n"); + fprintf(fout, "mul_tmp = "); + } + else if (!IS(pp->ret_type.name, "void")) { + if (po->flags & OPF_TAIL) { fprintf(fout, "return "); - else + if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr) + fprintf(fout, "(%s)", g_func_pp->ret_type.name); + } + else { fprintf(fout, "eax = "); - if (pp->ret_type.is_ptr) - fprintf(fout, "(u32)"); + if (pp->ret_type.is_ptr) + fprintf(fout, "(u32)"); + } } if (po->operand[0].type != OPT_LABEL) { @@ -3041,7 +3110,8 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) else { if (pp->name[0] == 0) ferr(po, "missing pp->name\n"); - fprintf(fout, "%s(", pp->name); + fprintf(fout, "%s%s(", pp->name, + pp->has_structarg ? "_sa" : ""); } for (arg = 0; arg < pp->argc; arg++) { @@ -3072,6 +3142,12 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) } fprintf(fout, ");"); + if (strstr(pp->ret_type.name, "int64")) { + fprintf(fout, "\n"); + fprintf(fout, " edx = mul_tmp >> 32;\n"); + fprintf(fout, " eax = mul_tmp;"); + } + if (po->flags & OPF_TAIL) { strcpy(g_comment, "tailcall"); if (IS(pp->ret_type.name, "void") @@ -3086,16 +3162,16 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) break; case OP_RET: - if (g_func_pp.is_vararg) + if (g_func_pp->is_vararg) fprintf(fout, " va_end(ap);\n"); - if (IS(g_func_pp.ret_type.name, "void")) { + if (IS(g_func_pp->ret_type.name, "void")) { if (i != opcnt - 1 || label_pending) fprintf(fout, " return;"); } - else if (g_func_pp.ret_type.is_ptr) { + else if (g_func_pp->ret_type.is_ptr) { fprintf(fout, " return (%s)eax;", - g_func_pp.ret_type.name); + g_func_pp->ret_type.name); } else fprintf(fout, " return eax;"); @@ -3131,6 +3207,7 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) break; case OP_NOP: + no_output = 1; break; default: @@ -3140,13 +3217,6 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) break; } - // some sanity checking - if ((po->flags & OPF_REP) && po->op != OP_STOS - && po->op != OP_MOVS && po->op != OP_CMPS) - ferr(po, "unexpected rep\n"); - if ((po->flags & (OPF_REPZ|OPF_REPNZ)) && po->op != OP_CMPS) - ferr(po, "unexpected repz/repnz\n"); - if (g_comment[0] != 0) { fprintf(fout, " // %s", g_comment); g_comment[0] = 0; @@ -3155,6 +3225,13 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) if (!no_output) fprintf(fout, "\n"); + // some sanity checking + if ((po->flags & OPF_REP) && po->op != OP_STOS + && po->op != OP_MOVS && po->op != OP_CMPS) + ferr(po, "unexpected rep\n"); + if ((po->flags & (OPF_REPZ|OPF_REPNZ)) && po->op != OP_CMPS) + ferr(po, "unexpected repz/repnz\n"); + if (pfomask != 0) ferr(po, "missed flag calc, pfomask=%x\n", pfomask); @@ -3189,13 +3266,11 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) if (ops[i].op == OP_CALL) { pp = ops[i].datap; - if (pp) { + if (pp) proto_release(pp); - free(pp); - } } } - proto_release(&g_func_pp); + g_func_pp = NULL; } static void set_label(int i, const char *name)