translate: float: stack mode and some more ops
[ia32rtools.git] / tools / translate.c
... / ...
CommitLineData
1/*
2 * ia32rtools
3 * (C) notaz, 2013-2015
4 *
5 * This work is licensed under the terms of 3-clause BSD license.
6 * See COPYING file in the top-level directory.
7 */
8
9#define _GNU_SOURCE
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13
14#include "my_assert.h"
15#include "my_str.h"
16#include "common.h"
17
18#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
19#define IS(w, y) !strcmp(w, y)
20#define IS_START(w, y) !strncmp(w, y, strlen(y))
21
22#include "protoparse.h"
23
24static const char *asmfn;
25static int asmln;
26static FILE *g_fhdr;
27
28#define anote(fmt, ...) \
29 printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
30#define awarn(fmt, ...) \
31 printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
32#define aerr(fmt, ...) do { \
33 printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
34 fcloseall(); \
35 exit(1); \
36} while (0)
37
38#include "masm_tools.h"
39
40enum op_flags {
41 OPF_RMD = (1 << 0), /* removed from code generation */
42 OPF_DATA = (1 << 1), /* data processing - writes to dst opr */
43 OPF_FLAGS = (1 << 2), /* sets flags */
44 OPF_JMP = (1 << 3), /* branch, call */
45 OPF_CJMP = (1 << 4), /* cond. branch (cc or jecxz/loop) */
46 OPF_CC = (1 << 5), /* uses flags */
47 OPF_TAIL = (1 << 6), /* ret or tail call */
48 OPF_RSAVE = (1 << 7), /* push/pop is local reg save/load */
49 OPF_REP = (1 << 8), /* prefixed by rep */
50 OPF_REPZ = (1 << 9), /* rep is repe/repz */
51 OPF_REPNZ = (1 << 10), /* rep is repne/repnz */
52 OPF_FARG = (1 << 11), /* push collected as func arg */
53 OPF_FARGNR = (1 << 12), /* push collected as func arg (no reuse) */
54 OPF_EBP_S = (1 << 13), /* ebp used as scratch here, not BP */
55 OPF_DF = (1 << 14), /* DF flag set */
56 OPF_ATAIL = (1 << 15), /* tail call with reused arg frame */
57 OPF_32BIT = (1 << 16), /* 32bit division */
58 OPF_LOCK = (1 << 17), /* op has lock prefix */
59 OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
60 OPF_DONE = (1 << 19), /* already fully handled by analysis */
61 OPF_PPUSH = (1 << 20), /* part of complex push-pop graph */
62 OPF_NOREGS = (1 << 21), /* don't track regs of this op */
63 OPF_FPUSH = (1 << 22), /* pushes x87 stack */
64 OPF_FPOP = (1 << 23), /* pops x87 stack */
65 OPF_FSHIFT = (1 << 24), /* x87 stack shift is actually needed */
66};
67
68enum op_op {
69 OP_INVAL,
70 OP_NOP,
71 OP_PUSH,
72 OP_POP,
73 OP_LEAVE,
74 OP_MOV,
75 OP_LEA,
76 OP_MOVZX,
77 OP_MOVSX,
78 OP_XCHG,
79 OP_NOT,
80 OP_XLAT,
81 OP_CDQ,
82 OP_LODS,
83 OP_STOS,
84 OP_MOVS,
85 OP_CMPS,
86 OP_SCAS,
87 OP_STD,
88 OP_CLD,
89 OP_RET,
90 OP_ADD,
91 OP_SUB,
92 OP_AND,
93 OP_OR,
94 OP_XOR,
95 OP_SHL,
96 OP_SHR,
97 OP_SAR,
98 OP_SHLD,
99 OP_SHRD,
100 OP_ROL,
101 OP_ROR,
102 OP_RCL,
103 OP_RCR,
104 OP_ADC,
105 OP_SBB,
106 OP_BSF,
107 OP_INC,
108 OP_DEC,
109 OP_NEG,
110 OP_MUL,
111 OP_IMUL,
112 OP_DIV,
113 OP_IDIV,
114 OP_TEST,
115 OP_CMP,
116 OP_CALL,
117 OP_JMP,
118 OP_JECXZ,
119 OP_LOOP,
120 OP_JCC,
121 OP_SCC,
122 // x87
123 OP_FLD,
124 OP_FILD,
125 OP_FLDc,
126 OP_FST,
127 OP_FADD,
128 OP_FDIV,
129 OP_FMUL,
130 OP_FSUB,
131 OP_FDIVR,
132 OP_FSUBR,
133 OP_FIADD,
134 OP_FIDIV,
135 OP_FIMUL,
136 OP_FISUB,
137 OP_FIDIVR,
138 OP_FISUBR,
139 OP_FCHS,
140 OP_FCOS,
141 OP_FPATAN,
142 OP_FPTAN,
143 OP_FSIN,
144 OP_FSQRT,
145 OP_FXCH,
146 OP_FYL2X,
147 // mmx
148 OP_EMMS,
149 // pseudo-ops for lib calls
150 OPP_FTOL,
151 // undefined
152 OP_UD2,
153};
154
155enum opr_type {
156 OPT_UNSPEC,
157 OPT_REG,
158 OPT_REGMEM,
159 OPT_LABEL,
160 OPT_OFFSET,
161 OPT_CONST,
162};
163
164// must be sorted (larger len must be further in enum)
165enum opr_lenmod {
166 OPLM_UNSPEC,
167 OPLM_BYTE,
168 OPLM_WORD,
169 OPLM_DWORD,
170 OPLM_QWORD,
171};
172
173#define MAX_EXITS 128
174
175#define MAX_OPERANDS 3
176#define NAMELEN 112
177
178#define OPR_INIT(type_, lmod_, reg_) \
179 { type_, lmod_, reg_, }
180
181struct parsed_opr {
182 enum opr_type type;
183 enum opr_lenmod lmod;
184 int reg;
185 unsigned int is_ptr:1; // pointer in C
186 unsigned int is_array:1; // array in C
187 unsigned int type_from_var:1; // .. in header, sometimes wrong
188 unsigned int size_mismatch:1; // type override differs from C
189 unsigned int size_lt:1; // type override is larger than C
190 unsigned int had_ds:1; // had ds: prefix
191 const struct parsed_proto *pp; // for OPT_LABEL
192 unsigned int val;
193 char name[NAMELEN];
194};
195
196struct parsed_op {
197 enum op_op op;
198 struct parsed_opr operand[MAX_OPERANDS];
199 unsigned int flags;
200 unsigned char pfo;
201 unsigned char pfo_inv;
202 unsigned char operand_cnt;
203 unsigned char p_argnum; // arg push: altered before call arg #
204 unsigned char p_arggrp; // arg push: arg group # for above
205 unsigned char p_argpass;// arg push: arg of host func
206 short p_argnext;// arg push: same arg pushed elsewhere or -1
207 int regmask_src; // all referensed regs
208 int regmask_dst;
209 int pfomask; // flagop: parsed_flag_op that can't be delayed
210 int cc_scratch; // scratch storage during analysis
211 int bt_i; // branch target for branches
212 struct parsed_data *btj;// branch targets for jumptables
213 struct parsed_proto *pp;// parsed_proto for OP_CALL
214 void *datap;
215 int asmln;
216};
217
218// datap:
219// on start: function/data type hint (sctproto)
220// after analysis:
221// (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
222// OP_PUSH - points to OP_POP in complex push/pop graph
223// OP_POP - points to OP_PUSH in simple push/pop pair
224
225struct parsed_equ {
226 char name[64];
227 enum opr_lenmod lmod;
228 int offset;
229};
230
231struct parsed_data {
232 char label[256];
233 enum opr_type type;
234 enum opr_lenmod lmod;
235 int count;
236 int count_alloc;
237 struct {
238 union {
239 char *label;
240 unsigned int val;
241 } u;
242 int bt_i;
243 } *d;
244};
245
246struct label_ref {
247 int i;
248 struct label_ref *next;
249};
250
251enum ida_func_attr {
252 IDAFA_BP_FRAME = (1 << 0),
253 IDAFA_LIB_FUNC = (1 << 1),
254 IDAFA_STATIC = (1 << 2),
255 IDAFA_NORETURN = (1 << 3),
256 IDAFA_THUNK = (1 << 4),
257 IDAFA_FPD = (1 << 5),
258};
259
260enum sct_func_attr {
261 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
262 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
263};
264
265enum x87_const {
266 X87_CONST_1 = 1,
267 X87_CONST_2T,
268 X87_CONST_2E,
269 X87_CONST_PI,
270 X87_CONST_LG2,
271 X87_CONST_LN2,
272 X87_CONST_Z,
273};
274
275// note: limited to 32k due to p_argnext
276#define MAX_OPS 4096
277#define MAX_ARG_GRP 2
278
279static struct parsed_op ops[MAX_OPS];
280static struct parsed_equ *g_eqs;
281static int g_eqcnt;
282static char *g_labels[MAX_OPS];
283static struct label_ref g_label_refs[MAX_OPS];
284static const struct parsed_proto *g_func_pp;
285static struct parsed_data *g_func_pd;
286static int g_func_pd_cnt;
287static int g_func_lmods;
288static char g_func[256];
289static char g_comment[256];
290static int g_bp_frame;
291static int g_sp_frame;
292static int g_stack_frame_used;
293static int g_stack_fsz;
294static int g_ida_func_attr;
295static int g_sct_func_attr;
296static int g_stack_clear_start; // in dwords
297static int g_stack_clear_len;
298static int g_regmask_init;
299static int g_skip_func;
300static int g_allow_regfunc;
301static int g_quiet_pp;
302static int g_header_mode;
303
304#define ferr(op_, fmt, ...) do { \
305 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
306 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
307 fcloseall(); \
308 exit(1); \
309} while (0)
310#define fnote(op_, fmt, ...) \
311 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
312 dump_op(op_), ##__VA_ARGS__)
313
314#define ferr_assert(op_, cond) do { \
315 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
316} while (0)
317
318const char *regs_r32[] = {
319 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
320 // not r32, but list here for easy parsing and printing
321 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
322 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
323};
324const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
325const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
326const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
327
328enum x86_regs {
329 xUNSPEC = -1,
330 xAX, xBX, xCX, xDX,
331 xSI, xDI, xBP, xSP,
332 xMM0, xMM1, xMM2, xMM3, // mmx
333 xMM4, xMM5, xMM6, xMM7,
334 xST0, xST1, xST2, xST3, // x87
335 xST4, xST5, xST6, xST7,
336};
337
338#define mxAX (1 << xAX)
339#define mxCX (1 << xCX)
340#define mxDX (1 << xDX)
341#define mxST0 (1 << xST0)
342#define mxST1 (1 << xST1)
343#define mxST1_0 (mxST1 | mxST0)
344#define mxST7_2 (0xfc << xST0)
345#define mxSTa (0xff << xST0)
346
347// possible basic comparison types (without inversion)
348enum parsed_flag_op {
349 PFO_O, // 0 OF=1
350 PFO_C, // 2 CF=1
351 PFO_Z, // 4 ZF=1
352 PFO_BE, // 6 CF=1||ZF=1
353 PFO_S, // 8 SF=1
354 PFO_P, // a PF=1
355 PFO_L, // c SF!=OF
356 PFO_LE, // e ZF=1||SF!=OF
357};
358
359#define PFOB_O (1 << PFO_O)
360#define PFOB_C (1 << PFO_C)
361#define PFOB_Z (1 << PFO_Z)
362#define PFOB_S (1 << PFO_S)
363
364static const char *parsed_flag_op_names[] = {
365 "o", "c", "z", "be", "s", "p", "l", "le"
366};
367
368static int char_array_i(const char *array[], size_t len, const char *s)
369{
370 int i;
371
372 for (i = 0; i < len; i++)
373 if (IS(s, array[i]))
374 return i;
375
376 return -1;
377}
378
379static void printf_number(char *buf, size_t buf_size,
380 unsigned long number)
381{
382 // output in C-friendly form
383 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
384}
385
386static int check_segment_prefix(const char *s)
387{
388 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
389 return 0;
390
391 switch (s[0]) {
392 case 'c': return 1;
393 case 'd': return 2;
394 case 's': return 3;
395 case 'e': return 4;
396 case 'f': return 5;
397 case 'g': return 6;
398 default: return 0;
399 }
400}
401
402static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
403{
404 int reg;
405
406 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
407 if (reg >= 8) {
408 *reg_lmod = OPLM_QWORD;
409 return reg;
410 }
411 if (reg >= 0) {
412 *reg_lmod = OPLM_DWORD;
413 return reg;
414 }
415 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
416 if (reg >= 0) {
417 *reg_lmod = OPLM_WORD;
418 return reg;
419 }
420 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
421 if (reg >= 0) {
422 *reg_lmod = OPLM_BYTE;
423 return reg;
424 }
425 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
426 if (reg >= 0) {
427 *reg_lmod = OPLM_BYTE;
428 return reg;
429 }
430
431 return -1;
432}
433
434static int parse_indmode(char *name, int *regmask, int need_c_cvt)
435{
436 enum opr_lenmod lmod;
437 char cvtbuf[256];
438 char *d = cvtbuf;
439 char *s = name;
440 char w[64];
441 long number;
442 int reg;
443 int c = 0;
444
445 *d = 0;
446
447 while (*s != 0) {
448 d += strlen(d);
449 while (my_isblank(*s))
450 s++;
451 for (; my_issep(*s); d++, s++)
452 *d = *s;
453 while (my_isblank(*s))
454 s++;
455 *d = 0;
456
457 // skip '?s:' prefixes
458 if (check_segment_prefix(s))
459 s += 3;
460
461 s = next_idt(w, sizeof(w), s);
462 if (w[0] == 0)
463 break;
464 c++;
465
466 reg = parse_reg(&lmod, w);
467 if (reg >= 0) {
468 *regmask |= 1 << reg;
469 goto pass;
470 }
471
472 if ('0' <= w[0] && w[0] <= '9') {
473 number = parse_number(w);
474 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
475 continue;
476 }
477
478 // probably some label/identifier - pass
479
480pass:
481 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
482 }
483
484 if (need_c_cvt)
485 strcpy(name, cvtbuf);
486
487 return c;
488}
489
490static int is_reg_in_str(const char *s)
491{
492 int i;
493
494 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
495 return 0;
496
497 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
498 if (!strncmp(s, regs_r32[i], 3))
499 return 1;
500
501 return 0;
502}
503
504static const char *parse_stack_el(const char *name, char *extra_reg,
505 int early_try)
506{
507 const char *p, *p2, *s;
508 char *endp = NULL;
509 char buf[32];
510 long val;
511 int len;
512
513 if (g_bp_frame || early_try)
514 {
515 p = name;
516 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
517 p += 4;
518 if (extra_reg != NULL) {
519 strncpy(extra_reg, name, 3);
520 extra_reg[4] = 0;
521 }
522 }
523
524 if (IS_START(p, "ebp+")) {
525 p += 4;
526
527 p2 = strchr(p, '+');
528 if (p2 != NULL && is_reg_in_str(p)) {
529 if (extra_reg != NULL) {
530 strncpy(extra_reg, p, p2 - p);
531 extra_reg[p2 - p] = 0;
532 }
533 p = p2 + 1;
534 }
535
536 if (!('0' <= *p && *p <= '9'))
537 return p;
538
539 return NULL;
540 }
541 }
542
543 if (!IS_START(name, "esp+"))
544 return NULL;
545
546 s = name + 4;
547 p = strchr(s, '+');
548 if (p) {
549 if (is_reg_in_str(s)) {
550 if (extra_reg != NULL) {
551 strncpy(extra_reg, s, p - s);
552 extra_reg[p - s] = 0;
553 }
554 s = p + 1;
555 p = strchr(s, '+');
556 if (p == NULL)
557 aerr("%s IDA stackvar not set?\n", __func__);
558 }
559 if (!('0' <= *s && *s <= '9')) {
560 aerr("%s IDA stackvar offset not set?\n", __func__);
561 return NULL;
562 }
563 if (s[0] == '0' && s[1] == 'x')
564 s += 2;
565 len = p - s;
566 if (len < sizeof(buf) - 1) {
567 strncpy(buf, s, len);
568 buf[len] = 0;
569 val = strtol(buf, &endp, 16);
570 if (val == 0 || *endp != 0) {
571 aerr("%s num parse fail for '%s'\n", __func__, buf);
572 return NULL;
573 }
574 }
575 p++;
576 }
577 else
578 p = name + 4;
579
580 if ('0' <= *p && *p <= '9')
581 return NULL;
582
583 return p;
584}
585
586static int guess_lmod_from_name(struct parsed_opr *opr)
587{
588 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
589 opr->lmod = OPLM_DWORD;
590 return 1;
591 }
592 if (IS_START(opr->name, "word_")) {
593 opr->lmod = OPLM_WORD;
594 return 1;
595 }
596 if (IS_START(opr->name, "byte_")) {
597 opr->lmod = OPLM_BYTE;
598 return 1;
599 }
600 if (IS_START(opr->name, "qword_")) {
601 opr->lmod = OPLM_QWORD;
602 return 1;
603 }
604 return 0;
605}
606
607static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
608 const struct parsed_type *c_type)
609{
610 static const char *dword_types[] = {
611 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
612 "WPARAM", "LPARAM", "UINT", "__int32",
613 "LONG", "HIMC", "BOOL", "size_t",
614 "float",
615 };
616 static const char *word_types[] = {
617 "uint16_t", "int16_t", "_WORD", "WORD",
618 "unsigned __int16", "__int16",
619 };
620 static const char *byte_types[] = {
621 "uint8_t", "int8_t", "char",
622 "unsigned __int8", "__int8", "BYTE", "_BYTE",
623 "CHAR", "_UNKNOWN",
624 // structures.. deal the same as with _UNKNOWN for now
625 "CRITICAL_SECTION",
626 };
627 const char *n;
628 int i;
629
630 if (c_type->is_ptr) {
631 *lmod = OPLM_DWORD;
632 return 1;
633 }
634
635 n = skip_type_mod(c_type->name);
636
637 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
638 if (IS(n, dword_types[i])) {
639 *lmod = OPLM_DWORD;
640 return 1;
641 }
642 }
643
644 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
645 if (IS(n, word_types[i])) {
646 *lmod = OPLM_WORD;
647 return 1;
648 }
649 }
650
651 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
652 if (IS(n, byte_types[i])) {
653 *lmod = OPLM_BYTE;
654 return 1;
655 }
656 }
657
658 return 0;
659}
660
661static char *default_cast_to(char *buf, size_t buf_size,
662 struct parsed_opr *opr)
663{
664 buf[0] = 0;
665
666 if (!opr->is_ptr || strchr(opr->name, '['))
667 return buf;
668 if (opr->pp == NULL || opr->pp->type.name == NULL
669 || opr->pp->is_fptr)
670 {
671 snprintf(buf, buf_size, "%s", "(void *)");
672 return buf;
673 }
674
675 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
676 return buf;
677}
678
679static enum opr_type lmod_from_directive(const char *d)
680{
681 if (IS(d, "dd"))
682 return OPLM_DWORD;
683 else if (IS(d, "dw"))
684 return OPLM_WORD;
685 else if (IS(d, "db"))
686 return OPLM_BYTE;
687
688 aerr("unhandled directive: '%s'\n", d);
689 return OPLM_UNSPEC;
690}
691
692static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
693 int *regmask)
694{
695 opr->type = OPT_REG;
696 opr->reg = reg;
697 opr->lmod = lmod;
698 *regmask |= 1 << reg;
699}
700
701static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
702 int *extra_offs);
703
704static int parse_operand(struct parsed_opr *opr,
705 int *regmask, int *regmask_indirect,
706 char words[16][256], int wordc, int w, unsigned int op_flags)
707{
708 const struct parsed_proto *pp = NULL;
709 enum opr_lenmod tmplmod;
710 unsigned long number;
711 char buf[256];
712 int ret, len;
713 int wordc_in;
714 char *p;
715 int i;
716
717 if (w >= wordc)
718 aerr("parse_operand w %d, wordc %d\n", w, wordc);
719
720 opr->reg = xUNSPEC;
721
722 for (i = w; i < wordc; i++) {
723 len = strlen(words[i]);
724 if (words[i][len - 1] == ',') {
725 words[i][len - 1] = 0;
726 wordc = i + 1;
727 break;
728 }
729 }
730
731 wordc_in = wordc - w;
732
733 if ((op_flags & OPF_JMP) && wordc_in > 0
734 && !('0' <= words[w][0] && words[w][0] <= '9'))
735 {
736 const char *label = NULL;
737
738 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
739 && IS(words[w + 1], "ptr"))
740 label = words[w + 2];
741 else if (wordc_in == 2 && IS(words[w], "short"))
742 label = words[w + 1];
743 else if (wordc_in == 1
744 && strchr(words[w], '[') == NULL
745 && parse_reg(&tmplmod, words[w]) < 0)
746 label = words[w];
747
748 if (label != NULL) {
749 opr->type = OPT_LABEL;
750 ret = check_segment_prefix(label);
751 if (ret != 0) {
752 if (ret >= 5)
753 aerr("fs/gs used\n");
754 opr->had_ds = 1;
755 label += 3;
756 }
757 strcpy(opr->name, label);
758 return wordc;
759 }
760 }
761
762 if (wordc_in >= 3) {
763 if (IS(words[w + 1], "ptr")) {
764 if (IS(words[w], "dword"))
765 opr->lmod = OPLM_DWORD;
766 else if (IS(words[w], "word"))
767 opr->lmod = OPLM_WORD;
768 else if (IS(words[w], "byte"))
769 opr->lmod = OPLM_BYTE;
770 else if (IS(words[w], "qword"))
771 opr->lmod = OPLM_QWORD;
772 else
773 aerr("type parsing failed\n");
774 w += 2;
775 wordc_in = wordc - w;
776 }
777 }
778
779 if (wordc_in == 2) {
780 if (IS(words[w], "offset")) {
781 opr->type = OPT_OFFSET;
782 opr->lmod = OPLM_DWORD;
783 strcpy(opr->name, words[w + 1]);
784 pp = proto_parse(g_fhdr, opr->name, 1);
785 goto do_label;
786 }
787 if (IS(words[w], "(offset")) {
788 p = strchr(words[w + 1], ')');
789 if (p == NULL)
790 aerr("parse of bracketed offset failed\n");
791 *p = 0;
792 opr->type = OPT_OFFSET;
793 strcpy(opr->name, words[w + 1]);
794 return wordc;
795 }
796 }
797
798 if (wordc_in != 1)
799 aerr("parse_operand 1 word expected\n");
800
801 ret = check_segment_prefix(words[w]);
802 if (ret != 0) {
803 if (ret >= 5)
804 aerr("fs/gs used\n");
805 opr->had_ds = 1;
806 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
807 }
808 strcpy(opr->name, words[w]);
809
810 if (words[w][0] == '[') {
811 opr->type = OPT_REGMEM;
812 ret = sscanf(words[w], "[%[^]]]", opr->name);
813 if (ret != 1)
814 aerr("[] parse failure\n");
815
816 parse_indmode(opr->name, regmask_indirect, 1);
817 if (opr->lmod == OPLM_UNSPEC && parse_stack_el(opr->name, NULL, 1))
818 {
819 // might be an equ
820 struct parsed_equ *eq =
821 equ_find(NULL, parse_stack_el(opr->name, NULL, 1), &i);
822 if (eq)
823 opr->lmod = eq->lmod;
824
825 // might be unaligned access
826 g_func_lmods |= 1 << OPLM_BYTE;
827 }
828 return wordc;
829 }
830 else if (strchr(words[w], '[')) {
831 // label[reg] form
832 p = strchr(words[w], '[');
833 opr->type = OPT_REGMEM;
834 parse_indmode(p, regmask_indirect, 0);
835 strncpy(buf, words[w], p - words[w]);
836 buf[p - words[w]] = 0;
837 pp = proto_parse(g_fhdr, buf, 1);
838 goto do_label;
839 }
840 else if (('0' <= words[w][0] && words[w][0] <= '9')
841 || words[w][0] == '-')
842 {
843 number = parse_number(words[w]);
844 opr->type = OPT_CONST;
845 opr->val = number;
846 printf_number(opr->name, sizeof(opr->name), number);
847 return wordc;
848 }
849
850 ret = parse_reg(&tmplmod, opr->name);
851 if (ret >= 0) {
852 setup_reg_opr(opr, ret, tmplmod, regmask);
853 return wordc;
854 }
855
856 // most likely var in data segment
857 opr->type = OPT_LABEL;
858 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
859
860do_label:
861 if (pp != NULL) {
862 if (pp->is_fptr || pp->is_func) {
863 opr->lmod = OPLM_DWORD;
864 opr->is_ptr = 1;
865 }
866 else {
867 tmplmod = OPLM_UNSPEC;
868 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
869 anote("unhandled C type '%s' for '%s'\n",
870 pp->type.name, opr->name);
871
872 if (opr->lmod == OPLM_UNSPEC) {
873 opr->lmod = tmplmod;
874 opr->type_from_var = 1;
875 }
876 else if (opr->lmod != tmplmod) {
877 opr->size_mismatch = 1;
878 if (tmplmod < opr->lmod)
879 opr->size_lt = 1;
880 }
881 opr->is_ptr = pp->type.is_ptr;
882 }
883 opr->is_array = pp->type.is_array;
884 }
885 opr->pp = pp;
886
887 if (opr->lmod == OPLM_UNSPEC)
888 guess_lmod_from_name(opr);
889 return wordc;
890}
891
892static const struct {
893 const char *name;
894 unsigned int flags;
895} pref_table[] = {
896 { "rep", OPF_REP },
897 { "repe", OPF_REP|OPF_REPZ },
898 { "repz", OPF_REP|OPF_REPZ },
899 { "repne", OPF_REP|OPF_REPNZ },
900 { "repnz", OPF_REP|OPF_REPNZ },
901 { "lock", OPF_LOCK }, // ignored for now..
902};
903
904#define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
905
906static const struct {
907 const char *name;
908 enum op_op op;
909 unsigned short minopr;
910 unsigned short maxopr;
911 unsigned int flags;
912 unsigned char pfo;
913 unsigned char pfo_inv;
914} op_table[] = {
915 { "nop", OP_NOP, 0, 0, 0 },
916 { "push", OP_PUSH, 1, 1, 0 },
917 { "pop", OP_POP, 1, 1, OPF_DATA },
918 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
919 { "mov" , OP_MOV, 2, 2, OPF_DATA },
920 { "lea", OP_LEA, 2, 2, OPF_DATA },
921 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
922 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
923 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
924 { "not", OP_NOT, 1, 1, OPF_DATA },
925 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
926 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
927 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
928 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
929 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
930 { "stosb",OP_STOS, 0, 0, OPF_DATA },
931 { "stosw",OP_STOS, 0, 0, OPF_DATA },
932 { "stosd",OP_STOS, 0, 0, OPF_DATA },
933 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
934 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
935 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
936 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
937 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
938 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
939 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
940 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
941 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
942 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
943 { "cld", OP_CLD, 0, 0, OPF_DATA },
944 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
945 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
946 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
947 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
948 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
949 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
950 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
951 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
952 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
953 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
954 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
955 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
956 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
957 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
958 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
959 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
960 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
961 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
962 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
963 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
964 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
965 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
966 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
967 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
968 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
969 { "test", OP_TEST, 2, 2, OPF_FLAGS },
970 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
971 { "retn", OP_RET, 0, 1, OPF_TAIL },
972 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
973 { "jmp", OP_JMP, 1, 1, OPF_JMP },
974 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
975 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
976 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
977 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
978 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
979 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
980 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
981 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
982 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
983 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
984 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
985 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
986 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
987 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
988 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
989 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
990 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
991 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
992 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
993 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
994 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
995 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
996 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
997 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
998 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
999 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1000 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1001 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1002 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1003 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1004 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1005 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1006 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1007 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1008 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1009 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1010 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1011 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1012 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1013 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1014 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1015 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1016 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1017 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1018 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1019 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1020 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1021 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1022 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1023 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1024 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1025 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1026 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1027 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1028 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1029 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1030 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1031 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1032 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1033 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1034 // x87
1035 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1036 { "fild", OP_FILD, 1, 1, OPF_FPUSH },
1037 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1038 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1039 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1040 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1041 { "fst", OP_FST, 1, 1, 0 },
1042 { "fadd", OP_FADD, 0, 2, 0 },
1043 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1044 { "fdiv", OP_FDIV, 0, 2, 0 },
1045 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1046 { "fmul", OP_FMUL, 0, 2, 0 },
1047 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1048 { "fsub", OP_FSUB, 0, 2, 0 },
1049 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1050 { "fdivr", OP_FDIVR, 0, 2, 0 },
1051 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1052 { "fsubr", OP_FSUBR, 0, 2, 0 },
1053 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1054 { "fiadd", OP_FIADD, 1, 1, 0 },
1055 { "fidiv", OP_FIDIV, 1, 1, 0 },
1056 { "fimul", OP_FIMUL, 1, 1, 0 },
1057 { "fisub", OP_FISUB, 1, 1, 0 },
1058 { "fidivr", OP_FIDIVR, 1, 1, 0 },
1059 { "fisubr", OP_FISUBR, 1, 1, 0 },
1060 { "fchs", OP_FCHS, 0, 0, 0 },
1061 { "fcos", OP_FCOS, 0, 0, 0 },
1062 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1063 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1064 { "fsin", OP_FSIN, 0, 0, 0 },
1065 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1066 { "fxch", OP_FXCH, 1, 1, 0 },
1067 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1068 // mmx
1069 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1070 { "movq", OP_MOV, 2, 2, OPF_DATA },
1071 // pseudo-ops for lib calls
1072 { "_ftol", OPP_FTOL },
1073 // must be last
1074 { "ud2", OP_UD2 },
1075};
1076
1077static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1078{
1079 enum opr_lenmod lmod = OPLM_UNSPEC;
1080 int prefix_flags = 0;
1081 int regmask_ind;
1082 int regmask;
1083 int op_w = 0;
1084 int opr = 0;
1085 int w = 0;
1086 int i, j;
1087
1088 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1089 if (IS(words[w], pref_table[i].name)) {
1090 prefix_flags = pref_table[i].flags;
1091 break;
1092 }
1093 }
1094
1095 if (prefix_flags) {
1096 if (wordc <= 1)
1097 aerr("lone prefix: '%s'\n", words[0]);
1098 w++;
1099 }
1100
1101 op_w = w;
1102 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1103 if (IS(words[w], op_table[i].name))
1104 break;
1105 }
1106
1107 if (i == ARRAY_SIZE(op_table)) {
1108 if (!g_skip_func)
1109 aerr("unhandled op: '%s'\n", words[0]);
1110 i--; // OP_UD2
1111 }
1112 w++;
1113
1114 op->op = op_table[i].op;
1115 op->flags = op_table[i].flags | prefix_flags;
1116 op->pfo = op_table[i].pfo;
1117 op->pfo_inv = op_table[i].pfo_inv;
1118 op->regmask_src = op->regmask_dst = 0;
1119 op->asmln = asmln;
1120
1121 if (op->op == OP_UD2)
1122 return;
1123
1124 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1125 if (opr >= op_table[i].minopr && w >= wordc)
1126 break;
1127
1128 regmask = regmask_ind = 0;
1129 w = parse_operand(&op->operand[opr], &regmask, &regmask_ind,
1130 words, wordc, w, op->flags);
1131
1132 if (opr == 0 && (op->flags & OPF_DATA))
1133 op->regmask_dst = regmask;
1134 else
1135 op->regmask_src |= regmask;
1136 op->regmask_src |= regmask_ind;
1137
1138 if (op->operand[opr].lmod != OPLM_UNSPEC)
1139 g_func_lmods |= 1 << op->operand[opr].lmod;
1140 }
1141
1142 if (w < wordc)
1143 aerr("parse_op %s incomplete: %d/%d\n",
1144 words[0], w, wordc);
1145
1146 // special cases
1147 op->operand_cnt = opr;
1148 if (!strncmp(op_table[i].name, "set", 3))
1149 op->operand[0].lmod = OPLM_BYTE;
1150
1151 switch (op->op) {
1152 // first operand is not dst
1153 case OP_CMP:
1154 case OP_TEST:
1155 op->regmask_src |= op->regmask_dst;
1156 op->regmask_dst = 0;
1157 break;
1158
1159 // first operand is src too
1160 case OP_NOT:
1161 case OP_ADD:
1162 case OP_AND:
1163 case OP_OR:
1164 case OP_RCL:
1165 case OP_RCR:
1166 case OP_ADC:
1167 case OP_INC:
1168 case OP_DEC:
1169 case OP_NEG:
1170 // more below..
1171 op->regmask_src |= op->regmask_dst;
1172 break;
1173
1174 // special
1175 case OP_XCHG:
1176 op->regmask_src |= op->regmask_dst;
1177 op->regmask_dst |= op->regmask_src;
1178 goto check_align;
1179
1180 case OP_SUB:
1181 case OP_SBB:
1182 case OP_XOR:
1183 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1184 && op->operand[0].lmod == op->operand[1].lmod
1185 && op->operand[0].reg == op->operand[1].reg
1186 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1187 {
1188 op->regmask_src = 0;
1189 }
1190 else
1191 op->regmask_src |= op->regmask_dst;
1192 break;
1193
1194 // ops with implicit argumets
1195 case OP_XLAT:
1196 op->operand_cnt = 2;
1197 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1198 op->regmask_dst = op->regmask_src;
1199 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1200 break;
1201
1202 case OP_CDQ:
1203 op->operand_cnt = 2;
1204 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1205 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1206 break;
1207
1208 case OP_LODS:
1209 case OP_STOS:
1210 case OP_SCAS:
1211 if (words[op_w][4] == 'b')
1212 lmod = OPLM_BYTE;
1213 else if (words[op_w][4] == 'w')
1214 lmod = OPLM_WORD;
1215 else if (words[op_w][4] == 'd')
1216 lmod = OPLM_DWORD;
1217 j = 0;
1218 op->regmask_src = 0;
1219 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1220 OPLM_DWORD, &op->regmask_src);
1221 op->regmask_dst = op->regmask_src;
1222 setup_reg_opr(&op->operand[j++], xAX, lmod,
1223 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1224 if (op->flags & OPF_REP) {
1225 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1226 op->regmask_dst |= 1 << xCX;
1227 }
1228 op->operand_cnt = j;
1229 break;
1230
1231 case OP_MOVS:
1232 case OP_CMPS:
1233 if (words[op_w][4] == 'b')
1234 lmod = OPLM_BYTE;
1235 else if (words[op_w][4] == 'w')
1236 lmod = OPLM_WORD;
1237 else if (words[op_w][4] == 'd')
1238 lmod = OPLM_DWORD;
1239 j = 0;
1240 op->regmask_src = 0;
1241 // note: lmod is not correct, don't have where to place it
1242 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1243 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1244 if (op->flags & OPF_REP)
1245 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1246 op->operand_cnt = j;
1247 op->regmask_dst = op->regmask_src;
1248 break;
1249
1250 case OP_LOOP:
1251 op->regmask_dst = 1 << xCX;
1252 // fallthrough
1253 case OP_JECXZ:
1254 op->operand_cnt = 2;
1255 op->regmask_src = 1 << xCX;
1256 op->operand[1].type = OPT_REG;
1257 op->operand[1].reg = xCX;
1258 op->operand[1].lmod = OPLM_DWORD;
1259 break;
1260
1261 case OP_IMUL:
1262 if (op->operand_cnt == 2) {
1263 if (op->operand[0].type != OPT_REG)
1264 aerr("reg expected\n");
1265 op->regmask_src |= 1 << op->operand[0].reg;
1266 }
1267 if (op->operand_cnt != 1)
1268 break;
1269 // fallthrough
1270 case OP_MUL:
1271 // singleop mul
1272 op->regmask_src |= op->regmask_dst;
1273 op->regmask_dst = (1 << xDX) | (1 << xAX);
1274 if (op->operand[0].lmod == OPLM_UNSPEC)
1275 op->operand[0].lmod = OPLM_DWORD;
1276 break;
1277
1278 case OP_DIV:
1279 case OP_IDIV:
1280 // we could set up operands for edx:eax, but there is no real need to
1281 // (see is_opr_modified())
1282 op->regmask_src |= op->regmask_dst;
1283 op->regmask_dst = (1 << xDX) | (1 << xAX);
1284 if (op->operand[0].lmod == OPLM_UNSPEC)
1285 op->operand[0].lmod = OPLM_DWORD;
1286 break;
1287
1288 case OP_SHL:
1289 case OP_SHR:
1290 case OP_SAR:
1291 case OP_ROL:
1292 case OP_ROR:
1293 op->regmask_src |= op->regmask_dst;
1294 if (op->operand[1].lmod == OPLM_UNSPEC)
1295 op->operand[1].lmod = OPLM_BYTE;
1296 break;
1297
1298 case OP_SHLD:
1299 case OP_SHRD:
1300 op->regmask_src |= op->regmask_dst;
1301 if (op->operand[2].lmod == OPLM_UNSPEC)
1302 op->operand[2].lmod = OPLM_BYTE;
1303 break;
1304
1305 case OP_PUSH:
1306 op->regmask_src |= op->regmask_dst;
1307 op->regmask_dst = 0;
1308 if (op->operand[0].lmod == OPLM_UNSPEC
1309 && (op->operand[0].type == OPT_CONST
1310 || op->operand[0].type == OPT_OFFSET
1311 || op->operand[0].type == OPT_LABEL))
1312 op->operand[0].lmod = OPLM_DWORD;
1313 break;
1314
1315 // alignment
1316 case OP_MOV:
1317 check_align:
1318 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1319 && op->operand[0].lmod == op->operand[1].lmod
1320 && op->operand[0].reg == op->operand[1].reg
1321 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1322 {
1323 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1324 op->regmask_src = op->regmask_dst = 0;
1325 }
1326 break;
1327
1328 case OP_LEA:
1329 if (op->operand[0].type == OPT_REG
1330 && op->operand[1].type == OPT_REGMEM)
1331 {
1332 char buf[16];
1333 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1334 if (IS(buf, op->operand[1].name))
1335 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1336 }
1337 break;
1338
1339 case OP_CALL:
1340 // trashed regs must be explicitly detected later
1341 op->regmask_dst = 0;
1342 break;
1343
1344 case OP_LEAVE:
1345 op->regmask_dst = (1 << xBP) | (1 << xSP);
1346 op->regmask_src = 1 << xBP;
1347 break;
1348
1349 case OP_FLD:
1350 case OP_FILD:
1351 op->regmask_dst |= mxST0;
1352 break;
1353
1354 case OP_FLDc:
1355 op->regmask_dst |= mxST0;
1356 if (IS(words[op_w] + 3, "1"))
1357 op->operand[0].val = X87_CONST_1;
1358 else if (IS(words[op_w] + 3, "ln2"))
1359 op->operand[0].val = X87_CONST_LN2;
1360 else if (IS(words[op_w] + 3, "z"))
1361 op->operand[0].val = X87_CONST_Z;
1362 else
1363 aerr("TODO\n");
1364 break;
1365
1366 case OP_FST:
1367 op->regmask_src |= mxST0;
1368 break;
1369
1370 case OP_FADD:
1371 case OP_FDIV:
1372 case OP_FMUL:
1373 case OP_FSUB:
1374 case OP_FDIVR:
1375 case OP_FSUBR:
1376 op->regmask_src |= mxST0;
1377 if (op->operand_cnt == 2)
1378 op->regmask_src |= op->regmask_dst;
1379 else if (op->operand_cnt == 1) {
1380 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1381 op->operand[0].type = OPT_REG;
1382 op->operand[0].lmod = OPLM_QWORD;
1383 op->operand[0].reg = xST0;
1384 op->regmask_dst |= mxST0;
1385 }
1386 else
1387 // IDA doesn't use this
1388 aerr("no operands?\n");
1389 break;
1390
1391 case OP_FIADD:
1392 case OP_FIDIV:
1393 case OP_FIMUL:
1394 case OP_FISUB:
1395 case OP_FIDIVR:
1396 case OP_FISUBR:
1397 case OP_FCHS:
1398 case OP_FCOS:
1399 case OP_FSIN:
1400 case OP_FSQRT:
1401 case OP_FXCH:
1402 op->regmask_src |= mxST0;
1403 op->regmask_dst |= mxST0;
1404 break;
1405
1406 case OP_FPATAN:
1407 case OP_FYL2X:
1408 op->regmask_src |= mxST0 | mxST1;
1409 op->regmask_dst |= mxST0;
1410 break;
1411
1412 case OP_FPTAN:
1413 aerr("TODO\n");
1414 break;
1415
1416 default:
1417 break;
1418 }
1419
1420 if (op->operand[0].type == OPT_REG
1421 && op->operand[1].type == OPT_CONST)
1422 {
1423 struct parsed_opr *op1 = &op->operand[1];
1424 if ((op->op == OP_AND && op1->val == 0)
1425 || (op->op == OP_OR
1426 && (op1->val == ~0
1427 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1428 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1429 {
1430 op->regmask_src = 0;
1431 }
1432 }
1433}
1434
1435static const char *op_name(struct parsed_op *po)
1436{
1437 static char buf[16];
1438 char *p;
1439 int i;
1440
1441 if (po->op == OP_JCC || po->op == OP_SCC) {
1442 p = buf;
1443 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1444 if (po->pfo_inv)
1445 *p++ = 'n';
1446 strcpy(p, parsed_flag_op_names[po->pfo]);
1447 return buf;
1448 }
1449
1450 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1451 if (op_table[i].op == po->op)
1452 return op_table[i].name;
1453
1454 return "???";
1455}
1456
1457// debug
1458static const char *dump_op(struct parsed_op *po)
1459{
1460 static char out[128];
1461 char *p = out;
1462 int i;
1463
1464 if (po == NULL)
1465 return "???";
1466
1467 snprintf(out, sizeof(out), "%s", op_name(po));
1468 for (i = 0; i < po->operand_cnt; i++) {
1469 p += strlen(p);
1470 if (i > 0)
1471 *p++ = ',';
1472 snprintf(p, sizeof(out) - (p - out),
1473 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1474 po->operand[i].name);
1475 }
1476
1477 return out;
1478}
1479
1480static const char *lmod_type_u(struct parsed_op *po,
1481 enum opr_lenmod lmod)
1482{
1483 switch (lmod) {
1484 case OPLM_QWORD:
1485 return "u64";
1486 case OPLM_DWORD:
1487 return "u32";
1488 case OPLM_WORD:
1489 return "u16";
1490 case OPLM_BYTE:
1491 return "u8";
1492 default:
1493 ferr(po, "invalid lmod: %d\n", lmod);
1494 return "(_invalid_)";
1495 }
1496}
1497
1498static const char *lmod_cast_u(struct parsed_op *po,
1499 enum opr_lenmod lmod)
1500{
1501 switch (lmod) {
1502 case OPLM_QWORD:
1503 return "";
1504 case OPLM_DWORD:
1505 return "";
1506 case OPLM_WORD:
1507 return "(u16)";
1508 case OPLM_BYTE:
1509 return "(u8)";
1510 default:
1511 ferr(po, "invalid lmod: %d\n", lmod);
1512 return "(_invalid_)";
1513 }
1514}
1515
1516static const char *lmod_cast_u_ptr(struct parsed_op *po,
1517 enum opr_lenmod lmod)
1518{
1519 switch (lmod) {
1520 case OPLM_QWORD:
1521 return "*(u64 *)";
1522 case OPLM_DWORD:
1523 return "*(u32 *)";
1524 case OPLM_WORD:
1525 return "*(u16 *)";
1526 case OPLM_BYTE:
1527 return "*(u8 *)";
1528 default:
1529 ferr(po, "invalid lmod: %d\n", lmod);
1530 return "(_invalid_)";
1531 }
1532}
1533
1534static const char *lmod_cast_s(struct parsed_op *po,
1535 enum opr_lenmod lmod)
1536{
1537 switch (lmod) {
1538 case OPLM_QWORD:
1539 return "(s64)";
1540 case OPLM_DWORD:
1541 return "(s32)";
1542 case OPLM_WORD:
1543 return "(s16)";
1544 case OPLM_BYTE:
1545 return "(s8)";
1546 default:
1547 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1548 return "(_invalid_)";
1549 }
1550}
1551
1552static const char *lmod_cast(struct parsed_op *po,
1553 enum opr_lenmod lmod, int is_signed)
1554{
1555 return is_signed ?
1556 lmod_cast_s(po, lmod) :
1557 lmod_cast_u(po, lmod);
1558}
1559
1560static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1561{
1562 switch (lmod) {
1563 case OPLM_QWORD:
1564 return 8;
1565 case OPLM_DWORD:
1566 return 4;
1567 case OPLM_WORD:
1568 return 2;
1569 case OPLM_BYTE:
1570 return 1;
1571 default:
1572 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1573 return 0;
1574 }
1575}
1576
1577static const char *opr_name(struct parsed_op *po, int opr_num)
1578{
1579 if (opr_num >= po->operand_cnt)
1580 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1581 return po->operand[opr_num].name;
1582}
1583
1584static unsigned int opr_const(struct parsed_op *po, int opr_num)
1585{
1586 if (opr_num >= po->operand_cnt)
1587 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1588 if (po->operand[opr_num].type != OPT_CONST)
1589 ferr(po, "opr %d: const expected\n", opr_num);
1590 return po->operand[opr_num].val;
1591}
1592
1593static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1594{
1595 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1596 ferr(po, "invalid reg: %d\n", popr->reg);
1597 return regs_r32[popr->reg];
1598}
1599
1600static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1601{
1602 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1603 *bits = 8;
1604 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1605 *bits = 16;
1606 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1607 *bits = 32;
1608 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1609 *bits = 64;
1610 else
1611 return -1;
1612
1613 *is_signed = cast[1] == 's' ? 1 : 0;
1614 return 0;
1615}
1616
1617static int check_deref_cast(const char *cast, int *bits)
1618{
1619 if (IS_START(cast, "*(u8 *)"))
1620 *bits = 8;
1621 else if (IS_START(cast, "*(u16 *)"))
1622 *bits = 16;
1623 else if (IS_START(cast, "*(u32 *)"))
1624 *bits = 32;
1625 else if (IS_START(cast, "*(u64 *)"))
1626 *bits = 64;
1627 else
1628 return -1;
1629
1630 return 0;
1631}
1632
1633// cast1 is the "final" cast
1634static const char *simplify_cast(const char *cast1, const char *cast2)
1635{
1636 static char buf[256];
1637 int bits1, bits2;
1638 int s1, s2;
1639
1640 if (cast1[0] == 0)
1641 return cast2;
1642 if (cast2[0] == 0)
1643 return cast1;
1644 if (IS(cast1, cast2))
1645 return cast1;
1646
1647 if (check_simple_cast(cast1, &bits1, &s1) == 0
1648 && check_simple_cast(cast2, &bits2, &s2) == 0)
1649 {
1650 if (bits1 <= bits2)
1651 return cast1;
1652 }
1653 if (check_simple_cast(cast1, &bits1, &s1) == 0
1654 && check_deref_cast(cast2, &bits2) == 0)
1655 {
1656 if (bits1 == bits2) {
1657 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1658 return buf;
1659 }
1660 }
1661
1662 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1663 return cast1;
1664
1665 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1666 return buf;
1667}
1668
1669static const char *simplify_cast_num(const char *cast, unsigned int val)
1670{
1671 if (IS(cast, "(u8)") && val < 0x100)
1672 return "";
1673 if (IS(cast, "(s8)") && val < 0x80)
1674 return "";
1675 if (IS(cast, "(u16)") && val < 0x10000)
1676 return "";
1677 if (IS(cast, "(s16)") && val < 0x8000)
1678 return "";
1679 if (IS(cast, "(s32)") && val < 0x80000000)
1680 return "";
1681
1682 return cast;
1683}
1684
1685static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1686 int *extra_offs)
1687{
1688 const char *p;
1689 char *endp;
1690 int namelen;
1691 int i;
1692
1693 *extra_offs = 0;
1694 namelen = strlen(name);
1695
1696 p = strchr(name, '+');
1697 if (p != NULL) {
1698 namelen = p - name;
1699 if (namelen <= 0)
1700 ferr(po, "equ parse failed for '%s'\n", name);
1701
1702 if (IS_START(p, "0x"))
1703 p += 2;
1704 *extra_offs = strtol(p, &endp, 16);
1705 if (*endp != 0)
1706 ferr(po, "equ parse failed for '%s'\n", name);
1707 }
1708
1709 for (i = 0; i < g_eqcnt; i++)
1710 if (strncmp(g_eqs[i].name, name, namelen) == 0
1711 && g_eqs[i].name[namelen] == 0)
1712 break;
1713 if (i >= g_eqcnt) {
1714 if (po != NULL)
1715 ferr(po, "unresolved equ name: '%s'\n", name);
1716 return NULL;
1717 }
1718
1719 return &g_eqs[i];
1720}
1721
1722static int is_stack_access(struct parsed_op *po,
1723 const struct parsed_opr *popr)
1724{
1725 return (parse_stack_el(popr->name, NULL, 0)
1726 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1727 && IS_START(popr->name, "ebp")));
1728}
1729
1730static void parse_stack_access(struct parsed_op *po,
1731 const char *name, char *ofs_reg, int *offset_out,
1732 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1733{
1734 const char *bp_arg = "";
1735 const char *p = NULL;
1736 struct parsed_equ *eq;
1737 char *endp = NULL;
1738 int stack_ra = 0;
1739 int offset = 0;
1740
1741 ofs_reg[0] = 0;
1742
1743 if (IS_START(name, "ebp-")
1744 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1745 {
1746 p = name + 4;
1747 if (IS_START(p, "0x"))
1748 p += 2;
1749 offset = strtoul(p, &endp, 16);
1750 if (name[3] == '-')
1751 offset = -offset;
1752 if (*endp != 0)
1753 ferr(po, "ebp- parse of '%s' failed\n", name);
1754 }
1755 else {
1756 bp_arg = parse_stack_el(name, ofs_reg, 0);
1757 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1758 eq = equ_find(po, bp_arg, &offset);
1759 if (eq == NULL)
1760 ferr(po, "detected but missing eq\n");
1761 offset += eq->offset;
1762 }
1763
1764 if (!strncmp(name, "ebp", 3))
1765 stack_ra = 4;
1766
1767 // yes it sometimes LEAs ra for compares..
1768 if (!is_lea && ofs_reg[0] == 0
1769 && stack_ra <= offset && offset < stack_ra + 4)
1770 {
1771 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1772 }
1773
1774 *offset_out = offset;
1775 *stack_ra_out = stack_ra;
1776 if (bp_arg_out)
1777 *bp_arg_out = bp_arg;
1778}
1779
1780static int stack_frame_access(struct parsed_op *po,
1781 struct parsed_opr *popr, char *buf, size_t buf_size,
1782 const char *name, const char *cast, int is_src, int is_lea)
1783{
1784 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1785 const char *prefix = "";
1786 const char *bp_arg = NULL;
1787 char ofs_reg[16] = { 0, };
1788 int i, arg_i, arg_s;
1789 int unaligned = 0;
1790 int stack_ra = 0;
1791 int offset = 0;
1792 int retval = -1;
1793 int sf_ofs;
1794 int lim;
1795
1796 if (po->flags & OPF_EBP_S)
1797 ferr(po, "stack_frame_access while ebp is scratch\n");
1798
1799 parse_stack_access(po, name, ofs_reg, &offset,
1800 &stack_ra, &bp_arg, is_lea);
1801
1802 if (offset > stack_ra)
1803 {
1804 arg_i = (offset - stack_ra - 4) / 4;
1805 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1806 {
1807 if (g_func_pp->is_vararg
1808 && arg_i == g_func_pp->argc_stack && is_lea)
1809 {
1810 // should be va_list
1811 if (cast[0] == 0)
1812 cast = "(u32)";
1813 snprintf(buf, buf_size, "%sap", cast);
1814 return -1;
1815 }
1816 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1817 offset, bp_arg, arg_i);
1818 }
1819 if (ofs_reg[0] != 0)
1820 ferr(po, "offset reg on arg access?\n");
1821
1822 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1823 if (g_func_pp->arg[i].reg != NULL)
1824 continue;
1825 if (arg_s == arg_i)
1826 break;
1827 arg_s++;
1828 }
1829 if (i == g_func_pp->argc)
1830 ferr(po, "arg %d not in prototype?\n", arg_i);
1831
1832 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1833 retval = i;
1834
1835 switch (popr->lmod)
1836 {
1837 case OPLM_BYTE:
1838 if (is_lea)
1839 ferr(po, "lea/byte to arg?\n");
1840 if (is_src && (offset & 3) == 0)
1841 snprintf(buf, buf_size, "%sa%d",
1842 simplify_cast(cast, "(u8)"), i + 1);
1843 else
1844 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1845 cast, offset & 3, i + 1);
1846 break;
1847
1848 case OPLM_WORD:
1849 if (is_lea)
1850 ferr(po, "lea/word to arg?\n");
1851 if (offset & 1) {
1852 unaligned = 1;
1853 if (!is_src) {
1854 if (offset & 2)
1855 ferr(po, "problematic arg store\n");
1856 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1857 simplify_cast(cast, "*(u16 *)"), i + 1);
1858 }
1859 else
1860 ferr(po, "unaligned arg word load\n");
1861 }
1862 else if (is_src && (offset & 2) == 0)
1863 snprintf(buf, buf_size, "%sa%d",
1864 simplify_cast(cast, "(u16)"), i + 1);
1865 else
1866 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1867 cast, (offset & 2) ? "HI" : "LO", i + 1);
1868 break;
1869
1870 case OPLM_DWORD:
1871 if (cast[0])
1872 prefix = cast;
1873 else if (is_src)
1874 prefix = "(u32)";
1875
1876 if (offset & 3) {
1877 unaligned = 1;
1878 if (is_lea)
1879 snprintf(buf, buf_size, "(u32)&a%d + %d",
1880 i + 1, offset & 3);
1881 else if (!is_src)
1882 ferr(po, "unaligned arg store\n");
1883 else {
1884 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1885 snprintf(buf, buf_size, "%s(a%d >> %d)",
1886 prefix, i + 1, (offset & 3) * 8);
1887 }
1888 }
1889 else {
1890 snprintf(buf, buf_size, "%s%sa%d",
1891 prefix, is_lea ? "&" : "", i + 1);
1892 }
1893 break;
1894
1895 default:
1896 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1897 }
1898
1899 if (unaligned)
1900 snprintf(g_comment, sizeof(g_comment), "%s unaligned", bp_arg);
1901
1902 // common problem
1903 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
1904 if (tmp_lmod != OPLM_DWORD
1905 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
1906 < lmod_bytes(po, popr->lmod) + (offset & 3))))
1907 {
1908 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
1909 i + 1, offset, g_func_pp->arg[i].type.name);
1910 }
1911 // can't check this because msvc likes to reuse
1912 // arg space for scratch..
1913 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
1914 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
1915 }
1916 else
1917 {
1918 if (g_stack_fsz == 0)
1919 ferr(po, "stack var access without stackframe\n");
1920 g_stack_frame_used = 1;
1921
1922 sf_ofs = g_stack_fsz + offset;
1923 lim = (ofs_reg[0] != 0) ? -4 : 0;
1924 if (offset > 0 || sf_ofs < lim)
1925 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
1926
1927 if (is_lea)
1928 prefix = "(u32)&";
1929 else
1930 prefix = cast;
1931
1932 switch (popr->lmod)
1933 {
1934 case OPLM_BYTE:
1935 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1936 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1937 break;
1938
1939 case OPLM_WORD:
1940 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
1941 // known unaligned or possibly unaligned
1942 strcat(g_comment, " unaligned");
1943 if (prefix[0] == 0)
1944 prefix = "*(u16 *)&";
1945 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1946 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1947 break;
1948 }
1949 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
1950 break;
1951
1952 case OPLM_DWORD:
1953 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
1954 // known unaligned or possibly unaligned
1955 strcat(g_comment, " unaligned");
1956 if (prefix[0] == 0)
1957 prefix = "*(u32 *)&";
1958 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1959 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1960 break;
1961 }
1962 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
1963 break;
1964
1965 case OPLM_QWORD:
1966 ferr_assert(po, !(sf_ofs & 7));
1967 ferr_assert(po, ofs_reg[0] == 0);
1968 // float callers set is_lea
1969 ferr_assert(po, is_lea);
1970 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
1971 break;
1972
1973 default:
1974 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
1975 }
1976 }
1977
1978 return retval;
1979}
1980
1981static void check_func_pp(struct parsed_op *po,
1982 const struct parsed_proto *pp, const char *pfx)
1983{
1984 enum opr_lenmod tmp_lmod;
1985 char buf[256];
1986 int ret, i;
1987
1988 if (pp->argc_reg != 0) {
1989 if (/*!g_allow_regfunc &&*/ !pp->is_fastcall) {
1990 pp_print(buf, sizeof(buf), pp);
1991 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
1992 }
1993 if (pp->argc_stack > 0 && pp->argc_reg != 2)
1994 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
1995 pfx, pp->argc_reg, pp->argc_stack);
1996 }
1997
1998 // fptrs must use 32bit args, callsite might have no information and
1999 // lack a cast to smaller types, which results in incorrectly masked
2000 // args passed (callee may assume masked args, it does on ARM)
2001 if (!pp->is_osinc) {
2002 for (i = 0; i < pp->argc; i++) {
2003 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2004 if (ret && tmp_lmod != OPLM_DWORD)
2005 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2006 i + 1, pp->arg[i].type.name);
2007 }
2008 }
2009}
2010
2011static const char *check_label_read_ref(struct parsed_op *po,
2012 const char *name)
2013{
2014 const struct parsed_proto *pp;
2015
2016 pp = proto_parse(g_fhdr, name, 0);
2017 if (pp == NULL)
2018 ferr(po, "proto_parse failed for ref '%s'\n", name);
2019
2020 if (pp->is_func)
2021 check_func_pp(po, pp, "ref");
2022
2023 return pp->name;
2024}
2025
2026static char *out_src_opr(char *buf, size_t buf_size,
2027 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2028 int is_lea)
2029{
2030 char tmp1[256], tmp2[256];
2031 char expr[256];
2032 const char *name;
2033 char *p;
2034 int ret;
2035
2036 if (cast == NULL)
2037 cast = "";
2038
2039 switch (popr->type) {
2040 case OPT_REG:
2041 if (is_lea)
2042 ferr(po, "lea from reg?\n");
2043
2044 switch (popr->lmod) {
2045 case OPLM_QWORD:
2046 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2047 break;
2048 case OPLM_DWORD:
2049 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2050 break;
2051 case OPLM_WORD:
2052 snprintf(buf, buf_size, "%s%s",
2053 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2054 break;
2055 case OPLM_BYTE:
2056 if (popr->name[1] == 'h') // XXX..
2057 snprintf(buf, buf_size, "%s(%s >> 8)",
2058 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2059 else
2060 snprintf(buf, buf_size, "%s%s",
2061 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2062 break;
2063 default:
2064 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2065 }
2066 break;
2067
2068 case OPT_REGMEM:
2069 if (is_stack_access(po, popr)) {
2070 stack_frame_access(po, popr, buf, buf_size,
2071 popr->name, cast, 1, is_lea);
2072 break;
2073 }
2074
2075 strcpy(expr, popr->name);
2076 if (strchr(expr, '[')) {
2077 // special case: '[' can only be left for label[reg] form
2078 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2079 if (ret != 2)
2080 ferr(po, "parse failure for '%s'\n", expr);
2081 if (tmp1[0] == '(') {
2082 // (off_4FFF50+3)[eax]
2083 p = strchr(tmp1 + 1, ')');
2084 if (p == NULL || p[1] != 0)
2085 ferr(po, "parse failure (2) for '%s'\n", expr);
2086 *p = 0;
2087 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2088 }
2089 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2090 }
2091
2092 // XXX: do we need more parsing?
2093 if (is_lea) {
2094 snprintf(buf, buf_size, "%s", expr);
2095 break;
2096 }
2097
2098 snprintf(buf, buf_size, "%s(%s)",
2099 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2100 break;
2101
2102 case OPT_LABEL:
2103 name = check_label_read_ref(po, popr->name);
2104 if (cast[0] == 0 && popr->is_ptr)
2105 cast = "(u32)";
2106
2107 if (is_lea)
2108 snprintf(buf, buf_size, "(u32)&%s", name);
2109 else if (popr->size_lt)
2110 snprintf(buf, buf_size, "%s%s%s%s", cast,
2111 lmod_cast_u_ptr(po, popr->lmod),
2112 popr->is_array ? "" : "&", name);
2113 else
2114 snprintf(buf, buf_size, "%s%s%s", cast, name,
2115 popr->is_array ? "[0]" : "");
2116 break;
2117
2118 case OPT_OFFSET:
2119 name = check_label_read_ref(po, popr->name);
2120 if (cast[0] == 0)
2121 cast = "(u32)";
2122 if (is_lea)
2123 ferr(po, "lea an offset?\n");
2124 snprintf(buf, buf_size, "%s&%s", cast, name);
2125 break;
2126
2127 case OPT_CONST:
2128 if (is_lea)
2129 ferr(po, "lea from const?\n");
2130
2131 printf_number(tmp1, sizeof(tmp1), popr->val);
2132 if (popr->val == 0 && strchr(cast, '*'))
2133 snprintf(buf, buf_size, "NULL");
2134 else
2135 snprintf(buf, buf_size, "%s%s",
2136 simplify_cast_num(cast, popr->val), tmp1);
2137 break;
2138
2139 default:
2140 ferr(po, "invalid src type: %d\n", popr->type);
2141 }
2142
2143 return buf;
2144}
2145
2146// note: may set is_ptr (we find that out late for ebp frame..)
2147static char *out_dst_opr(char *buf, size_t buf_size,
2148 struct parsed_op *po, struct parsed_opr *popr)
2149{
2150 switch (popr->type) {
2151 case OPT_REG:
2152 switch (popr->lmod) {
2153 case OPLM_QWORD:
2154 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2155 break;
2156 case OPLM_DWORD:
2157 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2158 break;
2159 case OPLM_WORD:
2160 // ugh..
2161 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2162 break;
2163 case OPLM_BYTE:
2164 // ugh..
2165 if (popr->name[1] == 'h') // XXX..
2166 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2167 else
2168 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2169 break;
2170 default:
2171 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2172 }
2173 break;
2174
2175 case OPT_REGMEM:
2176 if (is_stack_access(po, popr)) {
2177 stack_frame_access(po, popr, buf, buf_size,
2178 popr->name, "", 0, 0);
2179 break;
2180 }
2181
2182 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2183
2184 case OPT_LABEL:
2185 if (popr->size_mismatch)
2186 snprintf(buf, buf_size, "%s%s%s",
2187 lmod_cast_u_ptr(po, popr->lmod),
2188 popr->is_array ? "" : "&", popr->name);
2189 else
2190 snprintf(buf, buf_size, "%s%s", popr->name,
2191 popr->is_array ? "[0]" : "");
2192 break;
2193
2194 default:
2195 ferr(po, "invalid dst type: %d\n", popr->type);
2196 }
2197
2198 return buf;
2199}
2200
2201static char *out_src_opr_u32(char *buf, size_t buf_size,
2202 struct parsed_op *po, struct parsed_opr *popr)
2203{
2204 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2205}
2206
2207static char *out_src_opr_float(char *buf, size_t buf_size,
2208 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2209{
2210 const char *cast = NULL;
2211 char tmp[256];
2212
2213 switch (popr->type) {
2214 case OPT_REG:
2215 if (popr->reg < xST0 || popr->reg > xST7)
2216 ferr(po, "bad reg: %d\n", popr->reg);
2217
2218 if (need_float_stack) {
2219 if (popr->reg == xST0)
2220 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2221 else
2222 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2223 popr->reg - xST0);
2224 }
2225 else
2226 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2227 break;
2228
2229 case OPT_REGMEM:
2230 case OPT_LABEL:
2231 case OPT_OFFSET:
2232 switch (popr->lmod) {
2233 case OPLM_QWORD:
2234 cast = "double";
2235 break;
2236 case OPLM_DWORD:
2237 cast = "float";
2238 break;
2239 default:
2240 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2241 break;
2242 }
2243 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2244 snprintf(buf, buf_size, "*((%s *)%s)", cast, tmp);
2245 break;
2246
2247 default:
2248 ferr(po, "invalid float type: %d\n", popr->type);
2249 }
2250
2251 return buf;
2252}
2253
2254static char *out_dst_opr_float(char *buf, size_t buf_size,
2255 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2256{
2257 // same?
2258 return out_src_opr_float(buf, buf_size, po, popr, need_float_stack);
2259}
2260
2261static void out_test_for_cc(char *buf, size_t buf_size,
2262 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2263 enum opr_lenmod lmod, const char *expr)
2264{
2265 const char *cast, *scast;
2266
2267 cast = lmod_cast_u(po, lmod);
2268 scast = lmod_cast_s(po, lmod);
2269
2270 switch (pfo) {
2271 case PFO_Z:
2272 case PFO_BE: // CF=1||ZF=1; CF=0
2273 snprintf(buf, buf_size, "(%s%s %s 0)",
2274 cast, expr, is_inv ? "!=" : "==");
2275 break;
2276
2277 case PFO_S:
2278 case PFO_L: // SF!=OF; OF=0
2279 snprintf(buf, buf_size, "(%s%s %s 0)",
2280 scast, expr, is_inv ? ">=" : "<");
2281 break;
2282
2283 case PFO_LE: // ZF=1||SF!=OF; OF=0
2284 snprintf(buf, buf_size, "(%s%s %s 0)",
2285 scast, expr, is_inv ? ">" : "<=");
2286 break;
2287
2288 default:
2289 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2290 }
2291}
2292
2293static void out_cmp_for_cc(char *buf, size_t buf_size,
2294 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2295{
2296 const char *cast, *scast, *cast_use;
2297 char buf1[256], buf2[256];
2298 enum opr_lenmod lmod;
2299
2300 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2301 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2302 po->operand[0].lmod, po->operand[1].lmod);
2303 lmod = po->operand[0].lmod;
2304
2305 cast = lmod_cast_u(po, lmod);
2306 scast = lmod_cast_s(po, lmod);
2307
2308 switch (pfo) {
2309 case PFO_C:
2310 case PFO_Z:
2311 case PFO_BE: // !a
2312 cast_use = cast;
2313 break;
2314
2315 case PFO_S:
2316 case PFO_L: // !ge
2317 case PFO_LE:
2318 cast_use = scast;
2319 break;
2320
2321 default:
2322 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2323 }
2324
2325 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2326 if (po->op == OP_DEC)
2327 snprintf(buf2, sizeof(buf2), "1");
2328 else
2329 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_use, 0);
2330
2331 switch (pfo) {
2332 case PFO_C:
2333 // note: must be unsigned compare
2334 snprintf(buf, buf_size, "(%s %s %s)",
2335 buf1, is_inv ? ">=" : "<", buf2);
2336 break;
2337
2338 case PFO_Z:
2339 snprintf(buf, buf_size, "(%s %s %s)",
2340 buf1, is_inv ? "!=" : "==", buf2);
2341 break;
2342
2343 case PFO_BE: // !a
2344 // note: must be unsigned compare
2345 snprintf(buf, buf_size, "(%s %s %s)",
2346 buf1, is_inv ? ">" : "<=", buf2);
2347
2348 // annoying case
2349 if (is_inv && lmod == OPLM_BYTE
2350 && po->operand[1].type == OPT_CONST
2351 && po->operand[1].val == 0xff)
2352 {
2353 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2354 snprintf(buf, buf_size, "(0)");
2355 }
2356 break;
2357
2358 // note: must be signed compare
2359 case PFO_S:
2360 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2361 scast, buf1, buf2, is_inv ? ">=" : "<");
2362 break;
2363
2364 case PFO_L: // !ge
2365 snprintf(buf, buf_size, "(%s %s %s)",
2366 buf1, is_inv ? ">=" : "<", buf2);
2367 break;
2368
2369 case PFO_LE: // !g
2370 snprintf(buf, buf_size, "(%s %s %s)",
2371 buf1, is_inv ? ">" : "<=", buf2);
2372 break;
2373
2374 default:
2375 break;
2376 }
2377}
2378
2379static void out_cmp_test(char *buf, size_t buf_size,
2380 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2381{
2382 char buf1[256], buf2[256], buf3[256];
2383
2384 if (po->op == OP_TEST) {
2385 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2386 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2387 }
2388 else {
2389 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2390 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2391 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2392 }
2393 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2394 po->operand[0].lmod, buf3);
2395 }
2396 else if (po->op == OP_CMP) {
2397 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv);
2398 }
2399 else
2400 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2401}
2402
2403static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2404 struct parsed_opr *popr2)
2405{
2406 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2407 ferr(po, "missing lmod for both operands\n");
2408
2409 if (popr1->lmod == OPLM_UNSPEC)
2410 popr1->lmod = popr2->lmod;
2411 else if (popr2->lmod == OPLM_UNSPEC)
2412 popr2->lmod = popr1->lmod;
2413 else if (popr1->lmod != popr2->lmod) {
2414 if (popr1->type_from_var) {
2415 popr1->size_mismatch = 1;
2416 if (popr1->lmod < popr2->lmod)
2417 popr1->size_lt = 1;
2418 popr1->lmod = popr2->lmod;
2419 }
2420 else if (popr2->type_from_var) {
2421 popr2->size_mismatch = 1;
2422 if (popr2->lmod < popr1->lmod)
2423 popr2->size_lt = 1;
2424 popr2->lmod = popr1->lmod;
2425 }
2426 else
2427 ferr(po, "conflicting lmods: %d vs %d\n",
2428 popr1->lmod, popr2->lmod);
2429 }
2430}
2431
2432static const char *op_to_c(struct parsed_op *po)
2433{
2434 switch (po->op)
2435 {
2436 case OP_ADD:
2437 case OP_ADC:
2438 return "+";
2439 case OP_SUB:
2440 case OP_SBB:
2441 return "-";
2442 case OP_AND:
2443 return "&";
2444 case OP_OR:
2445 return "|";
2446 case OP_XOR:
2447 return "^";
2448 case OP_SHL:
2449 return "<<";
2450 case OP_SHR:
2451 return ">>";
2452 case OP_MUL:
2453 case OP_IMUL:
2454 return "*";
2455 default:
2456 ferr(po, "op_to_c was supplied with %d\n", po->op);
2457 }
2458}
2459
2460// last op in stream - unconditional branch or ret
2461#define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2462 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2463 && ops[_i].op != OP_CALL))
2464
2465#define check_i(po, i) \
2466 if ((i) < 0) \
2467 ferr(po, "bad " #i ": %d\n", i)
2468
2469// note: this skips over calls and rm'd stuff assuming they're handled
2470// so it's intended to use at one of final passes
2471static int scan_for_pop(int i, int opcnt, int magic, int reg,
2472 int depth, int flags_set)
2473{
2474 struct parsed_op *po;
2475 int relevant;
2476 int ret = 0;
2477 int j;
2478
2479 for (; i < opcnt; i++) {
2480 po = &ops[i];
2481 if (po->cc_scratch == magic)
2482 return ret; // already checked
2483 po->cc_scratch = magic;
2484
2485 if (po->flags & OPF_TAIL) {
2486 if (po->op == OP_CALL) {
2487 if (po->pp != NULL && po->pp->is_noreturn)
2488 // assume no stack cleanup for noreturn
2489 return 1;
2490 }
2491 return -1; // deadend
2492 }
2493
2494 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2495 continue;
2496
2497 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2498 if (po->btj != NULL) {
2499 // jumptable
2500 for (j = 0; j < po->btj->count; j++) {
2501 check_i(po, po->btj->d[j].bt_i);
2502 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2503 depth, flags_set);
2504 if (ret < 0)
2505 return ret; // dead end
2506 }
2507 return ret;
2508 }
2509
2510 check_i(po, po->bt_i);
2511 if (po->flags & OPF_CJMP) {
2512 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2513 depth, flags_set);
2514 if (ret < 0)
2515 return ret; // dead end
2516 }
2517 else {
2518 i = po->bt_i - 1;
2519 }
2520 continue;
2521 }
2522
2523 relevant = 0;
2524 if ((po->op == OP_POP || po->op == OP_PUSH)
2525 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2526 {
2527 relevant = 1;
2528 }
2529
2530 if (po->op == OP_PUSH) {
2531 depth++;
2532 }
2533 else if (po->op == OP_POP) {
2534 if (relevant && depth == 0) {
2535 po->flags |= flags_set;
2536 return 1;
2537 }
2538 depth--;
2539 }
2540 }
2541
2542 return -1;
2543}
2544
2545// scan for 'reg' pop backwards starting from i
2546// intended to use for register restore search, so other reg
2547// references are considered an error
2548static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2549{
2550 struct parsed_op *po;
2551 struct label_ref *lr;
2552 int ret = 0;
2553
2554 ops[i].cc_scratch = magic;
2555
2556 while (1)
2557 {
2558 if (g_labels[i] != NULL) {
2559 lr = &g_label_refs[i];
2560 for (; lr != NULL; lr = lr->next) {
2561 check_i(&ops[i], lr->i);
2562 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2563 if (ret < 0)
2564 return ret;
2565 }
2566 if (i > 0 && LAST_OP(i - 1))
2567 return ret;
2568 }
2569
2570 i--;
2571 if (i < 0)
2572 break;
2573
2574 if (ops[i].cc_scratch == magic)
2575 return ret;
2576 ops[i].cc_scratch = magic;
2577
2578 po = &ops[i];
2579 if (po->op == OP_POP && po->operand[0].reg == reg) {
2580 if (po->flags & (OPF_RMD|OPF_DONE))
2581 return -1;
2582
2583 po->flags |= set_flags;
2584 return 1;
2585 }
2586
2587 // this also covers the case where we reach corresponding push
2588 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2589 return -1;
2590 }
2591
2592 // nothing interesting on this path
2593 return 0;
2594}
2595
2596static void find_reachable_exits(int i, int opcnt, int magic,
2597 int *exits, int *exit_count)
2598{
2599 struct parsed_op *po;
2600 int j;
2601
2602 for (; i < opcnt; i++)
2603 {
2604 po = &ops[i];
2605 if (po->cc_scratch == magic)
2606 return;
2607 po->cc_scratch = magic;
2608
2609 if (po->flags & OPF_TAIL) {
2610 ferr_assert(po, *exit_count < MAX_EXITS);
2611 exits[*exit_count] = i;
2612 (*exit_count)++;
2613 return;
2614 }
2615
2616 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2617 if (po->flags & OPF_RMD)
2618 continue;
2619
2620 if (po->btj != NULL) {
2621 for (j = 0; j < po->btj->count; j++) {
2622 check_i(po, po->btj->d[j].bt_i);
2623 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2624 exits, exit_count);
2625 }
2626 return;
2627 }
2628
2629 check_i(po, po->bt_i);
2630 if (po->flags & OPF_CJMP)
2631 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2632 else
2633 i = po->bt_i - 1;
2634 continue;
2635 }
2636 }
2637}
2638
2639// scan for 'reg' pop backwards starting from exits (all paths)
2640static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2641{
2642 static int exits[MAX_EXITS];
2643 static int exit_count;
2644 int j, ret;
2645
2646 if (!set_flags) {
2647 exit_count = 0;
2648 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2649 &exit_count);
2650 ferr_assert(&ops[i], exit_count > 0);
2651 }
2652
2653 for (j = 0; j < exit_count; j++) {
2654 ret = scan_for_rsave_pop_reg(exits[j], i + opcnt * 16 + set_flags,
2655 reg, set_flags);
2656 if (ret == -1)
2657 return -1;
2658 }
2659
2660 return 1;
2661}
2662
2663// scan for one or more pop of push <const>
2664static int scan_for_pop_const_r(int i, int opcnt, int magic,
2665 int push_i, int is_probe)
2666{
2667 struct parsed_op *po;
2668 struct label_ref *lr;
2669 int ret = 0;
2670 int j;
2671
2672 for (; i < opcnt; i++)
2673 {
2674 po = &ops[i];
2675 if (po->cc_scratch == magic)
2676 return ret; // already checked
2677 po->cc_scratch = magic;
2678
2679 if (po->flags & OPF_JMP) {
2680 if (po->flags & OPF_RMD)
2681 continue;
2682 if (po->op == OP_CALL)
2683 return -1;
2684
2685 if (po->btj != NULL) {
2686 for (j = 0; j < po->btj->count; j++) {
2687 check_i(po, po->btj->d[j].bt_i);
2688 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2689 push_i, is_probe);
2690 if (ret < 0)
2691 return ret;
2692 }
2693 return ret;
2694 }
2695
2696 check_i(po, po->bt_i);
2697 if (po->flags & OPF_CJMP) {
2698 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2699 is_probe);
2700 if (ret < 0)
2701 return ret;
2702 }
2703 else {
2704 i = po->bt_i - 1;
2705 }
2706 continue;
2707 }
2708
2709 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2710 return -1;
2711
2712 if (g_labels[i] != NULL) {
2713 // all refs must be visited
2714 lr = &g_label_refs[i];
2715 for (; lr != NULL; lr = lr->next) {
2716 check_i(po, lr->i);
2717 if (ops[lr->i].cc_scratch != magic)
2718 return -1;
2719 }
2720 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2721 return -1;
2722 }
2723
2724 if (po->op == OP_POP)
2725 {
2726 if (po->flags & (OPF_RMD|OPF_DONE))
2727 return -1;
2728
2729 if (!is_probe) {
2730 po->flags |= OPF_DONE;
2731 po->datap = &ops[push_i];
2732 }
2733 return 1;
2734 }
2735 }
2736
2737 return -1;
2738}
2739
2740static void scan_for_pop_const(int i, int opcnt, int magic)
2741{
2742 int ret;
2743
2744 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2745 if (ret == 1) {
2746 ops[i].flags |= OPF_RMD | OPF_DONE;
2747 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2748 }
2749}
2750
2751// check if all branch targets within a marked path are also marked
2752// note: the path checked must not be empty or end with a branch
2753static int check_path_branches(int opcnt, int magic)
2754{
2755 struct parsed_op *po;
2756 int i, j;
2757
2758 for (i = 0; i < opcnt; i++) {
2759 po = &ops[i];
2760 if (po->cc_scratch != magic)
2761 continue;
2762
2763 if (po->flags & OPF_JMP) {
2764 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2765 continue;
2766
2767 if (po->btj != NULL) {
2768 for (j = 0; j < po->btj->count; j++) {
2769 check_i(po, po->btj->d[j].bt_i);
2770 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2771 return 0;
2772 }
2773 }
2774
2775 check_i(po, po->bt_i);
2776 if (ops[po->bt_i].cc_scratch != magic)
2777 return 0;
2778 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2779 return 0;
2780 }
2781 }
2782
2783 return 1;
2784}
2785
2786// scan for multiple pushes for given pop
2787static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2788 int is_probe)
2789{
2790 int reg = ops[pop_i].operand[0].reg;
2791 struct parsed_op *po;
2792 struct label_ref *lr;
2793 int ret = 0;
2794
2795 ops[i].cc_scratch = magic;
2796
2797 while (1)
2798 {
2799 if (g_labels[i] != NULL) {
2800 lr = &g_label_refs[i];
2801 for (; lr != NULL; lr = lr->next) {
2802 check_i(&ops[i], lr->i);
2803 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2804 if (ret < 0)
2805 return ret;
2806 }
2807 if (i > 0 && LAST_OP(i - 1))
2808 return ret;
2809 }
2810
2811 i--;
2812 if (i < 0)
2813 break;
2814
2815 if (ops[i].cc_scratch == magic)
2816 return ret;
2817 ops[i].cc_scratch = magic;
2818
2819 po = &ops[i];
2820 if (po->op == OP_CALL)
2821 return -1;
2822 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2823 return -1;
2824
2825 if (po->op == OP_PUSH)
2826 {
2827 if (po->datap != NULL)
2828 return -1;
2829 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2830 // leave this case for reg save/restore handlers
2831 return -1;
2832
2833 if (!is_probe) {
2834 po->flags |= OPF_PPUSH | OPF_DONE;
2835 po->datap = &ops[pop_i];
2836 }
2837 return 1;
2838 }
2839 }
2840
2841 return -1;
2842}
2843
2844static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2845{
2846 int magic = i + opcnt * 14;
2847 int ret;
2848
2849 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2850 if (ret == 1) {
2851 ret = check_path_branches(opcnt, magic);
2852 if (ret == 1) {
2853 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2854 *regmask_pp |= 1 << ops[i].operand[0].reg;
2855 scan_pushes_for_pop_r(i, magic + 1, i, 0);
2856 }
2857 }
2858}
2859
2860static void scan_propagate_df(int i, int opcnt)
2861{
2862 struct parsed_op *po = &ops[i];
2863 int j;
2864
2865 for (; i < opcnt; i++) {
2866 po = &ops[i];
2867 if (po->flags & OPF_DF)
2868 return; // already resolved
2869 po->flags |= OPF_DF;
2870
2871 if (po->op == OP_CALL)
2872 ferr(po, "call with DF set?\n");
2873
2874 if (po->flags & OPF_JMP) {
2875 if (po->btj != NULL) {
2876 // jumptable
2877 for (j = 0; j < po->btj->count; j++) {
2878 check_i(po, po->btj->d[j].bt_i);
2879 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
2880 }
2881 return;
2882 }
2883
2884 if (po->flags & OPF_RMD)
2885 continue;
2886 check_i(po, po->bt_i);
2887 if (po->flags & OPF_CJMP)
2888 scan_propagate_df(po->bt_i, opcnt);
2889 else
2890 i = po->bt_i - 1;
2891 continue;
2892 }
2893
2894 if (po->flags & OPF_TAIL)
2895 break;
2896
2897 if (po->op == OP_CLD) {
2898 po->flags |= OPF_RMD | OPF_DONE;
2899 return;
2900 }
2901 }
2902
2903 ferr(po, "missing DF clear?\n");
2904}
2905
2906// is operand 'opr' referenced by parsed_op 'po'?
2907static int is_opr_referenced(const struct parsed_opr *opr,
2908 const struct parsed_op *po)
2909{
2910 int i, mask;
2911
2912 if (opr->type == OPT_REG) {
2913 mask = po->regmask_dst | po->regmask_src;
2914 if (po->op == OP_CALL)
2915 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
2916 if ((1 << opr->reg) & mask)
2917 return 1;
2918 else
2919 return 0;
2920 }
2921
2922 for (i = 0; i < po->operand_cnt; i++)
2923 if (IS(po->operand[0].name, opr->name))
2924 return 1;
2925
2926 return 0;
2927}
2928
2929// is operand 'opr' read by parsed_op 'po'?
2930static int is_opr_read(const struct parsed_opr *opr,
2931 const struct parsed_op *po)
2932{
2933 if (opr->type == OPT_REG) {
2934 if (po->regmask_src & (1 << opr->reg))
2935 return 1;
2936 else
2937 return 0;
2938 }
2939
2940 // yes I'm lazy
2941 return 0;
2942}
2943
2944// is operand 'opr' modified by parsed_op 'po'?
2945static int is_opr_modified(const struct parsed_opr *opr,
2946 const struct parsed_op *po)
2947{
2948 int mask;
2949
2950 if (opr->type == OPT_REG) {
2951 if (po->op == OP_CALL) {
2952 mask = po->regmask_dst;
2953 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
2954 if (mask & (1 << opr->reg))
2955 return 1;
2956 else
2957 return 0;
2958 }
2959
2960 if (po->regmask_dst & (1 << opr->reg))
2961 return 1;
2962 else
2963 return 0;
2964 }
2965
2966 return IS(po->operand[0].name, opr->name);
2967}
2968
2969// is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
2970static int is_any_opr_modified(const struct parsed_op *po_test,
2971 const struct parsed_op *po, int c_mode)
2972{
2973 int mask;
2974 int i;
2975
2976 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
2977 return 0;
2978
2979 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
2980 return 0;
2981
2982 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
2983 return 1;
2984
2985 // in reality, it can wreck any register, but in decompiled C
2986 // version it can only overwrite eax or edx:eax
2987 mask = (1 << xAX) | (1 << xDX);
2988 if (!c_mode)
2989 mask |= 1 << xCX;
2990
2991 if (po->op == OP_CALL
2992 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
2993 return 1;
2994
2995 for (i = 0; i < po_test->operand_cnt; i++)
2996 if (IS(po_test->operand[i].name, po->operand[0].name))
2997 return 1;
2998
2999 return 0;
3000}
3001
3002// scan for any po_test operand modification in range given
3003static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3004 int c_mode)
3005{
3006 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3007 return -1;
3008
3009 for (; i < opcnt; i++) {
3010 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3011 return i;
3012 }
3013
3014 return -1;
3015}
3016
3017// scan for po_test operand[0] modification in range given
3018static int scan_for_mod_opr0(struct parsed_op *po_test,
3019 int i, int opcnt)
3020{
3021 for (; i < opcnt; i++) {
3022 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3023 return i;
3024 }
3025
3026 return -1;
3027}
3028
3029static int scan_for_flag_set(int i, int magic, int *branched,
3030 int *setters, int *setter_cnt)
3031{
3032 struct label_ref *lr;
3033 int ret;
3034
3035 while (i >= 0) {
3036 if (ops[i].cc_scratch == magic) {
3037 // is this a problem?
3038 //ferr(&ops[i], "%s looped\n", __func__);
3039 return 0;
3040 }
3041 ops[i].cc_scratch = magic;
3042
3043 if (g_labels[i] != NULL) {
3044 *branched = 1;
3045
3046 lr = &g_label_refs[i];
3047 for (; lr->next; lr = lr->next) {
3048 check_i(&ops[i], lr->i);
3049 ret = scan_for_flag_set(lr->i, magic,
3050 branched, setters, setter_cnt);
3051 if (ret < 0)
3052 return ret;
3053 }
3054
3055 check_i(&ops[i], lr->i);
3056 if (i > 0 && LAST_OP(i - 1)) {
3057 i = lr->i;
3058 continue;
3059 }
3060 ret = scan_for_flag_set(lr->i, magic,
3061 branched, setters, setter_cnt);
3062 if (ret < 0)
3063 return ret;
3064 }
3065 i--;
3066
3067 if (ops[i].flags & OPF_FLAGS) {
3068 setters[*setter_cnt] = i;
3069 (*setter_cnt)++;
3070 return 0;
3071 }
3072
3073 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3074 return -1;
3075 }
3076
3077 return -1;
3078}
3079
3080// scan back for cdq, if anything modifies edx, fail
3081static int scan_for_cdq_edx(int i)
3082{
3083 while (i >= 0) {
3084 if (g_labels[i] != NULL) {
3085 if (g_label_refs[i].next != NULL)
3086 return -1;
3087 if (i > 0 && LAST_OP(i - 1)) {
3088 i = g_label_refs[i].i;
3089 continue;
3090 }
3091 return -1;
3092 }
3093 i--;
3094
3095 if (ops[i].op == OP_CDQ)
3096 return i;
3097
3098 if (ops[i].regmask_dst & (1 << xDX))
3099 return -1;
3100 }
3101
3102 return -1;
3103}
3104
3105static int scan_for_reg_clear(int i, int reg)
3106{
3107 while (i >= 0) {
3108 if (g_labels[i] != NULL) {
3109 if (g_label_refs[i].next != NULL)
3110 return -1;
3111 if (i > 0 && LAST_OP(i - 1)) {
3112 i = g_label_refs[i].i;
3113 continue;
3114 }
3115 return -1;
3116 }
3117 i--;
3118
3119 if (ops[i].op == OP_XOR
3120 && ops[i].operand[0].lmod == OPLM_DWORD
3121 && ops[i].operand[0].reg == ops[i].operand[1].reg
3122 && ops[i].operand[0].reg == reg)
3123 return i;
3124
3125 if (ops[i].regmask_dst & (1 << reg))
3126 return -1;
3127 }
3128
3129 return -1;
3130}
3131
3132static void patch_esp_adjust(struct parsed_op *po, int adj)
3133{
3134 ferr_assert(po, po->op == OP_ADD);
3135 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3136 ferr_assert(po, po->operand[1].type == OPT_CONST);
3137
3138 // this is a bit of a hack, but deals with use of
3139 // single adj for multiple calls
3140 po->operand[1].val -= adj;
3141 po->flags |= OPF_RMD;
3142 if (po->operand[1].val == 0)
3143 po->flags |= OPF_DONE;
3144 ferr_assert(po, (int)po->operand[1].val >= 0);
3145}
3146
3147// scan for positive, constant esp adjust
3148// multipath case is preliminary
3149static int scan_for_esp_adjust(int i, int opcnt,
3150 int adj_expect, int *adj, int *is_multipath, int do_update)
3151{
3152 int adj_expect_unknown = 0;
3153 struct parsed_op *po;
3154 int first_pop = -1;
3155 int adj_best = 0;
3156
3157 *adj = *is_multipath = 0;
3158 if (adj_expect < 0) {
3159 adj_expect_unknown = 1;
3160 adj_expect = 32 * 4; // enough?
3161 }
3162
3163 for (; i < opcnt && *adj < adj_expect; i++) {
3164 if (g_labels[i] != NULL)
3165 *is_multipath = 1;
3166
3167 po = &ops[i];
3168 if (po->flags & OPF_DONE)
3169 continue;
3170
3171 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3172 if (po->operand[1].type != OPT_CONST)
3173 ferr(&ops[i], "non-const esp adjust?\n");
3174 *adj += po->operand[1].val;
3175 if (*adj & 3)
3176 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3177 if (do_update) {
3178 if (!*is_multipath)
3179 patch_esp_adjust(po, adj_expect);
3180 else
3181 po->flags |= OPF_RMD;
3182 }
3183 return i;
3184 }
3185 else if (po->op == OP_PUSH) {
3186 //if (first_pop == -1)
3187 // first_pop = -2; // none
3188 *adj -= lmod_bytes(po, po->operand[0].lmod);
3189 }
3190 else if (po->op == OP_POP) {
3191 if (!(po->flags & OPF_DONE)) {
3192 // seems like msvc only uses 'pop ecx' for stack realignment..
3193 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3194 break;
3195 if (first_pop == -1 && *adj >= 0)
3196 first_pop = i;
3197 }
3198 if (do_update && *adj >= 0) {
3199 po->flags |= OPF_RMD;
3200 if (!*is_multipath)
3201 po->flags |= OPF_DONE | OPF_NOREGS;
3202 }
3203
3204 *adj += lmod_bytes(po, po->operand[0].lmod);
3205 if (*adj > adj_best)
3206 adj_best = *adj;
3207 }
3208 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3209 if (po->op == OP_JMP && po->btj == NULL) {
3210 if (po->bt_i <= i)
3211 break;
3212 i = po->bt_i - 1;
3213 continue;
3214 }
3215 if (po->op != OP_CALL)
3216 break;
3217 if (po->operand[0].type != OPT_LABEL)
3218 break;
3219 if (po->pp != NULL && po->pp->is_stdcall)
3220 break;
3221 if (adj_expect_unknown && first_pop >= 0)
3222 break;
3223 // assume it's another cdecl call
3224 }
3225 }
3226
3227 if (first_pop >= 0) {
3228 // probably only 'pop ecx' was used
3229 *adj = adj_best;
3230 return first_pop;
3231 }
3232
3233 return -1;
3234}
3235
3236static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3237{
3238 struct parsed_op *po;
3239 int j;
3240
3241 if (i < 0)
3242 ferr(ops, "%s: followed bad branch?\n", __func__);
3243
3244 for (; i < opcnt; i++) {
3245 po = &ops[i];
3246 if (po->cc_scratch == magic)
3247 return;
3248 po->cc_scratch = magic;
3249 po->flags |= flags;
3250
3251 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3252 if (po->btj != NULL) {
3253 // jumptable
3254 for (j = 0; j < po->btj->count; j++)
3255 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3256 return;
3257 }
3258
3259 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3260 if (!(po->flags & OPF_CJMP))
3261 return;
3262 }
3263 if (po->flags & OPF_TAIL)
3264 return;
3265 }
3266}
3267
3268static const struct parsed_proto *try_recover_pp(
3269 struct parsed_op *po, const struct parsed_opr *opr, int *search_instead)
3270{
3271 const struct parsed_proto *pp = NULL;
3272 char buf[256];
3273 char *p;
3274
3275 // maybe an arg of g_func?
3276 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3277 {
3278 char ofs_reg[16] = { 0, };
3279 int arg, arg_s, arg_i;
3280 int stack_ra = 0;
3281 int offset = 0;
3282
3283 if (g_header_mode)
3284 return NULL;
3285
3286 parse_stack_access(po, opr->name, ofs_reg,
3287 &offset, &stack_ra, NULL, 0);
3288 if (ofs_reg[0] != 0)
3289 ferr(po, "offset reg on arg access?\n");
3290 if (offset <= stack_ra) {
3291 // search who set the stack var instead
3292 if (search_instead != NULL)
3293 *search_instead = 1;
3294 return NULL;
3295 }
3296
3297 arg_i = (offset - stack_ra - 4) / 4;
3298 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3299 if (g_func_pp->arg[arg].reg != NULL)
3300 continue;
3301 if (arg_s == arg_i)
3302 break;
3303 arg_s++;
3304 }
3305 if (arg == g_func_pp->argc)
3306 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3307
3308 pp = g_func_pp->arg[arg].fptr;
3309 if (pp == NULL)
3310 ferr(po, "icall sa: arg%d is not a fptr?\n", arg + 1);
3311 check_func_pp(po, pp, "icall arg");
3312 }
3313 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3314 // label[index]
3315 p = strchr(opr->name + 1, '[');
3316 memcpy(buf, opr->name, p - opr->name);
3317 buf[p - opr->name] = 0;
3318 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3319 }
3320 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3321 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3322 if (pp == NULL) {
3323 if (!g_header_mode)
3324 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3325 }
3326 else
3327 check_func_pp(po, pp, "reg-fptr ref");
3328 }
3329
3330 return pp;
3331}
3332
3333static void scan_for_call_type(int i, const struct parsed_opr *opr,
3334 int magic, const struct parsed_proto **pp_found, int *pp_i,
3335 int *multi)
3336{
3337 const struct parsed_proto *pp = NULL;
3338 struct parsed_op *po;
3339 struct label_ref *lr;
3340
3341 ops[i].cc_scratch = magic;
3342
3343 while (1) {
3344 if (g_labels[i] != NULL) {
3345 lr = &g_label_refs[i];
3346 for (; lr != NULL; lr = lr->next) {
3347 check_i(&ops[i], lr->i);
3348 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3349 }
3350 if (i > 0 && LAST_OP(i - 1))
3351 return;
3352 }
3353
3354 i--;
3355 if (i < 0)
3356 break;
3357
3358 if (ops[i].cc_scratch == magic)
3359 return;
3360 ops[i].cc_scratch = magic;
3361
3362 if (!(ops[i].flags & OPF_DATA))
3363 continue;
3364 if (!is_opr_modified(opr, &ops[i]))
3365 continue;
3366 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3367 // most probably trashed by some processing
3368 *pp_found = NULL;
3369 return;
3370 }
3371
3372 opr = &ops[i].operand[1];
3373 if (opr->type != OPT_REG)
3374 break;
3375 }
3376
3377 po = (i >= 0) ? &ops[i] : ops;
3378
3379 if (i < 0) {
3380 // reached the top - can only be an arg-reg
3381 if (opr->type != OPT_REG || g_func_pp == NULL)
3382 return;
3383
3384 for (i = 0; i < g_func_pp->argc; i++) {
3385 if (g_func_pp->arg[i].reg == NULL)
3386 continue;
3387 if (IS(opr->name, g_func_pp->arg[i].reg))
3388 break;
3389 }
3390 if (i == g_func_pp->argc)
3391 return;
3392 pp = g_func_pp->arg[i].fptr;
3393 if (pp == NULL)
3394 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3395 i + 1, g_func_pp->arg[i].reg);
3396 check_func_pp(po, pp, "icall reg-arg");
3397 }
3398 else
3399 pp = try_recover_pp(po, opr, NULL);
3400
3401 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3402 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3403 || (*pp_found)->is_stdcall != pp->is_stdcall
3404 || (*pp_found)->is_fptr != pp->is_fptr
3405 || (*pp_found)->argc != pp->argc
3406 || (*pp_found)->argc_reg != pp->argc_reg
3407 || (*pp_found)->argc_stack != pp->argc_stack)
3408 {
3409 ferr(po, "icall: parsed_proto mismatch\n");
3410 }
3411 *multi = 1;
3412 }
3413 if (pp != NULL) {
3414 *pp_found = pp;
3415 *pp_i = po - ops;
3416 }
3417}
3418
3419static void add_label_ref(struct label_ref *lr, int op_i)
3420{
3421 struct label_ref *lr_new;
3422
3423 if (lr->i == -1) {
3424 lr->i = op_i;
3425 return;
3426 }
3427
3428 lr_new = calloc(1, sizeof(*lr_new));
3429 lr_new->i = op_i;
3430 lr_new->next = lr->next;
3431 lr->next = lr_new;
3432}
3433
3434static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3435{
3436 struct parsed_op *po = &ops[i];
3437 struct parsed_data *pd;
3438 char label[NAMELEN], *p;
3439 int len, j, l;
3440
3441 p = strchr(po->operand[0].name, '[');
3442 if (p == NULL)
3443 return NULL;
3444
3445 len = p - po->operand[0].name;
3446 strncpy(label, po->operand[0].name, len);
3447 label[len] = 0;
3448
3449 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3450 if (IS(g_func_pd[j].label, label)) {
3451 pd = &g_func_pd[j];
3452 break;
3453 }
3454 }
3455 if (pd == NULL)
3456 //ferr(po, "label '%s' not parsed?\n", label);
3457 return NULL;
3458
3459 if (pd->type != OPT_OFFSET)
3460 ferr(po, "label '%s' with non-offset data?\n", label);
3461
3462 // find all labels, link
3463 for (j = 0; j < pd->count; j++) {
3464 for (l = 0; l < opcnt; l++) {
3465 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3466 add_label_ref(&g_label_refs[l], i);
3467 pd->d[j].bt_i = l;
3468 break;
3469 }
3470 }
3471 }
3472
3473 return pd;
3474}
3475
3476static void clear_labels(int count)
3477{
3478 int i;
3479
3480 for (i = 0; i < count; i++) {
3481 if (g_labels[i] != NULL) {
3482 free(g_labels[i]);
3483 g_labels[i] = NULL;
3484 }
3485 }
3486}
3487
3488static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3489{
3490 int regmask = 0;
3491 int i, reg;
3492
3493 for (i = 0; i < pp->argc; i++) {
3494 if (pp->arg[i].reg != NULL) {
3495 reg = char_array_i(regs_r32,
3496 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3497 if (reg < 0)
3498 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3499 pp->arg[i].reg, pp->name);
3500 regmask |= 1 << reg;
3501 }
3502 }
3503
3504 return regmask;
3505}
3506
3507static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3508{
3509 int regmask = 0;
3510 int i, reg;
3511
3512 if (pp->has_retreg) {
3513 for (i = 0; i < pp->argc; i++) {
3514 if (pp->arg[i].type.is_retreg) {
3515 reg = char_array_i(regs_r32,
3516 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3517 ferr_assert(ops, reg >= 0);
3518 regmask |= 1 << reg;
3519 }
3520 }
3521 }
3522
3523 if (strstr(pp->ret_type.name, "int64"))
3524 return regmask | (1 << xAX) | (1 << xDX);
3525 if (IS(pp->ret_type.name, "float")
3526 || IS(pp->ret_type.name, "double"))
3527 {
3528 return regmask | mxST0;
3529 }
3530 if (strcasecmp(pp->ret_type.name, "void") == 0)
3531 return regmask;
3532
3533 return regmask | mxAX;
3534}
3535
3536static void resolve_branches_parse_calls(int opcnt)
3537{
3538 static const struct {
3539 const char *name;
3540 enum op_op op;
3541 unsigned int flags;
3542 unsigned int regmask_src;
3543 unsigned int regmask_dst;
3544 } pseudo_ops[] = {
3545 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3546 };
3547 const struct parsed_proto *pp_c;
3548 struct parsed_proto *pp;
3549 struct parsed_data *pd;
3550 struct parsed_op *po;
3551 const char *tmpname;
3552 int i, l;
3553 int ret;
3554
3555 for (i = 0; i < opcnt; i++)
3556 {
3557 po = &ops[i];
3558 po->bt_i = -1;
3559 po->btj = NULL;
3560
3561 if (po->datap != NULL) {
3562 pp = calloc(1, sizeof(*pp));
3563 my_assert_not(pp, NULL);
3564
3565 ret = parse_protostr(po->datap, pp);
3566 if (ret < 0)
3567 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3568 free(po->datap);
3569 po->datap = NULL;
3570 po->pp = pp;
3571 }
3572
3573 if (po->op == OP_CALL) {
3574 pp = NULL;
3575
3576 if (po->pp != NULL)
3577 pp = po->pp;
3578 else if (po->operand[0].type == OPT_LABEL)
3579 {
3580 tmpname = opr_name(po, 0);
3581 if (IS_START(tmpname, "loc_"))
3582 ferr(po, "call to loc_*\n");
3583
3584 // convert some calls to pseudo-ops
3585 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3586 if (!IS(tmpname, pseudo_ops[l].name))
3587 continue;
3588
3589 po->op = pseudo_ops[l].op;
3590 po->operand_cnt = 0;
3591 po->regmask_src = pseudo_ops[l].regmask_src;
3592 po->regmask_dst = pseudo_ops[l].regmask_dst;
3593 po->flags = pseudo_ops[l].flags;
3594 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3595 break;
3596 }
3597 if (l < ARRAY_SIZE(pseudo_ops))
3598 continue;
3599
3600 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3601 if (!g_header_mode && pp_c == NULL)
3602 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3603
3604 if (pp_c != NULL) {
3605 pp = proto_clone(pp_c);
3606 my_assert_not(pp, NULL);
3607 }
3608 }
3609
3610 if (pp != NULL) {
3611 if (pp->is_fptr)
3612 check_func_pp(po, pp, "fptr var call");
3613 if (pp->is_noreturn)
3614 po->flags |= OPF_TAIL;
3615 }
3616 po->pp = pp;
3617 continue;
3618 }
3619
3620 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3621 continue;
3622
3623 if (po->operand[0].type == OPT_REGMEM) {
3624 pd = try_resolve_jumptab(i, opcnt);
3625 if (pd == NULL)
3626 goto tailcall;
3627
3628 po->btj = pd;
3629 continue;
3630 }
3631
3632 for (l = 0; l < opcnt; l++) {
3633 if (g_labels[l] != NULL
3634 && IS(po->operand[0].name, g_labels[l]))
3635 {
3636 if (l == i + 1 && po->op == OP_JMP) {
3637 // yet another alignment type..
3638 po->flags |= OPF_RMD|OPF_DONE;
3639 break;
3640 }
3641 add_label_ref(&g_label_refs[l], i);
3642 po->bt_i = l;
3643 break;
3644 }
3645 }
3646
3647 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3648 continue;
3649
3650 if (po->operand[0].type == OPT_LABEL)
3651 // assume tail call
3652 goto tailcall;
3653
3654 ferr(po, "unhandled branch\n");
3655
3656tailcall:
3657 po->op = OP_CALL;
3658 po->flags |= OPF_TAIL;
3659 if (i > 0 && ops[i - 1].op == OP_POP)
3660 po->flags |= OPF_ATAIL;
3661 i--; // reprocess
3662 }
3663}
3664
3665static void scan_prologue_epilogue(int opcnt)
3666{
3667 int ecx_push = 0, esp_sub = 0;
3668 int found;
3669 int i, j, l;
3670
3671 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3672 && ops[1].op == OP_MOV
3673 && IS(opr_name(&ops[1], 0), "ebp")
3674 && IS(opr_name(&ops[1], 1), "esp"))
3675 {
3676 g_bp_frame = 1;
3677 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3678 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3679 i = 2;
3680
3681 if (ops[2].op == OP_SUB && IS(opr_name(&ops[2], 0), "esp")) {
3682 g_stack_fsz = opr_const(&ops[2], 1);
3683 ops[2].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3684 i++;
3685 }
3686 else {
3687 // another way msvc builds stack frame..
3688 i = 2;
3689 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3690 g_stack_fsz += 4;
3691 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3692 ecx_push++;
3693 i++;
3694 }
3695 // and another way..
3696 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3697 && ops[i].operand[1].type == OPT_CONST
3698 && ops[i + 1].op == OP_CALL
3699 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3700 {
3701 g_stack_fsz += ops[i].operand[1].val;
3702 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3703 i++;
3704 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3705 i++;
3706 }
3707 }
3708
3709 found = 0;
3710 do {
3711 for (; i < opcnt; i++)
3712 if (ops[i].flags & OPF_TAIL)
3713 break;
3714 j = i - 1;
3715 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3716 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3717 break;
3718 i--;
3719 j--;
3720 }
3721
3722 if ((ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3723 || ops[j].op == OP_LEAVE)
3724 {
3725 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3726 }
3727 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3728 && ops[i].pp->is_noreturn)
3729 {
3730 // on noreturn, msvc sometimes cleans stack, sometimes not
3731 i++;
3732 found = 1;
3733 continue;
3734 }
3735 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3736 ferr(&ops[j], "'pop ebp' expected\n");
3737
3738 if (g_stack_fsz != 0) {
3739 if (ops[j].op == OP_LEAVE)
3740 j--;
3741 else if (ops[j].op == OP_POP
3742 && ops[j - 1].op == OP_MOV
3743 && IS(opr_name(&ops[j - 1], 0), "esp")
3744 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3745 {
3746 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3747 j -= 2;
3748 }
3749 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3750 {
3751 ferr(&ops[j], "esp restore expected\n");
3752 }
3753
3754 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3755 && IS(opr_name(&ops[j], 0), "ecx"))
3756 {
3757 ferr(&ops[j], "unexpected ecx pop\n");
3758 }
3759 }
3760
3761 found = 1;
3762 i++;
3763 } while (i < opcnt);
3764
3765 if (!found)
3766 ferr(ops, "missing ebp epilogue\n");
3767 return;
3768 }
3769
3770 // non-bp frame
3771 i = 0;
3772 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3773 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3774 g_stack_fsz += 4;
3775 ecx_push++;
3776 i++;
3777 }
3778
3779 for (; i < opcnt; i++) {
3780 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3781 break;
3782 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3783 && ops[i].operand[1].type == OPT_CONST)
3784 {
3785 g_stack_fsz = ops[i].operand[1].val;
3786 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3787 esp_sub = 1;
3788 break;
3789 }
3790 }
3791
3792 if (ecx_push && !esp_sub) {
3793 // could actually be args for a call..
3794 for (; i < opcnt; i++)
3795 if (ops[i].op != OP_PUSH)
3796 break;
3797
3798 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3799 const struct parsed_proto *pp;
3800 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3801 j = pp ? pp->argc_stack : 0;
3802 while (i > 0 && j > 0) {
3803 i--;
3804 if (ops[i].op == OP_PUSH) {
3805 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
3806 j--;
3807 }
3808 }
3809 if (j != 0)
3810 ferr(&ops[i], "unhandled prologue\n");
3811
3812 // recheck
3813 i = g_stack_fsz = ecx_push = 0;
3814 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3815 if (!(ops[i].flags & OPF_RMD))
3816 break;
3817 g_stack_fsz += 4;
3818 ecx_push++;
3819 i++;
3820 }
3821 }
3822 }
3823
3824 found = 0;
3825 if (ecx_push || esp_sub)
3826 {
3827 g_sp_frame = 1;
3828
3829 do {
3830 for (; i < opcnt; i++)
3831 if (ops[i].flags & OPF_TAIL)
3832 break;
3833
3834 j = i - 1;
3835 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3836 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3837 break;
3838 i--;
3839 j--;
3840 }
3841
3842 if (ecx_push > 0) {
3843 for (l = 0; l < ecx_push; l++) {
3844 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
3845 /* pop ecx */;
3846 else if (ops[j].op == OP_ADD
3847 && IS(opr_name(&ops[j], 0), "esp")
3848 && ops[j].operand[1].type == OPT_CONST)
3849 {
3850 /* add esp, N */
3851 l += ops[j].operand[1].val / 4 - 1;
3852 }
3853 else
3854 ferr(&ops[j], "'pop ecx' expected\n");
3855
3856 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3857 j--;
3858 }
3859 if (l != ecx_push)
3860 ferr(&ops[j], "epilogue scan failed\n");
3861
3862 found = 1;
3863 }
3864
3865 if (esp_sub) {
3866 if (ops[j].op != OP_ADD
3867 || !IS(opr_name(&ops[j], 0), "esp")
3868 || ops[j].operand[1].type != OPT_CONST
3869 || ops[j].operand[1].val != g_stack_fsz)
3870 ferr(&ops[j], "'add esp' expected\n");
3871
3872 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3873 ops[j].operand[1].val = 0; // hack for stack arg scanner
3874 found = 1;
3875 }
3876
3877 i++;
3878 } while (i < opcnt);
3879
3880 if (!found)
3881 ferr(ops, "missing esp epilogue\n");
3882 }
3883}
3884
3885// find an instruction that changed opr before i op
3886// *op_i must be set to -1 by the caller
3887// *is_caller is set to 1 if one source is determined to be g_func arg
3888// returns 1 if found, *op_i is then set to origin
3889// returns -1 if multiple origins are found
3890static int resolve_origin(int i, const struct parsed_opr *opr,
3891 int magic, int *op_i, int *is_caller)
3892{
3893 struct label_ref *lr;
3894 int ret = 0;
3895
3896 if (ops[i].cc_scratch == magic)
3897 return 0;
3898 ops[i].cc_scratch = magic;
3899
3900 while (1) {
3901 if (g_labels[i] != NULL) {
3902 lr = &g_label_refs[i];
3903 for (; lr != NULL; lr = lr->next) {
3904 check_i(&ops[i], lr->i);
3905 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
3906 }
3907 if (i > 0 && LAST_OP(i - 1))
3908 return ret;
3909 }
3910
3911 i--;
3912 if (i < 0) {
3913 if (is_caller != NULL)
3914 *is_caller = 1;
3915 return -1;
3916 }
3917
3918 if (ops[i].cc_scratch == magic)
3919 return ret;
3920 ops[i].cc_scratch = magic;
3921
3922 if (!(ops[i].flags & OPF_DATA))
3923 continue;
3924 if (!is_opr_modified(opr, &ops[i]))
3925 continue;
3926
3927 if (*op_i >= 0) {
3928 if (*op_i == i)
3929 return ret | 1;
3930
3931 // XXX: could check if the other op does the same
3932 return -1;
3933 }
3934
3935 *op_i = i;
3936 return ret | 1;
3937 }
3938}
3939
3940// find an instruction that previously referenced opr
3941// if multiple results are found - fail
3942// *op_i must be set to -1 by the caller
3943// returns 1 if found, *op_i is then set to referencer insn
3944static int resolve_last_ref(int i, const struct parsed_opr *opr,
3945 int magic, int *op_i)
3946{
3947 struct label_ref *lr;
3948 int ret = 0;
3949
3950 if (ops[i].cc_scratch == magic)
3951 return 0;
3952 ops[i].cc_scratch = magic;
3953
3954 while (1) {
3955 if (g_labels[i] != NULL) {
3956 lr = &g_label_refs[i];
3957 for (; lr != NULL; lr = lr->next) {
3958 check_i(&ops[i], lr->i);
3959 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
3960 }
3961 if (i > 0 && LAST_OP(i - 1))
3962 return ret;
3963 }
3964
3965 i--;
3966 if (i < 0)
3967 return -1;
3968
3969 if (ops[i].cc_scratch == magic)
3970 return 0;
3971 ops[i].cc_scratch = magic;
3972
3973 if (!is_opr_referenced(opr, &ops[i]))
3974 continue;
3975
3976 if (*op_i >= 0)
3977 return -1;
3978
3979 *op_i = i;
3980 return 1;
3981 }
3982}
3983
3984// find next instruction that reads opr
3985// *op_i must be set to -1 by the caller
3986// on return, *op_i is set to first referencer insn
3987// returns 1 if exactly 1 referencer is found
3988static int find_next_read(int i, int opcnt,
3989 const struct parsed_opr *opr, int magic, int *op_i)
3990{
3991 struct parsed_op *po;
3992 int j, ret = 0;
3993
3994 for (; i < opcnt; i++)
3995 {
3996 if (ops[i].cc_scratch == magic)
3997 return ret;
3998 ops[i].cc_scratch = magic;
3999
4000 po = &ops[i];
4001 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4002 if (po->btj != NULL) {
4003 // jumptable
4004 for (j = 0; j < po->btj->count; j++) {
4005 check_i(po, po->btj->d[j].bt_i);
4006 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4007 magic, op_i);
4008 }
4009 return ret;
4010 }
4011
4012 if (po->flags & OPF_RMD)
4013 continue;
4014 check_i(po, po->bt_i);
4015 if (po->flags & OPF_CJMP) {
4016 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4017 if (ret < 0)
4018 return ret;
4019 }
4020 else
4021 i = po->bt_i - 1;
4022 continue;
4023 }
4024
4025 if (!is_opr_read(opr, po)) {
4026 if (is_opr_modified(opr, po)
4027 && (po->op == OP_CALL
4028 || ((po->flags & OPF_DATA)
4029 && po->operand[0].lmod == OPLM_DWORD)))
4030 {
4031 // it's overwritten
4032 return ret;
4033 }
4034 if (po->flags & OPF_TAIL)
4035 return ret;
4036 continue;
4037 }
4038
4039 if (*op_i >= 0)
4040 return -1;
4041
4042 *op_i = i;
4043 return 1;
4044 }
4045
4046 return 0;
4047}
4048
4049static int try_resolve_const(int i, const struct parsed_opr *opr,
4050 int magic, unsigned int *val)
4051{
4052 int s_i = -1;
4053 int ret;
4054
4055 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4056 if (ret == 1) {
4057 i = s_i;
4058 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4059 return -1;
4060
4061 *val = ops[i].operand[1].val;
4062 return 1;
4063 }
4064
4065 return -1;
4066}
4067
4068static const struct parsed_proto *resolve_icall(int i, int opcnt,
4069 int *pp_i, int *multi_src)
4070{
4071 const struct parsed_proto *pp = NULL;
4072 int search_advice = 0;
4073 int offset = -1;
4074 char name[256];
4075 char s_reg[4];
4076 int reg, len;
4077 int ret;
4078
4079 *multi_src = 0;
4080 *pp_i = -1;
4081
4082 switch (ops[i].operand[0].type) {
4083 case OPT_REGMEM:
4084 // try to resolve struct member calls
4085 ret = sscanf(ops[i].operand[0].name, "%3s+%x%n",
4086 s_reg, &offset, &len);
4087 if (ret == 2 && len == strlen(ops[i].operand[0].name))
4088 {
4089 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4090 if (reg >= 0) {
4091 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4092 int j = -1;
4093 ret = resolve_origin(i, &opr, i + opcnt * 19, &j, NULL);
4094 if (ret != 1)
4095 break;
4096 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4097 && ops[j].operand[0].lmod == OPLM_DWORD
4098 && ops[j].pp == NULL) // no hint
4099 {
4100 // allow one simple dereference (directx)
4101 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4102 ops[j].operand[1].name);
4103 if (reg < 0)
4104 break;
4105 struct parsed_opr opr2 = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4106 int k = -1;
4107 ret = resolve_origin(j, &opr2, j + opcnt * 19, &k, NULL);
4108 if (ret != 1)
4109 break;
4110 j = k;
4111 }
4112 if (ops[j].op != OP_MOV)
4113 break;
4114 if (ops[j].operand[0].lmod != OPLM_DWORD)
4115 break;
4116 if (ops[j].pp != NULL) {
4117 // type hint in asm
4118 pp = ops[j].pp;
4119 }
4120 else if (ops[j].operand[1].type == OPT_REGMEM) {
4121 // allow 'hello[ecx]' - assume array of same type items
4122 ret = sscanf(ops[j].operand[1].name, "%[^[][e%2s]",
4123 name, s_reg);
4124 if (ret != 2)
4125 break;
4126 pp = proto_parse(g_fhdr, name, g_quiet_pp);
4127 }
4128 else if (ops[j].operand[1].type == OPT_LABEL)
4129 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4130 else
4131 break;
4132 if (pp == NULL)
4133 break;
4134 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4135 pp = NULL;
4136 break;
4137 }
4138 pp = proto_lookup_struct(g_fhdr, pp->type.name, offset);
4139 }
4140 break;
4141 }
4142 // fallthrough
4143 case OPT_LABEL:
4144 case OPT_OFFSET:
4145 pp = try_recover_pp(&ops[i], &ops[i].operand[0], &search_advice);
4146 if (!search_advice)
4147 break;
4148 // fallthrough
4149 default:
4150 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4151 pp_i, multi_src);
4152 break;
4153 }
4154
4155 return pp;
4156}
4157
4158static struct parsed_proto *process_call_early(int i, int opcnt,
4159 int *adj_i)
4160{
4161 struct parsed_op *po = &ops[i];
4162 struct parsed_proto *pp;
4163 int multipath = 0;
4164 int adj = 0;
4165 int j, ret;
4166
4167 pp = po->pp;
4168 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4169 // leave for later
4170 return NULL;
4171
4172 // look for and make use of esp adjust
4173 *adj_i = ret = -1;
4174 if (!pp->is_stdcall && pp->argc_stack > 0)
4175 ret = scan_for_esp_adjust(i + 1, opcnt,
4176 pp->argc_stack * 4, &adj, &multipath, 0);
4177 if (ret >= 0) {
4178 if (pp->argc_stack > adj / 4)
4179 return NULL;
4180 if (multipath)
4181 return NULL;
4182 if (ops[ret].op == OP_POP) {
4183 for (j = 1; j < adj / 4; j++) {
4184 if (ops[ret + j].op != OP_POP
4185 || ops[ret + j].operand[0].reg != xCX)
4186 {
4187 return NULL;
4188 }
4189 }
4190 }
4191 }
4192
4193 *adj_i = ret;
4194 return pp;
4195}
4196
4197static struct parsed_proto *process_call(int i, int opcnt)
4198{
4199 struct parsed_op *po = &ops[i];
4200 const struct parsed_proto *pp_c;
4201 struct parsed_proto *pp;
4202 const char *tmpname;
4203 int call_i = -1, ref_i = -1;
4204 int adj = 0, multipath = 0;
4205 int ret, arg;
4206
4207 tmpname = opr_name(po, 0);
4208 pp = po->pp;
4209 if (pp == NULL)
4210 {
4211 // indirect call
4212 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4213 if (pp_c != NULL) {
4214 if (!pp_c->is_func && !pp_c->is_fptr)
4215 ferr(po, "call to non-func: %s\n", pp_c->name);
4216 pp = proto_clone(pp_c);
4217 my_assert_not(pp, NULL);
4218 if (multipath)
4219 // not resolved just to single func
4220 pp->is_fptr = 1;
4221
4222 switch (po->operand[0].type) {
4223 case OPT_REG:
4224 // we resolved this call and no longer need the register
4225 po->regmask_src &= ~(1 << po->operand[0].reg);
4226
4227 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4228 && ops[call_i].operand[1].type == OPT_LABEL)
4229 {
4230 // no other source users?
4231 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4232 &ref_i);
4233 if (ret == 1 && call_i == ref_i) {
4234 // and nothing uses it after us?
4235 ref_i = -1;
4236 find_next_read(i + 1, opcnt, &po->operand[0],
4237 i + opcnt * 11, &ref_i);
4238 if (ref_i == -1)
4239 // then also don't need the source mov
4240 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4241 }
4242 }
4243 break;
4244 case OPT_REGMEM:
4245 pp->is_fptr = 1;
4246 break;
4247 default:
4248 break;
4249 }
4250 }
4251 if (pp == NULL) {
4252 pp = calloc(1, sizeof(*pp));
4253 my_assert_not(pp, NULL);
4254
4255 pp->is_fptr = 1;
4256 ret = scan_for_esp_adjust(i + 1, opcnt,
4257 -1, &adj, &multipath, 0);
4258 if (ret < 0 || adj < 0) {
4259 if (!g_allow_regfunc)
4260 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4261 pp->is_unresolved = 1;
4262 adj = 0;
4263 }
4264 adj /= 4;
4265 if (adj > ARRAY_SIZE(pp->arg))
4266 ferr(po, "esp adjust too large: %d\n", adj);
4267 pp->ret_type.name = strdup("int");
4268 pp->argc = pp->argc_stack = adj;
4269 for (arg = 0; arg < pp->argc; arg++)
4270 pp->arg[arg].type.name = strdup("int");
4271 }
4272 po->pp = pp;
4273 }
4274
4275 // look for and make use of esp adjust
4276 multipath = 0;
4277 ret = -1;
4278 if (!pp->is_stdcall && pp->argc_stack > 0) {
4279 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4280 ret = scan_for_esp_adjust(i + 1, opcnt,
4281 adj_expect, &adj, &multipath, 0);
4282 }
4283 if (ret >= 0) {
4284 if (pp->is_vararg) {
4285 if (adj / 4 < pp->argc_stack) {
4286 fnote(po, "(this call)\n");
4287 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4288 adj, pp->argc_stack * 4);
4289 }
4290 // modify pp to make it have varargs as normal args
4291 arg = pp->argc;
4292 pp->argc += adj / 4 - pp->argc_stack;
4293 for (; arg < pp->argc; arg++) {
4294 pp->arg[arg].type.name = strdup("int");
4295 pp->argc_stack++;
4296 }
4297 if (pp->argc > ARRAY_SIZE(pp->arg))
4298 ferr(po, "too many args for '%s'\n", tmpname);
4299 }
4300 if (pp->argc_stack > adj / 4) {
4301 fnote(po, "(this call)\n");
4302 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4303 tmpname, pp->argc_stack * 4, adj);
4304 }
4305
4306 scan_for_esp_adjust(i + 1, opcnt,
4307 pp->argc_stack * 4, &adj, &multipath, 1);
4308 }
4309 else if (pp->is_vararg)
4310 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4311 pp->name);
4312
4313 return pp;
4314}
4315
4316static int collect_call_args_early(struct parsed_op *po, int i,
4317 struct parsed_proto *pp, int *regmask)
4318{
4319 int arg, ret;
4320 int j;
4321
4322 for (arg = 0; arg < pp->argc; arg++)
4323 if (pp->arg[arg].reg == NULL)
4324 break;
4325
4326 // first see if it can be easily done
4327 for (j = i; j > 0 && arg < pp->argc; )
4328 {
4329 if (g_labels[j] != NULL)
4330 return -1;
4331 j--;
4332
4333 if (ops[j].op == OP_CALL)
4334 return -1;
4335 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP)
4336 return -1;
4337 else if (ops[j].op == OP_POP)
4338 return -1;
4339 else if (ops[j].flags & OPF_CJMP)
4340 return -1;
4341 else if (ops[j].op == OP_PUSH) {
4342 if (ops[j].flags & (OPF_FARG|OPF_FARGNR))
4343 return -1;
4344 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4345 if (ret >= 0)
4346 return -1;
4347
4348 if (pp->arg[arg].type.is_va_list)
4349 return -1;
4350
4351 // next arg
4352 for (arg++; arg < pp->argc; arg++)
4353 if (pp->arg[arg].reg == NULL)
4354 break;
4355 }
4356 }
4357
4358 if (arg < pp->argc)
4359 return -1;
4360
4361 // now do it
4362 for (arg = 0; arg < pp->argc; arg++)
4363 if (pp->arg[arg].reg == NULL)
4364 break;
4365
4366 for (j = i; j > 0 && arg < pp->argc; )
4367 {
4368 j--;
4369
4370 if (ops[j].op == OP_PUSH)
4371 {
4372 ops[j].p_argnext = -1;
4373 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4374 pp->arg[arg].datap = &ops[j];
4375
4376 if (ops[j].operand[0].type == OPT_REG)
4377 *regmask |= 1 << ops[j].operand[0].reg;
4378
4379 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4380 ops[j].flags &= ~OPF_RSAVE;
4381
4382 // next arg
4383 for (arg++; arg < pp->argc; arg++)
4384 if (pp->arg[arg].reg == NULL)
4385 break;
4386 }
4387 }
4388
4389 return 0;
4390}
4391
4392static int collect_call_args_r(struct parsed_op *po, int i,
4393 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4394 int *arg_grp, int arg, int magic, int need_op_saving, int may_reuse)
4395{
4396 struct parsed_proto *pp_tmp;
4397 struct parsed_op *po_tmp;
4398 struct label_ref *lr;
4399 int need_to_save_current;
4400 int arg_grp_current = 0;
4401 int save_args_seen = 0;
4402 int save_args;
4403 int ret = 0;
4404 int reg;
4405 char buf[32];
4406 int j, k;
4407
4408 if (i < 0) {
4409 ferr(po, "dead label encountered\n");
4410 return -1;
4411 }
4412
4413 for (; arg < pp->argc; arg++)
4414 if (pp->arg[arg].reg == NULL)
4415 break;
4416 magic = (magic & 0xffffff) | (arg << 24);
4417
4418 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4419 {
4420 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4421 if (ops[j].cc_scratch != magic) {
4422 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4423 pp->name);
4424 return -1;
4425 }
4426 // ok: have already been here
4427 return 0;
4428 }
4429 ops[j].cc_scratch = magic;
4430
4431 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4432 lr = &g_label_refs[j];
4433 if (lr->next != NULL)
4434 need_op_saving = 1;
4435 for (; lr->next; lr = lr->next) {
4436 check_i(&ops[j], lr->i);
4437 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4438 may_reuse = 1;
4439 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4440 arg_grp, arg, magic, need_op_saving, may_reuse);
4441 if (ret < 0)
4442 return ret;
4443 }
4444
4445 check_i(&ops[j], lr->i);
4446 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4447 may_reuse = 1;
4448 if (j > 0 && LAST_OP(j - 1)) {
4449 // follow last branch in reverse
4450 j = lr->i;
4451 continue;
4452 }
4453 need_op_saving = 1;
4454 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4455 arg_grp, arg, magic, need_op_saving, may_reuse);
4456 if (ret < 0)
4457 return ret;
4458 }
4459 j--;
4460
4461 if (ops[j].op == OP_CALL)
4462 {
4463 if (pp->is_unresolved)
4464 break;
4465
4466 pp_tmp = ops[j].pp;
4467 if (pp_tmp == NULL)
4468 ferr(po, "arg collect hit unparsed call '%s'\n",
4469 ops[j].operand[0].name);
4470 if (may_reuse && pp_tmp->argc_stack > 0)
4471 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4472 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4473 }
4474 // esp adjust of 0 means we collected it before
4475 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4476 && (ops[j].operand[1].type != OPT_CONST
4477 || ops[j].operand[1].val != 0))
4478 {
4479 if (pp->is_unresolved)
4480 break;
4481
4482 fnote(po, "(this call)\n");
4483 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4484 arg, pp->argc, ops[j].operand[1].val);
4485 }
4486 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4487 {
4488 if (pp->is_unresolved)
4489 break;
4490
4491 fnote(po, "(this call)\n");
4492 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4493 }
4494 else if (ops[j].flags & OPF_CJMP)
4495 {
4496 if (pp->is_unresolved)
4497 break;
4498
4499 may_reuse = 1;
4500 }
4501 else if (ops[j].op == OP_PUSH
4502 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4503 {
4504 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4505 break;
4506
4507 ops[j].p_argnext = -1;
4508 po_tmp = pp->arg[arg].datap;
4509 if (po_tmp != NULL)
4510 ops[j].p_argnext = po_tmp - ops;
4511 pp->arg[arg].datap = &ops[j];
4512
4513 need_to_save_current = 0;
4514 save_args = 0;
4515 reg = -1;
4516 if (ops[j].operand[0].type == OPT_REG)
4517 reg = ops[j].operand[0].reg;
4518
4519 if (!need_op_saving) {
4520 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4521 need_to_save_current = (ret >= 0);
4522 }
4523 if (need_op_saving || need_to_save_current) {
4524 // mark this push as one that needs operand saving
4525 ops[j].flags &= ~OPF_RMD;
4526 if (ops[j].p_argnum == 0) {
4527 ops[j].p_argnum = arg + 1;
4528 save_args |= 1 << arg;
4529 }
4530 else if (ops[j].p_argnum < arg + 1) {
4531 // XXX: might kill valid var..
4532 //*save_arg_vars &= ~(1 << (ops[j].p_argnum - 1));
4533 ops[j].p_argnum = arg + 1;
4534 save_args |= 1 << arg;
4535 }
4536
4537 if (save_args_seen & (1 << (ops[j].p_argnum - 1))) {
4538 save_args_seen = 0;
4539 arg_grp_current++;
4540 if (arg_grp_current >= MAX_ARG_GRP)
4541 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
4542 ops[j].p_argnum, pp->name);
4543 }
4544 }
4545 else if (ops[j].p_argnum == 0)
4546 ops[j].flags |= OPF_RMD;
4547
4548 // some PUSHes are reused by different calls on other branches,
4549 // but that can't happen if we didn't branch, so they
4550 // can be removed from future searches (handles nested calls)
4551 if (!may_reuse)
4552 ops[j].flags |= OPF_FARGNR;
4553
4554 ops[j].flags |= OPF_FARG;
4555 ops[j].flags &= ~OPF_RSAVE;
4556
4557 // check for __VALIST
4558 if (!pp->is_unresolved && g_func_pp != NULL
4559 && pp->arg[arg].type.is_va_list)
4560 {
4561 k = -1;
4562 ret = resolve_origin(j, &ops[j].operand[0],
4563 magic + 1, &k, NULL);
4564 if (ret == 1 && k >= 0)
4565 {
4566 if (ops[k].op == OP_LEA) {
4567 if (!g_func_pp->is_vararg)
4568 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
4569 g_func_pp->name);
4570
4571 snprintf(buf, sizeof(buf), "arg_%X",
4572 g_func_pp->argc_stack * 4);
4573 if (strstr(ops[k].operand[1].name, buf)
4574 || strstr(ops[k].operand[1].name, "arglist"))
4575 {
4576 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
4577 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
4578 save_args &= ~(1 << arg);
4579 reg = -1;
4580 }
4581 else
4582 ferr(&ops[k], "va_list arg detection failed\n");
4583 }
4584 // check for va_list from g_func_pp arg too
4585 else if (ops[k].op == OP_MOV
4586 && is_stack_access(&ops[k], &ops[k].operand[1]))
4587 {
4588 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
4589 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
4590 if (ret >= 0) {
4591 ops[k].flags |= OPF_RMD | OPF_DONE;
4592 ops[j].flags |= OPF_RMD;
4593 ops[j].p_argpass = ret + 1;
4594 save_args &= ~(1 << arg);
4595 reg = -1;
4596 }
4597 }
4598 }
4599 }
4600
4601 *save_arg_vars |= save_args;
4602
4603 // tracking reg usage
4604 if (reg >= 0)
4605 *regmask |= 1 << reg;
4606
4607 arg++;
4608 if (!pp->is_unresolved) {
4609 // next arg
4610 for (; arg < pp->argc; arg++)
4611 if (pp->arg[arg].reg == NULL)
4612 break;
4613 }
4614 magic = (magic & 0xffffff) | (arg << 24);
4615 }
4616
4617 if (ops[j].p_arggrp > arg_grp_current) {
4618 save_args_seen = 0;
4619 arg_grp_current = ops[j].p_arggrp;
4620 }
4621 if (ops[j].p_argnum > 0)
4622 save_args_seen |= 1 << (ops[j].p_argnum - 1);
4623 }
4624
4625 if (arg < pp->argc) {
4626 ferr(po, "arg collect failed for '%s': %d/%d\n",
4627 pp->name, arg, pp->argc);
4628 return -1;
4629 }
4630
4631 if (arg_grp_current > *arg_grp)
4632 *arg_grp = arg_grp_current;
4633
4634 return arg;
4635}
4636
4637static int collect_call_args(struct parsed_op *po, int i,
4638 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4639 int magic)
4640{
4641 // arg group is for cases when pushes for
4642 // multiple funcs are going on
4643 struct parsed_op *po_tmp;
4644 int save_arg_vars_current = 0;
4645 int arg_grp = 0;
4646 int ret;
4647 int a;
4648
4649 ret = collect_call_args_r(po, i, pp, regmask,
4650 &save_arg_vars_current, &arg_grp, 0, magic, 0, 0);
4651 if (ret < 0)
4652 return ret;
4653
4654 if (arg_grp != 0) {
4655 // propagate arg_grp
4656 for (a = 0; a < pp->argc; a++) {
4657 if (pp->arg[a].reg != NULL)
4658 continue;
4659
4660 po_tmp = pp->arg[a].datap;
4661 while (po_tmp != NULL) {
4662 po_tmp->p_arggrp = arg_grp;
4663 if (po_tmp->p_argnext > 0)
4664 po_tmp = &ops[po_tmp->p_argnext];
4665 else
4666 po_tmp = NULL;
4667 }
4668 }
4669 }
4670 save_arg_vars[arg_grp] |= save_arg_vars_current;
4671
4672 if (pp->is_unresolved) {
4673 pp->argc += ret;
4674 pp->argc_stack += ret;
4675 for (a = 0; a < pp->argc; a++)
4676 if (pp->arg[a].type.name == NULL)
4677 pp->arg[a].type.name = strdup("int");
4678 }
4679
4680 return ret;
4681}
4682
4683static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
4684 int regmask_now, int *regmask,
4685 int regmask_save_now, int *regmask_save,
4686 int *regmask_init, int regmask_arg)
4687{
4688 struct parsed_op *po;
4689 int already_saved;
4690 int regmask_new;
4691 int regmask_op;
4692 int flags_set;
4693 int ret, reg;
4694 int j;
4695
4696 for (; i < opcnt; i++)
4697 {
4698 po = &ops[i];
4699 if (cbits[i >> 3] & (1 << (i & 7)))
4700 return;
4701 cbits[i >> 3] |= (1 << (i & 7));
4702
4703 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4704 if (po->flags & (OPF_RMD|OPF_DONE))
4705 continue;
4706 if (po->btj != NULL) {
4707 for (j = 0; j < po->btj->count; j++) {
4708 check_i(po, po->btj->d[j].bt_i);
4709 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
4710 regmask_now, regmask, regmask_save_now, regmask_save,
4711 regmask_init, regmask_arg);
4712 }
4713 return;
4714 }
4715
4716 check_i(po, po->bt_i);
4717 if (po->flags & OPF_CJMP)
4718 reg_use_pass(po->bt_i, opcnt, cbits,
4719 regmask_now, regmask, regmask_save_now, regmask_save,
4720 regmask_init, regmask_arg);
4721 else
4722 i = po->bt_i - 1;
4723 continue;
4724 }
4725
4726 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
4727 && !g_func_pp->is_userstack
4728 && po->operand[0].type == OPT_REG)
4729 {
4730 reg = po->operand[0].reg;
4731 ferr_assert(po, reg >= 0);
4732
4733 already_saved = 0;
4734 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
4735 if (regmask_now & (1 << reg)) {
4736 already_saved = regmask_save_now & (1 << reg);
4737 flags_set = OPF_RSAVE | OPF_DONE;
4738 }
4739
4740 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0);
4741 if (ret == 1) {
4742 scan_for_pop(i + 1, opcnt, i + opcnt * 4, reg, 0, flags_set);
4743 }
4744 else {
4745 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
4746 if (ret == 1) {
4747 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
4748 flags_set);
4749 }
4750 }
4751 if (ret == 1) {
4752 ferr_assert(po, !already_saved);
4753 po->flags |= flags_set;
4754
4755 if (regmask_now & (1 << reg)) {
4756 regmask_save_now |= (1 << reg);
4757 *regmask_save |= regmask_save_now;
4758 }
4759 continue;
4760 }
4761 }
4762 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
4763 reg = po->operand[0].reg;
4764 ferr_assert(po, reg >= 0);
4765
4766 if (regmask_save_now & (1 << reg))
4767 regmask_save_now &= ~(1 << reg);
4768 else
4769 regmask_now &= ~(1 << reg);
4770 continue;
4771 }
4772 else if (po->op == OP_CALL) {
4773 if ((po->regmask_dst & (1 << xAX))
4774 && !(po->regmask_dst & (1 << xDX)))
4775 {
4776 if (po->flags & OPF_TAIL)
4777 // don't need eax, will do "return f();" or "f(); return;"
4778 po->regmask_dst &= ~(1 << xAX);
4779 else {
4780 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
4781 j = -1;
4782 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
4783 if (j == -1)
4784 // not used
4785 po->regmask_dst &= ~(1 << xAX);
4786 }
4787 }
4788
4789 // not "full stack" mode and have something in stack
4790 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
4791 ferr(po, "float stack is not empty on func call\n");
4792 }
4793
4794 if (po->flags & OPF_NOREGS)
4795 continue;
4796
4797 if (po->flags & OPF_FPUSH) {
4798 if (regmask_now & mxST1)
4799 regmask_now |= mxSTa; // switch to "full stack" mode
4800 if (regmask_now & mxSTa)
4801 po->flags |= OPF_FSHIFT;
4802 if (!(regmask_now & mxST7_2)) {
4803 regmask_now =
4804 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
4805 }
4806 }
4807
4808 // if incomplete register is used, clear it on init to avoid
4809 // later use of uninitialized upper part in some situations
4810 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
4811 && po->operand[0].lmod != OPLM_DWORD)
4812 {
4813 reg = po->operand[0].reg;
4814 ferr_assert(po, reg >= 0);
4815
4816 if (!(regmask_now & (1 << reg)))
4817 *regmask_init |= 1 << reg;
4818 }
4819
4820 regmask_op = po->regmask_src | po->regmask_dst;
4821
4822 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
4823 regmask_new &= ~(1 << xSP);
4824 if (g_bp_frame && !(po->flags & OPF_EBP_S))
4825 regmask_new &= ~(1 << xBP);
4826
4827 if (regmask_new != 0)
4828 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
4829
4830 if (regmask_op & (1 << xBP)) {
4831 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
4832 if (po->regmask_dst & (1 << xBP))
4833 // compiler decided to drop bp frame and use ebp as scratch
4834 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
4835 else
4836 regmask_op &= ~(1 << xBP);
4837 }
4838 }
4839
4840 regmask_now |= regmask_op;
4841 *regmask |= regmask_now;
4842
4843 // released regs
4844 if (po->flags & OPF_FPOP) {
4845 if ((regmask_now & mxSTa) == 0)
4846 ferr(po, "float pop on empty stack?\n");
4847 if (regmask_now & (mxST7_2 | mxST1))
4848 po->flags |= OPF_FSHIFT;
4849 if (!(regmask_now & mxST7_2)) {
4850 regmask_now =
4851 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
4852 }
4853 }
4854
4855 if (po->flags & OPF_TAIL) {
4856 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
4857 ferr(po, "float regs on tail: %x\n", regmask_now);
4858
4859 // there is support for "conditional tailcall", sort of
4860 if (!(po->flags & OPF_CC))
4861 return;
4862 }
4863 }
4864}
4865
4866static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
4867{
4868 int i;
4869
4870 for (i = 0; i < pp->argc; i++)
4871 if (pp->arg[i].reg == NULL)
4872 break;
4873
4874 if (pp->argc_stack)
4875 memmove(&pp->arg[i + 1], &pp->arg[i],
4876 sizeof(pp->arg[0]) * pp->argc_stack);
4877 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
4878 pp->arg[i].reg = strdup(reg);
4879 pp->arg[i].type.name = strdup("int");
4880 pp->argc++;
4881 pp->argc_reg++;
4882}
4883
4884static void output_std_flags(FILE *fout, struct parsed_op *po,
4885 int *pfomask, const char *dst_opr_text)
4886{
4887 if (*pfomask & (1 << PFO_Z)) {
4888 fprintf(fout, "\n cond_z = (%s%s == 0);",
4889 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
4890 *pfomask &= ~(1 << PFO_Z);
4891 }
4892 if (*pfomask & (1 << PFO_S)) {
4893 fprintf(fout, "\n cond_s = (%s%s < 0);",
4894 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
4895 *pfomask &= ~(1 << PFO_S);
4896 }
4897}
4898
4899enum {
4900 OPP_FORCE_NORETURN = (1 << 0),
4901 OPP_SIMPLE_ARGS = (1 << 1),
4902 OPP_ALIGN = (1 << 2),
4903};
4904
4905static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
4906 int flags)
4907{
4908 const char *cconv = "";
4909
4910 if (pp->is_fastcall)
4911 cconv = "__fastcall ";
4912 else if (pp->is_stdcall && pp->argc_reg == 0)
4913 cconv = "__stdcall ";
4914
4915 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
4916
4917 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
4918 fprintf(fout, "noreturn ");
4919}
4920
4921static void output_pp(FILE *fout, const struct parsed_proto *pp,
4922 int flags)
4923{
4924 int i;
4925
4926 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
4927 pp->ret_type.name);
4928 if (pp->is_fptr)
4929 fprintf(fout, "(");
4930 output_pp_attrs(fout, pp, flags);
4931 if (pp->is_fptr)
4932 fprintf(fout, "*");
4933 fprintf(fout, "%s", pp->name);
4934 if (pp->is_fptr)
4935 fprintf(fout, ")");
4936
4937 fprintf(fout, "(");
4938 for (i = 0; i < pp->argc; i++) {
4939 if (i > 0)
4940 fprintf(fout, ", ");
4941 if (pp->arg[i].fptr != NULL && !(flags & OPP_SIMPLE_ARGS)) {
4942 // func pointer
4943 output_pp(fout, pp->arg[i].fptr, 0);
4944 }
4945 else if (pp->arg[i].type.is_retreg) {
4946 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
4947 }
4948 else {
4949 fprintf(fout, "%s", pp->arg[i].type.name);
4950 if (!pp->is_fptr)
4951 fprintf(fout, " a%d", i + 1);
4952 }
4953 }
4954 if (pp->is_vararg) {
4955 if (i > 0)
4956 fprintf(fout, ", ");
4957 fprintf(fout, "...");
4958 }
4959 fprintf(fout, ")");
4960}
4961
4962static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
4963{
4964 char buf1[16];
4965
4966 buf1[0] = 0;
4967 if (grp > 0)
4968 snprintf(buf1, sizeof(buf1), "%d", grp);
4969 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
4970
4971 return buf;
4972}
4973
4974static void gen_x_cleanup(int opcnt);
4975
4976static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
4977{
4978 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
4979 struct parsed_opr *last_arith_dst = NULL;
4980 char buf1[256], buf2[256], buf3[256], cast[64];
4981 struct parsed_proto *pp, *pp_tmp;
4982 struct parsed_data *pd;
4983 unsigned int uval;
4984 int save_arg_vars[MAX_ARG_GRP] = { 0, };
4985 unsigned char cbits[MAX_OPS / 8];
4986 const char *float_type;
4987 const char *float_st0;
4988 const char *float_st1;
4989 int need_float_stack = 0;
4990 int need_tmp_var = 0;
4991 int need_tmp64 = 0;
4992 int cond_vars = 0;
4993 int had_decl = 0;
4994 int label_pending = 0;
4995 int need_double = 0;
4996 int regmask_save = 0; // regs saved/restored in this func
4997 int regmask_arg; // regs from this function args (fastcall, etc)
4998 int regmask_ret; // regs needed on ret
4999 int regmask_now; // temp
5000 int regmask_init = 0; // regs that need zero initialization
5001 int regmask_pp = 0; // regs used in complex push-pop graph
5002 int regmask = 0; // used regs
5003 int pfomask = 0;
5004 int found = 0;
5005 int dead_dst;
5006 int no_output;
5007 int i, j, l;
5008 int arg;
5009 int reg;
5010 int ret;
5011
5012 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5013 g_stack_frame_used = 0;
5014 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5015 regmask_init = g_regmask_init;
5016
5017 g_func_pp = proto_parse(fhdr, funcn, 0);
5018 if (g_func_pp == NULL)
5019 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5020
5021 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5022 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5023
5024 // pass1:
5025 // - resolve all branches
5026 // - parse calls with labels
5027 resolve_branches_parse_calls(opcnt);
5028
5029 // pass2:
5030 // - handle ebp/esp frame, remove ops related to it
5031 scan_prologue_epilogue(opcnt);
5032
5033 // pass3:
5034 // - remove dead labels
5035 // - set regs needed at ret
5036 for (i = 0; i < opcnt; i++)
5037 {
5038 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5039 free(g_labels[i]);
5040 g_labels[i] = NULL;
5041 }
5042
5043 if (ops[i].op == OP_RET)
5044 ops[i].regmask_src |= regmask_ret;
5045 }
5046
5047 // pass4:
5048 // - process trivial calls
5049 for (i = 0; i < opcnt; i++)
5050 {
5051 po = &ops[i];
5052 if (po->flags & (OPF_RMD|OPF_DONE))
5053 continue;
5054
5055 if (po->op == OP_CALL)
5056 {
5057 pp = process_call_early(i, opcnt, &j);
5058 if (pp != NULL) {
5059 if (!(po->flags & OPF_ATAIL))
5060 // since we know the args, try to collect them
5061 if (collect_call_args_early(po, i, pp, &regmask) != 0)
5062 pp = NULL;
5063 }
5064
5065 if (pp != NULL) {
5066 if (j >= 0) {
5067 // commit esp adjust
5068 if (ops[j].op != OP_POP)
5069 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5070 else {
5071 for (l = 0; l < pp->argc_stack; l++)
5072 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5073 }
5074 }
5075
5076 if (strstr(pp->ret_type.name, "int64"))
5077 need_tmp64 = 1;
5078
5079 po->flags |= OPF_DONE;
5080 }
5081 }
5082 }
5083
5084 // pass5:
5085 // - process calls, stage 2
5086 // - handle some push/pop pairs
5087 // - scan for STD/CLD, propagate DF
5088 for (i = 0; i < opcnt; i++)
5089 {
5090 po = &ops[i];
5091 if (po->flags & OPF_RMD)
5092 continue;
5093
5094 if (po->op == OP_CALL)
5095 {
5096 if (!(po->flags & OPF_DONE)) {
5097 pp = process_call(i, opcnt);
5098
5099 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5100 // since we know the args, collect them
5101 collect_call_args(po, i, pp, &regmask, save_arg_vars,
5102 i + opcnt * 2);
5103 }
5104 // for unresolved, collect after other passes
5105 }
5106
5107 pp = po->pp;
5108 ferr_assert(po, pp != NULL);
5109
5110 po->regmask_src |= get_pp_arg_regmask_src(pp);
5111 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5112
5113 if (po->regmask_dst & mxST0)
5114 po->flags |= OPF_FPUSH;
5115
5116 if (strstr(pp->ret_type.name, "int64"))
5117 need_tmp64 = 1;
5118
5119 continue;
5120 }
5121
5122 if (po->flags & OPF_DONE)
5123 continue;
5124
5125 if (po->op == OP_PUSH && !(po->flags & OPF_FARG)
5126 && !(po->flags & OPF_RSAVE) && po->operand[0].type == OPT_CONST)
5127 {
5128 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5129 }
5130 else if (po->op == OP_POP)
5131 scan_pushes_for_pop(i, opcnt, &regmask_pp);
5132 else if (po->op == OP_STD) {
5133 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5134 scan_propagate_df(i + 1, opcnt);
5135 }
5136 }
5137
5138 // pass6:
5139 // - find POPs for PUSHes, rm both
5140 // - scan for all used registers
5141 memset(cbits, 0, sizeof(cbits));
5142 reg_use_pass(0, opcnt, cbits, regmask_init, &regmask,
5143 0, &regmask_save, &regmask_init, regmask_arg);
5144
5145 // pass7:
5146 // - find flag set ops for their users
5147 // - do unresolved calls
5148 // - declare indirect functions
5149 for (i = 0; i < opcnt; i++)
5150 {
5151 po = &ops[i];
5152 if (po->flags & (OPF_RMD|OPF_DONE))
5153 continue;
5154
5155 if (po->flags & OPF_CC)
5156 {
5157 int setters[16], cnt = 0, branched = 0;
5158
5159 ret = scan_for_flag_set(i, i + opcnt * 6,
5160 &branched, setters, &cnt);
5161 if (ret < 0 || cnt <= 0)
5162 ferr(po, "unable to trace flag setter(s)\n");
5163 if (cnt > ARRAY_SIZE(setters))
5164 ferr(po, "too many flag setters\n");
5165
5166 for (j = 0; j < cnt; j++)
5167 {
5168 tmp_op = &ops[setters[j]]; // flag setter
5169 pfomask = 0;
5170
5171 // to get nicer code, we try to delay test and cmp;
5172 // if we can't because of operand modification, or if we
5173 // have arith op, or branch, make it calculate flags explicitly
5174 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5175 {
5176 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5177 pfomask = 1 << po->pfo;
5178 }
5179 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5180 pfomask = 1 << po->pfo;
5181 }
5182 else {
5183 // see if we'll be able to handle based on op result
5184 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5185 && po->pfo != PFO_Z && po->pfo != PFO_S
5186 && po->pfo != PFO_P)
5187 || branched
5188 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5189 {
5190 pfomask = 1 << po->pfo;
5191 }
5192
5193 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5194 propagate_lmod(tmp_op, &tmp_op->operand[0],
5195 &tmp_op->operand[1]);
5196 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5197 need_tmp64 = 1;
5198 }
5199 }
5200 if (pfomask) {
5201 tmp_op->pfomask |= pfomask;
5202 cond_vars |= pfomask;
5203 }
5204 // note: may overwrite, currently not a problem
5205 po->datap = tmp_op;
5206 }
5207
5208 if (po->op == OP_RCL || po->op == OP_RCR
5209 || po->op == OP_ADC || po->op == OP_SBB)
5210 cond_vars |= 1 << PFO_C;
5211 }
5212
5213 if (po->op == OP_CMPS || po->op == OP_SCAS) {
5214 cond_vars |= 1 << PFO_Z;
5215 }
5216 else if (po->op == OP_MUL
5217 || (po->op == OP_IMUL && po->operand_cnt == 1))
5218 {
5219 if (po->operand[0].lmod == OPLM_DWORD)
5220 need_tmp64 = 1;
5221 }
5222 else if (po->op == OP_CALL) {
5223 // note: resolved non-reg calls are OPF_DONE already
5224 pp = po->pp;
5225 ferr_assert(po, pp != NULL);
5226
5227 if (pp->is_unresolved) {
5228 int regmask_stack = 0;
5229 collect_call_args(po, i, pp, &regmask, save_arg_vars,
5230 i + opcnt * 2);
5231
5232 // this is pretty rough guess:
5233 // see ecx and edx were pushed (and not their saved versions)
5234 for (arg = 0; arg < pp->argc; arg++) {
5235 if (pp->arg[arg].reg != NULL)
5236 continue;
5237
5238 tmp_op = pp->arg[arg].datap;
5239 if (tmp_op == NULL)
5240 ferr(po, "parsed_op missing for arg%d\n", arg);
5241 if (tmp_op->p_argnum == 0 && tmp_op->operand[0].type == OPT_REG)
5242 regmask_stack |= 1 << tmp_op->operand[0].reg;
5243 }
5244
5245 if (!((regmask_stack & (1 << xCX))
5246 && (regmask_stack & (1 << xDX))))
5247 {
5248 if (pp->argc_stack != 0
5249 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5250 {
5251 pp_insert_reg_arg(pp, "ecx");
5252 pp->is_fastcall = 1;
5253 regmask_init |= 1 << xCX;
5254 regmask |= 1 << xCX;
5255 }
5256 if (pp->argc_stack != 0
5257 || ((regmask | regmask_arg) & (1 << xDX)))
5258 {
5259 pp_insert_reg_arg(pp, "edx");
5260 regmask_init |= 1 << xDX;
5261 regmask |= 1 << xDX;
5262 }
5263 }
5264
5265 // note: __cdecl doesn't fall into is_unresolved category
5266 if (pp->argc_stack > 0)
5267 pp->is_stdcall = 1;
5268 }
5269 }
5270 else if (po->op == OP_MOV && po->operand[0].pp != NULL
5271 && po->operand[1].pp != NULL)
5272 {
5273 // <var> = offset <something>
5274 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5275 && !IS_START(po->operand[1].name, "off_"))
5276 {
5277 if (!po->operand[0].pp->is_fptr)
5278 ferr(po, "%s not declared as fptr when it should be\n",
5279 po->operand[0].name);
5280 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5281 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5282 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5283 fnote(po, "var: %s\n", buf1);
5284 fnote(po, "func: %s\n", buf2);
5285 ferr(po, "^ mismatch\n");
5286 }
5287 }
5288 }
5289 else if (po->op == OP_DIV || po->op == OP_IDIV) {
5290 if (po->operand[0].lmod == OPLM_DWORD) {
5291 // 32bit division is common, look for it
5292 if (po->op == OP_DIV)
5293 ret = scan_for_reg_clear(i, xDX);
5294 else
5295 ret = scan_for_cdq_edx(i);
5296 if (ret >= 0)
5297 po->flags |= OPF_32BIT;
5298 else
5299 need_tmp64 = 1;
5300 }
5301 else
5302 need_tmp_var = 1;
5303 }
5304 else if (po->op == OP_CLD)
5305 po->flags |= OPF_RMD | OPF_DONE;
5306 else if (po->op == OPP_FTOL) {
5307 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5308 j = -1;
5309 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5310 if (j == -1)
5311 po->flags |= OPF_32BIT;
5312 }
5313 else if (po->op == OP_FLD && po->operand[0].lmod == OPLM_QWORD)
5314 need_double = 1;
5315
5316 if (po->op == OP_RCL || po->op == OP_RCR || po->op == OP_XCHG)
5317 need_tmp_var = 1;
5318 }
5319
5320 float_type = need_double ? "double" : "float";
5321 need_float_stack = !!(regmask & mxST7_2);
5322 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
5323 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
5324
5325 // output starts here
5326
5327 // define userstack size
5328 if (g_func_pp->is_userstack) {
5329 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5330 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5331 fprintf(fout, "#endif\n");
5332 }
5333
5334 // the function itself
5335 ferr_assert(ops, !g_func_pp->is_fptr);
5336 output_pp(fout, g_func_pp,
5337 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5338 fprintf(fout, "\n{\n");
5339
5340 // declare indirect functions
5341 for (i = 0; i < opcnt; i++) {
5342 po = &ops[i];
5343 if (po->flags & OPF_RMD)
5344 continue;
5345
5346 if (po->op == OP_CALL) {
5347 pp = po->pp;
5348 if (pp == NULL)
5349 ferr(po, "NULL pp\n");
5350
5351 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5352 if (pp->name[0] != 0) {
5353 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5354 memcpy(pp->name, "i_", 2);
5355
5356 // might be declared already
5357 found = 0;
5358 for (j = 0; j < i; j++) {
5359 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5360 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5361 found = 1;
5362 break;
5363 }
5364 }
5365 }
5366 if (found)
5367 continue;
5368 }
5369 else
5370 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5371
5372 fprintf(fout, " ");
5373 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5374 fprintf(fout, ";\n");
5375 }
5376 }
5377 }
5378
5379 // output LUTs/jumptables
5380 for (i = 0; i < g_func_pd_cnt; i++) {
5381 pd = &g_func_pd[i];
5382 fprintf(fout, " static const ");
5383 if (pd->type == OPT_OFFSET) {
5384 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5385
5386 for (j = 0; j < pd->count; j++) {
5387 if (j > 0)
5388 fprintf(fout, ", ");
5389 fprintf(fout, "&&%s", pd->d[j].u.label);
5390 }
5391 }
5392 else {
5393 fprintf(fout, "%s %s[] =\n { ",
5394 lmod_type_u(ops, pd->lmod), pd->label);
5395
5396 for (j = 0; j < pd->count; j++) {
5397 if (j > 0)
5398 fprintf(fout, ", ");
5399 fprintf(fout, "%u", pd->d[j].u.val);
5400 }
5401 }
5402 fprintf(fout, " };\n");
5403 had_decl = 1;
5404 }
5405
5406 // declare stack frame, va_arg
5407 if (g_stack_fsz) {
5408 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5409 if (g_func_lmods & (1 << OPLM_WORD))
5410 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5411 if (g_func_lmods & (1 << OPLM_BYTE))
5412 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5413 if (g_func_lmods & (1 << OPLM_QWORD))
5414 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5415 fprintf(fout, " } sf;\n");
5416 had_decl = 1;
5417 }
5418
5419 if (g_func_pp->is_userstack) {
5420 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5421 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5422 had_decl = 1;
5423 }
5424
5425 if (g_func_pp->is_vararg) {
5426 fprintf(fout, " va_list ap;\n");
5427 had_decl = 1;
5428 }
5429
5430 // declare arg-registers
5431 for (i = 0; i < g_func_pp->argc; i++) {
5432 if (g_func_pp->arg[i].reg != NULL) {
5433 reg = char_array_i(regs_r32,
5434 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5435 if (regmask & (1 << reg)) {
5436 if (g_func_pp->arg[i].type.is_retreg)
5437 fprintf(fout, " u32 %s = *r_%s;\n",
5438 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5439 else
5440 fprintf(fout, " u32 %s = (u32)a%d;\n",
5441 g_func_pp->arg[i].reg, i + 1);
5442 }
5443 else {
5444 if (g_func_pp->arg[i].type.is_retreg)
5445 ferr(ops, "retreg '%s' is unused?\n",
5446 g_func_pp->arg[i].reg);
5447 fprintf(fout, " // %s = a%d; // unused\n",
5448 g_func_pp->arg[i].reg, i + 1);
5449 }
5450 had_decl = 1;
5451 }
5452 }
5453
5454 // declare normal registers
5455 regmask_now = regmask & ~regmask_arg;
5456 regmask_now &= ~(1 << xSP);
5457 if (regmask_now & 0x00ff) {
5458 for (reg = 0; reg < 8; reg++) {
5459 if (regmask_now & (1 << reg)) {
5460 fprintf(fout, " u32 %s", regs_r32[reg]);
5461 if (regmask_init & (1 << reg))
5462 fprintf(fout, " = 0");
5463 fprintf(fout, ";\n");
5464 had_decl = 1;
5465 }
5466 }
5467 }
5468 // ... mmx
5469 if (regmask_now & 0xff00) {
5470 for (reg = 8; reg < 16; reg++) {
5471 if (regmask_now & (1 << reg)) {
5472 fprintf(fout, " mmxr %s", regs_r32[reg]);
5473 if (regmask_init & (1 << reg))
5474 fprintf(fout, " = { 0, }");
5475 fprintf(fout, ";\n");
5476 had_decl = 1;
5477 }
5478 }
5479 }
5480 // ... x87
5481 if (need_float_stack) {
5482 fprintf(fout, " %s f_st[8];\n", float_type);
5483 fprintf(fout, " int f_stp = 0;\n");
5484 had_decl = 1;
5485 }
5486 else {
5487 if (regmask_now & 0xff0000) {
5488 for (reg = 16; reg < 24; reg++) {
5489 if (regmask_now & (1 << reg)) {
5490 fprintf(fout, " %s f_st%d", float_type, reg - 16);
5491 if (regmask_init & (1 << reg))
5492 fprintf(fout, " = 0");
5493 fprintf(fout, ";\n");
5494 had_decl = 1;
5495 }
5496 }
5497 }
5498 }
5499
5500 if (regmask_save) {
5501 for (reg = 0; reg < 8; reg++) {
5502 if (regmask_save & (1 << reg)) {
5503 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
5504 had_decl = 1;
5505 }
5506 }
5507 }
5508
5509 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
5510 if (save_arg_vars[i] == 0)
5511 continue;
5512 for (reg = 0; reg < 32; reg++) {
5513 if (save_arg_vars[i] & (1 << reg)) {
5514 fprintf(fout, " u32 %s;\n",
5515 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
5516 had_decl = 1;
5517 }
5518 }
5519 }
5520
5521 // declare push-pop temporaries
5522 if (regmask_pp) {
5523 for (reg = 0; reg < 8; reg++) {
5524 if (regmask_pp & (1 << reg)) {
5525 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
5526 had_decl = 1;
5527 }
5528 }
5529 }
5530
5531 if (cond_vars) {
5532 for (i = 0; i < 8; i++) {
5533 if (cond_vars & (1 << i)) {
5534 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
5535 had_decl = 1;
5536 }
5537 }
5538 }
5539
5540 if (need_tmp_var) {
5541 fprintf(fout, " u32 tmp;\n");
5542 had_decl = 1;
5543 }
5544
5545 if (need_tmp64) {
5546 fprintf(fout, " u64 tmp64;\n");
5547 had_decl = 1;
5548 }
5549
5550 if (had_decl)
5551 fprintf(fout, "\n");
5552
5553 // do stack clear, if needed
5554 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
5555 fprintf(fout, " ");
5556 if (g_stack_clear_len != 0) {
5557 if (g_stack_clear_len <= 4) {
5558 for (i = 0; i < g_stack_clear_len; i++)
5559 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
5560 fprintf(fout, "0;\n");
5561 }
5562 else {
5563 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
5564 g_stack_clear_start, g_stack_clear_len * 4);
5565 }
5566 }
5567 else
5568 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
5569 }
5570
5571 if (g_func_pp->is_vararg) {
5572 if (g_func_pp->argc_stack == 0)
5573 ferr(ops, "vararg func without stack args?\n");
5574 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
5575 }
5576
5577 // output ops
5578 for (i = 0; i < opcnt; i++)
5579 {
5580 if (g_labels[i] != NULL) {
5581 fprintf(fout, "\n%s:\n", g_labels[i]);
5582 label_pending = 1;
5583
5584 delayed_flag_op = NULL;
5585 last_arith_dst = NULL;
5586 }
5587
5588 po = &ops[i];
5589 if (po->flags & OPF_RMD)
5590 continue;
5591
5592 no_output = 0;
5593
5594 #define assert_operand_cnt(n_) \
5595 if (po->operand_cnt != n_) \
5596 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
5597
5598 // conditional/flag using op?
5599 if (po->flags & OPF_CC)
5600 {
5601 int is_delayed = 0;
5602
5603 tmp_op = po->datap;
5604
5605 // we go through all this trouble to avoid using parsed_flag_op,
5606 // which makes generated code much nicer
5607 if (delayed_flag_op != NULL)
5608 {
5609 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
5610 po->pfo, po->pfo_inv);
5611 is_delayed = 1;
5612 }
5613 else if (last_arith_dst != NULL
5614 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
5615 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
5616 ))
5617 {
5618 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5619 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
5620 last_arith_dst->lmod, buf3);
5621 is_delayed = 1;
5622 }
5623 else if (tmp_op != NULL) {
5624 // use preprocessed flag calc results
5625 if (!(tmp_op->pfomask & (1 << po->pfo)))
5626 ferr(po, "not prepared for pfo %d\n", po->pfo);
5627
5628 // note: pfo_inv was not yet applied
5629 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
5630 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
5631 }
5632 else {
5633 ferr(po, "all methods of finding comparison failed\n");
5634 }
5635
5636 if (po->flags & OPF_JMP) {
5637 fprintf(fout, " if %s", buf1);
5638 }
5639 else if (po->op == OP_RCL || po->op == OP_RCR
5640 || po->op == OP_ADC || po->op == OP_SBB)
5641 {
5642 if (is_delayed)
5643 fprintf(fout, " cond_%s = %s;\n",
5644 parsed_flag_op_names[po->pfo], buf1);
5645 }
5646 else if (po->flags & OPF_DATA) { // SETcc
5647 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
5648 fprintf(fout, " %s = %s;", buf2, buf1);
5649 }
5650 else {
5651 ferr(po, "unhandled conditional op\n");
5652 }
5653 }
5654
5655 pfomask = po->pfomask;
5656
5657 if (po->flags & (OPF_REPZ|OPF_REPNZ)) {
5658 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
5659 ret = try_resolve_const(i, &opr, opcnt * 7 + i, &uval);
5660
5661 if (ret != 1 || uval == 0) {
5662 // we need initial flags for ecx=0 case..
5663 if (i > 0 && ops[i - 1].op == OP_XOR
5664 && IS(ops[i - 1].operand[0].name,
5665 ops[i - 1].operand[1].name))
5666 {
5667 fprintf(fout, " cond_z = ");
5668 if (pfomask & (1 << PFO_C))
5669 fprintf(fout, "cond_c = ");
5670 fprintf(fout, "0;\n");
5671 }
5672 else if (last_arith_dst != NULL) {
5673 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5674 out_test_for_cc(buf1, sizeof(buf1), po, PFO_Z, 0,
5675 last_arith_dst->lmod, buf3);
5676 fprintf(fout, " cond_z = %s;\n", buf1);
5677 }
5678 else
5679 ferr(po, "missing initial ZF\n");
5680 }
5681 }
5682
5683 switch (po->op)
5684 {
5685 case OP_MOV:
5686 assert_operand_cnt(2);
5687 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5688 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5689 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
5690 fprintf(fout, " %s = %s;", buf1,
5691 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5692 buf3, 0));
5693 break;
5694
5695 case OP_LEA:
5696 assert_operand_cnt(2);
5697 po->operand[1].lmod = OPLM_DWORD; // always
5698 fprintf(fout, " %s = %s;",
5699 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5700 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5701 NULL, 1));
5702 break;
5703
5704 case OP_MOVZX:
5705 assert_operand_cnt(2);
5706 fprintf(fout, " %s = %s;",
5707 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5708 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5709 break;
5710
5711 case OP_MOVSX:
5712 assert_operand_cnt(2);
5713 switch (po->operand[1].lmod) {
5714 case OPLM_BYTE:
5715 strcpy(buf3, "(s8)");
5716 break;
5717 case OPLM_WORD:
5718 strcpy(buf3, "(s16)");
5719 break;
5720 default:
5721 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
5722 }
5723 fprintf(fout, " %s = %s;",
5724 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5725 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5726 buf3, 0));
5727 break;
5728
5729 case OP_XCHG:
5730 assert_operand_cnt(2);
5731 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5732 fprintf(fout, " tmp = %s;",
5733 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
5734 fprintf(fout, " %s = %s;",
5735 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5736 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5737 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5738 fprintf(fout, " %s = %stmp;",
5739 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
5740 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
5741 snprintf(g_comment, sizeof(g_comment), "xchg");
5742 break;
5743
5744 case OP_NOT:
5745 assert_operand_cnt(1);
5746 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5747 fprintf(fout, " %s = ~%s;", buf1, buf1);
5748 break;
5749
5750 case OP_XLAT:
5751 assert_operand_cnt(2);
5752 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5753 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5754 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
5755 strcpy(g_comment, "xlat");
5756 break;
5757
5758 case OP_CDQ:
5759 assert_operand_cnt(2);
5760 fprintf(fout, " %s = (s32)%s >> 31;",
5761 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5762 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5763 strcpy(g_comment, "cdq");
5764 break;
5765
5766 case OP_LODS:
5767 if (po->flags & OPF_REP) {
5768 assert_operand_cnt(3);
5769 // hmh..
5770 ferr(po, "TODO\n");
5771 }
5772 else {
5773 assert_operand_cnt(2);
5774 fprintf(fout, " %s = %sesi; esi %c= %d;",
5775 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
5776 lmod_cast_u_ptr(po, po->operand[1].lmod),
5777 (po->flags & OPF_DF) ? '-' : '+',
5778 lmod_bytes(po, po->operand[1].lmod));
5779 strcpy(g_comment, "lods");
5780 }
5781 break;
5782
5783 case OP_STOS:
5784 if (po->flags & OPF_REP) {
5785 assert_operand_cnt(3);
5786 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
5787 (po->flags & OPF_DF) ? '-' : '+',
5788 lmod_bytes(po, po->operand[1].lmod));
5789 fprintf(fout, " %sedi = eax;",
5790 lmod_cast_u_ptr(po, po->operand[1].lmod));
5791 strcpy(g_comment, "rep stos");
5792 }
5793 else {
5794 assert_operand_cnt(2);
5795 fprintf(fout, " %sedi = eax; edi %c= %d;",
5796 lmod_cast_u_ptr(po, po->operand[1].lmod),
5797 (po->flags & OPF_DF) ? '-' : '+',
5798 lmod_bytes(po, po->operand[1].lmod));
5799 strcpy(g_comment, "stos");
5800 }
5801 break;
5802
5803 case OP_MOVS:
5804 j = lmod_bytes(po, po->operand[0].lmod);
5805 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
5806 l = (po->flags & OPF_DF) ? '-' : '+';
5807 if (po->flags & OPF_REP) {
5808 assert_operand_cnt(3);
5809 fprintf(fout,
5810 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
5811 l, j, l, j);
5812 fprintf(fout,
5813 " %sedi = %sesi;", buf1, buf1);
5814 strcpy(g_comment, "rep movs");
5815 }
5816 else {
5817 assert_operand_cnt(2);
5818 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
5819 buf1, buf1, l, j, l, j);
5820 strcpy(g_comment, "movs");
5821 }
5822 break;
5823
5824 case OP_CMPS:
5825 // repe ~ repeat while ZF=1
5826 j = lmod_bytes(po, po->operand[0].lmod);
5827 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
5828 l = (po->flags & OPF_DF) ? '-' : '+';
5829 if (po->flags & OPF_REP) {
5830 assert_operand_cnt(3);
5831 fprintf(fout,
5832 " for (; ecx != 0; ecx--) {\n");
5833 if (pfomask & (1 << PFO_C)) {
5834 // ugh..
5835 fprintf(fout,
5836 " cond_c = %sesi < %sedi;\n", buf1, buf1);
5837 pfomask &= ~(1 << PFO_C);
5838 }
5839 fprintf(fout,
5840 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
5841 buf1, buf1, l, j, l, j);
5842 fprintf(fout,
5843 " if (cond_z %s 0) break;\n",
5844 (po->flags & OPF_REPZ) ? "==" : "!=");
5845 fprintf(fout,
5846 " }");
5847 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
5848 (po->flags & OPF_REPZ) ? "e" : "ne");
5849 }
5850 else {
5851 assert_operand_cnt(2);
5852 fprintf(fout,
5853 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
5854 buf1, buf1, l, j, l, j);
5855 strcpy(g_comment, "cmps");
5856 }
5857 pfomask &= ~(1 << PFO_Z);
5858 last_arith_dst = NULL;
5859 delayed_flag_op = NULL;
5860 break;
5861
5862 case OP_SCAS:
5863 // only does ZF (for now)
5864 // repe ~ repeat while ZF=1
5865 j = lmod_bytes(po, po->operand[1].lmod);
5866 l = (po->flags & OPF_DF) ? '-' : '+';
5867 if (po->flags & OPF_REP) {
5868 assert_operand_cnt(3);
5869 fprintf(fout,
5870 " for (; ecx != 0; ecx--) {\n");
5871 fprintf(fout,
5872 " cond_z = (%seax == %sedi); edi %c= %d;\n",
5873 lmod_cast_u(po, po->operand[1].lmod),
5874 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
5875 fprintf(fout,
5876 " if (cond_z %s 0) break;\n",
5877 (po->flags & OPF_REPZ) ? "==" : "!=");
5878 fprintf(fout,
5879 " }");
5880 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
5881 (po->flags & OPF_REPZ) ? "e" : "ne");
5882 }
5883 else {
5884 assert_operand_cnt(2);
5885 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
5886 lmod_cast_u(po, po->operand[1].lmod),
5887 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
5888 strcpy(g_comment, "scas");
5889 }
5890 pfomask &= ~(1 << PFO_Z);
5891 last_arith_dst = NULL;
5892 delayed_flag_op = NULL;
5893 break;
5894
5895 // arithmetic w/flags
5896 case OP_AND:
5897 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
5898 goto dualop_arith_const;
5899 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5900 goto dualop_arith;
5901
5902 case OP_OR:
5903 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5904 if (po->operand[1].type == OPT_CONST) {
5905 j = lmod_bytes(po, po->operand[0].lmod);
5906 if (((1ull << j * 8) - 1) == po->operand[1].val)
5907 goto dualop_arith_const;
5908 }
5909 goto dualop_arith;
5910
5911 dualop_arith:
5912 assert_operand_cnt(2);
5913 fprintf(fout, " %s %s= %s;",
5914 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5915 op_to_c(po),
5916 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5917 output_std_flags(fout, po, &pfomask, buf1);
5918 last_arith_dst = &po->operand[0];
5919 delayed_flag_op = NULL;
5920 break;
5921
5922 dualop_arith_const:
5923 // and 0, or ~0 used instead mov
5924 assert_operand_cnt(2);
5925 fprintf(fout, " %s = %s;",
5926 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5927 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5928 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5929 output_std_flags(fout, po, &pfomask, buf1);
5930 last_arith_dst = &po->operand[0];
5931 delayed_flag_op = NULL;
5932 break;
5933
5934 case OP_SHL:
5935 case OP_SHR:
5936 assert_operand_cnt(2);
5937 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5938 if (pfomask & (1 << PFO_C)) {
5939 if (po->operand[1].type == OPT_CONST) {
5940 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5941 j = po->operand[1].val;
5942 j %= l;
5943 if (j != 0) {
5944 if (po->op == OP_SHL)
5945 j = l - j;
5946 else
5947 j -= 1;
5948 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
5949 buf1, j);
5950 }
5951 else
5952 ferr(po, "zero shift?\n");
5953 }
5954 else
5955 ferr(po, "TODO\n");
5956 pfomask &= ~(1 << PFO_C);
5957 }
5958 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
5959 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5960 if (po->operand[1].type != OPT_CONST)
5961 fprintf(fout, " & 0x1f");
5962 fprintf(fout, ";");
5963 output_std_flags(fout, po, &pfomask, buf1);
5964 last_arith_dst = &po->operand[0];
5965 delayed_flag_op = NULL;
5966 break;
5967
5968 case OP_SAR:
5969 assert_operand_cnt(2);
5970 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5971 fprintf(fout, " %s = %s%s >> %s;", buf1,
5972 lmod_cast_s(po, po->operand[0].lmod), buf1,
5973 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5974 output_std_flags(fout, po, &pfomask, buf1);
5975 last_arith_dst = &po->operand[0];
5976 delayed_flag_op = NULL;
5977 break;
5978
5979 case OP_SHLD:
5980 case OP_SHRD:
5981 assert_operand_cnt(3);
5982 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5983 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5984 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
5985 if (po->operand[2].type != OPT_CONST) {
5986 // no handling for "undefined" case, hopefully not needed
5987 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
5988 strcpy(buf3, buf2);
5989 }
5990 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5991 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5992 if (po->op == OP_SHLD) {
5993 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
5994 buf1, buf3, buf1, buf2, l, buf3);
5995 strcpy(g_comment, "shld");
5996 }
5997 else {
5998 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
5999 buf1, buf3, buf1, buf2, l, buf3);
6000 strcpy(g_comment, "shrd");
6001 }
6002 output_std_flags(fout, po, &pfomask, buf1);
6003 last_arith_dst = &po->operand[0];
6004 delayed_flag_op = NULL;
6005 break;
6006
6007 case OP_ROL:
6008 case OP_ROR:
6009 assert_operand_cnt(2);
6010 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6011 if (po->operand[1].type == OPT_CONST) {
6012 j = po->operand[1].val;
6013 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6014 fprintf(fout, po->op == OP_ROL ?
6015 " %s = (%s << %d) | (%s >> %d);" :
6016 " %s = (%s >> %d) | (%s << %d);",
6017 buf1, buf1, j, buf1,
6018 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6019 }
6020 else
6021 ferr(po, "TODO\n");
6022 output_std_flags(fout, po, &pfomask, buf1);
6023 last_arith_dst = &po->operand[0];
6024 delayed_flag_op = NULL;
6025 break;
6026
6027 case OP_RCL:
6028 case OP_RCR:
6029 assert_operand_cnt(2);
6030 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6031 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6032 if (po->operand[1].type == OPT_CONST) {
6033 j = po->operand[1].val % l;
6034 if (j == 0)
6035 ferr(po, "zero rotate\n");
6036 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6037 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6038 if (po->op == OP_RCL) {
6039 fprintf(fout,
6040 " %s = (%s << %d) | (cond_c << %d)",
6041 buf1, buf1, j, j - 1);
6042 if (j != 1)
6043 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6044 }
6045 else {
6046 fprintf(fout,
6047 " %s = (%s >> %d) | (cond_c << %d)",
6048 buf1, buf1, j, l - j);
6049 if (j != 1)
6050 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6051 }
6052 fprintf(fout, ";\n");
6053 fprintf(fout, " cond_c = tmp;");
6054 }
6055 else
6056 ferr(po, "TODO\n");
6057 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6058 output_std_flags(fout, po, &pfomask, buf1);
6059 last_arith_dst = &po->operand[0];
6060 delayed_flag_op = NULL;
6061 break;
6062
6063 case OP_XOR:
6064 assert_operand_cnt(2);
6065 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6066 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6067 // special case for XOR
6068 if (pfomask & (1 << PFO_BE)) { // weird, but it happens..
6069 fprintf(fout, " cond_be = 1;\n");
6070 pfomask &= ~(1 << PFO_BE);
6071 }
6072 fprintf(fout, " %s = 0;",
6073 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6074 last_arith_dst = &po->operand[0];
6075 delayed_flag_op = NULL;
6076 break;
6077 }
6078 goto dualop_arith;
6079
6080 case OP_ADD:
6081 assert_operand_cnt(2);
6082 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6083 if (pfomask & (1 << PFO_C)) {
6084 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6085 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6086 if (po->operand[0].lmod == OPLM_DWORD) {
6087 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6088 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6089 fprintf(fout, " %s = (u32)tmp64;",
6090 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6091 strcat(g_comment, " add64");
6092 }
6093 else {
6094 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6095 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6096 fprintf(fout, " %s += %s;",
6097 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6098 buf2);
6099 }
6100 pfomask &= ~(1 << PFO_C);
6101 output_std_flags(fout, po, &pfomask, buf1);
6102 last_arith_dst = &po->operand[0];
6103 delayed_flag_op = NULL;
6104 break;
6105 }
6106 goto dualop_arith;
6107
6108 case OP_SUB:
6109 assert_operand_cnt(2);
6110 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6111 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6112 for (j = 0; j <= PFO_LE; j++) {
6113 if (!(pfomask & (1 << j)))
6114 continue;
6115 if (j == PFO_Z || j == PFO_S)
6116 continue;
6117
6118 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
6119 fprintf(fout, " cond_%s = %s;\n",
6120 parsed_flag_op_names[j], buf1);
6121 pfomask &= ~(1 << j);
6122 }
6123 }
6124 goto dualop_arith;
6125
6126 case OP_ADC:
6127 case OP_SBB:
6128 assert_operand_cnt(2);
6129 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6130 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6131 if (po->op == OP_SBB
6132 && IS(po->operand[0].name, po->operand[1].name))
6133 {
6134 // avoid use of unitialized var
6135 fprintf(fout, " %s = -cond_c;", buf1);
6136 // carry remains what it was
6137 pfomask &= ~(1 << PFO_C);
6138 }
6139 else {
6140 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6141 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6142 }
6143 output_std_flags(fout, po, &pfomask, buf1);
6144 last_arith_dst = &po->operand[0];
6145 delayed_flag_op = NULL;
6146 break;
6147
6148 case OP_BSF:
6149 assert_operand_cnt(2);
6150 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6151 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6152 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6153 buf2, buf2);
6154 output_std_flags(fout, po, &pfomask, buf1);
6155 last_arith_dst = &po->operand[0];
6156 delayed_flag_op = NULL;
6157 strcat(g_comment, " bsf");
6158 break;
6159
6160 case OP_DEC:
6161 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6162 for (j = 0; j <= PFO_LE; j++) {
6163 if (!(pfomask & (1 << j)))
6164 continue;
6165 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6166 continue;
6167
6168 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
6169 fprintf(fout, " cond_%s = %s;\n",
6170 parsed_flag_op_names[j], buf1);
6171 pfomask &= ~(1 << j);
6172 }
6173 }
6174 // fallthrough
6175
6176 case OP_INC:
6177 if (pfomask & (1 << PFO_C))
6178 // carry is unaffected by inc/dec.. wtf?
6179 ferr(po, "carry propagation needed\n");
6180
6181 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6182 if (po->operand[0].type == OPT_REG) {
6183 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6184 fprintf(fout, " %s%s;", buf1, buf2);
6185 }
6186 else {
6187 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6188 fprintf(fout, " %s %s= 1;", buf1, buf2);
6189 }
6190 output_std_flags(fout, po, &pfomask, buf1);
6191 last_arith_dst = &po->operand[0];
6192 delayed_flag_op = NULL;
6193 break;
6194
6195 case OP_NEG:
6196 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6197 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6198 fprintf(fout, " %s = -%s%s;", buf1,
6199 lmod_cast_s(po, po->operand[0].lmod), buf2);
6200 last_arith_dst = &po->operand[0];
6201 delayed_flag_op = NULL;
6202 if (pfomask & (1 << PFO_C)) {
6203 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6204 pfomask &= ~(1 << PFO_C);
6205 }
6206 break;
6207
6208 case OP_IMUL:
6209 if (po->operand_cnt == 2) {
6210 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6211 goto dualop_arith;
6212 }
6213 if (po->operand_cnt == 3)
6214 ferr(po, "TODO imul3\n");
6215 // fallthrough
6216 case OP_MUL:
6217 assert_operand_cnt(1);
6218 switch (po->operand[0].lmod) {
6219 case OPLM_DWORD:
6220 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6221 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6222 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6223 fprintf(fout, " edx = tmp64 >> 32;\n");
6224 fprintf(fout, " eax = tmp64;");
6225 break;
6226 case OPLM_BYTE:
6227 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6228 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6229 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6230 buf1, 0));
6231 break;
6232 default:
6233 ferr(po, "TODO: unhandled mul type\n");
6234 break;
6235 }
6236 last_arith_dst = NULL;
6237 delayed_flag_op = NULL;
6238 break;
6239
6240 case OP_DIV:
6241 case OP_IDIV:
6242 assert_operand_cnt(1);
6243 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6244 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6245 po->op == OP_IDIV));
6246 switch (po->operand[0].lmod) {
6247 case OPLM_DWORD:
6248 if (po->flags & OPF_32BIT)
6249 snprintf(buf2, sizeof(buf2), "%seax", cast);
6250 else {
6251 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6252 snprintf(buf2, sizeof(buf2), "%stmp64",
6253 (po->op == OP_IDIV) ? "(s64)" : "");
6254 }
6255 if (po->operand[0].type == OPT_REG
6256 && po->operand[0].reg == xDX)
6257 {
6258 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6259 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6260 }
6261 else {
6262 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6263 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6264 }
6265 break;
6266 case OPLM_WORD:
6267 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6268 snprintf(buf2, sizeof(buf2), "%stmp",
6269 (po->op == OP_IDIV) ? "(s32)" : "");
6270 if (po->operand[0].type == OPT_REG
6271 && po->operand[0].reg == xDX)
6272 {
6273 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6274 buf2, cast, buf1);
6275 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6276 buf2, cast, buf1);
6277 }
6278 else {
6279 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6280 buf2, cast, buf1);
6281 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6282 buf2, cast, buf1);
6283 }
6284 strcat(g_comment, " div16");
6285 break;
6286 default:
6287 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6288 }
6289 last_arith_dst = NULL;
6290 delayed_flag_op = NULL;
6291 break;
6292
6293 case OP_TEST:
6294 case OP_CMP:
6295 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6296 if (pfomask != 0) {
6297 for (j = 0; j < 8; j++) {
6298 if (pfomask & (1 << j)) {
6299 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6300 fprintf(fout, " cond_%s = %s;",
6301 parsed_flag_op_names[j], buf1);
6302 }
6303 }
6304 pfomask = 0;
6305 }
6306 else
6307 no_output = 1;
6308 last_arith_dst = NULL;
6309 delayed_flag_op = po;
6310 break;
6311
6312 case OP_SCC:
6313 // SETcc - should already be handled
6314 break;
6315
6316 // note: we reuse OP_Jcc for SETcc, only flags differ
6317 case OP_JCC:
6318 fprintf(fout, "\n goto %s;", po->operand[0].name);
6319 break;
6320
6321 case OP_JECXZ:
6322 fprintf(fout, " if (ecx == 0)\n");
6323 fprintf(fout, " goto %s;", po->operand[0].name);
6324 strcat(g_comment, " jecxz");
6325 break;
6326
6327 case OP_LOOP:
6328 fprintf(fout, " if (--ecx != 0)\n");
6329 fprintf(fout, " goto %s;", po->operand[0].name);
6330 strcat(g_comment, " loop");
6331 break;
6332
6333 case OP_JMP:
6334 assert_operand_cnt(1);
6335 last_arith_dst = NULL;
6336 delayed_flag_op = NULL;
6337
6338 if (po->operand[0].type == OPT_REGMEM) {
6339 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6340 buf1, buf2);
6341 if (ret != 2)
6342 ferr(po, "parse failure for jmp '%s'\n",
6343 po->operand[0].name);
6344 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6345 break;
6346 }
6347 else if (po->operand[0].type != OPT_LABEL)
6348 ferr(po, "unhandled jmp type\n");
6349
6350 fprintf(fout, " goto %s;", po->operand[0].name);
6351 break;
6352
6353 case OP_CALL:
6354 assert_operand_cnt(1);
6355 pp = po->pp;
6356 my_assert_not(pp, NULL);
6357
6358 strcpy(buf3, " ");
6359 if (po->flags & OPF_CC) {
6360 // we treat conditional branch to another func
6361 // (yes such code exists..) as conditional tailcall
6362 strcat(buf3, " ");
6363 fprintf(fout, " {\n");
6364 }
6365
6366 if (pp->is_fptr && !pp->is_arg) {
6367 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6368 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6369 "(void *)", 0));
6370 if (pp->is_unresolved)
6371 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6372 buf3, asmfn, po->asmln, pp->name);
6373 }
6374
6375 fprintf(fout, "%s", buf3);
6376 if (strstr(pp->ret_type.name, "int64")) {
6377 if (po->flags & OPF_TAIL)
6378 ferr(po, "int64 and tail?\n");
6379 fprintf(fout, "tmp64 = ");
6380 }
6381 else if (!IS(pp->ret_type.name, "void")) {
6382 if (po->flags & OPF_TAIL) {
6383 if (regmask_ret & mxAX) {
6384 fprintf(fout, "return ");
6385 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6386 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6387 }
6388 else if (regmask_ret & mxST0)
6389 ferr(po, "float tailcall\n");
6390 }
6391 else if (po->regmask_dst & mxAX) {
6392 fprintf(fout, "eax = ");
6393 if (pp->ret_type.is_ptr)
6394 fprintf(fout, "(u32)");
6395 }
6396 else if (po->regmask_dst & mxST0) {
6397 ferr_assert(po, po->flags & OPF_FPUSH);
6398 if (need_float_stack)
6399 fprintf(fout, "f_st[--f_stp & 7] = ");
6400 else
6401 fprintf(fout, "f_st0 = ");
6402 }
6403 }
6404
6405 if (pp->name[0] == 0)
6406 ferr(po, "missing pp->name\n");
6407 fprintf(fout, "%s%s(", pp->name,
6408 pp->has_structarg ? "_sa" : "");
6409
6410 if (po->flags & OPF_ATAIL) {
6411 if (pp->argc_stack != g_func_pp->argc_stack
6412 || (pp->argc_stack > 0
6413 && pp->is_stdcall != g_func_pp->is_stdcall))
6414 ferr(po, "incompatible tailcall\n");
6415 if (g_func_pp->has_retreg)
6416 ferr(po, "TODO: retreg+tailcall\n");
6417
6418 for (arg = j = 0; arg < pp->argc; arg++) {
6419 if (arg > 0)
6420 fprintf(fout, ", ");
6421
6422 cast[0] = 0;
6423 if (pp->arg[arg].type.is_ptr)
6424 snprintf(cast, sizeof(cast), "(%s)",
6425 pp->arg[arg].type.name);
6426
6427 if (pp->arg[arg].reg != NULL) {
6428 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6429 continue;
6430 }
6431 // stack arg
6432 for (; j < g_func_pp->argc; j++)
6433 if (g_func_pp->arg[j].reg == NULL)
6434 break;
6435 fprintf(fout, "%sa%d", cast, j + 1);
6436 j++;
6437 }
6438 }
6439 else {
6440 for (arg = 0; arg < pp->argc; arg++) {
6441 if (arg > 0)
6442 fprintf(fout, ", ");
6443
6444 cast[0] = 0;
6445 if (pp->arg[arg].type.is_ptr)
6446 snprintf(cast, sizeof(cast), "(%s)",
6447 pp->arg[arg].type.name);
6448
6449 if (pp->arg[arg].reg != NULL) {
6450 if (pp->arg[arg].type.is_retreg)
6451 fprintf(fout, "&%s", pp->arg[arg].reg);
6452 else
6453 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6454 continue;
6455 }
6456
6457 // stack arg
6458 tmp_op = pp->arg[arg].datap;
6459 if (tmp_op == NULL)
6460 ferr(po, "parsed_op missing for arg%d\n", arg);
6461
6462 if (tmp_op->flags & OPF_VAPUSH) {
6463 fprintf(fout, "ap");
6464 }
6465 else if (tmp_op->p_argpass != 0) {
6466 fprintf(fout, "a%d", tmp_op->p_argpass);
6467 }
6468 else if (tmp_op->p_argnum != 0) {
6469 fprintf(fout, "%s%s", cast,
6470 saved_arg_name(buf1, sizeof(buf1),
6471 tmp_op->p_arggrp, tmp_op->p_argnum));
6472 }
6473 else {
6474 fprintf(fout, "%s",
6475 out_src_opr(buf1, sizeof(buf1),
6476 tmp_op, &tmp_op->operand[0], cast, 0));
6477 }
6478 }
6479 }
6480 fprintf(fout, ");");
6481
6482 if (strstr(pp->ret_type.name, "int64")) {
6483 fprintf(fout, "\n");
6484 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
6485 fprintf(fout, "%seax = tmp64;", buf3);
6486 }
6487
6488 if (pp->is_unresolved) {
6489 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
6490 pp->argc_reg);
6491 strcat(g_comment, buf2);
6492 }
6493
6494 if (po->flags & OPF_TAIL) {
6495 ret = 0;
6496 if (i == opcnt - 1 || pp->is_noreturn)
6497 ret = 0;
6498 else if (IS(pp->ret_type.name, "void"))
6499 ret = 1;
6500 else if (!(regmask_ret & (1 << xAX)))
6501 ret = 1;
6502 // else already handled as 'return f()'
6503
6504 if (ret) {
6505 fprintf(fout, "\n%sreturn;", buf3);
6506 strcat(g_comment, " ^ tailcall");
6507 }
6508 else
6509 strcat(g_comment, " tailcall");
6510
6511 if ((regmask_ret & (1 << xAX))
6512 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
6513 {
6514 ferr(po, "int func -> void func tailcall?\n");
6515 }
6516 }
6517 if (pp->is_noreturn)
6518 strcat(g_comment, " noreturn");
6519 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
6520 strcat(g_comment, " argframe");
6521 if (po->flags & OPF_CC)
6522 strcat(g_comment, " cond");
6523
6524 if (po->flags & OPF_CC)
6525 fprintf(fout, "\n }");
6526
6527 delayed_flag_op = NULL;
6528 last_arith_dst = NULL;
6529 break;
6530
6531 case OP_RET:
6532 if (g_func_pp->is_vararg)
6533 fprintf(fout, " va_end(ap);\n");
6534 if (g_func_pp->has_retreg) {
6535 for (arg = 0; arg < g_func_pp->argc; arg++)
6536 if (g_func_pp->arg[arg].type.is_retreg)
6537 fprintf(fout, " *r_%s = %s;\n",
6538 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
6539 }
6540
6541 if (!(regmask_ret & (1 << xAX))) {
6542 if (i != opcnt - 1 || label_pending)
6543 fprintf(fout, " return;");
6544 }
6545 else if (g_func_pp->ret_type.is_ptr) {
6546 fprintf(fout, " return (%s)eax;",
6547 g_func_pp->ret_type.name);
6548 }
6549 else if (IS(g_func_pp->ret_type.name, "__int64"))
6550 fprintf(fout, " return ((u64)edx << 32) | eax;");
6551 else
6552 fprintf(fout, " return eax;");
6553
6554 last_arith_dst = NULL;
6555 delayed_flag_op = NULL;
6556 break;
6557
6558 case OP_PUSH:
6559 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6560 if (po->p_argnum != 0) {
6561 // special case - saved func arg
6562 fprintf(fout, " %s = %s;",
6563 saved_arg_name(buf2, sizeof(buf2),
6564 po->p_arggrp, po->p_argnum), buf1);
6565 break;
6566 }
6567 else if (po->flags & OPF_RSAVE) {
6568 fprintf(fout, " s_%s = %s;", buf1, buf1);
6569 break;
6570 }
6571 else if (po->flags & OPF_PPUSH) {
6572 tmp_op = po->datap;
6573 ferr_assert(po, tmp_op != NULL);
6574 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
6575 fprintf(fout, " pp_%s = %s;", buf2, buf1);
6576 break;
6577 }
6578 else if (g_func_pp->is_userstack) {
6579 fprintf(fout, " *(--esp) = %s;", buf1);
6580 break;
6581 }
6582 if (!(g_ida_func_attr & IDAFA_NORETURN))
6583 ferr(po, "stray push encountered\n");
6584 no_output = 1;
6585 break;
6586
6587 case OP_POP:
6588 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6589 if (po->flags & OPF_RSAVE) {
6590 fprintf(fout, " %s = s_%s;", buf1, buf1);
6591 break;
6592 }
6593 else if (po->flags & OPF_PPUSH) {
6594 // push/pop graph / non-const
6595 ferr_assert(po, po->datap == NULL);
6596 fprintf(fout, " %s = pp_%s;", buf1, buf1);
6597 break;
6598 }
6599 else if (po->datap != NULL) {
6600 // push/pop pair
6601 tmp_op = po->datap;
6602 fprintf(fout, " %s = %s;", buf1,
6603 out_src_opr(buf2, sizeof(buf2),
6604 tmp_op, &tmp_op->operand[0],
6605 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6606 break;
6607 }
6608 else if (g_func_pp->is_userstack) {
6609 fprintf(fout, " %s = *esp++;", buf1);
6610 break;
6611 }
6612 else
6613 ferr(po, "stray pop encountered\n");
6614 break;
6615
6616 case OP_NOP:
6617 no_output = 1;
6618 break;
6619
6620 // x87
6621 case OP_FLD:
6622 if (need_float_stack) {
6623 out_src_opr_float(buf1, sizeof(buf1),
6624 po, &po->operand[0], 1);
6625 if (po->regmask_src & mxSTa) {
6626 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
6627 buf1);
6628 }
6629 else
6630 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
6631 }
6632 else {
6633 if (po->flags & OPF_FSHIFT)
6634 fprintf(fout, " f_st1 = f_st0;");
6635 if (po->operand[0].type == OPT_REG
6636 && po->operand[0].reg == xST0)
6637 {
6638 strcat(g_comment, " fld st");
6639 break;
6640 }
6641 fprintf(fout, " f_st0 = %s;",
6642 out_src_opr_float(buf1, sizeof(buf1),
6643 po, &po->operand[0], 0));
6644 }
6645 strcat(g_comment, " fld");
6646 break;
6647
6648 case OP_FILD:
6649 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6650 lmod_cast(po, po->operand[0].lmod, 1), 0);
6651 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
6652 if (need_float_stack) {
6653 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
6654 }
6655 else {
6656 if (po->flags & OPF_FSHIFT)
6657 fprintf(fout, " f_st1 = f_st0;");
6658 fprintf(fout, " f_st0 = %s;", buf2);
6659 }
6660 strcat(g_comment, " fild");
6661 break;
6662
6663 case OP_FLDc:
6664 if (need_float_stack)
6665 fprintf(fout, " f_st[--f_stp & 7] = ");
6666 else {
6667 if (po->flags & OPF_FSHIFT)
6668 fprintf(fout, " f_st1 = f_st0;");
6669 fprintf(fout, " f_st0 = ");
6670 }
6671 switch (po->operand[0].val) {
6672 case X87_CONST_1: fprintf(fout, "1.0;"); break;
6673 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
6674 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
6675 default: ferr(po, "TODO\n"); break;
6676 }
6677 break;
6678
6679 case OP_FST:
6680 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
6681 need_float_stack);
6682 dead_dst = po->operand[0].type == OPT_REG
6683 && po->operand[0].reg == xST0;
6684 if (need_float_stack) {
6685 if (!dead_dst)
6686 fprintf(fout, " %s = f_st[f_stp & 7];", buf1);
6687 if (po->flags & OPF_FSHIFT)
6688 fprintf(fout, " f_stp++;");
6689 }
6690 else {
6691 if (!dead_dst)
6692 fprintf(fout, " %s = f_st0;", buf1);
6693 if (po->flags & OPF_FSHIFT)
6694 fprintf(fout, " f_st0 = f_st1;");
6695 }
6696 if (dead_dst && !(po->flags & OPF_FSHIFT))
6697 no_output = 1;
6698 else
6699 strcat(g_comment, " fst");
6700 break;
6701
6702 case OP_FADD:
6703 case OP_FDIV:
6704 case OP_FMUL:
6705 case OP_FSUB:
6706 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
6707 need_float_stack);
6708 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
6709 need_float_stack);
6710 dead_dst = (po->flags & OPF_FPOP)
6711 && po->operand[0].type == OPT_REG
6712 && po->operand[0].reg == xST0;
6713 switch (po->op) {
6714 case OP_FADD: j = '+'; break;
6715 case OP_FDIV: j = '/'; break;
6716 case OP_FMUL: j = '*'; break;
6717 case OP_FSUB: j = '-'; break;
6718 default: j = 'x'; break;
6719 }
6720 if (need_float_stack) {
6721 if (!dead_dst)
6722 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
6723 if (po->flags & OPF_FSHIFT)
6724 fprintf(fout, " f_stp++;");
6725 }
6726 else {
6727 if (po->flags & OPF_FSHIFT) {
6728 // note: assumes only 2 regs handled
6729 if (!dead_dst)
6730 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
6731 else
6732 fprintf(fout, " f_st0 = f_st1;");
6733 }
6734 else if (!dead_dst)
6735 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
6736 }
6737 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
6738 break;
6739
6740 case OP_FDIVR:
6741 case OP_FSUBR:
6742 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
6743 need_float_stack);
6744 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
6745 need_float_stack);
6746 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
6747 need_float_stack);
6748 dead_dst = (po->flags & OPF_FPOP)
6749 && po->operand[0].type == OPT_REG
6750 && po->operand[0].reg == xST0;
6751 j = po->op == OP_FDIVR ? '/' : '-';
6752 if (need_float_stack) {
6753 if (!dead_dst)
6754 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
6755 if (po->flags & OPF_FSHIFT)
6756 fprintf(fout, " f_stp++;");
6757 }
6758 else {
6759 if (po->flags & OPF_FSHIFT) {
6760 if (!dead_dst)
6761 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
6762 else
6763 fprintf(fout, " f_st0 = f_st1;");
6764 }
6765 else if (!dead_dst)
6766 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
6767 }
6768 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
6769 break;
6770
6771 case OP_FIADD:
6772 case OP_FIDIV:
6773 case OP_FIMUL:
6774 case OP_FISUB:
6775 switch (po->op) {
6776 case OP_FIADD: j = '+'; break;
6777 case OP_FIDIV: j = '/'; break;
6778 case OP_FIMUL: j = '*'; break;
6779 case OP_FISUB: j = '-'; break;
6780 default: j = 'x'; break;
6781 }
6782 fprintf(fout, " %s %c= (%s)%s;", float_st0,
6783 j, float_type,
6784 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6785 lmod_cast(po, po->operand[0].lmod, 1), 0));
6786 break;
6787
6788 case OP_FIDIVR:
6789 case OP_FISUBR:
6790 fprintf(fout, " %s = %s %c %s;", float_st0,
6791 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
6792 need_float_stack),
6793 po->op == OP_FIDIVR ? '/' : '-', float_st0);
6794 break;
6795
6796 case OP_FCHS:
6797 fprintf(fout, " %s = -%s;", float_st0, float_st0);
6798 break;
6799
6800 case OP_FCOS:
6801 fprintf(fout, " %s = cos%s(%s);", float_st0,
6802 need_double ? "" : "f", float_st0);
6803 break;
6804
6805 case OP_FPATAN:
6806 if (need_float_stack) {
6807 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
6808 need_double ? "" : "f", float_st1, float_st0);
6809 fprintf(fout, " f_stp++;");
6810 }
6811 else {
6812 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
6813 need_double ? "" : "f");
6814 }
6815 break;
6816
6817 case OP_FYL2X:
6818 if (need_float_stack) {
6819 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
6820 float_st1, need_double ? "" : "f", float_st0);
6821 fprintf(fout, " f_stp++;");
6822 }
6823 else {
6824 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
6825 need_double ? "" : "f");
6826 }
6827 break;
6828
6829 case OP_FSIN:
6830 fprintf(fout, " %s = sin%s(%s);", float_st0,
6831 need_double ? "" : "f", float_st0);
6832 break;
6833
6834 case OP_FSQRT:
6835 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
6836 need_double ? "" : "f", float_st0);
6837 break;
6838
6839 case OP_FXCH:
6840 dead_dst = po->operand[0].type == OPT_REG
6841 && po->operand[0].reg == xST0;
6842 if (!dead_dst) {
6843 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
6844 need_float_stack);
6845 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
6846 float_st0, float_st0, buf1, buf1);
6847 strcat(g_comment, " fxch");
6848 }
6849 else
6850 no_output = 1;
6851 break;
6852
6853 case OPP_FTOL:
6854 ferr_assert(po, po->flags & OPF_32BIT);
6855 fprintf(fout, " eax = (s32)%s;", float_st0);
6856 if (po->flags & OPF_FSHIFT) {
6857 if (need_float_stack)
6858 fprintf(fout, " f_stp++;");
6859 else
6860 fprintf(fout, " f_st0 = f_st1;");
6861 }
6862 strcat(g_comment, " ftol");
6863 break;
6864
6865 // mmx
6866 case OP_EMMS:
6867 strcpy(g_comment, " (emms)");
6868 break;
6869
6870 default:
6871 no_output = 1;
6872 ferr(po, "unhandled op type %d, flags %x\n",
6873 po->op, po->flags);
6874 break;
6875 }
6876
6877 if (g_comment[0] != 0) {
6878 char *p = g_comment;
6879 while (my_isblank(*p))
6880 p++;
6881 fprintf(fout, " // %s", p);
6882 g_comment[0] = 0;
6883 no_output = 0;
6884 }
6885 if (!no_output)
6886 fprintf(fout, "\n");
6887
6888 // some sanity checking
6889 if (po->flags & OPF_REP) {
6890 if (po->op != OP_STOS && po->op != OP_MOVS
6891 && po->op != OP_CMPS && po->op != OP_SCAS)
6892 ferr(po, "unexpected rep\n");
6893 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
6894 && (po->op == OP_CMPS || po->op == OP_SCAS))
6895 ferr(po, "cmps/scas with plain rep\n");
6896 }
6897 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
6898 && po->op != OP_CMPS && po->op != OP_SCAS)
6899 ferr(po, "unexpected repz/repnz\n");
6900
6901 if (pfomask != 0)
6902 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
6903
6904 // see is delayed flag stuff is still valid
6905 if (delayed_flag_op != NULL && delayed_flag_op != po) {
6906 if (is_any_opr_modified(delayed_flag_op, po, 0))
6907 delayed_flag_op = NULL;
6908 }
6909
6910 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
6911 if (is_opr_modified(last_arith_dst, po))
6912 last_arith_dst = NULL;
6913 }
6914
6915 label_pending = 0;
6916 }
6917
6918 if (g_stack_fsz && !g_stack_frame_used)
6919 fprintf(fout, " (void)sf;\n");
6920
6921 fprintf(fout, "}\n\n");
6922
6923 gen_x_cleanup(opcnt);
6924}
6925
6926static void gen_x_cleanup(int opcnt)
6927{
6928 int i;
6929
6930 for (i = 0; i < opcnt; i++) {
6931 struct label_ref *lr, *lr_del;
6932
6933 lr = g_label_refs[i].next;
6934 while (lr != NULL) {
6935 lr_del = lr;
6936 lr = lr->next;
6937 free(lr_del);
6938 }
6939 g_label_refs[i].i = -1;
6940 g_label_refs[i].next = NULL;
6941
6942 if (ops[i].op == OP_CALL) {
6943 if (ops[i].pp)
6944 proto_release(ops[i].pp);
6945 }
6946 }
6947 g_func_pp = NULL;
6948}
6949
6950struct func_proto_dep;
6951
6952struct func_prototype {
6953 char name[NAMELEN];
6954 int id;
6955 int argc_stack;
6956 int regmask_dep;
6957 int has_ret:3; // -1, 0, 1: unresolved, no, yes
6958 unsigned int dep_resolved:1;
6959 unsigned int is_stdcall:1;
6960 struct func_proto_dep *dep_func;
6961 int dep_func_cnt;
6962 const struct parsed_proto *pp; // seed pp, if any
6963};
6964
6965struct func_proto_dep {
6966 char *name;
6967 struct func_prototype *proto;
6968 int regmask_live; // .. at the time of call
6969 unsigned int ret_dep:1; // return from this is caller's return
6970};
6971
6972static struct func_prototype *hg_fp;
6973static int hg_fp_cnt;
6974
6975static struct scanned_var {
6976 char name[NAMELEN];
6977 enum opr_lenmod lmod;
6978 unsigned int is_seeded:1;
6979 unsigned int is_c_str:1;
6980 const struct parsed_proto *pp; // seed pp, if any
6981} *hg_vars;
6982static int hg_var_cnt;
6983
6984static char **hg_refs;
6985static int hg_ref_cnt;
6986
6987static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
6988 int count);
6989
6990static struct func_prototype *hg_fp_add(const char *funcn)
6991{
6992 struct func_prototype *fp;
6993
6994 if ((hg_fp_cnt & 0xff) == 0) {
6995 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
6996 my_assert_not(hg_fp, NULL);
6997 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
6998 }
6999
7000 fp = &hg_fp[hg_fp_cnt];
7001 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7002 fp->id = hg_fp_cnt;
7003 fp->argc_stack = -1;
7004 hg_fp_cnt++;
7005
7006 return fp;
7007}
7008
7009static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7010 const char *name)
7011{
7012 int i;
7013
7014 for (i = 0; i < fp->dep_func_cnt; i++)
7015 if (IS(fp->dep_func[i].name, name))
7016 return &fp->dep_func[i];
7017
7018 return NULL;
7019}
7020
7021static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7022{
7023 // is it a dupe?
7024 if (hg_fp_find_dep(fp, name))
7025 return;
7026
7027 if ((fp->dep_func_cnt & 0xff) == 0) {
7028 fp->dep_func = realloc(fp->dep_func,
7029 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7030 my_assert_not(fp->dep_func, NULL);
7031 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7032 sizeof(fp->dep_func[0]) * 0x100);
7033 }
7034 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7035 fp->dep_func_cnt++;
7036}
7037
7038static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7039{
7040 const struct func_prototype *p1 = p1_, *p2 = p2_;
7041 return strcmp(p1->name, p2->name);
7042}
7043
7044#if 0
7045static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7046{
7047 const struct func_prototype *p1 = p1_, *p2 = p2_;
7048 return p1->id - p2->id;
7049}
7050#endif
7051
7052static void hg_ref_add(const char *name)
7053{
7054 if ((hg_ref_cnt & 0xff) == 0) {
7055 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7056 my_assert_not(hg_refs, NULL);
7057 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7058 }
7059
7060 hg_refs[hg_ref_cnt] = strdup(name);
7061 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7062 hg_ref_cnt++;
7063}
7064
7065// recursive register dep pass
7066// - track saved regs (part 2)
7067// - try to figure out arg-regs
7068// - calculate reg deps
7069static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
7070 struct func_prototype *fp, int regmask_save, int regmask_dst,
7071 int *regmask_dep, int *has_ret)
7072{
7073 struct func_proto_dep *dep;
7074 struct parsed_op *po;
7075 int from_caller = 0;
7076 int j, l;
7077 int reg;
7078 int ret;
7079
7080 for (; i < opcnt; i++)
7081 {
7082 if (cbits[i >> 3] & (1 << (i & 7)))
7083 return;
7084 cbits[i >> 3] |= (1 << (i & 7));
7085
7086 po = &ops[i];
7087
7088 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
7089 if (po->flags & OPF_RMD)
7090 continue;
7091
7092 if (po->btj != NULL) {
7093 // jumptable
7094 for (j = 0; j < po->btj->count; j++) {
7095 check_i(po, po->btj->d[j].bt_i);
7096 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
7097 regmask_save, regmask_dst, regmask_dep, has_ret);
7098 }
7099 return;
7100 }
7101
7102 check_i(po, po->bt_i);
7103 if (po->flags & OPF_CJMP) {
7104 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
7105 regmask_save, regmask_dst, regmask_dep, has_ret);
7106 }
7107 else {
7108 i = po->bt_i - 1;
7109 }
7110 continue;
7111 }
7112
7113 if (po->flags & OPF_FARG)
7114 /* (just calculate register deps) */;
7115 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
7116 {
7117 reg = po->operand[0].reg;
7118 ferr_assert(po, reg >= 0);
7119
7120 if (po->flags & OPF_RSAVE) {
7121 regmask_save |= 1 << reg;
7122 continue;
7123 }
7124 if (po->flags & OPF_DONE)
7125 continue;
7126
7127 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0);
7128 if (ret == 1) {
7129 regmask_save |= 1 << reg;
7130 po->flags |= OPF_RMD;
7131 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, OPF_RMD);
7132 continue;
7133 }
7134 }
7135 else if (po->flags & OPF_RMD)
7136 continue;
7137 else if (po->op == OP_CALL) {
7138 po->regmask_dst |= 1 << xAX;
7139
7140 dep = hg_fp_find_dep(fp, po->operand[0].name);
7141 if (dep != NULL)
7142 dep->regmask_live = regmask_save | regmask_dst;
7143 }
7144 else if (po->op == OP_RET) {
7145 if (po->operand_cnt > 0) {
7146 fp->is_stdcall = 1;
7147 if (fp->argc_stack >= 0
7148 && fp->argc_stack != po->operand[0].val / 4)
7149 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
7150 fp->argc_stack = po->operand[0].val / 4;
7151 }
7152 }
7153
7154 // if has_ret is 0, there is uninitialized eax path,
7155 // which means it's most likely void func
7156 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
7157 if (po->op == OP_CALL) {
7158 j = i;
7159 ret = 1;
7160 }
7161 else {
7162 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
7163 j = -1;
7164 from_caller = 0;
7165 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
7166 }
7167
7168 if (ret != 1 && from_caller) {
7169 // unresolved eax - probably void func
7170 *has_ret = 0;
7171 }
7172 else {
7173 if (j >= 0 && ops[j].op == OP_CALL) {
7174 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
7175 if (dep != NULL)
7176 dep->ret_dep = 1;
7177 else
7178 *has_ret = 1;
7179 }
7180 else
7181 *has_ret = 1;
7182 }
7183 }
7184
7185 l = regmask_save | regmask_dst;
7186 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7187 l |= 1 << xBP;
7188
7189 l = po->regmask_src & ~l;
7190#if 0
7191 if (l)
7192 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
7193 l, regmask_dst, regmask_save, po->flags);
7194#endif
7195 *regmask_dep |= l;
7196 regmask_dst |= po->regmask_dst;
7197
7198 if (po->flags & OPF_TAIL)
7199 return;
7200 }
7201}
7202
7203static void gen_hdr(const char *funcn, int opcnt)
7204{
7205 int save_arg_vars[MAX_ARG_GRP] = { 0, };
7206 unsigned char cbits[MAX_OPS / 8];
7207 const struct parsed_proto *pp_c;
7208 struct parsed_proto *pp;
7209 struct func_prototype *fp;
7210 struct parsed_op *po;
7211 int regmask_dummy = 0;
7212 int regmask_dep;
7213 int max_bp_offset = 0;
7214 int has_ret;
7215 int i, j, l;
7216 int ret;
7217
7218 pp_c = proto_parse(g_fhdr, funcn, 1);
7219 if (pp_c != NULL)
7220 // already in seed, will add to hg_fp later
7221 return;
7222
7223 fp = hg_fp_add(funcn);
7224
7225 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7226 g_stack_frame_used = 0;
7227
7228 // pass1:
7229 // - resolve all branches
7230 // - parse calls with labels
7231 resolve_branches_parse_calls(opcnt);
7232
7233 // pass2:
7234 // - handle ebp/esp frame, remove ops related to it
7235 scan_prologue_epilogue(opcnt);
7236
7237 // pass3:
7238 // - remove dead labels
7239 // - collect calls
7240 for (i = 0; i < opcnt; i++)
7241 {
7242 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7243 free(g_labels[i]);
7244 g_labels[i] = NULL;
7245 }
7246
7247 po = &ops[i];
7248 if (po->flags & (OPF_RMD|OPF_DONE))
7249 continue;
7250
7251 if (po->op == OP_CALL) {
7252 if (po->operand[0].type == OPT_LABEL)
7253 hg_fp_add_dep(fp, opr_name(po, 0));
7254 else if (po->pp != NULL)
7255 hg_fp_add_dep(fp, po->pp->name);
7256 }
7257 }
7258
7259 // pass4:
7260 // - remove dead labels
7261 // - handle push <const>/pop pairs
7262 for (i = 0; i < opcnt; i++)
7263 {
7264 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7265 free(g_labels[i]);
7266 g_labels[i] = NULL;
7267 }
7268
7269 po = &ops[i];
7270 if (po->flags & (OPF_RMD|OPF_DONE))
7271 continue;
7272
7273 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
7274 scan_for_pop_const(i, opcnt, i + opcnt * 13);
7275 }
7276
7277 // pass5:
7278 // - process trivial calls
7279 for (i = 0; i < opcnt; i++)
7280 {
7281 po = &ops[i];
7282 if (po->flags & (OPF_RMD|OPF_DONE))
7283 continue;
7284
7285 if (po->op == OP_CALL)
7286 {
7287 pp = process_call_early(i, opcnt, &j);
7288 if (pp != NULL) {
7289 if (!(po->flags & OPF_ATAIL))
7290 // since we know the args, try to collect them
7291 if (collect_call_args_early(po, i, pp, &regmask_dummy) != 0)
7292 pp = NULL;
7293 }
7294
7295 if (pp != NULL) {
7296 if (j >= 0) {
7297 // commit esp adjust
7298 if (ops[j].op != OP_POP)
7299 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
7300 else {
7301 for (l = 0; l < pp->argc_stack; l++)
7302 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
7303 }
7304 }
7305
7306 po->flags |= OPF_DONE;
7307 }
7308 }
7309 }
7310
7311 // pass6:
7312 // - track saved regs (simple)
7313 // - process calls
7314 for (i = 0; i < opcnt; i++)
7315 {
7316 po = &ops[i];
7317 if (po->flags & (OPF_RMD|OPF_DONE))
7318 continue;
7319
7320 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7321 && po->operand[0].reg != xCX)
7322 {
7323 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
7324 if (ret == 1) {
7325 // regmask_save |= 1 << po->operand[0].reg; // do it later
7326 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
7327 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
7328 }
7329 }
7330 else if (po->op == OP_CALL)
7331 {
7332 pp = process_call(i, opcnt);
7333
7334 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
7335 // since we know the args, collect them
7336 ret = collect_call_args(po, i, pp, &regmask_dummy, save_arg_vars,
7337 i + opcnt * 1);
7338 }
7339 }
7340 }
7341
7342 // pass7
7343 memset(cbits, 0, sizeof(cbits));
7344 regmask_dep = 0;
7345 has_ret = -1;
7346
7347 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, &regmask_dep, &has_ret);
7348
7349 // find unreachable code - must be fixed in IDA
7350 for (i = 0; i < opcnt; i++)
7351 {
7352 if (cbits[i >> 3] & (1 << (i & 7)))
7353 continue;
7354
7355 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
7356 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
7357 {
7358 // the compiler sometimes still generates code after
7359 // noreturn OS functions
7360 break;
7361 }
7362 if (ops[i].op != OP_NOP)
7363 ferr(&ops[i], "unreachable code\n");
7364 }
7365
7366 for (i = 0; i < g_eqcnt; i++) {
7367 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
7368 max_bp_offset = g_eqs[i].offset;
7369 }
7370
7371 if (fp->argc_stack < 0) {
7372 max_bp_offset = (max_bp_offset + 3) & ~3;
7373 fp->argc_stack = max_bp_offset / 4;
7374 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
7375 fp->argc_stack--;
7376 }
7377
7378 fp->regmask_dep = regmask_dep & ~(1 << xSP);
7379 fp->has_ret = has_ret;
7380#if 0
7381 printf("// has_ret %d, regmask_dep %x\n",
7382 fp->has_ret, fp->regmask_dep);
7383 output_hdr_fp(stdout, fp, 1);
7384 if (IS(funcn, "sub_10007F72")) exit(1);
7385#endif
7386
7387 gen_x_cleanup(opcnt);
7388}
7389
7390static void hg_fp_resolve_deps(struct func_prototype *fp)
7391{
7392 struct func_prototype fp_s;
7393 int dep;
7394 int i;
7395
7396 // this thing is recursive, so mark first..
7397 fp->dep_resolved = 1;
7398
7399 for (i = 0; i < fp->dep_func_cnt; i++) {
7400 strcpy(fp_s.name, fp->dep_func[i].name);
7401 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7402 sizeof(hg_fp[0]), hg_fp_cmp_name);
7403 if (fp->dep_func[i].proto != NULL) {
7404 if (!fp->dep_func[i].proto->dep_resolved)
7405 hg_fp_resolve_deps(fp->dep_func[i].proto);
7406
7407 dep = ~fp->dep_func[i].regmask_live
7408 & fp->dep_func[i].proto->regmask_dep;
7409 fp->regmask_dep |= dep;
7410 // printf("dep %s %s |= %x\n", fp->name,
7411 // fp->dep_func[i].name, dep);
7412
7413 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
7414 fp->has_ret = fp->dep_func[i].proto->has_ret;
7415 }
7416 }
7417}
7418
7419// make all thiscall/edx arg functions referenced from .data fastcall
7420static void do_func_refs_from_data(void)
7421{
7422 struct func_prototype *fp, fp_s;
7423 int i;
7424
7425 for (i = 0; i < hg_ref_cnt; i++) {
7426 strcpy(fp_s.name, hg_refs[i]);
7427 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7428 sizeof(hg_fp[0]), hg_fp_cmp_name);
7429 if (fp == NULL)
7430 continue;
7431
7432 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
7433 fp->regmask_dep |= mxCX | mxDX;
7434 }
7435}
7436
7437static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7438 int count)
7439{
7440 const struct parsed_proto *pp;
7441 char *p, namebuf[NAMELEN];
7442 const char *name;
7443 int regmask_dep;
7444 int argc_normal;
7445 int j, arg;
7446
7447 for (; count > 0; count--, fp++) {
7448 if (fp->has_ret == -1)
7449 fprintf(fout, "// ret unresolved\n");
7450#if 0
7451 fprintf(fout, "// dep:");
7452 for (j = 0; j < fp->dep_func_cnt; j++) {
7453 fprintf(fout, " %s/", fp->dep_func[j].name);
7454 if (fp->dep_func[j].proto != NULL)
7455 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
7456 fp->dep_func[j].proto->has_ret);
7457 }
7458 fprintf(fout, "\n");
7459#endif
7460
7461 p = strchr(fp->name, '@');
7462 if (p != NULL) {
7463 memcpy(namebuf, fp->name, p - fp->name);
7464 namebuf[p - fp->name] = 0;
7465 name = namebuf;
7466 }
7467 else
7468 name = fp->name;
7469 if (name[0] == '_')
7470 name++;
7471
7472 pp = proto_parse(g_fhdr, name, 1);
7473 if (pp != NULL && pp->is_include)
7474 continue;
7475
7476 if (fp->pp != NULL) {
7477 // part of seed, output later
7478 continue;
7479 }
7480
7481 regmask_dep = fp->regmask_dep;
7482 argc_normal = fp->argc_stack;
7483
7484 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
7485 (fp->has_ret ? "int" : "void"));
7486 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
7487 && (regmask_dep & ~mxCX) == 0)
7488 {
7489 fprintf(fout, "/*__thiscall*/ ");
7490 argc_normal++;
7491 regmask_dep = 0;
7492 }
7493 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
7494 && (regmask_dep & ~(mxCX | mxDX)) == 0)
7495 {
7496 fprintf(fout, " __fastcall ");
7497 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
7498 argc_normal = 1;
7499 else
7500 argc_normal += 2;
7501 regmask_dep = 0;
7502 }
7503 else if (regmask_dep && !fp->is_stdcall) {
7504 fprintf(fout, "/*__usercall*/ ");
7505 }
7506 else if (regmask_dep) {
7507 fprintf(fout, "/*__userpurge*/ ");
7508 }
7509 else if (fp->is_stdcall)
7510 fprintf(fout, " __stdcall ");
7511 else
7512 fprintf(fout, " __cdecl ");
7513
7514 fprintf(fout, "%s(", name);
7515
7516 arg = 0;
7517 for (j = 0; j < xSP; j++) {
7518 if (regmask_dep & (1 << j)) {
7519 arg++;
7520 if (arg != 1)
7521 fprintf(fout, ", ");
7522 if (fp->pp != NULL)
7523 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
7524 else
7525 fprintf(fout, "int");
7526 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
7527 }
7528 }
7529
7530 for (j = 0; j < argc_normal; j++) {
7531 arg++;
7532 if (arg != 1)
7533 fprintf(fout, ", ");
7534 if (fp->pp != NULL) {
7535 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
7536 if (!fp->pp->arg[arg - 1].type.is_ptr)
7537 fprintf(fout, " ");
7538 }
7539 else
7540 fprintf(fout, "int ");
7541 fprintf(fout, "a%d", arg);
7542 }
7543
7544 fprintf(fout, ");\n");
7545 }
7546}
7547
7548static void output_hdr(FILE *fout)
7549{
7550 static const char *lmod_c_names[] = {
7551 [OPLM_UNSPEC] = "???",
7552 [OPLM_BYTE] = "uint8_t",
7553 [OPLM_WORD] = "uint16_t",
7554 [OPLM_DWORD] = "uint32_t",
7555 [OPLM_QWORD] = "uint64_t",
7556 };
7557 const struct scanned_var *var;
7558 struct func_prototype *fp;
7559 char line[256] = { 0, };
7560 char name[256];
7561 int i;
7562
7563 // add stuff from headers
7564 for (i = 0; i < pp_cache_size; i++) {
7565 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
7566 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
7567 else
7568 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
7569 fp = hg_fp_add(name);
7570 fp->pp = &pp_cache[i];
7571 fp->argc_stack = fp->pp->argc_stack;
7572 fp->is_stdcall = fp->pp->is_stdcall;
7573 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
7574 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
7575 }
7576
7577 // resolve deps
7578 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
7579 for (i = 0; i < hg_fp_cnt; i++)
7580 hg_fp_resolve_deps(&hg_fp[i]);
7581
7582 // adjust functions referenced from data segment
7583 do_func_refs_from_data();
7584
7585 // note: messes up .proto ptr, don't use
7586 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
7587
7588 // output variables
7589 for (i = 0; i < hg_var_cnt; i++) {
7590 var = &hg_vars[i];
7591
7592 if (var->pp != NULL)
7593 // part of seed
7594 continue;
7595 else if (var->is_c_str)
7596 fprintf(fout, "extern %-8s %s[];", "char", var->name);
7597 else
7598 fprintf(fout, "extern %-8s %s;",
7599 lmod_c_names[var->lmod], var->name);
7600
7601 if (var->is_seeded)
7602 fprintf(fout, " // seeded");
7603 fprintf(fout, "\n");
7604 }
7605
7606 fprintf(fout, "\n");
7607
7608 // output function prototypes
7609 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
7610
7611 // seed passthrough
7612 fprintf(fout, "\n// - seed -\n");
7613
7614 rewind(g_fhdr);
7615 while (fgets(line, sizeof(line), g_fhdr))
7616 fwrite(line, 1, strlen(line), fout);
7617}
7618
7619// '=' needs special treatment
7620// also ' quote
7621static char *next_word_s(char *w, size_t wsize, char *s)
7622{
7623 size_t i;
7624
7625 s = sskip(s);
7626
7627 i = 0;
7628 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
7629 w[0] = s[0];
7630 for (i = 1; i < wsize - 1; i++) {
7631 if (s[i] == 0) {
7632 printf("warning: missing closing quote: \"%s\"\n", s);
7633 break;
7634 }
7635 if (s[i] == '\'')
7636 break;
7637 w[i] = s[i];
7638 }
7639 }
7640
7641 for (; i < wsize - 1; i++) {
7642 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
7643 break;
7644 w[i] = s[i];
7645 }
7646 w[i] = 0;
7647
7648 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
7649 printf("warning: '%s' truncated\n", w);
7650
7651 return s + i;
7652}
7653
7654static int cmpstringp(const void *p1, const void *p2)
7655{
7656 return strcmp(*(char * const *)p1, *(char * const *)p2);
7657}
7658
7659static int is_xref_needed(char *p, char **rlist, int rlist_len)
7660{
7661 char *p2;
7662
7663 p = sskip(p);
7664 if (strstr(p, "..."))
7665 // unable to determine, assume needed
7666 return 1;
7667
7668 if (*p == '.') // .text, .data, ...
7669 // ref from other data or non-function -> no
7670 return 0;
7671
7672 p2 = strpbrk(p, "+:\r\n\x18");
7673 if (p2 != NULL)
7674 *p2 = 0;
7675 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
7676 // referenced from removed code
7677 return 0;
7678
7679 return 1;
7680}
7681
7682static int ida_xrefs_show_need(FILE *fasm, char *p,
7683 char **rlist, int rlist_len)
7684{
7685 int found_need = 0;
7686 char line[256];
7687 long pos;
7688
7689 p = strrchr(p, ';');
7690 if (p != NULL && *p == ';' && IS_START(p + 2, "DATA XREF: ")) {
7691 p += 13;
7692 if (is_xref_needed(p, rlist, rlist_len))
7693 return 1;
7694 }
7695
7696 pos = ftell(fasm);
7697 while (1)
7698 {
7699 if (!my_fgets(line, sizeof(line), fasm))
7700 break;
7701 // non-first line is always indented
7702 if (!my_isblank(line[0]))
7703 break;
7704
7705 // should be no content, just comment
7706 p = sskip(line);
7707 if (*p != ';')
7708 break;
7709
7710 p = strrchr(p, ';');
7711 p += 2;
7712 // it's printed once, but no harm to check again
7713 if (IS_START(p, "DATA XREF: "))
7714 p += 11;
7715
7716 if (is_xref_needed(p, rlist, rlist_len)) {
7717 found_need = 1;
7718 break;
7719 }
7720 }
7721 fseek(fasm, pos, SEEK_SET);
7722 return found_need;
7723}
7724
7725static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
7726{
7727 struct scanned_var *var;
7728 char line[256] = { 0, };
7729 char words[4][256];
7730 int no_identifier;
7731 char *p = NULL;
7732 int wordc;
7733 int l;
7734
7735 while (!feof(fasm))
7736 {
7737 // skip to next data section
7738 while (my_fgets(line, sizeof(line), fasm))
7739 {
7740 asmln++;
7741
7742 p = sskip(line);
7743 if (*p == 0 || *p == ';')
7744 continue;
7745
7746 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
7747 if (*p == 0 || *p == ';')
7748 continue;
7749
7750 if (*p != 's' || !IS_START(p, "segment para public"))
7751 continue;
7752
7753 break;
7754 }
7755
7756 if (p == NULL || !IS_START(p, "segment para public"))
7757 break;
7758 p = sskip(p + 19);
7759
7760 if (!IS_START(p, "'DATA'"))
7761 continue;
7762
7763 // now process it
7764 while (my_fgets(line, sizeof(line), fasm))
7765 {
7766 asmln++;
7767
7768 p = line;
7769 no_identifier = my_isblank(*p);
7770
7771 p = sskip(p);
7772 if (*p == 0 || *p == ';')
7773 continue;
7774
7775 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7776 words[wordc][0] = 0;
7777 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7778 if (*p == 0 || *p == ';') {
7779 wordc++;
7780 break;
7781 }
7782 }
7783
7784 if (wordc == 2 && IS(words[1], "ends"))
7785 break;
7786 if (wordc < 2)
7787 continue;
7788
7789 if (no_identifier) {
7790 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
7791 hg_ref_add(words[2]);
7792 continue;
7793 }
7794
7795 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
7796 // when this starts, we don't need anything from this section
7797 break;
7798 }
7799
7800 // check refs comment(s)
7801 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
7802 continue;
7803
7804 if ((hg_var_cnt & 0xff) == 0) {
7805 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
7806 * (hg_var_cnt + 0x100));
7807 my_assert_not(hg_vars, NULL);
7808 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
7809 }
7810
7811 var = &hg_vars[hg_var_cnt++];
7812 snprintf(var->name, sizeof(var->name), "%s", words[0]);
7813
7814 // maybe already in seed header?
7815 var->pp = proto_parse(g_fhdr, var->name, 1);
7816 if (var->pp != NULL) {
7817 if (var->pp->is_fptr) {
7818 var->lmod = OPLM_DWORD;
7819 //var->is_ptr = 1;
7820 }
7821 else if (var->pp->is_func)
7822 aerr("func?\n");
7823 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
7824 aerr("unhandled C type '%s' for '%s'\n",
7825 var->pp->type.name, var->name);
7826
7827 var->is_seeded = 1;
7828 continue;
7829 }
7830
7831 if (IS(words[1], "dd")) {
7832 var->lmod = OPLM_DWORD;
7833 if (wordc >= 4 && IS(words[2], "offset"))
7834 hg_ref_add(words[3]);
7835 }
7836 else if (IS(words[1], "dw"))
7837 var->lmod = OPLM_WORD;
7838 else if (IS(words[1], "db")) {
7839 var->lmod = OPLM_BYTE;
7840 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
7841 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
7842 var->is_c_str = 1;
7843 }
7844 }
7845 else if (IS(words[1], "dq"))
7846 var->lmod = OPLM_QWORD;
7847 //else if (IS(words[1], "dt"))
7848 else
7849 aerr("type '%s' not known\n", words[1]);
7850 }
7851 }
7852
7853 rewind(fasm);
7854 asmln = 0;
7855}
7856
7857static void set_label(int i, const char *name)
7858{
7859 const char *p;
7860 int len;
7861
7862 len = strlen(name);
7863 p = strchr(name, ':');
7864 if (p != NULL)
7865 len = p - name;
7866
7867 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
7868 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
7869 g_labels[i] = realloc(g_labels[i], len + 1);
7870 my_assert_not(g_labels[i], NULL);
7871 memcpy(g_labels[i], name, len);
7872 g_labels[i][len] = 0;
7873}
7874
7875struct chunk_item {
7876 char *name;
7877 long fptr;
7878 int asmln;
7879};
7880
7881static struct chunk_item *func_chunks;
7882static int func_chunk_cnt;
7883static int func_chunk_alloc;
7884
7885static void add_func_chunk(FILE *fasm, const char *name, int line)
7886{
7887 if (func_chunk_cnt >= func_chunk_alloc) {
7888 func_chunk_alloc *= 2;
7889 func_chunks = realloc(func_chunks,
7890 func_chunk_alloc * sizeof(func_chunks[0]));
7891 my_assert_not(func_chunks, NULL);
7892 }
7893 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
7894 func_chunks[func_chunk_cnt].name = strdup(name);
7895 func_chunks[func_chunk_cnt].asmln = line;
7896 func_chunk_cnt++;
7897}
7898
7899static int cmp_chunks(const void *p1, const void *p2)
7900{
7901 const struct chunk_item *c1 = p1, *c2 = p2;
7902 return strcmp(c1->name, c2->name);
7903}
7904
7905static void scan_ahead(FILE *fasm)
7906{
7907 char words[2][256];
7908 char line[256];
7909 long oldpos;
7910 int oldasmln;
7911 int wordc;
7912 char *p;
7913 int i;
7914
7915 oldpos = ftell(fasm);
7916 oldasmln = asmln;
7917
7918 while (my_fgets(line, sizeof(line), fasm))
7919 {
7920 wordc = 0;
7921 asmln++;
7922
7923 p = sskip(line);
7924 if (*p == 0)
7925 continue;
7926
7927 if (*p == ';')
7928 {
7929 // get rid of random tabs
7930 for (i = 0; line[i] != 0; i++)
7931 if (line[i] == '\t')
7932 line[i] = ' ';
7933
7934 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
7935 {
7936 p += 30;
7937 next_word(words[0], sizeof(words[0]), p);
7938 if (words[0][0] == 0)
7939 aerr("missing name for func chunk?\n");
7940
7941 add_func_chunk(fasm, words[0], asmln);
7942 }
7943 else if (IS_START(p, "; sctend"))
7944 break;
7945
7946 continue;
7947 } // *p == ';'
7948
7949 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7950 words[wordc][0] = 0;
7951 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7952 if (*p == 0 || *p == ';') {
7953 wordc++;
7954 break;
7955 }
7956 }
7957
7958 if (wordc == 2 && IS(words[1], "ends"))
7959 break;
7960 }
7961
7962 fseek(fasm, oldpos, SEEK_SET);
7963 asmln = oldasmln;
7964}
7965
7966int main(int argc, char *argv[])
7967{
7968 FILE *fout, *fasm, *frlist;
7969 struct parsed_data *pd = NULL;
7970 int pd_alloc = 0;
7971 char **rlist = NULL;
7972 int rlist_len = 0;
7973 int rlist_alloc = 0;
7974 int func_chunks_used = 0;
7975 int func_chunks_sorted = 0;
7976 int func_chunk_i = -1;
7977 long func_chunk_ret = 0;
7978 int func_chunk_ret_ln = 0;
7979 int scanned_ahead = 0;
7980 char line[256];
7981 char words[20][256];
7982 enum opr_lenmod lmod;
7983 char *sctproto = NULL;
7984 int in_func = 0;
7985 int pending_endp = 0;
7986 int skip_func = 0;
7987 int skip_warned = 0;
7988 int eq_alloc;
7989 int verbose = 0;
7990 int multi_seg = 0;
7991 int end = 0;
7992 int arg_out;
7993 int arg;
7994 int pi = 0;
7995 int i, j;
7996 int ret, len;
7997 char *p;
7998 int wordc;
7999
8000 for (arg = 1; arg < argc; arg++) {
8001 if (IS(argv[arg], "-v"))
8002 verbose = 1;
8003 else if (IS(argv[arg], "-rf"))
8004 g_allow_regfunc = 1;
8005 else if (IS(argv[arg], "-m"))
8006 multi_seg = 1;
8007 else if (IS(argv[arg], "-hdr"))
8008 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8009 else
8010 break;
8011 }
8012
8013 if (argc < arg + 3) {
8014 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8015 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8016 "options:\n"
8017 " -hdr - header generation mode\n"
8018 " -rf - allow unannotated indirect calls\n"
8019 " -m - allow multiple .text sections\n"
8020 "[rlist] is a file with function names to skip,"
8021 " one per line\n",
8022 argv[0], argv[0]);
8023 return 1;
8024 }
8025
8026 arg_out = arg++;
8027
8028 asmfn = argv[arg++];
8029 fasm = fopen(asmfn, "r");
8030 my_assert_not(fasm, NULL);
8031
8032 hdrfn = argv[arg++];
8033 g_fhdr = fopen(hdrfn, "r");
8034 my_assert_not(g_fhdr, NULL);
8035
8036 rlist_alloc = 64;
8037 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8038 my_assert_not(rlist, NULL);
8039 // needs special handling..
8040 rlist[rlist_len++] = "__alloca_probe";
8041
8042 func_chunk_alloc = 32;
8043 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8044 my_assert_not(func_chunks, NULL);
8045
8046 memset(words, 0, sizeof(words));
8047
8048 for (; arg < argc; arg++) {
8049 frlist = fopen(argv[arg], "r");
8050 my_assert_not(frlist, NULL);
8051
8052 while (my_fgets(line, sizeof(line), frlist)) {
8053 p = sskip(line);
8054 if (*p == 0 || *p == ';')
8055 continue;
8056 if (*p == '#') {
8057 if (IS_START(p, "#if 0")
8058 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
8059 {
8060 skip_func = 1;
8061 }
8062 else if (IS_START(p, "#endif"))
8063 skip_func = 0;
8064 continue;
8065 }
8066 if (skip_func)
8067 continue;
8068
8069 p = next_word(words[0], sizeof(words[0]), p);
8070 if (words[0][0] == 0)
8071 continue;
8072
8073 if (rlist_len >= rlist_alloc) {
8074 rlist_alloc = rlist_alloc * 2 + 64;
8075 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
8076 my_assert_not(rlist, NULL);
8077 }
8078 rlist[rlist_len++] = strdup(words[0]);
8079 }
8080 skip_func = 0;
8081
8082 fclose(frlist);
8083 frlist = NULL;
8084 }
8085
8086 if (rlist_len > 0)
8087 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
8088
8089 fout = fopen(argv[arg_out], "w");
8090 my_assert_not(fout, NULL);
8091
8092 eq_alloc = 128;
8093 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
8094 my_assert_not(g_eqs, NULL);
8095
8096 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
8097 g_label_refs[i].i = -1;
8098 g_label_refs[i].next = NULL;
8099 }
8100
8101 if (g_header_mode)
8102 scan_variables(fasm, rlist, rlist_len);
8103
8104 while (my_fgets(line, sizeof(line), fasm))
8105 {
8106 wordc = 0;
8107 asmln++;
8108
8109 p = sskip(line);
8110 if (*p == 0)
8111 continue;
8112
8113 // get rid of random tabs
8114 for (i = 0; line[i] != 0; i++)
8115 if (line[i] == '\t')
8116 line[i] = ' ';
8117
8118 if (*p == ';')
8119 {
8120 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
8121 goto do_pending_endp; // eww..
8122
8123 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
8124 {
8125 static const char *attrs[] = {
8126 "bp-based frame",
8127 "library function",
8128 "static",
8129 "noreturn",
8130 "thunk",
8131 "fpd=",
8132 };
8133
8134 // parse IDA's attribute-list comment
8135 g_ida_func_attr = 0;
8136 p = sskip(p + 13);
8137
8138 for (; *p != 0; p = sskip(p)) {
8139 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8140 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8141 g_ida_func_attr |= 1 << i;
8142 p += strlen(attrs[i]);
8143 break;
8144 }
8145 }
8146 if (i == ARRAY_SIZE(attrs)) {
8147 anote("unparsed IDA attr: %s\n", p);
8148 break;
8149 }
8150 if (IS(attrs[i], "fpd=")) {
8151 p = next_word(words[0], sizeof(words[0]), p);
8152 // ignore for now..
8153 }
8154 }
8155 }
8156 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
8157 {
8158 static const char *attrs[] = {
8159 "clear_sf",
8160 "clear_regmask",
8161 };
8162
8163 // parse manual attribute-list comment
8164 g_sct_func_attr = 0;
8165 p = sskip(p + 10);
8166
8167 for (; *p != 0; p = sskip(p)) {
8168 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8169 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8170 g_sct_func_attr |= 1 << i;
8171 p += strlen(attrs[i]);
8172 break;
8173 }
8174 }
8175 if (*p == '=') {
8176 j = ret = 0;
8177 if (i == 0)
8178 // clear_sf=start,len (in dwords)
8179 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
8180 &g_stack_clear_len, &j);
8181 else if (i == 1)
8182 // clear_regmask=<mask>
8183 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
8184 if (ret < 2) {
8185 anote("unparsed attr value: %s\n", p);
8186 break;
8187 }
8188 p += j;
8189 }
8190 else if (i == ARRAY_SIZE(attrs)) {
8191 anote("unparsed sct attr: %s\n", p);
8192 break;
8193 }
8194 }
8195 }
8196 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8197 {
8198 p += 30;
8199 next_word(words[0], sizeof(words[0]), p);
8200 if (words[0][0] == 0)
8201 aerr("missing name for func chunk?\n");
8202
8203 if (!scanned_ahead) {
8204 add_func_chunk(fasm, words[0], asmln);
8205 func_chunks_sorted = 0;
8206 }
8207 }
8208 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
8209 {
8210 if (func_chunk_i >= 0) {
8211 if (func_chunk_i < func_chunk_cnt
8212 && IS(func_chunks[func_chunk_i].name, g_func))
8213 {
8214 // move on to next chunk
8215 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8216 if (ret)
8217 aerr("seek failed for '%s' chunk #%d\n",
8218 g_func, func_chunk_i);
8219 asmln = func_chunks[func_chunk_i].asmln;
8220 func_chunk_i++;
8221 }
8222 else {
8223 if (func_chunk_ret == 0)
8224 aerr("no return from chunk?\n");
8225 fseek(fasm, func_chunk_ret, SEEK_SET);
8226 asmln = func_chunk_ret_ln;
8227 func_chunk_ret = 0;
8228 pending_endp = 1;
8229 }
8230 }
8231 }
8232 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
8233 func_chunks_used = 1;
8234 p += 20;
8235 if (IS_START(g_func, "sub_")) {
8236 unsigned long addr = strtoul(p, NULL, 16);
8237 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
8238 if (addr > f_addr && !scanned_ahead) {
8239 //anote("scan_ahead caused by '%s', addr %lx\n",
8240 // g_func, addr);
8241 scan_ahead(fasm);
8242 scanned_ahead = 1;
8243 func_chunks_sorted = 0;
8244 }
8245 }
8246 }
8247 continue;
8248 } // *p == ';'
8249
8250parse_words:
8251 for (i = wordc; i < ARRAY_SIZE(words); i++)
8252 words[i][0] = 0;
8253 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8254 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8255 if (*p == 0 || *p == ';') {
8256 wordc++;
8257 break;
8258 }
8259 }
8260 if (*p != 0 && *p != ';')
8261 aerr("too many words\n");
8262
8263 // alow asm patches in comments
8264 if (*p == ';') {
8265 if (IS_START(p, "; sctpatch:")) {
8266 p = sskip(p + 11);
8267 if (*p == 0 || *p == ';')
8268 continue;
8269 goto parse_words; // lame
8270 }
8271 if (IS_START(p, "; sctproto:")) {
8272 sctproto = strdup(p + 11);
8273 }
8274 else if (IS_START(p, "; sctend")) {
8275 end = 1;
8276 if (!pending_endp)
8277 break;
8278 }
8279 }
8280
8281 if (wordc == 0) {
8282 // shouldn't happen
8283 awarn("wordc == 0?\n");
8284 continue;
8285 }
8286
8287 // don't care about this:
8288 if (words[0][0] == '.'
8289 || IS(words[0], "include")
8290 || IS(words[0], "assume") || IS(words[1], "segment")
8291 || IS(words[0], "align"))
8292 {
8293 continue;
8294 }
8295
8296do_pending_endp:
8297 // do delayed endp processing to collect switch jumptables
8298 if (pending_endp) {
8299 if (in_func && !g_skip_func && !end && wordc >= 2
8300 && ((words[0][0] == 'd' && words[0][2] == 0)
8301 || (words[1][0] == 'd' && words[1][2] == 0)))
8302 {
8303 i = 1;
8304 if (words[1][0] == 'd' && words[1][2] == 0) {
8305 // label
8306 if (g_func_pd_cnt >= pd_alloc) {
8307 pd_alloc = pd_alloc * 2 + 16;
8308 g_func_pd = realloc(g_func_pd,
8309 sizeof(g_func_pd[0]) * pd_alloc);
8310 my_assert_not(g_func_pd, NULL);
8311 }
8312 pd = &g_func_pd[g_func_pd_cnt];
8313 g_func_pd_cnt++;
8314 memset(pd, 0, sizeof(*pd));
8315 strcpy(pd->label, words[0]);
8316 pd->type = OPT_CONST;
8317 pd->lmod = lmod_from_directive(words[1]);
8318 i = 2;
8319 }
8320 else {
8321 if (pd == NULL) {
8322 if (verbose)
8323 anote("skipping alignment byte?\n");
8324 continue;
8325 }
8326 lmod = lmod_from_directive(words[0]);
8327 if (lmod != pd->lmod)
8328 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
8329 }
8330
8331 if (pd->count_alloc < pd->count + wordc) {
8332 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
8333 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
8334 my_assert_not(pd->d, NULL);
8335 }
8336 for (; i < wordc; i++) {
8337 if (IS(words[i], "offset")) {
8338 pd->type = OPT_OFFSET;
8339 i++;
8340 }
8341 p = strchr(words[i], ',');
8342 if (p != NULL)
8343 *p = 0;
8344 if (pd->type == OPT_OFFSET)
8345 pd->d[pd->count].u.label = strdup(words[i]);
8346 else
8347 pd->d[pd->count].u.val = parse_number(words[i]);
8348 pd->d[pd->count].bt_i = -1;
8349 pd->count++;
8350 }
8351 continue;
8352 }
8353
8354 if (in_func && !g_skip_func) {
8355 if (g_header_mode)
8356 gen_hdr(g_func, pi);
8357 else
8358 gen_func(fout, g_fhdr, g_func, pi);
8359 }
8360
8361 pending_endp = 0;
8362 in_func = 0;
8363 g_ida_func_attr = 0;
8364 g_sct_func_attr = 0;
8365 g_stack_clear_start = 0;
8366 g_stack_clear_len = 0;
8367 g_regmask_init = 0;
8368 skip_warned = 0;
8369 g_skip_func = 0;
8370 g_func[0] = 0;
8371 func_chunks_used = 0;
8372 func_chunk_i = -1;
8373 if (pi != 0) {
8374 memset(&ops, 0, pi * sizeof(ops[0]));
8375 clear_labels(pi);
8376 pi = 0;
8377 }
8378 g_eqcnt = 0;
8379 for (i = 0; i < g_func_pd_cnt; i++) {
8380 pd = &g_func_pd[i];
8381 if (pd->type == OPT_OFFSET) {
8382 for (j = 0; j < pd->count; j++)
8383 free(pd->d[j].u.label);
8384 }
8385 free(pd->d);
8386 pd->d = NULL;
8387 }
8388 g_func_pd_cnt = 0;
8389 g_func_lmods = 0;
8390 pd = NULL;
8391
8392 if (end)
8393 break;
8394 if (wordc == 0)
8395 continue;
8396 }
8397
8398 if (IS(words[1], "proc")) {
8399 if (in_func)
8400 aerr("proc '%s' while in_func '%s'?\n",
8401 words[0], g_func);
8402 p = words[0];
8403 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8404 g_skip_func = 1;
8405 strcpy(g_func, words[0]);
8406 set_label(0, words[0]);
8407 in_func = 1;
8408 continue;
8409 }
8410
8411 if (IS(words[1], "endp"))
8412 {
8413 if (!in_func)
8414 aerr("endp '%s' while not in_func?\n", words[0]);
8415 if (!IS(g_func, words[0]))
8416 aerr("endp '%s' while in_func '%s'?\n",
8417 words[0], g_func);
8418
8419 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
8420 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
8421 {
8422 // import jump
8423 g_skip_func = 1;
8424 }
8425
8426 if (!g_skip_func && func_chunks_used) {
8427 // start processing chunks
8428 struct chunk_item *ci, key = { g_func, 0 };
8429
8430 func_chunk_ret = ftell(fasm);
8431 func_chunk_ret_ln = asmln;
8432 if (!func_chunks_sorted) {
8433 qsort(func_chunks, func_chunk_cnt,
8434 sizeof(func_chunks[0]), cmp_chunks);
8435 func_chunks_sorted = 1;
8436 }
8437 ci = bsearch(&key, func_chunks, func_chunk_cnt,
8438 sizeof(func_chunks[0]), cmp_chunks);
8439 if (ci == NULL)
8440 aerr("'%s' needs chunks, but none found\n", g_func);
8441 func_chunk_i = ci - func_chunks;
8442 for (; func_chunk_i > 0; func_chunk_i--)
8443 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
8444 break;
8445
8446 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8447 if (ret)
8448 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
8449 asmln = func_chunks[func_chunk_i].asmln;
8450 func_chunk_i++;
8451 continue;
8452 }
8453 pending_endp = 1;
8454 continue;
8455 }
8456
8457 if (wordc == 2 && IS(words[1], "ends")) {
8458 if (!multi_seg) {
8459 end = 1;
8460 if (pending_endp)
8461 goto do_pending_endp;
8462 break;
8463 }
8464
8465 // scan for next text segment
8466 while (my_fgets(line, sizeof(line), fasm)) {
8467 asmln++;
8468 p = sskip(line);
8469 if (*p == 0 || *p == ';')
8470 continue;
8471
8472 if (strstr(p, "segment para public 'CODE' use32"))
8473 break;
8474 }
8475
8476 continue;
8477 }
8478
8479 p = strchr(words[0], ':');
8480 if (p != NULL) {
8481 set_label(pi, words[0]);
8482 continue;
8483 }
8484
8485 if (!in_func || g_skip_func) {
8486 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
8487 if (verbose)
8488 anote("skipping from '%s'\n", g_labels[pi]);
8489 skip_warned = 1;
8490 }
8491 free(g_labels[pi]);
8492 g_labels[pi] = NULL;
8493 continue;
8494 }
8495
8496 if (wordc > 1 && IS(words[1], "="))
8497 {
8498 if (wordc != 5)
8499 aerr("unhandled equ, wc=%d\n", wordc);
8500 if (g_eqcnt >= eq_alloc) {
8501 eq_alloc *= 2;
8502 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
8503 my_assert_not(g_eqs, NULL);
8504 }
8505
8506 len = strlen(words[0]);
8507 if (len > sizeof(g_eqs[0].name) - 1)
8508 aerr("equ name too long: %d\n", len);
8509 strcpy(g_eqs[g_eqcnt].name, words[0]);
8510
8511 if (!IS(words[3], "ptr"))
8512 aerr("unhandled equ\n");
8513 if (IS(words[2], "dword"))
8514 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
8515 else if (IS(words[2], "word"))
8516 g_eqs[g_eqcnt].lmod = OPLM_WORD;
8517 else if (IS(words[2], "byte"))
8518 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
8519 else if (IS(words[2], "qword"))
8520 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
8521 else
8522 aerr("bad lmod: '%s'\n", words[2]);
8523
8524 g_eqs[g_eqcnt].offset = parse_number(words[4]);
8525 g_eqcnt++;
8526 continue;
8527 }
8528
8529 if (pi >= ARRAY_SIZE(ops))
8530 aerr("too many ops\n");
8531
8532 parse_op(&ops[pi], words, wordc);
8533
8534 ops[pi].datap = sctproto;
8535 sctproto = NULL;
8536 pi++;
8537 }
8538
8539 if (g_header_mode)
8540 output_hdr(fout);
8541
8542 fclose(fout);
8543 fclose(fasm);
8544 fclose(g_fhdr);
8545
8546 return 0;
8547}
8548
8549// vim:ts=2:shiftwidth=2:expandtab