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"))
3783 // convert some calls to pseudo-ops
3784 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3785 if (!IS(tmpname, pseudo_ops[l].name))
3788 po->op = pseudo_ops[l].op;
3789 po->operand_cnt = 0;
3790 po->regmask_src = pseudo_ops[l].regmask_src;
3791 po->regmask_dst = pseudo_ops[l].regmask_dst;
3792 po->flags = pseudo_ops[l].flags;
3793 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3796 if (l < ARRAY_SIZE(pseudo_ops))
3799 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3800 if (!g_header_mode && pp_c == NULL)
3801 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3804 pp = proto_clone(pp_c);
3805 my_assert_not(pp, NULL);
3811 check_func_pp(po, pp, "fptr var call");
3812 if (pp->is_noreturn) {
3813 po->flags |= OPF_TAIL;
3814 po->flags &= ~OPF_ATAIL; // most likely...
3821 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3824 if (po->operand[0].type == OPT_REGMEM) {
3825 pd = try_resolve_jumptab(i, opcnt);
3833 for (l = 0; l < opcnt; l++) {
3834 if (g_labels[l] != NULL
3835 && IS(po->operand[0].name, g_labels[l]))
3837 if (l == i + 1 && po->op == OP_JMP) {
3838 // yet another alignment type..
3839 po->flags |= OPF_RMD|OPF_DONE;
3842 add_label_ref(&g_label_refs[l], i);
3848 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3851 if (po->operand[0].type == OPT_LABEL)
3855 ferr(po, "unhandled branch\n");
3859 po->flags |= OPF_TAIL;
3860 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3861 if (prev_op == OP_POP)
3862 po->flags |= OPF_ATAIL;
3863 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3864 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3866 po->flags |= OPF_ATAIL;
3872 static int resolve_origin(int i, const struct parsed_opr *opr,
3873 int magic, int *op_i, int *is_caller);
3875 static void eliminate_seh(int opcnt)
3879 for (i = 0; i < opcnt; i++) {
3880 if (ops[i].op != OP_MOV)
3882 if (ops[i].operand[0].segment != SEG_FS)
3884 if (!IS(opr_name(&ops[i], 0), "0"))
3887 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3888 if (ops[i].operand[1].reg == xSP) {
3889 for (j = i - 1; j >= 0; j--) {
3890 if (ops[j].op != OP_PUSH)
3892 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3894 if (ops[j].operand[0].val == ~0)
3896 if (ops[j].operand[0].type == OPT_REG) {
3898 ret = resolve_origin(j, &ops[j].operand[0],
3899 j + opcnt * 22, &k, NULL);
3901 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3905 ferr(ops, "missing seh terminator\n");
3909 ret = resolve_origin(i, &ops[i].operand[1],
3910 i + opcnt * 23, &k, NULL);
3912 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3916 // assume all sf writes above g_seh_size to be seh related
3917 // (probably unsafe but oh well)
3918 for (i = 0; i < opcnt; i++) {
3919 const struct parsed_opr *opr;
3923 if (ops[i].op != OP_MOV)
3925 opr = &ops[i].operand[0];
3926 if (opr->type != OPT_REGMEM)
3928 if (!is_stack_access(&ops[i], opr))
3931 parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
3933 if (offset < 0 && offset >= -g_seh_size)
3934 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3938 static void scan_prologue_epilogue(int opcnt, int *stack_align)
3940 int ecx_push = 0, esp_sub = 0, pusha = 0;
3941 int sandard_epilogue;
3946 eliminate_seh(opcnt);
3947 // ida treats seh as part of sf
3948 g_stack_fsz = g_seh_size;
3952 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3953 && ops[1].op == OP_MOV
3954 && IS(opr_name(&ops[1], 0), "ebp")
3955 && IS(opr_name(&ops[1], 1), "esp"))
3958 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3959 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3961 for (i = 2; i < opcnt; i++)
3962 if (!(ops[i].flags & OPF_DONE))
3965 if (ops[i].op == OP_PUSHA) {
3966 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3971 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
3972 && ops[i].operand[1].type == OPT_CONST)
3974 l = ops[i].operand[1].val;
3976 if (j == -1 || (l >> j) != -1)
3977 ferr(&ops[i], "unhandled esp align: %x\n", l);
3978 if (stack_align != NULL)
3979 *stack_align = 1 << j;
3980 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3984 if (ops[i].op == OP_SUB && IS(opr_name(&ops[i], 0), "esp")) {
3985 g_stack_fsz += opr_const(&ops[i], 1);
3986 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3990 // another way msvc builds stack frame..
3991 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3993 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3997 // and another way..
3998 if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3999 && ops[i].operand[1].type == OPT_CONST
4000 && ops[i + 1].op == OP_CALL
4001 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
4003 g_stack_fsz += ops[i].operand[1].val;
4004 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4006 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4013 for (; i < opcnt; i++)
4014 if (ops[i].flags & OPF_TAIL)
4017 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4018 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4024 sandard_epilogue = 0;
4025 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4027 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4028 // the standard epilogue is sometimes even used without a sf
4029 if (ops[j - 1].op == OP_MOV
4030 && IS(opr_name(&ops[j - 1], 0), "esp")
4031 && IS(opr_name(&ops[j - 1], 1), "ebp"))
4032 sandard_epilogue = 1;
4034 else if (ops[j].op == OP_LEAVE)
4036 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4037 sandard_epilogue = 1;
4039 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4040 && ops[i].pp->is_noreturn)
4042 // on noreturn, msvc sometimes cleans stack, sometimes not
4047 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4048 ferr(&ops[j], "'pop ebp' expected\n");
4050 if (g_stack_fsz != 0 || sandard_epilogue) {
4051 if (ops[j].op == OP_LEAVE)
4053 else if (sandard_epilogue) // mov esp, ebp
4055 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4058 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4060 ferr(&ops[j], "esp restore expected\n");
4063 if (ecx_push && j >= 0 && ops[j].op == OP_POP
4064 && IS(opr_name(&ops[j], 0), "ecx"))
4066 ferr(&ops[j], "unexpected ecx pop\n");
4071 if (ops[j].op == OP_POPA)
4072 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4074 ferr(&ops[j], "popa expected\n");
4079 } while (i < opcnt);
4082 ferr(ops, "missing ebp epilogue\n");
4087 for (i = 0; i < opcnt; i++)
4088 if (!(ops[i].flags & OPF_DONE))
4091 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4092 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4098 for (; i < opcnt; i++) {
4099 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
4101 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4102 && ops[i].operand[1].type == OPT_CONST)
4104 g_stack_fsz += ops[i].operand[1].val;
4105 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4110 else if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4111 && ops[i].operand[1].type == OPT_CONST
4112 && ops[i + 1].op == OP_CALL
4113 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
4115 g_stack_fsz += ops[i].operand[1].val;
4116 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4118 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4125 if (ecx_push && !esp_sub) {
4126 // could actually be args for a call..
4127 for (; i < opcnt; i++)
4128 if (ops[i].op != OP_PUSH)
4131 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4132 const struct parsed_proto *pp;
4133 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4134 j = pp ? pp->argc_stack : 0;
4135 while (i > 0 && j > 0) {
4137 if (ops[i].op == OP_PUSH) {
4138 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4143 ferr(&ops[i], "unhandled prologue\n");
4147 g_stack_fsz = g_seh_size;
4148 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4149 if (!(ops[i].flags & OPF_RMD))
4159 if (ecx_push || esp_sub)
4164 for (; i < opcnt; i++)
4165 if (ops[i].flags & OPF_TAIL)
4169 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4170 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4176 if (ecx_push > 0 && !esp_sub) {
4177 for (l = 0; l < ecx_push; l++) {
4178 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4180 else if (ops[j].op == OP_ADD
4181 && IS(opr_name(&ops[j], 0), "esp")
4182 && ops[j].operand[1].type == OPT_CONST)
4185 l += ops[j].operand[1].val / 4 - 1;
4190 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4193 if (l != ecx_push) {
4194 if (i < opcnt && ops[i].op == OP_CALL
4195 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4197 // noreturn tailcall with no epilogue
4202 ferr(&ops[j], "epilogue scan failed\n");
4209 if (ops[j].op != OP_ADD
4210 || !IS(opr_name(&ops[j], 0), "esp")
4211 || ops[j].operand[1].type != OPT_CONST)
4213 if (i < opcnt && ops[i].op == OP_CALL
4214 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4216 // noreturn tailcall with no epilogue
4221 ferr(&ops[j], "'add esp' expected\n");
4224 if (ops[j].operand[1].val < g_stack_fsz)
4225 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4227 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4228 if (ops[j].operand[1].val == 0)
4229 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4234 } while (i < opcnt);
4237 ferr(ops, "missing esp epilogue\n");
4241 // find an instruction that changed opr before i op
4242 // *op_i must be set to -1 by the caller
4243 // *is_caller is set to 1 if one source is determined to be g_func arg
4244 // returns 1 if found, *op_i is then set to origin
4245 // returns -1 if multiple origins are found
4246 static int resolve_origin(int i, const struct parsed_opr *opr,
4247 int magic, int *op_i, int *is_caller)
4249 struct label_ref *lr;
4253 if (g_labels[i] != NULL) {
4254 lr = &g_label_refs[i];
4255 for (; lr != NULL; lr = lr->next) {
4256 check_i(&ops[i], lr->i);
4257 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4259 if (i > 0 && LAST_OP(i - 1))
4265 if (is_caller != NULL)
4270 if (ops[i].cc_scratch == magic)
4272 ops[i].cc_scratch = magic;
4274 if (!(ops[i].flags & OPF_DATA))
4276 if (!is_opr_modified(opr, &ops[i]))
4280 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4291 // find an instruction that previously referenced opr
4292 // if multiple results are found - fail
4293 // *op_i must be set to -1 by the caller
4294 // returns 1 if found, *op_i is then set to referencer insn
4295 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4296 int magic, int *op_i)
4298 struct label_ref *lr;
4302 if (g_labels[i] != NULL) {
4303 lr = &g_label_refs[i];
4304 for (; lr != NULL; lr = lr->next) {
4305 check_i(&ops[i], lr->i);
4306 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4308 if (i > 0 && LAST_OP(i - 1))
4316 if (ops[i].cc_scratch == magic)
4318 ops[i].cc_scratch = magic;
4320 if (!is_opr_referenced(opr, &ops[i]))
4331 // adjust datap of all reachable 'op' insns when moving back
4332 // returns 1 if at least 1 op was found
4333 // returns -1 if path without an op was found
4334 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4336 struct label_ref *lr;
4339 if (ops[i].cc_scratch == magic)
4341 ops[i].cc_scratch = magic;
4344 if (g_labels[i] != NULL) {
4345 lr = &g_label_refs[i];
4346 for (; lr != NULL; lr = lr->next) {
4347 check_i(&ops[i], lr->i);
4348 ret |= adjust_prev_op(lr->i, op, magic, datap);
4350 if (i > 0 && LAST_OP(i - 1))
4358 if (ops[i].cc_scratch == magic)
4360 ops[i].cc_scratch = magic;
4362 if (ops[i].op != op)
4365 ops[i].datap = datap;
4370 // find next instruction that reads opr
4371 // *op_i must be set to -1 by the caller
4372 // on return, *op_i is set to first referencer insn
4373 // returns 1 if exactly 1 referencer is found
4374 static int find_next_read(int i, int opcnt,
4375 const struct parsed_opr *opr, int magic, int *op_i)
4377 struct parsed_op *po;
4380 for (; i < opcnt; i++)
4382 if (ops[i].cc_scratch == magic)
4384 ops[i].cc_scratch = magic;
4387 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4388 if (po->btj != NULL) {
4390 for (j = 0; j < po->btj->count; j++) {
4391 check_i(po, po->btj->d[j].bt_i);
4392 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4398 if (po->flags & OPF_RMD)
4400 check_i(po, po->bt_i);
4401 if (po->flags & OPF_CJMP) {
4402 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4411 if (!is_opr_read(opr, po)) {
4413 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4414 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4416 full_opr = po->operand[0].lmod >= opr->lmod;
4418 if (is_opr_modified(opr, po) && full_opr) {
4422 if (po->flags & OPF_TAIL)
4437 // find next instruction that reads opr
4438 // *op_i must be set to -1 by the caller
4439 // on return, *op_i is set to first flag user insn
4440 // returns 1 if exactly 1 flag user is found
4441 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4443 struct parsed_op *po;
4446 for (; i < opcnt; i++)
4448 if (ops[i].cc_scratch == magic)
4450 ops[i].cc_scratch = magic;
4453 if (po->op == OP_CALL)
4455 if (po->flags & OPF_JMP) {
4456 if (po->btj != NULL) {
4458 for (j = 0; j < po->btj->count; j++) {
4459 check_i(po, po->btj->d[j].bt_i);
4460 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4466 if (po->flags & OPF_RMD)
4468 check_i(po, po->bt_i);
4469 if (po->flags & OPF_CJMP)
4476 if (!(po->flags & OPF_CC)) {
4477 if (po->flags & OPF_FLAGS)
4480 if (po->flags & OPF_TAIL)
4496 static int try_resolve_const(int i, const struct parsed_opr *opr,
4497 int magic, unsigned int *val)
4502 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4505 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4508 *val = ops[i].operand[1].val;
4515 static int resolve_used_bits(int i, int opcnt, int reg,
4516 int *mask, int *is_z_check)
4518 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4522 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4526 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4528 fnote(&ops[j], "(first read)\n");
4529 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4532 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4533 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4535 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4536 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4538 *mask = ops[j].operand[1].val;
4539 if (ops[j].operand[0].lmod == OPLM_BYTE
4540 && ops[j].operand[0].name[1] == 'h')
4544 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4547 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4549 *is_z_check = ops[k].pfo == PFO_Z;
4554 static const struct parsed_proto *resolve_deref(int i, int magic,
4555 struct parsed_opr *opr, int level)
4557 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4558 const struct parsed_proto *pp = NULL;
4559 int from_caller = 0;
4568 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4569 if (ret != 2 || len != strlen(opr->name)) {
4570 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4571 if (ret != 1 || len != strlen(opr->name))
4575 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4580 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4584 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4585 && strlen(ops[j].operand[1].name) == 3
4586 && ops[j].operand[0].lmod == OPLM_DWORD
4587 && ops[j].pp == NULL // no hint
4590 // allow one simple dereference (com/directx)
4591 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4592 ops[j].operand[1].name);
4596 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4601 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4604 if (ops[j].pp != NULL) {
4608 else if (ops[j].operand[1].type == OPT_REGMEM) {
4609 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4611 // maybe structure ptr in structure
4612 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4615 else if (ops[j].operand[1].type == OPT_LABEL)
4616 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4617 else if (ops[j].operand[1].type == OPT_REG) {
4620 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4622 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4623 for (k = 0; k < g_func_pp->argc; k++) {
4624 if (g_func_pp->arg[k].reg == NULL)
4626 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4627 pp = g_func_pp->arg[k].pp;
4636 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4638 ferr(&ops[j], "expected struct, got '%s %s'\n",
4639 pp->type.name, pp->name);
4643 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4646 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4647 int *pp_i, int *multi_src)
4649 const struct parsed_proto *pp = NULL;
4650 int search_advice = 0;
4655 switch (ops[i].operand[0].type) {
4657 // try to resolve struct member calls
4658 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4664 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4670 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4678 static struct parsed_proto *process_call_early(int i, int opcnt,
4681 struct parsed_op *po = &ops[i];
4682 struct parsed_proto *pp;
4688 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4692 // look for and make use of esp adjust
4694 if (!pp->is_stdcall && pp->argc_stack > 0)
4695 ret = scan_for_esp_adjust(i + 1, opcnt,
4696 pp->argc_stack * 4, &adj, &multipath, 0);
4698 if (pp->argc_stack > adj / 4)
4702 if (ops[ret].op == OP_POP) {
4703 for (j = 1; j < adj / 4; j++) {
4704 if (ops[ret + j].op != OP_POP
4705 || ops[ret + j].operand[0].reg != xCX)
4717 static struct parsed_proto *process_call(int i, int opcnt)
4719 struct parsed_op *po = &ops[i];
4720 const struct parsed_proto *pp_c;
4721 struct parsed_proto *pp;
4722 const char *tmpname;
4723 int call_i = -1, ref_i = -1;
4724 int adj = 0, multipath = 0;
4727 tmpname = opr_name(po, 0);
4732 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4734 if (!pp_c->is_func && !pp_c->is_fptr)
4735 ferr(po, "call to non-func: %s\n", pp_c->name);
4736 pp = proto_clone(pp_c);
4737 my_assert_not(pp, NULL);
4739 // not resolved just to single func
4742 switch (po->operand[0].type) {
4744 // we resolved this call and no longer need the register
4745 po->regmask_src &= ~(1 << po->operand[0].reg);
4747 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4748 && ops[call_i].operand[1].type == OPT_LABEL)
4750 // no other source users?
4751 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4753 if (ret == 1 && call_i == ref_i) {
4754 // and nothing uses it after us?
4756 find_next_read(i + 1, opcnt, &po->operand[0],
4757 i + opcnt * 11, &ref_i);
4759 // then also don't need the source mov
4760 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4772 pp = calloc(1, sizeof(*pp));
4773 my_assert_not(pp, NULL);
4776 ret = scan_for_esp_adjust(i + 1, opcnt,
4777 -1, &adj, &multipath, 0);
4778 if (ret < 0 || adj < 0) {
4779 if (!g_allow_regfunc)
4780 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4781 pp->is_unresolved = 1;
4785 if (adj > ARRAY_SIZE(pp->arg))
4786 ferr(po, "esp adjust too large: %d\n", adj);
4787 pp->ret_type.name = strdup("int");
4788 pp->argc = pp->argc_stack = adj;
4789 for (arg = 0; arg < pp->argc; arg++)
4790 pp->arg[arg].type.name = strdup("int");
4795 // look for and make use of esp adjust
4798 if (!pp->is_stdcall && pp->argc_stack > 0) {
4799 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4800 ret = scan_for_esp_adjust(i + 1, opcnt,
4801 adj_expect, &adj, &multipath, 0);
4804 if (pp->is_vararg) {
4805 if (adj / 4 < pp->argc_stack) {
4806 fnote(po, "(this call)\n");
4807 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4808 adj, pp->argc_stack * 4);
4810 // modify pp to make it have varargs as normal args
4812 pp->argc += adj / 4 - pp->argc_stack;
4813 for (; arg < pp->argc; arg++) {
4814 pp->arg[arg].type.name = strdup("int");
4817 if (pp->argc > ARRAY_SIZE(pp->arg))
4818 ferr(po, "too many args for '%s'\n", tmpname);
4820 if (pp->argc_stack > adj / 4) {
4821 if (pp->is_noreturn)
4822 // assume no stack adjust was emited
4824 fnote(po, "(this call)\n");
4825 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4826 tmpname, pp->argc_stack * 4, adj);
4829 scan_for_esp_adjust(i + 1, opcnt,
4830 pp->argc_stack * 4, &adj, &multipath, 1);
4832 else if (pp->is_vararg)
4833 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4840 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
4843 struct parsed_op *po;
4849 for (base_arg = 0; base_arg < pp->argc; base_arg++)
4850 if (pp->arg[base_arg].reg == NULL)
4853 for (j = i; j > 0; )
4855 ferr_assert(&ops[j], g_labels[j] == NULL);
4859 ferr_assert(po, po->op != OP_PUSH);
4860 if (po->op == OP_FST)
4862 if (po->operand[0].type != OPT_REGMEM)
4864 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
4867 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
4868 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
4872 arg = base_arg + offset / 4;
4874 po->p_argnum = arg + 1;
4875 ferr_assert(po, pp->arg[arg].datap == NULL);
4876 pp->arg[arg].datap = po;
4877 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
4878 if (regmask_ffca != NULL)
4879 *regmask_ffca |= 1 << arg;
4881 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4882 && po->operand[1].type == OPT_CONST)
4884 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4889 for (arg = base_arg; arg < pp->argc; arg++) {
4890 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
4891 po = pp->arg[arg].datap;
4893 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
4894 if (po->operand[0].lmod == OPLM_QWORD)
4901 static int collect_call_args_early(int i, struct parsed_proto *pp,
4902 int *regmask, int *regmask_ffca)
4904 struct parsed_op *po;
4908 for (arg = 0; arg < pp->argc; arg++)
4909 if (pp->arg[arg].reg == NULL)
4912 // first see if it can be easily done
4913 for (j = i; j > 0 && arg < pp->argc; )
4915 if (g_labels[j] != NULL)
4920 if (po->op == OP_CALL)
4922 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
4924 else if (po->op == OP_POP)
4926 else if (po->flags & OPF_CJMP)
4928 else if (po->op == OP_PUSH) {
4929 if (po->flags & (OPF_FARG|OPF_FARGNR))
4931 if (!g_header_mode) {
4932 ret = scan_for_mod(po, j + 1, i, 1);
4937 if (pp->arg[arg].type.is_va_list)
4941 for (arg++; arg < pp->argc; arg++)
4942 if (pp->arg[arg].reg == NULL)
4945 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4946 && po->operand[1].type == OPT_CONST)
4948 if (po->flags & (OPF_RMD|OPF_DONE))
4950 if (po->operand[1].val != pp->argc_stack * 4)
4951 ferr(po, "unexpected esp adjust: %d\n",
4952 po->operand[1].val * 4);
4953 ferr_assert(po, pp->argc - arg == pp->argc_stack);
4954 return collect_call_args_no_push(i, pp, regmask_ffca);
4962 for (arg = 0; arg < pp->argc; arg++)
4963 if (pp->arg[arg].reg == NULL)
4966 for (j = i; j > 0 && arg < pp->argc; )
4970 if (ops[j].op == OP_PUSH)
4972 ops[j].p_argnext = -1;
4973 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4974 pp->arg[arg].datap = &ops[j];
4976 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
4977 *regmask |= 1 << ops[j].operand[0].reg;
4979 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4980 ops[j].flags &= ~OPF_RSAVE;
4983 for (arg++; arg < pp->argc; arg++)
4984 if (pp->arg[arg].reg == NULL)
4992 static int sync_argnum(struct parsed_op *po, int argnum)
4994 struct parsed_op *po_tmp;
4996 // see if other branches don't have higher argnum
4997 for (po_tmp = po; po_tmp != NULL; ) {
4998 if (argnum < po_tmp->p_argnum)
4999 argnum = po_tmp->p_argnum;
5000 // note: p_argnext is active on current collect_call_args only
5001 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5004 // make all argnums consistent
5005 for (po_tmp = po; po_tmp != NULL; ) {
5006 if (po_tmp->p_argnum != 0)
5007 po_tmp->p_argnum = argnum;
5008 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5014 static int collect_call_args_r(struct parsed_op *po, int i,
5015 struct parsed_proto *pp, int *regmask, int *arg_grp,
5016 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
5018 struct parsed_proto *pp_tmp;
5019 struct parsed_op *po_tmp;
5020 struct label_ref *lr;
5021 int need_to_save_current;
5022 int arg_grp_current = 0;
5023 int save_args_seen = 0;
5030 ferr(po, "dead label encountered\n");
5034 for (; arg < pp->argc; arg++, argnum++)
5035 if (pp->arg[arg].reg == NULL)
5037 magic = (magic & 0xffffff) | (arg << 24);
5039 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5041 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5042 if (ops[j].cc_scratch != magic) {
5043 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5047 // ok: have already been here
5050 ops[j].cc_scratch = magic;
5052 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5053 lr = &g_label_refs[j];
5054 if (lr->next != NULL)
5056 for (; lr->next; lr = lr->next) {
5057 check_i(&ops[j], lr->i);
5058 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5060 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5061 arg, argnum, magic, need_op_saving, may_reuse);
5066 check_i(&ops[j], lr->i);
5067 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5069 if (j > 0 && LAST_OP(j - 1)) {
5070 // follow last branch in reverse
5075 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5076 arg, argnum, magic, need_op_saving, may_reuse);
5082 if (ops[j].op == OP_CALL)
5084 if (pp->is_unresolved)
5089 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5090 arg, pp->argc, ops[j].operand[0].name);
5091 if (may_reuse && pp_tmp->argc_stack > 0)
5092 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5093 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5095 // esp adjust of 0 means we collected it before
5096 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5097 && (ops[j].operand[1].type != OPT_CONST
5098 || ops[j].operand[1].val != 0))
5100 if (pp->is_unresolved)
5103 fnote(po, "(this call)\n");
5104 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5105 arg, pp->argc, ops[j].operand[1].val);
5107 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5109 if (pp->is_unresolved)
5112 fnote(po, "(this call)\n");
5113 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5115 else if (ops[j].flags & OPF_CJMP)
5117 if (pp->is_unresolved)
5122 else if (ops[j].op == OP_PUSH
5123 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5125 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5128 ops[j].p_argnext = -1;
5129 po_tmp = pp->arg[arg].datap;
5131 ops[j].p_argnext = po_tmp - ops;
5132 pp->arg[arg].datap = &ops[j];
5134 argnum = sync_argnum(&ops[j], argnum);
5136 need_to_save_current = 0;
5138 if (ops[j].operand[0].type == OPT_REG)
5139 reg = ops[j].operand[0].reg;
5141 if (!need_op_saving) {
5142 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5143 need_to_save_current = (ret >= 0);
5145 if (need_op_saving || need_to_save_current) {
5146 // mark this arg as one that needs operand saving
5147 pp->arg[arg].is_saved = 1;
5149 if (save_args_seen & (1 << (argnum - 1))) {
5152 if (arg_grp_current >= MAX_ARG_GRP)
5153 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5157 else if (ops[j].p_argnum == 0)
5158 ops[j].flags |= OPF_RMD;
5160 // some PUSHes are reused by different calls on other branches,
5161 // but that can't happen if we didn't branch, so they
5162 // can be removed from future searches (handles nested calls)
5164 ops[j].flags |= OPF_FARGNR;
5166 ops[j].flags |= OPF_FARG;
5167 ops[j].flags &= ~OPF_RSAVE;
5169 // check for __VALIST
5170 if (!pp->is_unresolved && g_func_pp != NULL
5171 && pp->arg[arg].type.is_va_list)
5174 ret = resolve_origin(j, &ops[j].operand[0],
5175 magic + 1, &k, NULL);
5176 if (ret == 1 && k >= 0)
5178 if (ops[k].op == OP_LEA) {
5179 if (!g_func_pp->is_vararg)
5180 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5183 snprintf(buf, sizeof(buf), "arg_%X",
5184 g_func_pp->argc_stack * 4);
5185 if (strstr(ops[k].operand[1].name, buf)
5186 || strstr(ops[k].operand[1].name, "arglist"))
5188 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5189 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5190 pp->arg[arg].is_saved = 0;
5194 ferr(&ops[k], "va_list arg detection failed\n");
5196 // check for va_list from g_func_pp arg too
5197 else if (ops[k].op == OP_MOV
5198 && is_stack_access(&ops[k], &ops[k].operand[1]))
5200 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5201 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5203 ops[k].flags |= OPF_RMD | OPF_DONE;
5204 ops[j].flags |= OPF_RMD;
5205 ops[j].p_argpass = ret + 1;
5206 pp->arg[arg].is_saved = 0;
5213 if (pp->arg[arg].is_saved) {
5214 ops[j].flags &= ~OPF_RMD;
5215 ops[j].p_argnum = argnum;
5218 // tracking reg usage
5220 *regmask |= 1 << reg;
5224 if (!pp->is_unresolved) {
5226 for (; arg < pp->argc; arg++, argnum++)
5227 if (pp->arg[arg].reg == NULL)
5230 magic = (magic & 0xffffff) | (arg << 24);
5233 if (ops[j].p_arggrp > arg_grp_current) {
5235 arg_grp_current = ops[j].p_arggrp;
5237 if (ops[j].p_argnum > 0)
5238 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5241 if (arg < pp->argc) {
5242 ferr(po, "arg collect failed for '%s': %d/%d\n",
5243 pp->name, arg, pp->argc);
5247 if (arg_grp_current > *arg_grp)
5248 *arg_grp = arg_grp_current;
5253 static int collect_call_args(struct parsed_op *po, int i,
5254 struct parsed_proto *pp, int *regmask, int magic)
5256 // arg group is for cases when pushes for
5257 // multiple funcs are going on
5258 struct parsed_op *po_tmp;
5263 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5269 // propagate arg_grp
5270 for (a = 0; a < pp->argc; a++) {
5271 if (pp->arg[a].reg != NULL)
5274 po_tmp = pp->arg[a].datap;
5275 while (po_tmp != NULL) {
5276 po_tmp->p_arggrp = arg_grp;
5277 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5282 if (pp->is_unresolved) {
5284 pp->argc_stack += ret;
5285 for (a = 0; a < pp->argc; a++)
5286 if (pp->arg[a].type.name == NULL)
5287 pp->arg[a].type.name = strdup("int");
5293 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5294 int regmask_now, int *regmask,
5295 int regmask_save_now, int *regmask_save,
5296 int *regmask_init, int regmask_arg)
5298 struct parsed_op *po;
5306 for (; i < opcnt; i++)
5309 if (cbits[i >> 3] & (1 << (i & 7)))
5311 cbits[i >> 3] |= (1 << (i & 7));
5313 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5314 if (po->flags & (OPF_RMD|OPF_DONE))
5316 if (po->btj != NULL) {
5317 for (j = 0; j < po->btj->count; j++) {
5318 check_i(po, po->btj->d[j].bt_i);
5319 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5320 regmask_now, regmask, regmask_save_now, regmask_save,
5321 regmask_init, regmask_arg);
5326 check_i(po, po->bt_i);
5327 if (po->flags & OPF_CJMP)
5328 reg_use_pass(po->bt_i, opcnt, cbits,
5329 regmask_now, regmask, regmask_save_now, regmask_save,
5330 regmask_init, regmask_arg);
5336 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5337 && !g_func_pp->is_userstack
5338 && po->operand[0].type == OPT_REG)
5340 reg = po->operand[0].reg;
5341 ferr_assert(po, reg >= 0);
5344 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5345 if (regmask_now & (1 << reg)) {
5346 already_saved = regmask_save_now & (1 << reg);
5347 flags_set = OPF_RSAVE | OPF_DONE;
5350 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5352 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5353 reg, 0, 0, flags_set);
5356 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5358 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5363 ferr_assert(po, !already_saved);
5364 po->flags |= flags_set;
5366 if (regmask_now & (1 << reg)) {
5367 regmask_save_now |= (1 << reg);
5368 *regmask_save |= regmask_save_now;
5373 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5374 reg = po->operand[0].reg;
5375 ferr_assert(po, reg >= 0);
5377 if (regmask_save_now & (1 << reg))
5378 regmask_save_now &= ~(1 << reg);
5380 regmask_now &= ~(1 << reg);
5383 else if (po->op == OP_CALL) {
5384 if ((po->regmask_dst & (1 << xAX))
5385 && !(po->regmask_dst & (1 << xDX)))
5387 if (po->flags & OPF_TAIL)
5388 // don't need eax, will do "return f();" or "f(); return;"
5389 po->regmask_dst &= ~(1 << xAX);
5391 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5393 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5396 po->regmask_dst &= ~(1 << xAX);
5400 // not "full stack" mode and have something in stack
5401 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5402 ferr(po, "float stack is not empty on func call\n");
5405 if (po->flags & OPF_NOREGS)
5408 // if incomplete register is used, clear it on init to avoid
5409 // later use of uninitialized upper part in some situations
5410 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5411 && po->operand[0].lmod != OPLM_DWORD)
5413 reg = po->operand[0].reg;
5414 ferr_assert(po, reg >= 0);
5416 if (!(regmask_now & (1 << reg)))
5417 *regmask_init |= 1 << reg;
5420 regmask_op = po->regmask_src | po->regmask_dst;
5422 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5423 regmask_new &= ~(1 << xSP);
5424 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5425 regmask_new &= ~(1 << xBP);
5427 if (regmask_new != 0)
5428 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5430 if (regmask_op & (1 << xBP)) {
5431 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5432 if (po->regmask_dst & (1 << xBP))
5433 // compiler decided to drop bp frame and use ebp as scratch
5434 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5436 regmask_op &= ~(1 << xBP);
5440 if (po->flags & OPF_FPUSH) {
5441 if (regmask_now & mxST1)
5442 regmask_now |= mxSTa; // switch to "full stack" mode
5443 if (regmask_now & mxSTa)
5444 po->flags |= OPF_FSHIFT;
5445 if (!(regmask_now & mxST7_2)) {
5447 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5451 regmask_now |= regmask_op;
5452 *regmask |= regmask_now;
5455 if (po->flags & OPF_FPOP) {
5456 if ((regmask_now & mxSTa) == 0)
5457 ferr(po, "float pop on empty stack?\n");
5458 if (regmask_now & (mxST7_2 | mxST1))
5459 po->flags |= OPF_FSHIFT;
5460 if (!(regmask_now & mxST7_2)) {
5462 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5466 if (po->flags & OPF_TAIL) {
5467 if (!(regmask_now & mxST7_2)) {
5468 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5469 if (!(regmask_now & mxST0))
5470 ferr(po, "no st0 on float return, mask: %x\n",
5473 else if (regmask_now & mxST1_0)
5474 ferr(po, "float regs on tail: %x\n", regmask_now);
5477 // there is support for "conditional tailcall", sort of
5478 if (!(po->flags & OPF_CC))
5484 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5488 for (i = 0; i < pp->argc; i++)
5489 if (pp->arg[i].reg == NULL)
5493 memmove(&pp->arg[i + 1], &pp->arg[i],
5494 sizeof(pp->arg[0]) * pp->argc_stack);
5495 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5496 pp->arg[i].reg = strdup(reg);
5497 pp->arg[i].type.name = strdup("int");
5502 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5503 int *pfomask, const char *dst_opr_text)
5505 if (*pfomask & (1 << PFO_Z)) {
5506 fprintf(fout, "\n cond_z = (%s%s == 0);",
5507 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5508 *pfomask &= ~(1 << PFO_Z);
5512 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5513 int *pfomask, const char *dst_opr_text)
5515 if (*pfomask & (1 << PFO_S)) {
5516 fprintf(fout, "\n cond_s = (%s%s < 0);",
5517 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5518 *pfomask &= ~(1 << PFO_S);
5522 static void output_std_flags(FILE *fout, struct parsed_op *po,
5523 int *pfomask, const char *dst_opr_text)
5525 output_std_flag_z(fout, po, pfomask, dst_opr_text);
5526 output_std_flag_s(fout, po, pfomask, dst_opr_text);
5530 OPP_FORCE_NORETURN = (1 << 0),
5531 OPP_SIMPLE_ARGS = (1 << 1),
5532 OPP_ALIGN = (1 << 2),
5535 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5538 const char *cconv = "";
5540 if (pp->is_fastcall)
5541 cconv = "__fastcall ";
5542 else if (pp->is_stdcall && pp->argc_reg == 0)
5543 cconv = "__stdcall ";
5545 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5547 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5548 fprintf(fout, "noreturn ");
5551 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5556 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5560 output_pp_attrs(fout, pp, flags);
5563 fprintf(fout, "%s", pp->name);
5568 for (i = 0; i < pp->argc; i++) {
5570 fprintf(fout, ", ");
5571 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5572 && !(flags & OPP_SIMPLE_ARGS))
5575 output_pp(fout, pp->arg[i].pp, 0);
5577 else if (pp->arg[i].type.is_retreg) {
5578 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5581 fprintf(fout, "%s", pp->arg[i].type.name);
5583 fprintf(fout, " a%d", i + 1);
5586 if (pp->arg[i].type.is_64bit)
5589 if (pp->is_vararg) {
5591 fprintf(fout, ", ");
5592 fprintf(fout, "...");
5597 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5603 snprintf(buf1, sizeof(buf1), "%d", grp);
5604 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5609 static void gen_x_cleanup(int opcnt);
5611 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5613 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5614 struct parsed_opr *last_arith_dst = NULL;
5615 char buf1[256], buf2[256], buf3[256], cast[64];
5616 struct parsed_proto *pp, *pp_tmp;
5617 struct parsed_data *pd;
5618 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5619 unsigned char cbits[MAX_OPS / 8];
5620 const char *float_type;
5621 const char *float_st0;
5622 const char *float_st1;
5623 int need_float_stack = 0;
5624 int need_float_sw = 0; // status word
5625 int need_tmp_var = 0;
5629 int label_pending = 0;
5630 int need_double = 0;
5631 int stack_align = 0;
5632 int stack_fsz_adj = 0;
5633 int regmask_save = 0; // used regs saved/restored in this func
5634 int regmask_arg; // regs from this function args (fastcall, etc)
5635 int regmask_ret; // regs needed on ret
5636 int regmask_now; // temp
5637 int regmask_init = 0; // regs that need zero initialization
5638 int regmask_pp = 0; // regs used in complex push-pop graph
5639 int regmask_ffca = 0; // float function call args
5640 int regmask = 0; // used regs
5650 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5651 g_stack_frame_used = 0;
5653 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5654 regmask_init = g_regmask_init;
5656 g_func_pp = proto_parse(fhdr, funcn, 0);
5657 if (g_func_pp == NULL)
5658 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5660 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5661 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5664 // - resolve all branches
5665 // - parse calls with labels
5666 resolve_branches_parse_calls(opcnt);
5669 // - handle ebp/esp frame, remove ops related to it
5670 scan_prologue_epilogue(opcnt, &stack_align);
5672 // handle a case where sf size is unalignment, but is
5673 // placed in a way that elements are still aligned
5674 if (g_stack_fsz & 4) {
5675 for (i = 0; i < g_eqcnt; i++) {
5676 if (g_eqs[i].lmod != OPLM_QWORD)
5678 if (!(g_eqs[i].offset & 4)) {
5687 // - remove dead labels
5688 // - set regs needed at ret
5689 for (i = 0; i < opcnt; i++)
5691 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5696 if (ops[i].op == OP_RET)
5697 ops[i].regmask_src |= regmask_ret;
5701 // - process trivial calls
5702 for (i = 0; i < opcnt; i++)
5705 if (po->flags & (OPF_RMD|OPF_DONE))
5708 if (po->op == OP_CALL)
5710 pp = process_call_early(i, opcnt, &j);
5712 if (!(po->flags & OPF_ATAIL)) {
5713 // since we know the args, try to collect them
5714 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5722 // commit esp adjust
5723 if (ops[j].op != OP_POP)
5724 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5726 for (l = 0; l < pp->argc_stack; l++)
5727 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5731 if (strstr(pp->ret_type.name, "int64"))
5734 po->flags |= OPF_DONE;
5740 // - process calls, stage 2
5741 // - handle some push/pop pairs
5742 // - scan for STD/CLD, propagate DF
5743 // - try to resolve needed x87 status word bits
5744 for (i = 0; i < opcnt; i++)
5749 if (po->flags & OPF_RMD)
5752 if (po->op == OP_CALL)
5754 if (!(po->flags & OPF_DONE)) {
5755 pp = process_call(i, opcnt);
5757 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5758 // since we know the args, collect them
5759 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5761 // for unresolved, collect after other passes
5765 ferr_assert(po, pp != NULL);
5767 po->regmask_src |= get_pp_arg_regmask_src(pp);
5768 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5770 if (po->regmask_dst & mxST0)
5771 po->flags |= OPF_FPUSH;
5773 if (strstr(pp->ret_type.name, "int64"))
5779 if (po->flags & OPF_DONE)
5784 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
5785 && po->operand[0].type == OPT_CONST)
5787 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5792 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5796 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5797 scan_propagate_df(i + 1, opcnt);
5802 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
5803 ferr(po, "TODO: fnstsw to mem\n");
5804 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
5806 ferr(po, "fnstsw resolve failed\n");
5807 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
5808 (void *)(long)(mask | (z_check << 16)));
5810 ferr(po, "failed to find fcom: %d\n", ret);
5819 // - find POPs for PUSHes, rm both
5820 // - scan for all used registers
5821 memset(cbits, 0, sizeof(cbits));
5822 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5823 0, ®mask_save, ®mask_init, regmask_arg);
5825 need_float_stack = !!(regmask & mxST7_2);
5828 // - find flag set ops for their users
5829 // - do unresolved calls
5830 // - declare indirect functions
5831 // - other op specific processing
5832 for (i = 0; i < opcnt; i++)
5835 if (po->flags & (OPF_RMD|OPF_DONE))
5838 if (po->flags & OPF_CC)
5840 int setters[16], cnt = 0, branched = 0;
5842 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
5843 &branched, setters, &cnt);
5844 if (ret < 0 || cnt <= 0)
5845 ferr(po, "unable to trace flag setter(s)\n");
5846 if (cnt > ARRAY_SIZE(setters))
5847 ferr(po, "too many flag setters\n");
5849 for (j = 0; j < cnt; j++)
5851 tmp_op = &ops[setters[j]]; // flag setter
5854 // to get nicer code, we try to delay test and cmp;
5855 // if we can't because of operand modification, or if we
5856 // have arith op, or branch, make it calculate flags explicitly
5857 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5859 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5860 pfomask = 1 << po->pfo;
5862 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5863 pfomask = 1 << po->pfo;
5866 // see if we'll be able to handle based on op result
5867 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5868 && po->pfo != PFO_Z && po->pfo != PFO_S
5869 && po->pfo != PFO_P)
5871 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5873 pfomask = 1 << po->pfo;
5876 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5877 propagate_lmod(tmp_op, &tmp_op->operand[0],
5878 &tmp_op->operand[1]);
5879 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5884 tmp_op->pfomask |= pfomask;
5885 cond_vars |= pfomask;
5887 // note: may overwrite, currently not a problem
5891 if (po->op == OP_RCL || po->op == OP_RCR
5892 || po->op == OP_ADC || po->op == OP_SBB)
5893 cond_vars |= 1 << PFO_C;
5899 cond_vars |= 1 << PFO_Z;
5903 if (po->operand[0].lmod == OPLM_DWORD)
5908 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
5913 // note: resolved non-reg calls are OPF_DONE already
5915 ferr_assert(po, pp != NULL);
5917 if (pp->is_unresolved) {
5918 int regmask_stack = 0;
5919 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5921 // this is pretty rough guess:
5922 // see ecx and edx were pushed (and not their saved versions)
5923 for (arg = 0; arg < pp->argc; arg++) {
5924 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
5927 tmp_op = pp->arg[arg].datap;
5929 ferr(po, "parsed_op missing for arg%d\n", arg);
5930 if (tmp_op->operand[0].type == OPT_REG)
5931 regmask_stack |= 1 << tmp_op->operand[0].reg;
5934 if (!((regmask_stack & (1 << xCX))
5935 && (regmask_stack & (1 << xDX))))
5937 if (pp->argc_stack != 0
5938 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5940 pp_insert_reg_arg(pp, "ecx");
5941 pp->is_fastcall = 1;
5942 regmask_init |= 1 << xCX;
5943 regmask |= 1 << xCX;
5945 if (pp->argc_stack != 0
5946 || ((regmask | regmask_arg) & (1 << xDX)))
5948 pp_insert_reg_arg(pp, "edx");
5949 regmask_init |= 1 << xDX;
5950 regmask |= 1 << xDX;
5954 // note: __cdecl doesn't fall into is_unresolved category
5955 if (pp->argc_stack > 0)
5961 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
5963 // <var> = offset <something>
5964 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5965 && !IS_START(po->operand[1].name, "off_"))
5967 if (!po->operand[0].pp->is_fptr)
5968 ferr(po, "%s not declared as fptr when it should be\n",
5969 po->operand[0].name);
5970 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5971 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5972 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5973 fnote(po, "var: %s\n", buf1);
5974 fnote(po, "func: %s\n", buf2);
5975 ferr(po, "^ mismatch\n");
5983 if (po->operand[0].lmod == OPLM_DWORD) {
5984 // 32bit division is common, look for it
5985 if (po->op == OP_DIV)
5986 ret = scan_for_reg_clear(i, xDX);
5988 ret = scan_for_cdq_edx(i);
5990 po->flags |= OPF_32BIT;
5999 po->flags |= OPF_RMD | OPF_DONE;
6009 if (po->operand[0].lmod == OPLM_QWORD)
6019 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
6021 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
6023 po->flags |= OPF_32BIT;
6031 // this might need it's own pass...
6032 if (po->op != OP_FST && po->p_argnum > 0)
6033 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6035 // correct for "full stack" mode late enable
6036 if ((po->flags & (OPF_PPUSH|OPF_FPOP)) && need_float_stack)
6037 po->flags |= OPF_FSHIFT;
6040 float_type = need_double ? "double" : "float";
6041 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6042 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6044 // output starts here
6047 fprintf(fout, "// had SEH\n");
6049 // define userstack size
6050 if (g_func_pp->is_userstack) {
6051 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6052 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6053 fprintf(fout, "#endif\n");
6056 // the function itself
6057 ferr_assert(ops, !g_func_pp->is_fptr);
6058 output_pp(fout, g_func_pp,
6059 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6060 fprintf(fout, "\n{\n");
6062 // declare indirect functions
6063 for (i = 0; i < opcnt; i++) {
6065 if (po->flags & OPF_RMD)
6068 if (po->op == OP_CALL) {
6071 ferr(po, "NULL pp\n");
6073 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6074 if (pp->name[0] != 0) {
6075 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6076 memcpy(pp->name, "i_", 2);
6078 // might be declared already
6080 for (j = 0; j < i; j++) {
6081 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6082 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6092 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6095 output_pp(fout, pp, OPP_SIMPLE_ARGS);
6096 fprintf(fout, ";\n");
6101 // output LUTs/jumptables
6102 for (i = 0; i < g_func_pd_cnt; i++) {
6104 fprintf(fout, " static const ");
6105 if (pd->type == OPT_OFFSET) {
6106 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6108 for (j = 0; j < pd->count; j++) {
6110 fprintf(fout, ", ");
6111 fprintf(fout, "&&%s", pd->d[j].u.label);
6115 fprintf(fout, "%s %s[] =\n { ",
6116 lmod_type_u(ops, pd->lmod), pd->label);
6118 for (j = 0; j < pd->count; j++) {
6120 fprintf(fout, ", ");
6121 fprintf(fout, "%u", pd->d[j].u.val);
6124 fprintf(fout, " };\n");
6128 // declare stack frame, va_arg
6131 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6133 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6134 if (g_func_lmods & (1 << OPLM_WORD))
6135 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6136 if (g_func_lmods & (1 << OPLM_BYTE))
6137 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6138 if (g_func_lmods & (1 << OPLM_QWORD))
6139 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6141 if (stack_align > 8)
6142 ferr(ops, "unhandled stack align of %d\n", stack_align);
6143 else if (stack_align == 8)
6144 fprintf(fout, " u64 align;");
6145 fprintf(fout, " } sf;\n");
6149 if (g_func_pp->is_userstack) {
6150 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6151 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6155 if (g_func_pp->is_vararg) {
6156 fprintf(fout, " va_list ap;\n");
6160 // declare arg-registers
6161 for (i = 0; i < g_func_pp->argc; i++) {
6162 if (g_func_pp->arg[i].reg != NULL) {
6163 reg = char_array_i(regs_r32,
6164 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6165 if (regmask & (1 << reg)) {
6166 if (g_func_pp->arg[i].type.is_retreg)
6167 fprintf(fout, " u32 %s = *r_%s;\n",
6168 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6170 fprintf(fout, " u32 %s = (u32)a%d;\n",
6171 g_func_pp->arg[i].reg, i + 1);
6174 if (g_func_pp->arg[i].type.is_retreg)
6175 ferr(ops, "retreg '%s' is unused?\n",
6176 g_func_pp->arg[i].reg);
6177 fprintf(fout, " // %s = a%d; // unused\n",
6178 g_func_pp->arg[i].reg, i + 1);
6184 // declare normal registers
6185 regmask_now = regmask & ~regmask_arg;
6186 regmask_now &= ~(1 << xSP);
6187 if (regmask_now & 0x00ff) {
6188 for (reg = 0; reg < 8; reg++) {
6189 if (regmask_now & (1 << reg)) {
6190 fprintf(fout, " u32 %s", regs_r32[reg]);
6191 if (regmask_init & (1 << reg))
6192 fprintf(fout, " = 0");
6193 fprintf(fout, ";\n");
6199 if (regmask_now & 0xff00) {
6200 for (reg = 8; reg < 16; reg++) {
6201 if (regmask_now & (1 << reg)) {
6202 fprintf(fout, " mmxr %s", regs_r32[reg]);
6203 if (regmask_init & (1 << reg))
6204 fprintf(fout, " = { 0, }");
6205 fprintf(fout, ";\n");
6211 if (need_float_stack) {
6212 fprintf(fout, " %s f_st[8];\n", float_type);
6213 fprintf(fout, " int f_stp = 0;\n");
6217 if (regmask_now & 0xff0000) {
6218 for (reg = 16; reg < 24; reg++) {
6219 if (regmask_now & (1 << reg)) {
6220 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6221 if (regmask_init & (1 << reg))
6222 fprintf(fout, " = 0");
6223 fprintf(fout, ";\n");
6230 if (need_float_sw) {
6231 fprintf(fout, " u16 f_sw;\n");
6236 for (reg = 0; reg < 8; reg++) {
6237 if (regmask_save & (1 << reg)) {
6238 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6244 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6245 if (save_arg_vars[i] == 0)
6247 for (reg = 0; reg < 32; reg++) {
6248 if (save_arg_vars[i] & (1 << reg)) {
6249 fprintf(fout, " u32 %s;\n",
6250 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6257 for (reg = 0; reg < 32; reg++) {
6258 if (regmask_ffca & (1 << reg)) {
6259 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6265 // declare push-pop temporaries
6267 for (reg = 0; reg < 8; reg++) {
6268 if (regmask_pp & (1 << reg)) {
6269 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6276 for (i = 0; i < 8; i++) {
6277 if (cond_vars & (1 << i)) {
6278 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6285 fprintf(fout, " u32 tmp;\n");
6290 fprintf(fout, " u64 tmp64;\n");
6295 fprintf(fout, "\n");
6297 // do stack clear, if needed
6298 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6300 if (g_stack_clear_len != 0) {
6301 if (g_stack_clear_len <= 4) {
6302 for (i = 0; i < g_stack_clear_len; i++)
6303 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6304 fprintf(fout, "0;\n");
6307 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6308 g_stack_clear_start, g_stack_clear_len * 4);
6312 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6315 if (g_func_pp->is_vararg) {
6316 if (g_func_pp->argc_stack == 0)
6317 ferr(ops, "vararg func without stack args?\n");
6318 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6322 for (i = 0; i < opcnt; i++)
6324 if (g_labels[i] != NULL) {
6325 fprintf(fout, "\n%s:\n", g_labels[i]);
6328 delayed_flag_op = NULL;
6329 last_arith_dst = NULL;
6333 if (po->flags & OPF_RMD)
6338 #define assert_operand_cnt(n_) \
6339 if (po->operand_cnt != n_) \
6340 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6342 // conditional/flag using op?
6343 if (po->flags & OPF_CC)
6349 // we go through all this trouble to avoid using parsed_flag_op,
6350 // which makes generated code much nicer
6351 if (delayed_flag_op != NULL)
6353 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6354 po->pfo, po->pfo_inv);
6357 else if (last_arith_dst != NULL
6358 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6359 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6362 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6363 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6364 last_arith_dst->lmod, buf3);
6367 else if (tmp_op != NULL) {
6368 // use preprocessed flag calc results
6369 if (!(tmp_op->pfomask & (1 << po->pfo)))
6370 ferr(po, "not prepared for pfo %d\n", po->pfo);
6372 // note: pfo_inv was not yet applied
6373 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6374 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6377 ferr(po, "all methods of finding comparison failed\n");
6380 if (po->flags & OPF_JMP) {
6381 fprintf(fout, " if %s", buf1);
6383 else if (po->op == OP_RCL || po->op == OP_RCR
6384 || po->op == OP_ADC || po->op == OP_SBB)
6387 fprintf(fout, " cond_%s = %s;\n",
6388 parsed_flag_op_names[po->pfo], buf1);
6390 else if (po->flags & OPF_DATA) { // SETcc
6391 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6392 fprintf(fout, " %s = %s;", buf2, buf1);
6395 ferr(po, "unhandled conditional op\n");
6399 pfomask = po->pfomask;
6404 assert_operand_cnt(2);
6405 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6406 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6407 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6408 fprintf(fout, " %s = %s;", buf1,
6409 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6414 assert_operand_cnt(2);
6415 po->operand[1].lmod = OPLM_DWORD; // always
6416 fprintf(fout, " %s = %s;",
6417 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6418 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6423 assert_operand_cnt(2);
6424 fprintf(fout, " %s = %s;",
6425 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6426 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6430 assert_operand_cnt(2);
6431 switch (po->operand[1].lmod) {
6433 strcpy(buf3, "(s8)");
6436 strcpy(buf3, "(s16)");
6439 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6441 fprintf(fout, " %s = %s;",
6442 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6443 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6448 assert_operand_cnt(2);
6449 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6450 fprintf(fout, " tmp = %s;",
6451 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6452 fprintf(fout, " %s = %s;",
6453 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6454 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6455 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6456 fprintf(fout, " %s = %stmp;",
6457 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6458 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6459 snprintf(g_comment, sizeof(g_comment), "xchg");
6463 assert_operand_cnt(1);
6464 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6465 fprintf(fout, " %s = ~%s;", buf1, buf1);
6469 assert_operand_cnt(2);
6470 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6471 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6472 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6473 strcpy(g_comment, "xlat");
6477 assert_operand_cnt(2);
6478 fprintf(fout, " %s = (s32)%s >> 31;",
6479 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6480 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6481 strcpy(g_comment, "cdq");
6485 assert_operand_cnt(1);
6486 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6487 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6491 if (po->flags & OPF_REP) {
6492 assert_operand_cnt(3);
6497 assert_operand_cnt(2);
6498 fprintf(fout, " %s = %sesi; esi %c= %d;",
6499 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6500 lmod_cast_u_ptr(po, po->operand[1].lmod),
6501 (po->flags & OPF_DF) ? '-' : '+',
6502 lmod_bytes(po, po->operand[1].lmod));
6503 strcpy(g_comment, "lods");
6508 if (po->flags & OPF_REP) {
6509 assert_operand_cnt(3);
6510 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6511 (po->flags & OPF_DF) ? '-' : '+',
6512 lmod_bytes(po, po->operand[1].lmod));
6513 fprintf(fout, " %sedi = eax;",
6514 lmod_cast_u_ptr(po, po->operand[1].lmod));
6515 strcpy(g_comment, "rep stos");
6518 assert_operand_cnt(2);
6519 fprintf(fout, " %sedi = eax; edi %c= %d;",
6520 lmod_cast_u_ptr(po, po->operand[1].lmod),
6521 (po->flags & OPF_DF) ? '-' : '+',
6522 lmod_bytes(po, po->operand[1].lmod));
6523 strcpy(g_comment, "stos");
6528 j = lmod_bytes(po, po->operand[0].lmod);
6529 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6530 l = (po->flags & OPF_DF) ? '-' : '+';
6531 if (po->flags & OPF_REP) {
6532 assert_operand_cnt(3);
6534 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6537 " %sedi = %sesi;", buf1, buf1);
6538 strcpy(g_comment, "rep movs");
6541 assert_operand_cnt(2);
6542 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6543 buf1, buf1, l, j, l, j);
6544 strcpy(g_comment, "movs");
6549 // repe ~ repeat while ZF=1
6550 j = lmod_bytes(po, po->operand[0].lmod);
6551 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6552 l = (po->flags & OPF_DF) ? '-' : '+';
6553 if (po->flags & OPF_REP) {
6554 assert_operand_cnt(3);
6556 " while (ecx != 0) {\n");
6557 if (pfomask & (1 << PFO_C)) {
6560 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6561 pfomask &= ~(1 << PFO_C);
6564 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6565 buf1, buf1, l, j, l, j);
6568 " if (cond_z %s 0) break;\n",
6569 (po->flags & OPF_REPZ) ? "==" : "!=");
6572 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6573 (po->flags & OPF_REPZ) ? "e" : "ne");
6576 assert_operand_cnt(2);
6578 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6579 buf1, buf1, l, j, l, j);
6580 strcpy(g_comment, "cmps");
6582 pfomask &= ~(1 << PFO_Z);
6583 last_arith_dst = NULL;
6584 delayed_flag_op = NULL;
6588 // only does ZF (for now)
6589 // repe ~ repeat while ZF=1
6590 j = lmod_bytes(po, po->operand[1].lmod);
6591 l = (po->flags & OPF_DF) ? '-' : '+';
6592 if (po->flags & OPF_REP) {
6593 assert_operand_cnt(3);
6595 " while (ecx != 0) {\n");
6597 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6598 lmod_cast_u(po, po->operand[1].lmod),
6599 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6602 " if (cond_z %s 0) break;\n",
6603 (po->flags & OPF_REPZ) ? "==" : "!=");
6606 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6607 (po->flags & OPF_REPZ) ? "e" : "ne");
6610 assert_operand_cnt(2);
6611 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6612 lmod_cast_u(po, po->operand[1].lmod),
6613 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6614 strcpy(g_comment, "scas");
6616 pfomask &= ~(1 << PFO_Z);
6617 last_arith_dst = NULL;
6618 delayed_flag_op = NULL;
6621 // arithmetic w/flags
6623 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6624 goto dualop_arith_const;
6625 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6629 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6630 if (po->operand[1].type == OPT_CONST) {
6631 j = lmod_bytes(po, po->operand[0].lmod);
6632 if (((1ull << j * 8) - 1) == po->operand[1].val)
6633 goto dualop_arith_const;
6638 assert_operand_cnt(2);
6639 fprintf(fout, " %s %s= %s;",
6640 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6642 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6643 output_std_flags(fout, po, &pfomask, buf1);
6644 last_arith_dst = &po->operand[0];
6645 delayed_flag_op = NULL;
6649 // and 0, or ~0 used instead mov
6650 assert_operand_cnt(2);
6651 fprintf(fout, " %s = %s;",
6652 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6653 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6654 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6655 output_std_flags(fout, po, &pfomask, buf1);
6656 last_arith_dst = &po->operand[0];
6657 delayed_flag_op = NULL;
6662 assert_operand_cnt(2);
6663 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6664 if (pfomask & (1 << PFO_C)) {
6665 if (po->operand[1].type == OPT_CONST) {
6666 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6667 j = po->operand[1].val;
6670 if (po->op == OP_SHL)
6674 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6678 ferr(po, "zero shift?\n");
6682 pfomask &= ~(1 << PFO_C);
6684 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6685 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6686 if (po->operand[1].type != OPT_CONST)
6687 fprintf(fout, " & 0x1f");
6689 output_std_flags(fout, po, &pfomask, buf1);
6690 last_arith_dst = &po->operand[0];
6691 delayed_flag_op = NULL;
6695 assert_operand_cnt(2);
6696 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6697 fprintf(fout, " %s = %s%s >> %s;", buf1,
6698 lmod_cast_s(po, po->operand[0].lmod), buf1,
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;
6707 assert_operand_cnt(3);
6708 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6709 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6710 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6711 if (po->operand[2].type != OPT_CONST) {
6712 // no handling for "undefined" case, hopefully not needed
6713 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6716 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6717 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6718 if (po->op == OP_SHLD) {
6719 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6720 buf1, buf3, buf1, buf2, l, buf3);
6721 strcpy(g_comment, "shld");
6724 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6725 buf1, buf3, buf1, buf2, l, buf3);
6726 strcpy(g_comment, "shrd");
6728 output_std_flags(fout, po, &pfomask, buf1);
6729 last_arith_dst = &po->operand[0];
6730 delayed_flag_op = NULL;
6735 assert_operand_cnt(2);
6736 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6737 if (po->operand[1].type == OPT_CONST) {
6738 j = po->operand[1].val;
6739 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6740 fprintf(fout, po->op == OP_ROL ?
6741 " %s = (%s << %d) | (%s >> %d);" :
6742 " %s = (%s >> %d) | (%s << %d);",
6743 buf1, buf1, j, buf1,
6744 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6748 output_std_flags(fout, po, &pfomask, buf1);
6749 last_arith_dst = &po->operand[0];
6750 delayed_flag_op = NULL;
6755 assert_operand_cnt(2);
6756 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6757 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6758 if (po->operand[1].type == OPT_CONST) {
6759 j = po->operand[1].val % l;
6761 ferr(po, "zero rotate\n");
6762 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6763 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6764 if (po->op == OP_RCL) {
6766 " %s = (%s << %d) | (cond_c << %d)",
6767 buf1, buf1, j, j - 1);
6769 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6773 " %s = (%s >> %d) | (cond_c << %d)",
6774 buf1, buf1, j, l - j);
6776 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6778 fprintf(fout, ";\n");
6779 fprintf(fout, " cond_c = tmp;");
6783 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6784 output_std_flags(fout, po, &pfomask, buf1);
6785 last_arith_dst = &po->operand[0];
6786 delayed_flag_op = NULL;
6790 assert_operand_cnt(2);
6791 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6792 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6793 // special case for XOR
6794 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
6795 for (j = 0; j <= PFO_LE; j++) {
6796 if (pfomask & (1 << j)) {
6797 fprintf(fout, " cond_%s = %d;\n",
6798 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
6799 pfomask &= ~(1 << j);
6802 fprintf(fout, " %s = 0;",
6803 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6804 last_arith_dst = &po->operand[0];
6805 delayed_flag_op = NULL;
6811 assert_operand_cnt(2);
6812 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6813 if (pfomask & (1 << PFO_C)) {
6814 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6815 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6816 if (po->operand[0].lmod == OPLM_DWORD) {
6817 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6818 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6819 fprintf(fout, " %s = (u32)tmp64;",
6820 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6821 strcat(g_comment, " add64");
6824 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6825 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6826 fprintf(fout, " %s += %s;",
6827 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6830 pfomask &= ~(1 << PFO_C);
6831 output_std_flags(fout, po, &pfomask, buf1);
6832 last_arith_dst = &po->operand[0];
6833 delayed_flag_op = NULL;
6836 if (pfomask & (1 << PFO_LE)) {
6837 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
6838 fprintf(fout, " cond_%s = %s;\n",
6839 parsed_flag_op_names[PFO_LE], buf1);
6840 pfomask &= ~(1 << PFO_LE);
6845 assert_operand_cnt(2);
6846 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6847 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6848 for (j = 0; j <= PFO_LE; j++) {
6849 if (!(pfomask & (1 << j)))
6851 if (j == PFO_Z || j == PFO_S)
6854 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6855 fprintf(fout, " cond_%s = %s;\n",
6856 parsed_flag_op_names[j], buf1);
6857 pfomask &= ~(1 << j);
6864 assert_operand_cnt(2);
6865 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6866 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6867 if (po->op == OP_SBB
6868 && IS(po->operand[0].name, po->operand[1].name))
6870 // avoid use of unitialized var
6871 fprintf(fout, " %s = -cond_c;", buf1);
6872 // carry remains what it was
6873 pfomask &= ~(1 << PFO_C);
6876 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6877 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6879 output_std_flags(fout, po, &pfomask, buf1);
6880 last_arith_dst = &po->operand[0];
6881 delayed_flag_op = NULL;
6886 // on SKL, if src is 0, dst is left unchanged
6887 assert_operand_cnt(2);
6888 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6889 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6890 output_std_flag_z(fout, po, &pfomask, buf2);
6891 if (po->op == OP_BSF)
6892 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
6894 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
6895 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
6896 last_arith_dst = &po->operand[0];
6897 delayed_flag_op = NULL;
6898 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
6902 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6903 for (j = 0; j <= PFO_LE; j++) {
6904 if (!(pfomask & (1 << j)))
6906 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6909 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6910 fprintf(fout, " cond_%s = %s;\n",
6911 parsed_flag_op_names[j], buf1);
6912 pfomask &= ~(1 << j);
6918 if (pfomask & (1 << PFO_C))
6919 // carry is unaffected by inc/dec.. wtf?
6920 ferr(po, "carry propagation needed\n");
6922 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6923 if (po->operand[0].type == OPT_REG) {
6924 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6925 fprintf(fout, " %s%s;", buf1, buf2);
6928 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6929 fprintf(fout, " %s %s= 1;", buf1, buf2);
6931 output_std_flags(fout, po, &pfomask, buf1);
6932 last_arith_dst = &po->operand[0];
6933 delayed_flag_op = NULL;
6937 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6938 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6939 fprintf(fout, " %s = -%s%s;", buf1,
6940 lmod_cast_s(po, po->operand[0].lmod), buf2);
6941 last_arith_dst = &po->operand[0];
6942 delayed_flag_op = NULL;
6943 if (pfomask & PFOB_C) {
6944 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6947 output_std_flags(fout, po, &pfomask, buf1);
6951 if (po->operand_cnt == 2) {
6952 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6955 if (po->operand_cnt == 3)
6956 ferr(po, "TODO imul3\n");
6959 assert_operand_cnt(1);
6960 switch (po->operand[0].lmod) {
6962 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6963 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6964 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6965 fprintf(fout, " edx = tmp64 >> 32;\n");
6966 fprintf(fout, " eax = tmp64;");
6969 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6970 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6971 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6975 ferr(po, "TODO: unhandled mul type\n");
6978 last_arith_dst = NULL;
6979 delayed_flag_op = NULL;
6984 assert_operand_cnt(1);
6985 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6986 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6987 po->op == OP_IDIV));
6988 switch (po->operand[0].lmod) {
6990 if (po->flags & OPF_32BIT)
6991 snprintf(buf2, sizeof(buf2), "%seax", cast);
6993 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6994 snprintf(buf2, sizeof(buf2), "%stmp64",
6995 (po->op == OP_IDIV) ? "(s64)" : "");
6997 if (po->operand[0].type == OPT_REG
6998 && po->operand[0].reg == xDX)
7000 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
7001 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
7004 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
7005 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
7009 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
7010 snprintf(buf2, sizeof(buf2), "%stmp",
7011 (po->op == OP_IDIV) ? "(s32)" : "");
7012 if (po->operand[0].type == OPT_REG
7013 && po->operand[0].reg == xDX)
7015 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
7017 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
7021 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
7023 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
7026 strcat(g_comment, " div16");
7029 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7031 last_arith_dst = NULL;
7032 delayed_flag_op = NULL;
7037 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7039 for (j = 0; j < 8; j++) {
7040 if (pfomask & (1 << j)) {
7041 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7042 fprintf(fout, " cond_%s = %s;",
7043 parsed_flag_op_names[j], buf1);
7050 last_arith_dst = NULL;
7051 delayed_flag_op = po;
7055 // SETcc - should already be handled
7058 // note: we reuse OP_Jcc for SETcc, only flags differ
7060 fprintf(fout, "\n goto %s;", po->operand[0].name);
7064 fprintf(fout, " if (ecx == 0)\n");
7065 fprintf(fout, " goto %s;", po->operand[0].name);
7066 strcat(g_comment, " jecxz");
7070 fprintf(fout, " if (--ecx != 0)\n");
7071 fprintf(fout, " goto %s;", po->operand[0].name);
7072 strcat(g_comment, " loop");
7076 assert_operand_cnt(1);
7077 last_arith_dst = NULL;
7078 delayed_flag_op = NULL;
7080 if (po->operand[0].type == OPT_REGMEM) {
7081 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7084 ferr(po, "parse failure for jmp '%s'\n",
7085 po->operand[0].name);
7086 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
7089 else if (po->operand[0].type != OPT_LABEL)
7090 ferr(po, "unhandled jmp type\n");
7092 fprintf(fout, " goto %s;", po->operand[0].name);
7096 assert_operand_cnt(1);
7098 my_assert_not(pp, NULL);
7101 if (po->flags & OPF_CC) {
7102 // we treat conditional branch to another func
7103 // (yes such code exists..) as conditional tailcall
7105 fprintf(fout, " {\n");
7108 if (pp->is_fptr && !pp->is_arg) {
7109 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7110 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7112 if (pp->is_unresolved)
7113 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7114 buf3, asmfn, po->asmln, pp->name);
7117 fprintf(fout, "%s", buf3);
7118 if (strstr(pp->ret_type.name, "int64")) {
7119 if (po->flags & OPF_TAIL)
7120 ferr(po, "int64 and tail?\n");
7121 fprintf(fout, "tmp64 = ");
7123 else if (!IS(pp->ret_type.name, "void")) {
7124 if (po->flags & OPF_TAIL) {
7125 if (regmask_ret & mxAX) {
7126 fprintf(fout, "return ");
7127 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7128 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7130 else if (regmask_ret & mxST0)
7131 ferr(po, "float tailcall\n");
7133 else if (po->regmask_dst & mxAX) {
7134 fprintf(fout, "eax = ");
7135 if (pp->ret_type.is_ptr)
7136 fprintf(fout, "(u32)");
7138 else if (po->regmask_dst & mxST0) {
7139 ferr_assert(po, po->flags & OPF_FPUSH);
7140 if (need_float_stack)
7141 fprintf(fout, "f_st[--f_stp & 7] = ");
7143 fprintf(fout, "f_st0 = ");
7147 if (pp->name[0] == 0)
7148 ferr(po, "missing pp->name\n");
7149 fprintf(fout, "%s%s(", pp->name,
7150 pp->has_structarg ? "_sa" : "");
7152 if (po->flags & OPF_ATAIL) {
7154 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7155 check_compat |= pp->argc_stack > 0;
7157 && (pp->argc_stack != g_func_pp->argc_stack
7158 || pp->is_stdcall != g_func_pp->is_stdcall))
7159 ferr(po, "incompatible arg-reuse tailcall\n");
7160 if (g_func_pp->has_retreg)
7161 ferr(po, "TODO: retreg+tailcall\n");
7163 for (arg = j = 0; arg < pp->argc; arg++) {
7165 fprintf(fout, ", ");
7168 if (pp->arg[arg].type.is_ptr)
7169 snprintf(cast, sizeof(cast), "(%s)",
7170 pp->arg[arg].type.name);
7172 if (pp->arg[arg].reg != NULL) {
7173 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7177 for (; j < g_func_pp->argc; j++)
7178 if (g_func_pp->arg[j].reg == NULL)
7180 fprintf(fout, "%sa%d", cast, j + 1);
7185 for (arg = 0; arg < pp->argc; arg++) {
7187 fprintf(fout, ", ");
7190 if (pp->arg[arg].type.is_ptr)
7191 snprintf(cast, sizeof(cast), "(%s)",
7192 pp->arg[arg].type.name);
7194 if (pp->arg[arg].reg != NULL) {
7195 if (pp->arg[arg].type.is_retreg)
7196 fprintf(fout, "&%s", pp->arg[arg].reg);
7197 else if (IS(pp->arg[arg].reg, "ebp")
7198 && g_bp_frame && !(po->flags & OPF_EBP_S))
7200 // rare special case
7201 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7202 strcat(g_comment, " bp_ref");
7205 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7210 tmp_op = pp->arg[arg].datap;
7212 ferr(po, "parsed_op missing for arg%d\n", arg);
7214 if (tmp_op->flags & OPF_VAPUSH) {
7215 fprintf(fout, "ap");
7217 else if (tmp_op->op == OP_FST) {
7218 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7219 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7222 else if (tmp_op->p_argpass != 0) {
7223 fprintf(fout, "a%d", tmp_op->p_argpass);
7225 else if (pp->arg[arg].is_saved) {
7226 ferr_assert(po, tmp_op->p_argnum > 0);
7227 fprintf(fout, "%s%s", cast,
7228 saved_arg_name(buf1, sizeof(buf1),
7229 tmp_op->p_arggrp, tmp_op->p_argnum));
7233 out_src_opr(buf1, sizeof(buf1),
7234 tmp_op, &tmp_op->operand[0], cast, 0));
7238 fprintf(fout, ");");
7240 if (strstr(pp->ret_type.name, "int64")) {
7241 fprintf(fout, "\n");
7242 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7243 fprintf(fout, "%seax = tmp64;", buf3);
7246 if (pp->is_unresolved) {
7247 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7249 strcat(g_comment, buf2);
7252 if (po->flags & OPF_TAIL) {
7254 if (i == opcnt - 1 || pp->is_noreturn)
7256 else if (IS(pp->ret_type.name, "void"))
7258 else if (!(regmask_ret & (1 << xAX)))
7260 // else already handled as 'return f()'
7263 fprintf(fout, "\n%sreturn;", buf3);
7264 strcat(g_comment, " ^ tailcall");
7267 strcat(g_comment, " tailcall");
7269 if ((regmask_ret & (1 << xAX))
7270 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7272 ferr(po, "int func -> void func tailcall?\n");
7275 if (pp->is_noreturn)
7276 strcat(g_comment, " noreturn");
7277 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7278 strcat(g_comment, " argframe");
7279 if (po->flags & OPF_CC)
7280 strcat(g_comment, " cond");
7282 if (po->flags & OPF_CC)
7283 fprintf(fout, "\n }");
7285 delayed_flag_op = NULL;
7286 last_arith_dst = NULL;
7290 if (g_func_pp->is_vararg)
7291 fprintf(fout, " va_end(ap);\n");
7292 if (g_func_pp->has_retreg) {
7293 for (arg = 0; arg < g_func_pp->argc; arg++)
7294 if (g_func_pp->arg[arg].type.is_retreg)
7295 fprintf(fout, " *r_%s = %s;\n",
7296 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7299 if (regmask_ret & mxST0) {
7300 fprintf(fout, " return %s;", float_st0);
7302 else if (!(regmask_ret & mxAX)) {
7303 if (i != opcnt - 1 || label_pending)
7304 fprintf(fout, " return;");
7306 else if (g_func_pp->ret_type.is_ptr) {
7307 fprintf(fout, " return (%s)eax;",
7308 g_func_pp->ret_type.name);
7310 else if (IS(g_func_pp->ret_type.name, "__int64"))
7311 fprintf(fout, " return ((u64)edx << 32) | eax;");
7313 fprintf(fout, " return eax;");
7315 last_arith_dst = NULL;
7316 delayed_flag_op = NULL;
7320 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7321 if (po->p_argnum != 0) {
7322 // special case - saved func arg
7323 fprintf(fout, " %s = %s;",
7324 saved_arg_name(buf2, sizeof(buf2),
7325 po->p_arggrp, po->p_argnum), buf1);
7328 else if (po->flags & OPF_RSAVE) {
7329 fprintf(fout, " s_%s = %s;", buf1, buf1);
7332 else if (po->flags & OPF_PPUSH) {
7334 ferr_assert(po, tmp_op != NULL);
7335 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7336 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7339 else if (g_func_pp->is_userstack) {
7340 fprintf(fout, " *(--esp) = %s;", buf1);
7343 if (!(g_ida_func_attr & IDAFA_NORETURN))
7344 ferr(po, "stray push encountered\n");
7349 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7350 if (po->flags & OPF_RSAVE) {
7351 fprintf(fout, " %s = s_%s;", buf1, buf1);
7354 else if (po->flags & OPF_PPUSH) {
7355 // push/pop graph / non-const
7356 ferr_assert(po, po->datap == NULL);
7357 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7360 else if (po->datap != NULL) {
7363 fprintf(fout, " %s = %s;", buf1,
7364 out_src_opr(buf2, sizeof(buf2),
7365 tmp_op, &tmp_op->operand[0],
7366 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7369 else if (g_func_pp->is_userstack) {
7370 fprintf(fout, " %s = *esp++;", buf1);
7374 ferr(po, "stray pop encountered\n");
7384 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7385 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7386 po->op == OPP_ALLSHL ? "<<" : ">>");
7387 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7388 strcat(g_comment, po->op == OPP_ALLSHL
7389 ? " allshl" : " allshr");
7394 if (need_float_stack) {
7395 out_src_opr_float(buf1, sizeof(buf1),
7396 po, &po->operand[0], 1);
7397 if (po->regmask_src & mxSTa) {
7398 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7402 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7405 if (po->flags & OPF_FSHIFT)
7406 fprintf(fout, " f_st1 = f_st0;");
7407 if (po->operand[0].type == OPT_REG
7408 && po->operand[0].reg == xST0)
7410 strcat(g_comment, " fld st");
7413 fprintf(fout, " f_st0 = %s;",
7414 out_src_opr_float(buf1, sizeof(buf1),
7415 po, &po->operand[0], 0));
7417 strcat(g_comment, " fld");
7421 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7422 lmod_cast(po, po->operand[0].lmod, 1), 0);
7423 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7424 if (need_float_stack) {
7425 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7428 if (po->flags & OPF_FSHIFT)
7429 fprintf(fout, " f_st1 = f_st0;");
7430 fprintf(fout, " f_st0 = %s;", buf2);
7432 strcat(g_comment, " fild");
7436 if (need_float_stack)
7437 fprintf(fout, " f_st[--f_stp & 7] = ");
7439 if (po->flags & OPF_FSHIFT)
7440 fprintf(fout, " f_st1 = f_st0;");
7441 fprintf(fout, " f_st0 = ");
7443 switch (po->operand[0].val) {
7444 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7445 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
7446 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7447 default: ferr(po, "TODO\n"); break;
7452 if (po->flags & OPF_FARG) {
7453 // store to stack as func arg
7454 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7458 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7460 dead_dst = po->operand[0].type == OPT_REG
7461 && po->operand[0].reg == xST0;
7464 fprintf(fout, " %s = %s;", buf1, float_st0);
7465 if (po->flags & OPF_FSHIFT) {
7466 if (need_float_stack)
7467 fprintf(fout, " f_stp++;");
7469 fprintf(fout, " f_st0 = f_st1;");
7471 if (dead_dst && !(po->flags & OPF_FSHIFT))
7474 strcat(g_comment, " fst");
7478 fprintf(fout, " %s = %s%s;",
7479 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7480 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7481 if (po->flags & OPF_FSHIFT) {
7482 if (need_float_stack)
7483 fprintf(fout, " f_stp++;");
7485 fprintf(fout, " f_st0 = f_st1;");
7487 strcat(g_comment, " fist");
7494 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7496 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7498 dead_dst = (po->flags & OPF_FPOP)
7499 && po->operand[0].type == OPT_REG
7500 && po->operand[0].reg == xST0;
7502 case OP_FADD: j = '+'; break;
7503 case OP_FDIV: j = '/'; break;
7504 case OP_FMUL: j = '*'; break;
7505 case OP_FSUB: j = '-'; break;
7506 default: j = 'x'; break;
7508 if (need_float_stack) {
7510 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7511 if (po->flags & OPF_FSHIFT)
7512 fprintf(fout, " f_stp++;");
7515 if (po->flags & OPF_FSHIFT) {
7516 // note: assumes only 2 regs handled
7518 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7520 fprintf(fout, " f_st0 = f_st1;");
7523 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7525 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7530 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7532 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7534 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7536 dead_dst = (po->flags & OPF_FPOP)
7537 && po->operand[0].type == OPT_REG
7538 && po->operand[0].reg == xST0;
7539 j = po->op == OP_FDIVR ? '/' : '-';
7540 if (need_float_stack) {
7542 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7543 if (po->flags & OPF_FSHIFT)
7544 fprintf(fout, " f_stp++;");
7547 if (po->flags & OPF_FSHIFT) {
7549 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7551 fprintf(fout, " f_st0 = f_st1;");
7554 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7556 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7564 case OP_FIADD: j = '+'; break;
7565 case OP_FIDIV: j = '/'; break;
7566 case OP_FIMUL: j = '*'; break;
7567 case OP_FISUB: j = '-'; break;
7568 default: j = 'x'; break;
7570 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7572 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7573 lmod_cast(po, po->operand[0].lmod, 1), 0));
7578 fprintf(fout, " %s = %s %c %s;", float_st0,
7579 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7581 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7586 ferr_assert(po, po->datap != NULL);
7587 mask = (long)po->datap & 0xffff;
7588 z_check = ((long)po->datap >> 16) & 1;
7589 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7591 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
7592 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7595 else if (mask == 0x4000) { // C3 -> =
7596 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7599 else if (mask == 0x4100) { // C3, C0
7601 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7603 strcat(g_comment, " z_chk_det");
7606 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7607 "(%s < %s ? 0x0100 : 0);",
7608 float_st0, buf1, float_st0, buf1);
7612 ferr(po, "unhandled sw mask: %x\n", mask);
7613 if (po->flags & OPF_FSHIFT) {
7614 if (need_float_stack)
7615 fprintf(fout, " f_stp++;");
7617 fprintf(fout, " f_st0 = f_st1;");
7623 fprintf(fout, " %s = f_sw;",
7624 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7628 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7632 fprintf(fout, " %s = cos%s(%s);", float_st0,
7633 need_double ? "" : "f", float_st0);
7637 if (need_float_stack) {
7638 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7639 need_double ? "" : "f", float_st1, float_st0);
7640 fprintf(fout, " f_stp++;");
7643 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7644 need_double ? "" : "f");
7649 if (need_float_stack) {
7650 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7651 float_st1, need_double ? "" : "f", float_st0);
7652 fprintf(fout, " f_stp++;");
7655 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7656 need_double ? "" : "f");
7658 strcat(g_comment, " fyl2x");
7662 fprintf(fout, " %s = sin%s(%s);", float_st0,
7663 need_double ? "" : "f", float_st0);
7667 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7668 need_double ? "" : "f", float_st0);
7672 dead_dst = po->operand[0].type == OPT_REG
7673 && po->operand[0].reg == xST0;
7675 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7677 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7678 float_st0, float_st0, buf1, buf1);
7679 strcat(g_comment, " fxch");
7686 ferr_assert(po, po->flags & OPF_32BIT);
7687 fprintf(fout, " eax = (s32)%s;", float_st0);
7688 if (po->flags & OPF_FSHIFT) {
7689 if (need_float_stack)
7690 fprintf(fout, " f_stp++;");
7692 fprintf(fout, " f_st0 = f_st1;");
7694 strcat(g_comment, " ftol");
7698 if (need_float_stack) {
7699 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
7700 need_double ? "" : "f", float_st1, float_st0);
7701 fprintf(fout, " f_stp++;");
7704 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
7705 need_double ? "" : "f");
7707 strcat(g_comment, " CIpow");
7711 fprintf(fout, " do_skip_code_abort();");
7716 fprintf(fout, " do_emms();");
7721 ferr(po, "unhandled op type %d, flags %x\n",
7726 if (g_comment[0] != 0) {
7727 char *p = g_comment;
7728 while (my_isblank(*p))
7730 fprintf(fout, " // %s", p);
7735 fprintf(fout, "\n");
7737 // some sanity checking
7738 if (po->flags & OPF_REP) {
7739 if (po->op != OP_STOS && po->op != OP_MOVS
7740 && po->op != OP_CMPS && po->op != OP_SCAS)
7741 ferr(po, "unexpected rep\n");
7742 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7743 && (po->op == OP_CMPS || po->op == OP_SCAS))
7744 ferr(po, "cmps/scas with plain rep\n");
7746 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7747 && po->op != OP_CMPS && po->op != OP_SCAS)
7748 ferr(po, "unexpected repz/repnz\n");
7751 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
7753 // see is delayed flag stuff is still valid
7754 if (delayed_flag_op != NULL && delayed_flag_op != po) {
7755 if (is_any_opr_modified(delayed_flag_op, po, 0))
7756 delayed_flag_op = NULL;
7759 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7760 if (is_opr_modified(last_arith_dst, po))
7761 last_arith_dst = NULL;
7768 if (g_stack_fsz && !g_stack_frame_used)
7769 fprintf(fout, " (void)sf;\n");
7771 fprintf(fout, "}\n\n");
7773 gen_x_cleanup(opcnt);
7776 static void gen_x_cleanup(int opcnt)
7780 for (i = 0; i < opcnt; i++) {
7781 struct label_ref *lr, *lr_del;
7783 lr = g_label_refs[i].next;
7784 while (lr != NULL) {
7789 g_label_refs[i].i = -1;
7790 g_label_refs[i].next = NULL;
7792 if (ops[i].op == OP_CALL) {
7794 proto_release(ops[i].pp);
7800 struct func_proto_dep;
7802 struct func_prototype {
7807 int has_ret:3; // -1, 0, 1: unresolved, no, yes
7808 unsigned int dep_resolved:1;
7809 unsigned int is_stdcall:1;
7810 struct func_proto_dep *dep_func;
7812 const struct parsed_proto *pp; // seed pp, if any
7815 struct func_proto_dep {
7817 struct func_prototype *proto;
7818 int regmask_live; // .. at the time of call
7819 unsigned int ret_dep:1; // return from this is caller's return
7822 static struct func_prototype *hg_fp;
7823 static int hg_fp_cnt;
7825 static struct scanned_var {
7827 enum opr_lenmod lmod;
7828 unsigned int is_seeded:1;
7829 unsigned int is_c_str:1;
7830 const struct parsed_proto *pp; // seed pp, if any
7832 static int hg_var_cnt;
7834 static char **hg_refs;
7835 static int hg_ref_cnt;
7837 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7840 static struct func_prototype *hg_fp_add(const char *funcn)
7842 struct func_prototype *fp;
7844 if ((hg_fp_cnt & 0xff) == 0) {
7845 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7846 my_assert_not(hg_fp, NULL);
7847 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7850 fp = &hg_fp[hg_fp_cnt];
7851 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7853 fp->argc_stack = -1;
7859 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7864 for (i = 0; i < fp->dep_func_cnt; i++)
7865 if (IS(fp->dep_func[i].name, name))
7866 return &fp->dep_func[i];
7871 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7874 if (hg_fp_find_dep(fp, name))
7877 if ((fp->dep_func_cnt & 0xff) == 0) {
7878 fp->dep_func = realloc(fp->dep_func,
7879 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7880 my_assert_not(fp->dep_func, NULL);
7881 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7882 sizeof(fp->dep_func[0]) * 0x100);
7884 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7888 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7890 const struct func_prototype *p1 = p1_, *p2 = p2_;
7891 return strcmp(p1->name, p2->name);
7895 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7897 const struct func_prototype *p1 = p1_, *p2 = p2_;
7898 return p1->id - p2->id;
7902 static void hg_ref_add(const char *name)
7904 if ((hg_ref_cnt & 0xff) == 0) {
7905 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7906 my_assert_not(hg_refs, NULL);
7907 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7910 hg_refs[hg_ref_cnt] = strdup(name);
7911 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7915 // recursive register dep pass
7916 // - track saved regs (part 2)
7917 // - try to figure out arg-regs
7918 // - calculate reg deps
7919 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
7920 struct func_prototype *fp, int regmask_save, int regmask_dst,
7921 int *regmask_dep, int *has_ret)
7923 struct func_proto_dep *dep;
7924 struct parsed_op *po;
7925 int from_caller = 0;
7930 for (; i < opcnt; i++)
7932 if (cbits[i >> 3] & (1 << (i & 7)))
7934 cbits[i >> 3] |= (1 << (i & 7));
7938 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
7939 if (po->flags & OPF_RMD)
7942 if (po->btj != NULL) {
7944 for (j = 0; j < po->btj->count; j++) {
7945 check_i(po, po->btj->d[j].bt_i);
7946 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
7947 regmask_save, regmask_dst, regmask_dep, has_ret);
7952 check_i(po, po->bt_i);
7953 if (po->flags & OPF_CJMP) {
7954 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
7955 regmask_save, regmask_dst, regmask_dep, has_ret);
7963 if (po->flags & OPF_FARG)
7964 /* (just calculate register deps) */;
7965 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
7967 reg = po->operand[0].reg;
7968 ferr_assert(po, reg >= 0);
7970 if (po->flags & OPF_RSAVE) {
7971 regmask_save |= 1 << reg;
7974 if (po->flags & OPF_DONE)
7977 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
7979 regmask_save |= 1 << reg;
7980 po->flags |= OPF_RMD;
7981 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
7985 else if (po->flags & OPF_RMD)
7987 else if (po->op == OP_CALL) {
7988 po->regmask_dst |= 1 << xAX;
7990 dep = hg_fp_find_dep(fp, po->operand[0].name);
7992 dep->regmask_live = regmask_save | regmask_dst;
7993 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7994 dep->regmask_live |= 1 << xBP;
7997 else if (po->op == OP_RET) {
7998 if (po->operand_cnt > 0) {
8000 if (fp->argc_stack >= 0
8001 && fp->argc_stack != po->operand[0].val / 4)
8002 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8003 fp->argc_stack = po->operand[0].val / 4;
8007 // if has_ret is 0, there is uninitialized eax path,
8008 // which means it's most likely void func
8009 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
8010 if (po->op == OP_CALL) {
8015 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
8018 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
8021 if (ret != 1 && from_caller) {
8022 // unresolved eax - probably void func
8026 if (j >= 0 && ops[j].op == OP_CALL) {
8027 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8038 l = regmask_save | regmask_dst;
8039 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8042 l = po->regmask_src & ~l;
8045 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8046 l, regmask_dst, regmask_save, po->flags);
8049 regmask_dst |= po->regmask_dst;
8051 if (po->flags & OPF_TAIL)
8056 static void gen_hdr(const char *funcn, int opcnt)
8058 unsigned char cbits[MAX_OPS / 8];
8059 const struct parsed_proto *pp_c;
8060 struct parsed_proto *pp;
8061 struct func_prototype *fp;
8062 struct parsed_op *po;
8063 int regmask_dummy = 0;
8065 int max_bp_offset = 0;
8070 pp_c = proto_parse(g_fhdr, funcn, 1);
8072 // already in seed, will add to hg_fp later
8075 fp = hg_fp_add(funcn);
8077 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8078 g_stack_frame_used = 0;
8082 // - resolve all branches
8083 // - parse calls with labels
8084 resolve_branches_parse_calls(opcnt);
8087 // - handle ebp/esp frame, remove ops related to it
8088 scan_prologue_epilogue(opcnt, NULL);
8091 // - remove dead labels
8093 for (i = 0; i < opcnt; i++)
8095 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8101 if (po->flags & (OPF_RMD|OPF_DONE))
8104 if (po->op == OP_CALL) {
8105 if (po->operand[0].type == OPT_LABEL)
8106 hg_fp_add_dep(fp, opr_name(po, 0));
8107 else if (po->pp != NULL)
8108 hg_fp_add_dep(fp, po->pp->name);
8113 // - remove dead labels
8114 // - handle push <const>/pop pairs
8115 for (i = 0; i < opcnt; i++)
8117 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8123 if (po->flags & (OPF_RMD|OPF_DONE))
8126 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8127 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8131 // - process trivial calls
8132 for (i = 0; i < opcnt; i++)
8135 if (po->flags & (OPF_RMD|OPF_DONE))
8138 if (po->op == OP_CALL)
8140 pp = process_call_early(i, opcnt, &j);
8142 if (!(po->flags & OPF_ATAIL))
8143 // since we know the args, try to collect them
8144 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8150 // commit esp adjust
8151 if (ops[j].op != OP_POP)
8152 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8154 for (l = 0; l < pp->argc_stack; l++)
8155 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8159 po->flags |= OPF_DONE;
8165 // - track saved regs (simple)
8167 for (i = 0; i < opcnt; i++)
8170 if (po->flags & (OPF_RMD|OPF_DONE))
8173 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8174 && po->operand[0].reg != xCX)
8176 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8178 // regmask_save |= 1 << po->operand[0].reg; // do it later
8179 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8180 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8183 else if (po->op == OP_CALL)
8185 pp = process_call(i, opcnt);
8187 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8188 // since we know the args, collect them
8189 ret = collect_call_args(po, i, pp, ®mask_dummy,
8196 memset(cbits, 0, sizeof(cbits));
8200 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
8202 // find unreachable code - must be fixed in IDA
8203 for (i = 0; i < opcnt; i++)
8205 if (cbits[i >> 3] & (1 << (i & 7)))
8208 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8209 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8211 // the compiler sometimes still generates code after
8212 // noreturn OS functions
8215 if (ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8216 ferr(&ops[i], "unreachable code\n");
8219 for (i = 0; i < g_eqcnt; i++) {
8220 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8221 max_bp_offset = g_eqs[i].offset;
8224 if (fp->argc_stack < 0) {
8225 max_bp_offset = (max_bp_offset + 3) & ~3;
8226 fp->argc_stack = max_bp_offset / 4;
8227 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8231 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8232 fp->has_ret = has_ret;
8234 printf("// has_ret %d, regmask_dep %x\n",
8235 fp->has_ret, fp->regmask_dep);
8236 output_hdr_fp(stdout, fp, 1);
8237 if (IS(funcn, "sub_10007F72")) exit(1);
8240 gen_x_cleanup(opcnt);
8243 static void hg_fp_resolve_deps(struct func_prototype *fp)
8245 struct func_prototype fp_s;
8249 // this thing is recursive, so mark first..
8250 fp->dep_resolved = 1;
8252 for (i = 0; i < fp->dep_func_cnt; i++) {
8253 strcpy(fp_s.name, fp->dep_func[i].name);
8254 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8255 sizeof(hg_fp[0]), hg_fp_cmp_name);
8256 if (fp->dep_func[i].proto != NULL) {
8257 if (!fp->dep_func[i].proto->dep_resolved)
8258 hg_fp_resolve_deps(fp->dep_func[i].proto);
8260 dep = ~fp->dep_func[i].regmask_live
8261 & fp->dep_func[i].proto->regmask_dep;
8262 fp->regmask_dep |= dep;
8263 // printf("dep %s %s |= %x\n", fp->name,
8264 // fp->dep_func[i].name, dep);
8266 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8267 fp->has_ret = fp->dep_func[i].proto->has_ret;
8272 // make all thiscall/edx arg functions referenced from .data fastcall
8273 static void do_func_refs_from_data(void)
8275 struct func_prototype *fp, fp_s;
8278 for (i = 0; i < hg_ref_cnt; i++) {
8279 strcpy(fp_s.name, hg_refs[i]);
8280 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8281 sizeof(hg_fp[0]), hg_fp_cmp_name);
8285 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8286 fp->regmask_dep |= mxCX | mxDX;
8290 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8293 const struct parsed_proto *pp;
8294 char *p, namebuf[NAMELEN];
8300 for (; count > 0; count--, fp++) {
8301 if (fp->has_ret == -1)
8302 fprintf(fout, "// ret unresolved\n");
8304 fprintf(fout, "// dep:");
8305 for (j = 0; j < fp->dep_func_cnt; j++) {
8306 fprintf(fout, " %s/", fp->dep_func[j].name);
8307 if (fp->dep_func[j].proto != NULL)
8308 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8309 fp->dep_func[j].proto->has_ret);
8311 fprintf(fout, "\n");
8314 p = strchr(fp->name, '@');
8316 memcpy(namebuf, fp->name, p - fp->name);
8317 namebuf[p - fp->name] = 0;
8325 pp = proto_parse(g_fhdr, name, 1);
8326 if (pp != NULL && pp->is_include)
8329 if (fp->pp != NULL) {
8330 // part of seed, output later
8334 regmask_dep = fp->regmask_dep;
8335 argc_normal = fp->argc_stack;
8337 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8338 (fp->has_ret ? "int" : "void"));
8339 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8340 && (regmask_dep & ~mxCX) == 0)
8342 fprintf(fout, "/*__thiscall*/ ");
8346 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8347 && (regmask_dep & ~(mxCX | mxDX)) == 0)
8349 fprintf(fout, " __fastcall ");
8350 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8356 else if (regmask_dep && !fp->is_stdcall) {
8357 fprintf(fout, "/*__usercall*/ ");
8359 else if (regmask_dep) {
8360 fprintf(fout, "/*__userpurge*/ ");
8362 else if (fp->is_stdcall)
8363 fprintf(fout, " __stdcall ");
8365 fprintf(fout, " __cdecl ");
8367 fprintf(fout, "%s(", name);
8370 for (j = 0; j < xSP; j++) {
8371 if (regmask_dep & (1 << j)) {
8374 fprintf(fout, ", ");
8376 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8378 fprintf(fout, "int");
8379 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8383 for (j = 0; j < argc_normal; j++) {
8386 fprintf(fout, ", ");
8387 if (fp->pp != NULL) {
8388 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8389 if (!fp->pp->arg[arg - 1].type.is_ptr)
8393 fprintf(fout, "int ");
8394 fprintf(fout, "a%d", arg);
8397 fprintf(fout, ");\n");
8401 static void output_hdr(FILE *fout)
8403 static const char *lmod_c_names[] = {
8404 [OPLM_UNSPEC] = "???",
8405 [OPLM_BYTE] = "uint8_t",
8406 [OPLM_WORD] = "uint16_t",
8407 [OPLM_DWORD] = "uint32_t",
8408 [OPLM_QWORD] = "uint64_t",
8410 const struct scanned_var *var;
8411 struct func_prototype *fp;
8412 char line[256] = { 0, };
8416 // add stuff from headers
8417 for (i = 0; i < pp_cache_size; i++) {
8418 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8419 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8421 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8422 fp = hg_fp_add(name);
8423 fp->pp = &pp_cache[i];
8424 fp->argc_stack = fp->pp->argc_stack;
8425 fp->is_stdcall = fp->pp->is_stdcall;
8426 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8427 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8431 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8432 for (i = 0; i < hg_fp_cnt; i++)
8433 hg_fp_resolve_deps(&hg_fp[i]);
8435 // adjust functions referenced from data segment
8436 do_func_refs_from_data();
8438 // note: messes up .proto ptr, don't use
8439 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8442 for (i = 0; i < hg_var_cnt; i++) {
8445 if (var->pp != NULL)
8448 else if (var->is_c_str)
8449 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8451 fprintf(fout, "extern %-8s %s;",
8452 lmod_c_names[var->lmod], var->name);
8455 fprintf(fout, " // seeded");
8456 fprintf(fout, "\n");
8459 fprintf(fout, "\n");
8461 // output function prototypes
8462 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8465 fprintf(fout, "\n// - seed -\n");
8468 while (fgets(line, sizeof(line), g_fhdr))
8469 fwrite(line, 1, strlen(line), fout);
8472 // '=' needs special treatment
8474 static char *next_word_s(char *w, size_t wsize, char *s)
8481 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8483 for (i = 1; i < wsize - 1; i++) {
8485 printf("warning: missing closing quote: \"%s\"\n", s);
8494 for (; i < wsize - 1; i++) {
8495 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8501 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8502 printf("warning: '%s' truncated\n", w);
8507 static int cmpstringp(const void *p1, const void *p2)
8509 return strcmp(*(char * const *)p1, *(char * const *)p2);
8512 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8517 if (strstr(p, "..."))
8518 // unable to determine, assume needed
8521 if (*p == '.') // .text, .data, ...
8522 // ref from other data or non-function -> no
8525 p2 = strpbrk(p, "+:\r\n\x18");
8528 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8529 // referenced from removed code
8535 static int ida_xrefs_show_need(FILE *fasm, char *p,
8536 char **rlist, int rlist_len)
8542 p = strrchr(p, ';');
8543 if (p != NULL && *p == ';') {
8544 if (IS_START(p + 2, "sctref"))
8546 if (IS_START(p + 2, "DATA XREF: ")) {
8548 if (is_xref_needed(p, rlist, rlist_len))
8556 if (!my_fgets(line, sizeof(line), fasm))
8558 // non-first line is always indented
8559 if (!my_isblank(line[0]))
8562 // should be no content, just comment
8567 p = strrchr(p, ';');
8570 if (IS_START(p, "sctref")) {
8575 // it's printed once, but no harm to check again
8576 if (IS_START(p, "DATA XREF: "))
8579 if (is_xref_needed(p, rlist, rlist_len)) {
8584 fseek(fasm, pos, SEEK_SET);
8588 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8590 struct scanned_var *var;
8591 char line[256] = { 0, };
8600 // skip to next data section
8601 while (my_fgets(line, sizeof(line), fasm))
8606 if (*p == 0 || *p == ';')
8609 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8610 if (*p == 0 || *p == ';')
8613 if (*p != 's' || !IS_START(p, "segment para public"))
8619 if (p == NULL || !IS_START(p, "segment para public"))
8623 if (!IS_START(p, "'DATA'"))
8627 while (my_fgets(line, sizeof(line), fasm))
8632 no_identifier = my_isblank(*p);
8635 if (*p == 0 || *p == ';')
8638 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8639 words[wordc][0] = 0;
8640 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8641 if (*p == 0 || *p == ';') {
8647 if (wordc == 2 && IS(words[1], "ends"))
8652 if (no_identifier) {
8653 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8654 hg_ref_add(words[2]);
8658 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8659 // when this starts, we don't need anything from this section
8663 // check refs comment(s)
8664 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8667 if ((hg_var_cnt & 0xff) == 0) {
8668 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8669 * (hg_var_cnt + 0x100));
8670 my_assert_not(hg_vars, NULL);
8671 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8674 var = &hg_vars[hg_var_cnt++];
8675 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8677 // maybe already in seed header?
8678 var->pp = proto_parse(g_fhdr, var->name, 1);
8679 if (var->pp != NULL) {
8680 if (var->pp->is_fptr) {
8681 var->lmod = OPLM_DWORD;
8684 else if (var->pp->is_func)
8686 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8687 aerr("unhandled C type '%s' for '%s'\n",
8688 var->pp->type.name, var->name);
8694 if (IS(words[1], "dd")) {
8695 var->lmod = OPLM_DWORD;
8696 if (wordc >= 4 && IS(words[2], "offset"))
8697 hg_ref_add(words[3]);
8699 else if (IS(words[1], "dw"))
8700 var->lmod = OPLM_WORD;
8701 else if (IS(words[1], "db")) {
8702 var->lmod = OPLM_BYTE;
8703 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8704 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8708 else if (IS(words[1], "dq"))
8709 var->lmod = OPLM_QWORD;
8710 //else if (IS(words[1], "dt"))
8712 aerr("type '%s' not known\n", words[1]);
8720 static void set_label(int i, const char *name)
8726 p = strchr(name, ':');
8730 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8731 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8732 g_labels[i] = realloc(g_labels[i], len + 1);
8733 my_assert_not(g_labels[i], NULL);
8734 memcpy(g_labels[i], name, len);
8735 g_labels[i][len] = 0;
8744 static struct chunk_item *func_chunks;
8745 static int func_chunk_cnt;
8746 static int func_chunk_alloc;
8748 static void add_func_chunk(FILE *fasm, const char *name, int line)
8750 if (func_chunk_cnt >= func_chunk_alloc) {
8751 func_chunk_alloc *= 2;
8752 func_chunks = realloc(func_chunks,
8753 func_chunk_alloc * sizeof(func_chunks[0]));
8754 my_assert_not(func_chunks, NULL);
8756 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8757 func_chunks[func_chunk_cnt].name = strdup(name);
8758 func_chunks[func_chunk_cnt].asmln = line;
8762 static int cmp_chunks(const void *p1, const void *p2)
8764 const struct chunk_item *c1 = p1, *c2 = p2;
8765 return strcmp(c1->name, c2->name);
8768 static void scan_ahead_for_chunks(FILE *fasm)
8778 oldpos = ftell(fasm);
8781 while (my_fgets(line, sizeof(line), fasm))
8792 // get rid of random tabs
8793 for (i = 0; line[i] != 0; i++)
8794 if (line[i] == '\t')
8797 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8800 next_word(words[0], sizeof(words[0]), p);
8801 if (words[0][0] == 0)
8802 aerr("missing name for func chunk?\n");
8804 add_func_chunk(fasm, words[0], asmln);
8806 else if (IS_START(p, "; sctend"))
8812 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8813 words[wordc][0] = 0;
8814 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8815 if (*p == 0 || *p == ';') {
8821 if (wordc == 2 && IS(words[1], "ends"))
8825 fseek(fasm, oldpos, SEEK_SET);
8829 int main(int argc, char *argv[])
8831 FILE *fout, *fasm, *frlist;
8832 struct parsed_data *pd = NULL;
8834 char **rlist = NULL;
8836 int rlist_alloc = 0;
8837 int func_chunks_used = 0;
8838 int func_chunks_sorted = 0;
8839 int func_chunk_i = -1;
8840 long func_chunk_ret = 0;
8841 int func_chunk_ret_ln = 0;
8842 int scanned_ahead = 0;
8844 char words[20][256];
8845 enum opr_lenmod lmod;
8846 char *sctproto = NULL;
8848 int pending_endp = 0;
8850 int skip_code_end = 0;
8851 int skip_warned = 0;
8864 for (arg = 1; arg < argc; arg++) {
8865 if (IS(argv[arg], "-v"))
8867 else if (IS(argv[arg], "-rf"))
8868 g_allow_regfunc = 1;
8869 else if (IS(argv[arg], "-uc"))
8870 g_allow_user_icall = 1;
8871 else if (IS(argv[arg], "-m"))
8873 else if (IS(argv[arg], "-hdr"))
8874 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8879 if (argc < arg + 3) {
8880 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8881 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8883 " -hdr - header generation mode\n"
8884 " -rf - allow unannotated indirect calls\n"
8885 " -uc - allow ind. calls/refs to __usercall\n"
8886 " -m - allow multiple .text sections\n"
8887 "[rlist] is a file with function names to skip,"
8895 asmfn = argv[arg++];
8896 fasm = fopen(asmfn, "r");
8897 my_assert_not(fasm, NULL);
8899 hdrfn = argv[arg++];
8900 g_fhdr = fopen(hdrfn, "r");
8901 my_assert_not(g_fhdr, NULL);
8904 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8905 my_assert_not(rlist, NULL);
8906 // needs special handling..
8907 rlist[rlist_len++] = "__alloca_probe";
8909 func_chunk_alloc = 32;
8910 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8911 my_assert_not(func_chunks, NULL);
8913 memset(words, 0, sizeof(words));
8915 for (; arg < argc; arg++) {
8918 frlist = fopen(argv[arg], "r");
8919 my_assert_not(frlist, NULL);
8921 while (my_fgets(line, sizeof(line), frlist)) {
8923 if (*p == 0 || *p == ';')
8926 if (IS_START(p, "#if 0")
8927 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
8931 else if (IS_START(p, "#endif"))
8938 p = next_word(words[0], sizeof(words[0]), p);
8939 if (words[0][0] == 0)
8942 if (rlist_len >= rlist_alloc) {
8943 rlist_alloc = rlist_alloc * 2 + 64;
8944 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
8945 my_assert_not(rlist, NULL);
8947 rlist[rlist_len++] = strdup(words[0]);
8955 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
8957 fout = fopen(argv[arg_out], "w");
8958 my_assert_not(fout, NULL);
8961 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
8962 my_assert_not(g_eqs, NULL);
8964 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
8965 g_label_refs[i].i = -1;
8966 g_label_refs[i].next = NULL;
8970 scan_variables(fasm, rlist, rlist_len);
8972 while (my_fgets(line, sizeof(line), fasm))
8981 // get rid of random tabs
8982 for (i = 0; line[i] != 0; i++)
8983 if (line[i] == '\t')
8988 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
8989 goto do_pending_endp; // eww..
8991 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
8993 static const char *attrs[] = {
9002 // parse IDA's attribute-list comment
9003 g_ida_func_attr = 0;
9006 for (; *p != 0; p = sskip(p)) {
9007 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9008 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9009 g_ida_func_attr |= 1 << i;
9010 p += strlen(attrs[i]);
9014 if (i == ARRAY_SIZE(attrs)) {
9015 anote("unparsed IDA attr: %s\n", p);
9018 if (IS(attrs[i], "fpd=")) {
9019 p = next_word(words[0], sizeof(words[0]), p);
9024 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9026 static const char *attrs[] = {
9031 // parse manual attribute-list comment
9032 g_sct_func_attr = 0;
9035 for (; *p != 0; p = sskip(p)) {
9036 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9037 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9038 g_sct_func_attr |= 1 << i;
9039 p += strlen(attrs[i]);
9046 // clear_sf=start,len (in dwords)
9047 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9048 &g_stack_clear_len, &j);
9050 // clear_regmask=<mask>
9051 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9053 anote("unparsed attr value: %s\n", p);
9058 else if (i == ARRAY_SIZE(attrs)) {
9059 anote("unparsed sct attr: %s\n", p);
9064 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9067 next_word(words[0], sizeof(words[0]), p);
9068 if (words[0][0] == 0)
9069 aerr("missing name for func chunk?\n");
9071 if (!scanned_ahead) {
9072 add_func_chunk(fasm, words[0], asmln);
9073 func_chunks_sorted = 0;
9076 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9078 if (func_chunk_i >= 0) {
9079 if (func_chunk_i < func_chunk_cnt
9080 && IS(func_chunks[func_chunk_i].name, g_func))
9082 // move on to next chunk
9083 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9085 aerr("seek failed for '%s' chunk #%d\n",
9086 g_func, func_chunk_i);
9087 asmln = func_chunks[func_chunk_i].asmln;
9091 if (func_chunk_ret == 0)
9092 aerr("no return from chunk?\n");
9093 fseek(fasm, func_chunk_ret, SEEK_SET);
9094 asmln = func_chunk_ret_ln;
9100 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9101 func_chunks_used = 1;
9103 if (IS_START(g_func, "sub_")) {
9104 unsigned long addr = strtoul(p, NULL, 16);
9105 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9106 if (addr > f_addr && !scanned_ahead) {
9107 //anote("scan_ahead caused by '%s', addr %lx\n",
9109 scan_ahead_for_chunks(fasm);
9111 func_chunks_sorted = 0;
9119 for (i = wordc; i < ARRAY_SIZE(words); i++)
9121 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9122 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9123 if (*p == 0 || *p == ';') {
9128 if (*p != 0 && *p != ';')
9129 aerr("too many words\n");
9131 if (skip_code_end) {
9136 // allow asm patches in comments
9138 if (IS_START(p, "; sctpatch:")) {
9140 if (*p == 0 || *p == ';')
9142 goto parse_words; // lame
9144 if (IS_START(p, "; sctproto:")) {
9145 sctproto = strdup(p + 11);
9147 else if (IS_START(p, "; sctend")) {
9152 else if (IS_START(p, "; sctskip_start")) {
9153 if (in_func && !g_skip_func) {
9155 ops[pi].op = OPP_ABORT;
9156 ops[pi].asmln = asmln;
9162 else if (IS_START(p, "; sctskip_end")) {
9170 awarn("wordc == 0?\n");
9174 // don't care about this:
9175 if (words[0][0] == '.'
9176 || IS(words[0], "include")
9177 || IS(words[0], "assume") || IS(words[1], "segment")
9178 || IS(words[0], "align"))
9184 // do delayed endp processing to collect switch jumptables
9186 if (in_func && !g_skip_func && !end && wordc >= 2
9187 && ((words[0][0] == 'd' && words[0][2] == 0)
9188 || (words[1][0] == 'd' && words[1][2] == 0)))
9191 if (words[1][0] == 'd' && words[1][2] == 0) {
9193 if (g_func_pd_cnt >= pd_alloc) {
9194 pd_alloc = pd_alloc * 2 + 16;
9195 g_func_pd = realloc(g_func_pd,
9196 sizeof(g_func_pd[0]) * pd_alloc);
9197 my_assert_not(g_func_pd, NULL);
9199 pd = &g_func_pd[g_func_pd_cnt];
9201 memset(pd, 0, sizeof(*pd));
9202 strcpy(pd->label, words[0]);
9203 pd->type = OPT_CONST;
9204 pd->lmod = lmod_from_directive(words[1]);
9210 anote("skipping alignment byte?\n");
9213 lmod = lmod_from_directive(words[0]);
9214 if (lmod != pd->lmod)
9215 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9218 if (pd->count_alloc < pd->count + wordc) {
9219 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9220 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9221 my_assert_not(pd->d, NULL);
9223 for (; i < wordc; i++) {
9224 if (IS(words[i], "offset")) {
9225 pd->type = OPT_OFFSET;
9228 p = strchr(words[i], ',');
9231 if (pd->type == OPT_OFFSET)
9232 pd->d[pd->count].u.label = strdup(words[i]);
9234 pd->d[pd->count].u.val = parse_number(words[i], 0);
9235 pd->d[pd->count].bt_i = -1;
9241 if (in_func && !g_skip_func) {
9243 gen_hdr(g_func, pi);
9245 gen_func(fout, g_fhdr, g_func, pi);
9250 g_ida_func_attr = 0;
9251 g_sct_func_attr = 0;
9252 g_stack_clear_start = 0;
9253 g_stack_clear_len = 0;
9259 func_chunks_used = 0;
9262 memset(&ops, 0, pi * sizeof(ops[0]));
9267 for (i = 0; i < g_func_pd_cnt; i++) {
9269 if (pd->type == OPT_OFFSET) {
9270 for (j = 0; j < pd->count; j++)
9271 free(pd->d[j].u.label);
9286 if (IS(words[1], "proc")) {
9288 aerr("proc '%s' while in_func '%s'?\n",
9291 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9293 strcpy(g_func, words[0]);
9294 set_label(0, words[0]);
9299 if (IS(words[1], "endp"))
9302 aerr("endp '%s' while not in_func?\n", words[0]);
9303 if (!IS(g_func, words[0]))
9304 aerr("endp '%s' while in_func '%s'?\n",
9307 aerr("endp '%s' while skipping code\n", words[0]);
9309 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9310 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
9316 if (!g_skip_func && func_chunks_used) {
9317 // start processing chunks
9318 struct chunk_item *ci, key = { g_func, 0 };
9320 func_chunk_ret = ftell(fasm);
9321 func_chunk_ret_ln = asmln;
9322 if (!func_chunks_sorted) {
9323 qsort(func_chunks, func_chunk_cnt,
9324 sizeof(func_chunks[0]), cmp_chunks);
9325 func_chunks_sorted = 1;
9327 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9328 sizeof(func_chunks[0]), cmp_chunks);
9330 aerr("'%s' needs chunks, but none found\n", g_func);
9331 func_chunk_i = ci - func_chunks;
9332 for (; func_chunk_i > 0; func_chunk_i--)
9333 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9336 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9338 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9339 asmln = func_chunks[func_chunk_i].asmln;
9347 if (wordc == 2 && IS(words[1], "ends")) {
9351 goto do_pending_endp;
9355 // scan for next text segment
9356 while (my_fgets(line, sizeof(line), fasm)) {
9359 if (*p == 0 || *p == ';')
9362 if (strstr(p, "segment para public 'CODE' use32"))
9369 p = strchr(words[0], ':');
9371 set_label(pi, words[0]);
9375 if (!in_func || g_skip_func || skip_code) {
9376 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9378 anote("skipping from '%s'\n", g_labels[pi]);
9382 g_labels[pi] = NULL;
9386 if (wordc > 1 && IS(words[1], "="))
9389 aerr("unhandled equ, wc=%d\n", wordc);
9390 if (g_eqcnt >= eq_alloc) {
9392 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9393 my_assert_not(g_eqs, NULL);
9396 len = strlen(words[0]);
9397 if (len > sizeof(g_eqs[0].name) - 1)
9398 aerr("equ name too long: %d\n", len);
9399 strcpy(g_eqs[g_eqcnt].name, words[0]);
9401 if (!IS(words[3], "ptr"))
9402 aerr("unhandled equ\n");
9403 if (IS(words[2], "dword"))
9404 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9405 else if (IS(words[2], "word"))
9406 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9407 else if (IS(words[2], "byte"))
9408 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9409 else if (IS(words[2], "qword"))
9410 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9412 aerr("bad lmod: '%s'\n", words[2]);
9414 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9419 if (pi >= ARRAY_SIZE(ops))
9420 aerr("too many ops\n");
9422 parse_op(&ops[pi], words, wordc);
9424 ops[pi].datap = sctproto;
9439 // vim:ts=2:shiftwidth=2:expandtab