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