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
314 #define MAX_ARG_GRP 2
316 static struct parsed_op ops[MAX_OPS];
317 static struct parsed_equ *g_eqs;
319 static char *g_labels[MAX_OPS];
320 static struct label_ref g_label_refs[MAX_OPS];
321 static const struct parsed_proto *g_func_pp;
322 static struct parsed_data *g_func_pd;
323 static int g_func_pd_cnt;
324 static int g_func_lmods;
325 static char g_func[256];
326 static char g_comment[256];
327 static int g_bp_frame;
328 static int g_sp_frame;
329 static int g_stack_frame_used;
330 static int g_stack_fsz;
331 static int g_seh_found;
332 static int g_seh_size;
333 static int g_ida_func_attr;
334 static int g_sct_func_attr;
335 static int g_stack_clear_start; // in dwords
336 static int g_stack_clear_len;
337 static int g_regmask_init;
338 static int g_regmask_rm;
339 static int g_skip_func;
340 static int g_allow_regfunc;
341 static int g_allow_user_icall;
342 static int g_nowarn_reguse;
343 static int g_quiet_pp;
344 static int g_header_mode;
346 #define ferr(op_, fmt, ...) do { \
347 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
348 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
352 #define fnote(op_, fmt, ...) \
353 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
354 dump_op(op_), ##__VA_ARGS__)
356 #define ferr_assert(op_, cond) do { \
357 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
360 #define IS_OP_INDIRECT_CALL(op_) \
361 ((op_)->op == OP_CALL && (op_)->operand[0].type != OPT_LABEL)
363 const char *regs_r32[] = {
364 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
365 // not r32, but list here for easy parsing and printing
366 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
367 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
369 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
370 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
371 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
377 xMM0, xMM1, xMM2, xMM3, // mmx
378 xMM4, xMM5, xMM6, xMM7,
379 xST0, xST1, xST2, xST3, // x87
380 xST4, xST5, xST6, xST7,
383 #define mxAX (1 << xAX)
384 #define mxBX (1 << xBX)
385 #define mxCX (1 << xCX)
386 #define mxDX (1 << xDX)
387 #define mxSP (1 << xSP)
388 #define mxST0 (1 << xST0)
389 #define mxST1 (1 << xST1)
390 #define mxST1_0 (mxST1 | mxST0)
391 #define mxST7_2 (0xfc << xST0)
392 #define mxSTa (0xff << xST0)
394 // possible basic comparison types (without inversion)
395 enum parsed_flag_op {
399 PFO_BE, // 6 CF=1||ZF=1
403 PFO_LE, // e ZF=1||SF!=OF
406 #define PFOB_O (1 << PFO_O)
407 #define PFOB_C (1 << PFO_C)
408 #define PFOB_Z (1 << PFO_Z)
409 #define PFOB_S (1 << PFO_S)
411 static const char *parsed_flag_op_names[] = {
412 "o", "c", "z", "be", "s", "p", "l", "le"
415 static int char_array_i(const char *array[], size_t len, const char *s)
419 for (i = 0; i < len; i++)
426 static void printf_number(char *buf, size_t buf_size,
427 unsigned long number)
429 // output in C-friendly form
430 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
433 static int check_segment_prefix(const char *s)
435 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
439 case 'c': return SEG_CS;
440 case 'd': return SEG_DS;
441 case 's': return SEG_SS;
442 case 'e': return SEG_ES;
443 case 'f': return SEG_FS;
444 case 'g': return SEG_GS;
449 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
453 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
455 *reg_lmod = OPLM_QWORD;
459 *reg_lmod = OPLM_DWORD;
462 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
464 *reg_lmod = OPLM_WORD;
467 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
469 *reg_lmod = OPLM_BYTE;
472 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
474 *reg_lmod = OPLM_BYTE;
481 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
483 enum opr_lenmod lmod;
496 while (my_isblank(*s))
498 for (; my_issep(*s); d++, s++)
500 while (my_isblank(*s))
504 // skip '?s:' prefixes
505 if (check_segment_prefix(s))
508 s = next_idt(w, sizeof(w), s);
513 reg = parse_reg(&lmod, w);
515 *regmask |= 1 << reg;
519 if ('0' <= w[0] && w[0] <= '9') {
520 number = parse_number(w, 0);
521 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
525 // probably some label/identifier - pass
528 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
532 strcpy(name, cvtbuf);
537 static int is_reg_in_str(const char *s)
541 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
544 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
545 if (!strncmp(s, regs_r32[i], 3))
551 static const char *parse_stack_el(const char *name, char *extra_reg,
552 int *base_val, int early_try)
554 const char *p, *p2, *s;
560 if (g_bp_frame || early_try)
563 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
565 if (extra_reg != NULL) {
566 strncpy(extra_reg, name, 3);
571 if (IS_START(p, "ebp+")) {
575 if (p2 != NULL && is_reg_in_str(p)) {
576 if (extra_reg != NULL) {
577 strncpy(extra_reg, p, p2 - p);
578 extra_reg[p2 - p] = 0;
583 if (!('0' <= *p && *p <= '9'))
590 if (!IS_START(name, "esp+"))
596 if (is_reg_in_str(s)) {
597 if (extra_reg != NULL) {
598 strncpy(extra_reg, s, p - s);
599 extra_reg[p - s] = 0;
604 aerr("%s IDA stackvar not set?\n", __func__);
606 if ('0' <= *s && *s <= '9') {
607 if (s[0] == '0' && s[1] == 'x')
610 if (len < sizeof(buf) - 1) {
611 strncpy(buf, s, len);
614 val = strtol(buf, &endp, 16);
615 if (val == 0 || *endp != 0 || errno != 0) {
616 aerr("%s num parse fail for '%s'\n", __func__, buf);
623 // probably something like [esp+arg_4+2]
631 if ('0' <= *p && *p <= '9')
634 if (base_val != NULL)
639 static int guess_lmod_from_name(struct parsed_opr *opr)
641 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
642 opr->lmod = OPLM_DWORD;
645 if (IS_START(opr->name, "word_")) {
646 opr->lmod = OPLM_WORD;
649 if (IS_START(opr->name, "byte_")) {
650 opr->lmod = OPLM_BYTE;
653 if (IS_START(opr->name, "qword_")) {
654 opr->lmod = OPLM_QWORD;
660 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
661 const struct parsed_type *c_type)
663 static const char *qword_types[] = {
664 "uint64_t", "int64_t", "__int64",
666 static const char *dword_types[] = {
667 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
668 "WPARAM", "LPARAM", "UINT", "__int32",
669 "LONG", "HIMC", "BOOL", "size_t",
672 static const char *word_types[] = {
673 "uint16_t", "int16_t", "_WORD", "WORD",
674 "unsigned __int16", "__int16",
676 static const char *byte_types[] = {
677 "uint8_t", "int8_t", "char",
678 "unsigned __int8", "__int8", "BYTE", "_BYTE",
680 // structures.. deal the same as with _UNKNOWN for now
686 if (c_type->is_ptr) {
691 n = skip_type_mod(c_type->name);
693 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
694 if (IS(n, dword_types[i])) {
700 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
701 if (IS(n, word_types[i])) {
707 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
708 if (IS(n, byte_types[i])) {
714 for (i = 0; i < ARRAY_SIZE(qword_types); i++) {
715 if (IS(n, qword_types[i])) {
724 static char *default_cast_to(char *buf, size_t buf_size,
725 struct parsed_opr *opr)
729 if (!opr->is_ptr || strchr(opr->name, '['))
731 if (opr->pp == NULL || opr->pp->type.name == NULL
734 snprintf(buf, buf_size, "%s", "(void *)");
738 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
742 static enum opr_type lmod_from_directive(const char *d)
746 else if (IS(d, "dw"))
748 else if (IS(d, "db"))
751 aerr("unhandled directive: '%s'\n", d);
755 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
761 *regmask |= 1 << reg;
764 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
767 static int parse_operand(struct parsed_opr *opr,
768 int *regmask, int *regmask_indirect,
769 char words[16][256], int wordc, int w, unsigned int op_flags)
771 const struct parsed_proto *pp = NULL;
772 enum opr_lenmod tmplmod;
773 unsigned long number;
781 aerr("parse_operand w %d, wordc %d\n", w, wordc);
785 for (i = w; i < wordc; i++) {
786 len = strlen(words[i]);
787 if (words[i][len - 1] == ',') {
788 words[i][len - 1] = 0;
794 wordc_in = wordc - w;
796 if ((op_flags & OPF_JMP) && wordc_in > 0
797 && !('0' <= words[w][0] && words[w][0] <= '9'))
799 const char *label = NULL;
801 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
802 && IS(words[w + 1], "ptr"))
803 label = words[w + 2];
804 else if (wordc_in == 2 && IS(words[w], "short"))
805 label = words[w + 1];
806 else if (wordc_in == 1
807 && strchr(words[w], '[') == NULL
808 && parse_reg(&tmplmod, words[w]) < 0)
812 opr->type = OPT_LABEL;
813 ret = check_segment_prefix(label);
818 strcpy(opr->name, label);
824 if (IS(words[w + 1], "ptr")) {
825 if (IS(words[w], "dword"))
826 opr->lmod = OPLM_DWORD;
827 else if (IS(words[w], "word"))
828 opr->lmod = OPLM_WORD;
829 else if (IS(words[w], "byte"))
830 opr->lmod = OPLM_BYTE;
831 else if (IS(words[w], "qword"))
832 opr->lmod = OPLM_QWORD;
834 aerr("type parsing failed\n");
836 wordc_in = wordc - w;
841 if (IS(words[w], "offset")) {
842 opr->type = OPT_OFFSET;
843 opr->lmod = OPLM_DWORD;
844 strcpy(opr->name, words[w + 1]);
845 pp = proto_parse(g_fhdr, opr->name, 1);
848 if (IS(words[w], "(offset")) {
849 p = strchr(words[w + 1], ')');
851 aerr("parse of bracketed offset failed\n");
853 opr->type = OPT_OFFSET;
854 strcpy(opr->name, words[w + 1]);
860 aerr("parse_operand 1 word expected\n");
862 ret = check_segment_prefix(words[w]);
865 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
866 if (ret == SEG_FS && IS(words[w], "0"))
869 strcpy(opr->name, words[w]);
871 if (words[w][0] == '[') {
872 opr->type = OPT_REGMEM;
873 ret = sscanf(words[w], "[%[^]]]", opr->name);
875 aerr("[] parse failure\n");
877 parse_indmode(opr->name, regmask_indirect, 1);
878 if (opr->lmod == OPLM_UNSPEC
879 && parse_stack_el(opr->name, NULL, NULL, 1))
882 struct parsed_equ *eq =
883 equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
885 opr->lmod = eq->lmod;
887 // might be unaligned access
888 g_func_lmods |= 1 << OPLM_BYTE;
892 else if (strchr(words[w], '[')) {
894 p = strchr(words[w], '[');
895 opr->type = OPT_REGMEM;
896 parse_indmode(p, regmask_indirect, 0);
897 strncpy(buf, words[w], p - words[w]);
898 buf[p - words[w]] = 0;
899 pp = proto_parse(g_fhdr, buf, 1);
902 else if (('0' <= words[w][0] && words[w][0] <= '9')
903 || words[w][0] == '-')
905 number = parse_number(words[w], 0);
906 opr->type = OPT_CONST;
908 printf_number(opr->name, sizeof(opr->name), number);
912 ret = parse_reg(&tmplmod, opr->name);
914 setup_reg_opr(opr, ret, tmplmod, regmask);
918 // most likely var in data segment
919 opr->type = OPT_LABEL;
920 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
924 if (pp->is_fptr || pp->is_func) {
925 opr->lmod = OPLM_DWORD;
929 tmplmod = OPLM_UNSPEC;
930 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
931 anote("unhandled C type '%s' for '%s'\n",
932 pp->type.name, opr->name);
934 if (opr->lmod == OPLM_UNSPEC) {
936 opr->type_from_var = 1;
938 else if (opr->lmod != tmplmod) {
939 opr->size_mismatch = 1;
940 if (tmplmod < opr->lmod)
943 opr->is_ptr = pp->type.is_ptr;
945 opr->is_array = pp->type.is_array;
949 if (opr->lmod == OPLM_UNSPEC)
950 guess_lmod_from_name(opr);
954 static const struct {
959 { "repe", OPF_REP|OPF_REPZ },
960 { "repz", OPF_REP|OPF_REPZ },
961 { "repne", OPF_REP|OPF_REPNZ },
962 { "repnz", OPF_REP|OPF_REPNZ },
963 { "lock", OPF_LOCK },
966 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
968 static const struct {
971 unsigned short minopr;
972 unsigned short maxopr;
975 unsigned char pfo_inv;
977 { "nop", OP_NOP, 0, 0, 0 },
978 { "push", OP_PUSH, 1, 1, 0 },
979 { "pop", OP_POP, 1, 1, OPF_DATA },
980 { "pusha",OP_PUSHA, 0, 0, 0 },
981 { "popa", OP_POPA, 0, 0, OPF_DATA },
982 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
983 { "mov" , OP_MOV, 2, 2, OPF_DATA },
984 { "lea", OP_LEA, 2, 2, OPF_DATA },
985 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
986 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
987 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
988 { "not", OP_NOT, 1, 1, OPF_DATA },
989 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
990 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
991 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
992 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
993 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
994 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
995 { "stosb",OP_STOS, 0, 0, OPF_DATA },
996 { "stosw",OP_STOS, 0, 0, OPF_DATA },
997 { "stosd",OP_STOS, 0, 0, OPF_DATA },
998 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
999 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
1000 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
1001 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
1002 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
1003 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
1004 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
1005 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
1006 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
1007 { "rdtsc",OP_RDTSC, 0, 0, OPF_DATA },
1008 { "cpuid",OP_CPUID, 0, 0, OPF_DATA },
1009 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
1010 { "cld", OP_CLD, 0, 0, OPF_DATA },
1011 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
1012 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
1013 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
1014 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
1015 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
1016 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
1017 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
1018 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
1019 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
1020 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
1021 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
1022 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
1023 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
1024 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1025 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1026 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1027 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1028 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
1029 { "bsr", OP_BSR, 2, 2, OPF_DATA|OPF_FLAGS },
1030 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
1031 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
1032 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
1033 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
1034 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
1035 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
1036 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
1037 { "test", OP_TEST, 2, 2, OPF_FLAGS },
1038 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
1039 { "retn", OP_RET, 0, 1, OPF_TAIL },
1040 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
1041 { "jmp", OP_JMP, 1, 1, OPF_JMP },
1042 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
1043 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
1044 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
1045 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
1046 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
1047 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
1048 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
1049 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1050 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1051 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
1052 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
1053 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
1054 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
1055 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1056 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1057 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1058 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1059 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1060 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1061 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1062 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1063 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1064 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1065 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1066 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1067 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1068 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1069 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1070 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1071 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1072 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1073 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1074 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1075 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1076 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1077 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1078 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1079 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1080 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1081 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1082 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1083 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1084 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1085 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1086 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1087 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1088 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1089 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1090 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1091 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1092 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1093 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1094 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1095 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1096 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1097 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1098 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1099 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1100 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1101 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1103 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1104 { "fild", OP_FILD, 1, 1, OPF_FPUSH|OPF_FINT },
1105 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1106 { "fldl2t", OP_FLDc, 0, 0, OPF_FPUSH },
1107 { "fldl2e", OP_FLDc, 0, 0, OPF_FPUSH },
1108 { "fldpi", OP_FLDc, 0, 0, OPF_FPUSH },
1109 { "fldlg2", OP_FLDc, 0, 0, OPF_FPUSH },
1110 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1111 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1112 { "fst", OP_FST, 1, 1, 0 },
1113 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1114 { "fist", OP_FIST, 1, 1, OPF_FINT },
1115 { "fistp", OP_FIST, 1, 1, OPF_FPOP|OPF_FINT },
1116 { "fabs", OP_FABS, 0, 0, 0 },
1117 { "fadd", OP_FADD, 0, 2, 0 },
1118 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1119 { "fdiv", OP_FDIV, 0, 2, 0 },
1120 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1121 { "fmul", OP_FMUL, 0, 2, 0 },
1122 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1123 { "fsub", OP_FSUB, 0, 2, 0 },
1124 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1125 { "fdivr", OP_FDIVR, 0, 2, 0 },
1126 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1127 { "fsubr", OP_FSUBR, 0, 2, 0 },
1128 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1129 { "fiadd", OP_FIADD, 1, 1, OPF_FINT },
1130 { "fidiv", OP_FIDIV, 1, 1, OPF_FINT },
1131 { "fimul", OP_FIMUL, 1, 1, OPF_FINT },
1132 { "fisub", OP_FISUB, 1, 1, OPF_FINT },
1133 { "fidivr", OP_FIDIVR, 1, 1, OPF_FINT },
1134 { "fisubr", OP_FISUBR, 1, 1, OPF_FINT },
1135 { "fcom", OP_FCOM, 0, 1, 0 },
1136 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1137 { "fcompp", OP_FCOM, 0, 0, OPF_FPOPP },
1138 { "fucom", OP_FCOM, 0, 1, 0 },
1139 { "fucomp", OP_FCOM, 0, 1, OPF_FPOP },
1140 { "fucompp",OP_FCOM, 0, 0, OPF_FPOPP },
1141 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1142 { "fchs", OP_FCHS, 0, 0, 0 },
1143 { "fcos", OP_FCOS, 0, 0, 0 },
1144 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1145 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1146 { "fsin", OP_FSIN, 0, 0, 0 },
1147 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1148 { "fxch", OP_FXCH, 1, 1, 0 },
1149 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1151 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1152 { "movq", OP_MOV, 2, 2, OPF_DATA },
1153 // pseudo-ops for lib calls
1154 { "_allshl",OPP_ALLSHL },
1155 { "_allshr",OPP_ALLSHR },
1156 { "_ftol", OPP_FTOL },
1157 { "_CIpow", OPP_CIPOW },
1158 { "abort", OPP_ABORT },
1163 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1165 enum opr_lenmod lmod = OPLM_UNSPEC;
1166 int prefix_flags = 0;
1174 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1175 if (IS(words[w], pref_table[i].name)) {
1176 prefix_flags = pref_table[i].flags;
1183 aerr("lone prefix: '%s'\n", words[0]);
1188 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1189 if (IS(words[w], op_table[i].name))
1193 if (i == ARRAY_SIZE(op_table)) {
1195 aerr("unhandled op: '%s'\n", words[0]);
1200 op->op = op_table[i].op;
1201 op->flags = op_table[i].flags | prefix_flags;
1202 op->pfo = op_table[i].pfo;
1203 op->pfo_inv = op_table[i].pfo_inv;
1204 op->regmask_src = op->regmask_dst = 0;
1207 if (op->op == OP_UD2)
1210 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1211 if (opr >= op_table[i].minopr && w >= wordc)
1214 regmask = regmask_ind = 0;
1215 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1216 words, wordc, w, op->flags);
1218 if (opr == 0 && (op->flags & OPF_DATA))
1219 op->regmask_dst = regmask;
1221 op->regmask_src |= regmask;
1222 op->regmask_src |= regmask_ind;
1224 if (op->operand[opr].lmod != OPLM_UNSPEC)
1225 g_func_lmods |= 1 << op->operand[opr].lmod;
1229 aerr("parse_op %s incomplete: %d/%d\n",
1230 words[0], w, wordc);
1233 op->operand_cnt = opr;
1234 if (!strncmp(op_table[i].name, "set", 3))
1235 op->operand[0].lmod = OPLM_BYTE;
1238 // first operand is not dst
1241 op->regmask_src |= op->regmask_dst;
1242 op->regmask_dst = 0;
1245 // first operand is src too
1258 op->regmask_src |= op->regmask_dst;
1263 op->regmask_src |= op->regmask_dst;
1264 op->regmask_dst |= op->regmask_src;
1270 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1271 && op->operand[0].lmod == op->operand[1].lmod
1272 && op->operand[0].reg == op->operand[1].reg
1273 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1275 op->regmask_src = 0;
1278 op->regmask_src |= op->regmask_dst;
1281 // ops with implicit argumets
1283 op->operand_cnt = 2;
1284 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1285 op->regmask_dst = op->regmask_src;
1286 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1290 op->operand_cnt = 2;
1291 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1292 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1298 if (words[op_w][4] == 'b')
1300 else if (words[op_w][4] == 'w')
1302 else if (words[op_w][4] == 'd')
1305 op->regmask_src = 0;
1306 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1307 OPLM_DWORD, &op->regmask_src);
1308 op->regmask_dst = op->regmask_src;
1309 setup_reg_opr(&op->operand[j++], xAX, lmod,
1310 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1311 if (op->flags & OPF_REP) {
1312 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1313 op->regmask_dst |= 1 << xCX;
1315 op->operand_cnt = j;
1320 if (words[op_w][4] == 'b')
1322 else if (words[op_w][4] == 'w')
1324 else if (words[op_w][4] == 'd')
1327 op->regmask_src = 0;
1328 // note: lmod is not correct, don't have where to place it
1329 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1330 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1331 if (op->flags & OPF_REP)
1332 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1333 op->operand_cnt = j;
1334 op->regmask_dst = op->regmask_src;
1338 op->regmask_dst = mxAX | mxDX;
1342 // for now, ignore ecx dep for eax={4,7,b,d}
1343 op->regmask_src = mxAX;
1344 op->regmask_dst = mxAX | mxBX | mxCX | mxDX;
1348 op->regmask_dst = 1 << xCX;
1351 op->operand_cnt = 2;
1352 op->regmask_src = 1 << xCX;
1353 op->operand[1].type = OPT_REG;
1354 op->operand[1].reg = xCX;
1355 op->operand[1].lmod = OPLM_DWORD;
1359 if (op->operand_cnt == 2) {
1360 if (op->operand[0].type != OPT_REG)
1361 aerr("reg expected\n");
1362 op->regmask_src |= 1 << op->operand[0].reg;
1364 if (op->operand_cnt != 1)
1369 if (op->operand[0].lmod == OPLM_UNSPEC)
1370 op->operand[0].lmod = OPLM_DWORD;
1371 op->regmask_src = mxAX | op->regmask_dst;
1372 op->regmask_dst = mxAX;
1373 if (op->operand[0].lmod != OPLM_BYTE)
1374 op->regmask_dst |= mxDX;
1379 // we could set up operands for edx:eax, but there is no real need to
1380 // (see is_opr_modified())
1381 if (op->operand[0].lmod == OPLM_UNSPEC)
1382 op->operand[0].lmod = OPLM_DWORD;
1383 op->regmask_src = mxAX | op->regmask_dst;
1384 op->regmask_dst = mxAX;
1385 if (op->operand[0].lmod != OPLM_BYTE) {
1386 op->regmask_src |= mxDX;
1387 op->regmask_dst |= mxDX;
1396 op->regmask_src |= op->regmask_dst;
1397 if (op->operand[1].lmod == OPLM_UNSPEC)
1398 op->operand[1].lmod = OPLM_BYTE;
1403 op->regmask_src |= op->regmask_dst;
1404 if (op->operand[2].lmod == OPLM_UNSPEC)
1405 op->operand[2].lmod = OPLM_BYTE;
1409 op->regmask_src |= op->regmask_dst;
1410 op->regmask_dst = 0;
1411 if (op->operand[0].lmod == OPLM_UNSPEC
1412 && (op->operand[0].type == OPT_CONST
1413 || op->operand[0].type == OPT_OFFSET
1414 || op->operand[0].type == OPT_LABEL))
1415 op->operand[0].lmod = OPLM_DWORD;
1421 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1422 && op->operand[0].lmod == op->operand[1].lmod
1423 && op->operand[0].reg == op->operand[1].reg
1424 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1426 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1427 op->regmask_src = op->regmask_dst = 0;
1432 if (op->operand[0].type == OPT_REG
1433 && op->operand[1].type == OPT_REGMEM)
1436 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1437 if (IS(buf, op->operand[1].name))
1438 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1443 // needed because of OPF_DATA
1444 op->regmask_src |= op->regmask_dst;
1445 // trashed regs must be explicitly detected later
1446 op->regmask_dst = 0;
1450 op->regmask_dst = (1 << xBP) | (1 << xSP);
1451 op->regmask_src = 1 << xBP;
1456 op->regmask_dst |= mxST0;
1460 op->regmask_dst |= mxST0;
1461 if (IS(words[op_w] + 3, "1"))
1462 op->operand[0].val = X87_CONST_1;
1463 else if (IS(words[op_w] + 3, "l2t"))
1464 op->operand[0].val = X87_CONST_L2T;
1465 else if (IS(words[op_w] + 3, "l2e"))
1466 op->operand[0].val = X87_CONST_L2E;
1467 else if (IS(words[op_w] + 3, "pi"))
1468 op->operand[0].val = X87_CONST_PI;
1469 else if (IS(words[op_w] + 3, "lg2"))
1470 op->operand[0].val = X87_CONST_LG2;
1471 else if (IS(words[op_w] + 3, "ln2"))
1472 op->operand[0].val = X87_CONST_LN2;
1473 else if (IS(words[op_w] + 3, "z"))
1474 op->operand[0].val = X87_CONST_Z;
1476 aerr("fld what?\n");
1481 op->regmask_src |= mxST0;
1490 op->regmask_src |= mxST0;
1491 if (op->operand_cnt == 2)
1492 op->regmask_src |= op->regmask_dst;
1493 else if (op->operand_cnt == 1) {
1494 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1495 op->operand[0].type = OPT_REG;
1496 op->operand[0].lmod = OPLM_QWORD;
1497 op->operand[0].reg = xST0;
1498 op->regmask_dst |= mxST0;
1501 // IDA doesn't use this
1502 aerr("no operands?\n");
1517 op->regmask_src |= mxST0;
1518 op->regmask_dst |= mxST0;
1523 op->regmask_src |= mxST0 | mxST1;
1524 op->regmask_dst |= mxST0;
1532 op->regmask_src |= mxST0;
1533 if (op->operand_cnt == 0) {
1534 op->operand_cnt = 1;
1535 op->operand[0].type = OPT_REG;
1536 op->operand[0].lmod = OPLM_QWORD;
1537 op->operand[0].reg = xST1;
1538 op->regmask_src |= mxST1;
1546 if (op->operand[0].type == OPT_REG
1547 && op->operand[1].type == OPT_CONST)
1549 struct parsed_opr *op1 = &op->operand[1];
1550 if ((op->op == OP_AND && op1->val == 0)
1553 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1554 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1556 op->regmask_src = 0;
1561 static const char *op_name(struct parsed_op *po)
1563 static char buf[16];
1567 if (po->op == OP_JCC || po->op == OP_SCC) {
1569 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1572 strcpy(p, parsed_flag_op_names[po->pfo]);
1576 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1577 if (op_table[i].op == po->op)
1578 return op_table[i].name;
1584 static const char *dump_op(struct parsed_op *po)
1586 static char out[128];
1593 snprintf(out, sizeof(out), "%s", op_name(po));
1594 for (i = 0; i < po->operand_cnt; i++) {
1598 snprintf(p, sizeof(out) - (p - out),
1599 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1600 po->operand[i].name);
1606 static const char *lmod_type_u(struct parsed_op *po,
1607 enum opr_lenmod lmod)
1619 ferr(po, "invalid lmod: %d\n", lmod);
1620 return "(_invalid_)";
1624 static const char *lmod_cast_u(struct parsed_op *po,
1625 enum opr_lenmod lmod)
1637 ferr(po, "invalid lmod: %d\n", lmod);
1638 return "(_invalid_)";
1642 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1643 enum opr_lenmod lmod)
1655 ferr(po, "invalid lmod: %d\n", lmod);
1656 return "(_invalid_)";
1660 static const char *lmod_cast_s(struct parsed_op *po,
1661 enum opr_lenmod lmod)
1673 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1674 return "(_invalid_)";
1678 static const char *lmod_cast(struct parsed_op *po,
1679 enum opr_lenmod lmod, int is_signed)
1682 lmod_cast_s(po, lmod) :
1683 lmod_cast_u(po, lmod);
1686 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1698 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1703 static const char *opr_name(struct parsed_op *po, int opr_num)
1705 if (opr_num >= po->operand_cnt)
1706 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1707 return po->operand[opr_num].name;
1710 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1712 if (opr_num >= po->operand_cnt)
1713 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1714 if (po->operand[opr_num].type != OPT_CONST)
1715 ferr(po, "opr %d: const expected\n", opr_num);
1716 return po->operand[opr_num].val;
1719 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1721 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1722 ferr(po, "invalid reg: %d\n", popr->reg);
1723 return regs_r32[popr->reg];
1726 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1728 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1730 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1732 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1734 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1739 *is_signed = cast[1] == 's' ? 1 : 0;
1743 static int check_deref_cast(const char *cast, int *bits)
1745 if (IS_START(cast, "*(u8 *)"))
1747 else if (IS_START(cast, "*(u16 *)"))
1749 else if (IS_START(cast, "*(u32 *)"))
1751 else if (IS_START(cast, "*(u64 *)"))
1759 // cast1 is the "final" cast
1760 static const char *simplify_cast(const char *cast1, const char *cast2)
1762 static char buf[256];
1770 if (IS(cast1, cast2))
1773 if (check_simple_cast(cast1, &bits1, &s1) == 0
1774 && check_simple_cast(cast2, &bits2, &s2) == 0)
1779 if (check_simple_cast(cast1, &bits1, &s1) == 0
1780 && check_deref_cast(cast2, &bits2) == 0)
1782 if (bits1 == bits2) {
1783 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1788 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1791 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1795 static const char *simplify_cast_num(const char *cast, unsigned int val)
1797 if (IS(cast, "(u8)") && val < 0x100)
1799 if (IS(cast, "(s8)") && val < 0x80)
1801 if (IS(cast, "(u16)") && val < 0x10000)
1803 if (IS(cast, "(s16)") && val < 0x8000)
1805 if (IS(cast, "(s32)") && val < 0x80000000)
1811 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1820 namelen = strlen(name);
1822 p = strpbrk(name, "+-");
1826 ferr(po, "equ parse failed for '%s'\n", name);
1829 *extra_offs = strtol(p, &endp, 16);
1830 if (*endp != 0 || errno != 0)
1831 ferr(po, "equ parse failed for '%s'\n", name);
1834 for (i = 0; i < g_eqcnt; i++)
1835 if (strncmp(g_eqs[i].name, name, namelen) == 0
1836 && g_eqs[i].name[namelen] == 0)
1840 ferr(po, "unresolved equ name: '%s'\n", name);
1847 static int is_stack_access(struct parsed_op *po,
1848 const struct parsed_opr *popr)
1850 return (parse_stack_el(popr->name, NULL, NULL, 0)
1851 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1852 && IS_START(popr->name, "ebp")));
1855 static void parse_stack_access(struct parsed_op *po,
1856 const char *name, char *ofs_reg, int *offset_out,
1857 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1859 const char *bp_arg = "";
1860 const char *p = NULL;
1861 struct parsed_equ *eq;
1868 if (IS_START(name, "ebp-")
1869 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1872 if (IS_START(p, "0x"))
1875 offset = strtoul(p, &endp, 16);
1878 if (*endp != 0 || errno != 0)
1879 ferr(po, "ebp- parse of '%s' failed\n", name);
1882 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1883 eq = equ_find(po, bp_arg, &offset);
1885 ferr(po, "detected but missing eq\n");
1886 offset += eq->offset;
1889 if (!strncmp(name, "ebp", 3))
1892 // yes it sometimes LEAs ra for compares..
1893 if (!is_lea && ofs_reg[0] == 0
1894 && stack_ra <= offset && offset < stack_ra + 4)
1896 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1899 *offset_out = offset;
1901 *stack_ra_out = stack_ra;
1903 *bp_arg_out = bp_arg;
1906 static int parse_stack_esp_offset(struct parsed_op *po,
1907 const char *name, int *offset_out)
1909 char ofs_reg[16] = { 0, };
1910 struct parsed_equ *eq;
1916 if (strstr(name, "esp") == NULL)
1918 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1919 if (bp_arg == NULL) {
1920 // just plain offset?
1921 if (!IS_START(name, "esp+"))
1924 offset = strtol(name + 4, &endp, 0);
1925 if (endp == NULL || *endp != 0 || errno != 0)
1927 *offset_out = offset;
1931 if (ofs_reg[0] != 0)
1933 eq = equ_find(po, bp_arg, &offset);
1935 ferr(po, "detected but missing eq\n");
1936 offset += eq->offset;
1937 *offset_out = base_val + offset;
1941 // returns g_func_pp arg number if arg is accessed
1942 // -1 otherwise (stack vars, va_list)
1943 // note: 'popr' must be from 'po', not some other op
1944 static int stack_frame_access(struct parsed_op *po,
1945 struct parsed_opr *popr, char *buf, size_t buf_size,
1946 const char *name, const char *cast, int is_src, int is_lea)
1948 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1949 const char *prefix = "";
1950 const char *bp_arg = NULL;
1951 char ofs_reg[16] = { 0, };
1953 int i, arg_i, arg_s;
1960 if (g_bp_frame && (po->flags & OPF_EBP_S)
1961 && !(po->regmask_src & mxSP))
1962 ferr(po, "stack_frame_access while ebp is scratch\n");
1964 parse_stack_access(po, name, ofs_reg, &offset,
1965 &stack_ra, &bp_arg, is_lea);
1967 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1969 if (offset > stack_ra)
1971 arg_i = (offset - stack_ra - 4) / 4;
1972 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1974 if (g_func_pp->is_vararg && arg_i == g_func_pp->argc_stack) {
1976 // should be va_list
1979 snprintf(buf, buf_size, "%sap", cast);
1982 snprintf(buf, buf_size, "%sva_arg(ap, u32)", cast);
1985 ferr(po, "offset 0x%x (%s,%d) doesn't map to any arg\n",
1986 offset, bp_arg, arg_i);
1988 if (ofs_reg[0] != 0)
1989 ferr(po, "offset reg on arg access?\n");
1991 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1992 if (g_func_pp->arg[i].reg != NULL)
1998 if (i == g_func_pp->argc)
1999 ferr(po, "arg %d not in prototype?\n", arg_i);
2001 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
2004 snprintf(argname, sizeof(argname), "%sa%d",
2005 g_sct_func_attr & SCTFA_ARGFRAME ? "af." : "", i + 1);
2011 ferr(po, "lea/byte to arg?\n");
2012 if (is_src && (offset & 3) == 0)
2013 snprintf(buf, buf_size, "%s%s",
2014 simplify_cast(cast, "(u8)"), argname);
2016 snprintf(buf, buf_size, "%sBYTE%d(%s)",
2017 cast, offset & 3, argname);
2022 ferr(po, "lea/word to arg?\n");
2027 ferr(po, "problematic arg store\n");
2028 snprintf(buf, buf_size, "%s((char *)&%s + 1)",
2029 simplify_cast(cast, "*(u16 *)"), argname);
2032 ferr(po, "unaligned arg word load\n");
2034 else if (is_src && (offset & 2) == 0)
2035 snprintf(buf, buf_size, "%s%s",
2036 simplify_cast(cast, "(u16)"), argname);
2038 snprintf(buf, buf_size, "%s%sWORD(%s)",
2039 cast, (offset & 2) ? "HI" : "LO", argname);
2051 snprintf(buf, buf_size, "(u32)&%s + %d",
2052 argname, offset & 3);
2054 ferr(po, "unaligned arg store\n");
2056 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
2057 snprintf(buf, buf_size, "%s(%s >> %d)",
2058 prefix, argname, (offset & 3) * 8);
2062 snprintf(buf, buf_size, "%s%s%s",
2063 prefix, is_lea ? "&" : "", argname);
2068 ferr_assert(po, !(offset & 7));
2071 snprintf(buf, buf_size, "%s%s%s",
2072 prefix, is_lea ? "&" : "", argname);
2076 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
2080 strcat(g_comment, " unaligned");
2083 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
2084 if (tmp_lmod != OPLM_DWORD
2085 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
2086 < lmod_bytes(po, popr->lmod) + (offset & 3))))
2088 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
2089 i + 1, offset, g_func_pp->arg[i].type.name);
2091 // can't check this because msvc likes to reuse
2092 // arg space for scratch..
2093 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
2094 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2098 if (g_stack_fsz == 0)
2099 ferr(po, "stack var access without stackframe\n");
2100 g_stack_frame_used = 1;
2102 sf_ofs = g_stack_fsz + offset;
2103 if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2104 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2114 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2115 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2119 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2120 // known unaligned or possibly unaligned
2121 strcat(g_comment, " unaligned");
2123 prefix = "*(u16 *)&";
2124 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2125 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2128 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2132 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2133 // known unaligned or possibly unaligned
2134 strcat(g_comment, " unaligned");
2136 prefix = "*(u32 *)&";
2137 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2138 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2141 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2145 ferr_assert(po, !(sf_ofs & 7));
2146 ferr_assert(po, ofs_reg[0] == 0);
2147 // only used for x87 int64/float, float sets is_lea
2148 if (!is_lea && (po->flags & OPF_FINT))
2149 prefix = "*(s64 *)&";
2150 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2154 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2161 static void check_func_pp(struct parsed_op *po,
2162 const struct parsed_proto *pp, const char *pfx)
2164 enum opr_lenmod tmp_lmod;
2168 if (pp->argc_reg != 0) {
2169 if (!g_allow_user_icall && !pp->is_fastcall) {
2170 pp_print(buf, sizeof(buf), pp);
2171 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2173 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2174 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2175 pfx, pp->argc_reg, pp->argc_stack);
2178 // fptrs must use 32bit args, callsite might have no information and
2179 // lack a cast to smaller types, which results in incorrectly masked
2180 // args passed (callee may assume masked args, it does on ARM)
2181 if (!pp->is_osinc) {
2182 for (i = 0; i < pp->argc; i++) {
2183 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2184 if (ret && tmp_lmod != OPLM_DWORD)
2185 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2186 i + 1, pp->arg[i].type.name);
2191 static const char *check_label_read_ref(struct parsed_op *po,
2192 const char *name, int *is_import)
2194 const struct parsed_proto *pp;
2196 pp = proto_parse(g_fhdr, name, 0);
2198 ferr(po, "proto_parse failed for ref '%s'\n", name);
2201 check_func_pp(po, pp, "ref");
2203 if (is_import != NULL)
2204 *is_import = pp->is_import;
2209 static void check_opr(struct parsed_op *po, struct parsed_opr *popr)
2211 if (popr->segment == SEG_FS)
2212 ferr(po, "fs: used\n");
2213 if (popr->segment == SEG_GS)
2214 ferr(po, "gs: used\n");
2217 static char *out_src_opr(char *buf, size_t buf_size,
2218 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2221 char tmp1[256], tmp2[256];
2228 check_opr(po, popr);
2233 switch (popr->type) {
2236 ferr(po, "lea from reg?\n");
2238 switch (popr->lmod) {
2240 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2243 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2246 snprintf(buf, buf_size, "%s%s",
2247 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2250 if (popr->name[1] == 'h') // XXX..
2251 snprintf(buf, buf_size, "%s(%s >> 8)",
2252 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2254 snprintf(buf, buf_size, "%s%s",
2255 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2258 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2263 if (is_stack_access(po, popr)) {
2264 stack_frame_access(po, popr, buf, buf_size,
2265 popr->name, cast, 1, is_lea);
2269 strcpy(expr, popr->name);
2270 if (strchr(expr, '[')) {
2271 // special case: '[' can only be left for label[reg] form
2272 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2274 ferr(po, "parse failure for '%s'\n", expr);
2275 if (tmp1[0] == '(') {
2276 // (off_4FFF50+3)[eax]
2277 p = strchr(tmp1 + 1, ')');
2278 if (p == NULL || p[1] != 0)
2279 ferr(po, "parse failure (2) for '%s'\n", expr);
2281 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2283 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2286 // XXX: do we need more parsing?
2288 snprintf(buf, buf_size, "%s", expr);
2292 snprintf(buf, buf_size, "%s(%s)",
2293 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2297 name = check_label_read_ref(po, popr->name, &is_import);
2299 // for imported data, asm is loading the offset
2302 if (cast[0] == 0 && popr->is_ptr)
2306 snprintf(buf, buf_size, "(u32)&%s", name);
2307 else if (popr->size_lt)
2308 snprintf(buf, buf_size, "%s%s%s%s", cast,
2309 lmod_cast_u_ptr(po, popr->lmod),
2310 popr->is_array ? "" : "&", name);
2312 snprintf(buf, buf_size, "%s%s%s", cast, name,
2313 popr->is_array ? "[0]" : "");
2318 name = check_label_read_ref(po, popr->name, NULL);
2322 ferr(po, "lea an offset?\n");
2323 snprintf(buf, buf_size, "%s&%s", cast, name);
2328 ferr(po, "lea from const?\n");
2330 printf_number(tmp1, sizeof(tmp1), popr->val);
2331 if (popr->val == 0 && strchr(cast, '*'))
2332 snprintf(buf, buf_size, "NULL");
2334 snprintf(buf, buf_size, "%s%s",
2335 simplify_cast_num(cast, popr->val), tmp1);
2339 ferr(po, "invalid src type: %d\n", popr->type);
2345 // note: may set is_ptr (we find that out late for ebp frame..)
2346 static char *out_dst_opr(char *buf, size_t buf_size,
2347 struct parsed_op *po, struct parsed_opr *popr)
2349 check_opr(po, popr);
2351 switch (popr->type) {
2353 switch (popr->lmod) {
2355 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2358 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2362 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2366 if (popr->name[1] == 'h') // XXX..
2367 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2369 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2372 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2377 if (is_stack_access(po, popr)) {
2378 stack_frame_access(po, popr, buf, buf_size,
2379 popr->name, "", 0, 0);
2383 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2386 if (popr->size_mismatch)
2387 snprintf(buf, buf_size, "%s%s%s",
2388 lmod_cast_u_ptr(po, popr->lmod),
2389 popr->is_array ? "" : "&", popr->name);
2391 snprintf(buf, buf_size, "%s%s", popr->name,
2392 popr->is_array ? "[0]" : "");
2396 ferr(po, "invalid dst type: %d\n", popr->type);
2402 static char *out_src_opr_u32(char *buf, size_t buf_size,
2403 struct parsed_op *po, struct parsed_opr *popr)
2405 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2408 static char *out_opr_float(char *buf, size_t buf_size,
2409 struct parsed_op *po, struct parsed_opr *popr, int is_src,
2410 int need_float_stack)
2412 const char *cast = NULL;
2419 switch (popr->type) {
2421 if (popr->reg < xST0 || popr->reg > xST7) {
2423 ferr_assert(po, po->op == OP_PUSH);
2424 ferr_assert(po, popr->lmod == OPLM_DWORD);
2425 snprintf(buf, buf_size, "*(float *)&%s", opr_reg_p(po, popr));
2429 if (need_float_stack) {
2430 if (popr->reg == xST0)
2431 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2433 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2437 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2441 if (popr->lmod == OPLM_QWORD && is_stack_access(po, popr)) {
2442 stack_frame_access(po, popr, buf, buf_size,
2443 popr->name, "", is_src, 0);
2449 switch (popr->lmod) {
2457 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2460 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2461 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2465 // only for func float args pushes
2466 ferr_assert(po, po->op == OP_PUSH);
2467 u.i = po->operand[0].val;
2468 if (ceilf(u.f) == u.f)
2469 snprintf(buf, buf_size, "%.1ff", u.f);
2471 snprintf(buf, buf_size, "%.8ff", u.f);
2475 ferr(po, "invalid float type: %d\n", popr->type);
2481 static char *out_src_opr_float(char *buf, size_t buf_size,
2482 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2484 return out_opr_float(buf, buf_size, po, popr, 1, need_float_stack);
2487 static char *out_dst_opr_float(char *buf, size_t buf_size,
2488 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2490 return out_opr_float(buf, buf_size, po, popr, 0, need_float_stack);
2493 static void out_test_for_cc(char *buf, size_t buf_size,
2494 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2495 enum opr_lenmod lmod, const char *expr)
2497 const char *cast, *scast;
2499 cast = lmod_cast_u(po, lmod);
2500 scast = lmod_cast_s(po, lmod);
2504 case PFO_BE: // CF==1||ZF==1; CF=0
2505 snprintf(buf, buf_size, "(%s%s %s 0)",
2506 cast, expr, is_inv ? "!=" : "==");
2510 case PFO_L: // SF!=OF; OF=0
2511 snprintf(buf, buf_size, "(%s%s %s 0)",
2512 scast, expr, is_inv ? ">=" : "<");
2515 case PFO_LE: // ZF==1||SF!=OF; OF=0
2516 snprintf(buf, buf_size, "(%s%s %s 0)",
2517 scast, expr, is_inv ? ">" : "<=");
2522 snprintf(buf, buf_size, "(%d)", !!is_inv);
2525 case PFO_P: // PF==1
2526 snprintf(buf, buf_size, "(%sdo_parity(%s))",
2527 is_inv ? "!" : "", expr);
2531 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2535 static void out_cmp_for_cc(char *buf, size_t buf_size,
2536 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2539 const char *cast, *scast, *cast_use;
2540 char buf1[256], buf2[256];
2541 enum opr_lenmod lmod;
2543 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2544 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2545 po->operand[0].lmod, po->operand[1].lmod);
2546 lmod = po->operand[0].lmod;
2548 cast = lmod_cast_u(po, lmod);
2549 scast = lmod_cast_s(po, lmod);
2565 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2568 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2569 if (po->op == OP_DEC)
2570 snprintf(buf2, sizeof(buf2), "1");
2573 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2575 strcat(cast_op2, "-");
2576 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2581 // note: must be unsigned compare
2582 snprintf(buf, buf_size, "(%s %s %s)",
2583 buf1, is_inv ? ">=" : "<", buf2);
2587 snprintf(buf, buf_size, "(%s %s %s)",
2588 buf1, is_inv ? "!=" : "==", buf2);
2592 // note: must be unsigned compare
2593 snprintf(buf, buf_size, "(%s %s %s)",
2594 buf1, is_inv ? ">" : "<=", buf2);
2597 if (is_inv && lmod == OPLM_BYTE
2598 && po->operand[1].type == OPT_CONST
2599 && po->operand[1].val == 0xff)
2601 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2602 snprintf(buf, buf_size, "(0)");
2606 // note: must be signed compare
2608 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2609 scast, buf1, buf2, is_inv ? ">=" : "<");
2613 snprintf(buf, buf_size, "(%s %s %s)",
2614 buf1, is_inv ? ">=" : "<", buf2);
2618 snprintf(buf, buf_size, "(%s %s %s)",
2619 buf1, is_inv ? ">" : "<=", buf2);
2627 static void out_cmp_test(char *buf, size_t buf_size,
2628 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2630 char buf1[256], buf2[256], buf3[256];
2632 if (po->op == OP_TEST) {
2633 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2634 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2637 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2638 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2639 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2641 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2642 po->operand[0].lmod, buf3);
2644 else if (po->op == OP_CMP) {
2645 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2648 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2651 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2652 struct parsed_opr *popr2)
2654 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2655 ferr(po, "missing lmod for both operands\n");
2657 if (popr1->lmod == OPLM_UNSPEC)
2658 popr1->lmod = popr2->lmod;
2659 else if (popr2->lmod == OPLM_UNSPEC)
2660 popr2->lmod = popr1->lmod;
2661 else if (popr1->lmod != popr2->lmod) {
2662 if (popr1->type_from_var) {
2663 popr1->size_mismatch = 1;
2664 if (popr1->lmod < popr2->lmod)
2666 popr1->lmod = popr2->lmod;
2668 else if (popr2->type_from_var) {
2669 popr2->size_mismatch = 1;
2670 if (popr2->lmod < popr1->lmod)
2672 popr2->lmod = popr1->lmod;
2675 ferr(po, "conflicting lmods: %d vs %d\n",
2676 popr1->lmod, popr2->lmod);
2680 static const char *op_to_c(struct parsed_op *po)
2704 ferr(po, "op_to_c was supplied with %d\n", po->op);
2708 // last op in stream - unconditional branch or ret
2709 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2710 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2711 && ops[_i].op != OP_CALL))
2713 #define check_i(po, i) \
2715 ferr(po, "bad " #i ": %d\n", i)
2717 // note: this skips over calls and rm'd stuff assuming they're handled
2718 // so it's intended to use at one of final passes
2719 // exception: doesn't skip OPF_RSAVE stuff
2720 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2721 int depth, int seen_noreturn, int save_level, int flags_set)
2723 struct parsed_op *po;
2728 for (; i < opcnt; i++) {
2730 if (po->cc_scratch == magic)
2731 return ret; // already checked
2732 po->cc_scratch = magic;
2734 if (po->flags & OPF_TAIL) {
2735 if (po->op == OP_CALL && po->pp != NULL && po->pp->is_noreturn) {
2736 // msvc sometimes generates stack cleanup code after
2737 // noreturn, set a flag and continue
2740 // ... but stop if there is another path to next insn -
2741 // if msvc skipped something stack tracking may mess up
2742 if (i + 1 < opcnt && g_labels[i + 1] != NULL)
2749 if (po->flags & OPF_FARG)
2751 if (po->flags & (OPF_RMD|OPF_DONE)) {
2752 if (!(po->flags & OPF_RSAVE))
2754 // reprocess, there might be another push in some "parallel"
2755 // path that took a pop what we should also take
2758 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2759 if (po->btj != NULL) {
2761 for (j = 0; j < po->btj->count; j++) {
2762 check_i(po, po->btj->d[j].bt_i);
2763 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2764 depth, seen_noreturn, save_level, flags_set);
2766 return ret; // dead end
2771 check_i(po, po->bt_i);
2772 if (po->flags & OPF_CJMP) {
2773 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2774 depth, seen_noreturn, save_level, flags_set);
2776 return ret; // dead end
2785 if ((po->op == OP_POP || po->op == OP_PUSH)
2786 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2791 if (po->op == OP_PUSH) {
2794 else if (po->op == OP_POP) {
2795 if (relevant && depth == 0) {
2796 if (flags_set == 0 && save_level > 0) {
2797 ret = scan_for_pop(i + 1, opcnt, magic, reg,
2798 depth, seen_noreturn, save_level - 1, flags_set);
2800 // no pop for other levels, current one must be false
2803 po->flags |= flags_set;
2811 // for noreturn, assume msvc skipped stack cleanup
2812 return seen_noreturn ? 1 : -1;
2815 // scan for 'reg' pop backwards starting from i
2816 // intended to use for register restore search, so other reg
2817 // references are considered an error
2818 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2820 struct parsed_op *po;
2821 struct label_ref *lr;
2824 ops[i].cc_scratch = magic;
2828 if (g_labels[i] != NULL) {
2829 lr = &g_label_refs[i];
2830 for (; lr != NULL; lr = lr->next) {
2831 check_i(&ops[i], lr->i);
2832 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2836 if (i > 0 && LAST_OP(i - 1))
2844 if (ops[i].cc_scratch == magic)
2846 ops[i].cc_scratch = magic;
2849 if (po->op == OP_POP && po->operand[0].reg == reg) {
2850 if (po->flags & (OPF_RMD|OPF_DONE))
2853 po->flags |= set_flags;
2857 // this also covers the case where we reach corresponding push
2858 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2862 // nothing interesting on this path,
2863 // still return ret for something recursive calls could find
2867 static void find_reachable_exits(int i, int opcnt, int magic,
2868 int *exits, int *exit_count)
2870 struct parsed_op *po;
2873 for (; i < opcnt; i++)
2876 if (po->cc_scratch == magic)
2878 po->cc_scratch = magic;
2880 if (po->flags & OPF_TAIL) {
2881 ferr_assert(po, *exit_count < MAX_EXITS);
2882 exits[*exit_count] = i;
2887 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2888 if (po->flags & OPF_RMD)
2891 if (po->btj != NULL) {
2892 for (j = 0; j < po->btj->count; j++) {
2893 check_i(po, po->btj->d[j].bt_i);
2894 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2900 check_i(po, po->bt_i);
2901 if (po->flags & OPF_CJMP)
2902 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2910 // scan for 'reg' pop backwards starting from exits (all paths)
2911 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2913 static int exits[MAX_EXITS];
2914 static int exit_count;
2920 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2922 ferr_assert(&ops[i], exit_count > 0);
2925 for (j = 0; j < exit_count; j++) {
2927 ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2933 if (ops[e].op == OP_CALL && ops[e].pp != NULL
2934 && ops[e].pp->is_noreturn)
2936 // assume stack cleanup was skipped
2945 // scan for one or more pop of push <const>
2946 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2947 int push_i, int is_probe)
2949 struct parsed_op *po;
2950 struct label_ref *lr;
2954 for (; i < opcnt; i++)
2957 if (po->cc_scratch == magic)
2958 return ret; // already checked
2959 po->cc_scratch = magic;
2961 if (po->flags & OPF_JMP) {
2962 if (po->flags & OPF_RMD)
2964 if (po->op == OP_CALL)
2967 if (po->btj != NULL) {
2968 for (j = 0; j < po->btj->count; j++) {
2969 check_i(po, po->btj->d[j].bt_i);
2970 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2978 check_i(po, po->bt_i);
2979 if (po->flags & OPF_CJMP) {
2980 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2991 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2994 if (g_labels[i] != NULL) {
2995 // all refs must be visited
2996 lr = &g_label_refs[i];
2997 for (; lr != NULL; lr = lr->next) {
2999 if (ops[lr->i].cc_scratch != magic)
3002 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
3006 if (po->op == OP_POP)
3008 if (po->flags & (OPF_RMD|OPF_DONE))
3012 po->flags |= OPF_DONE;
3013 po->datap = &ops[push_i];
3022 static void scan_for_pop_const(int i, int opcnt, int magic)
3026 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
3028 ops[i].flags |= OPF_RMD | OPF_DONE;
3029 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
3033 // check if all branch targets within a marked path are also marked
3034 // note: the path checked must not be empty or end with a branch
3035 static int check_path_branches(int opcnt, int magic)
3037 struct parsed_op *po;
3040 for (i = 0; i < opcnt; i++) {
3042 if (po->cc_scratch != magic)
3045 if (po->flags & OPF_JMP) {
3046 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
3049 if (po->btj != NULL) {
3050 for (j = 0; j < po->btj->count; j++) {
3051 check_i(po, po->btj->d[j].bt_i);
3052 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
3057 check_i(po, po->bt_i);
3058 if (ops[po->bt_i].cc_scratch != magic)
3060 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
3068 // scan for multiple pushes for given pop
3069 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
3072 int reg = ops[pop_i].operand[0].reg;
3073 struct parsed_op *po;
3074 struct label_ref *lr;
3077 ops[i].cc_scratch = magic;
3081 if (g_labels[i] != NULL) {
3082 lr = &g_label_refs[i];
3083 for (; lr != NULL; lr = lr->next) {
3084 check_i(&ops[i], lr->i);
3085 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
3089 if (i > 0 && LAST_OP(i - 1))
3097 if (ops[i].cc_scratch == magic)
3099 ops[i].cc_scratch = magic;
3102 if (po->op == OP_CALL)
3104 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
3107 if (po->op == OP_PUSH)
3109 if (po->datap != NULL)
3111 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
3112 // leave this case for reg save/restore handlers
3116 po->flags |= OPF_PPUSH | OPF_DONE;
3117 po->datap = &ops[pop_i];
3126 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
3128 int magic = i + opcnt * 14;
3131 ret = scan_pushes_for_pop_r(i, magic, i, 1);
3133 ret = check_path_branches(opcnt, magic);
3135 ops[i].flags |= OPF_PPUSH | OPF_DONE;
3136 *regmask_pp |= 1 << ops[i].operand[0].reg;
3137 scan_pushes_for_pop_r(i, magic + 1, i, 0);
3142 static void scan_propagate_df(int i, int opcnt)
3144 struct parsed_op *po = &ops[i];
3147 for (; i < opcnt; i++) {
3149 if (po->flags & OPF_DF)
3150 return; // already resolved
3151 po->flags |= OPF_DF;
3153 if (po->op == OP_CALL)
3154 ferr(po, "call with DF set?\n");
3156 if (po->flags & OPF_JMP) {
3157 if (po->btj != NULL) {
3159 for (j = 0; j < po->btj->count; j++) {
3160 check_i(po, po->btj->d[j].bt_i);
3161 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
3166 if (po->flags & OPF_RMD)
3168 check_i(po, po->bt_i);
3169 if (po->flags & OPF_CJMP)
3170 scan_propagate_df(po->bt_i, opcnt);
3176 if (po->flags & OPF_TAIL)
3179 if (po->op == OP_CLD) {
3180 po->flags |= OPF_RMD | OPF_DONE;
3185 ferr(po, "missing DF clear?\n");
3188 // is operand 'opr' referenced by parsed_op 'po'?
3189 static int is_opr_referenced(const struct parsed_opr *opr,
3190 const struct parsed_op *po)
3194 if (opr->type == OPT_REG) {
3195 mask = po->regmask_dst | po->regmask_src;
3196 if (po->op == OP_CALL)
3197 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3198 if ((1 << opr->reg) & mask)
3204 for (i = 0; i < po->operand_cnt; i++)
3205 if (IS(po->operand[0].name, opr->name))
3211 // is operand 'opr' read by parsed_op 'po'?
3212 static int is_opr_read(const struct parsed_opr *opr,
3213 const struct parsed_op *po)
3215 if (opr->type == OPT_REG) {
3216 if (po->regmask_src & (1 << opr->reg))
3226 // is operand 'opr' modified by parsed_op 'po'?
3227 static int is_opr_modified(const struct parsed_opr *opr,
3228 const struct parsed_op *po)
3232 if (opr->type == OPT_REG) {
3233 if (po->op == OP_CALL) {
3234 mask = po->regmask_dst;
3235 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3236 if (mask & (1 << opr->reg))
3242 if (po->regmask_dst & (1 << opr->reg))
3248 return IS(po->operand[0].name, opr->name);
3251 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3252 static int is_any_opr_modified(const struct parsed_op *po_test,
3253 const struct parsed_op *po, int c_mode)
3258 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3261 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3264 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3267 // in reality, it can wreck any register, but in decompiled C
3268 // version it can only overwrite eax or edx:eax
3269 mask = (1 << xAX) | (1 << xDX);
3273 if (po->op == OP_CALL
3274 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3277 for (i = 0; i < po_test->operand_cnt; i++)
3278 if (IS(po_test->operand[i].name, po->operand[0].name))
3284 // scan for any po_test operand modification in range given
3285 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3288 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3291 for (; i < opcnt; i++) {
3292 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3299 // scan for po_test operand[0] modification in range given
3300 static int scan_for_mod_opr0(struct parsed_op *po_test,
3303 for (; i < opcnt; i++) {
3304 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3311 static int try_resolve_const(int i, const struct parsed_opr *opr,
3312 int magic, unsigned int *val);
3314 static int scan_for_flag_set(int i, int opcnt, int magic,
3315 int *branched, int *setters, int *setter_cnt)
3317 struct label_ref *lr;
3321 if (ops[i].cc_scratch == magic) {
3322 // is this a problem?
3323 //ferr(&ops[i], "%s looped\n", __func__);
3326 ops[i].cc_scratch = magic;
3328 if (g_labels[i] != NULL) {
3331 lr = &g_label_refs[i];
3332 for (; lr->next; lr = lr->next) {
3333 check_i(&ops[i], lr->i);
3334 ret = scan_for_flag_set(lr->i, opcnt, magic,
3335 branched, setters, setter_cnt);
3340 check_i(&ops[i], lr->i);
3341 if (i > 0 && LAST_OP(i - 1)) {
3345 ret = scan_for_flag_set(lr->i, opcnt, magic,
3346 branched, setters, setter_cnt);
3352 if (ops[i].flags & OPF_FLAGS) {
3353 setters[*setter_cnt] = i;
3356 if (ops[i].flags & OPF_REP) {
3357 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3360 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3361 if (ret != 1 || uval == 0) {
3362 // can't treat it as full setter because of ecx=0 case,
3363 // also disallow delayed compare
3372 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3379 // scan back for cdq, if anything modifies edx, fail
3380 static int scan_for_cdq_edx(int i)
3383 if (g_labels[i] != NULL) {
3384 if (g_label_refs[i].next != NULL)
3386 if (i > 0 && LAST_OP(i - 1)) {
3387 i = g_label_refs[i].i;
3394 if (ops[i].op == OP_CDQ)
3397 if (ops[i].regmask_dst & (1 << xDX))
3404 static int scan_for_reg_clear(int i, int reg)
3407 if (g_labels[i] != NULL) {
3408 if (g_label_refs[i].next != NULL)
3410 if (i > 0 && LAST_OP(i - 1)) {
3411 i = g_label_refs[i].i;
3418 if (ops[i].op == OP_XOR
3419 && ops[i].operand[0].lmod == OPLM_DWORD
3420 && ops[i].operand[0].reg == ops[i].operand[1].reg
3421 && ops[i].operand[0].reg == reg)
3424 if (ops[i].regmask_dst & (1 << reg))
3431 static void patch_esp_adjust(struct parsed_op *po, int adj)
3433 ferr_assert(po, po->op == OP_ADD);
3434 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3435 ferr_assert(po, po->operand[1].type == OPT_CONST);
3437 // this is a bit of a hack, but deals with use of
3438 // single adj for multiple calls
3439 po->operand[1].val -= adj;
3440 po->flags |= OPF_RMD;
3441 if (po->operand[1].val == 0)
3442 po->flags |= OPF_DONE;
3443 ferr_assert(po, (int)po->operand[1].val >= 0);
3446 // scan for positive, constant esp adjust
3447 // multipath case is preliminary
3448 static int scan_for_esp_adjust(int i, int opcnt,
3449 int adj_expect, int *adj, int *is_multipath, int do_update)
3451 int adj_expect_unknown = 0;
3452 struct parsed_op *po;
3456 *adj = *is_multipath = 0;
3457 if (adj_expect < 0) {
3458 adj_expect_unknown = 1;
3459 adj_expect = 32 * 4; // enough?
3462 for (; i < opcnt && *adj < adj_expect; i++) {
3463 if (g_labels[i] != NULL)
3467 if (po->flags & OPF_DONE)
3470 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3471 if (po->operand[1].type != OPT_CONST)
3472 ferr(&ops[i], "non-const esp adjust?\n");
3473 *adj += po->operand[1].val;
3475 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3478 patch_esp_adjust(po, adj_expect);
3480 po->flags |= OPF_RMD;
3484 else if (po->op == OP_PUSH) {
3485 //if (first_pop == -1)
3486 // first_pop = -2; // none
3487 *adj -= lmod_bytes(po, po->operand[0].lmod);
3489 else if (po->op == OP_POP) {
3490 if (!(po->flags & OPF_DONE)) {
3491 // seems like msvc only uses 'pop ecx' for stack realignment..
3492 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3494 if (first_pop == -1 && *adj >= 0)
3497 if (do_update && *adj >= 0) {
3498 po->flags |= OPF_RMD;
3500 po->flags |= OPF_DONE | OPF_NOREGS;
3503 *adj += lmod_bytes(po, po->operand[0].lmod);
3504 if (*adj > adj_best)
3507 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3508 if (po->op == OP_JMP && po->btj == NULL) {
3514 if (po->op != OP_CALL)
3516 if (po->operand[0].type != OPT_LABEL)
3518 if (po->pp != NULL && po->pp->is_stdcall)
3520 if (adj_expect_unknown && first_pop >= 0)
3522 // assume it's another cdecl call
3526 if (first_pop >= 0) {
3527 // probably only 'pop ecx' was used
3535 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3537 struct parsed_op *po;
3541 ferr(ops, "%s: followed bad branch?\n", __func__);
3543 for (; i < opcnt; i++) {
3545 if (po->cc_scratch == magic)
3547 po->cc_scratch = magic;
3550 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3551 if (po->btj != NULL) {
3553 for (j = 0; j < po->btj->count; j++)
3554 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3558 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3559 if (!(po->flags & OPF_CJMP))
3562 if (po->flags & OPF_TAIL)
3567 static const struct parsed_proto *try_recover_pp(
3568 struct parsed_op *po, const struct parsed_opr *opr,
3569 int is_call, int *search_instead)
3571 const struct parsed_proto *pp = NULL;
3575 if (po->pp != NULL && (po->flags & OPF_DATA)) {
3576 // hint given in asm
3580 // maybe an arg of g_func?
3581 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3583 char ofs_reg[16] = { 0, };
3584 int arg, arg_s, arg_i;
3591 parse_stack_access(po, opr->name, ofs_reg,
3592 &offset, &stack_ra, NULL, 0);
3593 if (ofs_reg[0] != 0)
3594 ferr(po, "offset reg on arg access?\n");
3595 if (offset <= stack_ra) {
3596 // search who set the stack var instead
3597 if (search_instead != NULL)
3598 *search_instead = 1;
3602 arg_i = (offset - stack_ra - 4) / 4;
3603 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3604 if (g_func_pp->arg[arg].reg != NULL)
3610 if (arg == g_func_pp->argc)
3611 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3613 pp = g_func_pp->arg[arg].pp;
3616 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3617 check_func_pp(po, pp, "icall arg");
3620 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3622 p = strchr(opr->name + 1, '[');
3623 memcpy(buf, opr->name, p - opr->name);
3624 buf[p - opr->name] = 0;
3625 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3627 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3628 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3631 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3634 check_func_pp(po, pp, "reg-fptr ref");
3640 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3641 int magic, int is_call_op, const struct parsed_proto **pp_found,
3642 int *pp_i, int *multi)
3644 const struct parsed_proto *pp = NULL;
3645 struct parsed_op *po;
3646 struct label_ref *lr;
3648 ops[i].cc_scratch = magic;
3651 if (g_labels[i] != NULL) {
3652 lr = &g_label_refs[i];
3653 for (; lr != NULL; lr = lr->next) {
3654 check_i(&ops[i], lr->i);
3655 scan_for_call_type(lr->i, opr, magic, is_call_op,
3656 pp_found, pp_i, multi);
3658 if (i > 0 && LAST_OP(i - 1))
3666 if (ops[i].cc_scratch == magic)
3668 ops[i].cc_scratch = magic;
3670 if (!(ops[i].flags & OPF_DATA))
3672 if (!is_opr_modified(opr, &ops[i]))
3674 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3675 // most probably trashed by some processing
3680 opr = &ops[i].operand[1];
3681 if (opr->type != OPT_REG)
3685 po = (i >= 0) ? &ops[i] : ops;
3688 // reached the top - can only be an arg-reg
3689 if (opr->type != OPT_REG || g_func_pp == NULL)
3692 for (i = 0; i < g_func_pp->argc; i++) {
3693 if (g_func_pp->arg[i].reg == NULL)
3695 if (IS(opr->name, g_func_pp->arg[i].reg))
3698 if (i == g_func_pp->argc)
3700 pp = g_func_pp->arg[i].pp;
3703 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3704 i + 1, g_func_pp->arg[i].reg);
3707 check_func_pp(po, pp, "icall reg-arg");
3710 pp = try_recover_pp(po, opr, is_call_op, NULL);
3712 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3713 if (pp_cmp_func(*pp_found, pp)) {
3714 if (pp_i != NULL && *pp_i != -1)
3715 fnote(&ops[*pp_i], "(other ref)\n");
3716 ferr(po, "icall: parsed_proto mismatch\n");
3728 static void add_label_ref(struct label_ref *lr, int op_i)
3730 struct label_ref *lr_new;
3737 lr_new = calloc(1, sizeof(*lr_new));
3739 lr_new->next = lr->next;
3743 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3745 struct parsed_op *po = &ops[i];
3746 struct parsed_data *pd;
3747 char label[NAMELEN], *p;
3750 p = strchr(po->operand[0].name, '[');
3754 len = p - po->operand[0].name;
3755 strncpy(label, po->operand[0].name, len);
3758 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3759 if (IS(g_func_pd[j].label, label)) {
3765 //ferr(po, "label '%s' not parsed?\n", label);
3768 if (pd->type != OPT_OFFSET)
3769 ferr(po, "label '%s' with non-offset data?\n", label);
3771 // find all labels, link
3772 for (j = 0; j < pd->count; j++) {
3773 for (l = 0; l < opcnt; l++) {
3774 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3775 add_label_ref(&g_label_refs[l], i);
3785 static void clear_labels(int count)
3789 for (i = 0; i < count; i++) {
3790 if (g_labels[i] != NULL) {
3797 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3802 for (i = 0; i < pp->argc; i++) {
3803 if (pp->arg[i].reg != NULL) {
3804 reg = char_array_i(regs_r32,
3805 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3807 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3808 pp->arg[i].reg, pp->name);
3809 regmask |= 1 << reg;
3816 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3821 if (pp->has_retreg) {
3822 for (i = 0; i < pp->argc; i++) {
3823 if (pp->arg[i].type.is_retreg) {
3824 reg = char_array_i(regs_r32,
3825 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3826 ferr_assert(ops, reg >= 0);
3827 regmask |= 1 << reg;
3832 if (strstr(pp->ret_type.name, "int64"))
3833 return regmask | (1 << xAX) | (1 << xDX);
3834 if (IS(pp->ret_type.name, "float")
3835 || IS(pp->ret_type.name, "double"))
3837 return regmask | mxST0;
3839 if (strcasecmp(pp->ret_type.name, "void") == 0)
3842 return regmask | mxAX;
3845 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3847 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3848 && memcmp(po1->operand, po2->operand,
3849 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3852 static void resolve_branches_parse_calls(int opcnt)
3854 static const struct {
3858 unsigned int regmask_src;
3859 unsigned int regmask_dst;
3861 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3862 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3863 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3864 // more precise? Wine gets away with just __ftol handler
3865 { "__ftol2", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3866 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3868 const struct parsed_proto *pp_c;
3869 struct parsed_proto *pp;
3870 struct parsed_data *pd;
3871 struct parsed_op *po;
3872 const char *tmpname;
3877 for (i = 0; i < opcnt; i++)
3883 if (po->datap != NULL) {
3884 pp = calloc(1, sizeof(*pp));
3885 my_assert_not(pp, NULL);
3887 ret = parse_protostr(po->datap, pp);
3889 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3895 if (po->op == OP_CALL) {
3900 else if (po->operand[0].type == OPT_LABEL)
3902 tmpname = opr_name(po, 0);
3903 if (IS_START(tmpname, "loc_")) {
3905 ferr(po, "call to loc_*\n");
3906 // eliminate_seh() must take care of it
3909 if (IS(tmpname, "__alloca_probe"))
3911 if (IS(tmpname, "__SEH_prolog")) {
3912 ferr_assert(po, g_seh_found == 0);
3916 if (IS(tmpname, "__SEH_epilog"))
3919 // convert some calls to pseudo-ops
3920 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3921 if (!IS(tmpname, pseudo_ops[l].name))
3924 po->op = pseudo_ops[l].op;
3925 po->operand_cnt = 0;
3926 po->regmask_src = pseudo_ops[l].regmask_src;
3927 po->regmask_dst = pseudo_ops[l].regmask_dst;
3928 po->flags &= OPF_TAIL;
3929 po->flags |= pseudo_ops[l].flags;
3930 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3933 if (l < ARRAY_SIZE(pseudo_ops))
3936 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3937 if (!g_header_mode && pp_c == NULL)
3938 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3941 pp = proto_clone(pp_c);
3942 my_assert_not(pp, NULL);
3948 check_func_pp(po, pp, "fptr var call");
3949 if (pp->is_noreturn) {
3950 po->flags |= OPF_TAIL;
3951 po->flags &= ~OPF_ATAIL; // most likely...
3958 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3961 if (po->operand[0].type == OPT_REGMEM) {
3962 pd = try_resolve_jumptab(i, opcnt);
3970 for (l = 0; l < opcnt; l++) {
3971 if (g_labels[l] != NULL
3972 && IS(po->operand[0].name, g_labels[l]))
3974 if (l == i + 1 && po->op == OP_JMP) {
3975 // yet another alignment type...
3976 po->flags |= OPF_RMD | OPF_DONE;
3977 po->flags &= ~OPF_JMP;
3981 add_label_ref(&g_label_refs[l], i);
3987 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3990 if (po->operand[0].type == OPT_LABEL
3991 || po->operand[0].type == OPT_REG)
3995 ferr(po, "unhandled branch\n");
3999 po->flags |= OPF_TAIL;
4000 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
4001 if (prev_op == OP_POP)
4002 po->flags |= OPF_ATAIL;
4003 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
4004 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
4006 po->flags |= OPF_ATAIL;
4012 static int resolve_origin(int i, const struct parsed_opr *opr,
4013 int magic, int *op_i, int *is_caller);
4014 static void set_label(int i, const char *name);
4016 static void eliminate_seh_writes(int opcnt)
4018 const struct parsed_opr *opr;
4023 // assume all sf writes above g_seh_size to be seh related
4024 // (probably unsafe but oh well)
4025 for (i = 0; i < opcnt; i++) {
4026 if (ops[i].op != OP_MOV)
4028 opr = &ops[i].operand[0];
4029 if (opr->type != OPT_REGMEM)
4031 if (!is_stack_access(&ops[i], opr))
4035 parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
4037 if (offset < 0 && offset >= -g_seh_size)
4038 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4042 static void eliminate_seh_finally(int opcnt)
4044 const char *target_name = NULL;
4045 const char *return_name = NULL;
4046 int exits[MAX_EXITS];
4054 for (i = 0; i < opcnt; i++) {
4055 if (ops[i].op != OP_CALL)
4057 if (!IS_START(opr_name(&ops[i], 0), "loc_"))
4059 if (target_name != NULL)
4060 ferr(&ops[i], "multiple finally calls? (last was %s)\n",
4062 target_name = opr_name(&ops[i], 0);
4065 if (g_labels[i + 1] == NULL)
4066 set_label(i + 1, "seh_fin_done");
4067 return_name = g_labels[i + 1];
4075 // find finally code (bt_i is not set because it's call)
4076 for (i = 0; i < opcnt; i++) {
4077 if (g_labels[i] == NULL)
4079 if (!IS(g_labels[i], target_name))
4082 ferr_assert(&ops[i], target_i == -1);
4085 ferr_assert(&ops[0], target_i != -1);
4087 find_reachable_exits(target_i, opcnt, target_i + opcnt * 24,
4088 exits, &exit_count);
4089 ferr_assert(&ops[target_i], exit_count == 1);
4090 ferr_assert(&ops[target_i], ops[exits[0]].op == OP_RET);
4093 // convert to jumps, link
4094 ops[call_i].op = OP_JMP;
4095 ops[call_i].bt_i = target_i;
4096 add_label_ref(&g_label_refs[target_i], call_i);
4098 ops[tgend_i].op = OP_JMP;
4099 ops[tgend_i].flags &= ~OPF_TAIL;
4100 ops[tgend_i].flags |= OPF_JMP;
4101 ops[tgend_i].bt_i = return_i;
4102 ops[tgend_i].operand_cnt = 1;
4103 ops[tgend_i].operand[0].type = OPT_LABEL;
4104 snprintf(ops[tgend_i].operand[0].name, NAMELEN, "%s", return_name);
4105 add_label_ref(&g_label_refs[return_i], tgend_i);
4107 // rm seh finally entry code
4108 for (i = target_i - 1; i >= 0; i--) {
4109 if (g_labels[i] != NULL && g_label_refs[i].i != -1)
4111 if (ops[i].flags & OPF_CJMP)
4113 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4116 for (i = target_i - 1; i >= 0; i--) {
4117 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4119 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4123 static void eliminate_seh(int opcnt)
4127 for (i = 0; i < opcnt; i++) {
4128 if (ops[i].op != OP_MOV)
4130 if (ops[i].operand[0].segment != SEG_FS)
4132 if (!IS(opr_name(&ops[i], 0), "0"))
4135 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4136 if (ops[i].operand[1].reg == xSP) {
4137 for (j = i - 1; j >= 0; j--) {
4138 if (ops[j].op != OP_PUSH)
4140 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4142 if (ops[j].operand[0].val == ~0)
4144 if (ops[j].operand[0].type == OPT_REG) {
4146 ret = resolve_origin(j, &ops[j].operand[0],
4147 j + opcnt * 22, &k, NULL);
4149 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4153 ferr(ops, "missing seh terminator\n");
4157 ret = resolve_origin(i, &ops[i].operand[1],
4158 i + opcnt * 23, &k, NULL);
4160 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4164 eliminate_seh_writes(opcnt);
4165 eliminate_seh_finally(opcnt);
4168 static void eliminate_seh_calls(int opcnt)
4170 int epilog_found = 0;
4177 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4178 && ops[i].operand[0].type == OPT_CONST);
4179 g_stack_fsz = g_seh_size + ops[i].operand[0].val;
4180 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4183 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4184 && ops[i].operand[0].type == OPT_OFFSET);
4185 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4188 ferr_assert(&ops[i], ops[i].op == OP_CALL
4189 && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
4190 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4192 for (i++; i < opcnt; i++) {
4193 if (ops[i].op != OP_CALL)
4195 if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
4198 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4201 ferr_assert(ops, epilog_found);
4203 eliminate_seh_writes(opcnt);
4204 eliminate_seh_finally(opcnt);
4207 // check for prologue of many pushes and epilogue with pops
4208 static void check_simple_sequence(int opcnt, int *fsz)
4217 for (i = 0; i < opcnt && i < ARRAY_SIZE(seq); i++) {
4218 if (ops[i].op != OP_PUSH || ops[i].operand[0].type != OPT_REG)
4220 reg = ops[i].operand[0].reg;
4221 if (reg != xBX && reg != xSI && reg != xDI && reg != xBP)
4223 for (j = 0; j < i; j++)
4227 // probably something else is going on here
4235 for (; i < opcnt && seq_len > 0; i++) {
4236 if (!(ops[i].flags & OPF_TAIL))
4239 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4240 if (ops[j].op != OP_POP || ops[j].operand[0].type != OPT_REG)
4242 if (ops[j].operand[0].reg != seq[seq_p])
4246 found = seq_len = seq_p;
4251 for (i = 0; i < seq_len; i++)
4252 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4254 for (; i < opcnt && seq_len > 0; i++) {
4255 if (!(ops[i].flags & OPF_TAIL))
4258 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4259 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4264 // unlike pushes after sub esp,
4265 // IDA treats pushes like this as part of var area
4266 *fsz += seq_len * 4;
4269 static int scan_prologue_ecx(int i, int opcnt, int flags_set,
4270 int limit, int *ecx_push_out)
4272 const struct parsed_proto *pp;
4273 int ecx_push = 0, other_push = 0;
4276 while (limit > 0 && ops[i].op == OP_PUSH
4277 && IS(opr_name(&ops[i], 0), "ecx"))
4279 ops[i].flags |= flags_set;
4286 if (ecx_push == 0 || flags_set != 0)
4289 // check if some of the pushes aren't really call args
4290 for (; i < opcnt; i++) {
4291 if (i > 0 && g_labels[i] != NULL)
4293 if (ops[i].flags & (OPF_JMP|OPF_TAIL))
4295 if (ops[i].op == OP_PUSH)
4299 if (ops[i].op != OP_CALL)
4303 if (pp == NULL && ops[i].operand[0].type == OPT_LABEL)
4304 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4308 ferr_assert(&ops[i], ecx_push + other_push >= pp->argc_stack);
4309 if (other_push < pp->argc_stack)
4310 ecx_push -= pp->argc_stack - other_push;
4313 if (ecx_push_out != NULL)
4314 *ecx_push_out = ecx_push;
4318 static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4324 for (; i < opcnt; i++)
4325 if (!(ops[i].flags & OPF_DONE))
4328 ret = scan_prologue_ecx(i, opcnt, 0, 4, &ecx_tmp);
4330 scan_prologue_ecx(i, opcnt, OPF_RMD | OPF_DONE | OPF_NOREGS,
4332 g_stack_fsz += 4 * ecx_tmp;
4333 *ecx_push += ecx_tmp;
4337 for (; i < opcnt; i++) {
4338 if (i > 0 && g_labels[i] != NULL)
4340 if (ops[i].flags & (OPF_JMP|OPF_TAIL))
4342 if (ops[i].flags & OPF_DONE)
4344 if (ops[i].op == OP_PUSH)
4346 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4347 && ops[i].operand[1].type == OPT_CONST)
4349 g_stack_fsz += opr_const(&ops[i], 1);
4350 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4355 if (ops[i].op == OP_LEA && ops[i].operand[0].reg == xSP
4356 && ops[i].operand[1].type == OPT_REGMEM
4357 && IS_START(ops[i].operand[1].name, "esp-"))
4359 name = ops[i].operand[1].name;
4360 ret = sscanf(name, "esp-%x%n", &j, &len);
4361 ferr_assert(&ops[i], ret == 1 && len == strlen(name));
4363 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4368 if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4369 && ops[i].operand[1].type == OPT_CONST)
4371 for (j = i + 1; j < opcnt; j++)
4372 if (!(ops[j].flags & OPF_DONE))
4374 if (ops[j].op == OP_CALL
4375 && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4377 g_stack_fsz += opr_const(&ops[i], 1);
4378 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4379 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4390 static void scan_prologue_epilogue(int opcnt, int *stack_align)
4392 int ecx_push = 0, esp_sub = 0, pusha = 0;
4393 int sandard_epilogue;
4394 int found, ret, len;
4398 if (g_seh_found == 2) {
4399 eliminate_seh_calls(opcnt);
4403 eliminate_seh(opcnt);
4404 // ida treats seh as part of sf
4405 g_stack_fsz = g_seh_size;
4409 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4410 && ops[1].op == OP_MOV
4411 && IS(opr_name(&ops[1], 0), "ebp")
4412 && IS(opr_name(&ops[1], 1), "esp"))
4415 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4416 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4418 for (i = 2; i < opcnt; i++)
4419 if (!(ops[i].flags & OPF_DONE))
4422 if (ops[i].op == OP_PUSHA) {
4423 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4428 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4429 && ops[i].operand[1].type == OPT_CONST)
4431 l = ops[i].operand[1].val;
4433 if (j == -1 || (l >> j) != -1)
4434 ferr(&ops[i], "unhandled esp align: %x\n", l);
4435 if (stack_align != NULL)
4436 *stack_align = 1 << j;
4437 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4441 i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4445 for (; i < opcnt; i++)
4446 if (ops[i].flags & OPF_TAIL)
4449 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4450 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4456 sandard_epilogue = 0;
4457 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4459 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4460 // the standard epilogue is sometimes even used without a sf
4461 if (ops[j - 1].op == OP_MOV
4462 && IS(opr_name(&ops[j - 1], 0), "esp")
4463 && IS(opr_name(&ops[j - 1], 1), "ebp"))
4464 sandard_epilogue = 1;
4466 else if (ops[j].op == OP_LEAVE)
4468 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4469 sandard_epilogue = 1;
4471 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4472 && ops[i].pp->is_noreturn)
4474 // on noreturn, msvc sometimes cleans stack, sometimes not
4479 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4480 ferr(&ops[j], "'pop ebp' expected\n");
4482 if (g_stack_fsz != 0 || sandard_epilogue) {
4483 if (ops[j].op == OP_LEAVE)
4485 else if (sandard_epilogue) // mov esp, ebp
4487 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4490 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4492 ferr(&ops[j], "esp restore expected\n");
4495 if (ecx_push && j >= 0 && ops[j].op == OP_POP
4496 && IS(opr_name(&ops[j], 0), "ecx"))
4498 ferr(&ops[j], "unexpected ecx pop\n");
4503 if (ops[j].op == OP_POPA)
4504 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4506 ferr(&ops[j], "popa expected\n");
4511 } while (i < opcnt);
4514 ferr(ops, "missing ebp epilogue\n");
4519 check_simple_sequence(opcnt, &push_fsz);
4520 i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4523 if (ecx_push || esp_sub)
4528 for (; i < opcnt; i++)
4529 if (ops[i].flags & OPF_TAIL)
4533 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4534 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4539 else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4540 // skip arg updates for arg-reuse tailcall
4541 for (; j >= 0; j--) {
4542 if (ops[j].op != OP_MOV)
4544 if (ops[j].operand[0].type == OPT_REGMEM
4545 && strstr(ops[j].operand[0].name, "arg_") != NULL)
4547 if (ops[j].operand[0].type == OPT_REG)
4548 continue; // assume arg-reg mov
4553 for (; j >= 0; j--) {
4554 if ((ops[j].flags & (OPF_RMD | OPF_DONE | OPF_NOREGS)) !=
4555 (OPF_RMD | OPF_DONE | OPF_NOREGS))
4559 if (ecx_push > 0 && !esp_sub) {
4560 for (l = 0; l < ecx_push && j >= 0; l++) {
4561 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4563 else if (ops[j].op == OP_ADD
4564 && IS(opr_name(&ops[j], 0), "esp")
4565 && ops[j].operand[1].type == OPT_CONST)
4568 l += ops[j].operand[1].val / 4 - 1;
4573 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4576 if (l != ecx_push) {
4577 if (i < opcnt && ops[i].op == OP_CALL
4578 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4580 // noreturn tailcall with no epilogue
4585 ferr(&ops[j], "epilogue scan failed\n");
4592 if (ops[j].op == OP_ADD
4593 && IS(opr_name(&ops[j], 0), "esp")
4594 && ops[j].operand[1].type == OPT_CONST)
4596 if (ops[j].operand[1].val < g_stack_fsz)
4597 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4599 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4600 if (ops[j].operand[1].val == 0)
4601 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4604 else if (ops[j].op == OP_LEA && ops[j].operand[0].reg == xSP
4605 && ops[j].operand[1].type == OPT_REGMEM
4606 && IS_START(ops[j].operand[1].name, "esp+"))
4608 const char *name = ops[j].operand[1].name;
4609 ret = sscanf(name, "esp+%x%n", &l, &len);
4610 ferr_assert(&ops[j], ret == 1 && len == strlen(name));
4611 ferr_assert(&ops[j], l <= g_stack_fsz);
4612 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4615 else if (i < opcnt && ops[i].op == OP_CALL
4616 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4618 // noreturn tailcall with no epilogue
4622 ferr(&ops[j], "'add esp' expected\n");
4626 } while (i < opcnt);
4629 ferr(ops, "missing esp epilogue\n");
4632 if (g_stack_fsz != 0)
4633 // see check_simple_sequence
4634 g_stack_fsz += push_fsz;
4637 // find an instruction that changed opr before i op
4638 // *op_i must be set to -1 by the caller
4639 // *is_caller is set to 1 if one source is determined to be g_func arg
4640 // returns 1 if found, *op_i is then set to origin
4641 // returns -1 if multiple origins are found
4642 static int resolve_origin(int i, const struct parsed_opr *opr,
4643 int magic, int *op_i, int *is_caller)
4645 struct label_ref *lr;
4649 if (g_labels[i] != NULL) {
4650 lr = &g_label_refs[i];
4651 for (; lr != NULL; lr = lr->next) {
4652 check_i(&ops[i], lr->i);
4653 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4655 if (i > 0 && LAST_OP(i - 1))
4661 if (is_caller != NULL)
4666 if (ops[i].cc_scratch == magic)
4668 ops[i].cc_scratch = magic;
4670 if (!(ops[i].flags & OPF_DATA))
4672 if (!is_opr_modified(opr, &ops[i]))
4676 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4687 static int resolve_origin_reg(int i, int reg, int magic, int *op_i,
4690 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4693 if (is_caller != NULL)
4695 return resolve_origin(i, &opr, magic, op_i, is_caller);
4698 // find an instruction that previously referenced opr
4699 // if multiple results are found - fail
4700 // *op_i must be set to -1 by the caller
4701 // returns 1 if found, *op_i is then set to referencer insn
4702 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4703 int magic, int *op_i)
4705 struct label_ref *lr;
4709 if (g_labels[i] != NULL) {
4710 lr = &g_label_refs[i];
4711 for (; lr != NULL; lr = lr->next) {
4712 check_i(&ops[i], lr->i);
4713 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4715 if (i > 0 && LAST_OP(i - 1))
4723 if (ops[i].cc_scratch == magic)
4725 ops[i].cc_scratch = magic;
4727 if (!is_opr_referenced(opr, &ops[i]))
4738 // adjust datap of all reachable 'op' insns when moving back
4739 // returns 1 if at least 1 op was found
4740 // returns -1 if path without an op was found
4741 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4743 struct label_ref *lr;
4746 if (ops[i].cc_scratch == magic)
4748 ops[i].cc_scratch = magic;
4751 if (g_labels[i] != NULL) {
4752 lr = &g_label_refs[i];
4753 for (; lr != NULL; lr = lr->next) {
4754 check_i(&ops[i], lr->i);
4755 ret |= adjust_prev_op(lr->i, op, magic, datap);
4757 if (i > 0 && LAST_OP(i - 1))
4765 if (ops[i].cc_scratch == magic)
4767 ops[i].cc_scratch = magic;
4769 if (ops[i].op != op)
4772 ops[i].datap = datap;
4777 // find next instruction that reads opr
4778 // *op_i must be set to -1 by the caller
4779 // on return, *op_i is set to first referencer insn
4780 // returns 1 if exactly 1 referencer is found
4781 static int find_next_read(int i, int opcnt,
4782 const struct parsed_opr *opr, int magic, int *op_i)
4784 struct parsed_op *po;
4787 for (; i < opcnt; i++)
4789 if (ops[i].cc_scratch == magic)
4791 ops[i].cc_scratch = magic;
4794 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4795 if (po->btj != NULL) {
4797 for (j = 0; j < po->btj->count; j++) {
4798 check_i(po, po->btj->d[j].bt_i);
4799 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4805 if (po->flags & OPF_RMD)
4807 check_i(po, po->bt_i);
4808 if (po->flags & OPF_CJMP) {
4809 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4818 if (!is_opr_read(opr, po)) {
4820 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4821 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4823 full_opr = po->operand[0].lmod >= opr->lmod;
4825 if (is_opr_modified(opr, po) && full_opr) {
4829 if (po->flags & OPF_TAIL)
4844 static int find_next_read_reg(int i, int opcnt, int reg,
4845 enum opr_lenmod lmod, int magic, int *op_i)
4847 struct parsed_opr opr = OPR_INIT(OPT_REG, lmod, reg);
4850 return find_next_read(i, opcnt, &opr, magic, op_i);
4853 // find next instruction that reads opr
4854 // *op_i must be set to -1 by the caller
4855 // on return, *op_i is set to first flag user insn
4856 // returns 1 if exactly 1 flag user is found
4857 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4859 struct parsed_op *po;
4862 for (; i < opcnt; i++)
4864 if (ops[i].cc_scratch == magic)
4866 ops[i].cc_scratch = magic;
4869 if (po->op == OP_CALL)
4871 if (po->flags & OPF_JMP) {
4872 if (po->btj != NULL) {
4874 for (j = 0; j < po->btj->count; j++) {
4875 check_i(po, po->btj->d[j].bt_i);
4876 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4882 if (po->flags & OPF_RMD)
4884 check_i(po, po->bt_i);
4885 if (po->flags & OPF_CJMP)
4892 if (!(po->flags & OPF_CC)) {
4893 if (po->flags & OPF_FLAGS)
4896 if (po->flags & OPF_TAIL)
4912 static int try_resolve_const(int i, const struct parsed_opr *opr,
4913 int magic, unsigned int *val)
4918 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4921 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4924 *val = ops[i].operand[1].val;
4931 static int resolve_used_bits(int i, int opcnt, int reg,
4932 int *mask, int *is_z_check)
4934 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4938 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4942 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4944 fnote(&ops[j], "(first read)\n");
4945 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4948 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4949 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4951 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4952 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4954 *mask = ops[j].operand[1].val;
4955 if (ops[j].operand[0].lmod == OPLM_BYTE
4956 && ops[j].operand[0].name[1] == 'h')
4960 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4963 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4965 *is_z_check = ops[k].pfo == PFO_Z;
4970 static const struct parsed_proto *resolve_deref(int i, int magic,
4971 const struct parsed_opr *opr, int level)
4973 const struct parsed_proto *pp = NULL;
4974 int from_caller = 0;
4983 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4984 if (ret != 2 || len != strlen(opr->name)) {
4985 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4986 if (ret != 1 || len != strlen(opr->name))
4990 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4994 ret = resolve_origin_reg(i, reg, i + magic, &j, NULL);
4998 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4999 && strlen(ops[j].operand[1].name) == 3
5000 && ops[j].operand[0].lmod == OPLM_DWORD
5001 && ops[j].pp == NULL // no hint
5004 // allow one simple dereference (com/directx)
5005 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
5006 ops[j].operand[1].name);
5009 ret = resolve_origin_reg(j, reg, j + magic, &k, NULL);
5014 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
5017 if (ops[j].pp != NULL) {
5021 else if (ops[j].operand[1].type == OPT_REGMEM) {
5022 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
5024 // maybe structure ptr in structure
5025 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
5028 else if (ops[j].operand[1].type == OPT_LABEL)
5029 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
5030 else if (ops[j].operand[1].type == OPT_REG) {
5033 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
5035 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
5036 for (k = 0; k < g_func_pp->argc; k++) {
5037 if (g_func_pp->arg[k].reg == NULL)
5039 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
5040 pp = g_func_pp->arg[k].pp;
5049 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
5051 ferr(&ops[j], "expected struct, got '%s %s'\n",
5052 pp->type.name, pp->name);
5056 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
5059 static const struct parsed_proto *resolve_func_ptr(int i, int opcnt,
5060 int is_call_op, const struct parsed_opr *opr,
5061 int *pp_i, int *multi_src)
5063 const struct parsed_proto *pp = NULL;
5064 int search_advice = 0;
5066 if (multi_src != NULL)
5071 switch (opr->type) {
5073 // try to resolve struct member calls
5074 pp = resolve_deref(i, i + opcnt * 19, opr, 0);
5080 pp = try_recover_pp(&ops[i], opr, is_call_op, &search_advice);
5085 scan_for_call_type(i, opr, i + opcnt * 9, is_call_op,
5086 &pp, pp_i, multi_src);
5093 static struct parsed_proto *process_call_early(int i, int opcnt,
5096 struct parsed_op *po = &ops[i];
5097 struct parsed_proto *pp;
5103 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
5107 // look for and make use of esp adjust
5109 if (!pp->is_stdcall && pp->argc_stack > 0)
5110 ret = scan_for_esp_adjust(i + 1, opcnt,
5111 pp->argc_stack * 4, &adj, &multipath, 0);
5113 if (pp->argc_stack > adj / 4)
5117 if (ops[ret].op == OP_POP) {
5118 for (j = 1; j < adj / 4; j++) {
5119 if (ops[ret + j].op != OP_POP
5120 || ops[ret + j].operand[0].reg != xCX)
5132 static struct parsed_proto *process_call(int i, int opcnt)
5134 struct parsed_op *po = &ops[i];
5135 const struct parsed_proto *pp_c;
5136 struct parsed_proto *pp;
5137 const char *tmpname;
5138 int call_i = -1, ref_i = -1;
5139 int adj = 0, multipath = 0;
5142 tmpname = opr_name(po, 0);
5147 pp_c = resolve_func_ptr(i, opcnt, 1, &ops[i].operand[0],
5148 &call_i, &multipath);
5150 if (!pp_c->is_func && !pp_c->is_fptr)
5151 ferr(po, "call to non-func: %s\n", pp_c->name);
5152 pp = proto_clone(pp_c);
5153 my_assert_not(pp, NULL);
5155 // not resolved just to single func
5158 switch (po->operand[0].type) {
5160 // we resolved this call and no longer need the register
5161 po->regmask_src &= ~(1 << po->operand[0].reg);
5163 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
5164 && ops[call_i].operand[1].type == OPT_LABEL)
5166 // no other source users?
5167 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
5169 if (ret == 1 && call_i == ref_i) {
5170 // and nothing uses it after us?
5172 find_next_read(i + 1, opcnt, &po->operand[0],
5173 i + opcnt * 11, &ref_i);
5175 // then also don't need the source mov
5176 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
5188 pp = calloc(1, sizeof(*pp));
5189 my_assert_not(pp, NULL);
5192 ret = scan_for_esp_adjust(i + 1, opcnt,
5193 -1, &adj, &multipath, 0);
5194 if (ret < 0 || adj < 0) {
5195 if (!g_allow_regfunc)
5196 ferr(po, "non-__cdecl indirect call unhandled yet\n");
5197 pp->is_unresolved = 1;
5201 if (adj > ARRAY_SIZE(pp->arg))
5202 ferr(po, "esp adjust too large: %d\n", adj);
5203 pp->ret_type.name = strdup("int");
5204 pp->argc = pp->argc_stack = adj;
5205 for (arg = 0; arg < pp->argc; arg++)
5206 pp->arg[arg].type.name = strdup("int");
5211 // look for and make use of esp adjust
5214 if (!pp->is_stdcall && pp->argc_stack > 0) {
5215 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
5216 ret = scan_for_esp_adjust(i + 1, opcnt,
5217 adj_expect, &adj, &multipath, 0);
5220 if (pp->is_vararg) {
5221 if (adj / 4 < pp->argc_stack) {
5222 fnote(po, "(this call)\n");
5223 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
5224 adj, pp->argc_stack * 4);
5226 // modify pp to make it have varargs as normal args
5228 pp->argc += adj / 4 - pp->argc_stack;
5229 for (; arg < pp->argc; arg++) {
5230 pp->arg[arg].type.name = strdup("int");
5233 if (pp->argc > ARRAY_SIZE(pp->arg))
5234 ferr(po, "too many args for '%s'\n", tmpname);
5236 if (pp->argc_stack > adj / 4) {
5237 if (pp->is_noreturn)
5238 // assume no stack adjust was emited
5240 fnote(po, "(this call)\n");
5241 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
5242 tmpname, pp->argc_stack * 4, adj);
5245 scan_for_esp_adjust(i + 1, opcnt,
5246 pp->argc_stack * 4, &adj, &multipath, 1);
5248 else if (pp->is_vararg)
5249 ferr(po, "missing esp_adjust for vararg func '%s'\n",
5256 static void check_fptr_args(int i, int opcnt, struct parsed_proto *pp)
5258 struct parsed_opr s_opr = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
5259 const struct parsed_proto *pp_arg, *pp_cmp;
5260 const struct parsed_op *po_a;
5267 for (arg = 0; arg < pp->argc; arg++) {
5271 pp_arg = pp->arg[arg].pp;
5272 if (pp_arg == NULL || !pp_arg->is_func)
5275 s_reg = pp->arg[arg].reg;
5276 if (s_reg != NULL) {
5277 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
5278 ferr_assert(&ops[i], reg >= 0);
5280 scan_for_call_type(i, &s_opr, i + arg + opcnt * 28, 0,
5281 &pp_cmp, &pp_cmp_i, NULL);
5282 if (pp_cmp != NULL && !pp_compatible_func(pp_arg, pp_cmp)) {
5285 fnote(&ops[pp_cmp_i], "(referenced here)\n");
5289 for (j = 0; j < pp->arg[arg].push_ref_cnt; j++) {
5290 po_a = pp->arg[arg].push_refs[j];
5291 if (po_a == NULL || po_a->op != OP_PUSH)
5293 pp_cmp = resolve_func_ptr(po_a - ops, opcnt, 0,
5294 &po_a->operand[0], &pp_cmp_i, NULL);
5295 if (pp_cmp != NULL && !pp_compatible_func(pp_arg, pp_cmp)) {
5298 pp_cmp_i = po_a - ops;
5300 fnote(&ops[pp_cmp_i], "(referenced here)\n");
5306 ferr(&ops[i], "incompatible fptr arg %d\n", arg + 1);
5310 static void pp_add_push_ref(struct parsed_proto *pp,
5311 int arg, struct parsed_op *po)
5313 pp->arg[arg].push_refs = realloc(pp->arg[arg].push_refs,
5314 (pp->arg[arg].push_ref_cnt + 1)
5315 * sizeof(pp->arg[arg].push_refs[0]));
5316 ferr_assert(po, pp->arg[arg].push_refs != NULL);
5317 pp->arg[arg].push_refs[pp->arg[arg].push_ref_cnt++] = po;
5320 static void mark_float_arg(struct parsed_op *po,
5321 struct parsed_proto *pp, int arg, int *regmask_ffca)
5323 ferr_assert(po, pp->arg[arg].push_ref_cnt == 0);
5324 pp_add_push_ref(pp, arg, po);
5326 po->p_argnum = arg + 1;
5327 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
5328 if (regmask_ffca != NULL)
5329 *regmask_ffca |= 1 << arg;
5332 static int check_for_stp(int i, int i_to)
5334 struct parsed_op *po;
5336 for (; i < i_to; i++) {
5338 if (po->op == OP_FST)
5340 if (g_labels[i] != NULL || (po->flags & OPF_JMP))
5342 if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
5344 if (po->op == OP_ADD && po->operand[0].reg == xSP)
5351 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
5354 struct parsed_op *po;
5360 for (base_arg = 0; base_arg < pp->argc; base_arg++)
5361 if (pp->arg[base_arg].reg == NULL)
5364 for (j = i; j > 0; )
5366 ferr_assert(&ops[j], g_labels[j] == NULL);
5370 ferr_assert(po, po->op != OP_PUSH);
5371 if (po->op == OP_FST)
5373 if (po->operand[0].type != OPT_REGMEM)
5375 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
5378 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
5379 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
5383 arg = base_arg + offset / 4;
5384 mark_float_arg(po, pp, arg, regmask_ffca);
5386 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5387 && po->operand[1].type == OPT_CONST)
5389 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5394 for (arg = base_arg; arg < pp->argc; arg++) {
5395 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
5396 if (pp->arg[arg].push_ref_cnt != 1)
5397 ferr(&ops[i], "arg %d/%d not found or bad\n", arg, pp->argc);
5398 po = pp->arg[arg].push_refs[0];
5399 if (po->operand[0].lmod == OPLM_QWORD)
5406 static int collect_call_args_early(int i, int opcnt,
5407 struct parsed_proto *pp, int *regmask, int *regmask_ffca)
5409 struct parsed_op *po;
5414 for (arg = 0; arg < pp->argc; arg++)
5415 if (pp->arg[arg].reg == NULL)
5418 // first see if it can be easily done
5419 for (j = i; j > 0 && arg < pp->argc; )
5421 if (g_labels[j] != NULL)
5426 if (po->op == OP_CALL)
5428 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
5430 else if (po->op == OP_POP)
5432 else if (po->flags & OPF_CJMP)
5434 else if (po->op == OP_PUSH) {
5435 if (po->flags & (OPF_FARG|OPF_FARGNR))
5437 if (!g_header_mode) {
5438 ret = scan_for_mod(po, j + 1, i, 1);
5443 if (pp->arg[arg].type.is_va_list)
5447 for (arg++; arg < pp->argc; arg++)
5448 if (pp->arg[arg].reg == NULL)
5451 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5452 && po->operand[1].type == OPT_CONST)
5454 if (po->flags & (OPF_RMD|OPF_DONE))
5456 if (po->operand[1].val != pp->argc_stack * 4)
5457 ferr(po, "unexpected esp adjust: %d\n",
5458 po->operand[1].val * 4);
5459 ferr_assert(po, pp->argc - arg == pp->argc_stack);
5460 return collect_call_args_no_push(i, pp, regmask_ffca);
5468 for (arg = 0; arg < pp->argc; arg++)
5469 if (pp->arg[arg].reg == NULL)
5472 for (j = i; j > 0 && arg < pp->argc; )
5476 if (ops[j].op == OP_PUSH)
5478 int ref_handled = 0;
5480 k = check_for_stp(j + 1, i);
5482 // push ecx; fstp dword ptr [esp]
5483 ret = parse_stack_esp_offset(&ops[k],
5484 ops[k].operand[0].name, &offset);
5485 if (ret == 0 && offset == 0) {
5486 if (!pp->arg[arg].type.is_float)
5487 ferr(&ops[i], "arg %d should be float\n", arg + 1);
5488 mark_float_arg(&ops[k], pp, arg, regmask_ffca);
5494 ferr_assert(&ops[j], pp->arg[arg].push_ref_cnt == 0);
5495 pp_add_push_ref(pp, arg, &ops[j]);
5498 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5499 *regmask |= 1 << ops[j].operand[0].reg;
5501 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5502 ops[j].flags &= ~OPF_RSAVE;
5505 for (arg++; arg < pp->argc; arg++)
5506 if (pp->arg[arg].reg == NULL)
5512 check_fptr_args(i, opcnt, pp);
5517 // ensure all s_a* numbers match for a given func arg in all branches
5518 // returns 1 if any changes were made, 0 if not
5519 static int sync_argnum(struct parsed_proto *pp, int arg,
5520 int *argnum, int *arggrp)
5522 struct parsed_op *po_tmp;
5526 // see if other branches don't have higher argnum
5527 for (i = 0; i < pp->arg[arg].push_ref_cnt; i++) {
5528 po_tmp = pp->arg[arg].push_refs[i];
5529 if (*argnum < po_tmp->p_argnum)
5530 *argnum = po_tmp->p_argnum;
5531 if (*arggrp < po_tmp->p_arggrp)
5532 *arggrp = po_tmp->p_arggrp;
5535 // make all argnums consistent
5536 for (i = 0; i < pp->arg[arg].push_ref_cnt; i++) {
5537 po_tmp = pp->arg[arg].push_refs[i];
5538 if (po_tmp->p_argnum == 0)
5540 if (po_tmp->p_argnum != *argnum || po_tmp->p_arggrp != *arggrp) {
5541 po_tmp->p_argnum = *argnum;
5542 po_tmp->p_arggrp = *arggrp;
5550 static int collect_call_args_r(struct parsed_op *po, int i,
5551 struct parsed_proto *pp, int *regmask,
5552 int arg, int argnum, int magic,
5553 int skip, int need_op_saving, int may_reuse)
5555 struct parsed_proto *pp_tmp;
5556 struct label_ref *lr;
5557 int need_to_save_current;
5558 int arg_grp_current = 0;
5559 int save_args_seen = 0;
5567 ferr(po, "dead label encountered\n");
5571 for (; arg < pp->argc; arg++, argnum++)
5572 if (pp->arg[arg].reg == NULL)
5574 magic = (magic & 0xffffff) | (arg << 24);
5576 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5578 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5579 if (ops[j].cc_scratch != magic) {
5580 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5584 // ok: have already been here
5587 ops[j].cc_scratch = magic;
5589 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5590 lr = &g_label_refs[j];
5591 if (lr->next != NULL)
5593 for (; lr->next; lr = lr->next) {
5594 check_i(&ops[j], lr->i);
5595 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5597 ret = collect_call_args_r(po, lr->i, pp, regmask,
5598 arg, argnum, magic, skip, need_op_saving, may_reuse);
5603 check_i(&ops[j], lr->i);
5604 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5606 if (j > 0 && LAST_OP(j - 1)) {
5607 // follow last branch in reverse
5612 ret = collect_call_args_r(po, lr->i, pp, regmask,
5613 arg, argnum, magic, skip, need_op_saving, may_reuse);
5619 if (ops[j].op == OP_CALL)
5621 if (pp->is_unresolved)
5626 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5627 arg, pp->argc, ops[j].operand[0].name);
5628 if (may_reuse && pp_tmp->argc_stack > 0)
5629 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5630 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5631 if (!pp_tmp->is_unresolved)
5632 skip = pp_tmp->argc_stack;
5634 // esp adjust of 0 means we collected it before
5635 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5636 && (ops[j].operand[1].type != OPT_CONST
5637 || ops[j].operand[1].val != 0))
5639 if (pp->is_unresolved)
5642 fnote(po, "(this call)\n");
5643 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5644 arg, pp->argc, ops[j].operand[1].val);
5646 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5648 if (pp->is_unresolved)
5651 fnote(po, "(this call)\n");
5652 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5654 else if (ops[j].flags & OPF_CJMP)
5656 if (pp->is_unresolved)
5661 else if (ops[j].op == OP_PUSH && skip > 0) {
5662 // XXX: might want to rm OPF_FARGNR and only use this
5665 else if (ops[j].op == OP_PUSH
5666 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5668 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5671 pp_add_push_ref(pp, arg, &ops[j]);
5673 sync_argnum(pp, arg, &argnum, &dummy);
5675 need_to_save_current = 0;
5677 if (ops[j].operand[0].type == OPT_REG)
5678 reg = ops[j].operand[0].reg;
5680 if (!need_op_saving) {
5681 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5682 need_to_save_current = (ret >= 0);
5684 if (need_op_saving || need_to_save_current) {
5685 // mark this arg as one that needs operand saving
5686 pp->arg[arg].is_saved = 1;
5688 if (save_args_seen & (1 << (argnum - 1))) {
5691 if (arg_grp_current >= MAX_ARG_GRP)
5692 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5696 else if (ops[j].p_argnum == 0)
5697 ops[j].flags |= OPF_RMD;
5699 // some PUSHes are reused by different calls on other branches,
5700 // but that can't happen if we didn't branch, so they
5701 // can be removed from future searches (handles nested calls)
5703 ops[j].flags |= OPF_FARGNR;
5705 ops[j].flags |= OPF_FARG;
5706 ops[j].flags &= ~OPF_RSAVE;
5708 // check for __VALIST
5709 if (!pp->is_unresolved && g_func_pp != NULL
5710 && pp->arg[arg].type.is_va_list)
5713 ret = resolve_origin(j, &ops[j].operand[0],
5714 magic + 1, &k, NULL);
5715 if (ret == 1 && k >= 0)
5717 if (ops[k].op == OP_LEA) {
5718 if (!g_func_pp->is_vararg)
5719 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5722 snprintf(buf, sizeof(buf), "arg_%X",
5723 g_func_pp->argc_stack * 4);
5724 if (strstr(ops[k].operand[1].name, buf)
5725 || strstr(ops[k].operand[1].name, "arglist"))
5727 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5728 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5729 pp->arg[arg].is_saved = 0;
5733 ferr(&ops[k], "va_list arg detection failed\n");
5735 // check for va_list from g_func_pp arg too
5736 else if (ops[k].op == OP_MOV
5737 && is_stack_access(&ops[k], &ops[k].operand[1]))
5739 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5740 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5742 ops[k].flags |= OPF_RMD | OPF_DONE;
5743 ops[j].flags |= OPF_RMD;
5744 ops[j].p_argpass = ret + 1;
5745 pp->arg[arg].is_saved = 0;
5752 if (pp->arg[arg].is_saved) {
5753 ops[j].flags &= ~OPF_RMD;
5754 ops[j].p_argnum = argnum;
5755 ops[j].p_arggrp = arg_grp_current;
5758 // tracking reg usage
5760 *regmask |= 1 << reg;
5764 if (!pp->is_unresolved) {
5766 for (; arg < pp->argc; arg++, argnum++)
5767 if (pp->arg[arg].reg == NULL)
5770 magic = (magic & 0xffffff) | (arg << 24);
5773 if (ops[j].p_arggrp > arg_grp_current) {
5775 arg_grp_current = ops[j].p_arggrp;
5777 if (ops[j].p_argnum > 0)
5778 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5781 if (arg < pp->argc) {
5782 ferr(po, "arg collect failed for '%s': %d/%d\n",
5783 pp->name, arg, pp->argc);
5790 static int collect_call_args(struct parsed_op *po, int i, int opcnt,
5791 struct parsed_proto *pp, int *regmask, int magic)
5795 ret = collect_call_args_r(po, i, pp, regmask, 0, 1, magic,
5800 if (pp->is_unresolved) {
5802 pp->argc_stack += ret;
5803 for (a = 0; a < pp->argc; a++)
5804 if (pp->arg[a].type.name == NULL)
5805 pp->arg[a].type.name = strdup("int");
5808 // note: p_argnum, p_arggrp will be propagated in a later pass,
5809 // look for sync_argnum() (p_arggrp is for cases when mixed pushes
5810 // for multiple funcs are going on)
5813 check_fptr_args(i, opcnt, pp);
5818 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5819 int regmask_now, int *regmask,
5820 int regmask_save_now, int *regmask_save,
5821 int *regmask_init, int regmask_arg)
5823 struct parsed_op *po;
5831 for (; i < opcnt; i++)
5834 if (cbits[i >> 3] & (1 << (i & 7)))
5836 cbits[i >> 3] |= (1 << (i & 7));
5838 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5839 if (po->flags & (OPF_RMD|OPF_DONE))
5841 if (po->btj != NULL) {
5842 for (j = 0; j < po->btj->count; j++) {
5843 check_i(po, po->btj->d[j].bt_i);
5844 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5845 regmask_now, regmask, regmask_save_now, regmask_save,
5846 regmask_init, regmask_arg);
5851 check_i(po, po->bt_i);
5852 if (po->flags & OPF_CJMP)
5853 reg_use_pass(po->bt_i, opcnt, cbits,
5854 regmask_now, regmask, regmask_save_now, regmask_save,
5855 regmask_init, regmask_arg);
5861 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5862 && !g_func_pp->is_userstack
5863 && po->operand[0].type == OPT_REG)
5867 reg = po->operand[0].reg;
5868 ferr_assert(po, reg >= 0);
5871 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5872 if (regmask_now & (1 << reg)) {
5873 already_saved = regmask_save_now & (1 << reg);
5874 flags_set = OPF_RSAVE | OPF_DONE;
5878 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3,
5879 reg, 0, 0, save_level, 0);
5881 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5882 reg, 0, 0, save_level, flags_set);
5885 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5887 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5892 ferr_assert(po, !already_saved);
5893 po->flags |= flags_set;
5895 if (regmask_now & (1 << reg)) {
5896 regmask_save_now |= (1 << reg);
5897 *regmask_save |= regmask_save_now;
5902 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5903 reg = po->operand[0].reg;
5904 ferr_assert(po, reg >= 0);
5906 if (regmask_save_now & (1 << reg))
5907 regmask_save_now &= ~(1 << reg);
5909 regmask_now &= ~(1 << reg);
5912 else if (po->op == OP_CALL) {
5913 if ((po->regmask_dst & (1 << xAX))
5914 && !(po->regmask_dst & (1 << xDX)))
5916 if (po->flags & OPF_TAIL)
5917 // don't need eax, will do "return f();" or "f(); return;"
5918 po->regmask_dst &= ~(1 << xAX);
5920 find_next_read_reg(i + 1, opcnt, xAX, OPLM_DWORD,
5921 i + opcnt * 17, &j);
5924 po->regmask_dst &= ~(1 << xAX);
5928 // not "full stack" mode and have something in stack
5929 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5930 ferr(po, "float stack is not empty on func call\n");
5933 if (po->flags & OPF_NOREGS)
5936 // if incomplete register is used, clear it on init to avoid
5937 // later use of uninitialized upper part in some situations
5938 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5939 && po->operand[0].lmod != OPLM_DWORD)
5941 reg = po->operand[0].reg;
5942 ferr_assert(po, reg >= 0);
5944 if (!(regmask_now & (1 << reg)))
5945 *regmask_init |= 1 << reg;
5948 regmask_op = po->regmask_src | po->regmask_dst;
5950 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5951 regmask_new &= ~(1 << xSP);
5952 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5953 regmask_new &= ~(1 << xBP);
5955 if (regmask_new != 0)
5956 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5958 if (regmask_op & (1 << xBP)) {
5959 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5960 if (po->regmask_dst & (1 << xBP))
5961 // compiler decided to drop bp frame and use ebp as scratch
5962 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5964 regmask_op &= ~(1 << xBP);
5968 if (po->flags & OPF_FPUSH) {
5969 if (regmask_now & mxST1)
5970 regmask_now |= mxSTa; // switch to "full stack" mode
5971 if (regmask_now & mxSTa)
5972 po->flags |= OPF_FSHIFT;
5973 if (!(regmask_now & mxST7_2)) {
5975 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5979 regmask_now |= regmask_op;
5980 *regmask |= regmask_now;
5983 if (po->flags & OPF_FPOPP) {
5984 if ((regmask_now & mxSTa) == 0)
5985 ferr(po, "float pop on empty stack?\n");
5986 if (regmask_now & mxST7_2)
5987 po->flags |= OPF_FSHIFT;
5988 if (!(regmask_now & mxST7_2))
5989 regmask_now &= ~mxST1_0;
5991 else if (po->flags & OPF_FPOP) {
5992 if ((regmask_now & mxSTa) == 0)
5993 ferr(po, "float pop on empty stack?\n");
5994 if (regmask_now & (mxST7_2 | mxST1))
5995 po->flags |= OPF_FSHIFT;
5996 if (!(regmask_now & mxST7_2)) {
5998 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
6002 if (po->flags & OPF_TAIL) {
6003 if (!(regmask_now & mxST7_2)) {
6004 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
6005 if (!(regmask_now & mxST0))
6006 ferr(po, "no st0 on float return, mask: %x\n",
6009 else if (regmask_now & mxST1_0)
6010 ferr(po, "float regs on tail: %x\n", regmask_now);
6013 // there is support for "conditional tailcall", sort of
6014 if (!(po->flags & OPF_CC))
6020 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
6024 for (i = 0; i < pp->argc; i++)
6025 if (pp->arg[i].reg == NULL)
6029 memmove(&pp->arg[i + 1], &pp->arg[i],
6030 sizeof(pp->arg[0]) * pp->argc_stack);
6031 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
6032 pp->arg[i].reg = strdup(reg);
6033 pp->arg[i].type.name = strdup("int");
6038 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
6039 int *pfomask, const char *dst_opr_text)
6041 if (*pfomask & (1 << PFO_Z)) {
6042 fprintf(fout, "\n cond_z = (%s%s == 0);",
6043 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
6044 *pfomask &= ~(1 << PFO_Z);
6048 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
6049 int *pfomask, const char *dst_opr_text)
6051 if (*pfomask & (1 << PFO_S)) {
6052 fprintf(fout, "\n cond_s = (%s%s < 0);",
6053 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
6054 *pfomask &= ~(1 << PFO_S);
6058 static void output_std_flags(FILE *fout, struct parsed_op *po,
6059 int *pfomask, const char *dst_opr_text)
6061 output_std_flag_z(fout, po, pfomask, dst_opr_text);
6062 output_std_flag_s(fout, po, pfomask, dst_opr_text);
6066 OPP_FORCE_NORETURN = (1 << 0),
6067 OPP_SIMPLE_ARGS = (1 << 1),
6068 OPP_ALIGN = (1 << 2),
6071 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
6074 const char *cconv = "";
6076 if (pp->is_fastcall)
6077 cconv = "__fastcall ";
6078 else if (pp->is_stdcall && pp->argc_reg == 0)
6079 cconv = "__stdcall ";
6081 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
6083 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
6084 fprintf(fout, "noreturn ");
6087 static void output_pp(FILE *fout, const struct parsed_proto *pp,
6092 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
6096 output_pp_attrs(fout, pp, flags);
6099 fprintf(fout, "%s", pp->name);
6104 for (i = 0; i < pp->argc; i++) {
6106 fprintf(fout, ", ");
6107 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
6108 && !(flags & OPP_SIMPLE_ARGS))
6111 output_pp(fout, pp->arg[i].pp, 0);
6113 else if (pp->arg[i].type.is_retreg) {
6114 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
6117 fprintf(fout, "%s", pp->arg[i].type.name);
6119 fprintf(fout, " a%d", i + 1);
6122 if (pp->arg[i].type.is_64bit)
6125 if (pp->is_vararg) {
6127 fprintf(fout, ", ");
6128 fprintf(fout, "...");
6133 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
6139 snprintf(buf1, sizeof(buf1), "%d", grp);
6140 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
6145 static void gen_x_cleanup(int opcnt);
6147 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
6149 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
6150 struct parsed_opr *last_arith_dst = NULL;
6151 char buf1[256], buf2[256], buf3[256], cast[64];
6152 struct parsed_proto *pp, *pp_tmp;
6153 struct parsed_data *pd;
6154 int save_arg_vars[MAX_ARG_GRP] = { 0, };
6155 unsigned char cbits[MAX_OPS / 8];
6156 const char *float_type;
6157 const char *float_st0;
6158 const char *float_st1;
6159 int need_float_stack = 0;
6160 int need_float_sw = 0; // status word
6161 int need_tmp_var = 0;
6165 int label_pending = 0;
6166 int need_double = 0;
6167 int stack_align = 0;
6168 int stack_fsz_adj = 0;
6169 int lock_handled = 0;
6170 int regmask_save = 0; // used regs saved/restored in this func
6171 int regmask_arg; // regs from this function args (fastcall, etc)
6172 int regmask_ret; // regs needed on ret
6173 int regmask_now; // temp
6174 int regmask_init = 0; // regs that need zero initialization
6175 int regmask_pp = 0; // regs used in complex push-pop graph
6176 int regmask_ffca = 0; // float function call args
6177 int regmask = 0; // used regs
6187 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
6188 g_stack_frame_used = 0;
6190 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
6191 regmask_init = g_regmask_init;
6193 g_func_pp = proto_parse(fhdr, funcn, 0);
6194 if (g_func_pp == NULL)
6195 ferr(ops, "proto_parse failed for '%s'\n", funcn);
6197 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
6198 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
6201 // - resolve all branches
6202 // - parse calls with labels
6203 resolve_branches_parse_calls(opcnt);
6206 // - handle ebp/esp frame, remove ops related to it
6207 scan_prologue_epilogue(opcnt, &stack_align);
6209 // handle a case where sf size is unalignment, but is
6210 // placed in a way that elements are still aligned
6211 if (g_stack_fsz & 4) {
6212 for (i = 0; i < g_eqcnt; i++) {
6213 if (g_eqs[i].lmod != OPLM_QWORD)
6215 if (!(g_eqs[i].offset & 4)) {
6224 // - remove dead labels
6225 // - set regs needed at ret
6226 for (i = 0; i < opcnt; i++)
6228 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
6233 if (ops[i].op == OP_RET)
6234 ops[i].regmask_src |= regmask_ret;
6238 // - process trivial calls
6239 for (i = 0; i < opcnt; i++)
6242 if (po->flags & (OPF_RMD|OPF_DONE))
6245 if (po->op == OP_CALL)
6247 pp = process_call_early(i, opcnt, &j);
6249 if (!(po->flags & OPF_ATAIL)) {
6250 // since we know the args, try to collect them
6251 ret = collect_call_args_early(i, opcnt, pp,
6252 ®mask, ®mask_ffca);
6260 // commit esp adjust
6261 if (ops[j].op != OP_POP)
6262 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
6264 for (l = 0; l < pp->argc_stack; l++)
6265 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
6269 if (strstr(pp->ret_type.name, "int64"))
6272 po->flags |= OPF_DONE;
6278 // - process calls, stage 2
6279 // - handle some push/pop pairs
6280 // - scan for STD/CLD, propagate DF
6281 // - try to resolve needed x87 status word bits
6282 for (i = 0; i < opcnt; i++)
6287 if (po->flags & OPF_RMD)
6290 if (po->op == OP_CALL)
6292 if (!(po->flags & OPF_DONE)) {
6293 pp = process_call(i, opcnt);
6295 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
6296 // since we know the args, collect them
6297 collect_call_args(po, i, opcnt, pp, ®mask, i + opcnt * 2);
6299 // for unresolved, collect after other passes
6303 ferr_assert(po, pp != NULL);
6305 po->regmask_src |= get_pp_arg_regmask_src(pp);
6306 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
6308 if (po->regmask_dst & mxST0)
6309 po->flags |= OPF_FPUSH;
6311 if (strstr(pp->ret_type.name, "int64"))
6317 if (po->flags & OPF_DONE)
6322 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
6323 && po->operand[0].type == OPT_CONST)
6325 scan_for_pop_const(i, opcnt, i + opcnt * 12);
6330 scan_pushes_for_pop(i, opcnt, ®mask_pp);
6334 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
6335 scan_propagate_df(i + 1, opcnt);
6340 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
6341 ferr(po, "TODO: fnstsw to mem\n");
6342 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
6344 ferr(po, "fnstsw resolve failed\n");
6345 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
6346 (void *)(long)(mask | (z_check << 16)));
6348 ferr(po, "failed to find fcom: %d\n", ret);
6357 // - find POPs for PUSHes, rm both
6358 // - scan for all used registers
6359 memset(cbits, 0, sizeof(cbits));
6360 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
6361 0, ®mask_save, ®mask_init, regmask_arg);
6363 need_float_stack = !!(regmask & mxST7_2);
6366 // - find flag set ops for their users
6367 // - do unresolved calls
6368 // - declare indirect functions
6369 // - other op specific processing
6370 for (i = 0; i < opcnt; i++)
6373 if (po->flags & (OPF_RMD|OPF_DONE))
6376 if (po->flags & OPF_CC)
6378 int setters[16], cnt = 0, branched = 0;
6380 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
6381 &branched, setters, &cnt);
6382 if (ret < 0 || cnt <= 0)
6383 ferr(po, "unable to trace flag setter(s)\n");
6384 if (cnt > ARRAY_SIZE(setters))
6385 ferr(po, "too many flag setters\n");
6387 for (j = 0; j < cnt; j++)
6389 tmp_op = &ops[setters[j]]; // flag setter
6392 // to get nicer code, we try to delay test and cmp;
6393 // if we can't because of operand modification, or if we
6394 // have arith op, or branch, make it calculate flags explicitly
6395 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
6397 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
6398 pfomask = 1 << po->pfo;
6400 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
6401 pfomask = 1 << po->pfo;
6404 // see if we'll be able to handle based on op result
6405 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
6406 && po->pfo != PFO_Z && po->pfo != PFO_S
6407 && po->pfo != PFO_P)
6409 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
6411 pfomask = 1 << po->pfo;
6414 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
6415 propagate_lmod(tmp_op, &tmp_op->operand[0],
6416 &tmp_op->operand[1]);
6417 if (tmp_op->operand[0].lmod == OPLM_DWORD)
6422 tmp_op->pfomask |= pfomask;
6423 cond_vars |= pfomask;
6425 // note: may overwrite, currently not a problem
6429 if (po->op == OP_RCL || po->op == OP_RCR
6430 || po->op == OP_ADC || po->op == OP_SBB)
6431 cond_vars |= 1 << PFO_C;
6437 cond_vars |= 1 << PFO_Z;
6441 if (po->operand[0].lmod == OPLM_DWORD)
6446 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
6451 // note: resolved non-reg calls are OPF_DONE already
6453 ferr_assert(po, pp != NULL);
6455 if (pp->is_unresolved) {
6456 int regmask_stack = 0;
6457 collect_call_args(po, i, opcnt, pp, ®mask, i + opcnt * 2);
6459 // this is pretty rough guess:
6460 // see ecx and edx were pushed (and not their saved versions)
6461 for (arg = 0; arg < pp->argc; arg++) {
6462 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
6465 if (pp->arg[arg].push_ref_cnt == 0)
6466 ferr(po, "parsed_op missing for arg%d\n", arg);
6467 tmp_op = pp->arg[arg].push_refs[0];
6468 if (tmp_op->operand[0].type == OPT_REG)
6469 regmask_stack |= 1 << tmp_op->operand[0].reg;
6472 // quick dumb check for potential reg-args
6473 for (j = i - 1; j >= 0 && ops[j].op == OP_MOV; j--)
6474 if (ops[j].operand[0].type == OPT_REG)
6475 regmask_stack &= ~(1 << ops[j].operand[0].reg);
6477 if ((regmask_stack & (mxCX|mxDX)) != (mxCX|mxDX)
6478 && ((regmask | regmask_arg) & (mxCX|mxDX)))
6480 if (pp->argc_stack != 0
6481 || ((regmask | regmask_arg) & (mxCX|mxDX)))
6483 pp_insert_reg_arg(pp, "ecx");
6484 pp->is_fastcall = 1;
6485 regmask_init |= 1 << xCX;
6486 regmask |= 1 << xCX;
6488 if (pp->argc_stack != 0
6489 || ((regmask | regmask_arg) & mxDX))
6491 pp_insert_reg_arg(pp, "edx");
6492 regmask_init |= 1 << xDX;
6493 regmask |= 1 << xDX;
6497 // note: __cdecl doesn't fall into is_unresolved category
6498 if (pp->argc_stack > 0)
6501 if (!(po->flags & OPF_TAIL)
6502 && !(g_sct_func_attr & SCTFA_NOWARN) && !g_nowarn_reguse)
6504 // treat al write as overwrite to avoid many false positives
6505 if (IS(pp->ret_type.name, "void") || pp->ret_type.is_float) {
6506 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
6507 i + opcnt * 25, &j);
6509 fnote(po, "eax used after void/float ret call\n");
6510 fnote(&ops[j], "(used here)\n");
6513 if (!strstr(pp->ret_type.name, "int64")) {
6514 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
6515 i + opcnt * 26, &j);
6516 // indirect calls are often guessed, don't warn
6517 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6518 fnote(po, "edx used after 32bit ret call\n");
6519 fnote(&ops[j], "(used here)\n");
6523 // msvc often relies on callee not modifying 'this'
6524 for (arg = 0; arg < pp->argc; arg++) {
6525 if (pp->arg[arg].reg && IS(pp->arg[arg].reg, "ecx")) {
6531 find_next_read_reg(i + 1, opcnt, xCX, OPLM_BYTE,
6532 i + opcnt * 27, &j);
6533 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6534 fnote(po, "ecx used after call\n");
6535 fnote(&ops[j], "(used here)\n");
6542 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6544 // <var> = offset <something>
6545 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6546 && !IS_START(po->operand[1].name, "off_"))
6548 if (!po->operand[0].pp->is_fptr)
6549 ferr(po, "%s not declared as fptr when it should be\n",
6550 po->operand[0].name);
6551 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6552 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6553 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6554 fnote(po, "var: %s\n", buf1);
6555 fnote(po, "func: %s\n", buf2);
6556 ferr(po, "^ mismatch\n");
6564 if (po->operand[0].lmod == OPLM_DWORD) {
6565 // 32bit division is common, look for it
6566 if (po->op == OP_DIV)
6567 ret = scan_for_reg_clear(i, xDX);
6569 ret = scan_for_cdq_edx(i);
6571 po->flags |= OPF_32BIT;
6580 po->flags |= OPF_RMD | OPF_DONE;
6590 if (po->operand[0].lmod == OPLM_QWORD)
6601 find_next_read_reg(i + 1, opcnt, xDX, OPLM_DWORD,
6602 i + opcnt * 18, &j);
6604 po->flags |= OPF_32BIT;
6612 // pass8: sync all push arg numbers
6613 // some calls share args and not all of them
6614 // (there's only partial intersection)
6616 int changed, argnum, arggrp;
6619 for (i = 0; i < opcnt; i++)
6622 if ((po->flags & (OPF_RMD|OPF_DONE)) || po->op != OP_CALL)
6629 for (arg = argnum = 0; arg < pp->argc; arg++) {
6630 if (pp->arg[arg].reg != NULL)
6632 if (pp->arg[arg].is_saved)
6633 changed |= sync_argnum(pp, arg, &argnum, &arggrp);
6641 ferr(po, "too many args or looping in graph\n");
6646 // pass9: final adjustments
6647 for (i = 0; i < opcnt; i++)
6650 if (po->flags & (OPF_RMD|OPF_DONE))
6653 if (po->op != OP_FST && po->p_argnum > 0)
6654 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6656 // correct for "full stack" mode late enable
6657 if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6658 && need_float_stack)
6659 po->flags |= OPF_FSHIFT;
6662 float_type = need_double ? "double" : "float";
6663 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6664 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6666 // output starts here
6669 fprintf(fout, "// had SEH\n");
6671 // define userstack size
6672 if (g_func_pp->is_userstack) {
6673 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6674 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6675 fprintf(fout, "#endif\n");
6678 // the function itself
6679 ferr_assert(ops, !g_func_pp->is_fptr);
6680 output_pp(fout, g_func_pp,
6681 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6682 fprintf(fout, "\n{\n");
6684 // declare indirect functions
6685 for (i = 0; i < opcnt; i++) {
6687 if (po->flags & OPF_RMD)
6690 if (po->op == OP_CALL) {
6693 ferr(po, "NULL pp\n");
6695 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6696 if (pp->name[0] != 0) {
6697 if (IS_START(pp->name, "guess"))
6700 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6701 memcpy(pp->name, "i_", 2);
6703 // might be declared already
6705 for (j = 0; j < i; j++) {
6706 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6707 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6717 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6720 output_pp(fout, pp, OPP_SIMPLE_ARGS);
6721 fprintf(fout, ";\n");
6726 // output LUTs/jumptables
6727 for (i = 0; i < g_func_pd_cnt; i++) {
6729 fprintf(fout, " static const ");
6730 if (pd->type == OPT_OFFSET) {
6731 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6733 for (j = 0; j < pd->count; j++) {
6735 fprintf(fout, ", ");
6736 fprintf(fout, "&&%s", pd->d[j].u.label);
6740 fprintf(fout, "%s %s[] =\n { ",
6741 lmod_type_u(ops, pd->lmod), pd->label);
6743 for (j = 0; j < pd->count; j++) {
6745 fprintf(fout, ", ");
6746 fprintf(fout, "%u", pd->d[j].u.val);
6749 fprintf(fout, " };\n");
6753 // declare stack frame, va_arg
6756 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6758 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6759 if (g_func_lmods & (1 << OPLM_WORD))
6760 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6761 if (g_func_lmods & (1 << OPLM_BYTE))
6762 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6763 if (g_func_lmods & (1 << OPLM_QWORD))
6764 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6766 if (stack_align > 8)
6767 ferr(ops, "unhandled stack align of %d\n", stack_align);
6768 else if (stack_align == 8)
6769 fprintf(fout, " u64 align;");
6770 fprintf(fout, " } sf;\n");
6774 if ((g_sct_func_attr & SCTFA_ARGFRAME) && g_func_pp->argc_stack) {
6775 fprintf(fout, " struct { u32 ");
6776 for (i = j = 0; i < g_func_pp->argc; i++) {
6777 if (g_func_pp->arg[i].reg != NULL)
6780 fprintf(fout, ", ");
6781 fprintf(fout, "a%d", i + 1);
6783 fprintf(fout, "; } af = {\n ");
6784 for (i = j = 0; i < g_func_pp->argc; i++) {
6785 if (g_func_pp->arg[i].reg != NULL)
6788 fprintf(fout, ", ");
6789 if (g_func_pp->arg[i].type.is_ptr)
6790 fprintf(fout, "(u32)");
6791 fprintf(fout, "a%d", i + 1);
6793 fprintf(fout, "\n };\n");
6796 if (g_func_pp->is_userstack) {
6797 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6798 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6802 if (g_func_pp->is_vararg) {
6803 fprintf(fout, " va_list ap;\n");
6807 // declare arg-registers
6808 for (i = 0; i < g_func_pp->argc; i++) {
6809 if (g_func_pp->arg[i].reg != NULL) {
6810 reg = char_array_i(regs_r32,
6811 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6812 if (regmask & (1 << reg)) {
6813 if (g_func_pp->arg[i].type.is_retreg)
6814 fprintf(fout, " u32 %s = *r_%s;\n",
6815 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6817 fprintf(fout, " u32 %s = (u32)a%d;\n",
6818 g_func_pp->arg[i].reg, i + 1);
6821 if (g_func_pp->arg[i].type.is_retreg)
6822 ferr(ops, "retreg '%s' is unused?\n",
6823 g_func_pp->arg[i].reg);
6824 fprintf(fout, " // %s = a%d; // unused\n",
6825 g_func_pp->arg[i].reg, i + 1);
6831 // declare normal registers
6832 regmask_now = regmask & ~regmask_arg & ~g_regmask_rm;
6833 regmask_now &= ~(1 << xSP);
6834 if (regmask_now & 0x00ff) {
6835 for (reg = 0; reg < 8; reg++) {
6836 if (regmask_now & (1 << reg)) {
6837 fprintf(fout, " u32 %s", regs_r32[reg]);
6838 if (regmask_init & (1 << reg))
6839 fprintf(fout, " = 0");
6840 fprintf(fout, ";\n");
6846 if (regmask_now & 0xff00) {
6847 for (reg = 8; reg < 16; reg++) {
6848 if (regmask_now & (1 << reg)) {
6849 fprintf(fout, " mmxr %s", regs_r32[reg]);
6850 if (regmask_init & (1 << reg))
6851 fprintf(fout, " = { 0, }");
6852 fprintf(fout, ";\n");
6858 if (need_float_stack) {
6859 fprintf(fout, " %s f_st[8];\n", float_type);
6860 fprintf(fout, " int f_stp = 0;\n");
6864 if (regmask_now & 0xff0000) {
6865 for (reg = 16; reg < 24; reg++) {
6866 if (regmask_now & (1 << reg)) {
6867 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6868 if (regmask_init & (1 << reg))
6869 fprintf(fout, " = 0");
6870 fprintf(fout, ";\n");
6877 if (need_float_sw) {
6878 fprintf(fout, " u16 f_sw;\n");
6883 for (reg = 0; reg < 8; reg++) {
6884 if (regmask_save & (1 << reg)) {
6885 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6891 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6892 if (save_arg_vars[i] == 0)
6894 for (reg = 0; reg < 32; reg++) {
6895 if (save_arg_vars[i] & (1 << reg)) {
6896 fprintf(fout, " u32 %s;\n",
6897 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6904 for (reg = 0; reg < 32; reg++) {
6905 if (regmask_ffca & (1 << reg)) {
6906 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6912 // declare push-pop temporaries
6914 for (reg = 0; reg < 8; reg++) {
6915 if (regmask_pp & (1 << reg)) {
6916 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6923 for (i = 0; i < 8; i++) {
6924 if (cond_vars & (1 << i)) {
6925 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6932 fprintf(fout, " u32 tmp;\n");
6937 fprintf(fout, " u64 tmp64;\n");
6942 fprintf(fout, "\n");
6944 // do stack clear, if needed
6945 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6947 if (g_stack_clear_len != 0) {
6948 if (g_stack_clear_len <= 4) {
6949 for (i = 0; i < g_stack_clear_len; i++)
6950 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6951 fprintf(fout, "0;\n");
6954 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6955 g_stack_clear_start, g_stack_clear_len * 4);
6959 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6962 if (g_func_pp->is_vararg) {
6963 if (g_func_pp->argc_stack == 0)
6964 ferr(ops, "vararg func without stack args?\n");
6965 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6969 for (i = 0; i < opcnt; i++)
6971 if (g_labels[i] != NULL) {
6972 fprintf(fout, "\n%s:\n", g_labels[i]);
6975 delayed_flag_op = NULL;
6976 last_arith_dst = NULL;
6980 if (po->flags & OPF_RMD)
6986 #define assert_operand_cnt(n_) \
6987 if (po->operand_cnt != n_) \
6988 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6990 // conditional/flag using op?
6991 if (po->flags & OPF_CC)
6997 // we go through all this trouble to avoid using parsed_flag_op,
6998 // which makes generated code much nicer
6999 if (delayed_flag_op != NULL)
7001 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
7002 po->pfo, po->pfo_inv);
7005 else if (last_arith_dst != NULL
7006 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
7007 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
7010 struct parsed_op *po_arith = (void *)((char *)last_arith_dst
7011 - offsetof(struct parsed_op, operand[0]));
7012 ferr_assert(po, &ops[po_arith - ops] == po_arith);
7013 out_src_opr_u32(buf3, sizeof(buf3), po_arith, last_arith_dst);
7014 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
7015 last_arith_dst->lmod, buf3);
7018 else if (tmp_op != NULL) {
7019 // use preprocessed flag calc results
7020 if (!(tmp_op->pfomask & (1 << po->pfo)))
7021 ferr(po, "not prepared for pfo %d\n", po->pfo);
7023 // note: pfo_inv was not yet applied
7024 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
7025 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
7028 ferr(po, "all methods of finding comparison failed\n");
7031 if (po->flags & OPF_JMP) {
7032 fprintf(fout, " if %s", buf1);
7034 else if (po->op == OP_RCL || po->op == OP_RCR
7035 || po->op == OP_ADC || po->op == OP_SBB)
7038 fprintf(fout, " cond_%s = %s;\n",
7039 parsed_flag_op_names[po->pfo], buf1);
7041 else if (po->flags & OPF_DATA) { // SETcc
7042 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
7043 fprintf(fout, " %s = %s;", buf2, buf1);
7046 ferr(po, "unhandled conditional op\n");
7050 pfomask = po->pfomask;
7055 assert_operand_cnt(2);
7056 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7057 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7058 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
7059 fprintf(fout, " %s = %s;", buf1,
7060 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7065 assert_operand_cnt(2);
7066 po->operand[1].lmod = OPLM_DWORD; // always
7067 fprintf(fout, " %s = %s;",
7068 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7069 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7074 assert_operand_cnt(2);
7075 fprintf(fout, " %s = %s;",
7076 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7077 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7081 assert_operand_cnt(2);
7082 switch (po->operand[1].lmod) {
7084 strcpy(buf3, "(s8)");
7087 strcpy(buf3, "(s16)");
7090 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
7092 fprintf(fout, " %s = %s;",
7093 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7094 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7099 assert_operand_cnt(2);
7100 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7101 fprintf(fout, " tmp = %s;",
7102 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
7103 fprintf(fout, " %s = %s;",
7104 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7105 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7106 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7107 fprintf(fout, " %s = %stmp;",
7108 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
7109 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
7110 snprintf(g_comment, sizeof(g_comment), "xchg");
7114 assert_operand_cnt(1);
7115 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7116 fprintf(fout, " %s = ~%s;", buf1, buf1);
7120 assert_operand_cnt(2);
7121 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7122 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7123 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
7124 strcpy(g_comment, "xlat");
7128 assert_operand_cnt(2);
7129 fprintf(fout, " %s = (s32)%s >> 31;",
7130 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7131 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7132 strcpy(g_comment, "cdq");
7136 assert_operand_cnt(1);
7137 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7138 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
7142 if (po->flags & OPF_REP) {
7143 assert_operand_cnt(3);
7148 assert_operand_cnt(2);
7149 fprintf(fout, " %s = %sesi; esi %c= %d;",
7150 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
7151 lmod_cast_u_ptr(po, po->operand[1].lmod),
7152 (po->flags & OPF_DF) ? '-' : '+',
7153 lmod_bytes(po, po->operand[1].lmod));
7154 strcpy(g_comment, "lods");
7159 if (po->flags & OPF_REP) {
7160 assert_operand_cnt(3);
7161 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
7162 (po->flags & OPF_DF) ? '-' : '+',
7163 lmod_bytes(po, po->operand[1].lmod));
7164 fprintf(fout, " %sedi = eax;\n",
7165 lmod_cast_u_ptr(po, po->operand[1].lmod));
7166 fprintf(fout, " barrier();");
7167 strcpy(g_comment, "^ rep stos");
7170 assert_operand_cnt(2);
7171 fprintf(fout, " %sedi = eax; edi %c= %d;",
7172 lmod_cast_u_ptr(po, po->operand[1].lmod),
7173 (po->flags & OPF_DF) ? '-' : '+',
7174 lmod_bytes(po, po->operand[1].lmod));
7175 strcpy(g_comment, "stos");
7180 j = lmod_bytes(po, po->operand[0].lmod);
7181 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
7182 l = (po->flags & OPF_DF) ? '-' : '+';
7183 if (po->flags & OPF_REP) {
7184 assert_operand_cnt(3);
7186 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
7189 " %sedi = %sesi;\n", buf1, buf1);
7190 // this can overwrite many variables
7191 fprintf(fout, " barrier();");
7192 strcpy(g_comment, "^ rep movs");
7195 assert_operand_cnt(2);
7196 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
7197 buf1, buf1, l, j, l, j);
7198 strcpy(g_comment, "movs");
7203 // repe ~ repeat while ZF=1
7204 j = lmod_bytes(po, po->operand[0].lmod);
7205 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
7206 l = (po->flags & OPF_DF) ? '-' : '+';
7207 if (po->flags & OPF_REP) {
7208 assert_operand_cnt(3);
7210 " while (ecx != 0) {\n");
7211 if (pfomask & (1 << PFO_C)) {
7214 " cond_c = %sesi < %sedi;\n", buf1, buf1);
7215 pfomask &= ~(1 << PFO_C);
7218 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
7219 buf1, buf1, l, j, l, j);
7222 " if (cond_z %s 0) break;\n",
7223 (po->flags & OPF_REPZ) ? "==" : "!=");
7226 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
7227 (po->flags & OPF_REPZ) ? "e" : "ne");
7230 assert_operand_cnt(2);
7232 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
7233 buf1, buf1, l, j, l, j);
7234 strcpy(g_comment, "cmps");
7236 pfomask &= ~(1 << PFO_Z);
7237 last_arith_dst = NULL;
7238 delayed_flag_op = NULL;
7242 // only does ZF (for now)
7243 // repe ~ repeat while ZF=1
7244 j = lmod_bytes(po, po->operand[1].lmod);
7245 l = (po->flags & OPF_DF) ? '-' : '+';
7246 if (po->flags & OPF_REP) {
7247 assert_operand_cnt(3);
7249 " while (ecx != 0) {\n");
7251 " cond_z = (%seax == %sedi); edi %c= %d;\n",
7252 lmod_cast_u(po, po->operand[1].lmod),
7253 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
7256 " if (cond_z %s 0) break;\n",
7257 (po->flags & OPF_REPZ) ? "==" : "!=");
7260 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
7261 (po->flags & OPF_REPZ) ? "e" : "ne");
7264 assert_operand_cnt(2);
7265 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
7266 lmod_cast_u(po, po->operand[1].lmod),
7267 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
7268 strcpy(g_comment, "scas");
7270 pfomask &= ~(1 << PFO_Z);
7271 last_arith_dst = NULL;
7272 delayed_flag_op = NULL;
7276 fprintf(fout, " tmp64 = ext_rdtsc();\n");
7277 fprintf(fout, " edx = tmp64 >> 32;\n");
7278 fprintf(fout, " eax = tmp64;");
7282 fprintf(fout, " ext_cpuid(&eax, &ebx, &ecx, &edx);");
7285 // arithmetic w/flags
7287 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
7288 goto dualop_arith_const;
7289 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7293 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7294 if (po->operand[1].type == OPT_CONST) {
7295 j = lmod_bytes(po, po->operand[0].lmod);
7296 if (((1ull << j * 8) - 1) == po->operand[1].val)
7297 goto dualop_arith_const;
7302 assert_operand_cnt(2);
7303 fprintf(fout, " %s %s= %s;",
7304 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7306 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7307 output_std_flags(fout, po, &pfomask, buf1);
7308 last_arith_dst = &po->operand[0];
7309 delayed_flag_op = NULL;
7313 // and 0, or ~0 used instead mov
7314 assert_operand_cnt(2);
7315 fprintf(fout, " %s = %s;",
7316 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7317 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7318 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7319 output_std_flags(fout, po, &pfomask, buf1);
7320 last_arith_dst = &po->operand[0];
7321 delayed_flag_op = NULL;
7326 assert_operand_cnt(2);
7327 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7328 if (pfomask & (1 << PFO_C)) {
7329 if (po->operand[1].type == OPT_CONST) {
7330 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7331 j = po->operand[1].val;
7334 if (po->op == OP_SHL)
7338 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
7342 ferr(po, "zero shift?\n");
7346 pfomask &= ~(1 << PFO_C);
7348 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
7349 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7350 if (po->operand[1].type != OPT_CONST)
7351 fprintf(fout, " & 0x1f");
7353 output_std_flags(fout, po, &pfomask, buf1);
7354 last_arith_dst = &po->operand[0];
7355 delayed_flag_op = NULL;
7359 assert_operand_cnt(2);
7360 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7361 fprintf(fout, " %s = %s%s >> %s;", buf1,
7362 lmod_cast_s(po, po->operand[0].lmod), buf1,
7363 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7364 output_std_flags(fout, po, &pfomask, buf1);
7365 last_arith_dst = &po->operand[0];
7366 delayed_flag_op = NULL;
7371 assert_operand_cnt(3);
7372 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7373 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7374 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
7375 if (po->operand[2].type != OPT_CONST) {
7376 // no handling for "undefined" case, hopefully not needed
7377 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
7380 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7381 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7382 if (po->op == OP_SHLD) {
7383 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
7384 buf1, buf3, buf1, buf2, l, buf3);
7385 strcpy(g_comment, "shld");
7388 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
7389 buf1, buf3, buf1, buf2, l, buf3);
7390 strcpy(g_comment, "shrd");
7392 output_std_flags(fout, po, &pfomask, buf1);
7393 last_arith_dst = &po->operand[0];
7394 delayed_flag_op = NULL;
7399 assert_operand_cnt(2);
7400 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7401 if (po->operand[1].type == OPT_CONST) {
7402 j = po->operand[1].val;
7403 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
7404 fprintf(fout, po->op == OP_ROL ?
7405 " %s = (%s << %d) | (%s >> %d);" :
7406 " %s = (%s >> %d) | (%s << %d);",
7407 buf1, buf1, j, buf1,
7408 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
7412 output_std_flags(fout, po, &pfomask, buf1);
7413 last_arith_dst = &po->operand[0];
7414 delayed_flag_op = NULL;
7419 assert_operand_cnt(2);
7420 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7421 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7422 if (po->operand[1].type == OPT_CONST) {
7423 j = po->operand[1].val % l;
7425 ferr(po, "zero rotate\n");
7426 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
7427 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
7428 if (po->op == OP_RCL) {
7430 " %s = (%s << %d) | (cond_c << %d)",
7431 buf1, buf1, j, j - 1);
7433 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
7437 " %s = (%s >> %d) | (cond_c << %d)",
7438 buf1, buf1, j, l - j);
7440 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
7442 fprintf(fout, ";\n");
7443 fprintf(fout, " cond_c = tmp;");
7447 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
7448 output_std_flags(fout, po, &pfomask, buf1);
7449 last_arith_dst = &po->operand[0];
7450 delayed_flag_op = NULL;
7454 assert_operand_cnt(2);
7455 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7456 if (IS(opr_name(po, 0), opr_name(po, 1))) {
7457 // special case for XOR
7458 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
7459 for (j = 0; j <= PFO_LE; j++) {
7460 if (pfomask & (1 << j)) {
7461 fprintf(fout, " cond_%s = %d;\n",
7462 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
7463 pfomask &= ~(1 << j);
7466 fprintf(fout, " %s = 0;",
7467 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7468 last_arith_dst = &po->operand[0];
7469 delayed_flag_op = NULL;
7475 assert_operand_cnt(2);
7476 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7477 if (pfomask & (1 << PFO_C)) {
7478 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7479 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7480 if (po->operand[0].lmod == OPLM_DWORD) {
7481 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
7482 fprintf(fout, " cond_c = tmp64 >> 32;\n");
7483 fprintf(fout, " %s = (u32)tmp64;",
7484 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7485 strcat(g_comment, " add64");
7488 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
7489 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
7490 fprintf(fout, " %s += %s;",
7491 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7494 pfomask &= ~(1 << PFO_C);
7495 output_std_flags(fout, po, &pfomask, buf1);
7496 last_arith_dst = &po->operand[0];
7497 delayed_flag_op = NULL;
7500 if (pfomask & (1 << PFO_LE)) {
7501 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
7502 fprintf(fout, " cond_%s = %s;\n",
7503 parsed_flag_op_names[PFO_LE], buf1);
7504 pfomask &= ~(1 << PFO_LE);
7509 assert_operand_cnt(2);
7510 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7511 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
7512 for (j = 0; j <= PFO_LE; j++) {
7513 if (!(pfomask & (1 << j)))
7515 if (j == PFO_Z || j == PFO_S)
7518 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7519 fprintf(fout, " cond_%s = %s;\n",
7520 parsed_flag_op_names[j], buf1);
7521 pfomask &= ~(1 << j);
7528 assert_operand_cnt(2);
7529 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7530 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7531 if (po->op == OP_SBB
7532 && IS(po->operand[0].name, po->operand[1].name))
7534 // avoid use of unitialized var
7535 fprintf(fout, " %s = -cond_c;", buf1);
7536 // carry remains what it was
7537 pfomask &= ~(1 << PFO_C);
7540 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
7541 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7543 output_std_flags(fout, po, &pfomask, buf1);
7544 last_arith_dst = &po->operand[0];
7545 delayed_flag_op = NULL;
7550 // on SKL, if src is 0, dst is left unchanged
7551 assert_operand_cnt(2);
7552 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7553 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7554 output_std_flag_z(fout, po, &pfomask, buf2);
7555 if (po->op == OP_BSF)
7556 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
7558 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
7559 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
7560 last_arith_dst = &po->operand[0];
7561 delayed_flag_op = NULL;
7562 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
7566 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
7567 for (j = 0; j <= PFO_LE; j++) {
7568 if (!(pfomask & (1 << j)))
7570 if (j == PFO_Z || j == PFO_S || j == PFO_C)
7573 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7574 fprintf(fout, " cond_%s = %s;\n",
7575 parsed_flag_op_names[j], buf1);
7576 pfomask &= ~(1 << j);
7582 if (pfomask & (1 << PFO_C))
7583 // carry is unaffected by inc/dec.. wtf?
7584 ferr(po, "carry propagation needed\n");
7586 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7587 if (po->operand[0].type == OPT_REG) {
7588 ferr_assert(po, !(po->flags & OPF_LOCK));
7589 strcpy(buf2, po->op == OP_INC ? "++" : "--");
7590 fprintf(fout, " %s%s;", buf1, buf2);
7592 else if (po->flags & OPF_LOCK) {
7593 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], "", 1);
7594 fprintf(fout, " __sync_fetch_and_%s((%s *)(%s), 1);",
7595 po->op == OP_INC ? "add" : "sub",
7596 lmod_type_u(po, po->operand[0].lmod), buf2);
7597 strcat(g_comment, " lock");
7601 strcpy(buf2, po->op == OP_INC ? "+" : "-");
7602 fprintf(fout, " %s %s= 1;", buf1, buf2);
7604 output_std_flags(fout, po, &pfomask, buf1);
7605 last_arith_dst = &po->operand[0];
7606 delayed_flag_op = NULL;
7610 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7611 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
7612 fprintf(fout, " %s = -%s%s;", buf1,
7613 lmod_cast_s(po, po->operand[0].lmod), buf2);
7614 last_arith_dst = &po->operand[0];
7615 delayed_flag_op = NULL;
7616 if (pfomask & PFOB_C) {
7617 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
7620 output_std_flags(fout, po, &pfomask, buf1);
7624 if (po->operand_cnt == 2) {
7625 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7628 if (po->operand_cnt == 3)
7629 ferr(po, "TODO imul3\n");
7632 assert_operand_cnt(1);
7633 switch (po->operand[0].lmod) {
7635 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7636 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
7637 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7638 fprintf(fout, " edx = tmp64 >> 32;\n");
7639 fprintf(fout, " eax = tmp64;");
7642 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7643 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
7644 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7648 ferr(po, "TODO: unhandled mul type\n");
7651 last_arith_dst = NULL;
7652 delayed_flag_op = NULL;
7657 assert_operand_cnt(1);
7658 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7659 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7660 po->op == OP_IDIV));
7661 switch (po->operand[0].lmod) {
7663 if (po->flags & OPF_32BIT)
7664 snprintf(buf2, sizeof(buf2), "%seax", cast);
7666 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7667 snprintf(buf2, sizeof(buf2), "%stmp64",
7668 (po->op == OP_IDIV) ? "(s64)" : "");
7670 if (po->operand[0].type == OPT_REG
7671 && po->operand[0].reg == xDX)
7673 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
7674 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
7677 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
7678 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
7682 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
7683 snprintf(buf2, sizeof(buf2), "%stmp",
7684 (po->op == OP_IDIV) ? "(s32)" : "");
7685 if (po->operand[0].type == OPT_REG
7686 && po->operand[0].reg == xDX)
7688 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
7690 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
7694 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
7696 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
7699 strcat(g_comment, " div16");
7702 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7704 last_arith_dst = NULL;
7705 delayed_flag_op = NULL;
7710 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7712 for (j = 0; j < 8; j++) {
7713 if (pfomask & (1 << j)) {
7714 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7715 fprintf(fout, " cond_%s = %s;",
7716 parsed_flag_op_names[j], buf1);
7723 last_arith_dst = NULL;
7724 delayed_flag_op = po;
7728 // SETcc - should already be handled
7731 // note: we reuse OP_Jcc for SETcc, only flags differ
7733 fprintf(fout, "\n goto %s;", po->operand[0].name);
7737 fprintf(fout, " if (ecx == 0)\n");
7738 fprintf(fout, " goto %s;", po->operand[0].name);
7739 strcat(g_comment, " jecxz");
7743 fprintf(fout, " if (--ecx != 0)\n");
7744 fprintf(fout, " goto %s;", po->operand[0].name);
7745 strcat(g_comment, " loop");
7749 assert_operand_cnt(1);
7750 last_arith_dst = NULL;
7751 delayed_flag_op = NULL;
7753 if (po->operand[0].type == OPT_REGMEM) {
7754 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7757 ferr(po, "parse failure for jmp '%s'\n",
7758 po->operand[0].name);
7759 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
7762 else if (po->operand[0].type != OPT_LABEL)
7763 ferr(po, "unhandled jmp type\n");
7765 fprintf(fout, " goto %s;", po->operand[0].name);
7769 assert_operand_cnt(1);
7771 my_assert_not(pp, NULL);
7774 if (po->flags & OPF_CC) {
7775 // we treat conditional branch to another func
7776 // (yes such code exists..) as conditional tailcall
7778 fprintf(fout, " {\n");
7781 if (pp->is_fptr && !pp->is_arg) {
7782 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7783 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7786 if (pp->is_fptr && (pp->is_unresolved || pp->is_guessed)) {
7787 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7788 buf3, asmfn, po->asmln, pp->name);
7791 fprintf(fout, "%s", buf3);
7792 if (strstr(pp->ret_type.name, "int64")) {
7793 if (po->flags & OPF_TAIL)
7794 ferr(po, "int64 and tail?\n");
7795 fprintf(fout, "tmp64 = ");
7797 else if (!IS(pp->ret_type.name, "void")) {
7798 if (po->flags & OPF_TAIL) {
7799 if (regmask_ret & mxAX) {
7800 fprintf(fout, "return ");
7801 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7802 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7804 else if (regmask_ret & mxST0)
7805 ferr(po, "float tailcall\n");
7807 else if (po->regmask_dst & mxAX) {
7808 fprintf(fout, "eax = ");
7809 if (pp->ret_type.is_ptr)
7810 fprintf(fout, "(u32)");
7812 else if (po->regmask_dst & mxST0) {
7813 ferr_assert(po, po->flags & OPF_FPUSH);
7814 if (need_float_stack)
7815 fprintf(fout, "f_st[--f_stp & 7] = ");
7817 fprintf(fout, "f_st0 = ");
7821 if (pp->name[0] == 0)
7822 ferr(po, "missing pp->name\n");
7823 fprintf(fout, "%s%s(", pp->name,
7824 pp->has_structarg ? "_sa" : "");
7826 if (po->flags & OPF_ATAIL) {
7828 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7829 check_compat |= pp->argc_stack > 0;
7831 && (pp->argc_stack != g_func_pp->argc_stack
7832 || pp->is_stdcall != g_func_pp->is_stdcall))
7833 ferr(po, "incompatible arg-reuse tailcall\n");
7834 if (g_func_pp->has_retreg)
7835 ferr(po, "TODO: retreg+tailcall\n");
7837 for (arg = j = 0; arg < pp->argc; arg++) {
7839 fprintf(fout, ", ");
7842 if (pp->arg[arg].type.is_ptr)
7843 snprintf(cast, sizeof(cast), "(%s)",
7844 pp->arg[arg].type.name);
7846 if (pp->arg[arg].reg != NULL) {
7847 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7851 for (; j < g_func_pp->argc; j++)
7852 if (g_func_pp->arg[j].reg == NULL)
7854 fprintf(fout, "%sa%d", cast, j + 1);
7859 for (arg = 0; arg < pp->argc; arg++) {
7861 fprintf(fout, ", ");
7864 if (pp->arg[arg].type.is_ptr)
7865 snprintf(cast, sizeof(cast), "(%s)",
7866 pp->arg[arg].type.name);
7868 if (pp->arg[arg].reg != NULL) {
7869 if (pp->arg[arg].type.is_retreg)
7870 fprintf(fout, "&%s", pp->arg[arg].reg);
7871 else if (IS(pp->arg[arg].reg, "ebp")
7872 && g_bp_frame && !(po->flags & OPF_EBP_S))
7874 // rare special case
7875 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7876 strcat(g_comment, " bp_ref");
7879 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7884 if (pp->arg[arg].push_ref_cnt == 0)
7885 ferr(po, "parsed_op missing for arg%d\n", arg);
7886 if (pp->arg[arg].push_ref_cnt > 1)
7887 ferr_assert(po, pp->arg[arg].is_saved);
7888 tmp_op = pp->arg[arg].push_refs[0];
7889 ferr_assert(po, tmp_op != NULL);
7891 if (tmp_op->flags & OPF_VAPUSH) {
7892 fprintf(fout, "ap");
7894 else if (tmp_op->op == OP_FST) {
7895 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7896 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7899 else if (pp->arg[arg].type.is_64bit) {
7900 ferr_assert(po, tmp_op->p_argpass == 0);
7901 ferr_assert(po, !pp->arg[arg].is_saved);
7902 ferr_assert(po, !pp->arg[arg].type.is_float);
7903 ferr_assert(po, cast[0] == 0);
7904 out_src_opr(buf1, sizeof(buf1),
7905 tmp_op, &tmp_op->operand[0], cast, 0);
7907 ferr_assert(po, pp->arg[arg].push_ref_cnt == 1);
7908 tmp_op = pp->arg[arg].push_refs[0];
7909 ferr_assert(po, tmp_op != NULL);
7910 out_src_opr(buf2, sizeof(buf2),
7911 tmp_op, &tmp_op->operand[0], cast, 0);
7912 fprintf(fout, "((u64)(%s) << 32) | (%s)",
7915 else if (tmp_op->p_argpass != 0) {
7916 ferr_assert(po, !pp->arg[arg].type.is_float);
7917 fprintf(fout, "a%d", tmp_op->p_argpass);
7919 else if (pp->arg[arg].is_saved) {
7920 ferr_assert(po, tmp_op->p_argnum > 0);
7921 ferr_assert(po, !pp->arg[arg].type.is_float);
7922 fprintf(fout, "%s%s", cast,
7923 saved_arg_name(buf1, sizeof(buf1),
7924 tmp_op->p_arggrp, tmp_op->p_argnum));
7926 else if (pp->arg[arg].type.is_float) {
7927 ferr_assert(po, !pp->arg[arg].type.is_64bit);
7929 out_src_opr_float(buf1, sizeof(buf1),
7930 tmp_op, &tmp_op->operand[0], need_float_stack));
7934 out_src_opr(buf1, sizeof(buf1),
7935 tmp_op, &tmp_op->operand[0], cast, 0));
7939 fprintf(fout, ");");
7941 if (strstr(pp->ret_type.name, "int64")) {
7942 fprintf(fout, "\n");
7943 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7944 fprintf(fout, "%seax = tmp64;", buf3);
7947 if (pp->is_unresolved) {
7948 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7950 strcat(g_comment, buf2);
7953 if (po->flags & OPF_TAIL) {
7955 if (i == opcnt - 1 || pp->is_noreturn)
7957 else if (IS(pp->ret_type.name, "void"))
7959 else if (!(regmask_ret & (1 << xAX)))
7961 // else already handled as 'return f()'
7964 fprintf(fout, "\n%sreturn;", buf3);
7965 strcat(g_comment, " ^ tailcall");
7968 strcat(g_comment, " tailcall");
7970 if ((regmask_ret & (1 << xAX))
7971 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7973 ferr(po, "int func -> void func tailcall?\n");
7976 if (pp->is_noreturn)
7977 strcat(g_comment, " noreturn");
7978 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7979 strcat(g_comment, " argframe");
7980 if (po->flags & OPF_CC)
7981 strcat(g_comment, " cond");
7983 if (po->flags & OPF_CC)
7984 fprintf(fout, "\n }");
7986 delayed_flag_op = NULL;
7987 last_arith_dst = NULL;
7992 if (g_func_pp->is_vararg)
7993 fprintf(fout, " va_end(ap);\n");
7994 if (g_func_pp->has_retreg) {
7995 for (arg = 0; arg < g_func_pp->argc; arg++)
7996 if (g_func_pp->arg[arg].type.is_retreg)
7997 fprintf(fout, " *r_%s = %s;\n",
7998 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
8001 if (regmask_ret & mxST0) {
8002 fprintf(fout, " return %s;", float_st0);
8004 else if (!(regmask_ret & mxAX)) {
8005 if (i != opcnt - 1 || label_pending)
8006 fprintf(fout, " return;");
8008 else if (g_func_pp->ret_type.is_ptr) {
8009 fprintf(fout, " return (%s)eax;",
8010 g_func_pp->ret_type.name);
8012 else if (IS(g_func_pp->ret_type.name, "__int64"))
8013 fprintf(fout, " return ((u64)edx << 32) | eax;");
8015 fprintf(fout, " return eax;");
8017 last_arith_dst = NULL;
8018 delayed_flag_op = NULL;
8022 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
8023 if (po->p_argnum != 0) {
8024 // special case - saved func arg
8025 fprintf(fout, " %s = %s;",
8026 saved_arg_name(buf2, sizeof(buf2),
8027 po->p_arggrp, po->p_argnum), buf1);
8030 else if (po->flags & OPF_RSAVE) {
8031 fprintf(fout, " s_%s = %s;", buf1, buf1);
8034 else if (po->flags & OPF_PPUSH) {
8036 ferr_assert(po, tmp_op != NULL);
8037 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
8038 fprintf(fout, " pp_%s = %s;", buf2, buf1);
8041 else if (g_func_pp->is_userstack) {
8042 fprintf(fout, " *(--esp) = %s;", buf1);
8045 if (!(g_ida_func_attr & IDAFA_NORETURN))
8046 ferr(po, "stray push encountered\n");
8051 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
8052 if (po->flags & OPF_RSAVE) {
8053 fprintf(fout, " %s = s_%s;", buf1, buf1);
8056 else if (po->flags & OPF_PPUSH) {
8057 // push/pop graph / non-const
8058 ferr_assert(po, po->datap == NULL);
8059 fprintf(fout, " %s = pp_%s;", buf1, buf1);
8062 else if (po->datap != NULL) {
8065 fprintf(fout, " %s = %s;", buf1,
8066 out_src_opr(buf2, sizeof(buf2),
8067 tmp_op, &tmp_op->operand[0],
8068 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
8071 else if (g_func_pp->is_userstack) {
8072 fprintf(fout, " %s = *esp++;", buf1);
8076 ferr(po, "stray pop encountered\n");
8086 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
8087 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
8088 po->op == OPP_ALLSHL ? "<<" : ">>");
8089 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
8090 strcat(g_comment, po->op == OPP_ALLSHL
8091 ? " allshl" : " allshr");
8096 if (need_float_stack) {
8097 out_src_opr_float(buf1, sizeof(buf1),
8098 po, &po->operand[0], 1);
8099 if (po->regmask_src & mxSTa) {
8100 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
8104 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
8107 if (po->flags & OPF_FSHIFT)
8108 fprintf(fout, " f_st1 = f_st0;");
8109 if (po->operand[0].type == OPT_REG
8110 && po->operand[0].reg == xST0)
8112 strcat(g_comment, " fld st");
8115 fprintf(fout, " f_st0 = %s;",
8116 out_src_opr_float(buf1, sizeof(buf1),
8117 po, &po->operand[0], 0));
8119 strcat(g_comment, " fld");
8123 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
8124 lmod_cast(po, po->operand[0].lmod, 1), 0);
8125 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
8126 if (need_float_stack) {
8127 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
8130 if (po->flags & OPF_FSHIFT)
8131 fprintf(fout, " f_st1 = f_st0;");
8132 fprintf(fout, " f_st0 = %s;", buf2);
8134 strcat(g_comment, " fild");
8138 if (need_float_stack)
8139 fprintf(fout, " f_st[--f_stp & 7] = ");
8141 if (po->flags & OPF_FSHIFT)
8142 fprintf(fout, " f_st1 = f_st0;");
8143 fprintf(fout, " f_st0 = ");
8145 switch (po->operand[0].val) {
8146 case X87_CONST_1: fprintf(fout, "1.0;"); break;
8147 case X87_CONST_L2T: fprintf(fout, "3.321928094887362;"); break;
8148 case X87_CONST_L2E: fprintf(fout, "M_LOG2E;"); break;
8149 case X87_CONST_PI: fprintf(fout, "M_PI;"); break;
8150 case X87_CONST_LG2: fprintf(fout, "0.301029995663981;"); break;
8151 case X87_CONST_LN2: fprintf(fout, "M_LN2;"); break;
8152 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
8153 default: ferr_assert(po, 0); break;
8158 if (po->flags & OPF_FARG) {
8159 // store to stack as func arg
8160 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
8164 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8166 dead_dst = po->operand[0].type == OPT_REG
8167 && po->operand[0].reg == xST0;
8170 fprintf(fout, " %s = %s;", buf1, float_st0);
8171 if (po->flags & OPF_FSHIFT) {
8172 if (need_float_stack)
8173 fprintf(fout, " f_stp++;");
8175 fprintf(fout, " f_st0 = f_st1;");
8177 if (dead_dst && !(po->flags & OPF_FSHIFT))
8180 strcat(g_comment, " fst");
8184 fprintf(fout, " %s = %s%s;",
8185 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
8186 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
8187 if (po->flags & OPF_FSHIFT) {
8188 if (need_float_stack)
8189 fprintf(fout, " f_stp++;");
8191 fprintf(fout, " f_st0 = f_st1;");
8193 strcat(g_comment, " fist");
8197 fprintf(fout, " %s = fabs%s(%s);", float_st0,
8198 need_double ? "" : "f", float_st0);
8205 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8207 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8209 dead_dst = (po->flags & OPF_FPOP)
8210 && po->operand[0].type == OPT_REG
8211 && po->operand[0].reg == xST0;
8213 case OP_FADD: j = '+'; break;
8214 case OP_FDIV: j = '/'; break;
8215 case OP_FMUL: j = '*'; break;
8216 case OP_FSUB: j = '-'; break;
8217 default: j = 'x'; break;
8219 if (need_float_stack) {
8221 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
8222 if (po->flags & OPF_FSHIFT)
8223 fprintf(fout, " f_stp++;");
8226 if (po->flags & OPF_FSHIFT) {
8227 // note: assumes only 2 regs handled
8229 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
8231 fprintf(fout, " f_st0 = f_st1;");
8234 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
8236 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
8241 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8243 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8245 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
8247 dead_dst = (po->flags & OPF_FPOP)
8248 && po->operand[0].type == OPT_REG
8249 && po->operand[0].reg == xST0;
8250 j = po->op == OP_FDIVR ? '/' : '-';
8251 if (need_float_stack) {
8253 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
8254 if (po->flags & OPF_FSHIFT)
8255 fprintf(fout, " f_stp++;");
8258 if (po->flags & OPF_FSHIFT) {
8260 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
8262 fprintf(fout, " f_st0 = f_st1;");
8265 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
8267 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
8275 case OP_FIADD: j = '+'; break;
8276 case OP_FIDIV: j = '/'; break;
8277 case OP_FIMUL: j = '*'; break;
8278 case OP_FISUB: j = '-'; break;
8279 default: j = 'x'; break;
8281 fprintf(fout, " %s %c= (%s)%s;", float_st0,
8283 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
8284 lmod_cast(po, po->operand[0].lmod, 1), 0));
8289 fprintf(fout, " %s = %s %c %s;", float_st0,
8290 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8292 po->op == OP_FIDIVR ? '/' : '-', float_st0);
8297 ferr_assert(po, po->datap != NULL);
8298 mask = (long)po->datap & 0xffff;
8299 z_check = ((long)po->datap >> 16) & 1;
8300 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8302 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
8303 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
8306 else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
8307 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
8310 else if (mask == 0x4100) { // C3, C0
8312 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
8314 strcat(g_comment, " z_chk_det");
8317 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
8318 "(%s < %s ? 0x0100 : 0);",
8319 float_st0, buf1, float_st0, buf1);
8323 ferr(po, "unhandled sw mask: %x\n", mask);
8324 if (po->flags & OPF_FSHIFT) {
8325 if (need_float_stack) {
8326 if (po->flags & OPF_FPOPP)
8327 fprintf(fout, " f_stp += 2;");
8329 fprintf(fout, " f_stp++;");
8332 ferr_assert(po, !(po->flags & OPF_FPOPP));
8333 fprintf(fout, " f_st0 = f_st1;");
8340 fprintf(fout, " %s = f_sw;",
8341 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
8345 fprintf(fout, " %s = -%s;", float_st0, float_st0);
8349 fprintf(fout, " %s = cos%s(%s);", float_st0,
8350 need_double ? "" : "f", float_st0);
8354 if (need_float_stack) {
8355 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
8356 need_double ? "" : "f", float_st1, float_st0);
8357 fprintf(fout, " f_stp++;");
8360 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
8361 need_double ? "" : "f");
8366 if (need_float_stack) {
8367 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
8368 float_st1, need_double ? "" : "f", float_st0);
8369 fprintf(fout, " f_stp++;");
8372 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
8373 need_double ? "" : "f");
8375 strcat(g_comment, " fyl2x");
8379 fprintf(fout, " %s = sin%s(%s);", float_st0,
8380 need_double ? "" : "f", float_st0);
8384 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
8385 need_double ? "" : "f", float_st0);
8389 dead_dst = po->operand[0].type == OPT_REG
8390 && po->operand[0].reg == xST0;
8392 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8394 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
8395 float_st0, float_st0, buf1, buf1);
8396 strcat(g_comment, " fxch");
8403 ferr_assert(po, po->flags & OPF_32BIT);
8404 fprintf(fout, " eax = (s32)%s;", float_st0);
8405 if (po->flags & OPF_FSHIFT) {
8406 if (need_float_stack)
8407 fprintf(fout, " f_stp++;");
8409 fprintf(fout, " f_st0 = f_st1;");
8411 strcat(g_comment, " ftol");
8415 if (need_float_stack) {
8416 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
8417 need_double ? "" : "f", float_st1, float_st0);
8418 fprintf(fout, " f_stp++;");
8421 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
8422 need_double ? "" : "f");
8424 strcat(g_comment, " CIpow");
8428 fprintf(fout, " do_skip_code_abort();");
8433 fprintf(fout, " do_emms();");
8437 if (po->flags & OPF_TAIL) {
8438 fprintf(fout, "\n");
8439 strcat(g_comment, " tail");
8446 ferr(po, "unhandled op type %d, flags %x\n",
8451 if (g_comment[0] != 0) {
8452 char *p = g_comment;
8453 while (my_isblank(*p))
8455 fprintf(fout, " // %s", p);
8460 fprintf(fout, "\n");
8462 // some sanity checking
8463 if (po->flags & OPF_REP) {
8464 if (po->op != OP_STOS && po->op != OP_MOVS
8465 && po->op != OP_CMPS && po->op != OP_SCAS)
8466 ferr(po, "unexpected rep\n");
8467 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
8468 && (po->op == OP_CMPS || po->op == OP_SCAS))
8469 ferr(po, "cmps/scas with plain rep\n");
8471 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
8472 && po->op != OP_CMPS && po->op != OP_SCAS)
8473 ferr(po, "unexpected repz/repnz\n");
8476 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
8478 if ((po->flags & OPF_LOCK) && !lock_handled)
8479 ferr(po, "unhandled lock\n");
8481 // see is delayed flag stuff is still valid
8482 if (delayed_flag_op != NULL && delayed_flag_op != po) {
8483 if (is_any_opr_modified(delayed_flag_op, po, 0))
8484 delayed_flag_op = NULL;
8487 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
8488 if (is_opr_modified(last_arith_dst, po))
8489 last_arith_dst = NULL;
8496 if (g_stack_fsz && !g_stack_frame_used)
8497 fprintf(fout, " (void)sf;\n");
8499 fprintf(fout, "}\n\n");
8501 gen_x_cleanup(opcnt);
8504 static void gen_x_cleanup(int opcnt)
8508 for (i = 0; i < opcnt; i++) {
8509 struct label_ref *lr, *lr_del;
8511 lr = g_label_refs[i].next;
8512 while (lr != NULL) {
8517 g_label_refs[i].i = -1;
8518 g_label_refs[i].next = NULL;
8520 if (ops[i].op == OP_CALL) {
8522 proto_release(ops[i].pp);
8528 struct func_proto_dep;
8530 struct func_prototype {
8534 int regmask_dep; // likely register args
8535 int regmask_use; // used registers
8536 int has_ret:3; // -1, 0, 1: unresolved, no, yes
8537 unsigned int has_ret64:1;
8538 unsigned int dep_resolved:1;
8539 unsigned int is_stdcall:1;
8540 unsigned int eax_pass:1; // returns without touching eax
8541 unsigned int ptr_taken:1; // pointer taken of this func
8542 struct func_proto_dep *dep_func;
8544 const struct parsed_proto *pp; // seed pp, if any
8547 struct func_proto_dep {
8549 struct func_prototype *proto;
8550 int regmask_live; // .. at the time of call
8551 unsigned int ret_dep:1; // return from this is caller's return
8552 unsigned int has_ret:1; // found from eax use after return
8553 unsigned int has_ret64:1;
8554 unsigned int ptr_taken:1; // pointer taken, not a call
8557 static struct func_prototype *hg_fp;
8558 static int hg_fp_cnt;
8560 static struct scanned_var {
8562 enum opr_lenmod lmod;
8563 unsigned int is_seeded:1;
8564 unsigned int is_c_str:1;
8565 const struct parsed_proto *pp; // seed pp, if any
8567 static int hg_var_cnt;
8569 static char **hg_refs;
8570 static int hg_ref_cnt;
8572 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8575 static struct func_prototype *hg_fp_add(const char *funcn)
8577 struct func_prototype *fp;
8579 if ((hg_fp_cnt & 0xff) == 0) {
8580 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
8581 my_assert_not(hg_fp, NULL);
8582 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
8585 fp = &hg_fp[hg_fp_cnt];
8586 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
8588 fp->argc_stack = -1;
8594 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
8599 for (i = 0; i < fp->dep_func_cnt; i++)
8600 if (IS(fp->dep_func[i].name, name))
8601 return &fp->dep_func[i];
8606 static void hg_fp_add_dep(struct func_prototype *fp, const char *name,
8607 unsigned int ptr_taken)
8609 struct func_proto_dep * dep;
8612 dep = hg_fp_find_dep(fp, name);
8613 if (dep != NULL && dep->ptr_taken == ptr_taken)
8616 if ((fp->dep_func_cnt & 0xff) == 0) {
8617 fp->dep_func = realloc(fp->dep_func,
8618 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
8619 my_assert_not(fp->dep_func, NULL);
8620 memset(&fp->dep_func[fp->dep_func_cnt], 0,
8621 sizeof(fp->dep_func[0]) * 0x100);
8623 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
8624 fp->dep_func[fp->dep_func_cnt].ptr_taken = ptr_taken;
8628 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
8630 const struct func_prototype *p1 = p1_, *p2 = p2_;
8631 return strcmp(p1->name, p2->name);
8635 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
8637 const struct func_prototype *p1 = p1_, *p2 = p2_;
8638 return p1->id - p2->id;
8642 static void hg_ref_add(const char *name)
8644 if ((hg_ref_cnt & 0xff) == 0) {
8645 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8646 my_assert_not(hg_refs, NULL);
8647 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8650 hg_refs[hg_ref_cnt] = strdup(name);
8651 my_assert_not(hg_refs[hg_ref_cnt], NULL);
8655 // recursive register dep pass
8656 // - track saved regs (part 2)
8657 // - try to figure out arg-regs
8658 // - calculate reg deps
8659 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8660 struct func_prototype *fp, int regmask_save, int regmask_dst,
8661 int *regmask_dep, int *regmask_use, int *has_ret)
8663 struct func_proto_dep *dep;
8664 struct parsed_op *po;
8665 int from_caller = 0;
8670 for (; i < opcnt; i++)
8672 if (cbits[i >> 3] & (1 << (i & 7)))
8674 cbits[i >> 3] |= (1 << (i & 7));
8678 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8679 if (po->flags & OPF_RMD)
8682 if (po->btj != NULL) {
8684 for (j = 0; j < po->btj->count; j++) {
8685 check_i(po, po->btj->d[j].bt_i);
8686 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8687 regmask_save, regmask_dst, regmask_dep, regmask_use,
8693 check_i(po, po->bt_i);
8694 if (po->flags & OPF_CJMP) {
8695 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8696 regmask_save, regmask_dst, regmask_dep, regmask_use,
8705 if (po->flags & OPF_FARG)
8706 /* (just calculate register deps) */;
8707 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8709 reg = po->operand[0].reg;
8710 ferr_assert(po, reg >= 0);
8712 if (po->flags & OPF_RSAVE) {
8713 regmask_save |= 1 << reg;
8716 if (po->flags & OPF_DONE)
8719 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2,
8722 regmask_save |= 1 << reg;
8723 po->flags |= OPF_RMD;
8724 scan_for_pop(i + 1, opcnt, i + opcnt * 3,
8725 reg, 0, 0, 0, OPF_RMD);
8729 else if (po->flags & OPF_RMD)
8731 else if (po->op == OP_CALL) {
8732 po->regmask_dst |= 1 << xAX;
8734 dep = hg_fp_find_dep(fp, po->operand[0].name);
8736 dep->regmask_live = regmask_save | regmask_dst;
8737 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8738 dep->regmask_live |= 1 << xBP;
8740 if ((po->flags & OPF_TAIL) && po->pp != NULL
8741 && po->pp->is_stdcall)
8744 else if (po->op == OP_RET) {
8745 if (po->operand_cnt > 0) {
8747 if (fp->argc_stack >= 0
8748 && fp->argc_stack != po->operand[0].val / 4)
8749 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8750 fp->argc_stack = po->operand[0].val / 4;
8754 if (!fp->eax_pass && (po->flags & OPF_TAIL)) {
8755 if (po->op == OP_CALL) {
8762 ret = resolve_origin_reg(i, xAX, i + opcnt * 4, &j, &from_caller);
8765 if (ret != 1 && from_caller) {
8766 // unresolved eax - probably void func
8771 if (j >= 0 && ops[j].op == OP_CALL) {
8772 if (ops[j].pp != NULL && !ops[j].pp->is_unresolved) {
8773 int call_has_ret = !IS(ops[j].pp->ret_type.name, "void");
8774 if (ops[j].pp->is_noreturn) {
8775 // could be some fail path
8777 *has_ret = call_has_ret;
8780 *has_ret = call_has_ret;
8783 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8795 l = regmask_save | regmask_dst;
8796 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8799 l = po->regmask_src & ~l;
8802 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8803 l, regmask_dst, regmask_save, po->flags);
8806 *regmask_use |= (po->regmask_src | po->regmask_dst)
8808 regmask_dst |= po->regmask_dst;
8810 if (po->flags & OPF_TAIL) {
8811 if (!(po->flags & OPF_CC)) // not cond. tailcall
8817 static void gen_hdr(const char *funcn, int opcnt)
8819 unsigned char cbits[MAX_OPS / 8];
8820 const struct parsed_proto *pp_c;
8821 struct parsed_proto *pp;
8822 struct func_prototype *fp;
8823 struct func_proto_dep *dep;
8824 struct parsed_op *po;
8825 const char *tmpname;
8826 int regmask_dummy = 0;
8829 int max_bp_offset = 0;
8834 pp_c = proto_parse(g_fhdr, funcn, 1);
8836 // already in seed, will add to hg_fp later
8839 fp = hg_fp_add(funcn);
8841 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8842 g_stack_frame_used = 0;
8846 // - resolve all branches
8847 // - parse calls with labels
8848 resolve_branches_parse_calls(opcnt);
8851 // - handle ebp/esp frame, remove ops related to it
8852 scan_prologue_epilogue(opcnt, NULL);
8855 // - remove dead labels
8857 // - collect function ptr refs
8858 for (i = 0; i < opcnt; i++)
8860 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8866 if (po->flags & (OPF_RMD|OPF_DONE))
8869 if (po->op == OP_CALL) {
8870 if (po->operand[0].type == OPT_LABEL)
8871 hg_fp_add_dep(fp, opr_name(po, 0), 0);
8872 else if (po->pp != NULL)
8873 hg_fp_add_dep(fp, po->pp->name, 0);
8875 else if (po->op == OP_MOV && po->operand[1].type == OPT_OFFSET) {
8876 tmpname = opr_name(po, 1);
8877 if (IS_START(tmpname, "p_") || IS_START(tmpname, "sub_"))
8878 hg_fp_add_dep(fp, tmpname, 1);
8880 else if (po->op == OP_PUSH && po->operand[0].type == OPT_OFFSET) {
8881 tmpname = opr_name(po, 0);
8882 if (IS_START(tmpname, "p_") || IS_START(tmpname, "sub_"))
8883 hg_fp_add_dep(fp, tmpname, 1);
8888 // - handle push <const>/pop pairs
8889 for (i = 0; i < opcnt; i++)
8892 if (po->flags & (OPF_RMD|OPF_DONE))
8895 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8896 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8900 // - process trivial calls
8901 for (i = 0; i < opcnt; i++)
8904 if (po->flags & (OPF_RMD|OPF_DONE))
8907 if (po->op == OP_CALL)
8909 pp = process_call_early(i, opcnt, &j);
8911 if (!(po->flags & OPF_ATAIL))
8912 // since we know the args, try to collect them
8913 if (collect_call_args_early(i, opcnt, pp, NULL, NULL) != 0)
8919 // commit esp adjust
8920 if (ops[j].op != OP_POP)
8921 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8923 for (l = 0; l < pp->argc_stack; l++)
8924 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8928 po->flags |= OPF_DONE;
8934 // - track saved regs (simple)
8936 for (i = 0; i < opcnt; i++)
8939 if (po->flags & (OPF_RMD|OPF_DONE))
8942 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8943 && po->operand[0].reg != xCX)
8945 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8947 // regmask_save |= 1 << po->operand[0].reg; // do it later
8948 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8949 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8952 else if (po->op == OP_CALL)
8954 pp = process_call(i, opcnt);
8956 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8957 // since we know the args, collect them
8958 ret = collect_call_args(po, i, opcnt, pp, ®mask_dummy,
8961 if (!(po->flags & OPF_TAIL)
8962 && po->operand[0].type == OPT_LABEL)
8964 dep = hg_fp_find_dep(fp, opr_name(po, 0));
8965 ferr_assert(po, dep != NULL);
8966 // treat al write as overwrite to avoid many false positives
8967 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
8968 i + opcnt * 25, &j);
8971 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
8972 i + opcnt * 26, &j);
8973 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j]))
8980 memset(cbits, 0, (opcnt + 7) / 8);
8981 regmask_dep = regmask_use = 0;
8984 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0,
8985 ®mask_dep, ®mask_use, &has_ret);
8987 // find unreachable code - must be fixed in IDA
8988 for (i = 0; i < opcnt; i++)
8990 if (cbits[i >> 3] & (1 << (i & 7)))
8993 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8994 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8996 // the compiler sometimes still generates code after
8997 // noreturn OS functions
9000 if (!(ops[i].flags & OPF_RMD)
9001 && ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
9003 ferr(&ops[i], "unreachable code\n");
9007 for (i = 0; i < g_eqcnt; i++) {
9008 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
9009 max_bp_offset = g_eqs[i].offset;
9012 if (fp->argc_stack < 0) {
9013 max_bp_offset = (max_bp_offset + 3) & ~3;
9014 fp->argc_stack = max_bp_offset / 4;
9015 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
9019 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
9020 fp->regmask_use = regmask_use;
9021 fp->has_ret = has_ret;
9023 printf("// has_ret %d, regmask_dep %x\n",
9024 fp->has_ret, fp->regmask_dep);
9025 output_hdr_fp(stdout, fp, 1);
9026 if (IS(funcn, "sub_10007F72")) exit(1);
9029 gen_x_cleanup(opcnt);
9032 static void hg_fp_resolve_deps(struct func_prototype *fp)
9034 struct func_prototype fp_s;
9035 struct func_proto_dep *dep;
9039 // this thing is recursive, so mark first..
9040 fp->dep_resolved = 1;
9042 for (i = 0; i < fp->dep_func_cnt; i++) {
9043 dep = &fp->dep_func[i];
9045 strcpy(fp_s.name, dep->name);
9046 dep->proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
9047 sizeof(hg_fp[0]), hg_fp_cmp_name);
9048 if (dep->proto != NULL) {
9049 if (dep->ptr_taken) {
9050 dep->proto->ptr_taken = 1;
9054 if (!dep->proto->dep_resolved)
9055 hg_fp_resolve_deps(dep->proto);
9057 regmask_dep = ~dep->regmask_live
9058 & dep->proto->regmask_dep;
9059 fp->regmask_dep |= regmask_dep;
9060 // printf("dep %s %s |= %x\n", fp->name,
9061 // fp->dep_func[i].name, regmask_dep);
9063 if (dep->has_ret && (dep->proto->regmask_use & mxAX))
9064 dep->proto->has_ret = 1;
9065 if (dep->has_ret64 && (dep->proto->regmask_use & mxDX))
9066 dep->proto->has_ret64 = 1;
9067 if (fp->has_ret == -1 && dep->ret_dep)
9068 fp->has_ret = dep->proto->has_ret;
9073 // make all thiscall/edx arg functions referenced from .data fastcall
9074 static void do_func_refs_from_data(void)
9076 struct func_prototype *fp, fp_s;
9079 for (i = 0; i < hg_ref_cnt; i++) {
9080 strcpy(fp_s.name, hg_refs[i]);
9081 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
9082 sizeof(hg_fp[0]), hg_fp_cmp_name);
9088 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
9091 const struct parsed_proto *pp;
9092 char *p, namebuf[NAMELEN];
9098 for (; count > 0; count--, fp++) {
9099 if (fp->has_ret == -1)
9100 fprintf(fout, "// ret unresolved\n");
9102 fprintf(fout, "// dep:");
9103 for (j = 0; j < fp->dep_func_cnt; j++) {
9104 fprintf(fout, " %s/", fp->dep_func[j].name);
9105 if (fp->dep_func[j].proto != NULL)
9106 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
9107 fp->dep_func[j].proto->has_ret);
9109 fprintf(fout, "\n");
9112 p = strchr(fp->name, '@');
9114 memcpy(namebuf, fp->name, p - fp->name);
9115 namebuf[p - fp->name] = 0;
9123 pp = proto_parse(g_fhdr, name, 1);
9124 if (pp != NULL && pp->is_include)
9127 if (fp->pp != NULL) {
9128 // part of seed, output later
9132 regmask_dep = fp->regmask_dep;
9133 argc_normal = fp->argc_stack;
9134 if (fp->ptr_taken && regmask_dep
9135 && (regmask_dep & ~(mxCX|mxDX)) == 0)
9137 if ((regmask_dep & mxDX) || fp->argc_stack > 0)
9138 regmask_dep |= mxCX | mxDX;
9141 fprintf(fout, "%-5s",
9142 fp->pp ? fp->pp->ret_type.name :
9143 fp->has_ret64 ? "__int64" :
9144 fp->has_ret ? "int" : "void");
9145 if (regmask_dep == mxCX && fp->is_stdcall && fp->argc_stack > 0) {
9146 fprintf(fout, "/*__thiscall*/ ");
9150 else if ((regmask_dep == (mxCX | mxDX)
9151 && (fp->is_stdcall || fp->argc_stack == 0))
9152 || (regmask_dep == mxCX && fp->argc_stack == 0))
9154 fprintf(fout, " __fastcall ");
9155 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
9161 else if (regmask_dep && !fp->is_stdcall) {
9162 fprintf(fout, "/*__usercall*/ ");
9164 else if (regmask_dep) {
9165 fprintf(fout, "/*__userpurge*/ ");
9167 else if (fp->is_stdcall)
9168 fprintf(fout, " __stdcall ");
9170 fprintf(fout, " __cdecl ");
9172 fprintf(fout, "%s(", name);
9175 for (j = 0; j < xSP; j++) {
9176 if (regmask_dep & (1 << j)) {
9179 fprintf(fout, ", ");
9181 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
9183 fprintf(fout, "int");
9184 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
9188 for (j = 0; j < argc_normal; j++) {
9191 fprintf(fout, ", ");
9192 if (fp->pp != NULL) {
9193 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
9194 if (!fp->pp->arg[arg - 1].type.is_ptr)
9198 fprintf(fout, "int ");
9199 fprintf(fout, "a%d", arg);
9202 fprintf(fout, ");\n");
9206 static void output_hdr(FILE *fout)
9208 static const char *lmod_c_names[] = {
9209 [OPLM_UNSPEC] = "???",
9210 [OPLM_BYTE] = "uint8_t",
9211 [OPLM_WORD] = "uint16_t",
9212 [OPLM_DWORD] = "uint32_t",
9213 [OPLM_QWORD] = "uint64_t",
9215 const struct scanned_var *var;
9216 struct func_prototype *fp;
9217 char line[256] = { 0, };
9221 // add stuff from headers
9222 for (i = 0; i < pp_cache_size; i++) {
9223 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
9224 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
9226 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
9227 fp = hg_fp_add(name);
9228 fp->pp = &pp_cache[i];
9229 fp->argc_stack = fp->pp->argc_stack;
9230 fp->is_stdcall = fp->pp->is_stdcall;
9231 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
9232 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
9236 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
9237 for (i = 0; i < hg_fp_cnt; i++)
9238 hg_fp_resolve_deps(&hg_fp[i]);
9240 // adjust functions referenced from data segment
9241 do_func_refs_from_data();
9243 // final adjustments
9244 for (i = 0; i < hg_fp_cnt; i++) {
9245 if (hg_fp[i].eax_pass && (hg_fp[i].regmask_dep & mxAX))
9246 hg_fp[i].has_ret = 1;
9249 // note: messes up .proto ptr, don't use
9250 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
9253 for (i = 0; i < hg_var_cnt; i++) {
9256 if (var->pp != NULL)
9259 else if (var->is_c_str)
9260 fprintf(fout, "extern %-8s %s[];", "char", var->name);
9262 fprintf(fout, "extern %-8s %s;",
9263 lmod_c_names[var->lmod], var->name);
9266 fprintf(fout, " // seeded");
9267 fprintf(fout, "\n");
9270 fprintf(fout, "\n");
9272 // output function prototypes
9273 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
9276 fprintf(fout, "\n// - seed -\n");
9279 while (fgets(line, sizeof(line), g_fhdr))
9280 fwrite(line, 1, strlen(line), fout);
9283 // '=' needs special treatment
9285 static char *next_word_s(char *w, size_t wsize, char *s)
9292 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
9294 for (i = 1; i < wsize - 1; i++) {
9296 printf("warning: missing closing quote: \"%s\"\n", s);
9305 for (; i < wsize - 1; i++) {
9306 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
9312 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
9313 printf("warning: '%s' truncated\n", w);
9318 static int cmpstringp(const void *p1, const void *p2)
9320 return strcmp(*(char * const *)p1, *(char * const *)p2);
9323 static int is_xref_needed(char *p, char **rlist, int rlist_len)
9328 if (strstr(p, "..."))
9329 // unable to determine, assume needed
9332 if (*p == '.') // .text, .data, ...
9333 // ref from other data or non-function -> no
9336 p2 = strpbrk(p, "+:\r\n\x18");
9339 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9340 // referenced from removed code
9346 static int ida_xrefs_show_need(FILE *fasm, char *p,
9347 char **rlist, int rlist_len)
9353 p = strrchr(p, ';');
9354 if (p != NULL && *p == ';') {
9355 if (IS_START(p + 2, "sctref"))
9357 if (IS_START(p + 2, "DATA XREF: ")) {
9359 if (is_xref_needed(p, rlist, rlist_len))
9367 if (!my_fgets(line, sizeof(line), fasm))
9369 // non-first line is always indented
9370 if (!my_isblank(line[0]))
9373 // should be no content, just comment
9378 p = strrchr(p, ';');
9381 if (IS_START(p, "sctref")) {
9386 // it's printed once, but no harm to check again
9387 if (IS_START(p, "DATA XREF: "))
9390 if (is_xref_needed(p, rlist, rlist_len)) {
9395 fseek(fasm, pos, SEEK_SET);
9399 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
9401 struct scanned_var *var;
9402 char line[256] = { 0, };
9411 // skip to next data section
9412 while (my_fgets(line, sizeof(line), fasm))
9417 if (*p == 0 || *p == ';')
9420 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
9421 if (*p == 0 || *p == ';')
9424 if (*p != 's' || !IS_START(p, "segment para public"))
9430 if (p == NULL || !IS_START(p, "segment para public"))
9434 if (!IS_START(p, "'DATA'"))
9438 while (my_fgets(line, sizeof(line), fasm))
9443 no_identifier = my_isblank(*p);
9446 if (*p == 0 || *p == ';')
9449 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9450 words[wordc][0] = 0;
9451 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9452 if (*p == 0 || *p == ';') {
9458 if (wordc == 2 && IS(words[1], "ends"))
9463 if (no_identifier) {
9464 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
9465 hg_ref_add(words[2]);
9469 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
9470 // when this starts, we don't need anything from this section
9474 // check refs comment(s)
9475 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
9478 if ((hg_var_cnt & 0xff) == 0) {
9479 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
9480 * (hg_var_cnt + 0x100));
9481 my_assert_not(hg_vars, NULL);
9482 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
9485 var = &hg_vars[hg_var_cnt++];
9486 snprintf(var->name, sizeof(var->name), "%s", words[0]);
9488 // maybe already in seed header?
9489 var->pp = proto_parse(g_fhdr, var->name, 1);
9490 if (var->pp != NULL) {
9491 if (var->pp->is_fptr) {
9492 var->lmod = OPLM_DWORD;
9495 else if (var->pp->is_func)
9497 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
9498 aerr("unhandled C type '%s' for '%s'\n",
9499 var->pp->type.name, var->name);
9505 if (IS(words[1], "dd")) {
9506 var->lmod = OPLM_DWORD;
9507 if (wordc >= 4 && IS(words[2], "offset"))
9508 hg_ref_add(words[3]);
9510 else if (IS(words[1], "dw"))
9511 var->lmod = OPLM_WORD;
9512 else if (IS(words[1], "db")) {
9513 var->lmod = OPLM_BYTE;
9514 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
9515 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
9519 else if (IS(words[1], "dq"))
9520 var->lmod = OPLM_QWORD;
9521 //else if (IS(words[1], "dt"))
9523 aerr("type '%s' not known\n", words[1]);
9531 static void set_label(int i, const char *name)
9537 p = strchr(name, ':');
9541 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
9542 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
9543 g_labels[i] = realloc(g_labels[i], len + 1);
9544 my_assert_not(g_labels[i], NULL);
9545 memcpy(g_labels[i], name, len);
9546 g_labels[i][len] = 0;
9555 static struct chunk_item *func_chunks;
9556 static int func_chunk_cnt;
9557 static int func_chunk_alloc;
9559 static void add_func_chunk(FILE *fasm, const char *name, int line)
9561 if (func_chunk_cnt >= func_chunk_alloc) {
9562 func_chunk_alloc *= 2;
9563 func_chunks = realloc(func_chunks,
9564 func_chunk_alloc * sizeof(func_chunks[0]));
9565 my_assert_not(func_chunks, NULL);
9567 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
9568 func_chunks[func_chunk_cnt].name = strdup(name);
9569 func_chunks[func_chunk_cnt].asmln = line;
9573 static int cmp_chunks(const void *p1, const void *p2)
9575 const struct chunk_item *c1 = p1, *c2 = p2;
9576 return strcmp(c1->name, c2->name);
9579 static void scan_ahead_for_chunks(FILE *fasm)
9589 oldpos = ftell(fasm);
9592 while (my_fgets(line, sizeof(line), fasm))
9603 // get rid of random tabs
9604 for (i = 0; line[i] != 0; i++)
9605 if (line[i] == '\t')
9608 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9611 next_word(words[0], sizeof(words[0]), p);
9612 if (words[0][0] == 0)
9613 aerr("missing name for func chunk?\n");
9615 add_func_chunk(fasm, words[0], asmln);
9617 else if (IS_START(p, "; sctend"))
9623 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9624 words[wordc][0] = 0;
9625 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9626 if (*p == 0 || *p == ';') {
9632 if (wordc == 2 && IS(words[1], "ends"))
9636 fseek(fasm, oldpos, SEEK_SET);
9640 int main(int argc, char *argv[])
9642 FILE *fout, *fasm, *frlist;
9643 struct parsed_data *pd = NULL;
9645 char **rlist = NULL;
9647 int rlist_alloc = 0;
9648 int func_chunks_used = 0;
9649 int func_chunks_sorted = 0;
9650 int func_chunk_i = -1;
9651 long func_chunk_ret = 0;
9652 int func_chunk_ret_ln = 0;
9653 int scanned_ahead = 0;
9655 char words[20][256];
9656 enum opr_lenmod lmod;
9657 char *sctproto = NULL;
9659 int pending_endp = 0;
9661 int skip_code_end = 0;
9662 int skip_warned = 0;
9675 for (arg = 1; arg < argc; arg++) {
9676 if (IS(argv[arg], "-v"))
9678 else if (IS(argv[arg], "-rf"))
9679 g_allow_regfunc = 1;
9680 else if (IS(argv[arg], "-uc"))
9681 g_allow_user_icall = 1;
9682 else if (IS(argv[arg], "-wu"))
9683 g_nowarn_reguse = 1;
9684 else if (IS(argv[arg], "-m"))
9686 else if (IS(argv[arg], "-hdr"))
9687 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
9692 if (argc < arg + 3) {
9693 printf("usage:\n%s [options] <.c> <.asm> <hdr.h> [rlist]*\n"
9694 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
9696 " -hdr - header generation mode\n"
9697 " -rf - allow unannotated indirect calls\n"
9698 " -uc - allow ind. calls/refs to __usercall\n"
9699 " -m - allow multiple .text sections\n"
9700 " -wu - don't warn about bad reg use\n"
9701 "[rlist] is a file with function names to skip,"
9709 asmfn = argv[arg++];
9710 fasm = fopen(asmfn, "r");
9711 my_assert_not(fasm, NULL);
9713 hdrfn = argv[arg++];
9714 g_fhdr = fopen(hdrfn, "r");
9715 my_assert_not(g_fhdr, NULL);
9718 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9719 my_assert_not(rlist, NULL);
9720 // needs special handling..
9721 rlist[rlist_len++] = "__alloca_probe";
9723 func_chunk_alloc = 32;
9724 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9725 my_assert_not(func_chunks, NULL);
9727 memset(words, 0, sizeof(words));
9729 for (; arg < argc; arg++) {
9732 frlist = fopen(argv[arg], "r");
9733 my_assert_not(frlist, NULL);
9735 while (my_fgets(line, sizeof(line), frlist)) {
9737 if (*p == 0 || *p == ';')
9740 if (IS_START(p, "#if 0")
9741 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9745 else if (IS_START(p, "#endif"))
9752 p = next_word(words[0], sizeof(words[0]), p);
9753 if (words[0][0] == 0)
9756 if (rlist_len >= rlist_alloc) {
9757 rlist_alloc = rlist_alloc * 2 + 64;
9758 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9759 my_assert_not(rlist, NULL);
9761 rlist[rlist_len++] = strdup(words[0]);
9769 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9771 fout = fopen(argv[arg_out], "w");
9772 my_assert_not(fout, NULL);
9775 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9776 my_assert_not(g_eqs, NULL);
9778 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9779 g_label_refs[i].i = -1;
9780 g_label_refs[i].next = NULL;
9784 scan_variables(fasm, rlist, rlist_len);
9786 while (my_fgets(line, sizeof(line), fasm))
9795 // get rid of random tabs
9796 for (i = 0; line[i] != 0; i++)
9797 if (line[i] == '\t')
9802 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9803 goto do_pending_endp; // eww..
9805 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9807 static const char *attrs[] = {
9816 // parse IDA's attribute-list comment
9817 g_ida_func_attr = 0;
9820 for (; *p != 0; p = sskip(p)) {
9821 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9822 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9823 g_ida_func_attr |= 1 << i;
9824 p += strlen(attrs[i]);
9828 if (i == ARRAY_SIZE(attrs)) {
9829 anote("unparsed IDA attr: %s\n", p);
9832 if (IS(attrs[i], "fpd=")) {
9833 p = next_word(words[0], sizeof(words[0]), p);
9838 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9840 static const char *attrs[] = {
9848 // parse manual attribute-list comment
9849 g_sct_func_attr = 0;
9852 for (; *p != 0; p = sskip(p)) {
9853 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9854 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9855 g_sct_func_attr |= 1 << i;
9856 p += strlen(attrs[i]);
9863 // clear_sf=start,len (in dwords)
9864 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9865 &g_stack_clear_len, &j);
9867 // clear_regmask=<mask>
9868 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9870 // rm_regmask=<mask>
9871 ret = sscanf(p, "=%x%n", &g_regmask_rm, &j) + 1;
9873 anote("unparsed attr value: %s\n", p);
9878 else if (i == ARRAY_SIZE(attrs)) {
9879 anote("unparsed sct attr: %s\n", p);
9884 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9887 next_word(words[0], sizeof(words[0]), p);
9888 if (words[0][0] == 0)
9889 aerr("missing name for func chunk?\n");
9891 if (!scanned_ahead) {
9892 add_func_chunk(fasm, words[0], asmln);
9893 func_chunks_sorted = 0;
9896 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9898 if (func_chunk_i >= 0) {
9899 if (func_chunk_i < func_chunk_cnt
9900 && IS(func_chunks[func_chunk_i].name, g_func))
9902 // move on to next chunk
9903 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9905 aerr("seek failed for '%s' chunk #%d\n",
9906 g_func, func_chunk_i);
9907 asmln = func_chunks[func_chunk_i].asmln;
9911 if (func_chunk_ret == 0)
9912 aerr("no return from chunk?\n");
9913 fseek(fasm, func_chunk_ret, SEEK_SET);
9914 asmln = func_chunk_ret_ln;
9920 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9921 func_chunks_used = 1;
9923 if (IS_START(g_func, "sub_")) {
9924 unsigned long addr = strtoul(p, NULL, 16);
9925 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9926 if (addr > f_addr && !scanned_ahead) {
9927 //anote("scan_ahead caused by '%s', addr %lx\n",
9929 scan_ahead_for_chunks(fasm);
9931 func_chunks_sorted = 0;
9939 for (i = wordc; i < ARRAY_SIZE(words); i++)
9941 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9942 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9943 if (*p == 0 || *p == ';') {
9948 if (*p != 0 && *p != ';')
9949 aerr("too many words\n");
9951 if (skip_code_end) {
9956 // allow asm patches in comments
9958 // skip IDA's forced non-removable comment
9959 if (!IS_START(p, "; sct") && (p2 = strchr(p + 1, ';')))
9962 if (*p == ';' && IS_START(p, "; sct")) {
9963 if (IS_START(p, "; sctpatch:")) {
9965 if (*p == 0 || *p == ';')
9967 goto parse_words; // lame
9969 else if (IS_START(p, "; sctend")) {
9974 else if (g_skip_func)
9975 /* ignore remaining attrs */;
9976 else if (IS_START(p, "; sctproto:")) {
9977 sctproto = strdup(p + 11);
9979 else if (IS_START(p, "; sctskip_start")) {
9982 ops[pi].op = OPP_ABORT;
9983 ops[pi].asmln = asmln;
9989 else if (IS_START(p, "; sctskip_end")) {
9997 awarn("wordc == 0?\n");
10001 // don't care about this:
10002 if (words[0][0] == '.'
10003 || IS(words[0], "include")
10004 || IS(words[0], "assume") || IS(words[1], "segment")
10005 || IS(words[0], "align"))
10011 // do delayed endp processing to collect switch jumptables
10012 if (pending_endp) {
10013 if (in_func && !g_skip_func && !end && wordc >= 2
10014 && ((words[0][0] == 'd' && words[0][2] == 0)
10015 || (words[1][0] == 'd' && words[1][2] == 0)))
10018 if (words[1][0] == 'd' && words[1][2] == 0) {
10020 if (g_func_pd_cnt >= pd_alloc) {
10021 pd_alloc = pd_alloc * 2 + 16;
10022 g_func_pd = realloc(g_func_pd,
10023 sizeof(g_func_pd[0]) * pd_alloc);
10024 my_assert_not(g_func_pd, NULL);
10026 pd = &g_func_pd[g_func_pd_cnt];
10028 memset(pd, 0, sizeof(*pd));
10029 strcpy(pd->label, words[0]);
10030 pd->type = OPT_CONST;
10031 pd->lmod = lmod_from_directive(words[1]);
10037 anote("skipping alignment byte?\n");
10040 lmod = lmod_from_directive(words[0]);
10041 if (lmod != pd->lmod)
10042 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
10045 if (pd->count_alloc < pd->count + wordc) {
10046 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
10047 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
10048 my_assert_not(pd->d, NULL);
10050 for (; i < wordc; i++) {
10051 if (IS(words[i], "offset")) {
10052 pd->type = OPT_OFFSET;
10055 p = strchr(words[i], ',');
10058 if (pd->type == OPT_OFFSET)
10059 pd->d[pd->count].u.label = strdup(words[i]);
10061 pd->d[pd->count].u.val = parse_number(words[i], 0);
10062 pd->d[pd->count].bt_i = -1;
10068 if (in_func && !g_skip_func) {
10070 gen_hdr(g_func, pi);
10072 gen_func(fout, g_fhdr, g_func, pi);
10077 g_ida_func_attr = 0;
10078 g_sct_func_attr = 0;
10079 g_stack_clear_start = 0;
10080 g_stack_clear_len = 0;
10081 g_regmask_init = 0;
10087 func_chunks_used = 0;
10090 memset(&ops, 0, pi * sizeof(ops[0]));
10095 for (i = 0; i < g_func_pd_cnt; i++) {
10096 pd = &g_func_pd[i];
10097 if (pd->type == OPT_OFFSET) {
10098 for (j = 0; j < pd->count; j++)
10099 free(pd->d[j].u.label);
10114 if (IS(words[1], "proc")) {
10116 aerr("proc '%s' while in_func '%s'?\n",
10119 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
10121 strcpy(g_func, words[0]);
10122 set_label(0, words[0]);
10127 if (IS(words[1], "endp"))
10130 aerr("endp '%s' while not in_func?\n", words[0]);
10131 if (!IS(g_func, words[0]))
10132 aerr("endp '%s' while in_func '%s'?\n",
10135 aerr("endp '%s' while skipping code\n", words[0]);
10137 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
10138 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
10144 if (!g_skip_func && func_chunks_used) {
10145 // start processing chunks
10146 struct chunk_item *ci, key = { g_func, 0 };
10148 func_chunk_ret = ftell(fasm);
10149 func_chunk_ret_ln = asmln;
10150 if (!func_chunks_sorted) {
10151 qsort(func_chunks, func_chunk_cnt,
10152 sizeof(func_chunks[0]), cmp_chunks);
10153 func_chunks_sorted = 1;
10155 ci = bsearch(&key, func_chunks, func_chunk_cnt,
10156 sizeof(func_chunks[0]), cmp_chunks);
10158 aerr("'%s' needs chunks, but none found\n", g_func);
10159 func_chunk_i = ci - func_chunks;
10160 for (; func_chunk_i > 0; func_chunk_i--)
10161 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
10164 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
10166 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
10167 asmln = func_chunks[func_chunk_i].asmln;
10175 if (wordc == 2 && IS(words[1], "ends")) {
10179 goto do_pending_endp;
10183 // scan for next text segment
10184 while (my_fgets(line, sizeof(line), fasm)) {
10187 if (*p == 0 || *p == ';')
10190 if (strstr(p, "segment para public 'CODE' use32"))
10197 p = strchr(words[0], ':');
10199 set_label(pi, words[0]);
10203 if (!in_func || g_skip_func || skip_code) {
10204 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
10206 anote("skipping from '%s'\n", g_labels[pi]);
10209 free(g_labels[pi]);
10210 g_labels[pi] = NULL;
10214 if (wordc > 1 && IS(words[1], "="))
10217 aerr("unhandled equ, wc=%d\n", wordc);
10218 if (g_eqcnt >= eq_alloc) {
10220 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
10221 my_assert_not(g_eqs, NULL);
10224 len = strlen(words[0]);
10225 if (len > sizeof(g_eqs[0].name) - 1)
10226 aerr("equ name too long: %d\n", len);
10227 strcpy(g_eqs[g_eqcnt].name, words[0]);
10229 if (!IS(words[3], "ptr"))
10230 aerr("unhandled equ\n");
10231 if (IS(words[2], "dword"))
10232 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
10233 else if (IS(words[2], "word"))
10234 g_eqs[g_eqcnt].lmod = OPLM_WORD;
10235 else if (IS(words[2], "byte"))
10236 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
10237 else if (IS(words[2], "qword"))
10238 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
10240 aerr("bad lmod: '%s'\n", words[2]);
10242 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
10247 if (pi >= ARRAY_SIZE(ops))
10248 aerr("too many ops\n");
10250 parse_op(&ops[pi], words, wordc);
10252 ops[pi].datap = sctproto;
10267 // vim:ts=2:shiftwidth=2:expandtab