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