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