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