improve arg collect yet more, tune asm
[ia32rtools.git] / tools / translate.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include "my_assert.h"
7 #include "my_str.h"
8
9 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
10 #define IS(w, y) !strcmp(w, y)
11 #define IS_START(w, y) !strncmp(w, y, strlen(y))
12
13 #include "protoparse.h"
14
15 static const char *asmfn;
16 static int asmln;
17 static FILE *g_fhdr;
18
19 #define anote(fmt, ...) \
20         printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
21 #define awarn(fmt, ...) \
22         printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
23 #define aerr(fmt, ...) do { \
24         printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
25   fcloseall(); \
26         exit(1); \
27 } while (0)
28
29 enum op_flags {
30   OPF_RMD    = (1 << 0), /* removed or optimized out */
31   OPF_DATA   = (1 << 1), /* data processing - writes to dst opr */
32   OPF_FLAGS  = (1 << 2), /* sets flags */
33   OPF_JMP    = (1 << 3), /* branches, ret and call */
34   OPF_CC     = (1 << 4), /* uses flags */
35   OPF_TAIL   = (1 << 5), /* ret or tail call */
36   OPF_RSAVE  = (1 << 6), /* push/pop is local reg save/load */
37   OPF_REP    = (1 << 7), /* prefixed by rep */
38   OPF_REPZ   = (1 << 8), /* rep is repe/repz */
39   OPF_REPNZ  = (1 << 9), /* rep is repne/repnz */
40   OPF_FARG   = (1 << 10), /* push collected as func arg (no reuse) */
41 };
42
43 enum op_op {
44         OP_INVAL,
45         OP_NOP,
46         OP_PUSH,
47         OP_POP,
48         OP_MOV,
49         OP_LEA,
50         OP_MOVZX,
51         OP_MOVSX,
52         OP_NOT,
53         OP_CDQ,
54         OP_STOS,
55         OP_MOVS,
56         OP_CMPS,
57         OP_RET,
58         OP_ADD,
59         OP_SUB,
60         OP_AND,
61         OP_OR,
62         OP_XOR,
63         OP_SHL,
64         OP_SHR,
65         OP_SAR,
66         OP_ROL,
67         OP_ROR,
68         OP_ADC,
69         OP_SBB,
70         OP_INC,
71         OP_DEC,
72         OP_NEG,
73         OP_MUL,
74         OP_IMUL,
75         OP_DIV,
76         OP_IDIV,
77         OP_TEST,
78         OP_CMP,
79         OP_CALL,
80         OP_JMP,
81         OP_JO,
82         OP_JNO,
83         OP_JC,
84         OP_JNC,
85         OP_JZ,
86         OP_JNZ,
87         OP_JBE,
88         OP_JA,
89         OP_JS,
90         OP_JNS,
91         OP_JP,
92         OP_JNP,
93         OP_JL,
94         OP_JGE,
95         OP_JLE,
96         OP_JG,
97 };
98
99 enum opr_type {
100   OPT_UNSPEC,
101   OPT_REG,
102   OPT_REGMEM,
103   OPT_LABEL,
104   OPT_OFFSET,
105   OPT_CONST,
106 };
107
108 enum opr_lenmod {
109         OPLM_UNSPEC,
110         OPLM_BYTE,
111         OPLM_WORD,
112         OPLM_DWORD,
113 };
114
115 #define MAX_OPERANDS 3
116
117 struct parsed_opr {
118   enum opr_type type;
119   enum opr_lenmod lmod;
120   unsigned int is_ptr:1;   // pointer in C
121   unsigned int is_array:1; // array in C
122   int reg;
123   unsigned int val;
124   char name[256];
125 };
126
127 struct parsed_op {
128   enum op_op op;
129   struct parsed_opr operand[MAX_OPERANDS];
130   unsigned int flags;
131   int operand_cnt;
132   int regmask_src;        // all referensed regs
133   int regmask_dst;
134   int pfomask;            // flagop: parsed_flag_op that can't be delayed
135   int argnum;             // push: altered before call arg #
136   int cc_scratch;         // scratch storage during analysis
137   int bt_i;               // branch target for branches
138   struct parsed_data *btj;// branch targets for jumptables
139   void *datap;
140 };
141
142 // datap:
143 // OP_CALL - ptr to parsed_proto
144 // (OPF_CC) - point to corresponding (OPF_FLAGS)
145
146 struct parsed_equ {
147   char name[64];
148   enum opr_lenmod lmod;
149   int offset;
150 };
151
152 struct parsed_data {
153   char label[256];
154   enum opr_type type;
155   enum opr_lenmod lmod;
156   int count;
157   int count_alloc;
158   struct {
159     union {
160       char *label;
161       unsigned int val;
162     } u;
163     int bt_i;
164   } *d;
165 };
166
167 struct label_ref {
168   int i;
169   struct label_ref *next;
170 };
171
172 enum ida_func_attr {
173   IDAFA_BP_FRAME = (1 << 0),
174   IDAFA_LIB_FUNC = (1 << 1),
175   IDAFA_STATIC   = (1 << 2),
176   IDAFA_NORETURN = (1 << 3),
177   IDAFA_THUNK    = (1 << 4),
178   IDAFA_FPD      = (1 << 5),
179 };
180
181 #define MAX_OPS 4096
182
183 static struct parsed_op ops[MAX_OPS];
184 static struct parsed_equ *g_eqs;
185 static int g_eqcnt;
186 static char g_labels[MAX_OPS][32];
187 static struct label_ref g_label_refs[MAX_OPS];
188 static struct parsed_proto g_func_pp;
189 static struct parsed_data *g_func_pd;
190 static int g_func_pd_cnt;
191 static char g_func[256];
192 static char g_comment[256];
193 static int g_bp_frame;
194 static int g_sp_frame;
195 static int g_stack_fsz;
196 static int g_ida_func_attr;
197 #define ferr(op_, fmt, ...) do { \
198   printf("error:%s:#%zd: '%s': " fmt, g_func, (op_) - ops, \
199     dump_op(op_), ##__VA_ARGS__); \
200   fcloseall(); \
201   exit(1); \
202 } while (0)
203 #define fnote(op_, fmt, ...) \
204   printf("error:%s:#%zd: '%s': " fmt, g_func, (op_) - ops, \
205     dump_op(op_), ##__VA_ARGS__)
206
207 #define MAX_REGS 8
208
209 const char *regs_r32[] = { "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp" };
210 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
211 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
212 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
213
214 enum x86_regs { xUNSPEC = -1, xAX, xBX, xCX, xDX, xSI, xDI, xBP, xSP };
215
216 // possible basic comparison types (without inversion)
217 enum parsed_flag_op {
218   PFO_O,  // 0 OF=1
219   PFO_C,  // 2 CF=1
220   PFO_Z,  // 4 ZF=1
221   PFO_BE, // 6 CF=1||ZF=1
222   PFO_S,  // 8 SF=1
223   PFO_P,  // a PF=1
224   PFO_L,  // c SF!=OF
225   PFO_LE, // e ZF=1||SF!=OF
226 };
227
228 static const char *parsed_flag_op_names[] = {
229   "o", "c", "z", "be", "s", "p", "l", "le"
230 };
231
232 static int char_array_i(const char *array[], size_t len, const char *s)
233 {
234   int i;
235
236   for (i = 0; i < len; i++)
237     if (IS(s, array[i]))
238       return i;
239
240   return -1;
241 }
242
243 static void printf_number(char *buf, size_t buf_size,
244   unsigned long number)
245 {
246   // output in C-friendly form
247   snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
248 }
249
250 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
251 {
252   int reg;
253
254   reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
255   if (reg >= 0) {
256     *reg_lmod = OPLM_DWORD;
257     return reg;
258   }
259   reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
260   if (reg >= 0) {
261     *reg_lmod = OPLM_WORD;
262     return reg;
263   }
264   reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
265   if (reg >= 0) {
266     *reg_lmod = OPLM_BYTE;
267     return reg;
268   }
269   reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
270   if (reg >= 0) {
271     *reg_lmod = OPLM_BYTE;
272     return reg;
273   }
274
275   return -1;
276 }
277
278 static unsigned long parse_number(const char *number)
279 {
280   int len = strlen(number);
281   const char *p = number;
282   char *endp = NULL;
283   unsigned long ret;
284   int neg = 0;
285   int bad;
286
287   if (*p == '-') {
288     neg = 1;
289     p++;
290   }
291   if (len > 1 && *p == '0')
292     p++;
293   if (number[len - 1] == 'h') {
294     ret = strtoul(p, &endp, 16);
295     bad = (*endp != 'h');
296   }
297   else {
298     ret = strtoul(p, &endp, 10);
299     bad = (*endp != 0);
300   }
301   if (bad)
302     aerr("number parsing failed\n");
303   if (neg)
304     ret = -ret;
305   return ret;
306 }
307
308 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
309 {
310   enum opr_lenmod lmod;
311   char cvtbuf[256];
312   char *d = cvtbuf;
313   char *s = name;
314   char w[64];
315   long number;
316   int reg;
317   int c = 0;
318
319   *d = 0;
320
321   while (*s != 0) {
322     d += strlen(d);
323     while (my_isblank(*s))
324       s++;
325     for (; my_issep(*s); d++, s++)
326       *d = *s;
327     while (my_isblank(*s))
328       s++;
329     *d = 0;
330
331     // skip 'ds:' prefix
332     if (IS_START(s, "ds:"))
333       s += 3;
334
335     s = next_idt(w, sizeof(w), s);
336     if (w[0] == 0)
337       break;
338     c++;
339
340     reg = parse_reg(&lmod, w);
341     if (reg >= 0) {
342       *regmask |= 1 << reg;
343       goto pass;
344     }
345
346     if ('0' <= w[0] && w[0] <= '9') {
347       number = parse_number(w);
348       printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
349       continue;
350     }
351
352     // probably some label/identifier - pass
353
354 pass:
355     snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
356   }
357
358   if (need_c_cvt)
359     strcpy(name, cvtbuf);
360
361   return c;
362 }
363
364 static int is_reg_in_str(const char *s)
365 {
366   int i;
367
368   if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
369     return 0;
370
371   for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
372     if (!strncmp(s, regs_r32[i], 3))
373       return 1;
374
375   return 0;
376 }
377
378 static const char *parse_stack_el(const char *name, char *extra_reg)
379 {
380   const char *p, *p2, *s;
381   char *endp = NULL;
382   char buf[32];
383   long val;
384   int len;
385
386   p = name;
387   if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
388     p += 4;
389     if (extra_reg != NULL) {
390       strncpy(extra_reg, name, 3);
391       extra_reg[4] = 0;
392     }
393   }
394
395   if (IS_START(p, "ebp+")) {
396     p += 4;
397
398     p2 = strchr(p, '+');
399     if (p2 != NULL && is_reg_in_str(p)) {
400       if (extra_reg != NULL) {
401         strncpy(extra_reg, p, p2 - p);
402         extra_reg[p2 - p] = 0;
403       }
404       p = p2 + 1;
405     }
406
407     if (!('0' <= *p && *p <= '9'))
408       return p;
409
410     return NULL;
411   }
412
413   if (!IS_START(name, "esp+"))
414     return NULL;
415
416   p = strchr(name + 4, '+');
417   if (p) {
418     // must be a number after esp+, already converted to 0x..
419     s = name + 4;
420     if (!('0' <= *s && *s <= '9')) {
421                   aerr("%s nan?\n", __func__);
422       return NULL;
423     }
424     if (s[0] == '0' && s[1] == 'x')
425       s += 2;
426     len = p - s;
427     if (len < sizeof(buf) - 1) {
428       strncpy(buf, s, len);
429       buf[len] = 0;
430       val = strtol(buf, &endp, 16);
431       if (val == 0 || *endp != 0) {
432         aerr("%s num parse fail for '%s'\n", __func__, buf);
433         return NULL;
434       }
435     }
436     p++;
437   }
438   else
439     p = name + 4;
440
441   if ('0' <= *p && *p <= '9')
442     return NULL;
443
444   return p;
445 }
446
447 static int guess_lmod_from_name(struct parsed_opr *opr)
448 {
449   if (!strncmp(opr->name, "dword_", 6)) {
450     opr->lmod = OPLM_DWORD;
451     return 1;
452   }
453   if (!strncmp(opr->name, "word_", 5)) {
454     opr->lmod = OPLM_WORD;
455     return 1;
456   }
457   if (!strncmp(opr->name, "byte_", 5)) {
458     opr->lmod = OPLM_BYTE;
459     return 1;
460   }
461   return 0;
462 }
463
464 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
465   const struct parsed_type *c_type)
466 {
467   static const char *dword_types[] = {
468     "int", "_DWORD", "DWORD", "HANDLE", "HWND", "HMODULE",
469   };
470   static const char *word_types[] = {
471     "__int16", "unsigned __int16",
472   };
473   static const char *byte_types[] = {
474     "char", "__int8", "unsigned __int8", "BYTE",
475   };
476   const char *n;
477   int i;
478
479   if (c_type->is_ptr) {
480     *lmod = OPLM_DWORD;
481     return 1;
482   }
483
484   n = skip_type_mod(c_type->name);
485
486   for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
487     if (IS(n, dword_types[i])) {
488       *lmod = OPLM_DWORD;
489       return 1;
490     }
491   }
492
493   for (i = 0; i < ARRAY_SIZE(word_types); i++) {
494     if (IS(n, word_types[i])) {
495       *lmod = OPLM_WORD;
496       return 1;
497     }
498   }
499
500   for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
501     if (IS(n, byte_types[i])) {
502       *lmod = OPLM_BYTE;
503       return 1;
504     }
505   }
506
507   return 0;
508 }
509
510 static enum opr_type lmod_from_directive(const char *d)
511 {
512   if (IS(d, "dd"))
513     return OPLM_DWORD;
514   else if (IS(d, "dw"))
515     return OPLM_WORD;
516   else if (IS(d, "db"))
517     return OPLM_BYTE;
518
519   aerr("unhandled directive: '%s'\n", d);
520   return OPLM_UNSPEC;
521 }
522
523 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
524   int *regmask)
525 {
526   opr->type = OPT_REG;
527   opr->reg = reg;
528   opr->lmod = lmod;
529   *regmask |= 1 << reg;
530 }
531
532 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
533   int *extra_offs);
534
535 static int parse_operand(struct parsed_opr *opr,
536   int *regmask, int *regmask_indirect,
537   char words[16][256], int wordc, int w, unsigned int op_flags)
538 {
539   struct parsed_proto pp;
540   enum opr_lenmod tmplmod;
541   unsigned long number;
542   int ret, len;
543   int wordc_in;
544   char *tmp;
545   int i;
546
547   if (w >= wordc)
548     aerr("parse_operand w %d, wordc %d\n", w, wordc);
549
550   opr->reg = xUNSPEC;
551
552   for (i = w; i < wordc; i++) {
553     len = strlen(words[i]);
554     if (words[i][len - 1] == ',') {
555       words[i][len - 1] = 0;
556       wordc = i + 1;
557       break;
558     }
559   }
560
561   wordc_in = wordc - w;
562
563   if ((op_flags & OPF_JMP) && wordc_in > 0
564       && !('0' <= words[w][0] && words[w][0] <= '9'))
565   {
566     const char *label = NULL;
567
568     if (wordc_in == 3 && !strncmp(words[w], "near", 4)
569      && IS(words[w + 1], "ptr"))
570       label = words[w + 2];
571     else if (wordc_in == 2 && IS(words[w], "short"))
572       label = words[w + 1];
573     else if (wordc_in == 1
574           && strchr(words[w], '[') == NULL
575           && parse_reg(&tmplmod, words[w]) < 0)
576       label = words[w];
577
578     if (label != NULL) {
579       opr->type = OPT_LABEL;
580       if (IS_START(label, "ds:"))
581         label += 3;
582       strcpy(opr->name, label);
583       return wordc;
584     }
585   }
586
587   if (wordc_in >= 3) {
588     if (IS(words[w + 1], "ptr")) {
589       if (IS(words[w], "dword"))
590         opr->lmod = OPLM_DWORD;
591       else if (IS(words[w], "word"))
592         opr->lmod = OPLM_WORD;
593       else if (IS(words[w], "byte"))
594         opr->lmod = OPLM_BYTE;
595       else
596         aerr("type parsing failed\n");
597       w += 2;
598       wordc_in = wordc - w;
599     }
600   }
601
602   if (wordc_in == 2) {
603     if (IS(words[w], "offset")) {
604       opr->type = OPT_OFFSET;
605       strcpy(opr->name, words[w + 1]);
606       return wordc;
607     }
608     if (IS(words[w], "(offset")) {
609       char *p = strchr(words[w + 1], ')');
610       if (p == NULL)
611         aerr("parse of bracketed offset failed\n");
612       *p = 0;
613       opr->type = OPT_OFFSET;
614       strcpy(opr->name, words[w + 1]);
615       return wordc;
616     }
617   }
618
619   if (wordc_in != 1)
620     aerr("parse_operand 1 word expected\n");
621
622   tmp = words[w];
623   if (IS_START(tmp, "ds:"))
624     tmp += 3;
625   strcpy(opr->name, tmp);
626
627   if (words[w][0] == '[') {
628     opr->type = OPT_REGMEM;
629     ret = sscanf(words[w], "[%[^]]]", opr->name);
630     if (ret != 1)
631       aerr("[] parse failure\n");
632
633     parse_indmode(opr->name, regmask_indirect, 1);
634     if (opr->lmod == OPLM_UNSPEC && parse_stack_el(opr->name, NULL)) {
635       // might be an equ
636       struct parsed_equ *eq =
637         equ_find(NULL, parse_stack_el(opr->name, NULL), &i);
638       if (eq)
639         opr->lmod = eq->lmod;
640     }
641     return wordc;
642   }
643   else if (strchr(words[w], '[')) {
644     // label[reg] form
645     opr->type = OPT_REGMEM;
646     if (opr->lmod == OPLM_UNSPEC)
647       guess_lmod_from_name(opr);
648     parse_indmode(strchr(words[w], '['), regmask_indirect, 0);
649     return wordc;
650   }
651   else if (('0' <= words[w][0] && words[w][0] <= '9')
652     || words[w][0] == '-')
653   {
654     number = parse_number(words[w]);
655     opr->type = OPT_CONST;
656     opr->val = number;
657     printf_number(opr->name, sizeof(opr->name), number);
658     return wordc;
659   }
660
661   ret = parse_reg(&tmplmod, opr->name);
662   if (ret >= 0) {
663     setup_reg_opr(opr, ret, tmplmod, regmask);
664     return wordc;
665   }
666
667   // most likely var in data segment
668   opr->type = OPT_LABEL;
669
670   ret = proto_parse(g_fhdr, opr->name, &pp);
671   if (ret == 0) {
672     if (pp.is_fptr) {
673       opr->lmod = OPLM_DWORD;
674       opr->is_ptr = 1;
675     }
676     else if (opr->lmod == OPLM_UNSPEC) {
677       if (!guess_lmod_from_c_type(&opr->lmod, &pp.type))
678         anote("unhandled C type '%s' for '%s'\n", pp.type.name, opr->name);
679     }
680     opr->is_ptr = pp.type.is_ptr;
681     opr->is_array = pp.type.is_array;
682   }
683   proto_release(&pp);
684
685   if (opr->lmod == OPLM_UNSPEC)
686     guess_lmod_from_name(opr);
687   return wordc;
688 }
689
690 static const struct {
691   const char *name;
692   unsigned int flags;
693 } pref_table[] = {
694   { "rep",    OPF_REP },
695   { "repe",   OPF_REP|OPF_REPZ },
696   { "repz",   OPF_REP|OPF_REPZ },
697   { "repne",  OPF_REP|OPF_REPNZ },
698   { "repnz",  OPF_REP|OPF_REPNZ },
699 };
700
701 static const struct {
702   const char *name;
703   enum op_op op;
704   unsigned int minopr;
705   unsigned int maxopr;
706   unsigned int flags;
707 } op_table[] = {
708   { "nop",  OP_NOP,    0, 0, 0 },
709   { "push", OP_PUSH,   1, 1, 0 },
710   { "pop",  OP_POP,    1, 1, OPF_DATA },
711   { "mov" , OP_MOV,    2, 2, OPF_DATA },
712   { "lea",  OP_LEA,    2, 2, OPF_DATA },
713   { "movzx",OP_MOVZX,  2, 2, OPF_DATA },
714   { "movsx",OP_MOVSX,  2, 2, OPF_DATA },
715   { "not",  OP_NOT,    1, 1, OPF_DATA },
716   { "cdq",  OP_CDQ,    0, 0, OPF_DATA },
717   { "stosb",OP_STOS,   0, 0, OPF_DATA },
718   { "stosw",OP_STOS,   0, 0, OPF_DATA },
719   { "stosd",OP_STOS,   0, 0, OPF_DATA },
720   { "movsb",OP_MOVS,   0, 0, OPF_DATA },
721   { "movsw",OP_MOVS,   0, 0, OPF_DATA },
722   { "movsd",OP_MOVS,   0, 0, OPF_DATA },
723   { "cmpsb",OP_CMPS,   0, 0, OPF_DATA|OPF_FLAGS },
724   { "cmpsw",OP_CMPS,   0, 0, OPF_DATA|OPF_FLAGS },
725   { "cmpsd",OP_CMPS,   0, 0, OPF_DATA|OPF_FLAGS },
726   { "add",  OP_ADD,    2, 2, OPF_DATA|OPF_FLAGS },
727   { "sub",  OP_SUB,    2, 2, OPF_DATA|OPF_FLAGS },
728   { "and",  OP_AND,    2, 2, OPF_DATA|OPF_FLAGS },
729   { "or",   OP_OR,     2, 2, OPF_DATA|OPF_FLAGS },
730   { "xor",  OP_XOR,    2, 2, OPF_DATA|OPF_FLAGS },
731   { "shl",  OP_SHL,    2, 2, OPF_DATA|OPF_FLAGS },
732   { "shr",  OP_SHR,    2, 2, OPF_DATA|OPF_FLAGS },
733   { "sal",  OP_SHL,    2, 2, OPF_DATA|OPF_FLAGS },
734   { "sar",  OP_SAR,    2, 2, OPF_DATA|OPF_FLAGS },
735   { "rol",  OP_ROL,    2, 2, OPF_DATA|OPF_FLAGS },
736   { "ror",  OP_ROR,    2, 2, OPF_DATA|OPF_FLAGS },
737   { "adc",  OP_ADC,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
738   { "sbb",  OP_SBB,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
739   { "inc",  OP_INC,    1, 1, OPF_DATA|OPF_FLAGS },
740   { "dec",  OP_DEC,    1, 1, OPF_DATA|OPF_FLAGS },
741   { "neg",  OP_NEG,    1, 1, OPF_DATA|OPF_FLAGS },
742   { "mul",  OP_MUL,    1, 1, OPF_DATA|OPF_FLAGS },
743   { "imul", OP_IMUL,   1, 3, OPF_DATA|OPF_FLAGS },
744   { "div",  OP_DIV,    1, 1, OPF_DATA|OPF_FLAGS },
745   { "idiv", OP_IDIV,   1, 1, OPF_DATA|OPF_FLAGS },
746   { "test", OP_TEST,   2, 2, OPF_FLAGS },
747   { "cmp",  OP_CMP,    2, 2, OPF_FLAGS },
748   { "retn", OP_RET,    0, 1, OPF_JMP|OPF_TAIL },
749   { "call", OP_CALL,   1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
750   { "jmp",  OP_JMP,    1, 1, OPF_JMP },
751   { "jo",   OP_JO,     1, 1, OPF_JMP|OPF_CC }, // 70 OF=1
752   { "jno",  OP_JNO,    1, 1, OPF_JMP|OPF_CC }, // 71 OF=0
753   { "jc",   OP_JC,     1, 1, OPF_JMP|OPF_CC }, // 72 CF=1
754   { "jb",   OP_JC,     1, 1, OPF_JMP|OPF_CC }, // 72
755   { "jnc",  OP_JNC,    1, 1, OPF_JMP|OPF_CC }, // 73 CF=0
756   { "jnb",  OP_JNC,    1, 1, OPF_JMP|OPF_CC }, // 73
757   { "jae",  OP_JNC,    1, 1, OPF_JMP|OPF_CC }, // 73
758   { "jz",   OP_JZ,     1, 1, OPF_JMP|OPF_CC }, // 74 ZF=1
759   { "je",   OP_JZ,     1, 1, OPF_JMP|OPF_CC }, // 74
760   { "jnz",  OP_JNZ,    1, 1, OPF_JMP|OPF_CC }, // 75 ZF=0
761   { "jne",  OP_JNZ,    1, 1, OPF_JMP|OPF_CC }, // 75
762   { "jbe",  OP_JBE,    1, 1, OPF_JMP|OPF_CC }, // 76 CF=1 || ZF=1
763   { "jna",  OP_JBE,    1, 1, OPF_JMP|OPF_CC }, // 76
764   { "ja",   OP_JA,     1, 1, OPF_JMP|OPF_CC }, // 77 CF=0 && ZF=0
765   { "jnbe", OP_JA,     1, 1, OPF_JMP|OPF_CC }, // 77
766   { "js",   OP_JS,     1, 1, OPF_JMP|OPF_CC }, // 78 SF=1
767   { "jns",  OP_JNS,    1, 1, OPF_JMP|OPF_CC }, // 79 SF=0
768   { "jp",   OP_JP,     1, 1, OPF_JMP|OPF_CC }, // 7a PF=1
769   { "jpe",  OP_JP,     1, 1, OPF_JMP|OPF_CC }, // 7a
770   { "jnp",  OP_JNP,    1, 1, OPF_JMP|OPF_CC }, // 7b PF=0
771   { "jpo",  OP_JNP,    1, 1, OPF_JMP|OPF_CC }, // 7b
772   { "jl",   OP_JL,     1, 1, OPF_JMP|OPF_CC }, // 7c SF!=OF
773   { "jnge", OP_JL,     1, 1, OPF_JMP|OPF_CC }, // 7c
774   { "jge",  OP_JGE,    1, 1, OPF_JMP|OPF_CC }, // 7d SF=OF
775   { "jnl",  OP_JGE,    1, 1, OPF_JMP|OPF_CC }, // 7d
776   { "jle",  OP_JLE,    1, 1, OPF_JMP|OPF_CC }, // 7e ZF=1 || SF!=OF
777   { "jng",  OP_JLE,    1, 1, OPF_JMP|OPF_CC }, // 7e
778   { "jg",   OP_JG,     1, 1, OPF_JMP|OPF_CC }, // 7f ZF=0 && SF=OF
779   { "jnle", OP_JG,     1, 1, OPF_JMP|OPF_CC }, // 7f
780   { "seto",   OP_JO,   1, 1, OPF_DATA|OPF_CC },
781   { "setno",  OP_JNO,  1, 1, OPF_DATA|OPF_CC },
782   { "setc",   OP_JC,   1, 1, OPF_DATA|OPF_CC },
783   { "setb",   OP_JC,   1, 1, OPF_DATA|OPF_CC },
784   { "setnc",  OP_JNC,  1, 1, OPF_DATA|OPF_CC },
785   { "setae",  OP_JNC,  1, 1, OPF_DATA|OPF_CC },
786   { "setz",   OP_JZ,   1, 1, OPF_DATA|OPF_CC },
787   { "sete",   OP_JZ,   1, 1, OPF_DATA|OPF_CC },
788   { "setnz",  OP_JNZ,  1, 1, OPF_DATA|OPF_CC },
789   { "setne",  OP_JNZ,  1, 1, OPF_DATA|OPF_CC },
790   { "setbe",  OP_JBE,  1, 1, OPF_DATA|OPF_CC },
791   { "setna",  OP_JBE,  1, 1, OPF_DATA|OPF_CC },
792   { "seta",   OP_JA,   1, 1, OPF_DATA|OPF_CC },
793   { "setnbe", OP_JA,   1, 1, OPF_DATA|OPF_CC },
794   { "sets",   OP_JS,   1, 1, OPF_DATA|OPF_CC },
795   { "setns",  OP_JNS,  1, 1, OPF_DATA|OPF_CC },
796   { "setp",   OP_JP,   1, 1, OPF_DATA|OPF_CC },
797   { "setpe",  OP_JP,   1, 1, OPF_DATA|OPF_CC },
798   { "setnp",  OP_JNP,  1, 1, OPF_DATA|OPF_CC },
799   { "setpo",  OP_JNP,  1, 1, OPF_DATA|OPF_CC },
800   { "setl",   OP_JL,   1, 1, OPF_DATA|OPF_CC },
801   { "setnge", OP_JL,   1, 1, OPF_DATA|OPF_CC },
802   { "setge",  OP_JGE,  1, 1, OPF_DATA|OPF_CC },
803   { "setnl",  OP_JGE,  1, 1, OPF_DATA|OPF_CC },
804   { "setle",  OP_JLE,  1, 1, OPF_DATA|OPF_CC },
805   { "setng",  OP_JLE,  1, 1, OPF_DATA|OPF_CC },
806   { "setg",   OP_JG,   1, 1, OPF_DATA|OPF_CC },
807   { "setnle", OP_JG,   1, 1, OPF_DATA|OPF_CC },
808 };
809
810 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
811 {
812   enum opr_lenmod lmod = OPLM_UNSPEC;
813   int prefix_flags = 0;
814   int regmask_ind;
815   int regmask;
816   int op_w = 0;
817   int opr = 0;
818   int w = 0;
819   int i;
820
821   for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
822     if (IS(words[w], pref_table[i].name)) {
823       prefix_flags = pref_table[i].flags;
824       break;
825     }
826   }
827
828   if (prefix_flags) {
829     if (wordc <= 1)
830       aerr("lone prefix: '%s'\n", words[0]);
831     w++;
832   }
833
834   op_w = w;
835   for (i = 0; i < ARRAY_SIZE(op_table); i++) {
836     if (IS(words[w], op_table[i].name))
837       break;
838   }
839
840   if (i == ARRAY_SIZE(op_table))
841     aerr("unhandled op: '%s'\n", words[0]);
842   w++;
843
844   op->op = op_table[i].op;
845   op->flags = op_table[i].flags | prefix_flags;
846   op->regmask_src = op->regmask_dst = 0;
847
848   for (opr = 0; opr < op_table[i].minopr; opr++) {
849     regmask = regmask_ind = 0;
850     w = parse_operand(&op->operand[opr], &regmask, &regmask_ind,
851       words, wordc, w, op->flags);
852
853     if (opr == 0 && (op->flags & OPF_DATA))
854       op->regmask_dst = regmask;
855     // for now, mark dst as src too
856     op->regmask_src |= regmask | regmask_ind;
857   }
858
859   for (; w < wordc && opr < op_table[i].maxopr; opr++) {
860     w = parse_operand(&op->operand[opr],
861       &op->regmask_src, &op->regmask_src,
862       words, wordc, w, op->flags);
863   }
864
865   if (w < wordc)
866     aerr("parse_op %s incomplete: %d/%d\n",
867       words[0], w, wordc);
868
869   // special cases
870   op->operand_cnt = opr;
871   if (!strncmp(op_table[i].name, "set", 3))
872     op->operand[0].lmod = OPLM_BYTE;
873
874   // ops with implicit argumets
875   switch (op->op) {
876   case OP_CDQ:
877     op->operand_cnt = 2;
878     setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
879     setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
880     break;
881
882   case OP_STOS:
883     if (op->operand_cnt != 0)
884       break;
885     if      (IS(words[op_w], "stosb"))
886       lmod = OPLM_BYTE;
887     else if (IS(words[op_w], "stosw"))
888       lmod = OPLM_WORD;
889     else if (IS(words[op_w], "stosd"))
890       lmod = OPLM_DWORD;
891     op->operand_cnt = 3;
892     setup_reg_opr(&op->operand[0], xDI, lmod, &op->regmask_src);
893     setup_reg_opr(&op->operand[1], xCX, OPLM_DWORD, &op->regmask_src);
894     op->regmask_dst = op->regmask_src;
895     setup_reg_opr(&op->operand[2], xAX, OPLM_DWORD, &op->regmask_src);
896     break;
897
898   case OP_MOVS:
899   case OP_CMPS:
900     if (op->operand_cnt != 0)
901       break;
902     if      (words[op_w][4] == 'b')
903       lmod = OPLM_BYTE;
904     else if (words[op_w][4] == 'w')
905       lmod = OPLM_WORD;
906     else if (words[op_w][4] == 'd')
907       lmod = OPLM_DWORD;
908     op->operand_cnt = 3;
909     setup_reg_opr(&op->operand[0], xDI, lmod, &op->regmask_src);
910     setup_reg_opr(&op->operand[1], xSI, OPLM_DWORD, &op->regmask_src);
911     setup_reg_opr(&op->operand[2], xCX, OPLM_DWORD, &op->regmask_src);
912     op->regmask_dst = op->regmask_src;
913     break;
914
915   case OP_IMUL:
916     if (op->operand_cnt != 1)
917       break;
918     // fallthrough
919   case OP_MUL:
920     // singleop mul
921     op->regmask_dst = (1 << xDX) | (1 << xAX);
922     op->regmask_src |= (1 << xAX);
923     if (op->operand[0].lmod == OPLM_UNSPEC)
924       op->operand[0].lmod = OPLM_DWORD;
925     break;
926
927   case OP_DIV:
928   case OP_IDIV:
929     // we could set up operands for edx:eax, but there is no real need to
930     // (see is_opr_modified())
931     regmask = (1 << xDX) | (1 << xAX);
932     op->regmask_dst = regmask;
933     op->regmask_src |= regmask;
934     if (op->operand[0].lmod == OPLM_UNSPEC)
935       op->operand[0].lmod = OPLM_DWORD;
936     break;
937
938   case OP_SHL:
939   case OP_SHR:
940   case OP_SAR:
941   case OP_ROL:
942   case OP_ROR:
943     if (op->operand[1].lmod == OPLM_UNSPEC)
944       op->operand[1].lmod = OPLM_BYTE;
945     break;
946
947   case OP_PUSH:
948     if (op->operand[0].lmod == OPLM_UNSPEC
949         && (op->operand[0].type == OPT_CONST
950          || op->operand[0].type == OPT_OFFSET
951          || op->operand[0].type == OPT_LABEL))
952       op->operand[0].lmod = OPLM_DWORD;
953     break;
954
955   // alignment
956   case OP_MOV:
957     if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
958      && op->operand[0].reg == xDI && op->operand[1].reg == xDI)
959     {
960       op->flags |= OPF_RMD;
961     }
962     break;
963
964   case OP_LEA:
965     if (op->operand[0].type == OPT_REG
966      && op->operand[1].type == OPT_REGMEM)
967     {
968       char buf[16];
969       snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
970       if (IS(buf, op->operand[1].name))
971         op->flags |= OPF_RMD;
972     }
973     break;
974
975   default:
976     break;
977   }
978 }
979
980 static const char *op_name(enum op_op op)
981 {
982   int i;
983
984   for (i = 0; i < ARRAY_SIZE(op_table); i++)
985     if (op_table[i].op == op)
986       return op_table[i].name;
987
988   return "???";
989 }
990
991 // debug
992 static const char *dump_op(struct parsed_op *po)
993 {
994   static char out[128];
995   char *p = out;
996   int i;
997
998   if (po == NULL)
999     return "???";
1000
1001   snprintf(out, sizeof(out), "%s", op_name(po->op));
1002   for (i = 0; i < po->operand_cnt; i++) {
1003     p += strlen(p);
1004     if (i > 0)
1005       *p++ = ',';
1006     snprintf(p, sizeof(out) - (p - out),
1007       po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1008       po->operand[i].name);
1009   }
1010
1011   return out;
1012 }
1013
1014 static const char *lmod_type_u(struct parsed_op *po,
1015   enum opr_lenmod lmod)
1016 {
1017   switch (lmod) {
1018   case OPLM_DWORD:
1019     return "u32";
1020   case OPLM_WORD:
1021     return "u16";
1022   case OPLM_BYTE:
1023     return "u8";
1024   default:
1025     ferr(po, "invalid lmod: %d\n", lmod);
1026     return "(_invalid_)";
1027   }
1028 }
1029
1030 static const char *lmod_cast_u(struct parsed_op *po,
1031   enum opr_lenmod lmod)
1032 {
1033   switch (lmod) {
1034   case OPLM_DWORD:
1035     return "";
1036   case OPLM_WORD:
1037     return "(u16)";
1038   case OPLM_BYTE:
1039     return "(u8)";
1040   default:
1041     ferr(po, "invalid lmod: %d\n", lmod);
1042     return "(_invalid_)";
1043   }
1044 }
1045
1046 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1047   enum opr_lenmod lmod)
1048 {
1049   switch (lmod) {
1050   case OPLM_DWORD:
1051     return "*(u32 *)";
1052   case OPLM_WORD:
1053     return "*(u16 *)";
1054   case OPLM_BYTE:
1055     return "*(u8 *)";
1056   default:
1057     ferr(po, "invalid lmod: %d\n", lmod);
1058     return "(_invalid_)";
1059   }
1060 }
1061
1062 static const char *lmod_cast_s(struct parsed_op *po,
1063   enum opr_lenmod lmod)
1064 {
1065   switch (lmod) {
1066   case OPLM_DWORD:
1067     return "(s32)";
1068   case OPLM_WORD:
1069     return "(s16)";
1070   case OPLM_BYTE:
1071     return "(s8)";
1072   default:
1073     ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1074     return "(_invalid_)";
1075   }
1076 }
1077
1078 static const char *lmod_cast(struct parsed_op *po,
1079   enum opr_lenmod lmod, int is_signed)
1080 {
1081   return is_signed ?
1082     lmod_cast_s(po, lmod) :
1083     lmod_cast_u(po, lmod);
1084 }
1085
1086 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1087 {
1088   switch (lmod) {
1089   case OPLM_DWORD:
1090     return 4;
1091   case OPLM_WORD:
1092     return 2;
1093   case OPLM_BYTE:
1094     return 1;
1095   default:
1096     ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1097     return 0;
1098   }
1099 }
1100
1101 static const char *opr_name(struct parsed_op *po, int opr_num)
1102 {
1103   if (opr_num >= po->operand_cnt)
1104     ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1105   return po->operand[opr_num].name;
1106 }
1107
1108 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1109 {
1110   if (opr_num >= po->operand_cnt)
1111     ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1112   if (po->operand[opr_num].type != OPT_CONST)
1113     ferr(po, "opr %d: const expected\n", opr_num);
1114   return po->operand[opr_num].val;
1115 }
1116
1117 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1118 {
1119   if ((unsigned int)popr->reg >= MAX_REGS)
1120     ferr(po, "invalid reg: %d\n", popr->reg);
1121   return regs_r32[popr->reg];
1122 }
1123
1124 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1125   int *extra_offs)
1126 {
1127   const char *p;
1128   char *endp;
1129   int namelen;
1130   int i;
1131
1132   *extra_offs = 0;
1133   namelen = strlen(name);
1134
1135   p = strchr(name, '+');
1136   if (p != NULL) {
1137     namelen = p - name;
1138     if (namelen <= 0)
1139       ferr(po, "equ parse failed for '%s'\n", name);
1140
1141     if (IS_START(p, "0x"))
1142       p += 2;
1143     *extra_offs = strtol(p, &endp, 16);
1144     if (*endp != 0)
1145       ferr(po, "equ parse failed for '%s'\n", name);
1146   }
1147
1148   for (i = 0; i < g_eqcnt; i++)
1149     if (strncmp(g_eqs[i].name, name, namelen) == 0
1150      && g_eqs[i].name[namelen] == 0)
1151       break;
1152   if (i >= g_eqcnt) {
1153     if (po != NULL)
1154       ferr(po, "unresolved equ name: '%s'\n", name);
1155     return NULL;
1156   }
1157
1158   return &g_eqs[i];
1159 }
1160
1161 static void stack_frame_access(struct parsed_op *po,
1162   struct parsed_opr *popr, char *buf, size_t buf_size,
1163   const char *name, const char *cast, int is_src, int is_lea)
1164 {
1165   enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1166   const char *prefix = "";
1167   const char *bp_arg = NULL;
1168   char ofs_reg[16] = { 0, };
1169   struct parsed_equ *eq;
1170   const char *p;
1171   char *endp = NULL;
1172   int i, arg_i, arg_s;
1173   int stack_ra = 0;
1174   int offset = 0;
1175   int sf_ofs;
1176   int lim;
1177
1178   if (!IS_START(name, "ebp-")) {
1179     bp_arg = parse_stack_el(name, ofs_reg);
1180     snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1181     eq = equ_find(po, bp_arg, &offset);
1182     if (eq == NULL)
1183       ferr(po, "detected but missing eq\n");
1184     offset += eq->offset;
1185   }
1186   else {
1187     p = name + 4;
1188     if (IS_START(p, "0x"))
1189       p += 2;
1190     offset = -strtoul(p, &endp, 16);
1191     if (*endp != 0)
1192       ferr(po, "ebp- parse of '%s' failed\n", name);
1193   }
1194
1195   if (!strncmp(name, "ebp", 3))
1196     stack_ra = 4;
1197
1198   if (stack_ra <= offset && offset < stack_ra + 4)
1199     ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1200
1201   if (offset > stack_ra)
1202   {
1203     arg_i = (offset - stack_ra - 4) / 4;
1204     if (arg_i < 0 || arg_i >= g_func_pp.argc_stack)
1205     {
1206       if (g_func_pp.is_vararg && arg_i == g_func_pp.argc_stack && is_lea) {
1207         // should be va_list
1208         if (cast[0] == 0)
1209           cast = "(u32)";
1210         snprintf(buf, buf_size, "%sap", cast);
1211         return;
1212       }
1213       ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1214         offset, bp_arg, arg_i);
1215     }
1216     if (ofs_reg[0] != 0)
1217       ferr(po, "offset reg on arg access?\n");
1218
1219     for (i = arg_s = 0; i < g_func_pp.argc; i++) {
1220       if (g_func_pp.arg[i].reg != NULL)
1221         continue;
1222       if (arg_s == arg_i)
1223         break;
1224       arg_s++;
1225     }
1226     if (i == g_func_pp.argc)
1227       ferr(po, "arg %d not in prototype?\n", arg_i);
1228
1229     popr->is_ptr = g_func_pp.arg[i].type.is_ptr;
1230
1231     switch (popr->lmod)
1232     {
1233     case OPLM_BYTE:
1234       if (is_lea)
1235         ferr(po, "lea/byte to arg?\n");
1236       if (is_src && (offset & 3) == 0)
1237         snprintf(buf, buf_size, "(u8)a%d", i + 1);
1238       else
1239         snprintf(buf, buf_size, "BYTE%d(a%d)", offset & 3, i + 1);
1240       break;
1241
1242     case OPLM_WORD:
1243       if (is_lea)
1244         ferr(po, "lea/word to arg?\n");
1245       if (offset & 1)
1246         ferr(po, "unaligned arg access\n");
1247       if (is_src && (offset & 2) == 0)
1248         snprintf(buf, buf_size, "(u16)a%d", i + 1);
1249       else
1250         snprintf(buf, buf_size, "%sWORD(a%d)",
1251           (offset & 2) ? "HI" : "LO", i + 1);
1252       break;
1253
1254     case OPLM_DWORD:
1255       if (cast[0])
1256         prefix = cast;
1257       else if (is_src)
1258         prefix = "(u32)";
1259       if (offset & 3) {
1260         if (is_lea)
1261           ferr(po, "unaligned lea?\n");
1262         snprintf(g_comment, sizeof(g_comment), "%s unaligned", bp_arg);
1263         snprintf(buf, buf_size, "%s(a%d >> %d)",
1264           prefix, i + 1, (offset & 3) * 8);
1265       }
1266       else {
1267         snprintf(buf, buf_size, "%s%sa%d",
1268           prefix, is_lea ? "&" : "", i + 1);
1269       }
1270       break;
1271
1272     default:
1273       ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1274     }
1275
1276     // common problem
1277     guess_lmod_from_c_type(&tmp_lmod, &g_func_pp.arg[i].type);
1278     if ((offset & 3) && tmp_lmod != OPLM_DWORD)
1279       ferr(po, "bp_arg arg/w offset %d and type '%s'\n",
1280         offset, g_func_pp.arg[i].type.name);
1281   }
1282   else
1283   {
1284     if (g_stack_fsz == 0)
1285       ferr(po, "stack var access without stackframe\n");
1286
1287     sf_ofs = g_stack_fsz + offset;
1288     lim = (ofs_reg[0] != 0) ? -4 : 0;
1289     if (offset > 0 || sf_ofs < lim)
1290       ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
1291
1292     if (is_lea)
1293       prefix = "(u32)&";
1294     else
1295       prefix = cast;
1296
1297     switch (popr->lmod)
1298     {
1299     case OPLM_BYTE:
1300       snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1301         prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1302       break;
1303
1304     case OPLM_WORD:
1305       if ((sf_ofs & 1) || ofs_reg[0] != 0) {
1306         // known unaligned or possibly unaligned
1307         strcat(g_comment, " unaligned");
1308         if (prefix[0] == 0)
1309           prefix = "*(u16 *)&";
1310         snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1311           prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1312         break;
1313       }
1314       snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
1315       break;
1316
1317     case OPLM_DWORD:
1318       if ((sf_ofs & 3) || ofs_reg[0] != 0) {
1319         // known unaligned or possibly unaligned
1320         strcat(g_comment, " unaligned");
1321         if (prefix[0] == 0)
1322           prefix = "*(u32 *)&";
1323         snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1324           prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1325         break;
1326       }
1327       snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
1328       break;
1329
1330     default:
1331       ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
1332     }
1333   }
1334 }
1335
1336 static void check_label_read_ref(struct parsed_op *po, const char *name)
1337 {
1338   if (IS_START(name, "sub_"))
1339     ferr(po, "func reference?\n");
1340 }
1341
1342 static char *out_src_opr(char *buf, size_t buf_size,
1343         struct parsed_op *po, struct parsed_opr *popr, const char *cast,
1344   int is_lea)
1345 {
1346   char tmp1[256], tmp2[256];
1347   char expr[256];
1348   int ret;
1349
1350   if (cast == NULL)
1351     cast = "";
1352
1353   switch (popr->type) {
1354   case OPT_REG:
1355     if (is_lea)
1356       ferr(po, "lea from reg?\n");
1357
1358     switch (popr->lmod) {
1359     case OPLM_DWORD:
1360       snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
1361       break;
1362     case OPLM_WORD:
1363       snprintf(buf, buf_size, "(u16)%s", opr_reg_p(po, popr));
1364       break;
1365     case OPLM_BYTE:
1366       if (popr->name[1] == 'h') // XXX..
1367         snprintf(buf, buf_size, "(u8)(%s >> 8)", opr_reg_p(po, popr));
1368       else
1369         snprintf(buf, buf_size, "(u8)%s", opr_reg_p(po, popr));
1370       break;
1371     default:
1372       ferr(po, "invalid src lmod: %d\n", popr->lmod);
1373     }
1374     break;
1375
1376   case OPT_REGMEM:
1377     if (parse_stack_el(popr->name, NULL)
1378       || (g_bp_frame && IS_START(popr->name, "ebp-")))
1379     {
1380       stack_frame_access(po, popr, buf, buf_size,
1381         popr->name, cast, 1, is_lea);
1382       break;
1383     }
1384
1385     strcpy(expr, popr->name);
1386     if (strchr(expr, '[')) {
1387       // special case: '[' can only be left for label[reg] form
1388       ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
1389       if (ret != 2)
1390         ferr(po, "parse failure for '%s'\n", expr);
1391       snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
1392     }
1393
1394     // XXX: do we need more parsing?
1395     if (is_lea) {
1396       snprintf(buf, buf_size, "%s", expr);
1397       break;
1398     }
1399
1400     if (cast[0] == 0)
1401       cast = lmod_cast_u_ptr(po, popr->lmod);
1402     snprintf(buf, buf_size, "%s(%s)", cast, expr);
1403     break;
1404
1405   case OPT_LABEL:
1406     check_label_read_ref(po, popr->name);
1407     if (cast[0] == 0 && popr->is_ptr)
1408       cast = "(u32)";
1409     if (is_lea)
1410       snprintf(buf, buf_size, "(u32)&%s", popr->name);
1411     else
1412       snprintf(buf, buf_size, "%s%s%s", cast, popr->name,
1413         popr->is_array ? "[0]" : "");
1414     break;
1415
1416   case OPT_OFFSET:
1417     check_label_read_ref(po, popr->name);
1418     if (cast[0] == 0)
1419       cast = "(u32)";
1420     if (is_lea)
1421       ferr(po, "lea an offset?\n");
1422     snprintf(buf, buf_size, "%s&%s", cast, popr->name);
1423     break;
1424
1425   case OPT_CONST:
1426     if (is_lea)
1427       ferr(po, "lea from const?\n");
1428
1429     snprintf(buf, buf_size, "%s", cast);
1430     ret = strlen(buf);
1431     printf_number(buf + ret, buf_size - ret, popr->val);
1432     break;
1433
1434   default:
1435     ferr(po, "invalid src type: %d\n", popr->type);
1436   }
1437
1438   return buf;
1439 }
1440
1441 // note: may set is_ptr (we find that out late for ebp frame..)
1442 static char *out_dst_opr(char *buf, size_t buf_size,
1443         struct parsed_op *po, struct parsed_opr *popr)
1444 {
1445   switch (popr->type) {
1446   case OPT_REG:
1447     switch (popr->lmod) {
1448     case OPLM_DWORD:
1449       snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
1450       break;
1451     case OPLM_WORD:
1452       // ugh..
1453       snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
1454       break;
1455     case OPLM_BYTE:
1456       // ugh..
1457       if (popr->name[1] == 'h') // XXX..
1458         snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
1459       else
1460         snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
1461       break;
1462     default:
1463       ferr(po, "invalid dst lmod: %d\n", popr->lmod);
1464     }
1465     break;
1466
1467   case OPT_REGMEM:
1468     if (parse_stack_el(popr->name, NULL)
1469       || (g_bp_frame && IS_START(popr->name, "ebp-")))
1470     {
1471       stack_frame_access(po, popr, buf, buf_size,
1472         popr->name, "", 0, 0);
1473       break;
1474     }
1475
1476     return out_src_opr(buf, buf_size, po, popr, NULL, 0);
1477
1478   case OPT_LABEL:
1479     snprintf(buf, buf_size, "%s%s", popr->name,
1480       popr->is_array ? "[0]" : "");
1481     break;
1482
1483   default:
1484     ferr(po, "invalid dst type: %d\n", popr->type);
1485   }
1486
1487   return buf;
1488 }
1489
1490 static char *out_src_opr_u32(char *buf, size_t buf_size,
1491         struct parsed_op *po, struct parsed_opr *popr)
1492 {
1493   return out_src_opr(buf, buf_size, po, popr, NULL, 0);
1494 }
1495
1496 static enum parsed_flag_op split_cond(struct parsed_op *po,
1497   enum op_op op, int *is_inv)
1498 {
1499   *is_inv = 0;
1500
1501   switch (op) {
1502   case OP_JO:
1503     return PFO_O;
1504   case OP_JC:
1505     return PFO_C;
1506   case OP_JZ:
1507     return PFO_Z;
1508   case OP_JBE:
1509     return PFO_BE;
1510   case OP_JS:
1511     return PFO_S;
1512   case OP_JP:
1513     return PFO_P;
1514   case OP_JL:
1515     return PFO_L;
1516   case OP_JLE:
1517     return PFO_LE;
1518
1519   case OP_JNO:
1520     *is_inv = 1;
1521     return PFO_O;
1522   case OP_JNC:
1523     *is_inv = 1;
1524     return PFO_C;
1525   case OP_JNZ:
1526     *is_inv = 1;
1527     return PFO_Z;
1528   case OP_JA:
1529     *is_inv = 1;
1530     return PFO_BE;
1531   case OP_JNS:
1532     *is_inv = 1;
1533     return PFO_S;
1534   case OP_JNP:
1535     *is_inv = 1;
1536     return PFO_P;
1537   case OP_JGE:
1538     *is_inv = 1;
1539     return PFO_L;
1540   case OP_JG:
1541     *is_inv = 1;
1542     return PFO_LE;
1543
1544   case OP_ADC:
1545   case OP_SBB:
1546     return PFO_C;
1547
1548   default:
1549     ferr(po, "split_cond: bad op %d\n", op);
1550     return -1;
1551   }
1552 }
1553
1554 static void out_test_for_cc(char *buf, size_t buf_size,
1555   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
1556   enum opr_lenmod lmod, const char *expr)
1557 {
1558   const char *cast, *scast;
1559
1560   cast = lmod_cast_u(po, lmod);
1561   scast = lmod_cast_s(po, lmod);
1562
1563   switch (pfo) {
1564   case PFO_Z:
1565   case PFO_BE: // CF=1||ZF=1; CF=0
1566     snprintf(buf, buf_size, "(%s%s %s 0)",
1567       cast, expr, is_inv ? "!=" : "==");
1568     break;
1569
1570   case PFO_S:
1571   case PFO_L: // SF!=OF; OF=0
1572     snprintf(buf, buf_size, "(%s%s %s 0)",
1573       scast, expr, is_inv ? ">=" : "<");
1574     break;
1575
1576   case PFO_LE: // ZF=1||SF!=OF; OF=0
1577     snprintf(buf, buf_size, "(%s%s %s 0)",
1578       scast, expr, is_inv ? ">" : "<=");
1579     break;
1580
1581   default:
1582     ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
1583   }
1584 }
1585
1586 static void out_cmp_for_cc(char *buf, size_t buf_size,
1587   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
1588   enum opr_lenmod lmod, const char *expr1, const char *expr2)
1589 {
1590   const char *cast, *scast;
1591
1592   cast = lmod_cast_u(po, lmod);
1593   scast = lmod_cast_s(po, lmod);
1594
1595   switch (pfo) {
1596   case PFO_C:
1597     // note: must be unsigned compare
1598     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1599       cast, expr1, is_inv ? ">=" : "<", cast, expr2);
1600     break;
1601
1602   case PFO_Z:
1603     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1604       cast, expr1, is_inv ? "!=" : "==", cast, expr2);
1605     break;
1606
1607   case PFO_BE: // !a
1608     // note: must be unsigned compare
1609     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1610       cast, expr1, is_inv ? ">" : "<=", cast, expr2);
1611     break;
1612
1613   // note: must be signed compare
1614   case PFO_S:
1615     snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
1616       scast, expr1, expr2, is_inv ? ">=" : "<");
1617     break;
1618
1619   case PFO_L: // !ge
1620     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1621       scast, expr1, is_inv ? ">=" : "<", scast, expr2);
1622     break;
1623
1624   case PFO_LE:
1625     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1626       scast, expr1, is_inv ? ">" : "<=", scast, expr2);
1627     break;
1628
1629   default:
1630     ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
1631   }
1632 }
1633
1634 static void out_cmp_test(char *buf, size_t buf_size,
1635   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
1636 {
1637   char buf1[256], buf2[256], buf3[256];
1638
1639   if (po->op == OP_TEST) {
1640     if (IS(opr_name(po, 0), opr_name(po, 1))) {
1641       out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
1642     }
1643     else {
1644       out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
1645       out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
1646       snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
1647     }
1648     out_test_for_cc(buf, buf_size, po, pfo, is_inv,
1649       po->operand[0].lmod, buf3);
1650   }
1651   else if (po->op == OP_CMP) {
1652     out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
1653     out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[1]);
1654     out_cmp_for_cc(buf, buf_size, po, pfo, is_inv,
1655       po->operand[0].lmod, buf2, buf3);
1656   }
1657   else
1658     ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
1659 }
1660
1661 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
1662         struct parsed_opr *popr2)
1663 {
1664   if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
1665     ferr(po, "missing lmod for both operands\n");
1666
1667   if (popr1->lmod == OPLM_UNSPEC)
1668     popr1->lmod = popr2->lmod;
1669   else if (popr2->lmod == OPLM_UNSPEC)
1670     popr2->lmod = popr1->lmod;
1671   else if (popr1->lmod != popr2->lmod)
1672     ferr(po, "conflicting lmods: %d vs %d\n", popr1->lmod, popr2->lmod);
1673 }
1674
1675 static const char *op_to_c(struct parsed_op *po)
1676 {
1677   switch (po->op)
1678   {
1679     case OP_ADD:
1680     case OP_ADC:
1681       return "+";
1682     case OP_SUB:
1683     case OP_SBB:
1684       return "-";
1685     case OP_AND:
1686       return "&";
1687     case OP_OR:
1688       return "|";
1689     case OP_XOR:
1690       return "^";
1691     case OP_SHL:
1692       return "<<";
1693     case OP_SHR:
1694       return ">>";
1695     case OP_MUL:
1696     case OP_IMUL:
1697       return "*";
1698     default:
1699       ferr(po, "op_to_c was supplied with %d\n", po->op);
1700   }
1701 }
1702
1703 static void set_flag_no_dup(struct parsed_op *po, enum op_flags flag,
1704   enum op_flags flag_check)
1705 {
1706   if (po->flags & flag)
1707     ferr(po, "flag %x already set\n", flag);
1708   if (po->flags & flag_check)
1709     ferr(po, "flag_check %x already set\n", flag_check);
1710
1711   po->flags |= flag;
1712 }
1713
1714 // last op in stream - unconditional branch or ret
1715 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
1716   || (ops[_i].flags & (OPF_JMP|OPF_CC)) == OPF_JMP)
1717
1718 static int scan_for_pop(int i, int opcnt, const char *reg,
1719   int magic, int depth, int *maxdepth, int do_flags)
1720 {
1721   struct parsed_op *po;
1722   int ret = 0;
1723   int j;
1724
1725   for (; i < opcnt; i++) {
1726     po = &ops[i];
1727     if (po->cc_scratch == magic)
1728       break; // already checked
1729     po->cc_scratch = magic;
1730
1731     if (po->flags & OPF_TAIL)
1732       return -1; // deadend
1733
1734     if ((po->flags & OPF_RMD)
1735         || (po->op == OP_PUSH && po->argnum != 0)) // arg push
1736       continue;
1737
1738     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
1739       if (po->btj != NULL) {
1740         // jumptable
1741         for (j = 0; j < po->btj->count - 1; j++) {
1742           ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, reg, magic,
1743                    depth, maxdepth, do_flags);
1744           if (ret < 0)
1745             return ret; // dead end
1746         }
1747         // follow last jumptable entry
1748         i = po->btj->d[j].bt_i - 1;
1749         continue;
1750       }
1751
1752       if (po->bt_i < 0) {
1753         ferr(po, "dead branch\n");
1754         return -1;
1755       }
1756
1757       if (po->flags & OPF_CC) {
1758         ret |= scan_for_pop(po->bt_i, opcnt, reg, magic,
1759                  depth, maxdepth, do_flags);
1760         if (ret < 0)
1761           return ret; // dead end
1762       }
1763       else {
1764         i = po->bt_i - 1;
1765       }
1766       continue;
1767     }
1768
1769     if ((po->op == OP_POP || po->op == OP_PUSH)
1770         && po->operand[0].type == OPT_REG
1771         && IS(po->operand[0].name, reg))
1772     {
1773       if (po->op == OP_PUSH) {
1774         depth++;
1775         if (depth > *maxdepth)
1776           *maxdepth = depth;
1777         if (do_flags)
1778           set_flag_no_dup(po, OPF_RSAVE, OPF_RMD);
1779       }
1780       else if (depth == 0) {
1781         if (do_flags)
1782           set_flag_no_dup(po, OPF_RMD, OPF_RSAVE);
1783         return 1;
1784       }
1785       else {
1786         depth--;
1787         if (depth < 0) // should not happen
1788           ferr(po, "fail with depth\n");
1789         if (do_flags)
1790           set_flag_no_dup(po, OPF_RSAVE, OPF_RMD);
1791       }
1792     }
1793   }
1794
1795   return ret;
1796 }
1797
1798 // scan for pop starting from 'ret' op (all paths)
1799 static int scan_for_pop_ret(int i, int opcnt, const char *reg,
1800   int flag_set)
1801 {
1802   int found = 0;
1803   int j;
1804
1805   for (; i < opcnt; i++) {
1806     if (!(ops[i].flags & OPF_TAIL))
1807       continue;
1808
1809     for (j = i - 1; j >= 0; j--) {
1810       if (ops[j].flags & OPF_RMD)
1811         continue;
1812       if (ops[j].flags & OPF_JMP)
1813         return -1;
1814
1815       if (ops[j].op == OP_POP && ops[j].operand[0].type == OPT_REG
1816           && IS(ops[j].operand[0].name, reg))
1817       {
1818         found = 1;
1819         ops[j].flags |= flag_set;
1820         break;
1821       }
1822
1823       if (g_labels[j][0] != 0)
1824         return -1;
1825     }
1826   }
1827
1828   return found ? 0 : -1;
1829 }
1830
1831 // is operand 'opr modified' by parsed_op 'po'?
1832 static int is_opr_modified(const struct parsed_opr *opr,
1833   const struct parsed_op *po)
1834 {
1835   if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
1836     return 0;
1837
1838   if (opr->type == OPT_REG && po->operand[0].type == OPT_REG) {
1839     if (po->regmask_dst & (1 << opr->reg))
1840       return 1;
1841     else
1842       return 0;
1843   }
1844
1845   return IS(po->operand[0].name, opr->name);
1846 }
1847
1848 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
1849 static int is_any_opr_modified(const struct parsed_op *po_test,
1850   const struct parsed_op *po)
1851 {
1852   int i;
1853
1854   if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
1855     return 0;
1856
1857   if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
1858     return 0;
1859
1860   if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
1861     return 1;
1862
1863   // in reality, it can wreck any register, but in decompiled C
1864   // version it can only overwrite eax
1865   if (po->op == OP_CALL
1866    && ((po_test->regmask_src | po_test->regmask_dst) & (1 << xAX)))
1867     return 1;
1868
1869   for (i = 0; i < po_test->operand_cnt; i++)
1870     if (IS(po_test->operand[i].name, po->operand[0].name))
1871       return 1;
1872
1873   return 0;
1874 }
1875
1876 // scan for any po_test operand modification in range given
1877 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt)
1878 {
1879   for (; i < opcnt; i++) {
1880     if (is_any_opr_modified(po_test, &ops[i]))
1881       return i;
1882   }
1883
1884   return -1;
1885 }
1886
1887 // scan for po_test operand[0] modification in range given
1888 static int scan_for_mod_opr0(struct parsed_op *po_test,
1889   int i, int opcnt)
1890 {
1891   for (; i < opcnt; i++) {
1892     if (is_opr_modified(&po_test->operand[0], &ops[i]))
1893       return i;
1894   }
1895
1896   return -1;
1897 }
1898
1899 static int scan_for_flag_set(int i, int *branched)
1900 {
1901   *branched = 0;
1902
1903   while (i >= 0) {
1904     if (g_labels[i][0] != 0) {
1905       if (g_label_refs[i].next != NULL)
1906         return -1;
1907       if (i > 0 && LAST_OP(i - 1)) {
1908         i = g_label_refs[i].i;
1909         *branched = 1;
1910         continue;
1911       }
1912     }
1913     i--;
1914
1915     if (ops[i].flags & OPF_FLAGS)
1916       return i;
1917
1918     if ((ops[i].flags & OPF_JMP) && !(ops[i].flags & OPF_CC))
1919       return -1;
1920   }
1921
1922   return -1;
1923 }
1924
1925 // scan back for cdq, if anything modifies edx, fail
1926 static int scan_for_cdq_edx(int i)
1927 {
1928   for (; i >= 0; i--) {
1929     if (ops[i].op == OP_CDQ)
1930       return i;
1931
1932     if (ops[i].regmask_dst & (1 << xDX))
1933       return -1;
1934     if (g_labels[i][0] != 0)
1935       return -1;
1936   }
1937
1938   return -1;
1939 }
1940
1941 static int scan_for_reg_clear(int i, int reg)
1942 {
1943   for (; i >= 0; i--) {
1944     if (ops[i].op == OP_XOR
1945      && ops[i].operand[0].lmod == OPLM_DWORD
1946      && ops[i].operand[0].reg == ops[i].operand[1].reg
1947      && ops[i].operand[0].reg == reg)
1948       return i;
1949
1950     if (ops[i].regmask_dst & (1 << reg))
1951       return -1;
1952     if (g_labels[i][0] != 0)
1953       return -1;
1954   }
1955
1956   return -1;
1957 }
1958
1959 // scan for positive, constant esp adjust
1960 static int scan_for_esp_adjust(int i, int opcnt, int *adj)
1961 {
1962   struct parsed_op *po;
1963   *adj = 0;
1964
1965   for (; i < opcnt; i++) {
1966     po = &ops[i];
1967
1968     if (po->op == OP_ADD && po->operand[0].reg == xSP) {
1969       if (po->operand[1].type != OPT_CONST)
1970         ferr(&ops[i], "non-const esp adjust?\n");
1971       *adj += po->operand[1].val;
1972       if (*adj & 3)
1973         ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
1974       return i;
1975     }
1976     else if (po->op == OP_PUSH)
1977       *adj -= lmod_bytes(po, po->operand[0].lmod);
1978     else if (po->op == OP_POP)
1979       *adj += lmod_bytes(po, po->operand[0].lmod);
1980     else if (po->flags & (OPF_JMP|OPF_TAIL)) {
1981       if (po->op != OP_CALL)
1982         return -1;
1983       if (po->operand[0].type != OPT_LABEL)
1984         return -1;
1985       // TODO: should only allow combining __cdecl calls..
1986     }
1987
1988     if (g_labels[i][0] != 0)
1989       return -1;
1990   }
1991
1992   return -1;
1993 }
1994
1995 static int collect_call_args(struct parsed_op *po, int i,
1996   struct parsed_proto *pp, int *save_arg_vars, int arg,
1997   int need_op_saving, int branched)
1998 {
1999   struct parsed_proto *pp_tmp;
2000   struct label_ref *lr;
2001   int ret = 0;
2002   int j;
2003
2004   if (i < 0)
2005     ferr(po, "no refs for '%s'?\n", g_labels[i]);
2006
2007   for (; arg < pp->argc; arg++)
2008     if (pp->arg[arg].reg == NULL)
2009       break;
2010
2011   for (j = i; j >= 0 && arg < pp->argc; )
2012   {
2013     if (g_labels[j][0] != 0) {
2014       branched = 1;
2015       lr = &g_label_refs[j];
2016       if (lr->next != NULL)
2017         need_op_saving = 1;
2018       for (; lr->next; lr = lr->next)
2019         ret |= collect_call_args(po, lr->i, pp, save_arg_vars,
2020                  arg, need_op_saving, branched);
2021
2022       if (j > 0 && LAST_OP(j - 1)) {
2023         // follow last branch in reverse
2024         j = lr->i;
2025         continue;
2026       }
2027       need_op_saving = 1;
2028       ret |= collect_call_args(po, lr->i, pp, save_arg_vars,
2029                arg, need_op_saving, branched);
2030     }
2031     j--;
2032
2033     if (ops[j].op == OP_CALL)
2034     {
2035       pp_tmp = ops[j].datap;
2036       if (pp_tmp == NULL)
2037         ferr(po, "arg collect hit unparsed call\n");
2038       if (branched && pp_tmp->argc_stack > 0)
2039         ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
2040           arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
2041     }
2042     else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP) {
2043       ferr(po, "arg collect %d/%d hit esp adjust\n",
2044         arg, pp->argc);
2045     }
2046     else if (ops[j].op == OP_POP) {
2047       ferr(po, "arg collect %d/%d hit pop\n", arg, pp->argc);
2048     }
2049     else if (LAST_OP(j)) {
2050       break;
2051     }
2052     else if ((ops[j].flags & (OPF_JMP|OPF_CC)) == (OPF_JMP|OPF_CC))
2053     {
2054       branched = 1;
2055     }
2056     else if (ops[j].op == OP_PUSH && !(ops[j].flags & OPF_FARG))
2057     {
2058       pp->arg[arg].datap = &ops[j];
2059       if (!need_op_saving) {
2060         ret = scan_for_mod(&ops[j], j + 1, i);
2061         need_op_saving = (ret >= 0);
2062       }
2063       if (need_op_saving) {
2064         // mark this push as one that needs operand saving
2065         ops[j].flags &= ~OPF_RMD;
2066         if (ops[j].argnum == 0) {
2067           ops[j].argnum = arg + 1;
2068           *save_arg_vars |= 1 << arg;
2069         }
2070         else if (ops[j].argnum < arg + 1)
2071           ferr(&ops[j], "argnum conflict (%d<%d) for '%s'\n",
2072             ops[j].argnum, arg + 1, pp->name);
2073       }
2074       else if (ops[j].argnum == 0)
2075         ops[j].flags |= OPF_RMD;
2076
2077       // some PUSHes are reused by calls on multiple branches,
2078       // but that can't happen if we didn't branch, so they
2079       // can be removed from future searches (handles nested calls)
2080       if (!branched)
2081         ops[j].flags |= OPF_FARG;
2082
2083       // next arg
2084       for (arg++; arg < pp->argc; arg++)
2085         if (pp->arg[arg].reg == NULL)
2086           break;
2087     }
2088   }
2089
2090   if (arg < pp->argc) {
2091     ferr(po, "arg collect failed for '%s': %d/%d\n",
2092       pp->name, arg, pp->argc);
2093     ret = -1;
2094   }
2095   return ret;
2096 }
2097
2098 static void add_label_ref(struct label_ref *lr, int op_i)
2099 {
2100   struct label_ref *lr_new;
2101
2102   if (lr->i == -1) {
2103     lr->i = op_i;
2104     return;
2105   }
2106
2107   lr_new = calloc(1, sizeof(*lr_new));
2108   lr_new->i = op_i;
2109   lr->next = lr_new;
2110 }
2111
2112 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
2113 {
2114   struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
2115   struct parsed_opr *last_arith_dst = NULL;
2116   char buf1[256], buf2[256], buf3[256], cast[64];
2117   struct parsed_proto *pp, *pp_tmp;
2118   struct parsed_data *pd;
2119   const char *tmpname;
2120   enum parsed_flag_op pfo;
2121   int save_arg_vars = 0;
2122   int cmp_result_vars = 0;
2123   int need_mul_var = 0;
2124   int had_decl = 0;
2125   int branched = 0;
2126   int label_pending = 0;
2127   int regmask_save = 0;
2128   int regmask_arg = 0;
2129   int regmask = 0;
2130   int pfomask = 0;
2131   int found = 0;
2132   int depth = 0;
2133   int no_output;
2134   int i, j, l;
2135   int dummy;
2136   int arg;
2137   int reg;
2138   int ret;
2139
2140   g_bp_frame = g_sp_frame = g_stack_fsz = 0;
2141
2142   ret = proto_parse(fhdr, funcn, &g_func_pp);
2143   if (ret)
2144     ferr(ops, "proto_parse failed for '%s'\n", funcn);
2145
2146   fprintf(fout, "%s ", g_func_pp.ret_type.name);
2147   if (g_ida_func_attr & IDAFA_NORETURN)
2148     fprintf(fout, "noreturn ");
2149   fprintf(fout, "%s(", funcn);
2150   for (i = 0; i < g_func_pp.argc; i++) {
2151     if (i > 0)
2152       fprintf(fout, ", ");
2153     fprintf(fout, "%s a%d", g_func_pp.arg[i].type.name, i + 1);
2154   }
2155   if (g_func_pp.is_vararg) {
2156     if (i > 0)
2157       fprintf(fout, ", ");
2158     fprintf(fout, "...");
2159   }
2160   fprintf(fout, ")\n{\n");
2161
2162   // pass1:
2163   // - handle ebp/esp frame, remove ops related to it
2164   if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
2165       && ops[1].op == OP_MOV
2166       && IS(opr_name(&ops[1], 0), "ebp")
2167       && IS(opr_name(&ops[1], 1), "esp"))
2168   {
2169     int ecx_push = 0;
2170
2171     g_bp_frame = 1;
2172     ops[0].flags |= OPF_RMD;
2173     ops[1].flags |= OPF_RMD;
2174     i = 2;
2175
2176     if (ops[2].op == OP_SUB && IS(opr_name(&ops[2], 0), "esp")) {
2177       g_stack_fsz = opr_const(&ops[2], 1);
2178       ops[2].flags |= OPF_RMD;
2179       i++;
2180     }
2181     else {
2182       // another way msvc builds stack frame..
2183       i = 2;
2184       while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
2185         g_stack_fsz += 4;
2186         ops[i].flags |= OPF_RMD;
2187         ecx_push++;
2188         i++;
2189       }
2190       // and another way..
2191       if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
2192           && ops[i].operand[1].type == OPT_CONST
2193           && ops[i + 1].op == OP_CALL
2194           && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
2195       {
2196         g_stack_fsz += ops[i].operand[1].val;
2197         ops[i].flags |= OPF_RMD;
2198         i++;
2199         ops[i].flags |= OPF_RMD;
2200         i++;
2201       }
2202     }
2203
2204     found = 0;
2205     do {
2206       for (; i < opcnt; i++)
2207         if (ops[i].op == OP_RET)
2208           break;
2209       if (i == opcnt && (ops[i - 1].flags & OPF_JMP) && found)
2210         break;
2211
2212       if (ops[i - 1].op == OP_POP && IS(opr_name(&ops[i - 1], 0), "ebp"))
2213         ops[i - 1].flags |= OPF_RMD;
2214       else if (!(g_ida_func_attr & IDAFA_NORETURN))
2215         ferr(&ops[i - 1], "'pop ebp' expected\n");
2216
2217       if (g_stack_fsz != 0) {
2218         if (ops[i - 2].op == OP_MOV
2219             && IS(opr_name(&ops[i - 2], 0), "esp")
2220             && IS(opr_name(&ops[i - 2], 1), "ebp"))
2221         {
2222           ops[i - 2].flags |= OPF_RMD;
2223         }
2224         else if (!(g_ida_func_attr & IDAFA_NORETURN))
2225           ferr(&ops[i - 2], "esp restore expected\n");
2226
2227         if (ecx_push && ops[i - 3].op == OP_POP
2228           && IS(opr_name(&ops[i - 3], 0), "ecx"))
2229         {
2230           ferr(&ops[i - 3], "unexpected ecx pop\n");
2231         }
2232       }
2233
2234       found = 1;
2235       i++;
2236     } while (i < opcnt);
2237   }
2238   else {
2239     for (i = 0; i < opcnt; i++) {
2240       if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
2241         break;
2242       if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
2243         && ops[i].operand[1].type == OPT_CONST)
2244       {
2245         g_sp_frame = 1;
2246         break;
2247       }
2248     }
2249
2250     if (g_sp_frame)
2251     {
2252       g_stack_fsz = ops[i].operand[1].val;
2253       ops[i].flags |= OPF_RMD;
2254
2255       i++;
2256       do {
2257         for (; i < opcnt; i++)
2258           if (ops[i].op == OP_RET)
2259             break;
2260         if (ops[i - 1].op != OP_ADD
2261             || !IS(opr_name(&ops[i - 1], 0), "esp")
2262             || ops[i - 1].operand[1].type != OPT_CONST
2263             || ops[i - 1].operand[1].val != g_stack_fsz)
2264           ferr(&ops[i - 1], "'add esp' expected\n");
2265         ops[i - 1].flags |= OPF_RMD;
2266
2267         i++;
2268       } while (i < opcnt);
2269     }
2270   }
2271
2272   // pass2:
2273   // - resolve all branches
2274   for (i = 0; i < opcnt; i++)
2275   {
2276     po = &ops[i];
2277     po->bt_i = -1;
2278     po->btj = NULL;
2279
2280     if ((po->flags & OPF_RMD) || !(po->flags & OPF_JMP)
2281         || po->op == OP_CALL || po->op == OP_RET)
2282       continue;
2283
2284     if (po->operand[0].type == OPT_REGMEM) {
2285       char *p = strchr(po->operand[0].name, '[');
2286       if (p == NULL)
2287         ferr(po, "unhandled indirect branch\n");
2288       ret = p - po->operand[0].name;
2289       strncpy(buf1, po->operand[0].name, ret);
2290       buf1[ret] = 0;
2291
2292       for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
2293         if (IS(g_func_pd[j].label, buf1)) {
2294           pd = &g_func_pd[j];
2295           break;
2296         }
2297       }
2298       if (pd == NULL)
2299         ferr(po, "label '%s' not parsed?\n", buf1);
2300       if (pd->type != OPT_OFFSET)
2301         ferr(po, "label '%s' with non-offset data?\n", buf1);
2302
2303       // find all labels, link
2304       for (j = 0; j < pd->count; j++) {
2305         for (l = 0; l < opcnt; l++) {
2306           if (g_labels[l][0] && IS(g_labels[l], pd->d[j].u.label)) {
2307             add_label_ref(&g_label_refs[l], i);
2308             pd->d[j].bt_i = l;
2309             break;
2310           }
2311         }
2312       }
2313
2314       po->btj = pd;
2315       continue;
2316     }
2317
2318     for (l = 0; l < opcnt; l++) {
2319       if (g_labels[l][0] && IS(po->operand[0].name, g_labels[l])) {
2320         add_label_ref(&g_label_refs[l], i);
2321         po->bt_i = l;
2322         break;
2323       }
2324     }
2325
2326     if (po->bt_i != -1)
2327       continue;
2328
2329     if (po->operand[0].type == OPT_LABEL) {
2330       // assume tail call
2331       po->op = OP_CALL;
2332       po->flags |= OPF_TAIL;
2333       continue;
2334     }
2335
2336     ferr(po, "unhandled branch\n");
2337   }
2338
2339   // pass3:
2340   // - process calls
2341   for (i = 0; i < opcnt; i++)
2342   {
2343     po = &ops[i];
2344     if (po->flags & OPF_RMD)
2345       continue;
2346
2347     if (po->op == OP_CALL)
2348     {
2349       pp = calloc(1, sizeof(*pp));
2350       my_assert_not(pp, NULL);
2351       tmpname = opr_name(po, 0);
2352       if (po->operand[0].type != OPT_LABEL)
2353       {
2354         ret = scan_for_esp_adjust(i + 1, opcnt, &j);
2355         if (ret < 0)
2356           ferr(po, "non-__cdecl indirect call unhandled yet\n");
2357         j /= 4;
2358         if (j > ARRAY_SIZE(pp->arg))
2359           ferr(po, "esp adjust too large?\n");
2360         pp->ret_type.name = strdup("int");
2361         pp->argc = pp->argc_stack = j;
2362         for (arg = 0; arg < pp->argc; arg++)
2363           pp->arg[arg].type.name = strdup("int");
2364       }
2365       else {
2366         ret = proto_parse(fhdr, tmpname, pp);
2367         if (ret)
2368           ferr(po, "proto_parse failed for call '%s'\n", tmpname);
2369       }
2370
2371       // look for and make use of esp adjust
2372       ret = -1;
2373       if (!pp->is_stdcall && pp->argc_stack > 0)
2374         ret = scan_for_esp_adjust(i + 1, opcnt, &j);
2375       if (ret >= 0) {
2376         if (pp->is_vararg) {
2377           if (j / 4 < pp->argc_stack)
2378             ferr(po, "esp adjust is too small: %x < %x\n",
2379               j, pp->argc_stack * 4);
2380           // modify pp to make it have varargs as normal args
2381           arg = pp->argc;
2382           pp->argc += j / 4 - pp->argc_stack;
2383           for (; arg < pp->argc; arg++) {
2384             pp->arg[arg].type.name = strdup("int");
2385             pp->argc_stack++;
2386           }
2387           if (pp->argc > ARRAY_SIZE(pp->arg))
2388             ferr(po, "too many args for '%s'\n", tmpname);
2389         }
2390         if (pp->argc_stack != j / 4)
2391           ferr(po, "stack tracking failed for '%s': %x %x\n",
2392             tmpname, pp->argc_stack * 4, j);
2393
2394         ops[ret].flags |= OPF_RMD;
2395         // a bit of a hack, but deals with use of
2396         // single adj for multiple calls
2397         ops[ret].operand[1].val -= j;
2398       }
2399       else if (pp->is_vararg)
2400         ferr(po, "missing esp_adjust for vararg func '%s'\n",
2401           pp->name);
2402
2403       // can't call functions with non-__cdecl callbacks yet
2404       for (arg = 0; arg < pp->argc; arg++) {
2405         if (pp->arg[arg].fptr != NULL) {
2406           pp_tmp = pp->arg[arg].fptr;
2407           if (pp_tmp->is_stdcall || pp_tmp->argc != pp_tmp->argc_stack)
2408             ferr(po, "'%s' has a non-__cdecl callback\n", tmpname);
2409         }
2410       }
2411
2412       collect_call_args(po, i, pp, &save_arg_vars, 0, 0, 0);
2413       po->datap = pp;
2414     }
2415   }
2416
2417   // pass4:
2418   // - find POPs for PUSHes, rm both
2419   // - scan for all used registers
2420   // - find flag set ops for their users
2421   // - declare indirect functions
2422   for (i = 0; i < opcnt; i++) {
2423     po = &ops[i];
2424     if (po->flags & OPF_RMD)
2425       continue;
2426
2427     if (po->op == OP_PUSH
2428         && po->argnum == 0 && !(po->flags & OPF_RSAVE)
2429         && po->operand[0].type == OPT_REG)
2430     {
2431       reg = po->operand[0].reg;
2432       if (reg < 0)
2433         ferr(po, "reg not set for push?\n");
2434
2435       depth = 0;
2436       ret = scan_for_pop(i + 1, opcnt,
2437               po->operand[0].name, i + opcnt, 0, &depth, 0);
2438       if (ret == 1) {
2439         if (depth > 1)
2440           ferr(po, "too much depth: %d\n", depth);
2441         if (depth > 0)
2442           regmask_save |= 1 << reg;
2443
2444         po->flags |= OPF_RMD;
2445         scan_for_pop(i + 1, opcnt, po->operand[0].name,
2446           i + opcnt * 2, 0, &depth, 1);
2447         continue;
2448       }
2449       ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].name, 0);
2450       if (ret == 0) {
2451         arg = OPF_RMD;
2452         if (regmask & (1 << reg)) {
2453           if (regmask_save & (1 << reg))
2454             ferr(po, "%s already saved?\n", po->operand[0].name);
2455           arg = OPF_RSAVE;
2456         }
2457         po->flags |= arg;
2458         scan_for_pop_ret(i + 1, opcnt, po->operand[0].name, arg);
2459         continue;
2460       }
2461     }
2462
2463     regmask |= po->regmask_src | po->regmask_dst;
2464
2465     if (po->flags & OPF_CC)
2466     {
2467       ret = scan_for_flag_set(i, &branched);
2468       if (ret < 0)
2469         ferr(po, "unable to trace flag setter\n");
2470
2471       tmp_op = &ops[ret]; // flag setter
2472       pfo = split_cond(po, po->op, &dummy);
2473       pfomask = 0;
2474
2475       // to get nicer code, we try to delay test and cmp;
2476       // if we can't because of operand modification, or if we
2477       // have math op, or branch, make it calculate flags explicitly
2478       if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP) {
2479         if (branched || scan_for_mod(tmp_op, ret + 1, i) >= 0)
2480           pfomask = 1 << pfo;
2481       }
2482       else if (tmp_op->op == OP_CMPS) {
2483         pfomask = 1 << PFO_Z;
2484       }
2485       else {
2486         if ((pfo != PFO_Z && pfo != PFO_S && pfo != PFO_P)
2487             || scan_for_mod_opr0(tmp_op, ret + 1, i) >= 0)
2488           pfomask = 1 << pfo;
2489       }
2490       if (pfomask) {
2491         tmp_op->pfomask |= pfomask;
2492         cmp_result_vars |= pfomask;
2493         po->datap = tmp_op;
2494       }
2495
2496       if (po->op == OP_ADC || po->op == OP_SBB)
2497         cmp_result_vars |= 1 << PFO_C;
2498     }
2499     else if (po->op == OP_MUL
2500       || (po->op == OP_IMUL && po->operand_cnt == 1))
2501     {
2502       need_mul_var = 1;
2503     }
2504     else if (po->op == OP_CALL && po->operand[0].type != OPT_LABEL) {
2505       pp = po->datap;
2506       my_assert_not(pp, NULL);
2507       fprintf(fout, "  %s (*icall%d)(", pp->ret_type.name, i);
2508       for (j = 0; j < pp->argc; j++) {
2509         if (j > 0)
2510           fprintf(fout, ", ");
2511         fprintf(fout, "%s a%d", pp->arg[j].type.name, j + 1);
2512       }
2513       fprintf(fout, ");\n");
2514     }
2515   }
2516
2517   // output LUTs/jumptables
2518   for (i = 0; i < g_func_pd_cnt; i++) {
2519     pd = &g_func_pd[i];
2520     fprintf(fout, "  static const ");
2521     if (pd->type == OPT_OFFSET) {
2522       fprintf(fout, "void *jt_%s[] =\n    { ", pd->label);
2523
2524       for (j = 0; j < pd->count; j++) {
2525         if (j > 0)
2526           fprintf(fout, ", ");
2527         fprintf(fout, "&&%s", pd->d[j].u.label);
2528       }
2529     }
2530     else {
2531       fprintf(fout, "%s %s[] =\n    { ",
2532         lmod_type_u(ops, pd->lmod), pd->label);
2533
2534       for (j = 0; j < pd->count; j++) {
2535         if (j > 0)
2536           fprintf(fout, ", ");
2537         fprintf(fout, "%u", pd->d[j].u.val);
2538       }
2539     }
2540     fprintf(fout, " };\n");
2541   }
2542
2543   // declare stack frame, va_arg
2544   if (g_stack_fsz)
2545     fprintf(fout, "  union { u32 d[%d]; u16 w[%d]; u8 b[%d]; } sf;\n",
2546       (g_stack_fsz + 3) / 4, (g_stack_fsz + 1) / 2, g_stack_fsz);
2547
2548   if (g_func_pp.is_vararg)
2549     fprintf(fout, "  va_list ap;\n");
2550
2551   // declare arg-registers
2552   for (i = 0; i < g_func_pp.argc; i++) {
2553     if (g_func_pp.arg[i].reg != NULL) {
2554       reg = char_array_i(regs_r32,
2555               ARRAY_SIZE(regs_r32), g_func_pp.arg[i].reg);
2556       if (reg < 0)
2557         ferr(ops, "arg '%s' is not a reg?\n", g_func_pp.arg[i].reg);
2558
2559       regmask_arg |= 1 << reg;
2560       fprintf(fout, "  u32 %s = (u32)a%d;\n",
2561         g_func_pp.arg[i].reg, i + 1);
2562       had_decl = 1;
2563     }
2564   }
2565
2566   // declare other regs - special case for eax
2567   if (!((regmask | regmask_arg) & 1)
2568    && !IS(g_func_pp.ret_type.name, "void"))
2569   {
2570     fprintf(fout, "  u32 eax = 0;\n");
2571     had_decl = 1;
2572   }
2573
2574   regmask &= ~regmask_arg;
2575   regmask &= ~(1 << xSP);
2576   if (g_bp_frame)
2577     regmask &= ~(1 << xBP);
2578   if (regmask) {
2579     for (reg = 0; reg < 8; reg++) {
2580       if (regmask & (1 << reg)) {
2581         fprintf(fout, "  u32 %s;\n", regs_r32[reg]);
2582         had_decl = 1;
2583       }
2584     }
2585   }
2586
2587   if (regmask_save) {
2588     for (reg = 0; reg < 8; reg++) {
2589       if (regmask_save & (1 << reg)) {
2590         fprintf(fout, "  u32 s_%s;\n", regs_r32[reg]);
2591         had_decl = 1;
2592       }
2593     }
2594   }
2595
2596   if (save_arg_vars) {
2597     for (reg = 0; reg < 32; reg++) {
2598       if (save_arg_vars & (1 << reg)) {
2599         fprintf(fout, "  u32 s_a%d;\n", reg + 1);
2600         had_decl = 1;
2601       }
2602     }
2603   }
2604
2605   if (cmp_result_vars) {
2606     for (i = 0; i < 8; i++) {
2607       if (cmp_result_vars & (1 << i)) {
2608         fprintf(fout, "  u32 cond_%s;\n", parsed_flag_op_names[i]);
2609         had_decl = 1;
2610       }
2611     }
2612   }
2613
2614   if (need_mul_var) {
2615     fprintf(fout, "  u64 mul_tmp;\n");
2616     had_decl = 1;
2617   }
2618
2619   if (had_decl)
2620     fprintf(fout, "\n");
2621
2622   if (g_func_pp.is_vararg) {
2623     if (g_func_pp.argc_stack == 0)
2624       ferr(ops, "vararg func without stack args?\n");
2625     fprintf(fout, "  va_start(ap, a%d);\n", g_func_pp.argc);
2626   }
2627
2628   // output ops
2629   for (i = 0; i < opcnt; i++)
2630   {
2631     if (g_labels[i][0] != 0 && g_label_refs[i].i != -1) {
2632       fprintf(fout, "\n%s:\n", g_labels[i]);
2633       label_pending = 1;
2634     }
2635
2636     po = &ops[i];
2637     if (po->flags & OPF_RMD)
2638       continue;
2639
2640     no_output = 0;
2641
2642     #define assert_operand_cnt(n_) \
2643       if (po->operand_cnt != n_) \
2644         ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
2645
2646     // conditional/flag using op?
2647     if (po->flags & OPF_CC)
2648     {
2649       int is_delayed = 0;
2650       int is_inv = 0;
2651
2652       pfo = split_cond(po, po->op, &is_inv);
2653
2654       // we go through all this trouble to avoid using parsed_flag_op,
2655       // which makes generated code much nicer
2656       if (delayed_flag_op != NULL)
2657       {
2658         out_cmp_test(buf1, sizeof(buf1), delayed_flag_op, pfo, is_inv);
2659         is_delayed = 1;
2660       }
2661       else if (last_arith_dst != NULL
2662         && (pfo == PFO_Z || pfo == PFO_S || pfo == PFO_P))
2663       {
2664         out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
2665         out_test_for_cc(buf1, sizeof(buf1), po, pfo, is_inv,
2666           last_arith_dst->lmod, buf3);
2667         is_delayed = 1;
2668       }
2669       else if (po->datap != NULL) {
2670         // use preprocessed flag calc results
2671         tmp_op = po->datap;
2672         if (!tmp_op || !(tmp_op->pfomask & (1 << pfo)))
2673           ferr(po, "not prepared for pfo %d\n", pfo);
2674
2675         // note: is_inv was not yet applied
2676         snprintf(buf1, sizeof(buf1), "(%scond_%s)",
2677           is_inv ? "!" : "", parsed_flag_op_names[pfo]);
2678       }
2679       else {
2680         ferr(po, "all methods of finding comparison failed\n");
2681       }
2682  
2683       if (po->flags & OPF_JMP) {
2684         fprintf(fout, "  if %s\n", buf1);
2685       }
2686       else if (po->op == OP_ADC || po->op == OP_SBB) {
2687         if (is_delayed)
2688           fprintf(fout, "  cond_%s = %s;\n",
2689             parsed_flag_op_names[pfo], buf1);
2690       }
2691       else if (po->flags & OPF_DATA) { // SETcc
2692         out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
2693         fprintf(fout, "  %s = %s;", buf2, buf1);
2694       }
2695       else {
2696         ferr(po, "unhandled conditional op\n");
2697       }
2698     }
2699
2700     pfomask = po->pfomask;
2701
2702     switch (po->op)
2703     {
2704       case OP_MOV:
2705         assert_operand_cnt(2);
2706         propagate_lmod(po, &po->operand[0], &po->operand[1]);
2707         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
2708         fprintf(fout, "  %s = %s;", buf1,
2709             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
2710               po->operand[0].is_ptr ? "(void *)" : "", 0));
2711         break;
2712
2713       case OP_LEA:
2714         assert_operand_cnt(2);
2715         po->operand[1].lmod = OPLM_DWORD; // always
2716         fprintf(fout, "  %s = %s;",
2717             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
2718             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
2719               NULL, 1));
2720         break;
2721
2722       case OP_MOVZX:
2723         assert_operand_cnt(2);
2724         fprintf(fout, "  %s = %s;",
2725             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
2726             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
2727         break;
2728
2729       case OP_MOVSX:
2730         assert_operand_cnt(2);
2731         switch (po->operand[1].lmod) {
2732         case OPLM_BYTE:
2733           strcpy(buf3, "(s8)");
2734           break;
2735         case OPLM_WORD:
2736           strcpy(buf3, "(s16)");
2737           break;
2738         default:
2739           ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
2740         }
2741         fprintf(fout, "  %s = %s%s;",
2742             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
2743             buf3,
2744             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
2745         break;
2746
2747       case OP_NOT:
2748         assert_operand_cnt(1);
2749         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
2750         fprintf(fout, "  %s = ~%s;", buf1, buf1);
2751         break;
2752
2753       case OP_CDQ:
2754         assert_operand_cnt(2);
2755         fprintf(fout, "  %s = (s32)%s >> 31;",
2756             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
2757             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
2758         strcpy(g_comment, "cdq");
2759         break;
2760
2761       case OP_STOS:
2762         // assumes DF=0
2763         assert_operand_cnt(3);
2764         if (po->flags & OPF_REP) {
2765           fprintf(fout, "  for (; ecx != 0; ecx--, edi += %d)\n",
2766             lmod_bytes(po, po->operand[0].lmod));
2767           fprintf(fout, "    %sedi = eax;",
2768             lmod_cast_u_ptr(po, po->operand[0].lmod));
2769           strcpy(g_comment, "rep stos");
2770         }
2771         else {
2772           fprintf(fout, "    %sedi = eax; edi += %d;",
2773             lmod_cast_u_ptr(po, po->operand[0].lmod),
2774             lmod_bytes(po, po->operand[0].lmod));
2775           strcpy(g_comment, "stos");
2776         }
2777         break;
2778
2779       case OP_MOVS:
2780         // assumes DF=0
2781         assert_operand_cnt(3);
2782         j = lmod_bytes(po, po->operand[0].lmod);
2783         strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
2784         if (po->flags & OPF_REP) {
2785           fprintf(fout,
2786             "  for (; ecx != 0; ecx--, edi += %d, esi += %d)\n",
2787             j, j);
2788           fprintf(fout,
2789             "    %sedi = %sesi;", buf1, buf1);
2790           strcpy(g_comment, "rep movs");
2791         }
2792         else {
2793           fprintf(fout, "    %sedi = %sesi; edi += %d; esi += %d;",
2794             buf1, buf1, j, j);
2795           strcpy(g_comment, "movs");
2796         }
2797         break;
2798
2799       case OP_CMPS:
2800         // assumes DF=0
2801         // repe ~ repeat while ZF=1
2802         assert_operand_cnt(3);
2803         j = lmod_bytes(po, po->operand[0].lmod);
2804         strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
2805         if (po->flags & OPF_REP) {
2806           fprintf(fout,
2807             "  for (; ecx != 0; ecx--, edi += %d, esi += %d)\n",
2808             j, j);
2809           fprintf(fout,
2810             "    if ((cond_z = (%sedi == %sesi)) %s 0)\n",
2811               buf1, buf1, (po->flags & OPF_REPZ) ? "==" : "!=");
2812           fprintf(fout,
2813             "      break;");
2814           snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
2815             (po->flags & OPF_REPZ) ? "e" : "ne");
2816         }
2817         else {
2818           fprintf(fout,
2819             "    cond_z = (%sedi = %sesi); edi += %d; esi += %d;",
2820             buf1, buf1, j, j);
2821           strcpy(g_comment, "cmps");
2822         }
2823         pfomask &= ~(1 << PFO_Z);
2824         last_arith_dst = NULL;
2825         delayed_flag_op = NULL;
2826         break;
2827
2828       // arithmetic w/flags
2829       case OP_ADD:
2830       case OP_SUB:
2831       case OP_AND:
2832       case OP_OR:
2833         propagate_lmod(po, &po->operand[0], &po->operand[1]);
2834         // fallthrough
2835       case OP_SHL:
2836       case OP_SHR:
2837       dualop_arith:
2838         assert_operand_cnt(2);
2839         fprintf(fout, "  %s %s= %s;",
2840             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
2841             op_to_c(po),
2842             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
2843         last_arith_dst = &po->operand[0];
2844         delayed_flag_op = NULL;
2845         break;
2846
2847       case OP_SAR:
2848         assert_operand_cnt(2);
2849         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
2850         fprintf(fout, "  %s = %s%s >> %s;", buf1,
2851           lmod_cast_s(po, po->operand[0].lmod), buf1,
2852           out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
2853         last_arith_dst = &po->operand[0];
2854         delayed_flag_op = NULL;
2855         break;
2856
2857       case OP_ROL:
2858       case OP_ROR:
2859         assert_operand_cnt(2);
2860         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
2861         if (po->operand[1].type == OPT_CONST) {
2862           j = po->operand[1].val;
2863           j %= lmod_bytes(po, po->operand[0].lmod) * 8;
2864           fprintf(fout, po->op == OP_ROL ?
2865             "  %s = (%s << %d) | (%s >> %d);" :
2866             "  %s = (%s >> %d) | (%s << %d);",
2867             buf1, buf1, j, buf1,
2868             lmod_bytes(po, po->operand[0].lmod) * 8 - j);
2869         }
2870         else
2871           ferr(po, "TODO\n");
2872         last_arith_dst = &po->operand[0];
2873         delayed_flag_op = NULL;
2874         break;
2875
2876       case OP_XOR:
2877         assert_operand_cnt(2);
2878         propagate_lmod(po, &po->operand[0], &po->operand[1]);
2879         if (IS(opr_name(po, 0), opr_name(po, 1))) {
2880           // special case for XOR
2881           fprintf(fout, "  %s = 0;",
2882             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
2883           last_arith_dst = &po->operand[0];
2884           delayed_flag_op = NULL;
2885           break;
2886         }
2887         goto dualop_arith;
2888
2889       case OP_ADC:
2890       case OP_SBB:
2891         assert_operand_cnt(2);
2892         propagate_lmod(po, &po->operand[0], &po->operand[1]);
2893         fprintf(fout, "  %s %s= %s + cond_c;",
2894             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
2895             op_to_c(po),
2896             out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
2897         last_arith_dst = &po->operand[0];
2898         delayed_flag_op = NULL;
2899         break;
2900
2901       case OP_INC:
2902       case OP_DEC:
2903         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
2904         if (po->operand[0].type == OPT_REG) {
2905           strcpy(buf2, po->op == OP_INC ? "++" : "--");
2906           fprintf(fout, "  %s%s;", buf1, buf2);
2907         }
2908         else {
2909           strcpy(buf2, po->op == OP_INC ? "+" : "-");
2910           fprintf(fout, "  %s %s= 1;", buf1, buf2);
2911         }
2912         last_arith_dst = &po->operand[0];
2913         delayed_flag_op = NULL;
2914         break;
2915
2916       case OP_NEG:
2917         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
2918         out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
2919         fprintf(fout, "  %s = -%s%s;", buf1,
2920           lmod_cast_s(po, po->operand[0].lmod), buf2);
2921         last_arith_dst = &po->operand[0];
2922         delayed_flag_op = NULL;
2923         if (pfomask & (1 << PFO_C)) {
2924           fprintf(fout, "\n  cond_c = (%s != 0);", buf1);
2925           pfomask &= ~(1 << PFO_C);
2926         }
2927         break;
2928
2929       case OP_IMUL:
2930         if (po->operand_cnt == 2) {
2931           propagate_lmod(po, &po->operand[0], &po->operand[1]);
2932           goto dualop_arith;
2933         }
2934         if (po->operand_cnt == 3)
2935           ferr(po, "TODO imul3\n");
2936         // fallthrough
2937       case OP_MUL:
2938         assert_operand_cnt(1);
2939         strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
2940         fprintf(fout, "  mul_tmp = %seax * %s%s;\n", buf1, buf1,
2941           out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
2942         fprintf(fout, "  edx = mul_tmp >> 32;\n");
2943         fprintf(fout, "  eax = mul_tmp;");
2944         last_arith_dst = NULL;
2945         delayed_flag_op = NULL;
2946         break;
2947
2948       case OP_DIV:
2949       case OP_IDIV:
2950         assert_operand_cnt(1);
2951         if (po->operand[0].lmod != OPLM_DWORD)
2952           ferr(po, "unhandled lmod %d\n", po->operand[0].lmod);
2953
2954         // 32bit division is common, look for it
2955         if (po->op == OP_DIV)
2956           ret = scan_for_reg_clear(i - 1, xDX);
2957         else
2958           ret = scan_for_cdq_edx(i - 1);
2959         if (ret >= 0) {
2960           out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2961           strcpy(buf2, lmod_cast(po, po->operand[0].lmod,
2962             po->op == OP_IDIV));
2963           fprintf(fout, "  edx = %seax %% %s%s;\n", buf2, buf2, buf1);
2964           fprintf(fout, "  eax = %seax / %s%s;", buf2, buf2, buf1);
2965         }
2966         else
2967           ferr(po, "TODO 64bit divident\n");
2968         last_arith_dst = NULL;
2969         delayed_flag_op = NULL;
2970         break;
2971
2972       case OP_TEST:
2973       case OP_CMP:
2974         propagate_lmod(po, &po->operand[0], &po->operand[1]);
2975         if (pfomask != 0) {
2976           for (j = 0; j < 8; j++) {
2977             if (pfomask & (1 << j)) {
2978               out_cmp_test(buf1, sizeof(buf1), po, j, 0);
2979               fprintf(fout, "  cond_%s = %s;",
2980                 parsed_flag_op_names[j], buf1);
2981             }
2982           }
2983           pfomask = 0;
2984         }
2985         else
2986           no_output = 1;
2987         last_arith_dst = NULL;
2988         delayed_flag_op = po;
2989         break;
2990
2991       // note: we reuse OP_Jcc for SETcc, only flags differ
2992       case OP_JO ... OP_JG:
2993         if (po->flags & OPF_JMP)
2994           fprintf(fout, "    goto %s;", po->operand[0].name);
2995         // else SETcc - should already be handled
2996         break;
2997
2998       case OP_JMP:
2999         assert_operand_cnt(1);
3000         last_arith_dst = NULL;
3001         delayed_flag_op = NULL;
3002
3003         if (po->operand[0].type == OPT_REGMEM) {
3004           ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
3005                   buf1, buf2);
3006           if (ret != 2)
3007             ferr(po, "parse failure for jmp '%s'\n",
3008               po->operand[0].name);
3009           fprintf(fout, "  goto *jt_%s[%s];", buf1, buf2);
3010           break;
3011         }
3012         else if (po->operand[0].type != OPT_LABEL)
3013           ferr(po, "unhandled jmp type\n");
3014
3015         fprintf(fout, "  goto %s;", po->operand[0].name);
3016         break;
3017
3018       case OP_CALL:
3019         assert_operand_cnt(1);
3020         pp = po->datap;
3021         if (pp == NULL)
3022           ferr(po, "NULL pp\n");
3023
3024         if (po->operand[0].type != OPT_LABEL)
3025           fprintf(fout, "  icall%d = (void *)%s;\n", i,
3026             out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]));
3027
3028         fprintf(fout, "  ");
3029         if (!IS(pp->ret_type.name, "void")) {
3030           if (po->flags & OPF_TAIL)
3031             fprintf(fout, "return ");
3032           else
3033             fprintf(fout, "eax = ");
3034           if (pp->ret_type.is_ptr)
3035             fprintf(fout, "(u32)");
3036         }
3037
3038         if (po->operand[0].type != OPT_LABEL) {
3039           fprintf(fout, "icall%d(", i);
3040         }
3041         else {
3042           if (pp->name[0] == 0)
3043             ferr(po, "missing pp->name\n");
3044           fprintf(fout, "%s(", pp->name);
3045         }
3046
3047         for (arg = 0; arg < pp->argc; arg++) {
3048           if (arg > 0)
3049             fprintf(fout, ", ");
3050
3051           cast[0] = 0;
3052           if (pp->arg[arg].type.is_ptr)
3053             snprintf(cast, sizeof(cast), "(%s)", pp->arg[arg].type.name);
3054
3055           if (pp->arg[arg].reg != NULL) {
3056             fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
3057             continue;
3058           }
3059
3060           // stack arg
3061           tmp_op = pp->arg[arg].datap;
3062           if (tmp_op == NULL)
3063             ferr(po, "parsed_op missing for arg%d\n", arg);
3064           if (tmp_op->argnum != 0) {
3065             fprintf(fout, "%ss_a%d", cast, tmp_op->argnum);
3066           }
3067           else {
3068             fprintf(fout, "%s",
3069               out_src_opr(buf1, sizeof(buf1),
3070                 tmp_op, &tmp_op->operand[0], cast, 0));
3071           }
3072         }
3073         fprintf(fout, ");");
3074
3075         if (po->flags & OPF_TAIL) {
3076           strcpy(g_comment, "tailcall");
3077           if (IS(pp->ret_type.name, "void")
3078            && !(g_ida_func_attr & IDAFA_NORETURN))
3079           {
3080             fprintf(fout, "\n  return;");
3081             strcpy(g_comment, "^ tailcall");
3082           }
3083         }
3084         delayed_flag_op = NULL;
3085         last_arith_dst = NULL;
3086         break;
3087
3088       case OP_RET:
3089         if (g_func_pp.is_vararg)
3090           fprintf(fout, "  va_end(ap);\n");
3091  
3092         if (IS(g_func_pp.ret_type.name, "void")) {
3093           if (i != opcnt - 1 || label_pending)
3094             fprintf(fout, "  return;");
3095         }
3096         else if (g_func_pp.ret_type.is_ptr) {
3097           fprintf(fout, "  return (%s)eax;",
3098             g_func_pp.ret_type.name);
3099         }
3100         else
3101           fprintf(fout, "  return eax;");
3102
3103         last_arith_dst = NULL;
3104         delayed_flag_op = NULL;
3105         break;
3106
3107       case OP_PUSH:
3108         if (po->argnum != 0) {
3109           // special case - saved func arg
3110           out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
3111           fprintf(fout, "  s_a%d = %s;", po->argnum, buf1);
3112           break;
3113         }
3114         else if (po->flags & OPF_RSAVE) {
3115           out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
3116           fprintf(fout, "  s_%s = %s;", buf1, buf1);
3117           break;
3118         }
3119         if (!(g_ida_func_attr & IDAFA_NORETURN))
3120           ferr(po, "stray push encountered\n");
3121         no_output = 1;
3122         break;
3123
3124       case OP_POP:
3125         if (po->flags & OPF_RSAVE) {
3126           out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
3127           fprintf(fout, "  %s = s_%s;", buf1, buf1);
3128           break;
3129         }
3130         ferr(po, "stray pop encountered\n");
3131         break;
3132
3133       case OP_NOP:
3134         break;
3135
3136       default:
3137         no_output = 1;
3138         ferr(po, "unhandled op type %d, flags %x\n",
3139           po->op, po->flags);
3140         break;
3141     }
3142
3143     // some sanity checking
3144     if ((po->flags & OPF_REP) && po->op != OP_STOS
3145         && po->op != OP_MOVS && po->op != OP_CMPS)
3146       ferr(po, "unexpected rep\n");
3147     if ((po->flags & (OPF_REPZ|OPF_REPNZ)) && po->op != OP_CMPS)
3148       ferr(po, "unexpected repz/repnz\n");
3149
3150     if (g_comment[0] != 0) {
3151       fprintf(fout, "  // %s", g_comment);
3152       g_comment[0] = 0;
3153       no_output = 0;
3154     }
3155     if (!no_output)
3156       fprintf(fout, "\n");
3157
3158     if (pfomask != 0)
3159       ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
3160
3161     // see is delayed flag stuff is still valid
3162     if (delayed_flag_op != NULL && delayed_flag_op != po) {
3163       if (is_any_opr_modified(delayed_flag_op, po))
3164         delayed_flag_op = NULL;
3165     }
3166
3167     if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
3168       if (is_opr_modified(last_arith_dst, po))
3169         last_arith_dst = NULL;
3170     }
3171
3172     label_pending = 0;
3173   }
3174
3175   fprintf(fout, "}\n\n");
3176
3177   // cleanup
3178   for (i = 0; i < opcnt; i++) {
3179     struct label_ref *lr, *lr_del;
3180
3181     lr = g_label_refs[i].next;
3182     while (lr != NULL) {
3183       lr_del = lr;
3184       lr = lr->next;
3185       free(lr_del);
3186     }
3187     g_label_refs[i].i = -1;
3188     g_label_refs[i].next = NULL;
3189
3190     if (ops[i].op == OP_CALL) {
3191       pp = ops[i].datap;
3192       if (pp) {
3193         proto_release(pp);
3194         free(pp);
3195       }
3196     }
3197   }
3198   proto_release(&g_func_pp);
3199 }
3200
3201 static void set_label(int i, const char *name)
3202 {
3203   const char *p;
3204   int len;
3205
3206   len = strlen(name);
3207   p = strchr(name, ':');
3208   if (p != NULL)
3209     len = p - name;
3210
3211   if (len > sizeof(g_labels[0]) - 1)
3212     aerr("label '%s' too long: %d\n", name, len);
3213   if (g_labels[i][0] != 0 && !IS_START(g_labels[i], "algn_"))
3214     aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
3215   memcpy(g_labels[i], name, len);
3216   g_labels[i][len] = 0;
3217 }
3218
3219 // '=' needs special treatment..
3220 static char *next_word_s(char *w, size_t wsize, char *s)
3221 {
3222         size_t i;
3223
3224         s = sskip(s);
3225
3226         for (i = 0; i < wsize - 1; i++) {
3227                 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
3228                         break;
3229                 w[i] = s[i];
3230         }
3231         w[i] = 0;
3232
3233         if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
3234                 printf("warning: '%s' truncated\n", w);
3235
3236         return s + i;
3237 }
3238
3239 struct chunk_item {
3240   char *name;
3241   long fptr;
3242   int asmln;
3243 };
3244
3245 static int cmp_chunks(const void *p1, const void *p2)
3246 {
3247   const struct chunk_item *c1 = p1, *c2 = p2;
3248   return strcmp(c1->name, c2->name);
3249 }
3250
3251 static int cmpstringp(const void *p1, const void *p2)
3252 {
3253   return strcmp(*(char * const *)p1, *(char * const *)p2);
3254 }
3255
3256 int main(int argc, char *argv[])
3257 {
3258   FILE *fout, *fasm, *frlist;
3259   struct parsed_data *pd = NULL;
3260   int pd_alloc = 0;
3261   char **rlist = NULL;
3262   int rlist_len = 0;
3263   int rlist_alloc = 0;
3264   struct chunk_item *func_chunks;
3265   int func_chunks_used = 0;
3266   int func_chunks_sorted = 0;
3267   int func_chunk_cnt = 0;
3268   int func_chunk_alloc;
3269   int func_chunk_i = -1;
3270   long func_chunk_ret = 0;
3271   int func_chunk_ret_ln = 0;
3272   char line[256];
3273   char words[16][256];
3274   enum opr_lenmod lmod;
3275   int in_func = 0;
3276   int pending_endp = 0;
3277   int skip_func = 0;
3278   int skip_warned = 0;
3279   int eq_alloc;
3280   int verbose = 0;
3281   int arg_out;
3282   int arg = 1;
3283   int pi = 0;
3284   int i, j;
3285   int ret, len;
3286   char *p;
3287   int wordc;
3288
3289   if (argv[1] && IS(argv[1], "-v")) {
3290     verbose = 1;
3291     arg++;
3292   }
3293
3294   if (argc < arg + 3) {
3295     printf("usage:\n%s [-v] <.c> <.asm> <hdrf> [rlist]*\n",
3296       argv[0]);
3297     return 1;
3298   }
3299
3300   arg_out = arg++;
3301
3302   asmfn = argv[arg++];
3303   fasm = fopen(asmfn, "r");
3304   my_assert_not(fasm, NULL);
3305
3306   hdrfn = argv[arg++];
3307   g_fhdr = fopen(hdrfn, "r");
3308   my_assert_not(g_fhdr, NULL);
3309
3310   rlist_alloc = 64;
3311   rlist = malloc(rlist_alloc * sizeof(rlist[0]));
3312   my_assert_not(rlist, NULL);
3313   // needs special handling..
3314   rlist[rlist_len++] = "__alloca_probe";
3315
3316   func_chunk_alloc = 32;
3317   func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
3318   my_assert_not(func_chunks, NULL);
3319
3320   for (; arg < argc; arg++) {
3321     frlist = fopen(argv[arg], "r");
3322     my_assert_not(frlist, NULL);
3323
3324     while (fgets(line, sizeof(line), frlist)) {
3325       p = sskip(line);
3326       if (*p == 0 || *p == ';' || *p == '#')
3327         continue;
3328
3329       p = next_word(words[0], sizeof(words[0]), p);
3330       if (words[0][0] == 0)
3331         continue;
3332
3333       if (rlist_len >= rlist_alloc) {
3334         rlist_alloc = rlist_alloc * 2 + 64;
3335         rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
3336         my_assert_not(rlist, NULL);
3337       }
3338       rlist[rlist_len++] = strdup(words[0]);
3339     }
3340
3341     fclose(frlist);
3342     frlist = NULL;
3343   }
3344
3345   if (rlist_len > 0)
3346     qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
3347
3348   fout = fopen(argv[arg_out], "w");
3349   my_assert_not(fout, NULL);
3350
3351   eq_alloc = 128;
3352   g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
3353   my_assert_not(g_eqs, NULL);
3354
3355   for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
3356     g_label_refs[i].i = -1;
3357     g_label_refs[i].next = NULL;
3358   }
3359
3360   while (fgets(line, sizeof(line), fasm))
3361   {
3362     wordc = 0;
3363     asmln++;
3364
3365     p = sskip(line);
3366     if (*p == 0)
3367       continue;
3368
3369     // get rid of random tabs
3370     for (i = 0; line[i] != 0; i++)
3371       if (line[i] == '\t')
3372         line[i] = ' ';
3373
3374     if (*p == ';')
3375     {
3376       if (p[2] == '=' && IS_START(p, "; =============== S U B"))
3377         goto do_pending_endp; // eww..
3378
3379       if (p[2] == 'A' && IS_START(p, "; Attributes:"))
3380       {
3381         static const char *attrs[] = {
3382           "bp-based frame",
3383           "library function",
3384           "static",
3385           "noreturn",
3386           "thunk",
3387           "fpd=",
3388         };
3389
3390         // parse IDA's attribute-list comment
3391         g_ida_func_attr = 0;
3392         p = sskip(p + 13);
3393
3394         for (; *p != 0; p = sskip(p)) {
3395           for (i = 0; i < ARRAY_SIZE(attrs); i++) {
3396             if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
3397               g_ida_func_attr |= 1 << i;
3398               p += strlen(attrs[i]);
3399               break;
3400             }
3401           }
3402           if (i == ARRAY_SIZE(attrs)) {
3403             anote("unparsed IDA attr: %s\n", p);
3404             break;
3405           }
3406           if (IS(attrs[i], "fpd=")) {
3407             p = next_word(words[0], sizeof(words[0]), p);
3408             // ignore for now..
3409           }
3410         }
3411       }
3412       else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
3413       {
3414         p += 30;
3415         next_word(words[0], sizeof(words[0]), p);
3416         if (words[0][0] == 0)
3417           aerr("missing nam for func chunk?\n");
3418         if (func_chunk_cnt >= func_chunk_alloc) {
3419           func_chunk_alloc *= 2;
3420           func_chunks = realloc(func_chunks,
3421             func_chunk_alloc * sizeof(func_chunks[0]));
3422           my_assert_not(func_chunks, NULL);
3423         }
3424         func_chunks[func_chunk_cnt].fptr = ftell(fasm);
3425         func_chunks[func_chunk_cnt].name = strdup(words[0]);
3426         func_chunks[func_chunk_cnt].asmln = asmln;
3427         func_chunk_cnt++;
3428         func_chunks_sorted = 0;
3429       }
3430       else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
3431       {
3432         if (func_chunk_i >= 0) {
3433           if (func_chunk_i < func_chunk_cnt
3434             && IS(func_chunks[func_chunk_i].name, g_func))
3435           {
3436             // move on to next chunk
3437             ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
3438             if (ret)
3439               aerr("seek failed for '%s' chunk #%d\n",
3440                 g_func, func_chunk_i);
3441             asmln = func_chunks[func_chunk_i].asmln;
3442             func_chunk_i++;
3443           }
3444           else {
3445             if (func_chunk_ret == 0)
3446               aerr("no return from chunk?\n");
3447             fseek(fasm, func_chunk_ret, SEEK_SET);
3448             asmln = func_chunk_ret_ln;
3449             func_chunk_ret = 0;
3450             pending_endp = 1;
3451           }
3452         }
3453       }
3454       else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
3455         func_chunks_used = 1;
3456         p += 20;
3457         if (IS_START(g_func, "sub_")) {
3458           unsigned long addr = strtoul(p, NULL, 16);
3459           unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
3460           if (addr > f_addr)
3461             aerr("need a chunk %lX that is after %s\n", addr, g_func);
3462         }
3463       }
3464       continue;
3465     } // *p == ';'
3466
3467 parse_words:
3468     memset(words, 0, sizeof(words));
3469     for (wordc = 0; wordc < 16; wordc++) {
3470       p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
3471       if (*p == 0 || *p == ';') {
3472         wordc++;
3473         break;
3474       }
3475     }
3476
3477     // alow asm patches in comments
3478     if (*p == ';' && IS_START(p, "; sctpatch:")) {
3479       p = sskip(p + 11);
3480       if (*p == 0 || *p == ';')
3481         continue;
3482       goto parse_words; // lame
3483     }
3484
3485     if (wordc == 0) {
3486       // shouldn't happen
3487       awarn("wordc == 0?\n");
3488       continue;
3489     }
3490
3491     // don't care about this:
3492     if (words[0][0] == '.'
3493         || IS(words[0], "include")
3494         || IS(words[0], "assume") || IS(words[1], "segment")
3495         || IS(words[0], "align"))
3496     {
3497       continue;
3498     }
3499
3500 do_pending_endp:
3501     // do delayed endp processing to collect switch jumptables
3502     if (pending_endp) {
3503       if (in_func && !skip_func && wordc >= 2
3504           && ((words[0][0] == 'd' && words[0][2] == 0)
3505               || (words[1][0] == 'd' && words[1][2] == 0)))
3506       {
3507         i = 1;
3508         if (words[1][0] == 'd' && words[1][2] == 0) {
3509           // label
3510           if (g_func_pd_cnt >= pd_alloc) {
3511             pd_alloc = pd_alloc * 2 + 16;
3512             g_func_pd = realloc(g_func_pd,
3513               sizeof(g_func_pd[0]) * pd_alloc);
3514             my_assert_not(g_func_pd, NULL);
3515           }
3516           pd = &g_func_pd[g_func_pd_cnt];
3517           g_func_pd_cnt++;
3518           memset(pd, 0, sizeof(*pd));
3519           strcpy(pd->label, words[0]);
3520           pd->type = OPT_CONST;
3521           pd->lmod = lmod_from_directive(words[1]);
3522           i = 2;
3523         }
3524         else {
3525           lmod = lmod_from_directive(words[0]);
3526           if (lmod != pd->lmod)
3527             aerr("lmod change? %d->%d\n", pd->lmod, lmod);
3528         }
3529
3530         if (pd->count_alloc < pd->count + wordc) {
3531           pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
3532           pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
3533           my_assert_not(pd->d, NULL);
3534         }
3535         for (; i < wordc; i++) {
3536           if (IS(words[i], "offset")) {
3537             pd->type = OPT_OFFSET;
3538             i++;
3539           }
3540           p = strchr(words[i], ',');
3541           if (p != NULL)
3542             *p = 0;
3543           if (pd->type == OPT_OFFSET)
3544             pd->d[pd->count].u.label = strdup(words[i]);
3545           else
3546             pd->d[pd->count].u.val = parse_number(words[i]);
3547           pd->d[pd->count].bt_i = -1;
3548           pd->count++;
3549         }
3550         continue;
3551       }
3552
3553       if (in_func && !skip_func)
3554         gen_func(fout, g_fhdr, g_func, pi);
3555
3556       pending_endp = 0;
3557       in_func = 0;
3558       g_ida_func_attr = 0;
3559       skip_warned = 0;
3560       skip_func = 0;
3561       g_func[0] = 0;
3562       func_chunks_used = 0;
3563       func_chunk_i = -1;
3564       if (pi != 0) {
3565         memset(&ops, 0, pi * sizeof(ops[0]));
3566         memset(g_labels, 0, pi * sizeof(g_labels[0]));
3567         pi = 0;
3568       }
3569       g_eqcnt = 0;
3570       for (i = 0; i < g_func_pd_cnt; i++) {
3571         pd = &g_func_pd[i];
3572         if (pd->type == OPT_OFFSET) {
3573           for (j = 0; j < pd->count; j++)
3574             free(pd->d[j].u.label);
3575         }
3576         free(pd->d);
3577         pd->d = NULL;
3578       }
3579       g_func_pd_cnt = 0;
3580       pd = NULL;
3581       if (wordc == 0)
3582         continue;
3583     }
3584
3585     if (IS(words[1], "proc")) {
3586       if (in_func)
3587         aerr("proc '%s' while in_func '%s'?\n",
3588           words[0], g_func);
3589       p = words[0];
3590       if ((g_ida_func_attr & IDAFA_THUNK)
3591        || bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
3592         skip_func = 1;
3593       strcpy(g_func, words[0]);
3594       set_label(0, words[0]);
3595       in_func = 1;
3596       continue;
3597     }
3598
3599     if (IS(words[1], "endp"))
3600     {
3601       if (!in_func)
3602         aerr("endp '%s' while not in_func?\n", words[0]);
3603       if (!IS(g_func, words[0]))
3604         aerr("endp '%s' while in_func '%s'?\n",
3605           words[0], g_func);
3606
3607       if (!skip_func && func_chunks_used) {
3608         // start processing chunks
3609         struct chunk_item *ci, key = { g_func, 0 };
3610
3611         func_chunk_ret = ftell(fasm);
3612         func_chunk_ret_ln = asmln;
3613         if (!func_chunks_sorted) {
3614           qsort(func_chunks, func_chunk_cnt,
3615             sizeof(func_chunks[0]), cmp_chunks);
3616           func_chunks_sorted = 1;
3617         }
3618         ci = bsearch(&key, func_chunks, func_chunk_cnt,
3619                sizeof(func_chunks[0]), cmp_chunks);
3620         if (ci == NULL)
3621           aerr("'%s' needs chunks, but none found\n", g_func);
3622         func_chunk_i = ci - func_chunks;
3623         for (; func_chunk_i > 0; func_chunk_i--)
3624           if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
3625             break;
3626
3627         ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
3628         if (ret)
3629           aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
3630         asmln = func_chunks[func_chunk_i].asmln;
3631         func_chunk_i++;
3632         continue;
3633       }
3634       pending_endp = 1;
3635       continue;
3636     }
3637
3638     p = strchr(words[0], ':');
3639     if (p != NULL) {
3640       set_label(pi, words[0]);
3641       continue;
3642     }
3643
3644     if (!in_func || skip_func) {
3645       if (!skip_warned && !skip_func && g_labels[pi][0] != 0) {
3646         if (verbose)
3647           anote("skipping from '%s'\n", g_labels[pi]);
3648         skip_warned = 1;
3649       }
3650       g_labels[pi][0] = 0;
3651       continue;
3652     }
3653
3654     if (wordc > 1 && IS(words[1], "=")) {
3655       if (wordc != 5)
3656         aerr("unhandled equ, wc=%d\n", wordc);
3657       if (g_eqcnt >= eq_alloc) {
3658         eq_alloc *= 2;
3659         g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
3660         my_assert_not(g_eqs, NULL);
3661       }
3662
3663       len = strlen(words[0]);
3664       if (len > sizeof(g_eqs[0].name) - 1)
3665         aerr("equ name too long: %d\n", len);
3666       strcpy(g_eqs[g_eqcnt].name, words[0]);
3667
3668       if (!IS(words[3], "ptr"))
3669         aerr("unhandled equ\n");
3670       if (IS(words[2], "dword"))
3671         g_eqs[g_eqcnt].lmod = OPLM_DWORD;
3672       else if (IS(words[2], "word"))
3673         g_eqs[g_eqcnt].lmod = OPLM_WORD;
3674       else if (IS(words[2], "byte"))
3675         g_eqs[g_eqcnt].lmod = OPLM_BYTE;
3676       else
3677         aerr("bad lmod: '%s'\n", words[2]);
3678
3679       g_eqs[g_eqcnt].offset = parse_number(words[4]);
3680       g_eqcnt++;
3681       continue;
3682     }
3683
3684     if (pi >= ARRAY_SIZE(ops))
3685       aerr("too many ops\n");
3686
3687     parse_op(&ops[pi], words, wordc);
3688     pi++;
3689   }
3690
3691   fclose(fout);
3692   fclose(fasm);
3693   fclose(g_fhdr);
3694
3695   return 0;
3696 }
3697
3698 // vim:ts=2:shiftwidth=2:expandtab