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