translate: more float stuff
[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  * recognized asm hint comments:
9  * sctattr - function attributes (see code)
10  * sctend  - force end of function/chunk
11  * sctpatch: <p> - replace current asm line with <p>
12  * sctproto: <p> - prototype of ref'd function or struct
13  * sctref  - variable is referenced, make global
14  * sctskip_start - start of skipped code chunk (inclusive)
15  * sctskip_end   - end of skipped code chunk (inclusive)
16  */
17
18 #define _GNU_SOURCE
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <errno.h>
23
24 #include "my_assert.h"
25 #include "my_str.h"
26 #include "common.h"
27
28 #include "protoparse.h"
29
30 static const char *asmfn;
31 static int asmln;
32 static FILE *g_fhdr;
33
34 #define anote(fmt, ...) \
35         printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
36 #define awarn(fmt, ...) \
37         printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
38 #define aerr(fmt, ...) do { \
39         printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
40   fcloseall(); \
41         exit(1); \
42 } while (0)
43
44 #include "masm_tools.h"
45
46 enum op_flags {
47   OPF_RMD    = (1 << 0), /* removed from code generation */
48   OPF_DATA   = (1 << 1), /* data processing - writes to dst opr */
49   OPF_FLAGS  = (1 << 2), /* sets flags */
50   OPF_JMP    = (1 << 3), /* branch, call */
51   OPF_CJMP   = (1 << 4), /* cond. branch (cc or jecxz/loop) */
52   OPF_CC     = (1 << 5), /* uses flags */
53   OPF_TAIL   = (1 << 6), /* ret or tail call */
54   OPF_RSAVE  = (1 << 7), /* push/pop is local reg save/load */
55   OPF_REP    = (1 << 8), /* prefixed by rep */
56   OPF_REPZ   = (1 << 9), /* rep is repe/repz */
57   OPF_REPNZ  = (1 << 10), /* rep is repne/repnz */
58   OPF_FARG   = (1 << 11), /* push collected as func arg */
59   OPF_FARGNR = (1 << 12), /* push collected as func arg (no reuse) */
60   OPF_EBP_S  = (1 << 13), /* ebp used as scratch here, not BP */
61   OPF_DF     = (1 << 14), /* DF flag set */
62   OPF_ATAIL  = (1 << 15), /* tail call with reused arg frame */
63   OPF_32BIT  = (1 << 16), /* 32bit division */
64   OPF_LOCK   = (1 << 17), /* op has lock prefix */
65   OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
66   OPF_DONE   = (1 << 19), /* already fully handled by analysis */
67   OPF_PPUSH  = (1 << 20), /* part of complex push-pop graph */
68   OPF_NOREGS = (1 << 21), /* don't track regs of this op */
69   OPF_FPUSH  = (1 << 22), /* pushes x87 stack */
70   OPF_FPOP   = (1 << 23), /* pops x87 stack */
71   OPF_FSHIFT = (1 << 24), /* x87 stack shift is actually needed */
72   OPF_FINT   = (1 << 25), /* integer float op arg */
73 };
74
75 enum op_op {
76         OP_INVAL,
77         OP_NOP,
78         OP_PUSH,
79         OP_POP,
80         OP_PUSHA,
81         OP_POPA,
82         OP_LEAVE,
83         OP_MOV,
84         OP_LEA,
85         OP_MOVZX,
86         OP_MOVSX,
87         OP_XCHG,
88         OP_NOT,
89         OP_XLAT,
90         OP_CDQ,
91         OP_BSWAP,
92         OP_LODS,
93         OP_STOS,
94         OP_MOVS,
95         OP_CMPS,
96         OP_SCAS,
97         OP_STD,
98         OP_CLD,
99         OP_RET,
100         OP_ADD,
101         OP_SUB,
102         OP_AND,
103         OP_OR,
104         OP_XOR,
105         OP_SHL,
106         OP_SHR,
107         OP_SAR,
108         OP_SHLD,
109         OP_SHRD,
110         OP_ROL,
111         OP_ROR,
112         OP_RCL,
113         OP_RCR,
114         OP_ADC,
115         OP_SBB,
116         OP_BSF,
117         OP_BSR,
118         OP_INC,
119         OP_DEC,
120         OP_NEG,
121         OP_MUL,
122         OP_IMUL,
123         OP_DIV,
124         OP_IDIV,
125         OP_TEST,
126         OP_CMP,
127         OP_CALL,
128         OP_JMP,
129         OP_JECXZ,
130         OP_LOOP,
131         OP_JCC,
132         OP_SCC,
133   // x87
134   OP_FLD,
135   OP_FILD,
136   OP_FLDc,
137   OP_FST,
138   OP_FIST,
139   OP_FADD,
140   OP_FDIV,
141   OP_FMUL,
142   OP_FSUB,
143   OP_FDIVR,
144   OP_FSUBR,
145   OP_FIADD,
146   OP_FIDIV,
147   OP_FIMUL,
148   OP_FISUB,
149   OP_FIDIVR,
150   OP_FISUBR,
151   OP_FCOM,
152   OP_FNSTSW,
153   OP_FCHS,
154   OP_FCOS,
155   OP_FPATAN,
156   OP_FPTAN,
157   OP_FSIN,
158   OP_FSQRT,
159   OP_FXCH,
160   OP_FYL2X,
161   // mmx
162   OP_EMMS,
163   // pseudo-ops for lib calls
164   OPP_ALLSHL,
165   OPP_ALLSHR,
166   OPP_FTOL,
167   OPP_CIPOW,
168   OPP_ABORT,
169   // undefined
170   OP_UD2,
171 };
172
173 enum opr_type {
174   OPT_UNSPEC,
175   OPT_REG,
176   OPT_REGMEM,
177   OPT_LABEL,
178   OPT_OFFSET,
179   OPT_CONST,
180 };
181
182 // must be sorted (larger len must be further in enum)
183 enum opr_lenmod {
184         OPLM_UNSPEC,
185         OPLM_BYTE,
186         OPLM_WORD,
187         OPLM_DWORD,
188         OPLM_QWORD,
189 };
190
191 #define MAX_EXITS 128
192
193 #define MAX_OPERANDS 3
194 #define NAMELEN 112
195
196 #define OPR_INIT(type_, lmod_, reg_) \
197   { type_, lmod_, reg_, }
198
199 struct parsed_opr {
200   enum opr_type type;
201   enum opr_lenmod lmod;
202   int reg;
203   unsigned int is_ptr:1;   // pointer in C
204   unsigned int is_array:1; // array in C
205   unsigned int type_from_var:1; // .. in header, sometimes wrong
206   unsigned int size_mismatch:1; // type override differs from C
207   unsigned int size_lt:1;  // type override is larger than C
208   unsigned int had_ds:1;   // had ds: prefix
209   const struct parsed_proto *pp; // for OPT_LABEL
210   unsigned int val;
211   char name[NAMELEN];
212 };
213
214 struct parsed_op {
215   enum op_op op;
216   struct parsed_opr operand[MAX_OPERANDS];
217   unsigned int flags;
218   unsigned char pfo;
219   unsigned char pfo_inv;
220   unsigned char operand_cnt;
221   unsigned char p_argnum; // arg push: altered before call arg #
222   unsigned char p_arggrp; // arg push: arg group # for above
223   unsigned char p_argpass;// arg push: arg of host func
224   short         p_argnext;// arg push: same arg pushed elsewhere or -1
225   int regmask_src;        // all referensed regs
226   int regmask_dst;
227   int pfomask;            // flagop: parsed_flag_op that can't be delayed
228   int cc_scratch;         // scratch storage during analysis
229   int bt_i;               // branch target for branches
230   struct parsed_data *btj;// branch targets for jumptables
231   struct parsed_proto *pp;// parsed_proto for OP_CALL
232   void *datap;
233   int asmln;
234 };
235
236 // datap:
237 // on start:  function/data type hint (sctproto)
238 // after analysis:
239 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
240 // OP_PUSH  - points to OP_POP in complex push/pop graph
241 // OP_POP   - points to OP_PUSH in simple push/pop pair
242 // OP_FCOM  - needed_status_word_bits | (is_z_check << 16)
243
244 struct parsed_equ {
245   char name[64];
246   enum opr_lenmod lmod;
247   int offset;
248 };
249
250 struct parsed_data {
251   char label[256];
252   enum opr_type type;
253   enum opr_lenmod lmod;
254   int count;
255   int count_alloc;
256   struct {
257     union {
258       char *label;
259       unsigned int val;
260     } u;
261     int bt_i;
262   } *d;
263 };
264
265 struct label_ref {
266   int i;
267   struct label_ref *next;
268 };
269
270 enum ida_func_attr {
271   IDAFA_BP_FRAME = (1 << 0),
272   IDAFA_LIB_FUNC = (1 << 1),
273   IDAFA_STATIC   = (1 << 2),
274   IDAFA_NORETURN = (1 << 3),
275   IDAFA_THUNK    = (1 << 4),
276   IDAFA_FPD      = (1 << 5),
277 };
278
279 enum sct_func_attr {
280   SCTFA_CLEAR_SF   = (1 << 0), // clear stack frame
281   SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
282 };
283
284 enum x87_const {
285   X87_CONST_1 = 1,
286   X87_CONST_2T,
287   X87_CONST_2E,
288   X87_CONST_PI,
289   X87_CONST_LG2,
290   X87_CONST_LN2,
291   X87_CONST_Z,
292 };
293
294 // note: limited to 32k due to p_argnext
295 #define MAX_OPS     4096
296 #define MAX_ARG_GRP 2
297
298 static struct parsed_op ops[MAX_OPS];
299 static struct parsed_equ *g_eqs;
300 static int g_eqcnt;
301 static char *g_labels[MAX_OPS];
302 static struct label_ref g_label_refs[MAX_OPS];
303 static const struct parsed_proto *g_func_pp;
304 static struct parsed_data *g_func_pd;
305 static int g_func_pd_cnt;
306 static int g_func_lmods;
307 static char g_func[256];
308 static char g_comment[256];
309 static int g_bp_frame;
310 static int g_sp_frame;
311 static int g_stack_frame_used;
312 static int g_stack_fsz;
313 static int g_ida_func_attr;
314 static int g_sct_func_attr;
315 static int g_stack_clear_start; // in dwords
316 static int g_stack_clear_len;
317 static int g_regmask_init;
318 static int g_skip_func;
319 static int g_allow_regfunc;
320 static int g_allow_user_icall;
321 static int g_quiet_pp;
322 static int g_header_mode;
323
324 #define ferr(op_, fmt, ...) do { \
325   printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
326     __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
327   fcloseall(); \
328   exit(1); \
329 } while (0)
330 #define fnote(op_, fmt, ...) \
331   printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
332     dump_op(op_), ##__VA_ARGS__)
333
334 #define ferr_assert(op_, cond) do { \
335   if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
336 } while (0)
337
338 const char *regs_r32[] = {
339   "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
340   // not r32, but list here for easy parsing and printing
341   "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
342   "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
343 };
344 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
345 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
346 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
347
348 enum x86_regs {
349   xUNSPEC = -1,
350   xAX, xBX, xCX, xDX,
351   xSI, xDI, xBP, xSP,
352   xMM0, xMM1, xMM2, xMM3, // mmx
353   xMM4, xMM5, xMM6, xMM7,
354   xST0, xST1, xST2, xST3, // x87
355   xST4, xST5, xST6, xST7,
356 };
357
358 #define mxAX     (1 << xAX)
359 #define mxCX     (1 << xCX)
360 #define mxDX     (1 << xDX)
361 #define mxSP     (1 << xSP)
362 #define mxST0    (1 << xST0)
363 #define mxST1    (1 << xST1)
364 #define mxST1_0  (mxST1 | mxST0)
365 #define mxST7_2  (0xfc << xST0)
366 #define mxSTa    (0xff << xST0)
367
368 // possible basic comparison types (without inversion)
369 enum parsed_flag_op {
370   PFO_O,  // 0 OF=1
371   PFO_C,  // 2 CF=1
372   PFO_Z,  // 4 ZF=1
373   PFO_BE, // 6 CF=1||ZF=1
374   PFO_S,  // 8 SF=1
375   PFO_P,  // a PF=1
376   PFO_L,  // c SF!=OF
377   PFO_LE, // e ZF=1||SF!=OF
378 };
379
380 #define PFOB_O   (1 << PFO_O)
381 #define PFOB_C   (1 << PFO_C)
382 #define PFOB_Z   (1 << PFO_Z)
383 #define PFOB_S   (1 << PFO_S)
384
385 static const char *parsed_flag_op_names[] = {
386   "o", "c", "z", "be", "s", "p", "l", "le"
387 };
388
389 static int char_array_i(const char *array[], size_t len, const char *s)
390 {
391   int i;
392
393   for (i = 0; i < len; i++)
394     if (IS(s, array[i]))
395       return i;
396
397   return -1;
398 }
399
400 static void printf_number(char *buf, size_t buf_size,
401   unsigned long number)
402 {
403   // output in C-friendly form
404   snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
405 }
406
407 static int check_segment_prefix(const char *s)
408 {
409   if (s[0] == 0 || s[1] != 's' || s[2] != ':')
410     return 0;
411
412   switch (s[0]) {
413   case 'c': return 1;
414   case 'd': return 2;
415   case 's': return 3;
416   case 'e': return 4;
417   case 'f': return 5;
418   case 'g': return 6;
419   default:  return 0;
420   }
421 }
422
423 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
424 {
425   int reg;
426
427   reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
428   if (reg >= 8) {
429     *reg_lmod = OPLM_QWORD;
430     return reg;
431   }
432   if (reg >= 0) {
433     *reg_lmod = OPLM_DWORD;
434     return reg;
435   }
436   reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
437   if (reg >= 0) {
438     *reg_lmod = OPLM_WORD;
439     return reg;
440   }
441   reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
442   if (reg >= 0) {
443     *reg_lmod = OPLM_BYTE;
444     return reg;
445   }
446   reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
447   if (reg >= 0) {
448     *reg_lmod = OPLM_BYTE;
449     return reg;
450   }
451
452   return -1;
453 }
454
455 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
456 {
457   enum opr_lenmod lmod;
458   char cvtbuf[256];
459   char *d = cvtbuf;
460   char *s = name;
461   char w[64];
462   long number;
463   int reg;
464   int c = 0;
465
466   *d = 0;
467
468   while (*s != 0) {
469     d += strlen(d);
470     while (my_isblank(*s))
471       s++;
472     for (; my_issep(*s); d++, s++)
473       *d = *s;
474     while (my_isblank(*s))
475       s++;
476     *d = 0;
477
478     // skip '?s:' prefixes
479     if (check_segment_prefix(s))
480       s += 3;
481
482     s = next_idt(w, sizeof(w), s);
483     if (w[0] == 0)
484       break;
485     c++;
486
487     reg = parse_reg(&lmod, w);
488     if (reg >= 0) {
489       *regmask |= 1 << reg;
490       goto pass;
491     }
492
493     if ('0' <= w[0] && w[0] <= '9') {
494       number = parse_number(w, 0);
495       printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
496       continue;
497     }
498
499     // probably some label/identifier - pass
500
501 pass:
502     snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
503   }
504
505   if (need_c_cvt)
506     strcpy(name, cvtbuf);
507
508   return c;
509 }
510
511 static int is_reg_in_str(const char *s)
512 {
513   int i;
514
515   if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
516     return 0;
517
518   for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
519     if (!strncmp(s, regs_r32[i], 3))
520       return 1;
521
522   return 0;
523 }
524
525 static const char *parse_stack_el(const char *name, char *extra_reg,
526   int *base_val, int early_try)
527 {
528   const char *p, *p2, *s;
529   char *endp = NULL;
530   char buf[32];
531   long val = -1;
532   int len;
533
534   if (g_bp_frame || early_try)
535   {
536     p = name;
537     if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
538       p += 4;
539       if (extra_reg != NULL) {
540         strncpy(extra_reg, name, 3);
541         extra_reg[4] = 0;
542       }
543     }
544
545     if (IS_START(p, "ebp+")) {
546       p += 4;
547
548       p2 = strchr(p, '+');
549       if (p2 != NULL && is_reg_in_str(p)) {
550         if (extra_reg != NULL) {
551           strncpy(extra_reg, p, p2 - p);
552           extra_reg[p2 - p] = 0;
553         }
554         p = p2 + 1;
555       }
556
557       if (!('0' <= *p && *p <= '9'))
558         return p;
559
560       return NULL;
561     }
562   }
563
564   if (!IS_START(name, "esp+"))
565     return NULL;
566
567   s = name + 4;
568   p = strchr(s, '+');
569   if (p) {
570     if (is_reg_in_str(s)) {
571       if (extra_reg != NULL) {
572         strncpy(extra_reg, s, p - s);
573         extra_reg[p - s] = 0;
574       }
575       s = p + 1;
576       p = strchr(s, '+');
577       if (p == NULL)
578         aerr("%s IDA stackvar not set?\n", __func__);
579     }
580     if (!('0' <= *s && *s <= '9')) {
581       aerr("%s IDA stackvar offset not set?\n", __func__);
582       return NULL;
583     }
584     if (s[0] == '0' && s[1] == 'x')
585       s += 2;
586     len = p - s;
587     if (len < sizeof(buf) - 1) {
588       strncpy(buf, s, len);
589       buf[len] = 0;
590       errno = 0;
591       val = strtol(buf, &endp, 16);
592       if (val == 0 || *endp != 0 || errno != 0) {
593         aerr("%s num parse fail for '%s'\n", __func__, buf);
594         return NULL;
595       }
596     }
597     p++;
598   }
599   else
600     p = name + 4;
601
602   if ('0' <= *p && *p <= '9')
603     return NULL;
604
605   if (base_val != NULL)
606     *base_val = val;
607   return p;
608 }
609
610 static int guess_lmod_from_name(struct parsed_opr *opr)
611 {
612   if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
613     opr->lmod = OPLM_DWORD;
614     return 1;
615   }
616   if (IS_START(opr->name, "word_")) {
617     opr->lmod = OPLM_WORD;
618     return 1;
619   }
620   if (IS_START(opr->name, "byte_")) {
621     opr->lmod = OPLM_BYTE;
622     return 1;
623   }
624   if (IS_START(opr->name, "qword_")) {
625     opr->lmod = OPLM_QWORD;
626     return 1;
627   }
628   return 0;
629 }
630
631 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
632   const struct parsed_type *c_type)
633 {
634   static const char *qword_types[] = {
635     "uint64_t", "int64_t", "__int64",
636   };
637   static const char *dword_types[] = {
638     "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
639     "WPARAM", "LPARAM", "UINT", "__int32",
640     "LONG", "HIMC", "BOOL", "size_t",
641     "float",
642   };
643   static const char *word_types[] = {
644     "uint16_t", "int16_t", "_WORD", "WORD",
645     "unsigned __int16", "__int16",
646   };
647   static const char *byte_types[] = {
648     "uint8_t", "int8_t", "char",
649     "unsigned __int8", "__int8", "BYTE", "_BYTE",
650     "CHAR", "_UNKNOWN",
651     // structures.. deal the same as with _UNKNOWN for now
652     "CRITICAL_SECTION",
653   };
654   const char *n;
655   int i;
656
657   if (c_type->is_ptr) {
658     *lmod = OPLM_DWORD;
659     return 1;
660   }
661
662   n = skip_type_mod(c_type->name);
663
664   for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
665     if (IS(n, dword_types[i])) {
666       *lmod = OPLM_DWORD;
667       return 1;
668     }
669   }
670
671   for (i = 0; i < ARRAY_SIZE(word_types); i++) {
672     if (IS(n, word_types[i])) {
673       *lmod = OPLM_WORD;
674       return 1;
675     }
676   }
677
678   for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
679     if (IS(n, byte_types[i])) {
680       *lmod = OPLM_BYTE;
681       return 1;
682     }
683   }
684
685   for (i = 0; i < ARRAY_SIZE(qword_types); i++) {
686     if (IS(n, qword_types[i])) {
687       *lmod = OPLM_QWORD;
688       return 1;
689     }
690   }
691
692   return 0;
693 }
694
695 static char *default_cast_to(char *buf, size_t buf_size,
696   struct parsed_opr *opr)
697 {
698   buf[0] = 0;
699
700   if (!opr->is_ptr || strchr(opr->name, '['))
701     return buf;
702   if (opr->pp == NULL || opr->pp->type.name == NULL
703     || opr->pp->is_fptr)
704   {
705     snprintf(buf, buf_size, "%s", "(void *)");
706     return buf;
707   }
708
709   snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
710   return buf;
711 }
712
713 static enum opr_type lmod_from_directive(const char *d)
714 {
715   if (IS(d, "dd"))
716     return OPLM_DWORD;
717   else if (IS(d, "dw"))
718     return OPLM_WORD;
719   else if (IS(d, "db"))
720     return OPLM_BYTE;
721
722   aerr("unhandled directive: '%s'\n", d);
723   return OPLM_UNSPEC;
724 }
725
726 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
727   int *regmask)
728 {
729   opr->type = OPT_REG;
730   opr->reg = reg;
731   opr->lmod = lmod;
732   *regmask |= 1 << reg;
733 }
734
735 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
736   int *extra_offs);
737
738 static int parse_operand(struct parsed_opr *opr,
739   int *regmask, int *regmask_indirect,
740   char words[16][256], int wordc, int w, unsigned int op_flags)
741 {
742   const struct parsed_proto *pp = NULL;
743   enum opr_lenmod tmplmod;
744   unsigned long number;
745   char buf[256];
746   int ret, len;
747   int wordc_in;
748   char *p;
749   int i;
750
751   if (w >= wordc)
752     aerr("parse_operand w %d, wordc %d\n", w, wordc);
753
754   opr->reg = xUNSPEC;
755
756   for (i = w; i < wordc; i++) {
757     len = strlen(words[i]);
758     if (words[i][len - 1] == ',') {
759       words[i][len - 1] = 0;
760       wordc = i + 1;
761       break;
762     }
763   }
764
765   wordc_in = wordc - w;
766
767   if ((op_flags & OPF_JMP) && wordc_in > 0
768       && !('0' <= words[w][0] && words[w][0] <= '9'))
769   {
770     const char *label = NULL;
771
772     if (wordc_in == 3 && !strncmp(words[w], "near", 4)
773      && IS(words[w + 1], "ptr"))
774       label = words[w + 2];
775     else if (wordc_in == 2 && IS(words[w], "short"))
776       label = words[w + 1];
777     else if (wordc_in == 1
778           && strchr(words[w], '[') == NULL
779           && parse_reg(&tmplmod, words[w]) < 0)
780       label = words[w];
781
782     if (label != NULL) {
783       opr->type = OPT_LABEL;
784       ret = check_segment_prefix(label);
785       if (ret != 0) {
786         if (ret >= 5)
787           aerr("fs/gs used\n");
788         opr->had_ds = 1;
789         label += 3;
790       }
791       strcpy(opr->name, label);
792       return wordc;
793     }
794   }
795
796   if (wordc_in >= 3) {
797     if (IS(words[w + 1], "ptr")) {
798       if (IS(words[w], "dword"))
799         opr->lmod = OPLM_DWORD;
800       else if (IS(words[w], "word"))
801         opr->lmod = OPLM_WORD;
802       else if (IS(words[w], "byte"))
803         opr->lmod = OPLM_BYTE;
804       else if (IS(words[w], "qword"))
805         opr->lmod = OPLM_QWORD;
806       else
807         aerr("type parsing failed\n");
808       w += 2;
809       wordc_in = wordc - w;
810     }
811   }
812
813   if (wordc_in == 2) {
814     if (IS(words[w], "offset")) {
815       opr->type = OPT_OFFSET;
816       opr->lmod = OPLM_DWORD;
817       strcpy(opr->name, words[w + 1]);
818       pp = proto_parse(g_fhdr, opr->name, 1);
819       goto do_label;
820     }
821     if (IS(words[w], "(offset")) {
822       p = strchr(words[w + 1], ')');
823       if (p == NULL)
824         aerr("parse of bracketed offset failed\n");
825       *p = 0;
826       opr->type = OPT_OFFSET;
827       strcpy(opr->name, words[w + 1]);
828       return wordc;
829     }
830   }
831
832   if (wordc_in != 1)
833     aerr("parse_operand 1 word expected\n");
834
835   ret = check_segment_prefix(words[w]);
836   if (ret != 0) {
837     if (ret >= 5)
838       aerr("fs/gs used\n");
839     opr->had_ds = 1;
840     memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
841   }
842   strcpy(opr->name, words[w]);
843
844   if (words[w][0] == '[') {
845     opr->type = OPT_REGMEM;
846     ret = sscanf(words[w], "[%[^]]]", opr->name);
847     if (ret != 1)
848       aerr("[] parse failure\n");
849
850     parse_indmode(opr->name, regmask_indirect, 1);
851     if (opr->lmod == OPLM_UNSPEC
852       && parse_stack_el(opr->name, NULL, NULL, 1))
853     {
854       // might be an equ
855       struct parsed_equ *eq =
856         equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
857       if (eq)
858         opr->lmod = eq->lmod;
859
860       // might be unaligned access
861       g_func_lmods |= 1 << OPLM_BYTE;
862     }
863     return wordc;
864   }
865   else if (strchr(words[w], '[')) {
866     // label[reg] form
867     p = strchr(words[w], '[');
868     opr->type = OPT_REGMEM;
869     parse_indmode(p, regmask_indirect, 0);
870     strncpy(buf, words[w], p - words[w]);
871     buf[p - words[w]] = 0;
872     pp = proto_parse(g_fhdr, buf, 1);
873     goto do_label;
874   }
875   else if (('0' <= words[w][0] && words[w][0] <= '9')
876     || words[w][0] == '-')
877   {
878     number = parse_number(words[w], 0);
879     opr->type = OPT_CONST;
880     opr->val = number;
881     printf_number(opr->name, sizeof(opr->name), number);
882     return wordc;
883   }
884
885   ret = parse_reg(&tmplmod, opr->name);
886   if (ret >= 0) {
887     setup_reg_opr(opr, ret, tmplmod, regmask);
888     return wordc;
889   }
890
891   // most likely var in data segment
892   opr->type = OPT_LABEL;
893   pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
894
895 do_label:
896   if (pp != NULL) {
897     if (pp->is_fptr || pp->is_func) {
898       opr->lmod = OPLM_DWORD;
899       opr->is_ptr = 1;
900     }
901     else {
902       tmplmod = OPLM_UNSPEC;
903       if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
904         anote("unhandled C type '%s' for '%s'\n",
905           pp->type.name, opr->name);
906       
907       if (opr->lmod == OPLM_UNSPEC) {
908         opr->lmod = tmplmod;
909         opr->type_from_var = 1;
910       }
911       else if (opr->lmod != tmplmod) {
912         opr->size_mismatch = 1;
913         if (tmplmod < opr->lmod)
914           opr->size_lt = 1;
915       }
916       opr->is_ptr = pp->type.is_ptr;
917     }
918     opr->is_array = pp->type.is_array;
919   }
920   opr->pp = pp;
921
922   if (opr->lmod == OPLM_UNSPEC)
923     guess_lmod_from_name(opr);
924   return wordc;
925 }
926
927 static const struct {
928   const char *name;
929   unsigned int flags;
930 } pref_table[] = {
931   { "rep",    OPF_REP },
932   { "repe",   OPF_REP|OPF_REPZ },
933   { "repz",   OPF_REP|OPF_REPZ },
934   { "repne",  OPF_REP|OPF_REPNZ },
935   { "repnz",  OPF_REP|OPF_REPNZ },
936   { "lock",   OPF_LOCK }, // ignored for now..
937 };
938
939 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
940
941 static const struct {
942   const char *name;
943   enum op_op op;
944   unsigned short minopr;
945   unsigned short maxopr;
946   unsigned int flags;
947   unsigned char pfo;
948   unsigned char pfo_inv;
949 } op_table[] = {
950   { "nop",  OP_NOP,    0, 0, 0 },
951   { "push", OP_PUSH,   1, 1, 0 },
952   { "pop",  OP_POP,    1, 1, OPF_DATA },
953   { "pusha",OP_PUSHA,  0, 0, 0 },
954   { "popa", OP_POPA,   0, 0, OPF_DATA },
955   { "leave",OP_LEAVE,  0, 0, OPF_DATA },
956   { "mov" , OP_MOV,    2, 2, OPF_DATA },
957   { "lea",  OP_LEA,    2, 2, OPF_DATA },
958   { "movzx",OP_MOVZX,  2, 2, OPF_DATA },
959   { "movsx",OP_MOVSX,  2, 2, OPF_DATA },
960   { "xchg", OP_XCHG,   2, 2, OPF_DATA },
961   { "not",  OP_NOT,    1, 1, OPF_DATA },
962   { "xlat", OP_XLAT,   0, 0, OPF_DATA },
963   { "cdq",  OP_CDQ,    0, 0, OPF_DATA },
964   { "bswap",OP_BSWAP,  1, 1, OPF_DATA },
965   { "lodsb",OP_LODS,   0, 0, OPF_DATA },
966   { "lodsw",OP_LODS,   0, 0, OPF_DATA },
967   { "lodsd",OP_LODS,   0, 0, OPF_DATA },
968   { "stosb",OP_STOS,   0, 0, OPF_DATA },
969   { "stosw",OP_STOS,   0, 0, OPF_DATA },
970   { "stosd",OP_STOS,   0, 0, OPF_DATA },
971   { "movsb",OP_MOVS,   0, 0, OPF_DATA },
972   { "movsw",OP_MOVS,   0, 0, OPF_DATA },
973   { "movsd",OP_MOVS,   0, 0, OPF_DATA },
974   { "cmpsb",OP_CMPS,   0, 0, OPF_DATA|OPF_FLAGS },
975   { "cmpsw",OP_CMPS,   0, 0, OPF_DATA|OPF_FLAGS },
976   { "cmpsd",OP_CMPS,   0, 0, OPF_DATA|OPF_FLAGS },
977   { "scasb",OP_SCAS,   0, 0, OPF_DATA|OPF_FLAGS },
978   { "scasw",OP_SCAS,   0, 0, OPF_DATA|OPF_FLAGS },
979   { "scasd",OP_SCAS,   0, 0, OPF_DATA|OPF_FLAGS },
980   { "std",  OP_STD,    0, 0, OPF_DATA }, // special flag
981   { "cld",  OP_CLD,    0, 0, OPF_DATA },
982   { "add",  OP_ADD,    2, 2, OPF_DATA|OPF_FLAGS },
983   { "sub",  OP_SUB,    2, 2, OPF_DATA|OPF_FLAGS },
984   { "and",  OP_AND,    2, 2, OPF_DATA|OPF_FLAGS },
985   { "or",   OP_OR,     2, 2, OPF_DATA|OPF_FLAGS },
986   { "xor",  OP_XOR,    2, 2, OPF_DATA|OPF_FLAGS },
987   { "shl",  OP_SHL,    2, 2, OPF_DATA|OPF_FLAGS },
988   { "shr",  OP_SHR,    2, 2, OPF_DATA|OPF_FLAGS },
989   { "sal",  OP_SHL,    2, 2, OPF_DATA|OPF_FLAGS },
990   { "sar",  OP_SAR,    2, 2, OPF_DATA|OPF_FLAGS },
991   { "shld", OP_SHLD,   3, 3, OPF_DATA|OPF_FLAGS },
992   { "shrd", OP_SHRD,   3, 3, OPF_DATA|OPF_FLAGS },
993   { "rol",  OP_ROL,    2, 2, OPF_DATA|OPF_FLAGS },
994   { "ror",  OP_ROR,    2, 2, OPF_DATA|OPF_FLAGS },
995   { "rcl",  OP_RCL,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
996   { "rcr",  OP_RCR,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
997   { "adc",  OP_ADC,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
998   { "sbb",  OP_SBB,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
999   { "bsf",  OP_BSF,    2, 2, OPF_DATA|OPF_FLAGS },
1000   { "bsr",  OP_BSR,    2, 2, OPF_DATA|OPF_FLAGS },
1001   { "inc",  OP_INC,    1, 1, OPF_DATA|OPF_FLAGS },
1002   { "dec",  OP_DEC,    1, 1, OPF_DATA|OPF_FLAGS },
1003   { "neg",  OP_NEG,    1, 1, OPF_DATA|OPF_FLAGS },
1004   { "mul",  OP_MUL,    1, 1, OPF_DATA|OPF_FLAGS },
1005   { "imul", OP_IMUL,   1, 3, OPF_DATA|OPF_FLAGS },
1006   { "div",  OP_DIV,    1, 1, OPF_DATA|OPF_FLAGS },
1007   { "idiv", OP_IDIV,   1, 1, OPF_DATA|OPF_FLAGS },
1008   { "test", OP_TEST,   2, 2, OPF_FLAGS },
1009   { "cmp",  OP_CMP,    2, 2, OPF_FLAGS },
1010   { "retn", OP_RET,    0, 1, OPF_TAIL },
1011   { "call", OP_CALL,   1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
1012   { "jmp",  OP_JMP,    1, 1, OPF_JMP },
1013   { "jecxz",OP_JECXZ,  1, 1, OPF_JMP|OPF_CJMP },
1014   { "loop", OP_LOOP,   1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
1015   { "jo",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_O,  0 }, // 70 OF=1
1016   { "jno",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_O,  1 }, // 71 OF=0
1017   { "jc",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_C,  0 }, // 72 CF=1
1018   { "jb",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_C,  0 }, // 72
1019   { "jnc",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_C,  1 }, // 73 CF=0
1020   { "jnb",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_C,  1 }, // 73
1021   { "jae",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_C,  1 }, // 73
1022   { "jz",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_Z,  0 }, // 74 ZF=1
1023   { "je",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_Z,  0 }, // 74
1024   { "jnz",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_Z,  1 }, // 75 ZF=0
1025   { "jne",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_Z,  1 }, // 75
1026   { "jbe",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1027   { "jna",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1028   { "ja",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1029   { "jnbe", OP_JCC,    1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1030   { "js",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_S,  0 }, // 78 SF=1
1031   { "jns",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_S,  1 }, // 79 SF=0
1032   { "jp",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_P,  0 }, // 7a PF=1
1033   { "jpe",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_P,  0 }, // 7a
1034   { "jnp",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_P,  1 }, // 7b PF=0
1035   { "jpo",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_P,  1 }, // 7b
1036   { "jl",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_L,  0 }, // 7c SF!=OF
1037   { "jnge", OP_JCC,    1, 1, OPF_CJMP_CC, PFO_L,  0 }, // 7c
1038   { "jge",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_L,  1 }, // 7d SF=OF
1039   { "jnl",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_L,  1 }, // 7d
1040   { "jle",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1041   { "jng",  OP_JCC,    1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1042   { "jg",   OP_JCC,    1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1043   { "jnle", OP_JCC,    1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1044   { "seto",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_O,  0 },
1045   { "setno",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_O,  1 },
1046   { "setc",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_C,  0 },
1047   { "setb",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_C,  0 },
1048   { "setnc",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_C,  1 },
1049   { "setae",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_C,  1 },
1050   { "setnb",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_C,  1 },
1051   { "setz",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_Z,  0 },
1052   { "sete",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_Z,  0 },
1053   { "setnz",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_Z,  1 },
1054   { "setne",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_Z,  1 },
1055   { "setbe",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1056   { "setna",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1057   { "seta",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1058   { "setnbe", OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1059   { "sets",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_S,  0 },
1060   { "setns",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_S,  1 },
1061   { "setp",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_P,  0 },
1062   { "setpe",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_P,  0 },
1063   { "setnp",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_P,  1 },
1064   { "setpo",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_P,  1 },
1065   { "setl",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_L,  0 },
1066   { "setnge", OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_L,  0 },
1067   { "setge",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_L,  1 },
1068   { "setnl",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_L,  1 },
1069   { "setle",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1070   { "setng",  OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1071   { "setg",   OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1072   { "setnle", OP_SCC,  1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1073   // x87
1074   { "fld",    OP_FLD,    1, 1, OPF_FPUSH },
1075   { "fild",   OP_FILD,   1, 1, OPF_FPUSH|OPF_FINT },
1076   { "fld1",   OP_FLDc,   0, 0, OPF_FPUSH },
1077   { "fldln2", OP_FLDc,   0, 0, OPF_FPUSH },
1078   { "fldz",   OP_FLDc,   0, 0, OPF_FPUSH },
1079   { "fst",    OP_FST,    1, 1, 0 },
1080   { "fstp",   OP_FST,    1, 1, OPF_FPOP },
1081   { "fist",   OP_FIST,   1, 1, OPF_FINT },
1082   { "fistp",  OP_FIST,   1, 1, OPF_FPOP|OPF_FINT },
1083   { "fadd",   OP_FADD,   0, 2, 0 },
1084   { "faddp",  OP_FADD,   0, 2, OPF_FPOP },
1085   { "fdiv",   OP_FDIV,   0, 2, 0 },
1086   { "fdivp",  OP_FDIV,   0, 2, OPF_FPOP },
1087   { "fmul",   OP_FMUL,   0, 2, 0 },
1088   { "fmulp",  OP_FMUL,   0, 2, OPF_FPOP },
1089   { "fsub",   OP_FSUB,   0, 2, 0 },
1090   { "fsubp",  OP_FSUB,   0, 2, OPF_FPOP },
1091   { "fdivr",  OP_FDIVR,  0, 2, 0 },
1092   { "fdivrp", OP_FDIVR,  0, 2, OPF_FPOP },
1093   { "fsubr",  OP_FSUBR,  0, 2, 0 },
1094   { "fsubrp", OP_FSUBR,  0, 2, OPF_FPOP },
1095   { "fiadd",  OP_FIADD,  1, 1, OPF_FINT },
1096   { "fidiv",  OP_FIDIV,  1, 1, OPF_FINT },
1097   { "fimul",  OP_FIMUL,  1, 1, OPF_FINT },
1098   { "fisub",  OP_FISUB,  1, 1, OPF_FINT },
1099   { "fidivr", OP_FIDIVR, 1, 1, OPF_FINT },
1100   { "fisubr", OP_FISUBR, 1, 1, OPF_FINT },
1101   { "fcom",   OP_FCOM,   0, 1, 0 },
1102   { "fcomp",  OP_FCOM,   0, 1, OPF_FPOP },
1103   { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1104   { "fchs",   OP_FCHS,   0, 0, 0 },
1105   { "fcos",   OP_FCOS,   0, 0, 0 },
1106   { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1107   { "fptan",  OP_FPTAN,  0, 0, OPF_FPUSH },
1108   { "fsin",   OP_FSIN,   0, 0, 0 },
1109   { "fsqrt",  OP_FSQRT,  0, 0, 0 },
1110   { "fxch",   OP_FXCH,   1, 1, 0 },
1111   { "fyl2x",  OP_FYL2X,  0, 0, OPF_FPOP },
1112   // mmx
1113   { "emms",   OP_EMMS,   0, 0, OPF_DATA },
1114   { "movq",   OP_MOV,    2, 2, OPF_DATA },
1115   // pseudo-ops for lib calls
1116   { "_allshl",OPP_ALLSHL },
1117   { "_allshr",OPP_ALLSHR },
1118   { "_ftol",  OPP_FTOL },
1119   { "_CIpow", OPP_CIPOW },
1120   { "abort",  OPP_ABORT },
1121   // must be last
1122   { "ud2",    OP_UD2 },
1123 };
1124
1125 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1126 {
1127   enum opr_lenmod lmod = OPLM_UNSPEC;
1128   int prefix_flags = 0;
1129   int regmask_ind;
1130   int regmask;
1131   int op_w = 0;
1132   int opr = 0;
1133   int w = 0;
1134   int i, j;
1135
1136   for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1137     if (IS(words[w], pref_table[i].name)) {
1138       prefix_flags = pref_table[i].flags;
1139       break;
1140     }
1141   }
1142
1143   if (prefix_flags) {
1144     if (wordc <= 1)
1145       aerr("lone prefix: '%s'\n", words[0]);
1146     w++;
1147   }
1148
1149   op_w = w;
1150   for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1151     if (IS(words[w], op_table[i].name))
1152       break;
1153   }
1154
1155   if (i == ARRAY_SIZE(op_table)) {
1156     if (!g_skip_func)
1157       aerr("unhandled op: '%s'\n", words[0]);
1158     i--; // OP_UD2
1159   }
1160   w++;
1161
1162   op->op = op_table[i].op;
1163   op->flags = op_table[i].flags | prefix_flags;
1164   op->pfo = op_table[i].pfo;
1165   op->pfo_inv = op_table[i].pfo_inv;
1166   op->regmask_src = op->regmask_dst = 0;
1167   op->asmln = asmln;
1168
1169   if (op->op == OP_UD2)
1170     return;
1171
1172   for (opr = 0; opr < op_table[i].maxopr; opr++) {
1173     if (opr >= op_table[i].minopr && w >= wordc)
1174       break;
1175
1176     regmask = regmask_ind = 0;
1177     w = parse_operand(&op->operand[opr], &regmask, &regmask_ind,
1178       words, wordc, w, op->flags);
1179
1180     if (opr == 0 && (op->flags & OPF_DATA))
1181       op->regmask_dst = regmask;
1182     else
1183       op->regmask_src |= regmask;
1184     op->regmask_src |= regmask_ind;
1185
1186     if (op->operand[opr].lmod != OPLM_UNSPEC)
1187       g_func_lmods |= 1 << op->operand[opr].lmod;
1188   }
1189
1190   if (w < wordc)
1191     aerr("parse_op %s incomplete: %d/%d\n",
1192       words[0], w, wordc);
1193
1194   // special cases
1195   op->operand_cnt = opr;
1196   if (!strncmp(op_table[i].name, "set", 3))
1197     op->operand[0].lmod = OPLM_BYTE;
1198
1199   switch (op->op) {
1200   // first operand is not dst
1201   case OP_CMP:
1202   case OP_TEST:
1203     op->regmask_src |= op->regmask_dst;
1204     op->regmask_dst = 0;
1205     break;
1206
1207   // first operand is src too
1208   case OP_NOT:
1209   case OP_ADD:
1210   case OP_AND:
1211   case OP_OR:
1212   case OP_RCL:
1213   case OP_RCR:
1214   case OP_ADC:
1215   case OP_INC:
1216   case OP_DEC:
1217   case OP_NEG:
1218   case OP_BSWAP:
1219   // more below..
1220     op->regmask_src |= op->regmask_dst;
1221     break;
1222
1223   // special
1224   case OP_XCHG:
1225     op->regmask_src |= op->regmask_dst;
1226     op->regmask_dst |= op->regmask_src;
1227     goto check_align;
1228
1229   case OP_SUB:
1230   case OP_SBB:
1231   case OP_XOR:
1232     if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1233      && op->operand[0].lmod == op->operand[1].lmod
1234      && op->operand[0].reg == op->operand[1].reg
1235      && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1236     {
1237       op->regmask_src = 0;
1238     }
1239     else
1240       op->regmask_src |= op->regmask_dst;
1241     break;
1242
1243   // ops with implicit argumets
1244   case OP_XLAT:
1245     op->operand_cnt = 2;
1246     setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1247     op->regmask_dst = op->regmask_src;
1248     setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1249     break;
1250
1251   case OP_CDQ:
1252     op->operand_cnt = 2;
1253     setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1254     setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1255     break;
1256
1257   case OP_LODS:
1258   case OP_STOS:
1259   case OP_SCAS:
1260     if      (words[op_w][4] == 'b')
1261       lmod = OPLM_BYTE;
1262     else if (words[op_w][4] == 'w')
1263       lmod = OPLM_WORD;
1264     else if (words[op_w][4] == 'd')
1265       lmod = OPLM_DWORD;
1266     j = 0;
1267     op->regmask_src = 0;
1268     setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1269       OPLM_DWORD, &op->regmask_src);
1270     op->regmask_dst = op->regmask_src;
1271     setup_reg_opr(&op->operand[j++], xAX, lmod,
1272       op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1273     if (op->flags & OPF_REP) {
1274       setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1275       op->regmask_dst |= 1 << xCX;
1276     }
1277     op->operand_cnt = j;
1278     break;
1279
1280   case OP_MOVS:
1281   case OP_CMPS:
1282     if      (words[op_w][4] == 'b')
1283       lmod = OPLM_BYTE;
1284     else if (words[op_w][4] == 'w')
1285       lmod = OPLM_WORD;
1286     else if (words[op_w][4] == 'd')
1287       lmod = OPLM_DWORD;
1288     j = 0;
1289     op->regmask_src = 0;
1290     // note: lmod is not correct, don't have where to place it
1291     setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1292     setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1293     if (op->flags & OPF_REP)
1294       setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1295     op->operand_cnt = j;
1296     op->regmask_dst = op->regmask_src;
1297     break;
1298
1299   case OP_LOOP:
1300     op->regmask_dst = 1 << xCX;
1301     // fallthrough
1302   case OP_JECXZ:
1303     op->operand_cnt = 2;
1304     op->regmask_src = 1 << xCX;
1305     op->operand[1].type = OPT_REG;
1306     op->operand[1].reg = xCX;
1307     op->operand[1].lmod = OPLM_DWORD;
1308     break;
1309
1310   case OP_IMUL:
1311     if (op->operand_cnt == 2) {
1312       if (op->operand[0].type != OPT_REG)
1313         aerr("reg expected\n");
1314       op->regmask_src |= 1 << op->operand[0].reg;
1315     }
1316     if (op->operand_cnt != 1)
1317       break;
1318     // fallthrough
1319   case OP_MUL:
1320     // singleop mul
1321     op->regmask_src |= op->regmask_dst;
1322     op->regmask_dst = (1 << xDX) | (1 << xAX);
1323     if (op->operand[0].lmod == OPLM_UNSPEC)
1324       op->operand[0].lmod = OPLM_DWORD;
1325     break;
1326
1327   case OP_DIV:
1328   case OP_IDIV:
1329     // we could set up operands for edx:eax, but there is no real need to
1330     // (see is_opr_modified())
1331     op->regmask_src |= op->regmask_dst;
1332     op->regmask_dst = (1 << xDX) | (1 << xAX);
1333     if (op->operand[0].lmod == OPLM_UNSPEC)
1334       op->operand[0].lmod = OPLM_DWORD;
1335     break;
1336
1337   case OP_SHL:
1338   case OP_SHR:
1339   case OP_SAR:
1340   case OP_ROL:
1341   case OP_ROR:
1342     op->regmask_src |= op->regmask_dst;
1343     if (op->operand[1].lmod == OPLM_UNSPEC)
1344       op->operand[1].lmod = OPLM_BYTE;
1345     break;
1346
1347   case OP_SHLD:
1348   case OP_SHRD:
1349     op->regmask_src |= op->regmask_dst;
1350     if (op->operand[2].lmod == OPLM_UNSPEC)
1351       op->operand[2].lmod = OPLM_BYTE;
1352     break;
1353
1354   case OP_PUSH:
1355     op->regmask_src |= op->regmask_dst;
1356     op->regmask_dst = 0;
1357     if (op->operand[0].lmod == OPLM_UNSPEC
1358         && (op->operand[0].type == OPT_CONST
1359          || op->operand[0].type == OPT_OFFSET
1360          || op->operand[0].type == OPT_LABEL))
1361       op->operand[0].lmod = OPLM_DWORD;
1362     break;
1363
1364   // alignment
1365   case OP_MOV:
1366   check_align:
1367     if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1368      && op->operand[0].lmod == op->operand[1].lmod
1369      && op->operand[0].reg == op->operand[1].reg
1370      && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1371     {
1372       op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1373       op->regmask_src = op->regmask_dst = 0;
1374     }
1375     break;
1376
1377   case OP_LEA:
1378     if (op->operand[0].type == OPT_REG
1379      && op->operand[1].type == OPT_REGMEM)
1380     {
1381       char buf[16];
1382       snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1383       if (IS(buf, op->operand[1].name))
1384         op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1385     }
1386     break;
1387
1388   case OP_CALL:
1389     // trashed regs must be explicitly detected later
1390     op->regmask_dst = 0;
1391     break;
1392
1393   case OP_LEAVE:
1394     op->regmask_dst = (1 << xBP) | (1 << xSP);
1395     op->regmask_src =  1 << xBP;
1396     break;
1397
1398   case OP_FLD:
1399   case OP_FILD:
1400     op->regmask_dst |= mxST0;
1401     break;
1402
1403   case OP_FLDc:
1404     op->regmask_dst |= mxST0;
1405     if      (IS(words[op_w] + 3, "1"))
1406       op->operand[0].val = X87_CONST_1;
1407     else if (IS(words[op_w] + 3, "ln2"))
1408       op->operand[0].val = X87_CONST_LN2;
1409     else if (IS(words[op_w] + 3, "z"))
1410       op->operand[0].val = X87_CONST_Z;
1411     else
1412       aerr("TODO\n");
1413     break;
1414
1415   case OP_FST:
1416   case OP_FIST:
1417     op->regmask_src |= mxST0;
1418     break;
1419
1420   case OP_FADD:
1421   case OP_FDIV:
1422   case OP_FMUL:
1423   case OP_FSUB:
1424   case OP_FDIVR:
1425   case OP_FSUBR:
1426     op->regmask_src |= mxST0;
1427     if (op->operand_cnt == 2)
1428       op->regmask_src |= op->regmask_dst;
1429     else if (op->operand_cnt == 1) {
1430       memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1431       op->operand[0].type = OPT_REG;
1432       op->operand[0].lmod = OPLM_QWORD;
1433       op->operand[0].reg = xST0;
1434       op->regmask_dst |= mxST0;
1435     }
1436     else
1437       // IDA doesn't use this
1438       aerr("no operands?\n");
1439     break;
1440
1441   case OP_FIADD:
1442   case OP_FIDIV:
1443   case OP_FIMUL:
1444   case OP_FISUB:
1445   case OP_FIDIVR:
1446   case OP_FISUBR:
1447   case OP_FCHS:
1448   case OP_FCOS:
1449   case OP_FSIN:
1450   case OP_FSQRT:
1451   case OP_FXCH:
1452     op->regmask_src |= mxST0;
1453     op->regmask_dst |= mxST0;
1454     break;
1455
1456   case OP_FPATAN:
1457   case OP_FYL2X:
1458     op->regmask_src |= mxST0 | mxST1;
1459     op->regmask_dst |= mxST0;
1460     break;
1461
1462   case OP_FPTAN:
1463     aerr("TODO\n");
1464     break;
1465
1466   case OP_FCOM:
1467     op->regmask_src |= mxST0;
1468     break;
1469
1470   default:
1471     break;
1472   }
1473
1474   if (op->operand[0].type == OPT_REG
1475    && op->operand[1].type == OPT_CONST)
1476   {
1477     struct parsed_opr *op1 = &op->operand[1];
1478     if ((op->op == OP_AND && op1->val == 0)
1479      || (op->op == OP_OR
1480       && (op1->val == ~0
1481        || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1482        || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1483     {
1484       op->regmask_src = 0;
1485     }
1486   }
1487 }
1488
1489 static const char *op_name(struct parsed_op *po)
1490 {
1491   static char buf[16];
1492   char *p;
1493   int i;
1494
1495   if (po->op == OP_JCC || po->op == OP_SCC) {
1496     p = buf;
1497     *p++ = (po->op == OP_JCC) ? 'j' : 's';
1498     if (po->pfo_inv)
1499       *p++ = 'n';
1500     strcpy(p, parsed_flag_op_names[po->pfo]);
1501     return buf;
1502   }
1503
1504   for (i = 0; i < ARRAY_SIZE(op_table); i++)
1505     if (op_table[i].op == po->op)
1506       return op_table[i].name;
1507
1508   return "???";
1509 }
1510
1511 // debug
1512 static const char *dump_op(struct parsed_op *po)
1513 {
1514   static char out[128];
1515   char *p = out;
1516   int i;
1517
1518   if (po == NULL)
1519     return "???";
1520
1521   snprintf(out, sizeof(out), "%s", op_name(po));
1522   for (i = 0; i < po->operand_cnt; i++) {
1523     p += strlen(p);
1524     if (i > 0)
1525       *p++ = ',';
1526     snprintf(p, sizeof(out) - (p - out),
1527       po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1528       po->operand[i].name);
1529   }
1530
1531   return out;
1532 }
1533
1534 static const char *lmod_type_u(struct parsed_op *po,
1535   enum opr_lenmod lmod)
1536 {
1537   switch (lmod) {
1538   case OPLM_QWORD:
1539     return "u64";
1540   case OPLM_DWORD:
1541     return "u32";
1542   case OPLM_WORD:
1543     return "u16";
1544   case OPLM_BYTE:
1545     return "u8";
1546   default:
1547     ferr(po, "invalid lmod: %d\n", lmod);
1548     return "(_invalid_)";
1549   }
1550 }
1551
1552 static const char *lmod_cast_u(struct parsed_op *po,
1553   enum opr_lenmod lmod)
1554 {
1555   switch (lmod) {
1556   case OPLM_QWORD:
1557     return "";
1558   case OPLM_DWORD:
1559     return "";
1560   case OPLM_WORD:
1561     return "(u16)";
1562   case OPLM_BYTE:
1563     return "(u8)";
1564   default:
1565     ferr(po, "invalid lmod: %d\n", lmod);
1566     return "(_invalid_)";
1567   }
1568 }
1569
1570 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1571   enum opr_lenmod lmod)
1572 {
1573   switch (lmod) {
1574   case OPLM_QWORD:
1575     return "*(u64 *)";
1576   case OPLM_DWORD:
1577     return "*(u32 *)";
1578   case OPLM_WORD:
1579     return "*(u16 *)";
1580   case OPLM_BYTE:
1581     return "*(u8 *)";
1582   default:
1583     ferr(po, "invalid lmod: %d\n", lmod);
1584     return "(_invalid_)";
1585   }
1586 }
1587
1588 static const char *lmod_cast_s(struct parsed_op *po,
1589   enum opr_lenmod lmod)
1590 {
1591   switch (lmod) {
1592   case OPLM_QWORD:
1593     return "(s64)";
1594   case OPLM_DWORD:
1595     return "(s32)";
1596   case OPLM_WORD:
1597     return "(s16)";
1598   case OPLM_BYTE:
1599     return "(s8)";
1600   default:
1601     ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1602     return "(_invalid_)";
1603   }
1604 }
1605
1606 static const char *lmod_cast(struct parsed_op *po,
1607   enum opr_lenmod lmod, int is_signed)
1608 {
1609   return is_signed ?
1610     lmod_cast_s(po, lmod) :
1611     lmod_cast_u(po, lmod);
1612 }
1613
1614 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1615 {
1616   switch (lmod) {
1617   case OPLM_QWORD:
1618     return 8;
1619   case OPLM_DWORD:
1620     return 4;
1621   case OPLM_WORD:
1622     return 2;
1623   case OPLM_BYTE:
1624     return 1;
1625   default:
1626     ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1627     return 0;
1628   }
1629 }
1630
1631 static const char *opr_name(struct parsed_op *po, int opr_num)
1632 {
1633   if (opr_num >= po->operand_cnt)
1634     ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1635   return po->operand[opr_num].name;
1636 }
1637
1638 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1639 {
1640   if (opr_num >= po->operand_cnt)
1641     ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1642   if (po->operand[opr_num].type != OPT_CONST)
1643     ferr(po, "opr %d: const expected\n", opr_num);
1644   return po->operand[opr_num].val;
1645 }
1646
1647 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1648 {
1649   if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1650     ferr(po, "invalid reg: %d\n", popr->reg);
1651   return regs_r32[popr->reg];
1652 }
1653
1654 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1655 {
1656   if      (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1657     *bits = 8;
1658   else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1659     *bits = 16;
1660   else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1661     *bits = 32;
1662   else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1663     *bits = 64;
1664   else
1665     return -1;
1666
1667   *is_signed = cast[1] == 's' ? 1 : 0;
1668   return 0;
1669 }
1670
1671 static int check_deref_cast(const char *cast, int *bits)
1672 {
1673   if      (IS_START(cast, "*(u8 *)"))
1674     *bits = 8;
1675   else if (IS_START(cast, "*(u16 *)"))
1676     *bits = 16;
1677   else if (IS_START(cast, "*(u32 *)"))
1678     *bits = 32;
1679   else if (IS_START(cast, "*(u64 *)"))
1680     *bits = 64;
1681   else
1682     return -1;
1683
1684   return 0;
1685 }
1686
1687 // cast1 is the "final" cast
1688 static const char *simplify_cast(const char *cast1, const char *cast2)
1689 {
1690   static char buf[256];
1691   int bits1, bits2;
1692   int s1, s2;
1693
1694   if (cast1[0] == 0)
1695     return cast2;
1696   if (cast2[0] == 0)
1697     return cast1;
1698   if (IS(cast1, cast2))
1699     return cast1;
1700
1701   if (check_simple_cast(cast1, &bits1, &s1) == 0
1702     && check_simple_cast(cast2, &bits2, &s2) == 0)
1703   {
1704     if (bits1 <= bits2)
1705       return cast1;
1706   }
1707   if (check_simple_cast(cast1, &bits1, &s1) == 0
1708     && check_deref_cast(cast2, &bits2) == 0)
1709   {
1710     if (bits1 == bits2) {
1711       snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1712       return buf;
1713     }
1714   }
1715
1716   if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1717     return cast1;
1718
1719   snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1720   return buf;
1721 }
1722
1723 static const char *simplify_cast_num(const char *cast, unsigned int val)
1724 {
1725   if (IS(cast, "(u8)") && val < 0x100)
1726     return "";
1727   if (IS(cast, "(s8)") && val < 0x80)
1728     return "";
1729   if (IS(cast, "(u16)") && val < 0x10000)
1730     return "";
1731   if (IS(cast, "(s16)") && val < 0x8000)
1732     return "";
1733   if (IS(cast, "(s32)") && val < 0x80000000)
1734     return "";
1735
1736   return cast;
1737 }
1738
1739 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1740   int *extra_offs)
1741 {
1742   const char *p;
1743   char *endp;
1744   int namelen;
1745   int i;
1746
1747   *extra_offs = 0;
1748   namelen = strlen(name);
1749
1750   p = strpbrk(name, "+-");
1751   if (p != NULL) {
1752     namelen = p - name;
1753     if (namelen <= 0)
1754       ferr(po, "equ parse failed for '%s'\n", name);
1755
1756     errno = 0;
1757     *extra_offs = strtol(p, &endp, 16);
1758     if (*endp != 0 || errno != 0)
1759       ferr(po, "equ parse failed for '%s'\n", name);
1760   }
1761
1762   for (i = 0; i < g_eqcnt; i++)
1763     if (strncmp(g_eqs[i].name, name, namelen) == 0
1764      && g_eqs[i].name[namelen] == 0)
1765       break;
1766   if (i >= g_eqcnt) {
1767     if (po != NULL)
1768       ferr(po, "unresolved equ name: '%s'\n", name);
1769     return NULL;
1770   }
1771
1772   return &g_eqs[i];
1773 }
1774
1775 static int is_stack_access(struct parsed_op *po,
1776   const struct parsed_opr *popr)
1777 {
1778   return (parse_stack_el(popr->name, NULL, NULL, 0)
1779     || (g_bp_frame && !(po->flags & OPF_EBP_S)
1780         && IS_START(popr->name, "ebp")));
1781 }
1782
1783 static void parse_stack_access(struct parsed_op *po,
1784   const char *name, char *ofs_reg, int *offset_out,
1785   int *stack_ra_out, const char **bp_arg_out, int is_lea)
1786 {
1787   const char *bp_arg = "";
1788   const char *p = NULL;
1789   struct parsed_equ *eq;
1790   char *endp = NULL;
1791   int stack_ra = 0;
1792   int offset = 0;
1793
1794   ofs_reg[0] = 0;
1795
1796   if (IS_START(name, "ebp-")
1797    || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1798   {
1799     p = name + 4;
1800     if (IS_START(p, "0x"))
1801       p += 2;
1802     errno = 0;
1803     offset = strtoul(p, &endp, 16);
1804     if (name[3] == '-')
1805       offset = -offset;
1806     if (*endp != 0 || errno != 0)
1807       ferr(po, "ebp- parse of '%s' failed\n", name);
1808   }
1809   else {
1810     bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1811     eq = equ_find(po, bp_arg, &offset);
1812     if (eq == NULL)
1813       ferr(po, "detected but missing eq\n");
1814     offset += eq->offset;
1815   }
1816
1817   if (!strncmp(name, "ebp", 3))
1818     stack_ra = 4;
1819
1820   // yes it sometimes LEAs ra for compares..
1821   if (!is_lea && ofs_reg[0] == 0
1822     && stack_ra <= offset && offset < stack_ra + 4)
1823   {
1824     ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1825   }
1826
1827   *offset_out = offset;
1828   if (stack_ra_out)
1829     *stack_ra_out = stack_ra;
1830   if (bp_arg_out)
1831     *bp_arg_out = bp_arg;
1832 }
1833
1834 static int parse_stack_esp_offset(struct parsed_op *po,
1835   const char *name, int *offset_out)
1836 {
1837   char ofs_reg[16] = { 0, };
1838   struct parsed_equ *eq;
1839   const char *bp_arg;
1840   char *endp = NULL;
1841   int base_val = 0;
1842   int offset = 0;
1843
1844   if (strstr(name, "esp") == NULL)
1845     return -1;
1846   bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1847   if (bp_arg == NULL) {
1848     // just plain offset?
1849     if (!IS_START(name, "esp+"))
1850       return -1;
1851     errno = 0;
1852     offset = strtol(name + 4, &endp, 0);
1853     if (endp == NULL || *endp != 0 || errno != 0)
1854       return -1;
1855     *offset_out = offset;
1856     return 0;
1857   }
1858
1859   if (ofs_reg[0] != 0)
1860     return -1;
1861   eq = equ_find(po, bp_arg, &offset);
1862   if (eq == NULL)
1863     ferr(po, "detected but missing eq\n");
1864   offset += eq->offset;
1865   *offset_out = base_val + offset;
1866   return 0;
1867 }
1868
1869 static int stack_frame_access(struct parsed_op *po,
1870   struct parsed_opr *popr, char *buf, size_t buf_size,
1871   const char *name, const char *cast, int is_src, int is_lea)
1872 {
1873   enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1874   const char *prefix = "";
1875   const char *bp_arg = NULL;
1876   char ofs_reg[16] = { 0, };
1877   int i, arg_i, arg_s;
1878   int unaligned = 0;
1879   int stack_ra = 0;
1880   int offset = 0;
1881   int retval = -1;
1882   int sf_ofs;
1883
1884   if (g_bp_frame && (po->flags & OPF_EBP_S)
1885       && !(po->regmask_src & mxSP))
1886     ferr(po, "stack_frame_access while ebp is scratch\n");
1887
1888   parse_stack_access(po, name, ofs_reg, &offset,
1889     &stack_ra, &bp_arg, is_lea);
1890
1891   snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1892
1893   if (offset > stack_ra)
1894   {
1895     arg_i = (offset - stack_ra - 4) / 4;
1896     if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1897     {
1898       if (g_func_pp->is_vararg
1899           && arg_i == g_func_pp->argc_stack && is_lea)
1900       {
1901         // should be va_list
1902         if (cast[0] == 0)
1903           cast = "(u32)";
1904         snprintf(buf, buf_size, "%sap", cast);
1905         return -1;
1906       }
1907       ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1908         offset, bp_arg, arg_i);
1909     }
1910     if (ofs_reg[0] != 0)
1911       ferr(po, "offset reg on arg access?\n");
1912
1913     for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1914       if (g_func_pp->arg[i].reg != NULL)
1915         continue;
1916       if (arg_s == arg_i)
1917         break;
1918       arg_s++;
1919     }
1920     if (i == g_func_pp->argc)
1921       ferr(po, "arg %d not in prototype?\n", arg_i);
1922
1923     popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1924     retval = i;
1925
1926     switch (popr->lmod)
1927     {
1928     case OPLM_BYTE:
1929       if (is_lea)
1930         ferr(po, "lea/byte to arg?\n");
1931       if (is_src && (offset & 3) == 0)
1932         snprintf(buf, buf_size, "%sa%d",
1933           simplify_cast(cast, "(u8)"), i + 1);
1934       else
1935         snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1936           cast, offset & 3, i + 1);
1937       break;
1938
1939     case OPLM_WORD:
1940       if (is_lea)
1941         ferr(po, "lea/word to arg?\n");
1942       if (offset & 1) {
1943         unaligned = 1;
1944         if (!is_src) {
1945           if (offset & 2)
1946             ferr(po, "problematic arg store\n");
1947           snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1948             simplify_cast(cast, "*(u16 *)"), i + 1);
1949         }
1950         else
1951           ferr(po, "unaligned arg word load\n");
1952       }
1953       else if (is_src && (offset & 2) == 0)
1954         snprintf(buf, buf_size, "%sa%d",
1955           simplify_cast(cast, "(u16)"), i + 1);
1956       else
1957         snprintf(buf, buf_size, "%s%sWORD(a%d)",
1958           cast, (offset & 2) ? "HI" : "LO", i + 1);
1959       break;
1960
1961     case OPLM_DWORD:
1962       if (cast[0])
1963         prefix = cast;
1964       else if (is_src)
1965         prefix = "(u32)";
1966
1967       if (offset & 3) {
1968         unaligned = 1;
1969         if (is_lea)
1970           snprintf(buf, buf_size, "(u32)&a%d + %d",
1971             i + 1, offset & 3);
1972         else if (!is_src)
1973           ferr(po, "unaligned arg store\n");
1974         else {
1975           // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1976           snprintf(buf, buf_size, "%s(a%d >> %d)",
1977             prefix, i + 1, (offset & 3) * 8);
1978         }
1979       }
1980       else {
1981         snprintf(buf, buf_size, "%s%sa%d",
1982           prefix, is_lea ? "&" : "", i + 1);
1983       }
1984       break;
1985
1986     case OPLM_QWORD:
1987       ferr_assert(po, !(offset & 7));
1988       if (cast[0])
1989         prefix = cast;
1990       snprintf(buf, buf_size, "%s%sa%d",
1991         prefix, is_lea ? "&" : "", i + 1);
1992       break;
1993
1994     default:
1995       ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1996     }
1997
1998     if (unaligned)
1999       strcat(g_comment, " unaligned");
2000
2001     // common problem
2002     guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
2003     if (tmp_lmod != OPLM_DWORD
2004       && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
2005                          < lmod_bytes(po, popr->lmod) + (offset & 3))))
2006     {
2007       ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
2008         i + 1, offset, g_func_pp->arg[i].type.name);
2009     }
2010     // can't check this because msvc likes to reuse
2011     // arg space for scratch..
2012     //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
2013     //  ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2014   }
2015   else
2016   {
2017     if (g_stack_fsz == 0)
2018       ferr(po, "stack var access without stackframe\n");
2019     g_stack_frame_used = 1;
2020
2021     sf_ofs = g_stack_fsz + offset;
2022     if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2023       ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2024
2025     if (is_lea)
2026       prefix = "(u32)&";
2027     else
2028       prefix = cast;
2029
2030     switch (popr->lmod)
2031     {
2032     case OPLM_BYTE:
2033       snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2034         prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2035       break;
2036
2037     case OPLM_WORD:
2038       if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2039         // known unaligned or possibly unaligned
2040         strcat(g_comment, " unaligned");
2041         if (prefix[0] == 0)
2042           prefix = "*(u16 *)&";
2043         snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2044           prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2045         break;
2046       }
2047       snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2048       break;
2049
2050     case OPLM_DWORD:
2051       if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2052         // known unaligned or possibly unaligned
2053         strcat(g_comment, " unaligned");
2054         if (prefix[0] == 0)
2055           prefix = "*(u32 *)&";
2056         snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2057           prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2058         break;
2059       }
2060       snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2061       break;
2062
2063     case OPLM_QWORD:
2064       ferr_assert(po, !(sf_ofs & 7));
2065       ferr_assert(po, ofs_reg[0] == 0);
2066       // only used for x87 int64/float, float sets is_lea
2067       if (!is_lea && (po->flags & OPF_FINT))
2068         prefix = "*(s64 *)&";
2069       snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2070       break;
2071
2072     default:
2073       ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2074     }
2075   }
2076
2077   return retval;
2078 }
2079
2080 static void check_func_pp(struct parsed_op *po,
2081   const struct parsed_proto *pp, const char *pfx)
2082 {
2083   enum opr_lenmod tmp_lmod;
2084   char buf[256];
2085   int ret, i;
2086
2087   if (pp->argc_reg != 0) {
2088     if (!g_allow_user_icall && !pp->is_fastcall) {
2089       pp_print(buf, sizeof(buf), pp);
2090       ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2091     }
2092     if (pp->argc_stack > 0 && pp->argc_reg != 2)
2093       ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2094         pfx, pp->argc_reg, pp->argc_stack);
2095   }
2096
2097   // fptrs must use 32bit args, callsite might have no information and
2098   // lack a cast to smaller types, which results in incorrectly masked
2099   // args passed (callee may assume masked args, it does on ARM)
2100   if (!pp->is_osinc) {
2101     for (i = 0; i < pp->argc; i++) {
2102       ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2103       if (ret && tmp_lmod != OPLM_DWORD)
2104         ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2105           i + 1, pp->arg[i].type.name);
2106     }
2107   }
2108 }
2109
2110 static const char *check_label_read_ref(struct parsed_op *po,
2111   const char *name)
2112 {
2113   const struct parsed_proto *pp;
2114
2115   pp = proto_parse(g_fhdr, name, 0);
2116   if (pp == NULL)
2117     ferr(po, "proto_parse failed for ref '%s'\n", name);
2118
2119   if (pp->is_func)
2120     check_func_pp(po, pp, "ref");
2121
2122   return pp->name;
2123 }
2124
2125 static char *out_src_opr(char *buf, size_t buf_size,
2126   struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2127   int is_lea)
2128 {
2129   char tmp1[256], tmp2[256];
2130   char expr[256];
2131   const char *name;
2132   char *p;
2133   int ret;
2134
2135   if (cast == NULL)
2136     cast = "";
2137
2138   switch (popr->type) {
2139   case OPT_REG:
2140     if (is_lea)
2141       ferr(po, "lea from reg?\n");
2142
2143     switch (popr->lmod) {
2144     case OPLM_QWORD:
2145       snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2146       break;
2147     case OPLM_DWORD:
2148       snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2149       break;
2150     case OPLM_WORD:
2151       snprintf(buf, buf_size, "%s%s",
2152         simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2153       break;
2154     case OPLM_BYTE:
2155       if (popr->name[1] == 'h') // XXX..
2156         snprintf(buf, buf_size, "%s(%s >> 8)",
2157           simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2158       else
2159         snprintf(buf, buf_size, "%s%s",
2160           simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2161       break;
2162     default:
2163       ferr(po, "invalid src lmod: %d\n", popr->lmod);
2164     }
2165     break;
2166
2167   case OPT_REGMEM:
2168     if (is_stack_access(po, popr)) {
2169       stack_frame_access(po, popr, buf, buf_size,
2170         popr->name, cast, 1, is_lea);
2171       break;
2172     }
2173
2174     strcpy(expr, popr->name);
2175     if (strchr(expr, '[')) {
2176       // special case: '[' can only be left for label[reg] form
2177       ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2178       if (ret != 2)
2179         ferr(po, "parse failure for '%s'\n", expr);
2180       if (tmp1[0] == '(') {
2181         // (off_4FFF50+3)[eax]
2182         p = strchr(tmp1 + 1, ')');
2183         if (p == NULL || p[1] != 0)
2184           ferr(po, "parse failure (2) for '%s'\n", expr);
2185         *p = 0;
2186         memmove(tmp1, tmp1 + 1, strlen(tmp1));
2187       }
2188       snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2189     }
2190
2191     // XXX: do we need more parsing?
2192     if (is_lea) {
2193       snprintf(buf, buf_size, "%s", expr);
2194       break;
2195     }
2196
2197     snprintf(buf, buf_size, "%s(%s)",
2198       simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2199     break;
2200
2201   case OPT_LABEL:
2202     name = check_label_read_ref(po, popr->name);
2203     if (cast[0] == 0 && popr->is_ptr)
2204       cast = "(u32)";
2205
2206     if (is_lea)
2207       snprintf(buf, buf_size, "(u32)&%s", name);
2208     else if (popr->size_lt)
2209       snprintf(buf, buf_size, "%s%s%s%s", cast,
2210         lmod_cast_u_ptr(po, popr->lmod),
2211         popr->is_array ? "" : "&", name);
2212     else
2213       snprintf(buf, buf_size, "%s%s%s", cast, name,
2214         popr->is_array ? "[0]" : "");
2215     break;
2216
2217   case OPT_OFFSET:
2218     name = check_label_read_ref(po, popr->name);
2219     if (cast[0] == 0)
2220       cast = "(u32)";
2221     if (is_lea)
2222       ferr(po, "lea an offset?\n");
2223     snprintf(buf, buf_size, "%s&%s", cast, name);
2224     break;
2225
2226   case OPT_CONST:
2227     if (is_lea)
2228       ferr(po, "lea from const?\n");
2229
2230     printf_number(tmp1, sizeof(tmp1), popr->val);
2231     if (popr->val == 0 && strchr(cast, '*'))
2232       snprintf(buf, buf_size, "NULL");
2233     else
2234       snprintf(buf, buf_size, "%s%s",
2235         simplify_cast_num(cast, popr->val), tmp1);
2236     break;
2237
2238   default:
2239     ferr(po, "invalid src type: %d\n", popr->type);
2240   }
2241
2242   return buf;
2243 }
2244
2245 // note: may set is_ptr (we find that out late for ebp frame..)
2246 static char *out_dst_opr(char *buf, size_t buf_size,
2247         struct parsed_op *po, struct parsed_opr *popr)
2248 {
2249   switch (popr->type) {
2250   case OPT_REG:
2251     switch (popr->lmod) {
2252     case OPLM_QWORD:
2253       snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2254       break;
2255     case OPLM_DWORD:
2256       snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2257       break;
2258     case OPLM_WORD:
2259       // ugh..
2260       snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2261       break;
2262     case OPLM_BYTE:
2263       // ugh..
2264       if (popr->name[1] == 'h') // XXX..
2265         snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2266       else
2267         snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2268       break;
2269     default:
2270       ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2271     }
2272     break;
2273
2274   case OPT_REGMEM:
2275     if (is_stack_access(po, popr)) {
2276       stack_frame_access(po, popr, buf, buf_size,
2277         popr->name, "", 0, 0);
2278       break;
2279     }
2280
2281     return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2282
2283   case OPT_LABEL:
2284     if (popr->size_mismatch)
2285       snprintf(buf, buf_size, "%s%s%s",
2286         lmod_cast_u_ptr(po, popr->lmod),
2287         popr->is_array ? "" : "&", popr->name);
2288     else
2289       snprintf(buf, buf_size, "%s%s", popr->name,
2290         popr->is_array ? "[0]" : "");
2291     break;
2292
2293   default:
2294     ferr(po, "invalid dst type: %d\n", popr->type);
2295   }
2296
2297   return buf;
2298 }
2299
2300 static char *out_src_opr_u32(char *buf, size_t buf_size,
2301         struct parsed_op *po, struct parsed_opr *popr)
2302 {
2303   return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2304 }
2305
2306 static char *out_opr_float(char *buf, size_t buf_size,
2307   struct parsed_op *po, struct parsed_opr *popr, int is_src,
2308   int need_float_stack)
2309 {
2310   const char *cast = NULL;
2311   char tmp[256];
2312
2313   switch (popr->type) {
2314   case OPT_REG:
2315     if (popr->reg < xST0 || popr->reg > xST7)
2316       ferr(po, "bad reg: %d\n", popr->reg);
2317
2318     if (need_float_stack) {
2319       if (popr->reg == xST0)
2320         snprintf(buf, buf_size, "f_st[f_stp & 7]");
2321       else
2322         snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2323           popr->reg - xST0);
2324     }
2325     else
2326       snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2327     break;
2328
2329   case OPT_REGMEM:
2330     if (popr->lmod == OPLM_QWORD && is_stack_access(po, popr)) {
2331       stack_frame_access(po, popr, buf, buf_size,
2332         popr->name, "", is_src, 0);
2333       break;
2334     }
2335     // fallthrough
2336   case OPT_LABEL:
2337   case OPT_OFFSET:
2338     switch (popr->lmod) {
2339     case OPLM_QWORD:
2340       cast = "double";
2341       break;
2342     case OPLM_DWORD:
2343       cast = "float";
2344       break;
2345     default:
2346       ferr(po, "unhandled lmod: %d\n", popr->lmod);
2347       break;
2348     }
2349     out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2350     snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2351     break;
2352
2353   default:
2354     ferr(po, "invalid float type: %d\n", popr->type);
2355   }
2356
2357   return buf;
2358 }
2359
2360 static char *out_src_opr_float(char *buf, size_t buf_size,
2361   struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2362 {
2363   return out_opr_float(buf, buf_size, po, popr, 1, need_float_stack);
2364 }
2365
2366 static char *out_dst_opr_float(char *buf, size_t buf_size,
2367   struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2368 {
2369   return out_opr_float(buf, buf_size, po, popr, 0, need_float_stack);
2370 }
2371
2372 static void out_test_for_cc(char *buf, size_t buf_size,
2373   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2374   enum opr_lenmod lmod, const char *expr)
2375 {
2376   const char *cast, *scast;
2377
2378   cast = lmod_cast_u(po, lmod);
2379   scast = lmod_cast_s(po, lmod);
2380
2381   switch (pfo) {
2382   case PFO_Z:
2383   case PFO_BE: // CF==1||ZF==1; CF=0
2384     snprintf(buf, buf_size, "(%s%s %s 0)",
2385       cast, expr, is_inv ? "!=" : "==");
2386     break;
2387
2388   case PFO_S:
2389   case PFO_L: // SF!=OF; OF=0
2390     snprintf(buf, buf_size, "(%s%s %s 0)",
2391       scast, expr, is_inv ? ">=" : "<");
2392     break;
2393
2394   case PFO_LE: // ZF==1||SF!=OF; OF=0
2395     snprintf(buf, buf_size, "(%s%s %s 0)",
2396       scast, expr, is_inv ? ">" : "<=");
2397     break;
2398
2399   case PFO_C: // CF=0
2400   case PFO_O: // OF=0
2401     snprintf(buf, buf_size, "(%d)", !!is_inv);
2402     break;
2403
2404   case PFO_P: // PF==1
2405     snprintf(buf, buf_size, "(%sdo_parity(%s))",
2406       is_inv ? "!" : "", expr);
2407     break;
2408
2409   default:
2410     ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2411   }
2412 }
2413
2414 static void out_cmp_for_cc(char *buf, size_t buf_size,
2415   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2416   int is_neg)
2417 {
2418   const char *cast, *scast, *cast_use;
2419   char buf1[256], buf2[256];
2420   enum opr_lenmod lmod;
2421
2422   if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2423     ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2424       po->operand[0].lmod, po->operand[1].lmod);
2425   lmod = po->operand[0].lmod;
2426
2427   cast = lmod_cast_u(po, lmod);
2428   scast = lmod_cast_s(po, lmod);
2429
2430   switch (pfo) {
2431   case PFO_C:
2432   case PFO_Z:
2433   case PFO_BE: // !a
2434     cast_use = cast;
2435     break;
2436
2437   case PFO_S:
2438   case PFO_L: // !ge
2439   case PFO_LE:
2440     cast_use = scast;
2441     break;
2442
2443   default:
2444     ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2445   }
2446
2447   out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2448   if (po->op == OP_DEC)
2449     snprintf(buf2, sizeof(buf2), "1");
2450   else {
2451     char cast_op2[64];
2452     snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2453     if (is_neg)
2454       strcat(cast_op2, "-");
2455     out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2456   }
2457
2458   switch (pfo) {
2459   case PFO_C:
2460     // note: must be unsigned compare
2461     snprintf(buf, buf_size, "(%s %s %s)",
2462       buf1, is_inv ? ">=" : "<", buf2);
2463     break;
2464
2465   case PFO_Z:
2466     snprintf(buf, buf_size, "(%s %s %s)",
2467       buf1, is_inv ? "!=" : "==", buf2);
2468     break;
2469
2470   case PFO_BE: // !a
2471     // note: must be unsigned compare
2472     snprintf(buf, buf_size, "(%s %s %s)",
2473       buf1, is_inv ? ">" : "<=", buf2);
2474
2475     // annoying case
2476     if (is_inv && lmod == OPLM_BYTE
2477       && po->operand[1].type == OPT_CONST
2478       && po->operand[1].val == 0xff)
2479     {
2480       snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2481       snprintf(buf, buf_size, "(0)");
2482     }
2483     break;
2484
2485   // note: must be signed compare
2486   case PFO_S:
2487     snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2488       scast, buf1, buf2, is_inv ? ">=" : "<");
2489     break;
2490
2491   case PFO_L: // !ge
2492     snprintf(buf, buf_size, "(%s %s %s)",
2493       buf1, is_inv ? ">=" : "<", buf2);
2494     break;
2495
2496   case PFO_LE: // !g
2497     snprintf(buf, buf_size, "(%s %s %s)",
2498       buf1, is_inv ? ">" : "<=", buf2);
2499     break;
2500
2501   default:
2502     break;
2503   }
2504 }
2505
2506 static void out_cmp_test(char *buf, size_t buf_size,
2507   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2508 {
2509   char buf1[256], buf2[256], buf3[256];
2510
2511   if (po->op == OP_TEST) {
2512     if (IS(opr_name(po, 0), opr_name(po, 1))) {
2513       out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2514     }
2515     else {
2516       out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2517       out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2518       snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2519     }
2520     out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2521       po->operand[0].lmod, buf3);
2522   }
2523   else if (po->op == OP_CMP) {
2524     out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2525   }
2526   else
2527     ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2528 }
2529
2530 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2531         struct parsed_opr *popr2)
2532 {
2533   if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2534     ferr(po, "missing lmod for both operands\n");
2535
2536   if (popr1->lmod == OPLM_UNSPEC)
2537     popr1->lmod = popr2->lmod;
2538   else if (popr2->lmod == OPLM_UNSPEC)
2539     popr2->lmod = popr1->lmod;
2540   else if (popr1->lmod != popr2->lmod) {
2541     if (popr1->type_from_var) {
2542       popr1->size_mismatch = 1;
2543       if (popr1->lmod < popr2->lmod)
2544         popr1->size_lt = 1;
2545       popr1->lmod = popr2->lmod;
2546     }
2547     else if (popr2->type_from_var) {
2548       popr2->size_mismatch = 1;
2549       if (popr2->lmod < popr1->lmod)
2550         popr2->size_lt = 1;
2551       popr2->lmod = popr1->lmod;
2552     }
2553     else
2554       ferr(po, "conflicting lmods: %d vs %d\n",
2555         popr1->lmod, popr2->lmod);
2556   }
2557 }
2558
2559 static const char *op_to_c(struct parsed_op *po)
2560 {
2561   switch (po->op)
2562   {
2563     case OP_ADD:
2564     case OP_ADC:
2565       return "+";
2566     case OP_SUB:
2567     case OP_SBB:
2568       return "-";
2569     case OP_AND:
2570       return "&";
2571     case OP_OR:
2572       return "|";
2573     case OP_XOR:
2574       return "^";
2575     case OP_SHL:
2576       return "<<";
2577     case OP_SHR:
2578       return ">>";
2579     case OP_MUL:
2580     case OP_IMUL:
2581       return "*";
2582     default:
2583       ferr(po, "op_to_c was supplied with %d\n", po->op);
2584   }
2585 }
2586
2587 // last op in stream - unconditional branch or ret
2588 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2589   || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2590       && ops[_i].op != OP_CALL))
2591
2592 #define check_i(po, i) \
2593   if ((i) < 0) \
2594     ferr(po, "bad " #i ": %d\n", i)
2595
2596 // note: this skips over calls and rm'd stuff assuming they're handled
2597 // so it's intended to use at one of final passes
2598 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2599   int depth, int seen_noreturn, int flags_set)
2600 {
2601   struct parsed_op *po;
2602   int relevant;
2603   int ret = 0;
2604   int j;
2605
2606   for (; i < opcnt; i++) {
2607     po = &ops[i];
2608     if (po->cc_scratch == magic)
2609       return ret; // already checked
2610     po->cc_scratch = magic;
2611
2612     if (po->flags & OPF_TAIL) {
2613       if (po->op == OP_CALL) {
2614         if (po->pp != NULL && po->pp->is_noreturn)
2615           seen_noreturn = 1;
2616         else
2617           goto out;
2618       }
2619       else
2620         goto out;
2621     }
2622
2623     if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2624       continue;
2625
2626     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2627       if (po->btj != NULL) {
2628         // jumptable
2629         for (j = 0; j < po->btj->count; j++) {
2630           check_i(po, po->btj->d[j].bt_i);
2631           ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2632                    depth, seen_noreturn, flags_set);
2633           if (ret < 0)
2634             return ret; // dead end
2635         }
2636         return ret;
2637       }
2638
2639       check_i(po, po->bt_i);
2640       if (po->flags & OPF_CJMP) {
2641         ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2642                  depth, seen_noreturn, flags_set);
2643         if (ret < 0)
2644           return ret; // dead end
2645       }
2646       else {
2647         i = po->bt_i - 1;
2648       }
2649       continue;
2650     }
2651
2652     relevant = 0;
2653     if ((po->op == OP_POP || po->op == OP_PUSH)
2654       && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2655     {
2656       relevant = 1;
2657     }
2658
2659     if (po->op == OP_PUSH) {
2660       depth++;
2661     }
2662     else if (po->op == OP_POP) {
2663       if (relevant && depth == 0) {
2664         po->flags |= flags_set;
2665         return 1;
2666       }
2667       depth--;
2668     }
2669   }
2670
2671 out:
2672   // for noreturn, assume msvc skipped stack cleanup
2673   return seen_noreturn ? 1 : -1;
2674 }
2675
2676 // scan for 'reg' pop backwards starting from i
2677 // intended to use for register restore search, so other reg
2678 // references are considered an error
2679 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2680 {
2681   struct parsed_op *po;
2682   struct label_ref *lr;
2683   int ret = 0;
2684
2685   ops[i].cc_scratch = magic;
2686
2687   while (1)
2688   {
2689     if (g_labels[i] != NULL) {
2690       lr = &g_label_refs[i];
2691       for (; lr != NULL; lr = lr->next) {
2692         check_i(&ops[i], lr->i);
2693         ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2694         if (ret < 0)
2695           return ret;
2696       }
2697       if (i > 0 && LAST_OP(i - 1))
2698         return ret;
2699     }
2700
2701     i--;
2702     if (i < 0)
2703       break;
2704
2705     if (ops[i].cc_scratch == magic)
2706       return ret;
2707     ops[i].cc_scratch = magic;
2708
2709     po = &ops[i];
2710     if (po->op == OP_POP && po->operand[0].reg == reg) {
2711       if (po->flags & (OPF_RMD|OPF_DONE))
2712         return -1;
2713
2714       po->flags |= set_flags;
2715       return 1;
2716     }
2717
2718     // this also covers the case where we reach corresponding push
2719     if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2720       return -1;
2721   }
2722
2723   // nothing interesting on this path,
2724   // still return ret for something recursive calls could find
2725   return ret;
2726 }
2727
2728 static void find_reachable_exits(int i, int opcnt, int magic,
2729   int *exits, int *exit_count)
2730 {
2731   struct parsed_op *po;
2732   int j;
2733
2734   for (; i < opcnt; i++)
2735   {
2736     po = &ops[i];
2737     if (po->cc_scratch == magic)
2738       return;
2739     po->cc_scratch = magic;
2740
2741     if (po->flags & OPF_TAIL) {
2742       ferr_assert(po, *exit_count < MAX_EXITS);
2743       exits[*exit_count] = i;
2744       (*exit_count)++;
2745       return;
2746     }
2747
2748     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2749       if (po->flags & OPF_RMD)
2750         continue;
2751
2752       if (po->btj != NULL) {
2753         for (j = 0; j < po->btj->count; j++) {
2754           check_i(po, po->btj->d[j].bt_i);
2755           find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2756                   exits, exit_count);
2757         }
2758         return;
2759       }
2760
2761       check_i(po, po->bt_i);
2762       if (po->flags & OPF_CJMP)
2763         find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2764       else
2765         i = po->bt_i - 1;
2766       continue;
2767     }
2768   }
2769 }
2770
2771 // scan for 'reg' pop backwards starting from exits (all paths)
2772 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2773 {
2774   static int exits[MAX_EXITS];
2775   static int exit_count;
2776   int found = 0;
2777   int e, j, ret;
2778
2779   if (!set_flags) {
2780     exit_count = 0;
2781     find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2782       &exit_count);
2783     ferr_assert(&ops[i], exit_count > 0);
2784   }
2785
2786   for (j = 0; j < exit_count; j++) {
2787     e = exits[j];
2788     ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2789             reg, set_flags);
2790     if (ret != -1) {
2791       found |= ret;
2792       continue;
2793     }
2794     if (ops[e].op == OP_CALL && ops[e].pp != NULL
2795       && ops[e].pp->is_noreturn)
2796     {
2797       // assume stack cleanup was skipped
2798       continue;
2799     }
2800     return -1;
2801   }
2802
2803   return found;
2804 }
2805
2806 // scan for one or more pop of push <const>
2807 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2808   int push_i, int is_probe)
2809 {
2810   struct parsed_op *po;
2811   struct label_ref *lr;
2812   int ret = 0;
2813   int j;
2814
2815   for (; i < opcnt; i++)
2816   {
2817     po = &ops[i];
2818     if (po->cc_scratch == magic)
2819       return ret; // already checked
2820     po->cc_scratch = magic;
2821
2822     if (po->flags & OPF_JMP) {
2823       if (po->flags & OPF_RMD)
2824         continue;
2825       if (po->op == OP_CALL)
2826         return -1;
2827
2828       if (po->btj != NULL) {
2829         for (j = 0; j < po->btj->count; j++) {
2830           check_i(po, po->btj->d[j].bt_i);
2831           ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2832                   push_i, is_probe);
2833           if (ret < 0)
2834             return ret;
2835         }
2836         return ret;
2837       }
2838
2839       check_i(po, po->bt_i);
2840       if (po->flags & OPF_CJMP) {
2841         ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2842                  is_probe);
2843         if (ret < 0)
2844           return ret;
2845       }
2846       else {
2847         i = po->bt_i - 1;
2848       }
2849       continue;
2850     }
2851
2852     if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2853       return -1;
2854
2855     if (g_labels[i] != NULL) {
2856       // all refs must be visited
2857       lr = &g_label_refs[i];
2858       for (; lr != NULL; lr = lr->next) {
2859         check_i(po, lr->i);
2860         if (ops[lr->i].cc_scratch != magic)
2861           return -1;
2862       }
2863       if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2864         return -1;
2865     }
2866
2867     if (po->op == OP_POP)
2868     {
2869       if (po->flags & (OPF_RMD|OPF_DONE))
2870         return -1;
2871
2872       if (!is_probe) {
2873         po->flags |= OPF_DONE;
2874         po->datap = &ops[push_i];
2875       }
2876       return 1;
2877     }
2878   }
2879
2880   return -1;
2881 }
2882
2883 static void scan_for_pop_const(int i, int opcnt, int magic)
2884 {
2885   int ret;
2886
2887   ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2888   if (ret == 1) {
2889     ops[i].flags |= OPF_RMD | OPF_DONE;
2890     scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2891   }
2892 }
2893
2894 // check if all branch targets within a marked path are also marked
2895 // note: the path checked must not be empty or end with a branch
2896 static int check_path_branches(int opcnt, int magic)
2897 {
2898   struct parsed_op *po;
2899   int i, j;
2900
2901   for (i = 0; i < opcnt; i++) {
2902     po = &ops[i];
2903     if (po->cc_scratch != magic)
2904       continue;
2905
2906     if (po->flags & OPF_JMP) {
2907       if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2908         continue;
2909
2910       if (po->btj != NULL) {
2911         for (j = 0; j < po->btj->count; j++) {
2912           check_i(po, po->btj->d[j].bt_i);
2913           if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2914             return 0;
2915         }
2916       }
2917
2918       check_i(po, po->bt_i);
2919       if (ops[po->bt_i].cc_scratch != magic)
2920         return 0;
2921       if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2922         return 0;
2923     }
2924   }
2925
2926   return 1;
2927 }
2928
2929 // scan for multiple pushes for given pop
2930 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2931   int is_probe)
2932 {
2933   int reg = ops[pop_i].operand[0].reg;
2934   struct parsed_op *po;
2935   struct label_ref *lr;
2936   int ret = 0;
2937
2938   ops[i].cc_scratch = magic;
2939
2940   while (1)
2941   {
2942     if (g_labels[i] != NULL) {
2943       lr = &g_label_refs[i];
2944       for (; lr != NULL; lr = lr->next) {
2945         check_i(&ops[i], lr->i);
2946         ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2947         if (ret < 0)
2948           return ret;
2949       }
2950       if (i > 0 && LAST_OP(i - 1))
2951         return ret;
2952     }
2953
2954     i--;
2955     if (i < 0)
2956       break;
2957
2958     if (ops[i].cc_scratch == magic)
2959       return ret;
2960     ops[i].cc_scratch = magic;
2961
2962     po = &ops[i];
2963     if (po->op == OP_CALL)
2964       return -1;
2965     if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2966       return -1;
2967
2968     if (po->op == OP_PUSH)
2969     {
2970       if (po->datap != NULL)
2971         return -1;
2972       if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2973         // leave this case for reg save/restore handlers
2974         return -1;
2975
2976       if (!is_probe) {
2977         po->flags |= OPF_PPUSH | OPF_DONE;
2978         po->datap = &ops[pop_i];
2979       }
2980       return 1;
2981     }
2982   }
2983
2984   return -1;
2985 }
2986
2987 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2988 {
2989   int magic = i + opcnt * 14;
2990   int ret;
2991
2992   ret = scan_pushes_for_pop_r(i, magic, i, 1);
2993   if (ret == 1) {
2994     ret = check_path_branches(opcnt, magic);
2995     if (ret == 1) {
2996       ops[i].flags |= OPF_PPUSH | OPF_DONE;
2997       *regmask_pp |= 1 << ops[i].operand[0].reg;
2998       scan_pushes_for_pop_r(i, magic + 1, i, 0);
2999     }
3000   }
3001 }
3002
3003 static void scan_propagate_df(int i, int opcnt)
3004 {
3005   struct parsed_op *po = &ops[i];
3006   int j;
3007
3008   for (; i < opcnt; i++) {
3009     po = &ops[i];
3010     if (po->flags & OPF_DF)
3011       return; // already resolved
3012     po->flags |= OPF_DF;
3013
3014     if (po->op == OP_CALL)
3015       ferr(po, "call with DF set?\n");
3016
3017     if (po->flags & OPF_JMP) {
3018       if (po->btj != NULL) {
3019         // jumptable
3020         for (j = 0; j < po->btj->count; j++) {
3021           check_i(po, po->btj->d[j].bt_i);
3022           scan_propagate_df(po->btj->d[j].bt_i, opcnt);
3023         }
3024         return;
3025       }
3026
3027       if (po->flags & OPF_RMD)
3028         continue;
3029       check_i(po, po->bt_i);
3030       if (po->flags & OPF_CJMP)
3031         scan_propagate_df(po->bt_i, opcnt);
3032       else
3033         i = po->bt_i - 1;
3034       continue;
3035     }
3036
3037     if (po->flags & OPF_TAIL)
3038       break;
3039
3040     if (po->op == OP_CLD) {
3041       po->flags |= OPF_RMD | OPF_DONE;
3042       return;
3043     }
3044   }
3045
3046   ferr(po, "missing DF clear?\n");
3047 }
3048
3049 // is operand 'opr' referenced by parsed_op 'po'?
3050 static int is_opr_referenced(const struct parsed_opr *opr,
3051   const struct parsed_op *po)
3052 {
3053   int i, mask;
3054
3055   if (opr->type == OPT_REG) {
3056     mask = po->regmask_dst | po->regmask_src;
3057     if (po->op == OP_CALL)
3058       mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3059     if ((1 << opr->reg) & mask)
3060       return 1;
3061     else
3062       return 0;
3063   }
3064
3065   for (i = 0; i < po->operand_cnt; i++)
3066     if (IS(po->operand[0].name, opr->name))
3067       return 1;
3068
3069   return 0;
3070 }
3071
3072 // is operand 'opr' read by parsed_op 'po'?
3073 static int is_opr_read(const struct parsed_opr *opr,
3074   const struct parsed_op *po)
3075 {
3076   if (opr->type == OPT_REG) {
3077     if (po->regmask_src & (1 << opr->reg))
3078       return 1;
3079     else
3080       return 0;
3081   }
3082
3083   // yes I'm lazy
3084   return 0;
3085 }
3086
3087 // is operand 'opr' modified by parsed_op 'po'?
3088 static int is_opr_modified(const struct parsed_opr *opr,
3089   const struct parsed_op *po)
3090 {
3091   int mask;
3092
3093   if (opr->type == OPT_REG) {
3094     if (po->op == OP_CALL) {
3095       mask = po->regmask_dst;
3096       mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3097       if (mask & (1 << opr->reg))
3098         return 1;
3099       else
3100         return 0;
3101     }
3102
3103     if (po->regmask_dst & (1 << opr->reg))
3104       return 1;
3105     else
3106       return 0;
3107   }
3108
3109   return IS(po->operand[0].name, opr->name);
3110 }
3111
3112 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3113 static int is_any_opr_modified(const struct parsed_op *po_test,
3114   const struct parsed_op *po, int c_mode)
3115 {
3116   int mask;
3117   int i;
3118
3119   if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3120     return 0;
3121
3122   if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3123     return 0;
3124
3125   if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3126     return 1;
3127
3128   // in reality, it can wreck any register, but in decompiled C
3129   // version it can only overwrite eax or edx:eax
3130   mask = (1 << xAX) | (1 << xDX);
3131   if (!c_mode)
3132     mask |= 1 << xCX;
3133
3134   if (po->op == OP_CALL
3135    && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3136     return 1;
3137
3138   for (i = 0; i < po_test->operand_cnt; i++)
3139     if (IS(po_test->operand[i].name, po->operand[0].name))
3140       return 1;
3141
3142   return 0;
3143 }
3144
3145 // scan for any po_test operand modification in range given
3146 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3147   int c_mode)
3148 {
3149   if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3150     return -1;
3151
3152   for (; i < opcnt; i++) {
3153     if (is_any_opr_modified(po_test, &ops[i], c_mode))
3154       return i;
3155   }
3156
3157   return -1;
3158 }
3159
3160 // scan for po_test operand[0] modification in range given
3161 static int scan_for_mod_opr0(struct parsed_op *po_test,
3162   int i, int opcnt)
3163 {
3164   for (; i < opcnt; i++) {
3165     if (is_opr_modified(&po_test->operand[0], &ops[i]))
3166       return i;
3167   }
3168
3169   return -1;
3170 }
3171
3172 static int try_resolve_const(int i, const struct parsed_opr *opr,
3173   int magic, unsigned int *val);
3174
3175 static int scan_for_flag_set(int i, int opcnt, int magic,
3176   int *branched, int *setters, int *setter_cnt)
3177 {
3178   struct label_ref *lr;
3179   int ret;
3180
3181   while (i >= 0) {
3182     if (ops[i].cc_scratch == magic) {
3183       // is this a problem?
3184       //ferr(&ops[i], "%s looped\n", __func__);
3185       return 0;
3186     }
3187     ops[i].cc_scratch = magic;
3188
3189     if (g_labels[i] != NULL) {
3190       *branched = 1;
3191
3192       lr = &g_label_refs[i];
3193       for (; lr->next; lr = lr->next) {
3194         check_i(&ops[i], lr->i);
3195         ret = scan_for_flag_set(lr->i, opcnt, magic,
3196                 branched, setters, setter_cnt);
3197         if (ret < 0)
3198           return ret;
3199       }
3200
3201       check_i(&ops[i], lr->i);
3202       if (i > 0 && LAST_OP(i - 1)) {
3203         i = lr->i;
3204         continue;
3205       }
3206       ret = scan_for_flag_set(lr->i, opcnt, magic,
3207               branched, setters, setter_cnt);
3208       if (ret < 0)
3209         return ret;
3210     }
3211     i--;
3212
3213     if (ops[i].flags & OPF_FLAGS) {
3214       setters[*setter_cnt] = i;
3215       (*setter_cnt)++;
3216
3217       if (ops[i].flags & OPF_REP) {
3218         struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3219         unsigned int uval;
3220
3221         ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3222         if (ret != 1 || uval == 0) {
3223           // can't treat it as full setter because of ecx=0 case,
3224           // also disallow delayed compare
3225           *branched = 1;
3226           continue;
3227         }
3228       }
3229
3230       return 0;
3231     }
3232
3233     if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3234       return -1;
3235   }
3236
3237   return -1;
3238 }
3239
3240 // scan back for cdq, if anything modifies edx, fail
3241 static int scan_for_cdq_edx(int i)
3242 {
3243   while (i >= 0) {
3244     if (g_labels[i] != NULL) {
3245       if (g_label_refs[i].next != NULL)
3246         return -1;
3247       if (i > 0 && LAST_OP(i - 1)) {
3248         i = g_label_refs[i].i;
3249         continue;
3250       }
3251       return -1;
3252     }
3253     i--;
3254
3255     if (ops[i].op == OP_CDQ)
3256       return i;
3257
3258     if (ops[i].regmask_dst & (1 << xDX))
3259       return -1;
3260   }
3261
3262   return -1;
3263 }
3264
3265 static int scan_for_reg_clear(int i, int reg)
3266 {
3267   while (i >= 0) {
3268     if (g_labels[i] != NULL) {
3269       if (g_label_refs[i].next != NULL)
3270         return -1;
3271       if (i > 0 && LAST_OP(i - 1)) {
3272         i = g_label_refs[i].i;
3273         continue;
3274       }
3275       return -1;
3276     }
3277     i--;
3278
3279     if (ops[i].op == OP_XOR
3280      && ops[i].operand[0].lmod == OPLM_DWORD
3281      && ops[i].operand[0].reg == ops[i].operand[1].reg
3282      && ops[i].operand[0].reg == reg)
3283       return i;
3284
3285     if (ops[i].regmask_dst & (1 << reg))
3286       return -1;
3287   }
3288
3289   return -1;
3290 }
3291
3292 static void patch_esp_adjust(struct parsed_op *po, int adj)
3293 {
3294   ferr_assert(po, po->op == OP_ADD);
3295   ferr_assert(po, IS(opr_name(po, 0), "esp"));
3296   ferr_assert(po, po->operand[1].type == OPT_CONST);
3297
3298   // this is a bit of a hack, but deals with use of
3299   // single adj for multiple calls
3300   po->operand[1].val -= adj;
3301   po->flags |= OPF_RMD;
3302   if (po->operand[1].val == 0)
3303     po->flags |= OPF_DONE;
3304   ferr_assert(po, (int)po->operand[1].val >= 0);
3305 }
3306
3307 // scan for positive, constant esp adjust
3308 // multipath case is preliminary
3309 static int scan_for_esp_adjust(int i, int opcnt,
3310   int adj_expect, int *adj, int *is_multipath, int do_update)
3311 {
3312   int adj_expect_unknown = 0;
3313   struct parsed_op *po;
3314   int first_pop = -1;
3315   int adj_best = 0;
3316
3317   *adj = *is_multipath = 0;
3318   if (adj_expect < 0) {
3319     adj_expect_unknown = 1;
3320     adj_expect = 32 * 4; // enough?
3321   }
3322
3323   for (; i < opcnt && *adj < adj_expect; i++) {
3324     if (g_labels[i] != NULL)
3325       *is_multipath = 1;
3326
3327     po = &ops[i];
3328     if (po->flags & OPF_DONE)
3329       continue;
3330
3331     if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3332       if (po->operand[1].type != OPT_CONST)
3333         ferr(&ops[i], "non-const esp adjust?\n");
3334       *adj += po->operand[1].val;
3335       if (*adj & 3)
3336         ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3337       if (do_update) {
3338         if (!*is_multipath)
3339           patch_esp_adjust(po, adj_expect);
3340         else
3341           po->flags |= OPF_RMD;
3342       }
3343       return i;
3344     }
3345     else if (po->op == OP_PUSH) {
3346       //if (first_pop == -1)
3347       //  first_pop = -2; // none
3348       *adj -= lmod_bytes(po, po->operand[0].lmod);
3349     }
3350     else if (po->op == OP_POP) {
3351       if (!(po->flags & OPF_DONE)) {
3352         // seems like msvc only uses 'pop ecx' for stack realignment..
3353         if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3354           break;
3355         if (first_pop == -1 && *adj >= 0)
3356           first_pop = i;
3357       }
3358       if (do_update && *adj >= 0) {
3359         po->flags |= OPF_RMD;
3360         if (!*is_multipath)
3361           po->flags |= OPF_DONE | OPF_NOREGS;
3362       }
3363
3364       *adj += lmod_bytes(po, po->operand[0].lmod);
3365       if (*adj > adj_best)
3366         adj_best = *adj;
3367     }
3368     else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3369       if (po->op == OP_JMP && po->btj == NULL) {
3370         if (po->bt_i <= i)
3371           break;
3372         i = po->bt_i - 1;
3373         continue;
3374       }
3375       if (po->op != OP_CALL)
3376         break;
3377       if (po->operand[0].type != OPT_LABEL)
3378         break;
3379       if (po->pp != NULL && po->pp->is_stdcall)
3380         break;
3381       if (adj_expect_unknown && first_pop >= 0)
3382         break;
3383       // assume it's another cdecl call
3384     }
3385   }
3386
3387   if (first_pop >= 0) {
3388     // probably only 'pop ecx' was used
3389     *adj = adj_best;
3390     return first_pop;
3391   }
3392
3393   return -1;
3394 }
3395
3396 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3397 {
3398   struct parsed_op *po;
3399   int j;
3400
3401   if (i < 0)
3402     ferr(ops, "%s: followed bad branch?\n", __func__);
3403
3404   for (; i < opcnt; i++) {
3405     po = &ops[i];
3406     if (po->cc_scratch == magic)
3407       return;
3408     po->cc_scratch = magic;
3409     po->flags |= flags;
3410
3411     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3412       if (po->btj != NULL) {
3413         // jumptable
3414         for (j = 0; j < po->btj->count; j++)
3415           scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3416         return;
3417       }
3418
3419       scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3420       if (!(po->flags & OPF_CJMP))
3421         return;
3422     }
3423     if (po->flags & OPF_TAIL)
3424       return;
3425   }
3426 }
3427
3428 static const struct parsed_proto *try_recover_pp(
3429   struct parsed_op *po, const struct parsed_opr *opr,
3430   int is_call, int *search_instead)
3431 {
3432   const struct parsed_proto *pp = NULL;
3433   char buf[256];
3434   char *p;
3435
3436   // maybe an arg of g_func?
3437   if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3438   {
3439     char ofs_reg[16] = { 0, };
3440     int arg, arg_s, arg_i;
3441     int stack_ra = 0;
3442     int offset = 0;
3443
3444     if (g_header_mode)
3445       return NULL;
3446
3447     parse_stack_access(po, opr->name, ofs_reg,
3448       &offset, &stack_ra, NULL, 0);
3449     if (ofs_reg[0] != 0)
3450       ferr(po, "offset reg on arg access?\n");
3451     if (offset <= stack_ra) {
3452       // search who set the stack var instead
3453       if (search_instead != NULL)
3454         *search_instead = 1;
3455       return NULL;
3456     }
3457
3458     arg_i = (offset - stack_ra - 4) / 4;
3459     for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3460       if (g_func_pp->arg[arg].reg != NULL)
3461         continue;
3462       if (arg_s == arg_i)
3463         break;
3464       arg_s++;
3465     }
3466     if (arg == g_func_pp->argc)
3467       ferr(po, "stack arg %d not in prototype?\n", arg_i);
3468
3469     pp = g_func_pp->arg[arg].pp;
3470     if (is_call) {
3471       if (pp == NULL)
3472         ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3473       check_func_pp(po, pp, "icall arg");
3474     }
3475   }
3476   else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3477     // label[index]
3478     p = strchr(opr->name + 1, '[');
3479     memcpy(buf, opr->name, p - opr->name);
3480     buf[p - opr->name] = 0;
3481     pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3482   }
3483   else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3484     pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3485     if (pp == NULL) {
3486       if (!g_header_mode)
3487         ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3488     }
3489     else
3490       check_func_pp(po, pp, "reg-fptr ref");
3491   }
3492
3493   return pp;
3494 }
3495
3496 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3497   int magic, const struct parsed_proto **pp_found, int *pp_i,
3498   int *multi)
3499 {
3500   const struct parsed_proto *pp = NULL;
3501   struct parsed_op *po;
3502   struct label_ref *lr;
3503
3504   ops[i].cc_scratch = magic;
3505
3506   while (1) {
3507     if (g_labels[i] != NULL) {
3508       lr = &g_label_refs[i];
3509       for (; lr != NULL; lr = lr->next) {
3510         check_i(&ops[i], lr->i);
3511         scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3512       }
3513       if (i > 0 && LAST_OP(i - 1))
3514         return;
3515     }
3516
3517     i--;
3518     if (i < 0)
3519       break;
3520
3521     if (ops[i].cc_scratch == magic)
3522       return;
3523     ops[i].cc_scratch = magic;
3524
3525     if (!(ops[i].flags & OPF_DATA))
3526       continue;
3527     if (!is_opr_modified(opr, &ops[i]))
3528       continue;
3529     if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3530       // most probably trashed by some processing
3531       *pp_found = NULL;
3532       return;
3533     }
3534
3535     opr = &ops[i].operand[1];
3536     if (opr->type != OPT_REG)
3537       break;
3538   }
3539
3540   po = (i >= 0) ? &ops[i] : ops;
3541
3542   if (i < 0) {
3543     // reached the top - can only be an arg-reg
3544     if (opr->type != OPT_REG || g_func_pp == NULL)
3545       return;
3546
3547     for (i = 0; i < g_func_pp->argc; i++) {
3548       if (g_func_pp->arg[i].reg == NULL)
3549         continue;
3550       if (IS(opr->name, g_func_pp->arg[i].reg))
3551         break;
3552     }
3553     if (i == g_func_pp->argc)
3554       return;
3555     pp = g_func_pp->arg[i].pp;
3556     if (pp == NULL)
3557       ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3558         i + 1, g_func_pp->arg[i].reg);
3559     check_func_pp(po, pp, "icall reg-arg");
3560   }
3561   else
3562     pp = try_recover_pp(po, opr, 1, NULL);
3563
3564   if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3565     if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3566       || (*pp_found)->is_stdcall != pp->is_stdcall
3567       //|| (*pp_found)->is_fptr != pp->is_fptr
3568       || (*pp_found)->argc != pp->argc
3569       || (*pp_found)->argc_reg != pp->argc_reg
3570       || (*pp_found)->argc_stack != pp->argc_stack)
3571     {
3572       ferr(po, "icall: parsed_proto mismatch\n");
3573     }
3574     *multi = 1;
3575   }
3576   if (pp != NULL) {
3577     *pp_found = pp;
3578     *pp_i = po - ops;
3579   }
3580 }
3581
3582 static void add_label_ref(struct label_ref *lr, int op_i)
3583 {
3584   struct label_ref *lr_new;
3585
3586   if (lr->i == -1) {
3587     lr->i = op_i;
3588     return;
3589   }
3590
3591   lr_new = calloc(1, sizeof(*lr_new));
3592   lr_new->i = op_i;
3593   lr_new->next = lr->next;
3594   lr->next = lr_new;
3595 }
3596
3597 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3598 {
3599   struct parsed_op *po = &ops[i];
3600   struct parsed_data *pd;
3601   char label[NAMELEN], *p;
3602   int len, j, l;
3603
3604   p = strchr(po->operand[0].name, '[');
3605   if (p == NULL)
3606     return NULL;
3607
3608   len = p - po->operand[0].name;
3609   strncpy(label, po->operand[0].name, len);
3610   label[len] = 0;
3611
3612   for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3613     if (IS(g_func_pd[j].label, label)) {
3614       pd = &g_func_pd[j];
3615       break;
3616     }
3617   }
3618   if (pd == NULL)
3619     //ferr(po, "label '%s' not parsed?\n", label);
3620     return NULL;
3621
3622   if (pd->type != OPT_OFFSET)
3623     ferr(po, "label '%s' with non-offset data?\n", label);
3624
3625   // find all labels, link
3626   for (j = 0; j < pd->count; j++) {
3627     for (l = 0; l < opcnt; l++) {
3628       if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3629         add_label_ref(&g_label_refs[l], i);
3630         pd->d[j].bt_i = l;
3631         break;
3632       }
3633     }
3634   }
3635
3636   return pd;
3637 }
3638
3639 static void clear_labels(int count)
3640 {
3641   int i;
3642
3643   for (i = 0; i < count; i++) {
3644     if (g_labels[i] != NULL) {
3645       free(g_labels[i]);
3646       g_labels[i] = NULL;
3647     }
3648   }
3649 }
3650
3651 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3652 {
3653   int regmask = 0;
3654   int i, reg;
3655
3656   for (i = 0; i < pp->argc; i++) {
3657     if (pp->arg[i].reg != NULL) {
3658       reg = char_array_i(regs_r32,
3659               ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3660       if (reg < 0)
3661         ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3662           pp->arg[i].reg, pp->name);
3663       regmask |= 1 << reg;
3664     }
3665   }
3666
3667   return regmask;
3668 }
3669
3670 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3671 {
3672   int regmask = 0;
3673   int i, reg;
3674
3675   if (pp->has_retreg) {
3676     for (i = 0; i < pp->argc; i++) {
3677       if (pp->arg[i].type.is_retreg) {
3678         reg = char_array_i(regs_r32,
3679                 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3680         ferr_assert(ops, reg >= 0);
3681         regmask |= 1 << reg;
3682       }
3683     }
3684   }
3685
3686   if (strstr(pp->ret_type.name, "int64"))
3687     return regmask | (1 << xAX) | (1 << xDX);
3688   if (IS(pp->ret_type.name, "float")
3689    || IS(pp->ret_type.name, "double"))
3690   {
3691     return regmask | mxST0;
3692   }
3693   if (strcasecmp(pp->ret_type.name, "void") == 0)
3694     return regmask;
3695
3696   return regmask | mxAX;
3697 }
3698
3699 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3700 {
3701   return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3702     && memcmp(po1->operand, po2->operand,
3703               sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3704 }
3705
3706 static void resolve_branches_parse_calls(int opcnt)
3707 {
3708   static const struct {
3709     const char *name;
3710     enum op_op op;
3711     unsigned int flags;
3712     unsigned int regmask_src;
3713     unsigned int regmask_dst;
3714   } pseudo_ops[] = {
3715     { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3716     { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3717     { "__ftol",   OPP_FTOL,   OPF_FPOP, mxST0, mxAX | mxDX },
3718     // more precise? Wine gets away with just __ftol handler
3719     { "__ftol2",  OPP_FTOL,   OPF_FPOP, mxST0, mxAX | mxDX },
3720     { "__CIpow",  OPP_CIPOW,  OPF_FPOP, mxST0|mxST1, mxST0 },
3721   };
3722   const struct parsed_proto *pp_c;
3723   struct parsed_proto *pp;
3724   struct parsed_data *pd;
3725   struct parsed_op *po;
3726   const char *tmpname;
3727   enum op_op prev_op;
3728   int i, l;
3729   int ret;
3730
3731   for (i = 0; i < opcnt; i++)
3732   {
3733     po = &ops[i];
3734     po->bt_i = -1;
3735     po->btj = NULL;
3736
3737     if (po->datap != NULL) {
3738       pp = calloc(1, sizeof(*pp));
3739       my_assert_not(pp, NULL);
3740
3741       ret = parse_protostr(po->datap, pp);
3742       if (ret < 0)
3743         ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3744       free(po->datap);
3745       po->datap = NULL;
3746       po->pp = pp;
3747     }
3748
3749     if (po->op == OP_CALL) {
3750       pp = NULL;
3751
3752       if (po->pp != NULL)
3753         pp = po->pp;
3754       else if (po->operand[0].type == OPT_LABEL)
3755       {
3756         tmpname = opr_name(po, 0);
3757         if (IS_START(tmpname, "loc_"))
3758           ferr(po, "call to loc_*\n");
3759         if (IS(tmpname, "__alloca_probe"))
3760           continue;
3761
3762         // convert some calls to pseudo-ops
3763         for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3764           if (!IS(tmpname, pseudo_ops[l].name))
3765             continue;
3766
3767           po->op = pseudo_ops[l].op;
3768           po->operand_cnt = 0;
3769           po->regmask_src = pseudo_ops[l].regmask_src;
3770           po->regmask_dst = pseudo_ops[l].regmask_dst;
3771           po->flags = pseudo_ops[l].flags;
3772           po->flags |= po->regmask_dst ? OPF_DATA : 0;
3773           break;
3774         }
3775         if (l < ARRAY_SIZE(pseudo_ops))
3776           continue;
3777
3778         pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3779         if (!g_header_mode && pp_c == NULL)
3780           ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3781
3782         if (pp_c != NULL) {
3783           pp = proto_clone(pp_c);
3784           my_assert_not(pp, NULL);
3785         }
3786       }
3787
3788       if (pp != NULL) {
3789         if (pp->is_fptr)
3790           check_func_pp(po, pp, "fptr var call");
3791         if (pp->is_noreturn) {
3792           po->flags |= OPF_TAIL;
3793           po->flags &= ~OPF_ATAIL; // most likely...
3794         }
3795       }
3796       po->pp = pp;
3797       continue;
3798     }
3799
3800     if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3801       continue;
3802
3803     if (po->operand[0].type == OPT_REGMEM) {
3804       pd = try_resolve_jumptab(i, opcnt);
3805       if (pd == NULL)
3806         goto tailcall;
3807
3808       po->btj = pd;
3809       continue;
3810     }
3811
3812     for (l = 0; l < opcnt; l++) {
3813       if (g_labels[l] != NULL
3814           && IS(po->operand[0].name, g_labels[l]))
3815       {
3816         if (l == i + 1 && po->op == OP_JMP) {
3817           // yet another alignment type..
3818           po->flags |= OPF_RMD|OPF_DONE;
3819           break;
3820         }
3821         add_label_ref(&g_label_refs[l], i);
3822         po->bt_i = l;
3823         break;
3824       }
3825     }
3826
3827     if (po->bt_i != -1 || (po->flags & OPF_RMD))
3828       continue;
3829
3830     if (po->operand[0].type == OPT_LABEL)
3831       // assume tail call
3832       goto tailcall;
3833
3834     ferr(po, "unhandled branch\n");
3835
3836 tailcall:
3837     po->op = OP_CALL;
3838     po->flags |= OPF_TAIL;
3839     prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3840     if (prev_op == OP_POP)
3841       po->flags |= OPF_ATAIL;
3842     if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3843       && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3844     {
3845       po->flags |= OPF_ATAIL;
3846     }
3847     i--; // reprocess
3848   }
3849 }
3850
3851 static void scan_prologue_epilogue(int opcnt, int *stack_align)
3852 {
3853   int ecx_push = 0, esp_sub = 0, pusha = 0;
3854   int sandard_epilogue;
3855   int found;
3856   int i, j, l;
3857
3858   if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3859       && ops[1].op == OP_MOV
3860       && IS(opr_name(&ops[1], 0), "ebp")
3861       && IS(opr_name(&ops[1], 1), "esp"))
3862   {
3863     g_bp_frame = 1;
3864     ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3865     ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3866     i = 2;
3867
3868     if (ops[i].op == OP_PUSHA) {
3869       ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3870       pusha = 1;
3871       i++;
3872     }
3873
3874     if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
3875         && ops[i].operand[1].type == OPT_CONST)
3876     {
3877       l = ops[i].operand[1].val;
3878       j = ffs(l) - 1;
3879       if (j == -1 || (l >> j) != -1)
3880         ferr(&ops[i], "unhandled esp align: %x\n", l);
3881       if (stack_align != NULL)
3882         *stack_align = 1 << j;
3883       ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3884       i++;
3885     }
3886
3887     if (ops[i].op == OP_SUB && IS(opr_name(&ops[i], 0), "esp")) {
3888       g_stack_fsz = opr_const(&ops[i], 1);
3889       ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3890       i++;
3891     }
3892     else {
3893       // another way msvc builds stack frame..
3894       while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3895         g_stack_fsz += 4;
3896         ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3897         ecx_push++;
3898         i++;
3899       }
3900       // and another way..
3901       if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3902           && ops[i].operand[1].type == OPT_CONST
3903           && ops[i + 1].op == OP_CALL
3904           && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3905       {
3906         g_stack_fsz += ops[i].operand[1].val;
3907         ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3908         i++;
3909         ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3910         i++;
3911       }
3912     }
3913
3914     found = 0;
3915     do {
3916       for (; i < opcnt; i++)
3917         if (ops[i].flags & OPF_TAIL)
3918           break;
3919       j = i - 1;
3920       if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3921         if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3922           break;
3923         i--;
3924         j--;
3925       }
3926
3927       sandard_epilogue = 0;
3928       if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3929       {
3930         ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3931         // the standard epilogue is sometimes even used without a sf
3932         if (ops[j - 1].op == OP_MOV
3933             && IS(opr_name(&ops[j - 1], 0), "esp")
3934             && IS(opr_name(&ops[j - 1], 1), "ebp"))
3935           sandard_epilogue = 1;
3936       }
3937       else if (ops[j].op == OP_LEAVE)
3938       {
3939         ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3940         sandard_epilogue = 1;
3941       }
3942       else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3943         && ops[i].pp->is_noreturn)
3944       {
3945         // on noreturn, msvc sometimes cleans stack, sometimes not
3946         i++;
3947         found = 1;
3948         continue;
3949       }
3950       else if (!(g_ida_func_attr & IDAFA_NORETURN))
3951         ferr(&ops[j], "'pop ebp' expected\n");
3952
3953       if (g_stack_fsz != 0 || sandard_epilogue) {
3954         if (ops[j].op == OP_LEAVE)
3955           j--;
3956         else if (sandard_epilogue) // mov esp, ebp
3957         {
3958           ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3959           j -= 2;
3960         }
3961         else if (!(g_ida_func_attr & IDAFA_NORETURN))
3962         {
3963           ferr(&ops[j], "esp restore expected\n");
3964         }
3965
3966         if (ecx_push && j >= 0 && ops[j].op == OP_POP
3967           && IS(opr_name(&ops[j], 0), "ecx"))
3968         {
3969           ferr(&ops[j], "unexpected ecx pop\n");
3970         }
3971       }
3972
3973       if (pusha) {
3974         if (ops[j].op == OP_POPA)
3975           ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3976         else
3977           ferr(&ops[j], "popa expected\n");
3978       }
3979
3980       found = 1;
3981       i++;
3982     } while (i < opcnt);
3983
3984     if (!found)
3985       ferr(ops, "missing ebp epilogue\n");
3986     return;
3987   }
3988
3989   // non-bp frame
3990   i = 0;
3991   while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3992     ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3993     g_stack_fsz += 4;
3994     ecx_push++;
3995     i++;
3996   }
3997
3998   for (; i < opcnt; i++) {
3999     if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
4000       break;
4001     if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4002       && ops[i].operand[1].type == OPT_CONST)
4003     {
4004       g_stack_fsz = ops[i].operand[1].val;
4005       ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4006       i++;
4007       esp_sub = 1;
4008       break;
4009     }
4010     else if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4011           && ops[i].operand[1].type == OPT_CONST
4012           && ops[i + 1].op == OP_CALL
4013           && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
4014     {
4015       g_stack_fsz += ops[i].operand[1].val;
4016       ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4017       i++;
4018       ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4019       i++;
4020       esp_sub = 1;
4021       break;
4022     }
4023   }
4024
4025   if (ecx_push && !esp_sub) {
4026     // could actually be args for a call..
4027     for (; i < opcnt; i++)
4028       if (ops[i].op != OP_PUSH)
4029         break;
4030
4031     if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4032       const struct parsed_proto *pp;
4033       pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4034       j = pp ? pp->argc_stack : 0;
4035       while (i > 0 && j > 0) {
4036         i--;
4037         if (ops[i].op == OP_PUSH) {
4038           ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4039           j--;
4040         }
4041       }
4042       if (j != 0)
4043         ferr(&ops[i], "unhandled prologue\n");
4044
4045       // recheck
4046       i = g_stack_fsz = ecx_push = 0;
4047       while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4048         if (!(ops[i].flags & OPF_RMD))
4049           break;
4050         g_stack_fsz += 4;
4051         ecx_push++;
4052         i++;
4053       }
4054     }
4055   }
4056
4057   found = 0;
4058   if (ecx_push || esp_sub)
4059   {
4060     g_sp_frame = 1;
4061
4062     do {
4063       for (; i < opcnt; i++)
4064         if (ops[i].flags & OPF_TAIL)
4065           break;
4066
4067       j = i - 1;
4068       if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4069         if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4070           break;
4071         i--;
4072         j--;
4073       }
4074
4075       if (ecx_push > 0) {
4076         for (l = 0; l < ecx_push; l++) {
4077           if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4078             /* pop ecx */;
4079           else if (ops[j].op == OP_ADD
4080                    && IS(opr_name(&ops[j], 0), "esp")
4081                    && ops[j].operand[1].type == OPT_CONST)
4082           {
4083             /* add esp, N */
4084             l += ops[j].operand[1].val / 4 - 1;
4085           }
4086           else
4087             break;
4088
4089           ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4090           j--;
4091         }
4092         if (l != ecx_push) {
4093           if (i < opcnt && ops[i].op == OP_CALL
4094             && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4095           {
4096             // noreturn tailcall with no epilogue
4097             i++;
4098             found = 1;
4099             continue;
4100           }
4101           ferr(&ops[j], "epilogue scan failed\n");
4102         }
4103
4104         found = 1;
4105       }
4106
4107       if (esp_sub) {
4108         if (ops[j].op != OP_ADD
4109             || !IS(opr_name(&ops[j], 0), "esp")
4110             || ops[j].operand[1].type != OPT_CONST)
4111         {
4112           if (i < opcnt && ops[i].op == OP_CALL
4113             && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4114           {
4115             // noreturn tailcall with no epilogue
4116             i++;
4117             found = 1;
4118             continue;
4119           }
4120           ferr(&ops[j], "'add esp' expected\n");
4121         }
4122
4123         if (ops[j].operand[1].val < g_stack_fsz)
4124           ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4125
4126         ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4127         if (ops[j].operand[1].val == 0)
4128           ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4129         found = 1;
4130       }
4131
4132       i++;
4133     } while (i < opcnt);
4134
4135     if (!found)
4136       ferr(ops, "missing esp epilogue\n");
4137   }
4138 }
4139
4140 // find an instruction that changed opr before i op
4141 // *op_i must be set to -1 by the caller
4142 // *is_caller is set to 1 if one source is determined to be g_func arg
4143 // returns 1 if found, *op_i is then set to origin
4144 // returns -1 if multiple origins are found
4145 static int resolve_origin(int i, const struct parsed_opr *opr,
4146   int magic, int *op_i, int *is_caller)
4147 {
4148   struct label_ref *lr;
4149   int ret = 0;
4150
4151   while (1) {
4152     if (g_labels[i] != NULL) {
4153       lr = &g_label_refs[i];
4154       for (; lr != NULL; lr = lr->next) {
4155         check_i(&ops[i], lr->i);
4156         ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4157       }
4158       if (i > 0 && LAST_OP(i - 1))
4159         return ret;
4160     }
4161
4162     i--;
4163     if (i < 0) {
4164       if (is_caller != NULL)
4165         *is_caller = 1;
4166       return -1;
4167     }
4168
4169     if (ops[i].cc_scratch == magic)
4170       return ret;
4171     ops[i].cc_scratch = magic;
4172
4173     if (!(ops[i].flags & OPF_DATA))
4174       continue;
4175     if (!is_opr_modified(opr, &ops[i]))
4176       continue;
4177
4178     if (*op_i >= 0) {
4179       if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4180         return ret | 1;
4181
4182       return -1;
4183     }
4184
4185     *op_i = i;
4186     return ret | 1;
4187   }
4188 }
4189
4190 // find an instruction that previously referenced opr
4191 // if multiple results are found - fail
4192 // *op_i must be set to -1 by the caller
4193 // returns 1 if found, *op_i is then set to referencer insn
4194 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4195   int magic, int *op_i)
4196 {
4197   struct label_ref *lr;
4198   int ret = 0;
4199
4200   while (1) {
4201     if (g_labels[i] != NULL) {
4202       lr = &g_label_refs[i];
4203       for (; lr != NULL; lr = lr->next) {
4204         check_i(&ops[i], lr->i);
4205         ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4206       }
4207       if (i > 0 && LAST_OP(i - 1))
4208         return ret;
4209     }
4210
4211     i--;
4212     if (i < 0)
4213       return -1;
4214
4215     if (ops[i].cc_scratch == magic)
4216       return 0;
4217     ops[i].cc_scratch = magic;
4218
4219     if (!is_opr_referenced(opr, &ops[i]))
4220       continue;
4221
4222     if (*op_i >= 0)
4223       return -1;
4224
4225     *op_i = i;
4226     return 1;
4227   }
4228 }
4229
4230 // adjust datap of all reachable 'op' insns when moving back
4231 // returns  1 if at least 1 op was found
4232 // returns -1 if path without an op was found
4233 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4234 {
4235   struct label_ref *lr;
4236   int ret = 0;
4237
4238   if (ops[i].cc_scratch == magic)
4239     return 0;
4240   ops[i].cc_scratch = magic;
4241
4242   while (1) {
4243     if (g_labels[i] != NULL) {
4244       lr = &g_label_refs[i];
4245       for (; lr != NULL; lr = lr->next) {
4246         check_i(&ops[i], lr->i);
4247         ret |= adjust_prev_op(lr->i, op, magic, datap);
4248       }
4249       if (i > 0 && LAST_OP(i - 1))
4250         return ret;
4251     }
4252
4253     i--;
4254     if (i < 0)
4255       return -1;
4256
4257     if (ops[i].cc_scratch == magic)
4258       return 0;
4259     ops[i].cc_scratch = magic;
4260
4261     if (ops[i].op != op)
4262       continue;
4263
4264     ops[i].datap = datap;
4265     return 1;
4266   }
4267 }
4268
4269 // find next instruction that reads opr
4270 // *op_i must be set to -1 by the caller
4271 // on return, *op_i is set to first referencer insn
4272 // returns 1 if exactly 1 referencer is found
4273 static int find_next_read(int i, int opcnt,
4274   const struct parsed_opr *opr, int magic, int *op_i)
4275 {
4276   struct parsed_op *po;
4277   int j, ret = 0;
4278
4279   for (; i < opcnt; i++)
4280   {
4281     if (ops[i].cc_scratch == magic)
4282       return ret;
4283     ops[i].cc_scratch = magic;
4284
4285     po = &ops[i];
4286     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4287       if (po->btj != NULL) {
4288         // jumptable
4289         for (j = 0; j < po->btj->count; j++) {
4290           check_i(po, po->btj->d[j].bt_i);
4291           ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4292                    magic, op_i);
4293         }
4294         return ret;
4295       }
4296
4297       if (po->flags & OPF_RMD)
4298         continue;
4299       check_i(po, po->bt_i);
4300       if (po->flags & OPF_CJMP) {
4301         ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4302         if (ret < 0)
4303           return ret;
4304       }
4305       else
4306         i = po->bt_i - 1;
4307       continue;
4308     }
4309
4310     if (!is_opr_read(opr, po)) {
4311       int full_opr = 1;
4312       if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4313           && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4314       {
4315         full_opr = po->operand[0].lmod >= opr->lmod;
4316       }
4317       if (is_opr_modified(opr, po) && full_opr) {
4318         // it's overwritten
4319         return ret;
4320       }
4321       if (po->flags & OPF_TAIL)
4322         return ret;
4323       continue;
4324     }
4325
4326     if (*op_i >= 0)
4327       return -1;
4328
4329     *op_i = i;
4330     return 1;
4331   }
4332
4333   return 0;
4334 }
4335
4336 // find next instruction that reads opr
4337 // *op_i must be set to -1 by the caller
4338 // on return, *op_i is set to first flag user insn
4339 // returns 1 if exactly 1 flag user is found
4340 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4341 {
4342   struct parsed_op *po;
4343   int j, ret = 0;
4344
4345   for (; i < opcnt; i++)
4346   {
4347     if (ops[i].cc_scratch == magic)
4348       return ret;
4349     ops[i].cc_scratch = magic;
4350
4351     po = &ops[i];
4352     if (po->op == OP_CALL)
4353       return -1;
4354     if (po->flags & OPF_JMP) {
4355       if (po->btj != NULL) {
4356         // jumptable
4357         for (j = 0; j < po->btj->count; j++) {
4358           check_i(po, po->btj->d[j].bt_i);
4359           ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4360                    magic, op_i);
4361         }
4362         return ret;
4363       }
4364
4365       if (po->flags & OPF_RMD)
4366         continue;
4367       check_i(po, po->bt_i);
4368       if (po->flags & OPF_CJMP)
4369         goto found;
4370       else
4371         i = po->bt_i - 1;
4372       continue;
4373     }
4374
4375     if (!(po->flags & OPF_CC)) {
4376       if (po->flags & OPF_FLAGS)
4377         // flags changed
4378         return ret;
4379       if (po->flags & OPF_TAIL)
4380         return ret;
4381       continue;
4382     }
4383
4384 found:
4385     if (*op_i >= 0)
4386       return -1;
4387
4388     *op_i = i;
4389     return 1;
4390   }
4391
4392   return 0;
4393 }
4394
4395 static int try_resolve_const(int i, const struct parsed_opr *opr,
4396   int magic, unsigned int *val)
4397 {
4398   int s_i = -1;
4399   int ret;
4400
4401   ret = resolve_origin(i, opr, magic, &s_i, NULL);
4402   if (ret == 1) {
4403     i = s_i;
4404     if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4405       return -1;
4406
4407     *val = ops[i].operand[1].val;
4408     return 1;
4409   }
4410
4411   return -1;
4412 }
4413
4414 static int resolve_used_bits(int i, int opcnt, int reg,
4415   int *mask, int *is_z_check)
4416 {
4417   struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4418   int j = -1, k = -1;
4419   int ret;
4420
4421   ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4422   if (ret != 1)
4423     return -1;
4424
4425   find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4426   if (k != -1) {
4427     fnote(&ops[j], "(first read)\n");
4428     ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4429   }
4430
4431   if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4432     ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4433
4434   ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4435   ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4436
4437   *mask = ops[j].operand[1].val;
4438   if (ops[j].operand[0].lmod == OPLM_BYTE
4439     && ops[j].operand[0].name[1] == 'h')
4440   {
4441     *mask <<= 8;
4442   }
4443   ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4444
4445   *is_z_check = 0;
4446   ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4447   if (ret == 1)
4448     *is_z_check = ops[k].pfo == PFO_Z;
4449
4450   return 0;
4451 }
4452
4453 static const struct parsed_proto *resolve_deref(int i, int magic,
4454   struct parsed_opr *opr, int level)
4455 {
4456   struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4457   const struct parsed_proto *pp = NULL;
4458   int from_caller = 0;
4459   char s_reg[4];
4460   int offset = 0;
4461   int len = 0;
4462   int j = -1;
4463   int k = -1;
4464   int reg;
4465   int ret;
4466
4467   ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4468   if (ret != 2 || len != strlen(opr->name)) {
4469     ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4470     if (ret != 1 || len != strlen(opr->name))
4471       return NULL;
4472   }
4473
4474   reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4475   if (reg < 0)
4476     return NULL;
4477
4478   opr_s.reg = reg;
4479   ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4480   if (ret != 1)
4481     return NULL;
4482
4483   if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4484     && strlen(ops[j].operand[1].name) == 3
4485     && ops[j].operand[0].lmod == OPLM_DWORD
4486     && ops[j].pp == NULL // no hint
4487     && level == 0)
4488   {
4489     // allow one simple dereference (com/directx)
4490     reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4491             ops[j].operand[1].name);
4492     if (reg < 0)
4493       return NULL;
4494     opr_s.reg = reg;
4495     ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4496     if (ret != 1)
4497       return NULL;
4498     j = k;
4499   }
4500   if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4501     return NULL;
4502
4503   if (ops[j].pp != NULL) {
4504     // type hint in asm
4505     pp = ops[j].pp;
4506   }
4507   else if (ops[j].operand[1].type == OPT_REGMEM) {
4508     pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4509     if (pp == NULL) {
4510       // maybe structure ptr in structure
4511       pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4512     }
4513   }
4514   else if (ops[j].operand[1].type == OPT_LABEL)
4515     pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4516   else if (ops[j].operand[1].type == OPT_REG) {
4517     // maybe arg reg?
4518     k = -1;
4519     ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4520             &k, &from_caller);
4521     if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4522       for (k = 0; k < g_func_pp->argc; k++) {
4523         if (g_func_pp->arg[k].reg == NULL)
4524           continue;
4525         if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4526           pp = g_func_pp->arg[k].pp;
4527           break;
4528         }
4529       }
4530     }
4531   }
4532
4533   if (pp == NULL)
4534     return NULL;
4535   if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4536     if (offset != 0)
4537       ferr(&ops[j], "expected struct, got '%s %s'\n",
4538            pp->type.name, pp->name);
4539     return NULL;
4540   }
4541
4542   return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4543 }
4544
4545 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4546   int *pp_i, int *multi_src)
4547 {
4548   const struct parsed_proto *pp = NULL;
4549   int search_advice = 0;
4550
4551   *multi_src = 0;
4552   *pp_i = -1;
4553
4554   switch (ops[i].operand[0].type) {
4555   case OPT_REGMEM:
4556     // try to resolve struct member calls
4557     pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4558     if (pp != NULL)
4559       break;
4560     // fallthrough
4561   case OPT_LABEL:
4562   case OPT_OFFSET:
4563     pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4564            1, &search_advice);
4565     if (!search_advice)
4566       break;
4567     // fallthrough
4568   default:
4569     scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4570       pp_i, multi_src);
4571     break;
4572   }
4573
4574   return pp;
4575 }
4576
4577 static struct parsed_proto *process_call_early(int i, int opcnt,
4578   int *adj_i)
4579 {
4580   struct parsed_op *po = &ops[i];
4581   struct parsed_proto *pp;
4582   int multipath = 0;
4583   int adj = 0;
4584   int j, ret;
4585
4586   pp = po->pp;
4587   if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4588     // leave for later
4589     return NULL;
4590
4591   // look for and make use of esp adjust
4592   *adj_i = ret = -1;
4593   if (!pp->is_stdcall && pp->argc_stack > 0)
4594     ret = scan_for_esp_adjust(i + 1, opcnt,
4595             pp->argc_stack * 4, &adj, &multipath, 0);
4596   if (ret >= 0) {
4597     if (pp->argc_stack > adj / 4)
4598       return NULL;
4599     if (multipath)
4600       return NULL;
4601     if (ops[ret].op == OP_POP) {
4602       for (j = 1; j < adj / 4; j++) {
4603         if (ops[ret + j].op != OP_POP
4604           || ops[ret + j].operand[0].reg != xCX)
4605         {
4606           return NULL;
4607         }
4608       }
4609     }
4610   }
4611
4612   *adj_i = ret;
4613   return pp;
4614 }
4615
4616 static struct parsed_proto *process_call(int i, int opcnt)
4617 {
4618   struct parsed_op *po = &ops[i];
4619   const struct parsed_proto *pp_c;
4620   struct parsed_proto *pp;
4621   const char *tmpname;
4622   int call_i = -1, ref_i = -1;
4623   int adj = 0, multipath = 0;
4624   int ret, arg;
4625
4626   tmpname = opr_name(po, 0);
4627   pp = po->pp;
4628   if (pp == NULL)
4629   {
4630     // indirect call
4631     pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4632     if (pp_c != NULL) {
4633       if (!pp_c->is_func && !pp_c->is_fptr)
4634         ferr(po, "call to non-func: %s\n", pp_c->name);
4635       pp = proto_clone(pp_c);
4636       my_assert_not(pp, NULL);
4637       if (multipath)
4638         // not resolved just to single func
4639         pp->is_fptr = 1;
4640
4641       switch (po->operand[0].type) {
4642       case OPT_REG:
4643         // we resolved this call and no longer need the register
4644         po->regmask_src &= ~(1 << po->operand[0].reg);
4645
4646         if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4647           && ops[call_i].operand[1].type == OPT_LABEL)
4648         {
4649           // no other source users?
4650           ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4651                   &ref_i);
4652           if (ret == 1 && call_i == ref_i) {
4653             // and nothing uses it after us?
4654             ref_i = -1;
4655             find_next_read(i + 1, opcnt, &po->operand[0],
4656               i + opcnt * 11, &ref_i);
4657             if (ref_i == -1)
4658               // then also don't need the source mov
4659               ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4660           }
4661         }
4662         break;
4663       case OPT_REGMEM:
4664         pp->is_fptr = 1;
4665         break;
4666       default:
4667         break;
4668       }
4669     }
4670     if (pp == NULL) {
4671       pp = calloc(1, sizeof(*pp));
4672       my_assert_not(pp, NULL);
4673
4674       pp->is_fptr = 1;
4675       ret = scan_for_esp_adjust(i + 1, opcnt,
4676               -1, &adj, &multipath, 0);
4677       if (ret < 0 || adj < 0) {
4678         if (!g_allow_regfunc)
4679           ferr(po, "non-__cdecl indirect call unhandled yet\n");
4680         pp->is_unresolved = 1;
4681         adj = 0;
4682       }
4683       adj /= 4;
4684       if (adj > ARRAY_SIZE(pp->arg))
4685         ferr(po, "esp adjust too large: %d\n", adj);
4686       pp->ret_type.name = strdup("int");
4687       pp->argc = pp->argc_stack = adj;
4688       for (arg = 0; arg < pp->argc; arg++)
4689         pp->arg[arg].type.name = strdup("int");
4690     }
4691     po->pp = pp;
4692   }
4693
4694   // look for and make use of esp adjust
4695   multipath = 0;
4696   ret = -1;
4697   if (!pp->is_stdcall && pp->argc_stack > 0) {
4698     int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4699     ret = scan_for_esp_adjust(i + 1, opcnt,
4700             adj_expect, &adj, &multipath, 0);
4701   }
4702   if (ret >= 0) {
4703     if (pp->is_vararg) {
4704       if (adj / 4 < pp->argc_stack) {
4705         fnote(po, "(this call)\n");
4706         ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4707           adj, pp->argc_stack * 4);
4708       }
4709       // modify pp to make it have varargs as normal args
4710       arg = pp->argc;
4711       pp->argc += adj / 4 - pp->argc_stack;
4712       for (; arg < pp->argc; arg++) {
4713         pp->arg[arg].type.name = strdup("int");
4714         pp->argc_stack++;
4715       }
4716       if (pp->argc > ARRAY_SIZE(pp->arg))
4717         ferr(po, "too many args for '%s'\n", tmpname);
4718     }
4719     if (pp->argc_stack > adj / 4) {
4720       if (pp->is_noreturn)
4721         // assume no stack adjust was emited
4722         goto out;
4723       fnote(po, "(this call)\n");
4724       ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4725         tmpname, pp->argc_stack * 4, adj);
4726     }
4727
4728     scan_for_esp_adjust(i + 1, opcnt,
4729       pp->argc_stack * 4, &adj, &multipath, 1);
4730   }
4731   else if (pp->is_vararg)
4732     ferr(po, "missing esp_adjust for vararg func '%s'\n",
4733       pp->name);
4734
4735 out:
4736   return pp;
4737 }
4738
4739 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
4740   int *regmask_ffca)
4741 {
4742   struct parsed_op *po;
4743   int offset = 0;
4744   int base_arg;
4745   int j, arg;
4746   int ret;
4747
4748   for (base_arg = 0; base_arg < pp->argc; base_arg++)
4749     if (pp->arg[base_arg].reg == NULL)
4750       break;
4751
4752   for (j = i; j > 0; )
4753   {
4754     ferr_assert(&ops[j], g_labels[j] == NULL);
4755     j--;
4756
4757     po = &ops[j];
4758     ferr_assert(po, po->op != OP_PUSH);
4759     if (po->op == OP_FST)
4760     {
4761       if (po->operand[0].type != OPT_REGMEM)
4762         continue;
4763       ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
4764       if (ret != 0)
4765         continue;
4766       if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
4767         //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
4768         continue;
4769       }
4770
4771       arg = base_arg + offset / 4;
4772       po->p_argnext = -1;
4773       po->p_argnum = arg + 1;
4774       ferr_assert(po, pp->arg[arg].datap == NULL);
4775       pp->arg[arg].datap = po;
4776       po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
4777       if (regmask_ffca != NULL)
4778         *regmask_ffca |= 1 << arg;
4779     }
4780     else if (po->op == OP_SUB && po->operand[0].reg == xSP
4781       && po->operand[1].type == OPT_CONST)
4782     {
4783       po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4784       break;
4785     }
4786   }
4787
4788   for (arg = base_arg; arg < pp->argc; arg++) {
4789     ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
4790     po = pp->arg[arg].datap;
4791     if (po == NULL)
4792       ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
4793     if (po->operand[0].lmod == OPLM_QWORD)
4794       arg++;
4795   }
4796
4797   return 0;
4798 }
4799
4800 static int collect_call_args_early(int i, struct parsed_proto *pp,
4801   int *regmask, int *regmask_ffca)
4802 {
4803   struct parsed_op *po;
4804   int arg, ret;
4805   int j;
4806
4807   for (arg = 0; arg < pp->argc; arg++)
4808     if (pp->arg[arg].reg == NULL)
4809       break;
4810
4811   // first see if it can be easily done
4812   for (j = i; j > 0 && arg < pp->argc; )
4813   {
4814     if (g_labels[j] != NULL)
4815       return -1;
4816     j--;
4817
4818     po = &ops[j];
4819     if (po->op == OP_CALL)
4820       return -1;
4821     else if (po->op == OP_ADD && po->operand[0].reg == xSP)
4822       return -1;
4823     else if (po->op == OP_POP)
4824       return -1;
4825     else if (po->flags & OPF_CJMP)
4826       return -1;
4827     else if (po->op == OP_PUSH) {
4828       if (po->flags & (OPF_FARG|OPF_FARGNR))
4829         return -1;
4830       if (!g_header_mode) {
4831         ret = scan_for_mod(po, j + 1, i, 1);
4832         if (ret >= 0)
4833           return -1;
4834       }
4835
4836       if (pp->arg[arg].type.is_va_list)
4837         return -1;
4838
4839       // next arg
4840       for (arg++; arg < pp->argc; arg++)
4841         if (pp->arg[arg].reg == NULL)
4842           break;
4843     }
4844     else if (po->op == OP_SUB && po->operand[0].reg == xSP
4845       && po->operand[1].type == OPT_CONST)
4846     {
4847       if (po->flags & (OPF_RMD|OPF_DONE))
4848         return -1;
4849       if (po->operand[1].val != pp->argc_stack * 4)
4850         ferr(po, "unexpected esp adjust: %d\n",
4851              po->operand[1].val * 4);
4852       ferr_assert(po, pp->argc - arg == pp->argc_stack);
4853       return collect_call_args_no_push(i, pp, regmask_ffca);
4854     }
4855   }
4856
4857   if (arg < pp->argc)
4858     return -1;
4859
4860   // now do it
4861   for (arg = 0; arg < pp->argc; arg++)
4862     if (pp->arg[arg].reg == NULL)
4863       break;
4864
4865   for (j = i; j > 0 && arg < pp->argc; )
4866   {
4867     j--;
4868
4869     if (ops[j].op == OP_PUSH)
4870     {
4871       ops[j].p_argnext = -1;
4872       ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4873       pp->arg[arg].datap = &ops[j];
4874
4875       if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
4876         *regmask |= 1 << ops[j].operand[0].reg;
4877
4878       ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4879       ops[j].flags &= ~OPF_RSAVE;
4880
4881       // next arg
4882       for (arg++; arg < pp->argc; arg++)
4883         if (pp->arg[arg].reg == NULL)
4884           break;
4885     }
4886   }
4887
4888   return 0;
4889 }
4890
4891 static int sync_argnum(struct parsed_op *po, int argnum)
4892 {
4893   struct parsed_op *po_tmp;
4894
4895   // see if other branches don't have higher argnum
4896   for (po_tmp = po; po_tmp != NULL; ) {
4897     if (argnum < po_tmp->p_argnum)
4898       argnum = po_tmp->p_argnum;
4899     // note: p_argnext is active on current collect_call_args only
4900     po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4901   }
4902
4903   // make all argnums consistent
4904   for (po_tmp = po; po_tmp != NULL; ) {
4905     if (po_tmp->p_argnum != 0)
4906       po_tmp->p_argnum = argnum;
4907     po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4908   }
4909
4910   return argnum;
4911 }
4912
4913 static int collect_call_args_r(struct parsed_op *po, int i,
4914   struct parsed_proto *pp, int *regmask, int *arg_grp,
4915   int arg, int argnum, int magic, int need_op_saving, int may_reuse)
4916 {
4917   struct parsed_proto *pp_tmp;
4918   struct parsed_op *po_tmp;
4919   struct label_ref *lr;
4920   int need_to_save_current;
4921   int arg_grp_current = 0;
4922   int save_args_seen = 0;
4923   int ret = 0;
4924   int reg;
4925   char buf[32];
4926   int j, k;
4927
4928   if (i < 0) {
4929     ferr(po, "dead label encountered\n");
4930     return -1;
4931   }
4932
4933   for (; arg < pp->argc; arg++, argnum++)
4934     if (pp->arg[arg].reg == NULL)
4935       break;
4936   magic = (magic & 0xffffff) | (arg << 24);
4937
4938   for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4939   {
4940     if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4941       if (ops[j].cc_scratch != magic) {
4942         ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4943            pp->name);
4944         return -1;
4945       }
4946       // ok: have already been here
4947       return 0;
4948     }
4949     ops[j].cc_scratch = magic;
4950
4951     if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4952       lr = &g_label_refs[j];
4953       if (lr->next != NULL)
4954         need_op_saving = 1;
4955       for (; lr->next; lr = lr->next) {
4956         check_i(&ops[j], lr->i);
4957         if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4958           may_reuse = 1;
4959         ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4960                 arg, argnum, magic, need_op_saving, may_reuse);
4961         if (ret < 0)
4962           return ret;
4963       }
4964
4965       check_i(&ops[j], lr->i);
4966       if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4967         may_reuse = 1;
4968       if (j > 0 && LAST_OP(j - 1)) {
4969         // follow last branch in reverse
4970         j = lr->i;
4971         continue;
4972       }
4973       need_op_saving = 1;
4974       ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4975               arg, argnum, magic, need_op_saving, may_reuse);
4976       if (ret < 0)
4977         return ret;
4978     }
4979     j--;
4980
4981     if (ops[j].op == OP_CALL)
4982     {
4983       if (pp->is_unresolved)
4984         break;
4985
4986       pp_tmp = ops[j].pp;
4987       if (pp_tmp == NULL)
4988         ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
4989           arg, pp->argc, ops[j].operand[0].name);
4990       if (may_reuse && pp_tmp->argc_stack > 0)
4991         ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4992           arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4993     }
4994     // esp adjust of 0 means we collected it before
4995     else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4996       && (ops[j].operand[1].type != OPT_CONST
4997           || ops[j].operand[1].val != 0))
4998     {
4999       if (pp->is_unresolved)
5000         break;
5001
5002       fnote(po, "(this call)\n");
5003       ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5004         arg, pp->argc, ops[j].operand[1].val);
5005     }
5006     else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5007     {
5008       if (pp->is_unresolved)
5009         break;
5010
5011       fnote(po, "(this call)\n");
5012       ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5013     }
5014     else if (ops[j].flags & OPF_CJMP)
5015     {
5016       if (pp->is_unresolved)
5017         break;
5018
5019       may_reuse = 1;
5020     }
5021     else if (ops[j].op == OP_PUSH
5022       && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5023     {
5024       if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5025         break;
5026
5027       ops[j].p_argnext = -1;
5028       po_tmp = pp->arg[arg].datap;
5029       if (po_tmp != NULL)
5030         ops[j].p_argnext = po_tmp - ops;
5031       pp->arg[arg].datap = &ops[j];
5032
5033       argnum = sync_argnum(&ops[j], argnum);
5034
5035       need_to_save_current = 0;
5036       reg = -1;
5037       if (ops[j].operand[0].type == OPT_REG)
5038         reg = ops[j].operand[0].reg;
5039
5040       if (!need_op_saving) {
5041         ret = scan_for_mod(&ops[j], j + 1, i, 1);
5042         need_to_save_current = (ret >= 0);
5043       }
5044       if (need_op_saving || need_to_save_current) {
5045         // mark this arg as one that needs operand saving
5046         pp->arg[arg].is_saved = 1;
5047
5048         if (save_args_seen & (1 << (argnum - 1))) {
5049           save_args_seen = 0;
5050           arg_grp_current++;
5051           if (arg_grp_current >= MAX_ARG_GRP)
5052             ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5053               argnum, pp->name);
5054         }
5055       }
5056       else if (ops[j].p_argnum == 0)
5057         ops[j].flags |= OPF_RMD;
5058
5059       // some PUSHes are reused by different calls on other branches,
5060       // but that can't happen if we didn't branch, so they
5061       // can be removed from future searches (handles nested calls)
5062       if (!may_reuse)
5063         ops[j].flags |= OPF_FARGNR;
5064
5065       ops[j].flags |= OPF_FARG;
5066       ops[j].flags &= ~OPF_RSAVE;
5067
5068       // check for __VALIST
5069       if (!pp->is_unresolved && g_func_pp != NULL
5070         && pp->arg[arg].type.is_va_list)
5071       {
5072         k = -1;
5073         ret = resolve_origin(j, &ops[j].operand[0],
5074                 magic + 1, &k, NULL);
5075         if (ret == 1 && k >= 0)
5076         {
5077           if (ops[k].op == OP_LEA) {
5078             if (!g_func_pp->is_vararg)
5079               ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5080                    g_func_pp->name);
5081
5082             snprintf(buf, sizeof(buf), "arg_%X",
5083               g_func_pp->argc_stack * 4);
5084             if (strstr(ops[k].operand[1].name, buf)
5085              || strstr(ops[k].operand[1].name, "arglist"))
5086             {
5087               ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5088               ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5089               pp->arg[arg].is_saved = 0;
5090               reg = -1;
5091             }
5092             else
5093               ferr(&ops[k], "va_list arg detection failed\n");
5094           }
5095           // check for va_list from g_func_pp arg too
5096           else if (ops[k].op == OP_MOV
5097             && is_stack_access(&ops[k], &ops[k].operand[1]))
5098           {
5099             ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5100               buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5101             if (ret >= 0) {
5102               ops[k].flags |= OPF_RMD | OPF_DONE;
5103               ops[j].flags |= OPF_RMD;
5104               ops[j].p_argpass = ret + 1;
5105               pp->arg[arg].is_saved = 0;
5106               reg = -1;
5107             }
5108           }
5109         }
5110       }
5111
5112       if (pp->arg[arg].is_saved) {
5113         ops[j].flags &= ~OPF_RMD;
5114         ops[j].p_argnum = argnum;
5115       }
5116
5117       // tracking reg usage
5118       if (reg >= 0)
5119         *regmask |= 1 << reg;
5120
5121       arg++;
5122       argnum++;
5123       if (!pp->is_unresolved) {
5124         // next arg
5125         for (; arg < pp->argc; arg++, argnum++)
5126           if (pp->arg[arg].reg == NULL)
5127             break;
5128       }
5129       magic = (magic & 0xffffff) | (arg << 24);
5130     }
5131
5132     if (ops[j].p_arggrp > arg_grp_current) {
5133       save_args_seen = 0;
5134       arg_grp_current = ops[j].p_arggrp;
5135     }
5136     if (ops[j].p_argnum > 0)
5137       save_args_seen |= 1 << (ops[j].p_argnum - 1);
5138   }
5139
5140   if (arg < pp->argc) {
5141     ferr(po, "arg collect failed for '%s': %d/%d\n",
5142       pp->name, arg, pp->argc);
5143     return -1;
5144   }
5145
5146   if (arg_grp_current > *arg_grp)
5147     *arg_grp = arg_grp_current;
5148
5149   return arg;
5150 }
5151
5152 static int collect_call_args(struct parsed_op *po, int i,
5153   struct parsed_proto *pp, int *regmask, int magic)
5154 {
5155   // arg group is for cases when pushes for
5156   // multiple funcs are going on
5157   struct parsed_op *po_tmp;
5158   int arg_grp = 0;
5159   int ret;
5160   int a;
5161
5162   ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5163           0, 1, magic, 0, 0);
5164   if (ret < 0)
5165     return ret;
5166
5167   if (arg_grp != 0) {
5168     // propagate arg_grp
5169     for (a = 0; a < pp->argc; a++) {
5170       if (pp->arg[a].reg != NULL)
5171         continue;
5172
5173       po_tmp = pp->arg[a].datap;
5174       while (po_tmp != NULL) {
5175         po_tmp->p_arggrp = arg_grp;
5176         po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5177       }
5178     }
5179   }
5180
5181   if (pp->is_unresolved) {
5182     pp->argc += ret;
5183     pp->argc_stack += ret;
5184     for (a = 0; a < pp->argc; a++)
5185       if (pp->arg[a].type.name == NULL)
5186         pp->arg[a].type.name = strdup("int");
5187   }
5188
5189   return ret;
5190 }
5191
5192 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5193   int regmask_now, int *regmask,
5194   int regmask_save_now, int *regmask_save,
5195   int *regmask_init, int regmask_arg)
5196 {
5197   struct parsed_op *po;
5198   int already_saved;
5199   int regmask_new;
5200   int regmask_op;
5201   int flags_set;
5202   int ret, reg;
5203   int j;
5204
5205   for (; i < opcnt; i++)
5206   {
5207     po = &ops[i];
5208     if (cbits[i >> 3] & (1 << (i & 7)))
5209       return;
5210     cbits[i >> 3] |= (1 << (i & 7));
5211
5212     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5213       if (po->flags & (OPF_RMD|OPF_DONE))
5214         continue;
5215       if (po->btj != NULL) {
5216         for (j = 0; j < po->btj->count; j++) {
5217           check_i(po, po->btj->d[j].bt_i);
5218           reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5219             regmask_now, regmask, regmask_save_now, regmask_save,
5220             regmask_init, regmask_arg);
5221         }
5222         return;
5223       }
5224
5225       check_i(po, po->bt_i);
5226       if (po->flags & OPF_CJMP)
5227         reg_use_pass(po->bt_i, opcnt, cbits,
5228           regmask_now, regmask, regmask_save_now, regmask_save,
5229           regmask_init, regmask_arg);
5230       else
5231         i = po->bt_i - 1;
5232       continue;
5233     }
5234
5235     if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5236       && !g_func_pp->is_userstack
5237       && po->operand[0].type == OPT_REG)
5238     {
5239       reg = po->operand[0].reg;
5240       ferr_assert(po, reg >= 0);
5241
5242       already_saved = 0;
5243       flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5244       if (regmask_now & (1 << reg)) {
5245         already_saved = regmask_save_now & (1 << reg);
5246         flags_set = OPF_RSAVE | OPF_DONE;
5247       }
5248
5249       ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5250       if (ret == 1) {
5251         scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5252           reg, 0, 0, flags_set);
5253       }
5254       else {
5255         ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5256         if (ret == 1) {
5257           scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5258             flags_set);
5259         }
5260       }
5261       if (ret == 1) {
5262         ferr_assert(po, !already_saved);
5263         po->flags |= flags_set;
5264
5265         if (regmask_now & (1 << reg)) {
5266           regmask_save_now |= (1 << reg);
5267           *regmask_save |= regmask_save_now;
5268         }
5269         continue;
5270       }
5271     }
5272     else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5273       reg = po->operand[0].reg;
5274       ferr_assert(po, reg >= 0);
5275
5276       if (regmask_save_now & (1 << reg))
5277         regmask_save_now &= ~(1 << reg);
5278       else
5279         regmask_now &= ~(1 << reg);
5280       continue;
5281     }
5282     else if (po->op == OP_CALL) {
5283       if ((po->regmask_dst & (1 << xAX))
5284         && !(po->regmask_dst & (1 << xDX)))
5285       {
5286         if (po->flags & OPF_TAIL)
5287           // don't need eax, will do "return f();" or "f(); return;"
5288           po->regmask_dst &= ~(1 << xAX);
5289         else {
5290           struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5291           j = -1;
5292           find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5293           if (j == -1)
5294             // not used
5295             po->regmask_dst &= ~(1 << xAX);
5296         }
5297       }
5298
5299       // not "full stack" mode and have something in stack
5300       if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5301         ferr(po, "float stack is not empty on func call\n");
5302     }
5303
5304     if (po->flags & OPF_NOREGS)
5305       continue;
5306
5307     // if incomplete register is used, clear it on init to avoid
5308     // later use of uninitialized upper part in some situations
5309     if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5310         && po->operand[0].lmod != OPLM_DWORD)
5311     {
5312       reg = po->operand[0].reg;
5313       ferr_assert(po, reg >= 0);
5314
5315       if (!(regmask_now & (1 << reg)))
5316         *regmask_init |= 1 << reg;
5317     }
5318
5319     regmask_op = po->regmask_src | po->regmask_dst;
5320
5321     regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5322     regmask_new &= ~(1 << xSP);
5323     if (g_bp_frame && !(po->flags & OPF_EBP_S))
5324       regmask_new &= ~(1 << xBP);
5325
5326     if (regmask_new != 0)
5327       fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5328
5329     if (regmask_op & (1 << xBP)) {
5330       if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5331         if (po->regmask_dst & (1 << xBP))
5332           // compiler decided to drop bp frame and use ebp as scratch
5333           scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5334         else
5335           regmask_op &= ~(1 << xBP);
5336       }
5337     }
5338
5339     if (po->flags & OPF_FPUSH) {
5340       if (regmask_now & mxST1)
5341         regmask_now |= mxSTa; // switch to "full stack" mode
5342       if (regmask_now & mxSTa)
5343         po->flags |= OPF_FSHIFT;
5344       if (!(regmask_now & mxST7_2)) {
5345         regmask_now =
5346           (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5347       }
5348     }
5349
5350     regmask_now |= regmask_op;
5351     *regmask |= regmask_now;
5352
5353     // released regs
5354     if (po->flags & OPF_FPOP) {
5355       if ((regmask_now & mxSTa) == 0)
5356         ferr(po, "float pop on empty stack?\n");
5357       if (regmask_now & (mxST7_2 | mxST1))
5358         po->flags |= OPF_FSHIFT;
5359       if (!(regmask_now & mxST7_2)) {
5360         regmask_now =
5361           (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5362       }
5363     }
5364
5365     if (po->flags & OPF_TAIL) {
5366       if (!(regmask_now & mxST7_2)) {
5367         if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5368           if (!(regmask_now & mxST0))
5369             ferr(po, "no st0 on float return, mask: %x\n",
5370                  regmask_now);
5371         }
5372         else if (regmask_now & mxST1_0)
5373           ferr(po, "float regs on tail: %x\n", regmask_now);
5374       }
5375
5376       // there is support for "conditional tailcall", sort of
5377       if (!(po->flags & OPF_CC))
5378         return;
5379     }
5380   }
5381 }
5382
5383 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5384 {
5385   int i;
5386
5387   for (i = 0; i < pp->argc; i++)
5388     if (pp->arg[i].reg == NULL)
5389       break;
5390
5391   if (pp->argc_stack)
5392     memmove(&pp->arg[i + 1], &pp->arg[i],
5393       sizeof(pp->arg[0]) * pp->argc_stack);
5394   memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5395   pp->arg[i].reg = strdup(reg);
5396   pp->arg[i].type.name = strdup("int");
5397   pp->argc++;
5398   pp->argc_reg++;
5399 }
5400
5401 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5402   int *pfomask, const char *dst_opr_text)
5403 {
5404   if (*pfomask & (1 << PFO_Z)) {
5405     fprintf(fout, "\n  cond_z = (%s%s == 0);",
5406       lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5407     *pfomask &= ~(1 << PFO_Z);
5408   }
5409 }
5410
5411 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5412   int *pfomask, const char *dst_opr_text)
5413 {
5414   if (*pfomask & (1 << PFO_S)) {
5415     fprintf(fout, "\n  cond_s = (%s%s < 0);",
5416       lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5417     *pfomask &= ~(1 << PFO_S);
5418   }
5419 }
5420
5421 static void output_std_flags(FILE *fout, struct parsed_op *po,
5422   int *pfomask, const char *dst_opr_text)
5423 {
5424   output_std_flag_z(fout, po, pfomask, dst_opr_text);
5425   output_std_flag_s(fout, po, pfomask, dst_opr_text);
5426 }
5427
5428 enum {
5429   OPP_FORCE_NORETURN = (1 << 0),
5430   OPP_SIMPLE_ARGS    = (1 << 1),
5431   OPP_ALIGN          = (1 << 2),
5432 };
5433
5434 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5435   int flags)
5436 {
5437   const char *cconv = "";
5438
5439   if (pp->is_fastcall)
5440     cconv = "__fastcall ";
5441   else if (pp->is_stdcall && pp->argc_reg == 0)
5442     cconv = "__stdcall ";
5443
5444   fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5445
5446   if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5447     fprintf(fout, "noreturn ");
5448 }
5449
5450 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5451   int flags)
5452 {
5453   int i;
5454
5455   fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5456     pp->ret_type.name);
5457   if (pp->is_fptr)
5458     fprintf(fout, "(");
5459   output_pp_attrs(fout, pp, flags);
5460   if (pp->is_fptr)
5461     fprintf(fout, "*");
5462   fprintf(fout, "%s", pp->name);
5463   if (pp->is_fptr)
5464     fprintf(fout, ")");
5465
5466   fprintf(fout, "(");
5467   for (i = 0; i < pp->argc; i++) {
5468     if (i > 0)
5469       fprintf(fout, ", ");
5470     if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5471       && !(flags & OPP_SIMPLE_ARGS))
5472     {
5473       // func pointer
5474       output_pp(fout, pp->arg[i].pp, 0);
5475     }
5476     else if (pp->arg[i].type.is_retreg) {
5477       fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5478     }
5479     else {
5480       fprintf(fout, "%s", pp->arg[i].type.name);
5481       if (!pp->is_fptr)
5482         fprintf(fout, " a%d", i + 1);
5483     }
5484
5485     if (pp->arg[i].type.is_64bit)
5486       i++;
5487   }
5488   if (pp->is_vararg) {
5489     if (i > 0)
5490       fprintf(fout, ", ");
5491     fprintf(fout, "...");
5492   }
5493   fprintf(fout, ")");
5494 }
5495
5496 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5497 {
5498   char buf1[16];
5499
5500   buf1[0] = 0;
5501   if (grp > 0)
5502     snprintf(buf1, sizeof(buf1), "%d", grp);
5503   snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5504
5505   return buf;
5506 }
5507
5508 static void gen_x_cleanup(int opcnt);
5509
5510 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5511 {
5512   struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5513   struct parsed_opr *last_arith_dst = NULL;
5514   char buf1[256], buf2[256], buf3[256], cast[64];
5515   struct parsed_proto *pp, *pp_tmp;
5516   struct parsed_data *pd;
5517   int save_arg_vars[MAX_ARG_GRP] = { 0, };
5518   unsigned char cbits[MAX_OPS / 8];
5519   const char *float_type;
5520   const char *float_st0;
5521   const char *float_st1;
5522   int need_float_stack = 0;
5523   int need_float_sw = 0; // status word
5524   int need_tmp_var = 0;
5525   int need_tmp64 = 0;
5526   int cond_vars = 0;
5527   int had_decl = 0;
5528   int label_pending = 0;
5529   int need_double = 0;
5530   int stack_align = 0;
5531   int stack_fsz_adj = 0;
5532   int regmask_save = 0; // used regs saved/restored in this func
5533   int regmask_arg;      // regs from this function args (fastcall, etc)
5534   int regmask_ret;      // regs needed on ret
5535   int regmask_now;      // temp
5536   int regmask_init = 0; // regs that need zero initialization
5537   int regmask_pp = 0;   // regs used in complex push-pop graph
5538   int regmask_ffca = 0; // float function call args
5539   int regmask = 0;      // used regs
5540   int pfomask = 0;
5541   int found = 0;
5542   int dead_dst;
5543   int no_output;
5544   int i, j, l;
5545   int arg;
5546   int reg;
5547   int ret;
5548
5549   g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5550   g_stack_frame_used = 0;
5551   if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5552     regmask_init = g_regmask_init;
5553
5554   g_func_pp = proto_parse(fhdr, funcn, 0);
5555   if (g_func_pp == NULL)
5556     ferr(ops, "proto_parse failed for '%s'\n", funcn);
5557
5558   regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5559   regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5560
5561   // pass1:
5562   // - resolve all branches
5563   // - parse calls with labels
5564   resolve_branches_parse_calls(opcnt);
5565
5566   // pass2:
5567   // - handle ebp/esp frame, remove ops related to it
5568   scan_prologue_epilogue(opcnt, &stack_align);
5569
5570   // handle a case where sf size is unalignment, but is
5571   // placed in a way that elements are still aligned
5572   if (g_stack_fsz & 4) {
5573     for (i = 0; i < g_eqcnt; i++) {
5574       if (g_eqs[i].lmod != OPLM_QWORD)
5575         continue;
5576       if (!(g_eqs[i].offset & 4)) {
5577         g_stack_fsz += 4;
5578         stack_fsz_adj = 4;
5579       }
5580       break;
5581     }
5582   }
5583
5584   // pass3:
5585   // - remove dead labels
5586   // - set regs needed at ret
5587   for (i = 0; i < opcnt; i++)
5588   {
5589     if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5590       free(g_labels[i]);
5591       g_labels[i] = NULL;
5592     }
5593
5594     if (ops[i].op == OP_RET)
5595       ops[i].regmask_src |= regmask_ret;
5596   }
5597
5598   // pass4:
5599   // - process trivial calls
5600   for (i = 0; i < opcnt; i++)
5601   {
5602     po = &ops[i];
5603     if (po->flags & (OPF_RMD|OPF_DONE))
5604       continue;
5605
5606     if (po->op == OP_CALL)
5607     {
5608       pp = process_call_early(i, opcnt, &j);
5609       if (pp != NULL) {
5610         if (!(po->flags & OPF_ATAIL)) {
5611           // since we know the args, try to collect them
5612           ret = collect_call_args_early(i, pp, &regmask, &regmask_ffca);
5613           if (ret != 0)
5614             pp = NULL;
5615         }
5616       }
5617
5618       if (pp != NULL) {
5619         if (j >= 0) {
5620           // commit esp adjust
5621           if (ops[j].op != OP_POP)
5622             patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5623           else {
5624             for (l = 0; l < pp->argc_stack; l++)
5625               ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5626           }
5627         }
5628
5629         if (strstr(pp->ret_type.name, "int64"))
5630           need_tmp64 = 1;
5631
5632         po->flags |= OPF_DONE;
5633       }
5634     }
5635   }
5636
5637   // pass5:
5638   // - process calls, stage 2
5639   // - handle some push/pop pairs
5640   // - scan for STD/CLD, propagate DF
5641   // - try to resolve needed x87 status word bits
5642   for (i = 0; i < opcnt; i++)
5643   {
5644     int mask, z_check;
5645
5646     po = &ops[i];
5647     if (po->flags & OPF_RMD)
5648       continue;
5649
5650     if (po->op == OP_CALL)
5651     {
5652       if (!(po->flags & OPF_DONE)) {
5653         pp = process_call(i, opcnt);
5654
5655         if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5656           // since we know the args, collect them
5657           collect_call_args(po, i, pp, &regmask, i + opcnt * 2);
5658         }
5659         // for unresolved, collect after other passes
5660       }
5661
5662       pp = po->pp;
5663       ferr_assert(po, pp != NULL);
5664
5665       po->regmask_src |= get_pp_arg_regmask_src(pp);
5666       po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5667
5668       if (po->regmask_dst & mxST0)
5669         po->flags |= OPF_FPUSH;
5670
5671       if (strstr(pp->ret_type.name, "int64"))
5672         need_tmp64 = 1;
5673
5674       continue;
5675     }
5676
5677     if (po->flags & OPF_DONE)
5678       continue;
5679
5680     switch (po->op) {
5681     case OP_PUSH:
5682       if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
5683         && po->operand[0].type == OPT_CONST)
5684       {
5685         scan_for_pop_const(i, opcnt, i + opcnt * 12);
5686       }
5687       break;
5688
5689     case OP_POP:
5690       scan_pushes_for_pop(i, opcnt, &regmask_pp);
5691       break;
5692
5693     case OP_STD:
5694       po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5695       scan_propagate_df(i + 1, opcnt);
5696       break;
5697
5698     case OP_FNSTSW:
5699       need_float_sw = 1;
5700       if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
5701         ferr(po, "TODO: fnstsw to mem\n");
5702       ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
5703       if (ret != 0)
5704         ferr(po, "fnstsw resolve failed\n");
5705       ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
5706               (void *)(long)(mask | (z_check << 16)));
5707       if (ret != 1)
5708         ferr(po, "failed to find fcom: %d\n", ret);
5709       break;
5710
5711     default:
5712       break;
5713     }
5714   }
5715
5716   // pass6:
5717   // - find POPs for PUSHes, rm both
5718   // - scan for all used registers
5719   memset(cbits, 0, sizeof(cbits));
5720   reg_use_pass(0, opcnt, cbits, regmask_init, &regmask,
5721     0, &regmask_save, &regmask_init, regmask_arg);
5722
5723   need_float_stack = !!(regmask & mxST7_2);
5724
5725   // pass7:
5726   // - find flag set ops for their users
5727   // - do unresolved calls
5728   // - declare indirect functions
5729   // - other op specific processing
5730   for (i = 0; i < opcnt; i++)
5731   {
5732     po = &ops[i];
5733     if (po->flags & (OPF_RMD|OPF_DONE))
5734       continue;
5735
5736     if (po->flags & OPF_CC)
5737     {
5738       int setters[16], cnt = 0, branched = 0;
5739
5740       ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
5741               &branched, setters, &cnt);
5742       if (ret < 0 || cnt <= 0)
5743         ferr(po, "unable to trace flag setter(s)\n");
5744       if (cnt > ARRAY_SIZE(setters))
5745         ferr(po, "too many flag setters\n");
5746
5747       for (j = 0; j < cnt; j++)
5748       {
5749         tmp_op = &ops[setters[j]]; // flag setter
5750         pfomask = 0;
5751
5752         // to get nicer code, we try to delay test and cmp;
5753         // if we can't because of operand modification, or if we
5754         // have arith op, or branch, make it calculate flags explicitly
5755         if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5756         {
5757           if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5758             pfomask = 1 << po->pfo;
5759         }
5760         else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5761           pfomask = 1 << po->pfo;
5762         }
5763         else {
5764           // see if we'll be able to handle based on op result
5765           if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5766                && po->pfo != PFO_Z && po->pfo != PFO_S
5767                && po->pfo != PFO_P)
5768               || branched
5769               || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5770           {
5771             pfomask = 1 << po->pfo;
5772           }
5773
5774           if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5775             propagate_lmod(tmp_op, &tmp_op->operand[0],
5776               &tmp_op->operand[1]);
5777             if (tmp_op->operand[0].lmod == OPLM_DWORD)
5778               need_tmp64 = 1;
5779           }
5780         }
5781         if (pfomask) {
5782           tmp_op->pfomask |= pfomask;
5783           cond_vars |= pfomask;
5784         }
5785         // note: may overwrite, currently not a problem
5786         po->datap = tmp_op;
5787       }
5788
5789       if (po->op == OP_RCL || po->op == OP_RCR
5790        || po->op == OP_ADC || po->op == OP_SBB)
5791         cond_vars |= 1 << PFO_C;
5792     }
5793
5794     switch (po->op) {
5795     case OP_CMPS:
5796     case OP_SCAS:
5797       cond_vars |= 1 << PFO_Z;
5798       break;
5799
5800     case OP_MUL:
5801       if (po->operand[0].lmod == OPLM_DWORD)
5802         need_tmp64 = 1;
5803       break;
5804
5805     case OP_IMUL:
5806       if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
5807         need_tmp64 = 1;
5808       break;
5809
5810     case OP_CALL:
5811       // note: resolved non-reg calls are OPF_DONE already
5812       pp = po->pp;
5813       ferr_assert(po, pp != NULL);
5814
5815       if (pp->is_unresolved) {
5816         int regmask_stack = 0;
5817         collect_call_args(po, i, pp, &regmask, i + opcnt * 2);
5818
5819         // this is pretty rough guess:
5820         // see ecx and edx were pushed (and not their saved versions)
5821         for (arg = 0; arg < pp->argc; arg++) {
5822           if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
5823             continue;
5824
5825           tmp_op = pp->arg[arg].datap;
5826           if (tmp_op == NULL)
5827             ferr(po, "parsed_op missing for arg%d\n", arg);
5828           if (tmp_op->operand[0].type == OPT_REG)
5829             regmask_stack |= 1 << tmp_op->operand[0].reg;
5830         }
5831
5832         if (!((regmask_stack & (1 << xCX))
5833           && (regmask_stack & (1 << xDX))))
5834         {
5835           if (pp->argc_stack != 0
5836            || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5837           {
5838             pp_insert_reg_arg(pp, "ecx");
5839             pp->is_fastcall = 1;
5840             regmask_init |= 1 << xCX;
5841             regmask |= 1 << xCX;
5842           }
5843           if (pp->argc_stack != 0
5844            || ((regmask | regmask_arg) & (1 << xDX)))
5845           {
5846             pp_insert_reg_arg(pp, "edx");
5847             regmask_init |= 1 << xDX;
5848             regmask |= 1 << xDX;
5849           }
5850         }
5851
5852         // note: __cdecl doesn't fall into is_unresolved category
5853         if (pp->argc_stack > 0)
5854           pp->is_stdcall = 1;
5855       }
5856       break;
5857
5858     case OP_MOV:
5859       if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
5860       {
5861         // <var> = offset <something>
5862         if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5863           && !IS_START(po->operand[1].name, "off_"))
5864         {
5865           if (!po->operand[0].pp->is_fptr)
5866             ferr(po, "%s not declared as fptr when it should be\n",
5867               po->operand[0].name);
5868           if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5869             pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5870             pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5871             fnote(po, "var:  %s\n", buf1);
5872             fnote(po, "func: %s\n", buf2);
5873             ferr(po, "^ mismatch\n");
5874           }
5875         }
5876       }
5877       break;
5878
5879     case OP_DIV:
5880     case OP_IDIV:
5881       if (po->operand[0].lmod == OPLM_DWORD) {
5882         // 32bit division is common, look for it
5883         if (po->op == OP_DIV)
5884           ret = scan_for_reg_clear(i, xDX);
5885         else
5886           ret = scan_for_cdq_edx(i);
5887         if (ret >= 0)
5888           po->flags |= OPF_32BIT;
5889         else
5890           need_tmp64 = 1;
5891       }
5892       else
5893         need_tmp_var = 1;
5894       break;
5895
5896     case OP_CLD:
5897       po->flags |= OPF_RMD | OPF_DONE;
5898       break;
5899
5900     case OP_RCL:
5901     case OP_RCR:
5902     case OP_XCHG:
5903       need_tmp_var = 1;
5904       break;
5905
5906     case OP_FLD:
5907       if (po->operand[0].lmod == OPLM_QWORD)
5908         need_double = 1;
5909       break;
5910
5911     case OPP_ALLSHL:
5912     case OPP_ALLSHR:
5913       need_tmp64 = 1;
5914       break;
5915
5916     case OPP_FTOL: {
5917       struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5918       j = -1;
5919       find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5920       if (j == -1)
5921         po->flags |= OPF_32BIT;
5922       break;
5923     }
5924
5925     default:
5926       break;
5927     }
5928
5929     // this might need it's own pass...
5930     if (po->op != OP_FST && po->p_argnum > 0)
5931       save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
5932
5933     // correct for "full stack" mode late enable
5934     if ((po->flags & (OPF_PPUSH|OPF_FPOP)) && need_float_stack)
5935       po->flags |= OPF_FSHIFT;
5936   }
5937
5938   float_type = need_double ? "double" : "float";
5939   float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
5940   float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
5941
5942   // output starts here
5943
5944   // define userstack size
5945   if (g_func_pp->is_userstack) {
5946     fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5947     fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5948     fprintf(fout, "#endif\n");
5949   }
5950
5951   // the function itself
5952   ferr_assert(ops, !g_func_pp->is_fptr);
5953   output_pp(fout, g_func_pp,
5954     (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5955   fprintf(fout, "\n{\n");
5956
5957   // declare indirect functions
5958   for (i = 0; i < opcnt; i++) {
5959     po = &ops[i];
5960     if (po->flags & OPF_RMD)
5961       continue;
5962
5963     if (po->op == OP_CALL) {
5964       pp = po->pp;
5965       if (pp == NULL)
5966         ferr(po, "NULL pp\n");
5967
5968       if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5969         if (pp->name[0] != 0) {
5970           memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5971           memcpy(pp->name, "i_", 2);
5972
5973           // might be declared already
5974           found = 0;
5975           for (j = 0; j < i; j++) {
5976             if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5977               if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5978                 found = 1;
5979                 break;
5980               }
5981             }
5982           }
5983           if (found)
5984             continue;
5985         }
5986         else
5987           snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5988
5989         fprintf(fout, "  ");
5990         output_pp(fout, pp, OPP_SIMPLE_ARGS);
5991         fprintf(fout, ";\n");
5992       }
5993     }
5994   }
5995
5996   // output LUTs/jumptables
5997   for (i = 0; i < g_func_pd_cnt; i++) {
5998     pd = &g_func_pd[i];
5999     fprintf(fout, "  static const ");
6000     if (pd->type == OPT_OFFSET) {
6001       fprintf(fout, "void *jt_%s[] =\n    { ", pd->label);
6002
6003       for (j = 0; j < pd->count; j++) {
6004         if (j > 0)
6005           fprintf(fout, ", ");
6006         fprintf(fout, "&&%s", pd->d[j].u.label);
6007       }
6008     }
6009     else {
6010       fprintf(fout, "%s %s[] =\n    { ",
6011         lmod_type_u(ops, pd->lmod), pd->label);
6012
6013       for (j = 0; j < pd->count; j++) {
6014         if (j > 0)
6015           fprintf(fout, ", ");
6016         fprintf(fout, "%u", pd->d[j].u.val);
6017       }
6018     }
6019     fprintf(fout, " };\n");
6020     had_decl = 1;
6021   }
6022
6023   // declare stack frame, va_arg
6024   if (g_stack_fsz) {
6025     if (stack_fsz_adj)
6026       fprintf(fout, "  // stack_fsz_adj %d\n", stack_fsz_adj);
6027
6028     fprintf(fout, "  union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6029     if (g_func_lmods & (1 << OPLM_WORD))
6030       fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6031     if (g_func_lmods & (1 << OPLM_BYTE))
6032       fprintf(fout, " u8 b[%d];", g_stack_fsz);
6033     if (g_func_lmods & (1 << OPLM_QWORD))
6034       fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6035
6036     if (stack_align > 8)
6037       ferr(ops, "unhandled stack align of %d\n", stack_align);
6038     else if (stack_align == 8)
6039       fprintf(fout, " u64 align;");
6040     fprintf(fout, " } sf;\n");
6041     had_decl = 1;
6042   }
6043
6044   if (g_func_pp->is_userstack) {
6045     fprintf(fout, "  u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6046     fprintf(fout, "  u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6047     had_decl = 1;
6048   }
6049
6050   if (g_func_pp->is_vararg) {
6051     fprintf(fout, "  va_list ap;\n");
6052     had_decl = 1;
6053   }
6054
6055   // declare arg-registers
6056   for (i = 0; i < g_func_pp->argc; i++) {
6057     if (g_func_pp->arg[i].reg != NULL) {
6058       reg = char_array_i(regs_r32,
6059               ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6060       if (regmask & (1 << reg)) {
6061         if (g_func_pp->arg[i].type.is_retreg)
6062           fprintf(fout, "  u32 %s = *r_%s;\n",
6063             g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6064         else
6065           fprintf(fout, "  u32 %s = (u32)a%d;\n",
6066             g_func_pp->arg[i].reg, i + 1);
6067       }
6068       else {
6069         if (g_func_pp->arg[i].type.is_retreg)
6070           ferr(ops, "retreg '%s' is unused?\n",
6071             g_func_pp->arg[i].reg);
6072         fprintf(fout, "  // %s = a%d; // unused\n",
6073           g_func_pp->arg[i].reg, i + 1);
6074       }
6075       had_decl = 1;
6076     }
6077   }
6078
6079   // declare normal registers
6080   regmask_now = regmask & ~regmask_arg;
6081   regmask_now &= ~(1 << xSP);
6082   if (regmask_now & 0x00ff) {
6083     for (reg = 0; reg < 8; reg++) {
6084       if (regmask_now & (1 << reg)) {
6085         fprintf(fout, "  u32 %s", regs_r32[reg]);
6086         if (regmask_init & (1 << reg))
6087           fprintf(fout, " = 0");
6088         fprintf(fout, ";\n");
6089         had_decl = 1;
6090       }
6091     }
6092   }
6093   // ... mmx
6094   if (regmask_now & 0xff00) {
6095     for (reg = 8; reg < 16; reg++) {
6096       if (regmask_now & (1 << reg)) {
6097         fprintf(fout, "  mmxr %s", regs_r32[reg]);
6098         if (regmask_init & (1 << reg))
6099           fprintf(fout, " = { 0, }");
6100         fprintf(fout, ";\n");
6101         had_decl = 1;
6102       }
6103     }
6104   }
6105   // ... x87
6106   if (need_float_stack) {
6107     fprintf(fout, "  %s f_st[8];\n", float_type);
6108     fprintf(fout, "  int f_stp = 0;\n");
6109     had_decl = 1;
6110   }
6111   else {
6112     if (regmask_now & 0xff0000) {
6113       for (reg = 16; reg < 24; reg++) {
6114         if (regmask_now & (1 << reg)) {
6115           fprintf(fout, "  %s f_st%d", float_type, reg - 16);
6116           if (regmask_init & (1 << reg))
6117             fprintf(fout, " = 0");
6118           fprintf(fout, ";\n");
6119           had_decl = 1;
6120         }
6121       }
6122     }
6123   }
6124
6125   if (need_float_sw) {
6126     fprintf(fout, "  u16 f_sw;\n");
6127     had_decl = 1;
6128   }
6129
6130   if (regmask_save) {
6131     for (reg = 0; reg < 8; reg++) {
6132       if (regmask_save & (1 << reg)) {
6133         fprintf(fout, "  u32 s_%s;\n", regs_r32[reg]);
6134         had_decl = 1;
6135       }
6136     }
6137   }
6138
6139   for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6140     if (save_arg_vars[i] == 0)
6141       continue;
6142     for (reg = 0; reg < 32; reg++) {
6143       if (save_arg_vars[i] & (1 << reg)) {
6144         fprintf(fout, "  u32 %s;\n",
6145           saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6146         had_decl = 1;
6147       }
6148     }
6149   }
6150
6151   if (regmask_ffca) {
6152     for (reg = 0; reg < 32; reg++) {
6153       if (regmask_ffca & (1 << reg)) {
6154         fprintf(fout, "  %s fs_%d;\n", float_type, reg + 1);
6155         had_decl = 1;
6156       }
6157     }
6158   }
6159
6160   // declare push-pop temporaries
6161   if (regmask_pp) {
6162     for (reg = 0; reg < 8; reg++) {
6163       if (regmask_pp & (1 << reg)) {
6164         fprintf(fout, "  u32 pp_%s;\n", regs_r32[reg]);
6165         had_decl = 1;
6166       }
6167     }
6168   }
6169
6170   if (cond_vars) {
6171     for (i = 0; i < 8; i++) {
6172       if (cond_vars & (1 << i)) {
6173         fprintf(fout, "  u32 cond_%s;\n", parsed_flag_op_names[i]);
6174         had_decl = 1;
6175       }
6176     }
6177   }
6178
6179   if (need_tmp_var) {
6180     fprintf(fout, "  u32 tmp;\n");
6181     had_decl = 1;
6182   }
6183
6184   if (need_tmp64) {
6185     fprintf(fout, "  u64 tmp64;\n");
6186     had_decl = 1;
6187   }
6188
6189   if (had_decl)
6190     fprintf(fout, "\n");
6191
6192   // do stack clear, if needed
6193   if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6194     fprintf(fout, "  ");
6195     if (g_stack_clear_len != 0) {
6196       if (g_stack_clear_len <= 4) {
6197         for (i = 0; i < g_stack_clear_len; i++)
6198           fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6199         fprintf(fout, "0;\n");
6200       }
6201       else {
6202         fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6203           g_stack_clear_start, g_stack_clear_len * 4);
6204       }
6205     }
6206     else
6207       fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6208   }
6209
6210   if (g_func_pp->is_vararg) {
6211     if (g_func_pp->argc_stack == 0)
6212       ferr(ops, "vararg func without stack args?\n");
6213     fprintf(fout, "  va_start(ap, a%d);\n", g_func_pp->argc);
6214   }
6215
6216   // output ops
6217   for (i = 0; i < opcnt; i++)
6218   {
6219     if (g_labels[i] != NULL) {
6220       fprintf(fout, "\n%s:\n", g_labels[i]);
6221       label_pending = 1;
6222
6223       delayed_flag_op = NULL;
6224       last_arith_dst = NULL;
6225     }
6226
6227     po = &ops[i];
6228     if (po->flags & OPF_RMD)
6229       continue;
6230
6231     no_output = 0;
6232
6233     #define assert_operand_cnt(n_) \
6234       if (po->operand_cnt != n_) \
6235         ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6236
6237     // conditional/flag using op?
6238     if (po->flags & OPF_CC)
6239     {
6240       int is_delayed = 0;
6241
6242       tmp_op = po->datap;
6243
6244       // we go through all this trouble to avoid using parsed_flag_op,
6245       // which makes generated code much nicer
6246       if (delayed_flag_op != NULL)
6247       {
6248         out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6249           po->pfo, po->pfo_inv);
6250         is_delayed = 1;
6251       }
6252       else if (last_arith_dst != NULL
6253         && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6254            || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6255            ))
6256       {
6257         out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6258         out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6259           last_arith_dst->lmod, buf3);
6260         is_delayed = 1;
6261       }
6262       else if (tmp_op != NULL) {
6263         // use preprocessed flag calc results
6264         if (!(tmp_op->pfomask & (1 << po->pfo)))
6265           ferr(po, "not prepared for pfo %d\n", po->pfo);
6266
6267         // note: pfo_inv was not yet applied
6268         snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6269           po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6270       }
6271       else {
6272         ferr(po, "all methods of finding comparison failed\n");
6273       }
6274  
6275       if (po->flags & OPF_JMP) {
6276         fprintf(fout, "  if %s", buf1);
6277       }
6278       else if (po->op == OP_RCL || po->op == OP_RCR
6279                || po->op == OP_ADC || po->op == OP_SBB)
6280       {
6281         if (is_delayed)
6282           fprintf(fout, "  cond_%s = %s;\n",
6283             parsed_flag_op_names[po->pfo], buf1);
6284       }
6285       else if (po->flags & OPF_DATA) { // SETcc
6286         out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6287         fprintf(fout, "  %s = %s;", buf2, buf1);
6288       }
6289       else {
6290         ferr(po, "unhandled conditional op\n");
6291       }
6292     }
6293
6294     pfomask = po->pfomask;
6295
6296     switch (po->op)
6297     {
6298       case OP_MOV:
6299         assert_operand_cnt(2);
6300         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6301         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6302         default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6303         fprintf(fout, "  %s = %s;", buf1,
6304             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6305               buf3, 0));
6306         break;
6307
6308       case OP_LEA:
6309         assert_operand_cnt(2);
6310         po->operand[1].lmod = OPLM_DWORD; // always
6311         fprintf(fout, "  %s = %s;",
6312             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6313             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6314               NULL, 1));
6315         break;
6316
6317       case OP_MOVZX:
6318         assert_operand_cnt(2);
6319         fprintf(fout, "  %s = %s;",
6320             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6321             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6322         break;
6323
6324       case OP_MOVSX:
6325         assert_operand_cnt(2);
6326         switch (po->operand[1].lmod) {
6327         case OPLM_BYTE:
6328           strcpy(buf3, "(s8)");
6329           break;
6330         case OPLM_WORD:
6331           strcpy(buf3, "(s16)");
6332           break;
6333         default:
6334           ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6335         }
6336         fprintf(fout, "  %s = %s;",
6337             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6338             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6339               buf3, 0));
6340         break;
6341
6342       case OP_XCHG:
6343         assert_operand_cnt(2);
6344         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6345         fprintf(fout, "  tmp = %s;",
6346           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6347         fprintf(fout, " %s = %s;",
6348           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6349           out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6350             default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6351         fprintf(fout, " %s = %stmp;",
6352           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6353           default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6354         snprintf(g_comment, sizeof(g_comment), "xchg");
6355         break;
6356
6357       case OP_NOT:
6358         assert_operand_cnt(1);
6359         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6360         fprintf(fout, "  %s = ~%s;", buf1, buf1);
6361         break;
6362
6363       case OP_XLAT:
6364         assert_operand_cnt(2);
6365         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6366         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6367         fprintf(fout, "  %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6368         strcpy(g_comment, "xlat");
6369         break;
6370
6371       case OP_CDQ:
6372         assert_operand_cnt(2);
6373         fprintf(fout, "  %s = (s32)%s >> 31;",
6374             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6375             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6376         strcpy(g_comment, "cdq");
6377         break;
6378
6379       case OP_BSWAP:
6380         assert_operand_cnt(1);
6381         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6382         fprintf(fout, "  %s = __builtin_bswap32(%s);", buf1, buf1);
6383         break;
6384
6385       case OP_LODS:
6386         if (po->flags & OPF_REP) {
6387           assert_operand_cnt(3);
6388           // hmh..
6389           ferr(po, "TODO\n");
6390         }
6391         else {
6392           assert_operand_cnt(2);
6393           fprintf(fout, "  %s = %sesi; esi %c= %d;",
6394             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6395             lmod_cast_u_ptr(po, po->operand[1].lmod),
6396             (po->flags & OPF_DF) ? '-' : '+',
6397             lmod_bytes(po, po->operand[1].lmod));
6398           strcpy(g_comment, "lods");
6399         }
6400         break;
6401
6402       case OP_STOS:
6403         if (po->flags & OPF_REP) {
6404           assert_operand_cnt(3);
6405           fprintf(fout, "  for (; ecx != 0; ecx--, edi %c= %d)\n",
6406             (po->flags & OPF_DF) ? '-' : '+',
6407             lmod_bytes(po, po->operand[1].lmod));
6408           fprintf(fout, "    %sedi = eax;",
6409             lmod_cast_u_ptr(po, po->operand[1].lmod));
6410           strcpy(g_comment, "rep stos");
6411         }
6412         else {
6413           assert_operand_cnt(2);
6414           fprintf(fout, "  %sedi = eax; edi %c= %d;",
6415             lmod_cast_u_ptr(po, po->operand[1].lmod),
6416             (po->flags & OPF_DF) ? '-' : '+',
6417             lmod_bytes(po, po->operand[1].lmod));
6418           strcpy(g_comment, "stos");
6419         }
6420         break;
6421
6422       case OP_MOVS:
6423         j = lmod_bytes(po, po->operand[0].lmod);
6424         strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6425         l = (po->flags & OPF_DF) ? '-' : '+';
6426         if (po->flags & OPF_REP) {
6427           assert_operand_cnt(3);
6428           fprintf(fout,
6429             "  for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6430             l, j, l, j);
6431           fprintf(fout,
6432             "    %sedi = %sesi;", buf1, buf1);
6433           strcpy(g_comment, "rep movs");
6434         }
6435         else {
6436           assert_operand_cnt(2);
6437           fprintf(fout, "  %sedi = %sesi; edi %c= %d; esi %c= %d;",
6438             buf1, buf1, l, j, l, j);
6439           strcpy(g_comment, "movs");
6440         }
6441         break;
6442
6443       case OP_CMPS:
6444         // repe ~ repeat while ZF=1
6445         j = lmod_bytes(po, po->operand[0].lmod);
6446         strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6447         l = (po->flags & OPF_DF) ? '-' : '+';
6448         if (po->flags & OPF_REP) {
6449           assert_operand_cnt(3);
6450           fprintf(fout,
6451             "  while (ecx != 0) {\n");
6452           if (pfomask & (1 << PFO_C)) {
6453             // ugh..
6454             fprintf(fout,
6455             "    cond_c = %sesi < %sedi;\n", buf1, buf1);
6456             pfomask &= ~(1 << PFO_C);
6457           }
6458           fprintf(fout,
6459             "    cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6460               buf1, buf1, l, j, l, j);
6461           fprintf(fout,
6462             "    ecx--;\n"
6463             "    if (cond_z %s 0) break;\n",
6464               (po->flags & OPF_REPZ) ? "==" : "!=");
6465           fprintf(fout,
6466             "  }");
6467           snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6468             (po->flags & OPF_REPZ) ? "e" : "ne");
6469         }
6470         else {
6471           assert_operand_cnt(2);
6472           fprintf(fout,
6473             "  cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6474             buf1, buf1, l, j, l, j);
6475           strcpy(g_comment, "cmps");
6476         }
6477         pfomask &= ~(1 << PFO_Z);
6478         last_arith_dst = NULL;
6479         delayed_flag_op = NULL;
6480         break;
6481
6482       case OP_SCAS:
6483         // only does ZF (for now)
6484         // repe ~ repeat while ZF=1
6485         j = lmod_bytes(po, po->operand[1].lmod);
6486         l = (po->flags & OPF_DF) ? '-' : '+';
6487         if (po->flags & OPF_REP) {
6488           assert_operand_cnt(3);
6489           fprintf(fout,
6490             "  while (ecx != 0) {\n");
6491           fprintf(fout,
6492             "    cond_z = (%seax == %sedi); edi %c= %d;\n",
6493               lmod_cast_u(po, po->operand[1].lmod),
6494               lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6495           fprintf(fout,
6496             "    ecx--;\n"
6497             "    if (cond_z %s 0) break;\n",
6498               (po->flags & OPF_REPZ) ? "==" : "!=");
6499           fprintf(fout,
6500             "  }");
6501           snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6502             (po->flags & OPF_REPZ) ? "e" : "ne");
6503         }
6504         else {
6505           assert_operand_cnt(2);
6506           fprintf(fout, "  cond_z = (%seax == %sedi); edi %c= %d;",
6507               lmod_cast_u(po, po->operand[1].lmod),
6508               lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6509           strcpy(g_comment, "scas");
6510         }
6511         pfomask &= ~(1 << PFO_Z);
6512         last_arith_dst = NULL;
6513         delayed_flag_op = NULL;
6514         break;
6515
6516       // arithmetic w/flags
6517       case OP_AND:
6518         if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6519           goto dualop_arith_const;
6520         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6521         goto dualop_arith;
6522
6523       case OP_OR:
6524         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6525         if (po->operand[1].type == OPT_CONST) {
6526           j = lmod_bytes(po, po->operand[0].lmod);
6527           if (((1ull << j * 8) - 1) == po->operand[1].val)
6528             goto dualop_arith_const;
6529         }
6530         goto dualop_arith;
6531
6532       dualop_arith:
6533         assert_operand_cnt(2);
6534         fprintf(fout, "  %s %s= %s;",
6535             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6536             op_to_c(po),
6537             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6538         output_std_flags(fout, po, &pfomask, buf1);
6539         last_arith_dst = &po->operand[0];
6540         delayed_flag_op = NULL;
6541         break;
6542
6543       dualop_arith_const:
6544         // and 0, or ~0 used instead mov
6545         assert_operand_cnt(2);
6546         fprintf(fout, "  %s = %s;",
6547           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6548           out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6549            default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6550         output_std_flags(fout, po, &pfomask, buf1);
6551         last_arith_dst = &po->operand[0];
6552         delayed_flag_op = NULL;
6553         break;
6554
6555       case OP_SHL:
6556       case OP_SHR:
6557         assert_operand_cnt(2);
6558         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6559         if (pfomask & (1 << PFO_C)) {
6560           if (po->operand[1].type == OPT_CONST) {
6561             l = lmod_bytes(po, po->operand[0].lmod) * 8;
6562             j = po->operand[1].val;
6563             j %= l;
6564             if (j != 0) {
6565               if (po->op == OP_SHL)
6566                 j = l - j;
6567               else
6568                 j -= 1;
6569               fprintf(fout, "  cond_c = (%s >> %d) & 1;\n",
6570                 buf1, j);
6571             }
6572             else
6573               ferr(po, "zero shift?\n");
6574           }
6575           else
6576             ferr(po, "TODO\n");
6577           pfomask &= ~(1 << PFO_C);
6578         }
6579         fprintf(fout, "  %s %s= %s", buf1, op_to_c(po),
6580             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6581         if (po->operand[1].type != OPT_CONST)
6582           fprintf(fout, " & 0x1f");
6583         fprintf(fout, ";");
6584         output_std_flags(fout, po, &pfomask, buf1);
6585         last_arith_dst = &po->operand[0];
6586         delayed_flag_op = NULL;
6587         break;
6588
6589       case OP_SAR:
6590         assert_operand_cnt(2);
6591         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6592         fprintf(fout, "  %s = %s%s >> %s;", buf1,
6593           lmod_cast_s(po, po->operand[0].lmod), buf1,
6594           out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6595         output_std_flags(fout, po, &pfomask, buf1);
6596         last_arith_dst = &po->operand[0];
6597         delayed_flag_op = NULL;
6598         break;
6599
6600       case OP_SHLD:
6601       case OP_SHRD:
6602         assert_operand_cnt(3);
6603         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6604         l = lmod_bytes(po, po->operand[0].lmod) * 8;
6605         out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6606         if (po->operand[2].type != OPT_CONST) {
6607           // no handling for "undefined" case, hopefully not needed
6608           snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6609           strcpy(buf3, buf2);
6610         }
6611         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6612         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6613         if (po->op == OP_SHLD) {
6614           fprintf(fout, "  %s <<= %s; %s |= %s >> (%d - %s);",
6615             buf1, buf3, buf1, buf2, l, buf3);
6616           strcpy(g_comment, "shld");
6617         }
6618         else {
6619           fprintf(fout, "  %s >>= %s; %s |= %s << (%d - %s);",
6620             buf1, buf3, buf1, buf2, l, buf3);
6621           strcpy(g_comment, "shrd");
6622         }
6623         output_std_flags(fout, po, &pfomask, buf1);
6624         last_arith_dst = &po->operand[0];
6625         delayed_flag_op = NULL;
6626         break;
6627
6628       case OP_ROL:
6629       case OP_ROR:
6630         assert_operand_cnt(2);
6631         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6632         if (po->operand[1].type == OPT_CONST) {
6633           j = po->operand[1].val;
6634           j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6635           fprintf(fout, po->op == OP_ROL ?
6636             "  %s = (%s << %d) | (%s >> %d);" :
6637             "  %s = (%s >> %d) | (%s << %d);",
6638             buf1, buf1, j, buf1,
6639             lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6640         }
6641         else
6642           ferr(po, "TODO\n");
6643         output_std_flags(fout, po, &pfomask, buf1);
6644         last_arith_dst = &po->operand[0];
6645         delayed_flag_op = NULL;
6646         break;
6647
6648       case OP_RCL:
6649       case OP_RCR:
6650         assert_operand_cnt(2);
6651         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6652         l = lmod_bytes(po, po->operand[0].lmod) * 8;
6653         if (po->operand[1].type == OPT_CONST) {
6654           j = po->operand[1].val % l;
6655           if (j == 0)
6656             ferr(po, "zero rotate\n");
6657           fprintf(fout, "  tmp = (%s >> %d) & 1;\n",
6658             buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6659           if (po->op == OP_RCL) {
6660             fprintf(fout,
6661               "  %s = (%s << %d) | (cond_c << %d)",
6662               buf1, buf1, j, j - 1);
6663             if (j != 1)
6664               fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6665           }
6666           else {
6667             fprintf(fout,
6668               "  %s = (%s >> %d) | (cond_c << %d)",
6669               buf1, buf1, j, l - j);
6670             if (j != 1)
6671               fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6672           }
6673           fprintf(fout, ";\n");
6674           fprintf(fout, "  cond_c = tmp;");
6675         }
6676         else
6677           ferr(po, "TODO\n");
6678         strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6679         output_std_flags(fout, po, &pfomask, buf1);
6680         last_arith_dst = &po->operand[0];
6681         delayed_flag_op = NULL;
6682         break;
6683
6684       case OP_XOR:
6685         assert_operand_cnt(2);
6686         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6687         if (IS(opr_name(po, 0), opr_name(po, 1))) {
6688           // special case for XOR
6689           int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
6690           for (j = 0; j <= PFO_LE; j++) {
6691             if (pfomask & (1 << j)) {
6692               fprintf(fout, "  cond_%s = %d;\n",
6693                 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
6694               pfomask &= ~(1 << j);
6695             }
6696           }
6697           fprintf(fout, "  %s = 0;",
6698             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6699           last_arith_dst = &po->operand[0];
6700           delayed_flag_op = NULL;
6701           break;
6702         }
6703         goto dualop_arith;
6704
6705       case OP_ADD:
6706         assert_operand_cnt(2);
6707         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6708         if (pfomask & (1 << PFO_C)) {
6709           out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6710           out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6711           if (po->operand[0].lmod == OPLM_DWORD) {
6712             fprintf(fout, "  tmp64 = (u64)%s + %s;\n", buf1, buf2);
6713             fprintf(fout, "  cond_c = tmp64 >> 32;\n");
6714             fprintf(fout, "  %s = (u32)tmp64;",
6715               out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6716             strcat(g_comment, " add64");
6717           }
6718           else {
6719             fprintf(fout, "  cond_c = ((u32)%s + %s) >> %d;\n",
6720               buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6721             fprintf(fout, "  %s += %s;",
6722               out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6723               buf2);
6724           }
6725           pfomask &= ~(1 << PFO_C);
6726           output_std_flags(fout, po, &pfomask, buf1);
6727           last_arith_dst = &po->operand[0];
6728           delayed_flag_op = NULL;
6729           break;
6730         }
6731         if (pfomask & (1 << PFO_LE)) {
6732           out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
6733           fprintf(fout, "  cond_%s = %s;\n",
6734             parsed_flag_op_names[PFO_LE], buf1);
6735           pfomask &= ~(1 << PFO_LE);
6736         }
6737         goto dualop_arith;
6738
6739       case OP_SUB:
6740         assert_operand_cnt(2);
6741         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6742         if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6743           for (j = 0; j <= PFO_LE; j++) {
6744             if (!(pfomask & (1 << j)))
6745               continue;
6746             if (j == PFO_Z || j == PFO_S)
6747               continue;
6748
6749             out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6750             fprintf(fout, "  cond_%s = %s;\n",
6751               parsed_flag_op_names[j], buf1);
6752             pfomask &= ~(1 << j);
6753           }
6754         }
6755         goto dualop_arith;
6756
6757       case OP_ADC:
6758       case OP_SBB:
6759         assert_operand_cnt(2);
6760         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6761         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6762         if (po->op == OP_SBB
6763           && IS(po->operand[0].name, po->operand[1].name))
6764         {
6765           // avoid use of unitialized var
6766           fprintf(fout, "  %s = -cond_c;", buf1);
6767           // carry remains what it was
6768           pfomask &= ~(1 << PFO_C);
6769         }
6770         else {
6771           fprintf(fout, "  %s %s= %s + cond_c;", buf1, op_to_c(po),
6772             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6773         }
6774         output_std_flags(fout, po, &pfomask, buf1);
6775         last_arith_dst = &po->operand[0];
6776         delayed_flag_op = NULL;
6777         break;
6778
6779       case OP_BSF:
6780       case OP_BSR:
6781         // on SKL, if src is 0, dst is left unchanged
6782         assert_operand_cnt(2);
6783         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6784         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6785         output_std_flag_z(fout, po, &pfomask, buf2);
6786         if (po->op == OP_BSF)
6787           snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
6788         else
6789           snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
6790         fprintf(fout, "  if (%s) %s = %s;", buf2, buf1, buf3);
6791         last_arith_dst = &po->operand[0];
6792         delayed_flag_op = NULL;
6793         strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
6794         break;
6795
6796       case OP_DEC:
6797         if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6798           for (j = 0; j <= PFO_LE; j++) {
6799             if (!(pfomask & (1 << j)))
6800               continue;
6801             if (j == PFO_Z || j == PFO_S || j == PFO_C)
6802               continue;
6803
6804             out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6805             fprintf(fout, "  cond_%s = %s;\n",
6806               parsed_flag_op_names[j], buf1);
6807             pfomask &= ~(1 << j);
6808           }
6809         }
6810         // fallthrough
6811
6812       case OP_INC:
6813         if (pfomask & (1 << PFO_C))
6814           // carry is unaffected by inc/dec.. wtf?
6815           ferr(po, "carry propagation needed\n");
6816
6817         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6818         if (po->operand[0].type == OPT_REG) {
6819           strcpy(buf2, po->op == OP_INC ? "++" : "--");
6820           fprintf(fout, "  %s%s;", buf1, buf2);
6821         }
6822         else {
6823           strcpy(buf2, po->op == OP_INC ? "+" : "-");
6824           fprintf(fout, "  %s %s= 1;", buf1, buf2);
6825         }
6826         output_std_flags(fout, po, &pfomask, buf1);
6827         last_arith_dst = &po->operand[0];
6828         delayed_flag_op = NULL;
6829         break;
6830
6831       case OP_NEG:
6832         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6833         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6834         fprintf(fout, "  %s = -%s%s;", buf1,
6835           lmod_cast_s(po, po->operand[0].lmod), buf2);
6836         last_arith_dst = &po->operand[0];
6837         delayed_flag_op = NULL;
6838         if (pfomask & PFOB_C) {
6839           fprintf(fout, "\n  cond_c = (%s != 0);", buf1);
6840           pfomask &= ~PFOB_C;
6841         }
6842         output_std_flags(fout, po, &pfomask, buf1);
6843         break;
6844
6845       case OP_IMUL:
6846         if (po->operand_cnt == 2) {
6847           propagate_lmod(po, &po->operand[0], &po->operand[1]);
6848           goto dualop_arith;
6849         }
6850         if (po->operand_cnt == 3)
6851           ferr(po, "TODO imul3\n");
6852         // fallthrough
6853       case OP_MUL:
6854         assert_operand_cnt(1);
6855         switch (po->operand[0].lmod) {
6856         case OPLM_DWORD:
6857           strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6858           fprintf(fout, "  tmp64 = %seax * %s%s;\n", buf1, buf1,
6859             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6860           fprintf(fout, "  edx = tmp64 >> 32;\n");
6861           fprintf(fout, "  eax = tmp64;");
6862           break;
6863         case OPLM_BYTE:
6864           strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6865           fprintf(fout, "  LOWORD(eax) = %seax * %s;", buf1,
6866             out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6867               buf1, 0));
6868           break;
6869         default:
6870           ferr(po, "TODO: unhandled mul type\n");
6871           break;
6872         }
6873         last_arith_dst = NULL;
6874         delayed_flag_op = NULL;
6875         break;
6876
6877       case OP_DIV:
6878       case OP_IDIV:
6879         assert_operand_cnt(1);
6880         out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6881         strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6882           po->op == OP_IDIV));
6883         switch (po->operand[0].lmod) {
6884         case OPLM_DWORD:
6885           if (po->flags & OPF_32BIT)
6886             snprintf(buf2, sizeof(buf2), "%seax", cast);
6887           else {
6888             fprintf(fout, "  tmp64 = ((u64)edx << 32) | eax;\n");
6889             snprintf(buf2, sizeof(buf2), "%stmp64",
6890               (po->op == OP_IDIV) ? "(s64)" : "");
6891           }
6892           if (po->operand[0].type == OPT_REG
6893             && po->operand[0].reg == xDX)
6894           {
6895             fprintf(fout, "  eax = %s / %s%s;\n", buf2, cast, buf1);
6896             fprintf(fout, "  edx = %s %% %s%s;", buf2, cast, buf1);
6897           }
6898           else {
6899             fprintf(fout, "  edx = %s %% %s%s;\n", buf2, cast, buf1);
6900             fprintf(fout, "  eax = %s / %s%s;", buf2, cast, buf1);
6901           }
6902           break;
6903         case OPLM_WORD:
6904           fprintf(fout, "  tmp = (edx << 16) | (eax & 0xffff);\n");
6905           snprintf(buf2, sizeof(buf2), "%stmp",
6906             (po->op == OP_IDIV) ? "(s32)" : "");
6907           if (po->operand[0].type == OPT_REG
6908             && po->operand[0].reg == xDX)
6909           {
6910             fprintf(fout, "  LOWORD(eax) = %s / %s%s;\n",
6911               buf2, cast, buf1);
6912             fprintf(fout, "  LOWORD(edx) = %s %% %s%s;",
6913               buf2, cast, buf1);
6914           }
6915           else {
6916             fprintf(fout, "  LOWORD(edx) = %s %% %s%s;\n",
6917               buf2, cast, buf1);
6918             fprintf(fout, "  LOWORD(eax) = %s / %s%s;",
6919               buf2, cast, buf1);
6920           }
6921           strcat(g_comment, " div16");
6922           break;
6923         default:
6924           ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6925         }
6926         last_arith_dst = NULL;
6927         delayed_flag_op = NULL;
6928         break;
6929
6930       case OP_TEST:
6931       case OP_CMP:
6932         propagate_lmod(po, &po->operand[0], &po->operand[1]);
6933         if (pfomask != 0) {
6934           for (j = 0; j < 8; j++) {
6935             if (pfomask & (1 << j)) {
6936               out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6937               fprintf(fout, "  cond_%s = %s;",
6938                 parsed_flag_op_names[j], buf1);
6939             }
6940           }
6941           pfomask = 0;
6942         }
6943         else
6944           no_output = 1;
6945         last_arith_dst = NULL;
6946         delayed_flag_op = po;
6947         break;
6948
6949       case OP_SCC:
6950         // SETcc - should already be handled
6951         break;
6952
6953       // note: we reuse OP_Jcc for SETcc, only flags differ
6954       case OP_JCC:
6955         fprintf(fout, "\n    goto %s;", po->operand[0].name);
6956         break;
6957
6958       case OP_JECXZ:
6959         fprintf(fout, "  if (ecx == 0)\n");
6960         fprintf(fout, "    goto %s;", po->operand[0].name);
6961         strcat(g_comment, " jecxz");
6962         break;
6963
6964       case OP_LOOP:
6965         fprintf(fout, "  if (--ecx != 0)\n");
6966         fprintf(fout, "    goto %s;", po->operand[0].name);
6967         strcat(g_comment, " loop");
6968         break;
6969
6970       case OP_JMP:
6971         assert_operand_cnt(1);
6972         last_arith_dst = NULL;
6973         delayed_flag_op = NULL;
6974
6975         if (po->operand[0].type == OPT_REGMEM) {
6976           ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6977                   buf1, buf2);
6978           if (ret != 2)
6979             ferr(po, "parse failure for jmp '%s'\n",
6980               po->operand[0].name);
6981           fprintf(fout, "  goto *jt_%s[%s];", buf1, buf2);
6982           break;
6983         }
6984         else if (po->operand[0].type != OPT_LABEL)
6985           ferr(po, "unhandled jmp type\n");
6986
6987         fprintf(fout, "  goto %s;", po->operand[0].name);
6988         break;
6989
6990       case OP_CALL:
6991         assert_operand_cnt(1);
6992         pp = po->pp;
6993         my_assert_not(pp, NULL);
6994
6995         strcpy(buf3, "  ");
6996         if (po->flags & OPF_CC) {
6997           // we treat conditional branch to another func
6998           // (yes such code exists..) as conditional tailcall
6999           strcat(buf3, "  ");
7000           fprintf(fout, " {\n");
7001         }
7002
7003         if (pp->is_fptr && !pp->is_arg) {
7004           fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7005             out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7006               "(void *)", 0));
7007           if (pp->is_unresolved)
7008             fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7009               buf3, asmfn, po->asmln, pp->name);
7010         }
7011
7012         fprintf(fout, "%s", buf3);
7013         if (strstr(pp->ret_type.name, "int64")) {
7014           if (po->flags & OPF_TAIL)
7015             ferr(po, "int64 and tail?\n");
7016           fprintf(fout, "tmp64 = ");
7017         }
7018         else if (!IS(pp->ret_type.name, "void")) {
7019           if (po->flags & OPF_TAIL) {
7020             if (regmask_ret & mxAX) {
7021               fprintf(fout, "return ");
7022               if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7023                 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7024             }
7025             else if (regmask_ret & mxST0)
7026               ferr(po, "float tailcall\n");
7027           }
7028           else if (po->regmask_dst & mxAX) {
7029             fprintf(fout, "eax = ");
7030             if (pp->ret_type.is_ptr)
7031               fprintf(fout, "(u32)");
7032           }
7033           else if (po->regmask_dst & mxST0) {
7034             ferr_assert(po, po->flags & OPF_FPUSH);
7035             if (need_float_stack)
7036               fprintf(fout, "f_st[--f_stp & 7] = ");
7037             else
7038               fprintf(fout, "f_st0 = ");
7039           }
7040         }
7041
7042         if (pp->name[0] == 0)
7043           ferr(po, "missing pp->name\n");
7044         fprintf(fout, "%s%s(", pp->name,
7045           pp->has_structarg ? "_sa" : "");
7046
7047         if (po->flags & OPF_ATAIL) {
7048           int check_compat =
7049             g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7050           check_compat |= pp->argc_stack > 0;
7051           if (check_compat
7052            && (pp->argc_stack != g_func_pp->argc_stack
7053                || pp->is_stdcall != g_func_pp->is_stdcall))
7054             ferr(po, "incompatible arg-reuse tailcall\n");
7055           if (g_func_pp->has_retreg)
7056             ferr(po, "TODO: retreg+tailcall\n");
7057
7058           for (arg = j = 0; arg < pp->argc; arg++) {
7059             if (arg > 0)
7060               fprintf(fout, ", ");
7061
7062             cast[0] = 0;
7063             if (pp->arg[arg].type.is_ptr)
7064               snprintf(cast, sizeof(cast), "(%s)",
7065                 pp->arg[arg].type.name);
7066
7067             if (pp->arg[arg].reg != NULL) {
7068               fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7069               continue;
7070             }
7071             // stack arg
7072             for (; j < g_func_pp->argc; j++)
7073               if (g_func_pp->arg[j].reg == NULL)
7074                 break;
7075             fprintf(fout, "%sa%d", cast, j + 1);
7076             j++;
7077           }
7078         }
7079         else {
7080           for (arg = 0; arg < pp->argc; arg++) {
7081             if (arg > 0)
7082               fprintf(fout, ", ");
7083
7084             cast[0] = 0;
7085             if (pp->arg[arg].type.is_ptr)
7086               snprintf(cast, sizeof(cast), "(%s)",
7087                 pp->arg[arg].type.name);
7088
7089             if (pp->arg[arg].reg != NULL) {
7090               if (pp->arg[arg].type.is_retreg)
7091                 fprintf(fout, "&%s", pp->arg[arg].reg);
7092               else if (IS(pp->arg[arg].reg, "ebp")
7093                     && g_bp_frame && !(po->flags & OPF_EBP_S))
7094               {
7095                 // rare special case
7096                 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7097                 strcat(g_comment, " bp_ref");
7098               }
7099               else
7100                 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7101               continue;
7102             }
7103
7104             // stack arg
7105             tmp_op = pp->arg[arg].datap;
7106             if (tmp_op == NULL)
7107               ferr(po, "parsed_op missing for arg%d\n", arg);
7108
7109             if (tmp_op->flags & OPF_VAPUSH) {
7110               fprintf(fout, "ap");
7111             }
7112             else if (tmp_op->op == OP_FST) {
7113               fprintf(fout, "fs_%d", tmp_op->p_argnum);
7114               if (tmp_op->operand[0].lmod == OPLM_QWORD)
7115                 arg++;
7116             }
7117             else if (tmp_op->p_argpass != 0) {
7118               fprintf(fout, "a%d", tmp_op->p_argpass);
7119             }
7120             else if (pp->arg[arg].is_saved) {
7121               ferr_assert(po, tmp_op->p_argnum > 0);
7122               fprintf(fout, "%s%s", cast,
7123                 saved_arg_name(buf1, sizeof(buf1),
7124                   tmp_op->p_arggrp, tmp_op->p_argnum));
7125             }
7126             else {
7127               fprintf(fout, "%s",
7128                 out_src_opr(buf1, sizeof(buf1),
7129                   tmp_op, &tmp_op->operand[0], cast, 0));
7130             }
7131           }
7132         }
7133         fprintf(fout, ");");
7134
7135         if (strstr(pp->ret_type.name, "int64")) {
7136           fprintf(fout, "\n");
7137           fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7138           fprintf(fout, "%seax = tmp64;", buf3);
7139         }
7140
7141         if (pp->is_unresolved) {
7142           snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7143             pp->argc_reg);
7144           strcat(g_comment, buf2);
7145         }
7146
7147         if (po->flags & OPF_TAIL) {
7148           ret = 0;
7149           if (i == opcnt - 1 || pp->is_noreturn)
7150             ret = 0;
7151           else if (IS(pp->ret_type.name, "void"))
7152             ret = 1;
7153           else if (!(regmask_ret & (1 << xAX)))
7154             ret = 1;
7155           // else already handled as 'return f()'
7156
7157           if (ret) {
7158             fprintf(fout, "\n%sreturn;", buf3);
7159             strcat(g_comment, " ^ tailcall");
7160           }
7161           else
7162             strcat(g_comment, " tailcall");
7163
7164           if ((regmask_ret & (1 << xAX))
7165             && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7166           {
7167             ferr(po, "int func -> void func tailcall?\n");
7168           }
7169         }
7170         if (pp->is_noreturn)
7171           strcat(g_comment, " noreturn");
7172         if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7173           strcat(g_comment, " argframe");
7174         if (po->flags & OPF_CC)
7175           strcat(g_comment, " cond");
7176
7177         if (po->flags & OPF_CC)
7178           fprintf(fout, "\n  }");
7179
7180         delayed_flag_op = NULL;
7181         last_arith_dst = NULL;
7182         break;
7183
7184       case OP_RET:
7185         if (g_func_pp->is_vararg)
7186           fprintf(fout, "  va_end(ap);\n");
7187         if (g_func_pp->has_retreg) {
7188           for (arg = 0; arg < g_func_pp->argc; arg++)
7189             if (g_func_pp->arg[arg].type.is_retreg)
7190               fprintf(fout, "  *r_%s = %s;\n",
7191                 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7192         }
7193  
7194         if (regmask_ret & mxST0) {
7195           fprintf(fout, "  return %s;", float_st0);
7196         }
7197         else if (!(regmask_ret & mxAX)) {
7198           if (i != opcnt - 1 || label_pending)
7199             fprintf(fout, "  return;");
7200         }
7201         else if (g_func_pp->ret_type.is_ptr) {
7202           fprintf(fout, "  return (%s)eax;",
7203             g_func_pp->ret_type.name);
7204         }
7205         else if (IS(g_func_pp->ret_type.name, "__int64"))
7206           fprintf(fout, "  return ((u64)edx << 32) | eax;");
7207         else
7208           fprintf(fout, "  return eax;");
7209
7210         last_arith_dst = NULL;
7211         delayed_flag_op = NULL;
7212         break;
7213
7214       case OP_PUSH:
7215         out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7216         if (po->p_argnum != 0) {
7217           // special case - saved func arg
7218           fprintf(fout, "  %s = %s;",
7219             saved_arg_name(buf2, sizeof(buf2),
7220               po->p_arggrp, po->p_argnum), buf1);
7221           break;
7222         }
7223         else if (po->flags & OPF_RSAVE) {
7224           fprintf(fout, "  s_%s = %s;", buf1, buf1);
7225           break;
7226         }
7227         else if (po->flags & OPF_PPUSH) {
7228           tmp_op = po->datap;
7229           ferr_assert(po, tmp_op != NULL);
7230           out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7231           fprintf(fout, "  pp_%s = %s;", buf2, buf1);
7232           break;
7233         }
7234         else if (g_func_pp->is_userstack) {
7235           fprintf(fout, "  *(--esp) = %s;", buf1);
7236           break;
7237         }
7238         if (!(g_ida_func_attr & IDAFA_NORETURN))
7239           ferr(po, "stray push encountered\n");
7240         no_output = 1;
7241         break;
7242
7243       case OP_POP:
7244         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7245         if (po->flags & OPF_RSAVE) {
7246           fprintf(fout, "  %s = s_%s;", buf1, buf1);
7247           break;
7248         }
7249         else if (po->flags & OPF_PPUSH) {
7250           // push/pop graph / non-const
7251           ferr_assert(po, po->datap == NULL);
7252           fprintf(fout, "  %s = pp_%s;", buf1, buf1);
7253           break;
7254         }
7255         else if (po->datap != NULL) {
7256           // push/pop pair
7257           tmp_op = po->datap;
7258           fprintf(fout, "  %s = %s;", buf1,
7259             out_src_opr(buf2, sizeof(buf2),
7260               tmp_op, &tmp_op->operand[0],
7261               default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7262           break;
7263         }
7264         else if (g_func_pp->is_userstack) {
7265           fprintf(fout, "  %s = *esp++;", buf1);
7266           break;
7267         }
7268         else
7269           ferr(po, "stray pop encountered\n");
7270         break;
7271
7272       case OP_NOP:
7273         no_output = 1;
7274         break;
7275
7276       // pseudo ops
7277       case OPP_ALLSHL:
7278       case OPP_ALLSHR:
7279         fprintf(fout, "  tmp64 = ((u64)edx << 32) | eax;\n");
7280         fprintf(fout, "  tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7281           po->op == OPP_ALLSHL ? "<<" : ">>");
7282         fprintf(fout, "  edx = tmp64 >> 32; eax = tmp64;");
7283         strcat(g_comment, po->op == OPP_ALLSHL
7284           ? " allshl" : " allshr");
7285         break;
7286
7287       // x87
7288       case OP_FLD:
7289         if (need_float_stack) {
7290           out_src_opr_float(buf1, sizeof(buf1),
7291             po, &po->operand[0], 1);
7292           if (po->regmask_src & mxSTa) {
7293             fprintf(fout, "  f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7294               buf1);
7295           }
7296           else
7297             fprintf(fout, "  f_st[--f_stp & 7] = %s;", buf1);
7298         }
7299         else {
7300           if (po->flags & OPF_FSHIFT)
7301             fprintf(fout, "  f_st1 = f_st0;");
7302           if (po->operand[0].type == OPT_REG
7303             && po->operand[0].reg == xST0)
7304           {
7305             strcat(g_comment, " fld st");
7306             break;
7307           }
7308           fprintf(fout, "  f_st0 = %s;",
7309             out_src_opr_float(buf1, sizeof(buf1),
7310               po, &po->operand[0], 0));
7311         }
7312         strcat(g_comment, " fld");
7313         break;
7314
7315       case OP_FILD:
7316         out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7317           lmod_cast(po, po->operand[0].lmod, 1), 0);
7318         snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7319         if (need_float_stack) {
7320           fprintf(fout, "  f_st[--f_stp & 7] = %s;", buf2);
7321         }
7322         else {
7323           if (po->flags & OPF_FSHIFT)
7324             fprintf(fout, "  f_st1 = f_st0;");
7325           fprintf(fout, "  f_st0 = %s;", buf2);
7326         }
7327         strcat(g_comment, " fild");
7328         break;
7329
7330       case OP_FLDc:
7331         if (need_float_stack)
7332           fprintf(fout, "  f_st[--f_stp & 7] = ");
7333         else {
7334           if (po->flags & OPF_FSHIFT)
7335             fprintf(fout, "  f_st1 = f_st0;");
7336           fprintf(fout, "  f_st0 = ");
7337         }
7338         switch (po->operand[0].val) {
7339         case X87_CONST_1:   fprintf(fout, "1.0;"); break;
7340         case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
7341         case X87_CONST_Z:   fprintf(fout, "0.0;"); break;
7342         default: ferr(po, "TODO\n"); break;
7343         }
7344         break;
7345
7346       case OP_FST:
7347         if (po->flags & OPF_FARG) {
7348           // store to stack as func arg
7349           snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7350           dead_dst = 0;
7351         }
7352         else {
7353           out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7354             need_float_stack);
7355           dead_dst = po->operand[0].type == OPT_REG
7356             && po->operand[0].reg == xST0;
7357         }
7358         if (!dead_dst)
7359           fprintf(fout, "  %s = %s;", buf1, float_st0);
7360         if (po->flags & OPF_FSHIFT) {
7361           if (need_float_stack)
7362             fprintf(fout, "  f_stp++;");
7363           else
7364             fprintf(fout, "  f_st0 = f_st1;");
7365         }
7366         if (dead_dst && !(po->flags & OPF_FSHIFT))
7367           no_output = 1;
7368         else
7369           strcat(g_comment, " fst");
7370         break;
7371
7372       case OP_FIST:
7373         fprintf(fout, "  %s = %s%s;",
7374           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7375             lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7376         if (po->flags & OPF_FSHIFT) {
7377           if (need_float_stack)
7378             fprintf(fout, "  f_stp++;");
7379           else
7380             fprintf(fout, "  f_st0 = f_st1;");
7381         }
7382         strcat(g_comment, " fist");
7383         break;
7384
7385       case OP_FADD:
7386       case OP_FDIV:
7387       case OP_FMUL:
7388       case OP_FSUB:
7389         out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7390           need_float_stack);
7391         out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7392           need_float_stack);
7393         dead_dst = (po->flags & OPF_FPOP)
7394           && po->operand[0].type == OPT_REG
7395           && po->operand[0].reg == xST0;
7396         switch (po->op) {
7397         case OP_FADD: j = '+'; break;
7398         case OP_FDIV: j = '/'; break;
7399         case OP_FMUL: j = '*'; break;
7400         case OP_FSUB: j = '-'; break;
7401         default: j = 'x'; break;
7402         }
7403         if (need_float_stack) {
7404           if (!dead_dst)
7405             fprintf(fout, "  %s %c= %s;", buf1, j, buf2);
7406           if (po->flags & OPF_FSHIFT)
7407             fprintf(fout, "  f_stp++;");
7408         }
7409         else {
7410           if (po->flags & OPF_FSHIFT) {
7411             // note: assumes only 2 regs handled
7412             if (!dead_dst)
7413               fprintf(fout, "  f_st0 = f_st1 %c f_st0;", j);
7414             else
7415               fprintf(fout, "  f_st0 = f_st1;");
7416           }
7417           else if (!dead_dst)
7418             fprintf(fout, "  %s %c= %s;", buf1, j, buf2);
7419         }
7420         no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7421         break;
7422
7423       case OP_FDIVR:
7424       case OP_FSUBR:
7425         out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7426           need_float_stack);
7427         out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7428           need_float_stack);
7429         out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7430           need_float_stack);
7431         dead_dst = (po->flags & OPF_FPOP)
7432           && po->operand[0].type == OPT_REG
7433           && po->operand[0].reg == xST0;
7434         j = po->op == OP_FDIVR ? '/' : '-';
7435         if (need_float_stack) {
7436           if (!dead_dst)
7437             fprintf(fout, "  %s = %s %c %s;", buf1, buf2, j, buf3);
7438           if (po->flags & OPF_FSHIFT)
7439             fprintf(fout, "  f_stp++;");
7440         }
7441         else {
7442           if (po->flags & OPF_FSHIFT) {
7443             if (!dead_dst)
7444               fprintf(fout, "  f_st0 = f_st0 %c f_st1;", j);
7445             else
7446               fprintf(fout, "  f_st0 = f_st1;");
7447           }
7448           else if (!dead_dst)
7449             fprintf(fout, "  %s = %s %c %s;", buf1, buf2, j, buf3);
7450         }
7451         no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7452         break;
7453
7454       case OP_FIADD:
7455       case OP_FIDIV:
7456       case OP_FIMUL:
7457       case OP_FISUB:
7458         switch (po->op) {
7459         case OP_FIADD: j = '+'; break;
7460         case OP_FIDIV: j = '/'; break;
7461         case OP_FIMUL: j = '*'; break;
7462         case OP_FISUB: j = '-'; break;
7463         default: j = 'x'; break;
7464         }
7465         fprintf(fout, "  %s %c= (%s)%s;", float_st0,
7466           j, float_type,
7467           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7468             lmod_cast(po, po->operand[0].lmod, 1), 0));
7469         break;
7470
7471       case OP_FIDIVR:
7472       case OP_FISUBR:
7473         fprintf(fout, "  %s = %s %c %s;", float_st0,
7474           out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7475             need_float_stack),
7476           po->op == OP_FIDIVR ? '/' : '-', float_st0);
7477         break;
7478
7479       case OP_FCOM: {
7480         int mask, z_check;
7481         ferr_assert(po, po->datap != NULL);
7482         mask = (long)po->datap & 0xffff;
7483         z_check = ((long)po->datap >> 16) & 1;
7484         out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7485           need_float_stack);
7486         if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
7487           fprintf(fout, "  f_sw = %s < %s ? 0x0100 : 0;",
7488             float_st0, buf1);
7489         }
7490         else if (mask == 0x4000) { // C3 -> =
7491           fprintf(fout, "  f_sw = %s == %s ? 0x4000 : 0;",
7492             float_st0, buf1);
7493         }
7494         else if (mask == 0x4100) { // C3, C0
7495           if (z_check) {
7496             fprintf(fout, "  f_sw = %s <= %s ? 0x4100 : 0;",
7497               float_st0, buf1);
7498             strcat(g_comment, " z_chk_det");
7499           }
7500           else {
7501             fprintf(fout, "  f_sw = %s == %s ? 0x4000 : "
7502                           "(%s < %s ? 0x0100 : 0);",
7503               float_st0, buf1, float_st0, buf1);
7504           }
7505         }
7506         else
7507           ferr(po, "unhandled sw mask: %x\n", mask);
7508         if (po->flags & OPF_FSHIFT) {
7509           if (need_float_stack)
7510             fprintf(fout, " f_stp++;");
7511           else
7512             fprintf(fout, " f_st0 = f_st1;");
7513         }
7514         break;
7515       }
7516
7517       case OP_FNSTSW:
7518         fprintf(fout, "  %s = f_sw;",
7519           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7520         break;
7521
7522       case OP_FCHS:
7523         fprintf(fout, "  %s = -%s;", float_st0, float_st0);
7524         break;
7525
7526       case OP_FCOS:
7527         fprintf(fout, "  %s = cos%s(%s);", float_st0,
7528           need_double ? "" : "f", float_st0);
7529         break;
7530
7531       case OP_FPATAN:
7532         if (need_float_stack) {
7533           fprintf(fout, "  %s = atan%s(%s / %s);", float_st1,
7534             need_double ? "" : "f", float_st1, float_st0);
7535           fprintf(fout, " f_stp++;");
7536         }
7537         else {
7538           fprintf(fout, "  f_st0 = atan%s(f_st1 / f_st0);",
7539             need_double ? "" : "f");
7540         }
7541         break;
7542
7543       case OP_FYL2X:
7544         if (need_float_stack) {
7545           fprintf(fout, "  %s = %s * log2%s(%s);", float_st1,
7546             float_st1, need_double ? "" : "f", float_st0);
7547           fprintf(fout, " f_stp++;");
7548         }
7549         else {
7550           fprintf(fout, "  f_st0 = f_st1 * log2%s(f_st0);",
7551             need_double ? "" : "f");
7552         }
7553         strcat(g_comment, " fyl2x");
7554         break;
7555
7556       case OP_FSIN:
7557         fprintf(fout, "  %s = sin%s(%s);", float_st0,
7558           need_double ? "" : "f", float_st0);
7559         break;
7560
7561       case OP_FSQRT:
7562         fprintf(fout, "  %s = sqrt%s(%s);", float_st0,
7563           need_double ? "" : "f", float_st0);
7564         break;
7565
7566       case OP_FXCH:
7567         dead_dst = po->operand[0].type == OPT_REG
7568           && po->operand[0].reg == xST0;
7569         if (!dead_dst) {
7570           out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7571             need_float_stack);
7572           fprintf(fout, "  { %s t = %s; %s = %s; %s = t; }", float_type,
7573             float_st0, float_st0, buf1, buf1);
7574           strcat(g_comment, " fxch");
7575         }
7576         else
7577           no_output = 1;
7578         break;
7579
7580       case OPP_FTOL:
7581         ferr_assert(po, po->flags & OPF_32BIT);
7582         fprintf(fout, "  eax = (s32)%s;", float_st0);
7583         if (po->flags & OPF_FSHIFT) {
7584           if (need_float_stack)
7585             fprintf(fout, " f_stp++;");
7586           else
7587             fprintf(fout, " f_st0 = f_st1;");
7588         }
7589         strcat(g_comment, " ftol");
7590         break;
7591
7592       case OPP_CIPOW:
7593         if (need_float_stack) {
7594           fprintf(fout, "  %s = pow%s(%s, %s);", float_st1,
7595             need_double ? "" : "f", float_st1, float_st0);
7596           fprintf(fout, " f_stp++;");
7597         }
7598         else {
7599           fprintf(fout, "  f_st0 = pow%s(f_st1, f_st0);",
7600             need_double ? "" : "f");
7601         }
7602         strcat(g_comment, " CIpow");
7603         break;
7604
7605       case OPP_ABORT:
7606         fprintf(fout, "  do_skip_code_abort();");
7607         break;
7608
7609       // mmx
7610       case OP_EMMS:
7611         fprintf(fout, "  do_emms();");
7612         break;
7613
7614       default:
7615         no_output = 1;
7616         ferr(po, "unhandled op type %d, flags %x\n",
7617           po->op, po->flags);
7618         break;
7619     }
7620
7621     if (g_comment[0] != 0) {
7622       char *p = g_comment;
7623       while (my_isblank(*p))
7624         p++;
7625       fprintf(fout, "  // %s", p);
7626       g_comment[0] = 0;
7627       no_output = 0;
7628     }
7629     if (!no_output)
7630       fprintf(fout, "\n");
7631
7632     // some sanity checking
7633     if (po->flags & OPF_REP) {
7634       if (po->op != OP_STOS && po->op != OP_MOVS
7635           && po->op != OP_CMPS && po->op != OP_SCAS)
7636         ferr(po, "unexpected rep\n");
7637       if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7638           && (po->op == OP_CMPS || po->op == OP_SCAS))
7639         ferr(po, "cmps/scas with plain rep\n");
7640     }
7641     if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7642         && po->op != OP_CMPS && po->op != OP_SCAS)
7643       ferr(po, "unexpected repz/repnz\n");
7644
7645     if (pfomask != 0)
7646       ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
7647
7648     // see is delayed flag stuff is still valid
7649     if (delayed_flag_op != NULL && delayed_flag_op != po) {
7650       if (is_any_opr_modified(delayed_flag_op, po, 0))
7651         delayed_flag_op = NULL;
7652     }
7653
7654     if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7655       if (is_opr_modified(last_arith_dst, po))
7656         last_arith_dst = NULL;
7657     }
7658
7659     if (!no_output)
7660       label_pending = 0;
7661   }
7662
7663   if (g_stack_fsz && !g_stack_frame_used)
7664     fprintf(fout, "  (void)sf;\n");
7665
7666   fprintf(fout, "}\n\n");
7667
7668   gen_x_cleanup(opcnt);
7669 }
7670
7671 static void gen_x_cleanup(int opcnt)
7672 {
7673   int i;
7674
7675   for (i = 0; i < opcnt; i++) {
7676     struct label_ref *lr, *lr_del;
7677
7678     lr = g_label_refs[i].next;
7679     while (lr != NULL) {
7680       lr_del = lr;
7681       lr = lr->next;
7682       free(lr_del);
7683     }
7684     g_label_refs[i].i = -1;
7685     g_label_refs[i].next = NULL;
7686
7687     if (ops[i].op == OP_CALL) {
7688       if (ops[i].pp)
7689         proto_release(ops[i].pp);
7690     }
7691   }
7692   g_func_pp = NULL;
7693 }
7694
7695 struct func_proto_dep;
7696
7697 struct func_prototype {
7698   char name[NAMELEN];
7699   int id;
7700   int argc_stack;
7701   int regmask_dep;
7702   int has_ret:3;                 // -1, 0, 1: unresolved, no, yes
7703   unsigned int dep_resolved:1;
7704   unsigned int is_stdcall:1;
7705   struct func_proto_dep *dep_func;
7706   int dep_func_cnt;
7707   const struct parsed_proto *pp; // seed pp, if any
7708 };
7709
7710 struct func_proto_dep {
7711   char *name;
7712   struct func_prototype *proto;
7713   int regmask_live;             // .. at the time of call
7714   unsigned int ret_dep:1;       // return from this is caller's return
7715 };
7716
7717 static struct func_prototype *hg_fp;
7718 static int hg_fp_cnt;
7719
7720 static struct scanned_var {
7721   char name[NAMELEN];
7722   enum opr_lenmod lmod;
7723   unsigned int is_seeded:1;
7724   unsigned int is_c_str:1;
7725   const struct parsed_proto *pp; // seed pp, if any
7726 } *hg_vars;
7727 static int hg_var_cnt;
7728
7729 static char **hg_refs;
7730 static int hg_ref_cnt;
7731
7732 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7733   int count);
7734
7735 static struct func_prototype *hg_fp_add(const char *funcn)
7736 {
7737   struct func_prototype *fp;
7738
7739   if ((hg_fp_cnt & 0xff) == 0) {
7740     hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7741     my_assert_not(hg_fp, NULL);
7742     memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7743   }
7744
7745   fp = &hg_fp[hg_fp_cnt];
7746   snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7747   fp->id = hg_fp_cnt;
7748   fp->argc_stack = -1;
7749   hg_fp_cnt++;
7750
7751   return fp;
7752 }
7753
7754 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7755   const char *name)
7756 {
7757   int i;
7758
7759   for (i = 0; i < fp->dep_func_cnt; i++)
7760     if (IS(fp->dep_func[i].name, name))
7761       return &fp->dep_func[i];
7762
7763   return NULL;
7764 }
7765
7766 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7767 {
7768   // is it a dupe?
7769   if (hg_fp_find_dep(fp, name))
7770     return;
7771
7772   if ((fp->dep_func_cnt & 0xff) == 0) {
7773     fp->dep_func = realloc(fp->dep_func,
7774       sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7775     my_assert_not(fp->dep_func, NULL);
7776     memset(&fp->dep_func[fp->dep_func_cnt], 0,
7777       sizeof(fp->dep_func[0]) * 0x100);
7778   }
7779   fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7780   fp->dep_func_cnt++;
7781 }
7782
7783 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7784 {
7785   const struct func_prototype *p1 = p1_, *p2 = p2_;
7786   return strcmp(p1->name, p2->name);
7787 }
7788
7789 #if 0
7790 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7791 {
7792   const struct func_prototype *p1 = p1_, *p2 = p2_;
7793   return p1->id - p2->id;
7794 }
7795 #endif
7796
7797 static void hg_ref_add(const char *name)
7798 {
7799   if ((hg_ref_cnt & 0xff) == 0) {
7800     hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7801     my_assert_not(hg_refs, NULL);
7802     memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7803   }
7804
7805   hg_refs[hg_ref_cnt] = strdup(name);
7806   my_assert_not(hg_refs[hg_ref_cnt], NULL);
7807   hg_ref_cnt++;
7808 }
7809
7810 // recursive register dep pass
7811 // - track saved regs (part 2)
7812 // - try to figure out arg-regs
7813 // - calculate reg deps
7814 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
7815   struct func_prototype *fp, int regmask_save, int regmask_dst,
7816   int *regmask_dep, int *has_ret)
7817 {
7818   struct func_proto_dep *dep;
7819   struct parsed_op *po;
7820   int from_caller = 0;
7821   int j, l;
7822   int reg;
7823   int ret;
7824
7825   for (; i < opcnt; i++)
7826   {
7827     if (cbits[i >> 3] & (1 << (i & 7)))
7828       return;
7829     cbits[i >> 3] |= (1 << (i & 7));
7830
7831     po = &ops[i];
7832
7833     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
7834       if (po->flags & OPF_RMD)
7835         continue;
7836
7837       if (po->btj != NULL) {
7838         // jumptable
7839         for (j = 0; j < po->btj->count; j++) {
7840           check_i(po, po->btj->d[j].bt_i);
7841           gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
7842             regmask_save, regmask_dst, regmask_dep, has_ret);
7843         }
7844         return;
7845       }
7846
7847       check_i(po, po->bt_i);
7848       if (po->flags & OPF_CJMP) {
7849         gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
7850           regmask_save, regmask_dst, regmask_dep, has_ret);
7851       }
7852       else {
7853         i = po->bt_i - 1;
7854       }
7855       continue;
7856     }
7857
7858     if (po->flags & OPF_FARG)
7859       /* (just calculate register deps) */;
7860     else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
7861     {
7862       reg = po->operand[0].reg;
7863       ferr_assert(po, reg >= 0);
7864
7865       if (po->flags & OPF_RSAVE) {
7866         regmask_save |= 1 << reg;
7867         continue;
7868       }
7869       if (po->flags & OPF_DONE)
7870         continue;
7871
7872       ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
7873       if (ret == 1) {
7874         regmask_save |= 1 << reg;
7875         po->flags |= OPF_RMD;
7876         scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
7877         continue;
7878       }
7879     }
7880     else if (po->flags & OPF_RMD)
7881       continue;
7882     else if (po->op == OP_CALL) {
7883       po->regmask_dst |= 1 << xAX;
7884
7885       dep = hg_fp_find_dep(fp, po->operand[0].name);
7886       if (dep != NULL) {
7887         dep->regmask_live = regmask_save | regmask_dst;
7888         if (g_bp_frame && !(po->flags & OPF_EBP_S))
7889           dep->regmask_live |= 1 << xBP;
7890       }
7891     }
7892     else if (po->op == OP_RET) {
7893       if (po->operand_cnt > 0) {
7894         fp->is_stdcall = 1;
7895         if (fp->argc_stack >= 0
7896             && fp->argc_stack != po->operand[0].val / 4)
7897           ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
7898         fp->argc_stack = po->operand[0].val / 4;
7899       }
7900     }
7901
7902     // if has_ret is 0, there is uninitialized eax path,
7903     // which means it's most likely void func
7904     if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
7905       if (po->op == OP_CALL) {
7906         j = i;
7907         ret = 1;
7908       }
7909       else {
7910         struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
7911         j = -1;
7912         from_caller = 0;
7913         ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
7914       }
7915
7916       if (ret != 1 && from_caller) {
7917         // unresolved eax - probably void func
7918         *has_ret = 0;
7919       }
7920       else {
7921         if (j >= 0 && ops[j].op == OP_CALL) {
7922           dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
7923           if (dep != NULL)
7924             dep->ret_dep = 1;
7925           else
7926             *has_ret = 1;
7927         }
7928         else
7929           *has_ret = 1;
7930       }
7931     }
7932
7933     l = regmask_save | regmask_dst;
7934     if (g_bp_frame && !(po->flags & OPF_EBP_S))
7935       l |= 1 << xBP;
7936
7937     l = po->regmask_src & ~l;
7938 #if 0
7939     if (l)
7940       fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
7941         l, regmask_dst, regmask_save, po->flags);
7942 #endif
7943     *regmask_dep |= l;
7944     regmask_dst |= po->regmask_dst;
7945
7946     if (po->flags & OPF_TAIL)
7947       return;
7948   }
7949 }
7950
7951 static void gen_hdr(const char *funcn, int opcnt)
7952 {
7953   unsigned char cbits[MAX_OPS / 8];
7954   const struct parsed_proto *pp_c;
7955   struct parsed_proto *pp;
7956   struct func_prototype *fp;
7957   struct parsed_op *po;
7958   int regmask_dummy = 0;
7959   int regmask_dep;
7960   int max_bp_offset = 0;
7961   int has_ret;
7962   int i, j, l;
7963   int ret;
7964
7965   pp_c = proto_parse(g_fhdr, funcn, 1);
7966   if (pp_c != NULL)
7967     // already in seed, will add to hg_fp later
7968     return;
7969
7970   fp = hg_fp_add(funcn);
7971
7972   g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7973   g_stack_frame_used = 0;
7974
7975   // pass1:
7976   // - resolve all branches
7977   // - parse calls with labels
7978   resolve_branches_parse_calls(opcnt);
7979
7980   // pass2:
7981   // - handle ebp/esp frame, remove ops related to it
7982   scan_prologue_epilogue(opcnt, NULL);
7983
7984   // pass3:
7985   // - remove dead labels
7986   // - collect calls
7987   for (i = 0; i < opcnt; i++)
7988   {
7989     if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7990       free(g_labels[i]);
7991       g_labels[i] = NULL;
7992     }
7993
7994     po = &ops[i];
7995     if (po->flags & (OPF_RMD|OPF_DONE))
7996       continue;
7997
7998     if (po->op == OP_CALL) {
7999       if (po->operand[0].type == OPT_LABEL)
8000         hg_fp_add_dep(fp, opr_name(po, 0));
8001       else if (po->pp != NULL)
8002         hg_fp_add_dep(fp, po->pp->name);
8003     }
8004   }
8005
8006   // pass4:
8007   // - remove dead labels
8008   // - handle push <const>/pop pairs
8009   for (i = 0; i < opcnt; i++)
8010   {
8011     if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8012       free(g_labels[i]);
8013       g_labels[i] = NULL;
8014     }
8015
8016     po = &ops[i];
8017     if (po->flags & (OPF_RMD|OPF_DONE))
8018       continue;
8019
8020     if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8021       scan_for_pop_const(i, opcnt, i + opcnt * 13);
8022   }
8023
8024   // pass5:
8025   // - process trivial calls
8026   for (i = 0; i < opcnt; i++)
8027   {
8028     po = &ops[i];
8029     if (po->flags & (OPF_RMD|OPF_DONE))
8030       continue;
8031
8032     if (po->op == OP_CALL)
8033     {
8034       pp = process_call_early(i, opcnt, &j);
8035       if (pp != NULL) {
8036         if (!(po->flags & OPF_ATAIL))
8037           // since we know the args, try to collect them
8038           if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8039             pp = NULL;
8040       }
8041
8042       if (pp != NULL) {
8043         if (j >= 0) {
8044           // commit esp adjust
8045           if (ops[j].op != OP_POP)
8046             patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8047           else {
8048             for (l = 0; l < pp->argc_stack; l++)
8049               ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8050           }
8051         }
8052
8053         po->flags |= OPF_DONE;
8054       }
8055     }
8056   }
8057
8058   // pass6:
8059   // - track saved regs (simple)
8060   // - process calls
8061   for (i = 0; i < opcnt; i++)
8062   {
8063     po = &ops[i];
8064     if (po->flags & (OPF_RMD|OPF_DONE))
8065       continue;
8066
8067     if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8068       && po->operand[0].reg != xCX)
8069     {
8070       ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8071       if (ret == 1) {
8072         // regmask_save |= 1 << po->operand[0].reg; // do it later
8073         po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8074         scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8075       }
8076     }
8077     else if (po->op == OP_CALL)
8078     {
8079       pp = process_call(i, opcnt);
8080
8081       if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8082         // since we know the args, collect them
8083         ret = collect_call_args(po, i, pp, &regmask_dummy,
8084                 i + opcnt * 1);
8085       }
8086     }
8087   }
8088
8089   // pass7
8090   memset(cbits, 0, sizeof(cbits));
8091   regmask_dep = 0;
8092   has_ret = -1;
8093
8094   gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, &regmask_dep, &has_ret);
8095
8096   // find unreachable code - must be fixed in IDA
8097   for (i = 0; i < opcnt; i++)
8098   {
8099     if (cbits[i >> 3] & (1 << (i & 7)))
8100       continue;
8101
8102     if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8103       && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8104     {
8105       // the compiler sometimes still generates code after
8106       // noreturn OS functions
8107       break;
8108     }
8109     if (ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8110       ferr(&ops[i], "unreachable code\n");
8111   }
8112
8113   for (i = 0; i < g_eqcnt; i++) {
8114     if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8115       max_bp_offset = g_eqs[i].offset;
8116   }
8117
8118   if (fp->argc_stack < 0) {
8119     max_bp_offset = (max_bp_offset + 3) & ~3;
8120     fp->argc_stack = max_bp_offset / 4;
8121     if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8122       fp->argc_stack--;
8123   }
8124
8125   fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8126   fp->has_ret = has_ret;
8127 #if 0
8128   printf("// has_ret %d, regmask_dep %x\n",
8129     fp->has_ret, fp->regmask_dep);
8130   output_hdr_fp(stdout, fp, 1);
8131   if (IS(funcn, "sub_10007F72")) exit(1);
8132 #endif
8133
8134   gen_x_cleanup(opcnt);
8135 }
8136
8137 static void hg_fp_resolve_deps(struct func_prototype *fp)
8138 {
8139   struct func_prototype fp_s;
8140   int dep;
8141   int i;
8142
8143   // this thing is recursive, so mark first..
8144   fp->dep_resolved = 1;
8145
8146   for (i = 0; i < fp->dep_func_cnt; i++) {
8147     strcpy(fp_s.name, fp->dep_func[i].name);
8148     fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8149       sizeof(hg_fp[0]), hg_fp_cmp_name);
8150     if (fp->dep_func[i].proto != NULL) {
8151       if (!fp->dep_func[i].proto->dep_resolved)
8152         hg_fp_resolve_deps(fp->dep_func[i].proto);
8153
8154       dep = ~fp->dep_func[i].regmask_live
8155            & fp->dep_func[i].proto->regmask_dep;
8156       fp->regmask_dep |= dep;
8157       // printf("dep %s %s |= %x\n", fp->name,
8158       //   fp->dep_func[i].name, dep);
8159
8160       if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8161         fp->has_ret = fp->dep_func[i].proto->has_ret;
8162     }
8163   }
8164 }
8165
8166 // make all thiscall/edx arg functions referenced from .data fastcall
8167 static void do_func_refs_from_data(void)
8168 {
8169   struct func_prototype *fp, fp_s;
8170   int i;
8171
8172   for (i = 0; i < hg_ref_cnt; i++) {
8173     strcpy(fp_s.name, hg_refs[i]);
8174     fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8175       sizeof(hg_fp[0]), hg_fp_cmp_name);
8176     if (fp == NULL)
8177       continue;
8178
8179     if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8180       fp->regmask_dep |= mxCX | mxDX;
8181   }
8182 }
8183
8184 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8185   int count)
8186 {
8187   const struct parsed_proto *pp;
8188   char *p, namebuf[NAMELEN];
8189   const char *name;
8190   int regmask_dep;
8191   int argc_normal;
8192   int j, arg;
8193
8194   for (; count > 0; count--, fp++) {
8195     if (fp->has_ret == -1)
8196       fprintf(fout, "// ret unresolved\n");
8197 #if 0
8198     fprintf(fout, "// dep:");
8199     for (j = 0; j < fp->dep_func_cnt; j++) {
8200       fprintf(fout, " %s/", fp->dep_func[j].name);
8201       if (fp->dep_func[j].proto != NULL)
8202         fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8203           fp->dep_func[j].proto->has_ret);
8204     }
8205     fprintf(fout, "\n");
8206 #endif
8207
8208     p = strchr(fp->name, '@');
8209     if (p != NULL) {
8210       memcpy(namebuf, fp->name, p - fp->name);
8211       namebuf[p - fp->name] = 0;
8212       name = namebuf;
8213     }
8214     else
8215       name = fp->name;
8216     if (name[0] == '_')
8217       name++;
8218
8219     pp = proto_parse(g_fhdr, name, 1);
8220     if (pp != NULL && pp->is_include)
8221       continue;
8222
8223     if (fp->pp != NULL) {
8224       // part of seed, output later
8225       continue;
8226     }
8227
8228     regmask_dep = fp->regmask_dep;
8229     argc_normal = fp->argc_stack;
8230
8231     fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8232       (fp->has_ret ? "int" : "void"));
8233     if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8234       && (regmask_dep & ~mxCX) == 0)
8235     {
8236       fprintf(fout, "/*__thiscall*/  ");
8237       argc_normal++;
8238       regmask_dep = 0;
8239     }
8240     else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8241       && (regmask_dep & ~(mxCX | mxDX)) == 0)
8242     {
8243       fprintf(fout, "  __fastcall    ");
8244       if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8245         argc_normal = 1;
8246       else
8247         argc_normal += 2;
8248       regmask_dep = 0;
8249     }
8250     else if (regmask_dep && !fp->is_stdcall) {
8251       fprintf(fout, "/*__usercall*/  ");
8252     }
8253     else if (regmask_dep) {
8254       fprintf(fout, "/*__userpurge*/ ");
8255     }
8256     else if (fp->is_stdcall)
8257       fprintf(fout, "  __stdcall     ");
8258     else
8259       fprintf(fout, "  __cdecl       ");
8260
8261     fprintf(fout, "%s(", name);
8262
8263     arg = 0;
8264     for (j = 0; j < xSP; j++) {
8265       if (regmask_dep & (1 << j)) {
8266         arg++;
8267         if (arg != 1)
8268           fprintf(fout, ", ");
8269         if (fp->pp != NULL)
8270           fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8271         else
8272           fprintf(fout, "int");
8273         fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8274       }
8275     }
8276
8277     for (j = 0; j < argc_normal; j++) {
8278       arg++;
8279       if (arg != 1)
8280         fprintf(fout, ", ");
8281       if (fp->pp != NULL) {
8282         fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8283         if (!fp->pp->arg[arg - 1].type.is_ptr)
8284           fprintf(fout, " ");
8285       }
8286       else
8287         fprintf(fout, "int ");
8288       fprintf(fout, "a%d", arg);
8289     }
8290
8291     fprintf(fout, ");\n");
8292   }
8293 }
8294
8295 static void output_hdr(FILE *fout)
8296 {
8297   static const char *lmod_c_names[] = {
8298     [OPLM_UNSPEC] = "???",
8299     [OPLM_BYTE]  = "uint8_t",
8300     [OPLM_WORD]  = "uint16_t",
8301     [OPLM_DWORD] = "uint32_t",
8302     [OPLM_QWORD] = "uint64_t",
8303   };
8304   const struct scanned_var *var;
8305   struct func_prototype *fp;
8306   char line[256] = { 0, };
8307   char name[256];
8308   int i;
8309
8310   // add stuff from headers
8311   for (i = 0; i < pp_cache_size; i++) {
8312     if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8313       snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8314     else
8315       snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8316     fp = hg_fp_add(name);
8317     fp->pp = &pp_cache[i];
8318     fp->argc_stack = fp->pp->argc_stack;
8319     fp->is_stdcall = fp->pp->is_stdcall;
8320     fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8321     fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8322   }
8323
8324   // resolve deps
8325   qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8326   for (i = 0; i < hg_fp_cnt; i++)
8327     hg_fp_resolve_deps(&hg_fp[i]);
8328
8329   // adjust functions referenced from data segment
8330   do_func_refs_from_data();
8331
8332   // note: messes up .proto ptr, don't use
8333   //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8334
8335   // output variables
8336   for (i = 0; i < hg_var_cnt; i++) {
8337     var = &hg_vars[i];
8338
8339     if (var->pp != NULL)
8340       // part of seed
8341       continue;
8342     else if (var->is_c_str)
8343       fprintf(fout, "extern %-8s %s[];", "char", var->name);
8344     else
8345       fprintf(fout, "extern %-8s %s;",
8346         lmod_c_names[var->lmod], var->name);
8347
8348     if (var->is_seeded)
8349       fprintf(fout, " // seeded");
8350     fprintf(fout, "\n");
8351   }
8352
8353   fprintf(fout, "\n");
8354
8355   // output function prototypes
8356   output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8357
8358   // seed passthrough
8359   fprintf(fout, "\n// - seed -\n");
8360
8361   rewind(g_fhdr);
8362   while (fgets(line, sizeof(line), g_fhdr))
8363     fwrite(line, 1, strlen(line), fout);
8364 }
8365
8366 // '=' needs special treatment
8367 // also ' quote
8368 static char *next_word_s(char *w, size_t wsize, char *s)
8369 {
8370   size_t i;
8371
8372   s = sskip(s);
8373
8374   i = 0;
8375   if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8376     w[0] = s[0];
8377     for (i = 1; i < wsize - 1; i++) {
8378       if (s[i] == 0) {
8379         printf("warning: missing closing quote: \"%s\"\n", s);
8380         break;
8381       }
8382       if (s[i] == '\'')
8383         break;
8384       w[i] = s[i];
8385     }
8386   }
8387
8388   for (; i < wsize - 1; i++) {
8389     if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8390       break;
8391     w[i] = s[i];
8392   }
8393   w[i] = 0;
8394
8395   if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8396     printf("warning: '%s' truncated\n", w);
8397
8398   return s + i;
8399 }
8400
8401 static int cmpstringp(const void *p1, const void *p2)
8402 {
8403   return strcmp(*(char * const *)p1, *(char * const *)p2);
8404 }
8405
8406 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8407 {
8408   char *p2;
8409
8410   p = sskip(p);
8411   if (strstr(p, "..."))
8412     // unable to determine, assume needed
8413     return 1;
8414
8415   if (*p == '.') // .text, .data, ...
8416     // ref from other data or non-function -> no
8417     return 0;
8418
8419   p2 = strpbrk(p, "+:\r\n\x18");
8420   if (p2 != NULL)
8421     *p2 = 0;
8422   if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8423     // referenced from removed code
8424     return 0;
8425
8426   return 1;
8427 }
8428
8429 static int ida_xrefs_show_need(FILE *fasm, char *p,
8430   char **rlist, int rlist_len)
8431 {
8432   int found_need = 0;
8433   char line[256];
8434   long pos;
8435
8436   p = strrchr(p, ';');
8437   if (p != NULL && *p == ';') {
8438     if (IS_START(p + 2, "sctref"))
8439       return 1;
8440     if (IS_START(p + 2, "DATA XREF: ")) {
8441       p += 13;
8442       if (is_xref_needed(p, rlist, rlist_len))
8443         return 1;
8444     }
8445   }
8446
8447   pos = ftell(fasm);
8448   while (1)
8449   {
8450     if (!my_fgets(line, sizeof(line), fasm))
8451       break;
8452     // non-first line is always indented
8453     if (!my_isblank(line[0]))
8454       break;
8455
8456     // should be no content, just comment
8457     p = sskip(line);
8458     if (*p != ';')
8459       break;
8460
8461     p = strrchr(p, ';');
8462     p += 2;
8463
8464     if (IS_START(p, "sctref")) {
8465       found_need = 1;
8466       break;
8467     }
8468
8469     // it's printed once, but no harm to check again
8470     if (IS_START(p, "DATA XREF: "))
8471       p += 11;
8472
8473     if (is_xref_needed(p, rlist, rlist_len)) {
8474       found_need = 1;
8475       break;
8476     }
8477   }
8478   fseek(fasm, pos, SEEK_SET);
8479   return found_need;
8480 }
8481
8482 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8483 {
8484   struct scanned_var *var;
8485   char line[256] = { 0, };
8486   char words[4][256];
8487   int no_identifier;
8488   char *p = NULL;
8489   int wordc;
8490   int l;
8491
8492   while (!feof(fasm))
8493   {
8494     // skip to next data section
8495     while (my_fgets(line, sizeof(line), fasm))
8496     {
8497       asmln++;
8498
8499       p = sskip(line);
8500       if (*p == 0 || *p == ';')
8501         continue;
8502
8503       p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8504       if (*p == 0 || *p == ';')
8505         continue;
8506
8507       if (*p != 's' || !IS_START(p, "segment para public"))
8508         continue;
8509
8510       break;
8511     }
8512
8513     if (p == NULL || !IS_START(p, "segment para public"))
8514       break;
8515     p = sskip(p + 19);
8516
8517     if (!IS_START(p, "'DATA'"))
8518       continue;
8519
8520     // now process it
8521     while (my_fgets(line, sizeof(line), fasm))
8522     {
8523       asmln++;
8524
8525       p = line;
8526       no_identifier = my_isblank(*p);
8527
8528       p = sskip(p);
8529       if (*p == 0 || *p == ';')
8530         continue;
8531
8532       for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8533         words[wordc][0] = 0;
8534         p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8535         if (*p == 0 || *p == ';') {
8536           wordc++;
8537           break;
8538         }
8539       }
8540
8541       if (wordc == 2 && IS(words[1], "ends"))
8542         break;
8543       if (wordc < 2)
8544         continue;
8545
8546       if (no_identifier) {
8547         if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8548           hg_ref_add(words[2]);
8549         continue;
8550       }
8551
8552       if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8553         // when this starts, we don't need anything from this section
8554         break;
8555       }
8556
8557       // check refs comment(s)
8558       if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8559         continue;
8560
8561       if ((hg_var_cnt & 0xff) == 0) {
8562         hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8563                    * (hg_var_cnt + 0x100));
8564         my_assert_not(hg_vars, NULL);
8565         memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8566       }
8567
8568       var = &hg_vars[hg_var_cnt++];
8569       snprintf(var->name, sizeof(var->name), "%s", words[0]);
8570
8571       // maybe already in seed header?
8572       var->pp = proto_parse(g_fhdr, var->name, 1);
8573       if (var->pp != NULL) {
8574         if (var->pp->is_fptr) {
8575           var->lmod = OPLM_DWORD;
8576           //var->is_ptr = 1;
8577         }
8578         else if (var->pp->is_func)
8579           aerr("func?\n");
8580         else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8581           aerr("unhandled C type '%s' for '%s'\n",
8582             var->pp->type.name, var->name);
8583
8584         var->is_seeded = 1;
8585         continue;
8586       }
8587
8588       if      (IS(words[1], "dd")) {
8589         var->lmod = OPLM_DWORD;
8590         if (wordc >= 4 && IS(words[2], "offset"))
8591           hg_ref_add(words[3]);
8592       }
8593       else if (IS(words[1], "dw"))
8594         var->lmod = OPLM_WORD;
8595       else if (IS(words[1], "db")) {
8596         var->lmod = OPLM_BYTE;
8597         if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8598           if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8599             var->is_c_str = 1;
8600         }
8601       }
8602       else if (IS(words[1], "dq"))
8603         var->lmod = OPLM_QWORD;
8604       //else if (IS(words[1], "dt"))
8605       else
8606         aerr("type '%s' not known\n", words[1]);
8607     }
8608   }
8609
8610   rewind(fasm);
8611   asmln = 0;
8612 }
8613
8614 static void set_label(int i, const char *name)
8615 {
8616   const char *p;
8617   int len;
8618
8619   len = strlen(name);
8620   p = strchr(name, ':');
8621   if (p != NULL)
8622     len = p - name;
8623
8624   if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8625     aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8626   g_labels[i] = realloc(g_labels[i], len + 1);
8627   my_assert_not(g_labels[i], NULL);
8628   memcpy(g_labels[i], name, len);
8629   g_labels[i][len] = 0;
8630 }
8631
8632 struct chunk_item {
8633   char *name;
8634   long fptr;
8635   int asmln;
8636 };
8637
8638 static struct chunk_item *func_chunks;
8639 static int func_chunk_cnt;
8640 static int func_chunk_alloc;
8641
8642 static void add_func_chunk(FILE *fasm, const char *name, int line)
8643 {
8644   if (func_chunk_cnt >= func_chunk_alloc) {
8645     func_chunk_alloc *= 2;
8646     func_chunks = realloc(func_chunks,
8647       func_chunk_alloc * sizeof(func_chunks[0]));
8648     my_assert_not(func_chunks, NULL);
8649   }
8650   func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8651   func_chunks[func_chunk_cnt].name = strdup(name);
8652   func_chunks[func_chunk_cnt].asmln = line;
8653   func_chunk_cnt++;
8654 }
8655
8656 static int cmp_chunks(const void *p1, const void *p2)
8657 {
8658   const struct chunk_item *c1 = p1, *c2 = p2;
8659   return strcmp(c1->name, c2->name);
8660 }
8661
8662 static void scan_ahead_for_chunks(FILE *fasm)
8663 {
8664   char words[2][256];
8665   char line[256];
8666   long oldpos;
8667   int oldasmln;
8668   int wordc;
8669   char *p;
8670   int i;
8671
8672   oldpos = ftell(fasm);
8673   oldasmln = asmln;
8674
8675   while (my_fgets(line, sizeof(line), fasm))
8676   {
8677     wordc = 0;
8678     asmln++;
8679
8680     p = sskip(line);
8681     if (*p == 0)
8682       continue;
8683
8684     if (*p == ';')
8685     {
8686       // get rid of random tabs
8687       for (i = 0; line[i] != 0; i++)
8688         if (line[i] == '\t')
8689           line[i] = ' ';
8690
8691       if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8692       {
8693         p += 30;
8694         next_word(words[0], sizeof(words[0]), p);
8695         if (words[0][0] == 0)
8696           aerr("missing name for func chunk?\n");
8697
8698         add_func_chunk(fasm, words[0], asmln);
8699       }
8700       else if (IS_START(p, "; sctend"))
8701         break;
8702
8703       continue;
8704     } // *p == ';'
8705
8706     for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8707       words[wordc][0] = 0;
8708       p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8709       if (*p == 0 || *p == ';') {
8710         wordc++;
8711         break;
8712       }
8713     }
8714
8715     if (wordc == 2 && IS(words[1], "ends"))
8716       break;
8717   }
8718
8719   fseek(fasm, oldpos, SEEK_SET);
8720   asmln = oldasmln;
8721 }
8722
8723 int main(int argc, char *argv[])
8724 {
8725   FILE *fout, *fasm, *frlist;
8726   struct parsed_data *pd = NULL;
8727   int pd_alloc = 0;
8728   char **rlist = NULL;
8729   int rlist_len = 0;
8730   int rlist_alloc = 0;
8731   int func_chunks_used = 0;
8732   int func_chunks_sorted = 0;
8733   int func_chunk_i = -1;
8734   long func_chunk_ret = 0;
8735   int func_chunk_ret_ln = 0;
8736   int scanned_ahead = 0;
8737   char line[256];
8738   char words[20][256];
8739   enum opr_lenmod lmod;
8740   char *sctproto = NULL;
8741   int in_func = 0;
8742   int pending_endp = 0;
8743   int skip_code = 0;
8744   int skip_code_end = 0;
8745   int skip_warned = 0;
8746   int eq_alloc;
8747   int verbose = 0;
8748   int multi_seg = 0;
8749   int end = 0;
8750   int arg_out;
8751   int arg;
8752   int pi = 0;
8753   int i, j;
8754   int ret, len;
8755   char *p;
8756   int wordc;
8757
8758   for (arg = 1; arg < argc; arg++) {
8759     if (IS(argv[arg], "-v"))
8760       verbose = 1;
8761     else if (IS(argv[arg], "-rf"))
8762       g_allow_regfunc = 1;
8763     else if (IS(argv[arg], "-uc"))
8764       g_allow_user_icall = 1;
8765     else if (IS(argv[arg], "-m"))
8766       multi_seg = 1;
8767     else if (IS(argv[arg], "-hdr"))
8768       g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8769     else
8770       break;
8771   }
8772
8773   if (argc < arg + 3) {
8774     printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8775            "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8776            "options:\n"
8777            "  -hdr - header generation mode\n"
8778            "  -rf  - allow unannotated indirect calls\n"
8779            "  -uc  - allow ind. calls/refs to __usercall\n"
8780            "  -m   - allow multiple .text sections\n"
8781            "[rlist] is a file with function names to skip,"
8782            " one per line\n",
8783       argv[0], argv[0]);
8784     return 1;
8785   }
8786
8787   arg_out = arg++;
8788
8789   asmfn = argv[arg++];
8790   fasm = fopen(asmfn, "r");
8791   my_assert_not(fasm, NULL);
8792
8793   hdrfn = argv[arg++];
8794   g_fhdr = fopen(hdrfn, "r");
8795   my_assert_not(g_fhdr, NULL);
8796
8797   rlist_alloc = 64;
8798   rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8799   my_assert_not(rlist, NULL);
8800   // needs special handling..
8801   rlist[rlist_len++] = "__alloca_probe";
8802
8803   func_chunk_alloc = 32;
8804   func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8805   my_assert_not(func_chunks, NULL);
8806
8807   memset(words, 0, sizeof(words));
8808
8809   for (; arg < argc; arg++) {
8810     int skip_func = 0;
8811
8812     frlist = fopen(argv[arg], "r");
8813     my_assert_not(frlist, NULL);
8814
8815     while (my_fgets(line, sizeof(line), frlist)) {
8816       p = sskip(line);
8817       if (*p == 0 || *p == ';')
8818         continue;
8819       if (*p == '#') {
8820         if (IS_START(p, "#if 0")
8821          || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
8822         {
8823           skip_func = 1;
8824         }
8825         else if (IS_START(p, "#endif"))
8826           skip_func = 0;
8827         continue;
8828       }
8829       if (skip_func)
8830         continue;
8831
8832       p = next_word(words[0], sizeof(words[0]), p);
8833       if (words[0][0] == 0)
8834         continue;
8835
8836       if (rlist_len >= rlist_alloc) {
8837         rlist_alloc = rlist_alloc * 2 + 64;
8838         rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
8839         my_assert_not(rlist, NULL);
8840       }
8841       rlist[rlist_len++] = strdup(words[0]);
8842     }
8843
8844     fclose(frlist);
8845     frlist = NULL;
8846   }
8847
8848   if (rlist_len > 0)
8849     qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
8850
8851   fout = fopen(argv[arg_out], "w");
8852   my_assert_not(fout, NULL);
8853
8854   eq_alloc = 128;
8855   g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
8856   my_assert_not(g_eqs, NULL);
8857
8858   for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
8859     g_label_refs[i].i = -1;
8860     g_label_refs[i].next = NULL;
8861   }
8862
8863   if (g_header_mode)
8864     scan_variables(fasm, rlist, rlist_len);
8865
8866   while (my_fgets(line, sizeof(line), fasm))
8867   {
8868     wordc = 0;
8869     asmln++;
8870
8871     p = sskip(line);
8872     if (*p == 0)
8873       continue;
8874
8875     // get rid of random tabs
8876     for (i = 0; line[i] != 0; i++)
8877       if (line[i] == '\t')
8878         line[i] = ' ';
8879
8880     if (*p == ';')
8881     {
8882       if (p[2] == '=' && IS_START(p, "; =============== S U B"))
8883         goto do_pending_endp; // eww..
8884
8885       if (p[2] == 'A' && IS_START(p, "; Attributes:"))
8886       {
8887         static const char *attrs[] = {
8888           "bp-based frame",
8889           "library function",
8890           "static",
8891           "noreturn",
8892           "thunk",
8893           "fpd=",
8894         };
8895
8896         // parse IDA's attribute-list comment
8897         g_ida_func_attr = 0;
8898         p = sskip(p + 13);
8899
8900         for (; *p != 0; p = sskip(p)) {
8901           for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8902             if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8903               g_ida_func_attr |= 1 << i;
8904               p += strlen(attrs[i]);
8905               break;
8906             }
8907           }
8908           if (i == ARRAY_SIZE(attrs)) {
8909             anote("unparsed IDA attr: %s\n", p);
8910             break;
8911           }
8912           if (IS(attrs[i], "fpd=")) {
8913             p = next_word(words[0], sizeof(words[0]), p);
8914             // ignore for now..
8915           }
8916         }
8917       }
8918       else if (p[2] == 's' && IS_START(p, "; sctattr:"))
8919       {
8920         static const char *attrs[] = {
8921           "clear_sf",
8922           "clear_regmask",
8923         };
8924
8925         // parse manual attribute-list comment
8926         g_sct_func_attr = 0;
8927         p = sskip(p + 10);
8928
8929         for (; *p != 0; p = sskip(p)) {
8930           for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8931             if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8932               g_sct_func_attr |= 1 << i;
8933               p += strlen(attrs[i]);
8934               break;
8935             }
8936           }
8937           if (*p == '=') {
8938             j = ret = 0;
8939             if (i == 0)
8940               // clear_sf=start,len (in dwords)
8941               ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
8942                       &g_stack_clear_len, &j);
8943             else if (i == 1)
8944               // clear_regmask=<mask>
8945               ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
8946             if (ret < 2) {
8947               anote("unparsed attr value: %s\n", p);
8948               break;
8949             }
8950             p += j;
8951           }
8952           else if (i == ARRAY_SIZE(attrs)) {
8953             anote("unparsed sct attr: %s\n", p);
8954             break;
8955           }
8956         }
8957       }
8958       else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8959       {
8960         p += 30;
8961         next_word(words[0], sizeof(words[0]), p);
8962         if (words[0][0] == 0)
8963           aerr("missing name for func chunk?\n");
8964
8965         if (!scanned_ahead) {
8966           add_func_chunk(fasm, words[0], asmln);
8967           func_chunks_sorted = 0;
8968         }
8969       }
8970       else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
8971       {
8972         if (func_chunk_i >= 0) {
8973           if (func_chunk_i < func_chunk_cnt
8974             && IS(func_chunks[func_chunk_i].name, g_func))
8975           {
8976             // move on to next chunk
8977             ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8978             if (ret)
8979               aerr("seek failed for '%s' chunk #%d\n",
8980                 g_func, func_chunk_i);
8981             asmln = func_chunks[func_chunk_i].asmln;
8982             func_chunk_i++;
8983           }
8984           else {
8985             if (func_chunk_ret == 0)
8986               aerr("no return from chunk?\n");
8987             fseek(fasm, func_chunk_ret, SEEK_SET);
8988             asmln = func_chunk_ret_ln;
8989             func_chunk_ret = 0;
8990             pending_endp = 1;
8991           }
8992         }
8993       }
8994       else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
8995         func_chunks_used = 1;
8996         p += 20;
8997         if (IS_START(g_func, "sub_")) {
8998           unsigned long addr = strtoul(p, NULL, 16);
8999           unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9000           if (addr > f_addr && !scanned_ahead) {
9001             //anote("scan_ahead caused by '%s', addr %lx\n",
9002             //  g_func, addr);
9003             scan_ahead_for_chunks(fasm);
9004             scanned_ahead = 1;
9005             func_chunks_sorted = 0;
9006           }
9007         }
9008       }
9009       continue;
9010     } // *p == ';'
9011
9012 parse_words:
9013     for (i = wordc; i < ARRAY_SIZE(words); i++)
9014       words[i][0] = 0;
9015     for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9016       p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9017       if (*p == 0 || *p == ';') {
9018         wordc++;
9019         break;
9020       }
9021     }
9022     if (*p != 0 && *p != ';')
9023       aerr("too many words\n");
9024
9025     if (skip_code_end) {
9026       skip_code_end = 0;
9027       skip_code = 0;
9028     }
9029
9030     // allow asm patches in comments
9031     if (*p == ';') {
9032       if (IS_START(p, "; sctpatch:")) {
9033         p = sskip(p + 11);
9034         if (*p == 0 || *p == ';')
9035           continue;
9036         goto parse_words; // lame
9037       }
9038       if (IS_START(p, "; sctproto:")) {
9039         sctproto = strdup(p + 11);
9040       }
9041       else if (IS_START(p, "; sctend")) {
9042         end = 1;
9043         if (!pending_endp)
9044           break;
9045       }
9046       else if (IS_START(p, "; sctskip_start")) {
9047         if (in_func && !g_skip_func) {
9048           if (!skip_code) {
9049             ops[pi].op = OPP_ABORT;
9050             ops[pi].asmln = asmln;
9051             pi++;
9052           }
9053           skip_code = 1;
9054         }
9055       }
9056       else if (IS_START(p, "; sctskip_end")) {
9057         if (skip_code)
9058           skip_code_end = 1;
9059       }
9060     }
9061
9062     if (wordc == 0) {
9063       // shouldn't happen
9064       awarn("wordc == 0?\n");
9065       continue;
9066     }
9067
9068     // don't care about this:
9069     if (words[0][0] == '.'
9070         || IS(words[0], "include")
9071         || IS(words[0], "assume") || IS(words[1], "segment")
9072         || IS(words[0], "align"))
9073     {
9074       continue;
9075     }
9076
9077 do_pending_endp:
9078     // do delayed endp processing to collect switch jumptables
9079     if (pending_endp) {
9080       if (in_func && !g_skip_func && !end && wordc >= 2
9081           && ((words[0][0] == 'd' && words[0][2] == 0)
9082               || (words[1][0] == 'd' && words[1][2] == 0)))
9083       {
9084         i = 1;
9085         if (words[1][0] == 'd' && words[1][2] == 0) {
9086           // label
9087           if (g_func_pd_cnt >= pd_alloc) {
9088             pd_alloc = pd_alloc * 2 + 16;
9089             g_func_pd = realloc(g_func_pd,
9090               sizeof(g_func_pd[0]) * pd_alloc);
9091             my_assert_not(g_func_pd, NULL);
9092           }
9093           pd = &g_func_pd[g_func_pd_cnt];
9094           g_func_pd_cnt++;
9095           memset(pd, 0, sizeof(*pd));
9096           strcpy(pd->label, words[0]);
9097           pd->type = OPT_CONST;
9098           pd->lmod = lmod_from_directive(words[1]);
9099           i = 2;
9100         }
9101         else {
9102           if (pd == NULL) {
9103             if (verbose)
9104               anote("skipping alignment byte?\n");
9105             continue;
9106           }
9107           lmod = lmod_from_directive(words[0]);
9108           if (lmod != pd->lmod)
9109             aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9110         }
9111
9112         if (pd->count_alloc < pd->count + wordc) {
9113           pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9114           pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9115           my_assert_not(pd->d, NULL);
9116         }
9117         for (; i < wordc; i++) {
9118           if (IS(words[i], "offset")) {
9119             pd->type = OPT_OFFSET;
9120             i++;
9121           }
9122           p = strchr(words[i], ',');
9123           if (p != NULL)
9124             *p = 0;
9125           if (pd->type == OPT_OFFSET)
9126             pd->d[pd->count].u.label = strdup(words[i]);
9127           else
9128             pd->d[pd->count].u.val = parse_number(words[i], 0);
9129           pd->d[pd->count].bt_i = -1;
9130           pd->count++;
9131         }
9132         continue;
9133       }
9134
9135       if (in_func && !g_skip_func) {
9136         if (g_header_mode)
9137           gen_hdr(g_func, pi);
9138         else
9139           gen_func(fout, g_fhdr, g_func, pi);
9140       }
9141
9142       pending_endp = 0;
9143       in_func = 0;
9144       g_ida_func_attr = 0;
9145       g_sct_func_attr = 0;
9146       g_stack_clear_start = 0;
9147       g_stack_clear_len = 0;
9148       g_regmask_init = 0;
9149       skip_warned = 0;
9150       g_skip_func = 0;
9151       g_func[0] = 0;
9152       func_chunks_used = 0;
9153       func_chunk_i = -1;
9154       if (pi != 0) {
9155         memset(&ops, 0, pi * sizeof(ops[0]));
9156         clear_labels(pi);
9157         pi = 0;
9158       }
9159       g_eqcnt = 0;
9160       for (i = 0; i < g_func_pd_cnt; i++) {
9161         pd = &g_func_pd[i];
9162         if (pd->type == OPT_OFFSET) {
9163           for (j = 0; j < pd->count; j++)
9164             free(pd->d[j].u.label);
9165         }
9166         free(pd->d);
9167         pd->d = NULL;
9168       }
9169       g_func_pd_cnt = 0;
9170       g_func_lmods = 0;
9171       pd = NULL;
9172
9173       if (end)
9174         break;
9175       if (wordc == 0)
9176         continue;
9177     }
9178
9179     if (IS(words[1], "proc")) {
9180       if (in_func)
9181         aerr("proc '%s' while in_func '%s'?\n",
9182           words[0], g_func);
9183       p = words[0];
9184       if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9185         g_skip_func = 1;
9186       strcpy(g_func, words[0]);
9187       set_label(0, words[0]);
9188       in_func = 1;
9189       continue;
9190     }
9191
9192     if (IS(words[1], "endp"))
9193     {
9194       if (!in_func)
9195         aerr("endp '%s' while not in_func?\n", words[0]);
9196       if (!IS(g_func, words[0]))
9197         aerr("endp '%s' while in_func '%s'?\n",
9198           words[0], g_func);
9199       if (skip_code)
9200         aerr("endp '%s' while skipping code\n", words[0]);
9201
9202       if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9203         && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
9204       {
9205         // import jump
9206         g_skip_func = 1;
9207       }
9208
9209       if (!g_skip_func && func_chunks_used) {
9210         // start processing chunks
9211         struct chunk_item *ci, key = { g_func, 0 };
9212
9213         func_chunk_ret = ftell(fasm);
9214         func_chunk_ret_ln = asmln;
9215         if (!func_chunks_sorted) {
9216           qsort(func_chunks, func_chunk_cnt,
9217             sizeof(func_chunks[0]), cmp_chunks);
9218           func_chunks_sorted = 1;
9219         }
9220         ci = bsearch(&key, func_chunks, func_chunk_cnt,
9221                sizeof(func_chunks[0]), cmp_chunks);
9222         if (ci == NULL)
9223           aerr("'%s' needs chunks, but none found\n", g_func);
9224         func_chunk_i = ci - func_chunks;
9225         for (; func_chunk_i > 0; func_chunk_i--)
9226           if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9227             break;
9228
9229         ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9230         if (ret)
9231           aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9232         asmln = func_chunks[func_chunk_i].asmln;
9233         func_chunk_i++;
9234         continue;
9235       }
9236       pending_endp = 1;
9237       continue;
9238     }
9239
9240     if (wordc == 2 && IS(words[1], "ends")) {
9241       if (!multi_seg) {
9242         end = 1;
9243         if (pending_endp)
9244           goto do_pending_endp;
9245         break;
9246       }
9247
9248       // scan for next text segment
9249       while (my_fgets(line, sizeof(line), fasm)) {
9250         asmln++;
9251         p = sskip(line);
9252         if (*p == 0 || *p == ';')
9253           continue;
9254
9255         if (strstr(p, "segment para public 'CODE' use32"))
9256           break;
9257       }
9258
9259       continue;
9260     }
9261
9262     p = strchr(words[0], ':');
9263     if (p != NULL) {
9264       set_label(pi, words[0]);
9265       continue;
9266     }
9267
9268     if (!in_func || g_skip_func || skip_code) {
9269       if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9270         if (verbose)
9271           anote("skipping from '%s'\n", g_labels[pi]);
9272         skip_warned = 1;
9273       }
9274       free(g_labels[pi]);
9275       g_labels[pi] = NULL;
9276       continue;
9277     }
9278
9279     if (wordc > 1 && IS(words[1], "="))
9280     {
9281       if (wordc != 5)
9282         aerr("unhandled equ, wc=%d\n", wordc);
9283       if (g_eqcnt >= eq_alloc) {
9284         eq_alloc *= 2;
9285         g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9286         my_assert_not(g_eqs, NULL);
9287       }
9288
9289       len = strlen(words[0]);
9290       if (len > sizeof(g_eqs[0].name) - 1)
9291         aerr("equ name too long: %d\n", len);
9292       strcpy(g_eqs[g_eqcnt].name, words[0]);
9293
9294       if (!IS(words[3], "ptr"))
9295         aerr("unhandled equ\n");
9296       if (IS(words[2], "dword"))
9297         g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9298       else if (IS(words[2], "word"))
9299         g_eqs[g_eqcnt].lmod = OPLM_WORD;
9300       else if (IS(words[2], "byte"))
9301         g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9302       else if (IS(words[2], "qword"))
9303         g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9304       else
9305         aerr("bad lmod: '%s'\n", words[2]);
9306
9307       g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9308       g_eqcnt++;
9309       continue;
9310     }
9311
9312     if (pi >= ARRAY_SIZE(ops))
9313       aerr("too many ops\n");
9314
9315     parse_op(&ops[pi], words, wordc);
9316
9317     ops[pi].datap = sctproto;
9318     sctproto = NULL;
9319     pi++;
9320   }
9321
9322   if (g_header_mode)
9323     output_hdr(fout);
9324
9325   fclose(fout);
9326   fclose(fasm);
9327   fclose(g_fhdr);
9328
9329   return 0;
9330 }
9331
9332 // vim:ts=2:shiftwidth=2:expandtab