X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=tools%2Ftranslate.c;h=a83c6bd1fa2201425bbd9eec203d2bc2b4d47b05;hb=4d247254d0230ce39aa03fda44fc54ec0aa02be2;hp=a55e6d174d6e723dcede52b3539bf1ad80d67864;hpb=4c20744d669982153209773e206c7a1f4ff28689;p=ia32rtools.git diff --git a/tools/translate.c b/tools/translate.c index a55e6d1..a83c6bd 100644 --- a/tools/translate.c +++ b/tools/translate.c @@ -249,6 +249,10 @@ enum ida_func_attr { IDAFA_FPD = (1 << 5), }; +enum sct_func_attr { + SCTFA_CLEAR_SF = (1 << 0), // clear stack frame +}; + enum x87_const { X87_CONST_1 = 1, X87_CONST_2T, @@ -279,6 +283,9 @@ static int g_sp_frame; static int g_stack_frame_used; static int g_stack_fsz; static int g_ida_func_attr; +static int g_sct_func_attr; +static int g_stack_clear_start; // in dwords +static int g_stack_clear_len; static int g_skip_func; static int g_allow_regfunc; static int g_quiet_pp; @@ -3451,17 +3458,31 @@ static int get_pp_arg_regmask_src(const struct parsed_proto *pp) static int get_pp_arg_regmask_dst(const struct parsed_proto *pp) { + int regmask = 0; + int i, reg; + + if (pp->has_retreg) { + for (i = 0; i < pp->argc; i++) { + if (pp->arg[i].type.is_retreg) { + reg = char_array_i(regs_r32, + ARRAY_SIZE(regs_r32), pp->arg[i].reg); + ferr_assert(ops, reg >= 0); + regmask |= 1 << reg; + } + } + } + if (strstr(pp->ret_type.name, "int64")) - return (1 << xAX) | (1 << xDX); + return regmask | (1 << xAX) | (1 << xDX); if (IS(pp->ret_type.name, "float") || IS(pp->ret_type.name, "double")) { - return mxST0; + return regmask | mxST0; } if (strcasecmp(pp->ret_type.name, "void") == 0) - return 0; + return regmask; - return mxAX; + return regmask | mxAX; } static void resolve_branches_parse_calls(int opcnt) @@ -4794,7 +4815,10 @@ static void reg_use_pass(int i, int opcnt, unsigned char *cbits, if (po->flags & OPF_TAIL) { if (regmask_now & (mxST0 | mxST1)) ferr(po, "float regs on tail: %x\n", regmask_now); - return; + + // there is support for "conditional tailcall", sort of + if (!(po->flags & OPF_CC)) + return; } } } @@ -4949,17 +4973,6 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) regmask_arg = get_pp_arg_regmask_src(g_func_pp); regmask_ret = get_pp_arg_regmask_dst(g_func_pp); - if (g_func_pp->has_retreg) { - for (arg = 0; arg < g_func_pp->argc; arg++) { - if (g_func_pp->arg[arg].type.is_retreg) { - reg = char_array_i(regs_r32, - ARRAY_SIZE(regs_r32), g_func_pp->arg[arg].reg); - ferr_assert(ops, reg >= 0); - regmask_ret |= 1 << reg; - } - } - } - // pass1: // - resolve all branches // - parse calls with labels @@ -5475,6 +5488,24 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) if (had_decl) fprintf(fout, "\n"); + // do stack clear, if needed + if (g_sct_func_attr & SCTFA_CLEAR_SF) { + fprintf(fout, " "); + if (g_stack_clear_len != 0) { + if (g_stack_clear_len <= 4) { + for (i = 0; i < g_stack_clear_len; i++) + fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i); + fprintf(fout, "0;\n"); + } + else { + fprintf(fout, "memset(&sf[%d], 0, %d);\n", + g_stack_clear_start, g_stack_clear_len * 4); + } + } + else + fprintf(fout, "memset(&sf, 0, sizeof(sf));\n"); + } + if (g_func_pp->is_vararg) { if (g_func_pp->argc_stack == 0) ferr(ops, "vararg func without stack args?\n"); @@ -7872,6 +7903,40 @@ int main(int argc, char *argv[]) } } } + else if (p[2] == 's' && IS_START(p, "; sctattr:")) + { + static const char *attrs[] = { + "clear_sf", + }; + + // parse manual attribute-list comment + g_sct_func_attr = 0; + p = sskip(p + 10); + + for (; *p != 0; p = sskip(p)) { + for (i = 0; i < ARRAY_SIZE(attrs); i++) { + if (!strncmp(p, attrs[i], strlen(attrs[i]))) { + g_sct_func_attr |= 1 << i; + p += strlen(attrs[i]); + break; + } + } + if (i == 0 && *p == '=') { + // clear_sf=start,len (in dwords) + ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start, + &g_stack_clear_len, &j); + if (ret < 2) { + anote("unparsed clear_sf attr value: %s\n", p); + break; + } + p += j; + } + else if (i == ARRAY_SIZE(attrs)) { + anote("unparsed sct attr: %s\n", p); + break; + } + } + } else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR ")) { p += 30; @@ -8040,6 +8105,9 @@ do_pending_endp: pending_endp = 0; in_func = 0; g_ida_func_attr = 0; + g_sct_func_attr = 0; + g_stack_clear_start = 0; + g_stack_clear_len = 0; skip_warned = 0; g_skip_func = 0; g_func[0] = 0;