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