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