5 * This work is licensed under the terms of 3-clause BSD license.
6 * See COPYING file in the top-level directory.
8 * recognized asm hint comments:
9 * sctattr - function attributes (see code)
10 * sctend - force end of function/chunk
11 * sctpatch: <p> - replace current asm line with <p>
12 * sctproto: <p> - prototype of ref'd function or struct
13 * sctref - variable is referenced, make global
14 * sctskip_start - start of skipped code chunk (inclusive)
15 * sctskip_end - end of skipped code chunk (inclusive)
24 #include "my_assert.h"
28 #include "protoparse.h"
30 static const char *asmfn;
34 #define anote(fmt, ...) \
35 printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
36 #define awarn(fmt, ...) \
37 printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
38 #define aerr(fmt, ...) do { \
39 printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
44 #include "masm_tools.h"
47 OPF_RMD = (1 << 0), /* removed from code generation */
48 OPF_DATA = (1 << 1), /* data processing - writes to dst opr */
49 OPF_FLAGS = (1 << 2), /* sets flags */
50 OPF_JMP = (1 << 3), /* branch, call */
51 OPF_CJMP = (1 << 4), /* cond. branch (cc or jecxz/loop) */
52 OPF_CC = (1 << 5), /* uses flags */
53 OPF_TAIL = (1 << 6), /* ret or tail call */
54 OPF_RSAVE = (1 << 7), /* push/pop is local reg save/load */
55 OPF_REP = (1 << 8), /* prefixed by rep */
56 OPF_REPZ = (1 << 9), /* rep is repe/repz */
57 OPF_REPNZ = (1 << 10), /* rep is repne/repnz */
58 OPF_FARG = (1 << 11), /* push collected as func arg */
59 OPF_FARGNR = (1 << 12), /* push collected as func arg (no reuse) */
60 OPF_EBP_S = (1 << 13), /* ebp used as scratch here, not BP */
61 OPF_DF = (1 << 14), /* DF flag set */
62 OPF_ATAIL = (1 << 15), /* tail call with reused arg frame */
63 OPF_32BIT = (1 << 16), /* 32bit division */
64 OPF_LOCK = (1 << 17), /* op has lock prefix */
65 OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
66 OPF_DONE = (1 << 19), /* already fully handled by analysis */
67 OPF_PPUSH = (1 << 20), /* part of complex push-pop graph */
68 OPF_NOREGS = (1 << 21), /* don't track regs of this op */
69 OPF_FPUSH = (1 << 22), /* pushes x87 stack */
70 OPF_FPOP = (1 << 23), /* pops x87 stack */
71 OPF_FSHIFT = (1 << 24), /* x87 stack shift is actually needed */
72 OPF_FINT = (1 << 25), /* integer float op arg */
163 // pseudo-ops for lib calls
182 // must be sorted (larger len must be further in enum)
191 #define MAX_EXITS 128
193 #define MAX_OPERANDS 3
196 #define OPR_INIT(type_, lmod_, reg_) \
197 { type_, lmod_, reg_, }
201 enum opr_lenmod lmod;
203 unsigned int is_ptr:1; // pointer in C
204 unsigned int is_array:1; // array in C
205 unsigned int type_from_var:1; // .. in header, sometimes wrong
206 unsigned int size_mismatch:1; // type override differs from C
207 unsigned int size_lt:1; // type override is larger than C
208 unsigned int had_ds:1; // had ds: prefix
209 const struct parsed_proto *pp; // for OPT_LABEL
216 struct parsed_opr operand[MAX_OPERANDS];
219 unsigned char pfo_inv;
220 unsigned char operand_cnt;
221 unsigned char p_argnum; // arg push: altered before call arg #
222 unsigned char p_arggrp; // arg push: arg group # for above
223 unsigned char p_argpass;// arg push: arg of host func
224 short p_argnext;// arg push: same arg pushed elsewhere or -1
225 int regmask_src; // all referensed regs
227 int pfomask; // flagop: parsed_flag_op that can't be delayed
228 int cc_scratch; // scratch storage during analysis
229 int bt_i; // branch target for branches
230 struct parsed_data *btj;// branch targets for jumptables
231 struct parsed_proto *pp;// parsed_proto for OP_CALL
237 // on start: function/data type hint (sctproto)
239 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
240 // OP_PUSH - points to OP_POP in complex push/pop graph
241 // OP_POP - points to OP_PUSH in simple push/pop pair
242 // OP_FCOM - needed_status_word_bits | (is_z_check << 16)
246 enum opr_lenmod lmod;
253 enum opr_lenmod lmod;
267 struct label_ref *next;
271 IDAFA_BP_FRAME = (1 << 0),
272 IDAFA_LIB_FUNC = (1 << 1),
273 IDAFA_STATIC = (1 << 2),
274 IDAFA_NORETURN = (1 << 3),
275 IDAFA_THUNK = (1 << 4),
276 IDAFA_FPD = (1 << 5),
280 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
281 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
294 // note: limited to 32k due to p_argnext
296 #define MAX_ARG_GRP 2
298 static struct parsed_op ops[MAX_OPS];
299 static struct parsed_equ *g_eqs;
301 static char *g_labels[MAX_OPS];
302 static struct label_ref g_label_refs[MAX_OPS];
303 static const struct parsed_proto *g_func_pp;
304 static struct parsed_data *g_func_pd;
305 static int g_func_pd_cnt;
306 static int g_func_lmods;
307 static char g_func[256];
308 static char g_comment[256];
309 static int g_bp_frame;
310 static int g_sp_frame;
311 static int g_stack_frame_used;
312 static int g_stack_fsz;
313 static int g_ida_func_attr;
314 static int g_sct_func_attr;
315 static int g_stack_clear_start; // in dwords
316 static int g_stack_clear_len;
317 static int g_regmask_init;
318 static int g_skip_func;
319 static int g_allow_regfunc;
320 static int g_allow_user_icall;
321 static int g_quiet_pp;
322 static int g_header_mode;
324 #define ferr(op_, fmt, ...) do { \
325 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
326 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
330 #define fnote(op_, fmt, ...) \
331 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
332 dump_op(op_), ##__VA_ARGS__)
334 #define ferr_assert(op_, cond) do { \
335 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
338 const char *regs_r32[] = {
339 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
340 // not r32, but list here for easy parsing and printing
341 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
342 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
344 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
345 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
346 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
352 xMM0, xMM1, xMM2, xMM3, // mmx
353 xMM4, xMM5, xMM6, xMM7,
354 xST0, xST1, xST2, xST3, // x87
355 xST4, xST5, xST6, xST7,
358 #define mxAX (1 << xAX)
359 #define mxCX (1 << xCX)
360 #define mxDX (1 << xDX)
361 #define mxSP (1 << xSP)
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, 0);
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);
591 val = strtol(buf, &endp, 16);
592 if (val == 0 || *endp != 0 || errno != 0) {
593 aerr("%s num parse fail for '%s'\n", __func__, buf);
602 if ('0' <= *p && *p <= '9')
605 if (base_val != NULL)
610 static int guess_lmod_from_name(struct parsed_opr *opr)
612 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
613 opr->lmod = OPLM_DWORD;
616 if (IS_START(opr->name, "word_")) {
617 opr->lmod = OPLM_WORD;
620 if (IS_START(opr->name, "byte_")) {
621 opr->lmod = OPLM_BYTE;
624 if (IS_START(opr->name, "qword_")) {
625 opr->lmod = OPLM_QWORD;
631 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
632 const struct parsed_type *c_type)
634 static const char *qword_types[] = {
635 "uint64_t", "int64_t", "__int64",
637 static const char *dword_types[] = {
638 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
639 "WPARAM", "LPARAM", "UINT", "__int32",
640 "LONG", "HIMC", "BOOL", "size_t",
643 static const char *word_types[] = {
644 "uint16_t", "int16_t", "_WORD", "WORD",
645 "unsigned __int16", "__int16",
647 static const char *byte_types[] = {
648 "uint8_t", "int8_t", "char",
649 "unsigned __int8", "__int8", "BYTE", "_BYTE",
651 // structures.. deal the same as with _UNKNOWN for now
657 if (c_type->is_ptr) {
662 n = skip_type_mod(c_type->name);
664 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
665 if (IS(n, dword_types[i])) {
671 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
672 if (IS(n, word_types[i])) {
678 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
679 if (IS(n, byte_types[i])) {
685 for (i = 0; i < ARRAY_SIZE(qword_types); i++) {
686 if (IS(n, qword_types[i])) {
695 static char *default_cast_to(char *buf, size_t buf_size,
696 struct parsed_opr *opr)
700 if (!opr->is_ptr || strchr(opr->name, '['))
702 if (opr->pp == NULL || opr->pp->type.name == NULL
705 snprintf(buf, buf_size, "%s", "(void *)");
709 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
713 static enum opr_type lmod_from_directive(const char *d)
717 else if (IS(d, "dw"))
719 else if (IS(d, "db"))
722 aerr("unhandled directive: '%s'\n", d);
726 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
732 *regmask |= 1 << reg;
735 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
738 static int parse_operand(struct parsed_opr *opr,
739 int *regmask, int *regmask_indirect,
740 char words[16][256], int wordc, int w, unsigned int op_flags)
742 const struct parsed_proto *pp = NULL;
743 enum opr_lenmod tmplmod;
744 unsigned long number;
752 aerr("parse_operand w %d, wordc %d\n", w, wordc);
756 for (i = w; i < wordc; i++) {
757 len = strlen(words[i]);
758 if (words[i][len - 1] == ',') {
759 words[i][len - 1] = 0;
765 wordc_in = wordc - w;
767 if ((op_flags & OPF_JMP) && wordc_in > 0
768 && !('0' <= words[w][0] && words[w][0] <= '9'))
770 const char *label = NULL;
772 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
773 && IS(words[w + 1], "ptr"))
774 label = words[w + 2];
775 else if (wordc_in == 2 && IS(words[w], "short"))
776 label = words[w + 1];
777 else if (wordc_in == 1
778 && strchr(words[w], '[') == NULL
779 && parse_reg(&tmplmod, words[w]) < 0)
783 opr->type = OPT_LABEL;
784 ret = check_segment_prefix(label);
787 aerr("fs/gs used\n");
791 strcpy(opr->name, label);
797 if (IS(words[w + 1], "ptr")) {
798 if (IS(words[w], "dword"))
799 opr->lmod = OPLM_DWORD;
800 else if (IS(words[w], "word"))
801 opr->lmod = OPLM_WORD;
802 else if (IS(words[w], "byte"))
803 opr->lmod = OPLM_BYTE;
804 else if (IS(words[w], "qword"))
805 opr->lmod = OPLM_QWORD;
807 aerr("type parsing failed\n");
809 wordc_in = wordc - w;
814 if (IS(words[w], "offset")) {
815 opr->type = OPT_OFFSET;
816 opr->lmod = OPLM_DWORD;
817 strcpy(opr->name, words[w + 1]);
818 pp = proto_parse(g_fhdr, opr->name, 1);
821 if (IS(words[w], "(offset")) {
822 p = strchr(words[w + 1], ')');
824 aerr("parse of bracketed offset failed\n");
826 opr->type = OPT_OFFSET;
827 strcpy(opr->name, words[w + 1]);
833 aerr("parse_operand 1 word expected\n");
835 ret = check_segment_prefix(words[w]);
838 aerr("fs/gs used\n");
840 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
842 strcpy(opr->name, words[w]);
844 if (words[w][0] == '[') {
845 opr->type = OPT_REGMEM;
846 ret = sscanf(words[w], "[%[^]]]", opr->name);
848 aerr("[] parse failure\n");
850 parse_indmode(opr->name, regmask_indirect, 1);
851 if (opr->lmod == OPLM_UNSPEC
852 && parse_stack_el(opr->name, NULL, NULL, 1))
855 struct parsed_equ *eq =
856 equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
858 opr->lmod = eq->lmod;
860 // might be unaligned access
861 g_func_lmods |= 1 << OPLM_BYTE;
865 else if (strchr(words[w], '[')) {
867 p = strchr(words[w], '[');
868 opr->type = OPT_REGMEM;
869 parse_indmode(p, regmask_indirect, 0);
870 strncpy(buf, words[w], p - words[w]);
871 buf[p - words[w]] = 0;
872 pp = proto_parse(g_fhdr, buf, 1);
875 else if (('0' <= words[w][0] && words[w][0] <= '9')
876 || words[w][0] == '-')
878 number = parse_number(words[w], 0);
879 opr->type = OPT_CONST;
881 printf_number(opr->name, sizeof(opr->name), number);
885 ret = parse_reg(&tmplmod, opr->name);
887 setup_reg_opr(opr, ret, tmplmod, regmask);
891 // most likely var in data segment
892 opr->type = OPT_LABEL;
893 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
897 if (pp->is_fptr || pp->is_func) {
898 opr->lmod = OPLM_DWORD;
902 tmplmod = OPLM_UNSPEC;
903 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
904 anote("unhandled C type '%s' for '%s'\n",
905 pp->type.name, opr->name);
907 if (opr->lmod == OPLM_UNSPEC) {
909 opr->type_from_var = 1;
911 else if (opr->lmod != tmplmod) {
912 opr->size_mismatch = 1;
913 if (tmplmod < opr->lmod)
916 opr->is_ptr = pp->type.is_ptr;
918 opr->is_array = pp->type.is_array;
922 if (opr->lmod == OPLM_UNSPEC)
923 guess_lmod_from_name(opr);
927 static const struct {
932 { "repe", OPF_REP|OPF_REPZ },
933 { "repz", OPF_REP|OPF_REPZ },
934 { "repne", OPF_REP|OPF_REPNZ },
935 { "repnz", OPF_REP|OPF_REPNZ },
936 { "lock", OPF_LOCK }, // ignored for now..
939 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
941 static const struct {
944 unsigned short minopr;
945 unsigned short maxopr;
948 unsigned char pfo_inv;
950 { "nop", OP_NOP, 0, 0, 0 },
951 { "push", OP_PUSH, 1, 1, 0 },
952 { "pop", OP_POP, 1, 1, OPF_DATA },
953 { "pusha",OP_PUSHA, 0, 0, 0 },
954 { "popa", OP_POPA, 0, 0, OPF_DATA },
955 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
956 { "mov" , OP_MOV, 2, 2, OPF_DATA },
957 { "lea", OP_LEA, 2, 2, OPF_DATA },
958 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
959 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
960 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
961 { "not", OP_NOT, 1, 1, OPF_DATA },
962 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
963 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
964 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
965 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
966 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
967 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
968 { "stosb",OP_STOS, 0, 0, OPF_DATA },
969 { "stosw",OP_STOS, 0, 0, OPF_DATA },
970 { "stosd",OP_STOS, 0, 0, OPF_DATA },
971 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
972 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
973 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
974 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
975 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
976 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
977 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
978 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
979 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
980 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
981 { "cld", OP_CLD, 0, 0, OPF_DATA },
982 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
983 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
984 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
985 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
986 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
987 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
988 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
989 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
990 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
991 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
992 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
993 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
994 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
995 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
996 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
997 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
998 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
999 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
1000 { "bsr", OP_BSR, 2, 2, OPF_DATA|OPF_FLAGS },
1001 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
1002 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
1003 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
1004 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
1005 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
1006 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
1007 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
1008 { "test", OP_TEST, 2, 2, OPF_FLAGS },
1009 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
1010 { "retn", OP_RET, 0, 1, OPF_TAIL },
1011 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
1012 { "jmp", OP_JMP, 1, 1, OPF_JMP },
1013 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
1014 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
1015 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
1016 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
1017 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
1018 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
1019 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
1020 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1021 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1022 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
1023 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
1024 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
1025 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
1026 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1027 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1028 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1029 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1030 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1031 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1032 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1033 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1034 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1035 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1036 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1037 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1038 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1039 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1040 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1041 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1042 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1043 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1044 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1045 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1046 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1047 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1048 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1049 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1050 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1051 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1052 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1053 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1054 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1055 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1056 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1057 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1058 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1059 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1060 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1061 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1062 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1063 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1064 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1065 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1066 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1067 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1068 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1069 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1070 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1071 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1072 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1074 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1075 { "fild", OP_FILD, 1, 1, OPF_FPUSH|OPF_FINT },
1076 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1077 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1078 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1079 { "fst", OP_FST, 1, 1, 0 },
1080 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1081 { "fist", OP_FIST, 1, 1, OPF_FINT },
1082 { "fistp", OP_FIST, 1, 1, OPF_FPOP|OPF_FINT },
1083 { "fadd", OP_FADD, 0, 2, 0 },
1084 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1085 { "fdiv", OP_FDIV, 0, 2, 0 },
1086 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1087 { "fmul", OP_FMUL, 0, 2, 0 },
1088 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1089 { "fsub", OP_FSUB, 0, 2, 0 },
1090 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1091 { "fdivr", OP_FDIVR, 0, 2, 0 },
1092 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1093 { "fsubr", OP_FSUBR, 0, 2, 0 },
1094 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1095 { "fiadd", OP_FIADD, 1, 1, OPF_FINT },
1096 { "fidiv", OP_FIDIV, 1, 1, OPF_FINT },
1097 { "fimul", OP_FIMUL, 1, 1, OPF_FINT },
1098 { "fisub", OP_FISUB, 1, 1, OPF_FINT },
1099 { "fidivr", OP_FIDIVR, 1, 1, OPF_FINT },
1100 { "fisubr", OP_FISUBR, 1, 1, OPF_FINT },
1101 { "fcom", OP_FCOM, 0, 1, 0 },
1102 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1103 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1104 { "fchs", OP_FCHS, 0, 0, 0 },
1105 { "fcos", OP_FCOS, 0, 0, 0 },
1106 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1107 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1108 { "fsin", OP_FSIN, 0, 0, 0 },
1109 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1110 { "fxch", OP_FXCH, 1, 1, 0 },
1111 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1113 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1114 { "movq", OP_MOV, 2, 2, OPF_DATA },
1115 // pseudo-ops for lib calls
1116 { "_allshl",OPP_ALLSHL },
1117 { "_allshr",OPP_ALLSHR },
1118 { "_ftol", OPP_FTOL },
1119 { "_CIpow", OPP_CIPOW },
1120 { "abort", OPP_ABORT },
1125 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1127 enum opr_lenmod lmod = OPLM_UNSPEC;
1128 int prefix_flags = 0;
1136 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1137 if (IS(words[w], pref_table[i].name)) {
1138 prefix_flags = pref_table[i].flags;
1145 aerr("lone prefix: '%s'\n", words[0]);
1150 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1151 if (IS(words[w], op_table[i].name))
1155 if (i == ARRAY_SIZE(op_table)) {
1157 aerr("unhandled op: '%s'\n", words[0]);
1162 op->op = op_table[i].op;
1163 op->flags = op_table[i].flags | prefix_flags;
1164 op->pfo = op_table[i].pfo;
1165 op->pfo_inv = op_table[i].pfo_inv;
1166 op->regmask_src = op->regmask_dst = 0;
1169 if (op->op == OP_UD2)
1172 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1173 if (opr >= op_table[i].minopr && w >= wordc)
1176 regmask = regmask_ind = 0;
1177 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1178 words, wordc, w, op->flags);
1180 if (opr == 0 && (op->flags & OPF_DATA))
1181 op->regmask_dst = regmask;
1183 op->regmask_src |= regmask;
1184 op->regmask_src |= regmask_ind;
1186 if (op->operand[opr].lmod != OPLM_UNSPEC)
1187 g_func_lmods |= 1 << op->operand[opr].lmod;
1191 aerr("parse_op %s incomplete: %d/%d\n",
1192 words[0], w, wordc);
1195 op->operand_cnt = opr;
1196 if (!strncmp(op_table[i].name, "set", 3))
1197 op->operand[0].lmod = OPLM_BYTE;
1200 // first operand is not dst
1203 op->regmask_src |= op->regmask_dst;
1204 op->regmask_dst = 0;
1207 // first operand is src too
1220 op->regmask_src |= op->regmask_dst;
1225 op->regmask_src |= op->regmask_dst;
1226 op->regmask_dst |= op->regmask_src;
1232 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1233 && op->operand[0].lmod == op->operand[1].lmod
1234 && op->operand[0].reg == op->operand[1].reg
1235 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1237 op->regmask_src = 0;
1240 op->regmask_src |= op->regmask_dst;
1243 // ops with implicit argumets
1245 op->operand_cnt = 2;
1246 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1247 op->regmask_dst = op->regmask_src;
1248 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1252 op->operand_cnt = 2;
1253 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1254 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1260 if (words[op_w][4] == 'b')
1262 else if (words[op_w][4] == 'w')
1264 else if (words[op_w][4] == 'd')
1267 op->regmask_src = 0;
1268 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1269 OPLM_DWORD, &op->regmask_src);
1270 op->regmask_dst = op->regmask_src;
1271 setup_reg_opr(&op->operand[j++], xAX, lmod,
1272 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1273 if (op->flags & OPF_REP) {
1274 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1275 op->regmask_dst |= 1 << xCX;
1277 op->operand_cnt = j;
1282 if (words[op_w][4] == 'b')
1284 else if (words[op_w][4] == 'w')
1286 else if (words[op_w][4] == 'd')
1289 op->regmask_src = 0;
1290 // note: lmod is not correct, don't have where to place it
1291 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1292 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1293 if (op->flags & OPF_REP)
1294 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1295 op->operand_cnt = j;
1296 op->regmask_dst = op->regmask_src;
1300 op->regmask_dst = 1 << xCX;
1303 op->operand_cnt = 2;
1304 op->regmask_src = 1 << xCX;
1305 op->operand[1].type = OPT_REG;
1306 op->operand[1].reg = xCX;
1307 op->operand[1].lmod = OPLM_DWORD;
1311 if (op->operand_cnt == 2) {
1312 if (op->operand[0].type != OPT_REG)
1313 aerr("reg expected\n");
1314 op->regmask_src |= 1 << op->operand[0].reg;
1316 if (op->operand_cnt != 1)
1321 op->regmask_src |= op->regmask_dst;
1322 op->regmask_dst = (1 << xDX) | (1 << xAX);
1323 if (op->operand[0].lmod == OPLM_UNSPEC)
1324 op->operand[0].lmod = OPLM_DWORD;
1329 // we could set up operands for edx:eax, but there is no real need to
1330 // (see is_opr_modified())
1331 op->regmask_src |= op->regmask_dst;
1332 op->regmask_dst = (1 << xDX) | (1 << xAX);
1333 if (op->operand[0].lmod == OPLM_UNSPEC)
1334 op->operand[0].lmod = OPLM_DWORD;
1342 op->regmask_src |= op->regmask_dst;
1343 if (op->operand[1].lmod == OPLM_UNSPEC)
1344 op->operand[1].lmod = OPLM_BYTE;
1349 op->regmask_src |= op->regmask_dst;
1350 if (op->operand[2].lmod == OPLM_UNSPEC)
1351 op->operand[2].lmod = OPLM_BYTE;
1355 op->regmask_src |= op->regmask_dst;
1356 op->regmask_dst = 0;
1357 if (op->operand[0].lmod == OPLM_UNSPEC
1358 && (op->operand[0].type == OPT_CONST
1359 || op->operand[0].type == OPT_OFFSET
1360 || op->operand[0].type == OPT_LABEL))
1361 op->operand[0].lmod = OPLM_DWORD;
1367 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1368 && op->operand[0].lmod == op->operand[1].lmod
1369 && op->operand[0].reg == op->operand[1].reg
1370 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1372 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1373 op->regmask_src = op->regmask_dst = 0;
1378 if (op->operand[0].type == OPT_REG
1379 && op->operand[1].type == OPT_REGMEM)
1382 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1383 if (IS(buf, op->operand[1].name))
1384 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1389 // trashed regs must be explicitly detected later
1390 op->regmask_dst = 0;
1394 op->regmask_dst = (1 << xBP) | (1 << xSP);
1395 op->regmask_src = 1 << xBP;
1400 op->regmask_dst |= mxST0;
1404 op->regmask_dst |= mxST0;
1405 if (IS(words[op_w] + 3, "1"))
1406 op->operand[0].val = X87_CONST_1;
1407 else if (IS(words[op_w] + 3, "ln2"))
1408 op->operand[0].val = X87_CONST_LN2;
1409 else if (IS(words[op_w] + 3, "z"))
1410 op->operand[0].val = X87_CONST_Z;
1417 op->regmask_src |= mxST0;
1426 op->regmask_src |= mxST0;
1427 if (op->operand_cnt == 2)
1428 op->regmask_src |= op->regmask_dst;
1429 else if (op->operand_cnt == 1) {
1430 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1431 op->operand[0].type = OPT_REG;
1432 op->operand[0].lmod = OPLM_QWORD;
1433 op->operand[0].reg = xST0;
1434 op->regmask_dst |= mxST0;
1437 // IDA doesn't use this
1438 aerr("no operands?\n");
1452 op->regmask_src |= mxST0;
1453 op->regmask_dst |= mxST0;
1458 op->regmask_src |= mxST0 | mxST1;
1459 op->regmask_dst |= mxST0;
1467 op->regmask_src |= mxST0;
1474 if (op->operand[0].type == OPT_REG
1475 && op->operand[1].type == OPT_CONST)
1477 struct parsed_opr *op1 = &op->operand[1];
1478 if ((op->op == OP_AND && op1->val == 0)
1481 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1482 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1484 op->regmask_src = 0;
1489 static const char *op_name(struct parsed_op *po)
1491 static char buf[16];
1495 if (po->op == OP_JCC || po->op == OP_SCC) {
1497 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1500 strcpy(p, parsed_flag_op_names[po->pfo]);
1504 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1505 if (op_table[i].op == po->op)
1506 return op_table[i].name;
1512 static const char *dump_op(struct parsed_op *po)
1514 static char out[128];
1521 snprintf(out, sizeof(out), "%s", op_name(po));
1522 for (i = 0; i < po->operand_cnt; i++) {
1526 snprintf(p, sizeof(out) - (p - out),
1527 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1528 po->operand[i].name);
1534 static const char *lmod_type_u(struct parsed_op *po,
1535 enum opr_lenmod lmod)
1547 ferr(po, "invalid lmod: %d\n", lmod);
1548 return "(_invalid_)";
1552 static const char *lmod_cast_u(struct parsed_op *po,
1553 enum opr_lenmod lmod)
1565 ferr(po, "invalid lmod: %d\n", lmod);
1566 return "(_invalid_)";
1570 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1571 enum opr_lenmod lmod)
1583 ferr(po, "invalid lmod: %d\n", lmod);
1584 return "(_invalid_)";
1588 static const char *lmod_cast_s(struct parsed_op *po,
1589 enum opr_lenmod lmod)
1601 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1602 return "(_invalid_)";
1606 static const char *lmod_cast(struct parsed_op *po,
1607 enum opr_lenmod lmod, int is_signed)
1610 lmod_cast_s(po, lmod) :
1611 lmod_cast_u(po, lmod);
1614 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1626 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1631 static const char *opr_name(struct parsed_op *po, int opr_num)
1633 if (opr_num >= po->operand_cnt)
1634 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1635 return po->operand[opr_num].name;
1638 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1640 if (opr_num >= po->operand_cnt)
1641 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1642 if (po->operand[opr_num].type != OPT_CONST)
1643 ferr(po, "opr %d: const expected\n", opr_num);
1644 return po->operand[opr_num].val;
1647 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1649 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1650 ferr(po, "invalid reg: %d\n", popr->reg);
1651 return regs_r32[popr->reg];
1654 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1656 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1658 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1660 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1662 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1667 *is_signed = cast[1] == 's' ? 1 : 0;
1671 static int check_deref_cast(const char *cast, int *bits)
1673 if (IS_START(cast, "*(u8 *)"))
1675 else if (IS_START(cast, "*(u16 *)"))
1677 else if (IS_START(cast, "*(u32 *)"))
1679 else if (IS_START(cast, "*(u64 *)"))
1687 // cast1 is the "final" cast
1688 static const char *simplify_cast(const char *cast1, const char *cast2)
1690 static char buf[256];
1698 if (IS(cast1, cast2))
1701 if (check_simple_cast(cast1, &bits1, &s1) == 0
1702 && check_simple_cast(cast2, &bits2, &s2) == 0)
1707 if (check_simple_cast(cast1, &bits1, &s1) == 0
1708 && check_deref_cast(cast2, &bits2) == 0)
1710 if (bits1 == bits2) {
1711 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1716 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1719 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1723 static const char *simplify_cast_num(const char *cast, unsigned int val)
1725 if (IS(cast, "(u8)") && val < 0x100)
1727 if (IS(cast, "(s8)") && val < 0x80)
1729 if (IS(cast, "(u16)") && val < 0x10000)
1731 if (IS(cast, "(s16)") && val < 0x8000)
1733 if (IS(cast, "(s32)") && val < 0x80000000)
1739 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1748 namelen = strlen(name);
1750 p = strpbrk(name, "+-");
1754 ferr(po, "equ parse failed for '%s'\n", name);
1757 *extra_offs = strtol(p, &endp, 16);
1758 if (*endp != 0 || errno != 0)
1759 ferr(po, "equ parse failed for '%s'\n", name);
1762 for (i = 0; i < g_eqcnt; i++)
1763 if (strncmp(g_eqs[i].name, name, namelen) == 0
1764 && g_eqs[i].name[namelen] == 0)
1768 ferr(po, "unresolved equ name: '%s'\n", name);
1775 static int is_stack_access(struct parsed_op *po,
1776 const struct parsed_opr *popr)
1778 return (parse_stack_el(popr->name, NULL, NULL, 0)
1779 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1780 && IS_START(popr->name, "ebp")));
1783 static void parse_stack_access(struct parsed_op *po,
1784 const char *name, char *ofs_reg, int *offset_out,
1785 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1787 const char *bp_arg = "";
1788 const char *p = NULL;
1789 struct parsed_equ *eq;
1796 if (IS_START(name, "ebp-")
1797 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1800 if (IS_START(p, "0x"))
1803 offset = strtoul(p, &endp, 16);
1806 if (*endp != 0 || errno != 0)
1807 ferr(po, "ebp- parse of '%s' failed\n", name);
1810 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1811 eq = equ_find(po, bp_arg, &offset);
1813 ferr(po, "detected but missing eq\n");
1814 offset += eq->offset;
1817 if (!strncmp(name, "ebp", 3))
1820 // yes it sometimes LEAs ra for compares..
1821 if (!is_lea && ofs_reg[0] == 0
1822 && stack_ra <= offset && offset < stack_ra + 4)
1824 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1827 *offset_out = offset;
1829 *stack_ra_out = stack_ra;
1831 *bp_arg_out = bp_arg;
1834 static int parse_stack_esp_offset(struct parsed_op *po,
1835 const char *name, int *offset_out)
1837 char ofs_reg[16] = { 0, };
1838 struct parsed_equ *eq;
1844 if (strstr(name, "esp") == NULL)
1846 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1847 if (bp_arg == NULL) {
1848 // just plain offset?
1849 if (!IS_START(name, "esp+"))
1852 offset = strtol(name + 4, &endp, 0);
1853 if (endp == NULL || *endp != 0 || errno != 0)
1855 *offset_out = offset;
1859 if (ofs_reg[0] != 0)
1861 eq = equ_find(po, bp_arg, &offset);
1863 ferr(po, "detected but missing eq\n");
1864 offset += eq->offset;
1865 *offset_out = base_val + offset;
1869 static int stack_frame_access(struct parsed_op *po,
1870 struct parsed_opr *popr, char *buf, size_t buf_size,
1871 const char *name, const char *cast, int is_src, int is_lea)
1873 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1874 const char *prefix = "";
1875 const char *bp_arg = NULL;
1876 char ofs_reg[16] = { 0, };
1877 int i, arg_i, arg_s;
1884 if (g_bp_frame && (po->flags & OPF_EBP_S)
1885 && !(po->regmask_src & mxSP))
1886 ferr(po, "stack_frame_access while ebp is scratch\n");
1888 parse_stack_access(po, name, ofs_reg, &offset,
1889 &stack_ra, &bp_arg, is_lea);
1891 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1893 if (offset > stack_ra)
1895 arg_i = (offset - stack_ra - 4) / 4;
1896 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1898 if (g_func_pp->is_vararg
1899 && arg_i == g_func_pp->argc_stack && is_lea)
1901 // should be va_list
1904 snprintf(buf, buf_size, "%sap", cast);
1907 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1908 offset, bp_arg, arg_i);
1910 if (ofs_reg[0] != 0)
1911 ferr(po, "offset reg on arg access?\n");
1913 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1914 if (g_func_pp->arg[i].reg != NULL)
1920 if (i == g_func_pp->argc)
1921 ferr(po, "arg %d not in prototype?\n", arg_i);
1923 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1930 ferr(po, "lea/byte to arg?\n");
1931 if (is_src && (offset & 3) == 0)
1932 snprintf(buf, buf_size, "%sa%d",
1933 simplify_cast(cast, "(u8)"), i + 1);
1935 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1936 cast, offset & 3, i + 1);
1941 ferr(po, "lea/word to arg?\n");
1946 ferr(po, "problematic arg store\n");
1947 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1948 simplify_cast(cast, "*(u16 *)"), i + 1);
1951 ferr(po, "unaligned arg word load\n");
1953 else if (is_src && (offset & 2) == 0)
1954 snprintf(buf, buf_size, "%sa%d",
1955 simplify_cast(cast, "(u16)"), i + 1);
1957 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1958 cast, (offset & 2) ? "HI" : "LO", i + 1);
1970 snprintf(buf, buf_size, "(u32)&a%d + %d",
1973 ferr(po, "unaligned arg store\n");
1975 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1976 snprintf(buf, buf_size, "%s(a%d >> %d)",
1977 prefix, i + 1, (offset & 3) * 8);
1981 snprintf(buf, buf_size, "%s%sa%d",
1982 prefix, is_lea ? "&" : "", i + 1);
1987 ferr_assert(po, !(offset & 7));
1990 snprintf(buf, buf_size, "%s%sa%d",
1991 prefix, is_lea ? "&" : "", i + 1);
1995 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1999 strcat(g_comment, " unaligned");
2002 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
2003 if (tmp_lmod != OPLM_DWORD
2004 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
2005 < lmod_bytes(po, popr->lmod) + (offset & 3))))
2007 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
2008 i + 1, offset, g_func_pp->arg[i].type.name);
2010 // can't check this because msvc likes to reuse
2011 // arg space for scratch..
2012 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
2013 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2017 if (g_stack_fsz == 0)
2018 ferr(po, "stack var access without stackframe\n");
2019 g_stack_frame_used = 1;
2021 sf_ofs = g_stack_fsz + offset;
2022 if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2023 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2033 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2034 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2038 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2039 // known unaligned or possibly unaligned
2040 strcat(g_comment, " unaligned");
2042 prefix = "*(u16 *)&";
2043 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2044 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2047 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2051 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2052 // known unaligned or possibly unaligned
2053 strcat(g_comment, " unaligned");
2055 prefix = "*(u32 *)&";
2056 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2057 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2060 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2064 ferr_assert(po, !(sf_ofs & 7));
2065 ferr_assert(po, ofs_reg[0] == 0);
2066 // only used for x87 int64/float, float sets is_lea
2067 if (!is_lea && (po->flags & OPF_FINT))
2068 prefix = "*(s64 *)&";
2069 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2073 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2080 static void check_func_pp(struct parsed_op *po,
2081 const struct parsed_proto *pp, const char *pfx)
2083 enum opr_lenmod tmp_lmod;
2087 if (pp->argc_reg != 0) {
2088 if (!g_allow_user_icall && !pp->is_fastcall) {
2089 pp_print(buf, sizeof(buf), pp);
2090 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2092 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2093 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2094 pfx, pp->argc_reg, pp->argc_stack);
2097 // fptrs must use 32bit args, callsite might have no information and
2098 // lack a cast to smaller types, which results in incorrectly masked
2099 // args passed (callee may assume masked args, it does on ARM)
2100 if (!pp->is_osinc) {
2101 for (i = 0; i < pp->argc; i++) {
2102 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2103 if (ret && tmp_lmod != OPLM_DWORD)
2104 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2105 i + 1, pp->arg[i].type.name);
2110 static const char *check_label_read_ref(struct parsed_op *po,
2113 const struct parsed_proto *pp;
2115 pp = proto_parse(g_fhdr, name, 0);
2117 ferr(po, "proto_parse failed for ref '%s'\n", name);
2120 check_func_pp(po, pp, "ref");
2125 static char *out_src_opr(char *buf, size_t buf_size,
2126 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2129 char tmp1[256], tmp2[256];
2138 switch (popr->type) {
2141 ferr(po, "lea from reg?\n");
2143 switch (popr->lmod) {
2145 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2148 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2151 snprintf(buf, buf_size, "%s%s",
2152 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2155 if (popr->name[1] == 'h') // XXX..
2156 snprintf(buf, buf_size, "%s(%s >> 8)",
2157 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2159 snprintf(buf, buf_size, "%s%s",
2160 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2163 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2168 if (is_stack_access(po, popr)) {
2169 stack_frame_access(po, popr, buf, buf_size,
2170 popr->name, cast, 1, is_lea);
2174 strcpy(expr, popr->name);
2175 if (strchr(expr, '[')) {
2176 // special case: '[' can only be left for label[reg] form
2177 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2179 ferr(po, "parse failure for '%s'\n", expr);
2180 if (tmp1[0] == '(') {
2181 // (off_4FFF50+3)[eax]
2182 p = strchr(tmp1 + 1, ')');
2183 if (p == NULL || p[1] != 0)
2184 ferr(po, "parse failure (2) for '%s'\n", expr);
2186 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2188 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2191 // XXX: do we need more parsing?
2193 snprintf(buf, buf_size, "%s", expr);
2197 snprintf(buf, buf_size, "%s(%s)",
2198 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2202 name = check_label_read_ref(po, popr->name);
2203 if (cast[0] == 0 && popr->is_ptr)
2207 snprintf(buf, buf_size, "(u32)&%s", name);
2208 else if (popr->size_lt)
2209 snprintf(buf, buf_size, "%s%s%s%s", cast,
2210 lmod_cast_u_ptr(po, popr->lmod),
2211 popr->is_array ? "" : "&", name);
2213 snprintf(buf, buf_size, "%s%s%s", cast, name,
2214 popr->is_array ? "[0]" : "");
2218 name = check_label_read_ref(po, popr->name);
2222 ferr(po, "lea an offset?\n");
2223 snprintf(buf, buf_size, "%s&%s", cast, name);
2228 ferr(po, "lea from const?\n");
2230 printf_number(tmp1, sizeof(tmp1), popr->val);
2231 if (popr->val == 0 && strchr(cast, '*'))
2232 snprintf(buf, buf_size, "NULL");
2234 snprintf(buf, buf_size, "%s%s",
2235 simplify_cast_num(cast, popr->val), tmp1);
2239 ferr(po, "invalid src type: %d\n", popr->type);
2245 // note: may set is_ptr (we find that out late for ebp frame..)
2246 static char *out_dst_opr(char *buf, size_t buf_size,
2247 struct parsed_op *po, struct parsed_opr *popr)
2249 switch (popr->type) {
2251 switch (popr->lmod) {
2253 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2256 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2260 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2264 if (popr->name[1] == 'h') // XXX..
2265 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2267 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2270 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2275 if (is_stack_access(po, popr)) {
2276 stack_frame_access(po, popr, buf, buf_size,
2277 popr->name, "", 0, 0);
2281 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2284 if (popr->size_mismatch)
2285 snprintf(buf, buf_size, "%s%s%s",
2286 lmod_cast_u_ptr(po, popr->lmod),
2287 popr->is_array ? "" : "&", popr->name);
2289 snprintf(buf, buf_size, "%s%s", popr->name,
2290 popr->is_array ? "[0]" : "");
2294 ferr(po, "invalid dst type: %d\n", popr->type);
2300 static char *out_src_opr_u32(char *buf, size_t buf_size,
2301 struct parsed_op *po, struct parsed_opr *popr)
2303 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2306 static char *out_opr_float(char *buf, size_t buf_size,
2307 struct parsed_op *po, struct parsed_opr *popr, int is_src,
2308 int need_float_stack)
2310 const char *cast = NULL;
2313 switch (popr->type) {
2315 if (popr->reg < xST0 || popr->reg > xST7)
2316 ferr(po, "bad reg: %d\n", popr->reg);
2318 if (need_float_stack) {
2319 if (popr->reg == xST0)
2320 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2322 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2326 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2330 if (popr->lmod == OPLM_QWORD && is_stack_access(po, popr)) {
2331 stack_frame_access(po, popr, buf, buf_size,
2332 popr->name, "", is_src, 0);
2338 switch (popr->lmod) {
2346 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2349 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2350 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2354 ferr(po, "invalid float type: %d\n", popr->type);
2360 static char *out_src_opr_float(char *buf, size_t buf_size,
2361 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2363 return out_opr_float(buf, buf_size, po, popr, 1, need_float_stack);
2366 static char *out_dst_opr_float(char *buf, size_t buf_size,
2367 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2369 return out_opr_float(buf, buf_size, po, popr, 0, need_float_stack);
2372 static void out_test_for_cc(char *buf, size_t buf_size,
2373 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2374 enum opr_lenmod lmod, const char *expr)
2376 const char *cast, *scast;
2378 cast = lmod_cast_u(po, lmod);
2379 scast = lmod_cast_s(po, lmod);
2383 case PFO_BE: // CF==1||ZF==1; CF=0
2384 snprintf(buf, buf_size, "(%s%s %s 0)",
2385 cast, expr, is_inv ? "!=" : "==");
2389 case PFO_L: // SF!=OF; OF=0
2390 snprintf(buf, buf_size, "(%s%s %s 0)",
2391 scast, expr, is_inv ? ">=" : "<");
2394 case PFO_LE: // ZF==1||SF!=OF; OF=0
2395 snprintf(buf, buf_size, "(%s%s %s 0)",
2396 scast, expr, is_inv ? ">" : "<=");
2401 snprintf(buf, buf_size, "(%d)", !!is_inv);
2404 case PFO_P: // PF==1
2405 snprintf(buf, buf_size, "(%sdo_parity(%s))",
2406 is_inv ? "!" : "", expr);
2410 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2414 static void out_cmp_for_cc(char *buf, size_t buf_size,
2415 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2418 const char *cast, *scast, *cast_use;
2419 char buf1[256], buf2[256];
2420 enum opr_lenmod lmod;
2422 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2423 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2424 po->operand[0].lmod, po->operand[1].lmod);
2425 lmod = po->operand[0].lmod;
2427 cast = lmod_cast_u(po, lmod);
2428 scast = lmod_cast_s(po, lmod);
2444 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2447 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2448 if (po->op == OP_DEC)
2449 snprintf(buf2, sizeof(buf2), "1");
2452 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2454 strcat(cast_op2, "-");
2455 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2460 // note: must be unsigned compare
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);
2471 // note: must be unsigned compare
2472 snprintf(buf, buf_size, "(%s %s %s)",
2473 buf1, is_inv ? ">" : "<=", buf2);
2476 if (is_inv && lmod == OPLM_BYTE
2477 && po->operand[1].type == OPT_CONST
2478 && po->operand[1].val == 0xff)
2480 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2481 snprintf(buf, buf_size, "(0)");
2485 // note: must be signed compare
2487 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2488 scast, buf1, buf2, is_inv ? ">=" : "<");
2492 snprintf(buf, buf_size, "(%s %s %s)",
2493 buf1, is_inv ? ">=" : "<", buf2);
2497 snprintf(buf, buf_size, "(%s %s %s)",
2498 buf1, is_inv ? ">" : "<=", buf2);
2506 static void out_cmp_test(char *buf, size_t buf_size,
2507 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2509 char buf1[256], buf2[256], buf3[256];
2511 if (po->op == OP_TEST) {
2512 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2513 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2516 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2517 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2518 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2520 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2521 po->operand[0].lmod, buf3);
2523 else if (po->op == OP_CMP) {
2524 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2527 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2530 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2531 struct parsed_opr *popr2)
2533 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2534 ferr(po, "missing lmod for both operands\n");
2536 if (popr1->lmod == OPLM_UNSPEC)
2537 popr1->lmod = popr2->lmod;
2538 else if (popr2->lmod == OPLM_UNSPEC)
2539 popr2->lmod = popr1->lmod;
2540 else if (popr1->lmod != popr2->lmod) {
2541 if (popr1->type_from_var) {
2542 popr1->size_mismatch = 1;
2543 if (popr1->lmod < popr2->lmod)
2545 popr1->lmod = popr2->lmod;
2547 else if (popr2->type_from_var) {
2548 popr2->size_mismatch = 1;
2549 if (popr2->lmod < popr1->lmod)
2551 popr2->lmod = popr1->lmod;
2554 ferr(po, "conflicting lmods: %d vs %d\n",
2555 popr1->lmod, popr2->lmod);
2559 static const char *op_to_c(struct parsed_op *po)
2583 ferr(po, "op_to_c was supplied with %d\n", po->op);
2587 // last op in stream - unconditional branch or ret
2588 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2589 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2590 && ops[_i].op != OP_CALL))
2592 #define check_i(po, i) \
2594 ferr(po, "bad " #i ": %d\n", i)
2596 // note: this skips over calls and rm'd stuff assuming they're handled
2597 // so it's intended to use at one of final passes
2598 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2599 int depth, int seen_noreturn, int flags_set)
2601 struct parsed_op *po;
2606 for (; i < opcnt; i++) {
2608 if (po->cc_scratch == magic)
2609 return ret; // already checked
2610 po->cc_scratch = magic;
2612 if (po->flags & OPF_TAIL) {
2613 if (po->op == OP_CALL) {
2614 if (po->pp != NULL && po->pp->is_noreturn)
2623 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2626 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2627 if (po->btj != NULL) {
2629 for (j = 0; j < po->btj->count; j++) {
2630 check_i(po, po->btj->d[j].bt_i);
2631 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2632 depth, seen_noreturn, flags_set);
2634 return ret; // dead end
2639 check_i(po, po->bt_i);
2640 if (po->flags & OPF_CJMP) {
2641 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2642 depth, seen_noreturn, flags_set);
2644 return ret; // dead end
2653 if ((po->op == OP_POP || po->op == OP_PUSH)
2654 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2659 if (po->op == OP_PUSH) {
2662 else if (po->op == OP_POP) {
2663 if (relevant && depth == 0) {
2664 po->flags |= flags_set;
2672 // for noreturn, assume msvc skipped stack cleanup
2673 return seen_noreturn ? 1 : -1;
2676 // scan for 'reg' pop backwards starting from i
2677 // intended to use for register restore search, so other reg
2678 // references are considered an error
2679 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2681 struct parsed_op *po;
2682 struct label_ref *lr;
2685 ops[i].cc_scratch = magic;
2689 if (g_labels[i] != NULL) {
2690 lr = &g_label_refs[i];
2691 for (; lr != NULL; lr = lr->next) {
2692 check_i(&ops[i], lr->i);
2693 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2697 if (i > 0 && LAST_OP(i - 1))
2705 if (ops[i].cc_scratch == magic)
2707 ops[i].cc_scratch = magic;
2710 if (po->op == OP_POP && po->operand[0].reg == reg) {
2711 if (po->flags & (OPF_RMD|OPF_DONE))
2714 po->flags |= set_flags;
2718 // this also covers the case where we reach corresponding push
2719 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2723 // nothing interesting on this path,
2724 // still return ret for something recursive calls could find
2728 static void find_reachable_exits(int i, int opcnt, int magic,
2729 int *exits, int *exit_count)
2731 struct parsed_op *po;
2734 for (; i < opcnt; i++)
2737 if (po->cc_scratch == magic)
2739 po->cc_scratch = magic;
2741 if (po->flags & OPF_TAIL) {
2742 ferr_assert(po, *exit_count < MAX_EXITS);
2743 exits[*exit_count] = i;
2748 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2749 if (po->flags & OPF_RMD)
2752 if (po->btj != NULL) {
2753 for (j = 0; j < po->btj->count; j++) {
2754 check_i(po, po->btj->d[j].bt_i);
2755 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2761 check_i(po, po->bt_i);
2762 if (po->flags & OPF_CJMP)
2763 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2771 // scan for 'reg' pop backwards starting from exits (all paths)
2772 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2774 static int exits[MAX_EXITS];
2775 static int exit_count;
2781 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2783 ferr_assert(&ops[i], exit_count > 0);
2786 for (j = 0; j < exit_count; j++) {
2788 ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2794 if (ops[e].op == OP_CALL && ops[e].pp != NULL
2795 && ops[e].pp->is_noreturn)
2797 // assume stack cleanup was skipped
2806 // scan for one or more pop of push <const>
2807 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2808 int push_i, int is_probe)
2810 struct parsed_op *po;
2811 struct label_ref *lr;
2815 for (; i < opcnt; i++)
2818 if (po->cc_scratch == magic)
2819 return ret; // already checked
2820 po->cc_scratch = magic;
2822 if (po->flags & OPF_JMP) {
2823 if (po->flags & OPF_RMD)
2825 if (po->op == OP_CALL)
2828 if (po->btj != NULL) {
2829 for (j = 0; j < po->btj->count; j++) {
2830 check_i(po, po->btj->d[j].bt_i);
2831 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2839 check_i(po, po->bt_i);
2840 if (po->flags & OPF_CJMP) {
2841 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2852 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2855 if (g_labels[i] != NULL) {
2856 // all refs must be visited
2857 lr = &g_label_refs[i];
2858 for (; lr != NULL; lr = lr->next) {
2860 if (ops[lr->i].cc_scratch != magic)
2863 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2867 if (po->op == OP_POP)
2869 if (po->flags & (OPF_RMD|OPF_DONE))
2873 po->flags |= OPF_DONE;
2874 po->datap = &ops[push_i];
2883 static void scan_for_pop_const(int i, int opcnt, int magic)
2887 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2889 ops[i].flags |= OPF_RMD | OPF_DONE;
2890 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2894 // check if all branch targets within a marked path are also marked
2895 // note: the path checked must not be empty or end with a branch
2896 static int check_path_branches(int opcnt, int magic)
2898 struct parsed_op *po;
2901 for (i = 0; i < opcnt; i++) {
2903 if (po->cc_scratch != magic)
2906 if (po->flags & OPF_JMP) {
2907 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2910 if (po->btj != NULL) {
2911 for (j = 0; j < po->btj->count; j++) {
2912 check_i(po, po->btj->d[j].bt_i);
2913 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2918 check_i(po, po->bt_i);
2919 if (ops[po->bt_i].cc_scratch != magic)
2921 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2929 // scan for multiple pushes for given pop
2930 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2933 int reg = ops[pop_i].operand[0].reg;
2934 struct parsed_op *po;
2935 struct label_ref *lr;
2938 ops[i].cc_scratch = magic;
2942 if (g_labels[i] != NULL) {
2943 lr = &g_label_refs[i];
2944 for (; lr != NULL; lr = lr->next) {
2945 check_i(&ops[i], lr->i);
2946 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2950 if (i > 0 && LAST_OP(i - 1))
2958 if (ops[i].cc_scratch == magic)
2960 ops[i].cc_scratch = magic;
2963 if (po->op == OP_CALL)
2965 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2968 if (po->op == OP_PUSH)
2970 if (po->datap != NULL)
2972 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2973 // leave this case for reg save/restore handlers
2977 po->flags |= OPF_PPUSH | OPF_DONE;
2978 po->datap = &ops[pop_i];
2987 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2989 int magic = i + opcnt * 14;
2992 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2994 ret = check_path_branches(opcnt, magic);
2996 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2997 *regmask_pp |= 1 << ops[i].operand[0].reg;
2998 scan_pushes_for_pop_r(i, magic + 1, i, 0);
3003 static void scan_propagate_df(int i, int opcnt)
3005 struct parsed_op *po = &ops[i];
3008 for (; i < opcnt; i++) {
3010 if (po->flags & OPF_DF)
3011 return; // already resolved
3012 po->flags |= OPF_DF;
3014 if (po->op == OP_CALL)
3015 ferr(po, "call with DF set?\n");
3017 if (po->flags & OPF_JMP) {
3018 if (po->btj != NULL) {
3020 for (j = 0; j < po->btj->count; j++) {
3021 check_i(po, po->btj->d[j].bt_i);
3022 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
3027 if (po->flags & OPF_RMD)
3029 check_i(po, po->bt_i);
3030 if (po->flags & OPF_CJMP)
3031 scan_propagate_df(po->bt_i, opcnt);
3037 if (po->flags & OPF_TAIL)
3040 if (po->op == OP_CLD) {
3041 po->flags |= OPF_RMD | OPF_DONE;
3046 ferr(po, "missing DF clear?\n");
3049 // is operand 'opr' referenced by parsed_op 'po'?
3050 static int is_opr_referenced(const struct parsed_opr *opr,
3051 const struct parsed_op *po)
3055 if (opr->type == OPT_REG) {
3056 mask = po->regmask_dst | po->regmask_src;
3057 if (po->op == OP_CALL)
3058 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3059 if ((1 << opr->reg) & mask)
3065 for (i = 0; i < po->operand_cnt; i++)
3066 if (IS(po->operand[0].name, opr->name))
3072 // is operand 'opr' read by parsed_op 'po'?
3073 static int is_opr_read(const struct parsed_opr *opr,
3074 const struct parsed_op *po)
3076 if (opr->type == OPT_REG) {
3077 if (po->regmask_src & (1 << opr->reg))
3087 // is operand 'opr' modified by parsed_op 'po'?
3088 static int is_opr_modified(const struct parsed_opr *opr,
3089 const struct parsed_op *po)
3093 if (opr->type == OPT_REG) {
3094 if (po->op == OP_CALL) {
3095 mask = po->regmask_dst;
3096 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3097 if (mask & (1 << opr->reg))
3103 if (po->regmask_dst & (1 << opr->reg))
3109 return IS(po->operand[0].name, opr->name);
3112 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3113 static int is_any_opr_modified(const struct parsed_op *po_test,
3114 const struct parsed_op *po, int c_mode)
3119 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3122 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3125 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3128 // in reality, it can wreck any register, but in decompiled C
3129 // version it can only overwrite eax or edx:eax
3130 mask = (1 << xAX) | (1 << xDX);
3134 if (po->op == OP_CALL
3135 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3138 for (i = 0; i < po_test->operand_cnt; i++)
3139 if (IS(po_test->operand[i].name, po->operand[0].name))
3145 // scan for any po_test operand modification in range given
3146 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3149 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3152 for (; i < opcnt; i++) {
3153 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3160 // scan for po_test operand[0] modification in range given
3161 static int scan_for_mod_opr0(struct parsed_op *po_test,
3164 for (; i < opcnt; i++) {
3165 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3172 static int try_resolve_const(int i, const struct parsed_opr *opr,
3173 int magic, unsigned int *val);
3175 static int scan_for_flag_set(int i, int opcnt, int magic,
3176 int *branched, int *setters, int *setter_cnt)
3178 struct label_ref *lr;
3182 if (ops[i].cc_scratch == magic) {
3183 // is this a problem?
3184 //ferr(&ops[i], "%s looped\n", __func__);
3187 ops[i].cc_scratch = magic;
3189 if (g_labels[i] != NULL) {
3192 lr = &g_label_refs[i];
3193 for (; lr->next; lr = lr->next) {
3194 check_i(&ops[i], lr->i);
3195 ret = scan_for_flag_set(lr->i, opcnt, magic,
3196 branched, setters, setter_cnt);
3201 check_i(&ops[i], lr->i);
3202 if (i > 0 && LAST_OP(i - 1)) {
3206 ret = scan_for_flag_set(lr->i, opcnt, magic,
3207 branched, setters, setter_cnt);
3213 if (ops[i].flags & OPF_FLAGS) {
3214 setters[*setter_cnt] = i;
3217 if (ops[i].flags & OPF_REP) {
3218 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3221 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3222 if (ret != 1 || uval == 0) {
3223 // can't treat it as full setter because of ecx=0 case,
3224 // also disallow delayed compare
3233 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3240 // scan back for cdq, if anything modifies edx, fail
3241 static int scan_for_cdq_edx(int i)
3244 if (g_labels[i] != NULL) {
3245 if (g_label_refs[i].next != NULL)
3247 if (i > 0 && LAST_OP(i - 1)) {
3248 i = g_label_refs[i].i;
3255 if (ops[i].op == OP_CDQ)
3258 if (ops[i].regmask_dst & (1 << xDX))
3265 static int scan_for_reg_clear(int i, int reg)
3268 if (g_labels[i] != NULL) {
3269 if (g_label_refs[i].next != NULL)
3271 if (i > 0 && LAST_OP(i - 1)) {
3272 i = g_label_refs[i].i;
3279 if (ops[i].op == OP_XOR
3280 && ops[i].operand[0].lmod == OPLM_DWORD
3281 && ops[i].operand[0].reg == ops[i].operand[1].reg
3282 && ops[i].operand[0].reg == reg)
3285 if (ops[i].regmask_dst & (1 << reg))
3292 static void patch_esp_adjust(struct parsed_op *po, int adj)
3294 ferr_assert(po, po->op == OP_ADD);
3295 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3296 ferr_assert(po, po->operand[1].type == OPT_CONST);
3298 // this is a bit of a hack, but deals with use of
3299 // single adj for multiple calls
3300 po->operand[1].val -= adj;
3301 po->flags |= OPF_RMD;
3302 if (po->operand[1].val == 0)
3303 po->flags |= OPF_DONE;
3304 ferr_assert(po, (int)po->operand[1].val >= 0);
3307 // scan for positive, constant esp adjust
3308 // multipath case is preliminary
3309 static int scan_for_esp_adjust(int i, int opcnt,
3310 int adj_expect, int *adj, int *is_multipath, int do_update)
3312 int adj_expect_unknown = 0;
3313 struct parsed_op *po;
3317 *adj = *is_multipath = 0;
3318 if (adj_expect < 0) {
3319 adj_expect_unknown = 1;
3320 adj_expect = 32 * 4; // enough?
3323 for (; i < opcnt && *adj < adj_expect; i++) {
3324 if (g_labels[i] != NULL)
3328 if (po->flags & OPF_DONE)
3331 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3332 if (po->operand[1].type != OPT_CONST)
3333 ferr(&ops[i], "non-const esp adjust?\n");
3334 *adj += po->operand[1].val;
3336 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3339 patch_esp_adjust(po, adj_expect);
3341 po->flags |= OPF_RMD;
3345 else if (po->op == OP_PUSH) {
3346 //if (first_pop == -1)
3347 // first_pop = -2; // none
3348 *adj -= lmod_bytes(po, po->operand[0].lmod);
3350 else if (po->op == OP_POP) {
3351 if (!(po->flags & OPF_DONE)) {
3352 // seems like msvc only uses 'pop ecx' for stack realignment..
3353 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3355 if (first_pop == -1 && *adj >= 0)
3358 if (do_update && *adj >= 0) {
3359 po->flags |= OPF_RMD;
3361 po->flags |= OPF_DONE | OPF_NOREGS;
3364 *adj += lmod_bytes(po, po->operand[0].lmod);
3365 if (*adj > adj_best)
3368 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3369 if (po->op == OP_JMP && po->btj == NULL) {
3375 if (po->op != OP_CALL)
3377 if (po->operand[0].type != OPT_LABEL)
3379 if (po->pp != NULL && po->pp->is_stdcall)
3381 if (adj_expect_unknown && first_pop >= 0)
3383 // assume it's another cdecl call
3387 if (first_pop >= 0) {
3388 // probably only 'pop ecx' was used
3396 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3398 struct parsed_op *po;
3402 ferr(ops, "%s: followed bad branch?\n", __func__);
3404 for (; i < opcnt; i++) {
3406 if (po->cc_scratch == magic)
3408 po->cc_scratch = magic;
3411 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3412 if (po->btj != NULL) {
3414 for (j = 0; j < po->btj->count; j++)
3415 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3419 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3420 if (!(po->flags & OPF_CJMP))
3423 if (po->flags & OPF_TAIL)
3428 static const struct parsed_proto *try_recover_pp(
3429 struct parsed_op *po, const struct parsed_opr *opr,
3430 int is_call, int *search_instead)
3432 const struct parsed_proto *pp = NULL;
3436 // maybe an arg of g_func?
3437 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3439 char ofs_reg[16] = { 0, };
3440 int arg, arg_s, arg_i;
3447 parse_stack_access(po, opr->name, ofs_reg,
3448 &offset, &stack_ra, NULL, 0);
3449 if (ofs_reg[0] != 0)
3450 ferr(po, "offset reg on arg access?\n");
3451 if (offset <= stack_ra) {
3452 // search who set the stack var instead
3453 if (search_instead != NULL)
3454 *search_instead = 1;
3458 arg_i = (offset - stack_ra - 4) / 4;
3459 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3460 if (g_func_pp->arg[arg].reg != NULL)
3466 if (arg == g_func_pp->argc)
3467 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3469 pp = g_func_pp->arg[arg].pp;
3472 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3473 check_func_pp(po, pp, "icall arg");
3476 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3478 p = strchr(opr->name + 1, '[');
3479 memcpy(buf, opr->name, p - opr->name);
3480 buf[p - opr->name] = 0;
3481 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3483 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3484 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3487 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3490 check_func_pp(po, pp, "reg-fptr ref");
3496 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3497 int magic, const struct parsed_proto **pp_found, int *pp_i,
3500 const struct parsed_proto *pp = NULL;
3501 struct parsed_op *po;
3502 struct label_ref *lr;
3504 ops[i].cc_scratch = magic;
3507 if (g_labels[i] != NULL) {
3508 lr = &g_label_refs[i];
3509 for (; lr != NULL; lr = lr->next) {
3510 check_i(&ops[i], lr->i);
3511 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3513 if (i > 0 && LAST_OP(i - 1))
3521 if (ops[i].cc_scratch == magic)
3523 ops[i].cc_scratch = magic;
3525 if (!(ops[i].flags & OPF_DATA))
3527 if (!is_opr_modified(opr, &ops[i]))
3529 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3530 // most probably trashed by some processing
3535 opr = &ops[i].operand[1];
3536 if (opr->type != OPT_REG)
3540 po = (i >= 0) ? &ops[i] : ops;
3543 // reached the top - can only be an arg-reg
3544 if (opr->type != OPT_REG || g_func_pp == NULL)
3547 for (i = 0; i < g_func_pp->argc; i++) {
3548 if (g_func_pp->arg[i].reg == NULL)
3550 if (IS(opr->name, g_func_pp->arg[i].reg))
3553 if (i == g_func_pp->argc)
3555 pp = g_func_pp->arg[i].pp;
3557 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3558 i + 1, g_func_pp->arg[i].reg);
3559 check_func_pp(po, pp, "icall reg-arg");
3562 pp = try_recover_pp(po, opr, 1, NULL);
3564 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3565 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3566 || (*pp_found)->is_stdcall != pp->is_stdcall
3567 //|| (*pp_found)->is_fptr != pp->is_fptr
3568 || (*pp_found)->argc != pp->argc
3569 || (*pp_found)->argc_reg != pp->argc_reg
3570 || (*pp_found)->argc_stack != pp->argc_stack)
3572 ferr(po, "icall: parsed_proto mismatch\n");
3582 static void add_label_ref(struct label_ref *lr, int op_i)
3584 struct label_ref *lr_new;
3591 lr_new = calloc(1, sizeof(*lr_new));
3593 lr_new->next = lr->next;
3597 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3599 struct parsed_op *po = &ops[i];
3600 struct parsed_data *pd;
3601 char label[NAMELEN], *p;
3604 p = strchr(po->operand[0].name, '[');
3608 len = p - po->operand[0].name;
3609 strncpy(label, po->operand[0].name, len);
3612 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3613 if (IS(g_func_pd[j].label, label)) {
3619 //ferr(po, "label '%s' not parsed?\n", label);
3622 if (pd->type != OPT_OFFSET)
3623 ferr(po, "label '%s' with non-offset data?\n", label);
3625 // find all labels, link
3626 for (j = 0; j < pd->count; j++) {
3627 for (l = 0; l < opcnt; l++) {
3628 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3629 add_label_ref(&g_label_refs[l], i);
3639 static void clear_labels(int count)
3643 for (i = 0; i < count; i++) {
3644 if (g_labels[i] != NULL) {
3651 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3656 for (i = 0; i < pp->argc; i++) {
3657 if (pp->arg[i].reg != NULL) {
3658 reg = char_array_i(regs_r32,
3659 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3661 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3662 pp->arg[i].reg, pp->name);
3663 regmask |= 1 << reg;
3670 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3675 if (pp->has_retreg) {
3676 for (i = 0; i < pp->argc; i++) {
3677 if (pp->arg[i].type.is_retreg) {
3678 reg = char_array_i(regs_r32,
3679 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3680 ferr_assert(ops, reg >= 0);
3681 regmask |= 1 << reg;
3686 if (strstr(pp->ret_type.name, "int64"))
3687 return regmask | (1 << xAX) | (1 << xDX);
3688 if (IS(pp->ret_type.name, "float")
3689 || IS(pp->ret_type.name, "double"))
3691 return regmask | mxST0;
3693 if (strcasecmp(pp->ret_type.name, "void") == 0)
3696 return regmask | mxAX;
3699 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3701 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3702 && memcmp(po1->operand, po2->operand,
3703 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3706 static void resolve_branches_parse_calls(int opcnt)
3708 static const struct {
3712 unsigned int regmask_src;
3713 unsigned int regmask_dst;
3715 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3716 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3717 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3718 // more precise? Wine gets away with just __ftol handler
3719 { "__ftol2", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3720 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3722 const struct parsed_proto *pp_c;
3723 struct parsed_proto *pp;
3724 struct parsed_data *pd;
3725 struct parsed_op *po;
3726 const char *tmpname;
3731 for (i = 0; i < opcnt; i++)
3737 if (po->datap != NULL) {
3738 pp = calloc(1, sizeof(*pp));
3739 my_assert_not(pp, NULL);
3741 ret = parse_protostr(po->datap, pp);
3743 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3749 if (po->op == OP_CALL) {
3754 else if (po->operand[0].type == OPT_LABEL)
3756 tmpname = opr_name(po, 0);
3757 if (IS_START(tmpname, "loc_"))
3758 ferr(po, "call to loc_*\n");
3759 if (IS(tmpname, "__alloca_probe"))
3762 // convert some calls to pseudo-ops
3763 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3764 if (!IS(tmpname, pseudo_ops[l].name))
3767 po->op = pseudo_ops[l].op;
3768 po->operand_cnt = 0;
3769 po->regmask_src = pseudo_ops[l].regmask_src;
3770 po->regmask_dst = pseudo_ops[l].regmask_dst;
3771 po->flags = pseudo_ops[l].flags;
3772 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3775 if (l < ARRAY_SIZE(pseudo_ops))
3778 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3779 if (!g_header_mode && pp_c == NULL)
3780 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3783 pp = proto_clone(pp_c);
3784 my_assert_not(pp, NULL);
3790 check_func_pp(po, pp, "fptr var call");
3791 if (pp->is_noreturn) {
3792 po->flags |= OPF_TAIL;
3793 po->flags &= ~OPF_ATAIL; // most likely...
3800 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3803 if (po->operand[0].type == OPT_REGMEM) {
3804 pd = try_resolve_jumptab(i, opcnt);
3812 for (l = 0; l < opcnt; l++) {
3813 if (g_labels[l] != NULL
3814 && IS(po->operand[0].name, g_labels[l]))
3816 if (l == i + 1 && po->op == OP_JMP) {
3817 // yet another alignment type..
3818 po->flags |= OPF_RMD|OPF_DONE;
3821 add_label_ref(&g_label_refs[l], i);
3827 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3830 if (po->operand[0].type == OPT_LABEL)
3834 ferr(po, "unhandled branch\n");
3838 po->flags |= OPF_TAIL;
3839 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3840 if (prev_op == OP_POP)
3841 po->flags |= OPF_ATAIL;
3842 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3843 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3845 po->flags |= OPF_ATAIL;
3851 static void scan_prologue_epilogue(int opcnt, int *stack_align)
3853 int ecx_push = 0, esp_sub = 0, pusha = 0;
3854 int sandard_epilogue;
3858 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3859 && ops[1].op == OP_MOV
3860 && IS(opr_name(&ops[1], 0), "ebp")
3861 && IS(opr_name(&ops[1], 1), "esp"))
3864 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3865 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3868 if (ops[i].op == OP_PUSHA) {
3869 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3874 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
3875 && ops[i].operand[1].type == OPT_CONST)
3877 l = ops[i].operand[1].val;
3879 if (j == -1 || (l >> j) != -1)
3880 ferr(&ops[i], "unhandled esp align: %x\n", l);
3881 if (stack_align != NULL)
3882 *stack_align = 1 << j;
3883 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3887 if (ops[i].op == OP_SUB && IS(opr_name(&ops[i], 0), "esp")) {
3888 g_stack_fsz = opr_const(&ops[i], 1);
3889 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3893 // another way msvc builds stack frame..
3894 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3896 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3900 // and another way..
3901 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3902 && ops[i].operand[1].type == OPT_CONST
3903 && ops[i + 1].op == OP_CALL
3904 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3906 g_stack_fsz += ops[i].operand[1].val;
3907 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3909 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3916 for (; i < opcnt; i++)
3917 if (ops[i].flags & OPF_TAIL)
3920 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3921 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3927 sandard_epilogue = 0;
3928 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3930 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3931 // the standard epilogue is sometimes even used without a sf
3932 if (ops[j - 1].op == OP_MOV
3933 && IS(opr_name(&ops[j - 1], 0), "esp")
3934 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3935 sandard_epilogue = 1;
3937 else if (ops[j].op == OP_LEAVE)
3939 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3940 sandard_epilogue = 1;
3942 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3943 && ops[i].pp->is_noreturn)
3945 // on noreturn, msvc sometimes cleans stack, sometimes not
3950 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3951 ferr(&ops[j], "'pop ebp' expected\n");
3953 if (g_stack_fsz != 0 || sandard_epilogue) {
3954 if (ops[j].op == OP_LEAVE)
3956 else if (sandard_epilogue) // mov esp, ebp
3958 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3961 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3963 ferr(&ops[j], "esp restore expected\n");
3966 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3967 && IS(opr_name(&ops[j], 0), "ecx"))
3969 ferr(&ops[j], "unexpected ecx pop\n");
3974 if (ops[j].op == OP_POPA)
3975 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3977 ferr(&ops[j], "popa expected\n");
3982 } while (i < opcnt);
3985 ferr(ops, "missing ebp epilogue\n");
3991 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3992 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3998 for (; i < opcnt; i++) {
3999 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
4001 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4002 && ops[i].operand[1].type == OPT_CONST)
4004 g_stack_fsz = ops[i].operand[1].val;
4005 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4010 else if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4011 && ops[i].operand[1].type == OPT_CONST
4012 && ops[i + 1].op == OP_CALL
4013 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
4015 g_stack_fsz += ops[i].operand[1].val;
4016 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4018 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4025 if (ecx_push && !esp_sub) {
4026 // could actually be args for a call..
4027 for (; i < opcnt; i++)
4028 if (ops[i].op != OP_PUSH)
4031 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4032 const struct parsed_proto *pp;
4033 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4034 j = pp ? pp->argc_stack : 0;
4035 while (i > 0 && j > 0) {
4037 if (ops[i].op == OP_PUSH) {
4038 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4043 ferr(&ops[i], "unhandled prologue\n");
4046 i = g_stack_fsz = ecx_push = 0;
4047 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4048 if (!(ops[i].flags & OPF_RMD))
4058 if (ecx_push || esp_sub)
4063 for (; i < opcnt; i++)
4064 if (ops[i].flags & OPF_TAIL)
4068 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4069 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4076 for (l = 0; l < ecx_push; l++) {
4077 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4079 else if (ops[j].op == OP_ADD
4080 && IS(opr_name(&ops[j], 0), "esp")
4081 && ops[j].operand[1].type == OPT_CONST)
4084 l += ops[j].operand[1].val / 4 - 1;
4089 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4092 if (l != ecx_push) {
4093 if (i < opcnt && ops[i].op == OP_CALL
4094 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4096 // noreturn tailcall with no epilogue
4101 ferr(&ops[j], "epilogue scan failed\n");
4108 if (ops[j].op != OP_ADD
4109 || !IS(opr_name(&ops[j], 0), "esp")
4110 || ops[j].operand[1].type != OPT_CONST)
4112 if (i < opcnt && ops[i].op == OP_CALL
4113 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4115 // noreturn tailcall with no epilogue
4120 ferr(&ops[j], "'add esp' expected\n");
4123 if (ops[j].operand[1].val < g_stack_fsz)
4124 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4126 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4127 if (ops[j].operand[1].val == 0)
4128 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4133 } while (i < opcnt);
4136 ferr(ops, "missing esp epilogue\n");
4140 // find an instruction that changed opr before i op
4141 // *op_i must be set to -1 by the caller
4142 // *is_caller is set to 1 if one source is determined to be g_func arg
4143 // returns 1 if found, *op_i is then set to origin
4144 // returns -1 if multiple origins are found
4145 static int resolve_origin(int i, const struct parsed_opr *opr,
4146 int magic, int *op_i, int *is_caller)
4148 struct label_ref *lr;
4152 if (g_labels[i] != NULL) {
4153 lr = &g_label_refs[i];
4154 for (; lr != NULL; lr = lr->next) {
4155 check_i(&ops[i], lr->i);
4156 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4158 if (i > 0 && LAST_OP(i - 1))
4164 if (is_caller != NULL)
4169 if (ops[i].cc_scratch == magic)
4171 ops[i].cc_scratch = magic;
4173 if (!(ops[i].flags & OPF_DATA))
4175 if (!is_opr_modified(opr, &ops[i]))
4179 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4190 // find an instruction that previously referenced opr
4191 // if multiple results are found - fail
4192 // *op_i must be set to -1 by the caller
4193 // returns 1 if found, *op_i is then set to referencer insn
4194 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4195 int magic, int *op_i)
4197 struct label_ref *lr;
4201 if (g_labels[i] != NULL) {
4202 lr = &g_label_refs[i];
4203 for (; lr != NULL; lr = lr->next) {
4204 check_i(&ops[i], lr->i);
4205 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4207 if (i > 0 && LAST_OP(i - 1))
4215 if (ops[i].cc_scratch == magic)
4217 ops[i].cc_scratch = magic;
4219 if (!is_opr_referenced(opr, &ops[i]))
4230 // adjust datap of all reachable 'op' insns when moving back
4231 // returns 1 if at least 1 op was found
4232 // returns -1 if path without an op was found
4233 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4235 struct label_ref *lr;
4238 if (ops[i].cc_scratch == magic)
4240 ops[i].cc_scratch = magic;
4243 if (g_labels[i] != NULL) {
4244 lr = &g_label_refs[i];
4245 for (; lr != NULL; lr = lr->next) {
4246 check_i(&ops[i], lr->i);
4247 ret |= adjust_prev_op(lr->i, op, magic, datap);
4249 if (i > 0 && LAST_OP(i - 1))
4257 if (ops[i].cc_scratch == magic)
4259 ops[i].cc_scratch = magic;
4261 if (ops[i].op != op)
4264 ops[i].datap = datap;
4269 // find next instruction that reads opr
4270 // *op_i must be set to -1 by the caller
4271 // on return, *op_i is set to first referencer insn
4272 // returns 1 if exactly 1 referencer is found
4273 static int find_next_read(int i, int opcnt,
4274 const struct parsed_opr *opr, int magic, int *op_i)
4276 struct parsed_op *po;
4279 for (; i < opcnt; i++)
4281 if (ops[i].cc_scratch == magic)
4283 ops[i].cc_scratch = magic;
4286 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4287 if (po->btj != NULL) {
4289 for (j = 0; j < po->btj->count; j++) {
4290 check_i(po, po->btj->d[j].bt_i);
4291 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4297 if (po->flags & OPF_RMD)
4299 check_i(po, po->bt_i);
4300 if (po->flags & OPF_CJMP) {
4301 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4310 if (!is_opr_read(opr, po)) {
4312 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4313 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4315 full_opr = po->operand[0].lmod >= opr->lmod;
4317 if (is_opr_modified(opr, po) && full_opr) {
4321 if (po->flags & OPF_TAIL)
4336 // find next instruction that reads opr
4337 // *op_i must be set to -1 by the caller
4338 // on return, *op_i is set to first flag user insn
4339 // returns 1 if exactly 1 flag user is found
4340 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4342 struct parsed_op *po;
4345 for (; i < opcnt; i++)
4347 if (ops[i].cc_scratch == magic)
4349 ops[i].cc_scratch = magic;
4352 if (po->op == OP_CALL)
4354 if (po->flags & OPF_JMP) {
4355 if (po->btj != NULL) {
4357 for (j = 0; j < po->btj->count; j++) {
4358 check_i(po, po->btj->d[j].bt_i);
4359 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4365 if (po->flags & OPF_RMD)
4367 check_i(po, po->bt_i);
4368 if (po->flags & OPF_CJMP)
4375 if (!(po->flags & OPF_CC)) {
4376 if (po->flags & OPF_FLAGS)
4379 if (po->flags & OPF_TAIL)
4395 static int try_resolve_const(int i, const struct parsed_opr *opr,
4396 int magic, unsigned int *val)
4401 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4404 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4407 *val = ops[i].operand[1].val;
4414 static int resolve_used_bits(int i, int opcnt, int reg,
4415 int *mask, int *is_z_check)
4417 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4421 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4425 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4427 fnote(&ops[j], "(first read)\n");
4428 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4431 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4432 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4434 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4435 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4437 *mask = ops[j].operand[1].val;
4438 if (ops[j].operand[0].lmod == OPLM_BYTE
4439 && ops[j].operand[0].name[1] == 'h')
4443 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4446 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4448 *is_z_check = ops[k].pfo == PFO_Z;
4453 static const struct parsed_proto *resolve_deref(int i, int magic,
4454 struct parsed_opr *opr, int level)
4456 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4457 const struct parsed_proto *pp = NULL;
4458 int from_caller = 0;
4467 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4468 if (ret != 2 || len != strlen(opr->name)) {
4469 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4470 if (ret != 1 || len != strlen(opr->name))
4474 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4479 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4483 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4484 && strlen(ops[j].operand[1].name) == 3
4485 && ops[j].operand[0].lmod == OPLM_DWORD
4486 && ops[j].pp == NULL // no hint
4489 // allow one simple dereference (com/directx)
4490 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4491 ops[j].operand[1].name);
4495 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4500 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4503 if (ops[j].pp != NULL) {
4507 else if (ops[j].operand[1].type == OPT_REGMEM) {
4508 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4510 // maybe structure ptr in structure
4511 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4514 else if (ops[j].operand[1].type == OPT_LABEL)
4515 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4516 else if (ops[j].operand[1].type == OPT_REG) {
4519 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4521 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4522 for (k = 0; k < g_func_pp->argc; k++) {
4523 if (g_func_pp->arg[k].reg == NULL)
4525 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4526 pp = g_func_pp->arg[k].pp;
4535 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4537 ferr(&ops[j], "expected struct, got '%s %s'\n",
4538 pp->type.name, pp->name);
4542 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4545 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4546 int *pp_i, int *multi_src)
4548 const struct parsed_proto *pp = NULL;
4549 int search_advice = 0;
4554 switch (ops[i].operand[0].type) {
4556 // try to resolve struct member calls
4557 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4563 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4569 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4577 static struct parsed_proto *process_call_early(int i, int opcnt,
4580 struct parsed_op *po = &ops[i];
4581 struct parsed_proto *pp;
4587 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4591 // look for and make use of esp adjust
4593 if (!pp->is_stdcall && pp->argc_stack > 0)
4594 ret = scan_for_esp_adjust(i + 1, opcnt,
4595 pp->argc_stack * 4, &adj, &multipath, 0);
4597 if (pp->argc_stack > adj / 4)
4601 if (ops[ret].op == OP_POP) {
4602 for (j = 1; j < adj / 4; j++) {
4603 if (ops[ret + j].op != OP_POP
4604 || ops[ret + j].operand[0].reg != xCX)
4616 static struct parsed_proto *process_call(int i, int opcnt)
4618 struct parsed_op *po = &ops[i];
4619 const struct parsed_proto *pp_c;
4620 struct parsed_proto *pp;
4621 const char *tmpname;
4622 int call_i = -1, ref_i = -1;
4623 int adj = 0, multipath = 0;
4626 tmpname = opr_name(po, 0);
4631 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4633 if (!pp_c->is_func && !pp_c->is_fptr)
4634 ferr(po, "call to non-func: %s\n", pp_c->name);
4635 pp = proto_clone(pp_c);
4636 my_assert_not(pp, NULL);
4638 // not resolved just to single func
4641 switch (po->operand[0].type) {
4643 // we resolved this call and no longer need the register
4644 po->regmask_src &= ~(1 << po->operand[0].reg);
4646 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4647 && ops[call_i].operand[1].type == OPT_LABEL)
4649 // no other source users?
4650 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4652 if (ret == 1 && call_i == ref_i) {
4653 // and nothing uses it after us?
4655 find_next_read(i + 1, opcnt, &po->operand[0],
4656 i + opcnt * 11, &ref_i);
4658 // then also don't need the source mov
4659 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4671 pp = calloc(1, sizeof(*pp));
4672 my_assert_not(pp, NULL);
4675 ret = scan_for_esp_adjust(i + 1, opcnt,
4676 -1, &adj, &multipath, 0);
4677 if (ret < 0 || adj < 0) {
4678 if (!g_allow_regfunc)
4679 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4680 pp->is_unresolved = 1;
4684 if (adj > ARRAY_SIZE(pp->arg))
4685 ferr(po, "esp adjust too large: %d\n", adj);
4686 pp->ret_type.name = strdup("int");
4687 pp->argc = pp->argc_stack = adj;
4688 for (arg = 0; arg < pp->argc; arg++)
4689 pp->arg[arg].type.name = strdup("int");
4694 // look for and make use of esp adjust
4697 if (!pp->is_stdcall && pp->argc_stack > 0) {
4698 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4699 ret = scan_for_esp_adjust(i + 1, opcnt,
4700 adj_expect, &adj, &multipath, 0);
4703 if (pp->is_vararg) {
4704 if (adj / 4 < pp->argc_stack) {
4705 fnote(po, "(this call)\n");
4706 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4707 adj, pp->argc_stack * 4);
4709 // modify pp to make it have varargs as normal args
4711 pp->argc += adj / 4 - pp->argc_stack;
4712 for (; arg < pp->argc; arg++) {
4713 pp->arg[arg].type.name = strdup("int");
4716 if (pp->argc > ARRAY_SIZE(pp->arg))
4717 ferr(po, "too many args for '%s'\n", tmpname);
4719 if (pp->argc_stack > adj / 4) {
4720 if (pp->is_noreturn)
4721 // assume no stack adjust was emited
4723 fnote(po, "(this call)\n");
4724 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4725 tmpname, pp->argc_stack * 4, adj);
4728 scan_for_esp_adjust(i + 1, opcnt,
4729 pp->argc_stack * 4, &adj, &multipath, 1);
4731 else if (pp->is_vararg)
4732 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4739 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
4742 struct parsed_op *po;
4748 for (base_arg = 0; base_arg < pp->argc; base_arg++)
4749 if (pp->arg[base_arg].reg == NULL)
4752 for (j = i; j > 0; )
4754 ferr_assert(&ops[j], g_labels[j] == NULL);
4758 ferr_assert(po, po->op != OP_PUSH);
4759 if (po->op == OP_FST)
4761 if (po->operand[0].type != OPT_REGMEM)
4763 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
4766 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
4767 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
4771 arg = base_arg + offset / 4;
4773 po->p_argnum = arg + 1;
4774 ferr_assert(po, pp->arg[arg].datap == NULL);
4775 pp->arg[arg].datap = po;
4776 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
4777 if (regmask_ffca != NULL)
4778 *regmask_ffca |= 1 << arg;
4780 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4781 && po->operand[1].type == OPT_CONST)
4783 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4788 for (arg = base_arg; arg < pp->argc; arg++) {
4789 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
4790 po = pp->arg[arg].datap;
4792 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
4793 if (po->operand[0].lmod == OPLM_QWORD)
4800 static int collect_call_args_early(int i, struct parsed_proto *pp,
4801 int *regmask, int *regmask_ffca)
4803 struct parsed_op *po;
4807 for (arg = 0; arg < pp->argc; arg++)
4808 if (pp->arg[arg].reg == NULL)
4811 // first see if it can be easily done
4812 for (j = i; j > 0 && arg < pp->argc; )
4814 if (g_labels[j] != NULL)
4819 if (po->op == OP_CALL)
4821 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
4823 else if (po->op == OP_POP)
4825 else if (po->flags & OPF_CJMP)
4827 else if (po->op == OP_PUSH) {
4828 if (po->flags & (OPF_FARG|OPF_FARGNR))
4830 if (!g_header_mode) {
4831 ret = scan_for_mod(po, j + 1, i, 1);
4836 if (pp->arg[arg].type.is_va_list)
4840 for (arg++; arg < pp->argc; arg++)
4841 if (pp->arg[arg].reg == NULL)
4844 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4845 && po->operand[1].type == OPT_CONST)
4847 if (po->flags & (OPF_RMD|OPF_DONE))
4849 if (po->operand[1].val != pp->argc_stack * 4)
4850 ferr(po, "unexpected esp adjust: %d\n",
4851 po->operand[1].val * 4);
4852 ferr_assert(po, pp->argc - arg == pp->argc_stack);
4853 return collect_call_args_no_push(i, pp, regmask_ffca);
4861 for (arg = 0; arg < pp->argc; arg++)
4862 if (pp->arg[arg].reg == NULL)
4865 for (j = i; j > 0 && arg < pp->argc; )
4869 if (ops[j].op == OP_PUSH)
4871 ops[j].p_argnext = -1;
4872 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4873 pp->arg[arg].datap = &ops[j];
4875 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
4876 *regmask |= 1 << ops[j].operand[0].reg;
4878 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4879 ops[j].flags &= ~OPF_RSAVE;
4882 for (arg++; arg < pp->argc; arg++)
4883 if (pp->arg[arg].reg == NULL)
4891 static int sync_argnum(struct parsed_op *po, int argnum)
4893 struct parsed_op *po_tmp;
4895 // see if other branches don't have higher argnum
4896 for (po_tmp = po; po_tmp != NULL; ) {
4897 if (argnum < po_tmp->p_argnum)
4898 argnum = po_tmp->p_argnum;
4899 // note: p_argnext is active on current collect_call_args only
4900 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4903 // make all argnums consistent
4904 for (po_tmp = po; po_tmp != NULL; ) {
4905 if (po_tmp->p_argnum != 0)
4906 po_tmp->p_argnum = argnum;
4907 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4913 static int collect_call_args_r(struct parsed_op *po, int i,
4914 struct parsed_proto *pp, int *regmask, int *arg_grp,
4915 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
4917 struct parsed_proto *pp_tmp;
4918 struct parsed_op *po_tmp;
4919 struct label_ref *lr;
4920 int need_to_save_current;
4921 int arg_grp_current = 0;
4922 int save_args_seen = 0;
4929 ferr(po, "dead label encountered\n");
4933 for (; arg < pp->argc; arg++, argnum++)
4934 if (pp->arg[arg].reg == NULL)
4936 magic = (magic & 0xffffff) | (arg << 24);
4938 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4940 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4941 if (ops[j].cc_scratch != magic) {
4942 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4946 // ok: have already been here
4949 ops[j].cc_scratch = magic;
4951 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4952 lr = &g_label_refs[j];
4953 if (lr->next != NULL)
4955 for (; lr->next; lr = lr->next) {
4956 check_i(&ops[j], lr->i);
4957 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4959 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4960 arg, argnum, magic, need_op_saving, may_reuse);
4965 check_i(&ops[j], lr->i);
4966 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4968 if (j > 0 && LAST_OP(j - 1)) {
4969 // follow last branch in reverse
4974 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4975 arg, argnum, magic, need_op_saving, may_reuse);
4981 if (ops[j].op == OP_CALL)
4983 if (pp->is_unresolved)
4988 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
4989 arg, pp->argc, ops[j].operand[0].name);
4990 if (may_reuse && pp_tmp->argc_stack > 0)
4991 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4992 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4994 // esp adjust of 0 means we collected it before
4995 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4996 && (ops[j].operand[1].type != OPT_CONST
4997 || ops[j].operand[1].val != 0))
4999 if (pp->is_unresolved)
5002 fnote(po, "(this call)\n");
5003 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5004 arg, pp->argc, ops[j].operand[1].val);
5006 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5008 if (pp->is_unresolved)
5011 fnote(po, "(this call)\n");
5012 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5014 else if (ops[j].flags & OPF_CJMP)
5016 if (pp->is_unresolved)
5021 else if (ops[j].op == OP_PUSH
5022 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5024 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5027 ops[j].p_argnext = -1;
5028 po_tmp = pp->arg[arg].datap;
5030 ops[j].p_argnext = po_tmp - ops;
5031 pp->arg[arg].datap = &ops[j];
5033 argnum = sync_argnum(&ops[j], argnum);
5035 need_to_save_current = 0;
5037 if (ops[j].operand[0].type == OPT_REG)
5038 reg = ops[j].operand[0].reg;
5040 if (!need_op_saving) {
5041 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5042 need_to_save_current = (ret >= 0);
5044 if (need_op_saving || need_to_save_current) {
5045 // mark this arg as one that needs operand saving
5046 pp->arg[arg].is_saved = 1;
5048 if (save_args_seen & (1 << (argnum - 1))) {
5051 if (arg_grp_current >= MAX_ARG_GRP)
5052 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5056 else if (ops[j].p_argnum == 0)
5057 ops[j].flags |= OPF_RMD;
5059 // some PUSHes are reused by different calls on other branches,
5060 // but that can't happen if we didn't branch, so they
5061 // can be removed from future searches (handles nested calls)
5063 ops[j].flags |= OPF_FARGNR;
5065 ops[j].flags |= OPF_FARG;
5066 ops[j].flags &= ~OPF_RSAVE;
5068 // check for __VALIST
5069 if (!pp->is_unresolved && g_func_pp != NULL
5070 && pp->arg[arg].type.is_va_list)
5073 ret = resolve_origin(j, &ops[j].operand[0],
5074 magic + 1, &k, NULL);
5075 if (ret == 1 && k >= 0)
5077 if (ops[k].op == OP_LEA) {
5078 if (!g_func_pp->is_vararg)
5079 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5082 snprintf(buf, sizeof(buf), "arg_%X",
5083 g_func_pp->argc_stack * 4);
5084 if (strstr(ops[k].operand[1].name, buf)
5085 || strstr(ops[k].operand[1].name, "arglist"))
5087 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5088 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5089 pp->arg[arg].is_saved = 0;
5093 ferr(&ops[k], "va_list arg detection failed\n");
5095 // check for va_list from g_func_pp arg too
5096 else if (ops[k].op == OP_MOV
5097 && is_stack_access(&ops[k], &ops[k].operand[1]))
5099 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5100 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5102 ops[k].flags |= OPF_RMD | OPF_DONE;
5103 ops[j].flags |= OPF_RMD;
5104 ops[j].p_argpass = ret + 1;
5105 pp->arg[arg].is_saved = 0;
5112 if (pp->arg[arg].is_saved) {
5113 ops[j].flags &= ~OPF_RMD;
5114 ops[j].p_argnum = argnum;
5117 // tracking reg usage
5119 *regmask |= 1 << reg;
5123 if (!pp->is_unresolved) {
5125 for (; arg < pp->argc; arg++, argnum++)
5126 if (pp->arg[arg].reg == NULL)
5129 magic = (magic & 0xffffff) | (arg << 24);
5132 if (ops[j].p_arggrp > arg_grp_current) {
5134 arg_grp_current = ops[j].p_arggrp;
5136 if (ops[j].p_argnum > 0)
5137 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5140 if (arg < pp->argc) {
5141 ferr(po, "arg collect failed for '%s': %d/%d\n",
5142 pp->name, arg, pp->argc);
5146 if (arg_grp_current > *arg_grp)
5147 *arg_grp = arg_grp_current;
5152 static int collect_call_args(struct parsed_op *po, int i,
5153 struct parsed_proto *pp, int *regmask, int magic)
5155 // arg group is for cases when pushes for
5156 // multiple funcs are going on
5157 struct parsed_op *po_tmp;
5162 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5168 // propagate arg_grp
5169 for (a = 0; a < pp->argc; a++) {
5170 if (pp->arg[a].reg != NULL)
5173 po_tmp = pp->arg[a].datap;
5174 while (po_tmp != NULL) {
5175 po_tmp->p_arggrp = arg_grp;
5176 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5181 if (pp->is_unresolved) {
5183 pp->argc_stack += ret;
5184 for (a = 0; a < pp->argc; a++)
5185 if (pp->arg[a].type.name == NULL)
5186 pp->arg[a].type.name = strdup("int");
5192 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5193 int regmask_now, int *regmask,
5194 int regmask_save_now, int *regmask_save,
5195 int *regmask_init, int regmask_arg)
5197 struct parsed_op *po;
5205 for (; i < opcnt; i++)
5208 if (cbits[i >> 3] & (1 << (i & 7)))
5210 cbits[i >> 3] |= (1 << (i & 7));
5212 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5213 if (po->flags & (OPF_RMD|OPF_DONE))
5215 if (po->btj != NULL) {
5216 for (j = 0; j < po->btj->count; j++) {
5217 check_i(po, po->btj->d[j].bt_i);
5218 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5219 regmask_now, regmask, regmask_save_now, regmask_save,
5220 regmask_init, regmask_arg);
5225 check_i(po, po->bt_i);
5226 if (po->flags & OPF_CJMP)
5227 reg_use_pass(po->bt_i, opcnt, cbits,
5228 regmask_now, regmask, regmask_save_now, regmask_save,
5229 regmask_init, regmask_arg);
5235 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5236 && !g_func_pp->is_userstack
5237 && po->operand[0].type == OPT_REG)
5239 reg = po->operand[0].reg;
5240 ferr_assert(po, reg >= 0);
5243 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5244 if (regmask_now & (1 << reg)) {
5245 already_saved = regmask_save_now & (1 << reg);
5246 flags_set = OPF_RSAVE | OPF_DONE;
5249 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5251 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5252 reg, 0, 0, flags_set);
5255 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5257 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5262 ferr_assert(po, !already_saved);
5263 po->flags |= flags_set;
5265 if (regmask_now & (1 << reg)) {
5266 regmask_save_now |= (1 << reg);
5267 *regmask_save |= regmask_save_now;
5272 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5273 reg = po->operand[0].reg;
5274 ferr_assert(po, reg >= 0);
5276 if (regmask_save_now & (1 << reg))
5277 regmask_save_now &= ~(1 << reg);
5279 regmask_now &= ~(1 << reg);
5282 else if (po->op == OP_CALL) {
5283 if ((po->regmask_dst & (1 << xAX))
5284 && !(po->regmask_dst & (1 << xDX)))
5286 if (po->flags & OPF_TAIL)
5287 // don't need eax, will do "return f();" or "f(); return;"
5288 po->regmask_dst &= ~(1 << xAX);
5290 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5292 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5295 po->regmask_dst &= ~(1 << xAX);
5299 // not "full stack" mode and have something in stack
5300 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5301 ferr(po, "float stack is not empty on func call\n");
5304 if (po->flags & OPF_NOREGS)
5307 // if incomplete register is used, clear it on init to avoid
5308 // later use of uninitialized upper part in some situations
5309 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5310 && po->operand[0].lmod != OPLM_DWORD)
5312 reg = po->operand[0].reg;
5313 ferr_assert(po, reg >= 0);
5315 if (!(regmask_now & (1 << reg)))
5316 *regmask_init |= 1 << reg;
5319 regmask_op = po->regmask_src | po->regmask_dst;
5321 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5322 regmask_new &= ~(1 << xSP);
5323 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5324 regmask_new &= ~(1 << xBP);
5326 if (regmask_new != 0)
5327 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5329 if (regmask_op & (1 << xBP)) {
5330 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5331 if (po->regmask_dst & (1 << xBP))
5332 // compiler decided to drop bp frame and use ebp as scratch
5333 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5335 regmask_op &= ~(1 << xBP);
5339 if (po->flags & OPF_FPUSH) {
5340 if (regmask_now & mxST1)
5341 regmask_now |= mxSTa; // switch to "full stack" mode
5342 if (regmask_now & mxSTa)
5343 po->flags |= OPF_FSHIFT;
5344 if (!(regmask_now & mxST7_2)) {
5346 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5350 regmask_now |= regmask_op;
5351 *regmask |= regmask_now;
5354 if (po->flags & OPF_FPOP) {
5355 if ((regmask_now & mxSTa) == 0)
5356 ferr(po, "float pop on empty stack?\n");
5357 if (regmask_now & (mxST7_2 | mxST1))
5358 po->flags |= OPF_FSHIFT;
5359 if (!(regmask_now & mxST7_2)) {
5361 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5365 if (po->flags & OPF_TAIL) {
5366 if (!(regmask_now & mxST7_2)) {
5367 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5368 if (!(regmask_now & mxST0))
5369 ferr(po, "no st0 on float return, mask: %x\n",
5372 else if (regmask_now & mxST1_0)
5373 ferr(po, "float regs on tail: %x\n", regmask_now);
5376 // there is support for "conditional tailcall", sort of
5377 if (!(po->flags & OPF_CC))
5383 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5387 for (i = 0; i < pp->argc; i++)
5388 if (pp->arg[i].reg == NULL)
5392 memmove(&pp->arg[i + 1], &pp->arg[i],
5393 sizeof(pp->arg[0]) * pp->argc_stack);
5394 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5395 pp->arg[i].reg = strdup(reg);
5396 pp->arg[i].type.name = strdup("int");
5401 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5402 int *pfomask, const char *dst_opr_text)
5404 if (*pfomask & (1 << PFO_Z)) {
5405 fprintf(fout, "\n cond_z = (%s%s == 0);",
5406 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5407 *pfomask &= ~(1 << PFO_Z);
5411 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5412 int *pfomask, const char *dst_opr_text)
5414 if (*pfomask & (1 << PFO_S)) {
5415 fprintf(fout, "\n cond_s = (%s%s < 0);",
5416 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5417 *pfomask &= ~(1 << PFO_S);
5421 static void output_std_flags(FILE *fout, struct parsed_op *po,
5422 int *pfomask, const char *dst_opr_text)
5424 output_std_flag_z(fout, po, pfomask, dst_opr_text);
5425 output_std_flag_s(fout, po, pfomask, dst_opr_text);
5429 OPP_FORCE_NORETURN = (1 << 0),
5430 OPP_SIMPLE_ARGS = (1 << 1),
5431 OPP_ALIGN = (1 << 2),
5434 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5437 const char *cconv = "";
5439 if (pp->is_fastcall)
5440 cconv = "__fastcall ";
5441 else if (pp->is_stdcall && pp->argc_reg == 0)
5442 cconv = "__stdcall ";
5444 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5446 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5447 fprintf(fout, "noreturn ");
5450 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5455 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5459 output_pp_attrs(fout, pp, flags);
5462 fprintf(fout, "%s", pp->name);
5467 for (i = 0; i < pp->argc; i++) {
5469 fprintf(fout, ", ");
5470 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5471 && !(flags & OPP_SIMPLE_ARGS))
5474 output_pp(fout, pp->arg[i].pp, 0);
5476 else if (pp->arg[i].type.is_retreg) {
5477 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5480 fprintf(fout, "%s", pp->arg[i].type.name);
5482 fprintf(fout, " a%d", i + 1);
5485 if (pp->arg[i].type.is_64bit)
5488 if (pp->is_vararg) {
5490 fprintf(fout, ", ");
5491 fprintf(fout, "...");
5496 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5502 snprintf(buf1, sizeof(buf1), "%d", grp);
5503 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5508 static void gen_x_cleanup(int opcnt);
5510 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5512 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5513 struct parsed_opr *last_arith_dst = NULL;
5514 char buf1[256], buf2[256], buf3[256], cast[64];
5515 struct parsed_proto *pp, *pp_tmp;
5516 struct parsed_data *pd;
5517 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5518 unsigned char cbits[MAX_OPS / 8];
5519 const char *float_type;
5520 const char *float_st0;
5521 const char *float_st1;
5522 int need_float_stack = 0;
5523 int need_float_sw = 0; // status word
5524 int need_tmp_var = 0;
5528 int label_pending = 0;
5529 int need_double = 0;
5530 int stack_align = 0;
5531 int stack_fsz_adj = 0;
5532 int regmask_save = 0; // used regs saved/restored in this func
5533 int regmask_arg; // regs from this function args (fastcall, etc)
5534 int regmask_ret; // regs needed on ret
5535 int regmask_now; // temp
5536 int regmask_init = 0; // regs that need zero initialization
5537 int regmask_pp = 0; // regs used in complex push-pop graph
5538 int regmask_ffca = 0; // float function call args
5539 int regmask = 0; // used regs
5549 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5550 g_stack_frame_used = 0;
5551 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5552 regmask_init = g_regmask_init;
5554 g_func_pp = proto_parse(fhdr, funcn, 0);
5555 if (g_func_pp == NULL)
5556 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5558 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5559 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5562 // - resolve all branches
5563 // - parse calls with labels
5564 resolve_branches_parse_calls(opcnt);
5567 // - handle ebp/esp frame, remove ops related to it
5568 scan_prologue_epilogue(opcnt, &stack_align);
5570 // handle a case where sf size is unalignment, but is
5571 // placed in a way that elements are still aligned
5572 if (g_stack_fsz & 4) {
5573 for (i = 0; i < g_eqcnt; i++) {
5574 if (g_eqs[i].lmod != OPLM_QWORD)
5576 if (!(g_eqs[i].offset & 4)) {
5585 // - remove dead labels
5586 // - set regs needed at ret
5587 for (i = 0; i < opcnt; i++)
5589 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5594 if (ops[i].op == OP_RET)
5595 ops[i].regmask_src |= regmask_ret;
5599 // - process trivial calls
5600 for (i = 0; i < opcnt; i++)
5603 if (po->flags & (OPF_RMD|OPF_DONE))
5606 if (po->op == OP_CALL)
5608 pp = process_call_early(i, opcnt, &j);
5610 if (!(po->flags & OPF_ATAIL)) {
5611 // since we know the args, try to collect them
5612 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5620 // commit esp adjust
5621 if (ops[j].op != OP_POP)
5622 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5624 for (l = 0; l < pp->argc_stack; l++)
5625 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5629 if (strstr(pp->ret_type.name, "int64"))
5632 po->flags |= OPF_DONE;
5638 // - process calls, stage 2
5639 // - handle some push/pop pairs
5640 // - scan for STD/CLD, propagate DF
5641 // - try to resolve needed x87 status word bits
5642 for (i = 0; i < opcnt; i++)
5647 if (po->flags & OPF_RMD)
5650 if (po->op == OP_CALL)
5652 if (!(po->flags & OPF_DONE)) {
5653 pp = process_call(i, opcnt);
5655 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5656 // since we know the args, collect them
5657 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5659 // for unresolved, collect after other passes
5663 ferr_assert(po, pp != NULL);
5665 po->regmask_src |= get_pp_arg_regmask_src(pp);
5666 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5668 if (po->regmask_dst & mxST0)
5669 po->flags |= OPF_FPUSH;
5671 if (strstr(pp->ret_type.name, "int64"))
5677 if (po->flags & OPF_DONE)
5682 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
5683 && po->operand[0].type == OPT_CONST)
5685 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5690 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5694 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5695 scan_propagate_df(i + 1, opcnt);
5700 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
5701 ferr(po, "TODO: fnstsw to mem\n");
5702 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
5704 ferr(po, "fnstsw resolve failed\n");
5705 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
5706 (void *)(long)(mask | (z_check << 16)));
5708 ferr(po, "failed to find fcom: %d\n", ret);
5717 // - find POPs for PUSHes, rm both
5718 // - scan for all used registers
5719 memset(cbits, 0, sizeof(cbits));
5720 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5721 0, ®mask_save, ®mask_init, regmask_arg);
5723 need_float_stack = !!(regmask & mxST7_2);
5726 // - find flag set ops for their users
5727 // - do unresolved calls
5728 // - declare indirect functions
5729 // - other op specific processing
5730 for (i = 0; i < opcnt; i++)
5733 if (po->flags & (OPF_RMD|OPF_DONE))
5736 if (po->flags & OPF_CC)
5738 int setters[16], cnt = 0, branched = 0;
5740 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
5741 &branched, setters, &cnt);
5742 if (ret < 0 || cnt <= 0)
5743 ferr(po, "unable to trace flag setter(s)\n");
5744 if (cnt > ARRAY_SIZE(setters))
5745 ferr(po, "too many flag setters\n");
5747 for (j = 0; j < cnt; j++)
5749 tmp_op = &ops[setters[j]]; // flag setter
5752 // to get nicer code, we try to delay test and cmp;
5753 // if we can't because of operand modification, or if we
5754 // have arith op, or branch, make it calculate flags explicitly
5755 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5757 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5758 pfomask = 1 << po->pfo;
5760 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5761 pfomask = 1 << po->pfo;
5764 // see if we'll be able to handle based on op result
5765 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5766 && po->pfo != PFO_Z && po->pfo != PFO_S
5767 && po->pfo != PFO_P)
5769 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5771 pfomask = 1 << po->pfo;
5774 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5775 propagate_lmod(tmp_op, &tmp_op->operand[0],
5776 &tmp_op->operand[1]);
5777 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5782 tmp_op->pfomask |= pfomask;
5783 cond_vars |= pfomask;
5785 // note: may overwrite, currently not a problem
5789 if (po->op == OP_RCL || po->op == OP_RCR
5790 || po->op == OP_ADC || po->op == OP_SBB)
5791 cond_vars |= 1 << PFO_C;
5797 cond_vars |= 1 << PFO_Z;
5801 if (po->operand[0].lmod == OPLM_DWORD)
5806 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
5811 // note: resolved non-reg calls are OPF_DONE already
5813 ferr_assert(po, pp != NULL);
5815 if (pp->is_unresolved) {
5816 int regmask_stack = 0;
5817 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5819 // this is pretty rough guess:
5820 // see ecx and edx were pushed (and not their saved versions)
5821 for (arg = 0; arg < pp->argc; arg++) {
5822 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
5825 tmp_op = pp->arg[arg].datap;
5827 ferr(po, "parsed_op missing for arg%d\n", arg);
5828 if (tmp_op->operand[0].type == OPT_REG)
5829 regmask_stack |= 1 << tmp_op->operand[0].reg;
5832 if (!((regmask_stack & (1 << xCX))
5833 && (regmask_stack & (1 << xDX))))
5835 if (pp->argc_stack != 0
5836 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5838 pp_insert_reg_arg(pp, "ecx");
5839 pp->is_fastcall = 1;
5840 regmask_init |= 1 << xCX;
5841 regmask |= 1 << xCX;
5843 if (pp->argc_stack != 0
5844 || ((regmask | regmask_arg) & (1 << xDX)))
5846 pp_insert_reg_arg(pp, "edx");
5847 regmask_init |= 1 << xDX;
5848 regmask |= 1 << xDX;
5852 // note: __cdecl doesn't fall into is_unresolved category
5853 if (pp->argc_stack > 0)
5859 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
5861 // <var> = offset <something>
5862 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5863 && !IS_START(po->operand[1].name, "off_"))
5865 if (!po->operand[0].pp->is_fptr)
5866 ferr(po, "%s not declared as fptr when it should be\n",
5867 po->operand[0].name);
5868 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5869 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5870 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5871 fnote(po, "var: %s\n", buf1);
5872 fnote(po, "func: %s\n", buf2);
5873 ferr(po, "^ mismatch\n");
5881 if (po->operand[0].lmod == OPLM_DWORD) {
5882 // 32bit division is common, look for it
5883 if (po->op == OP_DIV)
5884 ret = scan_for_reg_clear(i, xDX);
5886 ret = scan_for_cdq_edx(i);
5888 po->flags |= OPF_32BIT;
5897 po->flags |= OPF_RMD | OPF_DONE;
5907 if (po->operand[0].lmod == OPLM_QWORD)
5917 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5919 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5921 po->flags |= OPF_32BIT;
5929 // this might need it's own pass...
5930 if (po->op != OP_FST && po->p_argnum > 0)
5931 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
5933 // correct for "full stack" mode late enable
5934 if ((po->flags & (OPF_PPUSH|OPF_FPOP)) && need_float_stack)
5935 po->flags |= OPF_FSHIFT;
5938 float_type = need_double ? "double" : "float";
5939 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
5940 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
5942 // output starts here
5944 // define userstack size
5945 if (g_func_pp->is_userstack) {
5946 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5947 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5948 fprintf(fout, "#endif\n");
5951 // the function itself
5952 ferr_assert(ops, !g_func_pp->is_fptr);
5953 output_pp(fout, g_func_pp,
5954 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5955 fprintf(fout, "\n{\n");
5957 // declare indirect functions
5958 for (i = 0; i < opcnt; i++) {
5960 if (po->flags & OPF_RMD)
5963 if (po->op == OP_CALL) {
5966 ferr(po, "NULL pp\n");
5968 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5969 if (pp->name[0] != 0) {
5970 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5971 memcpy(pp->name, "i_", 2);
5973 // might be declared already
5975 for (j = 0; j < i; j++) {
5976 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5977 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5987 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5990 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5991 fprintf(fout, ";\n");
5996 // output LUTs/jumptables
5997 for (i = 0; i < g_func_pd_cnt; i++) {
5999 fprintf(fout, " static const ");
6000 if (pd->type == OPT_OFFSET) {
6001 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6003 for (j = 0; j < pd->count; j++) {
6005 fprintf(fout, ", ");
6006 fprintf(fout, "&&%s", pd->d[j].u.label);
6010 fprintf(fout, "%s %s[] =\n { ",
6011 lmod_type_u(ops, pd->lmod), pd->label);
6013 for (j = 0; j < pd->count; j++) {
6015 fprintf(fout, ", ");
6016 fprintf(fout, "%u", pd->d[j].u.val);
6019 fprintf(fout, " };\n");
6023 // declare stack frame, va_arg
6026 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6028 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6029 if (g_func_lmods & (1 << OPLM_WORD))
6030 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6031 if (g_func_lmods & (1 << OPLM_BYTE))
6032 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6033 if (g_func_lmods & (1 << OPLM_QWORD))
6034 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6036 if (stack_align > 8)
6037 ferr(ops, "unhandled stack align of %d\n", stack_align);
6038 else if (stack_align == 8)
6039 fprintf(fout, " u64 align;");
6040 fprintf(fout, " } sf;\n");
6044 if (g_func_pp->is_userstack) {
6045 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6046 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6050 if (g_func_pp->is_vararg) {
6051 fprintf(fout, " va_list ap;\n");
6055 // declare arg-registers
6056 for (i = 0; i < g_func_pp->argc; i++) {
6057 if (g_func_pp->arg[i].reg != NULL) {
6058 reg = char_array_i(regs_r32,
6059 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6060 if (regmask & (1 << reg)) {
6061 if (g_func_pp->arg[i].type.is_retreg)
6062 fprintf(fout, " u32 %s = *r_%s;\n",
6063 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6065 fprintf(fout, " u32 %s = (u32)a%d;\n",
6066 g_func_pp->arg[i].reg, i + 1);
6069 if (g_func_pp->arg[i].type.is_retreg)
6070 ferr(ops, "retreg '%s' is unused?\n",
6071 g_func_pp->arg[i].reg);
6072 fprintf(fout, " // %s = a%d; // unused\n",
6073 g_func_pp->arg[i].reg, i + 1);
6079 // declare normal registers
6080 regmask_now = regmask & ~regmask_arg;
6081 regmask_now &= ~(1 << xSP);
6082 if (regmask_now & 0x00ff) {
6083 for (reg = 0; reg < 8; reg++) {
6084 if (regmask_now & (1 << reg)) {
6085 fprintf(fout, " u32 %s", regs_r32[reg]);
6086 if (regmask_init & (1 << reg))
6087 fprintf(fout, " = 0");
6088 fprintf(fout, ";\n");
6094 if (regmask_now & 0xff00) {
6095 for (reg = 8; reg < 16; reg++) {
6096 if (regmask_now & (1 << reg)) {
6097 fprintf(fout, " mmxr %s", regs_r32[reg]);
6098 if (regmask_init & (1 << reg))
6099 fprintf(fout, " = { 0, }");
6100 fprintf(fout, ";\n");
6106 if (need_float_stack) {
6107 fprintf(fout, " %s f_st[8];\n", float_type);
6108 fprintf(fout, " int f_stp = 0;\n");
6112 if (regmask_now & 0xff0000) {
6113 for (reg = 16; reg < 24; reg++) {
6114 if (regmask_now & (1 << reg)) {
6115 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6116 if (regmask_init & (1 << reg))
6117 fprintf(fout, " = 0");
6118 fprintf(fout, ";\n");
6125 if (need_float_sw) {
6126 fprintf(fout, " u16 f_sw;\n");
6131 for (reg = 0; reg < 8; reg++) {
6132 if (regmask_save & (1 << reg)) {
6133 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6139 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6140 if (save_arg_vars[i] == 0)
6142 for (reg = 0; reg < 32; reg++) {
6143 if (save_arg_vars[i] & (1 << reg)) {
6144 fprintf(fout, " u32 %s;\n",
6145 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6152 for (reg = 0; reg < 32; reg++) {
6153 if (regmask_ffca & (1 << reg)) {
6154 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6160 // declare push-pop temporaries
6162 for (reg = 0; reg < 8; reg++) {
6163 if (regmask_pp & (1 << reg)) {
6164 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6171 for (i = 0; i < 8; i++) {
6172 if (cond_vars & (1 << i)) {
6173 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6180 fprintf(fout, " u32 tmp;\n");
6185 fprintf(fout, " u64 tmp64;\n");
6190 fprintf(fout, "\n");
6192 // do stack clear, if needed
6193 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6195 if (g_stack_clear_len != 0) {
6196 if (g_stack_clear_len <= 4) {
6197 for (i = 0; i < g_stack_clear_len; i++)
6198 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6199 fprintf(fout, "0;\n");
6202 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6203 g_stack_clear_start, g_stack_clear_len * 4);
6207 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6210 if (g_func_pp->is_vararg) {
6211 if (g_func_pp->argc_stack == 0)
6212 ferr(ops, "vararg func without stack args?\n");
6213 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6217 for (i = 0; i < opcnt; i++)
6219 if (g_labels[i] != NULL) {
6220 fprintf(fout, "\n%s:\n", g_labels[i]);
6223 delayed_flag_op = NULL;
6224 last_arith_dst = NULL;
6228 if (po->flags & OPF_RMD)
6233 #define assert_operand_cnt(n_) \
6234 if (po->operand_cnt != n_) \
6235 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6237 // conditional/flag using op?
6238 if (po->flags & OPF_CC)
6244 // we go through all this trouble to avoid using parsed_flag_op,
6245 // which makes generated code much nicer
6246 if (delayed_flag_op != NULL)
6248 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6249 po->pfo, po->pfo_inv);
6252 else if (last_arith_dst != NULL
6253 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6254 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6257 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6258 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6259 last_arith_dst->lmod, buf3);
6262 else if (tmp_op != NULL) {
6263 // use preprocessed flag calc results
6264 if (!(tmp_op->pfomask & (1 << po->pfo)))
6265 ferr(po, "not prepared for pfo %d\n", po->pfo);
6267 // note: pfo_inv was not yet applied
6268 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6269 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6272 ferr(po, "all methods of finding comparison failed\n");
6275 if (po->flags & OPF_JMP) {
6276 fprintf(fout, " if %s", buf1);
6278 else if (po->op == OP_RCL || po->op == OP_RCR
6279 || po->op == OP_ADC || po->op == OP_SBB)
6282 fprintf(fout, " cond_%s = %s;\n",
6283 parsed_flag_op_names[po->pfo], buf1);
6285 else if (po->flags & OPF_DATA) { // SETcc
6286 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6287 fprintf(fout, " %s = %s;", buf2, buf1);
6290 ferr(po, "unhandled conditional op\n");
6294 pfomask = po->pfomask;
6299 assert_operand_cnt(2);
6300 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6301 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6302 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6303 fprintf(fout, " %s = %s;", buf1,
6304 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6309 assert_operand_cnt(2);
6310 po->operand[1].lmod = OPLM_DWORD; // always
6311 fprintf(fout, " %s = %s;",
6312 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6313 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6318 assert_operand_cnt(2);
6319 fprintf(fout, " %s = %s;",
6320 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6321 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6325 assert_operand_cnt(2);
6326 switch (po->operand[1].lmod) {
6328 strcpy(buf3, "(s8)");
6331 strcpy(buf3, "(s16)");
6334 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6336 fprintf(fout, " %s = %s;",
6337 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6338 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6343 assert_operand_cnt(2);
6344 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6345 fprintf(fout, " tmp = %s;",
6346 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6347 fprintf(fout, " %s = %s;",
6348 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6349 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6350 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6351 fprintf(fout, " %s = %stmp;",
6352 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6353 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6354 snprintf(g_comment, sizeof(g_comment), "xchg");
6358 assert_operand_cnt(1);
6359 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6360 fprintf(fout, " %s = ~%s;", buf1, buf1);
6364 assert_operand_cnt(2);
6365 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6366 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6367 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6368 strcpy(g_comment, "xlat");
6372 assert_operand_cnt(2);
6373 fprintf(fout, " %s = (s32)%s >> 31;",
6374 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6375 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6376 strcpy(g_comment, "cdq");
6380 assert_operand_cnt(1);
6381 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6382 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6386 if (po->flags & OPF_REP) {
6387 assert_operand_cnt(3);
6392 assert_operand_cnt(2);
6393 fprintf(fout, " %s = %sesi; esi %c= %d;",
6394 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6395 lmod_cast_u_ptr(po, po->operand[1].lmod),
6396 (po->flags & OPF_DF) ? '-' : '+',
6397 lmod_bytes(po, po->operand[1].lmod));
6398 strcpy(g_comment, "lods");
6403 if (po->flags & OPF_REP) {
6404 assert_operand_cnt(3);
6405 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6406 (po->flags & OPF_DF) ? '-' : '+',
6407 lmod_bytes(po, po->operand[1].lmod));
6408 fprintf(fout, " %sedi = eax;",
6409 lmod_cast_u_ptr(po, po->operand[1].lmod));
6410 strcpy(g_comment, "rep stos");
6413 assert_operand_cnt(2);
6414 fprintf(fout, " %sedi = eax; edi %c= %d;",
6415 lmod_cast_u_ptr(po, po->operand[1].lmod),
6416 (po->flags & OPF_DF) ? '-' : '+',
6417 lmod_bytes(po, po->operand[1].lmod));
6418 strcpy(g_comment, "stos");
6423 j = lmod_bytes(po, po->operand[0].lmod);
6424 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6425 l = (po->flags & OPF_DF) ? '-' : '+';
6426 if (po->flags & OPF_REP) {
6427 assert_operand_cnt(3);
6429 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6432 " %sedi = %sesi;", buf1, buf1);
6433 strcpy(g_comment, "rep movs");
6436 assert_operand_cnt(2);
6437 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6438 buf1, buf1, l, j, l, j);
6439 strcpy(g_comment, "movs");
6444 // repe ~ repeat while ZF=1
6445 j = lmod_bytes(po, po->operand[0].lmod);
6446 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6447 l = (po->flags & OPF_DF) ? '-' : '+';
6448 if (po->flags & OPF_REP) {
6449 assert_operand_cnt(3);
6451 " while (ecx != 0) {\n");
6452 if (pfomask & (1 << PFO_C)) {
6455 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6456 pfomask &= ~(1 << PFO_C);
6459 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6460 buf1, buf1, l, j, l, j);
6463 " if (cond_z %s 0) break;\n",
6464 (po->flags & OPF_REPZ) ? "==" : "!=");
6467 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6468 (po->flags & OPF_REPZ) ? "e" : "ne");
6471 assert_operand_cnt(2);
6473 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6474 buf1, buf1, l, j, l, j);
6475 strcpy(g_comment, "cmps");
6477 pfomask &= ~(1 << PFO_Z);
6478 last_arith_dst = NULL;
6479 delayed_flag_op = NULL;
6483 // only does ZF (for now)
6484 // repe ~ repeat while ZF=1
6485 j = lmod_bytes(po, po->operand[1].lmod);
6486 l = (po->flags & OPF_DF) ? '-' : '+';
6487 if (po->flags & OPF_REP) {
6488 assert_operand_cnt(3);
6490 " while (ecx != 0) {\n");
6492 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6493 lmod_cast_u(po, po->operand[1].lmod),
6494 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6497 " if (cond_z %s 0) break;\n",
6498 (po->flags & OPF_REPZ) ? "==" : "!=");
6501 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6502 (po->flags & OPF_REPZ) ? "e" : "ne");
6505 assert_operand_cnt(2);
6506 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6507 lmod_cast_u(po, po->operand[1].lmod),
6508 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6509 strcpy(g_comment, "scas");
6511 pfomask &= ~(1 << PFO_Z);
6512 last_arith_dst = NULL;
6513 delayed_flag_op = NULL;
6516 // arithmetic w/flags
6518 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6519 goto dualop_arith_const;
6520 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6524 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6525 if (po->operand[1].type == OPT_CONST) {
6526 j = lmod_bytes(po, po->operand[0].lmod);
6527 if (((1ull << j * 8) - 1) == po->operand[1].val)
6528 goto dualop_arith_const;
6533 assert_operand_cnt(2);
6534 fprintf(fout, " %s %s= %s;",
6535 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6537 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6538 output_std_flags(fout, po, &pfomask, buf1);
6539 last_arith_dst = &po->operand[0];
6540 delayed_flag_op = NULL;
6544 // and 0, or ~0 used instead mov
6545 assert_operand_cnt(2);
6546 fprintf(fout, " %s = %s;",
6547 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6548 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6549 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6550 output_std_flags(fout, po, &pfomask, buf1);
6551 last_arith_dst = &po->operand[0];
6552 delayed_flag_op = NULL;
6557 assert_operand_cnt(2);
6558 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6559 if (pfomask & (1 << PFO_C)) {
6560 if (po->operand[1].type == OPT_CONST) {
6561 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6562 j = po->operand[1].val;
6565 if (po->op == OP_SHL)
6569 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6573 ferr(po, "zero shift?\n");
6577 pfomask &= ~(1 << PFO_C);
6579 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6580 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6581 if (po->operand[1].type != OPT_CONST)
6582 fprintf(fout, " & 0x1f");
6584 output_std_flags(fout, po, &pfomask, buf1);
6585 last_arith_dst = &po->operand[0];
6586 delayed_flag_op = NULL;
6590 assert_operand_cnt(2);
6591 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6592 fprintf(fout, " %s = %s%s >> %s;", buf1,
6593 lmod_cast_s(po, po->operand[0].lmod), buf1,
6594 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6595 output_std_flags(fout, po, &pfomask, buf1);
6596 last_arith_dst = &po->operand[0];
6597 delayed_flag_op = NULL;
6602 assert_operand_cnt(3);
6603 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6604 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6605 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6606 if (po->operand[2].type != OPT_CONST) {
6607 // no handling for "undefined" case, hopefully not needed
6608 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6611 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6612 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6613 if (po->op == OP_SHLD) {
6614 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6615 buf1, buf3, buf1, buf2, l, buf3);
6616 strcpy(g_comment, "shld");
6619 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6620 buf1, buf3, buf1, buf2, l, buf3);
6621 strcpy(g_comment, "shrd");
6623 output_std_flags(fout, po, &pfomask, buf1);
6624 last_arith_dst = &po->operand[0];
6625 delayed_flag_op = NULL;
6630 assert_operand_cnt(2);
6631 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6632 if (po->operand[1].type == OPT_CONST) {
6633 j = po->operand[1].val;
6634 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6635 fprintf(fout, po->op == OP_ROL ?
6636 " %s = (%s << %d) | (%s >> %d);" :
6637 " %s = (%s >> %d) | (%s << %d);",
6638 buf1, buf1, j, buf1,
6639 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6643 output_std_flags(fout, po, &pfomask, buf1);
6644 last_arith_dst = &po->operand[0];
6645 delayed_flag_op = NULL;
6650 assert_operand_cnt(2);
6651 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6652 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6653 if (po->operand[1].type == OPT_CONST) {
6654 j = po->operand[1].val % l;
6656 ferr(po, "zero rotate\n");
6657 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6658 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6659 if (po->op == OP_RCL) {
6661 " %s = (%s << %d) | (cond_c << %d)",
6662 buf1, buf1, j, j - 1);
6664 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6668 " %s = (%s >> %d) | (cond_c << %d)",
6669 buf1, buf1, j, l - j);
6671 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6673 fprintf(fout, ";\n");
6674 fprintf(fout, " cond_c = tmp;");
6678 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6679 output_std_flags(fout, po, &pfomask, buf1);
6680 last_arith_dst = &po->operand[0];
6681 delayed_flag_op = NULL;
6685 assert_operand_cnt(2);
6686 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6687 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6688 // special case for XOR
6689 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
6690 for (j = 0; j <= PFO_LE; j++) {
6691 if (pfomask & (1 << j)) {
6692 fprintf(fout, " cond_%s = %d;\n",
6693 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
6694 pfomask &= ~(1 << j);
6697 fprintf(fout, " %s = 0;",
6698 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6699 last_arith_dst = &po->operand[0];
6700 delayed_flag_op = NULL;
6706 assert_operand_cnt(2);
6707 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6708 if (pfomask & (1 << PFO_C)) {
6709 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6710 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6711 if (po->operand[0].lmod == OPLM_DWORD) {
6712 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6713 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6714 fprintf(fout, " %s = (u32)tmp64;",
6715 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6716 strcat(g_comment, " add64");
6719 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6720 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6721 fprintf(fout, " %s += %s;",
6722 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6725 pfomask &= ~(1 << PFO_C);
6726 output_std_flags(fout, po, &pfomask, buf1);
6727 last_arith_dst = &po->operand[0];
6728 delayed_flag_op = NULL;
6731 if (pfomask & (1 << PFO_LE)) {
6732 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
6733 fprintf(fout, " cond_%s = %s;\n",
6734 parsed_flag_op_names[PFO_LE], buf1);
6735 pfomask &= ~(1 << PFO_LE);
6740 assert_operand_cnt(2);
6741 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6742 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6743 for (j = 0; j <= PFO_LE; j++) {
6744 if (!(pfomask & (1 << j)))
6746 if (j == PFO_Z || j == PFO_S)
6749 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6750 fprintf(fout, " cond_%s = %s;\n",
6751 parsed_flag_op_names[j], buf1);
6752 pfomask &= ~(1 << j);
6759 assert_operand_cnt(2);
6760 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6761 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6762 if (po->op == OP_SBB
6763 && IS(po->operand[0].name, po->operand[1].name))
6765 // avoid use of unitialized var
6766 fprintf(fout, " %s = -cond_c;", buf1);
6767 // carry remains what it was
6768 pfomask &= ~(1 << PFO_C);
6771 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6772 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6774 output_std_flags(fout, po, &pfomask, buf1);
6775 last_arith_dst = &po->operand[0];
6776 delayed_flag_op = NULL;
6781 // on SKL, if src is 0, dst is left unchanged
6782 assert_operand_cnt(2);
6783 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6784 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6785 output_std_flag_z(fout, po, &pfomask, buf2);
6786 if (po->op == OP_BSF)
6787 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
6789 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
6790 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
6791 last_arith_dst = &po->operand[0];
6792 delayed_flag_op = NULL;
6793 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
6797 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6798 for (j = 0; j <= PFO_LE; j++) {
6799 if (!(pfomask & (1 << j)))
6801 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6804 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6805 fprintf(fout, " cond_%s = %s;\n",
6806 parsed_flag_op_names[j], buf1);
6807 pfomask &= ~(1 << j);
6813 if (pfomask & (1 << PFO_C))
6814 // carry is unaffected by inc/dec.. wtf?
6815 ferr(po, "carry propagation needed\n");
6817 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6818 if (po->operand[0].type == OPT_REG) {
6819 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6820 fprintf(fout, " %s%s;", buf1, buf2);
6823 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6824 fprintf(fout, " %s %s= 1;", buf1, buf2);
6826 output_std_flags(fout, po, &pfomask, buf1);
6827 last_arith_dst = &po->operand[0];
6828 delayed_flag_op = NULL;
6832 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6833 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6834 fprintf(fout, " %s = -%s%s;", buf1,
6835 lmod_cast_s(po, po->operand[0].lmod), buf2);
6836 last_arith_dst = &po->operand[0];
6837 delayed_flag_op = NULL;
6838 if (pfomask & PFOB_C) {
6839 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6842 output_std_flags(fout, po, &pfomask, buf1);
6846 if (po->operand_cnt == 2) {
6847 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6850 if (po->operand_cnt == 3)
6851 ferr(po, "TODO imul3\n");
6854 assert_operand_cnt(1);
6855 switch (po->operand[0].lmod) {
6857 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6858 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6859 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6860 fprintf(fout, " edx = tmp64 >> 32;\n");
6861 fprintf(fout, " eax = tmp64;");
6864 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6865 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6866 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6870 ferr(po, "TODO: unhandled mul type\n");
6873 last_arith_dst = NULL;
6874 delayed_flag_op = NULL;
6879 assert_operand_cnt(1);
6880 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6881 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6882 po->op == OP_IDIV));
6883 switch (po->operand[0].lmod) {
6885 if (po->flags & OPF_32BIT)
6886 snprintf(buf2, sizeof(buf2), "%seax", cast);
6888 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6889 snprintf(buf2, sizeof(buf2), "%stmp64",
6890 (po->op == OP_IDIV) ? "(s64)" : "");
6892 if (po->operand[0].type == OPT_REG
6893 && po->operand[0].reg == xDX)
6895 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6896 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6899 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6900 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6904 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6905 snprintf(buf2, sizeof(buf2), "%stmp",
6906 (po->op == OP_IDIV) ? "(s32)" : "");
6907 if (po->operand[0].type == OPT_REG
6908 && po->operand[0].reg == xDX)
6910 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6912 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6916 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6918 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6921 strcat(g_comment, " div16");
6924 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6926 last_arith_dst = NULL;
6927 delayed_flag_op = NULL;
6932 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6934 for (j = 0; j < 8; j++) {
6935 if (pfomask & (1 << j)) {
6936 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6937 fprintf(fout, " cond_%s = %s;",
6938 parsed_flag_op_names[j], buf1);
6945 last_arith_dst = NULL;
6946 delayed_flag_op = po;
6950 // SETcc - should already be handled
6953 // note: we reuse OP_Jcc for SETcc, only flags differ
6955 fprintf(fout, "\n goto %s;", po->operand[0].name);
6959 fprintf(fout, " if (ecx == 0)\n");
6960 fprintf(fout, " goto %s;", po->operand[0].name);
6961 strcat(g_comment, " jecxz");
6965 fprintf(fout, " if (--ecx != 0)\n");
6966 fprintf(fout, " goto %s;", po->operand[0].name);
6967 strcat(g_comment, " loop");
6971 assert_operand_cnt(1);
6972 last_arith_dst = NULL;
6973 delayed_flag_op = NULL;
6975 if (po->operand[0].type == OPT_REGMEM) {
6976 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6979 ferr(po, "parse failure for jmp '%s'\n",
6980 po->operand[0].name);
6981 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6984 else if (po->operand[0].type != OPT_LABEL)
6985 ferr(po, "unhandled jmp type\n");
6987 fprintf(fout, " goto %s;", po->operand[0].name);
6991 assert_operand_cnt(1);
6993 my_assert_not(pp, NULL);
6996 if (po->flags & OPF_CC) {
6997 // we treat conditional branch to another func
6998 // (yes such code exists..) as conditional tailcall
7000 fprintf(fout, " {\n");
7003 if (pp->is_fptr && !pp->is_arg) {
7004 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7005 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7007 if (pp->is_unresolved)
7008 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7009 buf3, asmfn, po->asmln, pp->name);
7012 fprintf(fout, "%s", buf3);
7013 if (strstr(pp->ret_type.name, "int64")) {
7014 if (po->flags & OPF_TAIL)
7015 ferr(po, "int64 and tail?\n");
7016 fprintf(fout, "tmp64 = ");
7018 else if (!IS(pp->ret_type.name, "void")) {
7019 if (po->flags & OPF_TAIL) {
7020 if (regmask_ret & mxAX) {
7021 fprintf(fout, "return ");
7022 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7023 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7025 else if (regmask_ret & mxST0)
7026 ferr(po, "float tailcall\n");
7028 else if (po->regmask_dst & mxAX) {
7029 fprintf(fout, "eax = ");
7030 if (pp->ret_type.is_ptr)
7031 fprintf(fout, "(u32)");
7033 else if (po->regmask_dst & mxST0) {
7034 ferr_assert(po, po->flags & OPF_FPUSH);
7035 if (need_float_stack)
7036 fprintf(fout, "f_st[--f_stp & 7] = ");
7038 fprintf(fout, "f_st0 = ");
7042 if (pp->name[0] == 0)
7043 ferr(po, "missing pp->name\n");
7044 fprintf(fout, "%s%s(", pp->name,
7045 pp->has_structarg ? "_sa" : "");
7047 if (po->flags & OPF_ATAIL) {
7049 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7050 check_compat |= pp->argc_stack > 0;
7052 && (pp->argc_stack != g_func_pp->argc_stack
7053 || pp->is_stdcall != g_func_pp->is_stdcall))
7054 ferr(po, "incompatible arg-reuse tailcall\n");
7055 if (g_func_pp->has_retreg)
7056 ferr(po, "TODO: retreg+tailcall\n");
7058 for (arg = j = 0; arg < pp->argc; arg++) {
7060 fprintf(fout, ", ");
7063 if (pp->arg[arg].type.is_ptr)
7064 snprintf(cast, sizeof(cast), "(%s)",
7065 pp->arg[arg].type.name);
7067 if (pp->arg[arg].reg != NULL) {
7068 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7072 for (; j < g_func_pp->argc; j++)
7073 if (g_func_pp->arg[j].reg == NULL)
7075 fprintf(fout, "%sa%d", cast, j + 1);
7080 for (arg = 0; arg < pp->argc; arg++) {
7082 fprintf(fout, ", ");
7085 if (pp->arg[arg].type.is_ptr)
7086 snprintf(cast, sizeof(cast), "(%s)",
7087 pp->arg[arg].type.name);
7089 if (pp->arg[arg].reg != NULL) {
7090 if (pp->arg[arg].type.is_retreg)
7091 fprintf(fout, "&%s", pp->arg[arg].reg);
7092 else if (IS(pp->arg[arg].reg, "ebp")
7093 && g_bp_frame && !(po->flags & OPF_EBP_S))
7095 // rare special case
7096 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7097 strcat(g_comment, " bp_ref");
7100 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7105 tmp_op = pp->arg[arg].datap;
7107 ferr(po, "parsed_op missing for arg%d\n", arg);
7109 if (tmp_op->flags & OPF_VAPUSH) {
7110 fprintf(fout, "ap");
7112 else if (tmp_op->op == OP_FST) {
7113 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7114 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7117 else if (tmp_op->p_argpass != 0) {
7118 fprintf(fout, "a%d", tmp_op->p_argpass);
7120 else if (pp->arg[arg].is_saved) {
7121 ferr_assert(po, tmp_op->p_argnum > 0);
7122 fprintf(fout, "%s%s", cast,
7123 saved_arg_name(buf1, sizeof(buf1),
7124 tmp_op->p_arggrp, tmp_op->p_argnum));
7128 out_src_opr(buf1, sizeof(buf1),
7129 tmp_op, &tmp_op->operand[0], cast, 0));
7133 fprintf(fout, ");");
7135 if (strstr(pp->ret_type.name, "int64")) {
7136 fprintf(fout, "\n");
7137 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7138 fprintf(fout, "%seax = tmp64;", buf3);
7141 if (pp->is_unresolved) {
7142 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7144 strcat(g_comment, buf2);
7147 if (po->flags & OPF_TAIL) {
7149 if (i == opcnt - 1 || pp->is_noreturn)
7151 else if (IS(pp->ret_type.name, "void"))
7153 else if (!(regmask_ret & (1 << xAX)))
7155 // else already handled as 'return f()'
7158 fprintf(fout, "\n%sreturn;", buf3);
7159 strcat(g_comment, " ^ tailcall");
7162 strcat(g_comment, " tailcall");
7164 if ((regmask_ret & (1 << xAX))
7165 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7167 ferr(po, "int func -> void func tailcall?\n");
7170 if (pp->is_noreturn)
7171 strcat(g_comment, " noreturn");
7172 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7173 strcat(g_comment, " argframe");
7174 if (po->flags & OPF_CC)
7175 strcat(g_comment, " cond");
7177 if (po->flags & OPF_CC)
7178 fprintf(fout, "\n }");
7180 delayed_flag_op = NULL;
7181 last_arith_dst = NULL;
7185 if (g_func_pp->is_vararg)
7186 fprintf(fout, " va_end(ap);\n");
7187 if (g_func_pp->has_retreg) {
7188 for (arg = 0; arg < g_func_pp->argc; arg++)
7189 if (g_func_pp->arg[arg].type.is_retreg)
7190 fprintf(fout, " *r_%s = %s;\n",
7191 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7194 if (regmask_ret & mxST0) {
7195 fprintf(fout, " return %s;", float_st0);
7197 else if (!(regmask_ret & mxAX)) {
7198 if (i != opcnt - 1 || label_pending)
7199 fprintf(fout, " return;");
7201 else if (g_func_pp->ret_type.is_ptr) {
7202 fprintf(fout, " return (%s)eax;",
7203 g_func_pp->ret_type.name);
7205 else if (IS(g_func_pp->ret_type.name, "__int64"))
7206 fprintf(fout, " return ((u64)edx << 32) | eax;");
7208 fprintf(fout, " return eax;");
7210 last_arith_dst = NULL;
7211 delayed_flag_op = NULL;
7215 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7216 if (po->p_argnum != 0) {
7217 // special case - saved func arg
7218 fprintf(fout, " %s = %s;",
7219 saved_arg_name(buf2, sizeof(buf2),
7220 po->p_arggrp, po->p_argnum), buf1);
7223 else if (po->flags & OPF_RSAVE) {
7224 fprintf(fout, " s_%s = %s;", buf1, buf1);
7227 else if (po->flags & OPF_PPUSH) {
7229 ferr_assert(po, tmp_op != NULL);
7230 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7231 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7234 else if (g_func_pp->is_userstack) {
7235 fprintf(fout, " *(--esp) = %s;", buf1);
7238 if (!(g_ida_func_attr & IDAFA_NORETURN))
7239 ferr(po, "stray push encountered\n");
7244 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7245 if (po->flags & OPF_RSAVE) {
7246 fprintf(fout, " %s = s_%s;", buf1, buf1);
7249 else if (po->flags & OPF_PPUSH) {
7250 // push/pop graph / non-const
7251 ferr_assert(po, po->datap == NULL);
7252 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7255 else if (po->datap != NULL) {
7258 fprintf(fout, " %s = %s;", buf1,
7259 out_src_opr(buf2, sizeof(buf2),
7260 tmp_op, &tmp_op->operand[0],
7261 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7264 else if (g_func_pp->is_userstack) {
7265 fprintf(fout, " %s = *esp++;", buf1);
7269 ferr(po, "stray pop encountered\n");
7279 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7280 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7281 po->op == OPP_ALLSHL ? "<<" : ">>");
7282 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7283 strcat(g_comment, po->op == OPP_ALLSHL
7284 ? " allshl" : " allshr");
7289 if (need_float_stack) {
7290 out_src_opr_float(buf1, sizeof(buf1),
7291 po, &po->operand[0], 1);
7292 if (po->regmask_src & mxSTa) {
7293 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7297 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7300 if (po->flags & OPF_FSHIFT)
7301 fprintf(fout, " f_st1 = f_st0;");
7302 if (po->operand[0].type == OPT_REG
7303 && po->operand[0].reg == xST0)
7305 strcat(g_comment, " fld st");
7308 fprintf(fout, " f_st0 = %s;",
7309 out_src_opr_float(buf1, sizeof(buf1),
7310 po, &po->operand[0], 0));
7312 strcat(g_comment, " fld");
7316 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7317 lmod_cast(po, po->operand[0].lmod, 1), 0);
7318 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7319 if (need_float_stack) {
7320 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7323 if (po->flags & OPF_FSHIFT)
7324 fprintf(fout, " f_st1 = f_st0;");
7325 fprintf(fout, " f_st0 = %s;", buf2);
7327 strcat(g_comment, " fild");
7331 if (need_float_stack)
7332 fprintf(fout, " f_st[--f_stp & 7] = ");
7334 if (po->flags & OPF_FSHIFT)
7335 fprintf(fout, " f_st1 = f_st0;");
7336 fprintf(fout, " f_st0 = ");
7338 switch (po->operand[0].val) {
7339 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7340 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
7341 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7342 default: ferr(po, "TODO\n"); break;
7347 if (po->flags & OPF_FARG) {
7348 // store to stack as func arg
7349 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7353 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7355 dead_dst = po->operand[0].type == OPT_REG
7356 && po->operand[0].reg == xST0;
7359 fprintf(fout, " %s = %s;", buf1, float_st0);
7360 if (po->flags & OPF_FSHIFT) {
7361 if (need_float_stack)
7362 fprintf(fout, " f_stp++;");
7364 fprintf(fout, " f_st0 = f_st1;");
7366 if (dead_dst && !(po->flags & OPF_FSHIFT))
7369 strcat(g_comment, " fst");
7373 fprintf(fout, " %s = %s%s;",
7374 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7375 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7376 if (po->flags & OPF_FSHIFT) {
7377 if (need_float_stack)
7378 fprintf(fout, " f_stp++;");
7380 fprintf(fout, " f_st0 = f_st1;");
7382 strcat(g_comment, " fist");
7389 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7391 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7393 dead_dst = (po->flags & OPF_FPOP)
7394 && po->operand[0].type == OPT_REG
7395 && po->operand[0].reg == xST0;
7397 case OP_FADD: j = '+'; break;
7398 case OP_FDIV: j = '/'; break;
7399 case OP_FMUL: j = '*'; break;
7400 case OP_FSUB: j = '-'; break;
7401 default: j = 'x'; break;
7403 if (need_float_stack) {
7405 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7406 if (po->flags & OPF_FSHIFT)
7407 fprintf(fout, " f_stp++;");
7410 if (po->flags & OPF_FSHIFT) {
7411 // note: assumes only 2 regs handled
7413 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7415 fprintf(fout, " f_st0 = f_st1;");
7418 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7420 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7425 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7427 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7429 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7431 dead_dst = (po->flags & OPF_FPOP)
7432 && po->operand[0].type == OPT_REG
7433 && po->operand[0].reg == xST0;
7434 j = po->op == OP_FDIVR ? '/' : '-';
7435 if (need_float_stack) {
7437 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7438 if (po->flags & OPF_FSHIFT)
7439 fprintf(fout, " f_stp++;");
7442 if (po->flags & OPF_FSHIFT) {
7444 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7446 fprintf(fout, " f_st0 = f_st1;");
7449 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7451 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7459 case OP_FIADD: j = '+'; break;
7460 case OP_FIDIV: j = '/'; break;
7461 case OP_FIMUL: j = '*'; break;
7462 case OP_FISUB: j = '-'; break;
7463 default: j = 'x'; break;
7465 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7467 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7468 lmod_cast(po, po->operand[0].lmod, 1), 0));
7473 fprintf(fout, " %s = %s %c %s;", float_st0,
7474 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7476 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7481 ferr_assert(po, po->datap != NULL);
7482 mask = (long)po->datap & 0xffff;
7483 z_check = ((long)po->datap >> 16) & 1;
7484 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7486 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
7487 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7490 else if (mask == 0x4000) { // C3 -> =
7491 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7494 else if (mask == 0x4100) { // C3, C0
7496 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7498 strcat(g_comment, " z_chk_det");
7501 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7502 "(%s < %s ? 0x0100 : 0);",
7503 float_st0, buf1, float_st0, buf1);
7507 ferr(po, "unhandled sw mask: %x\n", mask);
7508 if (po->flags & OPF_FSHIFT) {
7509 if (need_float_stack)
7510 fprintf(fout, " f_stp++;");
7512 fprintf(fout, " f_st0 = f_st1;");
7518 fprintf(fout, " %s = f_sw;",
7519 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7523 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7527 fprintf(fout, " %s = cos%s(%s);", float_st0,
7528 need_double ? "" : "f", float_st0);
7532 if (need_float_stack) {
7533 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7534 need_double ? "" : "f", float_st1, float_st0);
7535 fprintf(fout, " f_stp++;");
7538 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7539 need_double ? "" : "f");
7544 if (need_float_stack) {
7545 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7546 float_st1, need_double ? "" : "f", float_st0);
7547 fprintf(fout, " f_stp++;");
7550 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7551 need_double ? "" : "f");
7553 strcat(g_comment, " fyl2x");
7557 fprintf(fout, " %s = sin%s(%s);", float_st0,
7558 need_double ? "" : "f", float_st0);
7562 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7563 need_double ? "" : "f", float_st0);
7567 dead_dst = po->operand[0].type == OPT_REG
7568 && po->operand[0].reg == xST0;
7570 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7572 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7573 float_st0, float_st0, buf1, buf1);
7574 strcat(g_comment, " fxch");
7581 ferr_assert(po, po->flags & OPF_32BIT);
7582 fprintf(fout, " eax = (s32)%s;", float_st0);
7583 if (po->flags & OPF_FSHIFT) {
7584 if (need_float_stack)
7585 fprintf(fout, " f_stp++;");
7587 fprintf(fout, " f_st0 = f_st1;");
7589 strcat(g_comment, " ftol");
7593 if (need_float_stack) {
7594 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
7595 need_double ? "" : "f", float_st1, float_st0);
7596 fprintf(fout, " f_stp++;");
7599 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
7600 need_double ? "" : "f");
7602 strcat(g_comment, " CIpow");
7606 fprintf(fout, " do_skip_code_abort();");
7611 fprintf(fout, " do_emms();");
7616 ferr(po, "unhandled op type %d, flags %x\n",
7621 if (g_comment[0] != 0) {
7622 char *p = g_comment;
7623 while (my_isblank(*p))
7625 fprintf(fout, " // %s", p);
7630 fprintf(fout, "\n");
7632 // some sanity checking
7633 if (po->flags & OPF_REP) {
7634 if (po->op != OP_STOS && po->op != OP_MOVS
7635 && po->op != OP_CMPS && po->op != OP_SCAS)
7636 ferr(po, "unexpected rep\n");
7637 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7638 && (po->op == OP_CMPS || po->op == OP_SCAS))
7639 ferr(po, "cmps/scas with plain rep\n");
7641 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7642 && po->op != OP_CMPS && po->op != OP_SCAS)
7643 ferr(po, "unexpected repz/repnz\n");
7646 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
7648 // see is delayed flag stuff is still valid
7649 if (delayed_flag_op != NULL && delayed_flag_op != po) {
7650 if (is_any_opr_modified(delayed_flag_op, po, 0))
7651 delayed_flag_op = NULL;
7654 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7655 if (is_opr_modified(last_arith_dst, po))
7656 last_arith_dst = NULL;
7663 if (g_stack_fsz && !g_stack_frame_used)
7664 fprintf(fout, " (void)sf;\n");
7666 fprintf(fout, "}\n\n");
7668 gen_x_cleanup(opcnt);
7671 static void gen_x_cleanup(int opcnt)
7675 for (i = 0; i < opcnt; i++) {
7676 struct label_ref *lr, *lr_del;
7678 lr = g_label_refs[i].next;
7679 while (lr != NULL) {
7684 g_label_refs[i].i = -1;
7685 g_label_refs[i].next = NULL;
7687 if (ops[i].op == OP_CALL) {
7689 proto_release(ops[i].pp);
7695 struct func_proto_dep;
7697 struct func_prototype {
7702 int has_ret:3; // -1, 0, 1: unresolved, no, yes
7703 unsigned int dep_resolved:1;
7704 unsigned int is_stdcall:1;
7705 struct func_proto_dep *dep_func;
7707 const struct parsed_proto *pp; // seed pp, if any
7710 struct func_proto_dep {
7712 struct func_prototype *proto;
7713 int regmask_live; // .. at the time of call
7714 unsigned int ret_dep:1; // return from this is caller's return
7717 static struct func_prototype *hg_fp;
7718 static int hg_fp_cnt;
7720 static struct scanned_var {
7722 enum opr_lenmod lmod;
7723 unsigned int is_seeded:1;
7724 unsigned int is_c_str:1;
7725 const struct parsed_proto *pp; // seed pp, if any
7727 static int hg_var_cnt;
7729 static char **hg_refs;
7730 static int hg_ref_cnt;
7732 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7735 static struct func_prototype *hg_fp_add(const char *funcn)
7737 struct func_prototype *fp;
7739 if ((hg_fp_cnt & 0xff) == 0) {
7740 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7741 my_assert_not(hg_fp, NULL);
7742 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7745 fp = &hg_fp[hg_fp_cnt];
7746 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7748 fp->argc_stack = -1;
7754 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7759 for (i = 0; i < fp->dep_func_cnt; i++)
7760 if (IS(fp->dep_func[i].name, name))
7761 return &fp->dep_func[i];
7766 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7769 if (hg_fp_find_dep(fp, name))
7772 if ((fp->dep_func_cnt & 0xff) == 0) {
7773 fp->dep_func = realloc(fp->dep_func,
7774 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7775 my_assert_not(fp->dep_func, NULL);
7776 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7777 sizeof(fp->dep_func[0]) * 0x100);
7779 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7783 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7785 const struct func_prototype *p1 = p1_, *p2 = p2_;
7786 return strcmp(p1->name, p2->name);
7790 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7792 const struct func_prototype *p1 = p1_, *p2 = p2_;
7793 return p1->id - p2->id;
7797 static void hg_ref_add(const char *name)
7799 if ((hg_ref_cnt & 0xff) == 0) {
7800 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7801 my_assert_not(hg_refs, NULL);
7802 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7805 hg_refs[hg_ref_cnt] = strdup(name);
7806 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7810 // recursive register dep pass
7811 // - track saved regs (part 2)
7812 // - try to figure out arg-regs
7813 // - calculate reg deps
7814 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
7815 struct func_prototype *fp, int regmask_save, int regmask_dst,
7816 int *regmask_dep, int *has_ret)
7818 struct func_proto_dep *dep;
7819 struct parsed_op *po;
7820 int from_caller = 0;
7825 for (; i < opcnt; i++)
7827 if (cbits[i >> 3] & (1 << (i & 7)))
7829 cbits[i >> 3] |= (1 << (i & 7));
7833 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
7834 if (po->flags & OPF_RMD)
7837 if (po->btj != NULL) {
7839 for (j = 0; j < po->btj->count; j++) {
7840 check_i(po, po->btj->d[j].bt_i);
7841 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
7842 regmask_save, regmask_dst, regmask_dep, has_ret);
7847 check_i(po, po->bt_i);
7848 if (po->flags & OPF_CJMP) {
7849 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
7850 regmask_save, regmask_dst, regmask_dep, has_ret);
7858 if (po->flags & OPF_FARG)
7859 /* (just calculate register deps) */;
7860 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
7862 reg = po->operand[0].reg;
7863 ferr_assert(po, reg >= 0);
7865 if (po->flags & OPF_RSAVE) {
7866 regmask_save |= 1 << reg;
7869 if (po->flags & OPF_DONE)
7872 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
7874 regmask_save |= 1 << reg;
7875 po->flags |= OPF_RMD;
7876 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
7880 else if (po->flags & OPF_RMD)
7882 else if (po->op == OP_CALL) {
7883 po->regmask_dst |= 1 << xAX;
7885 dep = hg_fp_find_dep(fp, po->operand[0].name);
7887 dep->regmask_live = regmask_save | regmask_dst;
7888 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7889 dep->regmask_live |= 1 << xBP;
7892 else if (po->op == OP_RET) {
7893 if (po->operand_cnt > 0) {
7895 if (fp->argc_stack >= 0
7896 && fp->argc_stack != po->operand[0].val / 4)
7897 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
7898 fp->argc_stack = po->operand[0].val / 4;
7902 // if has_ret is 0, there is uninitialized eax path,
7903 // which means it's most likely void func
7904 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
7905 if (po->op == OP_CALL) {
7910 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
7913 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
7916 if (ret != 1 && from_caller) {
7917 // unresolved eax - probably void func
7921 if (j >= 0 && ops[j].op == OP_CALL) {
7922 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
7933 l = regmask_save | regmask_dst;
7934 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7937 l = po->regmask_src & ~l;
7940 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
7941 l, regmask_dst, regmask_save, po->flags);
7944 regmask_dst |= po->regmask_dst;
7946 if (po->flags & OPF_TAIL)
7951 static void gen_hdr(const char *funcn, int opcnt)
7953 unsigned char cbits[MAX_OPS / 8];
7954 const struct parsed_proto *pp_c;
7955 struct parsed_proto *pp;
7956 struct func_prototype *fp;
7957 struct parsed_op *po;
7958 int regmask_dummy = 0;
7960 int max_bp_offset = 0;
7965 pp_c = proto_parse(g_fhdr, funcn, 1);
7967 // already in seed, will add to hg_fp later
7970 fp = hg_fp_add(funcn);
7972 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7973 g_stack_frame_used = 0;
7976 // - resolve all branches
7977 // - parse calls with labels
7978 resolve_branches_parse_calls(opcnt);
7981 // - handle ebp/esp frame, remove ops related to it
7982 scan_prologue_epilogue(opcnt, NULL);
7985 // - remove dead labels
7987 for (i = 0; i < opcnt; i++)
7989 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7995 if (po->flags & (OPF_RMD|OPF_DONE))
7998 if (po->op == OP_CALL) {
7999 if (po->operand[0].type == OPT_LABEL)
8000 hg_fp_add_dep(fp, opr_name(po, 0));
8001 else if (po->pp != NULL)
8002 hg_fp_add_dep(fp, po->pp->name);
8007 // - remove dead labels
8008 // - handle push <const>/pop pairs
8009 for (i = 0; i < opcnt; i++)
8011 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8017 if (po->flags & (OPF_RMD|OPF_DONE))
8020 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8021 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8025 // - process trivial calls
8026 for (i = 0; i < opcnt; i++)
8029 if (po->flags & (OPF_RMD|OPF_DONE))
8032 if (po->op == OP_CALL)
8034 pp = process_call_early(i, opcnt, &j);
8036 if (!(po->flags & OPF_ATAIL))
8037 // since we know the args, try to collect them
8038 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8044 // commit esp adjust
8045 if (ops[j].op != OP_POP)
8046 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8048 for (l = 0; l < pp->argc_stack; l++)
8049 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8053 po->flags |= OPF_DONE;
8059 // - track saved regs (simple)
8061 for (i = 0; i < opcnt; i++)
8064 if (po->flags & (OPF_RMD|OPF_DONE))
8067 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8068 && po->operand[0].reg != xCX)
8070 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8072 // regmask_save |= 1 << po->operand[0].reg; // do it later
8073 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8074 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8077 else if (po->op == OP_CALL)
8079 pp = process_call(i, opcnt);
8081 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8082 // since we know the args, collect them
8083 ret = collect_call_args(po, i, pp, ®mask_dummy,
8090 memset(cbits, 0, sizeof(cbits));
8094 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
8096 // find unreachable code - must be fixed in IDA
8097 for (i = 0; i < opcnt; i++)
8099 if (cbits[i >> 3] & (1 << (i & 7)))
8102 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8103 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8105 // the compiler sometimes still generates code after
8106 // noreturn OS functions
8109 if (ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8110 ferr(&ops[i], "unreachable code\n");
8113 for (i = 0; i < g_eqcnt; i++) {
8114 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8115 max_bp_offset = g_eqs[i].offset;
8118 if (fp->argc_stack < 0) {
8119 max_bp_offset = (max_bp_offset + 3) & ~3;
8120 fp->argc_stack = max_bp_offset / 4;
8121 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8125 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8126 fp->has_ret = has_ret;
8128 printf("// has_ret %d, regmask_dep %x\n",
8129 fp->has_ret, fp->regmask_dep);
8130 output_hdr_fp(stdout, fp, 1);
8131 if (IS(funcn, "sub_10007F72")) exit(1);
8134 gen_x_cleanup(opcnt);
8137 static void hg_fp_resolve_deps(struct func_prototype *fp)
8139 struct func_prototype fp_s;
8143 // this thing is recursive, so mark first..
8144 fp->dep_resolved = 1;
8146 for (i = 0; i < fp->dep_func_cnt; i++) {
8147 strcpy(fp_s.name, fp->dep_func[i].name);
8148 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8149 sizeof(hg_fp[0]), hg_fp_cmp_name);
8150 if (fp->dep_func[i].proto != NULL) {
8151 if (!fp->dep_func[i].proto->dep_resolved)
8152 hg_fp_resolve_deps(fp->dep_func[i].proto);
8154 dep = ~fp->dep_func[i].regmask_live
8155 & fp->dep_func[i].proto->regmask_dep;
8156 fp->regmask_dep |= dep;
8157 // printf("dep %s %s |= %x\n", fp->name,
8158 // fp->dep_func[i].name, dep);
8160 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8161 fp->has_ret = fp->dep_func[i].proto->has_ret;
8166 // make all thiscall/edx arg functions referenced from .data fastcall
8167 static void do_func_refs_from_data(void)
8169 struct func_prototype *fp, fp_s;
8172 for (i = 0; i < hg_ref_cnt; i++) {
8173 strcpy(fp_s.name, hg_refs[i]);
8174 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8175 sizeof(hg_fp[0]), hg_fp_cmp_name);
8179 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8180 fp->regmask_dep |= mxCX | mxDX;
8184 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8187 const struct parsed_proto *pp;
8188 char *p, namebuf[NAMELEN];
8194 for (; count > 0; count--, fp++) {
8195 if (fp->has_ret == -1)
8196 fprintf(fout, "// ret unresolved\n");
8198 fprintf(fout, "// dep:");
8199 for (j = 0; j < fp->dep_func_cnt; j++) {
8200 fprintf(fout, " %s/", fp->dep_func[j].name);
8201 if (fp->dep_func[j].proto != NULL)
8202 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8203 fp->dep_func[j].proto->has_ret);
8205 fprintf(fout, "\n");
8208 p = strchr(fp->name, '@');
8210 memcpy(namebuf, fp->name, p - fp->name);
8211 namebuf[p - fp->name] = 0;
8219 pp = proto_parse(g_fhdr, name, 1);
8220 if (pp != NULL && pp->is_include)
8223 if (fp->pp != NULL) {
8224 // part of seed, output later
8228 regmask_dep = fp->regmask_dep;
8229 argc_normal = fp->argc_stack;
8231 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8232 (fp->has_ret ? "int" : "void"));
8233 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8234 && (regmask_dep & ~mxCX) == 0)
8236 fprintf(fout, "/*__thiscall*/ ");
8240 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8241 && (regmask_dep & ~(mxCX | mxDX)) == 0)
8243 fprintf(fout, " __fastcall ");
8244 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8250 else if (regmask_dep && !fp->is_stdcall) {
8251 fprintf(fout, "/*__usercall*/ ");
8253 else if (regmask_dep) {
8254 fprintf(fout, "/*__userpurge*/ ");
8256 else if (fp->is_stdcall)
8257 fprintf(fout, " __stdcall ");
8259 fprintf(fout, " __cdecl ");
8261 fprintf(fout, "%s(", name);
8264 for (j = 0; j < xSP; j++) {
8265 if (regmask_dep & (1 << j)) {
8268 fprintf(fout, ", ");
8270 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8272 fprintf(fout, "int");
8273 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8277 for (j = 0; j < argc_normal; j++) {
8280 fprintf(fout, ", ");
8281 if (fp->pp != NULL) {
8282 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8283 if (!fp->pp->arg[arg - 1].type.is_ptr)
8287 fprintf(fout, "int ");
8288 fprintf(fout, "a%d", arg);
8291 fprintf(fout, ");\n");
8295 static void output_hdr(FILE *fout)
8297 static const char *lmod_c_names[] = {
8298 [OPLM_UNSPEC] = "???",
8299 [OPLM_BYTE] = "uint8_t",
8300 [OPLM_WORD] = "uint16_t",
8301 [OPLM_DWORD] = "uint32_t",
8302 [OPLM_QWORD] = "uint64_t",
8304 const struct scanned_var *var;
8305 struct func_prototype *fp;
8306 char line[256] = { 0, };
8310 // add stuff from headers
8311 for (i = 0; i < pp_cache_size; i++) {
8312 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8313 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8315 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8316 fp = hg_fp_add(name);
8317 fp->pp = &pp_cache[i];
8318 fp->argc_stack = fp->pp->argc_stack;
8319 fp->is_stdcall = fp->pp->is_stdcall;
8320 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8321 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8325 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8326 for (i = 0; i < hg_fp_cnt; i++)
8327 hg_fp_resolve_deps(&hg_fp[i]);
8329 // adjust functions referenced from data segment
8330 do_func_refs_from_data();
8332 // note: messes up .proto ptr, don't use
8333 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8336 for (i = 0; i < hg_var_cnt; i++) {
8339 if (var->pp != NULL)
8342 else if (var->is_c_str)
8343 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8345 fprintf(fout, "extern %-8s %s;",
8346 lmod_c_names[var->lmod], var->name);
8349 fprintf(fout, " // seeded");
8350 fprintf(fout, "\n");
8353 fprintf(fout, "\n");
8355 // output function prototypes
8356 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8359 fprintf(fout, "\n// - seed -\n");
8362 while (fgets(line, sizeof(line), g_fhdr))
8363 fwrite(line, 1, strlen(line), fout);
8366 // '=' needs special treatment
8368 static char *next_word_s(char *w, size_t wsize, char *s)
8375 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8377 for (i = 1; i < wsize - 1; i++) {
8379 printf("warning: missing closing quote: \"%s\"\n", s);
8388 for (; i < wsize - 1; i++) {
8389 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8395 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8396 printf("warning: '%s' truncated\n", w);
8401 static int cmpstringp(const void *p1, const void *p2)
8403 return strcmp(*(char * const *)p1, *(char * const *)p2);
8406 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8411 if (strstr(p, "..."))
8412 // unable to determine, assume needed
8415 if (*p == '.') // .text, .data, ...
8416 // ref from other data or non-function -> no
8419 p2 = strpbrk(p, "+:\r\n\x18");
8422 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8423 // referenced from removed code
8429 static int ida_xrefs_show_need(FILE *fasm, char *p,
8430 char **rlist, int rlist_len)
8436 p = strrchr(p, ';');
8437 if (p != NULL && *p == ';') {
8438 if (IS_START(p + 2, "sctref"))
8440 if (IS_START(p + 2, "DATA XREF: ")) {
8442 if (is_xref_needed(p, rlist, rlist_len))
8450 if (!my_fgets(line, sizeof(line), fasm))
8452 // non-first line is always indented
8453 if (!my_isblank(line[0]))
8456 // should be no content, just comment
8461 p = strrchr(p, ';');
8464 if (IS_START(p, "sctref")) {
8469 // it's printed once, but no harm to check again
8470 if (IS_START(p, "DATA XREF: "))
8473 if (is_xref_needed(p, rlist, rlist_len)) {
8478 fseek(fasm, pos, SEEK_SET);
8482 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8484 struct scanned_var *var;
8485 char line[256] = { 0, };
8494 // skip to next data section
8495 while (my_fgets(line, sizeof(line), fasm))
8500 if (*p == 0 || *p == ';')
8503 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8504 if (*p == 0 || *p == ';')
8507 if (*p != 's' || !IS_START(p, "segment para public"))
8513 if (p == NULL || !IS_START(p, "segment para public"))
8517 if (!IS_START(p, "'DATA'"))
8521 while (my_fgets(line, sizeof(line), fasm))
8526 no_identifier = my_isblank(*p);
8529 if (*p == 0 || *p == ';')
8532 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8533 words[wordc][0] = 0;
8534 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8535 if (*p == 0 || *p == ';') {
8541 if (wordc == 2 && IS(words[1], "ends"))
8546 if (no_identifier) {
8547 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8548 hg_ref_add(words[2]);
8552 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8553 // when this starts, we don't need anything from this section
8557 // check refs comment(s)
8558 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8561 if ((hg_var_cnt & 0xff) == 0) {
8562 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8563 * (hg_var_cnt + 0x100));
8564 my_assert_not(hg_vars, NULL);
8565 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8568 var = &hg_vars[hg_var_cnt++];
8569 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8571 // maybe already in seed header?
8572 var->pp = proto_parse(g_fhdr, var->name, 1);
8573 if (var->pp != NULL) {
8574 if (var->pp->is_fptr) {
8575 var->lmod = OPLM_DWORD;
8578 else if (var->pp->is_func)
8580 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8581 aerr("unhandled C type '%s' for '%s'\n",
8582 var->pp->type.name, var->name);
8588 if (IS(words[1], "dd")) {
8589 var->lmod = OPLM_DWORD;
8590 if (wordc >= 4 && IS(words[2], "offset"))
8591 hg_ref_add(words[3]);
8593 else if (IS(words[1], "dw"))
8594 var->lmod = OPLM_WORD;
8595 else if (IS(words[1], "db")) {
8596 var->lmod = OPLM_BYTE;
8597 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8598 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8602 else if (IS(words[1], "dq"))
8603 var->lmod = OPLM_QWORD;
8604 //else if (IS(words[1], "dt"))
8606 aerr("type '%s' not known\n", words[1]);
8614 static void set_label(int i, const char *name)
8620 p = strchr(name, ':');
8624 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8625 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8626 g_labels[i] = realloc(g_labels[i], len + 1);
8627 my_assert_not(g_labels[i], NULL);
8628 memcpy(g_labels[i], name, len);
8629 g_labels[i][len] = 0;
8638 static struct chunk_item *func_chunks;
8639 static int func_chunk_cnt;
8640 static int func_chunk_alloc;
8642 static void add_func_chunk(FILE *fasm, const char *name, int line)
8644 if (func_chunk_cnt >= func_chunk_alloc) {
8645 func_chunk_alloc *= 2;
8646 func_chunks = realloc(func_chunks,
8647 func_chunk_alloc * sizeof(func_chunks[0]));
8648 my_assert_not(func_chunks, NULL);
8650 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8651 func_chunks[func_chunk_cnt].name = strdup(name);
8652 func_chunks[func_chunk_cnt].asmln = line;
8656 static int cmp_chunks(const void *p1, const void *p2)
8658 const struct chunk_item *c1 = p1, *c2 = p2;
8659 return strcmp(c1->name, c2->name);
8662 static void scan_ahead_for_chunks(FILE *fasm)
8672 oldpos = ftell(fasm);
8675 while (my_fgets(line, sizeof(line), fasm))
8686 // get rid of random tabs
8687 for (i = 0; line[i] != 0; i++)
8688 if (line[i] == '\t')
8691 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8694 next_word(words[0], sizeof(words[0]), p);
8695 if (words[0][0] == 0)
8696 aerr("missing name for func chunk?\n");
8698 add_func_chunk(fasm, words[0], asmln);
8700 else if (IS_START(p, "; sctend"))
8706 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8707 words[wordc][0] = 0;
8708 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8709 if (*p == 0 || *p == ';') {
8715 if (wordc == 2 && IS(words[1], "ends"))
8719 fseek(fasm, oldpos, SEEK_SET);
8723 int main(int argc, char *argv[])
8725 FILE *fout, *fasm, *frlist;
8726 struct parsed_data *pd = NULL;
8728 char **rlist = NULL;
8730 int rlist_alloc = 0;
8731 int func_chunks_used = 0;
8732 int func_chunks_sorted = 0;
8733 int func_chunk_i = -1;
8734 long func_chunk_ret = 0;
8735 int func_chunk_ret_ln = 0;
8736 int scanned_ahead = 0;
8738 char words[20][256];
8739 enum opr_lenmod lmod;
8740 char *sctproto = NULL;
8742 int pending_endp = 0;
8744 int skip_code_end = 0;
8745 int skip_warned = 0;
8758 for (arg = 1; arg < argc; arg++) {
8759 if (IS(argv[arg], "-v"))
8761 else if (IS(argv[arg], "-rf"))
8762 g_allow_regfunc = 1;
8763 else if (IS(argv[arg], "-uc"))
8764 g_allow_user_icall = 1;
8765 else if (IS(argv[arg], "-m"))
8767 else if (IS(argv[arg], "-hdr"))
8768 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8773 if (argc < arg + 3) {
8774 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8775 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8777 " -hdr - header generation mode\n"
8778 " -rf - allow unannotated indirect calls\n"
8779 " -uc - allow ind. calls/refs to __usercall\n"
8780 " -m - allow multiple .text sections\n"
8781 "[rlist] is a file with function names to skip,"
8789 asmfn = argv[arg++];
8790 fasm = fopen(asmfn, "r");
8791 my_assert_not(fasm, NULL);
8793 hdrfn = argv[arg++];
8794 g_fhdr = fopen(hdrfn, "r");
8795 my_assert_not(g_fhdr, NULL);
8798 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8799 my_assert_not(rlist, NULL);
8800 // needs special handling..
8801 rlist[rlist_len++] = "__alloca_probe";
8803 func_chunk_alloc = 32;
8804 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8805 my_assert_not(func_chunks, NULL);
8807 memset(words, 0, sizeof(words));
8809 for (; arg < argc; arg++) {
8812 frlist = fopen(argv[arg], "r");
8813 my_assert_not(frlist, NULL);
8815 while (my_fgets(line, sizeof(line), frlist)) {
8817 if (*p == 0 || *p == ';')
8820 if (IS_START(p, "#if 0")
8821 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
8825 else if (IS_START(p, "#endif"))
8832 p = next_word(words[0], sizeof(words[0]), p);
8833 if (words[0][0] == 0)
8836 if (rlist_len >= rlist_alloc) {
8837 rlist_alloc = rlist_alloc * 2 + 64;
8838 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
8839 my_assert_not(rlist, NULL);
8841 rlist[rlist_len++] = strdup(words[0]);
8849 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
8851 fout = fopen(argv[arg_out], "w");
8852 my_assert_not(fout, NULL);
8855 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
8856 my_assert_not(g_eqs, NULL);
8858 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
8859 g_label_refs[i].i = -1;
8860 g_label_refs[i].next = NULL;
8864 scan_variables(fasm, rlist, rlist_len);
8866 while (my_fgets(line, sizeof(line), fasm))
8875 // get rid of random tabs
8876 for (i = 0; line[i] != 0; i++)
8877 if (line[i] == '\t')
8882 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
8883 goto do_pending_endp; // eww..
8885 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
8887 static const char *attrs[] = {
8896 // parse IDA's attribute-list comment
8897 g_ida_func_attr = 0;
8900 for (; *p != 0; p = sskip(p)) {
8901 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8902 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8903 g_ida_func_attr |= 1 << i;
8904 p += strlen(attrs[i]);
8908 if (i == ARRAY_SIZE(attrs)) {
8909 anote("unparsed IDA attr: %s\n", p);
8912 if (IS(attrs[i], "fpd=")) {
8913 p = next_word(words[0], sizeof(words[0]), p);
8918 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
8920 static const char *attrs[] = {
8925 // parse manual attribute-list comment
8926 g_sct_func_attr = 0;
8929 for (; *p != 0; p = sskip(p)) {
8930 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8931 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8932 g_sct_func_attr |= 1 << i;
8933 p += strlen(attrs[i]);
8940 // clear_sf=start,len (in dwords)
8941 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
8942 &g_stack_clear_len, &j);
8944 // clear_regmask=<mask>
8945 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
8947 anote("unparsed attr value: %s\n", p);
8952 else if (i == ARRAY_SIZE(attrs)) {
8953 anote("unparsed sct attr: %s\n", p);
8958 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8961 next_word(words[0], sizeof(words[0]), p);
8962 if (words[0][0] == 0)
8963 aerr("missing name for func chunk?\n");
8965 if (!scanned_ahead) {
8966 add_func_chunk(fasm, words[0], asmln);
8967 func_chunks_sorted = 0;
8970 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
8972 if (func_chunk_i >= 0) {
8973 if (func_chunk_i < func_chunk_cnt
8974 && IS(func_chunks[func_chunk_i].name, g_func))
8976 // move on to next chunk
8977 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8979 aerr("seek failed for '%s' chunk #%d\n",
8980 g_func, func_chunk_i);
8981 asmln = func_chunks[func_chunk_i].asmln;
8985 if (func_chunk_ret == 0)
8986 aerr("no return from chunk?\n");
8987 fseek(fasm, func_chunk_ret, SEEK_SET);
8988 asmln = func_chunk_ret_ln;
8994 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
8995 func_chunks_used = 1;
8997 if (IS_START(g_func, "sub_")) {
8998 unsigned long addr = strtoul(p, NULL, 16);
8999 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9000 if (addr > f_addr && !scanned_ahead) {
9001 //anote("scan_ahead caused by '%s', addr %lx\n",
9003 scan_ahead_for_chunks(fasm);
9005 func_chunks_sorted = 0;
9013 for (i = wordc; i < ARRAY_SIZE(words); i++)
9015 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9016 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9017 if (*p == 0 || *p == ';') {
9022 if (*p != 0 && *p != ';')
9023 aerr("too many words\n");
9025 if (skip_code_end) {
9030 // allow asm patches in comments
9032 if (IS_START(p, "; sctpatch:")) {
9034 if (*p == 0 || *p == ';')
9036 goto parse_words; // lame
9038 if (IS_START(p, "; sctproto:")) {
9039 sctproto = strdup(p + 11);
9041 else if (IS_START(p, "; sctend")) {
9046 else if (IS_START(p, "; sctskip_start")) {
9047 if (in_func && !g_skip_func) {
9049 ops[pi].op = OPP_ABORT;
9050 ops[pi].asmln = asmln;
9056 else if (IS_START(p, "; sctskip_end")) {
9064 awarn("wordc == 0?\n");
9068 // don't care about this:
9069 if (words[0][0] == '.'
9070 || IS(words[0], "include")
9071 || IS(words[0], "assume") || IS(words[1], "segment")
9072 || IS(words[0], "align"))
9078 // do delayed endp processing to collect switch jumptables
9080 if (in_func && !g_skip_func && !end && wordc >= 2
9081 && ((words[0][0] == 'd' && words[0][2] == 0)
9082 || (words[1][0] == 'd' && words[1][2] == 0)))
9085 if (words[1][0] == 'd' && words[1][2] == 0) {
9087 if (g_func_pd_cnt >= pd_alloc) {
9088 pd_alloc = pd_alloc * 2 + 16;
9089 g_func_pd = realloc(g_func_pd,
9090 sizeof(g_func_pd[0]) * pd_alloc);
9091 my_assert_not(g_func_pd, NULL);
9093 pd = &g_func_pd[g_func_pd_cnt];
9095 memset(pd, 0, sizeof(*pd));
9096 strcpy(pd->label, words[0]);
9097 pd->type = OPT_CONST;
9098 pd->lmod = lmod_from_directive(words[1]);
9104 anote("skipping alignment byte?\n");
9107 lmod = lmod_from_directive(words[0]);
9108 if (lmod != pd->lmod)
9109 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9112 if (pd->count_alloc < pd->count + wordc) {
9113 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9114 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9115 my_assert_not(pd->d, NULL);
9117 for (; i < wordc; i++) {
9118 if (IS(words[i], "offset")) {
9119 pd->type = OPT_OFFSET;
9122 p = strchr(words[i], ',');
9125 if (pd->type == OPT_OFFSET)
9126 pd->d[pd->count].u.label = strdup(words[i]);
9128 pd->d[pd->count].u.val = parse_number(words[i], 0);
9129 pd->d[pd->count].bt_i = -1;
9135 if (in_func && !g_skip_func) {
9137 gen_hdr(g_func, pi);
9139 gen_func(fout, g_fhdr, g_func, pi);
9144 g_ida_func_attr = 0;
9145 g_sct_func_attr = 0;
9146 g_stack_clear_start = 0;
9147 g_stack_clear_len = 0;
9152 func_chunks_used = 0;
9155 memset(&ops, 0, pi * sizeof(ops[0]));
9160 for (i = 0; i < g_func_pd_cnt; i++) {
9162 if (pd->type == OPT_OFFSET) {
9163 for (j = 0; j < pd->count; j++)
9164 free(pd->d[j].u.label);
9179 if (IS(words[1], "proc")) {
9181 aerr("proc '%s' while in_func '%s'?\n",
9184 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9186 strcpy(g_func, words[0]);
9187 set_label(0, words[0]);
9192 if (IS(words[1], "endp"))
9195 aerr("endp '%s' while not in_func?\n", words[0]);
9196 if (!IS(g_func, words[0]))
9197 aerr("endp '%s' while in_func '%s'?\n",
9200 aerr("endp '%s' while skipping code\n", words[0]);
9202 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9203 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
9209 if (!g_skip_func && func_chunks_used) {
9210 // start processing chunks
9211 struct chunk_item *ci, key = { g_func, 0 };
9213 func_chunk_ret = ftell(fasm);
9214 func_chunk_ret_ln = asmln;
9215 if (!func_chunks_sorted) {
9216 qsort(func_chunks, func_chunk_cnt,
9217 sizeof(func_chunks[0]), cmp_chunks);
9218 func_chunks_sorted = 1;
9220 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9221 sizeof(func_chunks[0]), cmp_chunks);
9223 aerr("'%s' needs chunks, but none found\n", g_func);
9224 func_chunk_i = ci - func_chunks;
9225 for (; func_chunk_i > 0; func_chunk_i--)
9226 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9229 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9231 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9232 asmln = func_chunks[func_chunk_i].asmln;
9240 if (wordc == 2 && IS(words[1], "ends")) {
9244 goto do_pending_endp;
9248 // scan for next text segment
9249 while (my_fgets(line, sizeof(line), fasm)) {
9252 if (*p == 0 || *p == ';')
9255 if (strstr(p, "segment para public 'CODE' use32"))
9262 p = strchr(words[0], ':');
9264 set_label(pi, words[0]);
9268 if (!in_func || g_skip_func || skip_code) {
9269 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9271 anote("skipping from '%s'\n", g_labels[pi]);
9275 g_labels[pi] = NULL;
9279 if (wordc > 1 && IS(words[1], "="))
9282 aerr("unhandled equ, wc=%d\n", wordc);
9283 if (g_eqcnt >= eq_alloc) {
9285 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9286 my_assert_not(g_eqs, NULL);
9289 len = strlen(words[0]);
9290 if (len > sizeof(g_eqs[0].name) - 1)
9291 aerr("equ name too long: %d\n", len);
9292 strcpy(g_eqs[g_eqcnt].name, words[0]);
9294 if (!IS(words[3], "ptr"))
9295 aerr("unhandled equ\n");
9296 if (IS(words[2], "dword"))
9297 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9298 else if (IS(words[2], "word"))
9299 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9300 else if (IS(words[2], "byte"))
9301 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9302 else if (IS(words[2], "qword"))
9303 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9305 aerr("bad lmod: '%s'\n", words[2]);
9307 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9312 if (pi >= ARRAY_SIZE(ops))
9313 aerr("too many ops\n");
9315 parse_op(&ops[pi], words, wordc);
9317 ops[pi].datap = sctproto;
9332 // vim:ts=2:shiftwidth=2:expandtab