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)
26 #include "my_assert.h"
30 #include "protoparse.h"
32 static const char *asmfn;
36 #define anote(fmt, ...) \
37 printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
38 #define awarn(fmt, ...) \
39 printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
40 #define aerr(fmt, ...) do { \
41 printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
46 #include "masm_tools.h"
49 OPF_RMD = (1 << 0), /* removed from code generation */
50 OPF_DATA = (1 << 1), /* data processing - writes to dst opr */
51 OPF_FLAGS = (1 << 2), /* sets flags */
52 OPF_JMP = (1 << 3), /* branch, call */
53 OPF_CJMP = (1 << 4), /* cond. branch (cc or jecxz/loop) */
54 OPF_CC = (1 << 5), /* uses flags */
55 OPF_TAIL = (1 << 6), /* ret or tail call */
56 OPF_RSAVE = (1 << 7), /* push/pop is local reg save/load */
57 OPF_REP = (1 << 8), /* prefixed by rep */
58 OPF_REPZ = (1 << 9), /* rep is repe/repz */
59 OPF_REPNZ = (1 << 10), /* rep is repne/repnz */
60 OPF_FARG = (1 << 11), /* push collected as func arg */
61 OPF_FARGNR = (1 << 12), /* push collected as func arg (no reuse) */
62 OPF_EBP_S = (1 << 13), /* ebp used as scratch here, not BP */
63 OPF_DF = (1 << 14), /* DF flag set */
64 OPF_ATAIL = (1 << 15), /* tail call with reused arg frame */
65 OPF_32BIT = (1 << 16), /* enough to do 32bit for this op */
66 OPF_LOCK = (1 << 17), /* op has lock prefix */
67 OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
68 OPF_DONE = (1 << 19), /* already fully handled by analysis */
69 OPF_PPUSH = (1 << 20), /* part of complex push-pop graph */
70 OPF_NOREGS = (1 << 21), /* don't track regs of this op */
71 OPF_FPUSH = (1 << 22), /* pushes x87 stack */
72 OPF_FPOP = (1 << 23), /* pops x87 stack */
73 OPF_FPOPP = (1 << 24), /* pops x87 stack twice */
74 OPF_FSHIFT = (1 << 25), /* x87 stack shift is actually needed */
75 OPF_FINT = (1 << 26), /* integer float op arg */
169 // pseudo-ops for lib calls
188 // must be sorted (larger len must be further in enum)
197 #define MAX_EXITS 128
199 #define MAX_OPERANDS 3
202 #define OPR_INIT(type_, lmod_, reg_) \
203 { type_, lmod_, reg_, }
207 enum opr_lenmod lmod;
209 unsigned int is_ptr:1; // pointer in C
210 unsigned int is_array:1; // array in C
211 unsigned int type_from_var:1; // .. in header, sometimes wrong
212 unsigned int size_mismatch:1; // type override differs from C
213 unsigned int size_lt:1; // type override is larger than C
214 unsigned int segment:7; // had segment override (enum segment)
215 const struct parsed_proto *pp; // for OPT_LABEL
222 struct parsed_opr operand[MAX_OPERANDS];
225 unsigned char pfo_inv;
226 unsigned char operand_cnt;
227 unsigned char p_argnum; // arg push: altered before call arg #
228 unsigned char p_arggrp; // arg push: arg group # for above
229 unsigned char p_argpass;// arg push: arg of host func
230 short p_argnext;// arg push: same arg pushed elsewhere or -1
231 int regmask_src; // all referensed regs
233 int pfomask; // flagop: parsed_flag_op that can't be delayed
234 int cc_scratch; // scratch storage during analysis
235 int bt_i; // branch target for branches
236 struct parsed_data *btj;// branch targets for jumptables
237 struct parsed_proto *pp;// parsed_proto for OP_CALL
243 // on start: function/data type hint (sctproto)
245 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
246 // OP_PUSH - points to OP_POP in complex push/pop graph
247 // OP_POP - points to OP_PUSH in simple push/pop pair
248 // OP_FCOM - needed_status_word_bits | (is_z_check << 16)
252 enum opr_lenmod lmod;
259 enum opr_lenmod lmod;
273 struct label_ref *next;
277 IDAFA_BP_FRAME = (1 << 0),
278 IDAFA_LIB_FUNC = (1 << 1),
279 IDAFA_STATIC = (1 << 2),
280 IDAFA_NORETURN = (1 << 3),
281 IDAFA_THUNK = (1 << 4),
282 IDAFA_FPD = (1 << 5),
287 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
288 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
289 SCTFA_RM_REGS = (1 << 2), // don't emit regs (mask)
290 SCTFA_NOWARN = (1 << 3), // don't try to detect problems
291 SCTFA_ARGFRAME = (1 << 4), // copy all args to a struct, in order
313 // note: limited to 32k due to p_argnext
315 #define MAX_ARG_GRP 2
317 static struct parsed_op ops[MAX_OPS];
318 static struct parsed_equ *g_eqs;
320 static char *g_labels[MAX_OPS];
321 static struct label_ref g_label_refs[MAX_OPS];
322 static const struct parsed_proto *g_func_pp;
323 static struct parsed_data *g_func_pd;
324 static int g_func_pd_cnt;
325 static int g_func_lmods;
326 static char g_func[256];
327 static char g_comment[256];
328 static int g_bp_frame;
329 static int g_sp_frame;
330 static int g_stack_frame_used;
331 static int g_stack_fsz;
332 static int g_seh_found;
333 static int g_seh_size;
334 static int g_ida_func_attr;
335 static int g_sct_func_attr;
336 static int g_stack_clear_start; // in dwords
337 static int g_stack_clear_len;
338 static int g_regmask_init;
339 static int g_regmask_rm;
340 static int g_skip_func;
341 static int g_allow_regfunc;
342 static int g_allow_user_icall;
343 static int g_nowarn_reguse;
344 static int g_quiet_pp;
345 static int g_header_mode;
347 #define ferr(op_, fmt, ...) do { \
348 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
349 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
353 #define fnote(op_, fmt, ...) \
354 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
355 dump_op(op_), ##__VA_ARGS__)
357 #define ferr_assert(op_, cond) do { \
358 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
361 #define IS_OP_INDIRECT_CALL(op_) \
362 ((op_)->op == OP_CALL && (op_)->operand[0].type != OPT_LABEL)
364 const char *regs_r32[] = {
365 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
366 // not r32, but list here for easy parsing and printing
367 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
368 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
370 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
371 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
372 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
378 xMM0, xMM1, xMM2, xMM3, // mmx
379 xMM4, xMM5, xMM6, xMM7,
380 xST0, xST1, xST2, xST3, // x87
381 xST4, xST5, xST6, xST7,
384 #define mxAX (1 << xAX)
385 #define mxBX (1 << xBX)
386 #define mxCX (1 << xCX)
387 #define mxDX (1 << xDX)
388 #define mxSP (1 << xSP)
389 #define mxST0 (1 << xST0)
390 #define mxST1 (1 << xST1)
391 #define mxST1_0 (mxST1 | mxST0)
392 #define mxST7_2 (0xfc << xST0)
393 #define mxSTa (0xff << xST0)
395 // possible basic comparison types (without inversion)
396 enum parsed_flag_op {
400 PFO_BE, // 6 CF=1||ZF=1
404 PFO_LE, // e ZF=1||SF!=OF
407 #define PFOB_O (1 << PFO_O)
408 #define PFOB_C (1 << PFO_C)
409 #define PFOB_Z (1 << PFO_Z)
410 #define PFOB_S (1 << PFO_S)
412 static const char *parsed_flag_op_names[] = {
413 "o", "c", "z", "be", "s", "p", "l", "le"
416 static int char_array_i(const char *array[], size_t len, const char *s)
420 for (i = 0; i < len; i++)
427 static void printf_number(char *buf, size_t buf_size,
428 unsigned long number)
430 // output in C-friendly form
431 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
434 static int check_segment_prefix(const char *s)
436 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
440 case 'c': return SEG_CS;
441 case 'd': return SEG_DS;
442 case 's': return SEG_SS;
443 case 'e': return SEG_ES;
444 case 'f': return SEG_FS;
445 case 'g': return SEG_GS;
450 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
454 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
456 *reg_lmod = OPLM_QWORD;
460 *reg_lmod = OPLM_DWORD;
463 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
465 *reg_lmod = OPLM_WORD;
468 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
470 *reg_lmod = OPLM_BYTE;
473 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
475 *reg_lmod = OPLM_BYTE;
482 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
484 enum opr_lenmod lmod;
497 while (my_isblank(*s))
499 for (; my_issep(*s); d++, s++)
501 while (my_isblank(*s))
505 // skip '?s:' prefixes
506 if (check_segment_prefix(s))
509 s = next_idt(w, sizeof(w), s);
514 reg = parse_reg(&lmod, w);
516 *regmask |= 1 << reg;
520 if ('0' <= w[0] && w[0] <= '9') {
521 number = parse_number(w, 0);
522 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
526 // probably some label/identifier - pass
529 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
533 strcpy(name, cvtbuf);
538 static int is_reg_in_str(const char *s)
542 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
545 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
546 if (!strncmp(s, regs_r32[i], 3))
552 static const char *parse_stack_el(const char *name, char *extra_reg,
553 int *base_val, int early_try)
555 const char *p, *p2, *s;
561 if (g_bp_frame || early_try)
564 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
566 if (extra_reg != NULL) {
567 strncpy(extra_reg, name, 3);
572 if (IS_START(p, "ebp+")) {
576 if (p2 != NULL && is_reg_in_str(p)) {
577 if (extra_reg != NULL) {
578 strncpy(extra_reg, p, p2 - p);
579 extra_reg[p2 - p] = 0;
584 if (!('0' <= *p && *p <= '9'))
591 if (!IS_START(name, "esp+"))
597 if (is_reg_in_str(s)) {
598 if (extra_reg != NULL) {
599 strncpy(extra_reg, s, p - s);
600 extra_reg[p - s] = 0;
605 aerr("%s IDA stackvar not set?\n", __func__);
607 if ('0' <= *s && *s <= '9') {
608 if (s[0] == '0' && s[1] == 'x')
611 if (len < sizeof(buf) - 1) {
612 strncpy(buf, s, len);
615 val = strtol(buf, &endp, 16);
616 if (val == 0 || *endp != 0 || errno != 0) {
617 aerr("%s num parse fail for '%s'\n", __func__, buf);
624 // probably something like [esp+arg_4+2]
632 if ('0' <= *p && *p <= '9')
635 if (base_val != NULL)
640 static int guess_lmod_from_name(struct parsed_opr *opr)
642 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
643 opr->lmod = OPLM_DWORD;
646 if (IS_START(opr->name, "word_")) {
647 opr->lmod = OPLM_WORD;
650 if (IS_START(opr->name, "byte_")) {
651 opr->lmod = OPLM_BYTE;
654 if (IS_START(opr->name, "qword_")) {
655 opr->lmod = OPLM_QWORD;
661 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
662 const struct parsed_type *c_type)
664 static const char *qword_types[] = {
665 "uint64_t", "int64_t", "__int64",
667 static const char *dword_types[] = {
668 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
669 "WPARAM", "LPARAM", "UINT", "__int32",
670 "LONG", "HIMC", "BOOL", "size_t",
673 static const char *word_types[] = {
674 "uint16_t", "int16_t", "_WORD", "WORD",
675 "unsigned __int16", "__int16",
677 static const char *byte_types[] = {
678 "uint8_t", "int8_t", "char",
679 "unsigned __int8", "__int8", "BYTE", "_BYTE",
681 // structures.. deal the same as with _UNKNOWN for now
687 if (c_type->is_ptr) {
692 n = skip_type_mod(c_type->name);
694 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
695 if (IS(n, dword_types[i])) {
701 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
702 if (IS(n, word_types[i])) {
708 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
709 if (IS(n, byte_types[i])) {
715 for (i = 0; i < ARRAY_SIZE(qword_types); i++) {
716 if (IS(n, qword_types[i])) {
725 static char *default_cast_to(char *buf, size_t buf_size,
726 struct parsed_opr *opr)
730 if (!opr->is_ptr || strchr(opr->name, '['))
732 if (opr->pp == NULL || opr->pp->type.name == NULL
735 snprintf(buf, buf_size, "%s", "(void *)");
739 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
743 static enum opr_type lmod_from_directive(const char *d)
747 else if (IS(d, "dw"))
749 else if (IS(d, "db"))
752 aerr("unhandled directive: '%s'\n", d);
756 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
762 *regmask |= 1 << reg;
765 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
768 static int parse_operand(struct parsed_opr *opr,
769 int *regmask, int *regmask_indirect,
770 char words[16][256], int wordc, int w, unsigned int op_flags)
772 const struct parsed_proto *pp = NULL;
773 enum opr_lenmod tmplmod;
774 unsigned long number;
782 aerr("parse_operand w %d, wordc %d\n", w, wordc);
786 for (i = w; i < wordc; i++) {
787 len = strlen(words[i]);
788 if (words[i][len - 1] == ',') {
789 words[i][len - 1] = 0;
795 wordc_in = wordc - w;
797 if ((op_flags & OPF_JMP) && wordc_in > 0
798 && !('0' <= words[w][0] && words[w][0] <= '9'))
800 const char *label = NULL;
802 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
803 && IS(words[w + 1], "ptr"))
804 label = words[w + 2];
805 else if (wordc_in == 2 && IS(words[w], "short"))
806 label = words[w + 1];
807 else if (wordc_in == 1
808 && strchr(words[w], '[') == NULL
809 && parse_reg(&tmplmod, words[w]) < 0)
813 opr->type = OPT_LABEL;
814 ret = check_segment_prefix(label);
819 strcpy(opr->name, label);
825 if (IS(words[w + 1], "ptr")) {
826 if (IS(words[w], "dword"))
827 opr->lmod = OPLM_DWORD;
828 else if (IS(words[w], "word"))
829 opr->lmod = OPLM_WORD;
830 else if (IS(words[w], "byte"))
831 opr->lmod = OPLM_BYTE;
832 else if (IS(words[w], "qword"))
833 opr->lmod = OPLM_QWORD;
835 aerr("type parsing failed\n");
837 wordc_in = wordc - w;
842 if (IS(words[w], "offset")) {
843 opr->type = OPT_OFFSET;
844 opr->lmod = OPLM_DWORD;
845 strcpy(opr->name, words[w + 1]);
846 pp = proto_parse(g_fhdr, opr->name, 1);
849 if (IS(words[w], "(offset")) {
850 p = strchr(words[w + 1], ')');
852 aerr("parse of bracketed offset failed\n");
854 opr->type = OPT_OFFSET;
855 strcpy(opr->name, words[w + 1]);
861 aerr("parse_operand 1 word expected\n");
863 ret = check_segment_prefix(words[w]);
866 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
867 if (ret == SEG_FS && IS(words[w], "0"))
870 strcpy(opr->name, words[w]);
872 if (words[w][0] == '[') {
873 opr->type = OPT_REGMEM;
874 ret = sscanf(words[w], "[%[^]]]", opr->name);
876 aerr("[] parse failure\n");
878 parse_indmode(opr->name, regmask_indirect, 1);
879 if (opr->lmod == OPLM_UNSPEC
880 && parse_stack_el(opr->name, NULL, NULL, 1))
883 struct parsed_equ *eq =
884 equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
886 opr->lmod = eq->lmod;
888 // might be unaligned access
889 g_func_lmods |= 1 << OPLM_BYTE;
893 else if (strchr(words[w], '[')) {
895 p = strchr(words[w], '[');
896 opr->type = OPT_REGMEM;
897 parse_indmode(p, regmask_indirect, 0);
898 strncpy(buf, words[w], p - words[w]);
899 buf[p - words[w]] = 0;
900 pp = proto_parse(g_fhdr, buf, 1);
903 else if (('0' <= words[w][0] && words[w][0] <= '9')
904 || words[w][0] == '-')
906 number = parse_number(words[w], 0);
907 opr->type = OPT_CONST;
909 printf_number(opr->name, sizeof(opr->name), number);
913 ret = parse_reg(&tmplmod, opr->name);
915 setup_reg_opr(opr, ret, tmplmod, regmask);
919 // most likely var in data segment
920 opr->type = OPT_LABEL;
921 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
925 if (pp->is_fptr || pp->is_func) {
926 opr->lmod = OPLM_DWORD;
930 tmplmod = OPLM_UNSPEC;
931 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
932 anote("unhandled C type '%s' for '%s'\n",
933 pp->type.name, opr->name);
935 if (opr->lmod == OPLM_UNSPEC) {
937 opr->type_from_var = 1;
939 else if (opr->lmod != tmplmod) {
940 opr->size_mismatch = 1;
941 if (tmplmod < opr->lmod)
944 opr->is_ptr = pp->type.is_ptr;
946 opr->is_array = pp->type.is_array;
950 if (opr->lmod == OPLM_UNSPEC)
951 guess_lmod_from_name(opr);
955 static const struct {
960 { "repe", OPF_REP|OPF_REPZ },
961 { "repz", OPF_REP|OPF_REPZ },
962 { "repne", OPF_REP|OPF_REPNZ },
963 { "repnz", OPF_REP|OPF_REPNZ },
964 { "lock", OPF_LOCK },
967 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
969 static const struct {
972 unsigned short minopr;
973 unsigned short maxopr;
976 unsigned char pfo_inv;
978 { "nop", OP_NOP, 0, 0, 0 },
979 { "push", OP_PUSH, 1, 1, 0 },
980 { "pop", OP_POP, 1, 1, OPF_DATA },
981 { "pusha",OP_PUSHA, 0, 0, 0 },
982 { "popa", OP_POPA, 0, 0, OPF_DATA },
983 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
984 { "mov" , OP_MOV, 2, 2, OPF_DATA },
985 { "lea", OP_LEA, 2, 2, OPF_DATA },
986 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
987 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
988 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
989 { "not", OP_NOT, 1, 1, OPF_DATA },
990 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
991 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
992 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
993 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
994 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
995 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
996 { "stosb",OP_STOS, 0, 0, OPF_DATA },
997 { "stosw",OP_STOS, 0, 0, OPF_DATA },
998 { "stosd",OP_STOS, 0, 0, OPF_DATA },
999 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
1000 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
1001 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
1002 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
1003 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
1004 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
1005 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
1006 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
1007 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
1008 { "rdtsc",OP_RDTSC, 0, 0, OPF_DATA },
1009 { "cpuid",OP_CPUID, 0, 0, OPF_DATA },
1010 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
1011 { "cld", OP_CLD, 0, 0, OPF_DATA },
1012 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
1013 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
1014 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
1015 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
1016 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
1017 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
1018 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
1019 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
1020 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
1021 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
1022 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
1023 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
1024 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
1025 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1026 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1027 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1028 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1029 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
1030 { "bsr", OP_BSR, 2, 2, OPF_DATA|OPF_FLAGS },
1031 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
1032 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
1033 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
1034 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
1035 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
1036 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
1037 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
1038 { "test", OP_TEST, 2, 2, OPF_FLAGS },
1039 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
1040 { "retn", OP_RET, 0, 1, OPF_TAIL },
1041 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
1042 { "jmp", OP_JMP, 1, 1, OPF_JMP },
1043 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
1044 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
1045 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
1046 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
1047 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
1048 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
1049 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
1050 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1051 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1052 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
1053 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
1054 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
1055 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
1056 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1057 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1058 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1059 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1060 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1061 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1062 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1063 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1064 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1065 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1066 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1067 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1068 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1069 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1070 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1071 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1072 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1073 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1074 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1075 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1076 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1077 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1078 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1079 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1080 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1081 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1082 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1083 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1084 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1085 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1086 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1087 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1088 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1089 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1090 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1091 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1092 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1093 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1094 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1095 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1096 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1097 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1098 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1099 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1100 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1101 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1102 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1104 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1105 { "fild", OP_FILD, 1, 1, OPF_FPUSH|OPF_FINT },
1106 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1107 { "fldl2t", OP_FLDc, 0, 0, OPF_FPUSH },
1108 { "fldl2e", OP_FLDc, 0, 0, OPF_FPUSH },
1109 { "fldpi", OP_FLDc, 0, 0, OPF_FPUSH },
1110 { "fldlg2", OP_FLDc, 0, 0, OPF_FPUSH },
1111 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1112 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1113 { "fst", OP_FST, 1, 1, 0 },
1114 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1115 { "fist", OP_FIST, 1, 1, OPF_FINT },
1116 { "fistp", OP_FIST, 1, 1, OPF_FPOP|OPF_FINT },
1117 { "fabs", OP_FABS, 0, 0, 0 },
1118 { "fadd", OP_FADD, 0, 2, 0 },
1119 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1120 { "fdiv", OP_FDIV, 0, 2, 0 },
1121 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1122 { "fmul", OP_FMUL, 0, 2, 0 },
1123 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1124 { "fsub", OP_FSUB, 0, 2, 0 },
1125 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1126 { "fdivr", OP_FDIVR, 0, 2, 0 },
1127 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1128 { "fsubr", OP_FSUBR, 0, 2, 0 },
1129 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1130 { "fiadd", OP_FIADD, 1, 1, OPF_FINT },
1131 { "fidiv", OP_FIDIV, 1, 1, OPF_FINT },
1132 { "fimul", OP_FIMUL, 1, 1, OPF_FINT },
1133 { "fisub", OP_FISUB, 1, 1, OPF_FINT },
1134 { "fidivr", OP_FIDIVR, 1, 1, OPF_FINT },
1135 { "fisubr", OP_FISUBR, 1, 1, OPF_FINT },
1136 { "fcom", OP_FCOM, 0, 1, 0 },
1137 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1138 { "fcompp", OP_FCOM, 0, 0, OPF_FPOPP },
1139 { "fucom", OP_FCOM, 0, 1, 0 },
1140 { "fucomp", OP_FCOM, 0, 1, OPF_FPOP },
1141 { "fucompp",OP_FCOM, 0, 0, OPF_FPOPP },
1142 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1143 { "fchs", OP_FCHS, 0, 0, 0 },
1144 { "fcos", OP_FCOS, 0, 0, 0 },
1145 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1146 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1147 { "fsin", OP_FSIN, 0, 0, 0 },
1148 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1149 { "fxch", OP_FXCH, 1, 1, 0 },
1150 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1152 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1153 { "movq", OP_MOV, 2, 2, OPF_DATA },
1154 // pseudo-ops for lib calls
1155 { "_allshl",OPP_ALLSHL },
1156 { "_allshr",OPP_ALLSHR },
1157 { "_ftol", OPP_FTOL },
1158 { "_CIpow", OPP_CIPOW },
1159 { "abort", OPP_ABORT },
1164 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1166 enum opr_lenmod lmod = OPLM_UNSPEC;
1167 int prefix_flags = 0;
1175 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1176 if (IS(words[w], pref_table[i].name)) {
1177 prefix_flags = pref_table[i].flags;
1184 aerr("lone prefix: '%s'\n", words[0]);
1189 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1190 if (IS(words[w], op_table[i].name))
1194 if (i == ARRAY_SIZE(op_table)) {
1196 aerr("unhandled op: '%s'\n", words[0]);
1201 op->op = op_table[i].op;
1202 op->flags = op_table[i].flags | prefix_flags;
1203 op->pfo = op_table[i].pfo;
1204 op->pfo_inv = op_table[i].pfo_inv;
1205 op->regmask_src = op->regmask_dst = 0;
1208 if (op->op == OP_UD2)
1211 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1212 if (opr >= op_table[i].minopr && w >= wordc)
1215 regmask = regmask_ind = 0;
1216 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1217 words, wordc, w, op->flags);
1219 if (opr == 0 && (op->flags & OPF_DATA))
1220 op->regmask_dst = regmask;
1222 op->regmask_src |= regmask;
1223 op->regmask_src |= regmask_ind;
1225 if (op->operand[opr].lmod != OPLM_UNSPEC)
1226 g_func_lmods |= 1 << op->operand[opr].lmod;
1230 aerr("parse_op %s incomplete: %d/%d\n",
1231 words[0], w, wordc);
1234 op->operand_cnt = opr;
1235 if (!strncmp(op_table[i].name, "set", 3))
1236 op->operand[0].lmod = OPLM_BYTE;
1239 // first operand is not dst
1242 op->regmask_src |= op->regmask_dst;
1243 op->regmask_dst = 0;
1246 // first operand is src too
1259 op->regmask_src |= op->regmask_dst;
1264 op->regmask_src |= op->regmask_dst;
1265 op->regmask_dst |= op->regmask_src;
1271 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1272 && op->operand[0].lmod == op->operand[1].lmod
1273 && op->operand[0].reg == op->operand[1].reg
1274 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1276 op->regmask_src = 0;
1279 op->regmask_src |= op->regmask_dst;
1282 // ops with implicit argumets
1284 op->operand_cnt = 2;
1285 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1286 op->regmask_dst = op->regmask_src;
1287 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1291 op->operand_cnt = 2;
1292 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1293 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1299 if (words[op_w][4] == 'b')
1301 else if (words[op_w][4] == 'w')
1303 else if (words[op_w][4] == 'd')
1306 op->regmask_src = 0;
1307 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1308 OPLM_DWORD, &op->regmask_src);
1309 op->regmask_dst = op->regmask_src;
1310 setup_reg_opr(&op->operand[j++], xAX, lmod,
1311 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1312 if (op->flags & OPF_REP) {
1313 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1314 op->regmask_dst |= 1 << xCX;
1316 op->operand_cnt = j;
1321 if (words[op_w][4] == 'b')
1323 else if (words[op_w][4] == 'w')
1325 else if (words[op_w][4] == 'd')
1328 op->regmask_src = 0;
1329 // note: lmod is not correct, don't have where to place it
1330 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1331 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1332 if (op->flags & OPF_REP)
1333 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1334 op->operand_cnt = j;
1335 op->regmask_dst = op->regmask_src;
1339 op->regmask_dst = mxAX | mxDX;
1343 // for now, ignore ecx dep for eax={4,7,b,d}
1344 op->regmask_src = mxAX;
1345 op->regmask_dst = mxAX | mxBX | mxCX | mxDX;
1349 op->regmask_dst = 1 << xCX;
1352 op->operand_cnt = 2;
1353 op->regmask_src = 1 << xCX;
1354 op->operand[1].type = OPT_REG;
1355 op->operand[1].reg = xCX;
1356 op->operand[1].lmod = OPLM_DWORD;
1360 if (op->operand_cnt == 2) {
1361 if (op->operand[0].type != OPT_REG)
1362 aerr("reg expected\n");
1363 op->regmask_src |= 1 << op->operand[0].reg;
1365 if (op->operand_cnt != 1)
1370 if (op->operand[0].lmod == OPLM_UNSPEC)
1371 op->operand[0].lmod = OPLM_DWORD;
1372 op->regmask_src = mxAX | op->regmask_dst;
1373 op->regmask_dst = mxAX;
1374 if (op->operand[0].lmod != OPLM_BYTE)
1375 op->regmask_dst |= mxDX;
1380 // we could set up operands for edx:eax, but there is no real need to
1381 // (see is_opr_modified())
1382 if (op->operand[0].lmod == OPLM_UNSPEC)
1383 op->operand[0].lmod = OPLM_DWORD;
1384 op->regmask_src = mxAX | op->regmask_dst;
1385 op->regmask_dst = mxAX;
1386 if (op->operand[0].lmod != OPLM_BYTE) {
1387 op->regmask_src |= mxDX;
1388 op->regmask_dst |= mxDX;
1397 op->regmask_src |= op->regmask_dst;
1398 if (op->operand[1].lmod == OPLM_UNSPEC)
1399 op->operand[1].lmod = OPLM_BYTE;
1404 op->regmask_src |= op->regmask_dst;
1405 if (op->operand[2].lmod == OPLM_UNSPEC)
1406 op->operand[2].lmod = OPLM_BYTE;
1410 op->regmask_src |= op->regmask_dst;
1411 op->regmask_dst = 0;
1412 if (op->operand[0].lmod == OPLM_UNSPEC
1413 && (op->operand[0].type == OPT_CONST
1414 || op->operand[0].type == OPT_OFFSET
1415 || op->operand[0].type == OPT_LABEL))
1416 op->operand[0].lmod = OPLM_DWORD;
1422 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1423 && op->operand[0].lmod == op->operand[1].lmod
1424 && op->operand[0].reg == op->operand[1].reg
1425 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1427 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1428 op->regmask_src = op->regmask_dst = 0;
1433 if (op->operand[0].type == OPT_REG
1434 && op->operand[1].type == OPT_REGMEM)
1437 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1438 if (IS(buf, op->operand[1].name))
1439 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1444 // needed because of OPF_DATA
1445 op->regmask_src |= op->regmask_dst;
1446 // trashed regs must be explicitly detected later
1447 op->regmask_dst = 0;
1451 op->regmask_dst = (1 << xBP) | (1 << xSP);
1452 op->regmask_src = 1 << xBP;
1457 op->regmask_dst |= mxST0;
1461 op->regmask_dst |= mxST0;
1462 if (IS(words[op_w] + 3, "1"))
1463 op->operand[0].val = X87_CONST_1;
1464 else if (IS(words[op_w] + 3, "l2t"))
1465 op->operand[0].val = X87_CONST_L2T;
1466 else if (IS(words[op_w] + 3, "l2e"))
1467 op->operand[0].val = X87_CONST_L2E;
1468 else if (IS(words[op_w] + 3, "pi"))
1469 op->operand[0].val = X87_CONST_PI;
1470 else if (IS(words[op_w] + 3, "lg2"))
1471 op->operand[0].val = X87_CONST_LG2;
1472 else if (IS(words[op_w] + 3, "ln2"))
1473 op->operand[0].val = X87_CONST_LN2;
1474 else if (IS(words[op_w] + 3, "z"))
1475 op->operand[0].val = X87_CONST_Z;
1477 aerr("fld what?\n");
1482 op->regmask_src |= mxST0;
1491 op->regmask_src |= mxST0;
1492 if (op->operand_cnt == 2)
1493 op->regmask_src |= op->regmask_dst;
1494 else if (op->operand_cnt == 1) {
1495 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1496 op->operand[0].type = OPT_REG;
1497 op->operand[0].lmod = OPLM_QWORD;
1498 op->operand[0].reg = xST0;
1499 op->regmask_dst |= mxST0;
1502 // IDA doesn't use this
1503 aerr("no operands?\n");
1518 op->regmask_src |= mxST0;
1519 op->regmask_dst |= mxST0;
1524 op->regmask_src |= mxST0 | mxST1;
1525 op->regmask_dst |= mxST0;
1533 op->regmask_src |= mxST0;
1534 if (op->operand_cnt == 0) {
1535 op->operand_cnt = 1;
1536 op->operand[0].type = OPT_REG;
1537 op->operand[0].lmod = OPLM_QWORD;
1538 op->operand[0].reg = xST1;
1539 op->regmask_src |= mxST1;
1547 if (op->operand[0].type == OPT_REG
1548 && op->operand[1].type == OPT_CONST)
1550 struct parsed_opr *op1 = &op->operand[1];
1551 if ((op->op == OP_AND && op1->val == 0)
1554 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1555 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1557 op->regmask_src = 0;
1562 static const char *op_name(struct parsed_op *po)
1564 static char buf[16];
1568 if (po->op == OP_JCC || po->op == OP_SCC) {
1570 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1573 strcpy(p, parsed_flag_op_names[po->pfo]);
1577 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1578 if (op_table[i].op == po->op)
1579 return op_table[i].name;
1585 static const char *dump_op(struct parsed_op *po)
1587 static char out[128];
1594 snprintf(out, sizeof(out), "%s", op_name(po));
1595 for (i = 0; i < po->operand_cnt; i++) {
1599 snprintf(p, sizeof(out) - (p - out),
1600 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1601 po->operand[i].name);
1607 static const char *lmod_type_u(struct parsed_op *po,
1608 enum opr_lenmod lmod)
1620 ferr(po, "invalid lmod: %d\n", lmod);
1621 return "(_invalid_)";
1625 static const char *lmod_cast_u(struct parsed_op *po,
1626 enum opr_lenmod lmod)
1638 ferr(po, "invalid lmod: %d\n", lmod);
1639 return "(_invalid_)";
1643 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1644 enum opr_lenmod lmod)
1656 ferr(po, "invalid lmod: %d\n", lmod);
1657 return "(_invalid_)";
1661 static const char *lmod_cast_s(struct parsed_op *po,
1662 enum opr_lenmod lmod)
1674 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1675 return "(_invalid_)";
1679 static const char *lmod_cast(struct parsed_op *po,
1680 enum opr_lenmod lmod, int is_signed)
1683 lmod_cast_s(po, lmod) :
1684 lmod_cast_u(po, lmod);
1687 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1699 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1704 static const char *opr_name(struct parsed_op *po, int opr_num)
1706 if (opr_num >= po->operand_cnt)
1707 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1708 return po->operand[opr_num].name;
1711 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1713 if (opr_num >= po->operand_cnt)
1714 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1715 if (po->operand[opr_num].type != OPT_CONST)
1716 ferr(po, "opr %d: const expected\n", opr_num);
1717 return po->operand[opr_num].val;
1720 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1722 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1723 ferr(po, "invalid reg: %d\n", popr->reg);
1724 return regs_r32[popr->reg];
1727 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1729 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1731 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1733 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1735 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1740 *is_signed = cast[1] == 's' ? 1 : 0;
1744 static int check_deref_cast(const char *cast, int *bits)
1746 if (IS_START(cast, "*(u8 *)"))
1748 else if (IS_START(cast, "*(u16 *)"))
1750 else if (IS_START(cast, "*(u32 *)"))
1752 else if (IS_START(cast, "*(u64 *)"))
1760 // cast1 is the "final" cast
1761 static const char *simplify_cast(const char *cast1, const char *cast2)
1763 static char buf[256];
1771 if (IS(cast1, cast2))
1774 if (check_simple_cast(cast1, &bits1, &s1) == 0
1775 && check_simple_cast(cast2, &bits2, &s2) == 0)
1780 if (check_simple_cast(cast1, &bits1, &s1) == 0
1781 && check_deref_cast(cast2, &bits2) == 0)
1783 if (bits1 == bits2) {
1784 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1789 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1792 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1796 static const char *simplify_cast_num(const char *cast, unsigned int val)
1798 if (IS(cast, "(u8)") && val < 0x100)
1800 if (IS(cast, "(s8)") && val < 0x80)
1802 if (IS(cast, "(u16)") && val < 0x10000)
1804 if (IS(cast, "(s16)") && val < 0x8000)
1806 if (IS(cast, "(s32)") && val < 0x80000000)
1812 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1821 namelen = strlen(name);
1823 p = strpbrk(name, "+-");
1827 ferr(po, "equ parse failed for '%s'\n", name);
1830 *extra_offs = strtol(p, &endp, 16);
1831 if (*endp != 0 || errno != 0)
1832 ferr(po, "equ parse failed for '%s'\n", name);
1835 for (i = 0; i < g_eqcnt; i++)
1836 if (strncmp(g_eqs[i].name, name, namelen) == 0
1837 && g_eqs[i].name[namelen] == 0)
1841 ferr(po, "unresolved equ name: '%s'\n", name);
1848 static int is_stack_access(struct parsed_op *po,
1849 const struct parsed_opr *popr)
1851 return (parse_stack_el(popr->name, NULL, NULL, 0)
1852 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1853 && IS_START(popr->name, "ebp")));
1856 static void parse_stack_access(struct parsed_op *po,
1857 const char *name, char *ofs_reg, int *offset_out,
1858 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1860 const char *bp_arg = "";
1861 const char *p = NULL;
1862 struct parsed_equ *eq;
1869 if (IS_START(name, "ebp-")
1870 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1873 if (IS_START(p, "0x"))
1876 offset = strtoul(p, &endp, 16);
1879 if (*endp != 0 || errno != 0)
1880 ferr(po, "ebp- parse of '%s' failed\n", name);
1883 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1884 eq = equ_find(po, bp_arg, &offset);
1886 ferr(po, "detected but missing eq\n");
1887 offset += eq->offset;
1890 if (!strncmp(name, "ebp", 3))
1893 // yes it sometimes LEAs ra for compares..
1894 if (!is_lea && ofs_reg[0] == 0
1895 && stack_ra <= offset && offset < stack_ra + 4)
1897 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1900 *offset_out = offset;
1902 *stack_ra_out = stack_ra;
1904 *bp_arg_out = bp_arg;
1907 static int parse_stack_esp_offset(struct parsed_op *po,
1908 const char *name, int *offset_out)
1910 char ofs_reg[16] = { 0, };
1911 struct parsed_equ *eq;
1917 if (strstr(name, "esp") == NULL)
1919 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1920 if (bp_arg == NULL) {
1921 // just plain offset?
1922 if (!IS_START(name, "esp+"))
1925 offset = strtol(name + 4, &endp, 0);
1926 if (endp == NULL || *endp != 0 || errno != 0)
1928 *offset_out = offset;
1932 if (ofs_reg[0] != 0)
1934 eq = equ_find(po, bp_arg, &offset);
1936 ferr(po, "detected but missing eq\n");
1937 offset += eq->offset;
1938 *offset_out = base_val + offset;
1942 // returns g_func_pp arg number if arg is accessed
1943 // -1 otherwise (stack vars, va_list)
1944 // note: 'popr' must be from 'po', not some other op
1945 static int stack_frame_access(struct parsed_op *po,
1946 struct parsed_opr *popr, char *buf, size_t buf_size,
1947 const char *name, const char *cast, int is_src, int is_lea)
1949 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1950 const char *prefix = "";
1951 const char *bp_arg = NULL;
1952 char ofs_reg[16] = { 0, };
1954 int i, arg_i, arg_s;
1961 if (g_bp_frame && (po->flags & OPF_EBP_S)
1962 && !(po->regmask_src & mxSP))
1963 ferr(po, "stack_frame_access while ebp is scratch\n");
1965 parse_stack_access(po, name, ofs_reg, &offset,
1966 &stack_ra, &bp_arg, is_lea);
1968 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1970 if (offset > stack_ra)
1972 arg_i = (offset - stack_ra - 4) / 4;
1973 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1975 if (g_func_pp->is_vararg && arg_i == g_func_pp->argc_stack) {
1977 // should be va_list
1980 snprintf(buf, buf_size, "%sap", cast);
1983 snprintf(buf, buf_size, "%sva_arg(ap, u32)", cast);
1986 ferr(po, "offset 0x%x (%s,%d) doesn't map to any arg\n",
1987 offset, bp_arg, arg_i);
1989 if (ofs_reg[0] != 0)
1990 ferr(po, "offset reg on arg access?\n");
1992 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1993 if (g_func_pp->arg[i].reg != NULL)
1999 if (i == g_func_pp->argc)
2000 ferr(po, "arg %d not in prototype?\n", arg_i);
2002 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
2005 snprintf(argname, sizeof(argname), "%sa%d",
2006 g_sct_func_attr & SCTFA_ARGFRAME ? "af." : "", i + 1);
2012 ferr(po, "lea/byte to arg?\n");
2013 if (is_src && (offset & 3) == 0)
2014 snprintf(buf, buf_size, "%s%s",
2015 simplify_cast(cast, "(u8)"), argname);
2017 snprintf(buf, buf_size, "%sBYTE%d(%s)",
2018 cast, offset & 3, argname);
2023 ferr(po, "lea/word to arg?\n");
2028 ferr(po, "problematic arg store\n");
2029 snprintf(buf, buf_size, "%s((char *)&%s + 1)",
2030 simplify_cast(cast, "*(u16 *)"), argname);
2033 ferr(po, "unaligned arg word load\n");
2035 else if (is_src && (offset & 2) == 0)
2036 snprintf(buf, buf_size, "%s%s",
2037 simplify_cast(cast, "(u16)"), argname);
2039 snprintf(buf, buf_size, "%s%sWORD(%s)",
2040 cast, (offset & 2) ? "HI" : "LO", argname);
2052 snprintf(buf, buf_size, "(u32)&%s + %d",
2053 argname, offset & 3);
2055 ferr(po, "unaligned arg store\n");
2057 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
2058 snprintf(buf, buf_size, "%s(%s >> %d)",
2059 prefix, argname, (offset & 3) * 8);
2063 snprintf(buf, buf_size, "%s%s%s",
2064 prefix, is_lea ? "&" : "", argname);
2069 ferr_assert(po, !(offset & 7));
2072 snprintf(buf, buf_size, "%s%s%s",
2073 prefix, is_lea ? "&" : "", argname);
2077 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
2081 strcat(g_comment, " unaligned");
2084 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
2085 if (tmp_lmod != OPLM_DWORD
2086 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
2087 < lmod_bytes(po, popr->lmod) + (offset & 3))))
2089 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
2090 i + 1, offset, g_func_pp->arg[i].type.name);
2092 // can't check this because msvc likes to reuse
2093 // arg space for scratch..
2094 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
2095 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2099 if (g_stack_fsz == 0)
2100 ferr(po, "stack var access without stackframe\n");
2101 g_stack_frame_used = 1;
2103 sf_ofs = g_stack_fsz + offset;
2104 if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2105 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2115 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2116 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2120 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2121 // known unaligned or possibly unaligned
2122 strcat(g_comment, " unaligned");
2124 prefix = "*(u16 *)&";
2125 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2126 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2129 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2133 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2134 // known unaligned or possibly unaligned
2135 strcat(g_comment, " unaligned");
2137 prefix = "*(u32 *)&";
2138 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2139 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2142 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2146 ferr_assert(po, !(sf_ofs & 7));
2147 ferr_assert(po, ofs_reg[0] == 0);
2148 // only used for x87 int64/float, float sets is_lea
2149 if (!is_lea && (po->flags & OPF_FINT))
2150 prefix = "*(s64 *)&";
2151 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2155 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2162 static void check_func_pp(struct parsed_op *po,
2163 const struct parsed_proto *pp, const char *pfx)
2165 enum opr_lenmod tmp_lmod;
2169 if (pp->argc_reg != 0) {
2170 if (!g_allow_user_icall && !pp->is_fastcall) {
2171 pp_print(buf, sizeof(buf), pp);
2172 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2174 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2175 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2176 pfx, pp->argc_reg, pp->argc_stack);
2179 // fptrs must use 32bit args, callsite might have no information and
2180 // lack a cast to smaller types, which results in incorrectly masked
2181 // args passed (callee may assume masked args, it does on ARM)
2182 if (!pp->is_osinc) {
2183 for (i = 0; i < pp->argc; i++) {
2184 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2185 if (ret && tmp_lmod != OPLM_DWORD)
2186 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2187 i + 1, pp->arg[i].type.name);
2192 static const char *check_label_read_ref(struct parsed_op *po,
2193 const char *name, int *is_import)
2195 const struct parsed_proto *pp;
2197 pp = proto_parse(g_fhdr, name, 0);
2199 ferr(po, "proto_parse failed for ref '%s'\n", name);
2202 check_func_pp(po, pp, "ref");
2204 if (is_import != NULL)
2205 *is_import = pp->is_import;
2210 static void check_opr(struct parsed_op *po, struct parsed_opr *popr)
2212 if (popr->segment == SEG_FS)
2213 ferr(po, "fs: used\n");
2214 if (popr->segment == SEG_GS)
2215 ferr(po, "gs: used\n");
2218 static char *out_src_opr(char *buf, size_t buf_size,
2219 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2222 char tmp1[256], tmp2[256];
2229 check_opr(po, popr);
2234 switch (popr->type) {
2237 ferr(po, "lea from reg?\n");
2239 switch (popr->lmod) {
2241 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2244 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2247 snprintf(buf, buf_size, "%s%s",
2248 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2251 if (popr->name[1] == 'h') // XXX..
2252 snprintf(buf, buf_size, "%s(%s >> 8)",
2253 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2255 snprintf(buf, buf_size, "%s%s",
2256 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2259 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2264 if (is_stack_access(po, popr)) {
2265 stack_frame_access(po, popr, buf, buf_size,
2266 popr->name, cast, 1, is_lea);
2270 strcpy(expr, popr->name);
2271 if (strchr(expr, '[')) {
2272 // special case: '[' can only be left for label[reg] form
2273 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2275 ferr(po, "parse failure for '%s'\n", expr);
2276 if (tmp1[0] == '(') {
2277 // (off_4FFF50+3)[eax]
2278 p = strchr(tmp1 + 1, ')');
2279 if (p == NULL || p[1] != 0)
2280 ferr(po, "parse failure (2) for '%s'\n", expr);
2282 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2284 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2287 // XXX: do we need more parsing?
2289 snprintf(buf, buf_size, "%s", expr);
2293 snprintf(buf, buf_size, "%s(%s)",
2294 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2298 name = check_label_read_ref(po, popr->name, &is_import);
2300 // for imported data, asm is loading the offset
2303 if (cast[0] == 0 && popr->is_ptr)
2307 snprintf(buf, buf_size, "(u32)&%s", name);
2308 else if (popr->size_lt)
2309 snprintf(buf, buf_size, "%s%s%s%s", cast,
2310 lmod_cast_u_ptr(po, popr->lmod),
2311 popr->is_array ? "" : "&", name);
2313 snprintf(buf, buf_size, "%s%s%s", cast, name,
2314 popr->is_array ? "[0]" : "");
2319 name = check_label_read_ref(po, popr->name, NULL);
2323 ferr(po, "lea an offset?\n");
2324 snprintf(buf, buf_size, "%s&%s", cast, name);
2329 ferr(po, "lea from const?\n");
2331 printf_number(tmp1, sizeof(tmp1), popr->val);
2332 if (popr->val == 0 && strchr(cast, '*'))
2333 snprintf(buf, buf_size, "NULL");
2335 snprintf(buf, buf_size, "%s%s",
2336 simplify_cast_num(cast, popr->val), tmp1);
2340 ferr(po, "invalid src type: %d\n", popr->type);
2346 // note: may set is_ptr (we find that out late for ebp frame..)
2347 static char *out_dst_opr(char *buf, size_t buf_size,
2348 struct parsed_op *po, struct parsed_opr *popr)
2350 check_opr(po, popr);
2352 switch (popr->type) {
2354 switch (popr->lmod) {
2356 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2359 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2363 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2367 if (popr->name[1] == 'h') // XXX..
2368 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2370 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2373 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2378 if (is_stack_access(po, popr)) {
2379 stack_frame_access(po, popr, buf, buf_size,
2380 popr->name, "", 0, 0);
2384 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2387 if (popr->size_mismatch)
2388 snprintf(buf, buf_size, "%s%s%s",
2389 lmod_cast_u_ptr(po, popr->lmod),
2390 popr->is_array ? "" : "&", popr->name);
2392 snprintf(buf, buf_size, "%s%s", popr->name,
2393 popr->is_array ? "[0]" : "");
2397 ferr(po, "invalid dst type: %d\n", popr->type);
2403 static char *out_src_opr_u32(char *buf, size_t buf_size,
2404 struct parsed_op *po, struct parsed_opr *popr)
2406 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2409 static char *out_opr_float(char *buf, size_t buf_size,
2410 struct parsed_op *po, struct parsed_opr *popr, int is_src,
2411 int need_float_stack)
2413 const char *cast = NULL;
2420 switch (popr->type) {
2422 if (popr->reg < xST0 || popr->reg > xST7) {
2424 ferr_assert(po, po->op == OP_PUSH);
2425 ferr_assert(po, popr->lmod == OPLM_DWORD);
2426 snprintf(buf, buf_size, "*(float *)&%s", opr_reg_p(po, popr));
2430 if (need_float_stack) {
2431 if (popr->reg == xST0)
2432 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2434 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2438 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2442 if (popr->lmod == OPLM_QWORD && is_stack_access(po, popr)) {
2443 stack_frame_access(po, popr, buf, buf_size,
2444 popr->name, "", is_src, 0);
2450 switch (popr->lmod) {
2458 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2461 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2462 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2466 // only for func float args pushes
2467 ferr_assert(po, po->op == OP_PUSH);
2468 u.i = po->operand[0].val;
2469 if (ceilf(u.f) == u.f)
2470 snprintf(buf, buf_size, "%.1ff", u.f);
2472 snprintf(buf, buf_size, "%.8ff", u.f);
2476 ferr(po, "invalid float type: %d\n", popr->type);
2482 static char *out_src_opr_float(char *buf, size_t buf_size,
2483 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2485 return out_opr_float(buf, buf_size, po, popr, 1, need_float_stack);
2488 static char *out_dst_opr_float(char *buf, size_t buf_size,
2489 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2491 return out_opr_float(buf, buf_size, po, popr, 0, need_float_stack);
2494 static void out_test_for_cc(char *buf, size_t buf_size,
2495 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2496 enum opr_lenmod lmod, const char *expr)
2498 const char *cast, *scast;
2500 cast = lmod_cast_u(po, lmod);
2501 scast = lmod_cast_s(po, lmod);
2505 case PFO_BE: // CF==1||ZF==1; CF=0
2506 snprintf(buf, buf_size, "(%s%s %s 0)",
2507 cast, expr, is_inv ? "!=" : "==");
2511 case PFO_L: // SF!=OF; OF=0
2512 snprintf(buf, buf_size, "(%s%s %s 0)",
2513 scast, expr, is_inv ? ">=" : "<");
2516 case PFO_LE: // ZF==1||SF!=OF; OF=0
2517 snprintf(buf, buf_size, "(%s%s %s 0)",
2518 scast, expr, is_inv ? ">" : "<=");
2523 snprintf(buf, buf_size, "(%d)", !!is_inv);
2526 case PFO_P: // PF==1
2527 snprintf(buf, buf_size, "(%sdo_parity(%s))",
2528 is_inv ? "!" : "", expr);
2532 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2536 static void out_cmp_for_cc(char *buf, size_t buf_size,
2537 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2540 const char *cast, *scast, *cast_use;
2541 char buf1[256], buf2[256];
2542 enum opr_lenmod lmod;
2544 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2545 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2546 po->operand[0].lmod, po->operand[1].lmod);
2547 lmod = po->operand[0].lmod;
2549 cast = lmod_cast_u(po, lmod);
2550 scast = lmod_cast_s(po, lmod);
2566 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2569 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2570 if (po->op == OP_DEC)
2571 snprintf(buf2, sizeof(buf2), "1");
2574 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2576 strcat(cast_op2, "-");
2577 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2582 // note: must be unsigned compare
2583 snprintf(buf, buf_size, "(%s %s %s)",
2584 buf1, is_inv ? ">=" : "<", buf2);
2588 snprintf(buf, buf_size, "(%s %s %s)",
2589 buf1, is_inv ? "!=" : "==", buf2);
2593 // note: must be unsigned compare
2594 snprintf(buf, buf_size, "(%s %s %s)",
2595 buf1, is_inv ? ">" : "<=", buf2);
2598 if (is_inv && lmod == OPLM_BYTE
2599 && po->operand[1].type == OPT_CONST
2600 && po->operand[1].val == 0xff)
2602 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2603 snprintf(buf, buf_size, "(0)");
2607 // note: must be signed compare
2609 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2610 scast, buf1, buf2, is_inv ? ">=" : "<");
2614 snprintf(buf, buf_size, "(%s %s %s)",
2615 buf1, is_inv ? ">=" : "<", buf2);
2619 snprintf(buf, buf_size, "(%s %s %s)",
2620 buf1, is_inv ? ">" : "<=", buf2);
2628 static void out_cmp_test(char *buf, size_t buf_size,
2629 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2631 char buf1[256], buf2[256], buf3[256];
2633 if (po->op == OP_TEST) {
2634 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2635 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2638 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2639 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2640 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2642 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2643 po->operand[0].lmod, buf3);
2645 else if (po->op == OP_CMP) {
2646 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2649 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2652 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2653 struct parsed_opr *popr2)
2655 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2656 ferr(po, "missing lmod for both operands\n");
2658 if (popr1->lmod == OPLM_UNSPEC)
2659 popr1->lmod = popr2->lmod;
2660 else if (popr2->lmod == OPLM_UNSPEC)
2661 popr2->lmod = popr1->lmod;
2662 else if (popr1->lmod != popr2->lmod) {
2663 if (popr1->type_from_var) {
2664 popr1->size_mismatch = 1;
2665 if (popr1->lmod < popr2->lmod)
2667 popr1->lmod = popr2->lmod;
2669 else if (popr2->type_from_var) {
2670 popr2->size_mismatch = 1;
2671 if (popr2->lmod < popr1->lmod)
2673 popr2->lmod = popr1->lmod;
2676 ferr(po, "conflicting lmods: %d vs %d\n",
2677 popr1->lmod, popr2->lmod);
2681 static const char *op_to_c(struct parsed_op *po)
2705 ferr(po, "op_to_c was supplied with %d\n", po->op);
2709 // last op in stream - unconditional branch or ret
2710 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2711 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2712 && ops[_i].op != OP_CALL))
2714 #define check_i(po, i) \
2716 ferr(po, "bad " #i ": %d\n", i)
2718 // note: this skips over calls and rm'd stuff assuming they're handled
2719 // so it's intended to use at one of final passes
2720 // exception: doesn't skip OPF_RSAVE stuff
2721 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2722 int depth, int seen_noreturn, int save_level, int flags_set)
2724 struct parsed_op *po;
2729 for (; i < opcnt; i++) {
2731 if (po->cc_scratch == magic)
2732 return ret; // already checked
2733 po->cc_scratch = magic;
2735 if (po->flags & OPF_TAIL) {
2736 if (po->op == OP_CALL && po->pp != NULL && po->pp->is_noreturn) {
2737 // msvc sometimes generates stack cleanup code after
2738 // noreturn, set a flag and continue
2741 // ... but stop if there is another path to next insn -
2742 // if msvc skipped something stack tracking may mess up
2743 if (i + 1 < opcnt && g_labels[i + 1] != NULL)
2750 if (po->flags & OPF_FARG)
2752 if (po->flags & (OPF_RMD|OPF_DONE)) {
2753 if (!(po->flags & OPF_RSAVE))
2755 // reprocess, there might be another push in some "parallel"
2756 // path that took a pop what we should also take
2759 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2760 if (po->btj != NULL) {
2762 for (j = 0; j < po->btj->count; j++) {
2763 check_i(po, po->btj->d[j].bt_i);
2764 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2765 depth, seen_noreturn, save_level, flags_set);
2767 return ret; // dead end
2772 check_i(po, po->bt_i);
2773 if (po->flags & OPF_CJMP) {
2774 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2775 depth, seen_noreturn, save_level, flags_set);
2777 return ret; // dead end
2786 if ((po->op == OP_POP || po->op == OP_PUSH)
2787 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2792 if (po->op == OP_PUSH) {
2795 else if (po->op == OP_POP) {
2796 if (relevant && depth == 0) {
2797 if (flags_set == 0 && save_level > 0) {
2798 ret = scan_for_pop(i + 1, opcnt, magic, reg,
2799 depth, seen_noreturn, save_level - 1, flags_set);
2801 // no pop for other levels, current one must be false
2804 po->flags |= flags_set;
2812 // for noreturn, assume msvc skipped stack cleanup
2813 return seen_noreturn ? 1 : -1;
2816 // scan for 'reg' pop backwards starting from i
2817 // intended to use for register restore search, so other reg
2818 // references are considered an error
2819 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2821 struct parsed_op *po;
2822 struct label_ref *lr;
2825 ops[i].cc_scratch = magic;
2829 if (g_labels[i] != NULL) {
2830 lr = &g_label_refs[i];
2831 for (; lr != NULL; lr = lr->next) {
2832 check_i(&ops[i], lr->i);
2833 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2837 if (i > 0 && LAST_OP(i - 1))
2845 if (ops[i].cc_scratch == magic)
2847 ops[i].cc_scratch = magic;
2850 if (po->op == OP_POP && po->operand[0].reg == reg) {
2851 if (po->flags & (OPF_RMD|OPF_DONE))
2854 po->flags |= set_flags;
2858 // this also covers the case where we reach corresponding push
2859 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2863 // nothing interesting on this path,
2864 // still return ret for something recursive calls could find
2868 static void find_reachable_exits(int i, int opcnt, int magic,
2869 int *exits, int *exit_count)
2871 struct parsed_op *po;
2874 for (; i < opcnt; i++)
2877 if (po->cc_scratch == magic)
2879 po->cc_scratch = magic;
2881 if (po->flags & OPF_TAIL) {
2882 ferr_assert(po, *exit_count < MAX_EXITS);
2883 exits[*exit_count] = i;
2888 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2889 if (po->flags & OPF_RMD)
2892 if (po->btj != NULL) {
2893 for (j = 0; j < po->btj->count; j++) {
2894 check_i(po, po->btj->d[j].bt_i);
2895 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2901 check_i(po, po->bt_i);
2902 if (po->flags & OPF_CJMP)
2903 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2911 // scan for 'reg' pop backwards starting from exits (all paths)
2912 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2914 static int exits[MAX_EXITS];
2915 static int exit_count;
2921 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2923 ferr_assert(&ops[i], exit_count > 0);
2926 for (j = 0; j < exit_count; j++) {
2928 ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2934 if (ops[e].op == OP_CALL && ops[e].pp != NULL
2935 && ops[e].pp->is_noreturn)
2937 // assume stack cleanup was skipped
2946 // scan for one or more pop of push <const>
2947 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2948 int push_i, int is_probe)
2950 struct parsed_op *po;
2951 struct label_ref *lr;
2955 for (; i < opcnt; i++)
2958 if (po->cc_scratch == magic)
2959 return ret; // already checked
2960 po->cc_scratch = magic;
2962 if (po->flags & OPF_JMP) {
2963 if (po->flags & OPF_RMD)
2965 if (po->op == OP_CALL)
2968 if (po->btj != NULL) {
2969 for (j = 0; j < po->btj->count; j++) {
2970 check_i(po, po->btj->d[j].bt_i);
2971 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2979 check_i(po, po->bt_i);
2980 if (po->flags & OPF_CJMP) {
2981 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2992 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2995 if (g_labels[i] != NULL) {
2996 // all refs must be visited
2997 lr = &g_label_refs[i];
2998 for (; lr != NULL; lr = lr->next) {
3000 if (ops[lr->i].cc_scratch != magic)
3003 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
3007 if (po->op == OP_POP)
3009 if (po->flags & (OPF_RMD|OPF_DONE))
3013 po->flags |= OPF_DONE;
3014 po->datap = &ops[push_i];
3023 static void scan_for_pop_const(int i, int opcnt, int magic)
3027 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
3029 ops[i].flags |= OPF_RMD | OPF_DONE;
3030 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
3034 // check if all branch targets within a marked path are also marked
3035 // note: the path checked must not be empty or end with a branch
3036 static int check_path_branches(int opcnt, int magic)
3038 struct parsed_op *po;
3041 for (i = 0; i < opcnt; i++) {
3043 if (po->cc_scratch != magic)
3046 if (po->flags & OPF_JMP) {
3047 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
3050 if (po->btj != NULL) {
3051 for (j = 0; j < po->btj->count; j++) {
3052 check_i(po, po->btj->d[j].bt_i);
3053 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
3058 check_i(po, po->bt_i);
3059 if (ops[po->bt_i].cc_scratch != magic)
3061 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
3069 // scan for multiple pushes for given pop
3070 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
3073 int reg = ops[pop_i].operand[0].reg;
3074 struct parsed_op *po;
3075 struct label_ref *lr;
3078 ops[i].cc_scratch = magic;
3082 if (g_labels[i] != NULL) {
3083 lr = &g_label_refs[i];
3084 for (; lr != NULL; lr = lr->next) {
3085 check_i(&ops[i], lr->i);
3086 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
3090 if (i > 0 && LAST_OP(i - 1))
3098 if (ops[i].cc_scratch == magic)
3100 ops[i].cc_scratch = magic;
3103 if (po->op == OP_CALL)
3105 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
3108 if (po->op == OP_PUSH)
3110 if (po->datap != NULL)
3112 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
3113 // leave this case for reg save/restore handlers
3117 po->flags |= OPF_PPUSH | OPF_DONE;
3118 po->datap = &ops[pop_i];
3127 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
3129 int magic = i + opcnt * 14;
3132 ret = scan_pushes_for_pop_r(i, magic, i, 1);
3134 ret = check_path_branches(opcnt, magic);
3136 ops[i].flags |= OPF_PPUSH | OPF_DONE;
3137 *regmask_pp |= 1 << ops[i].operand[0].reg;
3138 scan_pushes_for_pop_r(i, magic + 1, i, 0);
3143 static void scan_propagate_df(int i, int opcnt)
3145 struct parsed_op *po = &ops[i];
3148 for (; i < opcnt; i++) {
3150 if (po->flags & OPF_DF)
3151 return; // already resolved
3152 po->flags |= OPF_DF;
3154 if (po->op == OP_CALL)
3155 ferr(po, "call with DF set?\n");
3157 if (po->flags & OPF_JMP) {
3158 if (po->btj != NULL) {
3160 for (j = 0; j < po->btj->count; j++) {
3161 check_i(po, po->btj->d[j].bt_i);
3162 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
3167 if (po->flags & OPF_RMD)
3169 check_i(po, po->bt_i);
3170 if (po->flags & OPF_CJMP)
3171 scan_propagate_df(po->bt_i, opcnt);
3177 if (po->flags & OPF_TAIL)
3180 if (po->op == OP_CLD) {
3181 po->flags |= OPF_RMD | OPF_DONE;
3186 ferr(po, "missing DF clear?\n");
3189 // is operand 'opr' referenced by parsed_op 'po'?
3190 static int is_opr_referenced(const struct parsed_opr *opr,
3191 const struct parsed_op *po)
3195 if (opr->type == OPT_REG) {
3196 mask = po->regmask_dst | po->regmask_src;
3197 if (po->op == OP_CALL)
3198 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3199 if ((1 << opr->reg) & mask)
3205 for (i = 0; i < po->operand_cnt; i++)
3206 if (IS(po->operand[0].name, opr->name))
3212 // is operand 'opr' read by parsed_op 'po'?
3213 static int is_opr_read(const struct parsed_opr *opr,
3214 const struct parsed_op *po)
3216 if (opr->type == OPT_REG) {
3217 if (po->regmask_src & (1 << opr->reg))
3227 // is operand 'opr' modified by parsed_op 'po'?
3228 static int is_opr_modified(const struct parsed_opr *opr,
3229 const struct parsed_op *po)
3233 if (opr->type == OPT_REG) {
3234 if (po->op == OP_CALL) {
3235 mask = po->regmask_dst;
3236 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3237 if (mask & (1 << opr->reg))
3243 if (po->regmask_dst & (1 << opr->reg))
3249 return IS(po->operand[0].name, opr->name);
3252 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3253 static int is_any_opr_modified(const struct parsed_op *po_test,
3254 const struct parsed_op *po, int c_mode)
3259 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3262 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3265 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3268 // in reality, it can wreck any register, but in decompiled C
3269 // version it can only overwrite eax or edx:eax
3270 mask = (1 << xAX) | (1 << xDX);
3274 if (po->op == OP_CALL
3275 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3278 for (i = 0; i < po_test->operand_cnt; i++)
3279 if (IS(po_test->operand[i].name, po->operand[0].name))
3285 // scan for any po_test operand modification in range given
3286 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3289 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3292 for (; i < opcnt; i++) {
3293 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3300 // scan for po_test operand[0] modification in range given
3301 static int scan_for_mod_opr0(struct parsed_op *po_test,
3304 for (; i < opcnt; i++) {
3305 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3312 static int try_resolve_const(int i, const struct parsed_opr *opr,
3313 int magic, unsigned int *val);
3315 static int scan_for_flag_set(int i, int opcnt, int magic,
3316 int *branched, int *setters, int *setter_cnt)
3318 struct label_ref *lr;
3322 if (ops[i].cc_scratch == magic) {
3323 // is this a problem?
3324 //ferr(&ops[i], "%s looped\n", __func__);
3327 ops[i].cc_scratch = magic;
3329 if (g_labels[i] != NULL) {
3332 lr = &g_label_refs[i];
3333 for (; lr->next; lr = lr->next) {
3334 check_i(&ops[i], lr->i);
3335 ret = scan_for_flag_set(lr->i, opcnt, magic,
3336 branched, setters, setter_cnt);
3341 check_i(&ops[i], lr->i);
3342 if (i > 0 && LAST_OP(i - 1)) {
3346 ret = scan_for_flag_set(lr->i, opcnt, magic,
3347 branched, setters, setter_cnt);
3353 if (ops[i].flags & OPF_FLAGS) {
3354 setters[*setter_cnt] = i;
3357 if (ops[i].flags & OPF_REP) {
3358 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3361 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3362 if (ret != 1 || uval == 0) {
3363 // can't treat it as full setter because of ecx=0 case,
3364 // also disallow delayed compare
3373 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3380 // scan back for cdq, if anything modifies edx, fail
3381 static int scan_for_cdq_edx(int i)
3384 if (g_labels[i] != NULL) {
3385 if (g_label_refs[i].next != NULL)
3387 if (i > 0 && LAST_OP(i - 1)) {
3388 i = g_label_refs[i].i;
3395 if (ops[i].op == OP_CDQ)
3398 if (ops[i].regmask_dst & (1 << xDX))
3405 static int scan_for_reg_clear(int i, int reg)
3408 if (g_labels[i] != NULL) {
3409 if (g_label_refs[i].next != NULL)
3411 if (i > 0 && LAST_OP(i - 1)) {
3412 i = g_label_refs[i].i;
3419 if (ops[i].op == OP_XOR
3420 && ops[i].operand[0].lmod == OPLM_DWORD
3421 && ops[i].operand[0].reg == ops[i].operand[1].reg
3422 && ops[i].operand[0].reg == reg)
3425 if (ops[i].regmask_dst & (1 << reg))
3432 static void patch_esp_adjust(struct parsed_op *po, int adj)
3434 ferr_assert(po, po->op == OP_ADD);
3435 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3436 ferr_assert(po, po->operand[1].type == OPT_CONST);
3438 // this is a bit of a hack, but deals with use of
3439 // single adj for multiple calls
3440 po->operand[1].val -= adj;
3441 po->flags |= OPF_RMD;
3442 if (po->operand[1].val == 0)
3443 po->flags |= OPF_DONE;
3444 ferr_assert(po, (int)po->operand[1].val >= 0);
3447 // scan for positive, constant esp adjust
3448 // multipath case is preliminary
3449 static int scan_for_esp_adjust(int i, int opcnt,
3450 int adj_expect, int *adj, int *is_multipath, int do_update)
3452 int adj_expect_unknown = 0;
3453 struct parsed_op *po;
3457 *adj = *is_multipath = 0;
3458 if (adj_expect < 0) {
3459 adj_expect_unknown = 1;
3460 adj_expect = 32 * 4; // enough?
3463 for (; i < opcnt && *adj < adj_expect; i++) {
3464 if (g_labels[i] != NULL)
3468 if (po->flags & OPF_DONE)
3471 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3472 if (po->operand[1].type != OPT_CONST)
3473 ferr(&ops[i], "non-const esp adjust?\n");
3474 *adj += po->operand[1].val;
3476 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3479 patch_esp_adjust(po, adj_expect);
3481 po->flags |= OPF_RMD;
3485 else if (po->op == OP_PUSH) {
3486 //if (first_pop == -1)
3487 // first_pop = -2; // none
3488 *adj -= lmod_bytes(po, po->operand[0].lmod);
3490 else if (po->op == OP_POP) {
3491 if (!(po->flags & OPF_DONE)) {
3492 // seems like msvc only uses 'pop ecx' for stack realignment..
3493 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3495 if (first_pop == -1 && *adj >= 0)
3498 if (do_update && *adj >= 0) {
3499 po->flags |= OPF_RMD;
3501 po->flags |= OPF_DONE | OPF_NOREGS;
3504 *adj += lmod_bytes(po, po->operand[0].lmod);
3505 if (*adj > adj_best)
3508 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3509 if (po->op == OP_JMP && po->btj == NULL) {
3515 if (po->op != OP_CALL)
3517 if (po->operand[0].type != OPT_LABEL)
3519 if (po->pp != NULL && po->pp->is_stdcall)
3521 if (adj_expect_unknown && first_pop >= 0)
3523 // assume it's another cdecl call
3527 if (first_pop >= 0) {
3528 // probably only 'pop ecx' was used
3536 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3538 struct parsed_op *po;
3542 ferr(ops, "%s: followed bad branch?\n", __func__);
3544 for (; i < opcnt; i++) {
3546 if (po->cc_scratch == magic)
3548 po->cc_scratch = magic;
3551 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3552 if (po->btj != NULL) {
3554 for (j = 0; j < po->btj->count; j++)
3555 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3559 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3560 if (!(po->flags & OPF_CJMP))
3563 if (po->flags & OPF_TAIL)
3568 static const struct parsed_proto *try_recover_pp(
3569 struct parsed_op *po, const struct parsed_opr *opr,
3570 int is_call, int *search_instead)
3572 const struct parsed_proto *pp = NULL;
3576 if (po->pp != NULL && (po->flags & OPF_DATA)) {
3577 // hint given in asm
3581 // maybe an arg of g_func?
3582 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3584 char ofs_reg[16] = { 0, };
3585 int arg, arg_s, arg_i;
3592 parse_stack_access(po, opr->name, ofs_reg,
3593 &offset, &stack_ra, NULL, 0);
3594 if (ofs_reg[0] != 0)
3595 ferr(po, "offset reg on arg access?\n");
3596 if (offset <= stack_ra) {
3597 // search who set the stack var instead
3598 if (search_instead != NULL)
3599 *search_instead = 1;
3603 arg_i = (offset - stack_ra - 4) / 4;
3604 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3605 if (g_func_pp->arg[arg].reg != NULL)
3611 if (arg == g_func_pp->argc)
3612 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3614 pp = g_func_pp->arg[arg].pp;
3617 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3618 check_func_pp(po, pp, "icall arg");
3621 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3623 p = strchr(opr->name + 1, '[');
3624 memcpy(buf, opr->name, p - opr->name);
3625 buf[p - opr->name] = 0;
3626 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3628 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3629 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3632 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3635 check_func_pp(po, pp, "reg-fptr ref");
3641 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3642 int magic, int is_call_op, const struct parsed_proto **pp_found,
3643 int *pp_i, int *multi)
3645 const struct parsed_proto *pp = NULL;
3646 struct parsed_op *po;
3647 struct label_ref *lr;
3649 ops[i].cc_scratch = magic;
3652 if (g_labels[i] != NULL) {
3653 lr = &g_label_refs[i];
3654 for (; lr != NULL; lr = lr->next) {
3655 check_i(&ops[i], lr->i);
3656 scan_for_call_type(lr->i, opr, magic, is_call_op,
3657 pp_found, pp_i, multi);
3659 if (i > 0 && LAST_OP(i - 1))
3667 if (ops[i].cc_scratch == magic)
3669 ops[i].cc_scratch = magic;
3671 if (!(ops[i].flags & OPF_DATA))
3673 if (!is_opr_modified(opr, &ops[i]))
3675 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3676 // most probably trashed by some processing
3681 opr = &ops[i].operand[1];
3682 if (opr->type != OPT_REG)
3686 po = (i >= 0) ? &ops[i] : ops;
3689 // reached the top - can only be an arg-reg
3690 if (opr->type != OPT_REG || g_func_pp == NULL)
3693 for (i = 0; i < g_func_pp->argc; i++) {
3694 if (g_func_pp->arg[i].reg == NULL)
3696 if (IS(opr->name, g_func_pp->arg[i].reg))
3699 if (i == g_func_pp->argc)
3701 pp = g_func_pp->arg[i].pp;
3704 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3705 i + 1, g_func_pp->arg[i].reg);
3708 check_func_pp(po, pp, "icall reg-arg");
3711 pp = try_recover_pp(po, opr, is_call_op, NULL);
3713 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3714 if (pp_cmp_func(*pp_found, pp)) {
3715 if (pp_i != NULL && *pp_i != -1)
3716 fnote(&ops[*pp_i], "(other ref)\n");
3717 ferr(po, "icall: parsed_proto mismatch\n");
3729 static void add_label_ref(struct label_ref *lr, int op_i)
3731 struct label_ref *lr_new;
3738 lr_new = calloc(1, sizeof(*lr_new));
3740 lr_new->next = lr->next;
3744 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3746 struct parsed_op *po = &ops[i];
3747 struct parsed_data *pd;
3748 char label[NAMELEN], *p;
3751 p = strchr(po->operand[0].name, '[');
3755 len = p - po->operand[0].name;
3756 strncpy(label, po->operand[0].name, len);
3759 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3760 if (IS(g_func_pd[j].label, label)) {
3766 //ferr(po, "label '%s' not parsed?\n", label);
3769 if (pd->type != OPT_OFFSET)
3770 ferr(po, "label '%s' with non-offset data?\n", label);
3772 // find all labels, link
3773 for (j = 0; j < pd->count; j++) {
3774 for (l = 0; l < opcnt; l++) {
3775 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3776 add_label_ref(&g_label_refs[l], i);
3786 static void clear_labels(int count)
3790 for (i = 0; i < count; i++) {
3791 if (g_labels[i] != NULL) {
3798 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3803 for (i = 0; i < pp->argc; i++) {
3804 if (pp->arg[i].reg != NULL) {
3805 reg = char_array_i(regs_r32,
3806 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3808 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3809 pp->arg[i].reg, pp->name);
3810 regmask |= 1 << reg;
3817 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3822 if (pp->has_retreg) {
3823 for (i = 0; i < pp->argc; i++) {
3824 if (pp->arg[i].type.is_retreg) {
3825 reg = char_array_i(regs_r32,
3826 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3827 ferr_assert(ops, reg >= 0);
3828 regmask |= 1 << reg;
3833 if (strstr(pp->ret_type.name, "int64"))
3834 return regmask | (1 << xAX) | (1 << xDX);
3835 if (IS(pp->ret_type.name, "float")
3836 || IS(pp->ret_type.name, "double"))
3838 return regmask | mxST0;
3840 if (strcasecmp(pp->ret_type.name, "void") == 0)
3843 return regmask | mxAX;
3846 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3848 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3849 && memcmp(po1->operand, po2->operand,
3850 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3853 static void resolve_branches_parse_calls(int opcnt)
3855 static const struct {
3859 unsigned int regmask_src;
3860 unsigned int regmask_dst;
3862 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3863 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3864 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3865 // more precise? Wine gets away with just __ftol handler
3866 { "__ftol2", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3867 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3869 const struct parsed_proto *pp_c;
3870 struct parsed_proto *pp;
3871 struct parsed_data *pd;
3872 struct parsed_op *po;
3873 const char *tmpname;
3878 for (i = 0; i < opcnt; i++)
3884 if (po->datap != NULL) {
3885 pp = calloc(1, sizeof(*pp));
3886 my_assert_not(pp, NULL);
3888 ret = parse_protostr(po->datap, pp);
3890 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3896 if (po->op == OP_CALL) {
3901 else if (po->operand[0].type == OPT_LABEL)
3903 tmpname = opr_name(po, 0);
3904 if (IS_START(tmpname, "loc_")) {
3906 ferr(po, "call to loc_*\n");
3907 // eliminate_seh() must take care of it
3910 if (IS(tmpname, "__alloca_probe"))
3912 if (IS(tmpname, "__SEH_prolog")) {
3913 ferr_assert(po, g_seh_found == 0);
3917 if (IS(tmpname, "__SEH_epilog"))
3920 // convert some calls to pseudo-ops
3921 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3922 if (!IS(tmpname, pseudo_ops[l].name))
3925 po->op = pseudo_ops[l].op;
3926 po->operand_cnt = 0;
3927 po->regmask_src = pseudo_ops[l].regmask_src;
3928 po->regmask_dst = pseudo_ops[l].regmask_dst;
3929 po->flags &= OPF_TAIL;
3930 po->flags |= pseudo_ops[l].flags;
3931 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3934 if (l < ARRAY_SIZE(pseudo_ops))
3937 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3938 if (!g_header_mode && pp_c == NULL)
3939 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3942 pp = proto_clone(pp_c);
3943 my_assert_not(pp, NULL);
3949 check_func_pp(po, pp, "fptr var call");
3950 if (pp->is_noreturn) {
3951 po->flags |= OPF_TAIL;
3952 po->flags &= ~OPF_ATAIL; // most likely...
3959 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3962 if (po->operand[0].type == OPT_REGMEM) {
3963 pd = try_resolve_jumptab(i, opcnt);
3971 for (l = 0; l < opcnt; l++) {
3972 if (g_labels[l] != NULL
3973 && IS(po->operand[0].name, g_labels[l]))
3975 if (l == i + 1 && po->op == OP_JMP) {
3976 // yet another alignment type...
3977 po->flags |= OPF_RMD | OPF_DONE;
3978 po->flags &= ~OPF_JMP;
3982 add_label_ref(&g_label_refs[l], i);
3988 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3991 if (po->operand[0].type == OPT_LABEL
3992 || po->operand[0].type == OPT_REG)
3996 ferr(po, "unhandled branch\n");
4000 po->flags |= OPF_TAIL;
4001 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
4002 if (prev_op == OP_POP)
4003 po->flags |= OPF_ATAIL;
4004 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
4005 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
4007 po->flags |= OPF_ATAIL;
4013 static int resolve_origin(int i, const struct parsed_opr *opr,
4014 int magic, int *op_i, int *is_caller);
4015 static void set_label(int i, const char *name);
4017 static void eliminate_seh_writes(int opcnt)
4019 const struct parsed_opr *opr;
4024 // assume all sf writes above g_seh_size to be seh related
4025 // (probably unsafe but oh well)
4026 for (i = 0; i < opcnt; i++) {
4027 if (ops[i].op != OP_MOV)
4029 opr = &ops[i].operand[0];
4030 if (opr->type != OPT_REGMEM)
4032 if (!is_stack_access(&ops[i], opr))
4036 parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
4038 if (offset < 0 && offset >= -g_seh_size)
4039 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4043 static void eliminate_seh_finally(int opcnt)
4045 const char *target_name = NULL;
4046 const char *return_name = NULL;
4047 int exits[MAX_EXITS];
4055 for (i = 0; i < opcnt; i++) {
4056 if (ops[i].op != OP_CALL)
4058 if (!IS_START(opr_name(&ops[i], 0), "loc_"))
4060 if (target_name != NULL)
4061 ferr(&ops[i], "multiple finally calls? (last was %s)\n",
4063 target_name = opr_name(&ops[i], 0);
4066 if (g_labels[i + 1] == NULL)
4067 set_label(i + 1, "seh_fin_done");
4068 return_name = g_labels[i + 1];
4076 // find finally code (bt_i is not set because it's call)
4077 for (i = 0; i < opcnt; i++) {
4078 if (g_labels[i] == NULL)
4080 if (!IS(g_labels[i], target_name))
4083 ferr_assert(&ops[i], target_i == -1);
4086 ferr_assert(&ops[0], target_i != -1);
4088 find_reachable_exits(target_i, opcnt, target_i + opcnt * 24,
4089 exits, &exit_count);
4090 ferr_assert(&ops[target_i], exit_count == 1);
4091 ferr_assert(&ops[target_i], ops[exits[0]].op == OP_RET);
4094 // convert to jumps, link
4095 ops[call_i].op = OP_JMP;
4096 ops[call_i].bt_i = target_i;
4097 add_label_ref(&g_label_refs[target_i], call_i);
4099 ops[tgend_i].op = OP_JMP;
4100 ops[tgend_i].flags &= ~OPF_TAIL;
4101 ops[tgend_i].flags |= OPF_JMP;
4102 ops[tgend_i].bt_i = return_i;
4103 ops[tgend_i].operand_cnt = 1;
4104 ops[tgend_i].operand[0].type = OPT_LABEL;
4105 snprintf(ops[tgend_i].operand[0].name, NAMELEN, "%s", return_name);
4106 add_label_ref(&g_label_refs[return_i], tgend_i);
4108 // rm seh finally entry code
4109 for (i = target_i - 1; i >= 0; i--) {
4110 if (g_labels[i] != NULL && g_label_refs[i].i != -1)
4112 if (ops[i].flags & OPF_CJMP)
4114 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4117 for (i = target_i - 1; i >= 0; i--) {
4118 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4120 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4124 static void eliminate_seh(int opcnt)
4128 for (i = 0; i < opcnt; i++) {
4129 if (ops[i].op != OP_MOV)
4131 if (ops[i].operand[0].segment != SEG_FS)
4133 if (!IS(opr_name(&ops[i], 0), "0"))
4136 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4137 if (ops[i].operand[1].reg == xSP) {
4138 for (j = i - 1; j >= 0; j--) {
4139 if (ops[j].op != OP_PUSH)
4141 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4143 if (ops[j].operand[0].val == ~0)
4145 if (ops[j].operand[0].type == OPT_REG) {
4147 ret = resolve_origin(j, &ops[j].operand[0],
4148 j + opcnt * 22, &k, NULL);
4150 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4154 ferr(ops, "missing seh terminator\n");
4158 ret = resolve_origin(i, &ops[i].operand[1],
4159 i + opcnt * 23, &k, NULL);
4161 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4165 eliminate_seh_writes(opcnt);
4166 eliminate_seh_finally(opcnt);
4169 static void eliminate_seh_calls(int opcnt)
4171 int epilog_found = 0;
4178 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4179 && ops[i].operand[0].type == OPT_CONST);
4180 g_stack_fsz = g_seh_size + ops[i].operand[0].val;
4181 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4184 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4185 && ops[i].operand[0].type == OPT_OFFSET);
4186 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4189 ferr_assert(&ops[i], ops[i].op == OP_CALL
4190 && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
4191 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4193 for (i++; i < opcnt; i++) {
4194 if (ops[i].op != OP_CALL)
4196 if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
4199 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4202 ferr_assert(ops, epilog_found);
4204 eliminate_seh_writes(opcnt);
4205 eliminate_seh_finally(opcnt);
4208 // check for prologue of many pushes and epilogue with pops
4209 static void check_simple_sequence(int opcnt, int *fsz)
4218 for (i = 0; i < opcnt && i < ARRAY_SIZE(seq); i++) {
4219 if (ops[i].op != OP_PUSH || ops[i].operand[0].type != OPT_REG)
4221 reg = ops[i].operand[0].reg;
4222 if (reg != xBX && reg != xSI && reg != xDI && reg != xBP)
4224 for (j = 0; j < i; j++)
4228 // probably something else is going on here
4236 for (; i < opcnt && seq_len > 0; i++) {
4237 if (!(ops[i].flags & OPF_TAIL))
4240 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4241 if (ops[j].op != OP_POP || ops[j].operand[0].type != OPT_REG)
4243 if (ops[j].operand[0].reg != seq[seq_p])
4247 found = seq_len = seq_p;
4252 for (i = 0; i < seq_len; i++)
4253 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4255 for (; i < opcnt && seq_len > 0; i++) {
4256 if (!(ops[i].flags & OPF_TAIL))
4259 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4260 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4265 // unlike pushes after sub esp,
4266 // IDA treats pushes like this as part of var area
4267 *fsz += seq_len * 4;
4270 static int scan_prologue_ecx(int i, int opcnt, int flags_set,
4271 int limit, int *ecx_push_out)
4273 const struct parsed_proto *pp;
4274 int ecx_push = 0, other_push = 0;
4277 while (limit > 0 && ops[i].op == OP_PUSH
4278 && IS(opr_name(&ops[i], 0), "ecx"))
4280 ops[i].flags |= flags_set;
4287 if (ecx_push == 0 || flags_set != 0)
4290 // check if some of the pushes aren't really call args
4291 for (; i < opcnt; i++) {
4292 if (i > 0 && g_labels[i] != NULL)
4294 if (ops[i].flags & (OPF_JMP|OPF_TAIL))
4296 if (ops[i].op == OP_PUSH)
4300 if (ops[i].op != OP_CALL)
4304 if (pp == NULL && ops[i].operand[0].type == OPT_LABEL)
4305 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4309 ferr_assert(&ops[i], ecx_push + other_push >= pp->argc_stack);
4310 if (other_push < pp->argc_stack)
4311 ecx_push -= pp->argc_stack - other_push;
4314 if (ecx_push_out != NULL)
4315 *ecx_push_out = ecx_push;
4319 static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4325 for (; i < opcnt; i++)
4326 if (!(ops[i].flags & OPF_DONE))
4329 ret = scan_prologue_ecx(i, opcnt, 0, 4, &ecx_tmp);
4331 scan_prologue_ecx(i, opcnt, OPF_RMD | OPF_DONE | OPF_NOREGS,
4333 g_stack_fsz += 4 * ecx_tmp;
4334 *ecx_push += ecx_tmp;
4338 for (; i < opcnt; i++) {
4339 if (i > 0 && g_labels[i] != NULL)
4341 if (ops[i].flags & (OPF_JMP|OPF_TAIL))
4343 if (ops[i].flags & OPF_DONE)
4345 if (ops[i].op == OP_PUSH)
4347 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4348 && ops[i].operand[1].type == OPT_CONST)
4350 g_stack_fsz += opr_const(&ops[i], 1);
4351 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4356 if (ops[i].op == OP_LEA && ops[i].operand[0].reg == xSP
4357 && ops[i].operand[1].type == OPT_REGMEM
4358 && IS_START(ops[i].operand[1].name, "esp-"))
4360 name = ops[i].operand[1].name;
4361 ret = sscanf(name, "esp-%x%n", &j, &len);
4362 ferr_assert(&ops[i], ret == 1 && len == strlen(name));
4364 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4369 if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4370 && ops[i].operand[1].type == OPT_CONST)
4372 for (j = i + 1; j < opcnt; j++)
4373 if (!(ops[j].flags & OPF_DONE))
4375 if (ops[j].op == OP_CALL
4376 && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4378 g_stack_fsz += opr_const(&ops[i], 1);
4379 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4380 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4391 static void scan_prologue_epilogue(int opcnt, int *stack_align)
4393 int ecx_push = 0, esp_sub = 0, pusha = 0;
4394 int sandard_epilogue;
4395 int found, ret, len;
4399 if (g_seh_found == 2) {
4400 eliminate_seh_calls(opcnt);
4404 eliminate_seh(opcnt);
4405 // ida treats seh as part of sf
4406 g_stack_fsz = g_seh_size;
4410 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4411 && ops[1].op == OP_MOV
4412 && IS(opr_name(&ops[1], 0), "ebp")
4413 && IS(opr_name(&ops[1], 1), "esp"))
4416 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4417 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4419 for (i = 2; i < opcnt; i++)
4420 if (!(ops[i].flags & OPF_DONE))
4423 if (ops[i].op == OP_PUSHA) {
4424 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4429 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4430 && ops[i].operand[1].type == OPT_CONST)
4432 l = ops[i].operand[1].val;
4434 if (j == -1 || (l >> j) != -1)
4435 ferr(&ops[i], "unhandled esp align: %x\n", l);
4436 if (stack_align != NULL)
4437 *stack_align = 1 << j;
4438 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4442 i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4446 for (; i < opcnt; i++)
4447 if (ops[i].flags & OPF_TAIL)
4450 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4451 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4457 sandard_epilogue = 0;
4458 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4460 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4461 // the standard epilogue is sometimes even used without a sf
4462 if (ops[j - 1].op == OP_MOV
4463 && IS(opr_name(&ops[j - 1], 0), "esp")
4464 && IS(opr_name(&ops[j - 1], 1), "ebp"))
4465 sandard_epilogue = 1;
4467 else if (ops[j].op == OP_LEAVE)
4469 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4470 sandard_epilogue = 1;
4472 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4473 && ops[i].pp->is_noreturn)
4475 // on noreturn, msvc sometimes cleans stack, sometimes not
4480 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4481 ferr(&ops[j], "'pop ebp' expected\n");
4483 if (g_stack_fsz != 0 || sandard_epilogue) {
4484 if (ops[j].op == OP_LEAVE)
4486 else if (sandard_epilogue) // mov esp, ebp
4488 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4491 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4493 ferr(&ops[j], "esp restore expected\n");
4496 if (ecx_push && j >= 0 && ops[j].op == OP_POP
4497 && IS(opr_name(&ops[j], 0), "ecx"))
4499 ferr(&ops[j], "unexpected ecx pop\n");
4504 if (ops[j].op == OP_POPA)
4505 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4507 ferr(&ops[j], "popa expected\n");
4512 } while (i < opcnt);
4515 ferr(ops, "missing ebp epilogue\n");
4520 check_simple_sequence(opcnt, &push_fsz);
4521 i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4524 if (ecx_push || esp_sub)
4529 for (; i < opcnt; i++)
4530 if (ops[i].flags & OPF_TAIL)
4534 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4535 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4540 else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4541 // skip arg updates for arg-reuse tailcall
4542 for (; j >= 0; j--) {
4543 if (ops[j].op != OP_MOV)
4545 if (ops[j].operand[0].type == OPT_REGMEM
4546 && strstr(ops[j].operand[0].name, "arg_") != NULL)
4548 if (ops[j].operand[0].type == OPT_REG)
4549 continue; // assume arg-reg mov
4554 for (; j >= 0; j--) {
4555 if ((ops[j].flags & (OPF_RMD | OPF_DONE | OPF_NOREGS)) !=
4556 (OPF_RMD | OPF_DONE | OPF_NOREGS))
4560 if (ecx_push > 0 && !esp_sub) {
4561 for (l = 0; l < ecx_push && j >= 0; l++) {
4562 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4564 else if (ops[j].op == OP_ADD
4565 && IS(opr_name(&ops[j], 0), "esp")
4566 && ops[j].operand[1].type == OPT_CONST)
4569 l += ops[j].operand[1].val / 4 - 1;
4574 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4577 if (l != ecx_push) {
4578 if (i < opcnt && ops[i].op == OP_CALL
4579 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4581 // noreturn tailcall with no epilogue
4586 ferr(&ops[j], "epilogue scan failed\n");
4593 if (ops[j].op == OP_ADD
4594 && IS(opr_name(&ops[j], 0), "esp")
4595 && ops[j].operand[1].type == OPT_CONST)
4597 if (ops[j].operand[1].val < g_stack_fsz)
4598 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4600 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4601 if (ops[j].operand[1].val == 0)
4602 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4605 else if (ops[j].op == OP_LEA && ops[j].operand[0].reg == xSP
4606 && ops[j].operand[1].type == OPT_REGMEM
4607 && IS_START(ops[j].operand[1].name, "esp+"))
4609 const char *name = ops[j].operand[1].name;
4610 ret = sscanf(name, "esp+%x%n", &l, &len);
4611 ferr_assert(&ops[j], ret == 1 && len == strlen(name));
4612 ferr_assert(&ops[j], l <= g_stack_fsz);
4613 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4616 else if (i < opcnt && ops[i].op == OP_CALL
4617 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4619 // noreturn tailcall with no epilogue
4623 ferr(&ops[j], "'add esp' expected\n");
4627 } while (i < opcnt);
4630 ferr(ops, "missing esp epilogue\n");
4633 if (g_stack_fsz != 0)
4634 // see check_simple_sequence
4635 g_stack_fsz += push_fsz;
4638 // find an instruction that changed opr before i op
4639 // *op_i must be set to -1 by the caller
4640 // *is_caller is set to 1 if one source is determined to be g_func arg
4641 // returns 1 if found, *op_i is then set to origin
4642 // returns -1 if multiple origins are found
4643 static int resolve_origin(int i, const struct parsed_opr *opr,
4644 int magic, int *op_i, int *is_caller)
4646 struct label_ref *lr;
4650 if (g_labels[i] != NULL) {
4651 lr = &g_label_refs[i];
4652 for (; lr != NULL; lr = lr->next) {
4653 check_i(&ops[i], lr->i);
4654 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4656 if (i > 0 && LAST_OP(i - 1))
4662 if (is_caller != NULL)
4667 if (ops[i].cc_scratch == magic)
4669 ops[i].cc_scratch = magic;
4671 if (!(ops[i].flags & OPF_DATA))
4673 if (!is_opr_modified(opr, &ops[i]))
4677 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4688 static int resolve_origin_reg(int i, int reg, int magic, int *op_i,
4691 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4694 if (is_caller != NULL)
4696 return resolve_origin(i, &opr, magic, op_i, is_caller);
4699 // find an instruction that previously referenced opr
4700 // if multiple results are found - fail
4701 // *op_i must be set to -1 by the caller
4702 // returns 1 if found, *op_i is then set to referencer insn
4703 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4704 int magic, int *op_i)
4706 struct label_ref *lr;
4710 if (g_labels[i] != NULL) {
4711 lr = &g_label_refs[i];
4712 for (; lr != NULL; lr = lr->next) {
4713 check_i(&ops[i], lr->i);
4714 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4716 if (i > 0 && LAST_OP(i - 1))
4724 if (ops[i].cc_scratch == magic)
4726 ops[i].cc_scratch = magic;
4728 if (!is_opr_referenced(opr, &ops[i]))
4739 // adjust datap of all reachable 'op' insns when moving back
4740 // returns 1 if at least 1 op was found
4741 // returns -1 if path without an op was found
4742 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4744 struct label_ref *lr;
4747 if (ops[i].cc_scratch == magic)
4749 ops[i].cc_scratch = magic;
4752 if (g_labels[i] != NULL) {
4753 lr = &g_label_refs[i];
4754 for (; lr != NULL; lr = lr->next) {
4755 check_i(&ops[i], lr->i);
4756 ret |= adjust_prev_op(lr->i, op, magic, datap);
4758 if (i > 0 && LAST_OP(i - 1))
4766 if (ops[i].cc_scratch == magic)
4768 ops[i].cc_scratch = magic;
4770 if (ops[i].op != op)
4773 ops[i].datap = datap;
4778 // find next instruction that reads opr
4779 // *op_i must be set to -1 by the caller
4780 // on return, *op_i is set to first referencer insn
4781 // returns 1 if exactly 1 referencer is found
4782 static int find_next_read(int i, int opcnt,
4783 const struct parsed_opr *opr, int magic, int *op_i)
4785 struct parsed_op *po;
4788 for (; i < opcnt; i++)
4790 if (ops[i].cc_scratch == magic)
4792 ops[i].cc_scratch = magic;
4795 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4796 if (po->btj != NULL) {
4798 for (j = 0; j < po->btj->count; j++) {
4799 check_i(po, po->btj->d[j].bt_i);
4800 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4806 if (po->flags & OPF_RMD)
4808 check_i(po, po->bt_i);
4809 if (po->flags & OPF_CJMP) {
4810 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4819 if (!is_opr_read(opr, po)) {
4821 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4822 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4824 full_opr = po->operand[0].lmod >= opr->lmod;
4826 if (is_opr_modified(opr, po) && full_opr) {
4830 if (po->flags & OPF_TAIL)
4845 static int find_next_read_reg(int i, int opcnt, int reg,
4846 enum opr_lenmod lmod, int magic, int *op_i)
4848 struct parsed_opr opr = OPR_INIT(OPT_REG, lmod, reg);
4851 return find_next_read(i, opcnt, &opr, magic, op_i);
4854 // find next instruction that reads opr
4855 // *op_i must be set to -1 by the caller
4856 // on return, *op_i is set to first flag user insn
4857 // returns 1 if exactly 1 flag user is found
4858 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4860 struct parsed_op *po;
4863 for (; i < opcnt; i++)
4865 if (ops[i].cc_scratch == magic)
4867 ops[i].cc_scratch = magic;
4870 if (po->op == OP_CALL)
4872 if (po->flags & OPF_JMP) {
4873 if (po->btj != NULL) {
4875 for (j = 0; j < po->btj->count; j++) {
4876 check_i(po, po->btj->d[j].bt_i);
4877 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4883 if (po->flags & OPF_RMD)
4885 check_i(po, po->bt_i);
4886 if (po->flags & OPF_CJMP)
4893 if (!(po->flags & OPF_CC)) {
4894 if (po->flags & OPF_FLAGS)
4897 if (po->flags & OPF_TAIL)
4913 static int try_resolve_const(int i, const struct parsed_opr *opr,
4914 int magic, unsigned int *val)
4919 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4922 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4925 *val = ops[i].operand[1].val;
4932 static int resolve_used_bits(int i, int opcnt, int reg,
4933 int *mask, int *is_z_check)
4935 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4939 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4943 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4945 fnote(&ops[j], "(first read)\n");
4946 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4949 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4950 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4952 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4953 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4955 *mask = ops[j].operand[1].val;
4956 if (ops[j].operand[0].lmod == OPLM_BYTE
4957 && ops[j].operand[0].name[1] == 'h')
4961 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4964 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4966 *is_z_check = ops[k].pfo == PFO_Z;
4971 static const struct parsed_proto *resolve_deref(int i, int magic,
4972 const struct parsed_opr *opr, int level)
4974 const struct parsed_proto *pp = NULL;
4975 int from_caller = 0;
4984 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4985 if (ret != 2 || len != strlen(opr->name)) {
4986 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4987 if (ret != 1 || len != strlen(opr->name))
4991 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4995 ret = resolve_origin_reg(i, reg, i + magic, &j, NULL);
4999 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
5000 && strlen(ops[j].operand[1].name) == 3
5001 && ops[j].operand[0].lmod == OPLM_DWORD
5002 && ops[j].pp == NULL // no hint
5005 // allow one simple dereference (com/directx)
5006 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
5007 ops[j].operand[1].name);
5010 ret = resolve_origin_reg(j, reg, j + magic, &k, NULL);
5015 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
5018 if (ops[j].pp != NULL) {
5022 else if (ops[j].operand[1].type == OPT_REGMEM) {
5023 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
5025 // maybe structure ptr in structure
5026 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
5029 else if (ops[j].operand[1].type == OPT_LABEL)
5030 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
5031 else if (ops[j].operand[1].type == OPT_REG) {
5034 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
5036 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
5037 for (k = 0; k < g_func_pp->argc; k++) {
5038 if (g_func_pp->arg[k].reg == NULL)
5040 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
5041 pp = g_func_pp->arg[k].pp;
5050 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
5052 ferr(&ops[j], "expected struct, got '%s %s'\n",
5053 pp->type.name, pp->name);
5057 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
5060 static const struct parsed_proto *resolve_func_ptr(int i, int opcnt,
5061 int is_call_op, const struct parsed_opr *opr,
5062 int *pp_i, int *multi_src)
5064 const struct parsed_proto *pp = NULL;
5065 int search_advice = 0;
5067 if (multi_src != NULL)
5072 switch (opr->type) {
5074 // try to resolve struct member calls
5075 pp = resolve_deref(i, i + opcnt * 19, opr, 0);
5081 pp = try_recover_pp(&ops[i], opr, is_call_op, &search_advice);
5086 scan_for_call_type(i, opr, i + opcnt * 9, is_call_op,
5087 &pp, pp_i, multi_src);
5094 static struct parsed_proto *process_call_early(int i, int opcnt,
5097 struct parsed_op *po = &ops[i];
5098 struct parsed_proto *pp;
5104 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
5108 // look for and make use of esp adjust
5110 if (!pp->is_stdcall && pp->argc_stack > 0)
5111 ret = scan_for_esp_adjust(i + 1, opcnt,
5112 pp->argc_stack * 4, &adj, &multipath, 0);
5114 if (pp->argc_stack > adj / 4)
5118 if (ops[ret].op == OP_POP) {
5119 for (j = 1; j < adj / 4; j++) {
5120 if (ops[ret + j].op != OP_POP
5121 || ops[ret + j].operand[0].reg != xCX)
5133 static struct parsed_proto *process_call(int i, int opcnt)
5135 struct parsed_op *po = &ops[i];
5136 const struct parsed_proto *pp_c;
5137 struct parsed_proto *pp;
5138 const char *tmpname;
5139 int call_i = -1, ref_i = -1;
5140 int adj = 0, multipath = 0;
5143 tmpname = opr_name(po, 0);
5148 pp_c = resolve_func_ptr(i, opcnt, 1, &ops[i].operand[0],
5149 &call_i, &multipath);
5151 if (!pp_c->is_func && !pp_c->is_fptr)
5152 ferr(po, "call to non-func: %s\n", pp_c->name);
5153 pp = proto_clone(pp_c);
5154 my_assert_not(pp, NULL);
5156 // not resolved just to single func
5159 switch (po->operand[0].type) {
5161 // we resolved this call and no longer need the register
5162 po->regmask_src &= ~(1 << po->operand[0].reg);
5164 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
5165 && ops[call_i].operand[1].type == OPT_LABEL)
5167 // no other source users?
5168 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
5170 if (ret == 1 && call_i == ref_i) {
5171 // and nothing uses it after us?
5173 find_next_read(i + 1, opcnt, &po->operand[0],
5174 i + opcnt * 11, &ref_i);
5176 // then also don't need the source mov
5177 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
5189 pp = calloc(1, sizeof(*pp));
5190 my_assert_not(pp, NULL);
5193 ret = scan_for_esp_adjust(i + 1, opcnt,
5194 -1, &adj, &multipath, 0);
5195 if (ret < 0 || adj < 0) {
5196 if (!g_allow_regfunc)
5197 ferr(po, "non-__cdecl indirect call unhandled yet\n");
5198 pp->is_unresolved = 1;
5202 if (adj > ARRAY_SIZE(pp->arg))
5203 ferr(po, "esp adjust too large: %d\n", adj);
5204 pp->ret_type.name = strdup("int");
5205 pp->argc = pp->argc_stack = adj;
5206 for (arg = 0; arg < pp->argc; arg++)
5207 pp->arg[arg].type.name = strdup("int");
5212 // look for and make use of esp adjust
5215 if (!pp->is_stdcall && pp->argc_stack > 0) {
5216 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
5217 ret = scan_for_esp_adjust(i + 1, opcnt,
5218 adj_expect, &adj, &multipath, 0);
5221 if (pp->is_vararg) {
5222 if (adj / 4 < pp->argc_stack) {
5223 fnote(po, "(this call)\n");
5224 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
5225 adj, pp->argc_stack * 4);
5227 // modify pp to make it have varargs as normal args
5229 pp->argc += adj / 4 - pp->argc_stack;
5230 for (; arg < pp->argc; arg++) {
5231 pp->arg[arg].type.name = strdup("int");
5234 if (pp->argc > ARRAY_SIZE(pp->arg))
5235 ferr(po, "too many args for '%s'\n", tmpname);
5237 if (pp->argc_stack > adj / 4) {
5238 if (pp->is_noreturn)
5239 // assume no stack adjust was emited
5241 fnote(po, "(this call)\n");
5242 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
5243 tmpname, pp->argc_stack * 4, adj);
5246 scan_for_esp_adjust(i + 1, opcnt,
5247 pp->argc_stack * 4, &adj, &multipath, 1);
5249 else if (pp->is_vararg)
5250 ferr(po, "missing esp_adjust for vararg func '%s'\n",
5257 static void check_fptr_args(int i, int opcnt, struct parsed_proto *pp)
5259 struct parsed_opr s_opr = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
5260 const struct parsed_proto *pp_arg, *pp_cmp;
5261 const struct parsed_op *po_a;
5266 for (arg = 0; arg < pp->argc; arg++) {
5270 pp_arg = pp->arg[arg].pp;
5271 if (pp_arg == NULL || !pp_arg->is_func)
5274 s_reg = pp->arg[arg].reg;
5275 if (s_reg != NULL) {
5276 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
5277 ferr_assert(&ops[i], reg >= 0);
5279 scan_for_call_type(i, &s_opr, i + arg + opcnt * 28, 0,
5280 &pp_cmp, &pp_cmp_i, NULL);
5283 po_a = pp->arg[arg].datap;
5284 if (po_a != NULL && po_a->op == OP_PUSH)
5285 pp_cmp = resolve_func_ptr(po_a - ops, opcnt, 0,
5286 &po_a->operand[0], &pp_cmp_i, NULL);
5288 pp_cmp_i = po_a - ops;
5291 if (pp_cmp != NULL && !pp_compatible_func(pp_arg, pp_cmp)) {
5293 fnote(&ops[pp_cmp_i], "(referenced here)\n");
5294 ferr(&ops[i], "incompatible fptr arg %d\n", arg + 1);
5299 static void mark_float_arg(struct parsed_op *po,
5300 struct parsed_proto *pp, int arg, int *regmask_ffca)
5303 po->p_argnum = arg + 1;
5304 ferr_assert(po, pp->arg[arg].datap == NULL);
5305 pp->arg[arg].datap = po;
5306 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
5307 if (regmask_ffca != NULL)
5308 *regmask_ffca |= 1 << arg;
5311 static int check_for_stp(int i, int i_to)
5313 struct parsed_op *po;
5315 for (; i < i_to; i++) {
5317 if (po->op == OP_FST)
5319 if (g_labels[i] != NULL || (po->flags & OPF_JMP))
5321 if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
5323 if (po->op == OP_ADD && po->operand[0].reg == xSP)
5330 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
5333 struct parsed_op *po;
5339 for (base_arg = 0; base_arg < pp->argc; base_arg++)
5340 if (pp->arg[base_arg].reg == NULL)
5343 for (j = i; j > 0; )
5345 ferr_assert(&ops[j], g_labels[j] == NULL);
5349 ferr_assert(po, po->op != OP_PUSH);
5350 if (po->op == OP_FST)
5352 if (po->operand[0].type != OPT_REGMEM)
5354 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
5357 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
5358 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
5362 arg = base_arg + offset / 4;
5363 mark_float_arg(po, pp, arg, regmask_ffca);
5365 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5366 && po->operand[1].type == OPT_CONST)
5368 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5373 for (arg = base_arg; arg < pp->argc; arg++) {
5374 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
5375 po = pp->arg[arg].datap;
5377 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
5378 if (po->operand[0].lmod == OPLM_QWORD)
5385 static int collect_call_args_early(int i, int opcnt,
5386 struct parsed_proto *pp, int *regmask, int *regmask_ffca)
5388 struct parsed_op *po;
5393 for (arg = 0; arg < pp->argc; arg++)
5394 if (pp->arg[arg].reg == NULL)
5397 // first see if it can be easily done
5398 for (j = i; j > 0 && arg < pp->argc; )
5400 if (g_labels[j] != NULL)
5405 if (po->op == OP_CALL)
5407 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
5409 else if (po->op == OP_POP)
5411 else if (po->flags & OPF_CJMP)
5413 else if (po->op == OP_PUSH) {
5414 if (po->flags & (OPF_FARG|OPF_FARGNR))
5416 if (!g_header_mode) {
5417 ret = scan_for_mod(po, j + 1, i, 1);
5422 if (pp->arg[arg].type.is_va_list)
5426 for (arg++; arg < pp->argc; arg++)
5427 if (pp->arg[arg].reg == NULL)
5430 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5431 && po->operand[1].type == OPT_CONST)
5433 if (po->flags & (OPF_RMD|OPF_DONE))
5435 if (po->operand[1].val != pp->argc_stack * 4)
5436 ferr(po, "unexpected esp adjust: %d\n",
5437 po->operand[1].val * 4);
5438 ferr_assert(po, pp->argc - arg == pp->argc_stack);
5439 return collect_call_args_no_push(i, pp, regmask_ffca);
5447 for (arg = 0; arg < pp->argc; arg++)
5448 if (pp->arg[arg].reg == NULL)
5451 for (j = i; j > 0 && arg < pp->argc; )
5455 if (ops[j].op == OP_PUSH)
5457 ops[j].p_argnext = -1;
5458 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
5460 k = check_for_stp(j + 1, i);
5462 // push ecx; fstp dword ptr [esp]
5463 ret = parse_stack_esp_offset(&ops[k],
5464 ops[k].operand[0].name, &offset);
5465 if (ret == 0 && offset == 0) {
5466 if (!pp->arg[arg].type.is_float)
5467 ferr(&ops[i], "arg %d should be float\n", arg + 1);
5468 mark_float_arg(&ops[k], pp, arg, regmask_ffca);
5472 if (pp->arg[arg].datap == NULL) {
5473 pp->arg[arg].datap = &ops[j];
5474 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5475 *regmask |= 1 << ops[j].operand[0].reg;
5478 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5479 ops[j].flags &= ~OPF_RSAVE;
5482 for (arg++; arg < pp->argc; arg++)
5483 if (pp->arg[arg].reg == NULL)
5489 check_fptr_args(i, opcnt, pp);
5494 static int sync_argnum(struct parsed_op *po, int argnum)
5496 struct parsed_op *po_tmp;
5498 // see if other branches don't have higher argnum
5499 for (po_tmp = po; po_tmp != NULL; ) {
5500 if (argnum < po_tmp->p_argnum)
5501 argnum = po_tmp->p_argnum;
5502 // note: p_argnext is active on current collect_call_args only
5503 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5506 // make all argnums consistent
5507 for (po_tmp = po; po_tmp != NULL; ) {
5508 if (po_tmp->p_argnum != 0)
5509 po_tmp->p_argnum = argnum;
5510 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5516 static int collect_call_args_r(struct parsed_op *po, int i,
5517 struct parsed_proto *pp, int *regmask, int *arg_grp,
5518 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
5520 struct parsed_proto *pp_tmp;
5521 struct parsed_op *po_tmp;
5522 struct label_ref *lr;
5523 int need_to_save_current;
5524 int arg_grp_current = 0;
5525 int save_args_seen = 0;
5532 ferr(po, "dead label encountered\n");
5536 for (; arg < pp->argc; arg++, argnum++)
5537 if (pp->arg[arg].reg == NULL)
5539 magic = (magic & 0xffffff) | (arg << 24);
5541 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5543 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5544 if (ops[j].cc_scratch != magic) {
5545 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5549 // ok: have already been here
5552 ops[j].cc_scratch = magic;
5554 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5555 lr = &g_label_refs[j];
5556 if (lr->next != NULL)
5558 for (; lr->next; lr = lr->next) {
5559 check_i(&ops[j], lr->i);
5560 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5562 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5563 arg, argnum, magic, need_op_saving, may_reuse);
5568 check_i(&ops[j], lr->i);
5569 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5571 if (j > 0 && LAST_OP(j - 1)) {
5572 // follow last branch in reverse
5577 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5578 arg, argnum, magic, need_op_saving, may_reuse);
5584 if (ops[j].op == OP_CALL)
5586 if (pp->is_unresolved)
5591 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5592 arg, pp->argc, ops[j].operand[0].name);
5593 if (may_reuse && pp_tmp->argc_stack > 0)
5594 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5595 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5597 // esp adjust of 0 means we collected it before
5598 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5599 && (ops[j].operand[1].type != OPT_CONST
5600 || ops[j].operand[1].val != 0))
5602 if (pp->is_unresolved)
5605 fnote(po, "(this call)\n");
5606 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5607 arg, pp->argc, ops[j].operand[1].val);
5609 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5611 if (pp->is_unresolved)
5614 fnote(po, "(this call)\n");
5615 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5617 else if (ops[j].flags & OPF_CJMP)
5619 if (pp->is_unresolved)
5624 else if (ops[j].op == OP_PUSH
5625 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5627 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5630 ops[j].p_argnext = -1;
5631 po_tmp = pp->arg[arg].datap;
5633 ops[j].p_argnext = po_tmp - ops;
5634 pp->arg[arg].datap = &ops[j];
5636 argnum = sync_argnum(&ops[j], argnum);
5638 need_to_save_current = 0;
5640 if (ops[j].operand[0].type == OPT_REG)
5641 reg = ops[j].operand[0].reg;
5643 if (!need_op_saving) {
5644 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5645 need_to_save_current = (ret >= 0);
5647 if (need_op_saving || need_to_save_current) {
5648 // mark this arg as one that needs operand saving
5649 pp->arg[arg].is_saved = 1;
5651 if (save_args_seen & (1 << (argnum - 1))) {
5654 if (arg_grp_current >= MAX_ARG_GRP)
5655 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5659 else if (ops[j].p_argnum == 0)
5660 ops[j].flags |= OPF_RMD;
5662 // some PUSHes are reused by different calls on other branches,
5663 // but that can't happen if we didn't branch, so they
5664 // can be removed from future searches (handles nested calls)
5666 ops[j].flags |= OPF_FARGNR;
5668 ops[j].flags |= OPF_FARG;
5669 ops[j].flags &= ~OPF_RSAVE;
5671 // check for __VALIST
5672 if (!pp->is_unresolved && g_func_pp != NULL
5673 && pp->arg[arg].type.is_va_list)
5676 ret = resolve_origin(j, &ops[j].operand[0],
5677 magic + 1, &k, NULL);
5678 if (ret == 1 && k >= 0)
5680 if (ops[k].op == OP_LEA) {
5681 if (!g_func_pp->is_vararg)
5682 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5685 snprintf(buf, sizeof(buf), "arg_%X",
5686 g_func_pp->argc_stack * 4);
5687 if (strstr(ops[k].operand[1].name, buf)
5688 || strstr(ops[k].operand[1].name, "arglist"))
5690 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5691 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5692 pp->arg[arg].is_saved = 0;
5696 ferr(&ops[k], "va_list arg detection failed\n");
5698 // check for va_list from g_func_pp arg too
5699 else if (ops[k].op == OP_MOV
5700 && is_stack_access(&ops[k], &ops[k].operand[1]))
5702 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5703 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5705 ops[k].flags |= OPF_RMD | OPF_DONE;
5706 ops[j].flags |= OPF_RMD;
5707 ops[j].p_argpass = ret + 1;
5708 pp->arg[arg].is_saved = 0;
5715 if (pp->arg[arg].is_saved) {
5716 ops[j].flags &= ~OPF_RMD;
5717 ops[j].p_argnum = argnum;
5720 // tracking reg usage
5722 *regmask |= 1 << reg;
5726 if (!pp->is_unresolved) {
5728 for (; arg < pp->argc; arg++, argnum++)
5729 if (pp->arg[arg].reg == NULL)
5732 magic = (magic & 0xffffff) | (arg << 24);
5735 if (ops[j].p_arggrp > arg_grp_current) {
5737 arg_grp_current = ops[j].p_arggrp;
5739 if (ops[j].p_argnum > 0)
5740 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5743 if (arg < pp->argc) {
5744 ferr(po, "arg collect failed for '%s': %d/%d\n",
5745 pp->name, arg, pp->argc);
5749 if (arg_grp_current > *arg_grp)
5750 *arg_grp = arg_grp_current;
5755 static int collect_call_args(struct parsed_op *po, int i, int opcnt,
5756 struct parsed_proto *pp, int *regmask, int magic)
5758 // arg group is for cases when pushes for
5759 // multiple funcs are going on
5760 struct parsed_op *po_tmp;
5765 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5770 if (pp->is_unresolved) {
5772 pp->argc_stack += ret;
5773 for (a = 0; a < pp->argc; a++)
5774 if (pp->arg[a].type.name == NULL)
5775 pp->arg[a].type.name = strdup("int");
5779 // propagate arg_grp
5780 for (a = 0; a < pp->argc; a++) {
5781 if (pp->arg[a].reg != NULL)
5784 po_tmp = pp->arg[a].datap;
5785 while (po_tmp != NULL) {
5786 po_tmp->p_arggrp = arg_grp;
5787 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5793 check_fptr_args(i, opcnt, pp);
5798 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5799 int regmask_now, int *regmask,
5800 int regmask_save_now, int *regmask_save,
5801 int *regmask_init, int regmask_arg)
5803 struct parsed_op *po;
5811 for (; i < opcnt; i++)
5814 if (cbits[i >> 3] & (1 << (i & 7)))
5816 cbits[i >> 3] |= (1 << (i & 7));
5818 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5819 if (po->flags & (OPF_RMD|OPF_DONE))
5821 if (po->btj != NULL) {
5822 for (j = 0; j < po->btj->count; j++) {
5823 check_i(po, po->btj->d[j].bt_i);
5824 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5825 regmask_now, regmask, regmask_save_now, regmask_save,
5826 regmask_init, regmask_arg);
5831 check_i(po, po->bt_i);
5832 if (po->flags & OPF_CJMP)
5833 reg_use_pass(po->bt_i, opcnt, cbits,
5834 regmask_now, regmask, regmask_save_now, regmask_save,
5835 regmask_init, regmask_arg);
5841 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5842 && !g_func_pp->is_userstack
5843 && po->operand[0].type == OPT_REG)
5847 reg = po->operand[0].reg;
5848 ferr_assert(po, reg >= 0);
5851 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5852 if (regmask_now & (1 << reg)) {
5853 already_saved = regmask_save_now & (1 << reg);
5854 flags_set = OPF_RSAVE | OPF_DONE;
5858 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3,
5859 reg, 0, 0, save_level, 0);
5861 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5862 reg, 0, 0, save_level, flags_set);
5865 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5867 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5872 ferr_assert(po, !already_saved);
5873 po->flags |= flags_set;
5875 if (regmask_now & (1 << reg)) {
5876 regmask_save_now |= (1 << reg);
5877 *regmask_save |= regmask_save_now;
5882 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5883 reg = po->operand[0].reg;
5884 ferr_assert(po, reg >= 0);
5886 if (regmask_save_now & (1 << reg))
5887 regmask_save_now &= ~(1 << reg);
5889 regmask_now &= ~(1 << reg);
5892 else if (po->op == OP_CALL) {
5893 if ((po->regmask_dst & (1 << xAX))
5894 && !(po->regmask_dst & (1 << xDX)))
5896 if (po->flags & OPF_TAIL)
5897 // don't need eax, will do "return f();" or "f(); return;"
5898 po->regmask_dst &= ~(1 << xAX);
5900 find_next_read_reg(i + 1, opcnt, xAX, OPLM_DWORD,
5901 i + opcnt * 17, &j);
5904 po->regmask_dst &= ~(1 << xAX);
5908 // not "full stack" mode and have something in stack
5909 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5910 ferr(po, "float stack is not empty on func call\n");
5913 if (po->flags & OPF_NOREGS)
5916 // if incomplete register is used, clear it on init to avoid
5917 // later use of uninitialized upper part in some situations
5918 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5919 && po->operand[0].lmod != OPLM_DWORD)
5921 reg = po->operand[0].reg;
5922 ferr_assert(po, reg >= 0);
5924 if (!(regmask_now & (1 << reg)))
5925 *regmask_init |= 1 << reg;
5928 regmask_op = po->regmask_src | po->regmask_dst;
5930 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5931 regmask_new &= ~(1 << xSP);
5932 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5933 regmask_new &= ~(1 << xBP);
5935 if (regmask_new != 0)
5936 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5938 if (regmask_op & (1 << xBP)) {
5939 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5940 if (po->regmask_dst & (1 << xBP))
5941 // compiler decided to drop bp frame and use ebp as scratch
5942 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5944 regmask_op &= ~(1 << xBP);
5948 if (po->flags & OPF_FPUSH) {
5949 if (regmask_now & mxST1)
5950 regmask_now |= mxSTa; // switch to "full stack" mode
5951 if (regmask_now & mxSTa)
5952 po->flags |= OPF_FSHIFT;
5953 if (!(regmask_now & mxST7_2)) {
5955 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5959 regmask_now |= regmask_op;
5960 *regmask |= regmask_now;
5963 if (po->flags & OPF_FPOPP) {
5964 if ((regmask_now & mxSTa) == 0)
5965 ferr(po, "float pop on empty stack?\n");
5966 if (regmask_now & mxST7_2)
5967 po->flags |= OPF_FSHIFT;
5968 if (!(regmask_now & mxST7_2))
5969 regmask_now &= ~mxST1_0;
5971 else if (po->flags & OPF_FPOP) {
5972 if ((regmask_now & mxSTa) == 0)
5973 ferr(po, "float pop on empty stack?\n");
5974 if (regmask_now & (mxST7_2 | mxST1))
5975 po->flags |= OPF_FSHIFT;
5976 if (!(regmask_now & mxST7_2)) {
5978 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5982 if (po->flags & OPF_TAIL) {
5983 if (!(regmask_now & mxST7_2)) {
5984 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5985 if (!(regmask_now & mxST0))
5986 ferr(po, "no st0 on float return, mask: %x\n",
5989 else if (regmask_now & mxST1_0)
5990 ferr(po, "float regs on tail: %x\n", regmask_now);
5993 // there is support for "conditional tailcall", sort of
5994 if (!(po->flags & OPF_CC))
6000 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
6004 for (i = 0; i < pp->argc; i++)
6005 if (pp->arg[i].reg == NULL)
6009 memmove(&pp->arg[i + 1], &pp->arg[i],
6010 sizeof(pp->arg[0]) * pp->argc_stack);
6011 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
6012 pp->arg[i].reg = strdup(reg);
6013 pp->arg[i].type.name = strdup("int");
6018 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
6019 int *pfomask, const char *dst_opr_text)
6021 if (*pfomask & (1 << PFO_Z)) {
6022 fprintf(fout, "\n cond_z = (%s%s == 0);",
6023 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
6024 *pfomask &= ~(1 << PFO_Z);
6028 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
6029 int *pfomask, const char *dst_opr_text)
6031 if (*pfomask & (1 << PFO_S)) {
6032 fprintf(fout, "\n cond_s = (%s%s < 0);",
6033 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
6034 *pfomask &= ~(1 << PFO_S);
6038 static void output_std_flags(FILE *fout, struct parsed_op *po,
6039 int *pfomask, const char *dst_opr_text)
6041 output_std_flag_z(fout, po, pfomask, dst_opr_text);
6042 output_std_flag_s(fout, po, pfomask, dst_opr_text);
6046 OPP_FORCE_NORETURN = (1 << 0),
6047 OPP_SIMPLE_ARGS = (1 << 1),
6048 OPP_ALIGN = (1 << 2),
6051 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
6054 const char *cconv = "";
6056 if (pp->is_fastcall)
6057 cconv = "__fastcall ";
6058 else if (pp->is_stdcall && pp->argc_reg == 0)
6059 cconv = "__stdcall ";
6061 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
6063 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
6064 fprintf(fout, "noreturn ");
6067 static void output_pp(FILE *fout, const struct parsed_proto *pp,
6072 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
6076 output_pp_attrs(fout, pp, flags);
6079 fprintf(fout, "%s", pp->name);
6084 for (i = 0; i < pp->argc; i++) {
6086 fprintf(fout, ", ");
6087 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
6088 && !(flags & OPP_SIMPLE_ARGS))
6091 output_pp(fout, pp->arg[i].pp, 0);
6093 else if (pp->arg[i].type.is_retreg) {
6094 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
6097 fprintf(fout, "%s", pp->arg[i].type.name);
6099 fprintf(fout, " a%d", i + 1);
6102 if (pp->arg[i].type.is_64bit)
6105 if (pp->is_vararg) {
6107 fprintf(fout, ", ");
6108 fprintf(fout, "...");
6113 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
6119 snprintf(buf1, sizeof(buf1), "%d", grp);
6120 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
6125 static void gen_x_cleanup(int opcnt);
6127 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
6129 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
6130 struct parsed_opr *last_arith_dst = NULL;
6131 char buf1[256], buf2[256], buf3[256], cast[64];
6132 struct parsed_proto *pp, *pp_tmp;
6133 struct parsed_data *pd;
6134 int save_arg_vars[MAX_ARG_GRP] = { 0, };
6135 unsigned char cbits[MAX_OPS / 8];
6136 const char *float_type;
6137 const char *float_st0;
6138 const char *float_st1;
6139 int need_float_stack = 0;
6140 int need_float_sw = 0; // status word
6141 int need_tmp_var = 0;
6145 int label_pending = 0;
6146 int need_double = 0;
6147 int stack_align = 0;
6148 int stack_fsz_adj = 0;
6149 int lock_handled = 0;
6150 int regmask_save = 0; // used regs saved/restored in this func
6151 int regmask_arg; // regs from this function args (fastcall, etc)
6152 int regmask_ret; // regs needed on ret
6153 int regmask_now; // temp
6154 int regmask_init = 0; // regs that need zero initialization
6155 int regmask_pp = 0; // regs used in complex push-pop graph
6156 int regmask_ffca = 0; // float function call args
6157 int regmask = 0; // used regs
6167 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
6168 g_stack_frame_used = 0;
6170 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
6171 regmask_init = g_regmask_init;
6173 g_func_pp = proto_parse(fhdr, funcn, 0);
6174 if (g_func_pp == NULL)
6175 ferr(ops, "proto_parse failed for '%s'\n", funcn);
6177 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
6178 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
6181 // - resolve all branches
6182 // - parse calls with labels
6183 resolve_branches_parse_calls(opcnt);
6186 // - handle ebp/esp frame, remove ops related to it
6187 scan_prologue_epilogue(opcnt, &stack_align);
6189 // handle a case where sf size is unalignment, but is
6190 // placed in a way that elements are still aligned
6191 if (g_stack_fsz & 4) {
6192 for (i = 0; i < g_eqcnt; i++) {
6193 if (g_eqs[i].lmod != OPLM_QWORD)
6195 if (!(g_eqs[i].offset & 4)) {
6204 // - remove dead labels
6205 // - set regs needed at ret
6206 for (i = 0; i < opcnt; i++)
6208 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
6213 if (ops[i].op == OP_RET)
6214 ops[i].regmask_src |= regmask_ret;
6218 // - process trivial calls
6219 for (i = 0; i < opcnt; i++)
6222 if (po->flags & (OPF_RMD|OPF_DONE))
6225 if (po->op == OP_CALL)
6227 pp = process_call_early(i, opcnt, &j);
6229 if (!(po->flags & OPF_ATAIL)) {
6230 // since we know the args, try to collect them
6231 ret = collect_call_args_early(i, opcnt, pp,
6232 ®mask, ®mask_ffca);
6240 // commit esp adjust
6241 if (ops[j].op != OP_POP)
6242 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
6244 for (l = 0; l < pp->argc_stack; l++)
6245 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
6249 if (strstr(pp->ret_type.name, "int64"))
6252 po->flags |= OPF_DONE;
6258 // - process calls, stage 2
6259 // - handle some push/pop pairs
6260 // - scan for STD/CLD, propagate DF
6261 // - try to resolve needed x87 status word bits
6262 for (i = 0; i < opcnt; i++)
6267 if (po->flags & OPF_RMD)
6270 if (po->op == OP_CALL)
6272 if (!(po->flags & OPF_DONE)) {
6273 pp = process_call(i, opcnt);
6275 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
6276 // since we know the args, collect them
6277 collect_call_args(po, i, opcnt, pp, ®mask, i + opcnt * 2);
6279 // for unresolved, collect after other passes
6283 ferr_assert(po, pp != NULL);
6285 po->regmask_src |= get_pp_arg_regmask_src(pp);
6286 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
6288 if (po->regmask_dst & mxST0)
6289 po->flags |= OPF_FPUSH;
6291 if (strstr(pp->ret_type.name, "int64"))
6297 if (po->flags & OPF_DONE)
6302 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
6303 && po->operand[0].type == OPT_CONST)
6305 scan_for_pop_const(i, opcnt, i + opcnt * 12);
6310 scan_pushes_for_pop(i, opcnt, ®mask_pp);
6314 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
6315 scan_propagate_df(i + 1, opcnt);
6320 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
6321 ferr(po, "TODO: fnstsw to mem\n");
6322 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
6324 ferr(po, "fnstsw resolve failed\n");
6325 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
6326 (void *)(long)(mask | (z_check << 16)));
6328 ferr(po, "failed to find fcom: %d\n", ret);
6337 // - find POPs for PUSHes, rm both
6338 // - scan for all used registers
6339 memset(cbits, 0, sizeof(cbits));
6340 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
6341 0, ®mask_save, ®mask_init, regmask_arg);
6343 need_float_stack = !!(regmask & mxST7_2);
6346 // - find flag set ops for their users
6347 // - do unresolved calls
6348 // - declare indirect functions
6349 // - other op specific processing
6350 for (i = 0; i < opcnt; i++)
6353 if (po->flags & (OPF_RMD|OPF_DONE))
6356 if (po->flags & OPF_CC)
6358 int setters[16], cnt = 0, branched = 0;
6360 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
6361 &branched, setters, &cnt);
6362 if (ret < 0 || cnt <= 0)
6363 ferr(po, "unable to trace flag setter(s)\n");
6364 if (cnt > ARRAY_SIZE(setters))
6365 ferr(po, "too many flag setters\n");
6367 for (j = 0; j < cnt; j++)
6369 tmp_op = &ops[setters[j]]; // flag setter
6372 // to get nicer code, we try to delay test and cmp;
6373 // if we can't because of operand modification, or if we
6374 // have arith op, or branch, make it calculate flags explicitly
6375 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
6377 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
6378 pfomask = 1 << po->pfo;
6380 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
6381 pfomask = 1 << po->pfo;
6384 // see if we'll be able to handle based on op result
6385 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
6386 && po->pfo != PFO_Z && po->pfo != PFO_S
6387 && po->pfo != PFO_P)
6389 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
6391 pfomask = 1 << po->pfo;
6394 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
6395 propagate_lmod(tmp_op, &tmp_op->operand[0],
6396 &tmp_op->operand[1]);
6397 if (tmp_op->operand[0].lmod == OPLM_DWORD)
6402 tmp_op->pfomask |= pfomask;
6403 cond_vars |= pfomask;
6405 // note: may overwrite, currently not a problem
6409 if (po->op == OP_RCL || po->op == OP_RCR
6410 || po->op == OP_ADC || po->op == OP_SBB)
6411 cond_vars |= 1 << PFO_C;
6417 cond_vars |= 1 << PFO_Z;
6421 if (po->operand[0].lmod == OPLM_DWORD)
6426 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
6431 // note: resolved non-reg calls are OPF_DONE already
6433 ferr_assert(po, pp != NULL);
6435 if (pp->is_unresolved) {
6436 int regmask_stack = 0;
6437 collect_call_args(po, i, opcnt, pp, ®mask, i + opcnt * 2);
6439 // this is pretty rough guess:
6440 // see ecx and edx were pushed (and not their saved versions)
6441 for (arg = 0; arg < pp->argc; arg++) {
6442 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
6445 tmp_op = pp->arg[arg].datap;
6447 ferr(po, "parsed_op missing for arg%d\n", arg);
6448 if (tmp_op->operand[0].type == OPT_REG)
6449 regmask_stack |= 1 << tmp_op->operand[0].reg;
6452 // quick dumb check for potential reg-args
6453 for (j = i - 1; j >= 0 && ops[j].op == OP_MOV; j--)
6454 if (ops[j].operand[0].type == OPT_REG)
6455 regmask_stack &= ~(1 << ops[j].operand[0].reg);
6457 if ((regmask_stack & (mxCX|mxDX)) != (mxCX|mxDX)
6458 && ((regmask | regmask_arg) & (mxCX|mxDX)))
6460 if (pp->argc_stack != 0
6461 || ((regmask | regmask_arg) & (mxCX|mxDX)))
6463 pp_insert_reg_arg(pp, "ecx");
6464 pp->is_fastcall = 1;
6465 regmask_init |= 1 << xCX;
6466 regmask |= 1 << xCX;
6468 if (pp->argc_stack != 0
6469 || ((regmask | regmask_arg) & mxDX))
6471 pp_insert_reg_arg(pp, "edx");
6472 regmask_init |= 1 << xDX;
6473 regmask |= 1 << xDX;
6477 // note: __cdecl doesn't fall into is_unresolved category
6478 if (pp->argc_stack > 0)
6481 if (!(po->flags & OPF_TAIL)
6482 && !(g_sct_func_attr & SCTFA_NOWARN) && !g_nowarn_reguse)
6484 // treat al write as overwrite to avoid many false positives
6485 if (IS(pp->ret_type.name, "void") || pp->ret_type.is_float) {
6486 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
6487 i + opcnt * 25, &j);
6489 fnote(po, "eax used after void/float ret call\n");
6490 fnote(&ops[j], "(used here)\n");
6493 if (!strstr(pp->ret_type.name, "int64")) {
6494 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
6495 i + opcnt * 26, &j);
6496 // indirect calls are often guessed, don't warn
6497 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6498 fnote(po, "edx used after 32bit ret call\n");
6499 fnote(&ops[j], "(used here)\n");
6503 // msvc often relies on callee not modifying 'this'
6504 for (arg = 0; arg < pp->argc; arg++) {
6505 if (pp->arg[arg].reg && IS(pp->arg[arg].reg, "ecx")) {
6511 find_next_read_reg(i + 1, opcnt, xCX, OPLM_BYTE,
6512 i + opcnt * 27, &j);
6513 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6514 fnote(po, "ecx used after call\n");
6515 fnote(&ops[j], "(used here)\n");
6522 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6524 // <var> = offset <something>
6525 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6526 && !IS_START(po->operand[1].name, "off_"))
6528 if (!po->operand[0].pp->is_fptr)
6529 ferr(po, "%s not declared as fptr when it should be\n",
6530 po->operand[0].name);
6531 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6532 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6533 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6534 fnote(po, "var: %s\n", buf1);
6535 fnote(po, "func: %s\n", buf2);
6536 ferr(po, "^ mismatch\n");
6544 if (po->operand[0].lmod == OPLM_DWORD) {
6545 // 32bit division is common, look for it
6546 if (po->op == OP_DIV)
6547 ret = scan_for_reg_clear(i, xDX);
6549 ret = scan_for_cdq_edx(i);
6551 po->flags |= OPF_32BIT;
6560 po->flags |= OPF_RMD | OPF_DONE;
6570 if (po->operand[0].lmod == OPLM_QWORD)
6581 find_next_read_reg(i + 1, opcnt, xDX, OPLM_DWORD,
6582 i + opcnt * 18, &j);
6584 po->flags |= OPF_32BIT;
6592 // pass8: final adjustments
6593 for (i = 0; i < opcnt; i++)
6596 if (po->flags & (OPF_RMD|OPF_DONE))
6599 if (po->op != OP_FST && po->p_argnum > 0)
6600 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6602 // correct for "full stack" mode late enable
6603 if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6604 && need_float_stack)
6605 po->flags |= OPF_FSHIFT;
6608 float_type = need_double ? "double" : "float";
6609 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6610 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6612 // output starts here
6615 fprintf(fout, "// had SEH\n");
6617 // define userstack size
6618 if (g_func_pp->is_userstack) {
6619 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6620 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6621 fprintf(fout, "#endif\n");
6624 // the function itself
6625 ferr_assert(ops, !g_func_pp->is_fptr);
6626 output_pp(fout, g_func_pp,
6627 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6628 fprintf(fout, "\n{\n");
6630 // declare indirect functions
6631 for (i = 0; i < opcnt; i++) {
6633 if (po->flags & OPF_RMD)
6636 if (po->op == OP_CALL) {
6639 ferr(po, "NULL pp\n");
6641 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6642 if (pp->name[0] != 0) {
6643 if (IS_START(pp->name, "guess"))
6646 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6647 memcpy(pp->name, "i_", 2);
6649 // might be declared already
6651 for (j = 0; j < i; j++) {
6652 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6653 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6663 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6666 output_pp(fout, pp, OPP_SIMPLE_ARGS);
6667 fprintf(fout, ";\n");
6672 // output LUTs/jumptables
6673 for (i = 0; i < g_func_pd_cnt; i++) {
6675 fprintf(fout, " static const ");
6676 if (pd->type == OPT_OFFSET) {
6677 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6679 for (j = 0; j < pd->count; j++) {
6681 fprintf(fout, ", ");
6682 fprintf(fout, "&&%s", pd->d[j].u.label);
6686 fprintf(fout, "%s %s[] =\n { ",
6687 lmod_type_u(ops, pd->lmod), pd->label);
6689 for (j = 0; j < pd->count; j++) {
6691 fprintf(fout, ", ");
6692 fprintf(fout, "%u", pd->d[j].u.val);
6695 fprintf(fout, " };\n");
6699 // declare stack frame, va_arg
6702 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6704 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6705 if (g_func_lmods & (1 << OPLM_WORD))
6706 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6707 if (g_func_lmods & (1 << OPLM_BYTE))
6708 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6709 if (g_func_lmods & (1 << OPLM_QWORD))
6710 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6712 if (stack_align > 8)
6713 ferr(ops, "unhandled stack align of %d\n", stack_align);
6714 else if (stack_align == 8)
6715 fprintf(fout, " u64 align;");
6716 fprintf(fout, " } sf;\n");
6720 if ((g_sct_func_attr & SCTFA_ARGFRAME) && g_func_pp->argc_stack) {
6721 fprintf(fout, " struct { u32 ");
6722 for (i = j = 0; i < g_func_pp->argc; i++) {
6723 if (g_func_pp->arg[i].reg != NULL)
6726 fprintf(fout, ", ");
6727 fprintf(fout, "a%d", i + 1);
6729 fprintf(fout, "; } af = {\n ");
6730 for (i = j = 0; i < g_func_pp->argc; i++) {
6731 if (g_func_pp->arg[i].reg != NULL)
6734 fprintf(fout, ", ");
6735 if (g_func_pp->arg[i].type.is_ptr)
6736 fprintf(fout, "(u32)");
6737 fprintf(fout, "a%d", i + 1);
6739 fprintf(fout, "\n };\n");
6742 if (g_func_pp->is_userstack) {
6743 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6744 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6748 if (g_func_pp->is_vararg) {
6749 fprintf(fout, " va_list ap;\n");
6753 // declare arg-registers
6754 for (i = 0; i < g_func_pp->argc; i++) {
6755 if (g_func_pp->arg[i].reg != NULL) {
6756 reg = char_array_i(regs_r32,
6757 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6758 if (regmask & (1 << reg)) {
6759 if (g_func_pp->arg[i].type.is_retreg)
6760 fprintf(fout, " u32 %s = *r_%s;\n",
6761 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6763 fprintf(fout, " u32 %s = (u32)a%d;\n",
6764 g_func_pp->arg[i].reg, i + 1);
6767 if (g_func_pp->arg[i].type.is_retreg)
6768 ferr(ops, "retreg '%s' is unused?\n",
6769 g_func_pp->arg[i].reg);
6770 fprintf(fout, " // %s = a%d; // unused\n",
6771 g_func_pp->arg[i].reg, i + 1);
6777 // declare normal registers
6778 regmask_now = regmask & ~regmask_arg & ~g_regmask_rm;
6779 regmask_now &= ~(1 << xSP);
6780 if (regmask_now & 0x00ff) {
6781 for (reg = 0; reg < 8; reg++) {
6782 if (regmask_now & (1 << reg)) {
6783 fprintf(fout, " u32 %s", regs_r32[reg]);
6784 if (regmask_init & (1 << reg))
6785 fprintf(fout, " = 0");
6786 fprintf(fout, ";\n");
6792 if (regmask_now & 0xff00) {
6793 for (reg = 8; reg < 16; reg++) {
6794 if (regmask_now & (1 << reg)) {
6795 fprintf(fout, " mmxr %s", regs_r32[reg]);
6796 if (regmask_init & (1 << reg))
6797 fprintf(fout, " = { 0, }");
6798 fprintf(fout, ";\n");
6804 if (need_float_stack) {
6805 fprintf(fout, " %s f_st[8];\n", float_type);
6806 fprintf(fout, " int f_stp = 0;\n");
6810 if (regmask_now & 0xff0000) {
6811 for (reg = 16; reg < 24; reg++) {
6812 if (regmask_now & (1 << reg)) {
6813 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6814 if (regmask_init & (1 << reg))
6815 fprintf(fout, " = 0");
6816 fprintf(fout, ";\n");
6823 if (need_float_sw) {
6824 fprintf(fout, " u16 f_sw;\n");
6829 for (reg = 0; reg < 8; reg++) {
6830 if (regmask_save & (1 << reg)) {
6831 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6837 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6838 if (save_arg_vars[i] == 0)
6840 for (reg = 0; reg < 32; reg++) {
6841 if (save_arg_vars[i] & (1 << reg)) {
6842 fprintf(fout, " u32 %s;\n",
6843 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6850 for (reg = 0; reg < 32; reg++) {
6851 if (regmask_ffca & (1 << reg)) {
6852 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6858 // declare push-pop temporaries
6860 for (reg = 0; reg < 8; reg++) {
6861 if (regmask_pp & (1 << reg)) {
6862 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6869 for (i = 0; i < 8; i++) {
6870 if (cond_vars & (1 << i)) {
6871 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6878 fprintf(fout, " u32 tmp;\n");
6883 fprintf(fout, " u64 tmp64;\n");
6888 fprintf(fout, "\n");
6890 // do stack clear, if needed
6891 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6893 if (g_stack_clear_len != 0) {
6894 if (g_stack_clear_len <= 4) {
6895 for (i = 0; i < g_stack_clear_len; i++)
6896 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6897 fprintf(fout, "0;\n");
6900 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6901 g_stack_clear_start, g_stack_clear_len * 4);
6905 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6908 if (g_func_pp->is_vararg) {
6909 if (g_func_pp->argc_stack == 0)
6910 ferr(ops, "vararg func without stack args?\n");
6911 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6915 for (i = 0; i < opcnt; i++)
6917 if (g_labels[i] != NULL) {
6918 fprintf(fout, "\n%s:\n", g_labels[i]);
6921 delayed_flag_op = NULL;
6922 last_arith_dst = NULL;
6926 if (po->flags & OPF_RMD)
6932 #define assert_operand_cnt(n_) \
6933 if (po->operand_cnt != n_) \
6934 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6936 // conditional/flag using op?
6937 if (po->flags & OPF_CC)
6943 // we go through all this trouble to avoid using parsed_flag_op,
6944 // which makes generated code much nicer
6945 if (delayed_flag_op != NULL)
6947 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6948 po->pfo, po->pfo_inv);
6951 else if (last_arith_dst != NULL
6952 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6953 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6956 struct parsed_op *po_arith = (void *)((char *)last_arith_dst
6957 - offsetof(struct parsed_op, operand[0]));
6958 ferr_assert(po, &ops[po_arith - ops] == po_arith);
6959 out_src_opr_u32(buf3, sizeof(buf3), po_arith, last_arith_dst);
6960 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6961 last_arith_dst->lmod, buf3);
6964 else if (tmp_op != NULL) {
6965 // use preprocessed flag calc results
6966 if (!(tmp_op->pfomask & (1 << po->pfo)))
6967 ferr(po, "not prepared for pfo %d\n", po->pfo);
6969 // note: pfo_inv was not yet applied
6970 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6971 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6974 ferr(po, "all methods of finding comparison failed\n");
6977 if (po->flags & OPF_JMP) {
6978 fprintf(fout, " if %s", buf1);
6980 else if (po->op == OP_RCL || po->op == OP_RCR
6981 || po->op == OP_ADC || po->op == OP_SBB)
6984 fprintf(fout, " cond_%s = %s;\n",
6985 parsed_flag_op_names[po->pfo], buf1);
6987 else if (po->flags & OPF_DATA) { // SETcc
6988 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6989 fprintf(fout, " %s = %s;", buf2, buf1);
6992 ferr(po, "unhandled conditional op\n");
6996 pfomask = po->pfomask;
7001 assert_operand_cnt(2);
7002 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7003 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7004 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
7005 fprintf(fout, " %s = %s;", buf1,
7006 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7011 assert_operand_cnt(2);
7012 po->operand[1].lmod = OPLM_DWORD; // always
7013 fprintf(fout, " %s = %s;",
7014 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7015 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7020 assert_operand_cnt(2);
7021 fprintf(fout, " %s = %s;",
7022 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7023 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7027 assert_operand_cnt(2);
7028 switch (po->operand[1].lmod) {
7030 strcpy(buf3, "(s8)");
7033 strcpy(buf3, "(s16)");
7036 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
7038 fprintf(fout, " %s = %s;",
7039 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7040 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7045 assert_operand_cnt(2);
7046 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7047 fprintf(fout, " tmp = %s;",
7048 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
7049 fprintf(fout, " %s = %s;",
7050 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7051 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7052 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7053 fprintf(fout, " %s = %stmp;",
7054 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
7055 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
7056 snprintf(g_comment, sizeof(g_comment), "xchg");
7060 assert_operand_cnt(1);
7061 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7062 fprintf(fout, " %s = ~%s;", buf1, buf1);
7066 assert_operand_cnt(2);
7067 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7068 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7069 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
7070 strcpy(g_comment, "xlat");
7074 assert_operand_cnt(2);
7075 fprintf(fout, " %s = (s32)%s >> 31;",
7076 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7077 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7078 strcpy(g_comment, "cdq");
7082 assert_operand_cnt(1);
7083 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7084 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
7088 if (po->flags & OPF_REP) {
7089 assert_operand_cnt(3);
7094 assert_operand_cnt(2);
7095 fprintf(fout, " %s = %sesi; esi %c= %d;",
7096 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
7097 lmod_cast_u_ptr(po, po->operand[1].lmod),
7098 (po->flags & OPF_DF) ? '-' : '+',
7099 lmod_bytes(po, po->operand[1].lmod));
7100 strcpy(g_comment, "lods");
7105 if (po->flags & OPF_REP) {
7106 assert_operand_cnt(3);
7107 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
7108 (po->flags & OPF_DF) ? '-' : '+',
7109 lmod_bytes(po, po->operand[1].lmod));
7110 fprintf(fout, " %sedi = eax;\n",
7111 lmod_cast_u_ptr(po, po->operand[1].lmod));
7112 fprintf(fout, " barrier();");
7113 strcpy(g_comment, "^ rep stos");
7116 assert_operand_cnt(2);
7117 fprintf(fout, " %sedi = eax; edi %c= %d;",
7118 lmod_cast_u_ptr(po, po->operand[1].lmod),
7119 (po->flags & OPF_DF) ? '-' : '+',
7120 lmod_bytes(po, po->operand[1].lmod));
7121 strcpy(g_comment, "stos");
7126 j = lmod_bytes(po, po->operand[0].lmod);
7127 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
7128 l = (po->flags & OPF_DF) ? '-' : '+';
7129 if (po->flags & OPF_REP) {
7130 assert_operand_cnt(3);
7132 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
7135 " %sedi = %sesi;\n", buf1, buf1);
7136 // this can overwrite many variables
7137 fprintf(fout, " barrier();");
7138 strcpy(g_comment, "^ rep movs");
7141 assert_operand_cnt(2);
7142 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
7143 buf1, buf1, l, j, l, j);
7144 strcpy(g_comment, "movs");
7149 // repe ~ repeat while ZF=1
7150 j = lmod_bytes(po, po->operand[0].lmod);
7151 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
7152 l = (po->flags & OPF_DF) ? '-' : '+';
7153 if (po->flags & OPF_REP) {
7154 assert_operand_cnt(3);
7156 " while (ecx != 0) {\n");
7157 if (pfomask & (1 << PFO_C)) {
7160 " cond_c = %sesi < %sedi;\n", buf1, buf1);
7161 pfomask &= ~(1 << PFO_C);
7164 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
7165 buf1, buf1, l, j, l, j);
7168 " if (cond_z %s 0) break;\n",
7169 (po->flags & OPF_REPZ) ? "==" : "!=");
7172 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
7173 (po->flags & OPF_REPZ) ? "e" : "ne");
7176 assert_operand_cnt(2);
7178 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
7179 buf1, buf1, l, j, l, j);
7180 strcpy(g_comment, "cmps");
7182 pfomask &= ~(1 << PFO_Z);
7183 last_arith_dst = NULL;
7184 delayed_flag_op = NULL;
7188 // only does ZF (for now)
7189 // repe ~ repeat while ZF=1
7190 j = lmod_bytes(po, po->operand[1].lmod);
7191 l = (po->flags & OPF_DF) ? '-' : '+';
7192 if (po->flags & OPF_REP) {
7193 assert_operand_cnt(3);
7195 " while (ecx != 0) {\n");
7197 " cond_z = (%seax == %sedi); edi %c= %d;\n",
7198 lmod_cast_u(po, po->operand[1].lmod),
7199 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
7202 " if (cond_z %s 0) break;\n",
7203 (po->flags & OPF_REPZ) ? "==" : "!=");
7206 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
7207 (po->flags & OPF_REPZ) ? "e" : "ne");
7210 assert_operand_cnt(2);
7211 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
7212 lmod_cast_u(po, po->operand[1].lmod),
7213 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
7214 strcpy(g_comment, "scas");
7216 pfomask &= ~(1 << PFO_Z);
7217 last_arith_dst = NULL;
7218 delayed_flag_op = NULL;
7222 fprintf(fout, " tmp64 = ext_rdtsc();\n");
7223 fprintf(fout, " edx = tmp64 >> 32;\n");
7224 fprintf(fout, " eax = tmp64;");
7228 fprintf(fout, " ext_cpuid(&eax, &ebx, &ecx, &edx);");
7231 // arithmetic w/flags
7233 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
7234 goto dualop_arith_const;
7235 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7239 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7240 if (po->operand[1].type == OPT_CONST) {
7241 j = lmod_bytes(po, po->operand[0].lmod);
7242 if (((1ull << j * 8) - 1) == po->operand[1].val)
7243 goto dualop_arith_const;
7248 assert_operand_cnt(2);
7249 fprintf(fout, " %s %s= %s;",
7250 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7252 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7253 output_std_flags(fout, po, &pfomask, buf1);
7254 last_arith_dst = &po->operand[0];
7255 delayed_flag_op = NULL;
7259 // and 0, or ~0 used instead mov
7260 assert_operand_cnt(2);
7261 fprintf(fout, " %s = %s;",
7262 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7263 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7264 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7265 output_std_flags(fout, po, &pfomask, buf1);
7266 last_arith_dst = &po->operand[0];
7267 delayed_flag_op = NULL;
7272 assert_operand_cnt(2);
7273 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7274 if (pfomask & (1 << PFO_C)) {
7275 if (po->operand[1].type == OPT_CONST) {
7276 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7277 j = po->operand[1].val;
7280 if (po->op == OP_SHL)
7284 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
7288 ferr(po, "zero shift?\n");
7292 pfomask &= ~(1 << PFO_C);
7294 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
7295 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7296 if (po->operand[1].type != OPT_CONST)
7297 fprintf(fout, " & 0x1f");
7299 output_std_flags(fout, po, &pfomask, buf1);
7300 last_arith_dst = &po->operand[0];
7301 delayed_flag_op = NULL;
7305 assert_operand_cnt(2);
7306 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7307 fprintf(fout, " %s = %s%s >> %s;", buf1,
7308 lmod_cast_s(po, po->operand[0].lmod), buf1,
7309 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7310 output_std_flags(fout, po, &pfomask, buf1);
7311 last_arith_dst = &po->operand[0];
7312 delayed_flag_op = NULL;
7317 assert_operand_cnt(3);
7318 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7319 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7320 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
7321 if (po->operand[2].type != OPT_CONST) {
7322 // no handling for "undefined" case, hopefully not needed
7323 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
7326 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7327 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7328 if (po->op == OP_SHLD) {
7329 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
7330 buf1, buf3, buf1, buf2, l, buf3);
7331 strcpy(g_comment, "shld");
7334 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
7335 buf1, buf3, buf1, buf2, l, buf3);
7336 strcpy(g_comment, "shrd");
7338 output_std_flags(fout, po, &pfomask, buf1);
7339 last_arith_dst = &po->operand[0];
7340 delayed_flag_op = NULL;
7345 assert_operand_cnt(2);
7346 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7347 if (po->operand[1].type == OPT_CONST) {
7348 j = po->operand[1].val;
7349 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
7350 fprintf(fout, po->op == OP_ROL ?
7351 " %s = (%s << %d) | (%s >> %d);" :
7352 " %s = (%s >> %d) | (%s << %d);",
7353 buf1, buf1, j, buf1,
7354 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
7358 output_std_flags(fout, po, &pfomask, buf1);
7359 last_arith_dst = &po->operand[0];
7360 delayed_flag_op = NULL;
7365 assert_operand_cnt(2);
7366 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7367 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7368 if (po->operand[1].type == OPT_CONST) {
7369 j = po->operand[1].val % l;
7371 ferr(po, "zero rotate\n");
7372 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
7373 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
7374 if (po->op == OP_RCL) {
7376 " %s = (%s << %d) | (cond_c << %d)",
7377 buf1, buf1, j, j - 1);
7379 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
7383 " %s = (%s >> %d) | (cond_c << %d)",
7384 buf1, buf1, j, l - j);
7386 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
7388 fprintf(fout, ";\n");
7389 fprintf(fout, " cond_c = tmp;");
7393 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
7394 output_std_flags(fout, po, &pfomask, buf1);
7395 last_arith_dst = &po->operand[0];
7396 delayed_flag_op = NULL;
7400 assert_operand_cnt(2);
7401 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7402 if (IS(opr_name(po, 0), opr_name(po, 1))) {
7403 // special case for XOR
7404 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
7405 for (j = 0; j <= PFO_LE; j++) {
7406 if (pfomask & (1 << j)) {
7407 fprintf(fout, " cond_%s = %d;\n",
7408 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
7409 pfomask &= ~(1 << j);
7412 fprintf(fout, " %s = 0;",
7413 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7414 last_arith_dst = &po->operand[0];
7415 delayed_flag_op = NULL;
7421 assert_operand_cnt(2);
7422 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7423 if (pfomask & (1 << PFO_C)) {
7424 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7425 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7426 if (po->operand[0].lmod == OPLM_DWORD) {
7427 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
7428 fprintf(fout, " cond_c = tmp64 >> 32;\n");
7429 fprintf(fout, " %s = (u32)tmp64;",
7430 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7431 strcat(g_comment, " add64");
7434 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
7435 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
7436 fprintf(fout, " %s += %s;",
7437 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7440 pfomask &= ~(1 << PFO_C);
7441 output_std_flags(fout, po, &pfomask, buf1);
7442 last_arith_dst = &po->operand[0];
7443 delayed_flag_op = NULL;
7446 if (pfomask & (1 << PFO_LE)) {
7447 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
7448 fprintf(fout, " cond_%s = %s;\n",
7449 parsed_flag_op_names[PFO_LE], buf1);
7450 pfomask &= ~(1 << PFO_LE);
7455 assert_operand_cnt(2);
7456 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7457 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
7458 for (j = 0; j <= PFO_LE; j++) {
7459 if (!(pfomask & (1 << j)))
7461 if (j == PFO_Z || j == PFO_S)
7464 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7465 fprintf(fout, " cond_%s = %s;\n",
7466 parsed_flag_op_names[j], buf1);
7467 pfomask &= ~(1 << j);
7474 assert_operand_cnt(2);
7475 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7476 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7477 if (po->op == OP_SBB
7478 && IS(po->operand[0].name, po->operand[1].name))
7480 // avoid use of unitialized var
7481 fprintf(fout, " %s = -cond_c;", buf1);
7482 // carry remains what it was
7483 pfomask &= ~(1 << PFO_C);
7486 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
7487 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7489 output_std_flags(fout, po, &pfomask, buf1);
7490 last_arith_dst = &po->operand[0];
7491 delayed_flag_op = NULL;
7496 // on SKL, if src is 0, dst is left unchanged
7497 assert_operand_cnt(2);
7498 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7499 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7500 output_std_flag_z(fout, po, &pfomask, buf2);
7501 if (po->op == OP_BSF)
7502 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
7504 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
7505 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
7506 last_arith_dst = &po->operand[0];
7507 delayed_flag_op = NULL;
7508 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
7512 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
7513 for (j = 0; j <= PFO_LE; j++) {
7514 if (!(pfomask & (1 << j)))
7516 if (j == PFO_Z || j == PFO_S || j == PFO_C)
7519 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7520 fprintf(fout, " cond_%s = %s;\n",
7521 parsed_flag_op_names[j], buf1);
7522 pfomask &= ~(1 << j);
7528 if (pfomask & (1 << PFO_C))
7529 // carry is unaffected by inc/dec.. wtf?
7530 ferr(po, "carry propagation needed\n");
7532 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7533 if (po->operand[0].type == OPT_REG) {
7534 ferr_assert(po, !(po->flags & OPF_LOCK));
7535 strcpy(buf2, po->op == OP_INC ? "++" : "--");
7536 fprintf(fout, " %s%s;", buf1, buf2);
7538 else if (po->flags & OPF_LOCK) {
7539 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], "", 1);
7540 fprintf(fout, " __sync_fetch_and_%s((%s *)(%s), 1);",
7541 po->op == OP_INC ? "add" : "sub",
7542 lmod_type_u(po, po->operand[0].lmod), buf2);
7543 strcat(g_comment, " lock");
7547 strcpy(buf2, po->op == OP_INC ? "+" : "-");
7548 fprintf(fout, " %s %s= 1;", buf1, buf2);
7550 output_std_flags(fout, po, &pfomask, buf1);
7551 last_arith_dst = &po->operand[0];
7552 delayed_flag_op = NULL;
7556 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7557 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
7558 fprintf(fout, " %s = -%s%s;", buf1,
7559 lmod_cast_s(po, po->operand[0].lmod), buf2);
7560 last_arith_dst = &po->operand[0];
7561 delayed_flag_op = NULL;
7562 if (pfomask & PFOB_C) {
7563 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
7566 output_std_flags(fout, po, &pfomask, buf1);
7570 if (po->operand_cnt == 2) {
7571 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7574 if (po->operand_cnt == 3)
7575 ferr(po, "TODO imul3\n");
7578 assert_operand_cnt(1);
7579 switch (po->operand[0].lmod) {
7581 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7582 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
7583 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7584 fprintf(fout, " edx = tmp64 >> 32;\n");
7585 fprintf(fout, " eax = tmp64;");
7588 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7589 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
7590 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7594 ferr(po, "TODO: unhandled mul type\n");
7597 last_arith_dst = NULL;
7598 delayed_flag_op = NULL;
7603 assert_operand_cnt(1);
7604 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7605 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7606 po->op == OP_IDIV));
7607 switch (po->operand[0].lmod) {
7609 if (po->flags & OPF_32BIT)
7610 snprintf(buf2, sizeof(buf2), "%seax", cast);
7612 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7613 snprintf(buf2, sizeof(buf2), "%stmp64",
7614 (po->op == OP_IDIV) ? "(s64)" : "");
7616 if (po->operand[0].type == OPT_REG
7617 && po->operand[0].reg == xDX)
7619 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
7620 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
7623 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
7624 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
7628 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
7629 snprintf(buf2, sizeof(buf2), "%stmp",
7630 (po->op == OP_IDIV) ? "(s32)" : "");
7631 if (po->operand[0].type == OPT_REG
7632 && po->operand[0].reg == xDX)
7634 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
7636 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
7640 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
7642 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
7645 strcat(g_comment, " div16");
7648 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7650 last_arith_dst = NULL;
7651 delayed_flag_op = NULL;
7656 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7658 for (j = 0; j < 8; j++) {
7659 if (pfomask & (1 << j)) {
7660 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7661 fprintf(fout, " cond_%s = %s;",
7662 parsed_flag_op_names[j], buf1);
7669 last_arith_dst = NULL;
7670 delayed_flag_op = po;
7674 // SETcc - should already be handled
7677 // note: we reuse OP_Jcc for SETcc, only flags differ
7679 fprintf(fout, "\n goto %s;", po->operand[0].name);
7683 fprintf(fout, " if (ecx == 0)\n");
7684 fprintf(fout, " goto %s;", po->operand[0].name);
7685 strcat(g_comment, " jecxz");
7689 fprintf(fout, " if (--ecx != 0)\n");
7690 fprintf(fout, " goto %s;", po->operand[0].name);
7691 strcat(g_comment, " loop");
7695 assert_operand_cnt(1);
7696 last_arith_dst = NULL;
7697 delayed_flag_op = NULL;
7699 if (po->operand[0].type == OPT_REGMEM) {
7700 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7703 ferr(po, "parse failure for jmp '%s'\n",
7704 po->operand[0].name);
7705 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
7708 else if (po->operand[0].type != OPT_LABEL)
7709 ferr(po, "unhandled jmp type\n");
7711 fprintf(fout, " goto %s;", po->operand[0].name);
7715 assert_operand_cnt(1);
7717 my_assert_not(pp, NULL);
7720 if (po->flags & OPF_CC) {
7721 // we treat conditional branch to another func
7722 // (yes such code exists..) as conditional tailcall
7724 fprintf(fout, " {\n");
7727 if (pp->is_fptr && !pp->is_arg) {
7728 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7729 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7732 if (pp->is_fptr && (pp->is_unresolved || pp->is_guessed)) {
7733 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7734 buf3, asmfn, po->asmln, pp->name);
7737 fprintf(fout, "%s", buf3);
7738 if (strstr(pp->ret_type.name, "int64")) {
7739 if (po->flags & OPF_TAIL)
7740 ferr(po, "int64 and tail?\n");
7741 fprintf(fout, "tmp64 = ");
7743 else if (!IS(pp->ret_type.name, "void")) {
7744 if (po->flags & OPF_TAIL) {
7745 if (regmask_ret & mxAX) {
7746 fprintf(fout, "return ");
7747 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7748 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7750 else if (regmask_ret & mxST0)
7751 ferr(po, "float tailcall\n");
7753 else if (po->regmask_dst & mxAX) {
7754 fprintf(fout, "eax = ");
7755 if (pp->ret_type.is_ptr)
7756 fprintf(fout, "(u32)");
7758 else if (po->regmask_dst & mxST0) {
7759 ferr_assert(po, po->flags & OPF_FPUSH);
7760 if (need_float_stack)
7761 fprintf(fout, "f_st[--f_stp & 7] = ");
7763 fprintf(fout, "f_st0 = ");
7767 if (pp->name[0] == 0)
7768 ferr(po, "missing pp->name\n");
7769 fprintf(fout, "%s%s(", pp->name,
7770 pp->has_structarg ? "_sa" : "");
7772 if (po->flags & OPF_ATAIL) {
7774 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7775 check_compat |= pp->argc_stack > 0;
7777 && (pp->argc_stack != g_func_pp->argc_stack
7778 || pp->is_stdcall != g_func_pp->is_stdcall))
7779 ferr(po, "incompatible arg-reuse tailcall\n");
7780 if (g_func_pp->has_retreg)
7781 ferr(po, "TODO: retreg+tailcall\n");
7783 for (arg = j = 0; arg < pp->argc; arg++) {
7785 fprintf(fout, ", ");
7788 if (pp->arg[arg].type.is_ptr)
7789 snprintf(cast, sizeof(cast), "(%s)",
7790 pp->arg[arg].type.name);
7792 if (pp->arg[arg].reg != NULL) {
7793 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7797 for (; j < g_func_pp->argc; j++)
7798 if (g_func_pp->arg[j].reg == NULL)
7800 fprintf(fout, "%sa%d", cast, j + 1);
7805 for (arg = 0; arg < pp->argc; arg++) {
7807 fprintf(fout, ", ");
7810 if (pp->arg[arg].type.is_ptr)
7811 snprintf(cast, sizeof(cast), "(%s)",
7812 pp->arg[arg].type.name);
7814 if (pp->arg[arg].reg != NULL) {
7815 if (pp->arg[arg].type.is_retreg)
7816 fprintf(fout, "&%s", pp->arg[arg].reg);
7817 else if (IS(pp->arg[arg].reg, "ebp")
7818 && g_bp_frame && !(po->flags & OPF_EBP_S))
7820 // rare special case
7821 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7822 strcat(g_comment, " bp_ref");
7825 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7830 tmp_op = pp->arg[arg].datap;
7832 ferr(po, "parsed_op missing for arg%d\n", arg);
7834 if (tmp_op->flags & OPF_VAPUSH) {
7835 fprintf(fout, "ap");
7837 else if (tmp_op->op == OP_FST) {
7838 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7839 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7842 else if (pp->arg[arg].type.is_64bit) {
7843 ferr_assert(po, tmp_op->p_argpass == 0);
7844 ferr_assert(po, !pp->arg[arg].is_saved);
7845 ferr_assert(po, !pp->arg[arg].type.is_float);
7846 ferr_assert(po, cast[0] == 0);
7847 out_src_opr(buf1, sizeof(buf1),
7848 tmp_op, &tmp_op->operand[0], cast, 0);
7849 tmp_op = pp->arg[++arg].datap;
7850 ferr_assert(po, tmp_op != NULL);
7851 out_src_opr(buf2, sizeof(buf2),
7852 tmp_op, &tmp_op->operand[0], cast, 0);
7853 fprintf(fout, "((u64)(%s) << 32) | (%s)",
7856 else if (tmp_op->p_argpass != 0) {
7857 ferr_assert(po, !pp->arg[arg].type.is_float);
7858 fprintf(fout, "a%d", tmp_op->p_argpass);
7860 else if (pp->arg[arg].is_saved) {
7861 ferr_assert(po, tmp_op->p_argnum > 0);
7862 ferr_assert(po, !pp->arg[arg].type.is_float);
7863 fprintf(fout, "%s%s", cast,
7864 saved_arg_name(buf1, sizeof(buf1),
7865 tmp_op->p_arggrp, tmp_op->p_argnum));
7867 else if (pp->arg[arg].type.is_float) {
7868 ferr_assert(po, !pp->arg[arg].type.is_64bit);
7870 out_src_opr_float(buf1, sizeof(buf1),
7871 tmp_op, &tmp_op->operand[0], need_float_stack));
7875 out_src_opr(buf1, sizeof(buf1),
7876 tmp_op, &tmp_op->operand[0], cast, 0));
7880 fprintf(fout, ");");
7882 if (strstr(pp->ret_type.name, "int64")) {
7883 fprintf(fout, "\n");
7884 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7885 fprintf(fout, "%seax = tmp64;", buf3);
7888 if (pp->is_unresolved) {
7889 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7891 strcat(g_comment, buf2);
7894 if (po->flags & OPF_TAIL) {
7896 if (i == opcnt - 1 || pp->is_noreturn)
7898 else if (IS(pp->ret_type.name, "void"))
7900 else if (!(regmask_ret & (1 << xAX)))
7902 // else already handled as 'return f()'
7905 fprintf(fout, "\n%sreturn;", buf3);
7906 strcat(g_comment, " ^ tailcall");
7909 strcat(g_comment, " tailcall");
7911 if ((regmask_ret & (1 << xAX))
7912 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7914 ferr(po, "int func -> void func tailcall?\n");
7917 if (pp->is_noreturn)
7918 strcat(g_comment, " noreturn");
7919 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7920 strcat(g_comment, " argframe");
7921 if (po->flags & OPF_CC)
7922 strcat(g_comment, " cond");
7924 if (po->flags & OPF_CC)
7925 fprintf(fout, "\n }");
7927 delayed_flag_op = NULL;
7928 last_arith_dst = NULL;
7933 if (g_func_pp->is_vararg)
7934 fprintf(fout, " va_end(ap);\n");
7935 if (g_func_pp->has_retreg) {
7936 for (arg = 0; arg < g_func_pp->argc; arg++)
7937 if (g_func_pp->arg[arg].type.is_retreg)
7938 fprintf(fout, " *r_%s = %s;\n",
7939 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7942 if (regmask_ret & mxST0) {
7943 fprintf(fout, " return %s;", float_st0);
7945 else if (!(regmask_ret & mxAX)) {
7946 if (i != opcnt - 1 || label_pending)
7947 fprintf(fout, " return;");
7949 else if (g_func_pp->ret_type.is_ptr) {
7950 fprintf(fout, " return (%s)eax;",
7951 g_func_pp->ret_type.name);
7953 else if (IS(g_func_pp->ret_type.name, "__int64"))
7954 fprintf(fout, " return ((u64)edx << 32) | eax;");
7956 fprintf(fout, " return eax;");
7958 last_arith_dst = NULL;
7959 delayed_flag_op = NULL;
7963 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7964 if (po->p_argnum != 0) {
7965 // special case - saved func arg
7966 fprintf(fout, " %s = %s;",
7967 saved_arg_name(buf2, sizeof(buf2),
7968 po->p_arggrp, po->p_argnum), buf1);
7971 else if (po->flags & OPF_RSAVE) {
7972 fprintf(fout, " s_%s = %s;", buf1, buf1);
7975 else if (po->flags & OPF_PPUSH) {
7977 ferr_assert(po, tmp_op != NULL);
7978 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7979 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7982 else if (g_func_pp->is_userstack) {
7983 fprintf(fout, " *(--esp) = %s;", buf1);
7986 if (!(g_ida_func_attr & IDAFA_NORETURN))
7987 ferr(po, "stray push encountered\n");
7992 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7993 if (po->flags & OPF_RSAVE) {
7994 fprintf(fout, " %s = s_%s;", buf1, buf1);
7997 else if (po->flags & OPF_PPUSH) {
7998 // push/pop graph / non-const
7999 ferr_assert(po, po->datap == NULL);
8000 fprintf(fout, " %s = pp_%s;", buf1, buf1);
8003 else if (po->datap != NULL) {
8006 fprintf(fout, " %s = %s;", buf1,
8007 out_src_opr(buf2, sizeof(buf2),
8008 tmp_op, &tmp_op->operand[0],
8009 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
8012 else if (g_func_pp->is_userstack) {
8013 fprintf(fout, " %s = *esp++;", buf1);
8017 ferr(po, "stray pop encountered\n");
8027 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
8028 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
8029 po->op == OPP_ALLSHL ? "<<" : ">>");
8030 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
8031 strcat(g_comment, po->op == OPP_ALLSHL
8032 ? " allshl" : " allshr");
8037 if (need_float_stack) {
8038 out_src_opr_float(buf1, sizeof(buf1),
8039 po, &po->operand[0], 1);
8040 if (po->regmask_src & mxSTa) {
8041 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
8045 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
8048 if (po->flags & OPF_FSHIFT)
8049 fprintf(fout, " f_st1 = f_st0;");
8050 if (po->operand[0].type == OPT_REG
8051 && po->operand[0].reg == xST0)
8053 strcat(g_comment, " fld st");
8056 fprintf(fout, " f_st0 = %s;",
8057 out_src_opr_float(buf1, sizeof(buf1),
8058 po, &po->operand[0], 0));
8060 strcat(g_comment, " fld");
8064 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
8065 lmod_cast(po, po->operand[0].lmod, 1), 0);
8066 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
8067 if (need_float_stack) {
8068 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
8071 if (po->flags & OPF_FSHIFT)
8072 fprintf(fout, " f_st1 = f_st0;");
8073 fprintf(fout, " f_st0 = %s;", buf2);
8075 strcat(g_comment, " fild");
8079 if (need_float_stack)
8080 fprintf(fout, " f_st[--f_stp & 7] = ");
8082 if (po->flags & OPF_FSHIFT)
8083 fprintf(fout, " f_st1 = f_st0;");
8084 fprintf(fout, " f_st0 = ");
8086 switch (po->operand[0].val) {
8087 case X87_CONST_1: fprintf(fout, "1.0;"); break;
8088 case X87_CONST_L2T: fprintf(fout, "3.321928094887362;"); break;
8089 case X87_CONST_L2E: fprintf(fout, "M_LOG2E;"); break;
8090 case X87_CONST_PI: fprintf(fout, "M_PI;"); break;
8091 case X87_CONST_LG2: fprintf(fout, "0.301029995663981;"); break;
8092 case X87_CONST_LN2: fprintf(fout, "M_LN2;"); break;
8093 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
8094 default: ferr_assert(po, 0); break;
8099 if (po->flags & OPF_FARG) {
8100 // store to stack as func arg
8101 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
8105 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8107 dead_dst = po->operand[0].type == OPT_REG
8108 && po->operand[0].reg == xST0;
8111 fprintf(fout, " %s = %s;", buf1, float_st0);
8112 if (po->flags & OPF_FSHIFT) {
8113 if (need_float_stack)
8114 fprintf(fout, " f_stp++;");
8116 fprintf(fout, " f_st0 = f_st1;");
8118 if (dead_dst && !(po->flags & OPF_FSHIFT))
8121 strcat(g_comment, " fst");
8125 fprintf(fout, " %s = %s%s;",
8126 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
8127 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
8128 if (po->flags & OPF_FSHIFT) {
8129 if (need_float_stack)
8130 fprintf(fout, " f_stp++;");
8132 fprintf(fout, " f_st0 = f_st1;");
8134 strcat(g_comment, " fist");
8138 fprintf(fout, " %s = fabs%s(%s);", float_st0,
8139 need_double ? "" : "f", float_st0);
8146 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8148 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8150 dead_dst = (po->flags & OPF_FPOP)
8151 && po->operand[0].type == OPT_REG
8152 && po->operand[0].reg == xST0;
8154 case OP_FADD: j = '+'; break;
8155 case OP_FDIV: j = '/'; break;
8156 case OP_FMUL: j = '*'; break;
8157 case OP_FSUB: j = '-'; break;
8158 default: j = 'x'; break;
8160 if (need_float_stack) {
8162 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
8163 if (po->flags & OPF_FSHIFT)
8164 fprintf(fout, " f_stp++;");
8167 if (po->flags & OPF_FSHIFT) {
8168 // note: assumes only 2 regs handled
8170 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
8172 fprintf(fout, " f_st0 = f_st1;");
8175 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
8177 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
8182 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8184 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8186 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
8188 dead_dst = (po->flags & OPF_FPOP)
8189 && po->operand[0].type == OPT_REG
8190 && po->operand[0].reg == xST0;
8191 j = po->op == OP_FDIVR ? '/' : '-';
8192 if (need_float_stack) {
8194 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
8195 if (po->flags & OPF_FSHIFT)
8196 fprintf(fout, " f_stp++;");
8199 if (po->flags & OPF_FSHIFT) {
8201 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
8203 fprintf(fout, " f_st0 = f_st1;");
8206 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
8208 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
8216 case OP_FIADD: j = '+'; break;
8217 case OP_FIDIV: j = '/'; break;
8218 case OP_FIMUL: j = '*'; break;
8219 case OP_FISUB: j = '-'; break;
8220 default: j = 'x'; break;
8222 fprintf(fout, " %s %c= (%s)%s;", float_st0,
8224 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
8225 lmod_cast(po, po->operand[0].lmod, 1), 0));
8230 fprintf(fout, " %s = %s %c %s;", float_st0,
8231 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8233 po->op == OP_FIDIVR ? '/' : '-', float_st0);
8238 ferr_assert(po, po->datap != NULL);
8239 mask = (long)po->datap & 0xffff;
8240 z_check = ((long)po->datap >> 16) & 1;
8241 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8243 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
8244 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
8247 else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
8248 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
8251 else if (mask == 0x4100) { // C3, C0
8253 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
8255 strcat(g_comment, " z_chk_det");
8258 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
8259 "(%s < %s ? 0x0100 : 0);",
8260 float_st0, buf1, float_st0, buf1);
8264 ferr(po, "unhandled sw mask: %x\n", mask);
8265 if (po->flags & OPF_FSHIFT) {
8266 if (need_float_stack) {
8267 if (po->flags & OPF_FPOPP)
8268 fprintf(fout, " f_stp += 2;");
8270 fprintf(fout, " f_stp++;");
8273 ferr_assert(po, !(po->flags & OPF_FPOPP));
8274 fprintf(fout, " f_st0 = f_st1;");
8281 fprintf(fout, " %s = f_sw;",
8282 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
8286 fprintf(fout, " %s = -%s;", float_st0, float_st0);
8290 fprintf(fout, " %s = cos%s(%s);", float_st0,
8291 need_double ? "" : "f", float_st0);
8295 if (need_float_stack) {
8296 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
8297 need_double ? "" : "f", float_st1, float_st0);
8298 fprintf(fout, " f_stp++;");
8301 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
8302 need_double ? "" : "f");
8307 if (need_float_stack) {
8308 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
8309 float_st1, need_double ? "" : "f", float_st0);
8310 fprintf(fout, " f_stp++;");
8313 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
8314 need_double ? "" : "f");
8316 strcat(g_comment, " fyl2x");
8320 fprintf(fout, " %s = sin%s(%s);", float_st0,
8321 need_double ? "" : "f", float_st0);
8325 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
8326 need_double ? "" : "f", float_st0);
8330 dead_dst = po->operand[0].type == OPT_REG
8331 && po->operand[0].reg == xST0;
8333 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8335 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
8336 float_st0, float_st0, buf1, buf1);
8337 strcat(g_comment, " fxch");
8344 ferr_assert(po, po->flags & OPF_32BIT);
8345 fprintf(fout, " eax = (s32)%s;", float_st0);
8346 if (po->flags & OPF_FSHIFT) {
8347 if (need_float_stack)
8348 fprintf(fout, " f_stp++;");
8350 fprintf(fout, " f_st0 = f_st1;");
8352 strcat(g_comment, " ftol");
8356 if (need_float_stack) {
8357 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
8358 need_double ? "" : "f", float_st1, float_st0);
8359 fprintf(fout, " f_stp++;");
8362 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
8363 need_double ? "" : "f");
8365 strcat(g_comment, " CIpow");
8369 fprintf(fout, " do_skip_code_abort();");
8374 fprintf(fout, " do_emms();");
8378 if (po->flags & OPF_TAIL) {
8379 fprintf(fout, "\n");
8380 strcat(g_comment, " tail");
8387 ferr(po, "unhandled op type %d, flags %x\n",
8392 if (g_comment[0] != 0) {
8393 char *p = g_comment;
8394 while (my_isblank(*p))
8396 fprintf(fout, " // %s", p);
8401 fprintf(fout, "\n");
8403 // some sanity checking
8404 if (po->flags & OPF_REP) {
8405 if (po->op != OP_STOS && po->op != OP_MOVS
8406 && po->op != OP_CMPS && po->op != OP_SCAS)
8407 ferr(po, "unexpected rep\n");
8408 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
8409 && (po->op == OP_CMPS || po->op == OP_SCAS))
8410 ferr(po, "cmps/scas with plain rep\n");
8412 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
8413 && po->op != OP_CMPS && po->op != OP_SCAS)
8414 ferr(po, "unexpected repz/repnz\n");
8417 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
8419 if ((po->flags & OPF_LOCK) && !lock_handled)
8420 ferr(po, "unhandled lock\n");
8422 // see is delayed flag stuff is still valid
8423 if (delayed_flag_op != NULL && delayed_flag_op != po) {
8424 if (is_any_opr_modified(delayed_flag_op, po, 0))
8425 delayed_flag_op = NULL;
8428 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
8429 if (is_opr_modified(last_arith_dst, po))
8430 last_arith_dst = NULL;
8437 if (g_stack_fsz && !g_stack_frame_used)
8438 fprintf(fout, " (void)sf;\n");
8440 fprintf(fout, "}\n\n");
8442 gen_x_cleanup(opcnt);
8445 static void gen_x_cleanup(int opcnt)
8449 for (i = 0; i < opcnt; i++) {
8450 struct label_ref *lr, *lr_del;
8452 lr = g_label_refs[i].next;
8453 while (lr != NULL) {
8458 g_label_refs[i].i = -1;
8459 g_label_refs[i].next = NULL;
8461 if (ops[i].op == OP_CALL) {
8463 proto_release(ops[i].pp);
8469 struct func_proto_dep;
8471 struct func_prototype {
8475 int regmask_dep; // likely register args
8476 int regmask_use; // used registers
8477 int has_ret:3; // -1, 0, 1: unresolved, no, yes
8478 unsigned int has_ret64:1;
8479 unsigned int dep_resolved:1;
8480 unsigned int is_stdcall:1;
8481 unsigned int eax_pass:1; // returns without touching eax
8482 unsigned int ptr_taken:1; // pointer taken of this func
8483 struct func_proto_dep *dep_func;
8485 const struct parsed_proto *pp; // seed pp, if any
8488 struct func_proto_dep {
8490 struct func_prototype *proto;
8491 int regmask_live; // .. at the time of call
8492 unsigned int ret_dep:1; // return from this is caller's return
8493 unsigned int has_ret:1; // found from eax use after return
8494 unsigned int has_ret64:1;
8495 unsigned int ptr_taken:1; // pointer taken, not a call
8498 static struct func_prototype *hg_fp;
8499 static int hg_fp_cnt;
8501 static struct scanned_var {
8503 enum opr_lenmod lmod;
8504 unsigned int is_seeded:1;
8505 unsigned int is_c_str:1;
8506 const struct parsed_proto *pp; // seed pp, if any
8508 static int hg_var_cnt;
8510 static char **hg_refs;
8511 static int hg_ref_cnt;
8513 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8516 static struct func_prototype *hg_fp_add(const char *funcn)
8518 struct func_prototype *fp;
8520 if ((hg_fp_cnt & 0xff) == 0) {
8521 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
8522 my_assert_not(hg_fp, NULL);
8523 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
8526 fp = &hg_fp[hg_fp_cnt];
8527 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
8529 fp->argc_stack = -1;
8535 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
8540 for (i = 0; i < fp->dep_func_cnt; i++)
8541 if (IS(fp->dep_func[i].name, name))
8542 return &fp->dep_func[i];
8547 static void hg_fp_add_dep(struct func_prototype *fp, const char *name,
8548 unsigned int ptr_taken)
8550 struct func_proto_dep * dep;
8553 dep = hg_fp_find_dep(fp, name);
8554 if (dep != NULL && dep->ptr_taken == ptr_taken)
8557 if ((fp->dep_func_cnt & 0xff) == 0) {
8558 fp->dep_func = realloc(fp->dep_func,
8559 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
8560 my_assert_not(fp->dep_func, NULL);
8561 memset(&fp->dep_func[fp->dep_func_cnt], 0,
8562 sizeof(fp->dep_func[0]) * 0x100);
8564 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
8565 fp->dep_func[fp->dep_func_cnt].ptr_taken = ptr_taken;
8569 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
8571 const struct func_prototype *p1 = p1_, *p2 = p2_;
8572 return strcmp(p1->name, p2->name);
8576 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
8578 const struct func_prototype *p1 = p1_, *p2 = p2_;
8579 return p1->id - p2->id;
8583 static void hg_ref_add(const char *name)
8585 if ((hg_ref_cnt & 0xff) == 0) {
8586 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8587 my_assert_not(hg_refs, NULL);
8588 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8591 hg_refs[hg_ref_cnt] = strdup(name);
8592 my_assert_not(hg_refs[hg_ref_cnt], NULL);
8596 // recursive register dep pass
8597 // - track saved regs (part 2)
8598 // - try to figure out arg-regs
8599 // - calculate reg deps
8600 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8601 struct func_prototype *fp, int regmask_save, int regmask_dst,
8602 int *regmask_dep, int *regmask_use, int *has_ret)
8604 struct func_proto_dep *dep;
8605 struct parsed_op *po;
8606 int from_caller = 0;
8611 for (; i < opcnt; i++)
8613 if (cbits[i >> 3] & (1 << (i & 7)))
8615 cbits[i >> 3] |= (1 << (i & 7));
8619 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8620 if (po->flags & OPF_RMD)
8623 if (po->btj != NULL) {
8625 for (j = 0; j < po->btj->count; j++) {
8626 check_i(po, po->btj->d[j].bt_i);
8627 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8628 regmask_save, regmask_dst, regmask_dep, regmask_use,
8634 check_i(po, po->bt_i);
8635 if (po->flags & OPF_CJMP) {
8636 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8637 regmask_save, regmask_dst, regmask_dep, regmask_use,
8646 if (po->flags & OPF_FARG)
8647 /* (just calculate register deps) */;
8648 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8650 reg = po->operand[0].reg;
8651 ferr_assert(po, reg >= 0);
8653 if (po->flags & OPF_RSAVE) {
8654 regmask_save |= 1 << reg;
8657 if (po->flags & OPF_DONE)
8660 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2,
8663 regmask_save |= 1 << reg;
8664 po->flags |= OPF_RMD;
8665 scan_for_pop(i + 1, opcnt, i + opcnt * 3,
8666 reg, 0, 0, 0, OPF_RMD);
8670 else if (po->flags & OPF_RMD)
8672 else if (po->op == OP_CALL) {
8673 po->regmask_dst |= 1 << xAX;
8675 dep = hg_fp_find_dep(fp, po->operand[0].name);
8677 dep->regmask_live = regmask_save | regmask_dst;
8678 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8679 dep->regmask_live |= 1 << xBP;
8681 if ((po->flags & OPF_TAIL) && po->pp != NULL
8682 && po->pp->is_stdcall)
8685 else if (po->op == OP_RET) {
8686 if (po->operand_cnt > 0) {
8688 if (fp->argc_stack >= 0
8689 && fp->argc_stack != po->operand[0].val / 4)
8690 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8691 fp->argc_stack = po->operand[0].val / 4;
8695 if (!fp->eax_pass && (po->flags & OPF_TAIL)) {
8696 if (po->op == OP_CALL) {
8703 ret = resolve_origin_reg(i, xAX, i + opcnt * 4, &j, &from_caller);
8706 if (ret != 1 && from_caller) {
8707 // unresolved eax - probably void func
8712 if (j >= 0 && ops[j].op == OP_CALL) {
8713 if (ops[j].pp != NULL && !ops[j].pp->is_unresolved) {
8714 int call_has_ret = !IS(ops[j].pp->ret_type.name, "void");
8715 if (ops[j].pp->is_noreturn) {
8716 // could be some fail path
8718 *has_ret = call_has_ret;
8721 *has_ret = call_has_ret;
8724 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8736 l = regmask_save | regmask_dst;
8737 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8740 l = po->regmask_src & ~l;
8743 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8744 l, regmask_dst, regmask_save, po->flags);
8747 *regmask_use |= (po->regmask_src | po->regmask_dst)
8749 regmask_dst |= po->regmask_dst;
8751 if (po->flags & OPF_TAIL) {
8752 if (!(po->flags & OPF_CC)) // not cond. tailcall
8758 static void gen_hdr(const char *funcn, int opcnt)
8760 unsigned char cbits[MAX_OPS / 8];
8761 const struct parsed_proto *pp_c;
8762 struct parsed_proto *pp;
8763 struct func_prototype *fp;
8764 struct func_proto_dep *dep;
8765 struct parsed_op *po;
8766 const char *tmpname;
8767 int regmask_dummy = 0;
8770 int max_bp_offset = 0;
8775 pp_c = proto_parse(g_fhdr, funcn, 1);
8777 // already in seed, will add to hg_fp later
8780 fp = hg_fp_add(funcn);
8782 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8783 g_stack_frame_used = 0;
8787 // - resolve all branches
8788 // - parse calls with labels
8789 resolve_branches_parse_calls(opcnt);
8792 // - handle ebp/esp frame, remove ops related to it
8793 scan_prologue_epilogue(opcnt, NULL);
8796 // - remove dead labels
8798 // - collect function ptr refs
8799 for (i = 0; i < opcnt; i++)
8801 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8807 if (po->flags & (OPF_RMD|OPF_DONE))
8810 if (po->op == OP_CALL) {
8811 if (po->operand[0].type == OPT_LABEL)
8812 hg_fp_add_dep(fp, opr_name(po, 0), 0);
8813 else if (po->pp != NULL)
8814 hg_fp_add_dep(fp, po->pp->name, 0);
8816 else if (po->op == OP_MOV && po->operand[1].type == OPT_OFFSET) {
8817 tmpname = opr_name(po, 1);
8818 if (IS_START(tmpname, "p_") || IS_START(tmpname, "sub_"))
8819 hg_fp_add_dep(fp, tmpname, 1);
8821 else if (po->op == OP_PUSH && po->operand[0].type == OPT_OFFSET) {
8822 tmpname = opr_name(po, 0);
8823 if (IS_START(tmpname, "p_") || IS_START(tmpname, "sub_"))
8824 hg_fp_add_dep(fp, tmpname, 1);
8829 // - handle push <const>/pop pairs
8830 for (i = 0; i < opcnt; i++)
8833 if (po->flags & (OPF_RMD|OPF_DONE))
8836 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8837 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8841 // - process trivial calls
8842 for (i = 0; i < opcnt; i++)
8845 if (po->flags & (OPF_RMD|OPF_DONE))
8848 if (po->op == OP_CALL)
8850 pp = process_call_early(i, opcnt, &j);
8852 if (!(po->flags & OPF_ATAIL))
8853 // since we know the args, try to collect them
8854 if (collect_call_args_early(i, opcnt, pp, NULL, NULL) != 0)
8860 // commit esp adjust
8861 if (ops[j].op != OP_POP)
8862 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8864 for (l = 0; l < pp->argc_stack; l++)
8865 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8869 po->flags |= OPF_DONE;
8875 // - track saved regs (simple)
8877 for (i = 0; i < opcnt; i++)
8880 if (po->flags & (OPF_RMD|OPF_DONE))
8883 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8884 && po->operand[0].reg != xCX)
8886 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8888 // regmask_save |= 1 << po->operand[0].reg; // do it later
8889 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8890 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8893 else if (po->op == OP_CALL)
8895 pp = process_call(i, opcnt);
8897 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8898 // since we know the args, collect them
8899 ret = collect_call_args(po, i, opcnt, pp, ®mask_dummy,
8902 if (!(po->flags & OPF_TAIL)
8903 && po->operand[0].type == OPT_LABEL)
8905 dep = hg_fp_find_dep(fp, opr_name(po, 0));
8906 ferr_assert(po, dep != NULL);
8907 // treat al write as overwrite to avoid many false positives
8908 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
8909 i + opcnt * 25, &j);
8912 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
8913 i + opcnt * 26, &j);
8914 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j]))
8921 memset(cbits, 0, (opcnt + 7) / 8);
8922 regmask_dep = regmask_use = 0;
8925 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0,
8926 ®mask_dep, ®mask_use, &has_ret);
8928 // find unreachable code - must be fixed in IDA
8929 for (i = 0; i < opcnt; i++)
8931 if (cbits[i >> 3] & (1 << (i & 7)))
8934 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8935 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8937 // the compiler sometimes still generates code after
8938 // noreturn OS functions
8941 if (!(ops[i].flags & OPF_RMD)
8942 && ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8944 ferr(&ops[i], "unreachable code\n");
8948 for (i = 0; i < g_eqcnt; i++) {
8949 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8950 max_bp_offset = g_eqs[i].offset;
8953 if (fp->argc_stack < 0) {
8954 max_bp_offset = (max_bp_offset + 3) & ~3;
8955 fp->argc_stack = max_bp_offset / 4;
8956 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8960 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8961 fp->regmask_use = regmask_use;
8962 fp->has_ret = has_ret;
8964 printf("// has_ret %d, regmask_dep %x\n",
8965 fp->has_ret, fp->regmask_dep);
8966 output_hdr_fp(stdout, fp, 1);
8967 if (IS(funcn, "sub_10007F72")) exit(1);
8970 gen_x_cleanup(opcnt);
8973 static void hg_fp_resolve_deps(struct func_prototype *fp)
8975 struct func_prototype fp_s;
8976 struct func_proto_dep *dep;
8980 // this thing is recursive, so mark first..
8981 fp->dep_resolved = 1;
8983 for (i = 0; i < fp->dep_func_cnt; i++) {
8984 dep = &fp->dep_func[i];
8986 strcpy(fp_s.name, dep->name);
8987 dep->proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8988 sizeof(hg_fp[0]), hg_fp_cmp_name);
8989 if (dep->proto != NULL) {
8990 if (dep->ptr_taken) {
8991 dep->proto->ptr_taken = 1;
8995 if (!dep->proto->dep_resolved)
8996 hg_fp_resolve_deps(dep->proto);
8998 regmask_dep = ~dep->regmask_live
8999 & dep->proto->regmask_dep;
9000 fp->regmask_dep |= regmask_dep;
9001 // printf("dep %s %s |= %x\n", fp->name,
9002 // fp->dep_func[i].name, regmask_dep);
9004 if (dep->has_ret && (dep->proto->regmask_use & mxAX))
9005 dep->proto->has_ret = 1;
9006 if (dep->has_ret64 && (dep->proto->regmask_use & mxDX))
9007 dep->proto->has_ret64 = 1;
9008 if (fp->has_ret == -1 && dep->ret_dep)
9009 fp->has_ret = dep->proto->has_ret;
9014 // make all thiscall/edx arg functions referenced from .data fastcall
9015 static void do_func_refs_from_data(void)
9017 struct func_prototype *fp, fp_s;
9020 for (i = 0; i < hg_ref_cnt; i++) {
9021 strcpy(fp_s.name, hg_refs[i]);
9022 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
9023 sizeof(hg_fp[0]), hg_fp_cmp_name);
9029 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
9032 const struct parsed_proto *pp;
9033 char *p, namebuf[NAMELEN];
9039 for (; count > 0; count--, fp++) {
9040 if (fp->has_ret == -1)
9041 fprintf(fout, "// ret unresolved\n");
9043 fprintf(fout, "// dep:");
9044 for (j = 0; j < fp->dep_func_cnt; j++) {
9045 fprintf(fout, " %s/", fp->dep_func[j].name);
9046 if (fp->dep_func[j].proto != NULL)
9047 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
9048 fp->dep_func[j].proto->has_ret);
9050 fprintf(fout, "\n");
9053 p = strchr(fp->name, '@');
9055 memcpy(namebuf, fp->name, p - fp->name);
9056 namebuf[p - fp->name] = 0;
9064 pp = proto_parse(g_fhdr, name, 1);
9065 if (pp != NULL && pp->is_include)
9068 if (fp->pp != NULL) {
9069 // part of seed, output later
9073 regmask_dep = fp->regmask_dep;
9074 argc_normal = fp->argc_stack;
9075 if (fp->ptr_taken && regmask_dep
9076 && (regmask_dep & ~(mxCX|mxDX)) == 0)
9078 if ((regmask_dep & mxDX) || fp->argc_stack > 0)
9079 regmask_dep |= mxCX | mxDX;
9082 fprintf(fout, "%-5s",
9083 fp->pp ? fp->pp->ret_type.name :
9084 fp->has_ret64 ? "__int64" :
9085 fp->has_ret ? "int" : "void");
9086 if (regmask_dep == mxCX && fp->is_stdcall && fp->argc_stack > 0) {
9087 fprintf(fout, "/*__thiscall*/ ");
9091 else if ((regmask_dep == (mxCX | mxDX)
9092 && (fp->is_stdcall || fp->argc_stack == 0))
9093 || (regmask_dep == mxCX && fp->argc_stack == 0))
9095 fprintf(fout, " __fastcall ");
9096 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
9102 else if (regmask_dep && !fp->is_stdcall) {
9103 fprintf(fout, "/*__usercall*/ ");
9105 else if (regmask_dep) {
9106 fprintf(fout, "/*__userpurge*/ ");
9108 else if (fp->is_stdcall)
9109 fprintf(fout, " __stdcall ");
9111 fprintf(fout, " __cdecl ");
9113 fprintf(fout, "%s(", name);
9116 for (j = 0; j < xSP; j++) {
9117 if (regmask_dep & (1 << j)) {
9120 fprintf(fout, ", ");
9122 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
9124 fprintf(fout, "int");
9125 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
9129 for (j = 0; j < argc_normal; j++) {
9132 fprintf(fout, ", ");
9133 if (fp->pp != NULL) {
9134 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
9135 if (!fp->pp->arg[arg - 1].type.is_ptr)
9139 fprintf(fout, "int ");
9140 fprintf(fout, "a%d", arg);
9143 fprintf(fout, ");\n");
9147 static void output_hdr(FILE *fout)
9149 static const char *lmod_c_names[] = {
9150 [OPLM_UNSPEC] = "???",
9151 [OPLM_BYTE] = "uint8_t",
9152 [OPLM_WORD] = "uint16_t",
9153 [OPLM_DWORD] = "uint32_t",
9154 [OPLM_QWORD] = "uint64_t",
9156 const struct scanned_var *var;
9157 struct func_prototype *fp;
9158 char line[256] = { 0, };
9162 // add stuff from headers
9163 for (i = 0; i < pp_cache_size; i++) {
9164 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
9165 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
9167 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
9168 fp = hg_fp_add(name);
9169 fp->pp = &pp_cache[i];
9170 fp->argc_stack = fp->pp->argc_stack;
9171 fp->is_stdcall = fp->pp->is_stdcall;
9172 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
9173 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
9177 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
9178 for (i = 0; i < hg_fp_cnt; i++)
9179 hg_fp_resolve_deps(&hg_fp[i]);
9181 // adjust functions referenced from data segment
9182 do_func_refs_from_data();
9184 // final adjustments
9185 for (i = 0; i < hg_fp_cnt; i++) {
9186 if (hg_fp[i].eax_pass && (hg_fp[i].regmask_dep & mxAX))
9187 hg_fp[i].has_ret = 1;
9190 // note: messes up .proto ptr, don't use
9191 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
9194 for (i = 0; i < hg_var_cnt; i++) {
9197 if (var->pp != NULL)
9200 else if (var->is_c_str)
9201 fprintf(fout, "extern %-8s %s[];", "char", var->name);
9203 fprintf(fout, "extern %-8s %s;",
9204 lmod_c_names[var->lmod], var->name);
9207 fprintf(fout, " // seeded");
9208 fprintf(fout, "\n");
9211 fprintf(fout, "\n");
9213 // output function prototypes
9214 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
9217 fprintf(fout, "\n// - seed -\n");
9220 while (fgets(line, sizeof(line), g_fhdr))
9221 fwrite(line, 1, strlen(line), fout);
9224 // '=' needs special treatment
9226 static char *next_word_s(char *w, size_t wsize, char *s)
9233 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
9235 for (i = 1; i < wsize - 1; i++) {
9237 printf("warning: missing closing quote: \"%s\"\n", s);
9246 for (; i < wsize - 1; i++) {
9247 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
9253 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
9254 printf("warning: '%s' truncated\n", w);
9259 static int cmpstringp(const void *p1, const void *p2)
9261 return strcmp(*(char * const *)p1, *(char * const *)p2);
9264 static int is_xref_needed(char *p, char **rlist, int rlist_len)
9269 if (strstr(p, "..."))
9270 // unable to determine, assume needed
9273 if (*p == '.') // .text, .data, ...
9274 // ref from other data or non-function -> no
9277 p2 = strpbrk(p, "+:\r\n\x18");
9280 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9281 // referenced from removed code
9287 static int ida_xrefs_show_need(FILE *fasm, char *p,
9288 char **rlist, int rlist_len)
9294 p = strrchr(p, ';');
9295 if (p != NULL && *p == ';') {
9296 if (IS_START(p + 2, "sctref"))
9298 if (IS_START(p + 2, "DATA XREF: ")) {
9300 if (is_xref_needed(p, rlist, rlist_len))
9308 if (!my_fgets(line, sizeof(line), fasm))
9310 // non-first line is always indented
9311 if (!my_isblank(line[0]))
9314 // should be no content, just comment
9319 p = strrchr(p, ';');
9322 if (IS_START(p, "sctref")) {
9327 // it's printed once, but no harm to check again
9328 if (IS_START(p, "DATA XREF: "))
9331 if (is_xref_needed(p, rlist, rlist_len)) {
9336 fseek(fasm, pos, SEEK_SET);
9340 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
9342 struct scanned_var *var;
9343 char line[256] = { 0, };
9352 // skip to next data section
9353 while (my_fgets(line, sizeof(line), fasm))
9358 if (*p == 0 || *p == ';')
9361 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
9362 if (*p == 0 || *p == ';')
9365 if (*p != 's' || !IS_START(p, "segment para public"))
9371 if (p == NULL || !IS_START(p, "segment para public"))
9375 if (!IS_START(p, "'DATA'"))
9379 while (my_fgets(line, sizeof(line), fasm))
9384 no_identifier = my_isblank(*p);
9387 if (*p == 0 || *p == ';')
9390 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9391 words[wordc][0] = 0;
9392 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9393 if (*p == 0 || *p == ';') {
9399 if (wordc == 2 && IS(words[1], "ends"))
9404 if (no_identifier) {
9405 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
9406 hg_ref_add(words[2]);
9410 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
9411 // when this starts, we don't need anything from this section
9415 // check refs comment(s)
9416 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
9419 if ((hg_var_cnt & 0xff) == 0) {
9420 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
9421 * (hg_var_cnt + 0x100));
9422 my_assert_not(hg_vars, NULL);
9423 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
9426 var = &hg_vars[hg_var_cnt++];
9427 snprintf(var->name, sizeof(var->name), "%s", words[0]);
9429 // maybe already in seed header?
9430 var->pp = proto_parse(g_fhdr, var->name, 1);
9431 if (var->pp != NULL) {
9432 if (var->pp->is_fptr) {
9433 var->lmod = OPLM_DWORD;
9436 else if (var->pp->is_func)
9438 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
9439 aerr("unhandled C type '%s' for '%s'\n",
9440 var->pp->type.name, var->name);
9446 if (IS(words[1], "dd")) {
9447 var->lmod = OPLM_DWORD;
9448 if (wordc >= 4 && IS(words[2], "offset"))
9449 hg_ref_add(words[3]);
9451 else if (IS(words[1], "dw"))
9452 var->lmod = OPLM_WORD;
9453 else if (IS(words[1], "db")) {
9454 var->lmod = OPLM_BYTE;
9455 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
9456 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
9460 else if (IS(words[1], "dq"))
9461 var->lmod = OPLM_QWORD;
9462 //else if (IS(words[1], "dt"))
9464 aerr("type '%s' not known\n", words[1]);
9472 static void set_label(int i, const char *name)
9478 p = strchr(name, ':');
9482 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
9483 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
9484 g_labels[i] = realloc(g_labels[i], len + 1);
9485 my_assert_not(g_labels[i], NULL);
9486 memcpy(g_labels[i], name, len);
9487 g_labels[i][len] = 0;
9496 static struct chunk_item *func_chunks;
9497 static int func_chunk_cnt;
9498 static int func_chunk_alloc;
9500 static void add_func_chunk(FILE *fasm, const char *name, int line)
9502 if (func_chunk_cnt >= func_chunk_alloc) {
9503 func_chunk_alloc *= 2;
9504 func_chunks = realloc(func_chunks,
9505 func_chunk_alloc * sizeof(func_chunks[0]));
9506 my_assert_not(func_chunks, NULL);
9508 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
9509 func_chunks[func_chunk_cnt].name = strdup(name);
9510 func_chunks[func_chunk_cnt].asmln = line;
9514 static int cmp_chunks(const void *p1, const void *p2)
9516 const struct chunk_item *c1 = p1, *c2 = p2;
9517 return strcmp(c1->name, c2->name);
9520 static void scan_ahead_for_chunks(FILE *fasm)
9530 oldpos = ftell(fasm);
9533 while (my_fgets(line, sizeof(line), fasm))
9544 // get rid of random tabs
9545 for (i = 0; line[i] != 0; i++)
9546 if (line[i] == '\t')
9549 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9552 next_word(words[0], sizeof(words[0]), p);
9553 if (words[0][0] == 0)
9554 aerr("missing name for func chunk?\n");
9556 add_func_chunk(fasm, words[0], asmln);
9558 else if (IS_START(p, "; sctend"))
9564 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9565 words[wordc][0] = 0;
9566 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9567 if (*p == 0 || *p == ';') {
9573 if (wordc == 2 && IS(words[1], "ends"))
9577 fseek(fasm, oldpos, SEEK_SET);
9581 int main(int argc, char *argv[])
9583 FILE *fout, *fasm, *frlist;
9584 struct parsed_data *pd = NULL;
9586 char **rlist = NULL;
9588 int rlist_alloc = 0;
9589 int func_chunks_used = 0;
9590 int func_chunks_sorted = 0;
9591 int func_chunk_i = -1;
9592 long func_chunk_ret = 0;
9593 int func_chunk_ret_ln = 0;
9594 int scanned_ahead = 0;
9596 char words[20][256];
9597 enum opr_lenmod lmod;
9598 char *sctproto = NULL;
9600 int pending_endp = 0;
9602 int skip_code_end = 0;
9603 int skip_warned = 0;
9616 for (arg = 1; arg < argc; arg++) {
9617 if (IS(argv[arg], "-v"))
9619 else if (IS(argv[arg], "-rf"))
9620 g_allow_regfunc = 1;
9621 else if (IS(argv[arg], "-uc"))
9622 g_allow_user_icall = 1;
9623 else if (IS(argv[arg], "-wu"))
9624 g_nowarn_reguse = 1;
9625 else if (IS(argv[arg], "-m"))
9627 else if (IS(argv[arg], "-hdr"))
9628 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
9633 if (argc < arg + 3) {
9634 printf("usage:\n%s [options] <.c> <.asm> <hdr.h> [rlist]*\n"
9635 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
9637 " -hdr - header generation mode\n"
9638 " -rf - allow unannotated indirect calls\n"
9639 " -uc - allow ind. calls/refs to __usercall\n"
9640 " -m - allow multiple .text sections\n"
9641 " -wu - don't warn about bad reg use\n"
9642 "[rlist] is a file with function names to skip,"
9650 asmfn = argv[arg++];
9651 fasm = fopen(asmfn, "r");
9652 my_assert_not(fasm, NULL);
9654 hdrfn = argv[arg++];
9655 g_fhdr = fopen(hdrfn, "r");
9656 my_assert_not(g_fhdr, NULL);
9659 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9660 my_assert_not(rlist, NULL);
9661 // needs special handling..
9662 rlist[rlist_len++] = "__alloca_probe";
9664 func_chunk_alloc = 32;
9665 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9666 my_assert_not(func_chunks, NULL);
9668 memset(words, 0, sizeof(words));
9670 for (; arg < argc; arg++) {
9673 frlist = fopen(argv[arg], "r");
9674 my_assert_not(frlist, NULL);
9676 while (my_fgets(line, sizeof(line), frlist)) {
9678 if (*p == 0 || *p == ';')
9681 if (IS_START(p, "#if 0")
9682 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9686 else if (IS_START(p, "#endif"))
9693 p = next_word(words[0], sizeof(words[0]), p);
9694 if (words[0][0] == 0)
9697 if (rlist_len >= rlist_alloc) {
9698 rlist_alloc = rlist_alloc * 2 + 64;
9699 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9700 my_assert_not(rlist, NULL);
9702 rlist[rlist_len++] = strdup(words[0]);
9710 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9712 fout = fopen(argv[arg_out], "w");
9713 my_assert_not(fout, NULL);
9716 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9717 my_assert_not(g_eqs, NULL);
9719 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9720 g_label_refs[i].i = -1;
9721 g_label_refs[i].next = NULL;
9725 scan_variables(fasm, rlist, rlist_len);
9727 while (my_fgets(line, sizeof(line), fasm))
9736 // get rid of random tabs
9737 for (i = 0; line[i] != 0; i++)
9738 if (line[i] == '\t')
9743 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9744 goto do_pending_endp; // eww..
9746 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9748 static const char *attrs[] = {
9757 // parse IDA's attribute-list comment
9758 g_ida_func_attr = 0;
9761 for (; *p != 0; p = sskip(p)) {
9762 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9763 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9764 g_ida_func_attr |= 1 << i;
9765 p += strlen(attrs[i]);
9769 if (i == ARRAY_SIZE(attrs)) {
9770 anote("unparsed IDA attr: %s\n", p);
9773 if (IS(attrs[i], "fpd=")) {
9774 p = next_word(words[0], sizeof(words[0]), p);
9779 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9781 static const char *attrs[] = {
9789 // parse manual attribute-list comment
9790 g_sct_func_attr = 0;
9793 for (; *p != 0; p = sskip(p)) {
9794 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9795 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9796 g_sct_func_attr |= 1 << i;
9797 p += strlen(attrs[i]);
9804 // clear_sf=start,len (in dwords)
9805 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9806 &g_stack_clear_len, &j);
9808 // clear_regmask=<mask>
9809 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9811 // rm_regmask=<mask>
9812 ret = sscanf(p, "=%x%n", &g_regmask_rm, &j) + 1;
9814 anote("unparsed attr value: %s\n", p);
9819 else if (i == ARRAY_SIZE(attrs)) {
9820 anote("unparsed sct attr: %s\n", p);
9825 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9828 next_word(words[0], sizeof(words[0]), p);
9829 if (words[0][0] == 0)
9830 aerr("missing name for func chunk?\n");
9832 if (!scanned_ahead) {
9833 add_func_chunk(fasm, words[0], asmln);
9834 func_chunks_sorted = 0;
9837 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9839 if (func_chunk_i >= 0) {
9840 if (func_chunk_i < func_chunk_cnt
9841 && IS(func_chunks[func_chunk_i].name, g_func))
9843 // move on to next chunk
9844 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9846 aerr("seek failed for '%s' chunk #%d\n",
9847 g_func, func_chunk_i);
9848 asmln = func_chunks[func_chunk_i].asmln;
9852 if (func_chunk_ret == 0)
9853 aerr("no return from chunk?\n");
9854 fseek(fasm, func_chunk_ret, SEEK_SET);
9855 asmln = func_chunk_ret_ln;
9861 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9862 func_chunks_used = 1;
9864 if (IS_START(g_func, "sub_")) {
9865 unsigned long addr = strtoul(p, NULL, 16);
9866 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9867 if (addr > f_addr && !scanned_ahead) {
9868 //anote("scan_ahead caused by '%s', addr %lx\n",
9870 scan_ahead_for_chunks(fasm);
9872 func_chunks_sorted = 0;
9880 for (i = wordc; i < ARRAY_SIZE(words); i++)
9882 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9883 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9884 if (*p == 0 || *p == ';') {
9889 if (*p != 0 && *p != ';')
9890 aerr("too many words\n");
9892 if (skip_code_end) {
9897 // allow asm patches in comments
9899 // skip IDA's forced non-removable comment
9900 if (!IS_START(p, "; sct") && (p2 = strchr(p + 1, ';')))
9903 if (*p == ';' && IS_START(p, "; sct")) {
9904 if (IS_START(p, "; sctpatch:")) {
9906 if (*p == 0 || *p == ';')
9908 goto parse_words; // lame
9910 else if (IS_START(p, "; sctend")) {
9915 else if (g_skip_func)
9916 /* ignore remaining attrs */;
9917 else if (IS_START(p, "; sctproto:")) {
9918 sctproto = strdup(p + 11);
9920 else if (IS_START(p, "; sctskip_start")) {
9923 ops[pi].op = OPP_ABORT;
9924 ops[pi].asmln = asmln;
9930 else if (IS_START(p, "; sctskip_end")) {
9938 awarn("wordc == 0?\n");
9942 // don't care about this:
9943 if (words[0][0] == '.'
9944 || IS(words[0], "include")
9945 || IS(words[0], "assume") || IS(words[1], "segment")
9946 || IS(words[0], "align"))
9952 // do delayed endp processing to collect switch jumptables
9954 if (in_func && !g_skip_func && !end && wordc >= 2
9955 && ((words[0][0] == 'd' && words[0][2] == 0)
9956 || (words[1][0] == 'd' && words[1][2] == 0)))
9959 if (words[1][0] == 'd' && words[1][2] == 0) {
9961 if (g_func_pd_cnt >= pd_alloc) {
9962 pd_alloc = pd_alloc * 2 + 16;
9963 g_func_pd = realloc(g_func_pd,
9964 sizeof(g_func_pd[0]) * pd_alloc);
9965 my_assert_not(g_func_pd, NULL);
9967 pd = &g_func_pd[g_func_pd_cnt];
9969 memset(pd, 0, sizeof(*pd));
9970 strcpy(pd->label, words[0]);
9971 pd->type = OPT_CONST;
9972 pd->lmod = lmod_from_directive(words[1]);
9978 anote("skipping alignment byte?\n");
9981 lmod = lmod_from_directive(words[0]);
9982 if (lmod != pd->lmod)
9983 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9986 if (pd->count_alloc < pd->count + wordc) {
9987 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9988 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9989 my_assert_not(pd->d, NULL);
9991 for (; i < wordc; i++) {
9992 if (IS(words[i], "offset")) {
9993 pd->type = OPT_OFFSET;
9996 p = strchr(words[i], ',');
9999 if (pd->type == OPT_OFFSET)
10000 pd->d[pd->count].u.label = strdup(words[i]);
10002 pd->d[pd->count].u.val = parse_number(words[i], 0);
10003 pd->d[pd->count].bt_i = -1;
10009 if (in_func && !g_skip_func) {
10011 gen_hdr(g_func, pi);
10013 gen_func(fout, g_fhdr, g_func, pi);
10018 g_ida_func_attr = 0;
10019 g_sct_func_attr = 0;
10020 g_stack_clear_start = 0;
10021 g_stack_clear_len = 0;
10022 g_regmask_init = 0;
10028 func_chunks_used = 0;
10031 memset(&ops, 0, pi * sizeof(ops[0]));
10036 for (i = 0; i < g_func_pd_cnt; i++) {
10037 pd = &g_func_pd[i];
10038 if (pd->type == OPT_OFFSET) {
10039 for (j = 0; j < pd->count; j++)
10040 free(pd->d[j].u.label);
10055 if (IS(words[1], "proc")) {
10057 aerr("proc '%s' while in_func '%s'?\n",
10060 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
10062 strcpy(g_func, words[0]);
10063 set_label(0, words[0]);
10068 if (IS(words[1], "endp"))
10071 aerr("endp '%s' while not in_func?\n", words[0]);
10072 if (!IS(g_func, words[0]))
10073 aerr("endp '%s' while in_func '%s'?\n",
10076 aerr("endp '%s' while skipping code\n", words[0]);
10078 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
10079 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
10085 if (!g_skip_func && func_chunks_used) {
10086 // start processing chunks
10087 struct chunk_item *ci, key = { g_func, 0 };
10089 func_chunk_ret = ftell(fasm);
10090 func_chunk_ret_ln = asmln;
10091 if (!func_chunks_sorted) {
10092 qsort(func_chunks, func_chunk_cnt,
10093 sizeof(func_chunks[0]), cmp_chunks);
10094 func_chunks_sorted = 1;
10096 ci = bsearch(&key, func_chunks, func_chunk_cnt,
10097 sizeof(func_chunks[0]), cmp_chunks);
10099 aerr("'%s' needs chunks, but none found\n", g_func);
10100 func_chunk_i = ci - func_chunks;
10101 for (; func_chunk_i > 0; func_chunk_i--)
10102 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
10105 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
10107 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
10108 asmln = func_chunks[func_chunk_i].asmln;
10116 if (wordc == 2 && IS(words[1], "ends")) {
10120 goto do_pending_endp;
10124 // scan for next text segment
10125 while (my_fgets(line, sizeof(line), fasm)) {
10128 if (*p == 0 || *p == ';')
10131 if (strstr(p, "segment para public 'CODE' use32"))
10138 p = strchr(words[0], ':');
10140 set_label(pi, words[0]);
10144 if (!in_func || g_skip_func || skip_code) {
10145 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
10147 anote("skipping from '%s'\n", g_labels[pi]);
10150 free(g_labels[pi]);
10151 g_labels[pi] = NULL;
10155 if (wordc > 1 && IS(words[1], "="))
10158 aerr("unhandled equ, wc=%d\n", wordc);
10159 if (g_eqcnt >= eq_alloc) {
10161 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
10162 my_assert_not(g_eqs, NULL);
10165 len = strlen(words[0]);
10166 if (len > sizeof(g_eqs[0].name) - 1)
10167 aerr("equ name too long: %d\n", len);
10168 strcpy(g_eqs[g_eqcnt].name, words[0]);
10170 if (!IS(words[3], "ptr"))
10171 aerr("unhandled equ\n");
10172 if (IS(words[2], "dword"))
10173 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
10174 else if (IS(words[2], "word"))
10175 g_eqs[g_eqcnt].lmod = OPLM_WORD;
10176 else if (IS(words[2], "byte"))
10177 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
10178 else if (IS(words[2], "qword"))
10179 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
10181 aerr("bad lmod: '%s'\n", words[2]);
10183 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
10188 if (pi >= ARRAY_SIZE(ops))
10189 aerr("too many ops\n");
10191 parse_op(&ops[pi], words, wordc);
10193 ops[pi].datap = sctproto;
10208 // vim:ts=2:shiftwidth=2:expandtab