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