support __fastcall
authornotaz <notasas@gmail.com>
Sun, 19 Jan 2014 23:23:10 +0000 (01:23 +0200)
committernotaz <notasas@gmail.com>
Tue, 21 Jan 2014 01:31:05 +0000 (03:31 +0200)
standalone starts, yay, but hangs later

tools/cvt_data.c
tools/mkbridge.c
tools/protoparse.h
tools/translate.c

index 7779287..e21ff96 100644 (file)
@@ -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 {
index 705567f..2066f02 100644 (file)
@@ -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");
index 3981588..be1dca9 100644 (file)
@@ -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;
 }
 
index 9643c63..e2b6d20 100644 (file)
@@ -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)