translate: add ref hint, document others
[ia32rtools.git] / tools / translate.c
index e7fd5c7..5e810a9 100644 (file)
@@ -4,6 +4,15 @@
  *
  * This work is licensed under the terms of 3-clause BSD license.
  * See COPYING file in the top-level directory.
+ *
+ * recognized asm hint comments:
+ * sctattr - function attributes (see code)
+ * sctend  - force end of function/chunk
+ * sctpatch: <p> - replace current asm line with <p>
+ * sctproto: <p> - prototype of ref'd function or struct
+ * sctref  - variable is referenced, make global
+ * sctskip_start - start of skipped code chunk (inclusive)
+ * sctskip_end   - end of skipped code chunk (inclusive)
  */
 
 #define _GNU_SOURCE
@@ -157,6 +166,7 @@ enum op_op {
   OPP_ALLSHR,
   OPP_FTOL,
   OPP_CIPOW,
+  OPP_ABORT,
   // undefined
   OP_UD2,
 };
@@ -620,6 +630,9 @@ static int guess_lmod_from_name(struct parsed_opr *opr)
 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
   const struct parsed_type *c_type)
 {
+  static const char *qword_types[] = {
+    "uint64_t", "int64_t", "__int64",
+  };
   static const char *dword_types[] = {
     "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
     "WPARAM", "LPARAM", "UINT", "__int32",
@@ -668,6 +681,13 @@ static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
     }
   }
 
+  for (i = 0; i < ARRAY_SIZE(qword_types); i++) {
+    if (IS(n, qword_types[i])) {
+      *lmod = OPLM_QWORD;
+      return 1;
+    }
+  }
+
   return 0;
 }
 
@@ -1724,14 +1744,12 @@ static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
   *extra_offs = 0;
   namelen = strlen(name);
 
