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