translate: handle various cases from smacker
[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 #include "masm_tools.h"
30
31 enum op_flags {
32   OPF_RMD    = (1 << 0), /* removed or optimized out */
33   OPF_DATA   = (1 << 1), /* data processing - writes to dst opr */
34   OPF_FLAGS  = (1 << 2), /* sets flags */
35   OPF_JMP    = (1 << 3), /* branch, call */
36   OPF_CJMP   = (1 << 4), /* cond. branch (cc or jecxz) */
37   OPF_CC     = (1 << 5), /* uses flags */
38   OPF_TAIL   = (1 << 6), /* ret or tail call */
39   OPF_RSAVE  = (1 << 7), /* push/pop is local reg save/load */
40   OPF_REP    = (1 << 8), /* prefixed by rep */
41   OPF_REPZ   = (1 << 9), /* rep is repe/repz */
42   OPF_REPNZ  = (1 << 10), /* rep is repne/repnz */
43   OPF_FARG   = (1 << 11), /* push collected as func arg (no reuse) */
44   OPF_EBP_S  = (1 << 12), /* ebp used as scratch here, not BP */
45   OPF_DF     = (1 << 13), /* DF flag set */
46   OPF_ATAIL  = (1 << 14), /* tail call with reused arg frame */
47   OPF_32BIT  = (1 << 15), /* 32bit division */
48   OPF_LOCK   = (1 << 16), /* op has lock prefix */
49 };
50
51 enum op_op {
52         OP_INVAL,
53         OP_NOP,
54         OP_PUSH,
55         OP_POP,
56         OP_LEAVE,
57         OP_MOV,
58         OP_LEA,
59         OP_MOVZX,
60         OP_MOVSX,
61         OP_XCHG,
62         OP_NOT,
63         OP_CDQ,
64         OP_STOS,
65         OP_MOVS,
66         OP_CMPS,
67         OP_SCAS,
68         OP_STD,
69         OP_CLD,
70         OP_RET,
71         OP_ADD,
72         OP_SUB,
73         OP_AND,
74         OP_OR,
75         OP_XOR,
76         OP_SHL,
77         OP_SHR,
78         OP_SAR,
79         OP_ROL,
80         OP_ROR,
81         OP_RCL,
82         OP_RCR,
83         OP_ADC,
84         OP_SBB,
85         OP_INC,
86         OP_DEC,
87         OP_NEG,
88         OP_MUL,
89         OP_IMUL,
90         OP_DIV,
91         OP_IDIV,
92         OP_TEST,
93         OP_CMP,
94         OP_CALL,
95         OP_JMP,
96         OP_JECXZ,
97         OP_JO,
98         OP_JNO,
99         OP_JC,
100         OP_JNC,
101         OP_JZ,
102         OP_JNZ,
103         OP_JBE,
104         OP_JA,
105         OP_JS,
106         OP_JNS,
107         OP_JP,
108         OP_JNP,
109         OP_JL,
110         OP_JGE,
111         OP_JLE,
112         OP_JG,
113 };
114
115 enum opr_type {
116   OPT_UNSPEC,
117   OPT_REG,
118   OPT_REGMEM,
119   OPT_LABEL,
120   OPT_OFFSET,
121   OPT_CONST,
122 };
123
124 // must be sorted (larger len must be further in enum)
125 enum opr_lenmod {
126         OPLM_UNSPEC,
127         OPLM_BYTE,
128         OPLM_WORD,
129         OPLM_DWORD,
130 };
131
132 #define MAX_OPERANDS 3
133
134 struct parsed_opr {
135   enum opr_type type;
136   enum opr_lenmod lmod;
137   unsigned int is_ptr:1;   // pointer in C
138   unsigned int is_array:1; // array in C
139   unsigned int type_from_var:1; // .. in header, sometimes wrong
140   unsigned int size_mismatch:1; // type override differs from C
141   unsigned int size_lt:1;  // type override is larger than C
142   unsigned int had_ds:1;   // had ds: prefix
143   int reg;
144   unsigned int val;
145   char name[256];
146 };
147
148 struct parsed_op {
149   enum op_op op;
150   struct parsed_opr operand[MAX_OPERANDS];
151   unsigned int flags;
152   int operand_cnt;
153   int regmask_src;        // all referensed regs
154   int regmask_dst;
155   int pfomask;            // flagop: parsed_flag_op that can't be delayed
156   int argnum;             // push: altered before call arg #
157   int cc_scratch;         // scratch storage during analysis
158   int bt_i;               // branch target for branches
159   struct parsed_data *btj;// branch targets for jumptables
160   void *datap;
161 };
162
163 // datap:
164 // OP_CALL - parser proto hint (str), ptr to struct parsed_proto
165 // (OPF_CC) - point to one of (OPF_FLAGS) that affects cc op
166 // OP_POP - point to OP_PUSH in push/pop pair
167
168 struct parsed_equ {
169   char name[64];
170   enum opr_lenmod lmod;
171   int offset;
172 };
173
174 struct parsed_data {
175   char label[256];
176   enum opr_type type;
177   enum opr_lenmod lmod;
178   int count;
179   int count_alloc;
180   struct {
181     union {
182       char *label;
183       unsigned int val;
184     } u;
185     int bt_i;
186   } *d;
187 };
188
189 struct label_ref {
190   int i;
191   struct label_ref *next;
192 };
193
194 enum ida_func_attr {
195   IDAFA_BP_FRAME = (1 << 0),
196   IDAFA_LIB_FUNC = (1 << 1),
197   IDAFA_STATIC   = (1 << 2),
198   IDAFA_NORETURN = (1 << 3),
199   IDAFA_THUNK    = (1 << 4),
200   IDAFA_FPD      = (1 << 5),
201 };
202
203 #define MAX_OPS 4096
204
205 static struct parsed_op ops[MAX_OPS];
206 static struct parsed_equ *g_eqs;
207 static int g_eqcnt;
208 static char g_labels[MAX_OPS][48];
209 static struct label_ref g_label_refs[MAX_OPS];
210 static const struct parsed_proto *g_func_pp;
211 static struct parsed_data *g_func_pd;
212 static int g_func_pd_cnt;
213 static char g_func[256];
214 static char g_comment[256];
215 static int g_bp_frame;
216 static int g_sp_frame;
217 static int g_stack_frame_used;
218 static int g_stack_fsz;
219 static int g_ida_func_attr;
220 static int g_allow_regfunc;
221 #define ferr(op_, fmt, ...) do { \
222   printf("error:%s:#%zd: '%s': " fmt, g_func, (op_) - ops, \
223     dump_op(op_), ##__VA_ARGS__); \
224   fcloseall(); \
225   exit(1); \
226 } while (0)
227 #define fnote(op_, fmt, ...) \
228   printf("error:%s:#%zd: '%s': " fmt, g_func, (op_) - ops, \
229     dump_op(op_), ##__VA_ARGS__)
230
231 #define MAX_REGS 8
232
233 const char *regs_r32[] = { "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp" };
234 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
235 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
236 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
237
238 enum x86_regs { xUNSPEC = -1, xAX, xBX, xCX, xDX, xSI, xDI, xBP, xSP };
239
240 // possible basic comparison types (without inversion)
241 enum parsed_flag_op {
242   PFO_O,  // 0 OF=1
243   PFO_C,  // 2 CF=1
244   PFO_Z,  // 4 ZF=1
245   PFO_BE, // 6 CF=1||ZF=1
246   PFO_S,  // 8 SF=1
247   PFO_P,  // a PF=1
248   PFO_L,  // c SF!=OF
249   PFO_LE, // e ZF=1||SF!=OF
250 };
251
252 static const char *parsed_flag_op_names[] = {
253   "o", "c", "z", "be", "s", "p", "l", "le"
254 };
255
256 static int char_array_i(const char *array[], size_t len, const char *s)
257 {
258   int i;
259
260   for (i = 0; i < len; i++)
261     if (IS(s, array[i]))
262       return i;
263
264   return -1;
265 }
266
267 static void printf_number(char *buf, size_t buf_size,
268   unsigned long number)
269 {
270   // output in C-friendly form
271   snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
272 }
273
274 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
275 {
276   int reg;
277
278   reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
279   if (reg >= 0) {
280     *reg_lmod = OPLM_DWORD;
281     return reg;
282   }
283   reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
284   if (reg >= 0) {
285     *reg_lmod = OPLM_WORD;
286     return reg;
287   }
288   reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
289   if (reg >= 0) {
290     *reg_lmod = OPLM_BYTE;
291     return reg;
292   }
293   reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
294   if (reg >= 0) {
295     *reg_lmod = OPLM_BYTE;
296     return reg;
297   }
298
299   return -1;
300 }
301
302 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
303 {
304   enum opr_lenmod lmod;
305   char cvtbuf[256];
306   char *d = cvtbuf;
307   char *s = name;
308   char w[64];
309   long number;
310   int reg;
311   int c = 0;
312
313   *d = 0;
314
315   while (*s != 0) {
316     d += strlen(d);
317     while (my_isblank(*s))
318       s++;
319     for (; my_issep(*s); d++, s++)
320       *d = *s;
321     while (my_isblank(*s))
322       s++;
323     *d = 0;
324
325     // skip 'ds:' prefix
326     if (IS_START(s, "ds:"))
327       s += 3;
328
329     s = next_idt(w, sizeof(w), s);
330     if (w[0] == 0)
331       break;
332     c++;
333
334     reg = parse_reg(&lmod, w);
335     if (reg >= 0) {
336       *regmask |= 1 << reg;
337       goto pass;
338     }
339
340     if ('0' <= w[0] && w[0] <= '9') {
341       number = parse_number(w);
342       printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
343       continue;
344     }
345
346     // probably some label/identifier - pass
347
348 pass:
349     snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
350   }
351
352   if (need_c_cvt)
353     strcpy(name, cvtbuf);
354
355   return c;
356 }
357
358 static int is_reg_in_str(const char *s)
359 {
360   int i;
361
362   if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
363     return 0;
364
365   for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
366     if (!strncmp(s, regs_r32[i], 3))
367       return 1;
368
369   return 0;
370 }
371
372 static const char *parse_stack_el(const char *name, char *extra_reg)
373 {
374   const char *p, *p2, *s;
375   char *endp = NULL;
376   char buf[32];
377   long val;
378   int len;
379
380   p = name;
381   if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
382     p += 4;
383     if (extra_reg != NULL) {
384       strncpy(extra_reg, name, 3);
385       extra_reg[4] = 0;
386     }
387   }
388
389   if (IS_START(p, "ebp+")) {
390     p += 4;
391
392     p2 = strchr(p, '+');
393     if (p2 != NULL && is_reg_in_str(p)) {
394       if (extra_reg != NULL) {
395         strncpy(extra_reg, p, p2 - p);
396         extra_reg[p2 - p] = 0;
397       }
398       p = p2 + 1;
399     }
400
401     if (!('0' <= *p && *p <= '9'))
402       return p;
403
404     return NULL;
405   }
406
407   if (!IS_START(name, "esp+"))
408     return NULL;
409
410   s = name + 4;
411   p = strchr(s, '+');
412   if (p) {
413     if (is_reg_in_str(s)) {
414       if (extra_reg != NULL) {
415         strncpy(extra_reg, s, p - s);
416         extra_reg[p - s] = 0;
417       }
418       s = p + 1;
419       p = strchr(s, '+');
420       if (p == NULL)
421         aerr("%s IDA stackvar not set?\n", __func__);
422     }
423     if (!('0' <= *s && *s <= '9')) {
424       aerr("%s IDA stackvar offset not set?\n", __func__);
425       return NULL;
426     }
427     if (s[0] == '0' && s[1] == 'x')
428       s += 2;
429     len = p - s;
430     if (len < sizeof(buf) - 1) {
431       strncpy(buf, s, len);
432       buf[len] = 0;
433       val = strtol(buf, &endp, 16);
434       if (val == 0 || *endp != 0) {
435         aerr("%s num parse fail for '%s'\n", __func__, buf);
436         return NULL;
437       }
438     }
439     p++;
440   }
441   else
442     p = name + 4;
443
444   if ('0' <= *p && *p <= '9')
445     return NULL;
446
447   return p;
448 }
449
450 static int guess_lmod_from_name(struct parsed_opr *opr)
451 {
452   if (!strncmp(opr->name, "dword_", 6)) {
453     opr->lmod = OPLM_DWORD;
454     return 1;
455   }
456   if (!strncmp(opr->name, "word_", 5)) {
457     opr->lmod = OPLM_WORD;
458     return 1;
459   }
460   if (!strncmp(opr->name, "byte_", 5)) {
461     opr->lmod = OPLM_BYTE;
462     return 1;
463   }
464   return 0;
465 }
466
467 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
468   const struct parsed_type *c_type)
469 {
470   static const char *dword_types[] = {
471     "int", "_DWORD", "UINT_PTR", "DWORD",
472     "WPARAM", "LPARAM", "UINT", "__int32",
473     "LONG", "HIMC",
474   };
475   static const char *word_types[] = {
476     "uint16_t", "int16_t", "_WORD",
477     "unsigned __int16", "__int16",
478   };
479   static const char *byte_types[] = {
480     "uint8_t", "int8_t", "char",
481     "unsigned __int8", "__int8", "BYTE", "_BYTE",
482     "CHAR", "_UNKNOWN",
483   };
484   const char *n;
485   int i;
486
487   if (c_type->is_ptr) {
488     *lmod = OPLM_DWORD;
489     return 1;
490   }
491
492   n = skip_type_mod(c_type->name);
493
494   for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
495     if (IS(n, dword_types[i])) {
496       *lmod = OPLM_DWORD;
497       return 1;
498     }
499   }
500
501   for (i = 0; i < ARRAY_SIZE(word_types); i++) {
502     if (IS(n, word_types[i])) {
503       *lmod = OPLM_WORD;
504       return 1;
505     }
506   }
507
508   for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
509     if (IS(n, byte_types[i])) {
510       *lmod = OPLM_BYTE;
511       return 1;
512     }
513   }
514
515   return 0;
516 }
517
518 static enum opr_type lmod_from_directive(const char *d)
519 {
520   if (IS(d, "dd"))
521     return OPLM_DWORD;
522   else if (IS(d, "dw"))
523     return OPLM_WORD;
524   else if (IS(d, "db"))
525     return OPLM_BYTE;
526
527   aerr("unhandled directive: '%s'\n", d);
528   return OPLM_UNSPEC;
529 }
530
531 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
532   int *regmask)
533 {
534   opr->type = OPT_REG;
535   opr->reg = reg;
536   opr->lmod = lmod;
537   *regmask |= 1 << reg;
538 }
539
540 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
541   int *extra_offs);
542
543 static int parse_operand(struct parsed_opr *opr,
544   int *regmask, int *regmask_indirect,
545   char words[16][256], int wordc, int w, unsigned int op_flags)
546 {
547   const struct parsed_proto *pp;
548   enum opr_lenmod tmplmod;
549   unsigned long number;
550   char buf[256];
551   int ret, len;
552   int wordc_in;
553   char *p;
554   int i;
555
556   if (w >= wordc)
557     aerr("parse_operand w %d, wordc %d\n", w, wordc);
558
559   opr->reg = xUNSPEC;
560
561   for (i = w; i < wordc; i++) {
562     len = strlen(words[i]);
563     if (words[i][len - 1] == ',') {
564       words[i][len - 1] = 0;
565       wordc = i + 1;
566       break;
567     }
568   }
569
570   wordc_in = wordc - w;
571
572   if ((op_flags & OPF_JMP) && wordc_in > 0
573       && !('0' <= words[w][0] && words[w][0] <= '9'))
574   {
575     const char *label = NULL;
576
577     if (wordc_in == 3 && !strncmp(words[w], "near", 4)
578      && IS(words[w + 1], "ptr"))
579       label = words[w + 2];
580     else if (wordc_in == 2 && IS(words[w], "short"))
581       label = words[w + 1];
582     else if (wordc_in == 1
583           && strchr(words[w], '[') == NULL
584           && parse_reg(&tmplmod, words[w]) < 0)
585       label = words[w];
586
587     if (label != NULL) {
588       opr->type = OPT_LABEL;
589       if (IS_START(label, "ds:")) {
590         opr->had_ds = 1;
591         label += 3;
592       }
593       strcpy(opr->name, label);
594       return wordc;
595     }
596   }
597
598   if (wordc_in >= 3) {
599     if (IS(words[w + 1], "ptr")) {
600       if (IS(words[w], "dword"))
601         opr->lmod = OPLM_DWORD;
602       else if (IS(words[w], "word"))
603         opr->lmod = OPLM_WORD;
604       else if (IS(words[w], "byte"))
605         opr->lmod = OPLM_BYTE;
606       else
607         aerr("type parsing failed\n");
608       w += 2;
609       wordc_in = wordc - w;
610     }
611   }
612
613   if (wordc_in == 2) {
614     if (IS(words[w], "offset")) {
615       opr->type = OPT_OFFSET;
616       strcpy(opr->name, words[w + 1]);
617       return wordc;
618     }
619     if (IS(words[w], "(offset")) {
620       p = strchr(words[w + 1], ')');
621       if (p == NULL)
622         aerr("parse of bracketed offset failed\n");
623       *p = 0;
624       opr->type = OPT_OFFSET;
625       strcpy(opr->name, words[w + 1]);
626       return wordc;
627     }
628   }
629
630   if (wordc_in != 1)
631     aerr("parse_operand 1 word expected\n");
632
633   if (IS_START(words[w], "ds:")) {
634     opr->had_ds = 1;
635     memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
636   }
637   strcpy(opr->name, words[w]);
638
639   if (words[w][0] == '[') {
640     opr->type = OPT_REGMEM;
641     ret = sscanf(words[w], "[%[^]]]", opr->name);
642     if (ret != 1)
643       aerr("[] parse failure\n");
644
645     parse_indmode(opr->name, regmask_indirect, 1);
646     if (opr->lmod == OPLM_UNSPEC && parse_stack_el(opr->name, NULL)) {
647       // might be an equ
648       struct parsed_equ *eq =
649         equ_find(NULL, parse_stack_el(opr->name, NULL), &i);
650       if (eq)
651         opr->lmod = eq->lmod;
652     }
653     return wordc;
654   }
655   else if (strchr(words[w], '[')) {
656     // label[reg] form
657     p = strchr(words[w], '[');
658     opr->type = OPT_REGMEM;
659     parse_indmode(p, regmask_indirect, 0);
660     strncpy(buf, words[w], p - words[w]);
661     buf[p - words[w]] = 0;
662     pp = proto_parse(g_fhdr, buf, 1);
663     goto do_label;
664   }
665   else if (('0' <= words[w][0] && words[w][0] <= '9')
666     || words[w][0] == '-')
667   {
668     number = parse_number(words[w]);
669     opr->type = OPT_CONST;
670     opr->val = number;
671     printf_number(opr->name, sizeof(opr->name), number);
672     return wordc;
673   }
674
675   ret = parse_reg(&tmplmod, opr->name);
676   if (ret >= 0) {
677     setup_reg_opr(opr, ret, tmplmod, regmask);
678     return wordc;
679   }
680
681   // most likely var in data segment
682   opr->type = OPT_LABEL;
683   pp = proto_parse(g_fhdr, opr->name, 0);
684
685 do_label:
686   if (pp != NULL) {
687     if (pp->is_fptr || pp->is_func) {
688       opr->lmod = OPLM_DWORD;
689       opr->is_ptr = 1;
690     }
691     else {
692       tmplmod = OPLM_UNSPEC;
693       if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
694         anote("unhandled C type '%s' for '%s'\n",
695           pp->type.name, opr->name);
696       
697       if (opr->lmod == OPLM_UNSPEC) {
698         opr->lmod = tmplmod;
699         opr->type_from_var = 1;
700       }
701       else if (opr->lmod != tmplmod) {
702         opr->size_mismatch = 1;
703         if (tmplmod < opr->lmod)
704           opr->size_lt = 1;
705       }
706       opr->is_ptr = pp->type.is_ptr;
707     }
708     opr->is_array = pp->type.is_array;
709   }
710
711   if (opr->lmod == OPLM_UNSPEC)
712     guess_lmod_from_name(opr);
713   return wordc;
714 }
715
716 static const struct {
717   const char *name;
718   unsigned int flags;
719 } pref_table[] = {
720   { "rep",    OPF_REP },
721   { "repe",   OPF_REP|OPF_REPZ },
722   { "repz",   OPF_REP|OPF_REPZ },
723   { "repne",  OPF_REP|OPF_REPNZ },
724   { "repnz",  OPF_REP|OPF_REPNZ },
725   { "lock",   OPF_LOCK }, // ignored for now..
726 };
727
728 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
729
730 static const struct {
731   const char *name;
732   enum op_op op;
733   unsigned int minopr;
734   unsigned int maxopr;
735   unsigned int flags;
736 } op_table[] = {
737   { "nop",  OP_NOP,    0, 0, 0 },
738   { "push", OP_PUSH,   1, 1, 0 },
739   { "pop",  OP_POP,    1, 1, OPF_DATA },
740   { "leave",OP_LEAVE,  0, 0, OPF_DATA },
741   { "mov" , OP_MOV,    2, 2, OPF_DATA },
742   { "lea",  OP_LEA,    2, 2, OPF_DATA },
743   { "movzx",OP_MOVZX,  2, 2, OPF_DATA },
744   { "movsx",OP_MOVSX,  2, 2, OPF_DATA },
745   { "xchg", OP_XCHG,   2, 2, OPF_DATA },
746   { "not",  OP_NOT,    1, 1, OPF_DATA },
747   { "cdq",  OP_CDQ,    0, 0, OPF_DATA },
748   { "stosb",OP_STOS,   0, 0, OPF_DATA },
749   { "stosw",OP_STOS,   0, 0, OPF_DATA },
750   { "stosd",OP_STOS,   0, 0, OPF_DATA },
751   { "movsb",OP_MOVS,   0, 0, OPF_DATA },
752   { "movsw",OP_MOVS,   0, 0, OPF_DATA },
753   { "movsd",OP_MOVS,   0, 0, OPF_DATA },
754   { "cmpsb",OP_CMPS,   0, 0, OPF_DATA|OPF_FLAGS },
755   { "cmpsw",OP_CMPS,   0, 0, OPF_DATA|OPF_FLAGS },
756   { "cmpsd",OP_CMPS,   0, 0, OPF_DATA|OPF_FLAGS },
757   { "scasb",OP_SCAS,   0, 0, OPF_DATA|OPF_FLAGS },
758   { "scasw",OP_SCAS,   0, 0, OPF_DATA|OPF_FLAGS },
759   { "scasd",OP_SCAS,   0, 0, OPF_DATA|OPF_FLAGS },
760   { "std",  OP_STD,    0, 0, OPF_DATA }, // special flag
761   { "cld",  OP_CLD,    0, 0, OPF_DATA },
762   { "add",  OP_ADD,    2, 2, OPF_DATA|OPF_FLAGS },
763   { "sub",  OP_SUB,    2, 2, OPF_DATA|OPF_FLAGS },
764   { "and",  OP_AND,    2, 2, OPF_DATA|OPF_FLAGS },
765   { "or",   OP_OR,     2, 2, OPF_DATA|OPF_FLAGS },
766   { "xor",  OP_XOR,    2, 2, OPF_DATA|OPF_FLAGS },
767   { "shl",  OP_SHL,    2, 2, OPF_DATA|OPF_FLAGS },
768   { "shr",  OP_SHR,    2, 2, OPF_DATA|OPF_FLAGS },
769   { "sal",  OP_SHL,    2, 2, OPF_DATA|OPF_FLAGS },
770   { "sar",  OP_SAR,    2, 2, OPF_DATA|OPF_FLAGS },
771   { "rol",  OP_ROL,    2, 2, OPF_DATA|OPF_FLAGS },
772   { "ror",  OP_ROR,    2, 2, OPF_DATA|OPF_FLAGS },
773   { "rcl",  OP_RCL,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
774   { "rcr",  OP_RCR,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
775   { "adc",  OP_ADC,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
776   { "sbb",  OP_SBB,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
777   { "inc",  OP_INC,    1, 1, OPF_DATA|OPF_FLAGS },
778   { "dec",  OP_DEC,    1, 1, OPF_DATA|OPF_FLAGS },
779   { "neg",  OP_NEG,    1, 1, OPF_DATA|OPF_FLAGS },
780   { "mul",  OP_MUL,    1, 1, OPF_DATA|OPF_FLAGS },
781   { "imul", OP_IMUL,   1, 3, OPF_DATA|OPF_FLAGS },
782   { "div",  OP_DIV,    1, 1, OPF_DATA|OPF_FLAGS },
783   { "idiv", OP_IDIV,   1, 1, OPF_DATA|OPF_FLAGS },
784   { "test", OP_TEST,   2, 2, OPF_FLAGS },
785   { "cmp",  OP_CMP,    2, 2, OPF_FLAGS },
786   { "retn", OP_RET,    0, 1, OPF_TAIL },
787   { "call", OP_CALL,   1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
788   { "jmp",  OP_JMP,    1, 1, OPF_JMP },
789   { "jecxz",OP_JECXZ,  1, 1, OPF_JMP|OPF_CJMP },
790   { "jo",   OP_JO,     1, 1, OPF_CJMP_CC }, // 70 OF=1
791   { "jno",  OP_JNO,    1, 1, OPF_CJMP_CC }, // 71 OF=0
792   { "jc",   OP_JC,     1, 1, OPF_CJMP_CC }, // 72 CF=1
793   { "jb",   OP_JC,     1, 1, OPF_CJMP_CC }, // 72
794   { "jnc",  OP_JNC,    1, 1, OPF_CJMP_CC }, // 73 CF=0
795   { "jnb",  OP_JNC,    1, 1, OPF_CJMP_CC }, // 73
796   { "jae",  OP_JNC,    1, 1, OPF_CJMP_CC }, // 73
797   { "jz",   OP_JZ,     1, 1, OPF_CJMP_CC }, // 74 ZF=1
798   { "je",   OP_JZ,     1, 1, OPF_CJMP_CC }, // 74
799   { "jnz",  OP_JNZ,    1, 1, OPF_CJMP_CC }, // 75 ZF=0
800   { "jne",  OP_JNZ,    1, 1, OPF_CJMP_CC }, // 75
801   { "jbe",  OP_JBE,    1, 1, OPF_CJMP_CC }, // 76 CF=1 || ZF=1
802   { "jna",  OP_JBE,    1, 1, OPF_CJMP_CC }, // 76
803   { "ja",   OP_JA,     1, 1, OPF_CJMP_CC }, // 77 CF=0 && ZF=0
804   { "jnbe", OP_JA,     1, 1, OPF_CJMP_CC }, // 77
805   { "js",   OP_JS,     1, 1, OPF_CJMP_CC }, // 78 SF=1
806   { "jns",  OP_JNS,    1, 1, OPF_CJMP_CC }, // 79 SF=0
807   { "jp",   OP_JP,     1, 1, OPF_CJMP_CC }, // 7a PF=1
808   { "jpe",  OP_JP,     1, 1, OPF_CJMP_CC }, // 7a
809   { "jnp",  OP_JNP,    1, 1, OPF_CJMP_CC }, // 7b PF=0
810   { "jpo",  OP_JNP,    1, 1, OPF_CJMP_CC }, // 7b
811   { "jl",   OP_JL,     1, 1, OPF_CJMP_CC }, // 7c SF!=OF
812   { "jnge", OP_JL,     1, 1, OPF_CJMP_CC }, // 7c
813   { "jge",  OP_JGE,    1, 1, OPF_CJMP_CC }, // 7d SF=OF
814   { "jnl",  OP_JGE,    1, 1, OPF_CJMP_CC }, // 7d
815   { "jle",  OP_JLE,    1, 1, OPF_CJMP_CC }, // 7e ZF=1 || SF!=OF
816   { "jng",  OP_JLE,    1, 1, OPF_CJMP_CC }, // 7e
817   { "jg",   OP_JG,     1, 1, OPF_CJMP_CC }, // 7f ZF=0 && SF=OF
818   { "jnle", OP_JG,     1, 1, OPF_CJMP_CC }, // 7f
819   { "seto",   OP_JO,   1, 1, OPF_DATA|OPF_CC },
820   { "setno",  OP_JNO,  1, 1, OPF_DATA|OPF_CC },
821   { "setc",   OP_JC,   1, 1, OPF_DATA|OPF_CC },
822   { "setb",   OP_JC,   1, 1, OPF_DATA|OPF_CC },
823   { "setnc",  OP_JNC,  1, 1, OPF_DATA|OPF_CC },
824   { "setae",  OP_JNC,  1, 1, OPF_DATA|OPF_CC },
825   { "setz",   OP_JZ,   1, 1, OPF_DATA|OPF_CC },
826   { "sete",   OP_JZ,   1, 1, OPF_DATA|OPF_CC },
827   { "setnz",  OP_JNZ,  1, 1, OPF_DATA|OPF_CC },
828   { "setne",  OP_JNZ,  1, 1, OPF_DATA|OPF_CC },
829   { "setbe",  OP_JBE,  1, 1, OPF_DATA|OPF_CC },
830   { "setna",  OP_JBE,  1, 1, OPF_DATA|OPF_CC },
831   { "seta",   OP_JA,   1, 1, OPF_DATA|OPF_CC },
832   { "setnbe", OP_JA,   1, 1, OPF_DATA|OPF_CC },
833   { "sets",   OP_JS,   1, 1, OPF_DATA|OPF_CC },
834   { "setns",  OP_JNS,  1, 1, OPF_DATA|OPF_CC },
835   { "setp",   OP_JP,   1, 1, OPF_DATA|OPF_CC },
836   { "setpe",  OP_JP,   1, 1, OPF_DATA|OPF_CC },
837   { "setnp",  OP_JNP,  1, 1, OPF_DATA|OPF_CC },
838   { "setpo",  OP_JNP,  1, 1, OPF_DATA|OPF_CC },
839   { "setl",   OP_JL,   1, 1, OPF_DATA|OPF_CC },
840   { "setnge", OP_JL,   1, 1, OPF_DATA|OPF_CC },
841   { "setge",  OP_JGE,  1, 1, OPF_DATA|OPF_CC },
842   { "setnl",  OP_JGE,  1, 1, OPF_DATA|OPF_CC },
843   { "setle",  OP_JLE,  1, 1, OPF_DATA|OPF_CC },
844   { "setng",  OP_JLE,  1, 1, OPF_DATA|OPF_CC },
845   { "setg",   OP_JG,   1, 1, OPF_DATA|OPF_CC },
846   { "setnle", OP_JG,   1, 1, OPF_DATA|OPF_CC },
847 };
848
849 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
850 {
851   enum opr_lenmod lmod = OPLM_UNSPEC;
852   int prefix_flags = 0;
853   int regmask_ind;
854   int regmask;
855   int op_w = 0;
856   int opr = 0;
857   int w = 0;
858   int i;
859
860   for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
861     if (IS(words[w], pref_table[i].name)) {
862       prefix_flags = pref_table[i].flags;
863       break;
864     }
865   }
866
867   if (prefix_flags) {
868     if (wordc <= 1)
869       aerr("lone prefix: '%s'\n", words[0]);
870     w++;
871   }
872
873   op_w = w;
874   for (i = 0; i < ARRAY_SIZE(op_table); i++) {
875     if (IS(words[w], op_table[i].name))
876       break;
877   }
878
879   if (i == ARRAY_SIZE(op_table))
880     aerr("unhandled op: '%s'\n", words[0]);
881   w++;
882
883   op->op = op_table[i].op;
884   op->flags = op_table[i].flags | prefix_flags;
885   op->regmask_src = op->regmask_dst = 0;
886
887   for (opr = 0; opr < op_table[i].minopr; opr++) {
888     regmask = regmask_ind = 0;
889     w = parse_operand(&op->operand[opr], &regmask, &regmask_ind,
890       words, wordc, w, op->flags);
891
892     if (opr == 0 && (op->flags & OPF_DATA))
893       op->regmask_dst = regmask;
894     // for now, mark dst as src too
895     op->regmask_src |= regmask | regmask_ind;
896   }
897
898   for (; w < wordc && opr < op_table[i].maxopr; opr++) {
899     w = parse_operand(&op->operand[opr],
900       &op->regmask_src, &op->regmask_src,
901       words, wordc, w, op->flags);
902   }
903
904   if (w < wordc)
905     aerr("parse_op %s incomplete: %d/%d\n",
906       words[0], w, wordc);
907
908   // special cases
909   op->operand_cnt = opr;
910   if (!strncmp(op_table[i].name, "set", 3))
911     op->operand[0].lmod = OPLM_BYTE;
912
913   // ops with implicit argumets
914   switch (op->op) {
915   case OP_CDQ:
916     op->operand_cnt = 2;
917     setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
918     setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
919     break;
920
921   case OP_STOS:
922   case OP_SCAS:
923     if (op->operand_cnt != 0)
924       break;
925     if      (words[op_w][4] == 'b')
926       lmod = OPLM_BYTE;
927     else if (words[op_w][4] == 'w')
928       lmod = OPLM_WORD;
929     else if (words[op_w][4] == 'd')
930       lmod = OPLM_DWORD;
931     op->operand_cnt = 3;
932     setup_reg_opr(&op->operand[0], xDI, lmod, &op->regmask_src);
933     setup_reg_opr(&op->operand[1], xCX, OPLM_DWORD, &op->regmask_src);
934     op->regmask_dst = op->regmask_src;
935     setup_reg_opr(&op->operand[2], xAX, OPLM_DWORD, &op->regmask_src);
936     break;
937
938   case OP_MOVS:
939   case OP_CMPS:
940     if (op->operand_cnt != 0)
941       break;
942     if      (words[op_w][4] == 'b')
943       lmod = OPLM_BYTE;
944     else if (words[op_w][4] == 'w')
945       lmod = OPLM_WORD;
946     else if (words[op_w][4] == 'd')
947       lmod = OPLM_DWORD;
948     op->operand_cnt = 3;
949     setup_reg_opr(&op->operand[0], xDI, lmod, &op->regmask_src);
950     setup_reg_opr(&op->operand[1], xSI, OPLM_DWORD, &op->regmask_src);
951     setup_reg_opr(&op->operand[2], xCX, OPLM_DWORD, &op->regmask_src);
952     op->regmask_dst = op->regmask_src;
953     break;
954
955   case OP_XCHG:
956     op->regmask_src |= op->regmask_dst;
957     op->regmask_dst |= op->regmask_src;
958     break;
959
960   case OP_JECXZ:
961     op->operand_cnt = 1;
962     op->regmask_src = 1 << xCX;
963     op->operand[0].type = OPT_REG;
964     op->operand[0].reg = xCX;
965     op->operand[0].lmod = OPLM_DWORD;
966     break;
967
968   case OP_IMUL:
969     if (op->operand_cnt != 1)
970       break;
971     // fallthrough
972   case OP_MUL:
973     // singleop mul
974     op->regmask_dst = (1 << xDX) | (1 << xAX);
975     op->regmask_src |= (1 << xAX);
976     if (op->operand[0].lmod == OPLM_UNSPEC)
977       op->operand[0].lmod = OPLM_DWORD;
978     break;
979
980   case OP_DIV:
981   case OP_IDIV:
982     // we could set up operands for edx:eax, but there is no real need to
983     // (see is_opr_modified())
984     regmask = (1 << xDX) | (1 << xAX);
985     op->regmask_dst = regmask;
986     op->regmask_src |= regmask;
987     if (op->operand[0].lmod == OPLM_UNSPEC)
988       op->operand[0].lmod = OPLM_DWORD;
989     break;
990
991   case OP_SHL:
992   case OP_SHR:
993   case OP_SAR:
994   case OP_ROL:
995   case OP_ROR:
996     if (op->operand[1].lmod == OPLM_UNSPEC)
997       op->operand[1].lmod = OPLM_BYTE;
998     break;
999
1000   case OP_PUSH:
1001     if (op->operand[0].lmod == OPLM_UNSPEC
1002         && (op->operand[0].type == OPT_CONST
1003          || op->operand[0].type == OPT_OFFSET
1004          || op->operand[0].type == OPT_LABEL))
1005       op->operand[0].lmod = OPLM_DWORD;
1006     break;
1007
1008   // alignment
1009   case OP_MOV:
1010     if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1011      && op->operand[0].reg == xDI && op->operand[1].reg == xDI)
1012     {
1013       op->flags |= OPF_RMD;
1014     }
1015     break;
1016
1017   case OP_LEA:
1018     if (op->operand[0].type == OPT_REG
1019      && op->operand[1].type == OPT_REGMEM)
1020     {
1021       char buf[16];
1022       snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1023       if (IS(buf, op->operand[1].name))
1024         op->flags |= OPF_RMD;
1025     }
1026     break;
1027
1028   case OP_CALL:
1029     // trashed regs must be explicitly detected later
1030     op->regmask_dst = 0;
1031     break;
1032
1033   default:
1034     break;
1035   }
1036 }
1037
1038 static const char *op_name(enum op_op op)
1039 {
1040   int i;
1041
1042   for (i = 0; i < ARRAY_SIZE(op_table); i++)
1043     if (op_table[i].op == op)
1044       return op_table[i].name;
1045
1046   return "???";
1047 }
1048
1049 // debug
1050 static const char *dump_op(struct parsed_op *po)
1051 {
1052   static char out[128];
1053   char *p = out;
1054   int i;
1055
1056   if (po == NULL)
1057     return "???";
1058
1059   snprintf(out, sizeof(out), "%s", op_name(po->op));
1060   for (i = 0; i < po->operand_cnt; i++) {
1061     p += strlen(p);
1062     if (i > 0)
1063       *p++ = ',';
1064     snprintf(p, sizeof(out) - (p - out),
1065       po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1066       po->operand[i].name);
1067   }
1068
1069   return out;
1070 }
1071
1072 static const char *lmod_type_u(struct parsed_op *po,
1073   enum opr_lenmod lmod)
1074 {
1075   switch (lmod) {
1076   case OPLM_DWORD:
1077     return "u32";
1078   case OPLM_WORD:
1079     return "u16";
1080   case OPLM_BYTE:
1081     return "u8";
1082   default:
1083     ferr(po, "invalid lmod: %d\n", lmod);
1084     return "(_invalid_)";
1085   }
1086 }
1087
1088 static const char *lmod_cast_u(struct parsed_op *po,
1089   enum opr_lenmod lmod)
1090 {
1091   switch (lmod) {
1092   case OPLM_DWORD:
1093     return "";
1094   case OPLM_WORD:
1095     return "(u16)";
1096   case OPLM_BYTE:
1097     return "(u8)";
1098   default:
1099     ferr(po, "invalid lmod: %d\n", lmod);
1100     return "(_invalid_)";
1101   }
1102 }
1103
1104 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1105   enum opr_lenmod lmod)
1106 {
1107   switch (lmod) {
1108   case OPLM_DWORD:
1109     return "*(u32 *)";
1110   case OPLM_WORD:
1111     return "*(u16 *)";
1112   case OPLM_BYTE:
1113     return "*(u8 *)";
1114   default:
1115     ferr(po, "invalid lmod: %d\n", lmod);
1116     return "(_invalid_)";
1117   }
1118 }
1119
1120 static const char *lmod_cast_s(struct parsed_op *po,
1121   enum opr_lenmod lmod)
1122 {
1123   switch (lmod) {
1124   case OPLM_DWORD:
1125     return "(s32)";
1126   case OPLM_WORD:
1127     return "(s16)";
1128   case OPLM_BYTE:
1129     return "(s8)";
1130   default:
1131     ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1132     return "(_invalid_)";
1133   }
1134 }
1135
1136 static const char *lmod_cast(struct parsed_op *po,
1137   enum opr_lenmod lmod, int is_signed)
1138 {
1139   return is_signed ?
1140     lmod_cast_s(po, lmod) :
1141     lmod_cast_u(po, lmod);
1142 }
1143
1144 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1145 {
1146   switch (lmod) {
1147   case OPLM_DWORD:
1148     return 4;
1149   case OPLM_WORD:
1150     return 2;
1151   case OPLM_BYTE:
1152     return 1;
1153   default:
1154     ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1155     return 0;
1156   }
1157 }
1158
1159 static const char *opr_name(struct parsed_op *po, int opr_num)
1160 {
1161   if (opr_num >= po->operand_cnt)
1162     ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1163   return po->operand[opr_num].name;
1164 }
1165
1166 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1167 {
1168   if (opr_num >= po->operand_cnt)
1169     ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1170   if (po->operand[opr_num].type != OPT_CONST)
1171     ferr(po, "opr %d: const expected\n", opr_num);
1172   return po->operand[opr_num].val;
1173 }
1174
1175 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1176 {
1177   if ((unsigned int)popr->reg >= MAX_REGS)
1178     ferr(po, "invalid reg: %d\n", popr->reg);
1179   return regs_r32[popr->reg];
1180 }
1181
1182 // cast1 is the "final" cast
1183 static const char *simplify_cast(const char *cast1, const char *cast2)
1184 {
1185   static char buf[256];
1186
1187   if (cast1[0] == 0)
1188     return cast2;
1189   if (cast2[0] == 0)
1190     return cast1;
1191   if (IS(cast1, cast2))
1192     return cast1;
1193   if (IS(cast1, "(s8)") && IS(cast2, "(u8)"))
1194     return cast1;
1195   if (IS(cast1, "(s16)") && IS(cast2, "(u16)"))
1196     return cast1;
1197   if (IS(cast1, "(u8)") && IS_START(cast2, "*(u8 *)"))
1198     return cast2;
1199   if (IS(cast1, "(u16)") && IS_START(cast2, "*(u16 *)"))
1200     return cast2;
1201   if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1202     return cast1;
1203
1204   snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1205   return buf;
1206 }
1207
1208 static const char *simplify_cast_num(const char *cast, unsigned int val)
1209 {
1210   if (IS(cast, "(u8)") && val < 0x100)
1211     return "";
1212   if (IS(cast, "(s8)") && val < 0x80)
1213     return "";
1214   if (IS(cast, "(u16)") && val < 0x10000)
1215     return "";
1216   if (IS(cast, "(s16)") && val < 0x8000)
1217     return "";
1218   if (IS(cast, "(s32)") && val < 0x80000000)
1219     return "";
1220
1221   return cast;
1222 }
1223
1224 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1225   int *extra_offs)
1226 {
1227   const char *p;
1228   char *endp;
1229   int namelen;
1230   int i;
1231
1232   *extra_offs = 0;
1233   namelen = strlen(name);
1234
1235   p = strchr(name, '+');
1236   if (p != NULL) {
1237     namelen = p - name;
1238     if (namelen <= 0)
1239       ferr(po, "equ parse failed for '%s'\n", name);
1240
1241     if (IS_START(p, "0x"))
1242       p += 2;
1243     *extra_offs = strtol(p, &endp, 16);
1244     if (*endp != 0)
1245       ferr(po, "equ parse failed for '%s'\n", name);
1246   }
1247
1248   for (i = 0; i < g_eqcnt; i++)
1249     if (strncmp(g_eqs[i].name, name, namelen) == 0
1250      && g_eqs[i].name[namelen] == 0)
1251       break;
1252   if (i >= g_eqcnt) {
1253     if (po != NULL)
1254       ferr(po, "unresolved equ name: '%s'\n", name);
1255     return NULL;
1256   }
1257
1258   return &g_eqs[i];
1259 }
1260
1261 static int is_stack_access(struct parsed_op *po,
1262   const struct parsed_opr *popr)
1263 {
1264   return (parse_stack_el(popr->name, NULL)
1265     || (g_bp_frame && !(po->flags & OPF_EBP_S)
1266         && IS_START(popr->name, "ebp")));
1267 }
1268
1269 static void parse_stack_access(struct parsed_op *po,
1270   const char *name, char *ofs_reg, int *offset_out,
1271   int *stack_ra_out, const char **bp_arg_out, int is_lea)
1272 {
1273   const char *bp_arg = "";
1274   const char *p = NULL;
1275   struct parsed_equ *eq;
1276   char *endp = NULL;
1277   int stack_ra = 0;
1278   int offset = 0;
1279
1280   ofs_reg[0] = 0;
1281
1282   if (IS_START(name, "ebp-")
1283    || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1284   {
1285     p = name + 4;
1286     if (IS_START(p, "0x"))
1287       p += 2;
1288     offset = strtoul(p, &endp, 16);
1289     if (name[3] == '-')
1290       offset = -offset;
1291     if (*endp != 0)
1292       ferr(po, "ebp- parse of '%s' failed\n", name);
1293   }
1294   else {
1295     bp_arg = parse_stack_el(name, ofs_reg);
1296     snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1297     eq = equ_find(po, bp_arg, &offset);
1298     if (eq == NULL)
1299       ferr(po, "detected but missing eq\n");
1300     offset += eq->offset;
1301   }
1302
1303   if (!strncmp(name, "ebp", 3))
1304     stack_ra = 4;
1305
1306   // yes it sometimes LEAs ra for compares..
1307   if (!is_lea && ofs_reg[0] == 0
1308     && stack_ra <= offset && offset < stack_ra + 4)
1309   {
1310     ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1311   }
1312
1313   *offset_out = offset;
1314   *stack_ra_out = stack_ra;
1315   if (bp_arg_out)
1316     *bp_arg_out = bp_arg;
1317 }
1318
1319 static void stack_frame_access(struct parsed_op *po,
1320   struct parsed_opr *popr, char *buf, size_t buf_size,
1321   const char *name, const char *cast, int is_src, int is_lea)
1322 {
1323   enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1324   const char *prefix = "";
1325   const char *bp_arg = NULL;
1326   char ofs_reg[16] = { 0, };
1327   int i, arg_i, arg_s;
1328   int unaligned = 0;
1329   int stack_ra = 0;
1330   int offset = 0;
1331   int sf_ofs;
1332   int lim;
1333
1334   if (po->flags & OPF_EBP_S)
1335     ferr(po, "stack_frame_access while ebp is scratch\n");
1336
1337   parse_stack_access(po, name, ofs_reg, &offset,
1338     &stack_ra, &bp_arg, is_lea);
1339
1340   if (offset > stack_ra)
1341   {
1342     arg_i = (offset - stack_ra - 4) / 4;
1343     if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1344     {
1345       if (g_func_pp->is_vararg
1346           && arg_i == g_func_pp->argc_stack && is_lea)
1347       {
1348         // should be va_list
1349         if (cast[0] == 0)
1350           cast = "(u32)";
1351         snprintf(buf, buf_size, "%sap", cast);
1352         return;
1353       }
1354       ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1355         offset, bp_arg, arg_i);
1356     }
1357     if (ofs_reg[0] != 0)
1358       ferr(po, "offset reg on arg access?\n");
1359
1360     for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1361       if (g_func_pp->arg[i].reg != NULL)
1362         continue;
1363       if (arg_s == arg_i)
1364         break;
1365       arg_s++;
1366     }
1367     if (i == g_func_pp->argc)
1368       ferr(po, "arg %d not in prototype?\n", arg_i);
1369
1370     popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1371
1372     switch (popr->lmod)
1373     {
1374     case OPLM_BYTE:
1375       if (is_lea)
1376         ferr(po, "lea/byte to arg?\n");
1377       if (is_src && (offset & 3) == 0)
1378         snprintf(buf, buf_size, "%sa%d",
1379           simplify_cast(cast, "(u8)"), i + 1);
1380       else
1381         snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1382           cast, offset & 3, i + 1);
1383       break;
1384
1385     case OPLM_WORD:
1386       if (is_lea)
1387         ferr(po, "lea/word to arg?\n");
1388       if (offset & 1) {
1389         unaligned = 1;
1390         if (!is_src) {
1391           if (offset & 2)
1392             ferr(po, "problematic arg store\n");
1393           snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1394             simplify_cast(cast, "*(u16 *)"), i + 1);
1395         }
1396         else
1397           ferr(po, "unaligned arg word load\n");
1398       }
1399       else if (is_src && (offset & 2) == 0)
1400         snprintf(buf, buf_size, "%sa%d",
1401           simplify_cast(cast, "(u16)"), i + 1);
1402       else
1403         snprintf(buf, buf_size, "%s%sWORD(a%d)",
1404           cast, (offset & 2) ? "HI" : "LO", i + 1);
1405       break;
1406
1407     case OPLM_DWORD:
1408       if (cast[0])
1409         prefix = cast;
1410       else if (is_src)
1411         prefix = "(u32)";
1412
1413       if (offset & 3) {
1414         unaligned = 1;
1415         if (is_lea)
1416           snprintf(buf, buf_size, "(u32)&a%d + %d",
1417             i + 1, offset & 3);
1418         else if (!is_src)
1419           ferr(po, "unaligned arg store\n");
1420         else {
1421           // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1422           snprintf(buf, buf_size, "%s(a%d >> %d)",
1423             prefix, i + 1, (offset & 3) * 8);
1424         }
1425       }
1426       else {
1427         snprintf(buf, buf_size, "%s%sa%d",
1428           prefix, is_lea ? "&" : "", i + 1);
1429       }
1430       break;
1431
1432     default:
1433       ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1434     }
1435
1436     if (unaligned)
1437       snprintf(g_comment, sizeof(g_comment), "%s unaligned", bp_arg);
1438
1439     // common problem
1440     guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
1441     if (tmp_lmod != OPLM_DWORD
1442       && (unaligned || (!is_src && tmp_lmod < popr->lmod)))
1443     {
1444       ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
1445         i + 1, offset, g_func_pp->arg[i].type.name);
1446     }
1447     // can't check this because msvc likes to reuse
1448     // arg space for scratch..
1449     //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
1450     //  ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
1451   }
1452   else
1453   {
1454     if (g_stack_fsz == 0)
1455       ferr(po, "stack var access without stackframe\n");
1456     g_stack_frame_used = 1;
1457
1458     sf_ofs = g_stack_fsz + offset;
1459     lim = (ofs_reg[0] != 0) ? -4 : 0;
1460     if (offset > 0 || sf_ofs < lim)
1461       ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
1462
1463     if (is_lea)
1464       prefix = "(u32)&";
1465     else
1466       prefix = cast;
1467
1468     switch (popr->lmod)
1469     {
1470     case OPLM_BYTE:
1471       snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1472         prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1473       break;
1474
1475     case OPLM_WORD:
1476       if ((sf_ofs & 1) || ofs_reg[0] != 0) {
1477         // known unaligned or possibly unaligned
1478         strcat(g_comment, " unaligned");
1479         if (prefix[0] == 0)
1480           prefix = "*(u16 *)&";
1481         snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1482           prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1483         break;
1484       }
1485       snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
1486       break;
1487
1488     case OPLM_DWORD:
1489       if ((sf_ofs & 3) || ofs_reg[0] != 0) {
1490         // known unaligned or possibly unaligned
1491         strcat(g_comment, " unaligned");
1492         if (prefix[0] == 0)
1493           prefix = "*(u32 *)&";
1494         snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1495           prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1496         break;
1497       }
1498       snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
1499       break;
1500
1501     default:
1502       ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
1503     }
1504   }
1505 }
1506
1507 static void check_func_pp(struct parsed_op *po,
1508   const struct parsed_proto *pp, const char *pfx)
1509 {
1510   char buf[256];
1511
1512   if (pp->argc_reg != 0) {
1513     if (/*!g_allow_regfunc &&*/ !pp->is_fastcall) {
1514       pp_print(buf, sizeof(buf), pp);
1515       ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
1516     }
1517     if (pp->argc_stack > 0 && pp->argc_reg != 2)
1518       ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
1519         pfx, pp->argc_reg, pp->argc_stack);
1520   }
1521 }
1522
1523 static const char *check_label_read_ref(struct parsed_op *po,
1524   const char *name)
1525 {
1526   const struct parsed_proto *pp;
1527
1528   pp = proto_parse(g_fhdr, name, 0);
1529   if (pp == NULL)
1530     ferr(po, "proto_parse failed for ref '%s'\n", name);
1531
1532   if (pp->is_func)
1533     check_func_pp(po, pp, "ref");
1534
1535   return pp->name;
1536 }
1537
1538 static char *out_src_opr(char *buf, size_t buf_size,
1539   struct parsed_op *po, struct parsed_opr *popr, const char *cast,
1540   int is_lea)
1541 {
1542   char tmp1[256], tmp2[256];
1543   char expr[256];
1544   const char *name;
1545   char *p;
1546   int ret;
1547
1548   if (cast == NULL)
1549     cast = "";
1550
1551   switch (popr->type) {
1552   case OPT_REG:
1553     if (is_lea)
1554       ferr(po, "lea from reg?\n");
1555
1556     switch (popr->lmod) {
1557     case OPLM_DWORD:
1558       snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
1559       break;
1560     case OPLM_WORD:
1561       snprintf(buf, buf_size, "%s%s",
1562         simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
1563       break;
1564     case OPLM_BYTE:
1565       if (popr->name[1] == 'h') // XXX..
1566         snprintf(buf, buf_size, "%s(%s >> 8)",
1567           simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
1568       else
1569         snprintf(buf, buf_size, "%s%s",
1570           simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
1571       break;
1572     default:
1573       ferr(po, "invalid src lmod: %d\n", popr->lmod);
1574     }
1575     break;
1576
1577   case OPT_REGMEM:
1578     if (is_stack_access(po, popr)) {
1579       stack_frame_access(po, popr, buf, buf_size,
1580         popr->name, cast, 1, is_lea);
1581       break;
1582     }
1583
1584     strcpy(expr, popr->name);
1585     if (strchr(expr, '[')) {
1586       // special case: '[' can only be left for label[reg] form
1587       ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
1588       if (ret != 2)
1589         ferr(po, "parse failure for '%s'\n", expr);
1590       if (tmp1[0] == '(') {
1591         // (off_4FFF50+3)[eax]
1592         p = strchr(tmp1 + 1, ')');
1593         if (p == NULL || p[1] != 0)
1594           ferr(po, "parse failure (2) for '%s'\n", expr);
1595         *p = 0;
1596         memmove(tmp1, tmp1 + 1, strlen(tmp1));
1597       }
1598       snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
1599     }
1600
1601     // XXX: do we need more parsing?
1602     if (is_lea) {
1603       snprintf(buf, buf_size, "%s", expr);
1604       break;
1605     }
1606
1607     snprintf(buf, buf_size, "%s(%s)",
1608       simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
1609     break;
1610
1611   case OPT_LABEL:
1612     name = check_label_read_ref(po, popr->name);
1613     if (cast[0] == 0 && popr->is_ptr)
1614       cast = "(u32)";
1615
1616     if (is_lea)
1617       snprintf(buf, buf_size, "(u32)&%s", name);
1618     else if (popr->size_lt)
1619       snprintf(buf, buf_size, "%s%s%s%s", cast,
1620         lmod_cast_u_ptr(po, popr->lmod),
1621         popr->is_array ? "" : "&", name);
1622     else
1623       snprintf(buf, buf_size, "%s%s%s", cast, name,
1624         popr->is_array ? "[0]" : "");
1625     break;
1626
1627   case OPT_OFFSET:
1628     name = check_label_read_ref(po, popr->name);
1629     if (cast[0] == 0)
1630       cast = "(u32)";
1631     if (is_lea)
1632       ferr(po, "lea an offset?\n");
1633     snprintf(buf, buf_size, "%s&%s", cast, name);
1634     break;
1635
1636   case OPT_CONST:
1637     if (is_lea)
1638       ferr(po, "lea from const?\n");
1639
1640     printf_number(tmp1, sizeof(tmp1), popr->val);
1641     if (popr->val == 0 && strchr(cast, '*'))
1642       snprintf(buf, buf_size, "NULL");
1643     else
1644       snprintf(buf, buf_size, "%s%s",
1645         simplify_cast_num(cast, popr->val), tmp1);
1646     break;
1647
1648   default:
1649     ferr(po, "invalid src type: %d\n", popr->type);
1650   }
1651
1652   return buf;
1653 }
1654
1655 // note: may set is_ptr (we find that out late for ebp frame..)
1656 static char *out_dst_opr(char *buf, size_t buf_size,
1657         struct parsed_op *po, struct parsed_opr *popr)
1658 {
1659   switch (popr->type) {
1660   case OPT_REG:
1661     switch (popr->lmod) {
1662     case OPLM_DWORD:
1663       snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
1664       break;
1665     case OPLM_WORD:
1666       // ugh..
1667       snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
1668       break;
1669     case OPLM_BYTE:
1670       // ugh..
1671       if (popr->name[1] == 'h') // XXX..
1672         snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
1673       else
1674         snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
1675       break;
1676     default:
1677       ferr(po, "invalid dst lmod: %d\n", popr->lmod);
1678     }
1679     break;
1680
1681   case OPT_REGMEM:
1682     if (is_stack_access(po, popr)) {
1683       stack_frame_access(po, popr, buf, buf_size,
1684         popr->name, "", 0, 0);
1685       break;
1686     }
1687
1688     return out_src_opr(buf, buf_size, po, popr, NULL, 0);
1689
1690   case OPT_LABEL:
1691     if (popr->size_mismatch)
1692       snprintf(buf, buf_size, "%s%s%s",
1693         lmod_cast_u_ptr(po, popr->lmod),
1694         popr->is_array ? "" : "&", popr->name);
1695     else
1696       snprintf(buf, buf_size, "%s%s", popr->name,
1697         popr->is_array ? "[0]" : "");
1698     break;
1699
1700   default:
1701     ferr(po, "invalid dst type: %d\n", popr->type);
1702   }
1703
1704   return buf;
1705 }
1706
1707 static char *out_src_opr_u32(char *buf, size_t buf_size,
1708         struct parsed_op *po, struct parsed_opr *popr)
1709 {
1710   return out_src_opr(buf, buf_size, po, popr, NULL, 0);
1711 }
1712
1713 static enum parsed_flag_op split_cond(struct parsed_op *po,
1714   enum op_op op, int *is_inv)
1715 {
1716   *is_inv = 0;
1717
1718   switch (op) {
1719   case OP_JO:
1720     return PFO_O;
1721   case OP_JC:
1722     return PFO_C;
1723   case OP_JZ:
1724     return PFO_Z;
1725   case OP_JBE:
1726     return PFO_BE;
1727   case OP_JS:
1728     return PFO_S;
1729   case OP_JP:
1730     return PFO_P;
1731   case OP_JL:
1732     return PFO_L;
1733   case OP_JLE:
1734     return PFO_LE;
1735
1736   case OP_JNO:
1737     *is_inv = 1;
1738     return PFO_O;
1739   case OP_JNC:
1740     *is_inv = 1;
1741     return PFO_C;
1742   case OP_JNZ:
1743     *is_inv = 1;
1744     return PFO_Z;
1745   case OP_JA:
1746     *is_inv = 1;
1747     return PFO_BE;
1748   case OP_JNS:
1749     *is_inv = 1;
1750     return PFO_S;
1751   case OP_JNP:
1752     *is_inv = 1;
1753     return PFO_P;
1754   case OP_JGE:
1755     *is_inv = 1;
1756     return PFO_L;
1757   case OP_JG:
1758     *is_inv = 1;
1759     return PFO_LE;
1760
1761   case OP_RCL:
1762   case OP_RCR:
1763   case OP_ADC:
1764   case OP_SBB:
1765     return PFO_C;
1766
1767   default:
1768     ferr(po, "split_cond: bad op %d\n", op);
1769     return -1;
1770   }
1771 }
1772
1773 static void out_test_for_cc(char *buf, size_t buf_size,
1774   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
1775   enum opr_lenmod lmod, const char *expr)
1776 {
1777   const char *cast, *scast;
1778
1779   cast = lmod_cast_u(po, lmod);
1780   scast = lmod_cast_s(po, lmod);
1781
1782   switch (pfo) {
1783   case PFO_Z:
1784   case PFO_BE: // CF=1||ZF=1; CF=0
1785     snprintf(buf, buf_size, "(%s%s %s 0)",
1786       cast, expr, is_inv ? "!=" : "==");
1787     break;
1788
1789   case PFO_S:
1790   case PFO_L: // SF!=OF; OF=0
1791     snprintf(buf, buf_size, "(%s%s %s 0)",
1792       scast, expr, is_inv ? ">=" : "<");
1793     break;
1794
1795   case PFO_LE: // ZF=1||SF!=OF; OF=0
1796     snprintf(buf, buf_size, "(%s%s %s 0)",
1797       scast, expr, is_inv ? ">" : "<=");
1798     break;
1799
1800   default:
1801     ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
1802   }
1803 }
1804
1805 static void out_cmp_for_cc(char *buf, size_t buf_size,
1806   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
1807 {
1808   const char *cast, *scast, *cast_use;
1809   char buf1[256], buf2[256];
1810   enum opr_lenmod lmod;
1811
1812   if (po->operand[0].lmod != po->operand[1].lmod)
1813     ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
1814       po->operand[0].lmod, po->operand[1].lmod);
1815   lmod = po->operand[0].lmod;
1816
1817   cast = lmod_cast_u(po, lmod);
1818   scast = lmod_cast_s(po, lmod);
1819
1820   switch (pfo) {
1821   case PFO_C:
1822   case PFO_Z:
1823   case PFO_BE: // !a
1824     cast_use = cast;
1825     break;
1826
1827   case PFO_S:
1828   case PFO_L: // !ge
1829   case PFO_LE:
1830     cast_use = scast;
1831     break;
1832
1833   default:
1834     ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
1835   }
1836
1837   out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
1838   out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_use, 0);
1839
1840   switch (pfo) {
1841   case PFO_C:
1842     // note: must be unsigned compare
1843     snprintf(buf, buf_size, "(%s %s %s)",
1844       buf1, is_inv ? ">=" : "<", buf2);
1845     break;
1846
1847   case PFO_Z:
1848     snprintf(buf, buf_size, "(%s %s %s)",
1849       buf1, is_inv ? "!=" : "==", buf2);
1850     break;
1851
1852   case PFO_BE: // !a
1853     // note: must be unsigned compare
1854     snprintf(buf, buf_size, "(%s %s %s)",
1855       buf1, is_inv ? ">" : "<=", buf2);
1856
1857     // annoying case
1858     if (is_inv && lmod == OPLM_BYTE
1859       && po->operand[1].type == OPT_CONST
1860       && po->operand[1].val == 0xff)
1861     {
1862       snprintf(g_comment, sizeof(g_comment), "if %s", buf);
1863       snprintf(buf, buf_size, "(0)");
1864     }
1865     break;
1866
1867   // note: must be signed compare
1868   case PFO_S:
1869     snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
1870       scast, buf1, buf2, is_inv ? ">=" : "<");
1871     break;
1872
1873   case PFO_L: // !ge
1874     snprintf(buf, buf_size, "(%s %s %s)",
1875       buf1, is_inv ? ">=" : "<", buf2);
1876     break;
1877
1878   case PFO_LE:
1879     snprintf(buf, buf_size, "(%s %s %s)",
1880       buf1, is_inv ? ">" : "<=", buf2);
1881     break;
1882
1883   default:
1884     break;
1885   }
1886 }
1887
1888 static void out_cmp_test(char *buf, size_t buf_size,
1889   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
1890 {
1891   char buf1[256], buf2[256], buf3[256];
1892
1893   if (po->op == OP_TEST) {
1894     if (IS(opr_name(po, 0), opr_name(po, 1))) {
1895       out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
1896     }
1897     else {
1898       out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
1899       out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
1900       snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
1901     }
1902     out_test_for_cc(buf, buf_size, po, pfo, is_inv,
1903       po->operand[0].lmod, buf3);
1904   }
1905   else if (po->op == OP_CMP) {
1906     out_cmp_for_cc(buf, buf_size, po, pfo, is_inv);
1907   }
1908   else
1909     ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
1910 }
1911
1912 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
1913         struct parsed_opr *popr2)
1914 {
1915   if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
1916     ferr(po, "missing lmod for both operands\n");
1917
1918   if (popr1->lmod == OPLM_UNSPEC)
1919     popr1->lmod = popr2->lmod;
1920   else if (popr2->lmod == OPLM_UNSPEC)
1921     popr2->lmod = popr1->lmod;
1922   else if (popr1->lmod != popr2->lmod) {
1923     if (popr1->type_from_var) {
1924       popr1->size_mismatch = 1;
1925       if (popr1->lmod < popr2->lmod)
1926         popr1->size_lt = 1;
1927       popr1->lmod = popr2->lmod;
1928     }
1929     else if (popr2->type_from_var) {
1930       popr2->size_mismatch = 1;
1931       if (popr2->lmod < popr1->lmod)
1932         popr2->size_lt = 1;
1933       popr2->lmod = popr1->lmod;
1934     }
1935     else
1936       ferr(po, "conflicting lmods: %d vs %d\n",
1937         popr1->lmod, popr2->lmod);
1938   }
1939 }
1940
1941 static const char *op_to_c(struct parsed_op *po)
1942 {
1943   switch (po->op)
1944   {
1945     case OP_ADD:
1946     case OP_ADC:
1947       return "+";
1948     case OP_SUB:
1949     case OP_SBB:
1950       return "-";
1951     case OP_AND:
1952       return "&";
1953     case OP_OR:
1954       return "|";
1955     case OP_XOR:
1956       return "^";
1957     case OP_SHL:
1958       return "<<";
1959     case OP_SHR:
1960       return ">>";
1961     case OP_MUL:
1962     case OP_IMUL:
1963       return "*";
1964     default:
1965       ferr(po, "op_to_c was supplied with %d\n", po->op);
1966   }
1967 }
1968
1969 static void op_set_clear_flag(struct parsed_op *po,
1970   enum op_flags flag_set, enum op_flags flag_clear)
1971 {
1972   po->flags |= flag_set;
1973   po->flags &= ~flag_clear;
1974 }
1975
1976 // last op in stream - unconditional branch or ret
1977 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
1978   || ((ops[_i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP \
1979       && ops[_i].op != OP_CALL))
1980
1981 static int scan_for_pop(int i, int opcnt, const char *reg,
1982   int magic, int depth, int *maxdepth, int do_flags)
1983 {
1984   const struct parsed_proto *pp;
1985   struct parsed_op *po;
1986   int ret = 0;
1987   int j;
1988
1989   for (; i < opcnt; i++) {
1990     po = &ops[i];
1991     if (po->cc_scratch == magic)
1992       break; // already checked
1993     po->cc_scratch = magic;
1994
1995     if (po->flags & OPF_TAIL) {
1996       if (po->op == OP_CALL) {
1997         pp = proto_parse(g_fhdr, po->operand[0].name, 0);
1998         if (pp != NULL && pp->is_noreturn)
1999           // no stack cleanup for noreturn
2000           return ret;
2001       }
2002       return -1; // deadend
2003     }
2004
2005     if ((po->flags & OPF_RMD)
2006         || (po->op == OP_PUSH && po->argnum != 0)) // arg push
2007       continue;
2008
2009     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2010       if (po->btj != NULL) {
2011         // jumptable
2012         for (j = 0; j < po->btj->count; j++) {
2013           ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, reg, magic,
2014                    depth, maxdepth, do_flags);
2015           if (ret < 0)
2016             return ret; // dead end
2017         }
2018         return ret;
2019       }
2020
2021       if (po->bt_i < 0) {
2022         ferr(po, "dead branch\n");
2023         return -1;
2024       }
2025
2026       if (po->flags & OPF_CJMP) {
2027         ret |= scan_for_pop(po->bt_i, opcnt, reg, magic,
2028                  depth, maxdepth, do_flags);
2029         if (ret < 0)
2030           return ret; // dead end
2031       }
2032       else {
2033         i = po->bt_i - 1;
2034       }
2035       continue;
2036     }
2037
2038     if ((po->op == OP_POP || po->op == OP_PUSH)
2039         && po->operand[0].type == OPT_REG
2040         && IS(po->operand[0].name, reg))
2041     {
2042       if (po->op == OP_PUSH && !(po->flags & OPF_FARG)) {
2043         depth++;
2044         if (depth > *maxdepth)
2045           *maxdepth = depth;
2046         if (do_flags)
2047           op_set_clear_flag(po, OPF_RSAVE, OPF_RMD);
2048       }
2049       else if (po->op == OP_POP) {
2050         if (depth == 0) {
2051           if (do_flags)
2052             op_set_clear_flag(po, OPF_RMD, OPF_RSAVE);
2053           return 1;
2054         }
2055         else {
2056           depth--;
2057           if (depth < 0) // should not happen
2058             ferr(po, "fail with depth\n");
2059           if (do_flags)
2060             op_set_clear_flag(po, OPF_RSAVE, OPF_RMD);
2061         }
2062       }
2063     }
2064   }
2065
2066   return ret;
2067 }
2068
2069 // scan for pop starting from 'ret' op (all paths)
2070 static int scan_for_pop_ret(int i, int opcnt, const char *reg,
2071   int flag_set)
2072 {
2073   int found = 0;
2074   int j;
2075
2076   for (; i < opcnt; i++) {
2077     if (!(ops[i].flags & OPF_TAIL))
2078       continue;
2079
2080     for (j = i - 1; j >= 0; j--) {
2081       if (ops[j].flags & OPF_RMD)
2082         continue;
2083       if (ops[j].flags & OPF_JMP)
2084         return -1;
2085
2086       if (ops[j].op == OP_POP && ops[j].operand[0].type == OPT_REG
2087           && IS(ops[j].operand[0].name, reg))
2088       {
2089         found = 1;
2090         ops[j].flags |= flag_set;
2091         break;
2092       }
2093
2094       if (g_labels[j][0] != 0)
2095         return -1;
2096     }
2097   }
2098
2099   return found ? 0 : -1;
2100 }
2101
2102 static void scan_propagate_df(int i, int opcnt)
2103 {
2104   struct parsed_op *po = &ops[i];
2105   int j;
2106
2107   for (; i < opcnt; i++) {
2108     po = &ops[i];
2109     if (po->flags & OPF_DF)
2110       return; // already resolved
2111     po->flags |= OPF_DF;
2112
2113     if (po->op == OP_CALL)
2114       ferr(po, "call with DF set?\n");
2115
2116     if (po->flags & OPF_JMP) {
2117       if (po->btj != NULL) {
2118         // jumptable
2119         for (j = 0; j < po->btj->count; j++)
2120           scan_propagate_df(po->btj->d[j].bt_i, opcnt);
2121         return;
2122       }
2123
2124       if (po->bt_i < 0) {
2125         ferr(po, "dead branch\n");
2126         return;
2127       }
2128
2129       if (po->flags & OPF_CJMP)
2130         scan_propagate_df(po->bt_i, opcnt);
2131       else
2132         i = po->bt_i - 1;
2133       continue;
2134     }
2135
2136     if (po->flags & OPF_TAIL)
2137       break;
2138
2139     if (po->op == OP_CLD) {
2140       po->flags |= OPF_RMD;
2141       return;
2142     }
2143   }
2144
2145   ferr(po, "missing DF clear?\n");
2146 }
2147
2148 // is operand 'opr' modified by parsed_op 'po'?
2149 static int is_opr_modified(const struct parsed_opr *opr,
2150   const struct parsed_op *po)
2151 {
2152   int mask;
2153
2154   if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
2155     return 0;
2156
2157   if (opr->type == OPT_REG) {
2158     if (po->op == OP_CALL) {
2159       mask = (1 << xAX) | (1 << xCX) | (1 << xDX);
2160       if ((1 << opr->reg) & mask)
2161         return 1;
2162       else
2163         return 0;
2164     }
2165
2166     if (po->operand[0].type == OPT_REG) {
2167       if (po->regmask_dst & (1 << opr->reg))
2168         return 1;
2169       else
2170         return 0;
2171     }
2172   }
2173
2174   return IS(po->operand[0].name, opr->name);
2175 }
2176
2177 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
2178 static int is_any_opr_modified(const struct parsed_op *po_test,
2179   const struct parsed_op *po, int c_mode)
2180 {
2181   int mask;
2182   int i;
2183
2184   if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
2185     return 0;
2186
2187   if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
2188     return 0;
2189
2190   if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
2191     return 1;
2192
2193   // in reality, it can wreck any register, but in decompiled C
2194   // version it can only overwrite eax or edx:eax
2195   mask = (1 << xAX) | (1 << xDX);
2196   if (!c_mode)
2197     mask |= 1 << xCX;
2198
2199   if (po->op == OP_CALL
2200    && ((po_test->regmask_src | po_test->regmask_dst) & mask))
2201     return 1;
2202
2203   for (i = 0; i < po_test->operand_cnt; i++)
2204     if (IS(po_test->operand[i].name, po->operand[0].name))
2205       return 1;
2206
2207   return 0;
2208 }
2209
2210 // scan for any po_test operand modification in range given
2211 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
2212   int c_mode)
2213 {
2214   if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
2215     return -1;
2216
2217   for (; i < opcnt; i++) {
2218     if (is_any_opr_modified(po_test, &ops[i], c_mode))
2219       return i;
2220   }
2221
2222   return -1;
2223 }
2224
2225 // scan for po_test operand[0] modification in range given
2226 static int scan_for_mod_opr0(struct parsed_op *po_test,
2227   int i, int opcnt)
2228 {
2229   for (; i < opcnt; i++) {
2230     if (is_opr_modified(&po_test->operand[0], &ops[i]))
2231       return i;
2232   }
2233
2234   return -1;
2235 }
2236
2237 static int scan_for_flag_set(int i, int magic, int *branched,
2238   int *setters, int *setter_cnt)
2239 {
2240   struct label_ref *lr;
2241   int ret;
2242
2243   while (i >= 0) {
2244     if (ops[i].cc_scratch == magic) {
2245       ferr(&ops[i], "%s looped\n", __func__);
2246       return -1;
2247     }
2248     ops[i].cc_scratch = magic;
2249
2250     if (g_labels[i][0] != 0) {
2251       *branched = 1;
2252
2253       lr = &g_label_refs[i];
2254       for (; lr->next; lr = lr->next) {
2255         ret = scan_for_flag_set(lr->i, magic,
2256                 branched, setters, setter_cnt);
2257         if (ret < 0)
2258           return ret;
2259       }
2260
2261       if (i > 0 && LAST_OP(i - 1)) {
2262         i = lr->i;
2263         continue;
2264       }
2265       ret = scan_for_flag_set(lr->i, magic,
2266               branched, setters, setter_cnt);
2267       if (ret < 0)
2268         return ret;
2269     }
2270     i--;
2271
2272     if (ops[i].flags & OPF_FLAGS) {
2273       setters[*setter_cnt] = i;
2274       (*setter_cnt)++;
2275       return 0;
2276     }
2277
2278     if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
2279       return -1;
2280   }
2281
2282   return -1;
2283 }
2284
2285 // scan back for cdq, if anything modifies edx, fail
2286 static int scan_for_cdq_edx(int i)
2287 {
2288   while (i >= 0) {
2289     if (g_labels[i][0] != 0) {
2290       if (g_label_refs[i].next != NULL)
2291         return -1;
2292       if (i > 0 && LAST_OP(i - 1)) {
2293         i = g_label_refs[i].i;
2294         continue;
2295       }
2296       return -1;
2297     }
2298     i--;
2299
2300     if (ops[i].op == OP_CDQ)
2301       return i;
2302
2303     if (ops[i].regmask_dst & (1 << xDX))
2304       return -1;
2305   }
2306
2307   return -1;
2308 }
2309
2310 static int scan_for_reg_clear(int i, int reg)
2311 {
2312   while (i >= 0) {
2313     if (g_labels[i][0] != 0) {
2314       if (g_label_refs[i].next != NULL)
2315         return -1;
2316       if (i > 0 && LAST_OP(i - 1)) {
2317         i = g_label_refs[i].i;
2318         continue;
2319       }
2320       return -1;
2321     }
2322     i--;
2323
2324     if (ops[i].op == OP_XOR
2325      && ops[i].operand[0].lmod == OPLM_DWORD
2326      && ops[i].operand[0].reg == ops[i].operand[1].reg
2327      && ops[i].operand[0].reg == reg)
2328       return i;
2329
2330     if (ops[i].regmask_dst & (1 << reg))
2331       return -1;
2332   }
2333
2334   return -1;
2335 }
2336
2337 // scan for positive, constant esp adjust
2338 static int scan_for_esp_adjust(int i, int opcnt, int *adj,
2339   int *multipath)
2340 {
2341   const struct parsed_proto *pp;
2342   struct parsed_op *po;
2343   int first_pop = -1;
2344
2345   *adj = *multipath = 0;
2346
2347   for (; i < opcnt; i++) {
2348     po = &ops[i];
2349
2350     if (g_labels[i][0] != 0)
2351       *multipath = 1;
2352
2353     if (po->op == OP_ADD && po->operand[0].reg == xSP) {
2354       if (po->operand[1].type != OPT_CONST)
2355         ferr(&ops[i], "non-const esp adjust?\n");
2356       *adj += po->operand[1].val;
2357       if (*adj & 3)
2358         ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
2359       return i;
2360     }
2361     else if (po->op == OP_PUSH && !(po->flags & OPF_RMD)) {
2362       //if (first_pop == -1)
2363       //  first_pop = -2; // none
2364       *adj -= lmod_bytes(po, po->operand[0].lmod);
2365     }
2366     else if (po->op == OP_POP && !(po->flags & OPF_RMD)) {
2367       // seems like msvc only uses 'pop ecx' for stack realignment..
2368       if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
2369         break;
2370       if (first_pop == -1 && *adj >= 0)
2371         first_pop = i;
2372       *adj += lmod_bytes(po, po->operand[0].lmod);
2373     }
2374     else if (po->flags & (OPF_JMP|OPF_TAIL)) {
2375       if (po->op == OP_JMP && po->btj == NULL) {
2376         i = po->bt_i - 1;
2377         continue;
2378       }
2379       if (po->op != OP_CALL)
2380         break;
2381       if (po->operand[0].type != OPT_LABEL)
2382         break;
2383       pp = po->datap;
2384       if (pp != NULL && pp->is_stdcall)
2385         break;
2386     }
2387   }
2388
2389   if (first_pop >= 0) {
2390     // probably 'pop ecx' was used..
2391     return first_pop;
2392   }
2393
2394   return -1;
2395 }
2396
2397 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
2398 {
2399   struct parsed_op *po;
2400   int j;
2401
2402   if (i < 0)
2403     ferr(ops, "%s: followed bad branch?\n", __func__);
2404
2405   for (; i < opcnt; i++) {
2406     po = &ops[i];
2407     if (po->cc_scratch == magic)
2408       return;
2409     po->cc_scratch = magic;
2410     po->flags |= flags;
2411
2412     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2413       if (po->btj != NULL) {
2414         // jumptable
2415         for (j = 0; j < po->btj->count; j++)
2416           scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
2417         return;
2418       }
2419
2420       scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
2421       if (!(po->flags & OPF_CJMP))
2422         return;
2423     }
2424     if (po->flags & OPF_TAIL)
2425       return;
2426   }
2427 }
2428
2429 static const struct parsed_proto *try_recover_pp(
2430   struct parsed_op *po, const struct parsed_opr *opr, int *search_instead)
2431 {
2432   const struct parsed_proto *pp = NULL;
2433   char buf[256];
2434   char *p;
2435
2436   // maybe an arg of g_func?
2437   if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
2438   {
2439     char ofs_reg[16] = { 0, };
2440     int arg, arg_s, arg_i;
2441     int stack_ra = 0;
2442     int offset = 0;
2443
2444     parse_stack_access(po, opr->name, ofs_reg,
2445       &offset, &stack_ra, NULL, 0);
2446     if (ofs_reg[0] != 0)
2447       ferr(po, "offset reg on arg access?\n");
2448     if (offset <= stack_ra) {
2449       // search who set the stack var instead
2450       if (search_instead != NULL)
2451         *search_instead = 1;
2452       return NULL;
2453     }
2454
2455     arg_i = (offset - stack_ra - 4) / 4;
2456     for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
2457       if (g_func_pp->arg[arg].reg != NULL)
2458         continue;
2459       if (arg_s == arg_i)
2460         break;
2461       arg_s++;
2462     }
2463     if (arg == g_func_pp->argc)
2464       ferr(po, "stack arg %d not in prototype?\n", arg_i);
2465
2466     pp = g_func_pp->arg[arg].fptr;
2467     if (pp == NULL)
2468       ferr(po, "icall sa: arg%d is not a fptr?\n", arg + 1);
2469     check_func_pp(po, pp, "icall arg");
2470   }
2471   else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
2472     // label[index]
2473     p = strchr(opr->name + 1, '[');
2474     memcpy(buf, opr->name, p - opr->name);
2475     buf[p - opr->name] = 0;
2476     pp = proto_parse(g_fhdr, buf, 0);
2477   }
2478   else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
2479     pp = proto_parse(g_fhdr, opr->name, 0);
2480     if (pp == NULL)
2481       ferr(po, "proto_parse failed for icall from '%s'\n", opr->name);
2482     check_func_pp(po, pp, "reg-fptr ref");
2483   }
2484
2485   return pp;
2486 }
2487
2488 static void scan_for_call_type(int i, const struct parsed_opr *opr,
2489   int magic, const struct parsed_proto **pp_found, int *multi)
2490 {
2491   const struct parsed_proto *pp = NULL;
2492   struct parsed_op *po;
2493   struct label_ref *lr;
2494
2495   ops[i].cc_scratch = magic;
2496
2497   while (1) {
2498     if (g_labels[i][0] != 0) {
2499       lr = &g_label_refs[i];
2500       for (; lr != NULL; lr = lr->next)
2501         scan_for_call_type(lr->i, opr, magic, pp_found, multi);
2502       if (i > 0 && LAST_OP(i - 1))
2503         return;
2504     }
2505
2506     i--;
2507     if (i < 0)
2508       break;
2509
2510     if (ops[i].cc_scratch == magic)
2511       return;
2512     ops[i].cc_scratch = magic;
2513
2514     if (!(ops[i].flags & OPF_DATA))
2515       continue;
2516     if (!is_opr_modified(opr, &ops[i]))
2517       continue;
2518     if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
2519       // most probably trashed by some processing
2520       *pp_found = NULL;
2521       return;
2522     }
2523
2524     opr = &ops[i].operand[1];
2525     if (opr->type != OPT_REG)
2526       break;
2527   }
2528
2529   po = (i >= 0) ? &ops[i] : ops;
2530
2531   if (i < 0) {
2532     // reached the top - can only be an arg-reg
2533     if (opr->type != OPT_REG)
2534       return;
2535
2536     for (i = 0; i < g_func_pp->argc; i++) {
2537       if (g_func_pp->arg[i].reg == NULL)
2538         continue;
2539       if (IS(opr->name, g_func_pp->arg[i].reg))
2540         break;
2541     }
2542     if (i == g_func_pp->argc)
2543       return;
2544     pp = g_func_pp->arg[i].fptr;
2545     if (pp == NULL)
2546       ferr(po, "icall: arg%d (%s) is not a fptr?\n",
2547         i + 1, g_func_pp->arg[i].reg);
2548     check_func_pp(po, pp, "icall reg-arg");
2549   }
2550   else
2551     pp = try_recover_pp(po, opr, NULL);
2552
2553   if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
2554     if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
2555       || (*pp_found)->is_stdcall != pp->is_stdcall
2556       || (*pp_found)->is_fptr != pp->is_fptr
2557       || (*pp_found)->argc != pp->argc
2558       || (*pp_found)->argc_reg != pp->argc_reg
2559       || (*pp_found)->argc_stack != pp->argc_stack)
2560     {
2561       ferr(po, "icall: parsed_proto mismatch\n");
2562     }
2563     *multi = 1;
2564   }
2565   if (pp != NULL)
2566     *pp_found = pp;
2567 }
2568
2569 static const struct parsed_proto *resolve_icall(int i, int opcnt,
2570   int *multi_src)
2571 {
2572   const struct parsed_proto *pp = NULL;
2573   int search_advice = 0;
2574
2575   *multi_src = 0;
2576
2577   switch (ops[i].operand[0].type) {
2578   case OPT_REGMEM:
2579   case OPT_LABEL:
2580   case OPT_OFFSET:
2581     pp = try_recover_pp(&ops[i], &ops[i].operand[0], &search_advice);
2582     if (!search_advice)
2583       break;
2584     // fallthrough
2585   default:
2586     scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
2587       multi_src);
2588     break;
2589   }
2590
2591   return pp;
2592 }
2593
2594 static int collect_call_args_r(struct parsed_op *po, int i,
2595   struct parsed_proto *pp, int *regmask, int *save_arg_vars, int arg,
2596   int magic, int need_op_saving, int may_reuse)
2597 {
2598   struct parsed_proto *pp_tmp;
2599   struct label_ref *lr;
2600   int need_to_save_current;
2601   int ret = 0;
2602   int j;
2603
2604   if (i < 0) {
2605     ferr(po, "dead label encountered\n");
2606     return -1;
2607   }
2608
2609   for (; arg < pp->argc; arg++)
2610     if (pp->arg[arg].reg == NULL)
2611       break;
2612   magic = (magic & 0xffffff) | (arg << 24);
2613
2614   for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
2615   {
2616     if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
2617       if (ops[j].cc_scratch != magic) {
2618         ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
2619            pp->name);
2620         return -1;
2621       }
2622       // ok: have already been here
2623       return 0;
2624     }
2625     ops[j].cc_scratch = magic;
2626
2627     if (g_labels[j][0] != 0 && g_label_refs[j].i != -1) {
2628       lr = &g_label_refs[j];
2629       if (lr->next != NULL)
2630         need_op_saving = 1;
2631       for (; lr->next; lr = lr->next) {
2632         if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
2633           may_reuse = 1;
2634         ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
2635                 arg, magic, need_op_saving, may_reuse);
2636         if (ret < 0)
2637           return ret;
2638       }
2639
2640       if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
2641         may_reuse = 1;
2642       if (j > 0 && LAST_OP(j - 1)) {
2643         // follow last branch in reverse
2644         j = lr->i;
2645         continue;
2646       }
2647       need_op_saving = 1;
2648       ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
2649                arg, magic, need_op_saving, may_reuse);
2650       if (ret < 0)
2651         return ret;
2652     }
2653     j--;
2654
2655     if (ops[j].op == OP_CALL)
2656     {
2657       if (pp->is_unresolved)
2658         break;
2659
2660       pp_tmp = ops[j].datap;
2661       if (pp_tmp == NULL)
2662         ferr(po, "arg collect hit unparsed call '%s'\n",
2663           ops[j].operand[0].name);
2664       if (may_reuse && pp_tmp->argc_stack > 0)
2665         ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
2666           arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
2667     }
2668     else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP) {
2669       if (pp->is_unresolved)
2670         break;
2671
2672       ferr(po, "arg collect %d/%d hit esp adjust\n",
2673         arg, pp->argc);
2674     }
2675     else if (ops[j].op == OP_POP) {
2676       if (pp->is_unresolved)
2677         break;
2678
2679       ferr(po, "arg collect %d/%d hit pop\n", arg, pp->argc);
2680     }
2681     else if (ops[j].flags & OPF_CJMP)
2682     {
2683       if (pp->is_unresolved)
2684         break;
2685
2686       may_reuse = 1;
2687     }
2688     else if (ops[j].op == OP_PUSH && !(ops[j].flags & OPF_FARG))
2689     {
2690       if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
2691         break;
2692
2693       pp->arg[arg].datap = &ops[j];
2694       need_to_save_current = 0;
2695       if (!need_op_saving) {
2696         ret = scan_for_mod(&ops[j], j + 1, i, 1);
2697         need_to_save_current = (ret >= 0);
2698       }
2699       if (need_op_saving || need_to_save_current) {
2700         // mark this push as one that needs operand saving
2701         ops[j].flags &= ~OPF_RMD;
2702         if (ops[j].argnum == 0) {
2703           ops[j].argnum = arg + 1;
2704           *save_arg_vars |= 1 << arg;
2705         }
2706         else if (ops[j].argnum < arg + 1)
2707           ferr(&ops[j], "argnum conflict (%d<%d) for '%s'\n",
2708             ops[j].argnum, arg + 1, pp->name);
2709       }
2710       else if (ops[j].argnum == 0)
2711         ops[j].flags |= OPF_RMD;
2712
2713       // some PUSHes are reused by different calls on other branches,
2714       // but that can't happen if we didn't branch, so they
2715       // can be removed from future searches (handles nested calls)
2716       if (!may_reuse)
2717         ops[j].flags |= OPF_FARG;
2718
2719       ops[j].flags &= ~OPF_RSAVE;
2720
2721       arg++;
2722       if (!pp->is_unresolved) {
2723         // next arg
2724         for (; arg < pp->argc; arg++)
2725           if (pp->arg[arg].reg == NULL)
2726             break;
2727       }
2728       magic = (magic & 0xffffff) | (arg << 24);
2729
2730       // tracking reg usage
2731       if (ops[j].operand[0].type == OPT_REG)
2732         *regmask |= 1 << ops[j].operand[0].reg;
2733     }
2734   }
2735
2736   if (arg < pp->argc) {
2737     ferr(po, "arg collect failed for '%s': %d/%d\n",
2738       pp->name, arg, pp->argc);
2739     return -1;
2740   }
2741
2742   return arg;
2743 }
2744
2745 static int collect_call_args(struct parsed_op *po, int i,
2746   struct parsed_proto *pp, int *regmask, int *save_arg_vars,
2747   int magic)
2748 {
2749   int ret;
2750   int a;
2751
2752   ret = collect_call_args_r(po, i, pp, regmask, save_arg_vars,
2753           0, magic, 0, 0);
2754   if (ret < 0)
2755     return ret;
2756
2757   if (pp->is_unresolved) {
2758     pp->argc += ret;
2759     pp->argc_stack += ret;
2760     for (a = 0; a < pp->argc; a++)
2761       if (pp->arg[a].type.name == NULL)
2762         pp->arg[a].type.name = strdup("int");
2763   }
2764
2765   return ret;
2766 }
2767
2768 // early check for tail call or branch back
2769 static int is_like_tailjmp(int j)
2770 {
2771   if (!(ops[j].flags & OPF_JMP))
2772     return 0;
2773
2774   if (ops[j].op == OP_JMP && !ops[j].operand[0].had_ds)
2775     // probably local branch back..
2776     return 1;
2777   if (ops[j].op == OP_CALL)
2778     // probably noreturn call..
2779     return 1;
2780
2781   return 0;
2782 }
2783
2784 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
2785 {
2786   int i;
2787
2788   for (i = 0; i < pp->argc; i++)
2789     if (pp->arg[i].reg == NULL)
2790       break;
2791
2792   if (pp->argc_stack)
2793     memmove(&pp->arg[i + 1], &pp->arg[i],
2794       sizeof(pp->arg[0]) * pp->argc_stack);
2795   memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
2796   pp->arg[i].reg = strdup(reg);
2797   pp->arg[i].type.name = strdup("int");
2798   pp->argc++;
2799   pp->argc_reg++;
2800 }
2801
2802 static void add_label_ref(struct label_ref *lr, int op_i)
2803 {
2804   struct label_ref *lr_new;
2805
2806   if (lr->i == -1) {
2807     lr->i = op_i;
2808     return;
2809   }
2810
2811   lr_new = calloc(1, sizeof(*lr_new));
2812   lr_new->i = op_i;
2813   lr_new->next = lr->next;
2814   lr->next = lr_new;
2815 }
2816
2817 static void output_std_flags(FILE *fout, struct parsed_op *po,
2818   int *pfomask, const char *dst_opr_text)
2819 {
2820   if (*pfomask & (1 << PFO_Z)) {
2821     fprintf(fout, "\n  cond_z = (%s%s == 0);",
2822       lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
2823     *pfomask &= ~(1 << PFO_Z);
2824   }
2825   if (*pfomask & (1 << PFO_S)) {
2826     fprintf(fout, "\n  cond_s = (%s%s < 0);",
2827       lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
2828     *pfomask &= ~(1 << PFO_S);
2829   }
2830 }
2831
2832 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
2833   int is_noreturn)
2834 {
2835   if (pp->is_fastcall)
2836     fprintf(fout, "__fastcall ");
2837   else if (pp->is_stdcall && pp->argc_reg == 0)
2838     fprintf(fout, "__stdcall ");
2839   if (pp->is_noreturn || is_noreturn)
2840     fprintf(fout, "noreturn ");
2841 }
2842
2843 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
2844 {
2845   struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
2846   struct parsed_opr *last_arith_dst = NULL;
2847   char buf1[256], buf2[256], buf3[256], cast[64];
2848   const struct parsed_proto *pp_c;
2849   struct parsed_proto *pp, *pp_tmp;
2850   struct parsed_data *pd;
2851   const char *tmpname;
2852   enum parsed_flag_op pfo;
2853   int save_arg_vars = 0;
2854   int cond_vars = 0;
2855   int need_tmp_var = 0;
2856   int need_tmp64 = 0;
2857   int had_decl = 0;
2858   int label_pending = 0;
2859   int regmask_save = 0;
2860   int regmask_arg = 0;
2861   int regmask_now = 0;
2862   int regmask_init = 0;
2863   int regmask = 0;
2864   int pfomask = 0;
2865   int found = 0;
2866   int depth = 0;
2867   int no_output;
2868   int i, j, l;
2869   int dummy;
2870   int arg;
2871   int reg;
2872   int ret;
2873
2874   g_bp_frame = g_sp_frame = g_stack_fsz = 0;
2875   g_stack_frame_used = 0;
2876
2877   g_func_pp = proto_parse(fhdr, funcn, 0);
2878   if (g_func_pp == NULL)
2879     ferr(ops, "proto_parse failed for '%s'\n", funcn);
2880
2881   fprintf(fout, "%s ", g_func_pp->ret_type.name);
2882   output_pp_attrs(fout, g_func_pp, g_ida_func_attr & IDAFA_NORETURN);
2883   fprintf(fout, "%s(", g_func_pp->name);
2884
2885   for (i = 0; i < g_func_pp->argc; i++) {
2886     if (i > 0)
2887       fprintf(fout, ", ");
2888     if (g_func_pp->arg[i].fptr != NULL) {
2889       // func pointer..
2890       pp = g_func_pp->arg[i].fptr;
2891       fprintf(fout, "%s (", pp->ret_type.name);
2892       output_pp_attrs(fout, pp, 0);
2893       fprintf(fout, "*a%d)(", i + 1);
2894       for (j = 0; j < pp->argc; j++) {
2895         if (j > 0)
2896           fprintf(fout, ", ");
2897         if (pp->arg[j].fptr)
2898           ferr(ops, "nested fptr\n");
2899         fprintf(fout, "%s", pp->arg[j].type.name);
2900       }
2901       if (pp->is_vararg) {
2902         if (j > 0)
2903           fprintf(fout, ", ");
2904         fprintf(fout, "...");
2905       }
2906       fprintf(fout, ")");
2907     }
2908     else {
2909       fprintf(fout, "%s a%d", g_func_pp->arg[i].type.name, i + 1);
2910     }
2911     if (g_func_pp->arg[i].reg != NULL) {
2912       reg = char_array_i(regs_r32,
2913               ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
2914       if (reg < 0)
2915         ferr(ops, "arg '%s' is not a reg?\n", g_func_pp->arg[i].reg);
2916       regmask_arg |= 1 << reg;
2917     }
2918   }
2919   if (g_func_pp->is_vararg) {
2920     if (i > 0)
2921       fprintf(fout, ", ");
2922     fprintf(fout, "...");
2923   }
2924
2925   fprintf(fout, ")\n{\n");
2926
2927   // pass1:
2928   // - handle ebp/esp frame, remove ops related to it
2929   if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
2930       && ops[1].op == OP_MOV
2931       && IS(opr_name(&ops[1], 0), "ebp")
2932       && IS(opr_name(&ops[1], 1), "esp"))
2933   {
2934     int ecx_push = 0;
2935
2936     g_bp_frame = 1;
2937     ops[0].flags |= OPF_RMD;
2938     ops[1].flags |= OPF_RMD;
2939     i = 2;
2940
2941     if (ops[2].op == OP_SUB && IS(opr_name(&ops[2], 0), "esp")) {
2942       g_stack_fsz = opr_const(&ops[2], 1);
2943       ops[2].flags |= OPF_RMD;
2944       i++;
2945     }
2946     else {
2947       // another way msvc builds stack frame..
2948       i = 2;
2949       while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
2950         g_stack_fsz += 4;
2951         ops[i].flags |= OPF_RMD;
2952         ecx_push++;
2953         i++;
2954       }
2955       // and another way..
2956       if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
2957           && ops[i].operand[1].type == OPT_CONST
2958           && ops[i + 1].op == OP_CALL
2959           && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
2960       {
2961         g_stack_fsz += ops[i].operand[1].val;
2962         ops[i].flags |= OPF_RMD;
2963         i++;
2964         ops[i].flags |= OPF_RMD;
2965         i++;
2966       }
2967     }
2968
2969     found = 0;
2970     do {
2971       for (; i < opcnt; i++)
2972         if (ops[i].op == OP_RET)
2973           break;
2974       j = i - 1;
2975       if (i == opcnt && (ops[j].flags & OPF_JMP)) {
2976         if (found && is_like_tailjmp(j))
2977             break;
2978         j--;
2979       }
2980
2981       if ((ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
2982           || ops[j].op == OP_LEAVE)
2983       {
2984         ops[j].flags |= OPF_RMD;
2985       }
2986       else if (!(g_ida_func_attr & IDAFA_NORETURN))
2987         ferr(&ops[j], "'pop ebp' expected\n");
2988
2989       if (g_stack_fsz != 0) {
2990         if (ops[j - 1].op == OP_MOV
2991             && IS(opr_name(&ops[j - 1], 0), "esp")
2992             && IS(opr_name(&ops[j - 1], 1), "ebp"))
2993         {
2994           ops[j - 1].flags |= OPF_RMD;
2995         }
2996         else if (ops[j].op != OP_LEAVE
2997           && !(g_ida_func_attr & IDAFA_NORETURN))
2998         {
2999           ferr(&ops[j - 1], "esp restore expected\n");
3000         }
3001
3002         if (ecx_push && ops[j - 2].op == OP_POP
3003           && IS(opr_name(&ops[j - 2], 0), "ecx"))
3004         {
3005           ferr(&ops[j - 2], "unexpected ecx pop\n");
3006         }
3007       }
3008
3009       found = 1;
3010       i++;
3011     } while (i < opcnt);
3012   }
3013   else {
3014     for (i = 0; i < opcnt; i++) {
3015       if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3016         break;
3017       if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3018         && ops[i].operand[1].type == OPT_CONST)
3019       {
3020         g_sp_frame = 1;
3021         break;
3022       }
3023     }
3024
3025     found = 0;
3026     if (g_sp_frame)
3027     {
3028       g_stack_fsz = ops[i].operand[1].val;
3029       ops[i].flags |= OPF_RMD;
3030
3031       i++;
3032       do {
3033         for (; i < opcnt; i++)
3034           if (ops[i].op == OP_RET)
3035             break;
3036         j = i - 1;
3037         if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3038           if (found && is_like_tailjmp(j))
3039               break;
3040           j--;
3041         }
3042
3043         if (ops[j].op != OP_ADD
3044             || !IS(opr_name(&ops[j], 0), "esp")
3045             || ops[j].operand[1].type != OPT_CONST
3046             || ops[j].operand[1].val != g_stack_fsz)
3047           ferr(&ops[j], "'add esp' expected\n");
3048         ops[j].flags |= OPF_RMD;
3049
3050         found = 1;
3051         i++;
3052       } while (i < opcnt);
3053     }
3054   }
3055
3056   // pass2:
3057   // - parse calls with labels
3058   // - resolve all branches
3059   for (i = 0; i < opcnt; i++)
3060   {
3061     po = &ops[i];
3062     po->bt_i = -1;
3063     po->btj = NULL;
3064
3065     if (po->flags & OPF_RMD)
3066       continue;
3067
3068     if (po->op == OP_CALL) {
3069       pp = NULL;
3070
3071       if (po->operand[0].type == OPT_LABEL) {
3072         tmpname = opr_name(po, 0);
3073         if (IS_START(tmpname, "loc_"))
3074           ferr(po, "call to loc_*\n");
3075         pp_c = proto_parse(fhdr, tmpname, 0);
3076         if (pp_c == NULL)
3077           ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3078
3079         pp = proto_clone(pp_c);
3080         my_assert_not(pp, NULL);
3081       }
3082       else if (po->datap != NULL) {
3083         pp = calloc(1, sizeof(*pp));
3084         my_assert_not(pp, NULL);
3085
3086         ret = parse_protostr(po->datap, pp);
3087         if (ret < 0)
3088           ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3089         free(po->datap);
3090         po->datap = NULL;
3091       }
3092
3093       if (pp != NULL) {
3094         if (pp->is_fptr)
3095           check_func_pp(po, pp, "fptr var call");
3096         if (pp->is_noreturn)
3097           po->flags |= OPF_TAIL;
3098         po->datap = pp;
3099       }
3100       continue;
3101     }
3102
3103     if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3104       continue;
3105
3106     if (po->operand[0].type == OPT_REGMEM) {
3107       char *p = strchr(po->operand[0].name, '[');
3108       if (p == NULL)
3109         goto tailcall;
3110       ret = p - po->operand[0].name;
3111       strncpy(buf1, po->operand[0].name, ret);
3112       buf1[ret] = 0;
3113
3114       for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3115         if (IS(g_func_pd[j].label, buf1)) {
3116           pd = &g_func_pd[j];
3117           break;
3118         }
3119       }
3120       if (pd == NULL)
3121         //ferr(po, "label '%s' not parsed?\n", buf1);
3122         goto tailcall;
3123       if (pd->type != OPT_OFFSET)
3124         ferr(po, "label '%s' with non-offset data?\n", buf1);
3125
3126       // find all labels, link
3127       for (j = 0; j < pd->count; j++) {
3128         for (l = 0; l < opcnt; l++) {
3129           if (g_labels[l][0] && IS(g_labels[l], pd->d[j].u.label)) {
3130             add_label_ref(&g_label_refs[l], i);
3131             pd->d[j].bt_i = l;
3132             break;
3133           }
3134         }
3135       }
3136
3137       po->btj = pd;
3138       continue;
3139     }
3140
3141     for (l = 0; l < opcnt; l++) {
3142       if (g_labels[l][0] && IS(po->operand[0].name, g_labels[l])) {
3143         add_label_ref(&g_label_refs[l], i);
3144         po->bt_i = l;
3145         break;
3146       }
3147     }
3148
3149     if (po->bt_i != -1)
3150       continue;
3151
3152     if (po->operand[0].type == OPT_LABEL)
3153       // assume tail call
3154       goto tailcall;
3155
3156     ferr(po, "unhandled branch\n");
3157
3158 tailcall:
3159     po->op = OP_CALL;
3160     po->flags |= OPF_TAIL;
3161     if (i > 0 && ops[i - 1].op == OP_POP)
3162       po->flags |= OPF_ATAIL;
3163     i--; // reprocess
3164   }
3165
3166   // pass3:
3167   // - remove dead labels
3168   // - process calls
3169   for (i = 0; i < opcnt; i++)
3170   {
3171     if (g_labels[i][0] != 0 && g_label_refs[i].i == -1)
3172       g_labels[i][0] = 0;
3173
3174     po = &ops[i];
3175     if (po->flags & OPF_RMD)
3176       continue;
3177
3178     if (po->op == OP_CALL)
3179     {
3180       tmpname = opr_name(po, 0);
3181       pp = po->datap;
3182       if (pp == NULL)
3183       {
3184         // indirect call
3185         pp_c = resolve_icall(i, opcnt, &l);
3186         if (pp_c != NULL) {
3187           pp = proto_clone(pp_c);
3188           my_assert_not(pp, NULL);
3189           if (l)
3190             // not resolved just to single func
3191             pp->is_fptr = 1;
3192           if (po->operand[0].type == OPT_REG)
3193             // we resolved this call and no longer need the register
3194             po->regmask_src &= ~(1 << po->operand[0].reg);
3195         }
3196         if (pp == NULL) {
3197           pp = calloc(1, sizeof(*pp));
3198           my_assert_not(pp, NULL);
3199           pp->is_fptr = 1;
3200           ret = scan_for_esp_adjust(i + 1, opcnt, &j, &l);
3201           if (ret < 0) {
3202             if (!g_allow_regfunc)
3203               ferr(po, "non-__cdecl indirect call unhandled yet\n");
3204             pp->is_unresolved = 1;
3205             j = 0;
3206           }
3207           j /= 4;
3208           if (j > ARRAY_SIZE(pp->arg))
3209             ferr(po, "esp adjust too large: %d\n", j);
3210           pp->ret_type.name = strdup("int");
3211           pp->argc = pp->argc_stack = j;
3212           for (arg = 0; arg < pp->argc; arg++)
3213             pp->arg[arg].type.name = strdup("int");
3214         }
3215         po->datap = pp;
3216       }
3217
3218       // look for and make use of esp adjust
3219       ret = -1;
3220       if (!pp->is_stdcall && pp->argc_stack > 0)
3221         ret = scan_for_esp_adjust(i + 1, opcnt, &j, &l);
3222       if (ret >= 0) {
3223         if (pp->is_vararg) {
3224           if (j / 4 < pp->argc_stack)
3225             ferr(po, "esp adjust is too small: %x < %x\n",
3226               j, pp->argc_stack * 4);
3227           // modify pp to make it have varargs as normal args
3228           arg = pp->argc;
3229           pp->argc += j / 4 - pp->argc_stack;
3230           for (; arg < pp->argc; arg++) {
3231             pp->arg[arg].type.name = strdup("int");
3232             pp->argc_stack++;
3233           }
3234           if (pp->argc > ARRAY_SIZE(pp->arg))
3235             ferr(po, "too many args for '%s'\n", tmpname);
3236         }
3237         if (pp->argc_stack != j / 4)
3238           ferr(po, "stack tracking failed for '%s': %x %x\n",
3239             tmpname, pp->argc_stack * 4, j);
3240
3241         ops[ret].flags |= OPF_RMD;
3242         if (ops[ret].op == OP_POP && j > 4) {
3243           // deal with multi-pop stack adjust
3244           j = pp->argc_stack;
3245           while (ops[ret].op == OP_POP && j > 0 && ret < opcnt) {
3246             ops[ret].flags |= OPF_RMD;
3247             j--;
3248             ret++;
3249           }
3250         }
3251         else if (!l) {
3252           // a bit of a hack, but deals with use of
3253           // single adj for multiple calls
3254           ops[ret].operand[1].val -= j;
3255         }
3256       }
3257       else if (pp->is_vararg)
3258         ferr(po, "missing esp_adjust for vararg func '%s'\n",
3259           pp->name);
3260
3261       if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
3262         // since we know the args, collect them
3263         collect_call_args(po, i, pp, &regmask, &save_arg_vars,
3264           i + opcnt * 2);
3265       }
3266
3267       if (strstr(pp->ret_type.name, "int64"))
3268         need_tmp64 = 1;
3269     }
3270   }
3271
3272   // pass4:
3273   // - find POPs for PUSHes, rm both
3274   // - scan for STD/CLD, propagate DF
3275   // - scan for all used registers
3276   // - find flag set ops for their users
3277   // - do unreselved calls
3278   // - declare indirect functions
3279   for (i = 0; i < opcnt; i++) {
3280     po = &ops[i];
3281     if (po->flags & OPF_RMD)
3282       continue;
3283
3284     if (po->op == OP_PUSH && (po->flags & OPF_RSAVE)) {
3285       reg = po->operand[0].reg;
3286       if (!(regmask & (1 << reg)))
3287         // not a reg save after all, rerun scan_for_pop
3288         po->flags &= ~OPF_RSAVE;
3289       else
3290         regmask_save |= 1 << reg;
3291     }
3292
3293     if (po->op == OP_PUSH && po->argnum == 0
3294       && !(po->flags & OPF_RSAVE))
3295     {
3296       if (po->operand[0].type == OPT_REG)
3297       {
3298         reg = po->operand[0].reg;
3299         if (reg < 0)
3300           ferr(po, "reg not set for push?\n");
3301
3302         depth = 0;
3303         ret = scan_for_pop(i + 1, opcnt,
3304                 po->operand[0].name, i + opcnt * 3, 0, &depth, 0);
3305         if (ret == 1) {
3306           if (depth > 1)
3307             ferr(po, "too much depth: %d\n", depth);
3308
3309           po->flags |= OPF_RMD;
3310           scan_for_pop(i + 1, opcnt, po->operand[0].name,
3311             i + opcnt * 4, 0, &depth, 1);
3312           continue;
3313         }
3314         ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].name, 0);
3315         if (ret == 0) {
3316           arg = OPF_RMD;
3317           if (regmask & (1 << reg)) {
3318             if (regmask_save & (1 << reg))
3319               ferr(po, "%s already saved?\n", po->operand[0].name);
3320             arg = OPF_RSAVE;
3321           }
3322           po->flags |= arg;
3323           scan_for_pop_ret(i + 1, opcnt, po->operand[0].name, arg);
3324           continue;
3325         }
3326       }
3327       else if (po->operand[0].type == OPT_CONST) {
3328         for (j = i + 1; j < opcnt; j++) {
3329           if ((ops[j].flags & (OPF_JMP|OPF_TAIL|OPF_RSAVE))
3330             || ops[j].op == OP_PUSH || g_labels[i][0] != 0)
3331           {
3332             break;
3333           }
3334
3335           if (!(ops[j].flags & OPF_RMD) && ops[j].op == OP_POP)
3336           {
3337             po->flags |= OPF_RMD;
3338             ops[j].datap = po;
3339             break;
3340           }
3341         }
3342       }
3343     }
3344
3345     if (po->op == OP_STD) {
3346       po->flags |= OPF_DF | OPF_RMD;
3347       scan_propagate_df(i + 1, opcnt);
3348     }
3349
3350     regmask_now = po->regmask_src | po->regmask_dst;
3351     if (regmask_now & (1 << xBP)) {
3352       if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
3353         if (po->regmask_dst & (1 << xBP))
3354           // compiler decided to drop bp frame and use ebp as scratch
3355           scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
3356         else
3357           regmask_now &= ~(1 << xBP);
3358       }
3359     }
3360
3361     regmask |= regmask_now;
3362
3363     if (po->flags & OPF_CC)
3364     {
3365       int setters[16], cnt = 0, branched = 0;
3366
3367       ret = scan_for_flag_set(i, i + opcnt * 6,
3368               &branched, setters, &cnt);
3369       if (ret < 0 || cnt <= 0)
3370         ferr(po, "unable to trace flag setter(s)\n");
3371       if (cnt > ARRAY_SIZE(setters))
3372         ferr(po, "too many flag setters\n");
3373
3374       pfo = split_cond(po, po->op, &dummy);
3375       for (j = 0; j < cnt; j++)
3376       {
3377         tmp_op = &ops[setters[j]]; // flag setter
3378         pfomask = 0;
3379
3380         // to get nicer code, we try to delay test and cmp;
3381         // if we can't because of operand modification, or if we
3382         // have arith op, or branch, make it calculate flags explicitly
3383         if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
3384         {
3385           if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
3386             pfomask = 1 << pfo;
3387         }
3388         else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
3389           pfomask = 1 << pfo;
3390         }
3391         else {
3392           // see if we'll be able to handle based on op result
3393           if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
3394                && pfo != PFO_Z && pfo != PFO_S && pfo != PFO_P)
3395               || branched
3396               || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
3397             pfomask = 1 << pfo;
3398
3399           if (tmp_op->op == OP_ADD && pfo == PFO_C)
3400             need_tmp64 = 1;
3401         }
3402         if (pfomask) {
3403           tmp_op->pfomask |= pfomask;
3404           cond_vars |= pfomask;
3405         }
3406         // note: may overwrite, currently not a problem
3407         po->datap = tmp_op;
3408       }
3409
3410       if (po->op == OP_RCL || po->op == OP_RCR
3411        || po->op == OP_ADC || po->op == OP_SBB)
3412         cond_vars |= 1 << PFO_C;
3413     }
3414     else if (po->op == OP_CMPS || po->op == OP_SCAS) {
3415       cond_vars |= 1 << PFO_Z;
3416     }
3417     else if (po->op == OP_MUL
3418       || (po->op == OP_IMUL && po->operand_cnt == 1))
3419     {
3420       need_tmp64 = 1;
3421     }
3422     else if (po->op == OP_CALL) {
3423       pp = po->datap;
3424       if (pp == NULL)
3425         ferr(po, "NULL pp\n");
3426
3427       if (pp->is_unresolved) {
3428         int regmask_stack = 0;
3429         collect_call_args(po, i, pp, &regmask, &save_arg_vars,
3430           i + opcnt * 2);
3431
3432         // this is pretty rough guess:
3433         // see ecx and edx were pushed (and not their saved versions)
3434         for (arg = 0; arg < pp->argc; arg++) {
3435           if (pp->arg[arg].reg != NULL)
3436             continue;
3437
3438           tmp_op = pp->arg[arg].datap;
3439           if (tmp_op == NULL)
3440             ferr(po, "parsed_op missing for arg%d\n", arg);
3441           if (tmp_op->argnum == 0 && tmp_op->operand[0].type == OPT_REG)
3442             regmask_stack |= 1 << tmp_op->operand[0].reg;
3443         }
3444
3445         if (!((regmask_stack & (1 << xCX))
3446           && (regmask_stack & (1 << xDX))))
3447         {
3448           if (pp->argc_stack != 0
3449            || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
3450           {
3451             pp_insert_reg_arg(pp, "ecx");
3452             pp->is_fastcall = 1;
3453             regmask_init |= 1 << xCX;
3454             regmask |= 1 << xCX;
3455           }
3456           if (pp->argc_stack != 0
3457            || ((regmask | regmask_arg) & (1 << xDX)))
3458           {
3459             pp_insert_reg_arg(pp, "edx");
3460             regmask_init |= 1 << xDX;
3461             regmask |= 1 << xDX;
3462           }
3463         }
3464
3465         // note: __cdecl doesn't fall into is_unresolved category
3466         if (pp->argc_stack > 0)
3467           pp->is_stdcall = 1;
3468       }
3469
3470       for (arg = 0; arg < pp->argc; arg++) {
3471         if (pp->arg[arg].reg != NULL) {
3472           reg = char_array_i(regs_r32,
3473                   ARRAY_SIZE(regs_r32), pp->arg[arg].reg);
3474           if (reg < 0)
3475             ferr(ops, "arg '%s' is not a reg?\n", pp->arg[arg].reg);
3476           if (!(regmask & (1 << reg))) {
3477             regmask_init |= 1 << reg;
3478             regmask |= 1 << reg;
3479           }
3480         }
3481       }
3482
3483       // declare indirect funcs
3484       if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
3485         if (pp->name[0] != 0) {
3486           memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
3487           memcpy(pp->name, "i_", 2);
3488
3489           // might be declared already
3490           found = 0;
3491           for (j = 0; j < i; j++) {
3492             if (ops[j].op == OP_CALL && (pp_tmp = ops[j].datap)) {
3493               if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
3494                 found = 1;
3495                 break;
3496               }
3497             }
3498           }
3499           if (found)
3500             continue;
3501         }
3502         else
3503           snprintf(pp->name, sizeof(pp->name), "icall%d", i);
3504
3505         fprintf(fout, "  %s (", pp->ret_type.name);
3506         output_pp_attrs(fout, pp, 0);
3507         fprintf(fout, "*%s)(", pp->name);
3508         for (j = 0; j < pp->argc; j++) {
3509           if (j > 0)
3510             fprintf(fout, ", ");
3511           fprintf(fout, "%s a%d", pp->arg[j].type.name, j + 1);
3512         }
3513         fprintf(fout, ");\n");
3514       }
3515     }
3516     else if (po->op == OP_RET && !IS(g_func_pp->ret_type.name, "void"))
3517       regmask |= 1 << xAX;
3518     else if (po->op == OP_DIV || po->op == OP_IDIV) {
3519       // 32bit division is common, look for it
3520       if (po->op == OP_DIV)
3521         ret = scan_for_reg_clear(i, xDX);
3522       else
3523         ret = scan_for_cdq_edx(i);
3524       if (ret >= 0)
3525         po->flags |= OPF_32BIT;
3526       else
3527         need_tmp64 = 1;
3528     }
3529     else if (po->op == OP_CLD)
3530       po->flags |= OPF_RMD;
3531
3532     if (po->op == OP_RCL || po->op == OP_RCR || po->op == OP_XCHG) {
3533       need_tmp_var = 1;
3534     }
3535   }
3536
3537   // pass4:
3538   // - confirm regmask_save, it might have been reduced
3539   if (regmask_save != 0)
3540   {
3541     regmask_save = 0;
3542     for (i = 0; i < opcnt; i++) {
3543       po = &ops[i];
3544       if (po->flags & OPF_RMD)
3545         continue;
3546
3547       if (po->op == OP_PUSH && (po->flags & OPF_RSAVE))
3548         regmask_save |= 1 << po->operand[0].reg;
3549     }
3550   }
3551
3552
3553   // output LUTs/jumptables
3554   for (i = 0; i < g_func_pd_cnt; i++) {
3555     pd = &g_func_pd[i];
3556     fprintf(fout, "  static const ");
3557     if (pd->type == OPT_OFFSET) {
3558       fprintf(fout, "void *jt_%s[] =\n    { ", pd->label);
3559
3560       for (j = 0; j < pd->count; j++) {
3561         if (j > 0)
3562           fprintf(fout, ", ");
3563         fprintf(fout, "&&%s", pd->d[j].u.label);
3564       }
3565     }
3566     else {
3567       fprintf(fout, "%s %s[] =\n    { ",
3568         lmod_type_u(ops, pd->lmod), pd->label);
3569
3570       for (j = 0; j < pd->count; j++) {
3571         if (j > 0)
3572           fprintf(fout, ", ");
3573         fprintf(fout, "%u", pd->d[j].u.val);
3574       }
3575     }
3576     fprintf(fout, " };\n");
3577   }
3578
3579   // declare stack frame, va_arg
3580   if (g_stack_fsz)
3581     fprintf(fout, "  union { u32 d[%d]; u16 w[%d]; u8 b[%d]; } sf;\n",
3582       (g_stack_fsz + 3) / 4, (g_stack_fsz + 1) / 2, g_stack_fsz);
3583
3584   if (g_func_pp->is_vararg)
3585     fprintf(fout, "  va_list ap;\n");
3586
3587   // declare arg-registers
3588   for (i = 0; i < g_func_pp->argc; i++) {
3589     if (g_func_pp->arg[i].reg != NULL) {
3590       reg = char_array_i(regs_r32,
3591               ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
3592       if (regmask & (1 << reg)) {
3593         fprintf(fout, "  u32 %s = (u32)a%d;\n",
3594           g_func_pp->arg[i].reg, i + 1);
3595       }
3596       else
3597         fprintf(fout, "  // %s = a%d; // unused\n",
3598           g_func_pp->arg[i].reg, i + 1);
3599       had_decl = 1;
3600     }
3601   }
3602
3603   regmask_now = regmask & ~regmask_arg;
3604   regmask_now &= ~(1 << xSP);
3605   if (regmask_now) {
3606     for (reg = 0; reg < 8; reg++) {
3607       if (regmask_now & (1 << reg)) {
3608         fprintf(fout, "  u32 %s", regs_r32[reg]);
3609         if (regmask_init & (1 << reg))
3610           fprintf(fout, " = 0");
3611         fprintf(fout, ";\n");
3612         had_decl = 1;
3613       }
3614     }
3615   }
3616
3617   if (regmask_save) {
3618     for (reg = 0; reg < 8; reg++) {
3619       if (regmask_save & (1 << reg)) {
3620         fprintf(fout, "  u32 s_%s;\n", regs_r32[reg]);
3621         had_decl = 1;
3622       }
3623     }
3624   }
3625
3626   if (save_arg_vars) {
3627     for (reg = 0; reg < 32; reg++) {
3628       if (save_arg_vars & (1 << reg)) {
3629         fprintf(fout, "  u32 s_a%d;\n", reg + 1);
3630         had_decl = 1;
3631       }
3632     }
3633   }
3634
3635   if (cond_vars) {
3636     for (i = 0; i < 8; i++) {
3637       if (cond_vars & (1 << i)) {
3638         fprintf(fout, "  u32 cond_%s;\n", parsed_flag_op_names[i]);
3639         had_decl = 1;
3640       }
3641     }
3642   }
3643
3644   if (need_tmp_var) {
3645     fprintf(fout, "  u32 tmp;\n");
3646     had_decl = 1;
3647   }
3648
3649   if (need_tmp64) {
3650     fprintf(fout, "  u64 tmp64;\n");
3651     had_decl = 1;
3652   }
3653
3654   if (had_decl)
3655     fprintf(fout, "\n");
3656
3657   if (g_func_pp->is_vararg) {
3658     if (g_func_pp->argc_stack == 0)
3659       ferr(ops, "vararg func without stack args?\n");
3660     fprintf(fout, "  va_start(ap, a%d);\n", g_func_pp->argc);
3661   }
3662
3663   // output ops
3664   for (i = 0; i < opcnt; i++)
3665   {
3666     if (g_labels[i][0] != 0) {
3667       fprintf(fout, "\n%s:\n", g_labels[i]);
3668       label_pending = 1;
3669
3670       delayed_flag_op = NULL;
3671       last_arith_dst = NULL;
3672     }
3673
3674     po = &ops[i];
3675     if (po->flags & OPF_RMD)
3676       continue;
3677
3678     no_output = 0;
3679
3680     #define assert_operand_cnt(n_) \
3681       if (po->operand_cnt != n_) \
3682         ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
3683
3684     // conditional/flag using op?
3685     if (po->flags & OPF_CC)
3686     {
3687       int is_delayed = 0;
3688       int is_inv = 0;
3689
3690       pfo = split_cond(po, po->op, &is_inv);
3691       tmp_op = po->datap;
3692
3693       // we go through all this trouble to avoid using parsed_flag_op,
3694       // which makes generated code much nicer
3695       if (delayed_flag_op != NULL)
3696       {
3697         out_cmp_test(buf1, sizeof(buf1), delayed_flag_op, pfo, is_inv);
3698         is_delayed = 1;
3699       }
3700       else if (last_arith_dst != NULL
3701         && (pfo == PFO_Z || pfo == PFO_S || pfo == PFO_P
3702            || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
3703            ))
3704       {
3705         out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
3706         out_test_for_cc(buf1, sizeof(buf1), po, pfo, is_inv,
3707           last_arith_dst->lmod, buf3);
3708         is_delayed = 1;
3709       }
3710       else if (tmp_op != NULL) {
3711         // use preprocessed flag calc results
3712         if (!(tmp_op->pfomask & (1 << pfo)))
3713           ferr(po, "not prepared for pfo %d\n", pfo);
3714
3715         // note: is_inv was not yet applied
3716         snprintf(buf1, sizeof(buf1), "(%scond_%s)",
3717           is_inv ? "!" : "", parsed_flag_op_names[pfo]);
3718       }
3719       else {
3720         ferr(po, "all methods of finding comparison failed\n");
3721       }
3722  
3723       if (po->flags & OPF_JMP) {
3724         fprintf(fout, "  if %s\n", buf1);
3725       }
3726       else if (po->op == OP_RCL || po->op == OP_RCR
3727                || po->op == OP_ADC || po->op == OP_SBB)
3728       {
3729         if (is_delayed)
3730           fprintf(fout, "  cond_%s = %s;\n",
3731             parsed_flag_op_names[pfo], buf1);
3732       }
3733       else if (po->flags & OPF_DATA) { // SETcc
3734         out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
3735         fprintf(fout, "  %s = %s;", buf2, buf1);
3736       }
3737       else {
3738         ferr(po, "unhandled conditional op\n");
3739       }
3740     }
3741
3742     pfomask = po->pfomask;
3743
3744     if (po->flags & (OPF_REPZ|OPF_REPNZ)) {
3745       // we need initial flags for ecx=0 case..
3746       if (i > 0 && ops[i - 1].op == OP_XOR
3747         && IS(ops[i - 1].operand[0].name,
3748               ops[i - 1].operand[1].name))
3749       {
3750         fprintf(fout, "  cond_z = ");
3751         if (pfomask & (1 << PFO_C))
3752           fprintf(fout, "cond_c = ");
3753         fprintf(fout, "0;\n");
3754       }
3755       else if (last_arith_dst != NULL) {
3756         out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
3757         out_test_for_cc(buf1, sizeof(buf1), po, PFO_Z, 0,
3758           last_arith_dst->lmod, buf3);
3759         fprintf(fout, "  cond_z = %s;\n", buf1);
3760       }
3761       else
3762         ferr(po, "missing initial ZF\n");
3763     }
3764
3765     switch (po->op)
3766     {
3767       case OP_MOV:
3768         assert_operand_cnt(2);
3769         propagate_lmod(po, &po->operand[0], &po->operand[1]);
3770         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
3771         fprintf(fout, "  %s = %s;", buf1,
3772             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
3773               po->operand[0].is_ptr ? "(void *)" : "", 0));
3774         break;
3775
3776       case OP_LEA:
3777         assert_operand_cnt(2);
3778         po->operand[1].lmod = OPLM_DWORD; // always
3779         fprintf(fout, "  %s = %s;",
3780             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
3781             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
3782               NULL, 1));
3783         break;
3784
3785       case OP_MOVZX:
3786         assert_operand_cnt(2);
3787         fprintf(fout, "  %s = %s;",
3788             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
3789             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
3790         break;
3791
3792       case OP_MOVSX:
3793         assert_operand_cnt(2);
3794         switch (po->operand[1].lmod) {
3795         case OPLM_BYTE:
3796           strcpy(buf3, "(s8)");
3797           break;
3798         case OPLM_WORD:
3799           strcpy(buf3, "(s16)");
3800           break;
3801         default:
3802           ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
3803         }
3804         fprintf(fout, "  %s = %s;",
3805             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
3806             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
3807               buf3, 0));
3808         break;
3809
3810       case OP_XCHG:
3811         assert_operand_cnt(2);
3812         propagate_lmod(po, &po->operand[0], &po->operand[1]);
3813         fprintf(fout, "  tmp = %s;",
3814           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
3815         fprintf(fout, " %s = %s;",
3816           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
3817           out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], "", 0));
3818         fprintf(fout, " %s = tmp;",
3819           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]));
3820         snprintf(g_comment, sizeof(g_comment), "xchg");
3821         break;
3822
3823       case OP_NOT:
3824         assert_operand_cnt(1);
3825         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
3826         fprintf(fout, "  %s = ~%s;", buf1, buf1);
3827         break;
3828
3829       case OP_CDQ:
3830         assert_operand_cnt(2);
3831         fprintf(fout, "  %s = (s32)%s >> 31;",
3832             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
3833             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
3834         strcpy(g_comment, "cdq");
3835         break;
3836
3837       case OP_STOS:
3838         assert_operand_cnt(3);
3839         if (po->flags & OPF_REP) {
3840           fprintf(fout, "  for (; ecx != 0; ecx--, edi %c= %d)\n",
3841             (po->flags & OPF_DF) ? '-' : '+',
3842             lmod_bytes(po, po->operand[0].lmod));
3843           fprintf(fout, "    %sedi = eax;",
3844             lmod_cast_u_ptr(po, po->operand[0].lmod));
3845           strcpy(g_comment, "rep stos");
3846         }
3847         else {
3848           fprintf(fout, "    %sedi = eax; edi %c= %d;",
3849             lmod_cast_u_ptr(po, po->operand[0].lmod),
3850             (po->flags & OPF_DF) ? '-' : '+',
3851             lmod_bytes(po, po->operand[0].lmod));
3852           strcpy(g_comment, "stos");
3853         }
3854         break;
3855
3856       case OP_MOVS:
3857         assert_operand_cnt(3);
3858         j = lmod_bytes(po, po->operand[0].lmod);
3859         strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
3860         l = (po->flags & OPF_DF) ? '-' : '+';
3861         if (po->flags & OPF_REP) {
3862           fprintf(fout,
3863             "  for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
3864             l, j, l, j);
3865           fprintf(fout,
3866             "    %sedi = %sesi;", buf1, buf1);
3867           strcpy(g_comment, "rep movs");
3868         }
3869         else {
3870           fprintf(fout, "    %sedi = %sesi; edi %c= %d; esi %c= %d;",
3871             buf1, buf1, l, j, l, j);
3872           strcpy(g_comment, "movs");
3873         }
3874         break;
3875
3876       case OP_CMPS:
3877         // repe ~ repeat while ZF=1
3878         assert_operand_cnt(3);
3879         j = lmod_bytes(po, po->operand[0].lmod);
3880         strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
3881         l = (po->flags & OPF_DF) ? '-' : '+';
3882         if (po->flags & OPF_REP) {
3883           fprintf(fout,
3884             "  for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d) {\n",
3885             l, j, l, j);
3886           if (pfomask & (1 << PFO_C)) {
3887             // ugh..
3888             fprintf(fout,
3889             "    cond_c = %sedi < %sesi;\n", buf1, buf1);
3890             pfomask &= ~(1 << PFO_C);
3891           }
3892           fprintf(fout,
3893             "    if ((cond_z = (%sedi == %sesi)) %s 0)\n",
3894               buf1, buf1, (po->flags & OPF_REPZ) ? "==" : "!=");
3895           fprintf(fout,
3896             "      break;\n"
3897             "  }");
3898           snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
3899             (po->flags & OPF_REPZ) ? "e" : "ne");
3900         }
3901         else {
3902           fprintf(fout,
3903             "    cond_z = (%sedi = %sesi); edi %c= %d; esi %c= %d;",
3904             buf1, buf1, l, j, l, j);
3905           strcpy(g_comment, "cmps");
3906         }
3907         pfomask &= ~(1 << PFO_Z);
3908         last_arith_dst = NULL;
3909         delayed_flag_op = NULL;
3910         break;
3911
3912       case OP_SCAS:
3913         // only does ZF (for now)
3914         // repe ~ repeat while ZF=1
3915         assert_operand_cnt(3);
3916         j = lmod_bytes(po, po->operand[0].lmod);
3917         l = (po->flags & OPF_DF) ? '-' : '+';
3918         if (po->flags & OPF_REP) {
3919           fprintf(fout,
3920             "  for (; ecx != 0; ecx--, edi %c= %d)\n", l, j);
3921           fprintf(fout,
3922             "    if ((cond_z = (%seax == %sedi)) %s 0)\n",
3923               lmod_cast_u(po, po->operand[0].lmod),
3924               lmod_cast_u_ptr(po, po->operand[0].lmod),
3925               (po->flags & OPF_REPZ) ? "==" : "!=");
3926           fprintf(fout,
3927             "      break;");
3928           snprintf(g_comment, sizeof(g_comment), "rep%s scas",
3929             (po->flags & OPF_REPZ) ? "e" : "ne");
3930         }
3931         else {
3932           fprintf(fout, "    cond_z = (%seax = %sedi); edi %c= %d;",
3933               lmod_cast_u(po, po->operand[0].lmod),
3934               lmod_cast_u_ptr(po, po->operand[0].lmod), l, j);
3935           strcpy(g_comment, "scas");
3936         }
3937         pfomask &= ~(1 << PFO_Z);
3938         last_arith_dst = NULL;
3939         delayed_flag_op = NULL;
3940         break;
3941
3942       // arithmetic w/flags
3943       case OP_AND:
3944       case OP_OR:
3945         propagate_lmod(po, &po->operand[0], &po->operand[1]);
3946         // fallthrough
3947       dualop_arith:
3948         assert_operand_cnt(2);
3949         fprintf(fout, "  %s %s= %s;",
3950             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
3951             op_to_c(po),
3952             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
3953         output_std_flags(fout, po, &pfomask, buf1);
3954         last_arith_dst = &po->operand[0];
3955         delayed_flag_op = NULL;
3956         break;
3957
3958       case OP_SHL:
3959       case OP_SHR:
3960         assert_operand_cnt(2);
3961         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
3962         if (pfomask & (1 << PFO_C)) {
3963           if (po->operand[1].type == OPT_CONST) {
3964             l = lmod_bytes(po, po->operand[0].lmod) * 8;
3965             j = po->operand[1].val;
3966             j %= l;
3967             if (j != 0) {
3968               if (po->op == OP_SHL)
3969                 j = l - j;
3970               else
3971                 j -= 1;
3972               fprintf(fout, "  cond_c = (%s >> %d) & 1;\n",
3973                 buf1, j);
3974             }
3975             else
3976               ferr(po, "zero shift?\n");
3977           }
3978           else
3979             ferr(po, "TODO\n");
3980           pfomask &= ~(1 << PFO_C);
3981         }
3982         fprintf(fout, "  %s %s= %s;", buf1, op_to_c(po),
3983             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
3984         output_std_flags(fout, po, &pfomask, buf1);
3985         last_arith_dst = &po->operand[0];
3986         delayed_flag_op = NULL;
3987         break;
3988
3989       case OP_SAR:
3990         assert_operand_cnt(2);
3991         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
3992         fprintf(fout, "  %s = %s%s >> %s;", buf1,
3993           lmod_cast_s(po, po->operand[0].lmod), buf1,
3994           out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
3995         output_std_flags(fout, po, &pfomask, buf1);
3996         last_arith_dst = &po->operand[0];
3997         delayed_flag_op = NULL;
3998         break;
3999
4000       case OP_ROL:
4001       case OP_ROR:
4002         assert_operand_cnt(2);
4003         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
4004         if (po->operand[1].type == OPT_CONST) {
4005           j = po->operand[1].val;
4006           j %= lmod_bytes(po, po->operand[0].lmod) * 8;
4007           fprintf(fout, po->op == OP_ROL ?
4008             "  %s = (%s << %d) | (%s >> %d);" :
4009             "  %s = (%s >> %d) | (%s << %d);",
4010             buf1, buf1, j, buf1,
4011             lmod_bytes(po, po->operand[0].lmod) * 8 - j);
4012         }
4013         else
4014           ferr(po, "TODO\n");
4015         output_std_flags(fout, po, &pfomask, buf1);
4016         last_arith_dst = &po->operand[0];
4017         delayed_flag_op = NULL;
4018         break;
4019
4020       case OP_RCL:
4021       case OP_RCR:
4022         assert_operand_cnt(2);
4023         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
4024         l = lmod_bytes(po, po->operand[0].lmod) * 8;
4025         if (po->operand[1].type == OPT_CONST) {
4026           j = po->operand[1].val % l;
4027           if (j == 0)
4028             ferr(po, "zero rotate\n");
4029           fprintf(fout, "  tmp = (%s >> %d) & 1;\n",
4030             buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
4031           if (po->op == OP_RCL) {
4032             fprintf(fout,
4033               "  %s = (%s << %d) | (cond_c << %d)",
4034               buf1, buf1, j, j - 1);
4035             if (j != 1)
4036               fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
4037           }
4038           else {
4039             fprintf(fout,
4040               "  %s = (%s >> %d) | (cond_c << %d)",
4041               buf1, buf1, j, l - j);
4042             if (j != 1)
4043               fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
4044           }
4045           fprintf(fout, ";\n");
4046           fprintf(fout, "  cond_c = tmp;");
4047         }
4048         else
4049           ferr(po, "TODO\n");
4050         strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
4051         output_std_flags(fout, po, &pfomask, buf1);
4052         last_arith_dst = &po->operand[0];
4053         delayed_flag_op = NULL;
4054         break;
4055
4056       case OP_XOR:
4057         assert_operand_cnt(2);
4058         propagate_lmod(po, &po->operand[0], &po->operand[1]);
4059         if (IS(opr_name(po, 0), opr_name(po, 1))) {
4060           // special case for XOR
4061           if (pfomask & (1 << PFO_BE)) { // weird, but it happens..
4062             fprintf(fout, "  cond_be = 1;\n");
4063             pfomask &= ~(1 << PFO_BE);
4064           }
4065           fprintf(fout, "  %s = 0;",
4066             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
4067           last_arith_dst = &po->operand[0];
4068           delayed_flag_op = NULL;
4069           break;
4070         }
4071         goto dualop_arith;
4072
4073       case OP_ADD:
4074         assert_operand_cnt(2);
4075         propagate_lmod(po, &po->operand[0], &po->operand[1]);
4076         if (pfomask & (1 << PFO_C)) {
4077           fprintf(fout, "  tmp64 = (u64)%s + %s;\n",
4078             out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]),
4079             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
4080           fprintf(fout, "  cond_c = tmp64 >> 32;\n");
4081           fprintf(fout, "  %s = (u32)tmp64;",
4082             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
4083           strcat(g_comment, "add64");
4084           pfomask &= ~(1 << PFO_C);
4085           output_std_flags(fout, po, &pfomask, buf1);
4086           last_arith_dst = &po->operand[0];
4087           delayed_flag_op = NULL;
4088           break;
4089         }
4090         goto dualop_arith;
4091
4092       case OP_SUB:
4093         assert_operand_cnt(2);
4094         propagate_lmod(po, &po->operand[0], &po->operand[1]);
4095         if (pfomask & (1 << PFO_C)) {
4096           fprintf(fout, "  cond_c = %s < %s;\n",
4097             out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]),
4098             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
4099           pfomask &= ~(1 << PFO_C);
4100         }
4101         goto dualop_arith;
4102
4103       case OP_ADC:
4104       case OP_SBB:
4105         assert_operand_cnt(2);
4106         propagate_lmod(po, &po->operand[0], &po->operand[1]);
4107         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
4108         if (po->op == OP_SBB
4109           && IS(po->operand[0].name, po->operand[1].name))
4110         {
4111           // avoid use of unitialized var
4112           fprintf(fout, "  %s = -cond_c;", buf1);
4113           // carry remains what it was
4114           pfomask &= ~(1 << PFO_C);
4115         }
4116         else {
4117           fprintf(fout, "  %s %s= %s + cond_c;", buf1, op_to_c(po),
4118             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
4119         }
4120         output_std_flags(fout, po, &pfomask, buf1);
4121         last_arith_dst = &po->operand[0];
4122         delayed_flag_op = NULL;
4123         break;
4124
4125       case OP_INC:
4126       case OP_DEC:
4127         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
4128         if (po->operand[0].type == OPT_REG) {
4129           strcpy(buf2, po->op == OP_INC ? "++" : "--");
4130           fprintf(fout, "  %s%s;", buf1, buf2);
4131         }
4132         else {
4133           strcpy(buf2, po->op == OP_INC ? "+" : "-");
4134           fprintf(fout, "  %s %s= 1;", buf1, buf2);
4135         }
4136         output_std_flags(fout, po, &pfomask, buf1);
4137         last_arith_dst = &po->operand[0];
4138         delayed_flag_op = NULL;
4139         break;
4140
4141       case OP_NEG:
4142         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
4143         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
4144         fprintf(fout, "  %s = -%s%s;", buf1,
4145           lmod_cast_s(po, po->operand[0].lmod), buf2);
4146         last_arith_dst = &po->operand[0];
4147         delayed_flag_op = NULL;
4148         if (pfomask & (1 << PFO_C)) {
4149           fprintf(fout, "\n  cond_c = (%s != 0);", buf1);
4150           pfomask &= ~(1 << PFO_C);
4151         }
4152         break;
4153
4154       case OP_IMUL:
4155         if (po->operand_cnt == 2) {
4156           propagate_lmod(po, &po->operand[0], &po->operand[1]);
4157           goto dualop_arith;
4158         }
4159         if (po->operand_cnt == 3)
4160           ferr(po, "TODO imul3\n");
4161         // fallthrough
4162       case OP_MUL:
4163         assert_operand_cnt(1);
4164         strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
4165         fprintf(fout, "  tmp64 = %seax * %s%s;\n", buf1, buf1,
4166           out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
4167         fprintf(fout, "  edx = tmp64 >> 32;\n");
4168         fprintf(fout, "  eax = tmp64;");
4169         last_arith_dst = NULL;
4170         delayed_flag_op = NULL;
4171         break;
4172
4173       case OP_DIV:
4174       case OP_IDIV:
4175         assert_operand_cnt(1);
4176         if (po->operand[0].lmod != OPLM_DWORD)
4177           ferr(po, "unhandled lmod %d\n", po->operand[0].lmod);
4178
4179         out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
4180         strcpy(buf2, lmod_cast(po, po->operand[0].lmod,
4181           po->op == OP_IDIV));
4182         switch (po->operand[0].lmod) {
4183         case OPLM_DWORD:
4184           if (po->flags & OPF_32BIT)
4185             snprintf(buf3, sizeof(buf3), "%seax", buf2);
4186           else {
4187             fprintf(fout, "  tmp64 = ((u64)edx << 32) | eax;\n");
4188             snprintf(buf3, sizeof(buf3), "%stmp64",
4189               (po->op == OP_IDIV) ? "(s64)" : "");
4190           }
4191           if (po->operand[0].type == OPT_REG
4192             && po->operand[0].reg == xDX)
4193           {
4194             fprintf(fout, "  eax = %s / %s%s;", buf3, buf2, buf1);
4195             fprintf(fout, "  edx = %s %% %s%s;\n", buf3, buf2, buf1);
4196           }
4197           else {
4198             fprintf(fout, "  edx = %s %% %s%s;\n", buf3, buf2, buf1);
4199             fprintf(fout, "  eax = %s / %s%s;", buf3, buf2, buf1);
4200           }
4201           break;
4202         default:
4203           ferr(po, "unhandled division type\n");
4204         }
4205         last_arith_dst = NULL;
4206         delayed_flag_op = NULL;
4207         break;
4208
4209       case OP_TEST:
4210       case OP_CMP:
4211         propagate_lmod(po, &po->operand[0], &po->operand[1]);
4212         if (pfomask != 0) {
4213           for (j = 0; j < 8; j++) {
4214             if (pfomask & (1 << j)) {
4215               out_cmp_test(buf1, sizeof(buf1), po, j, 0);
4216               fprintf(fout, "  cond_%s = %s;",
4217                 parsed_flag_op_names[j], buf1);
4218             }
4219           }
4220           pfomask = 0;
4221         }
4222         else
4223           no_output = 1;
4224         last_arith_dst = NULL;
4225         delayed_flag_op = po;
4226         break;
4227
4228       // note: we reuse OP_Jcc for SETcc, only flags differ
4229       case OP_JO ... OP_JG:
4230         if (po->flags & OPF_JMP)
4231           fprintf(fout, "    goto %s;", po->operand[0].name);
4232         // else SETcc - should already be handled
4233         break;
4234
4235       case OP_JECXZ:
4236         fprintf(fout, "  if (ecx == 0)\n");
4237         fprintf(fout, "    goto %s;", po->operand[0].name);
4238         strcat(g_comment, "jecxz");
4239         break;
4240
4241       case OP_JMP:
4242         assert_operand_cnt(1);
4243         last_arith_dst = NULL;
4244         delayed_flag_op = NULL;
4245
4246         if (po->operand[0].type == OPT_REGMEM) {
4247           ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
4248                   buf1, buf2);
4249           if (ret != 2)
4250             ferr(po, "parse failure for jmp '%s'\n",
4251               po->operand[0].name);
4252           fprintf(fout, "  goto *jt_%s[%s];", buf1, buf2);
4253           break;
4254         }
4255         else if (po->operand[0].type != OPT_LABEL)
4256           ferr(po, "unhandled jmp type\n");
4257
4258         fprintf(fout, "  goto %s;", po->operand[0].name);
4259         break;
4260
4261       case OP_CALL:
4262         assert_operand_cnt(1);
4263         pp = po->datap;
4264         my_assert_not(pp, NULL);
4265
4266         if (pp->is_fptr && !pp->is_arg)
4267           fprintf(fout, "  %s = %s;\n", pp->name,
4268             out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
4269               "(void *)", 0));
4270
4271         fprintf(fout, "  ");
4272         if (strstr(pp->ret_type.name, "int64")) {
4273           if (po->flags & OPF_TAIL)
4274             ferr(po, "int64 and tail?\n");
4275           fprintf(fout, "tmp64 = ");
4276         }
4277         else if (!IS(pp->ret_type.name, "void")) {
4278           if (po->flags & OPF_TAIL) {
4279             if (!IS(g_func_pp->ret_type.name, "void")) {
4280               fprintf(fout, "return ");
4281               if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
4282                 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
4283             }
4284           }
4285           else if (regmask & (1 << xAX)) {
4286             fprintf(fout, "eax = ");
4287             if (pp->ret_type.is_ptr)
4288               fprintf(fout, "(u32)");
4289           }
4290         }
4291
4292         if (pp->name[0] == 0)
4293           ferr(po, "missing pp->name\n");
4294         fprintf(fout, "%s%s(", pp->name,
4295           pp->has_structarg ? "_sa" : "");
4296
4297         if (po->flags & OPF_ATAIL) {
4298           if (pp->argc_stack != g_func_pp->argc_stack
4299             || (pp->argc_stack > 0
4300                 && pp->is_stdcall != g_func_pp->is_stdcall))
4301             ferr(po, "incompatible tailcall\n");
4302
4303           for (arg = j = 0; arg < pp->argc; arg++) {
4304             if (arg > 0)
4305               fprintf(fout, ", ");
4306
4307             cast[0] = 0;
4308             if (pp->arg[arg].type.is_ptr)
4309               snprintf(cast, sizeof(cast), "(%s)",
4310                 pp->arg[arg].type.name);
4311
4312             if (pp->arg[arg].reg != NULL) {
4313               fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
4314               continue;
4315             }
4316             // stack arg
4317             for (; j < g_func_pp->argc; j++)
4318               if (g_func_pp->arg[j].reg == NULL)
4319                 break;
4320             fprintf(fout, "%sa%d", cast, j + 1);
4321             j++;
4322           }
4323         }
4324         else {
4325           for (arg = 0; arg < pp->argc; arg++) {
4326             if (arg > 0)
4327               fprintf(fout, ", ");
4328
4329             cast[0] = 0;
4330             if (pp->arg[arg].type.is_ptr)
4331               snprintf(cast, sizeof(cast), "(%s)",
4332                 pp->arg[arg].type.name);
4333
4334             if (pp->arg[arg].reg != NULL) {
4335               fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
4336               continue;
4337             }
4338
4339             // stack arg
4340             tmp_op = pp->arg[arg].datap;
4341             if (tmp_op == NULL)
4342               ferr(po, "parsed_op missing for arg%d\n", arg);
4343             if (tmp_op->argnum != 0) {
4344               fprintf(fout, "%ss_a%d", cast, tmp_op->argnum);
4345             }
4346             else {
4347               fprintf(fout, "%s",
4348                 out_src_opr(buf1, sizeof(buf1),
4349                   tmp_op, &tmp_op->operand[0], cast, 0));
4350             }
4351           }
4352         }
4353         fprintf(fout, ");");
4354
4355         if (strstr(pp->ret_type.name, "int64")) {
4356           fprintf(fout, "\n");
4357           fprintf(fout, "  edx = tmp64 >> 32;\n");
4358           fprintf(fout, "  eax = tmp64;");
4359         }
4360
4361         if (pp->is_unresolved) {
4362           snprintf(buf3, sizeof(buf3), " unresoved %dreg",
4363             pp->argc_reg);
4364           strcat(g_comment, buf3);
4365         }
4366
4367         if (po->flags & OPF_TAIL) {
4368           ret = 0;
4369           if (i == opcnt - 1 || pp->is_noreturn)
4370             ret = 0;
4371           else if (IS(pp->ret_type.name, "void"))
4372             ret = 1;
4373           else if (IS(g_func_pp->ret_type.name, "void"))
4374             ret = 1;
4375           // else already handled as 'return f()'
4376
4377           if (ret) {
4378             if (!IS(g_func_pp->ret_type.name, "void")) {
4379               ferr(po, "int func -> void func tailcall?\n");
4380             }
4381             else {
4382               fprintf(fout, "\n  return;");
4383               strcat(g_comment, " ^ tailcall");
4384             }
4385           }
4386           else
4387             strcat(g_comment, " tailcall");
4388         }
4389         if (pp->is_noreturn)
4390           strcat(g_comment, " noreturn");
4391         if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
4392           strcat(g_comment, " argframe");
4393         delayed_flag_op = NULL;
4394         last_arith_dst = NULL;
4395         break;
4396
4397       case OP_RET:
4398         if (g_func_pp->is_vararg)
4399           fprintf(fout, "  va_end(ap);\n");
4400  
4401         if (IS(g_func_pp->ret_type.name, "void")) {
4402           if (i != opcnt - 1 || label_pending)
4403             fprintf(fout, "  return;");
4404         }
4405         else if (g_func_pp->ret_type.is_ptr) {
4406           fprintf(fout, "  return (%s)eax;",
4407             g_func_pp->ret_type.name);
4408         }
4409         else if (IS(g_func_pp->ret_type.name, "__int64"))
4410           fprintf(fout, "  return ((u64)edx << 32) | eax;");
4411         else
4412           fprintf(fout, "  return eax;");
4413
4414         last_arith_dst = NULL;
4415         delayed_flag_op = NULL;
4416         break;
4417
4418       case OP_PUSH:
4419         if (po->argnum != 0) {
4420           // special case - saved func arg
4421           out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
4422           fprintf(fout, "  s_a%d = %s;", po->argnum, buf1);
4423           break;
4424         }
4425         else if (po->flags & OPF_RSAVE) {
4426           out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
4427           fprintf(fout, "  s_%s = %s;", buf1, buf1);
4428           break;
4429         }
4430         if (!(g_ida_func_attr & IDAFA_NORETURN))
4431           ferr(po, "stray push encountered\n");
4432         no_output = 1;
4433         break;
4434
4435       case OP_POP:
4436         if (po->flags & OPF_RSAVE) {
4437           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
4438           fprintf(fout, "  %s = s_%s;", buf1, buf1);
4439           break;
4440         }
4441         else if (po->datap != NULL) {
4442           // push/pop pair
4443           tmp_op = po->datap;
4444           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
4445           fprintf(fout, "  %s = %s;", buf1,
4446             out_src_opr(buf2, sizeof(buf2),
4447               tmp_op, &tmp_op->operand[0],
4448               po->operand[0].is_ptr ? "(void *)" : "", 0));
4449           break;
4450         }
4451         ferr(po, "stray pop encountered\n");
4452         break;
4453
4454       case OP_NOP:
4455         no_output = 1;
4456         break;
4457
4458       default:
4459         no_output = 1;
4460         ferr(po, "unhandled op type %d, flags %x\n",
4461           po->op, po->flags);
4462         break;
4463     }
4464
4465     if (g_comment[0] != 0) {
4466       char *p = g_comment;
4467       while (my_isblank(*p))
4468         p++;
4469       fprintf(fout, "  // %s", p);
4470       g_comment[0] = 0;
4471       no_output = 0;
4472     }
4473     if (!no_output)
4474       fprintf(fout, "\n");
4475
4476     // some sanity checking
4477     if (po->flags & OPF_REP) {
4478       if (po->op != OP_STOS && po->op != OP_MOVS
4479           && po->op != OP_CMPS && po->op != OP_SCAS)
4480         ferr(po, "unexpected rep\n");
4481       if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
4482           && (po->op == OP_CMPS || po->op == OP_SCAS))
4483         ferr(po, "cmps/scas with plain rep\n");
4484     }
4485     if ((po->flags & (OPF_REPZ|OPF_REPNZ))
4486         && po->op != OP_CMPS && po->op != OP_SCAS)
4487       ferr(po, "unexpected repz/repnz\n");
4488
4489     if (pfomask != 0)
4490       ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
4491
4492     // see is delayed flag stuff is still valid
4493     if (delayed_flag_op != NULL && delayed_flag_op != po) {
4494       if (is_any_opr_modified(delayed_flag_op, po, 0))
4495         delayed_flag_op = NULL;
4496     }
4497
4498     if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
4499       if (is_opr_modified(last_arith_dst, po))
4500         last_arith_dst = NULL;
4501     }
4502
4503     label_pending = 0;
4504   }
4505
4506   if (g_stack_fsz && !g_stack_frame_used)
4507     fprintf(fout, "  (void)sf;\n");
4508
4509   fprintf(fout, "}\n\n");
4510
4511   // cleanup
4512   for (i = 0; i < opcnt; i++) {
4513     struct label_ref *lr, *lr_del;
4514
4515     lr = g_label_refs[i].next;
4516     while (lr != NULL) {
4517       lr_del = lr;
4518       lr = lr->next;
4519       free(lr_del);
4520     }
4521     g_label_refs[i].i = -1;
4522     g_label_refs[i].next = NULL;
4523
4524     if (ops[i].op == OP_CALL) {
4525       pp = ops[i].datap;
4526       if (pp)
4527         proto_release(pp);
4528     }
4529   }
4530   g_func_pp = NULL;
4531 }
4532
4533 static void set_label(int i, const char *name)
4534 {
4535   const char *p;
4536   int len;
4537
4538   len = strlen(name);
4539   p = strchr(name, ':');
4540   if (p != NULL)
4541     len = p - name;
4542
4543   if (len > sizeof(g_labels[0]) - 1)
4544     aerr("label '%s' too long: %d\n", name, len);
4545   if (g_labels[i][0] != 0 && !IS_START(g_labels[i], "algn_"))
4546     aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
4547   memcpy(g_labels[i], name, len);
4548   g_labels[i][len] = 0;
4549 }
4550
4551 // '=' needs special treatment..
4552 static char *next_word_s(char *w, size_t wsize, char *s)
4553 {
4554         size_t i;
4555
4556         s = sskip(s);
4557
4558         for (i = 0; i < wsize - 1; i++) {
4559                 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
4560                         break;
4561                 w[i] = s[i];
4562         }
4563         w[i] = 0;
4564
4565         if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
4566                 printf("warning: '%s' truncated\n", w);
4567
4568         return s + i;
4569 }
4570
4571 struct chunk_item {
4572   char *name;
4573   long fptr;
4574   int asmln;
4575 };
4576
4577 static struct chunk_item *func_chunks;
4578 static int func_chunk_cnt;
4579 static int func_chunk_alloc;
4580
4581 static void add_func_chunk(FILE *fasm, const char *name, int line)
4582 {
4583   if (func_chunk_cnt >= func_chunk_alloc) {
4584     func_chunk_alloc *= 2;
4585     func_chunks = realloc(func_chunks,
4586       func_chunk_alloc * sizeof(func_chunks[0]));
4587     my_assert_not(func_chunks, NULL);
4588   }
4589   func_chunks[func_chunk_cnt].fptr = ftell(fasm);
4590   func_chunks[func_chunk_cnt].name = strdup(name);
4591   func_chunks[func_chunk_cnt].asmln = line;
4592   func_chunk_cnt++;
4593 }
4594
4595 static int cmp_chunks(const void *p1, const void *p2)
4596 {
4597   const struct chunk_item *c1 = p1, *c2 = p2;
4598   return strcmp(c1->name, c2->name);
4599 }
4600
4601 static int cmpstringp(const void *p1, const void *p2)
4602 {
4603   return strcmp(*(char * const *)p1, *(char * const *)p2);
4604 }
4605
4606 static void scan_ahead(FILE *fasm)
4607 {
4608   char words[2][256];
4609   char line[256];
4610   long oldpos;
4611   int oldasmln;
4612   int wordc;
4613   char *p;
4614   int i;
4615
4616   oldpos = ftell(fasm);
4617   oldasmln = asmln;
4618
4619   while (fgets(line, sizeof(line), fasm))
4620   {
4621     wordc = 0;
4622     asmln++;
4623
4624     p = sskip(line);
4625     if (*p == 0)
4626       continue;
4627
4628     if (*p == ';')
4629     {
4630       // get rid of random tabs
4631       for (i = 0; line[i] != 0; i++)
4632         if (line[i] == '\t')
4633           line[i] = ' ';
4634
4635       if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
4636       {
4637         p += 30;
4638         next_word(words[0], sizeof(words[0]), p);
4639         if (words[0][0] == 0)
4640           aerr("missing name for func chunk?\n");
4641
4642         add_func_chunk(fasm, words[0], asmln);
4643       }
4644       continue;
4645     } // *p == ';'
4646
4647     for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
4648       words[wordc][0] = 0;
4649       p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
4650       if (*p == 0 || *p == ';') {
4651         wordc++;
4652         break;
4653       }
4654     }
4655
4656     if (wordc == 2 && IS(words[1], "ends"))
4657       break;
4658   }
4659
4660   fseek(fasm, oldpos, SEEK_SET);
4661   asmln = oldasmln;
4662 }
4663
4664 int main(int argc, char *argv[])
4665 {
4666   FILE *fout, *fasm, *frlist;
4667   struct parsed_data *pd = NULL;
4668   int pd_alloc = 0;
4669   char **rlist = NULL;
4670   int rlist_len = 0;
4671   int rlist_alloc = 0;
4672   int func_chunks_used = 0;
4673   int func_chunks_sorted = 0;
4674   int func_chunk_i = -1;
4675   long func_chunk_ret = 0;
4676   int func_chunk_ret_ln = 0;
4677   int scanned_ahead = 0;
4678   char line[256];
4679   char words[20][256];
4680   enum opr_lenmod lmod;
4681   char *sctproto = NULL;
4682   int in_func = 0;
4683   int pending_endp = 0;
4684   int skip_func = 0;
4685   int skip_warned = 0;
4686   int eq_alloc;
4687   int verbose = 0;
4688   int arg_out;
4689   int arg;
4690   int pi = 0;
4691   int i, j;
4692   int ret, len;
4693   char *p;
4694   int wordc;
4695
4696   for (arg = 1; arg < argc; arg++) {
4697     if (IS(argv[arg], "-v"))
4698       verbose = 1;
4699     else if (IS(argv[arg], "-rf"))
4700       g_allow_regfunc = 1;
4701     else
4702       break;
4703   }
4704
4705   if (argc < arg + 3) {
4706     printf("usage:\n%s [-v] [-rf] <.c> <.asm> <hdrf> [rlist]*\n",
4707       argv[0]);
4708     return 1;
4709   }
4710
4711   arg_out = arg++;
4712
4713   asmfn = argv[arg++];
4714   fasm = fopen(asmfn, "r");
4715   my_assert_not(fasm, NULL);
4716
4717   hdrfn = argv[arg++];
4718   g_fhdr = fopen(hdrfn, "r");
4719   my_assert_not(g_fhdr, NULL);
4720
4721   rlist_alloc = 64;
4722   rlist = malloc(rlist_alloc * sizeof(rlist[0]));
4723   my_assert_not(rlist, NULL);
4724   // needs special handling..
4725   rlist[rlist_len++] = "__alloca_probe";
4726
4727   func_chunk_alloc = 32;
4728   func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
4729   my_assert_not(func_chunks, NULL);
4730
4731   memset(words, 0, sizeof(words));
4732
4733   for (; arg < argc; arg++) {
4734     frlist = fopen(argv[arg], "r");
4735     my_assert_not(frlist, NULL);
4736
4737     while (fgets(line, sizeof(line), frlist)) {
4738       p = sskip(line);
4739       if (*p == 0 || *p == ';')
4740         continue;
4741       if (*p == '#') {
4742         if (IS_START(p, "#if 0")
4743          || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
4744         {
4745           skip_func = 1;
4746         }
4747         else if (IS_START(p, "#endif"))
4748           skip_func = 0;
4749         continue;
4750       }
4751       if (skip_func)
4752         continue;
4753
4754       p = next_word(words[0], sizeof(words[0]), p);
4755       if (words[0][0] == 0)
4756         continue;
4757
4758       if (rlist_len >= rlist_alloc) {
4759         rlist_alloc = rlist_alloc * 2 + 64;
4760         rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
4761         my_assert_not(rlist, NULL);
4762       }
4763       rlist[rlist_len++] = strdup(words[0]);
4764     }
4765     skip_func = 0;
4766
4767     fclose(frlist);
4768     frlist = NULL;
4769   }
4770
4771   if (rlist_len > 0)
4772     qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
4773
4774   fout = fopen(argv[arg_out], "w");
4775   my_assert_not(fout, NULL);
4776
4777   eq_alloc = 128;
4778   g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
4779   my_assert_not(g_eqs, NULL);
4780
4781   for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
4782     g_label_refs[i].i = -1;
4783     g_label_refs[i].next = NULL;
4784   }
4785
4786   while (fgets(line, sizeof(line), fasm))
4787   {
4788     wordc = 0;
4789     asmln++;
4790
4791     p = sskip(line);
4792     if (*p == 0)
4793       continue;
4794
4795     // get rid of random tabs
4796     for (i = 0; line[i] != 0; i++)
4797       if (line[i] == '\t')
4798         line[i] = ' ';
4799
4800     if (*p == ';')
4801     {
4802       if (p[2] == '=' && IS_START(p, "; =============== S U B"))
4803         goto do_pending_endp; // eww..
4804
4805       if (p[2] == 'A' && IS_START(p, "; Attributes:"))
4806       {
4807         static const char *attrs[] = {
4808           "bp-based frame",
4809           "library function",
4810           "static",
4811           "noreturn",
4812           "thunk",
4813           "fpd=",
4814         };
4815
4816         // parse IDA's attribute-list comment
4817         g_ida_func_attr = 0;
4818         p = sskip(p + 13);
4819
4820         for (; *p != 0; p = sskip(p)) {
4821           for (i = 0; i < ARRAY_SIZE(attrs); i++) {
4822             if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
4823               g_ida_func_attr |= 1 << i;
4824               p += strlen(attrs[i]);
4825               break;
4826             }
4827           }
4828           if (i == ARRAY_SIZE(attrs)) {
4829             anote("unparsed IDA attr: %s\n", p);
4830             break;
4831           }
4832           if (IS(attrs[i], "fpd=")) {
4833             p = next_word(words[0], sizeof(words[0]), p);
4834             // ignore for now..
4835           }
4836         }
4837       }
4838       else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
4839       {
4840         p += 30;
4841         next_word(words[0], sizeof(words[0]), p);
4842         if (words[0][0] == 0)
4843           aerr("missing name for func chunk?\n");
4844
4845         if (!scanned_ahead) {
4846           add_func_chunk(fasm, words[0], asmln);
4847           func_chunks_sorted = 0;
4848         }
4849       }
4850       else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
4851       {
4852         if (func_chunk_i >= 0) {
4853           if (func_chunk_i < func_chunk_cnt
4854             && IS(func_chunks[func_chunk_i].name, g_func))
4855           {
4856             // move on to next chunk
4857             ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
4858             if (ret)
4859               aerr("seek failed for '%s' chunk #%d\n",
4860                 g_func, func_chunk_i);
4861             asmln = func_chunks[func_chunk_i].asmln;
4862             func_chunk_i++;
4863           }
4864           else {
4865             if (func_chunk_ret == 0)
4866               aerr("no return from chunk?\n");
4867             fseek(fasm, func_chunk_ret, SEEK_SET);
4868             asmln = func_chunk_ret_ln;
4869             func_chunk_ret = 0;
4870             pending_endp = 1;
4871           }
4872         }
4873       }
4874       else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
4875         func_chunks_used = 1;
4876         p += 20;
4877         if (IS_START(g_func, "sub_")) {
4878           unsigned long addr = strtoul(p, NULL, 16);
4879           unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
4880           if (addr > f_addr && !scanned_ahead) {
4881             anote("scan_ahead caused by '%s', addr %lx\n",
4882               g_func, addr);
4883             scan_ahead(fasm);
4884             scanned_ahead = 1;
4885             func_chunks_sorted = 0;
4886           }
4887         }
4888       }
4889       continue;
4890     } // *p == ';'
4891
4892 parse_words:
4893     for (i = wordc; i < ARRAY_SIZE(words); i++)
4894       words[i][0] = 0;
4895     for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
4896       p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
4897       if (*p == 0 || *p == ';') {
4898         wordc++;
4899         break;
4900       }
4901     }
4902     if (*p != 0 && *p != ';')
4903       aerr("too many words\n");
4904
4905     // alow asm patches in comments
4906     if (*p == ';') {
4907       if (IS_START(p, "; sctpatch:")) {
4908         p = sskip(p + 11);
4909         if (*p == 0 || *p == ';')
4910           continue;
4911         goto parse_words; // lame
4912       }
4913       if (IS_START(p, "; sctproto:")) {
4914         sctproto = strdup(p + 11);
4915       }
4916     }
4917
4918     if (wordc == 0) {
4919       // shouldn't happen
4920       awarn("wordc == 0?\n");
4921       continue;
4922     }
4923
4924     // don't care about this:
4925     if (words[0][0] == '.'
4926         || IS(words[0], "include")
4927         || IS(words[0], "assume") || IS(words[1], "segment")
4928         || IS(words[0], "align"))
4929     {
4930       continue;
4931     }
4932
4933 do_pending_endp:
4934     // do delayed endp processing to collect switch jumptables
4935     if (pending_endp) {
4936       if (in_func && !skip_func && wordc >= 2
4937           && ((words[0][0] == 'd' && words[0][2] == 0)
4938               || (words[1][0] == 'd' && words[1][2] == 0)))
4939       {
4940         i = 1;
4941         if (words[1][0] == 'd' && words[1][2] == 0) {
4942           // label
4943           if (g_func_pd_cnt >= pd_alloc) {
4944             pd_alloc = pd_alloc * 2 + 16;
4945             g_func_pd = realloc(g_func_pd,
4946               sizeof(g_func_pd[0]) * pd_alloc);
4947             my_assert_not(g_func_pd, NULL);
4948           }
4949           pd = &g_func_pd[g_func_pd_cnt];
4950           g_func_pd_cnt++;
4951           memset(pd, 0, sizeof(*pd));
4952           strcpy(pd->label, words[0]);
4953           pd->type = OPT_CONST;
4954           pd->lmod = lmod_from_directive(words[1]);
4955           i = 2;
4956         }
4957         else {
4958           if (pd == NULL) {
4959             if (verbose)
4960               anote("skipping alignment byte?\n");
4961             continue;
4962           }
4963           lmod = lmod_from_directive(words[0]);
4964           if (lmod != pd->lmod)
4965             aerr("lmod change? %d->%d\n", pd->lmod, lmod);
4966         }
4967
4968         if (pd->count_alloc < pd->count + wordc) {
4969           pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
4970           pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
4971           my_assert_not(pd->d, NULL);
4972         }
4973         for (; i < wordc; i++) {
4974           if (IS(words[i], "offset")) {
4975             pd->type = OPT_OFFSET;
4976             i++;
4977           }
4978           p = strchr(words[i], ',');
4979           if (p != NULL)
4980             *p = 0;
4981           if (pd->type == OPT_OFFSET)
4982             pd->d[pd->count].u.label = strdup(words[i]);
4983           else
4984             pd->d[pd->count].u.val = parse_number(words[i]);
4985           pd->d[pd->count].bt_i = -1;
4986           pd->count++;
4987         }
4988         continue;
4989       }
4990
4991       if (in_func && !skip_func)
4992         gen_func(fout, g_fhdr, g_func, pi);
4993
4994       pending_endp = 0;
4995       in_func = 0;
4996       g_ida_func_attr = 0;
4997       skip_warned = 0;
4998       skip_func = 0;
4999       g_func[0] = 0;
5000       func_chunks_used = 0;
5001       func_chunk_i = -1;
5002       if (pi != 0) {
5003         memset(&ops, 0, pi * sizeof(ops[0]));
5004         memset(g_labels, 0, pi * sizeof(g_labels[0]));
5005         pi = 0;
5006       }
5007       g_eqcnt = 0;
5008       for (i = 0; i < g_func_pd_cnt; i++) {
5009         pd = &g_func_pd[i];
5010         if (pd->type == OPT_OFFSET) {
5011           for (j = 0; j < pd->count; j++)
5012             free(pd->d[j].u.label);
5013         }
5014         free(pd->d);
5015         pd->d = NULL;
5016       }
5017       g_func_pd_cnt = 0;
5018       pd = NULL;
5019       if (wordc == 0)
5020         continue;
5021     }
5022
5023     if (IS(words[1], "proc")) {
5024       if (in_func)
5025         aerr("proc '%s' while in_func '%s'?\n",
5026           words[0], g_func);
5027       p = words[0];
5028       if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
5029         skip_func = 1;
5030       strcpy(g_func, words[0]);
5031       set_label(0, words[0]);
5032       in_func = 1;
5033       continue;
5034     }
5035
5036     if (IS(words[1], "endp"))
5037     {
5038       if (!in_func)
5039         aerr("endp '%s' while not in_func?\n", words[0]);
5040       if (!IS(g_func, words[0]))
5041         aerr("endp '%s' while in_func '%s'?\n",
5042           words[0], g_func);
5043
5044       if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
5045         && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
5046       {
5047         // import jump
5048         skip_func = 1;
5049       }
5050
5051       if (!skip_func && func_chunks_used) {
5052         // start processing chunks
5053         struct chunk_item *ci, key = { g_func, 0 };
5054
5055         func_chunk_ret = ftell(fasm);
5056         func_chunk_ret_ln = asmln;
5057         if (!func_chunks_sorted) {
5058           qsort(func_chunks, func_chunk_cnt,
5059             sizeof(func_chunks[0]), cmp_chunks);
5060           func_chunks_sorted = 1;
5061         }
5062         ci = bsearch(&key, func_chunks, func_chunk_cnt,
5063                sizeof(func_chunks[0]), cmp_chunks);
5064         if (ci == NULL)
5065           aerr("'%s' needs chunks, but none found\n", g_func);
5066         func_chunk_i = ci - func_chunks;
5067         for (; func_chunk_i > 0; func_chunk_i--)
5068           if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
5069             break;
5070
5071         ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
5072         if (ret)
5073           aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
5074         asmln = func_chunks[func_chunk_i].asmln;
5075         func_chunk_i++;
5076         continue;
5077       }
5078       pending_endp = 1;
5079       continue;
5080     }
5081
5082     if (wordc == 2 && IS(words[1], "ends"))
5083       break;
5084
5085     p = strchr(words[0], ':');
5086     if (p != NULL) {
5087       set_label(pi, words[0]);
5088       continue;
5089     }
5090
5091     if (!in_func || skip_func) {
5092       if (!skip_warned && !skip_func && g_labels[pi][0] != 0) {
5093         if (verbose)
5094           anote("skipping from '%s'\n", g_labels[pi]);
5095         skip_warned = 1;
5096       }
5097       g_labels[pi][0] = 0;
5098       continue;
5099     }
5100
5101     if (wordc > 1 && IS(words[1], "="))
5102     {
5103       if (wordc != 5)
5104         aerr("unhandled equ, wc=%d\n", wordc);
5105       if (g_eqcnt >= eq_alloc) {
5106         eq_alloc *= 2;
5107         g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
5108         my_assert_not(g_eqs, NULL);
5109       }
5110
5111       len = strlen(words[0]);
5112       if (len > sizeof(g_eqs[0].name) - 1)
5113         aerr("equ name too long: %d\n", len);
5114       strcpy(g_eqs[g_eqcnt].name, words[0]);
5115
5116       if (!IS(words[3], "ptr"))
5117         aerr("unhandled equ\n");
5118       if (IS(words[2], "dword"))
5119         g_eqs[g_eqcnt].lmod = OPLM_DWORD;
5120       else if (IS(words[2], "word"))
5121         g_eqs[g_eqcnt].lmod = OPLM_WORD;
5122       else if (IS(words[2], "byte"))
5123         g_eqs[g_eqcnt].lmod = OPLM_BYTE;
5124       else
5125         aerr("bad lmod: '%s'\n", words[2]);
5126
5127       g_eqs[g_eqcnt].offset = parse_number(words[4]);
5128       g_eqcnt++;
5129       continue;
5130     }
5131
5132     if (pi >= ARRAY_SIZE(ops))
5133       aerr("too many ops\n");
5134
5135     parse_op(&ops[pi], words, wordc);
5136
5137     if (sctproto != NULL) {
5138       if (ops[pi].op == OP_CALL)
5139         ops[pi].datap = sctproto;
5140       sctproto = NULL;
5141     }
5142     pi++;
5143   }
5144
5145   fclose(fout);
5146   fclose(fasm);
5147   fclose(g_fhdr);
5148
5149   return 0;
5150 }
5151
5152 // vim:ts=2:shiftwidth=2:expandtab