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