9922f32996c724ccd21f184db6ea1340dca71017
[ia32rtools.git] / tools / translate.c
1 /*
2  * ia32rtools
3  * (C) notaz, 2013-2015
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 #include "common.h"
17
18 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
19 #define IS(w, y) !strcmp(w, y)
20 #define IS_START(w, y) !strncmp(w, y, strlen(y))
21
22 #include "protoparse.h"
23
24 static const char *asmfn;
25 static int asmln;
26 static FILE *g_fhdr;
27
28 #define anote(fmt, ...) \
29         printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
30 #define awarn(fmt, ...) \
31         printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
32 #define aerr(fmt, ...) do { \
33         printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
34   fcloseall(); \
35         exit(1); \
36 } while (0)
37
38 #include "masm_tools.h"
39
40 enum op_flags {
41   OPF_RMD    = (1 << 0), /* removed from code generation */
42   OPF_DATA   = (1 << 1), /* data processing - writes to dst opr */
43   OPF_FLAGS  = (1 << 2), /* sets flags */
44   OPF_JMP    = (1 << 3), /* branch, call */
45   OPF_CJMP   = (1 << 4), /* cond. branch (cc or jecxz/loop) */
46   OPF_CC     = (1 << 5), /* uses flags */
47   OPF_TAIL   = (1 << 6), /* ret or tail call */
48   OPF_RSAVE  = (1 << 7), /* push/pop is local reg save/load */
49   OPF_REP    = (1 << 8), /* prefixed by rep */
50   OPF_REPZ   = (1 << 9), /* rep is repe/repz */
51   OPF_REPNZ  = (1 << 10), /* rep is repne/repnz */
52   OPF_FARG   = (1 << 11), /* push collected as func arg */
53   OPF_FARGNR = (1 << 12), /* push collected as func arg (no reuse) */
54   OPF_EBP_S  = (1 << 13), /* ebp used as scratch here, not BP */
55   OPF_DF     = (1 << 14), /* DF flag set */
56   OPF_ATAIL  = (1 << 15), /* tail call with reused arg frame */
57   OPF_32BIT  = (1 << 16), /* 32bit division */
58   OPF_LOCK   = (1 << 17), /* op has lock prefix */
59   OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
60   OPF_DONE   = (1 << 19), /* already fully handled by analysis */
61   OPF_PPUSH  = (1 << 20), /* part of complex push-pop graph */
62   OPF_NOREGS = (1 << 21), /* don't track regs of this op */
63 };
64
65 enum op_op {
66         OP_INVAL,
67         OP_NOP,
68         OP_PUSH,
69         OP_POP,
70         OP_LEAVE,
71         OP_MOV,
72         OP_LEA,
73         OP_MOVZX,
74         OP_MOVSX,
75         OP_XCHG,
76         OP_NOT,
77         OP_XLAT,
78         OP_CDQ,
79         OP_LODS,
80         OP_STOS,
81         OP_MOVS,
82         OP_CMPS,
83         OP_SCAS,
84         OP_STD,
85         OP_CLD,
86         OP_RET,
87         OP_ADD,
88         OP_SUB,
89         OP_AND,
90         OP_OR,
91         OP_XOR,
92         OP_SHL,
93         OP_SHR,
94         OP_SAR,
95         OP_SHLD,
96         OP_SHRD,
97         OP_ROL,
98         OP_ROR,
99         OP_RCL,
100         OP_RCR,
101         OP_ADC,
102         OP_SBB,
103         OP_BSF,
104         OP_INC,
105         OP_DEC,
106         OP_NEG,
107         OP_MUL,
108         OP_IMUL,
109         OP_DIV,
110         OP_IDIV,
111         OP_TEST,
112         OP_CMP,
113         OP_CALL,
114         OP_JMP,
115         OP_JECXZ,
116         OP_LOOP,
117         OP_JCC,
118         OP_SCC,
119         // x87
120         // mmx
121         OP_EMMS,
122         // undefined
123         OP_UD2,
124 };
125
126 enum opr_type {
127   OPT_UNSPEC,
128   OPT_REG,
129   OPT_REGMEM,
130   OPT_LABEL,
131   OPT_OFFSET,
132   OPT_CONST,
133 };
134
135 // must be sorted (larger len must be further in enum)
136 enum opr_lenmod {
137         OPLM_UNSPEC,
138         OPLM_BYTE,
139         OPLM_WORD,
140         OPLM_DWORD,
141         OPLM_QWORD,
142 };
143
144 #define MAX_EXITS 128
145
146 #define MAX_OPERANDS 3
147 #define NAMELEN 112
148
149 #define OPR_INIT(type_, lmod_, reg_) \
150   { type_, lmod_, reg_, }
151
152 struct parsed_opr {
153   enum opr_type type;
154   enum opr_lenmod lmod;
155   int reg;
156   unsigned int is_ptr:1;   // pointer in C
157   unsigned int is_array:1; // array in C
158   unsigned int type_from_var:1; // .. in header, sometimes wrong
159   unsigned int size_mismatch:1; // type override differs from C
160   unsigned int size_lt:1;  // type override is larger than C
161   unsigned int had_ds:1;   // had ds: prefix
162   const struct parsed_proto *pp; // for OPT_LABEL
163   unsigned int val;
164   char name[NAMELEN];
165 };
166
167 struct parsed_op {
168   enum op_op op;
169   struct parsed_opr operand[MAX_OPERANDS];
170   unsigned int flags;
171   unsigned char pfo;
172   unsigned char pfo_inv;
173   unsigned char operand_cnt;
174   unsigned char p_argnum; // arg push: altered before call arg #
175   unsigned char p_arggrp; // arg push: arg group # for above
176   unsigned char p_argpass;// arg push: arg of host func
177   short         p_argnext;// arg push: same arg pushed elsewhere or -1
178   int regmask_src;        // all referensed regs
179   int regmask_dst;
180   int pfomask;            // flagop: parsed_flag_op that can't be delayed
181   int cc_scratch;         // scratch storage during analysis
182   int bt_i;               // branch target for branches
183   struct parsed_data *btj;// branch targets for jumptables
184   struct parsed_proto *pp;// parsed_proto for OP_CALL
185   void *datap;
186   int asmln;
187 };
188
189 // datap:
190 // OP_CALL  - parser proto hint (str)
191 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
192 // OP_PUSH  - points to OP_POP in complex push/pop graph
193 // OP_POP   - points to OP_PUSH in simple push/pop pair
194
195 struct parsed_equ {
196   char name[64];
197   enum opr_lenmod lmod;
198   int offset;
199 };
200
201 struct parsed_data {
202   char label[256];
203   enum opr_type type;
204   enum opr_lenmod lmod;
205   int count;
206   int count_alloc;
207   struct {
208     union {
209       char *label;
210       unsigned int val;
211     } u;
212     int bt_i;
213   } *d;
214 };
215
216 struct label_ref {
217   int i;
218   struct label_ref *next;
219 };
220
221 enum ida_func_attr {
222   IDAFA_BP_FRAME = (1 << 0),
223   IDAFA_LIB_FUNC = (1 << 1),
224   IDAFA_STATIC   = (1 << 2),
225   IDAFA_NORETURN = (1 << 3),
226   IDAFA_THUNK    = (1 << 4),
227   IDAFA_FPD      = (1 << 5),
228 };
229
230 // note: limited to 32k due to p_argnext
231 #define MAX_OPS     4096
232 #define MAX_ARG_GRP 2
233
234 static struct parsed_op ops[MAX_OPS];
235 static struct parsed_equ *g_eqs;
236 static int g_eqcnt;
237 static char *g_labels[MAX_OPS];
238 static struct label_ref g_label_refs[MAX_OPS];
239 static const struct parsed_proto *g_func_pp;
240 static struct parsed_data *g_func_pd;
241 static int g_func_pd_cnt;
242 static char g_func[256];
243 static char g_comment[256];
244 static int g_bp_frame;
245 static int g_sp_frame;
246 static int g_stack_frame_used;
247 static int g_stack_fsz;
248 static int g_ida_func_attr;
249 static int g_skip_func;
250 static int g_allow_regfunc;
251 static int g_quiet_pp;
252 static int g_header_mode;
253
254 #define ferr(op_, fmt, ...) do { \
255   printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
256     __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
257   fcloseall(); \
258   exit(1); \
259 } while (0)
260 #define fnote(op_, fmt, ...) \
261   printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
262     dump_op(op_), ##__VA_ARGS__)
263
264 #define ferr_assert(op_, cond) do { \
265   if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
266 } while (0)
267
268 const char *regs_r32[] = {
269   "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
270   // not r32, but list here for easy parsing and printing
271   "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
272 };
273 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
274 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
275 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
276
277 enum x86_regs { xUNSPEC = -1, xAX, xBX, xCX, xDX, xSI, xDI, xBP, xSP };
278
279 // possible basic comparison types (without inversion)
280 enum parsed_flag_op {
281   PFO_O,  // 0 OF=1
282   PFO_C,  // 2 CF=1
283   PFO_Z,  // 4 ZF=1
284   PFO_BE, // 6 CF=1||ZF=1
285   PFO_S,  // 8 SF=1
286   PFO_P,  // a PF=1
287   PFO_L,  // c SF!=OF
288   PFO_LE, // e ZF=1||SF!=OF
289 };
290
291 #define PFOB_O   (1 << PFO_O)
292 #define PFOB_C   (1 << PFO_C)
293 #define PFOB_Z   (1 << PFO_Z)
294 #define PFOB_S   (1 << PFO_S)
295
296 static const char *parsed_flag_op_names[] = {
297   "o", "c", "z", "be", "s", "p", "l", "le"
298 };
299
300 static int char_array_i(const char *array[], size_t len, const char *s)
301 {
302   int i;
303
304   for (i = 0; i < len; i++)
305     if (IS(s, array[i]))
306       return i;
307
308   return -1;
309 }
310
311 static void printf_number(char *buf, size_t buf_size,
312   unsigned long number)
313 {
314   // output in C-friendly form
315   snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
316 }
317
318 static int check_segment_prefix(const char *s)
319 {
320   if (s[0] == 0 || s[1] != 's' || s[2] != ':')
321     return 0;
322
323   switch (s[0]) {
324   case 'c': return 1;
325   case 'd': return 2;
326   case 's': return 3;
327   case 'e': return 4;
328   case 'f': return 5;
329   case 'g': return 6;
330   default:  return 0;
331   }
332 }
333
334 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
335 {
336   int reg;
337
338   reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
339   if (reg >= 8) {
340     *reg_lmod = OPLM_QWORD;
341     return reg;
342   }
343   if (reg >= 0) {
344     *reg_lmod = OPLM_DWORD;
345     return reg;
346   }
347   reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
348   if (reg >= 0) {
349     *reg_lmod = OPLM_WORD;
350     return reg;
351   }
352   reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
353   if (reg >= 0) {
354     *reg_lmod = OPLM_BYTE;
355     return reg;
356   }
357   reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
358   if (reg >= 0) {
359     *reg_lmod = OPLM_BYTE;
360     return reg;
361   }
362
363   return -1;
364 }
365
366 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
367 {
368   enum opr_lenmod lmod;
369   char cvtbuf[256];
370   char *d = cvtbuf;
371   char *s = name;
372   char w[64];
373   long number;
374   int reg;
375   int c = 0;
376
377   *d = 0;
378
379   while (*s != 0) {
380     d += strlen(d);
381     while (my_isblank(*s))
382       s++;
383     for (; my_issep(*s); d++, s++)
384       *d = *s;
385     while (my_isblank(*s))
386       s++;
387     *d = 0;
388
389     // skip '?s:' prefixes
390     if (check_segment_prefix(s))
391       s += 3;
392
393     s = next_idt(w, sizeof(w), s);
394     if (w[0] == 0)
395       break;
396     c++;
397
398     reg = parse_reg(&lmod, w);
399     if (reg >= 0) {
400       *regmask |= 1 << reg;
401       goto pass;
402     }
403
404     if ('0' <= w[0] && w[0] <= '9') {
405       number = parse_number(w);
406       printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
407       continue;
408     }
409
410     // probably some label/identifier - pass
411
412 pass:
413     snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
414   }
415
416   if (need_c_cvt)
417     strcpy(name, cvtbuf);
418
419   return c;
420 }
421
422 static int is_reg_in_str(const char *s)
423 {
424   int i;
425
426   if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
427     return 0;
428
429   for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
430     if (!strncmp(s, regs_r32[i], 3))
431       return 1;
432
433   return 0;
434 }
435
436 static const char *parse_stack_el(const char *name, char *extra_reg,
437   int early_try)
438 {
439   const char *p, *p2, *s;
440   char *endp = NULL;
441   char buf[32];
442   long val;
443   int len;
444
445   if (g_bp_frame || early_try)
446   {
447     p = name;
448     if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
449       p += 4;
450       if (extra_reg != NULL) {
451         strncpy(extra_reg, name, 3);
452         extra_reg[4] = 0;
453       }
454     }
455
456     if (IS_START(p, "ebp+")) {
457       p += 4;
458
459       p2 = strchr(p, '+');
460       if (p2 != NULL && is_reg_in_str(p)) {
461         if (extra_reg != NULL) {
462           strncpy(extra_reg, p, p2 - p);
463           extra_reg[p2 - p] = 0;
464         }
465         p = p2 + 1;
466       }
467
468       if (!('0' <= *p && *p <= '9'))
469         return p;
470
471       return NULL;
472     }
473   }
474
475   if (!IS_START(name, "esp+"))
476     return NULL;
477
478   s = name + 4;
479   p = strchr(s, '+');
480   if (p) {
481     if (is_reg_in_str(s)) {
482       if (extra_reg != NULL) {
483         strncpy(extra_reg, s, p - s);
484         extra_reg[p - s] = 0;
485       }
486       s = p + 1;
487       p = strchr(s, '+');
488       if (p == NULL)
489         aerr("%s IDA stackvar not set?\n", __func__);
490     }
491     if (!('0' <= *s && *s <= '9')) {
492       aerr("%s IDA stackvar offset not set?\n", __func__);
493       return NULL;
494     }
495     if (s[0] == '0' && s[1] == 'x')
496       s += 2;
497     len = p - s;
498     if (len < sizeof(buf) - 1) {
499       strncpy(buf, s, len);
500       buf[len] = 0;
501       val = strtol(buf, &endp, 16);
502       if (val == 0 || *endp != 0) {
503         aerr("%s num parse fail for '%s'\n", __func__, buf);
504         return NULL;
505       }
506     }
507     p++;
508   }
509   else
510     p = name + 4;
511
512   if ('0' <= *p && *p <= '9')
513     return NULL;
514
515   return p;
516 }
517
518 static int guess_lmod_from_name(struct parsed_opr *opr)
519 {
520   if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
521     opr->lmod = OPLM_DWORD;
522     return 1;
523   }
524   if (IS_START(opr->name, "word_")) {
525     opr->lmod = OPLM_WORD;
526     return 1;
527   }
528   if (IS_START(opr->name, "byte_")) {
529     opr->lmod = OPLM_BYTE;
530     return 1;
531   }
532   if (IS_START(opr->name, "qword_")) {
533     opr->lmod = OPLM_QWORD;
534     return 1;
535   }
536   return 0;
537 }
538
539 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
540   const struct parsed_type *c_type)
541 {
542   static const char *dword_types[] = {
543     "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
544     "WPARAM", "LPARAM", "UINT", "__int32",
545     "LONG", "HIMC", "BOOL", "size_t",
546     "float",
547   };
548   static const char *word_types[] = {
549     "uint16_t", "int16_t", "_WORD", "WORD",
550     "unsigned __int16", "__int16",
551   };
552   static const char *byte_types[] = {
553     "uint8_t", "int8_t", "char",
554     "unsigned __int8", "__int8", "BYTE", "_BYTE",
555     "CHAR", "_UNKNOWN",
556     // structures.. deal the same as with _UNKNOWN for now
557     "CRITICAL_SECTION",
558   };
559   const char *n;
560   int i;
561
562   if (c_type->is_ptr) {
563     *lmod = OPLM_DWORD;
564     return 1;
565   }
566
567   n = skip_type_mod(c_type->name);
568
569   for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
570     if (IS(n, dword_types[i])) {
571       *lmod = OPLM_DWORD;
572       return 1;
573     }
574   }
575
576   for (i = 0; i < ARRAY_SIZE(word_types); i++) {
577     if (IS(n, word_types[i])) {
578       *lmod = OPLM_WORD;
579       return 1;
580     }
581   }
582
583   for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
584     if (IS(n, byte_types[i])) {
585       *lmod = OPLM_BYTE;
586       return 1;
587     }
588   }
589
590   return 0;
591 }
592
593 static char *default_cast_to(char *buf, size_t buf_size,
594   struct parsed_opr *opr)
595 {
596   buf[0] = 0;
597
598   if (!opr->is_ptr)
599     return buf;
600   if (opr->pp == NULL || opr->pp->type.name == NULL
601     || opr->pp->is_fptr)
602   {
603     snprintf(buf, buf_size, "%s", "(void *)");
604     return buf;
605   }
606
607   snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
608   return buf;
609 }
610
611 static enum opr_type lmod_from_directive(const char *d)
612 {
613   if (IS(d, "dd"))
614     return OPLM_DWORD;
615   else if (IS(d, "dw"))
616     return OPLM_WORD;
617   else if (IS(d, "db"))
618     return OPLM_BYTE;
619
620   aerr("unhandled directive: '%s'\n", d);
621   return OPLM_UNSPEC;
622 }
623
624 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
625   int *regmask)
626 {
627   opr->type = OPT_REG;
628   opr->reg = reg;
629   opr->lmod = lmod;
630   *regmask |= 1 << reg;
631 }
632
633 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
634   int *extra_offs);
635
636 static int parse_operand(struct parsed_opr *opr,
637   int *regmask, int *regmask_indirect,
638   char words[16][256], int wordc, int w, unsigned int op_flags)
639 {
640   const struct parsed_proto *pp = NULL;
641   enum opr_lenmod tmplmod;
642   unsigned long number;
643   char buf[256];
644   int ret, len;
645   int wordc_in;
646   char *p;
647   int i;
648
649   if (w >= wordc)
650     aerr("parse_operand w %d, wordc %d\n", w, wordc);
651
652   opr->reg = xUNSPEC;
653
654   for (i = w; i < wordc; i++) {
655     len = strlen(words[i]);
656     if (words[i][len - 1] == ',') {
657       words[i][len - 1] = 0;
658       wordc = i + 1;
659       break;
660     }
661   }
662
663   wordc_in = wordc - w;
664
665   if ((op_flags & OPF_JMP) && wordc_in > 0
666       && !('0' <= words[w][0] && words[w][0] <= '9'))
667   {
668     const char *label = NULL;
669
670     if (wordc_in == 3 && !strncmp(words[w], "near", 4)
671      && IS(words[w + 1], "ptr"))
672       label = words[w + 2];
673     else if (wordc_in == 2 && IS(words[w], "short"))
674       label = words[w + 1];
675     else if (wordc_in == 1
676           && strchr(words[w], '[') == NULL
677           && parse_reg(&tmplmod, words[w]) < 0)
678       label = words[w];
679
680     if (label != NULL) {
681       opr->type = OPT_LABEL;
682       ret = check_segment_prefix(label);
683       if (ret != 0) {
684         if (ret >= 5)
685           aerr("fs/gs used\n");
686         opr->had_ds = 1;
687         label += 3;
688       }
689       strcpy(opr->name, label);
690       return wordc;
691     }
692   }
693
694   if (wordc_in >= 3) {
695     if (IS(words[w + 1], "ptr")) {
696       if (IS(words[w], "dword"))
697         opr->lmod = OPLM_DWORD;
698       else if (IS(words[w], "word"))
699         opr->lmod = OPLM_WORD;
700       else if (IS(words[w], "byte"))
701         opr->lmod = OPLM_BYTE;
702       else if (IS(words[w], "qword"))
703         opr->lmod = OPLM_QWORD;
704       else
705         aerr("type parsing failed\n");
706       w += 2;
707       wordc_in = wordc - w;
708     }
709   }
710
711   if (wordc_in == 2) {
712     if (IS(words[w], "offset")) {
713       opr->type = OPT_OFFSET;
714       opr->lmod = OPLM_DWORD;
715       strcpy(opr->name, words[w + 1]);
716       pp = proto_parse(g_fhdr, opr->name, 1);
717       goto do_label;
718     }
719     if (IS(words[w], "(offset")) {
720       p = strchr(words[w + 1], ')');
721       if (p == NULL)
722         aerr("parse of bracketed offset failed\n");
723       *p = 0;
724       opr->type = OPT_OFFSET;
725       strcpy(opr->name, words[w + 1]);
726       return wordc;
727     }
728   }
729
730   if (wordc_in != 1)
731     aerr("parse_operand 1 word expected\n");
732
733   ret = check_segment_prefix(words[w]);
734   if (ret != 0) {
735     if (ret >= 5)
736       aerr("fs/gs used\n");
737     opr->had_ds = 1;
738     memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
739   }
740   strcpy(opr->name, words[w]);
741
742   if (words[w][0] == '[') {
743     opr->type = OPT_REGMEM;
744     ret = sscanf(words[w], "[%[^]]]", opr->name);
745     if (ret != 1)
746       aerr("[] parse failure\n");
747
748     parse_indmode(opr->name, regmask_indirect, 1);
749     if (opr->lmod == OPLM_UNSPEC && parse_stack_el(opr->name, NULL, 1))
750     {
751       // might be an equ
752       struct parsed_equ *eq =
753         equ_find(NULL, parse_stack_el(opr->name, NULL, 1), &i);
754       if (eq)
755         opr->lmod = eq->lmod;
756     }
757     return wordc;
758   }
759   else if (strchr(words[w], '[')) {
760     // label[reg] form
761     p = strchr(words[w], '[');
762     opr->type = OPT_REGMEM;
763     parse_indmode(p, regmask_indirect, 0);
764     strncpy(buf, words[w], p - words[w]);
765     buf[p - words[w]] = 0;
766     pp = proto_parse(g_fhdr, buf, 1);
767     goto do_label;
768   }
769   else if (('0' <= words[w][0] && words[w][0] <= '9')
770     || words[w][0] == '-')
771   {
772     number = parse_number(words[w]);
773     opr->type = OPT_CONST;
774     opr->val = number;
775     printf_number(opr->name, sizeof(opr->name), number);
776     return wordc;
777   }
778
779   ret = parse_reg(&tmplmod, opr->name);
780   if (ret >= 0) {
781     setup_reg_opr(opr, ret, tmplmod, regmask);
782     return wordc;
783   }
784
785   // most likely var in data segment
786   opr->type = OPT_LABEL;
787   pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
788
789 do_label:
790   if (pp != NULL) {
791     if (pp->is_fptr || pp->is_func) {
792       opr->lmod = OPLM_DWORD;
793       opr->is_ptr = 1;
794     }
795     else {
796       tmplmod = OPLM_UNSPEC;
797       if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
798         anote("unhandled C type '%s' for '%s'\n",
799           pp->type.name, opr->name);
800       
801       if (opr->lmod == OPLM_UNSPEC) {
802         opr->lmod = tmplmod;
803         opr->type_from_var = 1;
804       }
805       else if (opr->lmod != tmplmod) {
806         opr->size_mismatch = 1;
807         if (tmplmod < opr->lmod)
808           opr->size_lt = 1;
809       }
810       opr->is_ptr = pp->type.is_ptr;
811     }
812     opr->is_array = pp->type.is_array;
813   }
814   opr->pp = pp;
815
816   if (opr->lmod == OPLM_UNSPEC)
817     guess_lmod_from_name(opr);
818   return wordc;
819 }
820
821 static const struct {
822   const char *name;
823   unsigned int flags;
824 } pref_table[] = {
825   { "rep",    OPF_REP },
826   { "repe",   OPF_REP|OPF_REPZ },
827   { "repz",   OPF_REP|OPF_REPZ },
828   { "repne",  OPF_REP|OPF_REPNZ },
829   { "repnz",  OPF_REP|OPF_REPNZ },
830   { "lock",   OPF_LOCK }, // ignored for now..
831 };
832
833 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
834
835 static const struct {
836   const char *name;
837   enum op_op op;
838   unsigned short minopr;
839   unsigned short maxopr;
840   unsigned int flags;
841   unsigned char pfo;
842   unsigned char pfo_inv;
843 } op_table[] = {
844   { "nop",  OP_NOP,    0, 0, 0 },
845   { "push", OP_PUSH,   1, 1, 0 },
846   { "pop",  OP_POP,    1, 1, OPF_DATA },
847   { "leave",OP_LEAVE,  0, 0, OPF_DATA },
848   { "mov" , OP_MOV,    2, 2, OPF_DATA },
849   { "lea",  OP_LEA,    2, 2, OPF_DATA },
850   { "movzx",OP_MOVZX,  2, 2, OPF_DATA },
851   { "movsx",OP_MOVSX,  2, 2, OPF_DATA },
852   { "xchg", OP_XCHG,   2, 2, OPF_DATA },
853   { "not",  OP_NOT,    1, 1, OPF_DATA },
854   { "xlat", OP_XLAT,   0, 0, OPF_DATA },
855   { "cdq",  OP_CDQ,    0, 0, OPF_DATA },
856   { "lodsb",OP_LODS,   0, 0, OPF_DATA },
857   { "lodsw",OP_LODS,   0, 0, OPF_DATA },
858   { "lodsd",OP_LODS,   0, 0, OPF_DATA },
859   { "stosb",OP_STOS,   0, 0, OPF_DATA },
860   { "stosw",OP_STOS,   0, 0, OPF_DATA },
861   { "stosd",OP_STOS,   0, 0, OPF_DATA },
862   { "movsb",OP_MOVS,   0, 0, OPF_DATA },
863   { "movsw",OP_MOVS,   0, 0, OPF_DATA },
864   { "movsd",OP_MOVS,   0, 0, OPF_DATA },
865   { "cmpsb",OP_CMPS,   0, 0, OPF_DATA|OPF_FLAGS },
866   { "cmpsw",OP_CMPS,   0, 0, OPF_DATA|OPF_FLAGS },
867   { "cmpsd",OP_CMPS,   0, 0, OPF_DATA|OPF_FLAGS },
868   { "scasb",OP_SCAS,   0, 0, OPF_DATA|OPF_FLAGS },
869   { "scasw",OP_SCAS,   0, 0, OPF_DATA|OPF_FLAGS },
870   { "scasd",OP_SCAS,   0, 0, OPF_DATA|OPF_FLAGS },
871   { "std",  OP_STD,    0, 0, OPF_DATA }, // special flag
872   { "cld",  OP_CLD,    0, 0, OPF_DATA },
873   { "add",  OP_ADD,    2, 2, OPF_DATA|OPF_FLAGS },
874   { "sub",  OP_SUB,    2, 2, OPF_DATA|OPF_FLAGS },
875   { "and",  OP_AND,    2, 2, OPF_DATA|OPF_FLAGS },
876   { "or",   OP_OR,     2, 2, OPF_DATA|OPF_FLAGS },
877   { "xor",  OP_XOR,    2, 2, OPF_DATA|OPF_FLAGS },
878   { "shl",  OP_SHL,    2, 2, OPF_DATA|OPF_FLAGS },
879   { "shr",  OP_SHR,    2, 2, OPF_DATA|OPF_FLAGS },
880   { "sal",  OP_SHL,    2, 2, OPF_DATA|OPF_FLAGS },
881   { "sar",  OP_SAR,    2, 2, OPF_DATA|OPF_FLAGS },
882   { "shld", OP_SHLD,   3, 3, OPF_DATA|OPF_FLAGS },
883   { "shrd", OP_SHRD,   3, 3, OPF_DATA|OPF_FLAGS },
884   { "rol",  OP_ROL,    2, 2, OPF_DATA|OPF_FLAGS },
885   { "ror",  OP_ROR,    2, 2, OPF_DATA|OPF_FLAGS },
886   { "rcl",  OP_RCL,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
887   { "rcr",  OP_RCR,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
888   { "adc",  OP_ADC,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
889   { "sbb",  OP_SBB,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
890   { "bsf",  OP_BSF,    2, 2, OPF_DATA|OPF_FLAGS },
891   { "inc",  OP_INC,    1, 1, OPF_DATA|OPF_FLAGS },
892   { "dec",  OP_DEC,    1, 1, OPF_DATA|OPF_FLAGS },
893   { "neg",  OP_NEG,    1, 1, OPF_DATA|OPF_FLAGS },
894   { "mul",  OP_MUL,    1, 1, OPF_DATA|OPF_FLAGS },
895   { "imul", OP_IMUL,   1, 3, OPF_DATA|OPF_FLAGS },
896   { "div",  OP_DIV,    1, 1, OPF_DATA|OPF_FLAGS },
897   { "idiv", OP_IDIV,   1, 1, OPF_DATA|OPF_FLAGS },
898   { "test", OP_TEST,   2, 2, OPF_FLAGS },
899   { "cmp",  OP_CMP,    2, 2, OPF_FLAGS },
900   { "retn", OP_RET,    0, 1, OPF_TAIL },
901   { "call", OP_CALL,   1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
902   { "jmp",  OP_JMP,    1, 1, OPF_JMP },
903   { "jecxz",OP_JECXZ,  1, 1, OPF_JMP|OPF_CJMP },
904   { "loop", OP_LOOP,   1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
905   { "jo",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_O,  0 }, // 70 OF=1
906   { "jno",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_O,  1 }, // 71 OF=0
907   { "jc",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_C,  0 }, // 72 CF=1
908   { "jb",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_C,  0 }, // 72
909   { "jnc",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_C,  1 }, // 73 CF=0
910   { "jnb",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_C,  1 }, // 73
911   { "jae",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_C,  1 }, // 73
912   { "jz",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_Z,  0 }, // 74 ZF=1
913   { "je",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_Z,  0 }, // 74
914   { "jnz",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_Z,  1 }, // 75 ZF=0
915   { "jne",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_Z,  1 }, // 75
916   { "jbe",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
917   { "jna",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
918   { "ja",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
919   { "jnbe", OP_JCC,    1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
920   { "js",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_S,  0 }, // 78 SF=1
921   { "jns",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_S,  1 }, // 79 SF=0
922   { "jp",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_P,  0 }, // 7a PF=1
923   { "jpe",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_P,  0 }, // 7a
924   { "jnp",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_P,  1 }, // 7b PF=0
925   { "jpo",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_P,  1 }, // 7b
926   { "jl",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_L,  0 }, // 7c SF!=OF
927   { "jnge", OP_JCC,    1, 1, OPF_CJMP_CC, PFO_L,  0 }, // 7c
928   { "jge",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_L,  1 }, // 7d SF=OF
929   { "jnl",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_L,  1 }, // 7d
930   { "jle",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
931   { "jng",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
932   { "jg",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
933   { "jnle", OP_JCC,    1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
934   { "seto",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_O,  0 },
935   { "setno",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_O,  1 },
936   { "setc",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_C,  0 },
937   { "setb",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_C,  0 },
938   { "setnc",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_C,  1 },
939   { "setae",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_C,  1 },
940   { "setnb",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_C,  1 },
941   { "setz",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_Z,  0 },
942   { "sete",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_Z,  0 },
943   { "setnz",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_Z,  1 },
944   { "setne",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_Z,  1 },
945   { "setbe",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
946   { "setna",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
947   { "seta",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
948   { "setnbe", OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
949   { "sets",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_S,  0 },
950   { "setns",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_S,  1 },
951   { "setp",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_P,  0 },
952   { "setpe",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_P,  0 },
953   { "setnp",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_P,  1 },
954   { "setpo",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_P,  1 },
955   { "setl",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_L,  0 },
956   { "setnge", OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_L,  0 },
957   { "setge",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_L,  1 },
958   { "setnl",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_L,  1 },
959   { "setle",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
960   { "setng",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
961   { "setg",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
962   { "setnle", OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
963   // x87
964   // mmx
965   { "emms",   OP_EMMS, 0, 0, OPF_DATA },
966   { "movq",   OP_MOV,  2, 2, OPF_DATA },
967   // must be last
968   { "ud2",    OP_UD2 },
969 };
970
971 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
972 {
973   enum opr_lenmod lmod = OPLM_UNSPEC;
974   int prefix_flags = 0;
975   int regmask_ind;
976   int regmask;
977   int op_w = 0;
978   int opr = 0;
979   int w = 0;
980   int i, j;
981
982   for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
983     if (IS(words[w], pref_table[i].name)) {
984       prefix_flags = pref_table[i].flags;
985       break;
986     }
987   }
988
989   if (prefix_flags) {
990     if (wordc <= 1)
991       aerr("lone prefix: '%s'\n", words[0]);
992     w++;
993   }
994
995   op_w = w;
996   for (i = 0; i < ARRAY_SIZE(op_table); i++) {
997     if (IS(words[w], op_table[i].name))
998       break;
999   }
1000
1001   if (i == ARRAY_SIZE(op_table)) {
1002     if (!g_skip_func)
1003       aerr("unhandled op: '%s'\n", words[0]);
1004     i--; // OP_UD2
1005   }
1006   w++;
1007
1008   op->op = op_table[i].op;
1009   op->flags = op_table[i].flags | prefix_flags;
1010   op->pfo = op_table[i].pfo;
1011   op->pfo_inv = op_table[i].pfo_inv;
1012   op->regmask_src = op->regmask_dst = 0;
1013   op->asmln = asmln;
1014
1015   if (op->op == OP_UD2)
1016     return;
1017
1018   for (opr = 0; opr < op_table[i].maxopr; opr++) {
1019     if (opr >= op_table[i].minopr && w >= wordc)
1020       break;
1021
1022     regmask = regmask_ind = 0;
1023     w = parse_operand(&op->operand[opr], &regmask, &regmask_ind,
1024       words, wordc, w, op->flags);
1025
1026     if (opr == 0 && (op->flags & OPF_DATA))
1027       op->regmask_dst = regmask;
1028     else
1029       op->regmask_src |= regmask;
1030     op->regmask_src |= regmask_ind;
1031   }
1032
1033   if (w < wordc)
1034     aerr("parse_op %s incomplete: %d/%d\n",
1035       words[0], w, wordc);
1036
1037   // special cases
1038   op->operand_cnt = opr;
1039   if (!strncmp(op_table[i].name, "set", 3))
1040     op->operand[0].lmod = OPLM_BYTE;
1041
1042   switch (op->op) {
1043   // first operand is not dst
1044   case OP_CMP:
1045   case OP_TEST:
1046     op->regmask_src |= op->regmask_dst;
1047     op->regmask_dst = 0;
1048     break;
1049
1050   // first operand is src too
1051   case OP_NOT:
1052   case OP_ADD:
1053   case OP_AND:
1054   case OP_OR:
1055   case OP_RCL:
1056   case OP_RCR:
1057   case OP_ADC:
1058   case OP_INC:
1059   case OP_DEC:
1060   case OP_NEG:
1061   // more below..
1062     op->regmask_src |= op->regmask_dst;
1063     break;
1064
1065   // special
1066   case OP_XCHG:
1067     op->regmask_src |= op->regmask_dst;
1068     op->regmask_dst |= op->regmask_src;
1069     goto check_align;
1070
1071   case OP_SUB:
1072   case OP_SBB:
1073   case OP_XOR:
1074     if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1075      && op->operand[0].lmod == op->operand[1].lmod
1076      && op->operand[0].reg == op->operand[1].reg
1077      && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1078     {
1079       op->regmask_src = 0;
1080     }
1081     else
1082       op->regmask_src |= op->regmask_dst;
1083     break;
1084
1085   // ops with implicit argumets
1086   case OP_XLAT:
1087     op->operand_cnt = 2;
1088     setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1089     op->regmask_dst = op->regmask_src;
1090     setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1091     break;
1092
1093   case OP_CDQ:
1094     op->operand_cnt = 2;
1095     setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1096     setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1097     break;
1098
1099   case OP_LODS:
1100   case OP_STOS:
1101   case OP_SCAS:
1102     if      (words[op_w][4] == 'b')
1103       lmod = OPLM_BYTE;
1104     else if (words[op_w][4] == 'w')
1105       lmod = OPLM_WORD;
1106     else if (words[op_w][4] == 'd')
1107       lmod = OPLM_DWORD;
1108     j = 0;
1109     op->regmask_src = 0;
1110     setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1111       OPLM_DWORD, &op->regmask_src);
1112     op->regmask_dst = op->regmask_src;
1113     setup_reg_opr(&op->operand[j++], xAX, lmod,
1114       op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1115     if (op->flags & OPF_REP) {
1116       setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1117       op->regmask_dst |= 1 << xCX;
1118     }
1119     op->operand_cnt = j;
1120     break;
1121
1122   case OP_MOVS:
1123   case OP_CMPS:
1124     if      (words[op_w][4] == 'b')
1125       lmod = OPLM_BYTE;
1126     else if (words[op_w][4] == 'w')
1127       lmod = OPLM_WORD;
1128     else if (words[op_w][4] == 'd')
1129       lmod = OPLM_DWORD;
1130     j = 0;
1131     op->regmask_src = 0;
1132     // note: lmod is not correct, don't have where to place it
1133     setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1134     setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1135     if (op->flags & OPF_REP)
1136       setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1137     op->operand_cnt = j;
1138     op->regmask_dst = op->regmask_src;
1139     break;
1140
1141   case OP_LOOP:
1142     op->regmask_dst = 1 << xCX;
1143     // fallthrough
1144   case OP_JECXZ:
1145     op->operand_cnt = 2;
1146     op->regmask_src = 1 << xCX;
1147     op->operand[1].type = OPT_REG;
1148     op->operand[1].reg = xCX;
1149     op->operand[1].lmod = OPLM_DWORD;
1150     break;
1151
1152   case OP_IMUL:
1153     if (op->operand_cnt == 2) {
1154       if (op->operand[0].type != OPT_REG)
1155         aerr("reg expected\n");
1156       op->regmask_src |= 1 << op->operand[0].reg;
1157     }
1158     if (op->operand_cnt != 1)
1159       break;
1160     // fallthrough
1161   case OP_MUL:
1162     // singleop mul
1163     op->regmask_src |= op->regmask_dst;
1164     op->regmask_dst = (1 << xDX) | (1 << xAX);
1165     if (op->operand[0].lmod == OPLM_UNSPEC)
1166       op->operand[0].lmod = OPLM_DWORD;
1167     break;
1168
1169   case OP_DIV:
1170   case OP_IDIV:
1171     // we could set up operands for edx:eax, but there is no real need to
1172     // (see is_opr_modified())
1173     op->regmask_src |= op->regmask_dst;
1174     op->regmask_dst = (1 << xDX) | (1 << xAX);
1175     if (op->operand[0].lmod == OPLM_UNSPEC)
1176       op->operand[0].lmod = OPLM_DWORD;
1177     break;
1178
1179   case OP_SHL:
1180   case OP_SHR:
1181   case OP_SAR:
1182   case OP_ROL:
1183   case OP_ROR:
1184     op->regmask_src |= op->regmask_dst;
1185     if (op->operand[1].lmod == OPLM_UNSPEC)
1186       op->operand[1].lmod = OPLM_BYTE;
1187     break;
1188
1189   case OP_SHLD:
1190   case OP_SHRD:
1191     op->regmask_src |= op->regmask_dst;
1192     if (op->operand[2].lmod == OPLM_UNSPEC)
1193       op->operand[2].lmod = OPLM_BYTE;
1194     break;
1195
1196   case OP_PUSH:
1197     op->regmask_src |= op->regmask_dst;
1198     op->regmask_dst = 0;
1199     if (op->operand[0].lmod == OPLM_UNSPEC
1200         && (op->operand[0].type == OPT_CONST
1201          || op->operand[0].type == OPT_OFFSET
1202          || op->operand[0].type == OPT_LABEL))
1203       op->operand[0].lmod = OPLM_DWORD;
1204     break;
1205
1206   // alignment
1207   case OP_MOV:
1208   check_align:
1209     if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1210      && op->operand[0].lmod == op->operand[1].lmod
1211      && op->operand[0].reg == op->operand[1].reg
1212      && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1213     {
1214       op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1215       op->regmask_src = op->regmask_dst = 0;
1216     }
1217     break;
1218
1219   case OP_LEA:
1220     if (op->operand[0].type == OPT_REG
1221      && op->operand[1].type == OPT_REGMEM)
1222     {
1223       char buf[16];
1224       snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1225       if (IS(buf, op->operand[1].name))
1226         op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1227     }
1228     break;
1229
1230   case OP_CALL:
1231     // trashed regs must be explicitly detected later
1232     op->regmask_dst = 0;
1233     break;
1234
1235   case OP_LEAVE:
1236     op->regmask_dst = (1 << xBP) | (1 << xSP);
1237     op->regmask_src =  1 << xBP;
1238     break;
1239
1240   default:
1241     break;
1242   }
1243
1244   if (op->operand[0].type == OPT_REG
1245    && op->operand[1].type == OPT_CONST)
1246   {
1247     struct parsed_opr *op1 = &op->operand[1];
1248     if ((op->op == OP_AND && op1->val == 0)
1249      || (op->op == OP_OR
1250       && (op1->val == ~0
1251        || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1252        || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1253     {
1254       op->regmask_src = 0;
1255     }
1256   }
1257 }
1258
1259 static const char *op_name(struct parsed_op *po)
1260 {
1261   static char buf[16];
1262   char *p;
1263   int i;
1264
1265   if (po->op == OP_JCC || po->op == OP_SCC) {
1266     p = buf;
1267     *p++ = (po->op == OP_JCC) ? 'j' : 's';
1268     if (po->pfo_inv)
1269       *p++ = 'n';
1270     strcpy(p, parsed_flag_op_names[po->pfo]);
1271     return buf;
1272   }
1273
1274   for (i = 0; i < ARRAY_SIZE(op_table); i++)
1275     if (op_table[i].op == po->op)
1276       return op_table[i].name;
1277
1278   return "???";
1279 }
1280
1281 // debug
1282 static const char *dump_op(struct parsed_op *po)
1283 {
1284   static char out[128];
1285   char *p = out;
1286   int i;
1287
1288   if (po == NULL)
1289     return "???";
1290
1291   snprintf(out, sizeof(out), "%s", op_name(po));
1292   for (i = 0; i < po->operand_cnt; i++) {
1293     p += strlen(p);
1294     if (i > 0)
1295       *p++ = ',';
1296     snprintf(p, sizeof(out) - (p - out),
1297       po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1298       po->operand[i].name);
1299   }
1300
1301   return out;
1302 }
1303
1304 static const char *lmod_type_u(struct parsed_op *po,
1305   enum opr_lenmod lmod)
1306 {
1307   switch (lmod) {
1308   case OPLM_QWORD:
1309     return "u64";
1310   case OPLM_DWORD:
1311     return "u32";
1312   case OPLM_WORD:
1313     return "u16";
1314   case OPLM_BYTE:
1315     return "u8";
1316   default:
1317     ferr(po, "invalid lmod: %d\n", lmod);
1318     return "(_invalid_)";
1319   }
1320 }
1321
1322 static const char *lmod_cast_u(struct parsed_op *po,
1323   enum opr_lenmod lmod)
1324 {
1325   switch (lmod) {
1326   case OPLM_QWORD:
1327     return "";
1328   case OPLM_DWORD:
1329     return "";
1330   case OPLM_WORD:
1331     return "(u16)";
1332   case OPLM_BYTE:
1333     return "(u8)";
1334   default:
1335     ferr(po, "invalid lmod: %d\n", lmod);
1336     return "(_invalid_)";
1337   }
1338 }
1339
1340 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1341   enum opr_lenmod lmod)
1342 {
1343   switch (lmod) {
1344   case OPLM_QWORD:
1345     return "*(u64 *)";
1346   case OPLM_DWORD:
1347     return "*(u32 *)";
1348   case OPLM_WORD:
1349     return "*(u16 *)";
1350   case OPLM_BYTE:
1351     return "*(u8 *)";
1352   default:
1353     ferr(po, "invalid lmod: %d\n", lmod);
1354     return "(_invalid_)";
1355   }
1356 }
1357
1358 static const char *lmod_cast_s(struct parsed_op *po,
1359   enum opr_lenmod lmod)
1360 {
1361   switch (lmod) {
1362   case OPLM_QWORD:
1363     return "(s64)";
1364   case OPLM_DWORD:
1365     return "(s32)";
1366   case OPLM_WORD:
1367     return "(s16)";
1368   case OPLM_BYTE:
1369     return "(s8)";
1370   default:
1371     ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1372     return "(_invalid_)";
1373   }
1374 }
1375
1376 static const char *lmod_cast(struct parsed_op *po,
1377   enum opr_lenmod lmod, int is_signed)
1378 {
1379   return is_signed ?
1380     lmod_cast_s(po, lmod) :
1381     lmod_cast_u(po, lmod);
1382 }
1383
1384 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1385 {
1386   switch (lmod) {
1387   case OPLM_QWORD:
1388     return 8;
1389   case OPLM_DWORD:
1390     return 4;
1391   case OPLM_WORD:
1392     return 2;
1393   case OPLM_BYTE:
1394     return 1;
1395   default:
1396     ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1397     return 0;
1398   }
1399 }
1400
1401 static const char *opr_name(struct parsed_op *po, int opr_num)
1402 {
1403   if (opr_num >= po->operand_cnt)
1404     ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1405   return po->operand[opr_num].name;
1406 }
1407
1408 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1409 {
1410   if (opr_num >= po->operand_cnt)
1411     ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1412   if (po->operand[opr_num].type != OPT_CONST)
1413     ferr(po, "opr %d: const expected\n", opr_num);
1414   return po->operand[opr_num].val;
1415 }
1416
1417 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1418 {
1419   if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1420     ferr(po, "invalid reg: %d\n", popr->reg);
1421   return regs_r32[popr->reg];
1422 }
1423
1424 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1425 {
1426   if      (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1427     *bits = 8;
1428   else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1429     *bits = 16;
1430   else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1431     *bits = 32;
1432   else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1433     *bits = 64;
1434   else
1435     return -1;
1436
1437   *is_signed = cast[1] == 's' ? 1 : 0;
1438   return 0;
1439 }
1440
1441 static int check_deref_cast(const char *cast, int *bits)
1442 {
1443   if      (IS_START(cast, "*(u8 *)"))
1444     *bits = 8;
1445   else if (IS_START(cast, "*(u16 *)"))
1446     *bits = 16;
1447   else if (IS_START(cast, "*(u32 *)"))
1448     *bits = 32;
1449   else if (IS_START(cast, "*(u64 *)"))
1450     *bits = 64;
1451   else
1452     return -1;
1453
1454   return 0;
1455 }
1456
1457 // cast1 is the "final" cast
1458 static const char *simplify_cast(const char *cast1, const char *cast2)
1459 {
1460   static char buf[256];
1461   int bits1, bits2;
1462   int s1, s2;
1463
1464   if (cast1[0] == 0)
1465     return cast2;
1466   if (cast2[0] == 0)
1467     return cast1;
1468   if (IS(cast1, cast2))
1469     return cast1;
1470
1471   if (check_simple_cast(cast1, &bits1, &s1) == 0
1472     && check_simple_cast(cast2, &bits2, &s2) == 0)
1473   {
1474     if (bits1 <= bits2)
1475       return cast1;
1476   }
1477   if (check_simple_cast(cast1, &bits1, &s1) == 0
1478     && check_deref_cast(cast2, &bits2) == 0)
1479   {
1480     if (bits1 == bits2) {
1481       snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1482       return buf;
1483     }
1484   }
1485
1486   if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1487     return cast1;
1488
1489   snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1490   return buf;
1491 }
1492
1493 static const char *simplify_cast_num(const char *cast, unsigned int val)
1494 {
1495   if (IS(cast, "(u8)") && val < 0x100)
1496     return "";
1497   if (IS(cast, "(s8)") && val < 0x80)
1498     return "";
1499   if (IS(cast, "(u16)") && val < 0x10000)
1500     return "";
1501   if (IS(cast, "(s16)") && val < 0x8000)
1502     return "";
1503   if (IS(cast, "(s32)") && val < 0x80000000)
1504     return "";
1505
1506   return cast;
1507 }
1508
1509 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1510   int *extra_offs)
1511 {
1512   const char *p;
1513   char *endp;
1514   int namelen;
1515   int i;
1516
1517   *extra_offs = 0;
1518   namelen = strlen(name);
1519
1520   p = strchr(name, '+');
1521   if (p != NULL) {
1522     namelen = p - name;
1523     if (namelen <= 0)
1524       ferr(po, "equ parse failed for '%s'\n", name);
1525
1526     if (IS_START(p, "0x"))
1527       p += 2;
1528     *extra_offs = strtol(p, &endp, 16);
1529     if (*endp != 0)
1530       ferr(po, "equ parse failed for '%s'\n", name);
1531   }
1532
1533   for (i = 0; i < g_eqcnt; i++)
1534     if (strncmp(g_eqs[i].name, name, namelen) == 0
1535      && g_eqs[i].name[namelen] == 0)
1536       break;
1537   if (i >= g_eqcnt) {
1538     if (po != NULL)
1539       ferr(po, "unresolved equ name: '%s'\n", name);
1540     return NULL;
1541   }
1542
1543   return &g_eqs[i];
1544 }
1545
1546 static int is_stack_access(struct parsed_op *po,
1547   const struct parsed_opr *popr)
1548 {
1549   return (parse_stack_el(popr->name, NULL, 0)
1550     || (g_bp_frame && !(po->flags & OPF_EBP_S)
1551         && IS_START(popr->name, "ebp")));
1552 }
1553
1554 static void parse_stack_access(struct parsed_op *po,
1555   const char *name, char *ofs_reg, int *offset_out,
1556   int *stack_ra_out, const char **bp_arg_out, int is_lea)
1557 {
1558   const char *bp_arg = "";
1559   const char *p = NULL;
1560   struct parsed_equ *eq;
1561   char *endp = NULL;
1562   int stack_ra = 0;
1563   int offset = 0;
1564
1565   ofs_reg[0] = 0;
1566
1567   if (IS_START(name, "ebp-")
1568    || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1569   {
1570     p = name + 4;
1571     if (IS_START(p, "0x"))
1572       p += 2;
1573     offset = strtoul(p, &endp, 16);
1574     if (name[3] == '-')
1575       offset = -offset;
1576     if (*endp != 0)
1577       ferr(po, "ebp- parse of '%s' failed\n", name);
1578   }
1579   else {
1580     bp_arg = parse_stack_el(name, ofs_reg, 0);
1581     snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1582     eq = equ_find(po, bp_arg, &offset);
1583     if (eq == NULL)
1584       ferr(po, "detected but missing eq\n");
1585     offset += eq->offset;
1586   }
1587
1588   if (!strncmp(name, "ebp", 3))
1589     stack_ra = 4;
1590
1591   // yes it sometimes LEAs ra for compares..
1592   if (!is_lea && ofs_reg[0] == 0
1593     && stack_ra <= offset && offset < stack_ra + 4)
1594   {
1595     ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1596   }
1597
1598   *offset_out = offset;
1599   *stack_ra_out = stack_ra;
1600   if (bp_arg_out)
1601     *bp_arg_out = bp_arg;
1602 }
1603
1604 static int stack_frame_access(struct parsed_op *po,
1605   struct parsed_opr *popr, char *buf, size_t buf_size,
1606   const char *name, const char *cast, int is_src, int is_lea)
1607 {
1608   enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1609   const char *prefix = "";
1610   const char *bp_arg = NULL;
1611   char ofs_reg[16] = { 0, };
1612   int i, arg_i, arg_s;
1613   int unaligned = 0;
1614   int stack_ra = 0;
1615   int offset = 0;
1616   int retval = -1;
1617   int sf_ofs;
1618   int lim;
1619
1620   if (po->flags & OPF_EBP_S)
1621     ferr(po, "stack_frame_access while ebp is scratch\n");
1622
1623   parse_stack_access(po, name, ofs_reg, &offset,
1624     &stack_ra, &bp_arg, is_lea);
1625
1626   if (offset > stack_ra)
1627   {
1628     arg_i = (offset - stack_ra - 4) / 4;
1629     if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1630     {
1631       if (g_func_pp->is_vararg
1632           && arg_i == g_func_pp->argc_stack && is_lea)
1633       {
1634         // should be va_list
1635         if (cast[0] == 0)
1636           cast = "(u32)";
1637         snprintf(buf, buf_size, "%sap", cast);
1638         return -1;
1639       }
1640       ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1641         offset, bp_arg, arg_i);
1642     }
1643     if (ofs_reg[0] != 0)
1644       ferr(po, "offset reg on arg access?\n");
1645
1646     for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1647       if (g_func_pp->arg[i].reg != NULL)
1648         continue;
1649       if (arg_s == arg_i)
1650         break;
1651       arg_s++;
1652     }
1653     if (i == g_func_pp->argc)
1654       ferr(po, "arg %d not in prototype?\n", arg_i);
1655
1656     popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1657     retval = i;
1658
1659     switch (popr->lmod)
1660     {
1661     case OPLM_BYTE:
1662       if (is_lea)
1663         ferr(po, "lea/byte to arg?\n");
1664       if (is_src && (offset & 3) == 0)
1665         snprintf(buf, buf_size, "%sa%d",
1666           simplify_cast(cast, "(u8)"), i + 1);
1667       else
1668         snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1669           cast, offset & 3, i + 1);
1670       break;
1671
1672     case OPLM_WORD:
1673       if (is_lea)
1674         ferr(po, "lea/word to arg?\n");
1675       if (offset & 1) {
1676         unaligned = 1;
1677         if (!is_src) {
1678           if (offset & 2)
1679             ferr(po, "problematic arg store\n");
1680           snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1681             simplify_cast(cast, "*(u16 *)"), i + 1);
1682         }
1683         else
1684           ferr(po, "unaligned arg word load\n");
1685       }
1686       else if (is_src && (offset & 2) == 0)
1687         snprintf(buf, buf_size, "%sa%d",
1688           simplify_cast(cast, "(u16)"), i + 1);
1689       else
1690         snprintf(buf, buf_size, "%s%sWORD(a%d)",
1691           cast, (offset & 2) ? "HI" : "LO", i + 1);
1692       break;
1693
1694     case OPLM_DWORD:
1695       if (cast[0])
1696         prefix = cast;
1697       else if (is_src)
1698         prefix = "(u32)";
1699
1700       if (offset & 3) {
1701         unaligned = 1;
1702         if (is_lea)
1703           snprintf(buf, buf_size, "(u32)&a%d + %d",
1704             i + 1, offset & 3);
1705         else if (!is_src)
1706           ferr(po, "unaligned arg store\n");
1707         else {
1708           // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1709           snprintf(buf, buf_size, "%s(a%d >> %d)",
1710             prefix, i + 1, (offset & 3) * 8);
1711         }
1712       }
1713       else {
1714         snprintf(buf, buf_size, "%s%sa%d",
1715           prefix, is_lea ? "&" : "", i + 1);
1716       }
1717       break;
1718
1719     default:
1720       ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1721     }
1722
1723     if (unaligned)
1724       snprintf(g_comment, sizeof(g_comment), "%s unaligned", bp_arg);
1725
1726     // common problem
1727     guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
1728     if (tmp_lmod != OPLM_DWORD
1729       && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
1730                          < lmod_bytes(po, popr->lmod) + (offset & 3))))
1731     {
1732       ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
1733         i + 1, offset, g_func_pp->arg[i].type.name);
1734     }
1735     // can't check this because msvc likes to reuse
1736     // arg space for scratch..
1737     //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
1738     //  ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
1739   }
1740   else
1741   {
1742     if (g_stack_fsz == 0)
1743       ferr(po, "stack var access without stackframe\n");
1744     g_stack_frame_used = 1;
1745
1746     sf_ofs = g_stack_fsz + offset;
1747     lim = (ofs_reg[0] != 0) ? -4 : 0;
1748     if (offset > 0 || sf_ofs < lim)
1749       ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
1750
1751     if (is_lea)
1752       prefix = "(u32)&";
1753     else
1754       prefix = cast;
1755
1756     switch (popr->lmod)
1757     {
1758     case OPLM_BYTE:
1759       snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1760         prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1761       break;
1762
1763     case OPLM_WORD:
1764       if ((sf_ofs & 1) || ofs_reg[0] != 0) {
1765         // known unaligned or possibly unaligned
1766         strcat(g_comment, " unaligned");
1767         if (prefix[0] == 0)
1768           prefix = "*(u16 *)&";
1769         snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1770           prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1771         break;
1772       }
1773       snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
1774       break;
1775
1776     case OPLM_DWORD:
1777       if ((sf_ofs & 3) || ofs_reg[0] != 0) {
1778         // known unaligned or possibly unaligned
1779         strcat(g_comment, " unaligned");
1780         if (prefix[0] == 0)
1781           prefix = "*(u32 *)&";
1782         snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1783           prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1784         break;
1785       }
1786       snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
1787       break;
1788
1789     default:
1790       ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
1791     }
1792   }
1793
1794   return retval;
1795 }
1796
1797 static void check_func_pp(struct parsed_op *po,
1798   const struct parsed_proto *pp, const char *pfx)
1799 {
1800   enum opr_lenmod tmp_lmod;
1801   char buf[256];
1802   int ret, i;
1803
1804   if (pp->argc_reg != 0) {
1805     if (/*!g_allow_regfunc &&*/ !pp->is_fastcall) {
1806       pp_print(buf, sizeof(buf), pp);
1807       ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
1808     }
1809     if (pp->argc_stack > 0 && pp->argc_reg != 2)
1810       ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
1811         pfx, pp->argc_reg, pp->argc_stack);
1812   }
1813
1814   // fptrs must use 32bit args, callsite might have no information and
1815   // lack a cast to smaller types, which results in incorrectly masked
1816   // args passed (callee may assume masked args, it does on ARM)
1817   if (!pp->is_osinc) {
1818     for (i = 0; i < pp->argc; i++) {
1819       ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
1820       if (ret && tmp_lmod != OPLM_DWORD)
1821         ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
1822           i + 1, pp->arg[i].type.name);
1823     }
1824   }
1825 }
1826
1827 static const char *check_label_read_ref(struct parsed_op *po,
1828   const char *name)
1829 {
1830   const struct parsed_proto *pp;
1831
1832   pp = proto_parse(g_fhdr, name, 0);
1833   if (pp == NULL)
1834     ferr(po, "proto_parse failed for ref '%s'\n", name);
1835
1836   if (pp->is_func)
1837     check_func_pp(po, pp, "ref");
1838
1839   return pp->name;
1840 }
1841
1842 static char *out_src_opr(char *buf, size_t buf_size,
1843   struct parsed_op *po, struct parsed_opr *popr, const char *cast,
1844   int is_lea)
1845 {
1846   char tmp1[256], tmp2[256];
1847   char expr[256];
1848   const char *name;
1849   char *p;
1850   int ret;
1851
1852   if (cast == NULL)
1853     cast = "";
1854
1855   switch (popr->type) {
1856   case OPT_REG:
1857     if (is_lea)
1858       ferr(po, "lea from reg?\n");
1859
1860     switch (popr->lmod) {
1861     case OPLM_QWORD:
1862       snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
1863       break;
1864     case OPLM_DWORD:
1865       snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
1866       break;
1867     case OPLM_WORD:
1868       snprintf(buf, buf_size, "%s%s",
1869         simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
1870       break;
1871     case OPLM_BYTE:
1872       if (popr->name[1] == 'h') // XXX..
1873         snprintf(buf, buf_size, "%s(%s >> 8)",
1874           simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
1875       else
1876         snprintf(buf, buf_size, "%s%s",
1877           simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
1878       break;
1879     default:
1880       ferr(po, "invalid src lmod: %d\n", popr->lmod);
1881     }
1882     break;
1883
1884   case OPT_REGMEM:
1885     if (is_stack_access(po, popr)) {
1886       stack_frame_access(po, popr, buf, buf_size,
1887         popr->name, cast, 1, is_lea);
1888       break;
1889     }
1890
1891     strcpy(expr, popr->name);
1892     if (strchr(expr, '[')) {
1893       // special case: '[' can only be left for label[reg] form
1894       ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
1895       if (ret != 2)
1896         ferr(po, "parse failure for '%s'\n", expr);
1897       if (tmp1[0] == '(') {
1898         // (off_4FFF50+3)[eax]
1899         p = strchr(tmp1 + 1, ')');
1900         if (p == NULL || p[1] != 0)
1901           ferr(po, "parse failure (2) for '%s'\n", expr);
1902         *p = 0;
1903         memmove(tmp1, tmp1 + 1, strlen(tmp1));
1904       }
1905       snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
1906     }
1907
1908     // XXX: do we need more parsing?
1909     if (is_lea) {
1910       snprintf(buf, buf_size, "%s", expr);
1911       break;
1912     }
1913
1914     snprintf(buf, buf_size, "%s(%s)",
1915       simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
1916     break;
1917
1918   case OPT_LABEL:
1919     name = check_label_read_ref(po, popr->name);
1920     if (cast[0] == 0 && popr->is_ptr)
1921       cast = "(u32)";
1922
1923     if (is_lea)
1924       snprintf(buf, buf_size, "(u32)&%s", name);
1925     else if (popr->size_lt)
1926       snprintf(buf, buf_size, "%s%s%s%s", cast,
1927         lmod_cast_u_ptr(po, popr->lmod),
1928         popr->is_array ? "" : "&", name);
1929     else
1930       snprintf(buf, buf_size, "%s%s%s", cast, name,
1931         popr->is_array ? "[0]" : "");
1932     break;
1933
1934   case OPT_OFFSET:
1935     name = check_label_read_ref(po, popr->name);
1936     if (cast[0] == 0)
1937       cast = "(u32)";
1938     if (is_lea)
1939       ferr(po, "lea an offset?\n");
1940     snprintf(buf, buf_size, "%s&%s", cast, name);
1941     break;
1942
1943   case OPT_CONST:
1944     if (is_lea)
1945       ferr(po, "lea from const?\n");
1946
1947     printf_number(tmp1, sizeof(tmp1), popr->val);
1948     if (popr->val == 0 && strchr(cast, '*'))
1949       snprintf(buf, buf_size, "NULL");
1950     else
1951       snprintf(buf, buf_size, "%s%s",
1952         simplify_cast_num(cast, popr->val), tmp1);
1953     break;
1954
1955   default:
1956     ferr(po, "invalid src type: %d\n", popr->type);
1957   }
1958
1959   return buf;
1960 }
1961
1962 // note: may set is_ptr (we find that out late for ebp frame..)
1963 static char *out_dst_opr(char *buf, size_t buf_size,
1964         struct parsed_op *po, struct parsed_opr *popr)
1965 {
1966   switch (popr->type) {
1967   case OPT_REG:
1968     switch (popr->lmod) {
1969     case OPLM_QWORD:
1970       snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
1971       break;
1972     case OPLM_DWORD:
1973       snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
1974       break;
1975     case OPLM_WORD:
1976       // ugh..
1977       snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
1978       break;
1979     case OPLM_BYTE:
1980       // ugh..
1981       if (popr->name[1] == 'h') // XXX..
1982         snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
1983       else
1984         snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
1985       break;
1986     default:
1987       ferr(po, "invalid dst lmod: %d\n", popr->lmod);
1988     }
1989     break;
1990
1991   case OPT_REGMEM:
1992     if (is_stack_access(po, popr)) {
1993       stack_frame_access(po, popr, buf, buf_size,
1994         popr->name, "", 0, 0);
1995       break;
1996     }
1997
1998     return out_src_opr(buf, buf_size, po, popr, NULL, 0);
1999
2000   case OPT_LABEL:
2001     if (popr->size_mismatch)
2002       snprintf(buf, buf_size, "%s%s%s",
2003         lmod_cast_u_ptr(po, popr->lmod),
2004         popr->is_array ? "" : "&", popr->name);
2005     else
2006       snprintf(buf, buf_size, "%s%s", popr->name,
2007         popr->is_array ? "[0]" : "");
2008     break;
2009
2010   default:
2011     ferr(po, "invalid dst type: %d\n", popr->type);
2012   }
2013
2014   return buf;
2015 }
2016
2017 static char *out_src_opr_u32(char *buf, size_t buf_size,
2018         struct parsed_op *po, struct parsed_opr *popr)
2019 {
2020   return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2021 }
2022
2023 static void out_test_for_cc(char *buf, size_t buf_size,
2024   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2025   enum opr_lenmod lmod, const char *expr)
2026 {
2027   const char *cast, *scast;
2028
2029   cast = lmod_cast_u(po, lmod);
2030   scast = lmod_cast_s(po, lmod);
2031
2032   switch (pfo) {
2033   case PFO_Z:
2034   case PFO_BE: // CF=1||ZF=1; CF=0
2035     snprintf(buf, buf_size, "(%s%s %s 0)",
2036       cast, expr, is_inv ? "!=" : "==");
2037     break;
2038
2039   case PFO_S:
2040   case PFO_L: // SF!=OF; OF=0
2041     snprintf(buf, buf_size, "(%s%s %s 0)",
2042       scast, expr, is_inv ? ">=" : "<");
2043     break;
2044
2045   case PFO_LE: // ZF=1||SF!=OF; OF=0
2046     snprintf(buf, buf_size, "(%s%s %s 0)",
2047       scast, expr, is_inv ? ">" : "<=");
2048     break;
2049
2050   default:
2051     ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2052   }
2053 }
2054
2055 static void out_cmp_for_cc(char *buf, size_t buf_size,
2056   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2057 {
2058   const char *cast, *scast, *cast_use;
2059   char buf1[256], buf2[256];
2060   enum opr_lenmod lmod;
2061
2062   if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2063     ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2064       po->operand[0].lmod, po->operand[1].lmod);
2065   lmod = po->operand[0].lmod;
2066
2067   cast = lmod_cast_u(po, lmod);
2068   scast = lmod_cast_s(po, lmod);
2069
2070   switch (pfo) {
2071   case PFO_C:
2072   case PFO_Z:
2073   case PFO_BE: // !a
2074     cast_use = cast;
2075     break;
2076
2077   case PFO_S:
2078   case PFO_L: // !ge
2079   case PFO_LE:
2080     cast_use = scast;
2081     break;
2082
2083   default:
2084     ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2085   }
2086
2087   out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2088   if (po->op == OP_DEC)
2089     snprintf(buf2, sizeof(buf2), "1");
2090   else
2091     out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_use, 0);
2092
2093   switch (pfo) {
2094   case PFO_C:
2095     // note: must be unsigned compare
2096     snprintf(buf, buf_size, "(%s %s %s)",
2097       buf1, is_inv ? ">=" : "<", buf2);
2098     break;
2099
2100   case PFO_Z:
2101     snprintf(buf, buf_size, "(%s %s %s)",
2102       buf1, is_inv ? "!=" : "==", buf2);
2103     break;
2104
2105   case PFO_BE: // !a
2106     // note: must be unsigned compare
2107     snprintf(buf, buf_size, "(%s %s %s)",
2108       buf1, is_inv ? ">" : "<=", buf2);
2109
2110     // annoying case
2111     if (is_inv && lmod == OPLM_BYTE
2112       && po->operand[1].type == OPT_CONST
2113       && po->operand[1].val == 0xff)
2114     {
2115       snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2116       snprintf(buf, buf_size, "(0)");
2117     }
2118     break;
2119
2120   // note: must be signed compare
2121   case PFO_S:
2122     snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2123       scast, buf1, buf2, is_inv ? ">=" : "<");
2124     break;
2125
2126   case PFO_L: // !ge
2127     snprintf(buf, buf_size, "(%s %s %s)",
2128       buf1, is_inv ? ">=" : "<", buf2);
2129     break;
2130
2131   case PFO_LE: // !g
2132     snprintf(buf, buf_size, "(%s %s %s)",
2133       buf1, is_inv ? ">" : "<=", buf2);
2134     break;
2135
2136   default:
2137     break;
2138   }
2139 }
2140
2141 static void out_cmp_test(char *buf, size_t buf_size,
2142   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2143 {
2144   char buf1[256], buf2[256], buf3[256];
2145
2146   if (po->op == OP_TEST) {
2147     if (IS(opr_name(po, 0), opr_name(po, 1))) {
2148       out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2149     }
2150     else {
2151       out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2152       out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2153       snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2154     }
2155     out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2156       po->operand[0].lmod, buf3);
2157   }
2158   else if (po->op == OP_CMP) {
2159     out_cmp_for_cc(buf, buf_size, po, pfo, is_inv);
2160   }
2161   else
2162     ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2163 }
2164
2165 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2166         struct parsed_opr *popr2)
2167 {
2168   if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2169     ferr(po, "missing lmod for both operands\n");
2170
2171   if (popr1->lmod == OPLM_UNSPEC)
2172     popr1->lmod = popr2->lmod;
2173   else if (popr2->lmod == OPLM_UNSPEC)
2174     popr2->lmod = popr1->lmod;
2175   else if (popr1->lmod != popr2->lmod) {
2176     if (popr1->type_from_var) {
2177       popr1->size_mismatch = 1;
2178       if (popr1->lmod < popr2->lmod)
2179         popr1->size_lt = 1;
2180       popr1->lmod = popr2->lmod;
2181     }
2182     else if (popr2->type_from_var) {
2183       popr2->size_mismatch = 1;
2184       if (popr2->lmod < popr1->lmod)
2185         popr2->size_lt = 1;
2186       popr2->lmod = popr1->lmod;
2187     }
2188     else
2189       ferr(po, "conflicting lmods: %d vs %d\n",
2190         popr1->lmod, popr2->lmod);
2191   }
2192 }
2193
2194 static const char *op_to_c(struct parsed_op *po)
2195 {
2196   switch (po->op)
2197   {
2198     case OP_ADD:
2199     case OP_ADC:
2200       return "+";
2201     case OP_SUB:
2202     case OP_SBB:
2203       return "-";
2204     case OP_AND:
2205       return "&";
2206     case OP_OR:
2207       return "|";
2208     case OP_XOR:
2209       return "^";
2210     case OP_SHL:
2211       return "<<";
2212     case OP_SHR:
2213       return ">>";
2214     case OP_MUL:
2215     case OP_IMUL:
2216       return "*";
2217     default:
2218       ferr(po, "op_to_c was supplied with %d\n", po->op);
2219   }
2220 }
2221
2222 // last op in stream - unconditional branch or ret
2223 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2224   || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2225       && ops[_i].op != OP_CALL))
2226
2227 #define check_i(po, i) \
2228   if ((i) < 0) \
2229     ferr(po, "bad " #i ": %d\n", i)
2230
2231 // note: this skips over calls and rm'd stuff assuming they're handled
2232 // so it's intended to use at one of final passes
2233 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2234   int depth, int flags_set)
2235 {
2236   struct parsed_op *po;
2237   int relevant;
2238   int ret = 0;
2239   int j;
2240
2241   for (; i < opcnt; i++) {
2242     po = &ops[i];
2243     if (po->cc_scratch == magic)
2244       return ret; // already checked
2245     po->cc_scratch = magic;
2246
2247     if (po->flags & OPF_TAIL) {
2248       if (po->op == OP_CALL) {
2249         if (po->pp != NULL && po->pp->is_noreturn)
2250           // assume no stack cleanup for noreturn
2251           return 1;
2252       }
2253       return -1; // deadend
2254     }
2255
2256     if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2257       continue;
2258
2259     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2260       if (po->btj != NULL) {
2261         // jumptable
2262         for (j = 0; j < po->btj->count; j++) {
2263           check_i(po, po->btj->d[j].bt_i);
2264           ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2265                    depth, flags_set);
2266           if (ret < 0)
2267             return ret; // dead end
2268         }
2269         return ret;
2270       }
2271
2272       check_i(po, po->bt_i);
2273       if (po->flags & OPF_CJMP) {
2274         ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2275                  depth, flags_set);
2276         if (ret < 0)
2277           return ret; // dead end
2278       }
2279       else {
2280         i = po->bt_i - 1;
2281       }
2282       continue;
2283     }
2284
2285     relevant = 0;
2286     if ((po->op == OP_POP || po->op == OP_PUSH)
2287       && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2288     {
2289       relevant = 1;
2290     }
2291
2292     if (po->op == OP_PUSH) {
2293       depth++;
2294     }
2295     else if (po->op == OP_POP) {
2296       if (relevant && depth == 0) {
2297         po->flags |= flags_set;
2298         return 1;
2299       }
2300       depth--;
2301     }
2302   }
2303
2304   return -1;
2305 }
2306
2307 // scan for 'reg' pop backwards starting from i
2308 // intended to use for register restore search, so other reg
2309 // references are considered an error
2310 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2311 {
2312   struct parsed_op *po;
2313   struct label_ref *lr;
2314   int ret = 0;
2315
2316   ops[i].cc_scratch = magic;
2317
2318   while (1)
2319   {
2320     if (g_labels[i] != NULL) {
2321       lr = &g_label_refs[i];
2322       for (; lr != NULL; lr = lr->next) {
2323         check_i(&ops[i], lr->i);
2324         ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2325         if (ret < 0)
2326           return ret;
2327       }
2328       if (i > 0 && LAST_OP(i - 1))
2329         return ret;
2330     }
2331
2332     i--;
2333     if (i < 0)
2334       break;
2335
2336     if (ops[i].cc_scratch == magic)
2337       return ret;
2338     ops[i].cc_scratch = magic;
2339
2340     po = &ops[i];
2341     if (po->op == OP_POP && po->operand[0].reg == reg) {
2342       if (po->flags & (OPF_RMD|OPF_DONE))
2343         return -1;
2344
2345       po->flags |= set_flags;
2346       return 1;
2347     }
2348
2349     // this also covers the case where we reach corresponding push
2350     if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2351       return -1;
2352   }
2353
2354   // nothing interesting on this path
2355   return 0;
2356 }
2357
2358 static void find_reachable_exits(int i, int opcnt, int magic,
2359   int *exits, int *exit_count)
2360 {
2361   struct parsed_op *po;
2362   int j;
2363
2364   for (; i < opcnt; i++)
2365   {
2366     po = &ops[i];
2367     if (po->cc_scratch == magic)
2368       return;
2369     po->cc_scratch = magic;
2370
2371     if (po->flags & OPF_TAIL) {
2372       ferr_assert(po, *exit_count < MAX_EXITS);
2373       exits[*exit_count] = i;
2374       (*exit_count)++;
2375       return;
2376     }
2377
2378     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2379       if (po->flags & OPF_RMD)
2380         continue;
2381
2382       if (po->btj != NULL) {
2383         for (j = 0; j < po->btj->count; j++) {
2384           check_i(po, po->btj->d[j].bt_i);
2385           find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2386                   exits, exit_count);
2387         }
2388         return;
2389       }
2390
2391       check_i(po, po->bt_i);
2392       if (po->flags & OPF_CJMP)
2393         find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2394       else
2395         i = po->bt_i - 1;
2396       continue;
2397     }
2398   }
2399 }
2400
2401 // scan for 'reg' pop backwards starting from exits (all paths)
2402 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2403 {
2404   static int exits[MAX_EXITS];
2405   static int exit_count;
2406   int j, ret;
2407
2408   if (!set_flags) {
2409     exit_count = 0;
2410     find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2411       &exit_count);
2412     ferr_assert(&ops[i], exit_count > 0);
2413   }
2414
2415   for (j = 0; j < exit_count; j++) {
2416     ret = scan_for_rsave_pop_reg(exits[j], i + opcnt * 16 + set_flags,
2417             reg, set_flags);
2418     if (ret == -1)
2419       return -1;
2420   }
2421
2422   return 1;
2423 }
2424
2425 // scan for one or more pop of push <const>
2426 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2427   int push_i, int is_probe)
2428 {
2429   struct parsed_op *po;
2430   struct label_ref *lr;
2431   int ret = 0;
2432   int j;
2433
2434   for (; i < opcnt; i++)
2435   {
2436     po = &ops[i];
2437     if (po->cc_scratch == magic)
2438       return ret; // already checked
2439     po->cc_scratch = magic;
2440
2441     if (po->flags & OPF_JMP) {
2442       if (po->flags & OPF_RMD)
2443         continue;
2444       if (po->op == OP_CALL)
2445         return -1;
2446
2447       if (po->btj != NULL) {
2448         for (j = 0; j < po->btj->count; j++) {
2449           check_i(po, po->btj->d[j].bt_i);
2450           ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2451                   push_i, is_probe);
2452           if (ret < 0)
2453             return ret;
2454         }
2455         return ret;
2456       }
2457
2458       check_i(po, po->bt_i);
2459       if (po->flags & OPF_CJMP) {
2460         ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2461                  is_probe);
2462         if (ret < 0)
2463           return ret;
2464       }
2465       else {
2466         i = po->bt_i - 1;
2467       }
2468       continue;
2469     }
2470
2471     if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2472       return -1;
2473
2474     if (g_labels[i] != NULL) {
2475       // all refs must be visited
2476       lr = &g_label_refs[i];
2477       for (; lr != NULL; lr = lr->next) {
2478         check_i(po, lr->i);
2479         if (ops[lr->i].cc_scratch != magic)
2480           return -1;
2481       }
2482       if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2483         return -1;
2484     }
2485
2486     if (po->op == OP_POP)
2487     {
2488       if (po->flags & (OPF_RMD|OPF_DONE))
2489         return -1;
2490
2491       if (!is_probe) {
2492         po->flags |= OPF_DONE;
2493         po->datap = &ops[push_i];
2494       }
2495       return 1;
2496     }
2497   }
2498
2499   return -1;
2500 }
2501
2502 static void scan_for_pop_const(int i, int opcnt, int magic)
2503 {
2504   int ret;
2505
2506   ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2507   if (ret == 1) {
2508     ops[i].flags |= OPF_RMD | OPF_DONE;
2509     scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2510   }
2511 }
2512
2513 // check if all branch targets within a marked path are also marked
2514 // note: the path checked must not be empty or end with a branch
2515 static int check_path_branches(int opcnt, int magic)
2516 {
2517   struct parsed_op *po;
2518   int i, j;
2519
2520   for (i = 0; i < opcnt; i++) {
2521     po = &ops[i];
2522     if (po->cc_scratch != magic)
2523       continue;
2524
2525     if (po->flags & OPF_JMP) {
2526       if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2527         continue;
2528
2529       if (po->btj != NULL) {
2530         for (j = 0; j < po->btj->count; j++) {
2531           check_i(po, po->btj->d[j].bt_i);
2532           if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2533             return 0;
2534         }
2535       }
2536
2537       check_i(po, po->bt_i);
2538       if (ops[po->bt_i].cc_scratch != magic)
2539         return 0;
2540       if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2541         return 0;
2542     }
2543   }
2544
2545   return 1;
2546 }
2547
2548 // scan for multiple pushes for given pop
2549 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2550   int is_probe)
2551 {
2552   int reg = ops[pop_i].operand[0].reg;
2553   struct parsed_op *po;
2554   struct label_ref *lr;
2555   int ret = 0;
2556
2557   ops[i].cc_scratch = magic;
2558
2559   while (1)
2560   {
2561     if (g_labels[i] != NULL) {
2562       lr = &g_label_refs[i];
2563       for (; lr != NULL; lr = lr->next) {
2564         check_i(&ops[i], lr->i);
2565         ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2566         if (ret < 0)
2567           return ret;
2568       }
2569       if (i > 0 && LAST_OP(i - 1))
2570         return ret;
2571     }
2572
2573     i--;
2574     if (i < 0)
2575       break;
2576
2577     if (ops[i].cc_scratch == magic)
2578       return ret;
2579     ops[i].cc_scratch = magic;
2580
2581     po = &ops[i];
2582     if (po->op == OP_CALL)
2583       return -1;
2584     if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2585       return -1;
2586
2587     if (po->op == OP_PUSH)
2588     {
2589       if (po->datap != NULL)
2590         return -1;
2591       if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2592         // leave this case for reg save/restore handlers
2593         return -1;
2594
2595       if (!is_probe) {
2596         po->flags |= OPF_PPUSH | OPF_DONE;
2597         po->datap = &ops[pop_i];
2598       }
2599       return 1;
2600     }
2601   }
2602
2603   return -1;
2604 }
2605
2606 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2607 {
2608   int magic = i + opcnt * 14;
2609   int ret;
2610
2611   ret = scan_pushes_for_pop_r(i, magic, i, 1);
2612   if (ret == 1) {
2613     ret = check_path_branches(opcnt, magic);
2614     if (ret == 1) {
2615       ops[i].flags |= OPF_PPUSH | OPF_DONE;
2616       *regmask_pp |= 1 << ops[i].operand[0].reg;
2617       scan_pushes_for_pop_r(i, magic + 1, i, 0);
2618     }
2619   }
2620 }
2621
2622 static void scan_propagate_df(int i, int opcnt)
2623 {
2624   struct parsed_op *po = &ops[i];
2625   int j;
2626
2627   for (; i < opcnt; i++) {
2628     po = &ops[i];
2629     if (po->flags & OPF_DF)
2630       return; // already resolved
2631     po->flags |= OPF_DF;
2632
2633     if (po->op == OP_CALL)
2634       ferr(po, "call with DF set?\n");
2635
2636     if (po->flags & OPF_JMP) {
2637       if (po->btj != NULL) {
2638         // jumptable
2639         for (j = 0; j < po->btj->count; j++) {
2640           check_i(po, po->btj->d[j].bt_i);
2641           scan_propagate_df(po->btj->d[j].bt_i, opcnt);
2642         }
2643         return;
2644       }
2645
2646       if (po->flags & OPF_RMD)
2647         continue;
2648       check_i(po, po->bt_i);
2649       if (po->flags & OPF_CJMP)
2650         scan_propagate_df(po->bt_i, opcnt);
2651       else
2652         i = po->bt_i - 1;
2653       continue;
2654     }
2655
2656     if (po->flags & OPF_TAIL)
2657       break;
2658
2659     if (po->op == OP_CLD) {
2660       po->flags |= OPF_RMD | OPF_DONE;
2661       return;
2662     }
2663   }
2664
2665   ferr(po, "missing DF clear?\n");
2666 }
2667
2668 // is operand 'opr' referenced by parsed_op 'po'?
2669 static int is_opr_referenced(const struct parsed_opr *opr,
2670   const struct parsed_op *po)
2671 {
2672   int i, mask;
2673
2674   if (opr->type == OPT_REG) {
2675     mask = po->regmask_dst | po->regmask_src;
2676     if (po->op == OP_CALL)
2677       mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
2678     if ((1 << opr->reg) & mask)
2679       return 1;
2680     else
2681       return 0;
2682   }
2683
2684   for (i = 0; i < po->operand_cnt; i++)
2685     if (IS(po->operand[0].name, opr->name))
2686       return 1;
2687
2688   return 0;
2689 }
2690
2691 // is operand 'opr' read by parsed_op 'po'?
2692 static int is_opr_read(const struct parsed_opr *opr,
2693   const struct parsed_op *po)
2694 {
2695   if (opr->type == OPT_REG) {
2696     if (po->regmask_src & (1 << opr->reg))
2697       return 1;
2698     else
2699       return 0;
2700   }
2701
2702   // yes I'm lazy
2703   return 0;
2704 }
2705
2706 // is operand 'opr' modified by parsed_op 'po'?
2707 static int is_opr_modified(const struct parsed_opr *opr,
2708   const struct parsed_op *po)
2709 {
2710   int mask;
2711
2712   if (opr->type == OPT_REG) {
2713     if (po->op == OP_CALL) {
2714       mask = po->regmask_dst;
2715       mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
2716       if (mask & (1 << opr->reg))
2717         return 1;
2718       else
2719         return 0;
2720     }
2721
2722     if (po->regmask_dst & (1 << opr->reg))
2723       return 1;
2724     else
2725       return 0;
2726   }
2727
2728   return IS(po->operand[0].name, opr->name);
2729 }
2730
2731 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
2732 static int is_any_opr_modified(const struct parsed_op *po_test,
2733   const struct parsed_op *po, int c_mode)
2734 {
2735   int mask;
2736   int i;
2737
2738   if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
2739     return 0;
2740
2741   if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
2742     return 0;
2743
2744   if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
2745     return 1;
2746
2747   // in reality, it can wreck any register, but in decompiled C
2748   // version it can only overwrite eax or edx:eax
2749   mask = (1 << xAX) | (1 << xDX);
2750   if (!c_mode)
2751     mask |= 1 << xCX;
2752
2753   if (po->op == OP_CALL
2754    && ((po_test->regmask_src | po_test->regmask_dst) & mask))
2755     return 1;
2756
2757   for (i = 0; i < po_test->operand_cnt; i++)
2758     if (IS(po_test->operand[i].name, po->operand[0].name))
2759       return 1;
2760
2761   return 0;
2762 }
2763
2764 // scan for any po_test operand modification in range given
2765 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
2766   int c_mode)
2767 {
2768   if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
2769     return -1;
2770
2771   for (; i < opcnt; i++) {
2772     if (is_any_opr_modified(po_test, &ops[i], c_mode))
2773       return i;
2774   }
2775
2776   return -1;
2777 }
2778
2779 // scan for po_test operand[0] modification in range given
2780 static int scan_for_mod_opr0(struct parsed_op *po_test,
2781   int i, int opcnt)
2782 {
2783   for (; i < opcnt; i++) {
2784     if (is_opr_modified(&po_test->operand[0], &ops[i]))
2785       return i;
2786   }
2787
2788   return -1;
2789 }
2790
2791 static int scan_for_flag_set(int i, int magic, int *branched,
2792   int *setters, int *setter_cnt)
2793 {
2794   struct label_ref *lr;
2795   int ret;
2796
2797   while (i >= 0) {
2798     if (ops[i].cc_scratch == magic) {
2799       // is this a problem?
2800       //ferr(&ops[i], "%s looped\n", __func__);
2801       return 0;
2802     }
2803     ops[i].cc_scratch = magic;
2804
2805     if (g_labels[i] != NULL) {
2806       *branched = 1;
2807
2808       lr = &g_label_refs[i];
2809       for (; lr->next; lr = lr->next) {
2810         check_i(&ops[i], lr->i);
2811         ret = scan_for_flag_set(lr->i, magic,
2812                 branched, setters, setter_cnt);
2813         if (ret < 0)
2814           return ret;
2815       }
2816
2817       check_i(&ops[i], lr->i);
2818       if (i > 0 && LAST_OP(i - 1)) {
2819         i = lr->i;
2820         continue;
2821       }
2822       ret = scan_for_flag_set(lr->i, magic,
2823               branched, setters, setter_cnt);
2824       if (ret < 0)
2825         return ret;
2826     }
2827     i--;
2828
2829     if (ops[i].flags & OPF_FLAGS) {
2830       setters[*setter_cnt] = i;
2831       (*setter_cnt)++;
2832       return 0;
2833     }
2834
2835     if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
2836       return -1;
2837   }
2838
2839   return -1;
2840 }
2841
2842 // scan back for cdq, if anything modifies edx, fail
2843 static int scan_for_cdq_edx(int i)
2844 {
2845   while (i >= 0) {
2846     if (g_labels[i] != NULL) {
2847       if (g_label_refs[i].next != NULL)
2848         return -1;
2849       if (i > 0 && LAST_OP(i - 1)) {
2850         i = g_label_refs[i].i;
2851         continue;
2852       }
2853       return -1;
2854     }
2855     i--;
2856
2857     if (ops[i].op == OP_CDQ)
2858       return i;
2859
2860     if (ops[i].regmask_dst & (1 << xDX))
2861       return -1;
2862   }
2863
2864   return -1;
2865 }
2866
2867 static int scan_for_reg_clear(int i, int reg)
2868 {
2869   while (i >= 0) {
2870     if (g_labels[i] != NULL) {
2871       if (g_label_refs[i].next != NULL)
2872         return -1;
2873       if (i > 0 && LAST_OP(i - 1)) {
2874         i = g_label_refs[i].i;
2875         continue;
2876       }
2877       return -1;
2878     }
2879     i--;
2880
2881     if (ops[i].op == OP_XOR
2882      && ops[i].operand[0].lmod == OPLM_DWORD
2883      && ops[i].operand[0].reg == ops[i].operand[1].reg
2884      && ops[i].operand[0].reg == reg)
2885       return i;
2886
2887     if (ops[i].regmask_dst & (1 << reg))
2888       return -1;
2889   }
2890
2891   return -1;
2892 }
2893
2894 static void patch_esp_adjust(struct parsed_op *po, int adj)
2895 {
2896   ferr_assert(po, po->op == OP_ADD);
2897   ferr_assert(po, IS(opr_name(po, 0), "esp"));
2898   ferr_assert(po, po->operand[1].type == OPT_CONST);
2899
2900   // this is a bit of a hack, but deals with use of
2901   // single adj for multiple calls
2902   po->operand[1].val -= adj;
2903   po->flags |= OPF_RMD;
2904   if (po->operand[1].val == 0)
2905     po->flags |= OPF_DONE;
2906   ferr_assert(po, (int)po->operand[1].val >= 0);
2907 }
2908
2909 // scan for positive, constant esp adjust
2910 // multipath case is preliminary
2911 static int scan_for_esp_adjust(int i, int opcnt,
2912   int adj_expect, int *adj, int *is_multipath, int do_update)
2913 {
2914   int adj_expect_unknown = 0;
2915   struct parsed_op *po;
2916   int first_pop = -1;
2917   int adj_best = 0;
2918
2919   *adj = *is_multipath = 0;
2920   if (adj_expect < 0) {
2921     adj_expect_unknown = 1;
2922     adj_expect = 32 * 4; // enough?
2923   }
2924
2925   for (; i < opcnt && *adj < adj_expect; i++) {
2926     if (g_labels[i] != NULL)
2927       *is_multipath = 1;
2928
2929     po = &ops[i];
2930     if (po->flags & OPF_DONE)
2931       continue;
2932
2933     if (po->op == OP_ADD && po->operand[0].reg == xSP) {
2934       if (po->operand[1].type != OPT_CONST)
2935         ferr(&ops[i], "non-const esp adjust?\n");
2936       *adj += po->operand[1].val;
2937       if (*adj & 3)
2938         ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
2939       if (do_update) {
2940         if (!*is_multipath)
2941           patch_esp_adjust(po, adj_expect);
2942         else
2943           po->flags |= OPF_RMD;
2944       }
2945       return i;
2946     }
2947     else if (po->op == OP_PUSH) {
2948       //if (first_pop == -1)
2949       //  first_pop = -2; // none
2950       *adj -= lmod_bytes(po, po->operand[0].lmod);
2951     }
2952     else if (po->op == OP_POP) {
2953       if (!(po->flags & OPF_DONE)) {
2954         // seems like msvc only uses 'pop ecx' for stack realignment..
2955         if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
2956           break;
2957         if (first_pop == -1 && *adj >= 0)
2958           first_pop = i;
2959       }
2960       if (do_update && *adj >= 0) {
2961         po->flags |= OPF_RMD;
2962         if (!*is_multipath)
2963           po->flags |= OPF_DONE | OPF_NOREGS;
2964       }
2965
2966       *adj += lmod_bytes(po, po->operand[0].lmod);
2967       if (*adj > adj_best)
2968         adj_best = *adj;
2969     }
2970     else if (po->flags & (OPF_JMP|OPF_TAIL)) {
2971       if (po->op == OP_JMP && po->btj == NULL) {
2972         if (po->bt_i <= i)
2973           break;
2974         i = po->bt_i - 1;
2975         continue;
2976       }
2977       if (po->op != OP_CALL)
2978         break;
2979       if (po->operand[0].type != OPT_LABEL)
2980         break;
2981       if (po->pp != NULL && po->pp->is_stdcall)
2982         break;
2983       if (adj_expect_unknown && first_pop >= 0)
2984         break;
2985       // assume it's another cdecl call
2986     }
2987   }
2988
2989   if (first_pop >= 0) {
2990     // probably only 'pop ecx' was used
2991     *adj = adj_best;
2992     return first_pop;
2993   }
2994
2995   return -1;
2996 }
2997
2998 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
2999 {
3000   struct parsed_op *po;
3001   int j;
3002
3003   if (i < 0)
3004     ferr(ops, "%s: followed bad branch?\n", __func__);
3005
3006   for (; i < opcnt; i++) {
3007     po = &ops[i];
3008     if (po->cc_scratch == magic)
3009       return;
3010     po->cc_scratch = magic;
3011     po->flags |= flags;
3012
3013     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3014       if (po->btj != NULL) {
3015         // jumptable
3016         for (j = 0; j < po->btj->count; j++)
3017           scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3018         return;
3019       }
3020
3021       scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3022       if (!(po->flags & OPF_CJMP))
3023         return;
3024     }
3025     if (po->flags & OPF_TAIL)
3026       return;
3027   }
3028 }
3029
3030 static const struct parsed_proto *try_recover_pp(
3031   struct parsed_op *po, const struct parsed_opr *opr, int *search_instead)
3032 {
3033   const struct parsed_proto *pp = NULL;
3034   char buf[256];
3035   char *p;
3036
3037   // maybe an arg of g_func?
3038   if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3039   {
3040     char ofs_reg[16] = { 0, };
3041     int arg, arg_s, arg_i;
3042     int stack_ra = 0;
3043     int offset = 0;
3044
3045     if (g_header_mode)
3046       return NULL;
3047
3048     parse_stack_access(po, opr->name, ofs_reg,
3049       &offset, &stack_ra, NULL, 0);
3050     if (ofs_reg[0] != 0)
3051       ferr(po, "offset reg on arg access?\n");
3052     if (offset <= stack_ra) {
3053       // search who set the stack var instead
3054       if (search_instead != NULL)
3055         *search_instead = 1;
3056       return NULL;
3057     }
3058
3059     arg_i = (offset - stack_ra - 4) / 4;
3060     for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3061       if (g_func_pp->arg[arg].reg != NULL)
3062         continue;
3063       if (arg_s == arg_i)
3064         break;
3065       arg_s++;
3066     }
3067     if (arg == g_func_pp->argc)
3068       ferr(po, "stack arg %d not in prototype?\n", arg_i);
3069
3070     pp = g_func_pp->arg[arg].fptr;
3071     if (pp == NULL)
3072       ferr(po, "icall sa: arg%d is not a fptr?\n", arg + 1);
3073     check_func_pp(po, pp, "icall arg");
3074   }
3075   else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3076     // label[index]
3077     p = strchr(opr->name + 1, '[');
3078     memcpy(buf, opr->name, p - opr->name);
3079     buf[p - opr->name] = 0;
3080     pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3081   }
3082   else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3083     pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3084     if (pp == NULL) {
3085       if (!g_header_mode)
3086         ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3087     }
3088     else
3089       check_func_pp(po, pp, "reg-fptr ref");
3090   }
3091
3092   return pp;
3093 }
3094
3095 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3096   int magic, const struct parsed_proto **pp_found, int *pp_i,
3097   int *multi)
3098 {
3099   const struct parsed_proto *pp = NULL;
3100   struct parsed_op *po;
3101   struct label_ref *lr;
3102
3103   ops[i].cc_scratch = magic;
3104
3105   while (1) {
3106     if (g_labels[i] != NULL) {
3107       lr = &g_label_refs[i];
3108       for (; lr != NULL; lr = lr->next) {
3109         check_i(&ops[i], lr->i);
3110         scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3111       }
3112       if (i > 0 && LAST_OP(i - 1))
3113         return;
3114     }
3115
3116     i--;
3117     if (i < 0)
3118       break;
3119
3120     if (ops[i].cc_scratch == magic)
3121       return;
3122     ops[i].cc_scratch = magic;
3123
3124     if (!(ops[i].flags & OPF_DATA))
3125       continue;
3126     if (!is_opr_modified(opr, &ops[i]))
3127       continue;
3128     if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3129       // most probably trashed by some processing
3130       *pp_found = NULL;
3131       return;
3132     }
3133
3134     opr = &ops[i].operand[1];
3135     if (opr->type != OPT_REG)
3136       break;
3137   }
3138
3139   po = (i >= 0) ? &ops[i] : ops;
3140
3141   if (i < 0) {
3142     // reached the top - can only be an arg-reg
3143     if (opr->type != OPT_REG || g_func_pp == NULL)
3144       return;
3145
3146     for (i = 0; i < g_func_pp->argc; i++) {
3147       if (g_func_pp->arg[i].reg == NULL)
3148         continue;
3149       if (IS(opr->name, g_func_pp->arg[i].reg))
3150         break;
3151     }
3152     if (i == g_func_pp->argc)
3153       return;
3154     pp = g_func_pp->arg[i].fptr;
3155     if (pp == NULL)
3156       ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3157         i + 1, g_func_pp->arg[i].reg);
3158     check_func_pp(po, pp, "icall reg-arg");
3159   }
3160   else
3161     pp = try_recover_pp(po, opr, NULL);
3162
3163   if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3164     if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3165       || (*pp_found)->is_stdcall != pp->is_stdcall
3166       || (*pp_found)->is_fptr != pp->is_fptr
3167       || (*pp_found)->argc != pp->argc
3168       || (*pp_found)->argc_reg != pp->argc_reg
3169       || (*pp_found)->argc_stack != pp->argc_stack)
3170     {
3171       ferr(po, "icall: parsed_proto mismatch\n");
3172     }
3173     *multi = 1;
3174   }
3175   if (pp != NULL) {
3176     *pp_found = pp;
3177     *pp_i = po - ops;
3178   }
3179 }
3180
3181 static void add_label_ref(struct label_ref *lr, int op_i)
3182 {
3183   struct label_ref *lr_new;
3184
3185   if (lr->i == -1) {
3186     lr->i = op_i;
3187     return;
3188   }
3189
3190   lr_new = calloc(1, sizeof(*lr_new));
3191   lr_new->i = op_i;
3192   lr_new->next = lr->next;
3193   lr->next = lr_new;
3194 }
3195
3196 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3197 {
3198   struct parsed_op *po = &ops[i];
3199   struct parsed_data *pd;
3200   char label[NAMELEN], *p;
3201   int len, j, l;
3202
3203   p = strchr(po->operand[0].name, '[');
3204   if (p == NULL)
3205     return NULL;
3206
3207   len = p - po->operand[0].name;
3208   strncpy(label, po->operand[0].name, len);
3209   label[len] = 0;
3210
3211   for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3212     if (IS(g_func_pd[j].label, label)) {
3213       pd = &g_func_pd[j];
3214       break;
3215     }
3216   }
3217   if (pd == NULL)
3218     //ferr(po, "label '%s' not parsed?\n", label);
3219     return NULL;
3220
3221   if (pd->type != OPT_OFFSET)
3222     ferr(po, "label '%s' with non-offset data?\n", label);
3223
3224   // find all labels, link
3225   for (j = 0; j < pd->count; j++) {
3226     for (l = 0; l < opcnt; l++) {
3227       if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3228         add_label_ref(&g_label_refs[l], i);
3229         pd->d[j].bt_i = l;
3230         break;
3231       }
3232     }
3233   }
3234
3235   return pd;
3236 }
3237
3238 static void clear_labels(int count)
3239 {
3240   int i;
3241
3242   for (i = 0; i < count; i++) {
3243     if (g_labels[i] != NULL) {
3244       free(g_labels[i]);
3245       g_labels[i] = NULL;
3246     }
3247   }
3248 }
3249
3250 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3251 {
3252   int regmask = 0;
3253   int i, reg;
3254
3255   for (i = 0; i < pp->argc; i++) {
3256     if (pp->arg[i].reg != NULL) {
3257       reg = char_array_i(regs_r32,
3258               ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3259       if (reg < 0)
3260         ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3261           pp->arg[i].reg, pp->name);
3262       regmask |= 1 << reg;
3263     }
3264   }
3265
3266   return regmask;
3267 }
3268
3269 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3270 {
3271   if (strstr(pp->ret_type.name, "int64"))
3272     return (1 << xAX) | (1 << xDX);
3273   if (strcasecmp(pp->ret_type.name, "void") == 0)
3274     return 0;
3275
3276   return (1 << xAX);
3277 }
3278
3279 static void resolve_branches_parse_calls(int opcnt)
3280 {
3281   const struct parsed_proto *pp_c;
3282   struct parsed_proto *pp;
3283   struct parsed_data *pd;
3284   struct parsed_op *po;
3285   const char *tmpname;
3286   int i, l;
3287   int ret;
3288
3289   for (i = 0; i < opcnt; i++)
3290   {
3291     po = &ops[i];
3292     po->bt_i = -1;
3293     po->btj = NULL;
3294
3295     if (po->op == OP_CALL) {
3296       pp = NULL;
3297
3298       if (po->operand[0].type == OPT_LABEL) {
3299         tmpname = opr_name(po, 0);
3300         if (IS_START(tmpname, "loc_"))
3301           ferr(po, "call to loc_*\n");
3302         pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3303         if (!g_header_mode && pp_c == NULL)
3304           ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3305
3306         if (pp_c != NULL) {
3307           pp = proto_clone(pp_c);
3308           my_assert_not(pp, NULL);
3309         }
3310       }
3311       else if (po->datap != NULL) {
3312         pp = calloc(1, sizeof(*pp));
3313         my_assert_not(pp, NULL);
3314
3315         ret = parse_protostr(po->datap, pp);
3316         if (ret < 0)
3317           ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3318         free(po->datap);
3319         po->datap = NULL;
3320       }
3321
3322       if (pp != NULL) {
3323         if (pp->is_fptr)
3324           check_func_pp(po, pp, "fptr var call");
3325         if (pp->is_noreturn)
3326           po->flags |= OPF_TAIL;
3327       }
3328       po->pp = pp;
3329       continue;
3330     }
3331
3332     if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3333       continue;
3334
3335     if (po->operand[0].type == OPT_REGMEM) {
3336       pd = try_resolve_jumptab(i, opcnt);
3337       if (pd == NULL)
3338         goto tailcall;
3339
3340       po->btj = pd;
3341       continue;
3342     }
3343
3344     for (l = 0; l < opcnt; l++) {
3345       if (g_labels[l] != NULL
3346           && IS(po->operand[0].name, g_labels[l]))
3347       {
3348         if (l == i + 1 && po->op == OP_JMP) {
3349           // yet another alignment type..
3350           po->flags |= OPF_RMD|OPF_DONE;
3351           break;
3352         }
3353         add_label_ref(&g_label_refs[l], i);
3354         po->bt_i = l;
3355         break;
3356       }
3357     }
3358
3359     if (po->bt_i != -1 || (po->flags & OPF_RMD))
3360       continue;
3361
3362     if (po->operand[0].type == OPT_LABEL)
3363       // assume tail call
3364       goto tailcall;
3365
3366     ferr(po, "unhandled branch\n");
3367
3368 tailcall:
3369     po->op = OP_CALL;
3370     po->flags |= OPF_TAIL;
3371     if (i > 0 && ops[i - 1].op == OP_POP)
3372       po->flags |= OPF_ATAIL;
3373     i--; // reprocess
3374   }
3375 }
3376
3377 static void scan_prologue_epilogue(int opcnt)
3378 {
3379   int ecx_push = 0, esp_sub = 0;
3380   int found;
3381   int i, j, l;
3382
3383   if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3384       && ops[1].op == OP_MOV
3385       && IS(opr_name(&ops[1], 0), "ebp")
3386       && IS(opr_name(&ops[1], 1), "esp"))
3387   {
3388     g_bp_frame = 1;
3389     ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3390     ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3391     i = 2;
3392
3393     if (ops[2].op == OP_SUB && IS(opr_name(&ops[2], 0), "esp")) {
3394       g_stack_fsz = opr_const(&ops[2], 1);
3395       ops[2].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3396       i++;
3397     }
3398     else {
3399       // another way msvc builds stack frame..
3400       i = 2;
3401       while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3402         g_stack_fsz += 4;
3403         ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3404         ecx_push++;
3405         i++;
3406       }
3407       // and another way..
3408       if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3409           && ops[i].operand[1].type == OPT_CONST
3410           && ops[i + 1].op == OP_CALL
3411           && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3412       {
3413         g_stack_fsz += ops[i].operand[1].val;
3414         ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3415         i++;
3416         ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3417         i++;
3418       }
3419     }
3420
3421     found = 0;
3422     do {
3423       for (; i < opcnt; i++)
3424         if (ops[i].flags & OPF_TAIL)
3425           break;
3426       j = i - 1;
3427       if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3428         if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3429           break;
3430         i--;
3431         j--;
3432       }
3433
3434       if ((ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3435           || ops[j].op == OP_LEAVE)
3436       {
3437         ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3438       }
3439       else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3440         && ops[i].pp->is_noreturn)
3441       {
3442         // on noreturn, msvc sometimes cleans stack, sometimes not
3443         i++;
3444         found = 1;
3445         continue;
3446       }
3447       else if (!(g_ida_func_attr & IDAFA_NORETURN))
3448         ferr(&ops[j], "'pop ebp' expected\n");
3449
3450       if (g_stack_fsz != 0) {
3451         if (ops[j].op == OP_LEAVE)
3452           j--;
3453         else if (ops[j].op == OP_POP
3454             && ops[j - 1].op == OP_MOV
3455             && IS(opr_name(&ops[j - 1], 0), "esp")
3456             && IS(opr_name(&ops[j - 1], 1), "ebp"))
3457         {
3458           ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3459           j -= 2;
3460         }
3461         else if (!(g_ida_func_attr & IDAFA_NORETURN))
3462         {
3463           ferr(&ops[j], "esp restore expected\n");
3464         }
3465
3466         if (ecx_push && j >= 0 && ops[j].op == OP_POP
3467           && IS(opr_name(&ops[j], 0), "ecx"))
3468         {
3469           ferr(&ops[j], "unexpected ecx pop\n");
3470         }
3471       }
3472
3473       found = 1;
3474       i++;
3475     } while (i < opcnt);
3476
3477     if (!found)
3478       ferr(ops, "missing ebp epilogue\n");
3479     return;
3480   }
3481
3482   // non-bp frame
3483   i = 0;
3484   while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3485     ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3486     g_stack_fsz += 4;
3487     ecx_push++;
3488     i++;
3489   }
3490
3491   for (; i < opcnt; i++) {
3492     if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3493       break;
3494     if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3495       && ops[i].operand[1].type == OPT_CONST)
3496     {
3497       g_stack_fsz = ops[i].operand[1].val;
3498       ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3499       esp_sub = 1;
3500       break;
3501     }
3502   }
3503
3504   if (ecx_push && !esp_sub) {
3505     // could actually be args for a call..
3506     for (; i < opcnt; i++)
3507       if (ops[i].op != OP_PUSH)
3508         break;
3509
3510     if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3511       const struct parsed_proto *pp;
3512       pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3513       j = pp ? pp->argc_stack : 0;
3514       while (i > 0 && j > 0) {
3515         i--;
3516         if (ops[i].op == OP_PUSH) {
3517           ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
3518           j--;
3519         }
3520       }
3521       if (j != 0)
3522         ferr(&ops[i], "unhandled prologue\n");
3523
3524       // recheck
3525       i = g_stack_fsz = ecx_push = 0;
3526       while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3527         if (!(ops[i].flags & OPF_RMD))
3528           break;
3529         g_stack_fsz += 4;
3530         ecx_push++;
3531         i++;
3532       }
3533     }
3534   }
3535
3536   found = 0;
3537   if (ecx_push || esp_sub)
3538   {
3539     g_sp_frame = 1;
3540
3541     i++;
3542     do {
3543       for (; i < opcnt; i++)
3544         if (ops[i].flags & OPF_TAIL)
3545           break;
3546       j = i - 1;
3547       if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3548         if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3549           break;
3550         i--;
3551         j--;
3552       }
3553
3554       if (ecx_push > 0) {
3555         for (l = 0; l < ecx_push; l++) {
3556           if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
3557             /* pop ecx */;
3558           else if (ops[j].op == OP_ADD
3559                    && IS(opr_name(&ops[j], 0), "esp")
3560                    && ops[j].operand[1].type == OPT_CONST)
3561           {
3562             /* add esp, N */
3563             l += ops[j].operand[1].val / 4 - 1;
3564           }
3565           else
3566             ferr(&ops[j], "'pop ecx' expected\n");
3567
3568           ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3569           j--;
3570         }
3571         if (l != ecx_push)
3572           ferr(&ops[j], "epilogue scan failed\n");
3573
3574         found = 1;
3575       }
3576
3577       if (esp_sub) {
3578         if (ops[j].op != OP_ADD
3579             || !IS(opr_name(&ops[j], 0), "esp")
3580             || ops[j].operand[1].type != OPT_CONST
3581             || ops[j].operand[1].val != g_stack_fsz)
3582           ferr(&ops[j], "'add esp' expected\n");
3583
3584         ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3585         ops[j].operand[1].val = 0; // hack for stack arg scanner
3586         found = 1;
3587       }
3588
3589       i++;
3590     } while (i < opcnt);
3591
3592     if (!found)
3593       ferr(ops, "missing esp epilogue\n");
3594   }
3595 }
3596
3597 static const struct parsed_proto *resolve_icall(int i, int opcnt,
3598   int *pp_i, int *multi_src)
3599 {
3600   const struct parsed_proto *pp = NULL;
3601   int search_advice = 0;
3602
3603   *multi_src = 0;
3604   *pp_i = -1;
3605
3606   switch (ops[i].operand[0].type) {
3607   case OPT_REGMEM:
3608   case OPT_LABEL:
3609   case OPT_OFFSET:
3610     pp = try_recover_pp(&ops[i], &ops[i].operand[0], &search_advice);
3611     if (!search_advice)
3612       break;
3613     // fallthrough
3614   default:
3615     scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
3616       pp_i, multi_src);
3617     break;
3618   }
3619
3620   return pp;
3621 }
3622
3623 // find an instruction that changed opr before i op
3624 // *op_i must be set to -1 by the caller
3625 // *entry is set to 1 if one source is determined to be the caller
3626 // returns 1 if found, *op_i is then set to origin
3627 static int resolve_origin(int i, const struct parsed_opr *opr,
3628   int magic, int *op_i, int *is_caller)
3629 {
3630   struct label_ref *lr;
3631   int ret = 0;
3632
3633   if (ops[i].cc_scratch == magic)
3634     return 0;
3635   ops[i].cc_scratch = magic;
3636
3637   while (1) {
3638     if (g_labels[i] != NULL) {
3639       lr = &g_label_refs[i];
3640       for (; lr != NULL; lr = lr->next) {
3641         check_i(&ops[i], lr->i);
3642         ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
3643       }
3644       if (i > 0 && LAST_OP(i - 1))
3645         return ret;
3646     }
3647
3648     i--;
3649     if (i < 0) {
3650       if (is_caller != NULL)
3651         *is_caller = 1;
3652       return -1;
3653     }
3654
3655     if (ops[i].cc_scratch == magic)
3656       return ret;
3657     ops[i].cc_scratch = magic;
3658
3659     if (!(ops[i].flags & OPF_DATA))
3660       continue;
3661     if (!is_opr_modified(opr, &ops[i]))
3662       continue;
3663
3664     if (*op_i >= 0) {
3665       if (*op_i == i)
3666         return ret | 1;
3667
3668       // XXX: could check if the other op does the same
3669       return -1;
3670     }
3671
3672     *op_i = i;
3673     return ret | 1;
3674   }
3675 }
3676
3677 // find an instruction that previously referenced opr
3678 // if multiple results are found - fail
3679 // *op_i must be set to -1 by the caller
3680 // returns 1 if found, *op_i is then set to referencer insn
3681 static int resolve_last_ref(int i, const struct parsed_opr *opr,
3682   int magic, int *op_i)
3683 {
3684   struct label_ref *lr;
3685   int ret = 0;
3686
3687   if (ops[i].cc_scratch == magic)
3688     return 0;
3689   ops[i].cc_scratch = magic;
3690
3691   while (1) {
3692     if (g_labels[i] != NULL) {
3693       lr = &g_label_refs[i];
3694       for (; lr != NULL; lr = lr->next) {
3695         check_i(&ops[i], lr->i);
3696         ret |= resolve_last_ref(lr->i, opr, magic, op_i);
3697       }
3698       if (i > 0 && LAST_OP(i - 1))
3699         return ret;
3700     }
3701
3702     i--;
3703     if (i < 0)
3704       return -1;
3705
3706     if (ops[i].cc_scratch == magic)
3707       return 0;
3708     ops[i].cc_scratch = magic;
3709
3710     if (!is_opr_referenced(opr, &ops[i]))
3711       continue;
3712
3713     if (*op_i >= 0)
3714       return -1;
3715
3716     *op_i = i;
3717     return 1;
3718   }
3719 }
3720
3721 // find next instruction that reads opr
3722 // *op_i must be set to -1 by the caller
3723 // on return, *op_i is set to first referencer insn
3724 // returns 1 if exactly 1 referencer is found
3725 static int find_next_read(int i, int opcnt,
3726   const struct parsed_opr *opr, int magic, int *op_i)
3727 {
3728   struct parsed_op *po;
3729   int j, ret = 0;
3730
3731   for (; i < opcnt; i++)
3732   {
3733     if (ops[i].cc_scratch == magic)
3734       return ret;
3735     ops[i].cc_scratch = magic;
3736
3737     po = &ops[i];
3738     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3739       if (po->btj != NULL) {
3740         // jumptable
3741         for (j = 0; j < po->btj->count; j++) {
3742           check_i(po, po->btj->d[j].bt_i);
3743           ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
3744                    magic, op_i);
3745         }
3746         return ret;
3747       }
3748
3749       if (po->flags & OPF_RMD)
3750         continue;
3751       check_i(po, po->bt_i);
3752       if (po->flags & OPF_CJMP) {
3753         ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
3754         if (ret < 0)
3755           return ret;
3756       }
3757       else
3758         i = po->bt_i - 1;
3759       continue;
3760     }
3761
3762     if (!is_opr_read(opr, po)) {
3763       if (is_opr_modified(opr, po)
3764         && (po->op == OP_CALL
3765          || ((po->flags & OPF_DATA)
3766            && po->operand[0].lmod == OPLM_DWORD)))
3767       {
3768         // it's overwritten
3769         return ret;
3770       }
3771       if (po->flags & OPF_TAIL)
3772         return ret;
3773       continue;
3774     }
3775
3776     if (*op_i >= 0)
3777       return -1;
3778
3779     *op_i = i;
3780     return 1;
3781   }
3782
3783   return 0;
3784 }
3785
3786 static int try_resolve_const(int i, const struct parsed_opr *opr,
3787   int magic, unsigned int *val)
3788 {
3789   int s_i = -1;
3790   int ret;
3791
3792   ret = resolve_origin(i, opr, magic, &s_i, NULL);
3793   if (ret == 1) {
3794     i = s_i;
3795     if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
3796       return -1;
3797
3798     *val = ops[i].operand[1].val;
3799     return 1;
3800   }
3801
3802   return -1;
3803 }
3804
3805 static struct parsed_proto *process_call_early(int i, int opcnt,
3806   int *adj_i)
3807 {
3808   struct parsed_op *po = &ops[i];
3809   struct parsed_proto *pp;
3810   int multipath = 0;
3811   int adj = 0;
3812   int j, ret;
3813
3814   pp = po->pp;
3815   if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
3816     // leave for later
3817     return NULL;
3818
3819   // look for and make use of esp adjust
3820   *adj_i = ret = -1;
3821   if (!pp->is_stdcall && pp->argc_stack > 0)
3822     ret = scan_for_esp_adjust(i + 1, opcnt,
3823             pp->argc_stack * 4, &adj, &multipath, 0);
3824   if (ret >= 0) {
3825     if (pp->argc_stack > adj / 4)
3826       return NULL;
3827     if (multipath)
3828       return NULL;
3829     if (ops[ret].op == OP_POP) {
3830       for (j = 1; j < adj / 4; j++) {
3831         if (ops[ret + j].op != OP_POP
3832           || ops[ret + j].operand[0].reg != xCX)
3833         {
3834           return NULL;
3835         }
3836       }
3837     }
3838   }
3839
3840   *adj_i = ret;
3841   return pp;
3842 }
3843
3844 static struct parsed_proto *process_call(int i, int opcnt)
3845 {
3846   struct parsed_op *po = &ops[i];
3847   const struct parsed_proto *pp_c;
3848   struct parsed_proto *pp;
3849   const char *tmpname;
3850   int call_i = -1, ref_i = -1;
3851   int adj = 0, multipath = 0;
3852   int ret, arg;
3853
3854   tmpname = opr_name(po, 0);
3855   pp = po->pp;
3856   if (pp == NULL)
3857   {
3858     // indirect call
3859     pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
3860     if (pp_c != NULL) {
3861       if (!pp_c->is_func && !pp_c->is_fptr)
3862         ferr(po, "call to non-func: %s\n", pp_c->name);
3863       pp = proto_clone(pp_c);
3864       my_assert_not(pp, NULL);
3865       if (multipath)
3866         // not resolved just to single func
3867         pp->is_fptr = 1;
3868
3869       switch (po->operand[0].type) {
3870       case OPT_REG:
3871         // we resolved this call and no longer need the register
3872         po->regmask_src &= ~(1 << po->operand[0].reg);
3873
3874         if (!multipath && i != call_i && ops[call_i].op == OP_MOV
3875           && ops[call_i].operand[1].type == OPT_LABEL)
3876         {
3877           // no other source users?
3878           ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
3879                   &ref_i);
3880           if (ret == 1 && call_i == ref_i) {
3881             // and nothing uses it after us?
3882             ref_i = -1;
3883             find_next_read(i + 1, opcnt, &po->operand[0],
3884               i + opcnt * 11, &ref_i);
3885             if (ref_i == -1)
3886               // then also don't need the source mov
3887               ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
3888           }
3889         }
3890         break;
3891       case OPT_REGMEM:
3892         pp->is_fptr = 1;
3893         break;
3894       default:
3895         break;
3896       }
3897     }
3898     if (pp == NULL) {
3899       pp = calloc(1, sizeof(*pp));
3900       my_assert_not(pp, NULL);
3901
3902       pp->is_fptr = 1;
3903       ret = scan_for_esp_adjust(i + 1, opcnt,
3904               -1, &adj, &multipath, 0);
3905       if (ret < 0 || adj < 0) {
3906         if (!g_allow_regfunc)
3907           ferr(po, "non-__cdecl indirect call unhandled yet\n");
3908         pp->is_unresolved = 1;
3909         adj = 0;
3910       }
3911       adj /= 4;
3912       if (adj > ARRAY_SIZE(pp->arg))
3913         ferr(po, "esp adjust too large: %d\n", adj);
3914       pp->ret_type.name = strdup("int");
3915       pp->argc = pp->argc_stack = adj;
3916       for (arg = 0; arg < pp->argc; arg++)
3917         pp->arg[arg].type.name = strdup("int");
3918     }
3919     po->pp = pp;
3920   }
3921
3922   // look for and make use of esp adjust
3923   multipath = 0;
3924   ret = -1;
3925   if (!pp->is_stdcall && pp->argc_stack > 0) {
3926     int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
3927     ret = scan_for_esp_adjust(i + 1, opcnt,
3928             adj_expect, &adj, &multipath, 0);
3929   }
3930   if (ret >= 0) {
3931     if (pp->is_vararg) {
3932       if (adj / 4 < pp->argc_stack) {
3933         fnote(po, "(this call)\n");
3934         ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
3935           adj, pp->argc_stack * 4);
3936       }
3937       // modify pp to make it have varargs as normal args
3938       arg = pp->argc;
3939       pp->argc += adj / 4 - pp->argc_stack;
3940       for (; arg < pp->argc; arg++) {
3941         pp->arg[arg].type.name = strdup("int");
3942         pp->argc_stack++;
3943       }
3944       if (pp->argc > ARRAY_SIZE(pp->arg))
3945         ferr(po, "too many args for '%s'\n", tmpname);
3946     }
3947     if (pp->argc_stack > adj / 4) {
3948       fnote(po, "(this call)\n");
3949       ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
3950         tmpname, pp->argc_stack * 4, adj);
3951     }
3952
3953     scan_for_esp_adjust(i + 1, opcnt,
3954       pp->argc_stack * 4, &adj, &multipath, 1);
3955   }
3956   else if (pp->is_vararg)
3957     ferr(po, "missing esp_adjust for vararg func '%s'\n",
3958       pp->name);
3959
3960   return pp;
3961 }
3962
3963 static int collect_call_args_early(struct parsed_op *po, int i,
3964   struct parsed_proto *pp, int *regmask)
3965 {
3966   int arg, ret;
3967   int j;
3968
3969   for (arg = 0; arg < pp->argc; arg++)
3970     if (pp->arg[arg].reg == NULL)
3971       break;
3972
3973   // first see if it can be easily done
3974   for (j = i; j > 0 && arg < pp->argc; )
3975   {
3976     if (g_labels[j] != NULL)
3977       return -1;
3978     j--;
3979
3980     if (ops[j].op == OP_CALL)
3981       return -1;
3982     else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP)
3983       return -1;
3984     else if (ops[j].op == OP_POP)
3985       return -1;
3986     else if (ops[j].flags & OPF_CJMP)
3987       return -1;
3988     else if (ops[j].op == OP_PUSH) {
3989       if (ops[j].flags & (OPF_FARG|OPF_FARGNR))
3990         return -1;
3991       ret = scan_for_mod(&ops[j], j + 1, i, 1);
3992       if (ret >= 0)
3993         return -1;
3994
3995       if (pp->arg[arg].type.is_va_list)
3996         return -1;
3997
3998       // next arg
3999       for (arg++; arg < pp->argc; arg++)
4000         if (pp->arg[arg].reg == NULL)
4001           break;
4002     }
4003   }
4004
4005   if (arg < pp->argc)
4006     return -1;
4007
4008   // now do it
4009   for (arg = 0; arg < pp->argc; arg++)
4010     if (pp->arg[arg].reg == NULL)
4011       break;
4012
4013   for (j = i; j > 0 && arg < pp->argc; )
4014   {
4015     j--;
4016
4017     if (ops[j].op == OP_PUSH)
4018     {
4019       ops[j].p_argnext = -1;
4020       ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4021       pp->arg[arg].datap = &ops[j];
4022
4023       if (ops[j].operand[0].type == OPT_REG)
4024         *regmask |= 1 << ops[j].operand[0].reg;
4025
4026       ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4027       ops[j].flags &= ~OPF_RSAVE;
4028
4029       // next arg
4030       for (arg++; arg < pp->argc; arg++)
4031         if (pp->arg[arg].reg == NULL)
4032           break;
4033     }
4034   }
4035
4036   return 0;
4037 }
4038
4039 static int collect_call_args_r(struct parsed_op *po, int i,
4040   struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4041   int *arg_grp, int arg, int magic, int need_op_saving, int may_reuse)
4042 {
4043   struct parsed_proto *pp_tmp;
4044   struct parsed_op *po_tmp;
4045   struct label_ref *lr;
4046   int need_to_save_current;
4047   int arg_grp_current = 0;
4048   int save_args_seen = 0;
4049   int save_args;
4050   int ret = 0;
4051   int reg;
4052   char buf[32];
4053   int j, k;
4054
4055   if (i < 0) {
4056     ferr(po, "dead label encountered\n");
4057     return -1;
4058   }
4059
4060   for (; arg < pp->argc; arg++)
4061     if (pp->arg[arg].reg == NULL)
4062       break;
4063   magic = (magic & 0xffffff) | (arg << 24);
4064
4065   for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4066   {
4067     if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4068       if (ops[j].cc_scratch != magic) {
4069         ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4070            pp->name);
4071         return -1;
4072       }
4073       // ok: have already been here
4074       return 0;
4075     }
4076     ops[j].cc_scratch = magic;
4077
4078     if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4079       lr = &g_label_refs[j];
4080       if (lr->next != NULL)
4081         need_op_saving = 1;
4082       for (; lr->next; lr = lr->next) {
4083         check_i(&ops[j], lr->i);
4084         if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4085           may_reuse = 1;
4086         ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4087                 arg_grp, arg, magic, need_op_saving, may_reuse);
4088         if (ret < 0)
4089           return ret;
4090       }
4091
4092       check_i(&ops[j], lr->i);
4093       if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4094         may_reuse = 1;
4095       if (j > 0 && LAST_OP(j - 1)) {
4096         // follow last branch in reverse
4097         j = lr->i;
4098         continue;
4099       }
4100       need_op_saving = 1;
4101       ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4102                arg_grp, arg, magic, need_op_saving, may_reuse);
4103       if (ret < 0)
4104         return ret;
4105     }
4106     j--;
4107
4108     if (ops[j].op == OP_CALL)
4109     {
4110       if (pp->is_unresolved)
4111         break;
4112
4113       pp_tmp = ops[j].pp;
4114       if (pp_tmp == NULL)
4115         ferr(po, "arg collect hit unparsed call '%s'\n",
4116           ops[j].operand[0].name);
4117       if (may_reuse && pp_tmp->argc_stack > 0)
4118         ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4119           arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4120     }
4121     // esp adjust of 0 means we collected it before
4122     else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4123       && (ops[j].operand[1].type != OPT_CONST
4124           || ops[j].operand[1].val != 0))
4125     {
4126       if (pp->is_unresolved)
4127         break;
4128
4129       fnote(po, "(this call)\n");
4130       ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4131         arg, pp->argc, ops[j].operand[1].val);
4132     }
4133     else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4134     {
4135       if (pp->is_unresolved)
4136         break;
4137
4138       fnote(po, "(this call)\n");
4139       ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4140     }
4141     else if (ops[j].flags & OPF_CJMP)
4142     {
4143       if (pp->is_unresolved)
4144         break;
4145
4146       may_reuse = 1;
4147     }
4148     else if (ops[j].op == OP_PUSH
4149       && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4150     {
4151       if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4152         break;
4153
4154       ops[j].p_argnext = -1;
4155       po_tmp = pp->arg[arg].datap;
4156       if (po_tmp != NULL)
4157         ops[j].p_argnext = po_tmp - ops;
4158       pp->arg[arg].datap = &ops[j];
4159
4160       need_to_save_current = 0;
4161       save_args = 0;
4162       reg = -1;
4163       if (ops[j].operand[0].type == OPT_REG)
4164         reg = ops[j].operand[0].reg;
4165
4166       if (!need_op_saving) {
4167         ret = scan_for_mod(&ops[j], j + 1, i, 1);
4168         need_to_save_current = (ret >= 0);
4169       }
4170       if (need_op_saving || need_to_save_current) {
4171         // mark this push as one that needs operand saving
4172         ops[j].flags &= ~OPF_RMD;
4173         if (ops[j].p_argnum == 0) {
4174           ops[j].p_argnum = arg + 1;
4175           save_args |= 1 << arg;
4176         }
4177         else if (ops[j].p_argnum < arg + 1) {
4178           // XXX: might kill valid var..
4179           //*save_arg_vars &= ~(1 << (ops[j].p_argnum - 1));
4180           ops[j].p_argnum = arg + 1;
4181           save_args |= 1 << arg;
4182         }
4183
4184         if (save_args_seen & (1 << (ops[j].p_argnum - 1))) {
4185           save_args_seen = 0;
4186           arg_grp_current++;
4187           if (arg_grp_current >= MAX_ARG_GRP)
4188             ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
4189               ops[j].p_argnum, pp->name);
4190         }
4191       }
4192       else if (ops[j].p_argnum == 0)
4193         ops[j].flags |= OPF_RMD;
4194
4195       // some PUSHes are reused by different calls on other branches,
4196       // but that can't happen if we didn't branch, so they
4197       // can be removed from future searches (handles nested calls)
4198       if (!may_reuse)
4199         ops[j].flags |= OPF_FARGNR;
4200
4201       ops[j].flags |= OPF_FARG;
4202       ops[j].flags &= ~OPF_RSAVE;
4203
4204       // check for __VALIST
4205       if (!pp->is_unresolved && g_func_pp != NULL
4206         && pp->arg[arg].type.is_va_list)
4207       {
4208         k = -1;
4209         ret = resolve_origin(j, &ops[j].operand[0],
4210                 magic + 1, &k, NULL);
4211         if (ret == 1 && k >= 0)
4212         {
4213           if (ops[k].op == OP_LEA) {
4214             if (!g_func_pp->is_vararg)
4215               ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
4216                    g_func_pp->name);
4217
4218             snprintf(buf, sizeof(buf), "arg_%X",
4219               g_func_pp->argc_stack * 4);
4220             if (strstr(ops[k].operand[1].name, buf)
4221              || strstr(ops[k].operand[1].name, "arglist"))
4222             {
4223               ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
4224               ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
4225               save_args &= ~(1 << arg);
4226               reg = -1;
4227             }
4228             else
4229               ferr(&ops[k], "va_list arg detection failed\n");
4230           }
4231           // check for va_list from g_func_pp arg too
4232           else if (ops[k].op == OP_MOV
4233             && is_stack_access(&ops[k], &ops[k].operand[1]))
4234           {
4235             ret = stack_frame_access(&ops[k], &ops[k].operand[1],
4236               buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
4237             if (ret >= 0) {
4238               ops[k].flags |= OPF_RMD | OPF_DONE;
4239               ops[j].flags |= OPF_RMD;
4240               ops[j].p_argpass = ret + 1;
4241               save_args &= ~(1 << arg);
4242               reg = -1;
4243             }
4244           }
4245         }
4246       }
4247
4248       *save_arg_vars |= save_args;
4249
4250       // tracking reg usage
4251       if (reg >= 0)
4252         *regmask |= 1 << reg;
4253
4254       arg++;
4255       if (!pp->is_unresolved) {
4256         // next arg
4257         for (; arg < pp->argc; arg++)
4258           if (pp->arg[arg].reg == NULL)
4259             break;
4260       }
4261       magic = (magic & 0xffffff) | (arg << 24);
4262     }
4263
4264     if (ops[j].p_arggrp > arg_grp_current) {
4265       save_args_seen = 0;
4266       arg_grp_current = ops[j].p_arggrp;
4267     }
4268     if (ops[j].p_argnum > 0)
4269       save_args_seen |= 1 << (ops[j].p_argnum - 1);
4270   }
4271
4272   if (arg < pp->argc) {
4273     ferr(po, "arg collect failed for '%s': %d/%d\n",
4274       pp->name, arg, pp->argc);
4275     return -1;
4276   }
4277
4278   if (arg_grp_current > *arg_grp)
4279     *arg_grp = arg_grp_current;
4280
4281   return arg;
4282 }
4283
4284 static int collect_call_args(struct parsed_op *po, int i,
4285   struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4286   int magic)
4287 {
4288   // arg group is for cases when pushes for
4289   // multiple funcs are going on
4290   struct parsed_op *po_tmp;
4291   int save_arg_vars_current = 0;
4292   int arg_grp = 0;
4293   int ret;
4294   int a;
4295
4296   ret = collect_call_args_r(po, i, pp, regmask,
4297           &save_arg_vars_current, &arg_grp, 0, magic, 0, 0);
4298   if (ret < 0)
4299     return ret;
4300
4301   if (arg_grp != 0) {
4302     // propagate arg_grp
4303     for (a = 0; a < pp->argc; a++) {
4304       if (pp->arg[a].reg != NULL)
4305         continue;
4306
4307       po_tmp = pp->arg[a].datap;
4308       while (po_tmp != NULL) {
4309         po_tmp->p_arggrp = arg_grp;
4310         if (po_tmp->p_argnext > 0)
4311           po_tmp = &ops[po_tmp->p_argnext];
4312         else
4313           po_tmp = NULL;
4314       }
4315     }
4316   }
4317   save_arg_vars[arg_grp] |= save_arg_vars_current;
4318
4319   if (pp->is_unresolved) {
4320     pp->argc += ret;
4321     pp->argc_stack += ret;
4322     for (a = 0; a < pp->argc; a++)
4323       if (pp->arg[a].type.name == NULL)
4324         pp->arg[a].type.name = strdup("int");
4325   }
4326
4327   return ret;
4328 }
4329
4330 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
4331   int regmask_now, int *regmask,
4332   int regmask_save_now, int *regmask_save,
4333   int *regmask_init, int regmask_arg)
4334 {
4335   struct parsed_op *po;
4336   int already_saved;
4337   int regmask_new;
4338   int regmask_op;
4339   int flags_set;
4340   int ret, reg;
4341   int j;
4342
4343   for (; i < opcnt; i++)
4344   {
4345     po = &ops[i];
4346     if (cbits[i >> 3] & (1 << (i & 7)))
4347       return;
4348     cbits[i >> 3] |= (1 << (i & 7));
4349
4350     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4351       if (po->flags & (OPF_RMD|OPF_DONE))
4352         continue;
4353       if (po->btj != NULL) {
4354         for (j = 0; j < po->btj->count; j++) {
4355           check_i(po, po->btj->d[j].bt_i);
4356           reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
4357             regmask_now, regmask, regmask_save_now, regmask_save,
4358             regmask_init, regmask_arg);
4359         }
4360         return;
4361       }
4362
4363       check_i(po, po->bt_i);
4364       if (po->flags & OPF_CJMP)
4365         reg_use_pass(po->bt_i, opcnt, cbits,
4366           regmask_now, regmask, regmask_save_now, regmask_save,
4367           regmask_init, regmask_arg);
4368       else
4369         i = po->bt_i - 1;
4370       continue;
4371     }
4372
4373     if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
4374       && !g_func_pp->is_userstack
4375       && po->operand[0].type == OPT_REG)
4376     {
4377       reg = po->operand[0].reg;
4378       ferr_assert(po, reg >= 0);
4379
4380       already_saved = 0;
4381       flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
4382       if (regmask_now & (1 << reg)) {
4383         already_saved = regmask_save_now & (1 << reg);
4384         flags_set = OPF_RSAVE | OPF_DONE;
4385       }
4386
4387       ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0);
4388       if (ret == 1) {
4389         scan_for_pop(i + 1, opcnt, i + opcnt * 4, reg, 0, flags_set);
4390       }
4391       else {
4392         ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
4393         if (ret == 1) {
4394           scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
4395             flags_set);
4396         }
4397       }
4398       if (ret == 1) {
4399         ferr_assert(po, !already_saved);
4400         po->flags |= flags_set;
4401
4402         if (regmask_now & (1 << reg)) {
4403           regmask_save_now |= (1 << reg);
4404           *regmask_save |= regmask_save_now;
4405         }
4406         continue;
4407       }
4408     }
4409     else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
4410       reg = po->operand[0].reg;
4411       ferr_assert(po, reg >= 0);
4412
4413       if (regmask_save_now & (1 << reg))
4414         regmask_save_now &= ~(1 << reg);
4415       else
4416         regmask_now &= ~(1 << reg);
4417       continue;
4418     }
4419     else if (po->op == OP_CALL) {
4420       if ((po->regmask_dst & (1 << xAX))
4421         && !(po->regmask_dst & (1 << xDX)))
4422       {
4423         if (po->flags & OPF_TAIL)
4424           // don't need eax, will do "return f();" or "f(); return;"
4425           po->regmask_dst &= ~(1 << xAX);
4426         else {
4427           struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
4428           j = -1;
4429           find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
4430           if (j == -1)
4431             // not used
4432             po->regmask_dst &= ~(1 << xAX);
4433         }
4434       }
4435     }
4436
4437     if (po->flags & OPF_NOREGS)
4438       continue;
4439
4440     // if incomplete register is used, clear it on init to avoid
4441     // later use of uninitialized upper part in some situations
4442     if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
4443         && po->operand[0].lmod != OPLM_DWORD)
4444     {
4445       reg = po->operand[0].reg;
4446       ferr_assert(po, reg >= 0);
4447
4448       if (!(regmask_now & (1 << reg)))
4449         *regmask_init |= 1 << reg;
4450     }
4451
4452     regmask_op = po->regmask_src | po->regmask_dst;
4453
4454     regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
4455     regmask_new &= ~(1 << xSP);
4456     if (g_bp_frame && !(po->flags & OPF_EBP_S))
4457       regmask_new &= ~(1 << xBP);
4458
4459     if (po->op == OP_CALL) {
4460       // allow fastcall calls from anywhere, calee may be also sitting
4461       // in some fastcall table even when it's not using reg args
4462       if (regmask_new & po->regmask_src & (1 << xCX)) {
4463         *regmask_init |= (1 << xCX);
4464         regmask_now |= (1 << xCX);
4465         regmask_new &= ~(1 << xCX);
4466       }
4467       if (regmask_new & po->regmask_src & (1 << xDX)) {
4468         *regmask_init |= (1 << xDX);
4469         regmask_now |= (1 << xDX);
4470         regmask_new &= ~(1 << xDX);
4471       }
4472     }
4473
4474     if (regmask_new != 0)
4475       fnote(po, "uninitialized reg mask: %x\n", regmask_new);
4476
4477     if (regmask_op & (1 << xBP)) {
4478       if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
4479         if (po->regmask_dst & (1 << xBP))
4480           // compiler decided to drop bp frame and use ebp as scratch
4481           scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
4482         else
4483           regmask_op &= ~(1 << xBP);
4484       }
4485     }
4486
4487     regmask_now |= regmask_op;
4488     *regmask |= regmask_now;
4489
4490     if (po->flags & OPF_TAIL)
4491       return;
4492   }
4493 }
4494
4495 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
4496 {
4497   int i;
4498
4499   for (i = 0; i < pp->argc; i++)
4500     if (pp->arg[i].reg == NULL)
4501       break;
4502
4503   if (pp->argc_stack)
4504     memmove(&pp->arg[i + 1], &pp->arg[i],
4505       sizeof(pp->arg[0]) * pp->argc_stack);
4506   memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
4507   pp->arg[i].reg = strdup(reg);
4508   pp->arg[i].type.name = strdup("int");
4509   pp->argc++;
4510   pp->argc_reg++;
4511 }
4512
4513 static void output_std_flags(FILE *fout, struct parsed_op *po,
4514   int *pfomask, const char *dst_opr_text)
4515 {
4516   if (*pfomask & (1 << PFO_Z)) {
4517     fprintf(fout, "\n  cond_z = (%s%s == 0);",
4518       lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
4519     *pfomask &= ~(1 << PFO_Z);
4520   }
4521   if (*pfomask & (1 << PFO_S)) {
4522     fprintf(fout, "\n  cond_s = (%s%s < 0);",
4523       lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
4524     *pfomask &= ~(1 << PFO_S);
4525   }
4526 }
4527
4528 enum {
4529   OPP_FORCE_NORETURN = (1 << 0),
4530   OPP_SIMPLE_ARGS    = (1 << 1),
4531   OPP_ALIGN          = (1 << 2),
4532 };
4533
4534 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
4535   int flags)
4536 {
4537   const char *cconv = "";
4538
4539   if (pp->is_fastcall)
4540     cconv = "__fastcall ";
4541   else if (pp->is_stdcall && pp->argc_reg == 0)
4542     cconv = "__stdcall ";
4543
4544   fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
4545
4546   if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
4547     fprintf(fout, "noreturn ");
4548 }
4549
4550 static void output_pp(FILE *fout, const struct parsed_proto *pp,
4551   int flags)
4552 {
4553   int i;
4554
4555   fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
4556     pp->ret_type.name);
4557   if (pp->is_fptr)
4558     fprintf(fout, "(");
4559   output_pp_attrs(fout, pp, flags);
4560   if (pp->is_fptr)
4561     fprintf(fout, "*");
4562   fprintf(fout, "%s", pp->name);
4563   if (pp->is_fptr)
4564     fprintf(fout, ")");
4565
4566   fprintf(fout, "(");
4567   for (i = 0; i < pp->argc; i++) {
4568     if (i > 0)
4569       fprintf(fout, ", ");
4570     if (pp->arg[i].fptr != NULL && !(flags & OPP_SIMPLE_ARGS)) {
4571       // func pointer
4572       output_pp(fout, pp->arg[i].fptr, 0);
4573     }
4574     else if (pp->arg[i].type.is_retreg) {
4575       fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
4576     }
4577     else {
4578       fprintf(fout, "%s", pp->arg[i].type.name);
4579       if (!pp->is_fptr)
4580         fprintf(fout, " a%d", i + 1);
4581     }
4582   }
4583   if (pp->is_vararg) {
4584     if (i > 0)
4585       fprintf(fout, ", ");
4586     fprintf(fout, "...");
4587   }
4588   fprintf(fout, ")");
4589 }
4590
4591 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
4592 {
4593   char buf1[16];
4594
4595   buf1[0] = 0;
4596   if (grp > 0)
4597     snprintf(buf1, sizeof(buf1), "%d", grp);
4598   snprintf(buf, buf_size, "s%s_a%d", buf1, num);
4599
4600   return buf;
4601 }
4602
4603 static void gen_x_cleanup(int opcnt);
4604
4605 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
4606 {
4607   struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
4608   struct parsed_opr *last_arith_dst = NULL;
4609   char buf1[256], buf2[256], buf3[256], cast[64];
4610   struct parsed_proto *pp, *pp_tmp;
4611   struct parsed_data *pd;
4612   unsigned int uval;
4613   int save_arg_vars[MAX_ARG_GRP] = { 0, };
4614   unsigned char cbits[MAX_OPS / 8];
4615   int cond_vars = 0;
4616   int need_tmp_var = 0;
4617   int need_tmp64 = 0;
4618   int had_decl = 0;
4619   int label_pending = 0;
4620   int regmask_save = 0; // regs saved/restored in this func
4621   int regmask_arg;      // regs from this function args (fastcall, etc)
4622   int regmask_ret;      // regs needed on ret
4623   int regmask_now;      // temp
4624   int regmask_init = 0; // regs that need zero initialization
4625   int regmask_pp = 0;   // regs used in complex push-pop graph
4626   int regmask = 0;      // used regs
4627   int pfomask = 0;
4628   int found = 0;
4629   int no_output;
4630   int i, j, l;
4631   int arg;
4632   int reg;
4633   int ret;
4634
4635   g_bp_frame = g_sp_frame = g_stack_fsz = 0;
4636   g_stack_frame_used = 0;
4637
4638   g_func_pp = proto_parse(fhdr, funcn, 0);
4639   if (g_func_pp == NULL)
4640     ferr(ops, "proto_parse failed for '%s'\n", funcn);
4641
4642   regmask_arg = get_pp_arg_regmask_src(g_func_pp);
4643   regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
4644
4645   if (g_func_pp->has_retreg) {
4646     for (arg = 0; arg < g_func_pp->argc; arg++) {
4647       if (g_func_pp->arg[arg].type.is_retreg) {
4648         reg = char_array_i(regs_r32,
4649                 ARRAY_SIZE(regs_r32), g_func_pp->arg[arg].reg);
4650         ferr_assert(ops, reg >= 0);
4651         regmask_ret |= 1 << reg;
4652       }
4653     }
4654   }
4655
4656   // pass1:
4657   // - resolve all branches
4658   // - parse calls with labels
4659   resolve_branches_parse_calls(opcnt);
4660
4661   // pass2:
4662   // - handle ebp/esp frame, remove ops related to it
4663   scan_prologue_epilogue(opcnt);
4664
4665   // pass3:
4666   // - remove dead labels
4667   // - set regs needed at ret
4668   for (i = 0; i < opcnt; i++)
4669   {
4670     if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
4671       free(g_labels[i]);
4672       g_labels[i] = NULL;
4673     }
4674
4675     if (ops[i].op == OP_RET)
4676       ops[i].regmask_src |= regmask_ret;
4677   }
4678
4679   // pass4:
4680   // - process trivial calls
4681   for (i = 0; i < opcnt; i++)
4682   {
4683     po = &ops[i];
4684     if (po->flags & (OPF_RMD|OPF_DONE))
4685       continue;
4686
4687     if (po->op == OP_CALL)
4688     {
4689       pp = process_call_early(i, opcnt, &j);
4690       if (pp != NULL) {
4691         if (!(po->flags & OPF_ATAIL))
4692           // since we know the args, try to collect them
4693           if (collect_call_args_early(po, i, pp, &regmask) != 0)
4694             pp = NULL;
4695       }
4696
4697       if (pp != NULL) {
4698         if (j >= 0) {
4699           // commit esp adjust
4700           if (ops[j].op != OP_POP)
4701             patch_esp_adjust(&ops[j], pp->argc_stack * 4);
4702           else {
4703             for (l = 0; l < pp->argc_stack; l++)
4704               ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
4705           }
4706         }
4707
4708         if (strstr(pp->ret_type.name, "int64"))
4709           need_tmp64 = 1;
4710
4711         po->flags |= OPF_DONE;
4712       }
4713     }
4714   }
4715
4716   // pass5:
4717   // - process calls, stage 2
4718   // - handle some push/pop pairs
4719   // - scan for STD/CLD, propagate DF
4720   for (i = 0; i < opcnt; i++)
4721   {
4722     po = &ops[i];
4723     if (po->flags & OPF_RMD)
4724       continue;
4725
4726     if (po->op == OP_CALL)
4727     {
4728       if (!(po->flags & OPF_DONE)) {
4729         pp = process_call(i, opcnt);
4730
4731         if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
4732           // since we know the args, collect them
4733           collect_call_args(po, i, pp, &regmask, save_arg_vars,
4734             i + opcnt * 2);
4735         }
4736         // for unresolved, collect after other passes
4737       }
4738
4739       pp = po->pp;
4740       ferr_assert(po, pp != NULL);
4741
4742       po->regmask_src |= get_pp_arg_regmask_src(pp);
4743       po->regmask_dst |= get_pp_arg_regmask_dst(pp);
4744
4745       if (strstr(pp->ret_type.name, "int64"))
4746         need_tmp64 = 1;
4747
4748       continue;
4749     }
4750
4751     if (po->flags & OPF_DONE)
4752       continue;
4753
4754     if (po->op == OP_PUSH && !(po->flags & OPF_FARG)
4755       && !(po->flags & OPF_RSAVE) && po->operand[0].type == OPT_CONST)
4756     {
4757       scan_for_pop_const(i, opcnt, i + opcnt * 12);
4758     }
4759     else if (po->op == OP_POP)
4760       scan_pushes_for_pop(i, opcnt, &regmask_pp);
4761     else if (po->op == OP_STD) {
4762       po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
4763       scan_propagate_df(i + 1, opcnt);
4764     }
4765   }
4766
4767   // pass6:
4768   // - find POPs for PUSHes, rm both
4769   // - scan for all used registers
4770   memset(cbits, 0, sizeof(cbits));
4771   reg_use_pass(0, opcnt, cbits, 0, &regmask,
4772     0, &regmask_save, &regmask_init, regmask_arg);
4773
4774   // pass7:
4775   // - find flag set ops for their users
4776   // - do unresolved calls
4777   // - declare indirect functions
4778   for (i = 0; i < opcnt; i++)
4779   {
4780     po = &ops[i];
4781     if (po->flags & (OPF_RMD|OPF_DONE))
4782       continue;
4783
4784     if (po->flags & OPF_CC)
4785     {
4786       int setters[16], cnt = 0, branched = 0;
4787
4788       ret = scan_for_flag_set(i, i + opcnt * 6,
4789               &branched, setters, &cnt);
4790       if (ret < 0 || cnt <= 0)
4791         ferr(po, "unable to trace flag setter(s)\n");
4792       if (cnt > ARRAY_SIZE(setters))
4793         ferr(po, "too many flag setters\n");
4794
4795       for (j = 0; j < cnt; j++)
4796       {
4797         tmp_op = &ops[setters[j]]; // flag setter
4798         pfomask = 0;
4799
4800         // to get nicer code, we try to delay test and cmp;
4801         // if we can't because of operand modification, or if we
4802         // have arith op, or branch, make it calculate flags explicitly
4803         if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
4804         {
4805           if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
4806             pfomask = 1 << po->pfo;
4807         }
4808         else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
4809           pfomask = 1 << po->pfo;
4810         }
4811         else {
4812           // see if we'll be able to handle based on op result
4813           if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
4814                && po->pfo != PFO_Z && po->pfo != PFO_S
4815                && po->pfo != PFO_P)
4816               || branched
4817               || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
4818           {
4819             pfomask = 1 << po->pfo;
4820           }
4821
4822           if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
4823             propagate_lmod(tmp_op, &tmp_op->operand[0],
4824               &tmp_op->operand[1]);
4825             if (tmp_op->operand[0].lmod == OPLM_DWORD)
4826               need_tmp64 = 1;
4827           }
4828         }
4829         if (pfomask) {
4830           tmp_op->pfomask |= pfomask;
4831           cond_vars |= pfomask;
4832         }
4833         // note: may overwrite, currently not a problem
4834         po->datap = tmp_op;
4835       }
4836
4837       if (po->op == OP_RCL || po->op == OP_RCR
4838        || po->op == OP_ADC || po->op == OP_SBB)
4839         cond_vars |= 1 << PFO_C;
4840     }
4841
4842     if (po->op == OP_CMPS || po->op == OP_SCAS) {
4843       cond_vars |= 1 << PFO_Z;
4844     }
4845     else if (po->op == OP_MUL
4846       || (po->op == OP_IMUL && po->operand_cnt == 1))
4847     {
4848       if (po->operand[0].lmod == OPLM_DWORD)
4849         need_tmp64 = 1;
4850     }
4851     else if (po->op == OP_CALL) {
4852       // note: resolved non-reg calls are OPF_DONE already
4853       pp = po->pp;
4854       ferr_assert(po, pp != NULL);
4855
4856       if (pp->is_unresolved) {
4857         int regmask_stack = 0;
4858         collect_call_args(po, i, pp, &regmask, save_arg_vars,
4859           i + opcnt * 2);
4860
4861         // this is pretty rough guess:
4862         // see ecx and edx were pushed (and not their saved versions)
4863         for (arg = 0; arg < pp->argc; arg++) {
4864           if (pp->arg[arg].reg != NULL)
4865             continue;
4866
4867           tmp_op = pp->arg[arg].datap;
4868           if (tmp_op == NULL)
4869             ferr(po, "parsed_op missing for arg%d\n", arg);
4870           if (tmp_op->p_argnum == 0 && tmp_op->operand[0].type == OPT_REG)
4871             regmask_stack |= 1 << tmp_op->operand[0].reg;
4872         }
4873
4874         if (!((regmask_stack & (1 << xCX))
4875           && (regmask_stack & (1 << xDX))))
4876         {
4877           if (pp->argc_stack != 0
4878            || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
4879           {
4880             pp_insert_reg_arg(pp, "ecx");
4881             pp->is_fastcall = 1;
4882             regmask_init |= 1 << xCX;
4883             regmask |= 1 << xCX;
4884           }
4885           if (pp->argc_stack != 0
4886            || ((regmask | regmask_arg) & (1 << xDX)))
4887           {
4888             pp_insert_reg_arg(pp, "edx");
4889             regmask_init |= 1 << xDX;
4890             regmask |= 1 << xDX;
4891           }
4892         }
4893
4894         // note: __cdecl doesn't fall into is_unresolved category
4895         if (pp->argc_stack > 0)
4896           pp->is_stdcall = 1;
4897       }
4898     }
4899     else if (po->op == OP_MOV && po->operand[0].pp != NULL
4900       && po->operand[1].pp != NULL)
4901     {
4902       // <var> = offset <something>
4903       if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
4904         && !IS_START(po->operand[1].name, "off_"))
4905       {
4906         if (!po->operand[0].pp->is_fptr)
4907           ferr(po, "%s not declared as fptr when it should be\n",
4908             po->operand[0].name);
4909         if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
4910           pp_print(buf1, sizeof(buf1), po->operand[0].pp);
4911           pp_print(buf2, sizeof(buf2), po->operand[1].pp);
4912           fnote(po, "var:  %s\n", buf1);
4913           fnote(po, "func: %s\n", buf2);
4914           ferr(po, "^ mismatch\n");
4915         }
4916       }
4917     }
4918     else if (po->op == OP_DIV || po->op == OP_IDIV) {
4919       if (po->operand[0].lmod == OPLM_DWORD) {
4920         // 32bit division is common, look for it
4921         if (po->op == OP_DIV)
4922           ret = scan_for_reg_clear(i, xDX);
4923         else
4924           ret = scan_for_cdq_edx(i);
4925         if (ret >= 0)
4926           po->flags |= OPF_32BIT;
4927         else
4928           need_tmp64 = 1;
4929       }
4930       else
4931         need_tmp_var = 1;
4932     }
4933     else if (po->op == OP_CLD)
4934       po->flags |= OPF_RMD | OPF_DONE;
4935
4936     if (po->op == OP_RCL || po->op == OP_RCR || po->op == OP_XCHG)
4937       need_tmp_var = 1;
4938   }
4939
4940   // output starts here
4941
4942   // define userstack size
4943   if (g_func_pp->is_userstack) {
4944     fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
4945     fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
4946     fprintf(fout, "#endif\n");
4947   }
4948
4949   // the function itself
4950   ferr_assert(ops, !g_func_pp->is_fptr);
4951   output_pp(fout, g_func_pp,
4952     (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
4953   fprintf(fout, "\n{\n");
4954
4955   // declare indirect functions
4956   for (i = 0; i < opcnt; i++) {
4957     po = &ops[i];
4958     if (po->flags & OPF_RMD)
4959       continue;
4960
4961     if (po->op == OP_CALL) {
4962       pp = po->pp;
4963       if (pp == NULL)
4964         ferr(po, "NULL pp\n");
4965
4966       if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
4967         if (pp->name[0] != 0) {
4968           memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
4969           memcpy(pp->name, "i_", 2);
4970
4971           // might be declared already
4972           found = 0;
4973           for (j = 0; j < i; j++) {
4974             if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
4975               if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
4976                 found = 1;
4977                 break;
4978               }
4979             }
4980           }
4981           if (found)
4982             continue;
4983         }
4984         else
4985           snprintf(pp->name, sizeof(pp->name), "icall%d", i);
4986
4987         fprintf(fout, "  ");
4988         output_pp(fout, pp, OPP_SIMPLE_ARGS);
4989         fprintf(fout, ";\n");
4990       }
4991     }
4992   }
4993
4994   // output LUTs/jumptables
4995   for (i = 0; i < g_func_pd_cnt; i++) {
4996     pd = &g_func_pd[i];
4997     fprintf(fout, "  static const ");
4998     if (pd->type == OPT_OFFSET) {
4999       fprintf(fout, "void *jt_%s[] =\n    { ", pd->label);
5000
5001       for (j = 0; j < pd->count; j++) {
5002         if (j > 0)
5003           fprintf(fout, ", ");
5004         fprintf(fout, "&&%s", pd->d[j].u.label);
5005       }
5006     }
5007     else {
5008       fprintf(fout, "%s %s[] =\n    { ",
5009         lmod_type_u(ops, pd->lmod), pd->label);
5010
5011       for (j = 0; j < pd->count; j++) {
5012         if (j > 0)
5013           fprintf(fout, ", ");
5014         fprintf(fout, "%u", pd->d[j].u.val);
5015       }
5016     }
5017     fprintf(fout, " };\n");
5018     had_decl = 1;
5019   }
5020
5021   // declare stack frame, va_arg
5022   if (g_stack_fsz) {
5023     fprintf(fout, "  union { u32 d[%d]; u16 w[%d]; u8 b[%d]; } sf;\n",
5024       (g_stack_fsz + 3) / 4, (g_stack_fsz + 1) / 2, g_stack_fsz);
5025     had_decl = 1;
5026   }
5027
5028   if (g_func_pp->is_userstack) {
5029     fprintf(fout, "  u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5030     fprintf(fout, "  u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5031     had_decl = 1;
5032   }
5033
5034   if (g_func_pp->is_vararg) {
5035     fprintf(fout, "  va_list ap;\n");
5036     had_decl = 1;
5037   }
5038
5039   // declare arg-registers
5040   for (i = 0; i < g_func_pp->argc; i++) {
5041     if (g_func_pp->arg[i].reg != NULL) {
5042       reg = char_array_i(regs_r32,
5043               ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5044       if (regmask & (1 << reg)) {
5045         if (g_func_pp->arg[i].type.is_retreg)
5046           fprintf(fout, "  u32 %s = *r_%s;\n",
5047             g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5048         else
5049           fprintf(fout, "  u32 %s = (u32)a%d;\n",
5050             g_func_pp->arg[i].reg, i + 1);
5051       }
5052       else {
5053         if (g_func_pp->arg[i].type.is_retreg)
5054           ferr(ops, "retreg '%s' is unused?\n",
5055             g_func_pp->arg[i].reg);
5056         fprintf(fout, "  // %s = a%d; // unused\n",
5057           g_func_pp->arg[i].reg, i + 1);
5058       }
5059       had_decl = 1;
5060     }
5061   }
5062
5063   // declare normal registers
5064   regmask_now = regmask & ~regmask_arg;
5065   regmask_now &= ~(1 << xSP);
5066   if (regmask_now & 0x00ff) {
5067     for (reg = 0; reg < 8; reg++) {
5068       if (regmask_now & (1 << reg)) {
5069         fprintf(fout, "  u32 %s", regs_r32[reg]);
5070         if (regmask_init & (1 << reg))
5071           fprintf(fout, " = 0");
5072         fprintf(fout, ";\n");
5073         had_decl = 1;
5074       }
5075     }
5076   }
5077   if (regmask_now & 0xff00) {
5078     for (reg = 8; reg < 16; reg++) {
5079       if (regmask_now & (1 << reg)) {
5080         fprintf(fout, "  mmxr %s", regs_r32[reg]);
5081         if (regmask_init & (1 << reg))
5082           fprintf(fout, " = { 0, }");
5083         fprintf(fout, ";\n");
5084         had_decl = 1;
5085       }
5086     }
5087   }
5088
5089   if (regmask_save) {
5090     for (reg = 0; reg < 8; reg++) {
5091       if (regmask_save & (1 << reg)) {
5092         fprintf(fout, "  u32 s_%s;\n", regs_r32[reg]);
5093         had_decl = 1;
5094       }
5095     }
5096   }
5097
5098   for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
5099     if (save_arg_vars[i] == 0)
5100       continue;
5101     for (reg = 0; reg < 32; reg++) {
5102       if (save_arg_vars[i] & (1 << reg)) {
5103         fprintf(fout, "  u32 %s;\n",
5104           saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
5105         had_decl = 1;
5106       }
5107     }
5108   }
5109
5110   // declare push-pop temporaries
5111   if (regmask_pp) {
5112     for (reg = 0; reg < 8; reg++) {
5113       if (regmask_pp & (1 << reg)) {
5114         fprintf(fout, "  u32 pp_%s;\n", regs_r32[reg]);
5115         had_decl = 1;
5116       }
5117     }
5118   }
5119
5120   if (cond_vars) {
5121     for (i = 0; i < 8; i++) {
5122       if (cond_vars & (1 << i)) {
5123         fprintf(fout, "  u32 cond_%s;\n", parsed_flag_op_names[i]);
5124         had_decl = 1;
5125       }
5126     }
5127   }
5128
5129   if (need_tmp_var) {
5130     fprintf(fout, "  u32 tmp;\n");
5131     had_decl = 1;
5132   }
5133
5134   if (need_tmp64) {
5135     fprintf(fout, "  u64 tmp64;\n");
5136     had_decl = 1;
5137   }
5138
5139   if (had_decl)
5140     fprintf(fout, "\n");
5141
5142   if (g_func_pp->is_vararg) {
5143     if (g_func_pp->argc_stack == 0)
5144       ferr(ops, "vararg func without stack args?\n");
5145     fprintf(fout, "  va_start(ap, a%d);\n", g_func_pp->argc);
5146   }
5147
5148   // output ops
5149   for (i = 0; i < opcnt; i++)
5150   {
5151     if (g_labels[i] != NULL) {
5152       fprintf(fout, "\n%s:\n", g_labels[i]);
5153       label_pending = 1;
5154
5155       delayed_flag_op = NULL;
5156       last_arith_dst = NULL;
5157     }
5158
5159     po = &ops[i];
5160     if (po->flags & OPF_RMD)
5161       continue;
5162
5163     no_output = 0;
5164
5165     #define assert_operand_cnt(n_) \
5166       if (po->operand_cnt != n_) \
5167         ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
5168
5169     // conditional/flag using op?
5170     if (po->flags & OPF_CC)
5171     {
5172       int is_delayed = 0;
5173
5174       tmp_op = po->datap;
5175
5176       // we go through all this trouble to avoid using parsed_flag_op,
5177       // which makes generated code much nicer
5178       if (delayed_flag_op != NULL)
5179       {
5180         out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
5181           po->pfo, po->pfo_inv);
5182         is_delayed = 1;
5183       }
5184       else if (last_arith_dst != NULL
5185         && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
5186            || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
5187            ))
5188       {
5189         out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5190         out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
5191           last_arith_dst->lmod, buf3);
5192         is_delayed = 1;
5193       }
5194       else if (tmp_op != NULL) {
5195         // use preprocessed flag calc results
5196         if (!(tmp_op->pfomask & (1 << po->pfo)))
5197           ferr(po, "not prepared for pfo %d\n", po->pfo);
5198
5199         // note: pfo_inv was not yet applied
5200         snprintf(buf1, sizeof(buf1), "(%scond_%s)",
5201           po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
5202       }
5203       else {
5204         ferr(po, "all methods of finding comparison failed\n");
5205       }
5206  
5207       if (po->flags & OPF_JMP) {
5208         fprintf(fout, "  if %s", buf1);
5209       }
5210       else if (po->op == OP_RCL || po->op == OP_RCR
5211                || po->op == OP_ADC || po->op == OP_SBB)
5212       {
5213         if (is_delayed)
5214           fprintf(fout, "  cond_%s = %s;\n",
5215             parsed_flag_op_names[po->pfo], buf1);
5216       }
5217       else if (po->flags & OPF_DATA) { // SETcc
5218         out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
5219         fprintf(fout, "  %s = %s;", buf2, buf1);
5220       }
5221       else {
5222         ferr(po, "unhandled conditional op\n");
5223       }
5224     }
5225
5226     pfomask = po->pfomask;
5227
5228     if (po->flags & (OPF_REPZ|OPF_REPNZ)) {
5229       struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
5230       ret = try_resolve_const(i, &opr, opcnt * 7 + i, &uval);
5231
5232       if (ret != 1 || uval == 0) {
5233         // we need initial flags for ecx=0 case..
5234         if (i > 0 && ops[i - 1].op == OP_XOR
5235           && IS(ops[i - 1].operand[0].name,
5236                 ops[i - 1].operand[1].name))
5237         {
5238           fprintf(fout, "  cond_z = ");
5239           if (pfomask & (1 << PFO_C))
5240             fprintf(fout, "cond_c = ");
5241           fprintf(fout, "0;\n");
5242         }
5243         else if (last_arith_dst != NULL) {
5244           out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5245           out_test_for_cc(buf1, sizeof(buf1), po, PFO_Z, 0,
5246             last_arith_dst->lmod, buf3);
5247           fprintf(fout, "  cond_z = %s;\n", buf1);
5248         }
5249         else
5250           ferr(po, "missing initial ZF\n");
5251       }
5252     }
5253
5254     switch (po->op)
5255     {
5256       case OP_MOV:
5257         assert_operand_cnt(2);
5258         propagate_lmod(po, &po->operand[0], &po->operand[1]);
5259         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5260         default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
5261         fprintf(fout, "  %s = %s;", buf1,
5262             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5263               buf3, 0));
5264         break;
5265
5266       case OP_LEA:
5267         assert_operand_cnt(2);
5268         po->operand[1].lmod = OPLM_DWORD; // always
5269         fprintf(fout, "  %s = %s;",
5270             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5271             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5272               NULL, 1));
5273         break;
5274
5275       case OP_MOVZX:
5276         assert_operand_cnt(2);
5277         fprintf(fout, "  %s = %s;",
5278             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5279             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5280         break;
5281
5282       case OP_MOVSX:
5283         assert_operand_cnt(2);
5284         switch (po->operand[1].lmod) {
5285         case OPLM_BYTE:
5286           strcpy(buf3, "(s8)");
5287           break;
5288         case OPLM_WORD:
5289           strcpy(buf3, "(s16)");
5290           break;
5291         default:
5292           ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
5293         }
5294         fprintf(fout, "  %s = %s;",
5295             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5296             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5297               buf3, 0));
5298         break;
5299
5300       case OP_XCHG:
5301         assert_operand_cnt(2);
5302         propagate_lmod(po, &po->operand[0], &po->operand[1]);
5303         fprintf(fout, "  tmp = %s;",
5304           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
5305         fprintf(fout, " %s = %s;",
5306           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5307           out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5308             default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5309         fprintf(fout, " %s = %stmp;",
5310           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
5311           default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
5312         snprintf(g_comment, sizeof(g_comment), "xchg");
5313         break;
5314
5315       case OP_NOT:
5316         assert_operand_cnt(1);
5317         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5318         fprintf(fout, "  %s = ~%s;", buf1, buf1);
5319         break;
5320
5321       case OP_XLAT:
5322         assert_operand_cnt(2);
5323         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5324         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5325         fprintf(fout, "  %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
5326         strcpy(g_comment, "xlat");
5327         break;
5328
5329       case OP_CDQ:
5330         assert_operand_cnt(2);
5331         fprintf(fout, "  %s = (s32)%s >> 31;",
5332             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5333             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5334         strcpy(g_comment, "cdq");
5335         break;
5336
5337       case OP_LODS:
5338         if (po->flags & OPF_REP) {
5339           assert_operand_cnt(3);
5340           // hmh..
5341           ferr(po, "TODO\n");
5342         }
5343         else {
5344           assert_operand_cnt(2);
5345           fprintf(fout, "  %s = %sesi; esi %c= %d;",
5346             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
5347             lmod_cast_u_ptr(po, po->operand[1].lmod),
5348             (po->flags & OPF_DF) ? '-' : '+',
5349             lmod_bytes(po, po->operand[1].lmod));
5350           strcpy(g_comment, "lods");
5351         }
5352         break;
5353
5354       case OP_STOS:
5355         if (po->flags & OPF_REP) {
5356           assert_operand_cnt(3);
5357           fprintf(fout, "  for (; ecx != 0; ecx--, edi %c= %d)\n",
5358             (po->flags & OPF_DF) ? '-' : '+',
5359             lmod_bytes(po, po->operand[1].lmod));
5360           fprintf(fout, "    %sedi = eax;",
5361             lmod_cast_u_ptr(po, po->operand[1].lmod));
5362           strcpy(g_comment, "rep stos");
5363         }
5364         else {
5365           assert_operand_cnt(2);
5366           fprintf(fout, "  %sedi = eax; edi %c= %d;",
5367             lmod_cast_u_ptr(po, po->operand[1].lmod),
5368             (po->flags & OPF_DF) ? '-' : '+',
5369             lmod_bytes(po, po->operand[1].lmod));
5370           strcpy(g_comment, "stos");
5371         }
5372         break;
5373
5374       case OP_MOVS:
5375         j = lmod_bytes(po, po->operand[0].lmod);
5376         strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
5377         l = (po->flags & OPF_DF) ? '-' : '+';
5378         if (po->flags & OPF_REP) {
5379           assert_operand_cnt(3);
5380           fprintf(fout,
5381             "  for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
5382             l, j, l, j);
5383           fprintf(fout,
5384             "    %sedi = %sesi;", buf1, buf1);
5385           strcpy(g_comment, "rep movs");
5386         }
5387         else {
5388           assert_operand_cnt(2);
5389           fprintf(fout, "  %sedi = %sesi; edi %c= %d; esi %c= %d;",
5390             buf1, buf1, l, j, l, j);
5391           strcpy(g_comment, "movs");
5392         }
5393         break;
5394
5395       case OP_CMPS:
5396         // repe ~ repeat while ZF=1
5397         j = lmod_bytes(po, po->operand[0].lmod);
5398         strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
5399         l = (po->flags & OPF_DF) ? '-' : '+';
5400         if (po->flags & OPF_REP) {
5401           assert_operand_cnt(3);
5402           fprintf(fout,
5403             "  for (; ecx != 0; ecx--) {\n");
5404           if (pfomask & (1 << PFO_C)) {
5405             // ugh..
5406             fprintf(fout,
5407             "    cond_c = %sesi < %sedi;\n", buf1, buf1);
5408             pfomask &= ~(1 << PFO_C);
5409           }
5410           fprintf(fout,
5411             "    cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
5412               buf1, buf1, l, j, l, j);
5413           fprintf(fout,
5414             "    if (cond_z %s 0) break;\n",
5415               (po->flags & OPF_REPZ) ? "==" : "!=");
5416           fprintf(fout,
5417             "  }");
5418           snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
5419             (po->flags & OPF_REPZ) ? "e" : "ne");
5420         }
5421         else {
5422           assert_operand_cnt(2);
5423           fprintf(fout,
5424             "  cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
5425             buf1, buf1, l, j, l, j);
5426           strcpy(g_comment, "cmps");
5427         }
5428         pfomask &= ~(1 << PFO_Z);
5429         last_arith_dst = NULL;
5430         delayed_flag_op = NULL;
5431         break;
5432
5433       case OP_SCAS:
5434         // only does ZF (for now)
5435         // repe ~ repeat while ZF=1
5436         j = lmod_bytes(po, po->operand[1].lmod);
5437         l = (po->flags & OPF_DF) ? '-' : '+';
5438         if (po->flags & OPF_REP) {
5439           assert_operand_cnt(3);
5440           fprintf(fout,
5441             "  for (; ecx != 0; ecx--) {\n");
5442           fprintf(fout,
5443             "    cond_z = (%seax == %sedi); edi %c= %d;\n",
5444               lmod_cast_u(po, po->operand[1].lmod),
5445               lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
5446           fprintf(fout,
5447             "    if (cond_z %s 0) break;\n",
5448               (po->flags & OPF_REPZ) ? "==" : "!=");
5449           fprintf(fout,
5450             "  }");
5451           snprintf(g_comment, sizeof(g_comment), "rep%s scas",
5452             (po->flags & OPF_REPZ) ? "e" : "ne");
5453         }
5454         else {
5455           assert_operand_cnt(2);
5456           fprintf(fout, "  cond_z = (%seax == %sedi); edi %c= %d;",
5457               lmod_cast_u(po, po->operand[1].lmod),
5458               lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
5459           strcpy(g_comment, "scas");
5460         }
5461         pfomask &= ~(1 << PFO_Z);
5462         last_arith_dst = NULL;
5463         delayed_flag_op = NULL;
5464         break;
5465
5466       // arithmetic w/flags
5467       case OP_AND:
5468         if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
5469           goto dualop_arith_const;
5470         propagate_lmod(po, &po->operand[0], &po->operand[1]);
5471         goto dualop_arith;
5472
5473       case OP_OR:
5474         propagate_lmod(po, &po->operand[0], &po->operand[1]);
5475         if (po->operand[1].type == OPT_CONST) {
5476           j = lmod_bytes(po, po->operand[0].lmod);
5477           if (((1ull << j * 8) - 1) == po->operand[1].val)
5478             goto dualop_arith_const;
5479         }
5480         goto dualop_arith;
5481
5482       dualop_arith:
5483         assert_operand_cnt(2);
5484         fprintf(fout, "  %s %s= %s;",
5485             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5486             op_to_c(po),
5487             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5488         output_std_flags(fout, po, &pfomask, buf1);
5489         last_arith_dst = &po->operand[0];
5490         delayed_flag_op = NULL;
5491         break;
5492
5493       dualop_arith_const:
5494         // and 0, or ~0 used instead mov
5495         assert_operand_cnt(2);
5496         fprintf(fout, "  %s = %s;",
5497           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5498           out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5499            default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5500         output_std_flags(fout, po, &pfomask, buf1);
5501         last_arith_dst = &po->operand[0];
5502         delayed_flag_op = NULL;
5503         break;
5504
5505       case OP_SHL:
5506       case OP_SHR:
5507         assert_operand_cnt(2);
5508         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5509         if (pfomask & (1 << PFO_C)) {
5510           if (po->operand[1].type == OPT_CONST) {
5511             l = lmod_bytes(po, po->operand[0].lmod) * 8;
5512             j = po->operand[1].val;
5513             j %= l;
5514             if (j != 0) {
5515               if (po->op == OP_SHL)
5516                 j = l - j;
5517               else
5518                 j -= 1;
5519               fprintf(fout, "  cond_c = (%s >> %d) & 1;\n",
5520                 buf1, j);
5521             }
5522             else
5523               ferr(po, "zero shift?\n");
5524           }
5525           else
5526             ferr(po, "TODO\n");
5527           pfomask &= ~(1 << PFO_C);
5528         }
5529         fprintf(fout, "  %s %s= %s", buf1, op_to_c(po),
5530             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5531         if (po->operand[1].type != OPT_CONST)
5532           fprintf(fout, " & 0x1f");
5533         fprintf(fout, ";");
5534         output_std_flags(fout, po, &pfomask, buf1);
5535         last_arith_dst = &po->operand[0];
5536         delayed_flag_op = NULL;
5537         break;
5538
5539       case OP_SAR:
5540         assert_operand_cnt(2);
5541         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5542         fprintf(fout, "  %s = %s%s >> %s;", buf1,
5543           lmod_cast_s(po, po->operand[0].lmod), buf1,
5544           out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5545         output_std_flags(fout, po, &pfomask, buf1);
5546         last_arith_dst = &po->operand[0];
5547         delayed_flag_op = NULL;
5548         break;
5549
5550       case OP_SHLD:
5551       case OP_SHRD:
5552         assert_operand_cnt(3);
5553         propagate_lmod(po, &po->operand[0], &po->operand[1]);
5554         l = lmod_bytes(po, po->operand[0].lmod) * 8;
5555         out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
5556         if (po->operand[2].type != OPT_CONST) {
5557           // no handling for "undefined" case, hopefully not needed
5558           snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
5559           strcpy(buf3, buf2);
5560         }
5561         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5562         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5563         if (po->op == OP_SHLD) {
5564           fprintf(fout, "  %s <<= %s; %s |= %s >> (%d - %s);",
5565             buf1, buf3, buf1, buf2, l, buf3);
5566           strcpy(g_comment, "shld");
5567         }
5568         else {
5569           fprintf(fout, "  %s >>= %s; %s |= %s << (%d - %s);",
5570             buf1, buf3, buf1, buf2, l, buf3);
5571           strcpy(g_comment, "shrd");
5572         }
5573         output_std_flags(fout, po, &pfomask, buf1);
5574         last_arith_dst = &po->operand[0];
5575         delayed_flag_op = NULL;
5576         break;
5577
5578       case OP_ROL:
5579       case OP_ROR:
5580         assert_operand_cnt(2);
5581         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5582         if (po->operand[1].type == OPT_CONST) {
5583           j = po->operand[1].val;
5584           j %= lmod_bytes(po, po->operand[0].lmod) * 8;
5585           fprintf(fout, po->op == OP_ROL ?
5586             "  %s = (%s << %d) | (%s >> %d);" :
5587             "  %s = (%s >> %d) | (%s << %d);",
5588             buf1, buf1, j, buf1,
5589             lmod_bytes(po, po->operand[0].lmod) * 8 - j);
5590         }
5591         else
5592           ferr(po, "TODO\n");
5593         output_std_flags(fout, po, &pfomask, buf1);
5594         last_arith_dst = &po->operand[0];
5595         delayed_flag_op = NULL;
5596         break;
5597
5598       case OP_RCL:
5599       case OP_RCR:
5600         assert_operand_cnt(2);
5601         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5602         l = lmod_bytes(po, po->operand[0].lmod) * 8;
5603         if (po->operand[1].type == OPT_CONST) {
5604           j = po->operand[1].val % l;
5605           if (j == 0)
5606             ferr(po, "zero rotate\n");
5607           fprintf(fout, "  tmp = (%s >> %d) & 1;\n",
5608             buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
5609           if (po->op == OP_RCL) {
5610             fprintf(fout,
5611               "  %s = (%s << %d) | (cond_c << %d)",
5612               buf1, buf1, j, j - 1);
5613             if (j != 1)
5614               fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
5615           }
5616           else {
5617             fprintf(fout,
5618               "  %s = (%s >> %d) | (cond_c << %d)",
5619               buf1, buf1, j, l - j);
5620             if (j != 1)
5621               fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
5622           }
5623           fprintf(fout, ";\n");
5624           fprintf(fout, "  cond_c = tmp;");
5625         }
5626         else
5627           ferr(po, "TODO\n");
5628         strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
5629         output_std_flags(fout, po, &pfomask, buf1);
5630         last_arith_dst = &po->operand[0];
5631         delayed_flag_op = NULL;
5632         break;
5633
5634       case OP_XOR:
5635         assert_operand_cnt(2);
5636         propagate_lmod(po, &po->operand[0], &po->operand[1]);
5637         if (IS(opr_name(po, 0), opr_name(po, 1))) {
5638           // special case for XOR
5639           if (pfomask & (1 << PFO_BE)) { // weird, but it happens..
5640             fprintf(fout, "  cond_be = 1;\n");
5641             pfomask &= ~(1 << PFO_BE);
5642           }
5643           fprintf(fout, "  %s = 0;",
5644             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
5645           last_arith_dst = &po->operand[0];
5646           delayed_flag_op = NULL;
5647           break;
5648         }
5649         goto dualop_arith;
5650
5651       case OP_ADD:
5652         assert_operand_cnt(2);
5653         propagate_lmod(po, &po->operand[0], &po->operand[1]);
5654         if (pfomask & (1 << PFO_C)) {
5655           out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
5656           out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5657           if (po->operand[0].lmod == OPLM_DWORD) {
5658             fprintf(fout, "  tmp64 = (u64)%s + %s;\n", buf1, buf2);
5659             fprintf(fout, "  cond_c = tmp64 >> 32;\n");
5660             fprintf(fout, "  %s = (u32)tmp64;",
5661               out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
5662             strcat(g_comment, "add64");
5663           }
5664           else {
5665             fprintf(fout, "  cond_c = ((u32)%s + %s) >> %d;\n",
5666               buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
5667             fprintf(fout, "  %s += %s;",
5668               out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5669               buf2);
5670           }
5671           pfomask &= ~(1 << PFO_C);
5672           output_std_flags(fout, po, &pfomask, buf1);
5673           last_arith_dst = &po->operand[0];
5674           delayed_flag_op = NULL;
5675           break;
5676         }
5677         goto dualop_arith;
5678
5679       case OP_SUB:
5680         assert_operand_cnt(2);
5681         propagate_lmod(po, &po->operand[0], &po->operand[1]);
5682         if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
5683           for (j = 0; j <= PFO_LE; j++) {
5684             if (!(pfomask & (1 << j)))
5685               continue;
5686             if (j == PFO_Z || j == PFO_S)
5687               continue;
5688
5689             out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
5690             fprintf(fout, "  cond_%s = %s;\n",
5691               parsed_flag_op_names[j], buf1);
5692             pfomask &= ~(1 << j);
5693           }
5694         }
5695         goto dualop_arith;
5696
5697       case OP_ADC:
5698       case OP_SBB:
5699         assert_operand_cnt(2);
5700         propagate_lmod(po, &po->operand[0], &po->operand[1]);
5701         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5702         if (po->op == OP_SBB
5703           && IS(po->operand[0].name, po->operand[1].name))
5704         {
5705           // avoid use of unitialized var
5706           fprintf(fout, "  %s = -cond_c;", buf1);
5707           // carry remains what it was
5708           pfomask &= ~(1 << PFO_C);
5709         }
5710         else {
5711           fprintf(fout, "  %s %s= %s + cond_c;", buf1, op_to_c(po),
5712             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5713         }
5714         output_std_flags(fout, po, &pfomask, buf1);
5715         last_arith_dst = &po->operand[0];
5716         delayed_flag_op = NULL;
5717         break;
5718
5719       case OP_BSF:
5720         assert_operand_cnt(2);
5721         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5722         fprintf(fout, "  %s = %s ? __builtin_ffs(%s) - 1 : 0;",
5723           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5724           buf2, buf2);
5725         output_std_flags(fout, po, &pfomask, buf1);
5726         last_arith_dst = &po->operand[0];
5727         delayed_flag_op = NULL;
5728         strcat(g_comment, "bsf");
5729         break;
5730
5731       case OP_DEC:
5732         if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
5733           for (j = 0; j <= PFO_LE; j++) {
5734             if (!(pfomask & (1 << j)))
5735               continue;
5736             if (j == PFO_Z || j == PFO_S || j == PFO_C)
5737               continue;
5738
5739             out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
5740             fprintf(fout, "  cond_%s = %s;\n",
5741               parsed_flag_op_names[j], buf1);
5742             pfomask &= ~(1 << j);
5743           }
5744         }
5745         // fallthrough
5746
5747       case OP_INC:
5748         if (pfomask & (1 << PFO_C))
5749           // carry is unaffected by inc/dec.. wtf?
5750           ferr(po, "carry propagation needed\n");
5751
5752         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5753         if (po->operand[0].type == OPT_REG) {
5754           strcpy(buf2, po->op == OP_INC ? "++" : "--");
5755           fprintf(fout, "  %s%s;", buf1, buf2);
5756         }
5757         else {
5758           strcpy(buf2, po->op == OP_INC ? "+" : "-");
5759           fprintf(fout, "  %s %s= 1;", buf1, buf2);
5760         }
5761         output_std_flags(fout, po, &pfomask, buf1);
5762         last_arith_dst = &po->operand[0];
5763         delayed_flag_op = NULL;
5764         break;
5765
5766       case OP_NEG:
5767         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5768         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
5769         fprintf(fout, "  %s = -%s%s;", buf1,
5770           lmod_cast_s(po, po->operand[0].lmod), buf2);
5771         last_arith_dst = &po->operand[0];
5772         delayed_flag_op = NULL;
5773         if (pfomask & (1 << PFO_C)) {
5774           fprintf(fout, "\n  cond_c = (%s != 0);", buf1);
5775           pfomask &= ~(1 << PFO_C);
5776         }
5777         break;
5778
5779       case OP_IMUL:
5780         if (po->operand_cnt == 2) {
5781           propagate_lmod(po, &po->operand[0], &po->operand[1]);
5782           goto dualop_arith;
5783         }
5784         if (po->operand_cnt == 3)
5785           ferr(po, "TODO imul3\n");
5786         // fallthrough
5787       case OP_MUL:
5788         assert_operand_cnt(1);
5789         switch (po->operand[0].lmod) {
5790         case OPLM_DWORD:
5791           strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
5792           fprintf(fout, "  tmp64 = %seax * %s%s;\n", buf1, buf1,
5793             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
5794           fprintf(fout, "  edx = tmp64 >> 32;\n");
5795           fprintf(fout, "  eax = tmp64;");
5796           break;
5797         case OPLM_BYTE:
5798           strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
5799           fprintf(fout, "  LOWORD(eax) = %seax * %s;", buf1,
5800             out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
5801               buf1, 0));
5802           break;
5803         default:
5804           ferr(po, "TODO: unhandled mul type\n");
5805           break;
5806         }
5807         last_arith_dst = NULL;
5808         delayed_flag_op = NULL;
5809         break;
5810
5811       case OP_DIV:
5812       case OP_IDIV:
5813         assert_operand_cnt(1);
5814         out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
5815         strcpy(cast, lmod_cast(po, po->operand[0].lmod,
5816           po->op == OP_IDIV));
5817         switch (po->operand[0].lmod) {
5818         case OPLM_DWORD:
5819           if (po->flags & OPF_32BIT)
5820             snprintf(buf2, sizeof(buf2), "%seax", cast);
5821           else {
5822             fprintf(fout, "  tmp64 = ((u64)edx << 32) | eax;\n");
5823             snprintf(buf2, sizeof(buf2), "%stmp64",
5824               (po->op == OP_IDIV) ? "(s64)" : "");
5825           }
5826           if (po->operand[0].type == OPT_REG
5827             && po->operand[0].reg == xDX)
5828           {
5829             fprintf(fout, "  eax = %s / %s%s;\n", buf2, cast, buf1);
5830             fprintf(fout, "  edx = %s %% %s%s;", buf2, cast, buf1);
5831           }
5832           else {
5833             fprintf(fout, "  edx = %s %% %s%s;\n", buf2, cast, buf1);
5834             fprintf(fout, "  eax = %s / %s%s;", buf2, cast, buf1);
5835           }
5836           break;
5837         case OPLM_WORD:
5838           fprintf(fout, "  tmp = (edx << 16) | (eax & 0xffff);\n");
5839           snprintf(buf2, sizeof(buf2), "%stmp",
5840             (po->op == OP_IDIV) ? "(s32)" : "");
5841           if (po->operand[0].type == OPT_REG
5842             && po->operand[0].reg == xDX)
5843           {
5844             fprintf(fout, "  LOWORD(eax) = %s / %s%s;\n",
5845               buf2, cast, buf1);
5846             fprintf(fout, "  LOWORD(edx) = %s %% %s%s;",
5847               buf2, cast, buf1);
5848           }
5849           else {
5850             fprintf(fout, "  LOWORD(edx) = %s %% %s%s;\n",
5851               buf2, cast, buf1);
5852             fprintf(fout, "  LOWORD(eax) = %s / %s%s;",
5853               buf2, cast, buf1);
5854           }
5855           strcat(g_comment, "div16");
5856           break;
5857         default:
5858           ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
5859         }
5860         last_arith_dst = NULL;
5861         delayed_flag_op = NULL;
5862         break;
5863
5864       case OP_TEST:
5865       case OP_CMP:
5866         propagate_lmod(po, &po->operand[0], &po->operand[1]);
5867         if (pfomask != 0) {
5868           for (j = 0; j < 8; j++) {
5869             if (pfomask & (1 << j)) {
5870               out_cmp_test(buf1, sizeof(buf1), po, j, 0);
5871               fprintf(fout, "  cond_%s = %s;",
5872                 parsed_flag_op_names[j], buf1);
5873             }
5874           }
5875           pfomask = 0;
5876         }
5877         else
5878           no_output = 1;
5879         last_arith_dst = NULL;
5880         delayed_flag_op = po;
5881         break;
5882
5883       case OP_SCC:
5884         // SETcc - should already be handled
5885         break;
5886
5887       // note: we reuse OP_Jcc for SETcc, only flags differ
5888       case OP_JCC:
5889         fprintf(fout, "\n    goto %s;", po->operand[0].name);
5890         break;
5891
5892       case OP_JECXZ:
5893         fprintf(fout, "  if (ecx == 0)\n");
5894         fprintf(fout, "    goto %s;", po->operand[0].name);
5895         strcat(g_comment, "jecxz");
5896         break;
5897
5898       case OP_LOOP:
5899         fprintf(fout, "  if (--ecx != 0)\n");
5900         fprintf(fout, "    goto %s;", po->operand[0].name);
5901         strcat(g_comment, "loop");
5902         break;
5903
5904       case OP_JMP:
5905         assert_operand_cnt(1);
5906         last_arith_dst = NULL;
5907         delayed_flag_op = NULL;
5908
5909         if (po->operand[0].type == OPT_REGMEM) {
5910           ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
5911                   buf1, buf2);
5912           if (ret != 2)
5913             ferr(po, "parse failure for jmp '%s'\n",
5914               po->operand[0].name);
5915           fprintf(fout, "  goto *jt_%s[%s];", buf1, buf2);
5916           break;
5917         }
5918         else if (po->operand[0].type != OPT_LABEL)
5919           ferr(po, "unhandled jmp type\n");
5920
5921         fprintf(fout, "  goto %s;", po->operand[0].name);
5922         break;
5923
5924       case OP_CALL:
5925         assert_operand_cnt(1);
5926         pp = po->pp;
5927         my_assert_not(pp, NULL);
5928
5929         strcpy(buf3, "  ");
5930         if (po->flags & OPF_CC) {
5931           // we treat conditional branch to another func
5932           // (yes such code exists..) as conditional tailcall
5933           strcat(buf3, "  ");
5934           fprintf(fout, " {\n");
5935         }
5936
5937         if (pp->is_fptr && !pp->is_arg) {
5938           fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
5939             out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
5940               "(void *)", 0));
5941           if (pp->is_unresolved)
5942             fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
5943               buf3, asmfn, po->asmln, pp->name);
5944         }
5945
5946         fprintf(fout, "%s", buf3);
5947         if (strstr(pp->ret_type.name, "int64")) {
5948           if (po->flags & OPF_TAIL)
5949             ferr(po, "int64 and tail?\n");
5950           fprintf(fout, "tmp64 = ");
5951         }
5952         else if (!IS(pp->ret_type.name, "void")) {
5953           if (po->flags & OPF_TAIL) {
5954             if (regmask_ret & (1 << xAX)) {
5955               fprintf(fout, "return ");
5956               if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
5957                 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
5958             }
5959           }
5960           else if (po->regmask_dst & (1 << xAX)) {
5961             fprintf(fout, "eax = ");
5962             if (pp->ret_type.is_ptr)
5963               fprintf(fout, "(u32)");
5964           }
5965         }
5966
5967         if (pp->name[0] == 0)
5968           ferr(po, "missing pp->name\n");
5969         fprintf(fout, "%s%s(", pp->name,
5970           pp->has_structarg ? "_sa" : "");
5971
5972         if (po->flags & OPF_ATAIL) {
5973           if (pp->argc_stack != g_func_pp->argc_stack
5974             || (pp->argc_stack > 0
5975                 && pp->is_stdcall != g_func_pp->is_stdcall))
5976             ferr(po, "incompatible tailcall\n");
5977           if (g_func_pp->has_retreg)
5978             ferr(po, "TODO: retreg+tailcall\n");
5979
5980           for (arg = j = 0; arg < pp->argc; arg++) {
5981             if (arg > 0)
5982               fprintf(fout, ", ");
5983
5984             cast[0] = 0;
5985             if (pp->arg[arg].type.is_ptr)
5986               snprintf(cast, sizeof(cast), "(%s)",
5987                 pp->arg[arg].type.name);
5988
5989             if (pp->arg[arg].reg != NULL) {
5990               fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
5991               continue;
5992             }
5993             // stack arg
5994             for (; j < g_func_pp->argc; j++)
5995               if (g_func_pp->arg[j].reg == NULL)
5996                 break;
5997             fprintf(fout, "%sa%d", cast, j + 1);
5998             j++;
5999           }
6000         }
6001         else {
6002           for (arg = 0; arg < pp->argc; arg++) {
6003             if (arg > 0)
6004               fprintf(fout, ", ");
6005
6006             cast[0] = 0;
6007             if (pp->arg[arg].type.is_ptr)
6008               snprintf(cast, sizeof(cast), "(%s)",
6009                 pp->arg[arg].type.name);
6010
6011             if (pp->arg[arg].reg != NULL) {
6012               if (pp->arg[arg].type.is_retreg)
6013                 fprintf(fout, "&%s", pp->arg[arg].reg);
6014               else
6015                 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6016               continue;
6017             }
6018
6019             // stack arg
6020             tmp_op = pp->arg[arg].datap;
6021             if (tmp_op == NULL)
6022               ferr(po, "parsed_op missing for arg%d\n", arg);
6023
6024             if (tmp_op->flags & OPF_VAPUSH) {
6025               fprintf(fout, "ap");
6026             }
6027             else if (tmp_op->p_argpass != 0) {
6028               fprintf(fout, "a%d", tmp_op->p_argpass);
6029             }
6030             else if (tmp_op->p_argnum != 0) {
6031               fprintf(fout, "%s%s", cast,
6032                 saved_arg_name(buf1, sizeof(buf1),
6033                   tmp_op->p_arggrp, tmp_op->p_argnum));
6034             }
6035             else {
6036               fprintf(fout, "%s",
6037                 out_src_opr(buf1, sizeof(buf1),
6038                   tmp_op, &tmp_op->operand[0], cast, 0));
6039             }
6040           }
6041         }
6042         fprintf(fout, ");");
6043
6044         if (strstr(pp->ret_type.name, "int64")) {
6045           fprintf(fout, "\n");
6046           fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
6047           fprintf(fout, "%seax = tmp64;", buf3);
6048         }
6049
6050         if (pp->is_unresolved) {
6051           snprintf(buf2, sizeof(buf2), " unresolved %dreg",
6052             pp->argc_reg);
6053           strcat(g_comment, buf2);
6054         }
6055
6056         if (po->flags & OPF_TAIL) {
6057           ret = 0;
6058           if (i == opcnt - 1 || pp->is_noreturn)
6059             ret = 0;
6060           else if (IS(pp->ret_type.name, "void"))
6061             ret = 1;
6062           else if (!(regmask_ret & (1 << xAX)))
6063             ret = 1;
6064           // else already handled as 'return f()'
6065
6066           if (ret) {
6067             fprintf(fout, "\n%sreturn;", buf3);
6068             strcat(g_comment, " ^ tailcall");
6069           }
6070           else
6071             strcat(g_comment, " tailcall");
6072
6073           if ((regmask_ret & (1 << xAX))
6074             && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
6075           {
6076             ferr(po, "int func -> void func tailcall?\n");
6077           }
6078         }
6079         if (pp->is_noreturn)
6080           strcat(g_comment, " noreturn");
6081         if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
6082           strcat(g_comment, " argframe");
6083         if (po->flags & OPF_CC)
6084           strcat(g_comment, " cond");
6085
6086         if (po->flags & OPF_CC)
6087           fprintf(fout, "\n  }");
6088
6089         delayed_flag_op = NULL;
6090         last_arith_dst = NULL;
6091         break;
6092
6093       case OP_RET:
6094         if (g_func_pp->is_vararg)
6095           fprintf(fout, "  va_end(ap);\n");
6096         if (g_func_pp->has_retreg) {
6097           for (arg = 0; arg < g_func_pp->argc; arg++)
6098             if (g_func_pp->arg[arg].type.is_retreg)
6099               fprintf(fout, "  *r_%s = %s;\n",
6100                 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
6101         }
6102  
6103         if (!(regmask_ret & (1 << xAX))) {
6104           if (i != opcnt - 1 || label_pending)
6105             fprintf(fout, "  return;");
6106         }
6107         else if (g_func_pp->ret_type.is_ptr) {
6108           fprintf(fout, "  return (%s)eax;",
6109             g_func_pp->ret_type.name);
6110         }
6111         else if (IS(g_func_pp->ret_type.name, "__int64"))
6112           fprintf(fout, "  return ((u64)edx << 32) | eax;");
6113         else
6114           fprintf(fout, "  return eax;");
6115
6116         last_arith_dst = NULL;
6117         delayed_flag_op = NULL;
6118         break;
6119
6120       case OP_PUSH:
6121         out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6122         if (po->p_argnum != 0) {
6123           // special case - saved func arg
6124           fprintf(fout, "  %s = %s;",
6125             saved_arg_name(buf2, sizeof(buf2),
6126               po->p_arggrp, po->p_argnum), buf1);
6127           break;
6128         }
6129         else if (po->flags & OPF_RSAVE) {
6130           fprintf(fout, "  s_%s = %s;", buf1, buf1);
6131           break;
6132         }
6133         else if (po->flags & OPF_PPUSH) {
6134           tmp_op = po->datap;
6135           ferr_assert(po, tmp_op != NULL);
6136           out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
6137           fprintf(fout, "  pp_%s = %s;", buf2, buf1);
6138           break;
6139         }
6140         else if (g_func_pp->is_userstack) {
6141           fprintf(fout, "  *(--esp) = %s;", buf1);
6142           break;
6143         }
6144         if (!(g_ida_func_attr & IDAFA_NORETURN))
6145           ferr(po, "stray push encountered\n");
6146         no_output = 1;
6147         break;
6148
6149       case OP_POP:
6150         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6151         if (po->flags & OPF_RSAVE) {
6152           fprintf(fout, "  %s = s_%s;", buf1, buf1);
6153           break;
6154         }
6155         else if (po->flags & OPF_PPUSH) {
6156           // push/pop graph / non-const
6157           ferr_assert(po, po->datap == NULL);
6158           fprintf(fout, "  %s = pp_%s;", buf1, buf1);
6159           break;
6160         }
6161         else if (po->datap != NULL) {
6162           // push/pop pair
6163           tmp_op = po->datap;
6164           fprintf(fout, "  %s = %s;", buf1,
6165             out_src_opr(buf2, sizeof(buf2),
6166               tmp_op, &tmp_op->operand[0],
6167               default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6168           break;
6169         }
6170         else if (g_func_pp->is_userstack) {
6171           fprintf(fout, "  %s = *esp++;", buf1);
6172           break;
6173         }
6174         else
6175           ferr(po, "stray pop encountered\n");
6176         break;
6177
6178       case OP_NOP:
6179         no_output = 1;
6180         break;
6181
6182       // mmx
6183       case OP_EMMS:
6184         strcpy(g_comment, "(emms)");
6185         break;
6186
6187       default:
6188         no_output = 1;
6189         ferr(po, "unhandled op type %d, flags %x\n",
6190           po->op, po->flags);
6191         break;
6192     }
6193
6194     if (g_comment[0] != 0) {
6195       char *p = g_comment;
6196       while (my_isblank(*p))
6197         p++;
6198       fprintf(fout, "  // %s", p);
6199       g_comment[0] = 0;
6200       no_output = 0;
6201     }
6202     if (!no_output)
6203       fprintf(fout, "\n");
6204
6205     // some sanity checking
6206     if (po->flags & OPF_REP) {
6207       if (po->op != OP_STOS && po->op != OP_MOVS
6208           && po->op != OP_CMPS && po->op != OP_SCAS)
6209         ferr(po, "unexpected rep\n");
6210       if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
6211           && (po->op == OP_CMPS || po->op == OP_SCAS))
6212         ferr(po, "cmps/scas with plain rep\n");
6213     }
6214     if ((po->flags & (OPF_REPZ|OPF_REPNZ))
6215         && po->op != OP_CMPS && po->op != OP_SCAS)
6216       ferr(po, "unexpected repz/repnz\n");
6217
6218     if (pfomask != 0)
6219       ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
6220
6221     // see is delayed flag stuff is still valid
6222     if (delayed_flag_op != NULL && delayed_flag_op != po) {
6223       if (is_any_opr_modified(delayed_flag_op, po, 0))
6224         delayed_flag_op = NULL;
6225     }
6226
6227     if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
6228       if (is_opr_modified(last_arith_dst, po))
6229         last_arith_dst = NULL;
6230     }
6231
6232     label_pending = 0;
6233   }
6234
6235   if (g_stack_fsz && !g_stack_frame_used)
6236     fprintf(fout, "  (void)sf;\n");
6237
6238   fprintf(fout, "}\n\n");
6239
6240   gen_x_cleanup(opcnt);
6241 }
6242
6243 static void gen_x_cleanup(int opcnt)
6244 {
6245   int i;
6246
6247   for (i = 0; i < opcnt; i++) {
6248     struct label_ref *lr, *lr_del;
6249
6250     lr = g_label_refs[i].next;
6251     while (lr != NULL) {
6252       lr_del = lr;
6253       lr = lr->next;
6254       free(lr_del);
6255     }
6256     g_label_refs[i].i = -1;
6257     g_label_refs[i].next = NULL;
6258
6259     if (ops[i].op == OP_CALL) {
6260       if (ops[i].pp)
6261         proto_release(ops[i].pp);
6262     }
6263   }
6264   g_func_pp = NULL;
6265 }
6266
6267 struct func_proto_dep;
6268
6269 struct func_prototype {
6270   char name[NAMELEN];
6271   int id;
6272   int argc_stack;
6273   int regmask_dep;
6274   int has_ret:3;                 // -1, 0, 1: unresolved, no, yes
6275   unsigned int dep_resolved:1;
6276   unsigned int is_stdcall:1;
6277   struct func_proto_dep *dep_func;
6278   int dep_func_cnt;
6279   const struct parsed_proto *pp; // seed pp, if any
6280 };
6281
6282 struct func_proto_dep {
6283   char *name;
6284   struct func_prototype *proto;
6285   int regmask_live;             // .. at the time of call
6286   unsigned int ret_dep:1;       // return from this is caller's return
6287 };
6288
6289 static struct func_prototype *hg_fp;
6290 static int hg_fp_cnt;
6291
6292 static struct scanned_var {
6293   char name[NAMELEN];
6294   enum opr_lenmod lmod;
6295   unsigned int is_seeded:1;
6296   unsigned int is_c_str:1;
6297   const struct parsed_proto *pp; // seed pp, if any
6298 } *hg_vars;
6299 static int hg_var_cnt;
6300
6301 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
6302   int count);
6303
6304 struct func_prototype *hg_fp_add(const char *funcn)
6305 {
6306   struct func_prototype *fp;
6307
6308   if ((hg_fp_cnt & 0xff) == 0) {
6309     hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
6310     my_assert_not(hg_fp, NULL);
6311     memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
6312   }
6313
6314   fp = &hg_fp[hg_fp_cnt];
6315   snprintf(fp->name, sizeof(fp->name), "%s", funcn);
6316   fp->id = hg_fp_cnt;
6317   fp->argc_stack = -1;
6318   hg_fp_cnt++;
6319
6320   return fp;
6321 }
6322
6323 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
6324   const char *name)
6325 {
6326   int i;
6327
6328   for (i = 0; i < fp->dep_func_cnt; i++)
6329     if (IS(fp->dep_func[i].name, name))
6330       return &fp->dep_func[i];
6331
6332   return NULL;
6333 }
6334
6335 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
6336 {
6337   // is it a dupe?
6338   if (hg_fp_find_dep(fp, name))
6339     return;
6340
6341   if ((fp->dep_func_cnt & 0xff) == 0) {
6342     fp->dep_func = realloc(fp->dep_func,
6343       sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
6344     my_assert_not(fp->dep_func, NULL);
6345     memset(&fp->dep_func[fp->dep_func_cnt], 0,
6346       sizeof(fp->dep_func[0]) * 0x100);
6347   }
6348   fp->dep_func[fp->dep_func_cnt].name = strdup(name);
6349   fp->dep_func_cnt++;
6350 }
6351
6352 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
6353 {
6354   const struct func_prototype *p1 = p1_, *p2 = p2_;
6355   return strcmp(p1->name, p2->name);
6356 }
6357
6358 #if 0
6359 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
6360 {
6361   const struct func_prototype *p1 = p1_, *p2 = p2_;
6362   return p1->id - p2->id;
6363 }
6364 #endif
6365
6366 // recursive register dep pass
6367 // - track saved regs (part 2)
6368 // - try to figure out arg-regs
6369 // - calculate reg deps
6370 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
6371   struct func_prototype *fp, int regmask_save, int regmask_dst,
6372   int *regmask_dep, int *has_ret)
6373 {
6374   struct func_proto_dep *dep;
6375   struct parsed_op *po;
6376   int from_caller = 0;
6377   int j, l;
6378   int reg;
6379   int ret;
6380
6381   for (; i < opcnt; i++)
6382   {
6383     if (cbits[i >> 3] & (1 << (i & 7)))
6384       return;
6385     cbits[i >> 3] |= (1 << (i & 7));
6386
6387     po = &ops[i];
6388
6389     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
6390       if (po->flags & OPF_RMD)
6391         continue;
6392
6393       if (po->btj != NULL) {
6394         // jumptable
6395         for (j = 0; j < po->btj->count; j++) {
6396           check_i(po, po->btj->d[j].bt_i);
6397           gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
6398             regmask_save, regmask_dst, regmask_dep, has_ret);
6399         }
6400         return;
6401       }
6402
6403       check_i(po, po->bt_i);
6404       if (po->flags & OPF_CJMP) {
6405         gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
6406           regmask_save, regmask_dst, regmask_dep, has_ret);
6407       }
6408       else {
6409         i = po->bt_i - 1;
6410       }
6411       continue;
6412     }
6413
6414     if (po->flags & OPF_FARG)
6415       /* (just calculate register deps) */;
6416     else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
6417     {
6418       reg = po->operand[0].reg;
6419       ferr_assert(po, reg >= 0);
6420
6421       if (po->flags & OPF_RSAVE) {
6422         regmask_save |= 1 << reg;
6423         continue;
6424       }
6425       if (po->flags & OPF_DONE)
6426         continue;
6427
6428       ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0);
6429       if (ret == 1) {
6430         regmask_save |= 1 << reg;
6431         po->flags |= OPF_RMD;
6432         scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, OPF_RMD);
6433         continue;
6434       }
6435     }
6436     else if (po->flags & OPF_RMD)
6437       continue;
6438     else if (po->op == OP_CALL) {
6439       po->regmask_dst |= 1 << xAX;
6440
6441       dep = hg_fp_find_dep(fp, po->operand[0].name);
6442       if (dep != NULL)
6443         dep->regmask_live = regmask_save | regmask_dst;
6444     }
6445     else if (po->op == OP_RET) {
6446       if (po->operand_cnt > 0) {
6447         fp->is_stdcall = 1;
6448         if (fp->argc_stack >= 0
6449             && fp->argc_stack != po->operand[0].val / 4)
6450           ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
6451         fp->argc_stack = po->operand[0].val / 4;
6452       }
6453     }
6454
6455     // if has_ret is 0, there is uninitialized eax path,
6456     // which means it's most likely void func
6457     if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
6458       if (po->op == OP_CALL) {
6459         j = i;
6460         ret = 1;
6461       }
6462       else {
6463         struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
6464         j = -1;
6465         from_caller = 0;
6466         ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
6467       }
6468
6469       if (ret != 1 && from_caller) {
6470         // unresolved eax - probably void func
6471         *has_ret = 0;
6472       }
6473       else {
6474         if (j >= 0 && ops[j].op == OP_CALL) {
6475           dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
6476           if (dep != NULL)
6477             dep->ret_dep = 1;
6478           else
6479             *has_ret = 1;
6480         }
6481         else
6482           *has_ret = 1;
6483       }
6484     }
6485
6486     l = regmask_save | regmask_dst;
6487     if (g_bp_frame && !(po->flags & OPF_EBP_S))
6488       l |= 1 << xBP;
6489
6490     l = po->regmask_src & ~l;
6491 #if 0
6492     if (l)
6493       fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
6494         l, regmask_dst, regmask_save, po->flags);
6495 #endif
6496     *regmask_dep |= l;
6497     regmask_dst |= po->regmask_dst;
6498
6499     if (po->flags & OPF_TAIL)
6500       return;
6501   }
6502 }
6503
6504 static void gen_hdr(const char *funcn, int opcnt)
6505 {
6506   int save_arg_vars[MAX_ARG_GRP] = { 0, };
6507   unsigned char cbits[MAX_OPS / 8];
6508   const struct parsed_proto *pp_c;
6509   struct parsed_proto *pp;
6510   struct func_prototype *fp;
6511   struct parsed_op *po;
6512   int regmask_dummy = 0;
6513   int regmask_dep;
6514   int max_bp_offset = 0;
6515   int has_ret;
6516   int i, j, l;
6517   int ret;
6518
6519   pp_c = proto_parse(g_fhdr, funcn, 1);
6520   if (pp_c != NULL)
6521     // already in seed, will add to hg_fp later
6522     return;
6523
6524   fp = hg_fp_add(funcn);
6525
6526   g_bp_frame = g_sp_frame = g_stack_fsz = 0;
6527   g_stack_frame_used = 0;
6528
6529   // pass1:
6530   // - resolve all branches
6531   // - parse calls with labels
6532   resolve_branches_parse_calls(opcnt);
6533
6534   // pass2:
6535   // - handle ebp/esp frame, remove ops related to it
6536   scan_prologue_epilogue(opcnt);
6537
6538   // pass3:
6539   // - remove dead labels
6540   // - collect calls
6541   for (i = 0; i < opcnt; i++)
6542   {
6543     if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
6544       free(g_labels[i]);
6545       g_labels[i] = NULL;
6546     }
6547
6548     po = &ops[i];
6549     if (po->flags & (OPF_RMD|OPF_DONE))
6550       continue;
6551
6552     if (po->op == OP_CALL) {
6553       if (po->operand[0].type == OPT_LABEL)
6554         hg_fp_add_dep(fp, opr_name(po, 0));
6555       else if (po->pp != NULL)
6556         hg_fp_add_dep(fp, po->pp->name);
6557     }
6558   }
6559
6560   // pass4:
6561   // - remove dead labels
6562   // - handle push <const>/pop pairs
6563   for (i = 0; i < opcnt; i++)
6564   {
6565     if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
6566       free(g_labels[i]);
6567       g_labels[i] = NULL;
6568     }
6569
6570     po = &ops[i];
6571     if (po->flags & (OPF_RMD|OPF_DONE))
6572       continue;
6573
6574     if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
6575       scan_for_pop_const(i, opcnt, i + opcnt * 13);
6576   }
6577
6578   // pass5:
6579   // - process trivial calls
6580   for (i = 0; i < opcnt; i++)
6581   {
6582     po = &ops[i];
6583     if (po->flags & (OPF_RMD|OPF_DONE))
6584       continue;
6585
6586     if (po->op == OP_CALL)
6587     {
6588       pp = process_call_early(i, opcnt, &j);
6589       if (pp != NULL) {
6590         if (!(po->flags & OPF_ATAIL))
6591           // since we know the args, try to collect them
6592           if (collect_call_args_early(po, i, pp, &regmask_dummy) != 0)
6593             pp = NULL;
6594       }
6595
6596       if (pp != NULL) {
6597         if (j >= 0) {
6598           // commit esp adjust
6599           if (ops[j].op != OP_POP)
6600             patch_esp_adjust(&ops[j], pp->argc_stack * 4);
6601           else {
6602             for (l = 0; l < pp->argc_stack; l++)
6603               ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
6604           }
6605         }
6606
6607         po->flags |= OPF_DONE;
6608       }
6609     }
6610   }
6611
6612   // pass6:
6613   // - track saved regs (simple)
6614   // - process calls
6615   for (i = 0; i < opcnt; i++)
6616   {
6617     po = &ops[i];
6618     if (po->flags & (OPF_RMD|OPF_DONE))
6619       continue;
6620
6621     if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
6622       && po->operand[0].reg != xCX)
6623     {
6624       ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
6625       if (ret == 1) {
6626         // regmask_save |= 1 << po->operand[0].reg; // do it later
6627         po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
6628         scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
6629       }
6630     }
6631     else if (po->op == OP_CALL)
6632     {
6633       pp = process_call(i, opcnt);
6634
6635       if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
6636         // since we know the args, collect them
6637         ret = collect_call_args(po, i, pp, &regmask_dummy, save_arg_vars,
6638           i + opcnt * 1);
6639       }
6640     }
6641   }
6642
6643   // pass7
6644   memset(cbits, 0, sizeof(cbits));
6645   regmask_dep = 0;
6646   has_ret = -1;
6647
6648   gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, &regmask_dep, &has_ret);
6649
6650   // find unreachable code - must be fixed in IDA
6651   for (i = 0; i < opcnt; i++)
6652   {
6653     if (cbits[i >> 3] & (1 << (i & 7)))
6654       continue;
6655
6656     if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
6657       && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
6658     {
6659       // the compiler sometimes still generates code after
6660       // noreturn OS functions
6661       break;
6662     }
6663     if (ops[i].op != OP_NOP)
6664       ferr(&ops[i], "unreachable code\n");
6665   }
6666
6667   for (i = 0; i < g_eqcnt; i++) {
6668     if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
6669       max_bp_offset = g_eqs[i].offset;
6670   }
6671
6672   if (fp->argc_stack < 0) {
6673     max_bp_offset = (max_bp_offset + 3) & ~3;
6674     fp->argc_stack = max_bp_offset / 4;
6675     if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
6676       fp->argc_stack--;
6677   }
6678
6679   fp->regmask_dep = regmask_dep & ~(1 << xSP);
6680   fp->has_ret = has_ret;
6681 #if 0
6682   printf("// has_ret %d, regmask_dep %x\n",
6683     fp->has_ret, fp->regmask_dep);
6684   output_hdr_fp(stdout, fp, 1);
6685   if (IS(funcn, "sub_10007F72")) exit(1);
6686 #endif
6687
6688   gen_x_cleanup(opcnt);
6689 }
6690
6691 static void hg_fp_resolve_deps(struct func_prototype *fp)
6692 {
6693   struct func_prototype fp_s;
6694   int dep;
6695   int i;
6696
6697   // this thing is recursive, so mark first..
6698   fp->dep_resolved = 1;
6699
6700   for (i = 0; i < fp->dep_func_cnt; i++) {
6701     strcpy(fp_s.name, fp->dep_func[i].name);
6702     fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
6703       sizeof(hg_fp[0]), hg_fp_cmp_name);
6704     if (fp->dep_func[i].proto != NULL) {
6705       if (!fp->dep_func[i].proto->dep_resolved)
6706         hg_fp_resolve_deps(fp->dep_func[i].proto);
6707
6708       dep = ~fp->dep_func[i].regmask_live
6709            & fp->dep_func[i].proto->regmask_dep;
6710       fp->regmask_dep |= dep;
6711       // printf("dep %s %s |= %x\n", fp->name,
6712       //   fp->dep_func[i].name, dep);
6713
6714       if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
6715         fp->has_ret = fp->dep_func[i].proto->has_ret;
6716     }
6717   }
6718 }
6719
6720 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
6721   int count)
6722 {
6723   const struct parsed_proto *pp;
6724   char *p, namebuf[NAMELEN];
6725   const char *name;
6726   int regmask_dep;
6727   int argc_stack;
6728   int j, arg;
6729
6730   for (; count > 0; count--, fp++) {
6731     if (fp->has_ret == -1)
6732       fprintf(fout, "// ret unresolved\n");
6733 #if 0
6734     fprintf(fout, "// dep:");
6735     for (j = 0; j < fp->dep_func_cnt; j++) {
6736       fprintf(fout, " %s/", fp->dep_func[j].name);
6737       if (fp->dep_func[j].proto != NULL)
6738         fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
6739           fp->dep_func[j].proto->has_ret);
6740     }
6741     fprintf(fout, "\n");
6742 #endif
6743
6744     p = strchr(fp->name, '@');
6745     if (p != NULL) {
6746       memcpy(namebuf, fp->name, p - fp->name);
6747       namebuf[p - fp->name] = 0;
6748       name = namebuf;
6749     }
6750     else
6751       name = fp->name;
6752     if (name[0] == '_')
6753       name++;
6754
6755     pp = proto_parse(g_fhdr, name, 1);
6756     if (pp != NULL && pp->is_include)
6757       continue;
6758
6759     if (fp->pp != NULL) {
6760       // part of seed, output later
6761       continue;
6762     }
6763
6764     regmask_dep = fp->regmask_dep;
6765     argc_stack = fp->argc_stack;
6766
6767     fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
6768       (fp->has_ret ? "int" : "void"));
6769     if (regmask_dep && (fp->is_stdcall || argc_stack == 0)
6770       && (regmask_dep & ~((1 << xCX) | (1 << xDX))) == 0)
6771     {
6772       fprintf(fout, "  __fastcall    ");
6773       if (!(regmask_dep & (1 << xDX)) && argc_stack == 0)
6774         argc_stack = 1;
6775       else
6776         argc_stack += 2;
6777       regmask_dep = 0;
6778     }
6779     else if (regmask_dep && !fp->is_stdcall) {
6780       fprintf(fout, "/*__usercall*/  ");
6781     }
6782     else if (regmask_dep) {
6783       fprintf(fout, "/*__userpurge*/ ");
6784     }
6785     else if (fp->is_stdcall)
6786       fprintf(fout, "  __stdcall     ");
6787     else
6788       fprintf(fout, "  __cdecl       ");
6789
6790     fprintf(fout, "%s(", name);
6791
6792     arg = 0;
6793     for (j = 0; j < xSP; j++) {
6794       if (regmask_dep & (1 << j)) {
6795         arg++;
6796         if (arg != 1)
6797           fprintf(fout, ", ");
6798         if (fp->pp != NULL)
6799           fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
6800         else
6801           fprintf(fout, "int");
6802         fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
6803       }
6804     }
6805
6806     for (j = 0; j < argc_stack; j++) {
6807       arg++;
6808       if (arg != 1)
6809         fprintf(fout, ", ");
6810       if (fp->pp != NULL) {
6811         fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
6812         if (!fp->pp->arg[arg - 1].type.is_ptr)
6813           fprintf(fout, " ");
6814       }
6815       else
6816         fprintf(fout, "int ");
6817       fprintf(fout, "a%d", arg);
6818     }
6819
6820     fprintf(fout, ");\n");
6821   }
6822 }
6823
6824 static void output_hdr(FILE *fout)
6825 {
6826   static const char *lmod_c_names[] = {
6827     [OPLM_UNSPEC] = "???",
6828     [OPLM_BYTE]  = "uint8_t",
6829     [OPLM_WORD]  = "uint16_t",
6830     [OPLM_DWORD] = "uint32_t",
6831     [OPLM_QWORD] = "uint64_t",
6832   };
6833   const struct scanned_var *var;
6834   struct func_prototype *fp;
6835   char line[256] = { 0, };
6836   char name[256];
6837   int i;
6838
6839   // add stuff from headers
6840   for (i = 0; i < pp_cache_size; i++) {
6841     if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
6842       snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
6843     else
6844       snprintf(name, sizeof(name), "%s", pp_cache[i].name);
6845     fp = hg_fp_add(name);
6846     fp->pp = &pp_cache[i];
6847     fp->argc_stack = fp->pp->argc_stack;
6848     fp->is_stdcall = fp->pp->is_stdcall;
6849     fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
6850     fp->has_ret = !IS(fp->pp->ret_type.name, "void");
6851   }
6852
6853   // resolve deps
6854   qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
6855   for (i = 0; i < hg_fp_cnt; i++)
6856     hg_fp_resolve_deps(&hg_fp[i]);
6857
6858   // note: messes up .proto ptr, don't use
6859   //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
6860
6861   // output variables
6862   for (i = 0; i < hg_var_cnt; i++) {
6863     var = &hg_vars[i];
6864
6865     if (var->pp != NULL)
6866       // part of seed
6867       continue;
6868     else if (var->is_c_str)
6869       fprintf(fout, "extern %-8s %s[];", "char", var->name);
6870     else
6871       fprintf(fout, "extern %-8s %s;",
6872         lmod_c_names[var->lmod], var->name);
6873
6874     if (var->is_seeded)
6875       fprintf(fout, " // seeded");
6876     fprintf(fout, "\n");
6877   }
6878
6879   fprintf(fout, "\n");
6880
6881   // output function prototypes
6882   output_hdr_fp(fout, hg_fp, hg_fp_cnt);
6883
6884   // seed passthrough
6885   fprintf(fout, "\n// - seed -\n");
6886
6887   rewind(g_fhdr);
6888   while (fgets(line, sizeof(line), g_fhdr))
6889     fwrite(line, 1, strlen(line), fout);
6890 }
6891
6892 // '=' needs special treatment
6893 // also ' quote
6894 static char *next_word_s(char *w, size_t wsize, char *s)
6895 {
6896   size_t i;
6897
6898   s = sskip(s);
6899
6900   i = 0;
6901   if (*s == '\'') {
6902     w[0] = s[0];
6903     for (i = 1; i < wsize - 1; i++) {
6904       if (s[i] == 0) {
6905         printf("warning: missing closing quote: \"%s\"\n", s);
6906         break;
6907       }
6908       if (s[i] == '\'')
6909         break;
6910       w[i] = s[i];
6911     }
6912   }
6913
6914   for (; i < wsize - 1; i++) {
6915     if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
6916       break;
6917     w[i] = s[i];
6918   }
6919   w[i] = 0;
6920
6921   if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
6922     printf("warning: '%s' truncated\n", w);
6923
6924   return s + i;
6925 }
6926
6927 static void scan_variables(FILE *fasm)
6928 {
6929   struct scanned_var *var;
6930   char line[256] = { 0, };
6931   char words[3][256];
6932   char *p = NULL;
6933   int wordc;
6934   int l;
6935
6936   while (!feof(fasm))
6937   {
6938     // skip to next data section
6939     while (my_fgets(line, sizeof(line), fasm))
6940     {
6941       asmln++;
6942
6943       p = sskip(line);
6944       if (*p == 0 || *p == ';')
6945         continue;
6946
6947       p = sskip(next_word_s(words[0], sizeof(words[0]), p));
6948       if (*p == 0 || *p == ';')
6949         continue;
6950
6951       if (*p != 's' || !IS_START(p, "segment para public"))
6952         continue;
6953
6954       break;
6955     }
6956
6957     if (p == NULL || !IS_START(p, "segment para public"))
6958       break;
6959     p = sskip(p + 19);
6960
6961     if (!IS_START(p, "'DATA'"))
6962       continue;
6963
6964     // now process it
6965     while (my_fgets(line, sizeof(line), fasm))
6966     {
6967       asmln++;
6968
6969       p = line;
6970       if (my_isblank(*p))
6971         continue;
6972
6973       p = sskip(p);
6974       if (*p == 0 || *p == ';')
6975         continue;
6976
6977       for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
6978         words[wordc][0] = 0;
6979         p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
6980         if (*p == 0 || *p == ';') {
6981           wordc++;
6982           break;
6983         }
6984       }
6985
6986       if (wordc == 2 && IS(words[1], "ends"))
6987         break;
6988       if (wordc < 2)
6989         continue;
6990
6991       if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
6992         // when this starts, we don't need anything from this section
6993         break;
6994       }
6995
6996       if ((hg_var_cnt & 0xff) == 0) {
6997         hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
6998                    * (hg_var_cnt + 0x100));
6999         my_assert_not(hg_vars, NULL);
7000         memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
7001       }
7002
7003       var = &hg_vars[hg_var_cnt++];
7004       snprintf(var->name, sizeof(var->name), "%s", words[0]);
7005
7006       // maybe already in seed header?
7007       var->pp = proto_parse(g_fhdr, var->name, 1);
7008       if (var->pp != NULL) {
7009         if (var->pp->is_fptr) {
7010           var->lmod = OPLM_DWORD;
7011           //var->is_ptr = 1;
7012         }
7013         else if (var->pp->is_func)
7014           aerr("func?\n");
7015         else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
7016           aerr("unhandled C type '%s' for '%s'\n",
7017             var->pp->type.name, var->name);
7018
7019         var->is_seeded = 1;
7020         continue;
7021       }
7022
7023       if      (IS(words[1], "dd"))
7024         var->lmod = OPLM_DWORD;
7025       else if (IS(words[1], "dw"))
7026         var->lmod = OPLM_WORD;
7027       else if (IS(words[1], "db")) {
7028         var->lmod = OPLM_BYTE;
7029         if (wordc >= 3 && (l = strlen(words[2])) > 4) {
7030           if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
7031             var->is_c_str = 1;
7032         }
7033       }
7034       else if (IS(words[1], "dq"))
7035         var->lmod = OPLM_QWORD;
7036       //else if (IS(words[1], "dt"))
7037       else
7038         aerr("type '%s' not known\n", words[1]);
7039     }
7040   }
7041
7042   rewind(fasm);
7043   asmln = 0;
7044 }
7045
7046 static void set_label(int i, const char *name)
7047 {
7048   const char *p;
7049   int len;
7050
7051   len = strlen(name);
7052   p = strchr(name, ':');
7053   if (p != NULL)
7054     len = p - name;
7055
7056   if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
7057     aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
7058   g_labels[i] = realloc(g_labels[i], len + 1);
7059   my_assert_not(g_labels[i], NULL);
7060   memcpy(g_labels[i], name, len);
7061   g_labels[i][len] = 0;
7062 }
7063
7064 struct chunk_item {
7065   char *name;
7066   long fptr;
7067   int asmln;
7068 };
7069
7070 static struct chunk_item *func_chunks;
7071 static int func_chunk_cnt;
7072 static int func_chunk_alloc;
7073
7074 static void add_func_chunk(FILE *fasm, const char *name, int line)
7075 {
7076   if (func_chunk_cnt >= func_chunk_alloc) {
7077     func_chunk_alloc *= 2;
7078     func_chunks = realloc(func_chunks,
7079       func_chunk_alloc * sizeof(func_chunks[0]));
7080     my_assert_not(func_chunks, NULL);
7081   }
7082   func_chunks[func_chunk_cnt].fptr = ftell(fasm);
7083   func_chunks[func_chunk_cnt].name = strdup(name);
7084   func_chunks[func_chunk_cnt].asmln = line;
7085   func_chunk_cnt++;
7086 }
7087
7088 static int cmp_chunks(const void *p1, const void *p2)
7089 {
7090   const struct chunk_item *c1 = p1, *c2 = p2;
7091   return strcmp(c1->name, c2->name);
7092 }
7093
7094 static int cmpstringp(const void *p1, const void *p2)
7095 {
7096   return strcmp(*(char * const *)p1, *(char * const *)p2);
7097 }
7098
7099 static void scan_ahead(FILE *fasm)
7100 {
7101   char words[2][256];
7102   char line[256];
7103   long oldpos;
7104   int oldasmln;
7105   int wordc;
7106   char *p;
7107   int i;
7108
7109   oldpos = ftell(fasm);
7110   oldasmln = asmln;
7111
7112   while (my_fgets(line, sizeof(line), fasm))
7113   {
7114     wordc = 0;
7115     asmln++;
7116
7117     p = sskip(line);
7118     if (*p == 0)
7119       continue;
7120
7121     if (*p == ';')
7122     {
7123       // get rid of random tabs
7124       for (i = 0; line[i] != 0; i++)
7125         if (line[i] == '\t')
7126           line[i] = ' ';
7127
7128       if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
7129       {
7130         p += 30;
7131         next_word(words[0], sizeof(words[0]), p);
7132         if (words[0][0] == 0)
7133           aerr("missing name for func chunk?\n");
7134
7135         add_func_chunk(fasm, words[0], asmln);
7136       }
7137       else if (IS_START(p, "; sctend"))
7138         break;
7139
7140       continue;
7141     } // *p == ';'
7142
7143     for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7144       words[wordc][0] = 0;
7145       p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7146       if (*p == 0 || *p == ';') {
7147         wordc++;
7148         break;
7149       }
7150     }
7151
7152     if (wordc == 2 && IS(words[1], "ends"))
7153       break;
7154   }
7155
7156   fseek(fasm, oldpos, SEEK_SET);
7157   asmln = oldasmln;
7158 }
7159
7160 int main(int argc, char *argv[])
7161 {
7162   FILE *fout, *fasm, *frlist;
7163   struct parsed_data *pd = NULL;
7164   int pd_alloc = 0;
7165   char **rlist = NULL;
7166   int rlist_len = 0;
7167   int rlist_alloc = 0;
7168   int func_chunks_used = 0;
7169   int func_chunks_sorted = 0;
7170   int func_chunk_i = -1;
7171   long func_chunk_ret = 0;
7172   int func_chunk_ret_ln = 0;
7173   int scanned_ahead = 0;
7174   char line[256];
7175   char words[20][256];
7176   enum opr_lenmod lmod;
7177   char *sctproto = NULL;
7178   int in_func = 0;
7179   int pending_endp = 0;
7180   int skip_func = 0;
7181   int skip_warned = 0;
7182   int eq_alloc;
7183   int verbose = 0;
7184   int multi_seg = 0;
7185   int end = 0;
7186   int arg_out;
7187   int arg;
7188   int pi = 0;
7189   int i, j;
7190   int ret, len;
7191   char *p;
7192   int wordc;
7193
7194   for (arg = 1; arg < argc; arg++) {
7195     if (IS(argv[arg], "-v"))
7196       verbose = 1;
7197     else if (IS(argv[arg], "-rf"))
7198       g_allow_regfunc = 1;
7199     else if (IS(argv[arg], "-m"))
7200       multi_seg = 1;
7201     else if (IS(argv[arg], "-hdr"))
7202       g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
7203     else
7204       break;
7205   }
7206
7207   if (argc < arg + 3) {
7208     printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
7209            "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
7210            "options:\n"
7211            "  -hdr - header generation mode\n"
7212            "  -rf  - allow unannotated indirect calls\n"
7213            "  -m   - allow multiple .text sections\n"
7214            "[rlist] is a file with function names to skip,"
7215            " one per line\n",
7216       argv[0], argv[0]);
7217     return 1;
7218   }
7219
7220   arg_out = arg++;
7221
7222   asmfn = argv[arg++];
7223   fasm = fopen(asmfn, "r");
7224   my_assert_not(fasm, NULL);
7225
7226   hdrfn = argv[arg++];
7227   g_fhdr = fopen(hdrfn, "r");
7228   my_assert_not(g_fhdr, NULL);
7229
7230   rlist_alloc = 64;
7231   rlist = malloc(rlist_alloc * sizeof(rlist[0]));
7232   my_assert_not(rlist, NULL);
7233   // needs special handling..
7234   rlist[rlist_len++] = "__alloca_probe";
7235
7236   func_chunk_alloc = 32;
7237   func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
7238   my_assert_not(func_chunks, NULL);
7239
7240   memset(words, 0, sizeof(words));
7241
7242   for (; arg < argc; arg++) {
7243     frlist = fopen(argv[arg], "r");
7244     my_assert_not(frlist, NULL);
7245
7246     while (my_fgets(line, sizeof(line), frlist)) {
7247       p = sskip(line);
7248       if (*p == 0 || *p == ';')
7249         continue;
7250       if (*p == '#') {
7251         if (IS_START(p, "#if 0")
7252          || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
7253         {
7254           skip_func = 1;
7255         }
7256         else if (IS_START(p, "#endif"))
7257           skip_func = 0;
7258         continue;
7259       }
7260       if (skip_func)
7261         continue;
7262
7263       p = next_word(words[0], sizeof(words[0]), p);
7264       if (words[0][0] == 0)
7265         continue;
7266
7267       if (rlist_len >= rlist_alloc) {
7268         rlist_alloc = rlist_alloc * 2 + 64;
7269         rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
7270         my_assert_not(rlist, NULL);
7271       }
7272       rlist[rlist_len++] = strdup(words[0]);
7273     }
7274     skip_func = 0;
7275
7276     fclose(frlist);
7277     frlist = NULL;
7278   }
7279
7280   if (rlist_len > 0)
7281     qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
7282
7283   fout = fopen(argv[arg_out], "w");
7284   my_assert_not(fout, NULL);
7285
7286   eq_alloc = 128;
7287   g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
7288   my_assert_not(g_eqs, NULL);
7289
7290   for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
7291     g_label_refs[i].i = -1;
7292     g_label_refs[i].next = NULL;
7293   }
7294
7295   if (g_header_mode)
7296     scan_variables(fasm);
7297
7298   while (my_fgets(line, sizeof(line), fasm))
7299   {
7300     wordc = 0;
7301     asmln++;
7302
7303     p = sskip(line);
7304     if (*p == 0)
7305       continue;
7306
7307     // get rid of random tabs
7308     for (i = 0; line[i] != 0; i++)
7309       if (line[i] == '\t')
7310         line[i] = ' ';
7311
7312     if (*p == ';')
7313     {
7314       if (p[2] == '=' && IS_START(p, "; =============== S U B"))
7315         goto do_pending_endp; // eww..
7316
7317       if (p[2] == 'A' && IS_START(p, "; Attributes:"))
7318       {
7319         static const char *attrs[] = {
7320           "bp-based frame",
7321           "library function",
7322           "static",
7323           "noreturn",
7324           "thunk",
7325           "fpd=",
7326         };
7327
7328         // parse IDA's attribute-list comment
7329         g_ida_func_attr = 0;
7330         p = sskip(p + 13);
7331
7332         for (; *p != 0; p = sskip(p)) {
7333           for (i = 0; i < ARRAY_SIZE(attrs); i++) {
7334             if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
7335               g_ida_func_attr |= 1 << i;
7336               p += strlen(attrs[i]);
7337               break;
7338             }
7339           }
7340           if (i == ARRAY_SIZE(attrs)) {
7341             anote("unparsed IDA attr: %s\n", p);
7342             break;
7343           }
7344           if (IS(attrs[i], "fpd=")) {
7345             p = next_word(words[0], sizeof(words[0]), p);
7346             // ignore for now..
7347           }
7348         }
7349       }
7350       else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
7351       {
7352         p += 30;
7353         next_word(words[0], sizeof(words[0]), p);
7354         if (words[0][0] == 0)
7355           aerr("missing name for func chunk?\n");
7356
7357         if (!scanned_ahead) {
7358           add_func_chunk(fasm, words[0], asmln);
7359           func_chunks_sorted = 0;
7360         }
7361       }
7362       else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
7363       {
7364         if (func_chunk_i >= 0) {
7365           if (func_chunk_i < func_chunk_cnt
7366             && IS(func_chunks[func_chunk_i].name, g_func))
7367           {
7368             // move on to next chunk
7369             ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
7370             if (ret)
7371               aerr("seek failed for '%s' chunk #%d\n",
7372                 g_func, func_chunk_i);
7373             asmln = func_chunks[func_chunk_i].asmln;
7374             func_chunk_i++;
7375           }
7376           else {
7377             if (func_chunk_ret == 0)
7378               aerr("no return from chunk?\n");
7379             fseek(fasm, func_chunk_ret, SEEK_SET);
7380             asmln = func_chunk_ret_ln;
7381             func_chunk_ret = 0;
7382             pending_endp = 1;
7383           }
7384         }
7385       }
7386       else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
7387         func_chunks_used = 1;
7388         p += 20;
7389         if (IS_START(g_func, "sub_")) {
7390           unsigned long addr = strtoul(p, NULL, 16);
7391           unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
7392           if (addr > f_addr && !scanned_ahead) {
7393             //anote("scan_ahead caused by '%s', addr %lx\n",
7394             //  g_func, addr);
7395             scan_ahead(fasm);
7396             scanned_ahead = 1;
7397             func_chunks_sorted = 0;
7398           }
7399         }
7400       }
7401       continue;
7402     } // *p == ';'
7403
7404 parse_words:
7405     for (i = wordc; i < ARRAY_SIZE(words); i++)
7406       words[i][0] = 0;
7407     for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7408       p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7409       if (*p == 0 || *p == ';') {
7410         wordc++;
7411         break;
7412       }
7413     }
7414     if (*p != 0 && *p != ';')
7415       aerr("too many words\n");
7416
7417     // alow asm patches in comments
7418     if (*p == ';') {
7419       if (IS_START(p, "; sctpatch:")) {
7420         p = sskip(p + 11);
7421         if (*p == 0 || *p == ';')
7422           continue;
7423         goto parse_words; // lame
7424       }
7425       if (IS_START(p, "; sctproto:")) {
7426         sctproto = strdup(p + 11);
7427       }
7428       else if (IS_START(p, "; sctend")) {
7429         end = 1;
7430         if (!pending_endp)
7431           break;
7432       }
7433     }
7434
7435     if (wordc == 0) {
7436       // shouldn't happen
7437       awarn("wordc == 0?\n");
7438       continue;
7439     }
7440
7441     // don't care about this:
7442     if (words[0][0] == '.'
7443         || IS(words[0], "include")
7444         || IS(words[0], "assume") || IS(words[1], "segment")
7445         || IS(words[0], "align"))
7446     {
7447       continue;
7448     }
7449
7450 do_pending_endp:
7451     // do delayed endp processing to collect switch jumptables
7452     if (pending_endp) {
7453       if (in_func && !g_skip_func && !end && wordc >= 2
7454           && ((words[0][0] == 'd' && words[0][2] == 0)
7455               || (words[1][0] == 'd' && words[1][2] == 0)))
7456       {
7457         i = 1;
7458         if (words[1][0] == 'd' && words[1][2] == 0) {
7459           // label
7460           if (g_func_pd_cnt >= pd_alloc) {
7461             pd_alloc = pd_alloc * 2 + 16;
7462             g_func_pd = realloc(g_func_pd,
7463               sizeof(g_func_pd[0]) * pd_alloc);
7464             my_assert_not(g_func_pd, NULL);
7465           }
7466           pd = &g_func_pd[g_func_pd_cnt];
7467           g_func_pd_cnt++;
7468           memset(pd, 0, sizeof(*pd));
7469           strcpy(pd->label, words[0]);
7470           pd->type = OPT_CONST;
7471           pd->lmod = lmod_from_directive(words[1]);
7472           i = 2;
7473         }
7474         else {
7475           if (pd == NULL) {
7476             if (verbose)
7477               anote("skipping alignment byte?\n");
7478             continue;
7479           }
7480           lmod = lmod_from_directive(words[0]);
7481           if (lmod != pd->lmod)
7482             aerr("lmod change? %d->%d\n", pd->lmod, lmod);
7483         }
7484
7485         if (pd->count_alloc < pd->count + wordc) {
7486           pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
7487           pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
7488           my_assert_not(pd->d, NULL);
7489         }
7490         for (; i < wordc; i++) {
7491           if (IS(words[i], "offset")) {
7492             pd->type = OPT_OFFSET;
7493             i++;
7494           }
7495           p = strchr(words[i], ',');
7496           if (p != NULL)
7497             *p = 0;
7498           if (pd->type == OPT_OFFSET)
7499             pd->d[pd->count].u.label = strdup(words[i]);
7500           else
7501             pd->d[pd->count].u.val = parse_number(words[i]);
7502           pd->d[pd->count].bt_i = -1;
7503           pd->count++;
7504         }
7505         continue;
7506       }
7507
7508       if (in_func && !g_skip_func) {
7509         if (g_header_mode)
7510           gen_hdr(g_func, pi);
7511         else
7512           gen_func(fout, g_fhdr, g_func, pi);
7513       }
7514
7515       pending_endp = 0;
7516       in_func = 0;
7517       g_ida_func_attr = 0;
7518       skip_warned = 0;
7519       g_skip_func = 0;
7520       g_func[0] = 0;
7521       func_chunks_used = 0;
7522       func_chunk_i = -1;
7523       if (pi != 0) {
7524         memset(&ops, 0, pi * sizeof(ops[0]));
7525         clear_labels(pi);
7526         pi = 0;
7527       }
7528       g_eqcnt = 0;
7529       for (i = 0; i < g_func_pd_cnt; i++) {
7530         pd = &g_func_pd[i];
7531         if (pd->type == OPT_OFFSET) {
7532           for (j = 0; j < pd->count; j++)
7533             free(pd->d[j].u.label);
7534         }
7535         free(pd->d);
7536         pd->d = NULL;
7537       }
7538       g_func_pd_cnt = 0;
7539       pd = NULL;
7540
7541       if (end)
7542         break;
7543       if (wordc == 0)
7544         continue;
7545     }
7546
7547     if (IS(words[1], "proc")) {
7548       if (in_func)
7549         aerr("proc '%s' while in_func '%s'?\n",
7550           words[0], g_func);
7551       p = words[0];
7552       if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
7553         g_skip_func = 1;
7554       strcpy(g_func, words[0]);
7555       set_label(0, words[0]);
7556       in_func = 1;
7557       continue;
7558     }
7559
7560     if (IS(words[1], "endp"))
7561     {
7562       if (!in_func)
7563         aerr("endp '%s' while not in_func?\n", words[0]);
7564       if (!IS(g_func, words[0]))
7565         aerr("endp '%s' while in_func '%s'?\n",
7566           words[0], g_func);
7567
7568       if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
7569         && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
7570       {
7571         // import jump
7572         g_skip_func = 1;
7573       }
7574
7575       if (!g_skip_func && func_chunks_used) {
7576         // start processing chunks
7577         struct chunk_item *ci, key = { g_func, 0 };
7578
7579         func_chunk_ret = ftell(fasm);
7580         func_chunk_ret_ln = asmln;
7581         if (!func_chunks_sorted) {
7582           qsort(func_chunks, func_chunk_cnt,
7583             sizeof(func_chunks[0]), cmp_chunks);
7584           func_chunks_sorted = 1;
7585         }
7586         ci = bsearch(&key, func_chunks, func_chunk_cnt,
7587                sizeof(func_chunks[0]), cmp_chunks);
7588         if (ci == NULL)
7589           aerr("'%s' needs chunks, but none found\n", g_func);
7590         func_chunk_i = ci - func_chunks;
7591         for (; func_chunk_i > 0; func_chunk_i--)
7592           if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
7593             break;
7594
7595         ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
7596         if (ret)
7597           aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
7598         asmln = func_chunks[func_chunk_i].asmln;
7599         func_chunk_i++;
7600         continue;
7601       }
7602       pending_endp = 1;
7603       continue;
7604     }
7605
7606     if (wordc == 2 && IS(words[1], "ends")) {
7607       if (!multi_seg) {
7608         end = 1;
7609         if (pending_endp)
7610           goto do_pending_endp;
7611         break;
7612       }
7613
7614       // scan for next text segment
7615       while (my_fgets(line, sizeof(line), fasm)) {
7616         asmln++;
7617         p = sskip(line);
7618         if (*p == 0 || *p == ';')
7619           continue;
7620
7621         if (strstr(p, "segment para public 'CODE' use32"))
7622           break;
7623       }
7624
7625       continue;
7626     }
7627
7628     p = strchr(words[0], ':');
7629     if (p != NULL) {
7630       set_label(pi, words[0]);
7631       continue;
7632     }
7633
7634     if (!in_func || g_skip_func) {
7635       if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
7636         if (verbose)
7637           anote("skipping from '%s'\n", g_labels[pi]);
7638         skip_warned = 1;
7639       }
7640       free(g_labels[pi]);
7641       g_labels[pi] = NULL;
7642       continue;
7643     }
7644
7645     if (wordc > 1 && IS(words[1], "="))
7646     {
7647       if (wordc != 5)
7648         aerr("unhandled equ, wc=%d\n", wordc);
7649       if (g_eqcnt >= eq_alloc) {
7650         eq_alloc *= 2;
7651         g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
7652         my_assert_not(g_eqs, NULL);
7653       }
7654
7655       len = strlen(words[0]);
7656       if (len > sizeof(g_eqs[0].name) - 1)
7657         aerr("equ name too long: %d\n", len);
7658       strcpy(g_eqs[g_eqcnt].name, words[0]);
7659
7660       if (!IS(words[3], "ptr"))
7661         aerr("unhandled equ\n");
7662       if (IS(words[2], "dword"))
7663         g_eqs[g_eqcnt].lmod = OPLM_DWORD;
7664       else if (IS(words[2], "word"))
7665         g_eqs[g_eqcnt].lmod = OPLM_WORD;
7666       else if (IS(words[2], "byte"))
7667         g_eqs[g_eqcnt].lmod = OPLM_BYTE;
7668       else if (IS(words[2], "qword"))
7669         g_eqs[g_eqcnt].lmod = OPLM_QWORD;
7670       else
7671         aerr("bad lmod: '%s'\n", words[2]);
7672
7673       g_eqs[g_eqcnt].offset = parse_number(words[4]);
7674       g_eqcnt++;
7675       continue;
7676     }
7677
7678     if (pi >= ARRAY_SIZE(ops))
7679       aerr("too many ops\n");
7680
7681     parse_op(&ops[pi], words, wordc);
7682
7683     if (sctproto != NULL) {
7684       if (ops[pi].op == OP_CALL || ops[pi].op == OP_JMP)
7685         ops[pi].datap = sctproto;
7686       sctproto = NULL;
7687     }
7688     pi++;
7689   }
7690
7691   if (g_header_mode)
7692     output_hdr(fout);
7693
7694   fclose(fout);
7695   fclose(fasm);
7696   fclose(g_fhdr);
7697
7698   return 0;
7699 }
7700
7701 // vim:ts=2:shiftwidth=2:expandtab