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_FSHIFT = (1 << 24), /* x87 stack shift is actually needed */
72 OPF_FINT = (1 << 25), /* integer float op arg */
163 // pseudo-ops for lib calls
182 // must be sorted (larger len must be further in enum)
191 #define MAX_EXITS 128
193 #define MAX_OPERANDS 3
196 #define OPR_INIT(type_, lmod_, reg_) \
197 { type_, lmod_, reg_, }
201 enum opr_lenmod lmod;
203 unsigned int is_ptr:1; // pointer in C
204 unsigned int is_array:1; // array in C
205 unsigned int type_from_var:1; // .. in header, sometimes wrong
206 unsigned int size_mismatch:1; // type override differs from C
207 unsigned int size_lt:1; // type override is larger than C
208 unsigned int segment:7; // had segment override (enum segment)
209 const struct parsed_proto *pp; // for OPT_LABEL
216 struct parsed_opr operand[MAX_OPERANDS];
219 unsigned char pfo_inv;
220 unsigned char operand_cnt;
221 unsigned char p_argnum; // arg push: altered before call arg #
222 unsigned char p_arggrp; // arg push: arg group # for above
223 unsigned char p_argpass;// arg push: arg of host func
224 short p_argnext;// arg push: same arg pushed elsewhere or -1
225 int regmask_src; // all referensed regs
227 int pfomask; // flagop: parsed_flag_op that can't be delayed
228 int cc_scratch; // scratch storage during analysis
229 int bt_i; // branch target for branches
230 struct parsed_data *btj;// branch targets for jumptables
231 struct parsed_proto *pp;// parsed_proto for OP_CALL
237 // on start: function/data type hint (sctproto)
239 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
240 // OP_PUSH - points to OP_POP in complex push/pop graph
241 // OP_POP - points to OP_PUSH in simple push/pop pair
242 // OP_FCOM - needed_status_word_bits | (is_z_check << 16)
246 enum opr_lenmod lmod;
253 enum opr_lenmod lmod;
267 struct label_ref *next;
271 IDAFA_BP_FRAME = (1 << 0),
272 IDAFA_LIB_FUNC = (1 << 1),
273 IDAFA_STATIC = (1 << 2),
274 IDAFA_NORETURN = (1 << 3),
275 IDAFA_THUNK = (1 << 4),
276 IDAFA_FPD = (1 << 5),
280 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
281 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
303 // note: limited to 32k due to p_argnext
305 #define MAX_ARG_GRP 2
307 static struct parsed_op ops[MAX_OPS];
308 static struct parsed_equ *g_eqs;
310 static char *g_labels[MAX_OPS];
311 static struct label_ref g_label_refs[MAX_OPS];
312 static const struct parsed_proto *g_func_pp;
313 static struct parsed_data *g_func_pd;
314 static int g_func_pd_cnt;
315 static int g_func_lmods;
316 static char g_func[256];
317 static char g_comment[256];
318 static int g_bp_frame;
319 static int g_sp_frame;
320 static int g_stack_frame_used;
321 static int g_stack_fsz;
322 static int g_seh_found;
323 static int g_seh_size;
324 static int g_ida_func_attr;
325 static int g_sct_func_attr;
326 static int g_stack_clear_start; // in dwords
327 static int g_stack_clear_len;
328 static int g_regmask_init;
329 static int g_skip_func;
330 static int g_allow_regfunc;
331 static int g_allow_user_icall;
332 static int g_quiet_pp;
333 static int g_header_mode;
335 #define ferr(op_, fmt, ...) do { \
336 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
337 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
341 #define fnote(op_, fmt, ...) \
342 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
343 dump_op(op_), ##__VA_ARGS__)
345 #define ferr_assert(op_, cond) do { \
346 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
349 const char *regs_r32[] = {
350 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
351 // not r32, but list here for easy parsing and printing
352 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
353 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
355 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
356 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
357 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
363 xMM0, xMM1, xMM2, xMM3, // mmx
364 xMM4, xMM5, xMM6, xMM7,
365 xST0, xST1, xST2, xST3, // x87
366 xST4, xST5, xST6, xST7,
369 #define mxAX (1 << xAX)
370 #define mxCX (1 << xCX)
371 #define mxDX (1 << xDX)
372 #define mxSP (1 << xSP)
373 #define mxST0 (1 << xST0)
374 #define mxST1 (1 << xST1)
375 #define mxST1_0 (mxST1 | mxST0)
376 #define mxST7_2 (0xfc << xST0)
377 #define mxSTa (0xff << xST0)
379 // possible basic comparison types (without inversion)
380 enum parsed_flag_op {
384 PFO_BE, // 6 CF=1||ZF=1
388 PFO_LE, // e ZF=1||SF!=OF
391 #define PFOB_O (1 << PFO_O)
392 #define PFOB_C (1 << PFO_C)
393 #define PFOB_Z (1 << PFO_Z)
394 #define PFOB_S (1 << PFO_S)
396 static const char *parsed_flag_op_names[] = {
397 "o", "c", "z", "be", "s", "p", "l", "le"
400 static int char_array_i(const char *array[], size_t len, const char *s)
404 for (i = 0; i < len; i++)
411 static void printf_number(char *buf, size_t buf_size,
412 unsigned long number)
414 // output in C-friendly form
415 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
418 static int check_segment_prefix(const char *s)
420 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
424 case 'c': return SEG_CS;
425 case 'd': return SEG_DS;
426 case 's': return SEG_SS;
427 case 'e': return SEG_ES;
428 case 'f': return SEG_FS;
429 case 'g': return SEG_GS;
434 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
438 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
440 *reg_lmod = OPLM_QWORD;
444 *reg_lmod = OPLM_DWORD;
447 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
449 *reg_lmod = OPLM_WORD;
452 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
454 *reg_lmod = OPLM_BYTE;
457 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
459 *reg_lmod = OPLM_BYTE;
466 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
468 enum opr_lenmod lmod;
481 while (my_isblank(*s))
483 for (; my_issep(*s); d++, s++)
485 while (my_isblank(*s))
489 // skip '?s:' prefixes
490 if (check_segment_prefix(s))
493 s = next_idt(w, sizeof(w), s);
498 reg = parse_reg(&lmod, w);
500 *regmask |= 1 << reg;
504 if ('0' <= w[0] && w[0] <= '9') {
505 number = parse_number(w, 0);
506 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
510 // probably some label/identifier - pass
513 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
517 strcpy(name, cvtbuf);
522 static int is_reg_in_str(const char *s)
526 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
529 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
530 if (!strncmp(s, regs_r32[i], 3))
536 static const char *parse_stack_el(const char *name, char *extra_reg,
537 int *base_val, int early_try)
539 const char *p, *p2, *s;
545 if (g_bp_frame || early_try)
548 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
550 if (extra_reg != NULL) {
551 strncpy(extra_reg, name, 3);
556 if (IS_START(p, "ebp+")) {
560 if (p2 != NULL && is_reg_in_str(p)) {
561 if (extra_reg != NULL) {
562 strncpy(extra_reg, p, p2 - p);
563 extra_reg[p2 - p] = 0;
568 if (!('0' <= *p && *p <= '9'))
575 if (!IS_START(name, "esp+"))
581 if (is_reg_in_str(s)) {
582 if (extra_reg != NULL) {
583 strncpy(extra_reg, s, p - s);
584 extra_reg[p - s] = 0;
589 aerr("%s IDA stackvar not set?\n", __func__);
591 if (!('0' <= *s && *s <= '9')) {
592 aerr("%s IDA stackvar offset not set?\n", __func__);
595 if (s[0] == '0' && s[1] == 'x')
598 if (len < sizeof(buf) - 1) {
599 strncpy(buf, s, len);
602 val = strtol(buf, &endp, 16);
603 if (val == 0 || *endp != 0 || errno != 0) {
604 aerr("%s num parse fail for '%s'\n", __func__, buf);
613 if ('0' <= *p && *p <= '9')
616 if (base_val != NULL)
621 static int guess_lmod_from_name(struct parsed_opr *opr)
623 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
624 opr->lmod = OPLM_DWORD;
627 if (IS_START(opr->name, "word_")) {
628 opr->lmod = OPLM_WORD;
631 if (IS_START(opr->name, "byte_")) {
632 opr->lmod = OPLM_BYTE;
635 if (IS_START(opr->name, "qword_")) {
636 opr->lmod = OPLM_QWORD;
642 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
643 const struct parsed_type *c_type)
645 static const char *qword_types[] = {
646 "uint64_t", "int64_t", "__int64",
648 static const char *dword_types[] = {
649 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
650 "WPARAM", "LPARAM", "UINT", "__int32",
651 "LONG", "HIMC", "BOOL", "size_t",
654 static const char *word_types[] = {
655 "uint16_t", "int16_t", "_WORD", "WORD",
656 "unsigned __int16", "__int16",
658 static const char *byte_types[] = {
659 "uint8_t", "int8_t", "char",
660 "unsigned __int8", "__int8", "BYTE", "_BYTE",
662 // structures.. deal the same as with _UNKNOWN for now
668 if (c_type->is_ptr) {
673 n = skip_type_mod(c_type->name);
675 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
676 if (IS(n, dword_types[i])) {
682 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
683 if (IS(n, word_types[i])) {
689 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
690 if (IS(n, byte_types[i])) {
696 for (i = 0; i < ARRAY_SIZE(qword_types); i++) {
697 if (IS(n, qword_types[i])) {
706 static char *default_cast_to(char *buf, size_t buf_size,
707 struct parsed_opr *opr)
711 if (!opr->is_ptr || strchr(opr->name, '['))
713 if (opr->pp == NULL || opr->pp->type.name == NULL
716 snprintf(buf, buf_size, "%s", "(void *)");
720 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
724 static enum opr_type lmod_from_directive(const char *d)
728 else if (IS(d, "dw"))
730 else if (IS(d, "db"))
733 aerr("unhandled directive: '%s'\n", d);
737 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
743 *regmask |= 1 << reg;
746 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
749 static int parse_operand(struct parsed_opr *opr,
750 int *regmask, int *regmask_indirect,
751 char words[16][256], int wordc, int w, unsigned int op_flags)
753 const struct parsed_proto *pp = NULL;
754 enum opr_lenmod tmplmod;
755 unsigned long number;
763 aerr("parse_operand w %d, wordc %d\n", w, wordc);
767 for (i = w; i < wordc; i++) {
768 len = strlen(words[i]);
769 if (words[i][len - 1] == ',') {
770 words[i][len - 1] = 0;
776 wordc_in = wordc - w;
778 if ((op_flags & OPF_JMP) && wordc_in > 0
779 && !('0' <= words[w][0] && words[w][0] <= '9'))
781 const char *label = NULL;
783 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
784 && IS(words[w + 1], "ptr"))
785 label = words[w + 2];
786 else if (wordc_in == 2 && IS(words[w], "short"))
787 label = words[w + 1];
788 else if (wordc_in == 1
789 && strchr(words[w], '[') == NULL
790 && parse_reg(&tmplmod, words[w]) < 0)
794 opr->type = OPT_LABEL;
795 ret = check_segment_prefix(label);
800 strcpy(opr->name, label);
806 if (IS(words[w + 1], "ptr")) {
807 if (IS(words[w], "dword"))
808 opr->lmod = OPLM_DWORD;
809 else if (IS(words[w], "word"))
810 opr->lmod = OPLM_WORD;
811 else if (IS(words[w], "byte"))
812 opr->lmod = OPLM_BYTE;
813 else if (IS(words[w], "qword"))
814 opr->lmod = OPLM_QWORD;
816 aerr("type parsing failed\n");
818 wordc_in = wordc - w;
823 if (IS(words[w], "offset")) {
824 opr->type = OPT_OFFSET;
825 opr->lmod = OPLM_DWORD;
826 strcpy(opr->name, words[w + 1]);
827 pp = proto_parse(g_fhdr, opr->name, 1);
830 if (IS(words[w], "(offset")) {
831 p = strchr(words[w + 1], ')');
833 aerr("parse of bracketed offset failed\n");
835 opr->type = OPT_OFFSET;
836 strcpy(opr->name, words[w + 1]);
842 aerr("parse_operand 1 word expected\n");
844 ret = check_segment_prefix(words[w]);
847 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
848 if (ret == SEG_FS && IS(words[w], "0"))
851 strcpy(opr->name, words[w]);
853 if (words[w][0] == '[') {
854 opr->type = OPT_REGMEM;
855 ret = sscanf(words[w], "[%[^]]]", opr->name);
857 aerr("[] parse failure\n");
859 parse_indmode(opr->name, regmask_indirect, 1);
860 if (opr->lmod == OPLM_UNSPEC
861 && parse_stack_el(opr->name, NULL, NULL, 1))
864 struct parsed_equ *eq =
865 equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
867 opr->lmod = eq->lmod;
869 // might be unaligned access
870 g_func_lmods |= 1 << OPLM_BYTE;
874 else if (strchr(words[w], '[')) {
876 p = strchr(words[w], '[');
877 opr->type = OPT_REGMEM;
878 parse_indmode(p, regmask_indirect, 0);
879 strncpy(buf, words[w], p - words[w]);
880 buf[p - words[w]] = 0;
881 pp = proto_parse(g_fhdr, buf, 1);
884 else if (('0' <= words[w][0] && words[w][0] <= '9')
885 || words[w][0] == '-')
887 number = parse_number(words[w], 0);
888 opr->type = OPT_CONST;
890 printf_number(opr->name, sizeof(opr->name), number);
894 ret = parse_reg(&tmplmod, opr->name);
896 setup_reg_opr(opr, ret, tmplmod, regmask);
900 // most likely var in data segment
901 opr->type = OPT_LABEL;
902 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
906 if (pp->is_fptr || pp->is_func) {
907 opr->lmod = OPLM_DWORD;
911 tmplmod = OPLM_UNSPEC;
912 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
913 anote("unhandled C type '%s' for '%s'\n",
914 pp->type.name, opr->name);
916 if (opr->lmod == OPLM_UNSPEC) {
918 opr->type_from_var = 1;
920 else if (opr->lmod != tmplmod) {
921 opr->size_mismatch = 1;
922 if (tmplmod < opr->lmod)
925 opr->is_ptr = pp->type.is_ptr;
927 opr->is_array = pp->type.is_array;
931 if (opr->lmod == OPLM_UNSPEC)
932 guess_lmod_from_name(opr);
936 static const struct {
941 { "repe", OPF_REP|OPF_REPZ },
942 { "repz", OPF_REP|OPF_REPZ },
943 { "repne", OPF_REP|OPF_REPNZ },
944 { "repnz", OPF_REP|OPF_REPNZ },
945 { "lock", OPF_LOCK }, // ignored for now..
948 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
950 static const struct {
953 unsigned short minopr;
954 unsigned short maxopr;
957 unsigned char pfo_inv;
959 { "nop", OP_NOP, 0, 0, 0 },
960 { "push", OP_PUSH, 1, 1, 0 },
961 { "pop", OP_POP, 1, 1, OPF_DATA },
962 { "pusha",OP_PUSHA, 0, 0, 0 },
963 { "popa", OP_POPA, 0, 0, OPF_DATA },
964 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
965 { "mov" , OP_MOV, 2, 2, OPF_DATA },
966 { "lea", OP_LEA, 2, 2, OPF_DATA },
967 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
968 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
969 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
970 { "not", OP_NOT, 1, 1, OPF_DATA },
971 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
972 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
973 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
974 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
975 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
976 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
977 { "stosb",OP_STOS, 0, 0, OPF_DATA },
978 { "stosw",OP_STOS, 0, 0, OPF_DATA },
979 { "stosd",OP_STOS, 0, 0, OPF_DATA },
980 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
981 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
982 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
983 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
984 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
985 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
986 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
987 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
988 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
989 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
990 { "cld", OP_CLD, 0, 0, OPF_DATA },
991 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
992 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
993 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
994 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
995 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
996 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
997 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
998 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
999 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
1000 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
1001 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
1002 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
1003 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
1004 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1005 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1006 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1007 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1008 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
1009 { "bsr", OP_BSR, 2, 2, OPF_DATA|OPF_FLAGS },
1010 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
1011 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
1012 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
1013 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
1014 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
1015 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
1016 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
1017 { "test", OP_TEST, 2, 2, OPF_FLAGS },
1018 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
1019 { "retn", OP_RET, 0, 1, OPF_TAIL },
1020 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
1021 { "jmp", OP_JMP, 1, 1, OPF_JMP },
1022 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
1023 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
1024 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
1025 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
1026 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
1027 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
1028 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
1029 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1030 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1031 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
1032 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
1033 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
1034 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
1035 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1036 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1037 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1038 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1039 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1040 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1041 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1042 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1043 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1044 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1045 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1046 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1047 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1048 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1049 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1050 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1051 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1052 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1053 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1054 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1055 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1056 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1057 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1058 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1059 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1060 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1061 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1062 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1063 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1064 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1065 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1066 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1067 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1068 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1069 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1070 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1071 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1072 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1073 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1074 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1075 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1076 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1077 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1078 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1079 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1080 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1081 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1083 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1084 { "fild", OP_FILD, 1, 1, OPF_FPUSH|OPF_FINT },
1085 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1086 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1087 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1088 { "fst", OP_FST, 1, 1, 0 },
1089 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1090 { "fist", OP_FIST, 1, 1, OPF_FINT },
1091 { "fistp", OP_FIST, 1, 1, OPF_FPOP|OPF_FINT },
1092 { "fadd", OP_FADD, 0, 2, 0 },
1093 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1094 { "fdiv", OP_FDIV, 0, 2, 0 },
1095 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1096 { "fmul", OP_FMUL, 0, 2, 0 },
1097 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1098 { "fsub", OP_FSUB, 0, 2, 0 },
1099 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1100 { "fdivr", OP_FDIVR, 0, 2, 0 },
1101 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1102 { "fsubr", OP_FSUBR, 0, 2, 0 },
1103 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1104 { "fiadd", OP_FIADD, 1, 1, OPF_FINT },
1105 { "fidiv", OP_FIDIV, 1, 1, OPF_FINT },
1106 { "fimul", OP_FIMUL, 1, 1, OPF_FINT },
1107 { "fisub", OP_FISUB, 1, 1, OPF_FINT },
1108 { "fidivr", OP_FIDIVR, 1, 1, OPF_FINT },
1109 { "fisubr", OP_FISUBR, 1, 1, OPF_FINT },
1110 { "fcom", OP_FCOM, 0, 1, 0 },
1111 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1112 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1113 { "fchs", OP_FCHS, 0, 0, 0 },
1114 { "fcos", OP_FCOS, 0, 0, 0 },
1115 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1116 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1117 { "fsin", OP_FSIN, 0, 0, 0 },
1118 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1119 { "fxch", OP_FXCH, 1, 1, 0 },
1120 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1122 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1123 { "movq", OP_MOV, 2, 2, OPF_DATA },
1124 // pseudo-ops for lib calls
1125 { "_allshl",OPP_ALLSHL },
1126 { "_allshr",OPP_ALLSHR },
1127 { "_ftol", OPP_FTOL },
1128 { "_CIpow", OPP_CIPOW },
1129 { "abort", OPP_ABORT },
1134 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1136 enum opr_lenmod lmod = OPLM_UNSPEC;
1137 int prefix_flags = 0;
1145 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1146 if (IS(words[w], pref_table[i].name)) {
1147 prefix_flags = pref_table[i].flags;
1154 aerr("lone prefix: '%s'\n", words[0]);
1159 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1160 if (IS(words[w], op_table[i].name))
1164 if (i == ARRAY_SIZE(op_table)) {
1166 aerr("unhandled op: '%s'\n", words[0]);
1171 op->op = op_table[i].op;
1172 op->flags = op_table[i].flags | prefix_flags;
1173 op->pfo = op_table[i].pfo;
1174 op->pfo_inv = op_table[i].pfo_inv;
1175 op->regmask_src = op->regmask_dst = 0;
1178 if (op->op == OP_UD2)
1181 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1182 if (opr >= op_table[i].minopr && w >= wordc)
1185 regmask = regmask_ind = 0;
1186 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1187 words, wordc, w, op->flags);
1189 if (opr == 0 && (op->flags & OPF_DATA))
1190 op->regmask_dst = regmask;
1192 op->regmask_src |= regmask;
1193 op->regmask_src |= regmask_ind;
1195 if (op->operand[opr].lmod != OPLM_UNSPEC)
1196 g_func_lmods |= 1 << op->operand[opr].lmod;
1200 aerr("parse_op %s incomplete: %d/%d\n",
1201 words[0], w, wordc);
1204 op->operand_cnt = opr;
1205 if (!strncmp(op_table[i].name, "set", 3))
1206 op->operand[0].lmod = OPLM_BYTE;
1209 // first operand is not dst
1212 op->regmask_src |= op->regmask_dst;
1213 op->regmask_dst = 0;
1216 // first operand is src too
1229 op->regmask_src |= op->regmask_dst;
1234 op->regmask_src |= op->regmask_dst;
1235 op->regmask_dst |= op->regmask_src;
1241 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1242 && op->operand[0].lmod == op->operand[1].lmod
1243 && op->operand[0].reg == op->operand[1].reg
1244 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1246 op->regmask_src = 0;
1249 op->regmask_src |= op->regmask_dst;
1252 // ops with implicit argumets
1254 op->operand_cnt = 2;
1255 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1256 op->regmask_dst = op->regmask_src;
1257 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1261 op->operand_cnt = 2;
1262 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1263 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1269 if (words[op_w][4] == 'b')
1271 else if (words[op_w][4] == 'w')
1273 else if (words[op_w][4] == 'd')
1276 op->regmask_src = 0;
1277 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1278 OPLM_DWORD, &op->regmask_src);
1279 op->regmask_dst = op->regmask_src;
1280 setup_reg_opr(&op->operand[j++], xAX, lmod,
1281 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1282 if (op->flags & OPF_REP) {
1283 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1284 op->regmask_dst |= 1 << xCX;
1286 op->operand_cnt = j;
1291 if (words[op_w][4] == 'b')
1293 else if (words[op_w][4] == 'w')
1295 else if (words[op_w][4] == 'd')
1298 op->regmask_src = 0;
1299 // note: lmod is not correct, don't have where to place it
1300 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1301 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1302 if (op->flags & OPF_REP)
1303 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1304 op->operand_cnt = j;
1305 op->regmask_dst = op->regmask_src;
1309 op->regmask_dst = 1 << xCX;
1312 op->operand_cnt = 2;
1313 op->regmask_src = 1 << xCX;
1314 op->operand[1].type = OPT_REG;
1315 op->operand[1].reg = xCX;
1316 op->operand[1].lmod = OPLM_DWORD;
1320 if (op->operand_cnt == 2) {
1321 if (op->operand[0].type != OPT_REG)
1322 aerr("reg expected\n");
1323 op->regmask_src |= 1 << op->operand[0].reg;
1325 if (op->operand_cnt != 1)
1330 op->regmask_src |= op->regmask_dst;
1331 op->regmask_dst = (1 << xDX) | (1 << xAX);
1332 if (op->operand[0].lmod == OPLM_UNSPEC)
1333 op->operand[0].lmod = OPLM_DWORD;
1338 // we could set up operands for edx:eax, but there is no real need to
1339 // (see is_opr_modified())
1340 op->regmask_src |= op->regmask_dst;
1341 op->regmask_dst = (1 << xDX) | (1 << xAX);
1342 if (op->operand[0].lmod == OPLM_UNSPEC)
1343 op->operand[0].lmod = OPLM_DWORD;
1351 op->regmask_src |= op->regmask_dst;
1352 if (op->operand[1].lmod == OPLM_UNSPEC)
1353 op->operand[1].lmod = OPLM_BYTE;
1358 op->regmask_src |= op->regmask_dst;
1359 if (op->operand[2].lmod == OPLM_UNSPEC)
1360 op->operand[2].lmod = OPLM_BYTE;
1364 op->regmask_src |= op->regmask_dst;
1365 op->regmask_dst = 0;
1366 if (op->operand[0].lmod == OPLM_UNSPEC
1367 && (op->operand[0].type == OPT_CONST
1368 || op->operand[0].type == OPT_OFFSET
1369 || op->operand[0].type == OPT_LABEL))
1370 op->operand[0].lmod = OPLM_DWORD;
1376 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1377 && op->operand[0].lmod == op->operand[1].lmod
1378 && op->operand[0].reg == op->operand[1].reg
1379 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1381 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1382 op->regmask_src = op->regmask_dst = 0;
1387 if (op->operand[0].type == OPT_REG
1388 && op->operand[1].type == OPT_REGMEM)
1391 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1392 if (IS(buf, op->operand[1].name))
1393 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1398 // trashed regs must be explicitly detected later
1399 op->regmask_dst = 0;
1403 op->regmask_dst = (1 << xBP) | (1 << xSP);
1404 op->regmask_src = 1 << xBP;
1409 op->regmask_dst |= mxST0;
1413 op->regmask_dst |= mxST0;
1414 if (IS(words[op_w] + 3, "1"))
1415 op->operand[0].val = X87_CONST_1;
1416 else if (IS(words[op_w] + 3, "ln2"))
1417 op->operand[0].val = X87_CONST_LN2;
1418 else if (IS(words[op_w] + 3, "z"))
1419 op->operand[0].val = X87_CONST_Z;
1426 op->regmask_src |= mxST0;
1435 op->regmask_src |= mxST0;
1436 if (op->operand_cnt == 2)
1437 op->regmask_src |= op->regmask_dst;
1438 else if (op->operand_cnt == 1) {
1439 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1440 op->operand[0].type = OPT_REG;
1441 op->operand[0].lmod = OPLM_QWORD;
1442 op->operand[0].reg = xST0;
1443 op->regmask_dst |= mxST0;
1446 // IDA doesn't use this
1447 aerr("no operands?\n");
1461 op->regmask_src |= mxST0;
1462 op->regmask_dst |= mxST0;
1467 op->regmask_src |= mxST0 | mxST1;
1468 op->regmask_dst |= mxST0;
1476 op->regmask_src |= mxST0;
1483 if (op->operand[0].type == OPT_REG
1484 && op->operand[1].type == OPT_CONST)
1486 struct parsed_opr *op1 = &op->operand[1];
1487 if ((op->op == OP_AND && op1->val == 0)
1490 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1491 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1493 op->regmask_src = 0;
1498 static const char *op_name(struct parsed_op *po)
1500 static char buf[16];
1504 if (po->op == OP_JCC || po->op == OP_SCC) {
1506 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1509 strcpy(p, parsed_flag_op_names[po->pfo]);
1513 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1514 if (op_table[i].op == po->op)
1515 return op_table[i].name;
1521 static const char *dump_op(struct parsed_op *po)
1523 static char out[128];
1530 snprintf(out, sizeof(out), "%s", op_name(po));
1531 for (i = 0; i < po->operand_cnt; i++) {
1535 snprintf(p, sizeof(out) - (p - out),
1536 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1537 po->operand[i].name);
1543 static const char *lmod_type_u(struct parsed_op *po,
1544 enum opr_lenmod lmod)
1556 ferr(po, "invalid lmod: %d\n", lmod);
1557 return "(_invalid_)";
1561 static const char *lmod_cast_u(struct parsed_op *po,
1562 enum opr_lenmod lmod)
1574 ferr(po, "invalid lmod: %d\n", lmod);
1575 return "(_invalid_)";
1579 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1580 enum opr_lenmod lmod)
1592 ferr(po, "invalid lmod: %d\n", lmod);
1593 return "(_invalid_)";
1597 static const char *lmod_cast_s(struct parsed_op *po,
1598 enum opr_lenmod lmod)
1610 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1611 return "(_invalid_)";
1615 static const char *lmod_cast(struct parsed_op *po,
1616 enum opr_lenmod lmod, int is_signed)
1619 lmod_cast_s(po, lmod) :
1620 lmod_cast_u(po, lmod);
1623 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1635 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1640 static const char *opr_name(struct parsed_op *po, int opr_num)
1642 if (opr_num >= po->operand_cnt)
1643 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1644 return po->operand[opr_num].name;
1647 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1649 if (opr_num >= po->operand_cnt)
1650 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1651 if (po->operand[opr_num].type != OPT_CONST)
1652 ferr(po, "opr %d: const expected\n", opr_num);
1653 return po->operand[opr_num].val;
1656 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1658 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1659 ferr(po, "invalid reg: %d\n", popr->reg);
1660 return regs_r32[popr->reg];
1663 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1665 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1667 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1669 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1671 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1676 *is_signed = cast[1] == 's' ? 1 : 0;
1680 static int check_deref_cast(const char *cast, int *bits)
1682 if (IS_START(cast, "*(u8 *)"))
1684 else if (IS_START(cast, "*(u16 *)"))
1686 else if (IS_START(cast, "*(u32 *)"))
1688 else if (IS_START(cast, "*(u64 *)"))
1696 // cast1 is the "final" cast
1697 static const char *simplify_cast(const char *cast1, const char *cast2)
1699 static char buf[256];
1707 if (IS(cast1, cast2))
1710 if (check_simple_cast(cast1, &bits1, &s1) == 0
1711 && check_simple_cast(cast2, &bits2, &s2) == 0)
1716 if (check_simple_cast(cast1, &bits1, &s1) == 0
1717 && check_deref_cast(cast2, &bits2) == 0)
1719 if (bits1 == bits2) {
1720 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1725 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1728 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1732 static const char *simplify_cast_num(const char *cast, unsigned int val)
1734 if (IS(cast, "(u8)") && val < 0x100)
1736 if (IS(cast, "(s8)") && val < 0x80)
1738 if (IS(cast, "(u16)") && val < 0x10000)
1740 if (IS(cast, "(s16)") && val < 0x8000)
1742 if (IS(cast, "(s32)") && val < 0x80000000)
1748 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1757 namelen = strlen(name);
1759 p = strpbrk(name, "+-");
1763 ferr(po, "equ parse failed for '%s'\n", name);
1766 *extra_offs = strtol(p, &endp, 16);
1767 if (*endp != 0 || errno != 0)
1768 ferr(po, "equ parse failed for '%s'\n", name);
1771 for (i = 0; i < g_eqcnt; i++)
1772 if (strncmp(g_eqs[i].name, name, namelen) == 0
1773 && g_eqs[i].name[namelen] == 0)
1777 ferr(po, "unresolved equ name: '%s'\n", name);
1784 static int is_stack_access(struct parsed_op *po,
1785 const struct parsed_opr *popr)
1787 return (parse_stack_el(popr->name, NULL, NULL, 0)
1788 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1789 && IS_START(popr->name, "ebp")));
1792 static void parse_stack_access(struct parsed_op *po,
1793 const char *name, char *ofs_reg, int *offset_out,
1794 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1796 const char *bp_arg = "";
1797 const char *p = NULL;
1798 struct parsed_equ *eq;
1805 if (IS_START(name, "ebp-")
1806 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1809 if (IS_START(p, "0x"))
1812 offset = strtoul(p, &endp, 16);
1815 if (*endp != 0 || errno != 0)
1816 ferr(po, "ebp- parse of '%s' failed\n", name);
1819 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1820 eq = equ_find(po, bp_arg, &offset);
1822 ferr(po, "detected but missing eq\n");
1823 offset += eq->offset;
1826 if (!strncmp(name, "ebp", 3))
1829 // yes it sometimes LEAs ra for compares..
1830 if (!is_lea && ofs_reg[0] == 0
1831 && stack_ra <= offset && offset < stack_ra + 4)
1833 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1836 *offset_out = offset;
1838 *stack_ra_out = stack_ra;
1840 *bp_arg_out = bp_arg;
1843 static int parse_stack_esp_offset(struct parsed_op *po,
1844 const char *name, int *offset_out)
1846 char ofs_reg[16] = { 0, };
1847 struct parsed_equ *eq;
1853 if (strstr(name, "esp") == NULL)
1855 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1856 if (bp_arg == NULL) {
1857 // just plain offset?
1858 if (!IS_START(name, "esp+"))
1861 offset = strtol(name + 4, &endp, 0);
1862 if (endp == NULL || *endp != 0 || errno != 0)
1864 *offset_out = offset;
1868 if (ofs_reg[0] != 0)
1870 eq = equ_find(po, bp_arg, &offset);
1872 ferr(po, "detected but missing eq\n");
1873 offset += eq->offset;
1874 *offset_out = base_val + offset;
1878 static int stack_frame_access(struct parsed_op *po,
1879 struct parsed_opr *popr, char *buf, size_t buf_size,
1880 const char *name, const char *cast, int is_src, int is_lea)
1882 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1883 const char *prefix = "";
1884 const char *bp_arg = NULL;
1885 char ofs_reg[16] = { 0, };
1886 int i, arg_i, arg_s;
1893 if (g_bp_frame && (po->flags & OPF_EBP_S)
1894 && !(po->regmask_src & mxSP))
1895 ferr(po, "stack_frame_access while ebp is scratch\n");
1897 parse_stack_access(po, name, ofs_reg, &offset,
1898 &stack_ra, &bp_arg, is_lea);
1900 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1902 if (offset > stack_ra)
1904 arg_i = (offset - stack_ra - 4) / 4;
1905 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1907 if (g_func_pp->is_vararg
1908 && arg_i == g_func_pp->argc_stack && is_lea)
1910 // should be va_list
1913 snprintf(buf, buf_size, "%sap", cast);
1916 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1917 offset, bp_arg, arg_i);
1919 if (ofs_reg[0] != 0)
1920 ferr(po, "offset reg on arg access?\n");
1922 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1923 if (g_func_pp->arg[i].reg != NULL)
1929 if (i == g_func_pp->argc)
1930 ferr(po, "arg %d not in prototype?\n", arg_i);
1932 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1939 ferr(po, "lea/byte to arg?\n");
1940 if (is_src && (offset & 3) == 0)
1941 snprintf(buf, buf_size, "%sa%d",
1942 simplify_cast(cast, "(u8)"), i + 1);
1944 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1945 cast, offset & 3, i + 1);
1950 ferr(po, "lea/word to arg?\n");
1955 ferr(po, "problematic arg store\n");
1956 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1957 simplify_cast(cast, "*(u16 *)"), i + 1);
1960 ferr(po, "unaligned arg word load\n");
1962 else if (is_src && (offset & 2) == 0)
1963 snprintf(buf, buf_size, "%sa%d",
1964 simplify_cast(cast, "(u16)"), i + 1);
1966 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1967 cast, (offset & 2) ? "HI" : "LO", i + 1);
1979 snprintf(buf, buf_size, "(u32)&a%d + %d",
1982 ferr(po, "unaligned arg store\n");
1984 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1985 snprintf(buf, buf_size, "%s(a%d >> %d)",
1986 prefix, i + 1, (offset & 3) * 8);
1990 snprintf(buf, buf_size, "%s%sa%d",
1991 prefix, is_lea ? "&" : "", i + 1);
1996 ferr_assert(po, !(offset & 7));
1999 snprintf(buf, buf_size, "%s%sa%d",
2000 prefix, is_lea ? "&" : "", i + 1);
2004 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
2008 strcat(g_comment, " unaligned");
2011 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
2012 if (tmp_lmod != OPLM_DWORD
2013 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
2014 < lmod_bytes(po, popr->lmod) + (offset & 3))))
2016 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
2017 i + 1, offset, g_func_pp->arg[i].type.name);
2019 // can't check this because msvc likes to reuse
2020 // arg space for scratch..
2021 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
2022 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2026 if (g_stack_fsz == 0)
2027 ferr(po, "stack var access without stackframe\n");
2028 g_stack_frame_used = 1;
2030 sf_ofs = g_stack_fsz + offset;
2031 if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2032 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2042 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2043 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2047 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2048 // known unaligned or possibly unaligned
2049 strcat(g_comment, " unaligned");
2051 prefix = "*(u16 *)&";
2052 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2053 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2056 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2060 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2061 // known unaligned or possibly unaligned
2062 strcat(g_comment, " unaligned");
2064 prefix = "*(u32 *)&";
2065 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2066 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2069 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2073 ferr_assert(po, !(sf_ofs & 7));
2074 ferr_assert(po, ofs_reg[0] == 0);
2075 // only used for x87 int64/float, float sets is_lea
2076 if (!is_lea && (po->flags & OPF_FINT))
2077 prefix = "*(s64 *)&";
2078 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2082 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2089 static void check_func_pp(struct parsed_op *po,
2090 const struct parsed_proto *pp, const char *pfx)
2092 enum opr_lenmod tmp_lmod;
2096 if (pp->argc_reg != 0) {
2097 if (!g_allow_user_icall && !pp->is_fastcall) {
2098 pp_print(buf, sizeof(buf), pp);
2099 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2101 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2102 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2103 pfx, pp->argc_reg, pp->argc_stack);
2106 // fptrs must use 32bit args, callsite might have no information and
2107 // lack a cast to smaller types, which results in incorrectly masked
2108 // args passed (callee may assume masked args, it does on ARM)
2109 if (!pp->is_osinc) {
2110 for (i = 0; i < pp->argc; i++) {
2111 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2112 if (ret && tmp_lmod != OPLM_DWORD)
2113 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2114 i + 1, pp->arg[i].type.name);
2119 static const char *check_label_read_ref(struct parsed_op *po,
2122 const struct parsed_proto *pp;
2124 pp = proto_parse(g_fhdr, name, 0);
2126 ferr(po, "proto_parse failed for ref '%s'\n", name);
2129 check_func_pp(po, pp, "ref");
2134 static void check_opr(struct parsed_op *po, struct parsed_opr *popr)
2136 if (popr->segment == SEG_FS)
2137 ferr(po, "fs: used\n");
2138 if (popr->segment == SEG_GS)
2139 ferr(po, "gs: used\n");
2142 static char *out_src_opr(char *buf, size_t buf_size,
2143 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2146 char tmp1[256], tmp2[256];
2152 check_opr(po, popr);
2157 switch (popr->type) {
2160 ferr(po, "lea from reg?\n");
2162 switch (popr->lmod) {
2164 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2167 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2170 snprintf(buf, buf_size, "%s%s",
2171 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2174 if (popr->name[1] == 'h') // XXX..
2175 snprintf(buf, buf_size, "%s(%s >> 8)",
2176 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2178 snprintf(buf, buf_size, "%s%s",
2179 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2182 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2187 if (is_stack_access(po, popr)) {
2188 stack_frame_access(po, popr, buf, buf_size,
2189 popr->name, cast, 1, is_lea);
2193 strcpy(expr, popr->name);
2194 if (strchr(expr, '[')) {
2195 // special case: '[' can only be left for label[reg] form
2196 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2198 ferr(po, "parse failure for '%s'\n", expr);
2199 if (tmp1[0] == '(') {
2200 // (off_4FFF50+3)[eax]
2201 p = strchr(tmp1 + 1, ')');
2202 if (p == NULL || p[1] != 0)
2203 ferr(po, "parse failure (2) for '%s'\n", expr);
2205 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2207 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2210 // XXX: do we need more parsing?
2212 snprintf(buf, buf_size, "%s", expr);
2216 snprintf(buf, buf_size, "%s(%s)",
2217 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2221 name = check_label_read_ref(po, popr->name);
2222 if (cast[0] == 0 && popr->is_ptr)
2226 snprintf(buf, buf_size, "(u32)&%s", name);
2227 else if (popr->size_lt)
2228 snprintf(buf, buf_size, "%s%s%s%s", cast,
2229 lmod_cast_u_ptr(po, popr->lmod),
2230 popr->is_array ? "" : "&", name);
2232 snprintf(buf, buf_size, "%s%s%s", cast, name,
2233 popr->is_array ? "[0]" : "");
2237 name = check_label_read_ref(po, popr->name);
2241 ferr(po, "lea an offset?\n");
2242 snprintf(buf, buf_size, "%s&%s", cast, name);
2247 ferr(po, "lea from const?\n");
2249 printf_number(tmp1, sizeof(tmp1), popr->val);
2250 if (popr->val == 0 && strchr(cast, '*'))
2251 snprintf(buf, buf_size, "NULL");
2253 snprintf(buf, buf_size, "%s%s",
2254 simplify_cast_num(cast, popr->val), tmp1);
2258 ferr(po, "invalid src type: %d\n", popr->type);
2264 // note: may set is_ptr (we find that out late for ebp frame..)
2265 static char *out_dst_opr(char *buf, size_t buf_size,
2266 struct parsed_op *po, struct parsed_opr *popr)
2268 check_opr(po, popr);
2270 switch (popr->type) {
2272 switch (popr->lmod) {
2274 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2277 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2281 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2285 if (popr->name[1] == 'h') // XXX..
2286 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2288 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2291 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2296 if (is_stack_access(po, popr)) {
2297 stack_frame_access(po, popr, buf, buf_size,
2298 popr->name, "", 0, 0);
2302 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2305 if (popr->size_mismatch)
2306 snprintf(buf, buf_size, "%s%s%s",
2307 lmod_cast_u_ptr(po, popr->lmod),
2308 popr->is_array ? "" : "&", popr->name);
2310 snprintf(buf, buf_size, "%s%s", popr->name,
2311 popr->is_array ? "[0]" : "");
2315 ferr(po, "invalid dst type: %d\n", popr->type);
2321 static char *out_src_opr_u32(char *buf, size_t buf_size,
2322 struct parsed_op *po, struct parsed_opr *popr)
2324 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2327 static char *out_opr_float(char *buf, size_t buf_size,
2328 struct parsed_op *po, struct parsed_opr *popr, int is_src,
2329 int need_float_stack)
2331 const char *cast = NULL;
2334 switch (popr->type) {
2336 if (popr->reg < xST0 || popr->reg > xST7)
2337 ferr(po, "bad reg: %d\n", popr->reg);
2339 if (need_float_stack) {
2340 if (popr->reg == xST0)
2341 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2343 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2347 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2351 if (popr->lmod == OPLM_QWORD && is_stack_access(po, popr)) {
2352 stack_frame_access(po, popr, buf, buf_size,
2353 popr->name, "", is_src, 0);
2359 switch (popr->lmod) {
2367 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2370 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2371 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2375 ferr(po, "invalid float type: %d\n", popr->type);
2381 static char *out_src_opr_float(char *buf, size_t buf_size,
2382 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2384 return out_opr_float(buf, buf_size, po, popr, 1, need_float_stack);
2387 static char *out_dst_opr_float(char *buf, size_t buf_size,
2388 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2390 return out_opr_float(buf, buf_size, po, popr, 0, need_float_stack);
2393 static void out_test_for_cc(char *buf, size_t buf_size,
2394 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2395 enum opr_lenmod lmod, const char *expr)
2397 const char *cast, *scast;
2399 cast = lmod_cast_u(po, lmod);
2400 scast = lmod_cast_s(po, lmod);
2404 case PFO_BE: // CF==1||ZF==1; CF=0
2405 snprintf(buf, buf_size, "(%s%s %s 0)",
2406 cast, expr, is_inv ? "!=" : "==");
2410 case PFO_L: // SF!=OF; OF=0
2411 snprintf(buf, buf_size, "(%s%s %s 0)",
2412 scast, expr, is_inv ? ">=" : "<");
2415 case PFO_LE: // ZF==1||SF!=OF; OF=0
2416 snprintf(buf, buf_size, "(%s%s %s 0)",
2417 scast, expr, is_inv ? ">" : "<=");
2422 snprintf(buf, buf_size, "(%d)", !!is_inv);
2425 case PFO_P: // PF==1
2426 snprintf(buf, buf_size, "(%sdo_parity(%s))",
2427 is_inv ? "!" : "", expr);
2431 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2435 static void out_cmp_for_cc(char *buf, size_t buf_size,
2436 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2439 const char *cast, *scast, *cast_use;
2440 char buf1[256], buf2[256];
2441 enum opr_lenmod lmod;
2443 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2444 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2445 po->operand[0].lmod, po->operand[1].lmod);
2446 lmod = po->operand[0].lmod;
2448 cast = lmod_cast_u(po, lmod);
2449 scast = lmod_cast_s(po, lmod);
2465 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2468 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2469 if (po->op == OP_DEC)
2470 snprintf(buf2, sizeof(buf2), "1");
2473 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2475 strcat(cast_op2, "-");
2476 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2481 // note: must be unsigned compare
2482 snprintf(buf, buf_size, "(%s %s %s)",
2483 buf1, is_inv ? ">=" : "<", buf2);
2487 snprintf(buf, buf_size, "(%s %s %s)",
2488 buf1, is_inv ? "!=" : "==", buf2);
2492 // note: must be unsigned compare
2493 snprintf(buf, buf_size, "(%s %s %s)",
2494 buf1, is_inv ? ">" : "<=", buf2);
2497 if (is_inv && lmod == OPLM_BYTE
2498 && po->operand[1].type == OPT_CONST
2499 && po->operand[1].val == 0xff)
2501 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2502 snprintf(buf, buf_size, "(0)");
2506 // note: must be signed compare
2508 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2509 scast, buf1, buf2, is_inv ? ">=" : "<");
2513 snprintf(buf, buf_size, "(%s %s %s)",
2514 buf1, is_inv ? ">=" : "<", buf2);
2518 snprintf(buf, buf_size, "(%s %s %s)",
2519 buf1, is_inv ? ">" : "<=", buf2);
2527 static void out_cmp_test(char *buf, size_t buf_size,
2528 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2530 char buf1[256], buf2[256], buf3[256];
2532 if (po->op == OP_TEST) {
2533 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2534 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2537 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2538 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2539 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2541 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2542 po->operand[0].lmod, buf3);
2544 else if (po->op == OP_CMP) {
2545 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2548 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2551 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2552 struct parsed_opr *popr2)
2554 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2555 ferr(po, "missing lmod for both operands\n");
2557 if (popr1->lmod == OPLM_UNSPEC)
2558 popr1->lmod = popr2->lmod;
2559 else if (popr2->lmod == OPLM_UNSPEC)
2560 popr2->lmod = popr1->lmod;
2561 else if (popr1->lmod != popr2->lmod) {
2562 if (popr1->type_from_var) {
2563 popr1->size_mismatch = 1;
2564 if (popr1->lmod < popr2->lmod)
2566 popr1->lmod = popr2->lmod;
2568 else if (popr2->type_from_var) {
2569 popr2->size_mismatch = 1;
2570 if (popr2->lmod < popr1->lmod)
2572 popr2->lmod = popr1->lmod;
2575 ferr(po, "conflicting lmods: %d vs %d\n",
2576 popr1->lmod, popr2->lmod);
2580 static const char *op_to_c(struct parsed_op *po)
2604 ferr(po, "op_to_c was supplied with %d\n", po->op);
2608 // last op in stream - unconditional branch or ret
2609 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2610 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2611 && ops[_i].op != OP_CALL))
2613 #define check_i(po, i) \
2615 ferr(po, "bad " #i ": %d\n", i)
2617 // note: this skips over calls and rm'd stuff assuming they're handled
2618 // so it's intended to use at one of final passes
2619 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2620 int depth, int seen_noreturn, int flags_set)
2622 struct parsed_op *po;
2627 for (; i < opcnt; i++) {
2629 if (po->cc_scratch == magic)
2630 return ret; // already checked
2631 po->cc_scratch = magic;
2633 if (po->flags & OPF_TAIL) {
2634 if (po->op == OP_CALL) {
2635 if (po->pp != NULL && po->pp->is_noreturn)
2644 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2647 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2648 if (po->btj != NULL) {
2650 for (j = 0; j < po->btj->count; j++) {
2651 check_i(po, po->btj->d[j].bt_i);
2652 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2653 depth, seen_noreturn, flags_set);
2655 return ret; // dead end
2660 check_i(po, po->bt_i);
2661 if (po->flags & OPF_CJMP) {
2662 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2663 depth, seen_noreturn, flags_set);
2665 return ret; // dead end
2674 if ((po->op == OP_POP || po->op == OP_PUSH)
2675 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2680 if (po->op == OP_PUSH) {
2683 else if (po->op == OP_POP) {
2684 if (relevant && depth == 0) {
2685 po->flags |= flags_set;
2693 // for noreturn, assume msvc skipped stack cleanup
2694 return seen_noreturn ? 1 : -1;
2697 // scan for 'reg' pop backwards starting from i
2698 // intended to use for register restore search, so other reg
2699 // references are considered an error
2700 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2702 struct parsed_op *po;
2703 struct label_ref *lr;
2706 ops[i].cc_scratch = magic;
2710 if (g_labels[i] != NULL) {
2711 lr = &g_label_refs[i];
2712 for (; lr != NULL; lr = lr->next) {
2713 check_i(&ops[i], lr->i);
2714 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2718 if (i > 0 && LAST_OP(i - 1))
2726 if (ops[i].cc_scratch == magic)
2728 ops[i].cc_scratch = magic;
2731 if (po->op == OP_POP && po->operand[0].reg == reg) {
2732 if (po->flags & (OPF_RMD|OPF_DONE))
2735 po->flags |= set_flags;
2739 // this also covers the case where we reach corresponding push
2740 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2744 // nothing interesting on this path,
2745 // still return ret for something recursive calls could find
2749 static void find_reachable_exits(int i, int opcnt, int magic,
2750 int *exits, int *exit_count)
2752 struct parsed_op *po;
2755 for (; i < opcnt; i++)
2758 if (po->cc_scratch == magic)
2760 po->cc_scratch = magic;
2762 if (po->flags & OPF_TAIL) {
2763 ferr_assert(po, *exit_count < MAX_EXITS);
2764 exits[*exit_count] = i;
2769 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2770 if (po->flags & OPF_RMD)
2773 if (po->btj != NULL) {
2774 for (j = 0; j < po->btj->count; j++) {
2775 check_i(po, po->btj->d[j].bt_i);
2776 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2782 check_i(po, po->bt_i);
2783 if (po->flags & OPF_CJMP)
2784 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2792 // scan for 'reg' pop backwards starting from exits (all paths)
2793 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2795 static int exits[MAX_EXITS];
2796 static int exit_count;
2802 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2804 ferr_assert(&ops[i], exit_count > 0);
2807 for (j = 0; j < exit_count; j++) {
2809 ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2815 if (ops[e].op == OP_CALL && ops[e].pp != NULL
2816 && ops[e].pp->is_noreturn)
2818 // assume stack cleanup was skipped
2827 // scan for one or more pop of push <const>
2828 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2829 int push_i, int is_probe)
2831 struct parsed_op *po;
2832 struct label_ref *lr;
2836 for (; i < opcnt; i++)
2839 if (po->cc_scratch == magic)
2840 return ret; // already checked
2841 po->cc_scratch = magic;
2843 if (po->flags & OPF_JMP) {
2844 if (po->flags & OPF_RMD)
2846 if (po->op == OP_CALL)
2849 if (po->btj != NULL) {
2850 for (j = 0; j < po->btj->count; j++) {
2851 check_i(po, po->btj->d[j].bt_i);
2852 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2860 check_i(po, po->bt_i);
2861 if (po->flags & OPF_CJMP) {
2862 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2873 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2876 if (g_labels[i] != NULL) {
2877 // all refs must be visited
2878 lr = &g_label_refs[i];
2879 for (; lr != NULL; lr = lr->next) {
2881 if (ops[lr->i].cc_scratch != magic)
2884 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2888 if (po->op == OP_POP)
2890 if (po->flags & (OPF_RMD|OPF_DONE))
2894 po->flags |= OPF_DONE;
2895 po->datap = &ops[push_i];
2904 static void scan_for_pop_const(int i, int opcnt, int magic)
2908 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2910 ops[i].flags |= OPF_RMD | OPF_DONE;
2911 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2915 // check if all branch targets within a marked path are also marked
2916 // note: the path checked must not be empty or end with a branch
2917 static int check_path_branches(int opcnt, int magic)
2919 struct parsed_op *po;
2922 for (i = 0; i < opcnt; i++) {
2924 if (po->cc_scratch != magic)
2927 if (po->flags & OPF_JMP) {
2928 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2931 if (po->btj != NULL) {
2932 for (j = 0; j < po->btj->count; j++) {
2933 check_i(po, po->btj->d[j].bt_i);
2934 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2939 check_i(po, po->bt_i);
2940 if (ops[po->bt_i].cc_scratch != magic)
2942 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2950 // scan for multiple pushes for given pop
2951 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2954 int reg = ops[pop_i].operand[0].reg;
2955 struct parsed_op *po;
2956 struct label_ref *lr;
2959 ops[i].cc_scratch = magic;
2963 if (g_labels[i] != NULL) {
2964 lr = &g_label_refs[i];
2965 for (; lr != NULL; lr = lr->next) {
2966 check_i(&ops[i], lr->i);
2967 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2971 if (i > 0 && LAST_OP(i - 1))
2979 if (ops[i].cc_scratch == magic)
2981 ops[i].cc_scratch = magic;
2984 if (po->op == OP_CALL)
2986 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2989 if (po->op == OP_PUSH)
2991 if (po->datap != NULL)
2993 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2994 // leave this case for reg save/restore handlers
2998 po->flags |= OPF_PPUSH | OPF_DONE;
2999 po->datap = &ops[pop_i];
3008 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
3010 int magic = i + opcnt * 14;
3013 ret = scan_pushes_for_pop_r(i, magic, i, 1);
3015 ret = check_path_branches(opcnt, magic);
3017 ops[i].flags |= OPF_PPUSH | OPF_DONE;
3018 *regmask_pp |= 1 << ops[i].operand[0].reg;
3019 scan_pushes_for_pop_r(i, magic + 1, i, 0);
3024 static void scan_propagate_df(int i, int opcnt)
3026 struct parsed_op *po = &ops[i];
3029 for (; i < opcnt; i++) {
3031 if (po->flags & OPF_DF)
3032 return; // already resolved
3033 po->flags |= OPF_DF;
3035 if (po->op == OP_CALL)
3036 ferr(po, "call with DF set?\n");
3038 if (po->flags & OPF_JMP) {
3039 if (po->btj != NULL) {
3041 for (j = 0; j < po->btj->count; j++) {
3042 check_i(po, po->btj->d[j].bt_i);
3043 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
3048 if (po->flags & OPF_RMD)
3050 check_i(po, po->bt_i);
3051 if (po->flags & OPF_CJMP)
3052 scan_propagate_df(po->bt_i, opcnt);
3058 if (po->flags & OPF_TAIL)
3061 if (po->op == OP_CLD) {
3062 po->flags |= OPF_RMD | OPF_DONE;
3067 ferr(po, "missing DF clear?\n");
3070 // is operand 'opr' referenced by parsed_op 'po'?
3071 static int is_opr_referenced(const struct parsed_opr *opr,
3072 const struct parsed_op *po)
3076 if (opr->type == OPT_REG) {
3077 mask = po->regmask_dst | po->regmask_src;
3078 if (po->op == OP_CALL)
3079 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3080 if ((1 << opr->reg) & mask)
3086 for (i = 0; i < po->operand_cnt; i++)
3087 if (IS(po->operand[0].name, opr->name))
3093 // is operand 'opr' read by parsed_op 'po'?
3094 static int is_opr_read(const struct parsed_opr *opr,
3095 const struct parsed_op *po)
3097 if (opr->type == OPT_REG) {
3098 if (po->regmask_src & (1 << opr->reg))
3108 // is operand 'opr' modified by parsed_op 'po'?
3109 static int is_opr_modified(const struct parsed_opr *opr,
3110 const struct parsed_op *po)
3114 if (opr->type == OPT_REG) {
3115 if (po->op == OP_CALL) {
3116 mask = po->regmask_dst;
3117 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3118 if (mask & (1 << opr->reg))
3124 if (po->regmask_dst & (1 << opr->reg))
3130 return IS(po->operand[0].name, opr->name);
3133 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3134 static int is_any_opr_modified(const struct parsed_op *po_test,
3135 const struct parsed_op *po, int c_mode)
3140 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3143 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3146 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3149 // in reality, it can wreck any register, but in decompiled C
3150 // version it can only overwrite eax or edx:eax
3151 mask = (1 << xAX) | (1 << xDX);
3155 if (po->op == OP_CALL
3156 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3159 for (i = 0; i < po_test->operand_cnt; i++)
3160 if (IS(po_test->operand[i].name, po->operand[0].name))
3166 // scan for any po_test operand modification in range given
3167 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3170 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3173 for (; i < opcnt; i++) {
3174 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3181 // scan for po_test operand[0] modification in range given
3182 static int scan_for_mod_opr0(struct parsed_op *po_test,
3185 for (; i < opcnt; i++) {
3186 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3193 static int try_resolve_const(int i, const struct parsed_opr *opr,
3194 int magic, unsigned int *val);
3196 static int scan_for_flag_set(int i, int opcnt, int magic,
3197 int *branched, int *setters, int *setter_cnt)
3199 struct label_ref *lr;
3203 if (ops[i].cc_scratch == magic) {
3204 // is this a problem?
3205 //ferr(&ops[i], "%s looped\n", __func__);
3208 ops[i].cc_scratch = magic;
3210 if (g_labels[i] != NULL) {
3213 lr = &g_label_refs[i];
3214 for (; lr->next; lr = lr->next) {
3215 check_i(&ops[i], lr->i);
3216 ret = scan_for_flag_set(lr->i, opcnt, magic,
3217 branched, setters, setter_cnt);
3222 check_i(&ops[i], lr->i);
3223 if (i > 0 && LAST_OP(i - 1)) {
3227 ret = scan_for_flag_set(lr->i, opcnt, magic,
3228 branched, setters, setter_cnt);
3234 if (ops[i].flags & OPF_FLAGS) {
3235 setters[*setter_cnt] = i;
3238 if (ops[i].flags & OPF_REP) {
3239 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3242 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3243 if (ret != 1 || uval == 0) {
3244 // can't treat it as full setter because of ecx=0 case,
3245 // also disallow delayed compare
3254 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3261 // scan back for cdq, if anything modifies edx, fail
3262 static int scan_for_cdq_edx(int i)
3265 if (g_labels[i] != NULL) {
3266 if (g_label_refs[i].next != NULL)
3268 if (i > 0 && LAST_OP(i - 1)) {
3269 i = g_label_refs[i].i;
3276 if (ops[i].op == OP_CDQ)
3279 if (ops[i].regmask_dst & (1 << xDX))
3286 static int scan_for_reg_clear(int i, int reg)
3289 if (g_labels[i] != NULL) {
3290 if (g_label_refs[i].next != NULL)
3292 if (i > 0 && LAST_OP(i - 1)) {
3293 i = g_label_refs[i].i;
3300 if (ops[i].op == OP_XOR
3301 && ops[i].operand[0].lmod == OPLM_DWORD
3302 && ops[i].operand[0].reg == ops[i].operand[1].reg
3303 && ops[i].operand[0].reg == reg)
3306 if (ops[i].regmask_dst & (1 << reg))
3313 static void patch_esp_adjust(struct parsed_op *po, int adj)
3315 ferr_assert(po, po->op == OP_ADD);
3316 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3317 ferr_assert(po, po->operand[1].type == OPT_CONST);
3319 // this is a bit of a hack, but deals with use of
3320 // single adj for multiple calls
3321 po->operand[1].val -= adj;
3322 po->flags |= OPF_RMD;
3323 if (po->operand[1].val == 0)
3324 po->flags |= OPF_DONE;
3325 ferr_assert(po, (int)po->operand[1].val >= 0);
3328 // scan for positive, constant esp adjust
3329 // multipath case is preliminary
3330 static int scan_for_esp_adjust(int i, int opcnt,
3331 int adj_expect, int *adj, int *is_multipath, int do_update)
3333 int adj_expect_unknown = 0;
3334 struct parsed_op *po;
3338 *adj = *is_multipath = 0;
3339 if (adj_expect < 0) {
3340 adj_expect_unknown = 1;
3341 adj_expect = 32 * 4; // enough?
3344 for (; i < opcnt && *adj < adj_expect; i++) {
3345 if (g_labels[i] != NULL)
3349 if (po->flags & OPF_DONE)
3352 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3353 if (po->operand[1].type != OPT_CONST)
3354 ferr(&ops[i], "non-const esp adjust?\n");
3355 *adj += po->operand[1].val;
3357 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3360 patch_esp_adjust(po, adj_expect);
3362 po->flags |= OPF_RMD;
3366 else if (po->op == OP_PUSH) {
3367 //if (first_pop == -1)
3368 // first_pop = -2; // none
3369 *adj -= lmod_bytes(po, po->operand[0].lmod);
3371 else if (po->op == OP_POP) {
3372 if (!(po->flags & OPF_DONE)) {
3373 // seems like msvc only uses 'pop ecx' for stack realignment..
3374 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3376 if (first_pop == -1 && *adj >= 0)
3379 if (do_update && *adj >= 0) {
3380 po->flags |= OPF_RMD;
3382 po->flags |= OPF_DONE | OPF_NOREGS;
3385 *adj += lmod_bytes(po, po->operand[0].lmod);
3386 if (*adj > adj_best)
3389 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3390 if (po->op == OP_JMP && po->btj == NULL) {
3396 if (po->op != OP_CALL)
3398 if (po->operand[0].type != OPT_LABEL)
3400 if (po->pp != NULL && po->pp->is_stdcall)
3402 if (adj_expect_unknown && first_pop >= 0)
3404 // assume it's another cdecl call
3408 if (first_pop >= 0) {
3409 // probably only 'pop ecx' was used
3417 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3419 struct parsed_op *po;
3423 ferr(ops, "%s: followed bad branch?\n", __func__);
3425 for (; i < opcnt; i++) {
3427 if (po->cc_scratch == magic)
3429 po->cc_scratch = magic;
3432 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3433 if (po->btj != NULL) {
3435 for (j = 0; j < po->btj->count; j++)
3436 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3440 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3441 if (!(po->flags & OPF_CJMP))
3444 if (po->flags & OPF_TAIL)
3449 static const struct parsed_proto *try_recover_pp(
3450 struct parsed_op *po, const struct parsed_opr *opr,
3451 int is_call, int *search_instead)
3453 const struct parsed_proto *pp = NULL;
3457 // maybe an arg of g_func?
3458 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3460 char ofs_reg[16] = { 0, };
3461 int arg, arg_s, arg_i;
3468 parse_stack_access(po, opr->name, ofs_reg,
3469 &offset, &stack_ra, NULL, 0);
3470 if (ofs_reg[0] != 0)
3471 ferr(po, "offset reg on arg access?\n");
3472 if (offset <= stack_ra) {
3473 // search who set the stack var instead
3474 if (search_instead != NULL)
3475 *search_instead = 1;
3479 arg_i = (offset - stack_ra - 4) / 4;
3480 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3481 if (g_func_pp->arg[arg].reg != NULL)
3487 if (arg == g_func_pp->argc)
3488 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3490 pp = g_func_pp->arg[arg].pp;
3493 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3494 check_func_pp(po, pp, "icall arg");
3497 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3499 p = strchr(opr->name + 1, '[');
3500 memcpy(buf, opr->name, p - opr->name);
3501 buf[p - opr->name] = 0;
3502 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3504 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3505 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3508 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3511 check_func_pp(po, pp, "reg-fptr ref");
3517 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3518 int magic, const struct parsed_proto **pp_found, int *pp_i,
3521 const struct parsed_proto *pp = NULL;
3522 struct parsed_op *po;
3523 struct label_ref *lr;
3525 ops[i].cc_scratch = magic;
3528 if (g_labels[i] != NULL) {
3529 lr = &g_label_refs[i];
3530 for (; lr != NULL; lr = lr->next) {
3531 check_i(&ops[i], lr->i);
3532 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3534 if (i > 0 && LAST_OP(i - 1))
3542 if (ops[i].cc_scratch == magic)
3544 ops[i].cc_scratch = magic;
3546 if (!(ops[i].flags & OPF_DATA))
3548 if (!is_opr_modified(opr, &ops[i]))
3550 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3551 // most probably trashed by some processing
3556 opr = &ops[i].operand[1];
3557 if (opr->type != OPT_REG)
3561 po = (i >= 0) ? &ops[i] : ops;
3564 // reached the top - can only be an arg-reg
3565 if (opr->type != OPT_REG || g_func_pp == NULL)
3568 for (i = 0; i < g_func_pp->argc; i++) {
3569 if (g_func_pp->arg[i].reg == NULL)
3571 if (IS(opr->name, g_func_pp->arg[i].reg))
3574 if (i == g_func_pp->argc)
3576 pp = g_func_pp->arg[i].pp;
3578 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3579 i + 1, g_func_pp->arg[i].reg);
3580 check_func_pp(po, pp, "icall reg-arg");
3583 pp = try_recover_pp(po, opr, 1, NULL);
3585 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3586 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3587 || (*pp_found)->is_stdcall != pp->is_stdcall
3588 //|| (*pp_found)->is_fptr != pp->is_fptr
3589 || (*pp_found)->argc != pp->argc
3590 || (*pp_found)->argc_reg != pp->argc_reg
3591 || (*pp_found)->argc_stack != pp->argc_stack)
3593 ferr(po, "icall: parsed_proto mismatch\n");
3603 static void add_label_ref(struct label_ref *lr, int op_i)
3605 struct label_ref *lr_new;
3612 lr_new = calloc(1, sizeof(*lr_new));
3614 lr_new->next = lr->next;
3618 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3620 struct parsed_op *po = &ops[i];
3621 struct parsed_data *pd;
3622 char label[NAMELEN], *p;
3625 p = strchr(po->operand[0].name, '[');
3629 len = p - po->operand[0].name;
3630 strncpy(label, po->operand[0].name, len);
3633 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3634 if (IS(g_func_pd[j].label, label)) {
3640 //ferr(po, "label '%s' not parsed?\n", label);
3643 if (pd->type != OPT_OFFSET)
3644 ferr(po, "label '%s' with non-offset data?\n", label);
3646 // find all labels, link
3647 for (j = 0; j < pd->count; j++) {
3648 for (l = 0; l < opcnt; l++) {
3649 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3650 add_label_ref(&g_label_refs[l], i);
3660 static void clear_labels(int count)
3664 for (i = 0; i < count; i++) {
3665 if (g_labels[i] != NULL) {
3672 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3677 for (i = 0; i < pp->argc; i++) {
3678 if (pp->arg[i].reg != NULL) {
3679 reg = char_array_i(regs_r32,
3680 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3682 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3683 pp->arg[i].reg, pp->name);
3684 regmask |= 1 << reg;
3691 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3696 if (pp->has_retreg) {
3697 for (i = 0; i < pp->argc; i++) {
3698 if (pp->arg[i].type.is_retreg) {
3699 reg = char_array_i(regs_r32,
3700 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3701 ferr_assert(ops, reg >= 0);
3702 regmask |= 1 << reg;
3707 if (strstr(pp->ret_type.name, "int64"))
3708 return regmask | (1 << xAX) | (1 << xDX);
3709 if (IS(pp->ret_type.name, "float")
3710 || IS(pp->ret_type.name, "double"))
3712 return regmask | mxST0;
3714 if (strcasecmp(pp->ret_type.name, "void") == 0)
3717 return regmask | mxAX;
3720 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3722 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3723 && memcmp(po1->operand, po2->operand,
3724 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3727 static void resolve_branches_parse_calls(int opcnt)
3729 static const struct {
3733 unsigned int regmask_src;
3734 unsigned int regmask_dst;
3736 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3737 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3738 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3739 // more precise? Wine gets away with just __ftol handler
3740 { "__ftol2", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3741 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3743 const struct parsed_proto *pp_c;
3744 struct parsed_proto *pp;
3745 struct parsed_data *pd;
3746 struct parsed_op *po;
3747 const char *tmpname;
3752 for (i = 0; i < opcnt; i++)
3758 if (po->datap != NULL) {
3759 pp = calloc(1, sizeof(*pp));
3760 my_assert_not(pp, NULL);
3762 ret = parse_protostr(po->datap, pp);
3764 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3770 if (po->op == OP_CALL) {
3775 else if (po->operand[0].type == OPT_LABEL)
3777 tmpname = opr_name(po, 0);
3778 if (IS_START(tmpname, "loc_"))
3779 ferr(po, "call to loc_*\n");
3780 if (IS(tmpname, "__alloca_probe"))
3782 if (IS(tmpname, "__SEH_prolog")) {
3783 ferr_assert(po, g_seh_found == 0);
3787 if (IS(tmpname, "__SEH_epilog"))
3790 // convert some calls to pseudo-ops
3791 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3792 if (!IS(tmpname, pseudo_ops[l].name))
3795 po->op = pseudo_ops[l].op;
3796 po->operand_cnt = 0;
3797 po->regmask_src = pseudo_ops[l].regmask_src;
3798 po->regmask_dst = pseudo_ops[l].regmask_dst;
3799 po->flags = pseudo_ops[l].flags;
3800 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3803 if (l < ARRAY_SIZE(pseudo_ops))
3806 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3807 if (!g_header_mode && pp_c == NULL)
3808 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3811 pp = proto_clone(pp_c);
3812 my_assert_not(pp, NULL);
3818 check_func_pp(po, pp, "fptr var call");
3819 if (pp->is_noreturn) {
3820 po->flags |= OPF_TAIL;
3821 po->flags &= ~OPF_ATAIL; // most likely...
3828 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3831 if (po->operand[0].type == OPT_REGMEM) {
3832 pd = try_resolve_jumptab(i, opcnt);
3840 for (l = 0; l < opcnt; l++) {
3841 if (g_labels[l] != NULL
3842 && IS(po->operand[0].name, g_labels[l]))
3844 if (l == i + 1 && po->op == OP_JMP) {
3845 // yet another alignment type..
3846 po->flags |= OPF_RMD|OPF_DONE;
3849 add_label_ref(&g_label_refs[l], i);
3855 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3858 if (po->operand[0].type == OPT_LABEL)
3862 ferr(po, "unhandled branch\n");
3866 po->flags |= OPF_TAIL;
3867 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3868 if (prev_op == OP_POP)
3869 po->flags |= OPF_ATAIL;
3870 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3871 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3873 po->flags |= OPF_ATAIL;
3879 static int resolve_origin(int i, const struct parsed_opr *opr,
3880 int magic, int *op_i, int *is_caller);
3882 static void eliminate_seh_writes(int opcnt)
3884 const struct parsed_opr *opr;
3889 // assume all sf writes above g_seh_size to be seh related
3890 // (probably unsafe but oh well)
3891 for (i = 0; i < opcnt; i++) {
3892 if (ops[i].op != OP_MOV)
3894 opr = &ops[i].operand[0];
3895 if (opr->type != OPT_REGMEM)
3897 if (!is_stack_access(&ops[i], opr))
3901 parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
3903 if (offset < 0 && offset >= -g_seh_size)
3904 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3908 static void eliminate_seh(int opcnt)
3912 for (i = 0; i < opcnt; i++) {
3913 if (ops[i].op != OP_MOV)
3915 if (ops[i].operand[0].segment != SEG_FS)
3917 if (!IS(opr_name(&ops[i], 0), "0"))
3920 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3921 if (ops[i].operand[1].reg == xSP) {
3922 for (j = i - 1; j >= 0; j--) {
3923 if (ops[j].op != OP_PUSH)
3925 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3927 if (ops[j].operand[0].val == ~0)
3929 if (ops[j].operand[0].type == OPT_REG) {
3931 ret = resolve_origin(j, &ops[j].operand[0],
3932 j + opcnt * 22, &k, NULL);
3934 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3938 ferr(ops, "missing seh terminator\n");
3942 ret = resolve_origin(i, &ops[i].operand[1],
3943 i + opcnt * 23, &k, NULL);
3945 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3949 eliminate_seh_writes(opcnt);
3952 static void eliminate_seh_calls(int opcnt)
3954 int epilog_found = 0;
3961 ferr_assert(&ops[i], ops[i].op == OP_PUSH
3962 && ops[i].operand[0].type == OPT_CONST);
3963 g_stack_fsz = g_seh_size + ops[i].operand[0].val;
3964 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3967 ferr_assert(&ops[i], ops[i].op == OP_PUSH
3968 && ops[i].operand[0].type == OPT_OFFSET);
3969 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3972 ferr_assert(&ops[i], ops[i].op == OP_CALL
3973 && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
3974 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3976 for (i++; i < opcnt; i++) {
3977 if (ops[i].op != OP_CALL)
3979 if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
3982 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3985 ferr_assert(ops, epilog_found);
3987 eliminate_seh_writes(opcnt);
3990 static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
3994 for (; i < opcnt; i++)
3995 if (!(ops[i].flags & OPF_DONE))
3998 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3999 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4005 for (; i < opcnt; i++) {
4006 if (i > 0 && g_labels[i] != NULL)
4008 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
4010 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4011 && ops[i].operand[1].type == OPT_CONST)
4013 g_stack_fsz += opr_const(&ops[i], 1);
4014 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4019 if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4020 && ops[i].operand[1].type == OPT_CONST)
4022 for (j = i + 1; j < opcnt; j++)
4023 if (!(ops[j].flags & OPF_DONE))
4025 if (ops[j].op == OP_CALL
4026 && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4028 g_stack_fsz += opr_const(&ops[i], 1);
4029 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4030 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4041 static void scan_prologue_epilogue(int opcnt, int *stack_align)
4043 int ecx_push = 0, esp_sub = 0, pusha = 0;
4044 int sandard_epilogue;
4048 if (g_seh_found == 2) {
4049 eliminate_seh_calls(opcnt);
4053 eliminate_seh(opcnt);
4054 // ida treats seh as part of sf
4055 g_stack_fsz = g_seh_size;
4059 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4060 && ops[1].op == OP_MOV
4061 && IS(opr_name(&ops[1], 0), "ebp")
4062 && IS(opr_name(&ops[1], 1), "esp"))
4065 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4066 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4068 for (i = 2; i < opcnt; i++)
4069 if (!(ops[i].flags & OPF_DONE))
4072 if (ops[i].op == OP_PUSHA) {
4073 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4078 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4079 && ops[i].operand[1].type == OPT_CONST)
4081 l = ops[i].operand[1].val;
4083 if (j == -1 || (l >> j) != -1)
4084 ferr(&ops[i], "unhandled esp align: %x\n", l);
4085 if (stack_align != NULL)
4086 *stack_align = 1 << j;
4087 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4091 i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4095 for (; i < opcnt; i++)
4096 if (ops[i].flags & OPF_TAIL)
4099 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4100 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4106 sandard_epilogue = 0;
4107 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4109 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4110 // the standard epilogue is sometimes even used without a sf
4111 if (ops[j - 1].op == OP_MOV
4112 && IS(opr_name(&ops[j - 1], 0), "esp")
4113 && IS(opr_name(&ops[j - 1], 1), "ebp"))
4114 sandard_epilogue = 1;
4116 else if (ops[j].op == OP_LEAVE)
4118 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4119 sandard_epilogue = 1;
4121 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4122 && ops[i].pp->is_noreturn)
4124 // on noreturn, msvc sometimes cleans stack, sometimes not
4129 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4130 ferr(&ops[j], "'pop ebp' expected\n");
4132 if (g_stack_fsz != 0 || sandard_epilogue) {
4133 if (ops[j].op == OP_LEAVE)
4135 else if (sandard_epilogue) // mov esp, ebp
4137 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4140 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4142 ferr(&ops[j], "esp restore expected\n");
4145 if (ecx_push && j >= 0 && ops[j].op == OP_POP
4146 && IS(opr_name(&ops[j], 0), "ecx"))
4148 ferr(&ops[j], "unexpected ecx pop\n");
4153 if (ops[j].op == OP_POPA)
4154 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4156 ferr(&ops[j], "popa expected\n");
4161 } while (i < opcnt);
4164 ferr(ops, "missing ebp epilogue\n");
4169 i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4171 if (ecx_push && !esp_sub) {
4172 // could actually be args for a call..
4173 for (; i < opcnt; i++)
4174 if (ops[i].op != OP_PUSH)
4177 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4178 const struct parsed_proto *pp;
4179 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4180 j = pp ? pp->argc_stack : 0;
4181 while (i > 0 && j > 0) {
4183 if (ops[i].op == OP_PUSH) {
4184 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4189 ferr(&ops[i], "unhandled prologue\n");
4193 g_stack_fsz = g_seh_size;
4194 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4195 if (!(ops[i].flags & OPF_RMD))
4205 if (ecx_push || esp_sub)
4210 for (; i < opcnt; i++)
4211 if (ops[i].flags & OPF_TAIL)
4215 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4216 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4221 else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4222 // skip arg updates for arg-reuse tailcall
4223 for (; j >= 0; j--) {
4224 if (ops[j].op != OP_MOV)
4226 if (ops[j].operand[0].type != OPT_REGMEM)
4228 if (strstr(ops[j].operand[0].name, "arg_") == NULL)
4233 if (ecx_push > 0 && !esp_sub) {
4234 for (l = 0; l < ecx_push && j >= 0; l++) {
4235 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4237 else if (ops[j].op == OP_ADD
4238 && IS(opr_name(&ops[j], 0), "esp")
4239 && ops[j].operand[1].type == OPT_CONST)
4242 l += ops[j].operand[1].val / 4 - 1;
4247 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4250 if (l != ecx_push) {
4251 if (i < opcnt && ops[i].op == OP_CALL
4252 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4254 // noreturn tailcall with no epilogue
4259 ferr(&ops[j], "epilogue scan failed\n");
4266 if (ops[j].op != OP_ADD
4267 || !IS(opr_name(&ops[j], 0), "esp")
4268 || ops[j].operand[1].type != OPT_CONST)
4270 if (i < opcnt && ops[i].op == OP_CALL
4271 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4273 // noreturn tailcall with no epilogue
4278 ferr(&ops[j], "'add esp' expected\n");
4281 if (ops[j].operand[1].val < g_stack_fsz)
4282 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4284 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4285 if (ops[j].operand[1].val == 0)
4286 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4291 } while (i < opcnt);
4294 ferr(ops, "missing esp epilogue\n");
4298 // find an instruction that changed opr before i op
4299 // *op_i must be set to -1 by the caller
4300 // *is_caller is set to 1 if one source is determined to be g_func arg
4301 // returns 1 if found, *op_i is then set to origin
4302 // returns -1 if multiple origins are found
4303 static int resolve_origin(int i, const struct parsed_opr *opr,
4304 int magic, int *op_i, int *is_caller)
4306 struct label_ref *lr;
4310 if (g_labels[i] != NULL) {
4311 lr = &g_label_refs[i];
4312 for (; lr != NULL; lr = lr->next) {
4313 check_i(&ops[i], lr->i);
4314 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4316 if (i > 0 && LAST_OP(i - 1))
4322 if (is_caller != NULL)
4327 if (ops[i].cc_scratch == magic)
4329 ops[i].cc_scratch = magic;
4331 if (!(ops[i].flags & OPF_DATA))
4333 if (!is_opr_modified(opr, &ops[i]))
4337 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4348 // find an instruction that previously referenced opr
4349 // if multiple results are found - fail
4350 // *op_i must be set to -1 by the caller
4351 // returns 1 if found, *op_i is then set to referencer insn
4352 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4353 int magic, int *op_i)
4355 struct label_ref *lr;
4359 if (g_labels[i] != NULL) {
4360 lr = &g_label_refs[i];
4361 for (; lr != NULL; lr = lr->next) {
4362 check_i(&ops[i], lr->i);
4363 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4365 if (i > 0 && LAST_OP(i - 1))
4373 if (ops[i].cc_scratch == magic)
4375 ops[i].cc_scratch = magic;
4377 if (!is_opr_referenced(opr, &ops[i]))
4388 // adjust datap of all reachable 'op' insns when moving back
4389 // returns 1 if at least 1 op was found
4390 // returns -1 if path without an op was found
4391 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4393 struct label_ref *lr;
4396 if (ops[i].cc_scratch == magic)
4398 ops[i].cc_scratch = magic;
4401 if (g_labels[i] != NULL) {
4402 lr = &g_label_refs[i];
4403 for (; lr != NULL; lr = lr->next) {
4404 check_i(&ops[i], lr->i);
4405 ret |= adjust_prev_op(lr->i, op, magic, datap);
4407 if (i > 0 && LAST_OP(i - 1))
4415 if (ops[i].cc_scratch == magic)
4417 ops[i].cc_scratch = magic;
4419 if (ops[i].op != op)
4422 ops[i].datap = datap;
4427 // find next instruction that reads opr
4428 // *op_i must be set to -1 by the caller
4429 // on return, *op_i is set to first referencer insn
4430 // returns 1 if exactly 1 referencer is found
4431 static int find_next_read(int i, int opcnt,
4432 const struct parsed_opr *opr, int magic, int *op_i)
4434 struct parsed_op *po;
4437 for (; i < opcnt; i++)
4439 if (ops[i].cc_scratch == magic)
4441 ops[i].cc_scratch = magic;
4444 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4445 if (po->btj != NULL) {
4447 for (j = 0; j < po->btj->count; j++) {
4448 check_i(po, po->btj->d[j].bt_i);
4449 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4455 if (po->flags & OPF_RMD)
4457 check_i(po, po->bt_i);
4458 if (po->flags & OPF_CJMP) {
4459 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4468 if (!is_opr_read(opr, po)) {
4470 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4471 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4473 full_opr = po->operand[0].lmod >= opr->lmod;
4475 if (is_opr_modified(opr, po) && full_opr) {
4479 if (po->flags & OPF_TAIL)
4494 // find next instruction that reads opr
4495 // *op_i must be set to -1 by the caller
4496 // on return, *op_i is set to first flag user insn
4497 // returns 1 if exactly 1 flag user is found
4498 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4500 struct parsed_op *po;
4503 for (; i < opcnt; i++)
4505 if (ops[i].cc_scratch == magic)
4507 ops[i].cc_scratch = magic;
4510 if (po->op == OP_CALL)
4512 if (po->flags & OPF_JMP) {
4513 if (po->btj != NULL) {
4515 for (j = 0; j < po->btj->count; j++) {
4516 check_i(po, po->btj->d[j].bt_i);
4517 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4523 if (po->flags & OPF_RMD)
4525 check_i(po, po->bt_i);
4526 if (po->flags & OPF_CJMP)
4533 if (!(po->flags & OPF_CC)) {
4534 if (po->flags & OPF_FLAGS)
4537 if (po->flags & OPF_TAIL)
4553 static int try_resolve_const(int i, const struct parsed_opr *opr,
4554 int magic, unsigned int *val)
4559 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4562 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4565 *val = ops[i].operand[1].val;
4572 static int resolve_used_bits(int i, int opcnt, int reg,
4573 int *mask, int *is_z_check)
4575 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4579 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4583 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4585 fnote(&ops[j], "(first read)\n");
4586 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4589 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4590 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4592 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4593 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4595 *mask = ops[j].operand[1].val;
4596 if (ops[j].operand[0].lmod == OPLM_BYTE
4597 && ops[j].operand[0].name[1] == 'h')
4601 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4604 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4606 *is_z_check = ops[k].pfo == PFO_Z;
4611 static const struct parsed_proto *resolve_deref(int i, int magic,
4612 struct parsed_opr *opr, int level)
4614 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4615 const struct parsed_proto *pp = NULL;
4616 int from_caller = 0;
4625 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4626 if (ret != 2 || len != strlen(opr->name)) {
4627 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4628 if (ret != 1 || len != strlen(opr->name))
4632 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4637 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4641 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4642 && strlen(ops[j].operand[1].name) == 3
4643 && ops[j].operand[0].lmod == OPLM_DWORD
4644 && ops[j].pp == NULL // no hint
4647 // allow one simple dereference (com/directx)
4648 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4649 ops[j].operand[1].name);
4653 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4658 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4661 if (ops[j].pp != NULL) {
4665 else if (ops[j].operand[1].type == OPT_REGMEM) {
4666 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4668 // maybe structure ptr in structure
4669 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4672 else if (ops[j].operand[1].type == OPT_LABEL)
4673 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4674 else if (ops[j].operand[1].type == OPT_REG) {
4677 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4679 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4680 for (k = 0; k < g_func_pp->argc; k++) {
4681 if (g_func_pp->arg[k].reg == NULL)
4683 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4684 pp = g_func_pp->arg[k].pp;
4693 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4695 ferr(&ops[j], "expected struct, got '%s %s'\n",
4696 pp->type.name, pp->name);
4700 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4703 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4704 int *pp_i, int *multi_src)
4706 const struct parsed_proto *pp = NULL;
4707 int search_advice = 0;
4712 switch (ops[i].operand[0].type) {
4714 // try to resolve struct member calls
4715 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4721 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4727 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4735 static struct parsed_proto *process_call_early(int i, int opcnt,
4738 struct parsed_op *po = &ops[i];
4739 struct parsed_proto *pp;
4745 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4749 // look for and make use of esp adjust
4751 if (!pp->is_stdcall && pp->argc_stack > 0)
4752 ret = scan_for_esp_adjust(i + 1, opcnt,
4753 pp->argc_stack * 4, &adj, &multipath, 0);
4755 if (pp->argc_stack > adj / 4)
4759 if (ops[ret].op == OP_POP) {
4760 for (j = 1; j < adj / 4; j++) {
4761 if (ops[ret + j].op != OP_POP
4762 || ops[ret + j].operand[0].reg != xCX)
4774 static struct parsed_proto *process_call(int i, int opcnt)
4776 struct parsed_op *po = &ops[i];
4777 const struct parsed_proto *pp_c;
4778 struct parsed_proto *pp;
4779 const char *tmpname;
4780 int call_i = -1, ref_i = -1;
4781 int adj = 0, multipath = 0;
4784 tmpname = opr_name(po, 0);
4789 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4791 if (!pp_c->is_func && !pp_c->is_fptr)
4792 ferr(po, "call to non-func: %s\n", pp_c->name);
4793 pp = proto_clone(pp_c);
4794 my_assert_not(pp, NULL);
4796 // not resolved just to single func
4799 switch (po->operand[0].type) {
4801 // we resolved this call and no longer need the register
4802 po->regmask_src &= ~(1 << po->operand[0].reg);
4804 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4805 && ops[call_i].operand[1].type == OPT_LABEL)
4807 // no other source users?
4808 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4810 if (ret == 1 && call_i == ref_i) {
4811 // and nothing uses it after us?
4813 find_next_read(i + 1, opcnt, &po->operand[0],
4814 i + opcnt * 11, &ref_i);
4816 // then also don't need the source mov
4817 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4829 pp = calloc(1, sizeof(*pp));
4830 my_assert_not(pp, NULL);
4833 ret = scan_for_esp_adjust(i + 1, opcnt,
4834 -1, &adj, &multipath, 0);
4835 if (ret < 0 || adj < 0) {
4836 if (!g_allow_regfunc)
4837 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4838 pp->is_unresolved = 1;
4842 if (adj > ARRAY_SIZE(pp->arg))
4843 ferr(po, "esp adjust too large: %d\n", adj);
4844 pp->ret_type.name = strdup("int");
4845 pp->argc = pp->argc_stack = adj;
4846 for (arg = 0; arg < pp->argc; arg++)
4847 pp->arg[arg].type.name = strdup("int");
4852 // look for and make use of esp adjust
4855 if (!pp->is_stdcall && pp->argc_stack > 0) {
4856 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4857 ret = scan_for_esp_adjust(i + 1, opcnt,
4858 adj_expect, &adj, &multipath, 0);
4861 if (pp->is_vararg) {
4862 if (adj / 4 < pp->argc_stack) {
4863 fnote(po, "(this call)\n");
4864 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4865 adj, pp->argc_stack * 4);
4867 // modify pp to make it have varargs as normal args
4869 pp->argc += adj / 4 - pp->argc_stack;
4870 for (; arg < pp->argc; arg++) {
4871 pp->arg[arg].type.name = strdup("int");
4874 if (pp->argc > ARRAY_SIZE(pp->arg))
4875 ferr(po, "too many args for '%s'\n", tmpname);
4877 if (pp->argc_stack > adj / 4) {
4878 if (pp->is_noreturn)
4879 // assume no stack adjust was emited
4881 fnote(po, "(this call)\n");
4882 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4883 tmpname, pp->argc_stack * 4, adj);
4886 scan_for_esp_adjust(i + 1, opcnt,
4887 pp->argc_stack * 4, &adj, &multipath, 1);
4889 else if (pp->is_vararg)
4890 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4897 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
4900 struct parsed_op *po;
4906 for (base_arg = 0; base_arg < pp->argc; base_arg++)
4907 if (pp->arg[base_arg].reg == NULL)
4910 for (j = i; j > 0; )
4912 ferr_assert(&ops[j], g_labels[j] == NULL);
4916 ferr_assert(po, po->op != OP_PUSH);
4917 if (po->op == OP_FST)
4919 if (po->operand[0].type != OPT_REGMEM)
4921 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
4924 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
4925 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
4929 arg = base_arg + offset / 4;
4931 po->p_argnum = arg + 1;
4932 ferr_assert(po, pp->arg[arg].datap == NULL);
4933 pp->arg[arg].datap = po;
4934 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
4935 if (regmask_ffca != NULL)
4936 *regmask_ffca |= 1 << arg;
4938 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4939 && po->operand[1].type == OPT_CONST)
4941 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4946 for (arg = base_arg; arg < pp->argc; arg++) {
4947 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
4948 po = pp->arg[arg].datap;
4950 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
4951 if (po->operand[0].lmod == OPLM_QWORD)
4958 static int collect_call_args_early(int i, struct parsed_proto *pp,
4959 int *regmask, int *regmask_ffca)
4961 struct parsed_op *po;
4965 for (arg = 0; arg < pp->argc; arg++)
4966 if (pp->arg[arg].reg == NULL)
4969 // first see if it can be easily done
4970 for (j = i; j > 0 && arg < pp->argc; )
4972 if (g_labels[j] != NULL)
4977 if (po->op == OP_CALL)
4979 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
4981 else if (po->op == OP_POP)
4983 else if (po->flags & OPF_CJMP)
4985 else if (po->op == OP_PUSH) {
4986 if (po->flags & (OPF_FARG|OPF_FARGNR))
4988 if (!g_header_mode) {
4989 ret = scan_for_mod(po, j + 1, i, 1);
4994 if (pp->arg[arg].type.is_va_list)
4998 for (arg++; arg < pp->argc; arg++)
4999 if (pp->arg[arg].reg == NULL)
5002 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5003 && po->operand[1].type == OPT_CONST)
5005 if (po->flags & (OPF_RMD|OPF_DONE))
5007 if (po->operand[1].val != pp->argc_stack * 4)
5008 ferr(po, "unexpected esp adjust: %d\n",
5009 po->operand[1].val * 4);
5010 ferr_assert(po, pp->argc - arg == pp->argc_stack);
5011 return collect_call_args_no_push(i, pp, regmask_ffca);
5019 for (arg = 0; arg < pp->argc; arg++)
5020 if (pp->arg[arg].reg == NULL)
5023 for (j = i; j > 0 && arg < pp->argc; )
5027 if (ops[j].op == OP_PUSH)
5029 ops[j].p_argnext = -1;
5030 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
5031 pp->arg[arg].datap = &ops[j];
5033 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5034 *regmask |= 1 << ops[j].operand[0].reg;
5036 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5037 ops[j].flags &= ~OPF_RSAVE;
5040 for (arg++; arg < pp->argc; arg++)
5041 if (pp->arg[arg].reg == NULL)
5049 static int sync_argnum(struct parsed_op *po, int argnum)
5051 struct parsed_op *po_tmp;
5053 // see if other branches don't have higher argnum
5054 for (po_tmp = po; po_tmp != NULL; ) {
5055 if (argnum < po_tmp->p_argnum)
5056 argnum = po_tmp->p_argnum;
5057 // note: p_argnext is active on current collect_call_args only
5058 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5061 // make all argnums consistent
5062 for (po_tmp = po; po_tmp != NULL; ) {
5063 if (po_tmp->p_argnum != 0)
5064 po_tmp->p_argnum = argnum;
5065 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5071 static int collect_call_args_r(struct parsed_op *po, int i,
5072 struct parsed_proto *pp, int *regmask, int *arg_grp,
5073 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
5075 struct parsed_proto *pp_tmp;
5076 struct parsed_op *po_tmp;
5077 struct label_ref *lr;
5078 int need_to_save_current;
5079 int arg_grp_current = 0;
5080 int save_args_seen = 0;
5087 ferr(po, "dead label encountered\n");
5091 for (; arg < pp->argc; arg++, argnum++)
5092 if (pp->arg[arg].reg == NULL)
5094 magic = (magic & 0xffffff) | (arg << 24);
5096 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5098 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5099 if (ops[j].cc_scratch != magic) {
5100 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5104 // ok: have already been here
5107 ops[j].cc_scratch = magic;
5109 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5110 lr = &g_label_refs[j];
5111 if (lr->next != NULL)
5113 for (; lr->next; lr = lr->next) {
5114 check_i(&ops[j], lr->i);
5115 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5117 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5118 arg, argnum, magic, need_op_saving, may_reuse);
5123 check_i(&ops[j], lr->i);
5124 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5126 if (j > 0 && LAST_OP(j - 1)) {
5127 // follow last branch in reverse
5132 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5133 arg, argnum, magic, need_op_saving, may_reuse);
5139 if (ops[j].op == OP_CALL)
5141 if (pp->is_unresolved)
5146 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5147 arg, pp->argc, ops[j].operand[0].name);
5148 if (may_reuse && pp_tmp->argc_stack > 0)
5149 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5150 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5152 // esp adjust of 0 means we collected it before
5153 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5154 && (ops[j].operand[1].type != OPT_CONST
5155 || ops[j].operand[1].val != 0))
5157 if (pp->is_unresolved)
5160 fnote(po, "(this call)\n");
5161 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5162 arg, pp->argc, ops[j].operand[1].val);
5164 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5166 if (pp->is_unresolved)
5169 fnote(po, "(this call)\n");
5170 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5172 else if (ops[j].flags & OPF_CJMP)
5174 if (pp->is_unresolved)
5179 else if (ops[j].op == OP_PUSH
5180 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5182 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5185 ops[j].p_argnext = -1;
5186 po_tmp = pp->arg[arg].datap;
5188 ops[j].p_argnext = po_tmp - ops;
5189 pp->arg[arg].datap = &ops[j];
5191 argnum = sync_argnum(&ops[j], argnum);
5193 need_to_save_current = 0;
5195 if (ops[j].operand[0].type == OPT_REG)
5196 reg = ops[j].operand[0].reg;
5198 if (!need_op_saving) {
5199 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5200 need_to_save_current = (ret >= 0);
5202 if (need_op_saving || need_to_save_current) {
5203 // mark this arg as one that needs operand saving
5204 pp->arg[arg].is_saved = 1;
5206 if (save_args_seen & (1 << (argnum - 1))) {
5209 if (arg_grp_current >= MAX_ARG_GRP)
5210 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5214 else if (ops[j].p_argnum == 0)
5215 ops[j].flags |= OPF_RMD;
5217 // some PUSHes are reused by different calls on other branches,
5218 // but that can't happen if we didn't branch, so they
5219 // can be removed from future searches (handles nested calls)
5221 ops[j].flags |= OPF_FARGNR;
5223 ops[j].flags |= OPF_FARG;
5224 ops[j].flags &= ~OPF_RSAVE;
5226 // check for __VALIST
5227 if (!pp->is_unresolved && g_func_pp != NULL
5228 && pp->arg[arg].type.is_va_list)
5231 ret = resolve_origin(j, &ops[j].operand[0],
5232 magic + 1, &k, NULL);
5233 if (ret == 1 && k >= 0)
5235 if (ops[k].op == OP_LEA) {
5236 if (!g_func_pp->is_vararg)
5237 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5240 snprintf(buf, sizeof(buf), "arg_%X",
5241 g_func_pp->argc_stack * 4);
5242 if (strstr(ops[k].operand[1].name, buf)
5243 || strstr(ops[k].operand[1].name, "arglist"))
5245 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5246 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5247 pp->arg[arg].is_saved = 0;
5251 ferr(&ops[k], "va_list arg detection failed\n");
5253 // check for va_list from g_func_pp arg too
5254 else if (ops[k].op == OP_MOV
5255 && is_stack_access(&ops[k], &ops[k].operand[1]))
5257 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5258 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5260 ops[k].flags |= OPF_RMD | OPF_DONE;
5261 ops[j].flags |= OPF_RMD;
5262 ops[j].p_argpass = ret + 1;
5263 pp->arg[arg].is_saved = 0;
5270 if (pp->arg[arg].is_saved) {
5271 ops[j].flags &= ~OPF_RMD;
5272 ops[j].p_argnum = argnum;
5275 // tracking reg usage
5277 *regmask |= 1 << reg;
5281 if (!pp->is_unresolved) {
5283 for (; arg < pp->argc; arg++, argnum++)
5284 if (pp->arg[arg].reg == NULL)
5287 magic = (magic & 0xffffff) | (arg << 24);
5290 if (ops[j].p_arggrp > arg_grp_current) {
5292 arg_grp_current = ops[j].p_arggrp;
5294 if (ops[j].p_argnum > 0)
5295 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5298 if (arg < pp->argc) {
5299 ferr(po, "arg collect failed for '%s': %d/%d\n",
5300 pp->name, arg, pp->argc);
5304 if (arg_grp_current > *arg_grp)
5305 *arg_grp = arg_grp_current;
5310 static int collect_call_args(struct parsed_op *po, int i,
5311 struct parsed_proto *pp, int *regmask, int magic)
5313 // arg group is for cases when pushes for
5314 // multiple funcs are going on
5315 struct parsed_op *po_tmp;
5320 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5326 // propagate arg_grp
5327 for (a = 0; a < pp->argc; a++) {
5328 if (pp->arg[a].reg != NULL)
5331 po_tmp = pp->arg[a].datap;
5332 while (po_tmp != NULL) {
5333 po_tmp->p_arggrp = arg_grp;
5334 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5339 if (pp->is_unresolved) {
5341 pp->argc_stack += ret;
5342 for (a = 0; a < pp->argc; a++)
5343 if (pp->arg[a].type.name == NULL)
5344 pp->arg[a].type.name = strdup("int");
5350 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5351 int regmask_now, int *regmask,
5352 int regmask_save_now, int *regmask_save,
5353 int *regmask_init, int regmask_arg)
5355 struct parsed_op *po;
5363 for (; i < opcnt; i++)
5366 if (cbits[i >> 3] & (1 << (i & 7)))
5368 cbits[i >> 3] |= (1 << (i & 7));
5370 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5371 if (po->flags & (OPF_RMD|OPF_DONE))
5373 if (po->btj != NULL) {
5374 for (j = 0; j < po->btj->count; j++) {
5375 check_i(po, po->btj->d[j].bt_i);
5376 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5377 regmask_now, regmask, regmask_save_now, regmask_save,
5378 regmask_init, regmask_arg);
5383 check_i(po, po->bt_i);
5384 if (po->flags & OPF_CJMP)
5385 reg_use_pass(po->bt_i, opcnt, cbits,
5386 regmask_now, regmask, regmask_save_now, regmask_save,
5387 regmask_init, regmask_arg);
5393 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5394 && !g_func_pp->is_userstack
5395 && po->operand[0].type == OPT_REG)
5397 reg = po->operand[0].reg;
5398 ferr_assert(po, reg >= 0);
5401 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5402 if (regmask_now & (1 << reg)) {
5403 already_saved = regmask_save_now & (1 << reg);
5404 flags_set = OPF_RSAVE | OPF_DONE;
5407 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5409 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5410 reg, 0, 0, flags_set);
5413 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5415 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5420 ferr_assert(po, !already_saved);
5421 po->flags |= flags_set;
5423 if (regmask_now & (1 << reg)) {
5424 regmask_save_now |= (1 << reg);
5425 *regmask_save |= regmask_save_now;
5430 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5431 reg = po->operand[0].reg;
5432 ferr_assert(po, reg >= 0);
5434 if (regmask_save_now & (1 << reg))
5435 regmask_save_now &= ~(1 << reg);
5437 regmask_now &= ~(1 << reg);
5440 else if (po->op == OP_CALL) {
5441 if ((po->regmask_dst & (1 << xAX))
5442 && !(po->regmask_dst & (1 << xDX)))
5444 if (po->flags & OPF_TAIL)
5445 // don't need eax, will do "return f();" or "f(); return;"
5446 po->regmask_dst &= ~(1 << xAX);
5448 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5450 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5453 po->regmask_dst &= ~(1 << xAX);
5457 // not "full stack" mode and have something in stack
5458 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5459 ferr(po, "float stack is not empty on func call\n");
5462 if (po->flags & OPF_NOREGS)
5465 // if incomplete register is used, clear it on init to avoid
5466 // later use of uninitialized upper part in some situations
5467 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5468 && po->operand[0].lmod != OPLM_DWORD)
5470 reg = po->operand[0].reg;
5471 ferr_assert(po, reg >= 0);
5473 if (!(regmask_now & (1 << reg)))
5474 *regmask_init |= 1 << reg;
5477 regmask_op = po->regmask_src | po->regmask_dst;
5479 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5480 regmask_new &= ~(1 << xSP);
5481 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5482 regmask_new &= ~(1 << xBP);
5484 if (regmask_new != 0)
5485 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5487 if (regmask_op & (1 << xBP)) {
5488 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5489 if (po->regmask_dst & (1 << xBP))
5490 // compiler decided to drop bp frame and use ebp as scratch
5491 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5493 regmask_op &= ~(1 << xBP);
5497 if (po->flags & OPF_FPUSH) {
5498 if (regmask_now & mxST1)
5499 regmask_now |= mxSTa; // switch to "full stack" mode
5500 if (regmask_now & mxSTa)
5501 po->flags |= OPF_FSHIFT;
5502 if (!(regmask_now & mxST7_2)) {
5504 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5508 regmask_now |= regmask_op;
5509 *regmask |= regmask_now;
5512 if (po->flags & OPF_FPOP) {
5513 if ((regmask_now & mxSTa) == 0)
5514 ferr(po, "float pop on empty stack?\n");
5515 if (regmask_now & (mxST7_2 | mxST1))
5516 po->flags |= OPF_FSHIFT;
5517 if (!(regmask_now & mxST7_2)) {
5519 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5523 if (po->flags & OPF_TAIL) {
5524 if (!(regmask_now & mxST7_2)) {
5525 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5526 if (!(regmask_now & mxST0))
5527 ferr(po, "no st0 on float return, mask: %x\n",
5530 else if (regmask_now & mxST1_0)
5531 ferr(po, "float regs on tail: %x\n", regmask_now);
5534 // there is support for "conditional tailcall", sort of
5535 if (!(po->flags & OPF_CC))
5541 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5545 for (i = 0; i < pp->argc; i++)
5546 if (pp->arg[i].reg == NULL)
5550 memmove(&pp->arg[i + 1], &pp->arg[i],
5551 sizeof(pp->arg[0]) * pp->argc_stack);
5552 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5553 pp->arg[i].reg = strdup(reg);
5554 pp->arg[i].type.name = strdup("int");
5559 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5560 int *pfomask, const char *dst_opr_text)
5562 if (*pfomask & (1 << PFO_Z)) {
5563 fprintf(fout, "\n cond_z = (%s%s == 0);",
5564 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5565 *pfomask &= ~(1 << PFO_Z);
5569 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5570 int *pfomask, const char *dst_opr_text)
5572 if (*pfomask & (1 << PFO_S)) {
5573 fprintf(fout, "\n cond_s = (%s%s < 0);",
5574 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5575 *pfomask &= ~(1 << PFO_S);
5579 static void output_std_flags(FILE *fout, struct parsed_op *po,
5580 int *pfomask, const char *dst_opr_text)
5582 output_std_flag_z(fout, po, pfomask, dst_opr_text);
5583 output_std_flag_s(fout, po, pfomask, dst_opr_text);
5587 OPP_FORCE_NORETURN = (1 << 0),
5588 OPP_SIMPLE_ARGS = (1 << 1),
5589 OPP_ALIGN = (1 << 2),
5592 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5595 const char *cconv = "";
5597 if (pp->is_fastcall)
5598 cconv = "__fastcall ";
5599 else if (pp->is_stdcall && pp->argc_reg == 0)
5600 cconv = "__stdcall ";
5602 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5604 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5605 fprintf(fout, "noreturn ");
5608 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5613 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5617 output_pp_attrs(fout, pp, flags);
5620 fprintf(fout, "%s", pp->name);
5625 for (i = 0; i < pp->argc; i++) {
5627 fprintf(fout, ", ");
5628 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5629 && !(flags & OPP_SIMPLE_ARGS))
5632 output_pp(fout, pp->arg[i].pp, 0);
5634 else if (pp->arg[i].type.is_retreg) {
5635 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5638 fprintf(fout, "%s", pp->arg[i].type.name);
5640 fprintf(fout, " a%d", i + 1);
5643 if (pp->arg[i].type.is_64bit)
5646 if (pp->is_vararg) {
5648 fprintf(fout, ", ");
5649 fprintf(fout, "...");
5654 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5660 snprintf(buf1, sizeof(buf1), "%d", grp);
5661 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5666 static void gen_x_cleanup(int opcnt);
5668 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5670 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5671 struct parsed_opr *last_arith_dst = NULL;
5672 char buf1[256], buf2[256], buf3[256], cast[64];
5673 struct parsed_proto *pp, *pp_tmp;
5674 struct parsed_data *pd;
5675 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5676 unsigned char cbits[MAX_OPS / 8];
5677 const char *float_type;
5678 const char *float_st0;
5679 const char *float_st1;
5680 int need_float_stack = 0;
5681 int need_float_sw = 0; // status word
5682 int need_tmp_var = 0;
5686 int label_pending = 0;
5687 int need_double = 0;
5688 int stack_align = 0;
5689 int stack_fsz_adj = 0;
5690 int regmask_save = 0; // used regs saved/restored in this func
5691 int regmask_arg; // regs from this function args (fastcall, etc)
5692 int regmask_ret; // regs needed on ret
5693 int regmask_now; // temp
5694 int regmask_init = 0; // regs that need zero initialization
5695 int regmask_pp = 0; // regs used in complex push-pop graph
5696 int regmask_ffca = 0; // float function call args
5697 int regmask = 0; // used regs
5707 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5708 g_stack_frame_used = 0;
5710 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5711 regmask_init = g_regmask_init;
5713 g_func_pp = proto_parse(fhdr, funcn, 0);
5714 if (g_func_pp == NULL)
5715 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5717 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5718 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5721 // - resolve all branches
5722 // - parse calls with labels
5723 resolve_branches_parse_calls(opcnt);
5726 // - handle ebp/esp frame, remove ops related to it
5727 scan_prologue_epilogue(opcnt, &stack_align);
5729 // handle a case where sf size is unalignment, but is
5730 // placed in a way that elements are still aligned
5731 if (g_stack_fsz & 4) {
5732 for (i = 0; i < g_eqcnt; i++) {
5733 if (g_eqs[i].lmod != OPLM_QWORD)
5735 if (!(g_eqs[i].offset & 4)) {
5744 // - remove dead labels
5745 // - set regs needed at ret
5746 for (i = 0; i < opcnt; i++)
5748 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5753 if (ops[i].op == OP_RET)
5754 ops[i].regmask_src |= regmask_ret;
5758 // - process trivial calls
5759 for (i = 0; i < opcnt; i++)
5762 if (po->flags & (OPF_RMD|OPF_DONE))
5765 if (po->op == OP_CALL)
5767 pp = process_call_early(i, opcnt, &j);
5769 if (!(po->flags & OPF_ATAIL)) {
5770 // since we know the args, try to collect them
5771 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5779 // commit esp adjust
5780 if (ops[j].op != OP_POP)
5781 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5783 for (l = 0; l < pp->argc_stack; l++)
5784 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5788 if (strstr(pp->ret_type.name, "int64"))
5791 po->flags |= OPF_DONE;
5797 // - process calls, stage 2
5798 // - handle some push/pop pairs
5799 // - scan for STD/CLD, propagate DF
5800 // - try to resolve needed x87 status word bits
5801 for (i = 0; i < opcnt; i++)
5806 if (po->flags & OPF_RMD)
5809 if (po->op == OP_CALL)
5811 if (!(po->flags & OPF_DONE)) {
5812 pp = process_call(i, opcnt);
5814 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5815 // since we know the args, collect them
5816 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5818 // for unresolved, collect after other passes
5822 ferr_assert(po, pp != NULL);
5824 po->regmask_src |= get_pp_arg_regmask_src(pp);
5825 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5827 if (po->regmask_dst & mxST0)
5828 po->flags |= OPF_FPUSH;
5830 if (strstr(pp->ret_type.name, "int64"))
5836 if (po->flags & OPF_DONE)
5841 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
5842 && po->operand[0].type == OPT_CONST)
5844 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5849 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5853 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5854 scan_propagate_df(i + 1, opcnt);
5859 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
5860 ferr(po, "TODO: fnstsw to mem\n");
5861 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
5863 ferr(po, "fnstsw resolve failed\n");
5864 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
5865 (void *)(long)(mask | (z_check << 16)));
5867 ferr(po, "failed to find fcom: %d\n", ret);
5876 // - find POPs for PUSHes, rm both
5877 // - scan for all used registers
5878 memset(cbits, 0, sizeof(cbits));
5879 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5880 0, ®mask_save, ®mask_init, regmask_arg);
5882 need_float_stack = !!(regmask & mxST7_2);
5885 // - find flag set ops for their users
5886 // - do unresolved calls
5887 // - declare indirect functions
5888 // - other op specific processing
5889 for (i = 0; i < opcnt; i++)
5892 if (po->flags & (OPF_RMD|OPF_DONE))
5895 if (po->flags & OPF_CC)
5897 int setters[16], cnt = 0, branched = 0;
5899 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
5900 &branched, setters, &cnt);
5901 if (ret < 0 || cnt <= 0)
5902 ferr(po, "unable to trace flag setter(s)\n");
5903 if (cnt > ARRAY_SIZE(setters))
5904 ferr(po, "too many flag setters\n");
5906 for (j = 0; j < cnt; j++)
5908 tmp_op = &ops[setters[j]]; // flag setter
5911 // to get nicer code, we try to delay test and cmp;
5912 // if we can't because of operand modification, or if we
5913 // have arith op, or branch, make it calculate flags explicitly
5914 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5916 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5917 pfomask = 1 << po->pfo;
5919 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5920 pfomask = 1 << po->pfo;
5923 // see if we'll be able to handle based on op result
5924 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5925 && po->pfo != PFO_Z && po->pfo != PFO_S
5926 && po->pfo != PFO_P)
5928 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5930 pfomask = 1 << po->pfo;
5933 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5934 propagate_lmod(tmp_op, &tmp_op->operand[0],
5935 &tmp_op->operand[1]);
5936 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5941 tmp_op->pfomask |= pfomask;
5942 cond_vars |= pfomask;
5944 // note: may overwrite, currently not a problem
5948 if (po->op == OP_RCL || po->op == OP_RCR
5949 || po->op == OP_ADC || po->op == OP_SBB)
5950 cond_vars |= 1 << PFO_C;
5956 cond_vars |= 1 << PFO_Z;
5960 if (po->operand[0].lmod == OPLM_DWORD)
5965 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
5970 // note: resolved non-reg calls are OPF_DONE already
5972 ferr_assert(po, pp != NULL);
5974 if (pp->is_unresolved) {
5975 int regmask_stack = 0;
5976 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5978 // this is pretty rough guess:
5979 // see ecx and edx were pushed (and not their saved versions)
5980 for (arg = 0; arg < pp->argc; arg++) {
5981 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
5984 tmp_op = pp->arg[arg].datap;
5986 ferr(po, "parsed_op missing for arg%d\n", arg);
5987 if (tmp_op->operand[0].type == OPT_REG)
5988 regmask_stack |= 1 << tmp_op->operand[0].reg;
5991 if (!((regmask_stack & (1 << xCX))
5992 && (regmask_stack & (1 << xDX))))
5994 if (pp->argc_stack != 0
5995 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5997 pp_insert_reg_arg(pp, "ecx");
5998 pp->is_fastcall = 1;
5999 regmask_init |= 1 << xCX;
6000 regmask |= 1 << xCX;
6002 if (pp->argc_stack != 0
6003 || ((regmask | regmask_arg) & (1 << xDX)))
6005 pp_insert_reg_arg(pp, "edx");
6006 regmask_init |= 1 << xDX;
6007 regmask |= 1 << xDX;
6011 // note: __cdecl doesn't fall into is_unresolved category
6012 if (pp->argc_stack > 0)
6018 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6020 // <var> = offset <something>
6021 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6022 && !IS_START(po->operand[1].name, "off_"))
6024 if (!po->operand[0].pp->is_fptr)
6025 ferr(po, "%s not declared as fptr when it should be\n",
6026 po->operand[0].name);
6027 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6028 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6029 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6030 fnote(po, "var: %s\n", buf1);
6031 fnote(po, "func: %s\n", buf2);
6032 ferr(po, "^ mismatch\n");
6040 if (po->operand[0].lmod == OPLM_DWORD) {
6041 // 32bit division is common, look for it
6042 if (po->op == OP_DIV)
6043 ret = scan_for_reg_clear(i, xDX);
6045 ret = scan_for_cdq_edx(i);
6047 po->flags |= OPF_32BIT;
6056 po->flags |= OPF_RMD | OPF_DONE;
6066 if (po->operand[0].lmod == OPLM_QWORD)
6076 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
6078 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
6080 po->flags |= OPF_32BIT;
6088 // this might need it's own pass...
6089 if (po->op != OP_FST && po->p_argnum > 0)
6090 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6092 // correct for "full stack" mode late enable
6093 if ((po->flags & (OPF_PPUSH|OPF_FPOP)) && need_float_stack)
6094 po->flags |= OPF_FSHIFT;
6097 float_type = need_double ? "double" : "float";
6098 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6099 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6101 // output starts here
6104 fprintf(fout, "// had SEH\n");
6106 // define userstack size
6107 if (g_func_pp->is_userstack) {
6108 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6109 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6110 fprintf(fout, "#endif\n");
6113 // the function itself
6114 ferr_assert(ops, !g_func_pp->is_fptr);
6115 output_pp(fout, g_func_pp,
6116 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6117 fprintf(fout, "\n{\n");
6119 // declare indirect functions
6120 for (i = 0; i < opcnt; i++) {
6122 if (po->flags & OPF_RMD)
6125 if (po->op == OP_CALL) {
6128 ferr(po, "NULL pp\n");
6130 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6131 if (pp->name[0] != 0) {
6132 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6133 memcpy(pp->name, "i_", 2);
6135 // might be declared already
6137 for (j = 0; j < i; j++) {
6138 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6139 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6149 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6152 output_pp(fout, pp, OPP_SIMPLE_ARGS);
6153 fprintf(fout, ";\n");
6158 // output LUTs/jumptables
6159 for (i = 0; i < g_func_pd_cnt; i++) {
6161 fprintf(fout, " static const ");
6162 if (pd->type == OPT_OFFSET) {
6163 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6165 for (j = 0; j < pd->count; j++) {
6167 fprintf(fout, ", ");
6168 fprintf(fout, "&&%s", pd->d[j].u.label);
6172 fprintf(fout, "%s %s[] =\n { ",
6173 lmod_type_u(ops, pd->lmod), pd->label);
6175 for (j = 0; j < pd->count; j++) {
6177 fprintf(fout, ", ");
6178 fprintf(fout, "%u", pd->d[j].u.val);
6181 fprintf(fout, " };\n");
6185 // declare stack frame, va_arg
6188 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6190 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6191 if (g_func_lmods & (1 << OPLM_WORD))
6192 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6193 if (g_func_lmods & (1 << OPLM_BYTE))
6194 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6195 if (g_func_lmods & (1 << OPLM_QWORD))
6196 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6198 if (stack_align > 8)
6199 ferr(ops, "unhandled stack align of %d\n", stack_align);
6200 else if (stack_align == 8)
6201 fprintf(fout, " u64 align;");
6202 fprintf(fout, " } sf;\n");
6206 if (g_func_pp->is_userstack) {
6207 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6208 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6212 if (g_func_pp->is_vararg) {
6213 fprintf(fout, " va_list ap;\n");
6217 // declare arg-registers
6218 for (i = 0; i < g_func_pp->argc; i++) {
6219 if (g_func_pp->arg[i].reg != NULL) {
6220 reg = char_array_i(regs_r32,
6221 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6222 if (regmask & (1 << reg)) {
6223 if (g_func_pp->arg[i].type.is_retreg)
6224 fprintf(fout, " u32 %s = *r_%s;\n",
6225 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6227 fprintf(fout, " u32 %s = (u32)a%d;\n",
6228 g_func_pp->arg[i].reg, i + 1);
6231 if (g_func_pp->arg[i].type.is_retreg)
6232 ferr(ops, "retreg '%s' is unused?\n",
6233 g_func_pp->arg[i].reg);
6234 fprintf(fout, " // %s = a%d; // unused\n",
6235 g_func_pp->arg[i].reg, i + 1);
6241 // declare normal registers
6242 regmask_now = regmask & ~regmask_arg;
6243 regmask_now &= ~(1 << xSP);
6244 if (regmask_now & 0x00ff) {
6245 for (reg = 0; reg < 8; reg++) {
6246 if (regmask_now & (1 << reg)) {
6247 fprintf(fout, " u32 %s", regs_r32[reg]);
6248 if (regmask_init & (1 << reg))
6249 fprintf(fout, " = 0");
6250 fprintf(fout, ";\n");
6256 if (regmask_now & 0xff00) {
6257 for (reg = 8; reg < 16; reg++) {
6258 if (regmask_now & (1 << reg)) {
6259 fprintf(fout, " mmxr %s", regs_r32[reg]);
6260 if (regmask_init & (1 << reg))
6261 fprintf(fout, " = { 0, }");
6262 fprintf(fout, ";\n");
6268 if (need_float_stack) {
6269 fprintf(fout, " %s f_st[8];\n", float_type);
6270 fprintf(fout, " int f_stp = 0;\n");
6274 if (regmask_now & 0xff0000) {
6275 for (reg = 16; reg < 24; reg++) {
6276 if (regmask_now & (1 << reg)) {
6277 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6278 if (regmask_init & (1 << reg))
6279 fprintf(fout, " = 0");
6280 fprintf(fout, ";\n");
6287 if (need_float_sw) {
6288 fprintf(fout, " u16 f_sw;\n");
6293 for (reg = 0; reg < 8; reg++) {
6294 if (regmask_save & (1 << reg)) {
6295 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6301 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6302 if (save_arg_vars[i] == 0)
6304 for (reg = 0; reg < 32; reg++) {
6305 if (save_arg_vars[i] & (1 << reg)) {
6306 fprintf(fout, " u32 %s;\n",
6307 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6314 for (reg = 0; reg < 32; reg++) {
6315 if (regmask_ffca & (1 << reg)) {
6316 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6322 // declare push-pop temporaries
6324 for (reg = 0; reg < 8; reg++) {
6325 if (regmask_pp & (1 << reg)) {
6326 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6333 for (i = 0; i < 8; i++) {
6334 if (cond_vars & (1 << i)) {
6335 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6342 fprintf(fout, " u32 tmp;\n");
6347 fprintf(fout, " u64 tmp64;\n");
6352 fprintf(fout, "\n");
6354 // do stack clear, if needed
6355 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6357 if (g_stack_clear_len != 0) {
6358 if (g_stack_clear_len <= 4) {
6359 for (i = 0; i < g_stack_clear_len; i++)
6360 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6361 fprintf(fout, "0;\n");
6364 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6365 g_stack_clear_start, g_stack_clear_len * 4);
6369 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6372 if (g_func_pp->is_vararg) {
6373 if (g_func_pp->argc_stack == 0)
6374 ferr(ops, "vararg func without stack args?\n");
6375 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6379 for (i = 0; i < opcnt; i++)
6381 if (g_labels[i] != NULL) {
6382 fprintf(fout, "\n%s:\n", g_labels[i]);
6385 delayed_flag_op = NULL;
6386 last_arith_dst = NULL;
6390 if (po->flags & OPF_RMD)
6395 #define assert_operand_cnt(n_) \
6396 if (po->operand_cnt != n_) \
6397 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6399 // conditional/flag using op?
6400 if (po->flags & OPF_CC)
6406 // we go through all this trouble to avoid using parsed_flag_op,
6407 // which makes generated code much nicer
6408 if (delayed_flag_op != NULL)
6410 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6411 po->pfo, po->pfo_inv);
6414 else if (last_arith_dst != NULL
6415 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6416 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6419 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6420 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6421 last_arith_dst->lmod, buf3);
6424 else if (tmp_op != NULL) {
6425 // use preprocessed flag calc results
6426 if (!(tmp_op->pfomask & (1 << po->pfo)))
6427 ferr(po, "not prepared for pfo %d\n", po->pfo);
6429 // note: pfo_inv was not yet applied
6430 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6431 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6434 ferr(po, "all methods of finding comparison failed\n");
6437 if (po->flags & OPF_JMP) {
6438 fprintf(fout, " if %s", buf1);
6440 else if (po->op == OP_RCL || po->op == OP_RCR
6441 || po->op == OP_ADC || po->op == OP_SBB)
6444 fprintf(fout, " cond_%s = %s;\n",
6445 parsed_flag_op_names[po->pfo], buf1);
6447 else if (po->flags & OPF_DATA) { // SETcc
6448 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6449 fprintf(fout, " %s = %s;", buf2, buf1);
6452 ferr(po, "unhandled conditional op\n");
6456 pfomask = po->pfomask;
6461 assert_operand_cnt(2);
6462 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6463 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6464 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6465 fprintf(fout, " %s = %s;", buf1,
6466 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6471 assert_operand_cnt(2);
6472 po->operand[1].lmod = OPLM_DWORD; // always
6473 fprintf(fout, " %s = %s;",
6474 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6475 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6480 assert_operand_cnt(2);
6481 fprintf(fout, " %s = %s;",
6482 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6483 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6487 assert_operand_cnt(2);
6488 switch (po->operand[1].lmod) {
6490 strcpy(buf3, "(s8)");
6493 strcpy(buf3, "(s16)");
6496 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6498 fprintf(fout, " %s = %s;",
6499 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6500 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6505 assert_operand_cnt(2);
6506 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6507 fprintf(fout, " tmp = %s;",
6508 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6509 fprintf(fout, " %s = %s;",
6510 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6511 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6512 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6513 fprintf(fout, " %s = %stmp;",
6514 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6515 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6516 snprintf(g_comment, sizeof(g_comment), "xchg");
6520 assert_operand_cnt(1);
6521 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6522 fprintf(fout, " %s = ~%s;", buf1, buf1);
6526 assert_operand_cnt(2);
6527 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6528 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6529 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6530 strcpy(g_comment, "xlat");
6534 assert_operand_cnt(2);
6535 fprintf(fout, " %s = (s32)%s >> 31;",
6536 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6537 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6538 strcpy(g_comment, "cdq");
6542 assert_operand_cnt(1);
6543 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6544 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6548 if (po->flags & OPF_REP) {
6549 assert_operand_cnt(3);
6554 assert_operand_cnt(2);
6555 fprintf(fout, " %s = %sesi; esi %c= %d;",
6556 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6557 lmod_cast_u_ptr(po, po->operand[1].lmod),
6558 (po->flags & OPF_DF) ? '-' : '+',
6559 lmod_bytes(po, po->operand[1].lmod));
6560 strcpy(g_comment, "lods");
6565 if (po->flags & OPF_REP) {
6566 assert_operand_cnt(3);
6567 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6568 (po->flags & OPF_DF) ? '-' : '+',
6569 lmod_bytes(po, po->operand[1].lmod));
6570 fprintf(fout, " %sedi = eax;",
6571 lmod_cast_u_ptr(po, po->operand[1].lmod));
6572 strcpy(g_comment, "rep stos");
6575 assert_operand_cnt(2);
6576 fprintf(fout, " %sedi = eax; edi %c= %d;",
6577 lmod_cast_u_ptr(po, po->operand[1].lmod),
6578 (po->flags & OPF_DF) ? '-' : '+',
6579 lmod_bytes(po, po->operand[1].lmod));
6580 strcpy(g_comment, "stos");
6585 j = lmod_bytes(po, po->operand[0].lmod);
6586 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6587 l = (po->flags & OPF_DF) ? '-' : '+';
6588 if (po->flags & OPF_REP) {
6589 assert_operand_cnt(3);
6591 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6594 " %sedi = %sesi;", buf1, buf1);
6595 strcpy(g_comment, "rep movs");
6598 assert_operand_cnt(2);
6599 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6600 buf1, buf1, l, j, l, j);
6601 strcpy(g_comment, "movs");
6606 // repe ~ repeat while ZF=1
6607 j = lmod_bytes(po, po->operand[0].lmod);
6608 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6609 l = (po->flags & OPF_DF) ? '-' : '+';
6610 if (po->flags & OPF_REP) {
6611 assert_operand_cnt(3);
6613 " while (ecx != 0) {\n");
6614 if (pfomask & (1 << PFO_C)) {
6617 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6618 pfomask &= ~(1 << PFO_C);
6621 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6622 buf1, buf1, l, j, l, j);
6625 " if (cond_z %s 0) break;\n",
6626 (po->flags & OPF_REPZ) ? "==" : "!=");
6629 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6630 (po->flags & OPF_REPZ) ? "e" : "ne");
6633 assert_operand_cnt(2);
6635 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6636 buf1, buf1, l, j, l, j);
6637 strcpy(g_comment, "cmps");
6639 pfomask &= ~(1 << PFO_Z);
6640 last_arith_dst = NULL;
6641 delayed_flag_op = NULL;
6645 // only does ZF (for now)
6646 // repe ~ repeat while ZF=1
6647 j = lmod_bytes(po, po->operand[1].lmod);
6648 l = (po->flags & OPF_DF) ? '-' : '+';
6649 if (po->flags & OPF_REP) {
6650 assert_operand_cnt(3);
6652 " while (ecx != 0) {\n");
6654 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6655 lmod_cast_u(po, po->operand[1].lmod),
6656 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6659 " if (cond_z %s 0) break;\n",
6660 (po->flags & OPF_REPZ) ? "==" : "!=");
6663 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6664 (po->flags & OPF_REPZ) ? "e" : "ne");
6667 assert_operand_cnt(2);
6668 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6669 lmod_cast_u(po, po->operand[1].lmod),
6670 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6671 strcpy(g_comment, "scas");
6673 pfomask &= ~(1 << PFO_Z);
6674 last_arith_dst = NULL;
6675 delayed_flag_op = NULL;
6678 // arithmetic w/flags
6680 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6681 goto dualop_arith_const;
6682 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6686 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6687 if (po->operand[1].type == OPT_CONST) {
6688 j = lmod_bytes(po, po->operand[0].lmod);
6689 if (((1ull << j * 8) - 1) == po->operand[1].val)
6690 goto dualop_arith_const;
6695 assert_operand_cnt(2);
6696 fprintf(fout, " %s %s= %s;",
6697 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6699 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6700 output_std_flags(fout, po, &pfomask, buf1);
6701 last_arith_dst = &po->operand[0];
6702 delayed_flag_op = NULL;
6706 // and 0, or ~0 used instead mov
6707 assert_operand_cnt(2);
6708 fprintf(fout, " %s = %s;",
6709 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6710 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6711 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6712 output_std_flags(fout, po, &pfomask, buf1);
6713 last_arith_dst = &po->operand[0];
6714 delayed_flag_op = NULL;
6719 assert_operand_cnt(2);
6720 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6721 if (pfomask & (1 << PFO_C)) {
6722 if (po->operand[1].type == OPT_CONST) {
6723 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6724 j = po->operand[1].val;
6727 if (po->op == OP_SHL)
6731 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6735 ferr(po, "zero shift?\n");
6739 pfomask &= ~(1 << PFO_C);
6741 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6742 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6743 if (po->operand[1].type != OPT_CONST)
6744 fprintf(fout, " & 0x1f");
6746 output_std_flags(fout, po, &pfomask, buf1);
6747 last_arith_dst = &po->operand[0];
6748 delayed_flag_op = NULL;
6752 assert_operand_cnt(2);
6753 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6754 fprintf(fout, " %s = %s%s >> %s;", buf1,
6755 lmod_cast_s(po, po->operand[0].lmod), buf1,
6756 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6757 output_std_flags(fout, po, &pfomask, buf1);
6758 last_arith_dst = &po->operand[0];
6759 delayed_flag_op = NULL;
6764 assert_operand_cnt(3);
6765 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6766 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6767 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6768 if (po->operand[2].type != OPT_CONST) {
6769 // no handling for "undefined" case, hopefully not needed
6770 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6773 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6774 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6775 if (po->op == OP_SHLD) {
6776 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6777 buf1, buf3, buf1, buf2, l, buf3);
6778 strcpy(g_comment, "shld");
6781 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6782 buf1, buf3, buf1, buf2, l, buf3);
6783 strcpy(g_comment, "shrd");
6785 output_std_flags(fout, po, &pfomask, buf1);
6786 last_arith_dst = &po->operand[0];
6787 delayed_flag_op = NULL;
6792 assert_operand_cnt(2);
6793 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6794 if (po->operand[1].type == OPT_CONST) {
6795 j = po->operand[1].val;
6796 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6797 fprintf(fout, po->op == OP_ROL ?
6798 " %s = (%s << %d) | (%s >> %d);" :
6799 " %s = (%s >> %d) | (%s << %d);",
6800 buf1, buf1, j, buf1,
6801 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6805 output_std_flags(fout, po, &pfomask, buf1);
6806 last_arith_dst = &po->operand[0];
6807 delayed_flag_op = NULL;
6812 assert_operand_cnt(2);
6813 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6814 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6815 if (po->operand[1].type == OPT_CONST) {
6816 j = po->operand[1].val % l;
6818 ferr(po, "zero rotate\n");
6819 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6820 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6821 if (po->op == OP_RCL) {
6823 " %s = (%s << %d) | (cond_c << %d)",
6824 buf1, buf1, j, j - 1);
6826 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6830 " %s = (%s >> %d) | (cond_c << %d)",
6831 buf1, buf1, j, l - j);
6833 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6835 fprintf(fout, ";\n");
6836 fprintf(fout, " cond_c = tmp;");
6840 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6841 output_std_flags(fout, po, &pfomask, buf1);
6842 last_arith_dst = &po->operand[0];
6843 delayed_flag_op = NULL;
6847 assert_operand_cnt(2);
6848 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6849 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6850 // special case for XOR
6851 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
6852 for (j = 0; j <= PFO_LE; j++) {
6853 if (pfomask & (1 << j)) {
6854 fprintf(fout, " cond_%s = %d;\n",
6855 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
6856 pfomask &= ~(1 << j);
6859 fprintf(fout, " %s = 0;",
6860 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6861 last_arith_dst = &po->operand[0];
6862 delayed_flag_op = NULL;
6868 assert_operand_cnt(2);
6869 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6870 if (pfomask & (1 << PFO_C)) {
6871 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6872 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6873 if (po->operand[0].lmod == OPLM_DWORD) {
6874 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6875 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6876 fprintf(fout, " %s = (u32)tmp64;",
6877 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6878 strcat(g_comment, " add64");
6881 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6882 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6883 fprintf(fout, " %s += %s;",
6884 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6887 pfomask &= ~(1 << PFO_C);
6888 output_std_flags(fout, po, &pfomask, buf1);
6889 last_arith_dst = &po->operand[0];
6890 delayed_flag_op = NULL;
6893 if (pfomask & (1 << PFO_LE)) {
6894 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
6895 fprintf(fout, " cond_%s = %s;\n",
6896 parsed_flag_op_names[PFO_LE], buf1);
6897 pfomask &= ~(1 << PFO_LE);
6902 assert_operand_cnt(2);
6903 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6904 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6905 for (j = 0; j <= PFO_LE; j++) {
6906 if (!(pfomask & (1 << j)))
6908 if (j == PFO_Z || j == PFO_S)
6911 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6912 fprintf(fout, " cond_%s = %s;\n",
6913 parsed_flag_op_names[j], buf1);
6914 pfomask &= ~(1 << j);
6921 assert_operand_cnt(2);
6922 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6923 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6924 if (po->op == OP_SBB
6925 && IS(po->operand[0].name, po->operand[1].name))
6927 // avoid use of unitialized var
6928 fprintf(fout, " %s = -cond_c;", buf1);
6929 // carry remains what it was
6930 pfomask &= ~(1 << PFO_C);
6933 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6934 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6936 output_std_flags(fout, po, &pfomask, buf1);
6937 last_arith_dst = &po->operand[0];
6938 delayed_flag_op = NULL;
6943 // on SKL, if src is 0, dst is left unchanged
6944 assert_operand_cnt(2);
6945 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6946 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6947 output_std_flag_z(fout, po, &pfomask, buf2);
6948 if (po->op == OP_BSF)
6949 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
6951 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
6952 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
6953 last_arith_dst = &po->operand[0];
6954 delayed_flag_op = NULL;
6955 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
6959 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6960 for (j = 0; j <= PFO_LE; j++) {
6961 if (!(pfomask & (1 << j)))
6963 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6966 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6967 fprintf(fout, " cond_%s = %s;\n",
6968 parsed_flag_op_names[j], buf1);
6969 pfomask &= ~(1 << j);
6975 if (pfomask & (1 << PFO_C))
6976 // carry is unaffected by inc/dec.. wtf?
6977 ferr(po, "carry propagation needed\n");
6979 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6980 if (po->operand[0].type == OPT_REG) {
6981 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6982 fprintf(fout, " %s%s;", buf1, buf2);
6985 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6986 fprintf(fout, " %s %s= 1;", buf1, buf2);
6988 output_std_flags(fout, po, &pfomask, buf1);
6989 last_arith_dst = &po->operand[0];
6990 delayed_flag_op = NULL;
6994 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6995 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6996 fprintf(fout, " %s = -%s%s;", buf1,
6997 lmod_cast_s(po, po->operand[0].lmod), buf2);
6998 last_arith_dst = &po->operand[0];
6999 delayed_flag_op = NULL;
7000 if (pfomask & PFOB_C) {
7001 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
7004 output_std_flags(fout, po, &pfomask, buf1);
7008 if (po->operand_cnt == 2) {
7009 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7012 if (po->operand_cnt == 3)
7013 ferr(po, "TODO imul3\n");
7016 assert_operand_cnt(1);
7017 switch (po->operand[0].lmod) {
7019 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7020 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
7021 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7022 fprintf(fout, " edx = tmp64 >> 32;\n");
7023 fprintf(fout, " eax = tmp64;");
7026 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7027 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
7028 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7032 ferr(po, "TODO: unhandled mul type\n");
7035 last_arith_dst = NULL;
7036 delayed_flag_op = NULL;
7041 assert_operand_cnt(1);
7042 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7043 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7044 po->op == OP_IDIV));
7045 switch (po->operand[0].lmod) {
7047 if (po->flags & OPF_32BIT)
7048 snprintf(buf2, sizeof(buf2), "%seax", cast);
7050 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7051 snprintf(buf2, sizeof(buf2), "%stmp64",
7052 (po->op == OP_IDIV) ? "(s64)" : "");
7054 if (po->operand[0].type == OPT_REG
7055 && po->operand[0].reg == xDX)
7057 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
7058 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
7061 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
7062 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
7066 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
7067 snprintf(buf2, sizeof(buf2), "%stmp",
7068 (po->op == OP_IDIV) ? "(s32)" : "");
7069 if (po->operand[0].type == OPT_REG
7070 && po->operand[0].reg == xDX)
7072 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
7074 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
7078 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
7080 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
7083 strcat(g_comment, " div16");
7086 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7088 last_arith_dst = NULL;
7089 delayed_flag_op = NULL;
7094 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7096 for (j = 0; j < 8; j++) {
7097 if (pfomask & (1 << j)) {
7098 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7099 fprintf(fout, " cond_%s = %s;",
7100 parsed_flag_op_names[j], buf1);
7107 last_arith_dst = NULL;
7108 delayed_flag_op = po;
7112 // SETcc - should already be handled
7115 // note: we reuse OP_Jcc for SETcc, only flags differ
7117 fprintf(fout, "\n goto %s;", po->operand[0].name);
7121 fprintf(fout, " if (ecx == 0)\n");
7122 fprintf(fout, " goto %s;", po->operand[0].name);
7123 strcat(g_comment, " jecxz");
7127 fprintf(fout, " if (--ecx != 0)\n");
7128 fprintf(fout, " goto %s;", po->operand[0].name);
7129 strcat(g_comment, " loop");
7133 assert_operand_cnt(1);
7134 last_arith_dst = NULL;
7135 delayed_flag_op = NULL;
7137 if (po->operand[0].type == OPT_REGMEM) {
7138 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7141 ferr(po, "parse failure for jmp '%s'\n",
7142 po->operand[0].name);
7143 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
7146 else if (po->operand[0].type != OPT_LABEL)
7147 ferr(po, "unhandled jmp type\n");
7149 fprintf(fout, " goto %s;", po->operand[0].name);
7153 assert_operand_cnt(1);
7155 my_assert_not(pp, NULL);
7158 if (po->flags & OPF_CC) {
7159 // we treat conditional branch to another func
7160 // (yes such code exists..) as conditional tailcall
7162 fprintf(fout, " {\n");
7165 if (pp->is_fptr && !pp->is_arg) {
7166 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7167 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7169 if (pp->is_unresolved || IS_START(pp->name, "i_guess"))
7170 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7171 buf3, asmfn, po->asmln, pp->name);
7174 fprintf(fout, "%s", buf3);
7175 if (strstr(pp->ret_type.name, "int64")) {
7176 if (po->flags & OPF_TAIL)
7177 ferr(po, "int64 and tail?\n");
7178 fprintf(fout, "tmp64 = ");
7180 else if (!IS(pp->ret_type.name, "void")) {
7181 if (po->flags & OPF_TAIL) {
7182 if (regmask_ret & mxAX) {
7183 fprintf(fout, "return ");
7184 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7185 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7187 else if (regmask_ret & mxST0)
7188 ferr(po, "float tailcall\n");
7190 else if (po->regmask_dst & mxAX) {
7191 fprintf(fout, "eax = ");
7192 if (pp->ret_type.is_ptr)
7193 fprintf(fout, "(u32)");
7195 else if (po->regmask_dst & mxST0) {
7196 ferr_assert(po, po->flags & OPF_FPUSH);
7197 if (need_float_stack)
7198 fprintf(fout, "f_st[--f_stp & 7] = ");
7200 fprintf(fout, "f_st0 = ");
7204 if (pp->name[0] == 0)
7205 ferr(po, "missing pp->name\n");
7206 fprintf(fout, "%s%s(", pp->name,
7207 pp->has_structarg ? "_sa" : "");
7209 if (po->flags & OPF_ATAIL) {
7211 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7212 check_compat |= pp->argc_stack > 0;
7214 && (pp->argc_stack != g_func_pp->argc_stack
7215 || pp->is_stdcall != g_func_pp->is_stdcall))
7216 ferr(po, "incompatible arg-reuse tailcall\n");
7217 if (g_func_pp->has_retreg)
7218 ferr(po, "TODO: retreg+tailcall\n");
7220 for (arg = j = 0; arg < pp->argc; arg++) {
7222 fprintf(fout, ", ");
7225 if (pp->arg[arg].type.is_ptr)
7226 snprintf(cast, sizeof(cast), "(%s)",
7227 pp->arg[arg].type.name);
7229 if (pp->arg[arg].reg != NULL) {
7230 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7234 for (; j < g_func_pp->argc; j++)
7235 if (g_func_pp->arg[j].reg == NULL)
7237 fprintf(fout, "%sa%d", cast, j + 1);
7242 for (arg = 0; arg < pp->argc; arg++) {
7244 fprintf(fout, ", ");
7247 if (pp->arg[arg].type.is_ptr)
7248 snprintf(cast, sizeof(cast), "(%s)",
7249 pp->arg[arg].type.name);
7251 if (pp->arg[arg].reg != NULL) {
7252 if (pp->arg[arg].type.is_retreg)
7253 fprintf(fout, "&%s", pp->arg[arg].reg);
7254 else if (IS(pp->arg[arg].reg, "ebp")
7255 && g_bp_frame && !(po->flags & OPF_EBP_S))
7257 // rare special case
7258 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7259 strcat(g_comment, " bp_ref");
7262 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7267 tmp_op = pp->arg[arg].datap;
7269 ferr(po, "parsed_op missing for arg%d\n", arg);
7271 if (tmp_op->flags & OPF_VAPUSH) {
7272 fprintf(fout, "ap");
7274 else if (tmp_op->op == OP_FST) {
7275 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7276 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7279 else if (tmp_op->p_argpass != 0) {
7280 fprintf(fout, "a%d", tmp_op->p_argpass);
7282 else if (pp->arg[arg].is_saved) {
7283 ferr_assert(po, tmp_op->p_argnum > 0);
7284 fprintf(fout, "%s%s", cast,
7285 saved_arg_name(buf1, sizeof(buf1),
7286 tmp_op->p_arggrp, tmp_op->p_argnum));
7290 out_src_opr(buf1, sizeof(buf1),
7291 tmp_op, &tmp_op->operand[0], cast, 0));
7295 fprintf(fout, ");");
7297 if (strstr(pp->ret_type.name, "int64")) {
7298 fprintf(fout, "\n");
7299 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7300 fprintf(fout, "%seax = tmp64;", buf3);
7303 if (pp->is_unresolved) {
7304 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7306 strcat(g_comment, buf2);
7309 if (po->flags & OPF_TAIL) {
7311 if (i == opcnt - 1 || pp->is_noreturn)
7313 else if (IS(pp->ret_type.name, "void"))
7315 else if (!(regmask_ret & (1 << xAX)))
7317 // else already handled as 'return f()'
7320 fprintf(fout, "\n%sreturn;", buf3);
7321 strcat(g_comment, " ^ tailcall");
7324 strcat(g_comment, " tailcall");
7326 if ((regmask_ret & (1 << xAX))
7327 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7329 ferr(po, "int func -> void func tailcall?\n");
7332 if (pp->is_noreturn)
7333 strcat(g_comment, " noreturn");
7334 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7335 strcat(g_comment, " argframe");
7336 if (po->flags & OPF_CC)
7337 strcat(g_comment, " cond");
7339 if (po->flags & OPF_CC)
7340 fprintf(fout, "\n }");
7342 delayed_flag_op = NULL;
7343 last_arith_dst = NULL;
7347 if (g_func_pp->is_vararg)
7348 fprintf(fout, " va_end(ap);\n");
7349 if (g_func_pp->has_retreg) {
7350 for (arg = 0; arg < g_func_pp->argc; arg++)
7351 if (g_func_pp->arg[arg].type.is_retreg)
7352 fprintf(fout, " *r_%s = %s;\n",
7353 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7356 if (regmask_ret & mxST0) {
7357 fprintf(fout, " return %s;", float_st0);
7359 else if (!(regmask_ret & mxAX)) {
7360 if (i != opcnt - 1 || label_pending)
7361 fprintf(fout, " return;");
7363 else if (g_func_pp->ret_type.is_ptr) {
7364 fprintf(fout, " return (%s)eax;",
7365 g_func_pp->ret_type.name);
7367 else if (IS(g_func_pp->ret_type.name, "__int64"))
7368 fprintf(fout, " return ((u64)edx << 32) | eax;");
7370 fprintf(fout, " return eax;");
7372 last_arith_dst = NULL;
7373 delayed_flag_op = NULL;
7377 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7378 if (po->p_argnum != 0) {
7379 // special case - saved func arg
7380 fprintf(fout, " %s = %s;",
7381 saved_arg_name(buf2, sizeof(buf2),
7382 po->p_arggrp, po->p_argnum), buf1);
7385 else if (po->flags & OPF_RSAVE) {
7386 fprintf(fout, " s_%s = %s;", buf1, buf1);
7389 else if (po->flags & OPF_PPUSH) {
7391 ferr_assert(po, tmp_op != NULL);
7392 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7393 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7396 else if (g_func_pp->is_userstack) {
7397 fprintf(fout, " *(--esp) = %s;", buf1);
7400 if (!(g_ida_func_attr & IDAFA_NORETURN))
7401 ferr(po, "stray push encountered\n");
7406 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7407 if (po->flags & OPF_RSAVE) {
7408 fprintf(fout, " %s = s_%s;", buf1, buf1);
7411 else if (po->flags & OPF_PPUSH) {
7412 // push/pop graph / non-const
7413 ferr_assert(po, po->datap == NULL);
7414 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7417 else if (po->datap != NULL) {
7420 fprintf(fout, " %s = %s;", buf1,
7421 out_src_opr(buf2, sizeof(buf2),
7422 tmp_op, &tmp_op->operand[0],
7423 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7426 else if (g_func_pp->is_userstack) {
7427 fprintf(fout, " %s = *esp++;", buf1);
7431 ferr(po, "stray pop encountered\n");
7441 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7442 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7443 po->op == OPP_ALLSHL ? "<<" : ">>");
7444 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7445 strcat(g_comment, po->op == OPP_ALLSHL
7446 ? " allshl" : " allshr");
7451 if (need_float_stack) {
7452 out_src_opr_float(buf1, sizeof(buf1),
7453 po, &po->operand[0], 1);
7454 if (po->regmask_src & mxSTa) {
7455 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7459 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7462 if (po->flags & OPF_FSHIFT)
7463 fprintf(fout, " f_st1 = f_st0;");
7464 if (po->operand[0].type == OPT_REG
7465 && po->operand[0].reg == xST0)
7467 strcat(g_comment, " fld st");
7470 fprintf(fout, " f_st0 = %s;",
7471 out_src_opr_float(buf1, sizeof(buf1),
7472 po, &po->operand[0], 0));
7474 strcat(g_comment, " fld");
7478 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7479 lmod_cast(po, po->operand[0].lmod, 1), 0);
7480 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7481 if (need_float_stack) {
7482 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7485 if (po->flags & OPF_FSHIFT)
7486 fprintf(fout, " f_st1 = f_st0;");
7487 fprintf(fout, " f_st0 = %s;", buf2);
7489 strcat(g_comment, " fild");
7493 if (need_float_stack)
7494 fprintf(fout, " f_st[--f_stp & 7] = ");
7496 if (po->flags & OPF_FSHIFT)
7497 fprintf(fout, " f_st1 = f_st0;");
7498 fprintf(fout, " f_st0 = ");
7500 switch (po->operand[0].val) {
7501 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7502 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
7503 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7504 default: ferr(po, "TODO\n"); break;
7509 if (po->flags & OPF_FARG) {
7510 // store to stack as func arg
7511 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7515 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7517 dead_dst = po->operand[0].type == OPT_REG
7518 && po->operand[0].reg == xST0;
7521 fprintf(fout, " %s = %s;", buf1, float_st0);
7522 if (po->flags & OPF_FSHIFT) {
7523 if (need_float_stack)
7524 fprintf(fout, " f_stp++;");
7526 fprintf(fout, " f_st0 = f_st1;");
7528 if (dead_dst && !(po->flags & OPF_FSHIFT))
7531 strcat(g_comment, " fst");
7535 fprintf(fout, " %s = %s%s;",
7536 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7537 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7538 if (po->flags & OPF_FSHIFT) {
7539 if (need_float_stack)
7540 fprintf(fout, " f_stp++;");
7542 fprintf(fout, " f_st0 = f_st1;");
7544 strcat(g_comment, " fist");
7551 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7553 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7555 dead_dst = (po->flags & OPF_FPOP)
7556 && po->operand[0].type == OPT_REG
7557 && po->operand[0].reg == xST0;
7559 case OP_FADD: j = '+'; break;
7560 case OP_FDIV: j = '/'; break;
7561 case OP_FMUL: j = '*'; break;
7562 case OP_FSUB: j = '-'; break;
7563 default: j = 'x'; break;
7565 if (need_float_stack) {
7567 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7568 if (po->flags & OPF_FSHIFT)
7569 fprintf(fout, " f_stp++;");
7572 if (po->flags & OPF_FSHIFT) {
7573 // note: assumes only 2 regs handled
7575 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7577 fprintf(fout, " f_st0 = f_st1;");
7580 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7582 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7587 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7589 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7591 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7593 dead_dst = (po->flags & OPF_FPOP)
7594 && po->operand[0].type == OPT_REG
7595 && po->operand[0].reg == xST0;
7596 j = po->op == OP_FDIVR ? '/' : '-';
7597 if (need_float_stack) {
7599 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7600 if (po->flags & OPF_FSHIFT)
7601 fprintf(fout, " f_stp++;");
7604 if (po->flags & OPF_FSHIFT) {
7606 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7608 fprintf(fout, " f_st0 = f_st1;");
7611 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7613 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7621 case OP_FIADD: j = '+'; break;
7622 case OP_FIDIV: j = '/'; break;
7623 case OP_FIMUL: j = '*'; break;
7624 case OP_FISUB: j = '-'; break;
7625 default: j = 'x'; break;
7627 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7629 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7630 lmod_cast(po, po->operand[0].lmod, 1), 0));
7635 fprintf(fout, " %s = %s %c %s;", float_st0,
7636 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7638 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7643 ferr_assert(po, po->datap != NULL);
7644 mask = (long)po->datap & 0xffff;
7645 z_check = ((long)po->datap >> 16) & 1;
7646 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7648 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
7649 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7652 else if (mask == 0x4000) { // C3 -> =
7653 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7656 else if (mask == 0x4100) { // C3, C0
7658 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7660 strcat(g_comment, " z_chk_det");
7663 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7664 "(%s < %s ? 0x0100 : 0);",
7665 float_st0, buf1, float_st0, buf1);
7669 ferr(po, "unhandled sw mask: %x\n", mask);
7670 if (po->flags & OPF_FSHIFT) {
7671 if (need_float_stack)
7672 fprintf(fout, " f_stp++;");
7674 fprintf(fout, " f_st0 = f_st1;");
7680 fprintf(fout, " %s = f_sw;",
7681 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7685 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7689 fprintf(fout, " %s = cos%s(%s);", float_st0,
7690 need_double ? "" : "f", float_st0);
7694 if (need_float_stack) {
7695 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7696 need_double ? "" : "f", float_st1, float_st0);
7697 fprintf(fout, " f_stp++;");
7700 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7701 need_double ? "" : "f");
7706 if (need_float_stack) {
7707 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7708 float_st1, need_double ? "" : "f", float_st0);
7709 fprintf(fout, " f_stp++;");
7712 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7713 need_double ? "" : "f");
7715 strcat(g_comment, " fyl2x");
7719 fprintf(fout, " %s = sin%s(%s);", float_st0,
7720 need_double ? "" : "f", float_st0);
7724 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7725 need_double ? "" : "f", float_st0);
7729 dead_dst = po->operand[0].type == OPT_REG
7730 && po->operand[0].reg == xST0;
7732 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7734 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7735 float_st0, float_st0, buf1, buf1);
7736 strcat(g_comment, " fxch");
7743 ferr_assert(po, po->flags & OPF_32BIT);
7744 fprintf(fout, " eax = (s32)%s;", float_st0);
7745 if (po->flags & OPF_FSHIFT) {
7746 if (need_float_stack)
7747 fprintf(fout, " f_stp++;");
7749 fprintf(fout, " f_st0 = f_st1;");
7751 strcat(g_comment, " ftol");
7755 if (need_float_stack) {
7756 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
7757 need_double ? "" : "f", float_st1, float_st0);
7758 fprintf(fout, " f_stp++;");
7761 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
7762 need_double ? "" : "f");
7764 strcat(g_comment, " CIpow");
7768 fprintf(fout, " do_skip_code_abort();");
7773 fprintf(fout, " do_emms();");
7778 ferr(po, "unhandled op type %d, flags %x\n",
7783 if (g_comment[0] != 0) {
7784 char *p = g_comment;
7785 while (my_isblank(*p))
7787 fprintf(fout, " // %s", p);
7792 fprintf(fout, "\n");
7794 // some sanity checking
7795 if (po->flags & OPF_REP) {
7796 if (po->op != OP_STOS && po->op != OP_MOVS
7797 && po->op != OP_CMPS && po->op != OP_SCAS)
7798 ferr(po, "unexpected rep\n");
7799 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7800 && (po->op == OP_CMPS || po->op == OP_SCAS))
7801 ferr(po, "cmps/scas with plain rep\n");
7803 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7804 && po->op != OP_CMPS && po->op != OP_SCAS)
7805 ferr(po, "unexpected repz/repnz\n");
7808 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
7810 // see is delayed flag stuff is still valid
7811 if (delayed_flag_op != NULL && delayed_flag_op != po) {
7812 if (is_any_opr_modified(delayed_flag_op, po, 0))
7813 delayed_flag_op = NULL;
7816 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7817 if (is_opr_modified(last_arith_dst, po))
7818 last_arith_dst = NULL;
7825 if (g_stack_fsz && !g_stack_frame_used)
7826 fprintf(fout, " (void)sf;\n");
7828 fprintf(fout, "}\n\n");
7830 gen_x_cleanup(opcnt);
7833 static void gen_x_cleanup(int opcnt)
7837 for (i = 0; i < opcnt; i++) {
7838 struct label_ref *lr, *lr_del;
7840 lr = g_label_refs[i].next;
7841 while (lr != NULL) {
7846 g_label_refs[i].i = -1;
7847 g_label_refs[i].next = NULL;
7849 if (ops[i].op == OP_CALL) {
7851 proto_release(ops[i].pp);
7857 struct func_proto_dep;
7859 struct func_prototype {
7864 int has_ret:3; // -1, 0, 1: unresolved, no, yes
7865 unsigned int dep_resolved:1;
7866 unsigned int is_stdcall:1;
7867 struct func_proto_dep *dep_func;
7869 const struct parsed_proto *pp; // seed pp, if any
7872 struct func_proto_dep {
7874 struct func_prototype *proto;
7875 int regmask_live; // .. at the time of call
7876 unsigned int ret_dep:1; // return from this is caller's return
7879 static struct func_prototype *hg_fp;
7880 static int hg_fp_cnt;
7882 static struct scanned_var {
7884 enum opr_lenmod lmod;
7885 unsigned int is_seeded:1;
7886 unsigned int is_c_str:1;
7887 const struct parsed_proto *pp; // seed pp, if any
7889 static int hg_var_cnt;
7891 static char **hg_refs;
7892 static int hg_ref_cnt;
7894 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7897 static struct func_prototype *hg_fp_add(const char *funcn)
7899 struct func_prototype *fp;
7901 if ((hg_fp_cnt & 0xff) == 0) {
7902 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7903 my_assert_not(hg_fp, NULL);
7904 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7907 fp = &hg_fp[hg_fp_cnt];
7908 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7910 fp->argc_stack = -1;
7916 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7921 for (i = 0; i < fp->dep_func_cnt; i++)
7922 if (IS(fp->dep_func[i].name, name))
7923 return &fp->dep_func[i];
7928 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7931 if (hg_fp_find_dep(fp, name))
7934 if ((fp->dep_func_cnt & 0xff) == 0) {
7935 fp->dep_func = realloc(fp->dep_func,
7936 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7937 my_assert_not(fp->dep_func, NULL);
7938 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7939 sizeof(fp->dep_func[0]) * 0x100);
7941 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7945 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7947 const struct func_prototype *p1 = p1_, *p2 = p2_;
7948 return strcmp(p1->name, p2->name);
7952 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7954 const struct func_prototype *p1 = p1_, *p2 = p2_;
7955 return p1->id - p2->id;
7959 static void hg_ref_add(const char *name)
7961 if ((hg_ref_cnt & 0xff) == 0) {
7962 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7963 my_assert_not(hg_refs, NULL);
7964 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7967 hg_refs[hg_ref_cnt] = strdup(name);
7968 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7972 // recursive register dep pass
7973 // - track saved regs (part 2)
7974 // - try to figure out arg-regs
7975 // - calculate reg deps
7976 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
7977 struct func_prototype *fp, int regmask_save, int regmask_dst,
7978 int *regmask_dep, int *has_ret)
7980 struct func_proto_dep *dep;
7981 struct parsed_op *po;
7982 int from_caller = 0;
7987 for (; i < opcnt; i++)
7989 if (cbits[i >> 3] & (1 << (i & 7)))
7991 cbits[i >> 3] |= (1 << (i & 7));
7995 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
7996 if (po->flags & OPF_RMD)
7999 if (po->btj != NULL) {
8001 for (j = 0; j < po->btj->count; j++) {
8002 check_i(po, po->btj->d[j].bt_i);
8003 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8004 regmask_save, regmask_dst, regmask_dep, has_ret);
8009 check_i(po, po->bt_i);
8010 if (po->flags & OPF_CJMP) {
8011 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8012 regmask_save, regmask_dst, regmask_dep, has_ret);
8020 if (po->flags & OPF_FARG)
8021 /* (just calculate register deps) */;
8022 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8024 reg = po->operand[0].reg;
8025 ferr_assert(po, reg >= 0);
8027 if (po->flags & OPF_RSAVE) {
8028 regmask_save |= 1 << reg;
8031 if (po->flags & OPF_DONE)
8034 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
8036 regmask_save |= 1 << reg;
8037 po->flags |= OPF_RMD;
8038 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
8042 else if (po->flags & OPF_RMD)
8044 else if (po->op == OP_CALL) {
8045 po->regmask_dst |= 1 << xAX;
8047 dep = hg_fp_find_dep(fp, po->operand[0].name);
8049 dep->regmask_live = regmask_save | regmask_dst;
8050 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8051 dep->regmask_live |= 1 << xBP;
8054 else if (po->op == OP_RET) {
8055 if (po->operand_cnt > 0) {
8057 if (fp->argc_stack >= 0
8058 && fp->argc_stack != po->operand[0].val / 4)
8059 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8060 fp->argc_stack = po->operand[0].val / 4;
8064 // if has_ret is 0, there is uninitialized eax path,
8065 // which means it's most likely void func
8066 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
8067 if (po->op == OP_CALL) {
8072 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
8075 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
8078 if (ret != 1 && from_caller) {
8079 // unresolved eax - probably void func
8083 if (j >= 0 && ops[j].op == OP_CALL) {
8084 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8095 l = regmask_save | regmask_dst;
8096 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8099 l = po->regmask_src & ~l;
8102 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8103 l, regmask_dst, regmask_save, po->flags);
8106 regmask_dst |= po->regmask_dst;
8108 if (po->flags & OPF_TAIL)
8113 static void gen_hdr(const char *funcn, int opcnt)
8115 unsigned char cbits[MAX_OPS / 8];
8116 const struct parsed_proto *pp_c;
8117 struct parsed_proto *pp;
8118 struct func_prototype *fp;
8119 struct parsed_op *po;
8120 int regmask_dummy = 0;
8122 int max_bp_offset = 0;
8127 pp_c = proto_parse(g_fhdr, funcn, 1);
8129 // already in seed, will add to hg_fp later
8132 fp = hg_fp_add(funcn);
8134 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8135 g_stack_frame_used = 0;
8139 // - resolve all branches
8140 // - parse calls with labels
8141 resolve_branches_parse_calls(opcnt);
8144 // - handle ebp/esp frame, remove ops related to it
8145 scan_prologue_epilogue(opcnt, NULL);
8148 // - remove dead labels
8150 for (i = 0; i < opcnt; i++)
8152 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8158 if (po->flags & (OPF_RMD|OPF_DONE))
8161 if (po->op == OP_CALL) {
8162 if (po->operand[0].type == OPT_LABEL)
8163 hg_fp_add_dep(fp, opr_name(po, 0));
8164 else if (po->pp != NULL)
8165 hg_fp_add_dep(fp, po->pp->name);
8170 // - remove dead labels
8171 // - handle push <const>/pop pairs
8172 for (i = 0; i < opcnt; i++)
8174 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8180 if (po->flags & (OPF_RMD|OPF_DONE))
8183 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8184 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8188 // - process trivial calls
8189 for (i = 0; i < opcnt; i++)
8192 if (po->flags & (OPF_RMD|OPF_DONE))
8195 if (po->op == OP_CALL)
8197 pp = process_call_early(i, opcnt, &j);
8199 if (!(po->flags & OPF_ATAIL))
8200 // since we know the args, try to collect them
8201 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8207 // commit esp adjust
8208 if (ops[j].op != OP_POP)
8209 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8211 for (l = 0; l < pp->argc_stack; l++)
8212 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8216 po->flags |= OPF_DONE;
8222 // - track saved regs (simple)
8224 for (i = 0; i < opcnt; i++)
8227 if (po->flags & (OPF_RMD|OPF_DONE))
8230 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8231 && po->operand[0].reg != xCX)
8233 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8235 // regmask_save |= 1 << po->operand[0].reg; // do it later
8236 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8237 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8240 else if (po->op == OP_CALL)
8242 pp = process_call(i, opcnt);
8244 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8245 // since we know the args, collect them
8246 ret = collect_call_args(po, i, pp, ®mask_dummy,
8253 memset(cbits, 0, sizeof(cbits));
8257 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
8259 // find unreachable code - must be fixed in IDA
8260 for (i = 0; i < opcnt; i++)
8262 if (cbits[i >> 3] & (1 << (i & 7)))
8265 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8266 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8268 // the compiler sometimes still generates code after
8269 // noreturn OS functions
8272 if (ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8273 ferr(&ops[i], "unreachable code\n");
8276 for (i = 0; i < g_eqcnt; i++) {
8277 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8278 max_bp_offset = g_eqs[i].offset;
8281 if (fp->argc_stack < 0) {
8282 max_bp_offset = (max_bp_offset + 3) & ~3;
8283 fp->argc_stack = max_bp_offset / 4;
8284 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8288 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8289 fp->has_ret = has_ret;
8291 printf("// has_ret %d, regmask_dep %x\n",
8292 fp->has_ret, fp->regmask_dep);
8293 output_hdr_fp(stdout, fp, 1);
8294 if (IS(funcn, "sub_10007F72")) exit(1);
8297 gen_x_cleanup(opcnt);
8300 static void hg_fp_resolve_deps(struct func_prototype *fp)
8302 struct func_prototype fp_s;
8306 // this thing is recursive, so mark first..
8307 fp->dep_resolved = 1;
8309 for (i = 0; i < fp->dep_func_cnt; i++) {
8310 strcpy(fp_s.name, fp->dep_func[i].name);
8311 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8312 sizeof(hg_fp[0]), hg_fp_cmp_name);
8313 if (fp->dep_func[i].proto != NULL) {
8314 if (!fp->dep_func[i].proto->dep_resolved)
8315 hg_fp_resolve_deps(fp->dep_func[i].proto);
8317 dep = ~fp->dep_func[i].regmask_live
8318 & fp->dep_func[i].proto->regmask_dep;
8319 fp->regmask_dep |= dep;
8320 // printf("dep %s %s |= %x\n", fp->name,
8321 // fp->dep_func[i].name, dep);
8323 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8324 fp->has_ret = fp->dep_func[i].proto->has_ret;
8329 // make all thiscall/edx arg functions referenced from .data fastcall
8330 static void do_func_refs_from_data(void)
8332 struct func_prototype *fp, fp_s;
8335 for (i = 0; i < hg_ref_cnt; i++) {
8336 strcpy(fp_s.name, hg_refs[i]);
8337 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8338 sizeof(hg_fp[0]), hg_fp_cmp_name);
8342 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8343 fp->regmask_dep |= mxCX | mxDX;
8347 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8350 const struct parsed_proto *pp;
8351 char *p, namebuf[NAMELEN];
8357 for (; count > 0; count--, fp++) {
8358 if (fp->has_ret == -1)
8359 fprintf(fout, "// ret unresolved\n");
8361 fprintf(fout, "// dep:");
8362 for (j = 0; j < fp->dep_func_cnt; j++) {
8363 fprintf(fout, " %s/", fp->dep_func[j].name);
8364 if (fp->dep_func[j].proto != NULL)
8365 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8366 fp->dep_func[j].proto->has_ret);
8368 fprintf(fout, "\n");
8371 p = strchr(fp->name, '@');
8373 memcpy(namebuf, fp->name, p - fp->name);
8374 namebuf[p - fp->name] = 0;
8382 pp = proto_parse(g_fhdr, name, 1);
8383 if (pp != NULL && pp->is_include)
8386 if (fp->pp != NULL) {
8387 // part of seed, output later
8391 regmask_dep = fp->regmask_dep;
8392 argc_normal = fp->argc_stack;
8394 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8395 (fp->has_ret ? "int" : "void"));
8396 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8397 && (regmask_dep & ~mxCX) == 0)
8399 fprintf(fout, "/*__thiscall*/ ");
8403 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8404 && (regmask_dep & ~(mxCX | mxDX)) == 0)
8406 fprintf(fout, " __fastcall ");
8407 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8413 else if (regmask_dep && !fp->is_stdcall) {
8414 fprintf(fout, "/*__usercall*/ ");
8416 else if (regmask_dep) {
8417 fprintf(fout, "/*__userpurge*/ ");
8419 else if (fp->is_stdcall)
8420 fprintf(fout, " __stdcall ");
8422 fprintf(fout, " __cdecl ");
8424 fprintf(fout, "%s(", name);
8427 for (j = 0; j < xSP; j++) {
8428 if (regmask_dep & (1 << j)) {
8431 fprintf(fout, ", ");
8433 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8435 fprintf(fout, "int");
8436 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8440 for (j = 0; j < argc_normal; j++) {
8443 fprintf(fout, ", ");
8444 if (fp->pp != NULL) {
8445 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8446 if (!fp->pp->arg[arg - 1].type.is_ptr)
8450 fprintf(fout, "int ");
8451 fprintf(fout, "a%d", arg);
8454 fprintf(fout, ");\n");
8458 static void output_hdr(FILE *fout)
8460 static const char *lmod_c_names[] = {
8461 [OPLM_UNSPEC] = "???",
8462 [OPLM_BYTE] = "uint8_t",
8463 [OPLM_WORD] = "uint16_t",
8464 [OPLM_DWORD] = "uint32_t",
8465 [OPLM_QWORD] = "uint64_t",
8467 const struct scanned_var *var;
8468 struct func_prototype *fp;
8469 char line[256] = { 0, };
8473 // add stuff from headers
8474 for (i = 0; i < pp_cache_size; i++) {
8475 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8476 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8478 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8479 fp = hg_fp_add(name);
8480 fp->pp = &pp_cache[i];
8481 fp->argc_stack = fp->pp->argc_stack;
8482 fp->is_stdcall = fp->pp->is_stdcall;
8483 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8484 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8488 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8489 for (i = 0; i < hg_fp_cnt; i++)
8490 hg_fp_resolve_deps(&hg_fp[i]);
8492 // adjust functions referenced from data segment
8493 do_func_refs_from_data();
8495 // note: messes up .proto ptr, don't use
8496 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8499 for (i = 0; i < hg_var_cnt; i++) {
8502 if (var->pp != NULL)
8505 else if (var->is_c_str)
8506 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8508 fprintf(fout, "extern %-8s %s;",
8509 lmod_c_names[var->lmod], var->name);
8512 fprintf(fout, " // seeded");
8513 fprintf(fout, "\n");
8516 fprintf(fout, "\n");
8518 // output function prototypes
8519 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8522 fprintf(fout, "\n// - seed -\n");
8525 while (fgets(line, sizeof(line), g_fhdr))
8526 fwrite(line, 1, strlen(line), fout);
8529 // '=' needs special treatment
8531 static char *next_word_s(char *w, size_t wsize, char *s)
8538 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8540 for (i = 1; i < wsize - 1; i++) {
8542 printf("warning: missing closing quote: \"%s\"\n", s);
8551 for (; i < wsize - 1; i++) {
8552 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8558 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8559 printf("warning: '%s' truncated\n", w);
8564 static int cmpstringp(const void *p1, const void *p2)
8566 return strcmp(*(char * const *)p1, *(char * const *)p2);
8569 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8574 if (strstr(p, "..."))
8575 // unable to determine, assume needed
8578 if (*p == '.') // .text, .data, ...
8579 // ref from other data or non-function -> no
8582 p2 = strpbrk(p, "+:\r\n\x18");
8585 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8586 // referenced from removed code
8592 static int ida_xrefs_show_need(FILE *fasm, char *p,
8593 char **rlist, int rlist_len)
8599 p = strrchr(p, ';');
8600 if (p != NULL && *p == ';') {
8601 if (IS_START(p + 2, "sctref"))
8603 if (IS_START(p + 2, "DATA XREF: ")) {
8605 if (is_xref_needed(p, rlist, rlist_len))
8613 if (!my_fgets(line, sizeof(line), fasm))
8615 // non-first line is always indented
8616 if (!my_isblank(line[0]))
8619 // should be no content, just comment
8624 p = strrchr(p, ';');
8627 if (IS_START(p, "sctref")) {
8632 // it's printed once, but no harm to check again
8633 if (IS_START(p, "DATA XREF: "))
8636 if (is_xref_needed(p, rlist, rlist_len)) {
8641 fseek(fasm, pos, SEEK_SET);
8645 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8647 struct scanned_var *var;
8648 char line[256] = { 0, };
8657 // skip to next data section
8658 while (my_fgets(line, sizeof(line), fasm))
8663 if (*p == 0 || *p == ';')
8666 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8667 if (*p == 0 || *p == ';')
8670 if (*p != 's' || !IS_START(p, "segment para public"))
8676 if (p == NULL || !IS_START(p, "segment para public"))
8680 if (!IS_START(p, "'DATA'"))
8684 while (my_fgets(line, sizeof(line), fasm))
8689 no_identifier = my_isblank(*p);
8692 if (*p == 0 || *p == ';')
8695 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8696 words[wordc][0] = 0;
8697 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8698 if (*p == 0 || *p == ';') {
8704 if (wordc == 2 && IS(words[1], "ends"))
8709 if (no_identifier) {
8710 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8711 hg_ref_add(words[2]);
8715 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8716 // when this starts, we don't need anything from this section
8720 // check refs comment(s)
8721 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8724 if ((hg_var_cnt & 0xff) == 0) {
8725 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8726 * (hg_var_cnt + 0x100));
8727 my_assert_not(hg_vars, NULL);
8728 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8731 var = &hg_vars[hg_var_cnt++];
8732 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8734 // maybe already in seed header?
8735 var->pp = proto_parse(g_fhdr, var->name, 1);
8736 if (var->pp != NULL) {
8737 if (var->pp->is_fptr) {
8738 var->lmod = OPLM_DWORD;
8741 else if (var->pp->is_func)
8743 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8744 aerr("unhandled C type '%s' for '%s'\n",
8745 var->pp->type.name, var->name);
8751 if (IS(words[1], "dd")) {
8752 var->lmod = OPLM_DWORD;
8753 if (wordc >= 4 && IS(words[2], "offset"))
8754 hg_ref_add(words[3]);
8756 else if (IS(words[1], "dw"))
8757 var->lmod = OPLM_WORD;
8758 else if (IS(words[1], "db")) {
8759 var->lmod = OPLM_BYTE;
8760 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8761 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8765 else if (IS(words[1], "dq"))
8766 var->lmod = OPLM_QWORD;
8767 //else if (IS(words[1], "dt"))
8769 aerr("type '%s' not known\n", words[1]);
8777 static void set_label(int i, const char *name)
8783 p = strchr(name, ':');
8787 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8788 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8789 g_labels[i] = realloc(g_labels[i], len + 1);
8790 my_assert_not(g_labels[i], NULL);
8791 memcpy(g_labels[i], name, len);
8792 g_labels[i][len] = 0;
8801 static struct chunk_item *func_chunks;
8802 static int func_chunk_cnt;
8803 static int func_chunk_alloc;
8805 static void add_func_chunk(FILE *fasm, const char *name, int line)
8807 if (func_chunk_cnt >= func_chunk_alloc) {
8808 func_chunk_alloc *= 2;
8809 func_chunks = realloc(func_chunks,
8810 func_chunk_alloc * sizeof(func_chunks[0]));
8811 my_assert_not(func_chunks, NULL);
8813 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8814 func_chunks[func_chunk_cnt].name = strdup(name);
8815 func_chunks[func_chunk_cnt].asmln = line;
8819 static int cmp_chunks(const void *p1, const void *p2)
8821 const struct chunk_item *c1 = p1, *c2 = p2;
8822 return strcmp(c1->name, c2->name);
8825 static void scan_ahead_for_chunks(FILE *fasm)
8835 oldpos = ftell(fasm);
8838 while (my_fgets(line, sizeof(line), fasm))
8849 // get rid of random tabs
8850 for (i = 0; line[i] != 0; i++)
8851 if (line[i] == '\t')
8854 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8857 next_word(words[0], sizeof(words[0]), p);
8858 if (words[0][0] == 0)
8859 aerr("missing name for func chunk?\n");
8861 add_func_chunk(fasm, words[0], asmln);
8863 else if (IS_START(p, "; sctend"))
8869 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8870 words[wordc][0] = 0;
8871 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8872 if (*p == 0 || *p == ';') {
8878 if (wordc == 2 && IS(words[1], "ends"))
8882 fseek(fasm, oldpos, SEEK_SET);
8886 int main(int argc, char *argv[])
8888 FILE *fout, *fasm, *frlist;
8889 struct parsed_data *pd = NULL;
8891 char **rlist = NULL;
8893 int rlist_alloc = 0;
8894 int func_chunks_used = 0;
8895 int func_chunks_sorted = 0;
8896 int func_chunk_i = -1;
8897 long func_chunk_ret = 0;
8898 int func_chunk_ret_ln = 0;
8899 int scanned_ahead = 0;
8901 char words[20][256];
8902 enum opr_lenmod lmod;
8903 char *sctproto = NULL;
8905 int pending_endp = 0;
8907 int skip_code_end = 0;
8908 int skip_warned = 0;
8921 for (arg = 1; arg < argc; arg++) {
8922 if (IS(argv[arg], "-v"))
8924 else if (IS(argv[arg], "-rf"))
8925 g_allow_regfunc = 1;
8926 else if (IS(argv[arg], "-uc"))
8927 g_allow_user_icall = 1;
8928 else if (IS(argv[arg], "-m"))
8930 else if (IS(argv[arg], "-hdr"))
8931 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8936 if (argc < arg + 3) {
8937 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8938 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8940 " -hdr - header generation mode\n"
8941 " -rf - allow unannotated indirect calls\n"
8942 " -uc - allow ind. calls/refs to __usercall\n"
8943 " -m - allow multiple .text sections\n"
8944 "[rlist] is a file with function names to skip,"
8952 asmfn = argv[arg++];
8953 fasm = fopen(asmfn, "r");
8954 my_assert_not(fasm, NULL);
8956 hdrfn = argv[arg++];
8957 g_fhdr = fopen(hdrfn, "r");
8958 my_assert_not(g_fhdr, NULL);
8961 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8962 my_assert_not(rlist, NULL);
8963 // needs special handling..
8964 rlist[rlist_len++] = "__alloca_probe";
8966 func_chunk_alloc = 32;
8967 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8968 my_assert_not(func_chunks, NULL);
8970 memset(words, 0, sizeof(words));
8972 for (; arg < argc; arg++) {
8975 frlist = fopen(argv[arg], "r");
8976 my_assert_not(frlist, NULL);
8978 while (my_fgets(line, sizeof(line), frlist)) {
8980 if (*p == 0 || *p == ';')
8983 if (IS_START(p, "#if 0")
8984 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
8988 else if (IS_START(p, "#endif"))
8995 p = next_word(words[0], sizeof(words[0]), p);
8996 if (words[0][0] == 0)
8999 if (rlist_len >= rlist_alloc) {
9000 rlist_alloc = rlist_alloc * 2 + 64;
9001 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9002 my_assert_not(rlist, NULL);
9004 rlist[rlist_len++] = strdup(words[0]);
9012 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9014 fout = fopen(argv[arg_out], "w");
9015 my_assert_not(fout, NULL);
9018 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9019 my_assert_not(g_eqs, NULL);
9021 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9022 g_label_refs[i].i = -1;
9023 g_label_refs[i].next = NULL;
9027 scan_variables(fasm, rlist, rlist_len);
9029 while (my_fgets(line, sizeof(line), fasm))
9038 // get rid of random tabs
9039 for (i = 0; line[i] != 0; i++)
9040 if (line[i] == '\t')
9045 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9046 goto do_pending_endp; // eww..
9048 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9050 static const char *attrs[] = {
9059 // parse IDA's attribute-list comment
9060 g_ida_func_attr = 0;
9063 for (; *p != 0; p = sskip(p)) {
9064 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9065 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9066 g_ida_func_attr |= 1 << i;
9067 p += strlen(attrs[i]);
9071 if (i == ARRAY_SIZE(attrs)) {
9072 anote("unparsed IDA attr: %s\n", p);
9075 if (IS(attrs[i], "fpd=")) {
9076 p = next_word(words[0], sizeof(words[0]), p);
9081 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9083 static const char *attrs[] = {
9088 // parse manual attribute-list comment
9089 g_sct_func_attr = 0;
9092 for (; *p != 0; p = sskip(p)) {
9093 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9094 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9095 g_sct_func_attr |= 1 << i;
9096 p += strlen(attrs[i]);
9103 // clear_sf=start,len (in dwords)
9104 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9105 &g_stack_clear_len, &j);
9107 // clear_regmask=<mask>
9108 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9110 anote("unparsed attr value: %s\n", p);
9115 else if (i == ARRAY_SIZE(attrs)) {
9116 anote("unparsed sct attr: %s\n", p);
9121 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9124 next_word(words[0], sizeof(words[0]), p);
9125 if (words[0][0] == 0)
9126 aerr("missing name for func chunk?\n");
9128 if (!scanned_ahead) {
9129 add_func_chunk(fasm, words[0], asmln);
9130 func_chunks_sorted = 0;
9133 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9135 if (func_chunk_i >= 0) {
9136 if (func_chunk_i < func_chunk_cnt
9137 && IS(func_chunks[func_chunk_i].name, g_func))
9139 // move on to next chunk
9140 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9142 aerr("seek failed for '%s' chunk #%d\n",
9143 g_func, func_chunk_i);
9144 asmln = func_chunks[func_chunk_i].asmln;
9148 if (func_chunk_ret == 0)
9149 aerr("no return from chunk?\n");
9150 fseek(fasm, func_chunk_ret, SEEK_SET);
9151 asmln = func_chunk_ret_ln;
9157 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9158 func_chunks_used = 1;
9160 if (IS_START(g_func, "sub_")) {
9161 unsigned long addr = strtoul(p, NULL, 16);
9162 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9163 if (addr > f_addr && !scanned_ahead) {
9164 //anote("scan_ahead caused by '%s', addr %lx\n",
9166 scan_ahead_for_chunks(fasm);
9168 func_chunks_sorted = 0;
9176 for (i = wordc; i < ARRAY_SIZE(words); i++)
9178 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9179 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9180 if (*p == 0 || *p == ';') {
9185 if (*p != 0 && *p != ';')
9186 aerr("too many words\n");
9188 if (skip_code_end) {
9193 // allow asm patches in comments
9195 if (IS_START(p, "; sctpatch:")) {
9197 if (*p == 0 || *p == ';')
9199 goto parse_words; // lame
9201 if (IS_START(p, "; sctproto:")) {
9202 sctproto = strdup(p + 11);
9204 else if (IS_START(p, "; sctend")) {
9209 else if (IS_START(p, "; sctskip_start")) {
9210 if (in_func && !g_skip_func) {
9212 ops[pi].op = OPP_ABORT;
9213 ops[pi].asmln = asmln;
9219 else if (IS_START(p, "; sctskip_end")) {
9227 awarn("wordc == 0?\n");
9231 // don't care about this:
9232 if (words[0][0] == '.'
9233 || IS(words[0], "include")
9234 || IS(words[0], "assume") || IS(words[1], "segment")
9235 || IS(words[0], "align"))
9241 // do delayed endp processing to collect switch jumptables
9243 if (in_func && !g_skip_func && !end && wordc >= 2
9244 && ((words[0][0] == 'd' && words[0][2] == 0)
9245 || (words[1][0] == 'd' && words[1][2] == 0)))
9248 if (words[1][0] == 'd' && words[1][2] == 0) {
9250 if (g_func_pd_cnt >= pd_alloc) {
9251 pd_alloc = pd_alloc * 2 + 16;
9252 g_func_pd = realloc(g_func_pd,
9253 sizeof(g_func_pd[0]) * pd_alloc);
9254 my_assert_not(g_func_pd, NULL);
9256 pd = &g_func_pd[g_func_pd_cnt];
9258 memset(pd, 0, sizeof(*pd));
9259 strcpy(pd->label, words[0]);
9260 pd->type = OPT_CONST;
9261 pd->lmod = lmod_from_directive(words[1]);
9267 anote("skipping alignment byte?\n");
9270 lmod = lmod_from_directive(words[0]);
9271 if (lmod != pd->lmod)
9272 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9275 if (pd->count_alloc < pd->count + wordc) {
9276 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9277 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9278 my_assert_not(pd->d, NULL);
9280 for (; i < wordc; i++) {
9281 if (IS(words[i], "offset")) {
9282 pd->type = OPT_OFFSET;
9285 p = strchr(words[i], ',');
9288 if (pd->type == OPT_OFFSET)
9289 pd->d[pd->count].u.label = strdup(words[i]);
9291 pd->d[pd->count].u.val = parse_number(words[i], 0);
9292 pd->d[pd->count].bt_i = -1;
9298 if (in_func && !g_skip_func) {
9300 gen_hdr(g_func, pi);
9302 gen_func(fout, g_fhdr, g_func, pi);
9307 g_ida_func_attr = 0;
9308 g_sct_func_attr = 0;
9309 g_stack_clear_start = 0;
9310 g_stack_clear_len = 0;
9316 func_chunks_used = 0;
9319 memset(&ops, 0, pi * sizeof(ops[0]));
9324 for (i = 0; i < g_func_pd_cnt; i++) {
9326 if (pd->type == OPT_OFFSET) {
9327 for (j = 0; j < pd->count; j++)
9328 free(pd->d[j].u.label);
9343 if (IS(words[1], "proc")) {
9345 aerr("proc '%s' while in_func '%s'?\n",
9348 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9350 strcpy(g_func, words[0]);
9351 set_label(0, words[0]);
9356 if (IS(words[1], "endp"))
9359 aerr("endp '%s' while not in_func?\n", words[0]);
9360 if (!IS(g_func, words[0]))
9361 aerr("endp '%s' while in_func '%s'?\n",
9364 aerr("endp '%s' while skipping code\n", words[0]);
9366 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9367 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
9373 if (!g_skip_func && func_chunks_used) {
9374 // start processing chunks
9375 struct chunk_item *ci, key = { g_func, 0 };
9377 func_chunk_ret = ftell(fasm);
9378 func_chunk_ret_ln = asmln;
9379 if (!func_chunks_sorted) {
9380 qsort(func_chunks, func_chunk_cnt,
9381 sizeof(func_chunks[0]), cmp_chunks);
9382 func_chunks_sorted = 1;
9384 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9385 sizeof(func_chunks[0]), cmp_chunks);
9387 aerr("'%s' needs chunks, but none found\n", g_func);
9388 func_chunk_i = ci - func_chunks;
9389 for (; func_chunk_i > 0; func_chunk_i--)
9390 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9393 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9395 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9396 asmln = func_chunks[func_chunk_i].asmln;
9404 if (wordc == 2 && IS(words[1], "ends")) {
9408 goto do_pending_endp;
9412 // scan for next text segment
9413 while (my_fgets(line, sizeof(line), fasm)) {
9416 if (*p == 0 || *p == ';')
9419 if (strstr(p, "segment para public 'CODE' use32"))
9426 p = strchr(words[0], ':');
9428 set_label(pi, words[0]);
9432 if (!in_func || g_skip_func || skip_code) {
9433 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9435 anote("skipping from '%s'\n", g_labels[pi]);
9439 g_labels[pi] = NULL;
9443 if (wordc > 1 && IS(words[1], "="))
9446 aerr("unhandled equ, wc=%d\n", wordc);
9447 if (g_eqcnt >= eq_alloc) {
9449 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9450 my_assert_not(g_eqs, NULL);
9453 len = strlen(words[0]);
9454 if (len > sizeof(g_eqs[0].name) - 1)
9455 aerr("equ name too long: %d\n", len);
9456 strcpy(g_eqs[g_eqcnt].name, words[0]);
9458 if (!IS(words[3], "ptr"))
9459 aerr("unhandled equ\n");
9460 if (IS(words[2], "dword"))
9461 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9462 else if (IS(words[2], "word"))
9463 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9464 else if (IS(words[2], "byte"))
9465 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9466 else if (IS(words[2], "qword"))
9467 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9469 aerr("bad lmod: '%s'\n", words[2]);
9471 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9476 if (pi >= ARRAY_SIZE(ops))
9477 aerr("too many ops\n");
9479 parse_op(&ops[pi], words, wordc);
9481 ops[pi].datap = sctproto;
9496 // vim:ts=2:shiftwidth=2:expandtab