translate: some float arg handling
[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           ferr(po, "call to loc_*\n");
3824         if (IS(tmpname, "__alloca_probe"))
3825           continue;
3826         if (IS(tmpname, "__SEH_prolog")) {
3827           ferr_assert(po, g_seh_found == 0);
3828           g_seh_found = 2;
3829           continue;
3830         }
3831         if (IS(tmpname, "__SEH_epilog"))
3832           continue;
3833
3834         // convert some calls to pseudo-ops
3835         for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3836           if (!IS(tmpname, pseudo_ops[l].name))
3837             continue;
3838
3839           po->op = pseudo_ops[l].op;
3840           po->operand_cnt = 0;
3841           po->regmask_src = pseudo_ops[l].regmask_src;
3842           po->regmask_dst = pseudo_ops[l].regmask_dst;
3843           po->flags = pseudo_ops[l].flags;
3844           po->flags |= po->regmask_dst ? OPF_DATA : 0;
3845           break;
3846         }
3847         if (l < ARRAY_SIZE(pseudo_ops))
3848           continue;
3849
3850         pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3851         if (!g_header_mode && pp_c == NULL)
3852           ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3853
3854         if (pp_c != NULL) {
3855           pp = proto_clone(pp_c);
3856           my_assert_not(pp, NULL);
3857         }
3858       }
3859
3860       if (pp != NULL) {
3861         if (pp->is_fptr)
3862           check_func_pp(po, pp, "fptr var call");
3863         if (pp->is_noreturn) {
3864           po->flags |= OPF_TAIL;
3865           po->flags &= ~OPF_ATAIL; // most likely...
3866         }
3867       }
3868       po->pp = pp;
3869       continue;
3870     }
3871
3872     if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3873       continue;
3874
3875     if (po->operand[0].type == OPT_REGMEM) {
3876       pd = try_resolve_jumptab(i, opcnt);
3877       if (pd == NULL)
3878         goto tailcall;
3879
3880       po->btj = pd;
3881       continue;
3882     }
3883
3884     for (l = 0; l < opcnt; l++) {
3885       if (g_labels[l] != NULL
3886           && IS(po->operand[0].name, g_labels[l]))
3887       {
3888         if (l == i + 1 && po->op == OP_JMP) {
3889           // yet another alignment type..
3890           po->flags |= OPF_RMD|OPF_DONE;
3891           break;
3892         }
3893         add_label_ref(&g_label_refs[l], i);
3894         po->bt_i = l;
3895         break;
3896       }
3897     }
3898
3899     if (po->bt_i != -1 || (po->flags & OPF_RMD))
3900       continue;
3901
3902     if (po->operand[0].type == OPT_LABEL)
3903       // assume tail call
3904       goto tailcall;
3905
3906     ferr(po, "unhandled branch\n");
3907
3908 tailcall:
3909     po->op = OP_CALL;
3910     po->flags |= OPF_TAIL;
3911     prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3912     if (prev_op == OP_POP)
3913       po->flags |= OPF_ATAIL;
3914     if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3915       && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3916     {
3917       po->flags |= OPF_ATAIL;
3918     }
3919     i--; // reprocess
3920   }
3921 }
3922
3923 static int resolve_origin(int i, const struct parsed_opr *opr,
3924   int magic, int *op_i, int *is_caller);
3925
3926 static void eliminate_seh_writes(int opcnt)
3927 {
3928   const struct parsed_opr *opr;
3929   char ofs_reg[16];
3930   int offset;
3931   int i;
3932
3933   // assume all sf writes above g_seh_size to be seh related
3934   // (probably unsafe but oh well)
3935   for (i = 0; i < opcnt; i++) {
3936     if (ops[i].op != OP_MOV)
3937       continue;
3938     opr = &ops[i].operand[0];
3939     if (opr->type != OPT_REGMEM)
3940       continue;
3941     if (!is_stack_access(&ops[i], opr))
3942       continue;
3943
3944     offset = 0;
3945     parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
3946       NULL, NULL, 0);
3947     if (offset < 0 && offset >= -g_seh_size)
3948       ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3949   }
3950 }
3951
3952 static void eliminate_seh(int opcnt)
3953 {
3954   int i, j, k, ret;
3955
3956   for (i = 0; i < opcnt; i++) {
3957     if (ops[i].op != OP_MOV)
3958       continue;
3959     if (ops[i].operand[0].segment != SEG_FS)
3960       continue;
3961     if (!IS(opr_name(&ops[i], 0), "0"))
3962       continue;
3963
3964     ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3965     if (ops[i].operand[1].reg == xSP) {
3966       for (j = i - 1; j >= 0; j--) {
3967         if (ops[j].op != OP_PUSH)
3968           continue;
3969         ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3970         g_seh_size += 4;
3971         if (ops[j].operand[0].val == ~0)
3972           break;
3973         if (ops[j].operand[0].type == OPT_REG) {
3974           k = -1;
3975           ret = resolve_origin(j, &ops[j].operand[0],
3976                   j + opcnt * 22, &k, NULL);
3977           if (ret == 1)
3978             ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3979         }
3980       }
3981       if (j < 0)
3982         ferr(ops, "missing seh terminator\n");
3983     }
3984     else {
3985       k = -1;
3986       ret = resolve_origin(i, &ops[i].operand[1],
3987               i + opcnt * 23, &k, NULL);
3988       if (ret == 1)
3989         ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3990     }
3991   }
3992
3993   eliminate_seh_writes(opcnt);
3994 }
3995
3996 static void eliminate_seh_calls(int opcnt)
3997 {
3998   int epilog_found = 0;
3999   int i;
4000
4001   g_bp_frame = 1;
4002   g_seh_size = 0x10;
4003
4004   i = 0;
4005   ferr_assert(&ops[i], ops[i].op == OP_PUSH
4006                && ops[i].operand[0].type == OPT_CONST);
4007   g_stack_fsz = g_seh_size + ops[i].operand[0].val;
4008   ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4009
4010   i++;
4011   ferr_assert(&ops[i], ops[i].op == OP_PUSH
4012                && ops[i].operand[0].type == OPT_OFFSET);
4013   ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4014
4015   i++;
4016   ferr_assert(&ops[i], ops[i].op == OP_CALL
4017                && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
4018   ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4019
4020   for (i++; i < opcnt; i++) {
4021     if (ops[i].op != OP_CALL)
4022       continue;
4023     if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
4024       continue;
4025
4026     ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4027     epilog_found = 1;
4028   }
4029   ferr_assert(ops, epilog_found);
4030
4031   eliminate_seh_writes(opcnt);
4032 }
4033
4034 static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4035 {
4036   int j;
4037
4038   for (; i < opcnt; i++)
4039     if (!(ops[i].flags & OPF_DONE))
4040       break;
4041
4042   while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4043     ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4044     g_stack_fsz += 4;
4045     (*ecx_push)++;
4046     i++;
4047   }
4048
4049   for (; i < opcnt; i++) {
4050     if (i > 0 && g_labels[i] != NULL)
4051       break;
4052     if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
4053       break;
4054     if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4055       && ops[i].operand[1].type == OPT_CONST)
4056     {
4057       g_stack_fsz += opr_const(&ops[i], 1);
4058       ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4059       i++;
4060       *esp_sub = 1;
4061       break;
4062     }
4063     if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4064         && ops[i].operand[1].type == OPT_CONST)
4065     {
4066       for (j = i + 1; j < opcnt; j++)
4067         if (!(ops[j].flags & OPF_DONE))
4068           break;
4069       if (ops[j].op == OP_CALL
4070         && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4071       {
4072         g_stack_fsz += opr_const(&ops[i], 1);
4073         ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4074         ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4075         i = j + 1;
4076         *esp_sub = 1;
4077       }
4078       break;
4079     }
4080   }
4081
4082   return i;
4083 }
4084
4085 static void scan_prologue_epilogue(int opcnt, int *stack_align)
4086 {
4087   int ecx_push = 0, esp_sub = 0, pusha = 0;
4088   int sandard_epilogue;
4089   int found;
4090   int i, j, l;
4091
4092   if (g_seh_found == 2) {
4093     eliminate_seh_calls(opcnt);
4094     return;
4095   }
4096   if (g_seh_found) {
4097     eliminate_seh(opcnt);
4098     // ida treats seh as part of sf
4099     g_stack_fsz = g_seh_size;
4100     esp_sub = 1;
4101   }
4102
4103   if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4104       && ops[1].op == OP_MOV
4105       && IS(opr_name(&ops[1], 0), "ebp")
4106       && IS(opr_name(&ops[1], 1), "esp"))
4107   {
4108     g_bp_frame = 1;
4109     ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4110     ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4111
4112     for (i = 2; i < opcnt; i++)
4113       if (!(ops[i].flags & OPF_DONE))
4114         break;
4115
4116     if (ops[i].op == OP_PUSHA) {
4117       ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4118       pusha = 1;
4119       i++;
4120     }
4121
4122     if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4123         && ops[i].operand[1].type == OPT_CONST)
4124     {
4125       l = ops[i].operand[1].val;
4126       j = ffs(l) - 1;
4127       if (j == -1 || (l >> j) != -1)
4128         ferr(&ops[i], "unhandled esp align: %x\n", l);
4129       if (stack_align != NULL)
4130         *stack_align = 1 << j;
4131       ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4132       i++;
4133     }
4134
4135     i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4136
4137     found = 0;
4138     do {
4139       for (; i < opcnt; i++)
4140         if (ops[i].flags & OPF_TAIL)
4141           break;
4142       j = i - 1;
4143       if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4144         if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4145           break;
4146         i--;
4147         j--;
4148       }
4149
4150       sandard_epilogue = 0;
4151       if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4152       {
4153         ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4154         // the standard epilogue is sometimes even used without a sf
4155         if (ops[j - 1].op == OP_MOV
4156             && IS(opr_name(&ops[j - 1], 0), "esp")
4157             && IS(opr_name(&ops[j - 1], 1), "ebp"))
4158           sandard_epilogue = 1;
4159       }
4160       else if (ops[j].op == OP_LEAVE)
4161       {
4162         ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4163         sandard_epilogue = 1;
4164       }
4165       else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4166         && ops[i].pp->is_noreturn)
4167       {
4168         // on noreturn, msvc sometimes cleans stack, sometimes not
4169         i++;
4170         found = 1;
4171         continue;
4172       }
4173       else if (!(g_ida_func_attr & IDAFA_NORETURN))
4174         ferr(&ops[j], "'pop ebp' expected\n");
4175
4176       if (g_stack_fsz != 0 || sandard_epilogue) {
4177         if (ops[j].op == OP_LEAVE)
4178           j--;
4179         else if (sandard_epilogue) // mov esp, ebp
4180         {
4181           ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4182           j -= 2;
4183         }
4184         else if (!(g_ida_func_attr & IDAFA_NORETURN))
4185         {
4186           ferr(&ops[j], "esp restore expected\n");
4187         }
4188
4189         if (ecx_push && j >= 0 && ops[j].op == OP_POP
4190           && IS(opr_name(&ops[j], 0), "ecx"))
4191         {
4192           ferr(&ops[j], "unexpected ecx pop\n");
4193         }
4194       }
4195
4196       if (pusha) {
4197         if (ops[j].op == OP_POPA)
4198           ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4199         else
4200           ferr(&ops[j], "popa expected\n");
4201       }
4202
4203       found = 1;
4204       i++;
4205     } while (i < opcnt);
4206
4207     if (!found)
4208       ferr(ops, "missing ebp epilogue\n");
4209     return;
4210   }
4211
4212   // non-bp frame
4213   i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4214
4215   if (ecx_push && !esp_sub) {
4216     // could actually be args for a call..
4217     for (; i < opcnt; i++)
4218       if (ops[i].op != OP_PUSH)
4219         break;
4220
4221     if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4222       const struct parsed_proto *pp;
4223       pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4224       j = pp ? pp->argc_stack : 0;
4225       while (i > 0 && j > 0) {
4226         i--;
4227         if (ops[i].op == OP_PUSH) {
4228           ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4229           j--;
4230         }
4231       }
4232       if (j != 0)
4233         ferr(&ops[i], "unhandled prologue\n");
4234
4235       // recheck
4236       i = ecx_push = 0;
4237       g_stack_fsz = g_seh_size;
4238       while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4239         if (!(ops[i].flags & OPF_RMD))
4240           break;
4241         g_stack_fsz += 4;
4242         ecx_push++;
4243         i++;
4244       }
4245     }
4246   }
4247
4248   found = 0;
4249   if (ecx_push || esp_sub)
4250   {
4251     g_sp_frame = 1;
4252
4253     do {
4254       for (; i < opcnt; i++)
4255         if (ops[i].flags & OPF_TAIL)
4256           break;
4257
4258       j = i - 1;
4259       if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4260         if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4261           break;
4262         i--;
4263         j--;
4264       }
4265       else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4266         // skip arg updates for arg-reuse tailcall
4267         for (; j >= 0; j--) {
4268           if (ops[j].op != OP_MOV)
4269             break;
4270           if (ops[j].operand[0].type != OPT_REGMEM)
4271             break;
4272           if (strstr(ops[j].operand[0].name, "arg_") == NULL)
4273             break;
4274         }
4275       }
4276
4277       if (ecx_push > 0 && !esp_sub) {
4278         for (l = 0; l < ecx_push && j >= 0; l++) {
4279           if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4280             /* pop ecx */;
4281           else if (ops[j].op == OP_ADD
4282                    && IS(opr_name(&ops[j], 0), "esp")
4283                    && ops[j].operand[1].type == OPT_CONST)
4284           {
4285             /* add esp, N */
4286             l += ops[j].operand[1].val / 4 - 1;
4287           }
4288           else
4289             break;
4290
4291           ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4292           j--;
4293         }
4294         if (l != ecx_push) {
4295           if (i < opcnt && ops[i].op == OP_CALL
4296             && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4297           {
4298             // noreturn tailcall with no epilogue
4299             i++;
4300             found = 1;
4301             continue;
4302           }
4303           ferr(&ops[j], "epilogue scan failed\n");
4304         }
4305
4306         found = 1;
4307       }
4308
4309       if (esp_sub) {
4310         if (ops[j].op != OP_ADD
4311             || !IS(opr_name(&ops[j], 0), "esp")
4312             || ops[j].operand[1].type != OPT_CONST)
4313         {
4314           if (i < opcnt && ops[i].op == OP_CALL
4315             && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4316           {
4317             // noreturn tailcall with no epilogue
4318             i++;
4319             found = 1;
4320             continue;
4321           }
4322           ferr(&ops[j], "'add esp' expected\n");
4323         }
4324
4325         if (ops[j].operand[1].val < g_stack_fsz)
4326           ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4327
4328         ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4329         if (ops[j].operand[1].val == 0)
4330           ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4331         found = 1;
4332       }
4333
4334       i++;
4335     } while (i < opcnt);
4336
4337     if (!found)
4338       ferr(ops, "missing esp epilogue\n");
4339   }
4340 }
4341
4342 // find an instruction that changed opr before i op
4343 // *op_i must be set to -1 by the caller
4344 // *is_caller is set to 1 if one source is determined to be g_func arg
4345 // returns 1 if found, *op_i is then set to origin
4346 // returns -1 if multiple origins are found
4347 static int resolve_origin(int i, const struct parsed_opr *opr,
4348   int magic, int *op_i, int *is_caller)
4349 {
4350   struct label_ref *lr;
4351   int ret = 0;
4352
4353   while (1) {
4354     if (g_labels[i] != NULL) {
4355       lr = &g_label_refs[i];
4356       for (; lr != NULL; lr = lr->next) {
4357         check_i(&ops[i], lr->i);
4358         ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4359       }
4360       if (i > 0 && LAST_OP(i - 1))
4361         return ret;
4362     }
4363
4364     i--;
4365     if (i < 0) {
4366       if (is_caller != NULL)
4367         *is_caller = 1;
4368       return -1;
4369     }
4370
4371     if (ops[i].cc_scratch == magic)
4372       return ret;
4373     ops[i].cc_scratch = magic;
4374
4375     if (!(ops[i].flags & OPF_DATA))
4376       continue;
4377     if (!is_opr_modified(opr, &ops[i]))
4378       continue;
4379
4380     if (*op_i >= 0) {
4381       if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4382         return ret | 1;
4383
4384       return -1;
4385     }
4386
4387     *op_i = i;
4388     return ret | 1;
4389   }
4390 }
4391
4392 // find an instruction that previously referenced opr
4393 // if multiple results are found - fail
4394 // *op_i must be set to -1 by the caller
4395 // returns 1 if found, *op_i is then set to referencer insn
4396 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4397   int magic, int *op_i)
4398 {
4399   struct label_ref *lr;
4400   int ret = 0;
4401
4402   while (1) {
4403     if (g_labels[i] != NULL) {
4404       lr = &g_label_refs[i];
4405       for (; lr != NULL; lr = lr->next) {
4406         check_i(&ops[i], lr->i);
4407         ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4408       }
4409       if (i > 0 && LAST_OP(i - 1))
4410         return ret;
4411     }
4412
4413     i--;
4414     if (i < 0)
4415       return -1;
4416
4417     if (ops[i].cc_scratch == magic)
4418       return 0;
4419     ops[i].cc_scratch = magic;
4420
4421     if (!is_opr_referenced(opr, &ops[i]))
4422       continue;
4423
4424     if (*op_i >= 0)
4425       return -1;
4426
4427     *op_i = i;
4428     return 1;
4429   }
4430 }
4431
4432 // adjust datap of all reachable 'op' insns when moving back
4433 // returns  1 if at least 1 op was found
4434 // returns -1 if path without an op was found
4435 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4436 {
4437   struct label_ref *lr;
4438   int ret = 0;
4439
4440   if (ops[i].cc_scratch == magic)
4441     return 0;
4442   ops[i].cc_scratch = magic;
4443
4444   while (1) {
4445     if (g_labels[i] != NULL) {
4446       lr = &g_label_refs[i];
4447       for (; lr != NULL; lr = lr->next) {
4448         check_i(&ops[i], lr->i);
4449         ret |= adjust_prev_op(lr->i, op, magic, datap);
4450       }
4451       if (i > 0 && LAST_OP(i - 1))
4452         return ret;
4453     }
4454
4455     i--;
4456     if (i < 0)
4457       return -1;
4458
4459     if (ops[i].cc_scratch == magic)
4460       return 0;
4461     ops[i].cc_scratch = magic;
4462
4463     if (ops[i].op != op)
4464       continue;
4465
4466     ops[i].datap = datap;
4467     return 1;
4468   }
4469 }
4470
4471 // find next instruction that reads opr
4472 // *op_i must be set to -1 by the caller
4473 // on return, *op_i is set to first referencer insn
4474 // returns 1 if exactly 1 referencer is found
4475 static int find_next_read(int i, int opcnt,
4476   const struct parsed_opr *opr, int magic, int *op_i)
4477 {
4478   struct parsed_op *po;
4479   int j, ret = 0;
4480
4481   for (; i < opcnt; i++)
4482   {
4483     if (ops[i].cc_scratch == magic)
4484       return ret;
4485     ops[i].cc_scratch = magic;
4486
4487     po = &ops[i];
4488     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4489       if (po->btj != NULL) {
4490         // jumptable
4491         for (j = 0; j < po->btj->count; j++) {
4492           check_i(po, po->btj->d[j].bt_i);
4493           ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4494                    magic, op_i);
4495         }
4496         return ret;
4497       }
4498
4499       if (po->flags & OPF_RMD)
4500         continue;
4501       check_i(po, po->bt_i);
4502       if (po->flags & OPF_CJMP) {
4503         ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4504         if (ret < 0)
4505           return ret;
4506       }
4507       else
4508         i = po->bt_i - 1;
4509       continue;
4510     }
4511
4512     if (!is_opr_read(opr, po)) {
4513       int full_opr = 1;
4514       if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4515           && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4516       {
4517         full_opr = po->operand[0].lmod >= opr->lmod;
4518       }
4519       if (is_opr_modified(opr, po) && full_opr) {
4520         // it's overwritten
4521         return ret;
4522       }
4523       if (po->flags & OPF_TAIL)
4524         return ret;
4525       continue;
4526     }
4527
4528     if (*op_i >= 0)
4529       return -1;
4530
4531     *op_i = i;
4532     return 1;
4533   }
4534
4535   return 0;
4536 }
4537
4538 // find next instruction that reads opr
4539 // *op_i must be set to -1 by the caller
4540 // on return, *op_i is set to first flag user insn
4541 // returns 1 if exactly 1 flag user is found
4542 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4543 {
4544   struct parsed_op *po;
4545   int j, ret = 0;
4546
4547   for (; i < opcnt; i++)
4548   {
4549     if (ops[i].cc_scratch == magic)
4550       return ret;
4551     ops[i].cc_scratch = magic;
4552
4553     po = &ops[i];
4554     if (po->op == OP_CALL)
4555       return -1;
4556     if (po->flags & OPF_JMP) {
4557       if (po->btj != NULL) {
4558         // jumptable
4559         for (j = 0; j < po->btj->count; j++) {
4560           check_i(po, po->btj->d[j].bt_i);
4561           ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4562                    magic, op_i);
4563         }
4564         return ret;
4565       }
4566
4567       if (po->flags & OPF_RMD)
4568         continue;
4569       check_i(po, po->bt_i);
4570       if (po->flags & OPF_CJMP)
4571         goto found;
4572       else
4573         i = po->bt_i - 1;
4574       continue;
4575     }
4576
4577     if (!(po->flags & OPF_CC)) {
4578       if (po->flags & OPF_FLAGS)
4579         // flags changed
4580         return ret;
4581       if (po->flags & OPF_TAIL)
4582         return ret;
4583       continue;
4584     }
4585
4586 found:
4587     if (*op_i >= 0)
4588       return -1;
4589
4590     *op_i = i;
4591     return 1;
4592   }
4593
4594   return 0;
4595 }
4596
4597 static int try_resolve_const(int i, const struct parsed_opr *opr,
4598   int magic, unsigned int *val)
4599 {
4600   int s_i = -1;
4601   int ret;
4602
4603   ret = resolve_origin(i, opr, magic, &s_i, NULL);
4604   if (ret == 1) {
4605     i = s_i;
4606     if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4607       return -1;
4608
4609     *val = ops[i].operand[1].val;
4610     return 1;
4611   }
4612
4613   return -1;
4614 }
4615
4616 static int resolve_used_bits(int i, int opcnt, int reg,
4617   int *mask, int *is_z_check)
4618 {
4619   struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4620   int j = -1, k = -1;
4621   int ret;
4622
4623   ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4624   if (ret != 1)
4625     return -1;
4626
4627   find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4628   if (k != -1) {
4629     fnote(&ops[j], "(first read)\n");
4630     ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4631   }
4632
4633   if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4634     ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4635
4636   ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4637   ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4638
4639   *mask = ops[j].operand[1].val;
4640   if (ops[j].operand[0].lmod == OPLM_BYTE
4641     && ops[j].operand[0].name[1] == 'h')
4642   {
4643     *mask <<= 8;
4644   }
4645   ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4646
4647   *is_z_check = 0;
4648   ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4649   if (ret == 1)
4650     *is_z_check = ops[k].pfo == PFO_Z;
4651
4652   return 0;
4653 }
4654
4655 static const struct parsed_proto *resolve_deref(int i, int magic,
4656   struct parsed_opr *opr, int level)
4657 {
4658   struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4659   const struct parsed_proto *pp = NULL;
4660   int from_caller = 0;
4661   char s_reg[4];
4662   int offset = 0;
4663   int len = 0;
4664   int j = -1;
4665   int k = -1;
4666   int reg;
4667   int ret;
4668
4669   ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4670   if (ret != 2 || len != strlen(opr->name)) {
4671     ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4672     if (ret != 1 || len != strlen(opr->name))
4673       return NULL;
4674   }
4675
4676   reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4677   if (reg < 0)
4678     return NULL;
4679
4680   opr_s.reg = reg;
4681   ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4682   if (ret != 1)
4683     return NULL;
4684
4685   if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4686     && strlen(ops[j].operand[1].name) == 3
4687     && ops[j].operand[0].lmod == OPLM_DWORD
4688     && ops[j].pp == NULL // no hint
4689     && level == 0)
4690   {
4691     // allow one simple dereference (com/directx)
4692     reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4693             ops[j].operand[1].name);
4694     if (reg < 0)
4695       return NULL;
4696     opr_s.reg = reg;
4697     ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4698     if (ret != 1)
4699       return NULL;
4700     j = k;
4701   }
4702   if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4703     return NULL;
4704
4705   if (ops[j].pp != NULL) {
4706     // type hint in asm
4707     pp = ops[j].pp;
4708   }
4709   else if (ops[j].operand[1].type == OPT_REGMEM) {
4710     pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4711     if (pp == NULL) {
4712       // maybe structure ptr in structure
4713       pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4714     }
4715   }
4716   else if (ops[j].operand[1].type == OPT_LABEL)
4717     pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4718   else if (ops[j].operand[1].type == OPT_REG) {
4719     // maybe arg reg?
4720     k = -1;
4721     ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4722             &k, &from_caller);
4723     if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4724       for (k = 0; k < g_func_pp->argc; k++) {
4725         if (g_func_pp->arg[k].reg == NULL)
4726           continue;
4727         if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4728           pp = g_func_pp->arg[k].pp;
4729           break;
4730         }
4731       }
4732     }
4733   }
4734
4735   if (pp == NULL)
4736     return NULL;
4737   if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4738     if (offset != 0)
4739       ferr(&ops[j], "expected struct, got '%s %s'\n",
4740            pp->type.name, pp->name);
4741     return NULL;
4742   }
4743
4744   return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4745 }
4746
4747 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4748   int *pp_i, int *multi_src)
4749 {
4750   const struct parsed_proto *pp = NULL;
4751   int search_advice = 0;
4752
4753   *multi_src = 0;
4754   *pp_i = -1;
4755
4756   switch (ops[i].operand[0].type) {
4757   case OPT_REGMEM:
4758     // try to resolve struct member calls
4759     pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4760     if (pp != NULL)
4761       break;
4762     // fallthrough
4763   case OPT_LABEL:
4764   case OPT_OFFSET:
4765     pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4766            1, &search_advice);
4767     if (!search_advice)
4768       break;
4769     // fallthrough
4770   default:
4771     scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4772       pp_i, multi_src);
4773     break;
4774   }
4775
4776   return pp;
4777 }
4778
4779 static struct parsed_proto *process_call_early(int i, int opcnt,
4780   int *adj_i)
4781 {
4782   struct parsed_op *po = &ops[i];
4783   struct parsed_proto *pp;
4784   int multipath = 0;
4785   int adj = 0;
4786   int j, ret;
4787
4788   pp = po->pp;
4789   if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4790     // leave for later
4791     return NULL;
4792
4793   // look for and make use of esp adjust
4794   *adj_i = ret = -1;
4795   if (!pp->is_stdcall && pp->argc_stack > 0)
4796     ret = scan_for_esp_adjust(i + 1, opcnt,
4797             pp->argc_stack * 4, &adj, &multipath, 0);
4798   if (ret >= 0) {
4799     if (pp->argc_stack > adj / 4)
4800       return NULL;
4801     if (multipath)
4802       return NULL;
4803     if (ops[ret].op == OP_POP) {
4804       for (j = 1; j < adj / 4; j++) {
4805         if (ops[ret + j].op != OP_POP
4806           || ops[ret + j].operand[0].reg != xCX)
4807         {
4808           return NULL;
4809         }
4810       }
4811     }
4812   }
4813
4814   *adj_i = ret;
4815   return pp;
4816 }
4817
4818 static struct parsed_proto *process_call(int i, int opcnt)
4819 {
4820   struct parsed_op *po = &ops[i];
4821   const struct parsed_proto *pp_c;
4822   struct parsed_proto *pp;
4823   const char *tmpname;
4824   int call_i = -1, ref_i = -1;
4825   int adj = 0, multipath = 0;
4826   int ret, arg;
4827
4828   tmpname = opr_name(po, 0);
4829   pp = po->pp;
4830   if (pp == NULL)
4831   {
4832     // indirect call
4833     pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4834     if (pp_c != NULL) {
4835       if (!pp_c->is_func && !pp_c->is_fptr)
4836         ferr(po, "call to non-func: %s\n", pp_c->name);
4837       pp = proto_clone(pp_c);
4838       my_assert_not(pp, NULL);
4839       if (multipath)
4840         // not resolved just to single func
4841         pp->is_fptr = 1;
4842
4843       switch (po->operand[0].type) {
4844       case OPT_REG:
4845         // we resolved this call and no longer need the register
4846         po->regmask_src &= ~(1 << po->operand[0].reg);
4847
4848         if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4849           && ops[call_i].operand[1].type == OPT_LABEL)
4850         {
4851           // no other source users?
4852           ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4853                   &ref_i);
4854           if (ret == 1 && call_i == ref_i) {
4855             // and nothing uses it after us?
4856             ref_i = -1;
4857             find_next_read(i + 1, opcnt, &po->operand[0],
4858               i + opcnt * 11, &ref_i);
4859             if (ref_i == -1)
4860               // then also don't need the source mov
4861               ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4862           }
4863         }
4864         break;
4865       case OPT_REGMEM:
4866         pp->is_fptr = 1;
4867         break;
4868       default:
4869         break;
4870       }
4871     }
4872     if (pp == NULL) {
4873       pp = calloc(1, sizeof(*pp));
4874       my_assert_not(pp, NULL);
4875
4876       pp->is_fptr = 1;
4877       ret = scan_for_esp_adjust(i + 1, opcnt,
4878               -1, &adj, &multipath, 0);
4879       if (ret < 0 || adj < 0) {
4880         if (!g_allow_regfunc)
4881           ferr(po, "non-__cdecl indirect call unhandled yet\n");
4882         pp->is_unresolved = 1;
4883         adj = 0;
4884       }
4885       adj /= 4;
4886       if (adj > ARRAY_SIZE(pp->arg))
4887         ferr(po, "esp adjust too large: %d\n", adj);
4888       pp->ret_type.name = strdup("int");
4889       pp->argc = pp->argc_stack = adj;
4890       for (arg = 0; arg < pp->argc; arg++)
4891         pp->arg[arg].type.name = strdup("int");
4892     }
4893     po->pp = pp;
4894   }
4895
4896   // look for and make use of esp adjust
4897   multipath = 0;
4898   ret = -1;
4899   if (!pp->is_stdcall && pp->argc_stack > 0) {
4900     int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4901     ret = scan_for_esp_adjust(i + 1, opcnt,
4902             adj_expect, &adj, &multipath, 0);
4903   }
4904   if (ret >= 0) {
4905     if (pp->is_vararg) {
4906       if (adj / 4 < pp->argc_stack) {
4907         fnote(po, "(this call)\n");
4908         ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4909           adj, pp->argc_stack * 4);
4910       }
4911       // modify pp to make it have varargs as normal args
4912       arg = pp->argc;
4913       pp->argc += adj / 4 - pp->argc_stack;
4914       for (; arg < pp->argc; arg++) {
4915         pp->arg[arg].type.name = strdup("int");
4916         pp->argc_stack++;
4917       }
4918       if (pp->argc > ARRAY_SIZE(pp->arg))
4919         ferr(po, "too many args for '%s'\n", tmpname);
4920     }
4921     if (pp->argc_stack > adj / 4) {
4922       if (pp->is_noreturn)
4923         // assume no stack adjust was emited
4924         goto out;
4925       fnote(po, "(this call)\n");
4926       ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4927         tmpname, pp->argc_stack * 4, adj);
4928     }
4929
4930     scan_for_esp_adjust(i + 1, opcnt,
4931       pp->argc_stack * 4, &adj, &multipath, 1);
4932   }
4933   else if (pp->is_vararg)
4934     ferr(po, "missing esp_adjust for vararg func '%s'\n",
4935       pp->name);
4936
4937 out:
4938   return pp;
4939 }
4940
4941 static void mark_float_arg(struct parsed_op *po,
4942   struct parsed_proto *pp, int arg, int *regmask_ffca)
4943 {
4944   po->p_argnext = -1;
4945   po->p_argnum = arg + 1;
4946   ferr_assert(po, pp->arg[arg].datap == NULL);
4947   pp->arg[arg].datap = po;
4948   po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
4949   if (regmask_ffca != NULL)
4950     *regmask_ffca |= 1 << arg;
4951 }
4952
4953 static int check_for_stp(int i, int i_to)
4954 {
4955   struct parsed_op *po;
4956
4957   for (; i < i_to; i++) {
4958     po = &ops[i];
4959     if (po->op == OP_FST)
4960       return i;
4961     if (g_labels[i] != NULL || (po->flags & OPF_JMP))
4962       return -1;
4963     if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
4964       return -1;
4965     if (po->op == OP_ADD && po->operand[0].reg == xSP)
4966       return -1;
4967   }
4968
4969   return -1;
4970 }
4971
4972 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
4973   int *regmask_ffca)
4974 {
4975   struct parsed_op *po;
4976   int offset = 0;
4977   int base_arg;
4978   int j, arg;
4979   int ret;
4980
4981   for (base_arg = 0; base_arg < pp->argc; base_arg++)
4982     if (pp->arg[base_arg].reg == NULL)
4983       break;
4984
4985   for (j = i; j > 0; )
4986   {
4987     ferr_assert(&ops[j], g_labels[j] == NULL);
4988     j--;
4989
4990     po = &ops[j];
4991     ferr_assert(po, po->op != OP_PUSH);
4992     if (po->op == OP_FST)
4993     {
4994       if (po->operand[0].type != OPT_REGMEM)
4995         continue;
4996       ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
4997       if (ret != 0)
4998         continue;
4999       if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
5000         //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
5001         continue;
5002       }
5003
5004       arg = base_arg + offset / 4;
5005       mark_float_arg(po, pp, arg, regmask_ffca);
5006     }
5007     else if (po->op == OP_SUB && po->operand[0].reg == xSP
5008       && po->operand[1].type == OPT_CONST)
5009     {
5010       po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5011       break;
5012     }
5013   }
5014
5015   for (arg = base_arg; arg < pp->argc; arg++) {
5016     ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
5017     po = pp->arg[arg].datap;
5018     if (po == NULL)
5019       ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
5020     if (po->operand[0].lmod == OPLM_QWORD)
5021       arg++;
5022   }
5023
5024   return 0;
5025 }
5026
5027 static int collect_call_args_early(int i, struct parsed_proto *pp,
5028   int *regmask, int *regmask_ffca)
5029 {
5030   struct parsed_op *po;
5031   int arg, ret;
5032   int offset;
5033   int j, k;
5034
5035   for (arg = 0; arg < pp->argc; arg++)
5036     if (pp->arg[arg].reg == NULL)
5037       break;
5038
5039   // first see if it can be easily done
5040   for (j = i; j > 0 && arg < pp->argc; )
5041   {
5042     if (g_labels[j] != NULL)
5043       return -1;
5044     j--;
5045
5046     po = &ops[j];
5047     if (po->op == OP_CALL)
5048       return -1;
5049     else if (po->op == OP_ADD && po->operand[0].reg == xSP)
5050       return -1;
5051     else if (po->op == OP_POP)
5052       return -1;
5053     else if (po->flags & OPF_CJMP)
5054       return -1;
5055     else if (po->op == OP_PUSH) {
5056       if (po->flags & (OPF_FARG|OPF_FARGNR))
5057         return -1;
5058       if (!g_header_mode) {
5059         ret = scan_for_mod(po, j + 1, i, 1);
5060         if (ret >= 0)
5061           return -1;
5062       }
5063
5064       if (pp->arg[arg].type.is_va_list)
5065         return -1;
5066
5067       // next arg
5068       for (arg++; arg < pp->argc; arg++)
5069         if (pp->arg[arg].reg == NULL)
5070           break;
5071     }
5072     else if (po->op == OP_SUB && po->operand[0].reg == xSP
5073       && po->operand[1].type == OPT_CONST)
5074     {
5075       if (po->flags & (OPF_RMD|OPF_DONE))
5076         return -1;
5077       if (po->operand[1].val != pp->argc_stack * 4)
5078         ferr(po, "unexpected esp adjust: %d\n",
5079              po->operand[1].val * 4);
5080       ferr_assert(po, pp->argc - arg == pp->argc_stack);
5081       return collect_call_args_no_push(i, pp, regmask_ffca);
5082     }
5083   }
5084
5085   if (arg < pp->argc)
5086     return -1;
5087
5088   // now do it
5089   for (arg = 0; arg < pp->argc; arg++)
5090     if (pp->arg[arg].reg == NULL)
5091       break;
5092
5093   for (j = i; j > 0 && arg < pp->argc; )
5094   {
5095     j--;
5096
5097     if (ops[j].op == OP_PUSH)
5098     {
5099       ops[j].p_argnext = -1;
5100       ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
5101
5102       k = check_for_stp(j + 1, i);
5103       if (k != -1) {
5104         // push ecx; fstp dword ptr [esp]
5105         ret = parse_stack_esp_offset(&ops[k],
5106                 ops[k].operand[0].name, &offset);
5107         if (ret == 0 && offset == 0) {
5108           if (!pp->arg[arg].type.is_float)
5109             ferr(&ops[i], "arg %d should be float\n", arg + 1);
5110           mark_float_arg(&ops[k], pp, arg, regmask_ffca);
5111         }
5112       }
5113
5114       if (pp->arg[arg].datap == NULL) {
5115         pp->arg[arg].datap = &ops[j];
5116         if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5117           *regmask |= 1 << ops[j].operand[0].reg;
5118       }
5119
5120       ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5121       ops[j].flags &= ~OPF_RSAVE;
5122
5123       // next arg
5124       for (arg++; arg < pp->argc; arg++)
5125         if (pp->arg[arg].reg == NULL)
5126           break;
5127     }
5128   }
5129
5130   return 0;
5131 }
5132
5133 static int sync_argnum(struct parsed_op *po, int argnum)
5134 {
5135   struct parsed_op *po_tmp;
5136
5137   // see if other branches don't have higher argnum
5138   for (po_tmp = po; po_tmp != NULL; ) {
5139     if (argnum < po_tmp->p_argnum)
5140       argnum = po_tmp->p_argnum;
5141     // note: p_argnext is active on current collect_call_args only
5142     po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5143   }
5144
5145   // make all argnums consistent
5146   for (po_tmp = po; po_tmp != NULL; ) {
5147     if (po_tmp->p_argnum != 0)
5148       po_tmp->p_argnum = argnum;
5149     po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5150   }
5151
5152   return argnum;
5153 }
5154
5155 static int collect_call_args_r(struct parsed_op *po, int i,
5156   struct parsed_proto *pp, int *regmask, int *arg_grp,
5157   int arg, int argnum, int magic, int need_op_saving, int may_reuse)
5158 {
5159   struct parsed_proto *pp_tmp;
5160   struct parsed_op *po_tmp;
5161   struct label_ref *lr;
5162   int need_to_save_current;
5163   int arg_grp_current = 0;
5164   int save_args_seen = 0;
5165   int ret = 0;
5166   int reg;
5167   char buf[32];
5168   int j, k;
5169
5170   if (i < 0) {
5171     ferr(po, "dead label encountered\n");
5172     return -1;
5173   }
5174
5175   for (; arg < pp->argc; arg++, argnum++)
5176     if (pp->arg[arg].reg == NULL)
5177       break;
5178   magic = (magic & 0xffffff) | (arg << 24);
5179
5180   for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5181   {
5182     if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5183       if (ops[j].cc_scratch != magic) {
5184         ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5185            pp->name);
5186         return -1;
5187       }
5188       // ok: have already been here
5189       return 0;
5190     }
5191     ops[j].cc_scratch = magic;
5192
5193     if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5194       lr = &g_label_refs[j];
5195       if (lr->next != NULL)
5196         need_op_saving = 1;
5197       for (; lr->next; lr = lr->next) {
5198         check_i(&ops[j], lr->i);
5199         if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5200           may_reuse = 1;
5201         ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5202                 arg, argnum, magic, need_op_saving, may_reuse);
5203         if (ret < 0)
5204           return ret;
5205       }
5206
5207       check_i(&ops[j], lr->i);
5208       if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5209         may_reuse = 1;
5210       if (j > 0 && LAST_OP(j - 1)) {
5211         // follow last branch in reverse
5212         j = lr->i;
5213         continue;
5214       }
5215       need_op_saving = 1;
5216       ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5217               arg, argnum, magic, need_op_saving, may_reuse);
5218       if (ret < 0)
5219         return ret;
5220     }
5221     j--;
5222
5223     if (ops[j].op == OP_CALL)
5224     {
5225       if (pp->is_unresolved)
5226         break;
5227
5228       pp_tmp = ops[j].pp;
5229       if (pp_tmp == NULL)
5230         ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5231           arg, pp->argc, ops[j].operand[0].name);
5232       if (may_reuse && pp_tmp->argc_stack > 0)
5233         ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5234           arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5235     }
5236     // esp adjust of 0 means we collected it before
5237     else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5238       && (ops[j].operand[1].type != OPT_CONST
5239           || ops[j].operand[1].val != 0))
5240     {
5241       if (pp->is_unresolved)
5242         break;
5243
5244       fnote(po, "(this call)\n");
5245       ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5246         arg, pp->argc, ops[j].operand[1].val);
5247     }
5248     else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5249     {
5250       if (pp->is_unresolved)
5251         break;
5252
5253       fnote(po, "(this call)\n");
5254       ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5255     }
5256     else if (ops[j].flags & OPF_CJMP)
5257     {
5258       if (pp->is_unresolved)
5259         break;
5260
5261       may_reuse = 1;
5262     }
5263     else if (ops[j].op == OP_PUSH
5264       && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5265     {
5266       if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5267         break;
5268
5269       ops[j].p_argnext = -1;
5270       po_tmp = pp->arg[arg].datap;
5271       if (po_tmp != NULL)
5272         ops[j].p_argnext = po_tmp - ops;
5273       pp->arg[arg].datap = &ops[j];
5274
5275       argnum = sync_argnum(&ops[j], argnum);
5276
5277       need_to_save_current = 0;
5278       reg = -1;
5279       if (ops[j].operand[0].type == OPT_REG)
5280         reg = ops[j].operand[0].reg;
5281
5282       if (!need_op_saving) {
5283         ret = scan_for_mod(&ops[j], j + 1, i, 1);
5284         need_to_save_current = (ret >= 0);
5285       }
5286       if (need_op_saving || need_to_save_current) {
5287         // mark this arg as one that needs operand saving
5288         pp->arg[arg].is_saved = 1;
5289
5290         if (save_args_seen & (1 << (argnum - 1))) {
5291           save_args_seen = 0;
5292           arg_grp_current++;
5293           if (arg_grp_current >= MAX_ARG_GRP)
5294             ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5295               argnum, pp->name);
5296         }
5297       }
5298       else if (ops[j].p_argnum == 0)
5299         ops[j].flags |= OPF_RMD;
5300
5301       // some PUSHes are reused by different calls on other branches,
5302       // but that can't happen if we didn't branch, so they
5303       // can be removed from future searches (handles nested calls)
5304       if (!may_reuse)
5305         ops[j].flags |= OPF_FARGNR;
5306
5307       ops[j].flags |= OPF_FARG;
5308       ops[j].flags &= ~OPF_RSAVE;
5309
5310       // check for __VALIST
5311       if (!pp->is_unresolved && g_func_pp != NULL
5312         && pp->arg[arg].type.is_va_list)
5313       {
5314         k = -1;
5315         ret = resolve_origin(j, &ops[j].operand[0],
5316                 magic + 1, &k, NULL);
5317         if (ret == 1 && k >= 0)
5318         {
5319           if (ops[k].op == OP_LEA) {
5320             if (!g_func_pp->is_vararg)
5321               ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5322                    g_func_pp->name);
5323
5324             snprintf(buf, sizeof(buf), "arg_%X",
5325               g_func_pp->argc_stack * 4);
5326             if (strstr(ops[k].operand[1].name, buf)
5327              || strstr(ops[k].operand[1].name, "arglist"))
5328             {
5329               ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5330               ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5331               pp->arg[arg].is_saved = 0;
5332               reg = -1;
5333             }
5334             else
5335               ferr(&ops[k], "va_list arg detection failed\n");
5336           }
5337           // check for va_list from g_func_pp arg too
5338           else if (ops[k].op == OP_MOV
5339             && is_stack_access(&ops[k], &ops[k].operand[1]))
5340           {
5341             ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5342               buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5343             if (ret >= 0) {
5344               ops[k].flags |= OPF_RMD | OPF_DONE;
5345               ops[j].flags |= OPF_RMD;
5346               ops[j].p_argpass = ret + 1;
5347               pp->arg[arg].is_saved = 0;
5348               reg = -1;
5349             }
5350           }
5351         }
5352       }
5353
5354       if (pp->arg[arg].is_saved) {
5355         ops[j].flags &= ~OPF_RMD;
5356         ops[j].p_argnum = argnum;
5357       }
5358
5359       // tracking reg usage
5360       if (reg >= 0)
5361         *regmask |= 1 << reg;
5362
5363       arg++;
5364       argnum++;
5365       if (!pp->is_unresolved) {
5366         // next arg
5367         for (; arg < pp->argc; arg++, argnum++)
5368           if (pp->arg[arg].reg == NULL)
5369             break;
5370       }
5371       magic = (magic & 0xffffff) | (arg << 24);
5372     }
5373
5374     if (ops[j].p_arggrp > arg_grp_current) {
5375       save_args_seen = 0;
5376       arg_grp_current = ops[j].p_arggrp;
5377     }
5378     if (ops[j].p_argnum > 0)
5379       save_args_seen |= 1 << (ops[j].p_argnum - 1);
5380   }
5381
5382   if (arg < pp->argc) {
5383     ferr(po, "arg collect failed for '%s': %d/%d\n",
5384       pp->name, arg, pp->argc);
5385     return -1;
5386   }
5387
5388   if (arg_grp_current > *arg_grp)
5389     *arg_grp = arg_grp_current;
5390
5391   return arg;
5392 }
5393
5394 static int collect_call_args(struct parsed_op *po, int i,
5395   struct parsed_proto *pp, int *regmask, int magic)
5396 {
5397   // arg group is for cases when pushes for
5398   // multiple funcs are going on
5399   struct parsed_op *po_tmp;
5400   int arg_grp = 0;
5401   int ret;
5402   int a;
5403
5404   ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5405           0, 1, magic, 0, 0);
5406   if (ret < 0)
5407     return ret;
5408
5409   if (arg_grp != 0) {
5410     // propagate arg_grp
5411     for (a = 0; a < pp->argc; a++) {
5412       if (pp->arg[a].reg != NULL)
5413         continue;
5414
5415       po_tmp = pp->arg[a].datap;
5416       while (po_tmp != NULL) {
5417         po_tmp->p_arggrp = arg_grp;
5418         po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5419       }
5420     }
5421   }
5422
5423   if (pp->is_unresolved) {
5424     pp->argc += ret;
5425     pp->argc_stack += ret;
5426     for (a = 0; a < pp->argc; a++)
5427       if (pp->arg[a].type.name == NULL)
5428         pp->arg[a].type.name = strdup("int");
5429   }
5430
5431   return ret;
5432 }
5433
5434 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5435   int regmask_now, int *regmask,
5436   int regmask_save_now, int *regmask_save,
5437   int *regmask_init, int regmask_arg)
5438 {
5439   struct parsed_op *po;
5440   int already_saved;
5441   int regmask_new;
5442   int regmask_op;
5443   int flags_set;
5444   int ret, reg;
5445   int j;
5446
5447   for (; i < opcnt; i++)
5448   {
5449     po = &ops[i];
5450     if (cbits[i >> 3] & (1 << (i & 7)))
5451       return;
5452     cbits[i >> 3] |= (1 << (i & 7));
5453
5454     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5455       if (po->flags & (OPF_RMD|OPF_DONE))
5456         continue;
5457       if (po->btj != NULL) {
5458         for (j = 0; j < po->btj->count; j++) {
5459           check_i(po, po->btj->d[j].bt_i);
5460           reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5461             regmask_now, regmask, regmask_save_now, regmask_save,
5462             regmask_init, regmask_arg);
5463         }
5464         return;
5465       }
5466
5467       check_i(po, po->bt_i);
5468       if (po->flags & OPF_CJMP)
5469         reg_use_pass(po->bt_i, opcnt, cbits,
5470           regmask_now, regmask, regmask_save_now, regmask_save,
5471           regmask_init, regmask_arg);
5472       else
5473         i = po->bt_i - 1;
5474       continue;
5475     }
5476
5477     if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5478       && !g_func_pp->is_userstack
5479       && po->operand[0].type == OPT_REG)
5480     {
5481       reg = po->operand[0].reg;
5482       ferr_assert(po, reg >= 0);
5483
5484       already_saved = 0;
5485       flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5486       if (regmask_now & (1 << reg)) {
5487         already_saved = regmask_save_now & (1 << reg);
5488         flags_set = OPF_RSAVE | OPF_DONE;
5489       }
5490
5491       ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5492       if (ret == 1) {
5493         scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5494           reg, 0, 0, flags_set);
5495       }
5496       else {
5497         ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5498         if (ret == 1) {
5499           scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5500             flags_set);
5501         }
5502       }
5503       if (ret == 1) {
5504         ferr_assert(po, !already_saved);
5505         po->flags |= flags_set;
5506
5507         if (regmask_now & (1 << reg)) {
5508           regmask_save_now |= (1 << reg);
5509           *regmask_save |= regmask_save_now;
5510         }
5511         continue;
5512       }
5513     }
5514     else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5515       reg = po->operand[0].reg;
5516       ferr_assert(po, reg >= 0);
5517
5518       if (regmask_save_now & (1 << reg))
5519         regmask_save_now &= ~(1 << reg);
5520       else
5521         regmask_now &= ~(1 << reg);
5522       continue;
5523     }
5524     else if (po->op == OP_CALL) {
5525       if ((po->regmask_dst & (1 << xAX))
5526         && !(po->regmask_dst & (1 << xDX)))
5527       {
5528         if (po->flags & OPF_TAIL)
5529           // don't need eax, will do "return f();" or "f(); return;"
5530           po->regmask_dst &= ~(1 << xAX);
5531         else {
5532           struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5533           j = -1;
5534           find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5535           if (j == -1)
5536             // not used
5537             po->regmask_dst &= ~(1 << xAX);
5538         }
5539       }
5540
5541       // not "full stack" mode and have something in stack
5542       if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5543         ferr(po, "float stack is not empty on func call\n");
5544     }
5545
5546     if (po->flags & OPF_NOREGS)
5547       continue;
5548
5549     // if incomplete register is used, clear it on init to avoid
5550     // later use of uninitialized upper part in some situations
5551     if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5552         && po->operand[0].lmod != OPLM_DWORD)
5553     {
5554       reg = po->operand[0].reg;
5555       ferr_assert(po, reg >= 0);
5556
5557       if (!(regmask_now & (1 << reg)))
5558         *regmask_init |= 1 << reg;
5559     }
5560
5561     regmask_op = po->regmask_src | po->regmask_dst;
5562
5563     regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5564     regmask_new &= ~(1 << xSP);
5565     if (g_bp_frame && !(po->flags & OPF_EBP_S))
5566       regmask_new &= ~(1 << xBP);
5567
5568     if (regmask_new != 0)
5569       fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5570
5571     if (regmask_op & (1 << xBP)) {
5572       if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5573         if (po->regmask_dst & (1 << xBP))
5574           // compiler decided to drop bp frame and use ebp as scratch
5575           scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5576         else
5577           regmask_op &= ~(1 << xBP);
5578       }
5579     }
5580
5581     if (po->flags & OPF_FPUSH) {
5582       if (regmask_now & mxST1)
5583         regmask_now |= mxSTa; // switch to "full stack" mode
5584       if (regmask_now & mxSTa)
5585         po->flags |= OPF_FSHIFT;
5586       if (!(regmask_now & mxST7_2)) {
5587         regmask_now =
5588           (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5589       }
5590     }
5591
5592     regmask_now |= regmask_op;
5593     *regmask |= regmask_now;
5594
5595     // released regs
5596     if (po->flags & OPF_FPOPP) {
5597       if ((regmask_now & mxSTa) == 0)
5598         ferr(po, "float pop on empty stack?\n");
5599       if (regmask_now & mxST7_2)
5600         po->flags |= OPF_FSHIFT;
5601       if (!(regmask_now & mxST7_2))
5602         regmask_now &= ~mxST1_0;
5603     }
5604     else if (po->flags & OPF_FPOP) {
5605       if ((regmask_now & mxSTa) == 0)
5606         ferr(po, "float pop on empty stack?\n");
5607       if (regmask_now & (mxST7_2 | mxST1))
5608         po->flags |= OPF_FSHIFT;
5609       if (!(regmask_now & mxST7_2)) {
5610         regmask_now =
5611           (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5612       }
5613     }
5614
5615     if (po->flags & OPF_TAIL) {
5616       if (!(regmask_now & mxST7_2)) {
5617         if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5618           if (!(regmask_now & mxST0))
5619             ferr(po, "no st0 on float return, mask: %x\n",
5620                  regmask_now);
5621         }
5622         else if (regmask_now & mxST1_0)
5623           ferr(po, "float regs on tail: %x\n", regmask_now);
5624       }
5625
5626       // there is support for "conditional tailcall", sort of
5627       if (!(po->flags & OPF_CC))
5628         return;
5629     }
5630   }
5631 }
5632
5633 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5634 {
5635   int i;
5636
5637   for (i = 0; i < pp->argc; i++)
5638     if (pp->arg[i].reg == NULL)
5639       break;
5640
5641   if (pp->argc_stack)
5642     memmove(&pp->arg[i + 1], &pp->arg[i],
5643       sizeof(pp->arg[0]) * pp->argc_stack);
5644   memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5645   pp->arg[i].reg = strdup(reg);
5646   pp->arg[i].type.name = strdup("int");
5647   pp->argc++;
5648   pp->argc_reg++;
5649 }
5650
5651 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5652   int *pfomask, const char *dst_opr_text)
5653 {
5654   if (*pfomask & (1 << PFO_Z)) {
5655     fprintf(fout, "\n  cond_z = (%s%s == 0);",
5656       lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5657     *pfomask &= ~(1 << PFO_Z);
5658   }
5659 }
5660
5661 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5662   int *pfomask, const char *dst_opr_text)
5663 {
5664   if (*pfomask & (1 << PFO_S)) {
5665     fprintf(fout, "\n  cond_s = (%s%s < 0);",
5666       lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5667     *pfomask &= ~(1 << PFO_S);
5668   }
5669 }
5670
5671 static void output_std_flags(FILE *fout, struct parsed_op *po,
5672   int *pfomask, const char *dst_opr_text)
5673 {
5674   output_std_flag_z(fout, po, pfomask, dst_opr_text);
5675   output_std_flag_s(fout, po, pfomask, dst_opr_text);
5676 }
5677
5678 enum {
5679   OPP_FORCE_NORETURN = (1 << 0),
5680   OPP_SIMPLE_ARGS    = (1 << 1),
5681   OPP_ALIGN          = (1 << 2),
5682 };
5683
5684 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5685   int flags)
5686 {
5687   const char *cconv = "";
5688
5689   if (pp->is_fastcall)
5690     cconv = "__fastcall ";
5691   else if (pp->is_stdcall && pp->argc_reg == 0)
5692     cconv = "__stdcall ";
5693
5694   fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5695
5696   if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5697     fprintf(fout, "noreturn ");
5698 }
5699
5700 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5701   int flags)
5702 {
5703   int i;
5704
5705   fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5706     pp->ret_type.name);
5707   if (pp->is_fptr)
5708     fprintf(fout, "(");
5709   output_pp_attrs(fout, pp, flags);
5710   if (pp->is_fptr)
5711     fprintf(fout, "*");
5712   fprintf(fout, "%s", pp->name);
5713   if (pp->is_fptr)
5714     fprintf(fout, ")");
5715
5716   fprintf(fout, "(");
5717   for (i = 0; i < pp->argc; i++) {
5718     if (i > 0)
5719       fprintf(fout, ", ");
5720     if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5721       && !(flags & OPP_SIMPLE_ARGS))
5722     {
5723       // func pointer
5724       output_pp(fout, pp->arg[i].pp, 0);
5725     }
5726     else if (pp->arg[i].type.is_retreg) {
5727       fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5728     }
5729     else {
5730       fprintf(fout, "%s", pp->arg[i].type.name);
5731       if (!pp->is_fptr)
5732         fprintf(fout, " a%d", i + 1);
5733     }
5734
5735     if (pp->arg[i].type.is_64bit)
5736       i++;
5737   }
5738   if (pp->is_vararg) {
5739     if (i > 0)
5740       fprintf(fout, ", ");
5741     fprintf(fout, "...");
5742   }
5743   fprintf(fout, ")");
5744 }
5745
5746 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5747 {
5748   char buf1[16];
5749
5750   buf1[0] = 0;
5751   if (grp > 0)
5752     snprintf(buf1, sizeof(buf1), "%d", grp);
5753   snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5754
5755   return buf;
5756 }
5757
5758 static void gen_x_cleanup(int opcnt);
5759
5760 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5761 {
5762   struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5763   struct parsed_opr *last_arith_dst = NULL;
5764   char buf1[256], buf2[256], buf3[256], cast[64];
5765   struct parsed_proto *pp, *pp_tmp;
5766   struct parsed_data *pd;
5767   int save_arg_vars[MAX_ARG_GRP] = { 0, };
5768   unsigned char cbits[MAX_OPS / 8];
5769   const char *float_type;
5770   const char *float_st0;
5771   const char *float_st1;
5772   int need_float_stack = 0;
5773   int need_float_sw = 0; // status word
5774   int need_tmp_var = 0;
5775   int need_tmp64 = 0;
5776   int cond_vars = 0;
5777   int had_decl = 0;
5778   int label_pending = 0;
5779   int need_double = 0;
5780   int stack_align = 0;
5781   int stack_fsz_adj = 0;
5782   int regmask_save = 0; // used regs saved/restored in this func
5783   int regmask_arg;      // regs from this function args (fastcall, etc)
5784   int regmask_ret;      // regs needed on ret
5785   int regmask_now;      // temp
5786   int regmask_init = 0; // regs that need zero initialization
5787   int regmask_pp = 0;   // regs used in complex push-pop graph
5788   int regmask_ffca = 0; // float function call args
5789   int regmask = 0;      // used regs
5790   int pfomask = 0;
5791   int found = 0;
5792   int dead_dst;
5793   int no_output;
5794   int i, j, l;
5795   int arg;
5796   int reg;
5797   int ret;
5798
5799   g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5800   g_stack_frame_used = 0;
5801   g_seh_size = 0;
5802   if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5803     regmask_init = g_regmask_init;
5804
5805   g_func_pp = proto_parse(fhdr, funcn, 0);
5806   if (g_func_pp == NULL)
5807     ferr(ops, "proto_parse failed for '%s'\n", funcn);
5808
5809   regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5810   regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5811
5812   // pass1:
5813   // - resolve all branches
5814   // - parse calls with labels
5815   resolve_branches_parse_calls(opcnt);
5816
5817   // pass2:
5818   // - handle ebp/esp frame, remove ops related to it
5819   scan_prologue_epilogue(opcnt, &stack_align);
5820
5821   // handle a case where sf size is unalignment, but is
5822   // placed in a way that elements are still aligned
5823   if (g_stack_fsz & 4) {
5824     for (i = 0; i < g_eqcnt; i++) {
5825       if (g_eqs[i].lmod != OPLM_QWORD)
5826         continue;
5827       if (!(g_eqs[i].offset & 4)) {
5828         g_stack_fsz += 4;
5829         stack_fsz_adj = 4;
5830       }
5831       break;
5832     }
5833   }
5834
5835   // pass3:
5836   // - remove dead labels
5837   // - set regs needed at ret
5838   for (i = 0; i < opcnt; i++)
5839   {
5840     if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5841       free(g_labels[i]);
5842       g_labels[i] = NULL;
5843     }
5844
5845     if (ops[i].op == OP_RET)
5846       ops[i].regmask_src |= regmask_ret;
5847   }
5848
5849   // pass4:
5850   // - process trivial calls
5851   for (i = 0; i < opcnt; i++)
5852   {
5853     po = &ops[i];
5854     if (po->flags & (OPF_RMD|OPF_DONE))
5855       continue;
5856
5857     if (po->op == OP_CALL)
5858     {
5859       pp = process_call_early(i, opcnt, &j);
5860       if (pp != NULL) {
5861         if (!(po->flags & OPF_ATAIL)) {
5862           // since we know the args, try to collect them
5863           ret = collect_call_args_early(i, pp, &regmask, &regmask_ffca);
5864           if (ret != 0)
5865             pp = NULL;
5866         }
5867       }
5868
5869       if (pp != NULL) {
5870         if (j >= 0) {
5871           // commit esp adjust
5872           if (ops[j].op != OP_POP)
5873             patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5874           else {
5875             for (l = 0; l < pp->argc_stack; l++)
5876               ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5877           }
5878         }
5879
5880         if (strstr(pp->ret_type.name, "int64"))
5881           need_tmp64 = 1;
5882
5883         po->flags |= OPF_DONE;
5884       }
5885     }
5886   }
5887
5888   // pass5:
5889   // - process calls, stage 2
5890   // - handle some push/pop pairs
5891   // - scan for STD/CLD, propagate DF
5892   // - try to resolve needed x87 status word bits
5893   for (i = 0; i < opcnt; i++)
5894   {
5895     int mask, z_check;
5896
5897     po = &ops[i];
5898     if (po->flags & OPF_RMD)
5899       continue;
5900
5901     if (po->op == OP_CALL)
5902     {
5903       if (!(po->flags & OPF_DONE)) {
5904         pp = process_call(i, opcnt);
5905
5906         if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5907           // since we know the args, collect them
5908           collect_call_args(po, i, pp, &regmask, i + opcnt * 2);
5909         }
5910         // for unresolved, collect after other passes
5911       }
5912
5913       pp = po->pp;
5914       ferr_assert(po, pp != NULL);
5915
5916       po->regmask_src |= get_pp_arg_regmask_src(pp);
5917       po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5918
5919       if (po->regmask_dst & mxST0)
5920         po->flags |= OPF_FPUSH;
5921
5922       if (strstr(pp->ret_type.name, "int64"))
5923         need_tmp64 = 1;
5924
5925       continue;
5926     }
5927
5928     if (po->flags & OPF_DONE)
5929       continue;
5930
5931     switch (po->op) {
5932     case OP_PUSH:
5933       if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
5934         && po->operand[0].type == OPT_CONST)
5935       {
5936         scan_for_pop_const(i, opcnt, i + opcnt * 12);
5937       }
5938       break;
5939
5940     case OP_POP:
5941       scan_pushes_for_pop(i, opcnt, &regmask_pp);
5942       break;
5943
5944     case OP_STD:
5945       po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5946       scan_propagate_df(i + 1, opcnt);
5947       break;
5948
5949     case OP_FNSTSW:
5950       need_float_sw = 1;
5951       if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
5952         ferr(po, "TODO: fnstsw to mem\n");
5953       ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
5954       if (ret != 0)
5955         ferr(po, "fnstsw resolve failed\n");
5956       ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
5957               (void *)(long)(mask | (z_check << 16)));
5958       if (ret != 1)
5959         ferr(po, "failed to find fcom: %d\n", ret);
5960       break;
5961
5962     default:
5963       break;
5964     }
5965   }
5966
5967   // pass6:
5968   // - find POPs for PUSHes, rm both
5969   // - scan for all used registers
5970   memset(cbits, 0, sizeof(cbits));
5971   reg_use_pass(0, opcnt, cbits, regmask_init, &regmask,
5972     0, &regmask_save, &regmask_init, regmask_arg);
5973
5974   need_float_stack = !!(regmask & mxST7_2);
5975
5976   // pass7:
5977   // - find flag set ops for their users
5978   // - do unresolved calls
5979   // - declare indirect functions
5980   // - other op specific processing
5981   for (i = 0; i < opcnt; i++)
5982   {
5983     po = &ops[i];
5984     if (po->flags & (OPF_RMD|OPF_DONE))
5985       continue;
5986
5987     if (po->flags & OPF_CC)
5988     {
5989       int setters[16], cnt = 0, branched = 0;
5990
5991       ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
5992               &branched, setters, &cnt);
5993       if (ret < 0 || cnt <= 0)
5994         ferr(po, "unable to trace flag setter(s)\n");
5995       if (cnt > ARRAY_SIZE(setters))
5996         ferr(po, "too many flag setters\n");
5997
5998       for (j = 0; j < cnt; j++)
5999       {
6000         tmp_op = &ops[setters[j]]; // flag setter
6001         pfomask = 0;
6002
6003         // to get nicer code, we try to delay test and cmp;
6004         // if we can't because of operand modification, or if we
6005         // have arith op, or branch, make it calculate flags explicitly
6006         if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
6007         {
6008           if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
6009             pfomask = 1 << po->pfo;
6010         }
6011         else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
6012           pfomask = 1 << po->pfo;
6013         }
6014         else {
6015           // see if we'll be able to handle based on op result
6016           if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
6017                && po->pfo != PFO_Z && po->pfo != PFO_S
6018                && po->pfo != PFO_P)
6019               || branched
6020               || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
6021           {
6022             pfomask = 1 << po->pfo;
6023           }
6024
6025           if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
6026             propagate_lmod(tmp_op, &tmp_op->operand[0],
6027               &tmp_op->operand[1]);
6028             if (tmp_op->operand[0].lmod == OPLM_DWORD)
6029               need_tmp64 = 1;
6030           }
6031         }
6032         if (pfomask) {
6033           tmp_op->pfomask |= pfomask;
6034           cond_vars |= pfomask;
6035         }
6036         // note: may overwrite, currently not a problem
6037         po->datap = tmp_op;
6038       }
6039
6040       if (po->op == OP_RCL || po->op == OP_RCR
6041        || po->op == OP_ADC || po->op == OP_SBB)
6042         cond_vars |= 1 << PFO_C;
6043     }
6044
6045     switch (po->op) {
6046     case OP_CMPS:
6047     case OP_SCAS:
6048       cond_vars |= 1 << PFO_Z;
6049       break;
6050
6051     case OP_MUL:
6052       if (po->operand[0].lmod == OPLM_DWORD)
6053         need_tmp64 = 1;
6054       break;
6055
6056     case OP_IMUL:
6057       if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
6058         need_tmp64 = 1;
6059       break;
6060
6061     case OP_CALL:
6062       // note: resolved non-reg calls are OPF_DONE already
6063       pp = po->pp;
6064       ferr_assert(po, pp != NULL);
6065
6066       if (pp->is_unresolved) {
6067         int regmask_stack = 0;
6068         collect_call_args(po, i, pp, &regmask, i + opcnt * 2);
6069
6070         // this is pretty rough guess:
6071         // see ecx and edx were pushed (and not their saved versions)
6072         for (arg = 0; arg < pp->argc; arg++) {
6073           if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
6074             continue;
6075
6076           tmp_op = pp->arg[arg].datap;
6077           if (tmp_op == NULL)
6078             ferr(po, "parsed_op missing for arg%d\n", arg);
6079           if (tmp_op->operand[0].type == OPT_REG)
6080             regmask_stack |= 1 << tmp_op->operand[0].reg;
6081         }
6082
6083         if (!((regmask_stack & (1 << xCX))
6084           && (regmask_stack & (1 << xDX))))
6085         {
6086           if (pp->argc_stack != 0
6087            || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
6088           {
6089             pp_insert_reg_arg(pp, "ecx");
6090             pp->is_fastcall = 1;
6091             regmask_init |= 1 << xCX;
6092             regmask |= 1 << xCX;
6093           }
6094           if (pp->argc_stack != 0
6095            || ((regmask | regmask_arg) & (1 << xDX)))
6096           {
6097             pp_insert_reg_arg(pp, "edx");
6098             regmask_init |= 1 << xDX;
6099             regmask |= 1 << xDX;
6100           }
6101         }
6102
6103         // note: __cdecl doesn't fall into is_unresolved category
6104         if (pp->argc_stack > 0)
6105           pp->is_stdcall = 1;
6106       }
6107       break;
6108
6109     case OP_MOV:
6110       if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6111       {
6112         // <var> = offset <something>
6113         if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6114           && !IS_START(po->operand[1].name, "off_"))
6115         {
6116           if (!po->operand[0].pp->is_fptr)
6117             ferr(po, "%s not declared as fptr when it should be\n",
6118               po->operand[0].name);
6119           if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6120             pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6121             pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6122             fnote(po, "var:  %s\n", buf1);
6123             fnote(po, "func: %s\n", buf2);
6124             ferr(po, "^ mismatch\n");
6125           }
6126         }
6127       }
6128       break;
6129
6130     case OP_DIV:
6131     case OP_IDIV:
6132       if (po->operand[0].lmod == OPLM_DWORD) {
6133         // 32bit division is common, look for it
6134         if (po->op == OP_DIV)
6135           ret = scan_for_reg_clear(i, xDX);
6136         else
6137           ret = scan_for_cdq_edx(i);
6138         if (ret >= 0)
6139           po->flags |= OPF_32BIT;
6140         else
6141           need_tmp64 = 1;
6142       }
6143       else
6144         need_tmp_var = 1;
6145       break;
6146
6147     case OP_CLD:
6148       po->flags |= OPF_RMD | OPF_DONE;
6149       break;
6150
6151     case OP_RCL:
6152     case OP_RCR:
6153     case OP_XCHG:
6154       need_tmp_var = 1;
6155       break;
6156
6157     case OP_FLD:
6158       if (po->operand[0].lmod == OPLM_QWORD)
6159         need_double = 1;
6160       break;
6161
6162     case OPP_ALLSHL:
6163     case OPP_ALLSHR:
6164       need_tmp64 = 1;
6165       break;
6166
6167     case OPP_FTOL: {
6168       struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
6169       j = -1;
6170       find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
6171       if (j == -1)
6172         po->flags |= OPF_32BIT;
6173       break;
6174     }
6175
6176     default:
6177       break;
6178     }
6179
6180     // this might need it's own pass...
6181     if (po->op != OP_FST && po->p_argnum > 0)
6182       save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6183
6184     // correct for "full stack" mode late enable
6185     if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6186         && need_float_stack)
6187       po->flags |= OPF_FSHIFT;
6188   }
6189
6190   float_type = need_double ? "double" : "float";
6191   float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6192   float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6193
6194   // output starts here
6195
6196   if (g_seh_found)
6197     fprintf(fout, "// had SEH\n");
6198
6199   // define userstack size
6200   if (g_func_pp->is_userstack) {
6201     fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6202     fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6203     fprintf(fout, "#endif\n");
6204   }
6205
6206   // the function itself
6207   ferr_assert(ops, !g_func_pp->is_fptr);
6208   output_pp(fout, g_func_pp,
6209     (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6210   fprintf(fout, "\n{\n");
6211
6212   // declare indirect functions
6213   for (i = 0; i < opcnt; i++) {
6214     po = &ops[i];
6215     if (po->flags & OPF_RMD)
6216       continue;
6217
6218     if (po->op == OP_CALL) {
6219       pp = po->pp;
6220       if (pp == NULL)
6221         ferr(po, "NULL pp\n");
6222
6223       if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6224         if (pp->name[0] != 0) {
6225           memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6226           memcpy(pp->name, "i_", 2);
6227
6228           // might be declared already
6229           found = 0;
6230           for (j = 0; j < i; j++) {
6231             if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6232               if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6233                 found = 1;
6234                 break;
6235               }
6236             }
6237           }
6238           if (found)
6239             continue;
6240         }
6241         else
6242           snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6243
6244         fprintf(fout, "  ");
6245         output_pp(fout, pp, OPP_SIMPLE_ARGS);
6246         fprintf(fout, ";\n");
6247       }
6248     }
6249   }
6250
6251   // output LUTs/jumptables
6252   for (i = 0; i < g_func_pd_cnt; i++) {
6253     pd = &g_func_pd[i];
6254     fprintf(fout, "  static const ");
6255     if (pd->type == OPT_OFFSET) {
6256       fprintf(fout, "void *jt_%s[] =\n    { ", pd->label);
6257
6258       for (j = 0; j < pd->count; j++) {
6259         if (j > 0)
6260           fprintf(fout, ", ");
6261         fprintf(fout, "&&%s", pd->d[j].u.label);
6262       }
6263     }
6264     else {
6265       fprintf(fout, "%s %s[] =\n    { ",
6266         lmod_type_u(ops, pd->lmod), pd->label);
6267
6268       for (j = 0; j < pd->count; j++) {
6269         if (j > 0)
6270           fprintf(fout, ", ");
6271         fprintf(fout, "%u", pd->d[j].u.val);
6272       }
6273     }
6274     fprintf(fout, " };\n");
6275     had_decl = 1;
6276   }
6277
6278   // declare stack frame, va_arg
6279   if (g_stack_fsz) {
6280     if (stack_fsz_adj)
6281       fprintf(fout, "  // stack_fsz_adj %d\n", stack_fsz_adj);
6282
6283     fprintf(fout, "  union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6284     if (g_func_lmods & (1 << OPLM_WORD))
6285       fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6286     if (g_func_lmods & (1 << OPLM_BYTE))
6287       fprintf(fout, " u8 b[%d];", g_stack_fsz);
6288     if (g_func_lmods & (1 << OPLM_QWORD))
6289       fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6290
6291     if (stack_align > 8)
6292       ferr(ops, "unhandled stack align of %d\n", stack_align);
6293     else if (stack_align == 8)
6294       fprintf(fout, " u64 align;");
6295     fprintf(fout, " } sf;\n");
6296     had_decl = 1;
6297   }
6298
6299   if (g_func_pp->is_userstack) {
6300     fprintf(fout, "  u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6301     fprintf(fout, "  u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6302     had_decl = 1;
6303   }
6304
6305   if (g_func_pp->is_vararg) {
6306     fprintf(fout, "  va_list ap;\n");
6307     had_decl = 1;
6308   }
6309
6310   // declare arg-registers
6311   for (i = 0; i < g_func_pp->argc; i++) {
6312     if (g_func_pp->arg[i].reg != NULL) {
6313       reg = char_array_i(regs_r32,
6314               ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6315       if (regmask & (1 << reg)) {
6316         if (g_func_pp->arg[i].type.is_retreg)
6317           fprintf(fout, "  u32 %s = *r_%s;\n",
6318             g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6319         else
6320           fprintf(fout, "  u32 %s = (u32)a%d;\n",
6321             g_func_pp->arg[i].reg, i + 1);
6322       }
6323       else {
6324         if (g_func_pp->arg[i].type.is_retreg)
6325           ferr(ops, "retreg '%s' is unused?\n",
6326             g_func_pp->arg[i].reg);
6327         fprintf(fout, "  // %s = a%d; // unused\n",
6328           g_func_pp->arg[i].reg, i + 1);
6329       }
6330       had_decl = 1;
6331     }
6332   }
6333
6334   // declare normal registers
6335   regmask_now = regmask & ~regmask_arg;
6336   regmask_now &= ~(1 << xSP);
6337   if (regmask_now & 0x00ff) {
6338     for (reg = 0; reg < 8; reg++) {
6339       if (regmask_now & (1 << reg)) {
6340         fprintf(fout, "  u32 %s", regs_r32[reg]);
6341         if (regmask_init & (1 << reg))
6342           fprintf(fout, " = 0");
6343         fprintf(fout, ";\n");
6344         had_decl = 1;
6345       }
6346     }
6347   }
6348   // ... mmx
6349   if (regmask_now & 0xff00) {
6350     for (reg = 8; reg < 16; reg++) {
6351       if (regmask_now & (1 << reg)) {
6352         fprintf(fout, "  mmxr %s", regs_r32[reg]);
6353         if (regmask_init & (1 << reg))
6354           fprintf(fout, " = { 0, }");
6355         fprintf(fout, ";\n");
6356         had_decl = 1;
6357       }
6358     }
6359   }
6360   // ... x87
6361   if (need_float_stack) {
6362     fprintf(fout, "  %s f_st[8];\n", float_type);
6363     fprintf(fout, "  int f_stp = 0;\n");
6364     had_decl = 1;
6365   }
6366   else {
6367     if (regmask_now & 0xff0000) {
6368       for (reg = 16; reg < 24; reg++) {
6369         if (regmask_now & (1 << reg)) {
6370           fprintf(fout, "  %s f_st%d", float_type, reg - 16);
6371           if (regmask_init & (1 << reg))
6372             fprintf(fout, " = 0");
6373           fprintf(fout, ";\n");
6374           had_decl = 1;
6375         }
6376       }
6377     }
6378   }
6379
6380   if (need_float_sw) {
6381     fprintf(fout, "  u16 f_sw;\n");
6382     had_decl = 1;
6383   }
6384
6385   if (regmask_save) {
6386     for (reg = 0; reg < 8; reg++) {
6387       if (regmask_save & (1 << reg)) {
6388         fprintf(fout, "  u32 s_%s;\n", regs_r32[reg]);
6389         had_decl = 1;
6390       }
6391     }
6392   }
6393
6394   for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6395     if (save_arg_vars[i] == 0)
6396       continue;
6397     for (reg = 0; reg < 32; reg++) {
6398       if (save_arg_vars[i] & (1 << reg)) {
6399         fprintf(fout, "  u32 %s;\n",
6400           saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6401         had_decl = 1;
6402       }
6403     }
6404   }
6405
6406   if (regmask_ffca) {
6407     for (reg = 0; reg < 32; reg++) {
6408       if (regmask_ffca & (1 << reg)) {
6409         fprintf(fout, "  %s fs_%d;\n", float_type, reg + 1);
6410         had_decl = 1;
6411       }
6412     }
6413   }
6414
6415   // declare push-pop temporaries
6416   if (regmask_pp) {
6417     for (reg = 0; reg < 8; reg++) {
6418       if (regmask_pp & (1 << reg)) {
6419         fprintf(fout, "  u32 pp_%s;\n", regs_r32[reg]);
6420         had_decl = 1;
6421       }
6422     }
6423   }
6424
6425   if (cond_vars) {
6426     for (i = 0; i < 8; i++) {
6427       if (cond_vars & (1 << i)) {
6428         fprintf(fout, "  u32 cond_%s;\n", parsed_flag_op_names[i]);
6429         had_decl = 1;
6430       }
6431     }
6432   }
6433
6434   if (need_tmp_var) {
6435     fprintf(fout, "  u32 tmp;\n");
6436     had_decl = 1;
6437   }
6438
6439   if (need_tmp64) {
6440     fprintf(fout, "  u64 tmp64;\n");
6441     had_decl = 1;
6442   }
6443
6444   if (had_decl)
6445     fprintf(fout, "\n");
6446
6447   // do stack clear, if needed
6448   if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6449     fprintf(fout, "  ");
6450     if (g_stack_clear_len != 0) {
6451       if (g_stack_clear_len <= 4) {
6452         for (i = 0; i < g_stack_clear_len; i++)
6453           fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6454         fprintf(fout, "0;\n");
6455       }
6456       else {
6457         fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6458           g_stack_clear_start, g_stack_clear_len * 4);
6459       }
6460     }
6461     else
6462       fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6463   }
6464
6465   if (g_func_pp->is_vararg) {
6466     if (g_func_pp->argc_stack == 0)
6467       ferr(ops, "vararg func without stack args?\n");
6468     fprintf(fout, "  va_start(ap, a%d);\n", g_func_pp->argc);
6469   }
6470
6471   // output ops
6472   for (i = 0; i < opcnt; i++)
6473   {
6474     if (g_labels[i] != NULL) {
6475       fprintf(fout, "\n%s:\n", g_labels[i]);
6476       label_pending = 1;
6477
6478       delayed_flag_op = NULL;
6479       last_arith_dst = NULL;
6480     }
6481
6482     po = &ops[i];
6483     if (po->flags & OPF_RMD)
6484       continue;
6485
6486     no_output = 0;
6487
6488     #define assert_operand_cnt(n_) \
6489       if (po->operand_cnt != n_) \
6490         ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6491
6492     // conditional/flag using op?
6493     if (po->flags & OPF_CC)
6494     {
6495       int is_delayed = 0;
6496
6497       tmp_op = po->datap;
6498
6499       // we go through all this trouble to avoid using parsed_flag_op,
6500       // which makes generated code much nicer
6501       if (delayed_flag_op != NULL)
6502       {
6503         out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6504           po->pfo, po->pfo_inv);
6505         is_delayed = 1;
6506       }
6507       else if (last_arith_dst != NULL
6508         && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6509            || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6510            ))
6511       {
6512         out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6513         out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6514           last_arith_dst->lmod, buf3);
6515         is_delayed = 1;
6516       }
6517       else if (tmp_op != NULL) {
6518         // use preprocessed flag calc results
6519         if (!(tmp_op->pfomask & (1 << po->pfo)))
6520           ferr(po, "not prepared for pfo %d\n", po->pfo);
6521
6522         // note: pfo_inv was not yet applied
6523         snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6524           po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6525       }
6526       else {
6527         ferr(po, "all methods of finding comparison failed\n");
6528       }
6529  
6530       if (po->flags & OPF_JMP) {
6531         fprintf(fout, "  if %s", buf1);
6532       }
6533       else if (po->op == OP_RCL || po->op == OP_RCR
6534                || po->op == OP_ADC || po->op == OP_SBB)
6535       {
6536         if (is_delayed)
6537           fprintf(fout, "  cond_%s = %s;\n",
6538             parsed_flag_op_names[po->pfo], buf1);
6539       }
6540       else if (po->flags & OPF_DATA) { // SETcc
6541         out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6542         fprintf(fout, "  %s = %s;", buf2, buf1);
6543       }
6544       else {
6545         ferr(po, "unhandled conditional op\n");
6546       }
6547     }
6548
6549     pfomask = po->pfomask;
6550
6551     switch (po->op)
6552     {
6553       case OP_MOV:
6554         assert_operand_cnt(2);
6555         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6556         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6557         default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6558         fprintf(fout, "  %s = %s;", buf1,
6559             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6560               buf3, 0));
6561         break;
6562
6563       case OP_LEA:
6564         assert_operand_cnt(2);
6565         po->operand[1].lmod = OPLM_DWORD; // always
6566         fprintf(fout, "  %s = %s;",
6567             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6568             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6569               NULL, 1));
6570         break;
6571
6572       case OP_MOVZX:
6573         assert_operand_cnt(2);
6574         fprintf(fout, "  %s = %s;",
6575             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6576             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6577         break;
6578
6579       case OP_MOVSX:
6580         assert_operand_cnt(2);
6581         switch (po->operand[1].lmod) {
6582         case OPLM_BYTE:
6583           strcpy(buf3, "(s8)");
6584           break;
6585         case OPLM_WORD:
6586           strcpy(buf3, "(s16)");
6587           break;
6588         default:
6589           ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6590         }
6591         fprintf(fout, "  %s = %s;",
6592             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6593             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6594               buf3, 0));
6595         break;
6596
6597       case OP_XCHG:
6598         assert_operand_cnt(2);
6599         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6600         fprintf(fout, "  tmp = %s;",
6601           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6602         fprintf(fout, " %s = %s;",
6603           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6604           out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6605             default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6606         fprintf(fout, " %s = %stmp;",
6607           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6608           default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6609         snprintf(g_comment, sizeof(g_comment), "xchg");
6610         break;
6611
6612       case OP_NOT:
6613         assert_operand_cnt(1);
6614         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6615         fprintf(fout, "  %s = ~%s;", buf1, buf1);
6616         break;
6617
6618       case OP_XLAT:
6619         assert_operand_cnt(2);
6620         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6621         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6622         fprintf(fout, "  %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6623         strcpy(g_comment, "xlat");
6624         break;
6625
6626       case OP_CDQ:
6627         assert_operand_cnt(2);
6628         fprintf(fout, "  %s = (s32)%s >> 31;",
6629             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6630             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6631         strcpy(g_comment, "cdq");
6632         break;
6633
6634       case OP_BSWAP:
6635         assert_operand_cnt(1);
6636         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6637         fprintf(fout, "  %s = __builtin_bswap32(%s);", buf1, buf1);
6638         break;
6639
6640       case OP_LODS:
6641         if (po->flags & OPF_REP) {
6642           assert_operand_cnt(3);
6643           // hmh..
6644           ferr(po, "TODO\n");
6645         }
6646         else {
6647           assert_operand_cnt(2);
6648           fprintf(fout, "  %s = %sesi; esi %c= %d;",
6649             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6650             lmod_cast_u_ptr(po, po->operand[1].lmod),
6651             (po->flags & OPF_DF) ? '-' : '+',
6652             lmod_bytes(po, po->operand[1].lmod));
6653           strcpy(g_comment, "lods");
6654         }
6655         break;
6656
6657       case OP_STOS:
6658         if (po->flags & OPF_REP) {
6659           assert_operand_cnt(3);
6660           fprintf(fout, "  for (; ecx != 0; ecx--, edi %c= %d)\n",
6661             (po->flags & OPF_DF) ? '-' : '+',
6662             lmod_bytes(po, po->operand[1].lmod));
6663           fprintf(fout, "    %sedi = eax;",
6664             lmod_cast_u_ptr(po, po->operand[1].lmod));
6665           strcpy(g_comment, "rep stos");
6666         }
6667         else {
6668           assert_operand_cnt(2);
6669           fprintf(fout, "  %sedi = eax; edi %c= %d;",
6670             lmod_cast_u_ptr(po, po->operand[1].lmod),
6671             (po->flags & OPF_DF) ? '-' : '+',
6672             lmod_bytes(po, po->operand[1].lmod));
6673           strcpy(g_comment, "stos");
6674         }
6675         break;
6676
6677       case OP_MOVS:
6678         j = lmod_bytes(po, po->operand[0].lmod);
6679         strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6680         l = (po->flags & OPF_DF) ? '-' : '+';
6681         if (po->flags & OPF_REP) {
6682           assert_operand_cnt(3);
6683           fprintf(fout,
6684             "  for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6685             l, j, l, j);
6686           fprintf(fout,
6687             "    %sedi = %sesi;", buf1, buf1);
6688           strcpy(g_comment, "rep movs");
6689         }
6690         else {
6691           assert_operand_cnt(2);
6692           fprintf(fout, "  %sedi = %sesi; edi %c= %d; esi %c= %d;",
6693             buf1, buf1, l, j, l, j);
6694           strcpy(g_comment, "movs");
6695         }
6696         break;
6697
6698       case OP_CMPS:
6699         // repe ~ repeat while ZF=1
6700         j = lmod_bytes(po, po->operand[0].lmod);
6701         strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6702         l = (po->flags & OPF_DF) ? '-' : '+';
6703         if (po->flags & OPF_REP) {
6704           assert_operand_cnt(3);
6705           fprintf(fout,
6706             "  while (ecx != 0) {\n");
6707           if (pfomask & (1 << PFO_C)) {
6708             // ugh..
6709             fprintf(fout,
6710             "    cond_c = %sesi < %sedi;\n", buf1, buf1);
6711             pfomask &= ~(1 << PFO_C);
6712           }
6713           fprintf(fout,
6714             "    cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6715               buf1, buf1, l, j, l, j);
6716           fprintf(fout,
6717             "    ecx--;\n"
6718             "    if (cond_z %s 0) break;\n",
6719               (po->flags & OPF_REPZ) ? "==" : "!=");
6720           fprintf(fout,
6721             "  }");
6722           snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6723             (po->flags & OPF_REPZ) ? "e" : "ne");
6724         }
6725         else {
6726           assert_operand_cnt(2);
6727           fprintf(fout,
6728             "  cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6729             buf1, buf1, l, j, l, j);
6730           strcpy(g_comment, "cmps");
6731         }
6732         pfomask &= ~(1 << PFO_Z);
6733         last_arith_dst = NULL;
6734         delayed_flag_op = NULL;
6735         break;
6736
6737       case OP_SCAS:
6738         // only does ZF (for now)
6739         // repe ~ repeat while ZF=1
6740         j = lmod_bytes(po, po->operand[1].lmod);
6741         l = (po->flags & OPF_DF) ? '-' : '+';
6742         if (po->flags & OPF_REP) {
6743           assert_operand_cnt(3);
6744           fprintf(fout,
6745             "  while (ecx != 0) {\n");
6746           fprintf(fout,
6747             "    cond_z = (%seax == %sedi); edi %c= %d;\n",
6748               lmod_cast_u(po, po->operand[1].lmod),
6749               lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6750           fprintf(fout,
6751             "    ecx--;\n"
6752             "    if (cond_z %s 0) break;\n",
6753               (po->flags & OPF_REPZ) ? "==" : "!=");
6754           fprintf(fout,
6755             "  }");
6756           snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6757             (po->flags & OPF_REPZ) ? "e" : "ne");
6758         }
6759         else {
6760           assert_operand_cnt(2);
6761           fprintf(fout, "  cond_z = (%seax == %sedi); edi %c= %d;",
6762               lmod_cast_u(po, po->operand[1].lmod),
6763               lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6764           strcpy(g_comment, "scas");
6765         }
6766         pfomask &= ~(1 << PFO_Z);
6767         last_arith_dst = NULL;
6768         delayed_flag_op = NULL;
6769         break;
6770
6771       // arithmetic w/flags
6772       case OP_AND:
6773         if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6774           goto dualop_arith_const;
6775         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6776         goto dualop_arith;
6777
6778       case OP_OR:
6779         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6780         if (po->operand[1].type == OPT_CONST) {
6781           j = lmod_bytes(po, po->operand[0].lmod);
6782           if (((1ull << j * 8) - 1) == po->operand[1].val)
6783             goto dualop_arith_const;
6784         }
6785         goto dualop_arith;
6786
6787       dualop_arith:
6788         assert_operand_cnt(2);
6789         fprintf(fout, "  %s %s= %s;",
6790             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6791             op_to_c(po),
6792             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6793         output_std_flags(fout, po, &pfomask, buf1);
6794         last_arith_dst = &po->operand[0];
6795         delayed_flag_op = NULL;
6796         break;
6797
6798       dualop_arith_const:
6799         // and 0, or ~0 used instead mov
6800         assert_operand_cnt(2);
6801         fprintf(fout, "  %s = %s;",
6802           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6803           out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6804            default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6805         output_std_flags(fout, po, &pfomask, buf1);
6806         last_arith_dst = &po->operand[0];
6807         delayed_flag_op = NULL;
6808         break;
6809
6810       case OP_SHL:
6811       case OP_SHR:
6812         assert_operand_cnt(2);
6813         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6814         if (pfomask & (1 << PFO_C)) {
6815           if (po->operand[1].type == OPT_CONST) {
6816             l = lmod_bytes(po, po->operand[0].lmod) * 8;
6817             j = po->operand[1].val;
6818             j %= l;
6819             if (j != 0) {
6820               if (po->op == OP_SHL)
6821                 j = l - j;
6822               else
6823                 j -= 1;
6824               fprintf(fout, "  cond_c = (%s >> %d) & 1;\n",
6825                 buf1, j);
6826             }
6827             else
6828               ferr(po, "zero shift?\n");
6829           }
6830           else
6831             ferr(po, "TODO\n");
6832           pfomask &= ~(1 << PFO_C);
6833         }
6834         fprintf(fout, "  %s %s= %s", buf1, op_to_c(po),
6835             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6836         if (po->operand[1].type != OPT_CONST)
6837           fprintf(fout, " & 0x1f");
6838         fprintf(fout, ";");
6839         output_std_flags(fout, po, &pfomask, buf1);
6840         last_arith_dst = &po->operand[0];
6841         delayed_flag_op = NULL;
6842         break;
6843
6844       case OP_SAR:
6845         assert_operand_cnt(2);
6846         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6847         fprintf(fout, "  %s = %s%s >> %s;", buf1,
6848           lmod_cast_s(po, po->operand[0].lmod), buf1,
6849           out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6850         output_std_flags(fout, po, &pfomask, buf1);
6851         last_arith_dst = &po->operand[0];
6852         delayed_flag_op = NULL;
6853         break;
6854
6855       case OP_SHLD:
6856       case OP_SHRD:
6857         assert_operand_cnt(3);
6858         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6859         l = lmod_bytes(po, po->operand[0].lmod) * 8;
6860         out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6861         if (po->operand[2].type != OPT_CONST) {
6862           // no handling for "undefined" case, hopefully not needed
6863           snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6864           strcpy(buf3, buf2);
6865         }
6866         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6867         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6868         if (po->op == OP_SHLD) {
6869           fprintf(fout, "  %s <<= %s; %s |= %s >> (%d - %s);",
6870             buf1, buf3, buf1, buf2, l, buf3);
6871           strcpy(g_comment, "shld");
6872         }
6873         else {
6874           fprintf(fout, "  %s >>= %s; %s |= %s << (%d - %s);",
6875             buf1, buf3, buf1, buf2, l, buf3);
6876           strcpy(g_comment, "shrd");
6877         }
6878         output_std_flags(fout, po, &pfomask, buf1);
6879         last_arith_dst = &po->operand[0];
6880         delayed_flag_op = NULL;
6881         break;
6882
6883       case OP_ROL:
6884       case OP_ROR:
6885         assert_operand_cnt(2);
6886         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6887         if (po->operand[1].type == OPT_CONST) {
6888           j = po->operand[1].val;
6889           j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6890           fprintf(fout, po->op == OP_ROL ?
6891             "  %s = (%s << %d) | (%s >> %d);" :
6892             "  %s = (%s >> %d) | (%s << %d);",
6893             buf1, buf1, j, buf1,
6894             lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6895         }
6896         else
6897           ferr(po, "TODO\n");
6898         output_std_flags(fout, po, &pfomask, buf1);
6899         last_arith_dst = &po->operand[0];
6900         delayed_flag_op = NULL;
6901         break;
6902
6903       case OP_RCL:
6904       case OP_RCR:
6905         assert_operand_cnt(2);
6906         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6907         l = lmod_bytes(po, po->operand[0].lmod) * 8;
6908         if (po->operand[1].type == OPT_CONST) {
6909           j = po->operand[1].val % l;
6910           if (j == 0)
6911             ferr(po, "zero rotate\n");
6912           fprintf(fout, "  tmp = (%s >> %d) & 1;\n",
6913             buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6914           if (po->op == OP_RCL) {
6915             fprintf(fout,
6916               "  %s = (%s << %d) | (cond_c << %d)",
6917               buf1, buf1, j, j - 1);
6918             if (j != 1)
6919               fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6920           }
6921           else {
6922             fprintf(fout,
6923               "  %s = (%s >> %d) | (cond_c << %d)",
6924               buf1, buf1, j, l - j);
6925             if (j != 1)
6926               fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6927           }
6928           fprintf(fout, ";\n");
6929           fprintf(fout, "  cond_c = tmp;");
6930         }
6931         else
6932           ferr(po, "TODO\n");
6933         strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6934         output_std_flags(fout, po, &pfomask, buf1);
6935         last_arith_dst = &po->operand[0];
6936         delayed_flag_op = NULL;
6937         break;
6938
6939       case OP_XOR:
6940         assert_operand_cnt(2);
6941         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6942         if (IS(opr_name(po, 0), opr_name(po, 1))) {
6943           // special case for XOR
6944           int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
6945           for (j = 0; j <= PFO_LE; j++) {
6946             if (pfomask & (1 << j)) {
6947               fprintf(fout, "  cond_%s = %d;\n",
6948                 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
6949               pfomask &= ~(1 << j);
6950             }
6951           }
6952           fprintf(fout, "  %s = 0;",
6953             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6954           last_arith_dst = &po->operand[0];
6955           delayed_flag_op = NULL;
6956           break;
6957         }
6958         goto dualop_arith;
6959
6960       case OP_ADD:
6961         assert_operand_cnt(2);
6962         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6963         if (pfomask & (1 << PFO_C)) {
6964           out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6965           out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6966           if (po->operand[0].lmod == OPLM_DWORD) {
6967             fprintf(fout, "  tmp64 = (u64)%s + %s;\n", buf1, buf2);
6968             fprintf(fout, "  cond_c = tmp64 >> 32;\n");
6969             fprintf(fout, "  %s = (u32)tmp64;",
6970               out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6971             strcat(g_comment, " add64");
6972           }
6973           else {
6974             fprintf(fout, "  cond_c = ((u32)%s + %s) >> %d;\n",
6975               buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6976             fprintf(fout, "  %s += %s;",
6977               out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6978               buf2);
6979           }
6980           pfomask &= ~(1 << PFO_C);
6981           output_std_flags(fout, po, &pfomask, buf1);
6982           last_arith_dst = &po->operand[0];
6983           delayed_flag_op = NULL;
6984           break;
6985         }
6986         if (pfomask & (1 << PFO_LE)) {
6987           out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
6988           fprintf(fout, "  cond_%s = %s;\n",
6989             parsed_flag_op_names[PFO_LE], buf1);
6990           pfomask &= ~(1 << PFO_LE);
6991         }
6992         goto dualop_arith;
6993
6994       case OP_SUB:
6995         assert_operand_cnt(2);
6996         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6997         if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6998           for (j = 0; j <= PFO_LE; j++) {
6999             if (!(pfomask & (1 << j)))
7000               continue;
7001             if (j == PFO_Z || j == PFO_S)
7002               continue;
7003
7004             out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7005             fprintf(fout, "  cond_%s = %s;\n",
7006               parsed_flag_op_names[j], buf1);
7007             pfomask &= ~(1 << j);
7008           }
7009         }
7010         goto dualop_arith;
7011
7012       case OP_ADC:
7013       case OP_SBB:
7014         assert_operand_cnt(2);
7015         propagate_lmod(po, &po->operand[0], &po->operand[1]);
7016         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7017         if (po->op == OP_SBB
7018           && IS(po->operand[0].name, po->operand[1].name))
7019         {
7020           // avoid use of unitialized var
7021           fprintf(fout, "  %s = -cond_c;", buf1);
7022           // carry remains what it was
7023           pfomask &= ~(1 << PFO_C);
7024         }
7025         else {
7026           fprintf(fout, "  %s %s= %s + cond_c;", buf1, op_to_c(po),
7027             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7028         }
7029         output_std_flags(fout, po, &pfomask, buf1);
7030         last_arith_dst = &po->operand[0];
7031         delayed_flag_op = NULL;
7032         break;
7033
7034       case OP_BSF:
7035       case OP_BSR:
7036         // on SKL, if src is 0, dst is left unchanged
7037         assert_operand_cnt(2);
7038         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7039         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7040         output_std_flag_z(fout, po, &pfomask, buf2);
7041         if (po->op == OP_BSF)
7042           snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
7043         else
7044           snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
7045         fprintf(fout, "  if (%s) %s = %s;", buf2, buf1, buf3);
7046         last_arith_dst = &po->operand[0];
7047         delayed_flag_op = NULL;
7048         strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
7049         break;
7050
7051       case OP_DEC:
7052         if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
7053           for (j = 0; j <= PFO_LE; j++) {
7054             if (!(pfomask & (1 << j)))
7055               continue;
7056             if (j == PFO_Z || j == PFO_S || j == PFO_C)
7057               continue;
7058
7059             out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7060             fprintf(fout, "  cond_%s = %s;\n",
7061               parsed_flag_op_names[j], buf1);
7062             pfomask &= ~(1 << j);
7063           }
7064         }
7065         // fallthrough
7066
7067       case OP_INC:
7068         if (pfomask & (1 << PFO_C))
7069           // carry is unaffected by inc/dec.. wtf?
7070           ferr(po, "carry propagation needed\n");
7071
7072         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7073         if (po->operand[0].type == OPT_REG) {
7074           strcpy(buf2, po->op == OP_INC ? "++" : "--");
7075           fprintf(fout, "  %s%s;", buf1, buf2);
7076         }
7077         else {
7078           strcpy(buf2, po->op == OP_INC ? "+" : "-");
7079           fprintf(fout, "  %s %s= 1;", buf1, buf2);
7080         }
7081         output_std_flags(fout, po, &pfomask, buf1);
7082         last_arith_dst = &po->operand[0];
7083         delayed_flag_op = NULL;
7084         break;
7085
7086       case OP_NEG:
7087         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7088         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
7089         fprintf(fout, "  %s = -%s%s;", buf1,
7090           lmod_cast_s(po, po->operand[0].lmod), buf2);
7091         last_arith_dst = &po->operand[0];
7092         delayed_flag_op = NULL;
7093         if (pfomask & PFOB_C) {
7094           fprintf(fout, "\n  cond_c = (%s != 0);", buf1);
7095           pfomask &= ~PFOB_C;
7096         }
7097         output_std_flags(fout, po, &pfomask, buf1);
7098         break;
7099
7100       case OP_IMUL:
7101         if (po->operand_cnt == 2) {
7102           propagate_lmod(po, &po->operand[0], &po->operand[1]);
7103           goto dualop_arith;
7104         }
7105         if (po->operand_cnt == 3)
7106           ferr(po, "TODO imul3\n");
7107         // fallthrough
7108       case OP_MUL:
7109         assert_operand_cnt(1);
7110         switch (po->operand[0].lmod) {
7111         case OPLM_DWORD:
7112           strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7113           fprintf(fout, "  tmp64 = %seax * %s%s;\n", buf1, buf1,
7114             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7115           fprintf(fout, "  edx = tmp64 >> 32;\n");
7116           fprintf(fout, "  eax = tmp64;");
7117           break;
7118         case OPLM_BYTE:
7119           strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7120           fprintf(fout, "  LOWORD(eax) = %seax * %s;", buf1,
7121             out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7122               buf1, 0));
7123           break;
7124         default:
7125           ferr(po, "TODO: unhandled mul type\n");
7126           break;
7127         }
7128         last_arith_dst = NULL;
7129         delayed_flag_op = NULL;
7130         break;
7131
7132       case OP_DIV:
7133       case OP_IDIV:
7134         assert_operand_cnt(1);
7135         out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7136         strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7137           po->op == OP_IDIV));
7138         switch (po->operand[0].lmod) {
7139         case OPLM_DWORD:
7140           if (po->flags & OPF_32BIT)
7141             snprintf(buf2, sizeof(buf2), "%seax", cast);
7142           else {
7143             fprintf(fout, "  tmp64 = ((u64)edx << 32) | eax;\n");
7144             snprintf(buf2, sizeof(buf2), "%stmp64",
7145               (po->op == OP_IDIV) ? "(s64)" : "");
7146           }
7147           if (po->operand[0].type == OPT_REG
7148             && po->operand[0].reg == xDX)
7149           {
7150             fprintf(fout, "  eax = %s / %s%s;\n", buf2, cast, buf1);
7151             fprintf(fout, "  edx = %s %% %s%s;", buf2, cast, buf1);
7152           }
7153           else {
7154             fprintf(fout, "  edx = %s %% %s%s;\n", buf2, cast, buf1);
7155             fprintf(fout, "  eax = %s / %s%s;", buf2, cast, buf1);
7156           }
7157           break;
7158         case OPLM_WORD:
7159           fprintf(fout, "  tmp = (edx << 16) | (eax & 0xffff);\n");
7160           snprintf(buf2, sizeof(buf2), "%stmp",
7161             (po->op == OP_IDIV) ? "(s32)" : "");
7162           if (po->operand[0].type == OPT_REG
7163             && po->operand[0].reg == xDX)
7164           {
7165             fprintf(fout, "  LOWORD(eax) = %s / %s%s;\n",
7166               buf2, cast, buf1);
7167             fprintf(fout, "  LOWORD(edx) = %s %% %s%s;",
7168               buf2, cast, buf1);
7169           }
7170           else {
7171             fprintf(fout, "  LOWORD(edx) = %s %% %s%s;\n",
7172               buf2, cast, buf1);
7173             fprintf(fout, "  LOWORD(eax) = %s / %s%s;",
7174               buf2, cast, buf1);
7175           }
7176           strcat(g_comment, " div16");
7177           break;
7178         default:
7179           ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7180         }
7181         last_arith_dst = NULL;
7182         delayed_flag_op = NULL;
7183         break;
7184
7185       case OP_TEST:
7186       case OP_CMP:
7187         propagate_lmod(po, &po->operand[0], &po->operand[1]);
7188         if (pfomask != 0) {
7189           for (j = 0; j < 8; j++) {
7190             if (pfomask & (1 << j)) {
7191               out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7192               fprintf(fout, "  cond_%s = %s;",
7193                 parsed_flag_op_names[j], buf1);
7194             }
7195           }
7196           pfomask = 0;
7197         }
7198         else
7199           no_output = 1;
7200         last_arith_dst = NULL;
7201         delayed_flag_op = po;
7202         break;
7203
7204       case OP_SCC:
7205         // SETcc - should already be handled
7206         break;
7207
7208       // note: we reuse OP_Jcc for SETcc, only flags differ
7209       case OP_JCC:
7210         fprintf(fout, "\n    goto %s;", po->operand[0].name);
7211         break;
7212
7213       case OP_JECXZ:
7214         fprintf(fout, "  if (ecx == 0)\n");
7215         fprintf(fout, "    goto %s;", po->operand[0].name);
7216         strcat(g_comment, " jecxz");
7217         break;
7218
7219       case OP_LOOP:
7220         fprintf(fout, "  if (--ecx != 0)\n");
7221         fprintf(fout, "    goto %s;", po->operand[0].name);
7222         strcat(g_comment, " loop");
7223         break;
7224
7225       case OP_JMP:
7226         assert_operand_cnt(1);
7227         last_arith_dst = NULL;
7228         delayed_flag_op = NULL;
7229
7230         if (po->operand[0].type == OPT_REGMEM) {
7231           ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7232                   buf1, buf2);
7233           if (ret != 2)
7234             ferr(po, "parse failure for jmp '%s'\n",
7235               po->operand[0].name);
7236           fprintf(fout, "  goto *jt_%s[%s];", buf1, buf2);
7237           break;
7238         }
7239         else if (po->operand[0].type != OPT_LABEL)
7240           ferr(po, "unhandled jmp type\n");
7241
7242         fprintf(fout, "  goto %s;", po->operand[0].name);
7243         break;
7244
7245       case OP_CALL:
7246         assert_operand_cnt(1);
7247         pp = po->pp;
7248         my_assert_not(pp, NULL);
7249
7250         strcpy(buf3, "  ");
7251         if (po->flags & OPF_CC) {
7252           // we treat conditional branch to another func
7253           // (yes such code exists..) as conditional tailcall
7254           strcat(buf3, "  ");
7255           fprintf(fout, " {\n");
7256         }
7257
7258         if (pp->is_fptr && !pp->is_arg) {
7259           fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7260             out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7261               "(void *)", 0));
7262           if (pp->is_unresolved || IS_START(pp->name, "i_guess"))
7263             fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7264               buf3, asmfn, po->asmln, pp->name);
7265         }
7266
7267         fprintf(fout, "%s", buf3);
7268         if (strstr(pp->ret_type.name, "int64")) {
7269           if (po->flags & OPF_TAIL)
7270             ferr(po, "int64 and tail?\n");
7271           fprintf(fout, "tmp64 = ");
7272         }
7273         else if (!IS(pp->ret_type.name, "void")) {
7274           if (po->flags & OPF_TAIL) {
7275             if (regmask_ret & mxAX) {
7276               fprintf(fout, "return ");
7277               if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7278                 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7279             }
7280             else if (regmask_ret & mxST0)
7281               ferr(po, "float tailcall\n");
7282           }
7283           else if (po->regmask_dst & mxAX) {
7284             fprintf(fout, "eax = ");
7285             if (pp->ret_type.is_ptr)
7286               fprintf(fout, "(u32)");
7287           }
7288           else if (po->regmask_dst & mxST0) {
7289             ferr_assert(po, po->flags & OPF_FPUSH);
7290             if (need_float_stack)
7291               fprintf(fout, "f_st[--f_stp & 7] = ");
7292             else
7293               fprintf(fout, "f_st0 = ");
7294           }
7295         }
7296
7297         if (pp->name[0] == 0)
7298           ferr(po, "missing pp->name\n");
7299         fprintf(fout, "%s%s(", pp->name,
7300           pp->has_structarg ? "_sa" : "");
7301
7302         if (po->flags & OPF_ATAIL) {
7303           int check_compat =
7304             g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7305           check_compat |= pp->argc_stack > 0;
7306           if (check_compat
7307            && (pp->argc_stack != g_func_pp->argc_stack
7308                || pp->is_stdcall != g_func_pp->is_stdcall))
7309             ferr(po, "incompatible arg-reuse tailcall\n");
7310           if (g_func_pp->has_retreg)
7311             ferr(po, "TODO: retreg+tailcall\n");
7312
7313           for (arg = j = 0; arg < pp->argc; arg++) {
7314             if (arg > 0)
7315               fprintf(fout, ", ");
7316
7317             cast[0] = 0;
7318             if (pp->arg[arg].type.is_ptr)
7319               snprintf(cast, sizeof(cast), "(%s)",
7320                 pp->arg[arg].type.name);
7321
7322             if (pp->arg[arg].reg != NULL) {
7323               fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7324               continue;
7325             }
7326             // stack arg
7327             for (; j < g_func_pp->argc; j++)
7328               if (g_func_pp->arg[j].reg == NULL)
7329                 break;
7330             fprintf(fout, "%sa%d", cast, j + 1);
7331             j++;
7332           }
7333         }
7334         else {
7335           for (arg = 0; arg < pp->argc; arg++) {
7336             if (arg > 0)
7337               fprintf(fout, ", ");
7338
7339             cast[0] = 0;
7340             if (pp->arg[arg].type.is_ptr)
7341               snprintf(cast, sizeof(cast), "(%s)",
7342                 pp->arg[arg].type.name);
7343
7344             if (pp->arg[arg].reg != NULL) {
7345               if (pp->arg[arg].type.is_retreg)
7346                 fprintf(fout, "&%s", pp->arg[arg].reg);
7347               else if (IS(pp->arg[arg].reg, "ebp")
7348                     && g_bp_frame && !(po->flags & OPF_EBP_S))
7349               {
7350                 // rare special case
7351                 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7352                 strcat(g_comment, " bp_ref");
7353               }
7354               else
7355                 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7356               continue;
7357             }
7358
7359             // stack arg
7360             tmp_op = pp->arg[arg].datap;
7361             if (tmp_op == NULL)
7362               ferr(po, "parsed_op missing for arg%d\n", arg);
7363
7364             if (tmp_op->flags & OPF_VAPUSH) {
7365               fprintf(fout, "ap");
7366             }
7367             else if (tmp_op->op == OP_FST) {
7368               fprintf(fout, "fs_%d", tmp_op->p_argnum);
7369               if (tmp_op->operand[0].lmod == OPLM_QWORD)
7370                 arg++;
7371             }
7372             else if (pp->arg[arg].type.is_64bit) {
7373               ferr_assert(po, tmp_op->p_argpass == 0);
7374               ferr_assert(po, !pp->arg[arg].is_saved);
7375               ferr_assert(po, !pp->arg[arg].type.is_float);
7376               ferr_assert(po, cast[0] == 0);
7377               out_src_opr(buf1, sizeof(buf1),
7378                 tmp_op, &tmp_op->operand[0], cast, 0);
7379               tmp_op = pp->arg[++arg].datap;
7380               ferr_assert(po, tmp_op != NULL);
7381               out_src_opr(buf2, sizeof(buf2),
7382                 tmp_op, &tmp_op->operand[0], cast, 0);
7383               fprintf(fout, "((u64)(%s) << 32) | (%s)",
7384                 buf2, buf1);
7385             }
7386             else if (tmp_op->p_argpass != 0) {
7387               ferr_assert(po, !pp->arg[arg].type.is_float);
7388               fprintf(fout, "a%d", tmp_op->p_argpass);
7389             }
7390             else if (pp->arg[arg].is_saved) {
7391               ferr_assert(po, tmp_op->p_argnum > 0);
7392               ferr_assert(po, !pp->arg[arg].type.is_float);
7393               fprintf(fout, "%s%s", cast,
7394                 saved_arg_name(buf1, sizeof(buf1),
7395                   tmp_op->p_arggrp, tmp_op->p_argnum));
7396             }
7397             else if (pp->arg[arg].type.is_float) {
7398               ferr_assert(po, !pp->arg[arg].type.is_64bit);
7399               fprintf(fout, "%s",
7400                 out_src_opr_float(buf1, sizeof(buf1),
7401                   tmp_op, &tmp_op->operand[0], need_float_stack));
7402             }
7403             else {
7404               fprintf(fout, "%s",
7405                 out_src_opr(buf1, sizeof(buf1),
7406                   tmp_op, &tmp_op->operand[0], cast, 0));
7407             }
7408           }
7409         }
7410         fprintf(fout, ");");
7411
7412         if (strstr(pp->ret_type.name, "int64")) {
7413           fprintf(fout, "\n");
7414           fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7415           fprintf(fout, "%seax = tmp64;", buf3);
7416         }
7417
7418         if (pp->is_unresolved) {
7419           snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7420             pp->argc_reg);
7421           strcat(g_comment, buf2);
7422         }
7423
7424         if (po->flags & OPF_TAIL) {
7425           ret = 0;
7426           if (i == opcnt - 1 || pp->is_noreturn)
7427             ret = 0;
7428           else if (IS(pp->ret_type.name, "void"))
7429             ret = 1;
7430           else if (!(regmask_ret & (1 << xAX)))
7431             ret = 1;
7432           // else already handled as 'return f()'
7433
7434           if (ret) {
7435             fprintf(fout, "\n%sreturn;", buf3);
7436             strcat(g_comment, " ^ tailcall");
7437           }
7438           else
7439             strcat(g_comment, " tailcall");
7440
7441           if ((regmask_ret & (1 << xAX))
7442             && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7443           {
7444             ferr(po, "int func -> void func tailcall?\n");
7445           }
7446         }
7447         if (pp->is_noreturn)
7448           strcat(g_comment, " noreturn");
7449         if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7450           strcat(g_comment, " argframe");
7451         if (po->flags & OPF_CC)
7452           strcat(g_comment, " cond");
7453
7454         if (po->flags & OPF_CC)
7455           fprintf(fout, "\n  }");
7456
7457         delayed_flag_op = NULL;
7458         last_arith_dst = NULL;
7459         break;
7460
7461       case OP_RET:
7462         if (g_func_pp->is_vararg)
7463           fprintf(fout, "  va_end(ap);\n");
7464         if (g_func_pp->has_retreg) {
7465           for (arg = 0; arg < g_func_pp->argc; arg++)
7466             if (g_func_pp->arg[arg].type.is_retreg)
7467               fprintf(fout, "  *r_%s = %s;\n",
7468                 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7469         }
7470  
7471         if (regmask_ret & mxST0) {
7472           fprintf(fout, "  return %s;", float_st0);
7473         }
7474         else if (!(regmask_ret & mxAX)) {
7475           if (i != opcnt - 1 || label_pending)
7476             fprintf(fout, "  return;");
7477         }
7478         else if (g_func_pp->ret_type.is_ptr) {
7479           fprintf(fout, "  return (%s)eax;",
7480             g_func_pp->ret_type.name);
7481         }
7482         else if (IS(g_func_pp->ret_type.name, "__int64"))
7483           fprintf(fout, "  return ((u64)edx << 32) | eax;");
7484         else
7485           fprintf(fout, "  return eax;");
7486
7487         last_arith_dst = NULL;
7488         delayed_flag_op = NULL;
7489         break;
7490
7491       case OP_PUSH:
7492         out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7493         if (po->p_argnum != 0) {
7494           // special case - saved func arg
7495           fprintf(fout, "  %s = %s;",
7496             saved_arg_name(buf2, sizeof(buf2),
7497               po->p_arggrp, po->p_argnum), buf1);
7498           break;
7499         }
7500         else if (po->flags & OPF_RSAVE) {
7501           fprintf(fout, "  s_%s = %s;", buf1, buf1);
7502           break;
7503         }
7504         else if (po->flags & OPF_PPUSH) {
7505           tmp_op = po->datap;
7506           ferr_assert(po, tmp_op != NULL);
7507           out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7508           fprintf(fout, "  pp_%s = %s;", buf2, buf1);
7509           break;
7510         }
7511         else if (g_func_pp->is_userstack) {
7512           fprintf(fout, "  *(--esp) = %s;", buf1);
7513           break;
7514         }
7515         if (!(g_ida_func_attr & IDAFA_NORETURN))
7516           ferr(po, "stray push encountered\n");
7517         no_output = 1;
7518         break;
7519
7520       case OP_POP:
7521         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7522         if (po->flags & OPF_RSAVE) {
7523           fprintf(fout, "  %s = s_%s;", buf1, buf1);
7524           break;
7525         }
7526         else if (po->flags & OPF_PPUSH) {
7527           // push/pop graph / non-const
7528           ferr_assert(po, po->datap == NULL);
7529           fprintf(fout, "  %s = pp_%s;", buf1, buf1);
7530           break;
7531         }
7532         else if (po->datap != NULL) {
7533           // push/pop pair
7534           tmp_op = po->datap;
7535           fprintf(fout, "  %s = %s;", buf1,
7536             out_src_opr(buf2, sizeof(buf2),
7537               tmp_op, &tmp_op->operand[0],
7538               default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7539           break;
7540         }
7541         else if (g_func_pp->is_userstack) {
7542           fprintf(fout, "  %s = *esp++;", buf1);
7543           break;
7544         }
7545         else
7546           ferr(po, "stray pop encountered\n");
7547         break;
7548
7549       case OP_NOP:
7550         no_output = 1;
7551         break;
7552
7553       // pseudo ops
7554       case OPP_ALLSHL:
7555       case OPP_ALLSHR:
7556         fprintf(fout, "  tmp64 = ((u64)edx << 32) | eax;\n");
7557         fprintf(fout, "  tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7558           po->op == OPP_ALLSHL ? "<<" : ">>");
7559         fprintf(fout, "  edx = tmp64 >> 32; eax = tmp64;");
7560         strcat(g_comment, po->op == OPP_ALLSHL
7561           ? " allshl" : " allshr");
7562         break;
7563
7564       // x87
7565       case OP_FLD:
7566         if (need_float_stack) {
7567           out_src_opr_float(buf1, sizeof(buf1),
7568             po, &po->operand[0], 1);
7569           if (po->regmask_src & mxSTa) {
7570             fprintf(fout, "  f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7571               buf1);
7572           }
7573           else
7574             fprintf(fout, "  f_st[--f_stp & 7] = %s;", buf1);
7575         }
7576         else {
7577           if (po->flags & OPF_FSHIFT)
7578             fprintf(fout, "  f_st1 = f_st0;");
7579           if (po->operand[0].type == OPT_REG
7580             && po->operand[0].reg == xST0)
7581           {
7582             strcat(g_comment, " fld st");
7583             break;
7584           }
7585           fprintf(fout, "  f_st0 = %s;",
7586             out_src_opr_float(buf1, sizeof(buf1),
7587               po, &po->operand[0], 0));
7588         }
7589         strcat(g_comment, " fld");
7590         break;
7591
7592       case OP_FILD:
7593         out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7594           lmod_cast(po, po->operand[0].lmod, 1), 0);
7595         snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7596         if (need_float_stack) {
7597           fprintf(fout, "  f_st[--f_stp & 7] = %s;", buf2);
7598         }
7599         else {
7600           if (po->flags & OPF_FSHIFT)
7601             fprintf(fout, "  f_st1 = f_st0;");
7602           fprintf(fout, "  f_st0 = %s;", buf2);
7603         }
7604         strcat(g_comment, " fild");
7605         break;
7606
7607       case OP_FLDc:
7608         if (need_float_stack)
7609           fprintf(fout, "  f_st[--f_stp & 7] = ");
7610         else {
7611           if (po->flags & OPF_FSHIFT)
7612             fprintf(fout, "  f_st1 = f_st0;");
7613           fprintf(fout, "  f_st0 = ");
7614         }
7615         switch (po->operand[0].val) {
7616         case X87_CONST_1:   fprintf(fout, "1.0;"); break;
7617         case X87_CONST_L2T: fprintf(fout, "3.321928094887362;"); break;
7618         case X87_CONST_L2E: fprintf(fout, "M_LOG2E;"); break;
7619         case X87_CONST_PI:  fprintf(fout, "M_PI;"); break;
7620         case X87_CONST_LG2: fprintf(fout, "0.301029995663981;"); break;
7621         case X87_CONST_LN2: fprintf(fout, "M_LN2;"); break;
7622         case X87_CONST_Z:   fprintf(fout, "0.0;"); break;
7623         default: ferr_assert(po, 0); break;
7624         }
7625         break;
7626
7627       case OP_FST:
7628         if (po->flags & OPF_FARG) {
7629           // store to stack as func arg
7630           snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7631           dead_dst = 0;
7632         }
7633         else {
7634           out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7635             need_float_stack);
7636           dead_dst = po->operand[0].type == OPT_REG
7637             && po->operand[0].reg == xST0;
7638         }
7639         if (!dead_dst)
7640           fprintf(fout, "  %s = %s;", buf1, float_st0);
7641         if (po->flags & OPF_FSHIFT) {
7642           if (need_float_stack)
7643             fprintf(fout, "  f_stp++;");
7644           else
7645             fprintf(fout, "  f_st0 = f_st1;");
7646         }
7647         if (dead_dst && !(po->flags & OPF_FSHIFT))
7648           no_output = 1;
7649         else
7650           strcat(g_comment, " fst");
7651         break;
7652
7653       case OP_FIST:
7654         fprintf(fout, "  %s = %s%s;",
7655           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7656             lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7657         if (po->flags & OPF_FSHIFT) {
7658           if (need_float_stack)
7659             fprintf(fout, "  f_stp++;");
7660           else
7661             fprintf(fout, "  f_st0 = f_st1;");
7662         }
7663         strcat(g_comment, " fist");
7664         break;
7665
7666       case OP_FADD:
7667       case OP_FDIV:
7668       case OP_FMUL:
7669       case OP_FSUB:
7670         out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7671           need_float_stack);
7672         out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7673           need_float_stack);
7674         dead_dst = (po->flags & OPF_FPOP)
7675           && po->operand[0].type == OPT_REG
7676           && po->operand[0].reg == xST0;
7677         switch (po->op) {
7678         case OP_FADD: j = '+'; break;
7679         case OP_FDIV: j = '/'; break;
7680         case OP_FMUL: j = '*'; break;
7681         case OP_FSUB: j = '-'; break;
7682         default: j = 'x'; break;
7683         }
7684         if (need_float_stack) {
7685           if (!dead_dst)
7686             fprintf(fout, "  %s %c= %s;", buf1, j, buf2);
7687           if (po->flags & OPF_FSHIFT)
7688             fprintf(fout, "  f_stp++;");
7689         }
7690         else {
7691           if (po->flags & OPF_FSHIFT) {
7692             // note: assumes only 2 regs handled
7693             if (!dead_dst)
7694               fprintf(fout, "  f_st0 = f_st1 %c f_st0;", j);
7695             else
7696               fprintf(fout, "  f_st0 = f_st1;");
7697           }
7698           else if (!dead_dst)
7699             fprintf(fout, "  %s %c= %s;", buf1, j, buf2);
7700         }
7701         no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7702         break;
7703
7704       case OP_FDIVR:
7705       case OP_FSUBR:
7706         out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7707           need_float_stack);
7708         out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7709           need_float_stack);
7710         out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7711           need_float_stack);
7712         dead_dst = (po->flags & OPF_FPOP)
7713           && po->operand[0].type == OPT_REG
7714           && po->operand[0].reg == xST0;
7715         j = po->op == OP_FDIVR ? '/' : '-';
7716         if (need_float_stack) {
7717           if (!dead_dst)
7718             fprintf(fout, "  %s = %s %c %s;", buf1, buf2, j, buf3);
7719           if (po->flags & OPF_FSHIFT)
7720             fprintf(fout, "  f_stp++;");
7721         }
7722         else {
7723           if (po->flags & OPF_FSHIFT) {
7724             if (!dead_dst)
7725               fprintf(fout, "  f_st0 = f_st0 %c f_st1;", j);
7726             else
7727               fprintf(fout, "  f_st0 = f_st1;");
7728           }
7729           else if (!dead_dst)
7730             fprintf(fout, "  %s = %s %c %s;", buf1, buf2, j, buf3);
7731         }
7732         no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7733         break;
7734
7735       case OP_FIADD:
7736       case OP_FIDIV:
7737       case OP_FIMUL:
7738       case OP_FISUB:
7739         switch (po->op) {
7740         case OP_FIADD: j = '+'; break;
7741         case OP_FIDIV: j = '/'; break;
7742         case OP_FIMUL: j = '*'; break;
7743         case OP_FISUB: j = '-'; break;
7744         default: j = 'x'; break;
7745         }
7746         fprintf(fout, "  %s %c= (%s)%s;", float_st0,
7747           j, float_type,
7748           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7749             lmod_cast(po, po->operand[0].lmod, 1), 0));
7750         break;
7751
7752       case OP_FIDIVR:
7753       case OP_FISUBR:
7754         fprintf(fout, "  %s = %s %c %s;", float_st0,
7755           out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7756             need_float_stack),
7757           po->op == OP_FIDIVR ? '/' : '-', float_st0);
7758         break;
7759
7760       case OP_FCOM: {
7761         int mask, z_check;
7762         ferr_assert(po, po->datap != NULL);
7763         mask = (long)po->datap & 0xffff;
7764         z_check = ((long)po->datap >> 16) & 1;
7765         out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7766           need_float_stack);
7767         if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
7768           fprintf(fout, "  f_sw = %s < %s ? 0x0100 : 0;",
7769             float_st0, buf1);
7770         }
7771         else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
7772           fprintf(fout, "  f_sw = %s == %s ? 0x4000 : 0;",
7773             float_st0, buf1);
7774         }
7775         else if (mask == 0x4100) { // C3, C0
7776           if (z_check) {
7777             fprintf(fout, "  f_sw = %s <= %s ? 0x4100 : 0;",
7778               float_st0, buf1);
7779             strcat(g_comment, " z_chk_det");
7780           }
7781           else {
7782             fprintf(fout, "  f_sw = %s == %s ? 0x4000 : "
7783                           "(%s < %s ? 0x0100 : 0);",
7784               float_st0, buf1, float_st0, buf1);
7785           }
7786         }
7787         else
7788           ferr(po, "unhandled sw mask: %x\n", mask);
7789         if (po->flags & OPF_FSHIFT) {
7790           if (need_float_stack) {
7791             if (po->flags & OPF_FPOPP)
7792               fprintf(fout, " f_stp += 2;");
7793             else
7794               fprintf(fout, " f_stp++;");
7795           }
7796           else {
7797             ferr_assert(po, !(po->flags & OPF_FPOPP));
7798             fprintf(fout, " f_st0 = f_st1;");
7799           }
7800         }
7801         break;
7802       }
7803
7804       case OP_FNSTSW:
7805         fprintf(fout, "  %s = f_sw;",
7806           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7807         break;
7808
7809       case OP_FCHS:
7810         fprintf(fout, "  %s = -%s;", float_st0, float_st0);
7811         break;
7812
7813       case OP_FCOS:
7814         fprintf(fout, "  %s = cos%s(%s);", float_st0,
7815           need_double ? "" : "f", float_st0);
7816         break;
7817
7818       case OP_FPATAN:
7819         if (need_float_stack) {
7820           fprintf(fout, "  %s = atan%s(%s / %s);", float_st1,
7821             need_double ? "" : "f", float_st1, float_st0);
7822           fprintf(fout, " f_stp++;");
7823         }
7824         else {
7825           fprintf(fout, "  f_st0 = atan%s(f_st1 / f_st0);",
7826             need_double ? "" : "f");
7827         }
7828         break;
7829
7830       case OP_FYL2X:
7831         if (need_float_stack) {
7832           fprintf(fout, "  %s = %s * log2%s(%s);", float_st1,
7833             float_st1, need_double ? "" : "f", float_st0);
7834           fprintf(fout, " f_stp++;");
7835         }
7836         else {
7837           fprintf(fout, "  f_st0 = f_st1 * log2%s(f_st0);",
7838             need_double ? "" : "f");
7839         }
7840         strcat(g_comment, " fyl2x");
7841         break;
7842
7843       case OP_FSIN:
7844         fprintf(fout, "  %s = sin%s(%s);", float_st0,
7845           need_double ? "" : "f", float_st0);
7846         break;
7847
7848       case OP_FSQRT:
7849         fprintf(fout, "  %s = sqrt%s(%s);", float_st0,
7850           need_double ? "" : "f", float_st0);
7851         break;
7852
7853       case OP_FXCH:
7854         dead_dst = po->operand[0].type == OPT_REG
7855           && po->operand[0].reg == xST0;
7856         if (!dead_dst) {
7857           out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7858             need_float_stack);
7859           fprintf(fout, "  { %s t = %s; %s = %s; %s = t; }", float_type,
7860             float_st0, float_st0, buf1, buf1);
7861           strcat(g_comment, " fxch");
7862         }
7863         else
7864           no_output = 1;
7865         break;
7866
7867       case OPP_FTOL:
7868         ferr_assert(po, po->flags & OPF_32BIT);
7869         fprintf(fout, "  eax = (s32)%s;", float_st0);
7870         if (po->flags & OPF_FSHIFT) {
7871           if (need_float_stack)
7872             fprintf(fout, " f_stp++;");
7873           else
7874             fprintf(fout, " f_st0 = f_st1;");
7875         }
7876         strcat(g_comment, " ftol");
7877         break;
7878
7879       case OPP_CIPOW:
7880         if (need_float_stack) {
7881           fprintf(fout, "  %s = pow%s(%s, %s);", float_st1,
7882             need_double ? "" : "f", float_st1, float_st0);
7883           fprintf(fout, " f_stp++;");
7884         }
7885         else {
7886           fprintf(fout, "  f_st0 = pow%s(f_st1, f_st0);",
7887             need_double ? "" : "f");
7888         }
7889         strcat(g_comment, " CIpow");
7890         break;
7891
7892       case OPP_ABORT:
7893         fprintf(fout, "  do_skip_code_abort();");
7894         break;
7895
7896       // mmx
7897       case OP_EMMS:
7898         fprintf(fout, "  do_emms();");
7899         break;
7900
7901       default:
7902         no_output = 1;
7903         ferr(po, "unhandled op type %d, flags %x\n",
7904           po->op, po->flags);
7905         break;
7906     }
7907
7908     if (g_comment[0] != 0) {
7909       char *p = g_comment;
7910       while (my_isblank(*p))
7911         p++;
7912       fprintf(fout, "  // %s", p);
7913       g_comment[0] = 0;
7914       no_output = 0;
7915     }
7916     if (!no_output)
7917       fprintf(fout, "\n");
7918
7919     // some sanity checking
7920     if (po->flags & OPF_REP) {
7921       if (po->op != OP_STOS && po->op != OP_MOVS
7922           && po->op != OP_CMPS && po->op != OP_SCAS)
7923         ferr(po, "unexpected rep\n");
7924       if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7925           && (po->op == OP_CMPS || po->op == OP_SCAS))
7926         ferr(po, "cmps/scas with plain rep\n");
7927     }
7928     if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7929         && po->op != OP_CMPS && po->op != OP_SCAS)
7930       ferr(po, "unexpected repz/repnz\n");
7931
7932     if (pfomask != 0)
7933       ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
7934
7935     // see is delayed flag stuff is still valid
7936     if (delayed_flag_op != NULL && delayed_flag_op != po) {
7937       if (is_any_opr_modified(delayed_flag_op, po, 0))
7938         delayed_flag_op = NULL;
7939     }
7940
7941     if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7942       if (is_opr_modified(last_arith_dst, po))
7943         last_arith_dst = NULL;
7944     }
7945
7946     if (!no_output)
7947       label_pending = 0;
7948   }
7949
7950   if (g_stack_fsz && !g_stack_frame_used)
7951     fprintf(fout, "  (void)sf;\n");
7952
7953   fprintf(fout, "}\n\n");
7954
7955   gen_x_cleanup(opcnt);
7956 }
7957
7958 static void gen_x_cleanup(int opcnt)
7959 {
7960   int i;
7961
7962   for (i = 0; i < opcnt; i++) {
7963     struct label_ref *lr, *lr_del;
7964
7965     lr = g_label_refs[i].next;
7966     while (lr != NULL) {
7967       lr_del = lr;
7968       lr = lr->next;
7969       free(lr_del);
7970     }
7971     g_label_refs[i].i = -1;
7972     g_label_refs[i].next = NULL;
7973
7974     if (ops[i].op == OP_CALL) {
7975       if (ops[i].pp)
7976         proto_release(ops[i].pp);
7977     }
7978   }
7979   g_func_pp = NULL;
7980 }
7981
7982 struct func_proto_dep;
7983
7984 struct func_prototype {
7985   char name[NAMELEN];
7986   int id;
7987   int argc_stack;
7988   int regmask_dep;
7989   int has_ret:3;                 // -1, 0, 1: unresolved, no, yes
7990   unsigned int dep_resolved:1;
7991   unsigned int is_stdcall:1;
7992   struct func_proto_dep *dep_func;
7993   int dep_func_cnt;
7994   const struct parsed_proto *pp; // seed pp, if any
7995 };
7996
7997 struct func_proto_dep {
7998   char *name;
7999   struct func_prototype *proto;
8000   int regmask_live;             // .. at the time of call
8001   unsigned int ret_dep:1;       // return from this is caller's return
8002 };
8003
8004 static struct func_prototype *hg_fp;
8005 static int hg_fp_cnt;
8006
8007 static struct scanned_var {
8008   char name[NAMELEN];
8009   enum opr_lenmod lmod;
8010   unsigned int is_seeded:1;
8011   unsigned int is_c_str:1;
8012   const struct parsed_proto *pp; // seed pp, if any
8013 } *hg_vars;
8014 static int hg_var_cnt;
8015
8016 static char **hg_refs;
8017 static int hg_ref_cnt;
8018
8019 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8020   int count);
8021
8022 static struct func_prototype *hg_fp_add(const char *funcn)
8023 {
8024   struct func_prototype *fp;
8025
8026   if ((hg_fp_cnt & 0xff) == 0) {
8027     hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
8028     my_assert_not(hg_fp, NULL);
8029     memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
8030   }
8031
8032   fp = &hg_fp[hg_fp_cnt];
8033   snprintf(fp->name, sizeof(fp->name), "%s", funcn);
8034   fp->id = hg_fp_cnt;
8035   fp->argc_stack = -1;
8036   hg_fp_cnt++;
8037
8038   return fp;
8039 }
8040
8041 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
8042   const char *name)
8043 {
8044   int i;
8045
8046   for (i = 0; i < fp->dep_func_cnt; i++)
8047     if (IS(fp->dep_func[i].name, name))
8048       return &fp->dep_func[i];
8049
8050   return NULL;
8051 }
8052
8053 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
8054 {
8055   // is it a dupe?
8056   if (hg_fp_find_dep(fp, name))
8057     return;
8058
8059   if ((fp->dep_func_cnt & 0xff) == 0) {
8060     fp->dep_func = realloc(fp->dep_func,
8061       sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
8062     my_assert_not(fp->dep_func, NULL);
8063     memset(&fp->dep_func[fp->dep_func_cnt], 0,
8064       sizeof(fp->dep_func[0]) * 0x100);
8065   }
8066   fp->dep_func[fp->dep_func_cnt].name = strdup(name);
8067   fp->dep_func_cnt++;
8068 }
8069
8070 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
8071 {
8072   const struct func_prototype *p1 = p1_, *p2 = p2_;
8073   return strcmp(p1->name, p2->name);
8074 }
8075
8076 #if 0
8077 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
8078 {
8079   const struct func_prototype *p1 = p1_, *p2 = p2_;
8080   return p1->id - p2->id;
8081 }
8082 #endif
8083
8084 static void hg_ref_add(const char *name)
8085 {
8086   if ((hg_ref_cnt & 0xff) == 0) {
8087     hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8088     my_assert_not(hg_refs, NULL);
8089     memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8090   }
8091
8092   hg_refs[hg_ref_cnt] = strdup(name);
8093   my_assert_not(hg_refs[hg_ref_cnt], NULL);
8094   hg_ref_cnt++;
8095 }
8096
8097 // recursive register dep pass
8098 // - track saved regs (part 2)
8099 // - try to figure out arg-regs
8100 // - calculate reg deps
8101 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8102   struct func_prototype *fp, int regmask_save, int regmask_dst,
8103   int *regmask_dep, int *has_ret)
8104 {
8105   struct func_proto_dep *dep;
8106   struct parsed_op *po;
8107   int from_caller = 0;
8108   int j, l;
8109   int reg;
8110   int ret;
8111
8112   for (; i < opcnt; i++)
8113   {
8114     if (cbits[i >> 3] & (1 << (i & 7)))
8115       return;
8116     cbits[i >> 3] |= (1 << (i & 7));
8117
8118     po = &ops[i];
8119
8120     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8121       if (po->flags & OPF_RMD)
8122         continue;
8123
8124       if (po->btj != NULL) {
8125         // jumptable
8126         for (j = 0; j < po->btj->count; j++) {
8127           check_i(po, po->btj->d[j].bt_i);
8128           gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8129             regmask_save, regmask_dst, regmask_dep, has_ret);
8130         }
8131         return;
8132       }
8133
8134       check_i(po, po->bt_i);
8135       if (po->flags & OPF_CJMP) {
8136         gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8137           regmask_save, regmask_dst, regmask_dep, has_ret);
8138       }
8139       else {
8140         i = po->bt_i - 1;
8141       }
8142       continue;
8143     }
8144
8145     if (po->flags & OPF_FARG)
8146       /* (just calculate register deps) */;
8147     else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8148     {
8149       reg = po->operand[0].reg;
8150       ferr_assert(po, reg >= 0);
8151
8152       if (po->flags & OPF_RSAVE) {
8153         regmask_save |= 1 << reg;
8154         continue;
8155       }
8156       if (po->flags & OPF_DONE)
8157         continue;
8158
8159       ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
8160       if (ret == 1) {
8161         regmask_save |= 1 << reg;
8162         po->flags |= OPF_RMD;
8163         scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
8164         continue;
8165       }
8166     }
8167     else if (po->flags & OPF_RMD)
8168       continue;
8169     else if (po->op == OP_CALL) {
8170       po->regmask_dst |= 1 << xAX;
8171
8172       dep = hg_fp_find_dep(fp, po->operand[0].name);
8173       if (dep != NULL) {
8174         dep->regmask_live = regmask_save | regmask_dst;
8175         if (g_bp_frame && !(po->flags & OPF_EBP_S))
8176           dep->regmask_live |= 1 << xBP;
8177       }
8178     }
8179     else if (po->op == OP_RET) {
8180       if (po->operand_cnt > 0) {
8181         fp->is_stdcall = 1;
8182         if (fp->argc_stack >= 0
8183             && fp->argc_stack != po->operand[0].val / 4)
8184           ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8185         fp->argc_stack = po->operand[0].val / 4;
8186       }
8187     }
8188
8189     // if has_ret is 0, there is uninitialized eax path,
8190     // which means it's most likely void func
8191     if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
8192       if (po->op == OP_CALL) {
8193         j = i;
8194         ret = 1;
8195       }
8196       else {
8197         struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
8198         j = -1;
8199         from_caller = 0;
8200         ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
8201       }
8202
8203       if (ret != 1 && from_caller) {
8204         // unresolved eax - probably void func
8205         *has_ret = 0;
8206       }
8207       else {
8208         if (j >= 0 && ops[j].op == OP_CALL) {
8209           dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8210           if (dep != NULL)
8211             dep->ret_dep = 1;
8212           else
8213             *has_ret = 1;
8214         }
8215         else
8216           *has_ret = 1;
8217       }
8218     }
8219
8220     l = regmask_save | regmask_dst;
8221     if (g_bp_frame && !(po->flags & OPF_EBP_S))
8222       l |= 1 << xBP;
8223
8224     l = po->regmask_src & ~l;
8225 #if 0
8226     if (l)
8227       fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8228         l, regmask_dst, regmask_save, po->flags);
8229 #endif
8230     *regmask_dep |= l;
8231     regmask_dst |= po->regmask_dst;
8232
8233     if (po->flags & OPF_TAIL)
8234       return;
8235   }
8236 }
8237
8238 static void gen_hdr(const char *funcn, int opcnt)
8239 {
8240   unsigned char cbits[MAX_OPS / 8];
8241   const struct parsed_proto *pp_c;
8242   struct parsed_proto *pp;
8243   struct func_prototype *fp;
8244   struct parsed_op *po;
8245   int regmask_dummy = 0;
8246   int regmask_dep;
8247   int max_bp_offset = 0;
8248   int has_ret;
8249   int i, j, l;
8250   int ret;
8251
8252   pp_c = proto_parse(g_fhdr, funcn, 1);
8253   if (pp_c != NULL)
8254     // already in seed, will add to hg_fp later
8255     return;
8256
8257   fp = hg_fp_add(funcn);
8258
8259   g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8260   g_stack_frame_used = 0;
8261   g_seh_size = 0;
8262
8263   // pass1:
8264   // - resolve all branches
8265   // - parse calls with labels
8266   resolve_branches_parse_calls(opcnt);
8267
8268   // pass2:
8269   // - handle ebp/esp frame, remove ops related to it
8270   scan_prologue_epilogue(opcnt, NULL);
8271
8272   // pass3:
8273   // - remove dead labels
8274   // - collect calls
8275   for (i = 0; i < opcnt; i++)
8276   {
8277     if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8278       free(g_labels[i]);
8279       g_labels[i] = NULL;
8280     }
8281
8282     po = &ops[i];
8283     if (po->flags & (OPF_RMD|OPF_DONE))
8284       continue;
8285
8286     if (po->op == OP_CALL) {
8287       if (po->operand[0].type == OPT_LABEL)
8288         hg_fp_add_dep(fp, opr_name(po, 0));
8289       else if (po->pp != NULL)
8290         hg_fp_add_dep(fp, po->pp->name);
8291     }
8292   }
8293
8294   // pass4:
8295   // - remove dead labels
8296   // - handle push <const>/pop pairs
8297   for (i = 0; i < opcnt; i++)
8298   {
8299     if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8300       free(g_labels[i]);
8301       g_labels[i] = NULL;
8302     }
8303
8304     po = &ops[i];
8305     if (po->flags & (OPF_RMD|OPF_DONE))
8306       continue;
8307
8308     if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8309       scan_for_pop_const(i, opcnt, i + opcnt * 13);
8310   }
8311
8312   // pass5:
8313   // - process trivial calls
8314   for (i = 0; i < opcnt; i++)
8315   {
8316     po = &ops[i];
8317     if (po->flags & (OPF_RMD|OPF_DONE))
8318       continue;
8319
8320     if (po->op == OP_CALL)
8321     {
8322       pp = process_call_early(i, opcnt, &j);
8323       if (pp != NULL) {
8324         if (!(po->flags & OPF_ATAIL))
8325           // since we know the args, try to collect them
8326           if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8327             pp = NULL;
8328       }
8329
8330       if (pp != NULL) {
8331         if (j >= 0) {
8332           // commit esp adjust
8333           if (ops[j].op != OP_POP)
8334             patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8335           else {
8336             for (l = 0; l < pp->argc_stack; l++)
8337               ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8338           }
8339         }
8340
8341         po->flags |= OPF_DONE;
8342       }
8343     }
8344   }
8345
8346   // pass6:
8347   // - track saved regs (simple)
8348   // - process calls
8349   for (i = 0; i < opcnt; i++)
8350   {
8351     po = &ops[i];
8352     if (po->flags & (OPF_RMD|OPF_DONE))
8353       continue;
8354
8355     if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8356       && po->operand[0].reg != xCX)
8357     {
8358       ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8359       if (ret == 1) {
8360         // regmask_save |= 1 << po->operand[0].reg; // do it later
8361         po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8362         scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8363       }
8364     }
8365     else if (po->op == OP_CALL)
8366     {
8367       pp = process_call(i, opcnt);
8368
8369       if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8370         // since we know the args, collect them
8371         ret = collect_call_args(po, i, pp, &regmask_dummy,
8372                 i + opcnt * 1);
8373       }
8374     }
8375   }
8376
8377   // pass7
8378   memset(cbits, 0, sizeof(cbits));
8379   regmask_dep = 0;
8380   has_ret = -1;
8381
8382   gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, &regmask_dep, &has_ret);
8383
8384   // find unreachable code - must be fixed in IDA
8385   for (i = 0; i < opcnt; i++)
8386   {
8387     if (cbits[i >> 3] & (1 << (i & 7)))
8388       continue;
8389
8390     if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8391       && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8392     {
8393       // the compiler sometimes still generates code after
8394       // noreturn OS functions
8395       break;
8396     }
8397     if (ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8398       ferr(&ops[i], "unreachable code\n");
8399   }
8400
8401   for (i = 0; i < g_eqcnt; i++) {
8402     if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8403       max_bp_offset = g_eqs[i].offset;
8404   }
8405
8406   if (fp->argc_stack < 0) {
8407     max_bp_offset = (max_bp_offset + 3) & ~3;
8408     fp->argc_stack = max_bp_offset / 4;
8409     if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8410       fp->argc_stack--;
8411   }
8412
8413   fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8414   fp->has_ret = has_ret;
8415 #if 0
8416   printf("// has_ret %d, regmask_dep %x\n",
8417     fp->has_ret, fp->regmask_dep);
8418   output_hdr_fp(stdout, fp, 1);
8419   if (IS(funcn, "sub_10007F72")) exit(1);
8420 #endif
8421
8422   gen_x_cleanup(opcnt);
8423 }
8424
8425 static void hg_fp_resolve_deps(struct func_prototype *fp)
8426 {
8427   struct func_prototype fp_s;
8428   int dep;
8429   int i;
8430
8431   // this thing is recursive, so mark first..
8432   fp->dep_resolved = 1;
8433
8434   for (i = 0; i < fp->dep_func_cnt; i++) {
8435     strcpy(fp_s.name, fp->dep_func[i].name);
8436     fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8437       sizeof(hg_fp[0]), hg_fp_cmp_name);
8438     if (fp->dep_func[i].proto != NULL) {
8439       if (!fp->dep_func[i].proto->dep_resolved)
8440         hg_fp_resolve_deps(fp->dep_func[i].proto);
8441
8442       dep = ~fp->dep_func[i].regmask_live
8443            & fp->dep_func[i].proto->regmask_dep;
8444       fp->regmask_dep |= dep;
8445       // printf("dep %s %s |= %x\n", fp->name,
8446       //   fp->dep_func[i].name, dep);
8447
8448       if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8449         fp->has_ret = fp->dep_func[i].proto->has_ret;
8450     }
8451   }
8452 }
8453
8454 // make all thiscall/edx arg functions referenced from .data fastcall
8455 static void do_func_refs_from_data(void)
8456 {
8457   struct func_prototype *fp, fp_s;
8458   int i;
8459
8460   for (i = 0; i < hg_ref_cnt; i++) {
8461     strcpy(fp_s.name, hg_refs[i]);
8462     fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8463       sizeof(hg_fp[0]), hg_fp_cmp_name);
8464     if (fp == NULL)
8465       continue;
8466
8467     if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8468       fp->regmask_dep |= mxCX | mxDX;
8469   }
8470 }
8471
8472 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8473   int count)
8474 {
8475   const struct parsed_proto *pp;
8476   char *p, namebuf[NAMELEN];
8477   const char *name;
8478   int regmask_dep;
8479   int argc_normal;
8480   int j, arg;
8481
8482   for (; count > 0; count--, fp++) {
8483     if (fp->has_ret == -1)
8484       fprintf(fout, "// ret unresolved\n");
8485 #if 0
8486     fprintf(fout, "// dep:");
8487     for (j = 0; j < fp->dep_func_cnt; j++) {
8488       fprintf(fout, " %s/", fp->dep_func[j].name);
8489       if (fp->dep_func[j].proto != NULL)
8490         fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8491           fp->dep_func[j].proto->has_ret);
8492     }
8493     fprintf(fout, "\n");
8494 #endif
8495
8496     p = strchr(fp->name, '@');
8497     if (p != NULL) {
8498       memcpy(namebuf, fp->name, p - fp->name);
8499       namebuf[p - fp->name] = 0;
8500       name = namebuf;
8501     }
8502     else
8503       name = fp->name;
8504     if (name[0] == '_')
8505       name++;
8506
8507     pp = proto_parse(g_fhdr, name, 1);
8508     if (pp != NULL && pp->is_include)
8509       continue;
8510
8511     if (fp->pp != NULL) {
8512       // part of seed, output later
8513       continue;
8514     }
8515
8516     regmask_dep = fp->regmask_dep;
8517     argc_normal = fp->argc_stack;
8518
8519     fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8520       (fp->has_ret ? "int" : "void"));
8521     if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8522       && (regmask_dep & ~mxCX) == 0)
8523     {
8524       fprintf(fout, "/*__thiscall*/  ");
8525       argc_normal++;
8526       regmask_dep = 0;
8527     }
8528     else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8529       && (regmask_dep & ~(mxCX | mxDX)) == 0)
8530     {
8531       fprintf(fout, "  __fastcall    ");
8532       if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8533         argc_normal = 1;
8534       else
8535         argc_normal += 2;
8536       regmask_dep = 0;
8537     }
8538     else if (regmask_dep && !fp->is_stdcall) {
8539       fprintf(fout, "/*__usercall*/  ");
8540     }
8541     else if (regmask_dep) {
8542       fprintf(fout, "/*__userpurge*/ ");
8543     }
8544     else if (fp->is_stdcall)
8545       fprintf(fout, "  __stdcall     ");
8546     else
8547       fprintf(fout, "  __cdecl       ");
8548
8549     fprintf(fout, "%s(", name);
8550
8551     arg = 0;
8552     for (j = 0; j < xSP; j++) {
8553       if (regmask_dep & (1 << j)) {
8554         arg++;
8555         if (arg != 1)
8556           fprintf(fout, ", ");
8557         if (fp->pp != NULL)
8558           fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8559         else
8560           fprintf(fout, "int");
8561         fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8562       }
8563     }
8564
8565     for (j = 0; j < argc_normal; j++) {
8566       arg++;
8567       if (arg != 1)
8568         fprintf(fout, ", ");
8569       if (fp->pp != NULL) {
8570         fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8571         if (!fp->pp->arg[arg - 1].type.is_ptr)
8572           fprintf(fout, " ");
8573       }
8574       else
8575         fprintf(fout, "int ");
8576       fprintf(fout, "a%d", arg);
8577     }
8578
8579     fprintf(fout, ");\n");
8580   }
8581 }
8582
8583 static void output_hdr(FILE *fout)
8584 {
8585   static const char *lmod_c_names[] = {
8586     [OPLM_UNSPEC] = "???",
8587     [OPLM_BYTE]  = "uint8_t",
8588     [OPLM_WORD]  = "uint16_t",
8589     [OPLM_DWORD] = "uint32_t",
8590     [OPLM_QWORD] = "uint64_t",
8591   };
8592   const struct scanned_var *var;
8593   struct func_prototype *fp;
8594   char line[256] = { 0, };
8595   char name[256];
8596   int i;
8597
8598   // add stuff from headers
8599   for (i = 0; i < pp_cache_size; i++) {
8600     if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8601       snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8602     else
8603       snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8604     fp = hg_fp_add(name);
8605     fp->pp = &pp_cache[i];
8606     fp->argc_stack = fp->pp->argc_stack;
8607     fp->is_stdcall = fp->pp->is_stdcall;
8608     fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8609     fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8610   }
8611
8612   // resolve deps
8613   qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8614   for (i = 0; i < hg_fp_cnt; i++)
8615     hg_fp_resolve_deps(&hg_fp[i]);
8616
8617   // adjust functions referenced from data segment
8618   do_func_refs_from_data();
8619
8620   // note: messes up .proto ptr, don't use
8621   //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8622
8623   // output variables
8624   for (i = 0; i < hg_var_cnt; i++) {
8625     var = &hg_vars[i];
8626
8627     if (var->pp != NULL)
8628       // part of seed
8629       continue;
8630     else if (var->is_c_str)
8631       fprintf(fout, "extern %-8s %s[];", "char", var->name);
8632     else
8633       fprintf(fout, "extern %-8s %s;",
8634         lmod_c_names[var->lmod], var->name);
8635
8636     if (var->is_seeded)
8637       fprintf(fout, " // seeded");
8638     fprintf(fout, "\n");
8639   }
8640
8641   fprintf(fout, "\n");
8642
8643   // output function prototypes
8644   output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8645
8646   // seed passthrough
8647   fprintf(fout, "\n// - seed -\n");
8648
8649   rewind(g_fhdr);
8650   while (fgets(line, sizeof(line), g_fhdr))
8651     fwrite(line, 1, strlen(line), fout);
8652 }
8653
8654 // '=' needs special treatment
8655 // also ' quote
8656 static char *next_word_s(char *w, size_t wsize, char *s)
8657 {
8658   size_t i;
8659
8660   s = sskip(s);
8661
8662   i = 0;
8663   if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8664     w[0] = s[0];
8665     for (i = 1; i < wsize - 1; i++) {
8666       if (s[i] == 0) {
8667         printf("warning: missing closing quote: \"%s\"\n", s);
8668         break;
8669       }
8670       if (s[i] == '\'')
8671         break;
8672       w[i] = s[i];
8673     }
8674   }
8675
8676   for (; i < wsize - 1; i++) {
8677     if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8678       break;
8679     w[i] = s[i];
8680   }
8681   w[i] = 0;
8682
8683   if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8684     printf("warning: '%s' truncated\n", w);
8685
8686   return s + i;
8687 }
8688
8689 static int cmpstringp(const void *p1, const void *p2)
8690 {
8691   return strcmp(*(char * const *)p1, *(char * const *)p2);
8692 }
8693
8694 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8695 {
8696   char *p2;
8697
8698   p = sskip(p);
8699   if (strstr(p, "..."))
8700     // unable to determine, assume needed
8701     return 1;
8702
8703   if (*p == '.') // .text, .data, ...
8704     // ref from other data or non-function -> no
8705     return 0;
8706
8707   p2 = strpbrk(p, "+:\r\n\x18");
8708   if (p2 != NULL)
8709     *p2 = 0;
8710   if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8711     // referenced from removed code
8712     return 0;
8713
8714   return 1;
8715 }
8716
8717 static int ida_xrefs_show_need(FILE *fasm, char *p,
8718   char **rlist, int rlist_len)
8719 {
8720   int found_need = 0;
8721   char line[256];
8722   long pos;
8723
8724   p = strrchr(p, ';');
8725   if (p != NULL && *p == ';') {
8726     if (IS_START(p + 2, "sctref"))
8727       return 1;
8728     if (IS_START(p + 2, "DATA XREF: ")) {
8729       p += 13;
8730       if (is_xref_needed(p, rlist, rlist_len))
8731         return 1;
8732     }
8733   }
8734
8735   pos = ftell(fasm);
8736   while (1)
8737   {
8738     if (!my_fgets(line, sizeof(line), fasm))
8739       break;
8740     // non-first line is always indented
8741     if (!my_isblank(line[0]))
8742       break;
8743
8744     // should be no content, just comment
8745     p = sskip(line);
8746     if (*p != ';')
8747       break;
8748
8749     p = strrchr(p, ';');
8750     p += 2;
8751
8752     if (IS_START(p, "sctref")) {
8753       found_need = 1;
8754       break;
8755     }
8756
8757     // it's printed once, but no harm to check again
8758     if (IS_START(p, "DATA XREF: "))
8759       p += 11;
8760
8761     if (is_xref_needed(p, rlist, rlist_len)) {
8762       found_need = 1;
8763       break;
8764     }
8765   }
8766   fseek(fasm, pos, SEEK_SET);
8767   return found_need;
8768 }
8769
8770 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8771 {
8772   struct scanned_var *var;
8773   char line[256] = { 0, };
8774   char words[4][256];
8775   int no_identifier;
8776   char *p = NULL;
8777   int wordc;
8778   int l;
8779
8780   while (!feof(fasm))
8781   {
8782     // skip to next data section
8783     while (my_fgets(line, sizeof(line), fasm))
8784     {
8785       asmln++;
8786
8787       p = sskip(line);
8788       if (*p == 0 || *p == ';')
8789         continue;
8790
8791       p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8792       if (*p == 0 || *p == ';')
8793         continue;
8794
8795       if (*p != 's' || !IS_START(p, "segment para public"))
8796         continue;
8797
8798       break;
8799     }
8800
8801     if (p == NULL || !IS_START(p, "segment para public"))
8802       break;
8803     p = sskip(p + 19);
8804
8805     if (!IS_START(p, "'DATA'"))
8806       continue;
8807
8808     // now process it
8809     while (my_fgets(line, sizeof(line), fasm))
8810     {
8811       asmln++;
8812
8813       p = line;
8814       no_identifier = my_isblank(*p);
8815
8816       p = sskip(p);
8817       if (*p == 0 || *p == ';')
8818         continue;
8819
8820       for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8821         words[wordc][0] = 0;
8822         p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8823         if (*p == 0 || *p == ';') {
8824           wordc++;
8825           break;
8826         }
8827       }
8828
8829       if (wordc == 2 && IS(words[1], "ends"))
8830         break;
8831       if (wordc < 2)
8832         continue;
8833
8834       if (no_identifier) {
8835         if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8836           hg_ref_add(words[2]);
8837         continue;
8838       }
8839
8840       if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8841         // when this starts, we don't need anything from this section
8842         break;
8843       }
8844
8845       // check refs comment(s)
8846       if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8847         continue;
8848
8849       if ((hg_var_cnt & 0xff) == 0) {
8850         hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8851                    * (hg_var_cnt + 0x100));
8852         my_assert_not(hg_vars, NULL);
8853         memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8854       }
8855
8856       var = &hg_vars[hg_var_cnt++];
8857       snprintf(var->name, sizeof(var->name), "%s", words[0]);
8858
8859       // maybe already in seed header?
8860       var->pp = proto_parse(g_fhdr, var->name, 1);
8861       if (var->pp != NULL) {
8862         if (var->pp->is_fptr) {
8863           var->lmod = OPLM_DWORD;
8864           //var->is_ptr = 1;
8865         }
8866         else if (var->pp->is_func)
8867           aerr("func?\n");
8868         else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8869           aerr("unhandled C type '%s' for '%s'\n",
8870             var->pp->type.name, var->name);
8871
8872         var->is_seeded = 1;
8873         continue;
8874       }
8875
8876       if      (IS(words[1], "dd")) {
8877         var->lmod = OPLM_DWORD;
8878         if (wordc >= 4 && IS(words[2], "offset"))
8879           hg_ref_add(words[3]);
8880       }
8881       else if (IS(words[1], "dw"))
8882         var->lmod = OPLM_WORD;
8883       else if (IS(words[1], "db")) {
8884         var->lmod = OPLM_BYTE;
8885         if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8886           if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8887             var->is_c_str = 1;
8888         }
8889       }
8890       else if (IS(words[1], "dq"))
8891         var->lmod = OPLM_QWORD;
8892       //else if (IS(words[1], "dt"))
8893       else
8894         aerr("type '%s' not known\n", words[1]);
8895     }
8896   }
8897
8898   rewind(fasm);
8899   asmln = 0;
8900 }
8901
8902 static void set_label(int i, const char *name)
8903 {
8904   const char *p;
8905   int len;
8906
8907   len = strlen(name);
8908   p = strchr(name, ':');
8909   if (p != NULL)
8910     len = p - name;
8911
8912   if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8913     aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8914   g_labels[i] = realloc(g_labels[i], len + 1);
8915   my_assert_not(g_labels[i], NULL);
8916   memcpy(g_labels[i], name, len);
8917   g_labels[i][len] = 0;
8918 }
8919
8920 struct chunk_item {
8921   char *name;
8922   long fptr;
8923   int asmln;
8924 };
8925
8926 static struct chunk_item *func_chunks;
8927 static int func_chunk_cnt;
8928 static int func_chunk_alloc;
8929
8930 static void add_func_chunk(FILE *fasm, const char *name, int line)
8931 {
8932   if (func_chunk_cnt >= func_chunk_alloc) {
8933     func_chunk_alloc *= 2;
8934     func_chunks = realloc(func_chunks,
8935       func_chunk_alloc * sizeof(func_chunks[0]));
8936     my_assert_not(func_chunks, NULL);
8937   }
8938   func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8939   func_chunks[func_chunk_cnt].name = strdup(name);
8940   func_chunks[func_chunk_cnt].asmln = line;
8941   func_chunk_cnt++;
8942 }
8943
8944 static int cmp_chunks(const void *p1, const void *p2)
8945 {
8946   const struct chunk_item *c1 = p1, *c2 = p2;
8947   return strcmp(c1->name, c2->name);
8948 }
8949
8950 static void scan_ahead_for_chunks(FILE *fasm)
8951 {
8952   char words[2][256];
8953   char line[256];
8954   long oldpos;
8955   int oldasmln;
8956   int wordc;
8957   char *p;
8958   int i;
8959
8960   oldpos = ftell(fasm);
8961   oldasmln = asmln;
8962
8963   while (my_fgets(line, sizeof(line), fasm))
8964   {
8965     wordc = 0;
8966     asmln++;
8967
8968     p = sskip(line);
8969     if (*p == 0)
8970       continue;
8971
8972     if (*p == ';')
8973     {
8974       // get rid of random tabs
8975       for (i = 0; line[i] != 0; i++)
8976         if (line[i] == '\t')
8977           line[i] = ' ';
8978
8979       if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8980       {
8981         p += 30;
8982         next_word(words[0], sizeof(words[0]), p);
8983         if (words[0][0] == 0)
8984           aerr("missing name for func chunk?\n");
8985
8986         add_func_chunk(fasm, words[0], asmln);
8987       }
8988       else if (IS_START(p, "; sctend"))
8989         break;
8990
8991       continue;
8992     } // *p == ';'
8993
8994     for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8995       words[wordc][0] = 0;
8996       p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8997       if (*p == 0 || *p == ';') {
8998         wordc++;
8999         break;
9000       }
9001     }
9002
9003     if (wordc == 2 && IS(words[1], "ends"))
9004       break;
9005   }
9006
9007   fseek(fasm, oldpos, SEEK_SET);
9008   asmln = oldasmln;
9009 }
9010
9011 int main(int argc, char *argv[])
9012 {
9013   FILE *fout, *fasm, *frlist;
9014   struct parsed_data *pd = NULL;
9015   int pd_alloc = 0;
9016   char **rlist = NULL;
9017   int rlist_len = 0;
9018   int rlist_alloc = 0;
9019   int func_chunks_used = 0;
9020   int func_chunks_sorted = 0;
9021   int func_chunk_i = -1;
9022   long func_chunk_ret = 0;
9023   int func_chunk_ret_ln = 0;
9024   int scanned_ahead = 0;
9025   char line[256];
9026   char words[20][256];
9027   enum opr_lenmod lmod;
9028   char *sctproto = NULL;
9029   int in_func = 0;
9030   int pending_endp = 0;
9031   int skip_code = 0;
9032   int skip_code_end = 0;
9033   int skip_warned = 0;
9034   int eq_alloc;
9035   int verbose = 0;
9036   int multi_seg = 0;
9037   int end = 0;
9038   int arg_out;
9039   int arg;
9040   int pi = 0;
9041   int i, j;
9042   int ret, len;
9043   char *p;
9044   int wordc;
9045
9046   for (arg = 1; arg < argc; arg++) {
9047     if (IS(argv[arg], "-v"))
9048       verbose = 1;
9049     else if (IS(argv[arg], "-rf"))
9050       g_allow_regfunc = 1;
9051     else if (IS(argv[arg], "-uc"))
9052       g_allow_user_icall = 1;
9053     else if (IS(argv[arg], "-m"))
9054       multi_seg = 1;
9055     else if (IS(argv[arg], "-hdr"))
9056       g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
9057     else
9058       break;
9059   }
9060
9061   if (argc < arg + 3) {
9062     printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
9063            "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
9064            "options:\n"
9065            "  -hdr - header generation mode\n"
9066            "  -rf  - allow unannotated indirect calls\n"
9067            "  -uc  - allow ind. calls/refs to __usercall\n"
9068            "  -m   - allow multiple .text sections\n"
9069            "[rlist] is a file with function names to skip,"
9070            " one per line\n",
9071       argv[0], argv[0]);
9072     return 1;
9073   }
9074
9075   arg_out = arg++;
9076
9077   asmfn = argv[arg++];
9078   fasm = fopen(asmfn, "r");
9079   my_assert_not(fasm, NULL);
9080
9081   hdrfn = argv[arg++];
9082   g_fhdr = fopen(hdrfn, "r");
9083   my_assert_not(g_fhdr, NULL);
9084
9085   rlist_alloc = 64;
9086   rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9087   my_assert_not(rlist, NULL);
9088   // needs special handling..
9089   rlist[rlist_len++] = "__alloca_probe";
9090
9091   func_chunk_alloc = 32;
9092   func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9093   my_assert_not(func_chunks, NULL);
9094
9095   memset(words, 0, sizeof(words));
9096
9097   for (; arg < argc; arg++) {
9098     int skip_func = 0;
9099
9100     frlist = fopen(argv[arg], "r");
9101     my_assert_not(frlist, NULL);
9102
9103     while (my_fgets(line, sizeof(line), frlist)) {
9104       p = sskip(line);
9105       if (*p == 0 || *p == ';')
9106         continue;
9107       if (*p == '#') {
9108         if (IS_START(p, "#if 0")
9109          || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9110         {
9111           skip_func = 1;
9112         }
9113         else if (IS_START(p, "#endif"))
9114           skip_func = 0;
9115         continue;
9116       }
9117       if (skip_func)
9118         continue;
9119
9120       p = next_word(words[0], sizeof(words[0]), p);
9121       if (words[0][0] == 0)
9122         continue;
9123
9124       if (rlist_len >= rlist_alloc) {
9125         rlist_alloc = rlist_alloc * 2 + 64;
9126         rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9127         my_assert_not(rlist, NULL);
9128       }
9129       rlist[rlist_len++] = strdup(words[0]);
9130     }
9131
9132     fclose(frlist);
9133     frlist = NULL;
9134   }
9135
9136   if (rlist_len > 0)
9137     qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9138
9139   fout = fopen(argv[arg_out], "w");
9140   my_assert_not(fout, NULL);
9141
9142   eq_alloc = 128;
9143   g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9144   my_assert_not(g_eqs, NULL);
9145
9146   for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9147     g_label_refs[i].i = -1;
9148     g_label_refs[i].next = NULL;
9149   }
9150
9151   if (g_header_mode)
9152     scan_variables(fasm, rlist, rlist_len);
9153
9154   while (my_fgets(line, sizeof(line), fasm))
9155   {
9156     wordc = 0;
9157     asmln++;
9158
9159     p = sskip(line);
9160     if (*p == 0)
9161       continue;
9162
9163     // get rid of random tabs
9164     for (i = 0; line[i] != 0; i++)
9165       if (line[i] == '\t')
9166         line[i] = ' ';
9167
9168     if (*p == ';')
9169     {
9170       if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9171         goto do_pending_endp; // eww..
9172
9173       if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9174       {
9175         static const char *attrs[] = {
9176           "bp-based frame",
9177           "library function",
9178           "static",
9179           "noreturn",
9180           "thunk",
9181           "fpd=",
9182         };
9183
9184         // parse IDA's attribute-list comment
9185         g_ida_func_attr = 0;
9186         p = sskip(p + 13);
9187
9188         for (; *p != 0; p = sskip(p)) {
9189           for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9190             if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9191               g_ida_func_attr |= 1 << i;
9192               p += strlen(attrs[i]);
9193               break;
9194             }
9195           }
9196           if (i == ARRAY_SIZE(attrs)) {
9197             anote("unparsed IDA attr: %s\n", p);
9198             break;
9199           }
9200           if (IS(attrs[i], "fpd=")) {
9201             p = next_word(words[0], sizeof(words[0]), p);
9202             // ignore for now..
9203           }
9204         }
9205       }
9206       else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9207       {
9208         static const char *attrs[] = {
9209           "clear_sf",
9210           "clear_regmask",
9211         };
9212
9213         // parse manual attribute-list comment
9214         g_sct_func_attr = 0;
9215         p = sskip(p + 10);
9216
9217         for (; *p != 0; p = sskip(p)) {
9218           for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9219             if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9220               g_sct_func_attr |= 1 << i;
9221               p += strlen(attrs[i]);
9222               break;
9223             }
9224           }
9225           if (*p == '=') {
9226             j = ret = 0;
9227             if (i == 0)
9228               // clear_sf=start,len (in dwords)
9229               ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9230                       &g_stack_clear_len, &j);
9231             else if (i == 1)
9232               // clear_regmask=<mask>
9233               ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9234             if (ret < 2) {
9235               anote("unparsed attr value: %s\n", p);
9236               break;
9237             }
9238             p += j;
9239           }
9240           else if (i == ARRAY_SIZE(attrs)) {
9241             anote("unparsed sct attr: %s\n", p);
9242             break;
9243           }
9244         }
9245       }
9246       else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9247       {
9248         p += 30;
9249         next_word(words[0], sizeof(words[0]), p);
9250         if (words[0][0] == 0)
9251           aerr("missing name for func chunk?\n");
9252
9253         if (!scanned_ahead) {
9254           add_func_chunk(fasm, words[0], asmln);
9255           func_chunks_sorted = 0;
9256         }
9257       }
9258       else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9259       {
9260         if (func_chunk_i >= 0) {
9261           if (func_chunk_i < func_chunk_cnt
9262             && IS(func_chunks[func_chunk_i].name, g_func))
9263           {
9264             // move on to next chunk
9265             ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9266             if (ret)
9267               aerr("seek failed for '%s' chunk #%d\n",
9268                 g_func, func_chunk_i);
9269             asmln = func_chunks[func_chunk_i].asmln;
9270             func_chunk_i++;
9271           }
9272           else {
9273             if (func_chunk_ret == 0)
9274               aerr("no return from chunk?\n");
9275             fseek(fasm, func_chunk_ret, SEEK_SET);
9276             asmln = func_chunk_ret_ln;
9277             func_chunk_ret = 0;
9278             pending_endp = 1;
9279           }
9280         }
9281       }
9282       else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9283         func_chunks_used = 1;
9284         p += 20;
9285         if (IS_START(g_func, "sub_")) {
9286           unsigned long addr = strtoul(p, NULL, 16);
9287           unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9288           if (addr > f_addr && !scanned_ahead) {
9289             //anote("scan_ahead caused by '%s', addr %lx\n",
9290             //  g_func, addr);
9291             scan_ahead_for_chunks(fasm);
9292             scanned_ahead = 1;
9293             func_chunks_sorted = 0;
9294           }
9295         }
9296       }
9297       continue;
9298     } // *p == ';'
9299
9300 parse_words:
9301     for (i = wordc; i < ARRAY_SIZE(words); i++)
9302       words[i][0] = 0;
9303     for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9304       p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9305       if (*p == 0 || *p == ';') {
9306         wordc++;
9307         break;
9308       }
9309     }
9310     if (*p != 0 && *p != ';')
9311       aerr("too many words\n");
9312
9313     if (skip_code_end) {
9314       skip_code_end = 0;
9315       skip_code = 0;
9316     }
9317
9318     // allow asm patches in comments
9319     if (*p == ';') {
9320       if (IS_START(p, "; sctpatch:")) {
9321         p = sskip(p + 11);
9322         if (*p == 0 || *p == ';')
9323           continue;
9324         goto parse_words; // lame
9325       }
9326       if (IS_START(p, "; sctproto:")) {
9327         sctproto = strdup(p + 11);
9328       }
9329       else if (IS_START(p, "; sctend")) {
9330         end = 1;
9331         if (!pending_endp)
9332           break;
9333       }
9334       else if (IS_START(p, "; sctskip_start")) {
9335         if (in_func && !g_skip_func) {
9336           if (!skip_code) {
9337             ops[pi].op = OPP_ABORT;
9338             ops[pi].asmln = asmln;
9339             pi++;
9340           }
9341           skip_code = 1;
9342         }
9343       }
9344       else if (IS_START(p, "; sctskip_end")) {
9345         if (skip_code)
9346           skip_code_end = 1;
9347       }
9348     }
9349
9350     if (wordc == 0) {
9351       // shouldn't happen
9352       awarn("wordc == 0?\n");
9353       continue;
9354     }
9355
9356     // don't care about this:
9357     if (words[0][0] == '.'
9358         || IS(words[0], "include")
9359         || IS(words[0], "assume") || IS(words[1], "segment")
9360         || IS(words[0], "align"))
9361     {
9362       continue;
9363     }
9364
9365 do_pending_endp:
9366     // do delayed endp processing to collect switch jumptables
9367     if (pending_endp) {
9368       if (in_func && !g_skip_func && !end && wordc >= 2
9369           && ((words[0][0] == 'd' && words[0][2] == 0)
9370               || (words[1][0] == 'd' && words[1][2] == 0)))
9371       {
9372         i = 1;
9373         if (words[1][0] == 'd' && words[1][2] == 0) {
9374           // label
9375           if (g_func_pd_cnt >= pd_alloc) {
9376             pd_alloc = pd_alloc * 2 + 16;
9377             g_func_pd = realloc(g_func_pd,
9378               sizeof(g_func_pd[0]) * pd_alloc);
9379             my_assert_not(g_func_pd, NULL);
9380           }
9381           pd = &g_func_pd[g_func_pd_cnt];
9382           g_func_pd_cnt++;
9383           memset(pd, 0, sizeof(*pd));
9384           strcpy(pd->label, words[0]);
9385           pd->type = OPT_CONST;
9386           pd->lmod = lmod_from_directive(words[1]);
9387           i = 2;
9388         }
9389         else {
9390           if (pd == NULL) {
9391             if (verbose)
9392               anote("skipping alignment byte?\n");
9393             continue;
9394           }
9395           lmod = lmod_from_directive(words[0]);
9396           if (lmod != pd->lmod)
9397             aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9398         }
9399
9400         if (pd->count_alloc < pd->count + wordc) {
9401           pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9402           pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9403           my_assert_not(pd->d, NULL);
9404         }
9405         for (; i < wordc; i++) {
9406           if (IS(words[i], "offset")) {
9407             pd->type = OPT_OFFSET;
9408             i++;
9409           }
9410           p = strchr(words[i], ',');
9411           if (p != NULL)
9412             *p = 0;
9413           if (pd->type == OPT_OFFSET)
9414             pd->d[pd->count].u.label = strdup(words[i]);
9415           else
9416             pd->d[pd->count].u.val = parse_number(words[i], 0);
9417           pd->d[pd->count].bt_i = -1;
9418           pd->count++;
9419         }
9420         continue;
9421       }
9422
9423       if (in_func && !g_skip_func) {
9424         if (g_header_mode)
9425           gen_hdr(g_func, pi);
9426         else
9427           gen_func(fout, g_fhdr, g_func, pi);
9428       }
9429
9430       pending_endp = 0;
9431       in_func = 0;
9432       g_ida_func_attr = 0;
9433       g_sct_func_attr = 0;
9434       g_stack_clear_start = 0;
9435       g_stack_clear_len = 0;
9436       g_regmask_init = 0;
9437       skip_warned = 0;
9438       g_skip_func = 0;
9439       g_func[0] = 0;
9440       g_seh_found = 0;
9441       func_chunks_used = 0;
9442       func_chunk_i = -1;
9443       if (pi != 0) {
9444         memset(&ops, 0, pi * sizeof(ops[0]));
9445         clear_labels(pi);
9446         pi = 0;
9447       }
9448       g_eqcnt = 0;
9449       for (i = 0; i < g_func_pd_cnt; i++) {
9450         pd = &g_func_pd[i];
9451         if (pd->type == OPT_OFFSET) {
9452           for (j = 0; j < pd->count; j++)
9453             free(pd->d[j].u.label);
9454         }
9455         free(pd->d);
9456         pd->d = NULL;
9457       }
9458       g_func_pd_cnt = 0;
9459       g_func_lmods = 0;
9460       pd = NULL;
9461
9462       if (end)
9463         break;
9464       if (wordc == 0)
9465         continue;
9466     }
9467
9468     if (IS(words[1], "proc")) {
9469       if (in_func)
9470         aerr("proc '%s' while in_func '%s'?\n",
9471           words[0], g_func);
9472       p = words[0];
9473       if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9474         g_skip_func = 1;
9475       strcpy(g_func, words[0]);
9476       set_label(0, words[0]);
9477       in_func = 1;
9478       continue;
9479     }
9480
9481     if (IS(words[1], "endp"))
9482     {
9483       if (!in_func)
9484         aerr("endp '%s' while not in_func?\n", words[0]);
9485       if (!IS(g_func, words[0]))
9486         aerr("endp '%s' while in_func '%s'?\n",
9487           words[0], g_func);
9488       if (skip_code)
9489         aerr("endp '%s' while skipping code\n", words[0]);
9490
9491       if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9492         && ops[0].op == OP_JMP && ops[0].operand[0].segment)
9493       {
9494         // import jump
9495         g_skip_func = 1;
9496       }
9497
9498       if (!g_skip_func && func_chunks_used) {
9499         // start processing chunks
9500         struct chunk_item *ci, key = { g_func, 0 };
9501
9502         func_chunk_ret = ftell(fasm);
9503         func_chunk_ret_ln = asmln;
9504         if (!func_chunks_sorted) {
9505           qsort(func_chunks, func_chunk_cnt,
9506             sizeof(func_chunks[0]), cmp_chunks);
9507           func_chunks_sorted = 1;
9508         }
9509         ci = bsearch(&key, func_chunks, func_chunk_cnt,
9510                sizeof(func_chunks[0]), cmp_chunks);
9511         if (ci == NULL)
9512           aerr("'%s' needs chunks, but none found\n", g_func);
9513         func_chunk_i = ci - func_chunks;
9514         for (; func_chunk_i > 0; func_chunk_i--)
9515           if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9516             break;
9517
9518         ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9519         if (ret)
9520           aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9521         asmln = func_chunks[func_chunk_i].asmln;
9522         func_chunk_i++;
9523         continue;
9524       }
9525       pending_endp = 1;
9526       continue;
9527     }
9528
9529     if (wordc == 2 && IS(words[1], "ends")) {
9530       if (!multi_seg) {
9531         end = 1;
9532         if (pending_endp)
9533           goto do_pending_endp;
9534         break;
9535       }
9536
9537       // scan for next text segment
9538       while (my_fgets(line, sizeof(line), fasm)) {
9539         asmln++;
9540         p = sskip(line);
9541         if (*p == 0 || *p == ';')
9542           continue;
9543
9544         if (strstr(p, "segment para public 'CODE' use32"))
9545           break;
9546       }
9547
9548       continue;
9549     }
9550
9551     p = strchr(words[0], ':');
9552     if (p != NULL) {
9553       set_label(pi, words[0]);
9554       continue;
9555     }
9556
9557     if (!in_func || g_skip_func || skip_code) {
9558       if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9559         if (verbose)
9560           anote("skipping from '%s'\n", g_labels[pi]);
9561         skip_warned = 1;
9562       }
9563       free(g_labels[pi]);
9564       g_labels[pi] = NULL;
9565       continue;
9566     }
9567
9568     if (wordc > 1 && IS(words[1], "="))
9569     {
9570       if (wordc != 5)
9571         aerr("unhandled equ, wc=%d\n", wordc);
9572       if (g_eqcnt >= eq_alloc) {
9573         eq_alloc *= 2;
9574         g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9575         my_assert_not(g_eqs, NULL);
9576       }
9577
9578       len = strlen(words[0]);
9579       if (len > sizeof(g_eqs[0].name) - 1)
9580         aerr("equ name too long: %d\n", len);
9581       strcpy(g_eqs[g_eqcnt].name, words[0]);
9582
9583       if (!IS(words[3], "ptr"))
9584         aerr("unhandled equ\n");
9585       if (IS(words[2], "dword"))
9586         g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9587       else if (IS(words[2], "word"))
9588         g_eqs[g_eqcnt].lmod = OPLM_WORD;
9589       else if (IS(words[2], "byte"))
9590         g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9591       else if (IS(words[2], "qword"))
9592         g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9593       else
9594         aerr("bad lmod: '%s'\n", words[2]);
9595
9596       g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9597       g_eqcnt++;
9598       continue;
9599     }
9600
9601     if (pi >= ARRAY_SIZE(ops))
9602       aerr("too many ops\n");
9603
9604     parse_op(&ops[pi], words, wordc);
9605
9606     ops[pi].datap = sctproto;
9607     sctproto = NULL;
9608     pi++;
9609   }
9610
9611   if (g_header_mode)
9612     output_hdr(fout);
9613
9614   fclose(fout);
9615   fclose(fasm);
9616   fclose(g_fhdr);
9617
9618   return 0;
9619 }
9620
9621 // vim:ts=2:shiftwidth=2:expandtab