From c0050df6e9d6eb81afacb0fa2d1910293dd2165e Mon Sep 17 00:00:00 2001 From: notaz Date: Mon, 20 Jan 2014 01:23:10 +0200 Subject: [PATCH] support __fastcall standalone starts, yay, but hangs later --- tools/cvt_data.c | 19 ++++++++++++------- tools/mkbridge.c | 19 ++++++++++++------- tools/protoparse.h | 29 ++++++++++++++++++++++------- tools/translate.c | 31 +++++++++++++++++++++---------- 4 files changed, 67 insertions(+), 31 deletions(-) diff --git a/tools/cvt_data.c b/tools/cvt_data.c index 7779287..e21ff96 100644 --- a/tools/cvt_data.c +++ b/tools/cvt_data.c @@ -255,7 +255,8 @@ static void sprint_pp_short(const struct parsed_proto *pp, char *buf, snprintf(buf + l, buf_size - l, ")"); } -static void check_var(FILE *fhdr, const char *sym, const char *varname) +static const struct parsed_proto *check_var(FILE *fhdr, + const char *sym, const char *varname) { const struct parsed_proto *pp, *pp_sym; char fp_sym[256], fp_var[256]; @@ -265,11 +266,11 @@ static void check_var(FILE *fhdr, const char *sym, const char *varname) if (pp == NULL) { if (IS_START(varname, "sub_")) awarn("sub_ sym missing proto: '%s'\n", varname); - return; + return NULL; } if (!pp->is_func && !pp->is_fptr) - return; + return NULL; sprint_pp(pp, fp_var, sizeof(fp_var)); @@ -294,7 +295,7 @@ check_sym: g_func_sym_pp = NULL; pp_sym = proto_parse(fhdr, sym, 1); if (pp_sym == NULL) - return; + return pp; if (!pp_sym->is_fptr) aerr("func ptr data, but label '%s' !is_fptr\n", pp_sym->name); g_func_sym_pp = pp_sym; @@ -302,7 +303,7 @@ check_sym: else { pp_sym = g_func_sym_pp; if (pp_sym == NULL) - return; + return pp; } if (pp->argc != pp_sym->argc || pp->argc_reg != pp_sym->argc_reg) @@ -328,6 +329,8 @@ check_sym: anote("sym: %s\n", fp_sym); awarn("^ mismatch\n"); } + + return pp; } static int cmpstringp(const void *p1, const void *p2) @@ -625,10 +628,12 @@ int main(int argc, char *argv[]) snprintf(g_comment, sizeof(g_comment), "%s", p); } else { - check_var(fhdr, sym, p); + pp = check_var(fhdr, sym, p); if (p[0] != '_') - fprintf(fout, "_"); + fprintf(fout, (pp && pp->is_fastcall) ? "@" : "_"); fprintf(fout, "%s", p); + if (pp && pp->is_stdcall && pp->argc > 0) + fprintf(fout, "@%d", pp->argc * 4); } } else { diff --git a/tools/mkbridge.c b/tools/mkbridge.c index 705567f..2066f02 100644 --- a/tools/mkbridge.c +++ b/tools/mkbridge.c @@ -41,10 +41,13 @@ static void out_toasm_x86(FILE *f, const char *sym_in, must_save |= is_x86_reg_saved(pp->arg[i].reg); } - fprintf(f, ".global _%s\n", sym_in); - fprintf(f, "_%s:\n", sym_in); + fprintf(f, ".global %s%s\n", pp->is_fastcall ? "@" : "_", sym_in); + fprintf(f, "%s%s:\n", pp->is_fastcall ? "@" : "_", sym_in); - if (pp->argc_reg == 0) { + if (pp->argc_reg == 0 || pp->is_fastcall) { + fprintf(f, "\t# %s\n", + pp->is_fastcall ? "__fastcall" : + (pp->is_stdcall ? "__stdcall" : "__cdecl")); fprintf(f, "\tjmp %s\n\n", sym_out); return; } @@ -123,15 +126,17 @@ static void out_fromasm_x86(FILE *f, const char *sym, ret64 = strstr(pp->ret_type.name, "int64") != NULL; - fprintf(f, "# %s", pp->is_stdcall ? "__stdcall" : "__cdecl"); + fprintf(f, "# %s", + pp->is_fastcall ? "__fastcall" : + (pp->is_stdcall ? "__stdcall" : "__cdecl")); if (ret64) fprintf(f, " ret64"); fprintf(f, "\n.global %s\n", sym); fprintf(f, "%s:\n", sym); - if (pp->argc_reg == 0) { - //fprintf(f, "\tjmp _%s\n\n", sym); - fprintf(f, "\tjmp _%s", sym); + if (pp->argc_reg == 0 || pp->is_fastcall) { + fprintf(f, "\tjmp %s%s", + pp->is_fastcall ? "@" : "_", sym); if (pp->is_stdcall && pp->argc > 0) fprintf(f, "@%d", pp->argc * 4); fprintf(f, "\n\n"); diff --git a/tools/protoparse.h b/tools/protoparse.h index 3981588..be1dca9 100644 --- a/tools/protoparse.h +++ b/tools/protoparse.h @@ -27,6 +27,7 @@ struct parsed_proto { int argc_reg; unsigned int is_func:1; unsigned int is_stdcall:1; + unsigned int is_fastcall:1; unsigned int is_vararg:1; unsigned int is_fptr:1; unsigned int is_noreturn:1; @@ -372,8 +373,10 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp) pp->is_stdcall = 0; else if (IS(cconv, "__stdcall")) pp->is_stdcall = 1; - else if (IS(cconv, "__fastcall")) - pp->is_stdcall = 1; + else if (IS(cconv, "__fastcall")) { + pp->is_fastcall = 1; + pp->is_stdcall = 1; // sort of.. + } else if (IS(cconv, "__thiscall")) pp->is_stdcall = 1; else if (IS(cconv, "__userpurge")) @@ -559,11 +562,6 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp) pp->arg[1].reg = strdup("edx"); } - if (pp->is_vararg && pp->is_stdcall) { - printf("%s:%d: vararg stdcall?\n", hdrfn, hdrfline); - return -1; - } - pp->argc = xarg; for (i = 0; i < pp->argc; i++) { @@ -573,6 +571,23 @@ static int parse_protostr(char *protostr, struct parsed_proto *pp) pp->argc_reg++; } + if (pp->argc == 1 && pp->arg[0].reg != NULL + && IS(pp->arg[0].reg, "ecx")) + { + pp->is_fastcall = 1; + } + else if (pp->argc_reg == 2 + && pp->arg[0].reg != NULL && IS(pp->arg[0].reg, "ecx") + && pp->arg[1].reg != NULL && IS(pp->arg[1].reg, "edx")) + { + pp->is_fastcall = 1; + } + + if (pp->is_vararg && (pp->is_stdcall || pp->is_fastcall)) { + printf("%s:%d: vararg %s?\n", hdrfn, hdrfline, cconv); + return -1; + } + return p - protostr; } diff --git a/tools/translate.c b/tools/translate.c index 9643c63..e2b6d20 100644 --- a/tools/translate.c +++ b/tools/translate.c @@ -1451,7 +1451,7 @@ static void check_func_pp(struct parsed_op *po, const struct parsed_proto *pp, const char *pfx) { if (pp->argc_reg != 0) { - if (!g_allow_regfunc) + if (!g_allow_regfunc && !pp->is_fastcall) ferr(po, "%s: reg arg in arg-call unhandled yet\n", pfx); if (pp->argc_stack > 0 && pp->argc_reg != 2) ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n", @@ -2689,6 +2689,17 @@ static void output_std_flags(FILE *fout, struct parsed_op *po, } } +static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp, + int is_noreturn) +{ + if (pp->is_fastcall) + fprintf(fout, "__fastcall "); + else if (pp->is_stdcall && pp->argc_reg == 0) + fprintf(fout, "__stdcall "); + if (pp->is_noreturn || is_noreturn) + fprintf(fout, "noreturn "); +} + static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) { struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op; @@ -2727,10 +2738,7 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) ferr(ops, "proto_parse failed for '%s'\n", funcn); fprintf(fout, "%s ", g_func_pp->ret_type.name); - if (g_func_pp->is_stdcall && g_func_pp->argc_reg == 0) - fprintf(fout, "__stdcall "); - if (g_ida_func_attr & IDAFA_NORETURN) - fprintf(fout, "noreturn "); + output_pp_attrs(fout, g_func_pp, g_ida_func_attr & IDAFA_NORETURN); fprintf(fout, "%s(", funcn); for (i = 0; i < g_func_pp->argc; i++) { @@ -2740,8 +2748,7 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt) // func pointer.. pp = g_func_pp->arg[i].fptr; fprintf(fout, "%s (", pp->ret_type.name); - if (pp->is_stdcall && pp->argc_reg == 0) - fprintf(fout, "__stdcall "); + output_pp_attrs(fout, pp, 0); fprintf(fout, "*a%d)(", i + 1); for (j = 0; j < pp->argc; j++) { if (j > 0) @@ -3213,9 +3220,10 @@ tailcall: && (regmask_stack & (1 << xDX)))) { if (pp->argc_stack != 0 - || ((regmask | regmask_arg) & (1 << xCX))) + || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX)))) { pp_insert_reg_arg(pp, "ecx"); + pp->is_fastcall = 1; regmask_init |= 1 << xCX; regmask |= 1 << xCX; } @@ -3228,6 +3236,10 @@ tailcall: } } regmask |= regmask_stack; + + // note: __cdecl doesn't fall into is_unresolved category + if (pp->argc_stack > 0) + pp->is_stdcall = 1; } for (arg = 0; arg < pp->argc; arg++) { @@ -3265,8 +3277,7 @@ tailcall: snprintf(pp->name, sizeof(pp->name), "icall%d", i); fprintf(fout, " %s (", pp->ret_type.name); - if (pp->is_stdcall && pp->argc_reg == 0) - fprintf(fout, "__stdcall "); + output_pp_attrs(fout, pp, 0); fprintf(fout, "*%s)(", pp->name); for (j = 0; j < pp->argc; j++) { if (j > 0) -- 2.39.2