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