translate: seh finalize handler
[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)
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   return pp->name;
2157 }
2158
2159 static void check_opr(struct parsed_op *po, struct parsed_opr *popr)
2160 {
2161   if (popr->segment == SEG_FS)
2162     ferr(po, "fs: used\n");
2163   if (popr->segment == SEG_GS)
2164     ferr(po, "gs: used\n");
2165 }
2166
2167 static char *out_src_opr(char *buf, size_t buf_size,
2168   struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2169   int is_lea)
2170 {
2171   char tmp1[256], tmp2[256];
2172   char expr[256];
2173   const char *name;
2174   char *p;
2175   int ret;
2176
2177   check_opr(po, popr);
2178
2179   if (cast == NULL)
2180     cast = "";
2181
2182   switch (popr->type) {
2183   case OPT_REG:
2184     if (is_lea)
2185       ferr(po, "lea from reg?\n");
2186
2187     switch (popr->lmod) {
2188     case OPLM_QWORD:
2189       snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2190       break;
2191     case OPLM_DWORD:
2192       snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2193       break;
2194     case OPLM_WORD:
2195       snprintf(buf, buf_size, "%s%s",
2196         simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2197       break;
2198     case OPLM_BYTE:
2199       if (popr->name[1] == 'h') // XXX..
2200         snprintf(buf, buf_size, "%s(%s >> 8)",
2201           simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2202       else
2203         snprintf(buf, buf_size, "%s%s",
2204           simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2205       break;
2206     default:
2207       ferr(po, "invalid src lmod: %d\n", popr->lmod);
2208     }
2209     break;
2210
2211   case OPT_REGMEM:
2212     if (is_stack_access(po, popr)) {
2213       stack_frame_access(po, popr, buf, buf_size,
2214         popr->name, cast, 1, is_lea);
2215       break;
2216     }
2217
2218     strcpy(expr, popr->name);
2219     if (strchr(expr, '[')) {
2220       // special case: '[' can only be left for label[reg] form
2221       ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2222       if (ret != 2)
2223         ferr(po, "parse failure for '%s'\n", expr);
2224       if (tmp1[0] == '(') {
2225         // (off_4FFF50+3)[eax]
2226         p = strchr(tmp1 + 1, ')');
2227         if (p == NULL || p[1] != 0)
2228           ferr(po, "parse failure (2) for '%s'\n", expr);
2229         *p = 0;
2230         memmove(tmp1, tmp1 + 1, strlen(tmp1));
2231       }
2232       snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2233     }
2234
2235     // XXX: do we need more parsing?
2236     if (is_lea) {
2237       snprintf(buf, buf_size, "%s", expr);
2238       break;
2239     }
2240
2241     snprintf(buf, buf_size, "%s(%s)",
2242       simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2243     break;
2244
2245   case OPT_LABEL:
2246     name = check_label_read_ref(po, popr->name);
2247     if (cast[0] == 0 && popr->is_ptr)
2248       cast = "(u32)";
2249
2250     if (is_lea)
2251       snprintf(buf, buf_size, "(u32)&%s", name);
2252     else if (popr->size_lt)
2253       snprintf(buf, buf_size, "%s%s%s%s", cast,
2254         lmod_cast_u_ptr(po, popr->lmod),
2255         popr->is_array ? "" : "&", name);
2256     else
2257       snprintf(buf, buf_size, "%s%s%s", cast, name,
2258         popr->is_array ? "[0]" : "");
2259     break;
2260
2261   case OPT_OFFSET:
2262     name = check_label_read_ref(po, popr->name);
2263     if (cast[0] == 0)
2264       cast = "(u32)";
2265     if (is_lea)
2266       ferr(po, "lea an offset?\n");
2267     snprintf(buf, buf_size, "%s&%s", cast, name);
2268     break;
2269
2270   case OPT_CONST:
2271     if (is_lea)
2272       ferr(po, "lea from const?\n");
2273
2274     printf_number(tmp1, sizeof(tmp1), popr->val);
2275     if (popr->val == 0 && strchr(cast, '*'))
2276       snprintf(buf, buf_size, "NULL");
2277     else
2278       snprintf(buf, buf_size, "%s%s",
2279         simplify_cast_num(cast, popr->val), tmp1);
2280     break;
2281
2282   default:
2283     ferr(po, "invalid src type: %d\n", popr->type);
2284   }
2285
2286   return buf;
2287 }
2288
2289 // note: may set is_ptr (we find that out late for ebp frame..)
2290 static char *out_dst_opr(char *buf, size_t buf_size,
2291         struct parsed_op *po, struct parsed_opr *popr)
2292 {
2293   check_opr(po, popr);
2294
2295   switch (popr->type) {
2296   case OPT_REG:
2297     switch (popr->lmod) {
2298     case OPLM_QWORD:
2299       snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2300       break;
2301     case OPLM_DWORD:
2302       snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2303       break;
2304     case OPLM_WORD:
2305       // ugh..
2306       snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2307       break;
2308     case OPLM_BYTE:
2309       // ugh..
2310       if (popr->name[1] == 'h') // XXX..
2311         snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2312       else
2313         snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2314       break;
2315     default:
2316       ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2317     }
2318     break;
2319
2320   case OPT_REGMEM:
2321     if (is_stack_access(po, popr)) {
2322       stack_frame_access(po, popr, buf, buf_size,
2323         popr->name, "", 0, 0);
2324       break;
2325     }
2326
2327     return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2328
2329   case OPT_LABEL:
2330     if (popr->size_mismatch)
2331       snprintf(buf, buf_size, "%s%s%s",
2332         lmod_cast_u_ptr(po, popr->lmod),
2333         popr->is_array ? "" : "&", popr->name);
2334     else
2335       snprintf(buf, buf_size, "%s%s", popr->name,
2336         popr->is_array ? "[0]" : "");
2337     break;
2338
2339   default:
2340     ferr(po, "invalid dst type: %d\n", popr->type);
2341   }
2342
2343   return buf;
2344 }
2345
2346 static char *out_src_opr_u32(char *buf, size_t buf_size,
2347         struct parsed_op *po, struct parsed_opr *popr)
2348 {
2349   return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2350 }
2351
2352 static char *out_opr_float(char *buf, size_t buf_size,
2353   struct parsed_op *po, struct parsed_opr *popr, int is_src,
2354   int need_float_stack)
2355 {
2356   const char *cast = NULL;
2357   char tmp[256];
2358   union {
2359     float f;
2360     int i;
2361   } u;
2362
2363   switch (popr->type) {
2364   case OPT_REG:
2365     if (popr->reg < xST0 || popr->reg > xST7) {
2366       // func arg
2367       ferr_assert(po, po->op == OP_PUSH);
2368       ferr_assert(po, popr->lmod == OPLM_DWORD);
2369       snprintf(buf, buf_size, "*(float *)&%s", opr_reg_p(po, popr));
2370       break;
2371     }
2372
2373     if (need_float_stack) {
2374       if (popr->reg == xST0)
2375         snprintf(buf, buf_size, "f_st[f_stp & 7]");
2376       else
2377         snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2378           popr->reg - xST0);
2379     }
2380     else
2381       snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2382     break;
2383
2384   case OPT_REGMEM:
2385     if (popr->lmod == OPLM_QWORD && is_stack_access(po, popr)) {
2386       stack_frame_access(po, popr, buf, buf_size,
2387         popr->name, "", is_src, 0);
2388       break;
2389     }
2390     // fallthrough
2391   case OPT_LABEL:
2392   case OPT_OFFSET:
2393     switch (popr->lmod) {
2394     case OPLM_QWORD:
2395       cast = "double";
2396       break;
2397     case OPLM_DWORD:
2398       cast = "float";
2399       break;
2400     default:
2401       ferr(po, "unhandled lmod: %d\n", popr->lmod);
2402       break;
2403     }
2404     out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2405     snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2406     break;
2407
2408   case OPT_CONST:
2409     // only for func float args pushes
2410     ferr_assert(po, po->op == OP_PUSH);
2411     u.i = po->operand[0].val;
2412     if (ceilf(u.f) == u.f)
2413       snprintf(buf, buf_size, "%.1ff", u.f);
2414     else
2415       snprintf(buf, buf_size, "%.8ff", u.f);
2416     break;
2417
2418   default:
2419     ferr(po, "invalid float type: %d\n", popr->type);
2420   }
2421
2422   return buf;
2423 }
2424
2425 static char *out_src_opr_float(char *buf, size_t buf_size,
2426   struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2427 {
2428   return out_opr_float(buf, buf_size, po, popr, 1, need_float_stack);
2429 }
2430
2431 static char *out_dst_opr_float(char *buf, size_t buf_size,
2432   struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2433 {
2434   return out_opr_float(buf, buf_size, po, popr, 0, need_float_stack);
2435 }
2436
2437 static void out_test_for_cc(char *buf, size_t buf_size,
2438   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2439   enum opr_lenmod lmod, const char *expr)
2440 {
2441   const char *cast, *scast;
2442
2443   cast = lmod_cast_u(po, lmod);
2444   scast = lmod_cast_s(po, lmod);
2445
2446   switch (pfo) {
2447   case PFO_Z:
2448   case PFO_BE: // CF==1||ZF==1; CF=0
2449     snprintf(buf, buf_size, "(%s%s %s 0)",
2450       cast, expr, is_inv ? "!=" : "==");
2451     break;
2452
2453   case PFO_S:
2454   case PFO_L: // SF!=OF; OF=0
2455     snprintf(buf, buf_size, "(%s%s %s 0)",
2456       scast, expr, is_inv ? ">=" : "<");
2457     break;
2458
2459   case PFO_LE: // ZF==1||SF!=OF; OF=0
2460     snprintf(buf, buf_size, "(%s%s %s 0)",
2461       scast, expr, is_inv ? ">" : "<=");
2462     break;
2463
2464   case PFO_C: // CF=0
2465   case PFO_O: // OF=0
2466     snprintf(buf, buf_size, "(%d)", !!is_inv);
2467     break;
2468
2469   case PFO_P: // PF==1
2470     snprintf(buf, buf_size, "(%sdo_parity(%s))",
2471       is_inv ? "!" : "", expr);
2472     break;
2473
2474   default:
2475     ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2476   }
2477 }
2478
2479 static void out_cmp_for_cc(char *buf, size_t buf_size,
2480   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2481   int is_neg)
2482 {
2483   const char *cast, *scast, *cast_use;
2484   char buf1[256], buf2[256];
2485   enum opr_lenmod lmod;
2486
2487   if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2488     ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2489       po->operand[0].lmod, po->operand[1].lmod);
2490   lmod = po->operand[0].lmod;
2491
2492   cast = lmod_cast_u(po, lmod);
2493   scast = lmod_cast_s(po, lmod);
2494
2495   switch (pfo) {
2496   case PFO_C:
2497   case PFO_Z:
2498   case PFO_BE: // !a
2499     cast_use = cast;
2500     break;
2501
2502   case PFO_S:
2503   case PFO_L: // !ge
2504   case PFO_LE:
2505     cast_use = scast;
2506     break;
2507
2508   default:
2509     ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2510   }
2511
2512   out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2513   if (po->op == OP_DEC)
2514     snprintf(buf2, sizeof(buf2), "1");
2515   else {
2516     char cast_op2[64];
2517     snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2518     if (is_neg)
2519       strcat(cast_op2, "-");
2520     out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2521   }
2522
2523   switch (pfo) {
2524   case PFO_C:
2525     // note: must be unsigned compare
2526     snprintf(buf, buf_size, "(%s %s %s)",
2527       buf1, is_inv ? ">=" : "<", buf2);
2528     break;
2529
2530   case PFO_Z:
2531     snprintf(buf, buf_size, "(%s %s %s)",
2532       buf1, is_inv ? "!=" : "==", buf2);
2533     break;
2534
2535   case PFO_BE: // !a
2536     // note: must be unsigned compare
2537     snprintf(buf, buf_size, "(%s %s %s)",
2538       buf1, is_inv ? ">" : "<=", buf2);
2539
2540     // annoying case
2541     if (is_inv && lmod == OPLM_BYTE
2542       && po->operand[1].type == OPT_CONST
2543       && po->operand[1].val == 0xff)
2544     {
2545       snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2546       snprintf(buf, buf_size, "(0)");
2547     }
2548     break;
2549
2550   // note: must be signed compare
2551   case PFO_S:
2552     snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2553       scast, buf1, buf2, is_inv ? ">=" : "<");
2554     break;
2555
2556   case PFO_L: // !ge
2557     snprintf(buf, buf_size, "(%s %s %s)",
2558       buf1, is_inv ? ">=" : "<", buf2);
2559     break;
2560
2561   case PFO_LE: // !g
2562     snprintf(buf, buf_size, "(%s %s %s)",
2563       buf1, is_inv ? ">" : "<=", buf2);
2564     break;
2565
2566   default:
2567     break;
2568   }
2569 }
2570
2571 static void out_cmp_test(char *buf, size_t buf_size,
2572   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2573 {
2574   char buf1[256], buf2[256], buf3[256];
2575
2576   if (po->op == OP_TEST) {
2577     if (IS(opr_name(po, 0), opr_name(po, 1))) {
2578       out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2579     }
2580     else {
2581       out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2582       out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2583       snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2584     }
2585     out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2586       po->operand[0].lmod, buf3);
2587   }
2588   else if (po->op == OP_CMP) {
2589     out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2590   }
2591   else
2592     ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2593 }
2594
2595 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2596         struct parsed_opr *popr2)
2597 {
2598   if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2599     ferr(po, "missing lmod for both operands\n");
2600
2601   if (popr1->lmod == OPLM_UNSPEC)
2602     popr1->lmod = popr2->lmod;
2603   else if (popr2->lmod == OPLM_UNSPEC)
2604     popr2->lmod = popr1->lmod;
2605   else if (popr1->lmod != popr2->lmod) {
2606     if (popr1->type_from_var) {
2607       popr1->size_mismatch = 1;
2608       if (popr1->lmod < popr2->lmod)
2609         popr1->size_lt = 1;
2610       popr1->lmod = popr2->lmod;
2611     }
2612     else if (popr2->type_from_var) {
2613       popr2->size_mismatch = 1;
2614       if (popr2->lmod < popr1->lmod)
2615         popr2->size_lt = 1;
2616       popr2->lmod = popr1->lmod;
2617     }
2618     else
2619       ferr(po, "conflicting lmods: %d vs %d\n",
2620         popr1->lmod, popr2->lmod);
2621   }
2622 }
2623
2624 static const char *op_to_c(struct parsed_op *po)
2625 {
2626   switch (po->op)
2627   {
2628     case OP_ADD:
2629     case OP_ADC:
2630       return "+";
2631     case OP_SUB:
2632     case OP_SBB:
2633       return "-";
2634     case OP_AND:
2635       return "&";
2636     case OP_OR:
2637       return "|";
2638     case OP_XOR:
2639       return "^";
2640     case OP_SHL:
2641       return "<<";
2642     case OP_SHR:
2643       return ">>";
2644     case OP_MUL:
2645     case OP_IMUL:
2646       return "*";
2647     default:
2648       ferr(po, "op_to_c was supplied with %d\n", po->op);
2649   }
2650 }
2651
2652 // last op in stream - unconditional branch or ret
2653 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2654   || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2655       && ops[_i].op != OP_CALL))
2656
2657 #define check_i(po, i) \
2658   if ((i) < 0) \
2659     ferr(po, "bad " #i ": %d\n", i)
2660
2661 // note: this skips over calls and rm'd stuff assuming they're handled
2662 // so it's intended to use at one of final passes
2663 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2664   int depth, int seen_noreturn, int flags_set)
2665 {
2666   struct parsed_op *po;
2667   int relevant;
2668   int ret = 0;
2669   int j;
2670
2671   for (; i < opcnt; i++) {
2672     po = &ops[i];
2673     if (po->cc_scratch == magic)
2674       return ret; // already checked
2675     po->cc_scratch = magic;
2676
2677     if (po->flags & OPF_TAIL) {
2678       if (po->op == OP_CALL) {
2679         if (po->pp != NULL && po->pp->is_noreturn)
2680           seen_noreturn = 1;
2681         else
2682           goto out;
2683       }
2684       else
2685         goto out;
2686     }
2687
2688     if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2689       continue;
2690
2691     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2692       if (po->btj != NULL) {
2693         // jumptable
2694         for (j = 0; j < po->btj->count; j++) {
2695           check_i(po, po->btj->d[j].bt_i);
2696           ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2697                    depth, seen_noreturn, flags_set);
2698           if (ret < 0)
2699             return ret; // dead end
2700         }
2701         return ret;
2702       }
2703
2704       check_i(po, po->bt_i);
2705       if (po->flags & OPF_CJMP) {
2706         ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2707                  depth, seen_noreturn, flags_set);
2708         if (ret < 0)
2709           return ret; // dead end
2710       }
2711       else {
2712         i = po->bt_i - 1;
2713       }
2714       continue;
2715     }
2716
2717     relevant = 0;
2718     if ((po->op == OP_POP || po->op == OP_PUSH)
2719       && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2720     {
2721       relevant = 1;
2722     }
2723
2724     if (po->op == OP_PUSH) {
2725       depth++;
2726     }
2727     else if (po->op == OP_POP) {
2728       if (relevant && depth == 0) {
2729         po->flags |= flags_set;
2730         return 1;
2731       }
2732       depth--;
2733     }
2734   }
2735
2736 out:
2737   // for noreturn, assume msvc skipped stack cleanup
2738   return seen_noreturn ? 1 : -1;
2739 }
2740
2741 // scan for 'reg' pop backwards starting from i
2742 // intended to use for register restore search, so other reg
2743 // references are considered an error
2744 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2745 {
2746   struct parsed_op *po;
2747   struct label_ref *lr;
2748   int ret = 0;
2749
2750   ops[i].cc_scratch = magic;
2751
2752   while (1)
2753   {
2754     if (g_labels[i] != NULL) {
2755       lr = &g_label_refs[i];
2756       for (; lr != NULL; lr = lr->next) {
2757         check_i(&ops[i], lr->i);
2758         ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2759         if (ret < 0)
2760           return ret;
2761       }
2762       if (i > 0 && LAST_OP(i - 1))
2763         return ret;
2764     }
2765
2766     i--;
2767     if (i < 0)
2768       break;
2769
2770     if (ops[i].cc_scratch == magic)
2771       return ret;
2772     ops[i].cc_scratch = magic;
2773
2774     po = &ops[i];
2775     if (po->op == OP_POP && po->operand[0].reg == reg) {
2776       if (po->flags & (OPF_RMD|OPF_DONE))
2777         return -1;
2778
2779       po->flags |= set_flags;
2780       return 1;
2781     }
2782
2783     // this also covers the case where we reach corresponding push
2784     if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2785       return -1;
2786   }
2787
2788   // nothing interesting on this path,
2789   // still return ret for something recursive calls could find
2790   return ret;
2791 }
2792
2793 static void find_reachable_exits(int i, int opcnt, int magic,
2794   int *exits, int *exit_count)
2795 {
2796   struct parsed_op *po;
2797   int j;
2798
2799   for (; i < opcnt; i++)
2800   {
2801     po = &ops[i];
2802     if (po->cc_scratch == magic)
2803       return;
2804     po->cc_scratch = magic;
2805
2806     if (po->flags & OPF_TAIL) {
2807       ferr_assert(po, *exit_count < MAX_EXITS);
2808       exits[*exit_count] = i;
2809       (*exit_count)++;
2810       return;
2811     }
2812
2813     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2814       if (po->flags & OPF_RMD)
2815         continue;
2816
2817       if (po->btj != NULL) {
2818         for (j = 0; j < po->btj->count; j++) {
2819           check_i(po, po->btj->d[j].bt_i);
2820           find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2821                   exits, exit_count);
2822         }
2823         return;
2824       }
2825
2826       check_i(po, po->bt_i);
2827       if (po->flags & OPF_CJMP)
2828         find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2829       else
2830         i = po->bt_i - 1;
2831       continue;
2832     }
2833   }
2834 }
2835
2836 // scan for 'reg' pop backwards starting from exits (all paths)
2837 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2838 {
2839   static int exits[MAX_EXITS];
2840   static int exit_count;
2841   int found = 0;
2842   int e, j, ret;
2843
2844   if (!set_flags) {
2845     exit_count = 0;
2846     find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2847       &exit_count);
2848     ferr_assert(&ops[i], exit_count > 0);
2849   }
2850
2851   for (j = 0; j < exit_count; j++) {
2852     e = exits[j];
2853     ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2854             reg, set_flags);
2855     if (ret != -1) {
2856       found |= ret;
2857       continue;
2858     }
2859     if (ops[e].op == OP_CALL && ops[e].pp != NULL
2860       && ops[e].pp->is_noreturn)
2861     {
2862       // assume stack cleanup was skipped
2863       continue;
2864     }
2865     return -1;
2866   }
2867
2868   return found;
2869 }
2870
2871 // scan for one or more pop of push <const>
2872 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2873   int push_i, int is_probe)
2874 {
2875   struct parsed_op *po;
2876   struct label_ref *lr;
2877   int ret = 0;
2878   int j;
2879
2880   for (; i < opcnt; i++)
2881   {
2882     po = &ops[i];
2883     if (po->cc_scratch == magic)
2884       return ret; // already checked
2885     po->cc_scratch = magic;
2886
2887     if (po->flags & OPF_JMP) {
2888       if (po->flags & OPF_RMD)
2889         continue;
2890       if (po->op == OP_CALL)
2891         return -1;
2892
2893       if (po->btj != NULL) {
2894         for (j = 0; j < po->btj->count; j++) {
2895           check_i(po, po->btj->d[j].bt_i);
2896           ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2897                   push_i, is_probe);
2898           if (ret < 0)
2899             return ret;
2900         }
2901         return ret;
2902       }
2903
2904       check_i(po, po->bt_i);
2905       if (po->flags & OPF_CJMP) {
2906         ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2907                  is_probe);
2908         if (ret < 0)
2909           return ret;
2910       }
2911       else {
2912         i = po->bt_i - 1;
2913       }
2914       continue;
2915     }
2916
2917     if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2918       return -1;
2919
2920     if (g_labels[i] != NULL) {
2921       // all refs must be visited
2922       lr = &g_label_refs[i];
2923       for (; lr != NULL; lr = lr->next) {
2924         check_i(po, lr->i);
2925         if (ops[lr->i].cc_scratch != magic)
2926           return -1;
2927       }
2928       if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2929         return -1;
2930     }
2931
2932     if (po->op == OP_POP)
2933     {
2934       if (po->flags & (OPF_RMD|OPF_DONE))
2935         return -1;
2936
2937       if (!is_probe) {
2938         po->flags |= OPF_DONE;
2939         po->datap = &ops[push_i];
2940       }
2941       return 1;
2942     }
2943   }
2944
2945   return -1;
2946 }
2947
2948 static void scan_for_pop_const(int i, int opcnt, int magic)
2949 {
2950   int ret;
2951
2952   ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2953   if (ret == 1) {
2954     ops[i].flags |= OPF_RMD | OPF_DONE;
2955     scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2956   }
2957 }
2958
2959 // check if all branch targets within a marked path are also marked
2960 // note: the path checked must not be empty or end with a branch
2961 static int check_path_branches(int opcnt, int magic)
2962 {
2963   struct parsed_op *po;
2964   int i, j;
2965
2966   for (i = 0; i < opcnt; i++) {
2967     po = &ops[i];
2968     if (po->cc_scratch != magic)
2969       continue;
2970
2971     if (po->flags & OPF_JMP) {
2972       if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2973         continue;
2974
2975       if (po->btj != NULL) {
2976         for (j = 0; j < po->btj->count; j++) {
2977           check_i(po, po->btj->d[j].bt_i);
2978           if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2979             return 0;
2980         }
2981       }
2982
2983       check_i(po, po->bt_i);
2984       if (ops[po->bt_i].cc_scratch != magic)
2985         return 0;
2986       if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2987         return 0;
2988     }
2989   }
2990
2991   return 1;
2992 }
2993
2994 // scan for multiple pushes for given pop
2995 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2996   int is_probe)
2997 {
2998   int reg = ops[pop_i].operand[0].reg;
2999   struct parsed_op *po;
3000   struct label_ref *lr;
3001   int ret = 0;
3002
3003   ops[i].cc_scratch = magic;
3004
3005   while (1)
3006   {
3007     if (g_labels[i] != NULL) {
3008       lr = &g_label_refs[i];
3009       for (; lr != NULL; lr = lr->next) {
3010         check_i(&ops[i], lr->i);
3011         ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
3012         if (ret < 0)
3013           return ret;
3014       }
3015       if (i > 0 && LAST_OP(i - 1))
3016         return ret;
3017     }
3018
3019     i--;
3020     if (i < 0)
3021       break;
3022
3023     if (ops[i].cc_scratch == magic)
3024       return ret;
3025     ops[i].cc_scratch = magic;
3026
3027     po = &ops[i];
3028     if (po->op == OP_CALL)
3029       return -1;
3030     if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
3031       return -1;
3032
3033     if (po->op == OP_PUSH)
3034     {
3035       if (po->datap != NULL)
3036         return -1;
3037       if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
3038         // leave this case for reg save/restore handlers
3039         return -1;
3040
3041       if (!is_probe) {
3042         po->flags |= OPF_PPUSH | OPF_DONE;
3043         po->datap = &ops[pop_i];
3044       }
3045       return 1;
3046     }
3047   }
3048
3049   return -1;
3050 }
3051
3052 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
3053 {
3054   int magic = i + opcnt * 14;
3055   int ret;
3056
3057   ret = scan_pushes_for_pop_r(i, magic, i, 1);
3058   if (ret == 1) {
3059     ret = check_path_branches(opcnt, magic);
3060     if (ret == 1) {
3061       ops[i].flags |= OPF_PPUSH | OPF_DONE;
3062       *regmask_pp |= 1 << ops[i].operand[0].reg;
3063       scan_pushes_for_pop_r(i, magic + 1, i, 0);
3064     }
3065   }
3066 }
3067
3068 static void scan_propagate_df(int i, int opcnt)
3069 {
3070   struct parsed_op *po = &ops[i];
3071   int j;
3072
3073   for (; i < opcnt; i++) {
3074     po = &ops[i];
3075     if (po->flags & OPF_DF)
3076       return; // already resolved
3077     po->flags |= OPF_DF;
3078
3079     if (po->op == OP_CALL)
3080       ferr(po, "call with DF set?\n");
3081
3082     if (po->flags & OPF_JMP) {
3083       if (po->btj != NULL) {
3084         // jumptable
3085         for (j = 0; j < po->btj->count; j++) {
3086           check_i(po, po->btj->d[j].bt_i);
3087           scan_propagate_df(po->btj->d[j].bt_i, opcnt);
3088         }
3089         return;
3090       }
3091
3092       if (po->flags & OPF_RMD)
3093         continue;
3094       check_i(po, po->bt_i);
3095       if (po->flags & OPF_CJMP)
3096         scan_propagate_df(po->bt_i, opcnt);
3097       else
3098         i = po->bt_i - 1;
3099       continue;
3100     }
3101
3102     if (po->flags & OPF_TAIL)
3103       break;
3104
3105     if (po->op == OP_CLD) {
3106       po->flags |= OPF_RMD | OPF_DONE;
3107       return;
3108     }
3109   }
3110
3111   ferr(po, "missing DF clear?\n");
3112 }
3113
3114 // is operand 'opr' referenced by parsed_op 'po'?
3115 static int is_opr_referenced(const struct parsed_opr *opr,
3116   const struct parsed_op *po)
3117 {
3118   int i, mask;
3119
3120   if (opr->type == OPT_REG) {
3121     mask = po->regmask_dst | po->regmask_src;
3122     if (po->op == OP_CALL)
3123       mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3124     if ((1 << opr->reg) & mask)
3125       return 1;
3126     else
3127       return 0;
3128   }
3129
3130   for (i = 0; i < po->operand_cnt; i++)
3131     if (IS(po->operand[0].name, opr->name))
3132       return 1;
3133
3134   return 0;
3135 }
3136
3137 // is operand 'opr' read by parsed_op 'po'?
3138 static int is_opr_read(const struct parsed_opr *opr,
3139   const struct parsed_op *po)
3140 {
3141   if (opr->type == OPT_REG) {
3142     if (po->regmask_src & (1 << opr->reg))
3143       return 1;
3144     else
3145       return 0;
3146   }
3147
3148   // yes I'm lazy
3149   return 0;
3150 }
3151
3152 // is operand 'opr' modified by parsed_op 'po'?
3153 static int is_opr_modified(const struct parsed_opr *opr,
3154   const struct parsed_op *po)
3155 {
3156   int mask;
3157
3158   if (opr->type == OPT_REG) {
3159     if (po->op == OP_CALL) {
3160       mask = po->regmask_dst;
3161       mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3162       if (mask & (1 << opr->reg))
3163         return 1;
3164       else
3165         return 0;
3166     }
3167
3168     if (po->regmask_dst & (1 << opr->reg))
3169       return 1;
3170     else
3171       return 0;
3172   }
3173
3174   return IS(po->operand[0].name, opr->name);
3175 }
3176
3177 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3178 static int is_any_opr_modified(const struct parsed_op *po_test,
3179   const struct parsed_op *po, int c_mode)
3180 {
3181   int mask;
3182   int i;
3183
3184   if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3185     return 0;
3186
3187   if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3188     return 0;
3189
3190   if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3191     return 1;
3192
3193   // in reality, it can wreck any register, but in decompiled C
3194   // version it can only overwrite eax or edx:eax
3195   mask = (1 << xAX) | (1 << xDX);
3196   if (!c_mode)
3197     mask |= 1 << xCX;
3198
3199   if (po->op == OP_CALL
3200    && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3201     return 1;
3202
3203   for (i = 0; i < po_test->operand_cnt; i++)
3204     if (IS(po_test->operand[i].name, po->operand[0].name))
3205       return 1;
3206
3207   return 0;
3208 }
3209
3210 // scan for any po_test operand modification in range given
3211 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3212   int c_mode)
3213 {
3214   if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3215     return -1;
3216
3217   for (; i < opcnt; i++) {
3218     if (is_any_opr_modified(po_test, &ops[i], c_mode))
3219       return i;
3220   }
3221
3222   return -1;
3223 }
3224
3225 // scan for po_test operand[0] modification in range given
3226 static int scan_for_mod_opr0(struct parsed_op *po_test,
3227   int i, int opcnt)
3228 {
3229   for (; i < opcnt; i++) {
3230     if (is_opr_modified(&po_test->operand[0], &ops[i]))
3231       return i;
3232   }
3233
3234   return -1;
3235 }
3236
3237 static int try_resolve_const(int i, const struct parsed_opr *opr,
3238   int magic, unsigned int *val);
3239
3240 static int scan_for_flag_set(int i, int opcnt, int magic,
3241   int *branched, int *setters, int *setter_cnt)
3242 {
3243   struct label_ref *lr;
3244   int ret;
3245
3246   while (i >= 0) {
3247     if (ops[i].cc_scratch == magic) {
3248       // is this a problem?
3249       //ferr(&ops[i], "%s looped\n", __func__);
3250       return 0;
3251     }
3252     ops[i].cc_scratch = magic;
3253
3254     if (g_labels[i] != NULL) {
3255       *branched = 1;
3256
3257       lr = &g_label_refs[i];
3258       for (; lr->next; lr = lr->next) {
3259         check_i(&ops[i], lr->i);
3260         ret = scan_for_flag_set(lr->i, opcnt, magic,
3261                 branched, setters, setter_cnt);
3262         if (ret < 0)
3263           return ret;
3264       }
3265
3266       check_i(&ops[i], lr->i);
3267       if (i > 0 && LAST_OP(i - 1)) {
3268         i = lr->i;
3269         continue;
3270       }
3271       ret = scan_for_flag_set(lr->i, opcnt, magic,
3272               branched, setters, setter_cnt);
3273       if (ret < 0)
3274         return ret;
3275     }
3276     i--;
3277
3278     if (ops[i].flags & OPF_FLAGS) {
3279       setters[*setter_cnt] = i;
3280       (*setter_cnt)++;
3281
3282       if (ops[i].flags & OPF_REP) {
3283         struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3284         unsigned int uval;
3285
3286         ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3287         if (ret != 1 || uval == 0) {
3288           // can't treat it as full setter because of ecx=0 case,
3289           // also disallow delayed compare
3290           *branched = 1;
3291           continue;
3292         }
3293       }
3294
3295       return 0;
3296     }
3297
3298     if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3299       return -1;
3300   }
3301
3302   return -1;
3303 }
3304
3305 // scan back for cdq, if anything modifies edx, fail
3306 static int scan_for_cdq_edx(int i)
3307 {
3308   while (i >= 0) {
3309     if (g_labels[i] != NULL) {
3310       if (g_label_refs[i].next != NULL)
3311         return -1;
3312       if (i > 0 && LAST_OP(i - 1)) {
3313         i = g_label_refs[i].i;
3314         continue;
3315       }
3316       return -1;
3317     }
3318     i--;
3319
3320     if (ops[i].op == OP_CDQ)
3321       return i;
3322
3323     if (ops[i].regmask_dst & (1 << xDX))
3324       return -1;
3325   }
3326
3327   return -1;
3328 }
3329
3330 static int scan_for_reg_clear(int i, int reg)
3331 {
3332   while (i >= 0) {
3333     if (g_labels[i] != NULL) {
3334       if (g_label_refs[i].next != NULL)
3335         return -1;
3336       if (i > 0 && LAST_OP(i - 1)) {
3337         i = g_label_refs[i].i;
3338         continue;
3339       }
3340       return -1;
3341     }
3342     i--;
3343
3344     if (ops[i].op == OP_XOR
3345      && ops[i].operand[0].lmod == OPLM_DWORD
3346      && ops[i].operand[0].reg == ops[i].operand[1].reg
3347      && ops[i].operand[0].reg == reg)
3348       return i;
3349
3350     if (ops[i].regmask_dst & (1 << reg))
3351       return -1;
3352   }
3353
3354   return -1;
3355 }
3356
3357 static void patch_esp_adjust(struct parsed_op *po, int adj)
3358 {
3359   ferr_assert(po, po->op == OP_ADD);
3360   ferr_assert(po, IS(opr_name(po, 0), "esp"));
3361   ferr_assert(po, po->operand[1].type == OPT_CONST);
3362
3363   // this is a bit of a hack, but deals with use of
3364   // single adj for multiple calls
3365   po->operand[1].val -= adj;
3366   po->flags |= OPF_RMD;
3367   if (po->operand[1].val == 0)
3368     po->flags |= OPF_DONE;
3369   ferr_assert(po, (int)po->operand[1].val >= 0);
3370 }
3371
3372 // scan for positive, constant esp adjust
3373 // multipath case is preliminary
3374 static int scan_for_esp_adjust(int i, int opcnt,
3375   int adj_expect, int *adj, int *is_multipath, int do_update)
3376 {
3377   int adj_expect_unknown = 0;
3378   struct parsed_op *po;
3379   int first_pop = -1;
3380   int adj_best = 0;
3381
3382   *adj = *is_multipath = 0;
3383   if (adj_expect < 0) {
3384     adj_expect_unknown = 1;
3385     adj_expect = 32 * 4; // enough?
3386   }
3387
3388   for (; i < opcnt && *adj < adj_expect; i++) {
3389     if (g_labels[i] != NULL)
3390       *is_multipath = 1;
3391
3392     po = &ops[i];
3393     if (po->flags & OPF_DONE)
3394       continue;
3395
3396     if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3397       if (po->operand[1].type != OPT_CONST)
3398         ferr(&ops[i], "non-const esp adjust?\n");
3399       *adj += po->operand[1].val;
3400       if (*adj & 3)
3401         ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3402       if (do_update) {
3403         if (!*is_multipath)
3404           patch_esp_adjust(po, adj_expect);
3405         else
3406           po->flags |= OPF_RMD;
3407       }
3408       return i;
3409     }
3410     else if (po->op == OP_PUSH) {
3411       //if (first_pop == -1)
3412       //  first_pop = -2; // none
3413       *adj -= lmod_bytes(po, po->operand[0].lmod);
3414     }
3415     else if (po->op == OP_POP) {
3416       if (!(po->flags & OPF_DONE)) {
3417         // seems like msvc only uses 'pop ecx' for stack realignment..
3418         if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3419           break;
3420         if (first_pop == -1 && *adj >= 0)
3421           first_pop = i;
3422       }
3423       if (do_update && *adj >= 0) {
3424         po->flags |= OPF_RMD;
3425         if (!*is_multipath)
3426           po->flags |= OPF_DONE | OPF_NOREGS;
3427       }
3428
3429       *adj += lmod_bytes(po, po->operand[0].lmod);
3430       if (*adj > adj_best)
3431         adj_best = *adj;
3432     }
3433     else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3434       if (po->op == OP_JMP && po->btj == NULL) {
3435         if (po->bt_i <= i)
3436           break;
3437         i = po->bt_i - 1;
3438         continue;
3439       }
3440       if (po->op != OP_CALL)
3441         break;
3442       if (po->operand[0].type != OPT_LABEL)
3443         break;
3444       if (po->pp != NULL && po->pp->is_stdcall)
3445         break;
3446       if (adj_expect_unknown && first_pop >= 0)
3447         break;
3448       // assume it's another cdecl call
3449     }
3450   }
3451
3452   if (first_pop >= 0) {
3453     // probably only 'pop ecx' was used
3454     *adj = adj_best;
3455     return first_pop;
3456   }
3457
3458   return -1;
3459 }
3460
3461 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3462 {
3463   struct parsed_op *po;
3464   int j;
3465
3466   if (i < 0)
3467     ferr(ops, "%s: followed bad branch?\n", __func__);
3468
3469   for (; i < opcnt; i++) {
3470     po = &ops[i];
3471     if (po->cc_scratch == magic)
3472       return;
3473     po->cc_scratch = magic;
3474     po->flags |= flags;
3475
3476     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3477       if (po->btj != NULL) {
3478         // jumptable
3479         for (j = 0; j < po->btj->count; j++)
3480           scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3481         return;
3482       }
3483
3484       scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3485       if (!(po->flags & OPF_CJMP))
3486         return;
3487     }
3488     if (po->flags & OPF_TAIL)
3489       return;
3490   }
3491 }
3492
3493 static const struct parsed_proto *try_recover_pp(
3494   struct parsed_op *po, const struct parsed_opr *opr,
3495   int is_call, int *search_instead)
3496 {
3497   const struct parsed_proto *pp = NULL;
3498   char buf[256];
3499   char *p;
3500
3501   // maybe an arg of g_func?
3502   if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3503   {
3504     char ofs_reg[16] = { 0, };
3505     int arg, arg_s, arg_i;
3506     int stack_ra = 0;
3507     int offset = 0;
3508
3509     if (g_header_mode)
3510       return NULL;
3511
3512     parse_stack_access(po, opr->name, ofs_reg,
3513       &offset, &stack_ra, NULL, 0);
3514     if (ofs_reg[0] != 0)
3515       ferr(po, "offset reg on arg access?\n");
3516     if (offset <= stack_ra) {
3517       // search who set the stack var instead
3518       if (search_instead != NULL)
3519         *search_instead = 1;
3520       return NULL;
3521     }
3522
3523     arg_i = (offset - stack_ra - 4) / 4;
3524     for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3525       if (g_func_pp->arg[arg].reg != NULL)
3526         continue;
3527       if (arg_s == arg_i)
3528         break;
3529       arg_s++;
3530     }
3531     if (arg == g_func_pp->argc)
3532       ferr(po, "stack arg %d not in prototype?\n", arg_i);
3533
3534     pp = g_func_pp->arg[arg].pp;
3535     if (is_call) {
3536       if (pp == NULL)
3537         ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3538       check_func_pp(po, pp, "icall arg");
3539     }
3540   }
3541   else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3542     // label[index]
3543     p = strchr(opr->name + 1, '[');
3544     memcpy(buf, opr->name, p - opr->name);
3545     buf[p - opr->name] = 0;
3546     pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3547   }
3548   else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3549     pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3550     if (pp == NULL) {
3551       if (!g_header_mode)
3552         ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3553     }
3554     else
3555       check_func_pp(po, pp, "reg-fptr ref");
3556   }
3557
3558   return pp;
3559 }
3560
3561 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3562   int magic, const struct parsed_proto **pp_found, int *pp_i,
3563   int *multi)
3564 {
3565   const struct parsed_proto *pp = NULL;
3566   struct parsed_op *po;
3567   struct label_ref *lr;
3568
3569   ops[i].cc_scratch = magic;
3570
3571   while (1) {
3572     if (g_labels[i] != NULL) {
3573       lr = &g_label_refs[i];
3574       for (; lr != NULL; lr = lr->next) {
3575         check_i(&ops[i], lr->i);
3576         scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3577       }
3578       if (i > 0 && LAST_OP(i - 1))
3579         return;
3580     }
3581
3582     i--;
3583     if (i < 0)
3584       break;
3585
3586     if (ops[i].cc_scratch == magic)
3587       return;
3588     ops[i].cc_scratch = magic;
3589
3590     if (!(ops[i].flags & OPF_DATA))
3591       continue;
3592     if (!is_opr_modified(opr, &ops[i]))
3593       continue;
3594     if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3595       // most probably trashed by some processing
3596       *pp_found = NULL;
3597       return;
3598     }
3599
3600     opr = &ops[i].operand[1];
3601     if (opr->type != OPT_REG)
3602       break;
3603   }
3604
3605   po = (i >= 0) ? &ops[i] : ops;
3606
3607   if (i < 0) {
3608     // reached the top - can only be an arg-reg
3609     if (opr->type != OPT_REG || g_func_pp == NULL)
3610       return;
3611
3612     for (i = 0; i < g_func_pp->argc; i++) {
3613       if (g_func_pp->arg[i].reg == NULL)
3614         continue;
3615       if (IS(opr->name, g_func_pp->arg[i].reg))
3616         break;
3617     }
3618     if (i == g_func_pp->argc)
3619       return;
3620     pp = g_func_pp->arg[i].pp;
3621     if (pp == NULL)
3622       ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3623         i + 1, g_func_pp->arg[i].reg);
3624     check_func_pp(po, pp, "icall reg-arg");
3625   }
3626   else
3627     pp = try_recover_pp(po, opr, 1, NULL);
3628
3629   if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3630     if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3631       || (*pp_found)->is_stdcall != pp->is_stdcall
3632       //|| (*pp_found)->is_fptr != pp->is_fptr
3633       || (*pp_found)->argc != pp->argc
3634       || (*pp_found)->argc_reg != pp->argc_reg
3635       || (*pp_found)->argc_stack != pp->argc_stack)
3636     {
3637       ferr(po, "icall: parsed_proto mismatch\n");
3638     }
3639     *multi = 1;
3640   }
3641   if (pp != NULL) {
3642     *pp_found = pp;
3643     *pp_i = po - ops;
3644   }
3645 }
3646
3647 static void add_label_ref(struct label_ref *lr, int op_i)
3648 {
3649   struct label_ref *lr_new;
3650
3651   if (lr->i == -1) {
3652     lr->i = op_i;
3653     return;
3654   }
3655
3656   lr_new = calloc(1, sizeof(*lr_new));
3657   lr_new->i = op_i;
3658   lr_new->next = lr->next;
3659   lr->next = lr_new;
3660 }
3661
3662 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3663 {
3664   struct parsed_op *po = &ops[i];
3665   struct parsed_data *pd;
3666   char label[NAMELEN], *p;
3667   int len, j, l;
3668
3669   p = strchr(po->operand[0].name, '[');
3670   if (p == NULL)
3671     return NULL;
3672
3673   len = p - po->operand[0].name;
3674   strncpy(label, po->operand[0].name, len);
3675   label[len] = 0;
3676
3677   for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3678     if (IS(g_func_pd[j].label, label)) {
3679       pd = &g_func_pd[j];
3680       break;
3681     }
3682   }
3683   if (pd == NULL)
3684     //ferr(po, "label '%s' not parsed?\n", label);
3685     return NULL;
3686
3687   if (pd->type != OPT_OFFSET)
3688     ferr(po, "label '%s' with non-offset data?\n", label);
3689
3690   // find all labels, link
3691   for (j = 0; j < pd->count; j++) {
3692     for (l = 0; l < opcnt; l++) {
3693       if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3694         add_label_ref(&g_label_refs[l], i);
3695         pd->d[j].bt_i = l;
3696         break;
3697       }
3698     }
3699   }
3700
3701   return pd;
3702 }
3703
3704 static void clear_labels(int count)
3705 {
3706   int i;
3707
3708   for (i = 0; i < count; i++) {
3709     if (g_labels[i] != NULL) {
3710       free(g_labels[i]);
3711       g_labels[i] = NULL;
3712     }
3713   }
3714 }
3715
3716 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3717 {
3718   int regmask = 0;
3719   int i, reg;
3720
3721   for (i = 0; i < pp->argc; i++) {
3722     if (pp->arg[i].reg != NULL) {
3723       reg = char_array_i(regs_r32,
3724               ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3725       if (reg < 0)
3726         ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3727           pp->arg[i].reg, pp->name);
3728       regmask |= 1 << reg;
3729     }
3730   }
3731
3732   return regmask;
3733 }
3734
3735 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3736 {
3737   int regmask = 0;
3738   int i, reg;
3739
3740   if (pp->has_retreg) {
3741     for (i = 0; i < pp->argc; i++) {
3742       if (pp->arg[i].type.is_retreg) {
3743         reg = char_array_i(regs_r32,
3744                 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3745         ferr_assert(ops, reg >= 0);
3746         regmask |= 1 << reg;
3747       }
3748     }
3749   }
3750
3751   if (strstr(pp->ret_type.name, "int64"))
3752     return regmask | (1 << xAX) | (1 << xDX);
3753   if (IS(pp->ret_type.name, "float")
3754    || IS(pp->ret_type.name, "double"))
3755   {
3756     return regmask | mxST0;
3757   }
3758   if (strcasecmp(pp->ret_type.name, "void") == 0)
3759     return regmask;
3760
3761   return regmask | mxAX;
3762 }
3763
3764 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3765 {
3766   return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3767     && memcmp(po1->operand, po2->operand,
3768               sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3769 }
3770
3771 static void resolve_branches_parse_calls(int opcnt)
3772 {
3773   static const struct {
3774     const char *name;
3775     enum op_op op;
3776     unsigned int flags;
3777     unsigned int regmask_src;
3778     unsigned int regmask_dst;
3779   } pseudo_ops[] = {
3780     { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3781     { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3782     { "__ftol",   OPP_FTOL,   OPF_FPOP, mxST0, mxAX | mxDX },
3783     // more precise? Wine gets away with just __ftol handler
3784     { "__ftol2",  OPP_FTOL,   OPF_FPOP, mxST0, mxAX | mxDX },
3785     { "__CIpow",  OPP_CIPOW,  OPF_FPOP, mxST0|mxST1, mxST0 },
3786   };
3787   const struct parsed_proto *pp_c;
3788   struct parsed_proto *pp;
3789   struct parsed_data *pd;
3790   struct parsed_op *po;
3791   const char *tmpname;
3792   enum op_op prev_op;
3793   int i, l;
3794   int ret;
3795
3796   for (i = 0; i < opcnt; i++)
3797   {
3798     po = &ops[i];
3799     po->bt_i = -1;
3800     po->btj = NULL;
3801
3802     if (po->datap != NULL) {
3803       pp = calloc(1, sizeof(*pp));
3804       my_assert_not(pp, NULL);
3805
3806       ret = parse_protostr(po->datap, pp);
3807       if (ret < 0)
3808         ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3809       free(po->datap);
3810       po->datap = NULL;
3811       po->pp = pp;
3812     }
3813
3814     if (po->op == OP_CALL) {
3815       pp = NULL;
3816
3817       if (po->pp != NULL)
3818         pp = po->pp;
3819       else if (po->operand[0].type == OPT_LABEL)
3820       {
3821         tmpname = opr_name(po, 0);
3822         if (IS_START(tmpname, "loc_")) {
3823           if (!g_seh_found)
3824             ferr(po, "call to loc_*\n");
3825           // eliminate_seh() must take care of it
3826           continue;
3827         }
3828         if (IS(tmpname, "__alloca_probe"))
3829           continue;
3830         if (IS(tmpname, "__SEH_prolog")) {
3831           ferr_assert(po, g_seh_found == 0);
3832           g_seh_found = 2;
3833           continue;
3834         }
3835         if (IS(tmpname, "__SEH_epilog"))
3836           continue;
3837
3838         // convert some calls to pseudo-ops
3839         for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3840           if (!IS(tmpname, pseudo_ops[l].name))
3841             continue;
3842
3843           po->op = pseudo_ops[l].op;
3844           po->operand_cnt = 0;
3845           po->regmask_src = pseudo_ops[l].regmask_src;
3846           po->regmask_dst = pseudo_ops[l].regmask_dst;
3847           po->flags = pseudo_ops[l].flags;
3848           po->flags |= po->regmask_dst ? OPF_DATA : 0;
3849           break;
3850         }
3851         if (l < ARRAY_SIZE(pseudo_ops))
3852           continue;
3853
3854         pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3855         if (!g_header_mode && pp_c == NULL)
3856           ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3857
3858         if (pp_c != NULL) {
3859           pp = proto_clone(pp_c);
3860           my_assert_not(pp, NULL);
3861         }
3862       }
3863
3864       if (pp != NULL) {
3865         if (pp->is_fptr)
3866           check_func_pp(po, pp, "fptr var call");
3867         if (pp->is_noreturn) {
3868           po->flags |= OPF_TAIL;
3869           po->flags &= ~OPF_ATAIL; // most likely...
3870         }
3871       }
3872       po->pp = pp;
3873       continue;
3874     }
3875
3876     if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3877       continue;
3878
3879     if (po->operand[0].type == OPT_REGMEM) {
3880       pd = try_resolve_jumptab(i, opcnt);
3881       if (pd == NULL)
3882         goto tailcall;
3883
3884       po->btj = pd;
3885       continue;
3886     }
3887
3888     for (l = 0; l < opcnt; l++) {
3889       if (g_labels[l] != NULL
3890           && IS(po->operand[0].name, g_labels[l]))
3891       {
3892         if (l == i + 1 && po->op == OP_JMP) {
3893           // yet another alignment type..
3894           po->flags |= OPF_RMD|OPF_DONE;
3895           break;
3896         }
3897         add_label_ref(&g_label_refs[l], i);
3898         po->bt_i = l;
3899         break;
3900       }
3901     }
3902
3903     if (po->bt_i != -1 || (po->flags & OPF_RMD))
3904       continue;
3905
3906     if (po->operand[0].type == OPT_LABEL)
3907       // assume tail call
3908       goto tailcall;
3909
3910     ferr(po, "unhandled branch\n");
3911
3912 tailcall:
3913     po->op = OP_CALL;
3914     po->flags |= OPF_TAIL;
3915     prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3916     if (prev_op == OP_POP)
3917       po->flags |= OPF_ATAIL;
3918     if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3919       && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3920     {
3921       po->flags |= OPF_ATAIL;
3922     }
3923     i--; // reprocess
3924   }
3925 }
3926
3927 static int resolve_origin(int i, const struct parsed_opr *opr,
3928   int magic, int *op_i, int *is_caller);
3929 static void set_label(int i, const char *name);
3930
3931 static void eliminate_seh_writes(int opcnt)
3932 {
3933   const struct parsed_opr *opr;
3934   char ofs_reg[16];
3935   int offset;
3936   int i;
3937
3938   // assume all sf writes above g_seh_size to be seh related
3939   // (probably unsafe but oh well)
3940   for (i = 0; i < opcnt; i++) {
3941     if (ops[i].op != OP_MOV)
3942       continue;
3943     opr = &ops[i].operand[0];
3944     if (opr->type != OPT_REGMEM)
3945       continue;
3946     if (!is_stack_access(&ops[i], opr))
3947       continue;
3948
3949     offset = 0;
3950     parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
3951       NULL, NULL, 0);
3952     if (offset < 0 && offset >= -g_seh_size)
3953       ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3954   }
3955 }
3956
3957 static void eliminate_seh_finally(int opcnt)
3958 {
3959   const char *target_name = NULL;
3960   const char *return_name = NULL;
3961   int exits[MAX_EXITS];
3962   int exit_count = 0;
3963   int call_i = -1;
3964   int target_i = -1;
3965   int return_i = -1;
3966   int tgend_i = -1;
3967   int i;
3968
3969   for (i = 0; i < opcnt; i++) {
3970     if (ops[i].op != OP_CALL)
3971       continue;
3972     if (!IS_START(opr_name(&ops[i], 0), "loc_"))
3973       continue;
3974     if (target_name != NULL)
3975       ferr(&ops[i], "multiple finally calls? (last was %s)\n",
3976         target_name);
3977     target_name = opr_name(&ops[i], 0);
3978     call_i = i;
3979
3980     if (g_labels[i + 1] == NULL)
3981       set_label(i + 1, "seh_fin_done");
3982     return_name = g_labels[i + 1];
3983     return_i = i + 1;
3984   }
3985
3986   if (call_i == -1)
3987     // no finally block
3988     return;
3989
3990   // find finally code (bt_i is not set because it's call)
3991   for (i = 0; i < opcnt; i++) {
3992     if (g_labels[i] == NULL)
3993       continue;
3994     if (!IS(g_labels[i], target_name))
3995       continue;
3996
3997     ferr_assert(&ops[i], target_i == -1);
3998     target_i = i;
3999   }
4000   ferr_assert(&ops[0], target_i != -1);
4001
4002   find_reachable_exits(target_i, opcnt, target_i + opcnt * 24,
4003     exits, &exit_count);
4004   ferr_assert(&ops[target_i], exit_count == 1);
4005   ferr_assert(&ops[target_i], ops[exits[0]].op == OP_RET);
4006   tgend_i = exits[0];
4007
4008   // convert to jumps, link
4009   ops[call_i].op = OP_JMP;
4010   ops[call_i].bt_i = target_i;
4011   add_label_ref(&g_label_refs[target_i], call_i);
4012
4013   ops[tgend_i].op = OP_JMP;
4014   ops[tgend_i].flags &= ~OPF_TAIL;
4015   ops[tgend_i].flags |= OPF_JMP;
4016   ops[tgend_i].bt_i = return_i;
4017   ops[tgend_i].operand_cnt = 1;
4018   ops[tgend_i].operand[0].type = OPT_LABEL;
4019   snprintf(ops[tgend_i].operand[0].name, NAMELEN, "%s", return_name);
4020   add_label_ref(&g_label_refs[return_i], tgend_i);
4021
4022   // rm seh finally entry code
4023   for (i = target_i - 1; i >= 0; i--) {
4024     if (g_labels[i] != NULL && g_label_refs[i].i != -1)
4025       return;
4026     if (ops[i].flags & OPF_CJMP)
4027       return;
4028     if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4029       break;
4030   }
4031   for (i = target_i - 1; i >= 0; i--) {
4032     if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4033       break;
4034     ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4035   }
4036 }
4037
4038 static void eliminate_seh(int opcnt)
4039 {
4040   int i, j, k, ret;
4041
4042   for (i = 0; i < opcnt; i++) {
4043     if (ops[i].op != OP_MOV)
4044       continue;
4045     if (ops[i].operand[0].segment != SEG_FS)
4046       continue;
4047     if (!IS(opr_name(&ops[i], 0), "0"))
4048       continue;
4049
4050     ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4051     if (ops[i].operand[1].reg == xSP) {
4052       for (j = i - 1; j >= 0; j--) {
4053         if (ops[j].op != OP_PUSH)
4054           continue;
4055         ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4056         g_seh_size += 4;
4057         if (ops[j].operand[0].val == ~0)
4058           break;
4059         if (ops[j].operand[0].type == OPT_REG) {
4060           k = -1;
4061           ret = resolve_origin(j, &ops[j].operand[0],
4062                   j + opcnt * 22, &k, NULL);
4063           if (ret == 1)
4064             ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4065         }
4066       }
4067       if (j < 0)
4068         ferr(ops, "missing seh terminator\n");
4069     }
4070     else {
4071       k = -1;
4072       ret = resolve_origin(i, &ops[i].operand[1],
4073               i + opcnt * 23, &k, NULL);
4074       if (ret == 1)
4075         ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4076     }
4077   }
4078
4079   eliminate_seh_writes(opcnt);
4080   eliminate_seh_finally(opcnt);
4081 }
4082
4083 static void eliminate_seh_calls(int opcnt)
4084 {
4085   int epilog_found = 0;
4086   int i;
4087
4088   g_bp_frame = 1;
4089   g_seh_size = 0x10;
4090
4091   i = 0;
4092   ferr_assert(&ops[i], ops[i].op == OP_PUSH
4093                && ops[i].operand[0].type == OPT_CONST);
4094   g_stack_fsz = g_seh_size + ops[i].operand[0].val;
4095   ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4096
4097   i++;
4098   ferr_assert(&ops[i], ops[i].op == OP_PUSH
4099                && ops[i].operand[0].type == OPT_OFFSET);
4100   ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4101
4102   i++;
4103   ferr_assert(&ops[i], ops[i].op == OP_CALL
4104                && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
4105   ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4106
4107   for (i++; i < opcnt; i++) {
4108     if (ops[i].op != OP_CALL)
4109       continue;
4110     if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
4111       continue;
4112
4113     ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4114     epilog_found = 1;
4115   }
4116   ferr_assert(ops, epilog_found);
4117
4118   eliminate_seh_writes(opcnt);
4119   eliminate_seh_finally(opcnt);
4120 }
4121
4122 static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4123 {
4124   int j;
4125
4126   for (; i < opcnt; i++)
4127     if (!(ops[i].flags & OPF_DONE))
4128       break;
4129
4130   while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4131     ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4132     g_stack_fsz += 4;
4133     (*ecx_push)++;
4134     i++;
4135   }
4136
4137   for (; i < opcnt; i++) {
4138     if (i > 0 && g_labels[i] != NULL)
4139       break;
4140     if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
4141       break;
4142     if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4143       && ops[i].operand[1].type == OPT_CONST)
4144     {
4145       g_stack_fsz += opr_const(&ops[i], 1);
4146       ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4147       i++;
4148       *esp_sub = 1;
4149       break;
4150     }
4151     if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4152         && ops[i].operand[1].type == OPT_CONST)
4153     {
4154       for (j = i + 1; j < opcnt; j++)
4155         if (!(ops[j].flags & OPF_DONE))
4156           break;
4157       if (ops[j].op == OP_CALL
4158         && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4159       {
4160         g_stack_fsz += opr_const(&ops[i], 1);
4161         ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4162         ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4163         i = j + 1;
4164         *esp_sub = 1;
4165       }
4166       break;
4167     }
4168   }
4169
4170   return i;
4171 }
4172
4173 static void scan_prologue_epilogue(int opcnt, int *stack_align)
4174 {
4175   int ecx_push = 0, esp_sub = 0, pusha = 0;
4176   int sandard_epilogue;
4177   int found;
4178   int i, j, l;
4179
4180   if (g_seh_found == 2) {
4181     eliminate_seh_calls(opcnt);
4182     return;
4183   }
4184   if (g_seh_found) {
4185     eliminate_seh(opcnt);
4186     // ida treats seh as part of sf
4187     g_stack_fsz = g_seh_size;
4188     esp_sub = 1;
4189   }
4190
4191   if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4192       && ops[1].op == OP_MOV
4193       && IS(opr_name(&ops[1], 0), "ebp")
4194       && IS(opr_name(&ops[1], 1), "esp"))
4195   {
4196     g_bp_frame = 1;
4197     ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4198     ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4199
4200     for (i = 2; i < opcnt; i++)
4201       if (!(ops[i].flags & OPF_DONE))
4202         break;
4203
4204     if (ops[i].op == OP_PUSHA) {
4205       ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4206       pusha = 1;
4207       i++;
4208     }
4209
4210     if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4211         && ops[i].operand[1].type == OPT_CONST)
4212     {
4213       l = ops[i].operand[1].val;
4214       j = ffs(l) - 1;
4215       if (j == -1 || (l >> j) != -1)
4216         ferr(&ops[i], "unhandled esp align: %x\n", l);
4217       if (stack_align != NULL)
4218         *stack_align = 1 << j;
4219       ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4220       i++;
4221     }
4222
4223     i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4224
4225     found = 0;
4226     do {
4227       for (; i < opcnt; i++)
4228         if (ops[i].flags & OPF_TAIL)
4229           break;
4230       j = i - 1;
4231       if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4232         if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4233           break;
4234         i--;
4235         j--;
4236       }
4237
4238       sandard_epilogue = 0;
4239       if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4240       {
4241         ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4242         // the standard epilogue is sometimes even used without a sf
4243         if (ops[j - 1].op == OP_MOV
4244             && IS(opr_name(&ops[j - 1], 0), "esp")
4245             && IS(opr_name(&ops[j - 1], 1), "ebp"))
4246           sandard_epilogue = 1;
4247       }
4248       else if (ops[j].op == OP_LEAVE)
4249       {
4250         ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4251         sandard_epilogue = 1;
4252       }
4253       else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4254         && ops[i].pp->is_noreturn)
4255       {
4256         // on noreturn, msvc sometimes cleans stack, sometimes not
4257         i++;
4258         found = 1;
4259         continue;
4260       }
4261       else if (!(g_ida_func_attr & IDAFA_NORETURN))
4262         ferr(&ops[j], "'pop ebp' expected\n");
4263
4264       if (g_stack_fsz != 0 || sandard_epilogue) {
4265         if (ops[j].op == OP_LEAVE)
4266           j--;
4267         else if (sandard_epilogue) // mov esp, ebp
4268         {
4269           ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4270           j -= 2;
4271         }
4272         else if (!(g_ida_func_attr & IDAFA_NORETURN))
4273         {
4274           ferr(&ops[j], "esp restore expected\n");
4275         }
4276
4277         if (ecx_push && j >= 0 && ops[j].op == OP_POP
4278           && IS(opr_name(&ops[j], 0), "ecx"))
4279         {
4280           ferr(&ops[j], "unexpected ecx pop\n");
4281         }
4282       }
4283
4284       if (pusha) {
4285         if (ops[j].op == OP_POPA)
4286           ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4287         else
4288           ferr(&ops[j], "popa expected\n");
4289       }
4290
4291       found = 1;
4292       i++;
4293     } while (i < opcnt);
4294
4295     if (!found)
4296       ferr(ops, "missing ebp epilogue\n");
4297     return;
4298   }
4299
4300   // non-bp frame
4301   i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4302
4303   if (ecx_push && !esp_sub) {
4304     // could actually be args for a call..
4305     for (; i < opcnt; i++)
4306       if (ops[i].op != OP_PUSH)
4307         break;
4308
4309     if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4310       const struct parsed_proto *pp;
4311       pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4312       j = pp ? pp->argc_stack : 0;
4313       while (i > 0 && j > 0) {
4314         i--;
4315         if (ops[i].op == OP_PUSH) {
4316           ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4317           j--;
4318         }
4319       }
4320       if (j != 0)
4321         ferr(&ops[i], "unhandled prologue\n");
4322
4323       // recheck
4324       i = ecx_push = 0;
4325       g_stack_fsz = g_seh_size;
4326       while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4327         if (!(ops[i].flags & OPF_RMD))
4328           break;
4329         g_stack_fsz += 4;
4330         ecx_push++;
4331         i++;
4332       }
4333     }
4334   }
4335
4336   found = 0;
4337   if (ecx_push || esp_sub)
4338   {
4339     g_sp_frame = 1;
4340
4341     do {
4342       for (; i < opcnt; i++)
4343         if (ops[i].flags & OPF_TAIL)
4344           break;
4345
4346       j = i - 1;
4347       if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4348         if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4349           break;
4350         i--;
4351         j--;
4352       }
4353       else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4354         // skip arg updates for arg-reuse tailcall
4355         for (; j >= 0; j--) {
4356           if (ops[j].op != OP_MOV)
4357             break;
4358           if (ops[j].operand[0].type != OPT_REGMEM)
4359             break;
4360           if (strstr(ops[j].operand[0].name, "arg_") == NULL)
4361             break;
4362         }
4363       }
4364
4365       if (ecx_push > 0 && !esp_sub) {
4366         for (l = 0; l < ecx_push && j >= 0; l++) {
4367           if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4368             /* pop ecx */;
4369           else if (ops[j].op == OP_ADD
4370                    && IS(opr_name(&ops[j], 0), "esp")
4371                    && ops[j].operand[1].type == OPT_CONST)
4372           {
4373             /* add esp, N */
4374             l += ops[j].operand[1].val / 4 - 1;
4375           }
4376           else
4377             break;
4378
4379           ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4380           j--;
4381         }
4382         if (l != ecx_push) {
4383           if (i < opcnt && ops[i].op == OP_CALL
4384             && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4385           {
4386             // noreturn tailcall with no epilogue
4387             i++;
4388             found = 1;
4389             continue;
4390           }
4391           ferr(&ops[j], "epilogue scan failed\n");
4392         }
4393
4394         found = 1;
4395       }
4396
4397       if (esp_sub) {
4398         if (ops[j].op != OP_ADD
4399             || !IS(opr_name(&ops[j], 0), "esp")
4400             || ops[j].operand[1].type != OPT_CONST)
4401         {
4402           if (i < opcnt && ops[i].op == OP_CALL
4403             && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4404           {
4405             // noreturn tailcall with no epilogue
4406             i++;
4407             found = 1;
4408             continue;
4409           }
4410           ferr(&ops[j], "'add esp' expected\n");
4411         }
4412
4413         if (ops[j].operand[1].val < g_stack_fsz)
4414           ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4415
4416         ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4417         if (ops[j].operand[1].val == 0)
4418           ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4419         found = 1;
4420       }
4421
4422       i++;
4423     } while (i < opcnt);
4424
4425     if (!found)
4426       ferr(ops, "missing esp epilogue\n");
4427   }
4428 }
4429
4430 // find an instruction that changed opr before i op
4431 // *op_i must be set to -1 by the caller
4432 // *is_caller is set to 1 if one source is determined to be g_func arg
4433 // returns 1 if found, *op_i is then set to origin
4434 // returns -1 if multiple origins are found
4435 static int resolve_origin(int i, const struct parsed_opr *opr,
4436   int magic, int *op_i, int *is_caller)
4437 {
4438   struct label_ref *lr;
4439   int ret = 0;
4440
4441   while (1) {
4442     if (g_labels[i] != NULL) {
4443       lr = &g_label_refs[i];
4444       for (; lr != NULL; lr = lr->next) {
4445         check_i(&ops[i], lr->i);
4446         ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4447       }
4448       if (i > 0 && LAST_OP(i - 1))
4449         return ret;
4450     }
4451
4452     i--;
4453     if (i < 0) {
4454       if (is_caller != NULL)
4455         *is_caller = 1;
4456       return -1;
4457     }
4458
4459     if (ops[i].cc_scratch == magic)
4460       return ret;
4461     ops[i].cc_scratch = magic;
4462
4463     if (!(ops[i].flags & OPF_DATA))
4464       continue;
4465     if (!is_opr_modified(opr, &ops[i]))
4466       continue;
4467
4468     if (*op_i >= 0) {
4469       if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4470         return ret | 1;
4471
4472       return -1;
4473     }
4474
4475     *op_i = i;
4476     return ret | 1;
4477   }
4478 }
4479
4480 // find an instruction that previously referenced opr
4481 // if multiple results are found - fail
4482 // *op_i must be set to -1 by the caller
4483 // returns 1 if found, *op_i is then set to referencer insn
4484 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4485   int magic, int *op_i)
4486 {
4487   struct label_ref *lr;
4488   int ret = 0;
4489
4490   while (1) {
4491     if (g_labels[i] != NULL) {
4492       lr = &g_label_refs[i];
4493       for (; lr != NULL; lr = lr->next) {
4494         check_i(&ops[i], lr->i);
4495         ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4496       }
4497       if (i > 0 && LAST_OP(i - 1))
4498         return ret;
4499     }
4500
4501     i--;
4502     if (i < 0)
4503       return -1;
4504
4505     if (ops[i].cc_scratch == magic)
4506       return 0;
4507     ops[i].cc_scratch = magic;
4508
4509     if (!is_opr_referenced(opr, &ops[i]))
4510       continue;
4511
4512     if (*op_i >= 0)
4513       return -1;
4514
4515     *op_i = i;
4516     return 1;
4517   }
4518 }
4519
4520 // adjust datap of all reachable 'op' insns when moving back
4521 // returns  1 if at least 1 op was found
4522 // returns -1 if path without an op was found
4523 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4524 {
4525   struct label_ref *lr;
4526   int ret = 0;
4527
4528   if (ops[i].cc_scratch == magic)
4529     return 0;
4530   ops[i].cc_scratch = magic;
4531
4532   while (1) {
4533     if (g_labels[i] != NULL) {
4534       lr = &g_label_refs[i];
4535       for (; lr != NULL; lr = lr->next) {
4536         check_i(&ops[i], lr->i);
4537         ret |= adjust_prev_op(lr->i, op, magic, datap);
4538       }
4539       if (i > 0 && LAST_OP(i - 1))
4540         return ret;
4541     }
4542
4543     i--;
4544     if (i < 0)
4545       return -1;
4546
4547     if (ops[i].cc_scratch == magic)
4548       return 0;
4549     ops[i].cc_scratch = magic;
4550
4551     if (ops[i].op != op)
4552       continue;
4553
4554     ops[i].datap = datap;
4555     return 1;
4556   }
4557 }
4558
4559 // find next instruction that reads opr
4560 // *op_i must be set to -1 by the caller
4561 // on return, *op_i is set to first referencer insn
4562 // returns 1 if exactly 1 referencer is found
4563 static int find_next_read(int i, int opcnt,
4564   const struct parsed_opr *opr, int magic, int *op_i)
4565 {
4566   struct parsed_op *po;
4567   int j, ret = 0;
4568
4569   for (; i < opcnt; i++)
4570   {
4571     if (ops[i].cc_scratch == magic)
4572       return ret;
4573     ops[i].cc_scratch = magic;
4574
4575     po = &ops[i];
4576     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4577       if (po->btj != NULL) {
4578         // jumptable
4579         for (j = 0; j < po->btj->count; j++) {
4580           check_i(po, po->btj->d[j].bt_i);
4581           ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4582                    magic, op_i);
4583         }
4584         return ret;
4585       }
4586
4587       if (po->flags & OPF_RMD)
4588         continue;
4589       check_i(po, po->bt_i);
4590       if (po->flags & OPF_CJMP) {
4591         ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4592         if (ret < 0)
4593           return ret;
4594       }
4595       else
4596         i = po->bt_i - 1;
4597       continue;
4598     }
4599
4600     if (!is_opr_read(opr, po)) {
4601       int full_opr = 1;
4602       if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4603           && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4604       {
4605         full_opr = po->operand[0].lmod >= opr->lmod;
4606       }
4607       if (is_opr_modified(opr, po) && full_opr) {
4608         // it's overwritten
4609         return ret;
4610       }
4611       if (po->flags & OPF_TAIL)
4612         return ret;
4613       continue;
4614     }
4615
4616     if (*op_i >= 0)
4617       return -1;
4618
4619     *op_i = i;
4620     return 1;
4621   }
4622
4623   return 0;
4624 }
4625
4626 // find next instruction that reads opr
4627 // *op_i must be set to -1 by the caller
4628 // on return, *op_i is set to first flag user insn
4629 // returns 1 if exactly 1 flag user is found
4630 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4631 {
4632   struct parsed_op *po;
4633   int j, ret = 0;
4634
4635   for (; i < opcnt; i++)
4636   {
4637     if (ops[i].cc_scratch == magic)
4638       return ret;
4639     ops[i].cc_scratch = magic;
4640
4641     po = &ops[i];
4642     if (po->op == OP_CALL)
4643       return -1;
4644     if (po->flags & OPF_JMP) {
4645       if (po->btj != NULL) {
4646         // jumptable
4647         for (j = 0; j < po->btj->count; j++) {
4648           check_i(po, po->btj->d[j].bt_i);
4649           ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4650                    magic, op_i);
4651         }
4652         return ret;
4653       }
4654
4655       if (po->flags & OPF_RMD)
4656         continue;
4657       check_i(po, po->bt_i);
4658       if (po->flags & OPF_CJMP)
4659         goto found;
4660       else
4661         i = po->bt_i - 1;
4662       continue;
4663     }
4664
4665     if (!(po->flags & OPF_CC)) {
4666       if (po->flags & OPF_FLAGS)
4667         // flags changed
4668         return ret;
4669       if (po->flags & OPF_TAIL)
4670         return ret;
4671       continue;
4672     }
4673
4674 found:
4675     if (*op_i >= 0)
4676       return -1;
4677
4678     *op_i = i;
4679     return 1;
4680   }
4681
4682   return 0;
4683 }
4684
4685 static int try_resolve_const(int i, const struct parsed_opr *opr,
4686   int magic, unsigned int *val)
4687 {
4688   int s_i = -1;
4689   int ret;
4690
4691   ret = resolve_origin(i, opr, magic, &s_i, NULL);
4692   if (ret == 1) {
4693     i = s_i;
4694     if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4695       return -1;
4696
4697     *val = ops[i].operand[1].val;
4698     return 1;
4699   }
4700
4701   return -1;
4702 }
4703
4704 static int resolve_used_bits(int i, int opcnt, int reg,
4705   int *mask, int *is_z_check)
4706 {
4707   struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4708   int j = -1, k = -1;
4709   int ret;
4710
4711   ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4712   if (ret != 1)
4713     return -1;
4714
4715   find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4716   if (k != -1) {
4717     fnote(&ops[j], "(first read)\n");
4718     ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4719   }
4720
4721   if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4722     ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4723
4724   ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4725   ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4726
4727   *mask = ops[j].operand[1].val;
4728   if (ops[j].operand[0].lmod == OPLM_BYTE
4729     && ops[j].operand[0].name[1] == 'h')
4730   {
4731     *mask <<= 8;
4732   }
4733   ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4734
4735   *is_z_check = 0;
4736   ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4737   if (ret == 1)
4738     *is_z_check = ops[k].pfo == PFO_Z;
4739
4740   return 0;
4741 }
4742
4743 static const struct parsed_proto *resolve_deref(int i, int magic,
4744   struct parsed_opr *opr, int level)
4745 {
4746   struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4747   const struct parsed_proto *pp = NULL;
4748   int from_caller = 0;
4749   char s_reg[4];
4750   int offset = 0;
4751   int len = 0;
4752   int j = -1;
4753   int k = -1;
4754   int reg;
4755   int ret;
4756
4757   ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4758   if (ret != 2 || len != strlen(opr->name)) {
4759     ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4760     if (ret != 1 || len != strlen(opr->name))
4761       return NULL;
4762   }
4763
4764   reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4765   if (reg < 0)
4766     return NULL;
4767
4768   opr_s.reg = reg;
4769   ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4770   if (ret != 1)
4771     return NULL;
4772
4773   if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4774     && strlen(ops[j].operand[1].name) == 3
4775     && ops[j].operand[0].lmod == OPLM_DWORD
4776     && ops[j].pp == NULL // no hint
4777     && level == 0)
4778   {
4779     // allow one simple dereference (com/directx)
4780     reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4781             ops[j].operand[1].name);
4782     if (reg < 0)
4783       return NULL;
4784     opr_s.reg = reg;
4785     ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4786     if (ret != 1)
4787       return NULL;
4788     j = k;
4789   }
4790   if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4791     return NULL;
4792
4793   if (ops[j].pp != NULL) {
4794     // type hint in asm
4795     pp = ops[j].pp;
4796   }
4797   else if (ops[j].operand[1].type == OPT_REGMEM) {
4798     pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4799     if (pp == NULL) {
4800       // maybe structure ptr in structure
4801       pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4802     }
4803   }
4804   else if (ops[j].operand[1].type == OPT_LABEL)
4805     pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4806   else if (ops[j].operand[1].type == OPT_REG) {
4807     // maybe arg reg?
4808     k = -1;
4809     ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4810             &k, &from_caller);
4811     if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4812       for (k = 0; k < g_func_pp->argc; k++) {
4813         if (g_func_pp->arg[k].reg == NULL)
4814           continue;
4815         if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4816           pp = g_func_pp->arg[k].pp;
4817           break;
4818         }
4819       }
4820     }
4821   }
4822
4823   if (pp == NULL)
4824     return NULL;
4825   if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4826     if (offset != 0)
4827       ferr(&ops[j], "expected struct, got '%s %s'\n",
4828            pp->type.name, pp->name);
4829     return NULL;
4830   }
4831
4832   return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4833 }
4834
4835 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4836   int *pp_i, int *multi_src)
4837 {
4838   const struct parsed_proto *pp = NULL;
4839   int search_advice = 0;
4840
4841   *multi_src = 0;
4842   *pp_i = -1;
4843
4844   switch (ops[i].operand[0].type) {
4845   case OPT_REGMEM:
4846     // try to resolve struct member calls
4847     pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4848     if (pp != NULL)
4849       break;
4850     // fallthrough
4851   case OPT_LABEL:
4852   case OPT_OFFSET:
4853     pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4854            1, &search_advice);
4855     if (!search_advice)
4856       break;
4857     // fallthrough
4858   default:
4859     scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4860       pp_i, multi_src);
4861     break;
4862   }
4863
4864   return pp;
4865 }
4866
4867 static struct parsed_proto *process_call_early(int i, int opcnt,
4868   int *adj_i)
4869 {
4870   struct parsed_op *po = &ops[i];
4871   struct parsed_proto *pp;
4872   int multipath = 0;
4873   int adj = 0;
4874   int j, ret;
4875
4876   pp = po->pp;
4877   if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4878     // leave for later
4879     return NULL;
4880
4881   // look for and make use of esp adjust
4882   *adj_i = ret = -1;
4883   if (!pp->is_stdcall && pp->argc_stack > 0)
4884     ret = scan_for_esp_adjust(i + 1, opcnt,
4885             pp->argc_stack * 4, &adj, &multipath, 0);
4886   if (ret >= 0) {
4887     if (pp->argc_stack > adj / 4)
4888       return NULL;
4889     if (multipath)
4890       return NULL;
4891     if (ops[ret].op == OP_POP) {
4892       for (j = 1; j < adj / 4; j++) {
4893         if (ops[ret + j].op != OP_POP
4894           || ops[ret + j].operand[0].reg != xCX)
4895         {
4896           return NULL;
4897         }
4898       }
4899     }
4900   }
4901
4902   *adj_i = ret;
4903   return pp;
4904 }
4905
4906 static struct parsed_proto *process_call(int i, int opcnt)
4907 {
4908   struct parsed_op *po = &ops[i];
4909   const struct parsed_proto *pp_c;
4910   struct parsed_proto *pp;
4911   const char *tmpname;
4912   int call_i = -1, ref_i = -1;
4913   int adj = 0, multipath = 0;
4914   int ret, arg;
4915
4916   tmpname = opr_name(po, 0);
4917   pp = po->pp;
4918   if (pp == NULL)
4919   {
4920     // indirect call
4921     pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4922     if (pp_c != NULL) {
4923       if (!pp_c->is_func && !pp_c->is_fptr)
4924         ferr(po, "call to non-func: %s\n", pp_c->name);
4925       pp = proto_clone(pp_c);
4926       my_assert_not(pp, NULL);
4927       if (multipath)
4928         // not resolved just to single func
4929         pp->is_fptr = 1;
4930
4931       switch (po->operand[0].type) {
4932       case OPT_REG:
4933         // we resolved this call and no longer need the register
4934         po->regmask_src &= ~(1 << po->operand[0].reg);
4935
4936         if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4937           && ops[call_i].operand[1].type == OPT_LABEL)
4938         {
4939           // no other source users?
4940           ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4941                   &ref_i);
4942           if (ret == 1 && call_i == ref_i) {
4943             // and nothing uses it after us?
4944             ref_i = -1;
4945             find_next_read(i + 1, opcnt, &po->operand[0],
4946               i + opcnt * 11, &ref_i);
4947             if (ref_i == -1)
4948               // then also don't need the source mov
4949               ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4950           }
4951         }
4952         break;
4953       case OPT_REGMEM:
4954         pp->is_fptr = 1;
4955         break;
4956       default:
4957         break;
4958       }
4959     }
4960     if (pp == NULL) {
4961       pp = calloc(1, sizeof(*pp));
4962       my_assert_not(pp, NULL);
4963
4964       pp->is_fptr = 1;
4965       ret = scan_for_esp_adjust(i + 1, opcnt,
4966               -1, &adj, &multipath, 0);
4967       if (ret < 0 || adj < 0) {
4968         if (!g_allow_regfunc)
4969           ferr(po, "non-__cdecl indirect call unhandled yet\n");
4970         pp->is_unresolved = 1;
4971         adj = 0;
4972       }
4973       adj /= 4;
4974       if (adj > ARRAY_SIZE(pp->arg))
4975         ferr(po, "esp adjust too large: %d\n", adj);
4976       pp->ret_type.name = strdup("int");
4977       pp->argc = pp->argc_stack = adj;
4978       for (arg = 0; arg < pp->argc; arg++)
4979         pp->arg[arg].type.name = strdup("int");
4980     }
4981     po->pp = pp;
4982   }
4983
4984   // look for and make use of esp adjust
4985   multipath = 0;
4986   ret = -1;
4987   if (!pp->is_stdcall && pp->argc_stack > 0) {
4988     int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4989     ret = scan_for_esp_adjust(i + 1, opcnt,
4990             adj_expect, &adj, &multipath, 0);
4991   }
4992   if (ret >= 0) {
4993     if (pp->is_vararg) {
4994       if (adj / 4 < pp->argc_stack) {
4995         fnote(po, "(this call)\n");
4996         ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4997           adj, pp->argc_stack * 4);
4998       }
4999       // modify pp to make it have varargs as normal args
5000       arg = pp->argc;
5001       pp->argc += adj / 4 - pp->argc_stack;
5002       for (; arg < pp->argc; arg++) {
5003         pp->arg[arg].type.name = strdup("int");
5004         pp->argc_stack++;
5005       }
5006       if (pp->argc > ARRAY_SIZE(pp->arg))
5007         ferr(po, "too many args for '%s'\n", tmpname);
5008     }
5009     if (pp->argc_stack > adj / 4) {
5010       if (pp->is_noreturn)
5011         // assume no stack adjust was emited
5012         goto out;
5013       fnote(po, "(this call)\n");
5014       ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
5015         tmpname, pp->argc_stack * 4, adj);
5016     }
5017
5018     scan_for_esp_adjust(i + 1, opcnt,
5019       pp->argc_stack * 4, &adj, &multipath, 1);
5020   }
5021   else if (pp->is_vararg)
5022     ferr(po, "missing esp_adjust for vararg func '%s'\n",
5023       pp->name);
5024
5025 out:
5026   return pp;
5027 }
5028
5029 static void mark_float_arg(struct parsed_op *po,
5030   struct parsed_proto *pp, int arg, int *regmask_ffca)
5031 {
5032   po->p_argnext = -1;
5033   po->p_argnum = arg + 1;
5034   ferr_assert(po, pp->arg[arg].datap == NULL);
5035   pp->arg[arg].datap = po;
5036   po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
5037   if (regmask_ffca != NULL)
5038     *regmask_ffca |= 1 << arg;
5039 }
5040
5041 static int check_for_stp(int i, int i_to)
5042 {
5043   struct parsed_op *po;
5044
5045   for (; i < i_to; i++) {
5046     po = &ops[i];
5047     if (po->op == OP_FST)
5048       return i;
5049     if (g_labels[i] != NULL || (po->flags & OPF_JMP))
5050       return -1;
5051     if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
5052       return -1;
5053     if (po->op == OP_ADD && po->operand[0].reg == xSP)
5054       return -1;
5055   }
5056
5057   return -1;
5058 }
5059
5060 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
5061   int *regmask_ffca)
5062 {
5063   struct parsed_op *po;
5064   int offset = 0;
5065   int base_arg;
5066   int j, arg;
5067   int ret;
5068
5069   for (base_arg = 0; base_arg < pp->argc; base_arg++)
5070     if (pp->arg[base_arg].reg == NULL)
5071       break;
5072
5073   for (j = i; j > 0; )
5074   {
5075     ferr_assert(&ops[j], g_labels[j] == NULL);
5076     j--;
5077
5078     po = &ops[j];
5079     ferr_assert(po, po->op != OP_PUSH);
5080     if (po->op == OP_FST)
5081     {
5082       if (po->operand[0].type != OPT_REGMEM)
5083         continue;
5084       ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
5085       if (ret != 0)
5086         continue;
5087       if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
5088         //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
5089         continue;
5090       }
5091
5092       arg = base_arg + offset / 4;
5093       mark_float_arg(po, pp, arg, regmask_ffca);
5094     }
5095     else if (po->op == OP_SUB && po->operand[0].reg == xSP
5096       && po->operand[1].type == OPT_CONST)
5097     {
5098       po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5099       break;
5100     }
5101   }
5102
5103   for (arg = base_arg; arg < pp->argc; arg++) {
5104     ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
5105     po = pp->arg[arg].datap;
5106     if (po == NULL)
5107       ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
5108     if (po->operand[0].lmod == OPLM_QWORD)
5109       arg++;
5110   }
5111
5112   return 0;
5113 }
5114
5115 static int collect_call_args_early(int i, struct parsed_proto *pp,
5116   int *regmask, int *regmask_ffca)
5117 {
5118   struct parsed_op *po;
5119   int arg, ret;
5120   int offset;
5121   int j, k;
5122
5123   for (arg = 0; arg < pp->argc; arg++)
5124     if (pp->arg[arg].reg == NULL)
5125       break;
5126
5127   // first see if it can be easily done
5128   for (j = i; j > 0 && arg < pp->argc; )
5129   {
5130     if (g_labels[j] != NULL)
5131       return -1;
5132     j--;
5133
5134     po = &ops[j];
5135     if (po->op == OP_CALL)
5136       return -1;
5137     else if (po->op == OP_ADD && po->operand[0].reg == xSP)
5138       return -1;
5139     else if (po->op == OP_POP)
5140       return -1;
5141     else if (po->flags & OPF_CJMP)
5142       return -1;
5143     else if (po->op == OP_PUSH) {
5144       if (po->flags & (OPF_FARG|OPF_FARGNR))
5145         return -1;
5146       if (!g_header_mode) {
5147         ret = scan_for_mod(po, j + 1, i, 1);
5148         if (ret >= 0)
5149           return -1;
5150       }
5151
5152       if (pp->arg[arg].type.is_va_list)
5153         return -1;
5154
5155       // next arg
5156       for (arg++; arg < pp->argc; arg++)
5157         if (pp->arg[arg].reg == NULL)
5158           break;
5159     }
5160     else if (po->op == OP_SUB && po->operand[0].reg == xSP
5161       && po->operand[1].type == OPT_CONST)
5162     {
5163       if (po->flags & (OPF_RMD|OPF_DONE))
5164         return -1;
5165       if (po->operand[1].val != pp->argc_stack * 4)
5166         ferr(po, "unexpected esp adjust: %d\n",
5167              po->operand[1].val * 4);
5168       ferr_assert(po, pp->argc - arg == pp->argc_stack);
5169       return collect_call_args_no_push(i, pp, regmask_ffca);
5170     }
5171   }
5172
5173   if (arg < pp->argc)
5174     return -1;
5175
5176   // now do it
5177   for (arg = 0; arg < pp->argc; arg++)
5178     if (pp->arg[arg].reg == NULL)
5179       break;
5180
5181   for (j = i; j > 0 && arg < pp->argc; )
5182   {
5183     j--;
5184
5185     if (ops[j].op == OP_PUSH)
5186     {
5187       ops[j].p_argnext = -1;
5188       ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
5189
5190       k = check_for_stp(j + 1, i);
5191       if (k != -1) {
5192         // push ecx; fstp dword ptr [esp]
5193         ret = parse_stack_esp_offset(&ops[k],
5194                 ops[k].operand[0].name, &offset);
5195         if (ret == 0 && offset == 0) {
5196           if (!pp->arg[arg].type.is_float)
5197             ferr(&ops[i], "arg %d should be float\n", arg + 1);
5198           mark_float_arg(&ops[k], pp, arg, regmask_ffca);
5199         }
5200       }
5201
5202       if (pp->arg[arg].datap == NULL) {
5203         pp->arg[arg].datap = &ops[j];
5204         if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5205           *regmask |= 1 << ops[j].operand[0].reg;
5206       }
5207
5208       ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5209       ops[j].flags &= ~OPF_RSAVE;
5210
5211       // next arg
5212       for (arg++; arg < pp->argc; arg++)
5213         if (pp->arg[arg].reg == NULL)
5214           break;
5215     }
5216   }
5217
5218   return 0;
5219 }
5220
5221 static int sync_argnum(struct parsed_op *po, int argnum)
5222 {
5223   struct parsed_op *po_tmp;
5224
5225   // see if other branches don't have higher argnum
5226   for (po_tmp = po; po_tmp != NULL; ) {
5227     if (argnum < po_tmp->p_argnum)
5228       argnum = po_tmp->p_argnum;
5229     // note: p_argnext is active on current collect_call_args only
5230     po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5231   }
5232
5233   // make all argnums consistent
5234   for (po_tmp = po; po_tmp != NULL; ) {
5235     if (po_tmp->p_argnum != 0)
5236       po_tmp->p_argnum = argnum;
5237     po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5238   }
5239
5240   return argnum;
5241 }
5242
5243 static int collect_call_args_r(struct parsed_op *po, int i,
5244   struct parsed_proto *pp, int *regmask, int *arg_grp,
5245   int arg, int argnum, int magic, int need_op_saving, int may_reuse)
5246 {
5247   struct parsed_proto *pp_tmp;
5248   struct parsed_op *po_tmp;
5249   struct label_ref *lr;
5250   int need_to_save_current;
5251   int arg_grp_current = 0;
5252   int save_args_seen = 0;
5253   int ret = 0;
5254   int reg;
5255   char buf[32];
5256   int j, k;
5257
5258   if (i < 0) {
5259     ferr(po, "dead label encountered\n");
5260     return -1;
5261   }
5262
5263   for (; arg < pp->argc; arg++, argnum++)
5264     if (pp->arg[arg].reg == NULL)
5265       break;
5266   magic = (magic & 0xffffff) | (arg << 24);
5267
5268   for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5269   {
5270     if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5271       if (ops[j].cc_scratch != magic) {
5272         ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5273            pp->name);
5274         return -1;
5275       }
5276       // ok: have already been here
5277       return 0;
5278     }
5279     ops[j].cc_scratch = magic;
5280
5281     if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5282       lr = &g_label_refs[j];
5283       if (lr->next != NULL)
5284         need_op_saving = 1;
5285       for (; lr->next; lr = lr->next) {
5286         check_i(&ops[j], lr->i);
5287         if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5288           may_reuse = 1;
5289         ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5290                 arg, argnum, magic, need_op_saving, may_reuse);
5291         if (ret < 0)
5292           return ret;
5293       }
5294
5295       check_i(&ops[j], lr->i);
5296       if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5297         may_reuse = 1;
5298       if (j > 0 && LAST_OP(j - 1)) {
5299         // follow last branch in reverse
5300         j = lr->i;
5301         continue;
5302       }
5303       need_op_saving = 1;
5304       ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5305               arg, argnum, magic, need_op_saving, may_reuse);
5306       if (ret < 0)
5307         return ret;
5308     }
5309     j--;
5310
5311     if (ops[j].op == OP_CALL)
5312     {
5313       if (pp->is_unresolved)
5314         break;
5315
5316       pp_tmp = ops[j].pp;
5317       if (pp_tmp == NULL)
5318         ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5319           arg, pp->argc, ops[j].operand[0].name);
5320       if (may_reuse && pp_tmp->argc_stack > 0)
5321         ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5322           arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5323     }
5324     // esp adjust of 0 means we collected it before
5325     else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5326       && (ops[j].operand[1].type != OPT_CONST
5327           || ops[j].operand[1].val != 0))
5328     {
5329       if (pp->is_unresolved)
5330         break;
5331
5332       fnote(po, "(this call)\n");
5333       ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5334         arg, pp->argc, ops[j].operand[1].val);
5335     }
5336     else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5337     {
5338       if (pp->is_unresolved)
5339         break;
5340
5341       fnote(po, "(this call)\n");
5342       ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5343     }
5344     else if (ops[j].flags & OPF_CJMP)
5345     {
5346       if (pp->is_unresolved)
5347         break;
5348
5349       may_reuse = 1;
5350     }
5351     else if (ops[j].op == OP_PUSH
5352       && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5353     {
5354       if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5355         break;
5356
5357       ops[j].p_argnext = -1;
5358       po_tmp = pp->arg[arg].datap;
5359       if (po_tmp != NULL)
5360         ops[j].p_argnext = po_tmp - ops;
5361       pp->arg[arg].datap = &ops[j];
5362
5363       argnum = sync_argnum(&ops[j], argnum);
5364
5365       need_to_save_current = 0;
5366       reg = -1;
5367       if (ops[j].operand[0].type == OPT_REG)
5368         reg = ops[j].operand[0].reg;
5369
5370       if (!need_op_saving) {
5371         ret = scan_for_mod(&ops[j], j + 1, i, 1);
5372         need_to_save_current = (ret >= 0);
5373       }
5374       if (need_op_saving || need_to_save_current) {
5375         // mark this arg as one that needs operand saving
5376         pp->arg[arg].is_saved = 1;
5377
5378         if (save_args_seen & (1 << (argnum - 1))) {
5379           save_args_seen = 0;
5380           arg_grp_current++;
5381           if (arg_grp_current >= MAX_ARG_GRP)
5382             ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5383               argnum, pp->name);
5384         }
5385       }
5386       else if (ops[j].p_argnum == 0)
5387         ops[j].flags |= OPF_RMD;
5388
5389       // some PUSHes are reused by different calls on other branches,
5390       // but that can't happen if we didn't branch, so they
5391       // can be removed from future searches (handles nested calls)
5392       if (!may_reuse)
5393         ops[j].flags |= OPF_FARGNR;
5394
5395       ops[j].flags |= OPF_FARG;
5396       ops[j].flags &= ~OPF_RSAVE;
5397
5398       // check for __VALIST
5399       if (!pp->is_unresolved && g_func_pp != NULL
5400         && pp->arg[arg].type.is_va_list)
5401       {
5402         k = -1;
5403         ret = resolve_origin(j, &ops[j].operand[0],
5404                 magic + 1, &k, NULL);
5405         if (ret == 1 && k >= 0)
5406         {
5407           if (ops[k].op == OP_LEA) {
5408             if (!g_func_pp->is_vararg)
5409               ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5410                    g_func_pp->name);
5411
5412             snprintf(buf, sizeof(buf), "arg_%X",
5413               g_func_pp->argc_stack * 4);
5414             if (strstr(ops[k].operand[1].name, buf)
5415              || strstr(ops[k].operand[1].name, "arglist"))
5416             {
5417               ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5418               ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5419               pp->arg[arg].is_saved = 0;
5420               reg = -1;
5421             }
5422             else
5423               ferr(&ops[k], "va_list arg detection failed\n");
5424           }
5425           // check for va_list from g_func_pp arg too
5426           else if (ops[k].op == OP_MOV
5427             && is_stack_access(&ops[k], &ops[k].operand[1]))
5428           {
5429             ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5430               buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5431             if (ret >= 0) {
5432               ops[k].flags |= OPF_RMD | OPF_DONE;
5433               ops[j].flags |= OPF_RMD;
5434               ops[j].p_argpass = ret + 1;
5435               pp->arg[arg].is_saved = 0;
5436               reg = -1;
5437             }
5438           }
5439         }
5440       }
5441
5442       if (pp->arg[arg].is_saved) {
5443         ops[j].flags &= ~OPF_RMD;
5444         ops[j].p_argnum = argnum;
5445       }
5446
5447       // tracking reg usage
5448       if (reg >= 0)
5449         *regmask |= 1 << reg;
5450
5451       arg++;
5452       argnum++;
5453       if (!pp->is_unresolved) {
5454         // next arg
5455         for (; arg < pp->argc; arg++, argnum++)
5456           if (pp->arg[arg].reg == NULL)
5457             break;
5458       }
5459       magic = (magic & 0xffffff) | (arg << 24);
5460     }
5461
5462     if (ops[j].p_arggrp > arg_grp_current) {
5463       save_args_seen = 0;
5464       arg_grp_current = ops[j].p_arggrp;
5465     }
5466     if (ops[j].p_argnum > 0)
5467       save_args_seen |= 1 << (ops[j].p_argnum - 1);
5468   }
5469
5470   if (arg < pp->argc) {
5471     ferr(po, "arg collect failed for '%s': %d/%d\n",
5472       pp->name, arg, pp->argc);
5473     return -1;
5474   }
5475
5476   if (arg_grp_current > *arg_grp)
5477     *arg_grp = arg_grp_current;
5478
5479   return arg;
5480 }
5481
5482 static int collect_call_args(struct parsed_op *po, int i,
5483   struct parsed_proto *pp, int *regmask, int magic)
5484 {
5485   // arg group is for cases when pushes for
5486   // multiple funcs are going on
5487   struct parsed_op *po_tmp;
5488   int arg_grp = 0;
5489   int ret;
5490   int a;
5491
5492   ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5493           0, 1, magic, 0, 0);
5494   if (ret < 0)
5495     return ret;
5496
5497   if (arg_grp != 0) {
5498     // propagate arg_grp
5499     for (a = 0; a < pp->argc; a++) {
5500       if (pp->arg[a].reg != NULL)
5501         continue;
5502
5503       po_tmp = pp->arg[a].datap;
5504       while (po_tmp != NULL) {
5505         po_tmp->p_arggrp = arg_grp;
5506         po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5507       }
5508     }
5509   }
5510
5511   if (pp->is_unresolved) {
5512     pp->argc += ret;
5513     pp->argc_stack += ret;
5514     for (a = 0; a < pp->argc; a++)
5515       if (pp->arg[a].type.name == NULL)
5516         pp->arg[a].type.name = strdup("int");
5517   }
5518
5519   return ret;
5520 }
5521
5522 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5523   int regmask_now, int *regmask,
5524   int regmask_save_now, int *regmask_save,
5525   int *regmask_init, int regmask_arg)
5526 {
5527   struct parsed_op *po;
5528   int already_saved;
5529   int regmask_new;
5530   int regmask_op;
5531   int flags_set;
5532   int ret, reg;
5533   int j;
5534
5535   for (; i < opcnt; i++)
5536   {
5537     po = &ops[i];
5538     if (cbits[i >> 3] & (1 << (i & 7)))
5539       return;
5540     cbits[i >> 3] |= (1 << (i & 7));
5541
5542     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5543       if (po->flags & (OPF_RMD|OPF_DONE))
5544         continue;
5545       if (po->btj != NULL) {
5546         for (j = 0; j < po->btj->count; j++) {
5547           check_i(po, po->btj->d[j].bt_i);
5548           reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5549             regmask_now, regmask, regmask_save_now, regmask_save,
5550             regmask_init, regmask_arg);
5551         }
5552         return;
5553       }
5554
5555       check_i(po, po->bt_i);
5556       if (po->flags & OPF_CJMP)
5557         reg_use_pass(po->bt_i, opcnt, cbits,
5558           regmask_now, regmask, regmask_save_now, regmask_save,
5559           regmask_init, regmask_arg);
5560       else
5561         i = po->bt_i - 1;
5562       continue;
5563     }
5564
5565     if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5566       && !g_func_pp->is_userstack
5567       && po->operand[0].type == OPT_REG)
5568     {
5569       reg = po->operand[0].reg;
5570       ferr_assert(po, reg >= 0);
5571
5572       already_saved = 0;
5573       flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5574       if (regmask_now & (1 << reg)) {
5575         already_saved = regmask_save_now & (1 << reg);
5576         flags_set = OPF_RSAVE | OPF_DONE;
5577       }
5578
5579       ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5580       if (ret == 1) {
5581         scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5582           reg, 0, 0, flags_set);
5583       }
5584       else {
5585         ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5586         if (ret == 1) {
5587           scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5588             flags_set);
5589         }
5590       }
5591       if (ret == 1) {
5592         ferr_assert(po, !already_saved);
5593         po->flags |= flags_set;
5594
5595         if (regmask_now & (1 << reg)) {
5596           regmask_save_now |= (1 << reg);
5597           *regmask_save |= regmask_save_now;
5598         }
5599         continue;
5600       }
5601     }
5602     else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5603       reg = po->operand[0].reg;
5604       ferr_assert(po, reg >= 0);
5605
5606       if (regmask_save_now & (1 << reg))
5607         regmask_save_now &= ~(1 << reg);
5608       else
5609         regmask_now &= ~(1 << reg);
5610       continue;
5611     }
5612     else if (po->op == OP_CALL) {
5613       if ((po->regmask_dst & (1 << xAX))
5614         && !(po->regmask_dst & (1 << xDX)))
5615       {
5616         if (po->flags & OPF_TAIL)
5617           // don't need eax, will do "return f();" or "f(); return;"
5618           po->regmask_dst &= ~(1 << xAX);
5619         else {
5620           struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5621           j = -1;
5622           find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5623           if (j == -1)
5624             // not used
5625             po->regmask_dst &= ~(1 << xAX);
5626         }
5627       }
5628
5629       // not "full stack" mode and have something in stack
5630       if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5631         ferr(po, "float stack is not empty on func call\n");
5632     }
5633
5634     if (po->flags & OPF_NOREGS)
5635       continue;
5636
5637     // if incomplete register is used, clear it on init to avoid
5638     // later use of uninitialized upper part in some situations
5639     if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5640         && po->operand[0].lmod != OPLM_DWORD)
5641     {
5642       reg = po->operand[0].reg;
5643       ferr_assert(po, reg >= 0);
5644
5645       if (!(regmask_now & (1 << reg)))
5646         *regmask_init |= 1 << reg;
5647     }
5648
5649     regmask_op = po->regmask_src | po->regmask_dst;
5650
5651     regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5652     regmask_new &= ~(1 << xSP);
5653     if (g_bp_frame && !(po->flags & OPF_EBP_S))
5654       regmask_new &= ~(1 << xBP);
5655
5656     if (regmask_new != 0)
5657       fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5658
5659     if (regmask_op & (1 << xBP)) {
5660       if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5661         if (po->regmask_dst & (1 << xBP))
5662           // compiler decided to drop bp frame and use ebp as scratch
5663           scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5664         else
5665           regmask_op &= ~(1 << xBP);
5666       }
5667     }
5668
5669     if (po->flags & OPF_FPUSH) {
5670       if (regmask_now & mxST1)
5671         regmask_now |= mxSTa; // switch to "full stack" mode
5672       if (regmask_now & mxSTa)
5673         po->flags |= OPF_FSHIFT;
5674       if (!(regmask_now & mxST7_2)) {
5675         regmask_now =
5676           (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5677       }
5678     }
5679
5680     regmask_now |= regmask_op;
5681     *regmask |= regmask_now;
5682
5683     // released regs
5684     if (po->flags & OPF_FPOPP) {
5685       if ((regmask_now & mxSTa) == 0)
5686         ferr(po, "float pop on empty stack?\n");
5687       if (regmask_now & mxST7_2)
5688         po->flags |= OPF_FSHIFT;
5689       if (!(regmask_now & mxST7_2))
5690         regmask_now &= ~mxST1_0;
5691     }
5692     else if (po->flags & OPF_FPOP) {
5693       if ((regmask_now & mxSTa) == 0)
5694         ferr(po, "float pop on empty stack?\n");
5695       if (regmask_now & (mxST7_2 | mxST1))
5696         po->flags |= OPF_FSHIFT;
5697       if (!(regmask_now & mxST7_2)) {
5698         regmask_now =
5699           (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5700       }
5701     }
5702
5703     if (po->flags & OPF_TAIL) {
5704       if (!(regmask_now & mxST7_2)) {
5705         if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5706           if (!(regmask_now & mxST0))
5707             ferr(po, "no st0 on float return, mask: %x\n",
5708                  regmask_now);
5709         }
5710         else if (regmask_now & mxST1_0)
5711           ferr(po, "float regs on tail: %x\n", regmask_now);
5712       }
5713
5714       // there is support for "conditional tailcall", sort of
5715       if (!(po->flags & OPF_CC))
5716         return;
5717     }
5718   }
5719 }
5720
5721 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5722 {
5723   int i;
5724
5725   for (i = 0; i < pp->argc; i++)
5726     if (pp->arg[i].reg == NULL)
5727       break;
5728
5729   if (pp->argc_stack)
5730     memmove(&pp->arg[i + 1], &pp->arg[i],
5731       sizeof(pp->arg[0]) * pp->argc_stack);
5732   memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5733   pp->arg[i].reg = strdup(reg);
5734   pp->arg[i].type.name = strdup("int");
5735   pp->argc++;
5736   pp->argc_reg++;
5737 }
5738
5739 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5740   int *pfomask, const char *dst_opr_text)
5741 {
5742   if (*pfomask & (1 << PFO_Z)) {
5743     fprintf(fout, "\n  cond_z = (%s%s == 0);",
5744       lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5745     *pfomask &= ~(1 << PFO_Z);
5746   }
5747 }
5748
5749 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5750   int *pfomask, const char *dst_opr_text)
5751 {
5752   if (*pfomask & (1 << PFO_S)) {
5753     fprintf(fout, "\n  cond_s = (%s%s < 0);",
5754       lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5755     *pfomask &= ~(1 << PFO_S);
5756   }
5757 }
5758
5759 static void output_std_flags(FILE *fout, struct parsed_op *po,
5760   int *pfomask, const char *dst_opr_text)
5761 {
5762   output_std_flag_z(fout, po, pfomask, dst_opr_text);
5763   output_std_flag_s(fout, po, pfomask, dst_opr_text);
5764 }
5765
5766 enum {
5767   OPP_FORCE_NORETURN = (1 << 0),
5768   OPP_SIMPLE_ARGS    = (1 << 1),
5769   OPP_ALIGN          = (1 << 2),
5770 };
5771
5772 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5773   int flags)
5774 {
5775   const char *cconv = "";
5776
5777   if (pp->is_fastcall)
5778     cconv = "__fastcall ";
5779   else if (pp->is_stdcall && pp->argc_reg == 0)
5780     cconv = "__stdcall ";
5781
5782   fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5783
5784   if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5785     fprintf(fout, "noreturn ");
5786 }
5787
5788 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5789   int flags)
5790 {
5791   int i;
5792
5793   fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5794     pp->ret_type.name);
5795   if (pp->is_fptr)
5796     fprintf(fout, "(");
5797   output_pp_attrs(fout, pp, flags);
5798   if (pp->is_fptr)
5799     fprintf(fout, "*");
5800   fprintf(fout, "%s", pp->name);
5801   if (pp->is_fptr)
5802     fprintf(fout, ")");
5803
5804   fprintf(fout, "(");
5805   for (i = 0; i < pp->argc; i++) {
5806     if (i > 0)
5807       fprintf(fout, ", ");
5808     if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5809       && !(flags & OPP_SIMPLE_ARGS))
5810     {
5811       // func pointer
5812       output_pp(fout, pp->arg[i].pp, 0);
5813     }
5814     else if (pp->arg[i].type.is_retreg) {
5815       fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5816     }
5817     else {
5818       fprintf(fout, "%s", pp->arg[i].type.name);
5819       if (!pp->is_fptr)
5820         fprintf(fout, " a%d", i + 1);
5821     }
5822
5823     if (pp->arg[i].type.is_64bit)
5824       i++;
5825   }
5826   if (pp->is_vararg) {
5827     if (i > 0)
5828       fprintf(fout, ", ");
5829     fprintf(fout, "...");
5830   }
5831   fprintf(fout, ")");
5832 }
5833
5834 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5835 {
5836   char buf1[16];
5837
5838   buf1[0] = 0;
5839   if (grp > 0)
5840     snprintf(buf1, sizeof(buf1), "%d", grp);
5841   snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5842
5843   return buf;
5844 }
5845
5846 static void gen_x_cleanup(int opcnt);
5847
5848 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5849 {
5850   struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5851   struct parsed_opr *last_arith_dst = NULL;
5852   char buf1[256], buf2[256], buf3[256], cast[64];
5853   struct parsed_proto *pp, *pp_tmp;
5854   struct parsed_data *pd;
5855   int save_arg_vars[MAX_ARG_GRP] = { 0, };
5856   unsigned char cbits[MAX_OPS / 8];
5857   const char *float_type;
5858   const char *float_st0;
5859   const char *float_st1;
5860   int need_float_stack = 0;
5861   int need_float_sw = 0; // status word
5862   int need_tmp_var = 0;
5863   int need_tmp64 = 0;
5864   int cond_vars = 0;
5865   int had_decl = 0;
5866   int label_pending = 0;
5867   int need_double = 0;
5868   int stack_align = 0;
5869   int stack_fsz_adj = 0;
5870   int regmask_save = 0; // used regs saved/restored in this func
5871   int regmask_arg;      // regs from this function args (fastcall, etc)
5872   int regmask_ret;      // regs needed on ret
5873   int regmask_now;      // temp
5874   int regmask_init = 0; // regs that need zero initialization
5875   int regmask_pp = 0;   // regs used in complex push-pop graph
5876   int regmask_ffca = 0; // float function call args
5877   int regmask = 0;      // used regs
5878   int pfomask = 0;
5879   int found = 0;
5880   int dead_dst;
5881   int no_output;
5882   int i, j, l;
5883   int arg;
5884   int reg;
5885   int ret;
5886
5887   g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5888   g_stack_frame_used = 0;
5889   g_seh_size = 0;
5890   if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5891     regmask_init = g_regmask_init;
5892
5893   g_func_pp = proto_parse(fhdr, funcn, 0);
5894   if (g_func_pp == NULL)
5895     ferr(ops, "proto_parse failed for '%s'\n", funcn);
5896
5897   regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5898   regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5899
5900   // pass1:
5901   // - resolve all branches
5902   // - parse calls with labels
5903   resolve_branches_parse_calls(opcnt);
5904
5905   // pass2:
5906   // - handle ebp/esp frame, remove ops related to it
5907   scan_prologue_epilogue(opcnt, &stack_align);
5908
5909   // handle a case where sf size is unalignment, but is
5910   // placed in a way that elements are still aligned
5911   if (g_stack_fsz & 4) {
5912     for (i = 0; i < g_eqcnt; i++) {
5913       if (g_eqs[i].lmod != OPLM_QWORD)
5914         continue;
5915       if (!(g_eqs[i].offset & 4)) {
5916         g_stack_fsz += 4;
5917         stack_fsz_adj = 4;
5918       }
5919       break;
5920     }
5921   }
5922
5923   // pass3:
5924   // - remove dead labels
5925   // - set regs needed at ret
5926   for (i = 0; i < opcnt; i++)
5927   {
5928     if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5929       free(g_labels[i]);
5930       g_labels[i] = NULL;
5931     }
5932
5933     if (ops[i].op == OP_RET)
5934       ops[i].regmask_src |= regmask_ret;
5935   }
5936
5937   // pass4:
5938   // - process trivial calls
5939   for (i = 0; i < opcnt; i++)
5940   {
5941     po = &ops[i];
5942     if (po->flags & (OPF_RMD|OPF_DONE))
5943       continue;
5944
5945     if (po->op == OP_CALL)
5946     {
5947       pp = process_call_early(i, opcnt, &j);
5948       if (pp != NULL) {
5949         if (!(po->flags & OPF_ATAIL)) {
5950           // since we know the args, try to collect them
5951           ret = collect_call_args_early(i, pp, &regmask, &regmask_ffca);
5952           if (ret != 0)
5953             pp = NULL;
5954         }
5955       }
5956
5957       if (pp != NULL) {
5958         if (j >= 0) {
5959           // commit esp adjust
5960           if (ops[j].op != OP_POP)
5961             patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5962           else {
5963             for (l = 0; l < pp->argc_stack; l++)
5964               ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5965           }
5966         }
5967
5968         if (strstr(pp->ret_type.name, "int64"))
5969           need_tmp64 = 1;
5970
5971         po->flags |= OPF_DONE;
5972       }
5973     }
5974   }
5975
5976   // pass5:
5977   // - process calls, stage 2
5978   // - handle some push/pop pairs
5979   // - scan for STD/CLD, propagate DF
5980   // - try to resolve needed x87 status word bits
5981   for (i = 0; i < opcnt; i++)
5982   {
5983     int mask, z_check;
5984
5985     po = &ops[i];
5986     if (po->flags & OPF_RMD)
5987       continue;
5988
5989     if (po->op == OP_CALL)
5990     {
5991       if (!(po->flags & OPF_DONE)) {
5992         pp = process_call(i, opcnt);
5993
5994         if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5995           // since we know the args, collect them
5996           collect_call_args(po, i, pp, &regmask, i + opcnt * 2);
5997         }
5998         // for unresolved, collect after other passes
5999       }
6000
6001       pp = po->pp;
6002       ferr_assert(po, pp != NULL);
6003
6004       po->regmask_src |= get_pp_arg_regmask_src(pp);
6005       po->regmask_dst |= get_pp_arg_regmask_dst(pp);
6006
6007       if (po->regmask_dst & mxST0)
6008         po->flags |= OPF_FPUSH;
6009
6010       if (strstr(pp->ret_type.name, "int64"))
6011         need_tmp64 = 1;
6012
6013       continue;
6014     }
6015
6016     if (po->flags & OPF_DONE)
6017       continue;
6018
6019     switch (po->op) {
6020     case OP_PUSH:
6021       if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
6022         && po->operand[0].type == OPT_CONST)
6023       {
6024         scan_for_pop_const(i, opcnt, i + opcnt * 12);
6025       }
6026       break;
6027
6028     case OP_POP:
6029       scan_pushes_for_pop(i, opcnt, &regmask_pp);
6030       break;
6031
6032     case OP_STD:
6033       po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
6034       scan_propagate_df(i + 1, opcnt);
6035       break;
6036
6037     case OP_FNSTSW:
6038       need_float_sw = 1;
6039       if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
6040         ferr(po, "TODO: fnstsw to mem\n");
6041       ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
6042       if (ret != 0)
6043         ferr(po, "fnstsw resolve failed\n");
6044       ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
6045               (void *)(long)(mask | (z_check << 16)));
6046       if (ret != 1)
6047         ferr(po, "failed to find fcom: %d\n", ret);
6048       break;
6049
6050     default:
6051       break;
6052     }
6053   }
6054
6055   // pass6:
6056   // - find POPs for PUSHes, rm both
6057   // - scan for all used registers
6058   memset(cbits, 0, sizeof(cbits));
6059   reg_use_pass(0, opcnt, cbits, regmask_init, &regmask,
6060     0, &regmask_save, &regmask_init, regmask_arg);
6061
6062   need_float_stack = !!(regmask & mxST7_2);
6063
6064   // pass7:
6065   // - find flag set ops for their users
6066   // - do unresolved calls
6067   // - declare indirect functions
6068   // - other op specific processing
6069   for (i = 0; i < opcnt; i++)
6070   {
6071     po = &ops[i];
6072     if (po->flags & (OPF_RMD|OPF_DONE))
6073       continue;
6074
6075     if (po->flags & OPF_CC)
6076     {
6077       int setters[16], cnt = 0, branched = 0;
6078
6079       ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
6080               &branched, setters, &cnt);
6081       if (ret < 0 || cnt <= 0)
6082         ferr(po, "unable to trace flag setter(s)\n");
6083       if (cnt > ARRAY_SIZE(setters))
6084         ferr(po, "too many flag setters\n");
6085
6086       for (j = 0; j < cnt; j++)
6087       {
6088         tmp_op = &ops[setters[j]]; // flag setter
6089         pfomask = 0;
6090
6091         // to get nicer code, we try to delay test and cmp;
6092         // if we can't because of operand modification, or if we
6093         // have arith op, or branch, make it calculate flags explicitly
6094         if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
6095         {
6096           if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
6097             pfomask = 1 << po->pfo;
6098         }
6099         else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
6100           pfomask = 1 << po->pfo;
6101         }
6102         else {
6103           // see if we'll be able to handle based on op result
6104           if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
6105                && po->pfo != PFO_Z && po->pfo != PFO_S
6106                && po->pfo != PFO_P)
6107               || branched
6108               || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
6109           {
6110             pfomask = 1 << po->pfo;
6111           }
6112
6113           if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
6114             propagate_lmod(tmp_op, &tmp_op->operand[0],
6115               &tmp_op->operand[1]);
6116             if (tmp_op->operand[0].lmod == OPLM_DWORD)
6117               need_tmp64 = 1;
6118           }
6119         }
6120         if (pfomask) {
6121           tmp_op->pfomask |= pfomask;
6122           cond_vars |= pfomask;
6123         }
6124         // note: may overwrite, currently not a problem
6125         po->datap = tmp_op;
6126       }
6127
6128       if (po->op == OP_RCL || po->op == OP_RCR
6129        || po->op == OP_ADC || po->op == OP_SBB)
6130         cond_vars |= 1 << PFO_C;
6131     }
6132
6133     switch (po->op) {
6134     case OP_CMPS:
6135     case OP_SCAS:
6136       cond_vars |= 1 << PFO_Z;
6137       break;
6138
6139     case OP_MUL:
6140       if (po->operand[0].lmod == OPLM_DWORD)
6141         need_tmp64 = 1;
6142       break;
6143
6144     case OP_IMUL:
6145       if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
6146         need_tmp64 = 1;
6147       break;
6148
6149     case OP_CALL:
6150       // note: resolved non-reg calls are OPF_DONE already
6151       pp = po->pp;
6152       ferr_assert(po, pp != NULL);
6153
6154       if (pp->is_unresolved) {
6155         int regmask_stack = 0;
6156         collect_call_args(po, i, pp, &regmask, i + opcnt * 2);
6157
6158         // this is pretty rough guess:
6159         // see ecx and edx were pushed (and not their saved versions)
6160         for (arg = 0; arg < pp->argc; arg++) {
6161           if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
6162             continue;
6163
6164           tmp_op = pp->arg[arg].datap;
6165           if (tmp_op == NULL)
6166             ferr(po, "parsed_op missing for arg%d\n", arg);
6167           if (tmp_op->operand[0].type == OPT_REG)
6168             regmask_stack |= 1 << tmp_op->operand[0].reg;
6169         }
6170
6171         if (!((regmask_stack & (1 << xCX))
6172           && (regmask_stack & (1 << xDX))))
6173         {
6174           if (pp->argc_stack != 0
6175            || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
6176           {
6177             pp_insert_reg_arg(pp, "ecx");
6178             pp->is_fastcall = 1;
6179             regmask_init |= 1 << xCX;
6180             regmask |= 1 << xCX;
6181           }
6182           if (pp->argc_stack != 0
6183            || ((regmask | regmask_arg) & (1 << xDX)))
6184           {
6185             pp_insert_reg_arg(pp, "edx");
6186             regmask_init |= 1 << xDX;
6187             regmask |= 1 << xDX;
6188           }
6189         }
6190
6191         // note: __cdecl doesn't fall into is_unresolved category
6192         if (pp->argc_stack > 0)
6193           pp->is_stdcall = 1;
6194       }
6195       break;
6196
6197     case OP_MOV:
6198       if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6199       {
6200         // <var> = offset <something>
6201         if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6202           && !IS_START(po->operand[1].name, "off_"))
6203         {
6204           if (!po->operand[0].pp->is_fptr)
6205             ferr(po, "%s not declared as fptr when it should be\n",
6206               po->operand[0].name);
6207           if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6208             pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6209             pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6210             fnote(po, "var:  %s\n", buf1);
6211             fnote(po, "func: %s\n", buf2);
6212             ferr(po, "^ mismatch\n");
6213           }
6214         }
6215       }
6216       break;
6217
6218     case OP_DIV:
6219     case OP_IDIV:
6220       if (po->operand[0].lmod == OPLM_DWORD) {
6221         // 32bit division is common, look for it
6222         if (po->op == OP_DIV)
6223           ret = scan_for_reg_clear(i, xDX);
6224         else
6225           ret = scan_for_cdq_edx(i);
6226         if (ret >= 0)
6227           po->flags |= OPF_32BIT;
6228         else
6229           need_tmp64 = 1;
6230       }
6231       else
6232         need_tmp_var = 1;
6233       break;
6234
6235     case OP_CLD:
6236       po->flags |= OPF_RMD | OPF_DONE;
6237       break;
6238
6239     case OP_RCL:
6240     case OP_RCR:
6241     case OP_XCHG:
6242       need_tmp_var = 1;
6243       break;
6244
6245     case OP_FLD:
6246       if (po->operand[0].lmod == OPLM_QWORD)
6247         need_double = 1;
6248       break;
6249
6250     case OPP_ALLSHL:
6251     case OPP_ALLSHR:
6252       need_tmp64 = 1;
6253       break;
6254
6255     case OPP_FTOL: {
6256       struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
6257       j = -1;
6258       find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
6259       if (j == -1)
6260         po->flags |= OPF_32BIT;
6261       break;
6262     }
6263
6264     default:
6265       break;
6266     }
6267
6268     // this might need it's own pass...
6269     if (po->op != OP_FST && po->p_argnum > 0)
6270       save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6271
6272     // correct for "full stack" mode late enable
6273     if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6274         && need_float_stack)
6275       po->flags |= OPF_FSHIFT;
6276   }
6277
6278   float_type = need_double ? "double" : "float";
6279   float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6280   float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6281
6282   // output starts here
6283
6284   if (g_seh_found)
6285     fprintf(fout, "// had SEH\n");
6286
6287   // define userstack size
6288   if (g_func_pp->is_userstack) {
6289     fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6290     fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6291     fprintf(fout, "#endif\n");
6292   }
6293
6294   // the function itself
6295   ferr_assert(ops, !g_func_pp->is_fptr);
6296   output_pp(fout, g_func_pp,
6297     (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6298   fprintf(fout, "\n{\n");
6299
6300   // declare indirect functions
6301   for (i = 0; i < opcnt; i++) {
6302     po = &ops[i];
6303     if (po->flags & OPF_RMD)
6304       continue;
6305
6306     if (po->op == OP_CALL) {
6307       pp = po->pp;
6308       if (pp == NULL)
6309         ferr(po, "NULL pp\n");
6310
6311       if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6312         if (pp->name[0] != 0) {
6313           memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6314           memcpy(pp->name, "i_", 2);
6315
6316           // might be declared already
6317           found = 0;
6318           for (j = 0; j < i; j++) {
6319             if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6320               if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6321                 found = 1;
6322                 break;
6323               }
6324             }
6325           }
6326           if (found)
6327             continue;
6328         }
6329         else
6330           snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6331
6332         fprintf(fout, "  ");
6333         output_pp(fout, pp, OPP_SIMPLE_ARGS);
6334         fprintf(fout, ";\n");
6335       }
6336     }
6337   }
6338
6339   // output LUTs/jumptables
6340   for (i = 0; i < g_func_pd_cnt; i++) {
6341     pd = &g_func_pd[i];
6342     fprintf(fout, "  static const ");
6343     if (pd->type == OPT_OFFSET) {
6344       fprintf(fout, "void *jt_%s[] =\n    { ", pd->label);
6345
6346       for (j = 0; j < pd->count; j++) {
6347         if (j > 0)
6348           fprintf(fout, ", ");
6349         fprintf(fout, "&&%s", pd->d[j].u.label);
6350       }
6351     }
6352     else {
6353       fprintf(fout, "%s %s[] =\n    { ",
6354         lmod_type_u(ops, pd->lmod), pd->label);
6355
6356       for (j = 0; j < pd->count; j++) {
6357         if (j > 0)
6358           fprintf(fout, ", ");
6359         fprintf(fout, "%u", pd->d[j].u.val);
6360       }
6361     }
6362     fprintf(fout, " };\n");
6363     had_decl = 1;
6364   }
6365
6366   // declare stack frame, va_arg
6367   if (g_stack_fsz) {
6368     if (stack_fsz_adj)
6369       fprintf(fout, "  // stack_fsz_adj %d\n", stack_fsz_adj);
6370
6371     fprintf(fout, "  union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6372     if (g_func_lmods & (1 << OPLM_WORD))
6373       fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6374     if (g_func_lmods & (1 << OPLM_BYTE))
6375       fprintf(fout, " u8 b[%d];", g_stack_fsz);
6376     if (g_func_lmods & (1 << OPLM_QWORD))
6377       fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6378
6379     if (stack_align > 8)
6380       ferr(ops, "unhandled stack align of %d\n", stack_align);
6381     else if (stack_align == 8)
6382       fprintf(fout, " u64 align;");
6383     fprintf(fout, " } sf;\n");
6384     had_decl = 1;
6385   }
6386
6387   if (g_func_pp->is_userstack) {
6388     fprintf(fout, "  u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6389     fprintf(fout, "  u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6390     had_decl = 1;
6391   }
6392
6393   if (g_func_pp->is_vararg) {
6394     fprintf(fout, "  va_list ap;\n");
6395     had_decl = 1;
6396   }
6397
6398   // declare arg-registers
6399   for (i = 0; i < g_func_pp->argc; i++) {
6400     if (g_func_pp->arg[i].reg != NULL) {
6401       reg = char_array_i(regs_r32,
6402               ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6403       if (regmask & (1 << reg)) {
6404         if (g_func_pp->arg[i].type.is_retreg)
6405           fprintf(fout, "  u32 %s = *r_%s;\n",
6406             g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6407         else
6408           fprintf(fout, "  u32 %s = (u32)a%d;\n",
6409             g_func_pp->arg[i].reg, i + 1);
6410       }
6411       else {
6412         if (g_func_pp->arg[i].type.is_retreg)
6413           ferr(ops, "retreg '%s' is unused?\n",
6414             g_func_pp->arg[i].reg);
6415         fprintf(fout, "  // %s = a%d; // unused\n",
6416           g_func_pp->arg[i].reg, i + 1);
6417       }
6418       had_decl = 1;
6419     }
6420   }
6421
6422   // declare normal registers
6423   regmask_now = regmask & ~regmask_arg;
6424   regmask_now &= ~(1 << xSP);
6425   if (regmask_now & 0x00ff) {
6426     for (reg = 0; reg < 8; reg++) {
6427       if (regmask_now & (1 << reg)) {
6428         fprintf(fout, "  u32 %s", regs_r32[reg]);
6429         if (regmask_init & (1 << reg))
6430           fprintf(fout, " = 0");
6431         fprintf(fout, ";\n");
6432         had_decl = 1;
6433       }
6434     }
6435   }
6436   // ... mmx
6437   if (regmask_now & 0xff00) {
6438     for (reg = 8; reg < 16; reg++) {
6439       if (regmask_now & (1 << reg)) {
6440         fprintf(fout, "  mmxr %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   // ... x87
6449   if (need_float_stack) {
6450     fprintf(fout, "  %s f_st[8];\n", float_type);
6451     fprintf(fout, "  int f_stp = 0;\n");
6452     had_decl = 1;
6453   }
6454   else {
6455     if (regmask_now & 0xff0000) {
6456       for (reg = 16; reg < 24; reg++) {
6457         if (regmask_now & (1 << reg)) {
6458           fprintf(fout, "  %s f_st%d", float_type, reg - 16);
6459           if (regmask_init & (1 << reg))
6460             fprintf(fout, " = 0");
6461           fprintf(fout, ";\n");
6462           had_decl = 1;
6463         }
6464       }
6465     }
6466   }
6467
6468   if (need_float_sw) {
6469     fprintf(fout, "  u16 f_sw;\n");
6470     had_decl = 1;
6471   }
6472
6473   if (regmask_save) {
6474     for (reg = 0; reg < 8; reg++) {
6475       if (regmask_save & (1 << reg)) {
6476         fprintf(fout, "  u32 s_%s;\n", regs_r32[reg]);
6477         had_decl = 1;
6478       }
6479     }
6480   }
6481
6482   for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6483     if (save_arg_vars[i] == 0)
6484       continue;
6485     for (reg = 0; reg < 32; reg++) {
6486       if (save_arg_vars[i] & (1 << reg)) {
6487         fprintf(fout, "  u32 %s;\n",
6488           saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6489         had_decl = 1;
6490       }
6491     }
6492   }
6493
6494   if (regmask_ffca) {
6495     for (reg = 0; reg < 32; reg++) {
6496       if (regmask_ffca & (1 << reg)) {
6497         fprintf(fout, "  %s fs_%d;\n", float_type, reg + 1);
6498         had_decl = 1;
6499       }
6500     }
6501   }
6502
6503   // declare push-pop temporaries
6504   if (regmask_pp) {
6505     for (reg = 0; reg < 8; reg++) {
6506       if (regmask_pp & (1 << reg)) {
6507         fprintf(fout, "  u32 pp_%s;\n", regs_r32[reg]);
6508         had_decl = 1;
6509       }
6510     }
6511   }
6512
6513   if (cond_vars) {
6514     for (i = 0; i < 8; i++) {
6515       if (cond_vars & (1 << i)) {
6516         fprintf(fout, "  u32 cond_%s;\n", parsed_flag_op_names[i]);
6517         had_decl = 1;
6518       }
6519     }
6520   }
6521
6522   if (need_tmp_var) {
6523     fprintf(fout, "  u32 tmp;\n");
6524     had_decl = 1;
6525   }
6526
6527   if (need_tmp64) {
6528     fprintf(fout, "  u64 tmp64;\n");
6529     had_decl = 1;
6530   }
6531
6532   if (had_decl)
6533     fprintf(fout, "\n");
6534
6535   // do stack clear, if needed
6536   if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6537     fprintf(fout, "  ");
6538     if (g_stack_clear_len != 0) {
6539       if (g_stack_clear_len <= 4) {
6540         for (i = 0; i < g_stack_clear_len; i++)
6541           fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6542         fprintf(fout, "0;\n");
6543       }
6544       else {
6545         fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6546           g_stack_clear_start, g_stack_clear_len * 4);
6547       }
6548     }
6549     else
6550       fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6551   }
6552
6553   if (g_func_pp->is_vararg) {
6554     if (g_func_pp->argc_stack == 0)
6555       ferr(ops, "vararg func without stack args?\n");
6556     fprintf(fout, "  va_start(ap, a%d);\n", g_func_pp->argc);
6557   }
6558
6559   // output ops
6560   for (i = 0; i < opcnt; i++)
6561   {
6562     if (g_labels[i] != NULL) {
6563       fprintf(fout, "\n%s:\n", g_labels[i]);
6564       label_pending = 1;
6565
6566       delayed_flag_op = NULL;
6567       last_arith_dst = NULL;
6568     }
6569
6570     po = &ops[i];
6571     if (po->flags & OPF_RMD)
6572       continue;
6573
6574     no_output = 0;
6575
6576     #define assert_operand_cnt(n_) \
6577       if (po->operand_cnt != n_) \
6578         ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6579
6580     // conditional/flag using op?
6581     if (po->flags & OPF_CC)
6582     {
6583       int is_delayed = 0;
6584
6585       tmp_op = po->datap;
6586
6587       // we go through all this trouble to avoid using parsed_flag_op,
6588       // which makes generated code much nicer
6589       if (delayed_flag_op != NULL)
6590       {
6591         out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6592           po->pfo, po->pfo_inv);
6593         is_delayed = 1;
6594       }
6595       else if (last_arith_dst != NULL
6596         && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6597            || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6598            ))
6599       {
6600         out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6601         out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6602           last_arith_dst->lmod, buf3);
6603         is_delayed = 1;
6604       }
6605       else if (tmp_op != NULL) {
6606         // use preprocessed flag calc results
6607         if (!(tmp_op->pfomask & (1 << po->pfo)))
6608           ferr(po, "not prepared for pfo %d\n", po->pfo);
6609
6610         // note: pfo_inv was not yet applied
6611         snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6612           po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6613       }
6614       else {
6615         ferr(po, "all methods of finding comparison failed\n");
6616       }
6617  
6618       if (po->flags & OPF_JMP) {
6619         fprintf(fout, "  if %s", buf1);
6620       }
6621       else if (po->op == OP_RCL || po->op == OP_RCR
6622                || po->op == OP_ADC || po->op == OP_SBB)
6623       {
6624         if (is_delayed)
6625           fprintf(fout, "  cond_%s = %s;\n",
6626             parsed_flag_op_names[po->pfo], buf1);
6627       }
6628       else if (po->flags & OPF_DATA) { // SETcc
6629         out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6630         fprintf(fout, "  %s = %s;", buf2, buf1);
6631       }
6632       else {
6633         ferr(po, "unhandled conditional op\n");
6634       }
6635     }
6636
6637     pfomask = po->pfomask;
6638
6639     switch (po->op)
6640     {
6641       case OP_MOV:
6642         assert_operand_cnt(2);
6643         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6644         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6645         default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6646         fprintf(fout, "  %s = %s;", buf1,
6647             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6648               buf3, 0));
6649         break;
6650
6651       case OP_LEA:
6652         assert_operand_cnt(2);
6653         po->operand[1].lmod = OPLM_DWORD; // always
6654         fprintf(fout, "  %s = %s;",
6655             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6656             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6657               NULL, 1));
6658         break;
6659
6660       case OP_MOVZX:
6661         assert_operand_cnt(2);
6662         fprintf(fout, "  %s = %s;",
6663             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6664             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6665         break;
6666
6667       case OP_MOVSX:
6668         assert_operand_cnt(2);
6669         switch (po->operand[1].lmod) {
6670         case OPLM_BYTE:
6671           strcpy(buf3, "(s8)");
6672           break;
6673         case OPLM_WORD:
6674           strcpy(buf3, "(s16)");
6675           break;
6676         default:
6677           ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6678         }
6679         fprintf(fout, "  %s = %s;",
6680             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6681             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6682               buf3, 0));
6683         break;
6684
6685       case OP_XCHG:
6686         assert_operand_cnt(2);
6687         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6688         fprintf(fout, "  tmp = %s;",
6689           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6690         fprintf(fout, " %s = %s;",
6691           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6692           out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6693             default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6694         fprintf(fout, " %s = %stmp;",
6695           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6696           default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6697         snprintf(g_comment, sizeof(g_comment), "xchg");
6698         break;
6699
6700       case OP_NOT:
6701         assert_operand_cnt(1);
6702         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6703         fprintf(fout, "  %s = ~%s;", buf1, buf1);
6704         break;
6705
6706       case OP_XLAT:
6707         assert_operand_cnt(2);
6708         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6709         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6710         fprintf(fout, "  %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6711         strcpy(g_comment, "xlat");
6712         break;
6713
6714       case OP_CDQ:
6715         assert_operand_cnt(2);
6716         fprintf(fout, "  %s = (s32)%s >> 31;",
6717             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6718             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6719         strcpy(g_comment, "cdq");
6720         break;
6721
6722       case OP_BSWAP:
6723         assert_operand_cnt(1);
6724         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6725         fprintf(fout, "  %s = __builtin_bswap32(%s);", buf1, buf1);
6726         break;
6727
6728       case OP_LODS:
6729         if (po->flags & OPF_REP) {
6730           assert_operand_cnt(3);
6731           // hmh..
6732           ferr(po, "TODO\n");
6733         }
6734         else {
6735           assert_operand_cnt(2);
6736           fprintf(fout, "  %s = %sesi; esi %c= %d;",
6737             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6738             lmod_cast_u_ptr(po, po->operand[1].lmod),
6739             (po->flags & OPF_DF) ? '-' : '+',
6740             lmod_bytes(po, po->operand[1].lmod));
6741           strcpy(g_comment, "lods");
6742         }
6743         break;
6744
6745       case OP_STOS:
6746         if (po->flags & OPF_REP) {
6747           assert_operand_cnt(3);
6748           fprintf(fout, "  for (; ecx != 0; ecx--, edi %c= %d)\n",
6749             (po->flags & OPF_DF) ? '-' : '+',
6750             lmod_bytes(po, po->operand[1].lmod));
6751           fprintf(fout, "    %sedi = eax;",
6752             lmod_cast_u_ptr(po, po->operand[1].lmod));
6753           strcpy(g_comment, "rep stos");
6754         }
6755         else {
6756           assert_operand_cnt(2);
6757           fprintf(fout, "  %sedi = eax; edi %c= %d;",
6758             lmod_cast_u_ptr(po, po->operand[1].lmod),
6759             (po->flags & OPF_DF) ? '-' : '+',
6760             lmod_bytes(po, po->operand[1].lmod));
6761           strcpy(g_comment, "stos");
6762         }
6763         break;
6764
6765       case OP_MOVS:
6766         j = lmod_bytes(po, po->operand[0].lmod);
6767         strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6768         l = (po->flags & OPF_DF) ? '-' : '+';
6769         if (po->flags & OPF_REP) {
6770           assert_operand_cnt(3);
6771           fprintf(fout,
6772             "  for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6773             l, j, l, j);
6774           fprintf(fout,
6775             "    %sedi = %sesi;", buf1, buf1);
6776           strcpy(g_comment, "rep movs");
6777         }
6778         else {
6779           assert_operand_cnt(2);
6780           fprintf(fout, "  %sedi = %sesi; edi %c= %d; esi %c= %d;",
6781             buf1, buf1, l, j, l, j);
6782           strcpy(g_comment, "movs");
6783         }
6784         break;
6785
6786       case OP_CMPS:
6787         // repe ~ repeat while ZF=1
6788         j = lmod_bytes(po, po->operand[0].lmod);
6789         strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6790         l = (po->flags & OPF_DF) ? '-' : '+';
6791         if (po->flags & OPF_REP) {
6792           assert_operand_cnt(3);
6793           fprintf(fout,
6794             "  while (ecx != 0) {\n");
6795           if (pfomask & (1 << PFO_C)) {
6796             // ugh..
6797             fprintf(fout,
6798             "    cond_c = %sesi < %sedi;\n", buf1, buf1);
6799             pfomask &= ~(1 << PFO_C);
6800           }
6801           fprintf(fout,
6802             "    cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6803               buf1, buf1, l, j, l, j);
6804           fprintf(fout,
6805             "    ecx--;\n"
6806             "    if (cond_z %s 0) break;\n",
6807               (po->flags & OPF_REPZ) ? "==" : "!=");
6808           fprintf(fout,
6809             "  }");
6810           snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6811             (po->flags & OPF_REPZ) ? "e" : "ne");
6812         }
6813         else {
6814           assert_operand_cnt(2);
6815           fprintf(fout,
6816             "  cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6817             buf1, buf1, l, j, l, j);
6818           strcpy(g_comment, "cmps");
6819         }
6820         pfomask &= ~(1 << PFO_Z);
6821         last_arith_dst = NULL;
6822         delayed_flag_op = NULL;
6823         break;
6824
6825       case OP_SCAS:
6826         // only does ZF (for now)
6827         // repe ~ repeat while ZF=1
6828         j = lmod_bytes(po, po->operand[1].lmod);
6829         l = (po->flags & OPF_DF) ? '-' : '+';
6830         if (po->flags & OPF_REP) {
6831           assert_operand_cnt(3);
6832           fprintf(fout,
6833             "  while (ecx != 0) {\n");
6834           fprintf(fout,
6835             "    cond_z = (%seax == %sedi); edi %c= %d;\n",
6836               lmod_cast_u(po, po->operand[1].lmod),
6837               lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6838           fprintf(fout,
6839             "    ecx--;\n"
6840             "    if (cond_z %s 0) break;\n",
6841               (po->flags & OPF_REPZ) ? "==" : "!=");
6842           fprintf(fout,
6843             "  }");
6844           snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6845             (po->flags & OPF_REPZ) ? "e" : "ne");
6846         }
6847         else {
6848           assert_operand_cnt(2);
6849           fprintf(fout, "  cond_z = (%seax == %sedi); edi %c= %d;",
6850               lmod_cast_u(po, po->operand[1].lmod),
6851               lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6852           strcpy(g_comment, "scas");
6853         }
6854         pfomask &= ~(1 << PFO_Z);
6855         last_arith_dst = NULL;
6856         delayed_flag_op = NULL;
6857         break;
6858
6859       // arithmetic w/flags
6860       case OP_AND:
6861         if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6862           goto dualop_arith_const;
6863         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6864         goto dualop_arith;
6865
6866       case OP_OR:
6867         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6868         if (po->operand[1].type == OPT_CONST) {
6869           j = lmod_bytes(po, po->operand[0].lmod);
6870           if (((1ull << j * 8) - 1) == po->operand[1].val)
6871             goto dualop_arith_const;
6872         }
6873         goto dualop_arith;
6874
6875       dualop_arith:
6876         assert_operand_cnt(2);
6877         fprintf(fout, "  %s %s= %s;",
6878             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6879             op_to_c(po),
6880             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6881         output_std_flags(fout, po, &pfomask, buf1);
6882         last_arith_dst = &po->operand[0];
6883         delayed_flag_op = NULL;
6884         break;
6885
6886       dualop_arith_const:
6887         // and 0, or ~0 used instead mov
6888         assert_operand_cnt(2);
6889         fprintf(fout, "  %s = %s;",
6890           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6891           out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6892            default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6893         output_std_flags(fout, po, &pfomask, buf1);
6894         last_arith_dst = &po->operand[0];
6895         delayed_flag_op = NULL;
6896         break;
6897
6898       case OP_SHL:
6899       case OP_SHR:
6900         assert_operand_cnt(2);
6901         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6902         if (pfomask & (1 << PFO_C)) {
6903           if (po->operand[1].type == OPT_CONST) {
6904             l = lmod_bytes(po, po->operand[0].lmod) * 8;
6905             j = po->operand[1].val;
6906             j %= l;
6907             if (j != 0) {
6908               if (po->op == OP_SHL)
6909                 j = l - j;
6910               else
6911                 j -= 1;
6912               fprintf(fout, "  cond_c = (%s >> %d) & 1;\n",
6913                 buf1, j);
6914             }
6915             else
6916               ferr(po, "zero shift?\n");
6917           }
6918           else
6919             ferr(po, "TODO\n");
6920           pfomask &= ~(1 << PFO_C);
6921         }
6922         fprintf(fout, "  %s %s= %s", buf1, op_to_c(po),
6923             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6924         if (po->operand[1].type != OPT_CONST)
6925           fprintf(fout, " & 0x1f");
6926         fprintf(fout, ";");
6927         output_std_flags(fout, po, &pfomask, buf1);
6928         last_arith_dst = &po->operand[0];
6929         delayed_flag_op = NULL;
6930         break;
6931
6932       case OP_SAR:
6933         assert_operand_cnt(2);
6934         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6935         fprintf(fout, "  %s = %s%s >> %s;", buf1,
6936           lmod_cast_s(po, po->operand[0].lmod), buf1,
6937           out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6938         output_std_flags(fout, po, &pfomask, buf1);
6939         last_arith_dst = &po->operand[0];
6940         delayed_flag_op = NULL;
6941         break;
6942
6943       case OP_SHLD:
6944       case OP_SHRD:
6945         assert_operand_cnt(3);
6946         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6947         l = lmod_bytes(po, po->operand[0].lmod) * 8;
6948         out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6949         if (po->operand[2].type != OPT_CONST) {
6950           // no handling for "undefined" case, hopefully not needed
6951           snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6952           strcpy(buf3, buf2);
6953         }
6954         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6955         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6956         if (po->op == OP_SHLD) {
6957           fprintf(fout, "  %s <<= %s; %s |= %s >> (%d - %s);",
6958             buf1, buf3, buf1, buf2, l, buf3);
6959           strcpy(g_comment, "shld");
6960         }
6961         else {
6962           fprintf(fout, "  %s >>= %s; %s |= %s << (%d - %s);",
6963             buf1, buf3, buf1, buf2, l, buf3);
6964           strcpy(g_comment, "shrd");
6965         }
6966         output_std_flags(fout, po, &pfomask, buf1);
6967         last_arith_dst = &po->operand[0];
6968         delayed_flag_op = NULL;
6969         break;
6970
6971       case OP_ROL:
6972       case OP_ROR:
6973         assert_operand_cnt(2);
6974         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6975         if (po->operand[1].type == OPT_CONST) {
6976           j = po->operand[1].val;
6977           j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6978           fprintf(fout, po->op == OP_ROL ?
6979             "  %s = (%s << %d) | (%s >> %d);" :
6980             "  %s = (%s >> %d) | (%s << %d);",
6981             buf1, buf1, j, buf1,
6982             lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6983         }
6984         else
6985           ferr(po, "TODO\n");
6986         output_std_flags(fout, po, &pfomask, buf1);
6987         last_arith_dst = &po->operand[0];
6988         delayed_flag_op = NULL;
6989         break;
6990
6991       case OP_RCL:
6992       case OP_RCR:
6993         assert_operand_cnt(2);
6994         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6995         l = lmod_bytes(po, po->operand[0].lmod) * 8;
6996         if (po->operand[1].type == OPT_CONST) {
6997           j = po->operand[1].val % l;
6998           if (j == 0)
6999             ferr(po, "zero rotate\n");
7000           fprintf(fout, "  tmp = (%s >> %d) & 1;\n",
7001             buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
7002           if (po->op == OP_RCL) {
7003             fprintf(fout,
7004               "  %s = (%s << %d) | (cond_c << %d)",
7005               buf1, buf1, j, j - 1);
7006             if (j != 1)
7007               fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
7008           }
7009           else {
7010             fprintf(fout,
7011               "  %s = (%s >> %d) | (cond_c << %d)",
7012               buf1, buf1, j, l - j);
7013             if (j != 1)
7014               fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
7015           }
7016           fprintf(fout, ";\n");
7017           fprintf(fout, "  cond_c = tmp;");
7018         }
7019         else
7020           ferr(po, "TODO\n");
7021         strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
7022         output_std_flags(fout, po, &pfomask, buf1);
7023         last_arith_dst = &po->operand[0];
7024         delayed_flag_op = NULL;
7025         break;
7026
7027       case OP_XOR:
7028         assert_operand_cnt(2);
7029         propagate_lmod(po, &po->operand[0], &po->operand[1]);
7030         if (IS(opr_name(po, 0), opr_name(po, 1))) {
7031           // special case for XOR
7032           int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
7033           for (j = 0; j <= PFO_LE; j++) {
7034             if (pfomask & (1 << j)) {
7035               fprintf(fout, "  cond_%s = %d;\n",
7036                 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
7037               pfomask &= ~(1 << j);
7038             }
7039           }
7040           fprintf(fout, "  %s = 0;",
7041             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7042           last_arith_dst = &po->operand[0];
7043           delayed_flag_op = NULL;
7044           break;
7045         }
7046         goto dualop_arith;
7047
7048       case OP_ADD:
7049         assert_operand_cnt(2);
7050         propagate_lmod(po, &po->operand[0], &po->operand[1]);
7051         if (pfomask & (1 << PFO_C)) {
7052           out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7053           out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7054           if (po->operand[0].lmod == OPLM_DWORD) {
7055             fprintf(fout, "  tmp64 = (u64)%s + %s;\n", buf1, buf2);
7056             fprintf(fout, "  cond_c = tmp64 >> 32;\n");
7057             fprintf(fout, "  %s = (u32)tmp64;",
7058               out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7059             strcat(g_comment, " add64");
7060           }
7061           else {
7062             fprintf(fout, "  cond_c = ((u32)%s + %s) >> %d;\n",
7063               buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
7064             fprintf(fout, "  %s += %s;",
7065               out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7066               buf2);
7067           }
7068           pfomask &= ~(1 << PFO_C);
7069           output_std_flags(fout, po, &pfomask, buf1);
7070           last_arith_dst = &po->operand[0];
7071           delayed_flag_op = NULL;
7072           break;
7073         }
7074         if (pfomask & (1 << PFO_LE)) {
7075           out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
7076           fprintf(fout, "  cond_%s = %s;\n",
7077             parsed_flag_op_names[PFO_LE], buf1);
7078           pfomask &= ~(1 << PFO_LE);
7079         }
7080         goto dualop_arith;
7081
7082       case OP_SUB:
7083         assert_operand_cnt(2);
7084         propagate_lmod(po, &po->operand[0], &po->operand[1]);
7085         if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
7086           for (j = 0; j <= PFO_LE; j++) {
7087             if (!(pfomask & (1 << j)))
7088               continue;
7089             if (j == PFO_Z || j == PFO_S)
7090               continue;
7091
7092             out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7093             fprintf(fout, "  cond_%s = %s;\n",
7094               parsed_flag_op_names[j], buf1);
7095             pfomask &= ~(1 << j);
7096           }
7097         }
7098         goto dualop_arith;
7099
7100       case OP_ADC:
7101       case OP_SBB:
7102         assert_operand_cnt(2);
7103         propagate_lmod(po, &po->operand[0], &po->operand[1]);
7104         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7105         if (po->op == OP_SBB
7106           && IS(po->operand[0].name, po->operand[1].name))
7107         {
7108           // avoid use of unitialized var
7109           fprintf(fout, "  %s = -cond_c;", buf1);
7110           // carry remains what it was
7111           pfomask &= ~(1 << PFO_C);
7112         }
7113         else {
7114           fprintf(fout, "  %s %s= %s + cond_c;", buf1, op_to_c(po),
7115             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7116         }
7117         output_std_flags(fout, po, &pfomask, buf1);
7118         last_arith_dst = &po->operand[0];
7119         delayed_flag_op = NULL;
7120         break;
7121
7122       case OP_BSF:
7123       case OP_BSR:
7124         // on SKL, if src is 0, dst is left unchanged
7125         assert_operand_cnt(2);
7126         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7127         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7128         output_std_flag_z(fout, po, &pfomask, buf2);
7129         if (po->op == OP_BSF)
7130           snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
7131         else
7132           snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
7133         fprintf(fout, "  if (%s) %s = %s;", buf2, buf1, buf3);
7134         last_arith_dst = &po->operand[0];
7135         delayed_flag_op = NULL;
7136         strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
7137         break;
7138
7139       case OP_DEC:
7140         if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
7141           for (j = 0; j <= PFO_LE; j++) {
7142             if (!(pfomask & (1 << j)))
7143               continue;
7144             if (j == PFO_Z || j == PFO_S || j == PFO_C)
7145               continue;
7146
7147             out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7148             fprintf(fout, "  cond_%s = %s;\n",
7149               parsed_flag_op_names[j], buf1);
7150             pfomask &= ~(1 << j);
7151           }
7152         }
7153         // fallthrough
7154
7155       case OP_INC:
7156         if (pfomask & (1 << PFO_C))
7157           // carry is unaffected by inc/dec.. wtf?
7158           ferr(po, "carry propagation needed\n");
7159
7160         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7161         if (po->operand[0].type == OPT_REG) {
7162           strcpy(buf2, po->op == OP_INC ? "++" : "--");
7163           fprintf(fout, "  %s%s;", buf1, buf2);
7164         }
7165         else {
7166           strcpy(buf2, po->op == OP_INC ? "+" : "-");
7167           fprintf(fout, "  %s %s= 1;", buf1, buf2);
7168         }
7169         output_std_flags(fout, po, &pfomask, buf1);
7170         last_arith_dst = &po->operand[0];
7171         delayed_flag_op = NULL;
7172         break;
7173
7174       case OP_NEG:
7175         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7176         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
7177         fprintf(fout, "  %s = -%s%s;", buf1,
7178           lmod_cast_s(po, po->operand[0].lmod), buf2);
7179         last_arith_dst = &po->operand[0];
7180         delayed_flag_op = NULL;
7181         if (pfomask & PFOB_C) {
7182           fprintf(fout, "\n  cond_c = (%s != 0);", buf1);
7183           pfomask &= ~PFOB_C;
7184         }
7185         output_std_flags(fout, po, &pfomask, buf1);
7186         break;
7187
7188       case OP_IMUL:
7189         if (po->operand_cnt == 2) {
7190           propagate_lmod(po, &po->operand[0], &po->operand[1]);
7191           goto dualop_arith;
7192         }
7193         if (po->operand_cnt == 3)
7194           ferr(po, "TODO imul3\n");
7195         // fallthrough
7196       case OP_MUL:
7197         assert_operand_cnt(1);
7198         switch (po->operand[0].lmod) {
7199         case OPLM_DWORD:
7200           strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7201           fprintf(fout, "  tmp64 = %seax * %s%s;\n", buf1, buf1,
7202             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7203           fprintf(fout, "  edx = tmp64 >> 32;\n");
7204           fprintf(fout, "  eax = tmp64;");
7205           break;
7206         case OPLM_BYTE:
7207           strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7208           fprintf(fout, "  LOWORD(eax) = %seax * %s;", buf1,
7209             out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7210               buf1, 0));
7211           break;
7212         default:
7213           ferr(po, "TODO: unhandled mul type\n");
7214           break;
7215         }
7216         last_arith_dst = NULL;
7217         delayed_flag_op = NULL;
7218         break;
7219
7220       case OP_DIV:
7221       case OP_IDIV:
7222         assert_operand_cnt(1);
7223         out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7224         strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7225           po->op == OP_IDIV));
7226         switch (po->operand[0].lmod) {
7227         case OPLM_DWORD:
7228           if (po->flags & OPF_32BIT)
7229             snprintf(buf2, sizeof(buf2), "%seax", cast);
7230           else {
7231             fprintf(fout, "  tmp64 = ((u64)edx << 32) | eax;\n");
7232             snprintf(buf2, sizeof(buf2), "%stmp64",
7233               (po->op == OP_IDIV) ? "(s64)" : "");
7234           }
7235           if (po->operand[0].type == OPT_REG
7236             && po->operand[0].reg == xDX)
7237           {
7238             fprintf(fout, "  eax = %s / %s%s;\n", buf2, cast, buf1);
7239             fprintf(fout, "  edx = %s %% %s%s;", buf2, cast, buf1);
7240           }
7241           else {
7242             fprintf(fout, "  edx = %s %% %s%s;\n", buf2, cast, buf1);
7243             fprintf(fout, "  eax = %s / %s%s;", buf2, cast, buf1);
7244           }
7245           break;
7246         case OPLM_WORD:
7247           fprintf(fout, "  tmp = (edx << 16) | (eax & 0xffff);\n");
7248           snprintf(buf2, sizeof(buf2), "%stmp",
7249             (po->op == OP_IDIV) ? "(s32)" : "");
7250           if (po->operand[0].type == OPT_REG
7251             && po->operand[0].reg == xDX)
7252           {
7253             fprintf(fout, "  LOWORD(eax) = %s / %s%s;\n",
7254               buf2, cast, buf1);
7255             fprintf(fout, "  LOWORD(edx) = %s %% %s%s;",
7256               buf2, cast, buf1);
7257           }
7258           else {
7259             fprintf(fout, "  LOWORD(edx) = %s %% %s%s;\n",
7260               buf2, cast, buf1);
7261             fprintf(fout, "  LOWORD(eax) = %s / %s%s;",
7262               buf2, cast, buf1);
7263           }
7264           strcat(g_comment, " div16");
7265           break;
7266         default:
7267           ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7268         }
7269         last_arith_dst = NULL;
7270         delayed_flag_op = NULL;
7271         break;
7272
7273       case OP_TEST:
7274       case OP_CMP:
7275         propagate_lmod(po, &po->operand[0], &po->operand[1]);
7276         if (pfomask != 0) {
7277           for (j = 0; j < 8; j++) {
7278             if (pfomask & (1 << j)) {
7279               out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7280               fprintf(fout, "  cond_%s = %s;",
7281                 parsed_flag_op_names[j], buf1);
7282             }
7283           }
7284           pfomask = 0;
7285         }
7286         else
7287           no_output = 1;
7288         last_arith_dst = NULL;
7289         delayed_flag_op = po;
7290         break;
7291
7292       case OP_SCC:
7293         // SETcc - should already be handled
7294         break;
7295
7296       // note: we reuse OP_Jcc for SETcc, only flags differ
7297       case OP_JCC:
7298         fprintf(fout, "\n    goto %s;", po->operand[0].name);
7299         break;
7300
7301       case OP_JECXZ:
7302         fprintf(fout, "  if (ecx == 0)\n");
7303         fprintf(fout, "    goto %s;", po->operand[0].name);
7304         strcat(g_comment, " jecxz");
7305         break;
7306
7307       case OP_LOOP:
7308         fprintf(fout, "  if (--ecx != 0)\n");
7309         fprintf(fout, "    goto %s;", po->operand[0].name);
7310         strcat(g_comment, " loop");
7311         break;
7312
7313       case OP_JMP:
7314         assert_operand_cnt(1);
7315         last_arith_dst = NULL;
7316         delayed_flag_op = NULL;
7317
7318         if (po->operand[0].type == OPT_REGMEM) {
7319           ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7320                   buf1, buf2);
7321           if (ret != 2)
7322             ferr(po, "parse failure for jmp '%s'\n",
7323               po->operand[0].name);
7324           fprintf(fout, "  goto *jt_%s[%s];", buf1, buf2);
7325           break;
7326         }
7327         else if (po->operand[0].type != OPT_LABEL)
7328           ferr(po, "unhandled jmp type\n");
7329
7330         fprintf(fout, "  goto %s;", po->operand[0].name);
7331         break;
7332
7333       case OP_CALL:
7334         assert_operand_cnt(1);
7335         pp = po->pp;
7336         my_assert_not(pp, NULL);
7337
7338         strcpy(buf3, "  ");
7339         if (po->flags & OPF_CC) {
7340           // we treat conditional branch to another func
7341           // (yes such code exists..) as conditional tailcall
7342           strcat(buf3, "  ");
7343           fprintf(fout, " {\n");
7344         }
7345
7346         if (pp->is_fptr && !pp->is_arg) {
7347           fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7348             out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7349               "(void *)", 0));
7350           if (pp->is_unresolved || IS_START(pp->name, "i_guess"))
7351             fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7352               buf3, asmfn, po->asmln, pp->name);
7353         }
7354
7355         fprintf(fout, "%s", buf3);
7356         if (strstr(pp->ret_type.name, "int64")) {
7357           if (po->flags & OPF_TAIL)
7358             ferr(po, "int64 and tail?\n");
7359           fprintf(fout, "tmp64 = ");
7360         }
7361         else if (!IS(pp->ret_type.name, "void")) {
7362           if (po->flags & OPF_TAIL) {
7363             if (regmask_ret & mxAX) {
7364               fprintf(fout, "return ");
7365               if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7366                 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7367             }
7368             else if (regmask_ret & mxST0)
7369               ferr(po, "float tailcall\n");
7370           }
7371           else if (po->regmask_dst & mxAX) {
7372             fprintf(fout, "eax = ");
7373             if (pp->ret_type.is_ptr)
7374               fprintf(fout, "(u32)");
7375           }
7376           else if (po->regmask_dst & mxST0) {
7377             ferr_assert(po, po->flags & OPF_FPUSH);
7378             if (need_float_stack)
7379               fprintf(fout, "f_st[--f_stp & 7] = ");
7380             else
7381               fprintf(fout, "f_st0 = ");
7382           }
7383         }
7384
7385         if (pp->name[0] == 0)
7386           ferr(po, "missing pp->name\n");
7387         fprintf(fout, "%s%s(", pp->name,
7388           pp->has_structarg ? "_sa" : "");
7389
7390         if (po->flags & OPF_ATAIL) {
7391           int check_compat =
7392             g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7393           check_compat |= pp->argc_stack > 0;
7394           if (check_compat
7395            && (pp->argc_stack != g_func_pp->argc_stack
7396                || pp->is_stdcall != g_func_pp->is_stdcall))
7397             ferr(po, "incompatible arg-reuse tailcall\n");
7398           if (g_func_pp->has_retreg)
7399             ferr(po, "TODO: retreg+tailcall\n");
7400
7401           for (arg = j = 0; arg < pp->argc; arg++) {
7402             if (arg > 0)
7403               fprintf(fout, ", ");
7404
7405             cast[0] = 0;
7406             if (pp->arg[arg].type.is_ptr)
7407               snprintf(cast, sizeof(cast), "(%s)",
7408                 pp->arg[arg].type.name);
7409
7410             if (pp->arg[arg].reg != NULL) {
7411               fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7412               continue;
7413             }
7414             // stack arg
7415             for (; j < g_func_pp->argc; j++)
7416               if (g_func_pp->arg[j].reg == NULL)
7417                 break;
7418             fprintf(fout, "%sa%d", cast, j + 1);
7419             j++;
7420           }
7421         }
7422         else {
7423           for (arg = 0; arg < pp->argc; arg++) {
7424             if (arg > 0)
7425               fprintf(fout, ", ");
7426
7427             cast[0] = 0;
7428             if (pp->arg[arg].type.is_ptr)
7429               snprintf(cast, sizeof(cast), "(%s)",
7430                 pp->arg[arg].type.name);
7431
7432             if (pp->arg[arg].reg != NULL) {
7433               if (pp->arg[arg].type.is_retreg)
7434                 fprintf(fout, "&%s", pp->arg[arg].reg);
7435               else if (IS(pp->arg[arg].reg, "ebp")
7436                     && g_bp_frame && !(po->flags & OPF_EBP_S))
7437               {
7438                 // rare special case
7439                 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7440                 strcat(g_comment, " bp_ref");
7441               }
7442               else
7443                 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7444               continue;
7445             }
7446
7447             // stack arg
7448             tmp_op = pp->arg[arg].datap;
7449             if (tmp_op == NULL)
7450               ferr(po, "parsed_op missing for arg%d\n", arg);
7451
7452             if (tmp_op->flags & OPF_VAPUSH) {
7453               fprintf(fout, "ap");
7454             }
7455             else if (tmp_op->op == OP_FST) {
7456               fprintf(fout, "fs_%d", tmp_op->p_argnum);
7457               if (tmp_op->operand[0].lmod == OPLM_QWORD)
7458                 arg++;
7459             }
7460             else if (pp->arg[arg].type.is_64bit) {
7461               ferr_assert(po, tmp_op->p_argpass == 0);
7462               ferr_assert(po, !pp->arg[arg].is_saved);
7463               ferr_assert(po, !pp->arg[arg].type.is_float);
7464               ferr_assert(po, cast[0] == 0);
7465               out_src_opr(buf1, sizeof(buf1),
7466                 tmp_op, &tmp_op->operand[0], cast, 0);
7467               tmp_op = pp->arg[++arg].datap;
7468               ferr_assert(po, tmp_op != NULL);
7469               out_src_opr(buf2, sizeof(buf2),
7470                 tmp_op, &tmp_op->operand[0], cast, 0);
7471               fprintf(fout, "((u64)(%s) << 32) | (%s)",
7472                 buf2, buf1);
7473             }
7474             else if (tmp_op->p_argpass != 0) {
7475               ferr_assert(po, !pp->arg[arg].type.is_float);
7476               fprintf(fout, "a%d", tmp_op->p_argpass);
7477             }
7478             else if (pp->arg[arg].is_saved) {
7479               ferr_assert(po, tmp_op->p_argnum > 0);
7480               ferr_assert(po, !pp->arg[arg].type.is_float);
7481               fprintf(fout, "%s%s", cast,
7482                 saved_arg_name(buf1, sizeof(buf1),
7483                   tmp_op->p_arggrp, tmp_op->p_argnum));
7484             }
7485             else if (pp->arg[arg].type.is_float) {
7486               ferr_assert(po, !pp->arg[arg].type.is_64bit);
7487               fprintf(fout, "%s",
7488                 out_src_opr_float(buf1, sizeof(buf1),
7489                   tmp_op, &tmp_op->operand[0], need_float_stack));
7490             }
7491             else {
7492               fprintf(fout, "%s",
7493                 out_src_opr(buf1, sizeof(buf1),
7494                   tmp_op, &tmp_op->operand[0], cast, 0));
7495             }
7496           }
7497         }
7498         fprintf(fout, ");");
7499
7500         if (strstr(pp->ret_type.name, "int64")) {
7501           fprintf(fout, "\n");
7502           fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7503           fprintf(fout, "%seax = tmp64;", buf3);
7504         }
7505
7506         if (pp->is_unresolved) {
7507           snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7508             pp->argc_reg);
7509           strcat(g_comment, buf2);
7510         }
7511
7512         if (po->flags & OPF_TAIL) {
7513           ret = 0;
7514           if (i == opcnt - 1 || pp->is_noreturn)
7515             ret = 0;
7516           else if (IS(pp->ret_type.name, "void"))
7517             ret = 1;
7518           else if (!(regmask_ret & (1 << xAX)))
7519             ret = 1;
7520           // else already handled as 'return f()'
7521
7522           if (ret) {
7523             fprintf(fout, "\n%sreturn;", buf3);
7524             strcat(g_comment, " ^ tailcall");
7525           }
7526           else
7527             strcat(g_comment, " tailcall");
7528
7529           if ((regmask_ret & (1 << xAX))
7530             && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7531           {
7532             ferr(po, "int func -> void func tailcall?\n");
7533           }
7534         }
7535         if (pp->is_noreturn)
7536           strcat(g_comment, " noreturn");
7537         if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7538           strcat(g_comment, " argframe");
7539         if (po->flags & OPF_CC)
7540           strcat(g_comment, " cond");
7541
7542         if (po->flags & OPF_CC)
7543           fprintf(fout, "\n  }");
7544
7545         delayed_flag_op = NULL;
7546         last_arith_dst = NULL;
7547         break;
7548
7549       case OP_RET:
7550         if (g_func_pp->is_vararg)
7551           fprintf(fout, "  va_end(ap);\n");
7552         if (g_func_pp->has_retreg) {
7553           for (arg = 0; arg < g_func_pp->argc; arg++)
7554             if (g_func_pp->arg[arg].type.is_retreg)
7555               fprintf(fout, "  *r_%s = %s;\n",
7556                 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7557         }
7558  
7559         if (regmask_ret & mxST0) {
7560           fprintf(fout, "  return %s;", float_st0);
7561         }
7562         else if (!(regmask_ret & mxAX)) {
7563           if (i != opcnt - 1 || label_pending)
7564             fprintf(fout, "  return;");
7565         }
7566         else if (g_func_pp->ret_type.is_ptr) {
7567           fprintf(fout, "  return (%s)eax;",
7568             g_func_pp->ret_type.name);
7569         }
7570         else if (IS(g_func_pp->ret_type.name, "__int64"))
7571           fprintf(fout, "  return ((u64)edx << 32) | eax;");
7572         else
7573           fprintf(fout, "  return eax;");
7574
7575         last_arith_dst = NULL;
7576         delayed_flag_op = NULL;
7577         break;
7578
7579       case OP_PUSH:
7580         out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7581         if (po->p_argnum != 0) {
7582           // special case - saved func arg
7583           fprintf(fout, "  %s = %s;",
7584             saved_arg_name(buf2, sizeof(buf2),
7585               po->p_arggrp, po->p_argnum), buf1);
7586           break;
7587         }
7588         else if (po->flags & OPF_RSAVE) {
7589           fprintf(fout, "  s_%s = %s;", buf1, buf1);
7590           break;
7591         }
7592         else if (po->flags & OPF_PPUSH) {
7593           tmp_op = po->datap;
7594           ferr_assert(po, tmp_op != NULL);
7595           out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7596           fprintf(fout, "  pp_%s = %s;", buf2, buf1);
7597           break;
7598         }
7599         else if (g_func_pp->is_userstack) {
7600           fprintf(fout, "  *(--esp) = %s;", buf1);
7601           break;
7602         }
7603         if (!(g_ida_func_attr & IDAFA_NORETURN))
7604           ferr(po, "stray push encountered\n");
7605         no_output = 1;
7606         break;
7607
7608       case OP_POP:
7609         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7610         if (po->flags & OPF_RSAVE) {
7611           fprintf(fout, "  %s = s_%s;", buf1, buf1);
7612           break;
7613         }
7614         else if (po->flags & OPF_PPUSH) {
7615           // push/pop graph / non-const
7616           ferr_assert(po, po->datap == NULL);
7617           fprintf(fout, "  %s = pp_%s;", buf1, buf1);
7618           break;
7619         }
7620         else if (po->datap != NULL) {
7621           // push/pop pair
7622           tmp_op = po->datap;
7623           fprintf(fout, "  %s = %s;", buf1,
7624             out_src_opr(buf2, sizeof(buf2),
7625               tmp_op, &tmp_op->operand[0],
7626               default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7627           break;
7628         }
7629         else if (g_func_pp->is_userstack) {
7630           fprintf(fout, "  %s = *esp++;", buf1);
7631           break;
7632         }
7633         else
7634           ferr(po, "stray pop encountered\n");
7635         break;
7636
7637       case OP_NOP:
7638         no_output = 1;
7639         break;
7640
7641       // pseudo ops
7642       case OPP_ALLSHL:
7643       case OPP_ALLSHR:
7644         fprintf(fout, "  tmp64 = ((u64)edx << 32) | eax;\n");
7645         fprintf(fout, "  tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7646           po->op == OPP_ALLSHL ? "<<" : ">>");
7647         fprintf(fout, "  edx = tmp64 >> 32; eax = tmp64;");
7648         strcat(g_comment, po->op == OPP_ALLSHL
7649           ? " allshl" : " allshr");
7650         break;
7651
7652       // x87
7653       case OP_FLD:
7654         if (need_float_stack) {
7655           out_src_opr_float(buf1, sizeof(buf1),
7656             po, &po->operand[0], 1);
7657           if (po->regmask_src & mxSTa) {
7658             fprintf(fout, "  f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7659               buf1);
7660           }
7661           else
7662             fprintf(fout, "  f_st[--f_stp & 7] = %s;", buf1);
7663         }
7664         else {
7665           if (po->flags & OPF_FSHIFT)
7666             fprintf(fout, "  f_st1 = f_st0;");
7667           if (po->operand[0].type == OPT_REG
7668             && po->operand[0].reg == xST0)
7669           {
7670             strcat(g_comment, " fld st");
7671             break;
7672           }
7673           fprintf(fout, "  f_st0 = %s;",
7674             out_src_opr_float(buf1, sizeof(buf1),
7675               po, &po->operand[0], 0));
7676         }
7677         strcat(g_comment, " fld");
7678         break;
7679
7680       case OP_FILD:
7681         out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7682           lmod_cast(po, po->operand[0].lmod, 1), 0);
7683         snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7684         if (need_float_stack) {
7685           fprintf(fout, "  f_st[--f_stp & 7] = %s;", buf2);
7686         }
7687         else {
7688           if (po->flags & OPF_FSHIFT)
7689             fprintf(fout, "  f_st1 = f_st0;");
7690           fprintf(fout, "  f_st0 = %s;", buf2);
7691         }
7692         strcat(g_comment, " fild");
7693         break;
7694
7695       case OP_FLDc:
7696         if (need_float_stack)
7697           fprintf(fout, "  f_st[--f_stp & 7] = ");
7698         else {
7699           if (po->flags & OPF_FSHIFT)
7700             fprintf(fout, "  f_st1 = f_st0;");
7701           fprintf(fout, "  f_st0 = ");
7702         }
7703         switch (po->operand[0].val) {
7704         case X87_CONST_1:   fprintf(fout, "1.0;"); break;
7705         case X87_CONST_L2T: fprintf(fout, "3.321928094887362;"); break;
7706         case X87_CONST_L2E: fprintf(fout, "M_LOG2E;"); break;
7707         case X87_CONST_PI:  fprintf(fout, "M_PI;"); break;
7708         case X87_CONST_LG2: fprintf(fout, "0.301029995663981;"); break;
7709         case X87_CONST_LN2: fprintf(fout, "M_LN2;"); break;
7710         case X87_CONST_Z:   fprintf(fout, "0.0;"); break;
7711         default: ferr_assert(po, 0); break;
7712         }
7713         break;
7714
7715       case OP_FST:
7716         if (po->flags & OPF_FARG) {
7717           // store to stack as func arg
7718           snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7719           dead_dst = 0;
7720         }
7721         else {
7722           out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7723             need_float_stack);
7724           dead_dst = po->operand[0].type == OPT_REG
7725             && po->operand[0].reg == xST0;
7726         }
7727         if (!dead_dst)
7728           fprintf(fout, "  %s = %s;", buf1, float_st0);
7729         if (po->flags & OPF_FSHIFT) {
7730           if (need_float_stack)
7731             fprintf(fout, "  f_stp++;");
7732           else
7733             fprintf(fout, "  f_st0 = f_st1;");
7734         }
7735         if (dead_dst && !(po->flags & OPF_FSHIFT))
7736           no_output = 1;
7737         else
7738           strcat(g_comment, " fst");
7739         break;
7740
7741       case OP_FIST:
7742         fprintf(fout, "  %s = %s%s;",
7743           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7744             lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7745         if (po->flags & OPF_FSHIFT) {
7746           if (need_float_stack)
7747             fprintf(fout, "  f_stp++;");
7748           else
7749             fprintf(fout, "  f_st0 = f_st1;");
7750         }
7751         strcat(g_comment, " fist");
7752         break;
7753
7754       case OP_FADD:
7755       case OP_FDIV:
7756       case OP_FMUL:
7757       case OP_FSUB:
7758         out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7759           need_float_stack);
7760         out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7761           need_float_stack);
7762         dead_dst = (po->flags & OPF_FPOP)
7763           && po->operand[0].type == OPT_REG
7764           && po->operand[0].reg == xST0;
7765         switch (po->op) {
7766         case OP_FADD: j = '+'; break;
7767         case OP_FDIV: j = '/'; break;
7768         case OP_FMUL: j = '*'; break;
7769         case OP_FSUB: j = '-'; break;
7770         default: j = 'x'; break;
7771         }
7772         if (need_float_stack) {
7773           if (!dead_dst)
7774             fprintf(fout, "  %s %c= %s;", buf1, j, buf2);
7775           if (po->flags & OPF_FSHIFT)
7776             fprintf(fout, "  f_stp++;");
7777         }
7778         else {
7779           if (po->flags & OPF_FSHIFT) {
7780             // note: assumes only 2 regs handled
7781             if (!dead_dst)
7782               fprintf(fout, "  f_st0 = f_st1 %c f_st0;", j);
7783             else
7784               fprintf(fout, "  f_st0 = f_st1;");
7785           }
7786           else if (!dead_dst)
7787             fprintf(fout, "  %s %c= %s;", buf1, j, buf2);
7788         }
7789         no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7790         break;
7791
7792       case OP_FDIVR:
7793       case OP_FSUBR:
7794         out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7795           need_float_stack);
7796         out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7797           need_float_stack);
7798         out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7799           need_float_stack);
7800         dead_dst = (po->flags & OPF_FPOP)
7801           && po->operand[0].type == OPT_REG
7802           && po->operand[0].reg == xST0;
7803         j = po->op == OP_FDIVR ? '/' : '-';
7804         if (need_float_stack) {
7805           if (!dead_dst)
7806             fprintf(fout, "  %s = %s %c %s;", buf1, buf2, j, buf3);
7807           if (po->flags & OPF_FSHIFT)
7808             fprintf(fout, "  f_stp++;");
7809         }
7810         else {
7811           if (po->flags & OPF_FSHIFT) {
7812             if (!dead_dst)
7813               fprintf(fout, "  f_st0 = f_st0 %c f_st1;", j);
7814             else
7815               fprintf(fout, "  f_st0 = f_st1;");
7816           }
7817           else if (!dead_dst)
7818             fprintf(fout, "  %s = %s %c %s;", buf1, buf2, j, buf3);
7819         }
7820         no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7821         break;
7822
7823       case OP_FIADD:
7824       case OP_FIDIV:
7825       case OP_FIMUL:
7826       case OP_FISUB:
7827         switch (po->op) {
7828         case OP_FIADD: j = '+'; break;
7829         case OP_FIDIV: j = '/'; break;
7830         case OP_FIMUL: j = '*'; break;
7831         case OP_FISUB: j = '-'; break;
7832         default: j = 'x'; break;
7833         }
7834         fprintf(fout, "  %s %c= (%s)%s;", float_st0,
7835           j, float_type,
7836           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7837             lmod_cast(po, po->operand[0].lmod, 1), 0));
7838         break;
7839
7840       case OP_FIDIVR:
7841       case OP_FISUBR:
7842         fprintf(fout, "  %s = %s %c %s;", float_st0,
7843           out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7844             need_float_stack),
7845           po->op == OP_FIDIVR ? '/' : '-', float_st0);
7846         break;
7847
7848       case OP_FCOM: {
7849         int mask, z_check;
7850         ferr_assert(po, po->datap != NULL);
7851         mask = (long)po->datap & 0xffff;
7852         z_check = ((long)po->datap >> 16) & 1;
7853         out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7854           need_float_stack);
7855         if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
7856           fprintf(fout, "  f_sw = %s < %s ? 0x0100 : 0;",
7857             float_st0, buf1);
7858         }
7859         else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
7860           fprintf(fout, "  f_sw = %s == %s ? 0x4000 : 0;",
7861             float_st0, buf1);
7862         }
7863         else if (mask == 0x4100) { // C3, C0
7864           if (z_check) {
7865             fprintf(fout, "  f_sw = %s <= %s ? 0x4100 : 0;",
7866               float_st0, buf1);
7867             strcat(g_comment, " z_chk_det");
7868           }
7869           else {
7870             fprintf(fout, "  f_sw = %s == %s ? 0x4000 : "
7871                           "(%s < %s ? 0x0100 : 0);",
7872               float_st0, buf1, float_st0, buf1);
7873           }
7874         }
7875         else
7876           ferr(po, "unhandled sw mask: %x\n", mask);
7877         if (po->flags & OPF_FSHIFT) {
7878           if (need_float_stack) {
7879             if (po->flags & OPF_FPOPP)
7880               fprintf(fout, " f_stp += 2;");
7881             else
7882               fprintf(fout, " f_stp++;");
7883           }
7884           else {
7885             ferr_assert(po, !(po->flags & OPF_FPOPP));
7886             fprintf(fout, " f_st0 = f_st1;");
7887           }
7888         }
7889         break;
7890       }
7891
7892       case OP_FNSTSW:
7893         fprintf(fout, "  %s = f_sw;",
7894           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7895         break;
7896
7897       case OP_FCHS:
7898         fprintf(fout, "  %s = -%s;", float_st0, float_st0);
7899         break;
7900
7901       case OP_FCOS:
7902         fprintf(fout, "  %s = cos%s(%s);", float_st0,
7903           need_double ? "" : "f", float_st0);
7904         break;
7905
7906       case OP_FPATAN:
7907         if (need_float_stack) {
7908           fprintf(fout, "  %s = atan%s(%s / %s);", float_st1,
7909             need_double ? "" : "f", float_st1, float_st0);
7910           fprintf(fout, " f_stp++;");
7911         }
7912         else {
7913           fprintf(fout, "  f_st0 = atan%s(f_st1 / f_st0);",
7914             need_double ? "" : "f");
7915         }
7916         break;
7917
7918       case OP_FYL2X:
7919         if (need_float_stack) {
7920           fprintf(fout, "  %s = %s * log2%s(%s);", float_st1,
7921             float_st1, need_double ? "" : "f", float_st0);
7922           fprintf(fout, " f_stp++;");
7923         }
7924         else {
7925           fprintf(fout, "  f_st0 = f_st1 * log2%s(f_st0);",
7926             need_double ? "" : "f");
7927         }
7928         strcat(g_comment, " fyl2x");
7929         break;
7930
7931       case OP_FSIN:
7932         fprintf(fout, "  %s = sin%s(%s);", float_st0,
7933           need_double ? "" : "f", float_st0);
7934         break;
7935
7936       case OP_FSQRT:
7937         fprintf(fout, "  %s = sqrt%s(%s);", float_st0,
7938           need_double ? "" : "f", float_st0);
7939         break;
7940
7941       case OP_FXCH:
7942         dead_dst = po->operand[0].type == OPT_REG
7943           && po->operand[0].reg == xST0;
7944         if (!dead_dst) {
7945           out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7946             need_float_stack);
7947           fprintf(fout, "  { %s t = %s; %s = %s; %s = t; }", float_type,
7948             float_st0, float_st0, buf1, buf1);
7949           strcat(g_comment, " fxch");
7950         }
7951         else
7952           no_output = 1;
7953         break;
7954
7955       case OPP_FTOL:
7956         ferr_assert(po, po->flags & OPF_32BIT);
7957         fprintf(fout, "  eax = (s32)%s;", float_st0);
7958         if (po->flags & OPF_FSHIFT) {
7959           if (need_float_stack)
7960             fprintf(fout, " f_stp++;");
7961           else
7962             fprintf(fout, " f_st0 = f_st1;");
7963         }
7964         strcat(g_comment, " ftol");
7965         break;
7966
7967       case OPP_CIPOW:
7968         if (need_float_stack) {
7969           fprintf(fout, "  %s = pow%s(%s, %s);", float_st1,
7970             need_double ? "" : "f", float_st1, float_st0);
7971           fprintf(fout, " f_stp++;");
7972         }
7973         else {
7974           fprintf(fout, "  f_st0 = pow%s(f_st1, f_st0);",
7975             need_double ? "" : "f");
7976         }
7977         strcat(g_comment, " CIpow");
7978         break;
7979
7980       case OPP_ABORT:
7981         fprintf(fout, "  do_skip_code_abort();");
7982         break;
7983
7984       // mmx
7985       case OP_EMMS:
7986         fprintf(fout, "  do_emms();");
7987         break;
7988
7989       default:
7990         no_output = 1;
7991         ferr(po, "unhandled op type %d, flags %x\n",
7992           po->op, po->flags);
7993         break;
7994     }
7995
7996     if (g_comment[0] != 0) {
7997       char *p = g_comment;
7998       while (my_isblank(*p))
7999         p++;
8000       fprintf(fout, "  // %s", p);
8001       g_comment[0] = 0;
8002       no_output = 0;
8003     }
8004     if (!no_output)
8005       fprintf(fout, "\n");
8006
8007     // some sanity checking
8008     if (po->flags & OPF_REP) {
8009       if (po->op != OP_STOS && po->op != OP_MOVS
8010           && po->op != OP_CMPS && po->op != OP_SCAS)
8011         ferr(po, "unexpected rep\n");
8012       if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
8013           && (po->op == OP_CMPS || po->op == OP_SCAS))
8014         ferr(po, "cmps/scas with plain rep\n");
8015     }
8016     if ((po->flags & (OPF_REPZ|OPF_REPNZ))
8017         && po->op != OP_CMPS && po->op != OP_SCAS)
8018       ferr(po, "unexpected repz/repnz\n");
8019
8020     if (pfomask != 0)
8021       ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
8022
8023     // see is delayed flag stuff is still valid
8024     if (delayed_flag_op != NULL && delayed_flag_op != po) {
8025       if (is_any_opr_modified(delayed_flag_op, po, 0))
8026         delayed_flag_op = NULL;
8027     }
8028
8029     if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
8030       if (is_opr_modified(last_arith_dst, po))
8031         last_arith_dst = NULL;
8032     }
8033
8034     if (!no_output)
8035       label_pending = 0;
8036   }
8037
8038   if (g_stack_fsz && !g_stack_frame_used)
8039     fprintf(fout, "  (void)sf;\n");
8040
8041   fprintf(fout, "}\n\n");
8042
8043   gen_x_cleanup(opcnt);
8044 }
8045
8046 static void gen_x_cleanup(int opcnt)
8047 {
8048   int i;
8049
8050   for (i = 0; i < opcnt; i++) {
8051     struct label_ref *lr, *lr_del;
8052
8053     lr = g_label_refs[i].next;
8054     while (lr != NULL) {
8055       lr_del = lr;
8056       lr = lr->next;
8057       free(lr_del);
8058     }
8059     g_label_refs[i].i = -1;
8060     g_label_refs[i].next = NULL;
8061
8062     if (ops[i].op == OP_CALL) {
8063       if (ops[i].pp)
8064         proto_release(ops[i].pp);
8065     }
8066   }
8067   g_func_pp = NULL;
8068 }
8069
8070 struct func_proto_dep;
8071
8072 struct func_prototype {
8073   char name[NAMELEN];
8074   int id;
8075   int argc_stack;
8076   int regmask_dep;
8077   int has_ret:3;                 // -1, 0, 1: unresolved, no, yes
8078   unsigned int dep_resolved:1;
8079   unsigned int is_stdcall:1;
8080   struct func_proto_dep *dep_func;
8081   int dep_func_cnt;
8082   const struct parsed_proto *pp; // seed pp, if any
8083 };
8084
8085 struct func_proto_dep {
8086   char *name;
8087   struct func_prototype *proto;
8088   int regmask_live;             // .. at the time of call
8089   unsigned int ret_dep:1;       // return from this is caller's return
8090 };
8091
8092 static struct func_prototype *hg_fp;
8093 static int hg_fp_cnt;
8094
8095 static struct scanned_var {
8096   char name[NAMELEN];
8097   enum opr_lenmod lmod;
8098   unsigned int is_seeded:1;
8099   unsigned int is_c_str:1;
8100   const struct parsed_proto *pp; // seed pp, if any
8101 } *hg_vars;
8102 static int hg_var_cnt;
8103
8104 static char **hg_refs;
8105 static int hg_ref_cnt;
8106
8107 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8108   int count);
8109
8110 static struct func_prototype *hg_fp_add(const char *funcn)
8111 {
8112   struct func_prototype *fp;
8113
8114   if ((hg_fp_cnt & 0xff) == 0) {
8115     hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
8116     my_assert_not(hg_fp, NULL);
8117     memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
8118   }
8119
8120   fp = &hg_fp[hg_fp_cnt];
8121   snprintf(fp->name, sizeof(fp->name), "%s", funcn);
8122   fp->id = hg_fp_cnt;
8123   fp->argc_stack = -1;
8124   hg_fp_cnt++;
8125
8126   return fp;
8127 }
8128
8129 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
8130   const char *name)
8131 {
8132   int i;
8133
8134   for (i = 0; i < fp->dep_func_cnt; i++)
8135     if (IS(fp->dep_func[i].name, name))
8136       return &fp->dep_func[i];
8137
8138   return NULL;
8139 }
8140
8141 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
8142 {
8143   // is it a dupe?
8144   if (hg_fp_find_dep(fp, name))
8145     return;
8146
8147   if ((fp->dep_func_cnt & 0xff) == 0) {
8148     fp->dep_func = realloc(fp->dep_func,
8149       sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
8150     my_assert_not(fp->dep_func, NULL);
8151     memset(&fp->dep_func[fp->dep_func_cnt], 0,
8152       sizeof(fp->dep_func[0]) * 0x100);
8153   }
8154   fp->dep_func[fp->dep_func_cnt].name = strdup(name);
8155   fp->dep_func_cnt++;
8156 }
8157
8158 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
8159 {
8160   const struct func_prototype *p1 = p1_, *p2 = p2_;
8161   return strcmp(p1->name, p2->name);
8162 }
8163
8164 #if 0
8165 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
8166 {
8167   const struct func_prototype *p1 = p1_, *p2 = p2_;
8168   return p1->id - p2->id;
8169 }
8170 #endif
8171
8172 static void hg_ref_add(const char *name)
8173 {
8174   if ((hg_ref_cnt & 0xff) == 0) {
8175     hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8176     my_assert_not(hg_refs, NULL);
8177     memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8178   }
8179
8180   hg_refs[hg_ref_cnt] = strdup(name);
8181   my_assert_not(hg_refs[hg_ref_cnt], NULL);
8182   hg_ref_cnt++;
8183 }
8184
8185 // recursive register dep pass
8186 // - track saved regs (part 2)
8187 // - try to figure out arg-regs
8188 // - calculate reg deps
8189 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8190   struct func_prototype *fp, int regmask_save, int regmask_dst,
8191   int *regmask_dep, int *has_ret)
8192 {
8193   struct func_proto_dep *dep;
8194   struct parsed_op *po;
8195   int from_caller = 0;
8196   int j, l;
8197   int reg;
8198   int ret;
8199
8200   for (; i < opcnt; i++)
8201   {
8202     if (cbits[i >> 3] & (1 << (i & 7)))
8203       return;
8204     cbits[i >> 3] |= (1 << (i & 7));
8205
8206     po = &ops[i];
8207
8208     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8209       if (po->flags & OPF_RMD)
8210         continue;
8211
8212       if (po->btj != NULL) {
8213         // jumptable
8214         for (j = 0; j < po->btj->count; j++) {
8215           check_i(po, po->btj->d[j].bt_i);
8216           gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8217             regmask_save, regmask_dst, regmask_dep, has_ret);
8218         }
8219         return;
8220       }
8221
8222       check_i(po, po->bt_i);
8223       if (po->flags & OPF_CJMP) {
8224         gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8225           regmask_save, regmask_dst, regmask_dep, has_ret);
8226       }
8227       else {
8228         i = po->bt_i - 1;
8229       }
8230       continue;
8231     }
8232
8233     if (po->flags & OPF_FARG)
8234       /* (just calculate register deps) */;
8235     else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8236     {
8237       reg = po->operand[0].reg;
8238       ferr_assert(po, reg >= 0);
8239
8240       if (po->flags & OPF_RSAVE) {
8241         regmask_save |= 1 << reg;
8242         continue;
8243       }
8244       if (po->flags & OPF_DONE)
8245         continue;
8246
8247       ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
8248       if (ret == 1) {
8249         regmask_save |= 1 << reg;
8250         po->flags |= OPF_RMD;
8251         scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
8252         continue;
8253       }
8254     }
8255     else if (po->flags & OPF_RMD)
8256       continue;
8257     else if (po->op == OP_CALL) {
8258       po->regmask_dst |= 1 << xAX;
8259
8260       dep = hg_fp_find_dep(fp, po->operand[0].name);
8261       if (dep != NULL) {
8262         dep->regmask_live = regmask_save | regmask_dst;
8263         if (g_bp_frame && !(po->flags & OPF_EBP_S))
8264           dep->regmask_live |= 1 << xBP;
8265       }
8266     }
8267     else if (po->op == OP_RET) {
8268       if (po->operand_cnt > 0) {
8269         fp->is_stdcall = 1;
8270         if (fp->argc_stack >= 0
8271             && fp->argc_stack != po->operand[0].val / 4)
8272           ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8273         fp->argc_stack = po->operand[0].val / 4;
8274       }
8275     }
8276
8277     // if has_ret is 0, there is uninitialized eax path,
8278     // which means it's most likely void func
8279     if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
8280       if (po->op == OP_CALL) {
8281         j = i;
8282         ret = 1;
8283       }
8284       else {
8285         struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
8286         j = -1;
8287         from_caller = 0;
8288         ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
8289       }
8290
8291       if (ret != 1 && from_caller) {
8292         // unresolved eax - probably void func
8293         *has_ret = 0;
8294       }
8295       else {
8296         if (j >= 0 && ops[j].op == OP_CALL) {
8297           dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8298           if (dep != NULL)
8299             dep->ret_dep = 1;
8300           else
8301             *has_ret = 1;
8302         }
8303         else
8304           *has_ret = 1;
8305       }
8306     }
8307
8308     l = regmask_save | regmask_dst;
8309     if (g_bp_frame && !(po->flags & OPF_EBP_S))
8310       l |= 1 << xBP;
8311
8312     l = po->regmask_src & ~l;
8313 #if 0
8314     if (l)
8315       fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8316         l, regmask_dst, regmask_save, po->flags);
8317 #endif
8318     *regmask_dep |= l;
8319     regmask_dst |= po->regmask_dst;
8320
8321     if (po->flags & OPF_TAIL)
8322       return;
8323   }
8324 }
8325
8326 static void gen_hdr(const char *funcn, int opcnt)
8327 {
8328   unsigned char cbits[MAX_OPS / 8];
8329   const struct parsed_proto *pp_c;
8330   struct parsed_proto *pp;
8331   struct func_prototype *fp;
8332   struct parsed_op *po;
8333   int regmask_dummy = 0;
8334   int regmask_dep;
8335   int max_bp_offset = 0;
8336   int has_ret;
8337   int i, j, l;
8338   int ret;
8339
8340   pp_c = proto_parse(g_fhdr, funcn, 1);
8341   if (pp_c != NULL)
8342     // already in seed, will add to hg_fp later
8343     return;
8344
8345   fp = hg_fp_add(funcn);
8346
8347   g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8348   g_stack_frame_used = 0;
8349   g_seh_size = 0;
8350
8351   // pass1:
8352   // - resolve all branches
8353   // - parse calls with labels
8354   resolve_branches_parse_calls(opcnt);
8355
8356   // pass2:
8357   // - handle ebp/esp frame, remove ops related to it
8358   scan_prologue_epilogue(opcnt, NULL);
8359
8360   // pass3:
8361   // - remove dead labels
8362   // - collect calls
8363   for (i = 0; i < opcnt; i++)
8364   {
8365     if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8366       free(g_labels[i]);
8367       g_labels[i] = NULL;
8368     }
8369
8370     po = &ops[i];
8371     if (po->flags & (OPF_RMD|OPF_DONE))
8372       continue;
8373
8374     if (po->op == OP_CALL) {
8375       if (po->operand[0].type == OPT_LABEL)
8376         hg_fp_add_dep(fp, opr_name(po, 0));
8377       else if (po->pp != NULL)
8378         hg_fp_add_dep(fp, po->pp->name);
8379     }
8380   }
8381
8382   // pass4:
8383   // - remove dead labels
8384   // - handle push <const>/pop pairs
8385   for (i = 0; i < opcnt; i++)
8386   {
8387     if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8388       free(g_labels[i]);
8389       g_labels[i] = NULL;
8390     }
8391
8392     po = &ops[i];
8393     if (po->flags & (OPF_RMD|OPF_DONE))
8394       continue;
8395
8396     if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8397       scan_for_pop_const(i, opcnt, i + opcnt * 13);
8398   }
8399
8400   // pass5:
8401   // - process trivial calls
8402   for (i = 0; i < opcnt; i++)
8403   {
8404     po = &ops[i];
8405     if (po->flags & (OPF_RMD|OPF_DONE))
8406       continue;
8407
8408     if (po->op == OP_CALL)
8409     {
8410       pp = process_call_early(i, opcnt, &j);
8411       if (pp != NULL) {
8412         if (!(po->flags & OPF_ATAIL))
8413           // since we know the args, try to collect them
8414           if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8415             pp = NULL;
8416       }
8417
8418       if (pp != NULL) {
8419         if (j >= 0) {
8420           // commit esp adjust
8421           if (ops[j].op != OP_POP)
8422             patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8423           else {
8424             for (l = 0; l < pp->argc_stack; l++)
8425               ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8426           }
8427         }
8428
8429         po->flags |= OPF_DONE;
8430       }
8431     }
8432   }
8433
8434   // pass6:
8435   // - track saved regs (simple)
8436   // - process calls
8437   for (i = 0; i < opcnt; i++)
8438   {
8439     po = &ops[i];
8440     if (po->flags & (OPF_RMD|OPF_DONE))
8441       continue;
8442
8443     if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8444       && po->operand[0].reg != xCX)
8445     {
8446       ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8447       if (ret == 1) {
8448         // regmask_save |= 1 << po->operand[0].reg; // do it later
8449         po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8450         scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8451       }
8452     }
8453     else if (po->op == OP_CALL)
8454     {
8455       pp = process_call(i, opcnt);
8456
8457       if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8458         // since we know the args, collect them
8459         ret = collect_call_args(po, i, pp, &regmask_dummy,
8460                 i + opcnt * 1);
8461       }
8462     }
8463   }
8464
8465   // pass7
8466   memset(cbits, 0, sizeof(cbits));
8467   regmask_dep = 0;
8468   has_ret = -1;
8469
8470   gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, &regmask_dep, &has_ret);
8471
8472   // find unreachable code - must be fixed in IDA
8473   for (i = 0; i < opcnt; i++)
8474   {
8475     if (cbits[i >> 3] & (1 << (i & 7)))
8476       continue;
8477
8478     if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8479       && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8480     {
8481       // the compiler sometimes still generates code after
8482       // noreturn OS functions
8483       break;
8484     }
8485     if (!(ops[i].flags & OPF_RMD)
8486         && ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8487     {
8488       ferr(&ops[i], "unreachable code\n");
8489     }
8490   }
8491
8492   for (i = 0; i < g_eqcnt; i++) {
8493     if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8494       max_bp_offset = g_eqs[i].offset;
8495   }
8496
8497   if (fp->argc_stack < 0) {
8498     max_bp_offset = (max_bp_offset + 3) & ~3;
8499     fp->argc_stack = max_bp_offset / 4;
8500     if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8501       fp->argc_stack--;
8502   }
8503
8504   fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8505   fp->has_ret = has_ret;
8506 #if 0
8507   printf("// has_ret %d, regmask_dep %x\n",
8508     fp->has_ret, fp->regmask_dep);
8509   output_hdr_fp(stdout, fp, 1);
8510   if (IS(funcn, "sub_10007F72")) exit(1);
8511 #endif
8512
8513   gen_x_cleanup(opcnt);
8514 }
8515
8516 static void hg_fp_resolve_deps(struct func_prototype *fp)
8517 {
8518   struct func_prototype fp_s;
8519   int dep;
8520   int i;
8521
8522   // this thing is recursive, so mark first..
8523   fp->dep_resolved = 1;
8524
8525   for (i = 0; i < fp->dep_func_cnt; i++) {
8526     strcpy(fp_s.name, fp->dep_func[i].name);
8527     fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8528       sizeof(hg_fp[0]), hg_fp_cmp_name);
8529     if (fp->dep_func[i].proto != NULL) {
8530       if (!fp->dep_func[i].proto->dep_resolved)
8531         hg_fp_resolve_deps(fp->dep_func[i].proto);
8532
8533       dep = ~fp->dep_func[i].regmask_live
8534            & fp->dep_func[i].proto->regmask_dep;
8535       fp->regmask_dep |= dep;
8536       // printf("dep %s %s |= %x\n", fp->name,
8537       //   fp->dep_func[i].name, dep);
8538
8539       if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8540         fp->has_ret = fp->dep_func[i].proto->has_ret;
8541     }
8542   }
8543 }
8544
8545 // make all thiscall/edx arg functions referenced from .data fastcall
8546 static void do_func_refs_from_data(void)
8547 {
8548   struct func_prototype *fp, fp_s;
8549   int i;
8550
8551   for (i = 0; i < hg_ref_cnt; i++) {
8552     strcpy(fp_s.name, hg_refs[i]);
8553     fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8554       sizeof(hg_fp[0]), hg_fp_cmp_name);
8555     if (fp == NULL)
8556       continue;
8557
8558     if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8559       fp->regmask_dep |= mxCX | mxDX;
8560   }
8561 }
8562
8563 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8564   int count)
8565 {
8566   const struct parsed_proto *pp;
8567   char *p, namebuf[NAMELEN];
8568   const char *name;
8569   int regmask_dep;
8570   int argc_normal;
8571   int j, arg;
8572
8573   for (; count > 0; count--, fp++) {
8574     if (fp->has_ret == -1)
8575       fprintf(fout, "// ret unresolved\n");
8576 #if 0
8577     fprintf(fout, "// dep:");
8578     for (j = 0; j < fp->dep_func_cnt; j++) {
8579       fprintf(fout, " %s/", fp->dep_func[j].name);
8580       if (fp->dep_func[j].proto != NULL)
8581         fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8582           fp->dep_func[j].proto->has_ret);
8583     }
8584     fprintf(fout, "\n");
8585 #endif
8586
8587     p = strchr(fp->name, '@');
8588     if (p != NULL) {
8589       memcpy(namebuf, fp->name, p - fp->name);
8590       namebuf[p - fp->name] = 0;
8591       name = namebuf;
8592     }
8593     else
8594       name = fp->name;
8595     if (name[0] == '_')
8596       name++;
8597
8598     pp = proto_parse(g_fhdr, name, 1);
8599     if (pp != NULL && pp->is_include)
8600       continue;
8601
8602     if (fp->pp != NULL) {
8603       // part of seed, output later
8604       continue;
8605     }
8606
8607     regmask_dep = fp->regmask_dep;
8608     argc_normal = fp->argc_stack;
8609
8610     fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8611       (fp->has_ret ? "int" : "void"));
8612     if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8613       && (regmask_dep & ~mxCX) == 0)
8614     {
8615       fprintf(fout, "/*__thiscall*/  ");
8616       argc_normal++;
8617       regmask_dep = 0;
8618     }
8619     else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8620       && (regmask_dep & ~(mxCX | mxDX)) == 0)
8621     {
8622       fprintf(fout, "  __fastcall    ");
8623       if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8624         argc_normal = 1;
8625       else
8626         argc_normal += 2;
8627       regmask_dep = 0;
8628     }
8629     else if (regmask_dep && !fp->is_stdcall) {
8630       fprintf(fout, "/*__usercall*/  ");
8631     }
8632     else if (regmask_dep) {
8633       fprintf(fout, "/*__userpurge*/ ");
8634     }
8635     else if (fp->is_stdcall)
8636       fprintf(fout, "  __stdcall     ");
8637     else
8638       fprintf(fout, "  __cdecl       ");
8639
8640     fprintf(fout, "%s(", name);
8641
8642     arg = 0;
8643     for (j = 0; j < xSP; j++) {
8644       if (regmask_dep & (1 << j)) {
8645         arg++;
8646         if (arg != 1)
8647           fprintf(fout, ", ");
8648         if (fp->pp != NULL)
8649           fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8650         else
8651           fprintf(fout, "int");
8652         fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8653       }
8654     }
8655
8656     for (j = 0; j < argc_normal; j++) {
8657       arg++;
8658       if (arg != 1)
8659         fprintf(fout, ", ");
8660       if (fp->pp != NULL) {
8661         fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8662         if (!fp->pp->arg[arg - 1].type.is_ptr)
8663           fprintf(fout, " ");
8664       }
8665       else
8666         fprintf(fout, "int ");
8667       fprintf(fout, "a%d", arg);
8668     }
8669
8670     fprintf(fout, ");\n");
8671   }
8672 }
8673
8674 static void output_hdr(FILE *fout)
8675 {
8676   static const char *lmod_c_names[] = {
8677     [OPLM_UNSPEC] = "???",
8678     [OPLM_BYTE]  = "uint8_t",
8679     [OPLM_WORD]  = "uint16_t",
8680     [OPLM_DWORD] = "uint32_t",
8681     [OPLM_QWORD] = "uint64_t",
8682   };
8683   const struct scanned_var *var;
8684   struct func_prototype *fp;
8685   char line[256] = { 0, };
8686   char name[256];
8687   int i;
8688
8689   // add stuff from headers
8690   for (i = 0; i < pp_cache_size; i++) {
8691     if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8692       snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8693     else
8694       snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8695     fp = hg_fp_add(name);
8696     fp->pp = &pp_cache[i];
8697     fp->argc_stack = fp->pp->argc_stack;
8698     fp->is_stdcall = fp->pp->is_stdcall;
8699     fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8700     fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8701   }
8702
8703   // resolve deps
8704   qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8705   for (i = 0; i < hg_fp_cnt; i++)
8706     hg_fp_resolve_deps(&hg_fp[i]);
8707
8708   // adjust functions referenced from data segment
8709   do_func_refs_from_data();
8710
8711   // note: messes up .proto ptr, don't use
8712   //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8713
8714   // output variables
8715   for (i = 0; i < hg_var_cnt; i++) {
8716     var = &hg_vars[i];
8717
8718     if (var->pp != NULL)
8719       // part of seed
8720       continue;
8721     else if (var->is_c_str)
8722       fprintf(fout, "extern %-8s %s[];", "char", var->name);
8723     else
8724       fprintf(fout, "extern %-8s %s;",
8725         lmod_c_names[var->lmod], var->name);
8726
8727     if (var->is_seeded)
8728       fprintf(fout, " // seeded");
8729     fprintf(fout, "\n");
8730   }
8731
8732   fprintf(fout, "\n");
8733
8734   // output function prototypes
8735   output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8736
8737   // seed passthrough
8738   fprintf(fout, "\n// - seed -\n");
8739
8740   rewind(g_fhdr);
8741   while (fgets(line, sizeof(line), g_fhdr))
8742     fwrite(line, 1, strlen(line), fout);
8743 }
8744
8745 // '=' needs special treatment
8746 // also ' quote
8747 static char *next_word_s(char *w, size_t wsize, char *s)
8748 {
8749   size_t i;
8750
8751   s = sskip(s);
8752
8753   i = 0;
8754   if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8755     w[0] = s[0];
8756     for (i = 1; i < wsize - 1; i++) {
8757       if (s[i] == 0) {
8758         printf("warning: missing closing quote: \"%s\"\n", s);
8759         break;
8760       }
8761       if (s[i] == '\'')
8762         break;
8763       w[i] = s[i];
8764     }
8765   }
8766
8767   for (; i < wsize - 1; i++) {
8768     if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8769       break;
8770     w[i] = s[i];
8771   }
8772   w[i] = 0;
8773
8774   if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8775     printf("warning: '%s' truncated\n", w);
8776
8777   return s + i;
8778 }
8779
8780 static int cmpstringp(const void *p1, const void *p2)
8781 {
8782   return strcmp(*(char * const *)p1, *(char * const *)p2);
8783 }
8784
8785 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8786 {
8787   char *p2;
8788
8789   p = sskip(p);
8790   if (strstr(p, "..."))
8791     // unable to determine, assume needed
8792     return 1;
8793
8794   if (*p == '.') // .text, .data, ...
8795     // ref from other data or non-function -> no
8796     return 0;
8797
8798   p2 = strpbrk(p, "+:\r\n\x18");
8799   if (p2 != NULL)
8800     *p2 = 0;
8801   if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8802     // referenced from removed code
8803     return 0;
8804
8805   return 1;
8806 }
8807
8808 static int ida_xrefs_show_need(FILE *fasm, char *p,
8809   char **rlist, int rlist_len)
8810 {
8811   int found_need = 0;
8812   char line[256];
8813   long pos;
8814
8815   p = strrchr(p, ';');
8816   if (p != NULL && *p == ';') {
8817     if (IS_START(p + 2, "sctref"))
8818       return 1;
8819     if (IS_START(p + 2, "DATA XREF: ")) {
8820       p += 13;
8821       if (is_xref_needed(p, rlist, rlist_len))
8822         return 1;
8823     }
8824   }
8825
8826   pos = ftell(fasm);
8827   while (1)
8828   {
8829     if (!my_fgets(line, sizeof(line), fasm))
8830       break;
8831     // non-first line is always indented
8832     if (!my_isblank(line[0]))
8833       break;
8834
8835     // should be no content, just comment
8836     p = sskip(line);
8837     if (*p != ';')
8838       break;
8839
8840     p = strrchr(p, ';');
8841     p += 2;
8842
8843     if (IS_START(p, "sctref")) {
8844       found_need = 1;
8845       break;
8846     }
8847
8848     // it's printed once, but no harm to check again
8849     if (IS_START(p, "DATA XREF: "))
8850       p += 11;
8851
8852     if (is_xref_needed(p, rlist, rlist_len)) {
8853       found_need = 1;
8854       break;
8855     }
8856   }
8857   fseek(fasm, pos, SEEK_SET);
8858   return found_need;
8859 }
8860
8861 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8862 {
8863   struct scanned_var *var;
8864   char line[256] = { 0, };
8865   char words[4][256];
8866   int no_identifier;
8867   char *p = NULL;
8868   int wordc;
8869   int l;
8870
8871   while (!feof(fasm))
8872   {
8873     // skip to next data section
8874     while (my_fgets(line, sizeof(line), fasm))
8875     {
8876       asmln++;
8877
8878       p = sskip(line);
8879       if (*p == 0 || *p == ';')
8880         continue;
8881
8882       p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8883       if (*p == 0 || *p == ';')
8884         continue;
8885
8886       if (*p != 's' || !IS_START(p, "segment para public"))
8887         continue;
8888
8889       break;
8890     }
8891
8892     if (p == NULL || !IS_START(p, "segment para public"))
8893       break;
8894     p = sskip(p + 19);
8895
8896     if (!IS_START(p, "'DATA'"))
8897       continue;
8898
8899     // now process it
8900     while (my_fgets(line, sizeof(line), fasm))
8901     {
8902       asmln++;
8903
8904       p = line;
8905       no_identifier = my_isblank(*p);
8906
8907       p = sskip(p);
8908       if (*p == 0 || *p == ';')
8909         continue;
8910
8911       for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8912         words[wordc][0] = 0;
8913         p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8914         if (*p == 0 || *p == ';') {
8915           wordc++;
8916           break;
8917         }
8918       }
8919
8920       if (wordc == 2 && IS(words[1], "ends"))
8921         break;
8922       if (wordc < 2)
8923         continue;
8924
8925       if (no_identifier) {
8926         if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8927           hg_ref_add(words[2]);
8928         continue;
8929       }
8930
8931       if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8932         // when this starts, we don't need anything from this section
8933         break;
8934       }
8935
8936       // check refs comment(s)
8937       if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8938         continue;
8939
8940       if ((hg_var_cnt & 0xff) == 0) {
8941         hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8942                    * (hg_var_cnt + 0x100));
8943         my_assert_not(hg_vars, NULL);
8944         memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8945       }
8946
8947       var = &hg_vars[hg_var_cnt++];
8948       snprintf(var->name, sizeof(var->name), "%s", words[0]);
8949
8950       // maybe already in seed header?
8951       var->pp = proto_parse(g_fhdr, var->name, 1);
8952       if (var->pp != NULL) {
8953         if (var->pp->is_fptr) {
8954           var->lmod = OPLM_DWORD;
8955           //var->is_ptr = 1;
8956         }
8957         else if (var->pp->is_func)
8958           aerr("func?\n");
8959         else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8960           aerr("unhandled C type '%s' for '%s'\n",
8961             var->pp->type.name, var->name);
8962
8963         var->is_seeded = 1;
8964         continue;
8965       }
8966
8967       if      (IS(words[1], "dd")) {
8968         var->lmod = OPLM_DWORD;
8969         if (wordc >= 4 && IS(words[2], "offset"))
8970           hg_ref_add(words[3]);
8971       }
8972       else if (IS(words[1], "dw"))
8973         var->lmod = OPLM_WORD;
8974       else if (IS(words[1], "db")) {
8975         var->lmod = OPLM_BYTE;
8976         if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8977           if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8978             var->is_c_str = 1;
8979         }
8980       }
8981       else if (IS(words[1], "dq"))
8982         var->lmod = OPLM_QWORD;
8983       //else if (IS(words[1], "dt"))
8984       else
8985         aerr("type '%s' not known\n", words[1]);
8986     }
8987   }
8988
8989   rewind(fasm);
8990   asmln = 0;
8991 }
8992
8993 static void set_label(int i, const char *name)
8994 {
8995   const char *p;
8996   int len;
8997
8998   len = strlen(name);
8999   p = strchr(name, ':');
9000   if (p != NULL)
9001     len = p - name;
9002
9003   if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
9004     aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
9005   g_labels[i] = realloc(g_labels[i], len + 1);
9006   my_assert_not(g_labels[i], NULL);
9007   memcpy(g_labels[i], name, len);
9008   g_labels[i][len] = 0;
9009 }
9010
9011 struct chunk_item {
9012   char *name;
9013   long fptr;
9014   int asmln;
9015 };
9016
9017 static struct chunk_item *func_chunks;
9018 static int func_chunk_cnt;
9019 static int func_chunk_alloc;
9020
9021 static void add_func_chunk(FILE *fasm, const char *name, int line)
9022 {
9023   if (func_chunk_cnt >= func_chunk_alloc) {
9024     func_chunk_alloc *= 2;
9025     func_chunks = realloc(func_chunks,
9026       func_chunk_alloc * sizeof(func_chunks[0]));
9027     my_assert_not(func_chunks, NULL);
9028   }
9029   func_chunks[func_chunk_cnt].fptr = ftell(fasm);
9030   func_chunks[func_chunk_cnt].name = strdup(name);
9031   func_chunks[func_chunk_cnt].asmln = line;
9032   func_chunk_cnt++;
9033 }
9034
9035 static int cmp_chunks(const void *p1, const void *p2)
9036 {
9037   const struct chunk_item *c1 = p1, *c2 = p2;
9038   return strcmp(c1->name, c2->name);
9039 }
9040
9041 static void scan_ahead_for_chunks(FILE *fasm)
9042 {
9043   char words[2][256];
9044   char line[256];
9045   long oldpos;
9046   int oldasmln;
9047   int wordc;
9048   char *p;
9049   int i;
9050
9051   oldpos = ftell(fasm);
9052   oldasmln = asmln;
9053
9054   while (my_fgets(line, sizeof(line), fasm))
9055   {
9056     wordc = 0;
9057     asmln++;
9058
9059     p = sskip(line);
9060     if (*p == 0)
9061       continue;
9062
9063     if (*p == ';')
9064     {
9065       // get rid of random tabs
9066       for (i = 0; line[i] != 0; i++)
9067         if (line[i] == '\t')
9068           line[i] = ' ';
9069
9070       if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9071       {
9072         p += 30;
9073         next_word(words[0], sizeof(words[0]), p);
9074         if (words[0][0] == 0)
9075           aerr("missing name for func chunk?\n");
9076
9077         add_func_chunk(fasm, words[0], asmln);
9078       }
9079       else if (IS_START(p, "; sctend"))
9080         break;
9081
9082       continue;
9083     } // *p == ';'
9084
9085     for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9086       words[wordc][0] = 0;
9087       p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9088       if (*p == 0 || *p == ';') {
9089         wordc++;
9090         break;
9091       }
9092     }
9093
9094     if (wordc == 2 && IS(words[1], "ends"))
9095       break;
9096   }
9097
9098   fseek(fasm, oldpos, SEEK_SET);
9099   asmln = oldasmln;
9100 }
9101
9102 int main(int argc, char *argv[])
9103 {
9104   FILE *fout, *fasm, *frlist;
9105   struct parsed_data *pd = NULL;
9106   int pd_alloc = 0;
9107   char **rlist = NULL;
9108   int rlist_len = 0;
9109   int rlist_alloc = 0;
9110   int func_chunks_used = 0;
9111   int func_chunks_sorted = 0;
9112   int func_chunk_i = -1;
9113   long func_chunk_ret = 0;
9114   int func_chunk_ret_ln = 0;
9115   int scanned_ahead = 0;
9116   char line[256];
9117   char words[20][256];
9118   enum opr_lenmod lmod;
9119   char *sctproto = NULL;
9120   int in_func = 0;
9121   int pending_endp = 0;
9122   int skip_code = 0;
9123   int skip_code_end = 0;
9124   int skip_warned = 0;
9125   int eq_alloc;
9126   int verbose = 0;
9127   int multi_seg = 0;
9128   int end = 0;
9129   int arg_out;
9130   int arg;
9131   int pi = 0;
9132   int i, j;
9133   int ret, len;
9134   char *p;
9135   int wordc;
9136
9137   for (arg = 1; arg < argc; arg++) {
9138     if (IS(argv[arg], "-v"))
9139       verbose = 1;
9140     else if (IS(argv[arg], "-rf"))
9141       g_allow_regfunc = 1;
9142     else if (IS(argv[arg], "-uc"))
9143       g_allow_user_icall = 1;
9144     else if (IS(argv[arg], "-m"))
9145       multi_seg = 1;
9146     else if (IS(argv[arg], "-hdr"))
9147       g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
9148     else
9149       break;
9150   }
9151
9152   if (argc < arg + 3) {
9153     printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
9154            "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
9155            "options:\n"
9156            "  -hdr - header generation mode\n"
9157            "  -rf  - allow unannotated indirect calls\n"
9158            "  -uc  - allow ind. calls/refs to __usercall\n"
9159            "  -m   - allow multiple .text sections\n"
9160            "[rlist] is a file with function names to skip,"
9161            " one per line\n",
9162       argv[0], argv[0]);
9163     return 1;
9164   }
9165
9166   arg_out = arg++;
9167
9168   asmfn = argv[arg++];
9169   fasm = fopen(asmfn, "r");
9170   my_assert_not(fasm, NULL);
9171
9172   hdrfn = argv[arg++];
9173   g_fhdr = fopen(hdrfn, "r");
9174   my_assert_not(g_fhdr, NULL);
9175
9176   rlist_alloc = 64;
9177   rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9178   my_assert_not(rlist, NULL);
9179   // needs special handling..
9180   rlist[rlist_len++] = "__alloca_probe";
9181
9182   func_chunk_alloc = 32;
9183   func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9184   my_assert_not(func_chunks, NULL);
9185
9186   memset(words, 0, sizeof(words));
9187
9188   for (; arg < argc; arg++) {
9189     int skip_func = 0;
9190
9191     frlist = fopen(argv[arg], "r");
9192     my_assert_not(frlist, NULL);
9193
9194     while (my_fgets(line, sizeof(line), frlist)) {
9195       p = sskip(line);
9196       if (*p == 0 || *p == ';')
9197         continue;
9198       if (*p == '#') {
9199         if (IS_START(p, "#if 0")
9200          || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9201         {
9202           skip_func = 1;
9203         }
9204         else if (IS_START(p, "#endif"))
9205           skip_func = 0;
9206         continue;
9207       }
9208       if (skip_func)
9209         continue;
9210
9211       p = next_word(words[0], sizeof(words[0]), p);
9212       if (words[0][0] == 0)
9213         continue;
9214
9215       if (rlist_len >= rlist_alloc) {
9216         rlist_alloc = rlist_alloc * 2 + 64;
9217         rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9218         my_assert_not(rlist, NULL);
9219       }
9220       rlist[rlist_len++] = strdup(words[0]);
9221     }
9222
9223     fclose(frlist);
9224     frlist = NULL;
9225   }
9226
9227   if (rlist_len > 0)
9228     qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9229
9230   fout = fopen(argv[arg_out], "w");
9231   my_assert_not(fout, NULL);
9232
9233   eq_alloc = 128;
9234   g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9235   my_assert_not(g_eqs, NULL);
9236
9237   for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9238     g_label_refs[i].i = -1;
9239     g_label_refs[i].next = NULL;
9240   }
9241
9242   if (g_header_mode)
9243     scan_variables(fasm, rlist, rlist_len);
9244
9245   while (my_fgets(line, sizeof(line), fasm))
9246   {
9247     wordc = 0;
9248     asmln++;
9249
9250     p = sskip(line);
9251     if (*p == 0)
9252       continue;
9253
9254     // get rid of random tabs
9255     for (i = 0; line[i] != 0; i++)
9256       if (line[i] == '\t')
9257         line[i] = ' ';
9258
9259     if (*p == ';')
9260     {
9261       if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9262         goto do_pending_endp; // eww..
9263
9264       if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9265       {
9266         static const char *attrs[] = {
9267           "bp-based frame",
9268           "library function",
9269           "static",
9270           "noreturn",
9271           "thunk",
9272           "fpd=",
9273         };
9274
9275         // parse IDA's attribute-list comment
9276         g_ida_func_attr = 0;
9277         p = sskip(p + 13);
9278
9279         for (; *p != 0; p = sskip(p)) {
9280           for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9281             if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9282               g_ida_func_attr |= 1 << i;
9283               p += strlen(attrs[i]);
9284               break;
9285             }
9286           }
9287           if (i == ARRAY_SIZE(attrs)) {
9288             anote("unparsed IDA attr: %s\n", p);
9289             break;
9290           }
9291           if (IS(attrs[i], "fpd=")) {
9292             p = next_word(words[0], sizeof(words[0]), p);
9293             // ignore for now..
9294           }
9295         }
9296       }
9297       else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9298       {
9299         static const char *attrs[] = {
9300           "clear_sf",
9301           "clear_regmask",
9302         };
9303
9304         // parse manual attribute-list comment
9305         g_sct_func_attr = 0;
9306         p = sskip(p + 10);
9307
9308         for (; *p != 0; p = sskip(p)) {
9309           for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9310             if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9311               g_sct_func_attr |= 1 << i;
9312               p += strlen(attrs[i]);
9313               break;
9314             }
9315           }
9316           if (*p == '=') {
9317             j = ret = 0;
9318             if (i == 0)
9319               // clear_sf=start,len (in dwords)
9320               ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9321                       &g_stack_clear_len, &j);
9322             else if (i == 1)
9323               // clear_regmask=<mask>
9324               ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9325             if (ret < 2) {
9326               anote("unparsed attr value: %s\n", p);
9327               break;
9328             }
9329             p += j;
9330           }
9331           else if (i == ARRAY_SIZE(attrs)) {
9332             anote("unparsed sct attr: %s\n", p);
9333             break;
9334           }
9335         }
9336       }
9337       else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9338       {
9339         p += 30;
9340         next_word(words[0], sizeof(words[0]), p);
9341         if (words[0][0] == 0)
9342           aerr("missing name for func chunk?\n");
9343
9344         if (!scanned_ahead) {
9345           add_func_chunk(fasm, words[0], asmln);
9346           func_chunks_sorted = 0;
9347         }
9348       }
9349       else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9350       {
9351         if (func_chunk_i >= 0) {
9352           if (func_chunk_i < func_chunk_cnt
9353             && IS(func_chunks[func_chunk_i].name, g_func))
9354           {
9355             // move on to next chunk
9356             ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9357             if (ret)
9358               aerr("seek failed for '%s' chunk #%d\n",
9359                 g_func, func_chunk_i);
9360             asmln = func_chunks[func_chunk_i].asmln;
9361             func_chunk_i++;
9362           }
9363           else {
9364             if (func_chunk_ret == 0)
9365               aerr("no return from chunk?\n");
9366             fseek(fasm, func_chunk_ret, SEEK_SET);
9367             asmln = func_chunk_ret_ln;
9368             func_chunk_ret = 0;
9369             pending_endp = 1;
9370           }
9371         }
9372       }
9373       else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9374         func_chunks_used = 1;
9375         p += 20;
9376         if (IS_START(g_func, "sub_")) {
9377           unsigned long addr = strtoul(p, NULL, 16);
9378           unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9379           if (addr > f_addr && !scanned_ahead) {
9380             //anote("scan_ahead caused by '%s', addr %lx\n",
9381             //  g_func, addr);
9382             scan_ahead_for_chunks(fasm);
9383             scanned_ahead = 1;
9384             func_chunks_sorted = 0;
9385           }
9386         }
9387       }
9388       continue;
9389     } // *p == ';'
9390
9391 parse_words:
9392     for (i = wordc; i < ARRAY_SIZE(words); i++)
9393       words[i][0] = 0;
9394     for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9395       p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9396       if (*p == 0 || *p == ';') {
9397         wordc++;
9398         break;
9399       }
9400     }
9401     if (*p != 0 && *p != ';')
9402       aerr("too many words\n");
9403
9404     if (skip_code_end) {
9405       skip_code_end = 0;
9406       skip_code = 0;
9407     }
9408
9409     // allow asm patches in comments
9410     if (*p == ';') {
9411       if (IS_START(p, "; sctpatch:")) {
9412         p = sskip(p + 11);
9413         if (*p == 0 || *p == ';')
9414           continue;
9415         goto parse_words; // lame
9416       }
9417       if (IS_START(p, "; sctproto:")) {
9418         sctproto = strdup(p + 11);
9419       }
9420       else if (IS_START(p, "; sctend")) {
9421         end = 1;
9422         if (!pending_endp)
9423           break;
9424       }
9425       else if (IS_START(p, "; sctskip_start")) {
9426         if (in_func && !g_skip_func) {
9427           if (!skip_code) {
9428             ops[pi].op = OPP_ABORT;
9429             ops[pi].asmln = asmln;
9430             pi++;
9431           }
9432           skip_code = 1;
9433         }
9434       }
9435       else if (IS_START(p, "; sctskip_end")) {
9436         if (skip_code)
9437           skip_code_end = 1;
9438       }
9439     }
9440
9441     if (wordc == 0) {
9442       // shouldn't happen
9443       awarn("wordc == 0?\n");
9444       continue;
9445     }
9446
9447     // don't care about this:
9448     if (words[0][0] == '.'
9449         || IS(words[0], "include")
9450         || IS(words[0], "assume") || IS(words[1], "segment")
9451         || IS(words[0], "align"))
9452     {
9453       continue;
9454     }
9455
9456 do_pending_endp:
9457     // do delayed endp processing to collect switch jumptables
9458     if (pending_endp) {
9459       if (in_func && !g_skip_func && !end && wordc >= 2
9460           && ((words[0][0] == 'd' && words[0][2] == 0)
9461               || (words[1][0] == 'd' && words[1][2] == 0)))
9462       {
9463         i = 1;
9464         if (words[1][0] == 'd' && words[1][2] == 0) {
9465           // label
9466           if (g_func_pd_cnt >= pd_alloc) {
9467             pd_alloc = pd_alloc * 2 + 16;
9468             g_func_pd = realloc(g_func_pd,
9469               sizeof(g_func_pd[0]) * pd_alloc);
9470             my_assert_not(g_func_pd, NULL);
9471           }
9472           pd = &g_func_pd[g_func_pd_cnt];
9473           g_func_pd_cnt++;
9474           memset(pd, 0, sizeof(*pd));
9475           strcpy(pd->label, words[0]);
9476           pd->type = OPT_CONST;
9477           pd->lmod = lmod_from_directive(words[1]);
9478           i = 2;
9479         }
9480         else {
9481           if (pd == NULL) {
9482             if (verbose)
9483               anote("skipping alignment byte?\n");
9484             continue;
9485           }
9486           lmod = lmod_from_directive(words[0]);
9487           if (lmod != pd->lmod)
9488             aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9489         }
9490
9491         if (pd->count_alloc < pd->count + wordc) {
9492           pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9493           pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9494           my_assert_not(pd->d, NULL);
9495         }
9496         for (; i < wordc; i++) {
9497           if (IS(words[i], "offset")) {
9498             pd->type = OPT_OFFSET;
9499             i++;
9500           }
9501           p = strchr(words[i], ',');
9502           if (p != NULL)
9503             *p = 0;
9504           if (pd->type == OPT_OFFSET)
9505             pd->d[pd->count].u.label = strdup(words[i]);
9506           else
9507             pd->d[pd->count].u.val = parse_number(words[i], 0);
9508           pd->d[pd->count].bt_i = -1;
9509           pd->count++;
9510         }
9511         continue;
9512       }
9513
9514       if (in_func && !g_skip_func) {
9515         if (g_header_mode)
9516           gen_hdr(g_func, pi);
9517         else
9518           gen_func(fout, g_fhdr, g_func, pi);
9519       }
9520
9521       pending_endp = 0;
9522       in_func = 0;
9523       g_ida_func_attr = 0;
9524       g_sct_func_attr = 0;
9525       g_stack_clear_start = 0;
9526       g_stack_clear_len = 0;
9527       g_regmask_init = 0;
9528       skip_warned = 0;
9529       g_skip_func = 0;
9530       g_func[0] = 0;
9531       g_seh_found = 0;
9532       func_chunks_used = 0;
9533       func_chunk_i = -1;
9534       if (pi != 0) {
9535         memset(&ops, 0, pi * sizeof(ops[0]));
9536         clear_labels(pi);
9537         pi = 0;
9538       }
9539       g_eqcnt = 0;
9540       for (i = 0; i < g_func_pd_cnt; i++) {
9541         pd = &g_func_pd[i];
9542         if (pd->type == OPT_OFFSET) {
9543           for (j = 0; j < pd->count; j++)
9544             free(pd->d[j].u.label);
9545         }
9546         free(pd->d);
9547         pd->d = NULL;
9548       }
9549       g_func_pd_cnt = 0;
9550       g_func_lmods = 0;
9551       pd = NULL;
9552
9553       if (end)
9554         break;
9555       if (wordc == 0)
9556         continue;
9557     }
9558
9559     if (IS(words[1], "proc")) {
9560       if (in_func)
9561         aerr("proc '%s' while in_func '%s'?\n",
9562           words[0], g_func);
9563       p = words[0];
9564       if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9565         g_skip_func = 1;
9566       strcpy(g_func, words[0]);
9567       set_label(0, words[0]);
9568       in_func = 1;
9569       continue;
9570     }
9571
9572     if (IS(words[1], "endp"))
9573     {
9574       if (!in_func)
9575         aerr("endp '%s' while not in_func?\n", words[0]);
9576       if (!IS(g_func, words[0]))
9577         aerr("endp '%s' while in_func '%s'?\n",
9578           words[0], g_func);
9579       if (skip_code)
9580         aerr("endp '%s' while skipping code\n", words[0]);
9581
9582       if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9583         && ops[0].op == OP_JMP && ops[0].operand[0].segment)
9584       {
9585         // import jump
9586         g_skip_func = 1;
9587       }
9588
9589       if (!g_skip_func && func_chunks_used) {
9590         // start processing chunks
9591         struct chunk_item *ci, key = { g_func, 0 };
9592
9593         func_chunk_ret = ftell(fasm);
9594         func_chunk_ret_ln = asmln;
9595         if (!func_chunks_sorted) {
9596           qsort(func_chunks, func_chunk_cnt,
9597             sizeof(func_chunks[0]), cmp_chunks);
9598           func_chunks_sorted = 1;
9599         }
9600         ci = bsearch(&key, func_chunks, func_chunk_cnt,
9601                sizeof(func_chunks[0]), cmp_chunks);
9602         if (ci == NULL)
9603           aerr("'%s' needs chunks, but none found\n", g_func);
9604         func_chunk_i = ci - func_chunks;
9605         for (; func_chunk_i > 0; func_chunk_i--)
9606           if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9607             break;
9608
9609         ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9610         if (ret)
9611           aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9612         asmln = func_chunks[func_chunk_i].asmln;
9613         func_chunk_i++;
9614         continue;
9615       }
9616       pending_endp = 1;
9617       continue;
9618     }
9619
9620     if (wordc == 2 && IS(words[1], "ends")) {
9621       if (!multi_seg) {
9622         end = 1;
9623         if (pending_endp)
9624           goto do_pending_endp;
9625         break;
9626       }
9627
9628       // scan for next text segment
9629       while (my_fgets(line, sizeof(line), fasm)) {
9630         asmln++;
9631         p = sskip(line);
9632         if (*p == 0 || *p == ';')
9633           continue;
9634
9635         if (strstr(p, "segment para public 'CODE' use32"))
9636           break;
9637       }
9638
9639       continue;
9640     }
9641
9642     p = strchr(words[0], ':');
9643     if (p != NULL) {
9644       set_label(pi, words[0]);
9645       continue;
9646     }
9647
9648     if (!in_func || g_skip_func || skip_code) {
9649       if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9650         if (verbose)
9651           anote("skipping from '%s'\n", g_labels[pi]);
9652         skip_warned = 1;
9653       }
9654       free(g_labels[pi]);
9655       g_labels[pi] = NULL;
9656       continue;
9657     }
9658
9659     if (wordc > 1 && IS(words[1], "="))
9660     {
9661       if (wordc != 5)
9662         aerr("unhandled equ, wc=%d\n", wordc);
9663       if (g_eqcnt >= eq_alloc) {
9664         eq_alloc *= 2;
9665         g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9666         my_assert_not(g_eqs, NULL);
9667       }
9668
9669       len = strlen(words[0]);
9670       if (len > sizeof(g_eqs[0].name) - 1)
9671         aerr("equ name too long: %d\n", len);
9672       strcpy(g_eqs[g_eqcnt].name, words[0]);
9673
9674       if (!IS(words[3], "ptr"))
9675         aerr("unhandled equ\n");
9676       if (IS(words[2], "dword"))
9677         g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9678       else if (IS(words[2], "word"))
9679         g_eqs[g_eqcnt].lmod = OPLM_WORD;
9680       else if (IS(words[2], "byte"))
9681         g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9682       else if (IS(words[2], "qword"))
9683         g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9684       else
9685         aerr("bad lmod: '%s'\n", words[2]);
9686
9687       g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9688       g_eqcnt++;
9689       continue;
9690     }
9691
9692     if (pi >= ARRAY_SIZE(ops))
9693       aerr("too many ops\n");
9694
9695     parse_op(&ops[pi], words, wordc);
9696
9697     ops[pi].datap = sctproto;
9698     sctproto = NULL;
9699     pi++;
9700   }
9701
9702   if (g_header_mode)
9703     output_hdr(fout);
9704
9705   fclose(fout);
9706   fclose(fasm);
9707   fclose(g_fhdr);
9708
9709   return 0;
9710 }
9711
9712 // vim:ts=2:shiftwidth=2:expandtab