e6ab80203bd603490527226af70af4ddaf4e455c
[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  * recognized asm hint comments:
9  * sctattr - function attributes (see code)
10  * sctend  - force end of function/chunk
11  * sctpatch: <p> - replace current asm line with <p>
12  * sctproto: <p> - prototype of ref'd function or struct
13  * sctref  - variable is referenced, make global
14  * sctskip_start - start of skipped code chunk (inclusive)
15  * sctskip_end   - end of skipped code chunk (inclusive)
16  */
17
18 #define _GNU_SOURCE
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <math.h>
23 #include <errno.h>
24
25 #include "my_assert.h"
26 #include "my_str.h"
27 #include "common.h"
28
29 #include "protoparse.h"
30
31 static const char *asmfn;
32 static int asmln;
33 static FILE *g_fhdr;
34
35 #define anote(fmt, ...) \
36         printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
37 #define awarn(fmt, ...) \
38         printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
39 #define aerr(fmt, ...) do { \
40         printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
41   fcloseall(); \
42         exit(1); \
43 } while (0)
44
45 #include "masm_tools.h"
46
47 enum op_flags {
48   OPF_RMD    = (1 << 0), /* removed from code generation */
49   OPF_DATA   = (1 << 1), /* data processing - writes to dst opr */
50   OPF_FLAGS  = (1 << 2), /* sets flags */
51   OPF_JMP    = (1 << 3), /* branch, call */
52   OPF_CJMP   = (1 << 4), /* cond. branch (cc or jecxz/loop) */
53   OPF_CC     = (1 << 5), /* uses flags */
54   OPF_TAIL   = (1 << 6), /* ret or tail call */
55   OPF_RSAVE  = (1 << 7), /* push/pop is local reg save/load */
56   OPF_REP    = (1 << 8), /* prefixed by rep */
57   OPF_REPZ   = (1 << 9), /* rep is repe/repz */
58   OPF_REPNZ  = (1 << 10), /* rep is repne/repnz */
59   OPF_FARG   = (1 << 11), /* push collected as func arg */
60   OPF_FARGNR = (1 << 12), /* push collected as func arg (no reuse) */
61   OPF_EBP_S  = (1 << 13), /* ebp used as scratch here, not BP */
62   OPF_DF     = (1 << 14), /* DF flag set */
63   OPF_ATAIL  = (1 << 15), /* tail call with reused arg frame */
64   OPF_32BIT  = (1 << 16), /* 32bit division */
65   OPF_LOCK   = (1 << 17), /* op has lock prefix */
66   OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
67   OPF_DONE   = (1 << 19), /* already fully handled by analysis */
68   OPF_PPUSH  = (1 << 20), /* part of complex push-pop graph */
69   OPF_NOREGS = (1 << 21), /* don't track regs of this op */
70   OPF_FPUSH  = (1 << 22), /* pushes x87 stack */
71   OPF_FPOP   = (1 << 23), /* pops x87 stack */
72   OPF_FPOPP  = (1 << 24), /* pops x87 stack twice */
73   OPF_FSHIFT = (1 << 25), /* x87 stack shift is actually needed */
74   OPF_FINT   = (1 << 26), /* integer float op arg */
75 };
76
77 enum op_op {
78         OP_INVAL,
79         OP_NOP,
80         OP_PUSH,
81         OP_POP,
82         OP_PUSHA,
83         OP_POPA,
84         OP_LEAVE,
85         OP_MOV,
86         OP_LEA,
87         OP_MOVZX,
88         OP_MOVSX,
89         OP_XCHG,
90         OP_NOT,
91         OP_XLAT,
92         OP_CDQ,
93         OP_BSWAP,
94         OP_LODS,
95         OP_STOS,
96         OP_MOVS,
97         OP_CMPS,
98         OP_SCAS,
99         OP_STD,
100         OP_CLD,
101         OP_RET,
102         OP_ADD,
103         OP_SUB,
104         OP_AND,
105         OP_OR,
106         OP_XOR,
107         OP_SHL,
108         OP_SHR,
109         OP_SAR,
110         OP_SHLD,
111         OP_SHRD,
112         OP_ROL,
113         OP_ROR,
114         OP_RCL,
115         OP_RCR,
116         OP_ADC,
117         OP_SBB,
118         OP_BSF,
119         OP_BSR,
120         OP_INC,
121         OP_DEC,
122         OP_NEG,
123         OP_MUL,
124         OP_IMUL,
125         OP_DIV,
126         OP_IDIV,
127         OP_TEST,
128         OP_CMP,
129         OP_CALL,
130         OP_JMP,
131         OP_JECXZ,
132         OP_LOOP,
133         OP_JCC,
134         OP_SCC,
135   // x87
136   OP_FLD,
137   OP_FILD,
138   OP_FLDc,
139   OP_FST,
140   OP_FIST,
141   OP_FADD,
142   OP_FDIV,
143   OP_FMUL,
144   OP_FSUB,
145   OP_FDIVR,
146   OP_FSUBR,
147   OP_FIADD,
148   OP_FIDIV,
149   OP_FIMUL,
150   OP_FISUB,
151   OP_FIDIVR,
152   OP_FISUBR,
153   OP_FCOM,
154   OP_FNSTSW,
155   OP_FCHS,
156   OP_FCOS,
157   OP_FPATAN,
158   OP_FPTAN,
159   OP_FSIN,
160   OP_FSQRT,
161   OP_FXCH,
162   OP_FYL2X,
163   // mmx
164   OP_EMMS,
165   // pseudo-ops for lib calls
166   OPP_ALLSHL,
167   OPP_ALLSHR,
168   OPP_FTOL,
169   OPP_CIPOW,
170   OPP_ABORT,
171   // undefined
172   OP_UD2,
173 };
174
175 enum opr_type {
176   OPT_UNSPEC,
177   OPT_REG,
178   OPT_REGMEM,
179   OPT_LABEL,
180   OPT_OFFSET,
181   OPT_CONST,
182 };
183
184 // must be sorted (larger len must be further in enum)
185 enum opr_lenmod {
186         OPLM_UNSPEC,
187         OPLM_BYTE,
188         OPLM_WORD,
189         OPLM_DWORD,
190         OPLM_QWORD,
191 };
192
193 #define MAX_EXITS 128
194
195 #define MAX_OPERANDS 3
196 #define NAMELEN 112
197
198 #define OPR_INIT(type_, lmod_, reg_) \
199   { type_, lmod_, reg_, }
200
201 struct parsed_opr {
202   enum opr_type type;
203   enum opr_lenmod lmod;
204   int reg;
205   unsigned int is_ptr:1;   // pointer in C
206   unsigned int is_array:1; // array in C
207   unsigned int type_from_var:1; // .. in header, sometimes wrong
208   unsigned int size_mismatch:1; // type override differs from C
209   unsigned int size_lt:1;  // type override is larger than C
210   unsigned int segment:7;  // had segment override (enum segment)
211   const struct parsed_proto *pp; // for OPT_LABEL
212   unsigned int val;
213   char name[NAMELEN];
214 };
215
216 struct parsed_op {
217   enum op_op op;
218   struct parsed_opr operand[MAX_OPERANDS];
219   unsigned int flags;
220   unsigned char pfo;
221   unsigned char pfo_inv;
222   unsigned char operand_cnt;
223   unsigned char p_argnum; // arg push: altered before call arg #
224   unsigned char p_arggrp; // arg push: arg group # for above
225   unsigned char p_argpass;// arg push: arg of host func
226   short         p_argnext;// arg push: same arg pushed elsewhere or -1
227   int regmask_src;        // all referensed regs
228   int regmask_dst;
229   int pfomask;            // flagop: parsed_flag_op that can't be delayed
230   int cc_scratch;         // scratch storage during analysis
231   int bt_i;               // branch target for branches
232   struct parsed_data *btj;// branch targets for jumptables
233   struct parsed_proto *pp;// parsed_proto for OP_CALL
234   void *datap;
235   int asmln;
236 };
237
238 // datap:
239 // on start:  function/data type hint (sctproto)
240 // after analysis:
241 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
242 // OP_PUSH  - points to OP_POP in complex push/pop graph
243 // OP_POP   - points to OP_PUSH in simple push/pop pair
244 // OP_FCOM  - needed_status_word_bits | (is_z_check << 16)
245
246 struct parsed_equ {
247   char name[64];
248   enum opr_lenmod lmod;
249   int offset;
250 };
251
252 struct parsed_data {
253   char label[256];
254   enum opr_type type;
255   enum opr_lenmod lmod;
256   int count;
257   int count_alloc;
258   struct {
259     union {
260       char *label;
261       unsigned int val;
262     } u;
263     int bt_i;
264   } *d;
265 };
266
267 struct label_ref {
268   int i;
269   struct label_ref *next;
270 };
271
272 enum ida_func_attr {
273   IDAFA_BP_FRAME = (1 << 0),
274   IDAFA_LIB_FUNC = (1 << 1),
275   IDAFA_STATIC   = (1 << 2),
276   IDAFA_NORETURN = (1 << 3),
277   IDAFA_THUNK    = (1 << 4),
278   IDAFA_FPD      = (1 << 5),
279 };
280
281 enum sct_func_attr {
282   SCTFA_CLEAR_SF   = (1 << 0), // clear stack frame
283   SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
284 };
285
286 enum x87_const {
287   X87_CONST_1 = 1,
288   X87_CONST_L2T,
289   X87_CONST_L2E,
290   X87_CONST_PI,
291   X87_CONST_LG2,
292   X87_CONST_LN2,
293   X87_CONST_Z,
294 };
295
296 enum segment {
297   SEG_CS = 1,
298   SEG_DS,
299   SEG_SS,
300   SEG_ES,
301   SEG_FS,
302   SEG_GS,
303 };
304
305 // note: limited to 32k due to p_argnext
306 #define MAX_OPS     4096
307 #define MAX_ARG_GRP 2
308
309 static struct parsed_op ops[MAX_OPS];
310 static struct parsed_equ *g_eqs;
311 static int g_eqcnt;
312 static char *g_labels[MAX_OPS];
313 static struct label_ref g_label_refs[MAX_OPS];
314 static const struct parsed_proto *g_func_pp;
315 static struct parsed_data *g_func_pd;
316 static int g_func_pd_cnt;
317 static int g_func_lmods;
318 static char g_func[256];
319 static char g_comment[256];
320 static int g_bp_frame;
321 static int g_sp_frame;
322 static int g_stack_frame_used;
323 static int g_stack_fsz;
324 static int g_seh_found;
325 static int g_seh_size;
326 static int g_ida_func_attr;
327 static int g_sct_func_attr;
328 static int g_stack_clear_start; // in dwords
329 static int g_stack_clear_len;
330 static int g_regmask_init;
331 static int g_skip_func;
332 static int g_allow_regfunc;
333 static int g_allow_user_icall;
334 static int g_quiet_pp;
335 static int g_header_mode;
336
337 #define ferr(op_, fmt, ...) do { \
338   printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
339     __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
340   fcloseall(); \
341   exit(1); \
342 } while (0)
343 #define fnote(op_, fmt, ...) \
344   printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
345     dump_op(op_), ##__VA_ARGS__)
346
347 #define ferr_assert(op_, cond) do { \
348   if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
349 } while (0)
350
351 const char *regs_r32[] = {
352   "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
353   // not r32, but list here for easy parsing and printing
354   "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
355   "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
356 };
357 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
358 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
359 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
360
361 enum x86_regs {
362   xUNSPEC = -1,
363   xAX, xBX, xCX, xDX,
364   xSI, xDI, xBP, xSP,
365   xMM0, xMM1, xMM2, xMM3, // mmx
366   xMM4, xMM5, xMM6, xMM7,
367   xST0, xST1, xST2, xST3, // x87
368   xST4, xST5, xST6, xST7,
369 };
370
371 #define mxAX     (1 << xAX)
372 #define mxCX     (1 << xCX)
373 #define mxDX     (1 << xDX)
374 #define mxSP     (1 << xSP)
375 #define mxST0    (1 << xST0)
376 #define mxST1    (1 << xST1)
377 #define mxST1_0  (mxST1 | mxST0)
378 #define mxST7_2  (0xfc << xST0)
379 #define mxSTa    (0xff << xST0)
380
381 // possible basic comparison types (without inversion)
382 enum parsed_flag_op {
383   PFO_O,  // 0 OF=1
384   PFO_C,  // 2 CF=1
385   PFO_Z,  // 4 ZF=1
386   PFO_BE, // 6 CF=1||ZF=1
387   PFO_S,  // 8 SF=1
388   PFO_P,  // a PF=1
389   PFO_L,  // c SF!=OF
390   PFO_LE, // e ZF=1||SF!=OF
391 };
392
393 #define PFOB_O   (1 << PFO_O)
394 #define PFOB_C   (1 << PFO_C)
395 #define PFOB_Z   (1 << PFO_Z)
396 #define PFOB_S   (1 << PFO_S)
397
398 static const char *parsed_flag_op_names[] = {
399   "o", "c", "z", "be", "s", "p", "l", "le"
400 };
401
402 static int char_array_i(const char *array[], size_t len, const char *s)
403 {
404   int i;
405
406   for (i = 0; i < len; i++)
407     if (IS(s, array[i]))
408       return i;
409
410   return -1;
411 }
412
413 static void printf_number(char *buf, size_t buf_size,
414   unsigned long number)
415 {
416   // output in C-friendly form
417   snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
418 }
419
420 static int check_segment_prefix(const char *s)
421 {
422   if (s[0] == 0 || s[1] != 's' || s[2] != ':')
423     return 0;
424
425   switch (s[0]) {
426   case 'c': return SEG_CS;
427   case 'd': return SEG_DS;
428   case 's': return SEG_SS;
429   case 'e': return SEG_ES;
430   case 'f': return SEG_FS;
431   case 'g': return SEG_GS;
432   default:  return 0;
433   }
434 }
435
436 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
437 {
438   int reg;
439
440   reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
441   if (reg >= 8) {
442     *reg_lmod = OPLM_QWORD;
443     return reg;
444   }
445   if (reg >= 0) {
446     *reg_lmod = OPLM_DWORD;
447     return reg;
448   }
449   reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
450   if (reg >= 0) {
451     *reg_lmod = OPLM_WORD;
452     return reg;
453   }
454   reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
455   if (reg >= 0) {
456     *reg_lmod = OPLM_BYTE;
457     return reg;
458   }
459   reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
460   if (reg >= 0) {
461     *reg_lmod = OPLM_BYTE;
462     return reg;
463   }
464
465   return -1;
466 }
467
468 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
469 {
470   enum opr_lenmod lmod;
471   char cvtbuf[256];
472   char *d = cvtbuf;
473   char *s = name;
474   char w[64];
475   long number;
476   int reg;
477   int c = 0;
478
479   *d = 0;
480
481   while (*s != 0) {
482     d += strlen(d);
483     while (my_isblank(*s))
484       s++;
485     for (; my_issep(*s); d++, s++)
486       *d = *s;
487     while (my_isblank(*s))
488       s++;
489     *d = 0;
490
491     // skip '?s:' prefixes
492     if (check_segment_prefix(s))
493       s += 3;
494
495     s = next_idt(w, sizeof(w), s);
496     if (w[0] == 0)
497       break;
498     c++;
499
500     reg = parse_reg(&lmod, w);
501     if (reg >= 0) {
502       *regmask |= 1 << reg;
503       goto pass;
504     }
505
506     if ('0' <= w[0] && w[0] <= '9') {
507       number = parse_number(w, 0);
508       printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
509       continue;
510     }
511
512     // probably some label/identifier - pass
513
514 pass:
515     snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
516   }
517
518   if (need_c_cvt)
519     strcpy(name, cvtbuf);
520
521   return c;
522 }
523
524 static int is_reg_in_str(const char *s)
525 {
526   int i;
527
528   if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
529     return 0;
530
531   for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
532     if (!strncmp(s, regs_r32[i], 3))
533       return 1;
534
535   return 0;
536 }
537
538 static const char *parse_stack_el(const char *name, char *extra_reg,
539   int *base_val, int early_try)
540 {
541   const char *p, *p2, *s;
542   char *endp = NULL;
543   char buf[32];
544   long val = -1;
545   int len;
546
547   if (g_bp_frame || early_try)
548   {
549     p = name;
550     if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
551       p += 4;
552       if (extra_reg != NULL) {
553         strncpy(extra_reg, name, 3);
554         extra_reg[4] = 0;
555       }
556     }
557
558     if (IS_START(p, "ebp+")) {
559       p += 4;
560
561       p2 = strchr(p, '+');
562       if (p2 != NULL && is_reg_in_str(p)) {
563         if (extra_reg != NULL) {
564           strncpy(extra_reg, p, p2 - p);
565           extra_reg[p2 - p] = 0;
566         }
567         p = p2 + 1;
568       }
569
570       if (!('0' <= *p && *p <= '9'))
571         return p;
572
573       return NULL;
574     }
575   }
576
577   if (!IS_START(name, "esp+"))
578     return NULL;
579
580   s = name + 4;
581   p = strchr(s, '+');
582   if (p) {
583     if (is_reg_in_str(s)) {
584       if (extra_reg != NULL) {
585         strncpy(extra_reg, s, p - s);
586         extra_reg[p - s] = 0;
587       }
588       s = p + 1;
589       p = strchr(s, '+');
590       if (p == NULL)
591         aerr("%s IDA stackvar not set?\n", __func__);
592     }
593     if (!('0' <= *s && *s <= '9')) {
594       aerr("%s IDA stackvar offset not set?\n", __func__);
595       return NULL;
596     }
597     if (s[0] == '0' && s[1] == 'x')
598       s += 2;
599     len = p - s;
600     if (len < sizeof(buf) - 1) {
601       strncpy(buf, s, len);
602       buf[len] = 0;
603       errno = 0;
604       val = strtol(buf, &endp, 16);
605       if (val == 0 || *endp != 0 || errno != 0) {
606         aerr("%s num parse fail for '%s'\n", __func__, buf);
607         return NULL;
608       }
609     }
610     p++;
611   }
612   else
613     p = name + 4;
614
615   if ('0' <= *p && *p <= '9')
616     return NULL;
617
618   if (base_val != NULL)
619     *base_val = val;
620   return p;
621 }
622
623 static int guess_lmod_from_name(struct parsed_opr *opr)
624 {
625   if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
626     opr->lmod = OPLM_DWORD;
627     return 1;
628   }
629   if (IS_START(opr->name, "word_")) {
630     opr->lmod = OPLM_WORD;
631     return 1;
632   }
633   if (IS_START(opr->name, "byte_")) {
634     opr->lmod = OPLM_BYTE;
635     return 1;
636   }
637   if (IS_START(opr->name, "qword_")) {
638     opr->lmod = OPLM_QWORD;
639     return 1;
640   }
641   return 0;
642 }
643
644 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
645   const struct parsed_type *c_type)
646 {
647   static const char *qword_types[] = {
648     "uint64_t", "int64_t", "__int64",
649   };
650   static const char *dword_types[] = {
651     "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
652     "WPARAM", "LPARAM", "UINT", "__int32",
653     "LONG", "HIMC", "BOOL", "size_t",
654     "float",
655   };
656   static const char *word_types[] = {
657     "uint16_t", "int16_t", "_WORD", "WORD",
658     "unsigned __int16", "__int16",
659   };
660   static const char *byte_types[] = {
661     "uint8_t", "int8_t", "char",
662     "unsigned __int8", "__int8", "BYTE", "_BYTE",
663     "CHAR", "_UNKNOWN",
664     // structures.. deal the same as with _UNKNOWN for now
665     "CRITICAL_SECTION",
666   };
667   const char *n;
668   int i;
669
670   if (c_type->is_ptr) {
671     *lmod = OPLM_DWORD;
672     return 1;
673   }
674
675   n = skip_type_mod(c_type->name);
676
677   for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
678     if (IS(n, dword_types[i])) {
679       *lmod = OPLM_DWORD;
680       return 1;
681     }
682   }
683
684   for (i = 0; i < ARRAY_SIZE(word_types); i++) {
685     if (IS(n, word_types[i])) {
686       *lmod = OPLM_WORD;
687       return 1;
688     }
689   }
690
691   for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
692     if (IS(n, byte_types[i])) {
693       *lmod = OPLM_BYTE;
694       return 1;
695     }
696   }
697
698   for (i = 0; i < ARRAY_SIZE(qword_types); i++) {
699     if (IS(n, qword_types[i])) {
700       *lmod = OPLM_QWORD;
701       return 1;
702     }
703   }
704
705   return 0;
706 }
707
708 static char *default_cast_to(char *buf, size_t buf_size,
709   struct parsed_opr *opr)
710 {
711   buf[0] = 0;
712
713   if (!opr->is_ptr || strchr(opr->name, '['))
714     return buf;
715   if (opr->pp == NULL || opr->pp->type.name == NULL
716     || opr->pp->is_fptr)
717   {
718     snprintf(buf, buf_size, "%s", "(void *)");
719     return buf;
720   }
721
722   snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
723   return buf;
724 }
725
726 static enum opr_type lmod_from_directive(const char *d)
727 {
728   if (IS(d, "dd"))
729     return OPLM_DWORD;
730   else if (IS(d, "dw"))
731     return OPLM_WORD;
732   else if (IS(d, "db"))
733     return OPLM_BYTE;
734
735   aerr("unhandled directive: '%s'\n", d);
736   return OPLM_UNSPEC;
737 }
738
739 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
740   int *regmask)
741 {
742   opr->type = OPT_REG;
743   opr->reg = reg;
744   opr->lmod = lmod;
745   *regmask |= 1 << reg;
746 }
747
748 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
749   int *extra_offs);
750
751 static int parse_operand(struct parsed_opr *opr,
752   int *regmask, int *regmask_indirect,
753   char words[16][256], int wordc, int w, unsigned int op_flags)
754 {
755   const struct parsed_proto *pp = NULL;
756   enum opr_lenmod tmplmod;
757   unsigned long number;
758   char buf[256];
759   int ret, len;
760   int wordc_in;
761   char *p;
762   int i;
763
764   if (w >= wordc)
765     aerr("parse_operand w %d, wordc %d\n", w, wordc);
766
767   opr->reg = xUNSPEC;
768
769   for (i = w; i < wordc; i++) {
770     len = strlen(words[i]);
771     if (words[i][len - 1] == ',') {
772       words[i][len - 1] = 0;
773       wordc = i + 1;
774       break;
775     }
776   }
777
778   wordc_in = wordc - w;
779
780   if ((op_flags & OPF_JMP) && wordc_in > 0
781       && !('0' <= words[w][0] && words[w][0] <= '9'))
782   {
783     const char *label = NULL;
784
785     if (wordc_in == 3 && !strncmp(words[w], "near", 4)
786      && IS(words[w + 1], "ptr"))
787       label = words[w + 2];
788     else if (wordc_in == 2 && IS(words[w], "short"))
789       label = words[w + 1];
790     else if (wordc_in == 1
791           && strchr(words[w], '[') == NULL
792           && parse_reg(&tmplmod, words[w]) < 0)
793       label = words[w];
794
795     if (label != NULL) {
796       opr->type = OPT_LABEL;
797       ret = check_segment_prefix(label);
798       if (ret != 0) {
799         opr->segment = ret;
800         label += 3;
801       }
802       strcpy(opr->name, label);
803       return wordc;
804     }
805   }
806
807   if (wordc_in >= 3) {
808     if (IS(words[w + 1], "ptr")) {
809       if (IS(words[w], "dword"))
810         opr->lmod = OPLM_DWORD;
811       else if (IS(words[w], "word"))
812         opr->lmod = OPLM_WORD;
813       else if (IS(words[w], "byte"))
814         opr->lmod = OPLM_BYTE;
815       else if (IS(words[w], "qword"))
816         opr->lmod = OPLM_QWORD;
817       else
818         aerr("type parsing failed\n");
819       w += 2;
820       wordc_in = wordc - w;
821     }
822   }
823
824   if (wordc_in == 2) {
825     if (IS(words[w], "offset")) {
826       opr->type = OPT_OFFSET;
827       opr->lmod = OPLM_DWORD;
828       strcpy(opr->name, words[w + 1]);
829       pp = proto_parse(g_fhdr, opr->name, 1);
830       goto do_label;
831     }
832     if (IS(words[w], "(offset")) {
833       p = strchr(words[w + 1], ')');
834       if (p == NULL)
835         aerr("parse of bracketed offset failed\n");
836       *p = 0;
837       opr->type = OPT_OFFSET;
838       strcpy(opr->name, words[w + 1]);
839       return wordc;
840     }
841   }
842
843   if (wordc_in != 1)
844     aerr("parse_operand 1 word expected\n");
845
846   ret = check_segment_prefix(words[w]);
847   if (ret != 0) {
848     opr->segment = ret;
849     memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
850     if (ret == SEG_FS && IS(words[w], "0"))
851       g_seh_found = 1;
852   }
853   strcpy(opr->name, words[w]);
854
855   if (words[w][0] == '[') {
856     opr->type = OPT_REGMEM;
857     ret = sscanf(words[w], "[%[^]]]", opr->name);
858     if (ret != 1)
859       aerr("[] parse failure\n");
860
861     parse_indmode(opr->name, regmask_indirect, 1);
862     if (opr->lmod == OPLM_UNSPEC
863       && parse_stack_el(opr->name, NULL, NULL, 1))
864     {
865       // might be an equ
866       struct parsed_equ *eq =
867         equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
868       if (eq)
869         opr->lmod = eq->lmod;
870
871       // might be unaligned access
872       g_func_lmods |= 1 << OPLM_BYTE;
873     }
874     return wordc;
875   }
876   else if (strchr(words[w], '[')) {
877     // label[reg] form
878     p = strchr(words[w], '[');
879     opr->type = OPT_REGMEM;
880     parse_indmode(p, regmask_indirect, 0);
881     strncpy(buf, words[w], p - words[w]);
882     buf[p - words[w]] = 0;
883     pp = proto_parse(g_fhdr, buf, 1);
884     goto do_label;
885   }
886   else if (('0' <= words[w][0] && words[w][0] <= '9')
887     || words[w][0] == '-')
888   {
889     number = parse_number(words[w], 0);
890     opr->type = OPT_CONST;
891     opr->val = number;
892     printf_number(opr->name, sizeof(opr->name), number);
893     return wordc;
894   }
895
896   ret = parse_reg(&tmplmod, opr->name);
897   if (ret >= 0) {
898     setup_reg_opr(opr, ret, tmplmod, regmask);
899     return wordc;
900   }
901
902   // most likely var in data segment
903   opr->type = OPT_LABEL;
904   pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
905
906 do_label:
907   if (pp != NULL) {
908     if (pp->is_fptr || pp->is_func) {
909       opr->lmod = OPLM_DWORD;
910       opr->is_ptr = 1;
911     }
912     else {
913       tmplmod = OPLM_UNSPEC;
914       if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
915         anote("unhandled C type '%s' for '%s'\n",
916           pp->type.name, opr->name);
917       
918       if (opr->lmod == OPLM_UNSPEC) {
919         opr->lmod = tmplmod;
920         opr->type_from_var = 1;
921       }
922       else if (opr->lmod != tmplmod) {
923         opr->size_mismatch = 1;
924         if (tmplmod < opr->lmod)
925           opr->size_lt = 1;
926       }
927       opr->is_ptr = pp->type.is_ptr;
928     }
929     opr->is_array = pp->type.is_array;
930   }
931   opr->pp = pp;
932
933   if (opr->lmod == OPLM_UNSPEC)
934     guess_lmod_from_name(opr);
935   return wordc;
936 }
937
938 static const struct {
939   const char *name;
940   unsigned int flags;
941 } pref_table[] = {
942   { "rep",    OPF_REP },
943   { "repe",   OPF_REP|OPF_REPZ },
944   { "repz",   OPF_REP|OPF_REPZ },
945   { "repne",  OPF_REP|OPF_REPNZ },
946   { "repnz",  OPF_REP|OPF_REPNZ },
947   { "lock",   OPF_LOCK }, // ignored for now..
948 };
949
950 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
951
952 static const struct {
953   const char *name;
954   enum op_op op;
955   unsigned short minopr;
956   unsigned short maxopr;
957   unsigned int flags;
958   unsigned char pfo;
959   unsigned char pfo_inv;
960 } op_table[] = {
961   { "nop",  OP_NOP,    0, 0, 0 },
962   { "push", OP_PUSH,   1, 1, 0 },
963   { "pop",  OP_POP,    1, 1, OPF_DATA },
964   { "pusha",OP_PUSHA,  0, 0, 0 },
965   { "popa", OP_POPA,   0, 0, OPF_DATA },
966   { "leave",OP_LEAVE,  0, 0, OPF_DATA },
967   { "mov" , OP_MOV,    2, 2, OPF_DATA },
968   { "lea",  OP_LEA,    2, 2, OPF_DATA },
969   { "movzx",OP_MOVZX,  2, 2, OPF_DATA },
970   { "movsx",OP_MOVSX,  2, 2, OPF_DATA },
971   { "xchg", OP_XCHG,   2, 2, OPF_DATA },
972   { "not",  OP_NOT,    1, 1, OPF_DATA },
973   { "xlat", OP_XLAT,   0, 0, OPF_DATA },
974   { "cdq",  OP_CDQ,    0, 0, OPF_DATA },
975   { "bswap",OP_BSWAP,  1, 1, OPF_DATA },
976   { "lodsb",OP_LODS,   0, 0, OPF_DATA },
977   { "lodsw",OP_LODS,   0, 0, OPF_DATA },
978   { "lodsd",OP_LODS,   0, 0, OPF_DATA },
979   { "stosb",OP_STOS,   0, 0, OPF_DATA },
980   { "stosw",OP_STOS,   0, 0, OPF_DATA },
981   { "stosd",OP_STOS,   0, 0, OPF_DATA },
982   { "movsb",OP_MOVS,   0, 0, OPF_DATA },
983   { "movsw",OP_MOVS,   0, 0, OPF_DATA },
984   { "movsd",OP_MOVS,   0, 0, OPF_DATA },
985   { "cmpsb",OP_CMPS,   0, 0, OPF_DATA|OPF_FLAGS },
986   { "cmpsw",OP_CMPS,   0, 0, OPF_DATA|OPF_FLAGS },
987   { "cmpsd",OP_CMPS,   0, 0, OPF_DATA|OPF_FLAGS },
988   { "scasb",OP_SCAS,   0, 0, OPF_DATA|OPF_FLAGS },
989   { "scasw",OP_SCAS,   0, 0, OPF_DATA|OPF_FLAGS },
990   { "scasd",OP_SCAS,   0, 0, OPF_DATA|OPF_FLAGS },
991   { "std",  OP_STD,    0, 0, OPF_DATA }, // special flag
992   { "cld",  OP_CLD,    0, 0, OPF_DATA },
993   { "add",  OP_ADD,    2, 2, OPF_DATA|OPF_FLAGS },
994   { "sub",  OP_SUB,    2, 2, OPF_DATA|OPF_FLAGS },
995   { "and",  OP_AND,    2, 2, OPF_DATA|OPF_FLAGS },
996   { "or",   OP_OR,     2, 2, OPF_DATA|OPF_FLAGS },
997   { "xor",  OP_XOR,    2, 2, OPF_DATA|OPF_FLAGS },
998   { "shl",  OP_SHL,    2, 2, OPF_DATA|OPF_FLAGS },
999   { "shr",  OP_SHR,    2, 2, OPF_DATA|OPF_FLAGS },
1000   { "sal",  OP_SHL,    2, 2, OPF_DATA|OPF_FLAGS },
1001   { "sar",  OP_SAR,    2, 2, OPF_DATA|OPF_FLAGS },
1002   { "shld", OP_SHLD,   3, 3, OPF_DATA|OPF_FLAGS },
1003   { "shrd", OP_SHRD,   3, 3, OPF_DATA|OPF_FLAGS },
1004   { "rol",  OP_ROL,    2, 2, OPF_DATA|OPF_FLAGS },
1005   { "ror",  OP_ROR,    2, 2, OPF_DATA|OPF_FLAGS },
1006   { "rcl",  OP_RCL,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1007   { "rcr",  OP_RCR,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1008   { "adc",  OP_ADC,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1009   { "sbb",  OP_SBB,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1010   { "bsf",  OP_BSF,    2, 2, OPF_DATA|OPF_FLAGS },
1011   { "bsr",  OP_BSR,    2, 2, OPF_DATA|OPF_FLAGS },
1012   { "inc",  OP_INC,    1, 1, OPF_DATA|OPF_FLAGS },
1013   { "dec",  OP_DEC,    1, 1, OPF_DATA|OPF_FLAGS },
1014   { "neg",  OP_NEG,    1, 1, OPF_DATA|OPF_FLAGS },
1015   { "mul",  OP_MUL,    1, 1, OPF_DATA|OPF_FLAGS },
1016   { "imul", OP_IMUL,   1, 3, OPF_DATA|OPF_FLAGS },
1017   { "div",  OP_DIV,    1, 1, OPF_DATA|OPF_FLAGS },
1018   { "idiv", OP_IDIV,   1, 1, OPF_DATA|OPF_FLAGS },
1019   { "test", OP_TEST,   2, 2, OPF_FLAGS },
1020   { "cmp",  OP_CMP,    2, 2, OPF_FLAGS },
1021   { "retn", OP_RET,    0, 1, OPF_TAIL },
1022   { "call", OP_CALL,   1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
1023   { "jmp",  OP_JMP,    1, 1, OPF_JMP },
1024   { "jecxz",OP_JECXZ,  1, 1, OPF_JMP|OPF_CJMP },
1025   { "loop", OP_LOOP,   1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
1026   { "jo",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_O,  0 }, // 70 OF=1
1027   { "jno",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_O,  1 }, // 71 OF=0
1028   { "jc",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_C,  0 }, // 72 CF=1
1029   { "jb",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_C,  0 }, // 72
1030   { "jnc",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_C,  1 }, // 73 CF=0
1031   { "jnb",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_C,  1 }, // 73
1032   { "jae",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_C,  1 }, // 73
1033   { "jz",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_Z,  0 }, // 74 ZF=1
1034   { "je",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_Z,  0 }, // 74
1035   { "jnz",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_Z,  1 }, // 75 ZF=0
1036   { "jne",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_Z,  1 }, // 75
1037   { "jbe",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1038   { "jna",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1039   { "ja",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1040   { "jnbe", OP_JCC,    1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1041   { "js",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_S,  0 }, // 78 SF=1
1042   { "jns",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_S,  1 }, // 79 SF=0
1043   { "jp",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_P,  0 }, // 7a PF=1
1044   { "jpe",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_P,  0 }, // 7a
1045   { "jnp",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_P,  1 }, // 7b PF=0
1046   { "jpo",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_P,  1 }, // 7b
1047   { "jl",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_L,  0 }, // 7c SF!=OF
1048   { "jnge", OP_JCC,    1, 1, OPF_CJMP_CC, PFO_L,  0 }, // 7c
1049   { "jge",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_L,  1 }, // 7d SF=OF
1050   { "jnl",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_L,  1 }, // 7d
1051   { "jle",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1052   { "jng",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1053   { "jg",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1054   { "jnle", OP_JCC,    1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1055   { "seto",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_O,  0 },
1056   { "setno",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_O,  1 },
1057   { "setc",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_C,  0 },
1058   { "setb",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_C,  0 },
1059   { "setnc",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_C,  1 },
1060   { "setae",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_C,  1 },
1061   { "setnb",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_C,  1 },
1062   { "setz",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_Z,  0 },
1063   { "sete",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_Z,  0 },
1064   { "setnz",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_Z,  1 },
1065   { "setne",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_Z,  1 },
1066   { "setbe",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1067   { "setna",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1068   { "seta",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1069   { "setnbe", OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1070   { "sets",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_S,  0 },
1071   { "setns",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_S,  1 },
1072   { "setp",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_P,  0 },
1073   { "setpe",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_P,  0 },
1074   { "setnp",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_P,  1 },
1075   { "setpo",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_P,  1 },
1076   { "setl",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_L,  0 },
1077   { "setnge", OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_L,  0 },
1078   { "setge",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_L,  1 },
1079   { "setnl",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_L,  1 },
1080   { "setle",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1081   { "setng",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1082   { "setg",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1083   { "setnle", OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1084   // x87
1085   { "fld",    OP_FLD,    1, 1, OPF_FPUSH },
1086   { "fild",   OP_FILD,   1, 1, OPF_FPUSH|OPF_FINT },
1087   { "fld1",   OP_FLDc,   0, 0, OPF_FPUSH },
1088   { "fldl2t", OP_FLDc,   0, 0, OPF_FPUSH },
1089   { "fldl2e", OP_FLDc,   0, 0, OPF_FPUSH },
1090   { "fldpi",  OP_FLDc,   0, 0, OPF_FPUSH },
1091   { "fldlg2", OP_FLDc,   0, 0, OPF_FPUSH },
1092   { "fldln2", OP_FLDc,   0, 0, OPF_FPUSH },
1093   { "fldz",   OP_FLDc,   0, 0, OPF_FPUSH },
1094   { "fst",    OP_FST,    1, 1, 0 },
1095   { "fstp",   OP_FST,    1, 1, OPF_FPOP },
1096   { "fist",   OP_FIST,   1, 1, OPF_FINT },
1097   { "fistp",  OP_FIST,   1, 1, OPF_FPOP|OPF_FINT },
1098   { "fadd",   OP_FADD,   0, 2, 0 },
1099   { "faddp",  OP_FADD,   0, 2, OPF_FPOP },
1100   { "fdiv",   OP_FDIV,   0, 2, 0 },
1101   { "fdivp",  OP_FDIV,   0, 2, OPF_FPOP },
1102   { "fmul",   OP_FMUL,   0, 2, 0 },
1103   { "fmulp",  OP_FMUL,   0, 2, OPF_FPOP },
1104   { "fsub",   OP_FSUB,   0, 2, 0 },
1105   { "fsubp",  OP_FSUB,   0, 2, OPF_FPOP },
1106   { "fdivr",  OP_FDIVR,  0, 2, 0 },
1107   { "fdivrp", OP_FDIVR,  0, 2, OPF_FPOP },
1108   { "fsubr",  OP_FSUBR,  0, 2, 0 },
1109   { "fsubrp", OP_FSUBR,  0, 2, OPF_FPOP },
1110   { "fiadd",  OP_FIADD,  1, 1, OPF_FINT },
1111   { "fidiv",  OP_FIDIV,  1, 1, OPF_FINT },
1112   { "fimul",  OP_FIMUL,  1, 1, OPF_FINT },
1113   { "fisub",  OP_FISUB,  1, 1, OPF_FINT },
1114   { "fidivr", OP_FIDIVR, 1, 1, OPF_FINT },
1115   { "fisubr", OP_FISUBR, 1, 1, OPF_FINT },
1116   { "fcom",   OP_FCOM,   0, 1, 0 },
1117   { "fcomp",  OP_FCOM,   0, 1, OPF_FPOP },
1118   { "fcompp", OP_FCOM,   0, 0, OPF_FPOPP },
1119   { "fucom",  OP_FCOM,   0, 1, 0 },
1120   { "fucomp", OP_FCOM,   0, 1, OPF_FPOP },
1121   { "fucompp",OP_FCOM,   0, 0, OPF_FPOPP },
1122   { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1123   { "fchs",   OP_FCHS,   0, 0, 0 },
1124   { "fcos",   OP_FCOS,   0, 0, 0 },
1125   { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1126   { "fptan",  OP_FPTAN,  0, 0, OPF_FPUSH },
1127   { "fsin",   OP_FSIN,   0, 0, 0 },
1128   { "fsqrt",  OP_FSQRT,  0, 0, 0 },
1129   { "fxch",   OP_FXCH,   1, 1, 0 },
1130   { "fyl2x",  OP_FYL2X,  0, 0, OPF_FPOP },
1131   // mmx
1132   { "emms",   OP_EMMS,   0, 0, OPF_DATA },
1133   { "movq",   OP_MOV,    2, 2, OPF_DATA },
1134   // pseudo-ops for lib calls
1135   { "_allshl",OPP_ALLSHL },
1136   { "_allshr",OPP_ALLSHR },
1137   { "_ftol",  OPP_FTOL },
1138   { "_CIpow", OPP_CIPOW },
1139   { "abort",  OPP_ABORT },
1140   // must be last
1141   { "ud2",    OP_UD2 },
1142 };
1143
1144 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1145 {
1146   enum opr_lenmod lmod = OPLM_UNSPEC;
1147   int prefix_flags = 0;
1148   int regmask_ind;
1149   int regmask;
1150   int op_w = 0;
1151   int opr = 0;
1152   int w = 0;
1153   int i, j;
1154
1155   for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1156     if (IS(words[w], pref_table[i].name)) {
1157       prefix_flags = pref_table[i].flags;
1158       break;
1159     }
1160   }
1161
1162   if (prefix_flags) {
1163     if (wordc <= 1)
1164       aerr("lone prefix: '%s'\n", words[0]);
1165     w++;
1166   }
1167
1168   op_w = w;
1169   for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1170     if (IS(words[w], op_table[i].name))
1171       break;
1172   }
1173
1174   if (i == ARRAY_SIZE(op_table)) {
1175     if (!g_skip_func)
1176       aerr("unhandled op: '%s'\n", words[0]);
1177     i--; // OP_UD2
1178   }
1179   w++;
1180
1181   op->op = op_table[i].op;
1182   op->flags = op_table[i].flags | prefix_flags;
1183   op->pfo = op_table[i].pfo;
1184   op->pfo_inv = op_table[i].pfo_inv;
1185   op->regmask_src = op->regmask_dst = 0;
1186   op->asmln = asmln;
1187
1188   if (op->op == OP_UD2)
1189     return;
1190
1191   for (opr = 0; opr < op_table[i].maxopr; opr++) {
1192     if (opr >= op_table[i].minopr && w >= wordc)
1193       break;
1194
1195     regmask = regmask_ind = 0;
1196     w = parse_operand(&op->operand[opr], &regmask, &regmask_ind,
1197       words, wordc, w, op->flags);
1198
1199     if (opr == 0 && (op->flags & OPF_DATA))
1200       op->regmask_dst = regmask;
1201     else
1202       op->regmask_src |= regmask;
1203     op->regmask_src |= regmask_ind;
1204
1205     if (op->operand[opr].lmod != OPLM_UNSPEC)
1206       g_func_lmods |= 1 << op->operand[opr].lmod;
1207   }
1208
1209   if (w < wordc)
1210     aerr("parse_op %s incomplete: %d/%d\n",
1211       words[0], w, wordc);
1212
1213   // special cases
1214   op->operand_cnt = opr;
1215   if (!strncmp(op_table[i].name, "set", 3))
1216     op->operand[0].lmod = OPLM_BYTE;
1217
1218   switch (op->op) {
1219   // first operand is not dst
1220   case OP_CMP:
1221   case OP_TEST:
1222     op->regmask_src |= op->regmask_dst;
1223     op->regmask_dst = 0;
1224     break;
1225
1226   // first operand is src too
1227   case OP_NOT:
1228   case OP_ADD:
1229   case OP_AND:
1230   case OP_OR:
1231   case OP_RCL:
1232   case OP_RCR:
1233   case OP_ADC:
1234   case OP_INC:
1235   case OP_DEC:
1236   case OP_NEG:
1237   case OP_BSWAP:
1238   // more below..
1239     op->regmask_src |= op->regmask_dst;
1240     break;
1241
1242   // special
1243   case OP_XCHG:
1244     op->regmask_src |= op->regmask_dst;
1245     op->regmask_dst |= op->regmask_src;
1246     goto check_align;
1247
1248   case OP_SUB:
1249   case OP_SBB:
1250   case OP_XOR:
1251     if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1252      && op->operand[0].lmod == op->operand[1].lmod
1253      && op->operand[0].reg == op->operand[1].reg
1254      && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1255     {
1256       op->regmask_src = 0;
1257     }
1258     else
1259       op->regmask_src |= op->regmask_dst;
1260     break;
1261
1262   // ops with implicit argumets
1263   case OP_XLAT:
1264     op->operand_cnt = 2;
1265     setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1266     op->regmask_dst = op->regmask_src;
1267     setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1268     break;
1269
1270   case OP_CDQ:
1271     op->operand_cnt = 2;
1272     setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1273     setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1274     break;
1275
1276   case OP_LODS:
1277   case OP_STOS:
1278   case OP_SCAS:
1279     if      (words[op_w][4] == 'b')
1280       lmod = OPLM_BYTE;
1281     else if (words[op_w][4] == 'w')
1282       lmod = OPLM_WORD;
1283     else if (words[op_w][4] == 'd')
1284       lmod = OPLM_DWORD;
1285     j = 0;
1286     op->regmask_src = 0;
1287     setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1288       OPLM_DWORD, &op->regmask_src);
1289     op->regmask_dst = op->regmask_src;
1290     setup_reg_opr(&op->operand[j++], xAX, lmod,
1291       op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1292     if (op->flags & OPF_REP) {
1293       setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1294       op->regmask_dst |= 1 << xCX;
1295     }
1296     op->operand_cnt = j;
1297     break;
1298
1299   case OP_MOVS:
1300   case OP_CMPS:
1301     if      (words[op_w][4] == 'b')
1302       lmod = OPLM_BYTE;
1303     else if (words[op_w][4] == 'w')
1304       lmod = OPLM_WORD;
1305     else if (words[op_w][4] == 'd')
1306       lmod = OPLM_DWORD;
1307     j = 0;
1308     op->regmask_src = 0;
1309     // note: lmod is not correct, don't have where to place it
1310     setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1311     setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1312     if (op->flags & OPF_REP)
1313       setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1314     op->operand_cnt = j;
1315     op->regmask_dst = op->regmask_src;
1316     break;
1317
1318   case OP_LOOP:
1319     op->regmask_dst = 1 << xCX;
1320     // fallthrough
1321   case OP_JECXZ:
1322     op->operand_cnt = 2;
1323     op->regmask_src = 1 << xCX;
1324     op->operand[1].type = OPT_REG;
1325     op->operand[1].reg = xCX;
1326     op->operand[1].lmod = OPLM_DWORD;
1327     break;
1328
1329   case OP_IMUL:
1330     if (op->operand_cnt == 2) {
1331       if (op->operand[0].type != OPT_REG)
1332         aerr("reg expected\n");
1333       op->regmask_src |= 1 << op->operand[0].reg;
1334     }
1335     if (op->operand_cnt != 1)
1336       break;
1337     // fallthrough
1338   case OP_MUL:
1339     // singleop mul
1340     op->regmask_src |= op->regmask_dst;
1341     op->regmask_dst = (1 << xDX) | (1 << xAX);
1342     if (op->operand[0].lmod == OPLM_UNSPEC)
1343       op->operand[0].lmod = OPLM_DWORD;
1344     break;
1345
1346   case OP_DIV:
1347   case OP_IDIV:
1348     // we could set up operands for edx:eax, but there is no real need to
1349     // (see is_opr_modified())
1350     op->regmask_src |= op->regmask_dst;
1351     op->regmask_dst = (1 << xDX) | (1 << xAX);
1352     if (op->operand[0].lmod == OPLM_UNSPEC)
1353       op->operand[0].lmod = OPLM_DWORD;
1354     break;
1355
1356   case OP_SHL:
1357   case OP_SHR:
1358   case OP_SAR:
1359   case OP_ROL:
1360   case OP_ROR:
1361     op->regmask_src |= op->regmask_dst;
1362     if (op->operand[1].lmod == OPLM_UNSPEC)
1363       op->operand[1].lmod = OPLM_BYTE;
1364     break;
1365
1366   case OP_SHLD:
1367   case OP_SHRD:
1368     op->regmask_src |= op->regmask_dst;
1369     if (op->operand[2].lmod == OPLM_UNSPEC)
1370       op->operand[2].lmod = OPLM_BYTE;
1371     break;
1372
1373   case OP_PUSH:
1374     op->regmask_src |= op->regmask_dst;
1375     op->regmask_dst = 0;
1376     if (op->operand[0].lmod == OPLM_UNSPEC
1377         && (op->operand[0].type == OPT_CONST
1378          || op->operand[0].type == OPT_OFFSET
1379          || op->operand[0].type == OPT_LABEL))
1380       op->operand[0].lmod = OPLM_DWORD;
1381     break;
1382
1383   // alignment
1384   case OP_MOV:
1385   check_align:
1386     if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1387      && op->operand[0].lmod == op->operand[1].lmod
1388      && op->operand[0].reg == op->operand[1].reg
1389      && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1390     {
1391       op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1392       op->regmask_src = op->regmask_dst = 0;
1393     }
1394     break;
1395
1396   case OP_LEA:
1397     if (op->operand[0].type == OPT_REG
1398      && op->operand[1].type == OPT_REGMEM)
1399     {
1400       char buf[16];
1401       snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1402       if (IS(buf, op->operand[1].name))
1403         op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1404     }
1405     break;
1406
1407   case OP_CALL:
1408     // trashed regs must be explicitly detected later
1409     op->regmask_dst = 0;
1410     break;
1411
1412   case OP_LEAVE:
1413     op->regmask_dst = (1 << xBP) | (1 << xSP);
1414     op->regmask_src =  1 << xBP;
1415     break;
1416
1417   case OP_FLD:
1418   case OP_FILD:
1419     op->regmask_dst |= mxST0;
1420     break;
1421
1422   case OP_FLDc:
1423     op->regmask_dst |= mxST0;
1424     if      (IS(words[op_w] + 3, "1"))
1425       op->operand[0].val = X87_CONST_1;
1426     else if (IS(words[op_w] + 3, "l2t"))
1427       op->operand[0].val = X87_CONST_L2T;
1428     else if (IS(words[op_w] + 3, "l2e"))
1429       op->operand[0].val = X87_CONST_L2E;
1430     else if (IS(words[op_w] + 3, "pi"))
1431       op->operand[0].val = X87_CONST_PI;
1432     else if (IS(words[op_w] + 3, "lg2"))
1433       op->operand[0].val = X87_CONST_LG2;
1434     else if (IS(words[op_w] + 3, "ln2"))
1435       op->operand[0].val = X87_CONST_LN2;
1436     else if (IS(words[op_w] + 3, "z"))
1437       op->operand[0].val = X87_CONST_Z;
1438     else
1439       aerr("fld what?\n");
1440     break;
1441
1442   case OP_FST:
1443   case OP_FIST:
1444     op->regmask_src |= mxST0;
1445     break;
1446
1447   case OP_FADD:
1448   case OP_FDIV:
1449   case OP_FMUL:
1450   case OP_FSUB:
1451   case OP_FDIVR:
1452   case OP_FSUBR:
1453     op->regmask_src |= mxST0;
1454     if (op->operand_cnt == 2)
1455       op->regmask_src |= op->regmask_dst;
1456     else if (op->operand_cnt == 1) {
1457       memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1458       op->operand[0].type = OPT_REG;
1459       op->operand[0].lmod = OPLM_QWORD;
1460       op->operand[0].reg = xST0;
1461       op->regmask_dst |= mxST0;
1462     }
1463     else
1464       // IDA doesn't use this
1465       aerr("no operands?\n");
1466     break;
1467
1468   case OP_FIADD:
1469   case OP_FIDIV:
1470   case OP_FIMUL:
1471   case OP_FISUB:
1472   case OP_FIDIVR:
1473   case OP_FISUBR:
1474   case OP_FCHS:
1475   case OP_FCOS:
1476   case OP_FSIN:
1477   case OP_FSQRT:
1478   case OP_FXCH:
1479     op->regmask_src |= mxST0;
1480     op->regmask_dst |= mxST0;
1481     break;
1482
1483   case OP_FPATAN:
1484   case OP_FYL2X:
1485     op->regmask_src |= mxST0 | mxST1;
1486     op->regmask_dst |= mxST0;
1487     break;
1488
1489   case OP_FPTAN:
1490     aerr("TODO\n");
1491     break;
1492
1493   case OP_FCOM:
1494     op->regmask_src |= mxST0;
1495     if (op->operand_cnt == 0) {
1496       op->operand_cnt = 1;
1497       op->operand[0].type = OPT_REG;
1498       op->operand[0].lmod = OPLM_QWORD;
1499       op->operand[0].reg = xST1;
1500       op->regmask_src |= mxST1;
1501     }
1502     break;
1503
1504   default:
1505     break;
1506   }
1507
1508   if (op->operand[0].type == OPT_REG
1509    && op->operand[1].type == OPT_CONST)
1510   {
1511     struct parsed_opr *op1 = &op->operand[1];
1512     if ((op->op == OP_AND && op1->val == 0)
1513      || (op->op == OP_OR
1514       && (op1->val == ~0
1515        || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1516        || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1517     {
1518       op->regmask_src = 0;
1519     }
1520   }
1521 }
1522
1523 static const char *op_name(struct parsed_op *po)
1524 {
1525   static char buf[16];
1526   char *p;
1527   int i;
1528
1529   if (po->op == OP_JCC || po->op == OP_SCC) {
1530     p = buf;
1531     *p++ = (po->op == OP_JCC) ? 'j' : 's';
1532     if (po->pfo_inv)
1533       *p++ = 'n';
1534     strcpy(p, parsed_flag_op_names[po->pfo]);
1535     return buf;
1536   }
1537
1538   for (i = 0; i < ARRAY_SIZE(op_table); i++)
1539     if (op_table[i].op == po->op)
1540       return op_table[i].name;
1541
1542   return "???";
1543 }
1544
1545 // debug
1546 static const char *dump_op(struct parsed_op *po)
1547 {
1548   static char out[128];
1549   char *p = out;
1550   int i;
1551
1552   if (po == NULL)
1553     return "???";
1554
1555   snprintf(out, sizeof(out), "%s", op_name(po));
1556   for (i = 0; i < po->operand_cnt; i++) {
1557     p += strlen(p);
1558     if (i > 0)
1559       *p++ = ',';
1560     snprintf(p, sizeof(out) - (p - out),
1561       po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1562       po->operand[i].name);
1563   }
1564
1565   return out;
1566 }
1567
1568 static const char *lmod_type_u(struct parsed_op *po,
1569   enum opr_lenmod lmod)
1570 {
1571   switch (lmod) {
1572   case OPLM_QWORD:
1573     return "u64";
1574   case OPLM_DWORD:
1575     return "u32";
1576   case OPLM_WORD:
1577     return "u16";
1578   case OPLM_BYTE:
1579     return "u8";
1580   default:
1581     ferr(po, "invalid lmod: %d\n", lmod);
1582     return "(_invalid_)";
1583   }
1584 }
1585
1586 static const char *lmod_cast_u(struct parsed_op *po,
1587   enum opr_lenmod lmod)
1588 {
1589   switch (lmod) {
1590   case OPLM_QWORD:
1591     return "";
1592   case OPLM_DWORD:
1593     return "";
1594   case OPLM_WORD:
1595     return "(u16)";
1596   case OPLM_BYTE:
1597     return "(u8)";
1598   default:
1599     ferr(po, "invalid lmod: %d\n", lmod);
1600     return "(_invalid_)";
1601   }
1602 }
1603
1604 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1605   enum opr_lenmod lmod)
1606 {
1607   switch (lmod) {
1608   case OPLM_QWORD:
1609     return "*(u64 *)";
1610   case OPLM_DWORD:
1611     return "*(u32 *)";
1612   case OPLM_WORD:
1613     return "*(u16 *)";
1614   case OPLM_BYTE:
1615     return "*(u8 *)";
1616   default:
1617     ferr(po, "invalid lmod: %d\n", lmod);
1618     return "(_invalid_)";
1619   }
1620 }
1621
1622 static const char *lmod_cast_s(struct parsed_op *po,
1623   enum opr_lenmod lmod)
1624 {
1625   switch (lmod) {
1626   case OPLM_QWORD:
1627     return "(s64)";
1628   case OPLM_DWORD:
1629     return "(s32)";
1630   case OPLM_WORD:
1631     return "(s16)";
1632   case OPLM_BYTE:
1633     return "(s8)";
1634   default:
1635     ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1636     return "(_invalid_)";
1637   }
1638 }
1639
1640 static const char *lmod_cast(struct parsed_op *po,
1641   enum opr_lenmod lmod, int is_signed)
1642 {
1643   return is_signed ?
1644     lmod_cast_s(po, lmod) :
1645     lmod_cast_u(po, lmod);
1646 }
1647
1648 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1649 {
1650   switch (lmod) {
1651   case OPLM_QWORD:
1652     return 8;
1653   case OPLM_DWORD:
1654     return 4;
1655   case OPLM_WORD:
1656     return 2;
1657   case OPLM_BYTE:
1658     return 1;
1659   default:
1660     ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1661     return 0;
1662   }
1663 }
1664
1665 static const char *opr_name(struct parsed_op *po, int opr_num)
1666 {
1667   if (opr_num >= po->operand_cnt)
1668     ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1669   return po->operand[opr_num].name;
1670 }
1671
1672 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1673 {
1674   if (opr_num >= po->operand_cnt)
1675     ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1676   if (po->operand[opr_num].type != OPT_CONST)
1677     ferr(po, "opr %d: const expected\n", opr_num);
1678   return po->operand[opr_num].val;
1679 }
1680
1681 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1682 {
1683   if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1684     ferr(po, "invalid reg: %d\n", popr->reg);
1685   return regs_r32[popr->reg];
1686 }
1687
1688 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1689 {
1690   if      (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1691     *bits = 8;
1692   else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1693     *bits = 16;
1694   else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1695     *bits = 32;
1696   else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1697     *bits = 64;
1698   else
1699     return -1;
1700
1701   *is_signed = cast[1] == 's' ? 1 : 0;
1702   return 0;
1703 }
1704
1705 static int check_deref_cast(const char *cast, int *bits)
1706 {
1707   if      (IS_START(cast, "*(u8 *)"))
1708     *bits = 8;
1709   else if (IS_START(cast, "*(u16 *)"))
1710     *bits = 16;
1711   else if (IS_START(cast, "*(u32 *)"))
1712     *bits = 32;
1713   else if (IS_START(cast, "*(u64 *)"))
1714     *bits = 64;
1715   else
1716     return -1;
1717
1718   return 0;
1719 }
1720
1721 // cast1 is the "final" cast
1722 static const char *simplify_cast(const char *cast1, const char *cast2)
1723 {
1724   static char buf[256];
1725   int bits1, bits2;
1726   int s1, s2;
1727
1728   if (cast1[0] == 0)
1729     return cast2;
1730   if (cast2[0] == 0)
1731     return cast1;
1732   if (IS(cast1, cast2))
1733     return cast1;
1734
1735   if (check_simple_cast(cast1, &bits1, &s1) == 0
1736     && check_simple_cast(cast2, &bits2, &s2) == 0)
1737   {
1738     if (bits1 <= bits2)
1739       return cast1;
1740   }
1741   if (check_simple_cast(cast1, &bits1, &s1) == 0
1742     && check_deref_cast(cast2, &bits2) == 0)
1743   {
1744     if (bits1 == bits2) {
1745       snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1746       return buf;
1747     }
1748   }
1749
1750   if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1751     return cast1;
1752
1753   snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1754   return buf;
1755 }
1756
1757 static const char *simplify_cast_num(const char *cast, unsigned int val)
1758 {
1759   if (IS(cast, "(u8)") && val < 0x100)
1760     return "";
1761   if (IS(cast, "(s8)") && val < 0x80)
1762     return "";
1763   if (IS(cast, "(u16)") && val < 0x10000)
1764     return "";
1765   if (IS(cast, "(s16)") && val < 0x8000)
1766     return "";
1767   if (IS(cast, "(s32)") && val < 0x80000000)
1768     return "";
1769
1770   return cast;
1771 }
1772
1773 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1774   int *extra_offs)
1775 {
1776   const char *p;
1777   char *endp;
1778   int namelen;
1779   int i;
1780
1781   *extra_offs = 0;
1782   namelen = strlen(name);
1783
1784   p = strpbrk(name, "+-");
1785   if (p != NULL) {
1786     namelen = p - name;
1787     if (namelen <= 0)
1788       ferr(po, "equ parse failed for '%s'\n", name);
1789
1790     errno = 0;
1791     *extra_offs = strtol(p, &endp, 16);
1792     if (*endp != 0 || errno != 0)
1793       ferr(po, "equ parse failed for '%s'\n", name);
1794   }
1795
1796   for (i = 0; i < g_eqcnt; i++)
1797     if (strncmp(g_eqs[i].name, name, namelen) == 0
1798      && g_eqs[i].name[namelen] == 0)
1799       break;
1800   if (i >= g_eqcnt) {
1801     if (po != NULL)
1802       ferr(po, "unresolved equ name: '%s'\n", name);
1803     return NULL;
1804   }
1805
1806   return &g_eqs[i];
1807 }
1808
1809 static int is_stack_access(struct parsed_op *po,
1810   const struct parsed_opr *popr)
1811 {
1812   return (parse_stack_el(popr->name, NULL, NULL, 0)
1813     || (g_bp_frame && !(po->flags & OPF_EBP_S)
1814         && IS_START(popr->name, "ebp")));
1815 }
1816
1817 static void parse_stack_access(struct parsed_op *po,
1818   const char *name, char *ofs_reg, int *offset_out,
1819   int *stack_ra_out, const char **bp_arg_out, int is_lea)
1820 {
1821   const char *bp_arg = "";
1822   const char *p = NULL;
1823   struct parsed_equ *eq;
1824   char *endp = NULL;
1825   int stack_ra = 0;
1826   int offset = 0;
1827
1828   ofs_reg[0] = 0;
1829
1830   if (IS_START(name, "ebp-")
1831    || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1832   {
1833     p = name + 4;
1834     if (IS_START(p, "0x"))
1835       p += 2;
1836     errno = 0;
1837     offset = strtoul(p, &endp, 16);
1838     if (name[3] == '-')
1839       offset = -offset;
1840     if (*endp != 0 || errno != 0)
1841       ferr(po, "ebp- parse of '%s' failed\n", name);
1842   }
1843   else {
1844     bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1845     eq = equ_find(po, bp_arg, &offset);
1846     if (eq == NULL)
1847       ferr(po, "detected but missing eq\n");
1848     offset += eq->offset;
1849   }
1850
1851   if (!strncmp(name, "ebp", 3))
1852     stack_ra = 4;
1853
1854   // yes it sometimes LEAs ra for compares..
1855   if (!is_lea && ofs_reg[0] == 0
1856     && stack_ra <= offset && offset < stack_ra + 4)
1857   {
1858     ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1859   }
1860
1861   *offset_out = offset;
1862   if (stack_ra_out)
1863     *stack_ra_out = stack_ra;
1864   if (bp_arg_out)
1865     *bp_arg_out = bp_arg;
1866 }
1867
1868 static int parse_stack_esp_offset(struct parsed_op *po,
1869   const char *name, int *offset_out)
1870 {
1871   char ofs_reg[16] = { 0, };
1872   struct parsed_equ *eq;
1873   const char *bp_arg;
1874   char *endp = NULL;
1875   int base_val = 0;
1876   int offset = 0;
1877
1878   if (strstr(name, "esp") == NULL)
1879     return -1;
1880   bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1881   if (bp_arg == NULL) {
1882     // just plain offset?
1883     if (!IS_START(name, "esp+"))
1884       return -1;
1885     errno = 0;
1886     offset = strtol(name + 4, &endp, 0);
1887     if (endp == NULL || *endp != 0 || errno != 0)
1888       return -1;
1889     *offset_out = offset;
1890     return 0;
1891   }
1892
1893   if (ofs_reg[0] != 0)
1894     return -1;
1895   eq = equ_find(po, bp_arg, &offset);
1896   if (eq == NULL)
1897     ferr(po, "detected but missing eq\n");
1898   offset += eq->offset;
1899   *offset_out = base_val + offset;
1900   return 0;
1901 }
1902
1903 static int stack_frame_access(struct parsed_op *po,
1904   struct parsed_opr *popr, char *buf, size_t buf_size,
1905   const char *name, const char *cast, int is_src, int is_lea)
1906 {
1907   enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1908   const char *prefix = "";
1909   const char *bp_arg = NULL;
1910   char ofs_reg[16] = { 0, };
1911   int i, arg_i, arg_s;
1912   int unaligned = 0;
1913   int stack_ra = 0;
1914   int offset = 0;
1915   int retval = -1;
1916   int sf_ofs;
1917
1918   if (g_bp_frame && (po->flags & OPF_EBP_S)
1919       && !(po->regmask_src & mxSP))
1920     ferr(po, "stack_frame_access while ebp is scratch\n");
1921
1922   parse_stack_access(po, name, ofs_reg, &offset,
1923     &stack_ra, &bp_arg, is_lea);
1924
1925   snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1926
1927   if (offset > stack_ra)
1928   {
1929     arg_i = (offset - stack_ra - 4) / 4;
1930     if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1931     {
1932       if (g_func_pp->is_vararg
1933           && arg_i == g_func_pp->argc_stack && is_lea)
1934       {
1935         // should be va_list
1936         if (cast[0] == 0)
1937           cast = "(u32)";
1938         snprintf(buf, buf_size, "%sap", cast);
1939         return -1;
1940       }
1941       ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1942         offset, bp_arg, arg_i);
1943     }
1944     if (ofs_reg[0] != 0)
1945       ferr(po, "offset reg on arg access?\n");
1946
1947     for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1948       if (g_func_pp->arg[i].reg != NULL)
1949         continue;
1950       if (arg_s == arg_i)
1951         break;
1952       arg_s++;
1953     }
1954     if (i == g_func_pp->argc)
1955       ferr(po, "arg %d not in prototype?\n", arg_i);
1956
1957     popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1958     retval = i;
1959
1960     switch (popr->lmod)
1961     {
1962     case OPLM_BYTE:
1963       if (is_lea)
1964         ferr(po, "lea/byte to arg?\n");
1965       if (is_src && (offset & 3) == 0)
1966         snprintf(buf, buf_size, "%sa%d",
1967           simplify_cast(cast, "(u8)"), i + 1);
1968       else
1969         snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1970           cast, offset & 3, i + 1);
1971       break;
1972
1973     case OPLM_WORD:
1974       if (is_lea)
1975         ferr(po, "lea/word to arg?\n");
1976       if (offset & 1) {
1977         unaligned = 1;
1978         if (!is_src) {
1979           if (offset & 2)
1980             ferr(po, "problematic arg store\n");
1981           snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1982             simplify_cast(cast, "*(u16 *)"), i + 1);
1983         }
1984         else
1985           ferr(po, "unaligned arg word load\n");
1986       }
1987       else if (is_src && (offset & 2) == 0)
1988         snprintf(buf, buf_size, "%sa%d",
1989           simplify_cast(cast, "(u16)"), i + 1);
1990       else
1991         snprintf(buf, buf_size, "%s%sWORD(a%d)",
1992           cast, (offset & 2) ? "HI" : "LO", i + 1);
1993       break;
1994
1995     case OPLM_DWORD:
1996       if (cast[0])
1997         prefix = cast;
1998       else if (is_src)
1999         prefix = "(u32)";
2000
2001       if (offset & 3) {
2002         unaligned = 1;
2003         if (is_lea)
2004           snprintf(buf, buf_size, "(u32)&a%d + %d",
2005             i + 1, offset & 3);
2006         else if (!is_src)
2007           ferr(po, "unaligned arg store\n");
2008         else {
2009           // mov edx, [ebp+arg_4+2]; movsx ecx, dx
2010           snprintf(buf, buf_size, "%s(a%d >> %d)",
2011             prefix, i + 1, (offset & 3) * 8);
2012         }
2013       }
2014       else {
2015         snprintf(buf, buf_size, "%s%sa%d",
2016           prefix, is_lea ? "&" : "", i + 1);
2017       }
2018       break;
2019
2020     case OPLM_QWORD:
2021       ferr_assert(po, !(offset & 7));
2022       if (cast[0])
2023         prefix = cast;
2024       snprintf(buf, buf_size, "%s%sa%d",
2025         prefix, is_lea ? "&" : "", i + 1);
2026       break;
2027
2028     default:
2029       ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
2030     }
2031
2032     if (unaligned)
2033       strcat(g_comment, " unaligned");
2034
2035     // common problem
2036     guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
2037     if (tmp_lmod != OPLM_DWORD
2038       && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
2039                          < lmod_bytes(po, popr->lmod) + (offset & 3))))
2040     {
2041       ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
2042         i + 1, offset, g_func_pp->arg[i].type.name);
2043     }
2044     // can't check this because msvc likes to reuse
2045     // arg space for scratch..
2046     //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
2047     //  ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2048   }
2049   else
2050   {
2051     if (g_stack_fsz == 0)
2052       ferr(po, "stack var access without stackframe\n");
2053     g_stack_frame_used = 1;
2054
2055     sf_ofs = g_stack_fsz + offset;
2056     if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2057       ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2058
2059     if (is_lea)
2060       prefix = "(u32)&";
2061     else
2062       prefix = cast;
2063
2064     switch (popr->lmod)
2065     {
2066     case OPLM_BYTE:
2067       snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2068         prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2069       break;
2070
2071     case OPLM_WORD:
2072       if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2073         // known unaligned or possibly unaligned
2074         strcat(g_comment, " unaligned");
2075         if (prefix[0] == 0)
2076           prefix = "*(u16 *)&";
2077         snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2078           prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2079         break;
2080       }
2081       snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2082       break;
2083
2084     case OPLM_DWORD:
2085       if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2086         // known unaligned or possibly unaligned
2087         strcat(g_comment, " unaligned");
2088         if (prefix[0] == 0)
2089           prefix = "*(u32 *)&";
2090         snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2091           prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2092         break;
2093       }
2094       snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2095       break;
2096
2097     case OPLM_QWORD:
2098       ferr_assert(po, !(sf_ofs & 7));
2099       ferr_assert(po, ofs_reg[0] == 0);
2100       // only used for x87 int64/float, float sets is_lea
2101       if (!is_lea && (po->flags & OPF_FINT))
2102         prefix = "*(s64 *)&";
2103       snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2104       break;
2105
2106     default:
2107       ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2108     }
2109   }
2110
2111   return retval;
2112 }
2113
2114 static void check_func_pp(struct parsed_op *po,
2115   const struct parsed_proto *pp, const char *pfx)
2116 {
2117   enum opr_lenmod tmp_lmod;
2118   char buf[256];
2119   int ret, i;
2120
2121   if (pp->argc_reg != 0) {
2122     if (!g_allow_user_icall && !pp->is_fastcall) {
2123       pp_print(buf, sizeof(buf), pp);
2124       ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2125     }
2126     if (pp->argc_stack > 0 && pp->argc_reg != 2)
2127       ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2128         pfx, pp->argc_reg, pp->argc_stack);
2129   }
2130
2131   // fptrs must use 32bit args, callsite might have no information and
2132   // lack a cast to smaller types, which results in incorrectly masked
2133   // args passed (callee may assume masked args, it does on ARM)
2134   if (!pp->is_osinc) {
2135     for (i = 0; i < pp->argc; i++) {
2136       ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2137       if (ret && tmp_lmod != OPLM_DWORD)
2138         ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2139           i + 1, pp->arg[i].type.name);
2140     }
2141   }
2142 }
2143
2144 static const char *check_label_read_ref(struct parsed_op *po,
2145   const char *name, int *is_import)
2146 {
2147   const struct parsed_proto *pp;
2148
2149   pp = proto_parse(g_fhdr, name, 0);
2150   if (pp == NULL)
2151     ferr(po, "proto_parse failed for ref '%s'\n", name);
2152
2153   if (pp->is_func)
2154     check_func_pp(po, pp, "ref");
2155
2156   if (is_import != NULL)
2157     *is_import = pp->is_import;
2158
2159   return pp->name;
2160 }
2161
2162 static void check_opr(struct parsed_op *po, struct parsed_opr *popr)
2163 {
2164   if (popr->segment == SEG_FS)
2165     ferr(po, "fs: used\n");
2166   if (popr->segment == SEG_GS)
2167     ferr(po, "gs: used\n");
2168 }
2169
2170 static char *out_src_opr(char *buf, size_t buf_size,
2171   struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2172   int is_lea)
2173 {
2174   char tmp1[256], tmp2[256];
2175   char expr[256];
2176   const char *name;
2177   int is_import = 0;
2178   char *p;
2179   int ret;
2180
2181   check_opr(po, popr);
2182
2183   if (cast == NULL)
2184     cast = "";
2185
2186   switch (popr->type) {
2187   case OPT_REG:
2188     if (is_lea)
2189       ferr(po, "lea from reg?\n");
2190
2191     switch (popr->lmod) {
2192     case OPLM_QWORD:
2193       snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2194       break;
2195     case OPLM_DWORD:
2196       snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2197       break;
2198     case OPLM_WORD:
2199       snprintf(buf, buf_size, "%s%s",
2200         simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2201       break;
2202     case OPLM_BYTE:
2203       if (popr->name[1] == 'h') // XXX..
2204         snprintf(buf, buf_size, "%s(%s >> 8)",
2205           simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2206       else
2207         snprintf(buf, buf_size, "%s%s",
2208           simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2209       break;
2210     default:
2211       ferr(po, "invalid src lmod: %d\n", popr->lmod);
2212     }
2213     break;
2214
2215   case OPT_REGMEM:
2216     if (is_stack_access(po, popr)) {
2217       stack_frame_access(po, popr, buf, buf_size,
2218         popr->name, cast, 1, is_lea);
2219       break;
2220     }
2221
2222     strcpy(expr, popr->name);
2223     if (strchr(expr, '[')) {
2224       // special case: '[' can only be left for label[reg] form
2225       ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2226       if (ret != 2)
2227         ferr(po, "parse failure for '%s'\n", expr);
2228       if (tmp1[0] == '(') {
2229         // (off_4FFF50+3)[eax]
2230         p = strchr(tmp1 + 1, ')');
2231         if (p == NULL || p[1] != 0)
2232           ferr(po, "parse failure (2) for '%s'\n", expr);
2233         *p = 0;
2234         memmove(tmp1, tmp1 + 1, strlen(tmp1));
2235       }
2236       snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2237     }
2238
2239     // XXX: do we need more parsing?
2240     if (is_lea) {
2241       snprintf(buf, buf_size, "%s", expr);
2242       break;
2243     }
2244
2245     snprintf(buf, buf_size, "%s(%s)",
2246       simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2247     break;
2248
2249   case OPT_LABEL:
2250     name = check_label_read_ref(po, popr->name, &is_import);
2251     if (is_import)
2252       // for imported data, asm is loading the offset
2253       goto do_offset;
2254
2255     if (cast[0] == 0 && popr->is_ptr)
2256       cast = "(u32)";
2257
2258     if (is_lea)
2259       snprintf(buf, buf_size, "(u32)&%s", name);
2260     else if (popr->size_lt)
2261       snprintf(buf, buf_size, "%s%s%s%s", cast,
2262         lmod_cast_u_ptr(po, popr->lmod),
2263         popr->is_array ? "" : "&", name);
2264     else
2265       snprintf(buf, buf_size, "%s%s%s", cast, name,
2266         popr->is_array ? "[0]" : "");
2267     break;
2268
2269   case OPT_OFFSET:
2270   do_offset:
2271     name = check_label_read_ref(po, popr->name, NULL);
2272     if (cast[0] == 0)
2273       cast = "(u32)";
2274     if (is_lea)
2275       ferr(po, "lea an offset?\n");
2276     snprintf(buf, buf_size, "%s&%s", cast, name);
2277     break;
2278
2279   case OPT_CONST:
2280     if (is_lea)
2281       ferr(po, "lea from const?\n");
2282
2283     printf_number(tmp1, sizeof(tmp1), popr->val);
2284     if (popr->val == 0 && strchr(cast, '*'))
2285       snprintf(buf, buf_size, "NULL");
2286     else
2287       snprintf(buf, buf_size, "%s%s",
2288         simplify_cast_num(cast, popr->val), tmp1);
2289     break;
2290
2291   default:
2292     ferr(po, "invalid src type: %d\n", popr->type);
2293   }
2294
2295   return buf;
2296 }
2297
2298 // note: may set is_ptr (we find that out late for ebp frame..)
2299 static char *out_dst_opr(char *buf, size_t buf_size,
2300         struct parsed_op *po, struct parsed_opr *popr)
2301 {
2302   check_opr(po, popr);
2303
2304   switch (popr->type) {
2305   case OPT_REG:
2306     switch (popr->lmod) {
2307     case OPLM_QWORD:
2308       snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2309       break;
2310     case OPLM_DWORD:
2311       snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2312       break;
2313     case OPLM_WORD:
2314       // ugh..
2315       snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2316       break;
2317     case OPLM_BYTE:
2318       // ugh..
2319       if (popr->name[1] == 'h') // XXX..
2320         snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2321       else
2322         snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2323       break;
2324     default:
2325       ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2326     }
2327     break;
2328
2329   case OPT_REGMEM:
2330     if (is_stack_access(po, popr)) {
2331       stack_frame_access(po, popr, buf, buf_size,
2332         popr->name, "", 0, 0);
2333       break;
2334     }
2335
2336     return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2337
2338   case OPT_LABEL:
2339     if (popr->size_mismatch)
2340       snprintf(buf, buf_size, "%s%s%s",
2341         lmod_cast_u_ptr(po, popr->lmod),
2342         popr->is_array ? "" : "&", popr->name);
2343     else
2344       snprintf(buf, buf_size, "%s%s", popr->name,
2345         popr->is_array ? "[0]" : "");
2346     break;
2347
2348   default:
2349     ferr(po, "invalid dst type: %d\n", popr->type);
2350   }
2351
2352   return buf;
2353 }
2354
2355 static char *out_src_opr_u32(char *buf, size_t buf_size,
2356         struct parsed_op *po, struct parsed_opr *popr)
2357 {
2358   return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2359 }
2360
2361 static char *out_opr_float(char *buf, size_t buf_size,
2362   struct parsed_op *po, struct parsed_opr *popr, int is_src,
2363   int need_float_stack)
2364 {
2365   const char *cast = NULL;
2366   char tmp[256];
2367   union {
2368     float f;
2369     int i;
2370   } u;
2371
2372   switch (popr->type) {
2373   case OPT_REG:
2374     if (popr->reg < xST0 || popr->reg > xST7) {
2375       // func arg
2376       ferr_assert(po, po->op == OP_PUSH);
2377       ferr_assert(po, popr->lmod == OPLM_DWORD);
2378       snprintf(buf, buf_size, "*(float *)&%s", opr_reg_p(po, popr));
2379       break;
2380     }
2381
2382     if (need_float_stack) {
2383       if (popr->reg == xST0)
2384         snprintf(buf, buf_size, "f_st[f_stp & 7]");
2385       else
2386         snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2387           popr->reg - xST0);
2388     }
2389     else
2390       snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2391     break;
2392
2393   case OPT_REGMEM:
2394     if (popr->lmod == OPLM_QWORD && is_stack_access(po, popr)) {
2395       stack_frame_access(po, popr, buf, buf_size,
2396         popr->name, "", is_src, 0);
2397       break;
2398     }
2399     // fallthrough
2400   case OPT_LABEL:
2401   case OPT_OFFSET:
2402     switch (popr->lmod) {
2403     case OPLM_QWORD:
2404       cast = "double";
2405       break;
2406     case OPLM_DWORD:
2407       cast = "float";
2408       break;
2409     default:
2410       ferr(po, "unhandled lmod: %d\n", popr->lmod);
2411       break;
2412     }
2413     out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2414     snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2415     break;
2416
2417   case OPT_CONST:
2418     // only for func float args pushes
2419     ferr_assert(po, po->op == OP_PUSH);
2420     u.i = po->operand[0].val;
2421     if (ceilf(u.f) == u.f)
2422       snprintf(buf, buf_size, "%.1ff", u.f);
2423     else
2424       snprintf(buf, buf_size, "%.8ff", u.f);
2425     break;
2426
2427   default:
2428     ferr(po, "invalid float type: %d\n", popr->type);
2429   }
2430
2431   return buf;
2432 }
2433
2434 static char *out_src_opr_float(char *buf, size_t buf_size,
2435   struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2436 {
2437   return out_opr_float(buf, buf_size, po, popr, 1, need_float_stack);
2438 }
2439
2440 static char *out_dst_opr_float(char *buf, size_t buf_size,
2441   struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2442 {
2443   return out_opr_float(buf, buf_size, po, popr, 0, need_float_stack);
2444 }
2445
2446 static void out_test_for_cc(char *buf, size_t buf_size,
2447   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2448   enum opr_lenmod lmod, const char *expr)
2449 {
2450   const char *cast, *scast;
2451
2452   cast = lmod_cast_u(po, lmod);
2453   scast = lmod_cast_s(po, lmod);
2454
2455   switch (pfo) {
2456   case PFO_Z:
2457   case PFO_BE: // CF==1||ZF==1; CF=0
2458     snprintf(buf, buf_size, "(%s%s %s 0)",
2459       cast, expr, is_inv ? "!=" : "==");
2460     break;
2461
2462   case PFO_S:
2463   case PFO_L: // SF!=OF; OF=0
2464     snprintf(buf, buf_size, "(%s%s %s 0)",
2465       scast, expr, is_inv ? ">=" : "<");
2466     break;
2467
2468   case PFO_LE: // ZF==1||SF!=OF; OF=0
2469     snprintf(buf, buf_size, "(%s%s %s 0)",
2470       scast, expr, is_inv ? ">" : "<=");
2471     break;
2472
2473   case PFO_C: // CF=0
2474   case PFO_O: // OF=0
2475     snprintf(buf, buf_size, "(%d)", !!is_inv);
2476     break;
2477
2478   case PFO_P: // PF==1
2479     snprintf(buf, buf_size, "(%sdo_parity(%s))",
2480       is_inv ? "!" : "", expr);
2481     break;
2482
2483   default:
2484     ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2485   }
2486 }
2487
2488 static void out_cmp_for_cc(char *buf, size_t buf_size,
2489   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2490   int is_neg)
2491 {
2492   const char *cast, *scast, *cast_use;
2493   char buf1[256], buf2[256];
2494   enum opr_lenmod lmod;
2495
2496   if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2497     ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2498       po->operand[0].lmod, po->operand[1].lmod);
2499   lmod = po->operand[0].lmod;
2500
2501   cast = lmod_cast_u(po, lmod);
2502   scast = lmod_cast_s(po, lmod);
2503
2504   switch (pfo) {
2505   case PFO_C:
2506   case PFO_Z:
2507   case PFO_BE: // !a
2508     cast_use = cast;
2509     break;
2510
2511   case PFO_S:
2512   case PFO_L: // !ge
2513   case PFO_LE:
2514     cast_use = scast;
2515     break;
2516
2517   default:
2518     ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2519   }
2520
2521   out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2522   if (po->op == OP_DEC)
2523     snprintf(buf2, sizeof(buf2), "1");
2524   else {
2525     char cast_op2[64];
2526     snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2527     if (is_neg)
2528       strcat(cast_op2, "-");
2529     out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2530   }
2531
2532   switch (pfo) {
2533   case PFO_C:
2534     // note: must be unsigned compare
2535     snprintf(buf, buf_size, "(%s %s %s)",
2536       buf1, is_inv ? ">=" : "<", buf2);
2537     break;
2538
2539   case PFO_Z:
2540     snprintf(buf, buf_size, "(%s %s %s)",
2541       buf1, is_inv ? "!=" : "==", buf2);
2542     break;
2543
2544   case PFO_BE: // !a
2545     // note: must be unsigned compare
2546     snprintf(buf, buf_size, "(%s %s %s)",
2547       buf1, is_inv ? ">" : "<=", buf2);
2548
2549     // annoying case
2550     if (is_inv && lmod == OPLM_BYTE
2551       && po->operand[1].type == OPT_CONST
2552       && po->operand[1].val == 0xff)
2553     {
2554       snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2555       snprintf(buf, buf_size, "(0)");
2556     }
2557     break;
2558
2559   // note: must be signed compare
2560   case PFO_S:
2561     snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2562       scast, buf1, buf2, is_inv ? ">=" : "<");
2563     break;
2564
2565   case PFO_L: // !ge
2566     snprintf(buf, buf_size, "(%s %s %s)",
2567       buf1, is_inv ? ">=" : "<", buf2);
2568     break;
2569
2570   case PFO_LE: // !g
2571     snprintf(buf, buf_size, "(%s %s %s)",
2572       buf1, is_inv ? ">" : "<=", buf2);
2573     break;
2574
2575   default:
2576     break;
2577   }
2578 }
2579
2580 static void out_cmp_test(char *buf, size_t buf_size,
2581   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2582 {
2583   char buf1[256], buf2[256], buf3[256];
2584
2585   if (po->op == OP_TEST) {
2586     if (IS(opr_name(po, 0), opr_name(po, 1))) {
2587       out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2588     }
2589     else {
2590       out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2591       out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2592       snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2593     }
2594     out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2595       po->operand[0].lmod, buf3);
2596   }
2597   else if (po->op == OP_CMP) {
2598     out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2599   }
2600   else
2601     ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2602 }
2603
2604 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2605         struct parsed_opr *popr2)
2606 {
2607   if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2608     ferr(po, "missing lmod for both operands\n");
2609
2610   if (popr1->lmod == OPLM_UNSPEC)
2611     popr1->lmod = popr2->lmod;
2612   else if (popr2->lmod == OPLM_UNSPEC)
2613     popr2->lmod = popr1->lmod;
2614   else if (popr1->lmod != popr2->lmod) {
2615     if (popr1->type_from_var) {
2616       popr1->size_mismatch = 1;
2617       if (popr1->lmod < popr2->lmod)
2618         popr1->size_lt = 1;
2619       popr1->lmod = popr2->lmod;
2620     }
2621     else if (popr2->type_from_var) {
2622       popr2->size_mismatch = 1;
2623       if (popr2->lmod < popr1->lmod)
2624         popr2->size_lt = 1;
2625       popr2->lmod = popr1->lmod;
2626     }
2627     else
2628       ferr(po, "conflicting lmods: %d vs %d\n",
2629         popr1->lmod, popr2->lmod);
2630   }
2631 }
2632
2633 static const char *op_to_c(struct parsed_op *po)
2634 {
2635   switch (po->op)
2636   {
2637     case OP_ADD:
2638     case OP_ADC:
2639       return "+";
2640     case OP_SUB:
2641     case OP_SBB:
2642       return "-";
2643     case OP_AND:
2644       return "&";
2645     case OP_OR:
2646       return "|";
2647     case OP_XOR:
2648       return "^";
2649     case OP_SHL:
2650       return "<<";
2651     case OP_SHR:
2652       return ">>";
2653     case OP_MUL:
2654     case OP_IMUL:
2655       return "*";
2656     default:
2657       ferr(po, "op_to_c was supplied with %d\n", po->op);
2658   }
2659 }
2660
2661 // last op in stream - unconditional branch or ret
2662 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2663   || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2664       && ops[_i].op != OP_CALL))
2665
2666 #define check_i(po, i) \
2667   if ((i) < 0) \
2668     ferr(po, "bad " #i ": %d\n", i)
2669
2670 // note: this skips over calls and rm'd stuff assuming they're handled
2671 // so it's intended to use at one of final passes
2672 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2673   int depth, int seen_noreturn, int flags_set)
2674 {
2675   struct parsed_op *po;
2676   int relevant;
2677   int ret = 0;
2678   int j;
2679
2680   for (; i < opcnt; i++) {
2681     po = &ops[i];
2682     if (po->cc_scratch == magic)
2683       return ret; // already checked
2684     po->cc_scratch = magic;
2685
2686     if (po->flags & OPF_TAIL) {
2687       if (po->op == OP_CALL) {
2688         if (po->pp != NULL && po->pp->is_noreturn)
2689           seen_noreturn = 1;
2690         else
2691           goto out;
2692       }
2693       else
2694         goto out;
2695     }
2696
2697     if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2698       continue;
2699
2700     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2701       if (po->btj != NULL) {
2702         // jumptable
2703         for (j = 0; j < po->btj->count; j++) {
2704           check_i(po, po->btj->d[j].bt_i);
2705           ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2706                    depth, seen_noreturn, flags_set);
2707           if (ret < 0)
2708             return ret; // dead end
2709         }
2710         return ret;
2711       }
2712
2713       check_i(po, po->bt_i);
2714       if (po->flags & OPF_CJMP) {
2715         ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2716                  depth, seen_noreturn, flags_set);
2717         if (ret < 0)
2718           return ret; // dead end
2719       }
2720       else {
2721         i = po->bt_i - 1;
2722       }
2723       continue;
2724     }
2725
2726     relevant = 0;
2727     if ((po->op == OP_POP || po->op == OP_PUSH)
2728       && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2729     {
2730       relevant = 1;
2731     }
2732
2733     if (po->op == OP_PUSH) {
2734       depth++;
2735     }
2736     else if (po->op == OP_POP) {
2737       if (relevant && depth == 0) {
2738         po->flags |= flags_set;
2739         return 1;
2740       }
2741       depth--;
2742     }
2743   }
2744
2745 out:
2746   // for noreturn, assume msvc skipped stack cleanup
2747   return seen_noreturn ? 1 : -1;
2748 }
2749
2750 // scan for 'reg' pop backwards starting from i
2751 // intended to use for register restore search, so other reg
2752 // references are considered an error
2753 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2754 {
2755   struct parsed_op *po;
2756   struct label_ref *lr;
2757   int ret = 0;
2758
2759   ops[i].cc_scratch = magic;
2760
2761   while (1)
2762   {
2763     if (g_labels[i] != NULL) {
2764       lr = &g_label_refs[i];
2765       for (; lr != NULL; lr = lr->next) {
2766         check_i(&ops[i], lr->i);
2767         ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2768         if (ret < 0)
2769           return ret;
2770       }
2771       if (i > 0 && LAST_OP(i - 1))
2772         return ret;
2773     }
2774
2775     i--;
2776     if (i < 0)
2777       break;
2778
2779     if (ops[i].cc_scratch == magic)
2780       return ret;
2781     ops[i].cc_scratch = magic;
2782
2783     po = &ops[i];
2784     if (po->op == OP_POP && po->operand[0].reg == reg) {
2785       if (po->flags & (OPF_RMD|OPF_DONE))
2786         return -1;
2787
2788       po->flags |= set_flags;
2789       return 1;
2790     }
2791
2792     // this also covers the case where we reach corresponding push
2793     if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2794       return -1;
2795   }
2796
2797   // nothing interesting on this path,
2798   // still return ret for something recursive calls could find
2799   return ret;
2800 }
2801
2802 static void find_reachable_exits(int i, int opcnt, int magic,
2803   int *exits, int *exit_count)
2804 {
2805   struct parsed_op *po;
2806   int j;
2807
2808   for (; i < opcnt; i++)
2809   {
2810     po = &ops[i];
2811     if (po->cc_scratch == magic)
2812       return;
2813     po->cc_scratch = magic;
2814
2815     if (po->flags & OPF_TAIL) {
2816       ferr_assert(po, *exit_count < MAX_EXITS);
2817       exits[*exit_count] = i;
2818       (*exit_count)++;
2819       return;
2820     }
2821
2822     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2823       if (po->flags & OPF_RMD)
2824         continue;
2825
2826       if (po->btj != NULL) {
2827         for (j = 0; j < po->btj->count; j++) {
2828           check_i(po, po->btj->d[j].bt_i);
2829           find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2830                   exits, exit_count);
2831         }
2832         return;
2833       }
2834
2835       check_i(po, po->bt_i);
2836       if (po->flags & OPF_CJMP)
2837         find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2838       else
2839         i = po->bt_i - 1;
2840       continue;
2841     }
2842   }
2843 }
2844
2845 // scan for 'reg' pop backwards starting from exits (all paths)
2846 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2847 {
2848   static int exits[MAX_EXITS];
2849   static int exit_count;
2850   int found = 0;
2851   int e, j, ret;
2852
2853   if (!set_flags) {
2854     exit_count = 0;
2855     find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2856       &exit_count);
2857     ferr_assert(&ops[i], exit_count > 0);
2858   }
2859
2860   for (j = 0; j < exit_count; j++) {
2861     e = exits[j];
2862     ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2863             reg, set_flags);
2864     if (ret != -1) {
2865       found |= ret;
2866       continue;
2867     }
2868     if (ops[e].op == OP_CALL && ops[e].pp != NULL
2869       && ops[e].pp->is_noreturn)
2870     {
2871       // assume stack cleanup was skipped
2872       continue;
2873     }
2874     return -1;
2875   }
2876
2877   return found;
2878 }
2879
2880 // scan for one or more pop of push <const>
2881 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2882   int push_i, int is_probe)
2883 {
2884   struct parsed_op *po;
2885   struct label_ref *lr;
2886   int ret = 0;
2887   int j;
2888
2889   for (; i < opcnt; i++)
2890   {
2891     po = &ops[i];
2892     if (po->cc_scratch == magic)
2893       return ret; // already checked
2894     po->cc_scratch = magic;
2895
2896     if (po->flags & OPF_JMP) {
2897       if (po->flags & OPF_RMD)
2898         continue;
2899       if (po->op == OP_CALL)
2900         return -1;
2901
2902       if (po->btj != NULL) {
2903         for (j = 0; j < po->btj->count; j++) {
2904           check_i(po, po->btj->d[j].bt_i);
2905           ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2906                   push_i, is_probe);
2907           if (ret < 0)
2908             return ret;
2909         }
2910         return ret;
2911       }
2912
2913       check_i(po, po->bt_i);
2914       if (po->flags & OPF_CJMP) {
2915         ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2916                  is_probe);
2917         if (ret < 0)
2918           return ret;
2919       }
2920       else {
2921         i = po->bt_i - 1;
2922       }
2923       continue;
2924     }
2925
2926     if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2927       return -1;
2928
2929     if (g_labels[i] != NULL) {
2930       // all refs must be visited
2931       lr = &g_label_refs[i];
2932       for (; lr != NULL; lr = lr->next) {
2933         check_i(po, lr->i);
2934         if (ops[lr->i].cc_scratch != magic)
2935           return -1;
2936       }
2937       if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2938         return -1;
2939     }
2940
2941     if (po->op == OP_POP)
2942     {
2943       if (po->flags & (OPF_RMD|OPF_DONE))
2944         return -1;
2945
2946       if (!is_probe) {
2947         po->flags |= OPF_DONE;
2948         po->datap = &ops[push_i];
2949       }
2950       return 1;
2951     }
2952   }
2953
2954   return -1;
2955 }
2956
2957 static void scan_for_pop_const(int i, int opcnt, int magic)
2958 {
2959   int ret;
2960
2961   ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2962   if (ret == 1) {
2963     ops[i].flags |= OPF_RMD | OPF_DONE;
2964     scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2965   }
2966 }
2967
2968 // check if all branch targets within a marked path are also marked
2969 // note: the path checked must not be empty or end with a branch
2970 static int check_path_branches(int opcnt, int magic)
2971 {
2972   struct parsed_op *po;
2973   int i, j;
2974
2975   for (i = 0; i < opcnt; i++) {
2976     po = &ops[i];
2977     if (po->cc_scratch != magic)
2978       continue;
2979
2980     if (po->flags & OPF_JMP) {
2981       if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2982         continue;
2983
2984       if (po->btj != NULL) {
2985         for (j = 0; j < po->btj->count; j++) {
2986           check_i(po, po->btj->d[j].bt_i);
2987           if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2988             return 0;
2989         }
2990       }
2991
2992       check_i(po, po->bt_i);
2993       if (ops[po->bt_i].cc_scratch != magic)
2994         return 0;
2995       if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2996         return 0;
2997     }
2998   }
2999
3000   return 1;
3001 }
3002
3003 // scan for multiple pushes for given pop
3004 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
3005   int is_probe)
3006 {
3007   int reg = ops[pop_i].operand[0].reg;
3008   struct parsed_op *po;
3009   struct label_ref *lr;
3010   int ret = 0;
3011
3012   ops[i].cc_scratch = magic;
3013
3014   while (1)
3015   {
3016     if (g_labels[i] != NULL) {
3017       lr = &g_label_refs[i];
3018       for (; lr != NULL; lr = lr->next) {
3019         check_i(&ops[i], lr->i);
3020         ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
3021         if (ret < 0)
3022           return ret;
3023       }
3024       if (i > 0 && LAST_OP(i - 1))
3025         return ret;
3026     }
3027
3028     i--;
3029     if (i < 0)
3030       break;
3031
3032     if (ops[i].cc_scratch == magic)
3033       return ret;
3034     ops[i].cc_scratch = magic;
3035
3036     po = &ops[i];
3037     if (po->op == OP_CALL)
3038       return -1;
3039     if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
3040       return -1;
3041
3042     if (po->op == OP_PUSH)
3043     {
3044       if (po->datap != NULL)
3045         return -1;
3046       if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
3047         // leave this case for reg save/restore handlers
3048         return -1;
3049
3050       if (!is_probe) {
3051         po->flags |= OPF_PPUSH | OPF_DONE;
3052         po->datap = &ops[pop_i];
3053       }
3054       return 1;
3055     }
3056   }
3057
3058   return -1;
3059 }
3060
3061 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
3062 {
3063   int magic = i + opcnt * 14;
3064   int ret;
3065
3066   ret = scan_pushes_for_pop_r(i, magic, i, 1);
3067   if (ret == 1) {
3068     ret = check_path_branches(opcnt, magic);
3069     if (ret == 1) {
3070       ops[i].flags |= OPF_PPUSH | OPF_DONE;
3071       *regmask_pp |= 1 << ops[i].operand[0].reg;
3072       scan_pushes_for_pop_r(i, magic + 1, i, 0);
3073     }
3074   }
3075 }
3076
3077 static void scan_propagate_df(int i, int opcnt)
3078 {
3079   struct parsed_op *po = &ops[i];
3080   int j;
3081
3082   for (; i < opcnt; i++) {
3083     po = &ops[i];
3084     if (po->flags & OPF_DF)
3085       return; // already resolved
3086     po->flags |= OPF_DF;
3087
3088     if (po->op == OP_CALL)
3089       ferr(po, "call with DF set?\n");
3090
3091     if (po->flags & OPF_JMP) {
3092       if (po->btj != NULL) {
3093         // jumptable
3094         for (j = 0; j < po->btj->count; j++) {
3095           check_i(po, po->btj->d[j].bt_i);
3096           scan_propagate_df(po->btj->d[j].bt_i, opcnt);
3097         }
3098         return;
3099       }
3100
3101       if (po->flags & OPF_RMD)
3102         continue;
3103       check_i(po, po->bt_i);
3104       if (po->flags & OPF_CJMP)
3105         scan_propagate_df(po->bt_i, opcnt);
3106       else
3107         i = po->bt_i - 1;
3108       continue;
3109     }
3110
3111     if (po->flags & OPF_TAIL)
3112       break;
3113
3114     if (po->op == OP_CLD) {
3115       po->flags |= OPF_RMD | OPF_DONE;
3116       return;
3117     }
3118   }
3119
3120   ferr(po, "missing DF clear?\n");
3121 }
3122
3123 // is operand 'opr' referenced by parsed_op 'po'?
3124 static int is_opr_referenced(const struct parsed_opr *opr,
3125   const struct parsed_op *po)
3126 {
3127   int i, mask;
3128
3129   if (opr->type == OPT_REG) {
3130     mask = po->regmask_dst | po->regmask_src;
3131     if (po->op == OP_CALL)
3132       mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3133     if ((1 << opr->reg) & mask)
3134       return 1;
3135     else
3136       return 0;
3137   }
3138
3139   for (i = 0; i < po->operand_cnt; i++)
3140     if (IS(po->operand[0].name, opr->name))
3141       return 1;
3142
3143   return 0;
3144 }
3145
3146 // is operand 'opr' read by parsed_op 'po'?
3147 static int is_opr_read(const struct parsed_opr *opr,
3148   const struct parsed_op *po)
3149 {
3150   if (opr->type == OPT_REG) {
3151     if (po->regmask_src & (1 << opr->reg))
3152       return 1;
3153     else
3154       return 0;
3155   }
3156
3157   // yes I'm lazy
3158   return 0;
3159 }
3160
3161 // is operand 'opr' modified by parsed_op 'po'?
3162 static int is_opr_modified(const struct parsed_opr *opr,
3163   const struct parsed_op *po)
3164 {
3165   int mask;
3166
3167   if (opr->type == OPT_REG) {
3168     if (po->op == OP_CALL) {
3169       mask = po->regmask_dst;
3170       mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3171       if (mask & (1 << opr->reg))
3172         return 1;
3173       else
3174         return 0;
3175     }
3176
3177     if (po->regmask_dst & (1 << opr->reg))
3178       return 1;
3179     else
3180       return 0;
3181   }
3182
3183   return IS(po->operand[0].name, opr->name);
3184 }
3185
3186 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3187 static int is_any_opr_modified(const struct parsed_op *po_test,
3188   const struct parsed_op *po, int c_mode)
3189 {
3190   int mask;
3191   int i;
3192
3193   if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3194     return 0;
3195
3196   if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3197     return 0;
3198
3199   if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3200     return 1;
3201
3202   // in reality, it can wreck any register, but in decompiled C
3203   // version it can only overwrite eax or edx:eax
3204   mask = (1 << xAX) | (1 << xDX);
3205   if (!c_mode)
3206     mask |= 1 << xCX;
3207
3208   if (po->op == OP_CALL
3209    && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3210     return 1;
3211
3212   for (i = 0; i < po_test->operand_cnt; i++)
3213     if (IS(po_test->operand[i].name, po->operand[0].name))
3214       return 1;
3215
3216   return 0;
3217 }
3218
3219 // scan for any po_test operand modification in range given
3220 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3221   int c_mode)
3222 {
3223   if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3224     return -1;
3225
3226   for (; i < opcnt; i++) {
3227     if (is_any_opr_modified(po_test, &ops[i], c_mode))
3228       return i;
3229   }
3230
3231   return -1;
3232 }
3233
3234 // scan for po_test operand[0] modification in range given
3235 static int scan_for_mod_opr0(struct parsed_op *po_test,
3236   int i, int opcnt)
3237 {
3238   for (; i < opcnt; i++) {
3239     if (is_opr_modified(&po_test->operand[0], &ops[i]))
3240       return i;
3241   }
3242
3243   return -1;
3244 }
3245
3246 static int try_resolve_const(int i, const struct parsed_opr *opr,
3247   int magic, unsigned int *val);
3248
3249 static int scan_for_flag_set(int i, int opcnt, int magic,
3250   int *branched, int *setters, int *setter_cnt)
3251 {
3252   struct label_ref *lr;
3253   int ret;
3254
3255   while (i >= 0) {
3256     if (ops[i].cc_scratch == magic) {
3257       // is this a problem?
3258       //ferr(&ops[i], "%s looped\n", __func__);
3259       return 0;
3260     }
3261     ops[i].cc_scratch = magic;
3262
3263     if (g_labels[i] != NULL) {
3264       *branched = 1;
3265
3266       lr = &g_label_refs[i];
3267       for (; lr->next; lr = lr->next) {
3268         check_i(&ops[i], lr->i);
3269         ret = scan_for_flag_set(lr->i, opcnt, magic,
3270                 branched, setters, setter_cnt);
3271         if (ret < 0)
3272           return ret;
3273       }
3274
3275       check_i(&ops[i], lr->i);
3276       if (i > 0 && LAST_OP(i - 1)) {
3277         i = lr->i;
3278         continue;
3279       }
3280       ret = scan_for_flag_set(lr->i, opcnt, magic,
3281               branched, setters, setter_cnt);
3282       if (ret < 0)
3283         return ret;
3284     }
3285     i--;
3286
3287     if (ops[i].flags & OPF_FLAGS) {
3288       setters[*setter_cnt] = i;
3289       (*setter_cnt)++;
3290
3291       if (ops[i].flags & OPF_REP) {
3292         struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3293         unsigned int uval;
3294
3295         ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3296         if (ret != 1 || uval == 0) {
3297           // can't treat it as full setter because of ecx=0 case,
3298           // also disallow delayed compare
3299           *branched = 1;
3300           continue;
3301         }
3302       }
3303
3304       return 0;
3305     }
3306
3307     if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3308       return -1;
3309   }
3310
3311   return -1;
3312 }
3313
3314 // scan back for cdq, if anything modifies edx, fail
3315 static int scan_for_cdq_edx(int i)
3316 {
3317   while (i >= 0) {
3318     if (g_labels[i] != NULL) {
3319       if (g_label_refs[i].next != NULL)
3320         return -1;
3321       if (i > 0 && LAST_OP(i - 1)) {
3322         i = g_label_refs[i].i;
3323         continue;
3324       }
3325       return -1;
3326     }
3327     i--;
3328
3329     if (ops[i].op == OP_CDQ)
3330       return i;
3331
3332     if (ops[i].regmask_dst & (1 << xDX))
3333       return -1;
3334   }
3335
3336   return -1;
3337 }
3338
3339 static int scan_for_reg_clear(int i, int reg)
3340 {
3341   while (i >= 0) {
3342     if (g_labels[i] != NULL) {
3343       if (g_label_refs[i].next != NULL)
3344         return -1;
3345       if (i > 0 && LAST_OP(i - 1)) {
3346         i = g_label_refs[i].i;
3347         continue;
3348       }
3349       return -1;
3350     }
3351     i--;
3352
3353     if (ops[i].op == OP_XOR
3354      && ops[i].operand[0].lmod == OPLM_DWORD
3355      && ops[i].operand[0].reg == ops[i].operand[1].reg
3356      && ops[i].operand[0].reg == reg)
3357       return i;
3358
3359     if (ops[i].regmask_dst & (1 << reg))
3360       return -1;
3361   }
3362
3363   return -1;
3364 }
3365
3366 static void patch_esp_adjust(struct parsed_op *po, int adj)
3367 {
3368   ferr_assert(po, po->op == OP_ADD);
3369   ferr_assert(po, IS(opr_name(po, 0), "esp"));
3370   ferr_assert(po, po->operand[1].type == OPT_CONST);
3371
3372   // this is a bit of a hack, but deals with use of
3373   // single adj for multiple calls
3374   po->operand[1].val -= adj;
3375   po->flags |= OPF_RMD;
3376   if (po->operand[1].val == 0)
3377     po->flags |= OPF_DONE;
3378   ferr_assert(po, (int)po->operand[1].val >= 0);
3379 }
3380
3381 // scan for positive, constant esp adjust
3382 // multipath case is preliminary
3383 static int scan_for_esp_adjust(int i, int opcnt,
3384   int adj_expect, int *adj, int *is_multipath, int do_update)
3385 {
3386   int adj_expect_unknown = 0;
3387   struct parsed_op *po;
3388   int first_pop = -1;
3389   int adj_best = 0;
3390
3391   *adj = *is_multipath = 0;
3392   if (adj_expect < 0) {
3393     adj_expect_unknown = 1;
3394     adj_expect = 32 * 4; // enough?
3395   }
3396
3397   for (; i < opcnt && *adj < adj_expect; i++) {
3398     if (g_labels[i] != NULL)
3399       *is_multipath = 1;
3400
3401     po = &ops[i];
3402     if (po->flags & OPF_DONE)
3403       continue;
3404
3405     if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3406       if (po->operand[1].type != OPT_CONST)
3407         ferr(&ops[i], "non-const esp adjust?\n");
3408       *adj += po->operand[1].val;
3409       if (*adj & 3)
3410         ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3411       if (do_update) {
3412         if (!*is_multipath)
3413           patch_esp_adjust(po, adj_expect);
3414         else
3415           po->flags |= OPF_RMD;
3416       }
3417       return i;
3418     }
3419     else if (po->op == OP_PUSH) {
3420       //if (first_pop == -1)
3421       //  first_pop = -2; // none
3422       *adj -= lmod_bytes(po, po->operand[0].lmod);
3423     }
3424     else if (po->op == OP_POP) {
3425       if (!(po->flags & OPF_DONE)) {
3426         // seems like msvc only uses 'pop ecx' for stack realignment..
3427         if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3428           break;
3429         if (first_pop == -1 && *adj >= 0)
3430           first_pop = i;
3431       }
3432       if (do_update && *adj >= 0) {
3433         po->flags |= OPF_RMD;
3434         if (!*is_multipath)
3435           po->flags |= OPF_DONE | OPF_NOREGS;
3436       }
3437
3438       *adj += lmod_bytes(po, po->operand[0].lmod);
3439       if (*adj > adj_best)
3440         adj_best = *adj;
3441     }
3442     else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3443       if (po->op == OP_JMP && po->btj == NULL) {
3444         if (po->bt_i <= i)
3445           break;
3446         i = po->bt_i - 1;
3447         continue;
3448       }
3449       if (po->op != OP_CALL)
3450         break;
3451       if (po->operand[0].type != OPT_LABEL)
3452         break;
3453       if (po->pp != NULL && po->pp->is_stdcall)
3454         break;
3455       if (adj_expect_unknown && first_pop >= 0)
3456         break;
3457       // assume it's another cdecl call
3458     }
3459   }
3460
3461   if (first_pop >= 0) {
3462     // probably only 'pop ecx' was used
3463     *adj = adj_best;
3464     return first_pop;
3465   }
3466
3467   return -1;
3468 }
3469
3470 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3471 {
3472   struct parsed_op *po;
3473   int j;
3474
3475   if (i < 0)
3476     ferr(ops, "%s: followed bad branch?\n", __func__);
3477
3478   for (; i < opcnt; i++) {
3479     po = &ops[i];
3480     if (po->cc_scratch == magic)
3481       return;
3482     po->cc_scratch = magic;
3483     po->flags |= flags;
3484
3485     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3486       if (po->btj != NULL) {
3487         // jumptable
3488         for (j = 0; j < po->btj->count; j++)
3489           scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3490         return;
3491       }
3492
3493       scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3494       if (!(po->flags & OPF_CJMP))
3495         return;
3496     }
3497     if (po->flags & OPF_TAIL)
3498       return;
3499   }
3500 }
3501
3502 static const struct parsed_proto *try_recover_pp(
3503   struct parsed_op *po, const struct parsed_opr *opr,
3504   int is_call, int *search_instead)
3505 {
3506   const struct parsed_proto *pp = NULL;
3507   char buf[256];
3508   char *p;
3509
3510   // maybe an arg of g_func?
3511   if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3512   {
3513     char ofs_reg[16] = { 0, };
3514     int arg, arg_s, arg_i;
3515     int stack_ra = 0;
3516     int offset = 0;
3517
3518     if (g_header_mode)
3519       return NULL;
3520
3521     parse_stack_access(po, opr->name, ofs_reg,
3522       &offset, &stack_ra, NULL, 0);
3523     if (ofs_reg[0] != 0)
3524       ferr(po, "offset reg on arg access?\n");
3525     if (offset <= stack_ra) {
3526       // search who set the stack var instead
3527       if (search_instead != NULL)
3528         *search_instead = 1;
3529       return NULL;
3530     }
3531
3532     arg_i = (offset - stack_ra - 4) / 4;
3533     for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3534       if (g_func_pp->arg[arg].reg != NULL)
3535         continue;
3536       if (arg_s == arg_i)
3537         break;
3538       arg_s++;
3539     }
3540     if (arg == g_func_pp->argc)
3541       ferr(po, "stack arg %d not in prototype?\n", arg_i);
3542
3543     pp = g_func_pp->arg[arg].pp;
3544     if (is_call) {
3545       if (pp == NULL)
3546         ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3547       check_func_pp(po, pp, "icall arg");
3548     }
3549   }
3550   else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3551     // label[index]
3552     p = strchr(opr->name + 1, '[');
3553     memcpy(buf, opr->name, p - opr->name);
3554     buf[p - opr->name] = 0;
3555     pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3556   }
3557   else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3558     pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3559     if (pp == NULL) {
3560       if (!g_header_mode)
3561         ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3562     }
3563     else
3564       check_func_pp(po, pp, "reg-fptr ref");
3565   }
3566
3567   return pp;
3568 }
3569
3570 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3571   int magic, const struct parsed_proto **pp_found, int *pp_i,
3572   int *multi)
3573 {
3574   const struct parsed_proto *pp = NULL;
3575   struct parsed_op *po;
3576   struct label_ref *lr;
3577
3578   ops[i].cc_scratch = magic;
3579
3580   while (1) {
3581     if (g_labels[i] != NULL) {
3582       lr = &g_label_refs[i];
3583       for (; lr != NULL; lr = lr->next) {
3584         check_i(&ops[i], lr->i);
3585         scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3586       }
3587       if (i > 0 && LAST_OP(i - 1))
3588         return;
3589     }
3590
3591     i--;
3592     if (i < 0)
3593       break;
3594
3595     if (ops[i].cc_scratch == magic)
3596       return;
3597     ops[i].cc_scratch = magic;
3598
3599     if (!(ops[i].flags & OPF_DATA))
3600       continue;
3601     if (!is_opr_modified(opr, &ops[i]))
3602       continue;
3603     if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3604       // most probably trashed by some processing
3605       *pp_found = NULL;
3606       return;
3607     }
3608
3609     opr = &ops[i].operand[1];
3610     if (opr->type != OPT_REG)
3611       break;
3612   }
3613
3614   po = (i >= 0) ? &ops[i] : ops;
3615
3616   if (i < 0) {
3617     // reached the top - can only be an arg-reg
3618     if (opr->type != OPT_REG || g_func_pp == NULL)
3619       return;
3620
3621     for (i = 0; i < g_func_pp->argc; i++) {
3622       if (g_func_pp->arg[i].reg == NULL)
3623         continue;
3624       if (IS(opr->name, g_func_pp->arg[i].reg))
3625         break;
3626     }
3627     if (i == g_func_pp->argc)
3628       return;
3629     pp = g_func_pp->arg[i].pp;
3630     if (pp == NULL)
3631       ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3632         i + 1, g_func_pp->arg[i].reg);
3633     check_func_pp(po, pp, "icall reg-arg");
3634   }
3635   else
3636     pp = try_recover_pp(po, opr, 1, NULL);
3637
3638   if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3639     if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3640       || (*pp_found)->is_stdcall != pp->is_stdcall
3641       //|| (*pp_found)->is_fptr != pp->is_fptr
3642       || (*pp_found)->argc != pp->argc
3643       || (*pp_found)->argc_reg != pp->argc_reg
3644       || (*pp_found)->argc_stack != pp->argc_stack)
3645     {
3646       ferr(po, "icall: parsed_proto mismatch\n");
3647     }
3648     *multi = 1;
3649   }
3650   if (pp != NULL) {
3651     *pp_found = pp;
3652     *pp_i = po - ops;
3653   }
3654 }
3655
3656 static void add_label_ref(struct label_ref *lr, int op_i)
3657 {
3658   struct label_ref *lr_new;
3659
3660   if (lr->i == -1) {
3661     lr->i = op_i;
3662     return;
3663   }
3664
3665   lr_new = calloc(1, sizeof(*lr_new));
3666   lr_new->i = op_i;
3667   lr_new->next = lr->next;
3668   lr->next = lr_new;
3669 }
3670
3671 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3672 {
3673   struct parsed_op *po = &ops[i];
3674   struct parsed_data *pd;
3675   char label[NAMELEN], *p;
3676   int len, j, l;
3677
3678   p = strchr(po->operand[0].name, '[');
3679   if (p == NULL)
3680     return NULL;
3681
3682   len = p - po->operand[0].name;
3683   strncpy(label, po->operand[0].name, len);
3684   label[len] = 0;
3685
3686   for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3687     if (IS(g_func_pd[j].label, label)) {
3688       pd = &g_func_pd[j];
3689       break;
3690     }
3691   }
3692   if (pd == NULL)
3693     //ferr(po, "label '%s' not parsed?\n", label);
3694     return NULL;
3695
3696   if (pd->type != OPT_OFFSET)
3697     ferr(po, "label '%s' with non-offset data?\n", label);
3698
3699   // find all labels, link
3700   for (j = 0; j < pd->count; j++) {
3701     for (l = 0; l < opcnt; l++) {
3702       if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3703         add_label_ref(&g_label_refs[l], i);
3704         pd->d[j].bt_i = l;
3705         break;
3706       }
3707     }
3708   }
3709
3710   return pd;
3711 }
3712
3713 static void clear_labels(int count)
3714 {
3715   int i;
3716
3717   for (i = 0; i < count; i++) {
3718     if (g_labels[i] != NULL) {
3719       free(g_labels[i]);
3720       g_labels[i] = NULL;
3721     }
3722   }
3723 }
3724
3725 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3726 {
3727   int regmask = 0;
3728   int i, reg;
3729
3730   for (i = 0; i < pp->argc; i++) {
3731     if (pp->arg[i].reg != NULL) {
3732       reg = char_array_i(regs_r32,
3733               ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3734       if (reg < 0)
3735         ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3736           pp->arg[i].reg, pp->name);
3737       regmask |= 1 << reg;
3738     }
3739   }
3740
3741   return regmask;
3742 }
3743
3744 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3745 {
3746   int regmask = 0;
3747   int i, reg;
3748
3749   if (pp->has_retreg) {
3750     for (i = 0; i < pp->argc; i++) {
3751       if (pp->arg[i].type.is_retreg) {
3752         reg = char_array_i(regs_r32,
3753                 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3754         ferr_assert(ops, reg >= 0);
3755         regmask |= 1 << reg;
3756       }
3757     }
3758   }
3759
3760   if (strstr(pp->ret_type.name, "int64"))
3761     return regmask | (1 << xAX) | (1 << xDX);
3762   if (IS(pp->ret_type.name, "float")
3763    || IS(pp->ret_type.name, "double"))
3764   {
3765     return regmask | mxST0;
3766   }
3767   if (strcasecmp(pp->ret_type.name, "void") == 0)
3768     return regmask;
3769
3770   return regmask | mxAX;
3771 }
3772
3773 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3774 {
3775   return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3776     && memcmp(po1->operand, po2->operand,
3777               sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3778 }
3779
3780 static void resolve_branches_parse_calls(int opcnt)
3781 {
3782   static const struct {
3783     const char *name;
3784     enum op_op op;
3785     unsigned int flags;
3786     unsigned int regmask_src;
3787     unsigned int regmask_dst;
3788   } pseudo_ops[] = {
3789     { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3790     { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3791     { "__ftol",   OPP_FTOL,   OPF_FPOP, mxST0, mxAX | mxDX },
3792     // more precise? Wine gets away with just __ftol handler
3793     { "__ftol2",  OPP_FTOL,   OPF_FPOP, mxST0, mxAX | mxDX },
3794     { "__CIpow",  OPP_CIPOW,  OPF_FPOP, mxST0|mxST1, mxST0 },
3795   };
3796   const struct parsed_proto *pp_c;
3797   struct parsed_proto *pp;
3798   struct parsed_data *pd;
3799   struct parsed_op *po;
3800   const char *tmpname;
3801   enum op_op prev_op;
3802   int i, l;
3803   int ret;
3804
3805   for (i = 0; i < opcnt; i++)
3806   {
3807     po = &ops[i];
3808     po->bt_i = -1;
3809     po->btj = NULL;
3810
3811     if (po->datap != NULL) {
3812       pp = calloc(1, sizeof(*pp));
3813       my_assert_not(pp, NULL);
3814
3815       ret = parse_protostr(po->datap, pp);
3816       if (ret < 0)
3817         ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3818       free(po->datap);
3819       po->datap = NULL;
3820       po->pp = pp;
3821     }
3822
3823     if (po->op == OP_CALL) {
3824       pp = NULL;
3825
3826       if (po->pp != NULL)
3827         pp = po->pp;
3828       else if (po->operand[0].type == OPT_LABEL)
3829       {
3830         tmpname = opr_name(po, 0);
3831         if (IS_START(tmpname, "loc_")) {
3832           if (!g_seh_found)
3833             ferr(po, "call to loc_*\n");
3834           // eliminate_seh() must take care of it
3835           continue;
3836         }
3837         if (IS(tmpname, "__alloca_probe"))
3838           continue;
3839         if (IS(tmpname, "__SEH_prolog")) {
3840           ferr_assert(po, g_seh_found == 0);
3841           g_seh_found = 2;
3842           continue;
3843         }
3844         if (IS(tmpname, "__SEH_epilog"))
3845           continue;
3846
3847         // convert some calls to pseudo-ops
3848         for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3849           if (!IS(tmpname, pseudo_ops[l].name))
3850             continue;
3851
3852           po->op = pseudo_ops[l].op;
3853           po->operand_cnt = 0;
3854           po->regmask_src = pseudo_ops[l].regmask_src;
3855           po->regmask_dst = pseudo_ops[l].regmask_dst;
3856           po->flags = pseudo_ops[l].flags;
3857           po->flags |= po->regmask_dst ? OPF_DATA : 0;
3858           break;
3859         }
3860         if (l < ARRAY_SIZE(pseudo_ops))
3861           continue;
3862
3863         pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3864         if (!g_header_mode && pp_c == NULL)
3865           ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3866
3867         if (pp_c != NULL) {
3868           pp = proto_clone(pp_c);
3869           my_assert_not(pp, NULL);
3870         }
3871       }
3872
3873       if (pp != NULL) {
3874         if (pp->is_fptr)
3875           check_func_pp(po, pp, "fptr var call");
3876         if (pp->is_noreturn) {
3877           po->flags |= OPF_TAIL;
3878           po->flags &= ~OPF_ATAIL; // most likely...
3879         }
3880       }
3881       po->pp = pp;
3882       continue;
3883     }
3884
3885     if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3886       continue;
3887
3888     if (po->operand[0].type == OPT_REGMEM) {
3889       pd = try_resolve_jumptab(i, opcnt);
3890       if (pd == NULL)
3891         goto tailcall;
3892
3893       po->btj = pd;
3894       continue;
3895     }
3896
3897     for (l = 0; l < opcnt; l++) {
3898       if (g_labels[l] != NULL
3899           && IS(po->operand[0].name, g_labels[l]))
3900       {
3901         if (l == i + 1 && po->op == OP_JMP) {
3902           // yet another alignment type..
3903           po->flags |= OPF_RMD|OPF_DONE;
3904           break;
3905         }
3906         add_label_ref(&g_label_refs[l], i);
3907         po->bt_i = l;
3908         break;
3909       }
3910     }
3911
3912     if (po->bt_i != -1 || (po->flags & OPF_RMD))
3913       continue;
3914
3915     if (po->operand[0].type == OPT_LABEL)
3916       // assume tail call
3917       goto tailcall;
3918
3919     ferr(po, "unhandled branch\n");
3920
3921 tailcall:
3922     po->op = OP_CALL;
3923     po->flags |= OPF_TAIL;
3924     prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3925     if (prev_op == OP_POP)
3926       po->flags |= OPF_ATAIL;
3927     if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3928       && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3929     {
3930       po->flags |= OPF_ATAIL;
3931     }
3932     i--; // reprocess
3933   }
3934 }
3935
3936 static int resolve_origin(int i, const struct parsed_opr *opr,
3937   int magic, int *op_i, int *is_caller);
3938 static void set_label(int i, const char *name);
3939
3940 static void eliminate_seh_writes(int opcnt)
3941 {
3942   const struct parsed_opr *opr;
3943   char ofs_reg[16];
3944   int offset;
3945   int i;
3946
3947   // assume all sf writes above g_seh_size to be seh related
3948   // (probably unsafe but oh well)
3949   for (i = 0; i < opcnt; i++) {
3950     if (ops[i].op != OP_MOV)
3951       continue;
3952     opr = &ops[i].operand[0];
3953     if (opr->type != OPT_REGMEM)
3954       continue;
3955     if (!is_stack_access(&ops[i], opr))
3956       continue;
3957
3958     offset = 0;
3959     parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
3960       NULL, NULL, 0);
3961     if (offset < 0 && offset >= -g_seh_size)
3962       ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3963   }
3964 }
3965
3966 static void eliminate_seh_finally(int opcnt)
3967 {
3968   const char *target_name = NULL;
3969   const char *return_name = NULL;
3970   int exits[MAX_EXITS];
3971   int exit_count = 0;
3972   int call_i = -1;
3973   int target_i = -1;
3974   int return_i = -1;
3975   int tgend_i = -1;
3976   int i;
3977
3978   for (i = 0; i < opcnt; i++) {
3979     if (ops[i].op != OP_CALL)
3980       continue;
3981     if (!IS_START(opr_name(&ops[i], 0), "loc_"))
3982       continue;
3983     if (target_name != NULL)
3984       ferr(&ops[i], "multiple finally calls? (last was %s)\n",
3985         target_name);
3986     target_name = opr_name(&ops[i], 0);
3987     call_i = i;
3988
3989     if (g_labels[i + 1] == NULL)
3990       set_label(i + 1, "seh_fin_done");
3991     return_name = g_labels[i + 1];
3992     return_i = i + 1;
3993   }
3994
3995   if (call_i == -1)
3996     // no finally block
3997     return;
3998
3999   // find finally code (bt_i is not set because it's call)
4000   for (i = 0; i < opcnt; i++) {
4001     if (g_labels[i] == NULL)
4002       continue;
4003     if (!IS(g_labels[i], target_name))
4004       continue;
4005
4006     ferr_assert(&ops[i], target_i == -1);
4007     target_i = i;
4008   }
4009   ferr_assert(&ops[0], target_i != -1);
4010
4011   find_reachable_exits(target_i, opcnt, target_i + opcnt * 24,
4012     exits, &exit_count);
4013   ferr_assert(&ops[target_i], exit_count == 1);
4014   ferr_assert(&ops[target_i], ops[exits[0]].op == OP_RET);
4015   tgend_i = exits[0];
4016
4017   // convert to jumps, link
4018   ops[call_i].op = OP_JMP;
4019   ops[call_i].bt_i = target_i;
4020   add_label_ref(&g_label_refs[target_i], call_i);
4021
4022   ops[tgend_i].op = OP_JMP;
4023   ops[tgend_i].flags &= ~OPF_TAIL;
4024   ops[tgend_i].flags |= OPF_JMP;
4025   ops[tgend_i].bt_i = return_i;
4026   ops[tgend_i].operand_cnt = 1;
4027   ops[tgend_i].operand[0].type = OPT_LABEL;
4028   snprintf(ops[tgend_i].operand[0].name, NAMELEN, "%s", return_name);
4029   add_label_ref(&g_label_refs[return_i], tgend_i);
4030
4031   // rm seh finally entry code
4032   for (i = target_i - 1; i >= 0; i--) {
4033     if (g_labels[i] != NULL && g_label_refs[i].i != -1)
4034       return;
4035     if (ops[i].flags & OPF_CJMP)
4036       return;
4037     if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4038       break;
4039   }
4040   for (i = target_i - 1; i >= 0; i--) {
4041     if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4042       break;
4043     ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4044   }
4045 }
4046
4047 static void eliminate_seh(int opcnt)
4048 {
4049   int i, j, k, ret;
4050
4051   for (i = 0; i < opcnt; i++) {
4052     if (ops[i].op != OP_MOV)
4053       continue;
4054     if (ops[i].operand[0].segment != SEG_FS)
4055       continue;
4056     if (!IS(opr_name(&ops[i], 0), "0"))
4057       continue;
4058
4059     ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4060     if (ops[i].operand[1].reg == xSP) {
4061       for (j = i - 1; j >= 0; j--) {
4062         if (ops[j].op != OP_PUSH)
4063           continue;
4064         ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4065         g_seh_size += 4;
4066         if (ops[j].operand[0].val == ~0)
4067           break;
4068         if (ops[j].operand[0].type == OPT_REG) {
4069           k = -1;
4070           ret = resolve_origin(j, &ops[j].operand[0],
4071                   j + opcnt * 22, &k, NULL);
4072           if (ret == 1)
4073             ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4074         }
4075       }
4076       if (j < 0)
4077         ferr(ops, "missing seh terminator\n");
4078     }
4079     else {
4080       k = -1;
4081       ret = resolve_origin(i, &ops[i].operand[1],
4082               i + opcnt * 23, &k, NULL);
4083       if (ret == 1)
4084         ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4085     }
4086   }
4087
4088   eliminate_seh_writes(opcnt);
4089   eliminate_seh_finally(opcnt);
4090 }
4091
4092 static void eliminate_seh_calls(int opcnt)
4093 {
4094   int epilog_found = 0;
4095   int i;
4096
4097   g_bp_frame = 1;
4098   g_seh_size = 0x10;
4099
4100   i = 0;
4101   ferr_assert(&ops[i], ops[i].op == OP_PUSH
4102                && ops[i].operand[0].type == OPT_CONST);
4103   g_stack_fsz = g_seh_size + ops[i].operand[0].val;
4104   ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4105
4106   i++;
4107   ferr_assert(&ops[i], ops[i].op == OP_PUSH
4108                && ops[i].operand[0].type == OPT_OFFSET);
4109   ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4110
4111   i++;
4112   ferr_assert(&ops[i], ops[i].op == OP_CALL
4113                && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
4114   ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4115
4116   for (i++; i < opcnt; i++) {
4117     if (ops[i].op != OP_CALL)
4118       continue;
4119     if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
4120       continue;
4121
4122     ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4123     epilog_found = 1;
4124   }
4125   ferr_assert(ops, epilog_found);
4126
4127   eliminate_seh_writes(opcnt);
4128   eliminate_seh_finally(opcnt);
4129 }
4130
4131 static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4132 {
4133   int j;
4134
4135   for (; i < opcnt; i++)
4136     if (!(ops[i].flags & OPF_DONE))
4137       break;
4138
4139   while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4140     ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4141     g_stack_fsz += 4;
4142     (*ecx_push)++;
4143     i++;
4144   }
4145
4146   for (; i < opcnt; i++) {
4147     if (i > 0 && g_labels[i] != NULL)
4148       break;
4149     if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
4150       break;
4151     if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4152       && ops[i].operand[1].type == OPT_CONST)
4153     {
4154       g_stack_fsz += opr_const(&ops[i], 1);
4155       ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4156       i++;
4157       *esp_sub = 1;
4158       break;
4159     }
4160     if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4161         && ops[i].operand[1].type == OPT_CONST)
4162     {
4163       for (j = i + 1; j < opcnt; j++)
4164         if (!(ops[j].flags & OPF_DONE))
4165           break;
4166       if (ops[j].op == OP_CALL
4167         && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4168       {
4169         g_stack_fsz += opr_const(&ops[i], 1);
4170         ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4171         ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4172         i = j + 1;
4173         *esp_sub = 1;
4174       }
4175       break;
4176     }
4177   }
4178
4179   return i;
4180 }
4181
4182 static void scan_prologue_epilogue(int opcnt, int *stack_align)
4183 {
4184   int ecx_push = 0, esp_sub = 0, pusha = 0;
4185   int sandard_epilogue;
4186   int found;
4187   int i, j, l;
4188
4189   if (g_seh_found == 2) {
4190     eliminate_seh_calls(opcnt);
4191     return;
4192   }
4193   if (g_seh_found) {
4194     eliminate_seh(opcnt);
4195     // ida treats seh as part of sf
4196     g_stack_fsz = g_seh_size;
4197     esp_sub = 1;
4198   }
4199
4200   if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4201       && ops[1].op == OP_MOV
4202       && IS(opr_name(&ops[1], 0), "ebp")
4203       && IS(opr_name(&ops[1], 1), "esp"))
4204   {
4205     g_bp_frame = 1;
4206     ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4207     ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4208
4209     for (i = 2; i < opcnt; i++)
4210       if (!(ops[i].flags & OPF_DONE))
4211         break;
4212
4213     if (ops[i].op == OP_PUSHA) {
4214       ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4215       pusha = 1;
4216       i++;
4217     }
4218
4219     if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4220         && ops[i].operand[1].type == OPT_CONST)
4221     {
4222       l = ops[i].operand[1].val;
4223       j = ffs(l) - 1;
4224       if (j == -1 || (l >> j) != -1)
4225         ferr(&ops[i], "unhandled esp align: %x\n", l);
4226       if (stack_align != NULL)
4227         *stack_align = 1 << j;
4228       ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4229       i++;
4230     }
4231
4232     i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4233
4234     found = 0;
4235     do {
4236       for (; i < opcnt; i++)
4237         if (ops[i].flags & OPF_TAIL)
4238           break;
4239       j = i - 1;
4240       if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4241         if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4242           break;
4243         i--;
4244         j--;
4245       }
4246
4247       sandard_epilogue = 0;
4248       if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4249       {
4250         ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4251         // the standard epilogue is sometimes even used without a sf
4252         if (ops[j - 1].op == OP_MOV
4253             && IS(opr_name(&ops[j - 1], 0), "esp")
4254             && IS(opr_name(&ops[j - 1], 1), "ebp"))
4255           sandard_epilogue = 1;
4256       }
4257       else if (ops[j].op == OP_LEAVE)
4258       {
4259         ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4260         sandard_epilogue = 1;
4261       }
4262       else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4263         && ops[i].pp->is_noreturn)
4264       {
4265         // on noreturn, msvc sometimes cleans stack, sometimes not
4266         i++;
4267         found = 1;
4268         continue;
4269       }
4270       else if (!(g_ida_func_attr & IDAFA_NORETURN))
4271         ferr(&ops[j], "'pop ebp' expected\n");
4272
4273       if (g_stack_fsz != 0 || sandard_epilogue) {
4274         if (ops[j].op == OP_LEAVE)
4275           j--;
4276         else if (sandard_epilogue) // mov esp, ebp
4277         {
4278           ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4279           j -= 2;
4280         }
4281         else if (!(g_ida_func_attr & IDAFA_NORETURN))
4282         {
4283           ferr(&ops[j], "esp restore expected\n");
4284         }
4285
4286         if (ecx_push && j >= 0 && ops[j].op == OP_POP
4287           && IS(opr_name(&ops[j], 0), "ecx"))
4288         {
4289           ferr(&ops[j], "unexpected ecx pop\n");
4290         }
4291       }
4292
4293       if (pusha) {
4294         if (ops[j].op == OP_POPA)
4295           ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4296         else
4297           ferr(&ops[j], "popa expected\n");
4298       }
4299
4300       found = 1;
4301       i++;
4302     } while (i < opcnt);
4303
4304     if (!found)
4305       ferr(ops, "missing ebp epilogue\n");
4306     return;
4307   }
4308
4309   // non-bp frame
4310   i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4311
4312   if (ecx_push && !esp_sub) {
4313     // could actually be args for a call..
4314     for (; i < opcnt; i++)
4315       if (ops[i].op != OP_PUSH)
4316         break;
4317
4318     if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4319       const struct parsed_proto *pp;
4320       pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4321       j = pp ? pp->argc_stack : 0;
4322       while (i > 0 && j > 0) {
4323         i--;
4324         if (ops[i].op == OP_PUSH) {
4325           ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4326           j--;
4327         }
4328       }
4329       if (j != 0)
4330         ferr(&ops[i], "unhandled prologue\n");
4331
4332       // recheck
4333       i = ecx_push = 0;
4334       g_stack_fsz = g_seh_size;
4335       while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4336         if (!(ops[i].flags & OPF_RMD))
4337           break;
4338         g_stack_fsz += 4;
4339         ecx_push++;
4340         i++;
4341       }
4342     }
4343   }
4344
4345   found = 0;
4346   if (ecx_push || esp_sub)
4347   {
4348     g_sp_frame = 1;
4349
4350     do {
4351       for (; i < opcnt; i++)
4352         if (ops[i].flags & OPF_TAIL)
4353           break;
4354
4355       j = i - 1;
4356       if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4357         if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4358           break;
4359         i--;
4360         j--;
4361       }
4362       else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4363         // skip arg updates for arg-reuse tailcall
4364         for (; j >= 0; j--) {
4365           if (ops[j].op != OP_MOV)
4366             break;
4367           if (ops[j].operand[0].type != OPT_REGMEM)
4368             break;
4369           if (strstr(ops[j].operand[0].name, "arg_") == NULL)
4370             break;
4371         }
4372       }
4373
4374       if (ecx_push > 0 && !esp_sub) {
4375         for (l = 0; l < ecx_push && j >= 0; l++) {
4376           if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4377             /* pop ecx */;
4378           else if (ops[j].op == OP_ADD
4379                    && IS(opr_name(&ops[j], 0), "esp")
4380                    && ops[j].operand[1].type == OPT_CONST)
4381           {
4382             /* add esp, N */
4383             l += ops[j].operand[1].val / 4 - 1;
4384           }
4385           else
4386             break;
4387
4388           ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4389           j--;
4390         }
4391         if (l != ecx_push) {
4392           if (i < opcnt && ops[i].op == OP_CALL
4393             && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4394           {
4395             // noreturn tailcall with no epilogue
4396             i++;
4397             found = 1;
4398             continue;
4399           }
4400           ferr(&ops[j], "epilogue scan failed\n");
4401         }
4402
4403         found = 1;
4404       }
4405
4406       if (esp_sub) {
4407         if (ops[j].op != OP_ADD
4408             || !IS(opr_name(&ops[j], 0), "esp")
4409             || ops[j].operand[1].type != OPT_CONST)
4410         {
4411           if (i < opcnt && ops[i].op == OP_CALL
4412             && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4413           {
4414             // noreturn tailcall with no epilogue
4415             i++;
4416             found = 1;
4417             continue;
4418           }
4419           ferr(&ops[j], "'add esp' expected\n");
4420         }
4421
4422         if (ops[j].operand[1].val < g_stack_fsz)
4423           ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4424
4425         ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4426         if (ops[j].operand[1].val == 0)
4427           ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4428         found = 1;
4429       }
4430
4431       i++;
4432     } while (i < opcnt);
4433
4434     if (!found)
4435       ferr(ops, "missing esp epilogue\n");
4436   }
4437 }
4438
4439 // find an instruction that changed opr before i op
4440 // *op_i must be set to -1 by the caller
4441 // *is_caller is set to 1 if one source is determined to be g_func arg
4442 // returns 1 if found, *op_i is then set to origin
4443 // returns -1 if multiple origins are found
4444 static int resolve_origin(int i, const struct parsed_opr *opr,
4445   int magic, int *op_i, int *is_caller)
4446 {
4447   struct label_ref *lr;
4448   int ret = 0;
4449
4450   while (1) {
4451     if (g_labels[i] != NULL) {
4452       lr = &g_label_refs[i];
4453       for (; lr != NULL; lr = lr->next) {
4454         check_i(&ops[i], lr->i);
4455         ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4456       }
4457       if (i > 0 && LAST_OP(i - 1))
4458         return ret;
4459     }
4460
4461     i--;
4462     if (i < 0) {
4463       if (is_caller != NULL)
4464         *is_caller = 1;
4465       return -1;
4466     }
4467
4468     if (ops[i].cc_scratch == magic)
4469       return ret;
4470     ops[i].cc_scratch = magic;
4471
4472     if (!(ops[i].flags & OPF_DATA))
4473       continue;
4474     if (!is_opr_modified(opr, &ops[i]))
4475       continue;
4476
4477     if (*op_i >= 0) {
4478       if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4479         return ret | 1;
4480
4481       return -1;
4482     }
4483
4484     *op_i = i;
4485     return ret | 1;
4486   }
4487 }
4488
4489 // find an instruction that previously referenced opr
4490 // if multiple results are found - fail
4491 // *op_i must be set to -1 by the caller
4492 // returns 1 if found, *op_i is then set to referencer insn
4493 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4494   int magic, int *op_i)
4495 {
4496   struct label_ref *lr;
4497   int ret = 0;
4498
4499   while (1) {
4500     if (g_labels[i] != NULL) {
4501       lr = &g_label_refs[i];
4502       for (; lr != NULL; lr = lr->next) {
4503         check_i(&ops[i], lr->i);
4504         ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4505       }
4506       if (i > 0 && LAST_OP(i - 1))
4507         return ret;
4508     }
4509
4510     i--;
4511     if (i < 0)
4512       return -1;
4513
4514     if (ops[i].cc_scratch == magic)
4515       return 0;
4516     ops[i].cc_scratch = magic;
4517
4518     if (!is_opr_referenced(opr, &ops[i]))
4519       continue;
4520
4521     if (*op_i >= 0)
4522       return -1;
4523
4524     *op_i = i;
4525     return 1;
4526   }
4527 }
4528
4529 // adjust datap of all reachable 'op' insns when moving back
4530 // returns  1 if at least 1 op was found
4531 // returns -1 if path without an op was found
4532 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4533 {
4534   struct label_ref *lr;
4535   int ret = 0;
4536
4537   if (ops[i].cc_scratch == magic)
4538     return 0;
4539   ops[i].cc_scratch = magic;
4540
4541   while (1) {
4542     if (g_labels[i] != NULL) {
4543       lr = &g_label_refs[i];
4544       for (; lr != NULL; lr = lr->next) {
4545         check_i(&ops[i], lr->i);
4546         ret |= adjust_prev_op(lr->i, op, magic, datap);
4547       }
4548       if (i > 0 && LAST_OP(i - 1))
4549         return ret;
4550     }
4551
4552     i--;
4553     if (i < 0)
4554       return -1;
4555
4556     if (ops[i].cc_scratch == magic)
4557       return 0;
4558     ops[i].cc_scratch = magic;
4559
4560     if (ops[i].op != op)
4561       continue;
4562
4563     ops[i].datap = datap;
4564     return 1;
4565   }
4566 }
4567
4568 // find next instruction that reads opr
4569 // *op_i must be set to -1 by the caller
4570 // on return, *op_i is set to first referencer insn
4571 // returns 1 if exactly 1 referencer is found
4572 static int find_next_read(int i, int opcnt,
4573   const struct parsed_opr *opr, int magic, int *op_i)
4574 {
4575   struct parsed_op *po;
4576   int j, ret = 0;
4577
4578   for (; i < opcnt; i++)
4579   {
4580     if (ops[i].cc_scratch == magic)
4581       return ret;
4582     ops[i].cc_scratch = magic;
4583
4584     po = &ops[i];
4585     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4586       if (po->btj != NULL) {
4587         // jumptable
4588         for (j = 0; j < po->btj->count; j++) {
4589           check_i(po, po->btj->d[j].bt_i);
4590           ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4591                    magic, op_i);
4592         }
4593         return ret;
4594       }
4595
4596       if (po->flags & OPF_RMD)
4597         continue;
4598       check_i(po, po->bt_i);
4599       if (po->flags & OPF_CJMP) {
4600         ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4601         if (ret < 0)
4602           return ret;
4603       }
4604       else
4605         i = po->bt_i - 1;
4606       continue;
4607     }
4608
4609     if (!is_opr_read(opr, po)) {
4610       int full_opr = 1;
4611       if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4612           && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4613       {
4614         full_opr = po->operand[0].lmod >= opr->lmod;
4615       }
4616       if (is_opr_modified(opr, po) && full_opr) {
4617         // it's overwritten
4618         return ret;
4619       }
4620       if (po->flags & OPF_TAIL)
4621         return ret;
4622       continue;
4623     }
4624
4625     if (*op_i >= 0)
4626       return -1;
4627
4628     *op_i = i;
4629     return 1;
4630   }
4631
4632   return 0;
4633 }
4634
4635 // find next instruction that reads opr
4636 // *op_i must be set to -1 by the caller
4637 // on return, *op_i is set to first flag user insn
4638 // returns 1 if exactly 1 flag user is found
4639 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4640 {
4641   struct parsed_op *po;
4642   int j, ret = 0;
4643
4644   for (; i < opcnt; i++)
4645   {
4646     if (ops[i].cc_scratch == magic)
4647       return ret;
4648     ops[i].cc_scratch = magic;
4649
4650     po = &ops[i];
4651     if (po->op == OP_CALL)
4652       return -1;
4653     if (po->flags & OPF_JMP) {
4654       if (po->btj != NULL) {
4655         // jumptable
4656         for (j = 0; j < po->btj->count; j++) {
4657           check_i(po, po->btj->d[j].bt_i);
4658           ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4659                    magic, op_i);
4660         }
4661         return ret;
4662       }
4663
4664       if (po->flags & OPF_RMD)
4665         continue;
4666       check_i(po, po->bt_i);
4667       if (po->flags & OPF_CJMP)
4668         goto found;
4669       else
4670         i = po->bt_i - 1;
4671       continue;
4672     }
4673
4674     if (!(po->flags & OPF_CC)) {
4675       if (po->flags & OPF_FLAGS)
4676         // flags changed
4677         return ret;
4678       if (po->flags & OPF_TAIL)
4679         return ret;
4680       continue;
4681     }
4682
4683 found:
4684     if (*op_i >= 0)
4685       return -1;
4686
4687     *op_i = i;
4688     return 1;
4689   }
4690
4691   return 0;
4692 }
4693
4694 static int try_resolve_const(int i, const struct parsed_opr *opr,
4695   int magic, unsigned int *val)
4696 {
4697   int s_i = -1;
4698   int ret;
4699
4700   ret = resolve_origin(i, opr, magic, &s_i, NULL);
4701   if (ret == 1) {
4702     i = s_i;
4703     if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4704       return -1;
4705
4706     *val = ops[i].operand[1].val;
4707     return 1;
4708   }
4709
4710   return -1;
4711 }
4712
4713 static int resolve_used_bits(int i, int opcnt, int reg,
4714   int *mask, int *is_z_check)
4715 {
4716   struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4717   int j = -1, k = -1;
4718   int ret;
4719
4720   ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4721   if (ret != 1)
4722     return -1;
4723
4724   find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4725   if (k != -1) {
4726     fnote(&ops[j], "(first read)\n");
4727     ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4728   }
4729
4730   if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4731     ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4732
4733   ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4734   ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4735
4736   *mask = ops[j].operand[1].val;
4737   if (ops[j].operand[0].lmod == OPLM_BYTE
4738     && ops[j].operand[0].name[1] == 'h')
4739   {
4740     *mask <<= 8;
4741   }
4742   ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4743
4744   *is_z_check = 0;
4745   ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4746   if (ret == 1)
4747     *is_z_check = ops[k].pfo == PFO_Z;
4748
4749   return 0;
4750 }
4751
4752 static const struct parsed_proto *resolve_deref(int i, int magic,
4753   struct parsed_opr *opr, int level)
4754 {
4755   struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4756   const struct parsed_proto *pp = NULL;
4757   int from_caller = 0;
4758   char s_reg[4];
4759   int offset = 0;
4760   int len = 0;
4761   int j = -1;
4762   int k = -1;
4763   int reg;
4764   int ret;
4765
4766   ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4767   if (ret != 2 || len != strlen(opr->name)) {
4768     ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4769     if (ret != 1 || len != strlen(opr->name))
4770       return NULL;
4771   }
4772
4773   reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4774   if (reg < 0)
4775     return NULL;
4776
4777   opr_s.reg = reg;
4778   ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4779   if (ret != 1)
4780     return NULL;
4781
4782   if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4783     && strlen(ops[j].operand[1].name) == 3
4784     && ops[j].operand[0].lmod == OPLM_DWORD
4785     && ops[j].pp == NULL // no hint
4786     && level == 0)
4787   {
4788     // allow one simple dereference (com/directx)
4789     reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4790             ops[j].operand[1].name);
4791     if (reg < 0)
4792       return NULL;
4793     opr_s.reg = reg;
4794     ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4795     if (ret != 1)
4796       return NULL;
4797     j = k;
4798   }
4799   if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4800     return NULL;
4801
4802   if (ops[j].pp != NULL) {
4803     // type hint in asm
4804     pp = ops[j].pp;
4805   }
4806   else if (ops[j].operand[1].type == OPT_REGMEM) {
4807     pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4808     if (pp == NULL) {
4809       // maybe structure ptr in structure
4810       pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4811     }
4812   }
4813   else if (ops[j].operand[1].type == OPT_LABEL)
4814     pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4815   else if (ops[j].operand[1].type == OPT_REG) {
4816     // maybe arg reg?
4817     k = -1;
4818     ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4819             &k, &from_caller);
4820     if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4821       for (k = 0; k < g_func_pp->argc; k++) {
4822         if (g_func_pp->arg[k].reg == NULL)
4823           continue;
4824         if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4825           pp = g_func_pp->arg[k].pp;
4826           break;
4827         }
4828       }
4829     }
4830   }
4831
4832   if (pp == NULL)
4833     return NULL;
4834   if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4835     if (offset != 0)
4836       ferr(&ops[j], "expected struct, got '%s %s'\n",
4837            pp->type.name, pp->name);
4838     return NULL;
4839   }
4840
4841   return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4842 }
4843
4844 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4845   int *pp_i, int *multi_src)
4846 {
4847   const struct parsed_proto *pp = NULL;
4848   int search_advice = 0;
4849
4850   *multi_src = 0;
4851   *pp_i = -1;
4852
4853   switch (ops[i].operand[0].type) {
4854   case OPT_REGMEM:
4855     // try to resolve struct member calls
4856     pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4857     if (pp != NULL)
4858       break;
4859     // fallthrough
4860   case OPT_LABEL:
4861   case OPT_OFFSET:
4862     pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4863            1, &search_advice);
4864     if (!search_advice)
4865       break;
4866     // fallthrough
4867   default:
4868     scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4869       pp_i, multi_src);
4870     break;
4871   }
4872
4873   return pp;
4874 }
4875
4876 static struct parsed_proto *process_call_early(int i, int opcnt,
4877   int *adj_i)
4878 {
4879   struct parsed_op *po = &ops[i];
4880   struct parsed_proto *pp;
4881   int multipath = 0;
4882   int adj = 0;
4883   int j, ret;
4884
4885   pp = po->pp;
4886   if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4887     // leave for later
4888     return NULL;
4889
4890   // look for and make use of esp adjust
4891   *adj_i = ret = -1;
4892   if (!pp->is_stdcall && pp->argc_stack > 0)
4893     ret = scan_for_esp_adjust(i + 1, opcnt,
4894             pp->argc_stack * 4, &adj, &multipath, 0);
4895   if (ret >= 0) {
4896     if (pp->argc_stack > adj / 4)
4897       return NULL;
4898     if (multipath)
4899       return NULL;
4900     if (ops[ret].op == OP_POP) {
4901       for (j = 1; j < adj / 4; j++) {
4902         if (ops[ret + j].op != OP_POP
4903           || ops[ret + j].operand[0].reg != xCX)
4904         {
4905           return NULL;
4906         }
4907       }
4908     }
4909   }
4910
4911   *adj_i = ret;
4912   return pp;
4913 }
4914
4915 static struct parsed_proto *process_call(int i, int opcnt)
4916 {
4917   struct parsed_op *po = &ops[i];
4918   const struct parsed_proto *pp_c;
4919   struct parsed_proto *pp;
4920   const char *tmpname;
4921   int call_i = -1, ref_i = -1;
4922   int adj = 0, multipath = 0;
4923   int ret, arg;
4924
4925   tmpname = opr_name(po, 0);
4926   pp = po->pp;
4927   if (pp == NULL)
4928   {
4929     // indirect call
4930     pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4931     if (pp_c != NULL) {
4932       if (!pp_c->is_func && !pp_c->is_fptr)
4933         ferr(po, "call to non-func: %s\n", pp_c->name);
4934       pp = proto_clone(pp_c);
4935       my_assert_not(pp, NULL);
4936       if (multipath)
4937         // not resolved just to single func
4938         pp->is_fptr = 1;
4939
4940       switch (po->operand[0].type) {
4941       case OPT_REG:
4942         // we resolved this call and no longer need the register
4943         po->regmask_src &= ~(1 << po->operand[0].reg);
4944
4945         if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4946           && ops[call_i].operand[1].type == OPT_LABEL)
4947         {
4948           // no other source users?
4949           ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4950                   &ref_i);
4951           if (ret == 1 && call_i == ref_i) {
4952             // and nothing uses it after us?
4953             ref_i = -1;
4954             find_next_read(i + 1, opcnt, &po->operand[0],
4955               i + opcnt * 11, &ref_i);
4956             if (ref_i == -1)
4957               // then also don't need the source mov
4958               ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4959           }
4960         }
4961         break;
4962       case OPT_REGMEM:
4963         pp->is_fptr = 1;
4964         break;
4965       default:
4966         break;
4967       }
4968     }
4969     if (pp == NULL) {
4970       pp = calloc(1, sizeof(*pp));
4971       my_assert_not(pp, NULL);
4972
4973       pp->is_fptr = 1;
4974       ret = scan_for_esp_adjust(i + 1, opcnt,
4975               -1, &adj, &multipath, 0);
4976       if (ret < 0 || adj < 0) {
4977         if (!g_allow_regfunc)
4978           ferr(po, "non-__cdecl indirect call unhandled yet\n");
4979         pp->is_unresolved = 1;
4980         adj = 0;
4981       }
4982       adj /= 4;
4983       if (adj > ARRAY_SIZE(pp->arg))
4984         ferr(po, "esp adjust too large: %d\n", adj);
4985       pp->ret_type.name = strdup("int");
4986       pp->argc = pp->argc_stack = adj;
4987       for (arg = 0; arg < pp->argc; arg++)
4988         pp->arg[arg].type.name = strdup("int");
4989     }
4990     po->pp = pp;
4991   }
4992
4993   // look for and make use of esp adjust
4994   multipath = 0;
4995   ret = -1;
4996   if (!pp->is_stdcall && pp->argc_stack > 0) {
4997     int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4998     ret = scan_for_esp_adjust(i + 1, opcnt,
4999             adj_expect, &adj, &multipath, 0);
5000   }
5001   if (ret >= 0) {
5002     if (pp->is_vararg) {
5003       if (adj / 4 < pp->argc_stack) {
5004         fnote(po, "(this call)\n");
5005         ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
5006           adj, pp->argc_stack * 4);
5007       }
5008       // modify pp to make it have varargs as normal args
5009       arg = pp->argc;
5010       pp->argc += adj / 4 - pp->argc_stack;
5011       for (; arg < pp->argc; arg++) {
5012         pp->arg[arg].type.name = strdup("int");
5013         pp->argc_stack++;
5014       }
5015       if (pp->argc > ARRAY_SIZE(pp->arg))
5016         ferr(po, "too many args for '%s'\n", tmpname);
5017     }
5018     if (pp->argc_stack > adj / 4) {
5019       if (pp->is_noreturn)
5020         // assume no stack adjust was emited
5021         goto out;
5022       fnote(po, "(this call)\n");
5023       ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
5024         tmpname, pp->argc_stack * 4, adj);
5025     }
5026
5027     scan_for_esp_adjust(i + 1, opcnt,
5028       pp->argc_stack * 4, &adj, &multipath, 1);
5029   }
5030   else if (pp->is_vararg)
5031     ferr(po, "missing esp_adjust for vararg func '%s'\n",
5032       pp->name);
5033
5034 out:
5035   return pp;
5036 }
5037
5038 static void mark_float_arg(struct parsed_op *po,
5039   struct parsed_proto *pp, int arg, int *regmask_ffca)
5040 {
5041   po->p_argnext = -1;
5042   po->p_argnum = arg + 1;
5043   ferr_assert(po, pp->arg[arg].datap == NULL);
5044   pp->arg[arg].datap = po;
5045   po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
5046   if (regmask_ffca != NULL)
5047     *regmask_ffca |= 1 << arg;
5048 }
5049
5050 static int check_for_stp(int i, int i_to)
5051 {
5052   struct parsed_op *po;
5053
5054   for (; i < i_to; i++) {
5055     po = &ops[i];
5056     if (po->op == OP_FST)
5057       return i;
5058     if (g_labels[i] != NULL || (po->flags & OPF_JMP))
5059       return -1;
5060     if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
5061       return -1;
5062     if (po->op == OP_ADD && po->operand[0].reg == xSP)
5063       return -1;
5064   }
5065
5066   return -1;
5067 }
5068
5069 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
5070   int *regmask_ffca)
5071 {
5072   struct parsed_op *po;
5073   int offset = 0;
5074   int base_arg;
5075   int j, arg;
5076   int ret;
5077
5078   for (base_arg = 0; base_arg < pp->argc; base_arg++)
5079     if (pp->arg[base_arg].reg == NULL)
5080       break;
5081
5082   for (j = i; j > 0; )
5083   {
5084     ferr_assert(&ops[j], g_labels[j] == NULL);
5085     j--;
5086
5087     po = &ops[j];
5088     ferr_assert(po, po->op != OP_PUSH);
5089     if (po->op == OP_FST)
5090     {
5091       if (po->operand[0].type != OPT_REGMEM)
5092         continue;
5093       ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
5094       if (ret != 0)
5095         continue;
5096       if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
5097         //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
5098         continue;
5099       }
5100
5101       arg = base_arg + offset / 4;
5102       mark_float_arg(po, pp, arg, regmask_ffca);
5103     }
5104     else if (po->op == OP_SUB && po->operand[0].reg == xSP
5105       && po->operand[1].type == OPT_CONST)
5106     {
5107       po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5108       break;
5109     }
5110   }
5111
5112   for (arg = base_arg; arg < pp->argc; arg++) {
5113     ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
5114     po = pp->arg[arg].datap;
5115     if (po == NULL)
5116       ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
5117     if (po->operand[0].lmod == OPLM_QWORD)
5118       arg++;
5119   }
5120
5121   return 0;
5122 }
5123
5124 static int collect_call_args_early(int i, struct parsed_proto *pp,
5125   int *regmask, int *regmask_ffca)
5126 {
5127   struct parsed_op *po;
5128   int arg, ret;
5129   int offset;
5130   int j, k;
5131
5132   for (arg = 0; arg < pp->argc; arg++)
5133     if (pp->arg[arg].reg == NULL)
5134       break;
5135
5136   // first see if it can be easily done
5137   for (j = i; j > 0 && arg < pp->argc; )
5138   {
5139     if (g_labels[j] != NULL)
5140       return -1;
5141     j--;
5142
5143     po = &ops[j];
5144     if (po->op == OP_CALL)
5145       return -1;
5146     else if (po->op == OP_ADD && po->operand[0].reg == xSP)
5147       return -1;
5148     else if (po->op == OP_POP)
5149       return -1;
5150     else if (po->flags & OPF_CJMP)
5151       return -1;
5152     else if (po->op == OP_PUSH) {
5153       if (po->flags & (OPF_FARG|OPF_FARGNR))
5154         return -1;
5155       if (!g_header_mode) {
5156         ret = scan_for_mod(po, j + 1, i, 1);
5157         if (ret >= 0)
5158           return -1;
5159       }
5160
5161       if (pp->arg[arg].type.is_va_list)
5162         return -1;
5163
5164       // next arg
5165       for (arg++; arg < pp->argc; arg++)
5166         if (pp->arg[arg].reg == NULL)
5167           break;
5168     }
5169     else if (po->op == OP_SUB && po->operand[0].reg == xSP
5170       && po->operand[1].type == OPT_CONST)
5171     {
5172       if (po->flags & (OPF_RMD|OPF_DONE))
5173         return -1;
5174       if (po->operand[1].val != pp->argc_stack * 4)
5175         ferr(po, "unexpected esp adjust: %d\n",
5176              po->operand[1].val * 4);
5177       ferr_assert(po, pp->argc - arg == pp->argc_stack);
5178       return collect_call_args_no_push(i, pp, regmask_ffca);
5179     }
5180   }
5181
5182   if (arg < pp->argc)
5183     return -1;
5184
5185   // now do it
5186   for (arg = 0; arg < pp->argc; arg++)
5187     if (pp->arg[arg].reg == NULL)
5188       break;
5189
5190   for (j = i; j > 0 && arg < pp->argc; )
5191   {
5192     j--;
5193
5194     if (ops[j].op == OP_PUSH)
5195     {
5196       ops[j].p_argnext = -1;
5197       ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
5198
5199       k = check_for_stp(j + 1, i);
5200       if (k != -1) {
5201         // push ecx; fstp dword ptr [esp]
5202         ret = parse_stack_esp_offset(&ops[k],
5203                 ops[k].operand[0].name, &offset);
5204         if (ret == 0 && offset == 0) {
5205           if (!pp->arg[arg].type.is_float)
5206             ferr(&ops[i], "arg %d should be float\n", arg + 1);
5207           mark_float_arg(&ops[k], pp, arg, regmask_ffca);
5208         }
5209       }
5210
5211       if (pp->arg[arg].datap == NULL) {
5212         pp->arg[arg].datap = &ops[j];
5213         if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5214           *regmask |= 1 << ops[j].operand[0].reg;
5215       }
5216
5217       ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5218       ops[j].flags &= ~OPF_RSAVE;
5219
5220       // next arg
5221       for (arg++; arg < pp->argc; arg++)
5222         if (pp->arg[arg].reg == NULL)
5223           break;
5224     }
5225   }
5226
5227   return 0;
5228 }
5229
5230 static int sync_argnum(struct parsed_op *po, int argnum)
5231 {
5232   struct parsed_op *po_tmp;
5233
5234   // see if other branches don't have higher argnum
5235   for (po_tmp = po; po_tmp != NULL; ) {
5236     if (argnum < po_tmp->p_argnum)
5237       argnum = po_tmp->p_argnum;
5238     // note: p_argnext is active on current collect_call_args only
5239     po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5240   }
5241
5242   // make all argnums consistent
5243   for (po_tmp = po; po_tmp != NULL; ) {
5244     if (po_tmp->p_argnum != 0)
5245       po_tmp->p_argnum = argnum;
5246     po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5247   }
5248
5249   return argnum;
5250 }
5251
5252 static int collect_call_args_r(struct parsed_op *po, int i,
5253   struct parsed_proto *pp, int *regmask, int *arg_grp,
5254   int arg, int argnum, int magic, int need_op_saving, int may_reuse)
5255 {
5256   struct parsed_proto *pp_tmp;
5257   struct parsed_op *po_tmp;
5258   struct label_ref *lr;
5259   int need_to_save_current;
5260   int arg_grp_current = 0;
5261   int save_args_seen = 0;
5262   int ret = 0;
5263   int reg;
5264   char buf[32];
5265   int j, k;
5266
5267   if (i < 0) {
5268     ferr(po, "dead label encountered\n");
5269     return -1;
5270   }
5271
5272   for (; arg < pp->argc; arg++, argnum++)
5273     if (pp->arg[arg].reg == NULL)
5274       break;
5275   magic = (magic & 0xffffff) | (arg << 24);
5276
5277   for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5278   {
5279     if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5280       if (ops[j].cc_scratch != magic) {
5281         ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5282            pp->name);
5283         return -1;
5284       }
5285       // ok: have already been here
5286       return 0;
5287     }
5288     ops[j].cc_scratch = magic;
5289
5290     if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5291       lr = &g_label_refs[j];
5292       if (lr->next != NULL)
5293         need_op_saving = 1;
5294       for (; lr->next; lr = lr->next) {
5295         check_i(&ops[j], lr->i);
5296         if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5297           may_reuse = 1;
5298         ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5299                 arg, argnum, magic, need_op_saving, may_reuse);
5300         if (ret < 0)
5301           return ret;
5302       }
5303
5304       check_i(&ops[j], lr->i);
5305       if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5306         may_reuse = 1;
5307       if (j > 0 && LAST_OP(j - 1)) {
5308         // follow last branch in reverse
5309         j = lr->i;
5310         continue;
5311       }
5312       need_op_saving = 1;
5313       ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5314               arg, argnum, magic, need_op_saving, may_reuse);
5315       if (ret < 0)
5316         return ret;
5317     }
5318     j--;
5319
5320     if (ops[j].op == OP_CALL)
5321     {
5322       if (pp->is_unresolved)
5323         break;
5324
5325       pp_tmp = ops[j].pp;
5326       if (pp_tmp == NULL)
5327         ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5328           arg, pp->argc, ops[j].operand[0].name);
5329       if (may_reuse && pp_tmp->argc_stack > 0)
5330         ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5331           arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5332     }
5333     // esp adjust of 0 means we collected it before
5334     else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5335       && (ops[j].operand[1].type != OPT_CONST
5336           || ops[j].operand[1].val != 0))
5337     {
5338       if (pp->is_unresolved)
5339         break;
5340
5341       fnote(po, "(this call)\n");
5342       ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5343         arg, pp->argc, ops[j].operand[1].val);
5344     }
5345     else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5346     {
5347       if (pp->is_unresolved)
5348         break;
5349
5350       fnote(po, "(this call)\n");
5351       ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5352     }
5353     else if (ops[j].flags & OPF_CJMP)
5354     {
5355       if (pp->is_unresolved)
5356         break;
5357
5358       may_reuse = 1;
5359     }
5360     else if (ops[j].op == OP_PUSH
5361       && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5362     {
5363       if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5364         break;
5365
5366       ops[j].p_argnext = -1;
5367       po_tmp = pp->arg[arg].datap;
5368       if (po_tmp != NULL)
5369         ops[j].p_argnext = po_tmp - ops;
5370       pp->arg[arg].datap = &ops[j];
5371
5372       argnum = sync_argnum(&ops[j], argnum);
5373
5374       need_to_save_current = 0;
5375       reg = -1;
5376       if (ops[j].operand[0].type == OPT_REG)
5377         reg = ops[j].operand[0].reg;
5378
5379       if (!need_op_saving) {
5380         ret = scan_for_mod(&ops[j], j + 1, i, 1);
5381         need_to_save_current = (ret >= 0);
5382       }
5383       if (need_op_saving || need_to_save_current) {
5384         // mark this arg as one that needs operand saving
5385         pp->arg[arg].is_saved = 1;
5386
5387         if (save_args_seen & (1 << (argnum - 1))) {
5388           save_args_seen = 0;
5389           arg_grp_current++;
5390           if (arg_grp_current >= MAX_ARG_GRP)
5391             ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5392               argnum, pp->name);
5393         }
5394       }
5395       else if (ops[j].p_argnum == 0)
5396         ops[j].flags |= OPF_RMD;
5397
5398       // some PUSHes are reused by different calls on other branches,
5399       // but that can't happen if we didn't branch, so they
5400       // can be removed from future searches (handles nested calls)
5401       if (!may_reuse)
5402         ops[j].flags |= OPF_FARGNR;
5403
5404       ops[j].flags |= OPF_FARG;
5405       ops[j].flags &= ~OPF_RSAVE;
5406
5407       // check for __VALIST
5408       if (!pp->is_unresolved && g_func_pp != NULL
5409         && pp->arg[arg].type.is_va_list)
5410       {
5411         k = -1;
5412         ret = resolve_origin(j, &ops[j].operand[0],
5413                 magic + 1, &k, NULL);
5414         if (ret == 1 && k >= 0)
5415         {
5416           if (ops[k].op == OP_LEA) {
5417             if (!g_func_pp->is_vararg)
5418               ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5419                    g_func_pp->name);
5420
5421             snprintf(buf, sizeof(buf), "arg_%X",
5422               g_func_pp->argc_stack * 4);
5423             if (strstr(ops[k].operand[1].name, buf)
5424              || strstr(ops[k].operand[1].name, "arglist"))
5425             {
5426               ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5427               ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5428               pp->arg[arg].is_saved = 0;
5429               reg = -1;
5430             }
5431             else
5432               ferr(&ops[k], "va_list arg detection failed\n");
5433           }
5434           // check for va_list from g_func_pp arg too
5435           else if (ops[k].op == OP_MOV
5436             && is_stack_access(&ops[k], &ops[k].operand[1]))
5437           {
5438             ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5439               buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5440             if (ret >= 0) {
5441               ops[k].flags |= OPF_RMD | OPF_DONE;
5442               ops[j].flags |= OPF_RMD;
5443               ops[j].p_argpass = ret + 1;
5444               pp->arg[arg].is_saved = 0;
5445               reg = -1;
5446             }
5447           }
5448         }
5449       }
5450
5451       if (pp->arg[arg].is_saved) {
5452         ops[j].flags &= ~OPF_RMD;
5453         ops[j].p_argnum = argnum;
5454       }
5455
5456       // tracking reg usage
5457       if (reg >= 0)
5458         *regmask |= 1 << reg;
5459
5460       arg++;
5461       argnum++;
5462       if (!pp->is_unresolved) {
5463         // next arg
5464         for (; arg < pp->argc; arg++, argnum++)
5465           if (pp->arg[arg].reg == NULL)
5466             break;
5467       }
5468       magic = (magic & 0xffffff) | (arg << 24);
5469     }
5470
5471     if (ops[j].p_arggrp > arg_grp_current) {
5472       save_args_seen = 0;
5473       arg_grp_current = ops[j].p_arggrp;
5474     }
5475     if (ops[j].p_argnum > 0)
5476       save_args_seen |= 1 << (ops[j].p_argnum - 1);
5477   }
5478
5479   if (arg < pp->argc) {
5480     ferr(po, "arg collect failed for '%s': %d/%d\n",
5481       pp->name, arg, pp->argc);
5482     return -1;
5483   }
5484
5485   if (arg_grp_current > *arg_grp)
5486     *arg_grp = arg_grp_current;
5487
5488   return arg;
5489 }
5490
5491 static int collect_call_args(struct parsed_op *po, int i,
5492   struct parsed_proto *pp, int *regmask, int magic)
5493 {
5494   // arg group is for cases when pushes for
5495   // multiple funcs are going on
5496   struct parsed_op *po_tmp;
5497   int arg_grp = 0;
5498   int ret;
5499   int a;
5500
5501   ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5502           0, 1, magic, 0, 0);
5503   if (ret < 0)
5504     return ret;
5505
5506   if (arg_grp != 0) {
5507     // propagate arg_grp
5508     for (a = 0; a < pp->argc; a++) {
5509       if (pp->arg[a].reg != NULL)
5510         continue;
5511
5512       po_tmp = pp->arg[a].datap;
5513       while (po_tmp != NULL) {
5514         po_tmp->p_arggrp = arg_grp;
5515         po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5516       }
5517     }
5518   }
5519
5520   if (pp->is_unresolved) {
5521     pp->argc += ret;
5522     pp->argc_stack += ret;
5523     for (a = 0; a < pp->argc; a++)
5524       if (pp->arg[a].type.name == NULL)
5525         pp->arg[a].type.name = strdup("int");
5526   }
5527
5528   return ret;
5529 }
5530
5531 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5532   int regmask_now, int *regmask,
5533   int regmask_save_now, int *regmask_save,
5534   int *regmask_init, int regmask_arg)
5535 {
5536   struct parsed_op *po;
5537   int already_saved;
5538   int regmask_new;
5539   int regmask_op;
5540   int flags_set;
5541   int ret, reg;
5542   int j;
5543
5544   for (; i < opcnt; i++)
5545   {
5546     po = &ops[i];
5547     if (cbits[i >> 3] & (1 << (i & 7)))
5548       return;
5549     cbits[i >> 3] |= (1 << (i & 7));
5550
5551     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5552       if (po->flags & (OPF_RMD|OPF_DONE))
5553         continue;
5554       if (po->btj != NULL) {
5555         for (j = 0; j < po->btj->count; j++) {
5556           check_i(po, po->btj->d[j].bt_i);
5557           reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5558             regmask_now, regmask, regmask_save_now, regmask_save,
5559             regmask_init, regmask_arg);
5560         }
5561         return;
5562       }
5563
5564       check_i(po, po->bt_i);
5565       if (po->flags & OPF_CJMP)
5566         reg_use_pass(po->bt_i, opcnt, cbits,
5567           regmask_now, regmask, regmask_save_now, regmask_save,
5568           regmask_init, regmask_arg);
5569       else
5570         i = po->bt_i - 1;
5571       continue;
5572     }
5573
5574     if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5575       && !g_func_pp->is_userstack
5576       && po->operand[0].type == OPT_REG)
5577     {
5578       reg = po->operand[0].reg;
5579       ferr_assert(po, reg >= 0);
5580
5581       already_saved = 0;
5582       flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5583       if (regmask_now & (1 << reg)) {
5584         already_saved = regmask_save_now & (1 << reg);
5585         flags_set = OPF_RSAVE | OPF_DONE;
5586       }
5587
5588       ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5589       if (ret == 1) {
5590         scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5591           reg, 0, 0, flags_set);
5592       }
5593       else {
5594         ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5595         if (ret == 1) {
5596           scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5597             flags_set);
5598         }
5599       }
5600       if (ret == 1) {
5601         ferr_assert(po, !already_saved);
5602         po->flags |= flags_set;
5603
5604         if (regmask_now & (1 << reg)) {
5605           regmask_save_now |= (1 << reg);
5606           *regmask_save |= regmask_save_now;
5607         }
5608         continue;
5609       }
5610     }
5611     else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5612       reg = po->operand[0].reg;
5613       ferr_assert(po, reg >= 0);
5614
5615       if (regmask_save_now & (1 << reg))
5616         regmask_save_now &= ~(1 << reg);
5617       else
5618         regmask_now &= ~(1 << reg);
5619       continue;
5620     }
5621     else if (po->op == OP_CALL) {
5622       if ((po->regmask_dst & (1 << xAX))
5623         && !(po->regmask_dst & (1 << xDX)))
5624       {
5625         if (po->flags & OPF_TAIL)
5626           // don't need eax, will do "return f();" or "f(); return;"
5627           po->regmask_dst &= ~(1 << xAX);
5628         else {
5629           struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5630           j = -1;
5631           find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5632           if (j == -1)
5633             // not used
5634             po->regmask_dst &= ~(1 << xAX);
5635         }
5636       }
5637
5638       // not "full stack" mode and have something in stack
5639       if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5640         ferr(po, "float stack is not empty on func call\n");
5641     }
5642
5643     if (po->flags & OPF_NOREGS)
5644       continue;
5645
5646     // if incomplete register is used, clear it on init to avoid
5647     // later use of uninitialized upper part in some situations
5648     if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5649         && po->operand[0].lmod != OPLM_DWORD)
5650     {
5651       reg = po->operand[0].reg;
5652       ferr_assert(po, reg >= 0);
5653
5654       if (!(regmask_now & (1 << reg)))
5655         *regmask_init |= 1 << reg;
5656     }
5657
5658     regmask_op = po->regmask_src | po->regmask_dst;
5659
5660     regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5661     regmask_new &= ~(1 << xSP);
5662     if (g_bp_frame && !(po->flags & OPF_EBP_S))
5663       regmask_new &= ~(1 << xBP);
5664
5665     if (regmask_new != 0)
5666       fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5667
5668     if (regmask_op & (1 << xBP)) {
5669       if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5670         if (po->regmask_dst & (1 << xBP))
5671           // compiler decided to drop bp frame and use ebp as scratch
5672           scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5673         else
5674           regmask_op &= ~(1 << xBP);
5675       }
5676     }
5677
5678     if (po->flags & OPF_FPUSH) {
5679       if (regmask_now & mxST1)
5680         regmask_now |= mxSTa; // switch to "full stack" mode
5681       if (regmask_now & mxSTa)
5682         po->flags |= OPF_FSHIFT;
5683       if (!(regmask_now & mxST7_2)) {
5684         regmask_now =
5685           (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5686       }
5687     }
5688
5689     regmask_now |= regmask_op;
5690     *regmask |= regmask_now;
5691
5692     // released regs
5693     if (po->flags & OPF_FPOPP) {
5694       if ((regmask_now & mxSTa) == 0)
5695         ferr(po, "float pop on empty stack?\n");
5696       if (regmask_now & mxST7_2)
5697         po->flags |= OPF_FSHIFT;
5698       if (!(regmask_now & mxST7_2))
5699         regmask_now &= ~mxST1_0;
5700     }
5701     else if (po->flags & OPF_FPOP) {
5702       if ((regmask_now & mxSTa) == 0)
5703         ferr(po, "float pop on empty stack?\n");
5704       if (regmask_now & (mxST7_2 | mxST1))
5705         po->flags |= OPF_FSHIFT;
5706       if (!(regmask_now & mxST7_2)) {
5707         regmask_now =
5708           (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5709       }
5710     }
5711
5712     if (po->flags & OPF_TAIL) {
5713       if (!(regmask_now & mxST7_2)) {
5714         if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5715           if (!(regmask_now & mxST0))
5716             ferr(po, "no st0 on float return, mask: %x\n",
5717                  regmask_now);
5718         }
5719         else if (regmask_now & mxST1_0)
5720           ferr(po, "float regs on tail: %x\n", regmask_now);
5721       }
5722
5723       // there is support for "conditional tailcall", sort of
5724       if (!(po->flags & OPF_CC))
5725         return;
5726     }
5727   }
5728 }
5729
5730 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5731 {
5732   int i;
5733
5734   for (i = 0; i < pp->argc; i++)
5735     if (pp->arg[i].reg == NULL)
5736       break;
5737
5738   if (pp->argc_stack)
5739     memmove(&pp->arg[i + 1], &pp->arg[i],
5740       sizeof(pp->arg[0]) * pp->argc_stack);
5741   memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5742   pp->arg[i].reg = strdup(reg);
5743   pp->arg[i].type.name = strdup("int");
5744   pp->argc++;
5745   pp->argc_reg++;
5746 }
5747
5748 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5749   int *pfomask, const char *dst_opr_text)
5750 {
5751   if (*pfomask & (1 << PFO_Z)) {
5752     fprintf(fout, "\n  cond_z = (%s%s == 0);",
5753       lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5754     *pfomask &= ~(1 << PFO_Z);
5755   }
5756 }
5757
5758 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5759   int *pfomask, const char *dst_opr_text)
5760 {
5761   if (*pfomask & (1 << PFO_S)) {
5762     fprintf(fout, "\n  cond_s = (%s%s < 0);",
5763       lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5764     *pfomask &= ~(1 << PFO_S);
5765   }
5766 }
5767
5768 static void output_std_flags(FILE *fout, struct parsed_op *po,
5769   int *pfomask, const char *dst_opr_text)
5770 {
5771   output_std_flag_z(fout, po, pfomask, dst_opr_text);
5772   output_std_flag_s(fout, po, pfomask, dst_opr_text);
5773 }
5774
5775 enum {
5776   OPP_FORCE_NORETURN = (1 << 0),
5777   OPP_SIMPLE_ARGS    = (1 << 1),
5778   OPP_ALIGN          = (1 << 2),
5779 };
5780
5781 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5782   int flags)
5783 {
5784   const char *cconv = "";
5785
5786   if (pp->is_fastcall)
5787     cconv = "__fastcall ";
5788   else if (pp->is_stdcall && pp->argc_reg == 0)
5789     cconv = "__stdcall ";
5790
5791   fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5792
5793   if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5794     fprintf(fout, "noreturn ");
5795 }
5796
5797 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5798   int flags)
5799 {
5800   int i;
5801
5802   fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5803     pp->ret_type.name);
5804   if (pp->is_fptr)
5805     fprintf(fout, "(");
5806   output_pp_attrs(fout, pp, flags);
5807   if (pp->is_fptr)
5808     fprintf(fout, "*");
5809   fprintf(fout, "%s", pp->name);
5810   if (pp->is_fptr)
5811     fprintf(fout, ")");
5812
5813   fprintf(fout, "(");
5814   for (i = 0; i < pp->argc; i++) {
5815     if (i > 0)
5816       fprintf(fout, ", ");
5817     if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5818       && !(flags & OPP_SIMPLE_ARGS))
5819     {
5820       // func pointer
5821       output_pp(fout, pp->arg[i].pp, 0);
5822     }
5823     else if (pp->arg[i].type.is_retreg) {
5824       fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5825     }
5826     else {
5827       fprintf(fout, "%s", pp->arg[i].type.name);
5828       if (!pp->is_fptr)
5829         fprintf(fout, " a%d", i + 1);
5830     }
5831
5832     if (pp->arg[i].type.is_64bit)
5833       i++;
5834   }
5835   if (pp->is_vararg) {
5836     if (i > 0)
5837       fprintf(fout, ", ");
5838     fprintf(fout, "...");
5839   }
5840   fprintf(fout, ")");
5841 }
5842
5843 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5844 {
5845   char buf1[16];
5846
5847   buf1[0] = 0;
5848   if (grp > 0)
5849     snprintf(buf1, sizeof(buf1), "%d", grp);
5850   snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5851
5852   return buf;
5853 }
5854
5855 static void gen_x_cleanup(int opcnt);
5856
5857 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5858 {
5859   struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5860   struct parsed_opr *last_arith_dst = NULL;
5861   char buf1[256], buf2[256], buf3[256], cast[64];
5862   struct parsed_proto *pp, *pp_tmp;
5863   struct parsed_data *pd;
5864   int save_arg_vars[MAX_ARG_GRP] = { 0, };
5865   unsigned char cbits[MAX_OPS / 8];
5866   const char *float_type;
5867   const char *float_st0;
5868   const char *float_st1;
5869   int need_float_stack = 0;
5870   int need_float_sw = 0; // status word
5871   int need_tmp_var = 0;
5872   int need_tmp64 = 0;
5873   int cond_vars = 0;
5874   int had_decl = 0;
5875   int label_pending = 0;
5876   int need_double = 0;
5877   int stack_align = 0;
5878   int stack_fsz_adj = 0;
5879   int regmask_save = 0; // used regs saved/restored in this func
5880   int regmask_arg;      // regs from this function args (fastcall, etc)
5881   int regmask_ret;      // regs needed on ret
5882   int regmask_now;      // temp
5883   int regmask_init = 0; // regs that need zero initialization
5884   int regmask_pp = 0;   // regs used in complex push-pop graph
5885   int regmask_ffca = 0; // float function call args
5886   int regmask = 0;      // used regs
5887   int pfomask = 0;
5888   int found = 0;
5889   int dead_dst;
5890   int no_output;
5891   int i, j, l;
5892   int arg;
5893   int reg;
5894   int ret;
5895
5896   g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5897   g_stack_frame_used = 0;
5898   g_seh_size = 0;
5899   if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5900     regmask_init = g_regmask_init;
5901
5902   g_func_pp = proto_parse(fhdr, funcn, 0);
5903   if (g_func_pp == NULL)
5904     ferr(ops, "proto_parse failed for '%s'\n", funcn);
5905
5906   regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5907   regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5908
5909   // pass1:
5910   // - resolve all branches
5911   // - parse calls with labels
5912   resolve_branches_parse_calls(opcnt);
5913
5914   // pass2:
5915   // - handle ebp/esp frame, remove ops related to it
5916   scan_prologue_epilogue(opcnt, &stack_align);
5917
5918   // handle a case where sf size is unalignment, but is
5919   // placed in a way that elements are still aligned
5920   if (g_stack_fsz & 4) {
5921     for (i = 0; i < g_eqcnt; i++) {
5922       if (g_eqs[i].lmod != OPLM_QWORD)
5923         continue;
5924       if (!(g_eqs[i].offset & 4)) {
5925         g_stack_fsz += 4;
5926         stack_fsz_adj = 4;
5927       }
5928       break;
5929     }
5930   }
5931
5932   // pass3:
5933   // - remove dead labels
5934   // - set regs needed at ret
5935   for (i = 0; i < opcnt; i++)
5936   {
5937     if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5938       free(g_labels[i]);
5939       g_labels[i] = NULL;
5940     }
5941
5942     if (ops[i].op == OP_RET)
5943       ops[i].regmask_src |= regmask_ret;
5944   }
5945
5946   // pass4:
5947   // - process trivial calls
5948   for (i = 0; i < opcnt; i++)
5949   {
5950     po = &ops[i];
5951     if (po->flags & (OPF_RMD|OPF_DONE))
5952       continue;
5953
5954     if (po->op == OP_CALL)
5955     {
5956       pp = process_call_early(i, opcnt, &j);
5957       if (pp != NULL) {
5958         if (!(po->flags & OPF_ATAIL)) {
5959           // since we know the args, try to collect them
5960           ret = collect_call_args_early(i, pp, &regmask, &regmask_ffca);
5961           if (ret != 0)
5962             pp = NULL;
5963         }
5964       }
5965
5966       if (pp != NULL) {
5967         if (j >= 0) {
5968           // commit esp adjust
5969           if (ops[j].op != OP_POP)
5970             patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5971           else {
5972             for (l = 0; l < pp->argc_stack; l++)
5973               ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5974           }
5975         }
5976
5977         if (strstr(pp->ret_type.name, "int64"))
5978           need_tmp64 = 1;
5979
5980         po->flags |= OPF_DONE;
5981       }
5982     }
5983   }
5984
5985   // pass5:
5986   // - process calls, stage 2
5987   // - handle some push/pop pairs
5988   // - scan for STD/CLD, propagate DF
5989   // - try to resolve needed x87 status word bits
5990   for (i = 0; i < opcnt; i++)
5991   {
5992     int mask, z_check;
5993
5994     po = &ops[i];
5995     if (po->flags & OPF_RMD)
5996       continue;
5997
5998     if (po->op == OP_CALL)
5999     {
6000       if (!(po->flags & OPF_DONE)) {
6001         pp = process_call(i, opcnt);
6002
6003         if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
6004           // since we know the args, collect them
6005           collect_call_args(po, i, pp, &regmask, i + opcnt * 2);
6006         }
6007         // for unresolved, collect after other passes
6008       }
6009
6010       pp = po->pp;
6011       ferr_assert(po, pp != NULL);
6012
6013       po->regmask_src |= get_pp_arg_regmask_src(pp);
6014       po->regmask_dst |= get_pp_arg_regmask_dst(pp);
6015
6016       if (po->regmask_dst & mxST0)
6017         po->flags |= OPF_FPUSH;
6018
6019       if (strstr(pp->ret_type.name, "int64"))
6020         need_tmp64 = 1;
6021
6022       continue;
6023     }
6024
6025     if (po->flags & OPF_DONE)
6026       continue;
6027
6028     switch (po->op) {
6029     case OP_PUSH:
6030       if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
6031         && po->operand[0].type == OPT_CONST)
6032       {
6033         scan_for_pop_const(i, opcnt, i + opcnt * 12);
6034       }
6035       break;
6036
6037     case OP_POP:
6038       scan_pushes_for_pop(i, opcnt, &regmask_pp);
6039       break;
6040
6041     case OP_STD:
6042       po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
6043       scan_propagate_df(i + 1, opcnt);
6044       break;
6045
6046     case OP_FNSTSW:
6047       need_float_sw = 1;
6048       if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
6049         ferr(po, "TODO: fnstsw to mem\n");
6050       ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
6051       if (ret != 0)
6052         ferr(po, "fnstsw resolve failed\n");
6053       ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
6054               (void *)(long)(mask | (z_check << 16)));
6055       if (ret != 1)
6056         ferr(po, "failed to find fcom: %d\n", ret);
6057       break;
6058
6059     default:
6060       break;
6061     }
6062   }
6063
6064   // pass6:
6065   // - find POPs for PUSHes, rm both
6066   // - scan for all used registers
6067   memset(cbits, 0, sizeof(cbits));
6068   reg_use_pass(0, opcnt, cbits, regmask_init, &regmask,
6069     0, &regmask_save, &regmask_init, regmask_arg);
6070
6071   need_float_stack = !!(regmask & mxST7_2);
6072
6073   // pass7:
6074   // - find flag set ops for their users
6075   // - do unresolved calls
6076   // - declare indirect functions
6077   // - other op specific processing
6078   for (i = 0; i < opcnt; i++)
6079   {
6080     po = &ops[i];
6081     if (po->flags & (OPF_RMD|OPF_DONE))
6082       continue;
6083
6084     if (po->flags & OPF_CC)
6085     {
6086       int setters[16], cnt = 0, branched = 0;
6087
6088       ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
6089               &branched, setters, &cnt);
6090       if (ret < 0 || cnt <= 0)
6091         ferr(po, "unable to trace flag setter(s)\n");
6092       if (cnt > ARRAY_SIZE(setters))
6093         ferr(po, "too many flag setters\n");
6094
6095       for (j = 0; j < cnt; j++)
6096       {
6097         tmp_op = &ops[setters[j]]; // flag setter
6098         pfomask = 0;
6099
6100         // to get nicer code, we try to delay test and cmp;
6101         // if we can't because of operand modification, or if we
6102         // have arith op, or branch, make it calculate flags explicitly
6103         if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
6104         {
6105           if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
6106             pfomask = 1 << po->pfo;
6107         }
6108         else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
6109           pfomask = 1 << po->pfo;
6110         }
6111         else {
6112           // see if we'll be able to handle based on op result
6113           if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
6114                && po->pfo != PFO_Z && po->pfo != PFO_S
6115                && po->pfo != PFO_P)
6116               || branched
6117               || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
6118           {
6119             pfomask = 1 << po->pfo;
6120           }
6121
6122           if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
6123             propagate_lmod(tmp_op, &tmp_op->operand[0],
6124               &tmp_op->operand[1]);
6125             if (tmp_op->operand[0].lmod == OPLM_DWORD)
6126               need_tmp64 = 1;
6127           }
6128         }
6129         if (pfomask) {
6130           tmp_op->pfomask |= pfomask;
6131           cond_vars |= pfomask;
6132         }
6133         // note: may overwrite, currently not a problem
6134         po->datap = tmp_op;
6135       }
6136
6137       if (po->op == OP_RCL || po->op == OP_RCR
6138        || po->op == OP_ADC || po->op == OP_SBB)
6139         cond_vars |= 1 << PFO_C;
6140     }
6141
6142     switch (po->op) {
6143     case OP_CMPS:
6144     case OP_SCAS:
6145       cond_vars |= 1 << PFO_Z;
6146       break;
6147
6148     case OP_MUL:
6149       if (po->operand[0].lmod == OPLM_DWORD)
6150         need_tmp64 = 1;
6151       break;
6152
6153     case OP_IMUL:
6154       if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
6155         need_tmp64 = 1;
6156       break;
6157
6158     case OP_CALL:
6159       // note: resolved non-reg calls are OPF_DONE already
6160       pp = po->pp;
6161       ferr_assert(po, pp != NULL);
6162
6163       if (pp->is_unresolved) {
6164         int regmask_stack = 0;
6165         collect_call_args(po, i, pp, &regmask, i + opcnt * 2);
6166
6167         // this is pretty rough guess:
6168         // see ecx and edx were pushed (and not their saved versions)
6169         for (arg = 0; arg < pp->argc; arg++) {
6170           if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
6171             continue;
6172
6173           tmp_op = pp->arg[arg].datap;
6174           if (tmp_op == NULL)
6175             ferr(po, "parsed_op missing for arg%d\n", arg);
6176           if (tmp_op->operand[0].type == OPT_REG)
6177             regmask_stack |= 1 << tmp_op->operand[0].reg;
6178         }
6179
6180         if (!((regmask_stack & (1 << xCX))
6181           && (regmask_stack & (1 << xDX))))
6182         {
6183           if (pp->argc_stack != 0
6184            || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
6185           {
6186             pp_insert_reg_arg(pp, "ecx");
6187             pp->is_fastcall = 1;
6188             regmask_init |= 1 << xCX;
6189             regmask |= 1 << xCX;
6190           }
6191           if (pp->argc_stack != 0
6192            || ((regmask | regmask_arg) & (1 << xDX)))
6193           {
6194             pp_insert_reg_arg(pp, "edx");
6195             regmask_init |= 1 << xDX;
6196             regmask |= 1 << xDX;
6197           }
6198         }
6199
6200         // note: __cdecl doesn't fall into is_unresolved category
6201         if (pp->argc_stack > 0)
6202           pp->is_stdcall = 1;
6203       }
6204       break;
6205
6206     case OP_MOV:
6207       if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6208       {
6209         // <var> = offset <something>
6210         if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6211           && !IS_START(po->operand[1].name, "off_"))
6212         {
6213           if (!po->operand[0].pp->is_fptr)
6214             ferr(po, "%s not declared as fptr when it should be\n",
6215               po->operand[0].name);
6216           if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6217             pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6218             pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6219             fnote(po, "var:  %s\n", buf1);
6220             fnote(po, "func: %s\n", buf2);
6221             ferr(po, "^ mismatch\n");
6222           }
6223         }
6224       }
6225       break;
6226
6227     case OP_DIV:
6228     case OP_IDIV:
6229       if (po->operand[0].lmod == OPLM_DWORD) {
6230         // 32bit division is common, look for it
6231         if (po->op == OP_DIV)
6232           ret = scan_for_reg_clear(i, xDX);
6233         else
6234           ret = scan_for_cdq_edx(i);
6235         if (ret >= 0)
6236           po->flags |= OPF_32BIT;
6237         else
6238           need_tmp64 = 1;
6239       }
6240       else
6241         need_tmp_var = 1;
6242       break;
6243
6244     case OP_CLD:
6245       po->flags |= OPF_RMD | OPF_DONE;
6246       break;
6247
6248     case OP_RCL:
6249     case OP_RCR:
6250     case OP_XCHG:
6251       need_tmp_var = 1;
6252       break;
6253
6254     case OP_FLD:
6255       if (po->operand[0].lmod == OPLM_QWORD)
6256         need_double = 1;
6257       break;
6258
6259     case OPP_ALLSHL:
6260     case OPP_ALLSHR:
6261       need_tmp64 = 1;
6262       break;
6263
6264     case OPP_FTOL: {
6265       struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
6266       j = -1;
6267       find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
6268       if (j == -1)
6269         po->flags |= OPF_32BIT;
6270       break;
6271     }
6272
6273     default:
6274       break;
6275     }
6276
6277     // this might need it's own pass...
6278     if (po->op != OP_FST && po->p_argnum > 0)
6279       save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6280
6281     // correct for "full stack" mode late enable
6282     if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6283         && need_float_stack)
6284       po->flags |= OPF_FSHIFT;
6285   }
6286
6287   float_type = need_double ? "double" : "float";
6288   float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6289   float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6290
6291   // output starts here
6292
6293   if (g_seh_found)
6294     fprintf(fout, "// had SEH\n");
6295
6296   // define userstack size
6297   if (g_func_pp->is_userstack) {
6298     fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6299     fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6300     fprintf(fout, "#endif\n");
6301   }
6302
6303   // the function itself
6304   ferr_assert(ops, !g_func_pp->is_fptr);
6305   output_pp(fout, g_func_pp,
6306     (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6307   fprintf(fout, "\n{\n");
6308
6309   // declare indirect functions
6310   for (i = 0; i < opcnt; i++) {
6311     po = &ops[i];
6312     if (po->flags & OPF_RMD)
6313       continue;
6314
6315     if (po->op == OP_CALL) {
6316       pp = po->pp;
6317       if (pp == NULL)
6318         ferr(po, "NULL pp\n");
6319
6320       if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6321         if (pp->name[0] != 0) {
6322           if (IS_START(pp->name, "guess"))
6323             pp->is_guessed = 1;
6324
6325           memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6326           memcpy(pp->name, "i_", 2);
6327
6328           // might be declared already
6329           found = 0;
6330           for (j = 0; j < i; j++) {
6331             if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6332               if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6333                 found = 1;
6334                 break;
6335               }
6336             }
6337           }
6338           if (found)
6339             continue;
6340         }
6341         else
6342           snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6343
6344         fprintf(fout, "  ");
6345         output_pp(fout, pp, OPP_SIMPLE_ARGS);
6346         fprintf(fout, ";\n");
6347       }
6348     }
6349   }
6350
6351   // output LUTs/jumptables
6352   for (i = 0; i < g_func_pd_cnt; i++) {
6353     pd = &g_func_pd[i];
6354     fprintf(fout, "  static const ");
6355     if (pd->type == OPT_OFFSET) {
6356       fprintf(fout, "void *jt_%s[] =\n    { ", pd->label);
6357
6358       for (j = 0; j < pd->count; j++) {
6359         if (j > 0)
6360           fprintf(fout, ", ");
6361         fprintf(fout, "&&%s", pd->d[j].u.label);
6362       }
6363     }
6364     else {
6365       fprintf(fout, "%s %s[] =\n    { ",
6366         lmod_type_u(ops, pd->lmod), pd->label);
6367
6368       for (j = 0; j < pd->count; j++) {
6369         if (j > 0)
6370           fprintf(fout, ", ");
6371         fprintf(fout, "%u", pd->d[j].u.val);
6372       }
6373     }
6374     fprintf(fout, " };\n");
6375     had_decl = 1;
6376   }
6377
6378   // declare stack frame, va_arg
6379   if (g_stack_fsz) {
6380     if (stack_fsz_adj)
6381       fprintf(fout, "  // stack_fsz_adj %d\n", stack_fsz_adj);
6382
6383     fprintf(fout, "  union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6384     if (g_func_lmods & (1 << OPLM_WORD))
6385       fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6386     if (g_func_lmods & (1 << OPLM_BYTE))
6387       fprintf(fout, " u8 b[%d];", g_stack_fsz);
6388     if (g_func_lmods & (1 << OPLM_QWORD))
6389       fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6390
6391     if (stack_align > 8)
6392       ferr(ops, "unhandled stack align of %d\n", stack_align);
6393     else if (stack_align == 8)
6394       fprintf(fout, " u64 align;");
6395     fprintf(fout, " } sf;\n");
6396     had_decl = 1;
6397   }
6398
6399   if (g_func_pp->is_userstack) {
6400     fprintf(fout, "  u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6401     fprintf(fout, "  u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6402     had_decl = 1;
6403   }
6404
6405   if (g_func_pp->is_vararg) {
6406     fprintf(fout, "  va_list ap;\n");
6407     had_decl = 1;
6408   }
6409
6410   // declare arg-registers
6411   for (i = 0; i < g_func_pp->argc; i++) {
6412     if (g_func_pp->arg[i].reg != NULL) {
6413       reg = char_array_i(regs_r32,
6414               ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6415       if (regmask & (1 << reg)) {
6416         if (g_func_pp->arg[i].type.is_retreg)
6417           fprintf(fout, "  u32 %s = *r_%s;\n",
6418             g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6419         else
6420           fprintf(fout, "  u32 %s = (u32)a%d;\n",
6421             g_func_pp->arg[i].reg, i + 1);
6422       }
6423       else {
6424         if (g_func_pp->arg[i].type.is_retreg)
6425           ferr(ops, "retreg '%s' is unused?\n",
6426             g_func_pp->arg[i].reg);
6427         fprintf(fout, "  // %s = a%d; // unused\n",
6428           g_func_pp->arg[i].reg, i + 1);
6429       }
6430       had_decl = 1;
6431     }
6432   }
6433
6434   // declare normal registers
6435   regmask_now = regmask & ~regmask_arg;
6436   regmask_now &= ~(1 << xSP);
6437   if (regmask_now & 0x00ff) {
6438     for (reg = 0; reg < 8; reg++) {
6439       if (regmask_now & (1 << reg)) {
6440         fprintf(fout, "  u32 %s", regs_r32[reg]);
6441         if (regmask_init & (1 << reg))
6442           fprintf(fout, " = 0");
6443         fprintf(fout, ";\n");
6444         had_decl = 1;
6445       }
6446     }
6447   }
6448   // ... mmx
6449   if (regmask_now & 0xff00) {
6450     for (reg = 8; reg < 16; reg++) {
6451       if (regmask_now & (1 << reg)) {
6452         fprintf(fout, "  mmxr %s", regs_r32[reg]);
6453         if (regmask_init & (1 << reg))
6454           fprintf(fout, " = { 0, }");
6455         fprintf(fout, ";\n");
6456         had_decl = 1;
6457       }
6458     }
6459   }
6460   // ... x87
6461   if (need_float_stack) {
6462     fprintf(fout, "  %s f_st[8];\n", float_type);
6463     fprintf(fout, "  int f_stp = 0;\n");
6464     had_decl = 1;
6465   }
6466   else {
6467     if (regmask_now & 0xff0000) {
6468       for (reg = 16; reg < 24; reg++) {
6469         if (regmask_now & (1 << reg)) {
6470           fprintf(fout, "  %s f_st%d", float_type, reg - 16);
6471           if (regmask_init & (1 << reg))
6472             fprintf(fout, " = 0");
6473           fprintf(fout, ";\n");
6474           had_decl = 1;
6475         }
6476       }
6477     }
6478   }
6479
6480   if (need_float_sw) {
6481     fprintf(fout, "  u16 f_sw;\n");
6482     had_decl = 1;
6483   }
6484
6485   if (regmask_save) {
6486     for (reg = 0; reg < 8; reg++) {
6487       if (regmask_save & (1 << reg)) {
6488         fprintf(fout, "  u32 s_%s;\n", regs_r32[reg]);
6489         had_decl = 1;
6490       }
6491     }
6492   }
6493
6494   for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6495     if (save_arg_vars[i] == 0)
6496       continue;
6497     for (reg = 0; reg < 32; reg++) {
6498       if (save_arg_vars[i] & (1 << reg)) {
6499         fprintf(fout, "  u32 %s;\n",
6500           saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6501         had_decl = 1;
6502       }
6503     }
6504   }
6505
6506   if (regmask_ffca) {
6507     for (reg = 0; reg < 32; reg++) {
6508       if (regmask_ffca & (1 << reg)) {
6509         fprintf(fout, "  %s fs_%d;\n", float_type, reg + 1);
6510         had_decl = 1;
6511       }
6512     }
6513   }
6514
6515   // declare push-pop temporaries
6516   if (regmask_pp) {
6517     for (reg = 0; reg < 8; reg++) {
6518       if (regmask_pp & (1 << reg)) {
6519         fprintf(fout, "  u32 pp_%s;\n", regs_r32[reg]);
6520         had_decl = 1;
6521       }
6522     }
6523   }
6524
6525   if (cond_vars) {
6526     for (i = 0; i < 8; i++) {
6527       if (cond_vars & (1 << i)) {
6528         fprintf(fout, "  u32 cond_%s;\n", parsed_flag_op_names[i]);
6529         had_decl = 1;
6530       }
6531     }
6532   }
6533
6534   if (need_tmp_var) {
6535     fprintf(fout, "  u32 tmp;\n");
6536     had_decl = 1;
6537   }
6538
6539   if (need_tmp64) {
6540     fprintf(fout, "  u64 tmp64;\n");
6541     had_decl = 1;
6542   }
6543
6544   if (had_decl)
6545     fprintf(fout, "\n");
6546
6547   // do stack clear, if needed
6548   if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6549     fprintf(fout, "  ");
6550     if (g_stack_clear_len != 0) {
6551       if (g_stack_clear_len <= 4) {
6552         for (i = 0; i < g_stack_clear_len; i++)
6553           fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6554         fprintf(fout, "0;\n");
6555       }
6556       else {
6557         fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6558           g_stack_clear_start, g_stack_clear_len * 4);
6559       }
6560     }
6561     else
6562       fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6563   }
6564
6565   if (g_func_pp->is_vararg) {
6566     if (g_func_pp->argc_stack == 0)
6567       ferr(ops, "vararg func without stack args?\n");
6568     fprintf(fout, "  va_start(ap, a%d);\n", g_func_pp->argc);
6569   }
6570
6571   // output ops
6572   for (i = 0; i < opcnt; i++)
6573   {
6574     if (g_labels[i] != NULL) {
6575       fprintf(fout, "\n%s:\n", g_labels[i]);
6576       label_pending = 1;
6577
6578       delayed_flag_op = NULL;
6579       last_arith_dst = NULL;
6580     }
6581
6582     po = &ops[i];
6583     if (po->flags & OPF_RMD)
6584       continue;
6585
6586     no_output = 0;
6587
6588     #define assert_operand_cnt(n_) \
6589       if (po->operand_cnt != n_) \
6590         ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6591
6592     // conditional/flag using op?
6593     if (po->flags & OPF_CC)
6594     {
6595       int is_delayed = 0;
6596
6597       tmp_op = po->datap;
6598
6599       // we go through all this trouble to avoid using parsed_flag_op,
6600       // which makes generated code much nicer
6601       if (delayed_flag_op != NULL)
6602       {
6603         out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6604           po->pfo, po->pfo_inv);
6605         is_delayed = 1;
6606       }
6607       else if (last_arith_dst != NULL
6608         && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6609            || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6610            ))
6611       {
6612         out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6613         out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6614           last_arith_dst->lmod, buf3);
6615         is_delayed = 1;
6616       }
6617       else if (tmp_op != NULL) {
6618         // use preprocessed flag calc results
6619         if (!(tmp_op->pfomask & (1 << po->pfo)))
6620           ferr(po, "not prepared for pfo %d\n", po->pfo);
6621
6622         // note: pfo_inv was not yet applied
6623         snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6624           po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6625       }
6626       else {
6627         ferr(po, "all methods of finding comparison failed\n");
6628       }
6629  
6630       if (po->flags & OPF_JMP) {
6631         fprintf(fout, "  if %s", buf1);
6632       }
6633       else if (po->op == OP_RCL || po->op == OP_RCR
6634                || po->op == OP_ADC || po->op == OP_SBB)
6635       {
6636         if (is_delayed)
6637           fprintf(fout, "  cond_%s = %s;\n",
6638             parsed_flag_op_names[po->pfo], buf1);
6639       }
6640       else if (po->flags & OPF_DATA) { // SETcc
6641         out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6642         fprintf(fout, "  %s = %s;", buf2, buf1);
6643       }
6644       else {
6645         ferr(po, "unhandled conditional op\n");
6646       }
6647     }
6648
6649     pfomask = po->pfomask;
6650
6651     switch (po->op)
6652     {
6653       case OP_MOV:
6654         assert_operand_cnt(2);
6655         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6656         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6657         default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6658         fprintf(fout, "  %s = %s;", buf1,
6659             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6660               buf3, 0));
6661         break;
6662
6663       case OP_LEA:
6664         assert_operand_cnt(2);
6665         po->operand[1].lmod = OPLM_DWORD; // always
6666         fprintf(fout, "  %s = %s;",
6667             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6668             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6669               NULL, 1));
6670         break;
6671
6672       case OP_MOVZX:
6673         assert_operand_cnt(2);
6674         fprintf(fout, "  %s = %s;",
6675             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6676             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6677         break;
6678
6679       case OP_MOVSX:
6680         assert_operand_cnt(2);
6681         switch (po->operand[1].lmod) {
6682         case OPLM_BYTE:
6683           strcpy(buf3, "(s8)");
6684           break;
6685         case OPLM_WORD:
6686           strcpy(buf3, "(s16)");
6687           break;
6688         default:
6689           ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6690         }
6691         fprintf(fout, "  %s = %s;",
6692             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6693             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6694               buf3, 0));
6695         break;
6696
6697       case OP_XCHG:
6698         assert_operand_cnt(2);
6699         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6700         fprintf(fout, "  tmp = %s;",
6701           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6702         fprintf(fout, " %s = %s;",
6703           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6704           out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6705             default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6706         fprintf(fout, " %s = %stmp;",
6707           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6708           default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6709         snprintf(g_comment, sizeof(g_comment), "xchg");
6710         break;
6711
6712       case OP_NOT:
6713         assert_operand_cnt(1);
6714         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6715         fprintf(fout, "  %s = ~%s;", buf1, buf1);
6716         break;
6717
6718       case OP_XLAT:
6719         assert_operand_cnt(2);
6720         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6721         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6722         fprintf(fout, "  %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6723         strcpy(g_comment, "xlat");
6724         break;
6725
6726       case OP_CDQ:
6727         assert_operand_cnt(2);
6728         fprintf(fout, "  %s = (s32)%s >> 31;",
6729             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6730             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6731         strcpy(g_comment, "cdq");
6732         break;
6733
6734       case OP_BSWAP:
6735         assert_operand_cnt(1);
6736         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6737         fprintf(fout, "  %s = __builtin_bswap32(%s);", buf1, buf1);
6738         break;
6739
6740       case OP_LODS:
6741         if (po->flags & OPF_REP) {
6742           assert_operand_cnt(3);
6743           // hmh..
6744           ferr(po, "TODO\n");
6745         }
6746         else {
6747           assert_operand_cnt(2);
6748           fprintf(fout, "  %s = %sesi; esi %c= %d;",
6749             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6750             lmod_cast_u_ptr(po, po->operand[1].lmod),
6751             (po->flags & OPF_DF) ? '-' : '+',
6752             lmod_bytes(po, po->operand[1].lmod));
6753           strcpy(g_comment, "lods");
6754         }
6755         break;
6756
6757       case OP_STOS:
6758         if (po->flags & OPF_REP) {
6759           assert_operand_cnt(3);
6760           fprintf(fout, "  for (; ecx != 0; ecx--, edi %c= %d)\n",
6761             (po->flags & OPF_DF) ? '-' : '+',
6762             lmod_bytes(po, po->operand[1].lmod));
6763           fprintf(fout, "    %sedi = eax;",
6764             lmod_cast_u_ptr(po, po->operand[1].lmod));
6765           strcpy(g_comment, "rep stos");
6766         }
6767         else {
6768           assert_operand_cnt(2);
6769           fprintf(fout, "  %sedi = eax; edi %c= %d;",
6770             lmod_cast_u_ptr(po, po->operand[1].lmod),
6771             (po->flags & OPF_DF) ? '-' : '+',
6772             lmod_bytes(po, po->operand[1].lmod));
6773           strcpy(g_comment, "stos");
6774         }
6775         break;
6776
6777       case OP_MOVS:
6778         j = lmod_bytes(po, po->operand[0].lmod);
6779         strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6780         l = (po->flags & OPF_DF) ? '-' : '+';
6781         if (po->flags & OPF_REP) {
6782           assert_operand_cnt(3);
6783           fprintf(fout,
6784             "  for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6785             l, j, l, j);
6786           fprintf(fout,
6787             "    %sedi = %sesi;", buf1, buf1);
6788           strcpy(g_comment, "rep movs");
6789         }
6790         else {
6791           assert_operand_cnt(2);
6792           fprintf(fout, "  %sedi = %sesi; edi %c= %d; esi %c= %d;",
6793             buf1, buf1, l, j, l, j);
6794           strcpy(g_comment, "movs");
6795         }
6796         break;
6797
6798       case OP_CMPS:
6799         // repe ~ repeat while ZF=1
6800         j = lmod_bytes(po, po->operand[0].lmod);
6801         strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6802         l = (po->flags & OPF_DF) ? '-' : '+';
6803         if (po->flags & OPF_REP) {
6804           assert_operand_cnt(3);
6805           fprintf(fout,
6806             "  while (ecx != 0) {\n");
6807           if (pfomask & (1 << PFO_C)) {
6808             // ugh..
6809             fprintf(fout,
6810             "    cond_c = %sesi < %sedi;\n", buf1, buf1);
6811             pfomask &= ~(1 << PFO_C);
6812           }
6813           fprintf(fout,
6814             "    cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6815               buf1, buf1, l, j, l, j);
6816           fprintf(fout,
6817             "    ecx--;\n"
6818             "    if (cond_z %s 0) break;\n",
6819               (po->flags & OPF_REPZ) ? "==" : "!=");
6820           fprintf(fout,
6821             "  }");
6822           snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6823             (po->flags & OPF_REPZ) ? "e" : "ne");
6824         }
6825         else {
6826           assert_operand_cnt(2);
6827           fprintf(fout,
6828             "  cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6829             buf1, buf1, l, j, l, j);
6830           strcpy(g_comment, "cmps");
6831         }
6832         pfomask &= ~(1 << PFO_Z);
6833         last_arith_dst = NULL;
6834         delayed_flag_op = NULL;
6835         break;
6836
6837       case OP_SCAS:
6838         // only does ZF (for now)
6839         // repe ~ repeat while ZF=1
6840         j = lmod_bytes(po, po->operand[1].lmod);
6841         l = (po->flags & OPF_DF) ? '-' : '+';
6842         if (po->flags & OPF_REP) {
6843           assert_operand_cnt(3);
6844           fprintf(fout,
6845             "  while (ecx != 0) {\n");
6846           fprintf(fout,
6847             "    cond_z = (%seax == %sedi); edi %c= %d;\n",
6848               lmod_cast_u(po, po->operand[1].lmod),
6849               lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6850           fprintf(fout,
6851             "    ecx--;\n"
6852             "    if (cond_z %s 0) break;\n",
6853               (po->flags & OPF_REPZ) ? "==" : "!=");
6854           fprintf(fout,
6855             "  }");
6856           snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6857             (po->flags & OPF_REPZ) ? "e" : "ne");
6858         }
6859         else {
6860           assert_operand_cnt(2);
6861           fprintf(fout, "  cond_z = (%seax == %sedi); edi %c= %d;",
6862               lmod_cast_u(po, po->operand[1].lmod),
6863               lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6864           strcpy(g_comment, "scas");
6865         }
6866         pfomask &= ~(1 << PFO_Z);
6867         last_arith_dst = NULL;
6868         delayed_flag_op = NULL;
6869         break;
6870
6871       // arithmetic w/flags
6872       case OP_AND:
6873         if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6874           goto dualop_arith_const;
6875         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6876         goto dualop_arith;
6877
6878       case OP_OR:
6879         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6880         if (po->operand[1].type == OPT_CONST) {
6881           j = lmod_bytes(po, po->operand[0].lmod);
6882           if (((1ull << j * 8) - 1) == po->operand[1].val)
6883             goto dualop_arith_const;
6884         }
6885         goto dualop_arith;
6886
6887       dualop_arith:
6888         assert_operand_cnt(2);
6889         fprintf(fout, "  %s %s= %s;",
6890             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6891             op_to_c(po),
6892             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6893         output_std_flags(fout, po, &pfomask, buf1);
6894         last_arith_dst = &po->operand[0];
6895         delayed_flag_op = NULL;
6896         break;
6897
6898       dualop_arith_const:
6899         // and 0, or ~0 used instead mov
6900         assert_operand_cnt(2);
6901         fprintf(fout, "  %s = %s;",
6902           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6903           out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6904            default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6905         output_std_flags(fout, po, &pfomask, buf1);
6906         last_arith_dst = &po->operand[0];
6907         delayed_flag_op = NULL;
6908         break;
6909
6910       case OP_SHL:
6911       case OP_SHR:
6912         assert_operand_cnt(2);
6913         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6914         if (pfomask & (1 << PFO_C)) {
6915           if (po->operand[1].type == OPT_CONST) {
6916             l = lmod_bytes(po, po->operand[0].lmod) * 8;
6917             j = po->operand[1].val;
6918             j %= l;
6919             if (j != 0) {
6920               if (po->op == OP_SHL)
6921                 j = l - j;
6922               else
6923                 j -= 1;
6924               fprintf(fout, "  cond_c = (%s >> %d) & 1;\n",
6925                 buf1, j);
6926             }
6927             else
6928               ferr(po, "zero shift?\n");
6929           }
6930           else
6931             ferr(po, "TODO\n");
6932           pfomask &= ~(1 << PFO_C);
6933         }
6934         fprintf(fout, "  %s %s= %s", buf1, op_to_c(po),
6935             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6936         if (po->operand[1].type != OPT_CONST)
6937           fprintf(fout, " & 0x1f");
6938         fprintf(fout, ";");
6939         output_std_flags(fout, po, &pfomask, buf1);
6940         last_arith_dst = &po->operand[0];
6941         delayed_flag_op = NULL;
6942         break;
6943
6944       case OP_SAR:
6945         assert_operand_cnt(2);
6946         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6947         fprintf(fout, "  %s = %s%s >> %s;", buf1,
6948           lmod_cast_s(po, po->operand[0].lmod), buf1,
6949           out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6950         output_std_flags(fout, po, &pfomask, buf1);
6951         last_arith_dst = &po->operand[0];
6952         delayed_flag_op = NULL;
6953         break;
6954
6955       case OP_SHLD:
6956       case OP_SHRD:
6957         assert_operand_cnt(3);
6958         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6959         l = lmod_bytes(po, po->operand[0].lmod) * 8;
6960         out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6961         if (po->operand[2].type != OPT_CONST) {
6962           // no handling for "undefined" case, hopefully not needed
6963           snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6964           strcpy(buf3, buf2);
6965         }
6966         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6967         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6968         if (po->op == OP_SHLD) {
6969           fprintf(fout, "  %s <<= %s; %s |= %s >> (%d - %s);",
6970             buf1, buf3, buf1, buf2, l, buf3);
6971           strcpy(g_comment, "shld");
6972         }
6973         else {
6974           fprintf(fout, "  %s >>= %s; %s |= %s << (%d - %s);",
6975             buf1, buf3, buf1, buf2, l, buf3);
6976           strcpy(g_comment, "shrd");
6977         }
6978         output_std_flags(fout, po, &pfomask, buf1);
6979         last_arith_dst = &po->operand[0];
6980         delayed_flag_op = NULL;
6981         break;
6982
6983       case OP_ROL:
6984       case OP_ROR:
6985         assert_operand_cnt(2);
6986         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6987         if (po->operand[1].type == OPT_CONST) {
6988           j = po->operand[1].val;
6989           j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6990           fprintf(fout, po->op == OP_ROL ?
6991             "  %s = (%s << %d) | (%s >> %d);" :
6992             "  %s = (%s >> %d) | (%s << %d);",
6993             buf1, buf1, j, buf1,
6994             lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6995         }
6996         else
6997           ferr(po, "TODO\n");
6998         output_std_flags(fout, po, &pfomask, buf1);
6999         last_arith_dst = &po->operand[0];
7000         delayed_flag_op = NULL;
7001         break;
7002
7003       case OP_RCL:
7004       case OP_RCR:
7005         assert_operand_cnt(2);
7006         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7007         l = lmod_bytes(po, po->operand[0].lmod) * 8;
7008         if (po->operand[1].type == OPT_CONST) {
7009           j = po->operand[1].val % l;
7010           if (j == 0)
7011             ferr(po, "zero rotate\n");
7012           fprintf(fout, "  tmp = (%s >> %d) & 1;\n",
7013             buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
7014           if (po->op == OP_RCL) {
7015             fprintf(fout,
7016               "  %s = (%s << %d) | (cond_c << %d)",
7017               buf1, buf1, j, j - 1);
7018             if (j != 1)
7019               fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
7020           }
7021           else {
7022             fprintf(fout,
7023               "  %s = (%s >> %d) | (cond_c << %d)",
7024               buf1, buf1, j, l - j);
7025             if (j != 1)
7026               fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
7027           }
7028           fprintf(fout, ";\n");
7029           fprintf(fout, "  cond_c = tmp;");
7030         }
7031         else
7032           ferr(po, "TODO\n");
7033         strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
7034         output_std_flags(fout, po, &pfomask, buf1);
7035         last_arith_dst = &po->operand[0];
7036         delayed_flag_op = NULL;
7037         break;
7038
7039       case OP_XOR:
7040         assert_operand_cnt(2);
7041         propagate_lmod(po, &po->operand[0], &po->operand[1]);
7042         if (IS(opr_name(po, 0), opr_name(po, 1))) {
7043           // special case for XOR
7044           int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
7045           for (j = 0; j <= PFO_LE; j++) {
7046             if (pfomask & (1 << j)) {
7047               fprintf(fout, "  cond_%s = %d;\n",
7048                 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
7049               pfomask &= ~(1 << j);
7050             }
7051           }
7052           fprintf(fout, "  %s = 0;",
7053             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7054           last_arith_dst = &po->operand[0];
7055           delayed_flag_op = NULL;
7056           break;
7057         }
7058         goto dualop_arith;
7059
7060       case OP_ADD:
7061         assert_operand_cnt(2);
7062         propagate_lmod(po, &po->operand[0], &po->operand[1]);
7063         if (pfomask & (1 << PFO_C)) {
7064           out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7065           out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7066           if (po->operand[0].lmod == OPLM_DWORD) {
7067             fprintf(fout, "  tmp64 = (u64)%s + %s;\n", buf1, buf2);
7068             fprintf(fout, "  cond_c = tmp64 >> 32;\n");
7069             fprintf(fout, "  %s = (u32)tmp64;",
7070               out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7071             strcat(g_comment, " add64");
7072           }
7073           else {
7074             fprintf(fout, "  cond_c = ((u32)%s + %s) >> %d;\n",
7075               buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
7076             fprintf(fout, "  %s += %s;",
7077               out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7078               buf2);
7079           }
7080           pfomask &= ~(1 << PFO_C);
7081           output_std_flags(fout, po, &pfomask, buf1);
7082           last_arith_dst = &po->operand[0];
7083           delayed_flag_op = NULL;
7084           break;
7085         }
7086         if (pfomask & (1 << PFO_LE)) {
7087           out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
7088           fprintf(fout, "  cond_%s = %s;\n",
7089             parsed_flag_op_names[PFO_LE], buf1);
7090           pfomask &= ~(1 << PFO_LE);
7091         }
7092         goto dualop_arith;
7093
7094       case OP_SUB:
7095         assert_operand_cnt(2);
7096         propagate_lmod(po, &po->operand[0], &po->operand[1]);
7097         if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
7098           for (j = 0; j <= PFO_LE; j++) {
7099             if (!(pfomask & (1 << j)))
7100               continue;
7101             if (j == PFO_Z || j == PFO_S)
7102               continue;
7103
7104             out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7105             fprintf(fout, "  cond_%s = %s;\n",
7106               parsed_flag_op_names[j], buf1);
7107             pfomask &= ~(1 << j);
7108           }
7109         }
7110         goto dualop_arith;
7111
7112       case OP_ADC:
7113       case OP_SBB:
7114         assert_operand_cnt(2);
7115         propagate_lmod(po, &po->operand[0], &po->operand[1]);
7116         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7117         if (po->op == OP_SBB
7118           && IS(po->operand[0].name, po->operand[1].name))
7119         {
7120           // avoid use of unitialized var
7121           fprintf(fout, "  %s = -cond_c;", buf1);
7122           // carry remains what it was
7123           pfomask &= ~(1 << PFO_C);
7124         }
7125         else {
7126           fprintf(fout, "  %s %s= %s + cond_c;", buf1, op_to_c(po),
7127             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7128         }
7129         output_std_flags(fout, po, &pfomask, buf1);
7130         last_arith_dst = &po->operand[0];
7131         delayed_flag_op = NULL;
7132         break;
7133
7134       case OP_BSF:
7135       case OP_BSR:
7136         // on SKL, if src is 0, dst is left unchanged
7137         assert_operand_cnt(2);
7138         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7139         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7140         output_std_flag_z(fout, po, &pfomask, buf2);
7141         if (po->op == OP_BSF)
7142           snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
7143         else
7144           snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
7145         fprintf(fout, "  if (%s) %s = %s;", buf2, buf1, buf3);
7146         last_arith_dst = &po->operand[0];
7147         delayed_flag_op = NULL;
7148         strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
7149         break;
7150
7151       case OP_DEC:
7152         if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
7153           for (j = 0; j <= PFO_LE; j++) {
7154             if (!(pfomask & (1 << j)))
7155               continue;
7156             if (j == PFO_Z || j == PFO_S || j == PFO_C)
7157               continue;
7158
7159             out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7160             fprintf(fout, "  cond_%s = %s;\n",
7161               parsed_flag_op_names[j], buf1);
7162             pfomask &= ~(1 << j);
7163           }
7164         }
7165         // fallthrough
7166
7167       case OP_INC:
7168         if (pfomask & (1 << PFO_C))
7169           // carry is unaffected by inc/dec.. wtf?
7170           ferr(po, "carry propagation needed\n");
7171
7172         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7173         if (po->operand[0].type == OPT_REG) {
7174           strcpy(buf2, po->op == OP_INC ? "++" : "--");
7175           fprintf(fout, "  %s%s;", buf1, buf2);
7176         }
7177         else {
7178           strcpy(buf2, po->op == OP_INC ? "+" : "-");
7179           fprintf(fout, "  %s %s= 1;", buf1, buf2);
7180         }
7181         output_std_flags(fout, po, &pfomask, buf1);
7182         last_arith_dst = &po->operand[0];
7183         delayed_flag_op = NULL;
7184         break;
7185
7186       case OP_NEG:
7187         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7188         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
7189         fprintf(fout, "  %s = -%s%s;", buf1,
7190           lmod_cast_s(po, po->operand[0].lmod), buf2);
7191         last_arith_dst = &po->operand[0];
7192         delayed_flag_op = NULL;
7193         if (pfomask & PFOB_C) {
7194           fprintf(fout, "\n  cond_c = (%s != 0);", buf1);
7195           pfomask &= ~PFOB_C;
7196         }
7197         output_std_flags(fout, po, &pfomask, buf1);
7198         break;
7199
7200       case OP_IMUL:
7201         if (po->operand_cnt == 2) {
7202           propagate_lmod(po, &po->operand[0], &po->operand[1]);
7203           goto dualop_arith;
7204         }
7205         if (po->operand_cnt == 3)
7206           ferr(po, "TODO imul3\n");
7207         // fallthrough
7208       case OP_MUL:
7209         assert_operand_cnt(1);
7210         switch (po->operand[0].lmod) {
7211         case OPLM_DWORD:
7212           strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7213           fprintf(fout, "  tmp64 = %seax * %s%s;\n", buf1, buf1,
7214             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7215           fprintf(fout, "  edx = tmp64 >> 32;\n");
7216           fprintf(fout, "  eax = tmp64;");
7217           break;
7218         case OPLM_BYTE:
7219           strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7220           fprintf(fout, "  LOWORD(eax) = %seax * %s;", buf1,
7221             out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7222               buf1, 0));
7223           break;
7224         default:
7225           ferr(po, "TODO: unhandled mul type\n");
7226           break;
7227         }
7228         last_arith_dst = NULL;
7229         delayed_flag_op = NULL;
7230         break;
7231
7232       case OP_DIV:
7233       case OP_IDIV:
7234         assert_operand_cnt(1);
7235         out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7236         strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7237           po->op == OP_IDIV));
7238         switch (po->operand[0].lmod) {
7239         case OPLM_DWORD:
7240           if (po->flags & OPF_32BIT)
7241             snprintf(buf2, sizeof(buf2), "%seax", cast);
7242           else {
7243             fprintf(fout, "  tmp64 = ((u64)edx << 32) | eax;\n");
7244             snprintf(buf2, sizeof(buf2), "%stmp64",
7245               (po->op == OP_IDIV) ? "(s64)" : "");
7246           }
7247           if (po->operand[0].type == OPT_REG
7248             && po->operand[0].reg == xDX)
7249           {
7250             fprintf(fout, "  eax = %s / %s%s;\n", buf2, cast, buf1);
7251             fprintf(fout, "  edx = %s %% %s%s;", buf2, cast, buf1);
7252           }
7253           else {
7254             fprintf(fout, "  edx = %s %% %s%s;\n", buf2, cast, buf1);
7255             fprintf(fout, "  eax = %s / %s%s;", buf2, cast, buf1);
7256           }
7257           break;
7258         case OPLM_WORD:
7259           fprintf(fout, "  tmp = (edx << 16) | (eax & 0xffff);\n");
7260           snprintf(buf2, sizeof(buf2), "%stmp",
7261             (po->op == OP_IDIV) ? "(s32)" : "");
7262           if (po->operand[0].type == OPT_REG
7263             && po->operand[0].reg == xDX)
7264           {
7265             fprintf(fout, "  LOWORD(eax) = %s / %s%s;\n",
7266               buf2, cast, buf1);
7267             fprintf(fout, "  LOWORD(edx) = %s %% %s%s;",
7268               buf2, cast, buf1);
7269           }
7270           else {
7271             fprintf(fout, "  LOWORD(edx) = %s %% %s%s;\n",
7272               buf2, cast, buf1);
7273             fprintf(fout, "  LOWORD(eax) = %s / %s%s;",
7274               buf2, cast, buf1);
7275           }
7276           strcat(g_comment, " div16");
7277           break;
7278         default:
7279           ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7280         }
7281         last_arith_dst = NULL;
7282         delayed_flag_op = NULL;
7283         break;
7284
7285       case OP_TEST:
7286       case OP_CMP:
7287         propagate_lmod(po, &po->operand[0], &po->operand[1]);
7288         if (pfomask != 0) {
7289           for (j = 0; j < 8; j++) {
7290             if (pfomask & (1 << j)) {
7291               out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7292               fprintf(fout, "  cond_%s = %s;",
7293                 parsed_flag_op_names[j], buf1);
7294             }
7295           }
7296           pfomask = 0;
7297         }
7298         else
7299           no_output = 1;
7300         last_arith_dst = NULL;
7301         delayed_flag_op = po;
7302         break;
7303
7304       case OP_SCC:
7305         // SETcc - should already be handled
7306         break;
7307
7308       // note: we reuse OP_Jcc for SETcc, only flags differ
7309       case OP_JCC:
7310         fprintf(fout, "\n    goto %s;", po->operand[0].name);
7311         break;
7312
7313       case OP_JECXZ:
7314         fprintf(fout, "  if (ecx == 0)\n");
7315         fprintf(fout, "    goto %s;", po->operand[0].name);
7316         strcat(g_comment, " jecxz");
7317         break;
7318
7319       case OP_LOOP:
7320         fprintf(fout, "  if (--ecx != 0)\n");
7321         fprintf(fout, "    goto %s;", po->operand[0].name);
7322         strcat(g_comment, " loop");
7323         break;
7324
7325       case OP_JMP:
7326         assert_operand_cnt(1);
7327         last_arith_dst = NULL;
7328         delayed_flag_op = NULL;
7329
7330         if (po->operand[0].type == OPT_REGMEM) {
7331           ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7332                   buf1, buf2);
7333           if (ret != 2)
7334             ferr(po, "parse failure for jmp '%s'\n",
7335               po->operand[0].name);
7336           fprintf(fout, "  goto *jt_%s[%s];", buf1, buf2);
7337           break;
7338         }
7339         else if (po->operand[0].type != OPT_LABEL)
7340           ferr(po, "unhandled jmp type\n");
7341
7342         fprintf(fout, "  goto %s;", po->operand[0].name);
7343         break;
7344
7345       case OP_CALL:
7346         assert_operand_cnt(1);
7347         pp = po->pp;
7348         my_assert_not(pp, NULL);
7349
7350         strcpy(buf3, "  ");
7351         if (po->flags & OPF_CC) {
7352           // we treat conditional branch to another func
7353           // (yes such code exists..) as conditional tailcall
7354           strcat(buf3, "  ");
7355           fprintf(fout, " {\n");
7356         }
7357
7358         if (pp->is_fptr && !pp->is_arg) {
7359           fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7360             out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7361               "(void *)", 0));
7362         }
7363         if (pp->is_fptr && (pp->is_unresolved || pp->is_guessed)) {
7364           fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7365             buf3, asmfn, po->asmln, pp->name);
7366         }
7367
7368         fprintf(fout, "%s", buf3);
7369         if (strstr(pp->ret_type.name, "int64")) {
7370           if (po->flags & OPF_TAIL)
7371             ferr(po, "int64 and tail?\n");
7372           fprintf(fout, "tmp64 = ");
7373         }
7374         else if (!IS(pp->ret_type.name, "void")) {
7375           if (po->flags & OPF_TAIL) {
7376             if (regmask_ret & mxAX) {
7377               fprintf(fout, "return ");
7378               if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7379                 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7380             }
7381             else if (regmask_ret & mxST0)
7382               ferr(po, "float tailcall\n");
7383           }
7384           else if (po->regmask_dst & mxAX) {
7385             fprintf(fout, "eax = ");
7386             if (pp->ret_type.is_ptr)
7387               fprintf(fout, "(u32)");
7388           }
7389           else if (po->regmask_dst & mxST0) {
7390             ferr_assert(po, po->flags & OPF_FPUSH);
7391             if (need_float_stack)
7392               fprintf(fout, "f_st[--f_stp & 7] = ");
7393             else
7394               fprintf(fout, "f_st0 = ");
7395           }
7396         }
7397
7398         if (pp->name[0] == 0)
7399           ferr(po, "missing pp->name\n");
7400         fprintf(fout, "%s%s(", pp->name,
7401           pp->has_structarg ? "_sa" : "");
7402
7403         if (po->flags & OPF_ATAIL) {
7404           int check_compat =
7405             g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7406           check_compat |= pp->argc_stack > 0;
7407           if (check_compat
7408            && (pp->argc_stack != g_func_pp->argc_stack
7409                || pp->is_stdcall != g_func_pp->is_stdcall))
7410             ferr(po, "incompatible arg-reuse tailcall\n");
7411           if (g_func_pp->has_retreg)
7412             ferr(po, "TODO: retreg+tailcall\n");
7413
7414           for (arg = j = 0; arg < pp->argc; arg++) {
7415             if (arg > 0)
7416               fprintf(fout, ", ");
7417
7418             cast[0] = 0;
7419             if (pp->arg[arg].type.is_ptr)
7420               snprintf(cast, sizeof(cast), "(%s)",
7421                 pp->arg[arg].type.name);
7422
7423             if (pp->arg[arg].reg != NULL) {
7424               fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7425               continue;
7426             }
7427             // stack arg
7428             for (; j < g_func_pp->argc; j++)
7429               if (g_func_pp->arg[j].reg == NULL)
7430                 break;
7431             fprintf(fout, "%sa%d", cast, j + 1);
7432             j++;
7433           }
7434         }
7435         else {
7436           for (arg = 0; arg < pp->argc; arg++) {
7437             if (arg > 0)
7438               fprintf(fout, ", ");
7439
7440             cast[0] = 0;
7441             if (pp->arg[arg].type.is_ptr)
7442               snprintf(cast, sizeof(cast), "(%s)",
7443                 pp->arg[arg].type.name);
7444
7445             if (pp->arg[arg].reg != NULL) {
7446               if (pp->arg[arg].type.is_retreg)
7447                 fprintf(fout, "&%s", pp->arg[arg].reg);
7448               else if (IS(pp->arg[arg].reg, "ebp")
7449                     && g_bp_frame && !(po->flags & OPF_EBP_S))
7450               {
7451                 // rare special case
7452                 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7453                 strcat(g_comment, " bp_ref");
7454               }
7455               else
7456                 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7457               continue;
7458             }
7459
7460             // stack arg
7461             tmp_op = pp->arg[arg].datap;
7462             if (tmp_op == NULL)
7463               ferr(po, "parsed_op missing for arg%d\n", arg);
7464
7465             if (tmp_op->flags & OPF_VAPUSH) {
7466               fprintf(fout, "ap");
7467             }
7468             else if (tmp_op->op == OP_FST) {
7469               fprintf(fout, "fs_%d", tmp_op->p_argnum);
7470               if (tmp_op->operand[0].lmod == OPLM_QWORD)
7471                 arg++;
7472             }
7473             else if (pp->arg[arg].type.is_64bit) {
7474               ferr_assert(po, tmp_op->p_argpass == 0);
7475               ferr_assert(po, !pp->arg[arg].is_saved);
7476               ferr_assert(po, !pp->arg[arg].type.is_float);
7477               ferr_assert(po, cast[0] == 0);
7478               out_src_opr(buf1, sizeof(buf1),
7479                 tmp_op, &tmp_op->operand[0], cast, 0);
7480               tmp_op = pp->arg[++arg].datap;
7481               ferr_assert(po, tmp_op != NULL);
7482               out_src_opr(buf2, sizeof(buf2),
7483                 tmp_op, &tmp_op->operand[0], cast, 0);
7484               fprintf(fout, "((u64)(%s) << 32) | (%s)",
7485                 buf2, buf1);
7486             }
7487             else if (tmp_op->p_argpass != 0) {
7488               ferr_assert(po, !pp->arg[arg].type.is_float);
7489               fprintf(fout, "a%d", tmp_op->p_argpass);
7490             }
7491             else if (pp->arg[arg].is_saved) {
7492               ferr_assert(po, tmp_op->p_argnum > 0);
7493               ferr_assert(po, !pp->arg[arg].type.is_float);
7494               fprintf(fout, "%s%s", cast,
7495                 saved_arg_name(buf1, sizeof(buf1),
7496                   tmp_op->p_arggrp, tmp_op->p_argnum));
7497             }
7498             else if (pp->arg[arg].type.is_float) {
7499               ferr_assert(po, !pp->arg[arg].type.is_64bit);
7500               fprintf(fout, "%s",
7501                 out_src_opr_float(buf1, sizeof(buf1),
7502                   tmp_op, &tmp_op->operand[0], need_float_stack));
7503             }
7504             else {
7505               fprintf(fout, "%s",
7506                 out_src_opr(buf1, sizeof(buf1),
7507                   tmp_op, &tmp_op->operand[0], cast, 0));
7508             }
7509           }
7510         }
7511         fprintf(fout, ");");
7512
7513         if (strstr(pp->ret_type.name, "int64")) {
7514           fprintf(fout, "\n");
7515           fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7516           fprintf(fout, "%seax = tmp64;", buf3);
7517         }
7518
7519         if (pp->is_unresolved) {
7520           snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7521             pp->argc_reg);
7522           strcat(g_comment, buf2);
7523         }
7524
7525         if (po->flags & OPF_TAIL) {
7526           ret = 0;
7527           if (i == opcnt - 1 || pp->is_noreturn)
7528             ret = 0;
7529           else if (IS(pp->ret_type.name, "void"))
7530             ret = 1;
7531           else if (!(regmask_ret & (1 << xAX)))
7532             ret = 1;
7533           // else already handled as 'return f()'
7534
7535           if (ret) {
7536             fprintf(fout, "\n%sreturn;", buf3);
7537             strcat(g_comment, " ^ tailcall");
7538           }
7539           else
7540             strcat(g_comment, " tailcall");
7541
7542           if ((regmask_ret & (1 << xAX))
7543             && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7544           {
7545             ferr(po, "int func -> void func tailcall?\n");
7546           }
7547         }
7548         if (pp->is_noreturn)
7549           strcat(g_comment, " noreturn");
7550         if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7551           strcat(g_comment, " argframe");
7552         if (po->flags & OPF_CC)
7553           strcat(g_comment, " cond");
7554
7555         if (po->flags & OPF_CC)
7556           fprintf(fout, "\n  }");
7557
7558         delayed_flag_op = NULL;
7559         last_arith_dst = NULL;
7560         break;
7561
7562       case OP_RET:
7563         if (g_func_pp->is_vararg)
7564           fprintf(fout, "  va_end(ap);\n");
7565         if (g_func_pp->has_retreg) {
7566           for (arg = 0; arg < g_func_pp->argc; arg++)
7567             if (g_func_pp->arg[arg].type.is_retreg)
7568               fprintf(fout, "  *r_%s = %s;\n",
7569                 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7570         }
7571  
7572         if (regmask_ret & mxST0) {
7573           fprintf(fout, "  return %s;", float_st0);
7574         }
7575         else if (!(regmask_ret & mxAX)) {
7576           if (i != opcnt - 1 || label_pending)
7577             fprintf(fout, "  return;");
7578         }
7579         else if (g_func_pp->ret_type.is_ptr) {
7580           fprintf(fout, "  return (%s)eax;",
7581             g_func_pp->ret_type.name);
7582         }
7583         else if (IS(g_func_pp->ret_type.name, "__int64"))
7584           fprintf(fout, "  return ((u64)edx << 32) | eax;");
7585         else
7586           fprintf(fout, "  return eax;");
7587
7588         last_arith_dst = NULL;
7589         delayed_flag_op = NULL;
7590         break;
7591
7592       case OP_PUSH:
7593         out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7594         if (po->p_argnum != 0) {
7595           // special case - saved func arg
7596           fprintf(fout, "  %s = %s;",
7597             saved_arg_name(buf2, sizeof(buf2),
7598               po->p_arggrp, po->p_argnum), buf1);
7599           break;
7600         }
7601         else if (po->flags & OPF_RSAVE) {
7602           fprintf(fout, "  s_%s = %s;", buf1, buf1);
7603           break;
7604         }
7605         else if (po->flags & OPF_PPUSH) {
7606           tmp_op = po->datap;
7607           ferr_assert(po, tmp_op != NULL);
7608           out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7609           fprintf(fout, "  pp_%s = %s;", buf2, buf1);
7610           break;
7611         }
7612         else if (g_func_pp->is_userstack) {
7613           fprintf(fout, "  *(--esp) = %s;", buf1);
7614           break;
7615         }
7616         if (!(g_ida_func_attr & IDAFA_NORETURN))
7617           ferr(po, "stray push encountered\n");
7618         no_output = 1;
7619         break;
7620
7621       case OP_POP:
7622         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7623         if (po->flags & OPF_RSAVE) {
7624           fprintf(fout, "  %s = s_%s;", buf1, buf1);
7625           break;
7626         }
7627         else if (po->flags & OPF_PPUSH) {
7628           // push/pop graph / non-const
7629           ferr_assert(po, po->datap == NULL);
7630           fprintf(fout, "  %s = pp_%s;", buf1, buf1);
7631           break;
7632         }
7633         else if (po->datap != NULL) {
7634           // push/pop pair
7635           tmp_op = po->datap;
7636           fprintf(fout, "  %s = %s;", buf1,
7637             out_src_opr(buf2, sizeof(buf2),
7638               tmp_op, &tmp_op->operand[0],
7639               default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7640           break;
7641         }
7642         else if (g_func_pp->is_userstack) {
7643           fprintf(fout, "  %s = *esp++;", buf1);
7644           break;
7645         }
7646         else
7647           ferr(po, "stray pop encountered\n");
7648         break;
7649
7650       case OP_NOP:
7651         no_output = 1;
7652         break;
7653
7654       // pseudo ops
7655       case OPP_ALLSHL:
7656       case OPP_ALLSHR:
7657         fprintf(fout, "  tmp64 = ((u64)edx << 32) | eax;\n");
7658         fprintf(fout, "  tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7659           po->op == OPP_ALLSHL ? "<<" : ">>");
7660         fprintf(fout, "  edx = tmp64 >> 32; eax = tmp64;");
7661         strcat(g_comment, po->op == OPP_ALLSHL
7662           ? " allshl" : " allshr");
7663         break;
7664
7665       // x87
7666       case OP_FLD:
7667         if (need_float_stack) {
7668           out_src_opr_float(buf1, sizeof(buf1),
7669             po, &po->operand[0], 1);
7670           if (po->regmask_src & mxSTa) {
7671             fprintf(fout, "  f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7672               buf1);
7673           }
7674           else
7675             fprintf(fout, "  f_st[--f_stp & 7] = %s;", buf1);
7676         }
7677         else {
7678           if (po->flags & OPF_FSHIFT)
7679             fprintf(fout, "  f_st1 = f_st0;");
7680           if (po->operand[0].type == OPT_REG
7681             && po->operand[0].reg == xST0)
7682           {
7683             strcat(g_comment, " fld st");
7684             break;
7685           }
7686           fprintf(fout, "  f_st0 = %s;",
7687             out_src_opr_float(buf1, sizeof(buf1),
7688               po, &po->operand[0], 0));
7689         }
7690         strcat(g_comment, " fld");
7691         break;
7692
7693       case OP_FILD:
7694         out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7695           lmod_cast(po, po->operand[0].lmod, 1), 0);
7696         snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7697         if (need_float_stack) {
7698           fprintf(fout, "  f_st[--f_stp & 7] = %s;", buf2);
7699         }
7700         else {
7701           if (po->flags & OPF_FSHIFT)
7702             fprintf(fout, "  f_st1 = f_st0;");
7703           fprintf(fout, "  f_st0 = %s;", buf2);
7704         }
7705         strcat(g_comment, " fild");
7706         break;
7707
7708       case OP_FLDc:
7709         if (need_float_stack)
7710           fprintf(fout, "  f_st[--f_stp & 7] = ");
7711         else {
7712           if (po->flags & OPF_FSHIFT)
7713             fprintf(fout, "  f_st1 = f_st0;");
7714           fprintf(fout, "  f_st0 = ");
7715         }
7716         switch (po->operand[0].val) {
7717         case X87_CONST_1:   fprintf(fout, "1.0;"); break;
7718         case X87_CONST_L2T: fprintf(fout, "3.321928094887362;"); break;
7719         case X87_CONST_L2E: fprintf(fout, "M_LOG2E;"); break;
7720         case X87_CONST_PI:  fprintf(fout, "M_PI;"); break;
7721         case X87_CONST_LG2: fprintf(fout, "0.301029995663981;"); break;
7722         case X87_CONST_LN2: fprintf(fout, "M_LN2;"); break;
7723         case X87_CONST_Z:   fprintf(fout, "0.0;"); break;
7724         default: ferr_assert(po, 0); break;
7725         }
7726         break;
7727
7728       case OP_FST:
7729         if (po->flags & OPF_FARG) {
7730           // store to stack as func arg
7731           snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7732           dead_dst = 0;
7733         }
7734         else {
7735           out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7736             need_float_stack);
7737           dead_dst = po->operand[0].type == OPT_REG
7738             && po->operand[0].reg == xST0;
7739         }
7740         if (!dead_dst)
7741           fprintf(fout, "  %s = %s;", buf1, float_st0);
7742         if (po->flags & OPF_FSHIFT) {
7743           if (need_float_stack)
7744             fprintf(fout, "  f_stp++;");
7745           else
7746             fprintf(fout, "  f_st0 = f_st1;");
7747         }
7748         if (dead_dst && !(po->flags & OPF_FSHIFT))
7749           no_output = 1;
7750         else
7751           strcat(g_comment, " fst");
7752         break;
7753
7754       case OP_FIST:
7755         fprintf(fout, "  %s = %s%s;",
7756           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7757             lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7758         if (po->flags & OPF_FSHIFT) {
7759           if (need_float_stack)
7760             fprintf(fout, "  f_stp++;");
7761           else
7762             fprintf(fout, "  f_st0 = f_st1;");
7763         }
7764         strcat(g_comment, " fist");
7765         break;
7766
7767       case OP_FADD:
7768       case OP_FDIV:
7769       case OP_FMUL:
7770       case OP_FSUB:
7771         out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7772           need_float_stack);
7773         out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7774           need_float_stack);
7775         dead_dst = (po->flags & OPF_FPOP)
7776           && po->operand[0].type == OPT_REG
7777           && po->operand[0].reg == xST0;
7778         switch (po->op) {
7779         case OP_FADD: j = '+'; break;
7780         case OP_FDIV: j = '/'; break;
7781         case OP_FMUL: j = '*'; break;
7782         case OP_FSUB: j = '-'; break;
7783         default: j = 'x'; break;
7784         }
7785         if (need_float_stack) {
7786           if (!dead_dst)
7787             fprintf(fout, "  %s %c= %s;", buf1, j, buf2);
7788           if (po->flags & OPF_FSHIFT)
7789             fprintf(fout, "  f_stp++;");
7790         }
7791         else {
7792           if (po->flags & OPF_FSHIFT) {
7793             // note: assumes only 2 regs handled
7794             if (!dead_dst)
7795               fprintf(fout, "  f_st0 = f_st1 %c f_st0;", j);
7796             else
7797               fprintf(fout, "  f_st0 = f_st1;");
7798           }
7799           else if (!dead_dst)
7800             fprintf(fout, "  %s %c= %s;", buf1, j, buf2);
7801         }
7802         no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7803         break;
7804
7805       case OP_FDIVR:
7806       case OP_FSUBR:
7807         out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7808           need_float_stack);
7809         out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7810           need_float_stack);
7811         out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7812           need_float_stack);
7813         dead_dst = (po->flags & OPF_FPOP)
7814           && po->operand[0].type == OPT_REG
7815           && po->operand[0].reg == xST0;
7816         j = po->op == OP_FDIVR ? '/' : '-';
7817         if (need_float_stack) {
7818           if (!dead_dst)
7819             fprintf(fout, "  %s = %s %c %s;", buf1, buf2, j, buf3);
7820           if (po->flags & OPF_FSHIFT)
7821             fprintf(fout, "  f_stp++;");
7822         }
7823         else {
7824           if (po->flags & OPF_FSHIFT) {
7825             if (!dead_dst)
7826               fprintf(fout, "  f_st0 = f_st0 %c f_st1;", j);
7827             else
7828               fprintf(fout, "  f_st0 = f_st1;");
7829           }
7830           else if (!dead_dst)
7831             fprintf(fout, "  %s = %s %c %s;", buf1, buf2, j, buf3);
7832         }
7833         no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7834         break;
7835
7836       case OP_FIADD:
7837       case OP_FIDIV:
7838       case OP_FIMUL:
7839       case OP_FISUB:
7840         switch (po->op) {
7841         case OP_FIADD: j = '+'; break;
7842         case OP_FIDIV: j = '/'; break;
7843         case OP_FIMUL: j = '*'; break;
7844         case OP_FISUB: j = '-'; break;
7845         default: j = 'x'; break;
7846         }
7847         fprintf(fout, "  %s %c= (%s)%s;", float_st0,
7848           j, float_type,
7849           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7850             lmod_cast(po, po->operand[0].lmod, 1), 0));
7851         break;
7852
7853       case OP_FIDIVR:
7854       case OP_FISUBR:
7855         fprintf(fout, "  %s = %s %c %s;", float_st0,
7856           out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7857             need_float_stack),
7858           po->op == OP_FIDIVR ? '/' : '-', float_st0);
7859         break;
7860
7861       case OP_FCOM: {
7862         int mask, z_check;
7863         ferr_assert(po, po->datap != NULL);
7864         mask = (long)po->datap & 0xffff;
7865         z_check = ((long)po->datap >> 16) & 1;
7866         out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7867           need_float_stack);
7868         if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
7869           fprintf(fout, "  f_sw = %s < %s ? 0x0100 : 0;",
7870             float_st0, buf1);
7871         }
7872         else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
7873           fprintf(fout, "  f_sw = %s == %s ? 0x4000 : 0;",
7874             float_st0, buf1);
7875         }
7876         else if (mask == 0x4100) { // C3, C0
7877           if (z_check) {
7878             fprintf(fout, "  f_sw = %s <= %s ? 0x4100 : 0;",
7879               float_st0, buf1);
7880             strcat(g_comment, " z_chk_det");
7881           }
7882           else {
7883             fprintf(fout, "  f_sw = %s == %s ? 0x4000 : "
7884                           "(%s < %s ? 0x0100 : 0);",
7885               float_st0, buf1, float_st0, buf1);
7886           }
7887         }
7888         else
7889           ferr(po, "unhandled sw mask: %x\n", mask);
7890         if (po->flags & OPF_FSHIFT) {
7891           if (need_float_stack) {
7892             if (po->flags & OPF_FPOPP)
7893               fprintf(fout, " f_stp += 2;");
7894             else
7895               fprintf(fout, " f_stp++;");
7896           }
7897           else {
7898             ferr_assert(po, !(po->flags & OPF_FPOPP));
7899             fprintf(fout, " f_st0 = f_st1;");
7900           }
7901         }
7902         break;
7903       }
7904
7905       case OP_FNSTSW:
7906         fprintf(fout, "  %s = f_sw;",
7907           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7908         break;
7909
7910       case OP_FCHS:
7911         fprintf(fout, "  %s = -%s;", float_st0, float_st0);
7912         break;
7913
7914       case OP_FCOS:
7915         fprintf(fout, "  %s = cos%s(%s);", float_st0,
7916           need_double ? "" : "f", float_st0);
7917         break;
7918
7919       case OP_FPATAN:
7920         if (need_float_stack) {
7921           fprintf(fout, "  %s = atan%s(%s / %s);", float_st1,
7922             need_double ? "" : "f", float_st1, float_st0);
7923           fprintf(fout, " f_stp++;");
7924         }
7925         else {
7926           fprintf(fout, "  f_st0 = atan%s(f_st1 / f_st0);",
7927             need_double ? "" : "f");
7928         }
7929         break;
7930
7931       case OP_FYL2X:
7932         if (need_float_stack) {
7933           fprintf(fout, "  %s = %s * log2%s(%s);", float_st1,
7934             float_st1, need_double ? "" : "f", float_st0);
7935           fprintf(fout, " f_stp++;");
7936         }
7937         else {
7938           fprintf(fout, "  f_st0 = f_st1 * log2%s(f_st0);",
7939             need_double ? "" : "f");
7940         }
7941         strcat(g_comment, " fyl2x");
7942         break;
7943
7944       case OP_FSIN:
7945         fprintf(fout, "  %s = sin%s(%s);", float_st0,
7946           need_double ? "" : "f", float_st0);
7947         break;
7948
7949       case OP_FSQRT:
7950         fprintf(fout, "  %s = sqrt%s(%s);", float_st0,
7951           need_double ? "" : "f", float_st0);
7952         break;
7953
7954       case OP_FXCH:
7955         dead_dst = po->operand[0].type == OPT_REG
7956           && po->operand[0].reg == xST0;
7957         if (!dead_dst) {
7958           out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7959             need_float_stack);
7960           fprintf(fout, "  { %s t = %s; %s = %s; %s = t; }", float_type,
7961             float_st0, float_st0, buf1, buf1);
7962           strcat(g_comment, " fxch");
7963         }
7964         else
7965           no_output = 1;
7966         break;
7967
7968       case OPP_FTOL:
7969         ferr_assert(po, po->flags & OPF_32BIT);
7970         fprintf(fout, "  eax = (s32)%s;", float_st0);
7971         if (po->flags & OPF_FSHIFT) {
7972           if (need_float_stack)
7973             fprintf(fout, " f_stp++;");
7974           else
7975             fprintf(fout, " f_st0 = f_st1;");
7976         }
7977         strcat(g_comment, " ftol");
7978         break;
7979
7980       case OPP_CIPOW:
7981         if (need_float_stack) {
7982           fprintf(fout, "  %s = pow%s(%s, %s);", float_st1,
7983             need_double ? "" : "f", float_st1, float_st0);
7984           fprintf(fout, " f_stp++;");
7985         }
7986         else {
7987           fprintf(fout, "  f_st0 = pow%s(f_st1, f_st0);",
7988             need_double ? "" : "f");
7989         }
7990         strcat(g_comment, " CIpow");
7991         break;
7992
7993       case OPP_ABORT:
7994         fprintf(fout, "  do_skip_code_abort();");
7995         break;
7996
7997       // mmx
7998       case OP_EMMS:
7999         fprintf(fout, "  do_emms();");
8000         break;
8001
8002       default:
8003         no_output = 1;
8004         ferr(po, "unhandled op type %d, flags %x\n",
8005           po->op, po->flags);
8006         break;
8007     }
8008
8009     if (g_comment[0] != 0) {
8010       char *p = g_comment;
8011       while (my_isblank(*p))
8012         p++;
8013       fprintf(fout, "  // %s", p);
8014       g_comment[0] = 0;
8015       no_output = 0;
8016     }
8017     if (!no_output)
8018       fprintf(fout, "\n");
8019
8020     // some sanity checking
8021     if (po->flags & OPF_REP) {
8022       if (po->op != OP_STOS && po->op != OP_MOVS
8023           && po->op != OP_CMPS && po->op != OP_SCAS)
8024         ferr(po, "unexpected rep\n");
8025       if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
8026           && (po->op == OP_CMPS || po->op == OP_SCAS))
8027         ferr(po, "cmps/scas with plain rep\n");
8028     }
8029     if ((po->flags & (OPF_REPZ|OPF_REPNZ))
8030         && po->op != OP_CMPS && po->op != OP_SCAS)
8031       ferr(po, "unexpected repz/repnz\n");
8032
8033     if (pfomask != 0)
8034       ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
8035
8036     // see is delayed flag stuff is still valid
8037     if (delayed_flag_op != NULL && delayed_flag_op != po) {
8038       if (is_any_opr_modified(delayed_flag_op, po, 0))
8039         delayed_flag_op = NULL;
8040     }
8041
8042     if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
8043       if (is_opr_modified(last_arith_dst, po))
8044         last_arith_dst = NULL;
8045     }
8046
8047     if (!no_output)
8048       label_pending = 0;
8049   }
8050
8051   if (g_stack_fsz && !g_stack_frame_used)
8052     fprintf(fout, "  (void)sf;\n");
8053
8054   fprintf(fout, "}\n\n");
8055
8056   gen_x_cleanup(opcnt);
8057 }
8058
8059 static void gen_x_cleanup(int opcnt)
8060 {
8061   int i;
8062
8063   for (i = 0; i < opcnt; i++) {
8064     struct label_ref *lr, *lr_del;
8065
8066     lr = g_label_refs[i].next;
8067     while (lr != NULL) {
8068       lr_del = lr;
8069       lr = lr->next;
8070       free(lr_del);
8071     }
8072     g_label_refs[i].i = -1;
8073     g_label_refs[i].next = NULL;
8074
8075     if (ops[i].op == OP_CALL) {
8076       if (ops[i].pp)
8077         proto_release(ops[i].pp);
8078     }
8079   }
8080   g_func_pp = NULL;
8081 }
8082
8083 struct func_proto_dep;
8084
8085 struct func_prototype {
8086   char name[NAMELEN];
8087   int id;
8088   int argc_stack;
8089   int regmask_dep;
8090   int has_ret:3;                 // -1, 0, 1: unresolved, no, yes
8091   unsigned int dep_resolved:1;
8092   unsigned int is_stdcall:1;
8093   struct func_proto_dep *dep_func;
8094   int dep_func_cnt;
8095   const struct parsed_proto *pp; // seed pp, if any
8096 };
8097
8098 struct func_proto_dep {
8099   char *name;
8100   struct func_prototype *proto;
8101   int regmask_live;             // .. at the time of call
8102   unsigned int ret_dep:1;       // return from this is caller's return
8103 };
8104
8105 static struct func_prototype *hg_fp;
8106 static int hg_fp_cnt;
8107
8108 static struct scanned_var {
8109   char name[NAMELEN];
8110   enum opr_lenmod lmod;
8111   unsigned int is_seeded:1;
8112   unsigned int is_c_str:1;
8113   const struct parsed_proto *pp; // seed pp, if any
8114 } *hg_vars;
8115 static int hg_var_cnt;
8116
8117 static char **hg_refs;
8118 static int hg_ref_cnt;
8119
8120 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8121   int count);
8122
8123 static struct func_prototype *hg_fp_add(const char *funcn)
8124 {
8125   struct func_prototype *fp;
8126
8127   if ((hg_fp_cnt & 0xff) == 0) {
8128     hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
8129     my_assert_not(hg_fp, NULL);
8130     memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
8131   }
8132
8133   fp = &hg_fp[hg_fp_cnt];
8134   snprintf(fp->name, sizeof(fp->name), "%s", funcn);
8135   fp->id = hg_fp_cnt;
8136   fp->argc_stack = -1;
8137   hg_fp_cnt++;
8138
8139   return fp;
8140 }
8141
8142 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
8143   const char *name)
8144 {
8145   int i;
8146
8147   for (i = 0; i < fp->dep_func_cnt; i++)
8148     if (IS(fp->dep_func[i].name, name))
8149       return &fp->dep_func[i];
8150
8151   return NULL;
8152 }
8153
8154 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
8155 {
8156   // is it a dupe?
8157   if (hg_fp_find_dep(fp, name))
8158     return;
8159
8160   if ((fp->dep_func_cnt & 0xff) == 0) {
8161     fp->dep_func = realloc(fp->dep_func,
8162       sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
8163     my_assert_not(fp->dep_func, NULL);
8164     memset(&fp->dep_func[fp->dep_func_cnt], 0,
8165       sizeof(fp->dep_func[0]) * 0x100);
8166   }
8167   fp->dep_func[fp->dep_func_cnt].name = strdup(name);
8168   fp->dep_func_cnt++;
8169 }
8170
8171 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
8172 {
8173   const struct func_prototype *p1 = p1_, *p2 = p2_;
8174   return strcmp(p1->name, p2->name);
8175 }
8176
8177 #if 0
8178 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
8179 {
8180   const struct func_prototype *p1 = p1_, *p2 = p2_;
8181   return p1->id - p2->id;
8182 }
8183 #endif
8184
8185 static void hg_ref_add(const char *name)
8186 {
8187   if ((hg_ref_cnt & 0xff) == 0) {
8188     hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8189     my_assert_not(hg_refs, NULL);
8190     memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8191   }
8192
8193   hg_refs[hg_ref_cnt] = strdup(name);
8194   my_assert_not(hg_refs[hg_ref_cnt], NULL);
8195   hg_ref_cnt++;
8196 }
8197
8198 // recursive register dep pass
8199 // - track saved regs (part 2)
8200 // - try to figure out arg-regs
8201 // - calculate reg deps
8202 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8203   struct func_prototype *fp, int regmask_save, int regmask_dst,
8204   int *regmask_dep, int *has_ret)
8205 {
8206   struct func_proto_dep *dep;
8207   struct parsed_op *po;
8208   int from_caller = 0;
8209   int j, l;
8210   int reg;
8211   int ret;
8212
8213   for (; i < opcnt; i++)
8214   {
8215     if (cbits[i >> 3] & (1 << (i & 7)))
8216       return;
8217     cbits[i >> 3] |= (1 << (i & 7));
8218
8219     po = &ops[i];
8220
8221     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8222       if (po->flags & OPF_RMD)
8223         continue;
8224
8225       if (po->btj != NULL) {
8226         // jumptable
8227         for (j = 0; j < po->btj->count; j++) {
8228           check_i(po, po->btj->d[j].bt_i);
8229           gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8230             regmask_save, regmask_dst, regmask_dep, has_ret);
8231         }
8232         return;
8233       }
8234
8235       check_i(po, po->bt_i);
8236       if (po->flags & OPF_CJMP) {
8237         gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8238           regmask_save, regmask_dst, regmask_dep, has_ret);
8239       }
8240       else {
8241         i = po->bt_i - 1;
8242       }
8243       continue;
8244     }
8245
8246     if (po->flags & OPF_FARG)
8247       /* (just calculate register deps) */;
8248     else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8249     {
8250       reg = po->operand[0].reg;
8251       ferr_assert(po, reg >= 0);
8252
8253       if (po->flags & OPF_RSAVE) {
8254         regmask_save |= 1 << reg;
8255         continue;
8256       }
8257       if (po->flags & OPF_DONE)
8258         continue;
8259
8260       ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
8261       if (ret == 1) {
8262         regmask_save |= 1 << reg;
8263         po->flags |= OPF_RMD;
8264         scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
8265         continue;
8266       }
8267     }
8268     else if (po->flags & OPF_RMD)
8269       continue;
8270     else if (po->op == OP_CALL) {
8271       po->regmask_dst |= 1 << xAX;
8272
8273       dep = hg_fp_find_dep(fp, po->operand[0].name);
8274       if (dep != NULL) {
8275         dep->regmask_live = regmask_save | regmask_dst;
8276         if (g_bp_frame && !(po->flags & OPF_EBP_S))
8277           dep->regmask_live |= 1 << xBP;
8278       }
8279     }
8280     else if (po->op == OP_RET) {
8281       if (po->operand_cnt > 0) {
8282         fp->is_stdcall = 1;
8283         if (fp->argc_stack >= 0
8284             && fp->argc_stack != po->operand[0].val / 4)
8285           ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8286         fp->argc_stack = po->operand[0].val / 4;
8287       }
8288     }
8289
8290     // if has_ret is 0, there is uninitialized eax path,
8291     // which means it's most likely void func
8292     if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
8293       if (po->op == OP_CALL) {
8294         j = i;
8295         ret = 1;
8296       }
8297       else {
8298         struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
8299         j = -1;
8300         from_caller = 0;
8301         ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
8302       }
8303
8304       if (ret != 1 && from_caller) {
8305         // unresolved eax - probably void func
8306         *has_ret = 0;
8307       }
8308       else {
8309         if (j >= 0 && ops[j].op == OP_CALL) {
8310           dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8311           if (dep != NULL)
8312             dep->ret_dep = 1;
8313           else
8314             *has_ret = 1;
8315         }
8316         else
8317           *has_ret = 1;
8318       }
8319     }
8320
8321     l = regmask_save | regmask_dst;
8322     if (g_bp_frame && !(po->flags & OPF_EBP_S))
8323       l |= 1 << xBP;
8324
8325     l = po->regmask_src & ~l;
8326 #if 0
8327     if (l)
8328       fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8329         l, regmask_dst, regmask_save, po->flags);
8330 #endif
8331     *regmask_dep |= l;
8332     regmask_dst |= po->regmask_dst;
8333
8334     if (po->flags & OPF_TAIL)
8335       return;
8336   }
8337 }
8338
8339 static void gen_hdr(const char *funcn, int opcnt)
8340 {
8341   unsigned char cbits[MAX_OPS / 8];
8342   const struct parsed_proto *pp_c;
8343   struct parsed_proto *pp;
8344   struct func_prototype *fp;
8345   struct parsed_op *po;
8346   int regmask_dummy = 0;
8347   int regmask_dep;
8348   int max_bp_offset = 0;
8349   int has_ret;
8350   int i, j, l;
8351   int ret;
8352
8353   pp_c = proto_parse(g_fhdr, funcn, 1);
8354   if (pp_c != NULL)
8355     // already in seed, will add to hg_fp later
8356     return;
8357
8358   fp = hg_fp_add(funcn);
8359
8360   g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8361   g_stack_frame_used = 0;
8362   g_seh_size = 0;
8363
8364   // pass1:
8365   // - resolve all branches
8366   // - parse calls with labels
8367   resolve_branches_parse_calls(opcnt);
8368
8369   // pass2:
8370   // - handle ebp/esp frame, remove ops related to it
8371   scan_prologue_epilogue(opcnt, NULL);
8372
8373   // pass3:
8374   // - remove dead labels
8375   // - collect calls
8376   for (i = 0; i < opcnt; i++)
8377   {
8378     if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8379       free(g_labels[i]);
8380       g_labels[i] = NULL;
8381     }
8382
8383     po = &ops[i];
8384     if (po->flags & (OPF_RMD|OPF_DONE))
8385       continue;
8386
8387     if (po->op == OP_CALL) {
8388       if (po->operand[0].type == OPT_LABEL)
8389         hg_fp_add_dep(fp, opr_name(po, 0));
8390       else if (po->pp != NULL)
8391         hg_fp_add_dep(fp, po->pp->name);
8392     }
8393   }
8394
8395   // pass4:
8396   // - remove dead labels
8397   // - handle push <const>/pop pairs
8398   for (i = 0; i < opcnt; i++)
8399   {
8400     if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8401       free(g_labels[i]);
8402       g_labels[i] = NULL;
8403     }
8404
8405     po = &ops[i];
8406     if (po->flags & (OPF_RMD|OPF_DONE))
8407       continue;
8408
8409     if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8410       scan_for_pop_const(i, opcnt, i + opcnt * 13);
8411   }
8412
8413   // pass5:
8414   // - process trivial calls
8415   for (i = 0; i < opcnt; i++)
8416   {
8417     po = &ops[i];
8418     if (po->flags & (OPF_RMD|OPF_DONE))
8419       continue;
8420
8421     if (po->op == OP_CALL)
8422     {
8423       pp = process_call_early(i, opcnt, &j);
8424       if (pp != NULL) {
8425         if (!(po->flags & OPF_ATAIL))
8426           // since we know the args, try to collect them
8427           if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8428             pp = NULL;
8429       }
8430
8431       if (pp != NULL) {
8432         if (j >= 0) {
8433           // commit esp adjust
8434           if (ops[j].op != OP_POP)
8435             patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8436           else {
8437             for (l = 0; l < pp->argc_stack; l++)
8438               ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8439           }
8440         }
8441
8442         po->flags |= OPF_DONE;
8443       }
8444     }
8445   }
8446
8447   // pass6:
8448   // - track saved regs (simple)
8449   // - process calls
8450   for (i = 0; i < opcnt; i++)
8451   {
8452     po = &ops[i];
8453     if (po->flags & (OPF_RMD|OPF_DONE))
8454       continue;
8455
8456     if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8457       && po->operand[0].reg != xCX)
8458     {
8459       ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8460       if (ret == 1) {
8461         // regmask_save |= 1 << po->operand[0].reg; // do it later
8462         po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8463         scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8464       }
8465     }
8466     else if (po->op == OP_CALL)
8467     {
8468       pp = process_call(i, opcnt);
8469
8470       if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8471         // since we know the args, collect them
8472         ret = collect_call_args(po, i, pp, &regmask_dummy,
8473                 i + opcnt * 1);
8474       }
8475     }
8476   }
8477
8478   // pass7
8479   memset(cbits, 0, sizeof(cbits));
8480   regmask_dep = 0;
8481   has_ret = -1;
8482
8483   gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, &regmask_dep, &has_ret);
8484
8485   // find unreachable code - must be fixed in IDA
8486   for (i = 0; i < opcnt; i++)
8487   {
8488     if (cbits[i >> 3] & (1 << (i & 7)))
8489       continue;
8490
8491     if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8492       && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8493     {
8494       // the compiler sometimes still generates code after
8495       // noreturn OS functions
8496       break;
8497     }
8498     if (!(ops[i].flags & OPF_RMD)
8499         && ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8500     {
8501       ferr(&ops[i], "unreachable code\n");
8502     }
8503   }
8504
8505   for (i = 0; i < g_eqcnt; i++) {
8506     if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8507       max_bp_offset = g_eqs[i].offset;
8508   }
8509
8510   if (fp->argc_stack < 0) {
8511     max_bp_offset = (max_bp_offset + 3) & ~3;
8512     fp->argc_stack = max_bp_offset / 4;
8513     if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8514       fp->argc_stack--;
8515   }
8516
8517   fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8518   fp->has_ret = has_ret;
8519 #if 0
8520   printf("// has_ret %d, regmask_dep %x\n",
8521     fp->has_ret, fp->regmask_dep);
8522   output_hdr_fp(stdout, fp, 1);
8523   if (IS(funcn, "sub_10007F72")) exit(1);
8524 #endif
8525
8526   gen_x_cleanup(opcnt);
8527 }
8528
8529 static void hg_fp_resolve_deps(struct func_prototype *fp)
8530 {
8531   struct func_prototype fp_s;
8532   int dep;
8533   int i;
8534
8535   // this thing is recursive, so mark first..
8536   fp->dep_resolved = 1;
8537
8538   for (i = 0; i < fp->dep_func_cnt; i++) {
8539     strcpy(fp_s.name, fp->dep_func[i].name);
8540     fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8541       sizeof(hg_fp[0]), hg_fp_cmp_name);
8542     if (fp->dep_func[i].proto != NULL) {
8543       if (!fp->dep_func[i].proto->dep_resolved)
8544         hg_fp_resolve_deps(fp->dep_func[i].proto);
8545
8546       dep = ~fp->dep_func[i].regmask_live
8547            & fp->dep_func[i].proto->regmask_dep;
8548       fp->regmask_dep |= dep;
8549       // printf("dep %s %s |= %x\n", fp->name,
8550       //   fp->dep_func[i].name, dep);
8551
8552       if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8553         fp->has_ret = fp->dep_func[i].proto->has_ret;
8554     }
8555   }
8556 }
8557
8558 // make all thiscall/edx arg functions referenced from .data fastcall
8559 static void do_func_refs_from_data(void)
8560 {
8561   struct func_prototype *fp, fp_s;
8562   int i;
8563
8564   for (i = 0; i < hg_ref_cnt; i++) {
8565     strcpy(fp_s.name, hg_refs[i]);
8566     fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8567       sizeof(hg_fp[0]), hg_fp_cmp_name);
8568     if (fp == NULL)
8569       continue;
8570
8571     if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8572       fp->regmask_dep |= mxCX | mxDX;
8573   }
8574 }
8575
8576 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8577   int count)
8578 {
8579   const struct parsed_proto *pp;
8580   char *p, namebuf[NAMELEN];
8581   const char *name;
8582   int regmask_dep;
8583   int argc_normal;
8584   int j, arg;
8585
8586   for (; count > 0; count--, fp++) {
8587     if (fp->has_ret == -1)
8588       fprintf(fout, "// ret unresolved\n");
8589 #if 0
8590     fprintf(fout, "// dep:");
8591     for (j = 0; j < fp->dep_func_cnt; j++) {
8592       fprintf(fout, " %s/", fp->dep_func[j].name);
8593       if (fp->dep_func[j].proto != NULL)
8594         fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8595           fp->dep_func[j].proto->has_ret);
8596     }
8597     fprintf(fout, "\n");
8598 #endif
8599
8600     p = strchr(fp->name, '@');
8601     if (p != NULL) {
8602       memcpy(namebuf, fp->name, p - fp->name);
8603       namebuf[p - fp->name] = 0;
8604       name = namebuf;
8605     }
8606     else
8607       name = fp->name;
8608     if (name[0] == '_')
8609       name++;
8610
8611     pp = proto_parse(g_fhdr, name, 1);
8612     if (pp != NULL && pp->is_include)
8613       continue;
8614
8615     if (fp->pp != NULL) {
8616       // part of seed, output later
8617       continue;
8618     }
8619
8620     regmask_dep = fp->regmask_dep;
8621     argc_normal = fp->argc_stack;
8622
8623     fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8624       (fp->has_ret ? "int" : "void"));
8625     if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8626       && (regmask_dep & ~mxCX) == 0)
8627     {
8628       fprintf(fout, "/*__thiscall*/  ");
8629       argc_normal++;
8630       regmask_dep = 0;
8631     }
8632     else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8633       && (regmask_dep & ~(mxCX | mxDX)) == 0)
8634     {
8635       fprintf(fout, "  __fastcall    ");
8636       if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8637         argc_normal = 1;
8638       else
8639         argc_normal += 2;
8640       regmask_dep = 0;
8641     }
8642     else if (regmask_dep && !fp->is_stdcall) {
8643       fprintf(fout, "/*__usercall*/  ");
8644     }
8645     else if (regmask_dep) {
8646       fprintf(fout, "/*__userpurge*/ ");
8647     }
8648     else if (fp->is_stdcall)
8649       fprintf(fout, "  __stdcall     ");
8650     else
8651       fprintf(fout, "  __cdecl       ");
8652
8653     fprintf(fout, "%s(", name);
8654
8655     arg = 0;
8656     for (j = 0; j < xSP; j++) {
8657       if (regmask_dep & (1 << j)) {
8658         arg++;
8659         if (arg != 1)
8660           fprintf(fout, ", ");
8661         if (fp->pp != NULL)
8662           fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8663         else
8664           fprintf(fout, "int");
8665         fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8666       }
8667     }
8668
8669     for (j = 0; j < argc_normal; j++) {
8670       arg++;
8671       if (arg != 1)
8672         fprintf(fout, ", ");
8673       if (fp->pp != NULL) {
8674         fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8675         if (!fp->pp->arg[arg - 1].type.is_ptr)
8676           fprintf(fout, " ");
8677       }
8678       else
8679         fprintf(fout, "int ");
8680       fprintf(fout, "a%d", arg);
8681     }
8682
8683     fprintf(fout, ");\n");
8684   }
8685 }
8686
8687 static void output_hdr(FILE *fout)
8688 {
8689   static const char *lmod_c_names[] = {
8690     [OPLM_UNSPEC] = "???",
8691     [OPLM_BYTE]  = "uint8_t",
8692     [OPLM_WORD]  = "uint16_t",
8693     [OPLM_DWORD] = "uint32_t",
8694     [OPLM_QWORD] = "uint64_t",
8695   };
8696   const struct scanned_var *var;
8697   struct func_prototype *fp;
8698   char line[256] = { 0, };
8699   char name[256];
8700   int i;
8701
8702   // add stuff from headers
8703   for (i = 0; i < pp_cache_size; i++) {
8704     if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8705       snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8706     else
8707       snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8708     fp = hg_fp_add(name);
8709     fp->pp = &pp_cache[i];
8710     fp->argc_stack = fp->pp->argc_stack;
8711     fp->is_stdcall = fp->pp->is_stdcall;
8712     fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8713     fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8714   }
8715
8716   // resolve deps
8717   qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8718   for (i = 0; i < hg_fp_cnt; i++)
8719     hg_fp_resolve_deps(&hg_fp[i]);
8720
8721   // adjust functions referenced from data segment
8722   do_func_refs_from_data();
8723
8724   // note: messes up .proto ptr, don't use
8725   //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8726
8727   // output variables
8728   for (i = 0; i < hg_var_cnt; i++) {
8729     var = &hg_vars[i];
8730
8731     if (var->pp != NULL)
8732       // part of seed
8733       continue;
8734     else if (var->is_c_str)
8735       fprintf(fout, "extern %-8s %s[];", "char", var->name);
8736     else
8737       fprintf(fout, "extern %-8s %s;",
8738         lmod_c_names[var->lmod], var->name);
8739
8740     if (var->is_seeded)
8741       fprintf(fout, " // seeded");
8742     fprintf(fout, "\n");
8743   }
8744
8745   fprintf(fout, "\n");
8746
8747   // output function prototypes
8748   output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8749
8750   // seed passthrough
8751   fprintf(fout, "\n// - seed -\n");
8752
8753   rewind(g_fhdr);
8754   while (fgets(line, sizeof(line), g_fhdr))
8755     fwrite(line, 1, strlen(line), fout);
8756 }
8757
8758 // '=' needs special treatment
8759 // also ' quote
8760 static char *next_word_s(char *w, size_t wsize, char *s)
8761 {
8762   size_t i;
8763
8764   s = sskip(s);
8765
8766   i = 0;
8767   if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8768     w[0] = s[0];
8769     for (i = 1; i < wsize - 1; i++) {
8770       if (s[i] == 0) {
8771         printf("warning: missing closing quote: \"%s\"\n", s);
8772         break;
8773       }
8774       if (s[i] == '\'')
8775         break;
8776       w[i] = s[i];
8777     }
8778   }
8779
8780   for (; i < wsize - 1; i++) {
8781     if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8782       break;
8783     w[i] = s[i];
8784   }
8785   w[i] = 0;
8786
8787   if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8788     printf("warning: '%s' truncated\n", w);
8789
8790   return s + i;
8791 }
8792
8793 static int cmpstringp(const void *p1, const void *p2)
8794 {
8795   return strcmp(*(char * const *)p1, *(char * const *)p2);
8796 }
8797
8798 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8799 {
8800   char *p2;
8801
8802   p = sskip(p);
8803   if (strstr(p, "..."))
8804     // unable to determine, assume needed
8805     return 1;
8806
8807   if (*p == '.') // .text, .data, ...
8808     // ref from other data or non-function -> no
8809     return 0;
8810
8811   p2 = strpbrk(p, "+:\r\n\x18");
8812   if (p2 != NULL)
8813     *p2 = 0;
8814   if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8815     // referenced from removed code
8816     return 0;
8817
8818   return 1;
8819 }
8820
8821 static int ida_xrefs_show_need(FILE *fasm, char *p,
8822   char **rlist, int rlist_len)
8823 {
8824   int found_need = 0;
8825   char line[256];
8826   long pos;
8827
8828   p = strrchr(p, ';');
8829   if (p != NULL && *p == ';') {
8830     if (IS_START(p + 2, "sctref"))
8831       return 1;
8832     if (IS_START(p + 2, "DATA XREF: ")) {
8833       p += 13;
8834       if (is_xref_needed(p, rlist, rlist_len))
8835         return 1;
8836     }
8837   }
8838
8839   pos = ftell(fasm);
8840   while (1)
8841   {
8842     if (!my_fgets(line, sizeof(line), fasm))
8843       break;
8844     // non-first line is always indented
8845     if (!my_isblank(line[0]))
8846       break;
8847
8848     // should be no content, just comment
8849     p = sskip(line);
8850     if (*p != ';')
8851       break;
8852
8853     p = strrchr(p, ';');
8854     p += 2;
8855
8856     if (IS_START(p, "sctref")) {
8857       found_need = 1;
8858       break;
8859     }
8860
8861     // it's printed once, but no harm to check again
8862     if (IS_START(p, "DATA XREF: "))
8863       p += 11;
8864
8865     if (is_xref_needed(p, rlist, rlist_len)) {
8866       found_need = 1;
8867       break;
8868     }
8869   }
8870   fseek(fasm, pos, SEEK_SET);
8871   return found_need;
8872 }
8873
8874 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8875 {
8876   struct scanned_var *var;
8877   char line[256] = { 0, };
8878   char words[4][256];
8879   int no_identifier;
8880   char *p = NULL;
8881   int wordc;
8882   int l;
8883
8884   while (!feof(fasm))
8885   {
8886     // skip to next data section
8887     while (my_fgets(line, sizeof(line), fasm))
8888     {
8889       asmln++;
8890
8891       p = sskip(line);
8892       if (*p == 0 || *p == ';')
8893         continue;
8894
8895       p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8896       if (*p == 0 || *p == ';')
8897         continue;
8898
8899       if (*p != 's' || !IS_START(p, "segment para public"))
8900         continue;
8901
8902       break;
8903     }
8904
8905     if (p == NULL || !IS_START(p, "segment para public"))
8906       break;
8907     p = sskip(p + 19);
8908
8909     if (!IS_START(p, "'DATA'"))
8910       continue;
8911
8912     // now process it
8913     while (my_fgets(line, sizeof(line), fasm))
8914     {
8915       asmln++;
8916
8917       p = line;
8918       no_identifier = my_isblank(*p);
8919
8920       p = sskip(p);
8921       if (*p == 0 || *p == ';')
8922         continue;
8923
8924       for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8925         words[wordc][0] = 0;
8926         p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8927         if (*p == 0 || *p == ';') {
8928           wordc++;
8929           break;
8930         }
8931       }
8932
8933       if (wordc == 2 && IS(words[1], "ends"))
8934         break;
8935       if (wordc < 2)
8936         continue;
8937
8938       if (no_identifier) {
8939         if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8940           hg_ref_add(words[2]);
8941         continue;
8942       }
8943
8944       if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8945         // when this starts, we don't need anything from this section
8946         break;
8947       }
8948
8949       // check refs comment(s)
8950       if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8951         continue;
8952
8953       if ((hg_var_cnt & 0xff) == 0) {
8954         hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8955                    * (hg_var_cnt + 0x100));
8956         my_assert_not(hg_vars, NULL);
8957         memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8958       }
8959
8960       var = &hg_vars[hg_var_cnt++];
8961       snprintf(var->name, sizeof(var->name), "%s", words[0]);
8962
8963       // maybe already in seed header?
8964       var->pp = proto_parse(g_fhdr, var->name, 1);
8965       if (var->pp != NULL) {
8966         if (var->pp->is_fptr) {
8967           var->lmod = OPLM_DWORD;
8968           //var->is_ptr = 1;
8969         }
8970         else if (var->pp->is_func)
8971           aerr("func?\n");
8972         else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8973           aerr("unhandled C type '%s' for '%s'\n",
8974             var->pp->type.name, var->name);
8975
8976         var->is_seeded = 1;
8977         continue;
8978       }
8979
8980       if      (IS(words[1], "dd")) {
8981         var->lmod = OPLM_DWORD;
8982         if (wordc >= 4 && IS(words[2], "offset"))
8983           hg_ref_add(words[3]);
8984       }
8985       else if (IS(words[1], "dw"))
8986         var->lmod = OPLM_WORD;
8987       else if (IS(words[1], "db")) {
8988         var->lmod = OPLM_BYTE;
8989         if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8990           if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8991             var->is_c_str = 1;
8992         }
8993       }
8994       else if (IS(words[1], "dq"))
8995         var->lmod = OPLM_QWORD;
8996       //else if (IS(words[1], "dt"))
8997       else
8998         aerr("type '%s' not known\n", words[1]);
8999     }
9000   }
9001
9002   rewind(fasm);
9003   asmln = 0;
9004 }
9005
9006 static void set_label(int i, const char *name)
9007 {
9008   const char *p;
9009   int len;
9010
9011   len = strlen(name);
9012   p = strchr(name, ':');
9013   if (p != NULL)
9014     len = p - name;
9015
9016   if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
9017     aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
9018   g_labels[i] = realloc(g_labels[i], len + 1);
9019   my_assert_not(g_labels[i], NULL);
9020   memcpy(g_labels[i], name, len);
9021   g_labels[i][len] = 0;
9022 }
9023
9024 struct chunk_item {
9025   char *name;
9026   long fptr;
9027   int asmln;
9028 };
9029
9030 static struct chunk_item *func_chunks;
9031 static int func_chunk_cnt;
9032 static int func_chunk_alloc;
9033
9034 static void add_func_chunk(FILE *fasm, const char *name, int line)
9035 {
9036   if (func_chunk_cnt >= func_chunk_alloc) {
9037     func_chunk_alloc *= 2;
9038     func_chunks = realloc(func_chunks,
9039       func_chunk_alloc * sizeof(func_chunks[0]));
9040     my_assert_not(func_chunks, NULL);
9041   }
9042   func_chunks[func_chunk_cnt].fptr = ftell(fasm);
9043   func_chunks[func_chunk_cnt].name = strdup(name);
9044   func_chunks[func_chunk_cnt].asmln = line;
9045   func_chunk_cnt++;
9046 }
9047
9048 static int cmp_chunks(const void *p1, const void *p2)
9049 {
9050   const struct chunk_item *c1 = p1, *c2 = p2;
9051   return strcmp(c1->name, c2->name);
9052 }
9053
9054 static void scan_ahead_for_chunks(FILE *fasm)
9055 {
9056   char words[2][256];
9057   char line[256];
9058   long oldpos;
9059   int oldasmln;
9060   int wordc;
9061   char *p;
9062   int i;
9063
9064   oldpos = ftell(fasm);
9065   oldasmln = asmln;
9066
9067   while (my_fgets(line, sizeof(line), fasm))
9068   {
9069     wordc = 0;
9070     asmln++;
9071
9072     p = sskip(line);
9073     if (*p == 0)
9074       continue;
9075
9076     if (*p == ';')
9077     {
9078       // get rid of random tabs
9079       for (i = 0; line[i] != 0; i++)
9080         if (line[i] == '\t')
9081           line[i] = ' ';
9082
9083       if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9084       {
9085         p += 30;
9086         next_word(words[0], sizeof(words[0]), p);
9087         if (words[0][0] == 0)
9088           aerr("missing name for func chunk?\n");
9089
9090         add_func_chunk(fasm, words[0], asmln);
9091       }
9092       else if (IS_START(p, "; sctend"))
9093         break;
9094
9095       continue;
9096     } // *p == ';'
9097
9098     for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9099       words[wordc][0] = 0;
9100       p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9101       if (*p == 0 || *p == ';') {
9102         wordc++;
9103         break;
9104       }
9105     }
9106
9107     if (wordc == 2 && IS(words[1], "ends"))
9108       break;
9109   }
9110
9111   fseek(fasm, oldpos, SEEK_SET);
9112   asmln = oldasmln;
9113 }
9114
9115 int main(int argc, char *argv[])
9116 {
9117   FILE *fout, *fasm, *frlist;
9118   struct parsed_data *pd = NULL;
9119   int pd_alloc = 0;
9120   char **rlist = NULL;
9121   int rlist_len = 0;
9122   int rlist_alloc = 0;
9123   int func_chunks_used = 0;
9124   int func_chunks_sorted = 0;
9125   int func_chunk_i = -1;
9126   long func_chunk_ret = 0;
9127   int func_chunk_ret_ln = 0;
9128   int scanned_ahead = 0;
9129   char line[256];
9130   char words[20][256];
9131   enum opr_lenmod lmod;
9132   char *sctproto = NULL;
9133   int in_func = 0;
9134   int pending_endp = 0;
9135   int skip_code = 0;
9136   int skip_code_end = 0;
9137   int skip_warned = 0;
9138   int eq_alloc;
9139   int verbose = 0;
9140   int multi_seg = 0;
9141   int end = 0;
9142   int arg_out;
9143   int arg;
9144   int pi = 0;
9145   int i, j;
9146   int ret, len;
9147   char *p;
9148   int wordc;
9149
9150   for (arg = 1; arg < argc; arg++) {
9151     if (IS(argv[arg], "-v"))
9152       verbose = 1;
9153     else if (IS(argv[arg], "-rf"))
9154       g_allow_regfunc = 1;
9155     else if (IS(argv[arg], "-uc"))
9156       g_allow_user_icall = 1;
9157     else if (IS(argv[arg], "-m"))
9158       multi_seg = 1;
9159     else if (IS(argv[arg], "-hdr"))
9160       g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
9161     else
9162       break;
9163   }
9164
9165   if (argc < arg + 3) {
9166     printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
9167            "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
9168            "options:\n"
9169            "  -hdr - header generation mode\n"
9170            "  -rf  - allow unannotated indirect calls\n"
9171            "  -uc  - allow ind. calls/refs to __usercall\n"
9172            "  -m   - allow multiple .text sections\n"
9173            "[rlist] is a file with function names to skip,"
9174            " one per line\n",
9175       argv[0], argv[0]);
9176     return 1;
9177   }
9178
9179   arg_out = arg++;
9180
9181   asmfn = argv[arg++];
9182   fasm = fopen(asmfn, "r");
9183   my_assert_not(fasm, NULL);
9184
9185   hdrfn = argv[arg++];
9186   g_fhdr = fopen(hdrfn, "r");
9187   my_assert_not(g_fhdr, NULL);
9188
9189   rlist_alloc = 64;
9190   rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9191   my_assert_not(rlist, NULL);
9192   // needs special handling..
9193   rlist[rlist_len++] = "__alloca_probe";
9194
9195   func_chunk_alloc = 32;
9196   func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9197   my_assert_not(func_chunks, NULL);
9198
9199   memset(words, 0, sizeof(words));
9200
9201   for (; arg < argc; arg++) {
9202     int skip_func = 0;
9203
9204     frlist = fopen(argv[arg], "r");
9205     my_assert_not(frlist, NULL);
9206
9207     while (my_fgets(line, sizeof(line), frlist)) {
9208       p = sskip(line);
9209       if (*p == 0 || *p == ';')
9210         continue;
9211       if (*p == '#') {
9212         if (IS_START(p, "#if 0")
9213          || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9214         {
9215           skip_func = 1;
9216         }
9217         else if (IS_START(p, "#endif"))
9218           skip_func = 0;
9219         continue;
9220       }
9221       if (skip_func)
9222         continue;
9223
9224       p = next_word(words[0], sizeof(words[0]), p);
9225       if (words[0][0] == 0)
9226         continue;
9227
9228       if (rlist_len >= rlist_alloc) {
9229         rlist_alloc = rlist_alloc * 2 + 64;
9230         rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9231         my_assert_not(rlist, NULL);
9232       }
9233       rlist[rlist_len++] = strdup(words[0]);
9234     }
9235
9236     fclose(frlist);
9237     frlist = NULL;
9238   }
9239
9240   if (rlist_len > 0)
9241     qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9242
9243   fout = fopen(argv[arg_out], "w");
9244   my_assert_not(fout, NULL);
9245
9246   eq_alloc = 128;
9247   g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9248   my_assert_not(g_eqs, NULL);
9249
9250   for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9251     g_label_refs[i].i = -1;
9252     g_label_refs[i].next = NULL;
9253   }
9254
9255   if (g_header_mode)
9256     scan_variables(fasm, rlist, rlist_len);
9257
9258   while (my_fgets(line, sizeof(line), fasm))
9259   {
9260     wordc = 0;
9261     asmln++;
9262
9263     p = sskip(line);
9264     if (*p == 0)
9265       continue;
9266
9267     // get rid of random tabs
9268     for (i = 0; line[i] != 0; i++)
9269       if (line[i] == '\t')
9270         line[i] = ' ';
9271
9272     if (*p == ';')
9273     {
9274       if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9275         goto do_pending_endp; // eww..
9276
9277       if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9278       {
9279         static const char *attrs[] = {
9280           "bp-based frame",
9281           "library function",
9282           "static",
9283           "noreturn",
9284           "thunk",
9285           "fpd=",
9286         };
9287
9288         // parse IDA's attribute-list comment
9289         g_ida_func_attr = 0;
9290         p = sskip(p + 13);
9291
9292         for (; *p != 0; p = sskip(p)) {
9293           for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9294             if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9295               g_ida_func_attr |= 1 << i;
9296               p += strlen(attrs[i]);
9297               break;
9298             }
9299           }
9300           if (i == ARRAY_SIZE(attrs)) {
9301             anote("unparsed IDA attr: %s\n", p);
9302             break;
9303           }
9304           if (IS(attrs[i], "fpd=")) {
9305             p = next_word(words[0], sizeof(words[0]), p);
9306             // ignore for now..
9307           }
9308         }
9309       }
9310       else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9311       {
9312         static const char *attrs[] = {
9313           "clear_sf",
9314           "clear_regmask",
9315         };
9316
9317         // parse manual attribute-list comment
9318         g_sct_func_attr = 0;
9319         p = sskip(p + 10);
9320
9321         for (; *p != 0; p = sskip(p)) {
9322           for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9323             if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9324               g_sct_func_attr |= 1 << i;
9325               p += strlen(attrs[i]);
9326               break;
9327             }
9328           }
9329           if (*p == '=') {
9330             j = ret = 0;
9331             if (i == 0)
9332               // clear_sf=start,len (in dwords)
9333               ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9334                       &g_stack_clear_len, &j);
9335             else if (i == 1)
9336               // clear_regmask=<mask>
9337               ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9338             if (ret < 2) {
9339               anote("unparsed attr value: %s\n", p);
9340               break;
9341             }
9342             p += j;
9343           }
9344           else if (i == ARRAY_SIZE(attrs)) {
9345             anote("unparsed sct attr: %s\n", p);
9346             break;
9347           }
9348         }
9349       }
9350       else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9351       {
9352         p += 30;
9353         next_word(words[0], sizeof(words[0]), p);
9354         if (words[0][0] == 0)
9355           aerr("missing name for func chunk?\n");
9356
9357         if (!scanned_ahead) {
9358           add_func_chunk(fasm, words[0], asmln);
9359           func_chunks_sorted = 0;
9360         }
9361       }
9362       else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9363       {
9364         if (func_chunk_i >= 0) {
9365           if (func_chunk_i < func_chunk_cnt
9366             && IS(func_chunks[func_chunk_i].name, g_func))
9367           {
9368             // move on to next chunk
9369             ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9370             if (ret)
9371               aerr("seek failed for '%s' chunk #%d\n",
9372                 g_func, func_chunk_i);
9373             asmln = func_chunks[func_chunk_i].asmln;
9374             func_chunk_i++;
9375           }
9376           else {
9377             if (func_chunk_ret == 0)
9378               aerr("no return from chunk?\n");
9379             fseek(fasm, func_chunk_ret, SEEK_SET);
9380             asmln = func_chunk_ret_ln;
9381             func_chunk_ret = 0;
9382             pending_endp = 1;
9383           }
9384         }
9385       }
9386       else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9387         func_chunks_used = 1;
9388         p += 20;
9389         if (IS_START(g_func, "sub_")) {
9390           unsigned long addr = strtoul(p, NULL, 16);
9391           unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9392           if (addr > f_addr && !scanned_ahead) {
9393             //anote("scan_ahead caused by '%s', addr %lx\n",
9394             //  g_func, addr);
9395             scan_ahead_for_chunks(fasm);
9396             scanned_ahead = 1;
9397             func_chunks_sorted = 0;
9398           }
9399         }
9400       }
9401       continue;
9402     } // *p == ';'
9403
9404 parse_words:
9405     for (i = wordc; i < ARRAY_SIZE(words); i++)
9406       words[i][0] = 0;
9407     for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9408       p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9409       if (*p == 0 || *p == ';') {
9410         wordc++;
9411         break;
9412       }
9413     }
9414     if (*p != 0 && *p != ';')
9415       aerr("too many words\n");
9416
9417     if (skip_code_end) {
9418       skip_code_end = 0;
9419       skip_code = 0;
9420     }
9421
9422     // allow asm patches in comments
9423     if (*p == ';') {
9424       if (IS_START(p, "; sctpatch:")) {
9425         p = sskip(p + 11);
9426         if (*p == 0 || *p == ';')
9427           continue;
9428         goto parse_words; // lame
9429       }
9430       if (IS_START(p, "; sctproto:")) {
9431         sctproto = strdup(p + 11);
9432       }
9433       else if (IS_START(p, "; sctend")) {
9434         end = 1;
9435         if (!pending_endp)
9436           break;
9437       }
9438       else if (IS_START(p, "; sctskip_start")) {
9439         if (in_func && !g_skip_func) {
9440           if (!skip_code) {
9441             ops[pi].op = OPP_ABORT;
9442             ops[pi].asmln = asmln;
9443             pi++;
9444           }
9445           skip_code = 1;
9446         }
9447       }
9448       else if (IS_START(p, "; sctskip_end")) {
9449         if (skip_code)
9450           skip_code_end = 1;
9451       }
9452     }
9453
9454     if (wordc == 0) {
9455       // shouldn't happen
9456       awarn("wordc == 0?\n");
9457       continue;
9458     }
9459
9460     // don't care about this:
9461     if (words[0][0] == '.'
9462         || IS(words[0], "include")
9463         || IS(words[0], "assume") || IS(words[1], "segment")
9464         || IS(words[0], "align"))
9465     {
9466       continue;
9467     }
9468
9469 do_pending_endp:
9470     // do delayed endp processing to collect switch jumptables
9471     if (pending_endp) {
9472       if (in_func && !g_skip_func && !end && wordc >= 2
9473           && ((words[0][0] == 'd' && words[0][2] == 0)
9474               || (words[1][0] == 'd' && words[1][2] == 0)))
9475       {
9476         i = 1;
9477         if (words[1][0] == 'd' && words[1][2] == 0) {
9478           // label
9479           if (g_func_pd_cnt >= pd_alloc) {
9480             pd_alloc = pd_alloc * 2 + 16;
9481             g_func_pd = realloc(g_func_pd,
9482               sizeof(g_func_pd[0]) * pd_alloc);
9483             my_assert_not(g_func_pd, NULL);
9484           }
9485           pd = &g_func_pd[g_func_pd_cnt];
9486           g_func_pd_cnt++;
9487           memset(pd, 0, sizeof(*pd));
9488           strcpy(pd->label, words[0]);
9489           pd->type = OPT_CONST;
9490           pd->lmod = lmod_from_directive(words[1]);
9491           i = 2;
9492         }
9493         else {
9494           if (pd == NULL) {
9495             if (verbose)
9496               anote("skipping alignment byte?\n");
9497             continue;
9498           }
9499           lmod = lmod_from_directive(words[0]);
9500           if (lmod != pd->lmod)
9501             aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9502         }
9503
9504         if (pd->count_alloc < pd->count + wordc) {
9505           pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9506           pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9507           my_assert_not(pd->d, NULL);
9508         }
9509         for (; i < wordc; i++) {
9510           if (IS(words[i], "offset")) {
9511             pd->type = OPT_OFFSET;
9512             i++;
9513           }
9514           p = strchr(words[i], ',');
9515           if (p != NULL)
9516             *p = 0;
9517           if (pd->type == OPT_OFFSET)
9518             pd->d[pd->count].u.label = strdup(words[i]);
9519           else
9520             pd->d[pd->count].u.val = parse_number(words[i], 0);
9521           pd->d[pd->count].bt_i = -1;
9522           pd->count++;
9523         }
9524         continue;
9525       }
9526
9527       if (in_func && !g_skip_func) {
9528         if (g_header_mode)
9529           gen_hdr(g_func, pi);
9530         else
9531           gen_func(fout, g_fhdr, g_func, pi);
9532       }
9533
9534       pending_endp = 0;
9535       in_func = 0;
9536       g_ida_func_attr = 0;
9537       g_sct_func_attr = 0;
9538       g_stack_clear_start = 0;
9539       g_stack_clear_len = 0;
9540       g_regmask_init = 0;
9541       skip_warned = 0;
9542       g_skip_func = 0;
9543       g_func[0] = 0;
9544       g_seh_found = 0;
9545       func_chunks_used = 0;
9546       func_chunk_i = -1;
9547       if (pi != 0) {
9548         memset(&ops, 0, pi * sizeof(ops[0]));
9549         clear_labels(pi);
9550         pi = 0;
9551       }
9552       g_eqcnt = 0;
9553       for (i = 0; i < g_func_pd_cnt; i++) {
9554         pd = &g_func_pd[i];
9555         if (pd->type == OPT_OFFSET) {
9556           for (j = 0; j < pd->count; j++)
9557             free(pd->d[j].u.label);
9558         }
9559         free(pd->d);
9560         pd->d = NULL;
9561       }
9562       g_func_pd_cnt = 0;
9563       g_func_lmods = 0;
9564       pd = NULL;
9565
9566       if (end)
9567         break;
9568       if (wordc == 0)
9569         continue;
9570     }
9571
9572     if (IS(words[1], "proc")) {
9573       if (in_func)
9574         aerr("proc '%s' while in_func '%s'?\n",
9575           words[0], g_func);
9576       p = words[0];
9577       if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9578         g_skip_func = 1;
9579       strcpy(g_func, words[0]);
9580       set_label(0, words[0]);
9581       in_func = 1;
9582       continue;
9583     }
9584
9585     if (IS(words[1], "endp"))
9586     {
9587       if (!in_func)
9588         aerr("endp '%s' while not in_func?\n", words[0]);
9589       if (!IS(g_func, words[0]))
9590         aerr("endp '%s' while in_func '%s'?\n",
9591           words[0], g_func);
9592       if (skip_code)
9593         aerr("endp '%s' while skipping code\n", words[0]);
9594
9595       if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9596         && ops[0].op == OP_JMP && ops[0].operand[0].segment)
9597       {
9598         // import jump
9599         g_skip_func = 1;
9600       }
9601
9602       if (!g_skip_func && func_chunks_used) {
9603         // start processing chunks
9604         struct chunk_item *ci, key = { g_func, 0 };
9605
9606         func_chunk_ret = ftell(fasm);
9607         func_chunk_ret_ln = asmln;
9608         if (!func_chunks_sorted) {
9609           qsort(func_chunks, func_chunk_cnt,
9610             sizeof(func_chunks[0]), cmp_chunks);
9611           func_chunks_sorted = 1;
9612         }
9613         ci = bsearch(&key, func_chunks, func_chunk_cnt,
9614                sizeof(func_chunks[0]), cmp_chunks);
9615         if (ci == NULL)
9616           aerr("'%s' needs chunks, but none found\n", g_func);
9617         func_chunk_i = ci - func_chunks;
9618         for (; func_chunk_i > 0; func_chunk_i--)
9619           if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9620             break;
9621
9622         ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9623         if (ret)
9624           aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9625         asmln = func_chunks[func_chunk_i].asmln;
9626         func_chunk_i++;
9627         continue;
9628       }
9629       pending_endp = 1;
9630       continue;
9631     }
9632
9633     if (wordc == 2 && IS(words[1], "ends")) {
9634       if (!multi_seg) {
9635         end = 1;
9636         if (pending_endp)
9637           goto do_pending_endp;
9638         break;
9639       }
9640
9641       // scan for next text segment
9642       while (my_fgets(line, sizeof(line), fasm)) {
9643         asmln++;
9644         p = sskip(line);
9645         if (*p == 0 || *p == ';')
9646           continue;
9647
9648         if (strstr(p, "segment para public 'CODE' use32"))
9649           break;
9650       }
9651
9652       continue;
9653     }
9654
9655     p = strchr(words[0], ':');
9656     if (p != NULL) {
9657       set_label(pi, words[0]);
9658       continue;
9659     }
9660
9661     if (!in_func || g_skip_func || skip_code) {
9662       if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9663         if (verbose)
9664           anote("skipping from '%s'\n", g_labels[pi]);
9665         skip_warned = 1;
9666       }
9667       free(g_labels[pi]);
9668       g_labels[pi] = NULL;
9669       continue;
9670     }
9671
9672     if (wordc > 1 && IS(words[1], "="))
9673     {
9674       if (wordc != 5)
9675         aerr("unhandled equ, wc=%d\n", wordc);
9676       if (g_eqcnt >= eq_alloc) {
9677         eq_alloc *= 2;
9678         g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9679         my_assert_not(g_eqs, NULL);
9680       }
9681
9682       len = strlen(words[0]);
9683       if (len > sizeof(g_eqs[0].name) - 1)
9684         aerr("equ name too long: %d\n", len);
9685       strcpy(g_eqs[g_eqcnt].name, words[0]);
9686
9687       if (!IS(words[3], "ptr"))
9688         aerr("unhandled equ\n");
9689       if (IS(words[2], "dword"))
9690         g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9691       else if (IS(words[2], "word"))
9692         g_eqs[g_eqcnt].lmod = OPLM_WORD;
9693       else if (IS(words[2], "byte"))
9694         g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9695       else if (IS(words[2], "qword"))
9696         g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9697       else
9698         aerr("bad lmod: '%s'\n", words[2]);
9699
9700       g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9701       g_eqcnt++;
9702       continue;
9703     }
9704
9705     if (pi >= ARRAY_SIZE(ops))
9706       aerr("too many ops\n");
9707
9708     parse_op(&ops[pi], words, wordc);
9709
9710     ops[pi].datap = sctproto;
9711     sctproto = NULL;
9712     pi++;
9713   }
9714
9715   if (g_header_mode)
9716     output_hdr(fout);
9717
9718   fclose(fout);
9719   fclose(fasm);
9720   fclose(g_fhdr);
9721
9722   return 0;
9723 }
9724
9725 // vim:ts=2:shiftwidth=2:expandtab