X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=tools%2Ftranslate.c;h=8ebda8289749b881ef54db6744b280bde8f4e001;hb=236c23eb625fc3d412b3105ab6e67723d661348d;hp=50af3bfbd5d61951180e76249512808fb072e7d4;hpb=0a2c6da1fa73197c1b9f75e74650ea98e3ad4ea1;p=ia32rtools.git diff --git a/tools/translate.c b/tools/translate.c index 50af3bf..8ebda82 100644 --- a/tools/translate.c +++ b/tools/translate.c @@ -61,7 +61,7 @@ enum op_flags { 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 */ @@ -328,6 +328,7 @@ static int g_sct_func_attr; 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; @@ -1337,20 +1338,26 @@ static void parse_op(struct parsed_op *op, char words[16][256], int wordc) // 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: @@ -1405,6 +1412,8 @@ static void parse_op(struct parsed_op *op, char words[16][256], int wordc) 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; @@ -2142,7 +2151,7 @@ static void check_func_pp(struct parsed_op *po, } static const char *check_label_read_ref(struct parsed_op *po, - const char *name) + const char *name, int *is_import) { const struct parsed_proto *pp; @@ -2153,6 +2162,9 @@ static const char *check_label_read_ref(struct parsed_op *po, if (pp->is_func) check_func_pp(po, pp, "ref"); + if (is_import != NULL) + *is_import = pp->is_import; + return pp->name; } @@ -2171,6 +2183,7 @@ static char *out_src_opr(char *buf, size_t buf_size, char tmp1[256], tmp2[256]; char expr[256]; const char *name; + int is_import = 0; char *p; int ret; @@ -2243,7 +2256,11 @@ static char *out_src_opr(char *buf, size_t buf_size, break; case OPT_LABEL: - name = check_label_read_ref(po, popr->name); + name = check_label_read_ref(po, popr->name, &is_import); + if (is_import) + // for imported data, asm is loading the offset + goto do_offset; + if (cast[0] == 0 && popr->is_ptr) cast = "(u32)"; @@ -2259,7 +2276,8 @@ static char *out_src_opr(char *buf, size_t buf_size, break; case OPT_OFFSET: - name = check_label_read_ref(po, popr->name); + do_offset: + name = check_label_read_ref(po, popr->name, NULL); if (cast[0] == 0) cast = "(u32)"; if (is_lea) @@ -6310,6 +6328,9 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) { if (pp->name[0] != 0) { + if (IS_START(pp->name, "guess")) + pp->is_guessed = 1; + memmove(pp->name + 2, pp->name, strlen(pp->name) + 1); memcpy(pp->name, "i_", 2); @@ -6420,7 +6441,7 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) } // 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++) { @@ -7347,9 +7368,10 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) fprintf(fout, "%s%s = %s;\n", buf3, pp->name, out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "(void *)", 0)); - if (pp->is_unresolved || IS_START(pp->name, "i_guess")) - fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n", - buf3, asmfn, po->asmln, pp->name); + } + if (pp->is_fptr && (pp->is_unresolved || pp->is_guessed)) { + fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n", + buf3, asmfn, po->asmln, pp->name); } fprintf(fout, "%s", buf3); @@ -8077,6 +8099,7 @@ struct func_prototype { 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 @@ -8291,6 +8314,7 @@ static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits, 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) { @@ -8380,15 +8404,9 @@ static void gen_hdr(const char *funcn, int opcnt) } // pass4: - // - remove dead labels // - handle push /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; @@ -8616,8 +8634,9 @@ static void output_hdr_fp(FILE *fout, const struct func_prototype *fp, 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) @@ -8708,6 +8727,12 @@ static void output_hdr(FILE *fout) // 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); @@ -9131,7 +9156,7 @@ int main(int argc, char *argv[]) int pi = 0; int i, j; int ret, len; - char *p; + char *p, *p2; int wordc; for (arg = 1; arg < argc; arg++) { @@ -9299,6 +9324,7 @@ int main(int argc, char *argv[]) static const char *attrs[] = { "clear_sf", "clear_regmask", + "rm_regmask", }; // parse manual attribute-list comment @@ -9322,6 +9348,9 @@ int main(int argc, char *argv[]) else if (i == 1) // clear_regmask= ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1; + else if (i == 2) + // rm_regmask= + ret = sscanf(p, "=%x%n", &g_regmask_rm, &j) + 1; if (ret < 2) { anote("unparsed attr value: %s\n", p); break; @@ -9408,6 +9437,11 @@ parse_words: // 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 == ';') @@ -9525,6 +9559,7 @@ do_pending_endp: 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;