From 306201740a8996e02008918dc3e6a5a8e0d00223 Mon Sep 17 00:00:00 2001 From: notaz Date: Wed, 29 Apr 2015 00:20:46 +0300 Subject: [PATCH] translate: handle float arg frame --- tests/x87.asm | 7 ++ tests/x87.expect.c | 6 ++ tests/x87.seed.h | 1 + tools/translate.c | 185 ++++++++++++++++++++++++++++++++++++++------- 4 files changed, 173 insertions(+), 26 deletions(-) diff --git a/tests/x87.asm b/tests/x87.asm index d80f264..18ec835 100644 --- a/tests/x87.asm +++ b/tests/x87.asm @@ -3,6 +3,7 @@ _text segment para public 'CODE' use32 sub_test proc near +var_28 = qword ptr -28h var_20 = dword ptr -20h var_18 = qword ptr -18h arg_0 = dword ptr 8 @@ -16,6 +17,12 @@ arg_0 = dword ptr 8 fild [ebp+var_20] fdiv st(1), st faddp st(1), st + fld [ebp+var_18] + sub esp, 10h + fstp [esp+30h+var_28] + fstp qword ptr [esp+0] + call _pow + add esp, 10h fcom [ebp+var_18] xor eax, eax fnstsw ax diff --git a/tests/x87.expect.c b/tests/x87.expect.c index 25223ee..b44043e 100644 --- a/tests/x87.expect.c +++ b/tests/x87.expect.c @@ -6,6 +6,8 @@ int sub_test(int a1, int a2) double f_st0; double f_st1; u16 f_sw; + double fs_1; + double fs_3; u32 cond_z; f_st0 = (double)(s32)sf.d[0]; // var_20 fild @@ -14,6 +16,10 @@ int sub_test(int a1, int a2) f_st1 = f_st0; f_st0 = (double)(s32)sf.d[0]; // var_20 fild f_st1 /= f_st0; f_st0 = f_st1 + f_st0; + f_st1 = f_st0; f_st0 = *((double *)(u32)&sf.q[1]); // var_18 fld + fs_3 = f_st0; f_st0 = f_st1; // fst + fs_1 = f_st0; // fst + f_st0 = pow(fs_1, fs_3); f_sw = f_st0 <= *((double *)(u32)&sf.q[1]) ? 0x4100 : 0; // var_18 z_chk_det eax = 0; LOWORD(eax) = f_sw; diff --git a/tests/x87.seed.h b/tests/x87.seed.h index e69de29..02943c6 100644 --- a/tests/x87.seed.h +++ b/tests/x87.seed.h @@ -0,0 +1 @@ +//#include ../stdc.hlist diff --git a/tools/translate.c b/tools/translate.c index 95e8802..dc0c74c 100644 --- a/tools/translate.c +++ b/tools/translate.c @@ -511,12 +511,12 @@ static int is_reg_in_str(const char *s) } static const char *parse_stack_el(const char *name, char *extra_reg, - int early_try) + int *base_val, int early_try) { const char *p, *p2, *s; char *endp = NULL; char buf[32]; - long val; + long val = -1; int len; if (g_bp_frame || early_try) @@ -589,6 +589,8 @@ static const char *parse_stack_el(const char *name, char *extra_reg, if ('0' <= *p && *p <= '9') return NULL; + if (base_val != NULL) + *base_val = val; return p; } @@ -823,11 +825,12 @@ static int parse_operand(struct parsed_opr *opr, aerr("[] parse failure\n"); parse_indmode(opr->name, regmask_indirect, 1); - if (opr->lmod == OPLM_UNSPEC && parse_stack_el(opr->name, NULL, 1)) + if (opr->lmod == OPLM_UNSPEC + && parse_stack_el(opr->name, NULL, NULL, 1)) { // might be an equ struct parsed_equ *eq = - equ_find(NULL, parse_stack_el(opr->name, NULL, 1), &i); + equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i); if (eq) opr->lmod = eq->lmod; @@ -1747,7 +1750,7 @@ static struct parsed_equ *equ_find(struct parsed_op *po, const char *name, static int is_stack_access(struct parsed_op *po, const struct parsed_opr *popr) { - return (parse_stack_el(popr->name, NULL, 0) + return (parse_stack_el(popr->name, NULL, NULL, 0) || (g_bp_frame && !(po->flags & OPF_EBP_S) && IS_START(popr->name, "ebp"))); } @@ -1778,7 +1781,7 @@ static void parse_stack_access(struct parsed_op *po, ferr(po, "ebp- parse of '%s' failed\n", name); } else { - bp_arg = parse_stack_el(name, ofs_reg, 0); + bp_arg = parse_stack_el(name, ofs_reg, NULL, 0); snprintf(g_comment, sizeof(g_comment), "%s", bp_arg); eq = equ_find(po, bp_arg, &offset); if (eq == NULL) @@ -1797,11 +1800,46 @@ static void parse_stack_access(struct parsed_op *po, } *offset_out = offset; - *stack_ra_out = stack_ra; + if (stack_ra_out) + *stack_ra_out = stack_ra; if (bp_arg_out) *bp_arg_out = bp_arg; } +static int parse_stack_esp_offset(struct parsed_op *po, + const char *name, int *offset_out) +{ + char ofs_reg[16] = { 0, }; + struct parsed_equ *eq; + const char *bp_arg; + char *endp = NULL; + int base_val = 0; + int offset = 0; + + if (strstr(name, "esp") == NULL) + return -1; + bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0); + if (bp_arg == NULL) { + // just plain offset? + if (!IS_START(name, "esp+")) + return -1; + offset = strtol(name + 4, &endp, 0); + if (endp == NULL || *endp != 0) + return -1; + *offset_out = offset; + return 0; + } + + if (ofs_reg[0] != 0) + return -1; + eq = equ_find(po, bp_arg, &offset); + if (eq == NULL) + ferr(po, "detected but missing eq\n"); + offset += eq->offset; + *offset_out = base_val + offset; + return 0; +} + static int stack_frame_access(struct parsed_op *po, struct parsed_opr *popr, char *buf, size_t buf_size, const char *name, const char *cast, int is_src, int is_lea) @@ -4530,9 +4568,69 @@ static struct parsed_proto *process_call(int i, int opcnt) return pp; } -static int collect_call_args_early(struct parsed_op *po, int i, - struct parsed_proto *pp, int *regmask) +static int collect_call_args_no_push(int i, struct parsed_proto *pp, + int *regmask_ffca) { + struct parsed_op *po; + int offset = 0; + int base_arg; + int j, arg; + int ret; + + for (base_arg = 0; base_arg < pp->argc; base_arg++) + if (pp->arg[base_arg].reg == NULL) + break; + + for (j = i; j > 0; ) + { + ferr_assert(&ops[j], g_labels[j] == NULL); + j--; + + po = &ops[j]; + ferr_assert(po, po->op != OP_PUSH); + if (po->op == OP_FST) + { + if (po->operand[0].type != OPT_REGMEM) + continue; + ret = parse_stack_esp_offset(po, po->operand[0].name, &offset); + if (ret != 0) + continue; + if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) + ferr(po, "bad offset %d (%d args)\n", offset, pp->argc_stack); + + arg = base_arg + offset / 4; + po->p_argnext = -1; + po->p_argnum = arg + 1; + ferr_assert(po, pp->arg[arg].datap == NULL); + pp->arg[arg].datap = po; + po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG; + if (regmask_ffca != NULL) + *regmask_ffca |= 1 << arg; + } + else if (po->op == OP_SUB && po->operand[0].reg == xSP + && po->operand[1].type == OPT_CONST) + { + po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG; + break; + } + } + + for (arg = base_arg; arg < pp->argc; arg++) { + ferr_assert(&ops[i], pp->arg[arg].reg == NULL); + po = pp->arg[arg].datap; + if (po == NULL) + ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc); + if (po->operand[0].lmod == OPLM_QWORD) + arg++; + } + + return 0; +} + +static int collect_call_args_early(int i, struct parsed_proto *pp, + int *regmask, int *regmask_ffca) +{ + struct parsed_op *po; int arg, ret; int j; @@ -4547,19 +4645,20 @@ static int collect_call_args_early(struct parsed_op *po, int i, return -1; j--; - if (ops[j].op == OP_CALL) + po = &ops[j]; + if (po->op == OP_CALL) return -1; - else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP) + else if (po->op == OP_ADD && po->operand[0].reg == xSP) return -1; - else if (ops[j].op == OP_POP) + else if (po->op == OP_POP) return -1; - else if (ops[j].flags & OPF_CJMP) + else if (po->flags & OPF_CJMP) return -1; - else if (ops[j].op == OP_PUSH) { - if (ops[j].flags & (OPF_FARG|OPF_FARGNR)) + else if (po->op == OP_PUSH) { + if (po->flags & (OPF_FARG|OPF_FARGNR)) return -1; if (!g_header_mode) { - ret = scan_for_mod(&ops[j], j + 1, i, 1); + ret = scan_for_mod(po, j + 1, i, 1); if (ret >= 0) return -1; } @@ -4572,6 +4671,17 @@ static int collect_call_args_early(struct parsed_op *po, int i, if (pp->arg[arg].reg == NULL) break; } + else if (po->op == OP_SUB && po->operand[0].reg == xSP + && po->operand[1].type == OPT_CONST) + { + if (po->flags & (OPF_RMD|OPF_DONE)) + return -1; + if (po->operand[1].val != pp->argc_stack * 4) + ferr(po, "unexpected esp adjust: %d\n", + po->operand[1].val * 4); + ferr_assert(po, pp->argc - arg == pp->argc_stack); + return collect_call_args_no_push(i, pp, regmask_ffca); + } } if (arg < pp->argc) @@ -4592,7 +4702,7 @@ static int collect_call_args_early(struct parsed_op *po, int i, ferr_assert(&ops[j], pp->arg[arg].datap == NULL); pp->arg[arg].datap = &ops[j]; - if (ops[j].operand[0].type == OPT_REG) + if (regmask != NULL && ops[j].operand[0].type == OPT_REG) *regmask |= 1 << ops[j].operand[0].reg; ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG; @@ -5226,6 +5336,7 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) int regmask_now; // temp int regmask_init = 0; // regs that need zero initialization int regmask_pp = 0; // regs used in complex push-pop graph + int regmask_ffca = 0; // float function call args int regmask = 0; // used regs int pfomask = 0; int found = 0; @@ -5283,10 +5394,12 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) { pp = process_call_early(i, opcnt, &j); if (pp != NULL) { - if (!(po->flags & OPF_ATAIL)) + if (!(po->flags & OPF_ATAIL)) { // since we know the args, try to collect them - if (collect_call_args_early(po, i, pp, ®mask) != 0) + ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca); + if (ret != 0) pp = NULL; + } } if (pp != NULL) { @@ -5807,6 +5920,15 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) } } + if (regmask_ffca) { + for (reg = 0; reg < 32; reg++) { + if (regmask_ffca & (1 << reg)) { + fprintf(fout, " %s fs_%d;\n", float_type, reg + 1); + had_decl = 1; + } + } + } + // declare push-pop temporaries if (regmask_pp) { for (reg = 0; reg < 8; reg++) { @@ -6763,6 +6885,11 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) if (tmp_op->flags & OPF_VAPUSH) { fprintf(fout, "ap"); } + else if (tmp_op->op == OP_FST) { + fprintf(fout, "fs_%d", tmp_op->p_argnum); + if (tmp_op->operand[0].lmod == OPLM_QWORD) + arg++; + } else if (tmp_op->p_argpass != 0) { fprintf(fout, "a%d", tmp_op->p_argpass); } @@ -6992,13 +7119,19 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) break; case OP_FST: - dead_dst = po->operand[0].type == OPT_REG - && po->operand[0].reg == xST0; - if (!dead_dst) { - fprintf(fout, " %s = %s;", - out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0], - need_float_stack), float_st0); + if (po->flags & OPF_FARG) { + // store to stack as func arg + snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum); + dead_dst = 0; + } + else { + out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0], + need_float_stack); + dead_dst = po->operand[0].type == OPT_REG + && po->operand[0].reg == xST0; } + if (!dead_dst) + fprintf(fout, " %s = %s;", buf1, float_st0); if (po->flags & OPF_FSHIFT) { if (need_float_stack) fprintf(fout, " f_stp++;"); @@ -7656,7 +7789,7 @@ static void gen_hdr(const char *funcn, int opcnt) if (pp != NULL) { if (!(po->flags & OPF_ATAIL)) // since we know the args, try to collect them - if (collect_call_args_early(po, i, pp, ®mask_dummy) != 0) + if (collect_call_args_early(i, pp, NULL, NULL) != 0) pp = NULL; } -- 2.39.5