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