5 * This work is licensed under the terms of 3-clause BSD license.
6 * See COPYING file in the top-level directory.
8 * recognized asm hint comments:
9 * sctattr - function attributes (see code)
10 * sctend - force end of function/chunk
11 * sctpatch: <p> - replace current asm line with <p>
12 * sctproto: <p> - prototype of ref'd function or struct
13 * sctref - variable is referenced, make global
14 * sctskip_start - start of skipped code chunk (inclusive)
15 * sctskip_end - end of skipped code chunk (inclusive)
23 #include "my_assert.h"
27 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
28 #define IS(w, y) !strcmp(w, y)
29 #define IS_START(w, y) !strncmp(w, y, strlen(y))
31 #include "protoparse.h"
33 static const char *asmfn;
37 #define anote(fmt, ...) \
38 printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
39 #define awarn(fmt, ...) \
40 printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
41 #define aerr(fmt, ...) do { \
42 printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
47 #include "masm_tools.h"
50 OPF_RMD = (1 << 0), /* removed from code generation */
51 OPF_DATA = (1 << 1), /* data processing - writes to dst opr */
52 OPF_FLAGS = (1 << 2), /* sets flags */
53 OPF_JMP = (1 << 3), /* branch, call */
54 OPF_CJMP = (1 << 4), /* cond. branch (cc or jecxz/loop) */
55 OPF_CC = (1 << 5), /* uses flags */
56 OPF_TAIL = (1 << 6), /* ret or tail call */
57 OPF_RSAVE = (1 << 7), /* push/pop is local reg save/load */
58 OPF_REP = (1 << 8), /* prefixed by rep */
59 OPF_REPZ = (1 << 9), /* rep is repe/repz */
60 OPF_REPNZ = (1 << 10), /* rep is repne/repnz */
61 OPF_FARG = (1 << 11), /* push collected as func arg */
62 OPF_FARGNR = (1 << 12), /* push collected as func arg (no reuse) */
63 OPF_EBP_S = (1 << 13), /* ebp used as scratch here, not BP */
64 OPF_DF = (1 << 14), /* DF flag set */
65 OPF_ATAIL = (1 << 15), /* tail call with reused arg frame */
66 OPF_32BIT = (1 << 16), /* 32bit division */
67 OPF_LOCK = (1 << 17), /* op has lock prefix */
68 OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
69 OPF_DONE = (1 << 19), /* already fully handled by analysis */
70 OPF_PPUSH = (1 << 20), /* part of complex push-pop graph */
71 OPF_NOREGS = (1 << 21), /* don't track regs of this op */
72 OPF_FPUSH = (1 << 22), /* pushes x87 stack */
73 OPF_FPOP = (1 << 23), /* pops x87 stack */
74 OPF_FSHIFT = (1 << 24), /* x87 stack shift is actually needed */
164 // pseudo-ops for lib calls
183 // must be sorted (larger len must be further in enum)
192 #define MAX_EXITS 128
194 #define MAX_OPERANDS 3
197 #define OPR_INIT(type_, lmod_, reg_) \
198 { type_, lmod_, reg_, }
202 enum opr_lenmod lmod;
204 unsigned int is_ptr:1; // pointer in C
205 unsigned int is_array:1; // array in C
206 unsigned int type_from_var:1; // .. in header, sometimes wrong
207 unsigned int size_mismatch:1; // type override differs from C
208 unsigned int size_lt:1; // type override is larger than C
209 unsigned int had_ds:1; // had ds: prefix
210 const struct parsed_proto *pp; // for OPT_LABEL
217 struct parsed_opr operand[MAX_OPERANDS];
220 unsigned char pfo_inv;
221 unsigned char operand_cnt;
222 unsigned char p_argnum; // arg push: altered before call arg #
223 unsigned char p_arggrp; // arg push: arg group # for above
224 unsigned char p_argpass;// arg push: arg of host func
225 short p_argnext;// arg push: same arg pushed elsewhere or -1
226 int regmask_src; // all referensed regs
228 int pfomask; // flagop: parsed_flag_op that can't be delayed
229 int cc_scratch; // scratch storage during analysis
230 int bt_i; // branch target for branches
231 struct parsed_data *btj;// branch targets for jumptables
232 struct parsed_proto *pp;// parsed_proto for OP_CALL
238 // on start: function/data type hint (sctproto)
240 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
241 // OP_PUSH - points to OP_POP in complex push/pop graph
242 // OP_POP - points to OP_PUSH in simple push/pop pair
243 // OP_FCOM - needed_status_word_bits | (is_z_check << 16)
247 enum opr_lenmod lmod;
254 enum opr_lenmod lmod;
268 struct label_ref *next;
272 IDAFA_BP_FRAME = (1 << 0),
273 IDAFA_LIB_FUNC = (1 << 1),
274 IDAFA_STATIC = (1 << 2),
275 IDAFA_NORETURN = (1 << 3),
276 IDAFA_THUNK = (1 << 4),
277 IDAFA_FPD = (1 << 5),
281 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
282 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
295 // note: limited to 32k due to p_argnext
297 #define MAX_ARG_GRP 2
299 static struct parsed_op ops[MAX_OPS];
300 static struct parsed_equ *g_eqs;
302 static char *g_labels[MAX_OPS];
303 static struct label_ref g_label_refs[MAX_OPS];
304 static const struct parsed_proto *g_func_pp;
305 static struct parsed_data *g_func_pd;
306 static int g_func_pd_cnt;
307 static int g_func_lmods;
308 static char g_func[256];
309 static char g_comment[256];
310 static int g_bp_frame;
311 static int g_sp_frame;
312 static int g_stack_frame_used;
313 static int g_stack_fsz;
314 static int g_ida_func_attr;
315 static int g_sct_func_attr;
316 static int g_stack_clear_start; // in dwords
317 static int g_stack_clear_len;
318 static int g_regmask_init;
319 static int g_skip_func;
320 static int g_allow_regfunc;
321 static int g_allow_user_icall;
322 static int g_quiet_pp;
323 static int g_header_mode;
325 #define ferr(op_, fmt, ...) do { \
326 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
327 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
331 #define fnote(op_, fmt, ...) \
332 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
333 dump_op(op_), ##__VA_ARGS__)
335 #define ferr_assert(op_, cond) do { \
336 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
339 const char *regs_r32[] = {
340 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
341 // not r32, but list here for easy parsing and printing
342 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
343 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
345 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
346 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
347 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
353 xMM0, xMM1, xMM2, xMM3, // mmx
354 xMM4, xMM5, xMM6, xMM7,
355 xST0, xST1, xST2, xST3, // x87
356 xST4, xST5, xST6, xST7,
359 #define mxAX (1 << xAX)
360 #define mxCX (1 << xCX)
361 #define mxDX (1 << xDX)
362 #define mxST0 (1 << xST0)
363 #define mxST1 (1 << xST1)
364 #define mxST1_0 (mxST1 | mxST0)
365 #define mxST7_2 (0xfc << xST0)
366 #define mxSTa (0xff << xST0)
368 // possible basic comparison types (without inversion)
369 enum parsed_flag_op {
373 PFO_BE, // 6 CF=1||ZF=1
377 PFO_LE, // e ZF=1||SF!=OF
380 #define PFOB_O (1 << PFO_O)
381 #define PFOB_C (1 << PFO_C)
382 #define PFOB_Z (1 << PFO_Z)
383 #define PFOB_S (1 << PFO_S)
385 static const char *parsed_flag_op_names[] = {
386 "o", "c", "z", "be", "s", "p", "l", "le"
389 static int char_array_i(const char *array[], size_t len, const char *s)
393 for (i = 0; i < len; i++)
400 static void printf_number(char *buf, size_t buf_size,
401 unsigned long number)
403 // output in C-friendly form
404 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
407 static int check_segment_prefix(const char *s)
409 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
423 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
427 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
429 *reg_lmod = OPLM_QWORD;
433 *reg_lmod = OPLM_DWORD;
436 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
438 *reg_lmod = OPLM_WORD;
441 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
443 *reg_lmod = OPLM_BYTE;
446 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
448 *reg_lmod = OPLM_BYTE;
455 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
457 enum opr_lenmod lmod;
470 while (my_isblank(*s))
472 for (; my_issep(*s); d++, s++)
474 while (my_isblank(*s))
478 // skip '?s:' prefixes
479 if (check_segment_prefix(s))
482 s = next_idt(w, sizeof(w), s);
487 reg = parse_reg(&lmod, w);
489 *regmask |= 1 << reg;
493 if ('0' <= w[0] && w[0] <= '9') {
494 number = parse_number(w);
495 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
499 // probably some label/identifier - pass
502 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
506 strcpy(name, cvtbuf);
511 static int is_reg_in_str(const char *s)
515 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
518 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
519 if (!strncmp(s, regs_r32[i], 3))
525 static const char *parse_stack_el(const char *name, char *extra_reg,
526 int *base_val, int early_try)
528 const char *p, *p2, *s;
534 if (g_bp_frame || early_try)
537 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
539 if (extra_reg != NULL) {
540 strncpy(extra_reg, name, 3);
545 if (IS_START(p, "ebp+")) {
549 if (p2 != NULL && is_reg_in_str(p)) {
550 if (extra_reg != NULL) {
551 strncpy(extra_reg, p, p2 - p);
552 extra_reg[p2 - p] = 0;
557 if (!('0' <= *p && *p <= '9'))
564 if (!IS_START(name, "esp+"))
570 if (is_reg_in_str(s)) {
571 if (extra_reg != NULL) {
572 strncpy(extra_reg, s, p - s);
573 extra_reg[p - s] = 0;
578 aerr("%s IDA stackvar not set?\n", __func__);
580 if (!('0' <= *s && *s <= '9')) {
581 aerr("%s IDA stackvar offset not set?\n", __func__);
584 if (s[0] == '0' && s[1] == 'x')
587 if (len < sizeof(buf) - 1) {
588 strncpy(buf, s, len);
590 val = strtol(buf, &endp, 16);
591 if (val == 0 || *endp != 0) {
592 aerr("%s num parse fail for '%s'\n", __func__, buf);
601 if ('0' <= *p && *p <= '9')
604 if (base_val != NULL)
609 static int guess_lmod_from_name(struct parsed_opr *opr)
611 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
612 opr->lmod = OPLM_DWORD;
615 if (IS_START(opr->name, "word_")) {
616 opr->lmod = OPLM_WORD;
619 if (IS_START(opr->name, "byte_")) {
620 opr->lmod = OPLM_BYTE;
623 if (IS_START(opr->name, "qword_")) {
624 opr->lmod = OPLM_QWORD;
630 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
631 const struct parsed_type *c_type)
633 static const char *qword_types[] = {
634 "uint64_t", "int64_t", "__int64",
636 static const char *dword_types[] = {
637 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
638 "WPARAM", "LPARAM", "UINT", "__int32",
639 "LONG", "HIMC", "BOOL", "size_t",
642 static const char *word_types[] = {
643 "uint16_t", "int16_t", "_WORD", "WORD",
644 "unsigned __int16", "__int16",
646 static const char *byte_types[] = {
647 "uint8_t", "int8_t", "char",
648 "unsigned __int8", "__int8", "BYTE", "_BYTE",
650 // structures.. deal the same as with _UNKNOWN for now
656 if (c_type->is_ptr) {
661 n = skip_type_mod(c_type->name);
663 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
664 if (IS(n, dword_types[i])) {
670 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
671 if (IS(n, word_types[i])) {
677 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
678 if (IS(n, byte_types[i])) {
684 for (i = 0; i < ARRAY_SIZE(qword_types); i++) {
685 if (IS(n, qword_types[i])) {
694 static char *default_cast_to(char *buf, size_t buf_size,
695 struct parsed_opr *opr)
699 if (!opr->is_ptr || strchr(opr->name, '['))
701 if (opr->pp == NULL || opr->pp->type.name == NULL
704 snprintf(buf, buf_size, "%s", "(void *)");
708 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
712 static enum opr_type lmod_from_directive(const char *d)
716 else if (IS(d, "dw"))
718 else if (IS(d, "db"))
721 aerr("unhandled directive: '%s'\n", d);
725 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
731 *regmask |= 1 << reg;
734 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
737 static int parse_operand(struct parsed_opr *opr,
738 int *regmask, int *regmask_indirect,
739 char words[16][256], int wordc, int w, unsigned int op_flags)
741 const struct parsed_proto *pp = NULL;
742 enum opr_lenmod tmplmod;
743 unsigned long number;
751 aerr("parse_operand w %d, wordc %d\n", w, wordc);
755 for (i = w; i < wordc; i++) {
756 len = strlen(words[i]);
757 if (words[i][len - 1] == ',') {
758 words[i][len - 1] = 0;
764 wordc_in = wordc - w;
766 if ((op_flags & OPF_JMP) && wordc_in > 0
767 && !('0' <= words[w][0] && words[w][0] <= '9'))
769 const char *label = NULL;
771 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
772 && IS(words[w + 1], "ptr"))
773 label = words[w + 2];
774 else if (wordc_in == 2 && IS(words[w], "short"))
775 label = words[w + 1];
776 else if (wordc_in == 1
777 && strchr(words[w], '[') == NULL
778 && parse_reg(&tmplmod, words[w]) < 0)
782 opr->type = OPT_LABEL;
783 ret = check_segment_prefix(label);
786 aerr("fs/gs used\n");
790 strcpy(opr->name, label);
796 if (IS(words[w + 1], "ptr")) {
797 if (IS(words[w], "dword"))
798 opr->lmod = OPLM_DWORD;
799 else if (IS(words[w], "word"))
800 opr->lmod = OPLM_WORD;
801 else if (IS(words[w], "byte"))
802 opr->lmod = OPLM_BYTE;
803 else if (IS(words[w], "qword"))
804 opr->lmod = OPLM_QWORD;
806 aerr("type parsing failed\n");
808 wordc_in = wordc - w;
813 if (IS(words[w], "offset")) {
814 opr->type = OPT_OFFSET;
815 opr->lmod = OPLM_DWORD;
816 strcpy(opr->name, words[w + 1]);
817 pp = proto_parse(g_fhdr, opr->name, 1);
820 if (IS(words[w], "(offset")) {
821 p = strchr(words[w + 1], ')');
823 aerr("parse of bracketed offset failed\n");
825 opr->type = OPT_OFFSET;
826 strcpy(opr->name, words[w + 1]);
832 aerr("parse_operand 1 word expected\n");
834 ret = check_segment_prefix(words[w]);
837 aerr("fs/gs used\n");
839 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
841 strcpy(opr->name, words[w]);
843 if (words[w][0] == '[') {
844 opr->type = OPT_REGMEM;
845 ret = sscanf(words[w], "[%[^]]]", opr->name);
847 aerr("[] parse failure\n");
849 parse_indmode(opr->name, regmask_indirect, 1);
850 if (opr->lmod == OPLM_UNSPEC
851 && parse_stack_el(opr->name, NULL, NULL, 1))
854 struct parsed_equ *eq =
855 equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
857 opr->lmod = eq->lmod;
859 // might be unaligned access
860 g_func_lmods |= 1 << OPLM_BYTE;
864 else if (strchr(words[w], '[')) {
866 p = strchr(words[w], '[');
867 opr->type = OPT_REGMEM;
868 parse_indmode(p, regmask_indirect, 0);
869 strncpy(buf, words[w], p - words[w]);
870 buf[p - words[w]] = 0;
871 pp = proto_parse(g_fhdr, buf, 1);
874 else if (('0' <= words[w][0] && words[w][0] <= '9')
875 || words[w][0] == '-')
877 number = parse_number(words[w]);
878 opr->type = OPT_CONST;
880 printf_number(opr->name, sizeof(opr->name), number);
884 ret = parse_reg(&tmplmod, opr->name);
886 setup_reg_opr(opr, ret, tmplmod, regmask);
890 // most likely var in data segment
891 opr->type = OPT_LABEL;
892 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
896 if (pp->is_fptr || pp->is_func) {
897 opr->lmod = OPLM_DWORD;
901 tmplmod = OPLM_UNSPEC;
902 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
903 anote("unhandled C type '%s' for '%s'\n",
904 pp->type.name, opr->name);
906 if (opr->lmod == OPLM_UNSPEC) {
908 opr->type_from_var = 1;
910 else if (opr->lmod != tmplmod) {
911 opr->size_mismatch = 1;
912 if (tmplmod < opr->lmod)
915 opr->is_ptr = pp->type.is_ptr;
917 opr->is_array = pp->type.is_array;
921 if (opr->lmod == OPLM_UNSPEC)
922 guess_lmod_from_name(opr);
926 static const struct {
931 { "repe", OPF_REP|OPF_REPZ },
932 { "repz", OPF_REP|OPF_REPZ },
933 { "repne", OPF_REP|OPF_REPNZ },
934 { "repnz", OPF_REP|OPF_REPNZ },
935 { "lock", OPF_LOCK }, // ignored for now..
938 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
940 static const struct {
943 unsigned short minopr;
944 unsigned short maxopr;
947 unsigned char pfo_inv;
949 { "nop", OP_NOP, 0, 0, 0 },
950 { "push", OP_PUSH, 1, 1, 0 },
951 { "pop", OP_POP, 1, 1, OPF_DATA },
952 { "pusha",OP_PUSHA, 0, 0, 0 },
953 { "popa", OP_POPA, 0, 0, OPF_DATA },
954 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
955 { "mov" , OP_MOV, 2, 2, OPF_DATA },
956 { "lea", OP_LEA, 2, 2, OPF_DATA },
957 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
958 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
959 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
960 { "not", OP_NOT, 1, 1, OPF_DATA },
961 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
962 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
963 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
964 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
965 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
966 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
967 { "stosb",OP_STOS, 0, 0, OPF_DATA },
968 { "stosw",OP_STOS, 0, 0, OPF_DATA },
969 { "stosd",OP_STOS, 0, 0, OPF_DATA },
970 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
971 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
972 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
973 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
974 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
975 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
976 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
977 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
978 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
979 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
980 { "cld", OP_CLD, 0, 0, OPF_DATA },
981 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
982 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
983 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
984 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
985 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
986 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
987 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
988 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
989 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
990 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
991 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
992 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
993 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
994 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
995 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
996 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
997 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
998 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
999 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
1000 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
1001 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
1002 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
1003 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
1004 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
1005 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
1006 { "test", OP_TEST, 2, 2, OPF_FLAGS },
1007 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
1008 { "retn", OP_RET, 0, 1, OPF_TAIL },
1009 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
1010 { "jmp", OP_JMP, 1, 1, OPF_JMP },
1011 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
1012 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
1013 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
1014 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
1015 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
1016 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
1017 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
1018 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1019 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1020 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
1021 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
1022 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
1023 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
1024 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1025 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1026 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1027 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1028 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1029 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1030 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1031 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1032 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1033 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1034 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1035 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1036 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1037 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1038 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1039 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1040 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1041 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1042 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1043 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1044 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1045 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1046 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1047 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1048 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1049 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1050 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1051 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1052 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1053 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1054 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1055 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1056 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1057 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1058 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1059 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1060 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1061 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1062 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1063 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1064 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1065 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1066 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1067 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1068 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1069 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1070 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1072 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1073 { "fild", OP_FILD, 1, 1, OPF_FPUSH },
1074 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1075 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1076 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1077 { "fst", OP_FST, 1, 1, 0 },
1078 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1079 { "fist", OP_FIST, 1, 1, 0 },
1080 { "fistp", OP_FIST, 1, 1, OPF_FPOP },
1081 { "fadd", OP_FADD, 0, 2, 0 },
1082 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1083 { "fdiv", OP_FDIV, 0, 2, 0 },
1084 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1085 { "fmul", OP_FMUL, 0, 2, 0 },
1086 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1087 { "fsub", OP_FSUB, 0, 2, 0 },
1088 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1089 { "fdivr", OP_FDIVR, 0, 2, 0 },
1090 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1091 { "fsubr", OP_FSUBR, 0, 2, 0 },
1092 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1093 { "fiadd", OP_FIADD, 1, 1, 0 },
1094 { "fidiv", OP_FIDIV, 1, 1, 0 },
1095 { "fimul", OP_FIMUL, 1, 1, 0 },
1096 { "fisub", OP_FISUB, 1, 1, 0 },
1097 { "fidivr", OP_FIDIVR, 1, 1, 0 },
1098 { "fisubr", OP_FISUBR, 1, 1, 0 },
1099 { "fcom", OP_FCOM, 0, 1, 0 },
1100 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1101 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1102 { "fchs", OP_FCHS, 0, 0, 0 },
1103 { "fcos", OP_FCOS, 0, 0, 0 },
1104 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1105 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1106 { "fsin", OP_FSIN, 0, 0, 0 },
1107 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1108 { "fxch", OP_FXCH, 1, 1, 0 },
1109 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1111 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1112 { "movq", OP_MOV, 2, 2, OPF_DATA },
1113 // pseudo-ops for lib calls
1114 { "_allshl",OPP_ALLSHL },
1115 { "_allshr",OPP_ALLSHR },
1116 { "_ftol", OPP_FTOL },
1117 { "_CIpow", OPP_CIPOW },
1122 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1124 enum opr_lenmod lmod = OPLM_UNSPEC;
1125 int prefix_flags = 0;
1133 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1134 if (IS(words[w], pref_table[i].name)) {
1135 prefix_flags = pref_table[i].flags;
1142 aerr("lone prefix: '%s'\n", words[0]);
1147 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1148 if (IS(words[w], op_table[i].name))
1152 if (i == ARRAY_SIZE(op_table)) {
1154 aerr("unhandled op: '%s'\n", words[0]);
1159 op->op = op_table[i].op;
1160 op->flags = op_table[i].flags | prefix_flags;
1161 op->pfo = op_table[i].pfo;
1162 op->pfo_inv = op_table[i].pfo_inv;
1163 op->regmask_src = op->regmask_dst = 0;
1166 if (op->op == OP_UD2)
1169 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1170 if (opr >= op_table[i].minopr && w >= wordc)
1173 regmask = regmask_ind = 0;
1174 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1175 words, wordc, w, op->flags);
1177 if (opr == 0 && (op->flags & OPF_DATA))
1178 op->regmask_dst = regmask;
1180 op->regmask_src |= regmask;
1181 op->regmask_src |= regmask_ind;
1183 if (op->operand[opr].lmod != OPLM_UNSPEC)
1184 g_func_lmods |= 1 << op->operand[opr].lmod;
1188 aerr("parse_op %s incomplete: %d/%d\n",
1189 words[0], w, wordc);
1192 op->operand_cnt = opr;
1193 if (!strncmp(op_table[i].name, "set", 3))
1194 op->operand[0].lmod = OPLM_BYTE;
1197 // first operand is not dst
1200 op->regmask_src |= op->regmask_dst;
1201 op->regmask_dst = 0;
1204 // first operand is src too
1217 op->regmask_src |= op->regmask_dst;
1222 op->regmask_src |= op->regmask_dst;
1223 op->regmask_dst |= op->regmask_src;
1229 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1230 && op->operand[0].lmod == op->operand[1].lmod
1231 && op->operand[0].reg == op->operand[1].reg
1232 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1234 op->regmask_src = 0;
1237 op->regmask_src |= op->regmask_dst;
1240 // ops with implicit argumets
1242 op->operand_cnt = 2;
1243 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1244 op->regmask_dst = op->regmask_src;
1245 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1249 op->operand_cnt = 2;
1250 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1251 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1257 if (words[op_w][4] == 'b')
1259 else if (words[op_w][4] == 'w')
1261 else if (words[op_w][4] == 'd')
1264 op->regmask_src = 0;
1265 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1266 OPLM_DWORD, &op->regmask_src);
1267 op->regmask_dst = op->regmask_src;
1268 setup_reg_opr(&op->operand[j++], xAX, lmod,
1269 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1270 if (op->flags & OPF_REP) {
1271 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1272 op->regmask_dst |= 1 << xCX;
1274 op->operand_cnt = j;
1279 if (words[op_w][4] == 'b')
1281 else if (words[op_w][4] == 'w')
1283 else if (words[op_w][4] == 'd')
1286 op->regmask_src = 0;
1287 // note: lmod is not correct, don't have where to place it
1288 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1289 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1290 if (op->flags & OPF_REP)
1291 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1292 op->operand_cnt = j;
1293 op->regmask_dst = op->regmask_src;
1297 op->regmask_dst = 1 << xCX;
1300 op->operand_cnt = 2;
1301 op->regmask_src = 1 << xCX;
1302 op->operand[1].type = OPT_REG;
1303 op->operand[1].reg = xCX;
1304 op->operand[1].lmod = OPLM_DWORD;
1308 if (op->operand_cnt == 2) {
1309 if (op->operand[0].type != OPT_REG)
1310 aerr("reg expected\n");
1311 op->regmask_src |= 1 << op->operand[0].reg;
1313 if (op->operand_cnt != 1)
1318 op->regmask_src |= op->regmask_dst;
1319 op->regmask_dst = (1 << xDX) | (1 << xAX);
1320 if (op->operand[0].lmod == OPLM_UNSPEC)
1321 op->operand[0].lmod = OPLM_DWORD;
1326 // we could set up operands for edx:eax, but there is no real need to
1327 // (see is_opr_modified())
1328 op->regmask_src |= op->regmask_dst;
1329 op->regmask_dst = (1 << xDX) | (1 << xAX);
1330 if (op->operand[0].lmod == OPLM_UNSPEC)
1331 op->operand[0].lmod = OPLM_DWORD;
1339 op->regmask_src |= op->regmask_dst;
1340 if (op->operand[1].lmod == OPLM_UNSPEC)
1341 op->operand[1].lmod = OPLM_BYTE;
1346 op->regmask_src |= op->regmask_dst;
1347 if (op->operand[2].lmod == OPLM_UNSPEC)
1348 op->operand[2].lmod = OPLM_BYTE;
1352 op->regmask_src |= op->regmask_dst;
1353 op->regmask_dst = 0;
1354 if (op->operand[0].lmod == OPLM_UNSPEC
1355 && (op->operand[0].type == OPT_CONST
1356 || op->operand[0].type == OPT_OFFSET
1357 || op->operand[0].type == OPT_LABEL))
1358 op->operand[0].lmod = OPLM_DWORD;
1364 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1365 && op->operand[0].lmod == op->operand[1].lmod
1366 && op->operand[0].reg == op->operand[1].reg
1367 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1369 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1370 op->regmask_src = op->regmask_dst = 0;
1375 if (op->operand[0].type == OPT_REG
1376 && op->operand[1].type == OPT_REGMEM)
1379 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1380 if (IS(buf, op->operand[1].name))
1381 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1386 // trashed regs must be explicitly detected later
1387 op->regmask_dst = 0;
1391 op->regmask_dst = (1 << xBP) | (1 << xSP);
1392 op->regmask_src = 1 << xBP;
1397 op->regmask_dst |= mxST0;
1401 op->regmask_dst |= mxST0;
1402 if (IS(words[op_w] + 3, "1"))
1403 op->operand[0].val = X87_CONST_1;
1404 else if (IS(words[op_w] + 3, "ln2"))
1405 op->operand[0].val = X87_CONST_LN2;
1406 else if (IS(words[op_w] + 3, "z"))
1407 op->operand[0].val = X87_CONST_Z;
1414 op->regmask_src |= mxST0;
1423 op->regmask_src |= mxST0;
1424 if (op->operand_cnt == 2)
1425 op->regmask_src |= op->regmask_dst;
1426 else if (op->operand_cnt == 1) {
1427 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1428 op->operand[0].type = OPT_REG;
1429 op->operand[0].lmod = OPLM_QWORD;
1430 op->operand[0].reg = xST0;
1431 op->regmask_dst |= mxST0;
1434 // IDA doesn't use this
1435 aerr("no operands?\n");
1449 op->regmask_src |= mxST0;
1450 op->regmask_dst |= mxST0;
1455 op->regmask_src |= mxST0 | mxST1;
1456 op->regmask_dst |= mxST0;
1464 op->regmask_src |= mxST0;
1471 if (op->operand[0].type == OPT_REG
1472 && op->operand[1].type == OPT_CONST)
1474 struct parsed_opr *op1 = &op->operand[1];
1475 if ((op->op == OP_AND && op1->val == 0)
1478 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1479 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1481 op->regmask_src = 0;
1486 static const char *op_name(struct parsed_op *po)
1488 static char buf[16];
1492 if (po->op == OP_JCC || po->op == OP_SCC) {
1494 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1497 strcpy(p, parsed_flag_op_names[po->pfo]);
1501 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1502 if (op_table[i].op == po->op)
1503 return op_table[i].name;
1509 static const char *dump_op(struct parsed_op *po)
1511 static char out[128];
1518 snprintf(out, sizeof(out), "%s", op_name(po));
1519 for (i = 0; i < po->operand_cnt; i++) {
1523 snprintf(p, sizeof(out) - (p - out),
1524 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1525 po->operand[i].name);
1531 static const char *lmod_type_u(struct parsed_op *po,
1532 enum opr_lenmod lmod)
1544 ferr(po, "invalid lmod: %d\n", lmod);
1545 return "(_invalid_)";
1549 static const char *lmod_cast_u(struct parsed_op *po,
1550 enum opr_lenmod lmod)
1562 ferr(po, "invalid lmod: %d\n", lmod);
1563 return "(_invalid_)";
1567 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1568 enum opr_lenmod lmod)
1580 ferr(po, "invalid lmod: %d\n", lmod);
1581 return "(_invalid_)";
1585 static const char *lmod_cast_s(struct parsed_op *po,
1586 enum opr_lenmod lmod)
1598 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1599 return "(_invalid_)";
1603 static const char *lmod_cast(struct parsed_op *po,
1604 enum opr_lenmod lmod, int is_signed)
1607 lmod_cast_s(po, lmod) :
1608 lmod_cast_u(po, lmod);
1611 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1623 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1628 static const char *opr_name(struct parsed_op *po, int opr_num)
1630 if (opr_num >= po->operand_cnt)
1631 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1632 return po->operand[opr_num].name;
1635 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1637 if (opr_num >= po->operand_cnt)
1638 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1639 if (po->operand[opr_num].type != OPT_CONST)
1640 ferr(po, "opr %d: const expected\n", opr_num);
1641 return po->operand[opr_num].val;
1644 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1646 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1647 ferr(po, "invalid reg: %d\n", popr->reg);
1648 return regs_r32[popr->reg];
1651 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1653 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1655 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1657 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1659 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1664 *is_signed = cast[1] == 's' ? 1 : 0;
1668 static int check_deref_cast(const char *cast, int *bits)
1670 if (IS_START(cast, "*(u8 *)"))
1672 else if (IS_START(cast, "*(u16 *)"))
1674 else if (IS_START(cast, "*(u32 *)"))
1676 else if (IS_START(cast, "*(u64 *)"))
1684 // cast1 is the "final" cast
1685 static const char *simplify_cast(const char *cast1, const char *cast2)
1687 static char buf[256];
1695 if (IS(cast1, cast2))
1698 if (check_simple_cast(cast1, &bits1, &s1) == 0
1699 && check_simple_cast(cast2, &bits2, &s2) == 0)
1704 if (check_simple_cast(cast1, &bits1, &s1) == 0
1705 && check_deref_cast(cast2, &bits2) == 0)
1707 if (bits1 == bits2) {
1708 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1713 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1716 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1720 static const char *simplify_cast_num(const char *cast, unsigned int val)
1722 if (IS(cast, "(u8)") && val < 0x100)
1724 if (IS(cast, "(s8)") && val < 0x80)
1726 if (IS(cast, "(u16)") && val < 0x10000)
1728 if (IS(cast, "(s16)") && val < 0x8000)
1730 if (IS(cast, "(s32)") && val < 0x80000000)
1736 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1745 namelen = strlen(name);
1747 p = strpbrk(name, "+-");
1751 ferr(po, "equ parse failed for '%s'\n", name);
1753 *extra_offs = strtol(p, &endp, 16);
1755 ferr(po, "equ parse failed for '%s'\n", name);
1758 for (i = 0; i < g_eqcnt; i++)
1759 if (strncmp(g_eqs[i].name, name, namelen) == 0
1760 && g_eqs[i].name[namelen] == 0)
1764 ferr(po, "unresolved equ name: '%s'\n", name);
1771 static int is_stack_access(struct parsed_op *po,
1772 const struct parsed_opr *popr)
1774 return (parse_stack_el(popr->name, NULL, NULL, 0)
1775 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1776 && IS_START(popr->name, "ebp")));
1779 static void parse_stack_access(struct parsed_op *po,
1780 const char *name, char *ofs_reg, int *offset_out,
1781 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1783 const char *bp_arg = "";
1784 const char *p = NULL;
1785 struct parsed_equ *eq;
1792 if (IS_START(name, "ebp-")
1793 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1796 if (IS_START(p, "0x"))
1798 offset = strtoul(p, &endp, 16);
1802 ferr(po, "ebp- parse of '%s' failed\n", name);
1805 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1806 eq = equ_find(po, bp_arg, &offset);
1808 ferr(po, "detected but missing eq\n");
1809 offset += eq->offset;
1812 if (!strncmp(name, "ebp", 3))
1815 // yes it sometimes LEAs ra for compares..
1816 if (!is_lea && ofs_reg[0] == 0
1817 && stack_ra <= offset && offset < stack_ra + 4)
1819 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1822 *offset_out = offset;
1824 *stack_ra_out = stack_ra;
1826 *bp_arg_out = bp_arg;
1829 static int parse_stack_esp_offset(struct parsed_op *po,
1830 const char *name, int *offset_out)
1832 char ofs_reg[16] = { 0, };
1833 struct parsed_equ *eq;
1839 if (strstr(name, "esp") == NULL)
1841 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1842 if (bp_arg == NULL) {
1843 // just plain offset?
1844 if (!IS_START(name, "esp+"))
1846 offset = strtol(name + 4, &endp, 0);
1847 if (endp == NULL || *endp != 0)
1849 *offset_out = offset;
1853 if (ofs_reg[0] != 0)
1855 eq = equ_find(po, bp_arg, &offset);
1857 ferr(po, "detected but missing eq\n");
1858 offset += eq->offset;
1859 *offset_out = base_val + offset;
1863 static int stack_frame_access(struct parsed_op *po,
1864 struct parsed_opr *popr, char *buf, size_t buf_size,
1865 const char *name, const char *cast, int is_src, int is_lea)
1867 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1868 const char *prefix = "";
1869 const char *bp_arg = NULL;
1870 char ofs_reg[16] = { 0, };
1871 int i, arg_i, arg_s;
1878 if (po->flags & OPF_EBP_S)
1879 ferr(po, "stack_frame_access while ebp is scratch\n");
1881 parse_stack_access(po, name, ofs_reg, &offset,
1882 &stack_ra, &bp_arg, is_lea);
1884 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1886 if (offset > stack_ra)
1888 arg_i = (offset - stack_ra - 4) / 4;
1889 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1891 if (g_func_pp->is_vararg
1892 && arg_i == g_func_pp->argc_stack && is_lea)
1894 // should be va_list
1897 snprintf(buf, buf_size, "%sap", cast);
1900 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1901 offset, bp_arg, arg_i);
1903 if (ofs_reg[0] != 0)
1904 ferr(po, "offset reg on arg access?\n");
1906 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1907 if (g_func_pp->arg[i].reg != NULL)
1913 if (i == g_func_pp->argc)
1914 ferr(po, "arg %d not in prototype?\n", arg_i);
1916 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1923 ferr(po, "lea/byte to arg?\n");
1924 if (is_src && (offset & 3) == 0)
1925 snprintf(buf, buf_size, "%sa%d",
1926 simplify_cast(cast, "(u8)"), i + 1);
1928 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1929 cast, offset & 3, i + 1);
1934 ferr(po, "lea/word to arg?\n");
1939 ferr(po, "problematic arg store\n");
1940 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1941 simplify_cast(cast, "*(u16 *)"), i + 1);
1944 ferr(po, "unaligned arg word load\n");
1946 else if (is_src && (offset & 2) == 0)
1947 snprintf(buf, buf_size, "%sa%d",
1948 simplify_cast(cast, "(u16)"), i + 1);
1950 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1951 cast, (offset & 2) ? "HI" : "LO", i + 1);
1963 snprintf(buf, buf_size, "(u32)&a%d + %d",
1966 ferr(po, "unaligned arg store\n");
1968 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1969 snprintf(buf, buf_size, "%s(a%d >> %d)",
1970 prefix, i + 1, (offset & 3) * 8);
1974 snprintf(buf, buf_size, "%s%sa%d",
1975 prefix, is_lea ? "&" : "", i + 1);
1980 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1984 strcat(g_comment, " unaligned");
1987 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
1988 if (tmp_lmod != OPLM_DWORD
1989 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
1990 < lmod_bytes(po, popr->lmod) + (offset & 3))))
1992 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
1993 i + 1, offset, g_func_pp->arg[i].type.name);
1995 // can't check this because msvc likes to reuse
1996 // arg space for scratch..
1997 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
1998 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2002 if (g_stack_fsz == 0)
2003 ferr(po, "stack var access without stackframe\n");
2004 g_stack_frame_used = 1;
2006 sf_ofs = g_stack_fsz + offset;
2007 if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2008 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2018 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2019 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2023 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2024 // known unaligned or possibly unaligned
2025 strcat(g_comment, " unaligned");
2027 prefix = "*(u16 *)&";
2028 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2029 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2032 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2036 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2037 // known unaligned or possibly unaligned
2038 strcat(g_comment, " unaligned");
2040 prefix = "*(u32 *)&";
2041 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2042 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2045 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2049 ferr_assert(po, !(sf_ofs & 7));
2050 ferr_assert(po, ofs_reg[0] == 0);
2051 // only used for x87 int64/float, float sets is_lea
2053 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2055 snprintf(buf, buf_size, "*(s64 *)&sf.q[%d]", sf_ofs / 8);
2059 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2066 static void check_func_pp(struct parsed_op *po,
2067 const struct parsed_proto *pp, const char *pfx)
2069 enum opr_lenmod tmp_lmod;
2073 if (pp->argc_reg != 0) {
2074 if (!g_allow_user_icall && !pp->is_fastcall) {
2075 pp_print(buf, sizeof(buf), pp);
2076 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2078 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2079 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2080 pfx, pp->argc_reg, pp->argc_stack);
2083 // fptrs must use 32bit args, callsite might have no information and
2084 // lack a cast to smaller types, which results in incorrectly masked
2085 // args passed (callee may assume masked args, it does on ARM)
2086 if (!pp->is_osinc) {
2087 for (i = 0; i < pp->argc; i++) {
2088 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2089 if (ret && tmp_lmod != OPLM_DWORD)
2090 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2091 i + 1, pp->arg[i].type.name);
2096 static const char *check_label_read_ref(struct parsed_op *po,
2099 const struct parsed_proto *pp;
2101 pp = proto_parse(g_fhdr, name, 0);
2103 ferr(po, "proto_parse failed for ref '%s'\n", name);
2106 check_func_pp(po, pp, "ref");
2111 static char *out_src_opr(char *buf, size_t buf_size,
2112 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2115 char tmp1[256], tmp2[256];
2124 switch (popr->type) {
2127 ferr(po, "lea from reg?\n");
2129 switch (popr->lmod) {
2131 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2134 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2137 snprintf(buf, buf_size, "%s%s",
2138 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2141 if (popr->name[1] == 'h') // XXX..
2142 snprintf(buf, buf_size, "%s(%s >> 8)",
2143 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2145 snprintf(buf, buf_size, "%s%s",
2146 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2149 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2154 if (is_stack_access(po, popr)) {
2155 stack_frame_access(po, popr, buf, buf_size,
2156 popr->name, cast, 1, is_lea);
2160 strcpy(expr, popr->name);
2161 if (strchr(expr, '[')) {
2162 // special case: '[' can only be left for label[reg] form
2163 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2165 ferr(po, "parse failure for '%s'\n", expr);
2166 if (tmp1[0] == '(') {
2167 // (off_4FFF50+3)[eax]
2168 p = strchr(tmp1 + 1, ')');
2169 if (p == NULL || p[1] != 0)
2170 ferr(po, "parse failure (2) for '%s'\n", expr);
2172 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2174 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2177 // XXX: do we need more parsing?
2179 snprintf(buf, buf_size, "%s", expr);
2183 snprintf(buf, buf_size, "%s(%s)",
2184 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2188 name = check_label_read_ref(po, popr->name);
2189 if (cast[0] == 0 && popr->is_ptr)
2193 snprintf(buf, buf_size, "(u32)&%s", name);
2194 else if (popr->size_lt)
2195 snprintf(buf, buf_size, "%s%s%s%s", cast,
2196 lmod_cast_u_ptr(po, popr->lmod),
2197 popr->is_array ? "" : "&", name);
2199 snprintf(buf, buf_size, "%s%s%s", cast, name,
2200 popr->is_array ? "[0]" : "");
2204 name = check_label_read_ref(po, popr->name);
2208 ferr(po, "lea an offset?\n");
2209 snprintf(buf, buf_size, "%s&%s", cast, name);
2214 ferr(po, "lea from const?\n");
2216 printf_number(tmp1, sizeof(tmp1), popr->val);
2217 if (popr->val == 0 && strchr(cast, '*'))
2218 snprintf(buf, buf_size, "NULL");
2220 snprintf(buf, buf_size, "%s%s",
2221 simplify_cast_num(cast, popr->val), tmp1);
2225 ferr(po, "invalid src type: %d\n", popr->type);
2231 // note: may set is_ptr (we find that out late for ebp frame..)
2232 static char *out_dst_opr(char *buf, size_t buf_size,
2233 struct parsed_op *po, struct parsed_opr *popr)
2235 switch (popr->type) {
2237 switch (popr->lmod) {
2239 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2242 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2246 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2250 if (popr->name[1] == 'h') // XXX..
2251 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2253 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2256 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2261 if (is_stack_access(po, popr)) {
2262 stack_frame_access(po, popr, buf, buf_size,
2263 popr->name, "", 0, 0);
2267 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2270 if (popr->size_mismatch)
2271 snprintf(buf, buf_size, "%s%s%s",
2272 lmod_cast_u_ptr(po, popr->lmod),
2273 popr->is_array ? "" : "&", popr->name);
2275 snprintf(buf, buf_size, "%s%s", popr->name,
2276 popr->is_array ? "[0]" : "");
2280 ferr(po, "invalid dst type: %d\n", popr->type);
2286 static char *out_src_opr_u32(char *buf, size_t buf_size,
2287 struct parsed_op *po, struct parsed_opr *popr)
2289 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2292 static char *out_src_opr_float(char *buf, size_t buf_size,
2293 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2295 const char *cast = NULL;
2298 switch (popr->type) {
2300 if (popr->reg < xST0 || popr->reg > xST7)
2301 ferr(po, "bad reg: %d\n", popr->reg);
2303 if (need_float_stack) {
2304 if (popr->reg == xST0)
2305 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2307 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2311 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2317 switch (popr->lmod) {
2325 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2328 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2329 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2333 ferr(po, "invalid float type: %d\n", popr->type);
2339 static char *out_dst_opr_float(char *buf, size_t buf_size,
2340 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2343 return out_src_opr_float(buf, buf_size, po, popr, need_float_stack);
2346 static void out_test_for_cc(char *buf, size_t buf_size,
2347 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2348 enum opr_lenmod lmod, const char *expr)
2350 const char *cast, *scast;
2352 cast = lmod_cast_u(po, lmod);
2353 scast = lmod_cast_s(po, lmod);
2357 case PFO_BE: // CF==1||ZF==1; CF=0
2358 snprintf(buf, buf_size, "(%s%s %s 0)",
2359 cast, expr, is_inv ? "!=" : "==");
2363 case PFO_L: // SF!=OF; OF=0
2364 snprintf(buf, buf_size, "(%s%s %s 0)",
2365 scast, expr, is_inv ? ">=" : "<");
2368 case PFO_LE: // ZF==1||SF!=OF; OF=0
2369 snprintf(buf, buf_size, "(%s%s %s 0)",
2370 scast, expr, is_inv ? ">" : "<=");
2375 snprintf(buf, buf_size, "(%d)", !!is_inv);
2379 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2383 static void out_cmp_for_cc(char *buf, size_t buf_size,
2384 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2387 const char *cast, *scast, *cast_use;
2388 char buf1[256], buf2[256];
2389 enum opr_lenmod lmod;
2391 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2392 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2393 po->operand[0].lmod, po->operand[1].lmod);
2394 lmod = po->operand[0].lmod;
2396 cast = lmod_cast_u(po, lmod);
2397 scast = lmod_cast_s(po, lmod);
2413 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2416 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2417 if (po->op == OP_DEC)
2418 snprintf(buf2, sizeof(buf2), "1");
2421 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2423 strcat(cast_op2, "-");
2424 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2429 // note: must be unsigned compare
2430 snprintf(buf, buf_size, "(%s %s %s)",
2431 buf1, is_inv ? ">=" : "<", buf2);
2435 snprintf(buf, buf_size, "(%s %s %s)",
2436 buf1, is_inv ? "!=" : "==", buf2);
2440 // note: must be unsigned compare
2441 snprintf(buf, buf_size, "(%s %s %s)",
2442 buf1, is_inv ? ">" : "<=", buf2);
2445 if (is_inv && lmod == OPLM_BYTE
2446 && po->operand[1].type == OPT_CONST
2447 && po->operand[1].val == 0xff)
2449 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2450 snprintf(buf, buf_size, "(0)");
2454 // note: must be signed compare
2456 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2457 scast, buf1, buf2, is_inv ? ">=" : "<");
2461 snprintf(buf, buf_size, "(%s %s %s)",
2462 buf1, is_inv ? ">=" : "<", buf2);
2466 snprintf(buf, buf_size, "(%s %s %s)",
2467 buf1, is_inv ? ">" : "<=", buf2);
2475 static void out_cmp_test(char *buf, size_t buf_size,
2476 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2478 char buf1[256], buf2[256], buf3[256];
2480 if (po->op == OP_TEST) {
2481 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2482 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2485 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2486 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2487 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2489 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2490 po->operand[0].lmod, buf3);
2492 else if (po->op == OP_CMP) {
2493 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2496 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2499 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2500 struct parsed_opr *popr2)
2502 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2503 ferr(po, "missing lmod for both operands\n");
2505 if (popr1->lmod == OPLM_UNSPEC)
2506 popr1->lmod = popr2->lmod;
2507 else if (popr2->lmod == OPLM_UNSPEC)
2508 popr2->lmod = popr1->lmod;
2509 else if (popr1->lmod != popr2->lmod) {
2510 if (popr1->type_from_var) {
2511 popr1->size_mismatch = 1;
2512 if (popr1->lmod < popr2->lmod)
2514 popr1->lmod = popr2->lmod;
2516 else if (popr2->type_from_var) {
2517 popr2->size_mismatch = 1;
2518 if (popr2->lmod < popr1->lmod)
2520 popr2->lmod = popr1->lmod;
2523 ferr(po, "conflicting lmods: %d vs %d\n",
2524 popr1->lmod, popr2->lmod);
2528 static const char *op_to_c(struct parsed_op *po)
2552 ferr(po, "op_to_c was supplied with %d\n", po->op);
2556 // last op in stream - unconditional branch or ret
2557 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2558 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2559 && ops[_i].op != OP_CALL))
2561 #define check_i(po, i) \
2563 ferr(po, "bad " #i ": %d\n", i)
2565 // note: this skips over calls and rm'd stuff assuming they're handled
2566 // so it's intended to use at one of final passes
2567 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2568 int depth, int seen_noreturn, int flags_set)
2570 struct parsed_op *po;
2575 for (; i < opcnt; i++) {
2577 if (po->cc_scratch == magic)
2578 return ret; // already checked
2579 po->cc_scratch = magic;
2581 if (po->flags & OPF_TAIL) {
2582 if (po->op == OP_CALL) {
2583 if (po->pp != NULL && po->pp->is_noreturn)
2589 return -1; // deadend
2592 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2595 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2596 if (po->btj != NULL) {
2598 for (j = 0; j < po->btj->count; j++) {
2599 check_i(po, po->btj->d[j].bt_i);
2600 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2601 depth, seen_noreturn, flags_set);
2603 return ret; // dead end
2608 check_i(po, po->bt_i);
2609 if (po->flags & OPF_CJMP) {
2610 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2611 depth, seen_noreturn, flags_set);
2613 return ret; // dead end
2622 if ((po->op == OP_POP || po->op == OP_PUSH)
2623 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2628 if (po->op == OP_PUSH) {
2631 else if (po->op == OP_POP) {
2632 if (relevant && depth == 0) {
2633 po->flags |= flags_set;
2640 // for noreturn, assume msvc skipped stack cleanup
2641 return seen_noreturn ? 1 : -1;
2644 // scan for 'reg' pop backwards starting from i
2645 // intended to use for register restore search, so other reg
2646 // references are considered an error
2647 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2649 struct parsed_op *po;
2650 struct label_ref *lr;
2653 ops[i].cc_scratch = magic;
2657 if (g_labels[i] != NULL) {
2658 lr = &g_label_refs[i];
2659 for (; lr != NULL; lr = lr->next) {
2660 check_i(&ops[i], lr->i);
2661 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2665 if (i > 0 && LAST_OP(i - 1))
2673 if (ops[i].cc_scratch == magic)
2675 ops[i].cc_scratch = magic;
2678 if (po->op == OP_POP && po->operand[0].reg == reg) {
2679 if (po->flags & (OPF_RMD|OPF_DONE))
2682 po->flags |= set_flags;
2686 // this also covers the case where we reach corresponding push
2687 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2691 // nothing interesting on this path
2695 static void find_reachable_exits(int i, int opcnt, int magic,
2696 int *exits, int *exit_count)
2698 struct parsed_op *po;
2701 for (; i < opcnt; i++)
2704 if (po->cc_scratch == magic)
2706 po->cc_scratch = magic;
2708 if (po->flags & OPF_TAIL) {
2709 ferr_assert(po, *exit_count < MAX_EXITS);
2710 exits[*exit_count] = i;
2715 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2716 if (po->flags & OPF_RMD)
2719 if (po->btj != NULL) {
2720 for (j = 0; j < po->btj->count; j++) {
2721 check_i(po, po->btj->d[j].bt_i);
2722 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2728 check_i(po, po->bt_i);
2729 if (po->flags & OPF_CJMP)
2730 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2738 // scan for 'reg' pop backwards starting from exits (all paths)
2739 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2741 static int exits[MAX_EXITS];
2742 static int exit_count;
2747 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2749 ferr_assert(&ops[i], exit_count > 0);
2752 for (j = 0; j < exit_count; j++) {
2753 ret = scan_for_rsave_pop_reg(exits[j], i + opcnt * 16 + set_flags,
2762 // scan for one or more pop of push <const>
2763 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2764 int push_i, int is_probe)
2766 struct parsed_op *po;
2767 struct label_ref *lr;
2771 for (; i < opcnt; i++)
2774 if (po->cc_scratch == magic)
2775 return ret; // already checked
2776 po->cc_scratch = magic;
2778 if (po->flags & OPF_JMP) {
2779 if (po->flags & OPF_RMD)
2781 if (po->op == OP_CALL)
2784 if (po->btj != NULL) {
2785 for (j = 0; j < po->btj->count; j++) {
2786 check_i(po, po->btj->d[j].bt_i);
2787 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2795 check_i(po, po->bt_i);
2796 if (po->flags & OPF_CJMP) {
2797 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2808 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2811 if (g_labels[i] != NULL) {
2812 // all refs must be visited
2813 lr = &g_label_refs[i];
2814 for (; lr != NULL; lr = lr->next) {
2816 if (ops[lr->i].cc_scratch != magic)
2819 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2823 if (po->op == OP_POP)
2825 if (po->flags & (OPF_RMD|OPF_DONE))
2829 po->flags |= OPF_DONE;
2830 po->datap = &ops[push_i];
2839 static void scan_for_pop_const(int i, int opcnt, int magic)
2843 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2845 ops[i].flags |= OPF_RMD | OPF_DONE;
2846 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2850 // check if all branch targets within a marked path are also marked
2851 // note: the path checked must not be empty or end with a branch
2852 static int check_path_branches(int opcnt, int magic)
2854 struct parsed_op *po;
2857 for (i = 0; i < opcnt; i++) {
2859 if (po->cc_scratch != magic)
2862 if (po->flags & OPF_JMP) {
2863 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2866 if (po->btj != NULL) {
2867 for (j = 0; j < po->btj->count; j++) {
2868 check_i(po, po->btj->d[j].bt_i);
2869 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2874 check_i(po, po->bt_i);
2875 if (ops[po->bt_i].cc_scratch != magic)
2877 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2885 // scan for multiple pushes for given pop
2886 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2889 int reg = ops[pop_i].operand[0].reg;
2890 struct parsed_op *po;
2891 struct label_ref *lr;
2894 ops[i].cc_scratch = magic;
2898 if (g_labels[i] != NULL) {
2899 lr = &g_label_refs[i];
2900 for (; lr != NULL; lr = lr->next) {
2901 check_i(&ops[i], lr->i);
2902 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2906 if (i > 0 && LAST_OP(i - 1))
2914 if (ops[i].cc_scratch == magic)
2916 ops[i].cc_scratch = magic;
2919 if (po->op == OP_CALL)
2921 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2924 if (po->op == OP_PUSH)
2926 if (po->datap != NULL)
2928 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2929 // leave this case for reg save/restore handlers
2933 po->flags |= OPF_PPUSH | OPF_DONE;
2934 po->datap = &ops[pop_i];
2943 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2945 int magic = i + opcnt * 14;
2948 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2950 ret = check_path_branches(opcnt, magic);
2952 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2953 *regmask_pp |= 1 << ops[i].operand[0].reg;
2954 scan_pushes_for_pop_r(i, magic + 1, i, 0);
2959 static void scan_propagate_df(int i, int opcnt)
2961 struct parsed_op *po = &ops[i];
2964 for (; i < opcnt; i++) {
2966 if (po->flags & OPF_DF)
2967 return; // already resolved
2968 po->flags |= OPF_DF;
2970 if (po->op == OP_CALL)
2971 ferr(po, "call with DF set?\n");
2973 if (po->flags & OPF_JMP) {
2974 if (po->btj != NULL) {
2976 for (j = 0; j < po->btj->count; j++) {
2977 check_i(po, po->btj->d[j].bt_i);
2978 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
2983 if (po->flags & OPF_RMD)
2985 check_i(po, po->bt_i);
2986 if (po->flags & OPF_CJMP)
2987 scan_propagate_df(po->bt_i, opcnt);
2993 if (po->flags & OPF_TAIL)
2996 if (po->op == OP_CLD) {
2997 po->flags |= OPF_RMD | OPF_DONE;
3002 ferr(po, "missing DF clear?\n");
3005 // is operand 'opr' referenced by parsed_op 'po'?
3006 static int is_opr_referenced(const struct parsed_opr *opr,
3007 const struct parsed_op *po)
3011 if (opr->type == OPT_REG) {
3012 mask = po->regmask_dst | po->regmask_src;
3013 if (po->op == OP_CALL)
3014 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3015 if ((1 << opr->reg) & mask)
3021 for (i = 0; i < po->operand_cnt; i++)
3022 if (IS(po->operand[0].name, opr->name))
3028 // is operand 'opr' read by parsed_op 'po'?
3029 static int is_opr_read(const struct parsed_opr *opr,
3030 const struct parsed_op *po)
3032 if (opr->type == OPT_REG) {
3033 if (po->regmask_src & (1 << opr->reg))
3043 // is operand 'opr' modified by parsed_op 'po'?
3044 static int is_opr_modified(const struct parsed_opr *opr,
3045 const struct parsed_op *po)
3049 if (opr->type == OPT_REG) {
3050 if (po->op == OP_CALL) {
3051 mask = po->regmask_dst;
3052 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3053 if (mask & (1 << opr->reg))
3059 if (po->regmask_dst & (1 << opr->reg))
3065 return IS(po->operand[0].name, opr->name);
3068 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3069 static int is_any_opr_modified(const struct parsed_op *po_test,
3070 const struct parsed_op *po, int c_mode)
3075 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3078 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3081 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3084 // in reality, it can wreck any register, but in decompiled C
3085 // version it can only overwrite eax or edx:eax
3086 mask = (1 << xAX) | (1 << xDX);
3090 if (po->op == OP_CALL
3091 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3094 for (i = 0; i < po_test->operand_cnt; i++)
3095 if (IS(po_test->operand[i].name, po->operand[0].name))
3101 // scan for any po_test operand modification in range given
3102 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3105 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3108 for (; i < opcnt; i++) {
3109 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3116 // scan for po_test operand[0] modification in range given
3117 static int scan_for_mod_opr0(struct parsed_op *po_test,
3120 for (; i < opcnt; i++) {
3121 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3128 static int try_resolve_const(int i, const struct parsed_opr *opr,
3129 int magic, unsigned int *val);
3131 static int scan_for_flag_set(int i, int opcnt, int magic,
3132 int *branched, int *setters, int *setter_cnt)
3134 struct label_ref *lr;
3138 if (ops[i].cc_scratch == magic) {
3139 // is this a problem?
3140 //ferr(&ops[i], "%s looped\n", __func__);
3143 ops[i].cc_scratch = magic;
3145 if (g_labels[i] != NULL) {
3148 lr = &g_label_refs[i];
3149 for (; lr->next; lr = lr->next) {
3150 check_i(&ops[i], lr->i);
3151 ret = scan_for_flag_set(lr->i, opcnt, magic,
3152 branched, setters, setter_cnt);
3157 check_i(&ops[i], lr->i);
3158 if (i > 0 && LAST_OP(i - 1)) {
3162 ret = scan_for_flag_set(lr->i, opcnt, magic,
3163 branched, setters, setter_cnt);
3169 if (ops[i].flags & OPF_FLAGS) {
3170 setters[*setter_cnt] = i;
3173 if (ops[i].flags & OPF_REP) {
3174 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3177 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3178 if (ret != 1 || uval == 0) {
3179 // can't treat it as full setter because of ecx=0 case,
3180 // also disallow delayed compare
3189 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3196 // scan back for cdq, if anything modifies edx, fail
3197 static int scan_for_cdq_edx(int i)
3200 if (g_labels[i] != NULL) {
3201 if (g_label_refs[i].next != NULL)
3203 if (i > 0 && LAST_OP(i - 1)) {
3204 i = g_label_refs[i].i;
3211 if (ops[i].op == OP_CDQ)
3214 if (ops[i].regmask_dst & (1 << xDX))
3221 static int scan_for_reg_clear(int i, int reg)
3224 if (g_labels[i] != NULL) {
3225 if (g_label_refs[i].next != NULL)
3227 if (i > 0 && LAST_OP(i - 1)) {
3228 i = g_label_refs[i].i;
3235 if (ops[i].op == OP_XOR
3236 && ops[i].operand[0].lmod == OPLM_DWORD
3237 && ops[i].operand[0].reg == ops[i].operand[1].reg
3238 && ops[i].operand[0].reg == reg)
3241 if (ops[i].regmask_dst & (1 << reg))
3248 static void patch_esp_adjust(struct parsed_op *po, int adj)
3250 ferr_assert(po, po->op == OP_ADD);
3251 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3252 ferr_assert(po, po->operand[1].type == OPT_CONST);
3254 // this is a bit of a hack, but deals with use of
3255 // single adj for multiple calls
3256 po->operand[1].val -= adj;
3257 po->flags |= OPF_RMD;
3258 if (po->operand[1].val == 0)
3259 po->flags |= OPF_DONE;
3260 ferr_assert(po, (int)po->operand[1].val >= 0);
3263 // scan for positive, constant esp adjust
3264 // multipath case is preliminary
3265 static int scan_for_esp_adjust(int i, int opcnt,
3266 int adj_expect, int *adj, int *is_multipath, int do_update)
3268 int adj_expect_unknown = 0;
3269 struct parsed_op *po;
3273 *adj = *is_multipath = 0;
3274 if (adj_expect < 0) {
3275 adj_expect_unknown = 1;
3276 adj_expect = 32 * 4; // enough?
3279 for (; i < opcnt && *adj < adj_expect; i++) {
3280 if (g_labels[i] != NULL)
3284 if (po->flags & OPF_DONE)
3287 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3288 if (po->operand[1].type != OPT_CONST)
3289 ferr(&ops[i], "non-const esp adjust?\n");
3290 *adj += po->operand[1].val;
3292 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3295 patch_esp_adjust(po, adj_expect);
3297 po->flags |= OPF_RMD;
3301 else if (po->op == OP_PUSH) {
3302 //if (first_pop == -1)
3303 // first_pop = -2; // none
3304 *adj -= lmod_bytes(po, po->operand[0].lmod);
3306 else if (po->op == OP_POP) {
3307 if (!(po->flags & OPF_DONE)) {
3308 // seems like msvc only uses 'pop ecx' for stack realignment..
3309 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3311 if (first_pop == -1 && *adj >= 0)
3314 if (do_update && *adj >= 0) {
3315 po->flags |= OPF_RMD;
3317 po->flags |= OPF_DONE | OPF_NOREGS;
3320 *adj += lmod_bytes(po, po->operand[0].lmod);
3321 if (*adj > adj_best)
3324 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3325 if (po->op == OP_JMP && po->btj == NULL) {
3331 if (po->op != OP_CALL)
3333 if (po->operand[0].type != OPT_LABEL)
3335 if (po->pp != NULL && po->pp->is_stdcall)
3337 if (adj_expect_unknown && first_pop >= 0)
3339 // assume it's another cdecl call
3343 if (first_pop >= 0) {
3344 // probably only 'pop ecx' was used
3352 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3354 struct parsed_op *po;
3358 ferr(ops, "%s: followed bad branch?\n", __func__);
3360 for (; i < opcnt; i++) {
3362 if (po->cc_scratch == magic)
3364 po->cc_scratch = magic;
3367 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3368 if (po->btj != NULL) {
3370 for (j = 0; j < po->btj->count; j++)
3371 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3375 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3376 if (!(po->flags & OPF_CJMP))
3379 if (po->flags & OPF_TAIL)
3384 static const struct parsed_proto *try_recover_pp(
3385 struct parsed_op *po, const struct parsed_opr *opr,
3386 int is_call, int *search_instead)
3388 const struct parsed_proto *pp = NULL;
3392 // maybe an arg of g_func?
3393 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3395 char ofs_reg[16] = { 0, };
3396 int arg, arg_s, arg_i;
3403 parse_stack_access(po, opr->name, ofs_reg,
3404 &offset, &stack_ra, NULL, 0);
3405 if (ofs_reg[0] != 0)
3406 ferr(po, "offset reg on arg access?\n");
3407 if (offset <= stack_ra) {
3408 // search who set the stack var instead
3409 if (search_instead != NULL)
3410 *search_instead = 1;
3414 arg_i = (offset - stack_ra - 4) / 4;
3415 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3416 if (g_func_pp->arg[arg].reg != NULL)
3422 if (arg == g_func_pp->argc)
3423 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3425 pp = g_func_pp->arg[arg].pp;
3428 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3429 check_func_pp(po, pp, "icall arg");
3432 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3434 p = strchr(opr->name + 1, '[');
3435 memcpy(buf, opr->name, p - opr->name);
3436 buf[p - opr->name] = 0;
3437 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3439 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3440 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3443 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3446 check_func_pp(po, pp, "reg-fptr ref");
3452 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3453 int magic, const struct parsed_proto **pp_found, int *pp_i,
3456 const struct parsed_proto *pp = NULL;
3457 struct parsed_op *po;
3458 struct label_ref *lr;
3460 ops[i].cc_scratch = magic;
3463 if (g_labels[i] != NULL) {
3464 lr = &g_label_refs[i];
3465 for (; lr != NULL; lr = lr->next) {
3466 check_i(&ops[i], lr->i);
3467 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3469 if (i > 0 && LAST_OP(i - 1))
3477 if (ops[i].cc_scratch == magic)
3479 ops[i].cc_scratch = magic;
3481 if (!(ops[i].flags & OPF_DATA))
3483 if (!is_opr_modified(opr, &ops[i]))
3485 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3486 // most probably trashed by some processing
3491 opr = &ops[i].operand[1];
3492 if (opr->type != OPT_REG)
3496 po = (i >= 0) ? &ops[i] : ops;
3499 // reached the top - can only be an arg-reg
3500 if (opr->type != OPT_REG || g_func_pp == NULL)
3503 for (i = 0; i < g_func_pp->argc; i++) {
3504 if (g_func_pp->arg[i].reg == NULL)
3506 if (IS(opr->name, g_func_pp->arg[i].reg))
3509 if (i == g_func_pp->argc)
3511 pp = g_func_pp->arg[i].pp;
3513 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3514 i + 1, g_func_pp->arg[i].reg);
3515 check_func_pp(po, pp, "icall reg-arg");
3518 pp = try_recover_pp(po, opr, 1, NULL);
3520 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3521 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3522 || (*pp_found)->is_stdcall != pp->is_stdcall
3523 || (*pp_found)->is_fptr != pp->is_fptr
3524 || (*pp_found)->argc != pp->argc
3525 || (*pp_found)->argc_reg != pp->argc_reg
3526 || (*pp_found)->argc_stack != pp->argc_stack)
3528 ferr(po, "icall: parsed_proto mismatch\n");
3538 static void add_label_ref(struct label_ref *lr, int op_i)
3540 struct label_ref *lr_new;
3547 lr_new = calloc(1, sizeof(*lr_new));
3549 lr_new->next = lr->next;
3553 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3555 struct parsed_op *po = &ops[i];
3556 struct parsed_data *pd;
3557 char label[NAMELEN], *p;
3560 p = strchr(po->operand[0].name, '[');
3564 len = p - po->operand[0].name;
3565 strncpy(label, po->operand[0].name, len);
3568 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3569 if (IS(g_func_pd[j].label, label)) {
3575 //ferr(po, "label '%s' not parsed?\n", label);
3578 if (pd->type != OPT_OFFSET)
3579 ferr(po, "label '%s' with non-offset data?\n", label);
3581 // find all labels, link
3582 for (j = 0; j < pd->count; j++) {
3583 for (l = 0; l < opcnt; l++) {
3584 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3585 add_label_ref(&g_label_refs[l], i);
3595 static void clear_labels(int count)
3599 for (i = 0; i < count; i++) {
3600 if (g_labels[i] != NULL) {
3607 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3612 for (i = 0; i < pp->argc; i++) {
3613 if (pp->arg[i].reg != NULL) {
3614 reg = char_array_i(regs_r32,
3615 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3617 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3618 pp->arg[i].reg, pp->name);
3619 regmask |= 1 << reg;
3626 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3631 if (pp->has_retreg) {
3632 for (i = 0; i < pp->argc; i++) {
3633 if (pp->arg[i].type.is_retreg) {
3634 reg = char_array_i(regs_r32,
3635 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3636 ferr_assert(ops, reg >= 0);
3637 regmask |= 1 << reg;
3642 if (strstr(pp->ret_type.name, "int64"))
3643 return regmask | (1 << xAX) | (1 << xDX);
3644 if (IS(pp->ret_type.name, "float")
3645 || IS(pp->ret_type.name, "double"))
3647 return regmask | mxST0;
3649 if (strcasecmp(pp->ret_type.name, "void") == 0)
3652 return regmask | mxAX;
3655 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3657 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3658 && memcmp(po1->operand, po2->operand,
3659 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3662 static void resolve_branches_parse_calls(int opcnt)
3664 static const struct {
3668 unsigned int regmask_src;
3669 unsigned int regmask_dst;
3671 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3672 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3673 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3674 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3676 const struct parsed_proto *pp_c;
3677 struct parsed_proto *pp;
3678 struct parsed_data *pd;
3679 struct parsed_op *po;
3680 const char *tmpname;
3684 for (i = 0; i < opcnt; i++)
3690 if (po->datap != NULL) {
3691 pp = calloc(1, sizeof(*pp));
3692 my_assert_not(pp, NULL);
3694 ret = parse_protostr(po->datap, pp);
3696 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3702 if (po->op == OP_CALL) {
3707 else if (po->operand[0].type == OPT_LABEL)
3709 tmpname = opr_name(po, 0);
3710 if (IS_START(tmpname, "loc_"))
3711 ferr(po, "call to loc_*\n");
3712 if (IS(tmpname, "__alloca_probe"))
3715 // convert some calls to pseudo-ops
3716 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3717 if (!IS(tmpname, pseudo_ops[l].name))
3720 po->op = pseudo_ops[l].op;
3721 po->operand_cnt = 0;
3722 po->regmask_src = pseudo_ops[l].regmask_src;
3723 po->regmask_dst = pseudo_ops[l].regmask_dst;
3724 po->flags = pseudo_ops[l].flags;
3725 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3728 if (l < ARRAY_SIZE(pseudo_ops))
3731 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3732 if (!g_header_mode && pp_c == NULL)
3733 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3736 pp = proto_clone(pp_c);
3737 my_assert_not(pp, NULL);
3743 check_func_pp(po, pp, "fptr var call");
3744 if (pp->is_noreturn)
3745 po->flags |= OPF_TAIL;
3751 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3754 if (po->operand[0].type == OPT_REGMEM) {
3755 pd = try_resolve_jumptab(i, opcnt);
3763 for (l = 0; l < opcnt; l++) {
3764 if (g_labels[l] != NULL
3765 && IS(po->operand[0].name, g_labels[l]))
3767 if (l == i + 1 && po->op == OP_JMP) {
3768 // yet another alignment type..
3769 po->flags |= OPF_RMD|OPF_DONE;
3772 add_label_ref(&g_label_refs[l], i);
3778 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3781 if (po->operand[0].type == OPT_LABEL)
3785 ferr(po, "unhandled branch\n");
3789 po->flags |= OPF_TAIL;
3790 if (i > 0 && ops[i - 1].op == OP_POP)
3791 po->flags |= OPF_ATAIL;
3796 static void scan_prologue_epilogue(int opcnt)
3798 int ecx_push = 0, esp_sub = 0, pusha = 0;
3799 int sandard_epilogue;
3803 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3804 && ops[1].op == OP_MOV
3805 && IS(opr_name(&ops[1], 0), "ebp")
3806 && IS(opr_name(&ops[1], 1), "esp"))
3809 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3810 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3813 if (ops[i].op == OP_PUSHA) {
3814 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3819 if (ops[i].op == OP_SUB && IS(opr_name(&ops[i], 0), "esp")) {
3820 g_stack_fsz = opr_const(&ops[i], 1);
3821 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3825 // another way msvc builds stack frame..
3826 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3828 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3832 // and another way..
3833 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3834 && ops[i].operand[1].type == OPT_CONST
3835 && ops[i + 1].op == OP_CALL
3836 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3838 g_stack_fsz += ops[i].operand[1].val;
3839 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3841 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3848 for (; i < opcnt; i++)
3849 if (ops[i].flags & OPF_TAIL)
3852 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3853 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3859 sandard_epilogue = 0;
3860 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3862 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3863 // the standard epilogue is sometimes even used without a sf
3864 if (ops[j - 1].op == OP_MOV
3865 && IS(opr_name(&ops[j - 1], 0), "esp")
3866 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3867 sandard_epilogue = 1;
3869 else if (ops[j].op == OP_LEAVE)
3871 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3872 sandard_epilogue = 1;
3874 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3875 && ops[i].pp->is_noreturn)
3877 // on noreturn, msvc sometimes cleans stack, sometimes not
3882 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3883 ferr(&ops[j], "'pop ebp' expected\n");
3885 if (g_stack_fsz != 0 || sandard_epilogue) {
3886 if (ops[j].op == OP_LEAVE)
3888 else if (sandard_epilogue) // mov esp, ebp
3890 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3893 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3895 ferr(&ops[j], "esp restore expected\n");
3898 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3899 && IS(opr_name(&ops[j], 0), "ecx"))
3901 ferr(&ops[j], "unexpected ecx pop\n");
3906 if (ops[j].op == OP_POPA)
3907 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3909 ferr(&ops[j], "popa expected\n");
3914 } while (i < opcnt);
3917 ferr(ops, "missing ebp epilogue\n");
3923 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3924 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3930 for (; i < opcnt; i++) {
3931 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3933 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3934 && ops[i].operand[1].type == OPT_CONST)
3936 g_stack_fsz = ops[i].operand[1].val;
3937 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3942 else if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3943 && ops[i].operand[1].type == OPT_CONST
3944 && ops[i + 1].op == OP_CALL
3945 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3947 g_stack_fsz += ops[i].operand[1].val;
3948 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3950 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3957 if (ecx_push && !esp_sub) {
3958 // could actually be args for a call..
3959 for (; i < opcnt; i++)
3960 if (ops[i].op != OP_PUSH)
3963 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3964 const struct parsed_proto *pp;
3965 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3966 j = pp ? pp->argc_stack : 0;
3967 while (i > 0 && j > 0) {
3969 if (ops[i].op == OP_PUSH) {
3970 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
3975 ferr(&ops[i], "unhandled prologue\n");
3978 i = g_stack_fsz = ecx_push = 0;
3979 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3980 if (!(ops[i].flags & OPF_RMD))
3990 if (ecx_push || esp_sub)
3995 for (; i < opcnt; i++)
3996 if (ops[i].flags & OPF_TAIL)
4000 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4001 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4008 for (l = 0; l < ecx_push; l++) {
4009 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4011 else if (ops[j].op == OP_ADD
4012 && IS(opr_name(&ops[j], 0), "esp")
4013 && ops[j].operand[1].type == OPT_CONST)
4016 l += ops[j].operand[1].val / 4 - 1;
4019 ferr(&ops[j], "'pop ecx' expected\n");
4021 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4025 ferr(&ops[j], "epilogue scan failed\n");
4031 if (ops[j].op != OP_ADD
4032 || !IS(opr_name(&ops[j], 0), "esp")
4033 || ops[j].operand[1].type != OPT_CONST
4034 || ops[j].operand[1].val != g_stack_fsz)
4036 if (ops[i].op == OP_CALL && ops[i].pp != NULL
4037 && ops[i].pp->is_noreturn)
4039 // noreturn tailcall with no epilogue
4043 ferr(&ops[j], "'add esp' expected\n");
4046 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4047 ops[j].operand[1].val = 0; // hack for stack arg scanner
4052 } while (i < opcnt);
4055 ferr(ops, "missing esp epilogue\n");
4059 // find an instruction that changed opr before i op
4060 // *op_i must be set to -1 by the caller
4061 // *is_caller is set to 1 if one source is determined to be g_func arg
4062 // returns 1 if found, *op_i is then set to origin
4063 // returns -1 if multiple origins are found
4064 static int resolve_origin(int i, const struct parsed_opr *opr,
4065 int magic, int *op_i, int *is_caller)
4067 struct label_ref *lr;
4071 if (g_labels[i] != NULL) {
4072 lr = &g_label_refs[i];
4073 for (; lr != NULL; lr = lr->next) {
4074 check_i(&ops[i], lr->i);
4075 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4077 if (i > 0 && LAST_OP(i - 1))
4083 if (is_caller != NULL)
4088 if (ops[i].cc_scratch == magic)
4090 ops[i].cc_scratch = magic;
4092 if (!(ops[i].flags & OPF_DATA))
4094 if (!is_opr_modified(opr, &ops[i]))
4098 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4109 // find an instruction that previously referenced opr
4110 // if multiple results are found - fail
4111 // *op_i must be set to -1 by the caller
4112 // returns 1 if found, *op_i is then set to referencer insn
4113 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4114 int magic, int *op_i)
4116 struct label_ref *lr;
4120 if (g_labels[i] != NULL) {
4121 lr = &g_label_refs[i];
4122 for (; lr != NULL; lr = lr->next) {
4123 check_i(&ops[i], lr->i);
4124 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4126 if (i > 0 && LAST_OP(i - 1))
4134 if (ops[i].cc_scratch == magic)
4136 ops[i].cc_scratch = magic;
4138 if (!is_opr_referenced(opr, &ops[i]))
4149 // adjust datap of all reachable 'op' insns when moving back
4150 // returns 1 if at least 1 op was found
4151 // returns -1 if path without an op was found
4152 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4154 struct label_ref *lr;
4157 if (ops[i].cc_scratch == magic)
4159 ops[i].cc_scratch = magic;
4162 if (g_labels[i] != NULL) {
4163 lr = &g_label_refs[i];
4164 for (; lr != NULL; lr = lr->next) {
4165 check_i(&ops[i], lr->i);
4166 ret |= adjust_prev_op(lr->i, op, magic, datap);
4168 if (i > 0 && LAST_OP(i - 1))
4176 if (ops[i].cc_scratch == magic)
4178 ops[i].cc_scratch = magic;
4180 if (ops[i].op != op)
4183 ops[i].datap = datap;
4188 // find next instruction that reads opr
4189 // *op_i must be set to -1 by the caller
4190 // on return, *op_i is set to first referencer insn
4191 // returns 1 if exactly 1 referencer is found
4192 static int find_next_read(int i, int opcnt,
4193 const struct parsed_opr *opr, int magic, int *op_i)
4195 struct parsed_op *po;
4198 for (; i < opcnt; i++)
4200 if (ops[i].cc_scratch == magic)
4202 ops[i].cc_scratch = magic;
4205 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4206 if (po->btj != NULL) {
4208 for (j = 0; j < po->btj->count; j++) {
4209 check_i(po, po->btj->d[j].bt_i);
4210 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4216 if (po->flags & OPF_RMD)
4218 check_i(po, po->bt_i);
4219 if (po->flags & OPF_CJMP) {
4220 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4229 if (!is_opr_read(opr, po)) {
4231 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4232 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4234 full_opr = po->operand[0].lmod >= opr->lmod;
4236 if (is_opr_modified(opr, po) && full_opr) {
4240 if (po->flags & OPF_TAIL)
4255 // find next instruction that reads opr
4256 // *op_i must be set to -1 by the caller
4257 // on return, *op_i is set to first flag user insn
4258 // returns 1 if exactly 1 flag user is found
4259 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4261 struct parsed_op *po;
4264 for (; i < opcnt; i++)
4266 if (ops[i].cc_scratch == magic)
4268 ops[i].cc_scratch = magic;
4271 if (po->op == OP_CALL)
4273 if (po->flags & OPF_JMP) {
4274 if (po->btj != NULL) {
4276 for (j = 0; j < po->btj->count; j++) {
4277 check_i(po, po->btj->d[j].bt_i);
4278 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4284 if (po->flags & OPF_RMD)
4286 check_i(po, po->bt_i);
4287 if (po->flags & OPF_CJMP)
4294 if (!(po->flags & OPF_CC)) {
4295 if (po->flags & OPF_FLAGS)
4298 if (po->flags & OPF_TAIL)
4314 static int try_resolve_const(int i, const struct parsed_opr *opr,
4315 int magic, unsigned int *val)
4320 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4323 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4326 *val = ops[i].operand[1].val;
4333 static int resolve_used_bits(int i, int opcnt, int reg,
4334 int *mask, int *is_z_check)
4336 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4340 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4344 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4346 fnote(&ops[j], "(first read)\n");
4347 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4350 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4351 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4353 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4354 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4356 *mask = ops[j].operand[1].val;
4357 if (ops[j].operand[0].lmod == OPLM_BYTE
4358 && ops[j].operand[0].name[1] == 'h')
4362 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4365 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4367 *is_z_check = ops[k].pfo == PFO_Z;
4372 static const struct parsed_proto *resolve_deref(int i, int magic,
4373 struct parsed_opr *opr, int level)
4375 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4376 const struct parsed_proto *pp = NULL;
4377 int from_caller = 0;
4386 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4387 if (ret != 2 || len != strlen(opr->name)) {
4388 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4389 if (ret != 1 || len != strlen(opr->name))
4393 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4398 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4402 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4403 && strlen(ops[j].operand[1].name) == 3
4404 && ops[j].operand[0].lmod == OPLM_DWORD
4405 && ops[j].pp == NULL // no hint
4408 // allow one simple dereference (com/directx)
4409 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4410 ops[j].operand[1].name);
4414 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4419 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4422 if (ops[j].pp != NULL) {
4426 else if (ops[j].operand[1].type == OPT_REGMEM) {
4427 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4429 // maybe structure ptr in structure
4430 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4433 else if (ops[j].operand[1].type == OPT_LABEL)
4434 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4435 else if (ops[j].operand[1].type == OPT_REG) {
4438 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4440 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4441 for (k = 0; k < g_func_pp->argc; k++) {
4442 if (g_func_pp->arg[k].reg == NULL)
4444 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4445 pp = g_func_pp->arg[k].pp;
4454 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4456 ferr(&ops[j], "expected struct, got '%s %s'\n",
4457 pp->type.name, pp->name);
4461 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4464 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4465 int *pp_i, int *multi_src)
4467 const struct parsed_proto *pp = NULL;
4468 int search_advice = 0;
4473 switch (ops[i].operand[0].type) {
4475 // try to resolve struct member calls
4476 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4482 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4488 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4496 static struct parsed_proto *process_call_early(int i, int opcnt,
4499 struct parsed_op *po = &ops[i];
4500 struct parsed_proto *pp;
4506 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4510 // look for and make use of esp adjust
4512 if (!pp->is_stdcall && pp->argc_stack > 0)
4513 ret = scan_for_esp_adjust(i + 1, opcnt,
4514 pp->argc_stack * 4, &adj, &multipath, 0);
4516 if (pp->argc_stack > adj / 4)
4520 if (ops[ret].op == OP_POP) {
4521 for (j = 1; j < adj / 4; j++) {
4522 if (ops[ret + j].op != OP_POP
4523 || ops[ret + j].operand[0].reg != xCX)
4535 static struct parsed_proto *process_call(int i, int opcnt)
4537 struct parsed_op *po = &ops[i];
4538 const struct parsed_proto *pp_c;
4539 struct parsed_proto *pp;
4540 const char *tmpname;
4541 int call_i = -1, ref_i = -1;
4542 int adj = 0, multipath = 0;
4545 tmpname = opr_name(po, 0);
4550 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4552 if (!pp_c->is_func && !pp_c->is_fptr)
4553 ferr(po, "call to non-func: %s\n", pp_c->name);
4554 pp = proto_clone(pp_c);
4555 my_assert_not(pp, NULL);
4557 // not resolved just to single func
4560 switch (po->operand[0].type) {
4562 // we resolved this call and no longer need the register
4563 po->regmask_src &= ~(1 << po->operand[0].reg);
4565 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4566 && ops[call_i].operand[1].type == OPT_LABEL)
4568 // no other source users?
4569 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4571 if (ret == 1 && call_i == ref_i) {
4572 // and nothing uses it after us?
4574 find_next_read(i + 1, opcnt, &po->operand[0],
4575 i + opcnt * 11, &ref_i);
4577 // then also don't need the source mov
4578 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4590 pp = calloc(1, sizeof(*pp));
4591 my_assert_not(pp, NULL);
4594 ret = scan_for_esp_adjust(i + 1, opcnt,
4595 -1, &adj, &multipath, 0);
4596 if (ret < 0 || adj < 0) {
4597 if (!g_allow_regfunc)
4598 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4599 pp->is_unresolved = 1;
4603 if (adj > ARRAY_SIZE(pp->arg))
4604 ferr(po, "esp adjust too large: %d\n", adj);
4605 pp->ret_type.name = strdup("int");
4606 pp->argc = pp->argc_stack = adj;
4607 for (arg = 0; arg < pp->argc; arg++)
4608 pp->arg[arg].type.name = strdup("int");
4613 // look for and make use of esp adjust
4616 if (!pp->is_stdcall && pp->argc_stack > 0) {
4617 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4618 ret = scan_for_esp_adjust(i + 1, opcnt,
4619 adj_expect, &adj, &multipath, 0);
4622 if (pp->is_vararg) {
4623 if (adj / 4 < pp->argc_stack) {
4624 fnote(po, "(this call)\n");
4625 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4626 adj, pp->argc_stack * 4);
4628 // modify pp to make it have varargs as normal args
4630 pp->argc += adj / 4 - pp->argc_stack;
4631 for (; arg < pp->argc; arg++) {
4632 pp->arg[arg].type.name = strdup("int");
4635 if (pp->argc > ARRAY_SIZE(pp->arg))
4636 ferr(po, "too many args for '%s'\n", tmpname);
4638 if (pp->argc_stack > adj / 4) {
4639 fnote(po, "(this call)\n");
4640 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4641 tmpname, pp->argc_stack * 4, adj);
4644 scan_for_esp_adjust(i + 1, opcnt,
4645 pp->argc_stack * 4, &adj, &multipath, 1);
4647 else if (pp->is_vararg)
4648 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4654 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
4657 struct parsed_op *po;
4663 for (base_arg = 0; base_arg < pp->argc; base_arg++)
4664 if (pp->arg[base_arg].reg == NULL)
4667 for (j = i; j > 0; )
4669 ferr_assert(&ops[j], g_labels[j] == NULL);
4673 ferr_assert(po, po->op != OP_PUSH);
4674 if (po->op == OP_FST)
4676 if (po->operand[0].type != OPT_REGMEM)
4678 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
4681 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3))
4682 ferr(po, "bad offset %d (%d args)\n", offset, pp->argc_stack);
4684 arg = base_arg + offset / 4;
4686 po->p_argnum = arg + 1;
4687 ferr_assert(po, pp->arg[arg].datap == NULL);
4688 pp->arg[arg].datap = po;
4689 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
4690 if (regmask_ffca != NULL)
4691 *regmask_ffca |= 1 << arg;
4693 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4694 && po->operand[1].type == OPT_CONST)
4696 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4701 for (arg = base_arg; arg < pp->argc; arg++) {
4702 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
4703 po = pp->arg[arg].datap;
4705 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
4706 if (po->operand[0].lmod == OPLM_QWORD)
4713 static int collect_call_args_early(int i, struct parsed_proto *pp,
4714 int *regmask, int *regmask_ffca)
4716 struct parsed_op *po;
4720 for (arg = 0; arg < pp->argc; arg++)
4721 if (pp->arg[arg].reg == NULL)
4724 // first see if it can be easily done
4725 for (j = i; j > 0 && arg < pp->argc; )
4727 if (g_labels[j] != NULL)
4732 if (po->op == OP_CALL)
4734 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
4736 else if (po->op == OP_POP)
4738 else if (po->flags & OPF_CJMP)
4740 else if (po->op == OP_PUSH) {
4741 if (po->flags & (OPF_FARG|OPF_FARGNR))
4743 if (!g_header_mode) {
4744 ret = scan_for_mod(po, j + 1, i, 1);
4749 if (pp->arg[arg].type.is_va_list)
4753 for (arg++; arg < pp->argc; arg++)
4754 if (pp->arg[arg].reg == NULL)
4757 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4758 && po->operand[1].type == OPT_CONST)
4760 if (po->flags & (OPF_RMD|OPF_DONE))
4762 if (po->operand[1].val != pp->argc_stack * 4)
4763 ferr(po, "unexpected esp adjust: %d\n",
4764 po->operand[1].val * 4);
4765 ferr_assert(po, pp->argc - arg == pp->argc_stack);
4766 return collect_call_args_no_push(i, pp, regmask_ffca);
4774 for (arg = 0; arg < pp->argc; arg++)
4775 if (pp->arg[arg].reg == NULL)
4778 for (j = i; j > 0 && arg < pp->argc; )
4782 if (ops[j].op == OP_PUSH)
4784 ops[j].p_argnext = -1;
4785 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4786 pp->arg[arg].datap = &ops[j];
4788 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
4789 *regmask |= 1 << ops[j].operand[0].reg;
4791 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4792 ops[j].flags &= ~OPF_RSAVE;
4795 for (arg++; arg < pp->argc; arg++)
4796 if (pp->arg[arg].reg == NULL)
4804 static int sync_argnum(struct parsed_op *po, int argnum)
4806 struct parsed_op *po_tmp;
4808 // see if other branches don't have higher argnum
4809 for (po_tmp = po; po_tmp != NULL; ) {
4810 if (argnum < po_tmp->p_argnum)
4811 argnum = po_tmp->p_argnum;
4812 // note: p_argnext is active on current collect_call_args only
4813 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4816 // make all argnums consistent
4817 for (po_tmp = po; po_tmp != NULL; ) {
4818 if (po_tmp->p_argnum != 0)
4819 po_tmp->p_argnum = argnum;
4820 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4826 static int collect_call_args_r(struct parsed_op *po, int i,
4827 struct parsed_proto *pp, int *regmask, int *arg_grp,
4828 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
4830 struct parsed_proto *pp_tmp;
4831 struct parsed_op *po_tmp;
4832 struct label_ref *lr;
4833 int need_to_save_current;
4834 int arg_grp_current = 0;
4835 int save_args_seen = 0;
4842 ferr(po, "dead label encountered\n");
4846 for (; arg < pp->argc; arg++, argnum++)
4847 if (pp->arg[arg].reg == NULL)
4849 magic = (magic & 0xffffff) | (arg << 24);
4851 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4853 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4854 if (ops[j].cc_scratch != magic) {
4855 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4859 // ok: have already been here
4862 ops[j].cc_scratch = magic;
4864 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4865 lr = &g_label_refs[j];
4866 if (lr->next != NULL)
4868 for (; lr->next; lr = lr->next) {
4869 check_i(&ops[j], lr->i);
4870 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4872 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4873 arg, argnum, magic, need_op_saving, may_reuse);
4878 check_i(&ops[j], lr->i);
4879 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4881 if (j > 0 && LAST_OP(j - 1)) {
4882 // follow last branch in reverse
4887 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4888 arg, argnum, magic, need_op_saving, may_reuse);
4894 if (ops[j].op == OP_CALL)
4896 if (pp->is_unresolved)
4901 ferr(po, "arg collect hit unparsed call '%s'\n",
4902 ops[j].operand[0].name);
4903 if (may_reuse && pp_tmp->argc_stack > 0)
4904 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4905 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4907 // esp adjust of 0 means we collected it before
4908 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4909 && (ops[j].operand[1].type != OPT_CONST
4910 || ops[j].operand[1].val != 0))
4912 if (pp->is_unresolved)
4915 fnote(po, "(this call)\n");
4916 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4917 arg, pp->argc, ops[j].operand[1].val);
4919 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4921 if (pp->is_unresolved)
4924 fnote(po, "(this call)\n");
4925 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4927 else if (ops[j].flags & OPF_CJMP)
4929 if (pp->is_unresolved)
4934 else if (ops[j].op == OP_PUSH
4935 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4937 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4940 ops[j].p_argnext = -1;
4941 po_tmp = pp->arg[arg].datap;
4943 ops[j].p_argnext = po_tmp - ops;
4944 pp->arg[arg].datap = &ops[j];
4946 argnum = sync_argnum(&ops[j], argnum);
4948 need_to_save_current = 0;
4950 if (ops[j].operand[0].type == OPT_REG)
4951 reg = ops[j].operand[0].reg;
4953 if (!need_op_saving) {
4954 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4955 need_to_save_current = (ret >= 0);
4957 if (need_op_saving || need_to_save_current) {
4958 // mark this arg as one that needs operand saving
4959 pp->arg[arg].is_saved = 1;
4961 if (save_args_seen & (1 << (argnum - 1))) {
4964 if (arg_grp_current >= MAX_ARG_GRP)
4965 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
4969 else if (ops[j].p_argnum == 0)
4970 ops[j].flags |= OPF_RMD;
4972 // some PUSHes are reused by different calls on other branches,
4973 // but that can't happen if we didn't branch, so they
4974 // can be removed from future searches (handles nested calls)
4976 ops[j].flags |= OPF_FARGNR;
4978 ops[j].flags |= OPF_FARG;
4979 ops[j].flags &= ~OPF_RSAVE;
4981 // check for __VALIST
4982 if (!pp->is_unresolved && g_func_pp != NULL
4983 && pp->arg[arg].type.is_va_list)
4986 ret = resolve_origin(j, &ops[j].operand[0],
4987 magic + 1, &k, NULL);
4988 if (ret == 1 && k >= 0)
4990 if (ops[k].op == OP_LEA) {
4991 if (!g_func_pp->is_vararg)
4992 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
4995 snprintf(buf, sizeof(buf), "arg_%X",
4996 g_func_pp->argc_stack * 4);
4997 if (strstr(ops[k].operand[1].name, buf)
4998 || strstr(ops[k].operand[1].name, "arglist"))
5000 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5001 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5002 pp->arg[arg].is_saved = 0;
5006 ferr(&ops[k], "va_list arg detection failed\n");
5008 // check for va_list from g_func_pp arg too
5009 else if (ops[k].op == OP_MOV
5010 && is_stack_access(&ops[k], &ops[k].operand[1]))
5012 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5013 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5015 ops[k].flags |= OPF_RMD | OPF_DONE;
5016 ops[j].flags |= OPF_RMD;
5017 ops[j].p_argpass = ret + 1;
5018 pp->arg[arg].is_saved = 0;
5025 if (pp->arg[arg].is_saved) {
5026 ops[j].flags &= ~OPF_RMD;
5027 ops[j].p_argnum = argnum;
5030 // tracking reg usage
5032 *regmask |= 1 << reg;
5036 if (!pp->is_unresolved) {
5038 for (; arg < pp->argc; arg++, argnum++)
5039 if (pp->arg[arg].reg == NULL)
5042 magic = (magic & 0xffffff) | (arg << 24);
5045 if (ops[j].p_arggrp > arg_grp_current) {
5047 arg_grp_current = ops[j].p_arggrp;
5049 if (ops[j].p_argnum > 0)
5050 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5053 if (arg < pp->argc) {
5054 ferr(po, "arg collect failed for '%s': %d/%d\n",
5055 pp->name, arg, pp->argc);
5059 if (arg_grp_current > *arg_grp)
5060 *arg_grp = arg_grp_current;
5065 static int collect_call_args(struct parsed_op *po, int i,
5066 struct parsed_proto *pp, int *regmask, int magic)
5068 // arg group is for cases when pushes for
5069 // multiple funcs are going on
5070 struct parsed_op *po_tmp;
5075 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5081 // propagate arg_grp
5082 for (a = 0; a < pp->argc; a++) {
5083 if (pp->arg[a].reg != NULL)
5086 po_tmp = pp->arg[a].datap;
5087 while (po_tmp != NULL) {
5088 po_tmp->p_arggrp = arg_grp;
5089 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5094 if (pp->is_unresolved) {
5096 pp->argc_stack += ret;
5097 for (a = 0; a < pp->argc; a++)
5098 if (pp->arg[a].type.name == NULL)
5099 pp->arg[a].type.name = strdup("int");
5105 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5106 int regmask_now, int *regmask,
5107 int regmask_save_now, int *regmask_save,
5108 int *regmask_init, int regmask_arg)
5110 struct parsed_op *po;
5118 for (; i < opcnt; i++)
5121 if (cbits[i >> 3] & (1 << (i & 7)))
5123 cbits[i >> 3] |= (1 << (i & 7));
5125 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5126 if (po->flags & (OPF_RMD|OPF_DONE))
5128 if (po->btj != NULL) {
5129 for (j = 0; j < po->btj->count; j++) {
5130 check_i(po, po->btj->d[j].bt_i);
5131 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5132 regmask_now, regmask, regmask_save_now, regmask_save,
5133 regmask_init, regmask_arg);
5138 check_i(po, po->bt_i);
5139 if (po->flags & OPF_CJMP)
5140 reg_use_pass(po->bt_i, opcnt, cbits,
5141 regmask_now, regmask, regmask_save_now, regmask_save,
5142 regmask_init, regmask_arg);
5148 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5149 && !g_func_pp->is_userstack
5150 && po->operand[0].type == OPT_REG)
5152 reg = po->operand[0].reg;
5153 ferr_assert(po, reg >= 0);
5156 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5157 if (regmask_now & (1 << reg)) {
5158 already_saved = regmask_save_now & (1 << reg);
5159 flags_set = OPF_RSAVE | OPF_DONE;
5162 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5164 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5165 reg, 0, 0, flags_set);
5168 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5170 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5175 ferr_assert(po, !already_saved);
5176 po->flags |= flags_set;
5178 if (regmask_now & (1 << reg)) {
5179 regmask_save_now |= (1 << reg);
5180 *regmask_save |= regmask_save_now;
5185 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5186 reg = po->operand[0].reg;
5187 ferr_assert(po, reg >= 0);
5189 if (regmask_save_now & (1 << reg))
5190 regmask_save_now &= ~(1 << reg);
5192 regmask_now &= ~(1 << reg);
5195 else if (po->op == OP_CALL) {
5196 if ((po->regmask_dst & (1 << xAX))
5197 && !(po->regmask_dst & (1 << xDX)))
5199 if (po->flags & OPF_TAIL)
5200 // don't need eax, will do "return f();" or "f(); return;"
5201 po->regmask_dst &= ~(1 << xAX);
5203 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5205 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5208 po->regmask_dst &= ~(1 << xAX);
5212 // not "full stack" mode and have something in stack
5213 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5214 ferr(po, "float stack is not empty on func call\n");
5217 if (po->flags & OPF_NOREGS)
5220 // if incomplete register is used, clear it on init to avoid
5221 // later use of uninitialized upper part in some situations
5222 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5223 && po->operand[0].lmod != OPLM_DWORD)
5225 reg = po->operand[0].reg;
5226 ferr_assert(po, reg >= 0);
5228 if (!(regmask_now & (1 << reg)))
5229 *regmask_init |= 1 << reg;
5232 regmask_op = po->regmask_src | po->regmask_dst;
5234 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5235 regmask_new &= ~(1 << xSP);
5236 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5237 regmask_new &= ~(1 << xBP);
5239 if (regmask_new != 0)
5240 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5242 if (regmask_op & (1 << xBP)) {
5243 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5244 if (po->regmask_dst & (1 << xBP))
5245 // compiler decided to drop bp frame and use ebp as scratch
5246 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5248 regmask_op &= ~(1 << xBP);
5252 if (po->flags & OPF_FPUSH) {
5253 if (regmask_now & mxST1)
5254 regmask_now |= mxSTa; // switch to "full stack" mode
5255 if (regmask_now & mxSTa)
5256 po->flags |= OPF_FSHIFT;
5257 if (!(regmask_now & mxST7_2)) {
5259 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5263 regmask_now |= regmask_op;
5264 *regmask |= regmask_now;
5267 if (po->flags & OPF_FPOP) {
5268 if ((regmask_now & mxSTa) == 0)
5269 ferr(po, "float pop on empty stack?\n");
5270 if (regmask_now & (mxST7_2 | mxST1))
5271 po->flags |= OPF_FSHIFT;
5272 if (!(regmask_now & mxST7_2)) {
5274 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5278 if (po->flags & OPF_TAIL) {
5279 if (!(regmask_now & mxST7_2)) {
5280 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5281 if (!(regmask_now & mxST0))
5282 ferr(po, "no st0 on float return, mask: %x\n",
5285 else if (regmask_now & mxST1_0)
5286 ferr(po, "float regs on tail: %x\n", regmask_now);
5289 // there is support for "conditional tailcall", sort of
5290 if (!(po->flags & OPF_CC))
5296 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5300 for (i = 0; i < pp->argc; i++)
5301 if (pp->arg[i].reg == NULL)
5305 memmove(&pp->arg[i + 1], &pp->arg[i],
5306 sizeof(pp->arg[0]) * pp->argc_stack);
5307 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5308 pp->arg[i].reg = strdup(reg);
5309 pp->arg[i].type.name = strdup("int");
5314 static void output_std_flags(FILE *fout, struct parsed_op *po,
5315 int *pfomask, const char *dst_opr_text)
5317 if (*pfomask & (1 << PFO_Z)) {
5318 fprintf(fout, "\n cond_z = (%s%s == 0);",
5319 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5320 *pfomask &= ~(1 << PFO_Z);
5322 if (*pfomask & (1 << PFO_S)) {
5323 fprintf(fout, "\n cond_s = (%s%s < 0);",
5324 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5325 *pfomask &= ~(1 << PFO_S);
5330 OPP_FORCE_NORETURN = (1 << 0),
5331 OPP_SIMPLE_ARGS = (1 << 1),
5332 OPP_ALIGN = (1 << 2),
5335 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5338 const char *cconv = "";
5340 if (pp->is_fastcall)
5341 cconv = "__fastcall ";
5342 else if (pp->is_stdcall && pp->argc_reg == 0)
5343 cconv = "__stdcall ";
5345 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5347 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5348 fprintf(fout, "noreturn ");
5351 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5356 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5360 output_pp_attrs(fout, pp, flags);
5363 fprintf(fout, "%s", pp->name);
5368 for (i = 0; i < pp->argc; i++) {
5370 fprintf(fout, ", ");
5371 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5372 && !(flags & OPP_SIMPLE_ARGS))
5375 output_pp(fout, pp->arg[i].pp, 0);
5377 else if (pp->arg[i].type.is_retreg) {
5378 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5381 fprintf(fout, "%s", pp->arg[i].type.name);
5383 fprintf(fout, " a%d", i + 1);
5386 if (pp->is_vararg) {
5388 fprintf(fout, ", ");
5389 fprintf(fout, "...");
5394 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5400 snprintf(buf1, sizeof(buf1), "%d", grp);
5401 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5406 static void gen_x_cleanup(int opcnt);
5408 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5410 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5411 struct parsed_opr *last_arith_dst = NULL;
5412 char buf1[256], buf2[256], buf3[256], cast[64];
5413 struct parsed_proto *pp, *pp_tmp;
5414 struct parsed_data *pd;
5415 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5416 unsigned char cbits[MAX_OPS / 8];
5417 const char *float_type;
5418 const char *float_st0;
5419 const char *float_st1;
5420 int need_float_stack = 0;
5421 int need_float_sw = 0; // status word
5422 int need_tmp_var = 0;
5426 int label_pending = 0;
5427 int need_double = 0;
5428 int regmask_save = 0; // used regs saved/restored in this func
5429 int regmask_arg; // regs from this function args (fastcall, etc)
5430 int regmask_ret; // regs needed on ret
5431 int regmask_now; // temp
5432 int regmask_init = 0; // regs that need zero initialization
5433 int regmask_pp = 0; // regs used in complex push-pop graph
5434 int regmask_ffca = 0; // float function call args
5435 int regmask = 0; // used regs
5445 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5446 g_stack_frame_used = 0;
5447 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5448 regmask_init = g_regmask_init;
5450 g_func_pp = proto_parse(fhdr, funcn, 0);
5451 if (g_func_pp == NULL)
5452 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5454 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5455 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5458 // - resolve all branches
5459 // - parse calls with labels
5460 resolve_branches_parse_calls(opcnt);
5463 // - handle ebp/esp frame, remove ops related to it
5464 scan_prologue_epilogue(opcnt);
5467 // - remove dead labels
5468 // - set regs needed at ret
5469 for (i = 0; i < opcnt; i++)
5471 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5476 if (ops[i].op == OP_RET)
5477 ops[i].regmask_src |= regmask_ret;
5481 // - process trivial calls
5482 for (i = 0; i < opcnt; i++)
5485 if (po->flags & (OPF_RMD|OPF_DONE))
5488 if (po->op == OP_CALL)
5490 pp = process_call_early(i, opcnt, &j);
5492 if (!(po->flags & OPF_ATAIL)) {
5493 // since we know the args, try to collect them
5494 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5502 // commit esp adjust
5503 if (ops[j].op != OP_POP)
5504 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5506 for (l = 0; l < pp->argc_stack; l++)
5507 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5511 if (strstr(pp->ret_type.name, "int64"))
5514 po->flags |= OPF_DONE;
5520 // - process calls, stage 2
5521 // - handle some push/pop pairs
5522 // - scan for STD/CLD, propagate DF
5523 // - try to resolve needed x87 status word bits
5524 for (i = 0; i < opcnt; i++)
5529 if (po->flags & OPF_RMD)
5532 if (po->op == OP_CALL)
5534 if (!(po->flags & OPF_DONE)) {
5535 pp = process_call(i, opcnt);
5537 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5538 // since we know the args, collect them
5539 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5541 // for unresolved, collect after other passes
5545 ferr_assert(po, pp != NULL);
5547 po->regmask_src |= get_pp_arg_regmask_src(pp);
5548 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5550 if (po->regmask_dst & mxST0)
5551 po->flags |= OPF_FPUSH;
5553 if (strstr(pp->ret_type.name, "int64"))
5559 if (po->flags & OPF_DONE)
5564 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
5565 && po->operand[0].type == OPT_CONST)
5567 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5572 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5576 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5577 scan_propagate_df(i + 1, opcnt);
5582 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
5583 ferr(po, "TODO: fnstsw to mem\n");
5584 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
5586 ferr(po, "fnstsw resolve failed\n");
5587 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
5588 (void *)(long)(mask | (z_check << 16)));
5590 ferr(po, "failed to find fcom: %d\n", ret);
5599 // - find POPs for PUSHes, rm both
5600 // - scan for all used registers
5601 memset(cbits, 0, sizeof(cbits));
5602 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5603 0, ®mask_save, ®mask_init, regmask_arg);
5605 need_float_stack = !!(regmask & mxST7_2);
5608 // - find flag set ops for their users
5609 // - do unresolved calls
5610 // - declare indirect functions
5611 // - other op specific processing
5612 for (i = 0; i < opcnt; i++)
5615 if (po->flags & (OPF_RMD|OPF_DONE))
5618 if (po->flags & OPF_CC)
5620 int setters[16], cnt = 0, branched = 0;
5622 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
5623 &branched, setters, &cnt);
5624 if (ret < 0 || cnt <= 0)
5625 ferr(po, "unable to trace flag setter(s)\n");
5626 if (cnt > ARRAY_SIZE(setters))
5627 ferr(po, "too many flag setters\n");
5629 for (j = 0; j < cnt; j++)
5631 tmp_op = &ops[setters[j]]; // flag setter
5634 // to get nicer code, we try to delay test and cmp;
5635 // if we can't because of operand modification, or if we
5636 // have arith op, or branch, make it calculate flags explicitly
5637 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5639 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5640 pfomask = 1 << po->pfo;
5642 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5643 pfomask = 1 << po->pfo;
5646 // see if we'll be able to handle based on op result
5647 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5648 && po->pfo != PFO_Z && po->pfo != PFO_S
5649 && po->pfo != PFO_P)
5651 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5653 pfomask = 1 << po->pfo;
5656 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5657 propagate_lmod(tmp_op, &tmp_op->operand[0],
5658 &tmp_op->operand[1]);
5659 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5664 tmp_op->pfomask |= pfomask;
5665 cond_vars |= pfomask;
5667 // note: may overwrite, currently not a problem
5671 if (po->op == OP_RCL || po->op == OP_RCR
5672 || po->op == OP_ADC || po->op == OP_SBB)
5673 cond_vars |= 1 << PFO_C;
5679 cond_vars |= 1 << PFO_Z;
5683 if (po->operand[0].lmod == OPLM_DWORD)
5688 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
5693 // note: resolved non-reg calls are OPF_DONE already
5695 ferr_assert(po, pp != NULL);
5697 if (pp->is_unresolved) {
5698 int regmask_stack = 0;
5699 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5701 // this is pretty rough guess:
5702 // see ecx and edx were pushed (and not their saved versions)
5703 for (arg = 0; arg < pp->argc; arg++) {
5704 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
5707 tmp_op = pp->arg[arg].datap;
5709 ferr(po, "parsed_op missing for arg%d\n", arg);
5710 if (tmp_op->operand[0].type == OPT_REG)
5711 regmask_stack |= 1 << tmp_op->operand[0].reg;
5714 if (!((regmask_stack & (1 << xCX))
5715 && (regmask_stack & (1 << xDX))))
5717 if (pp->argc_stack != 0
5718 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5720 pp_insert_reg_arg(pp, "ecx");
5721 pp->is_fastcall = 1;
5722 regmask_init |= 1 << xCX;
5723 regmask |= 1 << xCX;
5725 if (pp->argc_stack != 0
5726 || ((regmask | regmask_arg) & (1 << xDX)))
5728 pp_insert_reg_arg(pp, "edx");
5729 regmask_init |= 1 << xDX;
5730 regmask |= 1 << xDX;
5734 // note: __cdecl doesn't fall into is_unresolved category
5735 if (pp->argc_stack > 0)
5741 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
5743 // <var> = offset <something>
5744 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5745 && !IS_START(po->operand[1].name, "off_"))
5747 if (!po->operand[0].pp->is_fptr)
5748 ferr(po, "%s not declared as fptr when it should be\n",
5749 po->operand[0].name);
5750 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5751 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5752 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5753 fnote(po, "var: %s\n", buf1);
5754 fnote(po, "func: %s\n", buf2);
5755 ferr(po, "^ mismatch\n");
5763 if (po->operand[0].lmod == OPLM_DWORD) {
5764 // 32bit division is common, look for it
5765 if (po->op == OP_DIV)
5766 ret = scan_for_reg_clear(i, xDX);
5768 ret = scan_for_cdq_edx(i);
5770 po->flags |= OPF_32BIT;
5779 po->flags |= OPF_RMD | OPF_DONE;
5789 if (po->operand[0].lmod == OPLM_QWORD)
5799 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5801 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5803 po->flags |= OPF_32BIT;
5811 // this might need it's own pass...
5812 if (po->op != OP_FST && po->p_argnum > 0)
5813 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
5815 // correct for "full stack" mode late enable
5816 if ((po->flags & (OPF_PPUSH|OPF_FPOP)) && need_float_stack)
5817 po->flags |= OPF_FSHIFT;
5820 float_type = need_double ? "double" : "float";
5821 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
5822 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
5824 // output starts here
5826 // define userstack size
5827 if (g_func_pp->is_userstack) {
5828 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5829 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5830 fprintf(fout, "#endif\n");
5833 // the function itself
5834 ferr_assert(ops, !g_func_pp->is_fptr);
5835 output_pp(fout, g_func_pp,
5836 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5837 fprintf(fout, "\n{\n");
5839 // declare indirect functions
5840 for (i = 0; i < opcnt; i++) {
5842 if (po->flags & OPF_RMD)
5845 if (po->op == OP_CALL) {
5848 ferr(po, "NULL pp\n");
5850 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5851 if (pp->name[0] != 0) {
5852 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5853 memcpy(pp->name, "i_", 2);
5855 // might be declared already
5857 for (j = 0; j < i; j++) {
5858 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5859 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5869 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5872 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5873 fprintf(fout, ";\n");
5878 // output LUTs/jumptables
5879 for (i = 0; i < g_func_pd_cnt; i++) {
5881 fprintf(fout, " static const ");
5882 if (pd->type == OPT_OFFSET) {
5883 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5885 for (j = 0; j < pd->count; j++) {
5887 fprintf(fout, ", ");
5888 fprintf(fout, "&&%s", pd->d[j].u.label);
5892 fprintf(fout, "%s %s[] =\n { ",
5893 lmod_type_u(ops, pd->lmod), pd->label);
5895 for (j = 0; j < pd->count; j++) {
5897 fprintf(fout, ", ");
5898 fprintf(fout, "%u", pd->d[j].u.val);
5901 fprintf(fout, " };\n");
5905 // declare stack frame, va_arg
5907 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5908 if (g_func_lmods & (1 << OPLM_WORD))
5909 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5910 if (g_func_lmods & (1 << OPLM_BYTE))
5911 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5912 if (g_func_lmods & (1 << OPLM_QWORD))
5913 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5914 fprintf(fout, " } sf;\n");
5918 if (g_func_pp->is_userstack) {
5919 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5920 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5924 if (g_func_pp->is_vararg) {
5925 fprintf(fout, " va_list ap;\n");
5929 // declare arg-registers
5930 for (i = 0; i < g_func_pp->argc; i++) {
5931 if (g_func_pp->arg[i].reg != NULL) {
5932 reg = char_array_i(regs_r32,
5933 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5934 if (regmask & (1 << reg)) {
5935 if (g_func_pp->arg[i].type.is_retreg)
5936 fprintf(fout, " u32 %s = *r_%s;\n",
5937 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5939 fprintf(fout, " u32 %s = (u32)a%d;\n",
5940 g_func_pp->arg[i].reg, i + 1);
5943 if (g_func_pp->arg[i].type.is_retreg)
5944 ferr(ops, "retreg '%s' is unused?\n",
5945 g_func_pp->arg[i].reg);
5946 fprintf(fout, " // %s = a%d; // unused\n",
5947 g_func_pp->arg[i].reg, i + 1);
5953 // declare normal registers
5954 regmask_now = regmask & ~regmask_arg;
5955 regmask_now &= ~(1 << xSP);
5956 if (regmask_now & 0x00ff) {
5957 for (reg = 0; reg < 8; reg++) {
5958 if (regmask_now & (1 << reg)) {
5959 fprintf(fout, " u32 %s", regs_r32[reg]);
5960 if (regmask_init & (1 << reg))
5961 fprintf(fout, " = 0");
5962 fprintf(fout, ";\n");
5968 if (regmask_now & 0xff00) {
5969 for (reg = 8; reg < 16; reg++) {
5970 if (regmask_now & (1 << reg)) {
5971 fprintf(fout, " mmxr %s", regs_r32[reg]);
5972 if (regmask_init & (1 << reg))
5973 fprintf(fout, " = { 0, }");
5974 fprintf(fout, ";\n");
5980 if (need_float_stack) {
5981 fprintf(fout, " %s f_st[8];\n", float_type);
5982 fprintf(fout, " int f_stp = 0;\n");
5986 if (regmask_now & 0xff0000) {
5987 for (reg = 16; reg < 24; reg++) {
5988 if (regmask_now & (1 << reg)) {
5989 fprintf(fout, " %s f_st%d", float_type, reg - 16);
5990 if (regmask_init & (1 << reg))
5991 fprintf(fout, " = 0");
5992 fprintf(fout, ";\n");
5999 if (need_float_sw) {
6000 fprintf(fout, " u16 f_sw;\n");
6005 for (reg = 0; reg < 8; reg++) {
6006 if (regmask_save & (1 << reg)) {
6007 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6013 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6014 if (save_arg_vars[i] == 0)
6016 for (reg = 0; reg < 32; reg++) {
6017 if (save_arg_vars[i] & (1 << reg)) {
6018 fprintf(fout, " u32 %s;\n",
6019 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6026 for (reg = 0; reg < 32; reg++) {
6027 if (regmask_ffca & (1 << reg)) {
6028 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6034 // declare push-pop temporaries
6036 for (reg = 0; reg < 8; reg++) {
6037 if (regmask_pp & (1 << reg)) {
6038 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6045 for (i = 0; i < 8; i++) {
6046 if (cond_vars & (1 << i)) {
6047 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6054 fprintf(fout, " u32 tmp;\n");
6059 fprintf(fout, " u64 tmp64;\n");
6064 fprintf(fout, "\n");
6066 // do stack clear, if needed
6067 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6069 if (g_stack_clear_len != 0) {
6070 if (g_stack_clear_len <= 4) {
6071 for (i = 0; i < g_stack_clear_len; i++)
6072 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6073 fprintf(fout, "0;\n");
6076 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6077 g_stack_clear_start, g_stack_clear_len * 4);
6081 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6084 if (g_func_pp->is_vararg) {
6085 if (g_func_pp->argc_stack == 0)
6086 ferr(ops, "vararg func without stack args?\n");
6087 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6091 for (i = 0; i < opcnt; i++)
6093 if (g_labels[i] != NULL) {
6094 fprintf(fout, "\n%s:\n", g_labels[i]);
6097 delayed_flag_op = NULL;
6098 last_arith_dst = NULL;
6102 if (po->flags & OPF_RMD)
6107 #define assert_operand_cnt(n_) \
6108 if (po->operand_cnt != n_) \
6109 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6111 // conditional/flag using op?
6112 if (po->flags & OPF_CC)
6118 // we go through all this trouble to avoid using parsed_flag_op,
6119 // which makes generated code much nicer
6120 if (delayed_flag_op != NULL)
6122 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6123 po->pfo, po->pfo_inv);
6126 else if (last_arith_dst != NULL
6127 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6128 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6131 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6132 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6133 last_arith_dst->lmod, buf3);
6136 else if (tmp_op != NULL) {
6137 // use preprocessed flag calc results
6138 if (!(tmp_op->pfomask & (1 << po->pfo)))
6139 ferr(po, "not prepared for pfo %d\n", po->pfo);
6141 // note: pfo_inv was not yet applied
6142 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6143 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6146 ferr(po, "all methods of finding comparison failed\n");
6149 if (po->flags & OPF_JMP) {
6150 fprintf(fout, " if %s", buf1);
6152 else if (po->op == OP_RCL || po->op == OP_RCR
6153 || po->op == OP_ADC || po->op == OP_SBB)
6156 fprintf(fout, " cond_%s = %s;\n",
6157 parsed_flag_op_names[po->pfo], buf1);
6159 else if (po->flags & OPF_DATA) { // SETcc
6160 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6161 fprintf(fout, " %s = %s;", buf2, buf1);
6164 ferr(po, "unhandled conditional op\n");
6168 pfomask = po->pfomask;
6173 assert_operand_cnt(2);
6174 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6175 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6176 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6177 fprintf(fout, " %s = %s;", buf1,
6178 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6183 assert_operand_cnt(2);
6184 po->operand[1].lmod = OPLM_DWORD; // always
6185 fprintf(fout, " %s = %s;",
6186 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6187 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6192 assert_operand_cnt(2);
6193 fprintf(fout, " %s = %s;",
6194 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6195 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6199 assert_operand_cnt(2);
6200 switch (po->operand[1].lmod) {
6202 strcpy(buf3, "(s8)");
6205 strcpy(buf3, "(s16)");
6208 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6210 fprintf(fout, " %s = %s;",
6211 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6212 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6217 assert_operand_cnt(2);
6218 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6219 fprintf(fout, " tmp = %s;",
6220 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6221 fprintf(fout, " %s = %s;",
6222 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6223 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6224 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6225 fprintf(fout, " %s = %stmp;",
6226 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6227 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6228 snprintf(g_comment, sizeof(g_comment), "xchg");
6232 assert_operand_cnt(1);
6233 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6234 fprintf(fout, " %s = ~%s;", buf1, buf1);
6238 assert_operand_cnt(2);
6239 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6240 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6241 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6242 strcpy(g_comment, "xlat");
6246 assert_operand_cnt(2);
6247 fprintf(fout, " %s = (s32)%s >> 31;",
6248 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6249 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6250 strcpy(g_comment, "cdq");
6254 assert_operand_cnt(1);
6255 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6256 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6260 if (po->flags & OPF_REP) {
6261 assert_operand_cnt(3);
6266 assert_operand_cnt(2);
6267 fprintf(fout, " %s = %sesi; esi %c= %d;",
6268 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6269 lmod_cast_u_ptr(po, po->operand[1].lmod),
6270 (po->flags & OPF_DF) ? '-' : '+',
6271 lmod_bytes(po, po->operand[1].lmod));
6272 strcpy(g_comment, "lods");
6277 if (po->flags & OPF_REP) {
6278 assert_operand_cnt(3);
6279 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6280 (po->flags & OPF_DF) ? '-' : '+',
6281 lmod_bytes(po, po->operand[1].lmod));
6282 fprintf(fout, " %sedi = eax;",
6283 lmod_cast_u_ptr(po, po->operand[1].lmod));
6284 strcpy(g_comment, "rep stos");
6287 assert_operand_cnt(2);
6288 fprintf(fout, " %sedi = eax; edi %c= %d;",
6289 lmod_cast_u_ptr(po, po->operand[1].lmod),
6290 (po->flags & OPF_DF) ? '-' : '+',
6291 lmod_bytes(po, po->operand[1].lmod));
6292 strcpy(g_comment, "stos");
6297 j = lmod_bytes(po, po->operand[0].lmod);
6298 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6299 l = (po->flags & OPF_DF) ? '-' : '+';
6300 if (po->flags & OPF_REP) {
6301 assert_operand_cnt(3);
6303 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6306 " %sedi = %sesi;", buf1, buf1);
6307 strcpy(g_comment, "rep movs");
6310 assert_operand_cnt(2);
6311 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6312 buf1, buf1, l, j, l, j);
6313 strcpy(g_comment, "movs");
6318 // repe ~ repeat while ZF=1
6319 j = lmod_bytes(po, po->operand[0].lmod);
6320 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6321 l = (po->flags & OPF_DF) ? '-' : '+';
6322 if (po->flags & OPF_REP) {
6323 assert_operand_cnt(3);
6325 " while (ecx != 0) {\n");
6326 if (pfomask & (1 << PFO_C)) {
6329 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6330 pfomask &= ~(1 << PFO_C);
6333 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6334 buf1, buf1, l, j, l, j);
6337 " if (cond_z %s 0) break;\n",
6338 (po->flags & OPF_REPZ) ? "==" : "!=");
6341 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6342 (po->flags & OPF_REPZ) ? "e" : "ne");
6345 assert_operand_cnt(2);
6347 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6348 buf1, buf1, l, j, l, j);
6349 strcpy(g_comment, "cmps");
6351 pfomask &= ~(1 << PFO_Z);
6352 last_arith_dst = NULL;
6353 delayed_flag_op = NULL;
6357 // only does ZF (for now)
6358 // repe ~ repeat while ZF=1
6359 j = lmod_bytes(po, po->operand[1].lmod);
6360 l = (po->flags & OPF_DF) ? '-' : '+';
6361 if (po->flags & OPF_REP) {
6362 assert_operand_cnt(3);
6364 " while (ecx != 0) {\n");
6366 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6367 lmod_cast_u(po, po->operand[1].lmod),
6368 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6371 " if (cond_z %s 0) break;\n",
6372 (po->flags & OPF_REPZ) ? "==" : "!=");
6375 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6376 (po->flags & OPF_REPZ) ? "e" : "ne");
6379 assert_operand_cnt(2);
6380 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6381 lmod_cast_u(po, po->operand[1].lmod),
6382 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6383 strcpy(g_comment, "scas");
6385 pfomask &= ~(1 << PFO_Z);
6386 last_arith_dst = NULL;
6387 delayed_flag_op = NULL;
6390 // arithmetic w/flags
6392 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6393 goto dualop_arith_const;
6394 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6398 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6399 if (po->operand[1].type == OPT_CONST) {
6400 j = lmod_bytes(po, po->operand[0].lmod);
6401 if (((1ull << j * 8) - 1) == po->operand[1].val)
6402 goto dualop_arith_const;
6407 assert_operand_cnt(2);
6408 fprintf(fout, " %s %s= %s;",
6409 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6411 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6412 output_std_flags(fout, po, &pfomask, buf1);
6413 last_arith_dst = &po->operand[0];
6414 delayed_flag_op = NULL;
6418 // and 0, or ~0 used instead mov
6419 assert_operand_cnt(2);
6420 fprintf(fout, " %s = %s;",
6421 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6422 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6423 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6424 output_std_flags(fout, po, &pfomask, buf1);
6425 last_arith_dst = &po->operand[0];
6426 delayed_flag_op = NULL;
6431 assert_operand_cnt(2);
6432 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6433 if (pfomask & (1 << PFO_C)) {
6434 if (po->operand[1].type == OPT_CONST) {
6435 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6436 j = po->operand[1].val;
6439 if (po->op == OP_SHL)
6443 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6447 ferr(po, "zero shift?\n");
6451 pfomask &= ~(1 << PFO_C);
6453 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6454 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6455 if (po->operand[1].type != OPT_CONST)
6456 fprintf(fout, " & 0x1f");
6458 output_std_flags(fout, po, &pfomask, buf1);
6459 last_arith_dst = &po->operand[0];
6460 delayed_flag_op = NULL;
6464 assert_operand_cnt(2);
6465 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6466 fprintf(fout, " %s = %s%s >> %s;", buf1,
6467 lmod_cast_s(po, po->operand[0].lmod), buf1,
6468 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6469 output_std_flags(fout, po, &pfomask, buf1);
6470 last_arith_dst = &po->operand[0];
6471 delayed_flag_op = NULL;
6476 assert_operand_cnt(3);
6477 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6478 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6479 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6480 if (po->operand[2].type != OPT_CONST) {
6481 // no handling for "undefined" case, hopefully not needed
6482 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6485 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6486 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6487 if (po->op == OP_SHLD) {
6488 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6489 buf1, buf3, buf1, buf2, l, buf3);
6490 strcpy(g_comment, "shld");
6493 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6494 buf1, buf3, buf1, buf2, l, buf3);
6495 strcpy(g_comment, "shrd");
6497 output_std_flags(fout, po, &pfomask, buf1);
6498 last_arith_dst = &po->operand[0];
6499 delayed_flag_op = NULL;
6504 assert_operand_cnt(2);
6505 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6506 if (po->operand[1].type == OPT_CONST) {
6507 j = po->operand[1].val;
6508 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6509 fprintf(fout, po->op == OP_ROL ?
6510 " %s = (%s << %d) | (%s >> %d);" :
6511 " %s = (%s >> %d) | (%s << %d);",
6512 buf1, buf1, j, buf1,
6513 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6517 output_std_flags(fout, po, &pfomask, buf1);
6518 last_arith_dst = &po->operand[0];
6519 delayed_flag_op = NULL;
6524 assert_operand_cnt(2);
6525 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6526 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6527 if (po->operand[1].type == OPT_CONST) {
6528 j = po->operand[1].val % l;
6530 ferr(po, "zero rotate\n");
6531 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6532 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6533 if (po->op == OP_RCL) {
6535 " %s = (%s << %d) | (cond_c << %d)",
6536 buf1, buf1, j, j - 1);
6538 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6542 " %s = (%s >> %d) | (cond_c << %d)",
6543 buf1, buf1, j, l - j);
6545 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6547 fprintf(fout, ";\n");
6548 fprintf(fout, " cond_c = tmp;");
6552 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6553 output_std_flags(fout, po, &pfomask, buf1);
6554 last_arith_dst = &po->operand[0];
6555 delayed_flag_op = NULL;
6559 assert_operand_cnt(2);
6560 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6561 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6562 // special case for XOR
6563 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
6564 for (j = 0; j <= PFO_LE; j++) {
6565 if (pfomask & (1 << j)) {
6566 fprintf(fout, " cond_%s = %d;\n",
6567 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
6568 pfomask &= ~(1 << j);
6571 fprintf(fout, " %s = 0;",
6572 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6573 last_arith_dst = &po->operand[0];
6574 delayed_flag_op = NULL;
6580 assert_operand_cnt(2);
6581 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6582 if (pfomask & (1 << PFO_C)) {
6583 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6584 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6585 if (po->operand[0].lmod == OPLM_DWORD) {
6586 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6587 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6588 fprintf(fout, " %s = (u32)tmp64;",
6589 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6590 strcat(g_comment, " add64");
6593 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6594 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6595 fprintf(fout, " %s += %s;",
6596 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6599 pfomask &= ~(1 << PFO_C);
6600 output_std_flags(fout, po, &pfomask, buf1);
6601 last_arith_dst = &po->operand[0];
6602 delayed_flag_op = NULL;
6605 if (pfomask & (1 << PFO_LE)) {
6606 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
6607 fprintf(fout, " cond_%s = %s;\n",
6608 parsed_flag_op_names[PFO_LE], buf1);
6609 pfomask &= ~(1 << PFO_LE);
6614 assert_operand_cnt(2);
6615 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6616 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6617 for (j = 0; j <= PFO_LE; j++) {
6618 if (!(pfomask & (1 << j)))
6620 if (j == PFO_Z || j == PFO_S)
6623 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6624 fprintf(fout, " cond_%s = %s;\n",
6625 parsed_flag_op_names[j], buf1);
6626 pfomask &= ~(1 << j);
6633 assert_operand_cnt(2);
6634 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6635 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6636 if (po->op == OP_SBB
6637 && IS(po->operand[0].name, po->operand[1].name))
6639 // avoid use of unitialized var
6640 fprintf(fout, " %s = -cond_c;", buf1);
6641 // carry remains what it was
6642 pfomask &= ~(1 << PFO_C);
6645 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6646 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6648 output_std_flags(fout, po, &pfomask, buf1);
6649 last_arith_dst = &po->operand[0];
6650 delayed_flag_op = NULL;
6654 assert_operand_cnt(2);
6655 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6656 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6657 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6659 output_std_flags(fout, po, &pfomask, buf1);
6660 last_arith_dst = &po->operand[0];
6661 delayed_flag_op = NULL;
6662 strcat(g_comment, " bsf");
6666 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6667 for (j = 0; j <= PFO_LE; j++) {
6668 if (!(pfomask & (1 << j)))
6670 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6673 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6674 fprintf(fout, " cond_%s = %s;\n",
6675 parsed_flag_op_names[j], buf1);
6676 pfomask &= ~(1 << j);
6682 if (pfomask & (1 << PFO_C))
6683 // carry is unaffected by inc/dec.. wtf?
6684 ferr(po, "carry propagation needed\n");
6686 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6687 if (po->operand[0].type == OPT_REG) {
6688 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6689 fprintf(fout, " %s%s;", buf1, buf2);
6692 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6693 fprintf(fout, " %s %s= 1;", buf1, buf2);
6695 output_std_flags(fout, po, &pfomask, buf1);
6696 last_arith_dst = &po->operand[0];
6697 delayed_flag_op = NULL;
6701 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6702 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6703 fprintf(fout, " %s = -%s%s;", buf1,
6704 lmod_cast_s(po, po->operand[0].lmod), buf2);
6705 last_arith_dst = &po->operand[0];
6706 delayed_flag_op = NULL;
6707 if (pfomask & (1 << PFO_C)) {
6708 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6709 pfomask &= ~(1 << PFO_C);
6714 if (po->operand_cnt == 2) {
6715 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6718 if (po->operand_cnt == 3)
6719 ferr(po, "TODO imul3\n");
6722 assert_operand_cnt(1);
6723 switch (po->operand[0].lmod) {
6725 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6726 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6727 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6728 fprintf(fout, " edx = tmp64 >> 32;\n");
6729 fprintf(fout, " eax = tmp64;");
6732 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6733 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6734 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6738 ferr(po, "TODO: unhandled mul type\n");
6741 last_arith_dst = NULL;
6742 delayed_flag_op = NULL;
6747 assert_operand_cnt(1);
6748 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6749 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6750 po->op == OP_IDIV));
6751 switch (po->operand[0].lmod) {
6753 if (po->flags & OPF_32BIT)
6754 snprintf(buf2, sizeof(buf2), "%seax", cast);
6756 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6757 snprintf(buf2, sizeof(buf2), "%stmp64",
6758 (po->op == OP_IDIV) ? "(s64)" : "");
6760 if (po->operand[0].type == OPT_REG
6761 && po->operand[0].reg == xDX)
6763 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6764 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6767 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6768 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6772 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6773 snprintf(buf2, sizeof(buf2), "%stmp",
6774 (po->op == OP_IDIV) ? "(s32)" : "");
6775 if (po->operand[0].type == OPT_REG
6776 && po->operand[0].reg == xDX)
6778 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6780 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6784 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6786 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6789 strcat(g_comment, " div16");
6792 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6794 last_arith_dst = NULL;
6795 delayed_flag_op = NULL;
6800 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6802 for (j = 0; j < 8; j++) {
6803 if (pfomask & (1 << j)) {
6804 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6805 fprintf(fout, " cond_%s = %s;",
6806 parsed_flag_op_names[j], buf1);
6813 last_arith_dst = NULL;
6814 delayed_flag_op = po;
6818 // SETcc - should already be handled
6821 // note: we reuse OP_Jcc for SETcc, only flags differ
6823 fprintf(fout, "\n goto %s;", po->operand[0].name);
6827 fprintf(fout, " if (ecx == 0)\n");
6828 fprintf(fout, " goto %s;", po->operand[0].name);
6829 strcat(g_comment, " jecxz");
6833 fprintf(fout, " if (--ecx != 0)\n");
6834 fprintf(fout, " goto %s;", po->operand[0].name);
6835 strcat(g_comment, " loop");
6839 assert_operand_cnt(1);
6840 last_arith_dst = NULL;
6841 delayed_flag_op = NULL;
6843 if (po->operand[0].type == OPT_REGMEM) {
6844 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6847 ferr(po, "parse failure for jmp '%s'\n",
6848 po->operand[0].name);
6849 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6852 else if (po->operand[0].type != OPT_LABEL)
6853 ferr(po, "unhandled jmp type\n");
6855 fprintf(fout, " goto %s;", po->operand[0].name);
6859 assert_operand_cnt(1);
6861 my_assert_not(pp, NULL);
6864 if (po->flags & OPF_CC) {
6865 // we treat conditional branch to another func
6866 // (yes such code exists..) as conditional tailcall
6868 fprintf(fout, " {\n");
6871 if (pp->is_fptr && !pp->is_arg) {
6872 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6873 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6875 if (pp->is_unresolved)
6876 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6877 buf3, asmfn, po->asmln, pp->name);
6880 fprintf(fout, "%s", buf3);
6881 if (strstr(pp->ret_type.name, "int64")) {
6882 if (po->flags & OPF_TAIL)
6883 ferr(po, "int64 and tail?\n");
6884 fprintf(fout, "tmp64 = ");
6886 else if (!IS(pp->ret_type.name, "void")) {
6887 if (po->flags & OPF_TAIL) {
6888 if (regmask_ret & mxAX) {
6889 fprintf(fout, "return ");
6890 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6891 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6893 else if (regmask_ret & mxST0)
6894 ferr(po, "float tailcall\n");
6896 else if (po->regmask_dst & mxAX) {
6897 fprintf(fout, "eax = ");
6898 if (pp->ret_type.is_ptr)
6899 fprintf(fout, "(u32)");
6901 else if (po->regmask_dst & mxST0) {
6902 ferr_assert(po, po->flags & OPF_FPUSH);
6903 if (need_float_stack)
6904 fprintf(fout, "f_st[--f_stp & 7] = ");
6906 fprintf(fout, "f_st0 = ");
6910 if (pp->name[0] == 0)
6911 ferr(po, "missing pp->name\n");
6912 fprintf(fout, "%s%s(", pp->name,
6913 pp->has_structarg ? "_sa" : "");
6915 if (po->flags & OPF_ATAIL) {
6916 if (pp->argc_stack != g_func_pp->argc_stack
6917 || (pp->argc_stack > 0
6918 && pp->is_stdcall != g_func_pp->is_stdcall))
6919 ferr(po, "incompatible tailcall\n");
6920 if (g_func_pp->has_retreg)
6921 ferr(po, "TODO: retreg+tailcall\n");
6923 for (arg = j = 0; arg < pp->argc; arg++) {
6925 fprintf(fout, ", ");
6928 if (pp->arg[arg].type.is_ptr)
6929 snprintf(cast, sizeof(cast), "(%s)",
6930 pp->arg[arg].type.name);
6932 if (pp->arg[arg].reg != NULL) {
6933 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6937 for (; j < g_func_pp->argc; j++)
6938 if (g_func_pp->arg[j].reg == NULL)
6940 fprintf(fout, "%sa%d", cast, j + 1);
6945 for (arg = 0; arg < pp->argc; arg++) {
6947 fprintf(fout, ", ");
6950 if (pp->arg[arg].type.is_ptr)
6951 snprintf(cast, sizeof(cast), "(%s)",
6952 pp->arg[arg].type.name);
6954 if (pp->arg[arg].reg != NULL) {
6955 if (pp->arg[arg].type.is_retreg)
6956 fprintf(fout, "&%s", pp->arg[arg].reg);
6957 else if (IS(pp->arg[arg].reg, "ebp")
6958 && g_bp_frame && !(po->flags & OPF_EBP_S))
6960 // rare special case
6961 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
6962 strcat(g_comment, " bp_ref");
6965 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6970 tmp_op = pp->arg[arg].datap;
6972 ferr(po, "parsed_op missing for arg%d\n", arg);
6974 if (tmp_op->flags & OPF_VAPUSH) {
6975 fprintf(fout, "ap");
6977 else if (tmp_op->op == OP_FST) {
6978 fprintf(fout, "fs_%d", tmp_op->p_argnum);
6979 if (tmp_op->operand[0].lmod == OPLM_QWORD)
6982 else if (tmp_op->p_argpass != 0) {
6983 fprintf(fout, "a%d", tmp_op->p_argpass);
6985 else if (pp->arg[arg].is_saved) {
6986 ferr_assert(po, tmp_op->p_argnum > 0);
6987 fprintf(fout, "%s%s", cast,
6988 saved_arg_name(buf1, sizeof(buf1),
6989 tmp_op->p_arggrp, tmp_op->p_argnum));
6993 out_src_opr(buf1, sizeof(buf1),
6994 tmp_op, &tmp_op->operand[0], cast, 0));
6998 fprintf(fout, ");");
7000 if (strstr(pp->ret_type.name, "int64")) {
7001 fprintf(fout, "\n");
7002 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7003 fprintf(fout, "%seax = tmp64;", buf3);
7006 if (pp->is_unresolved) {
7007 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7009 strcat(g_comment, buf2);
7012 if (po->flags & OPF_TAIL) {
7014 if (i == opcnt - 1 || pp->is_noreturn)
7016 else if (IS(pp->ret_type.name, "void"))
7018 else if (!(regmask_ret & (1 << xAX)))
7020 // else already handled as 'return f()'
7023 fprintf(fout, "\n%sreturn;", buf3);
7024 strcat(g_comment, " ^ tailcall");
7027 strcat(g_comment, " tailcall");
7029 if ((regmask_ret & (1 << xAX))
7030 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7032 ferr(po, "int func -> void func tailcall?\n");
7035 if (pp->is_noreturn)
7036 strcat(g_comment, " noreturn");
7037 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7038 strcat(g_comment, " argframe");
7039 if (po->flags & OPF_CC)
7040 strcat(g_comment, " cond");
7042 if (po->flags & OPF_CC)
7043 fprintf(fout, "\n }");
7045 delayed_flag_op = NULL;
7046 last_arith_dst = NULL;
7050 if (g_func_pp->is_vararg)
7051 fprintf(fout, " va_end(ap);\n");
7052 if (g_func_pp->has_retreg) {
7053 for (arg = 0; arg < g_func_pp->argc; arg++)
7054 if (g_func_pp->arg[arg].type.is_retreg)
7055 fprintf(fout, " *r_%s = %s;\n",
7056 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7059 if (regmask_ret & mxST0) {
7060 fprintf(fout, " return %s;", float_st0);
7062 else if (!(regmask_ret & mxAX)) {
7063 if (i != opcnt - 1 || label_pending)
7064 fprintf(fout, " return;");
7066 else if (g_func_pp->ret_type.is_ptr) {
7067 fprintf(fout, " return (%s)eax;",
7068 g_func_pp->ret_type.name);
7070 else if (IS(g_func_pp->ret_type.name, "__int64"))
7071 fprintf(fout, " return ((u64)edx << 32) | eax;");
7073 fprintf(fout, " return eax;");
7075 last_arith_dst = NULL;
7076 delayed_flag_op = NULL;
7080 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7081 if (po->p_argnum != 0) {
7082 // special case - saved func arg
7083 fprintf(fout, " %s = %s;",
7084 saved_arg_name(buf2, sizeof(buf2),
7085 po->p_arggrp, po->p_argnum), buf1);
7088 else if (po->flags & OPF_RSAVE) {
7089 fprintf(fout, " s_%s = %s;", buf1, buf1);
7092 else if (po->flags & OPF_PPUSH) {
7094 ferr_assert(po, tmp_op != NULL);
7095 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7096 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7099 else if (g_func_pp->is_userstack) {
7100 fprintf(fout, " *(--esp) = %s;", buf1);
7103 if (!(g_ida_func_attr & IDAFA_NORETURN))
7104 ferr(po, "stray push encountered\n");
7109 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7110 if (po->flags & OPF_RSAVE) {
7111 fprintf(fout, " %s = s_%s;", buf1, buf1);
7114 else if (po->flags & OPF_PPUSH) {
7115 // push/pop graph / non-const
7116 ferr_assert(po, po->datap == NULL);
7117 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7120 else if (po->datap != NULL) {
7123 fprintf(fout, " %s = %s;", buf1,
7124 out_src_opr(buf2, sizeof(buf2),
7125 tmp_op, &tmp_op->operand[0],
7126 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7129 else if (g_func_pp->is_userstack) {
7130 fprintf(fout, " %s = *esp++;", buf1);
7134 ferr(po, "stray pop encountered\n");
7144 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7145 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7146 po->op == OPP_ALLSHL ? "<<" : ">>");
7147 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7148 strcat(g_comment, po->op == OPP_ALLSHL
7149 ? " allshl" : " allshr");
7154 if (need_float_stack) {
7155 out_src_opr_float(buf1, sizeof(buf1),
7156 po, &po->operand[0], 1);
7157 if (po->regmask_src & mxSTa) {
7158 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7162 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7165 if (po->flags & OPF_FSHIFT)
7166 fprintf(fout, " f_st1 = f_st0;");
7167 if (po->operand[0].type == OPT_REG
7168 && po->operand[0].reg == xST0)
7170 strcat(g_comment, " fld st");
7173 fprintf(fout, " f_st0 = %s;",
7174 out_src_opr_float(buf1, sizeof(buf1),
7175 po, &po->operand[0], 0));
7177 strcat(g_comment, " fld");
7181 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7182 lmod_cast(po, po->operand[0].lmod, 1), 0);
7183 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7184 if (need_float_stack) {
7185 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7188 if (po->flags & OPF_FSHIFT)
7189 fprintf(fout, " f_st1 = f_st0;");
7190 fprintf(fout, " f_st0 = %s;", buf2);
7192 strcat(g_comment, " fild");
7196 if (need_float_stack)
7197 fprintf(fout, " f_st[--f_stp & 7] = ");
7199 if (po->flags & OPF_FSHIFT)
7200 fprintf(fout, " f_st1 = f_st0;");
7201 fprintf(fout, " f_st0 = ");
7203 switch (po->operand[0].val) {
7204 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7205 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
7206 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7207 default: ferr(po, "TODO\n"); break;
7212 if (po->flags & OPF_FARG) {
7213 // store to stack as func arg
7214 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7218 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7220 dead_dst = po->operand[0].type == OPT_REG
7221 && po->operand[0].reg == xST0;
7224 fprintf(fout, " %s = %s;", buf1, float_st0);
7225 if (po->flags & OPF_FSHIFT) {
7226 if (need_float_stack)
7227 fprintf(fout, " f_stp++;");
7229 fprintf(fout, " f_st0 = f_st1;");
7231 if (dead_dst && !(po->flags & OPF_FSHIFT))
7234 strcat(g_comment, " fst");
7238 fprintf(fout, " %s = %s%s;",
7239 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7240 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7241 if (po->flags & OPF_FSHIFT) {
7242 if (need_float_stack)
7243 fprintf(fout, " f_stp++;");
7245 fprintf(fout, " f_st0 = f_st1;");
7247 strcat(g_comment, " fist");
7254 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7256 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7258 dead_dst = (po->flags & OPF_FPOP)
7259 && po->operand[0].type == OPT_REG
7260 && po->operand[0].reg == xST0;
7262 case OP_FADD: j = '+'; break;
7263 case OP_FDIV: j = '/'; break;
7264 case OP_FMUL: j = '*'; break;
7265 case OP_FSUB: j = '-'; break;
7266 default: j = 'x'; break;
7268 if (need_float_stack) {
7270 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7271 if (po->flags & OPF_FSHIFT)
7272 fprintf(fout, " f_stp++;");
7275 if (po->flags & OPF_FSHIFT) {
7276 // note: assumes only 2 regs handled
7278 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7280 fprintf(fout, " f_st0 = f_st1;");
7283 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7285 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7290 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7292 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7294 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7296 dead_dst = (po->flags & OPF_FPOP)
7297 && po->operand[0].type == OPT_REG
7298 && po->operand[0].reg == xST0;
7299 j = po->op == OP_FDIVR ? '/' : '-';
7300 if (need_float_stack) {
7302 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7303 if (po->flags & OPF_FSHIFT)
7304 fprintf(fout, " f_stp++;");
7307 if (po->flags & OPF_FSHIFT) {
7309 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7311 fprintf(fout, " f_st0 = f_st1;");
7314 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7316 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7324 case OP_FIADD: j = '+'; break;
7325 case OP_FIDIV: j = '/'; break;
7326 case OP_FIMUL: j = '*'; break;
7327 case OP_FISUB: j = '-'; break;
7328 default: j = 'x'; break;
7330 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7332 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7333 lmod_cast(po, po->operand[0].lmod, 1), 0));
7338 fprintf(fout, " %s = %s %c %s;", float_st0,
7339 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7341 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7346 ferr_assert(po, po->datap != NULL);
7347 mask = (long)po->datap & 0xffff;
7348 z_check = ((long)po->datap >> 16) & 1;
7349 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7351 if (mask == 0x0100) { // C0 -> <
7352 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7355 else if (mask == 0x4000) { // C3 -> =
7356 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7359 else if (mask == 0x4100) { // C3, C0
7361 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7363 strcat(g_comment, " z_chk_det");
7366 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7367 "(%s < %s ? 0x0100 : 0);",
7368 float_st0, buf1, float_st0, buf1);
7372 ferr(po, "unhandled sw mask: %x\n", mask);
7373 if (po->flags & OPF_FSHIFT) {
7374 if (need_float_stack)
7375 fprintf(fout, " f_stp++;");
7377 fprintf(fout, " f_st0 = f_st1;");
7383 fprintf(fout, " %s = f_sw;",
7384 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7388 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7392 fprintf(fout, " %s = cos%s(%s);", float_st0,
7393 need_double ? "" : "f", float_st0);
7397 if (need_float_stack) {
7398 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7399 need_double ? "" : "f", float_st1, float_st0);
7400 fprintf(fout, " f_stp++;");
7403 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7404 need_double ? "" : "f");
7409 if (need_float_stack) {
7410 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7411 float_st1, need_double ? "" : "f", float_st0);
7412 fprintf(fout, " f_stp++;");
7415 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7416 need_double ? "" : "f");
7418 strcat(g_comment, " fyl2x");
7422 fprintf(fout, " %s = sin%s(%s);", float_st0,
7423 need_double ? "" : "f", float_st0);
7427 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7428 need_double ? "" : "f", float_st0);
7432 dead_dst = po->operand[0].type == OPT_REG
7433 && po->operand[0].reg == xST0;
7435 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7437 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7438 float_st0, float_st0, buf1, buf1);
7439 strcat(g_comment, " fxch");
7446 ferr_assert(po, po->flags & OPF_32BIT);
7447 fprintf(fout, " eax = (s32)%s;", float_st0);
7448 if (po->flags & OPF_FSHIFT) {
7449 if (need_float_stack)
7450 fprintf(fout, " f_stp++;");
7452 fprintf(fout, " f_st0 = f_st1;");
7454 strcat(g_comment, " ftol");
7458 if (need_float_stack) {
7459 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
7460 need_double ? "" : "f", float_st1, float_st0);
7461 fprintf(fout, " f_stp++;");
7464 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
7465 need_double ? "" : "f");
7467 strcat(g_comment, " CIpow");
7471 fprintf(fout, " do_skip_code_abort();");
7476 fprintf(fout, " do_emms();");
7481 ferr(po, "unhandled op type %d, flags %x\n",
7486 if (g_comment[0] != 0) {
7487 char *p = g_comment;
7488 while (my_isblank(*p))
7490 fprintf(fout, " // %s", p);
7495 fprintf(fout, "\n");
7497 // some sanity checking
7498 if (po->flags & OPF_REP) {
7499 if (po->op != OP_STOS && po->op != OP_MOVS
7500 && po->op != OP_CMPS && po->op != OP_SCAS)
7501 ferr(po, "unexpected rep\n");
7502 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7503 && (po->op == OP_CMPS || po->op == OP_SCAS))
7504 ferr(po, "cmps/scas with plain rep\n");
7506 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7507 && po->op != OP_CMPS && po->op != OP_SCAS)
7508 ferr(po, "unexpected repz/repnz\n");
7511 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
7513 // see is delayed flag stuff is still valid
7514 if (delayed_flag_op != NULL && delayed_flag_op != po) {
7515 if (is_any_opr_modified(delayed_flag_op, po, 0))
7516 delayed_flag_op = NULL;
7519 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7520 if (is_opr_modified(last_arith_dst, po))
7521 last_arith_dst = NULL;
7527 if (g_stack_fsz && !g_stack_frame_used)
7528 fprintf(fout, " (void)sf;\n");
7530 fprintf(fout, "}\n\n");
7532 gen_x_cleanup(opcnt);
7535 static void gen_x_cleanup(int opcnt)
7539 for (i = 0; i < opcnt; i++) {
7540 struct label_ref *lr, *lr_del;
7542 lr = g_label_refs[i].next;
7543 while (lr != NULL) {
7548 g_label_refs[i].i = -1;
7549 g_label_refs[i].next = NULL;
7551 if (ops[i].op == OP_CALL) {
7553 proto_release(ops[i].pp);
7559 struct func_proto_dep;
7561 struct func_prototype {
7566 int has_ret:3; // -1, 0, 1: unresolved, no, yes
7567 unsigned int dep_resolved:1;
7568 unsigned int is_stdcall:1;
7569 struct func_proto_dep *dep_func;
7571 const struct parsed_proto *pp; // seed pp, if any
7574 struct func_proto_dep {
7576 struct func_prototype *proto;
7577 int regmask_live; // .. at the time of call
7578 unsigned int ret_dep:1; // return from this is caller's return
7581 static struct func_prototype *hg_fp;
7582 static int hg_fp_cnt;
7584 static struct scanned_var {
7586 enum opr_lenmod lmod;
7587 unsigned int is_seeded:1;
7588 unsigned int is_c_str:1;
7589 const struct parsed_proto *pp; // seed pp, if any
7591 static int hg_var_cnt;
7593 static char **hg_refs;
7594 static int hg_ref_cnt;
7596 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7599 static struct func_prototype *hg_fp_add(const char *funcn)
7601 struct func_prototype *fp;
7603 if ((hg_fp_cnt & 0xff) == 0) {
7604 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7605 my_assert_not(hg_fp, NULL);
7606 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7609 fp = &hg_fp[hg_fp_cnt];
7610 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7612 fp->argc_stack = -1;
7618 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7623 for (i = 0; i < fp->dep_func_cnt; i++)
7624 if (IS(fp->dep_func[i].name, name))
7625 return &fp->dep_func[i];
7630 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7633 if (hg_fp_find_dep(fp, name))
7636 if ((fp->dep_func_cnt & 0xff) == 0) {
7637 fp->dep_func = realloc(fp->dep_func,
7638 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7639 my_assert_not(fp->dep_func, NULL);
7640 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7641 sizeof(fp->dep_func[0]) * 0x100);
7643 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7647 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7649 const struct func_prototype *p1 = p1_, *p2 = p2_;
7650 return strcmp(p1->name, p2->name);
7654 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7656 const struct func_prototype *p1 = p1_, *p2 = p2_;
7657 return p1->id - p2->id;
7661 static void hg_ref_add(const char *name)
7663 if ((hg_ref_cnt & 0xff) == 0) {
7664 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7665 my_assert_not(hg_refs, NULL);
7666 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7669 hg_refs[hg_ref_cnt] = strdup(name);
7670 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7674 // recursive register dep pass
7675 // - track saved regs (part 2)
7676 // - try to figure out arg-regs
7677 // - calculate reg deps
7678 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
7679 struct func_prototype *fp, int regmask_save, int regmask_dst,
7680 int *regmask_dep, int *has_ret)
7682 struct func_proto_dep *dep;
7683 struct parsed_op *po;
7684 int from_caller = 0;
7689 for (; i < opcnt; i++)
7691 if (cbits[i >> 3] & (1 << (i & 7)))
7693 cbits[i >> 3] |= (1 << (i & 7));
7697 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
7698 if (po->flags & OPF_RMD)
7701 if (po->btj != NULL) {
7703 for (j = 0; j < po->btj->count; j++) {
7704 check_i(po, po->btj->d[j].bt_i);
7705 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
7706 regmask_save, regmask_dst, regmask_dep, has_ret);
7711 check_i(po, po->bt_i);
7712 if (po->flags & OPF_CJMP) {
7713 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
7714 regmask_save, regmask_dst, regmask_dep, has_ret);
7722 if (po->flags & OPF_FARG)
7723 /* (just calculate register deps) */;
7724 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
7726 reg = po->operand[0].reg;
7727 ferr_assert(po, reg >= 0);
7729 if (po->flags & OPF_RSAVE) {
7730 regmask_save |= 1 << reg;
7733 if (po->flags & OPF_DONE)
7736 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
7738 regmask_save |= 1 << reg;
7739 po->flags |= OPF_RMD;
7740 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
7744 else if (po->flags & OPF_RMD)
7746 else if (po->op == OP_CALL) {
7747 po->regmask_dst |= 1 << xAX;
7749 dep = hg_fp_find_dep(fp, po->operand[0].name);
7751 dep->regmask_live = regmask_save | regmask_dst;
7752 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7753 dep->regmask_live |= 1 << xBP;
7756 else if (po->op == OP_RET) {
7757 if (po->operand_cnt > 0) {
7759 if (fp->argc_stack >= 0
7760 && fp->argc_stack != po->operand[0].val / 4)
7761 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
7762 fp->argc_stack = po->operand[0].val / 4;
7766 // if has_ret is 0, there is uninitialized eax path,
7767 // which means it's most likely void func
7768 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
7769 if (po->op == OP_CALL) {
7774 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
7777 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
7780 if (ret != 1 && from_caller) {
7781 // unresolved eax - probably void func
7785 if (j >= 0 && ops[j].op == OP_CALL) {
7786 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
7797 l = regmask_save | regmask_dst;
7798 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7801 l = po->regmask_src & ~l;
7804 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
7805 l, regmask_dst, regmask_save, po->flags);
7808 regmask_dst |= po->regmask_dst;
7810 if (po->flags & OPF_TAIL)
7815 static void gen_hdr(const char *funcn, int opcnt)
7817 unsigned char cbits[MAX_OPS / 8];
7818 const struct parsed_proto *pp_c;
7819 struct parsed_proto *pp;
7820 struct func_prototype *fp;
7821 struct parsed_op *po;
7822 int regmask_dummy = 0;
7824 int max_bp_offset = 0;
7829 pp_c = proto_parse(g_fhdr, funcn, 1);
7831 // already in seed, will add to hg_fp later
7834 fp = hg_fp_add(funcn);
7836 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7837 g_stack_frame_used = 0;
7840 // - resolve all branches
7841 // - parse calls with labels
7842 resolve_branches_parse_calls(opcnt);
7845 // - handle ebp/esp frame, remove ops related to it
7846 scan_prologue_epilogue(opcnt);
7849 // - remove dead labels
7851 for (i = 0; i < opcnt; i++)
7853 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7859 if (po->flags & (OPF_RMD|OPF_DONE))
7862 if (po->op == OP_CALL) {
7863 if (po->operand[0].type == OPT_LABEL)
7864 hg_fp_add_dep(fp, opr_name(po, 0));
7865 else if (po->pp != NULL)
7866 hg_fp_add_dep(fp, po->pp->name);
7871 // - remove dead labels
7872 // - handle push <const>/pop pairs
7873 for (i = 0; i < opcnt; i++)
7875 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7881 if (po->flags & (OPF_RMD|OPF_DONE))
7884 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
7885 scan_for_pop_const(i, opcnt, i + opcnt * 13);
7889 // - process trivial calls
7890 for (i = 0; i < opcnt; i++)
7893 if (po->flags & (OPF_RMD|OPF_DONE))
7896 if (po->op == OP_CALL)
7898 pp = process_call_early(i, opcnt, &j);
7900 if (!(po->flags & OPF_ATAIL))
7901 // since we know the args, try to collect them
7902 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
7908 // commit esp adjust
7909 if (ops[j].op != OP_POP)
7910 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
7912 for (l = 0; l < pp->argc_stack; l++)
7913 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
7917 po->flags |= OPF_DONE;
7923 // - track saved regs (simple)
7925 for (i = 0; i < opcnt; i++)
7928 if (po->flags & (OPF_RMD|OPF_DONE))
7931 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7932 && po->operand[0].reg != xCX)
7934 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
7936 // regmask_save |= 1 << po->operand[0].reg; // do it later
7937 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
7938 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
7941 else if (po->op == OP_CALL)
7943 pp = process_call(i, opcnt);
7945 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
7946 // since we know the args, collect them
7947 ret = collect_call_args(po, i, pp, ®mask_dummy,
7954 memset(cbits, 0, sizeof(cbits));
7958 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
7960 // find unreachable code - must be fixed in IDA
7961 for (i = 0; i < opcnt; i++)
7963 if (cbits[i >> 3] & (1 << (i & 7)))
7966 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
7967 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
7969 // the compiler sometimes still generates code after
7970 // noreturn OS functions
7973 if (ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
7974 ferr(&ops[i], "unreachable code\n");
7977 for (i = 0; i < g_eqcnt; i++) {
7978 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
7979 max_bp_offset = g_eqs[i].offset;
7982 if (fp->argc_stack < 0) {
7983 max_bp_offset = (max_bp_offset + 3) & ~3;
7984 fp->argc_stack = max_bp_offset / 4;
7985 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
7989 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
7990 fp->has_ret = has_ret;
7992 printf("// has_ret %d, regmask_dep %x\n",
7993 fp->has_ret, fp->regmask_dep);
7994 output_hdr_fp(stdout, fp, 1);
7995 if (IS(funcn, "sub_10007F72")) exit(1);
7998 gen_x_cleanup(opcnt);
8001 static void hg_fp_resolve_deps(struct func_prototype *fp)
8003 struct func_prototype fp_s;
8007 // this thing is recursive, so mark first..
8008 fp->dep_resolved = 1;
8010 for (i = 0; i < fp->dep_func_cnt; i++) {
8011 strcpy(fp_s.name, fp->dep_func[i].name);
8012 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8013 sizeof(hg_fp[0]), hg_fp_cmp_name);
8014 if (fp->dep_func[i].proto != NULL) {
8015 if (!fp->dep_func[i].proto->dep_resolved)
8016 hg_fp_resolve_deps(fp->dep_func[i].proto);
8018 dep = ~fp->dep_func[i].regmask_live
8019 & fp->dep_func[i].proto->regmask_dep;
8020 fp->regmask_dep |= dep;
8021 // printf("dep %s %s |= %x\n", fp->name,
8022 // fp->dep_func[i].name, dep);
8024 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8025 fp->has_ret = fp->dep_func[i].proto->has_ret;
8030 // make all thiscall/edx arg functions referenced from .data fastcall
8031 static void do_func_refs_from_data(void)
8033 struct func_prototype *fp, fp_s;
8036 for (i = 0; i < hg_ref_cnt; i++) {
8037 strcpy(fp_s.name, hg_refs[i]);
8038 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8039 sizeof(hg_fp[0]), hg_fp_cmp_name);
8043 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8044 fp->regmask_dep |= mxCX | mxDX;
8048 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8051 const struct parsed_proto *pp;
8052 char *p, namebuf[NAMELEN];
8058 for (; count > 0; count--, fp++) {
8059 if (fp->has_ret == -1)
8060 fprintf(fout, "// ret unresolved\n");
8062 fprintf(fout, "// dep:");
8063 for (j = 0; j < fp->dep_func_cnt; j++) {
8064 fprintf(fout, " %s/", fp->dep_func[j].name);
8065 if (fp->dep_func[j].proto != NULL)
8066 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8067 fp->dep_func[j].proto->has_ret);
8069 fprintf(fout, "\n");
8072 p = strchr(fp->name, '@');
8074 memcpy(namebuf, fp->name, p - fp->name);
8075 namebuf[p - fp->name] = 0;
8083 pp = proto_parse(g_fhdr, name, 1);
8084 if (pp != NULL && pp->is_include)
8087 if (fp->pp != NULL) {
8088 // part of seed, output later
8092 regmask_dep = fp->regmask_dep;
8093 argc_normal = fp->argc_stack;
8095 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8096 (fp->has_ret ? "int" : "void"));
8097 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8098 && (regmask_dep & ~mxCX) == 0)
8100 fprintf(fout, "/*__thiscall*/ ");
8104 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8105 && (regmask_dep & ~(mxCX | mxDX)) == 0)
8107 fprintf(fout, " __fastcall ");
8108 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8114 else if (regmask_dep && !fp->is_stdcall) {
8115 fprintf(fout, "/*__usercall*/ ");
8117 else if (regmask_dep) {
8118 fprintf(fout, "/*__userpurge*/ ");
8120 else if (fp->is_stdcall)
8121 fprintf(fout, " __stdcall ");
8123 fprintf(fout, " __cdecl ");
8125 fprintf(fout, "%s(", name);
8128 for (j = 0; j < xSP; j++) {
8129 if (regmask_dep & (1 << j)) {
8132 fprintf(fout, ", ");
8134 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8136 fprintf(fout, "int");
8137 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8141 for (j = 0; j < argc_normal; j++) {
8144 fprintf(fout, ", ");
8145 if (fp->pp != NULL) {
8146 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8147 if (!fp->pp->arg[arg - 1].type.is_ptr)
8151 fprintf(fout, "int ");
8152 fprintf(fout, "a%d", arg);
8155 fprintf(fout, ");\n");
8159 static void output_hdr(FILE *fout)
8161 static const char *lmod_c_names[] = {
8162 [OPLM_UNSPEC] = "???",
8163 [OPLM_BYTE] = "uint8_t",
8164 [OPLM_WORD] = "uint16_t",
8165 [OPLM_DWORD] = "uint32_t",
8166 [OPLM_QWORD] = "uint64_t",
8168 const struct scanned_var *var;
8169 struct func_prototype *fp;
8170 char line[256] = { 0, };
8174 // add stuff from headers
8175 for (i = 0; i < pp_cache_size; i++) {
8176 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8177 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8179 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8180 fp = hg_fp_add(name);
8181 fp->pp = &pp_cache[i];
8182 fp->argc_stack = fp->pp->argc_stack;
8183 fp->is_stdcall = fp->pp->is_stdcall;
8184 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8185 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8189 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8190 for (i = 0; i < hg_fp_cnt; i++)
8191 hg_fp_resolve_deps(&hg_fp[i]);
8193 // adjust functions referenced from data segment
8194 do_func_refs_from_data();
8196 // note: messes up .proto ptr, don't use
8197 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8200 for (i = 0; i < hg_var_cnt; i++) {
8203 if (var->pp != NULL)
8206 else if (var->is_c_str)
8207 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8209 fprintf(fout, "extern %-8s %s;",
8210 lmod_c_names[var->lmod], var->name);
8213 fprintf(fout, " // seeded");
8214 fprintf(fout, "\n");
8217 fprintf(fout, "\n");
8219 // output function prototypes
8220 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8223 fprintf(fout, "\n// - seed -\n");
8226 while (fgets(line, sizeof(line), g_fhdr))
8227 fwrite(line, 1, strlen(line), fout);
8230 // '=' needs special treatment
8232 static char *next_word_s(char *w, size_t wsize, char *s)
8239 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8241 for (i = 1; i < wsize - 1; i++) {
8243 printf("warning: missing closing quote: \"%s\"\n", s);
8252 for (; i < wsize - 1; i++) {
8253 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8259 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8260 printf("warning: '%s' truncated\n", w);
8265 static int cmpstringp(const void *p1, const void *p2)
8267 return strcmp(*(char * const *)p1, *(char * const *)p2);
8270 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8275 if (strstr(p, "..."))
8276 // unable to determine, assume needed
8279 if (*p == '.') // .text, .data, ...
8280 // ref from other data or non-function -> no
8283 p2 = strpbrk(p, "+:\r\n\x18");
8286 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8287 // referenced from removed code
8293 static int ida_xrefs_show_need(FILE *fasm, char *p,
8294 char **rlist, int rlist_len)
8300 p = strrchr(p, ';');
8301 if (p != NULL && *p == ';') {
8302 if (IS_START(p + 2, "sctref"))
8304 if (IS_START(p + 2, "DATA XREF: ")) {
8306 if (is_xref_needed(p, rlist, rlist_len))
8314 if (!my_fgets(line, sizeof(line), fasm))
8316 // non-first line is always indented
8317 if (!my_isblank(line[0]))
8320 // should be no content, just comment
8325 p = strrchr(p, ';');
8328 if (IS_START(p, "sctref")) {
8333 // it's printed once, but no harm to check again
8334 if (IS_START(p, "DATA XREF: "))
8337 if (is_xref_needed(p, rlist, rlist_len)) {
8342 fseek(fasm, pos, SEEK_SET);
8346 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8348 struct scanned_var *var;
8349 char line[256] = { 0, };
8358 // skip to next data section
8359 while (my_fgets(line, sizeof(line), fasm))
8364 if (*p == 0 || *p == ';')
8367 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8368 if (*p == 0 || *p == ';')
8371 if (*p != 's' || !IS_START(p, "segment para public"))
8377 if (p == NULL || !IS_START(p, "segment para public"))
8381 if (!IS_START(p, "'DATA'"))
8385 while (my_fgets(line, sizeof(line), fasm))
8390 no_identifier = my_isblank(*p);
8393 if (*p == 0 || *p == ';')
8396 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8397 words[wordc][0] = 0;
8398 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8399 if (*p == 0 || *p == ';') {
8405 if (wordc == 2 && IS(words[1], "ends"))
8410 if (no_identifier) {
8411 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8412 hg_ref_add(words[2]);
8416 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8417 // when this starts, we don't need anything from this section
8421 // check refs comment(s)
8422 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8425 if ((hg_var_cnt & 0xff) == 0) {
8426 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8427 * (hg_var_cnt + 0x100));
8428 my_assert_not(hg_vars, NULL);
8429 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8432 var = &hg_vars[hg_var_cnt++];
8433 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8435 // maybe already in seed header?
8436 var->pp = proto_parse(g_fhdr, var->name, 1);
8437 if (var->pp != NULL) {
8438 if (var->pp->is_fptr) {
8439 var->lmod = OPLM_DWORD;
8442 else if (var->pp->is_func)
8444 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8445 aerr("unhandled C type '%s' for '%s'\n",
8446 var->pp->type.name, var->name);
8452 if (IS(words[1], "dd")) {
8453 var->lmod = OPLM_DWORD;
8454 if (wordc >= 4 && IS(words[2], "offset"))
8455 hg_ref_add(words[3]);
8457 else if (IS(words[1], "dw"))
8458 var->lmod = OPLM_WORD;
8459 else if (IS(words[1], "db")) {
8460 var->lmod = OPLM_BYTE;
8461 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8462 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8466 else if (IS(words[1], "dq"))
8467 var->lmod = OPLM_QWORD;
8468 //else if (IS(words[1], "dt"))
8470 aerr("type '%s' not known\n", words[1]);
8478 static void set_label(int i, const char *name)
8484 p = strchr(name, ':');
8488 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8489 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8490 g_labels[i] = realloc(g_labels[i], len + 1);
8491 my_assert_not(g_labels[i], NULL);
8492 memcpy(g_labels[i], name, len);
8493 g_labels[i][len] = 0;
8502 static struct chunk_item *func_chunks;
8503 static int func_chunk_cnt;
8504 static int func_chunk_alloc;
8506 static void add_func_chunk(FILE *fasm, const char *name, int line)
8508 if (func_chunk_cnt >= func_chunk_alloc) {
8509 func_chunk_alloc *= 2;
8510 func_chunks = realloc(func_chunks,
8511 func_chunk_alloc * sizeof(func_chunks[0]));
8512 my_assert_not(func_chunks, NULL);
8514 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8515 func_chunks[func_chunk_cnt].name = strdup(name);
8516 func_chunks[func_chunk_cnt].asmln = line;
8520 static int cmp_chunks(const void *p1, const void *p2)
8522 const struct chunk_item *c1 = p1, *c2 = p2;
8523 return strcmp(c1->name, c2->name);
8526 static void scan_ahead_for_chunks(FILE *fasm)
8536 oldpos = ftell(fasm);
8539 while (my_fgets(line, sizeof(line), fasm))
8550 // get rid of random tabs
8551 for (i = 0; line[i] != 0; i++)
8552 if (line[i] == '\t')
8555 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8558 next_word(words[0], sizeof(words[0]), p);
8559 if (words[0][0] == 0)
8560 aerr("missing name for func chunk?\n");
8562 add_func_chunk(fasm, words[0], asmln);
8564 else if (IS_START(p, "; sctend"))
8570 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8571 words[wordc][0] = 0;
8572 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8573 if (*p == 0 || *p == ';') {
8579 if (wordc == 2 && IS(words[1], "ends"))
8583 fseek(fasm, oldpos, SEEK_SET);
8587 int main(int argc, char *argv[])
8589 FILE *fout, *fasm, *frlist;
8590 struct parsed_data *pd = NULL;
8592 char **rlist = NULL;
8594 int rlist_alloc = 0;
8595 int func_chunks_used = 0;
8596 int func_chunks_sorted = 0;
8597 int func_chunk_i = -1;
8598 long func_chunk_ret = 0;
8599 int func_chunk_ret_ln = 0;
8600 int scanned_ahead = 0;
8602 char words[20][256];
8603 enum opr_lenmod lmod;
8604 char *sctproto = NULL;
8606 int pending_endp = 0;
8608 int skip_code_end = 0;
8609 int skip_warned = 0;
8622 for (arg = 1; arg < argc; arg++) {
8623 if (IS(argv[arg], "-v"))
8625 else if (IS(argv[arg], "-rf"))
8626 g_allow_regfunc = 1;
8627 else if (IS(argv[arg], "-uc"))
8628 g_allow_user_icall = 1;
8629 else if (IS(argv[arg], "-m"))
8631 else if (IS(argv[arg], "-hdr"))
8632 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8637 if (argc < arg + 3) {
8638 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8639 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8641 " -hdr - header generation mode\n"
8642 " -rf - allow unannotated indirect calls\n"
8643 " -uc - allow ind. calls/refs to __usercall\n"
8644 " -m - allow multiple .text sections\n"
8645 "[rlist] is a file with function names to skip,"
8653 asmfn = argv[arg++];
8654 fasm = fopen(asmfn, "r");
8655 my_assert_not(fasm, NULL);
8657 hdrfn = argv[arg++];
8658 g_fhdr = fopen(hdrfn, "r");
8659 my_assert_not(g_fhdr, NULL);
8662 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8663 my_assert_not(rlist, NULL);
8664 // needs special handling..
8665 rlist[rlist_len++] = "__alloca_probe";
8667 func_chunk_alloc = 32;
8668 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8669 my_assert_not(func_chunks, NULL);
8671 memset(words, 0, sizeof(words));
8673 for (; arg < argc; arg++) {
8676 frlist = fopen(argv[arg], "r");
8677 my_assert_not(frlist, NULL);
8679 while (my_fgets(line, sizeof(line), frlist)) {
8681 if (*p == 0 || *p == ';')
8684 if (IS_START(p, "#if 0")
8685 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
8689 else if (IS_START(p, "#endif"))
8696 p = next_word(words[0], sizeof(words[0]), p);
8697 if (words[0][0] == 0)
8700 if (rlist_len >= rlist_alloc) {
8701 rlist_alloc = rlist_alloc * 2 + 64;
8702 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
8703 my_assert_not(rlist, NULL);
8705 rlist[rlist_len++] = strdup(words[0]);
8713 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
8715 fout = fopen(argv[arg_out], "w");
8716 my_assert_not(fout, NULL);
8719 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
8720 my_assert_not(g_eqs, NULL);
8722 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
8723 g_label_refs[i].i = -1;
8724 g_label_refs[i].next = NULL;
8728 scan_variables(fasm, rlist, rlist_len);
8730 while (my_fgets(line, sizeof(line), fasm))
8739 // get rid of random tabs
8740 for (i = 0; line[i] != 0; i++)
8741 if (line[i] == '\t')
8746 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
8747 goto do_pending_endp; // eww..
8749 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
8751 static const char *attrs[] = {
8760 // parse IDA's attribute-list comment
8761 g_ida_func_attr = 0;
8764 for (; *p != 0; p = sskip(p)) {
8765 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8766 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8767 g_ida_func_attr |= 1 << i;
8768 p += strlen(attrs[i]);
8772 if (i == ARRAY_SIZE(attrs)) {
8773 anote("unparsed IDA attr: %s\n", p);
8776 if (IS(attrs[i], "fpd=")) {
8777 p = next_word(words[0], sizeof(words[0]), p);
8782 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
8784 static const char *attrs[] = {
8789 // parse manual attribute-list comment
8790 g_sct_func_attr = 0;
8793 for (; *p != 0; p = sskip(p)) {
8794 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8795 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8796 g_sct_func_attr |= 1 << i;
8797 p += strlen(attrs[i]);
8804 // clear_sf=start,len (in dwords)
8805 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
8806 &g_stack_clear_len, &j);
8808 // clear_regmask=<mask>
8809 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
8811 anote("unparsed attr value: %s\n", p);
8816 else if (i == ARRAY_SIZE(attrs)) {
8817 anote("unparsed sct attr: %s\n", p);
8822 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8825 next_word(words[0], sizeof(words[0]), p);
8826 if (words[0][0] == 0)
8827 aerr("missing name for func chunk?\n");
8829 if (!scanned_ahead) {
8830 add_func_chunk(fasm, words[0], asmln);
8831 func_chunks_sorted = 0;
8834 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
8836 if (func_chunk_i >= 0) {
8837 if (func_chunk_i < func_chunk_cnt
8838 && IS(func_chunks[func_chunk_i].name, g_func))
8840 // move on to next chunk
8841 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8843 aerr("seek failed for '%s' chunk #%d\n",
8844 g_func, func_chunk_i);
8845 asmln = func_chunks[func_chunk_i].asmln;
8849 if (func_chunk_ret == 0)
8850 aerr("no return from chunk?\n");
8851 fseek(fasm, func_chunk_ret, SEEK_SET);
8852 asmln = func_chunk_ret_ln;
8858 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
8859 func_chunks_used = 1;
8861 if (IS_START(g_func, "sub_")) {
8862 unsigned long addr = strtoul(p, NULL, 16);
8863 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
8864 if (addr > f_addr && !scanned_ahead) {
8865 //anote("scan_ahead caused by '%s', addr %lx\n",
8867 scan_ahead_for_chunks(fasm);
8869 func_chunks_sorted = 0;
8877 for (i = wordc; i < ARRAY_SIZE(words); i++)
8879 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8880 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8881 if (*p == 0 || *p == ';') {
8886 if (*p != 0 && *p != ';')
8887 aerr("too many words\n");
8889 if (skip_code_end) {
8894 // allow asm patches in comments
8896 if (IS_START(p, "; sctpatch:")) {
8898 if (*p == 0 || *p == ';')
8900 goto parse_words; // lame
8902 if (IS_START(p, "; sctproto:")) {
8903 sctproto = strdup(p + 11);
8905 else if (IS_START(p, "; sctend")) {
8910 else if (IS_START(p, "; sctskip_start")) {
8911 if (in_func && !g_skip_func) {
8913 ops[pi].op = OPP_ABORT;
8914 ops[pi].asmln = asmln;
8920 else if (IS_START(p, "; sctskip_end")) {
8928 awarn("wordc == 0?\n");
8932 // don't care about this:
8933 if (words[0][0] == '.'
8934 || IS(words[0], "include")
8935 || IS(words[0], "assume") || IS(words[1], "segment")
8936 || IS(words[0], "align"))
8942 // do delayed endp processing to collect switch jumptables
8944 if (in_func && !g_skip_func && !end && wordc >= 2
8945 && ((words[0][0] == 'd' && words[0][2] == 0)
8946 || (words[1][0] == 'd' && words[1][2] == 0)))
8949 if (words[1][0] == 'd' && words[1][2] == 0) {
8951 if (g_func_pd_cnt >= pd_alloc) {
8952 pd_alloc = pd_alloc * 2 + 16;
8953 g_func_pd = realloc(g_func_pd,
8954 sizeof(g_func_pd[0]) * pd_alloc);
8955 my_assert_not(g_func_pd, NULL);
8957 pd = &g_func_pd[g_func_pd_cnt];
8959 memset(pd, 0, sizeof(*pd));
8960 strcpy(pd->label, words[0]);
8961 pd->type = OPT_CONST;
8962 pd->lmod = lmod_from_directive(words[1]);
8968 anote("skipping alignment byte?\n");
8971 lmod = lmod_from_directive(words[0]);
8972 if (lmod != pd->lmod)
8973 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
8976 if (pd->count_alloc < pd->count + wordc) {
8977 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
8978 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
8979 my_assert_not(pd->d, NULL);
8981 for (; i < wordc; i++) {
8982 if (IS(words[i], "offset")) {
8983 pd->type = OPT_OFFSET;
8986 p = strchr(words[i], ',');
8989 if (pd->type == OPT_OFFSET)
8990 pd->d[pd->count].u.label = strdup(words[i]);
8992 pd->d[pd->count].u.val = parse_number(words[i]);
8993 pd->d[pd->count].bt_i = -1;
8999 if (in_func && !g_skip_func) {
9001 gen_hdr(g_func, pi);
9003 gen_func(fout, g_fhdr, g_func, pi);
9008 g_ida_func_attr = 0;
9009 g_sct_func_attr = 0;
9010 g_stack_clear_start = 0;
9011 g_stack_clear_len = 0;
9016 func_chunks_used = 0;
9019 memset(&ops, 0, pi * sizeof(ops[0]));
9024 for (i = 0; i < g_func_pd_cnt; i++) {
9026 if (pd->type == OPT_OFFSET) {
9027 for (j = 0; j < pd->count; j++)
9028 free(pd->d[j].u.label);
9043 if (IS(words[1], "proc")) {
9045 aerr("proc '%s' while in_func '%s'?\n",
9048 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9050 strcpy(g_func, words[0]);
9051 set_label(0, words[0]);
9056 if (IS(words[1], "endp"))
9059 aerr("endp '%s' while not in_func?\n", words[0]);
9060 if (!IS(g_func, words[0]))
9061 aerr("endp '%s' while in_func '%s'?\n",
9064 aerr("endp '%s' while skipping code\n", words[0]);
9066 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9067 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
9073 if (!g_skip_func && func_chunks_used) {
9074 // start processing chunks
9075 struct chunk_item *ci, key = { g_func, 0 };
9077 func_chunk_ret = ftell(fasm);
9078 func_chunk_ret_ln = asmln;
9079 if (!func_chunks_sorted) {
9080 qsort(func_chunks, func_chunk_cnt,
9081 sizeof(func_chunks[0]), cmp_chunks);
9082 func_chunks_sorted = 1;
9084 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9085 sizeof(func_chunks[0]), cmp_chunks);
9087 aerr("'%s' needs chunks, but none found\n", g_func);
9088 func_chunk_i = ci - func_chunks;
9089 for (; func_chunk_i > 0; func_chunk_i--)
9090 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9093 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9095 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9096 asmln = func_chunks[func_chunk_i].asmln;
9104 if (wordc == 2 && IS(words[1], "ends")) {
9108 goto do_pending_endp;
9112 // scan for next text segment
9113 while (my_fgets(line, sizeof(line), fasm)) {
9116 if (*p == 0 || *p == ';')
9119 if (strstr(p, "segment para public 'CODE' use32"))
9126 p = strchr(words[0], ':');
9128 set_label(pi, words[0]);
9132 if (!in_func || g_skip_func || skip_code) {
9133 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9135 anote("skipping from '%s'\n", g_labels[pi]);
9139 g_labels[pi] = NULL;
9143 if (wordc > 1 && IS(words[1], "="))
9146 aerr("unhandled equ, wc=%d\n", wordc);
9147 if (g_eqcnt >= eq_alloc) {
9149 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9150 my_assert_not(g_eqs, NULL);
9153 len = strlen(words[0]);
9154 if (len > sizeof(g_eqs[0].name) - 1)
9155 aerr("equ name too long: %d\n", len);
9156 strcpy(g_eqs[g_eqcnt].name, words[0]);
9158 if (!IS(words[3], "ptr"))
9159 aerr("unhandled equ\n");
9160 if (IS(words[2], "dword"))
9161 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9162 else if (IS(words[2], "word"))
9163 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9164 else if (IS(words[2], "byte"))
9165 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9166 else if (IS(words[2], "qword"))
9167 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9169 aerr("bad lmod: '%s'\n", words[2]);
9171 g_eqs[g_eqcnt].offset = parse_number(words[4]);
9176 if (pi >= ARRAY_SIZE(ops))
9177 aerr("too many ops\n");
9179 parse_op(&ops[pi], words, wordc);
9181 ops[pi].datap = sctproto;
9196 // vim:ts=2:shiftwidth=2:expandtab