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)
25 #include "my_assert.h"
29 #include "protoparse.h"
31 static const char *asmfn;
35 #define anote(fmt, ...) \
36 printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
37 #define awarn(fmt, ...) \
38 printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
39 #define aerr(fmt, ...) do { \
40 printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
45 #include "masm_tools.h"
48 OPF_RMD = (1 << 0), /* removed from code generation */
49 OPF_DATA = (1 << 1), /* data processing - writes to dst opr */
50 OPF_FLAGS = (1 << 2), /* sets flags */
51 OPF_JMP = (1 << 3), /* branch, call */
52 OPF_CJMP = (1 << 4), /* cond. branch (cc or jecxz/loop) */
53 OPF_CC = (1 << 5), /* uses flags */
54 OPF_TAIL = (1 << 6), /* ret or tail call */
55 OPF_RSAVE = (1 << 7), /* push/pop is local reg save/load */
56 OPF_REP = (1 << 8), /* prefixed by rep */
57 OPF_REPZ = (1 << 9), /* rep is repe/repz */
58 OPF_REPNZ = (1 << 10), /* rep is repne/repnz */
59 OPF_FARG = (1 << 11), /* push collected as func arg */
60 OPF_FARGNR = (1 << 12), /* push collected as func arg (no reuse) */
61 OPF_EBP_S = (1 << 13), /* ebp used as scratch here, not BP */
62 OPF_DF = (1 << 14), /* DF flag set */
63 OPF_ATAIL = (1 << 15), /* tail call with reused arg frame */
64 OPF_32BIT = (1 << 16), /* 32bit division */
65 OPF_LOCK = (1 << 17), /* op has lock prefix */
66 OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
67 OPF_DONE = (1 << 19), /* already fully handled by analysis */
68 OPF_PPUSH = (1 << 20), /* part of complex push-pop graph */
69 OPF_NOREGS = (1 << 21), /* don't track regs of this op */
70 OPF_FPUSH = (1 << 22), /* pushes x87 stack */
71 OPF_FPOP = (1 << 23), /* pops x87 stack */
72 OPF_FPOPP = (1 << 24), /* pops x87 stack twice */
73 OPF_FSHIFT = (1 << 25), /* x87 stack shift is actually needed */
74 OPF_FINT = (1 << 26), /* integer float op arg */
165 // pseudo-ops for lib calls
184 // must be sorted (larger len must be further in enum)
193 #define MAX_EXITS 128
195 #define MAX_OPERANDS 3
198 #define OPR_INIT(type_, lmod_, reg_) \
199 { type_, lmod_, reg_, }
203 enum opr_lenmod lmod;
205 unsigned int is_ptr:1; // pointer in C
206 unsigned int is_array:1; // array in C
207 unsigned int type_from_var:1; // .. in header, sometimes wrong
208 unsigned int size_mismatch:1; // type override differs from C
209 unsigned int size_lt:1; // type override is larger than C
210 unsigned int segment:7; // had segment override (enum segment)
211 const struct parsed_proto *pp; // for OPT_LABEL
218 struct parsed_opr operand[MAX_OPERANDS];
221 unsigned char pfo_inv;
222 unsigned char operand_cnt;
223 unsigned char p_argnum; // arg push: altered before call arg #
224 unsigned char p_arggrp; // arg push: arg group # for above
225 unsigned char p_argpass;// arg push: arg of host func
226 short p_argnext;// arg push: same arg pushed elsewhere or -1
227 int regmask_src; // all referensed regs
229 int pfomask; // flagop: parsed_flag_op that can't be delayed
230 int cc_scratch; // scratch storage during analysis
231 int bt_i; // branch target for branches
232 struct parsed_data *btj;// branch targets for jumptables
233 struct parsed_proto *pp;// parsed_proto for OP_CALL
239 // on start: function/data type hint (sctproto)
241 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
242 // OP_PUSH - points to OP_POP in complex push/pop graph
243 // OP_POP - points to OP_PUSH in simple push/pop pair
244 // OP_FCOM - needed_status_word_bits | (is_z_check << 16)
248 enum opr_lenmod lmod;
255 enum opr_lenmod lmod;
269 struct label_ref *next;
273 IDAFA_BP_FRAME = (1 << 0),
274 IDAFA_LIB_FUNC = (1 << 1),
275 IDAFA_STATIC = (1 << 2),
276 IDAFA_NORETURN = (1 << 3),
277 IDAFA_THUNK = (1 << 4),
278 IDAFA_FPD = (1 << 5),
282 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
283 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
305 // note: limited to 32k due to p_argnext
307 #define MAX_ARG_GRP 2
309 static struct parsed_op ops[MAX_OPS];
310 static struct parsed_equ *g_eqs;
312 static char *g_labels[MAX_OPS];
313 static struct label_ref g_label_refs[MAX_OPS];
314 static const struct parsed_proto *g_func_pp;
315 static struct parsed_data *g_func_pd;
316 static int g_func_pd_cnt;
317 static int g_func_lmods;
318 static char g_func[256];
319 static char g_comment[256];
320 static int g_bp_frame;
321 static int g_sp_frame;
322 static int g_stack_frame_used;
323 static int g_stack_fsz;
324 static int g_seh_found;
325 static int g_seh_size;
326 static int g_ida_func_attr;
327 static int g_sct_func_attr;
328 static int g_stack_clear_start; // in dwords
329 static int g_stack_clear_len;
330 static int g_regmask_init;
331 static int g_skip_func;
332 static int g_allow_regfunc;
333 static int g_allow_user_icall;
334 static int g_quiet_pp;
335 static int g_header_mode;
337 #define ferr(op_, fmt, ...) do { \
338 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
339 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
343 #define fnote(op_, fmt, ...) \
344 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
345 dump_op(op_), ##__VA_ARGS__)
347 #define ferr_assert(op_, cond) do { \
348 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
351 const char *regs_r32[] = {
352 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
353 // not r32, but list here for easy parsing and printing
354 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
355 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
357 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
358 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
359 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
365 xMM0, xMM1, xMM2, xMM3, // mmx
366 xMM4, xMM5, xMM6, xMM7,
367 xST0, xST1, xST2, xST3, // x87
368 xST4, xST5, xST6, xST7,
371 #define mxAX (1 << xAX)
372 #define mxCX (1 << xCX)
373 #define mxDX (1 << xDX)
374 #define mxSP (1 << xSP)
375 #define mxST0 (1 << xST0)
376 #define mxST1 (1 << xST1)
377 #define mxST1_0 (mxST1 | mxST0)
378 #define mxST7_2 (0xfc << xST0)
379 #define mxSTa (0xff << xST0)
381 // possible basic comparison types (without inversion)
382 enum parsed_flag_op {
386 PFO_BE, // 6 CF=1||ZF=1
390 PFO_LE, // e ZF=1||SF!=OF
393 #define PFOB_O (1 << PFO_O)
394 #define PFOB_C (1 << PFO_C)
395 #define PFOB_Z (1 << PFO_Z)
396 #define PFOB_S (1 << PFO_S)
398 static const char *parsed_flag_op_names[] = {
399 "o", "c", "z", "be", "s", "p", "l", "le"
402 static int char_array_i(const char *array[], size_t len, const char *s)
406 for (i = 0; i < len; i++)
413 static void printf_number(char *buf, size_t buf_size,
414 unsigned long number)
416 // output in C-friendly form
417 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
420 static int check_segment_prefix(const char *s)
422 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
426 case 'c': return SEG_CS;
427 case 'd': return SEG_DS;
428 case 's': return SEG_SS;
429 case 'e': return SEG_ES;
430 case 'f': return SEG_FS;
431 case 'g': return SEG_GS;
436 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
440 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
442 *reg_lmod = OPLM_QWORD;
446 *reg_lmod = OPLM_DWORD;
449 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
451 *reg_lmod = OPLM_WORD;
454 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
456 *reg_lmod = OPLM_BYTE;
459 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
461 *reg_lmod = OPLM_BYTE;
468 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
470 enum opr_lenmod lmod;
483 while (my_isblank(*s))
485 for (; my_issep(*s); d++, s++)
487 while (my_isblank(*s))
491 // skip '?s:' prefixes
492 if (check_segment_prefix(s))
495 s = next_idt(w, sizeof(w), s);
500 reg = parse_reg(&lmod, w);
502 *regmask |= 1 << reg;
506 if ('0' <= w[0] && w[0] <= '9') {
507 number = parse_number(w, 0);
508 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
512 // probably some label/identifier - pass
515 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
519 strcpy(name, cvtbuf);
524 static int is_reg_in_str(const char *s)
528 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
531 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
532 if (!strncmp(s, regs_r32[i], 3))
538 static const char *parse_stack_el(const char *name, char *extra_reg,
539 int *base_val, int early_try)
541 const char *p, *p2, *s;
547 if (g_bp_frame || early_try)
550 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
552 if (extra_reg != NULL) {
553 strncpy(extra_reg, name, 3);
558 if (IS_START(p, "ebp+")) {
562 if (p2 != NULL && is_reg_in_str(p)) {
563 if (extra_reg != NULL) {
564 strncpy(extra_reg, p, p2 - p);
565 extra_reg[p2 - p] = 0;
570 if (!('0' <= *p && *p <= '9'))
577 if (!IS_START(name, "esp+"))
583 if (is_reg_in_str(s)) {
584 if (extra_reg != NULL) {
585 strncpy(extra_reg, s, p - s);
586 extra_reg[p - s] = 0;
591 aerr("%s IDA stackvar not set?\n", __func__);
593 if (!('0' <= *s && *s <= '9')) {
594 aerr("%s IDA stackvar offset not set?\n", __func__);
597 if (s[0] == '0' && s[1] == 'x')
600 if (len < sizeof(buf) - 1) {
601 strncpy(buf, s, len);
604 val = strtol(buf, &endp, 16);
605 if (val == 0 || *endp != 0 || errno != 0) {
606 aerr("%s num parse fail for '%s'\n", __func__, buf);
615 if ('0' <= *p && *p <= '9')
618 if (base_val != NULL)
623 static int guess_lmod_from_name(struct parsed_opr *opr)
625 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
626 opr->lmod = OPLM_DWORD;
629 if (IS_START(opr->name, "word_")) {
630 opr->lmod = OPLM_WORD;
633 if (IS_START(opr->name, "byte_")) {
634 opr->lmod = OPLM_BYTE;
637 if (IS_START(opr->name, "qword_")) {
638 opr->lmod = OPLM_QWORD;
644 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
645 const struct parsed_type *c_type)
647 static const char *qword_types[] = {
648 "uint64_t", "int64_t", "__int64",
650 static const char *dword_types[] = {
651 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
652 "WPARAM", "LPARAM", "UINT", "__int32",
653 "LONG", "HIMC", "BOOL", "size_t",
656 static const char *word_types[] = {
657 "uint16_t", "int16_t", "_WORD", "WORD",
658 "unsigned __int16", "__int16",
660 static const char *byte_types[] = {
661 "uint8_t", "int8_t", "char",
662 "unsigned __int8", "__int8", "BYTE", "_BYTE",
664 // structures.. deal the same as with _UNKNOWN for now
670 if (c_type->is_ptr) {
675 n = skip_type_mod(c_type->name);
677 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
678 if (IS(n, dword_types[i])) {
684 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
685 if (IS(n, word_types[i])) {
691 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
692 if (IS(n, byte_types[i])) {
698 for (i = 0; i < ARRAY_SIZE(qword_types); i++) {
699 if (IS(n, qword_types[i])) {
708 static char *default_cast_to(char *buf, size_t buf_size,
709 struct parsed_opr *opr)
713 if (!opr->is_ptr || strchr(opr->name, '['))
715 if (opr->pp == NULL || opr->pp->type.name == NULL
718 snprintf(buf, buf_size, "%s", "(void *)");
722 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
726 static enum opr_type lmod_from_directive(const char *d)
730 else if (IS(d, "dw"))
732 else if (IS(d, "db"))
735 aerr("unhandled directive: '%s'\n", d);
739 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
745 *regmask |= 1 << reg;
748 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
751 static int parse_operand(struct parsed_opr *opr,
752 int *regmask, int *regmask_indirect,
753 char words[16][256], int wordc, int w, unsigned int op_flags)
755 const struct parsed_proto *pp = NULL;
756 enum opr_lenmod tmplmod;
757 unsigned long number;
765 aerr("parse_operand w %d, wordc %d\n", w, wordc);
769 for (i = w; i < wordc; i++) {
770 len = strlen(words[i]);
771 if (words[i][len - 1] == ',') {
772 words[i][len - 1] = 0;
778 wordc_in = wordc - w;
780 if ((op_flags & OPF_JMP) && wordc_in > 0
781 && !('0' <= words[w][0] && words[w][0] <= '9'))
783 const char *label = NULL;
785 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
786 && IS(words[w + 1], "ptr"))
787 label = words[w + 2];
788 else if (wordc_in == 2 && IS(words[w], "short"))
789 label = words[w + 1];
790 else if (wordc_in == 1
791 && strchr(words[w], '[') == NULL
792 && parse_reg(&tmplmod, words[w]) < 0)
796 opr->type = OPT_LABEL;
797 ret = check_segment_prefix(label);
802 strcpy(opr->name, label);
808 if (IS(words[w + 1], "ptr")) {
809 if (IS(words[w], "dword"))
810 opr->lmod = OPLM_DWORD;
811 else if (IS(words[w], "word"))
812 opr->lmod = OPLM_WORD;
813 else if (IS(words[w], "byte"))
814 opr->lmod = OPLM_BYTE;
815 else if (IS(words[w], "qword"))
816 opr->lmod = OPLM_QWORD;
818 aerr("type parsing failed\n");
820 wordc_in = wordc - w;
825 if (IS(words[w], "offset")) {
826 opr->type = OPT_OFFSET;
827 opr->lmod = OPLM_DWORD;
828 strcpy(opr->name, words[w + 1]);
829 pp = proto_parse(g_fhdr, opr->name, 1);
832 if (IS(words[w], "(offset")) {
833 p = strchr(words[w + 1], ')');
835 aerr("parse of bracketed offset failed\n");
837 opr->type = OPT_OFFSET;
838 strcpy(opr->name, words[w + 1]);
844 aerr("parse_operand 1 word expected\n");
846 ret = check_segment_prefix(words[w]);
849 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
850 if (ret == SEG_FS && IS(words[w], "0"))
853 strcpy(opr->name, words[w]);
855 if (words[w][0] == '[') {
856 opr->type = OPT_REGMEM;
857 ret = sscanf(words[w], "[%[^]]]", opr->name);
859 aerr("[] parse failure\n");
861 parse_indmode(opr->name, regmask_indirect, 1);
862 if (opr->lmod == OPLM_UNSPEC
863 && parse_stack_el(opr->name, NULL, NULL, 1))
866 struct parsed_equ *eq =
867 equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
869 opr->lmod = eq->lmod;
871 // might be unaligned access
872 g_func_lmods |= 1 << OPLM_BYTE;
876 else if (strchr(words[w], '[')) {
878 p = strchr(words[w], '[');
879 opr->type = OPT_REGMEM;
880 parse_indmode(p, regmask_indirect, 0);
881 strncpy(buf, words[w], p - words[w]);
882 buf[p - words[w]] = 0;
883 pp = proto_parse(g_fhdr, buf, 1);
886 else if (('0' <= words[w][0] && words[w][0] <= '9')
887 || words[w][0] == '-')
889 number = parse_number(words[w], 0);
890 opr->type = OPT_CONST;
892 printf_number(opr->name, sizeof(opr->name), number);
896 ret = parse_reg(&tmplmod, opr->name);
898 setup_reg_opr(opr, ret, tmplmod, regmask);
902 // most likely var in data segment
903 opr->type = OPT_LABEL;
904 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
908 if (pp->is_fptr || pp->is_func) {
909 opr->lmod = OPLM_DWORD;
913 tmplmod = OPLM_UNSPEC;
914 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
915 anote("unhandled C type '%s' for '%s'\n",
916 pp->type.name, opr->name);
918 if (opr->lmod == OPLM_UNSPEC) {
920 opr->type_from_var = 1;
922 else if (opr->lmod != tmplmod) {
923 opr->size_mismatch = 1;
924 if (tmplmod < opr->lmod)
927 opr->is_ptr = pp->type.is_ptr;
929 opr->is_array = pp->type.is_array;
933 if (opr->lmod == OPLM_UNSPEC)
934 guess_lmod_from_name(opr);
938 static const struct {
943 { "repe", OPF_REP|OPF_REPZ },
944 { "repz", OPF_REP|OPF_REPZ },
945 { "repne", OPF_REP|OPF_REPNZ },
946 { "repnz", OPF_REP|OPF_REPNZ },
947 { "lock", OPF_LOCK }, // ignored for now..
950 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
952 static const struct {
955 unsigned short minopr;
956 unsigned short maxopr;
959 unsigned char pfo_inv;
961 { "nop", OP_NOP, 0, 0, 0 },
962 { "push", OP_PUSH, 1, 1, 0 },
963 { "pop", OP_POP, 1, 1, OPF_DATA },
964 { "pusha",OP_PUSHA, 0, 0, 0 },
965 { "popa", OP_POPA, 0, 0, OPF_DATA },
966 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
967 { "mov" , OP_MOV, 2, 2, OPF_DATA },
968 { "lea", OP_LEA, 2, 2, OPF_DATA },
969 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
970 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
971 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
972 { "not", OP_NOT, 1, 1, OPF_DATA },
973 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
974 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
975 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
976 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
977 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
978 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
979 { "stosb",OP_STOS, 0, 0, OPF_DATA },
980 { "stosw",OP_STOS, 0, 0, OPF_DATA },
981 { "stosd",OP_STOS, 0, 0, OPF_DATA },
982 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
983 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
984 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
985 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
986 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
987 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
988 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
989 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
990 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
991 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
992 { "cld", OP_CLD, 0, 0, OPF_DATA },
993 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
994 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
995 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
996 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
997 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
998 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
999 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
1000 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
1001 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
1002 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
1003 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
1004 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
1005 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
1006 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1007 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1008 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1009 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1010 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
1011 { "bsr", OP_BSR, 2, 2, OPF_DATA|OPF_FLAGS },
1012 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
1013 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
1014 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
1015 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
1016 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
1017 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
1018 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
1019 { "test", OP_TEST, 2, 2, OPF_FLAGS },
1020 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
1021 { "retn", OP_RET, 0, 1, OPF_TAIL },
1022 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
1023 { "jmp", OP_JMP, 1, 1, OPF_JMP },
1024 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
1025 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
1026 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
1027 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
1028 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
1029 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
1030 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
1031 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1032 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1033 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
1034 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
1035 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
1036 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
1037 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1038 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1039 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1040 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1041 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1042 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1043 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1044 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1045 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1046 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1047 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1048 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1049 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1050 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1051 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1052 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1053 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1054 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1055 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1056 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1057 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1058 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1059 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1060 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1061 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1062 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1063 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1064 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1065 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1066 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1067 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1068 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1069 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1070 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1071 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1072 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1073 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1074 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1075 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1076 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1077 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1078 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1079 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1080 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1081 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1082 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1083 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1085 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1086 { "fild", OP_FILD, 1, 1, OPF_FPUSH|OPF_FINT },
1087 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1088 { "fldl2t", OP_FLDc, 0, 0, OPF_FPUSH },
1089 { "fldl2e", OP_FLDc, 0, 0, OPF_FPUSH },
1090 { "fldpi", OP_FLDc, 0, 0, OPF_FPUSH },
1091 { "fldlg2", OP_FLDc, 0, 0, OPF_FPUSH },
1092 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1093 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1094 { "fst", OP_FST, 1, 1, 0 },
1095 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1096 { "fist", OP_FIST, 1, 1, OPF_FINT },
1097 { "fistp", OP_FIST, 1, 1, OPF_FPOP|OPF_FINT },
1098 { "fadd", OP_FADD, 0, 2, 0 },
1099 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1100 { "fdiv", OP_FDIV, 0, 2, 0 },
1101 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1102 { "fmul", OP_FMUL, 0, 2, 0 },
1103 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1104 { "fsub", OP_FSUB, 0, 2, 0 },
1105 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1106 { "fdivr", OP_FDIVR, 0, 2, 0 },
1107 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1108 { "fsubr", OP_FSUBR, 0, 2, 0 },
1109 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1110 { "fiadd", OP_FIADD, 1, 1, OPF_FINT },
1111 { "fidiv", OP_FIDIV, 1, 1, OPF_FINT },
1112 { "fimul", OP_FIMUL, 1, 1, OPF_FINT },
1113 { "fisub", OP_FISUB, 1, 1, OPF_FINT },
1114 { "fidivr", OP_FIDIVR, 1, 1, OPF_FINT },
1115 { "fisubr", OP_FISUBR, 1, 1, OPF_FINT },
1116 { "fcom", OP_FCOM, 0, 1, 0 },
1117 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1118 { "fcompp", OP_FCOM, 0, 0, OPF_FPOPP },
1119 { "fucom", OP_FCOM, 0, 1, 0 },
1120 { "fucomp", OP_FCOM, 0, 1, OPF_FPOP },
1121 { "fucompp",OP_FCOM, 0, 0, OPF_FPOPP },
1122 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1123 { "fchs", OP_FCHS, 0, 0, 0 },
1124 { "fcos", OP_FCOS, 0, 0, 0 },
1125 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1126 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1127 { "fsin", OP_FSIN, 0, 0, 0 },
1128 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1129 { "fxch", OP_FXCH, 1, 1, 0 },
1130 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1132 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1133 { "movq", OP_MOV, 2, 2, OPF_DATA },
1134 // pseudo-ops for lib calls
1135 { "_allshl",OPP_ALLSHL },
1136 { "_allshr",OPP_ALLSHR },
1137 { "_ftol", OPP_FTOL },
1138 { "_CIpow", OPP_CIPOW },
1139 { "abort", OPP_ABORT },
1144 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1146 enum opr_lenmod lmod = OPLM_UNSPEC;
1147 int prefix_flags = 0;
1155 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1156 if (IS(words[w], pref_table[i].name)) {
1157 prefix_flags = pref_table[i].flags;
1164 aerr("lone prefix: '%s'\n", words[0]);
1169 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1170 if (IS(words[w], op_table[i].name))
1174 if (i == ARRAY_SIZE(op_table)) {
1176 aerr("unhandled op: '%s'\n", words[0]);
1181 op->op = op_table[i].op;
1182 op->flags = op_table[i].flags | prefix_flags;
1183 op->pfo = op_table[i].pfo;
1184 op->pfo_inv = op_table[i].pfo_inv;
1185 op->regmask_src = op->regmask_dst = 0;
1188 if (op->op == OP_UD2)
1191 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1192 if (opr >= op_table[i].minopr && w >= wordc)
1195 regmask = regmask_ind = 0;
1196 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1197 words, wordc, w, op->flags);
1199 if (opr == 0 && (op->flags & OPF_DATA))
1200 op->regmask_dst = regmask;
1202 op->regmask_src |= regmask;
1203 op->regmask_src |= regmask_ind;
1205 if (op->operand[opr].lmod != OPLM_UNSPEC)
1206 g_func_lmods |= 1 << op->operand[opr].lmod;
1210 aerr("parse_op %s incomplete: %d/%d\n",
1211 words[0], w, wordc);
1214 op->operand_cnt = opr;
1215 if (!strncmp(op_table[i].name, "set", 3))
1216 op->operand[0].lmod = OPLM_BYTE;
1219 // first operand is not dst
1222 op->regmask_src |= op->regmask_dst;
1223 op->regmask_dst = 0;
1226 // first operand is src too
1239 op->regmask_src |= op->regmask_dst;
1244 op->regmask_src |= op->regmask_dst;
1245 op->regmask_dst |= op->regmask_src;
1251 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1252 && op->operand[0].lmod == op->operand[1].lmod
1253 && op->operand[0].reg == op->operand[1].reg
1254 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1256 op->regmask_src = 0;
1259 op->regmask_src |= op->regmask_dst;
1262 // ops with implicit argumets
1264 op->operand_cnt = 2;
1265 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1266 op->regmask_dst = op->regmask_src;
1267 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1271 op->operand_cnt = 2;
1272 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1273 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1279 if (words[op_w][4] == 'b')
1281 else if (words[op_w][4] == 'w')
1283 else if (words[op_w][4] == 'd')
1286 op->regmask_src = 0;
1287 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1288 OPLM_DWORD, &op->regmask_src);
1289 op->regmask_dst = op->regmask_src;
1290 setup_reg_opr(&op->operand[j++], xAX, lmod,
1291 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1292 if (op->flags & OPF_REP) {
1293 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1294 op->regmask_dst |= 1 << xCX;
1296 op->operand_cnt = j;
1301 if (words[op_w][4] == 'b')
1303 else if (words[op_w][4] == 'w')
1305 else if (words[op_w][4] == 'd')
1308 op->regmask_src = 0;
1309 // note: lmod is not correct, don't have where to place it
1310 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1311 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1312 if (op->flags & OPF_REP)
1313 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1314 op->operand_cnt = j;
1315 op->regmask_dst = op->regmask_src;
1319 op->regmask_dst = 1 << xCX;
1322 op->operand_cnt = 2;
1323 op->regmask_src = 1 << xCX;
1324 op->operand[1].type = OPT_REG;
1325 op->operand[1].reg = xCX;
1326 op->operand[1].lmod = OPLM_DWORD;
1330 if (op->operand_cnt == 2) {
1331 if (op->operand[0].type != OPT_REG)
1332 aerr("reg expected\n");
1333 op->regmask_src |= 1 << op->operand[0].reg;
1335 if (op->operand_cnt != 1)
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;
1348 // we could set up operands for edx:eax, but there is no real need to
1349 // (see is_opr_modified())
1350 op->regmask_src |= op->regmask_dst;
1351 op->regmask_dst = (1 << xDX) | (1 << xAX);
1352 if (op->operand[0].lmod == OPLM_UNSPEC)
1353 op->operand[0].lmod = OPLM_DWORD;
1361 op->regmask_src |= op->regmask_dst;
1362 if (op->operand[1].lmod == OPLM_UNSPEC)
1363 op->operand[1].lmod = OPLM_BYTE;
1368 op->regmask_src |= op->regmask_dst;
1369 if (op->operand[2].lmod == OPLM_UNSPEC)
1370 op->operand[2].lmod = OPLM_BYTE;
1374 op->regmask_src |= op->regmask_dst;
1375 op->regmask_dst = 0;
1376 if (op->operand[0].lmod == OPLM_UNSPEC
1377 && (op->operand[0].type == OPT_CONST
1378 || op->operand[0].type == OPT_OFFSET
1379 || op->operand[0].type == OPT_LABEL))
1380 op->operand[0].lmod = OPLM_DWORD;
1386 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1387 && op->operand[0].lmod == op->operand[1].lmod
1388 && op->operand[0].reg == op->operand[1].reg
1389 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1391 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1392 op->regmask_src = op->regmask_dst = 0;
1397 if (op->operand[0].type == OPT_REG
1398 && op->operand[1].type == OPT_REGMEM)
1401 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1402 if (IS(buf, op->operand[1].name))
1403 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1408 // trashed regs must be explicitly detected later
1409 op->regmask_dst = 0;
1413 op->regmask_dst = (1 << xBP) | (1 << xSP);
1414 op->regmask_src = 1 << xBP;
1419 op->regmask_dst |= mxST0;
1423 op->regmask_dst |= mxST0;
1424 if (IS(words[op_w] + 3, "1"))
1425 op->operand[0].val = X87_CONST_1;
1426 else if (IS(words[op_w] + 3, "l2t"))
1427 op->operand[0].val = X87_CONST_L2T;
1428 else if (IS(words[op_w] + 3, "l2e"))
1429 op->operand[0].val = X87_CONST_L2E;
1430 else if (IS(words[op_w] + 3, "pi"))
1431 op->operand[0].val = X87_CONST_PI;
1432 else if (IS(words[op_w] + 3, "lg2"))
1433 op->operand[0].val = X87_CONST_LG2;
1434 else if (IS(words[op_w] + 3, "ln2"))
1435 op->operand[0].val = X87_CONST_LN2;
1436 else if (IS(words[op_w] + 3, "z"))
1437 op->operand[0].val = X87_CONST_Z;
1439 aerr("fld what?\n");
1444 op->regmask_src |= mxST0;
1453 op->regmask_src |= mxST0;
1454 if (op->operand_cnt == 2)
1455 op->regmask_src |= op->regmask_dst;
1456 else if (op->operand_cnt == 1) {
1457 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1458 op->operand[0].type = OPT_REG;
1459 op->operand[0].lmod = OPLM_QWORD;
1460 op->operand[0].reg = xST0;
1461 op->regmask_dst |= mxST0;
1464 // IDA doesn't use this
1465 aerr("no operands?\n");
1479 op->regmask_src |= mxST0;
1480 op->regmask_dst |= mxST0;
1485 op->regmask_src |= mxST0 | mxST1;
1486 op->regmask_dst |= mxST0;
1494 op->regmask_src |= mxST0;
1495 if (op->operand_cnt == 0) {
1496 op->operand_cnt = 1;
1497 op->operand[0].type = OPT_REG;
1498 op->operand[0].lmod = OPLM_QWORD;
1499 op->operand[0].reg = xST1;
1500 op->regmask_src |= mxST1;
1508 if (op->operand[0].type == OPT_REG
1509 && op->operand[1].type == OPT_CONST)
1511 struct parsed_opr *op1 = &op->operand[1];
1512 if ((op->op == OP_AND && op1->val == 0)
1515 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1516 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1518 op->regmask_src = 0;
1523 static const char *op_name(struct parsed_op *po)
1525 static char buf[16];
1529 if (po->op == OP_JCC || po->op == OP_SCC) {
1531 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1534 strcpy(p, parsed_flag_op_names[po->pfo]);
1538 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1539 if (op_table[i].op == po->op)
1540 return op_table[i].name;
1546 static const char *dump_op(struct parsed_op *po)
1548 static char out[128];
1555 snprintf(out, sizeof(out), "%s", op_name(po));
1556 for (i = 0; i < po->operand_cnt; i++) {
1560 snprintf(p, sizeof(out) - (p - out),
1561 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1562 po->operand[i].name);
1568 static const char *lmod_type_u(struct parsed_op *po,
1569 enum opr_lenmod lmod)
1581 ferr(po, "invalid lmod: %d\n", lmod);
1582 return "(_invalid_)";
1586 static const char *lmod_cast_u(struct parsed_op *po,
1587 enum opr_lenmod lmod)
1599 ferr(po, "invalid lmod: %d\n", lmod);
1600 return "(_invalid_)";
1604 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1605 enum opr_lenmod lmod)
1617 ferr(po, "invalid lmod: %d\n", lmod);
1618 return "(_invalid_)";
1622 static const char *lmod_cast_s(struct parsed_op *po,
1623 enum opr_lenmod lmod)
1635 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1636 return "(_invalid_)";
1640 static const char *lmod_cast(struct parsed_op *po,
1641 enum opr_lenmod lmod, int is_signed)
1644 lmod_cast_s(po, lmod) :
1645 lmod_cast_u(po, lmod);
1648 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1660 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1665 static const char *opr_name(struct parsed_op *po, int opr_num)
1667 if (opr_num >= po->operand_cnt)
1668 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1669 return po->operand[opr_num].name;
1672 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1674 if (opr_num >= po->operand_cnt)
1675 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1676 if (po->operand[opr_num].type != OPT_CONST)
1677 ferr(po, "opr %d: const expected\n", opr_num);
1678 return po->operand[opr_num].val;
1681 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1683 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1684 ferr(po, "invalid reg: %d\n", popr->reg);
1685 return regs_r32[popr->reg];
1688 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1690 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1692 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1694 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1696 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1701 *is_signed = cast[1] == 's' ? 1 : 0;
1705 static int check_deref_cast(const char *cast, int *bits)
1707 if (IS_START(cast, "*(u8 *)"))
1709 else if (IS_START(cast, "*(u16 *)"))
1711 else if (IS_START(cast, "*(u32 *)"))
1713 else if (IS_START(cast, "*(u64 *)"))
1721 // cast1 is the "final" cast
1722 static const char *simplify_cast(const char *cast1, const char *cast2)
1724 static char buf[256];
1732 if (IS(cast1, cast2))
1735 if (check_simple_cast(cast1, &bits1, &s1) == 0
1736 && check_simple_cast(cast2, &bits2, &s2) == 0)
1741 if (check_simple_cast(cast1, &bits1, &s1) == 0
1742 && check_deref_cast(cast2, &bits2) == 0)
1744 if (bits1 == bits2) {
1745 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1750 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1753 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1757 static const char *simplify_cast_num(const char *cast, unsigned int val)
1759 if (IS(cast, "(u8)") && val < 0x100)
1761 if (IS(cast, "(s8)") && val < 0x80)
1763 if (IS(cast, "(u16)") && val < 0x10000)
1765 if (IS(cast, "(s16)") && val < 0x8000)
1767 if (IS(cast, "(s32)") && val < 0x80000000)
1773 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1782 namelen = strlen(name);
1784 p = strpbrk(name, "+-");
1788 ferr(po, "equ parse failed for '%s'\n", name);
1791 *extra_offs = strtol(p, &endp, 16);
1792 if (*endp != 0 || errno != 0)
1793 ferr(po, "equ parse failed for '%s'\n", name);
1796 for (i = 0; i < g_eqcnt; i++)
1797 if (strncmp(g_eqs[i].name, name, namelen) == 0
1798 && g_eqs[i].name[namelen] == 0)
1802 ferr(po, "unresolved equ name: '%s'\n", name);
1809 static int is_stack_access(struct parsed_op *po,
1810 const struct parsed_opr *popr)
1812 return (parse_stack_el(popr->name, NULL, NULL, 0)
1813 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1814 && IS_START(popr->name, "ebp")));
1817 static void parse_stack_access(struct parsed_op *po,
1818 const char *name, char *ofs_reg, int *offset_out,
1819 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1821 const char *bp_arg = "";
1822 const char *p = NULL;
1823 struct parsed_equ *eq;
1830 if (IS_START(name, "ebp-")
1831 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1834 if (IS_START(p, "0x"))
1837 offset = strtoul(p, &endp, 16);
1840 if (*endp != 0 || errno != 0)
1841 ferr(po, "ebp- parse of '%s' failed\n", name);
1844 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1845 eq = equ_find(po, bp_arg, &offset);
1847 ferr(po, "detected but missing eq\n");
1848 offset += eq->offset;
1851 if (!strncmp(name, "ebp", 3))
1854 // yes it sometimes LEAs ra for compares..
1855 if (!is_lea && ofs_reg[0] == 0
1856 && stack_ra <= offset && offset < stack_ra + 4)
1858 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1861 *offset_out = offset;
1863 *stack_ra_out = stack_ra;
1865 *bp_arg_out = bp_arg;
1868 static int parse_stack_esp_offset(struct parsed_op *po,
1869 const char *name, int *offset_out)
1871 char ofs_reg[16] = { 0, };
1872 struct parsed_equ *eq;
1878 if (strstr(name, "esp") == NULL)
1880 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1881 if (bp_arg == NULL) {
1882 // just plain offset?
1883 if (!IS_START(name, "esp+"))
1886 offset = strtol(name + 4, &endp, 0);
1887 if (endp == NULL || *endp != 0 || errno != 0)
1889 *offset_out = offset;
1893 if (ofs_reg[0] != 0)
1895 eq = equ_find(po, bp_arg, &offset);
1897 ferr(po, "detected but missing eq\n");
1898 offset += eq->offset;
1899 *offset_out = base_val + offset;
1903 static int stack_frame_access(struct parsed_op *po,
1904 struct parsed_opr *popr, char *buf, size_t buf_size,
1905 const char *name, const char *cast, int is_src, int is_lea)
1907 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1908 const char *prefix = "";
1909 const char *bp_arg = NULL;
1910 char ofs_reg[16] = { 0, };
1911 int i, arg_i, arg_s;
1918 if (g_bp_frame && (po->flags & OPF_EBP_S)
1919 && !(po->regmask_src & mxSP))
1920 ferr(po, "stack_frame_access while ebp is scratch\n");
1922 parse_stack_access(po, name, ofs_reg, &offset,
1923 &stack_ra, &bp_arg, is_lea);
1925 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1927 if (offset > stack_ra)
1929 arg_i = (offset - stack_ra - 4) / 4;
1930 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1932 if (g_func_pp->is_vararg
1933 && arg_i == g_func_pp->argc_stack && is_lea)
1935 // should be va_list
1938 snprintf(buf, buf_size, "%sap", cast);
1941 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1942 offset, bp_arg, arg_i);
1944 if (ofs_reg[0] != 0)
1945 ferr(po, "offset reg on arg access?\n");
1947 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1948 if (g_func_pp->arg[i].reg != NULL)
1954 if (i == g_func_pp->argc)
1955 ferr(po, "arg %d not in prototype?\n", arg_i);
1957 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1964 ferr(po, "lea/byte to arg?\n");
1965 if (is_src && (offset & 3) == 0)
1966 snprintf(buf, buf_size, "%sa%d",
1967 simplify_cast(cast, "(u8)"), i + 1);
1969 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1970 cast, offset & 3, i + 1);
1975 ferr(po, "lea/word to arg?\n");
1980 ferr(po, "problematic arg store\n");
1981 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1982 simplify_cast(cast, "*(u16 *)"), i + 1);
1985 ferr(po, "unaligned arg word load\n");
1987 else if (is_src && (offset & 2) == 0)
1988 snprintf(buf, buf_size, "%sa%d",
1989 simplify_cast(cast, "(u16)"), i + 1);
1991 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1992 cast, (offset & 2) ? "HI" : "LO", i + 1);
2004 snprintf(buf, buf_size, "(u32)&a%d + %d",
2007 ferr(po, "unaligned arg store\n");
2009 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
2010 snprintf(buf, buf_size, "%s(a%d >> %d)",
2011 prefix, i + 1, (offset & 3) * 8);
2015 snprintf(buf, buf_size, "%s%sa%d",
2016 prefix, is_lea ? "&" : "", i + 1);
2021 ferr_assert(po, !(offset & 7));
2024 snprintf(buf, buf_size, "%s%sa%d",
2025 prefix, is_lea ? "&" : "", i + 1);
2029 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
2033 strcat(g_comment, " unaligned");
2036 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
2037 if (tmp_lmod != OPLM_DWORD
2038 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
2039 < lmod_bytes(po, popr->lmod) + (offset & 3))))
2041 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
2042 i + 1, offset, g_func_pp->arg[i].type.name);
2044 // can't check this because msvc likes to reuse
2045 // arg space for scratch..
2046 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
2047 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2051 if (g_stack_fsz == 0)
2052 ferr(po, "stack var access without stackframe\n");
2053 g_stack_frame_used = 1;
2055 sf_ofs = g_stack_fsz + offset;
2056 if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2057 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2067 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2068 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2072 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2073 // known unaligned or possibly unaligned
2074 strcat(g_comment, " unaligned");
2076 prefix = "*(u16 *)&";
2077 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2078 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2081 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2085 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2086 // known unaligned or possibly unaligned
2087 strcat(g_comment, " unaligned");
2089 prefix = "*(u32 *)&";
2090 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2091 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2094 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2098 ferr_assert(po, !(sf_ofs & 7));
2099 ferr_assert(po, ofs_reg[0] == 0);
2100 // only used for x87 int64/float, float sets is_lea
2101 if (!is_lea && (po->flags & OPF_FINT))
2102 prefix = "*(s64 *)&";
2103 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2107 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2114 static void check_func_pp(struct parsed_op *po,
2115 const struct parsed_proto *pp, const char *pfx)
2117 enum opr_lenmod tmp_lmod;
2121 if (pp->argc_reg != 0) {
2122 if (!g_allow_user_icall && !pp->is_fastcall) {
2123 pp_print(buf, sizeof(buf), pp);
2124 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2126 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2127 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2128 pfx, pp->argc_reg, pp->argc_stack);
2131 // fptrs must use 32bit args, callsite might have no information and
2132 // lack a cast to smaller types, which results in incorrectly masked
2133 // args passed (callee may assume masked args, it does on ARM)
2134 if (!pp->is_osinc) {
2135 for (i = 0; i < pp->argc; i++) {
2136 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2137 if (ret && tmp_lmod != OPLM_DWORD)
2138 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2139 i + 1, pp->arg[i].type.name);
2144 static const char *check_label_read_ref(struct parsed_op *po,
2145 const char *name, int *is_import)
2147 const struct parsed_proto *pp;
2149 pp = proto_parse(g_fhdr, name, 0);
2151 ferr(po, "proto_parse failed for ref '%s'\n", name);
2154 check_func_pp(po, pp, "ref");
2156 if (is_import != NULL)
2157 *is_import = pp->is_import;
2162 static void check_opr(struct parsed_op *po, struct parsed_opr *popr)
2164 if (popr->segment == SEG_FS)
2165 ferr(po, "fs: used\n");
2166 if (popr->segment == SEG_GS)
2167 ferr(po, "gs: used\n");
2170 static char *out_src_opr(char *buf, size_t buf_size,
2171 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2174 char tmp1[256], tmp2[256];
2181 check_opr(po, popr);
2186 switch (popr->type) {
2189 ferr(po, "lea from reg?\n");
2191 switch (popr->lmod) {
2193 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2196 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2199 snprintf(buf, buf_size, "%s%s",
2200 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2203 if (popr->name[1] == 'h') // XXX..
2204 snprintf(buf, buf_size, "%s(%s >> 8)",
2205 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2207 snprintf(buf, buf_size, "%s%s",
2208 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2211 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2216 if (is_stack_access(po, popr)) {
2217 stack_frame_access(po, popr, buf, buf_size,
2218 popr->name, cast, 1, is_lea);
2222 strcpy(expr, popr->name);
2223 if (strchr(expr, '[')) {
2224 // special case: '[' can only be left for label[reg] form
2225 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2227 ferr(po, "parse failure for '%s'\n", expr);
2228 if (tmp1[0] == '(') {
2229 // (off_4FFF50+3)[eax]
2230 p = strchr(tmp1 + 1, ')');
2231 if (p == NULL || p[1] != 0)
2232 ferr(po, "parse failure (2) for '%s'\n", expr);
2234 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2236 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2239 // XXX: do we need more parsing?
2241 snprintf(buf, buf_size, "%s", expr);
2245 snprintf(buf, buf_size, "%s(%s)",
2246 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2250 name = check_label_read_ref(po, popr->name, &is_import);
2252 // for imported data, asm is loading the offset
2255 if (cast[0] == 0 && popr->is_ptr)
2259 snprintf(buf, buf_size, "(u32)&%s", name);
2260 else if (popr->size_lt)
2261 snprintf(buf, buf_size, "%s%s%s%s", cast,
2262 lmod_cast_u_ptr(po, popr->lmod),
2263 popr->is_array ? "" : "&", name);
2265 snprintf(buf, buf_size, "%s%s%s", cast, name,
2266 popr->is_array ? "[0]" : "");
2271 name = check_label_read_ref(po, popr->name, NULL);
2275 ferr(po, "lea an offset?\n");
2276 snprintf(buf, buf_size, "%s&%s", cast, name);
2281 ferr(po, "lea from const?\n");
2283 printf_number(tmp1, sizeof(tmp1), popr->val);
2284 if (popr->val == 0 && strchr(cast, '*'))
2285 snprintf(buf, buf_size, "NULL");
2287 snprintf(buf, buf_size, "%s%s",
2288 simplify_cast_num(cast, popr->val), tmp1);
2292 ferr(po, "invalid src type: %d\n", popr->type);
2298 // note: may set is_ptr (we find that out late for ebp frame..)
2299 static char *out_dst_opr(char *buf, size_t buf_size,
2300 struct parsed_op *po, struct parsed_opr *popr)
2302 check_opr(po, popr);
2304 switch (popr->type) {
2306 switch (popr->lmod) {
2308 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2311 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2315 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2319 if (popr->name[1] == 'h') // XXX..
2320 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2322 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2325 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2330 if (is_stack_access(po, popr)) {
2331 stack_frame_access(po, popr, buf, buf_size,
2332 popr->name, "", 0, 0);
2336 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2339 if (popr->size_mismatch)
2340 snprintf(buf, buf_size, "%s%s%s",
2341 lmod_cast_u_ptr(po, popr->lmod),
2342 popr->is_array ? "" : "&", popr->name);
2344 snprintf(buf, buf_size, "%s%s", popr->name,
2345 popr->is_array ? "[0]" : "");
2349 ferr(po, "invalid dst type: %d\n", popr->type);
2355 static char *out_src_opr_u32(char *buf, size_t buf_size,
2356 struct parsed_op *po, struct parsed_opr *popr)
2358 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2361 static char *out_opr_float(char *buf, size_t buf_size,
2362 struct parsed_op *po, struct parsed_opr *popr, int is_src,
2363 int need_float_stack)
2365 const char *cast = NULL;
2372 switch (popr->type) {
2374 if (popr->reg < xST0 || popr->reg > xST7) {
2376 ferr_assert(po, po->op == OP_PUSH);
2377 ferr_assert(po, popr->lmod == OPLM_DWORD);
2378 snprintf(buf, buf_size, "*(float *)&%s", opr_reg_p(po, popr));
2382 if (need_float_stack) {
2383 if (popr->reg == xST0)
2384 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2386 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2390 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2394 if (popr->lmod == OPLM_QWORD && is_stack_access(po, popr)) {
2395 stack_frame_access(po, popr, buf, buf_size,
2396 popr->name, "", is_src, 0);
2402 switch (popr->lmod) {
2410 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2413 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2414 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2418 // only for func float args pushes
2419 ferr_assert(po, po->op == OP_PUSH);
2420 u.i = po->operand[0].val;
2421 if (ceilf(u.f) == u.f)
2422 snprintf(buf, buf_size, "%.1ff", u.f);
2424 snprintf(buf, buf_size, "%.8ff", u.f);
2428 ferr(po, "invalid float type: %d\n", popr->type);
2434 static char *out_src_opr_float(char *buf, size_t buf_size,
2435 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2437 return out_opr_float(buf, buf_size, po, popr, 1, need_float_stack);
2440 static char *out_dst_opr_float(char *buf, size_t buf_size,
2441 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2443 return out_opr_float(buf, buf_size, po, popr, 0, need_float_stack);
2446 static void out_test_for_cc(char *buf, size_t buf_size,
2447 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2448 enum opr_lenmod lmod, const char *expr)
2450 const char *cast, *scast;
2452 cast = lmod_cast_u(po, lmod);
2453 scast = lmod_cast_s(po, lmod);
2457 case PFO_BE: // CF==1||ZF==1; CF=0
2458 snprintf(buf, buf_size, "(%s%s %s 0)",
2459 cast, expr, is_inv ? "!=" : "==");
2463 case PFO_L: // SF!=OF; OF=0
2464 snprintf(buf, buf_size, "(%s%s %s 0)",
2465 scast, expr, is_inv ? ">=" : "<");
2468 case PFO_LE: // ZF==1||SF!=OF; OF=0
2469 snprintf(buf, buf_size, "(%s%s %s 0)",
2470 scast, expr, is_inv ? ">" : "<=");
2475 snprintf(buf, buf_size, "(%d)", !!is_inv);
2478 case PFO_P: // PF==1
2479 snprintf(buf, buf_size, "(%sdo_parity(%s))",
2480 is_inv ? "!" : "", expr);
2484 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2488 static void out_cmp_for_cc(char *buf, size_t buf_size,
2489 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2492 const char *cast, *scast, *cast_use;
2493 char buf1[256], buf2[256];
2494 enum opr_lenmod lmod;
2496 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2497 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2498 po->operand[0].lmod, po->operand[1].lmod);
2499 lmod = po->operand[0].lmod;
2501 cast = lmod_cast_u(po, lmod);
2502 scast = lmod_cast_s(po, lmod);
2518 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2521 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2522 if (po->op == OP_DEC)
2523 snprintf(buf2, sizeof(buf2), "1");
2526 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2528 strcat(cast_op2, "-");
2529 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2534 // note: must be unsigned compare
2535 snprintf(buf, buf_size, "(%s %s %s)",
2536 buf1, is_inv ? ">=" : "<", buf2);
2540 snprintf(buf, buf_size, "(%s %s %s)",
2541 buf1, is_inv ? "!=" : "==", buf2);
2545 // note: must be unsigned compare
2546 snprintf(buf, buf_size, "(%s %s %s)",
2547 buf1, is_inv ? ">" : "<=", buf2);
2550 if (is_inv && lmod == OPLM_BYTE
2551 && po->operand[1].type == OPT_CONST
2552 && po->operand[1].val == 0xff)
2554 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2555 snprintf(buf, buf_size, "(0)");
2559 // note: must be signed compare
2561 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2562 scast, buf1, buf2, is_inv ? ">=" : "<");
2566 snprintf(buf, buf_size, "(%s %s %s)",
2567 buf1, is_inv ? ">=" : "<", buf2);
2571 snprintf(buf, buf_size, "(%s %s %s)",
2572 buf1, is_inv ? ">" : "<=", buf2);
2580 static void out_cmp_test(char *buf, size_t buf_size,
2581 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2583 char buf1[256], buf2[256], buf3[256];
2585 if (po->op == OP_TEST) {
2586 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2587 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2590 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2591 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2592 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2594 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2595 po->operand[0].lmod, buf3);
2597 else if (po->op == OP_CMP) {
2598 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2601 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2604 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2605 struct parsed_opr *popr2)
2607 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2608 ferr(po, "missing lmod for both operands\n");
2610 if (popr1->lmod == OPLM_UNSPEC)
2611 popr1->lmod = popr2->lmod;
2612 else if (popr2->lmod == OPLM_UNSPEC)
2613 popr2->lmod = popr1->lmod;
2614 else if (popr1->lmod != popr2->lmod) {
2615 if (popr1->type_from_var) {
2616 popr1->size_mismatch = 1;
2617 if (popr1->lmod < popr2->lmod)
2619 popr1->lmod = popr2->lmod;
2621 else if (popr2->type_from_var) {
2622 popr2->size_mismatch = 1;
2623 if (popr2->lmod < popr1->lmod)
2625 popr2->lmod = popr1->lmod;
2628 ferr(po, "conflicting lmods: %d vs %d\n",
2629 popr1->lmod, popr2->lmod);
2633 static const char *op_to_c(struct parsed_op *po)
2657 ferr(po, "op_to_c was supplied with %d\n", po->op);
2661 // last op in stream - unconditional branch or ret
2662 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2663 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2664 && ops[_i].op != OP_CALL))
2666 #define check_i(po, i) \
2668 ferr(po, "bad " #i ": %d\n", i)
2670 // note: this skips over calls and rm'd stuff assuming they're handled
2671 // so it's intended to use at one of final passes
2672 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2673 int depth, int seen_noreturn, int flags_set)
2675 struct parsed_op *po;
2680 for (; i < opcnt; i++) {
2682 if (po->cc_scratch == magic)
2683 return ret; // already checked
2684 po->cc_scratch = magic;
2686 if (po->flags & OPF_TAIL) {
2687 if (po->op == OP_CALL) {
2688 if (po->pp != NULL && po->pp->is_noreturn)
2697 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2700 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2701 if (po->btj != NULL) {
2703 for (j = 0; j < po->btj->count; j++) {
2704 check_i(po, po->btj->d[j].bt_i);
2705 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2706 depth, seen_noreturn, flags_set);
2708 return ret; // dead end
2713 check_i(po, po->bt_i);
2714 if (po->flags & OPF_CJMP) {
2715 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2716 depth, seen_noreturn, flags_set);
2718 return ret; // dead end
2727 if ((po->op == OP_POP || po->op == OP_PUSH)
2728 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2733 if (po->op == OP_PUSH) {
2736 else if (po->op == OP_POP) {
2737 if (relevant && depth == 0) {
2738 po->flags |= flags_set;
2746 // for noreturn, assume msvc skipped stack cleanup
2747 return seen_noreturn ? 1 : -1;
2750 // scan for 'reg' pop backwards starting from i
2751 // intended to use for register restore search, so other reg
2752 // references are considered an error
2753 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2755 struct parsed_op *po;
2756 struct label_ref *lr;
2759 ops[i].cc_scratch = magic;
2763 if (g_labels[i] != NULL) {
2764 lr = &g_label_refs[i];
2765 for (; lr != NULL; lr = lr->next) {
2766 check_i(&ops[i], lr->i);
2767 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2771 if (i > 0 && LAST_OP(i - 1))
2779 if (ops[i].cc_scratch == magic)
2781 ops[i].cc_scratch = magic;
2784 if (po->op == OP_POP && po->operand[0].reg == reg) {
2785 if (po->flags & (OPF_RMD|OPF_DONE))
2788 po->flags |= set_flags;
2792 // this also covers the case where we reach corresponding push
2793 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2797 // nothing interesting on this path,
2798 // still return ret for something recursive calls could find
2802 static void find_reachable_exits(int i, int opcnt, int magic,
2803 int *exits, int *exit_count)
2805 struct parsed_op *po;
2808 for (; i < opcnt; i++)
2811 if (po->cc_scratch == magic)
2813 po->cc_scratch = magic;
2815 if (po->flags & OPF_TAIL) {
2816 ferr_assert(po, *exit_count < MAX_EXITS);
2817 exits[*exit_count] = i;
2822 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2823 if (po->flags & OPF_RMD)
2826 if (po->btj != NULL) {
2827 for (j = 0; j < po->btj->count; j++) {
2828 check_i(po, po->btj->d[j].bt_i);
2829 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2835 check_i(po, po->bt_i);
2836 if (po->flags & OPF_CJMP)
2837 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2845 // scan for 'reg' pop backwards starting from exits (all paths)
2846 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2848 static int exits[MAX_EXITS];
2849 static int exit_count;
2855 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2857 ferr_assert(&ops[i], exit_count > 0);
2860 for (j = 0; j < exit_count; j++) {
2862 ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2868 if (ops[e].op == OP_CALL && ops[e].pp != NULL
2869 && ops[e].pp->is_noreturn)
2871 // assume stack cleanup was skipped
2880 // scan for one or more pop of push <const>
2881 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2882 int push_i, int is_probe)
2884 struct parsed_op *po;
2885 struct label_ref *lr;
2889 for (; i < opcnt; i++)
2892 if (po->cc_scratch == magic)
2893 return ret; // already checked
2894 po->cc_scratch = magic;
2896 if (po->flags & OPF_JMP) {
2897 if (po->flags & OPF_RMD)
2899 if (po->op == OP_CALL)
2902 if (po->btj != NULL) {
2903 for (j = 0; j < po->btj->count; j++) {
2904 check_i(po, po->btj->d[j].bt_i);
2905 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2913 check_i(po, po->bt_i);
2914 if (po->flags & OPF_CJMP) {
2915 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2926 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2929 if (g_labels[i] != NULL) {
2930 // all refs must be visited
2931 lr = &g_label_refs[i];
2932 for (; lr != NULL; lr = lr->next) {
2934 if (ops[lr->i].cc_scratch != magic)
2937 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2941 if (po->op == OP_POP)
2943 if (po->flags & (OPF_RMD|OPF_DONE))
2947 po->flags |= OPF_DONE;
2948 po->datap = &ops[push_i];
2957 static void scan_for_pop_const(int i, int opcnt, int magic)
2961 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2963 ops[i].flags |= OPF_RMD | OPF_DONE;
2964 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2968 // check if all branch targets within a marked path are also marked
2969 // note: the path checked must not be empty or end with a branch
2970 static int check_path_branches(int opcnt, int magic)
2972 struct parsed_op *po;
2975 for (i = 0; i < opcnt; i++) {
2977 if (po->cc_scratch != magic)
2980 if (po->flags & OPF_JMP) {
2981 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2984 if (po->btj != NULL) {
2985 for (j = 0; j < po->btj->count; j++) {
2986 check_i(po, po->btj->d[j].bt_i);
2987 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2992 check_i(po, po->bt_i);
2993 if (ops[po->bt_i].cc_scratch != magic)
2995 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
3003 // scan for multiple pushes for given pop
3004 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
3007 int reg = ops[pop_i].operand[0].reg;
3008 struct parsed_op *po;
3009 struct label_ref *lr;
3012 ops[i].cc_scratch = magic;
3016 if (g_labels[i] != NULL) {
3017 lr = &g_label_refs[i];
3018 for (; lr != NULL; lr = lr->next) {
3019 check_i(&ops[i], lr->i);
3020 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
3024 if (i > 0 && LAST_OP(i - 1))
3032 if (ops[i].cc_scratch == magic)
3034 ops[i].cc_scratch = magic;
3037 if (po->op == OP_CALL)
3039 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
3042 if (po->op == OP_PUSH)
3044 if (po->datap != NULL)
3046 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
3047 // leave this case for reg save/restore handlers
3051 po->flags |= OPF_PPUSH | OPF_DONE;
3052 po->datap = &ops[pop_i];
3061 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
3063 int magic = i + opcnt * 14;
3066 ret = scan_pushes_for_pop_r(i, magic, i, 1);
3068 ret = check_path_branches(opcnt, magic);
3070 ops[i].flags |= OPF_PPUSH | OPF_DONE;
3071 *regmask_pp |= 1 << ops[i].operand[0].reg;
3072 scan_pushes_for_pop_r(i, magic + 1, i, 0);
3077 static void scan_propagate_df(int i, int opcnt)
3079 struct parsed_op *po = &ops[i];
3082 for (; i < opcnt; i++) {
3084 if (po->flags & OPF_DF)
3085 return; // already resolved
3086 po->flags |= OPF_DF;
3088 if (po->op == OP_CALL)
3089 ferr(po, "call with DF set?\n");
3091 if (po->flags & OPF_JMP) {
3092 if (po->btj != NULL) {
3094 for (j = 0; j < po->btj->count; j++) {
3095 check_i(po, po->btj->d[j].bt_i);
3096 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
3101 if (po->flags & OPF_RMD)
3103 check_i(po, po->bt_i);
3104 if (po->flags & OPF_CJMP)
3105 scan_propagate_df(po->bt_i, opcnt);
3111 if (po->flags & OPF_TAIL)
3114 if (po->op == OP_CLD) {
3115 po->flags |= OPF_RMD | OPF_DONE;
3120 ferr(po, "missing DF clear?\n");
3123 // is operand 'opr' referenced by parsed_op 'po'?
3124 static int is_opr_referenced(const struct parsed_opr *opr,
3125 const struct parsed_op *po)
3129 if (opr->type == OPT_REG) {
3130 mask = po->regmask_dst | po->regmask_src;
3131 if (po->op == OP_CALL)
3132 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3133 if ((1 << opr->reg) & mask)
3139 for (i = 0; i < po->operand_cnt; i++)
3140 if (IS(po->operand[0].name, opr->name))
3146 // is operand 'opr' read by parsed_op 'po'?
3147 static int is_opr_read(const struct parsed_opr *opr,
3148 const struct parsed_op *po)
3150 if (opr->type == OPT_REG) {
3151 if (po->regmask_src & (1 << opr->reg))
3161 // is operand 'opr' modified by parsed_op 'po'?
3162 static int is_opr_modified(const struct parsed_opr *opr,
3163 const struct parsed_op *po)
3167 if (opr->type == OPT_REG) {
3168 if (po->op == OP_CALL) {
3169 mask = po->regmask_dst;
3170 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3171 if (mask & (1 << opr->reg))
3177 if (po->regmask_dst & (1 << opr->reg))
3183 return IS(po->operand[0].name, opr->name);
3186 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3187 static int is_any_opr_modified(const struct parsed_op *po_test,
3188 const struct parsed_op *po, int c_mode)
3193 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3196 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3199 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3202 // in reality, it can wreck any register, but in decompiled C
3203 // version it can only overwrite eax or edx:eax
3204 mask = (1 << xAX) | (1 << xDX);
3208 if (po->op == OP_CALL
3209 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3212 for (i = 0; i < po_test->operand_cnt; i++)
3213 if (IS(po_test->operand[i].name, po->operand[0].name))
3219 // scan for any po_test operand modification in range given
3220 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3223 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3226 for (; i < opcnt; i++) {
3227 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3234 // scan for po_test operand[0] modification in range given
3235 static int scan_for_mod_opr0(struct parsed_op *po_test,
3238 for (; i < opcnt; i++) {
3239 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3246 static int try_resolve_const(int i, const struct parsed_opr *opr,
3247 int magic, unsigned int *val);
3249 static int scan_for_flag_set(int i, int opcnt, int magic,
3250 int *branched, int *setters, int *setter_cnt)
3252 struct label_ref *lr;
3256 if (ops[i].cc_scratch == magic) {
3257 // is this a problem?
3258 //ferr(&ops[i], "%s looped\n", __func__);
3261 ops[i].cc_scratch = magic;
3263 if (g_labels[i] != NULL) {
3266 lr = &g_label_refs[i];
3267 for (; lr->next; lr = lr->next) {
3268 check_i(&ops[i], lr->i);
3269 ret = scan_for_flag_set(lr->i, opcnt, magic,
3270 branched, setters, setter_cnt);
3275 check_i(&ops[i], lr->i);
3276 if (i > 0 && LAST_OP(i - 1)) {
3280 ret = scan_for_flag_set(lr->i, opcnt, magic,
3281 branched, setters, setter_cnt);
3287 if (ops[i].flags & OPF_FLAGS) {
3288 setters[*setter_cnt] = i;
3291 if (ops[i].flags & OPF_REP) {
3292 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3295 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3296 if (ret != 1 || uval == 0) {
3297 // can't treat it as full setter because of ecx=0 case,
3298 // also disallow delayed compare
3307 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3314 // scan back for cdq, if anything modifies edx, fail
3315 static int scan_for_cdq_edx(int i)
3318 if (g_labels[i] != NULL) {
3319 if (g_label_refs[i].next != NULL)
3321 if (i > 0 && LAST_OP(i - 1)) {
3322 i = g_label_refs[i].i;
3329 if (ops[i].op == OP_CDQ)
3332 if (ops[i].regmask_dst & (1 << xDX))
3339 static int scan_for_reg_clear(int i, int reg)
3342 if (g_labels[i] != NULL) {
3343 if (g_label_refs[i].next != NULL)
3345 if (i > 0 && LAST_OP(i - 1)) {
3346 i = g_label_refs[i].i;
3353 if (ops[i].op == OP_XOR
3354 && ops[i].operand[0].lmod == OPLM_DWORD
3355 && ops[i].operand[0].reg == ops[i].operand[1].reg
3356 && ops[i].operand[0].reg == reg)
3359 if (ops[i].regmask_dst & (1 << reg))
3366 static void patch_esp_adjust(struct parsed_op *po, int adj)
3368 ferr_assert(po, po->op == OP_ADD);
3369 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3370 ferr_assert(po, po->operand[1].type == OPT_CONST);
3372 // this is a bit of a hack, but deals with use of
3373 // single adj for multiple calls
3374 po->operand[1].val -= adj;
3375 po->flags |= OPF_RMD;
3376 if (po->operand[1].val == 0)
3377 po->flags |= OPF_DONE;
3378 ferr_assert(po, (int)po->operand[1].val >= 0);
3381 // scan for positive, constant esp adjust
3382 // multipath case is preliminary
3383 static int scan_for_esp_adjust(int i, int opcnt,
3384 int adj_expect, int *adj, int *is_multipath, int do_update)
3386 int adj_expect_unknown = 0;
3387 struct parsed_op *po;
3391 *adj = *is_multipath = 0;
3392 if (adj_expect < 0) {
3393 adj_expect_unknown = 1;
3394 adj_expect = 32 * 4; // enough?
3397 for (; i < opcnt && *adj < adj_expect; i++) {
3398 if (g_labels[i] != NULL)
3402 if (po->flags & OPF_DONE)
3405 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3406 if (po->operand[1].type != OPT_CONST)
3407 ferr(&ops[i], "non-const esp adjust?\n");
3408 *adj += po->operand[1].val;
3410 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3413 patch_esp_adjust(po, adj_expect);
3415 po->flags |= OPF_RMD;
3419 else if (po->op == OP_PUSH) {
3420 //if (first_pop == -1)
3421 // first_pop = -2; // none
3422 *adj -= lmod_bytes(po, po->operand[0].lmod);
3424 else if (po->op == OP_POP) {
3425 if (!(po->flags & OPF_DONE)) {
3426 // seems like msvc only uses 'pop ecx' for stack realignment..
3427 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3429 if (first_pop == -1 && *adj >= 0)
3432 if (do_update && *adj >= 0) {
3433 po->flags |= OPF_RMD;
3435 po->flags |= OPF_DONE | OPF_NOREGS;
3438 *adj += lmod_bytes(po, po->operand[0].lmod);
3439 if (*adj > adj_best)
3442 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3443 if (po->op == OP_JMP && po->btj == NULL) {
3449 if (po->op != OP_CALL)
3451 if (po->operand[0].type != OPT_LABEL)
3453 if (po->pp != NULL && po->pp->is_stdcall)
3455 if (adj_expect_unknown && first_pop >= 0)
3457 // assume it's another cdecl call
3461 if (first_pop >= 0) {
3462 // probably only 'pop ecx' was used
3470 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3472 struct parsed_op *po;
3476 ferr(ops, "%s: followed bad branch?\n", __func__);
3478 for (; i < opcnt; i++) {
3480 if (po->cc_scratch == magic)
3482 po->cc_scratch = magic;
3485 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3486 if (po->btj != NULL) {
3488 for (j = 0; j < po->btj->count; j++)
3489 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3493 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3494 if (!(po->flags & OPF_CJMP))
3497 if (po->flags & OPF_TAIL)
3502 static const struct parsed_proto *try_recover_pp(
3503 struct parsed_op *po, const struct parsed_opr *opr,
3504 int is_call, int *search_instead)
3506 const struct parsed_proto *pp = NULL;
3510 // maybe an arg of g_func?
3511 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3513 char ofs_reg[16] = { 0, };
3514 int arg, arg_s, arg_i;
3521 parse_stack_access(po, opr->name, ofs_reg,
3522 &offset, &stack_ra, NULL, 0);
3523 if (ofs_reg[0] != 0)
3524 ferr(po, "offset reg on arg access?\n");
3525 if (offset <= stack_ra) {
3526 // search who set the stack var instead
3527 if (search_instead != NULL)
3528 *search_instead = 1;
3532 arg_i = (offset - stack_ra - 4) / 4;
3533 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3534 if (g_func_pp->arg[arg].reg != NULL)
3540 if (arg == g_func_pp->argc)
3541 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3543 pp = g_func_pp->arg[arg].pp;
3546 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3547 check_func_pp(po, pp, "icall arg");
3550 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3552 p = strchr(opr->name + 1, '[');
3553 memcpy(buf, opr->name, p - opr->name);
3554 buf[p - opr->name] = 0;
3555 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3557 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3558 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3561 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3564 check_func_pp(po, pp, "reg-fptr ref");
3570 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3571 int magic, const struct parsed_proto **pp_found, int *pp_i,
3574 const struct parsed_proto *pp = NULL;
3575 struct parsed_op *po;
3576 struct label_ref *lr;
3578 ops[i].cc_scratch = magic;
3581 if (g_labels[i] != NULL) {
3582 lr = &g_label_refs[i];
3583 for (; lr != NULL; lr = lr->next) {
3584 check_i(&ops[i], lr->i);
3585 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3587 if (i > 0 && LAST_OP(i - 1))
3595 if (ops[i].cc_scratch == magic)
3597 ops[i].cc_scratch = magic;
3599 if (!(ops[i].flags & OPF_DATA))
3601 if (!is_opr_modified(opr, &ops[i]))
3603 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3604 // most probably trashed by some processing
3609 opr = &ops[i].operand[1];
3610 if (opr->type != OPT_REG)
3614 po = (i >= 0) ? &ops[i] : ops;
3617 // reached the top - can only be an arg-reg
3618 if (opr->type != OPT_REG || g_func_pp == NULL)
3621 for (i = 0; i < g_func_pp->argc; i++) {
3622 if (g_func_pp->arg[i].reg == NULL)
3624 if (IS(opr->name, g_func_pp->arg[i].reg))
3627 if (i == g_func_pp->argc)
3629 pp = g_func_pp->arg[i].pp;
3631 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3632 i + 1, g_func_pp->arg[i].reg);
3633 check_func_pp(po, pp, "icall reg-arg");
3636 pp = try_recover_pp(po, opr, 1, NULL);
3638 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3639 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3640 || (*pp_found)->is_stdcall != pp->is_stdcall
3641 //|| (*pp_found)->is_fptr != pp->is_fptr
3642 || (*pp_found)->argc != pp->argc
3643 || (*pp_found)->argc_reg != pp->argc_reg
3644 || (*pp_found)->argc_stack != pp->argc_stack)
3646 ferr(po, "icall: parsed_proto mismatch\n");
3656 static void add_label_ref(struct label_ref *lr, int op_i)
3658 struct label_ref *lr_new;
3665 lr_new = calloc(1, sizeof(*lr_new));
3667 lr_new->next = lr->next;
3671 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3673 struct parsed_op *po = &ops[i];
3674 struct parsed_data *pd;
3675 char label[NAMELEN], *p;
3678 p = strchr(po->operand[0].name, '[');
3682 len = p - po->operand[0].name;
3683 strncpy(label, po->operand[0].name, len);
3686 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3687 if (IS(g_func_pd[j].label, label)) {
3693 //ferr(po, "label '%s' not parsed?\n", label);
3696 if (pd->type != OPT_OFFSET)
3697 ferr(po, "label '%s' with non-offset data?\n", label);
3699 // find all labels, link
3700 for (j = 0; j < pd->count; j++) {
3701 for (l = 0; l < opcnt; l++) {
3702 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3703 add_label_ref(&g_label_refs[l], i);
3713 static void clear_labels(int count)
3717 for (i = 0; i < count; i++) {
3718 if (g_labels[i] != NULL) {
3725 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3730 for (i = 0; i < pp->argc; i++) {
3731 if (pp->arg[i].reg != NULL) {
3732 reg = char_array_i(regs_r32,
3733 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3735 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3736 pp->arg[i].reg, pp->name);
3737 regmask |= 1 << reg;
3744 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3749 if (pp->has_retreg) {
3750 for (i = 0; i < pp->argc; i++) {
3751 if (pp->arg[i].type.is_retreg) {
3752 reg = char_array_i(regs_r32,
3753 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3754 ferr_assert(ops, reg >= 0);
3755 regmask |= 1 << reg;
3760 if (strstr(pp->ret_type.name, "int64"))
3761 return regmask | (1 << xAX) | (1 << xDX);
3762 if (IS(pp->ret_type.name, "float")
3763 || IS(pp->ret_type.name, "double"))
3765 return regmask | mxST0;
3767 if (strcasecmp(pp->ret_type.name, "void") == 0)
3770 return regmask | mxAX;
3773 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3775 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3776 && memcmp(po1->operand, po2->operand,
3777 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3780 static void resolve_branches_parse_calls(int opcnt)
3782 static const struct {
3786 unsigned int regmask_src;
3787 unsigned int regmask_dst;
3789 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3790 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3791 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3792 // more precise? Wine gets away with just __ftol handler
3793 { "__ftol2", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3794 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3796 const struct parsed_proto *pp_c;
3797 struct parsed_proto *pp;
3798 struct parsed_data *pd;
3799 struct parsed_op *po;
3800 const char *tmpname;
3805 for (i = 0; i < opcnt; i++)
3811 if (po->datap != NULL) {
3812 pp = calloc(1, sizeof(*pp));
3813 my_assert_not(pp, NULL);
3815 ret = parse_protostr(po->datap, pp);
3817 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3823 if (po->op == OP_CALL) {
3828 else if (po->operand[0].type == OPT_LABEL)
3830 tmpname = opr_name(po, 0);
3831 if (IS_START(tmpname, "loc_")) {
3833 ferr(po, "call to loc_*\n");
3834 // eliminate_seh() must take care of it
3837 if (IS(tmpname, "__alloca_probe"))
3839 if (IS(tmpname, "__SEH_prolog")) {
3840 ferr_assert(po, g_seh_found == 0);
3844 if (IS(tmpname, "__SEH_epilog"))
3847 // convert some calls to pseudo-ops
3848 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3849 if (!IS(tmpname, pseudo_ops[l].name))
3852 po->op = pseudo_ops[l].op;
3853 po->operand_cnt = 0;
3854 po->regmask_src = pseudo_ops[l].regmask_src;
3855 po->regmask_dst = pseudo_ops[l].regmask_dst;
3856 po->flags = pseudo_ops[l].flags;
3857 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3860 if (l < ARRAY_SIZE(pseudo_ops))
3863 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3864 if (!g_header_mode && pp_c == NULL)
3865 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3868 pp = proto_clone(pp_c);
3869 my_assert_not(pp, NULL);
3875 check_func_pp(po, pp, "fptr var call");
3876 if (pp->is_noreturn) {
3877 po->flags |= OPF_TAIL;
3878 po->flags &= ~OPF_ATAIL; // most likely...
3885 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3888 if (po->operand[0].type == OPT_REGMEM) {
3889 pd = try_resolve_jumptab(i, opcnt);
3897 for (l = 0; l < opcnt; l++) {
3898 if (g_labels[l] != NULL
3899 && IS(po->operand[0].name, g_labels[l]))
3901 if (l == i + 1 && po->op == OP_JMP) {
3902 // yet another alignment type..
3903 po->flags |= OPF_RMD|OPF_DONE;
3906 add_label_ref(&g_label_refs[l], i);
3912 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3915 if (po->operand[0].type == OPT_LABEL)
3919 ferr(po, "unhandled branch\n");
3923 po->flags |= OPF_TAIL;
3924 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3925 if (prev_op == OP_POP)
3926 po->flags |= OPF_ATAIL;
3927 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3928 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3930 po->flags |= OPF_ATAIL;
3936 static int resolve_origin(int i, const struct parsed_opr *opr,
3937 int magic, int *op_i, int *is_caller);
3938 static void set_label(int i, const char *name);
3940 static void eliminate_seh_writes(int opcnt)
3942 const struct parsed_opr *opr;
3947 // assume all sf writes above g_seh_size to be seh related
3948 // (probably unsafe but oh well)
3949 for (i = 0; i < opcnt; i++) {
3950 if (ops[i].op != OP_MOV)
3952 opr = &ops[i].operand[0];
3953 if (opr->type != OPT_REGMEM)
3955 if (!is_stack_access(&ops[i], opr))
3959 parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
3961 if (offset < 0 && offset >= -g_seh_size)
3962 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3966 static void eliminate_seh_finally(int opcnt)
3968 const char *target_name = NULL;
3969 const char *return_name = NULL;
3970 int exits[MAX_EXITS];
3978 for (i = 0; i < opcnt; i++) {
3979 if (ops[i].op != OP_CALL)
3981 if (!IS_START(opr_name(&ops[i], 0), "loc_"))
3983 if (target_name != NULL)
3984 ferr(&ops[i], "multiple finally calls? (last was %s)\n",
3986 target_name = opr_name(&ops[i], 0);
3989 if (g_labels[i + 1] == NULL)
3990 set_label(i + 1, "seh_fin_done");
3991 return_name = g_labels[i + 1];
3999 // find finally code (bt_i is not set because it's call)
4000 for (i = 0; i < opcnt; i++) {
4001 if (g_labels[i] == NULL)
4003 if (!IS(g_labels[i], target_name))
4006 ferr_assert(&ops[i], target_i == -1);
4009 ferr_assert(&ops[0], target_i != -1);
4011 find_reachable_exits(target_i, opcnt, target_i + opcnt * 24,
4012 exits, &exit_count);
4013 ferr_assert(&ops[target_i], exit_count == 1);
4014 ferr_assert(&ops[target_i], ops[exits[0]].op == OP_RET);
4017 // convert to jumps, link
4018 ops[call_i].op = OP_JMP;
4019 ops[call_i].bt_i = target_i;
4020 add_label_ref(&g_label_refs[target_i], call_i);
4022 ops[tgend_i].op = OP_JMP;
4023 ops[tgend_i].flags &= ~OPF_TAIL;
4024 ops[tgend_i].flags |= OPF_JMP;
4025 ops[tgend_i].bt_i = return_i;
4026 ops[tgend_i].operand_cnt = 1;
4027 ops[tgend_i].operand[0].type = OPT_LABEL;
4028 snprintf(ops[tgend_i].operand[0].name, NAMELEN, "%s", return_name);
4029 add_label_ref(&g_label_refs[return_i], tgend_i);
4031 // rm seh finally entry code
4032 for (i = target_i - 1; i >= 0; i--) {
4033 if (g_labels[i] != NULL && g_label_refs[i].i != -1)
4035 if (ops[i].flags & OPF_CJMP)
4037 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4040 for (i = target_i - 1; i >= 0; i--) {
4041 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4043 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4047 static void eliminate_seh(int opcnt)
4051 for (i = 0; i < opcnt; i++) {
4052 if (ops[i].op != OP_MOV)
4054 if (ops[i].operand[0].segment != SEG_FS)
4056 if (!IS(opr_name(&ops[i], 0), "0"))
4059 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4060 if (ops[i].operand[1].reg == xSP) {
4061 for (j = i - 1; j >= 0; j--) {
4062 if (ops[j].op != OP_PUSH)
4064 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4066 if (ops[j].operand[0].val == ~0)
4068 if (ops[j].operand[0].type == OPT_REG) {
4070 ret = resolve_origin(j, &ops[j].operand[0],
4071 j + opcnt * 22, &k, NULL);
4073 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4077 ferr(ops, "missing seh terminator\n");
4081 ret = resolve_origin(i, &ops[i].operand[1],
4082 i + opcnt * 23, &k, NULL);
4084 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4088 eliminate_seh_writes(opcnt);
4089 eliminate_seh_finally(opcnt);
4092 static void eliminate_seh_calls(int opcnt)
4094 int epilog_found = 0;
4101 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4102 && ops[i].operand[0].type == OPT_CONST);
4103 g_stack_fsz = g_seh_size + ops[i].operand[0].val;
4104 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4107 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4108 && ops[i].operand[0].type == OPT_OFFSET);
4109 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4112 ferr_assert(&ops[i], ops[i].op == OP_CALL
4113 && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
4114 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4116 for (i++; i < opcnt; i++) {
4117 if (ops[i].op != OP_CALL)
4119 if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
4122 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4125 ferr_assert(ops, epilog_found);
4127 eliminate_seh_writes(opcnt);
4128 eliminate_seh_finally(opcnt);
4131 static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4135 for (; i < opcnt; i++)
4136 if (!(ops[i].flags & OPF_DONE))
4139 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4140 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4146 for (; i < opcnt; i++) {
4147 if (i > 0 && g_labels[i] != NULL)
4149 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
4151 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4152 && ops[i].operand[1].type == OPT_CONST)
4154 g_stack_fsz += opr_const(&ops[i], 1);
4155 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4160 if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4161 && ops[i].operand[1].type == OPT_CONST)
4163 for (j = i + 1; j < opcnt; j++)
4164 if (!(ops[j].flags & OPF_DONE))
4166 if (ops[j].op == OP_CALL
4167 && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4169 g_stack_fsz += opr_const(&ops[i], 1);
4170 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4171 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4182 static void scan_prologue_epilogue(int opcnt, int *stack_align)
4184 int ecx_push = 0, esp_sub = 0, pusha = 0;
4185 int sandard_epilogue;
4189 if (g_seh_found == 2) {
4190 eliminate_seh_calls(opcnt);
4194 eliminate_seh(opcnt);
4195 // ida treats seh as part of sf
4196 g_stack_fsz = g_seh_size;
4200 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4201 && ops[1].op == OP_MOV
4202 && IS(opr_name(&ops[1], 0), "ebp")
4203 && IS(opr_name(&ops[1], 1), "esp"))
4206 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4207 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4209 for (i = 2; i < opcnt; i++)
4210 if (!(ops[i].flags & OPF_DONE))
4213 if (ops[i].op == OP_PUSHA) {
4214 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4219 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4220 && ops[i].operand[1].type == OPT_CONST)
4222 l = ops[i].operand[1].val;
4224 if (j == -1 || (l >> j) != -1)
4225 ferr(&ops[i], "unhandled esp align: %x\n", l);
4226 if (stack_align != NULL)
4227 *stack_align = 1 << j;
4228 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4232 i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4236 for (; i < opcnt; i++)
4237 if (ops[i].flags & OPF_TAIL)
4240 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4241 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4247 sandard_epilogue = 0;
4248 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4250 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4251 // the standard epilogue is sometimes even used without a sf
4252 if (ops[j - 1].op == OP_MOV
4253 && IS(opr_name(&ops[j - 1], 0), "esp")
4254 && IS(opr_name(&ops[j - 1], 1), "ebp"))
4255 sandard_epilogue = 1;
4257 else if (ops[j].op == OP_LEAVE)
4259 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4260 sandard_epilogue = 1;
4262 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4263 && ops[i].pp->is_noreturn)
4265 // on noreturn, msvc sometimes cleans stack, sometimes not
4270 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4271 ferr(&ops[j], "'pop ebp' expected\n");
4273 if (g_stack_fsz != 0 || sandard_epilogue) {
4274 if (ops[j].op == OP_LEAVE)
4276 else if (sandard_epilogue) // mov esp, ebp
4278 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4281 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4283 ferr(&ops[j], "esp restore expected\n");
4286 if (ecx_push && j >= 0 && ops[j].op == OP_POP
4287 && IS(opr_name(&ops[j], 0), "ecx"))
4289 ferr(&ops[j], "unexpected ecx pop\n");
4294 if (ops[j].op == OP_POPA)
4295 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4297 ferr(&ops[j], "popa expected\n");
4302 } while (i < opcnt);
4305 ferr(ops, "missing ebp epilogue\n");
4310 i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4312 if (ecx_push && !esp_sub) {
4313 // could actually be args for a call..
4314 for (; i < opcnt; i++)
4315 if (ops[i].op != OP_PUSH)
4318 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4319 const struct parsed_proto *pp;
4320 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4321 j = pp ? pp->argc_stack : 0;
4322 while (i > 0 && j > 0) {
4324 if (ops[i].op == OP_PUSH) {
4325 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4330 ferr(&ops[i], "unhandled prologue\n");
4334 g_stack_fsz = g_seh_size;
4335 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4336 if (!(ops[i].flags & OPF_RMD))
4346 if (ecx_push || esp_sub)
4351 for (; i < opcnt; i++)
4352 if (ops[i].flags & OPF_TAIL)
4356 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4357 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4362 else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4363 // skip arg updates for arg-reuse tailcall
4364 for (; j >= 0; j--) {
4365 if (ops[j].op != OP_MOV)
4367 if (ops[j].operand[0].type != OPT_REGMEM)
4369 if (strstr(ops[j].operand[0].name, "arg_") == NULL)
4374 if (ecx_push > 0 && !esp_sub) {
4375 for (l = 0; l < ecx_push && j >= 0; l++) {
4376 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4378 else if (ops[j].op == OP_ADD
4379 && IS(opr_name(&ops[j], 0), "esp")
4380 && ops[j].operand[1].type == OPT_CONST)
4383 l += ops[j].operand[1].val / 4 - 1;
4388 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4391 if (l != ecx_push) {
4392 if (i < opcnt && ops[i].op == OP_CALL
4393 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4395 // noreturn tailcall with no epilogue
4400 ferr(&ops[j], "epilogue scan failed\n");
4407 if (ops[j].op != OP_ADD
4408 || !IS(opr_name(&ops[j], 0), "esp")
4409 || ops[j].operand[1].type != OPT_CONST)
4411 if (i < opcnt && ops[i].op == OP_CALL
4412 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4414 // noreturn tailcall with no epilogue
4419 ferr(&ops[j], "'add esp' expected\n");
4422 if (ops[j].operand[1].val < g_stack_fsz)
4423 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4425 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4426 if (ops[j].operand[1].val == 0)
4427 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4432 } while (i < opcnt);
4435 ferr(ops, "missing esp epilogue\n");
4439 // find an instruction that changed opr before i op
4440 // *op_i must be set to -1 by the caller
4441 // *is_caller is set to 1 if one source is determined to be g_func arg
4442 // returns 1 if found, *op_i is then set to origin
4443 // returns -1 if multiple origins are found
4444 static int resolve_origin(int i, const struct parsed_opr *opr,
4445 int magic, int *op_i, int *is_caller)
4447 struct label_ref *lr;
4451 if (g_labels[i] != NULL) {
4452 lr = &g_label_refs[i];
4453 for (; lr != NULL; lr = lr->next) {
4454 check_i(&ops[i], lr->i);
4455 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4457 if (i > 0 && LAST_OP(i - 1))
4463 if (is_caller != NULL)
4468 if (ops[i].cc_scratch == magic)
4470 ops[i].cc_scratch = magic;
4472 if (!(ops[i].flags & OPF_DATA))
4474 if (!is_opr_modified(opr, &ops[i]))
4478 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4489 // find an instruction that previously referenced opr
4490 // if multiple results are found - fail
4491 // *op_i must be set to -1 by the caller
4492 // returns 1 if found, *op_i is then set to referencer insn
4493 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4494 int magic, int *op_i)
4496 struct label_ref *lr;
4500 if (g_labels[i] != NULL) {
4501 lr = &g_label_refs[i];
4502 for (; lr != NULL; lr = lr->next) {
4503 check_i(&ops[i], lr->i);
4504 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4506 if (i > 0 && LAST_OP(i - 1))
4514 if (ops[i].cc_scratch == magic)
4516 ops[i].cc_scratch = magic;
4518 if (!is_opr_referenced(opr, &ops[i]))
4529 // adjust datap of all reachable 'op' insns when moving back
4530 // returns 1 if at least 1 op was found
4531 // returns -1 if path without an op was found
4532 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4534 struct label_ref *lr;
4537 if (ops[i].cc_scratch == magic)
4539 ops[i].cc_scratch = magic;
4542 if (g_labels[i] != NULL) {
4543 lr = &g_label_refs[i];
4544 for (; lr != NULL; lr = lr->next) {
4545 check_i(&ops[i], lr->i);
4546 ret |= adjust_prev_op(lr->i, op, magic, datap);
4548 if (i > 0 && LAST_OP(i - 1))
4556 if (ops[i].cc_scratch == magic)
4558 ops[i].cc_scratch = magic;
4560 if (ops[i].op != op)
4563 ops[i].datap = datap;
4568 // find next instruction that reads opr
4569 // *op_i must be set to -1 by the caller
4570 // on return, *op_i is set to first referencer insn
4571 // returns 1 if exactly 1 referencer is found
4572 static int find_next_read(int i, int opcnt,
4573 const struct parsed_opr *opr, int magic, int *op_i)
4575 struct parsed_op *po;
4578 for (; i < opcnt; i++)
4580 if (ops[i].cc_scratch == magic)
4582 ops[i].cc_scratch = magic;
4585 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4586 if (po->btj != NULL) {
4588 for (j = 0; j < po->btj->count; j++) {
4589 check_i(po, po->btj->d[j].bt_i);
4590 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4596 if (po->flags & OPF_RMD)
4598 check_i(po, po->bt_i);
4599 if (po->flags & OPF_CJMP) {
4600 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4609 if (!is_opr_read(opr, po)) {
4611 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4612 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4614 full_opr = po->operand[0].lmod >= opr->lmod;
4616 if (is_opr_modified(opr, po) && full_opr) {
4620 if (po->flags & OPF_TAIL)
4635 // find next instruction that reads opr
4636 // *op_i must be set to -1 by the caller
4637 // on return, *op_i is set to first flag user insn
4638 // returns 1 if exactly 1 flag user is found
4639 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4641 struct parsed_op *po;
4644 for (; i < opcnt; i++)
4646 if (ops[i].cc_scratch == magic)
4648 ops[i].cc_scratch = magic;
4651 if (po->op == OP_CALL)
4653 if (po->flags & OPF_JMP) {
4654 if (po->btj != NULL) {
4656 for (j = 0; j < po->btj->count; j++) {
4657 check_i(po, po->btj->d[j].bt_i);
4658 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4664 if (po->flags & OPF_RMD)
4666 check_i(po, po->bt_i);
4667 if (po->flags & OPF_CJMP)
4674 if (!(po->flags & OPF_CC)) {
4675 if (po->flags & OPF_FLAGS)
4678 if (po->flags & OPF_TAIL)
4694 static int try_resolve_const(int i, const struct parsed_opr *opr,
4695 int magic, unsigned int *val)
4700 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4703 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4706 *val = ops[i].operand[1].val;
4713 static int resolve_used_bits(int i, int opcnt, int reg,
4714 int *mask, int *is_z_check)
4716 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4720 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4724 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4726 fnote(&ops[j], "(first read)\n");
4727 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4730 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4731 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4733 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4734 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4736 *mask = ops[j].operand[1].val;
4737 if (ops[j].operand[0].lmod == OPLM_BYTE
4738 && ops[j].operand[0].name[1] == 'h')
4742 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4745 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4747 *is_z_check = ops[k].pfo == PFO_Z;
4752 static const struct parsed_proto *resolve_deref(int i, int magic,
4753 struct parsed_opr *opr, int level)
4755 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4756 const struct parsed_proto *pp = NULL;
4757 int from_caller = 0;
4766 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4767 if (ret != 2 || len != strlen(opr->name)) {
4768 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4769 if (ret != 1 || len != strlen(opr->name))
4773 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4778 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4782 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4783 && strlen(ops[j].operand[1].name) == 3
4784 && ops[j].operand[0].lmod == OPLM_DWORD
4785 && ops[j].pp == NULL // no hint
4788 // allow one simple dereference (com/directx)
4789 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4790 ops[j].operand[1].name);
4794 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4799 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4802 if (ops[j].pp != NULL) {
4806 else if (ops[j].operand[1].type == OPT_REGMEM) {
4807 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4809 // maybe structure ptr in structure
4810 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4813 else if (ops[j].operand[1].type == OPT_LABEL)
4814 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4815 else if (ops[j].operand[1].type == OPT_REG) {
4818 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4820 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4821 for (k = 0; k < g_func_pp->argc; k++) {
4822 if (g_func_pp->arg[k].reg == NULL)
4824 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4825 pp = g_func_pp->arg[k].pp;
4834 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4836 ferr(&ops[j], "expected struct, got '%s %s'\n",
4837 pp->type.name, pp->name);
4841 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4844 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4845 int *pp_i, int *multi_src)
4847 const struct parsed_proto *pp = NULL;
4848 int search_advice = 0;
4853 switch (ops[i].operand[0].type) {
4855 // try to resolve struct member calls
4856 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4862 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4868 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4876 static struct parsed_proto *process_call_early(int i, int opcnt,
4879 struct parsed_op *po = &ops[i];
4880 struct parsed_proto *pp;
4886 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4890 // look for and make use of esp adjust
4892 if (!pp->is_stdcall && pp->argc_stack > 0)
4893 ret = scan_for_esp_adjust(i + 1, opcnt,
4894 pp->argc_stack * 4, &adj, &multipath, 0);
4896 if (pp->argc_stack > adj / 4)
4900 if (ops[ret].op == OP_POP) {
4901 for (j = 1; j < adj / 4; j++) {
4902 if (ops[ret + j].op != OP_POP
4903 || ops[ret + j].operand[0].reg != xCX)
4915 static struct parsed_proto *process_call(int i, int opcnt)
4917 struct parsed_op *po = &ops[i];
4918 const struct parsed_proto *pp_c;
4919 struct parsed_proto *pp;
4920 const char *tmpname;
4921 int call_i = -1, ref_i = -1;
4922 int adj = 0, multipath = 0;
4925 tmpname = opr_name(po, 0);
4930 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4932 if (!pp_c->is_func && !pp_c->is_fptr)
4933 ferr(po, "call to non-func: %s\n", pp_c->name);
4934 pp = proto_clone(pp_c);
4935 my_assert_not(pp, NULL);
4937 // not resolved just to single func
4940 switch (po->operand[0].type) {
4942 // we resolved this call and no longer need the register
4943 po->regmask_src &= ~(1 << po->operand[0].reg);
4945 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4946 && ops[call_i].operand[1].type == OPT_LABEL)
4948 // no other source users?
4949 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4951 if (ret == 1 && call_i == ref_i) {
4952 // and nothing uses it after us?
4954 find_next_read(i + 1, opcnt, &po->operand[0],
4955 i + opcnt * 11, &ref_i);
4957 // then also don't need the source mov
4958 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4970 pp = calloc(1, sizeof(*pp));
4971 my_assert_not(pp, NULL);
4974 ret = scan_for_esp_adjust(i + 1, opcnt,
4975 -1, &adj, &multipath, 0);
4976 if (ret < 0 || adj < 0) {
4977 if (!g_allow_regfunc)
4978 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4979 pp->is_unresolved = 1;
4983 if (adj > ARRAY_SIZE(pp->arg))
4984 ferr(po, "esp adjust too large: %d\n", adj);
4985 pp->ret_type.name = strdup("int");
4986 pp->argc = pp->argc_stack = adj;
4987 for (arg = 0; arg < pp->argc; arg++)
4988 pp->arg[arg].type.name = strdup("int");
4993 // look for and make use of esp adjust
4996 if (!pp->is_stdcall && pp->argc_stack > 0) {
4997 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4998 ret = scan_for_esp_adjust(i + 1, opcnt,
4999 adj_expect, &adj, &multipath, 0);
5002 if (pp->is_vararg) {
5003 if (adj / 4 < pp->argc_stack) {
5004 fnote(po, "(this call)\n");
5005 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
5006 adj, pp->argc_stack * 4);
5008 // modify pp to make it have varargs as normal args
5010 pp->argc += adj / 4 - pp->argc_stack;
5011 for (; arg < pp->argc; arg++) {
5012 pp->arg[arg].type.name = strdup("int");
5015 if (pp->argc > ARRAY_SIZE(pp->arg))
5016 ferr(po, "too many args for '%s'\n", tmpname);
5018 if (pp->argc_stack > adj / 4) {
5019 if (pp->is_noreturn)
5020 // assume no stack adjust was emited
5022 fnote(po, "(this call)\n");
5023 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
5024 tmpname, pp->argc_stack * 4, adj);
5027 scan_for_esp_adjust(i + 1, opcnt,
5028 pp->argc_stack * 4, &adj, &multipath, 1);
5030 else if (pp->is_vararg)
5031 ferr(po, "missing esp_adjust for vararg func '%s'\n",
5038 static void mark_float_arg(struct parsed_op *po,
5039 struct parsed_proto *pp, int arg, int *regmask_ffca)
5042 po->p_argnum = arg + 1;
5043 ferr_assert(po, pp->arg[arg].datap == NULL);
5044 pp->arg[arg].datap = po;
5045 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
5046 if (regmask_ffca != NULL)
5047 *regmask_ffca |= 1 << arg;
5050 static int check_for_stp(int i, int i_to)
5052 struct parsed_op *po;
5054 for (; i < i_to; i++) {
5056 if (po->op == OP_FST)
5058 if (g_labels[i] != NULL || (po->flags & OPF_JMP))
5060 if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
5062 if (po->op == OP_ADD && po->operand[0].reg == xSP)
5069 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
5072 struct parsed_op *po;
5078 for (base_arg = 0; base_arg < pp->argc; base_arg++)
5079 if (pp->arg[base_arg].reg == NULL)
5082 for (j = i; j > 0; )
5084 ferr_assert(&ops[j], g_labels[j] == NULL);
5088 ferr_assert(po, po->op != OP_PUSH);
5089 if (po->op == OP_FST)
5091 if (po->operand[0].type != OPT_REGMEM)
5093 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
5096 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
5097 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
5101 arg = base_arg + offset / 4;
5102 mark_float_arg(po, pp, arg, regmask_ffca);
5104 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5105 && po->operand[1].type == OPT_CONST)
5107 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5112 for (arg = base_arg; arg < pp->argc; arg++) {
5113 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
5114 po = pp->arg[arg].datap;
5116 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
5117 if (po->operand[0].lmod == OPLM_QWORD)
5124 static int collect_call_args_early(int i, struct parsed_proto *pp,
5125 int *regmask, int *regmask_ffca)
5127 struct parsed_op *po;
5132 for (arg = 0; arg < pp->argc; arg++)
5133 if (pp->arg[arg].reg == NULL)
5136 // first see if it can be easily done
5137 for (j = i; j > 0 && arg < pp->argc; )
5139 if (g_labels[j] != NULL)
5144 if (po->op == OP_CALL)
5146 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
5148 else if (po->op == OP_POP)
5150 else if (po->flags & OPF_CJMP)
5152 else if (po->op == OP_PUSH) {
5153 if (po->flags & (OPF_FARG|OPF_FARGNR))
5155 if (!g_header_mode) {
5156 ret = scan_for_mod(po, j + 1, i, 1);
5161 if (pp->arg[arg].type.is_va_list)
5165 for (arg++; arg < pp->argc; arg++)
5166 if (pp->arg[arg].reg == NULL)
5169 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5170 && po->operand[1].type == OPT_CONST)
5172 if (po->flags & (OPF_RMD|OPF_DONE))
5174 if (po->operand[1].val != pp->argc_stack * 4)
5175 ferr(po, "unexpected esp adjust: %d\n",
5176 po->operand[1].val * 4);
5177 ferr_assert(po, pp->argc - arg == pp->argc_stack);
5178 return collect_call_args_no_push(i, pp, regmask_ffca);
5186 for (arg = 0; arg < pp->argc; arg++)
5187 if (pp->arg[arg].reg == NULL)
5190 for (j = i; j > 0 && arg < pp->argc; )
5194 if (ops[j].op == OP_PUSH)
5196 ops[j].p_argnext = -1;
5197 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
5199 k = check_for_stp(j + 1, i);
5201 // push ecx; fstp dword ptr [esp]
5202 ret = parse_stack_esp_offset(&ops[k],
5203 ops[k].operand[0].name, &offset);
5204 if (ret == 0 && offset == 0) {
5205 if (!pp->arg[arg].type.is_float)
5206 ferr(&ops[i], "arg %d should be float\n", arg + 1);
5207 mark_float_arg(&ops[k], pp, arg, regmask_ffca);
5211 if (pp->arg[arg].datap == NULL) {
5212 pp->arg[arg].datap = &ops[j];
5213 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5214 *regmask |= 1 << ops[j].operand[0].reg;
5217 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5218 ops[j].flags &= ~OPF_RSAVE;
5221 for (arg++; arg < pp->argc; arg++)
5222 if (pp->arg[arg].reg == NULL)
5230 static int sync_argnum(struct parsed_op *po, int argnum)
5232 struct parsed_op *po_tmp;
5234 // see if other branches don't have higher argnum
5235 for (po_tmp = po; po_tmp != NULL; ) {
5236 if (argnum < po_tmp->p_argnum)
5237 argnum = po_tmp->p_argnum;
5238 // note: p_argnext is active on current collect_call_args only
5239 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5242 // make all argnums consistent
5243 for (po_tmp = po; po_tmp != NULL; ) {
5244 if (po_tmp->p_argnum != 0)
5245 po_tmp->p_argnum = argnum;
5246 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5252 static int collect_call_args_r(struct parsed_op *po, int i,
5253 struct parsed_proto *pp, int *regmask, int *arg_grp,
5254 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
5256 struct parsed_proto *pp_tmp;
5257 struct parsed_op *po_tmp;
5258 struct label_ref *lr;
5259 int need_to_save_current;
5260 int arg_grp_current = 0;
5261 int save_args_seen = 0;
5268 ferr(po, "dead label encountered\n");
5272 for (; arg < pp->argc; arg++, argnum++)
5273 if (pp->arg[arg].reg == NULL)
5275 magic = (magic & 0xffffff) | (arg << 24);
5277 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5279 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5280 if (ops[j].cc_scratch != magic) {
5281 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5285 // ok: have already been here
5288 ops[j].cc_scratch = magic;
5290 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5291 lr = &g_label_refs[j];
5292 if (lr->next != NULL)
5294 for (; lr->next; lr = lr->next) {
5295 check_i(&ops[j], lr->i);
5296 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5298 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5299 arg, argnum, magic, need_op_saving, may_reuse);
5304 check_i(&ops[j], lr->i);
5305 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5307 if (j > 0 && LAST_OP(j - 1)) {
5308 // follow last branch in reverse
5313 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5314 arg, argnum, magic, need_op_saving, may_reuse);
5320 if (ops[j].op == OP_CALL)
5322 if (pp->is_unresolved)
5327 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5328 arg, pp->argc, ops[j].operand[0].name);
5329 if (may_reuse && pp_tmp->argc_stack > 0)
5330 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5331 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5333 // esp adjust of 0 means we collected it before
5334 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5335 && (ops[j].operand[1].type != OPT_CONST
5336 || ops[j].operand[1].val != 0))
5338 if (pp->is_unresolved)
5341 fnote(po, "(this call)\n");
5342 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5343 arg, pp->argc, ops[j].operand[1].val);
5345 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5347 if (pp->is_unresolved)
5350 fnote(po, "(this call)\n");
5351 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5353 else if (ops[j].flags & OPF_CJMP)
5355 if (pp->is_unresolved)
5360 else if (ops[j].op == OP_PUSH
5361 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5363 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5366 ops[j].p_argnext = -1;
5367 po_tmp = pp->arg[arg].datap;
5369 ops[j].p_argnext = po_tmp - ops;
5370 pp->arg[arg].datap = &ops[j];
5372 argnum = sync_argnum(&ops[j], argnum);
5374 need_to_save_current = 0;
5376 if (ops[j].operand[0].type == OPT_REG)
5377 reg = ops[j].operand[0].reg;
5379 if (!need_op_saving) {
5380 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5381 need_to_save_current = (ret >= 0);
5383 if (need_op_saving || need_to_save_current) {
5384 // mark this arg as one that needs operand saving
5385 pp->arg[arg].is_saved = 1;
5387 if (save_args_seen & (1 << (argnum - 1))) {
5390 if (arg_grp_current >= MAX_ARG_GRP)
5391 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5395 else if (ops[j].p_argnum == 0)
5396 ops[j].flags |= OPF_RMD;
5398 // some PUSHes are reused by different calls on other branches,
5399 // but that can't happen if we didn't branch, so they
5400 // can be removed from future searches (handles nested calls)
5402 ops[j].flags |= OPF_FARGNR;
5404 ops[j].flags |= OPF_FARG;
5405 ops[j].flags &= ~OPF_RSAVE;
5407 // check for __VALIST
5408 if (!pp->is_unresolved && g_func_pp != NULL
5409 && pp->arg[arg].type.is_va_list)
5412 ret = resolve_origin(j, &ops[j].operand[0],
5413 magic + 1, &k, NULL);
5414 if (ret == 1 && k >= 0)
5416 if (ops[k].op == OP_LEA) {
5417 if (!g_func_pp->is_vararg)
5418 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5421 snprintf(buf, sizeof(buf), "arg_%X",
5422 g_func_pp->argc_stack * 4);
5423 if (strstr(ops[k].operand[1].name, buf)
5424 || strstr(ops[k].operand[1].name, "arglist"))
5426 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5427 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5428 pp->arg[arg].is_saved = 0;
5432 ferr(&ops[k], "va_list arg detection failed\n");
5434 // check for va_list from g_func_pp arg too
5435 else if (ops[k].op == OP_MOV
5436 && is_stack_access(&ops[k], &ops[k].operand[1]))
5438 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5439 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5441 ops[k].flags |= OPF_RMD | OPF_DONE;
5442 ops[j].flags |= OPF_RMD;
5443 ops[j].p_argpass = ret + 1;
5444 pp->arg[arg].is_saved = 0;
5451 if (pp->arg[arg].is_saved) {
5452 ops[j].flags &= ~OPF_RMD;
5453 ops[j].p_argnum = argnum;
5456 // tracking reg usage
5458 *regmask |= 1 << reg;
5462 if (!pp->is_unresolved) {
5464 for (; arg < pp->argc; arg++, argnum++)
5465 if (pp->arg[arg].reg == NULL)
5468 magic = (magic & 0xffffff) | (arg << 24);
5471 if (ops[j].p_arggrp > arg_grp_current) {
5473 arg_grp_current = ops[j].p_arggrp;
5475 if (ops[j].p_argnum > 0)
5476 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5479 if (arg < pp->argc) {
5480 ferr(po, "arg collect failed for '%s': %d/%d\n",
5481 pp->name, arg, pp->argc);
5485 if (arg_grp_current > *arg_grp)
5486 *arg_grp = arg_grp_current;
5491 static int collect_call_args(struct parsed_op *po, int i,
5492 struct parsed_proto *pp, int *regmask, int magic)
5494 // arg group is for cases when pushes for
5495 // multiple funcs are going on
5496 struct parsed_op *po_tmp;
5501 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5507 // propagate arg_grp
5508 for (a = 0; a < pp->argc; a++) {
5509 if (pp->arg[a].reg != NULL)
5512 po_tmp = pp->arg[a].datap;
5513 while (po_tmp != NULL) {
5514 po_tmp->p_arggrp = arg_grp;
5515 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5520 if (pp->is_unresolved) {
5522 pp->argc_stack += ret;
5523 for (a = 0; a < pp->argc; a++)
5524 if (pp->arg[a].type.name == NULL)
5525 pp->arg[a].type.name = strdup("int");
5531 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5532 int regmask_now, int *regmask,
5533 int regmask_save_now, int *regmask_save,
5534 int *regmask_init, int regmask_arg)
5536 struct parsed_op *po;
5544 for (; i < opcnt; i++)
5547 if (cbits[i >> 3] & (1 << (i & 7)))
5549 cbits[i >> 3] |= (1 << (i & 7));
5551 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5552 if (po->flags & (OPF_RMD|OPF_DONE))
5554 if (po->btj != NULL) {
5555 for (j = 0; j < po->btj->count; j++) {
5556 check_i(po, po->btj->d[j].bt_i);
5557 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5558 regmask_now, regmask, regmask_save_now, regmask_save,
5559 regmask_init, regmask_arg);
5564 check_i(po, po->bt_i);
5565 if (po->flags & OPF_CJMP)
5566 reg_use_pass(po->bt_i, opcnt, cbits,
5567 regmask_now, regmask, regmask_save_now, regmask_save,
5568 regmask_init, regmask_arg);
5574 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5575 && !g_func_pp->is_userstack
5576 && po->operand[0].type == OPT_REG)
5578 reg = po->operand[0].reg;
5579 ferr_assert(po, reg >= 0);
5582 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5583 if (regmask_now & (1 << reg)) {
5584 already_saved = regmask_save_now & (1 << reg);
5585 flags_set = OPF_RSAVE | OPF_DONE;
5588 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5590 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5591 reg, 0, 0, flags_set);
5594 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5596 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5601 ferr_assert(po, !already_saved);
5602 po->flags |= flags_set;
5604 if (regmask_now & (1 << reg)) {
5605 regmask_save_now |= (1 << reg);
5606 *regmask_save |= regmask_save_now;
5611 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5612 reg = po->operand[0].reg;
5613 ferr_assert(po, reg >= 0);
5615 if (regmask_save_now & (1 << reg))
5616 regmask_save_now &= ~(1 << reg);
5618 regmask_now &= ~(1 << reg);
5621 else if (po->op == OP_CALL) {
5622 if ((po->regmask_dst & (1 << xAX))
5623 && !(po->regmask_dst & (1 << xDX)))
5625 if (po->flags & OPF_TAIL)
5626 // don't need eax, will do "return f();" or "f(); return;"
5627 po->regmask_dst &= ~(1 << xAX);
5629 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5631 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5634 po->regmask_dst &= ~(1 << xAX);
5638 // not "full stack" mode and have something in stack
5639 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5640 ferr(po, "float stack is not empty on func call\n");
5643 if (po->flags & OPF_NOREGS)
5646 // if incomplete register is used, clear it on init to avoid
5647 // later use of uninitialized upper part in some situations
5648 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5649 && po->operand[0].lmod != OPLM_DWORD)
5651 reg = po->operand[0].reg;
5652 ferr_assert(po, reg >= 0);
5654 if (!(regmask_now & (1 << reg)))
5655 *regmask_init |= 1 << reg;
5658 regmask_op = po->regmask_src | po->regmask_dst;
5660 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5661 regmask_new &= ~(1 << xSP);
5662 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5663 regmask_new &= ~(1 << xBP);
5665 if (regmask_new != 0)
5666 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5668 if (regmask_op & (1 << xBP)) {
5669 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5670 if (po->regmask_dst & (1 << xBP))
5671 // compiler decided to drop bp frame and use ebp as scratch
5672 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5674 regmask_op &= ~(1 << xBP);
5678 if (po->flags & OPF_FPUSH) {
5679 if (regmask_now & mxST1)
5680 regmask_now |= mxSTa; // switch to "full stack" mode
5681 if (regmask_now & mxSTa)
5682 po->flags |= OPF_FSHIFT;
5683 if (!(regmask_now & mxST7_2)) {
5685 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5689 regmask_now |= regmask_op;
5690 *regmask |= regmask_now;
5693 if (po->flags & OPF_FPOPP) {
5694 if ((regmask_now & mxSTa) == 0)
5695 ferr(po, "float pop on empty stack?\n");
5696 if (regmask_now & mxST7_2)
5697 po->flags |= OPF_FSHIFT;
5698 if (!(regmask_now & mxST7_2))
5699 regmask_now &= ~mxST1_0;
5701 else if (po->flags & OPF_FPOP) {
5702 if ((regmask_now & mxSTa) == 0)
5703 ferr(po, "float pop on empty stack?\n");
5704 if (regmask_now & (mxST7_2 | mxST1))
5705 po->flags |= OPF_FSHIFT;
5706 if (!(regmask_now & mxST7_2)) {
5708 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5712 if (po->flags & OPF_TAIL) {
5713 if (!(regmask_now & mxST7_2)) {
5714 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5715 if (!(regmask_now & mxST0))
5716 ferr(po, "no st0 on float return, mask: %x\n",
5719 else if (regmask_now & mxST1_0)
5720 ferr(po, "float regs on tail: %x\n", regmask_now);
5723 // there is support for "conditional tailcall", sort of
5724 if (!(po->flags & OPF_CC))
5730 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5734 for (i = 0; i < pp->argc; i++)
5735 if (pp->arg[i].reg == NULL)
5739 memmove(&pp->arg[i + 1], &pp->arg[i],
5740 sizeof(pp->arg[0]) * pp->argc_stack);
5741 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5742 pp->arg[i].reg = strdup(reg);
5743 pp->arg[i].type.name = strdup("int");
5748 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5749 int *pfomask, const char *dst_opr_text)
5751 if (*pfomask & (1 << PFO_Z)) {
5752 fprintf(fout, "\n cond_z = (%s%s == 0);",
5753 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5754 *pfomask &= ~(1 << PFO_Z);
5758 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5759 int *pfomask, const char *dst_opr_text)
5761 if (*pfomask & (1 << PFO_S)) {
5762 fprintf(fout, "\n cond_s = (%s%s < 0);",
5763 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5764 *pfomask &= ~(1 << PFO_S);
5768 static void output_std_flags(FILE *fout, struct parsed_op *po,
5769 int *pfomask, const char *dst_opr_text)
5771 output_std_flag_z(fout, po, pfomask, dst_opr_text);
5772 output_std_flag_s(fout, po, pfomask, dst_opr_text);
5776 OPP_FORCE_NORETURN = (1 << 0),
5777 OPP_SIMPLE_ARGS = (1 << 1),
5778 OPP_ALIGN = (1 << 2),
5781 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5784 const char *cconv = "";
5786 if (pp->is_fastcall)
5787 cconv = "__fastcall ";
5788 else if (pp->is_stdcall && pp->argc_reg == 0)
5789 cconv = "__stdcall ";
5791 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5793 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5794 fprintf(fout, "noreturn ");
5797 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5802 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5806 output_pp_attrs(fout, pp, flags);
5809 fprintf(fout, "%s", pp->name);
5814 for (i = 0; i < pp->argc; i++) {
5816 fprintf(fout, ", ");
5817 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5818 && !(flags & OPP_SIMPLE_ARGS))
5821 output_pp(fout, pp->arg[i].pp, 0);
5823 else if (pp->arg[i].type.is_retreg) {
5824 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5827 fprintf(fout, "%s", pp->arg[i].type.name);
5829 fprintf(fout, " a%d", i + 1);
5832 if (pp->arg[i].type.is_64bit)
5835 if (pp->is_vararg) {
5837 fprintf(fout, ", ");
5838 fprintf(fout, "...");
5843 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5849 snprintf(buf1, sizeof(buf1), "%d", grp);
5850 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5855 static void gen_x_cleanup(int opcnt);
5857 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5859 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5860 struct parsed_opr *last_arith_dst = NULL;
5861 char buf1[256], buf2[256], buf3[256], cast[64];
5862 struct parsed_proto *pp, *pp_tmp;
5863 struct parsed_data *pd;
5864 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5865 unsigned char cbits[MAX_OPS / 8];
5866 const char *float_type;
5867 const char *float_st0;
5868 const char *float_st1;
5869 int need_float_stack = 0;
5870 int need_float_sw = 0; // status word
5871 int need_tmp_var = 0;
5875 int label_pending = 0;
5876 int need_double = 0;
5877 int stack_align = 0;
5878 int stack_fsz_adj = 0;
5879 int regmask_save = 0; // used regs saved/restored in this func
5880 int regmask_arg; // regs from this function args (fastcall, etc)
5881 int regmask_ret; // regs needed on ret
5882 int regmask_now; // temp
5883 int regmask_init = 0; // regs that need zero initialization
5884 int regmask_pp = 0; // regs used in complex push-pop graph
5885 int regmask_ffca = 0; // float function call args
5886 int regmask = 0; // used regs
5896 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5897 g_stack_frame_used = 0;
5899 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5900 regmask_init = g_regmask_init;
5902 g_func_pp = proto_parse(fhdr, funcn, 0);
5903 if (g_func_pp == NULL)
5904 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5906 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5907 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5910 // - resolve all branches
5911 // - parse calls with labels
5912 resolve_branches_parse_calls(opcnt);
5915 // - handle ebp/esp frame, remove ops related to it
5916 scan_prologue_epilogue(opcnt, &stack_align);
5918 // handle a case where sf size is unalignment, but is
5919 // placed in a way that elements are still aligned
5920 if (g_stack_fsz & 4) {
5921 for (i = 0; i < g_eqcnt; i++) {
5922 if (g_eqs[i].lmod != OPLM_QWORD)
5924 if (!(g_eqs[i].offset & 4)) {
5933 // - remove dead labels
5934 // - set regs needed at ret
5935 for (i = 0; i < opcnt; i++)
5937 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5942 if (ops[i].op == OP_RET)
5943 ops[i].regmask_src |= regmask_ret;
5947 // - process trivial calls
5948 for (i = 0; i < opcnt; i++)
5951 if (po->flags & (OPF_RMD|OPF_DONE))
5954 if (po->op == OP_CALL)
5956 pp = process_call_early(i, opcnt, &j);
5958 if (!(po->flags & OPF_ATAIL)) {
5959 // since we know the args, try to collect them
5960 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5968 // commit esp adjust
5969 if (ops[j].op != OP_POP)
5970 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5972 for (l = 0; l < pp->argc_stack; l++)
5973 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5977 if (strstr(pp->ret_type.name, "int64"))
5980 po->flags |= OPF_DONE;
5986 // - process calls, stage 2
5987 // - handle some push/pop pairs
5988 // - scan for STD/CLD, propagate DF
5989 // - try to resolve needed x87 status word bits
5990 for (i = 0; i < opcnt; i++)
5995 if (po->flags & OPF_RMD)
5998 if (po->op == OP_CALL)
6000 if (!(po->flags & OPF_DONE)) {
6001 pp = process_call(i, opcnt);
6003 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
6004 // since we know the args, collect them
6005 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6007 // for unresolved, collect after other passes
6011 ferr_assert(po, pp != NULL);
6013 po->regmask_src |= get_pp_arg_regmask_src(pp);
6014 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
6016 if (po->regmask_dst & mxST0)
6017 po->flags |= OPF_FPUSH;
6019 if (strstr(pp->ret_type.name, "int64"))
6025 if (po->flags & OPF_DONE)
6030 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
6031 && po->operand[0].type == OPT_CONST)
6033 scan_for_pop_const(i, opcnt, i + opcnt * 12);
6038 scan_pushes_for_pop(i, opcnt, ®mask_pp);
6042 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
6043 scan_propagate_df(i + 1, opcnt);
6048 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
6049 ferr(po, "TODO: fnstsw to mem\n");
6050 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
6052 ferr(po, "fnstsw resolve failed\n");
6053 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
6054 (void *)(long)(mask | (z_check << 16)));
6056 ferr(po, "failed to find fcom: %d\n", ret);
6065 // - find POPs for PUSHes, rm both
6066 // - scan for all used registers
6067 memset(cbits, 0, sizeof(cbits));
6068 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
6069 0, ®mask_save, ®mask_init, regmask_arg);
6071 need_float_stack = !!(regmask & mxST7_2);
6074 // - find flag set ops for their users
6075 // - do unresolved calls
6076 // - declare indirect functions
6077 // - other op specific processing
6078 for (i = 0; i < opcnt; i++)
6081 if (po->flags & (OPF_RMD|OPF_DONE))
6084 if (po->flags & OPF_CC)
6086 int setters[16], cnt = 0, branched = 0;
6088 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
6089 &branched, setters, &cnt);
6090 if (ret < 0 || cnt <= 0)
6091 ferr(po, "unable to trace flag setter(s)\n");
6092 if (cnt > ARRAY_SIZE(setters))
6093 ferr(po, "too many flag setters\n");
6095 for (j = 0; j < cnt; j++)
6097 tmp_op = &ops[setters[j]]; // flag setter
6100 // to get nicer code, we try to delay test and cmp;
6101 // if we can't because of operand modification, or if we
6102 // have arith op, or branch, make it calculate flags explicitly
6103 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
6105 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
6106 pfomask = 1 << po->pfo;
6108 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
6109 pfomask = 1 << po->pfo;
6112 // see if we'll be able to handle based on op result
6113 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
6114 && po->pfo != PFO_Z && po->pfo != PFO_S
6115 && po->pfo != PFO_P)
6117 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
6119 pfomask = 1 << po->pfo;
6122 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
6123 propagate_lmod(tmp_op, &tmp_op->operand[0],
6124 &tmp_op->operand[1]);
6125 if (tmp_op->operand[0].lmod == OPLM_DWORD)
6130 tmp_op->pfomask |= pfomask;
6131 cond_vars |= pfomask;
6133 // note: may overwrite, currently not a problem
6137 if (po->op == OP_RCL || po->op == OP_RCR
6138 || po->op == OP_ADC || po->op == OP_SBB)
6139 cond_vars |= 1 << PFO_C;
6145 cond_vars |= 1 << PFO_Z;
6149 if (po->operand[0].lmod == OPLM_DWORD)
6154 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
6159 // note: resolved non-reg calls are OPF_DONE already
6161 ferr_assert(po, pp != NULL);
6163 if (pp->is_unresolved) {
6164 int regmask_stack = 0;
6165 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6167 // this is pretty rough guess:
6168 // see ecx and edx were pushed (and not their saved versions)
6169 for (arg = 0; arg < pp->argc; arg++) {
6170 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
6173 tmp_op = pp->arg[arg].datap;
6175 ferr(po, "parsed_op missing for arg%d\n", arg);
6176 if (tmp_op->operand[0].type == OPT_REG)
6177 regmask_stack |= 1 << tmp_op->operand[0].reg;
6180 if (!((regmask_stack & (1 << xCX))
6181 && (regmask_stack & (1 << xDX))))
6183 if (pp->argc_stack != 0
6184 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
6186 pp_insert_reg_arg(pp, "ecx");
6187 pp->is_fastcall = 1;
6188 regmask_init |= 1 << xCX;
6189 regmask |= 1 << xCX;
6191 if (pp->argc_stack != 0
6192 || ((regmask | regmask_arg) & (1 << xDX)))
6194 pp_insert_reg_arg(pp, "edx");
6195 regmask_init |= 1 << xDX;
6196 regmask |= 1 << xDX;
6200 // note: __cdecl doesn't fall into is_unresolved category
6201 if (pp->argc_stack > 0)
6207 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6209 // <var> = offset <something>
6210 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6211 && !IS_START(po->operand[1].name, "off_"))
6213 if (!po->operand[0].pp->is_fptr)
6214 ferr(po, "%s not declared as fptr when it should be\n",
6215 po->operand[0].name);
6216 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6217 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6218 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6219 fnote(po, "var: %s\n", buf1);
6220 fnote(po, "func: %s\n", buf2);
6221 ferr(po, "^ mismatch\n");
6229 if (po->operand[0].lmod == OPLM_DWORD) {
6230 // 32bit division is common, look for it
6231 if (po->op == OP_DIV)
6232 ret = scan_for_reg_clear(i, xDX);
6234 ret = scan_for_cdq_edx(i);
6236 po->flags |= OPF_32BIT;
6245 po->flags |= OPF_RMD | OPF_DONE;
6255 if (po->operand[0].lmod == OPLM_QWORD)
6265 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
6267 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
6269 po->flags |= OPF_32BIT;
6277 // this might need it's own pass...
6278 if (po->op != OP_FST && po->p_argnum > 0)
6279 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6281 // correct for "full stack" mode late enable
6282 if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6283 && need_float_stack)
6284 po->flags |= OPF_FSHIFT;
6287 float_type = need_double ? "double" : "float";
6288 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6289 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6291 // output starts here
6294 fprintf(fout, "// had SEH\n");
6296 // define userstack size
6297 if (g_func_pp->is_userstack) {
6298 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6299 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6300 fprintf(fout, "#endif\n");
6303 // the function itself
6304 ferr_assert(ops, !g_func_pp->is_fptr);
6305 output_pp(fout, g_func_pp,
6306 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6307 fprintf(fout, "\n{\n");
6309 // declare indirect functions
6310 for (i = 0; i < opcnt; i++) {
6312 if (po->flags & OPF_RMD)
6315 if (po->op == OP_CALL) {
6318 ferr(po, "NULL pp\n");
6320 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6321 if (pp->name[0] != 0) {
6322 if (IS_START(pp->name, "guess"))
6325 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6326 memcpy(pp->name, "i_", 2);
6328 // might be declared already
6330 for (j = 0; j < i; j++) {
6331 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6332 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6342 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6345 output_pp(fout, pp, OPP_SIMPLE_ARGS);
6346 fprintf(fout, ";\n");
6351 // output LUTs/jumptables
6352 for (i = 0; i < g_func_pd_cnt; i++) {
6354 fprintf(fout, " static const ");
6355 if (pd->type == OPT_OFFSET) {
6356 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6358 for (j = 0; j < pd->count; j++) {
6360 fprintf(fout, ", ");
6361 fprintf(fout, "&&%s", pd->d[j].u.label);
6365 fprintf(fout, "%s %s[] =\n { ",
6366 lmod_type_u(ops, pd->lmod), pd->label);
6368 for (j = 0; j < pd->count; j++) {
6370 fprintf(fout, ", ");
6371 fprintf(fout, "%u", pd->d[j].u.val);
6374 fprintf(fout, " };\n");
6378 // declare stack frame, va_arg
6381 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6383 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6384 if (g_func_lmods & (1 << OPLM_WORD))
6385 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6386 if (g_func_lmods & (1 << OPLM_BYTE))
6387 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6388 if (g_func_lmods & (1 << OPLM_QWORD))
6389 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6391 if (stack_align > 8)
6392 ferr(ops, "unhandled stack align of %d\n", stack_align);
6393 else if (stack_align == 8)
6394 fprintf(fout, " u64 align;");
6395 fprintf(fout, " } sf;\n");
6399 if (g_func_pp->is_userstack) {
6400 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6401 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6405 if (g_func_pp->is_vararg) {
6406 fprintf(fout, " va_list ap;\n");
6410 // declare arg-registers
6411 for (i = 0; i < g_func_pp->argc; i++) {
6412 if (g_func_pp->arg[i].reg != NULL) {
6413 reg = char_array_i(regs_r32,
6414 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6415 if (regmask & (1 << reg)) {
6416 if (g_func_pp->arg[i].type.is_retreg)
6417 fprintf(fout, " u32 %s = *r_%s;\n",
6418 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6420 fprintf(fout, " u32 %s = (u32)a%d;\n",
6421 g_func_pp->arg[i].reg, i + 1);
6424 if (g_func_pp->arg[i].type.is_retreg)
6425 ferr(ops, "retreg '%s' is unused?\n",
6426 g_func_pp->arg[i].reg);
6427 fprintf(fout, " // %s = a%d; // unused\n",
6428 g_func_pp->arg[i].reg, i + 1);
6434 // declare normal registers
6435 regmask_now = regmask & ~regmask_arg;
6436 regmask_now &= ~(1 << xSP);
6437 if (regmask_now & 0x00ff) {
6438 for (reg = 0; reg < 8; reg++) {
6439 if (regmask_now & (1 << reg)) {
6440 fprintf(fout, " u32 %s", regs_r32[reg]);
6441 if (regmask_init & (1 << reg))
6442 fprintf(fout, " = 0");
6443 fprintf(fout, ";\n");
6449 if (regmask_now & 0xff00) {
6450 for (reg = 8; reg < 16; reg++) {
6451 if (regmask_now & (1 << reg)) {
6452 fprintf(fout, " mmxr %s", regs_r32[reg]);
6453 if (regmask_init & (1 << reg))
6454 fprintf(fout, " = { 0, }");
6455 fprintf(fout, ";\n");
6461 if (need_float_stack) {
6462 fprintf(fout, " %s f_st[8];\n", float_type);
6463 fprintf(fout, " int f_stp = 0;\n");
6467 if (regmask_now & 0xff0000) {
6468 for (reg = 16; reg < 24; reg++) {
6469 if (regmask_now & (1 << reg)) {
6470 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6471 if (regmask_init & (1 << reg))
6472 fprintf(fout, " = 0");
6473 fprintf(fout, ";\n");
6480 if (need_float_sw) {
6481 fprintf(fout, " u16 f_sw;\n");
6486 for (reg = 0; reg < 8; reg++) {
6487 if (regmask_save & (1 << reg)) {
6488 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6494 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6495 if (save_arg_vars[i] == 0)
6497 for (reg = 0; reg < 32; reg++) {
6498 if (save_arg_vars[i] & (1 << reg)) {
6499 fprintf(fout, " u32 %s;\n",
6500 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6507 for (reg = 0; reg < 32; reg++) {
6508 if (regmask_ffca & (1 << reg)) {
6509 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6515 // declare push-pop temporaries
6517 for (reg = 0; reg < 8; reg++) {
6518 if (regmask_pp & (1 << reg)) {
6519 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6526 for (i = 0; i < 8; i++) {
6527 if (cond_vars & (1 << i)) {
6528 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6535 fprintf(fout, " u32 tmp;\n");
6540 fprintf(fout, " u64 tmp64;\n");
6545 fprintf(fout, "\n");
6547 // do stack clear, if needed
6548 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6550 if (g_stack_clear_len != 0) {
6551 if (g_stack_clear_len <= 4) {
6552 for (i = 0; i < g_stack_clear_len; i++)
6553 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6554 fprintf(fout, "0;\n");
6557 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6558 g_stack_clear_start, g_stack_clear_len * 4);
6562 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6565 if (g_func_pp->is_vararg) {
6566 if (g_func_pp->argc_stack == 0)
6567 ferr(ops, "vararg func without stack args?\n");
6568 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6572 for (i = 0; i < opcnt; i++)
6574 if (g_labels[i] != NULL) {
6575 fprintf(fout, "\n%s:\n", g_labels[i]);
6578 delayed_flag_op = NULL;
6579 last_arith_dst = NULL;
6583 if (po->flags & OPF_RMD)
6588 #define assert_operand_cnt(n_) \
6589 if (po->operand_cnt != n_) \
6590 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6592 // conditional/flag using op?
6593 if (po->flags & OPF_CC)
6599 // we go through all this trouble to avoid using parsed_flag_op,
6600 // which makes generated code much nicer
6601 if (delayed_flag_op != NULL)
6603 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6604 po->pfo, po->pfo_inv);
6607 else if (last_arith_dst != NULL
6608 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6609 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6612 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6613 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6614 last_arith_dst->lmod, buf3);
6617 else if (tmp_op != NULL) {
6618 // use preprocessed flag calc results
6619 if (!(tmp_op->pfomask & (1 << po->pfo)))
6620 ferr(po, "not prepared for pfo %d\n", po->pfo);
6622 // note: pfo_inv was not yet applied
6623 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6624 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6627 ferr(po, "all methods of finding comparison failed\n");
6630 if (po->flags & OPF_JMP) {
6631 fprintf(fout, " if %s", buf1);
6633 else if (po->op == OP_RCL || po->op == OP_RCR
6634 || po->op == OP_ADC || po->op == OP_SBB)
6637 fprintf(fout, " cond_%s = %s;\n",
6638 parsed_flag_op_names[po->pfo], buf1);
6640 else if (po->flags & OPF_DATA) { // SETcc
6641 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6642 fprintf(fout, " %s = %s;", buf2, buf1);
6645 ferr(po, "unhandled conditional op\n");
6649 pfomask = po->pfomask;
6654 assert_operand_cnt(2);
6655 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6656 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6657 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6658 fprintf(fout, " %s = %s;", buf1,
6659 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6664 assert_operand_cnt(2);
6665 po->operand[1].lmod = OPLM_DWORD; // always
6666 fprintf(fout, " %s = %s;",
6667 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6668 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6673 assert_operand_cnt(2);
6674 fprintf(fout, " %s = %s;",
6675 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6676 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6680 assert_operand_cnt(2);
6681 switch (po->operand[1].lmod) {
6683 strcpy(buf3, "(s8)");
6686 strcpy(buf3, "(s16)");
6689 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6691 fprintf(fout, " %s = %s;",
6692 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6693 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6698 assert_operand_cnt(2);
6699 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6700 fprintf(fout, " tmp = %s;",
6701 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6702 fprintf(fout, " %s = %s;",
6703 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6704 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6705 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6706 fprintf(fout, " %s = %stmp;",
6707 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6708 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6709 snprintf(g_comment, sizeof(g_comment), "xchg");
6713 assert_operand_cnt(1);
6714 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6715 fprintf(fout, " %s = ~%s;", buf1, buf1);
6719 assert_operand_cnt(2);
6720 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6721 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6722 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6723 strcpy(g_comment, "xlat");
6727 assert_operand_cnt(2);
6728 fprintf(fout, " %s = (s32)%s >> 31;",
6729 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6730 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6731 strcpy(g_comment, "cdq");
6735 assert_operand_cnt(1);
6736 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6737 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6741 if (po->flags & OPF_REP) {
6742 assert_operand_cnt(3);
6747 assert_operand_cnt(2);
6748 fprintf(fout, " %s = %sesi; esi %c= %d;",
6749 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6750 lmod_cast_u_ptr(po, po->operand[1].lmod),
6751 (po->flags & OPF_DF) ? '-' : '+',
6752 lmod_bytes(po, po->operand[1].lmod));
6753 strcpy(g_comment, "lods");
6758 if (po->flags & OPF_REP) {
6759 assert_operand_cnt(3);
6760 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6761 (po->flags & OPF_DF) ? '-' : '+',
6762 lmod_bytes(po, po->operand[1].lmod));
6763 fprintf(fout, " %sedi = eax;",
6764 lmod_cast_u_ptr(po, po->operand[1].lmod));
6765 strcpy(g_comment, "rep stos");
6768 assert_operand_cnt(2);
6769 fprintf(fout, " %sedi = eax; edi %c= %d;",
6770 lmod_cast_u_ptr(po, po->operand[1].lmod),
6771 (po->flags & OPF_DF) ? '-' : '+',
6772 lmod_bytes(po, po->operand[1].lmod));
6773 strcpy(g_comment, "stos");
6778 j = lmod_bytes(po, po->operand[0].lmod);
6779 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6780 l = (po->flags & OPF_DF) ? '-' : '+';
6781 if (po->flags & OPF_REP) {
6782 assert_operand_cnt(3);
6784 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6787 " %sedi = %sesi;", buf1, buf1);
6788 strcpy(g_comment, "rep movs");
6791 assert_operand_cnt(2);
6792 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6793 buf1, buf1, l, j, l, j);
6794 strcpy(g_comment, "movs");
6799 // repe ~ repeat while ZF=1
6800 j = lmod_bytes(po, po->operand[0].lmod);
6801 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6802 l = (po->flags & OPF_DF) ? '-' : '+';
6803 if (po->flags & OPF_REP) {
6804 assert_operand_cnt(3);
6806 " while (ecx != 0) {\n");
6807 if (pfomask & (1 << PFO_C)) {
6810 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6811 pfomask &= ~(1 << PFO_C);
6814 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6815 buf1, buf1, l, j, l, j);
6818 " if (cond_z %s 0) break;\n",
6819 (po->flags & OPF_REPZ) ? "==" : "!=");
6822 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6823 (po->flags & OPF_REPZ) ? "e" : "ne");
6826 assert_operand_cnt(2);
6828 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6829 buf1, buf1, l, j, l, j);
6830 strcpy(g_comment, "cmps");
6832 pfomask &= ~(1 << PFO_Z);
6833 last_arith_dst = NULL;
6834 delayed_flag_op = NULL;
6838 // only does ZF (for now)
6839 // repe ~ repeat while ZF=1
6840 j = lmod_bytes(po, po->operand[1].lmod);
6841 l = (po->flags & OPF_DF) ? '-' : '+';
6842 if (po->flags & OPF_REP) {
6843 assert_operand_cnt(3);
6845 " while (ecx != 0) {\n");
6847 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6848 lmod_cast_u(po, po->operand[1].lmod),
6849 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6852 " if (cond_z %s 0) break;\n",
6853 (po->flags & OPF_REPZ) ? "==" : "!=");
6856 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6857 (po->flags & OPF_REPZ) ? "e" : "ne");
6860 assert_operand_cnt(2);
6861 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6862 lmod_cast_u(po, po->operand[1].lmod),
6863 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6864 strcpy(g_comment, "scas");
6866 pfomask &= ~(1 << PFO_Z);
6867 last_arith_dst = NULL;
6868 delayed_flag_op = NULL;
6871 // arithmetic w/flags
6873 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6874 goto dualop_arith_const;
6875 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6879 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6880 if (po->operand[1].type == OPT_CONST) {
6881 j = lmod_bytes(po, po->operand[0].lmod);
6882 if (((1ull << j * 8) - 1) == po->operand[1].val)
6883 goto dualop_arith_const;
6888 assert_operand_cnt(2);
6889 fprintf(fout, " %s %s= %s;",
6890 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6892 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6893 output_std_flags(fout, po, &pfomask, buf1);
6894 last_arith_dst = &po->operand[0];
6895 delayed_flag_op = NULL;
6899 // and 0, or ~0 used instead mov
6900 assert_operand_cnt(2);
6901 fprintf(fout, " %s = %s;",
6902 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6903 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6904 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6905 output_std_flags(fout, po, &pfomask, buf1);
6906 last_arith_dst = &po->operand[0];
6907 delayed_flag_op = NULL;
6912 assert_operand_cnt(2);
6913 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6914 if (pfomask & (1 << PFO_C)) {
6915 if (po->operand[1].type == OPT_CONST) {
6916 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6917 j = po->operand[1].val;
6920 if (po->op == OP_SHL)
6924 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6928 ferr(po, "zero shift?\n");
6932 pfomask &= ~(1 << PFO_C);
6934 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6935 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6936 if (po->operand[1].type != OPT_CONST)
6937 fprintf(fout, " & 0x1f");
6939 output_std_flags(fout, po, &pfomask, buf1);
6940 last_arith_dst = &po->operand[0];
6941 delayed_flag_op = NULL;
6945 assert_operand_cnt(2);
6946 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6947 fprintf(fout, " %s = %s%s >> %s;", buf1,
6948 lmod_cast_s(po, po->operand[0].lmod), buf1,
6949 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6950 output_std_flags(fout, po, &pfomask, buf1);
6951 last_arith_dst = &po->operand[0];
6952 delayed_flag_op = NULL;
6957 assert_operand_cnt(3);
6958 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6959 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6960 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6961 if (po->operand[2].type != OPT_CONST) {
6962 // no handling for "undefined" case, hopefully not needed
6963 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6966 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6967 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6968 if (po->op == OP_SHLD) {
6969 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6970 buf1, buf3, buf1, buf2, l, buf3);
6971 strcpy(g_comment, "shld");
6974 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6975 buf1, buf3, buf1, buf2, l, buf3);
6976 strcpy(g_comment, "shrd");
6978 output_std_flags(fout, po, &pfomask, buf1);
6979 last_arith_dst = &po->operand[0];
6980 delayed_flag_op = NULL;
6985 assert_operand_cnt(2);
6986 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6987 if (po->operand[1].type == OPT_CONST) {
6988 j = po->operand[1].val;
6989 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6990 fprintf(fout, po->op == OP_ROL ?
6991 " %s = (%s << %d) | (%s >> %d);" :
6992 " %s = (%s >> %d) | (%s << %d);",
6993 buf1, buf1, j, buf1,
6994 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6998 output_std_flags(fout, po, &pfomask, buf1);
6999 last_arith_dst = &po->operand[0];
7000 delayed_flag_op = NULL;
7005 assert_operand_cnt(2);
7006 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7007 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7008 if (po->operand[1].type == OPT_CONST) {
7009 j = po->operand[1].val % l;
7011 ferr(po, "zero rotate\n");
7012 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
7013 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
7014 if (po->op == OP_RCL) {
7016 " %s = (%s << %d) | (cond_c << %d)",
7017 buf1, buf1, j, j - 1);
7019 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
7023 " %s = (%s >> %d) | (cond_c << %d)",
7024 buf1, buf1, j, l - j);
7026 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
7028 fprintf(fout, ";\n");
7029 fprintf(fout, " cond_c = tmp;");
7033 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
7034 output_std_flags(fout, po, &pfomask, buf1);
7035 last_arith_dst = &po->operand[0];
7036 delayed_flag_op = NULL;
7040 assert_operand_cnt(2);
7041 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7042 if (IS(opr_name(po, 0), opr_name(po, 1))) {
7043 // special case for XOR
7044 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
7045 for (j = 0; j <= PFO_LE; j++) {
7046 if (pfomask & (1 << j)) {
7047 fprintf(fout, " cond_%s = %d;\n",
7048 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
7049 pfomask &= ~(1 << j);
7052 fprintf(fout, " %s = 0;",
7053 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7054 last_arith_dst = &po->operand[0];
7055 delayed_flag_op = NULL;
7061 assert_operand_cnt(2);
7062 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7063 if (pfomask & (1 << PFO_C)) {
7064 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7065 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7066 if (po->operand[0].lmod == OPLM_DWORD) {
7067 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
7068 fprintf(fout, " cond_c = tmp64 >> 32;\n");
7069 fprintf(fout, " %s = (u32)tmp64;",
7070 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7071 strcat(g_comment, " add64");
7074 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
7075 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
7076 fprintf(fout, " %s += %s;",
7077 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7080 pfomask &= ~(1 << PFO_C);
7081 output_std_flags(fout, po, &pfomask, buf1);
7082 last_arith_dst = &po->operand[0];
7083 delayed_flag_op = NULL;
7086 if (pfomask & (1 << PFO_LE)) {
7087 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
7088 fprintf(fout, " cond_%s = %s;\n",
7089 parsed_flag_op_names[PFO_LE], buf1);
7090 pfomask &= ~(1 << PFO_LE);
7095 assert_operand_cnt(2);
7096 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7097 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
7098 for (j = 0; j <= PFO_LE; j++) {
7099 if (!(pfomask & (1 << j)))
7101 if (j == PFO_Z || j == PFO_S)
7104 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7105 fprintf(fout, " cond_%s = %s;\n",
7106 parsed_flag_op_names[j], buf1);
7107 pfomask &= ~(1 << j);
7114 assert_operand_cnt(2);
7115 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7116 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7117 if (po->op == OP_SBB
7118 && IS(po->operand[0].name, po->operand[1].name))
7120 // avoid use of unitialized var
7121 fprintf(fout, " %s = -cond_c;", buf1);
7122 // carry remains what it was
7123 pfomask &= ~(1 << PFO_C);
7126 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
7127 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7129 output_std_flags(fout, po, &pfomask, buf1);
7130 last_arith_dst = &po->operand[0];
7131 delayed_flag_op = NULL;
7136 // on SKL, if src is 0, dst is left unchanged
7137 assert_operand_cnt(2);
7138 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7139 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7140 output_std_flag_z(fout, po, &pfomask, buf2);
7141 if (po->op == OP_BSF)
7142 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
7144 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
7145 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
7146 last_arith_dst = &po->operand[0];
7147 delayed_flag_op = NULL;
7148 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
7152 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
7153 for (j = 0; j <= PFO_LE; j++) {
7154 if (!(pfomask & (1 << j)))
7156 if (j == PFO_Z || j == PFO_S || j == PFO_C)
7159 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7160 fprintf(fout, " cond_%s = %s;\n",
7161 parsed_flag_op_names[j], buf1);
7162 pfomask &= ~(1 << j);
7168 if (pfomask & (1 << PFO_C))
7169 // carry is unaffected by inc/dec.. wtf?
7170 ferr(po, "carry propagation needed\n");
7172 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7173 if (po->operand[0].type == OPT_REG) {
7174 strcpy(buf2, po->op == OP_INC ? "++" : "--");
7175 fprintf(fout, " %s%s;", buf1, buf2);
7178 strcpy(buf2, po->op == OP_INC ? "+" : "-");
7179 fprintf(fout, " %s %s= 1;", buf1, buf2);
7181 output_std_flags(fout, po, &pfomask, buf1);
7182 last_arith_dst = &po->operand[0];
7183 delayed_flag_op = NULL;
7187 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7188 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
7189 fprintf(fout, " %s = -%s%s;", buf1,
7190 lmod_cast_s(po, po->operand[0].lmod), buf2);
7191 last_arith_dst = &po->operand[0];
7192 delayed_flag_op = NULL;
7193 if (pfomask & PFOB_C) {
7194 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
7197 output_std_flags(fout, po, &pfomask, buf1);
7201 if (po->operand_cnt == 2) {
7202 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7205 if (po->operand_cnt == 3)
7206 ferr(po, "TODO imul3\n");
7209 assert_operand_cnt(1);
7210 switch (po->operand[0].lmod) {
7212 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7213 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
7214 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7215 fprintf(fout, " edx = tmp64 >> 32;\n");
7216 fprintf(fout, " eax = tmp64;");
7219 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7220 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
7221 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7225 ferr(po, "TODO: unhandled mul type\n");
7228 last_arith_dst = NULL;
7229 delayed_flag_op = NULL;
7234 assert_operand_cnt(1);
7235 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7236 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7237 po->op == OP_IDIV));
7238 switch (po->operand[0].lmod) {
7240 if (po->flags & OPF_32BIT)
7241 snprintf(buf2, sizeof(buf2), "%seax", cast);
7243 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7244 snprintf(buf2, sizeof(buf2), "%stmp64",
7245 (po->op == OP_IDIV) ? "(s64)" : "");
7247 if (po->operand[0].type == OPT_REG
7248 && po->operand[0].reg == xDX)
7250 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
7251 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
7254 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
7255 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
7259 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
7260 snprintf(buf2, sizeof(buf2), "%stmp",
7261 (po->op == OP_IDIV) ? "(s32)" : "");
7262 if (po->operand[0].type == OPT_REG
7263 && po->operand[0].reg == xDX)
7265 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
7267 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
7271 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
7273 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
7276 strcat(g_comment, " div16");
7279 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7281 last_arith_dst = NULL;
7282 delayed_flag_op = NULL;
7287 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7289 for (j = 0; j < 8; j++) {
7290 if (pfomask & (1 << j)) {
7291 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7292 fprintf(fout, " cond_%s = %s;",
7293 parsed_flag_op_names[j], buf1);
7300 last_arith_dst = NULL;
7301 delayed_flag_op = po;
7305 // SETcc - should already be handled
7308 // note: we reuse OP_Jcc for SETcc, only flags differ
7310 fprintf(fout, "\n goto %s;", po->operand[0].name);
7314 fprintf(fout, " if (ecx == 0)\n");
7315 fprintf(fout, " goto %s;", po->operand[0].name);
7316 strcat(g_comment, " jecxz");
7320 fprintf(fout, " if (--ecx != 0)\n");
7321 fprintf(fout, " goto %s;", po->operand[0].name);
7322 strcat(g_comment, " loop");
7326 assert_operand_cnt(1);
7327 last_arith_dst = NULL;
7328 delayed_flag_op = NULL;
7330 if (po->operand[0].type == OPT_REGMEM) {
7331 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7334 ferr(po, "parse failure for jmp '%s'\n",
7335 po->operand[0].name);
7336 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
7339 else if (po->operand[0].type != OPT_LABEL)
7340 ferr(po, "unhandled jmp type\n");
7342 fprintf(fout, " goto %s;", po->operand[0].name);
7346 assert_operand_cnt(1);
7348 my_assert_not(pp, NULL);
7351 if (po->flags & OPF_CC) {
7352 // we treat conditional branch to another func
7353 // (yes such code exists..) as conditional tailcall
7355 fprintf(fout, " {\n");
7358 if (pp->is_fptr && !pp->is_arg) {
7359 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7360 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7363 if (pp->is_fptr && (pp->is_unresolved || pp->is_guessed)) {
7364 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7365 buf3, asmfn, po->asmln, pp->name);
7368 fprintf(fout, "%s", buf3);
7369 if (strstr(pp->ret_type.name, "int64")) {
7370 if (po->flags & OPF_TAIL)
7371 ferr(po, "int64 and tail?\n");
7372 fprintf(fout, "tmp64 = ");
7374 else if (!IS(pp->ret_type.name, "void")) {
7375 if (po->flags & OPF_TAIL) {
7376 if (regmask_ret & mxAX) {
7377 fprintf(fout, "return ");
7378 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7379 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7381 else if (regmask_ret & mxST0)
7382 ferr(po, "float tailcall\n");
7384 else if (po->regmask_dst & mxAX) {
7385 fprintf(fout, "eax = ");
7386 if (pp->ret_type.is_ptr)
7387 fprintf(fout, "(u32)");
7389 else if (po->regmask_dst & mxST0) {
7390 ferr_assert(po, po->flags & OPF_FPUSH);
7391 if (need_float_stack)
7392 fprintf(fout, "f_st[--f_stp & 7] = ");
7394 fprintf(fout, "f_st0 = ");
7398 if (pp->name[0] == 0)
7399 ferr(po, "missing pp->name\n");
7400 fprintf(fout, "%s%s(", pp->name,
7401 pp->has_structarg ? "_sa" : "");
7403 if (po->flags & OPF_ATAIL) {
7405 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7406 check_compat |= pp->argc_stack > 0;
7408 && (pp->argc_stack != g_func_pp->argc_stack
7409 || pp->is_stdcall != g_func_pp->is_stdcall))
7410 ferr(po, "incompatible arg-reuse tailcall\n");
7411 if (g_func_pp->has_retreg)
7412 ferr(po, "TODO: retreg+tailcall\n");
7414 for (arg = j = 0; arg < pp->argc; arg++) {
7416 fprintf(fout, ", ");
7419 if (pp->arg[arg].type.is_ptr)
7420 snprintf(cast, sizeof(cast), "(%s)",
7421 pp->arg[arg].type.name);
7423 if (pp->arg[arg].reg != NULL) {
7424 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7428 for (; j < g_func_pp->argc; j++)
7429 if (g_func_pp->arg[j].reg == NULL)
7431 fprintf(fout, "%sa%d", cast, j + 1);
7436 for (arg = 0; arg < pp->argc; arg++) {
7438 fprintf(fout, ", ");
7441 if (pp->arg[arg].type.is_ptr)
7442 snprintf(cast, sizeof(cast), "(%s)",
7443 pp->arg[arg].type.name);
7445 if (pp->arg[arg].reg != NULL) {
7446 if (pp->arg[arg].type.is_retreg)
7447 fprintf(fout, "&%s", pp->arg[arg].reg);
7448 else if (IS(pp->arg[arg].reg, "ebp")
7449 && g_bp_frame && !(po->flags & OPF_EBP_S))
7451 // rare special case
7452 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7453 strcat(g_comment, " bp_ref");
7456 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7461 tmp_op = pp->arg[arg].datap;
7463 ferr(po, "parsed_op missing for arg%d\n", arg);
7465 if (tmp_op->flags & OPF_VAPUSH) {
7466 fprintf(fout, "ap");
7468 else if (tmp_op->op == OP_FST) {
7469 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7470 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7473 else if (pp->arg[arg].type.is_64bit) {
7474 ferr_assert(po, tmp_op->p_argpass == 0);
7475 ferr_assert(po, !pp->arg[arg].is_saved);
7476 ferr_assert(po, !pp->arg[arg].type.is_float);
7477 ferr_assert(po, cast[0] == 0);
7478 out_src_opr(buf1, sizeof(buf1),
7479 tmp_op, &tmp_op->operand[0], cast, 0);
7480 tmp_op = pp->arg[++arg].datap;
7481 ferr_assert(po, tmp_op != NULL);
7482 out_src_opr(buf2, sizeof(buf2),
7483 tmp_op, &tmp_op->operand[0], cast, 0);
7484 fprintf(fout, "((u64)(%s) << 32) | (%s)",
7487 else if (tmp_op->p_argpass != 0) {
7488 ferr_assert(po, !pp->arg[arg].type.is_float);
7489 fprintf(fout, "a%d", tmp_op->p_argpass);
7491 else if (pp->arg[arg].is_saved) {
7492 ferr_assert(po, tmp_op->p_argnum > 0);
7493 ferr_assert(po, !pp->arg[arg].type.is_float);
7494 fprintf(fout, "%s%s", cast,
7495 saved_arg_name(buf1, sizeof(buf1),
7496 tmp_op->p_arggrp, tmp_op->p_argnum));
7498 else if (pp->arg[arg].type.is_float) {
7499 ferr_assert(po, !pp->arg[arg].type.is_64bit);
7501 out_src_opr_float(buf1, sizeof(buf1),
7502 tmp_op, &tmp_op->operand[0], need_float_stack));
7506 out_src_opr(buf1, sizeof(buf1),
7507 tmp_op, &tmp_op->operand[0], cast, 0));
7511 fprintf(fout, ");");
7513 if (strstr(pp->ret_type.name, "int64")) {
7514 fprintf(fout, "\n");
7515 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7516 fprintf(fout, "%seax = tmp64;", buf3);
7519 if (pp->is_unresolved) {
7520 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7522 strcat(g_comment, buf2);
7525 if (po->flags & OPF_TAIL) {
7527 if (i == opcnt - 1 || pp->is_noreturn)
7529 else if (IS(pp->ret_type.name, "void"))
7531 else if (!(regmask_ret & (1 << xAX)))
7533 // else already handled as 'return f()'
7536 fprintf(fout, "\n%sreturn;", buf3);
7537 strcat(g_comment, " ^ tailcall");
7540 strcat(g_comment, " tailcall");
7542 if ((regmask_ret & (1 << xAX))
7543 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7545 ferr(po, "int func -> void func tailcall?\n");
7548 if (pp->is_noreturn)
7549 strcat(g_comment, " noreturn");
7550 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7551 strcat(g_comment, " argframe");
7552 if (po->flags & OPF_CC)
7553 strcat(g_comment, " cond");
7555 if (po->flags & OPF_CC)
7556 fprintf(fout, "\n }");
7558 delayed_flag_op = NULL;
7559 last_arith_dst = NULL;
7563 if (g_func_pp->is_vararg)
7564 fprintf(fout, " va_end(ap);\n");
7565 if (g_func_pp->has_retreg) {
7566 for (arg = 0; arg < g_func_pp->argc; arg++)
7567 if (g_func_pp->arg[arg].type.is_retreg)
7568 fprintf(fout, " *r_%s = %s;\n",
7569 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7572 if (regmask_ret & mxST0) {
7573 fprintf(fout, " return %s;", float_st0);
7575 else if (!(regmask_ret & mxAX)) {
7576 if (i != opcnt - 1 || label_pending)
7577 fprintf(fout, " return;");
7579 else if (g_func_pp->ret_type.is_ptr) {
7580 fprintf(fout, " return (%s)eax;",
7581 g_func_pp->ret_type.name);
7583 else if (IS(g_func_pp->ret_type.name, "__int64"))
7584 fprintf(fout, " return ((u64)edx << 32) | eax;");
7586 fprintf(fout, " return eax;");
7588 last_arith_dst = NULL;
7589 delayed_flag_op = NULL;
7593 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7594 if (po->p_argnum != 0) {
7595 // special case - saved func arg
7596 fprintf(fout, " %s = %s;",
7597 saved_arg_name(buf2, sizeof(buf2),
7598 po->p_arggrp, po->p_argnum), buf1);
7601 else if (po->flags & OPF_RSAVE) {
7602 fprintf(fout, " s_%s = %s;", buf1, buf1);
7605 else if (po->flags & OPF_PPUSH) {
7607 ferr_assert(po, tmp_op != NULL);
7608 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7609 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7612 else if (g_func_pp->is_userstack) {
7613 fprintf(fout, " *(--esp) = %s;", buf1);
7616 if (!(g_ida_func_attr & IDAFA_NORETURN))
7617 ferr(po, "stray push encountered\n");
7622 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7623 if (po->flags & OPF_RSAVE) {
7624 fprintf(fout, " %s = s_%s;", buf1, buf1);
7627 else if (po->flags & OPF_PPUSH) {
7628 // push/pop graph / non-const
7629 ferr_assert(po, po->datap == NULL);
7630 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7633 else if (po->datap != NULL) {
7636 fprintf(fout, " %s = %s;", buf1,
7637 out_src_opr(buf2, sizeof(buf2),
7638 tmp_op, &tmp_op->operand[0],
7639 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7642 else if (g_func_pp->is_userstack) {
7643 fprintf(fout, " %s = *esp++;", buf1);
7647 ferr(po, "stray pop encountered\n");
7657 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7658 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7659 po->op == OPP_ALLSHL ? "<<" : ">>");
7660 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7661 strcat(g_comment, po->op == OPP_ALLSHL
7662 ? " allshl" : " allshr");
7667 if (need_float_stack) {
7668 out_src_opr_float(buf1, sizeof(buf1),
7669 po, &po->operand[0], 1);
7670 if (po->regmask_src & mxSTa) {
7671 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7675 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7678 if (po->flags & OPF_FSHIFT)
7679 fprintf(fout, " f_st1 = f_st0;");
7680 if (po->operand[0].type == OPT_REG
7681 && po->operand[0].reg == xST0)
7683 strcat(g_comment, " fld st");
7686 fprintf(fout, " f_st0 = %s;",
7687 out_src_opr_float(buf1, sizeof(buf1),
7688 po, &po->operand[0], 0));
7690 strcat(g_comment, " fld");
7694 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7695 lmod_cast(po, po->operand[0].lmod, 1), 0);
7696 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7697 if (need_float_stack) {
7698 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7701 if (po->flags & OPF_FSHIFT)
7702 fprintf(fout, " f_st1 = f_st0;");
7703 fprintf(fout, " f_st0 = %s;", buf2);
7705 strcat(g_comment, " fild");
7709 if (need_float_stack)
7710 fprintf(fout, " f_st[--f_stp & 7] = ");
7712 if (po->flags & OPF_FSHIFT)
7713 fprintf(fout, " f_st1 = f_st0;");
7714 fprintf(fout, " f_st0 = ");
7716 switch (po->operand[0].val) {
7717 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7718 case X87_CONST_L2T: fprintf(fout, "3.321928094887362;"); break;
7719 case X87_CONST_L2E: fprintf(fout, "M_LOG2E;"); break;
7720 case X87_CONST_PI: fprintf(fout, "M_PI;"); break;
7721 case X87_CONST_LG2: fprintf(fout, "0.301029995663981;"); break;
7722 case X87_CONST_LN2: fprintf(fout, "M_LN2;"); break;
7723 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7724 default: ferr_assert(po, 0); break;
7729 if (po->flags & OPF_FARG) {
7730 // store to stack as func arg
7731 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7735 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7737 dead_dst = po->operand[0].type == OPT_REG
7738 && po->operand[0].reg == xST0;
7741 fprintf(fout, " %s = %s;", buf1, float_st0);
7742 if (po->flags & OPF_FSHIFT) {
7743 if (need_float_stack)
7744 fprintf(fout, " f_stp++;");
7746 fprintf(fout, " f_st0 = f_st1;");
7748 if (dead_dst && !(po->flags & OPF_FSHIFT))
7751 strcat(g_comment, " fst");
7755 fprintf(fout, " %s = %s%s;",
7756 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7757 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7758 if (po->flags & OPF_FSHIFT) {
7759 if (need_float_stack)
7760 fprintf(fout, " f_stp++;");
7762 fprintf(fout, " f_st0 = f_st1;");
7764 strcat(g_comment, " fist");
7771 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7773 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7775 dead_dst = (po->flags & OPF_FPOP)
7776 && po->operand[0].type == OPT_REG
7777 && po->operand[0].reg == xST0;
7779 case OP_FADD: j = '+'; break;
7780 case OP_FDIV: j = '/'; break;
7781 case OP_FMUL: j = '*'; break;
7782 case OP_FSUB: j = '-'; break;
7783 default: j = 'x'; break;
7785 if (need_float_stack) {
7787 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7788 if (po->flags & OPF_FSHIFT)
7789 fprintf(fout, " f_stp++;");
7792 if (po->flags & OPF_FSHIFT) {
7793 // note: assumes only 2 regs handled
7795 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7797 fprintf(fout, " f_st0 = f_st1;");
7800 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7802 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7807 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7809 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7811 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7813 dead_dst = (po->flags & OPF_FPOP)
7814 && po->operand[0].type == OPT_REG
7815 && po->operand[0].reg == xST0;
7816 j = po->op == OP_FDIVR ? '/' : '-';
7817 if (need_float_stack) {
7819 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7820 if (po->flags & OPF_FSHIFT)
7821 fprintf(fout, " f_stp++;");
7824 if (po->flags & OPF_FSHIFT) {
7826 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7828 fprintf(fout, " f_st0 = f_st1;");
7831 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7833 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7841 case OP_FIADD: j = '+'; break;
7842 case OP_FIDIV: j = '/'; break;
7843 case OP_FIMUL: j = '*'; break;
7844 case OP_FISUB: j = '-'; break;
7845 default: j = 'x'; break;
7847 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7849 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7850 lmod_cast(po, po->operand[0].lmod, 1), 0));
7855 fprintf(fout, " %s = %s %c %s;", float_st0,
7856 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7858 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7863 ferr_assert(po, po->datap != NULL);
7864 mask = (long)po->datap & 0xffff;
7865 z_check = ((long)po->datap >> 16) & 1;
7866 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7868 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
7869 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7872 else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
7873 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7876 else if (mask == 0x4100) { // C3, C0
7878 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7880 strcat(g_comment, " z_chk_det");
7883 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7884 "(%s < %s ? 0x0100 : 0);",
7885 float_st0, buf1, float_st0, buf1);
7889 ferr(po, "unhandled sw mask: %x\n", mask);
7890 if (po->flags & OPF_FSHIFT) {
7891 if (need_float_stack) {
7892 if (po->flags & OPF_FPOPP)
7893 fprintf(fout, " f_stp += 2;");
7895 fprintf(fout, " f_stp++;");
7898 ferr_assert(po, !(po->flags & OPF_FPOPP));
7899 fprintf(fout, " f_st0 = f_st1;");
7906 fprintf(fout, " %s = f_sw;",
7907 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7911 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7915 fprintf(fout, " %s = cos%s(%s);", float_st0,
7916 need_double ? "" : "f", float_st0);
7920 if (need_float_stack) {
7921 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7922 need_double ? "" : "f", float_st1, float_st0);
7923 fprintf(fout, " f_stp++;");
7926 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7927 need_double ? "" : "f");
7932 if (need_float_stack) {
7933 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7934 float_st1, need_double ? "" : "f", float_st0);
7935 fprintf(fout, " f_stp++;");
7938 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7939 need_double ? "" : "f");
7941 strcat(g_comment, " fyl2x");
7945 fprintf(fout, " %s = sin%s(%s);", float_st0,
7946 need_double ? "" : "f", float_st0);
7950 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7951 need_double ? "" : "f", float_st0);
7955 dead_dst = po->operand[0].type == OPT_REG
7956 && po->operand[0].reg == xST0;
7958 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7960 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7961 float_st0, float_st0, buf1, buf1);
7962 strcat(g_comment, " fxch");
7969 ferr_assert(po, po->flags & OPF_32BIT);
7970 fprintf(fout, " eax = (s32)%s;", float_st0);
7971 if (po->flags & OPF_FSHIFT) {
7972 if (need_float_stack)
7973 fprintf(fout, " f_stp++;");
7975 fprintf(fout, " f_st0 = f_st1;");
7977 strcat(g_comment, " ftol");
7981 if (need_float_stack) {
7982 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
7983 need_double ? "" : "f", float_st1, float_st0);
7984 fprintf(fout, " f_stp++;");
7987 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
7988 need_double ? "" : "f");
7990 strcat(g_comment, " CIpow");
7994 fprintf(fout, " do_skip_code_abort();");
7999 fprintf(fout, " do_emms();");
8004 ferr(po, "unhandled op type %d, flags %x\n",
8009 if (g_comment[0] != 0) {
8010 char *p = g_comment;
8011 while (my_isblank(*p))
8013 fprintf(fout, " // %s", p);
8018 fprintf(fout, "\n");
8020 // some sanity checking
8021 if (po->flags & OPF_REP) {
8022 if (po->op != OP_STOS && po->op != OP_MOVS
8023 && po->op != OP_CMPS && po->op != OP_SCAS)
8024 ferr(po, "unexpected rep\n");
8025 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
8026 && (po->op == OP_CMPS || po->op == OP_SCAS))
8027 ferr(po, "cmps/scas with plain rep\n");
8029 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
8030 && po->op != OP_CMPS && po->op != OP_SCAS)
8031 ferr(po, "unexpected repz/repnz\n");
8034 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
8036 // see is delayed flag stuff is still valid
8037 if (delayed_flag_op != NULL && delayed_flag_op != po) {
8038 if (is_any_opr_modified(delayed_flag_op, po, 0))
8039 delayed_flag_op = NULL;
8042 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
8043 if (is_opr_modified(last_arith_dst, po))
8044 last_arith_dst = NULL;
8051 if (g_stack_fsz && !g_stack_frame_used)
8052 fprintf(fout, " (void)sf;\n");
8054 fprintf(fout, "}\n\n");
8056 gen_x_cleanup(opcnt);
8059 static void gen_x_cleanup(int opcnt)
8063 for (i = 0; i < opcnt; i++) {
8064 struct label_ref *lr, *lr_del;
8066 lr = g_label_refs[i].next;
8067 while (lr != NULL) {
8072 g_label_refs[i].i = -1;
8073 g_label_refs[i].next = NULL;
8075 if (ops[i].op == OP_CALL) {
8077 proto_release(ops[i].pp);
8083 struct func_proto_dep;
8085 struct func_prototype {
8090 int has_ret:3; // -1, 0, 1: unresolved, no, yes
8091 unsigned int dep_resolved:1;
8092 unsigned int is_stdcall:1;
8093 struct func_proto_dep *dep_func;
8095 const struct parsed_proto *pp; // seed pp, if any
8098 struct func_proto_dep {
8100 struct func_prototype *proto;
8101 int regmask_live; // .. at the time of call
8102 unsigned int ret_dep:1; // return from this is caller's return
8105 static struct func_prototype *hg_fp;
8106 static int hg_fp_cnt;
8108 static struct scanned_var {
8110 enum opr_lenmod lmod;
8111 unsigned int is_seeded:1;
8112 unsigned int is_c_str:1;
8113 const struct parsed_proto *pp; // seed pp, if any
8115 static int hg_var_cnt;
8117 static char **hg_refs;
8118 static int hg_ref_cnt;
8120 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8123 static struct func_prototype *hg_fp_add(const char *funcn)
8125 struct func_prototype *fp;
8127 if ((hg_fp_cnt & 0xff) == 0) {
8128 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
8129 my_assert_not(hg_fp, NULL);
8130 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
8133 fp = &hg_fp[hg_fp_cnt];
8134 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
8136 fp->argc_stack = -1;
8142 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
8147 for (i = 0; i < fp->dep_func_cnt; i++)
8148 if (IS(fp->dep_func[i].name, name))
8149 return &fp->dep_func[i];
8154 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
8157 if (hg_fp_find_dep(fp, name))
8160 if ((fp->dep_func_cnt & 0xff) == 0) {
8161 fp->dep_func = realloc(fp->dep_func,
8162 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
8163 my_assert_not(fp->dep_func, NULL);
8164 memset(&fp->dep_func[fp->dep_func_cnt], 0,
8165 sizeof(fp->dep_func[0]) * 0x100);
8167 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
8171 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
8173 const struct func_prototype *p1 = p1_, *p2 = p2_;
8174 return strcmp(p1->name, p2->name);
8178 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
8180 const struct func_prototype *p1 = p1_, *p2 = p2_;
8181 return p1->id - p2->id;
8185 static void hg_ref_add(const char *name)
8187 if ((hg_ref_cnt & 0xff) == 0) {
8188 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8189 my_assert_not(hg_refs, NULL);
8190 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8193 hg_refs[hg_ref_cnt] = strdup(name);
8194 my_assert_not(hg_refs[hg_ref_cnt], NULL);
8198 // recursive register dep pass
8199 // - track saved regs (part 2)
8200 // - try to figure out arg-regs
8201 // - calculate reg deps
8202 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8203 struct func_prototype *fp, int regmask_save, int regmask_dst,
8204 int *regmask_dep, int *has_ret)
8206 struct func_proto_dep *dep;
8207 struct parsed_op *po;
8208 int from_caller = 0;
8213 for (; i < opcnt; i++)
8215 if (cbits[i >> 3] & (1 << (i & 7)))
8217 cbits[i >> 3] |= (1 << (i & 7));
8221 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8222 if (po->flags & OPF_RMD)
8225 if (po->btj != NULL) {
8227 for (j = 0; j < po->btj->count; j++) {
8228 check_i(po, po->btj->d[j].bt_i);
8229 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8230 regmask_save, regmask_dst, regmask_dep, has_ret);
8235 check_i(po, po->bt_i);
8236 if (po->flags & OPF_CJMP) {
8237 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8238 regmask_save, regmask_dst, regmask_dep, has_ret);
8246 if (po->flags & OPF_FARG)
8247 /* (just calculate register deps) */;
8248 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8250 reg = po->operand[0].reg;
8251 ferr_assert(po, reg >= 0);
8253 if (po->flags & OPF_RSAVE) {
8254 regmask_save |= 1 << reg;
8257 if (po->flags & OPF_DONE)
8260 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
8262 regmask_save |= 1 << reg;
8263 po->flags |= OPF_RMD;
8264 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
8268 else if (po->flags & OPF_RMD)
8270 else if (po->op == OP_CALL) {
8271 po->regmask_dst |= 1 << xAX;
8273 dep = hg_fp_find_dep(fp, po->operand[0].name);
8275 dep->regmask_live = regmask_save | regmask_dst;
8276 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8277 dep->regmask_live |= 1 << xBP;
8280 else if (po->op == OP_RET) {
8281 if (po->operand_cnt > 0) {
8283 if (fp->argc_stack >= 0
8284 && fp->argc_stack != po->operand[0].val / 4)
8285 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8286 fp->argc_stack = po->operand[0].val / 4;
8290 // if has_ret is 0, there is uninitialized eax path,
8291 // which means it's most likely void func
8292 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
8293 if (po->op == OP_CALL) {
8298 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
8301 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
8304 if (ret != 1 && from_caller) {
8305 // unresolved eax - probably void func
8309 if (j >= 0 && ops[j].op == OP_CALL) {
8310 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8321 l = regmask_save | regmask_dst;
8322 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8325 l = po->regmask_src & ~l;
8328 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8329 l, regmask_dst, regmask_save, po->flags);
8332 regmask_dst |= po->regmask_dst;
8334 if (po->flags & OPF_TAIL)
8339 static void gen_hdr(const char *funcn, int opcnt)
8341 unsigned char cbits[MAX_OPS / 8];
8342 const struct parsed_proto *pp_c;
8343 struct parsed_proto *pp;
8344 struct func_prototype *fp;
8345 struct parsed_op *po;
8346 int regmask_dummy = 0;
8348 int max_bp_offset = 0;
8353 pp_c = proto_parse(g_fhdr, funcn, 1);
8355 // already in seed, will add to hg_fp later
8358 fp = hg_fp_add(funcn);
8360 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8361 g_stack_frame_used = 0;
8365 // - resolve all branches
8366 // - parse calls with labels
8367 resolve_branches_parse_calls(opcnt);
8370 // - handle ebp/esp frame, remove ops related to it
8371 scan_prologue_epilogue(opcnt, NULL);
8374 // - remove dead labels
8376 for (i = 0; i < opcnt; i++)
8378 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8384 if (po->flags & (OPF_RMD|OPF_DONE))
8387 if (po->op == OP_CALL) {
8388 if (po->operand[0].type == OPT_LABEL)
8389 hg_fp_add_dep(fp, opr_name(po, 0));
8390 else if (po->pp != NULL)
8391 hg_fp_add_dep(fp, po->pp->name);
8396 // - remove dead labels
8397 // - handle push <const>/pop pairs
8398 for (i = 0; i < opcnt; i++)
8400 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8406 if (po->flags & (OPF_RMD|OPF_DONE))
8409 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8410 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8414 // - process trivial calls
8415 for (i = 0; i < opcnt; i++)
8418 if (po->flags & (OPF_RMD|OPF_DONE))
8421 if (po->op == OP_CALL)
8423 pp = process_call_early(i, opcnt, &j);
8425 if (!(po->flags & OPF_ATAIL))
8426 // since we know the args, try to collect them
8427 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8433 // commit esp adjust
8434 if (ops[j].op != OP_POP)
8435 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8437 for (l = 0; l < pp->argc_stack; l++)
8438 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8442 po->flags |= OPF_DONE;
8448 // - track saved regs (simple)
8450 for (i = 0; i < opcnt; i++)
8453 if (po->flags & (OPF_RMD|OPF_DONE))
8456 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8457 && po->operand[0].reg != xCX)
8459 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8461 // regmask_save |= 1 << po->operand[0].reg; // do it later
8462 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8463 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8466 else if (po->op == OP_CALL)
8468 pp = process_call(i, opcnt);
8470 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8471 // since we know the args, collect them
8472 ret = collect_call_args(po, i, pp, ®mask_dummy,
8479 memset(cbits, 0, sizeof(cbits));
8483 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
8485 // find unreachable code - must be fixed in IDA
8486 for (i = 0; i < opcnt; i++)
8488 if (cbits[i >> 3] & (1 << (i & 7)))
8491 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8492 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8494 // the compiler sometimes still generates code after
8495 // noreturn OS functions
8498 if (!(ops[i].flags & OPF_RMD)
8499 && ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8501 ferr(&ops[i], "unreachable code\n");
8505 for (i = 0; i < g_eqcnt; i++) {
8506 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8507 max_bp_offset = g_eqs[i].offset;
8510 if (fp->argc_stack < 0) {
8511 max_bp_offset = (max_bp_offset + 3) & ~3;
8512 fp->argc_stack = max_bp_offset / 4;
8513 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8517 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8518 fp->has_ret = has_ret;
8520 printf("// has_ret %d, regmask_dep %x\n",
8521 fp->has_ret, fp->regmask_dep);
8522 output_hdr_fp(stdout, fp, 1);
8523 if (IS(funcn, "sub_10007F72")) exit(1);
8526 gen_x_cleanup(opcnt);
8529 static void hg_fp_resolve_deps(struct func_prototype *fp)
8531 struct func_prototype fp_s;
8535 // this thing is recursive, so mark first..
8536 fp->dep_resolved = 1;
8538 for (i = 0; i < fp->dep_func_cnt; i++) {
8539 strcpy(fp_s.name, fp->dep_func[i].name);
8540 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8541 sizeof(hg_fp[0]), hg_fp_cmp_name);
8542 if (fp->dep_func[i].proto != NULL) {
8543 if (!fp->dep_func[i].proto->dep_resolved)
8544 hg_fp_resolve_deps(fp->dep_func[i].proto);
8546 dep = ~fp->dep_func[i].regmask_live
8547 & fp->dep_func[i].proto->regmask_dep;
8548 fp->regmask_dep |= dep;
8549 // printf("dep %s %s |= %x\n", fp->name,
8550 // fp->dep_func[i].name, dep);
8552 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8553 fp->has_ret = fp->dep_func[i].proto->has_ret;
8558 // make all thiscall/edx arg functions referenced from .data fastcall
8559 static void do_func_refs_from_data(void)
8561 struct func_prototype *fp, fp_s;
8564 for (i = 0; i < hg_ref_cnt; i++) {
8565 strcpy(fp_s.name, hg_refs[i]);
8566 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8567 sizeof(hg_fp[0]), hg_fp_cmp_name);
8571 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8572 fp->regmask_dep |= mxCX | mxDX;
8576 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8579 const struct parsed_proto *pp;
8580 char *p, namebuf[NAMELEN];
8586 for (; count > 0; count--, fp++) {
8587 if (fp->has_ret == -1)
8588 fprintf(fout, "// ret unresolved\n");
8590 fprintf(fout, "// dep:");
8591 for (j = 0; j < fp->dep_func_cnt; j++) {
8592 fprintf(fout, " %s/", fp->dep_func[j].name);
8593 if (fp->dep_func[j].proto != NULL)
8594 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8595 fp->dep_func[j].proto->has_ret);
8597 fprintf(fout, "\n");
8600 p = strchr(fp->name, '@');
8602 memcpy(namebuf, fp->name, p - fp->name);
8603 namebuf[p - fp->name] = 0;
8611 pp = proto_parse(g_fhdr, name, 1);
8612 if (pp != NULL && pp->is_include)
8615 if (fp->pp != NULL) {
8616 // part of seed, output later
8620 regmask_dep = fp->regmask_dep;
8621 argc_normal = fp->argc_stack;
8623 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8624 (fp->has_ret ? "int" : "void"));
8625 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8626 && (regmask_dep & ~mxCX) == 0)
8628 fprintf(fout, "/*__thiscall*/ ");
8632 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8633 && (regmask_dep & ~(mxCX | mxDX)) == 0)
8635 fprintf(fout, " __fastcall ");
8636 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8642 else if (regmask_dep && !fp->is_stdcall) {
8643 fprintf(fout, "/*__usercall*/ ");
8645 else if (regmask_dep) {
8646 fprintf(fout, "/*__userpurge*/ ");
8648 else if (fp->is_stdcall)
8649 fprintf(fout, " __stdcall ");
8651 fprintf(fout, " __cdecl ");
8653 fprintf(fout, "%s(", name);
8656 for (j = 0; j < xSP; j++) {
8657 if (regmask_dep & (1 << j)) {
8660 fprintf(fout, ", ");
8662 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8664 fprintf(fout, "int");
8665 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8669 for (j = 0; j < argc_normal; j++) {
8672 fprintf(fout, ", ");
8673 if (fp->pp != NULL) {
8674 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8675 if (!fp->pp->arg[arg - 1].type.is_ptr)
8679 fprintf(fout, "int ");
8680 fprintf(fout, "a%d", arg);
8683 fprintf(fout, ");\n");
8687 static void output_hdr(FILE *fout)
8689 static const char *lmod_c_names[] = {
8690 [OPLM_UNSPEC] = "???",
8691 [OPLM_BYTE] = "uint8_t",
8692 [OPLM_WORD] = "uint16_t",
8693 [OPLM_DWORD] = "uint32_t",
8694 [OPLM_QWORD] = "uint64_t",
8696 const struct scanned_var *var;
8697 struct func_prototype *fp;
8698 char line[256] = { 0, };
8702 // add stuff from headers
8703 for (i = 0; i < pp_cache_size; i++) {
8704 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8705 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8707 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8708 fp = hg_fp_add(name);
8709 fp->pp = &pp_cache[i];
8710 fp->argc_stack = fp->pp->argc_stack;
8711 fp->is_stdcall = fp->pp->is_stdcall;
8712 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8713 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8717 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8718 for (i = 0; i < hg_fp_cnt; i++)
8719 hg_fp_resolve_deps(&hg_fp[i]);
8721 // adjust functions referenced from data segment
8722 do_func_refs_from_data();
8724 // note: messes up .proto ptr, don't use
8725 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8728 for (i = 0; i < hg_var_cnt; i++) {
8731 if (var->pp != NULL)
8734 else if (var->is_c_str)
8735 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8737 fprintf(fout, "extern %-8s %s;",
8738 lmod_c_names[var->lmod], var->name);
8741 fprintf(fout, " // seeded");
8742 fprintf(fout, "\n");
8745 fprintf(fout, "\n");
8747 // output function prototypes
8748 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8751 fprintf(fout, "\n// - seed -\n");
8754 while (fgets(line, sizeof(line), g_fhdr))
8755 fwrite(line, 1, strlen(line), fout);
8758 // '=' needs special treatment
8760 static char *next_word_s(char *w, size_t wsize, char *s)
8767 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8769 for (i = 1; i < wsize - 1; i++) {
8771 printf("warning: missing closing quote: \"%s\"\n", s);
8780 for (; i < wsize - 1; i++) {
8781 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8787 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8788 printf("warning: '%s' truncated\n", w);
8793 static int cmpstringp(const void *p1, const void *p2)
8795 return strcmp(*(char * const *)p1, *(char * const *)p2);
8798 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8803 if (strstr(p, "..."))
8804 // unable to determine, assume needed
8807 if (*p == '.') // .text, .data, ...
8808 // ref from other data or non-function -> no
8811 p2 = strpbrk(p, "+:\r\n\x18");
8814 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8815 // referenced from removed code
8821 static int ida_xrefs_show_need(FILE *fasm, char *p,
8822 char **rlist, int rlist_len)
8828 p = strrchr(p, ';');
8829 if (p != NULL && *p == ';') {
8830 if (IS_START(p + 2, "sctref"))
8832 if (IS_START(p + 2, "DATA XREF: ")) {
8834 if (is_xref_needed(p, rlist, rlist_len))
8842 if (!my_fgets(line, sizeof(line), fasm))
8844 // non-first line is always indented
8845 if (!my_isblank(line[0]))
8848 // should be no content, just comment
8853 p = strrchr(p, ';');
8856 if (IS_START(p, "sctref")) {
8861 // it's printed once, but no harm to check again
8862 if (IS_START(p, "DATA XREF: "))
8865 if (is_xref_needed(p, rlist, rlist_len)) {
8870 fseek(fasm, pos, SEEK_SET);
8874 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8876 struct scanned_var *var;
8877 char line[256] = { 0, };
8886 // skip to next data section
8887 while (my_fgets(line, sizeof(line), fasm))
8892 if (*p == 0 || *p == ';')
8895 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8896 if (*p == 0 || *p == ';')
8899 if (*p != 's' || !IS_START(p, "segment para public"))
8905 if (p == NULL || !IS_START(p, "segment para public"))
8909 if (!IS_START(p, "'DATA'"))
8913 while (my_fgets(line, sizeof(line), fasm))
8918 no_identifier = my_isblank(*p);
8921 if (*p == 0 || *p == ';')
8924 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8925 words[wordc][0] = 0;
8926 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8927 if (*p == 0 || *p == ';') {
8933 if (wordc == 2 && IS(words[1], "ends"))
8938 if (no_identifier) {
8939 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8940 hg_ref_add(words[2]);
8944 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8945 // when this starts, we don't need anything from this section
8949 // check refs comment(s)
8950 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8953 if ((hg_var_cnt & 0xff) == 0) {
8954 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8955 * (hg_var_cnt + 0x100));
8956 my_assert_not(hg_vars, NULL);
8957 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8960 var = &hg_vars[hg_var_cnt++];
8961 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8963 // maybe already in seed header?
8964 var->pp = proto_parse(g_fhdr, var->name, 1);
8965 if (var->pp != NULL) {
8966 if (var->pp->is_fptr) {
8967 var->lmod = OPLM_DWORD;
8970 else if (var->pp->is_func)
8972 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8973 aerr("unhandled C type '%s' for '%s'\n",
8974 var->pp->type.name, var->name);
8980 if (IS(words[1], "dd")) {
8981 var->lmod = OPLM_DWORD;
8982 if (wordc >= 4 && IS(words[2], "offset"))
8983 hg_ref_add(words[3]);
8985 else if (IS(words[1], "dw"))
8986 var->lmod = OPLM_WORD;
8987 else if (IS(words[1], "db")) {
8988 var->lmod = OPLM_BYTE;
8989 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8990 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8994 else if (IS(words[1], "dq"))
8995 var->lmod = OPLM_QWORD;
8996 //else if (IS(words[1], "dt"))
8998 aerr("type '%s' not known\n", words[1]);
9006 static void set_label(int i, const char *name)
9012 p = strchr(name, ':');
9016 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
9017 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
9018 g_labels[i] = realloc(g_labels[i], len + 1);
9019 my_assert_not(g_labels[i], NULL);
9020 memcpy(g_labels[i], name, len);
9021 g_labels[i][len] = 0;
9030 static struct chunk_item *func_chunks;
9031 static int func_chunk_cnt;
9032 static int func_chunk_alloc;
9034 static void add_func_chunk(FILE *fasm, const char *name, int line)
9036 if (func_chunk_cnt >= func_chunk_alloc) {
9037 func_chunk_alloc *= 2;
9038 func_chunks = realloc(func_chunks,
9039 func_chunk_alloc * sizeof(func_chunks[0]));
9040 my_assert_not(func_chunks, NULL);
9042 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
9043 func_chunks[func_chunk_cnt].name = strdup(name);
9044 func_chunks[func_chunk_cnt].asmln = line;
9048 static int cmp_chunks(const void *p1, const void *p2)
9050 const struct chunk_item *c1 = p1, *c2 = p2;
9051 return strcmp(c1->name, c2->name);
9054 static void scan_ahead_for_chunks(FILE *fasm)
9064 oldpos = ftell(fasm);
9067 while (my_fgets(line, sizeof(line), fasm))
9078 // get rid of random tabs
9079 for (i = 0; line[i] != 0; i++)
9080 if (line[i] == '\t')
9083 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9086 next_word(words[0], sizeof(words[0]), p);
9087 if (words[0][0] == 0)
9088 aerr("missing name for func chunk?\n");
9090 add_func_chunk(fasm, words[0], asmln);
9092 else if (IS_START(p, "; sctend"))
9098 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9099 words[wordc][0] = 0;
9100 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9101 if (*p == 0 || *p == ';') {
9107 if (wordc == 2 && IS(words[1], "ends"))
9111 fseek(fasm, oldpos, SEEK_SET);
9115 int main(int argc, char *argv[])
9117 FILE *fout, *fasm, *frlist;
9118 struct parsed_data *pd = NULL;
9120 char **rlist = NULL;
9122 int rlist_alloc = 0;
9123 int func_chunks_used = 0;
9124 int func_chunks_sorted = 0;
9125 int func_chunk_i = -1;
9126 long func_chunk_ret = 0;
9127 int func_chunk_ret_ln = 0;
9128 int scanned_ahead = 0;
9130 char words[20][256];
9131 enum opr_lenmod lmod;
9132 char *sctproto = NULL;
9134 int pending_endp = 0;
9136 int skip_code_end = 0;
9137 int skip_warned = 0;
9150 for (arg = 1; arg < argc; arg++) {
9151 if (IS(argv[arg], "-v"))
9153 else if (IS(argv[arg], "-rf"))
9154 g_allow_regfunc = 1;
9155 else if (IS(argv[arg], "-uc"))
9156 g_allow_user_icall = 1;
9157 else if (IS(argv[arg], "-m"))
9159 else if (IS(argv[arg], "-hdr"))
9160 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
9165 if (argc < arg + 3) {
9166 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
9167 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
9169 " -hdr - header generation mode\n"
9170 " -rf - allow unannotated indirect calls\n"
9171 " -uc - allow ind. calls/refs to __usercall\n"
9172 " -m - allow multiple .text sections\n"
9173 "[rlist] is a file with function names to skip,"
9181 asmfn = argv[arg++];
9182 fasm = fopen(asmfn, "r");
9183 my_assert_not(fasm, NULL);
9185 hdrfn = argv[arg++];
9186 g_fhdr = fopen(hdrfn, "r");
9187 my_assert_not(g_fhdr, NULL);
9190 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9191 my_assert_not(rlist, NULL);
9192 // needs special handling..
9193 rlist[rlist_len++] = "__alloca_probe";
9195 func_chunk_alloc = 32;
9196 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9197 my_assert_not(func_chunks, NULL);
9199 memset(words, 0, sizeof(words));
9201 for (; arg < argc; arg++) {
9204 frlist = fopen(argv[arg], "r");
9205 my_assert_not(frlist, NULL);
9207 while (my_fgets(line, sizeof(line), frlist)) {
9209 if (*p == 0 || *p == ';')
9212 if (IS_START(p, "#if 0")
9213 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9217 else if (IS_START(p, "#endif"))
9224 p = next_word(words[0], sizeof(words[0]), p);
9225 if (words[0][0] == 0)
9228 if (rlist_len >= rlist_alloc) {
9229 rlist_alloc = rlist_alloc * 2 + 64;
9230 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9231 my_assert_not(rlist, NULL);
9233 rlist[rlist_len++] = strdup(words[0]);
9241 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9243 fout = fopen(argv[arg_out], "w");
9244 my_assert_not(fout, NULL);
9247 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9248 my_assert_not(g_eqs, NULL);
9250 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9251 g_label_refs[i].i = -1;
9252 g_label_refs[i].next = NULL;
9256 scan_variables(fasm, rlist, rlist_len);
9258 while (my_fgets(line, sizeof(line), fasm))
9267 // get rid of random tabs
9268 for (i = 0; line[i] != 0; i++)
9269 if (line[i] == '\t')
9274 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9275 goto do_pending_endp; // eww..
9277 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9279 static const char *attrs[] = {
9288 // parse IDA's attribute-list comment
9289 g_ida_func_attr = 0;
9292 for (; *p != 0; p = sskip(p)) {
9293 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9294 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9295 g_ida_func_attr |= 1 << i;
9296 p += strlen(attrs[i]);
9300 if (i == ARRAY_SIZE(attrs)) {
9301 anote("unparsed IDA attr: %s\n", p);
9304 if (IS(attrs[i], "fpd=")) {
9305 p = next_word(words[0], sizeof(words[0]), p);
9310 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9312 static const char *attrs[] = {
9317 // parse manual attribute-list comment
9318 g_sct_func_attr = 0;
9321 for (; *p != 0; p = sskip(p)) {
9322 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9323 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9324 g_sct_func_attr |= 1 << i;
9325 p += strlen(attrs[i]);
9332 // clear_sf=start,len (in dwords)
9333 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9334 &g_stack_clear_len, &j);
9336 // clear_regmask=<mask>
9337 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9339 anote("unparsed attr value: %s\n", p);
9344 else if (i == ARRAY_SIZE(attrs)) {
9345 anote("unparsed sct attr: %s\n", p);
9350 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9353 next_word(words[0], sizeof(words[0]), p);
9354 if (words[0][0] == 0)
9355 aerr("missing name for func chunk?\n");
9357 if (!scanned_ahead) {
9358 add_func_chunk(fasm, words[0], asmln);
9359 func_chunks_sorted = 0;
9362 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9364 if (func_chunk_i >= 0) {
9365 if (func_chunk_i < func_chunk_cnt
9366 && IS(func_chunks[func_chunk_i].name, g_func))
9368 // move on to next chunk
9369 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9371 aerr("seek failed for '%s' chunk #%d\n",
9372 g_func, func_chunk_i);
9373 asmln = func_chunks[func_chunk_i].asmln;
9377 if (func_chunk_ret == 0)
9378 aerr("no return from chunk?\n");
9379 fseek(fasm, func_chunk_ret, SEEK_SET);
9380 asmln = func_chunk_ret_ln;
9386 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9387 func_chunks_used = 1;
9389 if (IS_START(g_func, "sub_")) {
9390 unsigned long addr = strtoul(p, NULL, 16);
9391 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9392 if (addr > f_addr && !scanned_ahead) {
9393 //anote("scan_ahead caused by '%s', addr %lx\n",
9395 scan_ahead_for_chunks(fasm);
9397 func_chunks_sorted = 0;
9405 for (i = wordc; i < ARRAY_SIZE(words); i++)
9407 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9408 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9409 if (*p == 0 || *p == ';') {
9414 if (*p != 0 && *p != ';')
9415 aerr("too many words\n");
9417 if (skip_code_end) {
9422 // allow asm patches in comments
9424 if (IS_START(p, "; sctpatch:")) {
9426 if (*p == 0 || *p == ';')
9428 goto parse_words; // lame
9430 if (IS_START(p, "; sctproto:")) {
9431 sctproto = strdup(p + 11);
9433 else if (IS_START(p, "; sctend")) {
9438 else if (IS_START(p, "; sctskip_start")) {
9439 if (in_func && !g_skip_func) {
9441 ops[pi].op = OPP_ABORT;
9442 ops[pi].asmln = asmln;
9448 else if (IS_START(p, "; sctskip_end")) {
9456 awarn("wordc == 0?\n");
9460 // don't care about this:
9461 if (words[0][0] == '.'
9462 || IS(words[0], "include")
9463 || IS(words[0], "assume") || IS(words[1], "segment")
9464 || IS(words[0], "align"))
9470 // do delayed endp processing to collect switch jumptables
9472 if (in_func && !g_skip_func && !end && wordc >= 2
9473 && ((words[0][0] == 'd' && words[0][2] == 0)
9474 || (words[1][0] == 'd' && words[1][2] == 0)))
9477 if (words[1][0] == 'd' && words[1][2] == 0) {
9479 if (g_func_pd_cnt >= pd_alloc) {
9480 pd_alloc = pd_alloc * 2 + 16;
9481 g_func_pd = realloc(g_func_pd,
9482 sizeof(g_func_pd[0]) * pd_alloc);
9483 my_assert_not(g_func_pd, NULL);
9485 pd = &g_func_pd[g_func_pd_cnt];
9487 memset(pd, 0, sizeof(*pd));
9488 strcpy(pd->label, words[0]);
9489 pd->type = OPT_CONST;
9490 pd->lmod = lmod_from_directive(words[1]);
9496 anote("skipping alignment byte?\n");
9499 lmod = lmod_from_directive(words[0]);
9500 if (lmod != pd->lmod)
9501 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9504 if (pd->count_alloc < pd->count + wordc) {
9505 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9506 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9507 my_assert_not(pd->d, NULL);
9509 for (; i < wordc; i++) {
9510 if (IS(words[i], "offset")) {
9511 pd->type = OPT_OFFSET;
9514 p = strchr(words[i], ',');
9517 if (pd->type == OPT_OFFSET)
9518 pd->d[pd->count].u.label = strdup(words[i]);
9520 pd->d[pd->count].u.val = parse_number(words[i], 0);
9521 pd->d[pd->count].bt_i = -1;
9527 if (in_func && !g_skip_func) {
9529 gen_hdr(g_func, pi);
9531 gen_func(fout, g_fhdr, g_func, pi);
9536 g_ida_func_attr = 0;
9537 g_sct_func_attr = 0;
9538 g_stack_clear_start = 0;
9539 g_stack_clear_len = 0;
9545 func_chunks_used = 0;
9548 memset(&ops, 0, pi * sizeof(ops[0]));
9553 for (i = 0; i < g_func_pd_cnt; i++) {
9555 if (pd->type == OPT_OFFSET) {
9556 for (j = 0; j < pd->count; j++)
9557 free(pd->d[j].u.label);
9572 if (IS(words[1], "proc")) {
9574 aerr("proc '%s' while in_func '%s'?\n",
9577 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9579 strcpy(g_func, words[0]);
9580 set_label(0, words[0]);
9585 if (IS(words[1], "endp"))
9588 aerr("endp '%s' while not in_func?\n", words[0]);
9589 if (!IS(g_func, words[0]))
9590 aerr("endp '%s' while in_func '%s'?\n",
9593 aerr("endp '%s' while skipping code\n", words[0]);
9595 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9596 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
9602 if (!g_skip_func && func_chunks_used) {
9603 // start processing chunks
9604 struct chunk_item *ci, key = { g_func, 0 };
9606 func_chunk_ret = ftell(fasm);
9607 func_chunk_ret_ln = asmln;
9608 if (!func_chunks_sorted) {
9609 qsort(func_chunks, func_chunk_cnt,
9610 sizeof(func_chunks[0]), cmp_chunks);
9611 func_chunks_sorted = 1;
9613 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9614 sizeof(func_chunks[0]), cmp_chunks);
9616 aerr("'%s' needs chunks, but none found\n", g_func);
9617 func_chunk_i = ci - func_chunks;
9618 for (; func_chunk_i > 0; func_chunk_i--)
9619 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9622 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9624 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9625 asmln = func_chunks[func_chunk_i].asmln;
9633 if (wordc == 2 && IS(words[1], "ends")) {
9637 goto do_pending_endp;
9641 // scan for next text segment
9642 while (my_fgets(line, sizeof(line), fasm)) {
9645 if (*p == 0 || *p == ';')
9648 if (strstr(p, "segment para public 'CODE' use32"))
9655 p = strchr(words[0], ':');
9657 set_label(pi, words[0]);
9661 if (!in_func || g_skip_func || skip_code) {
9662 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9664 anote("skipping from '%s'\n", g_labels[pi]);
9668 g_labels[pi] = NULL;
9672 if (wordc > 1 && IS(words[1], "="))
9675 aerr("unhandled equ, wc=%d\n", wordc);
9676 if (g_eqcnt >= eq_alloc) {
9678 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9679 my_assert_not(g_eqs, NULL);
9682 len = strlen(words[0]);
9683 if (len > sizeof(g_eqs[0].name) - 1)
9684 aerr("equ name too long: %d\n", len);
9685 strcpy(g_eqs[g_eqcnt].name, words[0]);
9687 if (!IS(words[3], "ptr"))
9688 aerr("unhandled equ\n");
9689 if (IS(words[2], "dword"))
9690 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9691 else if (IS(words[2], "word"))
9692 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9693 else if (IS(words[2], "byte"))
9694 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9695 else if (IS(words[2], "qword"))
9696 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9698 aerr("bad lmod: '%s'\n", words[2]);
9700 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9705 if (pi >= ARRAY_SIZE(ops))
9706 aerr("too many ops\n");
9708 parse_op(&ops[pi], words, wordc);
9710 ops[pi].datap = sctproto;
9725 // vim:ts=2:shiftwidth=2:expandtab