jumptables, stack iterators, more prototypes, disasm fixes
[ia32rtools.git] / tools / translate.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include "my_assert.h"
7 #include "my_str.h"
8
9 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
10 #define IS(w, y) !strcmp(w, y)
11 #define IS_START(w, y) !strncmp(w, y, strlen(y))
12
13 #include "protoparse.h"
14
15 static const char *asmfn;
16 static int asmln;
17 static FILE *g_fhdr;
18
19 #define anote(fmt, ...) \
20         printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
21 #define awarn(fmt, ...) \
22         printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
23 #define aerr(fmt, ...) do { \
24         printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
25   fcloseall(); \
26         exit(1); \
27 } while (0)
28
29 enum op_flags {
30   OPF_RMD    = (1 << 0), /* removed or optimized out */
31   OPF_DATA   = (1 << 1), /* data processing - writes to dst opr */
32   OPF_FLAGS  = (1 << 2), /* sets flags */
33   OPF_JMP    = (1 << 3), /* branches, ret and call */
34   OPF_CC     = (1 << 4), /* uses flags */
35   OPF_TAIL   = (1 << 5), /* ret or tail call */
36   OPF_REP    = (1 << 6), /* prefixed by rep */
37   OPF_RSAVE  = (1 << 7), /* push/pop is local reg save/load */
38 };
39
40 enum op_op {
41         OP_INVAL,
42         OP_NOP,
43         OP_PUSH,
44         OP_POP,
45         OP_MOV,
46         OP_LEA,
47         OP_MOVZX,
48         OP_MOVSX,
49         OP_NOT,
50         OP_CDQ,
51         OP_STOS,
52         OP_MOVS,
53         OP_RET,
54         OP_ADD,
55         OP_SUB,
56         OP_AND,
57         OP_OR,
58         OP_XOR,
59         OP_SHL,
60         OP_SHR,
61         OP_SAR,
62         OP_ROL,
63         OP_ROR,
64         OP_ADC,
65         OP_SBB,
66         OP_INC,
67         OP_DEC,
68         OP_NEG,
69         OP_MUL,
70         OP_IMUL,
71         OP_DIV,
72         OP_IDIV,
73         OP_TEST,
74         OP_CMP,
75         OP_CALL,
76         OP_JMP,
77         OP_JO,
78         OP_JNO,
79         OP_JC,
80         OP_JNC,
81         OP_JZ,
82         OP_JNZ,
83         OP_JBE,
84         OP_JA,
85         OP_JS,
86         OP_JNS,
87         OP_JP,
88         OP_JNP,
89         OP_JL,
90         OP_JGE,
91         OP_JLE,
92         OP_JG,
93 };
94
95 enum opr_type {
96   OPT_UNSPEC,
97   OPT_REG,
98   OPT_REGMEM,
99   OPT_LABEL,
100   OPT_OFFSET,
101   OPT_CONST,
102 };
103
104 enum opr_lenmod {
105         OPLM_UNSPEC,
106         OPLM_BYTE,
107         OPLM_WORD,
108         OPLM_DWORD,
109 };
110
111 #define MAX_OPERANDS 3
112
113 struct parsed_opr {
114   enum opr_type type;
115   enum opr_lenmod lmod;
116   unsigned int is_ptr:1;  // pointer in C
117   int reg;
118   unsigned int val;
119   char name[256];
120 };
121
122 struct parsed_op {
123   enum op_op op;
124   struct parsed_opr operand[MAX_OPERANDS];
125   unsigned int flags;
126   int operand_cnt;
127   int regmask_src;        // all referensed regs
128   int regmask_dst;
129   int pfomask;            // flagop: parsed_flag_op that can't be delayed
130   int argmask;            // push: args that are altered before call
131   int cc_scratch;         // scratch storage during analysis
132   int bt_i;               // branch target for branches
133   struct parsed_data *btj;// branch targets for jumptables
134   void *datap;
135 };
136
137 // datap:
138 // OP_CALL - ptr to parsed_proto
139 // (OPF_CC) - point to corresponding (OPF_FLAGS)
140
141 struct parsed_equ {
142   char name[64];
143   enum opr_lenmod lmod;
144   int offset;
145 };
146
147 struct parsed_data {
148   char label[256];
149   enum opr_type type;
150   enum opr_lenmod lmod;
151   int count;
152   int count_alloc;
153   struct {
154     union {
155       char *label;
156       int val;
157     } u;
158     int bt_i;
159   } *d;
160 };
161
162 struct label_ref {
163   int i;
164   struct label_ref *next;
165 };
166
167 enum ida_func_attr {
168   IDAFA_BP_FRAME = (1 << 0),
169   IDAFA_LIB_FUNC = (1 << 1),
170   IDAFA_STATIC   = (1 << 2),
171   IDAFA_NORETURN = (1 << 3),
172   IDAFA_THUNK    = (1 << 4),
173   IDAFA_FPD      = (1 << 5),
174 };
175
176 #define MAX_OPS 4096
177
178 static struct parsed_op ops[MAX_OPS];
179 static struct parsed_equ *g_eqs;
180 static int g_eqcnt;
181 static char g_labels[MAX_OPS][32];
182 static struct label_ref g_label_refs[MAX_OPS];
183 static struct parsed_proto g_func_pp;
184 static struct parsed_data *g_func_pd;
185 static int g_func_pd_cnt;
186 static char g_func[256];
187 static char g_comment[256];
188 static int g_bp_frame;
189 static int g_sp_frame;
190 static int g_stack_fsz;
191 static int g_ida_func_attr;
192 #define ferr(op_, fmt, ...) do { \
193   printf("error:%s:#%ld: '%s': " fmt, g_func, (op_) - ops, \
194     dump_op(op_), ##__VA_ARGS__); \
195   fcloseall(); \
196   exit(1); \
197 } while (0)
198
199 #define MAX_REGS 8
200
201 const char *regs_r32[] = { "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp" };
202 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
203 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
204 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
205
206 enum x86_regs { xUNSPEC = -1, xAX, xBX, xCX, xDX, xSI, xDI, xBP, xSP };
207
208 // possible basic comparison types (without inversion)
209 enum parsed_flag_op {
210   PFO_O,  // 0 OF=1
211   PFO_C,  // 2 CF=1
212   PFO_Z,  // 4 ZF=1
213   PFO_BE, // 6 CF=1||ZF=1
214   PFO_S,  // 8 SF=1
215   PFO_P,  // a PF=1
216   PFO_L,  // c SF!=OF
217   PFO_LE, // e ZF=1||SF!=OF
218 };
219
220 static const char *parsed_flag_op_names[] = {
221   "o", "c", "z", "be", "s", "p", "l", "le"
222 };
223
224 static int char_array_i(const char *array[], size_t len, const char *s)
225 {
226   int i;
227
228   for (i = 0; i < len; i++)
229     if (IS(s, array[i]))
230       return i;
231
232   return -1;
233 }
234
235 static void printf_number(char *buf, size_t buf_size, long number)
236 {
237   // output in C-friendly form
238   snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
239 }
240
241 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
242 {
243   int reg;
244
245   reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
246   if (reg >= 0) {
247     *reg_lmod = OPLM_DWORD;
248     return reg;
249   }
250   reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
251   if (reg >= 0) {
252     *reg_lmod = OPLM_WORD;
253     return reg;
254   }
255   reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
256   if (reg >= 0) {
257     *reg_lmod = OPLM_BYTE;
258     return reg;
259   }
260   reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
261   if (reg >= 0) {
262     *reg_lmod = OPLM_BYTE;
263     return reg;
264   }
265
266   return -1;
267 }
268
269 static long parse_number(const char *number)
270 {
271   int len = strlen(number);
272   const char *p = number;
273   char *endp = NULL;
274   int neg = 0;
275   int bad;
276   long ret;
277
278   if (*p == '-') {
279     neg = 1;
280     p++;
281   }
282   if (len > 1 && *p == '0')
283     p++;
284   if (number[len - 1] == 'h') {
285     ret = strtol(p, &endp, 16);
286     bad = (*endp != 'h');
287   }
288   else {
289     ret = strtol(p, &endp, 10);
290     bad = (*endp != 0);
291   }
292   if (bad)
293     aerr("number parsing failed\n");
294   if (neg)
295     ret = -ret;
296   return ret;
297 }
298
299 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
300 {
301   enum opr_lenmod lmod;
302   char cvtbuf[256];
303   char *d = cvtbuf;
304   char *s = name;
305   char w[64];
306   long number;
307   int reg;
308   int c = 0;
309
310   *d = 0;
311
312   while (*s != 0) {
313     d += strlen(d);
314     while (my_isblank(*s))
315       s++;
316     for (; my_issep(*s); d++, s++)
317       *d = *s;
318     while (my_isblank(*s))
319       s++;
320     *d = 0;
321
322     // skip 'ds:' prefix
323     if (IS_START(s, "ds:"))
324       s += 3;
325
326     s = next_idt(w, sizeof(w), s);
327     if (w[0] == 0)
328       break;
329     c++;
330
331     reg = parse_reg(&lmod, w);
332     if (reg >= 0) {
333       *regmask |= 1 << reg;
334       goto pass;
335     }
336
337     if ('0' <= w[0] && w[0] <= '9') {
338       number = parse_number(w);
339       printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
340       continue;
341     }
342
343     // probably some label/identifier - pass
344
345 pass:
346     snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
347   }
348
349   if (need_c_cvt)
350     strcpy(name, cvtbuf);
351
352   return c;
353 }
354
355 static int is_reg_in_str(const char *s)
356 {
357   int i;
358
359   if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
360     return 0;
361
362   for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
363     if (!strncmp(s, regs_r32[i], 3))
364       return 1;
365
366   return 0;
367 }
368
369 static const char *parse_stack_el(const char *name, char *extra_reg)
370 {
371   const char *p, *p2, *s;
372   char *endp = NULL;
373   char buf[32];
374   long val;
375   int len;
376
377   p = name;
378   if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
379     p += 4;
380     if (extra_reg != NULL) {
381       strncpy(extra_reg, name, 3);
382       extra_reg[4] = 0;
383     }
384   }
385
386   if (IS_START(p, "ebp+")) {
387     p += 4;
388
389     p2 = strchr(p, '+');
390     if (p2 != NULL && is_reg_in_str(p)) {
391       if (extra_reg != NULL) {
392         strncpy(extra_reg, p, p2 - p);
393         extra_reg[p2 - p] = 0;
394       }
395       p = p2 + 1;
396     }
397
398     if (!('0' <= *p && *p <= '9'))
399       return p;
400
401     return NULL;
402   }
403
404   if (!IS_START(name, "esp+"))
405     return NULL;
406
407   p = strchr(name + 4, '+');
408   if (p) {
409     // must be a number after esp+, already converted to 0x..
410     s = name + 4;
411     if (!('0' <= *s && *s <= '9')) {
412                   aerr("%s nan?\n", __func__);
413       return NULL;
414     }
415     if (s[0] == '0' && s[1] == 'x')
416       s += 2;
417     len = p - s;
418     if (len < sizeof(buf) - 1) {
419       strncpy(buf, s, len);
420       buf[len] = 0;
421       val = strtol(buf, &endp, 16);
422       if (val == 0 || *endp != 0) {
423         aerr("%s num parse fail for '%s'\n", __func__, buf);
424         return NULL;
425       }
426     }
427     p++;
428   }
429   else
430     p = name + 4;
431
432   if ('0' <= *p && *p <= '9')
433     return NULL;
434
435   return p;
436 }
437
438 static int guess_lmod_from_name(struct parsed_opr *opr)
439 {
440   if (!strncmp(opr->name, "dword_", 6)) {
441     opr->lmod = OPLM_DWORD;
442     return 1;
443   }
444   if (!strncmp(opr->name, "word_", 5)) {
445     opr->lmod = OPLM_WORD;
446     return 1;
447   }
448   if (!strncmp(opr->name, "byte_", 5)) {
449     opr->lmod = OPLM_BYTE;
450     return 1;
451   }
452   return 0;
453 }
454
455 static int guess_lmod_from_c_type(struct parsed_opr *opr, const char *c_type)
456 {
457   static const char *ptr_types[] = {
458     "LPCSTR",
459   };
460   static const char *dword_types[] = {
461     "int", "_DWORD", "DWORD", "HANDLE", "HWND", "HMODULE",
462   };
463   static const char *word_types[] = {
464     "__int16", "unsigned __int16",
465   };
466   static const char *byte_types[] = {
467     "char", "__int8", "unsigned __int8", "BYTE",
468   };
469   int i;
470
471   if (strchr(c_type, '*')) {
472     opr->lmod = OPLM_DWORD;
473     opr->is_ptr = 1;
474     return 1;
475   }
476
477   for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
478     if (IS(c_type, dword_types[i])) {
479       opr->lmod = OPLM_DWORD;
480       return 1;
481     }
482   }
483
484   for (i = 0; i < ARRAY_SIZE(ptr_types); i++) {
485     if (IS(c_type, ptr_types[i])) {
486       opr->lmod = OPLM_DWORD;
487       opr->is_ptr = 1;
488       return 1;
489     }
490   }
491
492   for (i = 0; i < ARRAY_SIZE(word_types); i++) {
493     if (IS(c_type, word_types[i])) {
494       opr->lmod = OPLM_WORD;
495       return 1;
496     }
497   }
498
499   for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
500     if (IS(c_type, byte_types[i])) {
501       opr->lmod = OPLM_BYTE;
502       return 1;
503     }
504   }
505
506   anote("unhandled C type '%s' for '%s'\n", c_type, opr->name);
507   return 0;
508 }
509
510 static enum opr_type lmod_from_directive(const char *d)
511 {
512   if (IS(d, "dd"))
513     return OPLM_DWORD;
514   else if (IS(d, "dw"))
515     return OPLM_WORD;
516   else if (IS(d, "db"))
517     return OPLM_BYTE;
518
519   aerr("unhandled directive: '%s'\n", d);
520   return OPLM_UNSPEC;
521 }
522
523 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
524   int *regmask)
525 {
526   opr->type = OPT_REG;
527   opr->reg = reg;
528   opr->lmod = lmod;
529   *regmask |= 1 << reg;
530 }
531
532 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
533   int *extra_offs);
534
535 static int parse_operand(struct parsed_opr *opr,
536   int *regmask, int *regmask_indirect,
537   char words[16][256], int wordc, int w, unsigned int op_flags)
538 {
539   struct parsed_proto pp;
540   enum opr_lenmod tmplmod;
541   int ret, len;
542   long number;
543   int wordc_in;
544   char *tmp;
545   int i;
546
547   if (w >= wordc)
548     aerr("parse_operand w %d, wordc %d\n", w, wordc);
549
550   opr->reg = xUNSPEC;
551
552   for (i = w; i < wordc; i++) {
553     len = strlen(words[i]);
554     if (words[i][len - 1] == ',') {
555       words[i][len - 1] = 0;
556       wordc = i + 1;
557       break;
558     }
559   }
560
561   wordc_in = wordc - w;
562
563   if ((op_flags & OPF_JMP) && wordc_in > 0
564       && !('0' <= words[w][0] && words[w][0] <= '9'))
565   {
566     const char *label = NULL;
567
568     if (wordc_in == 3 && !strncmp(words[w], "near", 4)
569      && IS(words[w + 1], "ptr"))
570       label = words[w + 2];
571     else if (wordc_in == 2 && IS(words[w], "short"))
572       label = words[w + 1];
573     else if (wordc_in == 1
574           && strchr(words[w], '[') == NULL
575           && parse_reg(&tmplmod, words[w]) < 0)
576       label = words[w];
577
578     if (label != NULL) {
579       opr->type = OPT_LABEL;
580       if (IS_START(label, "ds:"))
581         label += 3;
582       strcpy(opr->name, label);
583       return wordc;
584     }
585   }
586
587   if (wordc_in >= 3) {
588     if (IS(words[w + 1], "ptr")) {
589       if (IS(words[w], "dword"))
590         opr->lmod = OPLM_DWORD;
591       else if (IS(words[w], "word"))
592         opr->lmod = OPLM_WORD;
593       else if (IS(words[w], "byte"))
594         opr->lmod = OPLM_BYTE;
595       else
596         aerr("type parsing failed\n");
597       w += 2;
598       wordc_in = wordc - w;
599     }
600   }
601
602   if (wordc_in == 2) {
603     if (IS(words[w], "offset")) {
604       opr->type = OPT_OFFSET;
605       strcpy(opr->name, words[w + 1]);
606       return wordc;
607     }
608     if (IS(words[w], "(offset")) {
609       char *p = strchr(words[w + 1], ')');
610       if (p == NULL)
611         aerr("parse of bracketed offset failed\n");
612       *p = 0;
613       opr->type = OPT_OFFSET;
614       strcpy(opr->name, words[w + 1]);
615       return wordc;
616     }
617   }
618
619   if (wordc_in != 1)
620     aerr("parse_operand 1 word expected\n");
621
622   tmp = words[w];
623   if (IS_START(tmp, "ds:"))
624     tmp += 3;
625   strcpy(opr->name, tmp);
626
627   if (words[w][0] == '[') {
628     opr->type = OPT_REGMEM;
629     ret = sscanf(words[w], "[%[^]]]", opr->name);
630     if (ret != 1)
631       aerr("[] parse failure\n");
632
633     parse_indmode(opr->name, regmask_indirect, 1);
634     if (opr->lmod == OPLM_UNSPEC && parse_stack_el(opr->name, NULL)) {
635       // might be an equ
636       struct parsed_equ *eq =
637         equ_find(NULL, parse_stack_el(opr->name, NULL), &i);
638       if (eq)
639         opr->lmod = eq->lmod;
640     }
641     return wordc;
642   }
643   else if (strchr(words[w], '[')) {
644     // label[reg] form
645     opr->type = OPT_REGMEM;
646     if (opr->lmod == OPLM_UNSPEC)
647       guess_lmod_from_name(opr);
648     parse_indmode(strchr(words[w], '['), regmask_indirect, 0);
649     return wordc;
650   }
651   else if (('0' <= words[w][0] && words[w][0] <= '9')
652     || words[w][0] == '-')
653   {
654     number = parse_number(words[w]);
655     opr->type = OPT_CONST;
656     opr->val = number;
657     printf_number(opr->name, sizeof(opr->name), number);
658     return wordc;
659   }
660
661   ret = parse_reg(&tmplmod, opr->name);
662   if (ret >= 0) {
663     setup_reg_opr(opr, ret, tmplmod, regmask);
664     return wordc;
665   }
666
667   // most likely var in data segment
668   opr->type = OPT_LABEL;
669
670   ret = proto_parse(g_fhdr, opr->name, &pp);
671   if (ret == 0) {
672     if (pp.is_fptr) {
673       opr->lmod = OPLM_DWORD;
674       opr->is_ptr = 1;
675     }
676     else if (opr->lmod == OPLM_UNSPEC)
677       guess_lmod_from_c_type(opr, pp.ret_type);
678   }
679   proto_release(&pp);
680
681   if (opr->lmod == OPLM_UNSPEC)
682     guess_lmod_from_name(opr);
683   return wordc;
684 }
685
686 static const struct {
687   const char *name;
688   unsigned int flags;
689 } pref_table[] = {
690   { "rep",    OPF_REP },
691 };
692
693 static const struct {
694   const char *name;
695   enum op_op op;
696   unsigned int minopr;
697   unsigned int maxopr;
698   unsigned int flags;
699 } op_table[] = {
700   { "nop",  OP_NOP,    0, 0, 0 },
701   { "push", OP_PUSH,   1, 1, 0 },
702   { "pop",  OP_POP,    1, 1, OPF_DATA },
703   { "mov" , OP_MOV,    2, 2, OPF_DATA },
704   { "lea",  OP_LEA,    2, 2, OPF_DATA },
705   { "movzx",OP_MOVZX,  2, 2, OPF_DATA },
706   { "movsx",OP_MOVSX,  2, 2, OPF_DATA },
707   { "not",  OP_NOT,    1, 1, OPF_DATA },
708   { "cdq",  OP_CDQ,    0, 0, OPF_DATA },
709   { "stosb",OP_STOS,   0, 0, OPF_DATA },
710   { "stosw",OP_STOS,   0, 0, OPF_DATA },
711   { "stosd",OP_STOS,   0, 0, OPF_DATA },
712   { "movsb",OP_MOVS,   0, 0, OPF_DATA },
713   { "movsw",OP_MOVS,   0, 0, OPF_DATA },
714   { "movsd",OP_MOVS,   0, 0, OPF_DATA },
715   { "add",  OP_ADD,    2, 2, OPF_DATA|OPF_FLAGS },
716   { "sub",  OP_SUB,    2, 2, OPF_DATA|OPF_FLAGS },
717   { "and",  OP_AND,    2, 2, OPF_DATA|OPF_FLAGS },
718   { "or",   OP_OR,     2, 2, OPF_DATA|OPF_FLAGS },
719   { "xor",  OP_XOR,    2, 2, OPF_DATA|OPF_FLAGS },
720   { "shl",  OP_SHL,    2, 2, OPF_DATA|OPF_FLAGS },
721   { "shr",  OP_SHR,    2, 2, OPF_DATA|OPF_FLAGS },
722   { "sal",  OP_SHL,    2, 2, OPF_DATA|OPF_FLAGS },
723   { "sar",  OP_SAR,    2, 2, OPF_DATA|OPF_FLAGS },
724   { "rol",  OP_ROL,    2, 2, OPF_DATA|OPF_FLAGS },
725   { "ror",  OP_ROR,    2, 2, OPF_DATA|OPF_FLAGS },
726   { "adc",  OP_ADC,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
727   { "sbb",  OP_SBB,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
728   { "inc",  OP_INC,    1, 1, OPF_DATA|OPF_FLAGS },
729   { "dec",  OP_DEC,    1, 1, OPF_DATA|OPF_FLAGS },
730   { "neg",  OP_NEG,    1, 1, OPF_DATA|OPF_FLAGS },
731   { "mul",  OP_MUL,    1, 1, OPF_DATA|OPF_FLAGS },
732   { "imul", OP_IMUL,   1, 3, OPF_DATA|OPF_FLAGS },
733   { "div",  OP_DIV,    1, 1, OPF_DATA|OPF_FLAGS },
734   { "idiv", OP_IDIV,   1, 1, OPF_DATA|OPF_FLAGS },
735   { "test", OP_TEST,   2, 2, OPF_FLAGS },
736   { "cmp",  OP_CMP,    2, 2, OPF_FLAGS },
737   { "retn", OP_RET,    0, 1, OPF_JMP|OPF_TAIL },
738   { "call", OP_CALL,   1, 1, OPF_JMP|OPF_FLAGS },
739   { "jmp",  OP_JMP,    1, 1, OPF_JMP },
740   { "jo",   OP_JO,     1, 1, OPF_JMP|OPF_CC }, // 70 OF=1
741   { "jno",  OP_JNO,    1, 1, OPF_JMP|OPF_CC }, // 71 OF=0
742   { "jc",   OP_JC,     1, 1, OPF_JMP|OPF_CC }, // 72 CF=1
743   { "jb",   OP_JC,     1, 1, OPF_JMP|OPF_CC }, // 72
744   { "jnc",  OP_JNC,    1, 1, OPF_JMP|OPF_CC }, // 73 CF=0
745   { "jnb",  OP_JNC,    1, 1, OPF_JMP|OPF_CC }, // 73
746   { "jae",  OP_JNC,    1, 1, OPF_JMP|OPF_CC }, // 73
747   { "jz",   OP_JZ,     1, 1, OPF_JMP|OPF_CC }, // 74 ZF=1
748   { "je",   OP_JZ,     1, 1, OPF_JMP|OPF_CC }, // 74
749   { "jnz",  OP_JNZ,    1, 1, OPF_JMP|OPF_CC }, // 75 ZF=0
750   { "jne",  OP_JNZ,    1, 1, OPF_JMP|OPF_CC }, // 75
751   { "jbe",  OP_JBE,    1, 1, OPF_JMP|OPF_CC }, // 76 CF=1 || ZF=1
752   { "jna",  OP_JBE,    1, 1, OPF_JMP|OPF_CC }, // 76
753   { "ja",   OP_JA,     1, 1, OPF_JMP|OPF_CC }, // 77 CF=0 && ZF=0
754   { "jnbe", OP_JA,     1, 1, OPF_JMP|OPF_CC }, // 77
755   { "js",   OP_JS,     1, 1, OPF_JMP|OPF_CC }, // 78 SF=1
756   { "jns",  OP_JNS,    1, 1, OPF_JMP|OPF_CC }, // 79 SF=0
757   { "jp",   OP_JP,     1, 1, OPF_JMP|OPF_CC }, // 7a PF=1
758   { "jpe",  OP_JP,     1, 1, OPF_JMP|OPF_CC }, // 7a
759   { "jnp",  OP_JNP,    1, 1, OPF_JMP|OPF_CC }, // 7b PF=0
760   { "jpo",  OP_JNP,    1, 1, OPF_JMP|OPF_CC }, // 7b
761   { "jl",   OP_JL,     1, 1, OPF_JMP|OPF_CC }, // 7c SF!=OF
762   { "jnge", OP_JL,     1, 1, OPF_JMP|OPF_CC }, // 7c
763   { "jge",  OP_JGE,    1, 1, OPF_JMP|OPF_CC }, // 7d SF=OF
764   { "jnl",  OP_JGE,    1, 1, OPF_JMP|OPF_CC }, // 7d
765   { "jle",  OP_JLE,    1, 1, OPF_JMP|OPF_CC }, // 7e ZF=1 || SF!=OF
766   { "jng",  OP_JLE,    1, 1, OPF_JMP|OPF_CC }, // 7e
767   { "jg",   OP_JG,     1, 1, OPF_JMP|OPF_CC }, // 7f ZF=0 && SF=OF
768   { "jnle", OP_JG,     1, 1, OPF_JMP|OPF_CC }, // 7f
769   { "seto",   OP_JO,   1, 1, OPF_DATA|OPF_CC },
770   { "setno",  OP_JNO,  1, 1, OPF_DATA|OPF_CC },
771   { "setc",   OP_JC,   1, 1, OPF_DATA|OPF_CC },
772   { "setb",   OP_JC,   1, 1, OPF_DATA|OPF_CC },
773   { "setnc",  OP_JNC,  1, 1, OPF_DATA|OPF_CC },
774   { "setae",  OP_JNC,  1, 1, OPF_DATA|OPF_CC },
775   { "setz",   OP_JZ,   1, 1, OPF_DATA|OPF_CC },
776   { "sete",   OP_JZ,   1, 1, OPF_DATA|OPF_CC },
777   { "setnz",  OP_JNZ,  1, 1, OPF_DATA|OPF_CC },
778   { "setne",  OP_JNZ,  1, 1, OPF_DATA|OPF_CC },
779   { "setbe",  OP_JBE,  1, 1, OPF_DATA|OPF_CC },
780   { "setna",  OP_JBE,  1, 1, OPF_DATA|OPF_CC },
781   { "seta",   OP_JA,   1, 1, OPF_DATA|OPF_CC },
782   { "setnbe", OP_JA,   1, 1, OPF_DATA|OPF_CC },
783   { "sets",   OP_JS,   1, 1, OPF_DATA|OPF_CC },
784   { "setns",  OP_JNS,  1, 1, OPF_DATA|OPF_CC },
785   { "setp",   OP_JP,   1, 1, OPF_DATA|OPF_CC },
786   { "setpe",  OP_JP,   1, 1, OPF_DATA|OPF_CC },
787   { "setnp",  OP_JNP,  1, 1, OPF_DATA|OPF_CC },
788   { "setpo",  OP_JNP,  1, 1, OPF_DATA|OPF_CC },
789   { "setl",   OP_JL,   1, 1, OPF_DATA|OPF_CC },
790   { "setnge", OP_JL,   1, 1, OPF_DATA|OPF_CC },
791   { "setge",  OP_JGE,  1, 1, OPF_DATA|OPF_CC },
792   { "setnl",  OP_JGE,  1, 1, OPF_DATA|OPF_CC },
793   { "setle",  OP_JLE,  1, 1, OPF_DATA|OPF_CC },
794   { "setng",  OP_JLE,  1, 1, OPF_DATA|OPF_CC },
795   { "setg",   OP_JG,   1, 1, OPF_DATA|OPF_CC },
796   { "setnle", OP_JG,   1, 1, OPF_DATA|OPF_CC },
797 };
798
799 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
800 {
801   enum opr_lenmod lmod = OPLM_UNSPEC;
802   int prefix_flags = 0;
803   int regmask_ind;
804   int regmask;
805   int op_w = 0;
806   int opr = 0;
807   int w = 0;
808   int i;
809
810   for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
811     if (IS(words[w], pref_table[i].name)) {
812       prefix_flags = pref_table[i].flags;
813       break;
814     }
815   }
816
817   if (prefix_flags) {
818     if (wordc <= 1)
819       aerr("lone prefix: '%s'\n", words[0]);
820     w++;
821   }
822
823   op_w = w;
824   for (i = 0; i < ARRAY_SIZE(op_table); i++) {
825     if (IS(words[w], op_table[i].name))
826       break;
827   }
828
829   if (i == ARRAY_SIZE(op_table))
830     aerr("unhandled op: '%s'\n", words[0]);
831   w++;
832
833   op->op = op_table[i].op;
834   op->flags = op_table[i].flags | prefix_flags;
835   op->regmask_src = op->regmask_dst = 0;
836
837   for (opr = 0; opr < op_table[i].minopr; opr++) {
838     regmask = regmask_ind = 0;
839     w = parse_operand(&op->operand[opr], &regmask, &regmask_ind,
840       words, wordc, w, op->flags);
841
842     if (opr == 0 && (op->flags & OPF_DATA))
843       op->regmask_dst = regmask;
844     // for now, mark dst as src too
845     op->regmask_src |= regmask | regmask_ind;
846   }
847
848   for (; w < wordc && opr < op_table[i].maxopr; opr++) {
849     w = parse_operand(&op->operand[opr],
850       &op->regmask_src, &op->regmask_src,
851       words, wordc, w, op->flags);
852   }
853
854   if (w < wordc)
855     aerr("parse_op %s incomplete: %d/%d\n",
856       words[0], w, wordc);
857
858   // special cases
859   op->operand_cnt = opr;
860   if (!strncmp(op_table[i].name, "set", 3))
861     op->operand[0].lmod = OPLM_BYTE;
862
863   // ops with implicit argumets
864   switch (op->op) {
865   case OP_CDQ:
866     op->operand_cnt = 2;
867     setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
868     setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
869     break;
870
871   case OP_STOS:
872     if (op->operand_cnt != 0)
873       break;
874     if      (IS(words[op_w], "stosb"))
875       lmod = OPLM_BYTE;
876     else if (IS(words[op_w], "stosw"))
877       lmod = OPLM_WORD;
878     else if (IS(words[op_w], "stosd"))
879       lmod = OPLM_DWORD;
880     op->operand_cnt = 3;
881     setup_reg_opr(&op->operand[0], xDI, lmod, &op->regmask_src);
882     setup_reg_opr(&op->operand[1], xCX, OPLM_DWORD, &op->regmask_src);
883     op->regmask_dst = op->regmask_src;
884     setup_reg_opr(&op->operand[2], xAX, OPLM_DWORD, &op->regmask_src);
885     break;
886
887   case OP_MOVS:
888     if (op->operand_cnt != 0)
889       break;
890     if      (IS(words[op_w], "movsb"))
891       lmod = OPLM_BYTE;
892     else if (IS(words[op_w], "movsw"))
893       lmod = OPLM_WORD;
894     else if (IS(words[op_w], "movsd"))
895       lmod = OPLM_DWORD;
896     op->operand_cnt = 3;
897     setup_reg_opr(&op->operand[0], xDI, lmod, &op->regmask_src);
898     setup_reg_opr(&op->operand[1], xSI, OPLM_DWORD, &op->regmask_src);
899     setup_reg_opr(&op->operand[2], xCX, OPLM_DWORD, &op->regmask_src);
900     op->regmask_dst = op->regmask_src;
901     break;
902
903   case OP_IMUL:
904     if (op->operand_cnt != 1)
905       break;
906     // fallthrough
907   case OP_MUL:
908     // singleop mul
909     op->regmask_dst = (1 << xDX) | (1 << xAX);
910     op->regmask_src |= (1 << xAX);
911     if (op->operand[0].lmod == OPLM_UNSPEC)
912       op->operand[0].lmod = OPLM_DWORD;
913     break;
914
915   case OP_DIV:
916   case OP_IDIV:
917     // we could set up operands for edx:eax, but there is no real need to
918     // (see is_opr_modified())
919     regmask = (1 << xDX) | (1 << xAX);
920     op->regmask_dst = regmask;
921     op->regmask_src |= regmask;
922     if (op->operand[0].lmod == OPLM_UNSPEC)
923       op->operand[0].lmod = OPLM_DWORD;
924     break;
925
926   case OP_SHL:
927   case OP_SHR:
928   case OP_SAR:
929   case OP_ROL:
930   case OP_ROR:
931     if (op->operand[1].lmod == OPLM_UNSPEC)
932       op->operand[1].lmod = OPLM_BYTE;
933     break;
934
935   default:
936     break;
937   }
938 }
939
940 static const char *op_name(enum op_op op)
941 {
942   int i;
943
944   for (i = 0; i < ARRAY_SIZE(op_table); i++)
945     if (op_table[i].op == op)
946       return op_table[i].name;
947
948   return "???";
949 }
950
951 // debug
952 static const char *dump_op(struct parsed_op *po)
953 {
954   static char out[128];
955   char *p = out;
956   int i;
957
958   if (po == NULL)
959     return "???";
960
961   snprintf(out, sizeof(out), "%s", op_name(po->op));
962   for (i = 0; i < po->operand_cnt; i++) {
963     p += strlen(p);
964     if (i > 0)
965       *p++ = ',';
966     snprintf(p, sizeof(out) - (p - out),
967       po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
968       po->operand[i].name);
969   }
970
971   return out;
972 }
973
974 static const char *lmod_type_u(struct parsed_op *po,
975   enum opr_lenmod lmod)
976 {
977   switch (lmod) {
978   case OPLM_DWORD:
979     return "u32";
980   case OPLM_WORD:
981     return "u16";
982   case OPLM_BYTE:
983     return "u8";
984   default:
985     ferr(po, "invalid lmod: %d\n", lmod);
986     return "(_invalid_)";
987   }
988 }
989
990 static const char *lmod_cast_u(struct parsed_op *po,
991   enum opr_lenmod lmod)
992 {
993   switch (lmod) {
994   case OPLM_DWORD:
995     return "";
996   case OPLM_WORD:
997     return "(u16)";
998   case OPLM_BYTE:
999     return "(u8)";
1000   default:
1001     ferr(po, "invalid lmod: %d\n", lmod);
1002     return "(_invalid_)";
1003   }
1004 }
1005
1006 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1007   enum opr_lenmod lmod)
1008 {
1009   switch (lmod) {
1010   case OPLM_DWORD:
1011     return "*(u32 *)";
1012   case OPLM_WORD:
1013     return "*(u16 *)";
1014   case OPLM_BYTE:
1015     return "*(u8 *)";
1016   default:
1017     ferr(po, "invalid lmod: %d\n", lmod);
1018     return "(_invalid_)";
1019   }
1020 }
1021
1022 static const char *lmod_cast_s(struct parsed_op *po,
1023   enum opr_lenmod lmod)
1024 {
1025   switch (lmod) {
1026   case OPLM_DWORD:
1027     return "(s32)";
1028   case OPLM_WORD:
1029     return "(s16)";
1030   case OPLM_BYTE:
1031     return "(s8)";
1032   default:
1033     ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1034     return "(_invalid_)";
1035   }
1036 }
1037
1038 static const char *lmod_cast(struct parsed_op *po,
1039   enum opr_lenmod lmod, int is_signed)
1040 {
1041   return is_signed ?
1042     lmod_cast_s(po, lmod) :
1043     lmod_cast_u(po, lmod);
1044 }
1045
1046 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1047 {
1048   switch (lmod) {
1049   case OPLM_DWORD:
1050     return 4;
1051   case OPLM_WORD:
1052     return 2;
1053   case OPLM_BYTE:
1054     return 1;
1055   default:
1056     ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1057     return 0;
1058   }
1059 }
1060
1061 static const char *opr_name(struct parsed_op *po, int opr_num)
1062 {
1063   if (opr_num >= po->operand_cnt)
1064     ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1065   return po->operand[opr_num].name;
1066 }
1067
1068 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1069 {
1070   if (opr_num >= po->operand_cnt)
1071     ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1072   if (po->operand[opr_num].type != OPT_CONST)
1073     ferr(po, "opr %d: const expected\n", opr_num);
1074   return po->operand[opr_num].val;
1075 }
1076
1077 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1078 {
1079   if ((unsigned int)popr->reg >= MAX_REGS)
1080     ferr(po, "invalid reg: %d\n", popr->reg);
1081   return regs_r32[popr->reg];
1082 }
1083
1084 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1085   int *extra_offs)
1086 {
1087   const char *p;
1088   char *endp;
1089   int namelen;
1090   int i;
1091
1092   *extra_offs = 0;
1093   namelen = strlen(name);
1094
1095   p = strchr(name, '+');
1096   if (p != NULL) {
1097     namelen = p - name;
1098     if (namelen <= 0)
1099       ferr(po, "equ parse failed for '%s'\n", name);
1100
1101     if (IS_START(p, "0x"))
1102       p += 2;
1103     *extra_offs = strtol(p, &endp, 16);
1104     if (*endp != 0)
1105       ferr(po, "equ parse failed for '%s'\n", name);
1106   }
1107
1108   for (i = 0; i < g_eqcnt; i++)
1109     if (strncmp(g_eqs[i].name, name, namelen) == 0
1110      && g_eqs[i].name[namelen] == 0)
1111       break;
1112   if (i >= g_eqcnt) {
1113     if (po != NULL)
1114       ferr(po, "unresolved equ name: '%s'\n", name);
1115     return NULL;
1116   }
1117
1118   return &g_eqs[i];
1119 }
1120
1121 static void stack_frame_access(struct parsed_op *po,
1122   enum opr_lenmod lmod, char *buf, size_t buf_size,
1123   const char *name, int is_src, int is_lea)
1124 {
1125   const char *prefix = "";
1126   char ofs_reg[16] = { 0, };
1127   struct parsed_equ *eq;
1128   int i, arg_i, arg_s;
1129   const char *bp_arg;
1130   int stack_ra = 0;
1131   int offset = 0;
1132   int sf_ofs;
1133
1134   bp_arg = parse_stack_el(name, ofs_reg);
1135   snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1136   eq = equ_find(po, bp_arg, &offset);
1137   if (eq == NULL)
1138     ferr(po, "detected but missing eq\n");
1139
1140   offset += eq->offset;
1141
1142   if (!strncmp(name, "ebp", 3))
1143     stack_ra = 4;
1144
1145   if (stack_ra <= offset && offset < stack_ra + 4)
1146     ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1147
1148   if (offset > stack_ra) {
1149     arg_i = (offset - stack_ra - 4) / 4;
1150     if (arg_i < 0 || arg_i >= g_func_pp.argc_stack)
1151       ferr(po, "offset %d (%s) doesn't map to any arg\n",
1152         offset, bp_arg);
1153     if (ofs_reg[0] != 0)
1154       ferr(po, "offset reg on arg acecss?\n");
1155
1156     for (i = arg_s = 0; i < g_func_pp.argc; i++) {
1157       if (g_func_pp.arg[i].reg != NULL)
1158         continue;
1159       if (arg_s == arg_i)
1160         break;
1161       arg_s++;
1162     }
1163     if (i == g_func_pp.argc)
1164       ferr(po, "arg %d not in prototype?\n", arg_i);
1165     if (is_lea)
1166       ferr(po, "lea to arg?\n");
1167
1168     snprintf(buf, buf_size, "%sa%d", is_src ? "(u32)" : "", i + 1);
1169   }
1170   else {
1171     if (g_stack_fsz == 0)
1172       ferr(po, "stack var access without stackframe\n");
1173
1174     sf_ofs = g_stack_fsz + offset;
1175     if (sf_ofs < 0)
1176       ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
1177
1178     if (is_lea)
1179       prefix = "(u32)&";
1180
1181     switch (lmod)
1182     {
1183     case OPLM_BYTE:
1184       if (ofs_reg[0] != 0)
1185         snprintf(buf, buf_size, "%ssf.b[%d+%s]",
1186           prefix, sf_ofs, ofs_reg);
1187       else
1188         snprintf(buf, buf_size, "%ssf.b[%d]",
1189           prefix, sf_ofs);
1190       break;
1191     case OPLM_WORD:
1192       if (ofs_reg[0] != 0)
1193         snprintf(buf, buf_size, "%ssf.w[%d+%s/2]",
1194           prefix, sf_ofs / 2, ofs_reg);
1195       else
1196         snprintf(buf, buf_size, "%ssf.w[%d]",
1197           prefix, sf_ofs / 2);
1198       break;
1199     case OPLM_DWORD:
1200       if (ofs_reg[0] != 0)
1201         snprintf(buf, buf_size, "%ssf.d[%d+%s/4]",
1202           prefix, sf_ofs / 4, ofs_reg);
1203       else
1204         snprintf(buf, buf_size, "%ssf.d[%d]",
1205           prefix, sf_ofs / 4);
1206       break;
1207     default:
1208       ferr(po, "bp_stack bad lmod: %d\n", lmod);
1209     }
1210   }
1211 }
1212
1213 static char *out_src_opr(char *buf, size_t buf_size,
1214         struct parsed_op *po, struct parsed_opr *popr, int is_lea)
1215 {
1216   char tmp1[256], tmp2[256];
1217   char expr[256];
1218   int ret;
1219
1220   switch (popr->type) {
1221   case OPT_REG:
1222     if (is_lea)
1223       ferr(po, "lea from reg?\n");
1224
1225     switch (popr->lmod) {
1226     case OPLM_DWORD:
1227       snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
1228       break;
1229     case OPLM_WORD:
1230       snprintf(buf, buf_size, "(u16)%s", opr_reg_p(po, popr));
1231       break;
1232     case OPLM_BYTE:
1233       if (popr->name[1] == 'h') // XXX..
1234         snprintf(buf, buf_size, "(u8)(%s >> 8)", opr_reg_p(po, popr));
1235       else
1236         snprintf(buf, buf_size, "(u8)%s", opr_reg_p(po, popr));
1237       break;
1238     default:
1239       ferr(po, "invalid src lmod: %d\n", popr->lmod);
1240     }
1241     break;
1242
1243   case OPT_REGMEM:
1244     if (parse_stack_el(popr->name, NULL)) {
1245       stack_frame_access(po, popr->lmod, buf, buf_size,
1246         popr->name, 1, is_lea);
1247       break;
1248     }
1249
1250     strcpy(expr, popr->name);
1251     if (strchr(expr, '[')) {
1252       // special case: '[' can only be left for label[reg] form
1253       ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
1254       if (ret != 2)
1255         ferr(po, "parse failure for '%s'\n", expr);
1256       snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
1257     }
1258
1259     // XXX: do we need more parsing?
1260     if (is_lea) {
1261       snprintf(buf, buf_size, "%s", expr);
1262       break;
1263     }
1264
1265     snprintf(buf, buf_size, "%s(%s)",
1266       lmod_cast_u_ptr(po, popr->lmod), expr);
1267     break;
1268
1269   case OPT_LABEL:
1270     if (is_lea)
1271       snprintf(buf, buf_size, "(u32)&%s", popr->name);
1272     else
1273       snprintf(buf, buf_size, "(u32)%s", popr->name);
1274     break;
1275
1276   case OPT_OFFSET:
1277     if (is_lea)
1278       ferr(po, "lea an offset?\n");
1279     snprintf(buf, buf_size, "(u32)&%s", popr->name);
1280     break;
1281
1282   case OPT_CONST:
1283     if (is_lea)
1284       ferr(po, "lea from const?\n");
1285
1286     printf_number(buf, buf_size, popr->val);
1287     break;
1288
1289   default:
1290     ferr(po, "invalid src type: %d\n", popr->type);
1291   }
1292
1293   return buf;
1294 }
1295
1296 static char *out_dst_opr(char *buf, size_t buf_size,
1297         struct parsed_op *po, struct parsed_opr *popr)
1298 {
1299   switch (popr->type) {
1300   case OPT_REG:
1301     switch (popr->lmod) {
1302     case OPLM_DWORD:
1303       snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
1304       break;
1305     case OPLM_WORD:
1306       // ugh..
1307       snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
1308       break;
1309     case OPLM_BYTE:
1310       // ugh..
1311       if (popr->name[1] == 'h') // XXX..
1312         snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
1313       else
1314         snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
1315       break;
1316     default:
1317       ferr(po, "invalid dst lmod: %d\n", popr->lmod);
1318     }
1319     break;
1320
1321   case OPT_REGMEM:
1322     if (parse_stack_el(popr->name, NULL)) {
1323       stack_frame_access(po, popr->lmod, buf, buf_size,
1324         popr->name, 0, 0);
1325       break;
1326     }
1327
1328     return out_src_opr(buf, buf_size, po, popr, 0);
1329
1330   case OPT_LABEL:
1331     snprintf(buf, buf_size, "%s", popr->name);
1332     break;
1333
1334   default:
1335     ferr(po, "invalid dst type: %d\n", popr->type);
1336   }
1337
1338   return buf;
1339 }
1340
1341 static enum parsed_flag_op split_cond(struct parsed_op *po,
1342   enum op_op op, int *is_inv)
1343 {
1344   *is_inv = 0;
1345
1346   switch (op) {
1347   case OP_JO:
1348     return PFO_O;
1349   case OP_JC:
1350     return PFO_C;
1351   case OP_JZ:
1352     return PFO_Z;
1353   case OP_JBE:
1354     return PFO_BE;
1355   case OP_JS:
1356     return PFO_S;
1357   case OP_JP:
1358     return PFO_P;
1359   case OP_JL:
1360     return PFO_L;
1361   case OP_JLE:
1362     return PFO_LE;
1363
1364   case OP_JNO:
1365     *is_inv = 1;
1366     return PFO_O;
1367   case OP_JNC:
1368     *is_inv = 1;
1369     return PFO_C;
1370   case OP_JNZ:
1371     *is_inv = 1;
1372     return PFO_Z;
1373   case OP_JA:
1374     *is_inv = 1;
1375     return PFO_BE;
1376   case OP_JNS:
1377     *is_inv = 1;
1378     return PFO_S;
1379   case OP_JNP:
1380     *is_inv = 1;
1381     return PFO_P;
1382   case OP_JGE:
1383     *is_inv = 1;
1384     return PFO_L;
1385   case OP_JG:
1386     *is_inv = 1;
1387     return PFO_LE;
1388
1389   case OP_ADC:
1390   case OP_SBB:
1391     return PFO_C;
1392
1393   default:
1394     ferr(po, "split_cond: bad op %d\n", op);
1395     return -1;
1396   }
1397 }
1398
1399 static void out_test_for_cc(char *buf, size_t buf_size,
1400   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
1401   enum opr_lenmod lmod, const char *expr)
1402 {
1403   const char *cast, *scast;
1404
1405   cast = lmod_cast_u(po, lmod);
1406   scast = lmod_cast_s(po, lmod);
1407
1408   switch (pfo) {
1409   case PFO_Z:
1410   case PFO_BE: // CF=1||ZF=1; CF=0
1411     snprintf(buf, buf_size, "(%s%s %s 0)",
1412       cast, expr, is_inv ? "!=" : "==");
1413     break;
1414
1415   case PFO_S:
1416   case PFO_L: // SF!=OF; OF=0
1417     snprintf(buf, buf_size, "(%s%s %s 0)",
1418       scast, expr, is_inv ? ">=" : "<");
1419     break;
1420
1421   case PFO_LE: // ZF=1||SF!=OF; OF=0
1422     snprintf(buf, buf_size, "(%s%s %s 0)",
1423       scast, expr, is_inv ? ">" : "<=");
1424     break;
1425
1426   default:
1427     ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
1428   }
1429 }
1430
1431 static void out_cmp_for_cc(char *buf, size_t buf_size,
1432   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
1433   enum opr_lenmod lmod, const char *expr1, const char *expr2)
1434 {
1435   const char *cast, *scast;
1436
1437   cast = lmod_cast_u(po, lmod);
1438   scast = lmod_cast_s(po, lmod);
1439
1440   switch (pfo) {
1441   case PFO_C:
1442     // note: must be unsigned compare
1443     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1444       cast, expr1, is_inv ? ">=" : "<", cast, expr2);
1445     break;
1446
1447   case PFO_Z:
1448     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1449       cast, expr1, is_inv ? "!=" : "==", cast, expr2);
1450     break;
1451
1452   case PFO_BE: // !a
1453     // note: must be unsigned compare
1454     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1455       cast, expr1, is_inv ? ">" : "<=", cast, expr2);
1456     break;
1457
1458   // note: must be signed compare
1459   case PFO_S:
1460     snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
1461       scast, expr1, expr2, is_inv ? ">=" : "<");
1462     break;
1463
1464   case PFO_L: // !ge
1465     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1466       scast, expr1, is_inv ? ">=" : "<", scast, expr2);
1467     break;
1468
1469   case PFO_LE:
1470     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1471       scast, expr1, is_inv ? ">" : "<=", scast, expr2);
1472     break;
1473
1474   default:
1475     ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
1476   }
1477 }
1478
1479 static void out_cmp_test(char *buf, size_t buf_size,
1480   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
1481 {
1482   char buf1[256], buf2[256], buf3[256];
1483
1484   if (po->op == OP_TEST) {
1485     if (IS(opr_name(po, 0), opr_name(po, 1))) {
1486       out_src_opr(buf3, sizeof(buf3), po, &po->operand[0], 0);
1487     }
1488     else {
1489       out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
1490       out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0);
1491       snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
1492     }
1493     out_test_for_cc(buf, buf_size, po, pfo, is_inv,
1494       po->operand[0].lmod, buf3);
1495   }
1496   else if (po->op == OP_CMP) {
1497     out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], 0);
1498     out_src_opr(buf3, sizeof(buf3), po, &po->operand[1], 0);
1499     out_cmp_for_cc(buf, buf_size, po, pfo, is_inv,
1500       po->operand[0].lmod, buf2, buf3);
1501   }
1502   else
1503     ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
1504 }
1505
1506 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
1507         struct parsed_opr *popr2)
1508 {
1509   if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
1510     ferr(po, "missing lmod for both operands\n");
1511
1512   if (popr1->lmod == OPLM_UNSPEC)
1513     popr1->lmod = popr2->lmod;
1514   else if (popr2->lmod == OPLM_UNSPEC)
1515     popr2->lmod = popr1->lmod;
1516   else if (popr1->lmod != popr2->lmod)
1517     ferr(po, "conflicting lmods: %d vs %d\n", popr1->lmod, popr2->lmod);
1518 }
1519
1520 static const char *op_to_c(struct parsed_op *po)
1521 {
1522   switch (po->op)
1523   {
1524     case OP_ADD:
1525     case OP_ADC:
1526       return "+";
1527     case OP_SUB:
1528     case OP_SBB:
1529       return "-";
1530     case OP_AND:
1531       return "&";
1532     case OP_OR:
1533       return "|";
1534     case OP_XOR:
1535       return "^";
1536     case OP_SHL:
1537       return "<<";
1538     case OP_SHR:
1539       return ">>";
1540     case OP_MUL:
1541     case OP_IMUL:
1542       return "*";
1543     default:
1544       ferr(po, "op_to_c was supplied with %d\n", po->op);
1545   }
1546 }
1547
1548 static void set_flag_no_dup(struct parsed_op *po, enum op_flags flag,
1549   enum op_flags flag_check)
1550 {
1551   if (po->flags & flag)
1552     ferr(po, "flag %x already set\n", flag);
1553   if (po->flags & flag_check)
1554     ferr(po, "flag_check %x already set\n", flag_check);
1555
1556   po->flags |= flag;
1557 }
1558
1559 static int scan_for_pop(int i, int opcnt, const char *reg,
1560   int magic, int depth, int *maxdepth, int do_flags)
1561 {
1562   struct parsed_op *po;
1563   int ret = 0;
1564   int j;
1565
1566   for (; i < opcnt; i++) {
1567     po = &ops[i];
1568     if (po->cc_scratch == magic)
1569       break; // already checked
1570     po->cc_scratch = magic;
1571
1572     if (po->flags & OPF_TAIL)
1573       return -1; // deadend
1574
1575     if ((po->flags & OPF_RMD)
1576         || (po->op == OP_PUSH && po->argmask)) // arg push
1577       continue;
1578
1579     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
1580       if (po->btj != NULL) {
1581         // jumptable
1582         for (j = 0; j < po->btj->count - 1; j++) {
1583           ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, reg, magic,
1584                    depth, maxdepth, do_flags);
1585           if (ret < 0)
1586             return ret; // dead end
1587         }
1588         // follow last jumptable entry
1589         i = po->btj->d[j].bt_i - 1;
1590         continue;
1591       }
1592
1593       if (po->bt_i < 0) {
1594         ferr(po, "dead branch\n");
1595         return -1;
1596       }
1597
1598       if (po->flags & OPF_CC) {
1599         ret |= scan_for_pop(po->bt_i, opcnt, reg, magic,
1600                  depth, maxdepth, do_flags);
1601         if (ret < 0)
1602           return ret; // dead end
1603       }
1604       else {
1605         i = po->bt_i - 1;
1606       }
1607       continue;
1608     }
1609
1610     if ((po->op == OP_POP || po->op == OP_PUSH)
1611         && po->operand[0].type == OPT_REG
1612         && IS(po->operand[0].name, reg))
1613     {
1614       if (po->op == OP_PUSH) {
1615         depth++;
1616         if (depth > *maxdepth)
1617           *maxdepth = depth;
1618         if (do_flags)
1619           set_flag_no_dup(po, OPF_RSAVE, OPF_RMD);
1620       }
1621       else if (depth == 0) {
1622         if (do_flags)
1623           set_flag_no_dup(po, OPF_RMD, OPF_RSAVE);
1624         return 1;
1625       }
1626       else {
1627         depth--;
1628         if (depth < 0) // should not happen
1629           ferr(po, "fail with depth\n");
1630         if (do_flags)
1631           set_flag_no_dup(po, OPF_RSAVE, OPF_RMD);
1632       }
1633     }
1634   }
1635
1636   return ret;
1637 }
1638
1639 // scan for pop starting from 'ret' op (all paths)
1640 static int scan_for_pop_ret(int i, int opcnt, const char *reg,
1641   int flag_set)
1642 {
1643   int found = 0;
1644   int j;
1645
1646   for (; i < opcnt; i++) {
1647     if (!(ops[i].flags & OPF_TAIL))
1648       continue;
1649
1650     for (j = i - 1; j >= 0; j--) {
1651       if (ops[j].flags & OPF_RMD)
1652         continue;
1653       if (ops[j].flags & OPF_JMP)
1654         return -1;
1655
1656       if (ops[j].op == OP_POP && ops[j].operand[0].type == OPT_REG
1657           && IS(ops[j].operand[0].name, reg))
1658       {
1659         found = 1;
1660         ops[j].flags |= flag_set;
1661         break;
1662       }
1663
1664       if (g_labels[j][0] != 0)
1665         return -1;
1666     }
1667   }
1668
1669   return found ? 0 : -1;
1670 }
1671
1672 // is operand 'opr modified' by parsed_op 'po'?
1673 static int is_opr_modified(const struct parsed_opr *opr,
1674   const struct parsed_op *po)
1675 {
1676   if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
1677     return 0;
1678
1679   if (opr->type == OPT_REG && po->operand[0].type == OPT_REG) {
1680     if (po->regmask_dst & (1 << opr->reg))
1681       return 1;
1682     else
1683       return 0;
1684   }
1685
1686   return IS(po->operand[0].name, opr->name);
1687 }
1688
1689 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
1690 static int is_any_opr_modified(const struct parsed_op *po_test,
1691   const struct parsed_op *po)
1692 {
1693   int i;
1694
1695   if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
1696     return 0;
1697
1698   if (po_test->regmask_src & po->regmask_dst)
1699     return 1;
1700
1701   for (i = 0; i < po_test->operand_cnt; i++)
1702     if (IS(po_test->operand[i].name, po->operand[0].name))
1703       return 1;
1704
1705   return 0;
1706 }
1707
1708 // scan for any po_test operand modification in range given
1709 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt)
1710 {
1711   for (; i < opcnt; i++) {
1712     if (is_any_opr_modified(po_test, &ops[i]))
1713       return i;
1714   }
1715
1716   return -1;
1717 }
1718
1719 // scan for po_test operand[0] modification in range given
1720 static int scan_for_mod_opr0(struct parsed_op *po_test,
1721   int i, int opcnt)
1722 {
1723   for (; i < opcnt; i++) {
1724     if (is_opr_modified(&po_test->operand[0], &ops[i]))
1725       return i;
1726   }
1727
1728   return -1;
1729 }
1730
1731 static int scan_for_flag_set(int i)
1732 {
1733   for (; i >= 0; i--) {
1734     if (ops[i].flags & OPF_FLAGS)
1735       return i;
1736
1737     if ((ops[i].flags & OPF_JMP) && !(ops[i].flags & OPF_CC))
1738       return -1;
1739     if (g_labels[i][0] != 0)
1740       return -1;
1741   }
1742
1743   return -1;
1744 }
1745
1746 // scan back for cdq, if anything modifies edx, fail
1747 static int scan_for_cdq_edx(int i)
1748 {
1749   for (; i >= 0; i--) {
1750     if (ops[i].op == OP_CDQ)
1751       return i;
1752
1753     if (ops[i].regmask_dst & (1 << xDX))
1754       return -1;
1755     if (g_labels[i][0] != 0)
1756       return -1;
1757   }
1758
1759   return -1;
1760 }
1761
1762 static int scan_for_reg_clear(int i, int reg)
1763 {
1764   for (; i >= 0; i--) {
1765     if (ops[i].op == OP_XOR
1766      && ops[i].operand[0].lmod == OPLM_DWORD
1767      && ops[i].operand[0].reg == ops[i].operand[1].reg
1768      && ops[i].operand[0].reg == reg)
1769       return i;
1770
1771     if (ops[i].regmask_dst & (1 << reg))
1772       return -1;
1773     if (g_labels[i][0] != 0)
1774       return -1;
1775   }
1776
1777   return -1;
1778 }
1779
1780 // scan for positive, constant esp adjust
1781 static int scan_for_esp_adjust(int i, int opcnt, int *adj)
1782 {
1783   for (; i < opcnt; i++) {
1784     if (ops[i].op == OP_ADD && ops[i].operand[0].reg == xSP) {
1785       if (ops[i].operand[1].type != OPT_CONST)
1786         ferr(&ops[i], "non-const esp adjust?\n");
1787       *adj = ops[i].operand[1].val;
1788       if (*adj & 3)
1789         ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
1790       return i;
1791     }
1792
1793     if ((ops[i].flags & (OPF_JMP|OPF_TAIL))
1794          || ops[i].op == OP_PUSH || ops[i].op == OP_POP)
1795       return -1;
1796     if (g_labels[i][0] != 0)
1797       return -1;
1798   }
1799
1800   return -1;
1801 }
1802
1803 static void add_label_ref(struct label_ref *lr, int op_i)
1804 {
1805   struct label_ref *lr_new;
1806
1807   if (lr->i == -1) {
1808     lr->i = op_i;
1809     return;
1810   }
1811
1812   lr_new = calloc(1, sizeof(*lr_new));
1813   lr_new->i = op_i;
1814   lr->next = lr_new;
1815 }
1816
1817 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
1818 {
1819   struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
1820   struct parsed_opr *last_arith_dst = NULL;
1821   char buf1[256], buf2[256], buf3[256];
1822   struct parsed_proto *pp, *pp_tmp;
1823   struct parsed_data *pd;
1824   const char *tmpname;
1825   enum parsed_flag_op pfo;
1826   int save_arg_vars = 0;
1827   int cmp_result_vars = 0;
1828   int need_mul_var = 0;
1829   int had_decl = 0;
1830   int regmask_save = 0;
1831   int regmask_arg = 0;
1832   int regmask = 0;
1833   int pfomask = 0;
1834   int found = 0;
1835   int depth = 0;
1836   int no_output;
1837   int i, j, l;
1838   int dummy;
1839   int arg;
1840   int reg;
1841   int ret;
1842
1843   g_bp_frame = g_sp_frame = g_stack_fsz = 0;
1844
1845   ret = proto_parse(fhdr, funcn, &g_func_pp);
1846   if (ret)
1847     ferr(ops, "proto_parse failed for '%s'\n", funcn);
1848
1849   fprintf(fout, "%s %s(", g_func_pp.ret_type, funcn);
1850   for (i = 0; i < g_func_pp.argc; i++) {
1851     if (i > 0)
1852       fprintf(fout, ", ");
1853     fprintf(fout, "%s a%d", g_func_pp.arg[i].type, i + 1);
1854   }
1855   fprintf(fout, ")\n{\n");
1856
1857   // pass1:
1858   // - handle ebp/esp frame, remove ops related to it
1859   if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
1860       && ops[1].op == OP_MOV
1861       && IS(opr_name(&ops[1], 0), "ebp")
1862       && IS(opr_name(&ops[1], 1), "esp"))
1863   {
1864     int ecx_push = 0;
1865
1866     g_bp_frame = 1;
1867     ops[0].flags |= OPF_RMD;
1868     ops[1].flags |= OPF_RMD;
1869     i = 2;
1870
1871     if (ops[2].op == OP_SUB && IS(opr_name(&ops[2], 0), "esp")) {
1872       g_stack_fsz = opr_const(&ops[2], 1);
1873       ops[2].flags |= OPF_RMD;
1874       i++;
1875     }
1876     else {
1877       // another way msvc builds stack frame..
1878       i = 2;
1879       while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
1880         g_stack_fsz += 4;
1881         ops[i].flags |= OPF_RMD;
1882         ecx_push++;
1883         i++;
1884       }
1885       // and another way..
1886       if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
1887           && ops[i].operand[1].type == OPT_CONST
1888           && ops[i + 1].op == OP_CALL
1889           && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
1890       {
1891         g_stack_fsz += ops[i].operand[1].val;
1892         ops[i].flags |= OPF_RMD;
1893         i++;
1894         ops[i].flags |= OPF_RMD;
1895         i++;
1896       }
1897     }
1898
1899     found = 0;
1900     do {
1901       for (; i < opcnt; i++)
1902         if (ops[i].op == OP_RET)
1903           break;
1904       if (i == opcnt && (ops[i - 1].flags & OPF_JMP) && found)
1905         break;
1906
1907       if (ops[i - 1].op != OP_POP || !IS(opr_name(&ops[i - 1], 0), "ebp"))
1908         ferr(&ops[i - 1], "'pop ebp' expected\n");
1909       ops[i - 1].flags |= OPF_RMD;
1910
1911       if (g_stack_fsz != 0) {
1912         if (ops[i - 2].op != OP_MOV
1913             || !IS(opr_name(&ops[i - 2], 0), "esp")
1914             || !IS(opr_name(&ops[i - 2], 1), "ebp"))
1915         {
1916           ferr(&ops[i - 2], "esp restore expected\n");
1917         }
1918         ops[i - 2].flags |= OPF_RMD;
1919
1920         if (ecx_push && ops[i - 3].op == OP_POP
1921           && IS(opr_name(&ops[i - 3], 0), "ecx"))
1922         {
1923           ferr(&ops[i - 3], "unexpected ecx pop\n");
1924         }
1925       }
1926
1927       found = 1;
1928       i++;
1929     } while (i < opcnt);
1930   }
1931   else {
1932     for (i = 0; i < opcnt; i++) {
1933       if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
1934         break;
1935       if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
1936         && ops[i].operand[1].type == OPT_CONST)
1937       {
1938         g_sp_frame = 1;
1939         break;
1940       }
1941     }
1942
1943     if (g_sp_frame)
1944     {
1945       g_stack_fsz = ops[i].operand[1].val;
1946       ops[i].flags |= OPF_RMD;
1947
1948       i++;
1949       do {
1950         for (; i < opcnt; i++)
1951           if (ops[i].op == OP_RET)
1952             break;
1953         if (ops[i - 1].op != OP_ADD
1954             || !IS(opr_name(&ops[i - 1], 0), "esp")
1955             || ops[i - 1].operand[1].type != OPT_CONST
1956             || ops[i - 1].operand[1].val != g_stack_fsz)
1957           ferr(&ops[i - 1], "'add esp' expected\n");
1958         ops[i - 1].flags |= OPF_RMD;
1959
1960         i++;
1961       } while (i < opcnt);
1962     }
1963   }
1964
1965   // pass2:
1966   // - resolve all branches
1967   for (i = 0; i < opcnt; i++) {
1968     po = &ops[i];
1969     po->bt_i = -1;
1970     po->btj = NULL;
1971
1972     if ((po->flags & OPF_RMD) || !(po->flags & OPF_JMP)
1973         || po->op == OP_CALL || po->op == OP_RET)
1974       continue;
1975
1976     if (po->operand[0].type == OPT_REGMEM) {
1977       char *p = strchr(po->operand[0].name, '[');
1978       if (p == NULL)
1979         ferr(po, "unhandled indirect branch\n");
1980       ret = p - po->operand[0].name;
1981       strncpy(buf1, po->operand[0].name, ret);
1982       buf1[ret] = 0;
1983
1984       for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
1985         if (IS(g_func_pd[j].label, buf1)) {
1986           pd = &g_func_pd[j];
1987           break;
1988         }
1989       }
1990       if (pd == NULL)
1991         ferr(po, "label '%s' not parsed?\n", buf1);
1992       if (pd->type != OPT_OFFSET)
1993         ferr(po, "label '%s' with non-offset data?\n", buf1);
1994
1995       // find all labels, link
1996       for (j = 0; j < pd->count; j++) {
1997         for (l = 0; l < opcnt; l++) {
1998           if (g_labels[l][0] && IS(g_labels[l], pd->d[j].u.label)) {
1999             add_label_ref(&g_label_refs[l], i);
2000             pd->d[j].bt_i = l;
2001             break;
2002           }
2003         }
2004       }
2005
2006       po->btj = pd;
2007       continue;
2008     }
2009
2010     for (l = 0; l < opcnt; l++) {
2011       if (g_labels[l][0] && IS(po->operand[0].name, g_labels[l])) {
2012         add_label_ref(&g_label_refs[l], i);
2013         po->bt_i = l;
2014         break;
2015       }
2016     }
2017
2018     if (po->bt_i != -1)
2019       continue;
2020
2021     if (po->operand[0].type == OPT_LABEL) {
2022       // assume tail call
2023       po->op = OP_CALL;
2024       po->flags |= OPF_TAIL;
2025       continue;
2026     }
2027
2028     ferr(po, "unhandled branch\n");
2029   }
2030
2031   // pass3:
2032   // - process calls
2033   for (i = 0; i < opcnt; i++)
2034   {
2035     po = &ops[i];
2036     if (po->flags & OPF_RMD)
2037       continue;
2038
2039     if (po->op == OP_CALL)
2040     {
2041       pp = calloc(1, sizeof(*pp));
2042       my_assert_not(pp, NULL);
2043       tmpname = opr_name(po, 0);
2044       if (po->operand[0].type != OPT_LABEL)
2045       {
2046         ret = scan_for_esp_adjust(i + 1, opcnt, &j);
2047         if (ret < 0)
2048           ferr(po, "non-__cdecl indirect call unhandled yet\n");
2049         j /= 4;
2050         if (j > ARRAY_SIZE(pp->arg))
2051           ferr(po, "esp adjust too large?\n");
2052         pp->ret_type = strdup("int");
2053         pp->argc = pp->argc_stack = j;
2054         for (arg = 0; arg < pp->argc; arg++)
2055           pp->arg[arg].type = strdup("int");
2056       }
2057       else {
2058         ret = proto_parse(fhdr, tmpname, pp);
2059         if (ret)
2060           ferr(po, "proto_parse failed for call '%s'\n", tmpname);
2061       }
2062
2063       ret = scan_for_esp_adjust(i + 1, opcnt, &j);
2064       if (ret >= 0) {
2065         if (pp->argc_stack != j / 4)
2066           ferr(po, "stack tracking failed: %x %x\n",
2067             pp->argc_stack, j);
2068         ops[ret].flags |= OPF_RMD;
2069       }
2070
2071       // can't call functions with non-__cdecl callbacks yet
2072       for (arg = 0; arg < pp->argc; arg++) {
2073         if (pp->arg[arg].fptr != NULL) {
2074           pp_tmp = pp->arg[arg].fptr;
2075           if (pp_tmp->is_stdcall || pp_tmp->argc != pp_tmp->argc_stack)
2076             ferr(po, "'%s' has a non-__cdecl callback\n", tmpname);
2077         }
2078       }
2079
2080       // collect all stack args
2081       for (arg = 0; arg < pp->argc; arg++)
2082         if (pp->arg[arg].reg == NULL)
2083           break;
2084
2085       for (j = i; j >= 0 && arg < pp->argc; )
2086       {
2087         if (g_labels[j][0] != 0) {
2088           if (j > 0 && ((ops[j - 1].flags & OPF_TAIL)
2089             || (ops[j - 1].flags & (OPF_JMP|OPF_CC)) == OPF_JMP))
2090           {
2091             // follow the branch in reverse
2092             if (g_label_refs[j].i == -1)
2093               ferr(po, "no refs for '%s'?\n", g_labels[j]);
2094             if (g_label_refs[j].next != NULL)
2095               ferr(po, "unhandled multiple refs to '%s'\n", g_labels[j]);
2096             j = g_label_refs[j].i + 1;
2097             continue;
2098           }
2099           break;
2100         }
2101         j--;
2102
2103         if (ops[j].op == OP_CALL)
2104         {
2105           pp_tmp = ops[j].datap;
2106           if (pp_tmp == NULL)
2107             ferr(po, "arg collect hit unparsed call\n");
2108           if (pp_tmp->argc_stack > 0)
2109             ferr(po, "arg collect hit '%s' with %d stack args\n",
2110               opr_name(&ops[j], 0), pp_tmp->argc_stack);
2111         }
2112         else if ((ops[j].flags & OPF_TAIL)
2113             || (ops[j].flags & (OPF_JMP|OPF_CC)) == OPF_JMP)
2114         {
2115           break;
2116         }
2117         else if (ops[j].op == OP_PUSH)
2118         {
2119           pp->arg[arg].datap = &ops[j];
2120           ret = scan_for_mod(&ops[j], j + 1, i);
2121           if (ret >= 0) {
2122             // mark this push as one that needs operand saving
2123             ops[j].flags &= ~OPF_RMD;
2124             ops[j].argmask |= 1 << arg;
2125             save_arg_vars |= 1 << arg;
2126           }
2127           else
2128             ops[j].flags |= OPF_RMD;
2129
2130           // next arg
2131           for (arg++; arg < pp->argc; arg++)
2132             if (pp->arg[arg].reg == NULL)
2133               break;
2134         }
2135       }
2136       if (arg < pp->argc)
2137         ferr(po, "arg collect failed for '%s': %d/%d\n",
2138           tmpname, arg, pp->argc);
2139       po->datap = pp;
2140     }
2141   }
2142
2143   // pass4:
2144   // - find POPs for PUSHes, rm both
2145   // - scan for all used registers
2146   // - find flag set ops for their users
2147   // - declare indirect functions
2148   for (i = 0; i < opcnt; i++) {
2149     po = &ops[i];
2150     if (po->flags & OPF_RMD)
2151       continue;
2152
2153     if (po->op == OP_PUSH
2154         && po->argmask == 0 && !(po->flags & OPF_RSAVE)
2155         && po->operand[0].type == OPT_REG)
2156     {
2157       reg = po->operand[0].reg;
2158       if (reg < 0)
2159         ferr(po, "reg not set for push?\n");
2160
2161       depth = 0;
2162       ret = scan_for_pop(i + 1, opcnt,
2163               po->operand[0].name, i + opcnt, 0, &depth, 0);
2164       if (ret == 1) {
2165         if (depth > 1)
2166           ferr(po, "too much depth: %d\n", depth);
2167         if (depth > 0)
2168           regmask_save |= 1 << reg;
2169
2170         po->flags |= OPF_RMD;
2171         scan_for_pop(i + 1, opcnt, po->operand[0].name,
2172           i + opcnt * 2, 0, &depth, 1);
2173         continue;
2174       }
2175       ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].name, 0);
2176       if (ret == 0) {
2177         arg = OPF_RMD;
2178         if (regmask & (1 << reg)) {
2179           if (regmask_save & (1 << reg))
2180             ferr(po, "%s already saved?\n", po->operand[0].name);
2181           arg = OPF_RSAVE;
2182         }
2183         po->flags |= arg;
2184         scan_for_pop_ret(i + 1, opcnt, po->operand[0].name, arg);
2185         continue;
2186       }
2187     }
2188
2189     regmask |= po->regmask_src | po->regmask_dst;
2190
2191     if (po->flags & OPF_CC)
2192     {
2193       ret = scan_for_flag_set(i - 1);
2194       if (ret < 0)
2195         ferr(po, "unable to trace flag setter\n");
2196
2197       tmp_op = &ops[ret]; // flag setter
2198       pfo = split_cond(po, po->op, &dummy);
2199       pfomask = 0;
2200
2201       // to get nicer code, we try to delay test and cmp;
2202       // if we can't because of operand modification, or if we
2203       // have math op, make it calculate flags explicitly
2204       if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP) {
2205         if (scan_for_mod(tmp_op, ret + 1, i) >= 0)
2206           pfomask = 1 << pfo;
2207       }
2208       else {
2209         if ((pfo != PFO_Z && pfo != PFO_S && pfo != PFO_P)
2210             || scan_for_mod_opr0(tmp_op, ret + 1, i) >= 0)
2211           pfomask = 1 << pfo;
2212       }
2213       if (pfomask) {
2214         tmp_op->pfomask |= pfomask;
2215         cmp_result_vars |= pfomask;
2216         po->datap = tmp_op;
2217       }
2218
2219       if (po->op == OP_ADC || po->op == OP_SBB)
2220         cmp_result_vars |= 1 << PFO_C;
2221     }
2222     else if (po->op == OP_MUL
2223       || (po->op == OP_IMUL && po->operand_cnt == 1))
2224     {
2225       need_mul_var = 1;
2226     }
2227     else if (po->op == OP_CALL && po->operand[0].type != OPT_LABEL) {
2228       pp = po->datap;
2229       my_assert_not(pp, NULL);
2230       fprintf(fout, "  %s (*icall%d)(", pp->ret_type, i);
2231       for (j = 0; j < pp->argc; j++) {
2232         if (j > 0)
2233           fprintf(fout, ", ");
2234         fprintf(fout, "%s a%d", pp->arg[j].type, j + 1);
2235       }
2236       fprintf(fout, ");\n");
2237     }
2238   }
2239
2240   // output LUTs/jumptables
2241   for (i = 0; i < g_func_pd_cnt; i++) {
2242     pd = &g_func_pd[i];
2243     fprintf(fout, "  static const ");
2244     if (pd->type == OPT_OFFSET) {
2245       fprintf(fout, "void *jt_%s[] =\n    { ", pd->label);
2246
2247       for (j = 0; j < pd->count; j++) {
2248         if (j > 0)
2249           fprintf(fout, ", ");
2250         fprintf(fout, "&&%s", pd->d[j].u.label);
2251       }
2252     }
2253     else {
2254       fprintf(fout, "%s %s[] =\n    { ",
2255         lmod_type_u(ops, pd->lmod), pd->label);
2256
2257       for (j = 0; j < pd->count; j++) {
2258         if (j > 0)
2259           fprintf(fout, ", ");
2260         fprintf(fout, "%u", pd->d[j].u.val);
2261       }
2262     }
2263     fprintf(fout, " };\n");
2264   }
2265
2266   // declare stack frame
2267   if (g_stack_fsz)
2268     fprintf(fout, "  union { u32 d[%d]; u16 w[%d]; u8 b[%d]; } sf;\n",
2269       (g_stack_fsz + 3) / 4, (g_stack_fsz + 1) / 2, g_stack_fsz);
2270
2271   // declare arg-registers
2272   for (i = 0; i < g_func_pp.argc; i++) {
2273     if (g_func_pp.arg[i].reg != NULL) {
2274       reg = char_array_i(regs_r32,
2275               ARRAY_SIZE(regs_r32), g_func_pp.arg[i].reg);
2276       if (reg < 0)
2277         ferr(ops, "arg '%s' is not a reg?\n", g_func_pp.arg[i].reg);
2278
2279       regmask_arg |= 1 << reg;
2280       fprintf(fout, "  u32 %s = (u32)a%d;\n",
2281         g_func_pp.arg[i].reg, i + 1);
2282       had_decl = 1;
2283     }
2284   }
2285
2286   // declare other regs - special case for eax
2287   if (!((regmask | regmask_arg) & 1) && !IS(g_func_pp.ret_type, "void")) {
2288     fprintf(fout, "  u32 eax = 0;\n");
2289     had_decl = 1;
2290   }
2291
2292   regmask &= ~regmask_arg;
2293   regmask &= ~(1 << xSP);
2294   if (g_bp_frame)
2295     regmask &= ~(1 << xBP);
2296   if (regmask) {
2297     for (reg = 0; reg < 8; reg++) {
2298       if (regmask & (1 << reg)) {
2299         fprintf(fout, "  u32 %s;\n", regs_r32[reg]);
2300         had_decl = 1;
2301       }
2302     }
2303   }
2304
2305   if (regmask_save) {
2306     for (reg = 0; reg < 8; reg++) {
2307       if (regmask_save & (1 << reg)) {
2308         fprintf(fout, "  u32 s_%s;\n", regs_r32[reg]);
2309         had_decl = 1;
2310       }
2311     }
2312   }
2313
2314   if (save_arg_vars) {
2315     for (reg = 0; reg < 32; reg++) {
2316       if (save_arg_vars & (1 << reg)) {
2317         fprintf(fout, "  u32 s_a%d;\n", reg + 1);
2318         had_decl = 1;
2319       }
2320     }
2321   }
2322
2323   if (cmp_result_vars) {
2324     for (i = 0; i < 8; i++) {
2325       if (cmp_result_vars & (1 << i)) {
2326         fprintf(fout, "  u32 cond_%s;\n", parsed_flag_op_names[i]);
2327         had_decl = 1;
2328       }
2329     }
2330   }
2331
2332   if (need_mul_var) {
2333     fprintf(fout, "  u64 mul_tmp;\n");
2334     had_decl = 1;
2335   }
2336
2337   if (had_decl)
2338     fprintf(fout, "\n");
2339
2340   // output ops
2341   for (i = 0; i < opcnt; i++)
2342   {
2343     if (g_labels[i][0] != 0 && g_label_refs[i].i != -1)
2344       fprintf(fout, "\n%s:\n", g_labels[i]);
2345
2346     po = &ops[i];
2347     if (po->flags & OPF_RMD)
2348       continue;
2349
2350     no_output = 0;
2351
2352     #define assert_operand_cnt(n_) \
2353       if (po->operand_cnt != n_) \
2354         ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
2355
2356     // conditional/flag using op?
2357     if (po->flags & OPF_CC)
2358     {
2359       int is_delayed = 0;
2360       int is_inv = 0;
2361
2362       pfo = split_cond(po, po->op, &is_inv);
2363
2364       // we go through all this trouble to avoid using parsed_flag_op,
2365       // which makes generated code much nicer
2366       if (delayed_flag_op != NULL)
2367       {
2368         out_cmp_test(buf1, sizeof(buf1), delayed_flag_op, pfo, is_inv);
2369         is_delayed = 1;
2370       }
2371       else if (last_arith_dst != NULL
2372         && (pfo == PFO_Z || pfo == PFO_S || pfo == PFO_P))
2373       {
2374         out_src_opr(buf3, sizeof(buf3), po, last_arith_dst, 0);
2375         out_test_for_cc(buf1, sizeof(buf1), po, pfo, is_inv,
2376           last_arith_dst->lmod, buf3);
2377         is_delayed = 1;
2378       }
2379       else if (po->datap != NULL) {
2380         // use preprocessed results
2381         tmp_op = po->datap;
2382         if (!tmp_op || !(tmp_op->pfomask & (1 << pfo)))
2383           ferr(po, "not prepared for pfo %d\n", pfo);
2384
2385         // note: is_inv was not yet applied
2386         snprintf(buf1, sizeof(buf1), "(%scond_%s)",
2387           is_inv ? "!" : "", parsed_flag_op_names[pfo]);
2388       }
2389       else {
2390         ferr(po, "all methods of finding comparison failed\n");
2391       }
2392  
2393       if (po->flags & OPF_JMP) {
2394         fprintf(fout, "  if %s\n", buf1);
2395       }
2396       else if (po->op == OP_ADC || po->op == OP_SBB) {
2397         if (is_delayed)
2398           fprintf(fout, "  cond_%s = %s;\n",
2399             parsed_flag_op_names[pfo], buf1);
2400       }
2401       else if (po->flags & OPF_DATA) { // SETcc
2402         out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
2403         fprintf(fout, "  %s = %s;", buf2, buf1);
2404       }
2405       else {
2406         ferr(po, "unhandled conditional op\n");
2407       }
2408     }
2409
2410     pfomask = po->pfomask;
2411
2412     switch (po->op)
2413     {
2414       case OP_MOV:
2415         assert_operand_cnt(2);
2416         propagate_lmod(po, &po->operand[0], &po->operand[1]);
2417         fprintf(fout, "  %s = %s%s;",
2418             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
2419             po->operand[0].is_ptr ? "(void *)" : "",
2420             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
2421         break;
2422
2423       case OP_LEA:
2424         assert_operand_cnt(2);
2425         po->operand[1].lmod = OPLM_DWORD; // always
2426         fprintf(fout, "  %s = %s;",
2427             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
2428             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 1));
2429         break;
2430
2431       case OP_MOVZX:
2432         assert_operand_cnt(2);
2433         fprintf(fout, "  %s = %s;",
2434             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
2435             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
2436         break;
2437
2438       case OP_MOVSX:
2439         assert_operand_cnt(2);
2440         switch (po->operand[1].lmod) {
2441         case OPLM_BYTE:
2442           strcpy(buf3, "(s8)");
2443           break;
2444         case OPLM_WORD:
2445           strcpy(buf3, "(s16)");
2446           break;
2447         default:
2448           ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
2449         }
2450         fprintf(fout, "  %s = %s%s;",
2451             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
2452             buf3,
2453             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
2454         break;
2455
2456       case OP_NOT:
2457         assert_operand_cnt(1);
2458         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
2459         fprintf(fout, "  %s = ~%s;", buf1, buf1);
2460         break;
2461
2462       case OP_CDQ:
2463         assert_operand_cnt(2);
2464         fprintf(fout, "  %s = (s32)%s >> 31;",
2465             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
2466             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
2467         strcpy(g_comment, "cdq");
2468         break;
2469
2470       case OP_STOS:
2471         // assumes DF=0
2472         assert_operand_cnt(3);
2473         if (po->flags & OPF_REP) {
2474           fprintf(fout, "  for (; ecx != 0; ecx--, edi += %d)\n",
2475             lmod_bytes(po, po->operand[0].lmod));
2476           fprintf(fout, "    %sedi = eax;",
2477             lmod_cast_u_ptr(po, po->operand[0].lmod));
2478           strcpy(g_comment, "rep stos");
2479         }
2480         else {
2481           fprintf(fout, "    %sedi = eax; edi += %d;",
2482             lmod_cast_u_ptr(po, po->operand[0].lmod),
2483             lmod_bytes(po, po->operand[0].lmod));
2484           strcpy(g_comment, "stos");
2485         }
2486         break;
2487
2488       case OP_MOVS:
2489         // assumes DF=0
2490         assert_operand_cnt(3);
2491         j = lmod_bytes(po, po->operand[0].lmod);
2492         strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
2493         if (po->flags & OPF_REP) {
2494           fprintf(fout,
2495             "  for (; ecx != 0; ecx--, edi += %d, esi += %d)\n",
2496             j, j);
2497           fprintf(fout,
2498             "    %sedi = %sesi;", buf1, buf1);
2499           strcpy(g_comment, "rep movs");
2500         }
2501         else {
2502           fprintf(fout, "    %sedi = %sesi; edi += %d; esi += %d;",
2503             buf1, buf1, j, j);
2504           strcpy(g_comment, "movs");
2505         }
2506         break;
2507
2508       // arithmetic w/flags
2509       case OP_ADD:
2510       case OP_SUB:
2511       case OP_AND:
2512       case OP_OR:
2513         propagate_lmod(po, &po->operand[0], &po->operand[1]);
2514         // fallthrough
2515       case OP_SHL:
2516       case OP_SHR:
2517       dualop_arith:
2518         assert_operand_cnt(2);
2519         fprintf(fout, "  %s %s= %s;",
2520             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
2521             op_to_c(po),
2522             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
2523         last_arith_dst = &po->operand[0];
2524         delayed_flag_op = NULL;
2525         break;
2526
2527       case OP_SAR:
2528         assert_operand_cnt(2);
2529         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
2530         fprintf(fout, "  %s = %s%s >> %s;", buf1,
2531           lmod_cast_s(po, po->operand[0].lmod), buf1,
2532           out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
2533         last_arith_dst = &po->operand[0];
2534         delayed_flag_op = NULL;
2535         break;
2536
2537       case OP_ROL:
2538       case OP_ROR:
2539         assert_operand_cnt(2);
2540         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
2541         if (po->operand[1].type == OPT_CONST) {
2542           j = po->operand[1].val;
2543           j %= lmod_bytes(po, po->operand[0].lmod) * 8;
2544           fprintf(fout, po->op == OP_ROL ?
2545             "  %s = (%s << %d) | (%s >> %d);" :
2546             "  %s = (%s >> %d) | (%s << %d);",
2547             buf1, buf1, j, buf1,
2548             lmod_bytes(po, po->operand[0].lmod) * 8 - j);
2549         }
2550         else
2551           ferr(po, "TODO\n");
2552         last_arith_dst = &po->operand[0];
2553         delayed_flag_op = NULL;
2554         break;
2555
2556       case OP_XOR:
2557         assert_operand_cnt(2);
2558         propagate_lmod(po, &po->operand[0], &po->operand[1]);
2559         if (IS(opr_name(po, 0), opr_name(po, 1))) {
2560           // special case for XOR
2561           fprintf(fout, "  %s = 0;",
2562             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
2563           last_arith_dst = &po->operand[0];
2564           delayed_flag_op = NULL;
2565           break;
2566         }
2567         goto dualop_arith;
2568
2569       case OP_ADC:
2570       case OP_SBB:
2571         assert_operand_cnt(2);
2572         propagate_lmod(po, &po->operand[0], &po->operand[1]);
2573         fprintf(fout, "  %s %s= %s + cond_c;",
2574             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
2575             op_to_c(po),
2576             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
2577         last_arith_dst = &po->operand[0];
2578         delayed_flag_op = NULL;
2579         break;
2580
2581       case OP_INC:
2582       case OP_DEC:
2583         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
2584         if (po->operand[0].type == OPT_REG) {
2585           strcpy(buf2, po->op == OP_INC ? "++" : "--");
2586           fprintf(fout, "  %s%s;", buf1, buf2);
2587         }
2588         else {
2589           strcpy(buf2, po->op == OP_INC ? "+" : "-");
2590           fprintf(fout, "  %s %s= 1;", buf1, buf2);
2591         }
2592         last_arith_dst = &po->operand[0];
2593         delayed_flag_op = NULL;
2594         break;
2595
2596       case OP_NEG:
2597         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
2598         out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], 0);
2599         fprintf(fout, "  %s = -%s%s;", buf1,
2600           lmod_cast_s(po, po->operand[0].lmod), buf2);
2601         last_arith_dst = &po->operand[0];
2602         delayed_flag_op = NULL;
2603         if (pfomask & (1 << PFO_C)) {
2604           fprintf(fout, "\n  cond_c = (%s != 0);", buf1);
2605           pfomask &= ~(1 << PFO_C);
2606         }
2607         break;
2608
2609       case OP_IMUL:
2610         if (po->operand_cnt == 2)
2611           goto dualop_arith;
2612         if (po->operand_cnt == 3)
2613           ferr(po, "TODO imul3\n");
2614         // fallthrough
2615       case OP_MUL:
2616         assert_operand_cnt(1);
2617         strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
2618         fprintf(fout, "  mul_tmp = %seax * %s%s;\n", buf1, buf1,
2619           out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], 0));
2620         fprintf(fout, "  edx = mul_tmp >> 32;\n");
2621         fprintf(fout, "  eax = mul_tmp;");
2622         last_arith_dst = NULL;
2623         delayed_flag_op = NULL;
2624         break;
2625
2626       case OP_DIV:
2627       case OP_IDIV:
2628         assert_operand_cnt(1);
2629         if (po->operand[0].lmod != OPLM_DWORD)
2630           ferr(po, "unhandled lmod %d\n", po->operand[0].lmod);
2631
2632         // 32bit division is common, look for it
2633         if (po->op == OP_DIV)
2634           ret = scan_for_reg_clear(i - 1, xDX);
2635         else
2636           ret = scan_for_cdq_edx(i - 1);
2637         if (ret >= 0) {
2638           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
2639           strcpy(buf2, lmod_cast(po, po->operand[0].lmod,
2640             po->op == OP_IDIV));
2641           fprintf(fout, "  edx = %seax %% %s%s;\n", buf2, buf2, buf1);
2642           fprintf(fout, "  eax = %seax / %s%s;", buf2, buf2, buf1);
2643         }
2644         else
2645           ferr(po, "TODO 64bit divident\n");
2646         last_arith_dst = NULL;
2647         delayed_flag_op = NULL;
2648         break;
2649
2650       case OP_TEST:
2651       case OP_CMP:
2652         propagate_lmod(po, &po->operand[0], &po->operand[1]);
2653         if (pfomask != 0) {
2654           for (j = 0; j < 8; j++) {
2655             if (pfomask & (1 << j)) {
2656               out_cmp_test(buf1, sizeof(buf1), po, j, 0);
2657               fprintf(fout, "  cond_%s = %s;",
2658                 parsed_flag_op_names[j], buf1);
2659             }
2660           }
2661           pfomask = 0;
2662         }
2663         else
2664           no_output = 1;
2665         delayed_flag_op = po;
2666         break;
2667
2668       // note: we reuse OP_Jcc for SETcc, only flags differ
2669       case OP_JO ... OP_JG:
2670         if (po->flags & OPF_JMP)
2671           fprintf(fout, "    goto %s;", po->operand[0].name);
2672         // else SETcc - should already be handled
2673         break;
2674
2675       case OP_JMP:
2676         assert_operand_cnt(1);
2677         if (po->operand[0].type == OPT_REGMEM) {
2678           ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
2679                   buf1, buf2);
2680           if (ret != 2)
2681             ferr(po, "parse failure for jmp '%s'\n",
2682               po->operand[0].name);
2683           fprintf(fout, "  goto *jt_%s[%s];", buf1, buf2);
2684           break;
2685         }
2686         else if (po->operand[0].type != OPT_LABEL)
2687           ferr(po, "unhandled jmp type\n");
2688
2689         fprintf(fout, "  goto %s;", po->operand[0].name);
2690         break;
2691
2692       case OP_CALL:
2693         assert_operand_cnt(1);
2694         pp = po->datap;
2695         if (pp == NULL)
2696           ferr(po, "NULL pp\n");
2697
2698         if (po->operand[0].type != OPT_LABEL)
2699           fprintf(fout, "  icall%d = (void *)%s;\n", i,
2700             out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0));
2701
2702         fprintf(fout, "  ");
2703         if (!IS(pp->ret_type, "void")) {
2704           if (po->flags & OPF_TAIL)
2705             fprintf(fout, "return ");
2706           else
2707             fprintf(fout, "eax = ");
2708           if (strchr(pp->ret_type, '*'))
2709             fprintf(fout, "(u32)");
2710         }
2711
2712         if (po->operand[0].type != OPT_LABEL) {
2713           fprintf(fout, "icall%d(", i);
2714         }
2715         else {
2716           if (pp->name[0] == 0)
2717             ferr(po, "missing pp->name\n");
2718           fprintf(fout, "%s(", pp->name);
2719         }
2720
2721         for (arg = 0; arg < pp->argc; arg++) {
2722           if (arg > 0)
2723             fprintf(fout, ", ");
2724
2725           if (strchr(pp->arg[arg].type, '*'))
2726             fprintf(fout, "(%s)", pp->arg[arg].type);
2727
2728           if (pp->arg[arg].reg != NULL) {
2729             fprintf(fout, "%s", pp->arg[arg].reg);
2730             continue;
2731           }
2732
2733           // stack arg
2734           tmp_op = pp->arg[arg].datap;
2735           if (tmp_op == NULL)
2736             ferr(po, "parsed_op missing for arg%d\n", arg);
2737           if (tmp_op->argmask) {
2738             fprintf(fout, "s_a%d", arg + 1);
2739           }
2740           else {
2741             fprintf(fout, "%s",
2742               out_src_opr(buf1, sizeof(buf1),
2743                 tmp_op, &tmp_op->operand[0], 0));
2744           }
2745         }
2746         fprintf(fout, ");");
2747
2748         if (po->flags & OPF_TAIL) {
2749           strcpy(g_comment, "tailcall");
2750           if (IS(pp->ret_type, "void"))
2751             fprintf(fout, "\n  return;");
2752         }
2753         delayed_flag_op = NULL;
2754         last_arith_dst = NULL;
2755         break;
2756
2757       case OP_RET:
2758         if (IS(g_func_pp.ret_type, "void"))
2759           fprintf(fout, "  return;");
2760         else if (strchr(g_func_pp.ret_type, '*'))
2761           fprintf(fout, "  return (%s)eax;",
2762             g_func_pp.ret_type);
2763         else
2764           fprintf(fout, "  return eax;");
2765         break;
2766
2767       case OP_PUSH:
2768         if (po->argmask) {
2769           // special case - saved func arg
2770           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
2771           for (j = 0; j < 32; j++) {
2772             if (po->argmask & (1 << j))
2773               fprintf(fout, "  s_a%d = %s;", j + 1, buf1);
2774           }
2775           break;
2776         }
2777         else if (po->flags & OPF_RSAVE) {
2778           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
2779           fprintf(fout, "  s_%s = %s;", buf1, buf1);
2780           break;
2781         }
2782         ferr(po, "stray push encountered\n");
2783         break;
2784
2785       case OP_POP:
2786         if (po->flags & OPF_RSAVE) {
2787           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
2788           fprintf(fout, "  %s = s_%s;", buf1, buf1);
2789           break;
2790         }
2791         ferr(po, "stray pop encountered\n");
2792         break;
2793
2794       case OP_NOP:
2795         break;
2796
2797       default:
2798         no_output = 1;
2799         ferr(po, "unhandled op type %d, flags %x\n",
2800           po->op, po->flags);
2801         break;
2802     }
2803
2804     if (g_comment[0] != 0) {
2805       fprintf(fout, "  // %s", g_comment);
2806       g_comment[0] = 0;
2807       no_output = 0;
2808     }
2809     if (!no_output)
2810       fprintf(fout, "\n");
2811
2812     if (pfomask != 0)
2813         ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
2814
2815     // see is delayed flag stuff is still valid
2816     if (delayed_flag_op != NULL && delayed_flag_op != po) {
2817       if (is_any_opr_modified(delayed_flag_op, po))
2818         delayed_flag_op = NULL;
2819     }
2820
2821     if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
2822       if (is_opr_modified(last_arith_dst, po))
2823         last_arith_dst = NULL;
2824     }
2825   }
2826
2827   fprintf(fout, "}\n\n");
2828
2829   // cleanup
2830   for (i = 0; i < opcnt; i++) {
2831     struct label_ref *lr, *lr_del;
2832
2833     lr = g_label_refs[i].next;
2834     while (lr != NULL) {
2835       lr_del = lr;
2836       lr = lr->next;
2837       free(lr_del);
2838     }
2839     g_label_refs[i].i = -1;
2840     g_label_refs[i].next = NULL;
2841
2842     if (ops[i].op == OP_CALL) {
2843       pp = ops[i].datap;
2844       if (pp) {
2845         proto_release(pp);
2846         free(pp);
2847       }
2848     }
2849   }
2850   proto_release(&g_func_pp);
2851 }
2852
2853 static void set_label(int i, const char *name)
2854 {
2855   const char *p;
2856   int len;
2857
2858   len = strlen(name);
2859   p = strchr(name, ':');
2860   if (p != NULL)
2861     len = p - name;
2862
2863   if (len > sizeof(g_labels[0]) - 1)
2864     aerr("label '%s' too long: %d\n", name, len);
2865   if (g_labels[i][0] != 0)
2866     aerr("dupe label '%s'?\n", name);
2867   memcpy(g_labels[i], name, len);
2868   g_labels[i][len] = 0;
2869 }
2870
2871 // '=' needs special treatment..
2872 static char *next_word_s(char *w, size_t wsize, char *s)
2873 {
2874         size_t i;
2875
2876         s = sskip(s);
2877
2878         for (i = 0; i < wsize - 1; i++) {
2879                 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
2880                         break;
2881                 w[i] = s[i];
2882         }
2883         w[i] = 0;
2884
2885         if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
2886                 printf("warning: '%s' truncated\n", w);
2887
2888         return s + i;
2889 }
2890
2891 static int cmpstringp(const void *p1, const void *p2)
2892 {
2893   return strcmp(*(char * const *)p1, *(char * const *)p2);
2894 }
2895
2896 int main(int argc, char *argv[])
2897 {
2898   FILE *fout, *fasm, *frlist;
2899   struct parsed_data *pd = NULL;
2900   int pd_alloc = 0;
2901   char **rlist = NULL;
2902   int rlist_len = 0;
2903   int rlist_alloc = 0;
2904   char line[256];
2905   char words[16][256];
2906   enum opr_lenmod lmod;
2907   int in_func = 0;
2908   int pending_endp = 0;
2909   int skip_func = 0;
2910   int skip_warned = 0;
2911   int eq_alloc;
2912   int verbose = 0;
2913   int arg_out;
2914   int arg = 1;
2915   int pi = 0;
2916   int i, j, len;
2917   char *p;
2918   int wordc;
2919
2920   if (argv[1] && IS(argv[1], "-v")) {
2921     verbose = 1;
2922     arg++;
2923   }
2924
2925   if (argc < arg + 3) {
2926     printf("usage:\n%s [-v] <.c> <.asm> <hdrf> [rlist]*\n",
2927       argv[0]);
2928     return 1;
2929   }
2930
2931   arg_out = arg++;
2932
2933   asmfn = argv[arg++];
2934   fasm = fopen(asmfn, "r");
2935   my_assert_not(fasm, NULL);
2936
2937   hdrfn = argv[arg++];
2938   g_fhdr = fopen(hdrfn, "r");
2939   my_assert_not(g_fhdr, NULL);
2940
2941   rlist_alloc = 64;
2942   rlist = malloc(rlist_alloc * sizeof(rlist[0]));
2943   my_assert_not(rlist, NULL);
2944   // needs special handling..
2945   rlist[rlist_len++] = "__alloca_probe";
2946
2947   for (; arg < argc; arg++) {
2948     frlist = fopen(argv[arg], "r");
2949     my_assert_not(frlist, NULL);
2950
2951     while (fgets(line, sizeof(line), frlist)) {
2952       p = sskip(line);
2953       if (*p == 0 || *p == ';' || *p == '#')
2954         continue;
2955
2956       p = next_word(words[0], sizeof(words[0]), p);
2957       if (words[0][0] == 0)
2958         continue;
2959
2960       if (rlist_len >= rlist_alloc) {
2961         rlist_alloc = rlist_alloc * 2 + 64;
2962         rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
2963         my_assert_not(rlist, NULL);
2964       }
2965       rlist[rlist_len++] = strdup(words[0]);
2966     }
2967
2968     fclose(frlist);
2969     frlist = NULL;
2970   }
2971
2972   if (rlist_len > 0)
2973     qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
2974
2975   fout = fopen(argv[arg_out], "w");
2976   my_assert_not(fout, NULL);
2977
2978   eq_alloc = 128;
2979   g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
2980   my_assert_not(g_eqs, NULL);
2981
2982   for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
2983     g_label_refs[i].i = -1;
2984     g_label_refs[i].next = NULL;
2985   }
2986
2987   while (fgets(line, sizeof(line), fasm))
2988   {
2989     wordc = 0;
2990     asmln++;
2991
2992     p = sskip(line);
2993     if (*p == 0)
2994       continue;
2995
2996     if (*p == ';') {
2997       static const char *attrs[] = {
2998         "bp-based frame",
2999         "library function",
3000         "static",
3001         "noreturn",
3002         "thunk",
3003         "fpd=",
3004       };
3005       if (p[2] == '=' && IS_START(p, "; =============== S U B"))
3006         goto do_pending_endp; // eww..
3007
3008       if (p[2] != 'A' || !IS_START(p, "; Attributes:"))
3009         continue;
3010
3011       // parse IDA's attribute-list comment
3012       g_ida_func_attr = 0;
3013       p = sskip(p + 13);
3014       // get rid of random tabs
3015       for (i = 0; p[i] != 0; i++)
3016         if (p[i] == '\t')
3017           p[i] = ' ';
3018
3019       for (; *p != 0; p = sskip(p)) {
3020         for (i = 0; i < ARRAY_SIZE(attrs); i++) {
3021           if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
3022             g_ida_func_attr |= 1 << i;
3023             p += strlen(attrs[i]);
3024             break;
3025           }
3026         }
3027         if (i == ARRAY_SIZE(attrs)) {
3028           anote("unparsed IDA attr: %s\n", p);
3029           break;
3030         }
3031         if (IS(attrs[i], "fpd=")) {
3032           p = next_word(words[0], sizeof(words[0]), p);
3033           // ignore for now..
3034         }
3035       }
3036       continue;
3037     }
3038
3039 parse_words:
3040     memset(words, 0, sizeof(words));
3041     for (wordc = 0; wordc < 16; wordc++) {
3042       p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
3043       if (*p == 0 || *p == ';') {
3044         wordc++;
3045         break;
3046       }
3047     }
3048
3049     // alow asm patches in comments
3050     if (*p == ';' && IS_START(p, "; sctpatch: ")) {
3051       p = sskip(p + 12);
3052       if (*p == 0 || *p == ';')
3053         continue;
3054       goto parse_words; // lame
3055     }
3056
3057     if (wordc == 0) {
3058       // shouldn't happen
3059       awarn("wordc == 0?\n");
3060       continue;
3061     }
3062
3063     // don't care about this:
3064     if (words[0][0] == '.'
3065         || IS(words[0], "include")
3066         || IS(words[0], "assume") || IS(words[1], "segment")
3067         || IS(words[0], "align"))
3068     {
3069       continue;
3070     }
3071
3072 do_pending_endp:
3073     // do delayed endp processing to collect switch jumptables
3074     if (pending_endp) {
3075       if (in_func && !skip_func && wordc >= 2
3076           && ((words[0][0] == 'd' && words[0][2] == 0)
3077               || (words[1][0] == 'd' && words[1][2] == 0)))
3078       {
3079         i = 1;
3080         if (words[1][0] == 'd' && words[1][2] == 0) {
3081           // label
3082           if (g_func_pd_cnt >= pd_alloc) {
3083             pd_alloc = pd_alloc * 2 + 16;
3084             g_func_pd = realloc(g_func_pd,
3085               sizeof(g_func_pd[0]) * pd_alloc);
3086             my_assert_not(g_func_pd, NULL);
3087           }
3088           pd = &g_func_pd[g_func_pd_cnt];
3089           g_func_pd_cnt++;
3090           memset(pd, 0, sizeof(*pd));
3091           strcpy(pd->label, words[0]);
3092           pd->type = OPT_CONST;
3093           pd->lmod = lmod_from_directive(words[1]);
3094           i = 2;
3095         }
3096         else {
3097           lmod = lmod_from_directive(words[0]);
3098           if (lmod != pd->lmod)
3099             aerr("lmod change? %d->%d\n", pd->lmod, lmod);
3100         }
3101
3102         if (pd->count_alloc < pd->count + wordc) {
3103           pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
3104           pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
3105           my_assert_not(pd->d, NULL);
3106         }
3107         for (; i < wordc; i++) {
3108           if (IS(words[i], "offset")) {
3109             pd->type = OPT_OFFSET;
3110             i++;
3111           }
3112           p = strchr(words[i], ',');
3113           if (p != NULL)
3114             *p = 0;
3115           if (pd->type == OPT_OFFSET)
3116             pd->d[pd->count].u.label = strdup(words[i]);
3117           else
3118             pd->d[pd->count].u.val = parse_number(words[i]);
3119           pd->d[pd->count].bt_i = -1;
3120           pd->count++;
3121         }
3122         continue;
3123       }
3124
3125       if (in_func && !skip_func)
3126         gen_func(fout, g_fhdr, g_func, pi);
3127
3128       pending_endp = 0;
3129       in_func = 0;
3130       g_ida_func_attr = 0;
3131       skip_warned = 0;
3132       skip_func = 0;
3133       g_func[0] = 0;
3134       if (pi != 0) {
3135         memset(&ops, 0, pi * sizeof(ops[0]));
3136         memset(g_labels, 0, pi * sizeof(g_labels[0]));
3137         pi = 0;
3138       }
3139       g_eqcnt = 0;
3140       for (i = 0; i < g_func_pd_cnt; i++) {
3141         pd = &g_func_pd[i];
3142         if (pd->type == OPT_OFFSET) {
3143           for (j = 0; j < pd->count; j++)
3144             free(pd->d[j].u.label);
3145         }
3146         free(pd->d);
3147         pd->d = NULL;
3148       }
3149       g_func_pd_cnt = 0;
3150       pd = NULL;
3151       if (wordc == 0)
3152         continue;
3153     }
3154
3155     if (IS(words[1], "proc")) {
3156       if (in_func)
3157         aerr("proc '%s' while in_func '%s'?\n",
3158           words[0], g_func);
3159       p = words[0];
3160       if ((g_ida_func_attr & IDAFA_THUNK)
3161        || bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
3162         skip_func = 1;
3163       strcpy(g_func, words[0]);
3164       set_label(0, words[0]);
3165       in_func = 1;
3166       continue;
3167     }
3168
3169     if (IS(words[1], "endp")) {
3170       if (!in_func)
3171         aerr("endp '%s' while not in_func?\n", words[0]);
3172       if (!IS(g_func, words[0]))
3173         aerr("endp '%s' while in_func '%s'?\n",
3174           words[0], g_func);
3175
3176       pending_endp = 1;
3177       continue;
3178     }
3179
3180     p = strchr(words[0], ':');
3181     if (p != NULL) {
3182       set_label(pi, words[0]);
3183       continue;
3184     }
3185
3186     if (!in_func || skip_func) {
3187       if (!skip_warned && !skip_func && g_labels[pi][0] != 0) {
3188         if (verbose)
3189           anote("skipping from '%s'\n", g_labels[pi]);
3190         skip_warned = 1;
3191       }
3192       g_labels[pi][0] = 0;
3193       continue;
3194     }
3195
3196     if (wordc > 1 && IS(words[1], "=")) {
3197       if (wordc != 5)
3198         aerr("unhandled equ, wc=%d\n", wordc);
3199       if (g_eqcnt >= eq_alloc) {
3200         eq_alloc *= 2;
3201         g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
3202         my_assert_not(g_eqs, NULL);
3203       }
3204
3205       len = strlen(words[0]);
3206       if (len > sizeof(g_eqs[0].name) - 1)
3207         aerr("equ name too long: %d\n", len);
3208       strcpy(g_eqs[g_eqcnt].name, words[0]);
3209
3210       if (!IS(words[3], "ptr"))
3211         aerr("unhandled equ\n");
3212       if (IS(words[2], "dword"))
3213         g_eqs[g_eqcnt].lmod = OPLM_DWORD;
3214       else if (IS(words[2], "word"))
3215         g_eqs[g_eqcnt].lmod = OPLM_WORD;
3216       else if (IS(words[2], "byte"))
3217         g_eqs[g_eqcnt].lmod = OPLM_BYTE;
3218       else
3219         aerr("bad lmod: '%s'\n", words[2]);
3220
3221       g_eqs[g_eqcnt].offset = parse_number(words[4]);
3222       g_eqcnt++;
3223       continue;
3224     }
3225
3226     if (pi >= ARRAY_SIZE(ops))
3227       aerr("too many ops\n");
3228
3229     parse_op(&ops[pi], words, wordc);
3230     pi++;
3231   }
3232
3233   fclose(fout);
3234   fclose(fasm);
3235   fclose(g_fhdr);
3236
3237   return 0;
3238 }
3239
3240 // vim:ts=2:shiftwidth=2:expandtab