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