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