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];
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));
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;
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)
anote("sym: %s\n", fp_sym);
awarn("^ mismatch\n");
}
+
+ return pp;
}
static int cmpstringp(const void *p1, const void *p2)
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 {
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;
}
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");
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;
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"))
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++) {
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;
}
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",
}
}
+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;
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++) {
// 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)
&& (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;
}
}
}
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++) {
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)