translate: stop data parse on imports
[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: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
247     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   struct parsed_op *po;
2611   int first_pop = -1;
2612
2613   *adj = *is_multipath = 0;
2614
2615   for (; i < opcnt && *adj < adj_expect; i++) {
2616     if (g_labels[i] != NULL)
2617       *is_multipath = 1;
2618
2619     po = &ops[i];
2620     if (po->flags & OPF_DONE)
2621       continue;
2622
2623     if (po->op == OP_ADD && po->operand[0].reg == xSP) {
2624       if (po->operand[1].type != OPT_CONST)
2625         ferr(&ops[i], "non-const esp adjust?\n");
2626       *adj += po->operand[1].val;
2627       if (*adj & 3)
2628         ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
2629       if (do_update) {
2630         if (!*is_multipath)
2631           patch_esp_adjust(po, adj_expect);
2632         else
2633           po->flags |= OPF_RMD;
2634       }
2635       return i;
2636     }
2637     else if (po->op == OP_PUSH) {
2638       //if (first_pop == -1)
2639       //  first_pop = -2; // none
2640       *adj -= lmod_bytes(po, po->operand[0].lmod);
2641     }
2642     else if (po->op == OP_POP) {
2643       if (!(po->flags & OPF_DONE)) {
2644         // seems like msvc only uses 'pop ecx' for stack realignment..
2645         if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
2646           break;
2647         if (first_pop == -1 && *adj >= 0)
2648           first_pop = i;
2649       }
2650       if (do_update && *adj >= 0) {
2651         po->flags |= OPF_RMD;
2652         if (!*is_multipath)
2653           po->flags |= OPF_DONE;
2654       }
2655
2656       *adj += lmod_bytes(po, po->operand[0].lmod);
2657     }
2658     else if (po->flags & (OPF_JMP|OPF_TAIL)) {
2659       if (po->op == OP_JMP && po->btj == NULL) {
2660         if (po->bt_i <= i)
2661           break;
2662         i = po->bt_i - 1;
2663         continue;
2664       }
2665       if (po->op != OP_CALL)
2666         break;
2667       if (po->operand[0].type != OPT_LABEL)
2668         break;
2669       if (po->pp != NULL && po->pp->is_stdcall)
2670         break;
2671       // assume it's another cdecl call
2672     }
2673   }
2674
2675   if (first_pop >= 0) {
2676     // probably 'pop ecx' was used..
2677     return first_pop;
2678   }
2679
2680   return -1;
2681 }
2682
2683 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
2684 {
2685   struct parsed_op *po;
2686   int j;
2687
2688   if (i < 0)
2689     ferr(ops, "%s: followed bad branch?\n", __func__);
2690
2691   for (; i < opcnt; i++) {
2692     po = &ops[i];
2693     if (po->cc_scratch == magic)
2694       return;
2695     po->cc_scratch = magic;
2696     po->flags |= flags;
2697
2698     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2699       if (po->btj != NULL) {
2700         // jumptable
2701         for (j = 0; j < po->btj->count; j++)
2702           scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
2703         return;
2704       }
2705
2706       scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
2707       if (!(po->flags & OPF_CJMP))
2708         return;
2709     }
2710     if (po->flags & OPF_TAIL)
2711       return;
2712   }
2713 }
2714
2715 static const struct parsed_proto *try_recover_pp(
2716   struct parsed_op *po, const struct parsed_opr *opr, int *search_instead)
2717 {
2718   const struct parsed_proto *pp = NULL;
2719   char buf[256];
2720   char *p;
2721
2722   // maybe an arg of g_func?
2723   if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
2724   {
2725     char ofs_reg[16] = { 0, };
2726     int arg, arg_s, arg_i;
2727     int stack_ra = 0;
2728     int offset = 0;
2729
2730     if (g_header_mode)
2731       return NULL;
2732
2733     parse_stack_access(po, opr->name, ofs_reg,
2734       &offset, &stack_ra, NULL, 0);
2735     if (ofs_reg[0] != 0)
2736       ferr(po, "offset reg on arg access?\n");
2737     if (offset <= stack_ra) {
2738       // search who set the stack var instead
2739       if (search_instead != NULL)
2740         *search_instead = 1;
2741       return NULL;
2742     }
2743
2744     arg_i = (offset - stack_ra - 4) / 4;
2745     for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
2746       if (g_func_pp->arg[arg].reg != NULL)
2747         continue;
2748       if (arg_s == arg_i)
2749         break;
2750       arg_s++;
2751     }
2752     if (arg == g_func_pp->argc)
2753       ferr(po, "stack arg %d not in prototype?\n", arg_i);
2754
2755     pp = g_func_pp->arg[arg].fptr;
2756     if (pp == NULL)
2757       ferr(po, "icall sa: arg%d is not a fptr?\n", arg + 1);
2758     check_func_pp(po, pp, "icall arg");
2759   }
2760   else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
2761     // label[index]
2762     p = strchr(opr->name + 1, '[');
2763     memcpy(buf, opr->name, p - opr->name);
2764     buf[p - opr->name] = 0;
2765     pp = proto_parse(g_fhdr, buf, g_quiet_pp);
2766   }
2767   else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
2768     pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
2769     if (pp == NULL) {
2770       if (!g_header_mode)
2771         ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
2772     }
2773     else
2774       check_func_pp(po, pp, "reg-fptr ref");
2775   }
2776
2777   return pp;
2778 }
2779
2780 static void scan_for_call_type(int i, const struct parsed_opr *opr,
2781   int magic, const struct parsed_proto **pp_found, int *pp_i,
2782   int *multi)
2783 {
2784   const struct parsed_proto *pp = NULL;
2785   struct parsed_op *po;
2786   struct label_ref *lr;
2787
2788   ops[i].cc_scratch = magic;
2789
2790   while (1) {
2791     if (g_labels[i] != NULL) {
2792       lr = &g_label_refs[i];
2793       for (; lr != NULL; lr = lr->next) {
2794         check_i(&ops[i], lr->i);
2795         scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
2796       }
2797       if (i > 0 && LAST_OP(i - 1))
2798         return;
2799     }
2800
2801     i--;
2802     if (i < 0)
2803       break;
2804
2805     if (ops[i].cc_scratch == magic)
2806       return;
2807     ops[i].cc_scratch = magic;
2808
2809     if (!(ops[i].flags & OPF_DATA))
2810       continue;
2811     if (!is_opr_modified(opr, &ops[i]))
2812       continue;
2813     if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
2814       // most probably trashed by some processing
2815       *pp_found = NULL;
2816       return;
2817     }
2818
2819     opr = &ops[i].operand[1];
2820     if (opr->type != OPT_REG)
2821       break;
2822   }
2823
2824   po = (i >= 0) ? &ops[i] : ops;
2825
2826   if (i < 0) {
2827     // reached the top - can only be an arg-reg
2828     if (opr->type != OPT_REG)
2829       return;
2830
2831     for (i = 0; i < g_func_pp->argc; i++) {
2832       if (g_func_pp->arg[i].reg == NULL)
2833         continue;
2834       if (IS(opr->name, g_func_pp->arg[i].reg))
2835         break;
2836     }
2837     if (i == g_func_pp->argc)
2838       return;
2839     pp = g_func_pp->arg[i].fptr;
2840     if (pp == NULL)
2841       ferr(po, "icall: arg%d (%s) is not a fptr?\n",
2842         i + 1, g_func_pp->arg[i].reg);
2843     check_func_pp(po, pp, "icall reg-arg");
2844   }
2845   else
2846     pp = try_recover_pp(po, opr, NULL);
2847
2848   if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
2849     if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
2850       || (*pp_found)->is_stdcall != pp->is_stdcall
2851       || (*pp_found)->is_fptr != pp->is_fptr
2852       || (*pp_found)->argc != pp->argc
2853       || (*pp_found)->argc_reg != pp->argc_reg
2854       || (*pp_found)->argc_stack != pp->argc_stack)
2855     {
2856       ferr(po, "icall: parsed_proto mismatch\n");
2857     }
2858     *multi = 1;
2859   }
2860   if (pp != NULL) {
2861     *pp_found = pp;
2862     *pp_i = po - ops;
2863   }
2864 }
2865
2866 static void add_label_ref(struct label_ref *lr, int op_i)
2867 {
2868   struct label_ref *lr_new;
2869
2870   if (lr->i == -1) {
2871     lr->i = op_i;
2872     return;
2873   }
2874
2875   lr_new = calloc(1, sizeof(*lr_new));
2876   lr_new->i = op_i;
2877   lr_new->next = lr->next;
2878   lr->next = lr_new;
2879 }
2880
2881 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
2882 {
2883   struct parsed_op *po = &ops[i];
2884   struct parsed_data *pd;
2885   char label[NAMELEN], *p;
2886   int len, j, l;
2887
2888   p = strchr(po->operand[0].name, '[');
2889   if (p == NULL)
2890     return NULL;
2891
2892   len = p - po->operand[0].name;
2893   strncpy(label, po->operand[0].name, len);
2894   label[len] = 0;
2895
2896   for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
2897     if (IS(g_func_pd[j].label, label)) {
2898       pd = &g_func_pd[j];
2899       break;
2900     }
2901   }
2902   if (pd == NULL)
2903     //ferr(po, "label '%s' not parsed?\n", label);
2904     return NULL;
2905
2906   if (pd->type != OPT_OFFSET)
2907     ferr(po, "label '%s' with non-offset data?\n", label);
2908
2909   // find all labels, link
2910   for (j = 0; j < pd->count; j++) {
2911     for (l = 0; l < opcnt; l++) {
2912       if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
2913         add_label_ref(&g_label_refs[l], i);
2914         pd->d[j].bt_i = l;
2915         break;
2916       }
2917     }
2918   }
2919
2920   return pd;
2921 }
2922
2923 static void clear_labels(int count)
2924 {
2925   int i;
2926
2927   for (i = 0; i < count; i++) {
2928     if (g_labels[i] != NULL) {
2929       free(g_labels[i]);
2930       g_labels[i] = NULL;
2931     }
2932   }
2933 }
2934
2935 static void resolve_branches_parse_calls(int opcnt)
2936 {
2937   const struct parsed_proto *pp_c;
2938   struct parsed_proto *pp;
2939   struct parsed_data *pd;
2940   struct parsed_op *po;
2941   const char *tmpname;
2942   int i, l, ret;
2943
2944   for (i = 0; i < opcnt; i++)
2945   {
2946     po = &ops[i];
2947     po->bt_i = -1;
2948     po->btj = NULL;
2949
2950     if (po->op == OP_CALL) {
2951       pp = NULL;
2952
2953       if (po->operand[0].type == OPT_LABEL) {
2954         tmpname = opr_name(po, 0);
2955         if (IS_START(tmpname, "loc_"))
2956           ferr(po, "call to loc_*\n");
2957         pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
2958         if (!g_header_mode && pp_c == NULL)
2959           ferr(po, "proto_parse failed for call '%s'\n", tmpname);
2960
2961         if (pp_c != NULL) {
2962           pp = proto_clone(pp_c);
2963           my_assert_not(pp, NULL);
2964         }
2965       }
2966       else if (po->datap != NULL) {
2967         pp = calloc(1, sizeof(*pp));
2968         my_assert_not(pp, NULL);
2969
2970         ret = parse_protostr(po->datap, pp);
2971         if (ret < 0)
2972           ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
2973         free(po->datap);
2974         po->datap = NULL;
2975       }
2976
2977       if (pp != NULL) {
2978         if (pp->is_fptr)
2979           check_func_pp(po, pp, "fptr var call");
2980         if (pp->is_noreturn)
2981           po->flags |= OPF_TAIL;
2982       }
2983       po->pp = pp;
2984       continue;
2985     }
2986
2987     if (!(po->flags & OPF_JMP) || po->op == OP_RET)
2988       continue;
2989
2990     if (po->operand[0].type == OPT_REGMEM) {
2991       pd = try_resolve_jumptab(i, opcnt);
2992       if (pd == NULL)
2993         goto tailcall;
2994
2995       po->btj = pd;
2996       continue;
2997     }
2998
2999     for (l = 0; l < opcnt; l++) {
3000       if (g_labels[l] != NULL
3001           && IS(po->operand[0].name, g_labels[l]))
3002       {
3003         if (l == i + 1 && po->op == OP_JMP) {
3004           // yet another alignment type..
3005           po->flags |= OPF_RMD|OPF_DONE;
3006           break;
3007         }
3008         add_label_ref(&g_label_refs[l], i);
3009         po->bt_i = l;
3010         break;
3011       }
3012     }
3013
3014     if (po->bt_i != -1 || (po->flags & OPF_RMD))
3015       continue;
3016
3017     if (po->operand[0].type == OPT_LABEL)
3018       // assume tail call
3019       goto tailcall;
3020
3021     ferr(po, "unhandled branch\n");
3022
3023 tailcall:
3024     po->op = OP_CALL;
3025     po->flags |= OPF_TAIL;
3026     if (i > 0 && ops[i - 1].op == OP_POP)
3027       po->flags |= OPF_ATAIL;
3028     i--; // reprocess
3029   }
3030 }
3031
3032 static void scan_prologue_epilogue(int opcnt)
3033 {
3034   int ecx_push = 0, esp_sub = 0;
3035   int found;
3036   int i, j, l;
3037
3038   if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3039       && ops[1].op == OP_MOV
3040       && IS(opr_name(&ops[1], 0), "ebp")
3041       && IS(opr_name(&ops[1], 1), "esp"))
3042   {
3043     g_bp_frame = 1;
3044     ops[0].flags |= OPF_RMD | OPF_DONE;
3045     ops[1].flags |= OPF_RMD | OPF_DONE;
3046     i = 2;
3047
3048     if (ops[2].op == OP_SUB && IS(opr_name(&ops[2], 0), "esp")) {
3049       g_stack_fsz = opr_const(&ops[2], 1);
3050       ops[2].flags |= OPF_RMD | OPF_DONE;
3051       i++;
3052     }
3053     else {
3054       // another way msvc builds stack frame..
3055       i = 2;
3056       while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3057         g_stack_fsz += 4;
3058         ops[i].flags |= OPF_RMD | OPF_DONE;
3059         ecx_push++;
3060         i++;
3061       }
3062       // and another way..
3063       if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3064           && ops[i].operand[1].type == OPT_CONST
3065           && ops[i + 1].op == OP_CALL
3066           && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3067       {
3068         g_stack_fsz += ops[i].operand[1].val;
3069         ops[i].flags |= OPF_RMD | OPF_DONE;
3070         i++;
3071         ops[i].flags |= OPF_RMD | OPF_DONE;
3072         i++;
3073       }
3074     }
3075
3076     found = 0;
3077     do {
3078       for (; i < opcnt; i++)
3079         if (ops[i].flags & OPF_TAIL)
3080           break;
3081       j = i - 1;
3082       if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3083         if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3084           break;
3085         i--;
3086         j--;
3087       }
3088
3089       if ((ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3090           || ops[j].op == OP_LEAVE)
3091       {
3092         ops[j].flags |= OPF_RMD | OPF_DONE;
3093       }
3094       else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3095         && ops[i].pp->is_noreturn)
3096       {
3097         // on noreturn, msvc sometimes cleans stack, sometimes not
3098         i++;
3099         found = 1;
3100         continue;
3101       }
3102       else if (!(g_ida_func_attr & IDAFA_NORETURN))
3103         ferr(&ops[j], "'pop ebp' expected\n");
3104
3105       if (g_stack_fsz != 0) {
3106         if (ops[j - 1].op == OP_MOV
3107             && IS(opr_name(&ops[j - 1], 0), "esp")
3108             && IS(opr_name(&ops[j - 1], 1), "ebp"))
3109         {
3110           ops[j - 1].flags |= OPF_RMD | OPF_DONE;
3111         }
3112         else if (ops[j].op != OP_LEAVE
3113           && !(g_ida_func_attr & IDAFA_NORETURN))
3114         {
3115           ferr(&ops[j - 1], "esp restore expected\n");
3116         }
3117
3118         if (ecx_push && ops[j - 2].op == OP_POP
3119           && IS(opr_name(&ops[j - 2], 0), "ecx"))
3120         {
3121           ferr(&ops[j - 2], "unexpected ecx pop\n");
3122         }
3123       }
3124
3125       found = 1;
3126       i++;
3127     } while (i < opcnt);
3128
3129     if (!found)
3130       ferr(ops, "missing ebp epilogue\n");
3131     return;
3132   }
3133
3134   // non-bp frame
3135   i = 0;
3136   while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3137     ops[i].flags |= OPF_RMD | OPF_DONE;
3138     g_stack_fsz += 4;
3139     ecx_push++;
3140     i++;
3141   }
3142
3143   for (; i < opcnt; i++) {
3144     if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3145       break;
3146     if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3147       && ops[i].operand[1].type == OPT_CONST)
3148     {
3149       g_stack_fsz = ops[i].operand[1].val;
3150       ops[i].flags |= OPF_RMD | OPF_DONE;
3151       esp_sub = 1;
3152       break;
3153     }
3154   }
3155
3156   if (ecx_push && !esp_sub) {
3157     // could actually be args for a call..
3158     for (; i < opcnt; i++)
3159       if (ops[i].op != OP_PUSH)
3160         break;
3161
3162     if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3163       const struct parsed_proto *pp;
3164       pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3165       j = pp ? pp->argc_stack : 0;
3166       while (i > 0 && j > 0) {
3167         i--;
3168         if (ops[i].op == OP_PUSH) {
3169           ops[i].flags &= ~(OPF_RMD | OPF_DONE);
3170           j--;
3171         }
3172       }
3173       if (j != 0)
3174         ferr(&ops[i], "unhandled prologue\n");
3175
3176       // recheck
3177       i = g_stack_fsz = ecx_push = 0;
3178       while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3179         if (!(ops[i].flags & OPF_RMD))
3180           break;
3181         g_stack_fsz += 4;
3182         ecx_push++;
3183         i++;
3184       }
3185     }
3186   }
3187
3188   found = 0;
3189   if (ecx_push || esp_sub)
3190   {
3191     g_sp_frame = 1;
3192
3193     i++;
3194     do {
3195       for (; i < opcnt; i++)
3196         if (ops[i].flags & OPF_TAIL)
3197           break;
3198       j = i - 1;
3199       if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3200         if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3201           break;
3202         i--;
3203         j--;
3204       }
3205
3206       if (ecx_push > 0) {
3207         for (l = 0; l < ecx_push; l++) {
3208           if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
3209             /* pop ecx */;
3210           else if (ops[j].op == OP_ADD
3211                    && IS(opr_name(&ops[j], 0), "esp")
3212                    && ops[j].operand[1].type == OPT_CONST)
3213           {
3214             /* add esp, N */
3215             l += ops[j].operand[1].val / 4 - 1;
3216           }
3217           else
3218             ferr(&ops[j], "'pop ecx' expected\n");
3219
3220           ops[j].flags |= OPF_RMD | OPF_DONE;
3221           j--;
3222         }
3223         if (l != ecx_push)
3224           ferr(&ops[j], "epilogue scan failed\n");
3225
3226         found = 1;
3227       }
3228
3229       if (esp_sub) {
3230         if (ops[j].op != OP_ADD
3231             || !IS(opr_name(&ops[j], 0), "esp")
3232             || ops[j].operand[1].type != OPT_CONST
3233             || ops[j].operand[1].val != g_stack_fsz)
3234           ferr(&ops[j], "'add esp' expected\n");
3235
3236         ops[j].flags |= OPF_RMD | OPF_DONE;
3237         ops[j].operand[1].val = 0; // hack for stack arg scanner
3238         found = 1;
3239       }
3240
3241       i++;
3242     } while (i < opcnt);
3243
3244     if (!found)
3245       ferr(ops, "missing esp epilogue\n");
3246   }
3247 }
3248
3249 static const struct parsed_proto *resolve_icall(int i, int opcnt,
3250   int *pp_i, int *multi_src)
3251 {
3252   const struct parsed_proto *pp = NULL;
3253   int search_advice = 0;
3254
3255   *multi_src = 0;
3256   *pp_i = -1;
3257
3258   switch (ops[i].operand[0].type) {
3259   case OPT_REGMEM:
3260   case OPT_LABEL:
3261   case OPT_OFFSET:
3262     pp = try_recover_pp(&ops[i], &ops[i].operand[0], &search_advice);
3263     if (!search_advice)
3264       break;
3265     // fallthrough
3266   default:
3267     scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
3268       pp_i, multi_src);
3269     break;
3270   }
3271
3272   return pp;
3273 }
3274
3275 // find an instruction that changed opr before i op
3276 // *op_i must be set to -1 by the caller
3277 // *entry is set to 1 if one source is determined to be the caller
3278 // returns 1 if found, *op_i is then set to origin
3279 static int resolve_origin(int i, const struct parsed_opr *opr,
3280   int magic, int *op_i, int *is_caller)
3281 {
3282   struct label_ref *lr;
3283   int ret = 0;
3284
3285   if (ops[i].cc_scratch == magic)
3286     return 0;
3287   ops[i].cc_scratch = magic;
3288
3289   while (1) {
3290     if (g_labels[i] != NULL) {
3291       lr = &g_label_refs[i];
3292       for (; lr != NULL; lr = lr->next) {
3293         check_i(&ops[i], lr->i);
3294         ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
3295       }
3296       if (i > 0 && LAST_OP(i - 1))
3297         return ret;
3298     }
3299
3300     i--;
3301     if (i < 0) {
3302       if (is_caller != NULL)
3303         *is_caller = 1;
3304       return -1;
3305     }
3306
3307     if (ops[i].cc_scratch == magic)
3308       return ret;
3309     ops[i].cc_scratch = magic;
3310
3311     if (!(ops[i].flags & OPF_DATA))
3312       continue;
3313     if (!is_opr_modified(opr, &ops[i]))
3314       continue;
3315
3316     if (*op_i >= 0) {
3317       if (*op_i == i)
3318         return ret | 1;
3319
3320       // XXX: could check if the other op does the same
3321       return -1;
3322     }
3323
3324     *op_i = i;
3325     return ret | 1;
3326   }
3327 }
3328
3329 // find an instruction that previously referenced opr
3330 // if multiple results are found - fail
3331 // *op_i must be set to -1 by the caller
3332 // returns 1 if found, *op_i is then set to referencer insn
3333 static int resolve_last_ref(int i, const struct parsed_opr *opr,
3334   int magic, int *op_i)
3335 {
3336   struct label_ref *lr;
3337   int ret = 0;
3338
3339   if (ops[i].cc_scratch == magic)
3340     return 0;
3341   ops[i].cc_scratch = magic;
3342
3343   while (1) {
3344     if (g_labels[i] != NULL) {
3345       lr = &g_label_refs[i];
3346       for (; lr != NULL; lr = lr->next) {
3347         check_i(&ops[i], lr->i);
3348         ret |= resolve_last_ref(lr->i, opr, magic, op_i);
3349       }
3350       if (i > 0 && LAST_OP(i - 1))
3351         return ret;
3352     }
3353
3354     i--;
3355     if (i < 0)
3356       return -1;
3357
3358     if (ops[i].cc_scratch == magic)
3359       return 0;
3360     ops[i].cc_scratch = magic;
3361
3362     if (!is_opr_referenced(opr, &ops[i]))
3363       continue;
3364
3365     if (*op_i >= 0)
3366       return -1;
3367
3368     *op_i = i;
3369     return 1;
3370   }
3371 }
3372
3373 // find next instruction that reads opr
3374 // if multiple results are found - fail
3375 // *op_i must be set to -1 by the caller
3376 // returns 1 if found, *op_i is then set to referencer insn
3377 static int find_next_read(int i, int opcnt,
3378   const struct parsed_opr *opr, int magic, int *op_i)
3379 {
3380   struct parsed_op *po;
3381   int j, ret = 0;
3382
3383   for (; i < opcnt; i++)
3384   {
3385     if (ops[i].cc_scratch == magic)
3386       return 0;
3387     ops[i].cc_scratch = magic;
3388
3389     po = &ops[i];
3390     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3391       if (po->btj != NULL) {
3392         // jumptable
3393         for (j = 0; j < po->btj->count; j++) {
3394           check_i(po, po->btj->d[j].bt_i);
3395           ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
3396                    magic, op_i);
3397         }
3398         return ret;
3399       }
3400
3401       if (po->flags & OPF_RMD)
3402         continue;
3403       check_i(po, po->bt_i);
3404       if (po->flags & OPF_CJMP) {
3405         ret = find_next_read(po->bt_i, opcnt, opr, magic, op_i);
3406         if (ret < 0)
3407           return ret;
3408       }
3409
3410       i = po->bt_i - 1;
3411       continue;
3412     }
3413
3414     if (!is_opr_read(opr, po)) {
3415       if (is_opr_modified(opr, po))
3416         // it's overwritten
3417         return 0;
3418       if (po->flags & OPF_TAIL)
3419         return 0;
3420       continue;
3421     }
3422
3423     if (*op_i >= 0)
3424       return -1;
3425
3426     *op_i = i;
3427     return 1;
3428   }
3429
3430   return 0;
3431 }
3432
3433 static int try_resolve_const(int i, const struct parsed_opr *opr,
3434   int magic, unsigned int *val)
3435 {
3436   int s_i = -1;
3437   int ret;
3438
3439   ret = resolve_origin(i, opr, magic, &s_i, NULL);
3440   if (ret == 1) {
3441     i = s_i;
3442     if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
3443       return -1;
3444
3445     *val = ops[i].operand[1].val;
3446     return 1;
3447   }
3448
3449   return -1;
3450 }
3451
3452 static struct parsed_proto *process_call_early(int i, int opcnt,
3453   int *adj_i)
3454 {
3455   struct parsed_op *po = &ops[i];
3456   struct parsed_proto *pp;
3457   int multipath = 0;
3458   int adj = 0;
3459   int ret;
3460
3461   pp = po->pp;
3462   if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
3463     // leave for later
3464     return NULL;
3465
3466   // look for and make use of esp adjust
3467   *adj_i = ret = -1;
3468   if (!pp->is_stdcall && pp->argc_stack > 0)
3469     ret = scan_for_esp_adjust(i + 1, opcnt,
3470             pp->argc_stack * 4, &adj, &multipath, 0);
3471   if (ret >= 0) {
3472     if (pp->argc_stack > adj / 4)
3473       return NULL;
3474     if (multipath)
3475       return NULL;
3476     if (ops[ret].op == OP_POP && adj != 4)
3477       return NULL;
3478   }
3479
3480   *adj_i = ret;
3481   return pp;
3482 }
3483
3484 static struct parsed_proto *process_call(int i, int opcnt)
3485 {
3486   struct parsed_op *po = &ops[i];
3487   const struct parsed_proto *pp_c;
3488   struct parsed_proto *pp;
3489   const char *tmpname;
3490   int call_i = -1, ref_i = -1;
3491   int adj = 0, multipath = 0;
3492   int ret, arg;
3493
3494   tmpname = opr_name(po, 0);
3495   pp = po->pp;
3496   if (pp == NULL)
3497   {
3498     // indirect call
3499     pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
3500     if (pp_c != NULL) {
3501       if (!pp_c->is_func && !pp_c->is_fptr)
3502         ferr(po, "call to non-func: %s\n", pp_c->name);
3503       pp = proto_clone(pp_c);
3504       my_assert_not(pp, NULL);
3505       if (multipath)
3506         // not resolved just to single func
3507         pp->is_fptr = 1;
3508
3509       switch (po->operand[0].type) {
3510       case OPT_REG:
3511         // we resolved this call and no longer need the register
3512         po->regmask_src &= ~(1 << po->operand[0].reg);
3513
3514         if (!multipath && i != call_i && ops[call_i].op == OP_MOV
3515           && ops[call_i].operand[1].type == OPT_LABEL)
3516         {
3517           // no other source users?
3518           ret = resolve_last_ref(i, &po->operand[0], opcnt * 10,
3519                   &ref_i);
3520           if (ret == 1 && call_i == ref_i) {
3521             // and nothing uses it after us?
3522             ref_i = -1;
3523             ret = find_next_read(i + 1, opcnt, &po->operand[0],
3524                     opcnt * 11, &ref_i);
3525             if (ret != 1)
3526               // then also don't need the source mov
3527               ops[call_i].flags |= OPF_RMD;
3528           }
3529         }
3530         break;
3531       case OPT_REGMEM:
3532         pp->is_fptr = 1;
3533         break;
3534       default:
3535         break;
3536       }
3537     }
3538     if (pp == NULL) {
3539       pp = calloc(1, sizeof(*pp));
3540       my_assert_not(pp, NULL);
3541
3542       pp->is_fptr = 1;
3543       ret = scan_for_esp_adjust(i + 1, opcnt,
3544               32*4, &adj, &multipath, 0);
3545       if (ret < 0 || adj < 0) {
3546         if (!g_allow_regfunc)
3547           ferr(po, "non-__cdecl indirect call unhandled yet\n");
3548         pp->is_unresolved = 1;
3549         adj = 0;
3550       }
3551       adj /= 4;
3552       if (adj > ARRAY_SIZE(pp->arg))
3553         ferr(po, "esp adjust too large: %d\n", adj);
3554       pp->ret_type.name = strdup("int");
3555       pp->argc = pp->argc_stack = adj;
3556       for (arg = 0; arg < pp->argc; arg++)
3557         pp->arg[arg].type.name = strdup("int");
3558     }
3559     po->pp = pp;
3560   }
3561
3562   // look for and make use of esp adjust
3563   multipath = 0;
3564   ret = -1;
3565   if (!pp->is_stdcall && pp->argc_stack > 0)
3566     ret = scan_for_esp_adjust(i + 1, opcnt,
3567             pp->argc_stack * 4, &adj, &multipath, 0);
3568   if (ret >= 0) {
3569     if (pp->is_vararg) {
3570       if (adj / 4 < pp->argc_stack) {
3571         fnote(po, "(this call)\n");
3572         ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
3573           adj, pp->argc_stack * 4);
3574       }
3575       // modify pp to make it have varargs as normal args
3576       arg = pp->argc;
3577       pp->argc += adj / 4 - pp->argc_stack;
3578       for (; arg < pp->argc; arg++) {
3579         pp->arg[arg].type.name = strdup("int");
3580         pp->argc_stack++;
3581       }
3582       if (pp->argc > ARRAY_SIZE(pp->arg))
3583         ferr(po, "too many args for '%s'\n", tmpname);
3584     }
3585     if (pp->argc_stack > adj / 4) {
3586       fnote(po, "(this call)\n");
3587       ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
3588         tmpname, pp->argc_stack * 4, adj);
3589     }
3590
3591     scan_for_esp_adjust(i + 1, opcnt,
3592       pp->argc_stack * 4, &adj, &multipath, 1);
3593   }
3594   else if (pp->is_vararg)
3595     ferr(po, "missing esp_adjust for vararg func '%s'\n",
3596       pp->name);
3597
3598   return pp;
3599 }
3600
3601 static int collect_call_args_early(struct parsed_op *po, int i,
3602   struct parsed_proto *pp, int *regmask)
3603 {
3604   int arg, ret;
3605   int j;
3606
3607   for (arg = 0; arg < pp->argc; arg++)
3608     if (pp->arg[arg].reg == NULL)
3609       break;
3610
3611   // first see if it can be easily done
3612   for (j = i; j > 0 && arg < pp->argc; )
3613   {
3614     if (g_labels[j] != NULL)
3615       return -1;
3616     j--;
3617
3618     if (ops[j].op == OP_CALL)
3619       return -1;
3620     else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP)
3621       return -1;
3622     else if (ops[j].op == OP_POP)
3623       return -1;
3624     else if (ops[j].flags & OPF_CJMP)
3625       return -1;
3626     else if (ops[j].op == OP_PUSH) {
3627       if (ops[j].flags & (OPF_FARG|OPF_FARGNR))
3628         return -1;
3629       ret = scan_for_mod(&ops[j], j + 1, i, 1);
3630       if (ret >= 0)
3631         return -1;
3632
3633       if (pp->arg[arg].type.is_va_list)
3634         return -1;
3635
3636       // next arg
3637       for (arg++; arg < pp->argc; arg++)
3638         if (pp->arg[arg].reg == NULL)
3639           break;
3640     }
3641   }
3642
3643   if (arg < pp->argc)
3644     return -1;
3645
3646   // now do it
3647   for (arg = 0; arg < pp->argc; arg++)
3648     if (pp->arg[arg].reg == NULL)
3649       break;
3650
3651   for (j = i; j > 0 && arg < pp->argc; )
3652   {
3653     j--;
3654
3655     if (ops[j].op == OP_PUSH)
3656     {
3657       ops[j].p_argnext = -1;
3658       ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
3659       pp->arg[arg].datap = &ops[j];
3660
3661       if (ops[j].operand[0].type == OPT_REG)
3662         *regmask |= 1 << ops[j].operand[0].reg;
3663
3664       ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
3665       ops[j].flags &= ~OPF_RSAVE;
3666
3667       // next arg
3668       for (arg++; arg < pp->argc; arg++)
3669         if (pp->arg[arg].reg == NULL)
3670           break;
3671     }
3672   }
3673
3674   return 0;
3675 }
3676
3677 static int collect_call_args_r(struct parsed_op *po, int i,
3678   struct parsed_proto *pp, int *regmask, int *save_arg_vars,
3679   int *arg_grp, int arg, int magic, int need_op_saving, int may_reuse)
3680 {
3681   struct parsed_proto *pp_tmp;
3682   struct parsed_op *po_tmp;
3683   struct label_ref *lr;
3684   int need_to_save_current;
3685   int arg_grp_current = 0;
3686   int save_args_seen = 0;
3687   int save_args;
3688   int ret = 0;
3689   int reg;
3690   char buf[32];
3691   int j, k;
3692
3693   if (i < 0) {
3694     ferr(po, "dead label encountered\n");
3695     return -1;
3696   }
3697
3698   for (; arg < pp->argc; arg++)
3699     if (pp->arg[arg].reg == NULL)
3700       break;
3701   magic = (magic & 0xffffff) | (arg << 24);
3702
3703   for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
3704   {
3705     if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
3706       if (ops[j].cc_scratch != magic) {
3707         ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
3708            pp->name);
3709         return -1;
3710       }
3711       // ok: have already been here
3712       return 0;
3713     }
3714     ops[j].cc_scratch = magic;
3715
3716     if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
3717       lr = &g_label_refs[j];
3718       if (lr->next != NULL)
3719         need_op_saving = 1;
3720       for (; lr->next; lr = lr->next) {
3721         check_i(&ops[j], lr->i);
3722         if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
3723           may_reuse = 1;
3724         ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
3725                 arg_grp, arg, magic, need_op_saving, may_reuse);
3726         if (ret < 0)
3727           return ret;
3728       }
3729
3730       check_i(&ops[j], lr->i);
3731       if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
3732         may_reuse = 1;
3733       if (j > 0 && LAST_OP(j - 1)) {
3734         // follow last branch in reverse
3735         j = lr->i;
3736         continue;
3737       }
3738       need_op_saving = 1;
3739       ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
3740                arg_grp, arg, magic, need_op_saving, may_reuse);
3741       if (ret < 0)
3742         return ret;
3743     }
3744     j--;
3745
3746     if (ops[j].op == OP_CALL)
3747     {
3748       if (pp->is_unresolved)
3749         break;
3750
3751       pp_tmp = ops[j].pp;
3752       if (pp_tmp == NULL)
3753         ferr(po, "arg collect hit unparsed call '%s'\n",
3754           ops[j].operand[0].name);
3755       if (may_reuse && pp_tmp->argc_stack > 0)
3756         ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
3757           arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
3758     }
3759     // esp adjust of 0 means we collected it before
3760     else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
3761       && (ops[j].operand[1].type != OPT_CONST
3762           || ops[j].operand[1].val != 0))
3763     {
3764       if (pp->is_unresolved)
3765         break;
3766
3767       ferr(po, "arg collect %d/%d hit esp adjust of %d\n",
3768         arg, pp->argc, ops[j].operand[1].val);
3769     }
3770     else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
3771     {
3772       if (pp->is_unresolved)
3773         break;
3774
3775       ferr(po, "arg collect %d/%d hit pop\n", arg, pp->argc);
3776     }
3777     else if (ops[j].flags & OPF_CJMP)
3778     {
3779       if (pp->is_unresolved)
3780         break;
3781
3782       may_reuse = 1;
3783     }
3784     else if (ops[j].op == OP_PUSH
3785       && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
3786     {
3787       if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
3788         break;
3789
3790       ops[j].p_argnext = -1;
3791       po_tmp = pp->arg[arg].datap;
3792       if (po_tmp != NULL)
3793         ops[j].p_argnext = po_tmp - ops;
3794       pp->arg[arg].datap = &ops[j];
3795
3796       need_to_save_current = 0;
3797       save_args = 0;
3798       reg = -1;
3799       if (ops[j].operand[0].type == OPT_REG)
3800         reg = ops[j].operand[0].reg;
3801
3802       if (!need_op_saving) {
3803         ret = scan_for_mod(&ops[j], j + 1, i, 1);
3804         need_to_save_current = (ret >= 0);
3805       }
3806       if (need_op_saving || need_to_save_current) {
3807         // mark this push as one that needs operand saving
3808         ops[j].flags &= ~OPF_RMD;
3809         if (ops[j].p_argnum == 0) {
3810           ops[j].p_argnum = arg + 1;
3811           save_args |= 1 << arg;
3812         }
3813         else if (ops[j].p_argnum < arg + 1) {
3814           // XXX: might kill valid var..
3815           //*save_arg_vars &= ~(1 << (ops[j].p_argnum - 1));
3816           ops[j].p_argnum = arg + 1;
3817           save_args |= 1 << arg;
3818         }
3819
3820         if (save_args_seen & (1 << (ops[j].p_argnum - 1))) {
3821           save_args_seen = 0;
3822           arg_grp_current++;
3823           if (arg_grp_current >= MAX_ARG_GRP)
3824             ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
3825               ops[j].p_argnum, pp->name);
3826         }
3827       }
3828       else if (ops[j].p_argnum == 0)
3829         ops[j].flags |= OPF_RMD;
3830
3831       // some PUSHes are reused by different calls on other branches,
3832       // but that can't happen if we didn't branch, so they
3833       // can be removed from future searches (handles nested calls)
3834       if (!may_reuse)
3835         ops[j].flags |= OPF_FARGNR;
3836
3837       ops[j].flags |= OPF_FARG;
3838       ops[j].flags &= ~OPF_RSAVE;
3839
3840       // check for __VALIST
3841       if (!pp->is_unresolved && pp->arg[arg].type.is_va_list) {
3842         k = -1;
3843         ret = resolve_origin(j, &ops[j].operand[0],
3844                 magic + 1, &k, NULL);
3845         if (ret == 1 && k >= 0)
3846         {
3847           if (ops[k].op == OP_LEA) {
3848             snprintf(buf, sizeof(buf), "arg_%X",
3849               g_func_pp->argc_stack * 4);
3850             if (!g_func_pp->is_vararg
3851               || strstr(ops[k].operand[1].name, buf))
3852             {
3853               ops[k].flags |= OPF_RMD | OPF_DONE;
3854               ops[j].flags |= OPF_RMD | OPF_VAPUSH;
3855               save_args &= ~(1 << arg);
3856               reg = -1;
3857             }
3858             else
3859               ferr(&ops[j], "lea va_list used, but no vararg?\n");
3860           }
3861           // check for va_list from g_func_pp arg too
3862           else if (ops[k].op == OP_MOV
3863             && is_stack_access(&ops[k], &ops[k].operand[1]))
3864           {
3865             ret = stack_frame_access(&ops[k], &ops[k].operand[1],
3866               buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
3867             if (ret >= 0) {
3868               ops[k].flags |= OPF_RMD | OPF_DONE;
3869               ops[j].flags |= OPF_RMD;
3870               ops[j].p_argpass = ret + 1;
3871               save_args &= ~(1 << arg);
3872               reg = -1;
3873             }
3874           }
3875         }
3876       }
3877
3878       *save_arg_vars |= save_args;
3879
3880       // tracking reg usage
3881       if (reg >= 0)
3882         *regmask |= 1 << reg;
3883
3884       arg++;
3885       if (!pp->is_unresolved) {
3886         // next arg
3887         for (; arg < pp->argc; arg++)
3888           if (pp->arg[arg].reg == NULL)
3889             break;
3890       }
3891       magic = (magic & 0xffffff) | (arg << 24);
3892     }
3893
3894     if (ops[j].p_arggrp > arg_grp_current) {
3895       save_args_seen = 0;
3896       arg_grp_current = ops[j].p_arggrp;
3897     }
3898     if (ops[j].p_argnum > 0)
3899       save_args_seen |= 1 << (ops[j].p_argnum - 1);
3900   }
3901
3902   if (arg < pp->argc) {
3903     ferr(po, "arg collect failed for '%s': %d/%d\n",
3904       pp->name, arg, pp->argc);
3905     return -1;
3906   }
3907
3908   if (arg_grp_current > *arg_grp)
3909     *arg_grp = arg_grp_current;
3910
3911   return arg;
3912 }
3913
3914 static int collect_call_args(struct parsed_op *po, int i,
3915   struct parsed_proto *pp, int *regmask, int *save_arg_vars,
3916   int magic)
3917 {
3918   // arg group is for cases when pushes for
3919   // multiple funcs are going on
3920   struct parsed_op *po_tmp;
3921   int save_arg_vars_current = 0;
3922   int arg_grp = 0;
3923   int ret;
3924   int a;
3925
3926   ret = collect_call_args_r(po, i, pp, regmask,
3927           &save_arg_vars_current, &arg_grp, 0, magic, 0, 0);
3928   if (ret < 0)
3929     return ret;
3930
3931   if (arg_grp != 0) {
3932     // propagate arg_grp
3933     for (a = 0; a < pp->argc; a++) {
3934       if (pp->arg[a].reg != NULL)
3935         continue;
3936
3937       po_tmp = pp->arg[a].datap;
3938       while (po_tmp != NULL) {
3939         po_tmp->p_arggrp = arg_grp;
3940         if (po_tmp->p_argnext > 0)
3941           po_tmp = &ops[po_tmp->p_argnext];
3942         else
3943           po_tmp = NULL;
3944       }
3945     }
3946   }
3947   save_arg_vars[arg_grp] |= save_arg_vars_current;
3948
3949   if (pp->is_unresolved) {
3950     pp->argc += ret;
3951     pp->argc_stack += ret;
3952     for (a = 0; a < pp->argc; a++)
3953       if (pp->arg[a].type.name == NULL)
3954         pp->arg[a].type.name = strdup("int");
3955   }
3956
3957   return ret;
3958 }
3959
3960 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
3961 {
3962   int i;
3963
3964   for (i = 0; i < pp->argc; i++)
3965     if (pp->arg[i].reg == NULL)
3966       break;
3967
3968   if (pp->argc_stack)
3969     memmove(&pp->arg[i + 1], &pp->arg[i],
3970       sizeof(pp->arg[0]) * pp->argc_stack);
3971   memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
3972   pp->arg[i].reg = strdup(reg);
3973   pp->arg[i].type.name = strdup("int");
3974   pp->argc++;
3975   pp->argc_reg++;
3976 }
3977
3978 static void output_std_flags(FILE *fout, struct parsed_op *po,
3979   int *pfomask, const char *dst_opr_text)
3980 {
3981   if (*pfomask & (1 << PFO_Z)) {
3982     fprintf(fout, "\n  cond_z = (%s%s == 0);",
3983       lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
3984     *pfomask &= ~(1 << PFO_Z);
3985   }
3986   if (*pfomask & (1 << PFO_S)) {
3987     fprintf(fout, "\n  cond_s = (%s%s < 0);",
3988       lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
3989     *pfomask &= ~(1 << PFO_S);
3990   }
3991 }
3992
3993 enum {
3994   OPP_FORCE_NORETURN = (1 << 0),
3995   OPP_SIMPLE_ARGS    = (1 << 1),
3996   OPP_ALIGN          = (1 << 2),
3997 };
3998
3999 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
4000   int flags)
4001 {
4002   const char *cconv = "";
4003
4004   if (pp->is_fastcall)
4005     cconv = "__fastcall ";
4006   else if (pp->is_stdcall && pp->argc_reg == 0)
4007     cconv = "__stdcall ";
4008
4009   fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
4010
4011   if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
4012     fprintf(fout, "noreturn ");
4013 }
4014
4015 static void output_pp(FILE *fout, const struct parsed_proto *pp,
4016   int flags)
4017 {
4018   int i;
4019
4020   fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
4021     pp->ret_type.name);
4022   if (pp->is_fptr)
4023     fprintf(fout, "(");
4024   output_pp_attrs(fout, pp, flags);
4025   if (pp->is_fptr)
4026     fprintf(fout, "*");
4027   fprintf(fout, "%s", pp->name);
4028   if (pp->is_fptr)
4029     fprintf(fout, ")");
4030
4031   fprintf(fout, "(");
4032   for (i = 0; i < pp->argc; i++) {
4033     if (i > 0)
4034       fprintf(fout, ", ");
4035     if (pp->arg[i].fptr != NULL && !(flags & OPP_SIMPLE_ARGS)) {
4036       // func pointer
4037       output_pp(fout, pp->arg[i].fptr, 0);
4038     }
4039     else if (pp->arg[i].type.is_retreg) {
4040       fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
4041     }
4042     else {
4043       fprintf(fout, "%s", pp->arg[i].type.name);
4044       if (!pp->is_fptr)
4045         fprintf(fout, " a%d", i + 1);
4046     }
4047   }
4048   if (pp->is_vararg) {
4049     if (i > 0)
4050       fprintf(fout, ", ");
4051     fprintf(fout, "...");
4052   }
4053   fprintf(fout, ")");
4054 }
4055
4056 static int get_pp_arg_regmask(const struct parsed_proto *pp)
4057 {
4058   int regmask = 0;
4059   int i, reg;
4060
4061   for (i = 0; i < pp->argc; i++) {
4062     if (pp->arg[i].reg != NULL) {
4063       reg = char_array_i(regs_r32,
4064               ARRAY_SIZE(regs_r32), pp->arg[i].reg);
4065       if (reg < 0)
4066         ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
4067           pp->arg[i].reg, pp->name);
4068       regmask |= 1 << reg;
4069     }
4070   }
4071
4072   return regmask;
4073 }
4074
4075 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
4076 {
4077   char buf1[16];
4078
4079   buf1[0] = 0;
4080   if (grp > 0)
4081     snprintf(buf1, sizeof(buf1), "%d", grp);
4082   snprintf(buf, buf_size, "s%s_a%d", buf1, num);
4083
4084   return buf;
4085 }
4086
4087 static void gen_x_cleanup(int opcnt);
4088
4089 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
4090 {
4091   struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
4092   struct parsed_opr *last_arith_dst = NULL;
4093   char buf1[256], buf2[256], buf3[256], cast[64];
4094   struct parsed_proto *pp, *pp_tmp;
4095   struct parsed_data *pd;
4096   unsigned int uval;
4097   int save_arg_vars[MAX_ARG_GRP] = { 0, };
4098   int cond_vars = 0;
4099   int need_tmp_var = 0;
4100   int need_tmp64 = 0;
4101   int had_decl = 0;
4102   int label_pending = 0;
4103   int regmask_save = 0; // regs saved/restored in this func
4104   int regmask_arg = 0;  // regs carrying function args (fastcall, etc)
4105   int regmask_now;      // temp
4106   int regmask_init = 0; // regs that need zero initialization
4107   int regmask_pp = 0;   // regs used in complex push-pop graph
4108   int regmask = 0;      // used regs
4109   int pfomask = 0;
4110   int found = 0;
4111   int depth = 0;
4112   int no_output;
4113   int i, j, l;
4114   int arg;
4115   int reg;
4116   int ret;
4117
4118   g_bp_frame = g_sp_frame = g_stack_fsz = 0;
4119   g_stack_frame_used = 0;
4120
4121   g_func_pp = proto_parse(fhdr, funcn, 0);
4122   if (g_func_pp == NULL)
4123     ferr(ops, "proto_parse failed for '%s'\n", funcn);
4124
4125   regmask_arg = get_pp_arg_regmask(g_func_pp);
4126
4127   // pass1:
4128   // - resolve all branches
4129   // - parse calls with labels
4130   resolve_branches_parse_calls(opcnt);
4131
4132   // pass2:
4133   // - handle ebp/esp frame, remove ops related to it
4134   scan_prologue_epilogue(opcnt);
4135
4136   // pass3:
4137   // - remove dead labels
4138   for (i = 0; i < opcnt; i++)
4139   {
4140     if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
4141       free(g_labels[i]);
4142       g_labels[i] = NULL;
4143     }
4144   }
4145
4146   // pass4:
4147   // - process trivial calls
4148   for (i = 0; i < opcnt; i++)
4149   {
4150     po = &ops[i];
4151     if (po->flags & (OPF_RMD|OPF_DONE))
4152       continue;
4153
4154     if (po->op == OP_CALL)
4155     {
4156       pp = process_call_early(i, opcnt, &j);
4157       if (pp != NULL) {
4158         if (!(po->flags & OPF_ATAIL))
4159           // since we know the args, try to collect them
4160           if (collect_call_args_early(po, i, pp, &regmask) != 0)
4161             pp = NULL;
4162       }
4163
4164       if (pp != NULL) {
4165         if (j >= 0) {
4166           // commit esp adjust
4167           ops[j].flags |= OPF_RMD;
4168           if (ops[j].op != OP_POP)
4169             patch_esp_adjust(&ops[j], pp->argc_stack * 4);
4170           else
4171             ops[j].flags |= OPF_DONE;
4172         }
4173
4174         if (strstr(pp->ret_type.name, "int64"))
4175           need_tmp64 = 1;
4176
4177         po->flags |= OPF_DONE;
4178       }
4179     }
4180   }
4181
4182   // pass5:
4183   // - process calls
4184   // - handle push <const>/pop pairs
4185   for (i = 0; i < opcnt; i++)
4186   {
4187     po = &ops[i];
4188     if (po->flags & (OPF_RMD|OPF_DONE))
4189       continue;
4190
4191     if (po->op == OP_CALL && !(po->flags & OPF_DONE))
4192     {
4193       pp = process_call(i, opcnt);
4194
4195       if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
4196         // since we know the args, collect them
4197         collect_call_args(po, i, pp, &regmask, save_arg_vars,
4198           i + opcnt * 2);
4199       }
4200
4201       if (strstr(pp->ret_type.name, "int64"))
4202         need_tmp64 = 1;
4203     }
4204     else if (po->op == OP_PUSH && !(po->flags & OPF_FARG)
4205       && !(po->flags & OPF_RSAVE) && po->operand[0].type == OPT_CONST)
4206         scan_for_pop_const(i, opcnt, &regmask_pp);
4207   }
4208
4209   // pass6:
4210   // - find POPs for PUSHes, rm both
4211   // - scan for STD/CLD, propagate DF
4212   // - scan for all used registers
4213   // - find flag set ops for their users
4214   // - do unreselved calls
4215   // - declare indirect functions
4216   for (i = 0; i < opcnt; i++)
4217   {
4218     po = &ops[i];
4219     if (po->flags & (OPF_RMD|OPF_DONE))
4220       continue;
4221
4222     if (po->op == OP_PUSH && (po->flags & OPF_RSAVE)) {
4223       reg = po->operand[0].reg;
4224       if (!(regmask & (1 << reg)))
4225         // not a reg save after all, rerun scan_for_pop
4226         po->flags &= ~OPF_RSAVE;
4227       else
4228         regmask_save |= 1 << reg;
4229     }
4230
4231     if (po->op == OP_PUSH && !(po->flags & OPF_FARG)
4232       && !(po->flags & OPF_RSAVE) && !g_func_pp->is_userstack)
4233     {
4234       if (po->operand[0].type == OPT_REG)
4235       {
4236         reg = po->operand[0].reg;
4237         if (reg < 0)
4238           ferr(po, "reg not set for push?\n");
4239
4240         depth = 0;
4241         ret = scan_for_pop(i + 1, opcnt,
4242                 po->operand[0].name, i + opcnt * 3, 0, &depth, 0);
4243         if (ret == 1) {
4244           if (depth > 1)
4245             ferr(po, "too much depth: %d\n", depth);
4246
4247           po->flags |= OPF_RMD;
4248           scan_for_pop(i + 1, opcnt, po->operand[0].name,
4249             i + opcnt * 4, 0, &depth, 1);
4250           continue;
4251         }
4252         ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].name, 0);
4253         if (ret == 0) {
4254           arg = OPF_RMD;
4255           if (regmask & (1 << reg)) {
4256             if (regmask_save & (1 << reg))
4257               ferr(po, "%s already saved?\n", po->operand[0].name);
4258             arg = OPF_RSAVE;
4259           }
4260           po->flags |= arg;
4261           scan_for_pop_ret(i + 1, opcnt, po->operand[0].name, arg);
4262           continue;
4263         }
4264       }
4265     }
4266
4267     if (po->op == OP_STD) {
4268       po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
4269       scan_propagate_df(i + 1, opcnt);
4270     }
4271
4272     regmask_now = po->regmask_src | po->regmask_dst;
4273     if (regmask_now & (1 << xBP)) {
4274       if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
4275         if (po->regmask_dst & (1 << xBP))
4276           // compiler decided to drop bp frame and use ebp as scratch
4277           scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
4278         else
4279           regmask_now &= ~(1 << xBP);
4280       }
4281     }
4282
4283     regmask |= regmask_now;
4284
4285     if (po->flags & OPF_CC)
4286     {
4287       int setters[16], cnt = 0, branched = 0;
4288
4289       ret = scan_for_flag_set(i, i + opcnt * 6,
4290               &branched, setters, &cnt);
4291       if (ret < 0 || cnt <= 0)
4292         ferr(po, "unable to trace flag setter(s)\n");
4293       if (cnt > ARRAY_SIZE(setters))
4294         ferr(po, "too many flag setters\n");
4295
4296       for (j = 0; j < cnt; j++)
4297       {
4298         tmp_op = &ops[setters[j]]; // flag setter
4299         pfomask = 0;
4300
4301         // to get nicer code, we try to delay test and cmp;
4302         // if we can't because of operand modification, or if we
4303         // have arith op, or branch, make it calculate flags explicitly
4304         if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
4305         {
4306           if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
4307             pfomask = 1 << po->pfo;
4308         }
4309         else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
4310           pfomask = 1 << po->pfo;
4311         }
4312         else {
4313           // see if we'll be able to handle based on op result
4314           if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
4315                && po->pfo != PFO_Z && po->pfo != PFO_S
4316                && po->pfo != PFO_P)
4317               || branched
4318               || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
4319           {
4320             pfomask = 1 << po->pfo;
4321           }
4322
4323           if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
4324             propagate_lmod(tmp_op, &tmp_op->operand[0],
4325               &tmp_op->operand[1]);
4326             if (tmp_op->operand[0].lmod == OPLM_DWORD)
4327               need_tmp64 = 1;
4328           }
4329         }
4330         if (pfomask) {
4331           tmp_op->pfomask |= pfomask;
4332           cond_vars |= pfomask;
4333         }
4334         // note: may overwrite, currently not a problem
4335         po->datap = tmp_op;
4336       }
4337
4338       if (po->op == OP_RCL || po->op == OP_RCR
4339        || po->op == OP_ADC || po->op == OP_SBB)
4340         cond_vars |= 1 << PFO_C;
4341     }
4342
4343     if (po->op == OP_CMPS || po->op == OP_SCAS) {
4344       cond_vars |= 1 << PFO_Z;
4345     }
4346     else if (po->op == OP_MUL
4347       || (po->op == OP_IMUL && po->operand_cnt == 1))
4348     {
4349       if (po->operand[0].lmod == OPLM_DWORD)
4350         need_tmp64 = 1;
4351     }
4352     else if (po->op == OP_CALL) {
4353       // note: resolved non-reg calls are OPF_DONE already
4354       pp = po->pp;
4355       if (pp == NULL)
4356         ferr(po, "NULL pp\n");
4357
4358       if (pp->is_unresolved) {
4359         int regmask_stack = 0;
4360         collect_call_args(po, i, pp, &regmask, save_arg_vars,
4361           i + opcnt * 2);
4362
4363         // this is pretty rough guess:
4364         // see ecx and edx were pushed (and not their saved versions)
4365         for (arg = 0; arg < pp->argc; arg++) {
4366           if (pp->arg[arg].reg != NULL)
4367             continue;
4368
4369           tmp_op = pp->arg[arg].datap;
4370           if (tmp_op == NULL)
4371             ferr(po, "parsed_op missing for arg%d\n", arg);
4372           if (tmp_op->p_argnum == 0 && tmp_op->operand[0].type == OPT_REG)
4373             regmask_stack |= 1 << tmp_op->operand[0].reg;
4374         }
4375
4376         if (!((regmask_stack & (1 << xCX))
4377           && (regmask_stack & (1 << xDX))))
4378         {
4379           if (pp->argc_stack != 0
4380            || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
4381           {
4382             pp_insert_reg_arg(pp, "ecx");
4383             pp->is_fastcall = 1;
4384             regmask_init |= 1 << xCX;
4385             regmask |= 1 << xCX;
4386           }
4387           if (pp->argc_stack != 0
4388            || ((regmask | regmask_arg) & (1 << xDX)))
4389           {
4390             pp_insert_reg_arg(pp, "edx");
4391             regmask_init |= 1 << xDX;
4392             regmask |= 1 << xDX;
4393           }
4394         }
4395
4396         // note: __cdecl doesn't fall into is_unresolved category
4397         if (pp->argc_stack > 0)
4398           pp->is_stdcall = 1;
4399       }
4400
4401       for (arg = 0; arg < pp->argc; arg++) {
4402         if (pp->arg[arg].reg != NULL) {
4403           reg = char_array_i(regs_r32,
4404                   ARRAY_SIZE(regs_r32), pp->arg[arg].reg);
4405           if (reg < 0)
4406             ferr(ops, "arg '%s' is not a reg?\n", pp->arg[arg].reg);
4407           if (!(regmask & (1 << reg))) {
4408             regmask_init |= 1 << reg;
4409             regmask |= 1 << reg;
4410           }
4411         }
4412       }
4413     }
4414     else if (po->op == OP_MOV && po->operand[0].pp != NULL
4415       && po->operand[1].pp != NULL)
4416     {
4417       // <var> = offset <something>
4418       if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
4419         && !IS_START(po->operand[1].name, "off_"))
4420       {
4421         if (!po->operand[0].pp->is_fptr)
4422           ferr(po, "%s not declared as fptr when it should be\n",
4423             po->operand[0].name);
4424         if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
4425           pp_print(buf1, sizeof(buf1), po->operand[0].pp);
4426           pp_print(buf2, sizeof(buf2), po->operand[1].pp);
4427           fnote(po, "var:  %s\n", buf1);
4428           fnote(po, "func: %s\n", buf2);
4429           ferr(po, "^ mismatch\n");
4430         }
4431       }
4432     }
4433     else if (po->op == OP_RET && !IS(g_func_pp->ret_type.name, "void"))
4434       regmask |= 1 << xAX;
4435     else if (po->op == OP_DIV || po->op == OP_IDIV) {
4436       // 32bit division is common, look for it
4437       if (po->op == OP_DIV)
4438         ret = scan_for_reg_clear(i, xDX);
4439       else
4440         ret = scan_for_cdq_edx(i);
4441       if (ret >= 0)
4442         po->flags |= OPF_32BIT;
4443       else
4444         need_tmp64 = 1;
4445     }
4446     else if (po->op == OP_CLD)
4447       po->flags |= OPF_RMD | OPF_DONE;
4448
4449     if (po->op == OP_RCL || po->op == OP_RCR || po->op == OP_XCHG) {
4450       need_tmp_var = 1;
4451     }
4452   }
4453
4454   // pass7:
4455   // - confirm regmask_save, it might have been reduced
4456   if (regmask_save != 0)
4457   {
4458     regmask_save = 0;
4459     for (i = 0; i < opcnt; i++) {
4460       po = &ops[i];
4461       if (po->flags & OPF_RMD)
4462         continue;
4463
4464       if (po->op == OP_PUSH && (po->flags & OPF_RSAVE))
4465         regmask_save |= 1 << po->operand[0].reg;
4466     }
4467   }
4468
4469   // output starts here
4470
4471   // define userstack size
4472   if (g_func_pp->is_userstack) {
4473     fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
4474     fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
4475     fprintf(fout, "#endif\n");
4476   }
4477
4478   // the function itself
4479   ferr_assert(ops, !g_func_pp->is_fptr);
4480   output_pp(fout, g_func_pp,
4481     (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
4482   fprintf(fout, "\n{\n");
4483
4484   // declare indirect functions
4485   for (i = 0; i < opcnt; i++) {
4486     po = &ops[i];
4487     if (po->flags & OPF_RMD)
4488       continue;
4489
4490     if (po->op == OP_CALL) {
4491       pp = po->pp;
4492       if (pp == NULL)
4493         ferr(po, "NULL pp\n");
4494
4495       if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
4496         if (pp->name[0] != 0) {
4497           memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
4498           memcpy(pp->name, "i_", 2);
4499
4500           // might be declared already
4501           found = 0;
4502           for (j = 0; j < i; j++) {
4503             if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
4504               if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
4505                 found = 1;
4506                 break;
4507               }
4508             }
4509           }
4510           if (found)
4511             continue;
4512         }
4513         else
4514           snprintf(pp->name, sizeof(pp->name), "icall%d", i);
4515
4516         fprintf(fout, "  ");
4517         output_pp(fout, pp, OPP_SIMPLE_ARGS);
4518         fprintf(fout, ";\n");
4519       }
4520     }
4521   }
4522
4523   // output LUTs/jumptables
4524   for (i = 0; i < g_func_pd_cnt; i++) {
4525     pd = &g_func_pd[i];
4526     fprintf(fout, "  static const ");
4527     if (pd->type == OPT_OFFSET) {
4528       fprintf(fout, "void *jt_%s[] =\n    { ", pd->label);
4529
4530       for (j = 0; j < pd->count; j++) {
4531         if (j > 0)
4532           fprintf(fout, ", ");
4533         fprintf(fout, "&&%s", pd->d[j].u.label);
4534       }
4535     }
4536     else {
4537       fprintf(fout, "%s %s[] =\n    { ",
4538         lmod_type_u(ops, pd->lmod), pd->label);
4539
4540       for (j = 0; j < pd->count; j++) {
4541         if (j > 0)
4542           fprintf(fout, ", ");
4543         fprintf(fout, "%u", pd->d[j].u.val);
4544       }
4545     }
4546     fprintf(fout, " };\n");
4547     had_decl = 1;
4548   }
4549
4550   // declare stack frame, va_arg
4551   if (g_stack_fsz) {
4552     fprintf(fout, "  union { u32 d[%d]; u16 w[%d]; u8 b[%d]; } sf;\n",
4553       (g_stack_fsz + 3) / 4, (g_stack_fsz + 1) / 2, g_stack_fsz);
4554     had_decl = 1;
4555   }
4556
4557   if (g_func_pp->is_userstack) {
4558     fprintf(fout, "  u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
4559     fprintf(fout, "  u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
4560     had_decl = 1;
4561   }
4562
4563   if (g_func_pp->is_vararg) {
4564     fprintf(fout, "  va_list ap;\n");
4565     had_decl = 1;
4566   }
4567
4568   // declare arg-registers
4569   for (i = 0; i < g_func_pp->argc; i++) {
4570     if (g_func_pp->arg[i].reg != NULL) {
4571       reg = char_array_i(regs_r32,
4572               ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
4573       if (regmask & (1 << reg)) {
4574         if (g_func_pp->arg[i].type.is_retreg)
4575           fprintf(fout, "  u32 %s = *r_%s;\n",
4576             g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
4577         else
4578           fprintf(fout, "  u32 %s = (u32)a%d;\n",
4579             g_func_pp->arg[i].reg, i + 1);
4580       }
4581       else {
4582         if (g_func_pp->arg[i].type.is_retreg)
4583           ferr(ops, "retreg '%s' is unused?\n",
4584             g_func_pp->arg[i].reg);
4585         fprintf(fout, "  // %s = a%d; // unused\n",
4586           g_func_pp->arg[i].reg, i + 1);
4587       }
4588       had_decl = 1;
4589     }
4590   }
4591
4592   // declare normal registers
4593   regmask_now = regmask & ~regmask_arg;
4594   regmask_now &= ~(1 << xSP);
4595   if (regmask_now & 0x00ff) {
4596     for (reg = 0; reg < 8; reg++) {
4597       if (regmask_now & (1 << reg)) {
4598         fprintf(fout, "  u32 %s", regs_r32[reg]);
4599         if (regmask_init & (1 << reg))
4600           fprintf(fout, " = 0");
4601         fprintf(fout, ";\n");
4602         had_decl = 1;
4603       }
4604     }
4605   }
4606   if (regmask_now & 0xff00) {
4607     for (reg = 8; reg < 16; reg++) {
4608       if (regmask_now & (1 << reg)) {
4609         fprintf(fout, "  mmxr %s", regs_r32[reg]);
4610         if (regmask_init & (1 << reg))
4611           fprintf(fout, " = { 0, }");
4612         fprintf(fout, ";\n");
4613         had_decl = 1;
4614       }
4615     }
4616   }
4617
4618   if (regmask_save) {
4619     for (reg = 0; reg < 8; reg++) {
4620       if (regmask_save & (1 << reg)) {
4621         fprintf(fout, "  u32 s_%s;\n", regs_r32[reg]);
4622         had_decl = 1;
4623       }
4624     }
4625   }
4626
4627   for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
4628     if (save_arg_vars[i] == 0)
4629       continue;
4630     for (reg = 0; reg < 32; reg++) {
4631       if (save_arg_vars[i] & (1 << reg)) {
4632         fprintf(fout, "  u32 %s;\n",
4633           saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
4634         had_decl = 1;
4635       }
4636     }
4637   }
4638
4639   // declare push-pop temporaries
4640   if (regmask_pp) {
4641     for (reg = 0; reg < 8; reg++) {
4642       if (regmask_pp & (1 << reg)) {
4643         fprintf(fout, "  u32 pp_%s;\n", regs_r32[reg]);
4644         had_decl = 1;
4645       }
4646     }
4647   }
4648
4649   if (cond_vars) {
4650     for (i = 0; i < 8; i++) {
4651       if (cond_vars & (1 << i)) {
4652         fprintf(fout, "  u32 cond_%s;\n", parsed_flag_op_names[i]);
4653         had_decl = 1;
4654       }
4655     }
4656   }
4657
4658   if (need_tmp_var) {
4659     fprintf(fout, "  u32 tmp;\n");
4660     had_decl = 1;
4661   }
4662
4663   if (need_tmp64) {
4664     fprintf(fout, "  u64 tmp64;\n");
4665     had_decl = 1;
4666   }
4667
4668   if (had_decl)
4669     fprintf(fout, "\n");
4670
4671   if (g_func_pp->is_vararg) {
4672     if (g_func_pp->argc_stack == 0)
4673       ferr(ops, "vararg func without stack args?\n");
4674     fprintf(fout, "  va_start(ap, a%d);\n", g_func_pp->argc);
4675   }
4676
4677   // output ops
4678   for (i = 0; i < opcnt; i++)
4679   {
4680     if (g_labels[i] != NULL) {
4681       fprintf(fout, "\n%s:\n", g_labels[i]);
4682       label_pending = 1;
4683
4684       delayed_flag_op = NULL;
4685       last_arith_dst = NULL;
4686     }
4687
4688     po = &ops[i];
4689     if (po->flags & OPF_RMD)
4690       continue;
4691
4692     no_output = 0;
4693
4694     #define assert_operand_cnt(n_) \
4695       if (po->operand_cnt != n_) \
4696         ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
4697
4698     // conditional/flag using op?
4699     if (po->flags & OPF_CC)
4700     {
4701       int is_delayed = 0;
4702
4703       tmp_op = po->datap;
4704
4705       // we go through all this trouble to avoid using parsed_flag_op,
4706       // which makes generated code much nicer
4707       if (delayed_flag_op != NULL)
4708       {
4709         out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
4710           po->pfo, po->pfo_inv);
4711         is_delayed = 1;
4712       }
4713       else if (last_arith_dst != NULL
4714         && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
4715            || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
4716            ))
4717       {
4718         out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
4719         out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
4720           last_arith_dst->lmod, buf3);
4721         is_delayed = 1;
4722       }
4723       else if (tmp_op != NULL) {
4724         // use preprocessed flag calc results
4725         if (!(tmp_op->pfomask & (1 << po->pfo)))
4726           ferr(po, "not prepared for pfo %d\n", po->pfo);
4727
4728         // note: pfo_inv was not yet applied
4729         snprintf(buf1, sizeof(buf1), "(%scond_%s)",
4730           po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
4731       }
4732       else {
4733         ferr(po, "all methods of finding comparison failed\n");
4734       }
4735  
4736       if (po->flags & OPF_JMP) {
4737         fprintf(fout, "  if %s", buf1);
4738       }
4739       else if (po->op == OP_RCL || po->op == OP_RCR
4740                || po->op == OP_ADC || po->op == OP_SBB)
4741       {
4742         if (is_delayed)
4743           fprintf(fout, "  cond_%s = %s;\n",
4744             parsed_flag_op_names[po->pfo], buf1);
4745       }
4746       else if (po->flags & OPF_DATA) { // SETcc
4747         out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
4748         fprintf(fout, "  %s = %s;", buf2, buf1);
4749       }
4750       else {
4751         ferr(po, "unhandled conditional op\n");
4752       }
4753     }
4754
4755     pfomask = po->pfomask;
4756
4757     if (po->flags & (OPF_REPZ|OPF_REPNZ)) {
4758       struct parsed_opr opr = {0,};
4759       opr.type = OPT_REG;
4760       opr.reg = xCX;
4761       opr.lmod = OPLM_DWORD;
4762       ret = try_resolve_const(i, &opr, opcnt * 7 + i, &uval);
4763
4764       if (ret != 1 || uval == 0) {
4765         // we need initial flags for ecx=0 case..
4766         if (i > 0 && ops[i - 1].op == OP_XOR
4767           && IS(ops[i - 1].operand[0].name,
4768                 ops[i - 1].operand[1].name))
4769         {
4770           fprintf(fout, "  cond_z = ");
4771           if (pfomask & (1 << PFO_C))
4772             fprintf(fout, "cond_c = ");
4773           fprintf(fout, "0;\n");
4774         }
4775         else if (last_arith_dst != NULL) {
4776           out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
4777           out_test_for_cc(buf1, sizeof(buf1), po, PFO_Z, 0,
4778             last_arith_dst->lmod, buf3);
4779           fprintf(fout, "  cond_z = %s;\n", buf1);
4780         }
4781         else
4782           ferr(po, "missing initial ZF\n");
4783       }
4784     }
4785
4786     switch (po->op)
4787     {
4788       case OP_MOV:
4789         assert_operand_cnt(2);
4790         propagate_lmod(po, &po->operand[0], &po->operand[1]);
4791         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
4792         default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
4793         fprintf(fout, "  %s = %s;", buf1,
4794             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
4795               buf3, 0));
4796         break;
4797
4798       case OP_LEA:
4799         assert_operand_cnt(2);
4800         po->operand[1].lmod = OPLM_DWORD; // always
4801         fprintf(fout, "  %s = %s;",
4802             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
4803             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
4804               NULL, 1));
4805         break;
4806
4807       case OP_MOVZX:
4808         assert_operand_cnt(2);
4809         fprintf(fout, "  %s = %s;",
4810             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
4811             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
4812         break;
4813
4814       case OP_MOVSX:
4815         assert_operand_cnt(2);
4816         switch (po->operand[1].lmod) {
4817         case OPLM_BYTE:
4818           strcpy(buf3, "(s8)");
4819           break;
4820         case OPLM_WORD:
4821           strcpy(buf3, "(s16)");
4822           break;
4823         default:
4824           ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
4825         }
4826         fprintf(fout, "  %s = %s;",
4827             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
4828             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
4829               buf3, 0));
4830         break;
4831
4832       case OP_XCHG:
4833         assert_operand_cnt(2);
4834         propagate_lmod(po, &po->operand[0], &po->operand[1]);
4835         fprintf(fout, "  tmp = %s;",
4836           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
4837         fprintf(fout, " %s = %s;",
4838           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
4839           out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
4840             default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
4841         fprintf(fout, " %s = %stmp;",
4842           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
4843           default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
4844         snprintf(g_comment, sizeof(g_comment), "xchg");
4845         break;
4846
4847       case OP_NOT:
4848         assert_operand_cnt(1);
4849         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
4850         fprintf(fout, "  %s = ~%s;", buf1, buf1);
4851         break;
4852
4853       case OP_CDQ:
4854         assert_operand_cnt(2);
4855         fprintf(fout, "  %s = (s32)%s >> 31;",
4856             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
4857             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
4858         strcpy(g_comment, "cdq");
4859         break;
4860
4861       case OP_LODS:
4862         assert_operand_cnt(3);
4863         if (po->flags & OPF_REP) {
4864           // hmh..
4865           ferr(po, "TODO\n");
4866         }
4867         else {
4868           fprintf(fout, "  eax = %sesi; esi %c= %d;",
4869             lmod_cast_u_ptr(po, po->operand[0].lmod),
4870             (po->flags & OPF_DF) ? '-' : '+',
4871             lmod_bytes(po, po->operand[0].lmod));
4872           strcpy(g_comment, "lods");
4873         }
4874         break;
4875
4876       case OP_STOS:
4877         assert_operand_cnt(3);
4878         if (po->flags & OPF_REP) {
4879           fprintf(fout, "  for (; ecx != 0; ecx--, edi %c= %d)\n",
4880             (po->flags & OPF_DF) ? '-' : '+',
4881             lmod_bytes(po, po->operand[0].lmod));
4882           fprintf(fout, "    %sedi = eax;",
4883             lmod_cast_u_ptr(po, po->operand[0].lmod));
4884           strcpy(g_comment, "rep stos");
4885         }
4886         else {
4887           fprintf(fout, "  %sedi = eax; edi %c= %d;",
4888             lmod_cast_u_ptr(po, po->operand[0].lmod),
4889             (po->flags & OPF_DF) ? '-' : '+',
4890             lmod_bytes(po, po->operand[0].lmod));
4891           strcpy(g_comment, "stos");
4892         }
4893         break;
4894
4895       case OP_MOVS:
4896         assert_operand_cnt(3);
4897         j = lmod_bytes(po, po->operand[0].lmod);
4898         strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
4899         l = (po->flags & OPF_DF) ? '-' : '+';
4900         if (po->flags & OPF_REP) {
4901           fprintf(fout,
4902             "  for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
4903             l, j, l, j);
4904           fprintf(fout,
4905             "    %sedi = %sesi;", buf1, buf1);
4906           strcpy(g_comment, "rep movs");
4907         }
4908         else {
4909           fprintf(fout, "  %sedi = %sesi; edi %c= %d; esi %c= %d;",
4910             buf1, buf1, l, j, l, j);
4911           strcpy(g_comment, "movs");
4912         }
4913         break;
4914
4915       case OP_CMPS:
4916         // repe ~ repeat while ZF=1
4917         assert_operand_cnt(3);
4918         j = lmod_bytes(po, po->operand[0].lmod);
4919         strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
4920         l = (po->flags & OPF_DF) ? '-' : '+';
4921         if (po->flags & OPF_REP) {
4922           fprintf(fout,
4923             "  for (; ecx != 0; ecx--) {\n");
4924           if (pfomask & (1 << PFO_C)) {
4925             // ugh..
4926             fprintf(fout,
4927             "    cond_c = %sesi < %sedi;\n", buf1, buf1);
4928             pfomask &= ~(1 << PFO_C);
4929           }
4930           fprintf(fout,
4931             "    cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
4932               buf1, buf1, l, j, l, j);
4933           fprintf(fout,
4934             "    if (cond_z %s 0) break;\n",
4935               (po->flags & OPF_REPZ) ? "==" : "!=");
4936           fprintf(fout,
4937             "  }");
4938           snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
4939             (po->flags & OPF_REPZ) ? "e" : "ne");
4940         }
4941         else {
4942           fprintf(fout,
4943             "  cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
4944             buf1, buf1, l, j, l, j);
4945           strcpy(g_comment, "cmps");
4946         }
4947         pfomask &= ~(1 << PFO_Z);
4948         last_arith_dst = NULL;
4949         delayed_flag_op = NULL;
4950         break;
4951
4952       case OP_SCAS:
4953         // only does ZF (for now)
4954         // repe ~ repeat while ZF=1
4955         assert_operand_cnt(3);
4956         j = lmod_bytes(po, po->operand[0].lmod);
4957         l = (po->flags & OPF_DF) ? '-' : '+';
4958         if (po->flags & OPF_REP) {
4959           fprintf(fout,
4960             "  for (; ecx != 0; ecx--) {\n");
4961           fprintf(fout,
4962             "    cond_z = (%seax == %sedi); edi %c= %d;\n",
4963               lmod_cast_u(po, po->operand[0].lmod),
4964               lmod_cast_u_ptr(po, po->operand[0].lmod), l, j);
4965           fprintf(fout,
4966             "    if (cond_z %s 0) break;\n",
4967               (po->flags & OPF_REPZ) ? "==" : "!=");
4968           fprintf(fout,
4969             "  }");
4970           snprintf(g_comment, sizeof(g_comment), "rep%s scas",
4971             (po->flags & OPF_REPZ) ? "e" : "ne");
4972         }
4973         else {
4974           fprintf(fout, "  cond_z = (%seax == %sedi); edi %c= %d;",
4975               lmod_cast_u(po, po->operand[0].lmod),
4976               lmod_cast_u_ptr(po, po->operand[0].lmod), l, j);
4977           strcpy(g_comment, "scas");
4978         }
4979         pfomask &= ~(1 << PFO_Z);
4980         last_arith_dst = NULL;
4981         delayed_flag_op = NULL;
4982         break;
4983
4984       // arithmetic w/flags
4985       case OP_AND:
4986         if (po->operand[1].type == OPT_CONST && !po->operand[1].val) {
4987           // deal with complex dst clear
4988           assert_operand_cnt(2);
4989           fprintf(fout, "  %s = %s;",
4990             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
4991             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
4992              default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
4993           output_std_flags(fout, po, &pfomask, buf1);
4994           last_arith_dst = &po->operand[0];
4995           delayed_flag_op = NULL;
4996           break;
4997         }
4998         // fallthrough
4999       case OP_OR:
5000         propagate_lmod(po, &po->operand[0], &po->operand[1]);
5001         // fallthrough
5002       dualop_arith:
5003         assert_operand_cnt(2);
5004         fprintf(fout, "  %s %s= %s;",
5005             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5006             op_to_c(po),
5007             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5008         output_std_flags(fout, po, &pfomask, buf1);
5009         last_arith_dst = &po->operand[0];
5010         delayed_flag_op = NULL;
5011         break;
5012
5013       case OP_SHL:
5014       case OP_SHR:
5015         assert_operand_cnt(2);
5016         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5017         if (pfomask & (1 << PFO_C)) {
5018           if (po->operand[1].type == OPT_CONST) {
5019             l = lmod_bytes(po, po->operand[0].lmod) * 8;
5020             j = po->operand[1].val;
5021             j %= l;
5022             if (j != 0) {
5023               if (po->op == OP_SHL)
5024                 j = l - j;
5025               else
5026                 j -= 1;
5027               fprintf(fout, "  cond_c = (%s >> %d) & 1;\n",
5028                 buf1, j);
5029             }
5030             else
5031               ferr(po, "zero shift?\n");
5032           }
5033           else
5034             ferr(po, "TODO\n");
5035           pfomask &= ~(1 << PFO_C);
5036         }
5037         fprintf(fout, "  %s %s= %s;", buf1, op_to_c(po),
5038             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5039         output_std_flags(fout, po, &pfomask, buf1);
5040         last_arith_dst = &po->operand[0];
5041         delayed_flag_op = NULL;
5042         break;
5043
5044       case OP_SAR:
5045         assert_operand_cnt(2);
5046         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5047         fprintf(fout, "  %s = %s%s >> %s;", buf1,
5048           lmod_cast_s(po, po->operand[0].lmod), buf1,
5049           out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5050         output_std_flags(fout, po, &pfomask, buf1);
5051         last_arith_dst = &po->operand[0];
5052         delayed_flag_op = NULL;
5053         break;
5054
5055       case OP_SHRD:
5056         assert_operand_cnt(3);
5057         propagate_lmod(po, &po->operand[0], &po->operand[1]);
5058         l = lmod_bytes(po, po->operand[0].lmod) * 8;
5059         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5060         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5061         out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
5062         fprintf(fout, "  %s >>= %s; %s |= %s << (%d - %s);",
5063           buf1, buf3, buf1, buf2, l, buf3);
5064         strcpy(g_comment, "shrd");
5065         output_std_flags(fout, po, &pfomask, buf1);
5066         last_arith_dst = &po->operand[0];
5067         delayed_flag_op = NULL;
5068         break;
5069
5070       case OP_ROL:
5071       case OP_ROR:
5072         assert_operand_cnt(2);
5073         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5074         if (po->operand[1].type == OPT_CONST) {
5075           j = po->operand[1].val;
5076           j %= lmod_bytes(po, po->operand[0].lmod) * 8;
5077           fprintf(fout, po->op == OP_ROL ?
5078             "  %s = (%s << %d) | (%s >> %d);" :
5079             "  %s = (%s >> %d) | (%s << %d);",
5080             buf1, buf1, j, buf1,
5081             lmod_bytes(po, po->operand[0].lmod) * 8 - j);
5082         }
5083         else
5084           ferr(po, "TODO\n");
5085         output_std_flags(fout, po, &pfomask, buf1);
5086         last_arith_dst = &po->operand[0];
5087         delayed_flag_op = NULL;
5088         break;
5089
5090       case OP_RCL:
5091       case OP_RCR:
5092         assert_operand_cnt(2);
5093         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5094         l = lmod_bytes(po, po->operand[0].lmod) * 8;
5095         if (po->operand[1].type == OPT_CONST) {
5096           j = po->operand[1].val % l;
5097           if (j == 0)
5098             ferr(po, "zero rotate\n");
5099           fprintf(fout, "  tmp = (%s >> %d) & 1;\n",
5100             buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
5101           if (po->op == OP_RCL) {
5102             fprintf(fout,
5103               "  %s = (%s << %d) | (cond_c << %d)",
5104               buf1, buf1, j, j - 1);
5105             if (j != 1)
5106               fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
5107           }
5108           else {
5109             fprintf(fout,
5110               "  %s = (%s >> %d) | (cond_c << %d)",
5111               buf1, buf1, j, l - j);
5112             if (j != 1)
5113               fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
5114           }
5115           fprintf(fout, ";\n");
5116           fprintf(fout, "  cond_c = tmp;");
5117         }
5118         else
5119           ferr(po, "TODO\n");
5120         strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
5121         output_std_flags(fout, po, &pfomask, buf1);
5122         last_arith_dst = &po->operand[0];
5123         delayed_flag_op = NULL;
5124         break;
5125
5126       case OP_XOR:
5127         assert_operand_cnt(2);
5128         propagate_lmod(po, &po->operand[0], &po->operand[1]);
5129         if (IS(opr_name(po, 0), opr_name(po, 1))) {
5130           // special case for XOR
5131           if (pfomask & (1 << PFO_BE)) { // weird, but it happens..
5132             fprintf(fout, "  cond_be = 1;\n");
5133             pfomask &= ~(1 << PFO_BE);
5134           }
5135           fprintf(fout, "  %s = 0;",
5136             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
5137           last_arith_dst = &po->operand[0];
5138           delayed_flag_op = NULL;
5139           break;
5140         }
5141         goto dualop_arith;
5142
5143       case OP_ADD:
5144         assert_operand_cnt(2);
5145         propagate_lmod(po, &po->operand[0], &po->operand[1]);
5146         if (pfomask & (1 << PFO_C)) {
5147           out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
5148           out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5149           if (po->operand[0].lmod == OPLM_DWORD) {
5150             fprintf(fout, "  tmp64 = (u64)%s + %s;\n", buf1, buf2);
5151             fprintf(fout, "  cond_c = tmp64 >> 32;\n");
5152             fprintf(fout, "  %s = (u32)tmp64;",
5153               out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
5154             strcat(g_comment, "add64");
5155           }
5156           else {
5157             fprintf(fout, "  cond_c = ((u32)%s + %s) >> %d;\n",
5158               buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
5159             fprintf(fout, "  %s += %s;",
5160               out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5161               buf2);
5162           }
5163           pfomask &= ~(1 << PFO_C);
5164           output_std_flags(fout, po, &pfomask, buf1);
5165           last_arith_dst = &po->operand[0];
5166           delayed_flag_op = NULL;
5167           break;
5168         }
5169         goto dualop_arith;
5170
5171       case OP_SUB:
5172         assert_operand_cnt(2);
5173         propagate_lmod(po, &po->operand[0], &po->operand[1]);
5174         if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
5175           for (j = 0; j <= PFO_LE; j++) {
5176             if (!(pfomask & (1 << j)))
5177               continue;
5178             if (j == PFO_Z || j == PFO_S)
5179               continue;
5180
5181             out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
5182             fprintf(fout, "  cond_%s = %s;\n",
5183               parsed_flag_op_names[j], buf1);
5184             pfomask &= ~(1 << j);
5185           }
5186         }
5187         goto dualop_arith;
5188
5189       case OP_ADC:
5190       case OP_SBB:
5191         assert_operand_cnt(2);
5192         propagate_lmod(po, &po->operand[0], &po->operand[1]);
5193         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5194         if (po->op == OP_SBB
5195           && IS(po->operand[0].name, po->operand[1].name))
5196         {
5197           // avoid use of unitialized var
5198           fprintf(fout, "  %s = -cond_c;", buf1);
5199           // carry remains what it was
5200           pfomask &= ~(1 << PFO_C);
5201         }
5202         else {
5203           fprintf(fout, "  %s %s= %s + cond_c;", buf1, op_to_c(po),
5204             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5205         }
5206         output_std_flags(fout, po, &pfomask, buf1);
5207         last_arith_dst = &po->operand[0];
5208         delayed_flag_op = NULL;
5209         break;
5210
5211       case OP_BSF:
5212         assert_operand_cnt(2);
5213         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5214         fprintf(fout, "  %s = %s ? __builtin_ffs(%s) - 1 : 0;",
5215           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5216           buf2, buf2);
5217         output_std_flags(fout, po, &pfomask, buf1);
5218         last_arith_dst = &po->operand[0];
5219         delayed_flag_op = NULL;
5220         strcat(g_comment, "bsf");
5221         break;
5222
5223       case OP_DEC:
5224         if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
5225           for (j = 0; j <= PFO_LE; j++) {
5226             if (!(pfomask & (1 << j)))
5227               continue;
5228             if (j == PFO_Z || j == PFO_S || j == PFO_C)
5229               continue;
5230
5231             out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
5232             fprintf(fout, "  cond_%s = %s;\n",
5233               parsed_flag_op_names[j], buf1);
5234             pfomask &= ~(1 << j);
5235           }
5236         }
5237         // fallthrough
5238
5239       case OP_INC:
5240         if (pfomask & (1 << PFO_C))
5241           // carry is unaffected by inc/dec.. wtf?
5242           ferr(po, "carry propagation needed\n");
5243
5244         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5245         if (po->operand[0].type == OPT_REG) {
5246           strcpy(buf2, po->op == OP_INC ? "++" : "--");
5247           fprintf(fout, "  %s%s;", buf1, buf2);
5248         }
5249         else {
5250           strcpy(buf2, po->op == OP_INC ? "+" : "-");
5251           fprintf(fout, "  %s %s= 1;", buf1, buf2);
5252         }
5253         output_std_flags(fout, po, &pfomask, buf1);
5254         last_arith_dst = &po->operand[0];
5255         delayed_flag_op = NULL;
5256         break;
5257
5258       case OP_NEG:
5259         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5260         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
5261         fprintf(fout, "  %s = -%s%s;", buf1,
5262           lmod_cast_s(po, po->operand[0].lmod), buf2);
5263         last_arith_dst = &po->operand[0];
5264         delayed_flag_op = NULL;
5265         if (pfomask & (1 << PFO_C)) {
5266           fprintf(fout, "\n  cond_c = (%s != 0);", buf1);
5267           pfomask &= ~(1 << PFO_C);
5268         }
5269         break;
5270
5271       case OP_IMUL:
5272         if (po->operand_cnt == 2) {
5273           propagate_lmod(po, &po->operand[0], &po->operand[1]);
5274           goto dualop_arith;
5275         }
5276         if (po->operand_cnt == 3)
5277           ferr(po, "TODO imul3\n");
5278         // fallthrough
5279       case OP_MUL:
5280         assert_operand_cnt(1);
5281         switch (po->operand[0].lmod) {
5282         case OPLM_DWORD:
5283           strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
5284           fprintf(fout, "  tmp64 = %seax * %s%s;\n", buf1, buf1,
5285             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
5286           fprintf(fout, "  edx = tmp64 >> 32;\n");
5287           fprintf(fout, "  eax = tmp64;");
5288           break;
5289         case OPLM_BYTE:
5290           strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
5291           fprintf(fout, "  LOWORD(eax) = %seax * %s;", buf1,
5292             out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
5293               buf1, 0));
5294           break;
5295         default:
5296           ferr(po, "TODO: unhandled mul type\n");
5297           break;
5298         }
5299         last_arith_dst = NULL;
5300         delayed_flag_op = NULL;
5301         break;
5302
5303       case OP_DIV:
5304       case OP_IDIV:
5305         assert_operand_cnt(1);
5306         if (po->operand[0].lmod != OPLM_DWORD)
5307           ferr(po, "unhandled lmod %d\n", po->operand[0].lmod);
5308
5309         out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
5310         strcpy(buf2, lmod_cast(po, po->operand[0].lmod,
5311           po->op == OP_IDIV));
5312         switch (po->operand[0].lmod) {
5313         case OPLM_DWORD:
5314           if (po->flags & OPF_32BIT)
5315             snprintf(buf3, sizeof(buf3), "%seax", buf2);
5316           else {
5317             fprintf(fout, "  tmp64 = ((u64)edx << 32) | eax;\n");
5318             snprintf(buf3, sizeof(buf3), "%stmp64",
5319               (po->op == OP_IDIV) ? "(s64)" : "");
5320           }
5321           if (po->operand[0].type == OPT_REG
5322             && po->operand[0].reg == xDX)
5323           {
5324             fprintf(fout, "  eax = %s / %s%s;", buf3, buf2, buf1);
5325             fprintf(fout, "  edx = %s %% %s%s;\n", buf3, buf2, buf1);
5326           }
5327           else {
5328             fprintf(fout, "  edx = %s %% %s%s;\n", buf3, buf2, buf1);
5329             fprintf(fout, "  eax = %s / %s%s;", buf3, buf2, buf1);
5330           }
5331           break;
5332         default:
5333           ferr(po, "unhandled division type\n");
5334         }
5335         last_arith_dst = NULL;
5336         delayed_flag_op = NULL;
5337         break;
5338
5339       case OP_TEST:
5340       case OP_CMP:
5341         propagate_lmod(po, &po->operand[0], &po->operand[1]);
5342         if (pfomask != 0) {
5343           for (j = 0; j < 8; j++) {
5344             if (pfomask & (1 << j)) {
5345               out_cmp_test(buf1, sizeof(buf1), po, j, 0);
5346               fprintf(fout, "  cond_%s = %s;",
5347                 parsed_flag_op_names[j], buf1);
5348             }
5349           }
5350           pfomask = 0;
5351         }
5352         else
5353           no_output = 1;
5354         last_arith_dst = NULL;
5355         delayed_flag_op = po;
5356         break;
5357
5358       case OP_SCC:
5359         // SETcc - should already be handled
5360         break;
5361
5362       // note: we reuse OP_Jcc for SETcc, only flags differ
5363       case OP_JCC:
5364         fprintf(fout, "\n    goto %s;", po->operand[0].name);
5365         break;
5366
5367       case OP_JECXZ:
5368         fprintf(fout, "  if (ecx == 0)\n");
5369         fprintf(fout, "    goto %s;", po->operand[0].name);
5370         strcat(g_comment, "jecxz");
5371         break;
5372
5373       case OP_JMP:
5374         assert_operand_cnt(1);
5375         last_arith_dst = NULL;
5376         delayed_flag_op = NULL;
5377
5378         if (po->operand[0].type == OPT_REGMEM) {
5379           ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
5380                   buf1, buf2);
5381           if (ret != 2)
5382             ferr(po, "parse failure for jmp '%s'\n",
5383               po->operand[0].name);
5384           fprintf(fout, "  goto *jt_%s[%s];", buf1, buf2);
5385           break;
5386         }
5387         else if (po->operand[0].type != OPT_LABEL)
5388           ferr(po, "unhandled jmp type\n");
5389
5390         fprintf(fout, "  goto %s;", po->operand[0].name);
5391         break;
5392
5393       case OP_CALL:
5394         assert_operand_cnt(1);
5395         pp = po->pp;
5396         my_assert_not(pp, NULL);
5397
5398         strcpy(buf3, "  ");
5399         if (po->flags & OPF_CC) {
5400           // we treat conditional branch to another func
5401           // (yes such code exists..) as conditional tailcall
5402           strcat(buf3, "  ");
5403           fprintf(fout, " {\n");
5404         }
5405
5406         if (pp->is_fptr && !pp->is_arg) {
5407           fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
5408             out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
5409               "(void *)", 0));
5410           if (pp->is_unresolved)
5411             fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
5412               buf3, asmfn, po->asmln, pp->name);
5413         }
5414
5415         fprintf(fout, "%s", buf3);
5416         if (strstr(pp->ret_type.name, "int64")) {
5417           if (po->flags & OPF_TAIL)
5418             ferr(po, "int64 and tail?\n");
5419           fprintf(fout, "tmp64 = ");
5420         }
5421         else if (!IS(pp->ret_type.name, "void")) {
5422           if (po->flags & OPF_TAIL) {
5423             if (!IS(g_func_pp->ret_type.name, "void")) {
5424               fprintf(fout, "return ");
5425               if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
5426                 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
5427             }
5428           }
5429           else if (regmask & (1 << xAX)) {
5430             fprintf(fout, "eax = ");
5431             if (pp->ret_type.is_ptr)
5432               fprintf(fout, "(u32)");
5433           }
5434         }
5435
5436         if (pp->name[0] == 0)
5437           ferr(po, "missing pp->name\n");
5438         fprintf(fout, "%s%s(", pp->name,
5439           pp->has_structarg ? "_sa" : "");
5440
5441         if (po->flags & OPF_ATAIL) {
5442           if (pp->argc_stack != g_func_pp->argc_stack
5443             || (pp->argc_stack > 0
5444                 && pp->is_stdcall != g_func_pp->is_stdcall))
5445             ferr(po, "incompatible tailcall\n");
5446           if (g_func_pp->has_retreg)
5447             ferr(po, "TODO: retreg+tailcall\n");
5448
5449           for (arg = j = 0; arg < pp->argc; arg++) {
5450             if (arg > 0)
5451               fprintf(fout, ", ");
5452
5453             cast[0] = 0;
5454             if (pp->arg[arg].type.is_ptr)
5455               snprintf(cast, sizeof(cast), "(%s)",
5456                 pp->arg[arg].type.name);
5457
5458             if (pp->arg[arg].reg != NULL) {
5459               fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
5460               continue;
5461             }
5462             // stack arg
5463             for (; j < g_func_pp->argc; j++)
5464               if (g_func_pp->arg[j].reg == NULL)
5465                 break;
5466             fprintf(fout, "%sa%d", cast, j + 1);
5467             j++;
5468           }
5469         }
5470         else {
5471           for (arg = 0; arg < pp->argc; arg++) {
5472             if (arg > 0)
5473               fprintf(fout, ", ");
5474
5475             cast[0] = 0;
5476             if (pp->arg[arg].type.is_ptr)
5477               snprintf(cast, sizeof(cast), "(%s)",
5478                 pp->arg[arg].type.name);
5479
5480             if (pp->arg[arg].reg != NULL) {
5481               if (pp->arg[arg].type.is_retreg)
5482                 fprintf(fout, "&%s", pp->arg[arg].reg);
5483               else
5484                 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
5485               continue;
5486             }
5487
5488             // stack arg
5489             tmp_op = pp->arg[arg].datap;
5490             if (tmp_op == NULL)
5491               ferr(po, "parsed_op missing for arg%d\n", arg);
5492
5493             if (tmp_op->flags & OPF_VAPUSH) {
5494               fprintf(fout, "ap");
5495             }
5496             else if (tmp_op->p_argpass != 0) {
5497               fprintf(fout, "a%d", tmp_op->p_argpass);
5498             }
5499             else if (tmp_op->p_argnum != 0) {
5500               fprintf(fout, "%s%s", cast,
5501                 saved_arg_name(buf1, sizeof(buf1),
5502                   tmp_op->p_arggrp, tmp_op->p_argnum));
5503             }
5504             else {
5505               fprintf(fout, "%s",
5506                 out_src_opr(buf1, sizeof(buf1),
5507                   tmp_op, &tmp_op->operand[0], cast, 0));
5508             }
5509           }
5510         }
5511         fprintf(fout, ");");
5512
5513         if (strstr(pp->ret_type.name, "int64")) {
5514           fprintf(fout, "\n");
5515           fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
5516           fprintf(fout, "%seax = tmp64;", buf3);
5517         }
5518
5519         if (pp->is_unresolved) {
5520           snprintf(buf2, sizeof(buf2), " unresolved %dreg",
5521             pp->argc_reg);
5522           strcat(g_comment, buf2);
5523         }
5524
5525         if (po->flags & OPF_TAIL) {
5526           ret = 0;
5527           if (i == opcnt - 1 || pp->is_noreturn)
5528             ret = 0;
5529           else if (IS(pp->ret_type.name, "void"))
5530             ret = 1;
5531           else if (IS(g_func_pp->ret_type.name, "void"))
5532             ret = 1;
5533           // else already handled as 'return f()'
5534
5535           if (ret) {
5536             if (!IS(g_func_pp->ret_type.name, "void")) {
5537               ferr(po, "int func -> void func tailcall?\n");
5538             }
5539             else {
5540               fprintf(fout, "\n%sreturn;", buf3);
5541               strcat(g_comment, " ^ tailcall");
5542             }
5543           }
5544           else
5545             strcat(g_comment, " tailcall");
5546         }
5547         if (pp->is_noreturn)
5548           strcat(g_comment, " noreturn");
5549         if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
5550           strcat(g_comment, " argframe");
5551         if (po->flags & OPF_CC)
5552           strcat(g_comment, " cond");
5553
5554         if (po->flags & OPF_CC)
5555           fprintf(fout, "\n  }");
5556
5557         delayed_flag_op = NULL;
5558         last_arith_dst = NULL;
5559         break;
5560
5561       case OP_RET:
5562         if (g_func_pp->is_vararg)
5563           fprintf(fout, "  va_end(ap);\n");
5564         if (g_func_pp->has_retreg) {
5565           for (arg = 0; arg < g_func_pp->argc; arg++)
5566             if (g_func_pp->arg[arg].type.is_retreg)
5567               fprintf(fout, "  *r_%s = %s;\n",
5568                 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
5569         }
5570  
5571         if (IS(g_func_pp->ret_type.name, "void")) {
5572           if (i != opcnt - 1 || label_pending)
5573             fprintf(fout, "  return;");
5574         }
5575         else if (g_func_pp->ret_type.is_ptr) {
5576           fprintf(fout, "  return (%s)eax;",
5577             g_func_pp->ret_type.name);
5578         }
5579         else if (IS(g_func_pp->ret_type.name, "__int64"))
5580           fprintf(fout, "  return ((u64)edx << 32) | eax;");
5581         else
5582           fprintf(fout, "  return eax;");
5583
5584         last_arith_dst = NULL;
5585         delayed_flag_op = NULL;
5586         break;
5587
5588       case OP_PUSH:
5589         out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
5590         if (po->p_argnum != 0) {
5591           // special case - saved func arg
5592           fprintf(fout, "  %s = %s;",
5593             saved_arg_name(buf2, sizeof(buf2),
5594               po->p_arggrp, po->p_argnum), buf1);
5595           break;
5596         }
5597         else if (po->flags & OPF_RSAVE) {
5598           fprintf(fout, "  s_%s = %s;", buf1, buf1);
5599           break;
5600         }
5601         else if (po->flags & OPF_PPUSH) {
5602           tmp_op = po->datap;
5603           ferr_assert(po, tmp_op != NULL);
5604           out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
5605           fprintf(fout, "  pp_%s = %s;", buf2, buf1);
5606           break;
5607         }
5608         else if (g_func_pp->is_userstack) {
5609           fprintf(fout, "  *(--esp) = %s;", buf1);
5610           break;
5611         }
5612         if (!(g_ida_func_attr & IDAFA_NORETURN))
5613           ferr(po, "stray push encountered\n");
5614         no_output = 1;
5615         break;
5616
5617       case OP_POP:
5618         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5619         if (po->flags & OPF_RSAVE) {
5620           fprintf(fout, "  %s = s_%s;", buf1, buf1);
5621           break;
5622         }
5623         else if (po->flags & OPF_PPUSH) {
5624           // push/pop graph
5625           ferr_assert(po, po->datap == NULL);
5626           fprintf(fout, "  %s = pp_%s;", buf1, buf1);
5627           break;
5628         }
5629         else if (po->datap != NULL) {
5630           // push/pop pair
5631           tmp_op = po->datap;
5632           fprintf(fout, "  %s = %s;", buf1,
5633             out_src_opr(buf2, sizeof(buf2),
5634               tmp_op, &tmp_op->operand[0],
5635               default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5636           break;
5637         }
5638         else if (g_func_pp->is_userstack) {
5639           fprintf(fout, "  %s = *esp++;", buf1);
5640           break;
5641         }
5642         else
5643           ferr(po, "stray pop encountered\n");
5644         break;
5645
5646       case OP_NOP:
5647         no_output = 1;
5648         break;
5649
5650       // mmx
5651       case OP_EMMS:
5652         strcpy(g_comment, "(emms)");
5653         break;
5654
5655       default:
5656         no_output = 1;
5657         ferr(po, "unhandled op type %d, flags %x\n",
5658           po->op, po->flags);
5659         break;
5660     }
5661
5662     if (g_comment[0] != 0) {
5663       char *p = g_comment;
5664       while (my_isblank(*p))
5665         p++;
5666       fprintf(fout, "  // %s", p);
5667       g_comment[0] = 0;
5668       no_output = 0;
5669     }
5670     if (!no_output)
5671       fprintf(fout, "\n");
5672
5673     // some sanity checking
5674     if (po->flags & OPF_REP) {
5675       if (po->op != OP_STOS && po->op != OP_MOVS
5676           && po->op != OP_CMPS && po->op != OP_SCAS)
5677         ferr(po, "unexpected rep\n");
5678       if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
5679           && (po->op == OP_CMPS || po->op == OP_SCAS))
5680         ferr(po, "cmps/scas with plain rep\n");
5681     }
5682     if ((po->flags & (OPF_REPZ|OPF_REPNZ))
5683         && po->op != OP_CMPS && po->op != OP_SCAS)
5684       ferr(po, "unexpected repz/repnz\n");
5685
5686     if (pfomask != 0)
5687       ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
5688
5689     // see is delayed flag stuff is still valid
5690     if (delayed_flag_op != NULL && delayed_flag_op != po) {
5691       if (is_any_opr_modified(delayed_flag_op, po, 0))
5692         delayed_flag_op = NULL;
5693     }
5694
5695     if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
5696       if (is_opr_modified(last_arith_dst, po))
5697         last_arith_dst = NULL;
5698     }
5699
5700     label_pending = 0;
5701   }
5702
5703   if (g_stack_fsz && !g_stack_frame_used)
5704     fprintf(fout, "  (void)sf;\n");
5705
5706   fprintf(fout, "}\n\n");
5707
5708   gen_x_cleanup(opcnt);
5709 }
5710
5711 static void gen_x_cleanup(int opcnt)
5712 {
5713   int i;
5714
5715   for (i = 0; i < opcnt; i++) {
5716     struct label_ref *lr, *lr_del;
5717
5718     lr = g_label_refs[i].next;
5719     while (lr != NULL) {
5720       lr_del = lr;
5721       lr = lr->next;
5722       free(lr_del);
5723     }
5724     g_label_refs[i].i = -1;
5725     g_label_refs[i].next = NULL;
5726
5727     if (ops[i].op == OP_CALL) {
5728       if (ops[i].pp)
5729         proto_release(ops[i].pp);
5730     }
5731   }
5732   g_func_pp = NULL;
5733 }
5734
5735 struct func_proto_dep;
5736
5737 struct func_prototype {
5738   char name[NAMELEN];
5739   int id;
5740   int argc_stack;
5741   int regmask_dep;
5742   int has_ret:3;                 // -1, 0, 1: unresolved, no, yes
5743   unsigned int dep_resolved:1;
5744   unsigned int is_stdcall:1;
5745   struct func_proto_dep *dep_func;
5746   int dep_func_cnt;
5747   const struct parsed_proto *pp; // seed pp, if any
5748 };
5749
5750 struct func_proto_dep {
5751   char *name;
5752   struct func_prototype *proto;
5753   int regmask_live;             // .. at the time of call
5754   unsigned int ret_dep:1;       // return from this is caller's return
5755 };
5756
5757 static struct func_prototype *hg_fp;
5758 static int hg_fp_cnt;
5759
5760 static struct scanned_var {
5761   char name[NAMELEN];
5762   enum opr_lenmod lmod;
5763   unsigned int is_seeded:1;
5764   unsigned int is_c_str:1;
5765   const struct parsed_proto *pp; // seed pp, if any
5766 } *hg_vars;
5767 static int hg_var_cnt;
5768
5769 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
5770   int count);
5771
5772 struct func_prototype *hg_fp_add(const char *funcn)
5773 {
5774   struct func_prototype *fp;
5775
5776   if ((hg_fp_cnt & 0xff) == 0) {
5777     hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
5778     my_assert_not(hg_fp, NULL);
5779     memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
5780   }
5781
5782   fp = &hg_fp[hg_fp_cnt];
5783   snprintf(fp->name, sizeof(fp->name), "%s", funcn);
5784   fp->id = hg_fp_cnt;
5785   fp->argc_stack = -1;
5786   hg_fp_cnt++;
5787
5788   return fp;
5789 }
5790
5791 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
5792   const char *name)
5793 {
5794   int i;
5795
5796   for (i = 0; i < fp->dep_func_cnt; i++)
5797     if (IS(fp->dep_func[i].name, name))
5798       return &fp->dep_func[i];
5799
5800   return NULL;
5801 }
5802
5803 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
5804 {
5805   // is it a dupe?
5806   if (hg_fp_find_dep(fp, name))
5807     return;
5808
5809   if ((fp->dep_func_cnt & 0xff) == 0) {
5810     fp->dep_func = realloc(fp->dep_func,
5811       sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
5812     my_assert_not(fp->dep_func, NULL);
5813     memset(&fp->dep_func[fp->dep_func_cnt], 0,
5814       sizeof(fp->dep_func[0]) * 0x100);
5815   }
5816   fp->dep_func[fp->dep_func_cnt].name = strdup(name);
5817   fp->dep_func_cnt++;
5818 }
5819
5820 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
5821 {
5822   const struct func_prototype *p1 = p1_, *p2 = p2_;
5823   return strcmp(p1->name, p2->name);
5824 }
5825
5826 #if 0
5827 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
5828 {
5829   const struct func_prototype *p1 = p1_, *p2 = p2_;
5830   return p1->id - p2->id;
5831 }
5832 #endif
5833
5834 // recursive register dep pass
5835 // - track saved regs (part 2)
5836 // - try to figure out arg-regs
5837 // - calculate reg deps
5838 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
5839   struct func_prototype *fp, int regmask_save, int regmask_dst,
5840   int *regmask_dep, int *has_ret)
5841 {
5842   struct func_proto_dep *dep;
5843   struct parsed_op *po;
5844   int from_caller = 0;
5845   int depth;
5846   int j, l;
5847   int reg;
5848   int ret;
5849
5850   for (; i < opcnt; i++)
5851   {
5852     if (cbits[i >> 3] & (1 << (i & 7)))
5853       return;
5854     cbits[i >> 3] |= (1 << (i & 7));
5855
5856     po = &ops[i];
5857
5858     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5859       if (po->btj != NULL) {
5860         // jumptable
5861         for (j = 0; j < po->btj->count; j++) {
5862           check_i(po, po->btj->d[j].bt_i);
5863           gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
5864             regmask_save, regmask_dst, regmask_dep, has_ret);
5865         }
5866         return;
5867       }
5868
5869       check_i(po, po->bt_i);
5870       if (po->flags & OPF_CJMP) {
5871         gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
5872           regmask_save, regmask_dst, regmask_dep, has_ret);
5873       }
5874       else {
5875         i = po->bt_i - 1;
5876       }
5877       continue;
5878     }
5879
5880     if (po->flags & OPF_FARG)
5881       /* (just calculate register deps) */;
5882     else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
5883     {
5884       reg = po->operand[0].reg;
5885       if (reg < 0)
5886         ferr(po, "reg not set for push?\n");
5887
5888       if (po->flags & OPF_RSAVE) {
5889         regmask_save |= 1 << reg;
5890         continue;
5891       }
5892       if (po->flags & OPF_DONE)
5893         continue;
5894
5895       depth = 0;
5896       ret = scan_for_pop(i + 1, opcnt,
5897               po->operand[0].name, i + opcnt * 2, 0, &depth, 0);
5898       if (ret == 1) {
5899         regmask_save |= 1 << reg;
5900         po->flags |= OPF_RMD;
5901         scan_for_pop(i + 1, opcnt,
5902           po->operand[0].name, i + opcnt * 3, 0, &depth, 1);
5903         continue;
5904       }
5905     }
5906     else if (po->flags & OPF_RMD)
5907       continue;
5908     else if (po->op == OP_CALL) {
5909       po->regmask_dst |= 1 << xAX;
5910
5911       dep = hg_fp_find_dep(fp, po->operand[0].name);
5912       if (dep != NULL)
5913         dep->regmask_live = regmask_save | regmask_dst;
5914     }
5915     else if (po->op == OP_RET) {
5916       if (po->operand_cnt > 0) {
5917         fp->is_stdcall = 1;
5918         if (fp->argc_stack >= 0
5919             && fp->argc_stack != po->operand[0].val / 4)
5920           ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
5921         fp->argc_stack = po->operand[0].val / 4;
5922       }
5923     }
5924
5925     // if has_ret is 0, there is uninitialized eax path,
5926     // which means it's most likely void func
5927     if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
5928       if (po->op == OP_CALL) {
5929         j = i;
5930         ret = 1;
5931       }
5932       else {
5933         struct parsed_opr opr = { 0, };
5934         opr.type = OPT_REG;
5935         opr.reg = xAX;
5936         j = -1;
5937         from_caller = 0;
5938         ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
5939       }
5940
5941       if (ret != 1 && from_caller) {
5942         // unresolved eax - probably void func
5943         *has_ret = 0;
5944       }
5945       else {
5946         if (j >= 0 && ops[j].op == OP_CALL) {
5947           dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
5948           if (dep != NULL)
5949             dep->ret_dep = 1;
5950           else
5951             *has_ret = 1;
5952         }
5953         else
5954           *has_ret = 1;
5955       }
5956     }
5957
5958     l = regmask_save | regmask_dst;
5959     if (g_bp_frame && !(po->flags & OPF_EBP_S))
5960       l |= 1 << xBP;
5961
5962     l = po->regmask_src & ~l;
5963 #if 0
5964     if (l)
5965       fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
5966         l, regmask_dst, regmask_save, po->flags);
5967 #endif
5968     *regmask_dep |= l;
5969     regmask_dst |= po->regmask_dst;
5970
5971     if (po->flags & OPF_TAIL)
5972       return;
5973   }
5974 }
5975
5976 static void gen_hdr(const char *funcn, int opcnt)
5977 {
5978   int save_arg_vars[MAX_ARG_GRP] = { 0, };
5979   unsigned char cbits[MAX_OPS / 8];
5980   const struct parsed_proto *pp_c;
5981   struct parsed_proto *pp;
5982   struct func_prototype *fp;
5983   struct parsed_op *po;
5984   int regmask_dummy = 0;
5985   int regmask_dep;
5986   int max_bp_offset = 0;
5987   int has_ret;
5988   int i, j, ret;
5989
5990   pp_c = proto_parse(g_fhdr, funcn, 1);
5991   if (pp_c != NULL)
5992     // already in seed, will add to hg_fp later
5993     return;
5994
5995   fp = hg_fp_add(funcn);
5996
5997   g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5998   g_stack_frame_used = 0;
5999
6000   // pass1:
6001   // - resolve all branches
6002   // - parse calls with labels
6003   resolve_branches_parse_calls(opcnt);
6004
6005   // pass2:
6006   // - handle ebp/esp frame, remove ops related to it
6007   scan_prologue_epilogue(opcnt);
6008
6009   // pass3:
6010   // - remove dead labels
6011   // - collect calls
6012   for (i = 0; i < opcnt; i++)
6013   {
6014     if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
6015       free(g_labels[i]);
6016       g_labels[i] = NULL;
6017     }
6018
6019     po = &ops[i];
6020     if (po->flags & (OPF_RMD|OPF_DONE))
6021       continue;
6022
6023     if (po->op == OP_CALL) {
6024       if (po->operand[0].type == OPT_LABEL)
6025         hg_fp_add_dep(fp, opr_name(po, 0));
6026       else if (po->pp != NULL)
6027         hg_fp_add_dep(fp, po->pp->name);
6028     }
6029   }
6030
6031   // pass4:
6032   // - remove dead labels
6033   // - handle push <const>/pop pairs
6034   for (i = 0; i < opcnt; i++)
6035   {
6036     if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
6037       free(g_labels[i]);
6038       g_labels[i] = NULL;
6039     }
6040
6041     po = &ops[i];
6042     if (po->flags & (OPF_RMD|OPF_DONE))
6043       continue;
6044
6045     if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
6046       scan_for_pop_const(i, opcnt, &regmask_dummy);
6047   }
6048
6049   // pass5:
6050   // - process trivial calls
6051   for (i = 0; i < opcnt; i++)
6052   {
6053     po = &ops[i];
6054     if (po->flags & (OPF_RMD|OPF_DONE))
6055       continue;
6056
6057     if (po->op == OP_CALL)
6058     {
6059       pp = process_call_early(i, opcnt, &j);
6060       if (pp != NULL) {
6061         if (!(po->flags & OPF_ATAIL))
6062           // since we know the args, try to collect them
6063           if (collect_call_args_early(po, i, pp, &regmask_dummy) != 0)
6064             pp = NULL;
6065       }
6066
6067       if (pp != NULL) {
6068         if (j >= 0) {
6069           // commit esp adjust
6070           ops[j].flags |= OPF_RMD;
6071           if (ops[j].op != OP_POP)
6072             patch_esp_adjust(&ops[j], pp->argc_stack * 4);
6073           else
6074             ops[j].flags |= OPF_DONE;
6075         }
6076
6077         po->flags |= OPF_DONE;
6078       }
6079     }
6080   }
6081
6082   // pass6:
6083   // - track saved regs (simple)
6084   // - process calls
6085   for (i = 0; i < opcnt; i++)
6086   {
6087     po = &ops[i];
6088     if (po->flags & (OPF_RMD|OPF_DONE))
6089       continue;
6090
6091     if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
6092     {
6093       ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].name, 0);
6094       if (ret == 0) {
6095         // regmask_save |= 1 << po->operand[0].reg; // do it later
6096         po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
6097         scan_for_pop_ret(i + 1, opcnt, po->operand[0].name, OPF_RMD);
6098       }
6099     }
6100     else if (po->op == OP_CALL && !(po->flags & OPF_DONE))
6101     {
6102       pp = process_call(i, opcnt);
6103
6104       if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
6105         // since we know the args, collect them
6106         ret = collect_call_args(po, i, pp, &regmask_dummy, save_arg_vars,
6107           i + opcnt * 1);
6108       }
6109     }
6110   }
6111
6112   // pass7
6113   memset(cbits, 0, sizeof(cbits));
6114   regmask_dep = 0;
6115   has_ret = -1;
6116
6117   gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, &regmask_dep, &has_ret);
6118
6119   // find unreachable code - must be fixed in IDA
6120   for (i = 0; i < opcnt; i++)
6121   {
6122     if (cbits[i >> 3] & (1 << (i & 7)))
6123       continue;
6124
6125     if (ops[i].op != OP_NOP)
6126       ferr(&ops[i], "unreachable code\n");
6127   }
6128
6129   for (i = 0; i < g_eqcnt; i++) {
6130     if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
6131       max_bp_offset = g_eqs[i].offset;
6132   }
6133
6134   if (fp->argc_stack < 0) {
6135     max_bp_offset = (max_bp_offset + 3) & ~3;
6136     fp->argc_stack = max_bp_offset / 4;
6137     if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
6138       fp->argc_stack--;
6139   }
6140
6141   fp->regmask_dep = regmask_dep & ~(1 << xSP);
6142   fp->has_ret = has_ret;
6143 #if 0
6144   printf("// has_ret %d, regmask_dep %x\n",
6145     fp->has_ret, fp->regmask_dep);
6146   output_hdr_fp(stdout, fp, 1);
6147   if (IS(funcn, "sub_10007F72")) exit(1);
6148 #endif
6149
6150   gen_x_cleanup(opcnt);
6151 }
6152
6153 static void hg_fp_resolve_deps(struct func_prototype *fp)
6154 {
6155   struct func_prototype fp_s;
6156   int dep;
6157   int i;
6158
6159   // this thing is recursive, so mark first..
6160   fp->dep_resolved = 1;
6161
6162   for (i = 0; i < fp->dep_func_cnt; i++) {
6163     strcpy(fp_s.name, fp->dep_func[i].name);
6164     fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
6165       sizeof(hg_fp[0]), hg_fp_cmp_name);
6166     if (fp->dep_func[i].proto != NULL) {
6167       if (!fp->dep_func[i].proto->dep_resolved)
6168         hg_fp_resolve_deps(fp->dep_func[i].proto);
6169
6170       dep = ~fp->dep_func[i].regmask_live
6171            & fp->dep_func[i].proto->regmask_dep;
6172       fp->regmask_dep |= dep;
6173       // printf("dep %s %s |= %x\n", fp->name,
6174       //   fp->dep_func[i].name, dep);
6175
6176       if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
6177         fp->has_ret = fp->dep_func[i].proto->has_ret;
6178     }
6179   }
6180 }
6181
6182 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
6183   int count)
6184 {
6185   const struct parsed_proto *pp;
6186   char *p, namebuf[NAMELEN];
6187   const char *name;
6188   int regmask_dep;
6189   int argc_stack;
6190   int j, arg;
6191
6192   for (; count > 0; count--, fp++) {
6193     if (fp->has_ret == -1)
6194       fprintf(fout, "// ret unresolved\n");
6195 #if 0
6196     fprintf(fout, "// dep:");
6197     for (j = 0; j < fp->dep_func_cnt; j++) {
6198       fprintf(fout, " %s/", fp->dep_func[j].name);
6199       if (fp->dep_func[j].proto != NULL)
6200         fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
6201           fp->dep_func[j].proto->has_ret);
6202     }
6203     fprintf(fout, "\n");
6204 #endif
6205
6206     p = strchr(fp->name, '@');
6207     if (p != NULL) {
6208       memcpy(namebuf, fp->name, p - fp->name);
6209       namebuf[p - fp->name] = 0;
6210       name = namebuf;
6211     }
6212     else
6213       name = fp->name;
6214     if (name[0] == '_')
6215       name++;
6216
6217     pp = proto_parse(g_fhdr, name, 1);
6218     if (pp != NULL && pp->is_include)
6219       continue;
6220
6221     if (fp->pp != NULL) {
6222       // part of seed, output later
6223       continue;
6224     }
6225
6226     regmask_dep = fp->regmask_dep;
6227     argc_stack = fp->argc_stack;
6228
6229     fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
6230       (fp->has_ret ? "int" : "void"));
6231     if (regmask_dep && (fp->is_stdcall || argc_stack == 0)
6232       && (regmask_dep & ~((1 << xCX) | (1 << xDX))) == 0)
6233     {
6234       fprintf(fout, "  __fastcall    ");
6235       if (!(regmask_dep & (1 << xDX)) && argc_stack == 0)
6236         argc_stack = 1;
6237       else
6238         argc_stack += 2;
6239       regmask_dep = 0;
6240     }
6241     else if (regmask_dep && !fp->is_stdcall) {
6242       fprintf(fout, "/*__usercall*/  ");
6243     }
6244     else if (regmask_dep) {
6245       fprintf(fout, "/*__userpurge*/ ");
6246     }
6247     else if (fp->is_stdcall)
6248       fprintf(fout, "  __stdcall     ");
6249     else
6250       fprintf(fout, "  __cdecl       ");
6251
6252     fprintf(fout, "%s(", name);
6253
6254     arg = 0;
6255     for (j = 0; j < xSP; j++) {
6256       if (regmask_dep & (1 << j)) {
6257         arg++;
6258         if (arg != 1)
6259           fprintf(fout, ", ");
6260         if (fp->pp != NULL)
6261           fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
6262         else
6263           fprintf(fout, "int");
6264         fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
6265       }
6266     }
6267
6268     for (j = 0; j < argc_stack; j++) {
6269       arg++;
6270       if (arg != 1)
6271         fprintf(fout, ", ");
6272       if (fp->pp != NULL) {
6273         fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
6274         if (!fp->pp->arg[arg - 1].type.is_ptr)
6275           fprintf(fout, " ");
6276       }
6277       else
6278         fprintf(fout, "int ");
6279       fprintf(fout, "a%d", arg);
6280     }
6281
6282     fprintf(fout, ");\n");
6283   }
6284 }
6285
6286 static void output_hdr(FILE *fout)
6287 {
6288   static const char *lmod_c_names[] = {
6289     [OPLM_UNSPEC] = "???",
6290     [OPLM_BYTE]  = "uint8_t",
6291     [OPLM_WORD]  = "uint16_t",
6292     [OPLM_DWORD] = "uint32_t",
6293     [OPLM_QWORD] = "uint64_t",
6294   };
6295   const struct scanned_var *var;
6296   struct func_prototype *fp;
6297   char line[256] = { 0, };
6298   char name[256];
6299   int i;
6300
6301   // add stuff from headers
6302   for (i = 0; i < pp_cache_size; i++) {
6303     if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
6304       snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
6305     else
6306       snprintf(name, sizeof(name), "%s", pp_cache[i].name);
6307     fp = hg_fp_add(name);
6308     fp->pp = &pp_cache[i];
6309     fp->argc_stack = fp->pp->argc_stack;
6310     fp->is_stdcall = fp->pp->is_stdcall;
6311     fp->regmask_dep = get_pp_arg_regmask(fp->pp);
6312     fp->has_ret = !IS(fp->pp->ret_type.name, "void");
6313   }
6314
6315   // resolve deps
6316   qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
6317   for (i = 0; i < hg_fp_cnt; i++)
6318     hg_fp_resolve_deps(&hg_fp[i]);
6319
6320   // note: messes up .proto ptr, don't use
6321   //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
6322
6323   // output variables
6324   for (i = 0; i < hg_var_cnt; i++) {
6325     var = &hg_vars[i];
6326
6327     if (var->pp != NULL)
6328       // part of seed
6329       continue;
6330     else if (var->is_c_str)
6331       fprintf(fout, "extern %-8s %s[];", "char", var->name);
6332     else
6333       fprintf(fout, "extern %-8s %s;",
6334         lmod_c_names[var->lmod], var->name);
6335
6336     if (var->is_seeded)
6337       fprintf(fout, " // seeded");
6338     fprintf(fout, "\n");
6339   }
6340
6341   fprintf(fout, "\n");
6342
6343   // output function prototypes
6344   output_hdr_fp(fout, hg_fp, hg_fp_cnt);
6345
6346   // seed passthrough
6347   fprintf(fout, "\n// - seed -\n");
6348
6349   rewind(g_fhdr);
6350   while (fgets(line, sizeof(line), g_fhdr))
6351     fwrite(line, 1, strlen(line), fout);
6352 }
6353
6354 // '=' needs special treatment
6355 // also ' quote
6356 static char *next_word_s(char *w, size_t wsize, char *s)
6357 {
6358   size_t i;
6359
6360   s = sskip(s);
6361
6362   i = 0;
6363   if (*s == '\'') {
6364     w[0] = s[0];
6365     for (i = 1; i < wsize - 1; i++) {
6366       if (s[i] == 0) {
6367         printf("warning: missing closing quote: \"%s\"\n", s);
6368         break;
6369       }
6370       if (s[i] == '\'')
6371         break;
6372       w[i] = s[i];
6373     }
6374   }
6375
6376   for (; i < wsize - 1; i++) {
6377     if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
6378       break;
6379     w[i] = s[i];
6380   }
6381   w[i] = 0;
6382
6383   if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
6384     printf("warning: '%s' truncated\n", w);
6385
6386   return s + i;
6387 }
6388
6389 static void scan_variables(FILE *fasm)
6390 {
6391   struct scanned_var *var;
6392   char line[256] = { 0, };
6393   char words[3][256];
6394   char *p = NULL;
6395   int wordc;
6396   int l;
6397
6398   while (!feof(fasm))
6399   {
6400     // skip to next data section
6401     while (my_fgets(line, sizeof(line), fasm))
6402     {
6403       asmln++;
6404
6405       p = sskip(line);
6406       if (*p == 0 || *p == ';')
6407         continue;
6408
6409       p = sskip(next_word_s(words[0], sizeof(words[0]), p));
6410       if (*p == 0 || *p == ';')
6411         continue;
6412
6413       if (*p != 's' || !IS_START(p, "segment para public"))
6414         continue;
6415
6416       break;
6417     }
6418
6419     if (p == NULL || !IS_START(p, "segment para public"))
6420       break;
6421     p = sskip(p + 19);
6422
6423     if (!IS_START(p, "'DATA'"))
6424       continue;
6425
6426     // now process it
6427     while (my_fgets(line, sizeof(line), fasm))
6428     {
6429       asmln++;
6430
6431       p = line;
6432       if (my_isblank(*p))
6433         continue;
6434
6435       p = sskip(p);
6436       if (*p == 0 || *p == ';')
6437         continue;
6438
6439       for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
6440         words[wordc][0] = 0;
6441         p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
6442         if (*p == 0 || *p == ';') {
6443           wordc++;
6444           break;
6445         }
6446       }
6447
6448       if (wordc == 2 && IS(words[1], "ends"))
6449         break;
6450       if (wordc < 2)
6451         continue;
6452
6453       if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
6454         // when this starts, we don't need anything from this section
6455         break;
6456       }
6457
6458       if ((hg_var_cnt & 0xff) == 0) {
6459         hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
6460                    * (hg_var_cnt + 0x100));
6461         my_assert_not(hg_vars, NULL);
6462         memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
6463       }
6464
6465       var = &hg_vars[hg_var_cnt++];
6466       snprintf(var->name, sizeof(var->name), "%s", words[0]);
6467
6468       // maybe already in seed header?
6469       var->pp = proto_parse(g_fhdr, var->name, 1);
6470       if (var->pp != NULL) {
6471         if (var->pp->is_fptr) {
6472           var->lmod = OPLM_DWORD;
6473           //var->is_ptr = 1;
6474         }
6475         else if (var->pp->is_func)
6476           aerr("func?\n");
6477         else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
6478           aerr("unhandled C type '%s' for '%s'\n",
6479             var->pp->type.name, var->name);
6480
6481         var->is_seeded = 1;
6482         continue;
6483       }
6484
6485       if      (IS(words[1], "dd"))
6486         var->lmod = OPLM_DWORD;
6487       else if (IS(words[1], "dw"))
6488         var->lmod = OPLM_WORD;
6489       else if (IS(words[1], "db")) {
6490         var->lmod = OPLM_BYTE;
6491         if (wordc >= 3 && (l = strlen(words[2])) > 4) {
6492           if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
6493             var->is_c_str = 1;
6494         }
6495       }
6496       else if (IS(words[1], "dq"))
6497         var->lmod = OPLM_QWORD;
6498       //else if (IS(words[1], "dt"))
6499       else
6500         aerr("type '%s' not known\n", words[1]);
6501     }
6502   }
6503
6504   rewind(fasm);
6505   asmln = 0;
6506 }
6507
6508 static void set_label(int i, const char *name)
6509 {
6510   const char *p;
6511   int len;
6512
6513   len = strlen(name);
6514   p = strchr(name, ':');
6515   if (p != NULL)
6516     len = p - name;
6517
6518   if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
6519     aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
6520   g_labels[i] = realloc(g_labels[i], len + 1);
6521   my_assert_not(g_labels[i], NULL);
6522   memcpy(g_labels[i], name, len);
6523   g_labels[i][len] = 0;
6524 }
6525
6526 struct chunk_item {
6527   char *name;
6528   long fptr;
6529   int asmln;
6530 };
6531
6532 static struct chunk_item *func_chunks;
6533 static int func_chunk_cnt;
6534 static int func_chunk_alloc;
6535
6536 static void add_func_chunk(FILE *fasm, const char *name, int line)
6537 {
6538   if (func_chunk_cnt >= func_chunk_alloc) {
6539     func_chunk_alloc *= 2;
6540     func_chunks = realloc(func_chunks,
6541       func_chunk_alloc * sizeof(func_chunks[0]));
6542     my_assert_not(func_chunks, NULL);
6543   }
6544   func_chunks[func_chunk_cnt].fptr = ftell(fasm);
6545   func_chunks[func_chunk_cnt].name = strdup(name);
6546   func_chunks[func_chunk_cnt].asmln = line;
6547   func_chunk_cnt++;
6548 }
6549
6550 static int cmp_chunks(const void *p1, const void *p2)
6551 {
6552   const struct chunk_item *c1 = p1, *c2 = p2;
6553   return strcmp(c1->name, c2->name);
6554 }
6555
6556 static int cmpstringp(const void *p1, const void *p2)
6557 {
6558   return strcmp(*(char * const *)p1, *(char * const *)p2);
6559 }
6560
6561 static void scan_ahead(FILE *fasm)
6562 {
6563   char words[2][256];
6564   char line[256];
6565   long oldpos;
6566   int oldasmln;
6567   int wordc;
6568   char *p;
6569   int i;
6570
6571   oldpos = ftell(fasm);
6572   oldasmln = asmln;
6573
6574   while (my_fgets(line, sizeof(line), fasm))
6575   {
6576     wordc = 0;
6577     asmln++;
6578
6579     p = sskip(line);
6580     if (*p == 0)
6581       continue;
6582
6583     if (*p == ';')
6584     {
6585       // get rid of random tabs
6586       for (i = 0; line[i] != 0; i++)
6587         if (line[i] == '\t')
6588           line[i] = ' ';
6589
6590       if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
6591       {
6592         p += 30;
6593         next_word(words[0], sizeof(words[0]), p);
6594         if (words[0][0] == 0)
6595           aerr("missing name for func chunk?\n");
6596
6597         add_func_chunk(fasm, words[0], asmln);
6598       }
6599       else if (IS_START(p, "; sctend"))
6600         break;
6601
6602       continue;
6603     } // *p == ';'
6604
6605     for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
6606       words[wordc][0] = 0;
6607       p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
6608       if (*p == 0 || *p == ';') {
6609         wordc++;
6610         break;
6611       }
6612     }
6613
6614     if (wordc == 2 && IS(words[1], "ends"))
6615       break;
6616   }
6617
6618   fseek(fasm, oldpos, SEEK_SET);
6619   asmln = oldasmln;
6620 }
6621
6622 int main(int argc, char *argv[])
6623 {
6624   FILE *fout, *fasm, *frlist;
6625   struct parsed_data *pd = NULL;
6626   int pd_alloc = 0;
6627   char **rlist = NULL;
6628   int rlist_len = 0;
6629   int rlist_alloc = 0;
6630   int func_chunks_used = 0;
6631   int func_chunks_sorted = 0;
6632   int func_chunk_i = -1;
6633   long func_chunk_ret = 0;
6634   int func_chunk_ret_ln = 0;
6635   int scanned_ahead = 0;
6636   char line[256];
6637   char words[20][256];
6638   enum opr_lenmod lmod;
6639   char *sctproto = NULL;
6640   int in_func = 0;
6641   int pending_endp = 0;
6642   int skip_func = 0;
6643   int skip_warned = 0;
6644   int eq_alloc;
6645   int verbose = 0;
6646   int multi_seg = 0;
6647   int end = 0;
6648   int arg_out;
6649   int arg;
6650   int pi = 0;
6651   int i, j;
6652   int ret, len;
6653   char *p;
6654   int wordc;
6655
6656   for (arg = 1; arg < argc; arg++) {
6657     if (IS(argv[arg], "-v"))
6658       verbose = 1;
6659     else if (IS(argv[arg], "-rf"))
6660       g_allow_regfunc = 1;
6661     else if (IS(argv[arg], "-m"))
6662       multi_seg = 1;
6663     else if (IS(argv[arg], "-hdr"))
6664       g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
6665     else
6666       break;
6667   }
6668
6669   if (argc < arg + 3) {
6670     printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
6671            "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
6672            "options:\n"
6673            "  -hdr - header generation mode\n"
6674            "  -rf  - allow unannotated indirect calls\n"
6675            "  -m   - allow multiple .text sections\n"
6676            "[rlist] is a file with function names to skip,"
6677            " one per line\n",
6678       argv[0], argv[0]);
6679     return 1;
6680   }
6681
6682   arg_out = arg++;
6683
6684   asmfn = argv[arg++];
6685   fasm = fopen(asmfn, "r");
6686   my_assert_not(fasm, NULL);
6687
6688   hdrfn = argv[arg++];
6689   g_fhdr = fopen(hdrfn, "r");
6690   my_assert_not(g_fhdr, NULL);
6691
6692   rlist_alloc = 64;
6693   rlist = malloc(rlist_alloc * sizeof(rlist[0]));
6694   my_assert_not(rlist, NULL);
6695   // needs special handling..
6696   rlist[rlist_len++] = "__alloca_probe";
6697
6698   func_chunk_alloc = 32;
6699   func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
6700   my_assert_not(func_chunks, NULL);
6701
6702   memset(words, 0, sizeof(words));
6703
6704   for (; arg < argc; arg++) {
6705     frlist = fopen(argv[arg], "r");
6706     my_assert_not(frlist, NULL);
6707
6708     while (my_fgets(line, sizeof(line), frlist)) {
6709       p = sskip(line);
6710       if (*p == 0 || *p == ';')
6711         continue;
6712       if (*p == '#') {
6713         if (IS_START(p, "#if 0")
6714          || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
6715         {
6716           skip_func = 1;
6717         }
6718         else if (IS_START(p, "#endif"))
6719           skip_func = 0;
6720         continue;
6721       }
6722       if (skip_func)
6723         continue;
6724
6725       p = next_word(words[0], sizeof(words[0]), p);
6726       if (words[0][0] == 0)
6727         continue;
6728
6729       if (rlist_len >= rlist_alloc) {
6730         rlist_alloc = rlist_alloc * 2 + 64;
6731         rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
6732         my_assert_not(rlist, NULL);
6733       }
6734       rlist[rlist_len++] = strdup(words[0]);
6735     }
6736     skip_func = 0;
6737
6738     fclose(frlist);
6739     frlist = NULL;
6740   }
6741
6742   if (rlist_len > 0)
6743     qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
6744
6745   fout = fopen(argv[arg_out], "w");
6746   my_assert_not(fout, NULL);
6747
6748   eq_alloc = 128;
6749   g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
6750   my_assert_not(g_eqs, NULL);
6751
6752   for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
6753     g_label_refs[i].i = -1;
6754     g_label_refs[i].next = NULL;
6755   }
6756
6757   if (g_header_mode)
6758     scan_variables(fasm);
6759
6760   while (my_fgets(line, sizeof(line), fasm))
6761   {
6762     wordc = 0;
6763     asmln++;
6764
6765     p = sskip(line);
6766     if (*p == 0)
6767       continue;
6768
6769     // get rid of random tabs
6770     for (i = 0; line[i] != 0; i++)
6771       if (line[i] == '\t')
6772         line[i] = ' ';
6773
6774     if (*p == ';')
6775     {
6776       if (p[2] == '=' && IS_START(p, "; =============== S U B"))
6777         goto do_pending_endp; // eww..
6778
6779       if (p[2] == 'A' && IS_START(p, "; Attributes:"))
6780       {
6781         static const char *attrs[] = {
6782           "bp-based frame",
6783           "library function",
6784           "static",
6785           "noreturn",
6786           "thunk",
6787           "fpd=",
6788         };
6789
6790         // parse IDA's attribute-list comment
6791         g_ida_func_attr = 0;
6792         p = sskip(p + 13);
6793
6794         for (; *p != 0; p = sskip(p)) {
6795           for (i = 0; i < ARRAY_SIZE(attrs); i++) {
6796             if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
6797               g_ida_func_attr |= 1 << i;
6798               p += strlen(attrs[i]);
6799               break;
6800             }
6801           }
6802           if (i == ARRAY_SIZE(attrs)) {
6803             anote("unparsed IDA attr: %s\n", p);
6804             break;
6805           }
6806           if (IS(attrs[i], "fpd=")) {
6807             p = next_word(words[0], sizeof(words[0]), p);
6808             // ignore for now..
6809           }
6810         }
6811       }
6812       else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
6813       {
6814         p += 30;
6815         next_word(words[0], sizeof(words[0]), p);
6816         if (words[0][0] == 0)
6817           aerr("missing name for func chunk?\n");
6818
6819         if (!scanned_ahead) {
6820           add_func_chunk(fasm, words[0], asmln);
6821           func_chunks_sorted = 0;
6822         }
6823       }
6824       else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
6825       {
6826         if (func_chunk_i >= 0) {
6827           if (func_chunk_i < func_chunk_cnt
6828             && IS(func_chunks[func_chunk_i].name, g_func))
6829           {
6830             // move on to next chunk
6831             ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
6832             if (ret)
6833               aerr("seek failed for '%s' chunk #%d\n",
6834                 g_func, func_chunk_i);
6835             asmln = func_chunks[func_chunk_i].asmln;
6836             func_chunk_i++;
6837           }
6838           else {
6839             if (func_chunk_ret == 0)
6840               aerr("no return from chunk?\n");
6841             fseek(fasm, func_chunk_ret, SEEK_SET);
6842             asmln = func_chunk_ret_ln;
6843             func_chunk_ret = 0;
6844             pending_endp = 1;
6845           }
6846         }
6847       }
6848       else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
6849         func_chunks_used = 1;
6850         p += 20;
6851         if (IS_START(g_func, "sub_")) {
6852           unsigned long addr = strtoul(p, NULL, 16);
6853           unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
6854           if (addr > f_addr && !scanned_ahead) {
6855             anote("scan_ahead caused by '%s', addr %lx\n",
6856               g_func, addr);
6857             scan_ahead(fasm);
6858             scanned_ahead = 1;
6859             func_chunks_sorted = 0;
6860           }
6861         }
6862       }
6863       continue;
6864     } // *p == ';'
6865
6866 parse_words:
6867     for (i = wordc; i < ARRAY_SIZE(words); i++)
6868       words[i][0] = 0;
6869     for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
6870       p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
6871       if (*p == 0 || *p == ';') {
6872         wordc++;
6873         break;
6874       }
6875     }
6876     if (*p != 0 && *p != ';')
6877       aerr("too many words\n");
6878
6879     // alow asm patches in comments
6880     if (*p == ';') {
6881       if (IS_START(p, "; sctpatch:")) {
6882         p = sskip(p + 11);
6883         if (*p == 0 || *p == ';')
6884           continue;
6885         goto parse_words; // lame
6886       }
6887       if (IS_START(p, "; sctproto:")) {
6888         sctproto = strdup(p + 11);
6889       }
6890       else if (IS_START(p, "; sctend")) {
6891         end = 1;
6892         if (!pending_endp)
6893           break;
6894       }
6895     }
6896
6897     if (wordc == 0) {
6898       // shouldn't happen
6899       awarn("wordc == 0?\n");
6900       continue;
6901     }
6902
6903     // don't care about this:
6904     if (words[0][0] == '.'
6905         || IS(words[0], "include")
6906         || IS(words[0], "assume") || IS(words[1], "segment")
6907         || IS(words[0], "align"))
6908     {
6909       continue;
6910     }
6911
6912 do_pending_endp:
6913     // do delayed endp processing to collect switch jumptables
6914     if (pending_endp) {
6915       if (in_func && !g_skip_func && !end && wordc >= 2
6916           && ((words[0][0] == 'd' && words[0][2] == 0)
6917               || (words[1][0] == 'd' && words[1][2] == 0)))
6918       {
6919         i = 1;
6920         if (words[1][0] == 'd' && words[1][2] == 0) {
6921           // label
6922           if (g_func_pd_cnt >= pd_alloc) {
6923             pd_alloc = pd_alloc * 2 + 16;
6924             g_func_pd = realloc(g_func_pd,
6925               sizeof(g_func_pd[0]) * pd_alloc);
6926             my_assert_not(g_func_pd, NULL);
6927           }
6928           pd = &g_func_pd[g_func_pd_cnt];
6929           g_func_pd_cnt++;
6930           memset(pd, 0, sizeof(*pd));
6931           strcpy(pd->label, words[0]);
6932           pd->type = OPT_CONST;
6933           pd->lmod = lmod_from_directive(words[1]);
6934           i = 2;
6935         }
6936         else {
6937           if (pd == NULL) {
6938             if (verbose)
6939               anote("skipping alignment byte?\n");
6940             continue;
6941           }
6942           lmod = lmod_from_directive(words[0]);
6943           if (lmod != pd->lmod)
6944             aerr("lmod change? %d->%d\n", pd->lmod, lmod);
6945         }
6946
6947         if (pd->count_alloc < pd->count + wordc) {
6948           pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
6949           pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
6950           my_assert_not(pd->d, NULL);
6951         }
6952         for (; i < wordc; i++) {
6953           if (IS(words[i], "offset")) {
6954             pd->type = OPT_OFFSET;
6955             i++;
6956           }
6957           p = strchr(words[i], ',');
6958           if (p != NULL)
6959             *p = 0;
6960           if (pd->type == OPT_OFFSET)
6961             pd->d[pd->count].u.label = strdup(words[i]);
6962           else
6963             pd->d[pd->count].u.val = parse_number(words[i]);
6964           pd->d[pd->count].bt_i = -1;
6965           pd->count++;
6966         }
6967         continue;
6968       }
6969
6970       if (in_func && !g_skip_func) {
6971         if (g_header_mode)
6972           gen_hdr(g_func, pi);
6973         else
6974           gen_func(fout, g_fhdr, g_func, pi);
6975       }
6976
6977       pending_endp = 0;
6978       in_func = 0;
6979       g_ida_func_attr = 0;
6980       skip_warned = 0;
6981       g_skip_func = 0;
6982       g_func[0] = 0;
6983       func_chunks_used = 0;
6984       func_chunk_i = -1;
6985       if (pi != 0) {
6986         memset(&ops, 0, pi * sizeof(ops[0]));
6987         clear_labels(pi);
6988         pi = 0;
6989       }
6990       g_eqcnt = 0;
6991       for (i = 0; i < g_func_pd_cnt; i++) {
6992         pd = &g_func_pd[i];
6993         if (pd->type == OPT_OFFSET) {
6994           for (j = 0; j < pd->count; j++)
6995             free(pd->d[j].u.label);
6996         }
6997         free(pd->d);
6998         pd->d = NULL;
6999       }
7000       g_func_pd_cnt = 0;
7001       pd = NULL;
7002
7003       if (end)
7004         break;
7005       if (wordc == 0)
7006         continue;
7007     }
7008
7009     if (IS(words[1], "proc")) {
7010       if (in_func)
7011         aerr("proc '%s' while in_func '%s'?\n",
7012           words[0], g_func);
7013       p = words[0];
7014       if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
7015         g_skip_func = 1;
7016       strcpy(g_func, words[0]);
7017       set_label(0, words[0]);
7018       in_func = 1;
7019       continue;
7020     }
7021
7022     if (IS(words[1], "endp"))
7023     {
7024       if (!in_func)
7025         aerr("endp '%s' while not in_func?\n", words[0]);
7026       if (!IS(g_func, words[0]))
7027         aerr("endp '%s' while in_func '%s'?\n",
7028           words[0], g_func);
7029
7030       if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
7031         && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
7032       {
7033         // import jump
7034         g_skip_func = 1;
7035       }
7036
7037       if (!g_skip_func && func_chunks_used) {
7038         // start processing chunks
7039         struct chunk_item *ci, key = { g_func, 0 };
7040
7041         func_chunk_ret = ftell(fasm);
7042         func_chunk_ret_ln = asmln;
7043         if (!func_chunks_sorted) {
7044           qsort(func_chunks, func_chunk_cnt,
7045             sizeof(func_chunks[0]), cmp_chunks);
7046           func_chunks_sorted = 1;
7047         }
7048         ci = bsearch(&key, func_chunks, func_chunk_cnt,
7049                sizeof(func_chunks[0]), cmp_chunks);
7050         if (ci == NULL)
7051           aerr("'%s' needs chunks, but none found\n", g_func);
7052         func_chunk_i = ci - func_chunks;
7053         for (; func_chunk_i > 0; func_chunk_i--)
7054           if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
7055             break;
7056
7057         ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
7058         if (ret)
7059           aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
7060         asmln = func_chunks[func_chunk_i].asmln;
7061         func_chunk_i++;
7062         continue;
7063       }
7064       pending_endp = 1;
7065       continue;
7066     }
7067
7068     if (wordc == 2 && IS(words[1], "ends")) {
7069       if (!multi_seg) {
7070         end = 1;
7071         if (pending_endp)
7072           goto do_pending_endp;
7073         break;
7074       }
7075
7076       // scan for next text segment
7077       while (my_fgets(line, sizeof(line), fasm)) {
7078         asmln++;
7079         p = sskip(line);
7080         if (*p == 0 || *p == ';')
7081           continue;
7082
7083         if (strstr(p, "segment para public 'CODE' use32"))
7084           break;
7085       }
7086
7087       continue;
7088     }
7089
7090     p = strchr(words[0], ':');
7091     if (p != NULL) {
7092       set_label(pi, words[0]);
7093       continue;
7094     }
7095
7096     if (!in_func || g_skip_func) {
7097       if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
7098         if (verbose)
7099           anote("skipping from '%s'\n", g_labels[pi]);
7100         skip_warned = 1;
7101       }
7102       free(g_labels[pi]);
7103       g_labels[pi] = NULL;
7104       continue;
7105     }
7106
7107     if (wordc > 1 && IS(words[1], "="))
7108     {
7109       if (wordc != 5)
7110         aerr("unhandled equ, wc=%d\n", wordc);
7111       if (g_eqcnt >= eq_alloc) {
7112         eq_alloc *= 2;
7113         g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
7114         my_assert_not(g_eqs, NULL);
7115       }
7116
7117       len = strlen(words[0]);
7118       if (len > sizeof(g_eqs[0].name) - 1)
7119         aerr("equ name too long: %d\n", len);
7120       strcpy(g_eqs[g_eqcnt].name, words[0]);
7121
7122       if (!IS(words[3], "ptr"))
7123         aerr("unhandled equ\n");
7124       if (IS(words[2], "dword"))
7125         g_eqs[g_eqcnt].lmod = OPLM_DWORD;
7126       else if (IS(words[2], "word"))
7127         g_eqs[g_eqcnt].lmod = OPLM_WORD;
7128       else if (IS(words[2], "byte"))
7129         g_eqs[g_eqcnt].lmod = OPLM_BYTE;
7130       else if (IS(words[2], "qword"))
7131         g_eqs[g_eqcnt].lmod = OPLM_QWORD;
7132       else
7133         aerr("bad lmod: '%s'\n", words[2]);
7134
7135       g_eqs[g_eqcnt].offset = parse_number(words[4]);
7136       g_eqcnt++;
7137       continue;
7138     }
7139
7140     if (pi >= ARRAY_SIZE(ops))
7141       aerr("too many ops\n");
7142
7143     parse_op(&ops[pi], words, wordc);
7144
7145     if (sctproto != NULL) {
7146       if (ops[pi].op == OP_CALL || ops[pi].op == OP_JMP)
7147         ops[pi].datap = sctproto;
7148       sctproto = NULL;
7149     }
7150     pi++;
7151   }
7152
7153   if (g_header_mode)
7154     output_hdr(fout);
7155
7156   fclose(fout);
7157   fclose(fasm);
7158   fclose(g_fhdr);
7159
7160   return 0;
7161 }
7162
7163 // vim:ts=2:shiftwidth=2:expandtab