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