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