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: call's saved arg #
228 unsigned char p_arggrp; // arg push: arg group # for above
229 unsigned char p_argpass;// arg push: arg of host func
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
292 SCTFA_UA_FLOAT = (1 << 5), // emit float i/o helpers for alignemnt
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, };
1953 char argname[8], buf2[32];
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) {
1976 // vararg access - messy and non-portable,
1977 // but works with gcc on both x86 and ARM
1978 if (arg_i == g_func_pp->argc_stack)
1979 // should be va_list
1980 snprintf(buf2, sizeof(buf2), "*(u32 *)&ap");
1982 snprintf(buf2, sizeof(buf2), "(*(u32 *)&ap + %u)",
1983 (arg_i - g_func_pp->argc_stack) * 4);
1986 snprintf(buf, buf_size, "%s%s", cast, buf2);
1988 snprintf(buf, buf_size, "%s*(u32 *)%s", cast, buf2);
1991 ferr(po, "offset 0x%x (%s,%d) doesn't map to any arg\n",
1992 offset, bp_arg, arg_i);
1994 if (ofs_reg[0] != 0)
1995 ferr(po, "offset reg on arg access?\n");
1997 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1998 if (g_func_pp->arg[i].reg != NULL)
2004 if (i == g_func_pp->argc)
2005 ferr(po, "arg %d not in prototype?\n", arg_i);
2007 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
2010 snprintf(argname, sizeof(argname), "%sa%d",
2011 g_sct_func_attr & SCTFA_ARGFRAME ? "af." : "", i + 1);
2017 ferr(po, "lea/byte to arg?\n");
2018 if (is_src && (offset & 3) == 0)
2019 snprintf(buf, buf_size, "%s%s",
2020 simplify_cast(cast, "(u8)"), argname);
2022 snprintf(buf, buf_size, "%sBYTE%d(%s)",
2023 cast, offset & 3, argname);
2028 ferr(po, "lea/word to arg?\n");
2033 ferr(po, "problematic arg store\n");
2034 snprintf(buf, buf_size, "%s((char *)&%s + 1)",
2035 simplify_cast(cast, "*(u16 *)"), argname);
2038 ferr(po, "unaligned arg word load\n");
2040 else if (is_src && (offset & 2) == 0)
2041 snprintf(buf, buf_size, "%s%s",
2042 simplify_cast(cast, "(u16)"), argname);
2044 snprintf(buf, buf_size, "%s%sWORD(%s)",
2045 cast, (offset & 2) ? "HI" : "LO", argname);
2057 snprintf(buf, buf_size, "(u32)&%s + %d",
2058 argname, offset & 3);
2060 ferr(po, "unaligned arg store\n");
2062 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
2063 snprintf(buf, buf_size, "%s(%s >> %d)",
2064 prefix, argname, (offset & 3) * 8);
2068 snprintf(buf, buf_size, "%s%s%s",
2069 prefix, is_lea ? "&" : "", argname);
2074 ferr_assert(po, !(offset & 7));
2077 snprintf(buf, buf_size, "%s%s%s",
2078 prefix, is_lea ? "&" : "", argname);
2082 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
2086 strcat(g_comment, " unaligned");
2089 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
2090 if (tmp_lmod != OPLM_DWORD
2091 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
2092 < lmod_bytes(po, popr->lmod) + (offset & 3))))
2094 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
2095 i + 1, offset, g_func_pp->arg[i].type.name);
2097 // can't check this because msvc likes to reuse
2098 // arg space for scratch..
2099 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
2100 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2104 if (g_stack_fsz == 0)
2105 ferr(po, "stack var access without stackframe\n");
2106 g_stack_frame_used = 1;
2108 sf_ofs = g_stack_fsz + offset;
2109 if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2110 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2120 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2121 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2125 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2126 // known unaligned or possibly unaligned
2127 strcat(g_comment, " unaligned");
2129 prefix = "*(u16 *)&";
2130 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2131 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2134 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2138 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2139 // known unaligned or possibly unaligned
2140 strcat(g_comment, " unaligned");
2142 prefix = "*(u32 *)&";
2143 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2144 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2147 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2151 ferr_assert(po, !(sf_ofs & 7));
2152 ferr_assert(po, ofs_reg[0] == 0);
2153 // only used for x87 int64/float, float sets is_lea
2154 if (!is_lea && (po->flags & OPF_FINT))
2155 prefix = "*(s64 *)&";
2156 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2160 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2167 static void check_func_pp(struct parsed_op *po,
2168 const struct parsed_proto *pp, const char *pfx)
2170 enum opr_lenmod tmp_lmod;
2174 if (pp->argc_reg != 0) {
2175 if (!g_allow_user_icall && !pp->is_fastcall) {
2176 pp_print(buf, sizeof(buf), pp);
2177 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2179 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2180 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2181 pfx, pp->argc_reg, pp->argc_stack);
2184 // fptrs must use 32bit args, callsite might have no information and
2185 // lack a cast to smaller types, which results in incorrectly masked
2186 // args passed (callee may assume masked args, it does on ARM)
2187 if (!pp->is_osinc) {
2188 for (i = 0; i < pp->argc; i++) {
2189 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2190 if (ret && tmp_lmod != OPLM_DWORD)
2191 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2192 i + 1, pp->arg[i].type.name);
2197 static const char *check_label_read_ref(struct parsed_op *po,
2198 const char *name, int *is_import)
2200 const struct parsed_proto *pp;
2202 pp = proto_parse(g_fhdr, name, 0);
2204 ferr(po, "proto_parse failed for ref '%s'\n", name);
2207 check_func_pp(po, pp, "ref");
2209 if (is_import != NULL)
2210 *is_import = pp->is_import;
2215 static void check_opr(struct parsed_op *po, struct parsed_opr *popr)
2217 if (popr->segment == SEG_FS)
2218 ferr(po, "fs: used\n");
2219 if (popr->segment == SEG_GS)
2220 ferr(po, "gs: used\n");
2223 static char *out_src_opr(char *buf, size_t buf_size,
2224 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2227 char tmp1[256], tmp2[256];
2234 check_opr(po, popr);
2239 switch (popr->type) {
2242 ferr(po, "lea from reg?\n");
2244 switch (popr->lmod) {
2246 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2249 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2252 snprintf(buf, buf_size, "%s%s",
2253 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2256 if (popr->name[1] == 'h') // XXX..
2257 snprintf(buf, buf_size, "%s(%s >> 8)",
2258 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2260 snprintf(buf, buf_size, "%s%s",
2261 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2264 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2269 if (is_stack_access(po, popr)) {
2270 stack_frame_access(po, popr, buf, buf_size,
2271 popr->name, cast, 1, is_lea);
2275 strcpy(expr, popr->name);
2276 if (strchr(expr, '[')) {
2277 // special case: '[' can only be left for label[reg] form
2278 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2280 ferr(po, "parse failure for '%s'\n", expr);
2281 if (tmp1[0] == '(') {
2282 // (off_4FFF50+3)[eax]
2283 p = strchr(tmp1 + 1, ')');
2284 if (p == NULL || p[1] != 0)
2285 ferr(po, "parse failure (2) for '%s'\n", expr);
2287 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2289 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2292 // XXX: do we need more parsing?
2294 snprintf(buf, buf_size, "%s", expr);
2298 snprintf(buf, buf_size, "%s(%s)",
2299 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2303 name = check_label_read_ref(po, popr->name, &is_import);
2305 // for imported data, asm is loading the offset
2308 if (cast[0] == 0 && popr->is_ptr)
2312 snprintf(buf, buf_size, "(u32)&%s", name);
2313 else if (popr->size_lt)
2314 snprintf(buf, buf_size, "%s%s%s%s", cast,
2315 lmod_cast_u_ptr(po, popr->lmod),
2316 popr->is_array ? "" : "&", name);
2318 snprintf(buf, buf_size, "%s%s%s", cast, name,
2319 popr->is_array ? "[0]" : "");
2324 name = check_label_read_ref(po, popr->name, NULL);
2328 ferr(po, "lea an offset?\n");
2329 snprintf(buf, buf_size, "%s&%s", cast, name);
2334 ferr(po, "lea from const?\n");
2336 printf_number(tmp1, sizeof(tmp1), popr->val);
2337 if (popr->val == 0 && strchr(cast, '*'))
2338 snprintf(buf, buf_size, "NULL");
2340 snprintf(buf, buf_size, "%s%s",
2341 simplify_cast_num(cast, popr->val), tmp1);
2345 ferr(po, "invalid src type: %d\n", popr->type);
2351 // note: may set is_ptr (we find that out late for ebp frame..)
2352 static char *out_dst_opr(char *buf, size_t buf_size,
2353 struct parsed_op *po, struct parsed_opr *popr)
2355 check_opr(po, popr);
2357 switch (popr->type) {
2359 switch (popr->lmod) {
2361 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2364 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2368 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2372 if (popr->name[1] == 'h') // XXX..
2373 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2375 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2378 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2383 if (is_stack_access(po, popr)) {
2384 stack_frame_access(po, popr, buf, buf_size,
2385 popr->name, "", 0, 0);
2389 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2392 if (popr->size_mismatch)
2393 snprintf(buf, buf_size, "%s%s%s",
2394 lmod_cast_u_ptr(po, popr->lmod),
2395 popr->is_array ? "" : "&", popr->name);
2397 snprintf(buf, buf_size, "%s%s", popr->name,
2398 popr->is_array ? "[0]" : "");
2402 ferr(po, "invalid dst type: %d\n", popr->type);
2408 static char *out_src_opr_u32(char *buf, size_t buf_size,
2409 struct parsed_op *po, struct parsed_opr *popr)
2411 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2414 // do we need a helper func to perform a float i/o?
2415 static int float_opr_needs_helper(struct parsed_op *po,
2416 struct parsed_opr *popr)
2418 if (!(g_sct_func_attr & SCTFA_UA_FLOAT))
2420 if (popr->type != OPT_REGMEM)
2422 if (is_stack_access(po, popr))
2428 static char *out_opr_float(char *buf, size_t buf_size,
2429 struct parsed_op *po, struct parsed_opr *popr, int is_src,
2430 int need_float_stack)
2432 const char *cast = NULL;
2439 switch (popr->type) {
2441 if (popr->reg < xST0 || popr->reg > xST7) {
2443 ferr_assert(po, po->op == OP_PUSH);
2444 ferr_assert(po, popr->lmod == OPLM_DWORD);
2445 snprintf(buf, buf_size, "*(float *)&%s", opr_reg_p(po, popr));
2449 if (need_float_stack) {
2450 if (popr->reg == xST0)
2451 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2453 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2457 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2461 if (popr->lmod == OPLM_QWORD && is_stack_access(po, popr)) {
2462 stack_frame_access(po, popr, buf, buf_size,
2463 popr->name, "", is_src, 0);
2469 switch (popr->lmod) {
2477 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2480 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2481 if (is_src && float_opr_needs_helper(po, popr))
2482 snprintf(buf, buf_size, "%s_load(%s)", cast, tmp);
2484 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2488 // only for func float args pushes
2489 ferr_assert(po, po->op == OP_PUSH);
2490 u.i = po->operand[0].val;
2491 if (ceilf(u.f) == u.f)
2492 snprintf(buf, buf_size, "%.1ff", u.f);
2494 snprintf(buf, buf_size, "%.8ff", u.f);
2498 ferr(po, "invalid float type: %d\n", popr->type);
2504 static char *out_src_opr_float(char *buf, size_t buf_size,
2505 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2507 return out_opr_float(buf, buf_size, po, popr, 1, need_float_stack);
2510 static char *out_dst_opr_float(char *buf, size_t buf_size,
2511 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2513 return out_opr_float(buf, buf_size, po, popr, 0, need_float_stack);
2516 static void out_test_for_cc(char *buf, size_t buf_size,
2517 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2518 enum opr_lenmod lmod, const char *expr)
2520 const char *cast, *scast;
2522 cast = lmod_cast_u(po, lmod);
2523 scast = lmod_cast_s(po, lmod);
2527 case PFO_BE: // CF==1||ZF==1; CF=0
2528 snprintf(buf, buf_size, "(%s%s %s 0)",
2529 cast, expr, is_inv ? "!=" : "==");
2533 case PFO_L: // SF!=OF; OF=0
2534 snprintf(buf, buf_size, "(%s%s %s 0)",
2535 scast, expr, is_inv ? ">=" : "<");
2538 case PFO_LE: // ZF==1||SF!=OF; OF=0
2539 snprintf(buf, buf_size, "(%s%s %s 0)",
2540 scast, expr, is_inv ? ">" : "<=");
2545 snprintf(buf, buf_size, "(%d)", !!is_inv);
2548 case PFO_P: // PF==1
2549 snprintf(buf, buf_size, "(%sdo_parity(%s))",
2550 is_inv ? "!" : "", expr);
2554 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2558 static void out_cmp_for_cc(char *buf, size_t buf_size,
2559 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2562 const char *cast, *scast, *cast_use;
2563 char buf1[256], buf2[256];
2564 enum opr_lenmod lmod;
2566 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2567 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2568 po->operand[0].lmod, po->operand[1].lmod);
2569 lmod = po->operand[0].lmod;
2571 cast = lmod_cast_u(po, lmod);
2572 scast = lmod_cast_s(po, lmod);
2588 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2591 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2592 if (po->op == OP_DEC)
2593 snprintf(buf2, sizeof(buf2), "1");
2596 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2598 strcat(cast_op2, "-");
2599 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2604 // note: must be unsigned compare
2605 snprintf(buf, buf_size, "(%s %s %s)",
2606 buf1, is_inv ? ">=" : "<", buf2);
2610 snprintf(buf, buf_size, "(%s %s %s)",
2611 buf1, is_inv ? "!=" : "==", buf2);
2615 // note: must be unsigned compare
2616 snprintf(buf, buf_size, "(%s %s %s)",
2617 buf1, is_inv ? ">" : "<=", buf2);
2620 if (is_inv && lmod == OPLM_BYTE
2621 && po->operand[1].type == OPT_CONST
2622 && po->operand[1].val == 0xff)
2624 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2625 snprintf(buf, buf_size, "(0)");
2629 // note: must be signed compare
2631 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2632 scast, buf1, buf2, is_inv ? ">=" : "<");
2636 snprintf(buf, buf_size, "(%s %s %s)",
2637 buf1, is_inv ? ">=" : "<", buf2);
2641 snprintf(buf, buf_size, "(%s %s %s)",
2642 buf1, is_inv ? ">" : "<=", buf2);
2650 static void out_cmp_test(char *buf, size_t buf_size,
2651 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2653 char buf1[256], buf2[256], buf3[256];
2655 if (po->op == OP_TEST) {
2656 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2657 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2660 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2661 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2662 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2664 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2665 po->operand[0].lmod, buf3);
2667 else if (po->op == OP_CMP) {
2668 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2671 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2674 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2675 struct parsed_opr *popr2)
2677 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2678 ferr(po, "missing lmod for both operands\n");
2680 if (popr1->lmod == OPLM_UNSPEC)
2681 popr1->lmod = popr2->lmod;
2682 else if (popr2->lmod == OPLM_UNSPEC)
2683 popr2->lmod = popr1->lmod;
2684 else if (popr1->lmod != popr2->lmod) {
2685 if (popr1->type_from_var) {
2686 popr1->size_mismatch = 1;
2687 if (popr1->lmod < popr2->lmod)
2689 popr1->lmod = popr2->lmod;
2691 else if (popr2->type_from_var) {
2692 popr2->size_mismatch = 1;
2693 if (popr2->lmod < popr1->lmod)
2695 popr2->lmod = popr1->lmod;
2698 ferr(po, "conflicting lmods: %d vs %d\n",
2699 popr1->lmod, popr2->lmod);
2703 static const char *op_to_c(struct parsed_op *po)
2727 ferr(po, "op_to_c was supplied with %d\n", po->op);
2731 // last op in stream - unconditional branch or ret
2732 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2733 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2734 && ops[_i].op != OP_CALL))
2736 #define check_i(po, i) \
2738 ferr(po, "bad " #i ": %d\n", i)
2740 // note: this skips over calls and rm'd stuff assuming they're handled
2741 // so it's intended to use at one of final passes
2742 // exception: doesn't skip OPF_RSAVE stuff
2743 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2744 int depth, int seen_noreturn, int save_level, int flags_set)
2746 struct parsed_op *po;
2751 for (; i < opcnt; i++) {
2753 if (po->cc_scratch == magic)
2754 return ret; // already checked
2755 po->cc_scratch = magic;
2757 if (po->flags & OPF_TAIL) {
2758 if (po->op == OP_CALL && po->pp != NULL && po->pp->is_noreturn) {
2759 // msvc sometimes generates stack cleanup code after
2760 // noreturn, set a flag and continue
2763 // ... but stop if there is another path to next insn -
2764 // if msvc skipped something stack tracking may mess up
2765 if (i + 1 < opcnt && g_labels[i + 1] != NULL)
2772 if (po->flags & OPF_FARG)
2774 if (po->flags & (OPF_RMD|OPF_DONE)) {
2775 if (!(po->flags & OPF_RSAVE))
2777 // reprocess, there might be another push in some "parallel"
2778 // path that took a pop what we should also take
2781 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2782 if (po->btj != NULL) {
2784 for (j = 0; j < po->btj->count; j++) {
2785 check_i(po, po->btj->d[j].bt_i);
2786 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2787 depth, seen_noreturn, save_level, flags_set);
2789 return ret; // dead end
2794 check_i(po, po->bt_i);
2795 if (po->flags & OPF_CJMP) {
2796 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2797 depth, seen_noreturn, save_level, flags_set);
2799 return ret; // dead end
2808 if ((po->op == OP_POP || po->op == OP_PUSH)
2809 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2814 if (po->op == OP_PUSH) {
2817 else if (po->op == OP_POP) {
2818 if (relevant && depth == 0) {
2819 if (flags_set == 0 && save_level > 0) {
2820 ret = scan_for_pop(i + 1, opcnt, magic, reg,
2821 depth, seen_noreturn, save_level - 1, flags_set);
2823 // no pop for other levels, current one must be false
2826 po->flags |= flags_set;
2834 // for noreturn, assume msvc skipped stack cleanup
2835 return seen_noreturn ? 1 : -1;
2838 // scan for 'reg' pop backwards starting from i
2839 // intended to use for register restore search, so other reg
2840 // references are considered an error
2841 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2843 struct parsed_op *po;
2844 struct label_ref *lr;
2847 ops[i].cc_scratch = magic;
2851 if (g_labels[i] != NULL) {
2852 lr = &g_label_refs[i];
2853 for (; lr != NULL; lr = lr->next) {
2854 check_i(&ops[i], lr->i);
2855 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2859 if (i > 0 && LAST_OP(i - 1))
2867 if (ops[i].cc_scratch == magic)
2869 ops[i].cc_scratch = magic;
2872 if (po->op == OP_POP && po->operand[0].reg == reg) {
2873 if (po->flags & (OPF_RMD|OPF_DONE))
2876 po->flags |= set_flags;
2880 // this also covers the case where we reach corresponding push
2881 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2885 // nothing interesting on this path,
2886 // still return ret for something recursive calls could find
2890 static void find_reachable_exits(int i, int opcnt, int magic,
2891 int *exits, int *exit_count)
2893 struct parsed_op *po;
2896 for (; i < opcnt; i++)
2899 if (po->cc_scratch == magic)
2901 po->cc_scratch = magic;
2903 if (po->flags & OPF_TAIL) {
2904 ferr_assert(po, *exit_count < MAX_EXITS);
2905 exits[*exit_count] = i;
2910 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2911 if (po->flags & OPF_RMD)
2914 if (po->btj != NULL) {
2915 for (j = 0; j < po->btj->count; j++) {
2916 check_i(po, po->btj->d[j].bt_i);
2917 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2923 check_i(po, po->bt_i);
2924 if (po->flags & OPF_CJMP)
2925 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2933 // scan for 'reg' pop backwards starting from exits (all paths)
2934 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2936 static int exits[MAX_EXITS];
2937 static int exit_count;
2943 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2945 ferr_assert(&ops[i], exit_count > 0);
2948 for (j = 0; j < exit_count; j++) {
2950 ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2956 if (ops[e].op == OP_CALL && ops[e].pp != NULL
2957 && ops[e].pp->is_noreturn)
2959 // assume stack cleanup was skipped
2968 // scan for one or more pop of push <const>
2969 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2970 int push_i, int is_probe)
2972 struct parsed_op *po;
2973 struct label_ref *lr;
2977 for (; i < opcnt; i++)
2980 if (po->cc_scratch == magic)
2981 return ret; // already checked
2982 po->cc_scratch = magic;
2984 if (po->flags & OPF_JMP) {
2985 if (po->flags & OPF_RMD)
2987 if (po->op == OP_CALL)
2990 if (po->btj != NULL) {
2991 for (j = 0; j < po->btj->count; j++) {
2992 check_i(po, po->btj->d[j].bt_i);
2993 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
3001 check_i(po, po->bt_i);
3002 if (po->flags & OPF_CJMP) {
3003 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
3014 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
3017 if (g_labels[i] != NULL) {
3018 // all refs must be visited
3019 lr = &g_label_refs[i];
3020 for (; lr != NULL; lr = lr->next) {
3022 if (ops[lr->i].cc_scratch != magic)
3025 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
3029 if (po->op == OP_POP)
3031 if (po->flags & (OPF_RMD|OPF_DONE))
3035 po->flags |= OPF_DONE;
3036 po->datap = &ops[push_i];
3045 static void scan_for_pop_const(int i, int opcnt, int magic)
3049 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
3051 ops[i].flags |= OPF_RMD | OPF_DONE;
3052 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
3056 // check if all branch targets within a marked path are also marked
3057 // note: the path checked must not be empty or end with a branch
3058 static int check_path_branches(int opcnt, int magic)
3060 struct parsed_op *po;
3063 for (i = 0; i < opcnt; i++) {
3065 if (po->cc_scratch != magic)
3068 if (po->flags & OPF_JMP) {
3069 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
3072 if (po->btj != NULL) {
3073 for (j = 0; j < po->btj->count; j++) {
3074 check_i(po, po->btj->d[j].bt_i);
3075 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
3080 check_i(po, po->bt_i);
3081 if (ops[po->bt_i].cc_scratch != magic)
3083 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
3091 // scan for multiple pushes for given pop
3092 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
3095 int reg = ops[pop_i].operand[0].reg;
3096 struct parsed_op *po;
3097 struct label_ref *lr;
3100 ops[i].cc_scratch = magic;
3104 if (g_labels[i] != NULL) {
3105 lr = &g_label_refs[i];
3106 for (; lr != NULL; lr = lr->next) {
3107 check_i(&ops[i], lr->i);
3108 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
3112 if (i > 0 && LAST_OP(i - 1))
3120 if (ops[i].cc_scratch == magic)
3122 ops[i].cc_scratch = magic;
3125 if (po->op == OP_CALL)
3127 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
3130 if (po->op == OP_PUSH)
3132 if (po->datap != NULL)
3134 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
3135 // leave this case for reg save/restore handlers
3139 po->flags |= OPF_PPUSH | OPF_DONE;
3140 po->datap = &ops[pop_i];
3149 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
3151 int magic = i + opcnt * 14;
3154 ret = scan_pushes_for_pop_r(i, magic, i, 1);
3156 ret = check_path_branches(opcnt, magic);
3158 ops[i].flags |= OPF_PPUSH | OPF_DONE;
3159 *regmask_pp |= 1 << ops[i].operand[0].reg;
3160 scan_pushes_for_pop_r(i, magic + 1, i, 0);
3165 static void scan_propagate_df(int i, int opcnt)
3167 struct parsed_op *po = &ops[i];
3170 for (; i < opcnt; i++) {
3172 if (po->flags & OPF_DF)
3173 return; // already resolved
3174 po->flags |= OPF_DF;
3176 if (po->op == OP_CALL)
3177 ferr(po, "call with DF set?\n");
3179 if (po->flags & OPF_JMP) {
3180 if (po->btj != NULL) {
3182 for (j = 0; j < po->btj->count; j++) {
3183 check_i(po, po->btj->d[j].bt_i);
3184 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
3189 if (po->flags & OPF_RMD)
3191 check_i(po, po->bt_i);
3192 if (po->flags & OPF_CJMP)
3193 scan_propagate_df(po->bt_i, opcnt);
3199 if (po->flags & OPF_TAIL)
3202 if (po->op == OP_CLD) {
3203 po->flags |= OPF_RMD | OPF_DONE;
3208 ferr(po, "missing DF clear?\n");
3211 // is operand 'opr' referenced by parsed_op 'po'?
3212 static int is_opr_referenced(const struct parsed_opr *opr,
3213 const struct parsed_op *po)
3217 if (opr->type == OPT_REG) {
3218 mask = po->regmask_dst | po->regmask_src;
3219 if (po->op == OP_CALL)
3220 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3221 if ((1 << opr->reg) & mask)
3227 for (i = 0; i < po->operand_cnt; i++)
3228 if (IS(po->operand[0].name, opr->name))
3234 // is operand 'opr' read by parsed_op 'po'?
3235 static int is_opr_read(const struct parsed_opr *opr,
3236 const struct parsed_op *po)
3238 if (opr->type == OPT_REG) {
3239 if (po->regmask_src & (1 << opr->reg))
3249 // is operand 'opr' modified by parsed_op 'po'?
3250 static int is_opr_modified(const struct parsed_opr *opr,
3251 const struct parsed_op *po)
3255 if (opr->type == OPT_REG) {
3256 if (po->op == OP_CALL) {
3257 mask = po->regmask_dst;
3258 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3259 if (mask & (1 << opr->reg))
3265 if (po->regmask_dst & (1 << opr->reg))
3271 return IS(po->operand[0].name, opr->name);
3274 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3275 static int is_any_opr_modified(const struct parsed_op *po_test,
3276 const struct parsed_op *po, int c_mode)
3281 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3284 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3287 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3290 // in reality, it can wreck any register, but in decompiled C
3291 // version it can only overwrite eax or edx:eax
3292 mask = (1 << xAX) | (1 << xDX);
3296 if (po->op == OP_CALL
3297 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3300 for (i = 0; i < po_test->operand_cnt; i++)
3301 if (IS(po_test->operand[i].name, po->operand[0].name))
3307 // scan for any po_test operand modification in range given
3308 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3311 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3314 for (; i < opcnt; i++) {
3315 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3322 // scan for po_test operand[0] modification in range given
3323 static int scan_for_mod_opr0(struct parsed_op *po_test,
3326 for (; i < opcnt; i++) {
3327 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3334 static int try_resolve_const(int i, const struct parsed_opr *opr,
3335 int magic, unsigned int *val);
3337 static int scan_for_flag_set(int i, int opcnt, int magic,
3338 int *branched, int *setters, int *setter_cnt)
3340 struct label_ref *lr;
3344 if (ops[i].cc_scratch == magic) {
3345 // is this a problem?
3346 //ferr(&ops[i], "%s looped\n", __func__);
3349 ops[i].cc_scratch = magic;
3351 if (g_labels[i] != NULL) {
3354 lr = &g_label_refs[i];
3355 for (; lr->next; lr = lr->next) {
3356 check_i(&ops[i], lr->i);
3357 ret = scan_for_flag_set(lr->i, opcnt, magic,
3358 branched, setters, setter_cnt);
3363 check_i(&ops[i], lr->i);
3364 if (i > 0 && LAST_OP(i - 1)) {
3368 ret = scan_for_flag_set(lr->i, opcnt, magic,
3369 branched, setters, setter_cnt);
3375 if (ops[i].flags & OPF_FLAGS) {
3376 setters[*setter_cnt] = i;
3379 if (ops[i].flags & OPF_REP) {
3380 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3383 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3384 if (ret != 1 || uval == 0) {
3385 // can't treat it as full setter because of ecx=0 case,
3386 // also disallow delayed compare
3395 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3402 // scan back for cdq, if anything modifies edx, fail
3403 static int scan_for_cdq_edx(int i)
3406 if (g_labels[i] != NULL) {
3407 if (g_label_refs[i].next != NULL)
3409 if (i > 0 && LAST_OP(i - 1)) {
3410 i = g_label_refs[i].i;
3417 if (ops[i].op == OP_CDQ)
3420 if (ops[i].regmask_dst & (1 << xDX))
3427 static int scan_for_reg_clear(int i, int reg)
3430 if (g_labels[i] != NULL) {
3431 if (g_label_refs[i].next != NULL)
3433 if (i > 0 && LAST_OP(i - 1)) {
3434 i = g_label_refs[i].i;
3441 if (ops[i].op == OP_XOR
3442 && ops[i].operand[0].lmod == OPLM_DWORD
3443 && ops[i].operand[0].reg == ops[i].operand[1].reg
3444 && ops[i].operand[0].reg == reg)
3447 if (ops[i].regmask_dst & (1 << reg))
3454 static void patch_esp_adjust(struct parsed_op *po, int adj)
3456 ferr_assert(po, po->op == OP_ADD);
3457 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3458 ferr_assert(po, po->operand[1].type == OPT_CONST);
3460 // this is a bit of a hack, but deals with use of
3461 // single adj for multiple calls
3462 po->operand[1].val -= adj;
3463 po->flags |= OPF_RMD;
3464 if (po->operand[1].val == 0)
3465 po->flags |= OPF_DONE;
3466 ferr_assert(po, (int)po->operand[1].val >= 0);
3469 // scan for positive, constant esp adjust
3470 // multipath case is preliminary
3471 static int scan_for_esp_adjust(int i, int opcnt,
3472 int adj_expect, int *adj, int *is_multipath, int do_update)
3474 int adj_expect_unknown = 0;
3475 struct parsed_op *po;
3479 *adj = *is_multipath = 0;
3480 if (adj_expect < 0) {
3481 adj_expect_unknown = 1;
3482 adj_expect = 32 * 4; // enough?
3485 for (; i < opcnt && *adj < adj_expect; i++) {
3486 if (g_labels[i] != NULL)
3490 if (po->flags & OPF_DONE)
3493 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3494 if (po->operand[1].type != OPT_CONST)
3495 ferr(&ops[i], "non-const esp adjust?\n");
3496 *adj += po->operand[1].val;
3498 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3501 patch_esp_adjust(po, adj_expect);
3503 po->flags |= OPF_RMD;
3507 else if (po->op == OP_PUSH) {
3508 //if (first_pop == -1)
3509 // first_pop = -2; // none
3510 *adj -= lmod_bytes(po, po->operand[0].lmod);
3512 else if (po->op == OP_POP) {
3513 if (!(po->flags & OPF_DONE)) {
3514 // seems like msvc only uses 'pop ecx' for stack realignment..
3515 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3517 if (first_pop == -1 && *adj >= 0)
3520 if (do_update && *adj >= 0) {
3521 po->flags |= OPF_RMD;
3523 po->flags |= OPF_DONE | OPF_NOREGS;
3526 *adj += lmod_bytes(po, po->operand[0].lmod);
3527 if (*adj > adj_best)
3530 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3531 if (po->op == OP_JMP && po->btj == NULL) {
3537 if (po->op != OP_CALL)
3539 if (po->operand[0].type != OPT_LABEL)
3541 if (po->pp != NULL && po->pp->is_stdcall)
3543 if (adj_expect_unknown && first_pop >= 0)
3545 // assume it's another cdecl call
3549 if (first_pop >= 0) {
3550 // probably only 'pop ecx' was used
3558 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3560 struct parsed_op *po;
3564 ferr(ops, "%s: followed bad branch?\n", __func__);
3566 for (; i < opcnt; i++) {
3568 if (po->cc_scratch == magic)
3570 po->cc_scratch = magic;
3573 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3574 if (po->btj != NULL) {
3576 for (j = 0; j < po->btj->count; j++)
3577 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3581 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3582 if (!(po->flags & OPF_CJMP))
3585 if (po->flags & OPF_TAIL)
3590 static const struct parsed_proto *try_recover_pp(
3591 struct parsed_op *po, const struct parsed_opr *opr,
3592 int is_call, int *search_instead)
3594 const struct parsed_proto *pp = NULL;
3598 if (po->pp != NULL && (po->flags & OPF_DATA)) {
3599 // hint given in asm
3603 // maybe an arg of g_func?
3604 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3606 char ofs_reg[16] = { 0, };
3607 int arg, arg_s, arg_i;
3614 parse_stack_access(po, opr->name, ofs_reg,
3615 &offset, &stack_ra, NULL, 0);
3616 if (ofs_reg[0] != 0)
3617 ferr(po, "offset reg on arg access?\n");
3618 if (offset <= stack_ra) {
3619 // search who set the stack var instead
3620 if (search_instead != NULL)
3621 *search_instead = 1;
3625 arg_i = (offset - stack_ra - 4) / 4;
3626 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3627 if (g_func_pp->arg[arg].reg != NULL)
3633 if (arg == g_func_pp->argc)
3634 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3636 pp = g_func_pp->arg[arg].pp;
3639 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3640 check_func_pp(po, pp, "icall arg");
3643 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3645 p = strchr(opr->name + 1, '[');
3646 memcpy(buf, opr->name, p - opr->name);
3647 buf[p - opr->name] = 0;
3648 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3650 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3651 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3654 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3657 check_func_pp(po, pp, "reg-fptr ref");
3663 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3664 int magic, int is_call_op, const struct parsed_proto **pp_found,
3665 int *pp_i, int *multi)
3667 const struct parsed_proto *pp = NULL;
3668 struct parsed_op *po;
3669 struct label_ref *lr;
3671 ops[i].cc_scratch = magic;
3674 if (g_labels[i] != NULL) {
3675 lr = &g_label_refs[i];
3676 for (; lr != NULL; lr = lr->next) {
3677 check_i(&ops[i], lr->i);
3678 scan_for_call_type(lr->i, opr, magic, is_call_op,
3679 pp_found, pp_i, multi);
3681 if (i > 0 && LAST_OP(i - 1))
3689 if (ops[i].cc_scratch == magic)
3691 ops[i].cc_scratch = magic;
3693 if (!(ops[i].flags & OPF_DATA))
3695 if (!is_opr_modified(opr, &ops[i]))
3697 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3698 // most probably trashed by some processing
3703 opr = &ops[i].operand[1];
3704 if (opr->type != OPT_REG)
3708 po = (i >= 0) ? &ops[i] : ops;
3711 // reached the top - can only be an arg-reg
3712 if (opr->type != OPT_REG || g_func_pp == NULL)
3715 for (i = 0; i < g_func_pp->argc; i++) {
3716 if (g_func_pp->arg[i].reg == NULL)
3718 if (IS(opr->name, g_func_pp->arg[i].reg))
3721 if (i == g_func_pp->argc)
3723 pp = g_func_pp->arg[i].pp;
3726 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3727 i + 1, g_func_pp->arg[i].reg);
3730 check_func_pp(po, pp, "icall reg-arg");
3733 pp = try_recover_pp(po, opr, is_call_op, NULL);
3735 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3736 if (pp_cmp_func(*pp_found, pp)) {
3737 if (pp_i != NULL && *pp_i != -1)
3738 fnote(&ops[*pp_i], "(other ref)\n");
3739 ferr(po, "icall: parsed_proto mismatch\n");
3751 static void add_label_ref(struct label_ref *lr, int op_i)
3753 struct label_ref *lr_new;
3760 lr_new = calloc(1, sizeof(*lr_new));
3762 lr_new->next = lr->next;
3766 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3768 struct parsed_op *po = &ops[i];
3769 struct parsed_data *pd;
3770 char label[NAMELEN], *p;
3773 p = strchr(po->operand[0].name, '[');
3777 len = p - po->operand[0].name;
3778 strncpy(label, po->operand[0].name, len);
3781 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3782 if (IS(g_func_pd[j].label, label)) {
3788 //ferr(po, "label '%s' not parsed?\n", label);
3791 if (pd->type != OPT_OFFSET)
3792 ferr(po, "label '%s' with non-offset data?\n", label);
3794 // find all labels, link
3795 for (j = 0; j < pd->count; j++) {
3796 for (l = 0; l < opcnt; l++) {
3797 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3798 add_label_ref(&g_label_refs[l], i);
3808 static void clear_labels(int count)
3812 for (i = 0; i < count; i++) {
3813 if (g_labels[i] != NULL) {
3820 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3825 for (i = 0; i < pp->argc; i++) {
3826 if (pp->arg[i].reg != NULL) {
3827 reg = char_array_i(regs_r32,
3828 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3830 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3831 pp->arg[i].reg, pp->name);
3832 regmask |= 1 << reg;
3839 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3844 if (pp->has_retreg) {
3845 for (i = 0; i < pp->argc; i++) {
3846 if (pp->arg[i].type.is_retreg) {
3847 reg = char_array_i(regs_r32,
3848 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3849 ferr_assert(ops, reg >= 0);
3850 regmask |= 1 << reg;
3855 if (strstr(pp->ret_type.name, "int64"))
3856 return regmask | (1 << xAX) | (1 << xDX);
3857 if (IS(pp->ret_type.name, "float")
3858 || IS(pp->ret_type.name, "double"))
3860 return regmask | mxST0;
3862 if (strcasecmp(pp->ret_type.name, "void") == 0)
3865 return regmask | mxAX;
3868 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3870 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3871 && memcmp(po1->operand, po2->operand,
3872 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3875 static void resolve_branches_parse_calls(int opcnt)
3877 static const struct {
3881 unsigned int regmask_src;
3882 unsigned int regmask_dst;
3884 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3885 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3886 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3887 // more precise? Wine gets away with just __ftol handler
3888 { "__ftol2", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3889 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3891 const struct parsed_proto *pp_c;
3892 struct parsed_proto *pp;
3893 struct parsed_data *pd;
3894 struct parsed_op *po;
3895 const char *tmpname;
3900 for (i = 0; i < opcnt; i++)
3906 if (po->datap != NULL) {
3907 pp = calloc(1, sizeof(*pp));
3908 my_assert_not(pp, NULL);
3910 ret = parse_protostr(po->datap, pp);
3912 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3918 if (po->op == OP_CALL) {
3923 else if (po->operand[0].type == OPT_LABEL)
3925 tmpname = opr_name(po, 0);
3926 if (IS_START(tmpname, "loc_")) {
3928 ferr(po, "call to loc_*\n");
3929 // eliminate_seh() must take care of it
3932 if (IS(tmpname, "__alloca_probe"))
3934 if (IS(tmpname, "__SEH_prolog")) {
3935 ferr_assert(po, g_seh_found == 0);
3939 if (IS(tmpname, "__SEH_epilog"))
3942 // convert some calls to pseudo-ops
3943 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3944 if (!IS(tmpname, pseudo_ops[l].name))
3947 po->op = pseudo_ops[l].op;
3948 po->operand_cnt = 0;
3949 po->regmask_src = pseudo_ops[l].regmask_src;
3950 po->regmask_dst = pseudo_ops[l].regmask_dst;
3951 po->flags &= OPF_TAIL;
3952 po->flags |= pseudo_ops[l].flags;
3953 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3956 if (l < ARRAY_SIZE(pseudo_ops))
3959 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3960 if (!g_header_mode && pp_c == NULL)
3961 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3964 pp = proto_clone(pp_c);
3965 my_assert_not(pp, NULL);
3971 check_func_pp(po, pp, "fptr var call");
3972 if (pp->is_noreturn) {
3973 po->flags |= OPF_TAIL;
3974 po->flags &= ~OPF_ATAIL; // most likely...
3981 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3984 if (po->operand[0].type == OPT_REGMEM) {
3985 pd = try_resolve_jumptab(i, opcnt);
3993 for (l = 0; l < opcnt; l++) {
3994 if (g_labels[l] != NULL
3995 && IS(po->operand[0].name, g_labels[l]))
3997 if (l == i + 1 && po->op == OP_JMP) {
3998 // yet another alignment type...
3999 po->flags |= OPF_RMD | OPF_DONE;
4000 po->flags &= ~OPF_JMP;
4004 add_label_ref(&g_label_refs[l], i);
4010 if (po->bt_i != -1 || (po->flags & OPF_RMD))
4013 if (po->operand[0].type == OPT_LABEL
4014 || po->operand[0].type == OPT_REG)
4018 ferr(po, "unhandled branch\n");
4022 po->flags |= OPF_TAIL;
4023 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
4024 if (prev_op == OP_POP)
4025 po->flags |= OPF_ATAIL;
4026 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
4027 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
4029 po->flags |= OPF_ATAIL;
4035 static int resolve_origin(int i, const struct parsed_opr *opr,
4036 int magic, int *op_i, int *is_caller);
4037 static void set_label(int i, const char *name);
4039 static void eliminate_seh_writes(int opcnt)
4041 const struct parsed_opr *opr;
4046 // assume all sf writes above g_seh_size to be seh related
4047 // (probably unsafe but oh well)
4048 for (i = 0; i < opcnt; i++) {
4049 if (ops[i].op != OP_MOV)
4051 opr = &ops[i].operand[0];
4052 if (opr->type != OPT_REGMEM)
4054 if (!is_stack_access(&ops[i], opr))
4058 parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
4060 if (offset < 0 && offset >= -g_seh_size)
4061 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4065 static void eliminate_seh_finally(int opcnt)
4067 const char *target_name = NULL;
4068 const char *return_name = NULL;
4069 int exits[MAX_EXITS];
4077 for (i = 0; i < opcnt; i++) {
4078 if (ops[i].op != OP_CALL)
4080 if (!IS_START(opr_name(&ops[i], 0), "loc_"))
4082 if (target_name != NULL)
4083 ferr(&ops[i], "multiple finally calls? (last was %s)\n",
4085 target_name = opr_name(&ops[i], 0);
4088 if (g_labels[i + 1] == NULL)
4089 set_label(i + 1, "seh_fin_done");
4090 return_name = g_labels[i + 1];
4098 // find finally code (bt_i is not set because it's call)
4099 for (i = 0; i < opcnt; i++) {
4100 if (g_labels[i] == NULL)
4102 if (!IS(g_labels[i], target_name))
4105 ferr_assert(&ops[i], target_i == -1);
4108 ferr_assert(&ops[0], target_i != -1);
4110 find_reachable_exits(target_i, opcnt, target_i + opcnt * 24,
4111 exits, &exit_count);
4112 ferr_assert(&ops[target_i], exit_count == 1);
4113 ferr_assert(&ops[target_i], ops[exits[0]].op == OP_RET);
4116 // convert to jumps, link
4117 ops[call_i].op = OP_JMP;
4118 ops[call_i].bt_i = target_i;
4119 add_label_ref(&g_label_refs[target_i], call_i);
4121 ops[tgend_i].op = OP_JMP;
4122 ops[tgend_i].flags &= ~OPF_TAIL;
4123 ops[tgend_i].flags |= OPF_JMP;
4124 ops[tgend_i].bt_i = return_i;
4125 ops[tgend_i].operand_cnt = 1;
4126 ops[tgend_i].operand[0].type = OPT_LABEL;
4127 snprintf(ops[tgend_i].operand[0].name, NAMELEN, "%s", return_name);
4128 add_label_ref(&g_label_refs[return_i], tgend_i);
4130 // rm seh finally entry code
4131 for (i = target_i - 1; i >= 0; i--) {
4132 if (g_labels[i] != NULL && g_label_refs[i].i != -1)
4134 if (ops[i].flags & OPF_CJMP)
4136 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4139 for (i = target_i - 1; i >= 0; i--) {
4140 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4142 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4146 static void eliminate_seh(int opcnt)
4150 for (i = 0; i < opcnt; i++) {
4151 if (ops[i].op != OP_MOV)
4153 if (ops[i].operand[0].segment != SEG_FS)
4155 if (!IS(opr_name(&ops[i], 0), "0"))
4158 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4159 if (ops[i].operand[1].reg == xSP) {
4160 for (j = i - 1; j >= 0; j--) {
4161 if (ops[j].op != OP_PUSH)
4163 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4165 if (ops[j].operand[0].val == ~0)
4167 if (ops[j].operand[0].type == OPT_REG) {
4169 ret = resolve_origin(j, &ops[j].operand[0],
4170 j + opcnt * 22, &k, NULL);
4172 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4176 ferr(ops, "missing seh terminator\n");
4180 ret = resolve_origin(i, &ops[i].operand[1],
4181 i + opcnt * 23, &k, NULL);
4183 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4187 eliminate_seh_writes(opcnt);
4188 eliminate_seh_finally(opcnt);
4191 static void eliminate_seh_calls(int opcnt)
4193 int epilog_found = 0;
4200 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4201 && ops[i].operand[0].type == OPT_CONST);
4202 g_stack_fsz = g_seh_size + ops[i].operand[0].val;
4203 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4206 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4207 && ops[i].operand[0].type == OPT_OFFSET);
4208 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4211 ferr_assert(&ops[i], ops[i].op == OP_CALL
4212 && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
4213 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4215 for (i++; i < opcnt; i++) {
4216 if (ops[i].op != OP_CALL)
4218 if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
4221 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4224 ferr_assert(ops, epilog_found);
4226 eliminate_seh_writes(opcnt);
4227 eliminate_seh_finally(opcnt);
4230 // check for prologue of many pushes and epilogue with pops
4231 static void check_simple_sequence(int opcnt, int *fsz)
4240 for (i = 0; i < opcnt && i < ARRAY_SIZE(seq); i++) {
4241 if (ops[i].op != OP_PUSH || ops[i].operand[0].type != OPT_REG)
4243 reg = ops[i].operand[0].reg;
4244 if (reg != xBX && reg != xSI && reg != xDI && reg != xBP)
4246 for (j = 0; j < i; j++)
4250 // probably something else is going on here
4258 for (; i < opcnt && seq_len > 0; i++) {
4259 if (!(ops[i].flags & OPF_TAIL))
4262 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4263 if (ops[j].op != OP_POP || ops[j].operand[0].type != OPT_REG)
4265 if (ops[j].operand[0].reg != seq[seq_p])
4269 found = seq_len = seq_p;
4274 for (i = 0; i < seq_len; i++)
4275 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4277 for (; i < opcnt && seq_len > 0; i++) {
4278 if (!(ops[i].flags & OPF_TAIL))
4281 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4282 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4287 // unlike pushes after sub esp,
4288 // IDA treats pushes like this as part of var area
4289 *fsz += seq_len * 4;
4292 static int scan_prologue_ecx(int i, int opcnt, int flags_set,
4293 int limit, int *ecx_push_out)
4295 const struct parsed_proto *pp;
4296 int ecx_push = 0, other_push = 0;
4299 while (limit > 0 && ops[i].op == OP_PUSH
4300 && IS(opr_name(&ops[i], 0), "ecx"))
4302 ops[i].flags |= flags_set;
4309 if (ecx_push == 0 || flags_set != 0)
4312 // check if some of the pushes aren't really call args
4313 for (; i < opcnt; i++) {
4314 if (i > 0 && g_labels[i] != NULL)
4316 if (ops[i].flags & (OPF_JMP|OPF_TAIL))
4318 if (ops[i].op == OP_PUSH)
4322 if (ops[i].op != OP_CALL)
4326 if (pp == NULL && ops[i].operand[0].type == OPT_LABEL)
4327 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4331 ferr_assert(&ops[i], ecx_push + other_push >= pp->argc_stack);
4332 if (other_push < pp->argc_stack)
4333 ecx_push -= pp->argc_stack - other_push;
4336 if (ecx_push_out != NULL)
4337 *ecx_push_out = ecx_push;
4341 static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4347 for (; i < opcnt; i++)
4348 if (!(ops[i].flags & OPF_DONE))
4351 ret = scan_prologue_ecx(i, opcnt, 0, 4, &ecx_tmp);
4353 scan_prologue_ecx(i, opcnt, OPF_RMD | OPF_DONE | OPF_NOREGS,
4355 g_stack_fsz += 4 * ecx_tmp;
4356 *ecx_push += ecx_tmp;
4360 for (; i < opcnt; i++) {
4361 if (i > 0 && g_labels[i] != NULL)
4363 if (ops[i].flags & (OPF_JMP|OPF_TAIL))
4365 if (ops[i].flags & OPF_DONE)
4367 if (ops[i].op == OP_PUSH)
4369 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4370 && ops[i].operand[1].type == OPT_CONST)
4372 g_stack_fsz += opr_const(&ops[i], 1);
4373 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4378 if (ops[i].op == OP_LEA && ops[i].operand[0].reg == xSP
4379 && ops[i].operand[1].type == OPT_REGMEM
4380 && IS_START(ops[i].operand[1].name, "esp-"))
4382 name = ops[i].operand[1].name;
4383 ret = sscanf(name, "esp-%x%n", &j, &len);
4384 ferr_assert(&ops[i], ret == 1 && len == strlen(name));
4386 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4391 if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4392 && ops[i].operand[1].type == OPT_CONST)
4394 for (j = i + 1; j < opcnt; j++)
4395 if (!(ops[j].flags & OPF_DONE))
4397 if (ops[j].op == OP_CALL
4398 && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4400 g_stack_fsz += opr_const(&ops[i], 1);
4401 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4402 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4413 static void scan_prologue_epilogue(int opcnt, int *stack_align)
4415 int ecx_push = 0, esp_sub = 0, pusha = 0;
4416 int sandard_epilogue;
4417 int found, ret, len;
4421 if (g_seh_found == 2) {
4422 eliminate_seh_calls(opcnt);
4426 eliminate_seh(opcnt);
4427 // ida treats seh as part of sf
4428 g_stack_fsz = g_seh_size;
4432 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4433 && ops[1].op == OP_MOV
4434 && IS(opr_name(&ops[1], 0), "ebp")
4435 && IS(opr_name(&ops[1], 1), "esp"))
4438 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4439 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4441 for (i = 2; i < opcnt; i++)
4442 if (!(ops[i].flags & OPF_DONE))
4445 if (ops[i].op == OP_PUSHA) {
4446 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4451 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4452 && ops[i].operand[1].type == OPT_CONST)
4454 l = ops[i].operand[1].val;
4456 if (j == -1 || (l >> j) != -1)
4457 ferr(&ops[i], "unhandled esp align: %x\n", l);
4458 if (stack_align != NULL)
4459 *stack_align = 1 << j;
4460 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4464 i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4468 for (; i < opcnt; i++)
4469 if (ops[i].flags & OPF_TAIL)
4472 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4473 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4479 sandard_epilogue = 0;
4480 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4482 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4483 // the standard epilogue is sometimes even used without a sf
4484 if (ops[j - 1].op == OP_MOV
4485 && IS(opr_name(&ops[j - 1], 0), "esp")
4486 && IS(opr_name(&ops[j - 1], 1), "ebp"))
4487 sandard_epilogue = 1;
4489 else if (ops[j].op == OP_LEAVE)
4491 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4492 sandard_epilogue = 1;
4494 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4495 && ops[i].pp->is_noreturn)
4497 // on noreturn, msvc sometimes cleans stack, sometimes not
4502 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4503 ferr(&ops[j], "'pop ebp' expected\n");
4505 if (g_stack_fsz != 0 || sandard_epilogue) {
4506 if (ops[j].op == OP_LEAVE)
4508 else if (sandard_epilogue) // mov esp, ebp
4510 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4513 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4515 ferr(&ops[j], "esp restore expected\n");
4518 if (ecx_push && j >= 0 && ops[j].op == OP_POP
4519 && IS(opr_name(&ops[j], 0), "ecx"))
4521 ferr(&ops[j], "unexpected ecx pop\n");
4526 if (ops[j].op == OP_POPA)
4527 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4529 ferr(&ops[j], "popa expected\n");
4534 } while (i < opcnt);
4537 ferr(ops, "missing ebp epilogue\n");
4542 check_simple_sequence(opcnt, &push_fsz);
4543 i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4546 if (ecx_push || esp_sub)
4551 for (; i < opcnt; i++)
4552 if (ops[i].flags & OPF_TAIL)
4556 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4557 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4562 else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4563 // skip arg updates for arg-reuse tailcall
4564 for (; j >= 0; j--) {
4565 if (ops[j].op != OP_MOV)
4567 if (ops[j].operand[0].type == OPT_REGMEM
4568 && strstr(ops[j].operand[0].name, "arg_") != NULL)
4570 if (ops[j].operand[0].type == OPT_REG)
4571 continue; // assume arg-reg mov
4576 for (; j >= 0; j--) {
4577 if ((ops[j].flags & (OPF_RMD | OPF_DONE | OPF_NOREGS)) !=
4578 (OPF_RMD | OPF_DONE | OPF_NOREGS))
4582 if (ecx_push > 0 && !esp_sub) {
4583 for (l = 0; l < ecx_push && j >= 0; l++) {
4584 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4586 else if (ops[j].op == OP_ADD
4587 && IS(opr_name(&ops[j], 0), "esp")
4588 && ops[j].operand[1].type == OPT_CONST)
4591 l += ops[j].operand[1].val / 4 - 1;
4596 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4599 if (l != ecx_push) {
4600 if (i < opcnt && ops[i].op == OP_CALL
4601 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4603 // noreturn tailcall with no epilogue
4608 ferr(&ops[j], "epilogue scan failed\n");
4615 if (ops[j].op == OP_ADD
4616 && IS(opr_name(&ops[j], 0), "esp")
4617 && ops[j].operand[1].type == OPT_CONST)
4619 if (ops[j].operand[1].val < g_stack_fsz)
4620 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4622 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4623 if (ops[j].operand[1].val == 0)
4624 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4627 else if (ops[j].op == OP_LEA && ops[j].operand[0].reg == xSP
4628 && ops[j].operand[1].type == OPT_REGMEM
4629 && IS_START(ops[j].operand[1].name, "esp+"))
4631 const char *name = ops[j].operand[1].name;
4632 ret = sscanf(name, "esp+%x%n", &l, &len);
4633 ferr_assert(&ops[j], ret == 1 && len == strlen(name));
4634 ferr_assert(&ops[j], l <= g_stack_fsz);
4635 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4638 else if (i < opcnt && ops[i].op == OP_CALL
4639 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4641 // noreturn tailcall with no epilogue
4645 ferr(&ops[j], "'add esp' expected\n");
4649 } while (i < opcnt);
4652 ferr(ops, "missing esp epilogue\n");
4655 if (g_stack_fsz != 0)
4656 // see check_simple_sequence
4657 g_stack_fsz += push_fsz;
4660 // find an instruction that changed opr before i op
4661 // *op_i must be set to -1 by the caller
4662 // *is_caller is set to 1 if one source is determined to be g_func arg
4663 // returns 1 if found, *op_i is then set to origin
4664 // returns -1 if multiple origins are found
4665 static int resolve_origin(int i, const struct parsed_opr *opr,
4666 int magic, int *op_i, int *is_caller)
4668 struct label_ref *lr;
4672 if (g_labels[i] != NULL) {
4673 lr = &g_label_refs[i];
4674 for (; lr != NULL; lr = lr->next) {
4675 check_i(&ops[i], lr->i);
4676 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4678 if (i > 0 && LAST_OP(i - 1))
4684 if (is_caller != NULL)
4689 if (ops[i].cc_scratch == magic)
4691 ops[i].cc_scratch = magic;
4693 if (!(ops[i].flags & OPF_DATA))
4695 if (!is_opr_modified(opr, &ops[i]))
4699 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4710 static int resolve_origin_reg(int i, int reg, int magic, int *op_i,
4713 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4716 if (is_caller != NULL)
4718 return resolve_origin(i, &opr, magic, op_i, is_caller);
4721 // find an instruction that previously referenced opr
4722 // if multiple results are found - fail
4723 // *op_i must be set to -1 by the caller
4724 // returns 1 if found, *op_i is then set to referencer insn
4725 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4726 int magic, int *op_i)
4728 struct label_ref *lr;
4732 if (g_labels[i] != NULL) {
4733 lr = &g_label_refs[i];
4734 for (; lr != NULL; lr = lr->next) {
4735 check_i(&ops[i], lr->i);
4736 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4738 if (i > 0 && LAST_OP(i - 1))
4746 if (ops[i].cc_scratch == magic)
4748 ops[i].cc_scratch = magic;
4750 if (!is_opr_referenced(opr, &ops[i]))
4761 // adjust datap of all reachable 'op' insns when moving back
4762 // returns 1 if at least 1 op was found
4763 // returns -1 if path without an op was found
4764 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4766 struct label_ref *lr;
4769 if (ops[i].cc_scratch == magic)
4771 ops[i].cc_scratch = magic;
4774 if (g_labels[i] != NULL) {
4775 lr = &g_label_refs[i];
4776 for (; lr != NULL; lr = lr->next) {
4777 check_i(&ops[i], lr->i);
4778 ret |= adjust_prev_op(lr->i, op, magic, datap);
4780 if (i > 0 && LAST_OP(i - 1))
4788 if (ops[i].cc_scratch == magic)
4790 ops[i].cc_scratch = magic;
4792 if (ops[i].op != op)
4795 ops[i].datap = datap;
4800 // find next instruction that reads opr
4801 // *op_i must be set to -1 by the caller
4802 // on return, *op_i is set to first referencer insn
4803 // returns 1 if exactly 1 referencer is found
4804 static int find_next_read(int i, int opcnt,
4805 const struct parsed_opr *opr, int magic, int *op_i)
4807 struct parsed_op *po;
4810 for (; i < opcnt; i++)
4812 if (ops[i].cc_scratch == magic)
4814 ops[i].cc_scratch = magic;
4817 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4818 if (po->btj != NULL) {
4820 for (j = 0; j < po->btj->count; j++) {
4821 check_i(po, po->btj->d[j].bt_i);
4822 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4828 if (po->flags & OPF_RMD)
4830 check_i(po, po->bt_i);
4831 if (po->flags & OPF_CJMP) {
4832 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4841 if (!is_opr_read(opr, po)) {
4843 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4844 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4846 full_opr = po->operand[0].lmod >= opr->lmod;
4848 if (is_opr_modified(opr, po) && full_opr) {
4852 if (po->flags & OPF_TAIL)
4867 static int find_next_read_reg(int i, int opcnt, int reg,
4868 enum opr_lenmod lmod, int magic, int *op_i)
4870 struct parsed_opr opr = OPR_INIT(OPT_REG, lmod, reg);
4873 return find_next_read(i, opcnt, &opr, magic, op_i);
4876 // find next instruction that reads opr
4877 // *op_i must be set to -1 by the caller
4878 // on return, *op_i is set to first flag user insn
4879 // returns 1 if exactly 1 flag user is found
4880 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4882 struct parsed_op *po;
4885 for (; i < opcnt; i++)
4887 if (ops[i].cc_scratch == magic)
4889 ops[i].cc_scratch = magic;
4892 if (po->op == OP_CALL)
4894 if (po->flags & OPF_JMP) {
4895 if (po->btj != NULL) {
4897 for (j = 0; j < po->btj->count; j++) {
4898 check_i(po, po->btj->d[j].bt_i);
4899 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4905 if (po->flags & OPF_RMD)
4907 check_i(po, po->bt_i);
4908 if (po->flags & OPF_CJMP)
4915 if (!(po->flags & OPF_CC)) {
4916 if (po->flags & OPF_FLAGS)
4919 if (po->flags & OPF_TAIL)
4935 static int try_resolve_const(int i, const struct parsed_opr *opr,
4936 int magic, unsigned int *val)
4941 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4944 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4947 *val = ops[i].operand[1].val;
4954 static int resolve_used_bits(int i, int opcnt, int reg,
4955 int *mask, int *is_z_check)
4957 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4961 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4965 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4967 fnote(&ops[j], "(first read)\n");
4968 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4971 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4972 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4974 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4975 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4977 *mask = ops[j].operand[1].val;
4978 if (ops[j].operand[0].lmod == OPLM_BYTE
4979 && ops[j].operand[0].name[1] == 'h')
4983 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4986 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4988 *is_z_check = ops[k].pfo == PFO_Z;
4993 static const struct parsed_proto *resolve_deref(int i, int magic,
4994 const struct parsed_opr *opr, int level)
4996 const struct parsed_proto *pp = NULL;
4997 int from_caller = 0;
5006 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
5007 if (ret != 2 || len != strlen(opr->name)) {
5008 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
5009 if (ret != 1 || len != strlen(opr->name))
5013 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
5017 ret = resolve_origin_reg(i, reg, i + magic, &j, NULL);
5021 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
5022 && strlen(ops[j].operand[1].name) == 3
5023 && ops[j].operand[0].lmod == OPLM_DWORD
5024 && ops[j].pp == NULL // no hint
5027 // allow one simple dereference (com/directx)
5028 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
5029 ops[j].operand[1].name);
5032 ret = resolve_origin_reg(j, reg, j + magic, &k, NULL);
5037 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
5040 if (ops[j].pp != NULL) {
5044 else if (ops[j].operand[1].type == OPT_REGMEM) {
5045 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
5047 // maybe structure ptr in structure
5048 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
5051 else if (ops[j].operand[1].type == OPT_LABEL)
5052 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
5053 else if (ops[j].operand[1].type == OPT_REG) {
5056 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
5058 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
5059 for (k = 0; k < g_func_pp->argc; k++) {
5060 if (g_func_pp->arg[k].reg == NULL)
5062 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
5063 pp = g_func_pp->arg[k].pp;
5072 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
5074 ferr(&ops[j], "expected struct, got '%s %s'\n",
5075 pp->type.name, pp->name);
5079 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
5082 static const struct parsed_proto *resolve_func_ptr(int i, int opcnt,
5083 int is_call_op, const struct parsed_opr *opr,
5084 int *pp_i, int *multi_src)
5086 const struct parsed_proto *pp = NULL;
5087 int search_advice = 0;
5089 if (multi_src != NULL)
5094 switch (opr->type) {
5096 // try to resolve struct member calls
5097 pp = resolve_deref(i, i + opcnt * 19, opr, 0);
5103 pp = try_recover_pp(&ops[i], opr, is_call_op, &search_advice);
5108 scan_for_call_type(i, opr, i + opcnt * 9, is_call_op,
5109 &pp, pp_i, multi_src);
5116 static struct parsed_proto *process_call_early(int i, int opcnt,
5119 struct parsed_op *po = &ops[i];
5120 struct parsed_proto *pp;
5126 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
5130 // look for and make use of esp adjust
5132 if (!pp->is_stdcall && pp->argc_stack > 0)
5133 ret = scan_for_esp_adjust(i + 1, opcnt,
5134 pp->argc_stack * 4, &adj, &multipath, 0);
5136 if (pp->argc_stack > adj / 4)
5140 if (ops[ret].op == OP_POP) {
5141 for (j = 1; j < adj / 4; j++) {
5142 if (ops[ret + j].op != OP_POP
5143 || ops[ret + j].operand[0].reg != xCX)
5155 static struct parsed_proto *process_call(int i, int opcnt)
5157 struct parsed_op *po = &ops[i];
5158 const struct parsed_proto *pp_c;
5159 struct parsed_proto *pp;
5160 const char *tmpname;
5161 int call_i = -1, ref_i = -1;
5162 int adj = 0, multipath = 0;
5165 tmpname = opr_name(po, 0);
5170 pp_c = resolve_func_ptr(i, opcnt, 1, &ops[i].operand[0],
5171 &call_i, &multipath);
5173 if (!pp_c->is_func && !pp_c->is_fptr)
5174 ferr(po, "call to non-func: %s\n", pp_c->name);
5175 pp = proto_clone(pp_c);
5176 my_assert_not(pp, NULL);
5178 // not resolved just to single func
5181 switch (po->operand[0].type) {
5183 // we resolved this call and no longer need the register
5184 po->regmask_src &= ~(1 << po->operand[0].reg);
5186 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
5187 && ops[call_i].operand[1].type == OPT_LABEL)
5189 // no other source users?
5190 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
5192 if (ret == 1 && call_i == ref_i) {
5193 // and nothing uses it after us?
5195 find_next_read(i + 1, opcnt, &po->operand[0],
5196 i + opcnt * 11, &ref_i);
5198 // then also don't need the source mov
5199 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
5211 pp = calloc(1, sizeof(*pp));
5212 my_assert_not(pp, NULL);
5215 ret = scan_for_esp_adjust(i + 1, opcnt,
5216 -1, &adj, &multipath, 0);
5217 if (ret < 0 || adj < 0) {
5218 if (!g_allow_regfunc)
5219 ferr(po, "non-__cdecl indirect call unhandled yet\n");
5220 pp->is_unresolved = 1;
5224 if (adj > ARRAY_SIZE(pp->arg))
5225 ferr(po, "esp adjust too large: %d\n", adj);
5226 pp->ret_type.name = strdup("int");
5227 pp->argc = pp->argc_stack = adj;
5228 for (arg = 0; arg < pp->argc; arg++)
5229 pp->arg[arg].type.name = strdup("int");
5234 // look for and make use of esp adjust
5237 if (!pp->is_stdcall && pp->argc_stack > 0) {
5238 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
5239 ret = scan_for_esp_adjust(i + 1, opcnt,
5240 adj_expect, &adj, &multipath, 0);
5243 if (pp->is_vararg) {
5244 if (adj / 4 < pp->argc_stack) {
5245 fnote(po, "(this call)\n");
5246 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
5247 adj, pp->argc_stack * 4);
5249 // modify pp to make it have varargs as normal args
5251 pp->argc += adj / 4 - pp->argc_stack;
5252 for (; arg < pp->argc; arg++) {
5253 pp->arg[arg].type.name = strdup("int");
5256 if (pp->argc > ARRAY_SIZE(pp->arg))
5257 ferr(po, "too many args for '%s'\n", tmpname);
5259 if (pp->argc_stack > adj / 4) {
5260 if (pp->is_noreturn)
5261 // assume no stack adjust was emited
5263 fnote(po, "(this call)\n");
5264 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
5265 tmpname, pp->argc_stack * 4, adj);
5268 scan_for_esp_adjust(i + 1, opcnt,
5269 pp->argc_stack * 4, &adj, &multipath, 1);
5271 else if (pp->is_vararg)
5272 ferr(po, "missing esp_adjust for vararg func '%s'\n",
5279 static void check_fptr_args(int i, int opcnt, struct parsed_proto *pp)
5281 struct parsed_opr s_opr = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
5282 const struct parsed_proto *pp_arg, *pp_cmp;
5283 const struct parsed_op *po_a;
5290 for (arg = 0; arg < pp->argc; arg++) {
5294 pp_arg = pp->arg[arg].pp;
5295 if (pp_arg == NULL || !pp_arg->is_func)
5298 s_reg = pp->arg[arg].reg;
5299 if (s_reg != NULL) {
5300 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
5301 ferr_assert(&ops[i], reg >= 0);
5303 scan_for_call_type(i, &s_opr, i + arg + opcnt * 28, 0,
5304 &pp_cmp, &pp_cmp_i, NULL);
5305 if (pp_cmp != NULL && !pp_compatible_func(pp_arg, pp_cmp)) {
5308 fnote(&ops[pp_cmp_i], "(referenced here)\n");
5312 for (j = 0; j < pp->arg[arg].push_ref_cnt; j++) {
5313 po_a = pp->arg[arg].push_refs[j];
5314 if (po_a == NULL || po_a->op != OP_PUSH)
5316 pp_cmp = resolve_func_ptr(po_a - ops, opcnt, 0,
5317 &po_a->operand[0], &pp_cmp_i, NULL);
5318 if (pp_cmp != NULL && !pp_compatible_func(pp_arg, pp_cmp)) {
5321 pp_cmp_i = po_a - ops;
5323 fnote(&ops[pp_cmp_i], "(referenced here)\n");
5329 ferr(&ops[i], "incompatible fptr arg %d\n", arg + 1);
5333 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5337 for (i = 0; i < pp->argc; i++)
5338 if (pp->arg[i].reg == NULL)
5342 memmove(&pp->arg[i + 1], &pp->arg[i],
5343 sizeof(pp->arg[0]) * pp->argc_stack);
5344 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5345 pp->arg[i].reg = strdup(reg);
5346 pp->arg[i].type.name = strdup("int");
5351 static void pp_insert_stack_args(struct parsed_proto *pp, int count)
5356 pp->argc_stack += count;
5358 for (a = 0; a < pp->argc; a++)
5359 if (pp->arg[a].type.name == NULL)
5360 pp->arg[a].type.name = strdup("int");
5363 static void pp_add_push_ref(struct parsed_proto *pp,
5364 int arg, struct parsed_op *po)
5366 pp->arg[arg].push_refs = realloc(pp->arg[arg].push_refs,
5367 (pp->arg[arg].push_ref_cnt + 1)
5368 * sizeof(pp->arg[arg].push_refs[0]));
5369 ferr_assert(po, pp->arg[arg].push_refs != NULL);
5370 pp->arg[arg].push_refs[pp->arg[arg].push_ref_cnt++] = po;
5373 static void mark_float_arg(struct parsed_op *po,
5374 struct parsed_proto *pp, int arg, int *regmask_ffca)
5376 ferr_assert(po, pp->arg[arg].push_ref_cnt == 0);
5377 pp_add_push_ref(pp, arg, po);
5379 po->p_argnum = arg + 1;
5380 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
5381 if (regmask_ffca != NULL)
5382 *regmask_ffca |= 1 << arg;
5385 static int check_for_stp(int i, int i_to)
5387 struct parsed_op *po;
5389 for (; i < i_to; i++) {
5391 if (po->op == OP_FST)
5393 if (g_labels[i] != NULL || (po->flags & OPF_JMP))
5395 if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
5397 if (po->op == OP_ADD && po->operand[0].reg == xSP)
5404 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
5407 struct parsed_op *po;
5413 for (base_arg = 0; base_arg < pp->argc; base_arg++)
5414 if (pp->arg[base_arg].reg == NULL)
5417 for (j = i; j > 0; )
5419 ferr_assert(&ops[j], g_labels[j] == NULL);
5423 ferr_assert(po, po->op != OP_PUSH);
5424 if (po->op == OP_FST)
5426 if (po->operand[0].type != OPT_REGMEM)
5428 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
5431 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
5432 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
5436 arg = base_arg + offset / 4;
5437 mark_float_arg(po, pp, arg, regmask_ffca);
5439 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5440 && po->operand[1].type == OPT_CONST)
5442 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5447 for (arg = base_arg; arg < pp->argc; arg++) {
5448 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
5449 if (pp->arg[arg].push_ref_cnt != 1)
5450 ferr(&ops[i], "arg %d/%d not found or bad\n", arg, pp->argc);
5451 po = pp->arg[arg].push_refs[0];
5452 if (po->operand[0].lmod == OPLM_QWORD)
5459 static int collect_call_args_early(int i, int opcnt,
5460 struct parsed_proto *pp, int *regmask, int *regmask_ffca)
5462 struct parsed_op *po;
5467 for (arg = 0; arg < pp->argc; arg++)
5468 if (pp->arg[arg].reg == NULL)
5471 // first see if it can be easily done
5472 for (j = i; j > 0 && arg < pp->argc; )
5474 if (g_labels[j] != NULL)
5479 if (po->op == OP_CALL)
5481 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
5483 else if (po->op == OP_POP)
5485 else if (po->flags & OPF_CJMP)
5487 else if (po->op == OP_PUSH) {
5488 if (po->flags & (OPF_FARG|OPF_FARGNR))
5490 if (!g_header_mode) {
5491 ret = scan_for_mod(po, j + 1, i, 1);
5496 if (pp->arg[arg].type.is_va_list)
5500 for (arg++; arg < pp->argc; arg++)
5501 if (pp->arg[arg].reg == NULL)
5504 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5505 && po->operand[1].type == OPT_CONST)
5507 if (po->flags & (OPF_RMD|OPF_DONE))
5509 if (po->operand[1].val != pp->argc_stack * 4)
5510 ferr(po, "unexpected esp adjust: %d\n",
5511 po->operand[1].val * 4);
5512 ferr_assert(po, pp->argc - arg == pp->argc_stack);
5513 return collect_call_args_no_push(i, pp, regmask_ffca);
5521 for (arg = 0; arg < pp->argc; arg++)
5522 if (pp->arg[arg].reg == NULL)
5525 for (j = i; j > 0 && arg < pp->argc; )
5529 if (ops[j].op == OP_PUSH)
5531 int ref_handled = 0;
5533 k = check_for_stp(j + 1, i);
5535 // push ecx; fstp dword ptr [esp]
5536 ret = parse_stack_esp_offset(&ops[k],
5537 ops[k].operand[0].name, &offset);
5538 if (ret == 0 && offset == 0) {
5539 if (!pp->arg[arg].type.is_float)
5540 ferr(&ops[i], "arg %d should be float\n", arg + 1);
5541 mark_float_arg(&ops[k], pp, arg, regmask_ffca);
5547 ferr_assert(&ops[j], pp->arg[arg].push_ref_cnt == 0);
5548 pp_add_push_ref(pp, arg, &ops[j]);
5551 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5552 *regmask |= 1 << ops[j].operand[0].reg;
5554 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5555 ops[j].flags &= ~OPF_RSAVE;
5558 for (arg++; arg < pp->argc; arg++)
5559 if (pp->arg[arg].reg == NULL)
5565 check_fptr_args(i, opcnt, pp);
5570 // ensure all s_a* numbers match for a given func arg in all branches
5571 // returns 1 if any changes were made, 0 if not
5572 static int sync_argnum(struct parsed_proto *pp, int arg,
5573 int *argnum, int *arggrp)
5575 struct parsed_op *po_tmp;
5579 // see if other branches don't have higher argnum
5580 for (i = 0; i < pp->arg[arg].push_ref_cnt; i++) {
5581 po_tmp = pp->arg[arg].push_refs[i];
5582 if (*argnum < po_tmp->p_argnum)
5583 *argnum = po_tmp->p_argnum;
5584 if (*arggrp < po_tmp->p_arggrp)
5585 *arggrp = po_tmp->p_arggrp;
5588 // make all argnums consistent
5589 for (i = 0; i < pp->arg[arg].push_ref_cnt; i++) {
5590 po_tmp = pp->arg[arg].push_refs[i];
5591 if (po_tmp->p_argnum == 0)
5593 if (po_tmp->p_argnum != *argnum || po_tmp->p_arggrp != *arggrp) {
5594 po_tmp->p_argnum = *argnum;
5595 po_tmp->p_arggrp = *arggrp;
5603 static int collect_call_args_r(struct parsed_op *po, int i,
5604 struct parsed_proto *pp, int *regmask,
5605 int arg, int argnum, int magic,
5606 int skip, int need_op_saving, int may_reuse)
5608 struct parsed_proto *pp_tmp;
5609 struct label_ref *lr;
5610 int need_to_save_current;
5611 int arg_grp_current = 0;
5612 int save_args_seen = 0;
5620 ferr(po, "dead label encountered\n");
5624 for (; arg < pp->argc; arg++, argnum++)
5625 if (pp->arg[arg].reg == NULL)
5627 magic = (magic & 0xffffff) | (arg << 24);
5629 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5631 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5632 if (ops[j].cc_scratch != magic) {
5633 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5637 // ok: have already been here
5640 ops[j].cc_scratch = magic;
5642 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5643 lr = &g_label_refs[j];
5644 if (lr->next != NULL)
5646 for (; lr->next; lr = lr->next) {
5647 check_i(&ops[j], lr->i);
5648 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5650 ret = collect_call_args_r(po, lr->i, pp, regmask,
5651 arg, argnum, magic, skip, need_op_saving, may_reuse);
5656 check_i(&ops[j], lr->i);
5657 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5659 if (j > 0 && LAST_OP(j - 1)) {
5660 // follow last branch in reverse
5665 ret = collect_call_args_r(po, lr->i, pp, regmask,
5666 arg, argnum, magic, skip, need_op_saving, may_reuse);
5672 if (ops[j].op == OP_CALL)
5674 if (pp->is_unresolved)
5679 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5680 arg, pp->argc, ops[j].operand[0].name);
5681 if (may_reuse && pp_tmp->argc_stack > 0)
5682 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5683 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5684 if (!pp_tmp->is_unresolved)
5685 skip = pp_tmp->argc_stack;
5687 // esp adjust of 0 means we collected it before
5688 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5689 && (ops[j].operand[1].type != OPT_CONST
5690 || ops[j].operand[1].val != 0))
5692 if (pp->is_unresolved)
5695 fnote(po, "(this call)\n");
5696 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5697 arg, pp->argc, ops[j].operand[1].val);
5699 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5701 if (pp->is_unresolved)
5704 fnote(po, "(this call)\n");
5705 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5707 else if (ops[j].flags & OPF_CJMP)
5709 if (pp->is_unresolved)
5714 else if (ops[j].op == OP_PUSH && skip > 0) {
5715 // XXX: might want to rm OPF_FARGNR and only use this
5718 else if (ops[j].op == OP_PUSH
5719 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5721 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5724 pp_add_push_ref(pp, arg, &ops[j]);
5726 sync_argnum(pp, arg, &argnum, &dummy);
5728 need_to_save_current = 0;
5730 if (ops[j].operand[0].type == OPT_REG)
5731 reg = ops[j].operand[0].reg;
5733 if (!need_op_saving) {
5734 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5735 need_to_save_current = (ret >= 0);
5737 if (need_op_saving || need_to_save_current) {
5738 // mark this arg as one that needs operand saving
5739 pp->arg[arg].is_saved = 1;
5741 if (save_args_seen & (1 << (argnum - 1))) {
5744 if (arg_grp_current >= MAX_ARG_GRP)
5745 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5749 else if (ops[j].p_argnum == 0)
5750 ops[j].flags |= OPF_RMD;
5752 // some PUSHes are reused by different calls on other branches,
5753 // but that can't happen if we didn't branch, so they
5754 // can be removed from future searches (handles nested calls)
5756 ops[j].flags |= OPF_FARGNR;
5758 ops[j].flags |= OPF_FARG;
5759 ops[j].flags &= ~OPF_RSAVE;
5761 // check for __VALIST
5762 if (!pp->is_unresolved && g_func_pp != NULL
5763 && pp->arg[arg].type.is_va_list)
5766 ret = resolve_origin(j, &ops[j].operand[0],
5767 magic + 1, &k, NULL);
5768 if (ret == 1 && k >= 0)
5770 if (ops[k].op == OP_LEA) {
5771 if (!g_func_pp->is_vararg)
5772 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5775 snprintf(buf, sizeof(buf), "arg_%X",
5776 g_func_pp->argc_stack * 4);
5777 if (strstr(ops[k].operand[1].name, buf)
5778 || strstr(ops[k].operand[1].name, "arglist"))
5780 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5781 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5782 pp->arg[arg].is_saved = 0;
5786 ferr(&ops[k], "va_list arg detection failed\n");
5788 // check for va_list from g_func_pp arg too
5789 else if (ops[k].op == OP_MOV
5790 && is_stack_access(&ops[k], &ops[k].operand[1]))
5792 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5793 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5795 ops[k].flags |= OPF_RMD | OPF_DONE;
5796 ops[j].flags |= OPF_RMD;
5797 ops[j].p_argpass = ret + 1;
5798 pp->arg[arg].is_saved = 0;
5805 if (pp->arg[arg].is_saved) {
5806 ops[j].flags &= ~OPF_RMD;
5807 ops[j].p_argnum = argnum;
5808 ops[j].p_arggrp = arg_grp_current;
5811 // tracking reg usage
5813 *regmask |= 1 << reg;
5817 if (!pp->is_unresolved) {
5819 for (; arg < pp->argc; arg++, argnum++)
5820 if (pp->arg[arg].reg == NULL)
5823 magic = (magic & 0xffffff) | (arg << 24);
5826 if (ops[j].p_arggrp > arg_grp_current) {
5828 arg_grp_current = ops[j].p_arggrp;
5830 if (ops[j].p_argnum > 0)
5831 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5834 if (arg < pp->argc) {
5835 ferr(po, "arg collect failed for '%s': %d/%d\n",
5836 pp->name, arg, pp->argc);
5843 static int collect_call_args(struct parsed_op *po, int i, int opcnt,
5844 struct parsed_proto *pp, int *regmask, int magic)
5848 ret = collect_call_args_r(po, i, pp, regmask, 0, 1, magic,
5853 if (pp->is_unresolved)
5854 pp_insert_stack_args(pp, ret);
5856 // note: p_argnum, p_arggrp will be propagated in a later pass,
5857 // look for sync_argnum() (p_arggrp is for cases when mixed pushes
5858 // for multiple funcs are going on)
5861 check_fptr_args(i, opcnt, pp);
5866 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5867 int regmask_now, int *regmask,
5868 int regmask_save_now, int *regmask_save,
5869 int *regmask_init, int regmask_arg)
5871 struct parsed_op *po;
5879 for (; i < opcnt; i++)
5882 if (cbits[i >> 3] & (1 << (i & 7)))
5884 cbits[i >> 3] |= (1 << (i & 7));
5886 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5887 if (po->flags & (OPF_RMD|OPF_DONE))
5889 if (po->btj != NULL) {
5890 for (j = 0; j < po->btj->count; j++) {
5891 check_i(po, po->btj->d[j].bt_i);
5892 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5893 regmask_now, regmask, regmask_save_now, regmask_save,
5894 regmask_init, regmask_arg);
5899 check_i(po, po->bt_i);
5900 if (po->flags & OPF_CJMP)
5901 reg_use_pass(po->bt_i, opcnt, cbits,
5902 regmask_now, regmask, regmask_save_now, regmask_save,
5903 regmask_init, regmask_arg);
5909 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5910 && !g_func_pp->is_userstack
5911 && po->operand[0].type == OPT_REG)
5915 reg = po->operand[0].reg;
5916 ferr_assert(po, reg >= 0);
5919 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5920 if (regmask_now & (1 << reg)) {
5921 already_saved = regmask_save_now & (1 << reg);
5922 flags_set = OPF_RSAVE | OPF_DONE;
5926 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3,
5927 reg, 0, 0, save_level, 0);
5929 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5930 reg, 0, 0, save_level, flags_set);
5933 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5935 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5940 ferr_assert(po, !already_saved);
5941 po->flags |= flags_set;
5943 if (regmask_now & (1 << reg)) {
5944 regmask_save_now |= (1 << reg);
5945 *regmask_save |= regmask_save_now;
5950 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5951 reg = po->operand[0].reg;
5952 ferr_assert(po, reg >= 0);
5954 if (regmask_save_now & (1 << reg))
5955 regmask_save_now &= ~(1 << reg);
5957 regmask_now &= ~(1 << reg);
5960 else if (po->op == OP_CALL) {
5961 if ((po->regmask_dst & (1 << xAX))
5962 && !(po->regmask_dst & (1 << xDX)))
5964 if (po->flags & OPF_TAIL)
5965 // don't need eax, will do "return f();" or "f(); return;"
5966 po->regmask_dst &= ~(1 << xAX);
5968 find_next_read_reg(i + 1, opcnt, xAX, OPLM_DWORD,
5969 i + opcnt * 17, &j);
5972 po->regmask_dst &= ~(1 << xAX);
5976 // not "full stack" mode and have something in stack
5977 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5978 ferr(po, "float stack is not empty on func call\n");
5981 if (po->flags & OPF_NOREGS)
5984 // if incomplete register is used, clear it on init to avoid
5985 // later use of uninitialized upper part in some situations
5986 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5987 && po->operand[0].lmod != OPLM_DWORD)
5989 reg = po->operand[0].reg;
5990 ferr_assert(po, reg >= 0);
5992 if (!(regmask_now & (1 << reg)))
5993 *regmask_init |= 1 << reg;
5996 regmask_op = po->regmask_src | po->regmask_dst;
5998 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5999 regmask_new &= ~(1 << xSP);
6000 if (g_bp_frame && !(po->flags & OPF_EBP_S))
6001 regmask_new &= ~(1 << xBP);
6003 if (regmask_new != 0)
6004 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
6006 if (regmask_op & (1 << xBP)) {
6007 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
6008 if (po->regmask_dst & (1 << xBP))
6009 // compiler decided to drop bp frame and use ebp as scratch
6010 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
6012 regmask_op &= ~(1 << xBP);
6016 if (po->flags & OPF_FPUSH) {
6017 if (regmask_now & mxST1)
6018 regmask_now |= mxSTa; // switch to "full stack" mode
6019 if (regmask_now & mxSTa)
6020 po->flags |= OPF_FSHIFT;
6021 if (!(regmask_now & mxST7_2)) {
6023 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
6027 regmask_now |= regmask_op;
6028 *regmask |= regmask_now;
6031 if (po->flags & OPF_FPOPP) {
6032 if ((regmask_now & mxSTa) == 0)
6033 ferr(po, "float pop on empty stack?\n");
6034 if (regmask_now & mxST7_2)
6035 po->flags |= OPF_FSHIFT;
6036 if (!(regmask_now & mxST7_2))
6037 regmask_now &= ~mxST1_0;
6039 else if (po->flags & OPF_FPOP) {
6040 if ((regmask_now & mxSTa) == 0)
6041 ferr(po, "float pop on empty stack?\n");
6042 if (regmask_now & (mxST7_2 | mxST1))
6043 po->flags |= OPF_FSHIFT;
6044 if (!(regmask_now & mxST7_2)) {
6046 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
6050 if (po->flags & OPF_TAIL) {
6051 if (!(regmask_now & mxST7_2)) {
6052 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
6053 if (!(regmask_now & mxST0))
6054 ferr(po, "no st0 on float return, mask: %x\n",
6057 else if (regmask_now & mxST1_0)
6058 ferr(po, "float regs on tail: %x\n", regmask_now);
6061 // there is support for "conditional tailcall", sort of
6062 if (!(po->flags & OPF_CC))
6068 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
6069 int *pfomask, const char *dst_opr_text)
6071 if (*pfomask & (1 << PFO_Z)) {
6072 fprintf(fout, "\n cond_z = (%s%s == 0);",
6073 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
6074 *pfomask &= ~(1 << PFO_Z);
6078 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
6079 int *pfomask, const char *dst_opr_text)
6081 if (*pfomask & (1 << PFO_S)) {
6082 fprintf(fout, "\n cond_s = (%s%s < 0);",
6083 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
6084 *pfomask &= ~(1 << PFO_S);
6088 static void output_std_flags(FILE *fout, struct parsed_op *po,
6089 int *pfomask, const char *dst_opr_text)
6091 output_std_flag_z(fout, po, pfomask, dst_opr_text);
6092 output_std_flag_s(fout, po, pfomask, dst_opr_text);
6096 OPP_FORCE_NORETURN = (1 << 0),
6097 OPP_SIMPLE_ARGS = (1 << 1),
6098 OPP_ALIGN = (1 << 2),
6101 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
6104 const char *cconv = "";
6106 if (pp->is_fastcall)
6107 cconv = "__fastcall ";
6108 else if (pp->is_stdcall && pp->argc_reg == 0)
6109 cconv = "__stdcall ";
6111 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
6113 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
6114 fprintf(fout, "noreturn ");
6117 static void output_pp(FILE *fout, const struct parsed_proto *pp,
6122 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
6126 output_pp_attrs(fout, pp, flags);
6129 fprintf(fout, "%s", pp->name);
6134 for (i = 0; i < pp->argc; i++) {
6136 fprintf(fout, ", ");
6137 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
6138 && !(flags & OPP_SIMPLE_ARGS))
6141 output_pp(fout, pp->arg[i].pp, 0);
6143 else if (pp->arg[i].type.is_retreg) {
6144 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
6147 fprintf(fout, "%s", pp->arg[i].type.name);
6149 fprintf(fout, " a%d", i + 1);
6152 if (pp->arg[i].type.is_64bit)
6155 if (pp->is_vararg) {
6157 fprintf(fout, ", ");
6158 fprintf(fout, "...");
6163 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
6169 snprintf(buf1, sizeof(buf1), "%d", grp);
6170 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
6175 static void gen_x_cleanup(int opcnt);
6177 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
6179 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
6180 struct parsed_opr *last_arith_dst = NULL;
6181 char buf1[256], buf2[256], buf3[256], cast[64];
6182 struct parsed_proto *pp, *pp_tmp;
6183 struct parsed_data *pd;
6184 int save_arg_vars[MAX_ARG_GRP] = { 0, };
6185 unsigned char cbits[MAX_OPS / 8];
6186 const char *float_type;
6187 const char *float_st0;
6188 const char *float_st1;
6189 int need_float_stack = 0;
6190 int need_float_sw = 0; // status word
6191 int need_tmp_var = 0;
6195 int label_pending = 0;
6196 int need_double = 0;
6197 int stack_align = 0;
6198 int stack_fsz_adj = 0;
6199 int lock_handled = 0;
6200 int regmask_save = 0; // used regs saved/restored in this func
6201 int regmask_arg; // regs from this function args (fastcall, etc)
6202 int regmask_ret; // regs needed on ret
6203 int regmask_now; // temp
6204 int regmask_init = 0; // regs that need zero initialization
6205 int regmask_pp = 0; // regs used in complex push-pop graph
6206 int regmask_ffca = 0; // float function call args
6207 int regmask = 0; // used regs
6217 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
6218 g_stack_frame_used = 0;
6220 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
6221 regmask_init = g_regmask_init;
6223 g_func_pp = proto_parse(fhdr, funcn, 0);
6224 if (g_func_pp == NULL)
6225 ferr(ops, "proto_parse failed for '%s'\n", funcn);
6227 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
6228 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
6231 // - resolve all branches
6232 // - parse calls with labels
6233 resolve_branches_parse_calls(opcnt);
6236 // - handle ebp/esp frame, remove ops related to it
6237 scan_prologue_epilogue(opcnt, &stack_align);
6239 // handle a case where sf size is unalignment, but is
6240 // placed in a way that elements are still aligned
6241 if (g_stack_fsz & 4) {
6242 for (i = 0; i < g_eqcnt; i++) {
6243 if (g_eqs[i].lmod != OPLM_QWORD)
6245 if (!(g_eqs[i].offset & 4)) {
6254 // - remove dead labels
6255 // - set regs needed at ret
6256 for (i = 0; i < opcnt; i++)
6258 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
6263 if (ops[i].op == OP_RET)
6264 ops[i].regmask_src |= regmask_ret;
6268 // - process trivial calls
6269 for (i = 0; i < opcnt; i++)
6272 if (po->flags & (OPF_RMD|OPF_DONE))
6275 if (po->op == OP_CALL)
6277 pp = process_call_early(i, opcnt, &j);
6279 if (!(po->flags & OPF_ATAIL)) {
6280 // since we know the args, try to collect them
6281 ret = collect_call_args_early(i, opcnt, pp,
6282 ®mask, ®mask_ffca);
6290 // commit esp adjust
6291 if (ops[j].op != OP_POP)
6292 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
6294 for (l = 0; l < pp->argc_stack; l++)
6295 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
6299 if (strstr(pp->ret_type.name, "int64"))
6302 po->flags |= OPF_DONE;
6308 // - process calls, stage 2
6309 // - handle some push/pop pairs
6310 // - scan for STD/CLD, propagate DF
6311 // - try to resolve needed x87 status word bits
6312 for (i = 0; i < opcnt; i++)
6317 if (po->flags & OPF_RMD)
6320 if (po->op == OP_CALL)
6322 if (!(po->flags & OPF_DONE)) {
6323 pp = process_call(i, opcnt);
6325 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
6326 // since we know the args, collect them
6327 collect_call_args(po, i, opcnt, pp, ®mask, i + opcnt * 2);
6329 // for unresolved, collect after other passes
6333 ferr_assert(po, pp != NULL);
6335 po->regmask_src |= get_pp_arg_regmask_src(pp);
6336 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
6338 if (po->regmask_dst & mxST0)
6339 po->flags |= OPF_FPUSH;
6341 if (strstr(pp->ret_type.name, "int64"))
6347 if (po->flags & OPF_DONE)
6352 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
6353 && po->operand[0].type == OPT_CONST)
6355 scan_for_pop_const(i, opcnt, i + opcnt * 12);
6360 scan_pushes_for_pop(i, opcnt, ®mask_pp);
6364 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
6365 scan_propagate_df(i + 1, opcnt);
6370 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
6371 ferr(po, "TODO: fnstsw to mem\n");
6372 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
6374 ferr(po, "fnstsw resolve failed\n");
6375 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
6376 (void *)(long)(mask | (z_check << 16)));
6378 ferr(po, "failed to find fcom: %d\n", ret);
6387 // - find POPs for PUSHes, rm both
6388 // - scan for all used registers
6389 memset(cbits, 0, sizeof(cbits));
6390 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
6391 0, ®mask_save, ®mask_init, regmask_arg);
6393 need_float_stack = !!(regmask & mxST7_2);
6396 // - find flag set ops for their users
6397 // - do unresolved calls
6398 // - declare indirect functions
6399 // - other op specific processing
6400 for (i = 0; i < opcnt; i++)
6403 if (po->flags & (OPF_RMD|OPF_DONE))
6406 if (po->flags & OPF_CC)
6408 int setters[16], cnt = 0, branched = 0;
6410 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
6411 &branched, setters, &cnt);
6412 if (ret < 0 || cnt <= 0)
6413 ferr(po, "unable to trace flag setter(s)\n");
6414 if (cnt > ARRAY_SIZE(setters))
6415 ferr(po, "too many flag setters\n");
6417 for (j = 0; j < cnt; j++)
6419 tmp_op = &ops[setters[j]]; // flag setter
6422 // to get nicer code, we try to delay test and cmp;
6423 // if we can't because of operand modification, or if we
6424 // have arith op, or branch, make it calculate flags explicitly
6425 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
6427 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
6428 pfomask = 1 << po->pfo;
6430 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
6431 pfomask = 1 << po->pfo;
6434 // see if we'll be able to handle based on op result
6435 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
6436 && po->pfo != PFO_Z && po->pfo != PFO_S
6437 && po->pfo != PFO_P)
6439 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
6441 pfomask = 1 << po->pfo;
6444 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
6445 propagate_lmod(tmp_op, &tmp_op->operand[0],
6446 &tmp_op->operand[1]);
6447 if (tmp_op->operand[0].lmod == OPLM_DWORD)
6452 tmp_op->pfomask |= pfomask;
6453 cond_vars |= pfomask;
6455 // note: may overwrite, currently not a problem
6459 if (po->op == OP_RCL || po->op == OP_RCR
6460 || po->op == OP_ADC || po->op == OP_SBB)
6461 cond_vars |= 1 << PFO_C;
6467 cond_vars |= 1 << PFO_Z;
6471 if (po->operand[0].lmod == OPLM_DWORD)
6476 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
6481 // note: resolved non-reg calls are OPF_DONE already
6483 ferr_assert(po, pp != NULL);
6485 if (pp->is_unresolved) {
6486 int regmask_stack = 0;
6488 if ((po->flags & OPF_TAIL) && g_func_pp->is_stdcall)
6489 pp_insert_stack_args(pp, g_func_pp->argc_stack);
6491 collect_call_args(po, i, opcnt, pp, ®mask, i + opcnt * 2);
6493 // this is pretty rough guess:
6494 // see ecx and edx were pushed (and not their saved versions)
6495 for (arg = 0; arg < pp->argc; arg++) {
6496 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
6499 if (pp->arg[arg].push_ref_cnt == 0)
6500 ferr(po, "parsed_op missing for arg%d\n", arg);
6501 tmp_op = pp->arg[arg].push_refs[0];
6502 if (tmp_op->operand[0].type == OPT_REG)
6503 regmask_stack |= 1 << tmp_op->operand[0].reg;
6507 // quick dumb check for potential reg-args
6508 for (j = i - 1; j >= 0 && ops[j].op == OP_MOV; j--)
6509 if (ops[j].operand[0].type == OPT_REG)
6510 regmask_stack &= ~(1 << ops[j].operand[0].reg);
6512 if ((regmask_stack & (mxCX|mxDX)) != (mxCX|mxDX)
6513 && ((regmask | regmask_arg) & (mxCX|mxDX)))
6515 if (pp->argc_stack != 0
6516 || ((regmask | regmask_arg) & (mxCX|mxDX)))
6518 pp_insert_reg_arg(pp, "ecx");
6519 pp->is_fastcall = 1;
6520 regmask_init |= 1 << xCX;
6521 regmask |= 1 << xCX;
6523 if (pp->argc_stack != 0
6524 || ((regmask | regmask_arg) & mxDX))
6526 pp_insert_reg_arg(pp, "edx");
6527 regmask_init |= 1 << xDX;
6528 regmask |= 1 << xDX;
6532 // note: __cdecl doesn't fall into is_unresolved category
6533 if (pp->argc_stack > 0)
6536 if (!(po->flags & OPF_TAIL)
6537 && !(g_sct_func_attr & SCTFA_NOWARN) && !g_nowarn_reguse)
6539 // treat al write as overwrite to avoid many false positives
6540 if (IS(pp->ret_type.name, "void") || pp->ret_type.is_float) {
6541 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
6542 i + opcnt * 25, &j);
6544 fnote(po, "eax used after void/float ret call\n");
6545 fnote(&ops[j], "(used here)\n");
6548 if (!strstr(pp->ret_type.name, "int64")) {
6549 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
6550 i + opcnt * 26, &j);
6551 // indirect calls are often guessed, don't warn
6552 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6553 fnote(po, "edx used after 32bit ret call\n");
6554 fnote(&ops[j], "(used here)\n");
6558 // msvc often relies on callee not modifying 'this'
6559 for (arg = 0; arg < pp->argc; arg++) {
6560 if (pp->arg[arg].reg && IS(pp->arg[arg].reg, "ecx")) {
6566 find_next_read_reg(i + 1, opcnt, xCX, OPLM_BYTE,
6567 i + opcnt * 27, &j);
6568 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6569 fnote(po, "ecx used after call\n");
6570 fnote(&ops[j], "(used here)\n");
6577 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6579 // <var> = offset <something>
6580 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6581 && !IS_START(po->operand[1].name, "off_"))
6583 if (!po->operand[0].pp->is_fptr)
6584 ferr(po, "%s not declared as fptr when it should be\n",
6585 po->operand[0].name);
6586 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6587 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6588 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6589 fnote(po, "var: %s\n", buf1);
6590 fnote(po, "func: %s\n", buf2);
6591 ferr(po, "^ mismatch\n");
6599 if (po->operand[0].lmod == OPLM_DWORD) {
6600 // 32bit division is common, look for it
6601 if (po->op == OP_DIV)
6602 ret = scan_for_reg_clear(i, xDX);
6604 ret = scan_for_cdq_edx(i);
6606 po->flags |= OPF_32BIT;
6615 po->flags |= OPF_RMD | OPF_DONE;
6625 if (po->operand[0].lmod == OPLM_QWORD)
6636 find_next_read_reg(i + 1, opcnt, xDX, OPLM_DWORD,
6637 i + opcnt * 18, &j);
6639 po->flags |= OPF_32BIT;
6647 // pass8: sync all push arg numbers
6648 // some calls share args and not all of them
6649 // (there's only partial intersection)
6651 int changed, argnum, arggrp;
6654 for (i = 0; i < opcnt; i++)
6657 if ((po->flags & (OPF_RMD|OPF_DONE)) || po->op != OP_CALL)
6664 for (arg = argnum = 0; arg < pp->argc; arg++) {
6665 if (pp->arg[arg].reg != NULL)
6667 if (pp->arg[arg].is_saved)
6668 changed |= sync_argnum(pp, arg, &argnum, &arggrp);
6676 ferr(po, "too many args or looping in graph\n");
6681 // pass9: final adjustments
6682 for (i = 0; i < opcnt; i++)
6685 if (po->flags & (OPF_RMD|OPF_DONE))
6688 if (po->op != OP_FST && po->p_argnum > 0)
6689 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6691 // correct for "full stack" mode late enable
6692 if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6693 && need_float_stack)
6694 po->flags |= OPF_FSHIFT;
6697 float_type = need_double ? "double" : "float";
6698 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6699 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6701 // output starts here
6704 fprintf(fout, "// had SEH\n");
6706 // define userstack size
6707 if (g_func_pp->is_userstack) {
6708 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6709 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6710 fprintf(fout, "#endif\n");
6713 // the function itself
6714 ferr_assert(ops, !g_func_pp->is_fptr);
6715 output_pp(fout, g_func_pp,
6716 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6717 fprintf(fout, "\n{\n");
6719 // declare indirect functions
6720 for (i = 0; i < opcnt; i++) {
6722 if (po->flags & OPF_RMD)
6725 if (po->op == OP_CALL) {
6728 ferr(po, "NULL pp\n");
6730 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6731 if (pp->name[0] != 0) {
6732 if (IS_START(pp->name, "guess"))
6735 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6736 memcpy(pp->name, "i_", 2);
6738 // might be declared already
6740 for (j = 0; j < i; j++) {
6741 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6742 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6752 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6755 output_pp(fout, pp, OPP_SIMPLE_ARGS);
6756 fprintf(fout, ";\n");
6761 // output LUTs/jumptables
6762 for (i = 0; i < g_func_pd_cnt; i++) {
6764 fprintf(fout, " static const ");
6765 if (pd->type == OPT_OFFSET) {
6766 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6768 for (j = 0; j < pd->count; j++) {
6770 fprintf(fout, ", ");
6771 fprintf(fout, "&&%s", pd->d[j].u.label);
6775 fprintf(fout, "%s %s[] =\n { ",
6776 lmod_type_u(ops, pd->lmod), pd->label);
6778 for (j = 0; j < pd->count; j++) {
6780 fprintf(fout, ", ");
6781 fprintf(fout, "%u", pd->d[j].u.val);
6784 fprintf(fout, " };\n");
6788 // declare stack frame, va_arg
6791 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6793 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6794 if (g_func_lmods & (1 << OPLM_WORD))
6795 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6796 if (g_func_lmods & (1 << OPLM_BYTE))
6797 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6798 if (g_func_lmods & (1 << OPLM_QWORD))
6799 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6801 if (stack_align > 8)
6802 ferr(ops, "unhandled stack align of %d\n", stack_align);
6803 else if (stack_align == 8)
6804 fprintf(fout, " u64 align;");
6805 fprintf(fout, " } sf;\n");
6809 if ((g_sct_func_attr & SCTFA_ARGFRAME) && g_func_pp->argc_stack) {
6810 fprintf(fout, " struct { u32 ");
6811 for (i = j = 0; i < g_func_pp->argc; i++) {
6812 if (g_func_pp->arg[i].reg != NULL)
6815 fprintf(fout, ", ");
6816 fprintf(fout, "a%d", i + 1);
6818 fprintf(fout, "; } af = {\n ");
6819 for (i = j = 0; i < g_func_pp->argc; i++) {
6820 if (g_func_pp->arg[i].reg != NULL)
6823 fprintf(fout, ", ");
6824 if (g_func_pp->arg[i].type.is_ptr)
6825 fprintf(fout, "(u32)");
6826 fprintf(fout, "a%d", i + 1);
6828 fprintf(fout, "\n };\n");
6831 if (g_func_pp->is_userstack) {
6832 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6833 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6837 if (g_func_pp->is_vararg) {
6838 fprintf(fout, " va_list ap;\n");
6842 // declare arg-registers
6843 for (i = 0; i < g_func_pp->argc; i++) {
6844 if (g_func_pp->arg[i].reg != NULL) {
6845 reg = char_array_i(regs_r32,
6846 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6847 if (regmask & (1 << reg)) {
6848 if (g_func_pp->arg[i].type.is_retreg)
6849 fprintf(fout, " u32 %s = *r_%s;\n",
6850 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6852 fprintf(fout, " u32 %s = (u32)a%d;\n",
6853 g_func_pp->arg[i].reg, i + 1);
6856 if (g_func_pp->arg[i].type.is_retreg)
6857 ferr(ops, "retreg '%s' is unused?\n",
6858 g_func_pp->arg[i].reg);
6859 fprintf(fout, " // %s = a%d; // unused\n",
6860 g_func_pp->arg[i].reg, i + 1);
6866 // declare normal registers
6867 regmask_now = regmask & ~regmask_arg & ~g_regmask_rm;
6868 regmask_now &= ~(1 << xSP);
6869 if (regmask_now & 0x00ff) {
6870 for (reg = 0; reg < 8; reg++) {
6871 if (regmask_now & (1 << reg)) {
6872 fprintf(fout, " u32 %s", regs_r32[reg]);
6873 if (regmask_init & (1 << reg))
6874 fprintf(fout, " = 0");
6875 fprintf(fout, ";\n");
6881 if (regmask_now & 0xff00) {
6882 for (reg = 8; reg < 16; reg++) {
6883 if (regmask_now & (1 << reg)) {
6884 fprintf(fout, " mmxr %s", regs_r32[reg]);
6885 if (regmask_init & (1 << reg))
6886 fprintf(fout, " = { 0, }");
6887 fprintf(fout, ";\n");
6893 if (need_float_stack) {
6894 fprintf(fout, " %s f_st[8];\n", float_type);
6895 fprintf(fout, " int f_stp = 0;\n");
6899 if (regmask_now & 0xff0000) {
6900 for (reg = 16; reg < 24; reg++) {
6901 if (regmask_now & (1 << reg)) {
6902 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6903 if (regmask_init & (1 << reg))
6904 fprintf(fout, " = 0");
6905 fprintf(fout, ";\n");
6912 if (need_float_sw) {
6913 fprintf(fout, " u16 f_sw;\n");
6918 for (reg = 0; reg < 8; reg++) {
6919 if (regmask_save & (1 << reg)) {
6920 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6926 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6927 if (save_arg_vars[i] == 0)
6929 for (reg = 0; reg < 32; reg++) {
6930 if (save_arg_vars[i] & (1 << reg)) {
6931 fprintf(fout, " u32 %s;\n",
6932 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6939 for (reg = 0; reg < 32; reg++) {
6940 if (regmask_ffca & (1 << reg)) {
6941 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6947 // declare push-pop temporaries
6949 for (reg = 0; reg < 8; reg++) {
6950 if (regmask_pp & (1 << reg)) {
6951 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6958 for (i = 0; i < 8; i++) {
6959 if (cond_vars & (1 << i)) {
6960 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6967 fprintf(fout, " u32 tmp;\n");
6972 fprintf(fout, " u64 tmp64;\n");
6977 fprintf(fout, "\n");
6979 // do stack clear, if needed
6980 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6982 if (g_stack_clear_len != 0) {
6983 if (g_stack_clear_len <= 4) {
6984 for (i = 0; i < g_stack_clear_len; i++)
6985 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6986 fprintf(fout, "0;\n");
6989 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6990 g_stack_clear_start, g_stack_clear_len * 4);
6994 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6997 if (g_func_pp->is_vararg) {
6998 if (g_func_pp->argc_stack == 0)
6999 ferr(ops, "vararg func without stack args?\n");
7000 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
7004 for (i = 0; i < opcnt; i++)
7006 if (g_labels[i] != NULL) {
7007 fprintf(fout, "\n%s:\n", g_labels[i]);
7010 delayed_flag_op = NULL;
7011 last_arith_dst = NULL;
7015 if (po->flags & OPF_RMD)
7021 #define assert_operand_cnt(n_) \
7022 if (po->operand_cnt != n_) \
7023 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
7025 // conditional/flag using op?
7026 if (po->flags & OPF_CC)
7032 // we go through all this trouble to avoid using parsed_flag_op,
7033 // which makes generated code much nicer
7034 if (delayed_flag_op != NULL)
7036 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
7037 po->pfo, po->pfo_inv);
7040 else if (last_arith_dst != NULL
7041 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
7042 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
7045 struct parsed_op *po_arith = (void *)((char *)last_arith_dst
7046 - offsetof(struct parsed_op, operand[0]));
7047 ferr_assert(po, &ops[po_arith - ops] == po_arith);
7048 out_src_opr_u32(buf3, sizeof(buf3), po_arith, last_arith_dst);
7049 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
7050 last_arith_dst->lmod, buf3);
7053 else if (tmp_op != NULL) {
7054 // use preprocessed flag calc results
7055 if (!(tmp_op->pfomask & (1 << po->pfo)))
7056 ferr(po, "not prepared for pfo %d\n", po->pfo);
7058 // note: pfo_inv was not yet applied
7059 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
7060 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
7063 ferr(po, "all methods of finding comparison failed\n");
7066 if (po->flags & OPF_JMP) {
7067 fprintf(fout, " if %s", buf1);
7069 else if (po->op == OP_RCL || po->op == OP_RCR
7070 || po->op == OP_ADC || po->op == OP_SBB)
7073 fprintf(fout, " cond_%s = %s;\n",
7074 parsed_flag_op_names[po->pfo], buf1);
7076 else if (po->flags & OPF_DATA) { // SETcc
7077 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
7078 fprintf(fout, " %s = %s;", buf2, buf1);
7081 ferr(po, "unhandled conditional op\n");
7085 pfomask = po->pfomask;
7090 assert_operand_cnt(2);
7091 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7092 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7093 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
7094 fprintf(fout, " %s = %s;", buf1,
7095 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7100 assert_operand_cnt(2);
7101 po->operand[1].lmod = OPLM_DWORD; // always
7102 fprintf(fout, " %s = %s;",
7103 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7104 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7109 assert_operand_cnt(2);
7110 fprintf(fout, " %s = %s;",
7111 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7112 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7116 assert_operand_cnt(2);
7117 switch (po->operand[1].lmod) {
7119 strcpy(buf3, "(s8)");
7122 strcpy(buf3, "(s16)");
7125 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
7127 fprintf(fout, " %s = %s;",
7128 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7129 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7134 assert_operand_cnt(2);
7135 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7136 fprintf(fout, " tmp = %s;",
7137 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
7138 fprintf(fout, " %s = %s;",
7139 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7140 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7141 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7142 fprintf(fout, " %s = %stmp;",
7143 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
7144 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
7145 snprintf(g_comment, sizeof(g_comment), "xchg");
7149 assert_operand_cnt(1);
7150 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7151 fprintf(fout, " %s = ~%s;", buf1, buf1);
7155 assert_operand_cnt(2);
7156 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7157 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7158 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
7159 strcpy(g_comment, "xlat");
7163 assert_operand_cnt(2);
7164 fprintf(fout, " %s = (s32)%s >> 31;",
7165 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7166 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7167 strcpy(g_comment, "cdq");
7171 assert_operand_cnt(1);
7172 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7173 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
7177 if (po->flags & OPF_REP) {
7178 assert_operand_cnt(3);
7183 assert_operand_cnt(2);
7184 fprintf(fout, " %s = %sesi; esi %c= %d;",
7185 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
7186 lmod_cast_u_ptr(po, po->operand[1].lmod),
7187 (po->flags & OPF_DF) ? '-' : '+',
7188 lmod_bytes(po, po->operand[1].lmod));
7189 strcpy(g_comment, "lods");
7194 if (po->flags & OPF_REP) {
7195 assert_operand_cnt(3);
7196 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
7197 (po->flags & OPF_DF) ? '-' : '+',
7198 lmod_bytes(po, po->operand[1].lmod));
7199 fprintf(fout, " %sedi = eax;\n",
7200 lmod_cast_u_ptr(po, po->operand[1].lmod));
7201 fprintf(fout, " barrier();");
7202 strcpy(g_comment, "^ rep stos");
7205 assert_operand_cnt(2);
7206 fprintf(fout, " %sedi = eax; edi %c= %d;",
7207 lmod_cast_u_ptr(po, po->operand[1].lmod),
7208 (po->flags & OPF_DF) ? '-' : '+',
7209 lmod_bytes(po, po->operand[1].lmod));
7210 strcpy(g_comment, "stos");
7215 j = lmod_bytes(po, po->operand[0].lmod);
7216 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
7217 l = (po->flags & OPF_DF) ? '-' : '+';
7218 if (po->flags & OPF_REP) {
7219 assert_operand_cnt(3);
7221 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
7224 " %sedi = %sesi;\n", buf1, buf1);
7225 // this can overwrite many variables
7226 fprintf(fout, " barrier();");
7227 strcpy(g_comment, "^ rep movs");
7230 assert_operand_cnt(2);
7231 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
7232 buf1, buf1, l, j, l, j);
7233 strcpy(g_comment, "movs");
7238 // repe ~ repeat while ZF=1
7239 j = lmod_bytes(po, po->operand[0].lmod);
7240 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
7241 l = (po->flags & OPF_DF) ? '-' : '+';
7242 if (po->flags & OPF_REP) {
7243 assert_operand_cnt(3);
7245 " while (ecx != 0) {\n");
7246 if (pfomask & (1 << PFO_C)) {
7249 " cond_c = %sesi < %sedi;\n", buf1, buf1);
7250 pfomask &= ~(1 << PFO_C);
7253 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
7254 buf1, buf1, l, j, l, j);
7257 " if (cond_z %s 0) break;\n",
7258 (po->flags & OPF_REPZ) ? "==" : "!=");
7261 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
7262 (po->flags & OPF_REPZ) ? "e" : "ne");
7265 assert_operand_cnt(2);
7267 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
7268 buf1, buf1, l, j, l, j);
7269 strcpy(g_comment, "cmps");
7271 pfomask &= ~(1 << PFO_Z);
7272 last_arith_dst = NULL;
7273 delayed_flag_op = NULL;
7277 // only does ZF (for now)
7278 // repe ~ repeat while ZF=1
7279 j = lmod_bytes(po, po->operand[1].lmod);
7280 l = (po->flags & OPF_DF) ? '-' : '+';
7281 if (po->flags & OPF_REP) {
7282 assert_operand_cnt(3);
7284 " while (ecx != 0) {\n");
7286 " cond_z = (%seax == %sedi); edi %c= %d;\n",
7287 lmod_cast_u(po, po->operand[1].lmod),
7288 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
7291 " if (cond_z %s 0) break;\n",
7292 (po->flags & OPF_REPZ) ? "==" : "!=");
7295 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
7296 (po->flags & OPF_REPZ) ? "e" : "ne");
7299 assert_operand_cnt(2);
7300 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
7301 lmod_cast_u(po, po->operand[1].lmod),
7302 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
7303 strcpy(g_comment, "scas");
7305 pfomask &= ~(1 << PFO_Z);
7306 last_arith_dst = NULL;
7307 delayed_flag_op = NULL;
7311 fprintf(fout, " tmp64 = ext_rdtsc();\n");
7312 fprintf(fout, " edx = tmp64 >> 32;\n");
7313 fprintf(fout, " eax = tmp64;");
7317 fprintf(fout, " ext_cpuid(&eax, &ebx, &ecx, &edx);");
7320 // arithmetic w/flags
7322 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
7323 goto dualop_arith_const;
7324 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7328 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7329 if (po->operand[1].type == OPT_CONST) {
7330 j = lmod_bytes(po, po->operand[0].lmod);
7331 if (((1ull << j * 8) - 1) == po->operand[1].val)
7332 goto dualop_arith_const;
7337 assert_operand_cnt(2);
7338 fprintf(fout, " %s %s= %s;",
7339 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7341 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7342 output_std_flags(fout, po, &pfomask, buf1);
7343 last_arith_dst = &po->operand[0];
7344 delayed_flag_op = NULL;
7348 // and 0, or ~0 used instead mov
7349 assert_operand_cnt(2);
7350 fprintf(fout, " %s = %s;",
7351 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7352 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7353 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7354 output_std_flags(fout, po, &pfomask, buf1);
7355 last_arith_dst = &po->operand[0];
7356 delayed_flag_op = NULL;
7361 assert_operand_cnt(2);
7362 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7363 if (pfomask & (1 << PFO_C)) {
7364 if (po->operand[1].type == OPT_CONST) {
7365 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7366 j = po->operand[1].val;
7369 if (po->op == OP_SHL)
7373 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
7377 ferr(po, "zero shift?\n");
7381 pfomask &= ~(1 << PFO_C);
7383 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
7384 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7385 if (po->operand[1].type != OPT_CONST)
7386 fprintf(fout, " & 0x1f");
7388 output_std_flags(fout, po, &pfomask, buf1);
7389 last_arith_dst = &po->operand[0];
7390 delayed_flag_op = NULL;
7394 assert_operand_cnt(2);
7395 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7396 fprintf(fout, " %s = %s%s >> %s;", buf1,
7397 lmod_cast_s(po, po->operand[0].lmod), buf1,
7398 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7399 output_std_flags(fout, po, &pfomask, buf1);
7400 last_arith_dst = &po->operand[0];
7401 delayed_flag_op = NULL;
7406 assert_operand_cnt(3);
7407 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7408 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7409 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
7410 if (po->operand[2].type != OPT_CONST) {
7411 // no handling for "undefined" case, hopefully not needed
7412 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
7415 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7416 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7417 if (po->op == OP_SHLD) {
7418 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
7419 buf1, buf3, buf1, buf2, l, buf3);
7420 strcpy(g_comment, "shld");
7423 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
7424 buf1, buf3, buf1, buf2, l, buf3);
7425 strcpy(g_comment, "shrd");
7427 output_std_flags(fout, po, &pfomask, buf1);
7428 last_arith_dst = &po->operand[0];
7429 delayed_flag_op = NULL;
7434 assert_operand_cnt(2);
7435 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7436 if (po->operand[1].type == OPT_CONST) {
7437 j = po->operand[1].val;
7438 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
7439 fprintf(fout, po->op == OP_ROL ?
7440 " %s = (%s << %d) | (%s >> %d);" :
7441 " %s = (%s >> %d) | (%s << %d);",
7442 buf1, buf1, j, buf1,
7443 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
7447 output_std_flags(fout, po, &pfomask, buf1);
7448 last_arith_dst = &po->operand[0];
7449 delayed_flag_op = NULL;
7454 assert_operand_cnt(2);
7455 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7456 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7457 if (po->operand[1].type == OPT_CONST) {
7458 j = po->operand[1].val % l;
7460 ferr(po, "zero rotate\n");
7461 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
7462 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
7463 if (po->op == OP_RCL) {
7465 " %s = (%s << %d) | (cond_c << %d)",
7466 buf1, buf1, j, j - 1);
7468 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
7472 " %s = (%s >> %d) | (cond_c << %d)",
7473 buf1, buf1, j, l - j);
7475 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
7477 fprintf(fout, ";\n");
7478 fprintf(fout, " cond_c = tmp;");
7482 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
7483 output_std_flags(fout, po, &pfomask, buf1);
7484 last_arith_dst = &po->operand[0];
7485 delayed_flag_op = NULL;
7489 assert_operand_cnt(2);
7490 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7491 if (IS(opr_name(po, 0), opr_name(po, 1))) {
7492 // special case for XOR
7493 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
7494 for (j = 0; j <= PFO_LE; j++) {
7495 if (pfomask & (1 << j)) {
7496 fprintf(fout, " cond_%s = %d;\n",
7497 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
7498 pfomask &= ~(1 << j);
7501 fprintf(fout, " %s = 0;",
7502 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7503 last_arith_dst = &po->operand[0];
7504 delayed_flag_op = NULL;
7510 assert_operand_cnt(2);
7511 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7512 if (pfomask & (1 << PFO_C)) {
7513 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7514 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7515 if (po->operand[0].lmod == OPLM_DWORD) {
7516 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
7517 fprintf(fout, " cond_c = tmp64 >> 32;\n");
7518 fprintf(fout, " %s = (u32)tmp64;",
7519 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7520 strcat(g_comment, " add64");
7523 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
7524 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
7525 fprintf(fout, " %s += %s;",
7526 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7529 pfomask &= ~(1 << PFO_C);
7530 output_std_flags(fout, po, &pfomask, buf1);
7531 last_arith_dst = &po->operand[0];
7532 delayed_flag_op = NULL;
7535 if (pfomask & (1 << PFO_LE)) {
7536 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
7537 fprintf(fout, " cond_%s = %s;\n",
7538 parsed_flag_op_names[PFO_LE], buf1);
7539 pfomask &= ~(1 << PFO_LE);
7544 assert_operand_cnt(2);
7545 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7546 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
7547 for (j = 0; j <= PFO_LE; j++) {
7548 if (!(pfomask & (1 << j)))
7550 if (j == PFO_Z || j == PFO_S)
7553 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7554 fprintf(fout, " cond_%s = %s;\n",
7555 parsed_flag_op_names[j], buf1);
7556 pfomask &= ~(1 << j);
7563 assert_operand_cnt(2);
7564 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7565 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7566 if (po->op == OP_SBB
7567 && IS(po->operand[0].name, po->operand[1].name))
7569 // avoid use of unitialized var
7570 fprintf(fout, " %s = -cond_c;", buf1);
7571 // carry remains what it was
7572 pfomask &= ~(1 << PFO_C);
7575 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
7576 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7578 output_std_flags(fout, po, &pfomask, buf1);
7579 last_arith_dst = &po->operand[0];
7580 delayed_flag_op = NULL;
7585 // on SKL, if src is 0, dst is left unchanged
7586 assert_operand_cnt(2);
7587 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7588 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7589 output_std_flag_z(fout, po, &pfomask, buf2);
7590 if (po->op == OP_BSF)
7591 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
7593 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
7594 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
7595 last_arith_dst = &po->operand[0];
7596 delayed_flag_op = NULL;
7597 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
7601 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
7602 for (j = 0; j <= PFO_LE; j++) {
7603 if (!(pfomask & (1 << j)))
7605 if (j == PFO_Z || j == PFO_S || j == PFO_C)
7608 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7609 fprintf(fout, " cond_%s = %s;\n",
7610 parsed_flag_op_names[j], buf1);
7611 pfomask &= ~(1 << j);
7617 if (pfomask & (1 << PFO_C))
7618 // carry is unaffected by inc/dec.. wtf?
7619 ferr(po, "carry propagation needed\n");
7621 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7622 if (po->operand[0].type == OPT_REG) {
7623 ferr_assert(po, !(po->flags & OPF_LOCK));
7624 strcpy(buf2, po->op == OP_INC ? "++" : "--");
7625 fprintf(fout, " %s%s;", buf1, buf2);
7627 else if (po->flags & OPF_LOCK) {
7628 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], "", 1);
7629 fprintf(fout, " __sync_fetch_and_%s((%s *)(%s), 1);",
7630 po->op == OP_INC ? "add" : "sub",
7631 lmod_type_u(po, po->operand[0].lmod), buf2);
7632 strcat(g_comment, " lock");
7636 strcpy(buf2, po->op == OP_INC ? "+" : "-");
7637 fprintf(fout, " %s %s= 1;", buf1, buf2);
7639 output_std_flags(fout, po, &pfomask, buf1);
7640 last_arith_dst = &po->operand[0];
7641 delayed_flag_op = NULL;
7645 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7646 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
7647 fprintf(fout, " %s = -%s%s;", buf1,
7648 lmod_cast_s(po, po->operand[0].lmod), buf2);
7649 last_arith_dst = &po->operand[0];
7650 delayed_flag_op = NULL;
7651 if (pfomask & PFOB_C) {
7652 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
7655 output_std_flags(fout, po, &pfomask, buf1);
7659 if (po->operand_cnt == 2) {
7660 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7663 if (po->operand_cnt == 3)
7664 ferr(po, "TODO imul3\n");
7667 assert_operand_cnt(1);
7668 switch (po->operand[0].lmod) {
7670 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7671 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
7672 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7673 fprintf(fout, " edx = tmp64 >> 32;\n");
7674 fprintf(fout, " eax = tmp64;");
7677 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7678 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
7679 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7683 ferr(po, "TODO: unhandled mul type\n");
7686 last_arith_dst = NULL;
7687 delayed_flag_op = NULL;
7692 assert_operand_cnt(1);
7693 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7694 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7695 po->op == OP_IDIV));
7696 switch (po->operand[0].lmod) {
7698 if (po->flags & OPF_32BIT)
7699 snprintf(buf2, sizeof(buf2), "%seax", cast);
7701 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7702 snprintf(buf2, sizeof(buf2), "%stmp64",
7703 (po->op == OP_IDIV) ? "(s64)" : "");
7705 if (po->operand[0].type == OPT_REG
7706 && po->operand[0].reg == xDX)
7708 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
7709 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
7712 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
7713 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
7717 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
7718 snprintf(buf2, sizeof(buf2), "%stmp",
7719 (po->op == OP_IDIV) ? "(s32)" : "");
7720 if (po->operand[0].type == OPT_REG
7721 && po->operand[0].reg == xDX)
7723 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
7725 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
7729 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
7731 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
7734 strcat(g_comment, " div16");
7737 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7739 last_arith_dst = NULL;
7740 delayed_flag_op = NULL;
7745 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7747 for (j = 0; j < 8; j++) {
7748 if (pfomask & (1 << j)) {
7749 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7750 fprintf(fout, " cond_%s = %s;",
7751 parsed_flag_op_names[j], buf1);
7758 last_arith_dst = NULL;
7759 delayed_flag_op = po;
7763 // SETcc - should already be handled
7766 // note: we reuse OP_Jcc for SETcc, only flags differ
7768 fprintf(fout, "\n goto %s;", po->operand[0].name);
7772 fprintf(fout, " if (ecx == 0)\n");
7773 fprintf(fout, " goto %s;", po->operand[0].name);
7774 strcat(g_comment, " jecxz");
7778 fprintf(fout, " if (--ecx != 0)\n");
7779 fprintf(fout, " goto %s;", po->operand[0].name);
7780 strcat(g_comment, " loop");
7784 assert_operand_cnt(1);
7785 last_arith_dst = NULL;
7786 delayed_flag_op = NULL;
7788 if (po->operand[0].type == OPT_REGMEM) {
7789 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7792 ferr(po, "parse failure for jmp '%s'\n",
7793 po->operand[0].name);
7794 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
7797 else if (po->operand[0].type != OPT_LABEL)
7798 ferr(po, "unhandled jmp type\n");
7800 fprintf(fout, " goto %s;", po->operand[0].name);
7804 assert_operand_cnt(1);
7806 my_assert_not(pp, NULL);
7809 if (po->flags & OPF_CC) {
7810 // we treat conditional branch to another func
7811 // (yes such code exists..) as conditional tailcall
7813 fprintf(fout, " {\n");
7816 if (pp->is_fptr && !pp->is_arg) {
7817 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7818 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7821 if (pp->is_fptr && (pp->is_unresolved || pp->is_guessed)) {
7822 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7823 buf3, asmfn, po->asmln, pp->name);
7826 fprintf(fout, "%s", buf3);
7827 if (strstr(pp->ret_type.name, "int64")) {
7828 if (po->flags & OPF_TAIL)
7829 ferr(po, "int64 and tail?\n");
7830 fprintf(fout, "tmp64 = ");
7832 else if (!IS(pp->ret_type.name, "void")) {
7833 if (po->flags & OPF_TAIL) {
7834 if (regmask_ret & mxAX) {
7835 fprintf(fout, "return ");
7836 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7837 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7839 else if (regmask_ret & mxST0)
7840 ferr(po, "float tailcall\n");
7842 else if (po->regmask_dst & mxAX) {
7843 fprintf(fout, "eax = ");
7844 if (pp->ret_type.is_ptr)
7845 fprintf(fout, "(u32)");
7847 else if (po->regmask_dst & mxST0) {
7848 ferr_assert(po, po->flags & OPF_FPUSH);
7849 if (need_float_stack)
7850 fprintf(fout, "f_st[--f_stp & 7] = ");
7852 fprintf(fout, "f_st0 = ");
7856 if (pp->name[0] == 0)
7857 ferr(po, "missing pp->name\n");
7858 fprintf(fout, "%s%s(", pp->name,
7859 pp->has_structarg ? "_sa" : "");
7861 if (po->flags & OPF_ATAIL) {
7863 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7864 check_compat |= pp->argc_stack > 0;
7866 && (pp->argc_stack != g_func_pp->argc_stack
7867 || pp->is_stdcall != g_func_pp->is_stdcall))
7868 ferr(po, "incompatible arg-reuse tailcall\n");
7869 if (g_func_pp->has_retreg)
7870 ferr(po, "TODO: retreg+tailcall\n");
7872 for (arg = j = 0; arg < pp->argc; arg++) {
7874 fprintf(fout, ", ");
7877 if (pp->arg[arg].type.is_ptr)
7878 snprintf(cast, sizeof(cast), "(%s)",
7879 pp->arg[arg].type.name);
7881 if (pp->arg[arg].reg != NULL) {
7882 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7886 for (; j < g_func_pp->argc; j++)
7887 if (g_func_pp->arg[j].reg == NULL)
7889 fprintf(fout, "%sa%d", cast, j + 1);
7894 for (arg = 0; arg < pp->argc; arg++) {
7896 fprintf(fout, ", ");
7899 if (pp->arg[arg].type.is_ptr)
7900 snprintf(cast, sizeof(cast), "(%s)",
7901 pp->arg[arg].type.name);
7903 if (pp->arg[arg].reg != NULL) {
7904 if (pp->arg[arg].type.is_retreg)
7905 fprintf(fout, "&%s", pp->arg[arg].reg);
7906 else if (IS(pp->arg[arg].reg, "ebp")
7907 && g_bp_frame && !(po->flags & OPF_EBP_S))
7909 // rare special case
7910 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7911 strcat(g_comment, " bp_ref");
7914 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7919 if (pp->arg[arg].push_ref_cnt == 0)
7920 ferr(po, "parsed_op missing for arg%d\n", arg);
7921 if (pp->arg[arg].push_ref_cnt > 1)
7922 ferr_assert(po, pp->arg[arg].is_saved);
7923 tmp_op = pp->arg[arg].push_refs[0];
7924 ferr_assert(po, tmp_op != NULL);
7926 if (tmp_op->flags & OPF_VAPUSH) {
7927 fprintf(fout, "ap");
7929 else if (tmp_op->op == OP_FST) {
7930 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7931 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7934 else if (pp->arg[arg].type.is_64bit) {
7935 ferr_assert(po, tmp_op->p_argpass == 0);
7936 ferr_assert(po, !pp->arg[arg].is_saved);
7937 ferr_assert(po, !pp->arg[arg].type.is_float);
7938 ferr_assert(po, cast[0] == 0);
7939 out_src_opr(buf1, sizeof(buf1),
7940 tmp_op, &tmp_op->operand[0], cast, 0);
7942 ferr_assert(po, pp->arg[arg].push_ref_cnt == 1);
7943 tmp_op = pp->arg[arg].push_refs[0];
7944 ferr_assert(po, tmp_op != NULL);
7945 out_src_opr(buf2, sizeof(buf2),
7946 tmp_op, &tmp_op->operand[0], cast, 0);
7947 fprintf(fout, "((u64)(%s) << 32) | (%s)",
7950 else if (tmp_op->p_argpass != 0) {
7951 ferr_assert(po, !pp->arg[arg].type.is_float);
7952 fprintf(fout, "a%d", tmp_op->p_argpass);
7954 else if (pp->arg[arg].is_saved) {
7955 ferr_assert(po, tmp_op->p_argnum > 0);
7956 ferr_assert(po, !pp->arg[arg].type.is_float);
7957 fprintf(fout, "%s%s", cast,
7958 saved_arg_name(buf1, sizeof(buf1),
7959 tmp_op->p_arggrp, tmp_op->p_argnum));
7961 else if (pp->arg[arg].type.is_float) {
7962 ferr_assert(po, !pp->arg[arg].type.is_64bit);
7964 out_src_opr_float(buf1, sizeof(buf1),
7965 tmp_op, &tmp_op->operand[0], need_float_stack));
7969 out_src_opr(buf1, sizeof(buf1),
7970 tmp_op, &tmp_op->operand[0], cast, 0));
7974 fprintf(fout, ");");
7976 if (strstr(pp->ret_type.name, "int64")) {
7977 fprintf(fout, "\n");
7978 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7979 fprintf(fout, "%seax = tmp64;", buf3);
7982 if (pp->is_unresolved) {
7983 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7985 strcat(g_comment, buf2);
7988 if (po->flags & OPF_TAIL) {
7990 if (i == opcnt - 1 || pp->is_noreturn)
7992 else if (IS(pp->ret_type.name, "void"))
7994 else if (!(regmask_ret & (1 << xAX)))
7996 // else already handled as 'return f()'
7999 fprintf(fout, "\n%sreturn;", buf3);
8000 strcat(g_comment, " ^ tailcall");
8003 strcat(g_comment, " tailcall");
8005 if ((regmask_ret & (1 << xAX))
8006 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
8008 ferr(po, "int func -> void func tailcall?\n");
8011 if (pp->is_noreturn)
8012 strcat(g_comment, " noreturn");
8013 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
8014 strcat(g_comment, " argframe");
8015 if (po->flags & OPF_CC)
8016 strcat(g_comment, " cond");
8018 if (po->flags & OPF_CC)
8019 fprintf(fout, "\n }");
8021 delayed_flag_op = NULL;
8022 last_arith_dst = NULL;
8027 if (g_func_pp->is_vararg)
8028 fprintf(fout, " va_end(ap);\n");
8029 if (g_func_pp->has_retreg) {
8030 for (arg = 0; arg < g_func_pp->argc; arg++)
8031 if (g_func_pp->arg[arg].type.is_retreg)
8032 fprintf(fout, " *r_%s = %s;\n",
8033 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
8036 if (regmask_ret & mxST0) {
8037 fprintf(fout, " return %s;", float_st0);
8039 else if (!(regmask_ret & mxAX)) {
8040 if (i != opcnt - 1 || label_pending)
8041 fprintf(fout, " return;");
8043 else if (g_func_pp->ret_type.is_ptr) {
8044 fprintf(fout, " return (%s)eax;",
8045 g_func_pp->ret_type.name);
8047 else if (IS(g_func_pp->ret_type.name, "__int64"))
8048 fprintf(fout, " return ((u64)edx << 32) | eax;");
8050 fprintf(fout, " return eax;");
8052 last_arith_dst = NULL;
8053 delayed_flag_op = NULL;
8057 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
8058 if (po->p_argnum != 0) {
8059 // special case - saved func arg
8060 fprintf(fout, " %s = %s;",
8061 saved_arg_name(buf2, sizeof(buf2),
8062 po->p_arggrp, po->p_argnum), buf1);
8065 else if (po->flags & OPF_RSAVE) {
8066 fprintf(fout, " s_%s = %s;", buf1, buf1);
8069 else if (po->flags & OPF_PPUSH) {
8071 ferr_assert(po, tmp_op != NULL);
8072 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
8073 fprintf(fout, " pp_%s = %s;", buf2, buf1);
8076 else if (g_func_pp->is_userstack) {
8077 fprintf(fout, " *(--esp) = %s;", buf1);
8080 if (!(g_ida_func_attr & IDAFA_NORETURN))
8081 ferr(po, "stray push encountered\n");
8086 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
8087 if (po->flags & OPF_RSAVE) {
8088 fprintf(fout, " %s = s_%s;", buf1, buf1);
8091 else if (po->flags & OPF_PPUSH) {
8092 // push/pop graph / non-const
8093 ferr_assert(po, po->datap == NULL);
8094 fprintf(fout, " %s = pp_%s;", buf1, buf1);
8097 else if (po->datap != NULL) {
8100 fprintf(fout, " %s = %s;", buf1,
8101 out_src_opr(buf2, sizeof(buf2),
8102 tmp_op, &tmp_op->operand[0],
8103 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
8106 else if (g_func_pp->is_userstack) {
8107 fprintf(fout, " %s = *esp++;", buf1);
8111 ferr(po, "stray pop encountered\n");
8121 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
8122 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
8123 po->op == OPP_ALLSHL ? "<<" : ">>");
8124 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
8125 strcat(g_comment, po->op == OPP_ALLSHL
8126 ? " allshl" : " allshr");
8131 if (need_float_stack) {
8132 out_src_opr_float(buf1, sizeof(buf1),
8133 po, &po->operand[0], 1);
8134 if (po->regmask_src & mxSTa) {
8135 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
8139 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
8142 if (po->flags & OPF_FSHIFT)
8143 fprintf(fout, " f_st1 = f_st0;");
8144 if (po->operand[0].type == OPT_REG
8145 && po->operand[0].reg == xST0)
8147 strcat(g_comment, " fld st");
8150 fprintf(fout, " f_st0 = %s;",
8151 out_src_opr_float(buf1, sizeof(buf1),
8152 po, &po->operand[0], 0));
8154 strcat(g_comment, " fld");
8158 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
8159 lmod_cast(po, po->operand[0].lmod, 1), 0);
8160 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
8161 if (need_float_stack) {
8162 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
8165 if (po->flags & OPF_FSHIFT)
8166 fprintf(fout, " f_st1 = f_st0;");
8167 fprintf(fout, " f_st0 = %s;", buf2);
8169 strcat(g_comment, " fild");
8173 if (need_float_stack)
8174 fprintf(fout, " f_st[--f_stp & 7] = ");
8176 if (po->flags & OPF_FSHIFT)
8177 fprintf(fout, " f_st1 = f_st0;");
8178 fprintf(fout, " f_st0 = ");
8180 switch (po->operand[0].val) {
8181 case X87_CONST_1: fprintf(fout, "1.0;"); break;
8182 case X87_CONST_L2T: fprintf(fout, "3.321928094887362;"); break;
8183 case X87_CONST_L2E: fprintf(fout, "M_LOG2E;"); break;
8184 case X87_CONST_PI: fprintf(fout, "M_PI;"); break;
8185 case X87_CONST_LG2: fprintf(fout, "0.301029995663981;"); break;
8186 case X87_CONST_LN2: fprintf(fout, "M_LN2;"); break;
8187 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
8188 default: ferr_assert(po, 0); break;
8194 if (po->flags & OPF_FARG) {
8195 // store to stack as func arg
8196 fprintf(fout, " fs_%d = %s;", po->p_argnum, float_st0);
8198 else if (po->operand[0].type == OPT_REG
8199 && po->operand[0].reg == xST0)
8203 else if (float_opr_needs_helper(po, &po->operand[0])) {
8204 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 1);
8205 fprintf(fout, " %s_store(%s, %s);",
8206 po->operand[0].lmod == OPLM_QWORD ? "double" : "float",
8210 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8212 fprintf(fout, " %s = %s;", buf1, float_st0);
8214 if (po->flags & OPF_FSHIFT) {
8215 if (need_float_stack)
8216 fprintf(fout, " f_stp++;");
8218 fprintf(fout, " f_st0 = f_st1;");
8220 if (dead_dst && !(po->flags & OPF_FSHIFT))
8223 strcat(g_comment, " fst");
8227 fprintf(fout, " %s = %s%s;",
8228 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
8229 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
8230 if (po->flags & OPF_FSHIFT) {
8231 if (need_float_stack)
8232 fprintf(fout, " f_stp++;");
8234 fprintf(fout, " f_st0 = f_st1;");
8236 strcat(g_comment, " fist");
8240 fprintf(fout, " %s = fabs%s(%s);", float_st0,
8241 need_double ? "" : "f", float_st0);
8248 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8250 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8252 dead_dst = (po->flags & OPF_FPOP)
8253 && po->operand[0].type == OPT_REG
8254 && po->operand[0].reg == xST0;
8256 case OP_FADD: j = '+'; break;
8257 case OP_FDIV: j = '/'; break;
8258 case OP_FMUL: j = '*'; break;
8259 case OP_FSUB: j = '-'; break;
8260 default: j = 'x'; break;
8262 if (need_float_stack) {
8264 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
8265 if (po->flags & OPF_FSHIFT)
8266 fprintf(fout, " f_stp++;");
8269 if (po->flags & OPF_FSHIFT) {
8270 // note: assumes only 2 regs handled
8272 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
8274 fprintf(fout, " f_st0 = f_st1;");
8277 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
8279 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
8284 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8286 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8288 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
8290 dead_dst = (po->flags & OPF_FPOP)
8291 && po->operand[0].type == OPT_REG
8292 && po->operand[0].reg == xST0;
8293 j = po->op == OP_FDIVR ? '/' : '-';
8294 if (need_float_stack) {
8296 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
8297 if (po->flags & OPF_FSHIFT)
8298 fprintf(fout, " f_stp++;");
8301 if (po->flags & OPF_FSHIFT) {
8303 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
8305 fprintf(fout, " f_st0 = f_st1;");
8308 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
8310 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
8318 case OP_FIADD: j = '+'; break;
8319 case OP_FIDIV: j = '/'; break;
8320 case OP_FIMUL: j = '*'; break;
8321 case OP_FISUB: j = '-'; break;
8322 default: j = 'x'; break;
8324 fprintf(fout, " %s %c= (%s)%s;", float_st0,
8326 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
8327 lmod_cast(po, po->operand[0].lmod, 1), 0));
8332 fprintf(fout, " %s = %s %c %s;", float_st0,
8333 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8335 po->op == OP_FIDIVR ? '/' : '-', float_st0);
8340 ferr_assert(po, po->datap != NULL);
8341 mask = (long)po->datap & 0xffff;
8342 z_check = ((long)po->datap >> 16) & 1;
8343 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8345 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
8346 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
8349 else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
8350 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
8353 else if (mask == 0x4100) { // C3, C0
8355 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
8357 strcat(g_comment, " z_chk_det");
8360 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
8361 "(%s < %s ? 0x0100 : 0);",
8362 float_st0, buf1, float_st0, buf1);
8366 ferr(po, "unhandled sw mask: %x\n", mask);
8367 if (po->flags & OPF_FSHIFT) {
8368 if (need_float_stack) {
8369 if (po->flags & OPF_FPOPP)
8370 fprintf(fout, " f_stp += 2;");
8372 fprintf(fout, " f_stp++;");
8375 ferr_assert(po, !(po->flags & OPF_FPOPP));
8376 fprintf(fout, " f_st0 = f_st1;");
8383 fprintf(fout, " %s = f_sw;",
8384 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
8388 fprintf(fout, " %s = -%s;", float_st0, float_st0);
8392 fprintf(fout, " %s = cos%s(%s);", float_st0,
8393 need_double ? "" : "f", float_st0);
8397 if (need_float_stack) {
8398 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
8399 need_double ? "" : "f", float_st1, float_st0);
8400 fprintf(fout, " f_stp++;");
8403 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
8404 need_double ? "" : "f");
8409 if (need_float_stack) {
8410 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
8411 float_st1, need_double ? "" : "f", float_st0);
8412 fprintf(fout, " f_stp++;");
8415 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
8416 need_double ? "" : "f");
8418 strcat(g_comment, " fyl2x");
8422 fprintf(fout, " %s = sin%s(%s);", float_st0,
8423 need_double ? "" : "f", float_st0);
8427 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
8428 need_double ? "" : "f", float_st0);
8432 dead_dst = po->operand[0].type == OPT_REG
8433 && po->operand[0].reg == xST0;
8435 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8437 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
8438 float_st0, float_st0, buf1, buf1);
8439 strcat(g_comment, " fxch");
8446 ferr_assert(po, po->flags & OPF_32BIT);
8447 fprintf(fout, " eax = (s32)%s;", float_st0);
8448 if (po->flags & OPF_FSHIFT) {
8449 if (need_float_stack)
8450 fprintf(fout, " f_stp++;");
8452 fprintf(fout, " f_st0 = f_st1;");
8454 strcat(g_comment, " ftol");
8458 if (need_float_stack) {
8459 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
8460 need_double ? "" : "f", float_st1, float_st0);
8461 fprintf(fout, " f_stp++;");
8464 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
8465 need_double ? "" : "f");
8467 strcat(g_comment, " CIpow");
8471 fprintf(fout, " do_skip_code_abort();");
8476 fprintf(fout, " do_emms();");
8480 if (po->flags & OPF_TAIL) {
8481 fprintf(fout, "\n");
8482 strcat(g_comment, " tail");
8489 ferr(po, "unhandled op type %d, flags %x\n",
8494 if (g_comment[0] != 0) {
8495 char *p = g_comment;
8496 while (my_isblank(*p))
8498 fprintf(fout, " // %s", p);
8503 fprintf(fout, "\n");
8505 // some sanity checking
8506 if (po->flags & OPF_REP) {
8507 if (po->op != OP_STOS && po->op != OP_MOVS
8508 && po->op != OP_CMPS && po->op != OP_SCAS)
8509 ferr(po, "unexpected rep\n");
8510 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
8511 && (po->op == OP_CMPS || po->op == OP_SCAS))
8512 ferr(po, "cmps/scas with plain rep\n");
8514 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
8515 && po->op != OP_CMPS && po->op != OP_SCAS)
8516 ferr(po, "unexpected repz/repnz\n");
8519 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
8521 if ((po->flags & OPF_LOCK) && !lock_handled)
8522 ferr(po, "unhandled lock\n");
8524 // see is delayed flag stuff is still valid
8525 if (delayed_flag_op != NULL && delayed_flag_op != po) {
8526 if (is_any_opr_modified(delayed_flag_op, po, 0))
8527 delayed_flag_op = NULL;
8530 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
8531 if (is_opr_modified(last_arith_dst, po))
8532 last_arith_dst = NULL;
8539 if (g_stack_fsz && !g_stack_frame_used)
8540 fprintf(fout, " (void)sf;\n");
8542 fprintf(fout, "}\n\n");
8544 gen_x_cleanup(opcnt);
8547 static void gen_x_cleanup(int opcnt)
8551 for (i = 0; i < opcnt; i++) {
8552 struct label_ref *lr, *lr_del;
8554 lr = g_label_refs[i].next;
8555 while (lr != NULL) {
8560 g_label_refs[i].i = -1;
8561 g_label_refs[i].next = NULL;
8563 if (ops[i].op == OP_CALL) {
8565 proto_release(ops[i].pp);
8571 struct func_proto_dep;
8573 struct func_prototype {
8577 int regmask_dep; // likely register args
8578 int regmask_use; // used registers
8579 int has_ret:3; // -1, 0, 1: unresolved, no, yes
8580 unsigned int has_ret64:1;
8581 unsigned int dep_resolved:1;
8582 unsigned int is_stdcall:1;
8583 unsigned int eax_pass:1; // returns without touching eax
8584 unsigned int ptr_taken:1; // pointer taken of this func
8585 struct func_proto_dep *dep_func;
8587 const struct parsed_proto *pp; // seed pp, if any
8590 struct func_proto_dep {
8592 struct func_prototype *proto;
8593 int regmask_live; // .. at the time of call
8594 unsigned int ret_dep:1; // return from this is caller's return
8595 unsigned int has_ret:1; // found from eax use after return
8596 unsigned int has_ret64:1;
8597 unsigned int ptr_taken:1; // pointer taken, not a call
8600 static struct func_prototype *hg_fp;
8601 static int hg_fp_cnt;
8603 static struct scanned_var {
8605 enum opr_lenmod lmod;
8606 unsigned int is_seeded:1;
8607 unsigned int is_c_str:1;
8608 const struct parsed_proto *pp; // seed pp, if any
8610 static int hg_var_cnt;
8612 static char **hg_refs;
8613 static int hg_ref_cnt;
8615 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8618 static struct func_prototype *hg_fp_add(const char *funcn)
8620 struct func_prototype *fp;
8622 if ((hg_fp_cnt & 0xff) == 0) {
8623 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
8624 my_assert_not(hg_fp, NULL);
8625 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
8628 fp = &hg_fp[hg_fp_cnt];
8629 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
8631 fp->argc_stack = -1;
8637 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
8642 for (i = 0; i < fp->dep_func_cnt; i++)
8643 if (IS(fp->dep_func[i].name, name))
8644 return &fp->dep_func[i];
8649 static void hg_fp_add_dep(struct func_prototype *fp, const char *name,
8650 unsigned int ptr_taken)
8652 struct func_proto_dep * dep;
8655 dep = hg_fp_find_dep(fp, name);
8656 if (dep != NULL && dep->ptr_taken == ptr_taken)
8659 if ((fp->dep_func_cnt & 0xff) == 0) {
8660 fp->dep_func = realloc(fp->dep_func,
8661 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
8662 my_assert_not(fp->dep_func, NULL);
8663 memset(&fp->dep_func[fp->dep_func_cnt], 0,
8664 sizeof(fp->dep_func[0]) * 0x100);
8666 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
8667 fp->dep_func[fp->dep_func_cnt].ptr_taken = ptr_taken;
8671 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
8673 const struct func_prototype *p1 = p1_, *p2 = p2_;
8674 return strcmp(p1->name, p2->name);
8678 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
8680 const struct func_prototype *p1 = p1_, *p2 = p2_;
8681 return p1->id - p2->id;
8685 static void hg_ref_add(const char *name)
8687 if ((hg_ref_cnt & 0xff) == 0) {
8688 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8689 my_assert_not(hg_refs, NULL);
8690 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8693 hg_refs[hg_ref_cnt] = strdup(name);
8694 my_assert_not(hg_refs[hg_ref_cnt], NULL);
8698 // recursive register dep pass
8699 // - track saved regs (part 2)
8700 // - try to figure out arg-regs
8701 // - calculate reg deps
8702 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8703 struct func_prototype *fp, int regmask_save, int regmask_dst,
8704 int *regmask_dep, int *regmask_use, int *has_ret)
8706 struct func_proto_dep *dep;
8707 struct parsed_op *po;
8708 int from_caller = 0;
8713 for (; i < opcnt; i++)
8715 if (cbits[i >> 3] & (1 << (i & 7)))
8717 cbits[i >> 3] |= (1 << (i & 7));
8721 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8722 if (po->flags & OPF_RMD)
8725 if (po->btj != NULL) {
8727 for (j = 0; j < po->btj->count; j++) {
8728 check_i(po, po->btj->d[j].bt_i);
8729 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8730 regmask_save, regmask_dst, regmask_dep, regmask_use,
8736 check_i(po, po->bt_i);
8737 if (po->flags & OPF_CJMP) {
8738 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8739 regmask_save, regmask_dst, regmask_dep, regmask_use,
8748 if (po->flags & OPF_FARG)
8749 /* (just calculate register deps) */;
8750 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8752 reg = po->operand[0].reg;
8753 ferr_assert(po, reg >= 0);
8755 if (po->flags & OPF_RSAVE) {
8756 regmask_save |= 1 << reg;
8759 if (po->flags & OPF_DONE)
8762 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2,
8765 regmask_save |= 1 << reg;
8766 po->flags |= OPF_RMD;
8767 scan_for_pop(i + 1, opcnt, i + opcnt * 3,
8768 reg, 0, 0, 0, OPF_RMD);
8772 else if (po->flags & OPF_RMD)
8774 else if (po->op == OP_CALL) {
8775 po->regmask_dst |= 1 << xAX;
8777 dep = hg_fp_find_dep(fp, po->operand[0].name);
8779 dep->regmask_live = regmask_save | regmask_dst;
8780 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8781 dep->regmask_live |= 1 << xBP;
8783 if ((po->flags & OPF_TAIL) && po->pp != NULL
8784 && po->pp->is_stdcall)
8787 else if (po->op == OP_RET) {
8788 if (po->operand_cnt > 0) {
8790 if (fp->argc_stack >= 0
8791 && fp->argc_stack != po->operand[0].val / 4)
8792 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8793 fp->argc_stack = po->operand[0].val / 4;
8797 if (!fp->eax_pass && (po->flags & OPF_TAIL)) {
8798 if (po->op == OP_CALL) {
8805 ret = resolve_origin_reg(i, xAX, i + opcnt * 4, &j, &from_caller);
8808 if (ret != 1 && from_caller) {
8809 // unresolved eax - probably void func
8814 if (j >= 0 && ops[j].op == OP_CALL) {
8815 if (ops[j].pp != NULL && !ops[j].pp->is_unresolved) {
8816 int call_has_ret = !IS(ops[j].pp->ret_type.name, "void");
8817 if (ops[j].pp->is_noreturn) {
8818 // could be some fail path
8820 *has_ret = call_has_ret;
8823 *has_ret = call_has_ret;
8826 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8838 l = regmask_save | regmask_dst;
8839 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8842 l = po->regmask_src & ~l;
8845 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8846 l, regmask_dst, regmask_save, po->flags);
8849 *regmask_use |= (po->regmask_src | po->regmask_dst)
8851 regmask_dst |= po->regmask_dst;
8853 if (po->flags & OPF_TAIL) {
8854 if (!(po->flags & OPF_CC)) // not cond. tailcall
8860 static void gen_hdr(const char *funcn, int opcnt)
8862 unsigned char cbits[MAX_OPS / 8];
8863 const struct parsed_proto *pp_c;
8864 struct parsed_proto *pp;
8865 struct func_prototype *fp;
8866 struct func_proto_dep *dep;
8867 struct parsed_op *po;
8868 const char *tmpname;
8869 int regmask_dummy = 0;
8872 int max_bp_offset = 0;
8877 pp_c = proto_parse(g_fhdr, funcn, 1);
8879 // already in seed, will add to hg_fp later
8882 fp = hg_fp_add(funcn);
8884 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8885 g_stack_frame_used = 0;
8889 // - resolve all branches
8890 // - parse calls with labels
8891 resolve_branches_parse_calls(opcnt);
8894 // - handle ebp/esp frame, remove ops related to it
8895 scan_prologue_epilogue(opcnt, NULL);
8898 // - remove dead labels
8900 // - collect function ptr refs
8901 for (i = 0; i < opcnt; i++)
8903 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8909 if (po->flags & (OPF_RMD|OPF_DONE))
8912 if (po->op == OP_CALL) {
8913 if (po->operand[0].type == OPT_LABEL)
8914 hg_fp_add_dep(fp, opr_name(po, 0), 0);
8915 else if (po->pp != NULL)
8916 hg_fp_add_dep(fp, po->pp->name, 0);
8918 else if (po->op == OP_MOV && po->operand[1].type == OPT_OFFSET) {
8919 tmpname = opr_name(po, 1);
8920 if (IS_START(tmpname, "p_") || IS_START(tmpname, "sub_"))
8921 hg_fp_add_dep(fp, tmpname, 1);
8923 else if (po->op == OP_PUSH && po->operand[0].type == OPT_OFFSET) {
8924 tmpname = opr_name(po, 0);
8925 if (IS_START(tmpname, "p_") || IS_START(tmpname, "sub_"))
8926 hg_fp_add_dep(fp, tmpname, 1);
8931 // - handle push <const>/pop pairs
8932 for (i = 0; i < opcnt; i++)
8935 if (po->flags & (OPF_RMD|OPF_DONE))
8938 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8939 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8943 // - process trivial calls
8944 for (i = 0; i < opcnt; i++)
8947 if (po->flags & (OPF_RMD|OPF_DONE))
8950 if (po->op == OP_CALL)
8952 pp = process_call_early(i, opcnt, &j);
8954 if (!(po->flags & OPF_ATAIL))
8955 // since we know the args, try to collect them
8956 if (collect_call_args_early(i, opcnt, pp, NULL, NULL) != 0)
8962 // commit esp adjust
8963 if (ops[j].op != OP_POP)
8964 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8966 for (l = 0; l < pp->argc_stack; l++)
8967 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8971 po->flags |= OPF_DONE;
8977 // - track saved regs (simple)
8979 for (i = 0; i < opcnt; i++)
8982 if (po->flags & (OPF_RMD|OPF_DONE))
8985 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8986 && po->operand[0].reg != xCX)
8988 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8990 // regmask_save |= 1 << po->operand[0].reg; // do it later
8991 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8992 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8995 else if (po->op == OP_CALL)
8997 pp = process_call(i, opcnt);
8999 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
9000 // since we know the args, collect them
9001 ret = collect_call_args(po, i, opcnt, pp, ®mask_dummy,
9004 if (!(po->flags & OPF_TAIL)
9005 && po->operand[0].type == OPT_LABEL)
9007 dep = hg_fp_find_dep(fp, opr_name(po, 0));
9008 ferr_assert(po, dep != NULL);
9009 // treat al write as overwrite to avoid many false positives
9010 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
9011 i + opcnt * 25, &j);
9014 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
9015 i + opcnt * 26, &j);
9016 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j]))
9023 memset(cbits, 0, (opcnt + 7) / 8);
9024 regmask_dep = regmask_use = 0;
9027 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0,
9028 ®mask_dep, ®mask_use, &has_ret);
9030 // find unreachable code - must be fixed in IDA
9031 for (i = 0; i < opcnt; i++)
9033 if (cbits[i >> 3] & (1 << (i & 7)))
9036 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
9037 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
9039 // the compiler sometimes still generates code after
9040 // noreturn OS functions
9043 if (!(ops[i].flags & OPF_RMD)
9044 && ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
9046 ferr(&ops[i], "unreachable code\n");
9050 for (i = 0; i < g_eqcnt; i++) {
9051 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
9052 max_bp_offset = g_eqs[i].offset;
9055 if (fp->argc_stack < 0) {
9056 max_bp_offset = (max_bp_offset + 3) & ~3;
9057 fp->argc_stack = max_bp_offset / 4;
9058 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
9062 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
9063 fp->regmask_use = regmask_use;
9064 fp->has_ret = has_ret;
9066 printf("// has_ret %d, regmask_dep %x\n",
9067 fp->has_ret, fp->regmask_dep);
9068 output_hdr_fp(stdout, fp, 1);
9069 if (IS(funcn, "sub_10007F72")) exit(1);
9072 gen_x_cleanup(opcnt);
9075 static void hg_fp_resolve_deps(struct func_prototype *fp)
9077 struct func_prototype fp_s;
9078 struct func_proto_dep *dep;
9082 // this thing is recursive, so mark first..
9083 fp->dep_resolved = 1;
9085 for (i = 0; i < fp->dep_func_cnt; i++) {
9086 dep = &fp->dep_func[i];
9088 strcpy(fp_s.name, dep->name);
9089 dep->proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
9090 sizeof(hg_fp[0]), hg_fp_cmp_name);
9091 if (dep->proto != NULL) {
9092 if (dep->ptr_taken) {
9093 dep->proto->ptr_taken = 1;
9097 if (!dep->proto->dep_resolved)
9098 hg_fp_resolve_deps(dep->proto);
9100 regmask_dep = ~dep->regmask_live
9101 & dep->proto->regmask_dep;
9102 fp->regmask_dep |= regmask_dep;
9103 // printf("dep %s %s |= %x\n", fp->name,
9104 // fp->dep_func[i].name, regmask_dep);
9106 if (dep->has_ret && (dep->proto->regmask_use & mxAX))
9107 dep->proto->has_ret = 1;
9108 if (dep->has_ret64 && (dep->proto->regmask_use & mxDX))
9109 dep->proto->has_ret64 = 1;
9110 if (fp->has_ret == -1 && dep->ret_dep)
9111 fp->has_ret = dep->proto->has_ret;
9116 // make all thiscall/edx arg functions referenced from .data fastcall
9117 static void do_func_refs_from_data(void)
9119 struct func_prototype *fp, fp_s;
9122 for (i = 0; i < hg_ref_cnt; i++) {
9123 strcpy(fp_s.name, hg_refs[i]);
9124 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
9125 sizeof(hg_fp[0]), hg_fp_cmp_name);
9131 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
9134 const struct parsed_proto *pp;
9135 char *p, namebuf[NAMELEN];
9141 for (; count > 0; count--, fp++) {
9142 if (fp->has_ret == -1)
9143 fprintf(fout, "// ret unresolved\n");
9145 fprintf(fout, "// dep:");
9146 for (j = 0; j < fp->dep_func_cnt; j++) {
9147 fprintf(fout, " %s/", fp->dep_func[j].name);
9148 if (fp->dep_func[j].proto != NULL)
9149 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
9150 fp->dep_func[j].proto->has_ret);
9152 fprintf(fout, "\n");
9155 p = strchr(fp->name, '@');
9157 memcpy(namebuf, fp->name, p - fp->name);
9158 namebuf[p - fp->name] = 0;
9166 pp = proto_parse(g_fhdr, name, 1);
9167 if (pp != NULL && pp->is_include)
9170 if (fp->pp != NULL) {
9171 // part of seed, output later
9175 regmask_dep = fp->regmask_dep;
9176 argc_normal = fp->argc_stack;
9177 if (fp->ptr_taken && regmask_dep
9178 && (regmask_dep & ~(mxCX|mxDX)) == 0)
9180 if ((regmask_dep & mxDX) || fp->argc_stack > 0)
9181 regmask_dep |= mxCX | mxDX;
9184 fprintf(fout, "%-5s",
9185 fp->pp ? fp->pp->ret_type.name :
9186 fp->has_ret64 ? "__int64" :
9187 fp->has_ret ? "int" : "void");
9188 if (regmask_dep == mxCX && fp->is_stdcall && fp->argc_stack > 0) {
9189 fprintf(fout, "/*__thiscall*/ ");
9193 else if ((regmask_dep == (mxCX | mxDX)
9194 && (fp->is_stdcall || fp->argc_stack == 0))
9195 || (regmask_dep == mxCX && fp->argc_stack == 0))
9197 fprintf(fout, " __fastcall ");
9198 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
9204 else if (regmask_dep && !fp->is_stdcall) {
9205 fprintf(fout, "/*__usercall*/ ");
9207 else if (regmask_dep) {
9208 fprintf(fout, "/*__userpurge*/ ");
9210 else if (fp->is_stdcall)
9211 fprintf(fout, " __stdcall ");
9213 fprintf(fout, " __cdecl ");
9215 fprintf(fout, "%s(", name);
9218 for (j = 0; j < xSP; j++) {
9219 if (regmask_dep & (1 << j)) {
9222 fprintf(fout, ", ");
9224 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
9226 fprintf(fout, "int");
9227 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
9231 for (j = 0; j < argc_normal; j++) {
9234 fprintf(fout, ", ");
9235 if (fp->pp != NULL) {
9236 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
9237 if (!fp->pp->arg[arg - 1].type.is_ptr)
9241 fprintf(fout, "int ");
9242 fprintf(fout, "a%d", arg);
9245 fprintf(fout, ");\n");
9249 static void output_hdr(FILE *fout)
9251 static const char *lmod_c_names[] = {
9252 [OPLM_UNSPEC] = "???",
9253 [OPLM_BYTE] = "uint8_t",
9254 [OPLM_WORD] = "uint16_t",
9255 [OPLM_DWORD] = "uint32_t",
9256 [OPLM_QWORD] = "uint64_t",
9258 const struct scanned_var *var;
9259 struct func_prototype *fp;
9260 char line[256] = { 0, };
9264 // add stuff from headers
9265 for (i = 0; i < pp_cache_size; i++) {
9266 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
9267 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
9269 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
9270 fp = hg_fp_add(name);
9271 fp->pp = &pp_cache[i];
9272 fp->argc_stack = fp->pp->argc_stack;
9273 fp->is_stdcall = fp->pp->is_stdcall;
9274 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
9275 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
9279 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
9280 for (i = 0; i < hg_fp_cnt; i++)
9281 hg_fp_resolve_deps(&hg_fp[i]);
9283 // adjust functions referenced from data segment
9284 do_func_refs_from_data();
9286 // final adjustments
9287 for (i = 0; i < hg_fp_cnt; i++) {
9288 if (hg_fp[i].eax_pass && (hg_fp[i].regmask_dep & mxAX))
9289 hg_fp[i].has_ret = 1;
9292 // note: messes up .proto ptr, don't use
9293 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
9296 for (i = 0; i < hg_var_cnt; i++) {
9299 if (var->pp != NULL)
9302 else if (var->is_c_str)
9303 fprintf(fout, "extern %-8s %s[];", "char", var->name);
9305 fprintf(fout, "extern %-8s %s;",
9306 lmod_c_names[var->lmod], var->name);
9309 fprintf(fout, " // seeded");
9310 fprintf(fout, "\n");
9313 fprintf(fout, "\n");
9315 // output function prototypes
9316 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
9319 fprintf(fout, "\n// - seed -\n");
9322 while (fgets(line, sizeof(line), g_fhdr))
9323 fwrite(line, 1, strlen(line), fout);
9326 // '=' needs special treatment
9328 static char *next_word_s(char *w, size_t wsize, char *s)
9335 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
9337 for (i = 1; i < wsize - 1; i++) {
9339 printf("warning: missing closing quote: \"%s\"\n", s);
9348 for (; i < wsize - 1; i++) {
9349 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
9355 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
9356 printf("warning: '%s' truncated\n", w);
9361 static int cmpstringp(const void *p1, const void *p2)
9363 return strcmp(*(char * const *)p1, *(char * const *)p2);
9366 static int is_xref_needed(char *p, char **rlist, int rlist_len)
9371 if (strstr(p, "..."))
9372 // unable to determine, assume needed
9375 if (*p == '.') // .text, .data, ...
9376 // ref from other data or non-function -> no
9379 p2 = strpbrk(p, "+:\r\n\x18");
9382 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9383 // referenced from removed code
9389 static int ida_xrefs_show_need(FILE *fasm, char *p,
9390 char **rlist, int rlist_len)
9396 p = strrchr(p, ';');
9397 if (p != NULL && *p == ';') {
9398 if (IS_START(p + 2, "sctref"))
9400 if (IS_START(p + 2, "DATA XREF: ")) {
9402 if (is_xref_needed(p, rlist, rlist_len))
9410 if (!my_fgets(line, sizeof(line), fasm))
9412 // non-first line is always indented
9413 if (!my_isblank(line[0]))
9416 // should be no content, just comment
9421 p = strrchr(p, ';');
9424 if (IS_START(p, "sctref")) {
9429 // it's printed once, but no harm to check again
9430 if (IS_START(p, "DATA XREF: "))
9433 if (is_xref_needed(p, rlist, rlist_len)) {
9438 fseek(fasm, pos, SEEK_SET);
9442 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
9444 struct scanned_var *var;
9445 char line[256] = { 0, };
9454 // skip to next data section
9455 while (my_fgets(line, sizeof(line), fasm))
9460 if (*p == 0 || *p == ';')
9463 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
9464 if (*p == 0 || *p == ';')
9467 if (*p != 's' || !IS_START(p, "segment para public"))
9473 if (p == NULL || !IS_START(p, "segment para public"))
9477 if (!IS_START(p, "'DATA'"))
9481 while (my_fgets(line, sizeof(line), fasm))
9486 no_identifier = my_isblank(*p);
9489 if (*p == 0 || *p == ';')
9492 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9493 words[wordc][0] = 0;
9494 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9495 if (*p == 0 || *p == ';') {
9501 if (wordc == 2 && IS(words[1], "ends"))
9506 if (no_identifier) {
9507 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
9508 hg_ref_add(words[2]);
9512 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
9513 // when this starts, we don't need anything from this section
9517 // check refs comment(s)
9518 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
9521 if ((hg_var_cnt & 0xff) == 0) {
9522 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
9523 * (hg_var_cnt + 0x100));
9524 my_assert_not(hg_vars, NULL);
9525 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
9528 var = &hg_vars[hg_var_cnt++];
9529 snprintf(var->name, sizeof(var->name), "%s", words[0]);
9531 // maybe already in seed header?
9532 var->pp = proto_parse(g_fhdr, var->name, 1);
9533 if (var->pp != NULL) {
9534 if (var->pp->is_fptr) {
9535 var->lmod = OPLM_DWORD;
9538 else if (var->pp->is_func)
9540 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
9541 aerr("unhandled C type '%s' for '%s'\n",
9542 var->pp->type.name, var->name);
9548 if (IS(words[1], "dd")) {
9549 var->lmod = OPLM_DWORD;
9550 if (wordc >= 4 && IS(words[2], "offset"))
9551 hg_ref_add(words[3]);
9553 else if (IS(words[1], "dw"))
9554 var->lmod = OPLM_WORD;
9555 else if (IS(words[1], "db")) {
9556 var->lmod = OPLM_BYTE;
9557 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
9558 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
9562 else if (IS(words[1], "dq"))
9563 var->lmod = OPLM_QWORD;
9564 //else if (IS(words[1], "dt"))
9566 aerr("type '%s' not known\n", words[1]);
9574 static void set_label(int i, const char *name)
9580 p = strchr(name, ':');
9584 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
9585 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
9586 g_labels[i] = realloc(g_labels[i], len + 1);
9587 my_assert_not(g_labels[i], NULL);
9588 memcpy(g_labels[i], name, len);
9589 g_labels[i][len] = 0;
9598 static struct chunk_item *func_chunks;
9599 static int func_chunk_cnt;
9600 static int func_chunk_alloc;
9602 static void add_func_chunk(FILE *fasm, const char *name, int line)
9604 if (func_chunk_cnt >= func_chunk_alloc) {
9605 func_chunk_alloc *= 2;
9606 func_chunks = realloc(func_chunks,
9607 func_chunk_alloc * sizeof(func_chunks[0]));
9608 my_assert_not(func_chunks, NULL);
9610 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
9611 func_chunks[func_chunk_cnt].name = strdup(name);
9612 func_chunks[func_chunk_cnt].asmln = line;
9616 static int cmp_chunks(const void *p1, const void *p2)
9618 const struct chunk_item *c1 = p1, *c2 = p2;
9619 return strcmp(c1->name, c2->name);
9622 static void scan_ahead_for_chunks(FILE *fasm)
9632 oldpos = ftell(fasm);
9635 while (my_fgets(line, sizeof(line), fasm))
9646 // get rid of random tabs
9647 for (i = 0; line[i] != 0; i++)
9648 if (line[i] == '\t')
9651 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9654 next_word(words[0], sizeof(words[0]), p);
9655 if (words[0][0] == 0)
9656 aerr("missing name for func chunk?\n");
9658 add_func_chunk(fasm, words[0], asmln);
9660 else if (IS_START(p, "; sctend"))
9666 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9667 words[wordc][0] = 0;
9668 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9669 if (*p == 0 || *p == ';') {
9675 if (wordc == 2 && IS(words[1], "ends"))
9679 fseek(fasm, oldpos, SEEK_SET);
9683 int main(int argc, char *argv[])
9685 FILE *fout, *fasm, *frlist;
9686 struct parsed_data *pd = NULL;
9688 char **rlist = NULL;
9690 int rlist_alloc = 0;
9691 int func_chunks_used = 0;
9692 int func_chunks_sorted = 0;
9693 int func_chunk_i = -1;
9694 long func_chunk_ret = 0;
9695 int func_chunk_ret_ln = 0;
9696 int scanned_ahead = 0;
9698 char words[20][256];
9699 enum opr_lenmod lmod;
9700 char *sctproto = NULL;
9702 int pending_endp = 0;
9704 int skip_code_end = 0;
9705 int skip_warned = 0;
9718 for (arg = 1; arg < argc; arg++) {
9719 if (IS(argv[arg], "-v"))
9721 else if (IS(argv[arg], "-rf"))
9722 g_allow_regfunc = 1;
9723 else if (IS(argv[arg], "-uc"))
9724 g_allow_user_icall = 1;
9725 else if (IS(argv[arg], "-wu"))
9726 g_nowarn_reguse = 1;
9727 else if (IS(argv[arg], "-m"))
9729 else if (IS(argv[arg], "-hdr"))
9730 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
9735 if (argc < arg + 3) {
9736 printf("usage:\n%s [options] <.c> <.asm> <hdr.h> [rlist]*\n"
9737 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
9739 " -hdr - header generation mode\n"
9740 " -rf - allow unannotated indirect calls\n"
9741 " -uc - allow ind. calls/refs to __usercall\n"
9742 " -m - allow multiple .text sections\n"
9743 " -wu - don't warn about bad reg use\n"
9744 "[rlist] is a file with function names to skip,"
9752 asmfn = argv[arg++];
9753 fasm = fopen(asmfn, "r");
9754 my_assert_not(fasm, NULL);
9756 hdrfn = argv[arg++];
9757 g_fhdr = fopen(hdrfn, "r");
9758 my_assert_not(g_fhdr, NULL);
9761 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9762 my_assert_not(rlist, NULL);
9763 // needs special handling..
9764 rlist[rlist_len++] = "__alloca_probe";
9766 func_chunk_alloc = 32;
9767 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9768 my_assert_not(func_chunks, NULL);
9770 memset(words, 0, sizeof(words));
9772 for (; arg < argc; arg++) {
9775 frlist = fopen(argv[arg], "r");
9776 my_assert_not(frlist, NULL);
9778 while (my_fgets(line, sizeof(line), frlist)) {
9780 if (*p == 0 || *p == ';')
9783 if (IS_START(p, "#if 0")
9784 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9788 else if (IS_START(p, "#endif"))
9795 p = next_word(words[0], sizeof(words[0]), p);
9796 if (words[0][0] == 0)
9799 if (rlist_len >= rlist_alloc) {
9800 rlist_alloc = rlist_alloc * 2 + 64;
9801 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9802 my_assert_not(rlist, NULL);
9804 rlist[rlist_len++] = strdup(words[0]);
9812 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9814 fout = fopen(argv[arg_out], "w");
9815 my_assert_not(fout, NULL);
9818 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9819 my_assert_not(g_eqs, NULL);
9821 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9822 g_label_refs[i].i = -1;
9823 g_label_refs[i].next = NULL;
9827 scan_variables(fasm, rlist, rlist_len);
9829 while (my_fgets(line, sizeof(line), fasm))
9838 // get rid of random tabs
9839 for (i = 0; line[i] != 0; i++)
9840 if (line[i] == '\t')
9845 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9846 goto do_pending_endp; // eww..
9848 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9850 static const char *attrs[] = {
9859 // parse IDA's attribute-list comment
9860 g_ida_func_attr = 0;
9863 for (; *p != 0; p = sskip(p)) {
9864 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9865 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9866 g_ida_func_attr |= 1 << i;
9867 p += strlen(attrs[i]);
9871 if (i == ARRAY_SIZE(attrs)) {
9872 anote("unparsed IDA attr: %s\n", p);
9875 if (IS(attrs[i], "fpd=")) {
9876 p = next_word(words[0], sizeof(words[0]), p);
9881 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9883 static const char *attrs[] = {
9892 // parse manual attribute-list comment
9893 g_sct_func_attr = 0;
9896 for (; *p != 0; p = sskip(p)) {
9897 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9898 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9899 g_sct_func_attr |= 1 << i;
9900 p += strlen(attrs[i]);
9907 // clear_sf=start,len (in dwords)
9908 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9909 &g_stack_clear_len, &j);
9911 // clear_regmask=<mask>
9912 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9914 // rm_regmask=<mask>
9915 ret = sscanf(p, "=%x%n", &g_regmask_rm, &j) + 1;
9917 anote("unparsed attr value: %s\n", p);
9922 else if (i == ARRAY_SIZE(attrs)) {
9923 anote("unparsed sct attr: %s\n", p);
9928 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9931 next_word(words[0], sizeof(words[0]), p);
9932 if (words[0][0] == 0)
9933 aerr("missing name for func chunk?\n");
9935 if (!scanned_ahead) {
9936 add_func_chunk(fasm, words[0], asmln);
9937 func_chunks_sorted = 0;
9940 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9942 if (func_chunk_i >= 0) {
9943 if (func_chunk_i < func_chunk_cnt
9944 && IS(func_chunks[func_chunk_i].name, g_func))
9946 // move on to next chunk
9947 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9949 aerr("seek failed for '%s' chunk #%d\n",
9950 g_func, func_chunk_i);
9951 asmln = func_chunks[func_chunk_i].asmln;
9955 if (func_chunk_ret == 0)
9956 aerr("no return from chunk?\n");
9957 fseek(fasm, func_chunk_ret, SEEK_SET);
9958 asmln = func_chunk_ret_ln;
9964 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9965 func_chunks_used = 1;
9967 if (IS_START(g_func, "sub_")) {
9968 unsigned long addr = strtoul(p, NULL, 16);
9969 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9970 if (addr > f_addr && !scanned_ahead) {
9971 //anote("scan_ahead caused by '%s', addr %lx\n",
9973 scan_ahead_for_chunks(fasm);
9975 func_chunks_sorted = 0;
9983 for (i = wordc; i < ARRAY_SIZE(words); i++)
9985 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9986 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9987 if (*p == 0 || *p == ';') {
9992 if (*p != 0 && *p != ';')
9993 aerr("too many words\n");
9995 if (skip_code_end) {
10000 // allow asm patches in comments
10002 // skip IDA's forced non-removable comment
10003 if (!IS_START(p, "; sct") && (p2 = strchr(p + 1, ';')))
10006 if (*p == ';' && IS_START(p, "; sct")) {
10007 if (IS_START(p, "; sctpatch:")) {
10009 if (*p == 0 || *p == ';')
10011 goto parse_words; // lame
10013 else if (IS_START(p, "; sctend")) {
10018 else if (g_skip_func)
10019 /* ignore remaining attrs */;
10020 else if (IS_START(p, "; sctproto:")) {
10021 sctproto = strdup(p + 11);
10023 else if (IS_START(p, "; sctskip_start")) {
10026 ops[pi].op = OPP_ABORT;
10027 ops[pi].asmln = asmln;
10033 else if (IS_START(p, "; sctskip_end")) {
10040 // shouldn't happen
10041 awarn("wordc == 0?\n");
10045 // don't care about this:
10046 if (words[0][0] == '.'
10047 || IS(words[0], "include")
10048 || IS(words[0], "assume") || IS(words[1], "segment")
10049 || IS(words[0], "align"))
10055 // do delayed endp processing to collect switch jumptables
10056 if (pending_endp) {
10057 if (in_func && !g_skip_func && !end && wordc >= 2
10058 && ((words[0][0] == 'd' && words[0][2] == 0)
10059 || (words[1][0] == 'd' && words[1][2] == 0)))
10062 if (words[1][0] == 'd' && words[1][2] == 0) {
10064 if (g_func_pd_cnt >= pd_alloc) {
10065 pd_alloc = pd_alloc * 2 + 16;
10066 g_func_pd = realloc(g_func_pd,
10067 sizeof(g_func_pd[0]) * pd_alloc);
10068 my_assert_not(g_func_pd, NULL);
10070 pd = &g_func_pd[g_func_pd_cnt];
10072 memset(pd, 0, sizeof(*pd));
10073 strcpy(pd->label, words[0]);
10074 pd->type = OPT_CONST;
10075 pd->lmod = lmod_from_directive(words[1]);
10081 anote("skipping alignment byte?\n");
10084 lmod = lmod_from_directive(words[0]);
10085 if (lmod != pd->lmod)
10086 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
10089 if (pd->count_alloc < pd->count + wordc) {
10090 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
10091 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
10092 my_assert_not(pd->d, NULL);
10094 for (; i < wordc; i++) {
10095 if (IS(words[i], "offset")) {
10096 pd->type = OPT_OFFSET;
10099 p = strchr(words[i], ',');
10102 if (pd->type == OPT_OFFSET)
10103 pd->d[pd->count].u.label = strdup(words[i]);
10105 pd->d[pd->count].u.val = parse_number(words[i], 0);
10106 pd->d[pd->count].bt_i = -1;
10112 if (in_func && !g_skip_func) {
10114 gen_hdr(g_func, pi);
10116 gen_func(fout, g_fhdr, g_func, pi);
10121 g_ida_func_attr = 0;
10122 g_sct_func_attr = 0;
10123 g_stack_clear_start = 0;
10124 g_stack_clear_len = 0;
10125 g_regmask_init = 0;
10131 func_chunks_used = 0;
10134 memset(&ops, 0, pi * sizeof(ops[0]));
10139 for (i = 0; i < g_func_pd_cnt; i++) {
10140 pd = &g_func_pd[i];
10141 if (pd->type == OPT_OFFSET) {
10142 for (j = 0; j < pd->count; j++)
10143 free(pd->d[j].u.label);
10158 if (IS(words[1], "proc")) {
10160 aerr("proc '%s' while in_func '%s'?\n",
10163 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
10165 strcpy(g_func, words[0]);
10166 set_label(0, words[0]);
10171 if (IS(words[1], "endp"))
10174 aerr("endp '%s' while not in_func?\n", words[0]);
10175 if (!IS(g_func, words[0]))
10176 aerr("endp '%s' while in_func '%s'?\n",
10179 aerr("endp '%s' while skipping code\n", words[0]);
10181 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
10182 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
10188 if (!g_skip_func && func_chunks_used) {
10189 // start processing chunks
10190 struct chunk_item *ci, key = { g_func, 0 };
10192 func_chunk_ret = ftell(fasm);
10193 func_chunk_ret_ln = asmln;
10194 if (!func_chunks_sorted) {
10195 qsort(func_chunks, func_chunk_cnt,
10196 sizeof(func_chunks[0]), cmp_chunks);
10197 func_chunks_sorted = 1;
10199 ci = bsearch(&key, func_chunks, func_chunk_cnt,
10200 sizeof(func_chunks[0]), cmp_chunks);
10202 aerr("'%s' needs chunks, but none found\n", g_func);
10203 func_chunk_i = ci - func_chunks;
10204 for (; func_chunk_i > 0; func_chunk_i--)
10205 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
10208 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
10210 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
10211 asmln = func_chunks[func_chunk_i].asmln;
10219 if (wordc == 2 && IS(words[1], "ends")) {
10223 goto do_pending_endp;
10227 // scan for next text segment
10228 while (my_fgets(line, sizeof(line), fasm)) {
10231 if (*p == 0 || *p == ';')
10234 if (strstr(p, "segment para public 'CODE' use32"))
10241 p = strchr(words[0], ':');
10243 set_label(pi, words[0]);
10247 if (!in_func || g_skip_func || skip_code) {
10248 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
10250 anote("skipping from '%s'\n", g_labels[pi]);
10253 free(g_labels[pi]);
10254 g_labels[pi] = NULL;
10258 if (wordc > 1 && IS(words[1], "="))
10261 aerr("unhandled equ, wc=%d\n", wordc);
10262 if (g_eqcnt >= eq_alloc) {
10264 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
10265 my_assert_not(g_eqs, NULL);
10268 len = strlen(words[0]);
10269 if (len > sizeof(g_eqs[0].name) - 1)
10270 aerr("equ name too long: %d\n", len);
10271 strcpy(g_eqs[g_eqcnt].name, words[0]);
10273 if (!IS(words[3], "ptr"))
10274 aerr("unhandled equ\n");
10275 if (IS(words[2], "dword"))
10276 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
10277 else if (IS(words[2], "word"))
10278 g_eqs[g_eqcnt].lmod = OPLM_WORD;
10279 else if (IS(words[2], "byte"))
10280 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
10281 else if (IS(words[2], "qword"))
10282 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
10284 aerr("bad lmod: '%s'\n", words[2]);
10286 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
10291 if (pi >= ARRAY_SIZE(ops))
10292 aerr("too many ops\n");
10294 parse_op(&ops[pi], words, wordc);
10296 ops[pi].datap = sctproto;
10311 // vim:ts=2:shiftwidth=2:expandtab