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