5 * This work is licensed under the terms of 3-clause BSD license.
6 * See COPYING file in the top-level directory.
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)
23 #include "my_assert.h"
27 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
28 #define IS(w, y) !strcmp(w, y)
29 #define IS_START(w, y) !strncmp(w, y, strlen(y))
31 #include "protoparse.h"
33 static const char *asmfn;
37 #define anote(fmt, ...) \
38 printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
39 #define awarn(fmt, ...) \
40 printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
41 #define aerr(fmt, ...) do { \
42 printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
47 #include "masm_tools.h"
50 OPF_RMD = (1 << 0), /* removed from code generation */
51 OPF_DATA = (1 << 1), /* data processing - writes to dst opr */
52 OPF_FLAGS = (1 << 2), /* sets flags */
53 OPF_JMP = (1 << 3), /* branch, call */
54 OPF_CJMP = (1 << 4), /* cond. branch (cc or jecxz/loop) */
55 OPF_CC = (1 << 5), /* uses flags */
56 OPF_TAIL = (1 << 6), /* ret or tail call */
57 OPF_RSAVE = (1 << 7), /* push/pop is local reg save/load */
58 OPF_REP = (1 << 8), /* prefixed by rep */
59 OPF_REPZ = (1 << 9), /* rep is repe/repz */
60 OPF_REPNZ = (1 << 10), /* rep is repne/repnz */
61 OPF_FARG = (1 << 11), /* push collected as func arg */
62 OPF_FARGNR = (1 << 12), /* push collected as func arg (no reuse) */
63 OPF_EBP_S = (1 << 13), /* ebp used as scratch here, not BP */
64 OPF_DF = (1 << 14), /* DF flag set */
65 OPF_ATAIL = (1 << 15), /* tail call with reused arg frame */
66 OPF_32BIT = (1 << 16), /* 32bit division */
67 OPF_LOCK = (1 << 17), /* op has lock prefix */
68 OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
69 OPF_DONE = (1 << 19), /* already fully handled by analysis */
70 OPF_PPUSH = (1 << 20), /* part of complex push-pop graph */
71 OPF_NOREGS = (1 << 21), /* don't track regs of this op */
72 OPF_FPUSH = (1 << 22), /* pushes x87 stack */
73 OPF_FPOP = (1 << 23), /* pops x87 stack */
74 OPF_FSHIFT = (1 << 24), /* x87 stack shift is actually needed */
164 // pseudo-ops for lib calls
183 // must be sorted (larger len must be further in enum)
192 #define MAX_EXITS 128
194 #define MAX_OPERANDS 3
197 #define OPR_INIT(type_, lmod_, reg_) \
198 { type_, lmod_, reg_, }
202 enum opr_lenmod lmod;
204 unsigned int is_ptr:1; // pointer in C
205 unsigned int is_array:1; // array in C
206 unsigned int type_from_var:1; // .. in header, sometimes wrong
207 unsigned int size_mismatch:1; // type override differs from C
208 unsigned int size_lt:1; // type override is larger than C
209 unsigned int had_ds:1; // had ds: prefix
210 const struct parsed_proto *pp; // for OPT_LABEL
217 struct parsed_opr operand[MAX_OPERANDS];
220 unsigned char pfo_inv;
221 unsigned char operand_cnt;
222 unsigned char p_argnum; // arg push: altered before call arg #
223 unsigned char p_arggrp; // arg push: arg group # for above
224 unsigned char p_argpass;// arg push: arg of host func
225 short p_argnext;// arg push: same arg pushed elsewhere or -1
226 int regmask_src; // all referensed regs
228 int pfomask; // flagop: parsed_flag_op that can't be delayed
229 int cc_scratch; // scratch storage during analysis
230 int bt_i; // branch target for branches
231 struct parsed_data *btj;// branch targets for jumptables
232 struct parsed_proto *pp;// parsed_proto for OP_CALL
238 // on start: function/data type hint (sctproto)
240 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
241 // OP_PUSH - points to OP_POP in complex push/pop graph
242 // OP_POP - points to OP_PUSH in simple push/pop pair
243 // OP_FCOM - needed_status_word_bits | (is_z_check << 16)
247 enum opr_lenmod lmod;
254 enum opr_lenmod lmod;
268 struct label_ref *next;
272 IDAFA_BP_FRAME = (1 << 0),
273 IDAFA_LIB_FUNC = (1 << 1),
274 IDAFA_STATIC = (1 << 2),
275 IDAFA_NORETURN = (1 << 3),
276 IDAFA_THUNK = (1 << 4),
277 IDAFA_FPD = (1 << 5),
281 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
282 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
295 // note: limited to 32k due to p_argnext
297 #define MAX_ARG_GRP 2
299 static struct parsed_op ops[MAX_OPS];
300 static struct parsed_equ *g_eqs;
302 static char *g_labels[MAX_OPS];
303 static struct label_ref g_label_refs[MAX_OPS];
304 static const struct parsed_proto *g_func_pp;
305 static struct parsed_data *g_func_pd;
306 static int g_func_pd_cnt;
307 static int g_func_lmods;
308 static char g_func[256];
309 static char g_comment[256];
310 static int g_bp_frame;
311 static int g_sp_frame;
312 static int g_stack_frame_used;
313 static int g_stack_fsz;
314 static int g_ida_func_attr;
315 static int g_sct_func_attr;
316 static int g_stack_clear_start; // in dwords
317 static int g_stack_clear_len;
318 static int g_regmask_init;
319 static int g_skip_func;
320 static int g_allow_regfunc;
321 static int g_allow_user_icall;
322 static int g_quiet_pp;
323 static int g_header_mode;
325 #define ferr(op_, fmt, ...) do { \
326 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
327 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
331 #define fnote(op_, fmt, ...) \
332 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
333 dump_op(op_), ##__VA_ARGS__)
335 #define ferr_assert(op_, cond) do { \
336 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
339 const char *regs_r32[] = {
340 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
341 // not r32, but list here for easy parsing and printing
342 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
343 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
345 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
346 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
347 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
353 xMM0, xMM1, xMM2, xMM3, // mmx
354 xMM4, xMM5, xMM6, xMM7,
355 xST0, xST1, xST2, xST3, // x87
356 xST4, xST5, xST6, xST7,
359 #define mxAX (1 << xAX)
360 #define mxCX (1 << xCX)
361 #define mxDX (1 << xDX)
362 #define mxST0 (1 << xST0)
363 #define mxST1 (1 << xST1)
364 #define mxST1_0 (mxST1 | mxST0)
365 #define mxST7_2 (0xfc << xST0)
366 #define mxSTa (0xff << xST0)
368 // possible basic comparison types (without inversion)
369 enum parsed_flag_op {
373 PFO_BE, // 6 CF=1||ZF=1
377 PFO_LE, // e ZF=1||SF!=OF
380 #define PFOB_O (1 << PFO_O)
381 #define PFOB_C (1 << PFO_C)
382 #define PFOB_Z (1 << PFO_Z)
383 #define PFOB_S (1 << PFO_S)
385 static const char *parsed_flag_op_names[] = {
386 "o", "c", "z", "be", "s", "p", "l", "le"
389 static int char_array_i(const char *array[], size_t len, const char *s)
393 for (i = 0; i < len; i++)
400 static void printf_number(char *buf, size_t buf_size,
401 unsigned long number)
403 // output in C-friendly form
404 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
407 static int check_segment_prefix(const char *s)
409 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
423 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
427 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
429 *reg_lmod = OPLM_QWORD;
433 *reg_lmod = OPLM_DWORD;
436 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
438 *reg_lmod = OPLM_WORD;
441 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
443 *reg_lmod = OPLM_BYTE;
446 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
448 *reg_lmod = OPLM_BYTE;
455 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
457 enum opr_lenmod lmod;
470 while (my_isblank(*s))
472 for (; my_issep(*s); d++, s++)
474 while (my_isblank(*s))
478 // skip '?s:' prefixes
479 if (check_segment_prefix(s))
482 s = next_idt(w, sizeof(w), s);
487 reg = parse_reg(&lmod, w);
489 *regmask |= 1 << reg;
493 if ('0' <= w[0] && w[0] <= '9') {
494 number = parse_number(w);
495 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
499 // probably some label/identifier - pass
502 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
506 strcpy(name, cvtbuf);
511 static int is_reg_in_str(const char *s)
515 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
518 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
519 if (!strncmp(s, regs_r32[i], 3))
525 static const char *parse_stack_el(const char *name, char *extra_reg,
526 int *base_val, int early_try)
528 const char *p, *p2, *s;
534 if (g_bp_frame || early_try)
537 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
539 if (extra_reg != NULL) {
540 strncpy(extra_reg, name, 3);
545 if (IS_START(p, "ebp+")) {
549 if (p2 != NULL && is_reg_in_str(p)) {
550 if (extra_reg != NULL) {
551 strncpy(extra_reg, p, p2 - p);
552 extra_reg[p2 - p] = 0;
557 if (!('0' <= *p && *p <= '9'))
564 if (!IS_START(name, "esp+"))
570 if (is_reg_in_str(s)) {
571 if (extra_reg != NULL) {
572 strncpy(extra_reg, s, p - s);
573 extra_reg[p - s] = 0;
578 aerr("%s IDA stackvar not set?\n", __func__);
580 if (!('0' <= *s && *s <= '9')) {
581 aerr("%s IDA stackvar offset not set?\n", __func__);
584 if (s[0] == '0' && s[1] == 'x')
587 if (len < sizeof(buf) - 1) {
588 strncpy(buf, s, len);
590 val = strtol(buf, &endp, 16);
591 if (val == 0 || *endp != 0) {
592 aerr("%s num parse fail for '%s'\n", __func__, buf);
601 if ('0' <= *p && *p <= '9')
604 if (base_val != NULL)
609 static int guess_lmod_from_name(struct parsed_opr *opr)
611 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
612 opr->lmod = OPLM_DWORD;
615 if (IS_START(opr->name, "word_")) {
616 opr->lmod = OPLM_WORD;
619 if (IS_START(opr->name, "byte_")) {
620 opr->lmod = OPLM_BYTE;
623 if (IS_START(opr->name, "qword_")) {
624 opr->lmod = OPLM_QWORD;
630 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
631 const struct parsed_type *c_type)
633 static const char *qword_types[] = {
634 "uint64_t", "int64_t", "__int64",
636 static const char *dword_types[] = {
637 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
638 "WPARAM", "LPARAM", "UINT", "__int32",
639 "LONG", "HIMC", "BOOL", "size_t",
642 static const char *word_types[] = {
643 "uint16_t", "int16_t", "_WORD", "WORD",
644 "unsigned __int16", "__int16",
646 static const char *byte_types[] = {
647 "uint8_t", "int8_t", "char",
648 "unsigned __int8", "__int8", "BYTE", "_BYTE",
650 // structures.. deal the same as with _UNKNOWN for now
656 if (c_type->is_ptr) {
661 n = skip_type_mod(c_type->name);
663 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
664 if (IS(n, dword_types[i])) {
670 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
671 if (IS(n, word_types[i])) {
677 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
678 if (IS(n, byte_types[i])) {
684 for (i = 0; i < ARRAY_SIZE(qword_types); i++) {
685 if (IS(n, qword_types[i])) {
694 static char *default_cast_to(char *buf, size_t buf_size,
695 struct parsed_opr *opr)
699 if (!opr->is_ptr || strchr(opr->name, '['))
701 if (opr->pp == NULL || opr->pp->type.name == NULL
704 snprintf(buf, buf_size, "%s", "(void *)");
708 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
712 static enum opr_type lmod_from_directive(const char *d)
716 else if (IS(d, "dw"))
718 else if (IS(d, "db"))
721 aerr("unhandled directive: '%s'\n", d);
725 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
731 *regmask |= 1 << reg;
734 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
737 static int parse_operand(struct parsed_opr *opr,
738 int *regmask, int *regmask_indirect,
739 char words[16][256], int wordc, int w, unsigned int op_flags)
741 const struct parsed_proto *pp = NULL;
742 enum opr_lenmod tmplmod;
743 unsigned long number;
751 aerr("parse_operand w %d, wordc %d\n", w, wordc);
755 for (i = w; i < wordc; i++) {
756 len = strlen(words[i]);
757 if (words[i][len - 1] == ',') {
758 words[i][len - 1] = 0;
764 wordc_in = wordc - w;
766 if ((op_flags & OPF_JMP) && wordc_in > 0
767 && !('0' <= words[w][0] && words[w][0] <= '9'))
769 const char *label = NULL;
771 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
772 && IS(words[w + 1], "ptr"))
773 label = words[w + 2];
774 else if (wordc_in == 2 && IS(words[w], "short"))
775 label = words[w + 1];
776 else if (wordc_in == 1
777 && strchr(words[w], '[') == NULL
778 && parse_reg(&tmplmod, words[w]) < 0)
782 opr->type = OPT_LABEL;
783 ret = check_segment_prefix(label);
786 aerr("fs/gs used\n");
790 strcpy(opr->name, label);
796 if (IS(words[w + 1], "ptr")) {
797 if (IS(words[w], "dword"))
798 opr->lmod = OPLM_DWORD;
799 else if (IS(words[w], "word"))
800 opr->lmod = OPLM_WORD;
801 else if (IS(words[w], "byte"))
802 opr->lmod = OPLM_BYTE;
803 else if (IS(words[w], "qword"))
804 opr->lmod = OPLM_QWORD;
806 aerr("type parsing failed\n");
808 wordc_in = wordc - w;
813 if (IS(words[w], "offset")) {
814 opr->type = OPT_OFFSET;
815 opr->lmod = OPLM_DWORD;
816 strcpy(opr->name, words[w + 1]);
817 pp = proto_parse(g_fhdr, opr->name, 1);
820 if (IS(words[w], "(offset")) {
821 p = strchr(words[w + 1], ')');
823 aerr("parse of bracketed offset failed\n");
825 opr->type = OPT_OFFSET;
826 strcpy(opr->name, words[w + 1]);
832 aerr("parse_operand 1 word expected\n");
834 ret = check_segment_prefix(words[w]);
837 aerr("fs/gs used\n");
839 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
841 strcpy(opr->name, words[w]);
843 if (words[w][0] == '[') {
844 opr->type = OPT_REGMEM;
845 ret = sscanf(words[w], "[%[^]]]", opr->name);
847 aerr("[] parse failure\n");
849 parse_indmode(opr->name, regmask_indirect, 1);
850 if (opr->lmod == OPLM_UNSPEC
851 && parse_stack_el(opr->name, NULL, NULL, 1))
854 struct parsed_equ *eq =
855 equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
857 opr->lmod = eq->lmod;
859 // might be unaligned access
860 g_func_lmods |= 1 << OPLM_BYTE;
864 else if (strchr(words[w], '[')) {
866 p = strchr(words[w], '[');
867 opr->type = OPT_REGMEM;
868 parse_indmode(p, regmask_indirect, 0);
869 strncpy(buf, words[w], p - words[w]);
870 buf[p - words[w]] = 0;
871 pp = proto_parse(g_fhdr, buf, 1);
874 else if (('0' <= words[w][0] && words[w][0] <= '9')
875 || words[w][0] == '-')
877 number = parse_number(words[w]);
878 opr->type = OPT_CONST;
880 printf_number(opr->name, sizeof(opr->name), number);
884 ret = parse_reg(&tmplmod, opr->name);
886 setup_reg_opr(opr, ret, tmplmod, regmask);
890 // most likely var in data segment
891 opr->type = OPT_LABEL;
892 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
896 if (pp->is_fptr || pp->is_func) {
897 opr->lmod = OPLM_DWORD;
901 tmplmod = OPLM_UNSPEC;
902 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
903 anote("unhandled C type '%s' for '%s'\n",
904 pp->type.name, opr->name);
906 if (opr->lmod == OPLM_UNSPEC) {
908 opr->type_from_var = 1;
910 else if (opr->lmod != tmplmod) {
911 opr->size_mismatch = 1;
912 if (tmplmod < opr->lmod)
915 opr->is_ptr = pp->type.is_ptr;
917 opr->is_array = pp->type.is_array;
921 if (opr->lmod == OPLM_UNSPEC)
922 guess_lmod_from_name(opr);
926 static const struct {
931 { "repe", OPF_REP|OPF_REPZ },
932 { "repz", OPF_REP|OPF_REPZ },
933 { "repne", OPF_REP|OPF_REPNZ },
934 { "repnz", OPF_REP|OPF_REPNZ },
935 { "lock", OPF_LOCK }, // ignored for now..
938 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
940 static const struct {
943 unsigned short minopr;
944 unsigned short maxopr;
947 unsigned char pfo_inv;
949 { "nop", OP_NOP, 0, 0, 0 },
950 { "push", OP_PUSH, 1, 1, 0 },
951 { "pop", OP_POP, 1, 1, OPF_DATA },
952 { "pusha",OP_PUSHA, 0, 0, 0 },
953 { "popa", OP_POPA, 0, 0, OPF_DATA },
954 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
955 { "mov" , OP_MOV, 2, 2, OPF_DATA },
956 { "lea", OP_LEA, 2, 2, OPF_DATA },
957 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
958 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
959 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
960 { "not", OP_NOT, 1, 1, OPF_DATA },
961 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
962 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
963 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
964 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
965 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
966 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
967 { "stosb",OP_STOS, 0, 0, OPF_DATA },
968 { "stosw",OP_STOS, 0, 0, OPF_DATA },
969 { "stosd",OP_STOS, 0, 0, OPF_DATA },
970 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
971 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
972 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
973 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
974 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
975 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
976 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
977 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
978 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
979 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
980 { "cld", OP_CLD, 0, 0, OPF_DATA },
981 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
982 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
983 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
984 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
985 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
986 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
987 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
988 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
989 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
990 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
991 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
992 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
993 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
994 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
995 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
996 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
997 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
998 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
999 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
1000 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
1001 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
1002 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
1003 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
1004 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
1005 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
1006 { "test", OP_TEST, 2, 2, OPF_FLAGS },
1007 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
1008 { "retn", OP_RET, 0, 1, OPF_TAIL },
1009 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
1010 { "jmp", OP_JMP, 1, 1, OPF_JMP },
1011 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
1012 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
1013 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
1014 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
1015 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
1016 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
1017 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
1018 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1019 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1020 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
1021 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
1022 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
1023 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
1024 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1025 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1026 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1027 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1028 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1029 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1030 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1031 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1032 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1033 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1034 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1035 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1036 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1037 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1038 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1039 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1040 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1041 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1042 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1043 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1044 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1045 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1046 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1047 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1048 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1049 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1050 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1051 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1052 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1053 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1054 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1055 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1056 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1057 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1058 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1059 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1060 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1061 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1062 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1063 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1064 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1065 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1066 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1067 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1068 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1069 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1070 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1072 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1073 { "fild", OP_FILD, 1, 1, OPF_FPUSH },
1074 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1075 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1076 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1077 { "fst", OP_FST, 1, 1, 0 },
1078 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1079 { "fist", OP_FIST, 1, 1, 0 },
1080 { "fistp", OP_FIST, 1, 1, OPF_FPOP },
1081 { "fadd", OP_FADD, 0, 2, 0 },
1082 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1083 { "fdiv", OP_FDIV, 0, 2, 0 },
1084 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1085 { "fmul", OP_FMUL, 0, 2, 0 },
1086 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1087 { "fsub", OP_FSUB, 0, 2, 0 },
1088 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1089 { "fdivr", OP_FDIVR, 0, 2, 0 },
1090 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1091 { "fsubr", OP_FSUBR, 0, 2, 0 },
1092 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1093 { "fiadd", OP_FIADD, 1, 1, 0 },
1094 { "fidiv", OP_FIDIV, 1, 1, 0 },
1095 { "fimul", OP_FIMUL, 1, 1, 0 },
1096 { "fisub", OP_FISUB, 1, 1, 0 },
1097 { "fidivr", OP_FIDIVR, 1, 1, 0 },
1098 { "fisubr", OP_FISUBR, 1, 1, 0 },
1099 { "fcom", OP_FCOM, 0, 1, 0 },
1100 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1101 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1102 { "fchs", OP_FCHS, 0, 0, 0 },
1103 { "fcos", OP_FCOS, 0, 0, 0 },
1104 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1105 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1106 { "fsin", OP_FSIN, 0, 0, 0 },
1107 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1108 { "fxch", OP_FXCH, 1, 1, 0 },
1109 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1111 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1112 { "movq", OP_MOV, 2, 2, OPF_DATA },
1113 // pseudo-ops for lib calls
1114 { "_allshl",OPP_ALLSHL },
1115 { "_allshr",OPP_ALLSHR },
1116 { "_ftol", OPP_FTOL },
1117 { "_CIpow", OPP_CIPOW },
1122 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1124 enum opr_lenmod lmod = OPLM_UNSPEC;
1125 int prefix_flags = 0;
1133 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1134 if (IS(words[w], pref_table[i].name)) {
1135 prefix_flags = pref_table[i].flags;
1142 aerr("lone prefix: '%s'\n", words[0]);
1147 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1148 if (IS(words[w], op_table[i].name))
1152 if (i == ARRAY_SIZE(op_table)) {
1154 aerr("unhandled op: '%s'\n", words[0]);
1159 op->op = op_table[i].op;
1160 op->flags = op_table[i].flags | prefix_flags;
1161 op->pfo = op_table[i].pfo;
1162 op->pfo_inv = op_table[i].pfo_inv;
1163 op->regmask_src = op->regmask_dst = 0;
1166 if (op->op == OP_UD2)
1169 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1170 if (opr >= op_table[i].minopr && w >= wordc)
1173 regmask = regmask_ind = 0;
1174 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1175 words, wordc, w, op->flags);
1177 if (opr == 0 && (op->flags & OPF_DATA))
1178 op->regmask_dst = regmask;
1180 op->regmask_src |= regmask;
1181 op->regmask_src |= regmask_ind;
1183 if (op->operand[opr].lmod != OPLM_UNSPEC)
1184 g_func_lmods |= 1 << op->operand[opr].lmod;
1188 aerr("parse_op %s incomplete: %d/%d\n",
1189 words[0], w, wordc);
1192 op->operand_cnt = opr;
1193 if (!strncmp(op_table[i].name, "set", 3))
1194 op->operand[0].lmod = OPLM_BYTE;
1197 // first operand is not dst
1200 op->regmask_src |= op->regmask_dst;
1201 op->regmask_dst = 0;
1204 // first operand is src too
1217 op->regmask_src |= op->regmask_dst;
1222 op->regmask_src |= op->regmask_dst;
1223 op->regmask_dst |= op->regmask_src;
1229 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1230 && op->operand[0].lmod == op->operand[1].lmod
1231 && op->operand[0].reg == op->operand[1].reg
1232 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1234 op->regmask_src = 0;
1237 op->regmask_src |= op->regmask_dst;
1240 // ops with implicit argumets
1242 op->operand_cnt = 2;
1243 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1244 op->regmask_dst = op->regmask_src;
1245 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1249 op->operand_cnt = 2;
1250 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1251 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1257 if (words[op_w][4] == 'b')
1259 else if (words[op_w][4] == 'w')
1261 else if (words[op_w][4] == 'd')
1264 op->regmask_src = 0;
1265 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1266 OPLM_DWORD, &op->regmask_src);
1267 op->regmask_dst = op->regmask_src;
1268 setup_reg_opr(&op->operand[j++], xAX, lmod,
1269 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1270 if (op->flags & OPF_REP) {
1271 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1272 op->regmask_dst |= 1 << xCX;
1274 op->operand_cnt = j;
1279 if (words[op_w][4] == 'b')
1281 else if (words[op_w][4] == 'w')
1283 else if (words[op_w][4] == 'd')
1286 op->regmask_src = 0;
1287 // note: lmod is not correct, don't have where to place it
1288 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1289 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1290 if (op->flags & OPF_REP)
1291 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1292 op->operand_cnt = j;
1293 op->regmask_dst = op->regmask_src;
1297 op->regmask_dst = 1 << xCX;
1300 op->operand_cnt = 2;
1301 op->regmask_src = 1 << xCX;
1302 op->operand[1].type = OPT_REG;
1303 op->operand[1].reg = xCX;
1304 op->operand[1].lmod = OPLM_DWORD;
1308 if (op->operand_cnt == 2) {
1309 if (op->operand[0].type != OPT_REG)
1310 aerr("reg expected\n");
1311 op->regmask_src |= 1 << op->operand[0].reg;
1313 if (op->operand_cnt != 1)
1318 op->regmask_src |= op->regmask_dst;
1319 op->regmask_dst = (1 << xDX) | (1 << xAX);
1320 if (op->operand[0].lmod == OPLM_UNSPEC)
1321 op->operand[0].lmod = OPLM_DWORD;
1326 // we could set up operands for edx:eax, but there is no real need to
1327 // (see is_opr_modified())
1328 op->regmask_src |= op->regmask_dst;
1329 op->regmask_dst = (1 << xDX) | (1 << xAX);
1330 if (op->operand[0].lmod == OPLM_UNSPEC)
1331 op->operand[0].lmod = OPLM_DWORD;
1339 op->regmask_src |= op->regmask_dst;
1340 if (op->operand[1].lmod == OPLM_UNSPEC)
1341 op->operand[1].lmod = OPLM_BYTE;
1346 op->regmask_src |= op->regmask_dst;
1347 if (op->operand[2].lmod == OPLM_UNSPEC)
1348 op->operand[2].lmod = OPLM_BYTE;
1352 op->regmask_src |= op->regmask_dst;
1353 op->regmask_dst = 0;
1354 if (op->operand[0].lmod == OPLM_UNSPEC
1355 && (op->operand[0].type == OPT_CONST
1356 || op->operand[0].type == OPT_OFFSET
1357 || op->operand[0].type == OPT_LABEL))
1358 op->operand[0].lmod = OPLM_DWORD;
1364 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1365 && op->operand[0].lmod == op->operand[1].lmod
1366 && op->operand[0].reg == op->operand[1].reg
1367 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1369 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1370 op->regmask_src = op->regmask_dst = 0;
1375 if (op->operand[0].type == OPT_REG
1376 && op->operand[1].type == OPT_REGMEM)
1379 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1380 if (IS(buf, op->operand[1].name))
1381 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1386 // trashed regs must be explicitly detected later
1387 op->regmask_dst = 0;
1391 op->regmask_dst = (1 << xBP) | (1 << xSP);
1392 op->regmask_src = 1 << xBP;
1397 op->regmask_dst |= mxST0;
1401 op->regmask_dst |= mxST0;
1402 if (IS(words[op_w] + 3, "1"))
1403 op->operand[0].val = X87_CONST_1;
1404 else if (IS(words[op_w] + 3, "ln2"))
1405 op->operand[0].val = X87_CONST_LN2;
1406 else if (IS(words[op_w] + 3, "z"))
1407 op->operand[0].val = X87_CONST_Z;
1414 op->regmask_src |= mxST0;
1423 op->regmask_src |= mxST0;
1424 if (op->operand_cnt == 2)
1425 op->regmask_src |= op->regmask_dst;
1426 else if (op->operand_cnt == 1) {
1427 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1428 op->operand[0].type = OPT_REG;
1429 op->operand[0].lmod = OPLM_QWORD;
1430 op->operand[0].reg = xST0;
1431 op->regmask_dst |= mxST0;
1434 // IDA doesn't use this
1435 aerr("no operands?\n");
1449 op->regmask_src |= mxST0;
1450 op->regmask_dst |= mxST0;
1455 op->regmask_src |= mxST0 | mxST1;
1456 op->regmask_dst |= mxST0;
1464 op->regmask_src |= mxST0;
1471 if (op->operand[0].type == OPT_REG
1472 && op->operand[1].type == OPT_CONST)
1474 struct parsed_opr *op1 = &op->operand[1];
1475 if ((op->op == OP_AND && op1->val == 0)
1478 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1479 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1481 op->regmask_src = 0;
1486 static const char *op_name(struct parsed_op *po)
1488 static char buf[16];
1492 if (po->op == OP_JCC || po->op == OP_SCC) {
1494 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1497 strcpy(p, parsed_flag_op_names[po->pfo]);
1501 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1502 if (op_table[i].op == po->op)
1503 return op_table[i].name;
1509 static const char *dump_op(struct parsed_op *po)
1511 static char out[128];
1518 snprintf(out, sizeof(out), "%s", op_name(po));
1519 for (i = 0; i < po->operand_cnt; i++) {
1523 snprintf(p, sizeof(out) - (p - out),
1524 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1525 po->operand[i].name);
1531 static const char *lmod_type_u(struct parsed_op *po,
1532 enum opr_lenmod lmod)
1544 ferr(po, "invalid lmod: %d\n", lmod);
1545 return "(_invalid_)";
1549 static const char *lmod_cast_u(struct parsed_op *po,
1550 enum opr_lenmod lmod)
1562 ferr(po, "invalid lmod: %d\n", lmod);
1563 return "(_invalid_)";
1567 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1568 enum opr_lenmod lmod)
1580 ferr(po, "invalid lmod: %d\n", lmod);
1581 return "(_invalid_)";
1585 static const char *lmod_cast_s(struct parsed_op *po,
1586 enum opr_lenmod lmod)
1598 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1599 return "(_invalid_)";
1603 static const char *lmod_cast(struct parsed_op *po,
1604 enum opr_lenmod lmod, int is_signed)
1607 lmod_cast_s(po, lmod) :
1608 lmod_cast_u(po, lmod);
1611 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1623 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1628 static const char *opr_name(struct parsed_op *po, int opr_num)
1630 if (opr_num >= po->operand_cnt)
1631 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1632 return po->operand[opr_num].name;
1635 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1637 if (opr_num >= po->operand_cnt)
1638 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1639 if (po->operand[opr_num].type != OPT_CONST)
1640 ferr(po, "opr %d: const expected\n", opr_num);
1641 return po->operand[opr_num].val;
1644 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1646 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1647 ferr(po, "invalid reg: %d\n", popr->reg);
1648 return regs_r32[popr->reg];
1651 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1653 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1655 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1657 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1659 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1664 *is_signed = cast[1] == 's' ? 1 : 0;
1668 static int check_deref_cast(const char *cast, int *bits)
1670 if (IS_START(cast, "*(u8 *)"))
1672 else if (IS_START(cast, "*(u16 *)"))
1674 else if (IS_START(cast, "*(u32 *)"))
1676 else if (IS_START(cast, "*(u64 *)"))
1684 // cast1 is the "final" cast
1685 static const char *simplify_cast(const char *cast1, const char *cast2)
1687 static char buf[256];
1695 if (IS(cast1, cast2))
1698 if (check_simple_cast(cast1, &bits1, &s1) == 0
1699 && check_simple_cast(cast2, &bits2, &s2) == 0)
1704 if (check_simple_cast(cast1, &bits1, &s1) == 0
1705 && check_deref_cast(cast2, &bits2) == 0)
1707 if (bits1 == bits2) {
1708 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1713 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1716 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1720 static const char *simplify_cast_num(const char *cast, unsigned int val)
1722 if (IS(cast, "(u8)") && val < 0x100)
1724 if (IS(cast, "(s8)") && val < 0x80)
1726 if (IS(cast, "(u16)") && val < 0x10000)
1728 if (IS(cast, "(s16)") && val < 0x8000)
1730 if (IS(cast, "(s32)") && val < 0x80000000)
1736 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1745 namelen = strlen(name);
1747 p = strpbrk(name, "+-");
1751 ferr(po, "equ parse failed for '%s'\n", name);
1753 *extra_offs = strtol(p, &endp, 16);
1755 ferr(po, "equ parse failed for '%s'\n", name);
1758 for (i = 0; i < g_eqcnt; i++)
1759 if (strncmp(g_eqs[i].name, name, namelen) == 0
1760 && g_eqs[i].name[namelen] == 0)
1764 ferr(po, "unresolved equ name: '%s'\n", name);
1771 static int is_stack_access(struct parsed_op *po,
1772 const struct parsed_opr *popr)
1774 return (parse_stack_el(popr->name, NULL, NULL, 0)
1775 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1776 && IS_START(popr->name, "ebp")));
1779 static void parse_stack_access(struct parsed_op *po,
1780 const char *name, char *ofs_reg, int *offset_out,
1781 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1783 const char *bp_arg = "";
1784 const char *p = NULL;
1785 struct parsed_equ *eq;
1792 if (IS_START(name, "ebp-")
1793 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1796 if (IS_START(p, "0x"))
1798 offset = strtoul(p, &endp, 16);
1802 ferr(po, "ebp- parse of '%s' failed\n", name);
1805 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1806 eq = equ_find(po, bp_arg, &offset);
1808 ferr(po, "detected but missing eq\n");
1809 offset += eq->offset;
1812 if (!strncmp(name, "ebp", 3))
1815 // yes it sometimes LEAs ra for compares..
1816 if (!is_lea && ofs_reg[0] == 0
1817 && stack_ra <= offset && offset < stack_ra + 4)
1819 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1822 *offset_out = offset;
1824 *stack_ra_out = stack_ra;
1826 *bp_arg_out = bp_arg;
1829 static int parse_stack_esp_offset(struct parsed_op *po,
1830 const char *name, int *offset_out)
1832 char ofs_reg[16] = { 0, };
1833 struct parsed_equ *eq;
1839 if (strstr(name, "esp") == NULL)
1841 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1842 if (bp_arg == NULL) {
1843 // just plain offset?
1844 if (!IS_START(name, "esp+"))
1846 offset = strtol(name + 4, &endp, 0);
1847 if (endp == NULL || *endp != 0)
1849 *offset_out = offset;
1853 if (ofs_reg[0] != 0)
1855 eq = equ_find(po, bp_arg, &offset);
1857 ferr(po, "detected but missing eq\n");
1858 offset += eq->offset;
1859 *offset_out = base_val + offset;
1863 static int stack_frame_access(struct parsed_op *po,
1864 struct parsed_opr *popr, char *buf, size_t buf_size,
1865 const char *name, const char *cast, int is_src, int is_lea)
1867 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1868 const char *prefix = "";
1869 const char *bp_arg = NULL;
1870 char ofs_reg[16] = { 0, };
1871 int i, arg_i, arg_s;
1878 if (po->flags & OPF_EBP_S)
1879 ferr(po, "stack_frame_access while ebp is scratch\n");
1881 parse_stack_access(po, name, ofs_reg, &offset,
1882 &stack_ra, &bp_arg, is_lea);
1884 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1886 if (offset > stack_ra)
1888 arg_i = (offset - stack_ra - 4) / 4;
1889 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1891 if (g_func_pp->is_vararg
1892 && arg_i == g_func_pp->argc_stack && is_lea)
1894 // should be va_list
1897 snprintf(buf, buf_size, "%sap", cast);
1900 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1901 offset, bp_arg, arg_i);
1903 if (ofs_reg[0] != 0)
1904 ferr(po, "offset reg on arg access?\n");
1906 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1907 if (g_func_pp->arg[i].reg != NULL)
1913 if (i == g_func_pp->argc)
1914 ferr(po, "arg %d not in prototype?\n", arg_i);
1916 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1923 ferr(po, "lea/byte to arg?\n");
1924 if (is_src && (offset & 3) == 0)
1925 snprintf(buf, buf_size, "%sa%d",
1926 simplify_cast(cast, "(u8)"), i + 1);
1928 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1929 cast, offset & 3, i + 1);
1934 ferr(po, "lea/word to arg?\n");
1939 ferr(po, "problematic arg store\n");
1940 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1941 simplify_cast(cast, "*(u16 *)"), i + 1);
1944 ferr(po, "unaligned arg word load\n");
1946 else if (is_src && (offset & 2) == 0)
1947 snprintf(buf, buf_size, "%sa%d",
1948 simplify_cast(cast, "(u16)"), i + 1);
1950 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1951 cast, (offset & 2) ? "HI" : "LO", i + 1);
1963 snprintf(buf, buf_size, "(u32)&a%d + %d",
1966 ferr(po, "unaligned arg store\n");
1968 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1969 snprintf(buf, buf_size, "%s(a%d >> %d)",
1970 prefix, i + 1, (offset & 3) * 8);
1974 snprintf(buf, buf_size, "%s%sa%d",
1975 prefix, is_lea ? "&" : "", i + 1);
1980 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1984 strcat(g_comment, " unaligned");
1987 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
1988 if (tmp_lmod != OPLM_DWORD
1989 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
1990 < lmod_bytes(po, popr->lmod) + (offset & 3))))
1992 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
1993 i + 1, offset, g_func_pp->arg[i].type.name);
1995 // can't check this because msvc likes to reuse
1996 // arg space for scratch..
1997 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
1998 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2002 if (g_stack_fsz == 0)
2003 ferr(po, "stack var access without stackframe\n");
2004 g_stack_frame_used = 1;
2006 sf_ofs = g_stack_fsz + offset;
2007 if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2008 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2018 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2019 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2023 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2024 // known unaligned or possibly unaligned
2025 strcat(g_comment, " unaligned");
2027 prefix = "*(u16 *)&";
2028 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2029 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2032 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2036 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2037 // known unaligned or possibly unaligned
2038 strcat(g_comment, " unaligned");
2040 prefix = "*(u32 *)&";
2041 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2042 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2045 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2049 ferr_assert(po, !(sf_ofs & 7));
2050 ferr_assert(po, ofs_reg[0] == 0);
2051 // only used for x87 int64/float, float sets is_lea
2053 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2055 snprintf(buf, buf_size, "*(s64 *)&sf.q[%d]", sf_ofs / 8);
2059 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2066 static void check_func_pp(struct parsed_op *po,
2067 const struct parsed_proto *pp, const char *pfx)
2069 enum opr_lenmod tmp_lmod;
2073 if (pp->argc_reg != 0) {
2074 if (!g_allow_user_icall && !pp->is_fastcall) {
2075 pp_print(buf, sizeof(buf), pp);
2076 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2078 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2079 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2080 pfx, pp->argc_reg, pp->argc_stack);
2083 // fptrs must use 32bit args, callsite might have no information and
2084 // lack a cast to smaller types, which results in incorrectly masked
2085 // args passed (callee may assume masked args, it does on ARM)
2086 if (!pp->is_osinc) {
2087 for (i = 0; i < pp->argc; i++) {
2088 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2089 if (ret && tmp_lmod != OPLM_DWORD)
2090 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2091 i + 1, pp->arg[i].type.name);
2096 static const char *check_label_read_ref(struct parsed_op *po,
2099 const struct parsed_proto *pp;
2101 pp = proto_parse(g_fhdr, name, 0);
2103 ferr(po, "proto_parse failed for ref '%s'\n", name);
2106 check_func_pp(po, pp, "ref");
2111 static char *out_src_opr(char *buf, size_t buf_size,
2112 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2115 char tmp1[256], tmp2[256];
2124 switch (popr->type) {
2127 ferr(po, "lea from reg?\n");
2129 switch (popr->lmod) {
2131 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2134 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2137 snprintf(buf, buf_size, "%s%s",
2138 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2141 if (popr->name[1] == 'h') // XXX..
2142 snprintf(buf, buf_size, "%s(%s >> 8)",
2143 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2145 snprintf(buf, buf_size, "%s%s",
2146 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2149 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2154 if (is_stack_access(po, popr)) {
2155 stack_frame_access(po, popr, buf, buf_size,
2156 popr->name, cast, 1, is_lea);
2160 strcpy(expr, popr->name);
2161 if (strchr(expr, '[')) {
2162 // special case: '[' can only be left for label[reg] form
2163 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2165 ferr(po, "parse failure for '%s'\n", expr);
2166 if (tmp1[0] == '(') {
2167 // (off_4FFF50+3)[eax]
2168 p = strchr(tmp1 + 1, ')');
2169 if (p == NULL || p[1] != 0)
2170 ferr(po, "parse failure (2) for '%s'\n", expr);
2172 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2174 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2177 // XXX: do we need more parsing?
2179 snprintf(buf, buf_size, "%s", expr);
2183 snprintf(buf, buf_size, "%s(%s)",
2184 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2188 name = check_label_read_ref(po, popr->name);
2189 if (cast[0] == 0 && popr->is_ptr)
2193 snprintf(buf, buf_size, "(u32)&%s", name);
2194 else if (popr->size_lt)
2195 snprintf(buf, buf_size, "%s%s%s%s", cast,
2196 lmod_cast_u_ptr(po, popr->lmod),
2197 popr->is_array ? "" : "&", name);
2199 snprintf(buf, buf_size, "%s%s%s", cast, name,
2200 popr->is_array ? "[0]" : "");
2204 name = check_label_read_ref(po, popr->name);
2208 ferr(po, "lea an offset?\n");
2209 snprintf(buf, buf_size, "%s&%s", cast, name);
2214 ferr(po, "lea from const?\n");
2216 printf_number(tmp1, sizeof(tmp1), popr->val);
2217 if (popr->val == 0 && strchr(cast, '*'))
2218 snprintf(buf, buf_size, "NULL");
2220 snprintf(buf, buf_size, "%s%s",
2221 simplify_cast_num(cast, popr->val), tmp1);
2225 ferr(po, "invalid src type: %d\n", popr->type);
2231 // note: may set is_ptr (we find that out late for ebp frame..)
2232 static char *out_dst_opr(char *buf, size_t buf_size,
2233 struct parsed_op *po, struct parsed_opr *popr)
2235 switch (popr->type) {
2237 switch (popr->lmod) {
2239 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2242 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2246 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2250 if (popr->name[1] == 'h') // XXX..
2251 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2253 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2256 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2261 if (is_stack_access(po, popr)) {
2262 stack_frame_access(po, popr, buf, buf_size,
2263 popr->name, "", 0, 0);
2267 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2270 if (popr->size_mismatch)
2271 snprintf(buf, buf_size, "%s%s%s",
2272 lmod_cast_u_ptr(po, popr->lmod),
2273 popr->is_array ? "" : "&", popr->name);
2275 snprintf(buf, buf_size, "%s%s", popr->name,
2276 popr->is_array ? "[0]" : "");
2280 ferr(po, "invalid dst type: %d\n", popr->type);
2286 static char *out_src_opr_u32(char *buf, size_t buf_size,
2287 struct parsed_op *po, struct parsed_opr *popr)
2289 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2292 static char *out_src_opr_float(char *buf, size_t buf_size,
2293 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2295 const char *cast = NULL;
2298 switch (popr->type) {
2300 if (popr->reg < xST0 || popr->reg > xST7)
2301 ferr(po, "bad reg: %d\n", popr->reg);
2303 if (need_float_stack) {
2304 if (popr->reg == xST0)
2305 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2307 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2311 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2317 switch (popr->lmod) {
2325 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2328 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2329 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2333 ferr(po, "invalid float type: %d\n", popr->type);
2339 static char *out_dst_opr_float(char *buf, size_t buf_size,
2340 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2343 return out_src_opr_float(buf, buf_size, po, popr, need_float_stack);
2346 static void out_test_for_cc(char *buf, size_t buf_size,
2347 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2348 enum opr_lenmod lmod, const char *expr)
2350 const char *cast, *scast;
2352 cast = lmod_cast_u(po, lmod);
2353 scast = lmod_cast_s(po, lmod);
2357 case PFO_BE: // CF==1||ZF==1; CF=0
2358 snprintf(buf, buf_size, "(%s%s %s 0)",
2359 cast, expr, is_inv ? "!=" : "==");
2363 case PFO_L: // SF!=OF; OF=0
2364 snprintf(buf, buf_size, "(%s%s %s 0)",
2365 scast, expr, is_inv ? ">=" : "<");
2368 case PFO_LE: // ZF==1||SF!=OF; OF=0
2369 snprintf(buf, buf_size, "(%s%s %s 0)",
2370 scast, expr, is_inv ? ">" : "<=");
2375 snprintf(buf, buf_size, "(%d)", !!is_inv);
2379 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2383 static void out_cmp_for_cc(char *buf, size_t buf_size,
2384 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2387 const char *cast, *scast, *cast_use;
2388 char buf1[256], buf2[256];
2389 enum opr_lenmod lmod;
2391 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2392 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2393 po->operand[0].lmod, po->operand[1].lmod);
2394 lmod = po->operand[0].lmod;
2396 cast = lmod_cast_u(po, lmod);
2397 scast = lmod_cast_s(po, lmod);
2413 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2416 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2417 if (po->op == OP_DEC)
2418 snprintf(buf2, sizeof(buf2), "1");
2421 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2423 strcat(cast_op2, "-");
2424 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2429 // note: must be unsigned compare
2430 snprintf(buf, buf_size, "(%s %s %s)",
2431 buf1, is_inv ? ">=" : "<", buf2);
2435 snprintf(buf, buf_size, "(%s %s %s)",
2436 buf1, is_inv ? "!=" : "==", buf2);
2440 // note: must be unsigned compare
2441 snprintf(buf, buf_size, "(%s %s %s)",
2442 buf1, is_inv ? ">" : "<=", buf2);
2445 if (is_inv && lmod == OPLM_BYTE
2446 && po->operand[1].type == OPT_CONST
2447 && po->operand[1].val == 0xff)
2449 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2450 snprintf(buf, buf_size, "(0)");
2454 // note: must be signed compare
2456 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2457 scast, buf1, buf2, is_inv ? ">=" : "<");
2461 snprintf(buf, buf_size, "(%s %s %s)",
2462 buf1, is_inv ? ">=" : "<", buf2);
2466 snprintf(buf, buf_size, "(%s %s %s)",
2467 buf1, is_inv ? ">" : "<=", buf2);
2475 static void out_cmp_test(char *buf, size_t buf_size,
2476 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2478 char buf1[256], buf2[256], buf3[256];
2480 if (po->op == OP_TEST) {
2481 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2482 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2485 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2486 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2487 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2489 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2490 po->operand[0].lmod, buf3);
2492 else if (po->op == OP_CMP) {
2493 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2496 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2499 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2500 struct parsed_opr *popr2)
2502 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2503 ferr(po, "missing lmod for both operands\n");
2505 if (popr1->lmod == OPLM_UNSPEC)
2506 popr1->lmod = popr2->lmod;
2507 else if (popr2->lmod == OPLM_UNSPEC)
2508 popr2->lmod = popr1->lmod;
2509 else if (popr1->lmod != popr2->lmod) {
2510 if (popr1->type_from_var) {
2511 popr1->size_mismatch = 1;
2512 if (popr1->lmod < popr2->lmod)
2514 popr1->lmod = popr2->lmod;
2516 else if (popr2->type_from_var) {
2517 popr2->size_mismatch = 1;
2518 if (popr2->lmod < popr1->lmod)
2520 popr2->lmod = popr1->lmod;
2523 ferr(po, "conflicting lmods: %d vs %d\n",
2524 popr1->lmod, popr2->lmod);
2528 static const char *op_to_c(struct parsed_op *po)
2552 ferr(po, "op_to_c was supplied with %d\n", po->op);
2556 // last op in stream - unconditional branch or ret
2557 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2558 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2559 && ops[_i].op != OP_CALL))
2561 #define check_i(po, i) \
2563 ferr(po, "bad " #i ": %d\n", i)
2565 // note: this skips over calls and rm'd stuff assuming they're handled
2566 // so it's intended to use at one of final passes
2567 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2568 int depth, int seen_noreturn, int flags_set)
2570 struct parsed_op *po;
2575 for (; i < opcnt; i++) {
2577 if (po->cc_scratch == magic)
2578 return ret; // already checked
2579 po->cc_scratch = magic;
2581 if (po->flags & OPF_TAIL) {
2582 if (po->op == OP_CALL) {
2583 if (po->pp != NULL && po->pp->is_noreturn)
2592 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2595 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2596 if (po->btj != NULL) {
2598 for (j = 0; j < po->btj->count; j++) {
2599 check_i(po, po->btj->d[j].bt_i);
2600 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2601 depth, seen_noreturn, flags_set);
2603 return ret; // dead end
2608 check_i(po, po->bt_i);
2609 if (po->flags & OPF_CJMP) {
2610 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2611 depth, seen_noreturn, flags_set);
2613 return ret; // dead end
2622 if ((po->op == OP_POP || po->op == OP_PUSH)
2623 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2628 if (po->op == OP_PUSH) {
2631 else if (po->op == OP_POP) {
2632 if (relevant && depth == 0) {
2633 po->flags |= flags_set;
2641 // for noreturn, assume msvc skipped stack cleanup
2642 return seen_noreturn ? 1 : -1;
2645 // scan for 'reg' pop backwards starting from i
2646 // intended to use for register restore search, so other reg
2647 // references are considered an error
2648 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2650 struct parsed_op *po;
2651 struct label_ref *lr;
2654 ops[i].cc_scratch = magic;
2658 if (g_labels[i] != NULL) {
2659 lr = &g_label_refs[i];
2660 for (; lr != NULL; lr = lr->next) {
2661 check_i(&ops[i], lr->i);
2662 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2666 if (i > 0 && LAST_OP(i - 1))
2674 if (ops[i].cc_scratch == magic)
2676 ops[i].cc_scratch = magic;
2679 if (po->op == OP_POP && po->operand[0].reg == reg) {
2680 if (po->flags & (OPF_RMD|OPF_DONE))
2683 po->flags |= set_flags;
2687 // this also covers the case where we reach corresponding push
2688 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2692 // nothing interesting on this path
2696 static void find_reachable_exits(int i, int opcnt, int magic,
2697 int *exits, int *exit_count)
2699 struct parsed_op *po;
2702 for (; i < opcnt; i++)
2705 if (po->cc_scratch == magic)
2707 po->cc_scratch = magic;
2709 if (po->flags & OPF_TAIL) {
2710 ferr_assert(po, *exit_count < MAX_EXITS);
2711 exits[*exit_count] = i;
2716 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2717 if (po->flags & OPF_RMD)
2720 if (po->btj != NULL) {
2721 for (j = 0; j < po->btj->count; j++) {
2722 check_i(po, po->btj->d[j].bt_i);
2723 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2729 check_i(po, po->bt_i);
2730 if (po->flags & OPF_CJMP)
2731 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2739 // scan for 'reg' pop backwards starting from exits (all paths)
2740 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2742 static int exits[MAX_EXITS];
2743 static int exit_count;
2748 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2750 ferr_assert(&ops[i], exit_count > 0);
2753 for (j = 0; j < exit_count; j++) {
2754 ret = scan_for_rsave_pop_reg(exits[j], i + opcnt * 16 + set_flags,
2763 // scan for one or more pop of push <const>
2764 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2765 int push_i, int is_probe)
2767 struct parsed_op *po;
2768 struct label_ref *lr;
2772 for (; i < opcnt; i++)
2775 if (po->cc_scratch == magic)
2776 return ret; // already checked
2777 po->cc_scratch = magic;
2779 if (po->flags & OPF_JMP) {
2780 if (po->flags & OPF_RMD)
2782 if (po->op == OP_CALL)
2785 if (po->btj != NULL) {
2786 for (j = 0; j < po->btj->count; j++) {
2787 check_i(po, po->btj->d[j].bt_i);
2788 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2796 check_i(po, po->bt_i);
2797 if (po->flags & OPF_CJMP) {
2798 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2809 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2812 if (g_labels[i] != NULL) {
2813 // all refs must be visited
2814 lr = &g_label_refs[i];
2815 for (; lr != NULL; lr = lr->next) {
2817 if (ops[lr->i].cc_scratch != magic)
2820 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2824 if (po->op == OP_POP)
2826 if (po->flags & (OPF_RMD|OPF_DONE))
2830 po->flags |= OPF_DONE;
2831 po->datap = &ops[push_i];
2840 static void scan_for_pop_const(int i, int opcnt, int magic)
2844 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2846 ops[i].flags |= OPF_RMD | OPF_DONE;
2847 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2851 // check if all branch targets within a marked path are also marked
2852 // note: the path checked must not be empty or end with a branch
2853 static int check_path_branches(int opcnt, int magic)
2855 struct parsed_op *po;
2858 for (i = 0; i < opcnt; i++) {
2860 if (po->cc_scratch != magic)
2863 if (po->flags & OPF_JMP) {
2864 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2867 if (po->btj != NULL) {
2868 for (j = 0; j < po->btj->count; j++) {
2869 check_i(po, po->btj->d[j].bt_i);
2870 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2875 check_i(po, po->bt_i);
2876 if (ops[po->bt_i].cc_scratch != magic)
2878 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2886 // scan for multiple pushes for given pop
2887 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2890 int reg = ops[pop_i].operand[0].reg;
2891 struct parsed_op *po;
2892 struct label_ref *lr;
2895 ops[i].cc_scratch = magic;
2899 if (g_labels[i] != NULL) {
2900 lr = &g_label_refs[i];
2901 for (; lr != NULL; lr = lr->next) {
2902 check_i(&ops[i], lr->i);
2903 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2907 if (i > 0 && LAST_OP(i - 1))
2915 if (ops[i].cc_scratch == magic)
2917 ops[i].cc_scratch = magic;
2920 if (po->op == OP_CALL)
2922 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2925 if (po->op == OP_PUSH)
2927 if (po->datap != NULL)
2929 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2930 // leave this case for reg save/restore handlers
2934 po->flags |= OPF_PPUSH | OPF_DONE;
2935 po->datap = &ops[pop_i];
2944 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2946 int magic = i + opcnt * 14;
2949 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2951 ret = check_path_branches(opcnt, magic);
2953 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2954 *regmask_pp |= 1 << ops[i].operand[0].reg;
2955 scan_pushes_for_pop_r(i, magic + 1, i, 0);
2960 static void scan_propagate_df(int i, int opcnt)
2962 struct parsed_op *po = &ops[i];
2965 for (; i < opcnt; i++) {
2967 if (po->flags & OPF_DF)
2968 return; // already resolved
2969 po->flags |= OPF_DF;
2971 if (po->op == OP_CALL)
2972 ferr(po, "call with DF set?\n");
2974 if (po->flags & OPF_JMP) {
2975 if (po->btj != NULL) {
2977 for (j = 0; j < po->btj->count; j++) {
2978 check_i(po, po->btj->d[j].bt_i);
2979 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
2984 if (po->flags & OPF_RMD)
2986 check_i(po, po->bt_i);
2987 if (po->flags & OPF_CJMP)
2988 scan_propagate_df(po->bt_i, opcnt);
2994 if (po->flags & OPF_TAIL)
2997 if (po->op == OP_CLD) {
2998 po->flags |= OPF_RMD | OPF_DONE;
3003 ferr(po, "missing DF clear?\n");
3006 // is operand 'opr' referenced by parsed_op 'po'?
3007 static int is_opr_referenced(const struct parsed_opr *opr,
3008 const struct parsed_op *po)
3012 if (opr->type == OPT_REG) {
3013 mask = po->regmask_dst | po->regmask_src;
3014 if (po->op == OP_CALL)
3015 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3016 if ((1 << opr->reg) & mask)
3022 for (i = 0; i < po->operand_cnt; i++)
3023 if (IS(po->operand[0].name, opr->name))
3029 // is operand 'opr' read by parsed_op 'po'?
3030 static int is_opr_read(const struct parsed_opr *opr,
3031 const struct parsed_op *po)
3033 if (opr->type == OPT_REG) {
3034 if (po->regmask_src & (1 << opr->reg))
3044 // is operand 'opr' modified by parsed_op 'po'?
3045 static int is_opr_modified(const struct parsed_opr *opr,
3046 const struct parsed_op *po)
3050 if (opr->type == OPT_REG) {
3051 if (po->op == OP_CALL) {
3052 mask = po->regmask_dst;
3053 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3054 if (mask & (1 << opr->reg))
3060 if (po->regmask_dst & (1 << opr->reg))
3066 return IS(po->operand[0].name, opr->name);
3069 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3070 static int is_any_opr_modified(const struct parsed_op *po_test,
3071 const struct parsed_op *po, int c_mode)
3076 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3079 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3082 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3085 // in reality, it can wreck any register, but in decompiled C
3086 // version it can only overwrite eax or edx:eax
3087 mask = (1 << xAX) | (1 << xDX);
3091 if (po->op == OP_CALL
3092 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3095 for (i = 0; i < po_test->operand_cnt; i++)
3096 if (IS(po_test->operand[i].name, po->operand[0].name))
3102 // scan for any po_test operand modification in range given
3103 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3106 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3109 for (; i < opcnt; i++) {
3110 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3117 // scan for po_test operand[0] modification in range given
3118 static int scan_for_mod_opr0(struct parsed_op *po_test,
3121 for (; i < opcnt; i++) {
3122 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3129 static int try_resolve_const(int i, const struct parsed_opr *opr,
3130 int magic, unsigned int *val);
3132 static int scan_for_flag_set(int i, int opcnt, int magic,
3133 int *branched, int *setters, int *setter_cnt)
3135 struct label_ref *lr;
3139 if (ops[i].cc_scratch == magic) {
3140 // is this a problem?
3141 //ferr(&ops[i], "%s looped\n", __func__);
3144 ops[i].cc_scratch = magic;
3146 if (g_labels[i] != NULL) {
3149 lr = &g_label_refs[i];
3150 for (; lr->next; lr = lr->next) {
3151 check_i(&ops[i], lr->i);
3152 ret = scan_for_flag_set(lr->i, opcnt, magic,
3153 branched, setters, setter_cnt);
3158 check_i(&ops[i], lr->i);
3159 if (i > 0 && LAST_OP(i - 1)) {
3163 ret = scan_for_flag_set(lr->i, opcnt, magic,
3164 branched, setters, setter_cnt);
3170 if (ops[i].flags & OPF_FLAGS) {
3171 setters[*setter_cnt] = i;
3174 if (ops[i].flags & OPF_REP) {
3175 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3178 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3179 if (ret != 1 || uval == 0) {
3180 // can't treat it as full setter because of ecx=0 case,
3181 // also disallow delayed compare
3190 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3197 // scan back for cdq, if anything modifies edx, fail
3198 static int scan_for_cdq_edx(int i)
3201 if (g_labels[i] != NULL) {
3202 if (g_label_refs[i].next != NULL)
3204 if (i > 0 && LAST_OP(i - 1)) {
3205 i = g_label_refs[i].i;
3212 if (ops[i].op == OP_CDQ)
3215 if (ops[i].regmask_dst & (1 << xDX))
3222 static int scan_for_reg_clear(int i, int reg)
3225 if (g_labels[i] != NULL) {
3226 if (g_label_refs[i].next != NULL)
3228 if (i > 0 && LAST_OP(i - 1)) {
3229 i = g_label_refs[i].i;
3236 if (ops[i].op == OP_XOR
3237 && ops[i].operand[0].lmod == OPLM_DWORD
3238 && ops[i].operand[0].reg == ops[i].operand[1].reg
3239 && ops[i].operand[0].reg == reg)
3242 if (ops[i].regmask_dst & (1 << reg))
3249 static void patch_esp_adjust(struct parsed_op *po, int adj)
3251 ferr_assert(po, po->op == OP_ADD);
3252 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3253 ferr_assert(po, po->operand[1].type == OPT_CONST);
3255 // this is a bit of a hack, but deals with use of
3256 // single adj for multiple calls
3257 po->operand[1].val -= adj;
3258 po->flags |= OPF_RMD;
3259 if (po->operand[1].val == 0)
3260 po->flags |= OPF_DONE;
3261 ferr_assert(po, (int)po->operand[1].val >= 0);
3264 // scan for positive, constant esp adjust
3265 // multipath case is preliminary
3266 static int scan_for_esp_adjust(int i, int opcnt,
3267 int adj_expect, int *adj, int *is_multipath, int do_update)
3269 int adj_expect_unknown = 0;
3270 struct parsed_op *po;
3274 *adj = *is_multipath = 0;
3275 if (adj_expect < 0) {
3276 adj_expect_unknown = 1;
3277 adj_expect = 32 * 4; // enough?
3280 for (; i < opcnt && *adj < adj_expect; i++) {
3281 if (g_labels[i] != NULL)
3285 if (po->flags & OPF_DONE)
3288 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3289 if (po->operand[1].type != OPT_CONST)
3290 ferr(&ops[i], "non-const esp adjust?\n");
3291 *adj += po->operand[1].val;
3293 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3296 patch_esp_adjust(po, adj_expect);
3298 po->flags |= OPF_RMD;
3302 else if (po->op == OP_PUSH) {
3303 //if (first_pop == -1)
3304 // first_pop = -2; // none
3305 *adj -= lmod_bytes(po, po->operand[0].lmod);
3307 else if (po->op == OP_POP) {
3308 if (!(po->flags & OPF_DONE)) {
3309 // seems like msvc only uses 'pop ecx' for stack realignment..
3310 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3312 if (first_pop == -1 && *adj >= 0)
3315 if (do_update && *adj >= 0) {
3316 po->flags |= OPF_RMD;
3318 po->flags |= OPF_DONE | OPF_NOREGS;
3321 *adj += lmod_bytes(po, po->operand[0].lmod);
3322 if (*adj > adj_best)
3325 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3326 if (po->op == OP_JMP && po->btj == NULL) {
3332 if (po->op != OP_CALL)
3334 if (po->operand[0].type != OPT_LABEL)
3336 if (po->pp != NULL && po->pp->is_stdcall)
3338 if (adj_expect_unknown && first_pop >= 0)
3340 // assume it's another cdecl call
3344 if (first_pop >= 0) {
3345 // probably only 'pop ecx' was used
3353 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3355 struct parsed_op *po;
3359 ferr(ops, "%s: followed bad branch?\n", __func__);
3361 for (; i < opcnt; i++) {
3363 if (po->cc_scratch == magic)
3365 po->cc_scratch = magic;
3368 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3369 if (po->btj != NULL) {
3371 for (j = 0; j < po->btj->count; j++)
3372 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3376 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3377 if (!(po->flags & OPF_CJMP))
3380 if (po->flags & OPF_TAIL)
3385 static const struct parsed_proto *try_recover_pp(
3386 struct parsed_op *po, const struct parsed_opr *opr,
3387 int is_call, int *search_instead)
3389 const struct parsed_proto *pp = NULL;
3393 // maybe an arg of g_func?
3394 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3396 char ofs_reg[16] = { 0, };
3397 int arg, arg_s, arg_i;
3404 parse_stack_access(po, opr->name, ofs_reg,
3405 &offset, &stack_ra, NULL, 0);
3406 if (ofs_reg[0] != 0)
3407 ferr(po, "offset reg on arg access?\n");
3408 if (offset <= stack_ra) {
3409 // search who set the stack var instead
3410 if (search_instead != NULL)
3411 *search_instead = 1;
3415 arg_i = (offset - stack_ra - 4) / 4;
3416 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3417 if (g_func_pp->arg[arg].reg != NULL)
3423 if (arg == g_func_pp->argc)
3424 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3426 pp = g_func_pp->arg[arg].pp;
3429 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3430 check_func_pp(po, pp, "icall arg");
3433 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3435 p = strchr(opr->name + 1, '[');
3436 memcpy(buf, opr->name, p - opr->name);
3437 buf[p - opr->name] = 0;
3438 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3440 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3441 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3444 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3447 check_func_pp(po, pp, "reg-fptr ref");
3453 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3454 int magic, const struct parsed_proto **pp_found, int *pp_i,
3457 const struct parsed_proto *pp = NULL;
3458 struct parsed_op *po;
3459 struct label_ref *lr;
3461 ops[i].cc_scratch = magic;
3464 if (g_labels[i] != NULL) {
3465 lr = &g_label_refs[i];
3466 for (; lr != NULL; lr = lr->next) {
3467 check_i(&ops[i], lr->i);
3468 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3470 if (i > 0 && LAST_OP(i - 1))
3478 if (ops[i].cc_scratch == magic)
3480 ops[i].cc_scratch = magic;
3482 if (!(ops[i].flags & OPF_DATA))
3484 if (!is_opr_modified(opr, &ops[i]))
3486 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3487 // most probably trashed by some processing
3492 opr = &ops[i].operand[1];
3493 if (opr->type != OPT_REG)
3497 po = (i >= 0) ? &ops[i] : ops;
3500 // reached the top - can only be an arg-reg
3501 if (opr->type != OPT_REG || g_func_pp == NULL)
3504 for (i = 0; i < g_func_pp->argc; i++) {
3505 if (g_func_pp->arg[i].reg == NULL)
3507 if (IS(opr->name, g_func_pp->arg[i].reg))
3510 if (i == g_func_pp->argc)
3512 pp = g_func_pp->arg[i].pp;
3514 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3515 i + 1, g_func_pp->arg[i].reg);
3516 check_func_pp(po, pp, "icall reg-arg");
3519 pp = try_recover_pp(po, opr, 1, NULL);
3521 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3522 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3523 || (*pp_found)->is_stdcall != pp->is_stdcall
3524 || (*pp_found)->is_fptr != pp->is_fptr
3525 || (*pp_found)->argc != pp->argc
3526 || (*pp_found)->argc_reg != pp->argc_reg
3527 || (*pp_found)->argc_stack != pp->argc_stack)
3529 ferr(po, "icall: parsed_proto mismatch\n");
3539 static void add_label_ref(struct label_ref *lr, int op_i)
3541 struct label_ref *lr_new;
3548 lr_new = calloc(1, sizeof(*lr_new));
3550 lr_new->next = lr->next;
3554 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3556 struct parsed_op *po = &ops[i];
3557 struct parsed_data *pd;
3558 char label[NAMELEN], *p;
3561 p = strchr(po->operand[0].name, '[');
3565 len = p - po->operand[0].name;
3566 strncpy(label, po->operand[0].name, len);
3569 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3570 if (IS(g_func_pd[j].label, label)) {
3576 //ferr(po, "label '%s' not parsed?\n", label);
3579 if (pd->type != OPT_OFFSET)
3580 ferr(po, "label '%s' with non-offset data?\n", label);
3582 // find all labels, link
3583 for (j = 0; j < pd->count; j++) {
3584 for (l = 0; l < opcnt; l++) {
3585 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3586 add_label_ref(&g_label_refs[l], i);
3596 static void clear_labels(int count)
3600 for (i = 0; i < count; i++) {
3601 if (g_labels[i] != NULL) {
3608 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3613 for (i = 0; i < pp->argc; i++) {
3614 if (pp->arg[i].reg != NULL) {
3615 reg = char_array_i(regs_r32,
3616 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3618 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3619 pp->arg[i].reg, pp->name);
3620 regmask |= 1 << reg;
3627 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3632 if (pp->has_retreg) {
3633 for (i = 0; i < pp->argc; i++) {
3634 if (pp->arg[i].type.is_retreg) {
3635 reg = char_array_i(regs_r32,
3636 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3637 ferr_assert(ops, reg >= 0);
3638 regmask |= 1 << reg;
3643 if (strstr(pp->ret_type.name, "int64"))
3644 return regmask | (1 << xAX) | (1 << xDX);
3645 if (IS(pp->ret_type.name, "float")
3646 || IS(pp->ret_type.name, "double"))
3648 return regmask | mxST0;
3650 if (strcasecmp(pp->ret_type.name, "void") == 0)
3653 return regmask | mxAX;
3656 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3658 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3659 && memcmp(po1->operand, po2->operand,
3660 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3663 static void resolve_branches_parse_calls(int opcnt)
3665 static const struct {
3669 unsigned int regmask_src;
3670 unsigned int regmask_dst;
3672 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3673 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3674 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3675 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3677 const struct parsed_proto *pp_c;
3678 struct parsed_proto *pp;
3679 struct parsed_data *pd;
3680 struct parsed_op *po;
3681 const char *tmpname;
3685 for (i = 0; i < opcnt; i++)
3691 if (po->datap != NULL) {
3692 pp = calloc(1, sizeof(*pp));
3693 my_assert_not(pp, NULL);
3695 ret = parse_protostr(po->datap, pp);
3697 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3703 if (po->op == OP_CALL) {
3708 else if (po->operand[0].type == OPT_LABEL)
3710 tmpname = opr_name(po, 0);
3711 if (IS_START(tmpname, "loc_"))
3712 ferr(po, "call to loc_*\n");
3713 if (IS(tmpname, "__alloca_probe"))
3716 // convert some calls to pseudo-ops
3717 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3718 if (!IS(tmpname, pseudo_ops[l].name))
3721 po->op = pseudo_ops[l].op;
3722 po->operand_cnt = 0;
3723 po->regmask_src = pseudo_ops[l].regmask_src;
3724 po->regmask_dst = pseudo_ops[l].regmask_dst;
3725 po->flags = pseudo_ops[l].flags;
3726 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3729 if (l < ARRAY_SIZE(pseudo_ops))
3732 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3733 if (!g_header_mode && pp_c == NULL)
3734 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3737 pp = proto_clone(pp_c);
3738 my_assert_not(pp, NULL);
3744 check_func_pp(po, pp, "fptr var call");
3745 if (pp->is_noreturn)
3746 po->flags |= OPF_TAIL;
3752 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3755 if (po->operand[0].type == OPT_REGMEM) {
3756 pd = try_resolve_jumptab(i, opcnt);
3764 for (l = 0; l < opcnt; l++) {
3765 if (g_labels[l] != NULL
3766 && IS(po->operand[0].name, g_labels[l]))
3768 if (l == i + 1 && po->op == OP_JMP) {
3769 // yet another alignment type..
3770 po->flags |= OPF_RMD|OPF_DONE;
3773 add_label_ref(&g_label_refs[l], i);
3779 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3782 if (po->operand[0].type == OPT_LABEL)
3786 ferr(po, "unhandled branch\n");
3790 po->flags |= OPF_TAIL;
3791 if (i > 0 && ops[i - 1].op == OP_POP)
3792 po->flags |= OPF_ATAIL;
3797 static void scan_prologue_epilogue(int opcnt)
3799 int ecx_push = 0, esp_sub = 0, pusha = 0;
3800 int sandard_epilogue;
3804 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3805 && ops[1].op == OP_MOV
3806 && IS(opr_name(&ops[1], 0), "ebp")
3807 && IS(opr_name(&ops[1], 1), "esp"))
3810 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3811 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3814 if (ops[i].op == OP_PUSHA) {
3815 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3820 if (ops[i].op == OP_SUB && IS(opr_name(&ops[i], 0), "esp")) {
3821 g_stack_fsz = opr_const(&ops[i], 1);
3822 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3826 // another way msvc builds stack frame..
3827 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3829 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3833 // and another way..
3834 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3835 && ops[i].operand[1].type == OPT_CONST
3836 && ops[i + 1].op == OP_CALL
3837 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3839 g_stack_fsz += ops[i].operand[1].val;
3840 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3842 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3849 for (; i < opcnt; i++)
3850 if (ops[i].flags & OPF_TAIL)
3853 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3854 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3860 sandard_epilogue = 0;
3861 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3863 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3864 // the standard epilogue is sometimes even used without a sf
3865 if (ops[j - 1].op == OP_MOV
3866 && IS(opr_name(&ops[j - 1], 0), "esp")
3867 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3868 sandard_epilogue = 1;
3870 else if (ops[j].op == OP_LEAVE)
3872 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3873 sandard_epilogue = 1;
3875 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3876 && ops[i].pp->is_noreturn)
3878 // on noreturn, msvc sometimes cleans stack, sometimes not
3883 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3884 ferr(&ops[j], "'pop ebp' expected\n");
3886 if (g_stack_fsz != 0 || sandard_epilogue) {
3887 if (ops[j].op == OP_LEAVE)
3889 else if (sandard_epilogue) // mov esp, ebp
3891 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3894 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3896 ferr(&ops[j], "esp restore expected\n");
3899 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3900 && IS(opr_name(&ops[j], 0), "ecx"))
3902 ferr(&ops[j], "unexpected ecx pop\n");
3907 if (ops[j].op == OP_POPA)
3908 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3910 ferr(&ops[j], "popa expected\n");
3915 } while (i < opcnt);
3918 ferr(ops, "missing ebp epilogue\n");
3924 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3925 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3931 for (; i < opcnt; i++) {
3932 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3934 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3935 && ops[i].operand[1].type == OPT_CONST)
3937 g_stack_fsz = ops[i].operand[1].val;
3938 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3943 else if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3944 && ops[i].operand[1].type == OPT_CONST
3945 && ops[i + 1].op == OP_CALL
3946 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3948 g_stack_fsz += ops[i].operand[1].val;
3949 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3951 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3958 if (ecx_push && !esp_sub) {
3959 // could actually be args for a call..
3960 for (; i < opcnt; i++)
3961 if (ops[i].op != OP_PUSH)
3964 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3965 const struct parsed_proto *pp;
3966 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3967 j = pp ? pp->argc_stack : 0;
3968 while (i > 0 && j > 0) {
3970 if (ops[i].op == OP_PUSH) {
3971 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
3976 ferr(&ops[i], "unhandled prologue\n");
3979 i = g_stack_fsz = ecx_push = 0;
3980 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3981 if (!(ops[i].flags & OPF_RMD))
3991 if (ecx_push || esp_sub)
3996 for (; i < opcnt; i++)
3997 if (ops[i].flags & OPF_TAIL)
4001 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4002 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4009 for (l = 0; l < ecx_push; l++) {
4010 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4012 else if (ops[j].op == OP_ADD
4013 && IS(opr_name(&ops[j], 0), "esp")
4014 && ops[j].operand[1].type == OPT_CONST)
4017 l += ops[j].operand[1].val / 4 - 1;
4020 ferr(&ops[j], "'pop ecx' expected\n");
4022 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4026 ferr(&ops[j], "epilogue scan failed\n");
4032 if (ops[j].op != OP_ADD
4033 || !IS(opr_name(&ops[j], 0), "esp")
4034 || ops[j].operand[1].type != OPT_CONST
4035 || ops[j].operand[1].val != g_stack_fsz)
4037 if (ops[i].op == OP_CALL && ops[i].pp != NULL
4038 && ops[i].pp->is_noreturn)
4040 // noreturn tailcall with no epilogue
4044 ferr(&ops[j], "'add esp' expected\n");
4047 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4048 ops[j].operand[1].val = 0; // hack for stack arg scanner
4053 } while (i < opcnt);
4056 ferr(ops, "missing esp epilogue\n");
4060 // find an instruction that changed opr before i op
4061 // *op_i must be set to -1 by the caller
4062 // *is_caller is set to 1 if one source is determined to be g_func arg
4063 // returns 1 if found, *op_i is then set to origin
4064 // returns -1 if multiple origins are found
4065 static int resolve_origin(int i, const struct parsed_opr *opr,
4066 int magic, int *op_i, int *is_caller)
4068 struct label_ref *lr;
4072 if (g_labels[i] != NULL) {
4073 lr = &g_label_refs[i];
4074 for (; lr != NULL; lr = lr->next) {
4075 check_i(&ops[i], lr->i);
4076 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4078 if (i > 0 && LAST_OP(i - 1))
4084 if (is_caller != NULL)
4089 if (ops[i].cc_scratch == magic)
4091 ops[i].cc_scratch = magic;
4093 if (!(ops[i].flags & OPF_DATA))
4095 if (!is_opr_modified(opr, &ops[i]))
4099 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4110 // find an instruction that previously referenced opr
4111 // if multiple results are found - fail
4112 // *op_i must be set to -1 by the caller
4113 // returns 1 if found, *op_i is then set to referencer insn
4114 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4115 int magic, int *op_i)
4117 struct label_ref *lr;
4121 if (g_labels[i] != NULL) {
4122 lr = &g_label_refs[i];
4123 for (; lr != NULL; lr = lr->next) {
4124 check_i(&ops[i], lr->i);
4125 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4127 if (i > 0 && LAST_OP(i - 1))
4135 if (ops[i].cc_scratch == magic)
4137 ops[i].cc_scratch = magic;
4139 if (!is_opr_referenced(opr, &ops[i]))
4150 // adjust datap of all reachable 'op' insns when moving back
4151 // returns 1 if at least 1 op was found
4152 // returns -1 if path without an op was found
4153 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4155 struct label_ref *lr;
4158 if (ops[i].cc_scratch == magic)
4160 ops[i].cc_scratch = magic;
4163 if (g_labels[i] != NULL) {
4164 lr = &g_label_refs[i];
4165 for (; lr != NULL; lr = lr->next) {
4166 check_i(&ops[i], lr->i);
4167 ret |= adjust_prev_op(lr->i, op, magic, datap);
4169 if (i > 0 && LAST_OP(i - 1))
4177 if (ops[i].cc_scratch == magic)
4179 ops[i].cc_scratch = magic;
4181 if (ops[i].op != op)
4184 ops[i].datap = datap;
4189 // find next instruction that reads opr
4190 // *op_i must be set to -1 by the caller
4191 // on return, *op_i is set to first referencer insn
4192 // returns 1 if exactly 1 referencer is found
4193 static int find_next_read(int i, int opcnt,
4194 const struct parsed_opr *opr, int magic, int *op_i)
4196 struct parsed_op *po;
4199 for (; i < opcnt; i++)
4201 if (ops[i].cc_scratch == magic)
4203 ops[i].cc_scratch = magic;
4206 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4207 if (po->btj != NULL) {
4209 for (j = 0; j < po->btj->count; j++) {
4210 check_i(po, po->btj->d[j].bt_i);
4211 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4217 if (po->flags & OPF_RMD)
4219 check_i(po, po->bt_i);
4220 if (po->flags & OPF_CJMP) {
4221 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4230 if (!is_opr_read(opr, po)) {
4232 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4233 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4235 full_opr = po->operand[0].lmod >= opr->lmod;
4237 if (is_opr_modified(opr, po) && full_opr) {
4241 if (po->flags & OPF_TAIL)
4256 // find next instruction that reads opr
4257 // *op_i must be set to -1 by the caller
4258 // on return, *op_i is set to first flag user insn
4259 // returns 1 if exactly 1 flag user is found
4260 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4262 struct parsed_op *po;
4265 for (; i < opcnt; i++)
4267 if (ops[i].cc_scratch == magic)
4269 ops[i].cc_scratch = magic;
4272 if (po->op == OP_CALL)
4274 if (po->flags & OPF_JMP) {
4275 if (po->btj != NULL) {
4277 for (j = 0; j < po->btj->count; j++) {
4278 check_i(po, po->btj->d[j].bt_i);
4279 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4285 if (po->flags & OPF_RMD)
4287 check_i(po, po->bt_i);
4288 if (po->flags & OPF_CJMP)
4295 if (!(po->flags & OPF_CC)) {
4296 if (po->flags & OPF_FLAGS)
4299 if (po->flags & OPF_TAIL)
4315 static int try_resolve_const(int i, const struct parsed_opr *opr,
4316 int magic, unsigned int *val)
4321 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4324 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4327 *val = ops[i].operand[1].val;
4334 static int resolve_used_bits(int i, int opcnt, int reg,
4335 int *mask, int *is_z_check)
4337 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4341 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4345 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4347 fnote(&ops[j], "(first read)\n");
4348 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4351 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4352 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4354 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4355 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4357 *mask = ops[j].operand[1].val;
4358 if (ops[j].operand[0].lmod == OPLM_BYTE
4359 && ops[j].operand[0].name[1] == 'h')
4363 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4366 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4368 *is_z_check = ops[k].pfo == PFO_Z;
4373 static const struct parsed_proto *resolve_deref(int i, int magic,
4374 struct parsed_opr *opr, int level)
4376 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4377 const struct parsed_proto *pp = NULL;
4378 int from_caller = 0;
4387 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4388 if (ret != 2 || len != strlen(opr->name)) {
4389 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4390 if (ret != 1 || len != strlen(opr->name))
4394 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4399 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4403 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4404 && strlen(ops[j].operand[1].name) == 3
4405 && ops[j].operand[0].lmod == OPLM_DWORD
4406 && ops[j].pp == NULL // no hint
4409 // allow one simple dereference (com/directx)
4410 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4411 ops[j].operand[1].name);
4415 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4420 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4423 if (ops[j].pp != NULL) {
4427 else if (ops[j].operand[1].type == OPT_REGMEM) {
4428 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4430 // maybe structure ptr in structure
4431 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4434 else if (ops[j].operand[1].type == OPT_LABEL)
4435 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4436 else if (ops[j].operand[1].type == OPT_REG) {
4439 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4441 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4442 for (k = 0; k < g_func_pp->argc; k++) {
4443 if (g_func_pp->arg[k].reg == NULL)
4445 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4446 pp = g_func_pp->arg[k].pp;
4455 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4457 ferr(&ops[j], "expected struct, got '%s %s'\n",
4458 pp->type.name, pp->name);
4462 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4465 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4466 int *pp_i, int *multi_src)
4468 const struct parsed_proto *pp = NULL;
4469 int search_advice = 0;
4474 switch (ops[i].operand[0].type) {
4476 // try to resolve struct member calls
4477 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4483 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4489 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4497 static struct parsed_proto *process_call_early(int i, int opcnt,
4500 struct parsed_op *po = &ops[i];
4501 struct parsed_proto *pp;
4507 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4511 // look for and make use of esp adjust
4513 if (!pp->is_stdcall && pp->argc_stack > 0)
4514 ret = scan_for_esp_adjust(i + 1, opcnt,
4515 pp->argc_stack * 4, &adj, &multipath, 0);
4517 if (pp->argc_stack > adj / 4)
4521 if (ops[ret].op == OP_POP) {
4522 for (j = 1; j < adj / 4; j++) {
4523 if (ops[ret + j].op != OP_POP
4524 || ops[ret + j].operand[0].reg != xCX)
4536 static struct parsed_proto *process_call(int i, int opcnt)
4538 struct parsed_op *po = &ops[i];
4539 const struct parsed_proto *pp_c;
4540 struct parsed_proto *pp;
4541 const char *tmpname;
4542 int call_i = -1, ref_i = -1;
4543 int adj = 0, multipath = 0;
4546 tmpname = opr_name(po, 0);
4551 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4553 if (!pp_c->is_func && !pp_c->is_fptr)
4554 ferr(po, "call to non-func: %s\n", pp_c->name);
4555 pp = proto_clone(pp_c);
4556 my_assert_not(pp, NULL);
4558 // not resolved just to single func
4561 switch (po->operand[0].type) {
4563 // we resolved this call and no longer need the register
4564 po->regmask_src &= ~(1 << po->operand[0].reg);
4566 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4567 && ops[call_i].operand[1].type == OPT_LABEL)
4569 // no other source users?
4570 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4572 if (ret == 1 && call_i == ref_i) {
4573 // and nothing uses it after us?
4575 find_next_read(i + 1, opcnt, &po->operand[0],
4576 i + opcnt * 11, &ref_i);
4578 // then also don't need the source mov
4579 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4591 pp = calloc(1, sizeof(*pp));
4592 my_assert_not(pp, NULL);
4595 ret = scan_for_esp_adjust(i + 1, opcnt,
4596 -1, &adj, &multipath, 0);
4597 if (ret < 0 || adj < 0) {
4598 if (!g_allow_regfunc)
4599 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4600 pp->is_unresolved = 1;
4604 if (adj > ARRAY_SIZE(pp->arg))
4605 ferr(po, "esp adjust too large: %d\n", adj);
4606 pp->ret_type.name = strdup("int");
4607 pp->argc = pp->argc_stack = adj;
4608 for (arg = 0; arg < pp->argc; arg++)
4609 pp->arg[arg].type.name = strdup("int");
4614 // look for and make use of esp adjust
4617 if (!pp->is_stdcall && pp->argc_stack > 0) {
4618 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4619 ret = scan_for_esp_adjust(i + 1, opcnt,
4620 adj_expect, &adj, &multipath, 0);
4623 if (pp->is_vararg) {
4624 if (adj / 4 < pp->argc_stack) {
4625 fnote(po, "(this call)\n");
4626 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4627 adj, pp->argc_stack * 4);
4629 // modify pp to make it have varargs as normal args
4631 pp->argc += adj / 4 - pp->argc_stack;
4632 for (; arg < pp->argc; arg++) {
4633 pp->arg[arg].type.name = strdup("int");
4636 if (pp->argc > ARRAY_SIZE(pp->arg))
4637 ferr(po, "too many args for '%s'\n", tmpname);
4639 if (pp->argc_stack > adj / 4) {
4640 fnote(po, "(this call)\n");
4641 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4642 tmpname, pp->argc_stack * 4, adj);
4645 scan_for_esp_adjust(i + 1, opcnt,
4646 pp->argc_stack * 4, &adj, &multipath, 1);
4648 else if (pp->is_vararg)
4649 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4655 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
4658 struct parsed_op *po;
4664 for (base_arg = 0; base_arg < pp->argc; base_arg++)
4665 if (pp->arg[base_arg].reg == NULL)
4668 for (j = i; j > 0; )
4670 ferr_assert(&ops[j], g_labels[j] == NULL);
4674 ferr_assert(po, po->op != OP_PUSH);
4675 if (po->op == OP_FST)
4677 if (po->operand[0].type != OPT_REGMEM)
4679 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
4682 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3))
4683 ferr(po, "bad offset %d (%d args)\n", offset, pp->argc_stack);
4685 arg = base_arg + offset / 4;
4687 po->p_argnum = arg + 1;
4688 ferr_assert(po, pp->arg[arg].datap == NULL);
4689 pp->arg[arg].datap = po;
4690 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
4691 if (regmask_ffca != NULL)
4692 *regmask_ffca |= 1 << arg;
4694 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4695 && po->operand[1].type == OPT_CONST)
4697 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4702 for (arg = base_arg; arg < pp->argc; arg++) {
4703 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
4704 po = pp->arg[arg].datap;
4706 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
4707 if (po->operand[0].lmod == OPLM_QWORD)
4714 static int collect_call_args_early(int i, struct parsed_proto *pp,
4715 int *regmask, int *regmask_ffca)
4717 struct parsed_op *po;
4721 for (arg = 0; arg < pp->argc; arg++)
4722 if (pp->arg[arg].reg == NULL)
4725 // first see if it can be easily done
4726 for (j = i; j > 0 && arg < pp->argc; )
4728 if (g_labels[j] != NULL)
4733 if (po->op == OP_CALL)
4735 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
4737 else if (po->op == OP_POP)
4739 else if (po->flags & OPF_CJMP)
4741 else if (po->op == OP_PUSH) {
4742 if (po->flags & (OPF_FARG|OPF_FARGNR))
4744 if (!g_header_mode) {
4745 ret = scan_for_mod(po, j + 1, i, 1);
4750 if (pp->arg[arg].type.is_va_list)
4754 for (arg++; arg < pp->argc; arg++)
4755 if (pp->arg[arg].reg == NULL)
4758 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4759 && po->operand[1].type == OPT_CONST)
4761 if (po->flags & (OPF_RMD|OPF_DONE))
4763 if (po->operand[1].val != pp->argc_stack * 4)
4764 ferr(po, "unexpected esp adjust: %d\n",
4765 po->operand[1].val * 4);
4766 ferr_assert(po, pp->argc - arg == pp->argc_stack);
4767 return collect_call_args_no_push(i, pp, regmask_ffca);
4775 for (arg = 0; arg < pp->argc; arg++)
4776 if (pp->arg[arg].reg == NULL)
4779 for (j = i; j > 0 && arg < pp->argc; )
4783 if (ops[j].op == OP_PUSH)
4785 ops[j].p_argnext = -1;
4786 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4787 pp->arg[arg].datap = &ops[j];
4789 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
4790 *regmask |= 1 << ops[j].operand[0].reg;
4792 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4793 ops[j].flags &= ~OPF_RSAVE;
4796 for (arg++; arg < pp->argc; arg++)
4797 if (pp->arg[arg].reg == NULL)
4805 static int sync_argnum(struct parsed_op *po, int argnum)
4807 struct parsed_op *po_tmp;
4809 // see if other branches don't have higher argnum
4810 for (po_tmp = po; po_tmp != NULL; ) {
4811 if (argnum < po_tmp->p_argnum)
4812 argnum = po_tmp->p_argnum;
4813 // note: p_argnext is active on current collect_call_args only
4814 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4817 // make all argnums consistent
4818 for (po_tmp = po; po_tmp != NULL; ) {
4819 if (po_tmp->p_argnum != 0)
4820 po_tmp->p_argnum = argnum;
4821 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4827 static int collect_call_args_r(struct parsed_op *po, int i,
4828 struct parsed_proto *pp, int *regmask, int *arg_grp,
4829 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
4831 struct parsed_proto *pp_tmp;
4832 struct parsed_op *po_tmp;
4833 struct label_ref *lr;
4834 int need_to_save_current;
4835 int arg_grp_current = 0;
4836 int save_args_seen = 0;
4843 ferr(po, "dead label encountered\n");
4847 for (; arg < pp->argc; arg++, argnum++)
4848 if (pp->arg[arg].reg == NULL)
4850 magic = (magic & 0xffffff) | (arg << 24);
4852 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4854 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4855 if (ops[j].cc_scratch != magic) {
4856 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4860 // ok: have already been here
4863 ops[j].cc_scratch = magic;
4865 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4866 lr = &g_label_refs[j];
4867 if (lr->next != NULL)
4869 for (; lr->next; lr = lr->next) {
4870 check_i(&ops[j], lr->i);
4871 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4873 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4874 arg, argnum, magic, need_op_saving, may_reuse);
4879 check_i(&ops[j], lr->i);
4880 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4882 if (j > 0 && LAST_OP(j - 1)) {
4883 // follow last branch in reverse
4888 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4889 arg, argnum, magic, need_op_saving, may_reuse);
4895 if (ops[j].op == OP_CALL)
4897 if (pp->is_unresolved)
4902 ferr(po, "arg collect hit unparsed call '%s'\n",
4903 ops[j].operand[0].name);
4904 if (may_reuse && pp_tmp->argc_stack > 0)
4905 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4906 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4908 // esp adjust of 0 means we collected it before
4909 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4910 && (ops[j].operand[1].type != OPT_CONST
4911 || ops[j].operand[1].val != 0))
4913 if (pp->is_unresolved)
4916 fnote(po, "(this call)\n");
4917 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4918 arg, pp->argc, ops[j].operand[1].val);
4920 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4922 if (pp->is_unresolved)
4925 fnote(po, "(this call)\n");
4926 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4928 else if (ops[j].flags & OPF_CJMP)
4930 if (pp->is_unresolved)
4935 else if (ops[j].op == OP_PUSH
4936 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4938 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4941 ops[j].p_argnext = -1;
4942 po_tmp = pp->arg[arg].datap;
4944 ops[j].p_argnext = po_tmp - ops;
4945 pp->arg[arg].datap = &ops[j];
4947 argnum = sync_argnum(&ops[j], argnum);
4949 need_to_save_current = 0;
4951 if (ops[j].operand[0].type == OPT_REG)
4952 reg = ops[j].operand[0].reg;
4954 if (!need_op_saving) {
4955 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4956 need_to_save_current = (ret >= 0);
4958 if (need_op_saving || need_to_save_current) {
4959 // mark this arg as one that needs operand saving
4960 pp->arg[arg].is_saved = 1;
4962 if (save_args_seen & (1 << (argnum - 1))) {
4965 if (arg_grp_current >= MAX_ARG_GRP)
4966 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
4970 else if (ops[j].p_argnum == 0)
4971 ops[j].flags |= OPF_RMD;
4973 // some PUSHes are reused by different calls on other branches,
4974 // but that can't happen if we didn't branch, so they
4975 // can be removed from future searches (handles nested calls)
4977 ops[j].flags |= OPF_FARGNR;
4979 ops[j].flags |= OPF_FARG;
4980 ops[j].flags &= ~OPF_RSAVE;
4982 // check for __VALIST
4983 if (!pp->is_unresolved && g_func_pp != NULL
4984 && pp->arg[arg].type.is_va_list)
4987 ret = resolve_origin(j, &ops[j].operand[0],
4988 magic + 1, &k, NULL);
4989 if (ret == 1 && k >= 0)
4991 if (ops[k].op == OP_LEA) {
4992 if (!g_func_pp->is_vararg)
4993 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
4996 snprintf(buf, sizeof(buf), "arg_%X",
4997 g_func_pp->argc_stack * 4);
4998 if (strstr(ops[k].operand[1].name, buf)
4999 || strstr(ops[k].operand[1].name, "arglist"))
5001 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5002 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5003 pp->arg[arg].is_saved = 0;
5007 ferr(&ops[k], "va_list arg detection failed\n");
5009 // check for va_list from g_func_pp arg too
5010 else if (ops[k].op == OP_MOV
5011 && is_stack_access(&ops[k], &ops[k].operand[1]))
5013 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5014 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5016 ops[k].flags |= OPF_RMD | OPF_DONE;
5017 ops[j].flags |= OPF_RMD;
5018 ops[j].p_argpass = ret + 1;
5019 pp->arg[arg].is_saved = 0;
5026 if (pp->arg[arg].is_saved) {
5027 ops[j].flags &= ~OPF_RMD;
5028 ops[j].p_argnum = argnum;
5031 // tracking reg usage
5033 *regmask |= 1 << reg;
5037 if (!pp->is_unresolved) {
5039 for (; arg < pp->argc; arg++, argnum++)
5040 if (pp->arg[arg].reg == NULL)
5043 magic = (magic & 0xffffff) | (arg << 24);
5046 if (ops[j].p_arggrp > arg_grp_current) {
5048 arg_grp_current = ops[j].p_arggrp;
5050 if (ops[j].p_argnum > 0)
5051 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5054 if (arg < pp->argc) {
5055 ferr(po, "arg collect failed for '%s': %d/%d\n",
5056 pp->name, arg, pp->argc);
5060 if (arg_grp_current > *arg_grp)
5061 *arg_grp = arg_grp_current;
5066 static int collect_call_args(struct parsed_op *po, int i,
5067 struct parsed_proto *pp, int *regmask, int magic)
5069 // arg group is for cases when pushes for
5070 // multiple funcs are going on
5071 struct parsed_op *po_tmp;
5076 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5082 // propagate arg_grp
5083 for (a = 0; a < pp->argc; a++) {
5084 if (pp->arg[a].reg != NULL)
5087 po_tmp = pp->arg[a].datap;
5088 while (po_tmp != NULL) {
5089 po_tmp->p_arggrp = arg_grp;
5090 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5095 if (pp->is_unresolved) {
5097 pp->argc_stack += ret;
5098 for (a = 0; a < pp->argc; a++)
5099 if (pp->arg[a].type.name == NULL)
5100 pp->arg[a].type.name = strdup("int");
5106 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5107 int regmask_now, int *regmask,
5108 int regmask_save_now, int *regmask_save,
5109 int *regmask_init, int regmask_arg)
5111 struct parsed_op *po;
5119 for (; i < opcnt; i++)
5122 if (cbits[i >> 3] & (1 << (i & 7)))
5124 cbits[i >> 3] |= (1 << (i & 7));
5126 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5127 if (po->flags & (OPF_RMD|OPF_DONE))
5129 if (po->btj != NULL) {
5130 for (j = 0; j < po->btj->count; j++) {
5131 check_i(po, po->btj->d[j].bt_i);
5132 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5133 regmask_now, regmask, regmask_save_now, regmask_save,
5134 regmask_init, regmask_arg);
5139 check_i(po, po->bt_i);
5140 if (po->flags & OPF_CJMP)
5141 reg_use_pass(po->bt_i, opcnt, cbits,
5142 regmask_now, regmask, regmask_save_now, regmask_save,
5143 regmask_init, regmask_arg);
5149 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5150 && !g_func_pp->is_userstack
5151 && po->operand[0].type == OPT_REG)
5153 reg = po->operand[0].reg;
5154 ferr_assert(po, reg >= 0);
5157 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5158 if (regmask_now & (1 << reg)) {
5159 already_saved = regmask_save_now & (1 << reg);
5160 flags_set = OPF_RSAVE | OPF_DONE;
5163 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5165 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5166 reg, 0, 0, flags_set);
5169 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5171 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5176 ferr_assert(po, !already_saved);
5177 po->flags |= flags_set;
5179 if (regmask_now & (1 << reg)) {
5180 regmask_save_now |= (1 << reg);
5181 *regmask_save |= regmask_save_now;
5186 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5187 reg = po->operand[0].reg;
5188 ferr_assert(po, reg >= 0);
5190 if (regmask_save_now & (1 << reg))
5191 regmask_save_now &= ~(1 << reg);
5193 regmask_now &= ~(1 << reg);
5196 else if (po->op == OP_CALL) {
5197 if ((po->regmask_dst & (1 << xAX))
5198 && !(po->regmask_dst & (1 << xDX)))
5200 if (po->flags & OPF_TAIL)
5201 // don't need eax, will do "return f();" or "f(); return;"
5202 po->regmask_dst &= ~(1 << xAX);
5204 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5206 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5209 po->regmask_dst &= ~(1 << xAX);
5213 // not "full stack" mode and have something in stack
5214 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5215 ferr(po, "float stack is not empty on func call\n");
5218 if (po->flags & OPF_NOREGS)
5221 // if incomplete register is used, clear it on init to avoid
5222 // later use of uninitialized upper part in some situations
5223 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5224 && po->operand[0].lmod != OPLM_DWORD)
5226 reg = po->operand[0].reg;
5227 ferr_assert(po, reg >= 0);
5229 if (!(regmask_now & (1 << reg)))
5230 *regmask_init |= 1 << reg;
5233 regmask_op = po->regmask_src | po->regmask_dst;
5235 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5236 regmask_new &= ~(1 << xSP);
5237 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5238 regmask_new &= ~(1 << xBP);
5240 if (regmask_new != 0)
5241 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5243 if (regmask_op & (1 << xBP)) {
5244 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5245 if (po->regmask_dst & (1 << xBP))
5246 // compiler decided to drop bp frame and use ebp as scratch
5247 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5249 regmask_op &= ~(1 << xBP);
5253 if (po->flags & OPF_FPUSH) {
5254 if (regmask_now & mxST1)
5255 regmask_now |= mxSTa; // switch to "full stack" mode
5256 if (regmask_now & mxSTa)
5257 po->flags |= OPF_FSHIFT;
5258 if (!(regmask_now & mxST7_2)) {
5260 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5264 regmask_now |= regmask_op;
5265 *regmask |= regmask_now;
5268 if (po->flags & OPF_FPOP) {
5269 if ((regmask_now & mxSTa) == 0)
5270 ferr(po, "float pop on empty stack?\n");
5271 if (regmask_now & (mxST7_2 | mxST1))
5272 po->flags |= OPF_FSHIFT;
5273 if (!(regmask_now & mxST7_2)) {
5275 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5279 if (po->flags & OPF_TAIL) {
5280 if (!(regmask_now & mxST7_2)) {
5281 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5282 if (!(regmask_now & mxST0))
5283 ferr(po, "no st0 on float return, mask: %x\n",
5286 else if (regmask_now & mxST1_0)
5287 ferr(po, "float regs on tail: %x\n", regmask_now);
5290 // there is support for "conditional tailcall", sort of
5291 if (!(po->flags & OPF_CC))
5297 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5301 for (i = 0; i < pp->argc; i++)
5302 if (pp->arg[i].reg == NULL)
5306 memmove(&pp->arg[i + 1], &pp->arg[i],
5307 sizeof(pp->arg[0]) * pp->argc_stack);
5308 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5309 pp->arg[i].reg = strdup(reg);
5310 pp->arg[i].type.name = strdup("int");
5315 static void output_std_flags(FILE *fout, struct parsed_op *po,
5316 int *pfomask, const char *dst_opr_text)
5318 if (*pfomask & (1 << PFO_Z)) {
5319 fprintf(fout, "\n cond_z = (%s%s == 0);",
5320 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5321 *pfomask &= ~(1 << PFO_Z);
5323 if (*pfomask & (1 << PFO_S)) {
5324 fprintf(fout, "\n cond_s = (%s%s < 0);",
5325 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5326 *pfomask &= ~(1 << PFO_S);
5331 OPP_FORCE_NORETURN = (1 << 0),
5332 OPP_SIMPLE_ARGS = (1 << 1),
5333 OPP_ALIGN = (1 << 2),
5336 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5339 const char *cconv = "";
5341 if (pp->is_fastcall)
5342 cconv = "__fastcall ";
5343 else if (pp->is_stdcall && pp->argc_reg == 0)
5344 cconv = "__stdcall ";
5346 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5348 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5349 fprintf(fout, "noreturn ");
5352 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5357 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5361 output_pp_attrs(fout, pp, flags);
5364 fprintf(fout, "%s", pp->name);
5369 for (i = 0; i < pp->argc; i++) {
5371 fprintf(fout, ", ");
5372 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5373 && !(flags & OPP_SIMPLE_ARGS))
5376 output_pp(fout, pp->arg[i].pp, 0);
5378 else if (pp->arg[i].type.is_retreg) {
5379 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5382 fprintf(fout, "%s", pp->arg[i].type.name);
5384 fprintf(fout, " a%d", i + 1);
5387 if (pp->is_vararg) {
5389 fprintf(fout, ", ");
5390 fprintf(fout, "...");
5395 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5401 snprintf(buf1, sizeof(buf1), "%d", grp);
5402 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5407 static void gen_x_cleanup(int opcnt);
5409 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5411 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5412 struct parsed_opr *last_arith_dst = NULL;
5413 char buf1[256], buf2[256], buf3[256], cast[64];
5414 struct parsed_proto *pp, *pp_tmp;
5415 struct parsed_data *pd;
5416 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5417 unsigned char cbits[MAX_OPS / 8];
5418 const char *float_type;
5419 const char *float_st0;
5420 const char *float_st1;
5421 int need_float_stack = 0;
5422 int need_float_sw = 0; // status word
5423 int need_tmp_var = 0;
5427 int label_pending = 0;
5428 int need_double = 0;
5429 int regmask_save = 0; // used regs saved/restored in this func
5430 int regmask_arg; // regs from this function args (fastcall, etc)
5431 int regmask_ret; // regs needed on ret
5432 int regmask_now; // temp
5433 int regmask_init = 0; // regs that need zero initialization
5434 int regmask_pp = 0; // regs used in complex push-pop graph
5435 int regmask_ffca = 0; // float function call args
5436 int regmask = 0; // used regs
5446 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5447 g_stack_frame_used = 0;
5448 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5449 regmask_init = g_regmask_init;
5451 g_func_pp = proto_parse(fhdr, funcn, 0);
5452 if (g_func_pp == NULL)
5453 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5455 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5456 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5459 // - resolve all branches
5460 // - parse calls with labels
5461 resolve_branches_parse_calls(opcnt);
5464 // - handle ebp/esp frame, remove ops related to it
5465 scan_prologue_epilogue(opcnt);
5468 // - remove dead labels
5469 // - set regs needed at ret
5470 for (i = 0; i < opcnt; i++)
5472 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5477 if (ops[i].op == OP_RET)
5478 ops[i].regmask_src |= regmask_ret;
5482 // - process trivial calls
5483 for (i = 0; i < opcnt; i++)
5486 if (po->flags & (OPF_RMD|OPF_DONE))
5489 if (po->op == OP_CALL)
5491 pp = process_call_early(i, opcnt, &j);
5493 if (!(po->flags & OPF_ATAIL)) {
5494 // since we know the args, try to collect them
5495 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5503 // commit esp adjust
5504 if (ops[j].op != OP_POP)
5505 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5507 for (l = 0; l < pp->argc_stack; l++)
5508 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5512 if (strstr(pp->ret_type.name, "int64"))
5515 po->flags |= OPF_DONE;
5521 // - process calls, stage 2
5522 // - handle some push/pop pairs
5523 // - scan for STD/CLD, propagate DF
5524 // - try to resolve needed x87 status word bits
5525 for (i = 0; i < opcnt; i++)
5530 if (po->flags & OPF_RMD)
5533 if (po->op == OP_CALL)
5535 if (!(po->flags & OPF_DONE)) {
5536 pp = process_call(i, opcnt);
5538 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5539 // since we know the args, collect them
5540 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5542 // for unresolved, collect after other passes
5546 ferr_assert(po, pp != NULL);
5548 po->regmask_src |= get_pp_arg_regmask_src(pp);
5549 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5551 if (po->regmask_dst & mxST0)
5552 po->flags |= OPF_FPUSH;
5554 if (strstr(pp->ret_type.name, "int64"))
5560 if (po->flags & OPF_DONE)
5565 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
5566 && po->operand[0].type == OPT_CONST)
5568 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5573 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5577 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5578 scan_propagate_df(i + 1, opcnt);
5583 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
5584 ferr(po, "TODO: fnstsw to mem\n");
5585 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
5587 ferr(po, "fnstsw resolve failed\n");
5588 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
5589 (void *)(long)(mask | (z_check << 16)));
5591 ferr(po, "failed to find fcom: %d\n", ret);
5600 // - find POPs for PUSHes, rm both
5601 // - scan for all used registers
5602 memset(cbits, 0, sizeof(cbits));
5603 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5604 0, ®mask_save, ®mask_init, regmask_arg);
5606 need_float_stack = !!(regmask & mxST7_2);
5609 // - find flag set ops for their users
5610 // - do unresolved calls
5611 // - declare indirect functions
5612 // - other op specific processing
5613 for (i = 0; i < opcnt; i++)
5616 if (po->flags & (OPF_RMD|OPF_DONE))
5619 if (po->flags & OPF_CC)
5621 int setters[16], cnt = 0, branched = 0;
5623 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
5624 &branched, setters, &cnt);
5625 if (ret < 0 || cnt <= 0)
5626 ferr(po, "unable to trace flag setter(s)\n");
5627 if (cnt > ARRAY_SIZE(setters))
5628 ferr(po, "too many flag setters\n");
5630 for (j = 0; j < cnt; j++)
5632 tmp_op = &ops[setters[j]]; // flag setter
5635 // to get nicer code, we try to delay test and cmp;
5636 // if we can't because of operand modification, or if we
5637 // have arith op, or branch, make it calculate flags explicitly
5638 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5640 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5641 pfomask = 1 << po->pfo;
5643 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5644 pfomask = 1 << po->pfo;
5647 // see if we'll be able to handle based on op result
5648 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5649 && po->pfo != PFO_Z && po->pfo != PFO_S
5650 && po->pfo != PFO_P)
5652 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5654 pfomask = 1 << po->pfo;
5657 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5658 propagate_lmod(tmp_op, &tmp_op->operand[0],
5659 &tmp_op->operand[1]);
5660 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5665 tmp_op->pfomask |= pfomask;
5666 cond_vars |= pfomask;
5668 // note: may overwrite, currently not a problem
5672 if (po->op == OP_RCL || po->op == OP_RCR
5673 || po->op == OP_ADC || po->op == OP_SBB)
5674 cond_vars |= 1 << PFO_C;
5680 cond_vars |= 1 << PFO_Z;
5684 if (po->operand[0].lmod == OPLM_DWORD)
5689 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
5694 // note: resolved non-reg calls are OPF_DONE already
5696 ferr_assert(po, pp != NULL);
5698 if (pp->is_unresolved) {
5699 int regmask_stack = 0;
5700 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5702 // this is pretty rough guess:
5703 // see ecx and edx were pushed (and not their saved versions)
5704 for (arg = 0; arg < pp->argc; arg++) {
5705 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
5708 tmp_op = pp->arg[arg].datap;
5710 ferr(po, "parsed_op missing for arg%d\n", arg);
5711 if (tmp_op->operand[0].type == OPT_REG)
5712 regmask_stack |= 1 << tmp_op->operand[0].reg;
5715 if (!((regmask_stack & (1 << xCX))
5716 && (regmask_stack & (1 << xDX))))
5718 if (pp->argc_stack != 0
5719 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5721 pp_insert_reg_arg(pp, "ecx");
5722 pp->is_fastcall = 1;
5723 regmask_init |= 1 << xCX;
5724 regmask |= 1 << xCX;
5726 if (pp->argc_stack != 0
5727 || ((regmask | regmask_arg) & (1 << xDX)))
5729 pp_insert_reg_arg(pp, "edx");
5730 regmask_init |= 1 << xDX;
5731 regmask |= 1 << xDX;
5735 // note: __cdecl doesn't fall into is_unresolved category
5736 if (pp->argc_stack > 0)
5742 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
5744 // <var> = offset <something>
5745 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5746 && !IS_START(po->operand[1].name, "off_"))
5748 if (!po->operand[0].pp->is_fptr)
5749 ferr(po, "%s not declared as fptr when it should be\n",
5750 po->operand[0].name);
5751 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5752 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5753 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5754 fnote(po, "var: %s\n", buf1);
5755 fnote(po, "func: %s\n", buf2);
5756 ferr(po, "^ mismatch\n");
5764 if (po->operand[0].lmod == OPLM_DWORD) {
5765 // 32bit division is common, look for it
5766 if (po->op == OP_DIV)
5767 ret = scan_for_reg_clear(i, xDX);
5769 ret = scan_for_cdq_edx(i);
5771 po->flags |= OPF_32BIT;
5780 po->flags |= OPF_RMD | OPF_DONE;
5790 if (po->operand[0].lmod == OPLM_QWORD)
5800 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5802 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5804 po->flags |= OPF_32BIT;
5812 // this might need it's own pass...
5813 if (po->op != OP_FST && po->p_argnum > 0)
5814 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
5816 // correct for "full stack" mode late enable
5817 if ((po->flags & (OPF_PPUSH|OPF_FPOP)) && need_float_stack)
5818 po->flags |= OPF_FSHIFT;
5821 float_type = need_double ? "double" : "float";
5822 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
5823 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
5825 // output starts here
5827 // define userstack size
5828 if (g_func_pp->is_userstack) {
5829 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5830 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5831 fprintf(fout, "#endif\n");
5834 // the function itself
5835 ferr_assert(ops, !g_func_pp->is_fptr);
5836 output_pp(fout, g_func_pp,
5837 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5838 fprintf(fout, "\n{\n");
5840 // declare indirect functions
5841 for (i = 0; i < opcnt; i++) {
5843 if (po->flags & OPF_RMD)
5846 if (po->op == OP_CALL) {
5849 ferr(po, "NULL pp\n");
5851 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5852 if (pp->name[0] != 0) {
5853 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5854 memcpy(pp->name, "i_", 2);
5856 // might be declared already
5858 for (j = 0; j < i; j++) {
5859 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5860 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5870 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5873 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5874 fprintf(fout, ";\n");
5879 // output LUTs/jumptables
5880 for (i = 0; i < g_func_pd_cnt; i++) {
5882 fprintf(fout, " static const ");
5883 if (pd->type == OPT_OFFSET) {
5884 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5886 for (j = 0; j < pd->count; j++) {
5888 fprintf(fout, ", ");
5889 fprintf(fout, "&&%s", pd->d[j].u.label);
5893 fprintf(fout, "%s %s[] =\n { ",
5894 lmod_type_u(ops, pd->lmod), pd->label);
5896 for (j = 0; j < pd->count; j++) {
5898 fprintf(fout, ", ");
5899 fprintf(fout, "%u", pd->d[j].u.val);
5902 fprintf(fout, " };\n");
5906 // declare stack frame, va_arg
5908 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5909 if (g_func_lmods & (1 << OPLM_WORD))
5910 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5911 if (g_func_lmods & (1 << OPLM_BYTE))
5912 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5913 if (g_func_lmods & (1 << OPLM_QWORD))
5914 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5915 fprintf(fout, " } sf;\n");
5919 if (g_func_pp->is_userstack) {
5920 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5921 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5925 if (g_func_pp->is_vararg) {
5926 fprintf(fout, " va_list ap;\n");
5930 // declare arg-registers
5931 for (i = 0; i < g_func_pp->argc; i++) {
5932 if (g_func_pp->arg[i].reg != NULL) {
5933 reg = char_array_i(regs_r32,
5934 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5935 if (regmask & (1 << reg)) {
5936 if (g_func_pp->arg[i].type.is_retreg)
5937 fprintf(fout, " u32 %s = *r_%s;\n",
5938 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5940 fprintf(fout, " u32 %s = (u32)a%d;\n",
5941 g_func_pp->arg[i].reg, i + 1);
5944 if (g_func_pp->arg[i].type.is_retreg)
5945 ferr(ops, "retreg '%s' is unused?\n",
5946 g_func_pp->arg[i].reg);
5947 fprintf(fout, " // %s = a%d; // unused\n",
5948 g_func_pp->arg[i].reg, i + 1);
5954 // declare normal registers
5955 regmask_now = regmask & ~regmask_arg;
5956 regmask_now &= ~(1 << xSP);
5957 if (regmask_now & 0x00ff) {
5958 for (reg = 0; reg < 8; reg++) {
5959 if (regmask_now & (1 << reg)) {
5960 fprintf(fout, " u32 %s", regs_r32[reg]);
5961 if (regmask_init & (1 << reg))
5962 fprintf(fout, " = 0");
5963 fprintf(fout, ";\n");
5969 if (regmask_now & 0xff00) {
5970 for (reg = 8; reg < 16; reg++) {
5971 if (regmask_now & (1 << reg)) {
5972 fprintf(fout, " mmxr %s", regs_r32[reg]);
5973 if (regmask_init & (1 << reg))
5974 fprintf(fout, " = { 0, }");
5975 fprintf(fout, ";\n");
5981 if (need_float_stack) {
5982 fprintf(fout, " %s f_st[8];\n", float_type);
5983 fprintf(fout, " int f_stp = 0;\n");
5987 if (regmask_now & 0xff0000) {
5988 for (reg = 16; reg < 24; reg++) {
5989 if (regmask_now & (1 << reg)) {
5990 fprintf(fout, " %s f_st%d", float_type, reg - 16);
5991 if (regmask_init & (1 << reg))
5992 fprintf(fout, " = 0");
5993 fprintf(fout, ";\n");
6000 if (need_float_sw) {
6001 fprintf(fout, " u16 f_sw;\n");
6006 for (reg = 0; reg < 8; reg++) {
6007 if (regmask_save & (1 << reg)) {
6008 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6014 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6015 if (save_arg_vars[i] == 0)
6017 for (reg = 0; reg < 32; reg++) {
6018 if (save_arg_vars[i] & (1 << reg)) {
6019 fprintf(fout, " u32 %s;\n",
6020 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6027 for (reg = 0; reg < 32; reg++) {
6028 if (regmask_ffca & (1 << reg)) {
6029 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6035 // declare push-pop temporaries
6037 for (reg = 0; reg < 8; reg++) {
6038 if (regmask_pp & (1 << reg)) {
6039 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6046 for (i = 0; i < 8; i++) {
6047 if (cond_vars & (1 << i)) {
6048 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6055 fprintf(fout, " u32 tmp;\n");
6060 fprintf(fout, " u64 tmp64;\n");
6065 fprintf(fout, "\n");
6067 // do stack clear, if needed
6068 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6070 if (g_stack_clear_len != 0) {
6071 if (g_stack_clear_len <= 4) {
6072 for (i = 0; i < g_stack_clear_len; i++)
6073 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6074 fprintf(fout, "0;\n");
6077 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6078 g_stack_clear_start, g_stack_clear_len * 4);
6082 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6085 if (g_func_pp->is_vararg) {
6086 if (g_func_pp->argc_stack == 0)
6087 ferr(ops, "vararg func without stack args?\n");
6088 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6092 for (i = 0; i < opcnt; i++)
6094 if (g_labels[i] != NULL) {
6095 fprintf(fout, "\n%s:\n", g_labels[i]);
6098 delayed_flag_op = NULL;
6099 last_arith_dst = NULL;
6103 if (po->flags & OPF_RMD)
6108 #define assert_operand_cnt(n_) \
6109 if (po->operand_cnt != n_) \
6110 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6112 // conditional/flag using op?
6113 if (po->flags & OPF_CC)
6119 // we go through all this trouble to avoid using parsed_flag_op,
6120 // which makes generated code much nicer
6121 if (delayed_flag_op != NULL)
6123 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6124 po->pfo, po->pfo_inv);
6127 else if (last_arith_dst != NULL
6128 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6129 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6132 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6133 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6134 last_arith_dst->lmod, buf3);
6137 else if (tmp_op != NULL) {
6138 // use preprocessed flag calc results
6139 if (!(tmp_op->pfomask & (1 << po->pfo)))
6140 ferr(po, "not prepared for pfo %d\n", po->pfo);
6142 // note: pfo_inv was not yet applied
6143 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6144 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6147 ferr(po, "all methods of finding comparison failed\n");
6150 if (po->flags & OPF_JMP) {
6151 fprintf(fout, " if %s", buf1);
6153 else if (po->op == OP_RCL || po->op == OP_RCR
6154 || po->op == OP_ADC || po->op == OP_SBB)
6157 fprintf(fout, " cond_%s = %s;\n",
6158 parsed_flag_op_names[po->pfo], buf1);
6160 else if (po->flags & OPF_DATA) { // SETcc
6161 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6162 fprintf(fout, " %s = %s;", buf2, buf1);
6165 ferr(po, "unhandled conditional op\n");
6169 pfomask = po->pfomask;
6174 assert_operand_cnt(2);
6175 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6176 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6177 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6178 fprintf(fout, " %s = %s;", buf1,
6179 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6184 assert_operand_cnt(2);
6185 po->operand[1].lmod = OPLM_DWORD; // always
6186 fprintf(fout, " %s = %s;",
6187 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6188 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6193 assert_operand_cnt(2);
6194 fprintf(fout, " %s = %s;",
6195 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6196 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6200 assert_operand_cnt(2);
6201 switch (po->operand[1].lmod) {
6203 strcpy(buf3, "(s8)");
6206 strcpy(buf3, "(s16)");
6209 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6211 fprintf(fout, " %s = %s;",
6212 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6213 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6218 assert_operand_cnt(2);
6219 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6220 fprintf(fout, " tmp = %s;",
6221 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6222 fprintf(fout, " %s = %s;",
6223 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6224 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6225 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6226 fprintf(fout, " %s = %stmp;",
6227 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6228 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6229 snprintf(g_comment, sizeof(g_comment), "xchg");
6233 assert_operand_cnt(1);
6234 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6235 fprintf(fout, " %s = ~%s;", buf1, buf1);
6239 assert_operand_cnt(2);
6240 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6241 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6242 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6243 strcpy(g_comment, "xlat");
6247 assert_operand_cnt(2);
6248 fprintf(fout, " %s = (s32)%s >> 31;",
6249 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6250 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6251 strcpy(g_comment, "cdq");
6255 assert_operand_cnt(1);
6256 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6257 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6261 if (po->flags & OPF_REP) {
6262 assert_operand_cnt(3);
6267 assert_operand_cnt(2);
6268 fprintf(fout, " %s = %sesi; esi %c= %d;",
6269 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6270 lmod_cast_u_ptr(po, po->operand[1].lmod),
6271 (po->flags & OPF_DF) ? '-' : '+',
6272 lmod_bytes(po, po->operand[1].lmod));
6273 strcpy(g_comment, "lods");
6278 if (po->flags & OPF_REP) {
6279 assert_operand_cnt(3);
6280 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6281 (po->flags & OPF_DF) ? '-' : '+',
6282 lmod_bytes(po, po->operand[1].lmod));
6283 fprintf(fout, " %sedi = eax;",
6284 lmod_cast_u_ptr(po, po->operand[1].lmod));
6285 strcpy(g_comment, "rep stos");
6288 assert_operand_cnt(2);
6289 fprintf(fout, " %sedi = eax; edi %c= %d;",
6290 lmod_cast_u_ptr(po, po->operand[1].lmod),
6291 (po->flags & OPF_DF) ? '-' : '+',
6292 lmod_bytes(po, po->operand[1].lmod));
6293 strcpy(g_comment, "stos");
6298 j = lmod_bytes(po, po->operand[0].lmod);
6299 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6300 l = (po->flags & OPF_DF) ? '-' : '+';
6301 if (po->flags & OPF_REP) {
6302 assert_operand_cnt(3);
6304 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6307 " %sedi = %sesi;", buf1, buf1);
6308 strcpy(g_comment, "rep movs");
6311 assert_operand_cnt(2);
6312 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6313 buf1, buf1, l, j, l, j);
6314 strcpy(g_comment, "movs");
6319 // repe ~ repeat while ZF=1
6320 j = lmod_bytes(po, po->operand[0].lmod);
6321 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6322 l = (po->flags & OPF_DF) ? '-' : '+';
6323 if (po->flags & OPF_REP) {
6324 assert_operand_cnt(3);
6326 " while (ecx != 0) {\n");
6327 if (pfomask & (1 << PFO_C)) {
6330 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6331 pfomask &= ~(1 << PFO_C);
6334 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6335 buf1, buf1, l, j, l, j);
6338 " if (cond_z %s 0) break;\n",
6339 (po->flags & OPF_REPZ) ? "==" : "!=");
6342 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6343 (po->flags & OPF_REPZ) ? "e" : "ne");
6346 assert_operand_cnt(2);
6348 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6349 buf1, buf1, l, j, l, j);
6350 strcpy(g_comment, "cmps");
6352 pfomask &= ~(1 << PFO_Z);
6353 last_arith_dst = NULL;
6354 delayed_flag_op = NULL;
6358 // only does ZF (for now)
6359 // repe ~ repeat while ZF=1
6360 j = lmod_bytes(po, po->operand[1].lmod);
6361 l = (po->flags & OPF_DF) ? '-' : '+';
6362 if (po->flags & OPF_REP) {
6363 assert_operand_cnt(3);
6365 " while (ecx != 0) {\n");
6367 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6368 lmod_cast_u(po, po->operand[1].lmod),
6369 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6372 " if (cond_z %s 0) break;\n",
6373 (po->flags & OPF_REPZ) ? "==" : "!=");
6376 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6377 (po->flags & OPF_REPZ) ? "e" : "ne");
6380 assert_operand_cnt(2);
6381 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6382 lmod_cast_u(po, po->operand[1].lmod),
6383 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6384 strcpy(g_comment, "scas");
6386 pfomask &= ~(1 << PFO_Z);
6387 last_arith_dst = NULL;
6388 delayed_flag_op = NULL;
6391 // arithmetic w/flags
6393 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6394 goto dualop_arith_const;
6395 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6399 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6400 if (po->operand[1].type == OPT_CONST) {
6401 j = lmod_bytes(po, po->operand[0].lmod);
6402 if (((1ull << j * 8) - 1) == po->operand[1].val)
6403 goto dualop_arith_const;
6408 assert_operand_cnt(2);
6409 fprintf(fout, " %s %s= %s;",
6410 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6412 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6413 output_std_flags(fout, po, &pfomask, buf1);
6414 last_arith_dst = &po->operand[0];
6415 delayed_flag_op = NULL;
6419 // and 0, or ~0 used instead mov
6420 assert_operand_cnt(2);
6421 fprintf(fout, " %s = %s;",
6422 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6423 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6424 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6425 output_std_flags(fout, po, &pfomask, buf1);
6426 last_arith_dst = &po->operand[0];
6427 delayed_flag_op = NULL;
6432 assert_operand_cnt(2);
6433 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6434 if (pfomask & (1 << PFO_C)) {
6435 if (po->operand[1].type == OPT_CONST) {
6436 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6437 j = po->operand[1].val;
6440 if (po->op == OP_SHL)
6444 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6448 ferr(po, "zero shift?\n");
6452 pfomask &= ~(1 << PFO_C);
6454 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6455 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6456 if (po->operand[1].type != OPT_CONST)
6457 fprintf(fout, " & 0x1f");
6459 output_std_flags(fout, po, &pfomask, buf1);
6460 last_arith_dst = &po->operand[0];
6461 delayed_flag_op = NULL;
6465 assert_operand_cnt(2);
6466 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6467 fprintf(fout, " %s = %s%s >> %s;", buf1,
6468 lmod_cast_s(po, po->operand[0].lmod), buf1,
6469 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6470 output_std_flags(fout, po, &pfomask, buf1);
6471 last_arith_dst = &po->operand[0];
6472 delayed_flag_op = NULL;
6477 assert_operand_cnt(3);
6478 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6479 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6480 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6481 if (po->operand[2].type != OPT_CONST) {
6482 // no handling for "undefined" case, hopefully not needed
6483 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6486 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6487 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6488 if (po->op == OP_SHLD) {
6489 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6490 buf1, buf3, buf1, buf2, l, buf3);
6491 strcpy(g_comment, "shld");
6494 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6495 buf1, buf3, buf1, buf2, l, buf3);
6496 strcpy(g_comment, "shrd");
6498 output_std_flags(fout, po, &pfomask, buf1);
6499 last_arith_dst = &po->operand[0];
6500 delayed_flag_op = NULL;
6505 assert_operand_cnt(2);
6506 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6507 if (po->operand[1].type == OPT_CONST) {
6508 j = po->operand[1].val;
6509 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6510 fprintf(fout, po->op == OP_ROL ?
6511 " %s = (%s << %d) | (%s >> %d);" :
6512 " %s = (%s >> %d) | (%s << %d);",
6513 buf1, buf1, j, buf1,
6514 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6518 output_std_flags(fout, po, &pfomask, buf1);
6519 last_arith_dst = &po->operand[0];
6520 delayed_flag_op = NULL;
6525 assert_operand_cnt(2);
6526 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6527 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6528 if (po->operand[1].type == OPT_CONST) {
6529 j = po->operand[1].val % l;
6531 ferr(po, "zero rotate\n");
6532 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6533 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6534 if (po->op == OP_RCL) {
6536 " %s = (%s << %d) | (cond_c << %d)",
6537 buf1, buf1, j, j - 1);
6539 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6543 " %s = (%s >> %d) | (cond_c << %d)",
6544 buf1, buf1, j, l - j);
6546 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6548 fprintf(fout, ";\n");
6549 fprintf(fout, " cond_c = tmp;");
6553 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6554 output_std_flags(fout, po, &pfomask, buf1);
6555 last_arith_dst = &po->operand[0];
6556 delayed_flag_op = NULL;
6560 assert_operand_cnt(2);
6561 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6562 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6563 // special case for XOR
6564 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
6565 for (j = 0; j <= PFO_LE; j++) {
6566 if (pfomask & (1 << j)) {
6567 fprintf(fout, " cond_%s = %d;\n",
6568 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
6569 pfomask &= ~(1 << j);
6572 fprintf(fout, " %s = 0;",
6573 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6574 last_arith_dst = &po->operand[0];
6575 delayed_flag_op = NULL;
6581 assert_operand_cnt(2);
6582 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6583 if (pfomask & (1 << PFO_C)) {
6584 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6585 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6586 if (po->operand[0].lmod == OPLM_DWORD) {
6587 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6588 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6589 fprintf(fout, " %s = (u32)tmp64;",
6590 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6591 strcat(g_comment, " add64");
6594 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6595 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6596 fprintf(fout, " %s += %s;",
6597 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6600 pfomask &= ~(1 << PFO_C);
6601 output_std_flags(fout, po, &pfomask, buf1);
6602 last_arith_dst = &po->operand[0];
6603 delayed_flag_op = NULL;
6606 if (pfomask & (1 << PFO_LE)) {
6607 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
6608 fprintf(fout, " cond_%s = %s;\n",
6609 parsed_flag_op_names[PFO_LE], buf1);
6610 pfomask &= ~(1 << PFO_LE);
6615 assert_operand_cnt(2);
6616 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6617 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6618 for (j = 0; j <= PFO_LE; j++) {
6619 if (!(pfomask & (1 << j)))
6621 if (j == PFO_Z || j == PFO_S)
6624 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6625 fprintf(fout, " cond_%s = %s;\n",
6626 parsed_flag_op_names[j], buf1);
6627 pfomask &= ~(1 << j);
6634 assert_operand_cnt(2);
6635 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6636 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6637 if (po->op == OP_SBB
6638 && IS(po->operand[0].name, po->operand[1].name))
6640 // avoid use of unitialized var
6641 fprintf(fout, " %s = -cond_c;", buf1);
6642 // carry remains what it was
6643 pfomask &= ~(1 << PFO_C);
6646 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6647 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6649 output_std_flags(fout, po, &pfomask, buf1);
6650 last_arith_dst = &po->operand[0];
6651 delayed_flag_op = NULL;
6655 assert_operand_cnt(2);
6656 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6657 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6658 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6660 output_std_flags(fout, po, &pfomask, buf1);
6661 last_arith_dst = &po->operand[0];
6662 delayed_flag_op = NULL;
6663 strcat(g_comment, " bsf");
6667 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6668 for (j = 0; j <= PFO_LE; j++) {
6669 if (!(pfomask & (1 << j)))
6671 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6674 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6675 fprintf(fout, " cond_%s = %s;\n",
6676 parsed_flag_op_names[j], buf1);
6677 pfomask &= ~(1 << j);
6683 if (pfomask & (1 << PFO_C))
6684 // carry is unaffected by inc/dec.. wtf?
6685 ferr(po, "carry propagation needed\n");
6687 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6688 if (po->operand[0].type == OPT_REG) {
6689 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6690 fprintf(fout, " %s%s;", buf1, buf2);
6693 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6694 fprintf(fout, " %s %s= 1;", buf1, buf2);
6696 output_std_flags(fout, po, &pfomask, buf1);
6697 last_arith_dst = &po->operand[0];
6698 delayed_flag_op = NULL;
6702 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6703 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6704 fprintf(fout, " %s = -%s%s;", buf1,
6705 lmod_cast_s(po, po->operand[0].lmod), buf2);
6706 last_arith_dst = &po->operand[0];
6707 delayed_flag_op = NULL;
6708 if (pfomask & PFOB_C) {
6709 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6712 output_std_flags(fout, po, &pfomask, buf1);
6716 if (po->operand_cnt == 2) {
6717 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6720 if (po->operand_cnt == 3)
6721 ferr(po, "TODO imul3\n");
6724 assert_operand_cnt(1);
6725 switch (po->operand[0].lmod) {
6727 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6728 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6729 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6730 fprintf(fout, " edx = tmp64 >> 32;\n");
6731 fprintf(fout, " eax = tmp64;");
6734 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6735 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6736 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6740 ferr(po, "TODO: unhandled mul type\n");
6743 last_arith_dst = NULL;
6744 delayed_flag_op = NULL;
6749 assert_operand_cnt(1);
6750 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6751 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6752 po->op == OP_IDIV));
6753 switch (po->operand[0].lmod) {
6755 if (po->flags & OPF_32BIT)
6756 snprintf(buf2, sizeof(buf2), "%seax", cast);
6758 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6759 snprintf(buf2, sizeof(buf2), "%stmp64",
6760 (po->op == OP_IDIV) ? "(s64)" : "");
6762 if (po->operand[0].type == OPT_REG
6763 && po->operand[0].reg == xDX)
6765 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6766 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6769 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6770 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6774 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6775 snprintf(buf2, sizeof(buf2), "%stmp",
6776 (po->op == OP_IDIV) ? "(s32)" : "");
6777 if (po->operand[0].type == OPT_REG
6778 && po->operand[0].reg == xDX)
6780 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6782 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6786 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6788 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6791 strcat(g_comment, " div16");
6794 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6796 last_arith_dst = NULL;
6797 delayed_flag_op = NULL;
6802 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6804 for (j = 0; j < 8; j++) {
6805 if (pfomask & (1 << j)) {
6806 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6807 fprintf(fout, " cond_%s = %s;",
6808 parsed_flag_op_names[j], buf1);
6815 last_arith_dst = NULL;
6816 delayed_flag_op = po;
6820 // SETcc - should already be handled
6823 // note: we reuse OP_Jcc for SETcc, only flags differ
6825 fprintf(fout, "\n goto %s;", po->operand[0].name);
6829 fprintf(fout, " if (ecx == 0)\n");
6830 fprintf(fout, " goto %s;", po->operand[0].name);
6831 strcat(g_comment, " jecxz");
6835 fprintf(fout, " if (--ecx != 0)\n");
6836 fprintf(fout, " goto %s;", po->operand[0].name);
6837 strcat(g_comment, " loop");
6841 assert_operand_cnt(1);
6842 last_arith_dst = NULL;
6843 delayed_flag_op = NULL;
6845 if (po->operand[0].type == OPT_REGMEM) {
6846 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6849 ferr(po, "parse failure for jmp '%s'\n",
6850 po->operand[0].name);
6851 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6854 else if (po->operand[0].type != OPT_LABEL)
6855 ferr(po, "unhandled jmp type\n");
6857 fprintf(fout, " goto %s;", po->operand[0].name);
6861 assert_operand_cnt(1);
6863 my_assert_not(pp, NULL);
6866 if (po->flags & OPF_CC) {
6867 // we treat conditional branch to another func
6868 // (yes such code exists..) as conditional tailcall
6870 fprintf(fout, " {\n");
6873 if (pp->is_fptr && !pp->is_arg) {
6874 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6875 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6877 if (pp->is_unresolved)
6878 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6879 buf3, asmfn, po->asmln, pp->name);
6882 fprintf(fout, "%s", buf3);
6883 if (strstr(pp->ret_type.name, "int64")) {
6884 if (po->flags & OPF_TAIL)
6885 ferr(po, "int64 and tail?\n");
6886 fprintf(fout, "tmp64 = ");
6888 else if (!IS(pp->ret_type.name, "void")) {
6889 if (po->flags & OPF_TAIL) {
6890 if (regmask_ret & mxAX) {
6891 fprintf(fout, "return ");
6892 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6893 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6895 else if (regmask_ret & mxST0)
6896 ferr(po, "float tailcall\n");
6898 else if (po->regmask_dst & mxAX) {
6899 fprintf(fout, "eax = ");
6900 if (pp->ret_type.is_ptr)
6901 fprintf(fout, "(u32)");
6903 else if (po->regmask_dst & mxST0) {
6904 ferr_assert(po, po->flags & OPF_FPUSH);
6905 if (need_float_stack)
6906 fprintf(fout, "f_st[--f_stp & 7] = ");
6908 fprintf(fout, "f_st0 = ");
6912 if (pp->name[0] == 0)
6913 ferr(po, "missing pp->name\n");
6914 fprintf(fout, "%s%s(", pp->name,
6915 pp->has_structarg ? "_sa" : "");
6917 if (po->flags & OPF_ATAIL) {
6918 if (pp->argc_stack != g_func_pp->argc_stack
6919 || (pp->argc_stack > 0
6920 && pp->is_stdcall != g_func_pp->is_stdcall))
6921 ferr(po, "incompatible tailcall\n");
6922 if (g_func_pp->has_retreg)
6923 ferr(po, "TODO: retreg+tailcall\n");
6925 for (arg = j = 0; arg < pp->argc; arg++) {
6927 fprintf(fout, ", ");
6930 if (pp->arg[arg].type.is_ptr)
6931 snprintf(cast, sizeof(cast), "(%s)",
6932 pp->arg[arg].type.name);
6934 if (pp->arg[arg].reg != NULL) {
6935 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6939 for (; j < g_func_pp->argc; j++)
6940 if (g_func_pp->arg[j].reg == NULL)
6942 fprintf(fout, "%sa%d", cast, j + 1);
6947 for (arg = 0; arg < pp->argc; arg++) {
6949 fprintf(fout, ", ");
6952 if (pp->arg[arg].type.is_ptr)
6953 snprintf(cast, sizeof(cast), "(%s)",
6954 pp->arg[arg].type.name);
6956 if (pp->arg[arg].reg != NULL) {
6957 if (pp->arg[arg].type.is_retreg)
6958 fprintf(fout, "&%s", pp->arg[arg].reg);
6959 else if (IS(pp->arg[arg].reg, "ebp")
6960 && g_bp_frame && !(po->flags & OPF_EBP_S))
6962 // rare special case
6963 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
6964 strcat(g_comment, " bp_ref");
6967 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6972 tmp_op = pp->arg[arg].datap;
6974 ferr(po, "parsed_op missing for arg%d\n", arg);
6976 if (tmp_op->flags & OPF_VAPUSH) {
6977 fprintf(fout, "ap");
6979 else if (tmp_op->op == OP_FST) {
6980 fprintf(fout, "fs_%d", tmp_op->p_argnum);
6981 if (tmp_op->operand[0].lmod == OPLM_QWORD)
6984 else if (tmp_op->p_argpass != 0) {
6985 fprintf(fout, "a%d", tmp_op->p_argpass);
6987 else if (pp->arg[arg].is_saved) {
6988 ferr_assert(po, tmp_op->p_argnum > 0);
6989 fprintf(fout, "%s%s", cast,
6990 saved_arg_name(buf1, sizeof(buf1),
6991 tmp_op->p_arggrp, tmp_op->p_argnum));
6995 out_src_opr(buf1, sizeof(buf1),
6996 tmp_op, &tmp_op->operand[0], cast, 0));
7000 fprintf(fout, ");");
7002 if (strstr(pp->ret_type.name, "int64")) {
7003 fprintf(fout, "\n");
7004 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7005 fprintf(fout, "%seax = tmp64;", buf3);
7008 if (pp->is_unresolved) {
7009 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7011 strcat(g_comment, buf2);
7014 if (po->flags & OPF_TAIL) {
7016 if (i == opcnt - 1 || pp->is_noreturn)
7018 else if (IS(pp->ret_type.name, "void"))
7020 else if (!(regmask_ret & (1 << xAX)))
7022 // else already handled as 'return f()'
7025 fprintf(fout, "\n%sreturn;", buf3);
7026 strcat(g_comment, " ^ tailcall");
7029 strcat(g_comment, " tailcall");
7031 if ((regmask_ret & (1 << xAX))
7032 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7034 ferr(po, "int func -> void func tailcall?\n");
7037 if (pp->is_noreturn)
7038 strcat(g_comment, " noreturn");
7039 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7040 strcat(g_comment, " argframe");
7041 if (po->flags & OPF_CC)
7042 strcat(g_comment, " cond");
7044 if (po->flags & OPF_CC)
7045 fprintf(fout, "\n }");
7047 delayed_flag_op = NULL;
7048 last_arith_dst = NULL;
7052 if (g_func_pp->is_vararg)
7053 fprintf(fout, " va_end(ap);\n");
7054 if (g_func_pp->has_retreg) {
7055 for (arg = 0; arg < g_func_pp->argc; arg++)
7056 if (g_func_pp->arg[arg].type.is_retreg)
7057 fprintf(fout, " *r_%s = %s;\n",
7058 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7061 if (regmask_ret & mxST0) {
7062 fprintf(fout, " return %s;", float_st0);
7064 else if (!(regmask_ret & mxAX)) {
7065 if (i != opcnt - 1 || label_pending)
7066 fprintf(fout, " return;");
7068 else if (g_func_pp->ret_type.is_ptr) {
7069 fprintf(fout, " return (%s)eax;",
7070 g_func_pp->ret_type.name);
7072 else if (IS(g_func_pp->ret_type.name, "__int64"))
7073 fprintf(fout, " return ((u64)edx << 32) | eax;");
7075 fprintf(fout, " return eax;");
7077 last_arith_dst = NULL;
7078 delayed_flag_op = NULL;
7082 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7083 if (po->p_argnum != 0) {
7084 // special case - saved func arg
7085 fprintf(fout, " %s = %s;",
7086 saved_arg_name(buf2, sizeof(buf2),
7087 po->p_arggrp, po->p_argnum), buf1);
7090 else if (po->flags & OPF_RSAVE) {
7091 fprintf(fout, " s_%s = %s;", buf1, buf1);
7094 else if (po->flags & OPF_PPUSH) {
7096 ferr_assert(po, tmp_op != NULL);
7097 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7098 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7101 else if (g_func_pp->is_userstack) {
7102 fprintf(fout, " *(--esp) = %s;", buf1);
7105 if (!(g_ida_func_attr & IDAFA_NORETURN))
7106 ferr(po, "stray push encountered\n");
7111 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7112 if (po->flags & OPF_RSAVE) {
7113 fprintf(fout, " %s = s_%s;", buf1, buf1);
7116 else if (po->flags & OPF_PPUSH) {
7117 // push/pop graph / non-const
7118 ferr_assert(po, po->datap == NULL);
7119 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7122 else if (po->datap != NULL) {
7125 fprintf(fout, " %s = %s;", buf1,
7126 out_src_opr(buf2, sizeof(buf2),
7127 tmp_op, &tmp_op->operand[0],
7128 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7131 else if (g_func_pp->is_userstack) {
7132 fprintf(fout, " %s = *esp++;", buf1);
7136 ferr(po, "stray pop encountered\n");
7146 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7147 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7148 po->op == OPP_ALLSHL ? "<<" : ">>");
7149 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7150 strcat(g_comment, po->op == OPP_ALLSHL
7151 ? " allshl" : " allshr");
7156 if (need_float_stack) {
7157 out_src_opr_float(buf1, sizeof(buf1),
7158 po, &po->operand[0], 1);
7159 if (po->regmask_src & mxSTa) {
7160 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7164 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7167 if (po->flags & OPF_FSHIFT)
7168 fprintf(fout, " f_st1 = f_st0;");
7169 if (po->operand[0].type == OPT_REG
7170 && po->operand[0].reg == xST0)
7172 strcat(g_comment, " fld st");
7175 fprintf(fout, " f_st0 = %s;",
7176 out_src_opr_float(buf1, sizeof(buf1),
7177 po, &po->operand[0], 0));
7179 strcat(g_comment, " fld");
7183 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7184 lmod_cast(po, po->operand[0].lmod, 1), 0);
7185 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7186 if (need_float_stack) {
7187 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7190 if (po->flags & OPF_FSHIFT)
7191 fprintf(fout, " f_st1 = f_st0;");
7192 fprintf(fout, " f_st0 = %s;", buf2);
7194 strcat(g_comment, " fild");
7198 if (need_float_stack)
7199 fprintf(fout, " f_st[--f_stp & 7] = ");
7201 if (po->flags & OPF_FSHIFT)
7202 fprintf(fout, " f_st1 = f_st0;");
7203 fprintf(fout, " f_st0 = ");
7205 switch (po->operand[0].val) {
7206 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7207 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
7208 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7209 default: ferr(po, "TODO\n"); break;
7214 if (po->flags & OPF_FARG) {
7215 // store to stack as func arg
7216 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7220 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7222 dead_dst = po->operand[0].type == OPT_REG
7223 && po->operand[0].reg == xST0;
7226 fprintf(fout, " %s = %s;", buf1, float_st0);
7227 if (po->flags & OPF_FSHIFT) {
7228 if (need_float_stack)
7229 fprintf(fout, " f_stp++;");
7231 fprintf(fout, " f_st0 = f_st1;");
7233 if (dead_dst && !(po->flags & OPF_FSHIFT))
7236 strcat(g_comment, " fst");
7240 fprintf(fout, " %s = %s%s;",
7241 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7242 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7243 if (po->flags & OPF_FSHIFT) {
7244 if (need_float_stack)
7245 fprintf(fout, " f_stp++;");
7247 fprintf(fout, " f_st0 = f_st1;");
7249 strcat(g_comment, " fist");
7256 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7258 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7260 dead_dst = (po->flags & OPF_FPOP)
7261 && po->operand[0].type == OPT_REG
7262 && po->operand[0].reg == xST0;
7264 case OP_FADD: j = '+'; break;
7265 case OP_FDIV: j = '/'; break;
7266 case OP_FMUL: j = '*'; break;
7267 case OP_FSUB: j = '-'; break;
7268 default: j = 'x'; break;
7270 if (need_float_stack) {
7272 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7273 if (po->flags & OPF_FSHIFT)
7274 fprintf(fout, " f_stp++;");
7277 if (po->flags & OPF_FSHIFT) {
7278 // note: assumes only 2 regs handled
7280 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7282 fprintf(fout, " f_st0 = f_st1;");
7285 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7287 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7292 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7294 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7296 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7298 dead_dst = (po->flags & OPF_FPOP)
7299 && po->operand[0].type == OPT_REG
7300 && po->operand[0].reg == xST0;
7301 j = po->op == OP_FDIVR ? '/' : '-';
7302 if (need_float_stack) {
7304 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7305 if (po->flags & OPF_FSHIFT)
7306 fprintf(fout, " f_stp++;");
7309 if (po->flags & OPF_FSHIFT) {
7311 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7313 fprintf(fout, " f_st0 = f_st1;");
7316 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7318 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7326 case OP_FIADD: j = '+'; break;
7327 case OP_FIDIV: j = '/'; break;
7328 case OP_FIMUL: j = '*'; break;
7329 case OP_FISUB: j = '-'; break;
7330 default: j = 'x'; break;
7332 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7334 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7335 lmod_cast(po, po->operand[0].lmod, 1), 0));
7340 fprintf(fout, " %s = %s %c %s;", float_st0,
7341 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7343 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7348 ferr_assert(po, po->datap != NULL);
7349 mask = (long)po->datap & 0xffff;
7350 z_check = ((long)po->datap >> 16) & 1;
7351 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7353 if (mask == 0x0100) { // C0 -> <
7354 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7357 else if (mask == 0x4000) { // C3 -> =
7358 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7361 else if (mask == 0x4100) { // C3, C0
7363 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7365 strcat(g_comment, " z_chk_det");
7368 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7369 "(%s < %s ? 0x0100 : 0);",
7370 float_st0, buf1, float_st0, buf1);
7374 ferr(po, "unhandled sw mask: %x\n", mask);
7375 if (po->flags & OPF_FSHIFT) {
7376 if (need_float_stack)
7377 fprintf(fout, " f_stp++;");
7379 fprintf(fout, " f_st0 = f_st1;");
7385 fprintf(fout, " %s = f_sw;",
7386 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7390 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7394 fprintf(fout, " %s = cos%s(%s);", float_st0,
7395 need_double ? "" : "f", float_st0);
7399 if (need_float_stack) {
7400 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7401 need_double ? "" : "f", float_st1, float_st0);
7402 fprintf(fout, " f_stp++;");
7405 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7406 need_double ? "" : "f");
7411 if (need_float_stack) {
7412 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7413 float_st1, need_double ? "" : "f", float_st0);
7414 fprintf(fout, " f_stp++;");
7417 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7418 need_double ? "" : "f");
7420 strcat(g_comment, " fyl2x");
7424 fprintf(fout, " %s = sin%s(%s);", float_st0,
7425 need_double ? "" : "f", float_st0);
7429 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7430 need_double ? "" : "f", float_st0);
7434 dead_dst = po->operand[0].type == OPT_REG
7435 && po->operand[0].reg == xST0;
7437 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7439 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7440 float_st0, float_st0, buf1, buf1);
7441 strcat(g_comment, " fxch");
7448 ferr_assert(po, po->flags & OPF_32BIT);
7449 fprintf(fout, " eax = (s32)%s;", float_st0);
7450 if (po->flags & OPF_FSHIFT) {
7451 if (need_float_stack)
7452 fprintf(fout, " f_stp++;");
7454 fprintf(fout, " f_st0 = f_st1;");
7456 strcat(g_comment, " ftol");
7460 if (need_float_stack) {
7461 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
7462 need_double ? "" : "f", float_st1, float_st0);
7463 fprintf(fout, " f_stp++;");
7466 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
7467 need_double ? "" : "f");
7469 strcat(g_comment, " CIpow");
7473 fprintf(fout, " do_skip_code_abort();");
7478 fprintf(fout, " do_emms();");
7483 ferr(po, "unhandled op type %d, flags %x\n",
7488 if (g_comment[0] != 0) {
7489 char *p = g_comment;
7490 while (my_isblank(*p))
7492 fprintf(fout, " // %s", p);
7497 fprintf(fout, "\n");
7499 // some sanity checking
7500 if (po->flags & OPF_REP) {
7501 if (po->op != OP_STOS && po->op != OP_MOVS
7502 && po->op != OP_CMPS && po->op != OP_SCAS)
7503 ferr(po, "unexpected rep\n");
7504 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7505 && (po->op == OP_CMPS || po->op == OP_SCAS))
7506 ferr(po, "cmps/scas with plain rep\n");
7508 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7509 && po->op != OP_CMPS && po->op != OP_SCAS)
7510 ferr(po, "unexpected repz/repnz\n");
7513 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
7515 // see is delayed flag stuff is still valid
7516 if (delayed_flag_op != NULL && delayed_flag_op != po) {
7517 if (is_any_opr_modified(delayed_flag_op, po, 0))
7518 delayed_flag_op = NULL;
7521 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7522 if (is_opr_modified(last_arith_dst, po))
7523 last_arith_dst = NULL;
7529 if (g_stack_fsz && !g_stack_frame_used)
7530 fprintf(fout, " (void)sf;\n");
7532 fprintf(fout, "}\n\n");
7534 gen_x_cleanup(opcnt);
7537 static void gen_x_cleanup(int opcnt)
7541 for (i = 0; i < opcnt; i++) {
7542 struct label_ref *lr, *lr_del;
7544 lr = g_label_refs[i].next;
7545 while (lr != NULL) {
7550 g_label_refs[i].i = -1;
7551 g_label_refs[i].next = NULL;
7553 if (ops[i].op == OP_CALL) {
7555 proto_release(ops[i].pp);
7561 struct func_proto_dep;
7563 struct func_prototype {
7568 int has_ret:3; // -1, 0, 1: unresolved, no, yes
7569 unsigned int dep_resolved:1;
7570 unsigned int is_stdcall:1;
7571 struct func_proto_dep *dep_func;
7573 const struct parsed_proto *pp; // seed pp, if any
7576 struct func_proto_dep {
7578 struct func_prototype *proto;
7579 int regmask_live; // .. at the time of call
7580 unsigned int ret_dep:1; // return from this is caller's return
7583 static struct func_prototype *hg_fp;
7584 static int hg_fp_cnt;
7586 static struct scanned_var {
7588 enum opr_lenmod lmod;
7589 unsigned int is_seeded:1;
7590 unsigned int is_c_str:1;
7591 const struct parsed_proto *pp; // seed pp, if any
7593 static int hg_var_cnt;
7595 static char **hg_refs;
7596 static int hg_ref_cnt;
7598 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7601 static struct func_prototype *hg_fp_add(const char *funcn)
7603 struct func_prototype *fp;
7605 if ((hg_fp_cnt & 0xff) == 0) {
7606 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7607 my_assert_not(hg_fp, NULL);
7608 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7611 fp = &hg_fp[hg_fp_cnt];
7612 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7614 fp->argc_stack = -1;
7620 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7625 for (i = 0; i < fp->dep_func_cnt; i++)
7626 if (IS(fp->dep_func[i].name, name))
7627 return &fp->dep_func[i];
7632 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7635 if (hg_fp_find_dep(fp, name))
7638 if ((fp->dep_func_cnt & 0xff) == 0) {
7639 fp->dep_func = realloc(fp->dep_func,
7640 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7641 my_assert_not(fp->dep_func, NULL);
7642 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7643 sizeof(fp->dep_func[0]) * 0x100);
7645 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7649 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7651 const struct func_prototype *p1 = p1_, *p2 = p2_;
7652 return strcmp(p1->name, p2->name);
7656 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7658 const struct func_prototype *p1 = p1_, *p2 = p2_;
7659 return p1->id - p2->id;
7663 static void hg_ref_add(const char *name)
7665 if ((hg_ref_cnt & 0xff) == 0) {
7666 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7667 my_assert_not(hg_refs, NULL);
7668 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7671 hg_refs[hg_ref_cnt] = strdup(name);
7672 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7676 // recursive register dep pass
7677 // - track saved regs (part 2)
7678 // - try to figure out arg-regs
7679 // - calculate reg deps
7680 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
7681 struct func_prototype *fp, int regmask_save, int regmask_dst,
7682 int *regmask_dep, int *has_ret)
7684 struct func_proto_dep *dep;
7685 struct parsed_op *po;
7686 int from_caller = 0;
7691 for (; i < opcnt; i++)
7693 if (cbits[i >> 3] & (1 << (i & 7)))
7695 cbits[i >> 3] |= (1 << (i & 7));
7699 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
7700 if (po->flags & OPF_RMD)
7703 if (po->btj != NULL) {
7705 for (j = 0; j < po->btj->count; j++) {
7706 check_i(po, po->btj->d[j].bt_i);
7707 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
7708 regmask_save, regmask_dst, regmask_dep, has_ret);
7713 check_i(po, po->bt_i);
7714 if (po->flags & OPF_CJMP) {
7715 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
7716 regmask_save, regmask_dst, regmask_dep, has_ret);
7724 if (po->flags & OPF_FARG)
7725 /* (just calculate register deps) */;
7726 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
7728 reg = po->operand[0].reg;
7729 ferr_assert(po, reg >= 0);
7731 if (po->flags & OPF_RSAVE) {
7732 regmask_save |= 1 << reg;
7735 if (po->flags & OPF_DONE)
7738 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
7740 regmask_save |= 1 << reg;
7741 po->flags |= OPF_RMD;
7742 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
7746 else if (po->flags & OPF_RMD)
7748 else if (po->op == OP_CALL) {
7749 po->regmask_dst |= 1 << xAX;
7751 dep = hg_fp_find_dep(fp, po->operand[0].name);
7753 dep->regmask_live = regmask_save | regmask_dst;
7754 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7755 dep->regmask_live |= 1 << xBP;
7758 else if (po->op == OP_RET) {
7759 if (po->operand_cnt > 0) {
7761 if (fp->argc_stack >= 0
7762 && fp->argc_stack != po->operand[0].val / 4)
7763 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
7764 fp->argc_stack = po->operand[0].val / 4;
7768 // if has_ret is 0, there is uninitialized eax path,
7769 // which means it's most likely void func
7770 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
7771 if (po->op == OP_CALL) {
7776 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
7779 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
7782 if (ret != 1 && from_caller) {
7783 // unresolved eax - probably void func
7787 if (j >= 0 && ops[j].op == OP_CALL) {
7788 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
7799 l = regmask_save | regmask_dst;
7800 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7803 l = po->regmask_src & ~l;
7806 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
7807 l, regmask_dst, regmask_save, po->flags);
7810 regmask_dst |= po->regmask_dst;
7812 if (po->flags & OPF_TAIL)
7817 static void gen_hdr(const char *funcn, int opcnt)
7819 unsigned char cbits[MAX_OPS / 8];
7820 const struct parsed_proto *pp_c;
7821 struct parsed_proto *pp;
7822 struct func_prototype *fp;
7823 struct parsed_op *po;
7824 int regmask_dummy = 0;
7826 int max_bp_offset = 0;
7831 pp_c = proto_parse(g_fhdr, funcn, 1);
7833 // already in seed, will add to hg_fp later
7836 fp = hg_fp_add(funcn);
7838 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7839 g_stack_frame_used = 0;
7842 // - resolve all branches
7843 // - parse calls with labels
7844 resolve_branches_parse_calls(opcnt);
7847 // - handle ebp/esp frame, remove ops related to it
7848 scan_prologue_epilogue(opcnt);
7851 // - remove dead labels
7853 for (i = 0; i < opcnt; i++)
7855 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7861 if (po->flags & (OPF_RMD|OPF_DONE))
7864 if (po->op == OP_CALL) {
7865 if (po->operand[0].type == OPT_LABEL)
7866 hg_fp_add_dep(fp, opr_name(po, 0));
7867 else if (po->pp != NULL)
7868 hg_fp_add_dep(fp, po->pp->name);
7873 // - remove dead labels
7874 // - handle push <const>/pop pairs
7875 for (i = 0; i < opcnt; i++)
7877 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7883 if (po->flags & (OPF_RMD|OPF_DONE))
7886 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
7887 scan_for_pop_const(i, opcnt, i + opcnt * 13);
7891 // - process trivial calls
7892 for (i = 0; i < opcnt; i++)
7895 if (po->flags & (OPF_RMD|OPF_DONE))
7898 if (po->op == OP_CALL)
7900 pp = process_call_early(i, opcnt, &j);
7902 if (!(po->flags & OPF_ATAIL))
7903 // since we know the args, try to collect them
7904 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
7910 // commit esp adjust
7911 if (ops[j].op != OP_POP)
7912 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
7914 for (l = 0; l < pp->argc_stack; l++)
7915 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
7919 po->flags |= OPF_DONE;
7925 // - track saved regs (simple)
7927 for (i = 0; i < opcnt; i++)
7930 if (po->flags & (OPF_RMD|OPF_DONE))
7933 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7934 && po->operand[0].reg != xCX)
7936 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
7938 // regmask_save |= 1 << po->operand[0].reg; // do it later
7939 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
7940 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
7943 else if (po->op == OP_CALL)
7945 pp = process_call(i, opcnt);
7947 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
7948 // since we know the args, collect them
7949 ret = collect_call_args(po, i, pp, ®mask_dummy,
7956 memset(cbits, 0, sizeof(cbits));
7960 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
7962 // find unreachable code - must be fixed in IDA
7963 for (i = 0; i < opcnt; i++)
7965 if (cbits[i >> 3] & (1 << (i & 7)))
7968 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
7969 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
7971 // the compiler sometimes still generates code after
7972 // noreturn OS functions
7975 if (ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
7976 ferr(&ops[i], "unreachable code\n");
7979 for (i = 0; i < g_eqcnt; i++) {
7980 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
7981 max_bp_offset = g_eqs[i].offset;
7984 if (fp->argc_stack < 0) {
7985 max_bp_offset = (max_bp_offset + 3) & ~3;
7986 fp->argc_stack = max_bp_offset / 4;
7987 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
7991 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
7992 fp->has_ret = has_ret;
7994 printf("// has_ret %d, regmask_dep %x\n",
7995 fp->has_ret, fp->regmask_dep);
7996 output_hdr_fp(stdout, fp, 1);
7997 if (IS(funcn, "sub_10007F72")) exit(1);
8000 gen_x_cleanup(opcnt);
8003 static void hg_fp_resolve_deps(struct func_prototype *fp)
8005 struct func_prototype fp_s;
8009 // this thing is recursive, so mark first..
8010 fp->dep_resolved = 1;
8012 for (i = 0; i < fp->dep_func_cnt; i++) {
8013 strcpy(fp_s.name, fp->dep_func[i].name);
8014 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8015 sizeof(hg_fp[0]), hg_fp_cmp_name);
8016 if (fp->dep_func[i].proto != NULL) {
8017 if (!fp->dep_func[i].proto->dep_resolved)
8018 hg_fp_resolve_deps(fp->dep_func[i].proto);
8020 dep = ~fp->dep_func[i].regmask_live
8021 & fp->dep_func[i].proto->regmask_dep;
8022 fp->regmask_dep |= dep;
8023 // printf("dep %s %s |= %x\n", fp->name,
8024 // fp->dep_func[i].name, dep);
8026 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8027 fp->has_ret = fp->dep_func[i].proto->has_ret;
8032 // make all thiscall/edx arg functions referenced from .data fastcall
8033 static void do_func_refs_from_data(void)
8035 struct func_prototype *fp, fp_s;
8038 for (i = 0; i < hg_ref_cnt; i++) {
8039 strcpy(fp_s.name, hg_refs[i]);
8040 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8041 sizeof(hg_fp[0]), hg_fp_cmp_name);
8045 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8046 fp->regmask_dep |= mxCX | mxDX;
8050 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8053 const struct parsed_proto *pp;
8054 char *p, namebuf[NAMELEN];
8060 for (; count > 0; count--, fp++) {
8061 if (fp->has_ret == -1)
8062 fprintf(fout, "// ret unresolved\n");
8064 fprintf(fout, "// dep:");
8065 for (j = 0; j < fp->dep_func_cnt; j++) {
8066 fprintf(fout, " %s/", fp->dep_func[j].name);
8067 if (fp->dep_func[j].proto != NULL)
8068 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8069 fp->dep_func[j].proto->has_ret);
8071 fprintf(fout, "\n");
8074 p = strchr(fp->name, '@');
8076 memcpy(namebuf, fp->name, p - fp->name);
8077 namebuf[p - fp->name] = 0;
8085 pp = proto_parse(g_fhdr, name, 1);
8086 if (pp != NULL && pp->is_include)
8089 if (fp->pp != NULL) {
8090 // part of seed, output later
8094 regmask_dep = fp->regmask_dep;
8095 argc_normal = fp->argc_stack;
8097 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8098 (fp->has_ret ? "int" : "void"));
8099 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8100 && (regmask_dep & ~mxCX) == 0)
8102 fprintf(fout, "/*__thiscall*/ ");
8106 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8107 && (regmask_dep & ~(mxCX | mxDX)) == 0)
8109 fprintf(fout, " __fastcall ");
8110 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8116 else if (regmask_dep && !fp->is_stdcall) {
8117 fprintf(fout, "/*__usercall*/ ");
8119 else if (regmask_dep) {
8120 fprintf(fout, "/*__userpurge*/ ");
8122 else if (fp->is_stdcall)
8123 fprintf(fout, " __stdcall ");
8125 fprintf(fout, " __cdecl ");
8127 fprintf(fout, "%s(", name);
8130 for (j = 0; j < xSP; j++) {
8131 if (regmask_dep & (1 << j)) {
8134 fprintf(fout, ", ");
8136 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8138 fprintf(fout, "int");
8139 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8143 for (j = 0; j < argc_normal; j++) {
8146 fprintf(fout, ", ");
8147 if (fp->pp != NULL) {
8148 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8149 if (!fp->pp->arg[arg - 1].type.is_ptr)
8153 fprintf(fout, "int ");
8154 fprintf(fout, "a%d", arg);
8157 fprintf(fout, ");\n");
8161 static void output_hdr(FILE *fout)
8163 static const char *lmod_c_names[] = {
8164 [OPLM_UNSPEC] = "???",
8165 [OPLM_BYTE] = "uint8_t",
8166 [OPLM_WORD] = "uint16_t",
8167 [OPLM_DWORD] = "uint32_t",
8168 [OPLM_QWORD] = "uint64_t",
8170 const struct scanned_var *var;
8171 struct func_prototype *fp;
8172 char line[256] = { 0, };
8176 // add stuff from headers
8177 for (i = 0; i < pp_cache_size; i++) {
8178 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8179 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8181 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8182 fp = hg_fp_add(name);
8183 fp->pp = &pp_cache[i];
8184 fp->argc_stack = fp->pp->argc_stack;
8185 fp->is_stdcall = fp->pp->is_stdcall;
8186 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8187 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8191 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8192 for (i = 0; i < hg_fp_cnt; i++)
8193 hg_fp_resolve_deps(&hg_fp[i]);
8195 // adjust functions referenced from data segment
8196 do_func_refs_from_data();
8198 // note: messes up .proto ptr, don't use
8199 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8202 for (i = 0; i < hg_var_cnt; i++) {
8205 if (var->pp != NULL)
8208 else if (var->is_c_str)
8209 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8211 fprintf(fout, "extern %-8s %s;",
8212 lmod_c_names[var->lmod], var->name);
8215 fprintf(fout, " // seeded");
8216 fprintf(fout, "\n");
8219 fprintf(fout, "\n");
8221 // output function prototypes
8222 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8225 fprintf(fout, "\n// - seed -\n");
8228 while (fgets(line, sizeof(line), g_fhdr))
8229 fwrite(line, 1, strlen(line), fout);
8232 // '=' needs special treatment
8234 static char *next_word_s(char *w, size_t wsize, char *s)
8241 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8243 for (i = 1; i < wsize - 1; i++) {
8245 printf("warning: missing closing quote: \"%s\"\n", s);
8254 for (; i < wsize - 1; i++) {
8255 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8261 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8262 printf("warning: '%s' truncated\n", w);
8267 static int cmpstringp(const void *p1, const void *p2)
8269 return strcmp(*(char * const *)p1, *(char * const *)p2);
8272 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8277 if (strstr(p, "..."))
8278 // unable to determine, assume needed
8281 if (*p == '.') // .text, .data, ...
8282 // ref from other data or non-function -> no
8285 p2 = strpbrk(p, "+:\r\n\x18");
8288 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8289 // referenced from removed code
8295 static int ida_xrefs_show_need(FILE *fasm, char *p,
8296 char **rlist, int rlist_len)
8302 p = strrchr(p, ';');
8303 if (p != NULL && *p == ';') {
8304 if (IS_START(p + 2, "sctref"))
8306 if (IS_START(p + 2, "DATA XREF: ")) {
8308 if (is_xref_needed(p, rlist, rlist_len))
8316 if (!my_fgets(line, sizeof(line), fasm))
8318 // non-first line is always indented
8319 if (!my_isblank(line[0]))
8322 // should be no content, just comment
8327 p = strrchr(p, ';');
8330 if (IS_START(p, "sctref")) {
8335 // it's printed once, but no harm to check again
8336 if (IS_START(p, "DATA XREF: "))
8339 if (is_xref_needed(p, rlist, rlist_len)) {
8344 fseek(fasm, pos, SEEK_SET);
8348 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8350 struct scanned_var *var;
8351 char line[256] = { 0, };
8360 // skip to next data section
8361 while (my_fgets(line, sizeof(line), fasm))
8366 if (*p == 0 || *p == ';')
8369 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8370 if (*p == 0 || *p == ';')
8373 if (*p != 's' || !IS_START(p, "segment para public"))
8379 if (p == NULL || !IS_START(p, "segment para public"))
8383 if (!IS_START(p, "'DATA'"))
8387 while (my_fgets(line, sizeof(line), fasm))
8392 no_identifier = my_isblank(*p);
8395 if (*p == 0 || *p == ';')
8398 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8399 words[wordc][0] = 0;
8400 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8401 if (*p == 0 || *p == ';') {
8407 if (wordc == 2 && IS(words[1], "ends"))
8412 if (no_identifier) {
8413 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8414 hg_ref_add(words[2]);
8418 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8419 // when this starts, we don't need anything from this section
8423 // check refs comment(s)
8424 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8427 if ((hg_var_cnt & 0xff) == 0) {
8428 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8429 * (hg_var_cnt + 0x100));
8430 my_assert_not(hg_vars, NULL);
8431 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8434 var = &hg_vars[hg_var_cnt++];
8435 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8437 // maybe already in seed header?
8438 var->pp = proto_parse(g_fhdr, var->name, 1);
8439 if (var->pp != NULL) {
8440 if (var->pp->is_fptr) {
8441 var->lmod = OPLM_DWORD;
8444 else if (var->pp->is_func)
8446 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8447 aerr("unhandled C type '%s' for '%s'\n",
8448 var->pp->type.name, var->name);
8454 if (IS(words[1], "dd")) {
8455 var->lmod = OPLM_DWORD;
8456 if (wordc >= 4 && IS(words[2], "offset"))
8457 hg_ref_add(words[3]);
8459 else if (IS(words[1], "dw"))
8460 var->lmod = OPLM_WORD;
8461 else if (IS(words[1], "db")) {
8462 var->lmod = OPLM_BYTE;
8463 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8464 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8468 else if (IS(words[1], "dq"))
8469 var->lmod = OPLM_QWORD;
8470 //else if (IS(words[1], "dt"))
8472 aerr("type '%s' not known\n", words[1]);
8480 static void set_label(int i, const char *name)
8486 p = strchr(name, ':');
8490 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8491 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8492 g_labels[i] = realloc(g_labels[i], len + 1);
8493 my_assert_not(g_labels[i], NULL);
8494 memcpy(g_labels[i], name, len);
8495 g_labels[i][len] = 0;
8504 static struct chunk_item *func_chunks;
8505 static int func_chunk_cnt;
8506 static int func_chunk_alloc;
8508 static void add_func_chunk(FILE *fasm, const char *name, int line)
8510 if (func_chunk_cnt >= func_chunk_alloc) {
8511 func_chunk_alloc *= 2;
8512 func_chunks = realloc(func_chunks,
8513 func_chunk_alloc * sizeof(func_chunks[0]));
8514 my_assert_not(func_chunks, NULL);
8516 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8517 func_chunks[func_chunk_cnt].name = strdup(name);
8518 func_chunks[func_chunk_cnt].asmln = line;
8522 static int cmp_chunks(const void *p1, const void *p2)
8524 const struct chunk_item *c1 = p1, *c2 = p2;
8525 return strcmp(c1->name, c2->name);
8528 static void scan_ahead_for_chunks(FILE *fasm)
8538 oldpos = ftell(fasm);
8541 while (my_fgets(line, sizeof(line), fasm))
8552 // get rid of random tabs
8553 for (i = 0; line[i] != 0; i++)
8554 if (line[i] == '\t')
8557 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8560 next_word(words[0], sizeof(words[0]), p);
8561 if (words[0][0] == 0)
8562 aerr("missing name for func chunk?\n");
8564 add_func_chunk(fasm, words[0], asmln);
8566 else if (IS_START(p, "; sctend"))
8572 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8573 words[wordc][0] = 0;
8574 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8575 if (*p == 0 || *p == ';') {
8581 if (wordc == 2 && IS(words[1], "ends"))
8585 fseek(fasm, oldpos, SEEK_SET);
8589 int main(int argc, char *argv[])
8591 FILE *fout, *fasm, *frlist;
8592 struct parsed_data *pd = NULL;
8594 char **rlist = NULL;
8596 int rlist_alloc = 0;
8597 int func_chunks_used = 0;
8598 int func_chunks_sorted = 0;
8599 int func_chunk_i = -1;
8600 long func_chunk_ret = 0;
8601 int func_chunk_ret_ln = 0;
8602 int scanned_ahead = 0;
8604 char words[20][256];
8605 enum opr_lenmod lmod;
8606 char *sctproto = NULL;
8608 int pending_endp = 0;
8610 int skip_code_end = 0;
8611 int skip_warned = 0;
8624 for (arg = 1; arg < argc; arg++) {
8625 if (IS(argv[arg], "-v"))
8627 else if (IS(argv[arg], "-rf"))
8628 g_allow_regfunc = 1;
8629 else if (IS(argv[arg], "-uc"))
8630 g_allow_user_icall = 1;
8631 else if (IS(argv[arg], "-m"))
8633 else if (IS(argv[arg], "-hdr"))
8634 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8639 if (argc < arg + 3) {
8640 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8641 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8643 " -hdr - header generation mode\n"
8644 " -rf - allow unannotated indirect calls\n"
8645 " -uc - allow ind. calls/refs to __usercall\n"
8646 " -m - allow multiple .text sections\n"
8647 "[rlist] is a file with function names to skip,"
8655 asmfn = argv[arg++];
8656 fasm = fopen(asmfn, "r");
8657 my_assert_not(fasm, NULL);
8659 hdrfn = argv[arg++];
8660 g_fhdr = fopen(hdrfn, "r");
8661 my_assert_not(g_fhdr, NULL);
8664 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8665 my_assert_not(rlist, NULL);
8666 // needs special handling..
8667 rlist[rlist_len++] = "__alloca_probe";
8669 func_chunk_alloc = 32;
8670 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8671 my_assert_not(func_chunks, NULL);
8673 memset(words, 0, sizeof(words));
8675 for (; arg < argc; arg++) {
8678 frlist = fopen(argv[arg], "r");
8679 my_assert_not(frlist, NULL);
8681 while (my_fgets(line, sizeof(line), frlist)) {
8683 if (*p == 0 || *p == ';')
8686 if (IS_START(p, "#if 0")
8687 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
8691 else if (IS_START(p, "#endif"))
8698 p = next_word(words[0], sizeof(words[0]), p);
8699 if (words[0][0] == 0)
8702 if (rlist_len >= rlist_alloc) {
8703 rlist_alloc = rlist_alloc * 2 + 64;
8704 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
8705 my_assert_not(rlist, NULL);
8707 rlist[rlist_len++] = strdup(words[0]);
8715 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
8717 fout = fopen(argv[arg_out], "w");
8718 my_assert_not(fout, NULL);
8721 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
8722 my_assert_not(g_eqs, NULL);
8724 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
8725 g_label_refs[i].i = -1;
8726 g_label_refs[i].next = NULL;
8730 scan_variables(fasm, rlist, rlist_len);
8732 while (my_fgets(line, sizeof(line), fasm))
8741 // get rid of random tabs
8742 for (i = 0; line[i] != 0; i++)
8743 if (line[i] == '\t')
8748 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
8749 goto do_pending_endp; // eww..
8751 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
8753 static const char *attrs[] = {
8762 // parse IDA's attribute-list comment
8763 g_ida_func_attr = 0;
8766 for (; *p != 0; p = sskip(p)) {
8767 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8768 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8769 g_ida_func_attr |= 1 << i;
8770 p += strlen(attrs[i]);
8774 if (i == ARRAY_SIZE(attrs)) {
8775 anote("unparsed IDA attr: %s\n", p);
8778 if (IS(attrs[i], "fpd=")) {
8779 p = next_word(words[0], sizeof(words[0]), p);
8784 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
8786 static const char *attrs[] = {
8791 // parse manual attribute-list comment
8792 g_sct_func_attr = 0;
8795 for (; *p != 0; p = sskip(p)) {
8796 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8797 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8798 g_sct_func_attr |= 1 << i;
8799 p += strlen(attrs[i]);
8806 // clear_sf=start,len (in dwords)
8807 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
8808 &g_stack_clear_len, &j);
8810 // clear_regmask=<mask>
8811 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
8813 anote("unparsed attr value: %s\n", p);
8818 else if (i == ARRAY_SIZE(attrs)) {
8819 anote("unparsed sct attr: %s\n", p);
8824 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8827 next_word(words[0], sizeof(words[0]), p);
8828 if (words[0][0] == 0)
8829 aerr("missing name for func chunk?\n");
8831 if (!scanned_ahead) {
8832 add_func_chunk(fasm, words[0], asmln);
8833 func_chunks_sorted = 0;
8836 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
8838 if (func_chunk_i >= 0) {
8839 if (func_chunk_i < func_chunk_cnt
8840 && IS(func_chunks[func_chunk_i].name, g_func))
8842 // move on to next chunk
8843 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8845 aerr("seek failed for '%s' chunk #%d\n",
8846 g_func, func_chunk_i);
8847 asmln = func_chunks[func_chunk_i].asmln;
8851 if (func_chunk_ret == 0)
8852 aerr("no return from chunk?\n");
8853 fseek(fasm, func_chunk_ret, SEEK_SET);
8854 asmln = func_chunk_ret_ln;
8860 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
8861 func_chunks_used = 1;
8863 if (IS_START(g_func, "sub_")) {
8864 unsigned long addr = strtoul(p, NULL, 16);
8865 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
8866 if (addr > f_addr && !scanned_ahead) {
8867 //anote("scan_ahead caused by '%s', addr %lx\n",
8869 scan_ahead_for_chunks(fasm);
8871 func_chunks_sorted = 0;
8879 for (i = wordc; i < ARRAY_SIZE(words); i++)
8881 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8882 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8883 if (*p == 0 || *p == ';') {
8888 if (*p != 0 && *p != ';')
8889 aerr("too many words\n");
8891 if (skip_code_end) {
8896 // allow asm patches in comments
8898 if (IS_START(p, "; sctpatch:")) {
8900 if (*p == 0 || *p == ';')
8902 goto parse_words; // lame
8904 if (IS_START(p, "; sctproto:")) {
8905 sctproto = strdup(p + 11);
8907 else if (IS_START(p, "; sctend")) {
8912 else if (IS_START(p, "; sctskip_start")) {
8913 if (in_func && !g_skip_func) {
8915 ops[pi].op = OPP_ABORT;
8916 ops[pi].asmln = asmln;
8922 else if (IS_START(p, "; sctskip_end")) {
8930 awarn("wordc == 0?\n");
8934 // don't care about this:
8935 if (words[0][0] == '.'
8936 || IS(words[0], "include")
8937 || IS(words[0], "assume") || IS(words[1], "segment")
8938 || IS(words[0], "align"))
8944 // do delayed endp processing to collect switch jumptables
8946 if (in_func && !g_skip_func && !end && wordc >= 2
8947 && ((words[0][0] == 'd' && words[0][2] == 0)
8948 || (words[1][0] == 'd' && words[1][2] == 0)))
8951 if (words[1][0] == 'd' && words[1][2] == 0) {
8953 if (g_func_pd_cnt >= pd_alloc) {
8954 pd_alloc = pd_alloc * 2 + 16;
8955 g_func_pd = realloc(g_func_pd,
8956 sizeof(g_func_pd[0]) * pd_alloc);
8957 my_assert_not(g_func_pd, NULL);
8959 pd = &g_func_pd[g_func_pd_cnt];
8961 memset(pd, 0, sizeof(*pd));
8962 strcpy(pd->label, words[0]);
8963 pd->type = OPT_CONST;
8964 pd->lmod = lmod_from_directive(words[1]);
8970 anote("skipping alignment byte?\n");
8973 lmod = lmod_from_directive(words[0]);
8974 if (lmod != pd->lmod)
8975 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
8978 if (pd->count_alloc < pd->count + wordc) {
8979 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
8980 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
8981 my_assert_not(pd->d, NULL);
8983 for (; i < wordc; i++) {
8984 if (IS(words[i], "offset")) {
8985 pd->type = OPT_OFFSET;
8988 p = strchr(words[i], ',');
8991 if (pd->type == OPT_OFFSET)
8992 pd->d[pd->count].u.label = strdup(words[i]);
8994 pd->d[pd->count].u.val = parse_number(words[i]);
8995 pd->d[pd->count].bt_i = -1;
9001 if (in_func && !g_skip_func) {
9003 gen_hdr(g_func, pi);
9005 gen_func(fout, g_fhdr, g_func, pi);
9010 g_ida_func_attr = 0;
9011 g_sct_func_attr = 0;
9012 g_stack_clear_start = 0;
9013 g_stack_clear_len = 0;
9018 func_chunks_used = 0;
9021 memset(&ops, 0, pi * sizeof(ops[0]));
9026 for (i = 0; i < g_func_pd_cnt; i++) {
9028 if (pd->type == OPT_OFFSET) {
9029 for (j = 0; j < pd->count; j++)
9030 free(pd->d[j].u.label);
9045 if (IS(words[1], "proc")) {
9047 aerr("proc '%s' while in_func '%s'?\n",
9050 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9052 strcpy(g_func, words[0]);
9053 set_label(0, words[0]);
9058 if (IS(words[1], "endp"))
9061 aerr("endp '%s' while not in_func?\n", words[0]);
9062 if (!IS(g_func, words[0]))
9063 aerr("endp '%s' while in_func '%s'?\n",
9066 aerr("endp '%s' while skipping code\n", words[0]);
9068 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9069 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
9075 if (!g_skip_func && func_chunks_used) {
9076 // start processing chunks
9077 struct chunk_item *ci, key = { g_func, 0 };
9079 func_chunk_ret = ftell(fasm);
9080 func_chunk_ret_ln = asmln;
9081 if (!func_chunks_sorted) {
9082 qsort(func_chunks, func_chunk_cnt,
9083 sizeof(func_chunks[0]), cmp_chunks);
9084 func_chunks_sorted = 1;
9086 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9087 sizeof(func_chunks[0]), cmp_chunks);
9089 aerr("'%s' needs chunks, but none found\n", g_func);
9090 func_chunk_i = ci - func_chunks;
9091 for (; func_chunk_i > 0; func_chunk_i--)
9092 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9095 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9097 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9098 asmln = func_chunks[func_chunk_i].asmln;
9106 if (wordc == 2 && IS(words[1], "ends")) {
9110 goto do_pending_endp;
9114 // scan for next text segment
9115 while (my_fgets(line, sizeof(line), fasm)) {
9118 if (*p == 0 || *p == ';')
9121 if (strstr(p, "segment para public 'CODE' use32"))
9128 p = strchr(words[0], ':');
9130 set_label(pi, words[0]);
9134 if (!in_func || g_skip_func || skip_code) {
9135 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9137 anote("skipping from '%s'\n", g_labels[pi]);
9141 g_labels[pi] = NULL;
9145 if (wordc > 1 && IS(words[1], "="))
9148 aerr("unhandled equ, wc=%d\n", wordc);
9149 if (g_eqcnt >= eq_alloc) {
9151 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9152 my_assert_not(g_eqs, NULL);
9155 len = strlen(words[0]);
9156 if (len > sizeof(g_eqs[0].name) - 1)
9157 aerr("equ name too long: %d\n", len);
9158 strcpy(g_eqs[g_eqcnt].name, words[0]);
9160 if (!IS(words[3], "ptr"))
9161 aerr("unhandled equ\n");
9162 if (IS(words[2], "dword"))
9163 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9164 else if (IS(words[2], "word"))
9165 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9166 else if (IS(words[2], "byte"))
9167 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9168 else if (IS(words[2], "qword"))
9169 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9171 aerr("bad lmod: '%s'\n", words[2]);
9173 g_eqs[g_eqcnt].offset = parse_number(words[4]);
9178 if (pi >= ARRAY_SIZE(ops))
9179 aerr("too many ops\n");
9181 parse_op(&ops[pi], words, wordc);
9183 ops[pi].datap = sctproto;
9198 // vim:ts=2:shiftwidth=2:expandtab