-  p = strchr(name, '+');
+  p = strpbrk(name, "+-");
   if (p != NULL) {
     namelen = p - name;
     if (namelen <= 0)
       ferr(po, "equ parse failed for '%s'\n", name);
 
-    if (IS_START(p, "0x"))
-      p += 2;
     *extra_offs = strtol(p, &endp, 16);
     if (*endp != 0)
       ferr(po, "equ parse failed for '%s'\n", name);
@@ -1856,7 +1874,6 @@ static int stack_frame_access(struct parsed_op *po,
   int offset = 0;
   int retval = -1;
   int sf_ofs;
-  int lim;
 
   if (po->flags & OPF_EBP_S)
     ferr(po, "stack_frame_access while ebp is scratch\n");
@@ -1987,8 +2004,7 @@ static int stack_frame_access(struct parsed_op *po,
     g_stack_frame_used = 1;
 
     sf_ofs = g_stack_fsz + offset;
-    lim = (ofs_reg[0] != 0) ? -4 : 0;
-    if (offset > 0 || sf_ofs < lim)
+    if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
       ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
 
     if (is_lea)
@@ -2310,7 +2326,7 @@ static char *out_src_opr_float(char *buf, size_t buf_size,
       break;
     }
     out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
-    snprintf(buf, buf_size, "*((%s *)%s)", cast, tmp);
+    snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
     break;
 
   default:
@@ -5586,6 +5602,8 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
   reg_use_pass(0, opcnt, cbits, regmask_init, &regmask,
     0, &regmask_save, &regmask_init, regmask_arg);
 
+  need_float_stack = !!(regmask & mxST7_2);
+
   // pass7:
   // - find flag set ops for their users
   // - do unresolved calls
@@ -5793,10 +5811,13 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
     // this might need it's own pass...
     if (po->op != OP_FST && po->p_argnum > 0)
       save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
+
+    // correct for "full stack" mode late enable
+    if ((po->flags & (OPF_PPUSH|OPF_FPOP)) && need_float_stack)
+      po->flags |= OPF_FSHIFT;
   }
 
   float_type = need_double ? "double" : "float";
-  need_float_stack = !!(regmask & mxST7_2);
   float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
   float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
 
@@ -7446,9 +7467,13 @@ static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
         strcat(g_comment, " CIpow");
         break;
 
+      case OPP_ABORT:
+        fprintf(fout, "  do_skip_code_abort();");
+        break;
+
       // mmx
       case OP_EMMS:
-        strcpy(g_comment, " (emms)");
+        fprintf(fout, "  do_emms();");
         break;
 
       default:
@@ -7942,7 +7967,7 @@ static void gen_hdr(const char *funcn, int opcnt)
       // noreturn OS functions
       break;
     }
-    if (ops[i].op != OP_NOP)
+    if (ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
       ferr(&ops[i], "unreachable code\n");
   }
 
@@ -8270,10 +8295,14 @@ static int ida_xrefs_show_need(FILE *fasm, char *p,
   long pos;
 
   p = strrchr(p, ';');
-  if (p != NULL && *p == ';' && IS_START(p + 2, "DATA XREF: ")) {
-    p += 13;
-    if (is_xref_needed(p, rlist, rlist_len))
+  if (p != NULL && *p == ';') {
+    if (IS_START(p + 2, "sctref"))
       return 1;
+    if (IS_START(p + 2, "DATA XREF: ")) {
+      p += 13;
+      if (is_xref_needed(p, rlist, rlist_len))
+        return 1;
+    }
   }
 
   pos = ftell(fasm);
@@ -8292,6 +8321,12 @@ static int ida_xrefs_show_need(FILE *fasm, char *p,
 
     p = strrchr(p, ';');
     p += 2;
+
+    if (IS_START(p, "sctref")) {
+      found_need = 1;
+      break;
+    }
+
     // it's printed once, but no harm to check again
     if (IS_START(p, "DATA XREF: "))
       p += 11;
@@ -8485,7 +8520,7 @@ static int cmp_chunks(const void *p1, const void *p2)
   return strcmp(c1->name, c2->name);
 }
 
-static void scan_ahead(FILE *fasm)
+static void scan_ahead_for_chunks(FILE *fasm)
 {
   char words[2][256];
   char line[256];
@@ -8566,7 +8601,8 @@ int main(int argc, char *argv[])
   char *sctproto = NULL;
   int in_func = 0;
   int pending_endp = 0;
-  int skip_func = 0;
+  int skip_code = 0;
+  int skip_code_end = 0;
   int skip_warned = 0;
   int eq_alloc;
   int verbose = 0;
@@ -8632,6 +8668,8 @@ int main(int argc, char *argv[])
   memset(words, 0, sizeof(words));
 
   for (; arg < argc; arg++) {
+    int skip_func = 0;
+
     frlist = fopen(argv[arg], "r");
     my_assert_not(frlist, NULL);
 
@@ -8663,7 +8701,6 @@ int main(int argc, char *argv[])
       }
       rlist[rlist_len++] = strdup(words[0]);
     }
-    skip_func = 0;
 
     fclose(frlist);
     frlist = NULL;
@@ -8824,7 +8861,7 @@ int main(int argc, char *argv[])
           if (addr > f_addr && !scanned_ahead) {
             //anote("scan_ahead caused by '%s', addr %lx\n",
             //  g_func, addr);
-            scan_ahead(fasm);
+            scan_ahead_for_chunks(fasm);
             scanned_ahead = 1;
             func_chunks_sorted = 0;
           }
@@ -8846,7 +8883,12 @@ parse_words:
     if (*p != 0 && *p != ';')
       aerr("too many words\n");
 
-    // alow asm patches in comments
+    if (skip_code_end) {
+      skip_code_end = 0;
+      skip_code = 0;
+    }
+
+    // allow asm patches in comments
     if (*p == ';') {
       if (IS_START(p, "; sctpatch:")) {
         p = sskip(p + 11);
@@ -8862,6 +8904,20 @@ parse_words:
         if (!pending_endp)
           break;
       }
+      else if (IS_START(p, "; sctskip_start")) {
+        if (in_func && !g_skip_func) {
+          if (!skip_code) {
+            ops[pi].op = OPP_ABORT;
+            ops[pi].asmln = asmln;
+            pi++;
+          }
+          skip_code = 1;
+        }
+      }
+      else if (IS_START(p, "; sctskip_end")) {
+        if (skip_code)
+          skip_code_end = 1;
+      }
     }
 
     if (wordc == 0) {
@@ -9001,6 +9057,8 @@ do_pending_endp:
       if (!IS(g_func, words[0]))
         aerr("endp '%s' while in_func '%s'?\n",
           words[0], g_func);
+      if (skip_code)
+        aerr("endp '%s' while skipping code\n", words[0]);
 
       if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
         && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
@@ -9068,7 +9126,7 @@ do_pending_endp:
       continue;
     }
 
-    if (!in_func || g_skip_func) {
+    if (!in_func || g_skip_func || skip_code) {
       if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
         if (verbose)
           anote("skipping from '%s'\n", g_labels[pi]);