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