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