X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=tools%2Ftranslate.c;h=673e4ba5cc71e21f6686733e1454978ca8d45b69;hb=578603650c721811eb0a4747329e3854f171ce37;hp=12f01f9fae33c9de96c4c2cf2f4f473940f4fbb8;hpb=ba93cc12011777a68120c6c5cd488b8b149483f2;p=ia32rtools.git diff --git a/tools/translate.c b/tools/translate.c index 12f01f9..673e4ba 100644 --- a/tools/translate.c +++ b/tools/translate.c @@ -68,8 +68,9 @@ enum op_flags { OPF_NOREGS = (1 << 21), /* don't track regs of this op */ OPF_FPUSH = (1 << 22), /* pushes x87 stack */ OPF_FPOP = (1 << 23), /* pops x87 stack */ - OPF_FSHIFT = (1 << 24), /* x87 stack shift is actually needed */ - OPF_FINT = (1 << 25), /* integer float op arg */ + OPF_FPOPP = (1 << 24), /* pops x87 stack twice */ + OPF_FSHIFT = (1 << 25), /* x87 stack shift is actually needed */ + OPF_FINT = (1 << 26), /* integer float op arg */ }; enum op_op { @@ -1109,6 +1110,10 @@ static const struct { { "fisubr", OP_FISUBR, 1, 1, OPF_FINT }, { "fcom", OP_FCOM, 0, 1, 0 }, { "fcomp", OP_FCOM, 0, 1, OPF_FPOP }, + { "fcompp", OP_FCOM, 0, 0, OPF_FPOPP }, + { "fucom", OP_FCOM, 0, 1, 0 }, + { "fucomp", OP_FCOM, 0, 1, OPF_FPOP }, + { "fucompp",OP_FCOM, 0, 0, OPF_FPOPP }, { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA }, { "fchs", OP_FCHS, 0, 0, 0 }, { "fcos", OP_FCOS, 0, 0, 0 }, @@ -1474,6 +1479,13 @@ static void parse_op(struct parsed_op *op, char words[16][256], int wordc) case OP_FCOM: op->regmask_src |= mxST0; + if (op->operand_cnt == 0) { + op->operand_cnt = 1; + op->operand[0].type = OPT_REG; + op->operand[0].lmod = OPLM_QWORD; + op->operand[0].reg = xST1; + op->regmask_src |= mxST1; + } break; default: @@ -3779,6 +3791,13 @@ static void resolve_branches_parse_calls(int opcnt) ferr(po, "call to loc_*\n"); if (IS(tmpname, "__alloca_probe")) continue; + if (IS(tmpname, "__SEH_prolog")) { + ferr_assert(po, g_seh_found == 0); + g_seh_found = 2; + continue; + } + if (IS(tmpname, "__SEH_epilog")) + continue; // convert some calls to pseudo-ops for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) { @@ -3872,6 +3891,32 @@ tailcall: static int resolve_origin(int i, const struct parsed_opr *opr, int magic, int *op_i, int *is_caller); +static void eliminate_seh_writes(int opcnt) +{ + const struct parsed_opr *opr; + char ofs_reg[16]; + int offset; + int i; + + // assume all sf writes above g_seh_size to be seh related + // (probably unsafe but oh well) + for (i = 0; i < opcnt; i++) { + if (ops[i].op != OP_MOV) + continue; + opr = &ops[i].operand[0]; + if (opr->type != OPT_REGMEM) + continue; + if (!is_stack_access(&ops[i], opr)) + continue; + + offset = 0; + parse_stack_access(&ops[i], opr->name, ofs_reg, &offset, + NULL, NULL, 0); + if (offset < 0 && offset >= -g_seh_size) + ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS; + } +} + static void eliminate_seh(int opcnt) { int i, j, k, ret; @@ -3913,26 +3958,96 @@ static void eliminate_seh(int opcnt) } } - // assume all sf writes above g_seh_size to be seh related - // (probably unsafe but oh well) - for (i = 0; i < opcnt; i++) { - const struct parsed_opr *opr; - char ofs_reg[16]; - int offset = 0; + eliminate_seh_writes(opcnt); +} - if (ops[i].op != OP_MOV) - continue; - opr = &ops[i].operand[0]; - if (opr->type != OPT_REGMEM) +static void eliminate_seh_calls(int opcnt) +{ + int epilog_found = 0; + int i; + + g_bp_frame = 1; + g_seh_size = 0x10; + + i = 0; + ferr_assert(&ops[i], ops[i].op == OP_PUSH + && ops[i].operand[0].type == OPT_CONST); + g_stack_fsz = g_seh_size + ops[i].operand[0].val; + ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS; + + i++; + ferr_assert(&ops[i], ops[i].op == OP_PUSH + && ops[i].operand[0].type == OPT_OFFSET); + ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS; + + i++; + ferr_assert(&ops[i], ops[i].op == OP_CALL + && IS(opr_name(&ops[i], 0), "__SEH_prolog")); + ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS; + + for (i++; i < opcnt; i++) { + if (ops[i].op != OP_CALL) continue; - if (!is_stack_access(&ops[i], opr)) + if (!IS(opr_name(&ops[i], 0), "__SEH_epilog")) continue; - parse_stack_access(&ops[i], opr->name, ofs_reg, &offset, - NULL, NULL, 0); - if (offset < 0 && offset >= -g_seh_size) + ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS; + epilog_found = 1; + } + ferr_assert(ops, epilog_found); + + eliminate_seh_writes(opcnt); +} + +static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub) +{ + int j; + + for (; i < opcnt; i++) + if (!(ops[i].flags & OPF_DONE)) + break; + + while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) { + ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS; + g_stack_fsz += 4; + (*ecx_push)++; + i++; + } + + for (; i < opcnt; i++) { + if (i > 0 && g_labels[i] != NULL) + break; + if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL))) + break; + if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP + && ops[i].operand[1].type == OPT_CONST) + { + g_stack_fsz += opr_const(&ops[i], 1); ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS; + i++; + *esp_sub = 1; + break; + } + if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX + && ops[i].operand[1].type == OPT_CONST) + { + for (j = i + 1; j < opcnt; j++) + if (!(ops[j].flags & OPF_DONE)) + break; + if (ops[j].op == OP_CALL + && IS(opr_name(&ops[j], 0), "__alloca_probe")) + { + g_stack_fsz += opr_const(&ops[i], 1); + ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS; + ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS; + i = j + 1; + *esp_sub = 1; + } + break; + } } + + return i; } static void scan_prologue_epilogue(int opcnt, int *stack_align) @@ -3942,6 +4057,10 @@ static void scan_prologue_epilogue(int opcnt, int *stack_align) int found; int i, j, l; + if (g_seh_found == 2) { + eliminate_seh_calls(opcnt); + return; + } if (g_seh_found) { eliminate_seh(opcnt); // ida treats seh as part of sf @@ -3981,32 +4100,7 @@ static void scan_prologue_epilogue(int opcnt, int *stack_align) i++; } - if (ops[i].op == OP_SUB && IS(opr_name(&ops[i], 0), "esp")) { - g_stack_fsz += opr_const(&ops[i], 1); - ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS; - i++; - } - else { - // another way msvc builds stack frame.. - while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) { - g_stack_fsz += 4; - ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS; - ecx_push++; - i++; - } - // and another way.. - if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX - && ops[i].operand[1].type == OPT_CONST - && ops[i + 1].op == OP_CALL - && IS(opr_name(&ops[i + 1], 0), "__alloca_probe")) - { - g_stack_fsz += ops[i].operand[1].val; - ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS; - i++; - ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS; - i++; - } - } + i = scan_prologue(i, opcnt, &ecx_push, &esp_sub); found = 0; do { @@ -4084,43 +4178,7 @@ static void scan_prologue_epilogue(int opcnt, int *stack_align) } // non-bp frame - for (i = 0; i < opcnt; i++) - if (!(ops[i].flags & OPF_DONE)) - break; - - while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) { - ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS; - g_stack_fsz += 4; - ecx_push++; - i++; - } - - for (; i < opcnt; i++) { - if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL))) - break; - if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP - && ops[i].operand[1].type == OPT_CONST) - { - g_stack_fsz += ops[i].operand[1].val; - ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS; - i++; - esp_sub = 1; - break; - } - else if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX - && ops[i].operand[1].type == OPT_CONST - && ops[i + 1].op == OP_CALL - && IS(opr_name(&ops[i + 1], 0), "__alloca_probe")) - { - g_stack_fsz += ops[i].operand[1].val; - ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS; - i++; - ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS; - i++; - esp_sub = 1; - break; - } - } + i = scan_prologue(0, opcnt, &ecx_push, &esp_sub); if (ecx_push && !esp_sub) { // could actually be args for a call.. @@ -4172,9 +4230,20 @@ static void scan_prologue_epilogue(int opcnt, int *stack_align) i--; j--; } + else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) { + // skip arg updates for arg-reuse tailcall + for (; j >= 0; j--) { + if (ops[j].op != OP_MOV) + break; + if (ops[j].operand[0].type != OPT_REGMEM) + break; + if (strstr(ops[j].operand[0].name, "arg_") == NULL) + break; + } + } if (ecx_push > 0 && !esp_sub) { - for (l = 0; l < ecx_push; l++) { + for (l = 0; l < ecx_push && j >= 0; l++) { if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx")) /* pop ecx */; else if (ops[j].op == OP_ADD @@ -5452,7 +5521,15 @@ static void reg_use_pass(int i, int opcnt, unsigned char *cbits, *regmask |= regmask_now; // released regs - if (po->flags & OPF_FPOP) { + if (po->flags & OPF_FPOPP) { + if ((regmask_now & mxSTa) == 0) + ferr(po, "float pop on empty stack?\n"); + if (regmask_now & mxST7_2) + po->flags |= OPF_FSHIFT; + if (!(regmask_now & mxST7_2)) + regmask_now &= ~mxST1_0; + } + else if (po->flags & OPF_FPOP) { if ((regmask_now & mxSTa) == 0) ferr(po, "float pop on empty stack?\n"); if (regmask_now & (mxST7_2 | mxST1)) @@ -6033,7 +6110,8 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1); // correct for "full stack" mode late enable - if ((po->flags & (OPF_PPUSH|OPF_FPOP)) && need_float_stack) + if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP)) + && need_float_stack) po->flags |= OPF_FSHIFT; } @@ -7109,7 +7187,7 @@ 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) + if (pp->is_unresolved || IS_START(pp->name, "i_guess")) fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n", buf3, asmfn, po->asmln, pp->name); } @@ -7219,6 +7297,19 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) if (tmp_op->operand[0].lmod == OPLM_QWORD) arg++; } + else if (pp->arg[arg].type.is_64bit) { + ferr_assert(po, tmp_op->p_argpass == 0); + ferr_assert(po, !pp->arg[arg].is_saved); + ferr_assert(po, cast[0] == 0); + out_src_opr(buf1, sizeof(buf1), + tmp_op, &tmp_op->operand[0], cast, 0); + tmp_op = pp->arg[++arg].datap; + ferr_assert(po, tmp_op != NULL); + out_src_opr(buf2, sizeof(buf2), + tmp_op, &tmp_op->operand[0], cast, 0); + fprintf(fout, "((u64)(%s) << 32) | (%s)", + buf2, buf1); + } else if (tmp_op->p_argpass != 0) { fprintf(fout, "a%d", tmp_op->p_argpass); } @@ -7592,7 +7683,7 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;", float_st0, buf1); } - else if (mask == 0x4000) { // C3 -> = + else if (mask == 0x4000 || mask == 0x4400) { // C3 -> = fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;", float_st0, buf1); } @@ -7611,10 +7702,16 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) else ferr(po, "unhandled sw mask: %x\n", mask); if (po->flags & OPF_FSHIFT) { - if (need_float_stack) - fprintf(fout, " f_stp++;"); - else + if (need_float_stack) { + if (po->flags & OPF_FPOPP) + fprintf(fout, " f_stp += 2;"); + else + fprintf(fout, " f_stp++;"); + } + else { + ferr_assert(po, !(po->flags & OPF_FPOPP)); fprintf(fout, " f_st0 = f_st1;"); + } } break; }