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)
24 #include "my_assert.h"
28 #include "protoparse.h"
30 static const char *asmfn;
34 #define anote(fmt, ...) \
35 printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
36 #define awarn(fmt, ...) \
37 printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
38 #define aerr(fmt, ...) do { \
39 printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
44 #include "masm_tools.h"
47 OPF_RMD = (1 << 0), /* removed from code generation */
48 OPF_DATA = (1 << 1), /* data processing - writes to dst opr */
49 OPF_FLAGS = (1 << 2), /* sets flags */
50 OPF_JMP = (1 << 3), /* branch, call */
51 OPF_CJMP = (1 << 4), /* cond. branch (cc or jecxz/loop) */
52 OPF_CC = (1 << 5), /* uses flags */
53 OPF_TAIL = (1 << 6), /* ret or tail call */
54 OPF_RSAVE = (1 << 7), /* push/pop is local reg save/load */
55 OPF_REP = (1 << 8), /* prefixed by rep */
56 OPF_REPZ = (1 << 9), /* rep is repe/repz */
57 OPF_REPNZ = (1 << 10), /* rep is repne/repnz */
58 OPF_FARG = (1 << 11), /* push collected as func arg */
59 OPF_FARGNR = (1 << 12), /* push collected as func arg (no reuse) */
60 OPF_EBP_S = (1 << 13), /* ebp used as scratch here, not BP */
61 OPF_DF = (1 << 14), /* DF flag set */
62 OPF_ATAIL = (1 << 15), /* tail call with reused arg frame */
63 OPF_32BIT = (1 << 16), /* 32bit division */
64 OPF_LOCK = (1 << 17), /* op has lock prefix */
65 OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
66 OPF_DONE = (1 << 19), /* already fully handled by analysis */
67 OPF_PPUSH = (1 << 20), /* part of complex push-pop graph */
68 OPF_NOREGS = (1 << 21), /* don't track regs of this op */
69 OPF_FPUSH = (1 << 22), /* pushes x87 stack */
70 OPF_FPOP = (1 << 23), /* pops x87 stack */
71 OPF_FSHIFT = (1 << 24), /* x87 stack shift is actually needed */
162 // pseudo-ops for lib calls
181 // must be sorted (larger len must be further in enum)
190 #define MAX_EXITS 128
192 #define MAX_OPERANDS 3
195 #define OPR_INIT(type_, lmod_, reg_) \
196 { type_, lmod_, reg_, }
200 enum opr_lenmod lmod;
202 unsigned int is_ptr:1; // pointer in C
203 unsigned int is_array:1; // array in C
204 unsigned int type_from_var:1; // .. in header, sometimes wrong
205 unsigned int size_mismatch:1; // type override differs from C
206 unsigned int size_lt:1; // type override is larger than C
207 unsigned int had_ds:1; // had ds: prefix
208 const struct parsed_proto *pp; // for OPT_LABEL
215 struct parsed_opr operand[MAX_OPERANDS];
218 unsigned char pfo_inv;
219 unsigned char operand_cnt;
220 unsigned char p_argnum; // arg push: altered before call arg #
221 unsigned char p_arggrp; // arg push: arg group # for above
222 unsigned char p_argpass;// arg push: arg of host func
223 short p_argnext;// arg push: same arg pushed elsewhere or -1
224 int regmask_src; // all referensed regs
226 int pfomask; // flagop: parsed_flag_op that can't be delayed
227 int cc_scratch; // scratch storage during analysis
228 int bt_i; // branch target for branches
229 struct parsed_data *btj;// branch targets for jumptables
230 struct parsed_proto *pp;// parsed_proto for OP_CALL
236 // on start: function/data type hint (sctproto)
238 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
239 // OP_PUSH - points to OP_POP in complex push/pop graph
240 // OP_POP - points to OP_PUSH in simple push/pop pair
241 // OP_FCOM - needed_status_word_bits | (is_z_check << 16)
245 enum opr_lenmod lmod;
252 enum opr_lenmod lmod;
266 struct label_ref *next;
270 IDAFA_BP_FRAME = (1 << 0),
271 IDAFA_LIB_FUNC = (1 << 1),
272 IDAFA_STATIC = (1 << 2),
273 IDAFA_NORETURN = (1 << 3),
274 IDAFA_THUNK = (1 << 4),
275 IDAFA_FPD = (1 << 5),
279 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
280 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
293 // note: limited to 32k due to p_argnext
295 #define MAX_ARG_GRP 2
297 static struct parsed_op ops[MAX_OPS];
298 static struct parsed_equ *g_eqs;
300 static char *g_labels[MAX_OPS];
301 static struct label_ref g_label_refs[MAX_OPS];
302 static const struct parsed_proto *g_func_pp;
303 static struct parsed_data *g_func_pd;
304 static int g_func_pd_cnt;
305 static int g_func_lmods;
306 static char g_func[256];
307 static char g_comment[256];
308 static int g_bp_frame;
309 static int g_sp_frame;
310 static int g_stack_frame_used;
311 static int g_stack_fsz;
312 static int g_ida_func_attr;
313 static int g_sct_func_attr;
314 static int g_stack_clear_start; // in dwords
315 static int g_stack_clear_len;
316 static int g_regmask_init;
317 static int g_skip_func;
318 static int g_allow_regfunc;
319 static int g_allow_user_icall;
320 static int g_quiet_pp;
321 static int g_header_mode;
323 #define ferr(op_, fmt, ...) do { \
324 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
325 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
329 #define fnote(op_, fmt, ...) \
330 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
331 dump_op(op_), ##__VA_ARGS__)
333 #define ferr_assert(op_, cond) do { \
334 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
337 const char *regs_r32[] = {
338 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
339 // not r32, but list here for easy parsing and printing
340 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
341 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
343 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
344 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
345 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
351 xMM0, xMM1, xMM2, xMM3, // mmx
352 xMM4, xMM5, xMM6, xMM7,
353 xST0, xST1, xST2, xST3, // x87
354 xST4, xST5, xST6, xST7,
357 #define mxAX (1 << xAX)
358 #define mxCX (1 << xCX)
359 #define mxDX (1 << xDX)
360 #define mxSP (1 << xSP)
361 #define mxST0 (1 << xST0)
362 #define mxST1 (1 << xST1)
363 #define mxST1_0 (mxST1 | mxST0)
364 #define mxST7_2 (0xfc << xST0)
365 #define mxSTa (0xff << xST0)
367 // possible basic comparison types (without inversion)
368 enum parsed_flag_op {
372 PFO_BE, // 6 CF=1||ZF=1
376 PFO_LE, // e ZF=1||SF!=OF
379 #define PFOB_O (1 << PFO_O)
380 #define PFOB_C (1 << PFO_C)
381 #define PFOB_Z (1 << PFO_Z)
382 #define PFOB_S (1 << PFO_S)
384 static const char *parsed_flag_op_names[] = {
385 "o", "c", "z", "be", "s", "p", "l", "le"
388 static int char_array_i(const char *array[], size_t len, const char *s)
392 for (i = 0; i < len; i++)
399 static void printf_number(char *buf, size_t buf_size,
400 unsigned long number)
402 // output in C-friendly form
403 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
406 static int check_segment_prefix(const char *s)
408 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
422 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
426 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
428 *reg_lmod = OPLM_QWORD;
432 *reg_lmod = OPLM_DWORD;
435 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
437 *reg_lmod = OPLM_WORD;
440 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
442 *reg_lmod = OPLM_BYTE;
445 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
447 *reg_lmod = OPLM_BYTE;
454 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
456 enum opr_lenmod lmod;
469 while (my_isblank(*s))
471 for (; my_issep(*s); d++, s++)
473 while (my_isblank(*s))
477 // skip '?s:' prefixes
478 if (check_segment_prefix(s))
481 s = next_idt(w, sizeof(w), s);
486 reg = parse_reg(&lmod, w);
488 *regmask |= 1 << reg;
492 if ('0' <= w[0] && w[0] <= '9') {
493 number = parse_number(w, 0);
494 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
498 // probably some label/identifier - pass
501 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
505 strcpy(name, cvtbuf);
510 static int is_reg_in_str(const char *s)
514 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
517 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
518 if (!strncmp(s, regs_r32[i], 3))
524 static const char *parse_stack_el(const char *name, char *extra_reg,
525 int *base_val, int early_try)
527 const char *p, *p2, *s;
533 if (g_bp_frame || early_try)
536 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
538 if (extra_reg != NULL) {
539 strncpy(extra_reg, name, 3);
544 if (IS_START(p, "ebp+")) {
548 if (p2 != NULL && is_reg_in_str(p)) {
549 if (extra_reg != NULL) {
550 strncpy(extra_reg, p, p2 - p);
551 extra_reg[p2 - p] = 0;
556 if (!('0' <= *p && *p <= '9'))
563 if (!IS_START(name, "esp+"))
569 if (is_reg_in_str(s)) {
570 if (extra_reg != NULL) {
571 strncpy(extra_reg, s, p - s);
572 extra_reg[p - s] = 0;
577 aerr("%s IDA stackvar not set?\n", __func__);
579 if (!('0' <= *s && *s <= '9')) {
580 aerr("%s IDA stackvar offset not set?\n", __func__);
583 if (s[0] == '0' && s[1] == 'x')
586 if (len < sizeof(buf) - 1) {
587 strncpy(buf, s, len);
590 val = strtol(buf, &endp, 16);
591 if (val == 0 || *endp != 0 || errno != 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], 0);
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 { "bsr", OP_BSR, 2, 2, OPF_DATA|OPF_FLAGS },
1000 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
1001 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
1002 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
1003 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
1004 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
1005 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
1006 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
1007 { "test", OP_TEST, 2, 2, OPF_FLAGS },
1008 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
1009 { "retn", OP_RET, 0, 1, OPF_TAIL },
1010 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
1011 { "jmp", OP_JMP, 1, 1, OPF_JMP },
1012 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
1013 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
1014 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
1015 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
1016 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
1017 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
1018 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
1019 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1020 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1021 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
1022 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
1023 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
1024 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
1025 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1026 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1027 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1028 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1029 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1030 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1031 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1032 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1033 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1034 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1035 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1036 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1037 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1038 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1039 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1040 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1041 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1042 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1043 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1044 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1045 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1046 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1047 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1048 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1049 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1050 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1051 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1052 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1053 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1054 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1055 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1056 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1057 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1058 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1059 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1060 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1061 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1062 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1063 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1064 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1065 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1066 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1067 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1068 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1069 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1070 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1071 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1073 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1074 { "fild", OP_FILD, 1, 1, OPF_FPUSH },
1075 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1076 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1077 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1078 { "fst", OP_FST, 1, 1, 0 },
1079 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1080 { "fist", OP_FIST, 1, 1, 0 },
1081 { "fistp", OP_FIST, 1, 1, OPF_FPOP },
1082 { "fadd", OP_FADD, 0, 2, 0 },
1083 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1084 { "fdiv", OP_FDIV, 0, 2, 0 },
1085 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1086 { "fmul", OP_FMUL, 0, 2, 0 },
1087 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1088 { "fsub", OP_FSUB, 0, 2, 0 },
1089 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1090 { "fdivr", OP_FDIVR, 0, 2, 0 },
1091 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1092 { "fsubr", OP_FSUBR, 0, 2, 0 },
1093 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1094 { "fiadd", OP_FIADD, 1, 1, 0 },
1095 { "fidiv", OP_FIDIV, 1, 1, 0 },
1096 { "fimul", OP_FIMUL, 1, 1, 0 },
1097 { "fisub", OP_FISUB, 1, 1, 0 },
1098 { "fidivr", OP_FIDIVR, 1, 1, 0 },
1099 { "fisubr", OP_FISUBR, 1, 1, 0 },
1100 { "fcom", OP_FCOM, 0, 1, 0 },
1101 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1102 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1103 { "fchs", OP_FCHS, 0, 0, 0 },
1104 { "fcos", OP_FCOS, 0, 0, 0 },
1105 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1106 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1107 { "fsin", OP_FSIN, 0, 0, 0 },
1108 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1109 { "fxch", OP_FXCH, 1, 1, 0 },
1110 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1112 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1113 { "movq", OP_MOV, 2, 2, OPF_DATA },
1114 // pseudo-ops for lib calls
1115 { "_allshl",OPP_ALLSHL },
1116 { "_allshr",OPP_ALLSHR },
1117 { "_ftol", OPP_FTOL },
1118 { "_CIpow", OPP_CIPOW },
1123 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1125 enum opr_lenmod lmod = OPLM_UNSPEC;
1126 int prefix_flags = 0;
1134 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1135 if (IS(words[w], pref_table[i].name)) {
1136 prefix_flags = pref_table[i].flags;
1143 aerr("lone prefix: '%s'\n", words[0]);
1148 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1149 if (IS(words[w], op_table[i].name))
1153 if (i == ARRAY_SIZE(op_table)) {
1155 aerr("unhandled op: '%s'\n", words[0]);
1160 op->op = op_table[i].op;
1161 op->flags = op_table[i].flags | prefix_flags;
1162 op->pfo = op_table[i].pfo;
1163 op->pfo_inv = op_table[i].pfo_inv;
1164 op->regmask_src = op->regmask_dst = 0;
1167 if (op->op == OP_UD2)
1170 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1171 if (opr >= op_table[i].minopr && w >= wordc)
1174 regmask = regmask_ind = 0;
1175 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1176 words, wordc, w, op->flags);
1178 if (opr == 0 && (op->flags & OPF_DATA))
1179 op->regmask_dst = regmask;
1181 op->regmask_src |= regmask;
1182 op->regmask_src |= regmask_ind;
1184 if (op->operand[opr].lmod != OPLM_UNSPEC)
1185 g_func_lmods |= 1 << op->operand[opr].lmod;
1189 aerr("parse_op %s incomplete: %d/%d\n",
1190 words[0], w, wordc);
1193 op->operand_cnt = opr;
1194 if (!strncmp(op_table[i].name, "set", 3))
1195 op->operand[0].lmod = OPLM_BYTE;
1198 // first operand is not dst
1201 op->regmask_src |= op->regmask_dst;
1202 op->regmask_dst = 0;
1205 // first operand is src too
1218 op->regmask_src |= op->regmask_dst;
1223 op->regmask_src |= op->regmask_dst;
1224 op->regmask_dst |= op->regmask_src;
1230 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1231 && op->operand[0].lmod == op->operand[1].lmod
1232 && op->operand[0].reg == op->operand[1].reg
1233 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1235 op->regmask_src = 0;
1238 op->regmask_src |= op->regmask_dst;
1241 // ops with implicit argumets
1243 op->operand_cnt = 2;
1244 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1245 op->regmask_dst = op->regmask_src;
1246 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1250 op->operand_cnt = 2;
1251 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1252 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1258 if (words[op_w][4] == 'b')
1260 else if (words[op_w][4] == 'w')
1262 else if (words[op_w][4] == 'd')
1265 op->regmask_src = 0;
1266 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1267 OPLM_DWORD, &op->regmask_src);
1268 op->regmask_dst = op->regmask_src;
1269 setup_reg_opr(&op->operand[j++], xAX, lmod,
1270 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1271 if (op->flags & OPF_REP) {
1272 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1273 op->regmask_dst |= 1 << xCX;
1275 op->operand_cnt = j;
1280 if (words[op_w][4] == 'b')
1282 else if (words[op_w][4] == 'w')
1284 else if (words[op_w][4] == 'd')
1287 op->regmask_src = 0;
1288 // note: lmod is not correct, don't have where to place it
1289 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1290 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1291 if (op->flags & OPF_REP)
1292 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1293 op->operand_cnt = j;
1294 op->regmask_dst = op->regmask_src;
1298 op->regmask_dst = 1 << xCX;
1301 op->operand_cnt = 2;
1302 op->regmask_src = 1 << xCX;
1303 op->operand[1].type = OPT_REG;
1304 op->operand[1].reg = xCX;
1305 op->operand[1].lmod = OPLM_DWORD;
1309 if (op->operand_cnt == 2) {
1310 if (op->operand[0].type != OPT_REG)
1311 aerr("reg expected\n");
1312 op->regmask_src |= 1 << op->operand[0].reg;
1314 if (op->operand_cnt != 1)
1319 op->regmask_src |= op->regmask_dst;
1320 op->regmask_dst = (1 << xDX) | (1 << xAX);
1321 if (op->operand[0].lmod == OPLM_UNSPEC)
1322 op->operand[0].lmod = OPLM_DWORD;
1327 // we could set up operands for edx:eax, but there is no real need to
1328 // (see is_opr_modified())
1329 op->regmask_src |= op->regmask_dst;
1330 op->regmask_dst = (1 << xDX) | (1 << xAX);
1331 if (op->operand[0].lmod == OPLM_UNSPEC)
1332 op->operand[0].lmod = OPLM_DWORD;
1340 op->regmask_src |= op->regmask_dst;
1341 if (op->operand[1].lmod == OPLM_UNSPEC)
1342 op->operand[1].lmod = OPLM_BYTE;
1347 op->regmask_src |= op->regmask_dst;
1348 if (op->operand[2].lmod == OPLM_UNSPEC)
1349 op->operand[2].lmod = OPLM_BYTE;
1353 op->regmask_src |= op->regmask_dst;
1354 op->regmask_dst = 0;
1355 if (op->operand[0].lmod == OPLM_UNSPEC
1356 && (op->operand[0].type == OPT_CONST
1357 || op->operand[0].type == OPT_OFFSET
1358 || op->operand[0].type == OPT_LABEL))
1359 op->operand[0].lmod = OPLM_DWORD;
1365 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1366 && op->operand[0].lmod == op->operand[1].lmod
1367 && op->operand[0].reg == op->operand[1].reg
1368 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1370 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1371 op->regmask_src = op->regmask_dst = 0;
1376 if (op->operand[0].type == OPT_REG
1377 && op->operand[1].type == OPT_REGMEM)
1380 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1381 if (IS(buf, op->operand[1].name))
1382 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1387 // trashed regs must be explicitly detected later
1388 op->regmask_dst = 0;
1392 op->regmask_dst = (1 << xBP) | (1 << xSP);
1393 op->regmask_src = 1 << xBP;
1398 op->regmask_dst |= mxST0;
1402 op->regmask_dst |= mxST0;
1403 if (IS(words[op_w] + 3, "1"))
1404 op->operand[0].val = X87_CONST_1;
1405 else if (IS(words[op_w] + 3, "ln2"))
1406 op->operand[0].val = X87_CONST_LN2;
1407 else if (IS(words[op_w] + 3, "z"))
1408 op->operand[0].val = X87_CONST_Z;
1415 op->regmask_src |= mxST0;
1424 op->regmask_src |= mxST0;
1425 if (op->operand_cnt == 2)
1426 op->regmask_src |= op->regmask_dst;
1427 else if (op->operand_cnt == 1) {
1428 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1429 op->operand[0].type = OPT_REG;
1430 op->operand[0].lmod = OPLM_QWORD;
1431 op->operand[0].reg = xST0;
1432 op->regmask_dst |= mxST0;
1435 // IDA doesn't use this
1436 aerr("no operands?\n");
1450 op->regmask_src |= mxST0;
1451 op->regmask_dst |= mxST0;
1456 op->regmask_src |= mxST0 | mxST1;
1457 op->regmask_dst |= mxST0;
1465 op->regmask_src |= mxST0;
1472 if (op->operand[0].type == OPT_REG
1473 && op->operand[1].type == OPT_CONST)
1475 struct parsed_opr *op1 = &op->operand[1];
1476 if ((op->op == OP_AND && op1->val == 0)
1479 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1480 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1482 op->regmask_src = 0;
1487 static const char *op_name(struct parsed_op *po)
1489 static char buf[16];
1493 if (po->op == OP_JCC || po->op == OP_SCC) {
1495 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1498 strcpy(p, parsed_flag_op_names[po->pfo]);
1502 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1503 if (op_table[i].op == po->op)
1504 return op_table[i].name;
1510 static const char *dump_op(struct parsed_op *po)
1512 static char out[128];
1519 snprintf(out, sizeof(out), "%s", op_name(po));
1520 for (i = 0; i < po->operand_cnt; i++) {
1524 snprintf(p, sizeof(out) - (p - out),
1525 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1526 po->operand[i].name);
1532 static const char *lmod_type_u(struct parsed_op *po,
1533 enum opr_lenmod lmod)
1545 ferr(po, "invalid lmod: %d\n", lmod);
1546 return "(_invalid_)";
1550 static const char *lmod_cast_u(struct parsed_op *po,
1551 enum opr_lenmod lmod)
1563 ferr(po, "invalid lmod: %d\n", lmod);
1564 return "(_invalid_)";
1568 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1569 enum opr_lenmod lmod)
1581 ferr(po, "invalid lmod: %d\n", lmod);
1582 return "(_invalid_)";
1586 static const char *lmod_cast_s(struct parsed_op *po,
1587 enum opr_lenmod lmod)
1599 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1600 return "(_invalid_)";
1604 static const char *lmod_cast(struct parsed_op *po,
1605 enum opr_lenmod lmod, int is_signed)
1608 lmod_cast_s(po, lmod) :
1609 lmod_cast_u(po, lmod);
1612 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1624 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1629 static const char *opr_name(struct parsed_op *po, int opr_num)
1631 if (opr_num >= po->operand_cnt)
1632 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1633 return po->operand[opr_num].name;
1636 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1638 if (opr_num >= po->operand_cnt)
1639 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1640 if (po->operand[opr_num].type != OPT_CONST)
1641 ferr(po, "opr %d: const expected\n", opr_num);
1642 return po->operand[opr_num].val;
1645 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1647 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1648 ferr(po, "invalid reg: %d\n", popr->reg);
1649 return regs_r32[popr->reg];
1652 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1654 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1656 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1658 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1660 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1665 *is_signed = cast[1] == 's' ? 1 : 0;
1669 static int check_deref_cast(const char *cast, int *bits)
1671 if (IS_START(cast, "*(u8 *)"))
1673 else if (IS_START(cast, "*(u16 *)"))
1675 else if (IS_START(cast, "*(u32 *)"))
1677 else if (IS_START(cast, "*(u64 *)"))
1685 // cast1 is the "final" cast
1686 static const char *simplify_cast(const char *cast1, const char *cast2)
1688 static char buf[256];
1696 if (IS(cast1, cast2))
1699 if (check_simple_cast(cast1, &bits1, &s1) == 0
1700 && check_simple_cast(cast2, &bits2, &s2) == 0)
1705 if (check_simple_cast(cast1, &bits1, &s1) == 0
1706 && check_deref_cast(cast2, &bits2) == 0)
1708 if (bits1 == bits2) {
1709 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1714 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1717 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1721 static const char *simplify_cast_num(const char *cast, unsigned int val)
1723 if (IS(cast, "(u8)") && val < 0x100)
1725 if (IS(cast, "(s8)") && val < 0x80)
1727 if (IS(cast, "(u16)") && val < 0x10000)
1729 if (IS(cast, "(s16)") && val < 0x8000)
1731 if (IS(cast, "(s32)") && val < 0x80000000)
1737 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1746 namelen = strlen(name);
1748 p = strpbrk(name, "+-");
1752 ferr(po, "equ parse failed for '%s'\n", name);
1755 *extra_offs = strtol(p, &endp, 16);
1756 if (*endp != 0 || errno != 0)
1757 ferr(po, "equ parse failed for '%s'\n", name);
1760 for (i = 0; i < g_eqcnt; i++)
1761 if (strncmp(g_eqs[i].name, name, namelen) == 0
1762 && g_eqs[i].name[namelen] == 0)
1766 ferr(po, "unresolved equ name: '%s'\n", name);
1773 static int is_stack_access(struct parsed_op *po,
1774 const struct parsed_opr *popr)
1776 return (parse_stack_el(popr->name, NULL, NULL, 0)
1777 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1778 && IS_START(popr->name, "ebp")));
1781 static void parse_stack_access(struct parsed_op *po,
1782 const char *name, char *ofs_reg, int *offset_out,
1783 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1785 const char *bp_arg = "";
1786 const char *p = NULL;
1787 struct parsed_equ *eq;
1794 if (IS_START(name, "ebp-")
1795 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1798 if (IS_START(p, "0x"))
1801 offset = strtoul(p, &endp, 16);
1804 if (*endp != 0 || errno != 0)
1805 ferr(po, "ebp- parse of '%s' failed\n", name);
1808 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1809 eq = equ_find(po, bp_arg, &offset);
1811 ferr(po, "detected but missing eq\n");
1812 offset += eq->offset;
1815 if (!strncmp(name, "ebp", 3))
1818 // yes it sometimes LEAs ra for compares..
1819 if (!is_lea && ofs_reg[0] == 0
1820 && stack_ra <= offset && offset < stack_ra + 4)
1822 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1825 *offset_out = offset;
1827 *stack_ra_out = stack_ra;
1829 *bp_arg_out = bp_arg;
1832 static int parse_stack_esp_offset(struct parsed_op *po,
1833 const char *name, int *offset_out)
1835 char ofs_reg[16] = { 0, };
1836 struct parsed_equ *eq;
1842 if (strstr(name, "esp") == NULL)
1844 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1845 if (bp_arg == NULL) {
1846 // just plain offset?
1847 if (!IS_START(name, "esp+"))
1850 offset = strtol(name + 4, &endp, 0);
1851 if (endp == NULL || *endp != 0 || errno != 0)
1853 *offset_out = offset;
1857 if (ofs_reg[0] != 0)
1859 eq = equ_find(po, bp_arg, &offset);
1861 ferr(po, "detected but missing eq\n");
1862 offset += eq->offset;
1863 *offset_out = base_val + offset;
1867 static int stack_frame_access(struct parsed_op *po,
1868 struct parsed_opr *popr, char *buf, size_t buf_size,
1869 const char *name, const char *cast, int is_src, int is_lea)
1871 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1872 const char *prefix = "";
1873 const char *bp_arg = NULL;
1874 char ofs_reg[16] = { 0, };
1875 int i, arg_i, arg_s;
1882 if (g_bp_frame && (po->flags & OPF_EBP_S)
1883 && !(po->regmask_src & mxSP))
1884 ferr(po, "stack_frame_access while ebp is scratch\n");
1886 parse_stack_access(po, name, ofs_reg, &offset,
1887 &stack_ra, &bp_arg, is_lea);
1889 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1891 if (offset > stack_ra)
1893 arg_i = (offset - stack_ra - 4) / 4;
1894 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1896 if (g_func_pp->is_vararg
1897 && arg_i == g_func_pp->argc_stack && is_lea)
1899 // should be va_list
1902 snprintf(buf, buf_size, "%sap", cast);
1905 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1906 offset, bp_arg, arg_i);
1908 if (ofs_reg[0] != 0)
1909 ferr(po, "offset reg on arg access?\n");
1911 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1912 if (g_func_pp->arg[i].reg != NULL)
1918 if (i == g_func_pp->argc)
1919 ferr(po, "arg %d not in prototype?\n", arg_i);
1921 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1928 ferr(po, "lea/byte to arg?\n");
1929 if (is_src && (offset & 3) == 0)
1930 snprintf(buf, buf_size, "%sa%d",
1931 simplify_cast(cast, "(u8)"), i + 1);
1933 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1934 cast, offset & 3, i + 1);
1939 ferr(po, "lea/word to arg?\n");
1944 ferr(po, "problematic arg store\n");
1945 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1946 simplify_cast(cast, "*(u16 *)"), i + 1);
1949 ferr(po, "unaligned arg word load\n");
1951 else if (is_src && (offset & 2) == 0)
1952 snprintf(buf, buf_size, "%sa%d",
1953 simplify_cast(cast, "(u16)"), i + 1);
1955 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1956 cast, (offset & 2) ? "HI" : "LO", i + 1);
1968 snprintf(buf, buf_size, "(u32)&a%d + %d",
1971 ferr(po, "unaligned arg store\n");
1973 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1974 snprintf(buf, buf_size, "%s(a%d >> %d)",
1975 prefix, i + 1, (offset & 3) * 8);
1979 snprintf(buf, buf_size, "%s%sa%d",
1980 prefix, is_lea ? "&" : "", i + 1);
1985 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1989 strcat(g_comment, " unaligned");
1992 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
1993 if (tmp_lmod != OPLM_DWORD
1994 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
1995 < lmod_bytes(po, popr->lmod) + (offset & 3))))
1997 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
1998 i + 1, offset, g_func_pp->arg[i].type.name);
2000 // can't check this because msvc likes to reuse
2001 // arg space for scratch..
2002 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
2003 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2007 if (g_stack_fsz == 0)
2008 ferr(po, "stack var access without stackframe\n");
2009 g_stack_frame_used = 1;
2011 sf_ofs = g_stack_fsz + offset;
2012 if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2013 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2023 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2024 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2028 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2029 // known unaligned or possibly unaligned
2030 strcat(g_comment, " unaligned");
2032 prefix = "*(u16 *)&";
2033 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2034 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2037 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2041 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2042 // known unaligned or possibly unaligned
2043 strcat(g_comment, " unaligned");
2045 prefix = "*(u32 *)&";
2046 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2047 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2050 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2054 ferr_assert(po, !(sf_ofs & 7));
2055 ferr_assert(po, ofs_reg[0] == 0);
2056 // only used for x87 int64/float, float sets is_lea
2058 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2060 snprintf(buf, buf_size, "*(s64 *)&sf.q[%d]", sf_ofs / 8);
2064 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2071 static void check_func_pp(struct parsed_op *po,
2072 const struct parsed_proto *pp, const char *pfx)
2074 enum opr_lenmod tmp_lmod;
2078 if (pp->argc_reg != 0) {
2079 if (!g_allow_user_icall && !pp->is_fastcall) {
2080 pp_print(buf, sizeof(buf), pp);
2081 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2083 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2084 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2085 pfx, pp->argc_reg, pp->argc_stack);
2088 // fptrs must use 32bit args, callsite might have no information and
2089 // lack a cast to smaller types, which results in incorrectly masked
2090 // args passed (callee may assume masked args, it does on ARM)
2091 if (!pp->is_osinc) {
2092 for (i = 0; i < pp->argc; i++) {
2093 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2094 if (ret && tmp_lmod != OPLM_DWORD)
2095 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2096 i + 1, pp->arg[i].type.name);
2101 static const char *check_label_read_ref(struct parsed_op *po,
2104 const struct parsed_proto *pp;
2106 pp = proto_parse(g_fhdr, name, 0);
2108 ferr(po, "proto_parse failed for ref '%s'\n", name);
2111 check_func_pp(po, pp, "ref");
2116 static char *out_src_opr(char *buf, size_t buf_size,
2117 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2120 char tmp1[256], tmp2[256];
2129 switch (popr->type) {
2132 ferr(po, "lea from reg?\n");
2134 switch (popr->lmod) {
2136 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2139 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2142 snprintf(buf, buf_size, "%s%s",
2143 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2146 if (popr->name[1] == 'h') // XXX..
2147 snprintf(buf, buf_size, "%s(%s >> 8)",
2148 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2150 snprintf(buf, buf_size, "%s%s",
2151 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2154 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2159 if (is_stack_access(po, popr)) {
2160 stack_frame_access(po, popr, buf, buf_size,
2161 popr->name, cast, 1, is_lea);
2165 strcpy(expr, popr->name);
2166 if (strchr(expr, '[')) {
2167 // special case: '[' can only be left for label[reg] form
2168 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2170 ferr(po, "parse failure for '%s'\n", expr);
2171 if (tmp1[0] == '(') {
2172 // (off_4FFF50+3)[eax]
2173 p = strchr(tmp1 + 1, ')');
2174 if (p == NULL || p[1] != 0)
2175 ferr(po, "parse failure (2) for '%s'\n", expr);
2177 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2179 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2182 // XXX: do we need more parsing?
2184 snprintf(buf, buf_size, "%s", expr);
2188 snprintf(buf, buf_size, "%s(%s)",
2189 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2193 name = check_label_read_ref(po, popr->name);
2194 if (cast[0] == 0 && popr->is_ptr)
2198 snprintf(buf, buf_size, "(u32)&%s", name);
2199 else if (popr->size_lt)
2200 snprintf(buf, buf_size, "%s%s%s%s", cast,
2201 lmod_cast_u_ptr(po, popr->lmod),
2202 popr->is_array ? "" : "&", name);
2204 snprintf(buf, buf_size, "%s%s%s", cast, name,
2205 popr->is_array ? "[0]" : "");
2209 name = check_label_read_ref(po, popr->name);
2213 ferr(po, "lea an offset?\n");
2214 snprintf(buf, buf_size, "%s&%s", cast, name);
2219 ferr(po, "lea from const?\n");
2221 printf_number(tmp1, sizeof(tmp1), popr->val);
2222 if (popr->val == 0 && strchr(cast, '*'))
2223 snprintf(buf, buf_size, "NULL");
2225 snprintf(buf, buf_size, "%s%s",
2226 simplify_cast_num(cast, popr->val), tmp1);
2230 ferr(po, "invalid src type: %d\n", popr->type);
2236 // note: may set is_ptr (we find that out late for ebp frame..)
2237 static char *out_dst_opr(char *buf, size_t buf_size,
2238 struct parsed_op *po, struct parsed_opr *popr)
2240 switch (popr->type) {
2242 switch (popr->lmod) {
2244 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2247 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2251 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2255 if (popr->name[1] == 'h') // XXX..
2256 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2258 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2261 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2266 if (is_stack_access(po, popr)) {
2267 stack_frame_access(po, popr, buf, buf_size,
2268 popr->name, "", 0, 0);
2272 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2275 if (popr->size_mismatch)
2276 snprintf(buf, buf_size, "%s%s%s",
2277 lmod_cast_u_ptr(po, popr->lmod),
2278 popr->is_array ? "" : "&", popr->name);
2280 snprintf(buf, buf_size, "%s%s", popr->name,
2281 popr->is_array ? "[0]" : "");
2285 ferr(po, "invalid dst type: %d\n", popr->type);
2291 static char *out_src_opr_u32(char *buf, size_t buf_size,
2292 struct parsed_op *po, struct parsed_opr *popr)
2294 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2297 static char *out_src_opr_float(char *buf, size_t buf_size,
2298 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2300 const char *cast = NULL;
2303 switch (popr->type) {
2305 if (popr->reg < xST0 || popr->reg > xST7)
2306 ferr(po, "bad reg: %d\n", popr->reg);
2308 if (need_float_stack) {
2309 if (popr->reg == xST0)
2310 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2312 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2316 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2322 switch (popr->lmod) {
2330 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2333 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2334 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2338 ferr(po, "invalid float type: %d\n", popr->type);
2344 static char *out_dst_opr_float(char *buf, size_t buf_size,
2345 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2348 return out_src_opr_float(buf, buf_size, po, popr, need_float_stack);
2351 static void out_test_for_cc(char *buf, size_t buf_size,
2352 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2353 enum opr_lenmod lmod, const char *expr)
2355 const char *cast, *scast;
2357 cast = lmod_cast_u(po, lmod);
2358 scast = lmod_cast_s(po, lmod);
2362 case PFO_BE: // CF==1||ZF==1; CF=0
2363 snprintf(buf, buf_size, "(%s%s %s 0)",
2364 cast, expr, is_inv ? "!=" : "==");
2368 case PFO_L: // SF!=OF; OF=0
2369 snprintf(buf, buf_size, "(%s%s %s 0)",
2370 scast, expr, is_inv ? ">=" : "<");
2373 case PFO_LE: // ZF==1||SF!=OF; OF=0
2374 snprintf(buf, buf_size, "(%s%s %s 0)",
2375 scast, expr, is_inv ? ">" : "<=");
2380 snprintf(buf, buf_size, "(%d)", !!is_inv);
2384 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2388 static void out_cmp_for_cc(char *buf, size_t buf_size,
2389 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2392 const char *cast, *scast, *cast_use;
2393 char buf1[256], buf2[256];
2394 enum opr_lenmod lmod;
2396 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2397 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2398 po->operand[0].lmod, po->operand[1].lmod);
2399 lmod = po->operand[0].lmod;
2401 cast = lmod_cast_u(po, lmod);
2402 scast = lmod_cast_s(po, lmod);
2418 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2421 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2422 if (po->op == OP_DEC)
2423 snprintf(buf2, sizeof(buf2), "1");
2426 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2428 strcat(cast_op2, "-");
2429 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2434 // note: must be unsigned compare
2435 snprintf(buf, buf_size, "(%s %s %s)",
2436 buf1, is_inv ? ">=" : "<", buf2);
2440 snprintf(buf, buf_size, "(%s %s %s)",
2441 buf1, is_inv ? "!=" : "==", buf2);
2445 // note: must be unsigned compare
2446 snprintf(buf, buf_size, "(%s %s %s)",
2447 buf1, is_inv ? ">" : "<=", buf2);
2450 if (is_inv && lmod == OPLM_BYTE
2451 && po->operand[1].type == OPT_CONST
2452 && po->operand[1].val == 0xff)
2454 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2455 snprintf(buf, buf_size, "(0)");
2459 // note: must be signed compare
2461 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2462 scast, buf1, buf2, is_inv ? ">=" : "<");
2466 snprintf(buf, buf_size, "(%s %s %s)",
2467 buf1, is_inv ? ">=" : "<", buf2);
2471 snprintf(buf, buf_size, "(%s %s %s)",
2472 buf1, is_inv ? ">" : "<=", buf2);
2480 static void out_cmp_test(char *buf, size_t buf_size,
2481 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2483 char buf1[256], buf2[256], buf3[256];
2485 if (po->op == OP_TEST) {
2486 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2487 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2490 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2491 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2492 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2494 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2495 po->operand[0].lmod, buf3);
2497 else if (po->op == OP_CMP) {
2498 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2501 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2504 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2505 struct parsed_opr *popr2)
2507 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2508 ferr(po, "missing lmod for both operands\n");
2510 if (popr1->lmod == OPLM_UNSPEC)
2511 popr1->lmod = popr2->lmod;
2512 else if (popr2->lmod == OPLM_UNSPEC)
2513 popr2->lmod = popr1->lmod;
2514 else if (popr1->lmod != popr2->lmod) {
2515 if (popr1->type_from_var) {
2516 popr1->size_mismatch = 1;
2517 if (popr1->lmod < popr2->lmod)
2519 popr1->lmod = popr2->lmod;
2521 else if (popr2->type_from_var) {
2522 popr2->size_mismatch = 1;
2523 if (popr2->lmod < popr1->lmod)
2525 popr2->lmod = popr1->lmod;
2528 ferr(po, "conflicting lmods: %d vs %d\n",
2529 popr1->lmod, popr2->lmod);
2533 static const char *op_to_c(struct parsed_op *po)
2557 ferr(po, "op_to_c was supplied with %d\n", po->op);
2561 // last op in stream - unconditional branch or ret
2562 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2563 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2564 && ops[_i].op != OP_CALL))
2566 #define check_i(po, i) \
2568 ferr(po, "bad " #i ": %d\n", i)
2570 // note: this skips over calls and rm'd stuff assuming they're handled
2571 // so it's intended to use at one of final passes
2572 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2573 int depth, int seen_noreturn, int flags_set)
2575 struct parsed_op *po;
2580 for (; i < opcnt; i++) {
2582 if (po->cc_scratch == magic)
2583 return ret; // already checked
2584 po->cc_scratch = magic;
2586 if (po->flags & OPF_TAIL) {
2587 if (po->op == OP_CALL) {
2588 if (po->pp != NULL && po->pp->is_noreturn)
2597 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2600 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2601 if (po->btj != NULL) {
2603 for (j = 0; j < po->btj->count; j++) {
2604 check_i(po, po->btj->d[j].bt_i);
2605 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2606 depth, seen_noreturn, flags_set);
2608 return ret; // dead end
2613 check_i(po, po->bt_i);
2614 if (po->flags & OPF_CJMP) {
2615 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2616 depth, seen_noreturn, flags_set);
2618 return ret; // dead end
2627 if ((po->op == OP_POP || po->op == OP_PUSH)
2628 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2633 if (po->op == OP_PUSH) {
2636 else if (po->op == OP_POP) {
2637 if (relevant && depth == 0) {
2638 po->flags |= flags_set;
2646 // for noreturn, assume msvc skipped stack cleanup
2647 return seen_noreturn ? 1 : -1;
2650 // scan for 'reg' pop backwards starting from i
2651 // intended to use for register restore search, so other reg
2652 // references are considered an error
2653 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2655 struct parsed_op *po;
2656 struct label_ref *lr;
2659 ops[i].cc_scratch = magic;
2663 if (g_labels[i] != NULL) {
2664 lr = &g_label_refs[i];
2665 for (; lr != NULL; lr = lr->next) {
2666 check_i(&ops[i], lr->i);
2667 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2671 if (i > 0 && LAST_OP(i - 1))
2679 if (ops[i].cc_scratch == magic)
2681 ops[i].cc_scratch = magic;
2684 if (po->op == OP_POP && po->operand[0].reg == reg) {
2685 if (po->flags & (OPF_RMD|OPF_DONE))
2688 po->flags |= set_flags;
2692 // this also covers the case where we reach corresponding push
2693 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2697 // nothing interesting on this path,
2698 // still return ret for something recursive calls could find
2702 static void find_reachable_exits(int i, int opcnt, int magic,
2703 int *exits, int *exit_count)
2705 struct parsed_op *po;
2708 for (; i < opcnt; i++)
2711 if (po->cc_scratch == magic)
2713 po->cc_scratch = magic;
2715 if (po->flags & OPF_TAIL) {
2716 ferr_assert(po, *exit_count < MAX_EXITS);
2717 exits[*exit_count] = i;
2722 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2723 if (po->flags & OPF_RMD)
2726 if (po->btj != NULL) {
2727 for (j = 0; j < po->btj->count; j++) {
2728 check_i(po, po->btj->d[j].bt_i);
2729 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2735 check_i(po, po->bt_i);
2736 if (po->flags & OPF_CJMP)
2737 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2745 // scan for 'reg' pop backwards starting from exits (all paths)
2746 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2748 static int exits[MAX_EXITS];
2749 static int exit_count;
2755 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2757 ferr_assert(&ops[i], exit_count > 0);
2760 for (j = 0; j < exit_count; j++) {
2762 ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2768 if (ops[e].op == OP_CALL && ops[e].pp != NULL
2769 && ops[e].pp->is_noreturn)
2771 // assume stack cleanup was skipped
2780 // scan for one or more pop of push <const>
2781 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2782 int push_i, int is_probe)
2784 struct parsed_op *po;
2785 struct label_ref *lr;
2789 for (; i < opcnt; i++)
2792 if (po->cc_scratch == magic)
2793 return ret; // already checked
2794 po->cc_scratch = magic;
2796 if (po->flags & OPF_JMP) {
2797 if (po->flags & OPF_RMD)
2799 if (po->op == OP_CALL)
2802 if (po->btj != NULL) {
2803 for (j = 0; j < po->btj->count; j++) {
2804 check_i(po, po->btj->d[j].bt_i);
2805 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2813 check_i(po, po->bt_i);
2814 if (po->flags & OPF_CJMP) {
2815 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2826 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2829 if (g_labels[i] != NULL) {
2830 // all refs must be visited
2831 lr = &g_label_refs[i];
2832 for (; lr != NULL; lr = lr->next) {
2834 if (ops[lr->i].cc_scratch != magic)
2837 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2841 if (po->op == OP_POP)
2843 if (po->flags & (OPF_RMD|OPF_DONE))
2847 po->flags |= OPF_DONE;
2848 po->datap = &ops[push_i];
2857 static void scan_for_pop_const(int i, int opcnt, int magic)
2861 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2863 ops[i].flags |= OPF_RMD | OPF_DONE;
2864 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2868 // check if all branch targets within a marked path are also marked
2869 // note: the path checked must not be empty or end with a branch
2870 static int check_path_branches(int opcnt, int magic)
2872 struct parsed_op *po;
2875 for (i = 0; i < opcnt; i++) {
2877 if (po->cc_scratch != magic)
2880 if (po->flags & OPF_JMP) {
2881 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2884 if (po->btj != NULL) {
2885 for (j = 0; j < po->btj->count; j++) {
2886 check_i(po, po->btj->d[j].bt_i);
2887 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2892 check_i(po, po->bt_i);
2893 if (ops[po->bt_i].cc_scratch != magic)
2895 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2903 // scan for multiple pushes for given pop
2904 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2907 int reg = ops[pop_i].operand[0].reg;
2908 struct parsed_op *po;
2909 struct label_ref *lr;
2912 ops[i].cc_scratch = magic;
2916 if (g_labels[i] != NULL) {
2917 lr = &g_label_refs[i];
2918 for (; lr != NULL; lr = lr->next) {
2919 check_i(&ops[i], lr->i);
2920 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2924 if (i > 0 && LAST_OP(i - 1))
2932 if (ops[i].cc_scratch == magic)
2934 ops[i].cc_scratch = magic;
2937 if (po->op == OP_CALL)
2939 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2942 if (po->op == OP_PUSH)
2944 if (po->datap != NULL)
2946 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2947 // leave this case for reg save/restore handlers
2951 po->flags |= OPF_PPUSH | OPF_DONE;
2952 po->datap = &ops[pop_i];
2961 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2963 int magic = i + opcnt * 14;
2966 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2968 ret = check_path_branches(opcnt, magic);
2970 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2971 *regmask_pp |= 1 << ops[i].operand[0].reg;
2972 scan_pushes_for_pop_r(i, magic + 1, i, 0);
2977 static void scan_propagate_df(int i, int opcnt)
2979 struct parsed_op *po = &ops[i];
2982 for (; i < opcnt; i++) {
2984 if (po->flags & OPF_DF)
2985 return; // already resolved
2986 po->flags |= OPF_DF;
2988 if (po->op == OP_CALL)
2989 ferr(po, "call with DF set?\n");
2991 if (po->flags & OPF_JMP) {
2992 if (po->btj != NULL) {
2994 for (j = 0; j < po->btj->count; j++) {
2995 check_i(po, po->btj->d[j].bt_i);
2996 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
3001 if (po->flags & OPF_RMD)
3003 check_i(po, po->bt_i);
3004 if (po->flags & OPF_CJMP)
3005 scan_propagate_df(po->bt_i, opcnt);
3011 if (po->flags & OPF_TAIL)
3014 if (po->op == OP_CLD) {
3015 po->flags |= OPF_RMD | OPF_DONE;
3020 ferr(po, "missing DF clear?\n");
3023 // is operand 'opr' referenced by parsed_op 'po'?
3024 static int is_opr_referenced(const struct parsed_opr *opr,
3025 const struct parsed_op *po)
3029 if (opr->type == OPT_REG) {
3030 mask = po->regmask_dst | po->regmask_src;
3031 if (po->op == OP_CALL)
3032 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3033 if ((1 << opr->reg) & mask)
3039 for (i = 0; i < po->operand_cnt; i++)
3040 if (IS(po->operand[0].name, opr->name))
3046 // is operand 'opr' read by parsed_op 'po'?
3047 static int is_opr_read(const struct parsed_opr *opr,
3048 const struct parsed_op *po)
3050 if (opr->type == OPT_REG) {
3051 if (po->regmask_src & (1 << opr->reg))
3061 // is operand 'opr' modified by parsed_op 'po'?
3062 static int is_opr_modified(const struct parsed_opr *opr,
3063 const struct parsed_op *po)
3067 if (opr->type == OPT_REG) {
3068 if (po->op == OP_CALL) {
3069 mask = po->regmask_dst;
3070 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3071 if (mask & (1 << opr->reg))
3077 if (po->regmask_dst & (1 << opr->reg))
3083 return IS(po->operand[0].name, opr->name);
3086 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3087 static int is_any_opr_modified(const struct parsed_op *po_test,
3088 const struct parsed_op *po, int c_mode)
3093 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3096 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3099 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3102 // in reality, it can wreck any register, but in decompiled C
3103 // version it can only overwrite eax or edx:eax
3104 mask = (1 << xAX) | (1 << xDX);
3108 if (po->op == OP_CALL
3109 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3112 for (i = 0; i < po_test->operand_cnt; i++)
3113 if (IS(po_test->operand[i].name, po->operand[0].name))
3119 // scan for any po_test operand modification in range given
3120 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3123 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3126 for (; i < opcnt; i++) {
3127 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3134 // scan for po_test operand[0] modification in range given
3135 static int scan_for_mod_opr0(struct parsed_op *po_test,
3138 for (; i < opcnt; i++) {
3139 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3146 static int try_resolve_const(int i, const struct parsed_opr *opr,
3147 int magic, unsigned int *val);
3149 static int scan_for_flag_set(int i, int opcnt, int magic,
3150 int *branched, int *setters, int *setter_cnt)
3152 struct label_ref *lr;
3156 if (ops[i].cc_scratch == magic) {
3157 // is this a problem?
3158 //ferr(&ops[i], "%s looped\n", __func__);
3161 ops[i].cc_scratch = magic;
3163 if (g_labels[i] != NULL) {
3166 lr = &g_label_refs[i];
3167 for (; lr->next; lr = lr->next) {
3168 check_i(&ops[i], lr->i);
3169 ret = scan_for_flag_set(lr->i, opcnt, magic,
3170 branched, setters, setter_cnt);
3175 check_i(&ops[i], lr->i);
3176 if (i > 0 && LAST_OP(i - 1)) {
3180 ret = scan_for_flag_set(lr->i, opcnt, magic,
3181 branched, setters, setter_cnt);
3187 if (ops[i].flags & OPF_FLAGS) {
3188 setters[*setter_cnt] = i;
3191 if (ops[i].flags & OPF_REP) {
3192 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3195 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3196 if (ret != 1 || uval == 0) {
3197 // can't treat it as full setter because of ecx=0 case,
3198 // also disallow delayed compare
3207 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3214 // scan back for cdq, if anything modifies edx, fail
3215 static int scan_for_cdq_edx(int i)
3218 if (g_labels[i] != NULL) {
3219 if (g_label_refs[i].next != NULL)
3221 if (i > 0 && LAST_OP(i - 1)) {
3222 i = g_label_refs[i].i;
3229 if (ops[i].op == OP_CDQ)
3232 if (ops[i].regmask_dst & (1 << xDX))
3239 static int scan_for_reg_clear(int i, int reg)
3242 if (g_labels[i] != NULL) {
3243 if (g_label_refs[i].next != NULL)
3245 if (i > 0 && LAST_OP(i - 1)) {
3246 i = g_label_refs[i].i;
3253 if (ops[i].op == OP_XOR
3254 && ops[i].operand[0].lmod == OPLM_DWORD
3255 && ops[i].operand[0].reg == ops[i].operand[1].reg
3256 && ops[i].operand[0].reg == reg)
3259 if (ops[i].regmask_dst & (1 << reg))
3266 static void patch_esp_adjust(struct parsed_op *po, int adj)
3268 ferr_assert(po, po->op == OP_ADD);
3269 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3270 ferr_assert(po, po->operand[1].type == OPT_CONST);
3272 // this is a bit of a hack, but deals with use of
3273 // single adj for multiple calls
3274 po->operand[1].val -= adj;
3275 po->flags |= OPF_RMD;
3276 if (po->operand[1].val == 0)
3277 po->flags |= OPF_DONE;
3278 ferr_assert(po, (int)po->operand[1].val >= 0);
3281 // scan for positive, constant esp adjust
3282 // multipath case is preliminary
3283 static int scan_for_esp_adjust(int i, int opcnt,
3284 int adj_expect, int *adj, int *is_multipath, int do_update)
3286 int adj_expect_unknown = 0;
3287 struct parsed_op *po;
3291 *adj = *is_multipath = 0;
3292 if (adj_expect < 0) {
3293 adj_expect_unknown = 1;
3294 adj_expect = 32 * 4; // enough?
3297 for (; i < opcnt && *adj < adj_expect; i++) {
3298 if (g_labels[i] != NULL)
3302 if (po->flags & OPF_DONE)
3305 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3306 if (po->operand[1].type != OPT_CONST)
3307 ferr(&ops[i], "non-const esp adjust?\n");
3308 *adj += po->operand[1].val;
3310 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3313 patch_esp_adjust(po, adj_expect);
3315 po->flags |= OPF_RMD;
3319 else if (po->op == OP_PUSH) {
3320 //if (first_pop == -1)
3321 // first_pop = -2; // none
3322 *adj -= lmod_bytes(po, po->operand[0].lmod);
3324 else if (po->op == OP_POP) {
3325 if (!(po->flags & OPF_DONE)) {
3326 // seems like msvc only uses 'pop ecx' for stack realignment..
3327 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3329 if (first_pop == -1 && *adj >= 0)
3332 if (do_update && *adj >= 0) {
3333 po->flags |= OPF_RMD;
3335 po->flags |= OPF_DONE | OPF_NOREGS;
3338 *adj += lmod_bytes(po, po->operand[0].lmod);
3339 if (*adj > adj_best)
3342 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3343 if (po->op == OP_JMP && po->btj == NULL) {
3349 if (po->op != OP_CALL)
3351 if (po->operand[0].type != OPT_LABEL)
3353 if (po->pp != NULL && po->pp->is_stdcall)
3355 if (adj_expect_unknown && first_pop >= 0)
3357 // assume it's another cdecl call
3361 if (first_pop >= 0) {
3362 // probably only 'pop ecx' was used
3370 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3372 struct parsed_op *po;
3376 ferr(ops, "%s: followed bad branch?\n", __func__);
3378 for (; i < opcnt; i++) {
3380 if (po->cc_scratch == magic)
3382 po->cc_scratch = magic;
3385 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3386 if (po->btj != NULL) {
3388 for (j = 0; j < po->btj->count; j++)
3389 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3393 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3394 if (!(po->flags & OPF_CJMP))
3397 if (po->flags & OPF_TAIL)
3402 static const struct parsed_proto *try_recover_pp(
3403 struct parsed_op *po, const struct parsed_opr *opr,
3404 int is_call, int *search_instead)
3406 const struct parsed_proto *pp = NULL;
3410 // maybe an arg of g_func?
3411 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3413 char ofs_reg[16] = { 0, };
3414 int arg, arg_s, arg_i;
3421 parse_stack_access(po, opr->name, ofs_reg,
3422 &offset, &stack_ra, NULL, 0);
3423 if (ofs_reg[0] != 0)
3424 ferr(po, "offset reg on arg access?\n");
3425 if (offset <= stack_ra) {
3426 // search who set the stack var instead
3427 if (search_instead != NULL)
3428 *search_instead = 1;
3432 arg_i = (offset - stack_ra - 4) / 4;
3433 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3434 if (g_func_pp->arg[arg].reg != NULL)
3440 if (arg == g_func_pp->argc)
3441 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3443 pp = g_func_pp->arg[arg].pp;
3446 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3447 check_func_pp(po, pp, "icall arg");
3450 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3452 p = strchr(opr->name + 1, '[');
3453 memcpy(buf, opr->name, p - opr->name);
3454 buf[p - opr->name] = 0;
3455 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3457 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3458 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3461 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3464 check_func_pp(po, pp, "reg-fptr ref");
3470 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3471 int magic, const struct parsed_proto **pp_found, int *pp_i,
3474 const struct parsed_proto *pp = NULL;
3475 struct parsed_op *po;
3476 struct label_ref *lr;
3478 ops[i].cc_scratch = magic;
3481 if (g_labels[i] != NULL) {
3482 lr = &g_label_refs[i];
3483 for (; lr != NULL; lr = lr->next) {
3484 check_i(&ops[i], lr->i);
3485 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3487 if (i > 0 && LAST_OP(i - 1))
3495 if (ops[i].cc_scratch == magic)
3497 ops[i].cc_scratch = magic;
3499 if (!(ops[i].flags & OPF_DATA))
3501 if (!is_opr_modified(opr, &ops[i]))
3503 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3504 // most probably trashed by some processing
3509 opr = &ops[i].operand[1];
3510 if (opr->type != OPT_REG)
3514 po = (i >= 0) ? &ops[i] : ops;
3517 // reached the top - can only be an arg-reg
3518 if (opr->type != OPT_REG || g_func_pp == NULL)
3521 for (i = 0; i < g_func_pp->argc; i++) {
3522 if (g_func_pp->arg[i].reg == NULL)
3524 if (IS(opr->name, g_func_pp->arg[i].reg))
3527 if (i == g_func_pp->argc)
3529 pp = g_func_pp->arg[i].pp;
3531 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3532 i + 1, g_func_pp->arg[i].reg);
3533 check_func_pp(po, pp, "icall reg-arg");
3536 pp = try_recover_pp(po, opr, 1, NULL);
3538 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3539 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3540 || (*pp_found)->is_stdcall != pp->is_stdcall
3541 //|| (*pp_found)->is_fptr != pp->is_fptr
3542 || (*pp_found)->argc != pp->argc
3543 || (*pp_found)->argc_reg != pp->argc_reg
3544 || (*pp_found)->argc_stack != pp->argc_stack)
3546 ferr(po, "icall: parsed_proto mismatch\n");
3556 static void add_label_ref(struct label_ref *lr, int op_i)
3558 struct label_ref *lr_new;
3565 lr_new = calloc(1, sizeof(*lr_new));
3567 lr_new->next = lr->next;
3571 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3573 struct parsed_op *po = &ops[i];
3574 struct parsed_data *pd;
3575 char label[NAMELEN], *p;
3578 p = strchr(po->operand[0].name, '[');
3582 len = p - po->operand[0].name;
3583 strncpy(label, po->operand[0].name, len);
3586 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3587 if (IS(g_func_pd[j].label, label)) {
3593 //ferr(po, "label '%s' not parsed?\n", label);
3596 if (pd->type != OPT_OFFSET)
3597 ferr(po, "label '%s' with non-offset data?\n", label);
3599 // find all labels, link
3600 for (j = 0; j < pd->count; j++) {
3601 for (l = 0; l < opcnt; l++) {
3602 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3603 add_label_ref(&g_label_refs[l], i);
3613 static void clear_labels(int count)
3617 for (i = 0; i < count; i++) {
3618 if (g_labels[i] != NULL) {
3625 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3630 for (i = 0; i < pp->argc; i++) {
3631 if (pp->arg[i].reg != NULL) {
3632 reg = char_array_i(regs_r32,
3633 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3635 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3636 pp->arg[i].reg, pp->name);
3637 regmask |= 1 << reg;
3644 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3649 if (pp->has_retreg) {
3650 for (i = 0; i < pp->argc; i++) {
3651 if (pp->arg[i].type.is_retreg) {
3652 reg = char_array_i(regs_r32,
3653 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3654 ferr_assert(ops, reg >= 0);
3655 regmask |= 1 << reg;
3660 if (strstr(pp->ret_type.name, "int64"))
3661 return regmask | (1 << xAX) | (1 << xDX);
3662 if (IS(pp->ret_type.name, "float")
3663 || IS(pp->ret_type.name, "double"))
3665 return regmask | mxST0;
3667 if (strcasecmp(pp->ret_type.name, "void") == 0)
3670 return regmask | mxAX;
3673 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3675 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3676 && memcmp(po1->operand, po2->operand,
3677 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3680 static void resolve_branches_parse_calls(int opcnt)
3682 static const struct {
3686 unsigned int regmask_src;
3687 unsigned int regmask_dst;
3689 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3690 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3691 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3692 // more precise? Wine gets away with just __ftol handler
3693 { "__ftol2", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3694 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3696 const struct parsed_proto *pp_c;
3697 struct parsed_proto *pp;
3698 struct parsed_data *pd;
3699 struct parsed_op *po;
3700 const char *tmpname;
3705 for (i = 0; i < opcnt; i++)
3711 if (po->datap != NULL) {
3712 pp = calloc(1, sizeof(*pp));
3713 my_assert_not(pp, NULL);
3715 ret = parse_protostr(po->datap, pp);
3717 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3723 if (po->op == OP_CALL) {
3728 else if (po->operand[0].type == OPT_LABEL)
3730 tmpname = opr_name(po, 0);
3731 if (IS_START(tmpname, "loc_"))
3732 ferr(po, "call to loc_*\n");
3733 if (IS(tmpname, "__alloca_probe"))
3736 // convert some calls to pseudo-ops
3737 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3738 if (!IS(tmpname, pseudo_ops[l].name))
3741 po->op = pseudo_ops[l].op;
3742 po->operand_cnt = 0;
3743 po->regmask_src = pseudo_ops[l].regmask_src;
3744 po->regmask_dst = pseudo_ops[l].regmask_dst;
3745 po->flags = pseudo_ops[l].flags;
3746 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3749 if (l < ARRAY_SIZE(pseudo_ops))
3752 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3753 if (!g_header_mode && pp_c == NULL)
3754 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3757 pp = proto_clone(pp_c);
3758 my_assert_not(pp, NULL);
3764 check_func_pp(po, pp, "fptr var call");
3765 if (pp->is_noreturn) {
3766 po->flags |= OPF_TAIL;
3767 po->flags &= ~OPF_ATAIL; // most likely...
3774 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3777 if (po->operand[0].type == OPT_REGMEM) {
3778 pd = try_resolve_jumptab(i, opcnt);
3786 for (l = 0; l < opcnt; l++) {
3787 if (g_labels[l] != NULL
3788 && IS(po->operand[0].name, g_labels[l]))
3790 if (l == i + 1 && po->op == OP_JMP) {
3791 // yet another alignment type..
3792 po->flags |= OPF_RMD|OPF_DONE;
3795 add_label_ref(&g_label_refs[l], i);
3801 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3804 if (po->operand[0].type == OPT_LABEL)
3808 ferr(po, "unhandled branch\n");
3812 po->flags |= OPF_TAIL;
3813 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3814 if (prev_op == OP_POP)
3815 po->flags |= OPF_ATAIL;
3816 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3817 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3819 po->flags |= OPF_ATAIL;
3825 static void scan_prologue_epilogue(int opcnt, int *stack_align)
3827 int ecx_push = 0, esp_sub = 0, pusha = 0;
3828 int sandard_epilogue;
3832 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3833 && ops[1].op == OP_MOV
3834 && IS(opr_name(&ops[1], 0), "ebp")
3835 && IS(opr_name(&ops[1], 1), "esp"))
3838 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3839 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3842 if (ops[i].op == OP_PUSHA) {
3843 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3848 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
3849 && ops[i].operand[1].type == OPT_CONST)
3851 l = ops[i].operand[1].val;
3853 if (j == -1 || (l >> j) != -1)
3854 ferr(&ops[i], "unhandled esp align: %x\n", l);
3855 if (stack_align != NULL)
3856 *stack_align = 1 << j;
3857 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3861 if (ops[i].op == OP_SUB && IS(opr_name(&ops[i], 0), "esp")) {
3862 g_stack_fsz = opr_const(&ops[i], 1);
3863 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3867 // another way msvc builds stack frame..
3868 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3870 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3874 // and another way..
3875 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3876 && ops[i].operand[1].type == OPT_CONST
3877 && ops[i + 1].op == OP_CALL
3878 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3880 g_stack_fsz += ops[i].operand[1].val;
3881 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3883 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3890 for (; i < opcnt; i++)
3891 if (ops[i].flags & OPF_TAIL)
3894 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3895 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3901 sandard_epilogue = 0;
3902 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3904 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3905 // the standard epilogue is sometimes even used without a sf
3906 if (ops[j - 1].op == OP_MOV
3907 && IS(opr_name(&ops[j - 1], 0), "esp")
3908 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3909 sandard_epilogue = 1;
3911 else if (ops[j].op == OP_LEAVE)
3913 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3914 sandard_epilogue = 1;
3916 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3917 && ops[i].pp->is_noreturn)
3919 // on noreturn, msvc sometimes cleans stack, sometimes not
3924 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3925 ferr(&ops[j], "'pop ebp' expected\n");
3927 if (g_stack_fsz != 0 || sandard_epilogue) {
3928 if (ops[j].op == OP_LEAVE)
3930 else if (sandard_epilogue) // mov esp, ebp
3932 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3935 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3937 ferr(&ops[j], "esp restore expected\n");
3940 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3941 && IS(opr_name(&ops[j], 0), "ecx"))
3943 ferr(&ops[j], "unexpected ecx pop\n");
3948 if (ops[j].op == OP_POPA)
3949 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3951 ferr(&ops[j], "popa expected\n");
3956 } while (i < opcnt);
3959 ferr(ops, "missing ebp epilogue\n");
3965 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3966 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3972 for (; i < opcnt; i++) {
3973 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3975 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3976 && ops[i].operand[1].type == OPT_CONST)
3978 g_stack_fsz = ops[i].operand[1].val;
3979 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3984 else if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3985 && ops[i].operand[1].type == OPT_CONST
3986 && ops[i + 1].op == OP_CALL
3987 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3989 g_stack_fsz += ops[i].operand[1].val;
3990 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3992 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3999 if (ecx_push && !esp_sub) {
4000 // could actually be args for a call..
4001 for (; i < opcnt; i++)
4002 if (ops[i].op != OP_PUSH)
4005 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4006 const struct parsed_proto *pp;
4007 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4008 j = pp ? pp->argc_stack : 0;
4009 while (i > 0 && j > 0) {
4011 if (ops[i].op == OP_PUSH) {
4012 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4017 ferr(&ops[i], "unhandled prologue\n");
4020 i = g_stack_fsz = ecx_push = 0;
4021 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4022 if (!(ops[i].flags & OPF_RMD))
4032 if (ecx_push || esp_sub)
4037 for (; i < opcnt; i++)
4038 if (ops[i].flags & OPF_TAIL)
4042 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4043 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4050 for (l = 0; l < ecx_push; l++) {
4051 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4053 else if (ops[j].op == OP_ADD
4054 && IS(opr_name(&ops[j], 0), "esp")
4055 && ops[j].operand[1].type == OPT_CONST)
4058 l += ops[j].operand[1].val / 4 - 1;
4063 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4066 if (l != ecx_push) {
4067 if (i < opcnt && ops[i].op == OP_CALL
4068 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4070 // noreturn tailcall with no epilogue
4075 ferr(&ops[j], "epilogue scan failed\n");
4082 if (ops[j].op != OP_ADD
4083 || !IS(opr_name(&ops[j], 0), "esp")
4084 || ops[j].operand[1].type != OPT_CONST)
4086 if (i < opcnt && ops[i].op == OP_CALL
4087 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4089 // noreturn tailcall with no epilogue
4094 ferr(&ops[j], "'add esp' expected\n");
4097 if (ops[j].operand[1].val < g_stack_fsz)
4098 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4100 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4101 if (ops[j].operand[1].val == 0)
4102 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4107 } while (i < opcnt);
4110 ferr(ops, "missing esp epilogue\n");
4114 // find an instruction that changed opr before i op
4115 // *op_i must be set to -1 by the caller
4116 // *is_caller is set to 1 if one source is determined to be g_func arg
4117 // returns 1 if found, *op_i is then set to origin
4118 // returns -1 if multiple origins are found
4119 static int resolve_origin(int i, const struct parsed_opr *opr,
4120 int magic, int *op_i, int *is_caller)
4122 struct label_ref *lr;
4126 if (g_labels[i] != NULL) {
4127 lr = &g_label_refs[i];
4128 for (; lr != NULL; lr = lr->next) {
4129 check_i(&ops[i], lr->i);
4130 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4132 if (i > 0 && LAST_OP(i - 1))
4138 if (is_caller != NULL)
4143 if (ops[i].cc_scratch == magic)
4145 ops[i].cc_scratch = magic;
4147 if (!(ops[i].flags & OPF_DATA))
4149 if (!is_opr_modified(opr, &ops[i]))
4153 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4164 // find an instruction that previously referenced opr
4165 // if multiple results are found - fail
4166 // *op_i must be set to -1 by the caller
4167 // returns 1 if found, *op_i is then set to referencer insn
4168 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4169 int magic, int *op_i)
4171 struct label_ref *lr;
4175 if (g_labels[i] != NULL) {
4176 lr = &g_label_refs[i];
4177 for (; lr != NULL; lr = lr->next) {
4178 check_i(&ops[i], lr->i);
4179 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4181 if (i > 0 && LAST_OP(i - 1))
4189 if (ops[i].cc_scratch == magic)
4191 ops[i].cc_scratch = magic;
4193 if (!is_opr_referenced(opr, &ops[i]))
4204 // adjust datap of all reachable 'op' insns when moving back
4205 // returns 1 if at least 1 op was found
4206 // returns -1 if path without an op was found
4207 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4209 struct label_ref *lr;
4212 if (ops[i].cc_scratch == magic)
4214 ops[i].cc_scratch = magic;
4217 if (g_labels[i] != NULL) {
4218 lr = &g_label_refs[i];
4219 for (; lr != NULL; lr = lr->next) {
4220 check_i(&ops[i], lr->i);
4221 ret |= adjust_prev_op(lr->i, op, magic, datap);
4223 if (i > 0 && LAST_OP(i - 1))
4231 if (ops[i].cc_scratch == magic)
4233 ops[i].cc_scratch = magic;
4235 if (ops[i].op != op)
4238 ops[i].datap = datap;
4243 // find next instruction that reads opr
4244 // *op_i must be set to -1 by the caller
4245 // on return, *op_i is set to first referencer insn
4246 // returns 1 if exactly 1 referencer is found
4247 static int find_next_read(int i, int opcnt,
4248 const struct parsed_opr *opr, int magic, int *op_i)
4250 struct parsed_op *po;
4253 for (; i < opcnt; i++)
4255 if (ops[i].cc_scratch == magic)
4257 ops[i].cc_scratch = magic;
4260 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4261 if (po->btj != NULL) {
4263 for (j = 0; j < po->btj->count; j++) {
4264 check_i(po, po->btj->d[j].bt_i);
4265 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4271 if (po->flags & OPF_RMD)
4273 check_i(po, po->bt_i);
4274 if (po->flags & OPF_CJMP) {
4275 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4284 if (!is_opr_read(opr, po)) {
4286 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4287 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4289 full_opr = po->operand[0].lmod >= opr->lmod;
4291 if (is_opr_modified(opr, po) && full_opr) {
4295 if (po->flags & OPF_TAIL)
4310 // find next instruction that reads opr
4311 // *op_i must be set to -1 by the caller
4312 // on return, *op_i is set to first flag user insn
4313 // returns 1 if exactly 1 flag user is found
4314 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4316 struct parsed_op *po;
4319 for (; i < opcnt; i++)
4321 if (ops[i].cc_scratch == magic)
4323 ops[i].cc_scratch = magic;
4326 if (po->op == OP_CALL)
4328 if (po->flags & OPF_JMP) {
4329 if (po->btj != NULL) {
4331 for (j = 0; j < po->btj->count; j++) {
4332 check_i(po, po->btj->d[j].bt_i);
4333 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4339 if (po->flags & OPF_RMD)
4341 check_i(po, po->bt_i);
4342 if (po->flags & OPF_CJMP)
4349 if (!(po->flags & OPF_CC)) {
4350 if (po->flags & OPF_FLAGS)
4353 if (po->flags & OPF_TAIL)
4369 static int try_resolve_const(int i, const struct parsed_opr *opr,
4370 int magic, unsigned int *val)
4375 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4378 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4381 *val = ops[i].operand[1].val;
4388 static int resolve_used_bits(int i, int opcnt, int reg,
4389 int *mask, int *is_z_check)
4391 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4395 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4399 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4401 fnote(&ops[j], "(first read)\n");
4402 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4405 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4406 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4408 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4409 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4411 *mask = ops[j].operand[1].val;
4412 if (ops[j].operand[0].lmod == OPLM_BYTE
4413 && ops[j].operand[0].name[1] == 'h')
4417 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4420 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4422 *is_z_check = ops[k].pfo == PFO_Z;
4427 static const struct parsed_proto *resolve_deref(int i, int magic,
4428 struct parsed_opr *opr, int level)
4430 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4431 const struct parsed_proto *pp = NULL;
4432 int from_caller = 0;
4441 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4442 if (ret != 2 || len != strlen(opr->name)) {
4443 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4444 if (ret != 1 || len != strlen(opr->name))
4448 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4453 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4457 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4458 && strlen(ops[j].operand[1].name) == 3
4459 && ops[j].operand[0].lmod == OPLM_DWORD
4460 && ops[j].pp == NULL // no hint
4463 // allow one simple dereference (com/directx)
4464 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4465 ops[j].operand[1].name);
4469 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4474 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4477 if (ops[j].pp != NULL) {
4481 else if (ops[j].operand[1].type == OPT_REGMEM) {
4482 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4484 // maybe structure ptr in structure
4485 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4488 else if (ops[j].operand[1].type == OPT_LABEL)
4489 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4490 else if (ops[j].operand[1].type == OPT_REG) {
4493 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4495 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4496 for (k = 0; k < g_func_pp->argc; k++) {
4497 if (g_func_pp->arg[k].reg == NULL)
4499 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4500 pp = g_func_pp->arg[k].pp;
4509 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4511 ferr(&ops[j], "expected struct, got '%s %s'\n",
4512 pp->type.name, pp->name);
4516 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4519 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4520 int *pp_i, int *multi_src)
4522 const struct parsed_proto *pp = NULL;
4523 int search_advice = 0;
4528 switch (ops[i].operand[0].type) {
4530 // try to resolve struct member calls
4531 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4537 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4543 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4551 static struct parsed_proto *process_call_early(int i, int opcnt,
4554 struct parsed_op *po = &ops[i];
4555 struct parsed_proto *pp;
4561 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4565 // look for and make use of esp adjust
4567 if (!pp->is_stdcall && pp->argc_stack > 0)
4568 ret = scan_for_esp_adjust(i + 1, opcnt,
4569 pp->argc_stack * 4, &adj, &multipath, 0);
4571 if (pp->argc_stack > adj / 4)
4575 if (ops[ret].op == OP_POP) {
4576 for (j = 1; j < adj / 4; j++) {
4577 if (ops[ret + j].op != OP_POP
4578 || ops[ret + j].operand[0].reg != xCX)
4590 static struct parsed_proto *process_call(int i, int opcnt)
4592 struct parsed_op *po = &ops[i];
4593 const struct parsed_proto *pp_c;
4594 struct parsed_proto *pp;
4595 const char *tmpname;
4596 int call_i = -1, ref_i = -1;
4597 int adj = 0, multipath = 0;
4600 tmpname = opr_name(po, 0);
4605 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4607 if (!pp_c->is_func && !pp_c->is_fptr)
4608 ferr(po, "call to non-func: %s\n", pp_c->name);
4609 pp = proto_clone(pp_c);
4610 my_assert_not(pp, NULL);
4612 // not resolved just to single func
4615 switch (po->operand[0].type) {
4617 // we resolved this call and no longer need the register
4618 po->regmask_src &= ~(1 << po->operand[0].reg);
4620 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4621 && ops[call_i].operand[1].type == OPT_LABEL)
4623 // no other source users?
4624 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4626 if (ret == 1 && call_i == ref_i) {
4627 // and nothing uses it after us?
4629 find_next_read(i + 1, opcnt, &po->operand[0],
4630 i + opcnt * 11, &ref_i);
4632 // then also don't need the source mov
4633 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4645 pp = calloc(1, sizeof(*pp));
4646 my_assert_not(pp, NULL);
4649 ret = scan_for_esp_adjust(i + 1, opcnt,
4650 -1, &adj, &multipath, 0);
4651 if (ret < 0 || adj < 0) {
4652 if (!g_allow_regfunc)
4653 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4654 pp->is_unresolved = 1;
4658 if (adj > ARRAY_SIZE(pp->arg))
4659 ferr(po, "esp adjust too large: %d\n", adj);
4660 pp->ret_type.name = strdup("int");
4661 pp->argc = pp->argc_stack = adj;
4662 for (arg = 0; arg < pp->argc; arg++)
4663 pp->arg[arg].type.name = strdup("int");
4668 // look for and make use of esp adjust
4671 if (!pp->is_stdcall && pp->argc_stack > 0) {
4672 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4673 ret = scan_for_esp_adjust(i + 1, opcnt,
4674 adj_expect, &adj, &multipath, 0);
4677 if (pp->is_vararg) {
4678 if (adj / 4 < pp->argc_stack) {
4679 fnote(po, "(this call)\n");
4680 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4681 adj, pp->argc_stack * 4);
4683 // modify pp to make it have varargs as normal args
4685 pp->argc += adj / 4 - pp->argc_stack;
4686 for (; arg < pp->argc; arg++) {
4687 pp->arg[arg].type.name = strdup("int");
4690 if (pp->argc > ARRAY_SIZE(pp->arg))
4691 ferr(po, "too many args for '%s'\n", tmpname);
4693 if (pp->argc_stack > adj / 4) {
4694 if (pp->is_noreturn)
4695 // assume no stack adjust was emited
4697 fnote(po, "(this call)\n");
4698 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4699 tmpname, pp->argc_stack * 4, adj);
4702 scan_for_esp_adjust(i + 1, opcnt,
4703 pp->argc_stack * 4, &adj, &multipath, 1);
4705 else if (pp->is_vararg)
4706 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4713 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
4716 struct parsed_op *po;
4722 for (base_arg = 0; base_arg < pp->argc; base_arg++)
4723 if (pp->arg[base_arg].reg == NULL)
4726 for (j = i; j > 0; )
4728 ferr_assert(&ops[j], g_labels[j] == NULL);
4732 ferr_assert(po, po->op != OP_PUSH);
4733 if (po->op == OP_FST)
4735 if (po->operand[0].type != OPT_REGMEM)
4737 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
4740 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
4741 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
4745 arg = base_arg + offset / 4;
4747 po->p_argnum = arg + 1;
4748 ferr_assert(po, pp->arg[arg].datap == NULL);
4749 pp->arg[arg].datap = po;
4750 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
4751 if (regmask_ffca != NULL)
4752 *regmask_ffca |= 1 << arg;
4754 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4755 && po->operand[1].type == OPT_CONST)
4757 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4762 for (arg = base_arg; arg < pp->argc; arg++) {
4763 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
4764 po = pp->arg[arg].datap;
4766 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
4767 if (po->operand[0].lmod == OPLM_QWORD)
4774 static int collect_call_args_early(int i, struct parsed_proto *pp,
4775 int *regmask, int *regmask_ffca)
4777 struct parsed_op *po;
4781 for (arg = 0; arg < pp->argc; arg++)
4782 if (pp->arg[arg].reg == NULL)
4785 // first see if it can be easily done
4786 for (j = i; j > 0 && arg < pp->argc; )
4788 if (g_labels[j] != NULL)
4793 if (po->op == OP_CALL)
4795 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
4797 else if (po->op == OP_POP)
4799 else if (po->flags & OPF_CJMP)
4801 else if (po->op == OP_PUSH) {
4802 if (po->flags & (OPF_FARG|OPF_FARGNR))
4804 if (!g_header_mode) {
4805 ret = scan_for_mod(po, j + 1, i, 1);
4810 if (pp->arg[arg].type.is_va_list)
4814 for (arg++; arg < pp->argc; arg++)
4815 if (pp->arg[arg].reg == NULL)
4818 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4819 && po->operand[1].type == OPT_CONST)
4821 if (po->flags & (OPF_RMD|OPF_DONE))
4823 if (po->operand[1].val != pp->argc_stack * 4)
4824 ferr(po, "unexpected esp adjust: %d\n",
4825 po->operand[1].val * 4);
4826 ferr_assert(po, pp->argc - arg == pp->argc_stack);
4827 return collect_call_args_no_push(i, pp, regmask_ffca);
4835 for (arg = 0; arg < pp->argc; arg++)
4836 if (pp->arg[arg].reg == NULL)
4839 for (j = i; j > 0 && arg < pp->argc; )
4843 if (ops[j].op == OP_PUSH)
4845 ops[j].p_argnext = -1;
4846 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4847 pp->arg[arg].datap = &ops[j];
4849 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
4850 *regmask |= 1 << ops[j].operand[0].reg;
4852 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4853 ops[j].flags &= ~OPF_RSAVE;
4856 for (arg++; arg < pp->argc; arg++)
4857 if (pp->arg[arg].reg == NULL)
4865 static int sync_argnum(struct parsed_op *po, int argnum)
4867 struct parsed_op *po_tmp;
4869 // see if other branches don't have higher argnum
4870 for (po_tmp = po; po_tmp != NULL; ) {
4871 if (argnum < po_tmp->p_argnum)
4872 argnum = po_tmp->p_argnum;
4873 // note: p_argnext is active on current collect_call_args only
4874 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4877 // make all argnums consistent
4878 for (po_tmp = po; po_tmp != NULL; ) {
4879 if (po_tmp->p_argnum != 0)
4880 po_tmp->p_argnum = argnum;
4881 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4887 static int collect_call_args_r(struct parsed_op *po, int i,
4888 struct parsed_proto *pp, int *regmask, int *arg_grp,
4889 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
4891 struct parsed_proto *pp_tmp;
4892 struct parsed_op *po_tmp;
4893 struct label_ref *lr;
4894 int need_to_save_current;
4895 int arg_grp_current = 0;
4896 int save_args_seen = 0;
4903 ferr(po, "dead label encountered\n");
4907 for (; arg < pp->argc; arg++, argnum++)
4908 if (pp->arg[arg].reg == NULL)
4910 magic = (magic & 0xffffff) | (arg << 24);
4912 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4914 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4915 if (ops[j].cc_scratch != magic) {
4916 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4920 // ok: have already been here
4923 ops[j].cc_scratch = magic;
4925 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4926 lr = &g_label_refs[j];
4927 if (lr->next != NULL)
4929 for (; lr->next; lr = lr->next) {
4930 check_i(&ops[j], lr->i);
4931 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4933 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4934 arg, argnum, magic, need_op_saving, may_reuse);
4939 check_i(&ops[j], lr->i);
4940 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4942 if (j > 0 && LAST_OP(j - 1)) {
4943 // follow last branch in reverse
4948 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4949 arg, argnum, magic, need_op_saving, may_reuse);
4955 if (ops[j].op == OP_CALL)
4957 if (pp->is_unresolved)
4962 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
4963 arg, pp->argc, ops[j].operand[0].name);
4964 if (may_reuse && pp_tmp->argc_stack > 0)
4965 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4966 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4968 // esp adjust of 0 means we collected it before
4969 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4970 && (ops[j].operand[1].type != OPT_CONST
4971 || ops[j].operand[1].val != 0))
4973 if (pp->is_unresolved)
4976 fnote(po, "(this call)\n");
4977 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4978 arg, pp->argc, ops[j].operand[1].val);
4980 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4982 if (pp->is_unresolved)
4985 fnote(po, "(this call)\n");
4986 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4988 else if (ops[j].flags & OPF_CJMP)
4990 if (pp->is_unresolved)
4995 else if (ops[j].op == OP_PUSH
4996 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4998 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5001 ops[j].p_argnext = -1;
5002 po_tmp = pp->arg[arg].datap;
5004 ops[j].p_argnext = po_tmp - ops;
5005 pp->arg[arg].datap = &ops[j];
5007 argnum = sync_argnum(&ops[j], argnum);
5009 need_to_save_current = 0;
5011 if (ops[j].operand[0].type == OPT_REG)
5012 reg = ops[j].operand[0].reg;
5014 if (!need_op_saving) {
5015 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5016 need_to_save_current = (ret >= 0);
5018 if (need_op_saving || need_to_save_current) {
5019 // mark this arg as one that needs operand saving
5020 pp->arg[arg].is_saved = 1;
5022 if (save_args_seen & (1 << (argnum - 1))) {
5025 if (arg_grp_current >= MAX_ARG_GRP)
5026 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5030 else if (ops[j].p_argnum == 0)
5031 ops[j].flags |= OPF_RMD;
5033 // some PUSHes are reused by different calls on other branches,
5034 // but that can't happen if we didn't branch, so they
5035 // can be removed from future searches (handles nested calls)
5037 ops[j].flags |= OPF_FARGNR;
5039 ops[j].flags |= OPF_FARG;
5040 ops[j].flags &= ~OPF_RSAVE;
5042 // check for __VALIST
5043 if (!pp->is_unresolved && g_func_pp != NULL
5044 && pp->arg[arg].type.is_va_list)
5047 ret = resolve_origin(j, &ops[j].operand[0],
5048 magic + 1, &k, NULL);
5049 if (ret == 1 && k >= 0)
5051 if (ops[k].op == OP_LEA) {
5052 if (!g_func_pp->is_vararg)
5053 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5056 snprintf(buf, sizeof(buf), "arg_%X",
5057 g_func_pp->argc_stack * 4);
5058 if (strstr(ops[k].operand[1].name, buf)
5059 || strstr(ops[k].operand[1].name, "arglist"))
5061 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5062 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5063 pp->arg[arg].is_saved = 0;
5067 ferr(&ops[k], "va_list arg detection failed\n");
5069 // check for va_list from g_func_pp arg too
5070 else if (ops[k].op == OP_MOV
5071 && is_stack_access(&ops[k], &ops[k].operand[1]))
5073 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5074 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5076 ops[k].flags |= OPF_RMD | OPF_DONE;
5077 ops[j].flags |= OPF_RMD;
5078 ops[j].p_argpass = ret + 1;
5079 pp->arg[arg].is_saved = 0;
5086 if (pp->arg[arg].is_saved) {
5087 ops[j].flags &= ~OPF_RMD;
5088 ops[j].p_argnum = argnum;
5091 // tracking reg usage
5093 *regmask |= 1 << reg;
5097 if (!pp->is_unresolved) {
5099 for (; arg < pp->argc; arg++, argnum++)
5100 if (pp->arg[arg].reg == NULL)
5103 magic = (magic & 0xffffff) | (arg << 24);
5106 if (ops[j].p_arggrp > arg_grp_current) {
5108 arg_grp_current = ops[j].p_arggrp;
5110 if (ops[j].p_argnum > 0)
5111 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5114 if (arg < pp->argc) {
5115 ferr(po, "arg collect failed for '%s': %d/%d\n",
5116 pp->name, arg, pp->argc);
5120 if (arg_grp_current > *arg_grp)
5121 *arg_grp = arg_grp_current;
5126 static int collect_call_args(struct parsed_op *po, int i,
5127 struct parsed_proto *pp, int *regmask, int magic)
5129 // arg group is for cases when pushes for
5130 // multiple funcs are going on
5131 struct parsed_op *po_tmp;
5136 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5142 // propagate arg_grp
5143 for (a = 0; a < pp->argc; a++) {
5144 if (pp->arg[a].reg != NULL)
5147 po_tmp = pp->arg[a].datap;
5148 while (po_tmp != NULL) {
5149 po_tmp->p_arggrp = arg_grp;
5150 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5155 if (pp->is_unresolved) {
5157 pp->argc_stack += ret;
5158 for (a = 0; a < pp->argc; a++)
5159 if (pp->arg[a].type.name == NULL)
5160 pp->arg[a].type.name = strdup("int");
5166 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5167 int regmask_now, int *regmask,
5168 int regmask_save_now, int *regmask_save,
5169 int *regmask_init, int regmask_arg)
5171 struct parsed_op *po;
5179 for (; i < opcnt; i++)
5182 if (cbits[i >> 3] & (1 << (i & 7)))
5184 cbits[i >> 3] |= (1 << (i & 7));
5186 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5187 if (po->flags & (OPF_RMD|OPF_DONE))
5189 if (po->btj != NULL) {
5190 for (j = 0; j < po->btj->count; j++) {
5191 check_i(po, po->btj->d[j].bt_i);
5192 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5193 regmask_now, regmask, regmask_save_now, regmask_save,
5194 regmask_init, regmask_arg);
5199 check_i(po, po->bt_i);
5200 if (po->flags & OPF_CJMP)
5201 reg_use_pass(po->bt_i, opcnt, cbits,
5202 regmask_now, regmask, regmask_save_now, regmask_save,
5203 regmask_init, regmask_arg);
5209 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5210 && !g_func_pp->is_userstack
5211 && po->operand[0].type == OPT_REG)
5213 reg = po->operand[0].reg;
5214 ferr_assert(po, reg >= 0);
5217 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5218 if (regmask_now & (1 << reg)) {
5219 already_saved = regmask_save_now & (1 << reg);
5220 flags_set = OPF_RSAVE | OPF_DONE;
5223 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5225 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5226 reg, 0, 0, flags_set);
5229 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5231 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5236 ferr_assert(po, !already_saved);
5237 po->flags |= flags_set;
5239 if (regmask_now & (1 << reg)) {
5240 regmask_save_now |= (1 << reg);
5241 *regmask_save |= regmask_save_now;
5246 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5247 reg = po->operand[0].reg;
5248 ferr_assert(po, reg >= 0);
5250 if (regmask_save_now & (1 << reg))
5251 regmask_save_now &= ~(1 << reg);
5253 regmask_now &= ~(1 << reg);
5256 else if (po->op == OP_CALL) {
5257 if ((po->regmask_dst & (1 << xAX))
5258 && !(po->regmask_dst & (1 << xDX)))
5260 if (po->flags & OPF_TAIL)
5261 // don't need eax, will do "return f();" or "f(); return;"
5262 po->regmask_dst &= ~(1 << xAX);
5264 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5266 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5269 po->regmask_dst &= ~(1 << xAX);
5273 // not "full stack" mode and have something in stack
5274 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5275 ferr(po, "float stack is not empty on func call\n");
5278 if (po->flags & OPF_NOREGS)
5281 // if incomplete register is used, clear it on init to avoid
5282 // later use of uninitialized upper part in some situations
5283 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5284 && po->operand[0].lmod != OPLM_DWORD)
5286 reg = po->operand[0].reg;
5287 ferr_assert(po, reg >= 0);
5289 if (!(regmask_now & (1 << reg)))
5290 *regmask_init |= 1 << reg;
5293 regmask_op = po->regmask_src | po->regmask_dst;
5295 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5296 regmask_new &= ~(1 << xSP);
5297 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5298 regmask_new &= ~(1 << xBP);
5300 if (regmask_new != 0)
5301 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5303 if (regmask_op & (1 << xBP)) {
5304 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5305 if (po->regmask_dst & (1 << xBP))
5306 // compiler decided to drop bp frame and use ebp as scratch
5307 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5309 regmask_op &= ~(1 << xBP);
5313 if (po->flags & OPF_FPUSH) {
5314 if (regmask_now & mxST1)
5315 regmask_now |= mxSTa; // switch to "full stack" mode
5316 if (regmask_now & mxSTa)
5317 po->flags |= OPF_FSHIFT;
5318 if (!(regmask_now & mxST7_2)) {
5320 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5324 regmask_now |= regmask_op;
5325 *regmask |= regmask_now;
5328 if (po->flags & OPF_FPOP) {
5329 if ((regmask_now & mxSTa) == 0)
5330 ferr(po, "float pop on empty stack?\n");
5331 if (regmask_now & (mxST7_2 | mxST1))
5332 po->flags |= OPF_FSHIFT;
5333 if (!(regmask_now & mxST7_2)) {
5335 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5339 if (po->flags & OPF_TAIL) {
5340 if (!(regmask_now & mxST7_2)) {
5341 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5342 if (!(regmask_now & mxST0))
5343 ferr(po, "no st0 on float return, mask: %x\n",
5346 else if (regmask_now & mxST1_0)
5347 ferr(po, "float regs on tail: %x\n", regmask_now);
5350 // there is support for "conditional tailcall", sort of
5351 if (!(po->flags & OPF_CC))
5357 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5361 for (i = 0; i < pp->argc; i++)
5362 if (pp->arg[i].reg == NULL)
5366 memmove(&pp->arg[i + 1], &pp->arg[i],
5367 sizeof(pp->arg[0]) * pp->argc_stack);
5368 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5369 pp->arg[i].reg = strdup(reg);
5370 pp->arg[i].type.name = strdup("int");
5375 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5376 int *pfomask, const char *dst_opr_text)
5378 if (*pfomask & (1 << PFO_Z)) {
5379 fprintf(fout, "\n cond_z = (%s%s == 0);",
5380 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5381 *pfomask &= ~(1 << PFO_Z);
5385 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5386 int *pfomask, const char *dst_opr_text)
5388 if (*pfomask & (1 << PFO_S)) {
5389 fprintf(fout, "\n cond_s = (%s%s < 0);",
5390 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5391 *pfomask &= ~(1 << PFO_S);
5395 static void output_std_flags(FILE *fout, struct parsed_op *po,
5396 int *pfomask, const char *dst_opr_text)
5398 output_std_flag_z(fout, po, pfomask, dst_opr_text);
5399 output_std_flag_s(fout, po, pfomask, dst_opr_text);
5403 OPP_FORCE_NORETURN = (1 << 0),
5404 OPP_SIMPLE_ARGS = (1 << 1),
5405 OPP_ALIGN = (1 << 2),
5408 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5411 const char *cconv = "";
5413 if (pp->is_fastcall)
5414 cconv = "__fastcall ";
5415 else if (pp->is_stdcall && pp->argc_reg == 0)
5416 cconv = "__stdcall ";
5418 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5420 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5421 fprintf(fout, "noreturn ");
5424 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5429 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5433 output_pp_attrs(fout, pp, flags);
5436 fprintf(fout, "%s", pp->name);
5441 for (i = 0; i < pp->argc; i++) {
5443 fprintf(fout, ", ");
5444 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5445 && !(flags & OPP_SIMPLE_ARGS))
5448 output_pp(fout, pp->arg[i].pp, 0);
5450 else if (pp->arg[i].type.is_retreg) {
5451 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5454 fprintf(fout, "%s", pp->arg[i].type.name);
5456 fprintf(fout, " a%d", i + 1);
5459 if (pp->is_vararg) {
5461 fprintf(fout, ", ");
5462 fprintf(fout, "...");
5467 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5473 snprintf(buf1, sizeof(buf1), "%d", grp);
5474 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5479 static void gen_x_cleanup(int opcnt);
5481 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5483 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5484 struct parsed_opr *last_arith_dst = NULL;
5485 char buf1[256], buf2[256], buf3[256], cast[64];
5486 struct parsed_proto *pp, *pp_tmp;
5487 struct parsed_data *pd;
5488 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5489 unsigned char cbits[MAX_OPS / 8];
5490 const char *float_type;
5491 const char *float_st0;
5492 const char *float_st1;
5493 int need_float_stack = 0;
5494 int need_float_sw = 0; // status word
5495 int need_tmp_var = 0;
5499 int label_pending = 0;
5500 int need_double = 0;
5501 int stack_align = 0;
5502 int regmask_save = 0; // used regs saved/restored in this func
5503 int regmask_arg; // regs from this function args (fastcall, etc)
5504 int regmask_ret; // regs needed on ret
5505 int regmask_now; // temp
5506 int regmask_init = 0; // regs that need zero initialization
5507 int regmask_pp = 0; // regs used in complex push-pop graph
5508 int regmask_ffca = 0; // float function call args
5509 int regmask = 0; // used regs
5519 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5520 g_stack_frame_used = 0;
5521 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5522 regmask_init = g_regmask_init;
5524 g_func_pp = proto_parse(fhdr, funcn, 0);
5525 if (g_func_pp == NULL)
5526 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5528 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5529 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5532 // - resolve all branches
5533 // - parse calls with labels
5534 resolve_branches_parse_calls(opcnt);
5537 // - handle ebp/esp frame, remove ops related to it
5538 scan_prologue_epilogue(opcnt, &stack_align);
5541 // - remove dead labels
5542 // - set regs needed at ret
5543 for (i = 0; i < opcnt; i++)
5545 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5550 if (ops[i].op == OP_RET)
5551 ops[i].regmask_src |= regmask_ret;
5555 // - process trivial calls
5556 for (i = 0; i < opcnt; i++)
5559 if (po->flags & (OPF_RMD|OPF_DONE))
5562 if (po->op == OP_CALL)
5564 pp = process_call_early(i, opcnt, &j);
5566 if (!(po->flags & OPF_ATAIL)) {
5567 // since we know the args, try to collect them
5568 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5576 // commit esp adjust
5577 if (ops[j].op != OP_POP)
5578 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5580 for (l = 0; l < pp->argc_stack; l++)
5581 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5585 if (strstr(pp->ret_type.name, "int64"))
5588 po->flags |= OPF_DONE;
5594 // - process calls, stage 2
5595 // - handle some push/pop pairs
5596 // - scan for STD/CLD, propagate DF
5597 // - try to resolve needed x87 status word bits
5598 for (i = 0; i < opcnt; i++)
5603 if (po->flags & OPF_RMD)
5606 if (po->op == OP_CALL)
5608 if (!(po->flags & OPF_DONE)) {
5609 pp = process_call(i, opcnt);
5611 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5612 // since we know the args, collect them
5613 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5615 // for unresolved, collect after other passes
5619 ferr_assert(po, pp != NULL);
5621 po->regmask_src |= get_pp_arg_regmask_src(pp);
5622 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5624 if (po->regmask_dst & mxST0)
5625 po->flags |= OPF_FPUSH;
5627 if (strstr(pp->ret_type.name, "int64"))
5633 if (po->flags & OPF_DONE)
5638 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
5639 && po->operand[0].type == OPT_CONST)
5641 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5646 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5650 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5651 scan_propagate_df(i + 1, opcnt);
5656 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
5657 ferr(po, "TODO: fnstsw to mem\n");
5658 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
5660 ferr(po, "fnstsw resolve failed\n");
5661 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
5662 (void *)(long)(mask | (z_check << 16)));
5664 ferr(po, "failed to find fcom: %d\n", ret);
5673 // - find POPs for PUSHes, rm both
5674 // - scan for all used registers
5675 memset(cbits, 0, sizeof(cbits));
5676 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5677 0, ®mask_save, ®mask_init, regmask_arg);
5679 need_float_stack = !!(regmask & mxST7_2);
5682 // - find flag set ops for their users
5683 // - do unresolved calls
5684 // - declare indirect functions
5685 // - other op specific processing
5686 for (i = 0; i < opcnt; i++)
5689 if (po->flags & (OPF_RMD|OPF_DONE))
5692 if (po->flags & OPF_CC)
5694 int setters[16], cnt = 0, branched = 0;
5696 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
5697 &branched, setters, &cnt);
5698 if (ret < 0 || cnt <= 0)
5699 ferr(po, "unable to trace flag setter(s)\n");
5700 if (cnt > ARRAY_SIZE(setters))
5701 ferr(po, "too many flag setters\n");
5703 for (j = 0; j < cnt; j++)
5705 tmp_op = &ops[setters[j]]; // flag setter
5708 // to get nicer code, we try to delay test and cmp;
5709 // if we can't because of operand modification, or if we
5710 // have arith op, or branch, make it calculate flags explicitly
5711 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5713 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5714 pfomask = 1 << po->pfo;
5716 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5717 pfomask = 1 << po->pfo;
5720 // see if we'll be able to handle based on op result
5721 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5722 && po->pfo != PFO_Z && po->pfo != PFO_S
5723 && po->pfo != PFO_P)
5725 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5727 pfomask = 1 << po->pfo;
5730 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5731 propagate_lmod(tmp_op, &tmp_op->operand[0],
5732 &tmp_op->operand[1]);
5733 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5738 tmp_op->pfomask |= pfomask;
5739 cond_vars |= pfomask;
5741 // note: may overwrite, currently not a problem
5745 if (po->op == OP_RCL || po->op == OP_RCR
5746 || po->op == OP_ADC || po->op == OP_SBB)
5747 cond_vars |= 1 << PFO_C;
5753 cond_vars |= 1 << PFO_Z;
5757 if (po->operand[0].lmod == OPLM_DWORD)
5762 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
5767 // note: resolved non-reg calls are OPF_DONE already
5769 ferr_assert(po, pp != NULL);
5771 if (pp->is_unresolved) {
5772 int regmask_stack = 0;
5773 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5775 // this is pretty rough guess:
5776 // see ecx and edx were pushed (and not their saved versions)
5777 for (arg = 0; arg < pp->argc; arg++) {
5778 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
5781 tmp_op = pp->arg[arg].datap;
5783 ferr(po, "parsed_op missing for arg%d\n", arg);
5784 if (tmp_op->operand[0].type == OPT_REG)
5785 regmask_stack |= 1 << tmp_op->operand[0].reg;
5788 if (!((regmask_stack & (1 << xCX))
5789 && (regmask_stack & (1 << xDX))))
5791 if (pp->argc_stack != 0
5792 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5794 pp_insert_reg_arg(pp, "ecx");
5795 pp->is_fastcall = 1;
5796 regmask_init |= 1 << xCX;
5797 regmask |= 1 << xCX;
5799 if (pp->argc_stack != 0
5800 || ((regmask | regmask_arg) & (1 << xDX)))
5802 pp_insert_reg_arg(pp, "edx");
5803 regmask_init |= 1 << xDX;
5804 regmask |= 1 << xDX;
5808 // note: __cdecl doesn't fall into is_unresolved category
5809 if (pp->argc_stack > 0)
5815 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
5817 // <var> = offset <something>
5818 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5819 && !IS_START(po->operand[1].name, "off_"))
5821 if (!po->operand[0].pp->is_fptr)
5822 ferr(po, "%s not declared as fptr when it should be\n",
5823 po->operand[0].name);
5824 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5825 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5826 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5827 fnote(po, "var: %s\n", buf1);
5828 fnote(po, "func: %s\n", buf2);
5829 ferr(po, "^ mismatch\n");
5837 if (po->operand[0].lmod == OPLM_DWORD) {
5838 // 32bit division is common, look for it
5839 if (po->op == OP_DIV)
5840 ret = scan_for_reg_clear(i, xDX);
5842 ret = scan_for_cdq_edx(i);
5844 po->flags |= OPF_32BIT;
5853 po->flags |= OPF_RMD | OPF_DONE;
5863 if (po->operand[0].lmod == OPLM_QWORD)
5873 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5875 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5877 po->flags |= OPF_32BIT;
5885 // this might need it's own pass...
5886 if (po->op != OP_FST && po->p_argnum > 0)
5887 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
5889 // correct for "full stack" mode late enable
5890 if ((po->flags & (OPF_PPUSH|OPF_FPOP)) && need_float_stack)
5891 po->flags |= OPF_FSHIFT;
5894 float_type = need_double ? "double" : "float";
5895 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
5896 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
5898 // output starts here
5900 // define userstack size
5901 if (g_func_pp->is_userstack) {
5902 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5903 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5904 fprintf(fout, "#endif\n");
5907 // the function itself
5908 ferr_assert(ops, !g_func_pp->is_fptr);
5909 output_pp(fout, g_func_pp,
5910 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5911 fprintf(fout, "\n{\n");
5913 // declare indirect functions
5914 for (i = 0; i < opcnt; i++) {
5916 if (po->flags & OPF_RMD)
5919 if (po->op == OP_CALL) {
5922 ferr(po, "NULL pp\n");
5924 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5925 if (pp->name[0] != 0) {
5926 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5927 memcpy(pp->name, "i_", 2);
5929 // might be declared already
5931 for (j = 0; j < i; j++) {
5932 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5933 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5943 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5946 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5947 fprintf(fout, ";\n");
5952 // output LUTs/jumptables
5953 for (i = 0; i < g_func_pd_cnt; i++) {
5955 fprintf(fout, " static const ");
5956 if (pd->type == OPT_OFFSET) {
5957 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5959 for (j = 0; j < pd->count; j++) {
5961 fprintf(fout, ", ");
5962 fprintf(fout, "&&%s", pd->d[j].u.label);
5966 fprintf(fout, "%s %s[] =\n { ",
5967 lmod_type_u(ops, pd->lmod), pd->label);
5969 for (j = 0; j < pd->count; j++) {
5971 fprintf(fout, ", ");
5972 fprintf(fout, "%u", pd->d[j].u.val);
5975 fprintf(fout, " };\n");
5979 // declare stack frame, va_arg
5981 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5982 if (g_func_lmods & (1 << OPLM_WORD))
5983 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5984 if (g_func_lmods & (1 << OPLM_BYTE))
5985 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5986 if (g_func_lmods & (1 << OPLM_QWORD))
5987 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5988 if (stack_align > 8)
5989 ferr(ops, "unhandled stack align of %d\n", stack_align);
5990 else if (stack_align == 8)
5991 fprintf(fout, " u64 align;");
5992 fprintf(fout, " } sf;\n");
5996 if (g_func_pp->is_userstack) {
5997 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5998 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6002 if (g_func_pp->is_vararg) {
6003 fprintf(fout, " va_list ap;\n");
6007 // declare arg-registers
6008 for (i = 0; i < g_func_pp->argc; i++) {
6009 if (g_func_pp->arg[i].reg != NULL) {
6010 reg = char_array_i(regs_r32,
6011 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6012 if (regmask & (1 << reg)) {
6013 if (g_func_pp->arg[i].type.is_retreg)
6014 fprintf(fout, " u32 %s = *r_%s;\n",
6015 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6017 fprintf(fout, " u32 %s = (u32)a%d;\n",
6018 g_func_pp->arg[i].reg, i + 1);
6021 if (g_func_pp->arg[i].type.is_retreg)
6022 ferr(ops, "retreg '%s' is unused?\n",
6023 g_func_pp->arg[i].reg);
6024 fprintf(fout, " // %s = a%d; // unused\n",
6025 g_func_pp->arg[i].reg, i + 1);
6031 // declare normal registers
6032 regmask_now = regmask & ~regmask_arg;
6033 regmask_now &= ~(1 << xSP);
6034 if (regmask_now & 0x00ff) {
6035 for (reg = 0; reg < 8; reg++) {
6036 if (regmask_now & (1 << reg)) {
6037 fprintf(fout, " u32 %s", regs_r32[reg]);
6038 if (regmask_init & (1 << reg))
6039 fprintf(fout, " = 0");
6040 fprintf(fout, ";\n");
6046 if (regmask_now & 0xff00) {
6047 for (reg = 8; reg < 16; reg++) {
6048 if (regmask_now & (1 << reg)) {
6049 fprintf(fout, " mmxr %s", regs_r32[reg]);
6050 if (regmask_init & (1 << reg))
6051 fprintf(fout, " = { 0, }");
6052 fprintf(fout, ";\n");
6058 if (need_float_stack) {
6059 fprintf(fout, " %s f_st[8];\n", float_type);
6060 fprintf(fout, " int f_stp = 0;\n");
6064 if (regmask_now & 0xff0000) {
6065 for (reg = 16; reg < 24; reg++) {
6066 if (regmask_now & (1 << reg)) {
6067 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6068 if (regmask_init & (1 << reg))
6069 fprintf(fout, " = 0");
6070 fprintf(fout, ";\n");
6077 if (need_float_sw) {
6078 fprintf(fout, " u16 f_sw;\n");
6083 for (reg = 0; reg < 8; reg++) {
6084 if (regmask_save & (1 << reg)) {
6085 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6091 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6092 if (save_arg_vars[i] == 0)
6094 for (reg = 0; reg < 32; reg++) {
6095 if (save_arg_vars[i] & (1 << reg)) {
6096 fprintf(fout, " u32 %s;\n",
6097 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6104 for (reg = 0; reg < 32; reg++) {
6105 if (regmask_ffca & (1 << reg)) {
6106 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6112 // declare push-pop temporaries
6114 for (reg = 0; reg < 8; reg++) {
6115 if (regmask_pp & (1 << reg)) {
6116 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6123 for (i = 0; i < 8; i++) {
6124 if (cond_vars & (1 << i)) {
6125 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6132 fprintf(fout, " u32 tmp;\n");
6137 fprintf(fout, " u64 tmp64;\n");
6142 fprintf(fout, "\n");
6144 // do stack clear, if needed
6145 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6147 if (g_stack_clear_len != 0) {
6148 if (g_stack_clear_len <= 4) {
6149 for (i = 0; i < g_stack_clear_len; i++)
6150 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6151 fprintf(fout, "0;\n");
6154 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6155 g_stack_clear_start, g_stack_clear_len * 4);
6159 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6162 if (g_func_pp->is_vararg) {
6163 if (g_func_pp->argc_stack == 0)
6164 ferr(ops, "vararg func without stack args?\n");
6165 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6169 for (i = 0; i < opcnt; i++)
6171 if (g_labels[i] != NULL) {
6172 fprintf(fout, "\n%s:\n", g_labels[i]);
6175 delayed_flag_op = NULL;
6176 last_arith_dst = NULL;
6180 if (po->flags & OPF_RMD)
6185 #define assert_operand_cnt(n_) \
6186 if (po->operand_cnt != n_) \
6187 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6189 // conditional/flag using op?
6190 if (po->flags & OPF_CC)
6196 // we go through all this trouble to avoid using parsed_flag_op,
6197 // which makes generated code much nicer
6198 if (delayed_flag_op != NULL)
6200 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6201 po->pfo, po->pfo_inv);
6204 else if (last_arith_dst != NULL
6205 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6206 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6209 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6210 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6211 last_arith_dst->lmod, buf3);
6214 else if (tmp_op != NULL) {
6215 // use preprocessed flag calc results
6216 if (!(tmp_op->pfomask & (1 << po->pfo)))
6217 ferr(po, "not prepared for pfo %d\n", po->pfo);
6219 // note: pfo_inv was not yet applied
6220 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6221 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6224 ferr(po, "all methods of finding comparison failed\n");
6227 if (po->flags & OPF_JMP) {
6228 fprintf(fout, " if %s", buf1);
6230 else if (po->op == OP_RCL || po->op == OP_RCR
6231 || po->op == OP_ADC || po->op == OP_SBB)
6234 fprintf(fout, " cond_%s = %s;\n",
6235 parsed_flag_op_names[po->pfo], buf1);
6237 else if (po->flags & OPF_DATA) { // SETcc
6238 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6239 fprintf(fout, " %s = %s;", buf2, buf1);
6242 ferr(po, "unhandled conditional op\n");
6246 pfomask = po->pfomask;
6251 assert_operand_cnt(2);
6252 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6253 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6254 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6255 fprintf(fout, " %s = %s;", buf1,
6256 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6261 assert_operand_cnt(2);
6262 po->operand[1].lmod = OPLM_DWORD; // always
6263 fprintf(fout, " %s = %s;",
6264 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6265 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6270 assert_operand_cnt(2);
6271 fprintf(fout, " %s = %s;",
6272 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6273 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6277 assert_operand_cnt(2);
6278 switch (po->operand[1].lmod) {
6280 strcpy(buf3, "(s8)");
6283 strcpy(buf3, "(s16)");
6286 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6288 fprintf(fout, " %s = %s;",
6289 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6290 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6295 assert_operand_cnt(2);
6296 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6297 fprintf(fout, " tmp = %s;",
6298 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6299 fprintf(fout, " %s = %s;",
6300 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6301 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6302 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6303 fprintf(fout, " %s = %stmp;",
6304 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6305 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6306 snprintf(g_comment, sizeof(g_comment), "xchg");
6310 assert_operand_cnt(1);
6311 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6312 fprintf(fout, " %s = ~%s;", buf1, buf1);
6316 assert_operand_cnt(2);
6317 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6318 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6319 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6320 strcpy(g_comment, "xlat");
6324 assert_operand_cnt(2);
6325 fprintf(fout, " %s = (s32)%s >> 31;",
6326 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6327 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6328 strcpy(g_comment, "cdq");
6332 assert_operand_cnt(1);
6333 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6334 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6338 if (po->flags & OPF_REP) {
6339 assert_operand_cnt(3);
6344 assert_operand_cnt(2);
6345 fprintf(fout, " %s = %sesi; esi %c= %d;",
6346 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6347 lmod_cast_u_ptr(po, po->operand[1].lmod),
6348 (po->flags & OPF_DF) ? '-' : '+',
6349 lmod_bytes(po, po->operand[1].lmod));
6350 strcpy(g_comment, "lods");
6355 if (po->flags & OPF_REP) {
6356 assert_operand_cnt(3);
6357 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6358 (po->flags & OPF_DF) ? '-' : '+',
6359 lmod_bytes(po, po->operand[1].lmod));
6360 fprintf(fout, " %sedi = eax;",
6361 lmod_cast_u_ptr(po, po->operand[1].lmod));
6362 strcpy(g_comment, "rep stos");
6365 assert_operand_cnt(2);
6366 fprintf(fout, " %sedi = eax; edi %c= %d;",
6367 lmod_cast_u_ptr(po, po->operand[1].lmod),
6368 (po->flags & OPF_DF) ? '-' : '+',
6369 lmod_bytes(po, po->operand[1].lmod));
6370 strcpy(g_comment, "stos");
6375 j = lmod_bytes(po, po->operand[0].lmod);
6376 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6377 l = (po->flags & OPF_DF) ? '-' : '+';
6378 if (po->flags & OPF_REP) {
6379 assert_operand_cnt(3);
6381 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6384 " %sedi = %sesi;", buf1, buf1);
6385 strcpy(g_comment, "rep movs");
6388 assert_operand_cnt(2);
6389 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6390 buf1, buf1, l, j, l, j);
6391 strcpy(g_comment, "movs");
6396 // repe ~ repeat while ZF=1
6397 j = lmod_bytes(po, po->operand[0].lmod);
6398 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6399 l = (po->flags & OPF_DF) ? '-' : '+';
6400 if (po->flags & OPF_REP) {
6401 assert_operand_cnt(3);
6403 " while (ecx != 0) {\n");
6404 if (pfomask & (1 << PFO_C)) {
6407 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6408 pfomask &= ~(1 << PFO_C);
6411 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6412 buf1, buf1, l, j, l, j);
6415 " if (cond_z %s 0) break;\n",
6416 (po->flags & OPF_REPZ) ? "==" : "!=");
6419 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6420 (po->flags & OPF_REPZ) ? "e" : "ne");
6423 assert_operand_cnt(2);
6425 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6426 buf1, buf1, l, j, l, j);
6427 strcpy(g_comment, "cmps");
6429 pfomask &= ~(1 << PFO_Z);
6430 last_arith_dst = NULL;
6431 delayed_flag_op = NULL;
6435 // only does ZF (for now)
6436 // repe ~ repeat while ZF=1
6437 j = lmod_bytes(po, po->operand[1].lmod);
6438 l = (po->flags & OPF_DF) ? '-' : '+';
6439 if (po->flags & OPF_REP) {
6440 assert_operand_cnt(3);
6442 " while (ecx != 0) {\n");
6444 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6445 lmod_cast_u(po, po->operand[1].lmod),
6446 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6449 " if (cond_z %s 0) break;\n",
6450 (po->flags & OPF_REPZ) ? "==" : "!=");
6453 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6454 (po->flags & OPF_REPZ) ? "e" : "ne");
6457 assert_operand_cnt(2);
6458 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6459 lmod_cast_u(po, po->operand[1].lmod),
6460 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6461 strcpy(g_comment, "scas");
6463 pfomask &= ~(1 << PFO_Z);
6464 last_arith_dst = NULL;
6465 delayed_flag_op = NULL;
6468 // arithmetic w/flags
6470 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6471 goto dualop_arith_const;
6472 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6476 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6477 if (po->operand[1].type == OPT_CONST) {
6478 j = lmod_bytes(po, po->operand[0].lmod);
6479 if (((1ull << j * 8) - 1) == po->operand[1].val)
6480 goto dualop_arith_const;
6485 assert_operand_cnt(2);
6486 fprintf(fout, " %s %s= %s;",
6487 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6489 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6490 output_std_flags(fout, po, &pfomask, buf1);
6491 last_arith_dst = &po->operand[0];
6492 delayed_flag_op = NULL;
6496 // and 0, or ~0 used instead mov
6497 assert_operand_cnt(2);
6498 fprintf(fout, " %s = %s;",
6499 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6500 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6501 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6502 output_std_flags(fout, po, &pfomask, buf1);
6503 last_arith_dst = &po->operand[0];
6504 delayed_flag_op = NULL;
6509 assert_operand_cnt(2);
6510 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6511 if (pfomask & (1 << PFO_C)) {
6512 if (po->operand[1].type == OPT_CONST) {
6513 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6514 j = po->operand[1].val;
6517 if (po->op == OP_SHL)
6521 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6525 ferr(po, "zero shift?\n");
6529 pfomask &= ~(1 << PFO_C);
6531 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6532 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6533 if (po->operand[1].type != OPT_CONST)
6534 fprintf(fout, " & 0x1f");
6536 output_std_flags(fout, po, &pfomask, buf1);
6537 last_arith_dst = &po->operand[0];
6538 delayed_flag_op = NULL;
6542 assert_operand_cnt(2);
6543 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6544 fprintf(fout, " %s = %s%s >> %s;", buf1,
6545 lmod_cast_s(po, po->operand[0].lmod), buf1,
6546 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6547 output_std_flags(fout, po, &pfomask, buf1);
6548 last_arith_dst = &po->operand[0];
6549 delayed_flag_op = NULL;
6554 assert_operand_cnt(3);
6555 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6556 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6557 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6558 if (po->operand[2].type != OPT_CONST) {
6559 // no handling for "undefined" case, hopefully not needed
6560 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6563 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6564 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6565 if (po->op == OP_SHLD) {
6566 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6567 buf1, buf3, buf1, buf2, l, buf3);
6568 strcpy(g_comment, "shld");
6571 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6572 buf1, buf3, buf1, buf2, l, buf3);
6573 strcpy(g_comment, "shrd");
6575 output_std_flags(fout, po, &pfomask, buf1);
6576 last_arith_dst = &po->operand[0];
6577 delayed_flag_op = NULL;
6582 assert_operand_cnt(2);
6583 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6584 if (po->operand[1].type == OPT_CONST) {
6585 j = po->operand[1].val;
6586 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6587 fprintf(fout, po->op == OP_ROL ?
6588 " %s = (%s << %d) | (%s >> %d);" :
6589 " %s = (%s >> %d) | (%s << %d);",
6590 buf1, buf1, j, buf1,
6591 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6595 output_std_flags(fout, po, &pfomask, buf1);
6596 last_arith_dst = &po->operand[0];
6597 delayed_flag_op = NULL;
6602 assert_operand_cnt(2);
6603 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6604 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6605 if (po->operand[1].type == OPT_CONST) {
6606 j = po->operand[1].val % l;
6608 ferr(po, "zero rotate\n");
6609 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6610 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6611 if (po->op == OP_RCL) {
6613 " %s = (%s << %d) | (cond_c << %d)",
6614 buf1, buf1, j, j - 1);
6616 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6620 " %s = (%s >> %d) | (cond_c << %d)",
6621 buf1, buf1, j, l - j);
6623 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6625 fprintf(fout, ";\n");
6626 fprintf(fout, " cond_c = tmp;");
6630 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6631 output_std_flags(fout, po, &pfomask, buf1);
6632 last_arith_dst = &po->operand[0];
6633 delayed_flag_op = NULL;
6637 assert_operand_cnt(2);
6638 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6639 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6640 // special case for XOR
6641 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
6642 for (j = 0; j <= PFO_LE; j++) {
6643 if (pfomask & (1 << j)) {
6644 fprintf(fout, " cond_%s = %d;\n",
6645 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
6646 pfomask &= ~(1 << j);
6649 fprintf(fout, " %s = 0;",
6650 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6651 last_arith_dst = &po->operand[0];
6652 delayed_flag_op = NULL;
6658 assert_operand_cnt(2);
6659 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6660 if (pfomask & (1 << PFO_C)) {
6661 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6662 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6663 if (po->operand[0].lmod == OPLM_DWORD) {
6664 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6665 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6666 fprintf(fout, " %s = (u32)tmp64;",
6667 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6668 strcat(g_comment, " add64");
6671 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6672 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6673 fprintf(fout, " %s += %s;",
6674 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6677 pfomask &= ~(1 << PFO_C);
6678 output_std_flags(fout, po, &pfomask, buf1);
6679 last_arith_dst = &po->operand[0];
6680 delayed_flag_op = NULL;
6683 if (pfomask & (1 << PFO_LE)) {
6684 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
6685 fprintf(fout, " cond_%s = %s;\n",
6686 parsed_flag_op_names[PFO_LE], buf1);
6687 pfomask &= ~(1 << PFO_LE);
6692 assert_operand_cnt(2);
6693 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6694 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6695 for (j = 0; j <= PFO_LE; j++) {
6696 if (!(pfomask & (1 << j)))
6698 if (j == PFO_Z || j == PFO_S)
6701 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6702 fprintf(fout, " cond_%s = %s;\n",
6703 parsed_flag_op_names[j], buf1);
6704 pfomask &= ~(1 << j);
6711 assert_operand_cnt(2);
6712 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6713 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6714 if (po->op == OP_SBB
6715 && IS(po->operand[0].name, po->operand[1].name))
6717 // avoid use of unitialized var
6718 fprintf(fout, " %s = -cond_c;", buf1);
6719 // carry remains what it was
6720 pfomask &= ~(1 << PFO_C);
6723 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6724 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6726 output_std_flags(fout, po, &pfomask, buf1);
6727 last_arith_dst = &po->operand[0];
6728 delayed_flag_op = NULL;
6733 // on SKL, if src is 0, dst is left unchanged
6734 assert_operand_cnt(2);
6735 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6736 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6737 output_std_flag_z(fout, po, &pfomask, buf2);
6738 if (po->op == OP_BSF)
6739 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
6741 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
6742 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
6743 last_arith_dst = &po->operand[0];
6744 delayed_flag_op = NULL;
6745 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
6749 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6750 for (j = 0; j <= PFO_LE; j++) {
6751 if (!(pfomask & (1 << j)))
6753 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6756 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6757 fprintf(fout, " cond_%s = %s;\n",
6758 parsed_flag_op_names[j], buf1);
6759 pfomask &= ~(1 << j);
6765 if (pfomask & (1 << PFO_C))
6766 // carry is unaffected by inc/dec.. wtf?
6767 ferr(po, "carry propagation needed\n");
6769 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6770 if (po->operand[0].type == OPT_REG) {
6771 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6772 fprintf(fout, " %s%s;", buf1, buf2);
6775 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6776 fprintf(fout, " %s %s= 1;", buf1, buf2);
6778 output_std_flags(fout, po, &pfomask, buf1);
6779 last_arith_dst = &po->operand[0];
6780 delayed_flag_op = NULL;
6784 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6785 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6786 fprintf(fout, " %s = -%s%s;", buf1,
6787 lmod_cast_s(po, po->operand[0].lmod), buf2);
6788 last_arith_dst = &po->operand[0];
6789 delayed_flag_op = NULL;
6790 if (pfomask & PFOB_C) {
6791 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6794 output_std_flags(fout, po, &pfomask, buf1);
6798 if (po->operand_cnt == 2) {
6799 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6802 if (po->operand_cnt == 3)
6803 ferr(po, "TODO imul3\n");
6806 assert_operand_cnt(1);
6807 switch (po->operand[0].lmod) {
6809 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6810 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6811 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6812 fprintf(fout, " edx = tmp64 >> 32;\n");
6813 fprintf(fout, " eax = tmp64;");
6816 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6817 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6818 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6822 ferr(po, "TODO: unhandled mul type\n");
6825 last_arith_dst = NULL;
6826 delayed_flag_op = NULL;
6831 assert_operand_cnt(1);
6832 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6833 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6834 po->op == OP_IDIV));
6835 switch (po->operand[0].lmod) {
6837 if (po->flags & OPF_32BIT)
6838 snprintf(buf2, sizeof(buf2), "%seax", cast);
6840 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6841 snprintf(buf2, sizeof(buf2), "%stmp64",
6842 (po->op == OP_IDIV) ? "(s64)" : "");
6844 if (po->operand[0].type == OPT_REG
6845 && po->operand[0].reg == xDX)
6847 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6848 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6851 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6852 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6856 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6857 snprintf(buf2, sizeof(buf2), "%stmp",
6858 (po->op == OP_IDIV) ? "(s32)" : "");
6859 if (po->operand[0].type == OPT_REG
6860 && po->operand[0].reg == xDX)
6862 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6864 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6868 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6870 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6873 strcat(g_comment, " div16");
6876 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6878 last_arith_dst = NULL;
6879 delayed_flag_op = NULL;
6884 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6886 for (j = 0; j < 8; j++) {
6887 if (pfomask & (1 << j)) {
6888 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6889 fprintf(fout, " cond_%s = %s;",
6890 parsed_flag_op_names[j], buf1);
6897 last_arith_dst = NULL;
6898 delayed_flag_op = po;
6902 // SETcc - should already be handled
6905 // note: we reuse OP_Jcc for SETcc, only flags differ
6907 fprintf(fout, "\n goto %s;", po->operand[0].name);
6911 fprintf(fout, " if (ecx == 0)\n");
6912 fprintf(fout, " goto %s;", po->operand[0].name);
6913 strcat(g_comment, " jecxz");
6917 fprintf(fout, " if (--ecx != 0)\n");
6918 fprintf(fout, " goto %s;", po->operand[0].name);
6919 strcat(g_comment, " loop");
6923 assert_operand_cnt(1);
6924 last_arith_dst = NULL;
6925 delayed_flag_op = NULL;
6927 if (po->operand[0].type == OPT_REGMEM) {
6928 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6931 ferr(po, "parse failure for jmp '%s'\n",
6932 po->operand[0].name);
6933 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6936 else if (po->operand[0].type != OPT_LABEL)
6937 ferr(po, "unhandled jmp type\n");
6939 fprintf(fout, " goto %s;", po->operand[0].name);
6943 assert_operand_cnt(1);
6945 my_assert_not(pp, NULL);
6948 if (po->flags & OPF_CC) {
6949 // we treat conditional branch to another func
6950 // (yes such code exists..) as conditional tailcall
6952 fprintf(fout, " {\n");
6955 if (pp->is_fptr && !pp->is_arg) {
6956 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6957 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6959 if (pp->is_unresolved)
6960 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6961 buf3, asmfn, po->asmln, pp->name);
6964 fprintf(fout, "%s", buf3);
6965 if (strstr(pp->ret_type.name, "int64")) {
6966 if (po->flags & OPF_TAIL)
6967 ferr(po, "int64 and tail?\n");
6968 fprintf(fout, "tmp64 = ");
6970 else if (!IS(pp->ret_type.name, "void")) {
6971 if (po->flags & OPF_TAIL) {
6972 if (regmask_ret & mxAX) {
6973 fprintf(fout, "return ");
6974 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6975 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6977 else if (regmask_ret & mxST0)
6978 ferr(po, "float tailcall\n");
6980 else if (po->regmask_dst & mxAX) {
6981 fprintf(fout, "eax = ");
6982 if (pp->ret_type.is_ptr)
6983 fprintf(fout, "(u32)");
6985 else if (po->regmask_dst & mxST0) {
6986 ferr_assert(po, po->flags & OPF_FPUSH);
6987 if (need_float_stack)
6988 fprintf(fout, "f_st[--f_stp & 7] = ");
6990 fprintf(fout, "f_st0 = ");
6994 if (pp->name[0] == 0)
6995 ferr(po, "missing pp->name\n");
6996 fprintf(fout, "%s%s(", pp->name,
6997 pp->has_structarg ? "_sa" : "");
6999 if (po->flags & OPF_ATAIL) {
7001 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7002 check_compat |= pp->argc_stack > 0;
7004 && (pp->argc_stack != g_func_pp->argc_stack
7005 || pp->is_stdcall != g_func_pp->is_stdcall))
7006 ferr(po, "incompatible arg-reuse tailcall\n");
7007 if (g_func_pp->has_retreg)
7008 ferr(po, "TODO: retreg+tailcall\n");
7010 for (arg = j = 0; arg < pp->argc; arg++) {
7012 fprintf(fout, ", ");
7015 if (pp->arg[arg].type.is_ptr)
7016 snprintf(cast, sizeof(cast), "(%s)",
7017 pp->arg[arg].type.name);
7019 if (pp->arg[arg].reg != NULL) {
7020 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7024 for (; j < g_func_pp->argc; j++)
7025 if (g_func_pp->arg[j].reg == NULL)
7027 fprintf(fout, "%sa%d", cast, j + 1);
7032 for (arg = 0; arg < pp->argc; arg++) {
7034 fprintf(fout, ", ");
7037 if (pp->arg[arg].type.is_ptr)
7038 snprintf(cast, sizeof(cast), "(%s)",
7039 pp->arg[arg].type.name);
7041 if (pp->arg[arg].reg != NULL) {
7042 if (pp->arg[arg].type.is_retreg)
7043 fprintf(fout, "&%s", pp->arg[arg].reg);
7044 else if (IS(pp->arg[arg].reg, "ebp")
7045 && g_bp_frame && !(po->flags & OPF_EBP_S))
7047 // rare special case
7048 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7049 strcat(g_comment, " bp_ref");
7052 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7057 tmp_op = pp->arg[arg].datap;
7059 ferr(po, "parsed_op missing for arg%d\n", arg);
7061 if (tmp_op->flags & OPF_VAPUSH) {
7062 fprintf(fout, "ap");
7064 else if (tmp_op->op == OP_FST) {
7065 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7066 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7069 else if (tmp_op->p_argpass != 0) {
7070 fprintf(fout, "a%d", tmp_op->p_argpass);
7072 else if (pp->arg[arg].is_saved) {
7073 ferr_assert(po, tmp_op->p_argnum > 0);
7074 fprintf(fout, "%s%s", cast,
7075 saved_arg_name(buf1, sizeof(buf1),
7076 tmp_op->p_arggrp, tmp_op->p_argnum));
7080 out_src_opr(buf1, sizeof(buf1),
7081 tmp_op, &tmp_op->operand[0], cast, 0));
7085 fprintf(fout, ");");
7087 if (strstr(pp->ret_type.name, "int64")) {
7088 fprintf(fout, "\n");
7089 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7090 fprintf(fout, "%seax = tmp64;", buf3);
7093 if (pp->is_unresolved) {
7094 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7096 strcat(g_comment, buf2);
7099 if (po->flags & OPF_TAIL) {
7101 if (i == opcnt - 1 || pp->is_noreturn)
7103 else if (IS(pp->ret_type.name, "void"))
7105 else if (!(regmask_ret & (1 << xAX)))
7107 // else already handled as 'return f()'
7110 fprintf(fout, "\n%sreturn;", buf3);
7111 strcat(g_comment, " ^ tailcall");
7114 strcat(g_comment, " tailcall");
7116 if ((regmask_ret & (1 << xAX))
7117 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7119 ferr(po, "int func -> void func tailcall?\n");
7122 if (pp->is_noreturn)
7123 strcat(g_comment, " noreturn");
7124 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7125 strcat(g_comment, " argframe");
7126 if (po->flags & OPF_CC)
7127 strcat(g_comment, " cond");
7129 if (po->flags & OPF_CC)
7130 fprintf(fout, "\n }");
7132 delayed_flag_op = NULL;
7133 last_arith_dst = NULL;
7137 if (g_func_pp->is_vararg)
7138 fprintf(fout, " va_end(ap);\n");
7139 if (g_func_pp->has_retreg) {
7140 for (arg = 0; arg < g_func_pp->argc; arg++)
7141 if (g_func_pp->arg[arg].type.is_retreg)
7142 fprintf(fout, " *r_%s = %s;\n",
7143 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7146 if (regmask_ret & mxST0) {
7147 fprintf(fout, " return %s;", float_st0);
7149 else if (!(regmask_ret & mxAX)) {
7150 if (i != opcnt - 1 || label_pending)
7151 fprintf(fout, " return;");
7153 else if (g_func_pp->ret_type.is_ptr) {
7154 fprintf(fout, " return (%s)eax;",
7155 g_func_pp->ret_type.name);
7157 else if (IS(g_func_pp->ret_type.name, "__int64"))
7158 fprintf(fout, " return ((u64)edx << 32) | eax;");
7160 fprintf(fout, " return eax;");
7162 last_arith_dst = NULL;
7163 delayed_flag_op = NULL;
7167 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7168 if (po->p_argnum != 0) {
7169 // special case - saved func arg
7170 fprintf(fout, " %s = %s;",
7171 saved_arg_name(buf2, sizeof(buf2),
7172 po->p_arggrp, po->p_argnum), buf1);
7175 else if (po->flags & OPF_RSAVE) {
7176 fprintf(fout, " s_%s = %s;", buf1, buf1);
7179 else if (po->flags & OPF_PPUSH) {
7181 ferr_assert(po, tmp_op != NULL);
7182 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7183 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7186 else if (g_func_pp->is_userstack) {
7187 fprintf(fout, " *(--esp) = %s;", buf1);
7190 if (!(g_ida_func_attr & IDAFA_NORETURN))
7191 ferr(po, "stray push encountered\n");
7196 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7197 if (po->flags & OPF_RSAVE) {
7198 fprintf(fout, " %s = s_%s;", buf1, buf1);
7201 else if (po->flags & OPF_PPUSH) {
7202 // push/pop graph / non-const
7203 ferr_assert(po, po->datap == NULL);
7204 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7207 else if (po->datap != NULL) {
7210 fprintf(fout, " %s = %s;", buf1,
7211 out_src_opr(buf2, sizeof(buf2),
7212 tmp_op, &tmp_op->operand[0],
7213 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7216 else if (g_func_pp->is_userstack) {
7217 fprintf(fout, " %s = *esp++;", buf1);
7221 ferr(po, "stray pop encountered\n");
7231 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7232 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7233 po->op == OPP_ALLSHL ? "<<" : ">>");
7234 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7235 strcat(g_comment, po->op == OPP_ALLSHL
7236 ? " allshl" : " allshr");
7241 if (need_float_stack) {
7242 out_src_opr_float(buf1, sizeof(buf1),
7243 po, &po->operand[0], 1);
7244 if (po->regmask_src & mxSTa) {
7245 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7249 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7252 if (po->flags & OPF_FSHIFT)
7253 fprintf(fout, " f_st1 = f_st0;");
7254 if (po->operand[0].type == OPT_REG
7255 && po->operand[0].reg == xST0)
7257 strcat(g_comment, " fld st");
7260 fprintf(fout, " f_st0 = %s;",
7261 out_src_opr_float(buf1, sizeof(buf1),
7262 po, &po->operand[0], 0));
7264 strcat(g_comment, " fld");
7268 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7269 lmod_cast(po, po->operand[0].lmod, 1), 0);
7270 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7271 if (need_float_stack) {
7272 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7275 if (po->flags & OPF_FSHIFT)
7276 fprintf(fout, " f_st1 = f_st0;");
7277 fprintf(fout, " f_st0 = %s;", buf2);
7279 strcat(g_comment, " fild");
7283 if (need_float_stack)
7284 fprintf(fout, " f_st[--f_stp & 7] = ");
7286 if (po->flags & OPF_FSHIFT)
7287 fprintf(fout, " f_st1 = f_st0;");
7288 fprintf(fout, " f_st0 = ");
7290 switch (po->operand[0].val) {
7291 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7292 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
7293 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7294 default: ferr(po, "TODO\n"); break;
7299 if (po->flags & OPF_FARG) {
7300 // store to stack as func arg
7301 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7305 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7307 dead_dst = po->operand[0].type == OPT_REG
7308 && po->operand[0].reg == xST0;
7311 fprintf(fout, " %s = %s;", buf1, float_st0);
7312 if (po->flags & OPF_FSHIFT) {
7313 if (need_float_stack)
7314 fprintf(fout, " f_stp++;");
7316 fprintf(fout, " f_st0 = f_st1;");
7318 if (dead_dst && !(po->flags & OPF_FSHIFT))
7321 strcat(g_comment, " fst");
7325 fprintf(fout, " %s = %s%s;",
7326 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7327 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7328 if (po->flags & OPF_FSHIFT) {
7329 if (need_float_stack)
7330 fprintf(fout, " f_stp++;");
7332 fprintf(fout, " f_st0 = f_st1;");
7334 strcat(g_comment, " fist");
7341 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7343 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7345 dead_dst = (po->flags & OPF_FPOP)
7346 && po->operand[0].type == OPT_REG
7347 && po->operand[0].reg == xST0;
7349 case OP_FADD: j = '+'; break;
7350 case OP_FDIV: j = '/'; break;
7351 case OP_FMUL: j = '*'; break;
7352 case OP_FSUB: j = '-'; break;
7353 default: j = 'x'; break;
7355 if (need_float_stack) {
7357 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7358 if (po->flags & OPF_FSHIFT)
7359 fprintf(fout, " f_stp++;");
7362 if (po->flags & OPF_FSHIFT) {
7363 // note: assumes only 2 regs handled
7365 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7367 fprintf(fout, " f_st0 = f_st1;");
7370 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7372 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7377 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7379 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7381 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7383 dead_dst = (po->flags & OPF_FPOP)
7384 && po->operand[0].type == OPT_REG
7385 && po->operand[0].reg == xST0;
7386 j = po->op == OP_FDIVR ? '/' : '-';
7387 if (need_float_stack) {
7389 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7390 if (po->flags & OPF_FSHIFT)
7391 fprintf(fout, " f_stp++;");
7394 if (po->flags & OPF_FSHIFT) {
7396 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7398 fprintf(fout, " f_st0 = f_st1;");
7401 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7403 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7411 case OP_FIADD: j = '+'; break;
7412 case OP_FIDIV: j = '/'; break;
7413 case OP_FIMUL: j = '*'; break;
7414 case OP_FISUB: j = '-'; break;
7415 default: j = 'x'; break;
7417 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7419 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7420 lmod_cast(po, po->operand[0].lmod, 1), 0));
7425 fprintf(fout, " %s = %s %c %s;", float_st0,
7426 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7428 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7433 ferr_assert(po, po->datap != NULL);
7434 mask = (long)po->datap & 0xffff;
7435 z_check = ((long)po->datap >> 16) & 1;
7436 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7438 if (mask == 0x0100) { // C0 -> <
7439 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7442 else if (mask == 0x4000) { // C3 -> =
7443 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7446 else if (mask == 0x4100) { // C3, C0
7448 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7450 strcat(g_comment, " z_chk_det");
7453 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7454 "(%s < %s ? 0x0100 : 0);",
7455 float_st0, buf1, float_st0, buf1);
7459 ferr(po, "unhandled sw mask: %x\n", mask);
7460 if (po->flags & OPF_FSHIFT) {
7461 if (need_float_stack)
7462 fprintf(fout, " f_stp++;");
7464 fprintf(fout, " f_st0 = f_st1;");
7470 fprintf(fout, " %s = f_sw;",
7471 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7475 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7479 fprintf(fout, " %s = cos%s(%s);", float_st0,
7480 need_double ? "" : "f", float_st0);
7484 if (need_float_stack) {
7485 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7486 need_double ? "" : "f", float_st1, float_st0);
7487 fprintf(fout, " f_stp++;");
7490 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7491 need_double ? "" : "f");
7496 if (need_float_stack) {
7497 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7498 float_st1, need_double ? "" : "f", float_st0);
7499 fprintf(fout, " f_stp++;");
7502 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7503 need_double ? "" : "f");
7505 strcat(g_comment, " fyl2x");
7509 fprintf(fout, " %s = sin%s(%s);", float_st0,
7510 need_double ? "" : "f", float_st0);
7514 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7515 need_double ? "" : "f", float_st0);
7519 dead_dst = po->operand[0].type == OPT_REG
7520 && po->operand[0].reg == xST0;
7522 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7524 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7525 float_st0, float_st0, buf1, buf1);
7526 strcat(g_comment, " fxch");
7533 ferr_assert(po, po->flags & OPF_32BIT);
7534 fprintf(fout, " eax = (s32)%s;", float_st0);
7535 if (po->flags & OPF_FSHIFT) {
7536 if (need_float_stack)
7537 fprintf(fout, " f_stp++;");
7539 fprintf(fout, " f_st0 = f_st1;");
7541 strcat(g_comment, " ftol");
7545 if (need_float_stack) {
7546 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
7547 need_double ? "" : "f", float_st1, float_st0);
7548 fprintf(fout, " f_stp++;");
7551 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
7552 need_double ? "" : "f");
7554 strcat(g_comment, " CIpow");
7558 fprintf(fout, " do_skip_code_abort();");
7563 fprintf(fout, " do_emms();");
7568 ferr(po, "unhandled op type %d, flags %x\n",
7573 if (g_comment[0] != 0) {
7574 char *p = g_comment;
7575 while (my_isblank(*p))
7577 fprintf(fout, " // %s", p);
7582 fprintf(fout, "\n");
7584 // some sanity checking
7585 if (po->flags & OPF_REP) {
7586 if (po->op != OP_STOS && po->op != OP_MOVS
7587 && po->op != OP_CMPS && po->op != OP_SCAS)
7588 ferr(po, "unexpected rep\n");
7589 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7590 && (po->op == OP_CMPS || po->op == OP_SCAS))
7591 ferr(po, "cmps/scas with plain rep\n");
7593 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7594 && po->op != OP_CMPS && po->op != OP_SCAS)
7595 ferr(po, "unexpected repz/repnz\n");
7598 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
7600 // see is delayed flag stuff is still valid
7601 if (delayed_flag_op != NULL && delayed_flag_op != po) {
7602 if (is_any_opr_modified(delayed_flag_op, po, 0))
7603 delayed_flag_op = NULL;
7606 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7607 if (is_opr_modified(last_arith_dst, po))
7608 last_arith_dst = NULL;
7614 if (g_stack_fsz && !g_stack_frame_used)
7615 fprintf(fout, " (void)sf;\n");
7617 fprintf(fout, "}\n\n");
7619 gen_x_cleanup(opcnt);
7622 static void gen_x_cleanup(int opcnt)
7626 for (i = 0; i < opcnt; i++) {
7627 struct label_ref *lr, *lr_del;
7629 lr = g_label_refs[i].next;
7630 while (lr != NULL) {
7635 g_label_refs[i].i = -1;
7636 g_label_refs[i].next = NULL;
7638 if (ops[i].op == OP_CALL) {
7640 proto_release(ops[i].pp);
7646 struct func_proto_dep;
7648 struct func_prototype {
7653 int has_ret:3; // -1, 0, 1: unresolved, no, yes
7654 unsigned int dep_resolved:1;
7655 unsigned int is_stdcall:1;
7656 struct func_proto_dep *dep_func;
7658 const struct parsed_proto *pp; // seed pp, if any
7661 struct func_proto_dep {
7663 struct func_prototype *proto;
7664 int regmask_live; // .. at the time of call
7665 unsigned int ret_dep:1; // return from this is caller's return
7668 static struct func_prototype *hg_fp;
7669 static int hg_fp_cnt;
7671 static struct scanned_var {
7673 enum opr_lenmod lmod;
7674 unsigned int is_seeded:1;
7675 unsigned int is_c_str:1;
7676 const struct parsed_proto *pp; // seed pp, if any
7678 static int hg_var_cnt;
7680 static char **hg_refs;
7681 static int hg_ref_cnt;
7683 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7686 static struct func_prototype *hg_fp_add(const char *funcn)
7688 struct func_prototype *fp;
7690 if ((hg_fp_cnt & 0xff) == 0) {
7691 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7692 my_assert_not(hg_fp, NULL);
7693 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7696 fp = &hg_fp[hg_fp_cnt];
7697 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7699 fp->argc_stack = -1;
7705 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7710 for (i = 0; i < fp->dep_func_cnt; i++)
7711 if (IS(fp->dep_func[i].name, name))
7712 return &fp->dep_func[i];
7717 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7720 if (hg_fp_find_dep(fp, name))
7723 if ((fp->dep_func_cnt & 0xff) == 0) {
7724 fp->dep_func = realloc(fp->dep_func,
7725 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7726 my_assert_not(fp->dep_func, NULL);
7727 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7728 sizeof(fp->dep_func[0]) * 0x100);
7730 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7734 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7736 const struct func_prototype *p1 = p1_, *p2 = p2_;
7737 return strcmp(p1->name, p2->name);
7741 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7743 const struct func_prototype *p1 = p1_, *p2 = p2_;
7744 return p1->id - p2->id;
7748 static void hg_ref_add(const char *name)
7750 if ((hg_ref_cnt & 0xff) == 0) {
7751 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7752 my_assert_not(hg_refs, NULL);
7753 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7756 hg_refs[hg_ref_cnt] = strdup(name);
7757 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7761 // recursive register dep pass
7762 // - track saved regs (part 2)
7763 // - try to figure out arg-regs
7764 // - calculate reg deps
7765 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
7766 struct func_prototype *fp, int regmask_save, int regmask_dst,
7767 int *regmask_dep, int *has_ret)
7769 struct func_proto_dep *dep;
7770 struct parsed_op *po;
7771 int from_caller = 0;
7776 for (; i < opcnt; i++)
7778 if (cbits[i >> 3] & (1 << (i & 7)))
7780 cbits[i >> 3] |= (1 << (i & 7));
7784 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
7785 if (po->flags & OPF_RMD)
7788 if (po->btj != NULL) {
7790 for (j = 0; j < po->btj->count; j++) {
7791 check_i(po, po->btj->d[j].bt_i);
7792 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
7793 regmask_save, regmask_dst, regmask_dep, has_ret);
7798 check_i(po, po->bt_i);
7799 if (po->flags & OPF_CJMP) {
7800 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
7801 regmask_save, regmask_dst, regmask_dep, has_ret);
7809 if (po->flags & OPF_FARG)
7810 /* (just calculate register deps) */;
7811 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
7813 reg = po->operand[0].reg;
7814 ferr_assert(po, reg >= 0);
7816 if (po->flags & OPF_RSAVE) {
7817 regmask_save |= 1 << reg;
7820 if (po->flags & OPF_DONE)
7823 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
7825 regmask_save |= 1 << reg;
7826 po->flags |= OPF_RMD;
7827 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
7831 else if (po->flags & OPF_RMD)
7833 else if (po->op == OP_CALL) {
7834 po->regmask_dst |= 1 << xAX;
7836 dep = hg_fp_find_dep(fp, po->operand[0].name);
7838 dep->regmask_live = regmask_save | regmask_dst;
7839 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7840 dep->regmask_live |= 1 << xBP;
7843 else if (po->op == OP_RET) {
7844 if (po->operand_cnt > 0) {
7846 if (fp->argc_stack >= 0
7847 && fp->argc_stack != po->operand[0].val / 4)
7848 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
7849 fp->argc_stack = po->operand[0].val / 4;
7853 // if has_ret is 0, there is uninitialized eax path,
7854 // which means it's most likely void func
7855 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
7856 if (po->op == OP_CALL) {
7861 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
7864 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
7867 if (ret != 1 && from_caller) {
7868 // unresolved eax - probably void func
7872 if (j >= 0 && ops[j].op == OP_CALL) {
7873 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
7884 l = regmask_save | regmask_dst;
7885 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7888 l = po->regmask_src & ~l;
7891 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
7892 l, regmask_dst, regmask_save, po->flags);
7895 regmask_dst |= po->regmask_dst;
7897 if (po->flags & OPF_TAIL)
7902 static void gen_hdr(const char *funcn, int opcnt)
7904 unsigned char cbits[MAX_OPS / 8];
7905 const struct parsed_proto *pp_c;
7906 struct parsed_proto *pp;
7907 struct func_prototype *fp;
7908 struct parsed_op *po;
7909 int regmask_dummy = 0;
7911 int max_bp_offset = 0;
7916 pp_c = proto_parse(g_fhdr, funcn, 1);
7918 // already in seed, will add to hg_fp later
7921 fp = hg_fp_add(funcn);
7923 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7924 g_stack_frame_used = 0;
7927 // - resolve all branches
7928 // - parse calls with labels
7929 resolve_branches_parse_calls(opcnt);
7932 // - handle ebp/esp frame, remove ops related to it
7933 scan_prologue_epilogue(opcnt, NULL);
7936 // - remove dead labels
7938 for (i = 0; i < opcnt; i++)
7940 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7946 if (po->flags & (OPF_RMD|OPF_DONE))
7949 if (po->op == OP_CALL) {
7950 if (po->operand[0].type == OPT_LABEL)
7951 hg_fp_add_dep(fp, opr_name(po, 0));
7952 else if (po->pp != NULL)
7953 hg_fp_add_dep(fp, po->pp->name);
7958 // - remove dead labels
7959 // - handle push <const>/pop pairs
7960 for (i = 0; i < opcnt; i++)
7962 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7968 if (po->flags & (OPF_RMD|OPF_DONE))
7971 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
7972 scan_for_pop_const(i, opcnt, i + opcnt * 13);
7976 // - process trivial calls
7977 for (i = 0; i < opcnt; i++)
7980 if (po->flags & (OPF_RMD|OPF_DONE))
7983 if (po->op == OP_CALL)
7985 pp = process_call_early(i, opcnt, &j);
7987 if (!(po->flags & OPF_ATAIL))
7988 // since we know the args, try to collect them
7989 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
7995 // commit esp adjust
7996 if (ops[j].op != OP_POP)
7997 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
7999 for (l = 0; l < pp->argc_stack; l++)
8000 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8004 po->flags |= OPF_DONE;
8010 // - track saved regs (simple)
8012 for (i = 0; i < opcnt; i++)
8015 if (po->flags & (OPF_RMD|OPF_DONE))
8018 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8019 && po->operand[0].reg != xCX)
8021 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8023 // regmask_save |= 1 << po->operand[0].reg; // do it later
8024 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8025 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8028 else if (po->op == OP_CALL)
8030 pp = process_call(i, opcnt);
8032 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8033 // since we know the args, collect them
8034 ret = collect_call_args(po, i, pp, ®mask_dummy,
8041 memset(cbits, 0, sizeof(cbits));
8045 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
8047 // find unreachable code - must be fixed in IDA
8048 for (i = 0; i < opcnt; i++)
8050 if (cbits[i >> 3] & (1 << (i & 7)))
8053 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8054 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8056 // the compiler sometimes still generates code after
8057 // noreturn OS functions
8060 if (ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8061 ferr(&ops[i], "unreachable code\n");
8064 for (i = 0; i < g_eqcnt; i++) {
8065 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8066 max_bp_offset = g_eqs[i].offset;
8069 if (fp->argc_stack < 0) {
8070 max_bp_offset = (max_bp_offset + 3) & ~3;
8071 fp->argc_stack = max_bp_offset / 4;
8072 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8076 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8077 fp->has_ret = has_ret;
8079 printf("// has_ret %d, regmask_dep %x\n",
8080 fp->has_ret, fp->regmask_dep);
8081 output_hdr_fp(stdout, fp, 1);
8082 if (IS(funcn, "sub_10007F72")) exit(1);
8085 gen_x_cleanup(opcnt);
8088 static void hg_fp_resolve_deps(struct func_prototype *fp)
8090 struct func_prototype fp_s;
8094 // this thing is recursive, so mark first..
8095 fp->dep_resolved = 1;
8097 for (i = 0; i < fp->dep_func_cnt; i++) {
8098 strcpy(fp_s.name, fp->dep_func[i].name);
8099 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8100 sizeof(hg_fp[0]), hg_fp_cmp_name);
8101 if (fp->dep_func[i].proto != NULL) {
8102 if (!fp->dep_func[i].proto->dep_resolved)
8103 hg_fp_resolve_deps(fp->dep_func[i].proto);
8105 dep = ~fp->dep_func[i].regmask_live
8106 & fp->dep_func[i].proto->regmask_dep;
8107 fp->regmask_dep |= dep;
8108 // printf("dep %s %s |= %x\n", fp->name,
8109 // fp->dep_func[i].name, dep);
8111 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8112 fp->has_ret = fp->dep_func[i].proto->has_ret;
8117 // make all thiscall/edx arg functions referenced from .data fastcall
8118 static void do_func_refs_from_data(void)
8120 struct func_prototype *fp, fp_s;
8123 for (i = 0; i < hg_ref_cnt; i++) {
8124 strcpy(fp_s.name, hg_refs[i]);
8125 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8126 sizeof(hg_fp[0]), hg_fp_cmp_name);
8130 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8131 fp->regmask_dep |= mxCX | mxDX;
8135 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8138 const struct parsed_proto *pp;
8139 char *p, namebuf[NAMELEN];
8145 for (; count > 0; count--, fp++) {
8146 if (fp->has_ret == -1)
8147 fprintf(fout, "// ret unresolved\n");
8149 fprintf(fout, "// dep:");
8150 for (j = 0; j < fp->dep_func_cnt; j++) {
8151 fprintf(fout, " %s/", fp->dep_func[j].name);
8152 if (fp->dep_func[j].proto != NULL)
8153 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8154 fp->dep_func[j].proto->has_ret);
8156 fprintf(fout, "\n");
8159 p = strchr(fp->name, '@');
8161 memcpy(namebuf, fp->name, p - fp->name);
8162 namebuf[p - fp->name] = 0;
8170 pp = proto_parse(g_fhdr, name, 1);
8171 if (pp != NULL && pp->is_include)
8174 if (fp->pp != NULL) {
8175 // part of seed, output later
8179 regmask_dep = fp->regmask_dep;
8180 argc_normal = fp->argc_stack;
8182 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8183 (fp->has_ret ? "int" : "void"));
8184 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8185 && (regmask_dep & ~mxCX) == 0)
8187 fprintf(fout, "/*__thiscall*/ ");
8191 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8192 && (regmask_dep & ~(mxCX | mxDX)) == 0)
8194 fprintf(fout, " __fastcall ");
8195 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8201 else if (regmask_dep && !fp->is_stdcall) {
8202 fprintf(fout, "/*__usercall*/ ");
8204 else if (regmask_dep) {
8205 fprintf(fout, "/*__userpurge*/ ");
8207 else if (fp->is_stdcall)
8208 fprintf(fout, " __stdcall ");
8210 fprintf(fout, " __cdecl ");
8212 fprintf(fout, "%s(", name);
8215 for (j = 0; j < xSP; j++) {
8216 if (regmask_dep & (1 << j)) {
8219 fprintf(fout, ", ");
8221 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8223 fprintf(fout, "int");
8224 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8228 for (j = 0; j < argc_normal; j++) {
8231 fprintf(fout, ", ");
8232 if (fp->pp != NULL) {
8233 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8234 if (!fp->pp->arg[arg - 1].type.is_ptr)
8238 fprintf(fout, "int ");
8239 fprintf(fout, "a%d", arg);
8242 fprintf(fout, ");\n");
8246 static void output_hdr(FILE *fout)
8248 static const char *lmod_c_names[] = {
8249 [OPLM_UNSPEC] = "???",
8250 [OPLM_BYTE] = "uint8_t",
8251 [OPLM_WORD] = "uint16_t",
8252 [OPLM_DWORD] = "uint32_t",
8253 [OPLM_QWORD] = "uint64_t",
8255 const struct scanned_var *var;
8256 struct func_prototype *fp;
8257 char line[256] = { 0, };
8261 // add stuff from headers
8262 for (i = 0; i < pp_cache_size; i++) {
8263 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8264 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8266 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8267 fp = hg_fp_add(name);
8268 fp->pp = &pp_cache[i];
8269 fp->argc_stack = fp->pp->argc_stack;
8270 fp->is_stdcall = fp->pp->is_stdcall;
8271 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8272 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8276 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8277 for (i = 0; i < hg_fp_cnt; i++)
8278 hg_fp_resolve_deps(&hg_fp[i]);
8280 // adjust functions referenced from data segment
8281 do_func_refs_from_data();
8283 // note: messes up .proto ptr, don't use
8284 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8287 for (i = 0; i < hg_var_cnt; i++) {
8290 if (var->pp != NULL)
8293 else if (var->is_c_str)
8294 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8296 fprintf(fout, "extern %-8s %s;",
8297 lmod_c_names[var->lmod], var->name);
8300 fprintf(fout, " // seeded");
8301 fprintf(fout, "\n");
8304 fprintf(fout, "\n");
8306 // output function prototypes
8307 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8310 fprintf(fout, "\n// - seed -\n");
8313 while (fgets(line, sizeof(line), g_fhdr))
8314 fwrite(line, 1, strlen(line), fout);
8317 // '=' needs special treatment
8319 static char *next_word_s(char *w, size_t wsize, char *s)
8326 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8328 for (i = 1; i < wsize - 1; i++) {
8330 printf("warning: missing closing quote: \"%s\"\n", s);
8339 for (; i < wsize - 1; i++) {
8340 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8346 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8347 printf("warning: '%s' truncated\n", w);
8352 static int cmpstringp(const void *p1, const void *p2)
8354 return strcmp(*(char * const *)p1, *(char * const *)p2);
8357 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8362 if (strstr(p, "..."))
8363 // unable to determine, assume needed
8366 if (*p == '.') // .text, .data, ...
8367 // ref from other data or non-function -> no
8370 p2 = strpbrk(p, "+:\r\n\x18");
8373 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8374 // referenced from removed code
8380 static int ida_xrefs_show_need(FILE *fasm, char *p,
8381 char **rlist, int rlist_len)
8387 p = strrchr(p, ';');
8388 if (p != NULL && *p == ';') {
8389 if (IS_START(p + 2, "sctref"))
8391 if (IS_START(p + 2, "DATA XREF: ")) {
8393 if (is_xref_needed(p, rlist, rlist_len))
8401 if (!my_fgets(line, sizeof(line), fasm))
8403 // non-first line is always indented
8404 if (!my_isblank(line[0]))
8407 // should be no content, just comment
8412 p = strrchr(p, ';');
8415 if (IS_START(p, "sctref")) {
8420 // it's printed once, but no harm to check again
8421 if (IS_START(p, "DATA XREF: "))
8424 if (is_xref_needed(p, rlist, rlist_len)) {
8429 fseek(fasm, pos, SEEK_SET);
8433 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8435 struct scanned_var *var;
8436 char line[256] = { 0, };
8445 // skip to next data section
8446 while (my_fgets(line, sizeof(line), fasm))
8451 if (*p == 0 || *p == ';')
8454 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8455 if (*p == 0 || *p == ';')
8458 if (*p != 's' || !IS_START(p, "segment para public"))
8464 if (p == NULL || !IS_START(p, "segment para public"))
8468 if (!IS_START(p, "'DATA'"))
8472 while (my_fgets(line, sizeof(line), fasm))
8477 no_identifier = my_isblank(*p);
8480 if (*p == 0 || *p == ';')
8483 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8484 words[wordc][0] = 0;
8485 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8486 if (*p == 0 || *p == ';') {
8492 if (wordc == 2 && IS(words[1], "ends"))
8497 if (no_identifier) {
8498 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8499 hg_ref_add(words[2]);
8503 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8504 // when this starts, we don't need anything from this section
8508 // check refs comment(s)
8509 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8512 if ((hg_var_cnt & 0xff) == 0) {
8513 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8514 * (hg_var_cnt + 0x100));
8515 my_assert_not(hg_vars, NULL);
8516 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8519 var = &hg_vars[hg_var_cnt++];
8520 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8522 // maybe already in seed header?
8523 var->pp = proto_parse(g_fhdr, var->name, 1);
8524 if (var->pp != NULL) {
8525 if (var->pp->is_fptr) {
8526 var->lmod = OPLM_DWORD;
8529 else if (var->pp->is_func)
8531 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8532 aerr("unhandled C type '%s' for '%s'\n",
8533 var->pp->type.name, var->name);
8539 if (IS(words[1], "dd")) {
8540 var->lmod = OPLM_DWORD;
8541 if (wordc >= 4 && IS(words[2], "offset"))
8542 hg_ref_add(words[3]);
8544 else if (IS(words[1], "dw"))
8545 var->lmod = OPLM_WORD;
8546 else if (IS(words[1], "db")) {
8547 var->lmod = OPLM_BYTE;
8548 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8549 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8553 else if (IS(words[1], "dq"))
8554 var->lmod = OPLM_QWORD;
8555 //else if (IS(words[1], "dt"))
8557 aerr("type '%s' not known\n", words[1]);
8565 static void set_label(int i, const char *name)
8571 p = strchr(name, ':');
8575 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8576 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8577 g_labels[i] = realloc(g_labels[i], len + 1);
8578 my_assert_not(g_labels[i], NULL);
8579 memcpy(g_labels[i], name, len);
8580 g_labels[i][len] = 0;
8589 static struct chunk_item *func_chunks;
8590 static int func_chunk_cnt;
8591 static int func_chunk_alloc;
8593 static void add_func_chunk(FILE *fasm, const char *name, int line)
8595 if (func_chunk_cnt >= func_chunk_alloc) {
8596 func_chunk_alloc *= 2;
8597 func_chunks = realloc(func_chunks,
8598 func_chunk_alloc * sizeof(func_chunks[0]));
8599 my_assert_not(func_chunks, NULL);
8601 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8602 func_chunks[func_chunk_cnt].name = strdup(name);
8603 func_chunks[func_chunk_cnt].asmln = line;
8607 static int cmp_chunks(const void *p1, const void *p2)
8609 const struct chunk_item *c1 = p1, *c2 = p2;
8610 return strcmp(c1->name, c2->name);
8613 static void scan_ahead_for_chunks(FILE *fasm)
8623 oldpos = ftell(fasm);
8626 while (my_fgets(line, sizeof(line), fasm))
8637 // get rid of random tabs
8638 for (i = 0; line[i] != 0; i++)
8639 if (line[i] == '\t')
8642 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8645 next_word(words[0], sizeof(words[0]), p);
8646 if (words[0][0] == 0)
8647 aerr("missing name for func chunk?\n");
8649 add_func_chunk(fasm, words[0], asmln);
8651 else if (IS_START(p, "; sctend"))
8657 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8658 words[wordc][0] = 0;
8659 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8660 if (*p == 0 || *p == ';') {
8666 if (wordc == 2 && IS(words[1], "ends"))
8670 fseek(fasm, oldpos, SEEK_SET);
8674 int main(int argc, char *argv[])
8676 FILE *fout, *fasm, *frlist;
8677 struct parsed_data *pd = NULL;
8679 char **rlist = NULL;
8681 int rlist_alloc = 0;
8682 int func_chunks_used = 0;
8683 int func_chunks_sorted = 0;
8684 int func_chunk_i = -1;
8685 long func_chunk_ret = 0;
8686 int func_chunk_ret_ln = 0;
8687 int scanned_ahead = 0;
8689 char words[20][256];
8690 enum opr_lenmod lmod;
8691 char *sctproto = NULL;
8693 int pending_endp = 0;
8695 int skip_code_end = 0;
8696 int skip_warned = 0;
8709 for (arg = 1; arg < argc; arg++) {
8710 if (IS(argv[arg], "-v"))
8712 else if (IS(argv[arg], "-rf"))
8713 g_allow_regfunc = 1;
8714 else if (IS(argv[arg], "-uc"))
8715 g_allow_user_icall = 1;
8716 else if (IS(argv[arg], "-m"))
8718 else if (IS(argv[arg], "-hdr"))
8719 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8724 if (argc < arg + 3) {
8725 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8726 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8728 " -hdr - header generation mode\n"
8729 " -rf - allow unannotated indirect calls\n"
8730 " -uc - allow ind. calls/refs to __usercall\n"
8731 " -m - allow multiple .text sections\n"
8732 "[rlist] is a file with function names to skip,"
8740 asmfn = argv[arg++];
8741 fasm = fopen(asmfn, "r");
8742 my_assert_not(fasm, NULL);
8744 hdrfn = argv[arg++];
8745 g_fhdr = fopen(hdrfn, "r");
8746 my_assert_not(g_fhdr, NULL);
8749 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8750 my_assert_not(rlist, NULL);
8751 // needs special handling..
8752 rlist[rlist_len++] = "__alloca_probe";
8754 func_chunk_alloc = 32;
8755 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8756 my_assert_not(func_chunks, NULL);
8758 memset(words, 0, sizeof(words));
8760 for (; arg < argc; arg++) {
8763 frlist = fopen(argv[arg], "r");
8764 my_assert_not(frlist, NULL);
8766 while (my_fgets(line, sizeof(line), frlist)) {
8768 if (*p == 0 || *p == ';')
8771 if (IS_START(p, "#if 0")
8772 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
8776 else if (IS_START(p, "#endif"))
8783 p = next_word(words[0], sizeof(words[0]), p);
8784 if (words[0][0] == 0)
8787 if (rlist_len >= rlist_alloc) {
8788 rlist_alloc = rlist_alloc * 2 + 64;
8789 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
8790 my_assert_not(rlist, NULL);
8792 rlist[rlist_len++] = strdup(words[0]);
8800 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
8802 fout = fopen(argv[arg_out], "w");
8803 my_assert_not(fout, NULL);
8806 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
8807 my_assert_not(g_eqs, NULL);
8809 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
8810 g_label_refs[i].i = -1;
8811 g_label_refs[i].next = NULL;
8815 scan_variables(fasm, rlist, rlist_len);
8817 while (my_fgets(line, sizeof(line), fasm))
8826 // get rid of random tabs
8827 for (i = 0; line[i] != 0; i++)
8828 if (line[i] == '\t')
8833 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
8834 goto do_pending_endp; // eww..
8836 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
8838 static const char *attrs[] = {
8847 // parse IDA's attribute-list comment
8848 g_ida_func_attr = 0;
8851 for (; *p != 0; p = sskip(p)) {
8852 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8853 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8854 g_ida_func_attr |= 1 << i;
8855 p += strlen(attrs[i]);
8859 if (i == ARRAY_SIZE(attrs)) {
8860 anote("unparsed IDA attr: %s\n", p);
8863 if (IS(attrs[i], "fpd=")) {
8864 p = next_word(words[0], sizeof(words[0]), p);
8869 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
8871 static const char *attrs[] = {
8876 // parse manual attribute-list comment
8877 g_sct_func_attr = 0;
8880 for (; *p != 0; p = sskip(p)) {
8881 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8882 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8883 g_sct_func_attr |= 1 << i;
8884 p += strlen(attrs[i]);
8891 // clear_sf=start,len (in dwords)
8892 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
8893 &g_stack_clear_len, &j);
8895 // clear_regmask=<mask>
8896 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
8898 anote("unparsed attr value: %s\n", p);
8903 else if (i == ARRAY_SIZE(attrs)) {
8904 anote("unparsed sct attr: %s\n", p);
8909 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8912 next_word(words[0], sizeof(words[0]), p);
8913 if (words[0][0] == 0)
8914 aerr("missing name for func chunk?\n");
8916 if (!scanned_ahead) {
8917 add_func_chunk(fasm, words[0], asmln);
8918 func_chunks_sorted = 0;
8921 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
8923 if (func_chunk_i >= 0) {
8924 if (func_chunk_i < func_chunk_cnt
8925 && IS(func_chunks[func_chunk_i].name, g_func))
8927 // move on to next chunk
8928 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8930 aerr("seek failed for '%s' chunk #%d\n",
8931 g_func, func_chunk_i);
8932 asmln = func_chunks[func_chunk_i].asmln;
8936 if (func_chunk_ret == 0)
8937 aerr("no return from chunk?\n");
8938 fseek(fasm, func_chunk_ret, SEEK_SET);
8939 asmln = func_chunk_ret_ln;
8945 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
8946 func_chunks_used = 1;
8948 if (IS_START(g_func, "sub_")) {
8949 unsigned long addr = strtoul(p, NULL, 16);
8950 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
8951 if (addr > f_addr && !scanned_ahead) {
8952 //anote("scan_ahead caused by '%s', addr %lx\n",
8954 scan_ahead_for_chunks(fasm);
8956 func_chunks_sorted = 0;
8964 for (i = wordc; i < ARRAY_SIZE(words); i++)
8966 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8967 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8968 if (*p == 0 || *p == ';') {
8973 if (*p != 0 && *p != ';')
8974 aerr("too many words\n");
8976 if (skip_code_end) {
8981 // allow asm patches in comments
8983 if (IS_START(p, "; sctpatch:")) {
8985 if (*p == 0 || *p == ';')
8987 goto parse_words; // lame
8989 if (IS_START(p, "; sctproto:")) {
8990 sctproto = strdup(p + 11);
8992 else if (IS_START(p, "; sctend")) {
8997 else if (IS_START(p, "; sctskip_start")) {
8998 if (in_func && !g_skip_func) {
9000 ops[pi].op = OPP_ABORT;
9001 ops[pi].asmln = asmln;
9007 else if (IS_START(p, "; sctskip_end")) {
9015 awarn("wordc == 0?\n");
9019 // don't care about this:
9020 if (words[0][0] == '.'
9021 || IS(words[0], "include")
9022 || IS(words[0], "assume") || IS(words[1], "segment")
9023 || IS(words[0], "align"))
9029 // do delayed endp processing to collect switch jumptables
9031 if (in_func && !g_skip_func && !end && wordc >= 2
9032 && ((words[0][0] == 'd' && words[0][2] == 0)
9033 || (words[1][0] == 'd' && words[1][2] == 0)))
9036 if (words[1][0] == 'd' && words[1][2] == 0) {
9038 if (g_func_pd_cnt >= pd_alloc) {
9039 pd_alloc = pd_alloc * 2 + 16;
9040 g_func_pd = realloc(g_func_pd,
9041 sizeof(g_func_pd[0]) * pd_alloc);
9042 my_assert_not(g_func_pd, NULL);
9044 pd = &g_func_pd[g_func_pd_cnt];
9046 memset(pd, 0, sizeof(*pd));
9047 strcpy(pd->label, words[0]);
9048 pd->type = OPT_CONST;
9049 pd->lmod = lmod_from_directive(words[1]);
9055 anote("skipping alignment byte?\n");
9058 lmod = lmod_from_directive(words[0]);
9059 if (lmod != pd->lmod)
9060 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9063 if (pd->count_alloc < pd->count + wordc) {
9064 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9065 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9066 my_assert_not(pd->d, NULL);
9068 for (; i < wordc; i++) {
9069 if (IS(words[i], "offset")) {
9070 pd->type = OPT_OFFSET;
9073 p = strchr(words[i], ',');
9076 if (pd->type == OPT_OFFSET)
9077 pd->d[pd->count].u.label = strdup(words[i]);
9079 pd->d[pd->count].u.val = parse_number(words[i], 0);
9080 pd->d[pd->count].bt_i = -1;
9086 if (in_func && !g_skip_func) {
9088 gen_hdr(g_func, pi);
9090 gen_func(fout, g_fhdr, g_func, pi);
9095 g_ida_func_attr = 0;
9096 g_sct_func_attr = 0;
9097 g_stack_clear_start = 0;
9098 g_stack_clear_len = 0;
9103 func_chunks_used = 0;
9106 memset(&ops, 0, pi * sizeof(ops[0]));
9111 for (i = 0; i < g_func_pd_cnt; i++) {
9113 if (pd->type == OPT_OFFSET) {
9114 for (j = 0; j < pd->count; j++)
9115 free(pd->d[j].u.label);
9130 if (IS(words[1], "proc")) {
9132 aerr("proc '%s' while in_func '%s'?\n",
9135 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9137 strcpy(g_func, words[0]);
9138 set_label(0, words[0]);
9143 if (IS(words[1], "endp"))
9146 aerr("endp '%s' while not in_func?\n", words[0]);
9147 if (!IS(g_func, words[0]))
9148 aerr("endp '%s' while in_func '%s'?\n",
9151 aerr("endp '%s' while skipping code\n", words[0]);
9153 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9154 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
9160 if (!g_skip_func && func_chunks_used) {
9161 // start processing chunks
9162 struct chunk_item *ci, key = { g_func, 0 };
9164 func_chunk_ret = ftell(fasm);
9165 func_chunk_ret_ln = asmln;
9166 if (!func_chunks_sorted) {
9167 qsort(func_chunks, func_chunk_cnt,
9168 sizeof(func_chunks[0]), cmp_chunks);
9169 func_chunks_sorted = 1;
9171 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9172 sizeof(func_chunks[0]), cmp_chunks);
9174 aerr("'%s' needs chunks, but none found\n", g_func);
9175 func_chunk_i = ci - func_chunks;
9176 for (; func_chunk_i > 0; func_chunk_i--)
9177 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9180 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9182 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9183 asmln = func_chunks[func_chunk_i].asmln;
9191 if (wordc == 2 && IS(words[1], "ends")) {
9195 goto do_pending_endp;
9199 // scan for next text segment
9200 while (my_fgets(line, sizeof(line), fasm)) {
9203 if (*p == 0 || *p == ';')
9206 if (strstr(p, "segment para public 'CODE' use32"))
9213 p = strchr(words[0], ':');
9215 set_label(pi, words[0]);
9219 if (!in_func || g_skip_func || skip_code) {
9220 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9222 anote("skipping from '%s'\n", g_labels[pi]);
9226 g_labels[pi] = NULL;
9230 if (wordc > 1 && IS(words[1], "="))
9233 aerr("unhandled equ, wc=%d\n", wordc);
9234 if (g_eqcnt >= eq_alloc) {
9236 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9237 my_assert_not(g_eqs, NULL);
9240 len = strlen(words[0]);
9241 if (len > sizeof(g_eqs[0].name) - 1)
9242 aerr("equ name too long: %d\n", len);
9243 strcpy(g_eqs[g_eqcnt].name, words[0]);
9245 if (!IS(words[3], "ptr"))
9246 aerr("unhandled equ\n");
9247 if (IS(words[2], "dword"))
9248 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9249 else if (IS(words[2], "word"))
9250 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9251 else if (IS(words[2], "byte"))
9252 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9253 else if (IS(words[2], "qword"))
9254 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9256 aerr("bad lmod: '%s'\n", words[2]);
9258 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9263 if (pi >= ARRAY_SIZE(ops))
9264 aerr("too many ops\n");
9266 parse_op(&ops[pi], words, wordc);
9268 ops[pi].datap = sctproto;
9283 // vim:ts=2:shiftwidth=2:expandtab