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