use main header, parse variable types, asm patch comment
[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_REP    = (1 << 6), /* prefixed by rep */
37   OPF_RSAVE  = (1 << 7), /* push/pop is local reg save/load */
38 };
39
40 enum op_op {
41         OP_INVAL,
42         OP_NOP,
43         OP_PUSH,
44         OP_POP,
45         OP_MOV,
46         OP_LEA,
47         OP_MOVZX,
48         OP_MOVSX,
49         OP_NOT,
50         OP_CDQ,
51         OP_STOS,
52         OP_MOVS,
53         OP_RET,
54         OP_ADD,
55         OP_SUB,
56         OP_AND,
57         OP_OR,
58         OP_XOR,
59         OP_SHL,
60         OP_SHR,
61         OP_SAR,
62         OP_ROL,
63         OP_ROR,
64         OP_ADC,
65         OP_SBB,
66         OP_INC,
67         OP_DEC,
68         OP_NEG,
69         OP_MUL,
70         OP_IMUL,
71         OP_DIV,
72         OP_IDIV,
73         OP_TEST,
74         OP_CMP,
75         OP_CALL,
76         OP_JMP,
77         OP_JO,
78         OP_JNO,
79         OP_JC,
80         OP_JNC,
81         OP_JZ,
82         OP_JNZ,
83         OP_JBE,
84         OP_JA,
85         OP_JS,
86         OP_JNS,
87         OP_JP,
88         OP_JNP,
89         OP_JL,
90         OP_JGE,
91         OP_JLE,
92         OP_JG,
93 };
94
95 enum opr_type {
96   OPT_UNSPEC,
97   OPT_REG,
98   OPT_REGMEM,
99   OPT_LABEL,
100   OPT_OFFSET,
101   OPT_CONST,
102 };
103
104 enum opr_lenmod {
105         OPLM_UNSPEC,
106         OPLM_BYTE,
107         OPLM_WORD,
108         OPLM_DWORD,
109 };
110
111 #define MAX_OPERANDS 3
112
113 struct parsed_opr {
114   enum opr_type type;
115   enum opr_lenmod lmod;
116   unsigned int is_ptr:1;  // pointer in C
117   int reg;
118   unsigned int val;
119   char name[256];
120 };
121
122 struct parsed_op {
123   enum op_op op;
124   struct parsed_opr operand[MAX_OPERANDS];
125   unsigned int flags;
126   int operand_cnt;
127   int regmask_src;        // all referensed regs
128   int regmask_dst;
129   int pfomask;            // flagop: parsed_flag_op that can't be delayed
130   int argmask;            // push: args that are altered before call
131   int cc_scratch;         // scratch storage during analysis
132   int bt_i;               // branch target (for branches)
133   struct parsed_op *lrl;  // label reference list entry
134   void *datap;
135 };
136
137 // datap:
138 // OP_CALL - ptr to parsed_proto
139 // (OPF_CC) - point to corresponding (OPF_FLAGS)
140
141 struct parsed_equ {
142   char name[64];
143   enum opr_lenmod lmod;
144   int offset;
145 };
146
147 enum ida_func_attr {
148   IDAFA_BP_FRAME = (1 << 0),
149   IDAFA_LIB_FUNC = (1 << 1),
150   IDAFA_STATIC   = (1 << 2),
151   IDAFA_NORETURN = (1 << 3),
152   IDAFA_THUNK    = (1 << 4),
153   IDAFA_FPD      = (1 << 5),
154 };
155
156 #define MAX_OPS 4096
157
158 static struct parsed_op ops[MAX_OPS];
159 static struct parsed_equ *g_eqs;
160 static int g_eqcnt;
161 static char g_labels[MAX_OPS][32];
162 static struct parsed_op *g_label_refs[MAX_OPS];
163 static struct parsed_proto g_func_pp;
164 static char g_func[256];
165 static char g_comment[256];
166 static int g_bp_frame;
167 static int g_sp_frame;
168 static int g_stack_fsz;
169 #define ferr(op_, fmt, ...) do { \
170   printf("error:%s:#%ld: '%s': " fmt, g_func, (op_) - ops, \
171     dump_op(op_), ##__VA_ARGS__); \
172   fcloseall(); \
173   exit(1); \
174 } while (0)
175
176 #define MAX_REGS 8
177
178 const char *regs_r32[] = { "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp" };
179 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
180 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
181 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
182
183 enum x86_regs { xUNSPEC = -1, xAX, xBX, xCX, xDX, xSI, xDI, xBP, xSP };
184
185 // possible basic comparison types (without inversion)
186 enum parsed_flag_op {
187   PFO_O,  // 0 OF=1
188   PFO_C,  // 2 CF=1
189   PFO_Z,  // 4 ZF=1
190   PFO_BE, // 6 CF=1||ZF=1
191   PFO_S,  // 8 SF=1
192   PFO_P,  // a PF=1
193   PFO_L,  // c SF!=OF
194   PFO_LE, // e ZF=1||SF!=OF
195 };
196
197 static const char *parsed_flag_op_names[] = {
198   "o", "c", "z", "be", "s", "p", "l", "le"
199 };
200
201 static int char_array_i(const char *array[], size_t len, const char *s)
202 {
203   int i;
204
205   for (i = 0; i < len; i++)
206     if (IS(s, array[i]))
207       return i;
208
209   return -1;
210 }
211
212 static void printf_number(char *buf, size_t buf_size, long number)
213 {
214   // output in C-friendly form
215   snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
216 }
217
218 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
219 {
220   int reg;
221
222   reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
223   if (reg >= 0) {
224     *reg_lmod = OPLM_DWORD;
225     return reg;
226   }
227   reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
228   if (reg >= 0) {
229     *reg_lmod = OPLM_WORD;
230     return reg;
231   }
232   reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
233   if (reg >= 0) {
234     *reg_lmod = OPLM_BYTE;
235     return reg;
236   }
237   reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
238   if (reg >= 0) {
239     *reg_lmod = OPLM_BYTE;
240     return reg;
241   }
242
243   return -1;
244 }
245
246 static long parse_number(const char *number)
247 {
248   int len = strlen(number);
249   const char *p = number;
250   char *endp = NULL;
251   int neg = 0;
252   int bad;
253   long ret;
254
255   if (*p == '-') {
256     neg = 1;
257     p++;
258   }
259   if (len > 1 && *p == '0')
260     p++;
261   if (number[len - 1] == 'h') {
262     ret = strtol(p, &endp, 16);
263     bad = (*endp != 'h');
264   }
265   else {
266     ret = strtol(p, &endp, 10);
267     bad = (*endp != 0);
268   }
269   if (bad)
270     aerr("number parsing failed\n");
271   if (neg)
272     ret = -ret;
273   return ret;
274 }
275
276 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
277 {
278   enum opr_lenmod lmod;
279   char cvtbuf[256];
280   char *d = cvtbuf;
281   char *s = name;
282   char w[64];
283   long number;
284   int reg;
285   int c = 0;
286
287   *d = 0;
288
289   while (*s != 0) {
290     d += strlen(d);
291     while (my_isblank(*s))
292       s++;
293     for (; my_issep(*s); d++, s++)
294       *d = *s;
295     while (my_isblank(*s))
296       s++;
297     *d = 0;
298
299     // skip 'ds:' prefix
300     if (IS_START(s, "ds:"))
301       s += 3;
302
303     s = next_idt(w, sizeof(w), s);
304     if (w[0] == 0)
305       break;
306     c++;
307
308     reg = parse_reg(&lmod, w);
309     if (reg >= 0) {
310       *regmask |= 1 << reg;
311       goto pass;
312     }
313
314     if ('0' <= w[0] && w[0] <= '9') {
315       number = parse_number(w);
316       printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
317       continue;
318     }
319
320     // probably some label/identifier - pass
321
322 pass:
323     snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
324   }
325
326   if (need_c_cvt)
327     strcpy(name, cvtbuf);
328
329   return c;
330 }
331
332 static const char *parse_stack_el(const char *name)
333 {
334   const char *p, *s;
335   char *endp = NULL;
336   char buf[32];
337   long val;
338   int len;
339
340   if (IS_START(name, "ebp+")
341       && !('0' <= name[4] && name[4] <= '9'))
342   {
343     return name + 4;
344   }
345   if (!IS_START(name, "esp+"))
346     return NULL;
347
348   p = strchr(name + 4, '+');
349   if (p) {
350     // must be a number after esp+, already converted to 0x..
351     s = name + 4;
352     if (!('0' <= *s && *s <= '9')) {
353                   aerr("%s nan?\n", __func__);
354       return NULL;
355     }
356     if (s[0] == '0' && s[1] == 'x')
357       s += 2;
358     len = p - s;
359     if (len < sizeof(buf) - 1) {
360       strncpy(buf, s, len);
361       buf[len] = 0;
362       val = strtol(buf, &endp, 16);
363       if (val == 0 || *endp != 0) {
364         aerr("%s num parse fail for '%s'\n", __func__, buf);
365         return NULL;
366       }
367     }
368     p++;
369   }
370   else
371     p = name + 4;
372
373   if ('0' <= *p && *p <= '9')
374     return NULL;
375
376   return p;
377 }
378
379 static int guess_lmod_from_name(struct parsed_opr *opr)
380 {
381   if (!strncmp(opr->name, "dword_", 6)) {
382     opr->lmod = OPLM_DWORD;
383     return 1;
384   }
385   if (!strncmp(opr->name, "word_", 5)) {
386     opr->lmod = OPLM_WORD;
387     return 1;
388   }
389   if (!strncmp(opr->name, "byte_", 5)) {
390     opr->lmod = OPLM_BYTE;
391     return 1;
392   }
393   return 0;
394 }
395
396 static int guess_lmod_from_c_type(struct parsed_opr *opr, const char *c_type)
397 {
398   static const char *ptr_types[] = {
399     "LPCSTR",
400   };
401   static const char *dword_types[] = {
402     "int", "_DWORD", "DWORD", "HANDLE", "HWND", "HMODULE",
403   };
404   static const char *word_types[] = {
405     "__int16", "unsigned __int16",
406   };
407   static const char *byte_types[] = {
408     "char", "__int8", "unsigned __int8", "BYTE",
409   };
410   int i;
411
412   if (strchr(c_type, '*')) {
413     opr->lmod = OPLM_DWORD;
414     opr->is_ptr = 1;
415     return 1;
416   }
417
418   for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
419     if (IS(c_type, dword_types[i])) {
420       opr->lmod = OPLM_DWORD;
421       return 1;
422     }
423   }
424
425   for (i = 0; i < ARRAY_SIZE(ptr_types); i++) {
426     if (IS(c_type, ptr_types[i])) {
427       opr->lmod = OPLM_DWORD;
428       opr->is_ptr = 1;
429       return 1;
430     }
431   }
432
433   for (i = 0; i < ARRAY_SIZE(word_types); i++) {
434     if (IS(c_type, word_types[i])) {
435       opr->lmod = OPLM_WORD;
436       return 1;
437     }
438   }
439
440   for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
441     if (IS(c_type, byte_types[i])) {
442       opr->lmod = OPLM_BYTE;
443       return 1;
444     }
445   }
446
447   anote("unhandled C type '%s' for '%s'\n", c_type, opr->name);
448   return 0;
449 }
450
451 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
452   int *regmask)
453 {
454   opr->type = OPT_REG;
455   opr->reg = reg;
456   opr->lmod = lmod;
457   *regmask |= 1 << reg;
458 }
459
460 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
461   int *extra_offs);
462
463 static int parse_operand(struct parsed_opr *opr,
464   int *regmask, int *regmask_indirect,
465   char words[16][256], int wordc, int w, unsigned int op_flags)
466 {
467   struct parsed_proto pp;
468   enum opr_lenmod tmplmod;
469   int ret, len;
470   long number;
471   int wordc_in;
472   char *tmp;
473   int i;
474
475   if (w >= wordc)
476     aerr("parse_operand w %d, wordc %d\n", w, wordc);
477
478   opr->reg = xUNSPEC;
479
480   for (i = w; i < wordc; i++) {
481     len = strlen(words[i]);
482     if (words[i][len - 1] == ',') {
483       words[i][len - 1] = 0;
484       wordc = i + 1;
485       break;
486     }
487   }
488
489   wordc_in = wordc - w;
490
491   if ((op_flags & OPF_JMP) && wordc_in > 0
492       && !('0' <= words[w][0] && words[w][0] <= '9'))
493   {
494     const char *label = NULL;
495
496     if (wordc_in == 3 && !strncmp(words[w], "near", 4)
497      && IS(words[w + 1], "ptr"))
498       label = words[w + 2];
499     else if (wordc_in == 2 && IS(words[w], "short"))
500       label = words[w + 1];
501     else if (wordc_in == 1
502           && strchr(words[w], '[') == NULL
503           && parse_reg(&tmplmod, words[w]) < 0)
504       label = words[w];
505
506     if (label != NULL) {
507       opr->type = OPT_LABEL;
508       if (IS_START(label, "ds:"))
509         label += 3;
510       strcpy(opr->name, label);
511       return wordc;
512     }
513   }
514
515   if (wordc_in >= 3) {
516     if (IS(words[w + 1], "ptr")) {
517       if (IS(words[w], "dword"))
518         opr->lmod = OPLM_DWORD;
519       else if (IS(words[w], "word"))
520         opr->lmod = OPLM_WORD;
521       else if (IS(words[w], "byte"))
522         opr->lmod = OPLM_BYTE;
523       else
524         aerr("type parsing failed\n");
525       w += 2;
526       wordc_in = wordc - w;
527     }
528   }
529
530   if (wordc_in == 2) {
531     if (IS(words[w], "offset")) {
532       opr->type = OPT_OFFSET;
533       strcpy(opr->name, words[w + 1]);
534       return wordc;
535     }
536     if (IS(words[w], "(offset")) {
537       char *p = strchr(words[w + 1], ')');
538       if (p == NULL)
539         aerr("parse of bracketed offset failed\n");
540       *p = 0;
541       opr->type = OPT_OFFSET;
542       strcpy(opr->name, words[w + 1]);
543       return wordc;
544     }
545   }
546
547   if (wordc_in != 1)
548     aerr("parse_operand 1 word expected\n");
549
550   tmp = words[w];
551   if (IS_START(tmp, "ds:"))
552     tmp += 3;
553   strcpy(opr->name, tmp);
554
555   if (words[w][0] == '[') {
556     opr->type = OPT_REGMEM;
557     ret = sscanf(words[w], "[%[^]]]", opr->name);
558     if (ret != 1)
559       aerr("[] parse failure\n");
560
561     parse_indmode(opr->name, regmask_indirect, 1);
562     if (opr->lmod == OPLM_UNSPEC && parse_stack_el(opr->name)) {
563       // might be an equ
564       struct parsed_equ *eq =
565         equ_find(NULL, parse_stack_el(opr->name), &i);
566       if (eq)
567         opr->lmod = eq->lmod;
568     }
569     return wordc;
570   }
571   else if (strchr(words[w], '[')) {
572     // label[reg] form
573     opr->type = OPT_REGMEM;
574     if (opr->lmod == OPLM_UNSPEC)
575       guess_lmod_from_name(opr);
576     parse_indmode(strchr(words[w], '['), regmask_indirect, 0);
577     return wordc;
578   }
579   else if (('0' <= words[w][0] && words[w][0] <= '9')
580     || words[w][0] == '-')
581   {
582     number = parse_number(words[w]);
583     opr->type = OPT_CONST;
584     opr->val = number;
585     printf_number(opr->name, sizeof(opr->name), number);
586     return wordc;
587   }
588
589   ret = parse_reg(&tmplmod, opr->name);
590   if (ret >= 0) {
591     setup_reg_opr(opr, ret, tmplmod, regmask);
592     return wordc;
593   }
594
595   // most likely var in data segment
596   opr->type = OPT_LABEL;
597
598   ret = proto_parse(g_fhdr, opr->name, &pp);
599   if (ret == 0) {
600     if (pp.is_fptr) {
601       opr->lmod = OPLM_DWORD;
602       opr->is_ptr = 1;
603     }
604     else if (opr->lmod == OPLM_UNSPEC)
605       guess_lmod_from_c_type(opr, pp.ret_type);
606   }
607
608   if (opr->lmod == OPLM_UNSPEC)
609     guess_lmod_from_name(opr);
610   return wordc;
611 }
612
613 static const struct {
614   const char *name;
615   unsigned int flags;
616 } pref_table[] = {
617   { "rep",    OPF_REP },
618 };
619
620 static const struct {
621   const char *name;
622   enum op_op op;
623   unsigned int minopr;
624   unsigned int maxopr;
625   unsigned int flags;
626 } op_table[] = {
627   { "nop",  OP_NOP,    0, 0, 0 },
628   { "push", OP_PUSH,   1, 1, 0 },
629   { "pop",  OP_POP,    1, 1, OPF_DATA },
630   { "mov" , OP_MOV,    2, 2, OPF_DATA },
631   { "lea",  OP_LEA,    2, 2, OPF_DATA },
632   { "movzx",OP_MOVZX,  2, 2, OPF_DATA },
633   { "movsx",OP_MOVSX,  2, 2, OPF_DATA },
634   { "not",  OP_NOT,    1, 1, OPF_DATA },
635   { "cdq",  OP_CDQ,    0, 0, OPF_DATA },
636   { "stosb",OP_STOS,   0, 0, OPF_DATA },
637   { "stosw",OP_STOS,   0, 0, OPF_DATA },
638   { "stosd",OP_STOS,   0, 0, OPF_DATA },
639   { "movsb",OP_MOVS,   0, 0, OPF_DATA },
640   { "movsw",OP_MOVS,   0, 0, OPF_DATA },
641   { "movsd",OP_MOVS,   0, 0, OPF_DATA },
642   { "add",  OP_ADD,    2, 2, OPF_DATA|OPF_FLAGS },
643   { "sub",  OP_SUB,    2, 2, OPF_DATA|OPF_FLAGS },
644   { "and",  OP_AND,    2, 2, OPF_DATA|OPF_FLAGS },
645   { "or",   OP_OR,     2, 2, OPF_DATA|OPF_FLAGS },
646   { "xor",  OP_XOR,    2, 2, OPF_DATA|OPF_FLAGS },
647   { "shl",  OP_SHL,    2, 2, OPF_DATA|OPF_FLAGS },
648   { "shr",  OP_SHR,    2, 2, OPF_DATA|OPF_FLAGS },
649   { "sal",  OP_SHL,    2, 2, OPF_DATA|OPF_FLAGS },
650   { "sar",  OP_SAR,    2, 2, OPF_DATA|OPF_FLAGS },
651   { "rol",  OP_ROL,    2, 2, OPF_DATA|OPF_FLAGS },
652   { "ror",  OP_ROR,    2, 2, OPF_DATA|OPF_FLAGS },
653   { "adc",  OP_ADC,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
654   { "sbb",  OP_SBB,    2, 2, OPF_DATA|OPF_FLAGS|OPF_CC },
655   { "inc",  OP_INC,    1, 1, OPF_DATA|OPF_FLAGS },
656   { "dec",  OP_DEC,    1, 1, OPF_DATA|OPF_FLAGS },
657   { "neg",  OP_NEG,    1, 1, OPF_DATA|OPF_FLAGS },
658   { "mul",  OP_MUL,    1, 1, OPF_DATA|OPF_FLAGS },
659   { "imul", OP_IMUL,   1, 3, OPF_DATA|OPF_FLAGS },
660   { "div",  OP_DIV,    1, 1, OPF_DATA|OPF_FLAGS },
661   { "idiv", OP_IDIV,   1, 1, OPF_DATA|OPF_FLAGS },
662   { "test", OP_TEST,   2, 2, OPF_FLAGS },
663   { "cmp",  OP_CMP,    2, 2, OPF_FLAGS },
664   { "retn", OP_RET,    0, 1, OPF_JMP|OPF_TAIL },
665   { "call", OP_CALL,   1, 1, OPF_JMP|OPF_FLAGS },
666   { "jmp",  OP_JMP,    1, 1, OPF_JMP },
667   { "jo",   OP_JO,     1, 1, OPF_JMP|OPF_CC }, // 70 OF=1
668   { "jno",  OP_JNO,    1, 1, OPF_JMP|OPF_CC }, // 71 OF=0
669   { "jc",   OP_JC,     1, 1, OPF_JMP|OPF_CC }, // 72 CF=1
670   { "jb",   OP_JC,     1, 1, OPF_JMP|OPF_CC }, // 72
671   { "jnc",  OP_JNC,    1, 1, OPF_JMP|OPF_CC }, // 73 CF=0
672   { "jnb",  OP_JNC,    1, 1, OPF_JMP|OPF_CC }, // 73
673   { "jae",  OP_JNC,    1, 1, OPF_JMP|OPF_CC }, // 73
674   { "jz",   OP_JZ,     1, 1, OPF_JMP|OPF_CC }, // 74 ZF=1
675   { "je",   OP_JZ,     1, 1, OPF_JMP|OPF_CC }, // 74
676   { "jnz",  OP_JNZ,    1, 1, OPF_JMP|OPF_CC }, // 75 ZF=0
677   { "jne",  OP_JNZ,    1, 1, OPF_JMP|OPF_CC }, // 75
678   { "jbe",  OP_JBE,    1, 1, OPF_JMP|OPF_CC }, // 76 CF=1 || ZF=1
679   { "jna",  OP_JBE,    1, 1, OPF_JMP|OPF_CC }, // 76
680   { "ja",   OP_JA,     1, 1, OPF_JMP|OPF_CC }, // 77 CF=0 && ZF=0
681   { "jnbe", OP_JA,     1, 1, OPF_JMP|OPF_CC }, // 77
682   { "js",   OP_JS,     1, 1, OPF_JMP|OPF_CC }, // 78 SF=1
683   { "jns",  OP_JNS,    1, 1, OPF_JMP|OPF_CC }, // 79 SF=0
684   { "jp",   OP_JP,     1, 1, OPF_JMP|OPF_CC }, // 7a PF=1
685   { "jpe",  OP_JP,     1, 1, OPF_JMP|OPF_CC }, // 7a
686   { "jnp",  OP_JNP,    1, 1, OPF_JMP|OPF_CC }, // 7b PF=0
687   { "jpo",  OP_JNP,    1, 1, OPF_JMP|OPF_CC }, // 7b
688   { "jl",   OP_JL,     1, 1, OPF_JMP|OPF_CC }, // 7c SF!=OF
689   { "jnge", OP_JL,     1, 1, OPF_JMP|OPF_CC }, // 7c
690   { "jge",  OP_JGE,    1, 1, OPF_JMP|OPF_CC }, // 7d SF=OF
691   { "jnl",  OP_JGE,    1, 1, OPF_JMP|OPF_CC }, // 7d
692   { "jle",  OP_JLE,    1, 1, OPF_JMP|OPF_CC }, // 7e ZF=1 || SF!=OF
693   { "jng",  OP_JLE,    1, 1, OPF_JMP|OPF_CC }, // 7e
694   { "jg",   OP_JG,     1, 1, OPF_JMP|OPF_CC }, // 7f ZF=0 && SF=OF
695   { "jnle", OP_JG,     1, 1, OPF_JMP|OPF_CC }, // 7f
696   { "seto",   OP_JO,   1, 1, OPF_DATA|OPF_CC },
697   { "setno",  OP_JNO,  1, 1, OPF_DATA|OPF_CC },
698   { "setc",   OP_JC,   1, 1, OPF_DATA|OPF_CC },
699   { "setb",   OP_JC,   1, 1, OPF_DATA|OPF_CC },
700   { "setnc",  OP_JNC,  1, 1, OPF_DATA|OPF_CC },
701   { "setae",  OP_JNC,  1, 1, OPF_DATA|OPF_CC },
702   { "setz",   OP_JZ,   1, 1, OPF_DATA|OPF_CC },
703   { "sete",   OP_JZ,   1, 1, OPF_DATA|OPF_CC },
704   { "setnz",  OP_JNZ,  1, 1, OPF_DATA|OPF_CC },
705   { "setne",  OP_JNZ,  1, 1, OPF_DATA|OPF_CC },
706   { "setbe",  OP_JBE,  1, 1, OPF_DATA|OPF_CC },
707   { "setna",  OP_JBE,  1, 1, OPF_DATA|OPF_CC },
708   { "seta",   OP_JA,   1, 1, OPF_DATA|OPF_CC },
709   { "setnbe", OP_JA,   1, 1, OPF_DATA|OPF_CC },
710   { "sets",   OP_JS,   1, 1, OPF_DATA|OPF_CC },
711   { "setns",  OP_JNS,  1, 1, OPF_DATA|OPF_CC },
712   { "setp",   OP_JP,   1, 1, OPF_DATA|OPF_CC },
713   { "setpe",  OP_JP,   1, 1, OPF_DATA|OPF_CC },
714   { "setnp",  OP_JNP,  1, 1, OPF_DATA|OPF_CC },
715   { "setpo",  OP_JNP,  1, 1, OPF_DATA|OPF_CC },
716   { "setl",   OP_JL,   1, 1, OPF_DATA|OPF_CC },
717   { "setnge", OP_JL,   1, 1, OPF_DATA|OPF_CC },
718   { "setge",  OP_JGE,  1, 1, OPF_DATA|OPF_CC },
719   { "setnl",  OP_JGE,  1, 1, OPF_DATA|OPF_CC },
720   { "setle",  OP_JLE,  1, 1, OPF_DATA|OPF_CC },
721   { "setng",  OP_JLE,  1, 1, OPF_DATA|OPF_CC },
722   { "setg",   OP_JG,   1, 1, OPF_DATA|OPF_CC },
723   { "setnle", OP_JG,   1, 1, OPF_DATA|OPF_CC },
724 };
725
726 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
727 {
728   enum opr_lenmod lmod = OPLM_UNSPEC;
729   int prefix_flags = 0;
730   int regmask_ind;
731   int regmask;
732   int op_w = 0;
733   int opr = 0;
734   int w = 0;
735   int i;
736
737   for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
738     if (IS(words[w], pref_table[i].name)) {
739       prefix_flags = pref_table[i].flags;
740       break;
741     }
742   }
743
744   if (prefix_flags) {
745     if (wordc <= 1)
746       aerr("lone prefix: '%s'\n", words[0]);
747     w++;
748   }
749
750   op_w = w;
751   for (i = 0; i < ARRAY_SIZE(op_table); i++) {
752     if (IS(words[w], op_table[i].name))
753       break;
754   }
755
756   if (i == ARRAY_SIZE(op_table))
757     aerr("unhandled op: '%s'\n", words[0]);
758   w++;
759
760   op->op = op_table[i].op;
761   op->flags = op_table[i].flags | prefix_flags;
762   op->regmask_src = op->regmask_dst = 0;
763
764   for (opr = 0; opr < op_table[i].minopr; opr++) {
765     regmask = regmask_ind = 0;
766     w = parse_operand(&op->operand[opr], &regmask, &regmask_ind,
767       words, wordc, w, op->flags);
768
769     if (opr == 0 && (op->flags & OPF_DATA))
770       op->regmask_dst = regmask;
771     // for now, mark dst as src too
772     op->regmask_src |= regmask | regmask_ind;
773   }
774
775   for (; w < wordc && opr < op_table[i].maxopr; opr++) {
776     w = parse_operand(&op->operand[opr],
777       &op->regmask_src, &op->regmask_src,
778       words, wordc, w, op->flags);
779   }
780
781   if (w < wordc)
782     aerr("parse_op %s incomplete: %d/%d\n",
783       words[0], w, wordc);
784
785   // special cases
786   op->operand_cnt = opr;
787   if (!strncmp(op_table[i].name, "set", 3))
788     op->operand[0].lmod = OPLM_BYTE;
789
790   // ops with implicit argumets
791   switch (op->op) {
792   case OP_CDQ:
793     op->operand_cnt = 2;
794     setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
795     setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
796     break;
797
798   case OP_STOS:
799     if (op->operand_cnt != 0)
800       break;
801     if      (IS(words[op_w], "stosb"))
802       lmod = OPLM_BYTE;
803     else if (IS(words[op_w], "stosw"))
804       lmod = OPLM_WORD;
805     else if (IS(words[op_w], "stosd"))
806       lmod = OPLM_DWORD;
807     op->operand_cnt = 3;
808     setup_reg_opr(&op->operand[0], xDI, lmod, &op->regmask_src);
809     setup_reg_opr(&op->operand[1], xCX, OPLM_DWORD, &op->regmask_src);
810     op->regmask_dst = op->regmask_src;
811     setup_reg_opr(&op->operand[2], xAX, OPLM_DWORD, &op->regmask_src);
812     break;
813
814   case OP_MOVS:
815     if (op->operand_cnt != 0)
816       break;
817     if      (IS(words[op_w], "movsb"))
818       lmod = OPLM_BYTE;
819     else if (IS(words[op_w], "movsw"))
820       lmod = OPLM_WORD;
821     else if (IS(words[op_w], "movsd"))
822       lmod = OPLM_DWORD;
823     op->operand_cnt = 3;
824     setup_reg_opr(&op->operand[0], xDI, lmod, &op->regmask_src);
825     setup_reg_opr(&op->operand[1], xSI, OPLM_DWORD, &op->regmask_src);
826     setup_reg_opr(&op->operand[2], xCX, OPLM_DWORD, &op->regmask_src);
827     op->regmask_dst = op->regmask_src;
828     break;
829
830   case OP_IMUL:
831     if (op->operand_cnt != 1)
832       break;
833     // fallthrough
834   case OP_MUL:
835     // singleop mul
836     op->regmask_dst = (1 << xDX) | (1 << xAX);
837     op->regmask_src |= (1 << xAX);
838     if (op->operand[0].lmod == OPLM_UNSPEC)
839       op->operand[0].lmod = OPLM_DWORD;
840     break;
841
842   case OP_DIV:
843   case OP_IDIV:
844     // we could set up operands for edx:eax, but there is no real need to
845     // (see is_opr_modified())
846     regmask = (1 << xDX) | (1 << xAX);
847     op->regmask_dst = regmask;
848     op->regmask_src |= regmask;
849     if (op->operand[0].lmod == OPLM_UNSPEC)
850       op->operand[0].lmod = OPLM_DWORD;
851     break;
852
853   case OP_SHL:
854   case OP_SHR:
855   case OP_SAR:
856   case OP_ROL:
857   case OP_ROR:
858     if (op->operand[1].lmod == OPLM_UNSPEC)
859       op->operand[1].lmod = OPLM_BYTE;
860     break;
861
862   default:
863     break;
864   }
865 }
866
867 static const char *op_name(enum op_op op)
868 {
869   int i;
870
871   for (i = 0; i < ARRAY_SIZE(op_table); i++)
872     if (op_table[i].op == op)
873       return op_table[i].name;
874
875   return "???";
876 }
877
878 // debug
879 static const char *dump_op(struct parsed_op *po)
880 {
881   static char out[128];
882   char *p = out;
883   int i;
884
885   snprintf(out, sizeof(out), "%s", op_name(po->op));
886   for (i = 0; i < po->operand_cnt; i++) {
887     p += strlen(p);
888     if (i > 0)
889       *p++ = ',';
890     snprintf(p, sizeof(out) - (p - out),
891       po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
892       po->operand[i].name);
893   }
894
895   return out;
896 }
897
898 static const char *lmod_cast_u(struct parsed_op *po,
899   enum opr_lenmod lmod)
900 {
901   switch (lmod) {
902   case OPLM_DWORD:
903     return "";
904   case OPLM_WORD:
905     return "(u16)";
906   case OPLM_BYTE:
907     return "(u8)";
908   default:
909     ferr(po, "invalid lmod: %d\n", lmod);
910     return "(_invalid_)";
911   }
912 }
913
914 static const char *lmod_cast_u_ptr(struct parsed_op *po,
915   enum opr_lenmod lmod)
916 {
917   switch (lmod) {
918   case OPLM_DWORD:
919     return "*(u32 *)";
920   case OPLM_WORD:
921     return "*(u16 *)";
922   case OPLM_BYTE:
923     return "*(u8 *)";
924   default:
925     ferr(po, "invalid lmod: %d\n", lmod);
926     return "(_invalid_)";
927   }
928 }
929
930 static const char *lmod_cast_s(struct parsed_op *po,
931   enum opr_lenmod lmod)
932 {
933   switch (lmod) {
934   case OPLM_DWORD:
935     return "(s32)";
936   case OPLM_WORD:
937     return "(s16)";
938   case OPLM_BYTE:
939     return "(s8)";
940   default:
941     ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
942     return "(_invalid_)";
943   }
944 }
945
946 static const char *lmod_cast(struct parsed_op *po,
947   enum opr_lenmod lmod, int is_signed)
948 {
949   return is_signed ?
950     lmod_cast_s(po, lmod) :
951     lmod_cast_u(po, lmod);
952 }
953
954 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
955 {
956   switch (lmod) {
957   case OPLM_DWORD:
958     return 4;
959   case OPLM_WORD:
960     return 2;
961   case OPLM_BYTE:
962     return 1;
963   default:
964     ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
965     return 0;
966   }
967 }
968
969 static const char *opr_name(struct parsed_op *po, int opr_num)
970 {
971   if (opr_num >= po->operand_cnt)
972     ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
973   return po->operand[opr_num].name;
974 }
975
976 static unsigned int opr_const(struct parsed_op *po, int opr_num)
977 {
978   if (opr_num >= po->operand_cnt)
979     ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
980   if (po->operand[opr_num].type != OPT_CONST)
981     ferr(po, "opr %d: const expected\n", opr_num);
982   return po->operand[opr_num].val;
983 }
984
985 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
986 {
987   if ((unsigned int)popr->reg >= MAX_REGS)
988     ferr(po, "invalid reg: %d\n", popr->reg);
989   return regs_r32[popr->reg];
990 }
991
992 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
993   int *extra_offs)
994 {
995   const char *p;
996   char *endp;
997   int namelen;
998   int i;
999
1000   *extra_offs = 0;
1001   namelen = strlen(name);
1002
1003   p = strchr(name, '+');
1004   if (p != NULL) {
1005     namelen = p - name;
1006     if (namelen <= 0)
1007       ferr(po, "equ parse failed for '%s'\n", name);
1008
1009     if (IS_START(p, "0x"))
1010       p += 2;
1011     *extra_offs = strtol(p, &endp, 16);
1012     if (*endp != 0)
1013       ferr(po, "equ parse failed for '%s'\n", name);
1014   }
1015
1016   for (i = 0; i < g_eqcnt; i++)
1017     if (strncmp(g_eqs[i].name, name, namelen) == 0
1018      && g_eqs[i].name[namelen] == 0)
1019       break;
1020   if (i >= g_eqcnt) {
1021     if (po != NULL)
1022       ferr(po, "unresolved equ name: '%s'\n", name);
1023     return NULL;
1024   }
1025
1026   return &g_eqs[i];
1027 }
1028
1029 static void stack_frame_access(struct parsed_op *po,
1030   enum opr_lenmod lmod, char *buf, size_t buf_size,
1031   const char *name, int is_src, int is_lea)
1032 {
1033   const char *prefix = "";
1034   struct parsed_equ *eq;
1035   int i, arg_i, arg_s;
1036   const char *bp_arg;
1037   int stack_ra = 0;
1038   int offset = 0;
1039   int sf_ofs;
1040
1041   bp_arg = parse_stack_el(name);
1042   snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1043   eq = equ_find(po, bp_arg, &offset);
1044   if (eq == NULL)
1045     ferr(po, "detected but missing eq\n");
1046
1047   offset += eq->offset;
1048
1049   if (!strncmp(name, "ebp", 3))
1050     stack_ra = 4;
1051
1052   if (stack_ra <= offset && offset < stack_ra + 4)
1053     ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1054
1055   if (offset > stack_ra) {
1056     arg_i = (offset - stack_ra - 4) / 4;
1057     if (arg_i < 0 || arg_i >= g_func_pp.argc_stack)
1058       ferr(po, "offset %d (%s) doesn't map to any arg\n",
1059         offset, bp_arg);
1060
1061     for (i = arg_s = 0; i < g_func_pp.argc; i++) {
1062       if (g_func_pp.arg[i].reg != NULL)
1063         continue;
1064       if (arg_s == arg_i)
1065         break;
1066       arg_s++;
1067     }
1068     if (i == g_func_pp.argc)
1069       ferr(po, "arg %d not in prototype?\n", arg_i);
1070     if (is_lea)
1071       ferr(po, "lea to arg?\n");
1072
1073     snprintf(buf, buf_size, "%sa%d", is_src ? "(u32)" : "", i + 1);
1074   }
1075   else {
1076     if (g_stack_fsz == 0)
1077       ferr(po, "stack var access without stackframe\n");
1078
1079     sf_ofs = g_stack_fsz + offset;
1080     if (sf_ofs < 0)
1081       ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
1082
1083     if (is_lea)
1084       prefix = "(u32)&";
1085
1086     switch (lmod)
1087     {
1088     case OPLM_BYTE:
1089       snprintf(buf, buf_size, "%ssf.b[%d]", prefix, sf_ofs);
1090       break;
1091     case OPLM_WORD:
1092       snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
1093       break;
1094     case OPLM_DWORD:
1095       snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
1096       break;
1097     default:
1098       ferr(po, "bp_stack bad lmod: %d\n", lmod);
1099     }
1100   }
1101 }
1102
1103 static char *out_src_opr(char *buf, size_t buf_size,
1104         struct parsed_op *po, struct parsed_opr *popr, int is_lea)
1105 {
1106   char tmp1[256], tmp2[256];
1107   char expr[256];
1108   int ret;
1109
1110   switch (popr->type) {
1111   case OPT_REG:
1112     if (is_lea)
1113       ferr(po, "lea from reg?\n");
1114
1115     switch (popr->lmod) {
1116     case OPLM_DWORD:
1117       snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
1118       break;
1119     case OPLM_WORD:
1120       snprintf(buf, buf_size, "(u16)%s", opr_reg_p(po, popr));
1121       break;
1122     case OPLM_BYTE:
1123       if (popr->name[1] == 'h') // XXX..
1124         snprintf(buf, buf_size, "(u8)(%s >> 8)", opr_reg_p(po, popr));
1125       else
1126         snprintf(buf, buf_size, "(u8)%s", opr_reg_p(po, popr));
1127       break;
1128     default:
1129       ferr(po, "invalid src lmod: %d\n", popr->lmod);
1130     }
1131     break;
1132
1133   case OPT_REGMEM:
1134     if (parse_stack_el(popr->name)) {
1135       stack_frame_access(po, popr->lmod, buf, buf_size,
1136         popr->name, 1, is_lea);
1137       break;
1138     }
1139
1140     strcpy(expr, popr->name);
1141     if (strchr(expr, '[')) {
1142       // special case: '[' can only be left for label[reg] form
1143       ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
1144       if (ret != 2)
1145         ferr(po, "parse failure for '%s'\n", expr);
1146       snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
1147     }
1148
1149     // XXX: do we need more parsing?
1150     if (is_lea) {
1151       snprintf(buf, buf_size, "%s", expr);
1152       break;
1153     }
1154
1155     snprintf(buf, buf_size, "%s(%s)",
1156       lmod_cast_u_ptr(po, popr->lmod), expr);
1157     break;
1158
1159   case OPT_LABEL:
1160     if (is_lea)
1161       snprintf(buf, buf_size, "(u32)&%s", popr->name);
1162     else
1163       snprintf(buf, buf_size, "(u32)%s", popr->name);
1164     break;
1165
1166   case OPT_OFFSET:
1167     if (is_lea)
1168       ferr(po, "lea an offset?\n");
1169     snprintf(buf, buf_size, "(u32)&%s", popr->name);
1170     break;
1171
1172   case OPT_CONST:
1173     if (is_lea)
1174       ferr(po, "lea from const?\n");
1175
1176     printf_number(buf, buf_size, popr->val);
1177     break;
1178
1179   default:
1180     ferr(po, "invalid src type: %d\n", popr->type);
1181   }
1182
1183   return buf;
1184 }
1185
1186 static char *out_dst_opr(char *buf, size_t buf_size,
1187         struct parsed_op *po, struct parsed_opr *popr)
1188 {
1189   switch (popr->type) {
1190   case OPT_REG:
1191     switch (popr->lmod) {
1192     case OPLM_DWORD:
1193       snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
1194       break;
1195     case OPLM_WORD:
1196       // ugh..
1197       snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
1198       break;
1199     case OPLM_BYTE:
1200       // ugh..
1201       if (popr->name[1] == 'h') // XXX..
1202         snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
1203       else
1204         snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
1205       break;
1206     default:
1207       ferr(po, "invalid dst lmod: %d\n", popr->lmod);
1208     }
1209     break;
1210
1211   case OPT_REGMEM:
1212     if (parse_stack_el(popr->name)) {
1213       stack_frame_access(po, popr->lmod, buf, buf_size,
1214         popr->name, 0, 0);
1215       break;
1216     }
1217
1218     return out_src_opr(buf, buf_size, po, popr, 0);
1219
1220   case OPT_LABEL:
1221     snprintf(buf, buf_size, "%s", popr->name);
1222     break;
1223
1224   default:
1225     ferr(po, "invalid dst type: %d\n", popr->type);
1226   }
1227
1228   return buf;
1229 }
1230
1231 static enum parsed_flag_op split_cond(struct parsed_op *po,
1232   enum op_op op, int *is_inv)
1233 {
1234   *is_inv = 0;
1235
1236   switch (op) {
1237   case OP_JO:
1238     return PFO_O;
1239   case OP_JC:
1240     return PFO_C;
1241   case OP_JZ:
1242     return PFO_Z;
1243   case OP_JBE:
1244     return PFO_BE;
1245   case OP_JS:
1246     return PFO_S;
1247   case OP_JP:
1248     return PFO_P;
1249   case OP_JL:
1250     return PFO_L;
1251   case OP_JLE:
1252     return PFO_LE;
1253
1254   case OP_JNO:
1255     *is_inv = 1;
1256     return PFO_O;
1257   case OP_JNC:
1258     *is_inv = 1;
1259     return PFO_C;
1260   case OP_JNZ:
1261     *is_inv = 1;
1262     return PFO_Z;
1263   case OP_JA:
1264     *is_inv = 1;
1265     return PFO_BE;
1266   case OP_JNS:
1267     *is_inv = 1;
1268     return PFO_S;
1269   case OP_JNP:
1270     *is_inv = 1;
1271     return PFO_P;
1272   case OP_JGE:
1273     *is_inv = 1;
1274     return PFO_L;
1275   case OP_JG:
1276     *is_inv = 1;
1277     return PFO_LE;
1278
1279   case OP_ADC:
1280   case OP_SBB:
1281     return PFO_C;
1282
1283   default:
1284     ferr(po, "split_cond: bad op %d\n", op);
1285     return -1;
1286   }
1287 }
1288
1289 static void out_test_for_cc(char *buf, size_t buf_size,
1290   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
1291   enum opr_lenmod lmod, const char *expr)
1292 {
1293   const char *cast, *scast;
1294
1295   cast = lmod_cast_u(po, lmod);
1296   scast = lmod_cast_s(po, lmod);
1297
1298   switch (pfo) {
1299   case PFO_Z:
1300   case PFO_BE: // CF=1||ZF=1; CF=0
1301     snprintf(buf, buf_size, "(%s%s %s 0)",
1302       cast, expr, is_inv ? "!=" : "==");
1303     break;
1304
1305   case PFO_S:
1306   case PFO_L: // SF!=OF; OF=0
1307     snprintf(buf, buf_size, "(%s%s %s 0)",
1308       scast, expr, is_inv ? ">=" : "<");
1309     break;
1310
1311   case PFO_LE: // ZF=1||SF!=OF; OF=0
1312     snprintf(buf, buf_size, "(%s%s %s 0)",
1313       scast, expr, is_inv ? ">" : "<=");
1314     break;
1315
1316   default:
1317     ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
1318   }
1319 }
1320
1321 static void out_cmp_for_cc(char *buf, size_t buf_size,
1322   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
1323   enum opr_lenmod lmod, const char *expr1, const char *expr2)
1324 {
1325   const char *cast, *scast;
1326
1327   cast = lmod_cast_u(po, lmod);
1328   scast = lmod_cast_s(po, lmod);
1329
1330   switch (pfo) {
1331   case PFO_C:
1332     // note: must be unsigned compare
1333     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1334       cast, expr1, is_inv ? ">=" : "<", cast, expr2);
1335     break;
1336
1337   case PFO_Z:
1338     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1339       cast, expr1, is_inv ? "!=" : "==", cast, expr2);
1340     break;
1341
1342   case PFO_BE: // !a
1343     // note: must be unsigned compare
1344     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1345       cast, expr1, is_inv ? ">" : "<=", cast, expr2);
1346     break;
1347
1348   // note: must be signed compare
1349   case PFO_S:
1350     snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
1351       scast, expr1, expr2, is_inv ? ">=" : "<");
1352     break;
1353
1354   case PFO_L: // !ge
1355     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1356       scast, expr1, is_inv ? ">=" : "<", scast, expr2);
1357     break;
1358
1359   case PFO_LE:
1360     snprintf(buf, buf_size, "(%s%s %s %s%s)",
1361       scast, expr1, is_inv ? ">" : "<=", scast, expr2);
1362     break;
1363
1364   default:
1365     ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
1366   }
1367 }
1368
1369 static void out_cmp_test(char *buf, size_t buf_size,
1370   struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
1371 {
1372   char buf1[256], buf2[256], buf3[256];
1373
1374   if (po->op == OP_TEST) {
1375     if (IS(opr_name(po, 0), opr_name(po, 1))) {
1376       out_src_opr(buf3, sizeof(buf3), po, &po->operand[0], 0);
1377     }
1378     else {
1379       out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
1380       out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0);
1381       snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
1382     }
1383     out_test_for_cc(buf, buf_size, po, pfo, is_inv,
1384       po->operand[0].lmod, buf3);
1385   }
1386   else if (po->op == OP_CMP) {
1387     out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], 0);
1388     out_src_opr(buf3, sizeof(buf3), po, &po->operand[1], 0);
1389     out_cmp_for_cc(buf, buf_size, po, pfo, is_inv,
1390       po->operand[0].lmod, buf2, buf3);
1391   }
1392   else
1393     ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
1394 }
1395
1396 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
1397         struct parsed_opr *popr2)
1398 {
1399   if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
1400     ferr(po, "missing lmod for both operands\n");
1401
1402   if (popr1->lmod == OPLM_UNSPEC)
1403     popr1->lmod = popr2->lmod;
1404   else if (popr2->lmod == OPLM_UNSPEC)
1405     popr2->lmod = popr1->lmod;
1406   else if (popr1->lmod != popr2->lmod)
1407     ferr(po, "conflicting lmods: %d vs %d\n", popr1->lmod, popr2->lmod);
1408 }
1409
1410 static const char *op_to_c(struct parsed_op *po)
1411 {
1412   switch (po->op)
1413   {
1414     case OP_ADD:
1415     case OP_ADC:
1416       return "+";
1417     case OP_SUB:
1418     case OP_SBB:
1419       return "-";
1420     case OP_AND:
1421       return "&";
1422     case OP_OR:
1423       return "|";
1424     case OP_XOR:
1425       return "^";
1426     case OP_SHL:
1427       return "<<";
1428     case OP_SHR:
1429       return ">>";
1430     case OP_MUL:
1431     case OP_IMUL:
1432       return "*";
1433     default:
1434       ferr(po, "op_to_c was supplied with %d\n", po->op);
1435   }
1436 }
1437
1438 static void set_flag_no_dup(struct parsed_op *po, enum op_flags flag,
1439   enum op_flags flag_check)
1440 {
1441   if (po->flags & flag)
1442     ferr(po, "flag %x already set\n", flag);
1443   if (po->flags & flag_check)
1444     ferr(po, "flag_check %x already set\n", flag_check);
1445
1446   po->flags |= flag;
1447 }
1448
1449 static int scan_for_pop(int i, int opcnt, const char *reg,
1450   int magic, int depth, int *maxdepth, int do_flags)
1451 {
1452   struct parsed_op *po;
1453   int ret = 0;
1454
1455   for (; i < opcnt; i++) {
1456     po = &ops[i];
1457     if (po->cc_scratch == magic)
1458       break; // already checked
1459     po->cc_scratch = magic;
1460
1461     if (po->flags & OPF_TAIL)
1462       return -1; // deadend
1463
1464     if ((po->flags & OPF_RMD)
1465         || (po->op == OP_PUSH && po->argmask)) // arg push
1466       continue;
1467
1468     if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
1469       if (po->bt_i < 0) {
1470         ferr(po, "dead branch\n");
1471         return -1;
1472       }
1473
1474       if (po->flags & OPF_CC) {
1475         ret |= scan_for_pop(po->bt_i, opcnt, reg, magic,
1476                  depth, maxdepth, do_flags);
1477         if (ret < 0)
1478           return ret; // dead end
1479       }
1480       else {
1481         i = po->bt_i - 1;
1482       }
1483       continue;
1484     }
1485
1486     if ((po->op == OP_POP || po->op == OP_PUSH)
1487         && po->operand[0].type == OPT_REG
1488         && IS(po->operand[0].name, reg))
1489     {
1490       if (po->op == OP_PUSH) {
1491         depth++;
1492         if (depth > *maxdepth)
1493           *maxdepth = depth;
1494         if (do_flags)
1495           set_flag_no_dup(po, OPF_RSAVE, OPF_RMD);
1496       }
1497       else if (depth == 0) {
1498         if (do_flags)
1499           set_flag_no_dup(po, OPF_RMD, OPF_RSAVE);
1500         return 1;
1501       }
1502       else {
1503         depth--;
1504         if (depth < 0) // should not happen
1505           ferr(po, "fail with depth\n");
1506         if (do_flags)
1507           set_flag_no_dup(po, OPF_RSAVE, OPF_RMD);
1508       }
1509     }
1510   }
1511
1512   return ret;
1513 }
1514
1515 // scan for pop starting from 'ret' op (all paths)
1516 static int scan_for_pop_ret(int i, int opcnt, const char *reg,
1517   int flag_set)
1518 {
1519   int found = 0;
1520   int j;
1521
1522   for (; i < opcnt; i++) {
1523     if (!(ops[i].flags & OPF_TAIL))
1524       continue;
1525
1526     for (j = i - 1; j >= 0; j--) {
1527       if (ops[j].flags & OPF_RMD)
1528         continue;
1529       if (ops[j].flags & OPF_JMP)
1530         return -1;
1531
1532       if (ops[j].op == OP_POP && ops[j].operand[0].type == OPT_REG
1533           && IS(ops[j].operand[0].name, reg))
1534       {
1535         found = 1;
1536         ops[j].flags |= flag_set;
1537         break;
1538       }
1539
1540       if (g_labels[j][0] != 0)
1541         return -1;
1542     }
1543   }
1544
1545   return found ? 0 : -1;
1546 }
1547
1548 // is operand 'opr modified' by parsed_op 'po'?
1549 static int is_opr_modified(const struct parsed_opr *opr,
1550   const struct parsed_op *po)
1551 {
1552   if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
1553     return 0;
1554
1555   if (opr->type == OPT_REG && po->operand[0].type == OPT_REG) {
1556     if (po->regmask_dst & (1 << opr->reg))
1557       return 1;
1558     else
1559       return 0;
1560   }
1561
1562   return IS(po->operand[0].name, opr->name);
1563 }
1564
1565 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
1566 static int is_any_opr_modified(const struct parsed_op *po_test,
1567   const struct parsed_op *po)
1568 {
1569   int i;
1570
1571   if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
1572     return 0;
1573
1574   if (po_test->regmask_src & po->regmask_dst)
1575     return 1;
1576
1577   for (i = 0; i < po_test->operand_cnt; i++)
1578     if (IS(po_test->operand[i].name, po->operand[0].name))
1579       return 1;
1580
1581   return 0;
1582 }
1583
1584 // scan for any po_test operand modification in range given
1585 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt)
1586 {
1587   for (; i < opcnt; i++) {
1588     if (is_any_opr_modified(po_test, &ops[i]))
1589       return i;
1590   }
1591
1592   return -1;
1593 }
1594
1595 // scan for po_test operand[0] modification in range given
1596 static int scan_for_mod_opr0(struct parsed_op *po_test,
1597   int i, int opcnt)
1598 {
1599   for (; i < opcnt; i++) {
1600     if (is_opr_modified(&po_test->operand[0], &ops[i]))
1601       return i;
1602   }
1603
1604   return -1;
1605 }
1606
1607 static int scan_for_flag_set(int i)
1608 {
1609   for (; i >= 0; i--) {
1610     if (ops[i].flags & OPF_FLAGS)
1611       return i;
1612
1613     if ((ops[i].flags & OPF_JMP) && !(ops[i].flags & OPF_CC))
1614       return -1;
1615     if (g_labels[i][0] != 0)
1616       return -1;
1617   }
1618
1619   return -1;
1620 }
1621
1622 // scan back for cdq, if anything modifies edx, fail
1623 static int scan_for_cdq_edx(int i)
1624 {
1625   for (; i >= 0; i--) {
1626     if (ops[i].op == OP_CDQ)
1627       return i;
1628
1629     if (ops[i].regmask_dst & (1 << xDX))
1630       return -1;
1631     if (g_labels[i][0] != 0)
1632       return -1;
1633   }
1634
1635   return -1;
1636 }
1637
1638 // scan for positive, constant esp adjust
1639 static int scan_for_esp_adjust(int i, int opcnt, int *adj)
1640 {
1641   for (; i < opcnt; i++) {
1642     if (ops[i].op == OP_ADD && ops[i].operand[0].reg == xSP) {
1643       if (ops[i].operand[1].type != OPT_CONST)
1644         ferr(&ops[i], "non-const esp adjust?\n");
1645       *adj = ops[i].operand[1].val;
1646       if (*adj & 3)
1647         ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
1648       return i;
1649     }
1650
1651     if ((ops[i].flags & (OPF_JMP|OPF_TAIL))
1652          || ops[i].op == OP_PUSH || ops[i].op == OP_POP)
1653       return -1;
1654     if (g_labels[i][0] != 0)
1655       return -1;
1656   }
1657
1658   return -1;
1659 }
1660
1661 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
1662 {
1663   struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
1664   struct parsed_opr *last_arith_dst = NULL;
1665   char buf1[256], buf2[256], buf3[256];
1666   struct parsed_proto *pp, *pp_tmp;
1667   const char *tmpname;
1668   enum parsed_flag_op pfo;
1669   int save_arg_vars = 0;
1670   int cmp_result_vars = 0;
1671   int need_mul_var = 0;
1672   int had_decl = 0;
1673   int regmask_save = 0;
1674   int regmask_arg = 0;
1675   int regmask = 0;
1676   int pfomask = 0;
1677   int depth = 0;
1678   int no_output;
1679   int dummy;
1680   int arg;
1681   int i, j;
1682   int reg;
1683   int ret;
1684
1685   g_bp_frame = g_sp_frame = g_stack_fsz = 0;
1686
1687   ret = proto_parse(fhdr, funcn, &g_func_pp);
1688   if (ret)
1689     ferr(ops, "proto_parse failed for '%s'\n", funcn);
1690
1691   fprintf(fout, "%s %s(", g_func_pp.ret_type, funcn);
1692   for (i = 0; i < g_func_pp.argc; i++) {
1693     if (i > 0)
1694       fprintf(fout, ", ");
1695     fprintf(fout, "%s a%d", g_func_pp.arg[i].type, i + 1);
1696   }
1697   fprintf(fout, ")\n{\n");
1698
1699   // pass1:
1700   // - handle ebp/esp frame, remove ops related to it
1701   if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
1702       && ops[1].op == OP_MOV
1703       && IS(opr_name(&ops[1], 0), "ebp")
1704       && IS(opr_name(&ops[1], 1), "esp"))
1705   {
1706     int ecx_push = 0;
1707
1708     g_bp_frame = 1;
1709     ops[0].flags |= OPF_RMD;
1710     ops[1].flags |= OPF_RMD;
1711
1712     if (ops[2].op == OP_SUB && IS(opr_name(&ops[2], 0), "esp")) {
1713       g_stack_fsz = opr_const(&ops[2], 1);
1714       ops[2].flags |= OPF_RMD;
1715     }
1716     else {
1717       // another way msvc builds stack frame..
1718       i = 2;
1719       while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
1720         g_stack_fsz += 4;
1721         ops[i].flags |= OPF_RMD;
1722         ecx_push++;
1723         i++;
1724       }
1725     }
1726
1727     i = 2;
1728     do {
1729       for (; i < opcnt; i++)
1730         if (ops[i].op == OP_RET)
1731           break;
1732       if (ops[i - 1].op != OP_POP || !IS(opr_name(&ops[i - 1], 0), "ebp"))
1733         ferr(&ops[i - 1], "'pop ebp' expected\n");
1734       ops[i - 1].flags |= OPF_RMD;
1735
1736       if (g_stack_fsz != 0) {
1737         if (ops[i - 2].op != OP_MOV
1738             || !IS(opr_name(&ops[i - 2], 0), "esp")
1739             || !IS(opr_name(&ops[i - 2], 1), "ebp"))
1740         {
1741           ferr(&ops[i - 2], "esp restore expected\n");
1742         }
1743         ops[i - 2].flags |= OPF_RMD;
1744
1745         if (ecx_push && ops[i - 3].op == OP_POP
1746           && IS(opr_name(&ops[i - 3], 0), "ecx"))
1747         {
1748           ferr(&ops[i - 3], "unexpected ecx pop\n");
1749         }
1750       }
1751
1752       i++;
1753     } while (i < opcnt);
1754   }
1755   else {
1756     for (i = 0; i < opcnt; i++) {
1757       if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
1758         break;
1759       if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
1760         && ops[i].operand[1].type == OPT_CONST)
1761       {
1762         g_sp_frame = 1;
1763         break;
1764       }
1765     }
1766
1767     if (g_sp_frame)
1768     {
1769       g_stack_fsz = ops[i].operand[1].val;
1770       ops[i].flags |= OPF_RMD;
1771
1772       i++;
1773       do {
1774         for (; i < opcnt; i++)
1775           if (ops[i].op == OP_RET)
1776             break;
1777         if (ops[i - 1].op != OP_ADD
1778             || !IS(opr_name(&ops[i - 1], 0), "esp")
1779             || ops[i - 1].operand[1].type != OPT_CONST
1780             || ops[i - 1].operand[1].val != g_stack_fsz)
1781           ferr(&ops[i - 1], "'add esp' expected\n");
1782         ops[i - 1].flags |= OPF_RMD;
1783
1784         i++;
1785       } while (i < opcnt);
1786     }
1787   }
1788
1789   // pass2:
1790   // - resolve all branches
1791   for (i = 0; i < opcnt; i++) {
1792     po = &ops[i];
1793     po->bt_i = -1;
1794
1795     if ((po->flags & OPF_RMD) || !(po->flags & OPF_JMP)
1796         || po->op == OP_CALL || po->op == OP_RET)
1797       continue;
1798
1799     for (j = 0; j < opcnt; j++) {
1800       if (g_labels[j][0] && IS(po->operand[0].name, g_labels[j])) {
1801         po->bt_i = j;
1802         po->lrl = g_label_refs[j];
1803         g_label_refs[j] = po;
1804         break;
1805       }
1806     }
1807
1808     if (po->bt_i == -1) {
1809       // assume tail call
1810       po->op = OP_CALL;
1811       po->flags |= OPF_TAIL;
1812     }
1813   }
1814
1815   // pass3:
1816   // - process calls
1817   for (i = 0; i < opcnt; i++)
1818   {
1819     po = &ops[i];
1820     if (po->flags & OPF_RMD)
1821       continue;
1822
1823     if (po->op == OP_CALL)
1824     {
1825       pp = calloc(1, sizeof(*pp));
1826       my_assert_not(pp, NULL);
1827       tmpname = opr_name(po, 0);
1828       if (po->operand[0].type != OPT_LABEL)
1829       {
1830         ret = scan_for_esp_adjust(i + 1, opcnt, &j);
1831         if (ret < 0)
1832           ferr(po, "non-__cdecl indirect call unhandled yet\n");
1833         j /= 4;
1834         if (j > ARRAY_SIZE(pp->arg))
1835           ferr(po, "esp adjust too large?\n");
1836         pp->ret_type = "int";
1837         pp->argc = pp->argc_stack = j;
1838         for (arg = 0; arg < pp->argc; arg++)
1839           pp->arg[arg].type = "int";
1840       }
1841       else {
1842         ret = proto_parse(fhdr, tmpname, pp);
1843         if (ret)
1844           ferr(po, "proto_parse failed for call '%s'\n", tmpname);
1845       }
1846
1847       ret = scan_for_esp_adjust(i + 1, opcnt, &j);
1848       if (ret >= 0) {
1849         if (pp->argc_stack != j / 4)
1850           ferr(po, "stack tracking failed: %x %x\n",
1851             pp->argc_stack, j);
1852         ops[ret].flags |= OPF_RMD;
1853       }
1854
1855       // can't call functions with non-__cdecl callbacks yet
1856       for (arg = 0; arg < pp->argc; arg++) {
1857         if (pp->arg[arg].fptr != NULL) {
1858           pp_tmp = pp->arg[arg].fptr;
1859           if (pp_tmp->is_stdcall || pp_tmp->argc != pp_tmp->argc_stack)
1860             ferr(po, "'%s' has a non-__cdecl callback\n", tmpname);
1861         }
1862       }
1863
1864       for (arg = 0; arg < pp->argc; arg++)
1865         if (pp->arg[arg].reg == NULL)
1866           break;
1867
1868       for (j = i; j >= 0 && arg < pp->argc; )
1869       {
1870         if (g_labels[j][0] != 0) {
1871           if (j > 0 && ((ops[j - 1].flags & OPF_TAIL)
1872             || (ops[j - 1].flags & (OPF_JMP|OPF_CC)) == OPF_JMP))
1873           {
1874             // follow the branch in reverse
1875             if (g_label_refs[j] == NULL)
1876               ferr(po, "no refs for '%s'?\n", g_labels[j]);
1877             if (g_label_refs[j]->lrl != NULL)
1878               ferr(po, "unhandled multiple fefs to '%s'\n", g_labels[j]);
1879             j = (g_label_refs[j] - ops) + 1;
1880             continue;
1881           }
1882           break;
1883         }
1884         j--;
1885
1886         if (ops[j].op == OP_CALL)
1887         {
1888           pp_tmp = ops[j].datap;
1889           if (pp_tmp == NULL)
1890             ferr(po, "arg collect hit unparsed call\n");
1891           if (pp_tmp->argc_stack > 0)
1892             ferr(po, "arg collect hit '%s' with %d stack args\n",
1893               opr_name(&ops[j], 0), pp_tmp->argc_stack);
1894         }
1895         else if ((ops[j].flags & OPF_TAIL)
1896             || (ops[j].flags & (OPF_JMP|OPF_CC)) == OPF_JMP)
1897         {
1898           break;
1899         }
1900         else if (ops[j].op == OP_PUSH)
1901         {
1902           pp->arg[arg].datap = &ops[j];
1903           ret = scan_for_mod(&ops[j], j + 1, i);
1904           if (ret >= 0) {
1905             // mark this push as one that needs operand saving
1906             ops[j].flags &= ~OPF_RMD;
1907             ops[j].argmask |= 1 << arg;
1908             save_arg_vars |= 1 << arg;
1909           }
1910           else
1911             ops[j].flags |= OPF_RMD;
1912
1913           // next arg
1914           for (arg++; arg < pp->argc; arg++)
1915             if (pp->arg[arg].reg == NULL)
1916               break;
1917         }
1918       }
1919       if (arg < pp->argc)
1920         ferr(po, "arg collect failed for '%s'\n", tmpname);
1921       po->datap = pp;
1922     }
1923   }
1924
1925   // pass4:
1926   // - find POPs for PUSHes, rm both
1927   // - scan for all used registers
1928   // - find flag set ops for their users
1929   // - declare indirect functions
1930   for (i = 0; i < opcnt; i++) {
1931     po = &ops[i];
1932     if (po->flags & OPF_RMD)
1933       continue;
1934
1935     if (po->op == OP_PUSH
1936         && po->argmask == 0 && !(po->flags & OPF_RSAVE)
1937         && po->operand[0].type == OPT_REG)
1938     {
1939       reg = po->operand[0].reg;
1940       if (reg < 0)
1941         ferr(po, "reg not set for push?\n");
1942
1943       depth = 0;
1944       ret = scan_for_pop(i + 1, opcnt,
1945               po->operand[0].name, i + opcnt, 0, &depth, 0);
1946       if (ret == 1) {
1947         if (depth > 1)
1948           ferr(po, "too much depth: %d\n", depth);
1949         if (depth > 0)
1950           regmask_save |= 1 << reg;
1951
1952         po->flags |= OPF_RMD;
1953         scan_for_pop(i + 1, opcnt, po->operand[0].name,
1954           i + opcnt * 2, 0, &depth, 1);
1955         continue;
1956       }
1957       ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].name, 0);
1958       if (ret == 0) {
1959         arg = OPF_RMD;
1960         if (regmask & (1 << reg)) {
1961           if (regmask_save & (1 << reg))
1962             ferr(po, "%s already saved?\n", po->operand[0].name);
1963           arg = OPF_RSAVE;
1964         }
1965         po->flags |= arg;
1966         scan_for_pop_ret(i + 1, opcnt, po->operand[0].name, arg);
1967         continue;
1968       }
1969     }
1970
1971     regmask |= po->regmask_src | po->regmask_dst;
1972
1973     if (po->flags & OPF_CC)
1974     {
1975       ret = scan_for_flag_set(i - 1);
1976       if (ret < 0)
1977         ferr(po, "unable to trace flag setter\n");
1978
1979       tmp_op = &ops[ret]; // flag setter
1980       pfo = split_cond(po, po->op, &dummy);
1981       pfomask = 0;
1982
1983       // to get nicer code, we try to delay test and cmp;
1984       // if we can't because of operand modification, or if we
1985       // have math op, make it calculate flags explicitly
1986       if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP) {
1987         if (scan_for_mod(tmp_op, ret + 1, i) >= 0)
1988           pfomask = 1 << pfo;
1989       }
1990       else {
1991         if ((pfo != PFO_Z && pfo != PFO_S && pfo != PFO_P)
1992             || scan_for_mod_opr0(tmp_op, ret + 1, i) >= 0)
1993           pfomask = 1 << pfo;
1994       }
1995       if (pfomask) {
1996         tmp_op->pfomask |= pfomask;
1997         cmp_result_vars |= pfomask;
1998         po->datap = tmp_op;
1999       }
2000
2001       if (po->op == OP_ADC || po->op == OP_SBB)
2002         cmp_result_vars |= 1 << PFO_C;
2003     }
2004     else if (po->op == OP_MUL
2005       || (po->op == OP_IMUL && po->operand_cnt == 1))
2006     {
2007       need_mul_var = 1;
2008     }
2009     else if (po->op == OP_CALL && po->operand[0].type != OPT_LABEL) {
2010       pp = po->datap;
2011       my_assert_not(pp, NULL);
2012       fprintf(fout, "  %s (*icall%d)(", pp->ret_type, i);
2013       for (j = 0; j < pp->argc; j++) {
2014         if (j > 0)
2015           fprintf(fout, ", ");
2016         fprintf(fout, "%s a%d", pp->arg[j].type, j + 1);
2017       }
2018       fprintf(fout, ");\n");
2019     }
2020   }
2021
2022   // declare stack frame
2023   if (g_stack_fsz)
2024     fprintf(fout, "  union { u32 d[%d]; u16 w[%d]; u8 b[%d]; } sf;\n",
2025       (g_stack_fsz + 3) / 4, (g_stack_fsz + 1) / 2, g_stack_fsz);
2026
2027   // declare arg-registers
2028   for (i = 0; i < g_func_pp.argc; i++) {
2029     if (g_func_pp.arg[i].reg != NULL) {
2030       reg = char_array_i(regs_r32,
2031               ARRAY_SIZE(regs_r32), g_func_pp.arg[i].reg);
2032       if (reg < 0)
2033         ferr(ops, "arg '%s' is not a reg?\n", g_func_pp.arg[i].reg);
2034
2035       regmask_arg |= 1 << reg;
2036       fprintf(fout, "  u32 %s = (u32)a%d;\n",
2037         g_func_pp.arg[i].reg, i + 1);
2038       had_decl = 1;
2039     }
2040   }
2041
2042   // declare other regs - special case for eax
2043   if (!((regmask | regmask_arg) & 1) && !IS(g_func_pp.ret_type, "void")) {
2044     fprintf(fout, "  u32 eax = 0;\n");
2045     had_decl = 1;
2046   }
2047
2048   regmask &= ~regmask_arg;
2049   regmask &= ~(1 << xSP);
2050   if (g_bp_frame)
2051     regmask &= ~(1 << xBP);
2052   if (regmask) {
2053     for (reg = 0; reg < 8; reg++) {
2054       if (regmask & (1 << reg)) {
2055         fprintf(fout, "  u32 %s;\n", regs_r32[reg]);
2056         had_decl = 1;
2057       }
2058     }
2059   }
2060
2061   if (regmask_save) {
2062     for (reg = 0; reg < 8; reg++) {
2063       if (regmask_save & (1 << reg)) {
2064         fprintf(fout, "  u32 s_%s;\n", regs_r32[reg]);
2065         had_decl = 1;
2066       }
2067     }
2068   }
2069
2070   if (save_arg_vars) {
2071     for (reg = 0; reg < 32; reg++) {
2072       if (save_arg_vars & (1 << reg)) {
2073         fprintf(fout, "  u32 s_a%d;\n", reg + 1);
2074         had_decl = 1;
2075       }
2076     }
2077   }
2078
2079   if (cmp_result_vars) {
2080     for (i = 0; i < 8; i++) {
2081       if (cmp_result_vars & (1 << i)) {
2082         fprintf(fout, "  u32 cond_%s;\n", parsed_flag_op_names[i]);
2083         had_decl = 1;
2084       }
2085     }
2086   }
2087
2088   if (need_mul_var) {
2089     fprintf(fout, "  u64 mul_tmp;\n");
2090     had_decl = 1;
2091   }
2092
2093   if (had_decl)
2094     fprintf(fout, "\n");
2095
2096   // output ops
2097   for (i = 0; i < opcnt; i++)
2098   {
2099     if (g_labels[i][0] != 0 && g_label_refs[i] != NULL)
2100       fprintf(fout, "\n%s:\n", g_labels[i]);
2101
2102     po = &ops[i];
2103     if (po->flags & OPF_RMD)
2104       continue;
2105
2106     no_output = 0;
2107
2108     #define assert_operand_cnt(n_) \
2109       if (po->operand_cnt != n_) \
2110         ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
2111
2112     // conditional/flag using op?
2113     if (po->flags & OPF_CC)
2114     {
2115       int is_delayed = 0;
2116       int is_inv = 0;
2117
2118       pfo = split_cond(po, po->op, &is_inv);
2119
2120       // we go through all this trouble to avoid using parsed_flag_op,
2121       // which makes generated code much nicer
2122       if (delayed_flag_op != NULL)
2123       {
2124         out_cmp_test(buf1, sizeof(buf1), delayed_flag_op, pfo, is_inv);
2125         is_delayed = 1;
2126       }
2127       else if (last_arith_dst != NULL
2128         && (pfo == PFO_Z || pfo == PFO_S || pfo == PFO_P))
2129       {
2130         out_src_opr(buf3, sizeof(buf3), po, last_arith_dst, 0);
2131         out_test_for_cc(buf1, sizeof(buf1), po, pfo, is_inv,
2132           last_arith_dst->lmod, buf3);
2133         is_delayed = 1;
2134       }
2135       else if (po->datap != NULL) {
2136         // use preprocessed results
2137         tmp_op = po->datap;
2138         if (!tmp_op || !(tmp_op->pfomask & (1 << pfo)))
2139           ferr(po, "not prepared for pfo %d\n", pfo);
2140
2141         // note: is_inv was not yet applied
2142         snprintf(buf1, sizeof(buf1), "(%scond_%s)",
2143           is_inv ? "!" : "", parsed_flag_op_names[pfo]);
2144       }
2145       else {
2146         ferr(po, "all methods of finding comparison failed\n");
2147       }
2148  
2149       if (po->flags & OPF_JMP) {
2150         fprintf(fout, "  if %s\n", buf1);
2151       }
2152       else if (po->op == OP_ADC || po->op == OP_SBB) {
2153         if (is_delayed)
2154           fprintf(fout, "  cond_%s = %s;\n",
2155             parsed_flag_op_names[pfo], buf1);
2156       }
2157       else if (po->flags & OPF_DATA) { // SETcc
2158         out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
2159         fprintf(fout, "  %s = %s;", buf2, buf1);
2160       }
2161       else {
2162         ferr(po, "unhandled conditional op\n");
2163       }
2164     }
2165
2166     pfomask = po->pfomask;
2167
2168     switch (po->op)
2169     {
2170       case OP_MOV:
2171         assert_operand_cnt(2);
2172         propagate_lmod(po, &po->operand[0], &po->operand[1]);
2173         fprintf(fout, "  %s = %s%s;",
2174             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
2175             po->operand[0].is_ptr ? "(void *)" : "",
2176             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
2177         break;
2178
2179       case OP_LEA:
2180         assert_operand_cnt(2);
2181         po->operand[1].lmod = OPLM_DWORD; // always
2182         fprintf(fout, "  %s = %s;",
2183             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
2184             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 1));
2185         break;
2186
2187       case OP_MOVZX:
2188         assert_operand_cnt(2);
2189         fprintf(fout, "  %s = %s;",
2190             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
2191             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
2192         break;
2193
2194       case OP_MOVSX:
2195         assert_operand_cnt(2);
2196         switch (po->operand[1].lmod) {
2197         case OPLM_BYTE:
2198           strcpy(buf3, "(s8)");
2199           break;
2200         case OPLM_WORD:
2201           strcpy(buf3, "(s16)");
2202           break;
2203         default:
2204           ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
2205         }
2206         fprintf(fout, "  %s = %s%s;",
2207             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
2208             buf3,
2209             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
2210         break;
2211
2212       case OP_NOT:
2213         assert_operand_cnt(1);
2214         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
2215         fprintf(fout, "  %s = ~%s;", buf1, buf1);
2216         break;
2217
2218       case OP_CDQ:
2219         assert_operand_cnt(2);
2220         fprintf(fout, "  %s = (s32)%s >> 31;",
2221             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
2222             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
2223         strcpy(g_comment, "cdq");
2224         break;
2225
2226       case OP_STOS:
2227         // assumes DF=0
2228         assert_operand_cnt(3);
2229         if (po->flags & OPF_REP) {
2230           fprintf(fout, "  for (; ecx != 0; ecx--, edi += %d)\n",
2231             lmod_bytes(po, po->operand[0].lmod));
2232           fprintf(fout, "    %sedi = eax;",
2233             lmod_cast_u_ptr(po, po->operand[0].lmod));
2234           strcpy(g_comment, "rep stos");
2235         }
2236         else {
2237           fprintf(fout, "    %sedi = eax; edi += %d;",
2238             lmod_cast_u_ptr(po, po->operand[0].lmod),
2239             lmod_bytes(po, po->operand[0].lmod));
2240           strcpy(g_comment, "stos");
2241         }
2242         break;
2243
2244       case OP_MOVS:
2245         // assumes DF=0
2246         assert_operand_cnt(3);
2247         j = lmod_bytes(po, po->operand[0].lmod);
2248         strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
2249         if (po->flags & OPF_REP) {
2250           fprintf(fout,
2251             "  for (; ecx != 0; ecx--, edi += %d, esi += %d)\n",
2252             j, j);
2253           fprintf(fout,
2254             "    %sedi = %sesi;", buf1, buf1);
2255           strcpy(g_comment, "rep movs");
2256         }
2257         else {
2258           fprintf(fout, "    %sedi = %sesi; edi += %d; esi += %d;",
2259             buf1, buf1, j, j);
2260           strcpy(g_comment, "movs");
2261         }
2262         break;
2263
2264       // arithmetic w/flags
2265       case OP_ADD:
2266       case OP_SUB:
2267       case OP_AND:
2268       case OP_OR:
2269         propagate_lmod(po, &po->operand[0], &po->operand[1]);
2270         // fallthrough
2271       case OP_SHL:
2272       case OP_SHR:
2273       dualop_arith:
2274         assert_operand_cnt(2);
2275         fprintf(fout, "  %s %s= %s;",
2276             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
2277             op_to_c(po),
2278             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
2279         last_arith_dst = &po->operand[0];
2280         delayed_flag_op = NULL;
2281         break;
2282
2283       case OP_SAR:
2284         assert_operand_cnt(2);
2285         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
2286         fprintf(fout, "  %s = %s%s >> %s;", buf1,
2287           lmod_cast_s(po, po->operand[0].lmod), buf1,
2288           out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
2289         last_arith_dst = &po->operand[0];
2290         delayed_flag_op = NULL;
2291         break;
2292
2293       case OP_ROL:
2294       case OP_ROR:
2295         assert_operand_cnt(2);
2296         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
2297         if (po->operand[1].type == OPT_CONST) {
2298           j = po->operand[1].val;
2299           j %= lmod_bytes(po, po->operand[0].lmod) * 8;
2300           fprintf(fout, po->op == OP_ROL ?
2301             "  %s = (%s << %d) | (%s >> %d);" :
2302             "  %s = (%s >> %d) | (%s << %d);",
2303             buf1, buf1, j, buf1,
2304             lmod_bytes(po, po->operand[0].lmod) * 8 - j);
2305         }
2306         else
2307           ferr(po, "TODO\n");
2308         last_arith_dst = &po->operand[0];
2309         delayed_flag_op = NULL;
2310         break;
2311
2312       case OP_XOR:
2313         assert_operand_cnt(2);
2314         propagate_lmod(po, &po->operand[0], &po->operand[1]);
2315         if (IS(opr_name(po, 0), opr_name(po, 1))) {
2316           // special case for XOR
2317           fprintf(fout, "  %s = 0;",
2318             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
2319           last_arith_dst = &po->operand[0];
2320           delayed_flag_op = NULL;
2321           break;
2322         }
2323         goto dualop_arith;
2324
2325       case OP_ADC:
2326       case OP_SBB:
2327         assert_operand_cnt(2);
2328         propagate_lmod(po, &po->operand[0], &po->operand[1]);
2329         fprintf(fout, "  %s %s= %s + cond_c;",
2330             out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
2331             op_to_c(po),
2332             out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], 0));
2333         last_arith_dst = &po->operand[0];
2334         delayed_flag_op = NULL;
2335         break;
2336
2337       case OP_INC:
2338       case OP_DEC:
2339         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
2340         if (po->operand[0].type == OPT_REG) {
2341           strcpy(buf2, po->op == OP_INC ? "++" : "--");
2342           fprintf(fout, "  %s%s;", buf1, buf2);
2343         }
2344         else {
2345           strcpy(buf2, po->op == OP_INC ? "+" : "-");
2346           fprintf(fout, "  %s %s= 1;", buf1, buf2);
2347         }
2348         last_arith_dst = &po->operand[0];
2349         delayed_flag_op = NULL;
2350         break;
2351
2352       case OP_NEG:
2353         out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
2354         out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], 0);
2355         fprintf(fout, "  %s = -%s%s;", buf1,
2356           lmod_cast_s(po, po->operand[0].lmod), buf2);
2357         last_arith_dst = &po->operand[0];
2358         delayed_flag_op = NULL;
2359         if (pfomask & (1 << PFO_C)) {
2360           fprintf(fout, "\n  cond_c = (%s != 0);", buf1);
2361           pfomask &= ~(1 << PFO_C);
2362         }
2363         break;
2364
2365       case OP_IMUL:
2366         if (po->operand_cnt == 2)
2367           goto dualop_arith;
2368         if (po->operand_cnt == 3)
2369           ferr(po, "TODO imul3\n");
2370         // fallthrough
2371       case OP_MUL:
2372         assert_operand_cnt(1);
2373         strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
2374         fprintf(fout, "  mul_tmp = %seax * %s%s;\n", buf1, buf1,
2375           out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], 0));
2376         fprintf(fout, "  edx = mul_tmp >> 32;\n");
2377         fprintf(fout, "  eax = mul_tmp;");
2378         last_arith_dst = NULL;
2379         delayed_flag_op = NULL;
2380         break;
2381
2382       case OP_DIV:
2383       case OP_IDIV:
2384         assert_operand_cnt(1);
2385         if (po->operand[0].lmod != OPLM_DWORD)
2386           ferr(po, "unhandled lmod %d\n", po->operand[0].lmod);
2387
2388         // 32bit division is common, look for it
2389         if (scan_for_cdq_edx(i - 1) >= 0) {
2390           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
2391           strcpy(buf2, lmod_cast(po, po->operand[0].lmod,
2392             po->op == OP_IDIV));
2393           fprintf(fout, "  edx = %seax %% %s%s;\n", buf2, buf2, buf1);
2394           fprintf(fout, "  eax = %seax / %s%s;", buf2, buf2, buf1);
2395         }
2396         else
2397           ferr(po, "TODO 64bit divident\n");
2398         last_arith_dst = NULL;
2399         delayed_flag_op = NULL;
2400         break;
2401
2402       case OP_TEST:
2403       case OP_CMP:
2404         propagate_lmod(po, &po->operand[0], &po->operand[1]);
2405         if (pfomask != 0) {
2406           for (j = 0; j < 8; j++) {
2407             if (pfomask & (1 << j)) {
2408               out_cmp_test(buf1, sizeof(buf1), po, j, 0);
2409               fprintf(fout, "  cond_%s = %s;",
2410                 parsed_flag_op_names[j], buf1);
2411             }
2412           }
2413           pfomask = 0;
2414         }
2415         else
2416           no_output = 1;
2417         delayed_flag_op = po;
2418         break;
2419
2420       // note: we reuse OP_Jcc for SETcc, only flags differ
2421       case OP_JO ... OP_JG:
2422         if (po->flags & OPF_JMP)
2423           fprintf(fout, "    goto %s;", po->operand[0].name);
2424         // else SETcc - should already be handled
2425         break;
2426
2427       case OP_JMP:
2428         assert_operand_cnt(1);
2429         if (po->operand[0].type != OPT_LABEL)
2430           ferr(po, "unhandled call type\n");
2431
2432         fprintf(fout, "  goto %s;", po->operand[0].name);
2433         break;
2434
2435       case OP_CALL:
2436         assert_operand_cnt(1);
2437         pp = po->datap;
2438         if (pp == NULL)
2439           ferr(po, "NULL pp\n");
2440
2441         if (po->operand[0].type != OPT_LABEL)
2442           fprintf(fout, "  icall%d = (void *)%s;\n", i,
2443             out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0));
2444
2445         fprintf(fout, "  ");
2446         if (!IS(pp->ret_type, "void")) {
2447           if (po->flags & OPF_TAIL)
2448             fprintf(fout, "return ");
2449           else
2450             fprintf(fout, "eax = ");
2451           if (strchr(pp->ret_type, '*'))
2452             fprintf(fout, "(u32)");
2453         }
2454
2455         if (po->operand[0].type != OPT_LABEL) {
2456           fprintf(fout, "icall%d(", i);
2457         }
2458         else {
2459           if (pp->name[0] == 0)
2460             ferr(po, "missing pp->name\n");
2461           fprintf(fout, "%s(", pp->name);
2462         }
2463
2464         for (arg = 0; arg < pp->argc; arg++) {
2465           if (arg > 0)
2466             fprintf(fout, ", ");
2467
2468           if (strchr(pp->arg[arg].type, '*'))
2469             fprintf(fout, "(%s)", pp->arg[arg].type);
2470
2471           if (pp->arg[arg].reg != NULL) {
2472             fprintf(fout, "%s", pp->arg[arg].reg);
2473             continue;
2474           }
2475
2476           // stack arg
2477           tmp_op = pp->arg[arg].datap;
2478           if (tmp_op == NULL)
2479             ferr(po, "parsed_op missing for arg%d\n", arg);
2480           if (tmp_op->argmask) {
2481             fprintf(fout, "s_a%d", arg + 1);
2482           }
2483           else {
2484             fprintf(fout, "%s",
2485               out_src_opr(buf1, sizeof(buf1),
2486                 tmp_op, &tmp_op->operand[0], 0));
2487           }
2488         }
2489         fprintf(fout, ");");
2490
2491         if (po->flags & OPF_TAIL) {
2492           strcpy(g_comment, "tailcall");
2493           if (IS(pp->ret_type, "void"))
2494             fprintf(fout, "\n  return;");
2495         }
2496         delayed_flag_op = NULL;
2497         last_arith_dst = NULL;
2498         break;
2499
2500       case OP_RET:
2501         if (IS(g_func_pp.ret_type, "void"))
2502           fprintf(fout, "  return;");
2503         else if (strchr(g_func_pp.ret_type, '*'))
2504           fprintf(fout, "  return (%s)eax;",
2505             g_func_pp.ret_type);
2506         else
2507           fprintf(fout, "  return eax;");
2508         break;
2509
2510       case OP_PUSH:
2511         if (po->argmask) {
2512           // special case - saved func arg
2513           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
2514           for (j = 0; j < 32; j++) {
2515             if (po->argmask & (1 << j))
2516               fprintf(fout, "  s_a%d = %s;", j + 1, buf1);
2517           }
2518           break;
2519         }
2520         else if (po->flags & OPF_RSAVE) {
2521           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
2522           fprintf(fout, "  s_%s = %s;", buf1, buf1);
2523           break;
2524         }
2525         ferr(po, "stray push encountered\n");
2526         break;
2527
2528       case OP_POP:
2529         if (po->flags & OPF_RSAVE) {
2530           out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], 0);
2531           fprintf(fout, "  %s = s_%s;", buf1, buf1);
2532           break;
2533         }
2534         ferr(po, "stray pop encountered\n");
2535         break;
2536
2537       case OP_NOP:
2538         break;
2539
2540       default:
2541         no_output = 1;
2542         ferr(po, "unhandled op type %d, flags %x\n",
2543           po->op, po->flags);
2544         break;
2545     }
2546
2547     if (g_comment[0] != 0) {
2548       fprintf(fout, "  // %s", g_comment);
2549       g_comment[0] = 0;
2550       no_output = 0;
2551     }
2552     if (!no_output)
2553       fprintf(fout, "\n");
2554
2555     if (pfomask != 0)
2556         ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
2557
2558     // see is delayed flag stuff is still valid
2559     if (delayed_flag_op != NULL && delayed_flag_op != po) {
2560       if (is_any_opr_modified(delayed_flag_op, po))
2561         delayed_flag_op = NULL;
2562     }
2563
2564     if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
2565       if (is_opr_modified(last_arith_dst, po))
2566         last_arith_dst = NULL;
2567     }
2568   }
2569
2570   fprintf(fout, "}\n\n");
2571
2572   // cleanup
2573   for (i = 0; i < opcnt; i++) {
2574     if (ops[i].op == OP_CALL) {
2575       pp = ops[i].datap;
2576       if (pp) {
2577         proto_release(pp);
2578         free(pp);
2579       }
2580     }
2581   }
2582   proto_release(&g_func_pp);
2583 }
2584
2585 static void set_label(int i, const char *name)
2586 {
2587   const char *p;
2588   int len;
2589
2590   len = strlen(name);
2591   p = strchr(name, ':');
2592   if (p != NULL)
2593     len = p - name;
2594
2595   if (len > sizeof(g_labels[0]) - 1)
2596     aerr("label '%s' too long: %d\n", name, len);
2597   if (g_labels[i][0] != 0)
2598     aerr("dupe label '%s'?\n", name);
2599   memcpy(g_labels[i], name, len);
2600   g_labels[i][len] = 0;
2601 }
2602
2603 // '=' needs special treatment..
2604 static char *next_word_s(char *w, size_t wsize, char *s)
2605 {
2606         size_t i;
2607
2608         s = sskip(s);
2609
2610         for (i = 0; i < wsize - 1; i++) {
2611                 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
2612                         break;
2613                 w[i] = s[i];
2614         }
2615         w[i] = 0;
2616
2617         if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
2618                 printf("warning: '%s' truncated\n", w);
2619
2620         return s + i;
2621 }
2622
2623 static int cmpstringp(const void *p1, const void *p2)
2624 {
2625   return strcmp(*(char * const *)p1, *(char * const *)p2);
2626 }
2627
2628 int main(int argc, char *argv[])
2629 {
2630   FILE *fout, *fasm, *frlist;
2631   char line[256];
2632   char words[16][256];
2633   int ida_func_attr = 0;
2634   int in_func = 0;
2635   int skip_func = 0;
2636   int skip_warned = 0;
2637   int eq_alloc;
2638   char **rlist = NULL;
2639   int rlist_len = 0;
2640   int rlist_alloc = 0;
2641   int verbose = 0;
2642   int arg_out;
2643   int arg = 1;
2644   int pi = 0;
2645   int i, len;
2646   char *p;
2647   int wordc;
2648
2649   if (argv[1] && IS(argv[1], "-v")) {
2650     verbose = 1;
2651     arg++;
2652   }
2653
2654   if (argc < arg + 3) {
2655     printf("usage:\n%s [-v] <.c> <.asm> <hdrf> [rlist]*\n",
2656       argv[0]);
2657     return 1;
2658   }
2659
2660   arg_out = arg++;
2661
2662   asmfn = argv[arg++];
2663   fasm = fopen(asmfn, "r");
2664   my_assert_not(fasm, NULL);
2665
2666   hdrfn = argv[arg++];
2667   g_fhdr = fopen(hdrfn, "r");
2668   my_assert_not(g_fhdr, NULL);
2669
2670   rlist_alloc = 64;
2671   rlist = malloc(rlist_alloc * sizeof(rlist[0]));
2672   my_assert_not(rlist, NULL);
2673   // needs special handling..
2674   rlist[rlist_len++] = "__alloca_probe";
2675
2676   for (; arg < argc; arg++) {
2677     frlist = fopen(argv[arg], "r");
2678     my_assert_not(frlist, NULL);
2679
2680     while (fgets(line, sizeof(line), frlist)) {
2681       p = sskip(line);
2682       if (*p == 0 || *p == ';' || *p == '#')
2683         continue;
2684
2685       p = next_word(words[0], sizeof(words[0]), p);
2686       if (words[0][0] == 0)
2687         continue;
2688
2689       if (rlist_len >= rlist_alloc) {
2690         rlist_alloc = rlist_alloc * 2 + 64;
2691         rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
2692         my_assert_not(rlist, NULL);
2693       }
2694       rlist[rlist_len++] = strdup(words[0]);
2695     }
2696
2697     fclose(frlist);
2698     frlist = NULL;
2699   }
2700
2701   if (rlist_len > 0)
2702     qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
2703
2704   fout = fopen(argv[arg_out], "w");
2705   my_assert_not(fout, NULL);
2706
2707   eq_alloc = 128;
2708   g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
2709   my_assert_not(g_eqs, NULL);
2710
2711   while (fgets(line, sizeof(line), fasm))
2712   {
2713     asmln++;
2714
2715     p = sskip(line);
2716     if (*p == 0)
2717       continue;
2718
2719     if (*p == ';') {
2720       static const char *attrs[] = {
2721         "bp-based frame",
2722         "library function",
2723         "static",
2724         "noreturn",
2725         "thunk",
2726         "fpd=",
2727       };
2728       if (p[2] != 'A' || strncmp(p, "; Attributes:", 13) != 0)
2729         continue;
2730
2731       // parse IDA's attribute-list comment
2732       ida_func_attr = 0;
2733       p = sskip(p + 13);
2734       // get rid of random tabs
2735       for (i = 0; p[i] != 0; i++)
2736         if (p[i] == '\t')
2737           p[i] = ' ';
2738
2739       for (; *p != 0; p = sskip(p)) {
2740         for (i = 0; i < ARRAY_SIZE(attrs); i++) {
2741           if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
2742             ida_func_attr |= 1 << i;
2743             p += strlen(attrs[i]);
2744             break;
2745           }
2746         }
2747         if (i == ARRAY_SIZE(attrs)) {
2748           anote("unparsed IDA attr: %s\n", p);
2749           break;
2750         }
2751         if (IS(attrs[i], "fpd=")) {
2752           p = next_word(words[0], sizeof(words[0]), p);
2753           // ignore for now..
2754         }
2755       }
2756       continue;
2757     }
2758
2759 parse_words:
2760     memset(words, 0, sizeof(words));
2761     for (wordc = 0; wordc < 16; wordc++) {
2762       p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
2763       if (*p == 0 || *p == ';') {
2764         wordc++;
2765         break;
2766       }
2767     }
2768
2769     // alow asm patches in comments
2770     if (*p == ';' && IS_START(p, "; sctpatch: ")) {
2771       p = sskip(p + 12);
2772       if (*p == 0 || *p == ';')
2773         continue;
2774       goto parse_words; // lame
2775     }
2776
2777     if (wordc == 0) {
2778       // shouldn't happen
2779       awarn("wordc == 0?\n");
2780       continue;
2781     }
2782
2783     // don't care about this:
2784     if (words[0][0] == '.'
2785         || IS(words[0], "include")
2786         || IS(words[0], "assume") || IS(words[1], "segment")
2787         || IS(words[0], "align"))
2788     {
2789       continue;
2790     }
2791
2792     if (IS(words[1], "proc")) {
2793       if (in_func)
2794         aerr("proc '%s' while in_func '%s'?\n",
2795           words[0], g_func);
2796       p = words[0];
2797       if ((ida_func_attr & IDAFA_THUNK)
2798        || bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
2799         skip_func = 1;
2800       strcpy(g_func, words[0]);
2801       set_label(0, words[0]);
2802       in_func = 1;
2803       continue;
2804     }
2805
2806     if (IS(words[1], "endp")) {
2807       if (!in_func)
2808         aerr("endp '%s' while not in_func?\n", words[0]);
2809       if (!IS(g_func, words[0]))
2810         aerr("endp '%s' while in_func '%s'?\n",
2811           words[0], g_func);
2812
2813       if (in_func && !skip_func)
2814         gen_func(fout, g_fhdr, g_func, pi);
2815
2816       in_func = 0;
2817       skip_warned = 0;
2818       skip_func = 0;
2819       g_func[0] = 0;
2820       if (pi != 0) {
2821         memset(&ops, 0, pi * sizeof(ops[0]));
2822         memset(g_labels, 0, pi * sizeof(g_labels[0]));
2823         memset(g_label_refs, 0, pi * sizeof(g_label_refs[0]));
2824         pi = 0;
2825       }
2826       g_eqcnt = 0;
2827       ida_func_attr = 0;
2828       continue;
2829     }
2830
2831     p = strchr(words[0], ':');
2832     if (p != NULL) {
2833       set_label(pi, words[0]);
2834       continue;
2835     }
2836
2837     if (!in_func || skip_func) {
2838       if (!skip_warned && !skip_func && g_labels[pi][0] != 0) {
2839         if (verbose)
2840           anote("skipping from '%s'\n", g_labels[pi]);
2841         skip_warned = 1;
2842       }
2843       g_labels[pi][0] = 0;
2844       continue;
2845     }
2846
2847     if (IS(words[1], "=")) {
2848       if (wordc != 5)
2849         aerr("unhandled equ, wc=%d\n", wordc);
2850       if (g_eqcnt >= eq_alloc) {
2851         eq_alloc *= 2;
2852         g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
2853         my_assert_not(g_eqs, NULL);
2854       }
2855
2856       len = strlen(words[0]);
2857       if (len > sizeof(g_eqs[0].name) - 1)
2858         aerr("equ name too long: %d\n", len);
2859       strcpy(g_eqs[g_eqcnt].name, words[0]);
2860
2861       if (!IS(words[3], "ptr"))
2862         aerr("unhandled equ\n");
2863       if (IS(words[2], "dword"))
2864         g_eqs[g_eqcnt].lmod = OPLM_DWORD;
2865       else if (IS(words[2], "word"))
2866         g_eqs[g_eqcnt].lmod = OPLM_WORD;
2867       else if (IS(words[2], "byte"))
2868         g_eqs[g_eqcnt].lmod = OPLM_BYTE;
2869       else
2870         aerr("bad lmod: '%s'\n", words[2]);
2871
2872       g_eqs[g_eqcnt].offset = parse_number(words[4]);
2873       g_eqcnt++;
2874       continue;
2875     }
2876
2877     if (pi >= ARRAY_SIZE(ops))
2878       aerr("too many ops\n");
2879
2880     parse_op(&ops[pi], words, wordc);
2881     pi++;
2882   }
2883
2884   fclose(fout);
2885   fclose(fasm);
2886   fclose(g_fhdr);
2887
2888   return 0;
2889 }
2890
2891 // vim:ts=2:shiftwidth=2:expandtab