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