various additions
[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 break;
3948 }
3949 add_label_ref(&g_label_refs[l], i);
3950 po->bt_i = l;
3951 break;
3952 }
3953 }
3954
3955 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3956 continue;
3957
3958 if (po->operand[0].type == OPT_LABEL)
3959 // assume tail call
3960 goto tailcall;
3961
3962 ferr(po, "unhandled branch\n");
3963
3964tailcall:
3965 po->op = OP_CALL;
3966 po->flags |= OPF_TAIL;
3967 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3968 if (prev_op == OP_POP)
3969 po->flags |= OPF_ATAIL;
3970 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3971 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3972 {
3973 po->flags |= OPF_ATAIL;
3974 }
3975 i--; // reprocess
3976 }
3977}
3978
3979static int resolve_origin(int i, const struct parsed_opr *opr,
3980 int magic, int *op_i, int *is_caller);
3981static void set_label(int i, const char *name);
3982
3983static void eliminate_seh_writes(int opcnt)
3984{
3985 const struct parsed_opr *opr;
3986 char ofs_reg[16];
3987 int offset;
3988 int i;
3989
3990 // assume all sf writes above g_seh_size to be seh related
3991 // (probably unsafe but oh well)
3992 for (i = 0; i < opcnt; i++) {
3993 if (ops[i].op != OP_MOV)
3994 continue;
3995 opr = &ops[i].operand[0];
3996 if (opr->type != OPT_REGMEM)
3997 continue;
3998 if (!is_stack_access(&ops[i], opr))
3999 continue;
4000
4001 offset = 0;
4002 parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
4003 NULL, NULL, 0);
4004 if (offset < 0 && offset >= -g_seh_size)
4005 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4006 }
4007}
4008
4009static void eliminate_seh_finally(int opcnt)
4010{
4011 const char *target_name = NULL;
4012 const char *return_name = NULL;
4013 int exits[MAX_EXITS];
4014 int exit_count = 0;
4015 int call_i = -1;
4016 int target_i = -1;
4017 int return_i = -1;
4018 int tgend_i = -1;
4019 int i;
4020
4021 for (i = 0; i < opcnt; i++) {
4022 if (ops[i].op != OP_CALL)
4023 continue;
4024 if (!IS_START(opr_name(&ops[i], 0), "loc_"))
4025 continue;
4026 if (target_name != NULL)
4027 ferr(&ops[i], "multiple finally calls? (last was %s)\n",
4028 target_name);
4029 target_name = opr_name(&ops[i], 0);
4030 call_i = i;
4031
4032 if (g_labels[i + 1] == NULL)
4033 set_label(i + 1, "seh_fin_done");
4034 return_name = g_labels[i + 1];
4035 return_i = i + 1;
4036 }
4037
4038 if (call_i == -1)
4039 // no finally block
4040 return;
4041
4042 // find finally code (bt_i is not set because it's call)
4043 for (i = 0; i < opcnt; i++) {
4044 if (g_labels[i] == NULL)
4045 continue;
4046 if (!IS(g_labels[i], target_name))
4047 continue;
4048
4049 ferr_assert(&ops[i], target_i == -1);
4050 target_i = i;
4051 }
4052 ferr_assert(&ops[0], target_i != -1);
4053
4054 find_reachable_exits(target_i, opcnt, target_i + opcnt * 24,
4055 exits, &exit_count);
4056 ferr_assert(&ops[target_i], exit_count == 1);
4057 ferr_assert(&ops[target_i], ops[exits[0]].op == OP_RET);
4058 tgend_i = exits[0];
4059
4060 // convert to jumps, link
4061 ops[call_i].op = OP_JMP;
4062 ops[call_i].bt_i = target_i;
4063 add_label_ref(&g_label_refs[target_i], call_i);
4064
4065 ops[tgend_i].op = OP_JMP;
4066 ops[tgend_i].flags &= ~OPF_TAIL;
4067 ops[tgend_i].flags |= OPF_JMP;
4068 ops[tgend_i].bt_i = return_i;
4069 ops[tgend_i].operand_cnt = 1;
4070 ops[tgend_i].operand[0].type = OPT_LABEL;
4071 snprintf(ops[tgend_i].operand[0].name, NAMELEN, "%s", return_name);
4072 add_label_ref(&g_label_refs[return_i], tgend_i);
4073
4074 // rm seh finally entry code
4075 for (i = target_i - 1; i >= 0; i--) {
4076 if (g_labels[i] != NULL && g_label_refs[i].i != -1)
4077 return;
4078 if (ops[i].flags & OPF_CJMP)
4079 return;
4080 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4081 break;
4082 }
4083 for (i = target_i - 1; i >= 0; i--) {
4084 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4085 break;
4086 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4087 }
4088}
4089
4090static void eliminate_seh(int opcnt)
4091{
4092 int i, j, k, ret;
4093
4094 for (i = 0; i < opcnt; i++) {
4095 if (ops[i].op != OP_MOV)
4096 continue;
4097 if (ops[i].operand[0].segment != SEG_FS)
4098 continue;
4099 if (!IS(opr_name(&ops[i], 0), "0"))
4100 continue;
4101
4102 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4103 if (ops[i].operand[1].reg == xSP) {
4104 for (j = i - 1; j >= 0; j--) {
4105 if (ops[j].op != OP_PUSH)
4106 continue;
4107 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4108 g_seh_size += 4;
4109 if (ops[j].operand[0].val == ~0)
4110 break;
4111 if (ops[j].operand[0].type == OPT_REG) {
4112 k = -1;
4113 ret = resolve_origin(j, &ops[j].operand[0],
4114 j + opcnt * 22, &k, NULL);
4115 if (ret == 1)
4116 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4117 }
4118 }
4119 if (j < 0)
4120 ferr(ops, "missing seh terminator\n");
4121 }
4122 else {
4123 k = -1;
4124 ret = resolve_origin(i, &ops[i].operand[1],
4125 i + opcnt * 23, &k, NULL);
4126 if (ret == 1)
4127 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4128 }
4129 }
4130
4131 eliminate_seh_writes(opcnt);
4132 eliminate_seh_finally(opcnt);
4133}
4134
4135static void eliminate_seh_calls(int opcnt)
4136{
4137 int epilog_found = 0;
4138 int i;
4139
4140 g_bp_frame = 1;
4141 g_seh_size = 0x10;
4142
4143 i = 0;
4144 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4145 && ops[i].operand[0].type == OPT_CONST);
4146 g_stack_fsz = g_seh_size + ops[i].operand[0].val;
4147 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4148
4149 i++;
4150 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4151 && ops[i].operand[0].type == OPT_OFFSET);
4152 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4153
4154 i++;
4155 ferr_assert(&ops[i], ops[i].op == OP_CALL
4156 && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
4157 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4158
4159 for (i++; i < opcnt; i++) {
4160 if (ops[i].op != OP_CALL)
4161 continue;
4162 if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
4163 continue;
4164
4165 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4166 epilog_found = 1;
4167 }
4168 ferr_assert(ops, epilog_found);
4169
4170 eliminate_seh_writes(opcnt);
4171 eliminate_seh_finally(opcnt);
4172}
4173
4174// check for prologue of many pushes and epilogue with pops
4175static void check_simple_sequence(int opcnt, int *fsz)
4176{
4177 int found = 0;
4178 int seq_len;
4179 int seq_p;
4180 int seq[4];
4181 int reg;
4182 int i, j;
4183
4184 for (i = 0; i < opcnt && i < ARRAY_SIZE(seq); i++) {
4185 if (ops[i].op != OP_PUSH || ops[i].operand[0].type != OPT_REG)
4186 break;
4187 reg = ops[i].operand[0].reg;
4188 if (reg != xBX && reg != xSI && reg != xDI && reg != xBP)
4189 break;
4190 for (j = 0; j < i; j++)
4191 if (seq[j] == reg)
4192 break;
4193 if (j != i)
4194 // probably something else is going on here
4195 break;
4196 seq[i] = reg;
4197 }
4198 seq_len = i;
4199 if (seq_len == 0)
4200 return;
4201
4202 for (; i < opcnt && seq_len > 0; i++) {
4203 if (!(ops[i].flags & OPF_TAIL))
4204 continue;
4205
4206 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4207 if (ops[j].op != OP_POP || ops[j].operand[0].type != OPT_REG)
4208 break;
4209 if (ops[j].operand[0].reg != seq[seq_p])
4210 break;
4211 seq_p++;
4212 }
4213 found = seq_len = seq_p;
4214 }
4215 if (!found)
4216 return;
4217
4218 for (i = 0; i < seq_len; i++)
4219 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4220
4221 for (; i < opcnt && seq_len > 0; i++) {
4222 if (!(ops[i].flags & OPF_TAIL))
4223 continue;
4224
4225 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4226 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4227 seq_p++;
4228 }
4229 }
4230
4231 // unlike pushes after sub esp,
4232 // IDA treats pushed like this as part of var area
4233 *fsz += seq_len * 4;
4234}
4235
4236static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4237{
4238 const char *name;
4239 int j, len, ret;
4240
4241 for (; i < opcnt; i++)
4242 if (!(ops[i].flags & OPF_DONE))
4243 break;
4244
4245 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4246 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4247 g_stack_fsz += 4;
4248 (*ecx_push)++;
4249 i++;
4250 }
4251
4252 for (; i < opcnt; i++) {
4253 if (i > 0 && g_labels[i] != NULL)
4254 break;
4255 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
4256 break;
4257 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4258 && ops[i].operand[1].type == OPT_CONST)
4259 {
4260 g_stack_fsz += opr_const(&ops[i], 1);
4261 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4262 i++;
4263 *esp_sub = 1;
4264 break;
4265 }
4266 if (ops[i].op == OP_LEA && ops[i].operand[0].reg == xSP
4267 && ops[i].operand[1].type == OPT_REGMEM
4268 && IS_START(ops[i].operand[1].name, "esp-"))
4269 {
4270 name = ops[i].operand[1].name;
4271 ret = sscanf(name, "esp-%x%n", &j, &len);
4272 ferr_assert(&ops[i], ret == 1 && len == strlen(name));
4273 g_stack_fsz += j;
4274 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4275 i++;
4276 *esp_sub = 1;
4277 break;
4278 }
4279 if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4280 && ops[i].operand[1].type == OPT_CONST)
4281 {
4282 for (j = i + 1; j < opcnt; j++)
4283 if (!(ops[j].flags & OPF_DONE))
4284 break;
4285 if (ops[j].op == OP_CALL
4286 && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4287 {
4288 g_stack_fsz += opr_const(&ops[i], 1);
4289 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4290 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4291 i = j + 1;
4292 *esp_sub = 1;
4293 }
4294 break;
4295 }
4296 }
4297
4298 return i;
4299}
4300
4301static void scan_prologue_epilogue(int opcnt, int *stack_align)
4302{
4303 int ecx_push = 0, esp_sub = 0, pusha = 0;
4304 int sandard_epilogue;
4305 int found, ret, len;
4306 int push_fsz = 0;
4307 int i, j, l;
4308
4309 if (g_seh_found == 2) {
4310 eliminate_seh_calls(opcnt);
4311 return;
4312 }
4313 if (g_seh_found) {
4314 eliminate_seh(opcnt);
4315 // ida treats seh as part of sf
4316 g_stack_fsz = g_seh_size;
4317 esp_sub = 1;
4318 }
4319
4320 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4321 && ops[1].op == OP_MOV
4322 && IS(opr_name(&ops[1], 0), "ebp")
4323 && IS(opr_name(&ops[1], 1), "esp"))
4324 {
4325 g_bp_frame = 1;
4326 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4327 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4328
4329 for (i = 2; i < opcnt; i++)
4330 if (!(ops[i].flags & OPF_DONE))
4331 break;
4332
4333 if (ops[i].op == OP_PUSHA) {
4334 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4335 pusha = 1;
4336 i++;
4337 }
4338
4339 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4340 && ops[i].operand[1].type == OPT_CONST)
4341 {
4342 l = ops[i].operand[1].val;
4343 j = ffs(l) - 1;
4344 if (j == -1 || (l >> j) != -1)
4345 ferr(&ops[i], "unhandled esp align: %x\n", l);
4346 if (stack_align != NULL)
4347 *stack_align = 1 << j;
4348 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4349 i++;
4350 }
4351
4352 i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4353
4354 found = 0;
4355 do {
4356 for (; i < opcnt; i++)
4357 if (ops[i].flags & OPF_TAIL)
4358 break;
4359 j = i - 1;
4360 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4361 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4362 break;
4363 i--;
4364 j--;
4365 }
4366
4367 sandard_epilogue = 0;
4368 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4369 {
4370 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4371 // the standard epilogue is sometimes even used without a sf
4372 if (ops[j - 1].op == OP_MOV
4373 && IS(opr_name(&ops[j - 1], 0), "esp")
4374 && IS(opr_name(&ops[j - 1], 1), "ebp"))
4375 sandard_epilogue = 1;
4376 }
4377 else if (ops[j].op == OP_LEAVE)
4378 {
4379 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4380 sandard_epilogue = 1;
4381 }
4382 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4383 && ops[i].pp->is_noreturn)
4384 {
4385 // on noreturn, msvc sometimes cleans stack, sometimes not
4386 i++;
4387 found = 1;
4388 continue;
4389 }
4390 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4391 ferr(&ops[j], "'pop ebp' expected\n");
4392
4393 if (g_stack_fsz != 0 || sandard_epilogue) {
4394 if (ops[j].op == OP_LEAVE)
4395 j--;
4396 else if (sandard_epilogue) // mov esp, ebp
4397 {
4398 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4399 j -= 2;
4400 }
4401 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4402 {
4403 ferr(&ops[j], "esp restore expected\n");
4404 }
4405
4406 if (ecx_push && j >= 0 && ops[j].op == OP_POP
4407 && IS(opr_name(&ops[j], 0), "ecx"))
4408 {
4409 ferr(&ops[j], "unexpected ecx pop\n");
4410 }
4411 }
4412
4413 if (pusha) {
4414 if (ops[j].op == OP_POPA)
4415 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4416 else
4417 ferr(&ops[j], "popa expected\n");
4418 }
4419
4420 found = 1;
4421 i++;
4422 } while (i < opcnt);
4423
4424 if (!found)
4425 ferr(ops, "missing ebp epilogue\n");
4426 return;
4427 }
4428
4429 // non-bp frame
4430 check_simple_sequence(opcnt, &push_fsz);
4431 i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4432
4433 if (ecx_push && !esp_sub) {
4434 // could actually be args for a call..
4435 for (; i < opcnt; i++)
4436 if (ops[i].op != OP_PUSH)
4437 break;
4438
4439 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4440 const struct parsed_proto *pp;
4441 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4442 j = pp ? pp->argc_stack : 0;
4443 while (i > 0 && j > 0) {
4444 i--;
4445 if (ops[i].op == OP_PUSH) {
4446 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4447 j--;
4448 }
4449 }
4450 if (j != 0)
4451 ferr(&ops[i], "unhandled prologue\n");
4452
4453 // recheck
4454 i = ecx_push = 0;
4455 g_stack_fsz = g_seh_size;
4456 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4457 if (!(ops[i].flags & OPF_RMD))
4458 break;
4459 g_stack_fsz += 4;
4460 ecx_push++;
4461 i++;
4462 }
4463 }
4464 }
4465
4466 found = 0;
4467 if (ecx_push || esp_sub)
4468 {
4469 g_sp_frame = 1;
4470
4471 do {
4472 for (; i < opcnt; i++)
4473 if (ops[i].flags & OPF_TAIL)
4474 break;
4475
4476 j = i - 1;
4477 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4478 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4479 break;
4480 i--;
4481 j--;
4482 }
4483 else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4484 // skip arg updates for arg-reuse tailcall
4485 for (; j >= 0; j--) {
4486 if (ops[j].op != OP_MOV)
4487 break;
4488 if (ops[j].operand[0].type != OPT_REGMEM)
4489 break;
4490 if (strstr(ops[j].operand[0].name, "arg_") == NULL)
4491 break;
4492 }
4493 }
4494
4495 for (; j >= 0; j--) {
4496 if ((ops[j].flags & (OPF_RMD | OPF_DONE | OPF_NOREGS)) !=
4497 (OPF_RMD | OPF_DONE | OPF_NOREGS))
4498 break;
4499 }
4500
4501 if (ecx_push > 0 && !esp_sub) {
4502 for (l = 0; l < ecx_push && j >= 0; l++) {
4503 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4504 /* pop ecx */;
4505 else if (ops[j].op == OP_ADD
4506 && IS(opr_name(&ops[j], 0), "esp")
4507 && ops[j].operand[1].type == OPT_CONST)
4508 {
4509 /* add esp, N */
4510 l += ops[j].operand[1].val / 4 - 1;
4511 }
4512 else
4513 break;
4514
4515 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4516 j--;
4517 }
4518 if (l != ecx_push) {
4519 if (i < opcnt && ops[i].op == OP_CALL
4520 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4521 {
4522 // noreturn tailcall with no epilogue
4523 i++;
4524 found = 1;
4525 continue;
4526 }
4527 ferr(&ops[j], "epilogue scan failed\n");
4528 }
4529
4530 found = 1;
4531 }
4532
4533 if (esp_sub) {
4534 if (ops[j].op == OP_ADD
4535 && IS(opr_name(&ops[j], 0), "esp")
4536 && ops[j].operand[1].type == OPT_CONST)
4537 {
4538 if (ops[j].operand[1].val < g_stack_fsz)
4539 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4540
4541 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4542 if (ops[j].operand[1].val == 0)
4543 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4544 found = 1;
4545 }
4546 else if (ops[j].op == OP_LEA && ops[j].operand[0].reg == xSP
4547 && ops[j].operand[1].type == OPT_REGMEM
4548 && IS_START(ops[j].operand[1].name, "esp+"))
4549 {
4550 const char *name = ops[j].operand[1].name;
4551 ret = sscanf(name, "esp+%x%n", &l, &len);
4552 ferr_assert(&ops[j], ret == 1 && len == strlen(name));
4553 ferr_assert(&ops[j], l <= g_stack_fsz);
4554 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4555 found = 1;
4556 }
4557 else if (i < opcnt && ops[i].op == OP_CALL
4558 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4559 {
4560 // noreturn tailcall with no epilogue
4561 found = 1;
4562 }
4563 else
4564 ferr(&ops[j], "'add esp' expected\n");
4565 }
4566
4567 i++;
4568 } while (i < opcnt);
4569
4570 if (!found)
4571 ferr(ops, "missing esp epilogue\n");
4572 }
4573
4574 if (g_stack_fsz != 0)
4575 // see check_simple_sequence
4576 g_stack_fsz += push_fsz;
4577}
4578
4579// find an instruction that changed opr before i op
4580// *op_i must be set to -1 by the caller
4581// *is_caller is set to 1 if one source is determined to be g_func arg
4582// returns 1 if found, *op_i is then set to origin
4583// returns -1 if multiple origins are found
4584static int resolve_origin(int i, const struct parsed_opr *opr,
4585 int magic, int *op_i, int *is_caller)
4586{
4587 struct label_ref *lr;
4588 int ret = 0;
4589
4590 while (1) {
4591 if (g_labels[i] != NULL) {
4592 lr = &g_label_refs[i];
4593 for (; lr != NULL; lr = lr->next) {
4594 check_i(&ops[i], lr->i);
4595 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4596 }
4597 if (i > 0 && LAST_OP(i - 1))
4598 return ret;
4599 }
4600
4601 i--;
4602 if (i < 0) {
4603 if (is_caller != NULL)
4604 *is_caller = 1;
4605 return -1;
4606 }
4607
4608 if (ops[i].cc_scratch == magic)
4609 return ret;
4610 ops[i].cc_scratch = magic;
4611
4612 if (!(ops[i].flags & OPF_DATA))
4613 continue;
4614 if (!is_opr_modified(opr, &ops[i]))
4615 continue;
4616
4617 if (*op_i >= 0) {
4618 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4619 return ret | 1;
4620
4621 return -1;
4622 }
4623
4624 *op_i = i;
4625 return ret | 1;
4626 }
4627}
4628
4629// find an instruction that previously referenced opr
4630// if multiple results are found - fail
4631// *op_i must be set to -1 by the caller
4632// returns 1 if found, *op_i is then set to referencer insn
4633static int resolve_last_ref(int i, const struct parsed_opr *opr,
4634 int magic, int *op_i)
4635{
4636 struct label_ref *lr;
4637 int ret = 0;
4638
4639 while (1) {
4640 if (g_labels[i] != NULL) {
4641 lr = &g_label_refs[i];
4642 for (; lr != NULL; lr = lr->next) {
4643 check_i(&ops[i], lr->i);
4644 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4645 }
4646 if (i > 0 && LAST_OP(i - 1))
4647 return ret;
4648 }
4649
4650 i--;
4651 if (i < 0)
4652 return -1;
4653
4654 if (ops[i].cc_scratch == magic)
4655 return 0;
4656 ops[i].cc_scratch = magic;
4657
4658 if (!is_opr_referenced(opr, &ops[i]))
4659 continue;
4660
4661 if (*op_i >= 0)
4662 return -1;
4663
4664 *op_i = i;
4665 return 1;
4666 }
4667}
4668
4669// adjust datap of all reachable 'op' insns when moving back
4670// returns 1 if at least 1 op was found
4671// returns -1 if path without an op was found
4672static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4673{
4674 struct label_ref *lr;
4675 int ret = 0;
4676
4677 if (ops[i].cc_scratch == magic)
4678 return 0;
4679 ops[i].cc_scratch = magic;
4680
4681 while (1) {
4682 if (g_labels[i] != NULL) {
4683 lr = &g_label_refs[i];
4684 for (; lr != NULL; lr = lr->next) {
4685 check_i(&ops[i], lr->i);
4686 ret |= adjust_prev_op(lr->i, op, magic, datap);
4687 }
4688 if (i > 0 && LAST_OP(i - 1))
4689 return ret;
4690 }
4691
4692 i--;
4693 if (i < 0)
4694 return -1;
4695
4696 if (ops[i].cc_scratch == magic)
4697 return 0;
4698 ops[i].cc_scratch = magic;
4699
4700 if (ops[i].op != op)
4701 continue;
4702
4703 ops[i].datap = datap;
4704 return 1;
4705 }
4706}
4707
4708// find next instruction that reads opr
4709// *op_i must be set to -1 by the caller
4710// on return, *op_i is set to first referencer insn
4711// returns 1 if exactly 1 referencer is found
4712static int find_next_read(int i, int opcnt,
4713 const struct parsed_opr *opr, int magic, int *op_i)
4714{
4715 struct parsed_op *po;
4716 int j, ret = 0;
4717
4718 for (; i < opcnt; i++)
4719 {
4720 if (ops[i].cc_scratch == magic)
4721 return ret;
4722 ops[i].cc_scratch = magic;
4723
4724 po = &ops[i];
4725 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4726 if (po->btj != NULL) {
4727 // jumptable
4728 for (j = 0; j < po->btj->count; j++) {
4729 check_i(po, po->btj->d[j].bt_i);
4730 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4731 magic, op_i);
4732 }
4733 return ret;
4734 }
4735
4736 if (po->flags & OPF_RMD)
4737 continue;
4738 check_i(po, po->bt_i);
4739 if (po->flags & OPF_CJMP) {
4740 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4741 if (ret < 0)
4742 return ret;
4743 }
4744 else
4745 i = po->bt_i - 1;
4746 continue;
4747 }
4748
4749 if (!is_opr_read(opr, po)) {
4750 int full_opr = 1;
4751 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4752 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4753 {
4754 full_opr = po->operand[0].lmod >= opr->lmod;
4755 }
4756 if (is_opr_modified(opr, po) && full_opr) {
4757 // it's overwritten
4758 return ret;
4759 }
4760 if (po->flags & OPF_TAIL)
4761 return ret;
4762 continue;
4763 }
4764
4765 if (*op_i >= 0)
4766 return -1;
4767
4768 *op_i = i;
4769 return 1;
4770 }
4771
4772 return 0;
4773}
4774
4775static int find_next_read_reg(int i, int opcnt, int reg,
4776 enum opr_lenmod lmod, int magic, int *op_i)
4777{
4778 struct parsed_opr opr = OPR_INIT(OPT_REG, lmod, reg);
4779
4780 *op_i = -1;
4781 return find_next_read(i, opcnt, &opr, magic, op_i);
4782}
4783
4784// find next instruction that reads opr
4785// *op_i must be set to -1 by the caller
4786// on return, *op_i is set to first flag user insn
4787// returns 1 if exactly 1 flag user is found
4788static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4789{
4790 struct parsed_op *po;
4791 int j, ret = 0;
4792
4793 for (; i < opcnt; i++)
4794 {
4795 if (ops[i].cc_scratch == magic)
4796 return ret;
4797 ops[i].cc_scratch = magic;
4798
4799 po = &ops[i];
4800 if (po->op == OP_CALL)
4801 return -1;
4802 if (po->flags & OPF_JMP) {
4803 if (po->btj != NULL) {
4804 // jumptable
4805 for (j = 0; j < po->btj->count; j++) {
4806 check_i(po, po->btj->d[j].bt_i);
4807 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4808 magic, op_i);
4809 }
4810 return ret;
4811 }
4812
4813 if (po->flags & OPF_RMD)
4814 continue;
4815 check_i(po, po->bt_i);
4816 if (po->flags & OPF_CJMP)
4817 goto found;
4818 else
4819 i = po->bt_i - 1;
4820 continue;
4821 }
4822
4823 if (!(po->flags & OPF_CC)) {
4824 if (po->flags & OPF_FLAGS)
4825 // flags changed
4826 return ret;
4827 if (po->flags & OPF_TAIL)
4828 return ret;
4829 continue;
4830 }
4831
4832found:
4833 if (*op_i >= 0)
4834 return -1;
4835
4836 *op_i = i;
4837 return 1;
4838 }
4839
4840 return 0;
4841}
4842
4843static int try_resolve_const(int i, const struct parsed_opr *opr,
4844 int magic, unsigned int *val)
4845{
4846 int s_i = -1;
4847 int ret;
4848
4849 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4850 if (ret == 1) {
4851 i = s_i;
4852 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4853 return -1;
4854
4855 *val = ops[i].operand[1].val;
4856 return 1;
4857 }
4858
4859 return -1;
4860}
4861
4862static int resolve_used_bits(int i, int opcnt, int reg,
4863 int *mask, int *is_z_check)
4864{
4865 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4866 int j = -1, k = -1;
4867 int ret;
4868
4869 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4870 if (ret != 1)
4871 return -1;
4872
4873 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4874 if (k != -1) {
4875 fnote(&ops[j], "(first read)\n");
4876 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4877 }
4878
4879 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4880 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4881
4882 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4883 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4884
4885 *mask = ops[j].operand[1].val;
4886 if (ops[j].operand[0].lmod == OPLM_BYTE
4887 && ops[j].operand[0].name[1] == 'h')
4888 {
4889 *mask <<= 8;
4890 }
4891 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4892
4893 *is_z_check = 0;
4894 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4895 if (ret == 1)
4896 *is_z_check = ops[k].pfo == PFO_Z;
4897
4898 return 0;
4899}
4900
4901static const struct parsed_proto *resolve_deref(int i, int magic,
4902 struct parsed_opr *opr, int level)
4903{
4904 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4905 const struct parsed_proto *pp = NULL;
4906 int from_caller = 0;
4907 char s_reg[4];
4908 int offset = 0;
4909 int len = 0;
4910 int j = -1;
4911 int k = -1;
4912 int reg;
4913 int ret;
4914
4915 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4916 if (ret != 2 || len != strlen(opr->name)) {
4917 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4918 if (ret != 1 || len != strlen(opr->name))
4919 return NULL;
4920 }
4921
4922 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4923 if (reg < 0)
4924 return NULL;
4925
4926 opr_s.reg = reg;
4927 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4928 if (ret != 1)
4929 return NULL;
4930
4931 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4932 && strlen(ops[j].operand[1].name) == 3
4933 && ops[j].operand[0].lmod == OPLM_DWORD
4934 && ops[j].pp == NULL // no hint
4935 && level == 0)
4936 {
4937 // allow one simple dereference (com/directx)
4938 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4939 ops[j].operand[1].name);
4940 if (reg < 0)
4941 return NULL;
4942 opr_s.reg = reg;
4943 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4944 if (ret != 1)
4945 return NULL;
4946 j = k;
4947 }
4948 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4949 return NULL;
4950
4951 if (ops[j].pp != NULL) {
4952 // type hint in asm
4953 pp = ops[j].pp;
4954 }
4955 else if (ops[j].operand[1].type == OPT_REGMEM) {
4956 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4957 if (pp == NULL) {
4958 // maybe structure ptr in structure
4959 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4960 }
4961 }
4962 else if (ops[j].operand[1].type == OPT_LABEL)
4963 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4964 else if (ops[j].operand[1].type == OPT_REG) {
4965 // maybe arg reg?
4966 k = -1;
4967 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4968 &k, &from_caller);
4969 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4970 for (k = 0; k < g_func_pp->argc; k++) {
4971 if (g_func_pp->arg[k].reg == NULL)
4972 continue;
4973 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4974 pp = g_func_pp->arg[k].pp;
4975 break;
4976 }
4977 }
4978 }
4979 }
4980
4981 if (pp == NULL)
4982 return NULL;
4983 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4984 if (offset != 0)
4985 ferr(&ops[j], "expected struct, got '%s %s'\n",
4986 pp->type.name, pp->name);
4987 return NULL;
4988 }
4989
4990 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4991}
4992
4993static const struct parsed_proto *resolve_icall(int i, int opcnt,
4994 int *pp_i, int *multi_src)
4995{
4996 const struct parsed_proto *pp = NULL;
4997 int search_advice = 0;
4998
4999 *multi_src = 0;
5000 *pp_i = -1;
5001
5002 switch (ops[i].operand[0].type) {
5003 case OPT_REGMEM:
5004 // try to resolve struct member calls
5005 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
5006 if (pp != NULL)
5007 break;
5008 // fallthrough
5009 case OPT_LABEL:
5010 case OPT_OFFSET:
5011 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
5012 1, &search_advice);
5013 if (!search_advice)
5014 break;
5015 // fallthrough
5016 default:
5017 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
5018 pp_i, multi_src);
5019 break;
5020 }
5021
5022 return pp;
5023}
5024
5025static struct parsed_proto *process_call_early(int i, int opcnt,
5026 int *adj_i)
5027{
5028 struct parsed_op *po = &ops[i];
5029 struct parsed_proto *pp;
5030 int multipath = 0;
5031 int adj = 0;
5032 int j, ret;
5033
5034 pp = po->pp;
5035 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
5036 // leave for later
5037 return NULL;
5038
5039 // look for and make use of esp adjust
5040 *adj_i = ret = -1;
5041 if (!pp->is_stdcall && pp->argc_stack > 0)
5042 ret = scan_for_esp_adjust(i + 1, opcnt,
5043 pp->argc_stack * 4, &adj, &multipath, 0);
5044 if (ret >= 0) {
5045 if (pp->argc_stack > adj / 4)
5046 return NULL;
5047 if (multipath)
5048 return NULL;
5049 if (ops[ret].op == OP_POP) {
5050 for (j = 1; j < adj / 4; j++) {
5051 if (ops[ret + j].op != OP_POP
5052 || ops[ret + j].operand[0].reg != xCX)
5053 {
5054 return NULL;
5055 }
5056 }
5057 }
5058 }
5059
5060 *adj_i = ret;
5061 return pp;
5062}
5063
5064static struct parsed_proto *process_call(int i, int opcnt)
5065{
5066 struct parsed_op *po = &ops[i];
5067 const struct parsed_proto *pp_c;
5068 struct parsed_proto *pp;
5069 const char *tmpname;
5070 int call_i = -1, ref_i = -1;
5071 int adj = 0, multipath = 0;
5072 int ret, arg;
5073
5074 tmpname = opr_name(po, 0);
5075 pp = po->pp;
5076 if (pp == NULL)
5077 {
5078 // indirect call
5079 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
5080 if (pp_c != NULL) {
5081 if (!pp_c->is_func && !pp_c->is_fptr)
5082 ferr(po, "call to non-func: %s\n", pp_c->name);
5083 pp = proto_clone(pp_c);
5084 my_assert_not(pp, NULL);
5085 if (multipath)
5086 // not resolved just to single func
5087 pp->is_fptr = 1;
5088
5089 switch (po->operand[0].type) {
5090 case OPT_REG:
5091 // we resolved this call and no longer need the register
5092 po->regmask_src &= ~(1 << po->operand[0].reg);
5093
5094 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
5095 && ops[call_i].operand[1].type == OPT_LABEL)
5096 {
5097 // no other source users?
5098 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
5099 &ref_i);
5100 if (ret == 1 && call_i == ref_i) {
5101 // and nothing uses it after us?
5102 ref_i = -1;
5103 find_next_read(i + 1, opcnt, &po->operand[0],
5104 i + opcnt * 11, &ref_i);
5105 if (ref_i == -1)
5106 // then also don't need the source mov
5107 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
5108 }
5109 }
5110 break;
5111 case OPT_REGMEM:
5112 pp->is_fptr = 1;
5113 break;
5114 default:
5115 break;
5116 }
5117 }
5118 if (pp == NULL) {
5119 pp = calloc(1, sizeof(*pp));
5120 my_assert_not(pp, NULL);
5121
5122 pp->is_fptr = 1;
5123 ret = scan_for_esp_adjust(i + 1, opcnt,
5124 -1, &adj, &multipath, 0);
5125 if (ret < 0 || adj < 0) {
5126 if (!g_allow_regfunc)
5127 ferr(po, "non-__cdecl indirect call unhandled yet\n");
5128 pp->is_unresolved = 1;
5129 adj = 0;
5130 }
5131 adj /= 4;
5132 if (adj > ARRAY_SIZE(pp->arg))
5133 ferr(po, "esp adjust too large: %d\n", adj);
5134 pp->ret_type.name = strdup("int");
5135 pp->argc = pp->argc_stack = adj;
5136 for (arg = 0; arg < pp->argc; arg++)
5137 pp->arg[arg].type.name = strdup("int");
5138 }
5139 po->pp = pp;
5140 }
5141
5142 // look for and make use of esp adjust
5143 multipath = 0;
5144 ret = -1;
5145 if (!pp->is_stdcall && pp->argc_stack > 0) {
5146 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
5147 ret = scan_for_esp_adjust(i + 1, opcnt,
5148 adj_expect, &adj, &multipath, 0);
5149 }
5150 if (ret >= 0) {
5151 if (pp->is_vararg) {
5152 if (adj / 4 < pp->argc_stack) {
5153 fnote(po, "(this call)\n");
5154 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
5155 adj, pp->argc_stack * 4);
5156 }
5157 // modify pp to make it have varargs as normal args
5158 arg = pp->argc;
5159 pp->argc += adj / 4 - pp->argc_stack;
5160 for (; arg < pp->argc; arg++) {
5161 pp->arg[arg].type.name = strdup("int");
5162 pp->argc_stack++;
5163 }
5164 if (pp->argc > ARRAY_SIZE(pp->arg))
5165 ferr(po, "too many args for '%s'\n", tmpname);
5166 }
5167 if (pp->argc_stack > adj / 4) {
5168 if (pp->is_noreturn)
5169 // assume no stack adjust was emited
5170 goto out;
5171 fnote(po, "(this call)\n");
5172 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
5173 tmpname, pp->argc_stack * 4, adj);
5174 }
5175
5176 scan_for_esp_adjust(i + 1, opcnt,
5177 pp->argc_stack * 4, &adj, &multipath, 1);
5178 }
5179 else if (pp->is_vararg)
5180 ferr(po, "missing esp_adjust for vararg func '%s'\n",
5181 pp->name);
5182
5183out:
5184 return pp;
5185}
5186
5187static void mark_float_arg(struct parsed_op *po,
5188 struct parsed_proto *pp, int arg, int *regmask_ffca)
5189{
5190 po->p_argnext = -1;
5191 po->p_argnum = arg + 1;
5192 ferr_assert(po, pp->arg[arg].datap == NULL);
5193 pp->arg[arg].datap = po;
5194 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
5195 if (regmask_ffca != NULL)
5196 *regmask_ffca |= 1 << arg;
5197}
5198
5199static int check_for_stp(int i, int i_to)
5200{
5201 struct parsed_op *po;
5202
5203 for (; i < i_to; i++) {
5204 po = &ops[i];
5205 if (po->op == OP_FST)
5206 return i;
5207 if (g_labels[i] != NULL || (po->flags & OPF_JMP))
5208 return -1;
5209 if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
5210 return -1;
5211 if (po->op == OP_ADD && po->operand[0].reg == xSP)
5212 return -1;
5213 }
5214
5215 return -1;
5216}
5217
5218static int collect_call_args_no_push(int i, struct parsed_proto *pp,
5219 int *regmask_ffca)
5220{
5221 struct parsed_op *po;
5222 int offset = 0;
5223 int base_arg;
5224 int j, arg;
5225 int ret;
5226
5227 for (base_arg = 0; base_arg < pp->argc; base_arg++)
5228 if (pp->arg[base_arg].reg == NULL)
5229 break;
5230
5231 for (j = i; j > 0; )
5232 {
5233 ferr_assert(&ops[j], g_labels[j] == NULL);
5234 j--;
5235
5236 po = &ops[j];
5237 ferr_assert(po, po->op != OP_PUSH);
5238 if (po->op == OP_FST)
5239 {
5240 if (po->operand[0].type != OPT_REGMEM)
5241 continue;
5242 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
5243 if (ret != 0)
5244 continue;
5245 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
5246 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
5247 continue;
5248 }
5249
5250 arg = base_arg + offset / 4;
5251 mark_float_arg(po, pp, arg, regmask_ffca);
5252 }
5253 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5254 && po->operand[1].type == OPT_CONST)
5255 {
5256 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5257 break;
5258 }
5259 }
5260
5261 for (arg = base_arg; arg < pp->argc; arg++) {
5262 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
5263 po = pp->arg[arg].datap;
5264 if (po == NULL)
5265 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
5266 if (po->operand[0].lmod == OPLM_QWORD)
5267 arg++;
5268 }
5269
5270 return 0;
5271}
5272
5273static int collect_call_args_early(int i, struct parsed_proto *pp,
5274 int *regmask, int *regmask_ffca)
5275{
5276 struct parsed_op *po;
5277 int arg, ret;
5278 int offset;
5279 int j, k;
5280
5281 for (arg = 0; arg < pp->argc; arg++)
5282 if (pp->arg[arg].reg == NULL)
5283 break;
5284
5285 // first see if it can be easily done
5286 for (j = i; j > 0 && arg < pp->argc; )
5287 {
5288 if (g_labels[j] != NULL)
5289 return -1;
5290 j--;
5291
5292 po = &ops[j];
5293 if (po->op == OP_CALL)
5294 return -1;
5295 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
5296 return -1;
5297 else if (po->op == OP_POP)
5298 return -1;
5299 else if (po->flags & OPF_CJMP)
5300 return -1;
5301 else if (po->op == OP_PUSH) {
5302 if (po->flags & (OPF_FARG|OPF_FARGNR))
5303 return -1;
5304 if (!g_header_mode) {
5305 ret = scan_for_mod(po, j + 1, i, 1);
5306 if (ret >= 0)
5307 return -1;
5308 }
5309
5310 if (pp->arg[arg].type.is_va_list)
5311 return -1;
5312
5313 // next arg
5314 for (arg++; arg < pp->argc; arg++)
5315 if (pp->arg[arg].reg == NULL)
5316 break;
5317 }
5318 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5319 && po->operand[1].type == OPT_CONST)
5320 {
5321 if (po->flags & (OPF_RMD|OPF_DONE))
5322 return -1;
5323 if (po->operand[1].val != pp->argc_stack * 4)
5324 ferr(po, "unexpected esp adjust: %d\n",
5325 po->operand[1].val * 4);
5326 ferr_assert(po, pp->argc - arg == pp->argc_stack);
5327 return collect_call_args_no_push(i, pp, regmask_ffca);
5328 }
5329 }
5330
5331 if (arg < pp->argc)
5332 return -1;
5333
5334 // now do it
5335 for (arg = 0; arg < pp->argc; arg++)
5336 if (pp->arg[arg].reg == NULL)
5337 break;
5338
5339 for (j = i; j > 0 && arg < pp->argc; )
5340 {
5341 j--;
5342
5343 if (ops[j].op == OP_PUSH)
5344 {
5345 ops[j].p_argnext = -1;
5346 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
5347
5348 k = check_for_stp(j + 1, i);
5349 if (k != -1) {
5350 // push ecx; fstp dword ptr [esp]
5351 ret = parse_stack_esp_offset(&ops[k],
5352 ops[k].operand[0].name, &offset);
5353 if (ret == 0 && offset == 0) {
5354 if (!pp->arg[arg].type.is_float)
5355 ferr(&ops[i], "arg %d should be float\n", arg + 1);
5356 mark_float_arg(&ops[k], pp, arg, regmask_ffca);
5357 }
5358 }
5359
5360 if (pp->arg[arg].datap == NULL) {
5361 pp->arg[arg].datap = &ops[j];
5362 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5363 *regmask |= 1 << ops[j].operand[0].reg;
5364 }
5365
5366 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5367 ops[j].flags &= ~OPF_RSAVE;
5368
5369 // next arg
5370 for (arg++; arg < pp->argc; arg++)
5371 if (pp->arg[arg].reg == NULL)
5372 break;
5373 }
5374 }
5375
5376 return 0;
5377}
5378
5379static int sync_argnum(struct parsed_op *po, int argnum)
5380{
5381 struct parsed_op *po_tmp;
5382
5383 // see if other branches don't have higher argnum
5384 for (po_tmp = po; po_tmp != NULL; ) {
5385 if (argnum < po_tmp->p_argnum)
5386 argnum = po_tmp->p_argnum;
5387 // note: p_argnext is active on current collect_call_args only
5388 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5389 }
5390
5391 // make all argnums consistent
5392 for (po_tmp = po; po_tmp != NULL; ) {
5393 if (po_tmp->p_argnum != 0)
5394 po_tmp->p_argnum = argnum;
5395 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5396 }
5397
5398 return argnum;
5399}
5400
5401static int collect_call_args_r(struct parsed_op *po, int i,
5402 struct parsed_proto *pp, int *regmask, int *arg_grp,
5403 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
5404{
5405 struct parsed_proto *pp_tmp;
5406 struct parsed_op *po_tmp;
5407 struct label_ref *lr;
5408 int need_to_save_current;
5409 int arg_grp_current = 0;
5410 int save_args_seen = 0;
5411 int ret = 0;
5412 int reg;
5413 char buf[32];
5414 int j, k;
5415
5416 if (i < 0) {
5417 ferr(po, "dead label encountered\n");
5418 return -1;
5419 }
5420
5421 for (; arg < pp->argc; arg++, argnum++)
5422 if (pp->arg[arg].reg == NULL)
5423 break;
5424 magic = (magic & 0xffffff) | (arg << 24);
5425
5426 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5427 {
5428 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5429 if (ops[j].cc_scratch != magic) {
5430 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5431 pp->name);
5432 return -1;
5433 }
5434 // ok: have already been here
5435 return 0;
5436 }
5437 ops[j].cc_scratch = magic;
5438
5439 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5440 lr = &g_label_refs[j];
5441 if (lr->next != NULL)
5442 need_op_saving = 1;
5443 for (; lr->next; lr = lr->next) {
5444 check_i(&ops[j], lr->i);
5445 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5446 may_reuse = 1;
5447 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5448 arg, argnum, magic, need_op_saving, may_reuse);
5449 if (ret < 0)
5450 return ret;
5451 }
5452
5453 check_i(&ops[j], lr->i);
5454 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5455 may_reuse = 1;
5456 if (j > 0 && LAST_OP(j - 1)) {
5457 // follow last branch in reverse
5458 j = lr->i;
5459 continue;
5460 }
5461 need_op_saving = 1;
5462 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5463 arg, argnum, magic, need_op_saving, may_reuse);
5464 if (ret < 0)
5465 return ret;
5466 }
5467 j--;
5468
5469 if (ops[j].op == OP_CALL)
5470 {
5471 if (pp->is_unresolved)
5472 break;
5473
5474 pp_tmp = ops[j].pp;
5475 if (pp_tmp == NULL)
5476 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5477 arg, pp->argc, ops[j].operand[0].name);
5478 if (may_reuse && pp_tmp->argc_stack > 0)
5479 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5480 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5481 }
5482 // esp adjust of 0 means we collected it before
5483 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5484 && (ops[j].operand[1].type != OPT_CONST
5485 || ops[j].operand[1].val != 0))
5486 {
5487 if (pp->is_unresolved)
5488 break;
5489
5490 fnote(po, "(this call)\n");
5491 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5492 arg, pp->argc, ops[j].operand[1].val);
5493 }
5494 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5495 {
5496 if (pp->is_unresolved)
5497 break;
5498
5499 fnote(po, "(this call)\n");
5500 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5501 }
5502 else if (ops[j].flags & OPF_CJMP)
5503 {
5504 if (pp->is_unresolved)
5505 break;
5506
5507 may_reuse = 1;
5508 }
5509 else if (ops[j].op == OP_PUSH
5510 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5511 {
5512 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5513 break;
5514
5515 ops[j].p_argnext = -1;
5516 po_tmp = pp->arg[arg].datap;
5517 if (po_tmp != NULL)
5518 ops[j].p_argnext = po_tmp - ops;
5519 pp->arg[arg].datap = &ops[j];
5520
5521 argnum = sync_argnum(&ops[j], argnum);
5522
5523 need_to_save_current = 0;
5524 reg = -1;
5525 if (ops[j].operand[0].type == OPT_REG)
5526 reg = ops[j].operand[0].reg;
5527
5528 if (!need_op_saving) {
5529 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5530 need_to_save_current = (ret >= 0);
5531 }
5532 if (need_op_saving || need_to_save_current) {
5533 // mark this arg as one that needs operand saving
5534 pp->arg[arg].is_saved = 1;
5535
5536 if (save_args_seen & (1 << (argnum - 1))) {
5537 save_args_seen = 0;
5538 arg_grp_current++;
5539 if (arg_grp_current >= MAX_ARG_GRP)
5540 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5541 argnum, pp->name);
5542 }
5543 }
5544 else if (ops[j].p_argnum == 0)
5545 ops[j].flags |= OPF_RMD;
5546
5547 // some PUSHes are reused by different calls on other branches,
5548 // but that can't happen if we didn't branch, so they
5549 // can be removed from future searches (handles nested calls)
5550 if (!may_reuse)
5551 ops[j].flags |= OPF_FARGNR;
5552
5553 ops[j].flags |= OPF_FARG;
5554 ops[j].flags &= ~OPF_RSAVE;
5555
5556 // check for __VALIST
5557 if (!pp->is_unresolved && g_func_pp != NULL
5558 && pp->arg[arg].type.is_va_list)
5559 {
5560 k = -1;
5561 ret = resolve_origin(j, &ops[j].operand[0],
5562 magic + 1, &k, NULL);
5563 if (ret == 1 && k >= 0)
5564 {
5565 if (ops[k].op == OP_LEA) {
5566 if (!g_func_pp->is_vararg)
5567 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5568 g_func_pp->name);
5569
5570 snprintf(buf, sizeof(buf), "arg_%X",
5571 g_func_pp->argc_stack * 4);
5572 if (strstr(ops[k].operand[1].name, buf)
5573 || strstr(ops[k].operand[1].name, "arglist"))
5574 {
5575 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5576 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5577 pp->arg[arg].is_saved = 0;
5578 reg = -1;
5579 }
5580 else
5581 ferr(&ops[k], "va_list arg detection failed\n");
5582 }
5583 // check for va_list from g_func_pp arg too
5584 else if (ops[k].op == OP_MOV
5585 && is_stack_access(&ops[k], &ops[k].operand[1]))
5586 {
5587 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5588 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5589 if (ret >= 0) {
5590 ops[k].flags |= OPF_RMD | OPF_DONE;
5591 ops[j].flags |= OPF_RMD;
5592 ops[j].p_argpass = ret + 1;
5593 pp->arg[arg].is_saved = 0;
5594 reg = -1;
5595 }
5596 }
5597 }
5598 }
5599
5600 if (pp->arg[arg].is_saved) {
5601 ops[j].flags &= ~OPF_RMD;
5602 ops[j].p_argnum = argnum;
5603 }
5604
5605 // tracking reg usage
5606 if (reg >= 0)
5607 *regmask |= 1 << reg;
5608
5609 arg++;
5610 argnum++;
5611 if (!pp->is_unresolved) {
5612 // next arg
5613 for (; arg < pp->argc; arg++, argnum++)
5614 if (pp->arg[arg].reg == NULL)
5615 break;
5616 }
5617 magic = (magic & 0xffffff) | (arg << 24);
5618 }
5619
5620 if (ops[j].p_arggrp > arg_grp_current) {
5621 save_args_seen = 0;
5622 arg_grp_current = ops[j].p_arggrp;
5623 }
5624 if (ops[j].p_argnum > 0)
5625 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5626 }
5627
5628 if (arg < pp->argc) {
5629 ferr(po, "arg collect failed for '%s': %d/%d\n",
5630 pp->name, arg, pp->argc);
5631 return -1;
5632 }
5633
5634 if (arg_grp_current > *arg_grp)
5635 *arg_grp = arg_grp_current;
5636
5637 return arg;
5638}
5639
5640static int collect_call_args(struct parsed_op *po, int i,
5641 struct parsed_proto *pp, int *regmask, int magic)
5642{
5643 // arg group is for cases when pushes for
5644 // multiple funcs are going on
5645 struct parsed_op *po_tmp;
5646 int arg_grp = 0;
5647 int ret;
5648 int a;
5649
5650 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5651 0, 1, magic, 0, 0);
5652 if (ret < 0)
5653 return ret;
5654
5655 if (arg_grp != 0) {
5656 // propagate arg_grp
5657 for (a = 0; a < pp->argc; a++) {
5658 if (pp->arg[a].reg != NULL)
5659 continue;
5660
5661 po_tmp = pp->arg[a].datap;
5662 while (po_tmp != NULL) {
5663 po_tmp->p_arggrp = arg_grp;
5664 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5665 }
5666 }
5667 }
5668
5669 if (pp->is_unresolved) {
5670 pp->argc += ret;
5671 pp->argc_stack += ret;
5672 for (a = 0; a < pp->argc; a++)
5673 if (pp->arg[a].type.name == NULL)
5674 pp->arg[a].type.name = strdup("int");
5675 }
5676
5677 return ret;
5678}
5679
5680static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5681 int regmask_now, int *regmask,
5682 int regmask_save_now, int *regmask_save,
5683 int *regmask_init, int regmask_arg)
5684{
5685 struct parsed_op *po;
5686 int already_saved;
5687 int regmask_new;
5688 int regmask_op;
5689 int flags_set;
5690 int ret, reg;
5691 int j;
5692
5693 for (; i < opcnt; i++)
5694 {
5695 po = &ops[i];
5696 if (cbits[i >> 3] & (1 << (i & 7)))
5697 return;
5698 cbits[i >> 3] |= (1 << (i & 7));
5699
5700 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5701 if (po->flags & (OPF_RMD|OPF_DONE))
5702 continue;
5703 if (po->btj != NULL) {
5704 for (j = 0; j < po->btj->count; j++) {
5705 check_i(po, po->btj->d[j].bt_i);
5706 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5707 regmask_now, regmask, regmask_save_now, regmask_save,
5708 regmask_init, regmask_arg);
5709 }
5710 return;
5711 }
5712
5713 check_i(po, po->bt_i);
5714 if (po->flags & OPF_CJMP)
5715 reg_use_pass(po->bt_i, opcnt, cbits,
5716 regmask_now, regmask, regmask_save_now, regmask_save,
5717 regmask_init, regmask_arg);
5718 else
5719 i = po->bt_i - 1;
5720 continue;
5721 }
5722
5723 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5724 && !g_func_pp->is_userstack
5725 && po->operand[0].type == OPT_REG)
5726 {
5727 reg = po->operand[0].reg;
5728 ferr_assert(po, reg >= 0);
5729
5730 already_saved = 0;
5731 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5732 if (regmask_now & (1 << reg)) {
5733 already_saved = regmask_save_now & (1 << reg);
5734 flags_set = OPF_RSAVE | OPF_DONE;
5735 }
5736
5737 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5738 if (ret == 1) {
5739 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5740 reg, 0, 0, flags_set);
5741 }
5742 else {
5743 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5744 if (ret == 1) {
5745 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5746 flags_set);
5747 }
5748 }
5749 if (ret == 1) {
5750 ferr_assert(po, !already_saved);
5751 po->flags |= flags_set;
5752
5753 if (regmask_now & (1 << reg)) {
5754 regmask_save_now |= (1 << reg);
5755 *regmask_save |= regmask_save_now;
5756 }
5757 continue;
5758 }
5759 }
5760 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5761 reg = po->operand[0].reg;
5762 ferr_assert(po, reg >= 0);
5763
5764 if (regmask_save_now & (1 << reg))
5765 regmask_save_now &= ~(1 << reg);
5766 else
5767 regmask_now &= ~(1 << reg);
5768 continue;
5769 }
5770 else if (po->op == OP_CALL) {
5771 if ((po->regmask_dst & (1 << xAX))
5772 && !(po->regmask_dst & (1 << xDX)))
5773 {
5774 if (po->flags & OPF_TAIL)
5775 // don't need eax, will do "return f();" or "f(); return;"
5776 po->regmask_dst &= ~(1 << xAX);
5777 else {
5778 find_next_read_reg(i + 1, opcnt, xAX, OPLM_DWORD,
5779 i + opcnt * 17, &j);
5780 if (j == -1)
5781 // not used
5782 po->regmask_dst &= ~(1 << xAX);
5783 }
5784 }
5785
5786 // not "full stack" mode and have something in stack
5787 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5788 ferr(po, "float stack is not empty on func call\n");
5789 }
5790
5791 if (po->flags & OPF_NOREGS)
5792 continue;
5793
5794 // if incomplete register is used, clear it on init to avoid
5795 // later use of uninitialized upper part in some situations
5796 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5797 && po->operand[0].lmod != OPLM_DWORD)
5798 {
5799 reg = po->operand[0].reg;
5800 ferr_assert(po, reg >= 0);
5801
5802 if (!(regmask_now & (1 << reg)))
5803 *regmask_init |= 1 << reg;
5804 }
5805
5806 regmask_op = po->regmask_src | po->regmask_dst;
5807
5808 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5809 regmask_new &= ~(1 << xSP);
5810 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5811 regmask_new &= ~(1 << xBP);
5812
5813 if (regmask_new != 0)
5814 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5815
5816 if (regmask_op & (1 << xBP)) {
5817 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5818 if (po->regmask_dst & (1 << xBP))
5819 // compiler decided to drop bp frame and use ebp as scratch
5820 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5821 else
5822 regmask_op &= ~(1 << xBP);
5823 }
5824 }
5825
5826 if (po->flags & OPF_FPUSH) {
5827 if (regmask_now & mxST1)
5828 regmask_now |= mxSTa; // switch to "full stack" mode
5829 if (regmask_now & mxSTa)
5830 po->flags |= OPF_FSHIFT;
5831 if (!(regmask_now & mxST7_2)) {
5832 regmask_now =
5833 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5834 }
5835 }
5836
5837 regmask_now |= regmask_op;
5838 *regmask |= regmask_now;
5839
5840 // released regs
5841 if (po->flags & OPF_FPOPP) {
5842 if ((regmask_now & mxSTa) == 0)
5843 ferr(po, "float pop on empty stack?\n");
5844 if (regmask_now & mxST7_2)
5845 po->flags |= OPF_FSHIFT;
5846 if (!(regmask_now & mxST7_2))
5847 regmask_now &= ~mxST1_0;
5848 }
5849 else if (po->flags & OPF_FPOP) {
5850 if ((regmask_now & mxSTa) == 0)
5851 ferr(po, "float pop on empty stack?\n");
5852 if (regmask_now & (mxST7_2 | mxST1))
5853 po->flags |= OPF_FSHIFT;
5854 if (!(regmask_now & mxST7_2)) {
5855 regmask_now =
5856 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5857 }
5858 }
5859
5860 if (po->flags & OPF_TAIL) {
5861 if (!(regmask_now & mxST7_2)) {
5862 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5863 if (!(regmask_now & mxST0))
5864 ferr(po, "no st0 on float return, mask: %x\n",
5865 regmask_now);
5866 }
5867 else if (regmask_now & mxST1_0)
5868 ferr(po, "float regs on tail: %x\n", regmask_now);
5869 }
5870
5871 // there is support for "conditional tailcall", sort of
5872 if (!(po->flags & OPF_CC))
5873 return;
5874 }
5875 }
5876}
5877
5878static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5879{
5880 int i;
5881
5882 for (i = 0; i < pp->argc; i++)
5883 if (pp->arg[i].reg == NULL)
5884 break;
5885
5886 if (pp->argc_stack)
5887 memmove(&pp->arg[i + 1], &pp->arg[i],
5888 sizeof(pp->arg[0]) * pp->argc_stack);
5889 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5890 pp->arg[i].reg = strdup(reg);
5891 pp->arg[i].type.name = strdup("int");
5892 pp->argc++;
5893 pp->argc_reg++;
5894}
5895
5896static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5897 int *pfomask, const char *dst_opr_text)
5898{
5899 if (*pfomask & (1 << PFO_Z)) {
5900 fprintf(fout, "\n cond_z = (%s%s == 0);",
5901 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5902 *pfomask &= ~(1 << PFO_Z);
5903 }
5904}
5905
5906static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5907 int *pfomask, const char *dst_opr_text)
5908{
5909 if (*pfomask & (1 << PFO_S)) {
5910 fprintf(fout, "\n cond_s = (%s%s < 0);",
5911 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5912 *pfomask &= ~(1 << PFO_S);
5913 }
5914}
5915
5916static void output_std_flags(FILE *fout, struct parsed_op *po,
5917 int *pfomask, const char *dst_opr_text)
5918{
5919 output_std_flag_z(fout, po, pfomask, dst_opr_text);
5920 output_std_flag_s(fout, po, pfomask, dst_opr_text);
5921}
5922
5923enum {
5924 OPP_FORCE_NORETURN = (1 << 0),
5925 OPP_SIMPLE_ARGS = (1 << 1),
5926 OPP_ALIGN = (1 << 2),
5927};
5928
5929static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5930 int flags)
5931{
5932 const char *cconv = "";
5933
5934 if (pp->is_fastcall)
5935 cconv = "__fastcall ";
5936 else if (pp->is_stdcall && pp->argc_reg == 0)
5937 cconv = "__stdcall ";
5938
5939 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5940
5941 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5942 fprintf(fout, "noreturn ");
5943}
5944
5945static void output_pp(FILE *fout, const struct parsed_proto *pp,
5946 int flags)
5947{
5948 int i;
5949
5950 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5951 pp->ret_type.name);
5952 if (pp->is_fptr)
5953 fprintf(fout, "(");
5954 output_pp_attrs(fout, pp, flags);
5955 if (pp->is_fptr)
5956 fprintf(fout, "*");
5957 fprintf(fout, "%s", pp->name);
5958 if (pp->is_fptr)
5959 fprintf(fout, ")");
5960
5961 fprintf(fout, "(");
5962 for (i = 0; i < pp->argc; i++) {
5963 if (i > 0)
5964 fprintf(fout, ", ");
5965 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5966 && !(flags & OPP_SIMPLE_ARGS))
5967 {
5968 // func pointer
5969 output_pp(fout, pp->arg[i].pp, 0);
5970 }
5971 else if (pp->arg[i].type.is_retreg) {
5972 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5973 }
5974 else {
5975 fprintf(fout, "%s", pp->arg[i].type.name);
5976 if (!pp->is_fptr)
5977 fprintf(fout, " a%d", i + 1);
5978 }
5979
5980 if (pp->arg[i].type.is_64bit)
5981 i++;
5982 }
5983 if (pp->is_vararg) {
5984 if (i > 0)
5985 fprintf(fout, ", ");
5986 fprintf(fout, "...");
5987 }
5988 fprintf(fout, ")");
5989}
5990
5991static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5992{
5993 char buf1[16];
5994
5995 buf1[0] = 0;
5996 if (grp > 0)
5997 snprintf(buf1, sizeof(buf1), "%d", grp);
5998 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5999
6000 return buf;
6001}
6002
6003static void gen_x_cleanup(int opcnt);
6004
6005static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
6006{
6007 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
6008 struct parsed_opr *last_arith_dst = NULL;
6009 char buf1[256], buf2[256], buf3[256], cast[64];
6010 struct parsed_proto *pp, *pp_tmp;
6011 struct parsed_data *pd;
6012 int save_arg_vars[MAX_ARG_GRP] = { 0, };
6013 unsigned char cbits[MAX_OPS / 8];
6014 const char *float_type;
6015 const char *float_st0;
6016 const char *float_st1;
6017 int need_float_stack = 0;
6018 int need_float_sw = 0; // status word
6019 int need_tmp_var = 0;
6020 int need_tmp64 = 0;
6021 int cond_vars = 0;
6022 int had_decl = 0;
6023 int label_pending = 0;
6024 int need_double = 0;
6025 int stack_align = 0;
6026 int stack_fsz_adj = 0;
6027 int lock_handled = 0;
6028 int regmask_save = 0; // used regs saved/restored in this func
6029 int regmask_arg; // regs from this function args (fastcall, etc)
6030 int regmask_ret; // regs needed on ret
6031 int regmask_now; // temp
6032 int regmask_init = 0; // regs that need zero initialization
6033 int regmask_pp = 0; // regs used in complex push-pop graph
6034 int regmask_ffca = 0; // float function call args
6035 int regmask = 0; // used regs
6036 int pfomask = 0;
6037 int found = 0;
6038 int dead_dst;
6039 int no_output;
6040 int i, j, l;
6041 int arg;
6042 int reg;
6043 int ret;
6044
6045 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
6046 g_stack_frame_used = 0;
6047 g_seh_size = 0;
6048 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
6049 regmask_init = g_regmask_init;
6050
6051 g_func_pp = proto_parse(fhdr, funcn, 0);
6052 if (g_func_pp == NULL)
6053 ferr(ops, "proto_parse failed for '%s'\n", funcn);
6054
6055 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
6056 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
6057
6058 // pass1:
6059 // - resolve all branches
6060 // - parse calls with labels
6061 resolve_branches_parse_calls(opcnt);
6062
6063 // pass2:
6064 // - handle ebp/esp frame, remove ops related to it
6065 scan_prologue_epilogue(opcnt, &stack_align);
6066
6067 // handle a case where sf size is unalignment, but is
6068 // placed in a way that elements are still aligned
6069 if (g_stack_fsz & 4) {
6070 for (i = 0; i < g_eqcnt; i++) {
6071 if (g_eqs[i].lmod != OPLM_QWORD)
6072 continue;
6073 if (!(g_eqs[i].offset & 4)) {
6074 g_stack_fsz += 4;
6075 stack_fsz_adj = 4;
6076 }
6077 break;
6078 }
6079 }
6080
6081 // pass3:
6082 // - remove dead labels
6083 // - set regs needed at ret
6084 for (i = 0; i < opcnt; i++)
6085 {
6086 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
6087 free(g_labels[i]);
6088 g_labels[i] = NULL;
6089 }
6090
6091 if (ops[i].op == OP_RET)
6092 ops[i].regmask_src |= regmask_ret;
6093 }
6094
6095 // pass4:
6096 // - process trivial calls
6097 for (i = 0; i < opcnt; i++)
6098 {
6099 po = &ops[i];
6100 if (po->flags & (OPF_RMD|OPF_DONE))
6101 continue;
6102
6103 if (po->op == OP_CALL)
6104 {
6105 pp = process_call_early(i, opcnt, &j);
6106 if (pp != NULL) {
6107 if (!(po->flags & OPF_ATAIL)) {
6108 // since we know the args, try to collect them
6109 ret = collect_call_args_early(i, pp, &regmask, &regmask_ffca);
6110 if (ret != 0)
6111 pp = NULL;
6112 }
6113 }
6114
6115 if (pp != NULL) {
6116 if (j >= 0) {
6117 // commit esp adjust
6118 if (ops[j].op != OP_POP)
6119 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
6120 else {
6121 for (l = 0; l < pp->argc_stack; l++)
6122 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
6123 }
6124 }
6125
6126 if (strstr(pp->ret_type.name, "int64"))
6127 need_tmp64 = 1;
6128
6129 po->flags |= OPF_DONE;
6130 }
6131 }
6132 }
6133
6134 // pass5:
6135 // - process calls, stage 2
6136 // - handle some push/pop pairs
6137 // - scan for STD/CLD, propagate DF
6138 // - try to resolve needed x87 status word bits
6139 for (i = 0; i < opcnt; i++)
6140 {
6141 int mask, z_check;
6142
6143 po = &ops[i];
6144 if (po->flags & OPF_RMD)
6145 continue;
6146
6147 if (po->op == OP_CALL)
6148 {
6149 if (!(po->flags & OPF_DONE)) {
6150 pp = process_call(i, opcnt);
6151
6152 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
6153 // since we know the args, collect them
6154 collect_call_args(po, i, pp, &regmask, i + opcnt * 2);
6155 }
6156 // for unresolved, collect after other passes
6157 }
6158
6159 pp = po->pp;
6160 ferr_assert(po, pp != NULL);
6161
6162 po->regmask_src |= get_pp_arg_regmask_src(pp);
6163 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
6164
6165 if (po->regmask_dst & mxST0)
6166 po->flags |= OPF_FPUSH;
6167
6168 if (strstr(pp->ret_type.name, "int64"))
6169 need_tmp64 = 1;
6170
6171 continue;
6172 }
6173
6174 if (po->flags & OPF_DONE)
6175 continue;
6176
6177 switch (po->op) {
6178 case OP_PUSH:
6179 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
6180 && po->operand[0].type == OPT_CONST)
6181 {
6182 scan_for_pop_const(i, opcnt, i + opcnt * 12);
6183 }
6184 break;
6185
6186 case OP_POP:
6187 scan_pushes_for_pop(i, opcnt, &regmask_pp);
6188 break;
6189
6190 case OP_STD:
6191 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
6192 scan_propagate_df(i + 1, opcnt);
6193 break;
6194
6195 case OP_FNSTSW:
6196 need_float_sw = 1;
6197 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
6198 ferr(po, "TODO: fnstsw to mem\n");
6199 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
6200 if (ret != 0)
6201 ferr(po, "fnstsw resolve failed\n");
6202 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
6203 (void *)(long)(mask | (z_check << 16)));
6204 if (ret != 1)
6205 ferr(po, "failed to find fcom: %d\n", ret);
6206 break;
6207
6208 default:
6209 break;
6210 }
6211 }
6212
6213 // pass6:
6214 // - find POPs for PUSHes, rm both
6215 // - scan for all used registers
6216 memset(cbits, 0, sizeof(cbits));
6217 reg_use_pass(0, opcnt, cbits, regmask_init, &regmask,
6218 0, &regmask_save, &regmask_init, regmask_arg);
6219
6220 need_float_stack = !!(regmask & mxST7_2);
6221
6222 // pass7:
6223 // - find flag set ops for their users
6224 // - do unresolved calls
6225 // - declare indirect functions
6226 // - other op specific processing
6227 for (i = 0; i < opcnt; i++)
6228 {
6229 po = &ops[i];
6230 if (po->flags & (OPF_RMD|OPF_DONE))
6231 continue;
6232
6233 if (po->flags & OPF_CC)
6234 {
6235 int setters[16], cnt = 0, branched = 0;
6236
6237 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
6238 &branched, setters, &cnt);
6239 if (ret < 0 || cnt <= 0)
6240 ferr(po, "unable to trace flag setter(s)\n");
6241 if (cnt > ARRAY_SIZE(setters))
6242 ferr(po, "too many flag setters\n");
6243
6244 for (j = 0; j < cnt; j++)
6245 {
6246 tmp_op = &ops[setters[j]]; // flag setter
6247 pfomask = 0;
6248
6249 // to get nicer code, we try to delay test and cmp;
6250 // if we can't because of operand modification, or if we
6251 // have arith op, or branch, make it calculate flags explicitly
6252 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
6253 {
6254 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
6255 pfomask = 1 << po->pfo;
6256 }
6257 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
6258 pfomask = 1 << po->pfo;
6259 }
6260 else {
6261 // see if we'll be able to handle based on op result
6262 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
6263 && po->pfo != PFO_Z && po->pfo != PFO_S
6264 && po->pfo != PFO_P)
6265 || branched
6266 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
6267 {
6268 pfomask = 1 << po->pfo;
6269 }
6270
6271 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
6272 propagate_lmod(tmp_op, &tmp_op->operand[0],
6273 &tmp_op->operand[1]);
6274 if (tmp_op->operand[0].lmod == OPLM_DWORD)
6275 need_tmp64 = 1;
6276 }
6277 }
6278 if (pfomask) {
6279 tmp_op->pfomask |= pfomask;
6280 cond_vars |= pfomask;
6281 }
6282 // note: may overwrite, currently not a problem
6283 po->datap = tmp_op;
6284 }
6285
6286 if (po->op == OP_RCL || po->op == OP_RCR
6287 || po->op == OP_ADC || po->op == OP_SBB)
6288 cond_vars |= 1 << PFO_C;
6289 }
6290
6291 switch (po->op) {
6292 case OP_CMPS:
6293 case OP_SCAS:
6294 cond_vars |= 1 << PFO_Z;
6295 break;
6296
6297 case OP_MUL:
6298 if (po->operand[0].lmod == OPLM_DWORD)
6299 need_tmp64 = 1;
6300 break;
6301
6302 case OP_IMUL:
6303 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
6304 need_tmp64 = 1;
6305 break;
6306
6307 case OP_CALL:
6308 // note: resolved non-reg calls are OPF_DONE already
6309 pp = po->pp;
6310 ferr_assert(po, pp != NULL);
6311
6312 if (pp->is_unresolved) {
6313 int regmask_stack = 0;
6314 collect_call_args(po, i, pp, &regmask, i + opcnt * 2);
6315
6316 // this is pretty rough guess:
6317 // see ecx and edx were pushed (and not their saved versions)
6318 for (arg = 0; arg < pp->argc; arg++) {
6319 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
6320 continue;
6321
6322 tmp_op = pp->arg[arg].datap;
6323 if (tmp_op == NULL)
6324 ferr(po, "parsed_op missing for arg%d\n", arg);
6325 if (tmp_op->operand[0].type == OPT_REG)
6326 regmask_stack |= 1 << tmp_op->operand[0].reg;
6327 }
6328
6329 if (!((regmask_stack & (1 << xCX))
6330 && (regmask_stack & (1 << xDX))))
6331 {
6332 if (pp->argc_stack != 0
6333 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
6334 {
6335 pp_insert_reg_arg(pp, "ecx");
6336 pp->is_fastcall = 1;
6337 regmask_init |= 1 << xCX;
6338 regmask |= 1 << xCX;
6339 }
6340 if (pp->argc_stack != 0
6341 || ((regmask | regmask_arg) & (1 << xDX)))
6342 {
6343 pp_insert_reg_arg(pp, "edx");
6344 regmask_init |= 1 << xDX;
6345 regmask |= 1 << xDX;
6346 }
6347 }
6348
6349 // note: __cdecl doesn't fall into is_unresolved category
6350 if (pp->argc_stack > 0)
6351 pp->is_stdcall = 1;
6352 }
6353 if (!(po->flags & OPF_TAIL)
6354 && !(g_sct_func_attr & SCTFA_NOWARN))
6355 {
6356 // treat al write as overwrite to avoid many false positives
6357 if (IS(pp->ret_type.name, "void") || pp->ret_type.is_float) {
6358 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
6359 i + opcnt * 25, &j);
6360 if (j != -1) {
6361 fnote(po, "eax used after void/float ret call\n");
6362 fnote(&ops[j], "(used here)\n");
6363 }
6364 }
6365 if (!strstr(pp->ret_type.name, "int64")) {
6366 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
6367 i + opcnt * 26, &j);
6368 // indirect calls are often guessed, don't warn
6369 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6370 fnote(po, "edx used after 32bit ret call\n");
6371 fnote(&ops[j], "(used here)\n");
6372 }
6373 }
6374 j = 1;
6375 // msvc often relies on callee not modifying 'this'
6376 for (arg = 0; arg < pp->argc; arg++) {
6377 if (pp->arg[arg].reg && IS(pp->arg[arg].reg, "ecx")) {
6378 j = 0;
6379 break;
6380 }
6381 }
6382 if (j != 0) {
6383 find_next_read_reg(i + 1, opcnt, xCX, OPLM_BYTE,
6384 i + opcnt * 27, &j);
6385 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6386 fnote(po, "ecx used after call\n");
6387 fnote(&ops[j], "(used here)\n");
6388 }
6389 }
6390 }
6391 break;
6392
6393 case OP_MOV:
6394 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6395 {
6396 // <var> = offset <something>
6397 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6398 && !IS_START(po->operand[1].name, "off_"))
6399 {
6400 if (!po->operand[0].pp->is_fptr)
6401 ferr(po, "%s not declared as fptr when it should be\n",
6402 po->operand[0].name);
6403 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6404 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6405 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6406 fnote(po, "var: %s\n", buf1);
6407 fnote(po, "func: %s\n", buf2);
6408 ferr(po, "^ mismatch\n");
6409 }
6410 }
6411 }
6412 break;
6413
6414 case OP_DIV:
6415 case OP_IDIV:
6416 if (po->operand[0].lmod == OPLM_DWORD) {
6417 // 32bit division is common, look for it
6418 if (po->op == OP_DIV)
6419 ret = scan_for_reg_clear(i, xDX);
6420 else
6421 ret = scan_for_cdq_edx(i);
6422 if (ret >= 0)
6423 po->flags |= OPF_32BIT;
6424 else
6425 need_tmp64 = 1;
6426 }
6427 else
6428 need_tmp_var = 1;
6429 break;
6430
6431 case OP_CLD:
6432 po->flags |= OPF_RMD | OPF_DONE;
6433 break;
6434
6435 case OP_RCL:
6436 case OP_RCR:
6437 case OP_XCHG:
6438 need_tmp_var = 1;
6439 break;
6440
6441 case OP_FLD:
6442 if (po->operand[0].lmod == OPLM_QWORD)
6443 need_double = 1;
6444 break;
6445
6446 case OP_RDTSC:
6447 case OPP_ALLSHL:
6448 case OPP_ALLSHR:
6449 need_tmp64 = 1;
6450 break;
6451
6452 case OPP_FTOL:
6453 find_next_read_reg(i + 1, opcnt, xDX, OPLM_DWORD,
6454 i + opcnt * 18, &j);
6455 if (j == -1)
6456 po->flags |= OPF_32BIT;
6457 break;
6458
6459 default:
6460 break;
6461 }
6462
6463 // this might need it's own pass...
6464 if (po->op != OP_FST && po->p_argnum > 0)
6465 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6466
6467 // correct for "full stack" mode late enable
6468 if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6469 && need_float_stack)
6470 po->flags |= OPF_FSHIFT;
6471 }
6472
6473 float_type = need_double ? "double" : "float";
6474 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6475 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6476
6477 // output starts here
6478
6479 if (g_seh_found)
6480 fprintf(fout, "// had SEH\n");
6481
6482 // define userstack size
6483 if (g_func_pp->is_userstack) {
6484 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6485 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6486 fprintf(fout, "#endif\n");
6487 }
6488
6489 // the function itself
6490 ferr_assert(ops, !g_func_pp->is_fptr);
6491 output_pp(fout, g_func_pp,
6492 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6493 fprintf(fout, "\n{\n");
6494
6495 // declare indirect functions
6496 for (i = 0; i < opcnt; i++) {
6497 po = &ops[i];
6498 if (po->flags & OPF_RMD)
6499 continue;
6500
6501 if (po->op == OP_CALL) {
6502 pp = po->pp;
6503 if (pp == NULL)
6504 ferr(po, "NULL pp\n");
6505
6506 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6507 if (pp->name[0] != 0) {
6508 if (IS_START(pp->name, "guess"))
6509 pp->is_guessed = 1;
6510
6511 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6512 memcpy(pp->name, "i_", 2);
6513
6514 // might be declared already
6515 found = 0;
6516 for (j = 0; j < i; j++) {
6517 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6518 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6519 found = 1;
6520 break;
6521 }
6522 }
6523 }
6524 if (found)
6525 continue;
6526 }
6527 else
6528 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6529
6530 fprintf(fout, " ");
6531 output_pp(fout, pp, OPP_SIMPLE_ARGS);
6532 fprintf(fout, ";\n");
6533 }
6534 }
6535 }
6536
6537 // output LUTs/jumptables
6538 for (i = 0; i < g_func_pd_cnt; i++) {
6539 pd = &g_func_pd[i];
6540 fprintf(fout, " static const ");
6541 if (pd->type == OPT_OFFSET) {
6542 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6543
6544 for (j = 0; j < pd->count; j++) {
6545 if (j > 0)
6546 fprintf(fout, ", ");
6547 fprintf(fout, "&&%s", pd->d[j].u.label);
6548 }
6549 }
6550 else {
6551 fprintf(fout, "%s %s[] =\n { ",
6552 lmod_type_u(ops, pd->lmod), pd->label);
6553
6554 for (j = 0; j < pd->count; j++) {
6555 if (j > 0)
6556 fprintf(fout, ", ");
6557 fprintf(fout, "%u", pd->d[j].u.val);
6558 }
6559 }
6560 fprintf(fout, " };\n");
6561 had_decl = 1;
6562 }
6563
6564 // declare stack frame, va_arg
6565 if (g_stack_fsz) {
6566 if (stack_fsz_adj)
6567 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6568
6569 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6570 if (g_func_lmods & (1 << OPLM_WORD))
6571 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6572 if (g_func_lmods & (1 << OPLM_BYTE))
6573 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6574 if (g_func_lmods & (1 << OPLM_QWORD))
6575 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6576
6577 if (stack_align > 8)
6578 ferr(ops, "unhandled stack align of %d\n", stack_align);
6579 else if (stack_align == 8)
6580 fprintf(fout, " u64 align;");
6581 fprintf(fout, " } sf;\n");
6582 had_decl = 1;
6583 }
6584
6585 if ((g_sct_func_attr & SCTFA_ARGFRAME) && g_func_pp->argc_stack) {
6586 fprintf(fout, " struct { u32 ");
6587 for (i = j = 0; i < g_func_pp->argc; i++) {
6588 if (g_func_pp->arg[i].reg != NULL)
6589 continue;
6590 if (j++ != 0)
6591 fprintf(fout, ", ");
6592 fprintf(fout, "a%d", i + 1);
6593 }
6594 fprintf(fout, "; } af = {\n ");
6595 for (i = j = 0; i < g_func_pp->argc; i++) {
6596 if (g_func_pp->arg[i].reg != NULL)
6597 continue;
6598 if (j++ != 0)
6599 fprintf(fout, ", ");
6600 if (g_func_pp->arg[i].type.is_ptr)
6601 fprintf(fout, "(u32)");
6602 fprintf(fout, "a%d", i + 1);
6603 }
6604 fprintf(fout, "\n };\n");
6605 }
6606
6607 if (g_func_pp->is_userstack) {
6608 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6609 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6610 had_decl = 1;
6611 }
6612
6613 if (g_func_pp->is_vararg) {
6614 fprintf(fout, " va_list ap;\n");
6615 had_decl = 1;
6616 }
6617
6618 // declare arg-registers
6619 for (i = 0; i < g_func_pp->argc; i++) {
6620 if (g_func_pp->arg[i].reg != NULL) {
6621 reg = char_array_i(regs_r32,
6622 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6623 if (regmask & (1 << reg)) {
6624 if (g_func_pp->arg[i].type.is_retreg)
6625 fprintf(fout, " u32 %s = *r_%s;\n",
6626 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6627 else
6628 fprintf(fout, " u32 %s = (u32)a%d;\n",
6629 g_func_pp->arg[i].reg, i + 1);
6630 }
6631 else {
6632 if (g_func_pp->arg[i].type.is_retreg)
6633 ferr(ops, "retreg '%s' is unused?\n",
6634 g_func_pp->arg[i].reg);
6635 fprintf(fout, " // %s = a%d; // unused\n",
6636 g_func_pp->arg[i].reg, i + 1);
6637 }
6638 had_decl = 1;
6639 }
6640 }
6641
6642 // declare normal registers
6643 regmask_now = regmask & ~regmask_arg & ~g_regmask_rm;
6644 regmask_now &= ~(1 << xSP);
6645 if (regmask_now & 0x00ff) {
6646 for (reg = 0; reg < 8; reg++) {
6647 if (regmask_now & (1 << reg)) {
6648 fprintf(fout, " u32 %s", regs_r32[reg]);
6649 if (regmask_init & (1 << reg))
6650 fprintf(fout, " = 0");
6651 fprintf(fout, ";\n");
6652 had_decl = 1;
6653 }
6654 }
6655 }
6656 // ... mmx
6657 if (regmask_now & 0xff00) {
6658 for (reg = 8; reg < 16; reg++) {
6659 if (regmask_now & (1 << reg)) {
6660 fprintf(fout, " mmxr %s", regs_r32[reg]);
6661 if (regmask_init & (1 << reg))
6662 fprintf(fout, " = { 0, }");
6663 fprintf(fout, ";\n");
6664 had_decl = 1;
6665 }
6666 }
6667 }
6668 // ... x87
6669 if (need_float_stack) {
6670 fprintf(fout, " %s f_st[8];\n", float_type);
6671 fprintf(fout, " int f_stp = 0;\n");
6672 had_decl = 1;
6673 }
6674 else {
6675 if (regmask_now & 0xff0000) {
6676 for (reg = 16; reg < 24; reg++) {
6677 if (regmask_now & (1 << reg)) {
6678 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6679 if (regmask_init & (1 << reg))
6680 fprintf(fout, " = 0");
6681 fprintf(fout, ";\n");
6682 had_decl = 1;
6683 }
6684 }
6685 }
6686 }
6687
6688 if (need_float_sw) {
6689 fprintf(fout, " u16 f_sw;\n");
6690 had_decl = 1;
6691 }
6692
6693 if (regmask_save) {
6694 for (reg = 0; reg < 8; reg++) {
6695 if (regmask_save & (1 << reg)) {
6696 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6697 had_decl = 1;
6698 }
6699 }
6700 }
6701
6702 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6703 if (save_arg_vars[i] == 0)
6704 continue;
6705 for (reg = 0; reg < 32; reg++) {
6706 if (save_arg_vars[i] & (1 << reg)) {
6707 fprintf(fout, " u32 %s;\n",
6708 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6709 had_decl = 1;
6710 }
6711 }
6712 }
6713
6714 if (regmask_ffca) {
6715 for (reg = 0; reg < 32; reg++) {
6716 if (regmask_ffca & (1 << reg)) {
6717 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6718 had_decl = 1;
6719 }
6720 }
6721 }
6722
6723 // declare push-pop temporaries
6724 if (regmask_pp) {
6725 for (reg = 0; reg < 8; reg++) {
6726 if (regmask_pp & (1 << reg)) {
6727 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6728 had_decl = 1;
6729 }
6730 }
6731 }
6732
6733 if (cond_vars) {
6734 for (i = 0; i < 8; i++) {
6735 if (cond_vars & (1 << i)) {
6736 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6737 had_decl = 1;
6738 }
6739 }
6740 }
6741
6742 if (need_tmp_var) {
6743 fprintf(fout, " u32 tmp;\n");
6744 had_decl = 1;
6745 }
6746
6747 if (need_tmp64) {
6748 fprintf(fout, " u64 tmp64;\n");
6749 had_decl = 1;
6750 }
6751
6752 if (had_decl)
6753 fprintf(fout, "\n");
6754
6755 // do stack clear, if needed
6756 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6757 fprintf(fout, " ");
6758 if (g_stack_clear_len != 0) {
6759 if (g_stack_clear_len <= 4) {
6760 for (i = 0; i < g_stack_clear_len; i++)
6761 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6762 fprintf(fout, "0;\n");
6763 }
6764 else {
6765 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6766 g_stack_clear_start, g_stack_clear_len * 4);
6767 }
6768 }
6769 else
6770 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6771 }
6772
6773 if (g_func_pp->is_vararg) {
6774 if (g_func_pp->argc_stack == 0)
6775 ferr(ops, "vararg func without stack args?\n");
6776 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6777 }
6778
6779 // output ops
6780 for (i = 0; i < opcnt; i++)
6781 {
6782 if (g_labels[i] != NULL) {
6783 fprintf(fout, "\n%s:\n", g_labels[i]);
6784 label_pending = 1;
6785
6786 delayed_flag_op = NULL;
6787 last_arith_dst = NULL;
6788 }
6789
6790 po = &ops[i];
6791 if (po->flags & OPF_RMD)
6792 continue;
6793
6794 lock_handled = 0;
6795 no_output = 0;
6796
6797 #define assert_operand_cnt(n_) \
6798 if (po->operand_cnt != n_) \
6799 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6800
6801 // conditional/flag using op?
6802 if (po->flags & OPF_CC)
6803 {
6804 int is_delayed = 0;
6805
6806 tmp_op = po->datap;
6807
6808 // we go through all this trouble to avoid using parsed_flag_op,
6809 // which makes generated code much nicer
6810 if (delayed_flag_op != NULL)
6811 {
6812 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6813 po->pfo, po->pfo_inv);
6814 is_delayed = 1;
6815 }
6816 else if (last_arith_dst != NULL
6817 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6818 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6819 ))
6820 {
6821 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6822 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6823 last_arith_dst->lmod, buf3);
6824 is_delayed = 1;
6825 }
6826 else if (tmp_op != NULL) {
6827 // use preprocessed flag calc results
6828 if (!(tmp_op->pfomask & (1 << po->pfo)))
6829 ferr(po, "not prepared for pfo %d\n", po->pfo);
6830
6831 // note: pfo_inv was not yet applied
6832 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6833 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6834 }
6835 else {
6836 ferr(po, "all methods of finding comparison failed\n");
6837 }
6838
6839 if (po->flags & OPF_JMP) {
6840 fprintf(fout, " if %s", buf1);
6841 }
6842 else if (po->op == OP_RCL || po->op == OP_RCR
6843 || po->op == OP_ADC || po->op == OP_SBB)
6844 {
6845 if (is_delayed)
6846 fprintf(fout, " cond_%s = %s;\n",
6847 parsed_flag_op_names[po->pfo], buf1);
6848 }
6849 else if (po->flags & OPF_DATA) { // SETcc
6850 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6851 fprintf(fout, " %s = %s;", buf2, buf1);
6852 }
6853 else {
6854 ferr(po, "unhandled conditional op\n");
6855 }
6856 }
6857
6858 pfomask = po->pfomask;
6859
6860 switch (po->op)
6861 {
6862 case OP_MOV:
6863 assert_operand_cnt(2);
6864 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6865 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6866 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6867 fprintf(fout, " %s = %s;", buf1,
6868 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6869 buf3, 0));
6870 break;
6871
6872 case OP_LEA:
6873 assert_operand_cnt(2);
6874 po->operand[1].lmod = OPLM_DWORD; // always
6875 fprintf(fout, " %s = %s;",
6876 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6877 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6878 NULL, 1));
6879 break;
6880
6881 case OP_MOVZX:
6882 assert_operand_cnt(2);
6883 fprintf(fout, " %s = %s;",
6884 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6885 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6886 break;
6887
6888 case OP_MOVSX:
6889 assert_operand_cnt(2);
6890 switch (po->operand[1].lmod) {
6891 case OPLM_BYTE:
6892 strcpy(buf3, "(s8)");
6893 break;
6894 case OPLM_WORD:
6895 strcpy(buf3, "(s16)");
6896 break;
6897 default:
6898 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6899 }
6900 fprintf(fout, " %s = %s;",
6901 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6902 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6903 buf3, 0));
6904 break;
6905
6906 case OP_XCHG:
6907 assert_operand_cnt(2);
6908 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6909 fprintf(fout, " tmp = %s;",
6910 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6911 fprintf(fout, " %s = %s;",
6912 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6913 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6914 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6915 fprintf(fout, " %s = %stmp;",
6916 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6917 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6918 snprintf(g_comment, sizeof(g_comment), "xchg");
6919 break;
6920
6921 case OP_NOT:
6922 assert_operand_cnt(1);
6923 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6924 fprintf(fout, " %s = ~%s;", buf1, buf1);
6925 break;
6926
6927 case OP_XLAT:
6928 assert_operand_cnt(2);
6929 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6930 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6931 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6932 strcpy(g_comment, "xlat");
6933 break;
6934
6935 case OP_CDQ:
6936 assert_operand_cnt(2);
6937 fprintf(fout, " %s = (s32)%s >> 31;",
6938 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6939 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6940 strcpy(g_comment, "cdq");
6941 break;
6942
6943 case OP_BSWAP:
6944 assert_operand_cnt(1);
6945 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6946 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6947 break;
6948
6949 case OP_LODS:
6950 if (po->flags & OPF_REP) {
6951 assert_operand_cnt(3);
6952 // hmh..
6953 ferr(po, "TODO\n");
6954 }
6955 else {
6956 assert_operand_cnt(2);
6957 fprintf(fout, " %s = %sesi; esi %c= %d;",
6958 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6959 lmod_cast_u_ptr(po, po->operand[1].lmod),
6960 (po->flags & OPF_DF) ? '-' : '+',
6961 lmod_bytes(po, po->operand[1].lmod));
6962 strcpy(g_comment, "lods");
6963 }
6964 break;
6965
6966 case OP_STOS:
6967 if (po->flags & OPF_REP) {
6968 assert_operand_cnt(3);
6969 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6970 (po->flags & OPF_DF) ? '-' : '+',
6971 lmod_bytes(po, po->operand[1].lmod));
6972 fprintf(fout, " %sedi = eax;\n",
6973 lmod_cast_u_ptr(po, po->operand[1].lmod));
6974 fprintf(fout, " barrier();");
6975 strcpy(g_comment, "^ rep stos");
6976 }
6977 else {
6978 assert_operand_cnt(2);
6979 fprintf(fout, " %sedi = eax; edi %c= %d;",
6980 lmod_cast_u_ptr(po, po->operand[1].lmod),
6981 (po->flags & OPF_DF) ? '-' : '+',
6982 lmod_bytes(po, po->operand[1].lmod));
6983 strcpy(g_comment, "stos");
6984 }
6985 break;
6986
6987 case OP_MOVS:
6988 j = lmod_bytes(po, po->operand[0].lmod);
6989 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6990 l = (po->flags & OPF_DF) ? '-' : '+';
6991 if (po->flags & OPF_REP) {
6992 assert_operand_cnt(3);
6993 fprintf(fout,
6994 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6995 l, j, l, j);
6996 fprintf(fout,
6997 " %sedi = %sesi;\n", buf1, buf1);
6998 // this can overwrite many variables
6999 fprintf(fout, " barrier();");
7000 strcpy(g_comment, "^ rep movs");
7001 }
7002 else {
7003 assert_operand_cnt(2);
7004 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
7005 buf1, buf1, l, j, l, j);
7006 strcpy(g_comment, "movs");
7007 }
7008 break;
7009
7010 case OP_CMPS:
7011 // repe ~ repeat while ZF=1
7012 j = lmod_bytes(po, po->operand[0].lmod);
7013 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
7014 l = (po->flags & OPF_DF) ? '-' : '+';
7015 if (po->flags & OPF_REP) {
7016 assert_operand_cnt(3);
7017 fprintf(fout,
7018 " while (ecx != 0) {\n");
7019 if (pfomask & (1 << PFO_C)) {
7020 // ugh..
7021 fprintf(fout,
7022 " cond_c = %sesi < %sedi;\n", buf1, buf1);
7023 pfomask &= ~(1 << PFO_C);
7024 }
7025 fprintf(fout,
7026 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
7027 buf1, buf1, l, j, l, j);
7028 fprintf(fout,
7029 " ecx--;\n"
7030 " if (cond_z %s 0) break;\n",
7031 (po->flags & OPF_REPZ) ? "==" : "!=");
7032 fprintf(fout,
7033 " }");
7034 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
7035 (po->flags & OPF_REPZ) ? "e" : "ne");
7036 }
7037 else {
7038 assert_operand_cnt(2);
7039 fprintf(fout,
7040 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
7041 buf1, buf1, l, j, l, j);
7042 strcpy(g_comment, "cmps");
7043 }
7044 pfomask &= ~(1 << PFO_Z);
7045 last_arith_dst = NULL;
7046 delayed_flag_op = NULL;
7047 break;
7048
7049 case OP_SCAS:
7050 // only does ZF (for now)
7051 // repe ~ repeat while ZF=1
7052 j = lmod_bytes(po, po->operand[1].lmod);
7053 l = (po->flags & OPF_DF) ? '-' : '+';
7054 if (po->flags & OPF_REP) {
7055 assert_operand_cnt(3);
7056 fprintf(fout,
7057 " while (ecx != 0) {\n");
7058 fprintf(fout,
7059 " cond_z = (%seax == %sedi); edi %c= %d;\n",
7060 lmod_cast_u(po, po->operand[1].lmod),
7061 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
7062 fprintf(fout,
7063 " ecx--;\n"
7064 " if (cond_z %s 0) break;\n",
7065 (po->flags & OPF_REPZ) ? "==" : "!=");
7066 fprintf(fout,
7067 " }");
7068 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
7069 (po->flags & OPF_REPZ) ? "e" : "ne");
7070 }
7071 else {
7072 assert_operand_cnt(2);
7073 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
7074 lmod_cast_u(po, po->operand[1].lmod),
7075 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
7076 strcpy(g_comment, "scas");
7077 }
7078 pfomask &= ~(1 << PFO_Z);
7079 last_arith_dst = NULL;
7080 delayed_flag_op = NULL;
7081 break;
7082
7083 case OP_RDTSC:
7084 fprintf(fout, " tmp64 = ext_rdtsc();\n");
7085 fprintf(fout, " edx = tmp64 >> 32;\n");
7086 fprintf(fout, " eax = tmp64;");
7087 break;
7088
7089 case OP_CPUID:
7090 fprintf(fout, " ext_cpuid(&eax, &ebx, &ecx, &edx);");
7091 break;
7092
7093 // arithmetic w/flags
7094 case OP_AND:
7095 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
7096 goto dualop_arith_const;
7097 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7098 goto dualop_arith;
7099
7100 case OP_OR:
7101 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7102 if (po->operand[1].type == OPT_CONST) {
7103 j = lmod_bytes(po, po->operand[0].lmod);
7104 if (((1ull << j * 8) - 1) == po->operand[1].val)
7105 goto dualop_arith_const;
7106 }
7107 goto dualop_arith;
7108
7109 dualop_arith:
7110 assert_operand_cnt(2);
7111 fprintf(fout, " %s %s= %s;",
7112 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7113 op_to_c(po),
7114 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7115 output_std_flags(fout, po, &pfomask, buf1);
7116 last_arith_dst = &po->operand[0];
7117 delayed_flag_op = NULL;
7118 break;
7119
7120 dualop_arith_const:
7121 // and 0, or ~0 used instead mov
7122 assert_operand_cnt(2);
7123 fprintf(fout, " %s = %s;",
7124 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7125 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7126 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7127 output_std_flags(fout, po, &pfomask, buf1);
7128 last_arith_dst = &po->operand[0];
7129 delayed_flag_op = NULL;
7130 break;
7131
7132 case OP_SHL:
7133 case OP_SHR:
7134 assert_operand_cnt(2);
7135 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7136 if (pfomask & (1 << PFO_C)) {
7137 if (po->operand[1].type == OPT_CONST) {
7138 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7139 j = po->operand[1].val;
7140 j %= l;
7141 if (j != 0) {
7142 if (po->op == OP_SHL)
7143 j = l - j;
7144 else
7145 j -= 1;
7146 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
7147 buf1, j);
7148 }
7149 else
7150 ferr(po, "zero shift?\n");
7151 }
7152 else
7153 ferr(po, "TODO\n");
7154 pfomask &= ~(1 << PFO_C);
7155 }
7156 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
7157 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7158 if (po->operand[1].type != OPT_CONST)
7159 fprintf(fout, " & 0x1f");
7160 fprintf(fout, ";");
7161 output_std_flags(fout, po, &pfomask, buf1);
7162 last_arith_dst = &po->operand[0];
7163 delayed_flag_op = NULL;
7164 break;
7165
7166 case OP_SAR:
7167 assert_operand_cnt(2);
7168 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7169 fprintf(fout, " %s = %s%s >> %s;", buf1,
7170 lmod_cast_s(po, po->operand[0].lmod), buf1,
7171 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7172 output_std_flags(fout, po, &pfomask, buf1);
7173 last_arith_dst = &po->operand[0];
7174 delayed_flag_op = NULL;
7175 break;
7176
7177 case OP_SHLD:
7178 case OP_SHRD:
7179 assert_operand_cnt(3);
7180 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7181 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7182 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
7183 if (po->operand[2].type != OPT_CONST) {
7184 // no handling for "undefined" case, hopefully not needed
7185 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
7186 strcpy(buf3, buf2);
7187 }
7188 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7189 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7190 if (po->op == OP_SHLD) {
7191 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
7192 buf1, buf3, buf1, buf2, l, buf3);
7193 strcpy(g_comment, "shld");
7194 }
7195 else {
7196 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
7197 buf1, buf3, buf1, buf2, l, buf3);
7198 strcpy(g_comment, "shrd");
7199 }
7200 output_std_flags(fout, po, &pfomask, buf1);
7201 last_arith_dst = &po->operand[0];
7202 delayed_flag_op = NULL;
7203 break;
7204
7205 case OP_ROL:
7206 case OP_ROR:
7207 assert_operand_cnt(2);
7208 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7209 if (po->operand[1].type == OPT_CONST) {
7210 j = po->operand[1].val;
7211 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
7212 fprintf(fout, po->op == OP_ROL ?
7213 " %s = (%s << %d) | (%s >> %d);" :
7214 " %s = (%s >> %d) | (%s << %d);",
7215 buf1, buf1, j, buf1,
7216 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
7217 }
7218 else
7219 ferr(po, "TODO\n");
7220 output_std_flags(fout, po, &pfomask, buf1);
7221 last_arith_dst = &po->operand[0];
7222 delayed_flag_op = NULL;
7223 break;
7224
7225 case OP_RCL:
7226 case OP_RCR:
7227 assert_operand_cnt(2);
7228 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7229 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7230 if (po->operand[1].type == OPT_CONST) {
7231 j = po->operand[1].val % l;
7232 if (j == 0)
7233 ferr(po, "zero rotate\n");
7234 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
7235 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
7236 if (po->op == OP_RCL) {
7237 fprintf(fout,
7238 " %s = (%s << %d) | (cond_c << %d)",
7239 buf1, buf1, j, j - 1);
7240 if (j != 1)
7241 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
7242 }
7243 else {
7244 fprintf(fout,
7245 " %s = (%s >> %d) | (cond_c << %d)",
7246 buf1, buf1, j, l - j);
7247 if (j != 1)
7248 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
7249 }
7250 fprintf(fout, ";\n");
7251 fprintf(fout, " cond_c = tmp;");
7252 }
7253 else
7254 ferr(po, "TODO\n");
7255 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
7256 output_std_flags(fout, po, &pfomask, buf1);
7257 last_arith_dst = &po->operand[0];
7258 delayed_flag_op = NULL;
7259 break;
7260
7261 case OP_XOR:
7262 assert_operand_cnt(2);
7263 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7264 if (IS(opr_name(po, 0), opr_name(po, 1))) {
7265 // special case for XOR
7266 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
7267 for (j = 0; j <= PFO_LE; j++) {
7268 if (pfomask & (1 << j)) {
7269 fprintf(fout, " cond_%s = %d;\n",
7270 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
7271 pfomask &= ~(1 << j);
7272 }
7273 }
7274 fprintf(fout, " %s = 0;",
7275 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7276 last_arith_dst = &po->operand[0];
7277 delayed_flag_op = NULL;
7278 break;
7279 }
7280 goto dualop_arith;
7281
7282 case OP_ADD:
7283 assert_operand_cnt(2);
7284 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7285 if (pfomask & (1 << PFO_C)) {
7286 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7287 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7288 if (po->operand[0].lmod == OPLM_DWORD) {
7289 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
7290 fprintf(fout, " cond_c = tmp64 >> 32;\n");
7291 fprintf(fout, " %s = (u32)tmp64;",
7292 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7293 strcat(g_comment, " add64");
7294 }
7295 else {
7296 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
7297 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
7298 fprintf(fout, " %s += %s;",
7299 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7300 buf2);
7301 }
7302 pfomask &= ~(1 << PFO_C);
7303 output_std_flags(fout, po, &pfomask, buf1);
7304 last_arith_dst = &po->operand[0];
7305 delayed_flag_op = NULL;
7306 break;
7307 }
7308 if (pfomask & (1 << PFO_LE)) {
7309 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
7310 fprintf(fout, " cond_%s = %s;\n",
7311 parsed_flag_op_names[PFO_LE], buf1);
7312 pfomask &= ~(1 << PFO_LE);
7313 }
7314 goto dualop_arith;
7315
7316 case OP_SUB:
7317 assert_operand_cnt(2);
7318 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7319 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
7320 for (j = 0; j <= PFO_LE; j++) {
7321 if (!(pfomask & (1 << j)))
7322 continue;
7323 if (j == PFO_Z || j == PFO_S)
7324 continue;
7325
7326 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7327 fprintf(fout, " cond_%s = %s;\n",
7328 parsed_flag_op_names[j], buf1);
7329 pfomask &= ~(1 << j);
7330 }
7331 }
7332 goto dualop_arith;
7333
7334 case OP_ADC:
7335 case OP_SBB:
7336 assert_operand_cnt(2);
7337 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7338 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7339 if (po->op == OP_SBB
7340 && IS(po->operand[0].name, po->operand[1].name))
7341 {
7342 // avoid use of unitialized var
7343 fprintf(fout, " %s = -cond_c;", buf1);
7344 // carry remains what it was
7345 pfomask &= ~(1 << PFO_C);
7346 }
7347 else {
7348 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
7349 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7350 }
7351 output_std_flags(fout, po, &pfomask, buf1);
7352 last_arith_dst = &po->operand[0];
7353 delayed_flag_op = NULL;
7354 break;
7355
7356 case OP_BSF:
7357 case OP_BSR:
7358 // on SKL, if src is 0, dst is left unchanged
7359 assert_operand_cnt(2);
7360 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7361 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7362 output_std_flag_z(fout, po, &pfomask, buf2);
7363 if (po->op == OP_BSF)
7364 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
7365 else
7366 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
7367 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
7368 last_arith_dst = &po->operand[0];
7369 delayed_flag_op = NULL;
7370 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
7371 break;
7372
7373 case OP_DEC:
7374 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
7375 for (j = 0; j <= PFO_LE; j++) {
7376 if (!(pfomask & (1 << j)))
7377 continue;
7378 if (j == PFO_Z || j == PFO_S || j == PFO_C)
7379 continue;
7380
7381 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7382 fprintf(fout, " cond_%s = %s;\n",
7383 parsed_flag_op_names[j], buf1);
7384 pfomask &= ~(1 << j);
7385 }
7386 }
7387 // fallthrough
7388
7389 case OP_INC:
7390 if (pfomask & (1 << PFO_C))
7391 // carry is unaffected by inc/dec.. wtf?
7392 ferr(po, "carry propagation needed\n");
7393
7394 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7395 if (po->operand[0].type == OPT_REG) {
7396 ferr_assert(po, !(po->flags & OPF_LOCK));
7397 strcpy(buf2, po->op == OP_INC ? "++" : "--");
7398 fprintf(fout, " %s%s;", buf1, buf2);
7399 }
7400 else if (po->flags & OPF_LOCK) {
7401 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], "", 1);
7402 fprintf(fout, " __sync_fetch_and_%s((%s *)(%s), 1);",
7403 po->op == OP_INC ? "add" : "sub",
7404 lmod_type_u(po, po->operand[0].lmod), buf2);
7405 strcat(g_comment, " lock");
7406 lock_handled = 1;
7407 }
7408 else {
7409 strcpy(buf2, po->op == OP_INC ? "+" : "-");
7410 fprintf(fout, " %s %s= 1;", buf1, buf2);
7411 }
7412 output_std_flags(fout, po, &pfomask, buf1);
7413 last_arith_dst = &po->operand[0];
7414 delayed_flag_op = NULL;
7415 break;
7416
7417 case OP_NEG:
7418 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7419 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
7420 fprintf(fout, " %s = -%s%s;", buf1,
7421 lmod_cast_s(po, po->operand[0].lmod), buf2);
7422 last_arith_dst = &po->operand[0];
7423 delayed_flag_op = NULL;
7424 if (pfomask & PFOB_C) {
7425 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
7426 pfomask &= ~PFOB_C;
7427 }
7428 output_std_flags(fout, po, &pfomask, buf1);
7429 break;
7430
7431 case OP_IMUL:
7432 if (po->operand_cnt == 2) {
7433 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7434 goto dualop_arith;
7435 }
7436 if (po->operand_cnt == 3)
7437 ferr(po, "TODO imul3\n");
7438 // fallthrough
7439 case OP_MUL:
7440 assert_operand_cnt(1);
7441 switch (po->operand[0].lmod) {
7442 case OPLM_DWORD:
7443 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7444 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
7445 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7446 fprintf(fout, " edx = tmp64 >> 32;\n");
7447 fprintf(fout, " eax = tmp64;");
7448 break;
7449 case OPLM_BYTE:
7450 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7451 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
7452 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7453 buf1, 0));
7454 break;
7455 default:
7456 ferr(po, "TODO: unhandled mul type\n");
7457 break;
7458 }
7459 last_arith_dst = NULL;
7460 delayed_flag_op = NULL;
7461 break;
7462
7463 case OP_DIV:
7464 case OP_IDIV:
7465 assert_operand_cnt(1);
7466 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7467 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7468 po->op == OP_IDIV));
7469 switch (po->operand[0].lmod) {
7470 case OPLM_DWORD:
7471 if (po->flags & OPF_32BIT)
7472 snprintf(buf2, sizeof(buf2), "%seax", cast);
7473 else {
7474 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7475 snprintf(buf2, sizeof(buf2), "%stmp64",
7476 (po->op == OP_IDIV) ? "(s64)" : "");
7477 }
7478 if (po->operand[0].type == OPT_REG
7479 && po->operand[0].reg == xDX)
7480 {
7481 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
7482 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
7483 }
7484 else {
7485 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
7486 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
7487 }
7488 break;
7489 case OPLM_WORD:
7490 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
7491 snprintf(buf2, sizeof(buf2), "%stmp",
7492 (po->op == OP_IDIV) ? "(s32)" : "");
7493 if (po->operand[0].type == OPT_REG
7494 && po->operand[0].reg == xDX)
7495 {
7496 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
7497 buf2, cast, buf1);
7498 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
7499 buf2, cast, buf1);
7500 }
7501 else {
7502 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
7503 buf2, cast, buf1);
7504 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
7505 buf2, cast, buf1);
7506 }
7507 strcat(g_comment, " div16");
7508 break;
7509 default:
7510 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7511 }
7512 last_arith_dst = NULL;
7513 delayed_flag_op = NULL;
7514 break;
7515
7516 case OP_TEST:
7517 case OP_CMP:
7518 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7519 if (pfomask != 0) {
7520 for (j = 0; j < 8; j++) {
7521 if (pfomask & (1 << j)) {
7522 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7523 fprintf(fout, " cond_%s = %s;",
7524 parsed_flag_op_names[j], buf1);
7525 }
7526 }
7527 pfomask = 0;
7528 }
7529 else
7530 no_output = 1;
7531 last_arith_dst = NULL;
7532 delayed_flag_op = po;
7533 break;
7534
7535 case OP_SCC:
7536 // SETcc - should already be handled
7537 break;
7538
7539 // note: we reuse OP_Jcc for SETcc, only flags differ
7540 case OP_JCC:
7541 fprintf(fout, "\n goto %s;", po->operand[0].name);
7542 break;
7543
7544 case OP_JECXZ:
7545 fprintf(fout, " if (ecx == 0)\n");
7546 fprintf(fout, " goto %s;", po->operand[0].name);
7547 strcat(g_comment, " jecxz");
7548 break;
7549
7550 case OP_LOOP:
7551 fprintf(fout, " if (--ecx != 0)\n");
7552 fprintf(fout, " goto %s;", po->operand[0].name);
7553 strcat(g_comment, " loop");
7554 break;
7555
7556 case OP_JMP:
7557 assert_operand_cnt(1);
7558 last_arith_dst = NULL;
7559 delayed_flag_op = NULL;
7560
7561 if (po->operand[0].type == OPT_REGMEM) {
7562 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7563 buf1, buf2);
7564 if (ret != 2)
7565 ferr(po, "parse failure for jmp '%s'\n",
7566 po->operand[0].name);
7567 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
7568 break;
7569 }
7570 else if (po->operand[0].type != OPT_LABEL)
7571 ferr(po, "unhandled jmp type\n");
7572
7573 fprintf(fout, " goto %s;", po->operand[0].name);
7574 break;
7575
7576 case OP_CALL:
7577 assert_operand_cnt(1);
7578 pp = po->pp;
7579 my_assert_not(pp, NULL);
7580
7581 strcpy(buf3, " ");
7582 if (po->flags & OPF_CC) {
7583 // we treat conditional branch to another func
7584 // (yes such code exists..) as conditional tailcall
7585 strcat(buf3, " ");
7586 fprintf(fout, " {\n");
7587 }
7588
7589 if (pp->is_fptr && !pp->is_arg) {
7590 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7591 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7592 "(void *)", 0));
7593 }
7594 if (pp->is_fptr && (pp->is_unresolved || pp->is_guessed)) {
7595 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7596 buf3, asmfn, po->asmln, pp->name);
7597 }
7598
7599 fprintf(fout, "%s", buf3);
7600 if (strstr(pp->ret_type.name, "int64")) {
7601 if (po->flags & OPF_TAIL)
7602 ferr(po, "int64 and tail?\n");
7603 fprintf(fout, "tmp64 = ");
7604 }
7605 else if (!IS(pp->ret_type.name, "void")) {
7606 if (po->flags & OPF_TAIL) {
7607 if (regmask_ret & mxAX) {
7608 fprintf(fout, "return ");
7609 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7610 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7611 }
7612 else if (regmask_ret & mxST0)
7613 ferr(po, "float tailcall\n");
7614 }
7615 else if (po->regmask_dst & mxAX) {
7616 fprintf(fout, "eax = ");
7617 if (pp->ret_type.is_ptr)
7618 fprintf(fout, "(u32)");
7619 }
7620 else if (po->regmask_dst & mxST0) {
7621 ferr_assert(po, po->flags & OPF_FPUSH);
7622 if (need_float_stack)
7623 fprintf(fout, "f_st[--f_stp & 7] = ");
7624 else
7625 fprintf(fout, "f_st0 = ");
7626 }
7627 }
7628
7629 if (pp->name[0] == 0)
7630 ferr(po, "missing pp->name\n");
7631 fprintf(fout, "%s%s(", pp->name,
7632 pp->has_structarg ? "_sa" : "");
7633
7634 if (po->flags & OPF_ATAIL) {
7635 int check_compat =
7636 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7637 check_compat |= pp->argc_stack > 0;
7638 if (check_compat
7639 && (pp->argc_stack != g_func_pp->argc_stack
7640 || pp->is_stdcall != g_func_pp->is_stdcall))
7641 ferr(po, "incompatible arg-reuse tailcall\n");
7642 if (g_func_pp->has_retreg)
7643 ferr(po, "TODO: retreg+tailcall\n");
7644
7645 for (arg = j = 0; arg < pp->argc; arg++) {
7646 if (arg > 0)
7647 fprintf(fout, ", ");
7648
7649 cast[0] = 0;
7650 if (pp->arg[arg].type.is_ptr)
7651 snprintf(cast, sizeof(cast), "(%s)",
7652 pp->arg[arg].type.name);
7653
7654 if (pp->arg[arg].reg != NULL) {
7655 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7656 continue;
7657 }
7658 // stack arg
7659 for (; j < g_func_pp->argc; j++)
7660 if (g_func_pp->arg[j].reg == NULL)
7661 break;
7662 fprintf(fout, "%sa%d", cast, j + 1);
7663 j++;
7664 }
7665 }
7666 else {
7667 for (arg = 0; arg < pp->argc; arg++) {
7668 if (arg > 0)
7669 fprintf(fout, ", ");
7670
7671 cast[0] = 0;
7672 if (pp->arg[arg].type.is_ptr)
7673 snprintf(cast, sizeof(cast), "(%s)",
7674 pp->arg[arg].type.name);
7675
7676 if (pp->arg[arg].reg != NULL) {
7677 if (pp->arg[arg].type.is_retreg)
7678 fprintf(fout, "&%s", pp->arg[arg].reg);
7679 else if (IS(pp->arg[arg].reg, "ebp")
7680 && g_bp_frame && !(po->flags & OPF_EBP_S))
7681 {
7682 // rare special case
7683 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7684 strcat(g_comment, " bp_ref");
7685 }
7686 else
7687 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7688 continue;
7689 }
7690
7691 // stack arg
7692 tmp_op = pp->arg[arg].datap;
7693 if (tmp_op == NULL)
7694 ferr(po, "parsed_op missing for arg%d\n", arg);
7695
7696 if (tmp_op->flags & OPF_VAPUSH) {
7697 fprintf(fout, "ap");
7698 }
7699 else if (tmp_op->op == OP_FST) {
7700 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7701 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7702 arg++;
7703 }
7704 else if (pp->arg[arg].type.is_64bit) {
7705 ferr_assert(po, tmp_op->p_argpass == 0);
7706 ferr_assert(po, !pp->arg[arg].is_saved);
7707 ferr_assert(po, !pp->arg[arg].type.is_float);
7708 ferr_assert(po, cast[0] == 0);
7709 out_src_opr(buf1, sizeof(buf1),
7710 tmp_op, &tmp_op->operand[0], cast, 0);
7711 tmp_op = pp->arg[++arg].datap;
7712 ferr_assert(po, tmp_op != NULL);
7713 out_src_opr(buf2, sizeof(buf2),
7714 tmp_op, &tmp_op->operand[0], cast, 0);
7715 fprintf(fout, "((u64)(%s) << 32) | (%s)",
7716 buf2, buf1);
7717 }
7718 else if (tmp_op->p_argpass != 0) {
7719 ferr_assert(po, !pp->arg[arg].type.is_float);
7720 fprintf(fout, "a%d", tmp_op->p_argpass);
7721 }
7722 else if (pp->arg[arg].is_saved) {
7723 ferr_assert(po, tmp_op->p_argnum > 0);
7724 ferr_assert(po, !pp->arg[arg].type.is_float);
7725 fprintf(fout, "%s%s", cast,
7726 saved_arg_name(buf1, sizeof(buf1),
7727 tmp_op->p_arggrp, tmp_op->p_argnum));
7728 }
7729 else if (pp->arg[arg].type.is_float) {
7730 ferr_assert(po, !pp->arg[arg].type.is_64bit);
7731 fprintf(fout, "%s",
7732 out_src_opr_float(buf1, sizeof(buf1),
7733 tmp_op, &tmp_op->operand[0], need_float_stack));
7734 }
7735 else {
7736 fprintf(fout, "%s",
7737 out_src_opr(buf1, sizeof(buf1),
7738 tmp_op, &tmp_op->operand[0], cast, 0));
7739 }
7740 }
7741 }
7742 fprintf(fout, ");");
7743
7744 if (strstr(pp->ret_type.name, "int64")) {
7745 fprintf(fout, "\n");
7746 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7747 fprintf(fout, "%seax = tmp64;", buf3);
7748 }
7749
7750 if (pp->is_unresolved) {
7751 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7752 pp->argc_reg);
7753 strcat(g_comment, buf2);
7754 }
7755
7756 if (po->flags & OPF_TAIL) {
7757 ret = 0;
7758 if (i == opcnt - 1 || pp->is_noreturn)
7759 ret = 0;
7760 else if (IS(pp->ret_type.name, "void"))
7761 ret = 1;
7762 else if (!(regmask_ret & (1 << xAX)))
7763 ret = 1;
7764 // else already handled as 'return f()'
7765
7766 if (ret) {
7767 fprintf(fout, "\n%sreturn;", buf3);
7768 strcat(g_comment, " ^ tailcall");
7769 }
7770 else
7771 strcat(g_comment, " tailcall");
7772
7773 if ((regmask_ret & (1 << xAX))
7774 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7775 {
7776 ferr(po, "int func -> void func tailcall?\n");
7777 }
7778 }
7779 if (pp->is_noreturn)
7780 strcat(g_comment, " noreturn");
7781 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7782 strcat(g_comment, " argframe");
7783 if (po->flags & OPF_CC)
7784 strcat(g_comment, " cond");
7785
7786 if (po->flags & OPF_CC)
7787 fprintf(fout, "\n }");
7788
7789 delayed_flag_op = NULL;
7790 last_arith_dst = NULL;
7791 break;
7792
7793 case OP_RET:
7794 if (g_func_pp->is_vararg)
7795 fprintf(fout, " va_end(ap);\n");
7796 if (g_func_pp->has_retreg) {
7797 for (arg = 0; arg < g_func_pp->argc; arg++)
7798 if (g_func_pp->arg[arg].type.is_retreg)
7799 fprintf(fout, " *r_%s = %s;\n",
7800 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7801 }
7802
7803 if (regmask_ret & mxST0) {
7804 fprintf(fout, " return %s;", float_st0);
7805 }
7806 else if (!(regmask_ret & mxAX)) {
7807 if (i != opcnt - 1 || label_pending)
7808 fprintf(fout, " return;");
7809 }
7810 else if (g_func_pp->ret_type.is_ptr) {
7811 fprintf(fout, " return (%s)eax;",
7812 g_func_pp->ret_type.name);
7813 }
7814 else if (IS(g_func_pp->ret_type.name, "__int64"))
7815 fprintf(fout, " return ((u64)edx << 32) | eax;");
7816 else
7817 fprintf(fout, " return eax;");
7818
7819 last_arith_dst = NULL;
7820 delayed_flag_op = NULL;
7821 break;
7822
7823 case OP_PUSH:
7824 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7825 if (po->p_argnum != 0) {
7826 // special case - saved func arg
7827 fprintf(fout, " %s = %s;",
7828 saved_arg_name(buf2, sizeof(buf2),
7829 po->p_arggrp, po->p_argnum), buf1);
7830 break;
7831 }
7832 else if (po->flags & OPF_RSAVE) {
7833 fprintf(fout, " s_%s = %s;", buf1, buf1);
7834 break;
7835 }
7836 else if (po->flags & OPF_PPUSH) {
7837 tmp_op = po->datap;
7838 ferr_assert(po, tmp_op != NULL);
7839 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7840 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7841 break;
7842 }
7843 else if (g_func_pp->is_userstack) {
7844 fprintf(fout, " *(--esp) = %s;", buf1);
7845 break;
7846 }
7847 if (!(g_ida_func_attr & IDAFA_NORETURN))
7848 ferr(po, "stray push encountered\n");
7849 no_output = 1;
7850 break;
7851
7852 case OP_POP:
7853 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7854 if (po->flags & OPF_RSAVE) {
7855 fprintf(fout, " %s = s_%s;", buf1, buf1);
7856 break;
7857 }
7858 else if (po->flags & OPF_PPUSH) {
7859 // push/pop graph / non-const
7860 ferr_assert(po, po->datap == NULL);
7861 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7862 break;
7863 }
7864 else if (po->datap != NULL) {
7865 // push/pop pair
7866 tmp_op = po->datap;
7867 fprintf(fout, " %s = %s;", buf1,
7868 out_src_opr(buf2, sizeof(buf2),
7869 tmp_op, &tmp_op->operand[0],
7870 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7871 break;
7872 }
7873 else if (g_func_pp->is_userstack) {
7874 fprintf(fout, " %s = *esp++;", buf1);
7875 break;
7876 }
7877 else
7878 ferr(po, "stray pop encountered\n");
7879 break;
7880
7881 case OP_NOP:
7882 no_output = 1;
7883 break;
7884
7885 // pseudo ops
7886 case OPP_ALLSHL:
7887 case OPP_ALLSHR:
7888 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7889 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7890 po->op == OPP_ALLSHL ? "<<" : ">>");
7891 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7892 strcat(g_comment, po->op == OPP_ALLSHL
7893 ? " allshl" : " allshr");
7894 break;
7895
7896 // x87
7897 case OP_FLD:
7898 if (need_float_stack) {
7899 out_src_opr_float(buf1, sizeof(buf1),
7900 po, &po->operand[0], 1);
7901 if (po->regmask_src & mxSTa) {
7902 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7903 buf1);
7904 }
7905 else
7906 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7907 }
7908 else {
7909 if (po->flags & OPF_FSHIFT)
7910 fprintf(fout, " f_st1 = f_st0;");
7911 if (po->operand[0].type == OPT_REG
7912 && po->operand[0].reg == xST0)
7913 {
7914 strcat(g_comment, " fld st");
7915 break;
7916 }
7917 fprintf(fout, " f_st0 = %s;",
7918 out_src_opr_float(buf1, sizeof(buf1),
7919 po, &po->operand[0], 0));
7920 }
7921 strcat(g_comment, " fld");
7922 break;
7923
7924 case OP_FILD:
7925 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7926 lmod_cast(po, po->operand[0].lmod, 1), 0);
7927 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7928 if (need_float_stack) {
7929 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7930 }
7931 else {
7932 if (po->flags & OPF_FSHIFT)
7933 fprintf(fout, " f_st1 = f_st0;");
7934 fprintf(fout, " f_st0 = %s;", buf2);
7935 }
7936 strcat(g_comment, " fild");
7937 break;
7938
7939 case OP_FLDc:
7940 if (need_float_stack)
7941 fprintf(fout, " f_st[--f_stp & 7] = ");
7942 else {
7943 if (po->flags & OPF_FSHIFT)
7944 fprintf(fout, " f_st1 = f_st0;");
7945 fprintf(fout, " f_st0 = ");
7946 }
7947 switch (po->operand[0].val) {
7948 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7949 case X87_CONST_L2T: fprintf(fout, "3.321928094887362;"); break;
7950 case X87_CONST_L2E: fprintf(fout, "M_LOG2E;"); break;
7951 case X87_CONST_PI: fprintf(fout, "M_PI;"); break;
7952 case X87_CONST_LG2: fprintf(fout, "0.301029995663981;"); break;
7953 case X87_CONST_LN2: fprintf(fout, "M_LN2;"); break;
7954 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7955 default: ferr_assert(po, 0); break;
7956 }
7957 break;
7958
7959 case OP_FST:
7960 if (po->flags & OPF_FARG) {
7961 // store to stack as func arg
7962 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7963 dead_dst = 0;
7964 }
7965 else {
7966 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7967 need_float_stack);
7968 dead_dst = po->operand[0].type == OPT_REG
7969 && po->operand[0].reg == xST0;
7970 }
7971 if (!dead_dst)
7972 fprintf(fout, " %s = %s;", buf1, float_st0);
7973 if (po->flags & OPF_FSHIFT) {
7974 if (need_float_stack)
7975 fprintf(fout, " f_stp++;");
7976 else
7977 fprintf(fout, " f_st0 = f_st1;");
7978 }
7979 if (dead_dst && !(po->flags & OPF_FSHIFT))
7980 no_output = 1;
7981 else
7982 strcat(g_comment, " fst");
7983 break;
7984
7985 case OP_FIST:
7986 fprintf(fout, " %s = %s%s;",
7987 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7988 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7989 if (po->flags & OPF_FSHIFT) {
7990 if (need_float_stack)
7991 fprintf(fout, " f_stp++;");
7992 else
7993 fprintf(fout, " f_st0 = f_st1;");
7994 }
7995 strcat(g_comment, " fist");
7996 break;
7997
7998 case OP_FADD:
7999 case OP_FDIV:
8000 case OP_FMUL:
8001 case OP_FSUB:
8002 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8003 need_float_stack);
8004 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8005 need_float_stack);
8006 dead_dst = (po->flags & OPF_FPOP)
8007 && po->operand[0].type == OPT_REG
8008 && po->operand[0].reg == xST0;
8009 switch (po->op) {
8010 case OP_FADD: j = '+'; break;
8011 case OP_FDIV: j = '/'; break;
8012 case OP_FMUL: j = '*'; break;
8013 case OP_FSUB: j = '-'; break;
8014 default: j = 'x'; break;
8015 }
8016 if (need_float_stack) {
8017 if (!dead_dst)
8018 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
8019 if (po->flags & OPF_FSHIFT)
8020 fprintf(fout, " f_stp++;");
8021 }
8022 else {
8023 if (po->flags & OPF_FSHIFT) {
8024 // note: assumes only 2 regs handled
8025 if (!dead_dst)
8026 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
8027 else
8028 fprintf(fout, " f_st0 = f_st1;");
8029 }
8030 else if (!dead_dst)
8031 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
8032 }
8033 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
8034 break;
8035
8036 case OP_FDIVR:
8037 case OP_FSUBR:
8038 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8039 need_float_stack);
8040 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8041 need_float_stack);
8042 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
8043 need_float_stack);
8044 dead_dst = (po->flags & OPF_FPOP)
8045 && po->operand[0].type == OPT_REG
8046 && po->operand[0].reg == xST0;
8047 j = po->op == OP_FDIVR ? '/' : '-';
8048 if (need_float_stack) {
8049 if (!dead_dst)
8050 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
8051 if (po->flags & OPF_FSHIFT)
8052 fprintf(fout, " f_stp++;");
8053 }
8054 else {
8055 if (po->flags & OPF_FSHIFT) {
8056 if (!dead_dst)
8057 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
8058 else
8059 fprintf(fout, " f_st0 = f_st1;");
8060 }
8061 else if (!dead_dst)
8062 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
8063 }
8064 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
8065 break;
8066
8067 case OP_FIADD:
8068 case OP_FIDIV:
8069 case OP_FIMUL:
8070 case OP_FISUB:
8071 switch (po->op) {
8072 case OP_FIADD: j = '+'; break;
8073 case OP_FIDIV: j = '/'; break;
8074 case OP_FIMUL: j = '*'; break;
8075 case OP_FISUB: j = '-'; break;
8076 default: j = 'x'; break;
8077 }
8078 fprintf(fout, " %s %c= (%s)%s;", float_st0,
8079 j, float_type,
8080 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
8081 lmod_cast(po, po->operand[0].lmod, 1), 0));
8082 break;
8083
8084 case OP_FIDIVR:
8085 case OP_FISUBR:
8086 fprintf(fout, " %s = %s %c %s;", float_st0,
8087 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8088 need_float_stack),
8089 po->op == OP_FIDIVR ? '/' : '-', float_st0);
8090 break;
8091
8092 case OP_FCOM: {
8093 int mask, z_check;
8094 ferr_assert(po, po->datap != NULL);
8095 mask = (long)po->datap & 0xffff;
8096 z_check = ((long)po->datap >> 16) & 1;
8097 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8098 need_float_stack);
8099 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
8100 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
8101 float_st0, buf1);
8102 }
8103 else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
8104 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
8105 float_st0, buf1);
8106 }
8107 else if (mask == 0x4100) { // C3, C0
8108 if (z_check) {
8109 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
8110 float_st0, buf1);
8111 strcat(g_comment, " z_chk_det");
8112 }
8113 else {
8114 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
8115 "(%s < %s ? 0x0100 : 0);",
8116 float_st0, buf1, float_st0, buf1);
8117 }
8118 }
8119 else
8120 ferr(po, "unhandled sw mask: %x\n", mask);
8121 if (po->flags & OPF_FSHIFT) {
8122 if (need_float_stack) {
8123 if (po->flags & OPF_FPOPP)
8124 fprintf(fout, " f_stp += 2;");
8125 else
8126 fprintf(fout, " f_stp++;");
8127 }
8128 else {
8129 ferr_assert(po, !(po->flags & OPF_FPOPP));
8130 fprintf(fout, " f_st0 = f_st1;");
8131 }
8132 }
8133 break;
8134 }
8135
8136 case OP_FNSTSW:
8137 fprintf(fout, " %s = f_sw;",
8138 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
8139 break;
8140
8141 case OP_FCHS:
8142 fprintf(fout, " %s = -%s;", float_st0, float_st0);
8143 break;
8144
8145 case OP_FCOS:
8146 fprintf(fout, " %s = cos%s(%s);", float_st0,
8147 need_double ? "" : "f", float_st0);
8148 break;
8149
8150 case OP_FPATAN:
8151 if (need_float_stack) {
8152 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
8153 need_double ? "" : "f", float_st1, float_st0);
8154 fprintf(fout, " f_stp++;");
8155 }
8156 else {
8157 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
8158 need_double ? "" : "f");
8159 }
8160 break;
8161
8162 case OP_FYL2X:
8163 if (need_float_stack) {
8164 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
8165 float_st1, need_double ? "" : "f", float_st0);
8166 fprintf(fout, " f_stp++;");
8167 }
8168 else {
8169 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
8170 need_double ? "" : "f");
8171 }
8172 strcat(g_comment, " fyl2x");
8173 break;
8174
8175 case OP_FSIN:
8176 fprintf(fout, " %s = sin%s(%s);", float_st0,
8177 need_double ? "" : "f", float_st0);
8178 break;
8179
8180 case OP_FSQRT:
8181 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
8182 need_double ? "" : "f", float_st0);
8183 break;
8184
8185 case OP_FXCH:
8186 dead_dst = po->operand[0].type == OPT_REG
8187 && po->operand[0].reg == xST0;
8188 if (!dead_dst) {
8189 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8190 need_float_stack);
8191 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
8192 float_st0, float_st0, buf1, buf1);
8193 strcat(g_comment, " fxch");
8194 }
8195 else
8196 no_output = 1;
8197 break;
8198
8199 case OPP_FTOL:
8200 ferr_assert(po, po->flags & OPF_32BIT);
8201 fprintf(fout, " eax = (s32)%s;", float_st0);
8202 if (po->flags & OPF_FSHIFT) {
8203 if (need_float_stack)
8204 fprintf(fout, " f_stp++;");
8205 else
8206 fprintf(fout, " f_st0 = f_st1;");
8207 }
8208 strcat(g_comment, " ftol");
8209 break;
8210
8211 case OPP_CIPOW:
8212 if (need_float_stack) {
8213 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
8214 need_double ? "" : "f", float_st1, float_st0);
8215 fprintf(fout, " f_stp++;");
8216 }
8217 else {
8218 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
8219 need_double ? "" : "f");
8220 }
8221 strcat(g_comment, " CIpow");
8222 break;
8223
8224 case OPP_ABORT:
8225 fprintf(fout, " do_skip_code_abort();");
8226 break;
8227
8228 // mmx
8229 case OP_EMMS:
8230 fprintf(fout, " do_emms();");
8231 break;
8232
8233 default:
8234 no_output = 1;
8235 ferr(po, "unhandled op type %d, flags %x\n",
8236 po->op, po->flags);
8237 break;
8238 }
8239
8240 if (g_comment[0] != 0) {
8241 char *p = g_comment;
8242 while (my_isblank(*p))
8243 p++;
8244 fprintf(fout, " // %s", p);
8245 g_comment[0] = 0;
8246 no_output = 0;
8247 }
8248 if (!no_output)
8249 fprintf(fout, "\n");
8250
8251 // some sanity checking
8252 if (po->flags & OPF_REP) {
8253 if (po->op != OP_STOS && po->op != OP_MOVS
8254 && po->op != OP_CMPS && po->op != OP_SCAS)
8255 ferr(po, "unexpected rep\n");
8256 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
8257 && (po->op == OP_CMPS || po->op == OP_SCAS))
8258 ferr(po, "cmps/scas with plain rep\n");
8259 }
8260 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
8261 && po->op != OP_CMPS && po->op != OP_SCAS)
8262 ferr(po, "unexpected repz/repnz\n");
8263
8264 if (pfomask != 0)
8265 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
8266
8267 if ((po->flags & OPF_LOCK) && !lock_handled)
8268 ferr(po, "unhandled lock\n");
8269
8270 // see is delayed flag stuff is still valid
8271 if (delayed_flag_op != NULL && delayed_flag_op != po) {
8272 if (is_any_opr_modified(delayed_flag_op, po, 0))
8273 delayed_flag_op = NULL;
8274 }
8275
8276 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
8277 if (is_opr_modified(last_arith_dst, po))
8278 last_arith_dst = NULL;
8279 }
8280
8281 if (!no_output)
8282 label_pending = 0;
8283 }
8284
8285 if (g_stack_fsz && !g_stack_frame_used)
8286 fprintf(fout, " (void)sf;\n");
8287
8288 fprintf(fout, "}\n\n");
8289
8290 gen_x_cleanup(opcnt);
8291}
8292
8293static void gen_x_cleanup(int opcnt)
8294{
8295 int i;
8296
8297 for (i = 0; i < opcnt; i++) {
8298 struct label_ref *lr, *lr_del;
8299
8300 lr = g_label_refs[i].next;
8301 while (lr != NULL) {
8302 lr_del = lr;
8303 lr = lr->next;
8304 free(lr_del);
8305 }
8306 g_label_refs[i].i = -1;
8307 g_label_refs[i].next = NULL;
8308
8309 if (ops[i].op == OP_CALL) {
8310 if (ops[i].pp)
8311 proto_release(ops[i].pp);
8312 }
8313 }
8314 g_func_pp = NULL;
8315}
8316
8317struct func_proto_dep;
8318
8319struct func_prototype {
8320 char name[NAMELEN];
8321 int id;
8322 int argc_stack;
8323 int regmask_dep; // likely register args
8324 int regmask_use; // used registers
8325 int has_ret:3; // -1, 0, 1: unresolved, no, yes
8326 unsigned int has_ret64:1;
8327 unsigned int dep_resolved:1;
8328 unsigned int is_stdcall:1;
8329 unsigned int eax_pass:1; // returns without touching eax
8330 struct func_proto_dep *dep_func;
8331 int dep_func_cnt;
8332 const struct parsed_proto *pp; // seed pp, if any
8333};
8334
8335struct func_proto_dep {
8336 char *name;
8337 struct func_prototype *proto;
8338 int regmask_live; // .. at the time of call
8339 unsigned int ret_dep:1; // return from this is caller's return
8340 unsigned int has_ret:1; // found from eax use after return
8341 unsigned int has_ret64:1;
8342};
8343
8344static struct func_prototype *hg_fp;
8345static int hg_fp_cnt;
8346
8347static struct scanned_var {
8348 char name[NAMELEN];
8349 enum opr_lenmod lmod;
8350 unsigned int is_seeded:1;
8351 unsigned int is_c_str:1;
8352 const struct parsed_proto *pp; // seed pp, if any
8353} *hg_vars;
8354static int hg_var_cnt;
8355
8356static char **hg_refs;
8357static int hg_ref_cnt;
8358
8359static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8360 int count);
8361
8362static struct func_prototype *hg_fp_add(const char *funcn)
8363{
8364 struct func_prototype *fp;
8365
8366 if ((hg_fp_cnt & 0xff) == 0) {
8367 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
8368 my_assert_not(hg_fp, NULL);
8369 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
8370 }
8371
8372 fp = &hg_fp[hg_fp_cnt];
8373 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
8374 fp->id = hg_fp_cnt;
8375 fp->argc_stack = -1;
8376 hg_fp_cnt++;
8377
8378 return fp;
8379}
8380
8381static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
8382 const char *name)
8383{
8384 int i;
8385
8386 for (i = 0; i < fp->dep_func_cnt; i++)
8387 if (IS(fp->dep_func[i].name, name))
8388 return &fp->dep_func[i];
8389
8390 return NULL;
8391}
8392
8393static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
8394{
8395 // is it a dupe?
8396 if (hg_fp_find_dep(fp, name))
8397 return;
8398
8399 if ((fp->dep_func_cnt & 0xff) == 0) {
8400 fp->dep_func = realloc(fp->dep_func,
8401 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
8402 my_assert_not(fp->dep_func, NULL);
8403 memset(&fp->dep_func[fp->dep_func_cnt], 0,
8404 sizeof(fp->dep_func[0]) * 0x100);
8405 }
8406 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
8407 fp->dep_func_cnt++;
8408}
8409
8410static int hg_fp_cmp_name(const void *p1_, const void *p2_)
8411{
8412 const struct func_prototype *p1 = p1_, *p2 = p2_;
8413 return strcmp(p1->name, p2->name);
8414}
8415
8416#if 0
8417static int hg_fp_cmp_id(const void *p1_, const void *p2_)
8418{
8419 const struct func_prototype *p1 = p1_, *p2 = p2_;
8420 return p1->id - p2->id;
8421}
8422#endif
8423
8424static void hg_ref_add(const char *name)
8425{
8426 if ((hg_ref_cnt & 0xff) == 0) {
8427 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8428 my_assert_not(hg_refs, NULL);
8429 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8430 }
8431
8432 hg_refs[hg_ref_cnt] = strdup(name);
8433 my_assert_not(hg_refs[hg_ref_cnt], NULL);
8434 hg_ref_cnt++;
8435}
8436
8437// recursive register dep pass
8438// - track saved regs (part 2)
8439// - try to figure out arg-regs
8440// - calculate reg deps
8441static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8442 struct func_prototype *fp, int regmask_save, int regmask_dst,
8443 int *regmask_dep, int *regmask_use, int *has_ret)
8444{
8445 struct func_proto_dep *dep;
8446 struct parsed_op *po;
8447 int from_caller = 0;
8448 int j, l;
8449 int reg;
8450 int ret;
8451
8452 for (; i < opcnt; i++)
8453 {
8454 if (cbits[i >> 3] & (1 << (i & 7)))
8455 return;
8456 cbits[i >> 3] |= (1 << (i & 7));
8457
8458 po = &ops[i];
8459
8460 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8461 if (po->flags & OPF_RMD)
8462 continue;
8463
8464 if (po->btj != NULL) {
8465 // jumptable
8466 for (j = 0; j < po->btj->count; j++) {
8467 check_i(po, po->btj->d[j].bt_i);
8468 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8469 regmask_save, regmask_dst, regmask_dep, regmask_use,
8470 has_ret);
8471 }
8472 return;
8473 }
8474
8475 check_i(po, po->bt_i);
8476 if (po->flags & OPF_CJMP) {
8477 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8478 regmask_save, regmask_dst, regmask_dep, regmask_use,
8479 has_ret);
8480 }
8481 else {
8482 i = po->bt_i - 1;
8483 }
8484 continue;
8485 }
8486
8487 if (po->flags & OPF_FARG)
8488 /* (just calculate register deps) */;
8489 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8490 {
8491 reg = po->operand[0].reg;
8492 ferr_assert(po, reg >= 0);
8493
8494 if (po->flags & OPF_RSAVE) {
8495 regmask_save |= 1 << reg;
8496 continue;
8497 }
8498 if (po->flags & OPF_DONE)
8499 continue;
8500
8501 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
8502 if (ret == 1) {
8503 regmask_save |= 1 << reg;
8504 po->flags |= OPF_RMD;
8505 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
8506 continue;
8507 }
8508 }
8509 else if (po->flags & OPF_RMD)
8510 continue;
8511 else if (po->op == OP_CALL) {
8512 po->regmask_dst |= 1 << xAX;
8513
8514 dep = hg_fp_find_dep(fp, po->operand[0].name);
8515 if (dep != NULL) {
8516 dep->regmask_live = regmask_save | regmask_dst;
8517 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8518 dep->regmask_live |= 1 << xBP;
8519 }
8520 }
8521 else if (po->op == OP_RET) {
8522 if (po->operand_cnt > 0) {
8523 fp->is_stdcall = 1;
8524 if (fp->argc_stack >= 0
8525 && fp->argc_stack != po->operand[0].val / 4)
8526 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8527 fp->argc_stack = po->operand[0].val / 4;
8528 }
8529 }
8530
8531 if (!fp->eax_pass && (po->flags & OPF_TAIL)) {
8532 if (po->op == OP_CALL) {
8533 j = i;
8534 ret = 1;
8535 }
8536 else {
8537 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
8538 j = -1;
8539 from_caller = 0;
8540 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
8541 }
8542
8543 if (ret != 1 && from_caller) {
8544 // unresolved eax - probably void func
8545 *has_ret = 0;
8546 fp->eax_pass = 1;
8547 }
8548 else {
8549 if (j >= 0 && ops[j].op == OP_CALL) {
8550 if (ops[j].pp != NULL && !ops[j].pp->is_unresolved) {
8551 int call_has_ret = !IS(ops[j].pp->ret_type.name, "void");
8552 if (ops[j].pp->is_noreturn) {
8553 // could be some fail path
8554 if (*has_ret == -1)
8555 *has_ret = call_has_ret;
8556 }
8557 else
8558 *has_ret = call_has_ret;
8559 }
8560 else {
8561 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8562 if (dep != NULL)
8563 dep->ret_dep = 1;
8564 else
8565 *has_ret = 1;
8566 }
8567 }
8568 else
8569 *has_ret = 1;
8570 }
8571 }
8572
8573 l = regmask_save | regmask_dst;
8574 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8575 l |= 1 << xBP;
8576
8577 l = po->regmask_src & ~l;
8578#if 0
8579 if (l)
8580 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8581 l, regmask_dst, regmask_save, po->flags);
8582#endif
8583 *regmask_dep |= l;
8584 *regmask_use |= (po->regmask_src | po->regmask_dst)
8585 & ~regmask_save;
8586 regmask_dst |= po->regmask_dst;
8587
8588 if (po->flags & OPF_TAIL) {
8589 if (!(po->flags & OPF_CC)) // not cond. tailcall
8590 return;
8591 }
8592 }
8593}
8594
8595static void gen_hdr(const char *funcn, int opcnt)
8596{
8597 unsigned char cbits[MAX_OPS / 8];
8598 const struct parsed_proto *pp_c;
8599 struct parsed_proto *pp;
8600 struct func_prototype *fp;
8601 struct func_proto_dep *dep;
8602 struct parsed_op *po;
8603 int regmask_dummy = 0;
8604 int regmask_dep;
8605 int regmask_use;
8606 int max_bp_offset = 0;
8607 int has_ret;
8608 int i, j, l;
8609 int ret;
8610
8611 pp_c = proto_parse(g_fhdr, funcn, 1);
8612 if (pp_c != NULL)
8613 // already in seed, will add to hg_fp later
8614 return;
8615
8616 fp = hg_fp_add(funcn);
8617
8618 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8619 g_stack_frame_used = 0;
8620 g_seh_size = 0;
8621
8622 // pass1:
8623 // - resolve all branches
8624 // - parse calls with labels
8625 resolve_branches_parse_calls(opcnt);
8626
8627 // pass2:
8628 // - handle ebp/esp frame, remove ops related to it
8629 scan_prologue_epilogue(opcnt, NULL);
8630
8631 // pass3:
8632 // - remove dead labels
8633 // - collect calls
8634 for (i = 0; i < opcnt; i++)
8635 {
8636 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8637 free(g_labels[i]);
8638 g_labels[i] = NULL;
8639 }
8640
8641 po = &ops[i];
8642 if (po->flags & (OPF_RMD|OPF_DONE))
8643 continue;
8644
8645 if (po->op == OP_CALL) {
8646 if (po->operand[0].type == OPT_LABEL)
8647 hg_fp_add_dep(fp, opr_name(po, 0));
8648 else if (po->pp != NULL)
8649 hg_fp_add_dep(fp, po->pp->name);
8650 }
8651 }
8652
8653 // pass4:
8654 // - handle push <const>/pop pairs
8655 for (i = 0; i < opcnt; i++)
8656 {
8657 po = &ops[i];
8658 if (po->flags & (OPF_RMD|OPF_DONE))
8659 continue;
8660
8661 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8662 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8663 }
8664
8665 // pass5:
8666 // - process trivial calls
8667 for (i = 0; i < opcnt; i++)
8668 {
8669 po = &ops[i];
8670 if (po->flags & (OPF_RMD|OPF_DONE))
8671 continue;
8672
8673 if (po->op == OP_CALL)
8674 {
8675 pp = process_call_early(i, opcnt, &j);
8676 if (pp != NULL) {
8677 if (!(po->flags & OPF_ATAIL))
8678 // since we know the args, try to collect them
8679 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8680 pp = NULL;
8681 }
8682
8683 if (pp != NULL) {
8684 if (j >= 0) {
8685 // commit esp adjust
8686 if (ops[j].op != OP_POP)
8687 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8688 else {
8689 for (l = 0; l < pp->argc_stack; l++)
8690 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8691 }
8692 }
8693
8694 po->flags |= OPF_DONE;
8695 }
8696 }
8697 }
8698
8699 // pass6:
8700 // - track saved regs (simple)
8701 // - process calls
8702 for (i = 0; i < opcnt; i++)
8703 {
8704 po = &ops[i];
8705 if (po->flags & (OPF_RMD|OPF_DONE))
8706 continue;
8707
8708 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8709 && po->operand[0].reg != xCX)
8710 {
8711 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8712 if (ret == 1) {
8713 // regmask_save |= 1 << po->operand[0].reg; // do it later
8714 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8715 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8716 }
8717 }
8718 else if (po->op == OP_CALL)
8719 {
8720 pp = process_call(i, opcnt);
8721
8722 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8723 // since we know the args, collect them
8724 ret = collect_call_args(po, i, pp, &regmask_dummy,
8725 i + opcnt * 1);
8726 }
8727 if (!(po->flags & OPF_TAIL)
8728 && po->operand[0].type == OPT_LABEL)
8729 {
8730 dep = hg_fp_find_dep(fp, opr_name(po, 0));
8731 ferr_assert(po, dep != NULL);
8732 // treat al write as overwrite to avoid many false positives
8733 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
8734 i + opcnt * 25, &j);
8735 if (j != -1)
8736 dep->has_ret = 1;
8737 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
8738 i + opcnt * 26, &j);
8739 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j]))
8740 dep->has_ret64 = 1;
8741 }
8742 }
8743 }
8744
8745 // pass7
8746 memset(cbits, 0, (opcnt + 7) / 8);
8747 regmask_dep = regmask_use = 0;
8748 has_ret = -1;
8749
8750 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0,
8751 &regmask_dep, &regmask_use, &has_ret);
8752
8753 // find unreachable code - must be fixed in IDA
8754 for (i = 0; i < opcnt; i++)
8755 {
8756 if (cbits[i >> 3] & (1 << (i & 7)))
8757 continue;
8758
8759 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8760 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8761 {
8762 // the compiler sometimes still generates code after
8763 // noreturn OS functions
8764 break;
8765 }
8766 if (!(ops[i].flags & OPF_RMD)
8767 && ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8768 {
8769 ferr(&ops[i], "unreachable code\n");
8770 }
8771 }
8772
8773 for (i = 0; i < g_eqcnt; i++) {
8774 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8775 max_bp_offset = g_eqs[i].offset;
8776 }
8777
8778 if (fp->argc_stack < 0) {
8779 max_bp_offset = (max_bp_offset + 3) & ~3;
8780 fp->argc_stack = max_bp_offset / 4;
8781 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8782 fp->argc_stack--;
8783 }
8784
8785 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8786 fp->regmask_use = regmask_use;
8787 fp->has_ret = has_ret;
8788#if 0
8789 printf("// has_ret %d, regmask_dep %x\n",
8790 fp->has_ret, fp->regmask_dep);
8791 output_hdr_fp(stdout, fp, 1);
8792 if (IS(funcn, "sub_10007F72")) exit(1);
8793#endif
8794
8795 gen_x_cleanup(opcnt);
8796}
8797
8798static void hg_fp_resolve_deps(struct func_prototype *fp)
8799{
8800 struct func_prototype fp_s;
8801 struct func_proto_dep *dep;
8802 int regmask_dep;
8803 int i;
8804
8805 // this thing is recursive, so mark first..
8806 fp->dep_resolved = 1;
8807
8808 for (i = 0; i < fp->dep_func_cnt; i++) {
8809 dep = &fp->dep_func[i];
8810
8811 strcpy(fp_s.name, dep->name);
8812 dep->proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8813 sizeof(hg_fp[0]), hg_fp_cmp_name);
8814 if (dep->proto != NULL) {
8815 if (!dep->proto->dep_resolved)
8816 hg_fp_resolve_deps(dep->proto);
8817
8818 regmask_dep = ~dep->regmask_live
8819 & dep->proto->regmask_dep;
8820 fp->regmask_dep |= regmask_dep;
8821 // printf("dep %s %s |= %x\n", fp->name,
8822 // fp->dep_func[i].name, regmask_dep);
8823
8824 if (dep->has_ret && (dep->proto->regmask_use & mxAX))
8825 dep->proto->has_ret = 1;
8826 if (dep->has_ret64 && (dep->proto->regmask_use & mxDX))
8827 dep->proto->has_ret64 = 1;
8828 if (fp->has_ret == -1 && dep->ret_dep)
8829 fp->has_ret = dep->proto->has_ret;
8830 }
8831 }
8832}
8833
8834// make all thiscall/edx arg functions referenced from .data fastcall
8835static void do_func_refs_from_data(void)
8836{
8837 struct func_prototype *fp, fp_s;
8838 int i;
8839
8840 for (i = 0; i < hg_ref_cnt; i++) {
8841 strcpy(fp_s.name, hg_refs[i]);
8842 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8843 sizeof(hg_fp[0]), hg_fp_cmp_name);
8844 if (fp == NULL)
8845 continue;
8846
8847 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8848 fp->regmask_dep |= mxCX | mxDX;
8849 }
8850}
8851
8852static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8853 int count)
8854{
8855 const struct parsed_proto *pp;
8856 char *p, namebuf[NAMELEN];
8857 const char *name;
8858 int regmask_dep;
8859 int argc_normal;
8860 int j, arg;
8861
8862 for (; count > 0; count--, fp++) {
8863 if (fp->has_ret == -1)
8864 fprintf(fout, "// ret unresolved\n");
8865#if 0
8866 fprintf(fout, "// dep:");
8867 for (j = 0; j < fp->dep_func_cnt; j++) {
8868 fprintf(fout, " %s/", fp->dep_func[j].name);
8869 if (fp->dep_func[j].proto != NULL)
8870 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8871 fp->dep_func[j].proto->has_ret);
8872 }
8873 fprintf(fout, "\n");
8874#endif
8875
8876 p = strchr(fp->name, '@');
8877 if (p != NULL) {
8878 memcpy(namebuf, fp->name, p - fp->name);
8879 namebuf[p - fp->name] = 0;
8880 name = namebuf;
8881 }
8882 else
8883 name = fp->name;
8884 if (name[0] == '_')
8885 name++;
8886
8887 pp = proto_parse(g_fhdr, name, 1);
8888 if (pp != NULL && pp->is_include)
8889 continue;
8890
8891 if (fp->pp != NULL) {
8892 // part of seed, output later
8893 continue;
8894 }
8895
8896 regmask_dep = fp->regmask_dep;
8897 argc_normal = fp->argc_stack;
8898
8899 fprintf(fout, "%-5s",
8900 fp->pp ? fp->pp->ret_type.name :
8901 fp->has_ret64 ? "__int64" :
8902 fp->has_ret ? "int" : "void");
8903 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8904 && (regmask_dep & ~mxCX) == 0)
8905 {
8906 fprintf(fout, "/*__thiscall*/ ");
8907 argc_normal++;
8908 regmask_dep = 0;
8909 }
8910 else if ((regmask_dep == (mxCX | mxDX)
8911 && (fp->is_stdcall || fp->argc_stack == 0))
8912 || (regmask_dep == mxCX && fp->argc_stack == 0))
8913 {
8914 fprintf(fout, " __fastcall ");
8915 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8916 argc_normal = 1;
8917 else
8918 argc_normal += 2;
8919 regmask_dep = 0;
8920 }
8921 else if (regmask_dep && !fp->is_stdcall) {
8922 fprintf(fout, "/*__usercall*/ ");
8923 }
8924 else if (regmask_dep) {
8925 fprintf(fout, "/*__userpurge*/ ");
8926 }
8927 else if (fp->is_stdcall)
8928 fprintf(fout, " __stdcall ");
8929 else
8930 fprintf(fout, " __cdecl ");
8931
8932 fprintf(fout, "%s(", name);
8933
8934 arg = 0;
8935 for (j = 0; j < xSP; j++) {
8936 if (regmask_dep & (1 << j)) {
8937 arg++;
8938 if (arg != 1)
8939 fprintf(fout, ", ");
8940 if (fp->pp != NULL)
8941 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8942 else
8943 fprintf(fout, "int");
8944 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8945 }
8946 }
8947
8948 for (j = 0; j < argc_normal; j++) {
8949 arg++;
8950 if (arg != 1)
8951 fprintf(fout, ", ");
8952 if (fp->pp != NULL) {
8953 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8954 if (!fp->pp->arg[arg - 1].type.is_ptr)
8955 fprintf(fout, " ");
8956 }
8957 else
8958 fprintf(fout, "int ");
8959 fprintf(fout, "a%d", arg);
8960 }
8961
8962 fprintf(fout, ");\n");
8963 }
8964}
8965
8966static void output_hdr(FILE *fout)
8967{
8968 static const char *lmod_c_names[] = {
8969 [OPLM_UNSPEC] = "???",
8970 [OPLM_BYTE] = "uint8_t",
8971 [OPLM_WORD] = "uint16_t",
8972 [OPLM_DWORD] = "uint32_t",
8973 [OPLM_QWORD] = "uint64_t",
8974 };
8975 const struct scanned_var *var;
8976 struct func_prototype *fp;
8977 char line[256] = { 0, };
8978 char name[256];
8979 int i;
8980
8981 // add stuff from headers
8982 for (i = 0; i < pp_cache_size; i++) {
8983 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8984 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8985 else
8986 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8987 fp = hg_fp_add(name);
8988 fp->pp = &pp_cache[i];
8989 fp->argc_stack = fp->pp->argc_stack;
8990 fp->is_stdcall = fp->pp->is_stdcall;
8991 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8992 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8993 }
8994
8995 // resolve deps
8996 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8997 for (i = 0; i < hg_fp_cnt; i++)
8998 hg_fp_resolve_deps(&hg_fp[i]);
8999
9000 // adjust functions referenced from data segment
9001 do_func_refs_from_data();
9002
9003 // final adjustments
9004 for (i = 0; i < hg_fp_cnt; i++) {
9005 if (hg_fp[i].eax_pass && (hg_fp[i].regmask_dep & mxAX))
9006 hg_fp[i].has_ret = 1;
9007 }
9008
9009 // note: messes up .proto ptr, don't use
9010 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
9011
9012 // output variables
9013 for (i = 0; i < hg_var_cnt; i++) {
9014 var = &hg_vars[i];
9015
9016 if (var->pp != NULL)
9017 // part of seed
9018 continue;
9019 else if (var->is_c_str)
9020 fprintf(fout, "extern %-8s %s[];", "char", var->name);
9021 else
9022 fprintf(fout, "extern %-8s %s;",
9023 lmod_c_names[var->lmod], var->name);
9024
9025 if (var->is_seeded)
9026 fprintf(fout, " // seeded");
9027 fprintf(fout, "\n");
9028 }
9029
9030 fprintf(fout, "\n");
9031
9032 // output function prototypes
9033 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
9034
9035 // seed passthrough
9036 fprintf(fout, "\n// - seed -\n");
9037
9038 rewind(g_fhdr);
9039 while (fgets(line, sizeof(line), g_fhdr))
9040 fwrite(line, 1, strlen(line), fout);
9041}
9042
9043// '=' needs special treatment
9044// also ' quote
9045static char *next_word_s(char *w, size_t wsize, char *s)
9046{
9047 size_t i;
9048
9049 s = sskip(s);
9050
9051 i = 0;
9052 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
9053 w[0] = s[0];
9054 for (i = 1; i < wsize - 1; i++) {
9055 if (s[i] == 0) {
9056 printf("warning: missing closing quote: \"%s\"\n", s);
9057 break;
9058 }
9059 if (s[i] == '\'')
9060 break;
9061 w[i] = s[i];
9062 }
9063 }
9064
9065 for (; i < wsize - 1; i++) {
9066 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
9067 break;
9068 w[i] = s[i];
9069 }
9070 w[i] = 0;
9071
9072 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
9073 printf("warning: '%s' truncated\n", w);
9074
9075 return s + i;
9076}
9077
9078static int cmpstringp(const void *p1, const void *p2)
9079{
9080 return strcmp(*(char * const *)p1, *(char * const *)p2);
9081}
9082
9083static int is_xref_needed(char *p, char **rlist, int rlist_len)
9084{
9085 char *p2;
9086
9087 p = sskip(p);
9088 if (strstr(p, "..."))
9089 // unable to determine, assume needed
9090 return 1;
9091
9092 if (*p == '.') // .text, .data, ...
9093 // ref from other data or non-function -> no
9094 return 0;
9095
9096 p2 = strpbrk(p, "+:\r\n\x18");
9097 if (p2 != NULL)
9098 *p2 = 0;
9099 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9100 // referenced from removed code
9101 return 0;
9102
9103 return 1;
9104}
9105
9106static int ida_xrefs_show_need(FILE *fasm, char *p,
9107 char **rlist, int rlist_len)
9108{
9109 int found_need = 0;
9110 char line[256];
9111 long pos;
9112
9113 p = strrchr(p, ';');
9114 if (p != NULL && *p == ';') {
9115 if (IS_START(p + 2, "sctref"))
9116 return 1;
9117 if (IS_START(p + 2, "DATA XREF: ")) {
9118 p += 13;
9119 if (is_xref_needed(p, rlist, rlist_len))
9120 return 1;
9121 }
9122 }
9123
9124 pos = ftell(fasm);
9125 while (1)
9126 {
9127 if (!my_fgets(line, sizeof(line), fasm))
9128 break;
9129 // non-first line is always indented
9130 if (!my_isblank(line[0]))
9131 break;
9132
9133 // should be no content, just comment
9134 p = sskip(line);
9135 if (*p != ';')
9136 break;
9137
9138 p = strrchr(p, ';');
9139 p += 2;
9140
9141 if (IS_START(p, "sctref")) {
9142 found_need = 1;
9143 break;
9144 }
9145
9146 // it's printed once, but no harm to check again
9147 if (IS_START(p, "DATA XREF: "))
9148 p += 11;
9149
9150 if (is_xref_needed(p, rlist, rlist_len)) {
9151 found_need = 1;
9152 break;
9153 }
9154 }
9155 fseek(fasm, pos, SEEK_SET);
9156 return found_need;
9157}
9158
9159static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
9160{
9161 struct scanned_var *var;
9162 char line[256] = { 0, };
9163 char words[4][256];
9164 int no_identifier;
9165 char *p = NULL;
9166 int wordc;
9167 int l;
9168
9169 while (!feof(fasm))
9170 {
9171 // skip to next data section
9172 while (my_fgets(line, sizeof(line), fasm))
9173 {
9174 asmln++;
9175
9176 p = sskip(line);
9177 if (*p == 0 || *p == ';')
9178 continue;
9179
9180 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
9181 if (*p == 0 || *p == ';')
9182 continue;
9183
9184 if (*p != 's' || !IS_START(p, "segment para public"))
9185 continue;
9186
9187 break;
9188 }
9189
9190 if (p == NULL || !IS_START(p, "segment para public"))
9191 break;
9192 p = sskip(p + 19);
9193
9194 if (!IS_START(p, "'DATA'"))
9195 continue;
9196
9197 // now process it
9198 while (my_fgets(line, sizeof(line), fasm))
9199 {
9200 asmln++;
9201
9202 p = line;
9203 no_identifier = my_isblank(*p);
9204
9205 p = sskip(p);
9206 if (*p == 0 || *p == ';')
9207 continue;
9208
9209 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9210 words[wordc][0] = 0;
9211 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9212 if (*p == 0 || *p == ';') {
9213 wordc++;
9214 break;
9215 }
9216 }
9217
9218 if (wordc == 2 && IS(words[1], "ends"))
9219 break;
9220 if (wordc < 2)
9221 continue;
9222
9223 if (no_identifier) {
9224 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
9225 hg_ref_add(words[2]);
9226 continue;
9227 }
9228
9229 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
9230 // when this starts, we don't need anything from this section
9231 break;
9232 }
9233
9234 // check refs comment(s)
9235 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
9236 continue;
9237
9238 if ((hg_var_cnt & 0xff) == 0) {
9239 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
9240 * (hg_var_cnt + 0x100));
9241 my_assert_not(hg_vars, NULL);
9242 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
9243 }
9244
9245 var = &hg_vars[hg_var_cnt++];
9246 snprintf(var->name, sizeof(var->name), "%s", words[0]);
9247
9248 // maybe already in seed header?
9249 var->pp = proto_parse(g_fhdr, var->name, 1);
9250 if (var->pp != NULL) {
9251 if (var->pp->is_fptr) {
9252 var->lmod = OPLM_DWORD;
9253 //var->is_ptr = 1;
9254 }
9255 else if (var->pp->is_func)
9256 aerr("func?\n");
9257 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
9258 aerr("unhandled C type '%s' for '%s'\n",
9259 var->pp->type.name, var->name);
9260
9261 var->is_seeded = 1;
9262 continue;
9263 }
9264
9265 if (IS(words[1], "dd")) {
9266 var->lmod = OPLM_DWORD;
9267 if (wordc >= 4 && IS(words[2], "offset"))
9268 hg_ref_add(words[3]);
9269 }
9270 else if (IS(words[1], "dw"))
9271 var->lmod = OPLM_WORD;
9272 else if (IS(words[1], "db")) {
9273 var->lmod = OPLM_BYTE;
9274 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
9275 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
9276 var->is_c_str = 1;
9277 }
9278 }
9279 else if (IS(words[1], "dq"))
9280 var->lmod = OPLM_QWORD;
9281 //else if (IS(words[1], "dt"))
9282 else
9283 aerr("type '%s' not known\n", words[1]);
9284 }
9285 }
9286
9287 rewind(fasm);
9288 asmln = 0;
9289}
9290
9291static void set_label(int i, const char *name)
9292{
9293 const char *p;
9294 int len;
9295
9296 len = strlen(name);
9297 p = strchr(name, ':');
9298 if (p != NULL)
9299 len = p - name;
9300
9301 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
9302 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
9303 g_labels[i] = realloc(g_labels[i], len + 1);
9304 my_assert_not(g_labels[i], NULL);
9305 memcpy(g_labels[i], name, len);
9306 g_labels[i][len] = 0;
9307}
9308
9309struct chunk_item {
9310 char *name;
9311 long fptr;
9312 int asmln;
9313};
9314
9315static struct chunk_item *func_chunks;
9316static int func_chunk_cnt;
9317static int func_chunk_alloc;
9318
9319static void add_func_chunk(FILE *fasm, const char *name, int line)
9320{
9321 if (func_chunk_cnt >= func_chunk_alloc) {
9322 func_chunk_alloc *= 2;
9323 func_chunks = realloc(func_chunks,
9324 func_chunk_alloc * sizeof(func_chunks[0]));
9325 my_assert_not(func_chunks, NULL);
9326 }
9327 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
9328 func_chunks[func_chunk_cnt].name = strdup(name);
9329 func_chunks[func_chunk_cnt].asmln = line;
9330 func_chunk_cnt++;
9331}
9332
9333static int cmp_chunks(const void *p1, const void *p2)
9334{
9335 const struct chunk_item *c1 = p1, *c2 = p2;
9336 return strcmp(c1->name, c2->name);
9337}
9338
9339static void scan_ahead_for_chunks(FILE *fasm)
9340{
9341 char words[2][256];
9342 char line[256];
9343 long oldpos;
9344 int oldasmln;
9345 int wordc;
9346 char *p;
9347 int i;
9348
9349 oldpos = ftell(fasm);
9350 oldasmln = asmln;
9351
9352 while (my_fgets(line, sizeof(line), fasm))
9353 {
9354 wordc = 0;
9355 asmln++;
9356
9357 p = sskip(line);
9358 if (*p == 0)
9359 continue;
9360
9361 if (*p == ';')
9362 {
9363 // get rid of random tabs
9364 for (i = 0; line[i] != 0; i++)
9365 if (line[i] == '\t')
9366 line[i] = ' ';
9367
9368 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9369 {
9370 p += 30;
9371 next_word(words[0], sizeof(words[0]), p);
9372 if (words[0][0] == 0)
9373 aerr("missing name for func chunk?\n");
9374
9375 add_func_chunk(fasm, words[0], asmln);
9376 }
9377 else if (IS_START(p, "; sctend"))
9378 break;
9379
9380 continue;
9381 } // *p == ';'
9382
9383 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9384 words[wordc][0] = 0;
9385 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9386 if (*p == 0 || *p == ';') {
9387 wordc++;
9388 break;
9389 }
9390 }
9391
9392 if (wordc == 2 && IS(words[1], "ends"))
9393 break;
9394 }
9395
9396 fseek(fasm, oldpos, SEEK_SET);
9397 asmln = oldasmln;
9398}
9399
9400int main(int argc, char *argv[])
9401{
9402 FILE *fout, *fasm, *frlist;
9403 struct parsed_data *pd = NULL;
9404 int pd_alloc = 0;
9405 char **rlist = NULL;
9406 int rlist_len = 0;
9407 int rlist_alloc = 0;
9408 int func_chunks_used = 0;
9409 int func_chunks_sorted = 0;
9410 int func_chunk_i = -1;
9411 long func_chunk_ret = 0;
9412 int func_chunk_ret_ln = 0;
9413 int scanned_ahead = 0;
9414 char line[256];
9415 char words[20][256];
9416 enum opr_lenmod lmod;
9417 char *sctproto = NULL;
9418 int in_func = 0;
9419 int pending_endp = 0;
9420 int skip_code = 0;
9421 int skip_code_end = 0;
9422 int skip_warned = 0;
9423 int eq_alloc;
9424 int verbose = 0;
9425 int multi_seg = 0;
9426 int end = 0;
9427 int arg_out;
9428 int arg;
9429 int pi = 0;
9430 int i, j;
9431 int ret, len;
9432 char *p, *p2;
9433 int wordc;
9434
9435 for (arg = 1; arg < argc; arg++) {
9436 if (IS(argv[arg], "-v"))
9437 verbose = 1;
9438 else if (IS(argv[arg], "-rf"))
9439 g_allow_regfunc = 1;
9440 else if (IS(argv[arg], "-uc"))
9441 g_allow_user_icall = 1;
9442 else if (IS(argv[arg], "-m"))
9443 multi_seg = 1;
9444 else if (IS(argv[arg], "-hdr"))
9445 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
9446 else
9447 break;
9448 }
9449
9450 if (argc < arg + 3) {
9451 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
9452 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
9453 "options:\n"
9454 " -hdr - header generation mode\n"
9455 " -rf - allow unannotated indirect calls\n"
9456 " -uc - allow ind. calls/refs to __usercall\n"
9457 " -m - allow multiple .text sections\n"
9458 "[rlist] is a file with function names to skip,"
9459 " one per line\n",
9460 argv[0], argv[0]);
9461 return 1;
9462 }
9463
9464 arg_out = arg++;
9465
9466 asmfn = argv[arg++];
9467 fasm = fopen(asmfn, "r");
9468 my_assert_not(fasm, NULL);
9469
9470 hdrfn = argv[arg++];
9471 g_fhdr = fopen(hdrfn, "r");
9472 my_assert_not(g_fhdr, NULL);
9473
9474 rlist_alloc = 64;
9475 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9476 my_assert_not(rlist, NULL);
9477 // needs special handling..
9478 rlist[rlist_len++] = "__alloca_probe";
9479
9480 func_chunk_alloc = 32;
9481 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9482 my_assert_not(func_chunks, NULL);
9483
9484 memset(words, 0, sizeof(words));
9485
9486 for (; arg < argc; arg++) {
9487 int skip_func = 0;
9488
9489 frlist = fopen(argv[arg], "r");
9490 my_assert_not(frlist, NULL);
9491
9492 while (my_fgets(line, sizeof(line), frlist)) {
9493 p = sskip(line);
9494 if (*p == 0 || *p == ';')
9495 continue;
9496 if (*p == '#') {
9497 if (IS_START(p, "#if 0")
9498 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9499 {
9500 skip_func = 1;
9501 }
9502 else if (IS_START(p, "#endif"))
9503 skip_func = 0;
9504 continue;
9505 }
9506 if (skip_func)
9507 continue;
9508
9509 p = next_word(words[0], sizeof(words[0]), p);
9510 if (words[0][0] == 0)
9511 continue;
9512
9513 if (rlist_len >= rlist_alloc) {
9514 rlist_alloc = rlist_alloc * 2 + 64;
9515 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9516 my_assert_not(rlist, NULL);
9517 }
9518 rlist[rlist_len++] = strdup(words[0]);
9519 }
9520
9521 fclose(frlist);
9522 frlist = NULL;
9523 }
9524
9525 if (rlist_len > 0)
9526 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9527
9528 fout = fopen(argv[arg_out], "w");
9529 my_assert_not(fout, NULL);
9530
9531 eq_alloc = 128;
9532 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9533 my_assert_not(g_eqs, NULL);
9534
9535 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9536 g_label_refs[i].i = -1;
9537 g_label_refs[i].next = NULL;
9538 }
9539
9540 if (g_header_mode)
9541 scan_variables(fasm, rlist, rlist_len);
9542
9543 while (my_fgets(line, sizeof(line), fasm))
9544 {
9545 wordc = 0;
9546 asmln++;
9547
9548 p = sskip(line);
9549 if (*p == 0)
9550 continue;
9551
9552 // get rid of random tabs
9553 for (i = 0; line[i] != 0; i++)
9554 if (line[i] == '\t')
9555 line[i] = ' ';
9556
9557 if (*p == ';')
9558 {
9559 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9560 goto do_pending_endp; // eww..
9561
9562 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9563 {
9564 static const char *attrs[] = {
9565 "bp-based frame",
9566 "library function",
9567 "static",
9568 "noreturn",
9569 "thunk",
9570 "fpd=",
9571 };
9572
9573 // parse IDA's attribute-list comment
9574 g_ida_func_attr = 0;
9575 p = sskip(p + 13);
9576
9577 for (; *p != 0; p = sskip(p)) {
9578 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9579 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9580 g_ida_func_attr |= 1 << i;
9581 p += strlen(attrs[i]);
9582 break;
9583 }
9584 }
9585 if (i == ARRAY_SIZE(attrs)) {
9586 anote("unparsed IDA attr: %s\n", p);
9587 break;
9588 }
9589 if (IS(attrs[i], "fpd=")) {
9590 p = next_word(words[0], sizeof(words[0]), p);
9591 // ignore for now..
9592 }
9593 }
9594 }
9595 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9596 {
9597 static const char *attrs[] = {
9598 "clear_sf",
9599 "clear_regmask",
9600 "rm_regmask",
9601 "nowarn",
9602 "argframe",
9603 };
9604
9605 // parse manual attribute-list comment
9606 g_sct_func_attr = 0;
9607 p = sskip(p + 10);
9608
9609 for (; *p != 0; p = sskip(p)) {
9610 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9611 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9612 g_sct_func_attr |= 1 << i;
9613 p += strlen(attrs[i]);
9614 break;
9615 }
9616 }
9617 if (*p == '=') {
9618 j = ret = 0;
9619 if (i == 0)
9620 // clear_sf=start,len (in dwords)
9621 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9622 &g_stack_clear_len, &j);
9623 else if (i == 1)
9624 // clear_regmask=<mask>
9625 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9626 else if (i == 2)
9627 // rm_regmask=<mask>
9628 ret = sscanf(p, "=%x%n", &g_regmask_rm, &j) + 1;
9629 if (ret < 2) {
9630 anote("unparsed attr value: %s\n", p);
9631 break;
9632 }
9633 p += j;
9634 }
9635 else if (i == ARRAY_SIZE(attrs)) {
9636 anote("unparsed sct attr: %s\n", p);
9637 break;
9638 }
9639 }
9640 }
9641 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9642 {
9643 p += 30;
9644 next_word(words[0], sizeof(words[0]), p);
9645 if (words[0][0] == 0)
9646 aerr("missing name for func chunk?\n");
9647
9648 if (!scanned_ahead) {
9649 add_func_chunk(fasm, words[0], asmln);
9650 func_chunks_sorted = 0;
9651 }
9652 }
9653 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9654 {
9655 if (func_chunk_i >= 0) {
9656 if (func_chunk_i < func_chunk_cnt
9657 && IS(func_chunks[func_chunk_i].name, g_func))
9658 {
9659 // move on to next chunk
9660 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9661 if (ret)
9662 aerr("seek failed for '%s' chunk #%d\n",
9663 g_func, func_chunk_i);
9664 asmln = func_chunks[func_chunk_i].asmln;
9665 func_chunk_i++;
9666 }
9667 else {
9668 if (func_chunk_ret == 0)
9669 aerr("no return from chunk?\n");
9670 fseek(fasm, func_chunk_ret, SEEK_SET);
9671 asmln = func_chunk_ret_ln;
9672 func_chunk_ret = 0;
9673 pending_endp = 1;
9674 }
9675 }
9676 }
9677 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9678 func_chunks_used = 1;
9679 p += 20;
9680 if (IS_START(g_func, "sub_")) {
9681 unsigned long addr = strtoul(p, NULL, 16);
9682 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9683 if (addr > f_addr && !scanned_ahead) {
9684 //anote("scan_ahead caused by '%s', addr %lx\n",
9685 // g_func, addr);
9686 scan_ahead_for_chunks(fasm);
9687 scanned_ahead = 1;
9688 func_chunks_sorted = 0;
9689 }
9690 }
9691 }
9692 continue;
9693 } // *p == ';'
9694
9695parse_words:
9696 for (i = wordc; i < ARRAY_SIZE(words); i++)
9697 words[i][0] = 0;
9698 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9699 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9700 if (*p == 0 || *p == ';') {
9701 wordc++;
9702 break;
9703 }
9704 }
9705 if (*p != 0 && *p != ';')
9706 aerr("too many words\n");
9707
9708 if (skip_code_end) {
9709 skip_code_end = 0;
9710 skip_code = 0;
9711 }
9712
9713 // allow asm patches in comments
9714 if (*p == ';') {
9715 // skip IDA's forced non-removable comment
9716 if (!IS_START(p, "; sct") && (p2 = strchr(p + 1, ';')))
9717 p = p2;
9718 }
9719 if (*p == ';' && IS_START(p, "; sct")) {
9720 if (IS_START(p, "; sctpatch:")) {
9721 p = sskip(p + 11);
9722 if (*p == 0 || *p == ';')
9723 continue;
9724 goto parse_words; // lame
9725 }
9726 if (IS_START(p, "; sctproto:")) {
9727 sctproto = strdup(p + 11);
9728 }
9729 else if (IS_START(p, "; sctend")) {
9730 end = 1;
9731 if (!pending_endp)
9732 break;
9733 }
9734 else if (IS_START(p, "; sctskip_start")) {
9735 if (in_func && !g_skip_func) {
9736 if (!skip_code) {
9737 ops[pi].op = OPP_ABORT;
9738 ops[pi].asmln = asmln;
9739 pi++;
9740 }
9741 skip_code = 1;
9742 }
9743 }
9744 else if (IS_START(p, "; sctskip_end")) {
9745 if (skip_code)
9746 skip_code_end = 1;
9747 }
9748 }
9749
9750 if (wordc == 0) {
9751 // shouldn't happen
9752 awarn("wordc == 0?\n");
9753 continue;
9754 }
9755
9756 // don't care about this:
9757 if (words[0][0] == '.'
9758 || IS(words[0], "include")
9759 || IS(words[0], "assume") || IS(words[1], "segment")
9760 || IS(words[0], "align"))
9761 {
9762 continue;
9763 }
9764
9765do_pending_endp:
9766 // do delayed endp processing to collect switch jumptables
9767 if (pending_endp) {
9768 if (in_func && !g_skip_func && !end && wordc >= 2
9769 && ((words[0][0] == 'd' && words[0][2] == 0)
9770 || (words[1][0] == 'd' && words[1][2] == 0)))
9771 {
9772 i = 1;
9773 if (words[1][0] == 'd' && words[1][2] == 0) {
9774 // label
9775 if (g_func_pd_cnt >= pd_alloc) {
9776 pd_alloc = pd_alloc * 2 + 16;
9777 g_func_pd = realloc(g_func_pd,
9778 sizeof(g_func_pd[0]) * pd_alloc);
9779 my_assert_not(g_func_pd, NULL);
9780 }
9781 pd = &g_func_pd[g_func_pd_cnt];
9782 g_func_pd_cnt++;
9783 memset(pd, 0, sizeof(*pd));
9784 strcpy(pd->label, words[0]);
9785 pd->type = OPT_CONST;
9786 pd->lmod = lmod_from_directive(words[1]);
9787 i = 2;
9788 }
9789 else {
9790 if (pd == NULL) {
9791 if (verbose)
9792 anote("skipping alignment byte?\n");
9793 continue;
9794 }
9795 lmod = lmod_from_directive(words[0]);
9796 if (lmod != pd->lmod)
9797 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9798 }
9799
9800 if (pd->count_alloc < pd->count + wordc) {
9801 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9802 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9803 my_assert_not(pd->d, NULL);
9804 }
9805 for (; i < wordc; i++) {
9806 if (IS(words[i], "offset")) {
9807 pd->type = OPT_OFFSET;
9808 i++;
9809 }
9810 p = strchr(words[i], ',');
9811 if (p != NULL)
9812 *p = 0;
9813 if (pd->type == OPT_OFFSET)
9814 pd->d[pd->count].u.label = strdup(words[i]);
9815 else
9816 pd->d[pd->count].u.val = parse_number(words[i], 0);
9817 pd->d[pd->count].bt_i = -1;
9818 pd->count++;
9819 }
9820 continue;
9821 }
9822
9823 if (in_func && !g_skip_func) {
9824 if (g_header_mode)
9825 gen_hdr(g_func, pi);
9826 else
9827 gen_func(fout, g_fhdr, g_func, pi);
9828 }
9829
9830 pending_endp = 0;
9831 in_func = 0;
9832 g_ida_func_attr = 0;
9833 g_sct_func_attr = 0;
9834 g_stack_clear_start = 0;
9835 g_stack_clear_len = 0;
9836 g_regmask_init = 0;
9837 g_regmask_rm = 0;
9838 skip_warned = 0;
9839 g_skip_func = 0;
9840 g_func[0] = 0;
9841 g_seh_found = 0;
9842 func_chunks_used = 0;
9843 func_chunk_i = -1;
9844 if (pi != 0) {
9845 memset(&ops, 0, pi * sizeof(ops[0]));
9846 clear_labels(pi);
9847 pi = 0;
9848 }
9849 g_eqcnt = 0;
9850 for (i = 0; i < g_func_pd_cnt; i++) {
9851 pd = &g_func_pd[i];
9852 if (pd->type == OPT_OFFSET) {
9853 for (j = 0; j < pd->count; j++)
9854 free(pd->d[j].u.label);
9855 }
9856 free(pd->d);
9857 pd->d = NULL;
9858 }
9859 g_func_pd_cnt = 0;
9860 g_func_lmods = 0;
9861 pd = NULL;
9862
9863 if (end)
9864 break;
9865 if (wordc == 0)
9866 continue;
9867 }
9868
9869 if (IS(words[1], "proc")) {
9870 if (in_func)
9871 aerr("proc '%s' while in_func '%s'?\n",
9872 words[0], g_func);
9873 p = words[0];
9874 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9875 g_skip_func = 1;
9876 strcpy(g_func, words[0]);
9877 set_label(0, words[0]);
9878 in_func = 1;
9879 continue;
9880 }
9881
9882 if (IS(words[1], "endp"))
9883 {
9884 if (!in_func)
9885 aerr("endp '%s' while not in_func?\n", words[0]);
9886 if (!IS(g_func, words[0]))
9887 aerr("endp '%s' while in_func '%s'?\n",
9888 words[0], g_func);
9889 if (skip_code)
9890 aerr("endp '%s' while skipping code\n", words[0]);
9891
9892 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9893 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
9894 {
9895 // import jump
9896 g_skip_func = 1;
9897 }
9898
9899 if (!g_skip_func && func_chunks_used) {
9900 // start processing chunks
9901 struct chunk_item *ci, key = { g_func, 0 };
9902
9903 func_chunk_ret = ftell(fasm);
9904 func_chunk_ret_ln = asmln;
9905 if (!func_chunks_sorted) {
9906 qsort(func_chunks, func_chunk_cnt,
9907 sizeof(func_chunks[0]), cmp_chunks);
9908 func_chunks_sorted = 1;
9909 }
9910 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9911 sizeof(func_chunks[0]), cmp_chunks);
9912 if (ci == NULL)
9913 aerr("'%s' needs chunks, but none found\n", g_func);
9914 func_chunk_i = ci - func_chunks;
9915 for (; func_chunk_i > 0; func_chunk_i--)
9916 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9917 break;
9918
9919 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9920 if (ret)
9921 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9922 asmln = func_chunks[func_chunk_i].asmln;
9923 func_chunk_i++;
9924 continue;
9925 }
9926 pending_endp = 1;
9927 continue;
9928 }
9929
9930 if (wordc == 2 && IS(words[1], "ends")) {
9931 if (!multi_seg) {
9932 end = 1;
9933 if (pending_endp)
9934 goto do_pending_endp;
9935 break;
9936 }
9937
9938 // scan for next text segment
9939 while (my_fgets(line, sizeof(line), fasm)) {
9940 asmln++;
9941 p = sskip(line);
9942 if (*p == 0 || *p == ';')
9943 continue;
9944
9945 if (strstr(p, "segment para public 'CODE' use32"))
9946 break;
9947 }
9948
9949 continue;
9950 }
9951
9952 p = strchr(words[0], ':');
9953 if (p != NULL) {
9954 set_label(pi, words[0]);
9955 continue;
9956 }
9957
9958 if (!in_func || g_skip_func || skip_code) {
9959 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9960 if (verbose)
9961 anote("skipping from '%s'\n", g_labels[pi]);
9962 skip_warned = 1;
9963 }
9964 free(g_labels[pi]);
9965 g_labels[pi] = NULL;
9966 continue;
9967 }
9968
9969 if (wordc > 1 && IS(words[1], "="))
9970 {
9971 if (wordc != 5)
9972 aerr("unhandled equ, wc=%d\n", wordc);
9973 if (g_eqcnt >= eq_alloc) {
9974 eq_alloc *= 2;
9975 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9976 my_assert_not(g_eqs, NULL);
9977 }
9978
9979 len = strlen(words[0]);
9980 if (len > sizeof(g_eqs[0].name) - 1)
9981 aerr("equ name too long: %d\n", len);
9982 strcpy(g_eqs[g_eqcnt].name, words[0]);
9983
9984 if (!IS(words[3], "ptr"))
9985 aerr("unhandled equ\n");
9986 if (IS(words[2], "dword"))
9987 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9988 else if (IS(words[2], "word"))
9989 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9990 else if (IS(words[2], "byte"))
9991 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9992 else if (IS(words[2], "qword"))
9993 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9994 else
9995 aerr("bad lmod: '%s'\n", words[2]);
9996
9997 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9998 g_eqcnt++;
9999 continue;
10000 }
10001
10002 if (pi >= ARRAY_SIZE(ops))
10003 aerr("too many ops\n");
10004
10005 parse_op(&ops[pi], words, wordc);
10006
10007 ops[pi].datap = sctproto;
10008 sctproto = NULL;
10009 pi++;
10010 }
10011
10012 if (g_header_mode)
10013 output_hdr(fout);
10014
10015 fclose(fout);
10016 fclose(fasm);
10017 fclose(g_fhdr);
10018
10019 return 0;
10020}
10021
10022// vim:ts=2:shiftwidth=2:expandtab