5 * This work is licensed under the terms of 3-clause BSD license.
6 * See COPYING file in the top-level directory.
8 * recognized asm hint comments:
9 * sctattr - function attributes (see code)
10 * sctend - force end of function/chunk
11 * sctpatch: <p> - replace current asm line with <p>
12 * sctproto: <p> - prototype of ref'd function or struct
13 * sctref - variable is referenced, make global
14 * sctskip_start - start of skipped code chunk (inclusive)
15 * sctskip_end - end of skipped code chunk (inclusive)
24 #include "my_assert.h"
28 #include "protoparse.h"
30 static const char *asmfn;
34 #define anote(fmt, ...) \
35 printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
36 #define awarn(fmt, ...) \
37 printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
38 #define aerr(fmt, ...) do { \
39 printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
44 #include "masm_tools.h"
47 OPF_RMD = (1 << 0), /* removed from code generation */
48 OPF_DATA = (1 << 1), /* data processing - writes to dst opr */
49 OPF_FLAGS = (1 << 2), /* sets flags */
50 OPF_JMP = (1 << 3), /* branch, call */
51 OPF_CJMP = (1 << 4), /* cond. branch (cc or jecxz/loop) */
52 OPF_CC = (1 << 5), /* uses flags */
53 OPF_TAIL = (1 << 6), /* ret or tail call */
54 OPF_RSAVE = (1 << 7), /* push/pop is local reg save/load */
55 OPF_REP = (1 << 8), /* prefixed by rep */
56 OPF_REPZ = (1 << 9), /* rep is repe/repz */
57 OPF_REPNZ = (1 << 10), /* rep is repne/repnz */
58 OPF_FARG = (1 << 11), /* push collected as func arg */
59 OPF_FARGNR = (1 << 12), /* push collected as func arg (no reuse) */
60 OPF_EBP_S = (1 << 13), /* ebp used as scratch here, not BP */
61 OPF_DF = (1 << 14), /* DF flag set */
62 OPF_ATAIL = (1 << 15), /* tail call with reused arg frame */
63 OPF_32BIT = (1 << 16), /* 32bit division */
64 OPF_LOCK = (1 << 17), /* op has lock prefix */
65 OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
66 OPF_DONE = (1 << 19), /* already fully handled by analysis */
67 OPF_PPUSH = (1 << 20), /* part of complex push-pop graph */
68 OPF_NOREGS = (1 << 21), /* don't track regs of this op */
69 OPF_FPUSH = (1 << 22), /* pushes x87 stack */
70 OPF_FPOP = (1 << 23), /* pops x87 stack */
71 OPF_FPOPP = (1 << 24), /* pops x87 stack twice */
72 OPF_FSHIFT = (1 << 25), /* x87 stack shift is actually needed */
73 OPF_FINT = (1 << 26), /* integer float op arg */
164 // pseudo-ops for lib calls
183 // must be sorted (larger len must be further in enum)
192 #define MAX_EXITS 128
194 #define MAX_OPERANDS 3
197 #define OPR_INIT(type_, lmod_, reg_) \
198 { type_, lmod_, reg_, }
202 enum opr_lenmod lmod;
204 unsigned int is_ptr:1; // pointer in C
205 unsigned int is_array:1; // array in C
206 unsigned int type_from_var:1; // .. in header, sometimes wrong
207 unsigned int size_mismatch:1; // type override differs from C
208 unsigned int size_lt:1; // type override is larger than C
209 unsigned int segment:7; // had segment override (enum segment)
210 const struct parsed_proto *pp; // for OPT_LABEL
217 struct parsed_opr operand[MAX_OPERANDS];
220 unsigned char pfo_inv;
221 unsigned char operand_cnt;
222 unsigned char p_argnum; // arg push: altered before call arg #
223 unsigned char p_arggrp; // arg push: arg group # for above
224 unsigned char p_argpass;// arg push: arg of host func
225 short p_argnext;// arg push: same arg pushed elsewhere or -1
226 int regmask_src; // all referensed regs
228 int pfomask; // flagop: parsed_flag_op that can't be delayed
229 int cc_scratch; // scratch storage during analysis
230 int bt_i; // branch target for branches
231 struct parsed_data *btj;// branch targets for jumptables
232 struct parsed_proto *pp;// parsed_proto for OP_CALL
238 // on start: function/data type hint (sctproto)
240 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
241 // OP_PUSH - points to OP_POP in complex push/pop graph
242 // OP_POP - points to OP_PUSH in simple push/pop pair
243 // OP_FCOM - needed_status_word_bits | (is_z_check << 16)
247 enum opr_lenmod lmod;
254 enum opr_lenmod lmod;
268 struct label_ref *next;
272 IDAFA_BP_FRAME = (1 << 0),
273 IDAFA_LIB_FUNC = (1 << 1),
274 IDAFA_STATIC = (1 << 2),
275 IDAFA_NORETURN = (1 << 3),
276 IDAFA_THUNK = (1 << 4),
277 IDAFA_FPD = (1 << 5),
281 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
282 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
304 // note: limited to 32k due to p_argnext
306 #define MAX_ARG_GRP 2
308 static struct parsed_op ops[MAX_OPS];
309 static struct parsed_equ *g_eqs;
311 static char *g_labels[MAX_OPS];
312 static struct label_ref g_label_refs[MAX_OPS];
313 static const struct parsed_proto *g_func_pp;
314 static struct parsed_data *g_func_pd;
315 static int g_func_pd_cnt;
316 static int g_func_lmods;
317 static char g_func[256];
318 static char g_comment[256];
319 static int g_bp_frame;
320 static int g_sp_frame;
321 static int g_stack_frame_used;
322 static int g_stack_fsz;
323 static int g_seh_found;
324 static int g_seh_size;
325 static int g_ida_func_attr;
326 static int g_sct_func_attr;
327 static int g_stack_clear_start; // in dwords
328 static int g_stack_clear_len;
329 static int g_regmask_init;
330 static int g_skip_func;
331 static int g_allow_regfunc;
332 static int g_allow_user_icall;
333 static int g_quiet_pp;
334 static int g_header_mode;
336 #define ferr(op_, fmt, ...) do { \
337 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
338 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
342 #define fnote(op_, fmt, ...) \
343 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
344 dump_op(op_), ##__VA_ARGS__)
346 #define ferr_assert(op_, cond) do { \
347 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
350 const char *regs_r32[] = {
351 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
352 // not r32, but list here for easy parsing and printing
353 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
354 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
356 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
357 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
358 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
364 xMM0, xMM1, xMM2, xMM3, // mmx
365 xMM4, xMM5, xMM6, xMM7,
366 xST0, xST1, xST2, xST3, // x87
367 xST4, xST5, xST6, xST7,
370 #define mxAX (1 << xAX)
371 #define mxCX (1 << xCX)
372 #define mxDX (1 << xDX)
373 #define mxSP (1 << xSP)
374 #define mxST0 (1 << xST0)
375 #define mxST1 (1 << xST1)
376 #define mxST1_0 (mxST1 | mxST0)
377 #define mxST7_2 (0xfc << xST0)
378 #define mxSTa (0xff << xST0)
380 // possible basic comparison types (without inversion)
381 enum parsed_flag_op {
385 PFO_BE, // 6 CF=1||ZF=1
389 PFO_LE, // e ZF=1||SF!=OF
392 #define PFOB_O (1 << PFO_O)
393 #define PFOB_C (1 << PFO_C)
394 #define PFOB_Z (1 << PFO_Z)
395 #define PFOB_S (1 << PFO_S)
397 static const char *parsed_flag_op_names[] = {
398 "o", "c", "z", "be", "s", "p", "l", "le"
401 static int char_array_i(const char *array[], size_t len, const char *s)
405 for (i = 0; i < len; i++)
412 static void printf_number(char *buf, size_t buf_size,
413 unsigned long number)
415 // output in C-friendly form
416 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
419 static int check_segment_prefix(const char *s)
421 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
425 case 'c': return SEG_CS;
426 case 'd': return SEG_DS;
427 case 's': return SEG_SS;
428 case 'e': return SEG_ES;
429 case 'f': return SEG_FS;
430 case 'g': return SEG_GS;
435 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
439 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
441 *reg_lmod = OPLM_QWORD;
445 *reg_lmod = OPLM_DWORD;
448 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
450 *reg_lmod = OPLM_WORD;
453 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
455 *reg_lmod = OPLM_BYTE;
458 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
460 *reg_lmod = OPLM_BYTE;
467 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
469 enum opr_lenmod lmod;
482 while (my_isblank(*s))
484 for (; my_issep(*s); d++, s++)
486 while (my_isblank(*s))
490 // skip '?s:' prefixes
491 if (check_segment_prefix(s))
494 s = next_idt(w, sizeof(w), s);
499 reg = parse_reg(&lmod, w);
501 *regmask |= 1 << reg;
505 if ('0' <= w[0] && w[0] <= '9') {
506 number = parse_number(w, 0);
507 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
511 // probably some label/identifier - pass
514 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
518 strcpy(name, cvtbuf);
523 static int is_reg_in_str(const char *s)
527 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
530 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
531 if (!strncmp(s, regs_r32[i], 3))
537 static const char *parse_stack_el(const char *name, char *extra_reg,
538 int *base_val, int early_try)
540 const char *p, *p2, *s;
546 if (g_bp_frame || early_try)
549 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
551 if (extra_reg != NULL) {
552 strncpy(extra_reg, name, 3);
557 if (IS_START(p, "ebp+")) {
561 if (p2 != NULL && is_reg_in_str(p)) {
562 if (extra_reg != NULL) {
563 strncpy(extra_reg, p, p2 - p);
564 extra_reg[p2 - p] = 0;
569 if (!('0' <= *p && *p <= '9'))
576 if (!IS_START(name, "esp+"))
582 if (is_reg_in_str(s)) {
583 if (extra_reg != NULL) {
584 strncpy(extra_reg, s, p - s);
585 extra_reg[p - s] = 0;
590 aerr("%s IDA stackvar not set?\n", __func__);
592 if (!('0' <= *s && *s <= '9')) {
593 aerr("%s IDA stackvar offset not set?\n", __func__);
596 if (s[0] == '0' && s[1] == 'x')
599 if (len < sizeof(buf) - 1) {
600 strncpy(buf, s, len);
603 val = strtol(buf, &endp, 16);
604 if (val == 0 || *endp != 0 || errno != 0) {
605 aerr("%s num parse fail for '%s'\n", __func__, buf);
614 if ('0' <= *p && *p <= '9')
617 if (base_val != NULL)
622 static int guess_lmod_from_name(struct parsed_opr *opr)
624 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
625 opr->lmod = OPLM_DWORD;
628 if (IS_START(opr->name, "word_")) {
629 opr->lmod = OPLM_WORD;
632 if (IS_START(opr->name, "byte_")) {
633 opr->lmod = OPLM_BYTE;
636 if (IS_START(opr->name, "qword_")) {
637 opr->lmod = OPLM_QWORD;
643 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
644 const struct parsed_type *c_type)
646 static const char *qword_types[] = {
647 "uint64_t", "int64_t", "__int64",
649 static const char *dword_types[] = {
650 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
651 "WPARAM", "LPARAM", "UINT", "__int32",
652 "LONG", "HIMC", "BOOL", "size_t",
655 static const char *word_types[] = {
656 "uint16_t", "int16_t", "_WORD", "WORD",
657 "unsigned __int16", "__int16",
659 static const char *byte_types[] = {
660 "uint8_t", "int8_t", "char",
661 "unsigned __int8", "__int8", "BYTE", "_BYTE",
663 // structures.. deal the same as with _UNKNOWN for now
669 if (c_type->is_ptr) {
674 n = skip_type_mod(c_type->name);
676 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
677 if (IS(n, dword_types[i])) {
683 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
684 if (IS(n, word_types[i])) {
690 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
691 if (IS(n, byte_types[i])) {
697 for (i = 0; i < ARRAY_SIZE(qword_types); i++) {
698 if (IS(n, qword_types[i])) {
707 static char *default_cast_to(char *buf, size_t buf_size,
708 struct parsed_opr *opr)
712 if (!opr->is_ptr || strchr(opr->name, '['))
714 if (opr->pp == NULL || opr->pp->type.name == NULL
717 snprintf(buf, buf_size, "%s", "(void *)");
721 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
725 static enum opr_type lmod_from_directive(const char *d)
729 else if (IS(d, "dw"))
731 else if (IS(d, "db"))
734 aerr("unhandled directive: '%s'\n", d);
738 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
744 *regmask |= 1 << reg;
747 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
750 static int parse_operand(struct parsed_opr *opr,
751 int *regmask, int *regmask_indirect,
752 char words[16][256], int wordc, int w, unsigned int op_flags)
754 const struct parsed_proto *pp = NULL;
755 enum opr_lenmod tmplmod;
756 unsigned long number;
764 aerr("parse_operand w %d, wordc %d\n", w, wordc);
768 for (i = w; i < wordc; i++) {
769 len = strlen(words[i]);
770 if (words[i][len - 1] == ',') {
771 words[i][len - 1] = 0;
777 wordc_in = wordc - w;
779 if ((op_flags & OPF_JMP) && wordc_in > 0
780 && !('0' <= words[w][0] && words[w][0] <= '9'))
782 const char *label = NULL;
784 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
785 && IS(words[w + 1], "ptr"))
786 label = words[w + 2];
787 else if (wordc_in == 2 && IS(words[w], "short"))
788 label = words[w + 1];
789 else if (wordc_in == 1
790 && strchr(words[w], '[') == NULL
791 && parse_reg(&tmplmod, words[w]) < 0)
795 opr->type = OPT_LABEL;
796 ret = check_segment_prefix(label);
801 strcpy(opr->name, label);
807 if (IS(words[w + 1], "ptr")) {
808 if (IS(words[w], "dword"))
809 opr->lmod = OPLM_DWORD;
810 else if (IS(words[w], "word"))
811 opr->lmod = OPLM_WORD;
812 else if (IS(words[w], "byte"))
813 opr->lmod = OPLM_BYTE;
814 else if (IS(words[w], "qword"))
815 opr->lmod = OPLM_QWORD;
817 aerr("type parsing failed\n");
819 wordc_in = wordc - w;
824 if (IS(words[w], "offset")) {
825 opr->type = OPT_OFFSET;
826 opr->lmod = OPLM_DWORD;
827 strcpy(opr->name, words[w + 1]);
828 pp = proto_parse(g_fhdr, opr->name, 1);
831 if (IS(words[w], "(offset")) {
832 p = strchr(words[w + 1], ')');
834 aerr("parse of bracketed offset failed\n");
836 opr->type = OPT_OFFSET;
837 strcpy(opr->name, words[w + 1]);
843 aerr("parse_operand 1 word expected\n");
845 ret = check_segment_prefix(words[w]);
848 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
849 if (ret == SEG_FS && IS(words[w], "0"))
852 strcpy(opr->name, words[w]);
854 if (words[w][0] == '[') {
855 opr->type = OPT_REGMEM;
856 ret = sscanf(words[w], "[%[^]]]", opr->name);
858 aerr("[] parse failure\n");
860 parse_indmode(opr->name, regmask_indirect, 1);
861 if (opr->lmod == OPLM_UNSPEC
862 && parse_stack_el(opr->name, NULL, NULL, 1))
865 struct parsed_equ *eq =
866 equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
868 opr->lmod = eq->lmod;
870 // might be unaligned access
871 g_func_lmods |= 1 << OPLM_BYTE;
875 else if (strchr(words[w], '[')) {
877 p = strchr(words[w], '[');
878 opr->type = OPT_REGMEM;
879 parse_indmode(p, regmask_indirect, 0);
880 strncpy(buf, words[w], p - words[w]);
881 buf[p - words[w]] = 0;
882 pp = proto_parse(g_fhdr, buf, 1);
885 else if (('0' <= words[w][0] && words[w][0] <= '9')
886 || words[w][0] == '-')
888 number = parse_number(words[w], 0);
889 opr->type = OPT_CONST;
891 printf_number(opr->name, sizeof(opr->name), number);
895 ret = parse_reg(&tmplmod, opr->name);
897 setup_reg_opr(opr, ret, tmplmod, regmask);
901 // most likely var in data segment
902 opr->type = OPT_LABEL;
903 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
907 if (pp->is_fptr || pp->is_func) {
908 opr->lmod = OPLM_DWORD;
912 tmplmod = OPLM_UNSPEC;
913 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
914 anote("unhandled C type '%s' for '%s'\n",
915 pp->type.name, opr->name);
917 if (opr->lmod == OPLM_UNSPEC) {
919 opr->type_from_var = 1;
921 else if (opr->lmod != tmplmod) {
922 opr->size_mismatch = 1;
923 if (tmplmod < opr->lmod)
926 opr->is_ptr = pp->type.is_ptr;
928 opr->is_array = pp->type.is_array;
932 if (opr->lmod == OPLM_UNSPEC)
933 guess_lmod_from_name(opr);
937 static const struct {
942 { "repe", OPF_REP|OPF_REPZ },
943 { "repz", OPF_REP|OPF_REPZ },
944 { "repne", OPF_REP|OPF_REPNZ },
945 { "repnz", OPF_REP|OPF_REPNZ },
946 { "lock", OPF_LOCK }, // ignored for now..
949 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
951 static const struct {
954 unsigned short minopr;
955 unsigned short maxopr;
958 unsigned char pfo_inv;
960 { "nop", OP_NOP, 0, 0, 0 },
961 { "push", OP_PUSH, 1, 1, 0 },
962 { "pop", OP_POP, 1, 1, OPF_DATA },
963 { "pusha",OP_PUSHA, 0, 0, 0 },
964 { "popa", OP_POPA, 0, 0, OPF_DATA },
965 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
966 { "mov" , OP_MOV, 2, 2, OPF_DATA },
967 { "lea", OP_LEA, 2, 2, OPF_DATA },
968 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
969 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
970 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
971 { "not", OP_NOT, 1, 1, OPF_DATA },
972 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
973 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
974 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
975 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
976 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
977 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
978 { "stosb",OP_STOS, 0, 0, OPF_DATA },
979 { "stosw",OP_STOS, 0, 0, OPF_DATA },
980 { "stosd",OP_STOS, 0, 0, OPF_DATA },
981 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
982 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
983 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
984 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
985 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
986 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
987 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
988 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
989 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
990 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
991 { "cld", OP_CLD, 0, 0, OPF_DATA },
992 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
993 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
994 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
995 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
996 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
997 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
998 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
999 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
1000 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
1001 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
1002 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
1003 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
1004 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
1005 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1006 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1007 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1008 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1009 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
1010 { "bsr", OP_BSR, 2, 2, OPF_DATA|OPF_FLAGS },
1011 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
1012 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
1013 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
1014 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
1015 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
1016 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
1017 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
1018 { "test", OP_TEST, 2, 2, OPF_FLAGS },
1019 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
1020 { "retn", OP_RET, 0, 1, OPF_TAIL },
1021 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
1022 { "jmp", OP_JMP, 1, 1, OPF_JMP },
1023 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
1024 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
1025 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
1026 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
1027 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
1028 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
1029 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
1030 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1031 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1032 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
1033 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
1034 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
1035 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
1036 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1037 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1038 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1039 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1040 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1041 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1042 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1043 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1044 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1045 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1046 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1047 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1048 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1049 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1050 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1051 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1052 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1053 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1054 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1055 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1056 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1057 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1058 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1059 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1060 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1061 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1062 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1063 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1064 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1065 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1066 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1067 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1068 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1069 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1070 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1071 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1072 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1073 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1074 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1075 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1076 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1077 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1078 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1079 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1080 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1081 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1082 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1084 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1085 { "fild", OP_FILD, 1, 1, OPF_FPUSH|OPF_FINT },
1086 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1087 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1088 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1089 { "fst", OP_FST, 1, 1, 0 },
1090 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1091 { "fist", OP_FIST, 1, 1, OPF_FINT },
1092 { "fistp", OP_FIST, 1, 1, OPF_FPOP|OPF_FINT },
1093 { "fadd", OP_FADD, 0, 2, 0 },
1094 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1095 { "fdiv", OP_FDIV, 0, 2, 0 },
1096 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1097 { "fmul", OP_FMUL, 0, 2, 0 },
1098 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1099 { "fsub", OP_FSUB, 0, 2, 0 },
1100 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1101 { "fdivr", OP_FDIVR, 0, 2, 0 },
1102 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1103 { "fsubr", OP_FSUBR, 0, 2, 0 },
1104 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1105 { "fiadd", OP_FIADD, 1, 1, OPF_FINT },
1106 { "fidiv", OP_FIDIV, 1, 1, OPF_FINT },
1107 { "fimul", OP_FIMUL, 1, 1, OPF_FINT },
1108 { "fisub", OP_FISUB, 1, 1, OPF_FINT },
1109 { "fidivr", OP_FIDIVR, 1, 1, OPF_FINT },
1110 { "fisubr", OP_FISUBR, 1, 1, OPF_FINT },
1111 { "fcom", OP_FCOM, 0, 1, 0 },
1112 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1113 { "fcompp", OP_FCOM, 0, 0, OPF_FPOPP },
1114 { "fucom", OP_FCOM, 0, 1, 0 },
1115 { "fucomp", OP_FCOM, 0, 1, OPF_FPOP },
1116 { "fucompp",OP_FCOM, 0, 0, OPF_FPOPP },
1117 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1118 { "fchs", OP_FCHS, 0, 0, 0 },
1119 { "fcos", OP_FCOS, 0, 0, 0 },
1120 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1121 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1122 { "fsin", OP_FSIN, 0, 0, 0 },
1123 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1124 { "fxch", OP_FXCH, 1, 1, 0 },
1125 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1127 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1128 { "movq", OP_MOV, 2, 2, OPF_DATA },
1129 // pseudo-ops for lib calls
1130 { "_allshl",OPP_ALLSHL },
1131 { "_allshr",OPP_ALLSHR },
1132 { "_ftol", OPP_FTOL },
1133 { "_CIpow", OPP_CIPOW },
1134 { "abort", OPP_ABORT },
1139 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1141 enum opr_lenmod lmod = OPLM_UNSPEC;
1142 int prefix_flags = 0;
1150 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1151 if (IS(words[w], pref_table[i].name)) {
1152 prefix_flags = pref_table[i].flags;
1159 aerr("lone prefix: '%s'\n", words[0]);
1164 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1165 if (IS(words[w], op_table[i].name))
1169 if (i == ARRAY_SIZE(op_table)) {
1171 aerr("unhandled op: '%s'\n", words[0]);
1176 op->op = op_table[i].op;
1177 op->flags = op_table[i].flags | prefix_flags;
1178 op->pfo = op_table[i].pfo;
1179 op->pfo_inv = op_table[i].pfo_inv;
1180 op->regmask_src = op->regmask_dst = 0;
1183 if (op->op == OP_UD2)
1186 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1187 if (opr >= op_table[i].minopr && w >= wordc)
1190 regmask = regmask_ind = 0;
1191 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1192 words, wordc, w, op->flags);
1194 if (opr == 0 && (op->flags & OPF_DATA))
1195 op->regmask_dst = regmask;
1197 op->regmask_src |= regmask;
1198 op->regmask_src |= regmask_ind;
1200 if (op->operand[opr].lmod != OPLM_UNSPEC)
1201 g_func_lmods |= 1 << op->operand[opr].lmod;
1205 aerr("parse_op %s incomplete: %d/%d\n",
1206 words[0], w, wordc);
1209 op->operand_cnt = opr;
1210 if (!strncmp(op_table[i].name, "set", 3))
1211 op->operand[0].lmod = OPLM_BYTE;
1214 // first operand is not dst
1217 op->regmask_src |= op->regmask_dst;
1218 op->regmask_dst = 0;
1221 // first operand is src too
1234 op->regmask_src |= op->regmask_dst;
1239 op->regmask_src |= op->regmask_dst;
1240 op->regmask_dst |= op->regmask_src;
1246 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1247 && op->operand[0].lmod == op->operand[1].lmod
1248 && op->operand[0].reg == op->operand[1].reg
1249 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1251 op->regmask_src = 0;
1254 op->regmask_src |= op->regmask_dst;
1257 // ops with implicit argumets
1259 op->operand_cnt = 2;
1260 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1261 op->regmask_dst = op->regmask_src;
1262 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1266 op->operand_cnt = 2;
1267 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1268 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1274 if (words[op_w][4] == 'b')
1276 else if (words[op_w][4] == 'w')
1278 else if (words[op_w][4] == 'd')
1281 op->regmask_src = 0;
1282 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1283 OPLM_DWORD, &op->regmask_src);
1284 op->regmask_dst = op->regmask_src;
1285 setup_reg_opr(&op->operand[j++], xAX, lmod,
1286 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1287 if (op->flags & OPF_REP) {
1288 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1289 op->regmask_dst |= 1 << xCX;
1291 op->operand_cnt = j;
1296 if (words[op_w][4] == 'b')
1298 else if (words[op_w][4] == 'w')
1300 else if (words[op_w][4] == 'd')
1303 op->regmask_src = 0;
1304 // note: lmod is not correct, don't have where to place it
1305 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1306 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1307 if (op->flags & OPF_REP)
1308 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1309 op->operand_cnt = j;
1310 op->regmask_dst = op->regmask_src;
1314 op->regmask_dst = 1 << xCX;
1317 op->operand_cnt = 2;
1318 op->regmask_src = 1 << xCX;
1319 op->operand[1].type = OPT_REG;
1320 op->operand[1].reg = xCX;
1321 op->operand[1].lmod = OPLM_DWORD;
1325 if (op->operand_cnt == 2) {
1326 if (op->operand[0].type != OPT_REG)
1327 aerr("reg expected\n");
1328 op->regmask_src |= 1 << op->operand[0].reg;
1330 if (op->operand_cnt != 1)
1335 op->regmask_src |= op->regmask_dst;
1336 op->regmask_dst = (1 << xDX) | (1 << xAX);
1337 if (op->operand[0].lmod == OPLM_UNSPEC)
1338 op->operand[0].lmod = OPLM_DWORD;
1343 // we could set up operands for edx:eax, but there is no real need to
1344 // (see is_opr_modified())
1345 op->regmask_src |= op->regmask_dst;
1346 op->regmask_dst = (1 << xDX) | (1 << xAX);
1347 if (op->operand[0].lmod == OPLM_UNSPEC)
1348 op->operand[0].lmod = OPLM_DWORD;
1356 op->regmask_src |= op->regmask_dst;
1357 if (op->operand[1].lmod == OPLM_UNSPEC)
1358 op->operand[1].lmod = OPLM_BYTE;
1363 op->regmask_src |= op->regmask_dst;
1364 if (op->operand[2].lmod == OPLM_UNSPEC)
1365 op->operand[2].lmod = OPLM_BYTE;
1369 op->regmask_src |= op->regmask_dst;
1370 op->regmask_dst = 0;
1371 if (op->operand[0].lmod == OPLM_UNSPEC
1372 && (op->operand[0].type == OPT_CONST
1373 || op->operand[0].type == OPT_OFFSET
1374 || op->operand[0].type == OPT_LABEL))
1375 op->operand[0].lmod = OPLM_DWORD;
1381 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1382 && op->operand[0].lmod == op->operand[1].lmod
1383 && op->operand[0].reg == op->operand[1].reg
1384 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1386 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1387 op->regmask_src = op->regmask_dst = 0;
1392 if (op->operand[0].type == OPT_REG
1393 && op->operand[1].type == OPT_REGMEM)
1396 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1397 if (IS(buf, op->operand[1].name))
1398 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1403 // trashed regs must be explicitly detected later
1404 op->regmask_dst = 0;
1408 op->regmask_dst = (1 << xBP) | (1 << xSP);
1409 op->regmask_src = 1 << xBP;
1414 op->regmask_dst |= mxST0;
1418 op->regmask_dst |= mxST0;
1419 if (IS(words[op_w] + 3, "1"))
1420 op->operand[0].val = X87_CONST_1;
1421 else if (IS(words[op_w] + 3, "ln2"))
1422 op->operand[0].val = X87_CONST_LN2;
1423 else if (IS(words[op_w] + 3, "z"))
1424 op->operand[0].val = X87_CONST_Z;
1431 op->regmask_src |= mxST0;
1440 op->regmask_src |= mxST0;
1441 if (op->operand_cnt == 2)
1442 op->regmask_src |= op->regmask_dst;
1443 else if (op->operand_cnt == 1) {
1444 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1445 op->operand[0].type = OPT_REG;
1446 op->operand[0].lmod = OPLM_QWORD;
1447 op->operand[0].reg = xST0;
1448 op->regmask_dst |= mxST0;
1451 // IDA doesn't use this
1452 aerr("no operands?\n");
1466 op->regmask_src |= mxST0;
1467 op->regmask_dst |= mxST0;
1472 op->regmask_src |= mxST0 | mxST1;
1473 op->regmask_dst |= mxST0;
1481 op->regmask_src |= mxST0;
1482 if (op->operand_cnt == 0) {
1483 op->operand_cnt = 1;
1484 op->operand[0].type = OPT_REG;
1485 op->operand[0].lmod = OPLM_QWORD;
1486 op->operand[0].reg = xST1;
1487 op->regmask_src |= mxST1;
1495 if (op->operand[0].type == OPT_REG
1496 && op->operand[1].type == OPT_CONST)
1498 struct parsed_opr *op1 = &op->operand[1];
1499 if ((op->op == OP_AND && op1->val == 0)
1502 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1503 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1505 op->regmask_src = 0;
1510 static const char *op_name(struct parsed_op *po)
1512 static char buf[16];
1516 if (po->op == OP_JCC || po->op == OP_SCC) {
1518 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1521 strcpy(p, parsed_flag_op_names[po->pfo]);
1525 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1526 if (op_table[i].op == po->op)
1527 return op_table[i].name;
1533 static const char *dump_op(struct parsed_op *po)
1535 static char out[128];
1542 snprintf(out, sizeof(out), "%s", op_name(po));
1543 for (i = 0; i < po->operand_cnt; i++) {
1547 snprintf(p, sizeof(out) - (p - out),
1548 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1549 po->operand[i].name);
1555 static const char *lmod_type_u(struct parsed_op *po,
1556 enum opr_lenmod lmod)
1568 ferr(po, "invalid lmod: %d\n", lmod);
1569 return "(_invalid_)";
1573 static const char *lmod_cast_u(struct parsed_op *po,
1574 enum opr_lenmod lmod)
1586 ferr(po, "invalid lmod: %d\n", lmod);
1587 return "(_invalid_)";
1591 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1592 enum opr_lenmod lmod)
1604 ferr(po, "invalid lmod: %d\n", lmod);
1605 return "(_invalid_)";
1609 static const char *lmod_cast_s(struct parsed_op *po,
1610 enum opr_lenmod lmod)
1622 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1623 return "(_invalid_)";
1627 static const char *lmod_cast(struct parsed_op *po,
1628 enum opr_lenmod lmod, int is_signed)
1631 lmod_cast_s(po, lmod) :
1632 lmod_cast_u(po, lmod);
1635 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1647 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1652 static const char *opr_name(struct parsed_op *po, int opr_num)
1654 if (opr_num >= po->operand_cnt)
1655 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1656 return po->operand[opr_num].name;
1659 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1661 if (opr_num >= po->operand_cnt)
1662 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1663 if (po->operand[opr_num].type != OPT_CONST)
1664 ferr(po, "opr %d: const expected\n", opr_num);
1665 return po->operand[opr_num].val;
1668 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1670 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1671 ferr(po, "invalid reg: %d\n", popr->reg);
1672 return regs_r32[popr->reg];
1675 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1677 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1679 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1681 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1683 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1688 *is_signed = cast[1] == 's' ? 1 : 0;
1692 static int check_deref_cast(const char *cast, int *bits)
1694 if (IS_START(cast, "*(u8 *)"))
1696 else if (IS_START(cast, "*(u16 *)"))
1698 else if (IS_START(cast, "*(u32 *)"))
1700 else if (IS_START(cast, "*(u64 *)"))
1708 // cast1 is the "final" cast
1709 static const char *simplify_cast(const char *cast1, const char *cast2)
1711 static char buf[256];
1719 if (IS(cast1, cast2))
1722 if (check_simple_cast(cast1, &bits1, &s1) == 0
1723 && check_simple_cast(cast2, &bits2, &s2) == 0)
1728 if (check_simple_cast(cast1, &bits1, &s1) == 0
1729 && check_deref_cast(cast2, &bits2) == 0)
1731 if (bits1 == bits2) {
1732 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1737 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1740 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1744 static const char *simplify_cast_num(const char *cast, unsigned int val)
1746 if (IS(cast, "(u8)") && val < 0x100)
1748 if (IS(cast, "(s8)") && val < 0x80)
1750 if (IS(cast, "(u16)") && val < 0x10000)
1752 if (IS(cast, "(s16)") && val < 0x8000)
1754 if (IS(cast, "(s32)") && val < 0x80000000)
1760 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1769 namelen = strlen(name);
1771 p = strpbrk(name, "+-");
1775 ferr(po, "equ parse failed for '%s'\n", name);
1778 *extra_offs = strtol(p, &endp, 16);
1779 if (*endp != 0 || errno != 0)
1780 ferr(po, "equ parse failed for '%s'\n", name);
1783 for (i = 0; i < g_eqcnt; i++)
1784 if (strncmp(g_eqs[i].name, name, namelen) == 0
1785 && g_eqs[i].name[namelen] == 0)
1789 ferr(po, "unresolved equ name: '%s'\n", name);
1796 static int is_stack_access(struct parsed_op *po,
1797 const struct parsed_opr *popr)
1799 return (parse_stack_el(popr->name, NULL, NULL, 0)
1800 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1801 && IS_START(popr->name, "ebp")));
1804 static void parse_stack_access(struct parsed_op *po,
1805 const char *name, char *ofs_reg, int *offset_out,
1806 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1808 const char *bp_arg = "";
1809 const char *p = NULL;
1810 struct parsed_equ *eq;
1817 if (IS_START(name, "ebp-")
1818 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1821 if (IS_START(p, "0x"))
1824 offset = strtoul(p, &endp, 16);
1827 if (*endp != 0 || errno != 0)
1828 ferr(po, "ebp- parse of '%s' failed\n", name);
1831 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1832 eq = equ_find(po, bp_arg, &offset);
1834 ferr(po, "detected but missing eq\n");
1835 offset += eq->offset;
1838 if (!strncmp(name, "ebp", 3))
1841 // yes it sometimes LEAs ra for compares..
1842 if (!is_lea && ofs_reg[0] == 0
1843 && stack_ra <= offset && offset < stack_ra + 4)
1845 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1848 *offset_out = offset;
1850 *stack_ra_out = stack_ra;
1852 *bp_arg_out = bp_arg;
1855 static int parse_stack_esp_offset(struct parsed_op *po,
1856 const char *name, int *offset_out)
1858 char ofs_reg[16] = { 0, };
1859 struct parsed_equ *eq;
1865 if (strstr(name, "esp") == NULL)
1867 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1868 if (bp_arg == NULL) {
1869 // just plain offset?
1870 if (!IS_START(name, "esp+"))
1873 offset = strtol(name + 4, &endp, 0);
1874 if (endp == NULL || *endp != 0 || errno != 0)
1876 *offset_out = offset;
1880 if (ofs_reg[0] != 0)
1882 eq = equ_find(po, bp_arg, &offset);
1884 ferr(po, "detected but missing eq\n");
1885 offset += eq->offset;
1886 *offset_out = base_val + offset;
1890 static int stack_frame_access(struct parsed_op *po,
1891 struct parsed_opr *popr, char *buf, size_t buf_size,
1892 const char *name, const char *cast, int is_src, int is_lea)
1894 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1895 const char *prefix = "";
1896 const char *bp_arg = NULL;
1897 char ofs_reg[16] = { 0, };
1898 int i, arg_i, arg_s;
1905 if (g_bp_frame && (po->flags & OPF_EBP_S)
1906 && !(po->regmask_src & mxSP))
1907 ferr(po, "stack_frame_access while ebp is scratch\n");
1909 parse_stack_access(po, name, ofs_reg, &offset,
1910 &stack_ra, &bp_arg, is_lea);
1912 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1914 if (offset > stack_ra)
1916 arg_i = (offset - stack_ra - 4) / 4;
1917 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1919 if (g_func_pp->is_vararg
1920 && arg_i == g_func_pp->argc_stack && is_lea)
1922 // should be va_list
1925 snprintf(buf, buf_size, "%sap", cast);
1928 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1929 offset, bp_arg, arg_i);
1931 if (ofs_reg[0] != 0)
1932 ferr(po, "offset reg on arg access?\n");
1934 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1935 if (g_func_pp->arg[i].reg != NULL)
1941 if (i == g_func_pp->argc)
1942 ferr(po, "arg %d not in prototype?\n", arg_i);
1944 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1951 ferr(po, "lea/byte to arg?\n");
1952 if (is_src && (offset & 3) == 0)
1953 snprintf(buf, buf_size, "%sa%d",
1954 simplify_cast(cast, "(u8)"), i + 1);
1956 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1957 cast, offset & 3, i + 1);
1962 ferr(po, "lea/word to arg?\n");
1967 ferr(po, "problematic arg store\n");
1968 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1969 simplify_cast(cast, "*(u16 *)"), i + 1);
1972 ferr(po, "unaligned arg word load\n");
1974 else if (is_src && (offset & 2) == 0)
1975 snprintf(buf, buf_size, "%sa%d",
1976 simplify_cast(cast, "(u16)"), i + 1);
1978 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1979 cast, (offset & 2) ? "HI" : "LO", i + 1);
1991 snprintf(buf, buf_size, "(u32)&a%d + %d",
1994 ferr(po, "unaligned arg store\n");
1996 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1997 snprintf(buf, buf_size, "%s(a%d >> %d)",
1998 prefix, i + 1, (offset & 3) * 8);
2002 snprintf(buf, buf_size, "%s%sa%d",
2003 prefix, is_lea ? "&" : "", i + 1);
2008 ferr_assert(po, !(offset & 7));
2011 snprintf(buf, buf_size, "%s%sa%d",
2012 prefix, is_lea ? "&" : "", i + 1);
2016 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
2020 strcat(g_comment, " unaligned");
2023 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
2024 if (tmp_lmod != OPLM_DWORD
2025 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
2026 < lmod_bytes(po, popr->lmod) + (offset & 3))))
2028 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
2029 i + 1, offset, g_func_pp->arg[i].type.name);
2031 // can't check this because msvc likes to reuse
2032 // arg space for scratch..
2033 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
2034 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2038 if (g_stack_fsz == 0)
2039 ferr(po, "stack var access without stackframe\n");
2040 g_stack_frame_used = 1;
2042 sf_ofs = g_stack_fsz + offset;
2043 if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2044 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2054 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2055 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2059 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2060 // known unaligned or possibly unaligned
2061 strcat(g_comment, " unaligned");
2063 prefix = "*(u16 *)&";
2064 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2065 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2068 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2072 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2073 // known unaligned or possibly unaligned
2074 strcat(g_comment, " unaligned");
2076 prefix = "*(u32 *)&";
2077 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2078 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2081 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2085 ferr_assert(po, !(sf_ofs & 7));
2086 ferr_assert(po, ofs_reg[0] == 0);
2087 // only used for x87 int64/float, float sets is_lea
2088 if (!is_lea && (po->flags & OPF_FINT))
2089 prefix = "*(s64 *)&";
2090 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2094 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2101 static void check_func_pp(struct parsed_op *po,
2102 const struct parsed_proto *pp, const char *pfx)
2104 enum opr_lenmod tmp_lmod;
2108 if (pp->argc_reg != 0) {
2109 if (!g_allow_user_icall && !pp->is_fastcall) {
2110 pp_print(buf, sizeof(buf), pp);
2111 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2113 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2114 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2115 pfx, pp->argc_reg, pp->argc_stack);
2118 // fptrs must use 32bit args, callsite might have no information and
2119 // lack a cast to smaller types, which results in incorrectly masked
2120 // args passed (callee may assume masked args, it does on ARM)
2121 if (!pp->is_osinc) {
2122 for (i = 0; i < pp->argc; i++) {
2123 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2124 if (ret && tmp_lmod != OPLM_DWORD)
2125 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2126 i + 1, pp->arg[i].type.name);
2131 static const char *check_label_read_ref(struct parsed_op *po,
2134 const struct parsed_proto *pp;
2136 pp = proto_parse(g_fhdr, name, 0);
2138 ferr(po, "proto_parse failed for ref '%s'\n", name);
2141 check_func_pp(po, pp, "ref");
2146 static void check_opr(struct parsed_op *po, struct parsed_opr *popr)
2148 if (popr->segment == SEG_FS)
2149 ferr(po, "fs: used\n");
2150 if (popr->segment == SEG_GS)
2151 ferr(po, "gs: used\n");
2154 static char *out_src_opr(char *buf, size_t buf_size,
2155 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2158 char tmp1[256], tmp2[256];
2164 check_opr(po, popr);
2169 switch (popr->type) {
2172 ferr(po, "lea from reg?\n");
2174 switch (popr->lmod) {
2176 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2179 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2182 snprintf(buf, buf_size, "%s%s",
2183 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2186 if (popr->name[1] == 'h') // XXX..
2187 snprintf(buf, buf_size, "%s(%s >> 8)",
2188 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2190 snprintf(buf, buf_size, "%s%s",
2191 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2194 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2199 if (is_stack_access(po, popr)) {
2200 stack_frame_access(po, popr, buf, buf_size,
2201 popr->name, cast, 1, is_lea);
2205 strcpy(expr, popr->name);
2206 if (strchr(expr, '[')) {
2207 // special case: '[' can only be left for label[reg] form
2208 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2210 ferr(po, "parse failure for '%s'\n", expr);
2211 if (tmp1[0] == '(') {
2212 // (off_4FFF50+3)[eax]
2213 p = strchr(tmp1 + 1, ')');
2214 if (p == NULL || p[1] != 0)
2215 ferr(po, "parse failure (2) for '%s'\n", expr);
2217 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2219 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2222 // XXX: do we need more parsing?
2224 snprintf(buf, buf_size, "%s", expr);
2228 snprintf(buf, buf_size, "%s(%s)",
2229 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2233 name = check_label_read_ref(po, popr->name);
2234 if (cast[0] == 0 && popr->is_ptr)
2238 snprintf(buf, buf_size, "(u32)&%s", name);
2239 else if (popr->size_lt)
2240 snprintf(buf, buf_size, "%s%s%s%s", cast,
2241 lmod_cast_u_ptr(po, popr->lmod),
2242 popr->is_array ? "" : "&", name);
2244 snprintf(buf, buf_size, "%s%s%s", cast, name,
2245 popr->is_array ? "[0]" : "");
2249 name = check_label_read_ref(po, popr->name);
2253 ferr(po, "lea an offset?\n");
2254 snprintf(buf, buf_size, "%s&%s", cast, name);
2259 ferr(po, "lea from const?\n");
2261 printf_number(tmp1, sizeof(tmp1), popr->val);
2262 if (popr->val == 0 && strchr(cast, '*'))
2263 snprintf(buf, buf_size, "NULL");
2265 snprintf(buf, buf_size, "%s%s",
2266 simplify_cast_num(cast, popr->val), tmp1);
2270 ferr(po, "invalid src type: %d\n", popr->type);
2276 // note: may set is_ptr (we find that out late for ebp frame..)
2277 static char *out_dst_opr(char *buf, size_t buf_size,
2278 struct parsed_op *po, struct parsed_opr *popr)
2280 check_opr(po, popr);
2282 switch (popr->type) {
2284 switch (popr->lmod) {
2286 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2289 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2293 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2297 if (popr->name[1] == 'h') // XXX..
2298 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2300 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2303 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2308 if (is_stack_access(po, popr)) {
2309 stack_frame_access(po, popr, buf, buf_size,
2310 popr->name, "", 0, 0);
2314 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2317 if (popr->size_mismatch)
2318 snprintf(buf, buf_size, "%s%s%s",
2319 lmod_cast_u_ptr(po, popr->lmod),
2320 popr->is_array ? "" : "&", popr->name);
2322 snprintf(buf, buf_size, "%s%s", popr->name,
2323 popr->is_array ? "[0]" : "");
2327 ferr(po, "invalid dst type: %d\n", popr->type);
2333 static char *out_src_opr_u32(char *buf, size_t buf_size,
2334 struct parsed_op *po, struct parsed_opr *popr)
2336 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2339 static char *out_opr_float(char *buf, size_t buf_size,
2340 struct parsed_op *po, struct parsed_opr *popr, int is_src,
2341 int need_float_stack)
2343 const char *cast = NULL;
2346 switch (popr->type) {
2348 if (popr->reg < xST0 || popr->reg > xST7)
2349 ferr(po, "bad reg: %d\n", popr->reg);
2351 if (need_float_stack) {
2352 if (popr->reg == xST0)
2353 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2355 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2359 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2363 if (popr->lmod == OPLM_QWORD && is_stack_access(po, popr)) {
2364 stack_frame_access(po, popr, buf, buf_size,
2365 popr->name, "", is_src, 0);
2371 switch (popr->lmod) {
2379 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2382 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2383 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2387 ferr(po, "invalid float type: %d\n", popr->type);
2393 static char *out_src_opr_float(char *buf, size_t buf_size,
2394 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2396 return out_opr_float(buf, buf_size, po, popr, 1, need_float_stack);
2399 static char *out_dst_opr_float(char *buf, size_t buf_size,
2400 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2402 return out_opr_float(buf, buf_size, po, popr, 0, need_float_stack);
2405 static void out_test_for_cc(char *buf, size_t buf_size,
2406 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2407 enum opr_lenmod lmod, const char *expr)
2409 const char *cast, *scast;
2411 cast = lmod_cast_u(po, lmod);
2412 scast = lmod_cast_s(po, lmod);
2416 case PFO_BE: // CF==1||ZF==1; CF=0
2417 snprintf(buf, buf_size, "(%s%s %s 0)",
2418 cast, expr, is_inv ? "!=" : "==");
2422 case PFO_L: // SF!=OF; OF=0
2423 snprintf(buf, buf_size, "(%s%s %s 0)",
2424 scast, expr, is_inv ? ">=" : "<");
2427 case PFO_LE: // ZF==1||SF!=OF; OF=0
2428 snprintf(buf, buf_size, "(%s%s %s 0)",
2429 scast, expr, is_inv ? ">" : "<=");
2434 snprintf(buf, buf_size, "(%d)", !!is_inv);
2437 case PFO_P: // PF==1
2438 snprintf(buf, buf_size, "(%sdo_parity(%s))",
2439 is_inv ? "!" : "", expr);
2443 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2447 static void out_cmp_for_cc(char *buf, size_t buf_size,
2448 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2451 const char *cast, *scast, *cast_use;
2452 char buf1[256], buf2[256];
2453 enum opr_lenmod lmod;
2455 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2456 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2457 po->operand[0].lmod, po->operand[1].lmod);
2458 lmod = po->operand[0].lmod;
2460 cast = lmod_cast_u(po, lmod);
2461 scast = lmod_cast_s(po, lmod);
2477 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2480 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2481 if (po->op == OP_DEC)
2482 snprintf(buf2, sizeof(buf2), "1");
2485 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2487 strcat(cast_op2, "-");
2488 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2493 // note: must be unsigned compare
2494 snprintf(buf, buf_size, "(%s %s %s)",
2495 buf1, is_inv ? ">=" : "<", buf2);
2499 snprintf(buf, buf_size, "(%s %s %s)",
2500 buf1, is_inv ? "!=" : "==", buf2);
2504 // note: must be unsigned compare
2505 snprintf(buf, buf_size, "(%s %s %s)",
2506 buf1, is_inv ? ">" : "<=", buf2);
2509 if (is_inv && lmod == OPLM_BYTE
2510 && po->operand[1].type == OPT_CONST
2511 && po->operand[1].val == 0xff)
2513 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2514 snprintf(buf, buf_size, "(0)");
2518 // note: must be signed compare
2520 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2521 scast, buf1, buf2, is_inv ? ">=" : "<");
2525 snprintf(buf, buf_size, "(%s %s %s)",
2526 buf1, is_inv ? ">=" : "<", buf2);
2530 snprintf(buf, buf_size, "(%s %s %s)",
2531 buf1, is_inv ? ">" : "<=", buf2);
2539 static void out_cmp_test(char *buf, size_t buf_size,
2540 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2542 char buf1[256], buf2[256], buf3[256];
2544 if (po->op == OP_TEST) {
2545 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2546 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2549 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2550 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2551 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2553 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2554 po->operand[0].lmod, buf3);
2556 else if (po->op == OP_CMP) {
2557 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2560 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2563 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2564 struct parsed_opr *popr2)
2566 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2567 ferr(po, "missing lmod for both operands\n");
2569 if (popr1->lmod == OPLM_UNSPEC)
2570 popr1->lmod = popr2->lmod;
2571 else if (popr2->lmod == OPLM_UNSPEC)
2572 popr2->lmod = popr1->lmod;
2573 else if (popr1->lmod != popr2->lmod) {
2574 if (popr1->type_from_var) {
2575 popr1->size_mismatch = 1;
2576 if (popr1->lmod < popr2->lmod)
2578 popr1->lmod = popr2->lmod;
2580 else if (popr2->type_from_var) {
2581 popr2->size_mismatch = 1;
2582 if (popr2->lmod < popr1->lmod)
2584 popr2->lmod = popr1->lmod;
2587 ferr(po, "conflicting lmods: %d vs %d\n",
2588 popr1->lmod, popr2->lmod);
2592 static const char *op_to_c(struct parsed_op *po)
2616 ferr(po, "op_to_c was supplied with %d\n", po->op);
2620 // last op in stream - unconditional branch or ret
2621 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2622 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2623 && ops[_i].op != OP_CALL))
2625 #define check_i(po, i) \
2627 ferr(po, "bad " #i ": %d\n", i)
2629 // note: this skips over calls and rm'd stuff assuming they're handled
2630 // so it's intended to use at one of final passes
2631 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2632 int depth, int seen_noreturn, int flags_set)
2634 struct parsed_op *po;
2639 for (; i < opcnt; i++) {
2641 if (po->cc_scratch == magic)
2642 return ret; // already checked
2643 po->cc_scratch = magic;
2645 if (po->flags & OPF_TAIL) {
2646 if (po->op == OP_CALL) {
2647 if (po->pp != NULL && po->pp->is_noreturn)
2656 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2659 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2660 if (po->btj != NULL) {
2662 for (j = 0; j < po->btj->count; j++) {
2663 check_i(po, po->btj->d[j].bt_i);
2664 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2665 depth, seen_noreturn, flags_set);
2667 return ret; // dead end
2672 check_i(po, po->bt_i);
2673 if (po->flags & OPF_CJMP) {
2674 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2675 depth, seen_noreturn, flags_set);
2677 return ret; // dead end
2686 if ((po->op == OP_POP || po->op == OP_PUSH)
2687 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2692 if (po->op == OP_PUSH) {
2695 else if (po->op == OP_POP) {
2696 if (relevant && depth == 0) {
2697 po->flags |= flags_set;
2705 // for noreturn, assume msvc skipped stack cleanup
2706 return seen_noreturn ? 1 : -1;
2709 // scan for 'reg' pop backwards starting from i
2710 // intended to use for register restore search, so other reg
2711 // references are considered an error
2712 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2714 struct parsed_op *po;
2715 struct label_ref *lr;
2718 ops[i].cc_scratch = magic;
2722 if (g_labels[i] != NULL) {
2723 lr = &g_label_refs[i];
2724 for (; lr != NULL; lr = lr->next) {
2725 check_i(&ops[i], lr->i);
2726 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2730 if (i > 0 && LAST_OP(i - 1))
2738 if (ops[i].cc_scratch == magic)
2740 ops[i].cc_scratch = magic;
2743 if (po->op == OP_POP && po->operand[0].reg == reg) {
2744 if (po->flags & (OPF_RMD|OPF_DONE))
2747 po->flags |= set_flags;
2751 // this also covers the case where we reach corresponding push
2752 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2756 // nothing interesting on this path,
2757 // still return ret for something recursive calls could find
2761 static void find_reachable_exits(int i, int opcnt, int magic,
2762 int *exits, int *exit_count)
2764 struct parsed_op *po;
2767 for (; i < opcnt; i++)
2770 if (po->cc_scratch == magic)
2772 po->cc_scratch = magic;
2774 if (po->flags & OPF_TAIL) {
2775 ferr_assert(po, *exit_count < MAX_EXITS);
2776 exits[*exit_count] = i;
2781 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2782 if (po->flags & OPF_RMD)
2785 if (po->btj != NULL) {
2786 for (j = 0; j < po->btj->count; j++) {
2787 check_i(po, po->btj->d[j].bt_i);
2788 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2794 check_i(po, po->bt_i);
2795 if (po->flags & OPF_CJMP)
2796 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2804 // scan for 'reg' pop backwards starting from exits (all paths)
2805 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2807 static int exits[MAX_EXITS];
2808 static int exit_count;
2814 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2816 ferr_assert(&ops[i], exit_count > 0);
2819 for (j = 0; j < exit_count; j++) {
2821 ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2827 if (ops[e].op == OP_CALL && ops[e].pp != NULL
2828 && ops[e].pp->is_noreturn)
2830 // assume stack cleanup was skipped
2839 // scan for one or more pop of push <const>
2840 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2841 int push_i, int is_probe)
2843 struct parsed_op *po;
2844 struct label_ref *lr;
2848 for (; i < opcnt; i++)
2851 if (po->cc_scratch == magic)
2852 return ret; // already checked
2853 po->cc_scratch = magic;
2855 if (po->flags & OPF_JMP) {
2856 if (po->flags & OPF_RMD)
2858 if (po->op == OP_CALL)
2861 if (po->btj != NULL) {
2862 for (j = 0; j < po->btj->count; j++) {
2863 check_i(po, po->btj->d[j].bt_i);
2864 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2872 check_i(po, po->bt_i);
2873 if (po->flags & OPF_CJMP) {
2874 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2885 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2888 if (g_labels[i] != NULL) {
2889 // all refs must be visited
2890 lr = &g_label_refs[i];
2891 for (; lr != NULL; lr = lr->next) {
2893 if (ops[lr->i].cc_scratch != magic)
2896 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2900 if (po->op == OP_POP)
2902 if (po->flags & (OPF_RMD|OPF_DONE))
2906 po->flags |= OPF_DONE;
2907 po->datap = &ops[push_i];
2916 static void scan_for_pop_const(int i, int opcnt, int magic)
2920 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2922 ops[i].flags |= OPF_RMD | OPF_DONE;
2923 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2927 // check if all branch targets within a marked path are also marked
2928 // note: the path checked must not be empty or end with a branch
2929 static int check_path_branches(int opcnt, int magic)
2931 struct parsed_op *po;
2934 for (i = 0; i < opcnt; i++) {
2936 if (po->cc_scratch != magic)
2939 if (po->flags & OPF_JMP) {
2940 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2943 if (po->btj != NULL) {
2944 for (j = 0; j < po->btj->count; j++) {
2945 check_i(po, po->btj->d[j].bt_i);
2946 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2951 check_i(po, po->bt_i);
2952 if (ops[po->bt_i].cc_scratch != magic)
2954 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2962 // scan for multiple pushes for given pop
2963 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2966 int reg = ops[pop_i].operand[0].reg;
2967 struct parsed_op *po;
2968 struct label_ref *lr;
2971 ops[i].cc_scratch = magic;
2975 if (g_labels[i] != NULL) {
2976 lr = &g_label_refs[i];
2977 for (; lr != NULL; lr = lr->next) {
2978 check_i(&ops[i], lr->i);
2979 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2983 if (i > 0 && LAST_OP(i - 1))
2991 if (ops[i].cc_scratch == magic)
2993 ops[i].cc_scratch = magic;
2996 if (po->op == OP_CALL)
2998 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
3001 if (po->op == OP_PUSH)
3003 if (po->datap != NULL)
3005 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
3006 // leave this case for reg save/restore handlers
3010 po->flags |= OPF_PPUSH | OPF_DONE;
3011 po->datap = &ops[pop_i];
3020 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
3022 int magic = i + opcnt * 14;
3025 ret = scan_pushes_for_pop_r(i, magic, i, 1);
3027 ret = check_path_branches(opcnt, magic);
3029 ops[i].flags |= OPF_PPUSH | OPF_DONE;
3030 *regmask_pp |= 1 << ops[i].operand[0].reg;
3031 scan_pushes_for_pop_r(i, magic + 1, i, 0);
3036 static void scan_propagate_df(int i, int opcnt)
3038 struct parsed_op *po = &ops[i];
3041 for (; i < opcnt; i++) {
3043 if (po->flags & OPF_DF)
3044 return; // already resolved
3045 po->flags |= OPF_DF;
3047 if (po->op == OP_CALL)
3048 ferr(po, "call with DF set?\n");
3050 if (po->flags & OPF_JMP) {
3051 if (po->btj != NULL) {
3053 for (j = 0; j < po->btj->count; j++) {
3054 check_i(po, po->btj->d[j].bt_i);
3055 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
3060 if (po->flags & OPF_RMD)
3062 check_i(po, po->bt_i);
3063 if (po->flags & OPF_CJMP)
3064 scan_propagate_df(po->bt_i, opcnt);
3070 if (po->flags & OPF_TAIL)
3073 if (po->op == OP_CLD) {
3074 po->flags |= OPF_RMD | OPF_DONE;
3079 ferr(po, "missing DF clear?\n");
3082 // is operand 'opr' referenced by parsed_op 'po'?
3083 static int is_opr_referenced(const struct parsed_opr *opr,
3084 const struct parsed_op *po)
3088 if (opr->type == OPT_REG) {
3089 mask = po->regmask_dst | po->regmask_src;
3090 if (po->op == OP_CALL)
3091 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3092 if ((1 << opr->reg) & mask)
3098 for (i = 0; i < po->operand_cnt; i++)
3099 if (IS(po->operand[0].name, opr->name))
3105 // is operand 'opr' read by parsed_op 'po'?
3106 static int is_opr_read(const struct parsed_opr *opr,
3107 const struct parsed_op *po)
3109 if (opr->type == OPT_REG) {
3110 if (po->regmask_src & (1 << opr->reg))
3120 // is operand 'opr' modified by parsed_op 'po'?
3121 static int is_opr_modified(const struct parsed_opr *opr,
3122 const struct parsed_op *po)
3126 if (opr->type == OPT_REG) {
3127 if (po->op == OP_CALL) {
3128 mask = po->regmask_dst;
3129 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3130 if (mask & (1 << opr->reg))
3136 if (po->regmask_dst & (1 << opr->reg))
3142 return IS(po->operand[0].name, opr->name);
3145 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3146 static int is_any_opr_modified(const struct parsed_op *po_test,
3147 const struct parsed_op *po, int c_mode)
3152 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3155 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3158 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3161 // in reality, it can wreck any register, but in decompiled C
3162 // version it can only overwrite eax or edx:eax
3163 mask = (1 << xAX) | (1 << xDX);
3167 if (po->op == OP_CALL
3168 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3171 for (i = 0; i < po_test->operand_cnt; i++)
3172 if (IS(po_test->operand[i].name, po->operand[0].name))
3178 // scan for any po_test operand modification in range given
3179 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3182 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3185 for (; i < opcnt; i++) {
3186 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3193 // scan for po_test operand[0] modification in range given
3194 static int scan_for_mod_opr0(struct parsed_op *po_test,
3197 for (; i < opcnt; i++) {
3198 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3205 static int try_resolve_const(int i, const struct parsed_opr *opr,
3206 int magic, unsigned int *val);
3208 static int scan_for_flag_set(int i, int opcnt, int magic,
3209 int *branched, int *setters, int *setter_cnt)
3211 struct label_ref *lr;
3215 if (ops[i].cc_scratch == magic) {
3216 // is this a problem?
3217 //ferr(&ops[i], "%s looped\n", __func__);
3220 ops[i].cc_scratch = magic;
3222 if (g_labels[i] != NULL) {
3225 lr = &g_label_refs[i];
3226 for (; lr->next; lr = lr->next) {
3227 check_i(&ops[i], lr->i);
3228 ret = scan_for_flag_set(lr->i, opcnt, magic,
3229 branched, setters, setter_cnt);
3234 check_i(&ops[i], lr->i);
3235 if (i > 0 && LAST_OP(i - 1)) {
3239 ret = scan_for_flag_set(lr->i, opcnt, magic,
3240 branched, setters, setter_cnt);
3246 if (ops[i].flags & OPF_FLAGS) {
3247 setters[*setter_cnt] = i;
3250 if (ops[i].flags & OPF_REP) {
3251 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3254 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3255 if (ret != 1 || uval == 0) {
3256 // can't treat it as full setter because of ecx=0 case,
3257 // also disallow delayed compare
3266 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3273 // scan back for cdq, if anything modifies edx, fail
3274 static int scan_for_cdq_edx(int i)
3277 if (g_labels[i] != NULL) {
3278 if (g_label_refs[i].next != NULL)
3280 if (i > 0 && LAST_OP(i - 1)) {
3281 i = g_label_refs[i].i;
3288 if (ops[i].op == OP_CDQ)
3291 if (ops[i].regmask_dst & (1 << xDX))
3298 static int scan_for_reg_clear(int i, int reg)
3301 if (g_labels[i] != NULL) {
3302 if (g_label_refs[i].next != NULL)
3304 if (i > 0 && LAST_OP(i - 1)) {
3305 i = g_label_refs[i].i;
3312 if (ops[i].op == OP_XOR
3313 && ops[i].operand[0].lmod == OPLM_DWORD
3314 && ops[i].operand[0].reg == ops[i].operand[1].reg
3315 && ops[i].operand[0].reg == reg)
3318 if (ops[i].regmask_dst & (1 << reg))
3325 static void patch_esp_adjust(struct parsed_op *po, int adj)
3327 ferr_assert(po, po->op == OP_ADD);
3328 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3329 ferr_assert(po, po->operand[1].type == OPT_CONST);
3331 // this is a bit of a hack, but deals with use of
3332 // single adj for multiple calls
3333 po->operand[1].val -= adj;
3334 po->flags |= OPF_RMD;
3335 if (po->operand[1].val == 0)
3336 po->flags |= OPF_DONE;
3337 ferr_assert(po, (int)po->operand[1].val >= 0);
3340 // scan for positive, constant esp adjust
3341 // multipath case is preliminary
3342 static int scan_for_esp_adjust(int i, int opcnt,
3343 int adj_expect, int *adj, int *is_multipath, int do_update)
3345 int adj_expect_unknown = 0;
3346 struct parsed_op *po;
3350 *adj = *is_multipath = 0;
3351 if (adj_expect < 0) {
3352 adj_expect_unknown = 1;
3353 adj_expect = 32 * 4; // enough?
3356 for (; i < opcnt && *adj < adj_expect; i++) {
3357 if (g_labels[i] != NULL)
3361 if (po->flags & OPF_DONE)
3364 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3365 if (po->operand[1].type != OPT_CONST)
3366 ferr(&ops[i], "non-const esp adjust?\n");
3367 *adj += po->operand[1].val;
3369 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3372 patch_esp_adjust(po, adj_expect);
3374 po->flags |= OPF_RMD;
3378 else if (po->op == OP_PUSH) {
3379 //if (first_pop == -1)
3380 // first_pop = -2; // none
3381 *adj -= lmod_bytes(po, po->operand[0].lmod);
3383 else if (po->op == OP_POP) {
3384 if (!(po->flags & OPF_DONE)) {
3385 // seems like msvc only uses 'pop ecx' for stack realignment..
3386 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3388 if (first_pop == -1 && *adj >= 0)
3391 if (do_update && *adj >= 0) {
3392 po->flags |= OPF_RMD;
3394 po->flags |= OPF_DONE | OPF_NOREGS;
3397 *adj += lmod_bytes(po, po->operand[0].lmod);
3398 if (*adj > adj_best)
3401 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3402 if (po->op == OP_JMP && po->btj == NULL) {
3408 if (po->op != OP_CALL)
3410 if (po->operand[0].type != OPT_LABEL)
3412 if (po->pp != NULL && po->pp->is_stdcall)
3414 if (adj_expect_unknown && first_pop >= 0)
3416 // assume it's another cdecl call
3420 if (first_pop >= 0) {
3421 // probably only 'pop ecx' was used
3429 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3431 struct parsed_op *po;
3435 ferr(ops, "%s: followed bad branch?\n", __func__);
3437 for (; i < opcnt; i++) {
3439 if (po->cc_scratch == magic)
3441 po->cc_scratch = magic;
3444 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3445 if (po->btj != NULL) {
3447 for (j = 0; j < po->btj->count; j++)
3448 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3452 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3453 if (!(po->flags & OPF_CJMP))
3456 if (po->flags & OPF_TAIL)
3461 static const struct parsed_proto *try_recover_pp(
3462 struct parsed_op *po, const struct parsed_opr *opr,
3463 int is_call, int *search_instead)
3465 const struct parsed_proto *pp = NULL;
3469 // maybe an arg of g_func?
3470 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3472 char ofs_reg[16] = { 0, };
3473 int arg, arg_s, arg_i;
3480 parse_stack_access(po, opr->name, ofs_reg,
3481 &offset, &stack_ra, NULL, 0);
3482 if (ofs_reg[0] != 0)
3483 ferr(po, "offset reg on arg access?\n");
3484 if (offset <= stack_ra) {
3485 // search who set the stack var instead
3486 if (search_instead != NULL)
3487 *search_instead = 1;
3491 arg_i = (offset - stack_ra - 4) / 4;
3492 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3493 if (g_func_pp->arg[arg].reg != NULL)
3499 if (arg == g_func_pp->argc)
3500 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3502 pp = g_func_pp->arg[arg].pp;
3505 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3506 check_func_pp(po, pp, "icall arg");
3509 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3511 p = strchr(opr->name + 1, '[');
3512 memcpy(buf, opr->name, p - opr->name);
3513 buf[p - opr->name] = 0;
3514 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3516 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3517 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3520 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3523 check_func_pp(po, pp, "reg-fptr ref");
3529 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3530 int magic, const struct parsed_proto **pp_found, int *pp_i,
3533 const struct parsed_proto *pp = NULL;
3534 struct parsed_op *po;
3535 struct label_ref *lr;
3537 ops[i].cc_scratch = magic;
3540 if (g_labels[i] != NULL) {
3541 lr = &g_label_refs[i];
3542 for (; lr != NULL; lr = lr->next) {
3543 check_i(&ops[i], lr->i);
3544 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3546 if (i > 0 && LAST_OP(i - 1))
3554 if (ops[i].cc_scratch == magic)
3556 ops[i].cc_scratch = magic;
3558 if (!(ops[i].flags & OPF_DATA))
3560 if (!is_opr_modified(opr, &ops[i]))
3562 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3563 // most probably trashed by some processing
3568 opr = &ops[i].operand[1];
3569 if (opr->type != OPT_REG)
3573 po = (i >= 0) ? &ops[i] : ops;
3576 // reached the top - can only be an arg-reg
3577 if (opr->type != OPT_REG || g_func_pp == NULL)
3580 for (i = 0; i < g_func_pp->argc; i++) {
3581 if (g_func_pp->arg[i].reg == NULL)
3583 if (IS(opr->name, g_func_pp->arg[i].reg))
3586 if (i == g_func_pp->argc)
3588 pp = g_func_pp->arg[i].pp;
3590 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3591 i + 1, g_func_pp->arg[i].reg);
3592 check_func_pp(po, pp, "icall reg-arg");
3595 pp = try_recover_pp(po, opr, 1, NULL);
3597 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3598 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3599 || (*pp_found)->is_stdcall != pp->is_stdcall
3600 //|| (*pp_found)->is_fptr != pp->is_fptr
3601 || (*pp_found)->argc != pp->argc
3602 || (*pp_found)->argc_reg != pp->argc_reg
3603 || (*pp_found)->argc_stack != pp->argc_stack)
3605 ferr(po, "icall: parsed_proto mismatch\n");
3615 static void add_label_ref(struct label_ref *lr, int op_i)
3617 struct label_ref *lr_new;
3624 lr_new = calloc(1, sizeof(*lr_new));
3626 lr_new->next = lr->next;
3630 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3632 struct parsed_op *po = &ops[i];
3633 struct parsed_data *pd;
3634 char label[NAMELEN], *p;
3637 p = strchr(po->operand[0].name, '[');
3641 len = p - po->operand[0].name;
3642 strncpy(label, po->operand[0].name, len);
3645 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3646 if (IS(g_func_pd[j].label, label)) {
3652 //ferr(po, "label '%s' not parsed?\n", label);
3655 if (pd->type != OPT_OFFSET)
3656 ferr(po, "label '%s' with non-offset data?\n", label);
3658 // find all labels, link
3659 for (j = 0; j < pd->count; j++) {
3660 for (l = 0; l < opcnt; l++) {
3661 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3662 add_label_ref(&g_label_refs[l], i);
3672 static void clear_labels(int count)
3676 for (i = 0; i < count; i++) {
3677 if (g_labels[i] != NULL) {
3684 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3689 for (i = 0; i < pp->argc; i++) {
3690 if (pp->arg[i].reg != NULL) {
3691 reg = char_array_i(regs_r32,
3692 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3694 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3695 pp->arg[i].reg, pp->name);
3696 regmask |= 1 << reg;
3703 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3708 if (pp->has_retreg) {
3709 for (i = 0; i < pp->argc; i++) {
3710 if (pp->arg[i].type.is_retreg) {
3711 reg = char_array_i(regs_r32,
3712 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3713 ferr_assert(ops, reg >= 0);
3714 regmask |= 1 << reg;
3719 if (strstr(pp->ret_type.name, "int64"))
3720 return regmask | (1 << xAX) | (1 << xDX);
3721 if (IS(pp->ret_type.name, "float")
3722 || IS(pp->ret_type.name, "double"))
3724 return regmask | mxST0;
3726 if (strcasecmp(pp->ret_type.name, "void") == 0)
3729 return regmask | mxAX;
3732 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3734 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3735 && memcmp(po1->operand, po2->operand,
3736 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3739 static void resolve_branches_parse_calls(int opcnt)
3741 static const struct {
3745 unsigned int regmask_src;
3746 unsigned int regmask_dst;
3748 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3749 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3750 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3751 // more precise? Wine gets away with just __ftol handler
3752 { "__ftol2", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3753 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3755 const struct parsed_proto *pp_c;
3756 struct parsed_proto *pp;
3757 struct parsed_data *pd;
3758 struct parsed_op *po;
3759 const char *tmpname;
3764 for (i = 0; i < opcnt; i++)
3770 if (po->datap != NULL) {
3771 pp = calloc(1, sizeof(*pp));
3772 my_assert_not(pp, NULL);
3774 ret = parse_protostr(po->datap, pp);
3776 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3782 if (po->op == OP_CALL) {
3787 else if (po->operand[0].type == OPT_LABEL)
3789 tmpname = opr_name(po, 0);
3790 if (IS_START(tmpname, "loc_"))
3791 ferr(po, "call to loc_*\n");
3792 if (IS(tmpname, "__alloca_probe"))
3794 if (IS(tmpname, "__SEH_prolog")) {
3795 ferr_assert(po, g_seh_found == 0);
3799 if (IS(tmpname, "__SEH_epilog"))
3802 // convert some calls to pseudo-ops
3803 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3804 if (!IS(tmpname, pseudo_ops[l].name))
3807 po->op = pseudo_ops[l].op;
3808 po->operand_cnt = 0;
3809 po->regmask_src = pseudo_ops[l].regmask_src;
3810 po->regmask_dst = pseudo_ops[l].regmask_dst;
3811 po->flags = pseudo_ops[l].flags;
3812 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3815 if (l < ARRAY_SIZE(pseudo_ops))
3818 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3819 if (!g_header_mode && pp_c == NULL)
3820 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3823 pp = proto_clone(pp_c);
3824 my_assert_not(pp, NULL);
3830 check_func_pp(po, pp, "fptr var call");
3831 if (pp->is_noreturn) {
3832 po->flags |= OPF_TAIL;
3833 po->flags &= ~OPF_ATAIL; // most likely...
3840 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3843 if (po->operand[0].type == OPT_REGMEM) {
3844 pd = try_resolve_jumptab(i, opcnt);
3852 for (l = 0; l < opcnt; l++) {
3853 if (g_labels[l] != NULL
3854 && IS(po->operand[0].name, g_labels[l]))
3856 if (l == i + 1 && po->op == OP_JMP) {
3857 // yet another alignment type..
3858 po->flags |= OPF_RMD|OPF_DONE;
3861 add_label_ref(&g_label_refs[l], i);
3867 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3870 if (po->operand[0].type == OPT_LABEL)
3874 ferr(po, "unhandled branch\n");
3878 po->flags |= OPF_TAIL;
3879 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3880 if (prev_op == OP_POP)
3881 po->flags |= OPF_ATAIL;
3882 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3883 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3885 po->flags |= OPF_ATAIL;
3891 static int resolve_origin(int i, const struct parsed_opr *opr,
3892 int magic, int *op_i, int *is_caller);
3894 static void eliminate_seh_writes(int opcnt)
3896 const struct parsed_opr *opr;
3901 // assume all sf writes above g_seh_size to be seh related
3902 // (probably unsafe but oh well)
3903 for (i = 0; i < opcnt; i++) {
3904 if (ops[i].op != OP_MOV)
3906 opr = &ops[i].operand[0];
3907 if (opr->type != OPT_REGMEM)
3909 if (!is_stack_access(&ops[i], opr))
3913 parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
3915 if (offset < 0 && offset >= -g_seh_size)
3916 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3920 static void eliminate_seh(int opcnt)
3924 for (i = 0; i < opcnt; i++) {
3925 if (ops[i].op != OP_MOV)
3927 if (ops[i].operand[0].segment != SEG_FS)
3929 if (!IS(opr_name(&ops[i], 0), "0"))
3932 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3933 if (ops[i].operand[1].reg == xSP) {
3934 for (j = i - 1; j >= 0; j--) {
3935 if (ops[j].op != OP_PUSH)
3937 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3939 if (ops[j].operand[0].val == ~0)
3941 if (ops[j].operand[0].type == OPT_REG) {
3943 ret = resolve_origin(j, &ops[j].operand[0],
3944 j + opcnt * 22, &k, NULL);
3946 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3950 ferr(ops, "missing seh terminator\n");
3954 ret = resolve_origin(i, &ops[i].operand[1],
3955 i + opcnt * 23, &k, NULL);
3957 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3961 eliminate_seh_writes(opcnt);
3964 static void eliminate_seh_calls(int opcnt)
3966 int epilog_found = 0;
3973 ferr_assert(&ops[i], ops[i].op == OP_PUSH
3974 && ops[i].operand[0].type == OPT_CONST);
3975 g_stack_fsz = g_seh_size + ops[i].operand[0].val;
3976 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3979 ferr_assert(&ops[i], ops[i].op == OP_PUSH
3980 && ops[i].operand[0].type == OPT_OFFSET);
3981 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3984 ferr_assert(&ops[i], ops[i].op == OP_CALL
3985 && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
3986 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3988 for (i++; i < opcnt; i++) {
3989 if (ops[i].op != OP_CALL)
3991 if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
3994 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3997 ferr_assert(ops, epilog_found);
3999 eliminate_seh_writes(opcnt);
4002 static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4006 for (; i < opcnt; i++)
4007 if (!(ops[i].flags & OPF_DONE))
4010 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4011 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4017 for (; i < opcnt; i++) {
4018 if (i > 0 && g_labels[i] != NULL)
4020 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
4022 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4023 && ops[i].operand[1].type == OPT_CONST)
4025 g_stack_fsz += opr_const(&ops[i], 1);
4026 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4031 if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4032 && ops[i].operand[1].type == OPT_CONST)
4034 for (j = i + 1; j < opcnt; j++)
4035 if (!(ops[j].flags & OPF_DONE))
4037 if (ops[j].op == OP_CALL
4038 && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4040 g_stack_fsz += opr_const(&ops[i], 1);
4041 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4042 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4053 static void scan_prologue_epilogue(int opcnt, int *stack_align)
4055 int ecx_push = 0, esp_sub = 0, pusha = 0;
4056 int sandard_epilogue;
4060 if (g_seh_found == 2) {
4061 eliminate_seh_calls(opcnt);
4065 eliminate_seh(opcnt);
4066 // ida treats seh as part of sf
4067 g_stack_fsz = g_seh_size;
4071 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4072 && ops[1].op == OP_MOV
4073 && IS(opr_name(&ops[1], 0), "ebp")
4074 && IS(opr_name(&ops[1], 1), "esp"))
4077 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4078 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4080 for (i = 2; i < opcnt; i++)
4081 if (!(ops[i].flags & OPF_DONE))
4084 if (ops[i].op == OP_PUSHA) {
4085 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4090 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4091 && ops[i].operand[1].type == OPT_CONST)
4093 l = ops[i].operand[1].val;
4095 if (j == -1 || (l >> j) != -1)
4096 ferr(&ops[i], "unhandled esp align: %x\n", l);
4097 if (stack_align != NULL)
4098 *stack_align = 1 << j;
4099 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4103 i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4107 for (; i < opcnt; i++)
4108 if (ops[i].flags & OPF_TAIL)
4111 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4112 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4118 sandard_epilogue = 0;
4119 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4121 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4122 // the standard epilogue is sometimes even used without a sf
4123 if (ops[j - 1].op == OP_MOV
4124 && IS(opr_name(&ops[j - 1], 0), "esp")
4125 && IS(opr_name(&ops[j - 1], 1), "ebp"))
4126 sandard_epilogue = 1;
4128 else if (ops[j].op == OP_LEAVE)
4130 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4131 sandard_epilogue = 1;
4133 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4134 && ops[i].pp->is_noreturn)
4136 // on noreturn, msvc sometimes cleans stack, sometimes not
4141 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4142 ferr(&ops[j], "'pop ebp' expected\n");
4144 if (g_stack_fsz != 0 || sandard_epilogue) {
4145 if (ops[j].op == OP_LEAVE)
4147 else if (sandard_epilogue) // mov esp, ebp
4149 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4152 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4154 ferr(&ops[j], "esp restore expected\n");
4157 if (ecx_push && j >= 0 && ops[j].op == OP_POP
4158 && IS(opr_name(&ops[j], 0), "ecx"))
4160 ferr(&ops[j], "unexpected ecx pop\n");
4165 if (ops[j].op == OP_POPA)
4166 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4168 ferr(&ops[j], "popa expected\n");
4173 } while (i < opcnt);
4176 ferr(ops, "missing ebp epilogue\n");
4181 i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4183 if (ecx_push && !esp_sub) {
4184 // could actually be args for a call..
4185 for (; i < opcnt; i++)
4186 if (ops[i].op != OP_PUSH)
4189 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4190 const struct parsed_proto *pp;
4191 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4192 j = pp ? pp->argc_stack : 0;
4193 while (i > 0 && j > 0) {
4195 if (ops[i].op == OP_PUSH) {
4196 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4201 ferr(&ops[i], "unhandled prologue\n");
4205 g_stack_fsz = g_seh_size;
4206 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4207 if (!(ops[i].flags & OPF_RMD))
4217 if (ecx_push || esp_sub)
4222 for (; i < opcnt; i++)
4223 if (ops[i].flags & OPF_TAIL)
4227 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4228 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4233 else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4234 // skip arg updates for arg-reuse tailcall
4235 for (; j >= 0; j--) {
4236 if (ops[j].op != OP_MOV)
4238 if (ops[j].operand[0].type != OPT_REGMEM)
4240 if (strstr(ops[j].operand[0].name, "arg_") == NULL)
4245 if (ecx_push > 0 && !esp_sub) {
4246 for (l = 0; l < ecx_push && j >= 0; l++) {
4247 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4249 else if (ops[j].op == OP_ADD
4250 && IS(opr_name(&ops[j], 0), "esp")
4251 && ops[j].operand[1].type == OPT_CONST)
4254 l += ops[j].operand[1].val / 4 - 1;
4259 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4262 if (l != ecx_push) {
4263 if (i < opcnt && ops[i].op == OP_CALL
4264 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4266 // noreturn tailcall with no epilogue
4271 ferr(&ops[j], "epilogue scan failed\n");
4278 if (ops[j].op != OP_ADD
4279 || !IS(opr_name(&ops[j], 0), "esp")
4280 || ops[j].operand[1].type != OPT_CONST)
4282 if (i < opcnt && ops[i].op == OP_CALL
4283 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4285 // noreturn tailcall with no epilogue
4290 ferr(&ops[j], "'add esp' expected\n");
4293 if (ops[j].operand[1].val < g_stack_fsz)
4294 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4296 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4297 if (ops[j].operand[1].val == 0)
4298 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4303 } while (i < opcnt);
4306 ferr(ops, "missing esp epilogue\n");
4310 // find an instruction that changed opr before i op
4311 // *op_i must be set to -1 by the caller
4312 // *is_caller is set to 1 if one source is determined to be g_func arg
4313 // returns 1 if found, *op_i is then set to origin
4314 // returns -1 if multiple origins are found
4315 static int resolve_origin(int i, const struct parsed_opr *opr,
4316 int magic, int *op_i, int *is_caller)
4318 struct label_ref *lr;
4322 if (g_labels[i] != NULL) {
4323 lr = &g_label_refs[i];
4324 for (; lr != NULL; lr = lr->next) {
4325 check_i(&ops[i], lr->i);
4326 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4328 if (i > 0 && LAST_OP(i - 1))
4334 if (is_caller != NULL)
4339 if (ops[i].cc_scratch == magic)
4341 ops[i].cc_scratch = magic;
4343 if (!(ops[i].flags & OPF_DATA))
4345 if (!is_opr_modified(opr, &ops[i]))
4349 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4360 // find an instruction that previously referenced opr
4361 // if multiple results are found - fail
4362 // *op_i must be set to -1 by the caller
4363 // returns 1 if found, *op_i is then set to referencer insn
4364 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4365 int magic, int *op_i)
4367 struct label_ref *lr;
4371 if (g_labels[i] != NULL) {
4372 lr = &g_label_refs[i];
4373 for (; lr != NULL; lr = lr->next) {
4374 check_i(&ops[i], lr->i);
4375 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4377 if (i > 0 && LAST_OP(i - 1))
4385 if (ops[i].cc_scratch == magic)
4387 ops[i].cc_scratch = magic;
4389 if (!is_opr_referenced(opr, &ops[i]))
4400 // adjust datap of all reachable 'op' insns when moving back
4401 // returns 1 if at least 1 op was found
4402 // returns -1 if path without an op was found
4403 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4405 struct label_ref *lr;
4408 if (ops[i].cc_scratch == magic)
4410 ops[i].cc_scratch = magic;
4413 if (g_labels[i] != NULL) {
4414 lr = &g_label_refs[i];
4415 for (; lr != NULL; lr = lr->next) {
4416 check_i(&ops[i], lr->i);
4417 ret |= adjust_prev_op(lr->i, op, magic, datap);
4419 if (i > 0 && LAST_OP(i - 1))
4427 if (ops[i].cc_scratch == magic)
4429 ops[i].cc_scratch = magic;
4431 if (ops[i].op != op)
4434 ops[i].datap = datap;
4439 // find next instruction that reads opr
4440 // *op_i must be set to -1 by the caller
4441 // on return, *op_i is set to first referencer insn
4442 // returns 1 if exactly 1 referencer is found
4443 static int find_next_read(int i, int opcnt,
4444 const struct parsed_opr *opr, int magic, int *op_i)
4446 struct parsed_op *po;
4449 for (; i < opcnt; i++)
4451 if (ops[i].cc_scratch == magic)
4453 ops[i].cc_scratch = magic;
4456 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4457 if (po->btj != NULL) {
4459 for (j = 0; j < po->btj->count; j++) {
4460 check_i(po, po->btj->d[j].bt_i);
4461 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4467 if (po->flags & OPF_RMD)
4469 check_i(po, po->bt_i);
4470 if (po->flags & OPF_CJMP) {
4471 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4480 if (!is_opr_read(opr, po)) {
4482 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4483 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4485 full_opr = po->operand[0].lmod >= opr->lmod;
4487 if (is_opr_modified(opr, po) && full_opr) {
4491 if (po->flags & OPF_TAIL)
4506 // find next instruction that reads opr
4507 // *op_i must be set to -1 by the caller
4508 // on return, *op_i is set to first flag user insn
4509 // returns 1 if exactly 1 flag user is found
4510 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4512 struct parsed_op *po;
4515 for (; i < opcnt; i++)
4517 if (ops[i].cc_scratch == magic)
4519 ops[i].cc_scratch = magic;
4522 if (po->op == OP_CALL)
4524 if (po->flags & OPF_JMP) {
4525 if (po->btj != NULL) {
4527 for (j = 0; j < po->btj->count; j++) {
4528 check_i(po, po->btj->d[j].bt_i);
4529 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4535 if (po->flags & OPF_RMD)
4537 check_i(po, po->bt_i);
4538 if (po->flags & OPF_CJMP)
4545 if (!(po->flags & OPF_CC)) {
4546 if (po->flags & OPF_FLAGS)
4549 if (po->flags & OPF_TAIL)
4565 static int try_resolve_const(int i, const struct parsed_opr *opr,
4566 int magic, unsigned int *val)
4571 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4574 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4577 *val = ops[i].operand[1].val;
4584 static int resolve_used_bits(int i, int opcnt, int reg,
4585 int *mask, int *is_z_check)
4587 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4591 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4595 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4597 fnote(&ops[j], "(first read)\n");
4598 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4601 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4602 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4604 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4605 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4607 *mask = ops[j].operand[1].val;
4608 if (ops[j].operand[0].lmod == OPLM_BYTE
4609 && ops[j].operand[0].name[1] == 'h')
4613 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4616 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4618 *is_z_check = ops[k].pfo == PFO_Z;
4623 static const struct parsed_proto *resolve_deref(int i, int magic,
4624 struct parsed_opr *opr, int level)
4626 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4627 const struct parsed_proto *pp = NULL;
4628 int from_caller = 0;
4637 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4638 if (ret != 2 || len != strlen(opr->name)) {
4639 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4640 if (ret != 1 || len != strlen(opr->name))
4644 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4649 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4653 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4654 && strlen(ops[j].operand[1].name) == 3
4655 && ops[j].operand[0].lmod == OPLM_DWORD
4656 && ops[j].pp == NULL // no hint
4659 // allow one simple dereference (com/directx)
4660 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4661 ops[j].operand[1].name);
4665 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4670 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4673 if (ops[j].pp != NULL) {
4677 else if (ops[j].operand[1].type == OPT_REGMEM) {
4678 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4680 // maybe structure ptr in structure
4681 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4684 else if (ops[j].operand[1].type == OPT_LABEL)
4685 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4686 else if (ops[j].operand[1].type == OPT_REG) {
4689 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4691 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4692 for (k = 0; k < g_func_pp->argc; k++) {
4693 if (g_func_pp->arg[k].reg == NULL)
4695 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4696 pp = g_func_pp->arg[k].pp;
4705 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4707 ferr(&ops[j], "expected struct, got '%s %s'\n",
4708 pp->type.name, pp->name);
4712 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4715 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4716 int *pp_i, int *multi_src)
4718 const struct parsed_proto *pp = NULL;
4719 int search_advice = 0;
4724 switch (ops[i].operand[0].type) {
4726 // try to resolve struct member calls
4727 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4733 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4739 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4747 static struct parsed_proto *process_call_early(int i, int opcnt,
4750 struct parsed_op *po = &ops[i];
4751 struct parsed_proto *pp;
4757 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4761 // look for and make use of esp adjust
4763 if (!pp->is_stdcall && pp->argc_stack > 0)
4764 ret = scan_for_esp_adjust(i + 1, opcnt,
4765 pp->argc_stack * 4, &adj, &multipath, 0);
4767 if (pp->argc_stack > adj / 4)
4771 if (ops[ret].op == OP_POP) {
4772 for (j = 1; j < adj / 4; j++) {
4773 if (ops[ret + j].op != OP_POP
4774 || ops[ret + j].operand[0].reg != xCX)
4786 static struct parsed_proto *process_call(int i, int opcnt)
4788 struct parsed_op *po = &ops[i];
4789 const struct parsed_proto *pp_c;
4790 struct parsed_proto *pp;
4791 const char *tmpname;
4792 int call_i = -1, ref_i = -1;
4793 int adj = 0, multipath = 0;
4796 tmpname = opr_name(po, 0);
4801 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4803 if (!pp_c->is_func && !pp_c->is_fptr)
4804 ferr(po, "call to non-func: %s\n", pp_c->name);
4805 pp = proto_clone(pp_c);
4806 my_assert_not(pp, NULL);
4808 // not resolved just to single func
4811 switch (po->operand[0].type) {
4813 // we resolved this call and no longer need the register
4814 po->regmask_src &= ~(1 << po->operand[0].reg);
4816 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4817 && ops[call_i].operand[1].type == OPT_LABEL)
4819 // no other source users?
4820 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4822 if (ret == 1 && call_i == ref_i) {
4823 // and nothing uses it after us?
4825 find_next_read(i + 1, opcnt, &po->operand[0],
4826 i + opcnt * 11, &ref_i);
4828 // then also don't need the source mov
4829 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4841 pp = calloc(1, sizeof(*pp));
4842 my_assert_not(pp, NULL);
4845 ret = scan_for_esp_adjust(i + 1, opcnt,
4846 -1, &adj, &multipath, 0);
4847 if (ret < 0 || adj < 0) {
4848 if (!g_allow_regfunc)
4849 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4850 pp->is_unresolved = 1;
4854 if (adj > ARRAY_SIZE(pp->arg))
4855 ferr(po, "esp adjust too large: %d\n", adj);
4856 pp->ret_type.name = strdup("int");
4857 pp->argc = pp->argc_stack = adj;
4858 for (arg = 0; arg < pp->argc; arg++)
4859 pp->arg[arg].type.name = strdup("int");
4864 // look for and make use of esp adjust
4867 if (!pp->is_stdcall && pp->argc_stack > 0) {
4868 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4869 ret = scan_for_esp_adjust(i + 1, opcnt,
4870 adj_expect, &adj, &multipath, 0);
4873 if (pp->is_vararg) {
4874 if (adj / 4 < pp->argc_stack) {
4875 fnote(po, "(this call)\n");
4876 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4877 adj, pp->argc_stack * 4);
4879 // modify pp to make it have varargs as normal args
4881 pp->argc += adj / 4 - pp->argc_stack;
4882 for (; arg < pp->argc; arg++) {
4883 pp->arg[arg].type.name = strdup("int");
4886 if (pp->argc > ARRAY_SIZE(pp->arg))
4887 ferr(po, "too many args for '%s'\n", tmpname);
4889 if (pp->argc_stack > adj / 4) {
4890 if (pp->is_noreturn)
4891 // assume no stack adjust was emited
4893 fnote(po, "(this call)\n");
4894 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4895 tmpname, pp->argc_stack * 4, adj);
4898 scan_for_esp_adjust(i + 1, opcnt,
4899 pp->argc_stack * 4, &adj, &multipath, 1);
4901 else if (pp->is_vararg)
4902 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4909 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
4912 struct parsed_op *po;
4918 for (base_arg = 0; base_arg < pp->argc; base_arg++)
4919 if (pp->arg[base_arg].reg == NULL)
4922 for (j = i; j > 0; )
4924 ferr_assert(&ops[j], g_labels[j] == NULL);
4928 ferr_assert(po, po->op != OP_PUSH);
4929 if (po->op == OP_FST)
4931 if (po->operand[0].type != OPT_REGMEM)
4933 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
4936 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
4937 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
4941 arg = base_arg + offset / 4;
4943 po->p_argnum = arg + 1;
4944 ferr_assert(po, pp->arg[arg].datap == NULL);
4945 pp->arg[arg].datap = po;
4946 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
4947 if (regmask_ffca != NULL)
4948 *regmask_ffca |= 1 << arg;
4950 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4951 && po->operand[1].type == OPT_CONST)
4953 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4958 for (arg = base_arg; arg < pp->argc; arg++) {
4959 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
4960 po = pp->arg[arg].datap;
4962 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
4963 if (po->operand[0].lmod == OPLM_QWORD)
4970 static int collect_call_args_early(int i, struct parsed_proto *pp,
4971 int *regmask, int *regmask_ffca)
4973 struct parsed_op *po;
4977 for (arg = 0; arg < pp->argc; arg++)
4978 if (pp->arg[arg].reg == NULL)
4981 // first see if it can be easily done
4982 for (j = i; j > 0 && arg < pp->argc; )
4984 if (g_labels[j] != NULL)
4989 if (po->op == OP_CALL)
4991 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
4993 else if (po->op == OP_POP)
4995 else if (po->flags & OPF_CJMP)
4997 else if (po->op == OP_PUSH) {
4998 if (po->flags & (OPF_FARG|OPF_FARGNR))
5000 if (!g_header_mode) {
5001 ret = scan_for_mod(po, j + 1, i, 1);
5006 if (pp->arg[arg].type.is_va_list)
5010 for (arg++; arg < pp->argc; arg++)
5011 if (pp->arg[arg].reg == NULL)
5014 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5015 && po->operand[1].type == OPT_CONST)
5017 if (po->flags & (OPF_RMD|OPF_DONE))
5019 if (po->operand[1].val != pp->argc_stack * 4)
5020 ferr(po, "unexpected esp adjust: %d\n",
5021 po->operand[1].val * 4);
5022 ferr_assert(po, pp->argc - arg == pp->argc_stack);
5023 return collect_call_args_no_push(i, pp, regmask_ffca);
5031 for (arg = 0; arg < pp->argc; arg++)
5032 if (pp->arg[arg].reg == NULL)
5035 for (j = i; j > 0 && arg < pp->argc; )
5039 if (ops[j].op == OP_PUSH)
5041 ops[j].p_argnext = -1;
5042 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
5043 pp->arg[arg].datap = &ops[j];
5045 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5046 *regmask |= 1 << ops[j].operand[0].reg;
5048 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5049 ops[j].flags &= ~OPF_RSAVE;
5052 for (arg++; arg < pp->argc; arg++)
5053 if (pp->arg[arg].reg == NULL)
5061 static int sync_argnum(struct parsed_op *po, int argnum)
5063 struct parsed_op *po_tmp;
5065 // see if other branches don't have higher argnum
5066 for (po_tmp = po; po_tmp != NULL; ) {
5067 if (argnum < po_tmp->p_argnum)
5068 argnum = po_tmp->p_argnum;
5069 // note: p_argnext is active on current collect_call_args only
5070 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5073 // make all argnums consistent
5074 for (po_tmp = po; po_tmp != NULL; ) {
5075 if (po_tmp->p_argnum != 0)
5076 po_tmp->p_argnum = argnum;
5077 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5083 static int collect_call_args_r(struct parsed_op *po, int i,
5084 struct parsed_proto *pp, int *regmask, int *arg_grp,
5085 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
5087 struct parsed_proto *pp_tmp;
5088 struct parsed_op *po_tmp;
5089 struct label_ref *lr;
5090 int need_to_save_current;
5091 int arg_grp_current = 0;
5092 int save_args_seen = 0;
5099 ferr(po, "dead label encountered\n");
5103 for (; arg < pp->argc; arg++, argnum++)
5104 if (pp->arg[arg].reg == NULL)
5106 magic = (magic & 0xffffff) | (arg << 24);
5108 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5110 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5111 if (ops[j].cc_scratch != magic) {
5112 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5116 // ok: have already been here
5119 ops[j].cc_scratch = magic;
5121 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5122 lr = &g_label_refs[j];
5123 if (lr->next != NULL)
5125 for (; lr->next; lr = lr->next) {
5126 check_i(&ops[j], lr->i);
5127 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5129 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5130 arg, argnum, magic, need_op_saving, may_reuse);
5135 check_i(&ops[j], lr->i);
5136 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5138 if (j > 0 && LAST_OP(j - 1)) {
5139 // follow last branch in reverse
5144 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5145 arg, argnum, magic, need_op_saving, may_reuse);
5151 if (ops[j].op == OP_CALL)
5153 if (pp->is_unresolved)
5158 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5159 arg, pp->argc, ops[j].operand[0].name);
5160 if (may_reuse && pp_tmp->argc_stack > 0)
5161 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5162 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5164 // esp adjust of 0 means we collected it before
5165 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5166 && (ops[j].operand[1].type != OPT_CONST
5167 || ops[j].operand[1].val != 0))
5169 if (pp->is_unresolved)
5172 fnote(po, "(this call)\n");
5173 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5174 arg, pp->argc, ops[j].operand[1].val);
5176 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5178 if (pp->is_unresolved)
5181 fnote(po, "(this call)\n");
5182 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5184 else if (ops[j].flags & OPF_CJMP)
5186 if (pp->is_unresolved)
5191 else if (ops[j].op == OP_PUSH
5192 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5194 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5197 ops[j].p_argnext = -1;
5198 po_tmp = pp->arg[arg].datap;
5200 ops[j].p_argnext = po_tmp - ops;
5201 pp->arg[arg].datap = &ops[j];
5203 argnum = sync_argnum(&ops[j], argnum);
5205 need_to_save_current = 0;
5207 if (ops[j].operand[0].type == OPT_REG)
5208 reg = ops[j].operand[0].reg;
5210 if (!need_op_saving) {
5211 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5212 need_to_save_current = (ret >= 0);
5214 if (need_op_saving || need_to_save_current) {
5215 // mark this arg as one that needs operand saving
5216 pp->arg[arg].is_saved = 1;
5218 if (save_args_seen & (1 << (argnum - 1))) {
5221 if (arg_grp_current >= MAX_ARG_GRP)
5222 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5226 else if (ops[j].p_argnum == 0)
5227 ops[j].flags |= OPF_RMD;
5229 // some PUSHes are reused by different calls on other branches,
5230 // but that can't happen if we didn't branch, so they
5231 // can be removed from future searches (handles nested calls)
5233 ops[j].flags |= OPF_FARGNR;
5235 ops[j].flags |= OPF_FARG;
5236 ops[j].flags &= ~OPF_RSAVE;
5238 // check for __VALIST
5239 if (!pp->is_unresolved && g_func_pp != NULL
5240 && pp->arg[arg].type.is_va_list)
5243 ret = resolve_origin(j, &ops[j].operand[0],
5244 magic + 1, &k, NULL);
5245 if (ret == 1 && k >= 0)
5247 if (ops[k].op == OP_LEA) {
5248 if (!g_func_pp->is_vararg)
5249 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5252 snprintf(buf, sizeof(buf), "arg_%X",
5253 g_func_pp->argc_stack * 4);
5254 if (strstr(ops[k].operand[1].name, buf)
5255 || strstr(ops[k].operand[1].name, "arglist"))
5257 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5258 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5259 pp->arg[arg].is_saved = 0;
5263 ferr(&ops[k], "va_list arg detection failed\n");
5265 // check for va_list from g_func_pp arg too
5266 else if (ops[k].op == OP_MOV
5267 && is_stack_access(&ops[k], &ops[k].operand[1]))
5269 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5270 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5272 ops[k].flags |= OPF_RMD | OPF_DONE;
5273 ops[j].flags |= OPF_RMD;
5274 ops[j].p_argpass = ret + 1;
5275 pp->arg[arg].is_saved = 0;
5282 if (pp->arg[arg].is_saved) {
5283 ops[j].flags &= ~OPF_RMD;
5284 ops[j].p_argnum = argnum;
5287 // tracking reg usage
5289 *regmask |= 1 << reg;
5293 if (!pp->is_unresolved) {
5295 for (; arg < pp->argc; arg++, argnum++)
5296 if (pp->arg[arg].reg == NULL)
5299 magic = (magic & 0xffffff) | (arg << 24);
5302 if (ops[j].p_arggrp > arg_grp_current) {
5304 arg_grp_current = ops[j].p_arggrp;
5306 if (ops[j].p_argnum > 0)
5307 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5310 if (arg < pp->argc) {
5311 ferr(po, "arg collect failed for '%s': %d/%d\n",
5312 pp->name, arg, pp->argc);
5316 if (arg_grp_current > *arg_grp)
5317 *arg_grp = arg_grp_current;
5322 static int collect_call_args(struct parsed_op *po, int i,
5323 struct parsed_proto *pp, int *regmask, int magic)
5325 // arg group is for cases when pushes for
5326 // multiple funcs are going on
5327 struct parsed_op *po_tmp;
5332 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5338 // propagate arg_grp
5339 for (a = 0; a < pp->argc; a++) {
5340 if (pp->arg[a].reg != NULL)
5343 po_tmp = pp->arg[a].datap;
5344 while (po_tmp != NULL) {
5345 po_tmp->p_arggrp = arg_grp;
5346 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5351 if (pp->is_unresolved) {
5353 pp->argc_stack += ret;
5354 for (a = 0; a < pp->argc; a++)
5355 if (pp->arg[a].type.name == NULL)
5356 pp->arg[a].type.name = strdup("int");
5362 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5363 int regmask_now, int *regmask,
5364 int regmask_save_now, int *regmask_save,
5365 int *regmask_init, int regmask_arg)
5367 struct parsed_op *po;
5375 for (; i < opcnt; i++)
5378 if (cbits[i >> 3] & (1 << (i & 7)))
5380 cbits[i >> 3] |= (1 << (i & 7));
5382 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5383 if (po->flags & (OPF_RMD|OPF_DONE))
5385 if (po->btj != NULL) {
5386 for (j = 0; j < po->btj->count; j++) {
5387 check_i(po, po->btj->d[j].bt_i);
5388 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5389 regmask_now, regmask, regmask_save_now, regmask_save,
5390 regmask_init, regmask_arg);
5395 check_i(po, po->bt_i);
5396 if (po->flags & OPF_CJMP)
5397 reg_use_pass(po->bt_i, opcnt, cbits,
5398 regmask_now, regmask, regmask_save_now, regmask_save,
5399 regmask_init, regmask_arg);
5405 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5406 && !g_func_pp->is_userstack
5407 && po->operand[0].type == OPT_REG)
5409 reg = po->operand[0].reg;
5410 ferr_assert(po, reg >= 0);
5413 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5414 if (regmask_now & (1 << reg)) {
5415 already_saved = regmask_save_now & (1 << reg);
5416 flags_set = OPF_RSAVE | OPF_DONE;
5419 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5421 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5422 reg, 0, 0, flags_set);
5425 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5427 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5432 ferr_assert(po, !already_saved);
5433 po->flags |= flags_set;
5435 if (regmask_now & (1 << reg)) {
5436 regmask_save_now |= (1 << reg);
5437 *regmask_save |= regmask_save_now;
5442 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5443 reg = po->operand[0].reg;
5444 ferr_assert(po, reg >= 0);
5446 if (regmask_save_now & (1 << reg))
5447 regmask_save_now &= ~(1 << reg);
5449 regmask_now &= ~(1 << reg);
5452 else if (po->op == OP_CALL) {
5453 if ((po->regmask_dst & (1 << xAX))
5454 && !(po->regmask_dst & (1 << xDX)))
5456 if (po->flags & OPF_TAIL)
5457 // don't need eax, will do "return f();" or "f(); return;"
5458 po->regmask_dst &= ~(1 << xAX);
5460 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5462 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5465 po->regmask_dst &= ~(1 << xAX);
5469 // not "full stack" mode and have something in stack
5470 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5471 ferr(po, "float stack is not empty on func call\n");
5474 if (po->flags & OPF_NOREGS)
5477 // if incomplete register is used, clear it on init to avoid
5478 // later use of uninitialized upper part in some situations
5479 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5480 && po->operand[0].lmod != OPLM_DWORD)
5482 reg = po->operand[0].reg;
5483 ferr_assert(po, reg >= 0);
5485 if (!(regmask_now & (1 << reg)))
5486 *regmask_init |= 1 << reg;
5489 regmask_op = po->regmask_src | po->regmask_dst;
5491 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5492 regmask_new &= ~(1 << xSP);
5493 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5494 regmask_new &= ~(1 << xBP);
5496 if (regmask_new != 0)
5497 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5499 if (regmask_op & (1 << xBP)) {
5500 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5501 if (po->regmask_dst & (1 << xBP))
5502 // compiler decided to drop bp frame and use ebp as scratch
5503 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5505 regmask_op &= ~(1 << xBP);
5509 if (po->flags & OPF_FPUSH) {
5510 if (regmask_now & mxST1)
5511 regmask_now |= mxSTa; // switch to "full stack" mode
5512 if (regmask_now & mxSTa)
5513 po->flags |= OPF_FSHIFT;
5514 if (!(regmask_now & mxST7_2)) {
5516 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5520 regmask_now |= regmask_op;
5521 *regmask |= regmask_now;
5524 if (po->flags & OPF_FPOPP) {
5525 if ((regmask_now & mxSTa) == 0)
5526 ferr(po, "float pop on empty stack?\n");
5527 if (regmask_now & mxST7_2)
5528 po->flags |= OPF_FSHIFT;
5529 if (!(regmask_now & mxST7_2))
5530 regmask_now &= ~mxST1_0;
5532 else if (po->flags & OPF_FPOP) {
5533 if ((regmask_now & mxSTa) == 0)
5534 ferr(po, "float pop on empty stack?\n");
5535 if (regmask_now & (mxST7_2 | mxST1))
5536 po->flags |= OPF_FSHIFT;
5537 if (!(regmask_now & mxST7_2)) {
5539 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5543 if (po->flags & OPF_TAIL) {
5544 if (!(regmask_now & mxST7_2)) {
5545 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5546 if (!(regmask_now & mxST0))
5547 ferr(po, "no st0 on float return, mask: %x\n",
5550 else if (regmask_now & mxST1_0)
5551 ferr(po, "float regs on tail: %x\n", regmask_now);
5554 // there is support for "conditional tailcall", sort of
5555 if (!(po->flags & OPF_CC))
5561 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5565 for (i = 0; i < pp->argc; i++)
5566 if (pp->arg[i].reg == NULL)
5570 memmove(&pp->arg[i + 1], &pp->arg[i],
5571 sizeof(pp->arg[0]) * pp->argc_stack);
5572 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5573 pp->arg[i].reg = strdup(reg);
5574 pp->arg[i].type.name = strdup("int");
5579 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5580 int *pfomask, const char *dst_opr_text)
5582 if (*pfomask & (1 << PFO_Z)) {
5583 fprintf(fout, "\n cond_z = (%s%s == 0);",
5584 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5585 *pfomask &= ~(1 << PFO_Z);
5589 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5590 int *pfomask, const char *dst_opr_text)
5592 if (*pfomask & (1 << PFO_S)) {
5593 fprintf(fout, "\n cond_s = (%s%s < 0);",
5594 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5595 *pfomask &= ~(1 << PFO_S);
5599 static void output_std_flags(FILE *fout, struct parsed_op *po,
5600 int *pfomask, const char *dst_opr_text)
5602 output_std_flag_z(fout, po, pfomask, dst_opr_text);
5603 output_std_flag_s(fout, po, pfomask, dst_opr_text);
5607 OPP_FORCE_NORETURN = (1 << 0),
5608 OPP_SIMPLE_ARGS = (1 << 1),
5609 OPP_ALIGN = (1 << 2),
5612 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5615 const char *cconv = "";
5617 if (pp->is_fastcall)
5618 cconv = "__fastcall ";
5619 else if (pp->is_stdcall && pp->argc_reg == 0)
5620 cconv = "__stdcall ";
5622 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5624 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5625 fprintf(fout, "noreturn ");
5628 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5633 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5637 output_pp_attrs(fout, pp, flags);
5640 fprintf(fout, "%s", pp->name);
5645 for (i = 0; i < pp->argc; i++) {
5647 fprintf(fout, ", ");
5648 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5649 && !(flags & OPP_SIMPLE_ARGS))
5652 output_pp(fout, pp->arg[i].pp, 0);
5654 else if (pp->arg[i].type.is_retreg) {
5655 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5658 fprintf(fout, "%s", pp->arg[i].type.name);
5660 fprintf(fout, " a%d", i + 1);
5663 if (pp->arg[i].type.is_64bit)
5666 if (pp->is_vararg) {
5668 fprintf(fout, ", ");
5669 fprintf(fout, "...");
5674 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5680 snprintf(buf1, sizeof(buf1), "%d", grp);
5681 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5686 static void gen_x_cleanup(int opcnt);
5688 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5690 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5691 struct parsed_opr *last_arith_dst = NULL;
5692 char buf1[256], buf2[256], buf3[256], cast[64];
5693 struct parsed_proto *pp, *pp_tmp;
5694 struct parsed_data *pd;
5695 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5696 unsigned char cbits[MAX_OPS / 8];
5697 const char *float_type;
5698 const char *float_st0;
5699 const char *float_st1;
5700 int need_float_stack = 0;
5701 int need_float_sw = 0; // status word
5702 int need_tmp_var = 0;
5706 int label_pending = 0;
5707 int need_double = 0;
5708 int stack_align = 0;
5709 int stack_fsz_adj = 0;
5710 int regmask_save = 0; // used regs saved/restored in this func
5711 int regmask_arg; // regs from this function args (fastcall, etc)
5712 int regmask_ret; // regs needed on ret
5713 int regmask_now; // temp
5714 int regmask_init = 0; // regs that need zero initialization
5715 int regmask_pp = 0; // regs used in complex push-pop graph
5716 int regmask_ffca = 0; // float function call args
5717 int regmask = 0; // used regs
5727 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5728 g_stack_frame_used = 0;
5730 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5731 regmask_init = g_regmask_init;
5733 g_func_pp = proto_parse(fhdr, funcn, 0);
5734 if (g_func_pp == NULL)
5735 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5737 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5738 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5741 // - resolve all branches
5742 // - parse calls with labels
5743 resolve_branches_parse_calls(opcnt);
5746 // - handle ebp/esp frame, remove ops related to it
5747 scan_prologue_epilogue(opcnt, &stack_align);
5749 // handle a case where sf size is unalignment, but is
5750 // placed in a way that elements are still aligned
5751 if (g_stack_fsz & 4) {
5752 for (i = 0; i < g_eqcnt; i++) {
5753 if (g_eqs[i].lmod != OPLM_QWORD)
5755 if (!(g_eqs[i].offset & 4)) {
5764 // - remove dead labels
5765 // - set regs needed at ret
5766 for (i = 0; i < opcnt; i++)
5768 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5773 if (ops[i].op == OP_RET)
5774 ops[i].regmask_src |= regmask_ret;
5778 // - process trivial calls
5779 for (i = 0; i < opcnt; i++)
5782 if (po->flags & (OPF_RMD|OPF_DONE))
5785 if (po->op == OP_CALL)
5787 pp = process_call_early(i, opcnt, &j);
5789 if (!(po->flags & OPF_ATAIL)) {
5790 // since we know the args, try to collect them
5791 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5799 // commit esp adjust
5800 if (ops[j].op != OP_POP)
5801 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5803 for (l = 0; l < pp->argc_stack; l++)
5804 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5808 if (strstr(pp->ret_type.name, "int64"))
5811 po->flags |= OPF_DONE;
5817 // - process calls, stage 2
5818 // - handle some push/pop pairs
5819 // - scan for STD/CLD, propagate DF
5820 // - try to resolve needed x87 status word bits
5821 for (i = 0; i < opcnt; i++)
5826 if (po->flags & OPF_RMD)
5829 if (po->op == OP_CALL)
5831 if (!(po->flags & OPF_DONE)) {
5832 pp = process_call(i, opcnt);
5834 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5835 // since we know the args, collect them
5836 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5838 // for unresolved, collect after other passes
5842 ferr_assert(po, pp != NULL);
5844 po->regmask_src |= get_pp_arg_regmask_src(pp);
5845 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5847 if (po->regmask_dst & mxST0)
5848 po->flags |= OPF_FPUSH;
5850 if (strstr(pp->ret_type.name, "int64"))
5856 if (po->flags & OPF_DONE)
5861 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
5862 && po->operand[0].type == OPT_CONST)
5864 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5869 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5873 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5874 scan_propagate_df(i + 1, opcnt);
5879 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
5880 ferr(po, "TODO: fnstsw to mem\n");
5881 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
5883 ferr(po, "fnstsw resolve failed\n");
5884 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
5885 (void *)(long)(mask | (z_check << 16)));
5887 ferr(po, "failed to find fcom: %d\n", ret);
5896 // - find POPs for PUSHes, rm both
5897 // - scan for all used registers
5898 memset(cbits, 0, sizeof(cbits));
5899 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5900 0, ®mask_save, ®mask_init, regmask_arg);
5902 need_float_stack = !!(regmask & mxST7_2);
5905 // - find flag set ops for their users
5906 // - do unresolved calls
5907 // - declare indirect functions
5908 // - other op specific processing
5909 for (i = 0; i < opcnt; i++)
5912 if (po->flags & (OPF_RMD|OPF_DONE))
5915 if (po->flags & OPF_CC)
5917 int setters[16], cnt = 0, branched = 0;
5919 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
5920 &branched, setters, &cnt);
5921 if (ret < 0 || cnt <= 0)
5922 ferr(po, "unable to trace flag setter(s)\n");
5923 if (cnt > ARRAY_SIZE(setters))
5924 ferr(po, "too many flag setters\n");
5926 for (j = 0; j < cnt; j++)
5928 tmp_op = &ops[setters[j]]; // flag setter
5931 // to get nicer code, we try to delay test and cmp;
5932 // if we can't because of operand modification, or if we
5933 // have arith op, or branch, make it calculate flags explicitly
5934 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5936 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5937 pfomask = 1 << po->pfo;
5939 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5940 pfomask = 1 << po->pfo;
5943 // see if we'll be able to handle based on op result
5944 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5945 && po->pfo != PFO_Z && po->pfo != PFO_S
5946 && po->pfo != PFO_P)
5948 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5950 pfomask = 1 << po->pfo;
5953 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5954 propagate_lmod(tmp_op, &tmp_op->operand[0],
5955 &tmp_op->operand[1]);
5956 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5961 tmp_op->pfomask |= pfomask;
5962 cond_vars |= pfomask;
5964 // note: may overwrite, currently not a problem
5968 if (po->op == OP_RCL || po->op == OP_RCR
5969 || po->op == OP_ADC || po->op == OP_SBB)
5970 cond_vars |= 1 << PFO_C;
5976 cond_vars |= 1 << PFO_Z;
5980 if (po->operand[0].lmod == OPLM_DWORD)
5985 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
5990 // note: resolved non-reg calls are OPF_DONE already
5992 ferr_assert(po, pp != NULL);
5994 if (pp->is_unresolved) {
5995 int regmask_stack = 0;
5996 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5998 // this is pretty rough guess:
5999 // see ecx and edx were pushed (and not their saved versions)
6000 for (arg = 0; arg < pp->argc; arg++) {
6001 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
6004 tmp_op = pp->arg[arg].datap;
6006 ferr(po, "parsed_op missing for arg%d\n", arg);
6007 if (tmp_op->operand[0].type == OPT_REG)
6008 regmask_stack |= 1 << tmp_op->operand[0].reg;
6011 if (!((regmask_stack & (1 << xCX))
6012 && (regmask_stack & (1 << xDX))))
6014 if (pp->argc_stack != 0
6015 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
6017 pp_insert_reg_arg(pp, "ecx");
6018 pp->is_fastcall = 1;
6019 regmask_init |= 1 << xCX;
6020 regmask |= 1 << xCX;
6022 if (pp->argc_stack != 0
6023 || ((regmask | regmask_arg) & (1 << xDX)))
6025 pp_insert_reg_arg(pp, "edx");
6026 regmask_init |= 1 << xDX;
6027 regmask |= 1 << xDX;
6031 // note: __cdecl doesn't fall into is_unresolved category
6032 if (pp->argc_stack > 0)
6038 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6040 // <var> = offset <something>
6041 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6042 && !IS_START(po->operand[1].name, "off_"))
6044 if (!po->operand[0].pp->is_fptr)
6045 ferr(po, "%s not declared as fptr when it should be\n",
6046 po->operand[0].name);
6047 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6048 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6049 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6050 fnote(po, "var: %s\n", buf1);
6051 fnote(po, "func: %s\n", buf2);
6052 ferr(po, "^ mismatch\n");
6060 if (po->operand[0].lmod == OPLM_DWORD) {
6061 // 32bit division is common, look for it
6062 if (po->op == OP_DIV)
6063 ret = scan_for_reg_clear(i, xDX);
6065 ret = scan_for_cdq_edx(i);
6067 po->flags |= OPF_32BIT;
6076 po->flags |= OPF_RMD | OPF_DONE;
6086 if (po->operand[0].lmod == OPLM_QWORD)
6096 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
6098 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
6100 po->flags |= OPF_32BIT;
6108 // this might need it's own pass...
6109 if (po->op != OP_FST && po->p_argnum > 0)
6110 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6112 // correct for "full stack" mode late enable
6113 if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6114 && need_float_stack)
6115 po->flags |= OPF_FSHIFT;
6118 float_type = need_double ? "double" : "float";
6119 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6120 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6122 // output starts here
6125 fprintf(fout, "// had SEH\n");
6127 // define userstack size
6128 if (g_func_pp->is_userstack) {
6129 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6130 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6131 fprintf(fout, "#endif\n");
6134 // the function itself
6135 ferr_assert(ops, !g_func_pp->is_fptr);
6136 output_pp(fout, g_func_pp,
6137 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6138 fprintf(fout, "\n{\n");
6140 // declare indirect functions
6141 for (i = 0; i < opcnt; i++) {
6143 if (po->flags & OPF_RMD)
6146 if (po->op == OP_CALL) {
6149 ferr(po, "NULL pp\n");
6151 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6152 if (pp->name[0] != 0) {
6153 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6154 memcpy(pp->name, "i_", 2);
6156 // might be declared already
6158 for (j = 0; j < i; j++) {
6159 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6160 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6170 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6173 output_pp(fout, pp, OPP_SIMPLE_ARGS);
6174 fprintf(fout, ";\n");
6179 // output LUTs/jumptables
6180 for (i = 0; i < g_func_pd_cnt; i++) {
6182 fprintf(fout, " static const ");
6183 if (pd->type == OPT_OFFSET) {
6184 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6186 for (j = 0; j < pd->count; j++) {
6188 fprintf(fout, ", ");
6189 fprintf(fout, "&&%s", pd->d[j].u.label);
6193 fprintf(fout, "%s %s[] =\n { ",
6194 lmod_type_u(ops, pd->lmod), pd->label);
6196 for (j = 0; j < pd->count; j++) {
6198 fprintf(fout, ", ");
6199 fprintf(fout, "%u", pd->d[j].u.val);
6202 fprintf(fout, " };\n");
6206 // declare stack frame, va_arg
6209 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6211 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6212 if (g_func_lmods & (1 << OPLM_WORD))
6213 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6214 if (g_func_lmods & (1 << OPLM_BYTE))
6215 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6216 if (g_func_lmods & (1 << OPLM_QWORD))
6217 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6219 if (stack_align > 8)
6220 ferr(ops, "unhandled stack align of %d\n", stack_align);
6221 else if (stack_align == 8)
6222 fprintf(fout, " u64 align;");
6223 fprintf(fout, " } sf;\n");
6227 if (g_func_pp->is_userstack) {
6228 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6229 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6233 if (g_func_pp->is_vararg) {
6234 fprintf(fout, " va_list ap;\n");
6238 // declare arg-registers
6239 for (i = 0; i < g_func_pp->argc; i++) {
6240 if (g_func_pp->arg[i].reg != NULL) {
6241 reg = char_array_i(regs_r32,
6242 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6243 if (regmask & (1 << reg)) {
6244 if (g_func_pp->arg[i].type.is_retreg)
6245 fprintf(fout, " u32 %s = *r_%s;\n",
6246 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6248 fprintf(fout, " u32 %s = (u32)a%d;\n",
6249 g_func_pp->arg[i].reg, i + 1);
6252 if (g_func_pp->arg[i].type.is_retreg)
6253 ferr(ops, "retreg '%s' is unused?\n",
6254 g_func_pp->arg[i].reg);
6255 fprintf(fout, " // %s = a%d; // unused\n",
6256 g_func_pp->arg[i].reg, i + 1);
6262 // declare normal registers
6263 regmask_now = regmask & ~regmask_arg;
6264 regmask_now &= ~(1 << xSP);
6265 if (regmask_now & 0x00ff) {
6266 for (reg = 0; reg < 8; reg++) {
6267 if (regmask_now & (1 << reg)) {
6268 fprintf(fout, " u32 %s", regs_r32[reg]);
6269 if (regmask_init & (1 << reg))
6270 fprintf(fout, " = 0");
6271 fprintf(fout, ";\n");
6277 if (regmask_now & 0xff00) {
6278 for (reg = 8; reg < 16; reg++) {
6279 if (regmask_now & (1 << reg)) {
6280 fprintf(fout, " mmxr %s", regs_r32[reg]);
6281 if (regmask_init & (1 << reg))
6282 fprintf(fout, " = { 0, }");
6283 fprintf(fout, ";\n");
6289 if (need_float_stack) {
6290 fprintf(fout, " %s f_st[8];\n", float_type);
6291 fprintf(fout, " int f_stp = 0;\n");
6295 if (regmask_now & 0xff0000) {
6296 for (reg = 16; reg < 24; reg++) {
6297 if (regmask_now & (1 << reg)) {
6298 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6299 if (regmask_init & (1 << reg))
6300 fprintf(fout, " = 0");
6301 fprintf(fout, ";\n");
6308 if (need_float_sw) {
6309 fprintf(fout, " u16 f_sw;\n");
6314 for (reg = 0; reg < 8; reg++) {
6315 if (regmask_save & (1 << reg)) {
6316 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6322 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6323 if (save_arg_vars[i] == 0)
6325 for (reg = 0; reg < 32; reg++) {
6326 if (save_arg_vars[i] & (1 << reg)) {
6327 fprintf(fout, " u32 %s;\n",
6328 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6335 for (reg = 0; reg < 32; reg++) {
6336 if (regmask_ffca & (1 << reg)) {
6337 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6343 // declare push-pop temporaries
6345 for (reg = 0; reg < 8; reg++) {
6346 if (regmask_pp & (1 << reg)) {
6347 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6354 for (i = 0; i < 8; i++) {
6355 if (cond_vars & (1 << i)) {
6356 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6363 fprintf(fout, " u32 tmp;\n");
6368 fprintf(fout, " u64 tmp64;\n");
6373 fprintf(fout, "\n");
6375 // do stack clear, if needed
6376 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6378 if (g_stack_clear_len != 0) {
6379 if (g_stack_clear_len <= 4) {
6380 for (i = 0; i < g_stack_clear_len; i++)
6381 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6382 fprintf(fout, "0;\n");
6385 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6386 g_stack_clear_start, g_stack_clear_len * 4);
6390 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6393 if (g_func_pp->is_vararg) {
6394 if (g_func_pp->argc_stack == 0)
6395 ferr(ops, "vararg func without stack args?\n");
6396 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6400 for (i = 0; i < opcnt; i++)
6402 if (g_labels[i] != NULL) {
6403 fprintf(fout, "\n%s:\n", g_labels[i]);
6406 delayed_flag_op = NULL;
6407 last_arith_dst = NULL;
6411 if (po->flags & OPF_RMD)
6416 #define assert_operand_cnt(n_) \
6417 if (po->operand_cnt != n_) \
6418 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6420 // conditional/flag using op?
6421 if (po->flags & OPF_CC)
6427 // we go through all this trouble to avoid using parsed_flag_op,
6428 // which makes generated code much nicer
6429 if (delayed_flag_op != NULL)
6431 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6432 po->pfo, po->pfo_inv);
6435 else if (last_arith_dst != NULL
6436 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6437 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6440 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6441 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6442 last_arith_dst->lmod, buf3);
6445 else if (tmp_op != NULL) {
6446 // use preprocessed flag calc results
6447 if (!(tmp_op->pfomask & (1 << po->pfo)))
6448 ferr(po, "not prepared for pfo %d\n", po->pfo);
6450 // note: pfo_inv was not yet applied
6451 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6452 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6455 ferr(po, "all methods of finding comparison failed\n");
6458 if (po->flags & OPF_JMP) {
6459 fprintf(fout, " if %s", buf1);
6461 else if (po->op == OP_RCL || po->op == OP_RCR
6462 || po->op == OP_ADC || po->op == OP_SBB)
6465 fprintf(fout, " cond_%s = %s;\n",
6466 parsed_flag_op_names[po->pfo], buf1);
6468 else if (po->flags & OPF_DATA) { // SETcc
6469 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6470 fprintf(fout, " %s = %s;", buf2, buf1);
6473 ferr(po, "unhandled conditional op\n");
6477 pfomask = po->pfomask;
6482 assert_operand_cnt(2);
6483 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6484 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6485 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6486 fprintf(fout, " %s = %s;", buf1,
6487 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6492 assert_operand_cnt(2);
6493 po->operand[1].lmod = OPLM_DWORD; // always
6494 fprintf(fout, " %s = %s;",
6495 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6496 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6501 assert_operand_cnt(2);
6502 fprintf(fout, " %s = %s;",
6503 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6504 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6508 assert_operand_cnt(2);
6509 switch (po->operand[1].lmod) {
6511 strcpy(buf3, "(s8)");
6514 strcpy(buf3, "(s16)");
6517 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6519 fprintf(fout, " %s = %s;",
6520 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6521 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6526 assert_operand_cnt(2);
6527 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6528 fprintf(fout, " tmp = %s;",
6529 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6530 fprintf(fout, " %s = %s;",
6531 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6532 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6533 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6534 fprintf(fout, " %s = %stmp;",
6535 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6536 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6537 snprintf(g_comment, sizeof(g_comment), "xchg");
6541 assert_operand_cnt(1);
6542 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6543 fprintf(fout, " %s = ~%s;", buf1, buf1);
6547 assert_operand_cnt(2);
6548 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6549 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6550 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6551 strcpy(g_comment, "xlat");
6555 assert_operand_cnt(2);
6556 fprintf(fout, " %s = (s32)%s >> 31;",
6557 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6558 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6559 strcpy(g_comment, "cdq");
6563 assert_operand_cnt(1);
6564 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6565 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6569 if (po->flags & OPF_REP) {
6570 assert_operand_cnt(3);
6575 assert_operand_cnt(2);
6576 fprintf(fout, " %s = %sesi; esi %c= %d;",
6577 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6578 lmod_cast_u_ptr(po, po->operand[1].lmod),
6579 (po->flags & OPF_DF) ? '-' : '+',
6580 lmod_bytes(po, po->operand[1].lmod));
6581 strcpy(g_comment, "lods");
6586 if (po->flags & OPF_REP) {
6587 assert_operand_cnt(3);
6588 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6589 (po->flags & OPF_DF) ? '-' : '+',
6590 lmod_bytes(po, po->operand[1].lmod));
6591 fprintf(fout, " %sedi = eax;",
6592 lmod_cast_u_ptr(po, po->operand[1].lmod));
6593 strcpy(g_comment, "rep stos");
6596 assert_operand_cnt(2);
6597 fprintf(fout, " %sedi = eax; edi %c= %d;",
6598 lmod_cast_u_ptr(po, po->operand[1].lmod),
6599 (po->flags & OPF_DF) ? '-' : '+',
6600 lmod_bytes(po, po->operand[1].lmod));
6601 strcpy(g_comment, "stos");
6606 j = lmod_bytes(po, po->operand[0].lmod);
6607 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6608 l = (po->flags & OPF_DF) ? '-' : '+';
6609 if (po->flags & OPF_REP) {
6610 assert_operand_cnt(3);
6612 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6615 " %sedi = %sesi;", buf1, buf1);
6616 strcpy(g_comment, "rep movs");
6619 assert_operand_cnt(2);
6620 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6621 buf1, buf1, l, j, l, j);
6622 strcpy(g_comment, "movs");
6627 // repe ~ repeat while ZF=1
6628 j = lmod_bytes(po, po->operand[0].lmod);
6629 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6630 l = (po->flags & OPF_DF) ? '-' : '+';
6631 if (po->flags & OPF_REP) {
6632 assert_operand_cnt(3);
6634 " while (ecx != 0) {\n");
6635 if (pfomask & (1 << PFO_C)) {
6638 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6639 pfomask &= ~(1 << PFO_C);
6642 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6643 buf1, buf1, l, j, l, j);
6646 " if (cond_z %s 0) break;\n",
6647 (po->flags & OPF_REPZ) ? "==" : "!=");
6650 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6651 (po->flags & OPF_REPZ) ? "e" : "ne");
6654 assert_operand_cnt(2);
6656 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6657 buf1, buf1, l, j, l, j);
6658 strcpy(g_comment, "cmps");
6660 pfomask &= ~(1 << PFO_Z);
6661 last_arith_dst = NULL;
6662 delayed_flag_op = NULL;
6666 // only does ZF (for now)
6667 // repe ~ repeat while ZF=1
6668 j = lmod_bytes(po, po->operand[1].lmod);
6669 l = (po->flags & OPF_DF) ? '-' : '+';
6670 if (po->flags & OPF_REP) {
6671 assert_operand_cnt(3);
6673 " while (ecx != 0) {\n");
6675 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6676 lmod_cast_u(po, po->operand[1].lmod),
6677 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6680 " if (cond_z %s 0) break;\n",
6681 (po->flags & OPF_REPZ) ? "==" : "!=");
6684 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6685 (po->flags & OPF_REPZ) ? "e" : "ne");
6688 assert_operand_cnt(2);
6689 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6690 lmod_cast_u(po, po->operand[1].lmod),
6691 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6692 strcpy(g_comment, "scas");
6694 pfomask &= ~(1 << PFO_Z);
6695 last_arith_dst = NULL;
6696 delayed_flag_op = NULL;
6699 // arithmetic w/flags
6701 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6702 goto dualop_arith_const;
6703 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6707 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6708 if (po->operand[1].type == OPT_CONST) {
6709 j = lmod_bytes(po, po->operand[0].lmod);
6710 if (((1ull << j * 8) - 1) == po->operand[1].val)
6711 goto dualop_arith_const;
6716 assert_operand_cnt(2);
6717 fprintf(fout, " %s %s= %s;",
6718 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6720 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6721 output_std_flags(fout, po, &pfomask, buf1);
6722 last_arith_dst = &po->operand[0];
6723 delayed_flag_op = NULL;
6727 // and 0, or ~0 used instead mov
6728 assert_operand_cnt(2);
6729 fprintf(fout, " %s = %s;",
6730 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6731 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6732 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6733 output_std_flags(fout, po, &pfomask, buf1);
6734 last_arith_dst = &po->operand[0];
6735 delayed_flag_op = NULL;
6740 assert_operand_cnt(2);
6741 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6742 if (pfomask & (1 << PFO_C)) {
6743 if (po->operand[1].type == OPT_CONST) {
6744 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6745 j = po->operand[1].val;
6748 if (po->op == OP_SHL)
6752 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6756 ferr(po, "zero shift?\n");
6760 pfomask &= ~(1 << PFO_C);
6762 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6763 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6764 if (po->operand[1].type != OPT_CONST)
6765 fprintf(fout, " & 0x1f");
6767 output_std_flags(fout, po, &pfomask, buf1);
6768 last_arith_dst = &po->operand[0];
6769 delayed_flag_op = NULL;
6773 assert_operand_cnt(2);
6774 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6775 fprintf(fout, " %s = %s%s >> %s;", buf1,
6776 lmod_cast_s(po, po->operand[0].lmod), buf1,
6777 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6778 output_std_flags(fout, po, &pfomask, buf1);
6779 last_arith_dst = &po->operand[0];
6780 delayed_flag_op = NULL;
6785 assert_operand_cnt(3);
6786 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6787 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6788 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6789 if (po->operand[2].type != OPT_CONST) {
6790 // no handling for "undefined" case, hopefully not needed
6791 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6794 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6795 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6796 if (po->op == OP_SHLD) {
6797 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6798 buf1, buf3, buf1, buf2, l, buf3);
6799 strcpy(g_comment, "shld");
6802 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6803 buf1, buf3, buf1, buf2, l, buf3);
6804 strcpy(g_comment, "shrd");
6806 output_std_flags(fout, po, &pfomask, buf1);
6807 last_arith_dst = &po->operand[0];
6808 delayed_flag_op = NULL;
6813 assert_operand_cnt(2);
6814 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6815 if (po->operand[1].type == OPT_CONST) {
6816 j = po->operand[1].val;
6817 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6818 fprintf(fout, po->op == OP_ROL ?
6819 " %s = (%s << %d) | (%s >> %d);" :
6820 " %s = (%s >> %d) | (%s << %d);",
6821 buf1, buf1, j, buf1,
6822 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6826 output_std_flags(fout, po, &pfomask, buf1);
6827 last_arith_dst = &po->operand[0];
6828 delayed_flag_op = NULL;
6833 assert_operand_cnt(2);
6834 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6835 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6836 if (po->operand[1].type == OPT_CONST) {
6837 j = po->operand[1].val % l;
6839 ferr(po, "zero rotate\n");
6840 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6841 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6842 if (po->op == OP_RCL) {
6844 " %s = (%s << %d) | (cond_c << %d)",
6845 buf1, buf1, j, j - 1);
6847 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6851 " %s = (%s >> %d) | (cond_c << %d)",
6852 buf1, buf1, j, l - j);
6854 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6856 fprintf(fout, ";\n");
6857 fprintf(fout, " cond_c = tmp;");
6861 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6862 output_std_flags(fout, po, &pfomask, buf1);
6863 last_arith_dst = &po->operand[0];
6864 delayed_flag_op = NULL;
6868 assert_operand_cnt(2);
6869 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6870 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6871 // special case for XOR
6872 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
6873 for (j = 0; j <= PFO_LE; j++) {
6874 if (pfomask & (1 << j)) {
6875 fprintf(fout, " cond_%s = %d;\n",
6876 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
6877 pfomask &= ~(1 << j);
6880 fprintf(fout, " %s = 0;",
6881 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6882 last_arith_dst = &po->operand[0];
6883 delayed_flag_op = NULL;
6889 assert_operand_cnt(2);
6890 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6891 if (pfomask & (1 << PFO_C)) {
6892 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6893 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6894 if (po->operand[0].lmod == OPLM_DWORD) {
6895 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6896 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6897 fprintf(fout, " %s = (u32)tmp64;",
6898 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6899 strcat(g_comment, " add64");
6902 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6903 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6904 fprintf(fout, " %s += %s;",
6905 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6908 pfomask &= ~(1 << PFO_C);
6909 output_std_flags(fout, po, &pfomask, buf1);
6910 last_arith_dst = &po->operand[0];
6911 delayed_flag_op = NULL;
6914 if (pfomask & (1 << PFO_LE)) {
6915 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
6916 fprintf(fout, " cond_%s = %s;\n",
6917 parsed_flag_op_names[PFO_LE], buf1);
6918 pfomask &= ~(1 << PFO_LE);
6923 assert_operand_cnt(2);
6924 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6925 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6926 for (j = 0; j <= PFO_LE; j++) {
6927 if (!(pfomask & (1 << j)))
6929 if (j == PFO_Z || j == PFO_S)
6932 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6933 fprintf(fout, " cond_%s = %s;\n",
6934 parsed_flag_op_names[j], buf1);
6935 pfomask &= ~(1 << j);
6942 assert_operand_cnt(2);
6943 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6944 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6945 if (po->op == OP_SBB
6946 && IS(po->operand[0].name, po->operand[1].name))
6948 // avoid use of unitialized var
6949 fprintf(fout, " %s = -cond_c;", buf1);
6950 // carry remains what it was
6951 pfomask &= ~(1 << PFO_C);
6954 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6955 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6957 output_std_flags(fout, po, &pfomask, buf1);
6958 last_arith_dst = &po->operand[0];
6959 delayed_flag_op = NULL;
6964 // on SKL, if src is 0, dst is left unchanged
6965 assert_operand_cnt(2);
6966 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6967 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6968 output_std_flag_z(fout, po, &pfomask, buf2);
6969 if (po->op == OP_BSF)
6970 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
6972 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
6973 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
6974 last_arith_dst = &po->operand[0];
6975 delayed_flag_op = NULL;
6976 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
6980 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6981 for (j = 0; j <= PFO_LE; j++) {
6982 if (!(pfomask & (1 << j)))
6984 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6987 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6988 fprintf(fout, " cond_%s = %s;\n",
6989 parsed_flag_op_names[j], buf1);
6990 pfomask &= ~(1 << j);
6996 if (pfomask & (1 << PFO_C))
6997 // carry is unaffected by inc/dec.. wtf?
6998 ferr(po, "carry propagation needed\n");
7000 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7001 if (po->operand[0].type == OPT_REG) {
7002 strcpy(buf2, po->op == OP_INC ? "++" : "--");
7003 fprintf(fout, " %s%s;", buf1, buf2);
7006 strcpy(buf2, po->op == OP_INC ? "+" : "-");
7007 fprintf(fout, " %s %s= 1;", buf1, buf2);
7009 output_std_flags(fout, po, &pfomask, buf1);
7010 last_arith_dst = &po->operand[0];
7011 delayed_flag_op = NULL;
7015 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7016 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
7017 fprintf(fout, " %s = -%s%s;", buf1,
7018 lmod_cast_s(po, po->operand[0].lmod), buf2);
7019 last_arith_dst = &po->operand[0];
7020 delayed_flag_op = NULL;
7021 if (pfomask & PFOB_C) {
7022 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
7025 output_std_flags(fout, po, &pfomask, buf1);
7029 if (po->operand_cnt == 2) {
7030 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7033 if (po->operand_cnt == 3)
7034 ferr(po, "TODO imul3\n");
7037 assert_operand_cnt(1);
7038 switch (po->operand[0].lmod) {
7040 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7041 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
7042 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7043 fprintf(fout, " edx = tmp64 >> 32;\n");
7044 fprintf(fout, " eax = tmp64;");
7047 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7048 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
7049 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7053 ferr(po, "TODO: unhandled mul type\n");
7056 last_arith_dst = NULL;
7057 delayed_flag_op = NULL;
7062 assert_operand_cnt(1);
7063 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7064 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7065 po->op == OP_IDIV));
7066 switch (po->operand[0].lmod) {
7068 if (po->flags & OPF_32BIT)
7069 snprintf(buf2, sizeof(buf2), "%seax", cast);
7071 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7072 snprintf(buf2, sizeof(buf2), "%stmp64",
7073 (po->op == OP_IDIV) ? "(s64)" : "");
7075 if (po->operand[0].type == OPT_REG
7076 && po->operand[0].reg == xDX)
7078 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
7079 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
7082 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
7083 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
7087 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
7088 snprintf(buf2, sizeof(buf2), "%stmp",
7089 (po->op == OP_IDIV) ? "(s32)" : "");
7090 if (po->operand[0].type == OPT_REG
7091 && po->operand[0].reg == xDX)
7093 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
7095 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
7099 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
7101 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
7104 strcat(g_comment, " div16");
7107 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7109 last_arith_dst = NULL;
7110 delayed_flag_op = NULL;
7115 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7117 for (j = 0; j < 8; j++) {
7118 if (pfomask & (1 << j)) {
7119 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7120 fprintf(fout, " cond_%s = %s;",
7121 parsed_flag_op_names[j], buf1);
7128 last_arith_dst = NULL;
7129 delayed_flag_op = po;
7133 // SETcc - should already be handled
7136 // note: we reuse OP_Jcc for SETcc, only flags differ
7138 fprintf(fout, "\n goto %s;", po->operand[0].name);
7142 fprintf(fout, " if (ecx == 0)\n");
7143 fprintf(fout, " goto %s;", po->operand[0].name);
7144 strcat(g_comment, " jecxz");
7148 fprintf(fout, " if (--ecx != 0)\n");
7149 fprintf(fout, " goto %s;", po->operand[0].name);
7150 strcat(g_comment, " loop");
7154 assert_operand_cnt(1);
7155 last_arith_dst = NULL;
7156 delayed_flag_op = NULL;
7158 if (po->operand[0].type == OPT_REGMEM) {
7159 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7162 ferr(po, "parse failure for jmp '%s'\n",
7163 po->operand[0].name);
7164 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
7167 else if (po->operand[0].type != OPT_LABEL)
7168 ferr(po, "unhandled jmp type\n");
7170 fprintf(fout, " goto %s;", po->operand[0].name);
7174 assert_operand_cnt(1);
7176 my_assert_not(pp, NULL);
7179 if (po->flags & OPF_CC) {
7180 // we treat conditional branch to another func
7181 // (yes such code exists..) as conditional tailcall
7183 fprintf(fout, " {\n");
7186 if (pp->is_fptr && !pp->is_arg) {
7187 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7188 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7190 if (pp->is_unresolved || IS_START(pp->name, "i_guess"))
7191 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7192 buf3, asmfn, po->asmln, pp->name);
7195 fprintf(fout, "%s", buf3);
7196 if (strstr(pp->ret_type.name, "int64")) {
7197 if (po->flags & OPF_TAIL)
7198 ferr(po, "int64 and tail?\n");
7199 fprintf(fout, "tmp64 = ");
7201 else if (!IS(pp->ret_type.name, "void")) {
7202 if (po->flags & OPF_TAIL) {
7203 if (regmask_ret & mxAX) {
7204 fprintf(fout, "return ");
7205 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7206 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7208 else if (regmask_ret & mxST0)
7209 ferr(po, "float tailcall\n");
7211 else if (po->regmask_dst & mxAX) {
7212 fprintf(fout, "eax = ");
7213 if (pp->ret_type.is_ptr)
7214 fprintf(fout, "(u32)");
7216 else if (po->regmask_dst & mxST0) {
7217 ferr_assert(po, po->flags & OPF_FPUSH);
7218 if (need_float_stack)
7219 fprintf(fout, "f_st[--f_stp & 7] = ");
7221 fprintf(fout, "f_st0 = ");
7225 if (pp->name[0] == 0)
7226 ferr(po, "missing pp->name\n");
7227 fprintf(fout, "%s%s(", pp->name,
7228 pp->has_structarg ? "_sa" : "");
7230 if (po->flags & OPF_ATAIL) {
7232 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7233 check_compat |= pp->argc_stack > 0;
7235 && (pp->argc_stack != g_func_pp->argc_stack
7236 || pp->is_stdcall != g_func_pp->is_stdcall))
7237 ferr(po, "incompatible arg-reuse tailcall\n");
7238 if (g_func_pp->has_retreg)
7239 ferr(po, "TODO: retreg+tailcall\n");
7241 for (arg = j = 0; arg < pp->argc; arg++) {
7243 fprintf(fout, ", ");
7246 if (pp->arg[arg].type.is_ptr)
7247 snprintf(cast, sizeof(cast), "(%s)",
7248 pp->arg[arg].type.name);
7250 if (pp->arg[arg].reg != NULL) {
7251 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7255 for (; j < g_func_pp->argc; j++)
7256 if (g_func_pp->arg[j].reg == NULL)
7258 fprintf(fout, "%sa%d", cast, j + 1);
7263 for (arg = 0; arg < pp->argc; arg++) {
7265 fprintf(fout, ", ");
7268 if (pp->arg[arg].type.is_ptr)
7269 snprintf(cast, sizeof(cast), "(%s)",
7270 pp->arg[arg].type.name);
7272 if (pp->arg[arg].reg != NULL) {
7273 if (pp->arg[arg].type.is_retreg)
7274 fprintf(fout, "&%s", pp->arg[arg].reg);
7275 else if (IS(pp->arg[arg].reg, "ebp")
7276 && g_bp_frame && !(po->flags & OPF_EBP_S))
7278 // rare special case
7279 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7280 strcat(g_comment, " bp_ref");
7283 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7288 tmp_op = pp->arg[arg].datap;
7290 ferr(po, "parsed_op missing for arg%d\n", arg);
7292 if (tmp_op->flags & OPF_VAPUSH) {
7293 fprintf(fout, "ap");
7295 else if (tmp_op->op == OP_FST) {
7296 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7297 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7300 else if (pp->arg[arg].type.is_64bit) {
7301 ferr_assert(po, tmp_op->p_argpass == 0);
7302 ferr_assert(po, !pp->arg[arg].is_saved);
7303 ferr_assert(po, cast[0] == 0);
7304 out_src_opr(buf1, sizeof(buf1),
7305 tmp_op, &tmp_op->operand[0], cast, 0);
7306 tmp_op = pp->arg[++arg].datap;
7307 ferr_assert(po, tmp_op != NULL);
7308 out_src_opr(buf2, sizeof(buf2),
7309 tmp_op, &tmp_op->operand[0], cast, 0);
7310 fprintf(fout, "((u64)(%s) << 32) | (%s)",
7313 else if (tmp_op->p_argpass != 0) {
7314 fprintf(fout, "a%d", tmp_op->p_argpass);
7316 else if (pp->arg[arg].is_saved) {
7317 ferr_assert(po, tmp_op->p_argnum > 0);
7318 fprintf(fout, "%s%s", cast,
7319 saved_arg_name(buf1, sizeof(buf1),
7320 tmp_op->p_arggrp, tmp_op->p_argnum));
7324 out_src_opr(buf1, sizeof(buf1),
7325 tmp_op, &tmp_op->operand[0], cast, 0));
7329 fprintf(fout, ");");
7331 if (strstr(pp->ret_type.name, "int64")) {
7332 fprintf(fout, "\n");
7333 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7334 fprintf(fout, "%seax = tmp64;", buf3);
7337 if (pp->is_unresolved) {
7338 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7340 strcat(g_comment, buf2);
7343 if (po->flags & OPF_TAIL) {
7345 if (i == opcnt - 1 || pp->is_noreturn)
7347 else if (IS(pp->ret_type.name, "void"))
7349 else if (!(regmask_ret & (1 << xAX)))
7351 // else already handled as 'return f()'
7354 fprintf(fout, "\n%sreturn;", buf3);
7355 strcat(g_comment, " ^ tailcall");
7358 strcat(g_comment, " tailcall");
7360 if ((regmask_ret & (1 << xAX))
7361 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7363 ferr(po, "int func -> void func tailcall?\n");
7366 if (pp->is_noreturn)
7367 strcat(g_comment, " noreturn");
7368 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7369 strcat(g_comment, " argframe");
7370 if (po->flags & OPF_CC)
7371 strcat(g_comment, " cond");
7373 if (po->flags & OPF_CC)
7374 fprintf(fout, "\n }");
7376 delayed_flag_op = NULL;
7377 last_arith_dst = NULL;
7381 if (g_func_pp->is_vararg)
7382 fprintf(fout, " va_end(ap);\n");
7383 if (g_func_pp->has_retreg) {
7384 for (arg = 0; arg < g_func_pp->argc; arg++)
7385 if (g_func_pp->arg[arg].type.is_retreg)
7386 fprintf(fout, " *r_%s = %s;\n",
7387 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7390 if (regmask_ret & mxST0) {
7391 fprintf(fout, " return %s;", float_st0);
7393 else if (!(regmask_ret & mxAX)) {
7394 if (i != opcnt - 1 || label_pending)
7395 fprintf(fout, " return;");
7397 else if (g_func_pp->ret_type.is_ptr) {
7398 fprintf(fout, " return (%s)eax;",
7399 g_func_pp->ret_type.name);
7401 else if (IS(g_func_pp->ret_type.name, "__int64"))
7402 fprintf(fout, " return ((u64)edx << 32) | eax;");
7404 fprintf(fout, " return eax;");
7406 last_arith_dst = NULL;
7407 delayed_flag_op = NULL;
7411 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7412 if (po->p_argnum != 0) {
7413 // special case - saved func arg
7414 fprintf(fout, " %s = %s;",
7415 saved_arg_name(buf2, sizeof(buf2),
7416 po->p_arggrp, po->p_argnum), buf1);
7419 else if (po->flags & OPF_RSAVE) {
7420 fprintf(fout, " s_%s = %s;", buf1, buf1);
7423 else if (po->flags & OPF_PPUSH) {
7425 ferr_assert(po, tmp_op != NULL);
7426 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7427 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7430 else if (g_func_pp->is_userstack) {
7431 fprintf(fout, " *(--esp) = %s;", buf1);
7434 if (!(g_ida_func_attr & IDAFA_NORETURN))
7435 ferr(po, "stray push encountered\n");
7440 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7441 if (po->flags & OPF_RSAVE) {
7442 fprintf(fout, " %s = s_%s;", buf1, buf1);
7445 else if (po->flags & OPF_PPUSH) {
7446 // push/pop graph / non-const
7447 ferr_assert(po, po->datap == NULL);
7448 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7451 else if (po->datap != NULL) {
7454 fprintf(fout, " %s = %s;", buf1,
7455 out_src_opr(buf2, sizeof(buf2),
7456 tmp_op, &tmp_op->operand[0],
7457 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7460 else if (g_func_pp->is_userstack) {
7461 fprintf(fout, " %s = *esp++;", buf1);
7465 ferr(po, "stray pop encountered\n");
7475 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7476 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7477 po->op == OPP_ALLSHL ? "<<" : ">>");
7478 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7479 strcat(g_comment, po->op == OPP_ALLSHL
7480 ? " allshl" : " allshr");
7485 if (need_float_stack) {
7486 out_src_opr_float(buf1, sizeof(buf1),
7487 po, &po->operand[0], 1);
7488 if (po->regmask_src & mxSTa) {
7489 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7493 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7496 if (po->flags & OPF_FSHIFT)
7497 fprintf(fout, " f_st1 = f_st0;");
7498 if (po->operand[0].type == OPT_REG
7499 && po->operand[0].reg == xST0)
7501 strcat(g_comment, " fld st");
7504 fprintf(fout, " f_st0 = %s;",
7505 out_src_opr_float(buf1, sizeof(buf1),
7506 po, &po->operand[0], 0));
7508 strcat(g_comment, " fld");
7512 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7513 lmod_cast(po, po->operand[0].lmod, 1), 0);
7514 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7515 if (need_float_stack) {
7516 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7519 if (po->flags & OPF_FSHIFT)
7520 fprintf(fout, " f_st1 = f_st0;");
7521 fprintf(fout, " f_st0 = %s;", buf2);
7523 strcat(g_comment, " fild");
7527 if (need_float_stack)
7528 fprintf(fout, " f_st[--f_stp & 7] = ");
7530 if (po->flags & OPF_FSHIFT)
7531 fprintf(fout, " f_st1 = f_st0;");
7532 fprintf(fout, " f_st0 = ");
7534 switch (po->operand[0].val) {
7535 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7536 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
7537 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7538 default: ferr(po, "TODO\n"); break;
7543 if (po->flags & OPF_FARG) {
7544 // store to stack as func arg
7545 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7549 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7551 dead_dst = po->operand[0].type == OPT_REG
7552 && po->operand[0].reg == xST0;
7555 fprintf(fout, " %s = %s;", buf1, float_st0);
7556 if (po->flags & OPF_FSHIFT) {
7557 if (need_float_stack)
7558 fprintf(fout, " f_stp++;");
7560 fprintf(fout, " f_st0 = f_st1;");
7562 if (dead_dst && !(po->flags & OPF_FSHIFT))
7565 strcat(g_comment, " fst");
7569 fprintf(fout, " %s = %s%s;",
7570 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7571 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7572 if (po->flags & OPF_FSHIFT) {
7573 if (need_float_stack)
7574 fprintf(fout, " f_stp++;");
7576 fprintf(fout, " f_st0 = f_st1;");
7578 strcat(g_comment, " fist");
7585 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7587 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7589 dead_dst = (po->flags & OPF_FPOP)
7590 && po->operand[0].type == OPT_REG
7591 && po->operand[0].reg == xST0;
7593 case OP_FADD: j = '+'; break;
7594 case OP_FDIV: j = '/'; break;
7595 case OP_FMUL: j = '*'; break;
7596 case OP_FSUB: j = '-'; break;
7597 default: j = 'x'; break;
7599 if (need_float_stack) {
7601 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7602 if (po->flags & OPF_FSHIFT)
7603 fprintf(fout, " f_stp++;");
7606 if (po->flags & OPF_FSHIFT) {
7607 // note: assumes only 2 regs handled
7609 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7611 fprintf(fout, " f_st0 = f_st1;");
7614 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7616 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7621 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7623 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7625 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7627 dead_dst = (po->flags & OPF_FPOP)
7628 && po->operand[0].type == OPT_REG
7629 && po->operand[0].reg == xST0;
7630 j = po->op == OP_FDIVR ? '/' : '-';
7631 if (need_float_stack) {
7633 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7634 if (po->flags & OPF_FSHIFT)
7635 fprintf(fout, " f_stp++;");
7638 if (po->flags & OPF_FSHIFT) {
7640 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7642 fprintf(fout, " f_st0 = f_st1;");
7645 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7647 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7655 case OP_FIADD: j = '+'; break;
7656 case OP_FIDIV: j = '/'; break;
7657 case OP_FIMUL: j = '*'; break;
7658 case OP_FISUB: j = '-'; break;
7659 default: j = 'x'; break;
7661 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7663 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7664 lmod_cast(po, po->operand[0].lmod, 1), 0));
7669 fprintf(fout, " %s = %s %c %s;", float_st0,
7670 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7672 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7677 ferr_assert(po, po->datap != NULL);
7678 mask = (long)po->datap & 0xffff;
7679 z_check = ((long)po->datap >> 16) & 1;
7680 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7682 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
7683 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7686 else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
7687 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7690 else if (mask == 0x4100) { // C3, C0
7692 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7694 strcat(g_comment, " z_chk_det");
7697 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7698 "(%s < %s ? 0x0100 : 0);",
7699 float_st0, buf1, float_st0, buf1);
7703 ferr(po, "unhandled sw mask: %x\n", mask);
7704 if (po->flags & OPF_FSHIFT) {
7705 if (need_float_stack) {
7706 if (po->flags & OPF_FPOPP)
7707 fprintf(fout, " f_stp += 2;");
7709 fprintf(fout, " f_stp++;");
7712 ferr_assert(po, !(po->flags & OPF_FPOPP));
7713 fprintf(fout, " f_st0 = f_st1;");
7720 fprintf(fout, " %s = f_sw;",
7721 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7725 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7729 fprintf(fout, " %s = cos%s(%s);", float_st0,
7730 need_double ? "" : "f", float_st0);
7734 if (need_float_stack) {
7735 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7736 need_double ? "" : "f", float_st1, float_st0);
7737 fprintf(fout, " f_stp++;");
7740 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7741 need_double ? "" : "f");
7746 if (need_float_stack) {
7747 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7748 float_st1, need_double ? "" : "f", float_st0);
7749 fprintf(fout, " f_stp++;");
7752 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7753 need_double ? "" : "f");
7755 strcat(g_comment, " fyl2x");
7759 fprintf(fout, " %s = sin%s(%s);", float_st0,
7760 need_double ? "" : "f", float_st0);
7764 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7765 need_double ? "" : "f", float_st0);
7769 dead_dst = po->operand[0].type == OPT_REG
7770 && po->operand[0].reg == xST0;
7772 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7774 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7775 float_st0, float_st0, buf1, buf1);
7776 strcat(g_comment, " fxch");
7783 ferr_assert(po, po->flags & OPF_32BIT);
7784 fprintf(fout, " eax = (s32)%s;", float_st0);
7785 if (po->flags & OPF_FSHIFT) {
7786 if (need_float_stack)
7787 fprintf(fout, " f_stp++;");
7789 fprintf(fout, " f_st0 = f_st1;");
7791 strcat(g_comment, " ftol");
7795 if (need_float_stack) {
7796 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
7797 need_double ? "" : "f", float_st1, float_st0);
7798 fprintf(fout, " f_stp++;");
7801 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
7802 need_double ? "" : "f");
7804 strcat(g_comment, " CIpow");
7808 fprintf(fout, " do_skip_code_abort();");
7813 fprintf(fout, " do_emms();");
7818 ferr(po, "unhandled op type %d, flags %x\n",
7823 if (g_comment[0] != 0) {
7824 char *p = g_comment;
7825 while (my_isblank(*p))
7827 fprintf(fout, " // %s", p);
7832 fprintf(fout, "\n");
7834 // some sanity checking
7835 if (po->flags & OPF_REP) {
7836 if (po->op != OP_STOS && po->op != OP_MOVS
7837 && po->op != OP_CMPS && po->op != OP_SCAS)
7838 ferr(po, "unexpected rep\n");
7839 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7840 && (po->op == OP_CMPS || po->op == OP_SCAS))
7841 ferr(po, "cmps/scas with plain rep\n");
7843 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7844 && po->op != OP_CMPS && po->op != OP_SCAS)
7845 ferr(po, "unexpected repz/repnz\n");
7848 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
7850 // see is delayed flag stuff is still valid
7851 if (delayed_flag_op != NULL && delayed_flag_op != po) {
7852 if (is_any_opr_modified(delayed_flag_op, po, 0))
7853 delayed_flag_op = NULL;
7856 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7857 if (is_opr_modified(last_arith_dst, po))
7858 last_arith_dst = NULL;
7865 if (g_stack_fsz && !g_stack_frame_used)
7866 fprintf(fout, " (void)sf;\n");
7868 fprintf(fout, "}\n\n");
7870 gen_x_cleanup(opcnt);
7873 static void gen_x_cleanup(int opcnt)
7877 for (i = 0; i < opcnt; i++) {
7878 struct label_ref *lr, *lr_del;
7880 lr = g_label_refs[i].next;
7881 while (lr != NULL) {
7886 g_label_refs[i].i = -1;
7887 g_label_refs[i].next = NULL;
7889 if (ops[i].op == OP_CALL) {
7891 proto_release(ops[i].pp);
7897 struct func_proto_dep;
7899 struct func_prototype {
7904 int has_ret:3; // -1, 0, 1: unresolved, no, yes
7905 unsigned int dep_resolved:1;
7906 unsigned int is_stdcall:1;
7907 struct func_proto_dep *dep_func;
7909 const struct parsed_proto *pp; // seed pp, if any
7912 struct func_proto_dep {
7914 struct func_prototype *proto;
7915 int regmask_live; // .. at the time of call
7916 unsigned int ret_dep:1; // return from this is caller's return
7919 static struct func_prototype *hg_fp;
7920 static int hg_fp_cnt;
7922 static struct scanned_var {
7924 enum opr_lenmod lmod;
7925 unsigned int is_seeded:1;
7926 unsigned int is_c_str:1;
7927 const struct parsed_proto *pp; // seed pp, if any
7929 static int hg_var_cnt;
7931 static char **hg_refs;
7932 static int hg_ref_cnt;
7934 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7937 static struct func_prototype *hg_fp_add(const char *funcn)
7939 struct func_prototype *fp;
7941 if ((hg_fp_cnt & 0xff) == 0) {
7942 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7943 my_assert_not(hg_fp, NULL);
7944 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7947 fp = &hg_fp[hg_fp_cnt];
7948 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7950 fp->argc_stack = -1;
7956 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7961 for (i = 0; i < fp->dep_func_cnt; i++)
7962 if (IS(fp->dep_func[i].name, name))
7963 return &fp->dep_func[i];
7968 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7971 if (hg_fp_find_dep(fp, name))
7974 if ((fp->dep_func_cnt & 0xff) == 0) {
7975 fp->dep_func = realloc(fp->dep_func,
7976 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7977 my_assert_not(fp->dep_func, NULL);
7978 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7979 sizeof(fp->dep_func[0]) * 0x100);
7981 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7985 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7987 const struct func_prototype *p1 = p1_, *p2 = p2_;
7988 return strcmp(p1->name, p2->name);
7992 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7994 const struct func_prototype *p1 = p1_, *p2 = p2_;
7995 return p1->id - p2->id;
7999 static void hg_ref_add(const char *name)
8001 if ((hg_ref_cnt & 0xff) == 0) {
8002 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8003 my_assert_not(hg_refs, NULL);
8004 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8007 hg_refs[hg_ref_cnt] = strdup(name);
8008 my_assert_not(hg_refs[hg_ref_cnt], NULL);
8012 // recursive register dep pass
8013 // - track saved regs (part 2)
8014 // - try to figure out arg-regs
8015 // - calculate reg deps
8016 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8017 struct func_prototype *fp, int regmask_save, int regmask_dst,
8018 int *regmask_dep, int *has_ret)
8020 struct func_proto_dep *dep;
8021 struct parsed_op *po;
8022 int from_caller = 0;
8027 for (; i < opcnt; i++)
8029 if (cbits[i >> 3] & (1 << (i & 7)))
8031 cbits[i >> 3] |= (1 << (i & 7));
8035 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8036 if (po->flags & OPF_RMD)
8039 if (po->btj != NULL) {
8041 for (j = 0; j < po->btj->count; j++) {
8042 check_i(po, po->btj->d[j].bt_i);
8043 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8044 regmask_save, regmask_dst, regmask_dep, has_ret);
8049 check_i(po, po->bt_i);
8050 if (po->flags & OPF_CJMP) {
8051 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8052 regmask_save, regmask_dst, regmask_dep, has_ret);
8060 if (po->flags & OPF_FARG)
8061 /* (just calculate register deps) */;
8062 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8064 reg = po->operand[0].reg;
8065 ferr_assert(po, reg >= 0);
8067 if (po->flags & OPF_RSAVE) {
8068 regmask_save |= 1 << reg;
8071 if (po->flags & OPF_DONE)
8074 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
8076 regmask_save |= 1 << reg;
8077 po->flags |= OPF_RMD;
8078 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
8082 else if (po->flags & OPF_RMD)
8084 else if (po->op == OP_CALL) {
8085 po->regmask_dst |= 1 << xAX;
8087 dep = hg_fp_find_dep(fp, po->operand[0].name);
8089 dep->regmask_live = regmask_save | regmask_dst;
8090 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8091 dep->regmask_live |= 1 << xBP;
8094 else if (po->op == OP_RET) {
8095 if (po->operand_cnt > 0) {
8097 if (fp->argc_stack >= 0
8098 && fp->argc_stack != po->operand[0].val / 4)
8099 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8100 fp->argc_stack = po->operand[0].val / 4;
8104 // if has_ret is 0, there is uninitialized eax path,
8105 // which means it's most likely void func
8106 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
8107 if (po->op == OP_CALL) {
8112 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
8115 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
8118 if (ret != 1 && from_caller) {
8119 // unresolved eax - probably void func
8123 if (j >= 0 && ops[j].op == OP_CALL) {
8124 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8135 l = regmask_save | regmask_dst;
8136 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8139 l = po->regmask_src & ~l;
8142 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8143 l, regmask_dst, regmask_save, po->flags);
8146 regmask_dst |= po->regmask_dst;
8148 if (po->flags & OPF_TAIL)
8153 static void gen_hdr(const char *funcn, int opcnt)
8155 unsigned char cbits[MAX_OPS / 8];
8156 const struct parsed_proto *pp_c;
8157 struct parsed_proto *pp;
8158 struct func_prototype *fp;
8159 struct parsed_op *po;
8160 int regmask_dummy = 0;
8162 int max_bp_offset = 0;
8167 pp_c = proto_parse(g_fhdr, funcn, 1);
8169 // already in seed, will add to hg_fp later
8172 fp = hg_fp_add(funcn);
8174 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8175 g_stack_frame_used = 0;
8179 // - resolve all branches
8180 // - parse calls with labels
8181 resolve_branches_parse_calls(opcnt);
8184 // - handle ebp/esp frame, remove ops related to it
8185 scan_prologue_epilogue(opcnt, NULL);
8188 // - remove dead labels
8190 for (i = 0; i < opcnt; i++)
8192 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8198 if (po->flags & (OPF_RMD|OPF_DONE))
8201 if (po->op == OP_CALL) {
8202 if (po->operand[0].type == OPT_LABEL)
8203 hg_fp_add_dep(fp, opr_name(po, 0));
8204 else if (po->pp != NULL)
8205 hg_fp_add_dep(fp, po->pp->name);
8210 // - remove dead labels
8211 // - handle push <const>/pop pairs
8212 for (i = 0; i < opcnt; i++)
8214 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8220 if (po->flags & (OPF_RMD|OPF_DONE))
8223 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8224 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8228 // - process trivial calls
8229 for (i = 0; i < opcnt; i++)
8232 if (po->flags & (OPF_RMD|OPF_DONE))
8235 if (po->op == OP_CALL)
8237 pp = process_call_early(i, opcnt, &j);
8239 if (!(po->flags & OPF_ATAIL))
8240 // since we know the args, try to collect them
8241 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8247 // commit esp adjust
8248 if (ops[j].op != OP_POP)
8249 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8251 for (l = 0; l < pp->argc_stack; l++)
8252 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8256 po->flags |= OPF_DONE;
8262 // - track saved regs (simple)
8264 for (i = 0; i < opcnt; i++)
8267 if (po->flags & (OPF_RMD|OPF_DONE))
8270 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8271 && po->operand[0].reg != xCX)
8273 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8275 // regmask_save |= 1 << po->operand[0].reg; // do it later
8276 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8277 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8280 else if (po->op == OP_CALL)
8282 pp = process_call(i, opcnt);
8284 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8285 // since we know the args, collect them
8286 ret = collect_call_args(po, i, pp, ®mask_dummy,
8293 memset(cbits, 0, sizeof(cbits));
8297 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
8299 // find unreachable code - must be fixed in IDA
8300 for (i = 0; i < opcnt; i++)
8302 if (cbits[i >> 3] & (1 << (i & 7)))
8305 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8306 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8308 // the compiler sometimes still generates code after
8309 // noreturn OS functions
8312 if (ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8313 ferr(&ops[i], "unreachable code\n");
8316 for (i = 0; i < g_eqcnt; i++) {
8317 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8318 max_bp_offset = g_eqs[i].offset;
8321 if (fp->argc_stack < 0) {
8322 max_bp_offset = (max_bp_offset + 3) & ~3;
8323 fp->argc_stack = max_bp_offset / 4;
8324 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8328 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8329 fp->has_ret = has_ret;
8331 printf("// has_ret %d, regmask_dep %x\n",
8332 fp->has_ret, fp->regmask_dep);
8333 output_hdr_fp(stdout, fp, 1);
8334 if (IS(funcn, "sub_10007F72")) exit(1);
8337 gen_x_cleanup(opcnt);
8340 static void hg_fp_resolve_deps(struct func_prototype *fp)
8342 struct func_prototype fp_s;
8346 // this thing is recursive, so mark first..
8347 fp->dep_resolved = 1;
8349 for (i = 0; i < fp->dep_func_cnt; i++) {
8350 strcpy(fp_s.name, fp->dep_func[i].name);
8351 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8352 sizeof(hg_fp[0]), hg_fp_cmp_name);
8353 if (fp->dep_func[i].proto != NULL) {
8354 if (!fp->dep_func[i].proto->dep_resolved)
8355 hg_fp_resolve_deps(fp->dep_func[i].proto);
8357 dep = ~fp->dep_func[i].regmask_live
8358 & fp->dep_func[i].proto->regmask_dep;
8359 fp->regmask_dep |= dep;
8360 // printf("dep %s %s |= %x\n", fp->name,
8361 // fp->dep_func[i].name, dep);
8363 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8364 fp->has_ret = fp->dep_func[i].proto->has_ret;
8369 // make all thiscall/edx arg functions referenced from .data fastcall
8370 static void do_func_refs_from_data(void)
8372 struct func_prototype *fp, fp_s;
8375 for (i = 0; i < hg_ref_cnt; i++) {
8376 strcpy(fp_s.name, hg_refs[i]);
8377 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8378 sizeof(hg_fp[0]), hg_fp_cmp_name);
8382 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8383 fp->regmask_dep |= mxCX | mxDX;
8387 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8390 const struct parsed_proto *pp;
8391 char *p, namebuf[NAMELEN];
8397 for (; count > 0; count--, fp++) {
8398 if (fp->has_ret == -1)
8399 fprintf(fout, "// ret unresolved\n");
8401 fprintf(fout, "// dep:");
8402 for (j = 0; j < fp->dep_func_cnt; j++) {
8403 fprintf(fout, " %s/", fp->dep_func[j].name);
8404 if (fp->dep_func[j].proto != NULL)
8405 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8406 fp->dep_func[j].proto->has_ret);
8408 fprintf(fout, "\n");
8411 p = strchr(fp->name, '@');
8413 memcpy(namebuf, fp->name, p - fp->name);
8414 namebuf[p - fp->name] = 0;
8422 pp = proto_parse(g_fhdr, name, 1);
8423 if (pp != NULL && pp->is_include)
8426 if (fp->pp != NULL) {
8427 // part of seed, output later
8431 regmask_dep = fp->regmask_dep;
8432 argc_normal = fp->argc_stack;
8434 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8435 (fp->has_ret ? "int" : "void"));
8436 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8437 && (regmask_dep & ~mxCX) == 0)
8439 fprintf(fout, "/*__thiscall*/ ");
8443 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8444 && (regmask_dep & ~(mxCX | mxDX)) == 0)
8446 fprintf(fout, " __fastcall ");
8447 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8453 else if (regmask_dep && !fp->is_stdcall) {
8454 fprintf(fout, "/*__usercall*/ ");
8456 else if (regmask_dep) {
8457 fprintf(fout, "/*__userpurge*/ ");
8459 else if (fp->is_stdcall)
8460 fprintf(fout, " __stdcall ");
8462 fprintf(fout, " __cdecl ");
8464 fprintf(fout, "%s(", name);
8467 for (j = 0; j < xSP; j++) {
8468 if (regmask_dep & (1 << j)) {
8471 fprintf(fout, ", ");
8473 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8475 fprintf(fout, "int");
8476 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8480 for (j = 0; j < argc_normal; j++) {
8483 fprintf(fout, ", ");
8484 if (fp->pp != NULL) {
8485 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8486 if (!fp->pp->arg[arg - 1].type.is_ptr)
8490 fprintf(fout, "int ");
8491 fprintf(fout, "a%d", arg);
8494 fprintf(fout, ");\n");
8498 static void output_hdr(FILE *fout)
8500 static const char *lmod_c_names[] = {
8501 [OPLM_UNSPEC] = "???",
8502 [OPLM_BYTE] = "uint8_t",
8503 [OPLM_WORD] = "uint16_t",
8504 [OPLM_DWORD] = "uint32_t",
8505 [OPLM_QWORD] = "uint64_t",
8507 const struct scanned_var *var;
8508 struct func_prototype *fp;
8509 char line[256] = { 0, };
8513 // add stuff from headers
8514 for (i = 0; i < pp_cache_size; i++) {
8515 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8516 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8518 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8519 fp = hg_fp_add(name);
8520 fp->pp = &pp_cache[i];
8521 fp->argc_stack = fp->pp->argc_stack;
8522 fp->is_stdcall = fp->pp->is_stdcall;
8523 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8524 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8528 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8529 for (i = 0; i < hg_fp_cnt; i++)
8530 hg_fp_resolve_deps(&hg_fp[i]);
8532 // adjust functions referenced from data segment
8533 do_func_refs_from_data();
8535 // note: messes up .proto ptr, don't use
8536 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8539 for (i = 0; i < hg_var_cnt; i++) {
8542 if (var->pp != NULL)
8545 else if (var->is_c_str)
8546 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8548 fprintf(fout, "extern %-8s %s;",
8549 lmod_c_names[var->lmod], var->name);
8552 fprintf(fout, " // seeded");
8553 fprintf(fout, "\n");
8556 fprintf(fout, "\n");
8558 // output function prototypes
8559 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8562 fprintf(fout, "\n// - seed -\n");
8565 while (fgets(line, sizeof(line), g_fhdr))
8566 fwrite(line, 1, strlen(line), fout);
8569 // '=' needs special treatment
8571 static char *next_word_s(char *w, size_t wsize, char *s)
8578 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8580 for (i = 1; i < wsize - 1; i++) {
8582 printf("warning: missing closing quote: \"%s\"\n", s);
8591 for (; i < wsize - 1; i++) {
8592 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8598 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8599 printf("warning: '%s' truncated\n", w);
8604 static int cmpstringp(const void *p1, const void *p2)
8606 return strcmp(*(char * const *)p1, *(char * const *)p2);
8609 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8614 if (strstr(p, "..."))
8615 // unable to determine, assume needed
8618 if (*p == '.') // .text, .data, ...
8619 // ref from other data or non-function -> no
8622 p2 = strpbrk(p, "+:\r\n\x18");
8625 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8626 // referenced from removed code
8632 static int ida_xrefs_show_need(FILE *fasm, char *p,
8633 char **rlist, int rlist_len)
8639 p = strrchr(p, ';');
8640 if (p != NULL && *p == ';') {
8641 if (IS_START(p + 2, "sctref"))
8643 if (IS_START(p + 2, "DATA XREF: ")) {
8645 if (is_xref_needed(p, rlist, rlist_len))
8653 if (!my_fgets(line, sizeof(line), fasm))
8655 // non-first line is always indented
8656 if (!my_isblank(line[0]))
8659 // should be no content, just comment
8664 p = strrchr(p, ';');
8667 if (IS_START(p, "sctref")) {
8672 // it's printed once, but no harm to check again
8673 if (IS_START(p, "DATA XREF: "))
8676 if (is_xref_needed(p, rlist, rlist_len)) {
8681 fseek(fasm, pos, SEEK_SET);
8685 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8687 struct scanned_var *var;
8688 char line[256] = { 0, };
8697 // skip to next data section
8698 while (my_fgets(line, sizeof(line), fasm))
8703 if (*p == 0 || *p == ';')
8706 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8707 if (*p == 0 || *p == ';')
8710 if (*p != 's' || !IS_START(p, "segment para public"))
8716 if (p == NULL || !IS_START(p, "segment para public"))
8720 if (!IS_START(p, "'DATA'"))
8724 while (my_fgets(line, sizeof(line), fasm))
8729 no_identifier = my_isblank(*p);
8732 if (*p == 0 || *p == ';')
8735 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8736 words[wordc][0] = 0;
8737 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8738 if (*p == 0 || *p == ';') {
8744 if (wordc == 2 && IS(words[1], "ends"))
8749 if (no_identifier) {
8750 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8751 hg_ref_add(words[2]);
8755 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8756 // when this starts, we don't need anything from this section
8760 // check refs comment(s)
8761 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8764 if ((hg_var_cnt & 0xff) == 0) {
8765 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8766 * (hg_var_cnt + 0x100));
8767 my_assert_not(hg_vars, NULL);
8768 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8771 var = &hg_vars[hg_var_cnt++];
8772 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8774 // maybe already in seed header?
8775 var->pp = proto_parse(g_fhdr, var->name, 1);
8776 if (var->pp != NULL) {
8777 if (var->pp->is_fptr) {
8778 var->lmod = OPLM_DWORD;
8781 else if (var->pp->is_func)
8783 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8784 aerr("unhandled C type '%s' for '%s'\n",
8785 var->pp->type.name, var->name);
8791 if (IS(words[1], "dd")) {
8792 var->lmod = OPLM_DWORD;
8793 if (wordc >= 4 && IS(words[2], "offset"))
8794 hg_ref_add(words[3]);
8796 else if (IS(words[1], "dw"))
8797 var->lmod = OPLM_WORD;
8798 else if (IS(words[1], "db")) {
8799 var->lmod = OPLM_BYTE;
8800 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8801 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8805 else if (IS(words[1], "dq"))
8806 var->lmod = OPLM_QWORD;
8807 //else if (IS(words[1], "dt"))
8809 aerr("type '%s' not known\n", words[1]);
8817 static void set_label(int i, const char *name)
8823 p = strchr(name, ':');
8827 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8828 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8829 g_labels[i] = realloc(g_labels[i], len + 1);
8830 my_assert_not(g_labels[i], NULL);
8831 memcpy(g_labels[i], name, len);
8832 g_labels[i][len] = 0;
8841 static struct chunk_item *func_chunks;
8842 static int func_chunk_cnt;
8843 static int func_chunk_alloc;
8845 static void add_func_chunk(FILE *fasm, const char *name, int line)
8847 if (func_chunk_cnt >= func_chunk_alloc) {
8848 func_chunk_alloc *= 2;
8849 func_chunks = realloc(func_chunks,
8850 func_chunk_alloc * sizeof(func_chunks[0]));
8851 my_assert_not(func_chunks, NULL);
8853 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8854 func_chunks[func_chunk_cnt].name = strdup(name);
8855 func_chunks[func_chunk_cnt].asmln = line;
8859 static int cmp_chunks(const void *p1, const void *p2)
8861 const struct chunk_item *c1 = p1, *c2 = p2;
8862 return strcmp(c1->name, c2->name);
8865 static void scan_ahead_for_chunks(FILE *fasm)
8875 oldpos = ftell(fasm);
8878 while (my_fgets(line, sizeof(line), fasm))
8889 // get rid of random tabs
8890 for (i = 0; line[i] != 0; i++)
8891 if (line[i] == '\t')
8894 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8897 next_word(words[0], sizeof(words[0]), p);
8898 if (words[0][0] == 0)
8899 aerr("missing name for func chunk?\n");
8901 add_func_chunk(fasm, words[0], asmln);
8903 else if (IS_START(p, "; sctend"))
8909 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8910 words[wordc][0] = 0;
8911 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8912 if (*p == 0 || *p == ';') {
8918 if (wordc == 2 && IS(words[1], "ends"))
8922 fseek(fasm, oldpos, SEEK_SET);
8926 int main(int argc, char *argv[])
8928 FILE *fout, *fasm, *frlist;
8929 struct parsed_data *pd = NULL;
8931 char **rlist = NULL;
8933 int rlist_alloc = 0;
8934 int func_chunks_used = 0;
8935 int func_chunks_sorted = 0;
8936 int func_chunk_i = -1;
8937 long func_chunk_ret = 0;
8938 int func_chunk_ret_ln = 0;
8939 int scanned_ahead = 0;
8941 char words[20][256];
8942 enum opr_lenmod lmod;
8943 char *sctproto = NULL;
8945 int pending_endp = 0;
8947 int skip_code_end = 0;
8948 int skip_warned = 0;
8961 for (arg = 1; arg < argc; arg++) {
8962 if (IS(argv[arg], "-v"))
8964 else if (IS(argv[arg], "-rf"))
8965 g_allow_regfunc = 1;
8966 else if (IS(argv[arg], "-uc"))
8967 g_allow_user_icall = 1;
8968 else if (IS(argv[arg], "-m"))
8970 else if (IS(argv[arg], "-hdr"))
8971 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8976 if (argc < arg + 3) {
8977 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8978 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8980 " -hdr - header generation mode\n"
8981 " -rf - allow unannotated indirect calls\n"
8982 " -uc - allow ind. calls/refs to __usercall\n"
8983 " -m - allow multiple .text sections\n"
8984 "[rlist] is a file with function names to skip,"
8992 asmfn = argv[arg++];
8993 fasm = fopen(asmfn, "r");
8994 my_assert_not(fasm, NULL);
8996 hdrfn = argv[arg++];
8997 g_fhdr = fopen(hdrfn, "r");
8998 my_assert_not(g_fhdr, NULL);
9001 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9002 my_assert_not(rlist, NULL);
9003 // needs special handling..
9004 rlist[rlist_len++] = "__alloca_probe";
9006 func_chunk_alloc = 32;
9007 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9008 my_assert_not(func_chunks, NULL);
9010 memset(words, 0, sizeof(words));
9012 for (; arg < argc; arg++) {
9015 frlist = fopen(argv[arg], "r");
9016 my_assert_not(frlist, NULL);
9018 while (my_fgets(line, sizeof(line), frlist)) {
9020 if (*p == 0 || *p == ';')
9023 if (IS_START(p, "#if 0")
9024 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9028 else if (IS_START(p, "#endif"))
9035 p = next_word(words[0], sizeof(words[0]), p);
9036 if (words[0][0] == 0)
9039 if (rlist_len >= rlist_alloc) {
9040 rlist_alloc = rlist_alloc * 2 + 64;
9041 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9042 my_assert_not(rlist, NULL);
9044 rlist[rlist_len++] = strdup(words[0]);
9052 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9054 fout = fopen(argv[arg_out], "w");
9055 my_assert_not(fout, NULL);
9058 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9059 my_assert_not(g_eqs, NULL);
9061 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9062 g_label_refs[i].i = -1;
9063 g_label_refs[i].next = NULL;
9067 scan_variables(fasm, rlist, rlist_len);
9069 while (my_fgets(line, sizeof(line), fasm))
9078 // get rid of random tabs
9079 for (i = 0; line[i] != 0; i++)
9080 if (line[i] == '\t')
9085 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9086 goto do_pending_endp; // eww..
9088 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9090 static const char *attrs[] = {
9099 // parse IDA's attribute-list comment
9100 g_ida_func_attr = 0;
9103 for (; *p != 0; p = sskip(p)) {
9104 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9105 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9106 g_ida_func_attr |= 1 << i;
9107 p += strlen(attrs[i]);
9111 if (i == ARRAY_SIZE(attrs)) {
9112 anote("unparsed IDA attr: %s\n", p);
9115 if (IS(attrs[i], "fpd=")) {
9116 p = next_word(words[0], sizeof(words[0]), p);
9121 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9123 static const char *attrs[] = {
9128 // parse manual attribute-list comment
9129 g_sct_func_attr = 0;
9132 for (; *p != 0; p = sskip(p)) {
9133 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9134 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9135 g_sct_func_attr |= 1 << i;
9136 p += strlen(attrs[i]);
9143 // clear_sf=start,len (in dwords)
9144 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9145 &g_stack_clear_len, &j);
9147 // clear_regmask=<mask>
9148 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9150 anote("unparsed attr value: %s\n", p);
9155 else if (i == ARRAY_SIZE(attrs)) {
9156 anote("unparsed sct attr: %s\n", p);
9161 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9164 next_word(words[0], sizeof(words[0]), p);
9165 if (words[0][0] == 0)
9166 aerr("missing name for func chunk?\n");
9168 if (!scanned_ahead) {
9169 add_func_chunk(fasm, words[0], asmln);
9170 func_chunks_sorted = 0;
9173 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9175 if (func_chunk_i >= 0) {
9176 if (func_chunk_i < func_chunk_cnt
9177 && IS(func_chunks[func_chunk_i].name, g_func))
9179 // move on to next chunk
9180 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9182 aerr("seek failed for '%s' chunk #%d\n",
9183 g_func, func_chunk_i);
9184 asmln = func_chunks[func_chunk_i].asmln;
9188 if (func_chunk_ret == 0)
9189 aerr("no return from chunk?\n");
9190 fseek(fasm, func_chunk_ret, SEEK_SET);
9191 asmln = func_chunk_ret_ln;
9197 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9198 func_chunks_used = 1;
9200 if (IS_START(g_func, "sub_")) {
9201 unsigned long addr = strtoul(p, NULL, 16);
9202 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9203 if (addr > f_addr && !scanned_ahead) {
9204 //anote("scan_ahead caused by '%s', addr %lx\n",
9206 scan_ahead_for_chunks(fasm);
9208 func_chunks_sorted = 0;
9216 for (i = wordc; i < ARRAY_SIZE(words); i++)
9218 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9219 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9220 if (*p == 0 || *p == ';') {
9225 if (*p != 0 && *p != ';')
9226 aerr("too many words\n");
9228 if (skip_code_end) {
9233 // allow asm patches in comments
9235 if (IS_START(p, "; sctpatch:")) {
9237 if (*p == 0 || *p == ';')
9239 goto parse_words; // lame
9241 if (IS_START(p, "; sctproto:")) {
9242 sctproto = strdup(p + 11);
9244 else if (IS_START(p, "; sctend")) {
9249 else if (IS_START(p, "; sctskip_start")) {
9250 if (in_func && !g_skip_func) {
9252 ops[pi].op = OPP_ABORT;
9253 ops[pi].asmln = asmln;
9259 else if (IS_START(p, "; sctskip_end")) {
9267 awarn("wordc == 0?\n");
9271 // don't care about this:
9272 if (words[0][0] == '.'
9273 || IS(words[0], "include")
9274 || IS(words[0], "assume") || IS(words[1], "segment")
9275 || IS(words[0], "align"))
9281 // do delayed endp processing to collect switch jumptables
9283 if (in_func && !g_skip_func && !end && wordc >= 2
9284 && ((words[0][0] == 'd' && words[0][2] == 0)
9285 || (words[1][0] == 'd' && words[1][2] == 0)))
9288 if (words[1][0] == 'd' && words[1][2] == 0) {
9290 if (g_func_pd_cnt >= pd_alloc) {
9291 pd_alloc = pd_alloc * 2 + 16;
9292 g_func_pd = realloc(g_func_pd,
9293 sizeof(g_func_pd[0]) * pd_alloc);
9294 my_assert_not(g_func_pd, NULL);
9296 pd = &g_func_pd[g_func_pd_cnt];
9298 memset(pd, 0, sizeof(*pd));
9299 strcpy(pd->label, words[0]);
9300 pd->type = OPT_CONST;
9301 pd->lmod = lmod_from_directive(words[1]);
9307 anote("skipping alignment byte?\n");
9310 lmod = lmod_from_directive(words[0]);
9311 if (lmod != pd->lmod)
9312 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9315 if (pd->count_alloc < pd->count + wordc) {
9316 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9317 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9318 my_assert_not(pd->d, NULL);
9320 for (; i < wordc; i++) {
9321 if (IS(words[i], "offset")) {
9322 pd->type = OPT_OFFSET;
9325 p = strchr(words[i], ',');
9328 if (pd->type == OPT_OFFSET)
9329 pd->d[pd->count].u.label = strdup(words[i]);
9331 pd->d[pd->count].u.val = parse_number(words[i], 0);
9332 pd->d[pd->count].bt_i = -1;
9338 if (in_func && !g_skip_func) {
9340 gen_hdr(g_func, pi);
9342 gen_func(fout, g_fhdr, g_func, pi);
9347 g_ida_func_attr = 0;
9348 g_sct_func_attr = 0;
9349 g_stack_clear_start = 0;
9350 g_stack_clear_len = 0;
9356 func_chunks_used = 0;
9359 memset(&ops, 0, pi * sizeof(ops[0]));
9364 for (i = 0; i < g_func_pd_cnt; i++) {
9366 if (pd->type == OPT_OFFSET) {
9367 for (j = 0; j < pd->count; j++)
9368 free(pd->d[j].u.label);
9383 if (IS(words[1], "proc")) {
9385 aerr("proc '%s' while in_func '%s'?\n",
9388 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9390 strcpy(g_func, words[0]);
9391 set_label(0, words[0]);
9396 if (IS(words[1], "endp"))
9399 aerr("endp '%s' while not in_func?\n", words[0]);
9400 if (!IS(g_func, words[0]))
9401 aerr("endp '%s' while in_func '%s'?\n",
9404 aerr("endp '%s' while skipping code\n", words[0]);
9406 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9407 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
9413 if (!g_skip_func && func_chunks_used) {
9414 // start processing chunks
9415 struct chunk_item *ci, key = { g_func, 0 };
9417 func_chunk_ret = ftell(fasm);
9418 func_chunk_ret_ln = asmln;
9419 if (!func_chunks_sorted) {
9420 qsort(func_chunks, func_chunk_cnt,
9421 sizeof(func_chunks[0]), cmp_chunks);
9422 func_chunks_sorted = 1;
9424 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9425 sizeof(func_chunks[0]), cmp_chunks);
9427 aerr("'%s' needs chunks, but none found\n", g_func);
9428 func_chunk_i = ci - func_chunks;
9429 for (; func_chunk_i > 0; func_chunk_i--)
9430 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9433 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9435 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9436 asmln = func_chunks[func_chunk_i].asmln;
9444 if (wordc == 2 && IS(words[1], "ends")) {
9448 goto do_pending_endp;
9452 // scan for next text segment
9453 while (my_fgets(line, sizeof(line), fasm)) {
9456 if (*p == 0 || *p == ';')
9459 if (strstr(p, "segment para public 'CODE' use32"))
9466 p = strchr(words[0], ':');
9468 set_label(pi, words[0]);
9472 if (!in_func || g_skip_func || skip_code) {
9473 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9475 anote("skipping from '%s'\n", g_labels[pi]);
9479 g_labels[pi] = NULL;
9483 if (wordc > 1 && IS(words[1], "="))
9486 aerr("unhandled equ, wc=%d\n", wordc);
9487 if (g_eqcnt >= eq_alloc) {
9489 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9490 my_assert_not(g_eqs, NULL);
9493 len = strlen(words[0]);
9494 if (len > sizeof(g_eqs[0].name) - 1)
9495 aerr("equ name too long: %d\n", len);
9496 strcpy(g_eqs[g_eqcnt].name, words[0]);
9498 if (!IS(words[3], "ptr"))
9499 aerr("unhandled equ\n");
9500 if (IS(words[2], "dword"))
9501 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9502 else if (IS(words[2], "word"))
9503 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9504 else if (IS(words[2], "byte"))
9505 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9506 else if (IS(words[2], "qword"))
9507 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9509 aerr("bad lmod: '%s'\n", words[2]);
9511 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9516 if (pi >= ARRAY_SIZE(ops))
9517 aerr("too many ops\n");
9519 parse_op(&ops[pi], words, wordc);
9521 ops[pi].datap = sctproto;
9536 // vim:ts=2:shiftwidth=2:expandtab