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 (tmp_op->p_argpass != 0) {
7301 fprintf(fout, "a%d", tmp_op->p_argpass);
7303 else if (pp->arg[arg].is_saved) {
7304 ferr_assert(po, tmp_op->p_argnum > 0);
7305 fprintf(fout, "%s%s", cast,
7306 saved_arg_name(buf1, sizeof(buf1),
7307 tmp_op->p_arggrp, tmp_op->p_argnum));
7311 out_src_opr(buf1, sizeof(buf1),
7312 tmp_op, &tmp_op->operand[0], cast, 0));
7316 fprintf(fout, ");");
7318 if (strstr(pp->ret_type.name, "int64")) {
7319 fprintf(fout, "\n");
7320 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7321 fprintf(fout, "%seax = tmp64;", buf3);
7324 if (pp->is_unresolved) {
7325 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7327 strcat(g_comment, buf2);
7330 if (po->flags & OPF_TAIL) {
7332 if (i == opcnt - 1 || pp->is_noreturn)
7334 else if (IS(pp->ret_type.name, "void"))
7336 else if (!(regmask_ret & (1 << xAX)))
7338 // else already handled as 'return f()'
7341 fprintf(fout, "\n%sreturn;", buf3);
7342 strcat(g_comment, " ^ tailcall");
7345 strcat(g_comment, " tailcall");
7347 if ((regmask_ret & (1 << xAX))
7348 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7350 ferr(po, "int func -> void func tailcall?\n");
7353 if (pp->is_noreturn)
7354 strcat(g_comment, " noreturn");
7355 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7356 strcat(g_comment, " argframe");
7357 if (po->flags & OPF_CC)
7358 strcat(g_comment, " cond");
7360 if (po->flags & OPF_CC)
7361 fprintf(fout, "\n }");
7363 delayed_flag_op = NULL;
7364 last_arith_dst = NULL;
7368 if (g_func_pp->is_vararg)
7369 fprintf(fout, " va_end(ap);\n");
7370 if (g_func_pp->has_retreg) {
7371 for (arg = 0; arg < g_func_pp->argc; arg++)
7372 if (g_func_pp->arg[arg].type.is_retreg)
7373 fprintf(fout, " *r_%s = %s;\n",
7374 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7377 if (regmask_ret & mxST0) {
7378 fprintf(fout, " return %s;", float_st0);
7380 else if (!(regmask_ret & mxAX)) {
7381 if (i != opcnt - 1 || label_pending)
7382 fprintf(fout, " return;");
7384 else if (g_func_pp->ret_type.is_ptr) {
7385 fprintf(fout, " return (%s)eax;",
7386 g_func_pp->ret_type.name);
7388 else if (IS(g_func_pp->ret_type.name, "__int64"))
7389 fprintf(fout, " return ((u64)edx << 32) | eax;");
7391 fprintf(fout, " return eax;");
7393 last_arith_dst = NULL;
7394 delayed_flag_op = NULL;
7398 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7399 if (po->p_argnum != 0) {
7400 // special case - saved func arg
7401 fprintf(fout, " %s = %s;",
7402 saved_arg_name(buf2, sizeof(buf2),
7403 po->p_arggrp, po->p_argnum), buf1);
7406 else if (po->flags & OPF_RSAVE) {
7407 fprintf(fout, " s_%s = %s;", buf1, buf1);
7410 else if (po->flags & OPF_PPUSH) {
7412 ferr_assert(po, tmp_op != NULL);
7413 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7414 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7417 else if (g_func_pp->is_userstack) {
7418 fprintf(fout, " *(--esp) = %s;", buf1);
7421 if (!(g_ida_func_attr & IDAFA_NORETURN))
7422 ferr(po, "stray push encountered\n");
7427 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7428 if (po->flags & OPF_RSAVE) {
7429 fprintf(fout, " %s = s_%s;", buf1, buf1);
7432 else if (po->flags & OPF_PPUSH) {
7433 // push/pop graph / non-const
7434 ferr_assert(po, po->datap == NULL);
7435 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7438 else if (po->datap != NULL) {
7441 fprintf(fout, " %s = %s;", buf1,
7442 out_src_opr(buf2, sizeof(buf2),
7443 tmp_op, &tmp_op->operand[0],
7444 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7447 else if (g_func_pp->is_userstack) {
7448 fprintf(fout, " %s = *esp++;", buf1);
7452 ferr(po, "stray pop encountered\n");
7462 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7463 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7464 po->op == OPP_ALLSHL ? "<<" : ">>");
7465 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7466 strcat(g_comment, po->op == OPP_ALLSHL
7467 ? " allshl" : " allshr");
7472 if (need_float_stack) {
7473 out_src_opr_float(buf1, sizeof(buf1),
7474 po, &po->operand[0], 1);
7475 if (po->regmask_src & mxSTa) {
7476 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7480 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7483 if (po->flags & OPF_FSHIFT)
7484 fprintf(fout, " f_st1 = f_st0;");
7485 if (po->operand[0].type == OPT_REG
7486 && po->operand[0].reg == xST0)
7488 strcat(g_comment, " fld st");
7491 fprintf(fout, " f_st0 = %s;",
7492 out_src_opr_float(buf1, sizeof(buf1),
7493 po, &po->operand[0], 0));
7495 strcat(g_comment, " fld");
7499 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7500 lmod_cast(po, po->operand[0].lmod, 1), 0);
7501 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7502 if (need_float_stack) {
7503 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7506 if (po->flags & OPF_FSHIFT)
7507 fprintf(fout, " f_st1 = f_st0;");
7508 fprintf(fout, " f_st0 = %s;", buf2);
7510 strcat(g_comment, " fild");
7514 if (need_float_stack)
7515 fprintf(fout, " f_st[--f_stp & 7] = ");
7517 if (po->flags & OPF_FSHIFT)
7518 fprintf(fout, " f_st1 = f_st0;");
7519 fprintf(fout, " f_st0 = ");
7521 switch (po->operand[0].val) {
7522 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7523 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
7524 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7525 default: ferr(po, "TODO\n"); break;
7530 if (po->flags & OPF_FARG) {
7531 // store to stack as func arg
7532 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7536 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7538 dead_dst = po->operand[0].type == OPT_REG
7539 && po->operand[0].reg == xST0;
7542 fprintf(fout, " %s = %s;", buf1, float_st0);
7543 if (po->flags & OPF_FSHIFT) {
7544 if (need_float_stack)
7545 fprintf(fout, " f_stp++;");
7547 fprintf(fout, " f_st0 = f_st1;");
7549 if (dead_dst && !(po->flags & OPF_FSHIFT))
7552 strcat(g_comment, " fst");
7556 fprintf(fout, " %s = %s%s;",
7557 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7558 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7559 if (po->flags & OPF_FSHIFT) {
7560 if (need_float_stack)
7561 fprintf(fout, " f_stp++;");
7563 fprintf(fout, " f_st0 = f_st1;");
7565 strcat(g_comment, " fist");
7572 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7574 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7576 dead_dst = (po->flags & OPF_FPOP)
7577 && po->operand[0].type == OPT_REG
7578 && po->operand[0].reg == xST0;
7580 case OP_FADD: j = '+'; break;
7581 case OP_FDIV: j = '/'; break;
7582 case OP_FMUL: j = '*'; break;
7583 case OP_FSUB: j = '-'; break;
7584 default: j = 'x'; break;
7586 if (need_float_stack) {
7588 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7589 if (po->flags & OPF_FSHIFT)
7590 fprintf(fout, " f_stp++;");
7593 if (po->flags & OPF_FSHIFT) {
7594 // note: assumes only 2 regs handled
7596 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7598 fprintf(fout, " f_st0 = f_st1;");
7601 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7603 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7608 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7610 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7612 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7614 dead_dst = (po->flags & OPF_FPOP)
7615 && po->operand[0].type == OPT_REG
7616 && po->operand[0].reg == xST0;
7617 j = po->op == OP_FDIVR ? '/' : '-';
7618 if (need_float_stack) {
7620 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7621 if (po->flags & OPF_FSHIFT)
7622 fprintf(fout, " f_stp++;");
7625 if (po->flags & OPF_FSHIFT) {
7627 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7629 fprintf(fout, " f_st0 = f_st1;");
7632 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7634 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7642 case OP_FIADD: j = '+'; break;
7643 case OP_FIDIV: j = '/'; break;
7644 case OP_FIMUL: j = '*'; break;
7645 case OP_FISUB: j = '-'; break;
7646 default: j = 'x'; break;
7648 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7650 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7651 lmod_cast(po, po->operand[0].lmod, 1), 0));
7656 fprintf(fout, " %s = %s %c %s;", float_st0,
7657 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7659 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7664 ferr_assert(po, po->datap != NULL);
7665 mask = (long)po->datap & 0xffff;
7666 z_check = ((long)po->datap >> 16) & 1;
7667 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7669 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
7670 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7673 else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
7674 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7677 else if (mask == 0x4100) { // C3, C0
7679 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7681 strcat(g_comment, " z_chk_det");
7684 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7685 "(%s < %s ? 0x0100 : 0);",
7686 float_st0, buf1, float_st0, buf1);
7690 ferr(po, "unhandled sw mask: %x\n", mask);
7691 if (po->flags & OPF_FSHIFT) {
7692 if (need_float_stack) {
7693 if (po->flags & OPF_FPOPP)
7694 fprintf(fout, " f_stp += 2;");
7696 fprintf(fout, " f_stp++;");
7699 ferr_assert(po, !(po->flags & OPF_FPOPP));
7700 fprintf(fout, " f_st0 = f_st1;");
7707 fprintf(fout, " %s = f_sw;",
7708 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7712 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7716 fprintf(fout, " %s = cos%s(%s);", float_st0,
7717 need_double ? "" : "f", float_st0);
7721 if (need_float_stack) {
7722 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7723 need_double ? "" : "f", float_st1, float_st0);
7724 fprintf(fout, " f_stp++;");
7727 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7728 need_double ? "" : "f");
7733 if (need_float_stack) {
7734 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7735 float_st1, need_double ? "" : "f", float_st0);
7736 fprintf(fout, " f_stp++;");
7739 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7740 need_double ? "" : "f");
7742 strcat(g_comment, " fyl2x");
7746 fprintf(fout, " %s = sin%s(%s);", float_st0,
7747 need_double ? "" : "f", float_st0);
7751 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7752 need_double ? "" : "f", float_st0);
7756 dead_dst = po->operand[0].type == OPT_REG
7757 && po->operand[0].reg == xST0;
7759 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7761 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7762 float_st0, float_st0, buf1, buf1);
7763 strcat(g_comment, " fxch");
7770 ferr_assert(po, po->flags & OPF_32BIT);
7771 fprintf(fout, " eax = (s32)%s;", float_st0);
7772 if (po->flags & OPF_FSHIFT) {
7773 if (need_float_stack)
7774 fprintf(fout, " f_stp++;");
7776 fprintf(fout, " f_st0 = f_st1;");
7778 strcat(g_comment, " ftol");
7782 if (need_float_stack) {
7783 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
7784 need_double ? "" : "f", float_st1, float_st0);
7785 fprintf(fout, " f_stp++;");
7788 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
7789 need_double ? "" : "f");
7791 strcat(g_comment, " CIpow");
7795 fprintf(fout, " do_skip_code_abort();");
7800 fprintf(fout, " do_emms();");
7805 ferr(po, "unhandled op type %d, flags %x\n",
7810 if (g_comment[0] != 0) {
7811 char *p = g_comment;
7812 while (my_isblank(*p))
7814 fprintf(fout, " // %s", p);
7819 fprintf(fout, "\n");
7821 // some sanity checking
7822 if (po->flags & OPF_REP) {
7823 if (po->op != OP_STOS && po->op != OP_MOVS
7824 && po->op != OP_CMPS && po->op != OP_SCAS)
7825 ferr(po, "unexpected rep\n");
7826 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7827 && (po->op == OP_CMPS || po->op == OP_SCAS))
7828 ferr(po, "cmps/scas with plain rep\n");
7830 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7831 && po->op != OP_CMPS && po->op != OP_SCAS)
7832 ferr(po, "unexpected repz/repnz\n");
7835 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
7837 // see is delayed flag stuff is still valid
7838 if (delayed_flag_op != NULL && delayed_flag_op != po) {
7839 if (is_any_opr_modified(delayed_flag_op, po, 0))
7840 delayed_flag_op = NULL;
7843 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7844 if (is_opr_modified(last_arith_dst, po))
7845 last_arith_dst = NULL;
7852 if (g_stack_fsz && !g_stack_frame_used)
7853 fprintf(fout, " (void)sf;\n");
7855 fprintf(fout, "}\n\n");
7857 gen_x_cleanup(opcnt);
7860 static void gen_x_cleanup(int opcnt)
7864 for (i = 0; i < opcnt; i++) {
7865 struct label_ref *lr, *lr_del;
7867 lr = g_label_refs[i].next;
7868 while (lr != NULL) {
7873 g_label_refs[i].i = -1;
7874 g_label_refs[i].next = NULL;
7876 if (ops[i].op == OP_CALL) {
7878 proto_release(ops[i].pp);
7884 struct func_proto_dep;
7886 struct func_prototype {
7891 int has_ret:3; // -1, 0, 1: unresolved, no, yes
7892 unsigned int dep_resolved:1;
7893 unsigned int is_stdcall:1;
7894 struct func_proto_dep *dep_func;
7896 const struct parsed_proto *pp; // seed pp, if any
7899 struct func_proto_dep {
7901 struct func_prototype *proto;
7902 int regmask_live; // .. at the time of call
7903 unsigned int ret_dep:1; // return from this is caller's return
7906 static struct func_prototype *hg_fp;
7907 static int hg_fp_cnt;
7909 static struct scanned_var {
7911 enum opr_lenmod lmod;
7912 unsigned int is_seeded:1;
7913 unsigned int is_c_str:1;
7914 const struct parsed_proto *pp; // seed pp, if any
7916 static int hg_var_cnt;
7918 static char **hg_refs;
7919 static int hg_ref_cnt;
7921 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7924 static struct func_prototype *hg_fp_add(const char *funcn)
7926 struct func_prototype *fp;
7928 if ((hg_fp_cnt & 0xff) == 0) {
7929 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7930 my_assert_not(hg_fp, NULL);
7931 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7934 fp = &hg_fp[hg_fp_cnt];
7935 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7937 fp->argc_stack = -1;
7943 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7948 for (i = 0; i < fp->dep_func_cnt; i++)
7949 if (IS(fp->dep_func[i].name, name))
7950 return &fp->dep_func[i];
7955 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7958 if (hg_fp_find_dep(fp, name))
7961 if ((fp->dep_func_cnt & 0xff) == 0) {
7962 fp->dep_func = realloc(fp->dep_func,
7963 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7964 my_assert_not(fp->dep_func, NULL);
7965 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7966 sizeof(fp->dep_func[0]) * 0x100);
7968 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7972 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7974 const struct func_prototype *p1 = p1_, *p2 = p2_;
7975 return strcmp(p1->name, p2->name);
7979 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7981 const struct func_prototype *p1 = p1_, *p2 = p2_;
7982 return p1->id - p2->id;
7986 static void hg_ref_add(const char *name)
7988 if ((hg_ref_cnt & 0xff) == 0) {
7989 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7990 my_assert_not(hg_refs, NULL);
7991 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7994 hg_refs[hg_ref_cnt] = strdup(name);
7995 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7999 // recursive register dep pass
8000 // - track saved regs (part 2)
8001 // - try to figure out arg-regs
8002 // - calculate reg deps
8003 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8004 struct func_prototype *fp, int regmask_save, int regmask_dst,
8005 int *regmask_dep, int *has_ret)
8007 struct func_proto_dep *dep;
8008 struct parsed_op *po;
8009 int from_caller = 0;
8014 for (; i < opcnt; i++)
8016 if (cbits[i >> 3] & (1 << (i & 7)))
8018 cbits[i >> 3] |= (1 << (i & 7));
8022 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8023 if (po->flags & OPF_RMD)
8026 if (po->btj != NULL) {
8028 for (j = 0; j < po->btj->count; j++) {
8029 check_i(po, po->btj->d[j].bt_i);
8030 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8031 regmask_save, regmask_dst, regmask_dep, has_ret);
8036 check_i(po, po->bt_i);
8037 if (po->flags & OPF_CJMP) {
8038 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8039 regmask_save, regmask_dst, regmask_dep, has_ret);
8047 if (po->flags & OPF_FARG)
8048 /* (just calculate register deps) */;
8049 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8051 reg = po->operand[0].reg;
8052 ferr_assert(po, reg >= 0);
8054 if (po->flags & OPF_RSAVE) {
8055 regmask_save |= 1 << reg;
8058 if (po->flags & OPF_DONE)
8061 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
8063 regmask_save |= 1 << reg;
8064 po->flags |= OPF_RMD;
8065 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
8069 else if (po->flags & OPF_RMD)
8071 else if (po->op == OP_CALL) {
8072 po->regmask_dst |= 1 << xAX;
8074 dep = hg_fp_find_dep(fp, po->operand[0].name);
8076 dep->regmask_live = regmask_save | regmask_dst;
8077 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8078 dep->regmask_live |= 1 << xBP;
8081 else if (po->op == OP_RET) {
8082 if (po->operand_cnt > 0) {
8084 if (fp->argc_stack >= 0
8085 && fp->argc_stack != po->operand[0].val / 4)
8086 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8087 fp->argc_stack = po->operand[0].val / 4;
8091 // if has_ret is 0, there is uninitialized eax path,
8092 // which means it's most likely void func
8093 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
8094 if (po->op == OP_CALL) {
8099 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
8102 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
8105 if (ret != 1 && from_caller) {
8106 // unresolved eax - probably void func
8110 if (j >= 0 && ops[j].op == OP_CALL) {
8111 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8122 l = regmask_save | regmask_dst;
8123 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8126 l = po->regmask_src & ~l;
8129 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8130 l, regmask_dst, regmask_save, po->flags);
8133 regmask_dst |= po->regmask_dst;
8135 if (po->flags & OPF_TAIL)
8140 static void gen_hdr(const char *funcn, int opcnt)
8142 unsigned char cbits[MAX_OPS / 8];
8143 const struct parsed_proto *pp_c;
8144 struct parsed_proto *pp;
8145 struct func_prototype *fp;
8146 struct parsed_op *po;
8147 int regmask_dummy = 0;
8149 int max_bp_offset = 0;
8154 pp_c = proto_parse(g_fhdr, funcn, 1);
8156 // already in seed, will add to hg_fp later
8159 fp = hg_fp_add(funcn);
8161 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8162 g_stack_frame_used = 0;
8166 // - resolve all branches
8167 // - parse calls with labels
8168 resolve_branches_parse_calls(opcnt);
8171 // - handle ebp/esp frame, remove ops related to it
8172 scan_prologue_epilogue(opcnt, NULL);
8175 // - remove dead labels
8177 for (i = 0; i < opcnt; i++)
8179 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8185 if (po->flags & (OPF_RMD|OPF_DONE))
8188 if (po->op == OP_CALL) {
8189 if (po->operand[0].type == OPT_LABEL)
8190 hg_fp_add_dep(fp, opr_name(po, 0));
8191 else if (po->pp != NULL)
8192 hg_fp_add_dep(fp, po->pp->name);
8197 // - remove dead labels
8198 // - handle push <const>/pop pairs
8199 for (i = 0; i < opcnt; i++)
8201 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8207 if (po->flags & (OPF_RMD|OPF_DONE))
8210 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8211 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8215 // - process trivial calls
8216 for (i = 0; i < opcnt; i++)
8219 if (po->flags & (OPF_RMD|OPF_DONE))
8222 if (po->op == OP_CALL)
8224 pp = process_call_early(i, opcnt, &j);
8226 if (!(po->flags & OPF_ATAIL))
8227 // since we know the args, try to collect them
8228 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8234 // commit esp adjust
8235 if (ops[j].op != OP_POP)
8236 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8238 for (l = 0; l < pp->argc_stack; l++)
8239 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8243 po->flags |= OPF_DONE;
8249 // - track saved regs (simple)
8251 for (i = 0; i < opcnt; i++)
8254 if (po->flags & (OPF_RMD|OPF_DONE))
8257 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8258 && po->operand[0].reg != xCX)
8260 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8262 // regmask_save |= 1 << po->operand[0].reg; // do it later
8263 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8264 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8267 else if (po->op == OP_CALL)
8269 pp = process_call(i, opcnt);
8271 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8272 // since we know the args, collect them
8273 ret = collect_call_args(po, i, pp, ®mask_dummy,
8280 memset(cbits, 0, sizeof(cbits));
8284 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
8286 // find unreachable code - must be fixed in IDA
8287 for (i = 0; i < opcnt; i++)
8289 if (cbits[i >> 3] & (1 << (i & 7)))
8292 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8293 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8295 // the compiler sometimes still generates code after
8296 // noreturn OS functions
8299 if (ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8300 ferr(&ops[i], "unreachable code\n");
8303 for (i = 0; i < g_eqcnt; i++) {
8304 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8305 max_bp_offset = g_eqs[i].offset;
8308 if (fp->argc_stack < 0) {
8309 max_bp_offset = (max_bp_offset + 3) & ~3;
8310 fp->argc_stack = max_bp_offset / 4;
8311 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8315 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8316 fp->has_ret = has_ret;
8318 printf("// has_ret %d, regmask_dep %x\n",
8319 fp->has_ret, fp->regmask_dep);
8320 output_hdr_fp(stdout, fp, 1);
8321 if (IS(funcn, "sub_10007F72")) exit(1);
8324 gen_x_cleanup(opcnt);
8327 static void hg_fp_resolve_deps(struct func_prototype *fp)
8329 struct func_prototype fp_s;
8333 // this thing is recursive, so mark first..
8334 fp->dep_resolved = 1;
8336 for (i = 0; i < fp->dep_func_cnt; i++) {
8337 strcpy(fp_s.name, fp->dep_func[i].name);
8338 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8339 sizeof(hg_fp[0]), hg_fp_cmp_name);
8340 if (fp->dep_func[i].proto != NULL) {
8341 if (!fp->dep_func[i].proto->dep_resolved)
8342 hg_fp_resolve_deps(fp->dep_func[i].proto);
8344 dep = ~fp->dep_func[i].regmask_live
8345 & fp->dep_func[i].proto->regmask_dep;
8346 fp->regmask_dep |= dep;
8347 // printf("dep %s %s |= %x\n", fp->name,
8348 // fp->dep_func[i].name, dep);
8350 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8351 fp->has_ret = fp->dep_func[i].proto->has_ret;
8356 // make all thiscall/edx arg functions referenced from .data fastcall
8357 static void do_func_refs_from_data(void)
8359 struct func_prototype *fp, fp_s;
8362 for (i = 0; i < hg_ref_cnt; i++) {
8363 strcpy(fp_s.name, hg_refs[i]);
8364 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8365 sizeof(hg_fp[0]), hg_fp_cmp_name);
8369 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8370 fp->regmask_dep |= mxCX | mxDX;
8374 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8377 const struct parsed_proto *pp;
8378 char *p, namebuf[NAMELEN];
8384 for (; count > 0; count--, fp++) {
8385 if (fp->has_ret == -1)
8386 fprintf(fout, "// ret unresolved\n");
8388 fprintf(fout, "// dep:");
8389 for (j = 0; j < fp->dep_func_cnt; j++) {
8390 fprintf(fout, " %s/", fp->dep_func[j].name);
8391 if (fp->dep_func[j].proto != NULL)
8392 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8393 fp->dep_func[j].proto->has_ret);
8395 fprintf(fout, "\n");
8398 p = strchr(fp->name, '@');
8400 memcpy(namebuf, fp->name, p - fp->name);
8401 namebuf[p - fp->name] = 0;
8409 pp = proto_parse(g_fhdr, name, 1);
8410 if (pp != NULL && pp->is_include)
8413 if (fp->pp != NULL) {
8414 // part of seed, output later
8418 regmask_dep = fp->regmask_dep;
8419 argc_normal = fp->argc_stack;
8421 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8422 (fp->has_ret ? "int" : "void"));
8423 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8424 && (regmask_dep & ~mxCX) == 0)
8426 fprintf(fout, "/*__thiscall*/ ");
8430 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8431 && (regmask_dep & ~(mxCX | mxDX)) == 0)
8433 fprintf(fout, " __fastcall ");
8434 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8440 else if (regmask_dep && !fp->is_stdcall) {
8441 fprintf(fout, "/*__usercall*/ ");
8443 else if (regmask_dep) {
8444 fprintf(fout, "/*__userpurge*/ ");
8446 else if (fp->is_stdcall)
8447 fprintf(fout, " __stdcall ");
8449 fprintf(fout, " __cdecl ");
8451 fprintf(fout, "%s(", name);
8454 for (j = 0; j < xSP; j++) {
8455 if (regmask_dep & (1 << j)) {
8458 fprintf(fout, ", ");
8460 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8462 fprintf(fout, "int");
8463 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8467 for (j = 0; j < argc_normal; j++) {
8470 fprintf(fout, ", ");
8471 if (fp->pp != NULL) {
8472 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8473 if (!fp->pp->arg[arg - 1].type.is_ptr)
8477 fprintf(fout, "int ");
8478 fprintf(fout, "a%d", arg);
8481 fprintf(fout, ");\n");
8485 static void output_hdr(FILE *fout)
8487 static const char *lmod_c_names[] = {
8488 [OPLM_UNSPEC] = "???",
8489 [OPLM_BYTE] = "uint8_t",
8490 [OPLM_WORD] = "uint16_t",
8491 [OPLM_DWORD] = "uint32_t",
8492 [OPLM_QWORD] = "uint64_t",
8494 const struct scanned_var *var;
8495 struct func_prototype *fp;
8496 char line[256] = { 0, };
8500 // add stuff from headers
8501 for (i = 0; i < pp_cache_size; i++) {
8502 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8503 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8505 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8506 fp = hg_fp_add(name);
8507 fp->pp = &pp_cache[i];
8508 fp->argc_stack = fp->pp->argc_stack;
8509 fp->is_stdcall = fp->pp->is_stdcall;
8510 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8511 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8515 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8516 for (i = 0; i < hg_fp_cnt; i++)
8517 hg_fp_resolve_deps(&hg_fp[i]);
8519 // adjust functions referenced from data segment
8520 do_func_refs_from_data();
8522 // note: messes up .proto ptr, don't use
8523 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8526 for (i = 0; i < hg_var_cnt; i++) {
8529 if (var->pp != NULL)
8532 else if (var->is_c_str)
8533 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8535 fprintf(fout, "extern %-8s %s;",
8536 lmod_c_names[var->lmod], var->name);
8539 fprintf(fout, " // seeded");
8540 fprintf(fout, "\n");
8543 fprintf(fout, "\n");
8545 // output function prototypes
8546 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8549 fprintf(fout, "\n// - seed -\n");
8552 while (fgets(line, sizeof(line), g_fhdr))
8553 fwrite(line, 1, strlen(line), fout);
8556 // '=' needs special treatment
8558 static char *next_word_s(char *w, size_t wsize, char *s)
8565 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8567 for (i = 1; i < wsize - 1; i++) {
8569 printf("warning: missing closing quote: \"%s\"\n", s);
8578 for (; i < wsize - 1; i++) {
8579 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8585 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8586 printf("warning: '%s' truncated\n", w);
8591 static int cmpstringp(const void *p1, const void *p2)
8593 return strcmp(*(char * const *)p1, *(char * const *)p2);
8596 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8601 if (strstr(p, "..."))
8602 // unable to determine, assume needed
8605 if (*p == '.') // .text, .data, ...
8606 // ref from other data or non-function -> no
8609 p2 = strpbrk(p, "+:\r\n\x18");
8612 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8613 // referenced from removed code
8619 static int ida_xrefs_show_need(FILE *fasm, char *p,
8620 char **rlist, int rlist_len)
8626 p = strrchr(p, ';');
8627 if (p != NULL && *p == ';') {
8628 if (IS_START(p + 2, "sctref"))
8630 if (IS_START(p + 2, "DATA XREF: ")) {
8632 if (is_xref_needed(p, rlist, rlist_len))
8640 if (!my_fgets(line, sizeof(line), fasm))
8642 // non-first line is always indented
8643 if (!my_isblank(line[0]))
8646 // should be no content, just comment
8651 p = strrchr(p, ';');
8654 if (IS_START(p, "sctref")) {
8659 // it's printed once, but no harm to check again
8660 if (IS_START(p, "DATA XREF: "))
8663 if (is_xref_needed(p, rlist, rlist_len)) {
8668 fseek(fasm, pos, SEEK_SET);
8672 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8674 struct scanned_var *var;
8675 char line[256] = { 0, };
8684 // skip to next data section
8685 while (my_fgets(line, sizeof(line), fasm))
8690 if (*p == 0 || *p == ';')
8693 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8694 if (*p == 0 || *p == ';')
8697 if (*p != 's' || !IS_START(p, "segment para public"))
8703 if (p == NULL || !IS_START(p, "segment para public"))
8707 if (!IS_START(p, "'DATA'"))
8711 while (my_fgets(line, sizeof(line), fasm))
8716 no_identifier = my_isblank(*p);
8719 if (*p == 0 || *p == ';')
8722 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8723 words[wordc][0] = 0;
8724 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8725 if (*p == 0 || *p == ';') {
8731 if (wordc == 2 && IS(words[1], "ends"))
8736 if (no_identifier) {
8737 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8738 hg_ref_add(words[2]);
8742 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8743 // when this starts, we don't need anything from this section
8747 // check refs comment(s)
8748 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8751 if ((hg_var_cnt & 0xff) == 0) {
8752 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8753 * (hg_var_cnt + 0x100));
8754 my_assert_not(hg_vars, NULL);
8755 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8758 var = &hg_vars[hg_var_cnt++];
8759 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8761 // maybe already in seed header?
8762 var->pp = proto_parse(g_fhdr, var->name, 1);
8763 if (var->pp != NULL) {
8764 if (var->pp->is_fptr) {
8765 var->lmod = OPLM_DWORD;
8768 else if (var->pp->is_func)
8770 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8771 aerr("unhandled C type '%s' for '%s'\n",
8772 var->pp->type.name, var->name);
8778 if (IS(words[1], "dd")) {
8779 var->lmod = OPLM_DWORD;
8780 if (wordc >= 4 && IS(words[2], "offset"))
8781 hg_ref_add(words[3]);
8783 else if (IS(words[1], "dw"))
8784 var->lmod = OPLM_WORD;
8785 else if (IS(words[1], "db")) {
8786 var->lmod = OPLM_BYTE;
8787 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8788 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8792 else if (IS(words[1], "dq"))
8793 var->lmod = OPLM_QWORD;
8794 //else if (IS(words[1], "dt"))
8796 aerr("type '%s' not known\n", words[1]);
8804 static void set_label(int i, const char *name)
8810 p = strchr(name, ':');
8814 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8815 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8816 g_labels[i] = realloc(g_labels[i], len + 1);
8817 my_assert_not(g_labels[i], NULL);
8818 memcpy(g_labels[i], name, len);
8819 g_labels[i][len] = 0;
8828 static struct chunk_item *func_chunks;
8829 static int func_chunk_cnt;
8830 static int func_chunk_alloc;
8832 static void add_func_chunk(FILE *fasm, const char *name, int line)
8834 if (func_chunk_cnt >= func_chunk_alloc) {
8835 func_chunk_alloc *= 2;
8836 func_chunks = realloc(func_chunks,
8837 func_chunk_alloc * sizeof(func_chunks[0]));
8838 my_assert_not(func_chunks, NULL);
8840 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8841 func_chunks[func_chunk_cnt].name = strdup(name);
8842 func_chunks[func_chunk_cnt].asmln = line;
8846 static int cmp_chunks(const void *p1, const void *p2)
8848 const struct chunk_item *c1 = p1, *c2 = p2;
8849 return strcmp(c1->name, c2->name);
8852 static void scan_ahead_for_chunks(FILE *fasm)
8862 oldpos = ftell(fasm);
8865 while (my_fgets(line, sizeof(line), fasm))
8876 // get rid of random tabs
8877 for (i = 0; line[i] != 0; i++)
8878 if (line[i] == '\t')
8881 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8884 next_word(words[0], sizeof(words[0]), p);
8885 if (words[0][0] == 0)
8886 aerr("missing name for func chunk?\n");
8888 add_func_chunk(fasm, words[0], asmln);
8890 else if (IS_START(p, "; sctend"))
8896 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8897 words[wordc][0] = 0;
8898 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8899 if (*p == 0 || *p == ';') {
8905 if (wordc == 2 && IS(words[1], "ends"))
8909 fseek(fasm, oldpos, SEEK_SET);
8913 int main(int argc, char *argv[])
8915 FILE *fout, *fasm, *frlist;
8916 struct parsed_data *pd = NULL;
8918 char **rlist = NULL;
8920 int rlist_alloc = 0;
8921 int func_chunks_used = 0;
8922 int func_chunks_sorted = 0;
8923 int func_chunk_i = -1;
8924 long func_chunk_ret = 0;
8925 int func_chunk_ret_ln = 0;
8926 int scanned_ahead = 0;
8928 char words[20][256];
8929 enum opr_lenmod lmod;
8930 char *sctproto = NULL;
8932 int pending_endp = 0;
8934 int skip_code_end = 0;
8935 int skip_warned = 0;
8948 for (arg = 1; arg < argc; arg++) {
8949 if (IS(argv[arg], "-v"))
8951 else if (IS(argv[arg], "-rf"))
8952 g_allow_regfunc = 1;
8953 else if (IS(argv[arg], "-uc"))
8954 g_allow_user_icall = 1;
8955 else if (IS(argv[arg], "-m"))
8957 else if (IS(argv[arg], "-hdr"))
8958 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8963 if (argc < arg + 3) {
8964 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8965 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8967 " -hdr - header generation mode\n"
8968 " -rf - allow unannotated indirect calls\n"
8969 " -uc - allow ind. calls/refs to __usercall\n"
8970 " -m - allow multiple .text sections\n"
8971 "[rlist] is a file with function names to skip,"
8979 asmfn = argv[arg++];
8980 fasm = fopen(asmfn, "r");
8981 my_assert_not(fasm, NULL);
8983 hdrfn = argv[arg++];
8984 g_fhdr = fopen(hdrfn, "r");
8985 my_assert_not(g_fhdr, NULL);
8988 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8989 my_assert_not(rlist, NULL);
8990 // needs special handling..
8991 rlist[rlist_len++] = "__alloca_probe";
8993 func_chunk_alloc = 32;
8994 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8995 my_assert_not(func_chunks, NULL);
8997 memset(words, 0, sizeof(words));
8999 for (; arg < argc; arg++) {
9002 frlist = fopen(argv[arg], "r");
9003 my_assert_not(frlist, NULL);
9005 while (my_fgets(line, sizeof(line), frlist)) {
9007 if (*p == 0 || *p == ';')
9010 if (IS_START(p, "#if 0")
9011 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9015 else if (IS_START(p, "#endif"))
9022 p = next_word(words[0], sizeof(words[0]), p);
9023 if (words[0][0] == 0)
9026 if (rlist_len >= rlist_alloc) {
9027 rlist_alloc = rlist_alloc * 2 + 64;
9028 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9029 my_assert_not(rlist, NULL);
9031 rlist[rlist_len++] = strdup(words[0]);
9039 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9041 fout = fopen(argv[arg_out], "w");
9042 my_assert_not(fout, NULL);
9045 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9046 my_assert_not(g_eqs, NULL);
9048 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9049 g_label_refs[i].i = -1;
9050 g_label_refs[i].next = NULL;
9054 scan_variables(fasm, rlist, rlist_len);
9056 while (my_fgets(line, sizeof(line), fasm))
9065 // get rid of random tabs
9066 for (i = 0; line[i] != 0; i++)
9067 if (line[i] == '\t')
9072 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9073 goto do_pending_endp; // eww..
9075 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9077 static const char *attrs[] = {
9086 // parse IDA's attribute-list comment
9087 g_ida_func_attr = 0;
9090 for (; *p != 0; p = sskip(p)) {
9091 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9092 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9093 g_ida_func_attr |= 1 << i;
9094 p += strlen(attrs[i]);
9098 if (i == ARRAY_SIZE(attrs)) {
9099 anote("unparsed IDA attr: %s\n", p);
9102 if (IS(attrs[i], "fpd=")) {
9103 p = next_word(words[0], sizeof(words[0]), p);
9108 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9110 static const char *attrs[] = {
9115 // parse manual attribute-list comment
9116 g_sct_func_attr = 0;
9119 for (; *p != 0; p = sskip(p)) {
9120 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9121 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9122 g_sct_func_attr |= 1 << i;
9123 p += strlen(attrs[i]);
9130 // clear_sf=start,len (in dwords)
9131 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9132 &g_stack_clear_len, &j);
9134 // clear_regmask=<mask>
9135 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9137 anote("unparsed attr value: %s\n", p);
9142 else if (i == ARRAY_SIZE(attrs)) {
9143 anote("unparsed sct attr: %s\n", p);
9148 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9151 next_word(words[0], sizeof(words[0]), p);
9152 if (words[0][0] == 0)
9153 aerr("missing name for func chunk?\n");
9155 if (!scanned_ahead) {
9156 add_func_chunk(fasm, words[0], asmln);
9157 func_chunks_sorted = 0;
9160 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9162 if (func_chunk_i >= 0) {
9163 if (func_chunk_i < func_chunk_cnt
9164 && IS(func_chunks[func_chunk_i].name, g_func))
9166 // move on to next chunk
9167 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9169 aerr("seek failed for '%s' chunk #%d\n",
9170 g_func, func_chunk_i);
9171 asmln = func_chunks[func_chunk_i].asmln;
9175 if (func_chunk_ret == 0)
9176 aerr("no return from chunk?\n");
9177 fseek(fasm, func_chunk_ret, SEEK_SET);
9178 asmln = func_chunk_ret_ln;
9184 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9185 func_chunks_used = 1;
9187 if (IS_START(g_func, "sub_")) {
9188 unsigned long addr = strtoul(p, NULL, 16);
9189 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9190 if (addr > f_addr && !scanned_ahead) {
9191 //anote("scan_ahead caused by '%s', addr %lx\n",
9193 scan_ahead_for_chunks(fasm);
9195 func_chunks_sorted = 0;
9203 for (i = wordc; i < ARRAY_SIZE(words); i++)
9205 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9206 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9207 if (*p == 0 || *p == ';') {
9212 if (*p != 0 && *p != ';')
9213 aerr("too many words\n");
9215 if (skip_code_end) {
9220 // allow asm patches in comments
9222 if (IS_START(p, "; sctpatch:")) {
9224 if (*p == 0 || *p == ';')
9226 goto parse_words; // lame
9228 if (IS_START(p, "; sctproto:")) {
9229 sctproto = strdup(p + 11);
9231 else if (IS_START(p, "; sctend")) {
9236 else if (IS_START(p, "; sctskip_start")) {
9237 if (in_func && !g_skip_func) {
9239 ops[pi].op = OPP_ABORT;
9240 ops[pi].asmln = asmln;
9246 else if (IS_START(p, "; sctskip_end")) {
9254 awarn("wordc == 0?\n");
9258 // don't care about this:
9259 if (words[0][0] == '.'
9260 || IS(words[0], "include")
9261 || IS(words[0], "assume") || IS(words[1], "segment")
9262 || IS(words[0], "align"))
9268 // do delayed endp processing to collect switch jumptables
9270 if (in_func && !g_skip_func && !end && wordc >= 2
9271 && ((words[0][0] == 'd' && words[0][2] == 0)
9272 || (words[1][0] == 'd' && words[1][2] == 0)))
9275 if (words[1][0] == 'd' && words[1][2] == 0) {
9277 if (g_func_pd_cnt >= pd_alloc) {
9278 pd_alloc = pd_alloc * 2 + 16;
9279 g_func_pd = realloc(g_func_pd,
9280 sizeof(g_func_pd[0]) * pd_alloc);
9281 my_assert_not(g_func_pd, NULL);
9283 pd = &g_func_pd[g_func_pd_cnt];
9285 memset(pd, 0, sizeof(*pd));
9286 strcpy(pd->label, words[0]);
9287 pd->type = OPT_CONST;
9288 pd->lmod = lmod_from_directive(words[1]);
9294 anote("skipping alignment byte?\n");
9297 lmod = lmod_from_directive(words[0]);
9298 if (lmod != pd->lmod)
9299 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9302 if (pd->count_alloc < pd->count + wordc) {
9303 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9304 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9305 my_assert_not(pd->d, NULL);
9307 for (; i < wordc; i++) {
9308 if (IS(words[i], "offset")) {
9309 pd->type = OPT_OFFSET;
9312 p = strchr(words[i], ',');
9315 if (pd->type == OPT_OFFSET)
9316 pd->d[pd->count].u.label = strdup(words[i]);
9318 pd->d[pd->count].u.val = parse_number(words[i], 0);
9319 pd->d[pd->count].bt_i = -1;
9325 if (in_func && !g_skip_func) {
9327 gen_hdr(g_func, pi);
9329 gen_func(fout, g_fhdr, g_func, pi);
9334 g_ida_func_attr = 0;
9335 g_sct_func_attr = 0;
9336 g_stack_clear_start = 0;
9337 g_stack_clear_len = 0;
9343 func_chunks_used = 0;
9346 memset(&ops, 0, pi * sizeof(ops[0]));
9351 for (i = 0; i < g_func_pd_cnt; i++) {
9353 if (pd->type == OPT_OFFSET) {
9354 for (j = 0; j < pd->count; j++)
9355 free(pd->d[j].u.label);
9370 if (IS(words[1], "proc")) {
9372 aerr("proc '%s' while in_func '%s'?\n",
9375 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9377 strcpy(g_func, words[0]);
9378 set_label(0, words[0]);
9383 if (IS(words[1], "endp"))
9386 aerr("endp '%s' while not in_func?\n", words[0]);
9387 if (!IS(g_func, words[0]))
9388 aerr("endp '%s' while in_func '%s'?\n",
9391 aerr("endp '%s' while skipping code\n", words[0]);
9393 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9394 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
9400 if (!g_skip_func && func_chunks_used) {
9401 // start processing chunks
9402 struct chunk_item *ci, key = { g_func, 0 };
9404 func_chunk_ret = ftell(fasm);
9405 func_chunk_ret_ln = asmln;
9406 if (!func_chunks_sorted) {
9407 qsort(func_chunks, func_chunk_cnt,
9408 sizeof(func_chunks[0]), cmp_chunks);
9409 func_chunks_sorted = 1;
9411 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9412 sizeof(func_chunks[0]), cmp_chunks);
9414 aerr("'%s' needs chunks, but none found\n", g_func);
9415 func_chunk_i = ci - func_chunks;
9416 for (; func_chunk_i > 0; func_chunk_i--)
9417 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9420 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9422 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9423 asmln = func_chunks[func_chunk_i].asmln;
9431 if (wordc == 2 && IS(words[1], "ends")) {
9435 goto do_pending_endp;
9439 // scan for next text segment
9440 while (my_fgets(line, sizeof(line), fasm)) {
9443 if (*p == 0 || *p == ';')
9446 if (strstr(p, "segment para public 'CODE' use32"))
9453 p = strchr(words[0], ':');
9455 set_label(pi, words[0]);
9459 if (!in_func || g_skip_func || skip_code) {
9460 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9462 anote("skipping from '%s'\n", g_labels[pi]);
9466 g_labels[pi] = NULL;
9470 if (wordc > 1 && IS(words[1], "="))
9473 aerr("unhandled equ, wc=%d\n", wordc);
9474 if (g_eqcnt >= eq_alloc) {
9476 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9477 my_assert_not(g_eqs, NULL);
9480 len = strlen(words[0]);
9481 if (len > sizeof(g_eqs[0].name) - 1)
9482 aerr("equ name too long: %d\n", len);
9483 strcpy(g_eqs[g_eqcnt].name, words[0]);
9485 if (!IS(words[3], "ptr"))
9486 aerr("unhandled equ\n");
9487 if (IS(words[2], "dword"))
9488 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9489 else if (IS(words[2], "word"))
9490 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9491 else if (IS(words[2], "byte"))
9492 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9493 else if (IS(words[2], "qword"))
9494 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9496 aerr("bad lmod: '%s'\n", words[2]);
9498 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9503 if (pi >= ARRAY_SIZE(ops))
9504 aerr("too many ops\n");
9506 parse_op(&ops[pi], words, wordc);
9508 ops[pi].datap = sctproto;
9523 // vim:ts=2:shiftwidth=2:expandtab