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