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), /* enough to do 32bit for this op */
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_regmask_rm;
332 static int g_skip_func;
333 static int g_allow_regfunc;
334 static int g_allow_user_icall;
335 static int g_quiet_pp;
336 static int g_header_mode;
338 #define ferr(op_, fmt, ...) do { \
339 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
340 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
344 #define fnote(op_, fmt, ...) \
345 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
346 dump_op(op_), ##__VA_ARGS__)
348 #define ferr_assert(op_, cond) do { \
349 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
352 const char *regs_r32[] = {
353 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
354 // not r32, but list here for easy parsing and printing
355 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
356 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
358 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
359 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
360 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
366 xMM0, xMM1, xMM2, xMM3, // mmx
367 xMM4, xMM5, xMM6, xMM7,
368 xST0, xST1, xST2, xST3, // x87
369 xST4, xST5, xST6, xST7,
372 #define mxAX (1 << xAX)
373 #define mxCX (1 << xCX)
374 #define mxDX (1 << xDX)
375 #define mxSP (1 << xSP)
376 #define mxST0 (1 << xST0)
377 #define mxST1 (1 << xST1)
378 #define mxST1_0 (mxST1 | mxST0)
379 #define mxST7_2 (0xfc << xST0)
380 #define mxSTa (0xff << xST0)
382 // possible basic comparison types (without inversion)
383 enum parsed_flag_op {
387 PFO_BE, // 6 CF=1||ZF=1
391 PFO_LE, // e ZF=1||SF!=OF
394 #define PFOB_O (1 << PFO_O)
395 #define PFOB_C (1 << PFO_C)
396 #define PFOB_Z (1 << PFO_Z)
397 #define PFOB_S (1 << PFO_S)
399 static const char *parsed_flag_op_names[] = {
400 "o", "c", "z", "be", "s", "p", "l", "le"
403 static int char_array_i(const char *array[], size_t len, const char *s)
407 for (i = 0; i < len; i++)
414 static void printf_number(char *buf, size_t buf_size,
415 unsigned long number)
417 // output in C-friendly form
418 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
421 static int check_segment_prefix(const char *s)
423 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
427 case 'c': return SEG_CS;
428 case 'd': return SEG_DS;
429 case 's': return SEG_SS;
430 case 'e': return SEG_ES;
431 case 'f': return SEG_FS;
432 case 'g': return SEG_GS;
437 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
441 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
443 *reg_lmod = OPLM_QWORD;
447 *reg_lmod = OPLM_DWORD;
450 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
452 *reg_lmod = OPLM_WORD;
455 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
457 *reg_lmod = OPLM_BYTE;
460 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
462 *reg_lmod = OPLM_BYTE;
469 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
471 enum opr_lenmod lmod;
484 while (my_isblank(*s))
486 for (; my_issep(*s); d++, s++)
488 while (my_isblank(*s))
492 // skip '?s:' prefixes
493 if (check_segment_prefix(s))
496 s = next_idt(w, sizeof(w), s);
501 reg = parse_reg(&lmod, w);
503 *regmask |= 1 << reg;
507 if ('0' <= w[0] && w[0] <= '9') {
508 number = parse_number(w, 0);
509 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
513 // probably some label/identifier - pass
516 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
520 strcpy(name, cvtbuf);
525 static int is_reg_in_str(const char *s)
529 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
532 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
533 if (!strncmp(s, regs_r32[i], 3))
539 static const char *parse_stack_el(const char *name, char *extra_reg,
540 int *base_val, int early_try)
542 const char *p, *p2, *s;
548 if (g_bp_frame || early_try)
551 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
553 if (extra_reg != NULL) {
554 strncpy(extra_reg, name, 3);
559 if (IS_START(p, "ebp+")) {
563 if (p2 != NULL && is_reg_in_str(p)) {
564 if (extra_reg != NULL) {
565 strncpy(extra_reg, p, p2 - p);
566 extra_reg[p2 - p] = 0;
571 if (!('0' <= *p && *p <= '9'))
578 if (!IS_START(name, "esp+"))
584 if (is_reg_in_str(s)) {
585 if (extra_reg != NULL) {
586 strncpy(extra_reg, s, p - s);
587 extra_reg[p - s] = 0;
592 aerr("%s IDA stackvar not set?\n", __func__);
594 if (!('0' <= *s && *s <= '9')) {
595 aerr("%s IDA stackvar offset not set?\n", __func__);
598 if (s[0] == '0' && s[1] == 'x')
601 if (len < sizeof(buf) - 1) {
602 strncpy(buf, s, len);
605 val = strtol(buf, &endp, 16);
606 if (val == 0 || *endp != 0 || errno != 0) {
607 aerr("%s num parse fail for '%s'\n", __func__, buf);
616 if ('0' <= *p && *p <= '9')
619 if (base_val != NULL)
624 static int guess_lmod_from_name(struct parsed_opr *opr)
626 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
627 opr->lmod = OPLM_DWORD;
630 if (IS_START(opr->name, "word_")) {
631 opr->lmod = OPLM_WORD;
634 if (IS_START(opr->name, "byte_")) {
635 opr->lmod = OPLM_BYTE;
638 if (IS_START(opr->name, "qword_")) {
639 opr->lmod = OPLM_QWORD;
645 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
646 const struct parsed_type *c_type)
648 static const char *qword_types[] = {
649 "uint64_t", "int64_t", "__int64",
651 static const char *dword_types[] = {
652 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
653 "WPARAM", "LPARAM", "UINT", "__int32",
654 "LONG", "HIMC", "BOOL", "size_t",
657 static const char *word_types[] = {
658 "uint16_t", "int16_t", "_WORD", "WORD",
659 "unsigned __int16", "__int16",
661 static const char *byte_types[] = {
662 "uint8_t", "int8_t", "char",
663 "unsigned __int8", "__int8", "BYTE", "_BYTE",
665 // structures.. deal the same as with _UNKNOWN for now
671 if (c_type->is_ptr) {
676 n = skip_type_mod(c_type->name);
678 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
679 if (IS(n, dword_types[i])) {
685 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
686 if (IS(n, word_types[i])) {
692 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
693 if (IS(n, byte_types[i])) {
699 for (i = 0; i < ARRAY_SIZE(qword_types); i++) {
700 if (IS(n, qword_types[i])) {
709 static char *default_cast_to(char *buf, size_t buf_size,
710 struct parsed_opr *opr)
714 if (!opr->is_ptr || strchr(opr->name, '['))
716 if (opr->pp == NULL || opr->pp->type.name == NULL
719 snprintf(buf, buf_size, "%s", "(void *)");
723 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
727 static enum opr_type lmod_from_directive(const char *d)
731 else if (IS(d, "dw"))
733 else if (IS(d, "db"))
736 aerr("unhandled directive: '%s'\n", d);
740 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
746 *regmask |= 1 << reg;
749 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
752 static int parse_operand(struct parsed_opr *opr,
753 int *regmask, int *regmask_indirect,
754 char words[16][256], int wordc, int w, unsigned int op_flags)
756 const struct parsed_proto *pp = NULL;
757 enum opr_lenmod tmplmod;
758 unsigned long number;
766 aerr("parse_operand w %d, wordc %d\n", w, wordc);
770 for (i = w; i < wordc; i++) {
771 len = strlen(words[i]);
772 if (words[i][len - 1] == ',') {
773 words[i][len - 1] = 0;
779 wordc_in = wordc - w;
781 if ((op_flags & OPF_JMP) && wordc_in > 0
782 && !('0' <= words[w][0] && words[w][0] <= '9'))
784 const char *label = NULL;
786 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
787 && IS(words[w + 1], "ptr"))
788 label = words[w + 2];
789 else if (wordc_in == 2 && IS(words[w], "short"))
790 label = words[w + 1];
791 else if (wordc_in == 1
792 && strchr(words[w], '[') == NULL
793 && parse_reg(&tmplmod, words[w]) < 0)
797 opr->type = OPT_LABEL;
798 ret = check_segment_prefix(label);
803 strcpy(opr->name, label);
809 if (IS(words[w + 1], "ptr")) {
810 if (IS(words[w], "dword"))
811 opr->lmod = OPLM_DWORD;
812 else if (IS(words[w], "word"))
813 opr->lmod = OPLM_WORD;
814 else if (IS(words[w], "byte"))
815 opr->lmod = OPLM_BYTE;
816 else if (IS(words[w], "qword"))
817 opr->lmod = OPLM_QWORD;
819 aerr("type parsing failed\n");
821 wordc_in = wordc - w;
826 if (IS(words[w], "offset")) {
827 opr->type = OPT_OFFSET;
828 opr->lmod = OPLM_DWORD;
829 strcpy(opr->name, words[w + 1]);
830 pp = proto_parse(g_fhdr, opr->name, 1);
833 if (IS(words[w], "(offset")) {
834 p = strchr(words[w + 1], ')');
836 aerr("parse of bracketed offset failed\n");
838 opr->type = OPT_OFFSET;
839 strcpy(opr->name, words[w + 1]);
845 aerr("parse_operand 1 word expected\n");
847 ret = check_segment_prefix(words[w]);
850 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
851 if (ret == SEG_FS && IS(words[w], "0"))
854 strcpy(opr->name, words[w]);
856 if (words[w][0] == '[') {
857 opr->type = OPT_REGMEM;
858 ret = sscanf(words[w], "[%[^]]]", opr->name);
860 aerr("[] parse failure\n");
862 parse_indmode(opr->name, regmask_indirect, 1);
863 if (opr->lmod == OPLM_UNSPEC
864 && parse_stack_el(opr->name, NULL, NULL, 1))
867 struct parsed_equ *eq =
868 equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
870 opr->lmod = eq->lmod;
872 // might be unaligned access
873 g_func_lmods |= 1 << OPLM_BYTE;
877 else if (strchr(words[w], '[')) {
879 p = strchr(words[w], '[');
880 opr->type = OPT_REGMEM;
881 parse_indmode(p, regmask_indirect, 0);
882 strncpy(buf, words[w], p - words[w]);
883 buf[p - words[w]] = 0;
884 pp = proto_parse(g_fhdr, buf, 1);
887 else if (('0' <= words[w][0] && words[w][0] <= '9')
888 || words[w][0] == '-')
890 number = parse_number(words[w], 0);
891 opr->type = OPT_CONST;
893 printf_number(opr->name, sizeof(opr->name), number);
897 ret = parse_reg(&tmplmod, opr->name);
899 setup_reg_opr(opr, ret, tmplmod, regmask);
903 // most likely var in data segment
904 opr->type = OPT_LABEL;
905 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
909 if (pp->is_fptr || pp->is_func) {
910 opr->lmod = OPLM_DWORD;
914 tmplmod = OPLM_UNSPEC;
915 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
916 anote("unhandled C type '%s' for '%s'\n",
917 pp->type.name, opr->name);
919 if (opr->lmod == OPLM_UNSPEC) {
921 opr->type_from_var = 1;
923 else if (opr->lmod != tmplmod) {
924 opr->size_mismatch = 1;
925 if (tmplmod < opr->lmod)
928 opr->is_ptr = pp->type.is_ptr;
930 opr->is_array = pp->type.is_array;
934 if (opr->lmod == OPLM_UNSPEC)
935 guess_lmod_from_name(opr);
939 static const struct {
944 { "repe", OPF_REP|OPF_REPZ },
945 { "repz", OPF_REP|OPF_REPZ },
946 { "repne", OPF_REP|OPF_REPNZ },
947 { "repnz", OPF_REP|OPF_REPNZ },
948 { "lock", OPF_LOCK }, // ignored for now..
951 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
953 static const struct {
956 unsigned short minopr;
957 unsigned short maxopr;
960 unsigned char pfo_inv;
962 { "nop", OP_NOP, 0, 0, 0 },
963 { "push", OP_PUSH, 1, 1, 0 },
964 { "pop", OP_POP, 1, 1, OPF_DATA },
965 { "pusha",OP_PUSHA, 0, 0, 0 },
966 { "popa", OP_POPA, 0, 0, OPF_DATA },
967 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
968 { "mov" , OP_MOV, 2, 2, OPF_DATA },
969 { "lea", OP_LEA, 2, 2, OPF_DATA },
970 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
971 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
972 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
973 { "not", OP_NOT, 1, 1, OPF_DATA },
974 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
975 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
976 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
977 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
978 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
979 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
980 { "stosb",OP_STOS, 0, 0, OPF_DATA },
981 { "stosw",OP_STOS, 0, 0, OPF_DATA },
982 { "stosd",OP_STOS, 0, 0, OPF_DATA },
983 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
984 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
985 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
986 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
987 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
988 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
989 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
990 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
991 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
992 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
993 { "cld", OP_CLD, 0, 0, OPF_DATA },
994 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
995 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
996 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
997 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
998 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
999 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
1000 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
1001 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
1002 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
1003 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
1004 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
1005 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
1006 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
1007 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1008 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1009 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1010 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1011 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
1012 { "bsr", OP_BSR, 2, 2, OPF_DATA|OPF_FLAGS },
1013 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
1014 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
1015 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
1016 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
1017 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
1018 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
1019 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
1020 { "test", OP_TEST, 2, 2, OPF_FLAGS },
1021 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
1022 { "retn", OP_RET, 0, 1, OPF_TAIL },
1023 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
1024 { "jmp", OP_JMP, 1, 1, OPF_JMP },
1025 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
1026 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
1027 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
1028 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
1029 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
1030 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
1031 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
1032 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1033 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1034 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
1035 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
1036 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
1037 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
1038 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1039 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1040 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1041 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1042 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1043 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1044 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1045 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1046 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1047 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1048 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1049 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1050 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1051 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1052 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1053 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1054 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1055 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1056 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1057 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1058 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1059 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1060 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1061 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1062 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1063 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1064 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1065 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1066 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1067 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1068 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1069 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1070 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1071 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1072 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1073 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1074 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1075 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1076 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1077 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1078 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1079 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1080 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1081 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1082 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1083 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1084 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1086 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1087 { "fild", OP_FILD, 1, 1, OPF_FPUSH|OPF_FINT },
1088 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1089 { "fldl2t", OP_FLDc, 0, 0, OPF_FPUSH },
1090 { "fldl2e", OP_FLDc, 0, 0, OPF_FPUSH },
1091 { "fldpi", OP_FLDc, 0, 0, OPF_FPUSH },
1092 { "fldlg2", OP_FLDc, 0, 0, OPF_FPUSH },
1093 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1094 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1095 { "fst", OP_FST, 1, 1, 0 },
1096 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1097 { "fist", OP_FIST, 1, 1, OPF_FINT },
1098 { "fistp", OP_FIST, 1, 1, OPF_FPOP|OPF_FINT },
1099 { "fadd", OP_FADD, 0, 2, 0 },
1100 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1101 { "fdiv", OP_FDIV, 0, 2, 0 },
1102 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1103 { "fmul", OP_FMUL, 0, 2, 0 },
1104 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1105 { "fsub", OP_FSUB, 0, 2, 0 },
1106 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1107 { "fdivr", OP_FDIVR, 0, 2, 0 },
1108 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1109 { "fsubr", OP_FSUBR, 0, 2, 0 },
1110 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1111 { "fiadd", OP_FIADD, 1, 1, OPF_FINT },
1112 { "fidiv", OP_FIDIV, 1, 1, OPF_FINT },
1113 { "fimul", OP_FIMUL, 1, 1, OPF_FINT },
1114 { "fisub", OP_FISUB, 1, 1, OPF_FINT },
1115 { "fidivr", OP_FIDIVR, 1, 1, OPF_FINT },
1116 { "fisubr", OP_FISUBR, 1, 1, OPF_FINT },
1117 { "fcom", OP_FCOM, 0, 1, 0 },
1118 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1119 { "fcompp", OP_FCOM, 0, 0, OPF_FPOPP },
1120 { "fucom", OP_FCOM, 0, 1, 0 },
1121 { "fucomp", OP_FCOM, 0, 1, OPF_FPOP },
1122 { "fucompp",OP_FCOM, 0, 0, OPF_FPOPP },
1123 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1124 { "fchs", OP_FCHS, 0, 0, 0 },
1125 { "fcos", OP_FCOS, 0, 0, 0 },
1126 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1127 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1128 { "fsin", OP_FSIN, 0, 0, 0 },
1129 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1130 { "fxch", OP_FXCH, 1, 1, 0 },
1131 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1133 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1134 { "movq", OP_MOV, 2, 2, OPF_DATA },
1135 // pseudo-ops for lib calls
1136 { "_allshl",OPP_ALLSHL },
1137 { "_allshr",OPP_ALLSHR },
1138 { "_ftol", OPP_FTOL },
1139 { "_CIpow", OPP_CIPOW },
1140 { "abort", OPP_ABORT },
1145 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1147 enum opr_lenmod lmod = OPLM_UNSPEC;
1148 int prefix_flags = 0;
1156 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1157 if (IS(words[w], pref_table[i].name)) {
1158 prefix_flags = pref_table[i].flags;
1165 aerr("lone prefix: '%s'\n", words[0]);
1170 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1171 if (IS(words[w], op_table[i].name))
1175 if (i == ARRAY_SIZE(op_table)) {
1177 aerr("unhandled op: '%s'\n", words[0]);
1182 op->op = op_table[i].op;
1183 op->flags = op_table[i].flags | prefix_flags;
1184 op->pfo = op_table[i].pfo;
1185 op->pfo_inv = op_table[i].pfo_inv;
1186 op->regmask_src = op->regmask_dst = 0;
1189 if (op->op == OP_UD2)
1192 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1193 if (opr >= op_table[i].minopr && w >= wordc)
1196 regmask = regmask_ind = 0;
1197 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1198 words, wordc, w, op->flags);
1200 if (opr == 0 && (op->flags & OPF_DATA))
1201 op->regmask_dst = regmask;
1203 op->regmask_src |= regmask;
1204 op->regmask_src |= regmask_ind;
1206 if (op->operand[opr].lmod != OPLM_UNSPEC)
1207 g_func_lmods |= 1 << op->operand[opr].lmod;
1211 aerr("parse_op %s incomplete: %d/%d\n",
1212 words[0], w, wordc);
1215 op->operand_cnt = opr;
1216 if (!strncmp(op_table[i].name, "set", 3))
1217 op->operand[0].lmod = OPLM_BYTE;
1220 // first operand is not dst
1223 op->regmask_src |= op->regmask_dst;
1224 op->regmask_dst = 0;
1227 // first operand is src too
1240 op->regmask_src |= op->regmask_dst;
1245 op->regmask_src |= op->regmask_dst;
1246 op->regmask_dst |= op->regmask_src;
1252 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1253 && op->operand[0].lmod == op->operand[1].lmod
1254 && op->operand[0].reg == op->operand[1].reg
1255 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1257 op->regmask_src = 0;
1260 op->regmask_src |= op->regmask_dst;
1263 // ops with implicit argumets
1265 op->operand_cnt = 2;
1266 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1267 op->regmask_dst = op->regmask_src;
1268 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1272 op->operand_cnt = 2;
1273 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1274 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1280 if (words[op_w][4] == 'b')
1282 else if (words[op_w][4] == 'w')
1284 else if (words[op_w][4] == 'd')
1287 op->regmask_src = 0;
1288 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1289 OPLM_DWORD, &op->regmask_src);
1290 op->regmask_dst = op->regmask_src;
1291 setup_reg_opr(&op->operand[j++], xAX, lmod,
1292 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1293 if (op->flags & OPF_REP) {
1294 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1295 op->regmask_dst |= 1 << xCX;
1297 op->operand_cnt = j;
1302 if (words[op_w][4] == 'b')
1304 else if (words[op_w][4] == 'w')
1306 else if (words[op_w][4] == 'd')
1309 op->regmask_src = 0;
1310 // note: lmod is not correct, don't have where to place it
1311 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1312 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1313 if (op->flags & OPF_REP)
1314 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1315 op->operand_cnt = j;
1316 op->regmask_dst = op->regmask_src;
1320 op->regmask_dst = 1 << xCX;
1323 op->operand_cnt = 2;
1324 op->regmask_src = 1 << xCX;
1325 op->operand[1].type = OPT_REG;
1326 op->operand[1].reg = xCX;
1327 op->operand[1].lmod = OPLM_DWORD;
1331 if (op->operand_cnt == 2) {
1332 if (op->operand[0].type != OPT_REG)
1333 aerr("reg expected\n");
1334 op->regmask_src |= 1 << op->operand[0].reg;
1336 if (op->operand_cnt != 1)
1341 if (op->operand[0].lmod == OPLM_UNSPEC)
1342 op->operand[0].lmod = OPLM_DWORD;
1343 op->regmask_src = mxAX | op->regmask_dst;
1344 op->regmask_dst = mxAX;
1345 if (op->operand[0].lmod != OPLM_BYTE)
1346 op->regmask_dst |= mxDX;
1351 // we could set up operands for edx:eax, but there is no real need to
1352 // (see is_opr_modified())
1353 if (op->operand[0].lmod == OPLM_UNSPEC)
1354 op->operand[0].lmod = OPLM_DWORD;
1355 op->regmask_src = mxAX | op->regmask_dst;
1356 op->regmask_dst = mxAX;
1357 if (op->operand[0].lmod != OPLM_BYTE) {
1358 op->regmask_src |= mxDX;
1359 op->regmask_dst |= mxDX;
1368 op->regmask_src |= op->regmask_dst;
1369 if (op->operand[1].lmod == OPLM_UNSPEC)
1370 op->operand[1].lmod = OPLM_BYTE;
1375 op->regmask_src |= op->regmask_dst;
1376 if (op->operand[2].lmod == OPLM_UNSPEC)
1377 op->operand[2].lmod = OPLM_BYTE;
1381 op->regmask_src |= op->regmask_dst;
1382 op->regmask_dst = 0;
1383 if (op->operand[0].lmod == OPLM_UNSPEC
1384 && (op->operand[0].type == OPT_CONST
1385 || op->operand[0].type == OPT_OFFSET
1386 || op->operand[0].type == OPT_LABEL))
1387 op->operand[0].lmod = OPLM_DWORD;
1393 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1394 && op->operand[0].lmod == op->operand[1].lmod
1395 && op->operand[0].reg == op->operand[1].reg
1396 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1398 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1399 op->regmask_src = op->regmask_dst = 0;
1404 if (op->operand[0].type == OPT_REG
1405 && op->operand[1].type == OPT_REGMEM)
1408 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1409 if (IS(buf, op->operand[1].name))
1410 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1415 // needed because of OPF_DATA
1416 op->regmask_src = op->regmask_dst;
1417 // trashed regs must be explicitly detected later
1418 op->regmask_dst = 0;
1422 op->regmask_dst = (1 << xBP) | (1 << xSP);
1423 op->regmask_src = 1 << xBP;
1428 op->regmask_dst |= mxST0;
1432 op->regmask_dst |= mxST0;
1433 if (IS(words[op_w] + 3, "1"))
1434 op->operand[0].val = X87_CONST_1;
1435 else if (IS(words[op_w] + 3, "l2t"))
1436 op->operand[0].val = X87_CONST_L2T;
1437 else if (IS(words[op_w] + 3, "l2e"))
1438 op->operand[0].val = X87_CONST_L2E;
1439 else if (IS(words[op_w] + 3, "pi"))
1440 op->operand[0].val = X87_CONST_PI;
1441 else if (IS(words[op_w] + 3, "lg2"))
1442 op->operand[0].val = X87_CONST_LG2;
1443 else if (IS(words[op_w] + 3, "ln2"))
1444 op->operand[0].val = X87_CONST_LN2;
1445 else if (IS(words[op_w] + 3, "z"))
1446 op->operand[0].val = X87_CONST_Z;
1448 aerr("fld what?\n");
1453 op->regmask_src |= mxST0;
1462 op->regmask_src |= mxST0;
1463 if (op->operand_cnt == 2)
1464 op->regmask_src |= op->regmask_dst;
1465 else if (op->operand_cnt == 1) {
1466 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1467 op->operand[0].type = OPT_REG;
1468 op->operand[0].lmod = OPLM_QWORD;
1469 op->operand[0].reg = xST0;
1470 op->regmask_dst |= mxST0;
1473 // IDA doesn't use this
1474 aerr("no operands?\n");
1488 op->regmask_src |= mxST0;
1489 op->regmask_dst |= mxST0;
1494 op->regmask_src |= mxST0 | mxST1;
1495 op->regmask_dst |= mxST0;
1503 op->regmask_src |= mxST0;
1504 if (op->operand_cnt == 0) {
1505 op->operand_cnt = 1;
1506 op->operand[0].type = OPT_REG;
1507 op->operand[0].lmod = OPLM_QWORD;
1508 op->operand[0].reg = xST1;
1509 op->regmask_src |= mxST1;
1517 if (op->operand[0].type == OPT_REG
1518 && op->operand[1].type == OPT_CONST)
1520 struct parsed_opr *op1 = &op->operand[1];
1521 if ((op->op == OP_AND && op1->val == 0)
1524 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1525 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1527 op->regmask_src = 0;
1532 static const char *op_name(struct parsed_op *po)
1534 static char buf[16];
1538 if (po->op == OP_JCC || po->op == OP_SCC) {
1540 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1543 strcpy(p, parsed_flag_op_names[po->pfo]);
1547 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1548 if (op_table[i].op == po->op)
1549 return op_table[i].name;
1555 static const char *dump_op(struct parsed_op *po)
1557 static char out[128];
1564 snprintf(out, sizeof(out), "%s", op_name(po));
1565 for (i = 0; i < po->operand_cnt; i++) {
1569 snprintf(p, sizeof(out) - (p - out),
1570 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1571 po->operand[i].name);
1577 static const char *lmod_type_u(struct parsed_op *po,
1578 enum opr_lenmod lmod)
1590 ferr(po, "invalid lmod: %d\n", lmod);
1591 return "(_invalid_)";
1595 static const char *lmod_cast_u(struct parsed_op *po,
1596 enum opr_lenmod lmod)
1608 ferr(po, "invalid lmod: %d\n", lmod);
1609 return "(_invalid_)";
1613 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1614 enum opr_lenmod lmod)
1626 ferr(po, "invalid lmod: %d\n", lmod);
1627 return "(_invalid_)";
1631 static const char *lmod_cast_s(struct parsed_op *po,
1632 enum opr_lenmod lmod)
1644 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1645 return "(_invalid_)";
1649 static const char *lmod_cast(struct parsed_op *po,
1650 enum opr_lenmod lmod, int is_signed)
1653 lmod_cast_s(po, lmod) :
1654 lmod_cast_u(po, lmod);
1657 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1669 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1674 static const char *opr_name(struct parsed_op *po, int opr_num)
1676 if (opr_num >= po->operand_cnt)
1677 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1678 return po->operand[opr_num].name;
1681 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1683 if (opr_num >= po->operand_cnt)
1684 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1685 if (po->operand[opr_num].type != OPT_CONST)
1686 ferr(po, "opr %d: const expected\n", opr_num);
1687 return po->operand[opr_num].val;
1690 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1692 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1693 ferr(po, "invalid reg: %d\n", popr->reg);
1694 return regs_r32[popr->reg];
1697 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1699 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1701 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1703 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1705 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1710 *is_signed = cast[1] == 's' ? 1 : 0;
1714 static int check_deref_cast(const char *cast, int *bits)
1716 if (IS_START(cast, "*(u8 *)"))
1718 else if (IS_START(cast, "*(u16 *)"))
1720 else if (IS_START(cast, "*(u32 *)"))
1722 else if (IS_START(cast, "*(u64 *)"))
1730 // cast1 is the "final" cast
1731 static const char *simplify_cast(const char *cast1, const char *cast2)
1733 static char buf[256];
1741 if (IS(cast1, cast2))
1744 if (check_simple_cast(cast1, &bits1, &s1) == 0
1745 && check_simple_cast(cast2, &bits2, &s2) == 0)
1750 if (check_simple_cast(cast1, &bits1, &s1) == 0
1751 && check_deref_cast(cast2, &bits2) == 0)
1753 if (bits1 == bits2) {
1754 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1759 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1762 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1766 static const char *simplify_cast_num(const char *cast, unsigned int val)
1768 if (IS(cast, "(u8)") && val < 0x100)
1770 if (IS(cast, "(s8)") && val < 0x80)
1772 if (IS(cast, "(u16)") && val < 0x10000)
1774 if (IS(cast, "(s16)") && val < 0x8000)
1776 if (IS(cast, "(s32)") && val < 0x80000000)
1782 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1791 namelen = strlen(name);
1793 p = strpbrk(name, "+-");
1797 ferr(po, "equ parse failed for '%s'\n", name);
1800 *extra_offs = strtol(p, &endp, 16);
1801 if (*endp != 0 || errno != 0)
1802 ferr(po, "equ parse failed for '%s'\n", name);
1805 for (i = 0; i < g_eqcnt; i++)
1806 if (strncmp(g_eqs[i].name, name, namelen) == 0
1807 && g_eqs[i].name[namelen] == 0)
1811 ferr(po, "unresolved equ name: '%s'\n", name);
1818 static int is_stack_access(struct parsed_op *po,
1819 const struct parsed_opr *popr)
1821 return (parse_stack_el(popr->name, NULL, NULL, 0)
1822 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1823 && IS_START(popr->name, "ebp")));
1826 static void parse_stack_access(struct parsed_op *po,
1827 const char *name, char *ofs_reg, int *offset_out,
1828 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1830 const char *bp_arg = "";
1831 const char *p = NULL;
1832 struct parsed_equ *eq;
1839 if (IS_START(name, "ebp-")
1840 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1843 if (IS_START(p, "0x"))
1846 offset = strtoul(p, &endp, 16);
1849 if (*endp != 0 || errno != 0)
1850 ferr(po, "ebp- parse of '%s' failed\n", name);
1853 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1854 eq = equ_find(po, bp_arg, &offset);
1856 ferr(po, "detected but missing eq\n");
1857 offset += eq->offset;
1860 if (!strncmp(name, "ebp", 3))
1863 // yes it sometimes LEAs ra for compares..
1864 if (!is_lea && ofs_reg[0] == 0
1865 && stack_ra <= offset && offset < stack_ra + 4)
1867 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1870 *offset_out = offset;
1872 *stack_ra_out = stack_ra;
1874 *bp_arg_out = bp_arg;
1877 static int parse_stack_esp_offset(struct parsed_op *po,
1878 const char *name, int *offset_out)
1880 char ofs_reg[16] = { 0, };
1881 struct parsed_equ *eq;
1887 if (strstr(name, "esp") == NULL)
1889 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1890 if (bp_arg == NULL) {
1891 // just plain offset?
1892 if (!IS_START(name, "esp+"))
1895 offset = strtol(name + 4, &endp, 0);
1896 if (endp == NULL || *endp != 0 || errno != 0)
1898 *offset_out = offset;
1902 if (ofs_reg[0] != 0)
1904 eq = equ_find(po, bp_arg, &offset);
1906 ferr(po, "detected but missing eq\n");
1907 offset += eq->offset;
1908 *offset_out = base_val + offset;
1912 static int stack_frame_access(struct parsed_op *po,
1913 struct parsed_opr *popr, char *buf, size_t buf_size,
1914 const char *name, const char *cast, int is_src, int is_lea)
1916 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1917 const char *prefix = "";
1918 const char *bp_arg = NULL;
1919 char ofs_reg[16] = { 0, };
1920 int i, arg_i, arg_s;
1927 if (g_bp_frame && (po->flags & OPF_EBP_S)
1928 && !(po->regmask_src & mxSP))
1929 ferr(po, "stack_frame_access while ebp is scratch\n");
1931 parse_stack_access(po, name, ofs_reg, &offset,
1932 &stack_ra, &bp_arg, is_lea);
1934 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1936 if (offset > stack_ra)
1938 arg_i = (offset - stack_ra - 4) / 4;
1939 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1941 if (g_func_pp->is_vararg
1942 && arg_i == g_func_pp->argc_stack && is_lea)
1944 // should be va_list
1947 snprintf(buf, buf_size, "%sap", cast);
1950 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1951 offset, bp_arg, arg_i);
1953 if (ofs_reg[0] != 0)
1954 ferr(po, "offset reg on arg access?\n");
1956 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1957 if (g_func_pp->arg[i].reg != NULL)
1963 if (i == g_func_pp->argc)
1964 ferr(po, "arg %d not in prototype?\n", arg_i);
1966 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1973 ferr(po, "lea/byte to arg?\n");
1974 if (is_src && (offset & 3) == 0)
1975 snprintf(buf, buf_size, "%sa%d",
1976 simplify_cast(cast, "(u8)"), i + 1);
1978 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1979 cast, offset & 3, i + 1);
1984 ferr(po, "lea/word to arg?\n");
1989 ferr(po, "problematic arg store\n");
1990 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1991 simplify_cast(cast, "*(u16 *)"), i + 1);
1994 ferr(po, "unaligned arg word load\n");
1996 else if (is_src && (offset & 2) == 0)
1997 snprintf(buf, buf_size, "%sa%d",
1998 simplify_cast(cast, "(u16)"), i + 1);
2000 snprintf(buf, buf_size, "%s%sWORD(a%d)",
2001 cast, (offset & 2) ? "HI" : "LO", i + 1);
2013 snprintf(buf, buf_size, "(u32)&a%d + %d",
2016 ferr(po, "unaligned arg store\n");
2018 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
2019 snprintf(buf, buf_size, "%s(a%d >> %d)",
2020 prefix, i + 1, (offset & 3) * 8);
2024 snprintf(buf, buf_size, "%s%sa%d",
2025 prefix, is_lea ? "&" : "", i + 1);
2030 ferr_assert(po, !(offset & 7));
2033 snprintf(buf, buf_size, "%s%sa%d",
2034 prefix, is_lea ? "&" : "", i + 1);
2038 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
2042 strcat(g_comment, " unaligned");
2045 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
2046 if (tmp_lmod != OPLM_DWORD
2047 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
2048 < lmod_bytes(po, popr->lmod) + (offset & 3))))
2050 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
2051 i + 1, offset, g_func_pp->arg[i].type.name);
2053 // can't check this because msvc likes to reuse
2054 // arg space for scratch..
2055 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
2056 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2060 if (g_stack_fsz == 0)
2061 ferr(po, "stack var access without stackframe\n");
2062 g_stack_frame_used = 1;
2064 sf_ofs = g_stack_fsz + offset;
2065 if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2066 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2076 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2077 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2081 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2082 // known unaligned or possibly unaligned
2083 strcat(g_comment, " unaligned");
2085 prefix = "*(u16 *)&";
2086 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2087 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2090 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2094 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2095 // known unaligned or possibly unaligned
2096 strcat(g_comment, " unaligned");
2098 prefix = "*(u32 *)&";
2099 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2100 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2103 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2107 ferr_assert(po, !(sf_ofs & 7));
2108 ferr_assert(po, ofs_reg[0] == 0);
2109 // only used for x87 int64/float, float sets is_lea
2110 if (!is_lea && (po->flags & OPF_FINT))
2111 prefix = "*(s64 *)&";
2112 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2116 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2123 static void check_func_pp(struct parsed_op *po,
2124 const struct parsed_proto *pp, const char *pfx)
2126 enum opr_lenmod tmp_lmod;
2130 if (pp->argc_reg != 0) {
2131 if (!g_allow_user_icall && !pp->is_fastcall) {
2132 pp_print(buf, sizeof(buf), pp);
2133 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2135 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2136 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2137 pfx, pp->argc_reg, pp->argc_stack);
2140 // fptrs must use 32bit args, callsite might have no information and
2141 // lack a cast to smaller types, which results in incorrectly masked
2142 // args passed (callee may assume masked args, it does on ARM)
2143 if (!pp->is_osinc) {
2144 for (i = 0; i < pp->argc; i++) {
2145 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2146 if (ret && tmp_lmod != OPLM_DWORD)
2147 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2148 i + 1, pp->arg[i].type.name);
2153 static const char *check_label_read_ref(struct parsed_op *po,
2154 const char *name, int *is_import)
2156 const struct parsed_proto *pp;
2158 pp = proto_parse(g_fhdr, name, 0);
2160 ferr(po, "proto_parse failed for ref '%s'\n", name);
2163 check_func_pp(po, pp, "ref");
2165 if (is_import != NULL)
2166 *is_import = pp->is_import;
2171 static void check_opr(struct parsed_op *po, struct parsed_opr *popr)
2173 if (popr->segment == SEG_FS)
2174 ferr(po, "fs: used\n");
2175 if (popr->segment == SEG_GS)
2176 ferr(po, "gs: used\n");
2179 static char *out_src_opr(char *buf, size_t buf_size,
2180 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2183 char tmp1[256], tmp2[256];
2190 check_opr(po, popr);
2195 switch (popr->type) {
2198 ferr(po, "lea from reg?\n");
2200 switch (popr->lmod) {
2202 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2205 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2208 snprintf(buf, buf_size, "%s%s",
2209 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2212 if (popr->name[1] == 'h') // XXX..
2213 snprintf(buf, buf_size, "%s(%s >> 8)",
2214 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2216 snprintf(buf, buf_size, "%s%s",
2217 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2220 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2225 if (is_stack_access(po, popr)) {
2226 stack_frame_access(po, popr, buf, buf_size,
2227 popr->name, cast, 1, is_lea);
2231 strcpy(expr, popr->name);
2232 if (strchr(expr, '[')) {
2233 // special case: '[' can only be left for label[reg] form
2234 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2236 ferr(po, "parse failure for '%s'\n", expr);
2237 if (tmp1[0] == '(') {
2238 // (off_4FFF50+3)[eax]
2239 p = strchr(tmp1 + 1, ')');
2240 if (p == NULL || p[1] != 0)
2241 ferr(po, "parse failure (2) for '%s'\n", expr);
2243 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2245 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2248 // XXX: do we need more parsing?
2250 snprintf(buf, buf_size, "%s", expr);
2254 snprintf(buf, buf_size, "%s(%s)",
2255 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2259 name = check_label_read_ref(po, popr->name, &is_import);
2261 // for imported data, asm is loading the offset
2264 if (cast[0] == 0 && popr->is_ptr)
2268 snprintf(buf, buf_size, "(u32)&%s", name);
2269 else if (popr->size_lt)
2270 snprintf(buf, buf_size, "%s%s%s%s", cast,
2271 lmod_cast_u_ptr(po, popr->lmod),
2272 popr->is_array ? "" : "&", name);
2274 snprintf(buf, buf_size, "%s%s%s", cast, name,
2275 popr->is_array ? "[0]" : "");
2280 name = check_label_read_ref(po, popr->name, NULL);
2284 ferr(po, "lea an offset?\n");
2285 snprintf(buf, buf_size, "%s&%s", cast, name);
2290 ferr(po, "lea from const?\n");
2292 printf_number(tmp1, sizeof(tmp1), popr->val);
2293 if (popr->val == 0 && strchr(cast, '*'))
2294 snprintf(buf, buf_size, "NULL");
2296 snprintf(buf, buf_size, "%s%s",
2297 simplify_cast_num(cast, popr->val), tmp1);
2301 ferr(po, "invalid src type: %d\n", popr->type);
2307 // note: may set is_ptr (we find that out late for ebp frame..)
2308 static char *out_dst_opr(char *buf, size_t buf_size,
2309 struct parsed_op *po, struct parsed_opr *popr)
2311 check_opr(po, popr);
2313 switch (popr->type) {
2315 switch (popr->lmod) {
2317 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2320 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2324 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2328 if (popr->name[1] == 'h') // XXX..
2329 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2331 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2334 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2339 if (is_stack_access(po, popr)) {
2340 stack_frame_access(po, popr, buf, buf_size,
2341 popr->name, "", 0, 0);
2345 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2348 if (popr->size_mismatch)
2349 snprintf(buf, buf_size, "%s%s%s",
2350 lmod_cast_u_ptr(po, popr->lmod),
2351 popr->is_array ? "" : "&", popr->name);
2353 snprintf(buf, buf_size, "%s%s", popr->name,
2354 popr->is_array ? "[0]" : "");
2358 ferr(po, "invalid dst type: %d\n", popr->type);
2364 static char *out_src_opr_u32(char *buf, size_t buf_size,
2365 struct parsed_op *po, struct parsed_opr *popr)
2367 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2370 static char *out_opr_float(char *buf, size_t buf_size,
2371 struct parsed_op *po, struct parsed_opr *popr, int is_src,
2372 int need_float_stack)
2374 const char *cast = NULL;
2381 switch (popr->type) {
2383 if (popr->reg < xST0 || popr->reg > xST7) {
2385 ferr_assert(po, po->op == OP_PUSH);
2386 ferr_assert(po, popr->lmod == OPLM_DWORD);
2387 snprintf(buf, buf_size, "*(float *)&%s", opr_reg_p(po, popr));
2391 if (need_float_stack) {
2392 if (popr->reg == xST0)
2393 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2395 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2399 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2403 if (popr->lmod == OPLM_QWORD && is_stack_access(po, popr)) {
2404 stack_frame_access(po, popr, buf, buf_size,
2405 popr->name, "", is_src, 0);
2411 switch (popr->lmod) {
2419 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2422 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2423 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2427 // only for func float args pushes
2428 ferr_assert(po, po->op == OP_PUSH);
2429 u.i = po->operand[0].val;
2430 if (ceilf(u.f) == u.f)
2431 snprintf(buf, buf_size, "%.1ff", u.f);
2433 snprintf(buf, buf_size, "%.8ff", u.f);
2437 ferr(po, "invalid float type: %d\n", popr->type);
2443 static char *out_src_opr_float(char *buf, size_t buf_size,
2444 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2446 return out_opr_float(buf, buf_size, po, popr, 1, need_float_stack);
2449 static char *out_dst_opr_float(char *buf, size_t buf_size,
2450 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2452 return out_opr_float(buf, buf_size, po, popr, 0, need_float_stack);
2455 static void out_test_for_cc(char *buf, size_t buf_size,
2456 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2457 enum opr_lenmod lmod, const char *expr)
2459 const char *cast, *scast;
2461 cast = lmod_cast_u(po, lmod);
2462 scast = lmod_cast_s(po, lmod);
2466 case PFO_BE: // CF==1||ZF==1; CF=0
2467 snprintf(buf, buf_size, "(%s%s %s 0)",
2468 cast, expr, is_inv ? "!=" : "==");
2472 case PFO_L: // SF!=OF; OF=0
2473 snprintf(buf, buf_size, "(%s%s %s 0)",
2474 scast, expr, is_inv ? ">=" : "<");
2477 case PFO_LE: // ZF==1||SF!=OF; OF=0
2478 snprintf(buf, buf_size, "(%s%s %s 0)",
2479 scast, expr, is_inv ? ">" : "<=");
2484 snprintf(buf, buf_size, "(%d)", !!is_inv);
2487 case PFO_P: // PF==1
2488 snprintf(buf, buf_size, "(%sdo_parity(%s))",
2489 is_inv ? "!" : "", expr);
2493 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2497 static void out_cmp_for_cc(char *buf, size_t buf_size,
2498 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2501 const char *cast, *scast, *cast_use;
2502 char buf1[256], buf2[256];
2503 enum opr_lenmod lmod;
2505 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2506 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2507 po->operand[0].lmod, po->operand[1].lmod);
2508 lmod = po->operand[0].lmod;
2510 cast = lmod_cast_u(po, lmod);
2511 scast = lmod_cast_s(po, lmod);
2527 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2530 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2531 if (po->op == OP_DEC)
2532 snprintf(buf2, sizeof(buf2), "1");
2535 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2537 strcat(cast_op2, "-");
2538 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2543 // note: must be unsigned compare
2544 snprintf(buf, buf_size, "(%s %s %s)",
2545 buf1, is_inv ? ">=" : "<", buf2);
2549 snprintf(buf, buf_size, "(%s %s %s)",
2550 buf1, is_inv ? "!=" : "==", buf2);
2554 // note: must be unsigned compare
2555 snprintf(buf, buf_size, "(%s %s %s)",
2556 buf1, is_inv ? ">" : "<=", buf2);
2559 if (is_inv && lmod == OPLM_BYTE
2560 && po->operand[1].type == OPT_CONST
2561 && po->operand[1].val == 0xff)
2563 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2564 snprintf(buf, buf_size, "(0)");
2568 // note: must be signed compare
2570 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2571 scast, buf1, buf2, is_inv ? ">=" : "<");
2575 snprintf(buf, buf_size, "(%s %s %s)",
2576 buf1, is_inv ? ">=" : "<", buf2);
2580 snprintf(buf, buf_size, "(%s %s %s)",
2581 buf1, is_inv ? ">" : "<=", buf2);
2589 static void out_cmp_test(char *buf, size_t buf_size,
2590 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2592 char buf1[256], buf2[256], buf3[256];
2594 if (po->op == OP_TEST) {
2595 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2596 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2599 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2600 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2601 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2603 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2604 po->operand[0].lmod, buf3);
2606 else if (po->op == OP_CMP) {
2607 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2610 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2613 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2614 struct parsed_opr *popr2)
2616 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2617 ferr(po, "missing lmod for both operands\n");
2619 if (popr1->lmod == OPLM_UNSPEC)
2620 popr1->lmod = popr2->lmod;
2621 else if (popr2->lmod == OPLM_UNSPEC)
2622 popr2->lmod = popr1->lmod;
2623 else if (popr1->lmod != popr2->lmod) {
2624 if (popr1->type_from_var) {
2625 popr1->size_mismatch = 1;
2626 if (popr1->lmod < popr2->lmod)
2628 popr1->lmod = popr2->lmod;
2630 else if (popr2->type_from_var) {
2631 popr2->size_mismatch = 1;
2632 if (popr2->lmod < popr1->lmod)
2634 popr2->lmod = popr1->lmod;
2637 ferr(po, "conflicting lmods: %d vs %d\n",
2638 popr1->lmod, popr2->lmod);
2642 static const char *op_to_c(struct parsed_op *po)
2666 ferr(po, "op_to_c was supplied with %d\n", po->op);
2670 // last op in stream - unconditional branch or ret
2671 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2672 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2673 && ops[_i].op != OP_CALL))
2675 #define check_i(po, i) \
2677 ferr(po, "bad " #i ": %d\n", i)
2679 // note: this skips over calls and rm'd stuff assuming they're handled
2680 // so it's intended to use at one of final passes
2681 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2682 int depth, int seen_noreturn, int flags_set)
2684 struct parsed_op *po;
2689 for (; i < opcnt; i++) {
2691 if (po->cc_scratch == magic)
2692 return ret; // already checked
2693 po->cc_scratch = magic;
2695 if (po->flags & OPF_TAIL) {
2696 if (po->op == OP_CALL) {
2697 if (po->pp != NULL && po->pp->is_noreturn)
2706 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2709 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2710 if (po->btj != NULL) {
2712 for (j = 0; j < po->btj->count; j++) {
2713 check_i(po, po->btj->d[j].bt_i);
2714 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2715 depth, seen_noreturn, flags_set);
2717 return ret; // dead end
2722 check_i(po, po->bt_i);
2723 if (po->flags & OPF_CJMP) {
2724 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2725 depth, seen_noreturn, flags_set);
2727 return ret; // dead end
2736 if ((po->op == OP_POP || po->op == OP_PUSH)
2737 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2742 if (po->op == OP_PUSH) {
2745 else if (po->op == OP_POP) {
2746 if (relevant && depth == 0) {
2747 po->flags |= flags_set;
2755 // for noreturn, assume msvc skipped stack cleanup
2756 return seen_noreturn ? 1 : -1;
2759 // scan for 'reg' pop backwards starting from i
2760 // intended to use for register restore search, so other reg
2761 // references are considered an error
2762 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2764 struct parsed_op *po;
2765 struct label_ref *lr;
2768 ops[i].cc_scratch = magic;
2772 if (g_labels[i] != NULL) {
2773 lr = &g_label_refs[i];
2774 for (; lr != NULL; lr = lr->next) {
2775 check_i(&ops[i], lr->i);
2776 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2780 if (i > 0 && LAST_OP(i - 1))
2788 if (ops[i].cc_scratch == magic)
2790 ops[i].cc_scratch = magic;
2793 if (po->op == OP_POP && po->operand[0].reg == reg) {
2794 if (po->flags & (OPF_RMD|OPF_DONE))
2797 po->flags |= set_flags;
2801 // this also covers the case where we reach corresponding push
2802 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2806 // nothing interesting on this path,
2807 // still return ret for something recursive calls could find
2811 static void find_reachable_exits(int i, int opcnt, int magic,
2812 int *exits, int *exit_count)
2814 struct parsed_op *po;
2817 for (; i < opcnt; i++)
2820 if (po->cc_scratch == magic)
2822 po->cc_scratch = magic;
2824 if (po->flags & OPF_TAIL) {
2825 ferr_assert(po, *exit_count < MAX_EXITS);
2826 exits[*exit_count] = i;
2831 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2832 if (po->flags & OPF_RMD)
2835 if (po->btj != NULL) {
2836 for (j = 0; j < po->btj->count; j++) {
2837 check_i(po, po->btj->d[j].bt_i);
2838 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2844 check_i(po, po->bt_i);
2845 if (po->flags & OPF_CJMP)
2846 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2854 // scan for 'reg' pop backwards starting from exits (all paths)
2855 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2857 static int exits[MAX_EXITS];
2858 static int exit_count;
2864 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2866 ferr_assert(&ops[i], exit_count > 0);
2869 for (j = 0; j < exit_count; j++) {
2871 ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2877 if (ops[e].op == OP_CALL && ops[e].pp != NULL
2878 && ops[e].pp->is_noreturn)
2880 // assume stack cleanup was skipped
2889 // scan for one or more pop of push <const>
2890 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2891 int push_i, int is_probe)
2893 struct parsed_op *po;
2894 struct label_ref *lr;
2898 for (; i < opcnt; i++)
2901 if (po->cc_scratch == magic)
2902 return ret; // already checked
2903 po->cc_scratch = magic;
2905 if (po->flags & OPF_JMP) {
2906 if (po->flags & OPF_RMD)
2908 if (po->op == OP_CALL)
2911 if (po->btj != NULL) {
2912 for (j = 0; j < po->btj->count; j++) {
2913 check_i(po, po->btj->d[j].bt_i);
2914 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2922 check_i(po, po->bt_i);
2923 if (po->flags & OPF_CJMP) {
2924 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2935 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2938 if (g_labels[i] != NULL) {
2939 // all refs must be visited
2940 lr = &g_label_refs[i];
2941 for (; lr != NULL; lr = lr->next) {
2943 if (ops[lr->i].cc_scratch != magic)
2946 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2950 if (po->op == OP_POP)
2952 if (po->flags & (OPF_RMD|OPF_DONE))
2956 po->flags |= OPF_DONE;
2957 po->datap = &ops[push_i];
2966 static void scan_for_pop_const(int i, int opcnt, int magic)
2970 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2972 ops[i].flags |= OPF_RMD | OPF_DONE;
2973 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2977 // check if all branch targets within a marked path are also marked
2978 // note: the path checked must not be empty or end with a branch
2979 static int check_path_branches(int opcnt, int magic)
2981 struct parsed_op *po;
2984 for (i = 0; i < opcnt; i++) {
2986 if (po->cc_scratch != magic)
2989 if (po->flags & OPF_JMP) {
2990 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2993 if (po->btj != NULL) {
2994 for (j = 0; j < po->btj->count; j++) {
2995 check_i(po, po->btj->d[j].bt_i);
2996 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
3001 check_i(po, po->bt_i);
3002 if (ops[po->bt_i].cc_scratch != magic)
3004 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
3012 // scan for multiple pushes for given pop
3013 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
3016 int reg = ops[pop_i].operand[0].reg;
3017 struct parsed_op *po;
3018 struct label_ref *lr;
3021 ops[i].cc_scratch = magic;
3025 if (g_labels[i] != NULL) {
3026 lr = &g_label_refs[i];
3027 for (; lr != NULL; lr = lr->next) {
3028 check_i(&ops[i], lr->i);
3029 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
3033 if (i > 0 && LAST_OP(i - 1))
3041 if (ops[i].cc_scratch == magic)
3043 ops[i].cc_scratch = magic;
3046 if (po->op == OP_CALL)
3048 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
3051 if (po->op == OP_PUSH)
3053 if (po->datap != NULL)
3055 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
3056 // leave this case for reg save/restore handlers
3060 po->flags |= OPF_PPUSH | OPF_DONE;
3061 po->datap = &ops[pop_i];
3070 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
3072 int magic = i + opcnt * 14;
3075 ret = scan_pushes_for_pop_r(i, magic, i, 1);
3077 ret = check_path_branches(opcnt, magic);
3079 ops[i].flags |= OPF_PPUSH | OPF_DONE;
3080 *regmask_pp |= 1 << ops[i].operand[0].reg;
3081 scan_pushes_for_pop_r(i, magic + 1, i, 0);
3086 static void scan_propagate_df(int i, int opcnt)
3088 struct parsed_op *po = &ops[i];
3091 for (; i < opcnt; i++) {
3093 if (po->flags & OPF_DF)
3094 return; // already resolved
3095 po->flags |= OPF_DF;
3097 if (po->op == OP_CALL)
3098 ferr(po, "call with DF set?\n");
3100 if (po->flags & OPF_JMP) {
3101 if (po->btj != NULL) {
3103 for (j = 0; j < po->btj->count; j++) {
3104 check_i(po, po->btj->d[j].bt_i);
3105 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
3110 if (po->flags & OPF_RMD)
3112 check_i(po, po->bt_i);
3113 if (po->flags & OPF_CJMP)
3114 scan_propagate_df(po->bt_i, opcnt);
3120 if (po->flags & OPF_TAIL)
3123 if (po->op == OP_CLD) {
3124 po->flags |= OPF_RMD | OPF_DONE;
3129 ferr(po, "missing DF clear?\n");
3132 // is operand 'opr' referenced by parsed_op 'po'?
3133 static int is_opr_referenced(const struct parsed_opr *opr,
3134 const struct parsed_op *po)
3138 if (opr->type == OPT_REG) {
3139 mask = po->regmask_dst | po->regmask_src;
3140 if (po->op == OP_CALL)
3141 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3142 if ((1 << opr->reg) & mask)
3148 for (i = 0; i < po->operand_cnt; i++)
3149 if (IS(po->operand[0].name, opr->name))
3155 // is operand 'opr' read by parsed_op 'po'?
3156 static int is_opr_read(const struct parsed_opr *opr,
3157 const struct parsed_op *po)
3159 if (opr->type == OPT_REG) {
3160 if (po->regmask_src & (1 << opr->reg))
3170 // is operand 'opr' modified by parsed_op 'po'?
3171 static int is_opr_modified(const struct parsed_opr *opr,
3172 const struct parsed_op *po)
3176 if (opr->type == OPT_REG) {
3177 if (po->op == OP_CALL) {
3178 mask = po->regmask_dst;
3179 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3180 if (mask & (1 << opr->reg))
3186 if (po->regmask_dst & (1 << opr->reg))
3192 return IS(po->operand[0].name, opr->name);
3195 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3196 static int is_any_opr_modified(const struct parsed_op *po_test,
3197 const struct parsed_op *po, int c_mode)
3202 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3205 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3208 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3211 // in reality, it can wreck any register, but in decompiled C
3212 // version it can only overwrite eax or edx:eax
3213 mask = (1 << xAX) | (1 << xDX);
3217 if (po->op == OP_CALL
3218 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3221 for (i = 0; i < po_test->operand_cnt; i++)
3222 if (IS(po_test->operand[i].name, po->operand[0].name))
3228 // scan for any po_test operand modification in range given
3229 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3232 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3235 for (; i < opcnt; i++) {
3236 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3243 // scan for po_test operand[0] modification in range given
3244 static int scan_for_mod_opr0(struct parsed_op *po_test,
3247 for (; i < opcnt; i++) {
3248 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3255 static int try_resolve_const(int i, const struct parsed_opr *opr,
3256 int magic, unsigned int *val);
3258 static int scan_for_flag_set(int i, int opcnt, int magic,
3259 int *branched, int *setters, int *setter_cnt)
3261 struct label_ref *lr;
3265 if (ops[i].cc_scratch == magic) {
3266 // is this a problem?
3267 //ferr(&ops[i], "%s looped\n", __func__);
3270 ops[i].cc_scratch = magic;
3272 if (g_labels[i] != NULL) {
3275 lr = &g_label_refs[i];
3276 for (; lr->next; lr = lr->next) {
3277 check_i(&ops[i], lr->i);
3278 ret = scan_for_flag_set(lr->i, opcnt, magic,
3279 branched, setters, setter_cnt);
3284 check_i(&ops[i], lr->i);
3285 if (i > 0 && LAST_OP(i - 1)) {
3289 ret = scan_for_flag_set(lr->i, opcnt, magic,
3290 branched, setters, setter_cnt);
3296 if (ops[i].flags & OPF_FLAGS) {
3297 setters[*setter_cnt] = i;
3300 if (ops[i].flags & OPF_REP) {
3301 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3304 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3305 if (ret != 1 || uval == 0) {
3306 // can't treat it as full setter because of ecx=0 case,
3307 // also disallow delayed compare
3316 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3323 // scan back for cdq, if anything modifies edx, fail
3324 static int scan_for_cdq_edx(int i)
3327 if (g_labels[i] != NULL) {
3328 if (g_label_refs[i].next != NULL)
3330 if (i > 0 && LAST_OP(i - 1)) {
3331 i = g_label_refs[i].i;
3338 if (ops[i].op == OP_CDQ)
3341 if (ops[i].regmask_dst & (1 << xDX))
3348 static int scan_for_reg_clear(int i, int reg)
3351 if (g_labels[i] != NULL) {
3352 if (g_label_refs[i].next != NULL)
3354 if (i > 0 && LAST_OP(i - 1)) {
3355 i = g_label_refs[i].i;
3362 if (ops[i].op == OP_XOR
3363 && ops[i].operand[0].lmod == OPLM_DWORD
3364 && ops[i].operand[0].reg == ops[i].operand[1].reg
3365 && ops[i].operand[0].reg == reg)
3368 if (ops[i].regmask_dst & (1 << reg))
3375 static void patch_esp_adjust(struct parsed_op *po, int adj)
3377 ferr_assert(po, po->op == OP_ADD);
3378 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3379 ferr_assert(po, po->operand[1].type == OPT_CONST);
3381 // this is a bit of a hack, but deals with use of
3382 // single adj for multiple calls
3383 po->operand[1].val -= adj;
3384 po->flags |= OPF_RMD;
3385 if (po->operand[1].val == 0)
3386 po->flags |= OPF_DONE;
3387 ferr_assert(po, (int)po->operand[1].val >= 0);
3390 // scan for positive, constant esp adjust
3391 // multipath case is preliminary
3392 static int scan_for_esp_adjust(int i, int opcnt,
3393 int adj_expect, int *adj, int *is_multipath, int do_update)
3395 int adj_expect_unknown = 0;
3396 struct parsed_op *po;
3400 *adj = *is_multipath = 0;
3401 if (adj_expect < 0) {
3402 adj_expect_unknown = 1;
3403 adj_expect = 32 * 4; // enough?
3406 for (; i < opcnt && *adj < adj_expect; i++) {
3407 if (g_labels[i] != NULL)
3411 if (po->flags & OPF_DONE)
3414 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3415 if (po->operand[1].type != OPT_CONST)
3416 ferr(&ops[i], "non-const esp adjust?\n");
3417 *adj += po->operand[1].val;
3419 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3422 patch_esp_adjust(po, adj_expect);
3424 po->flags |= OPF_RMD;
3428 else if (po->op == OP_PUSH) {
3429 //if (first_pop == -1)
3430 // first_pop = -2; // none
3431 *adj -= lmod_bytes(po, po->operand[0].lmod);
3433 else if (po->op == OP_POP) {
3434 if (!(po->flags & OPF_DONE)) {
3435 // seems like msvc only uses 'pop ecx' for stack realignment..
3436 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3438 if (first_pop == -1 && *adj >= 0)
3441 if (do_update && *adj >= 0) {
3442 po->flags |= OPF_RMD;
3444 po->flags |= OPF_DONE | OPF_NOREGS;
3447 *adj += lmod_bytes(po, po->operand[0].lmod);
3448 if (*adj > adj_best)
3451 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3452 if (po->op == OP_JMP && po->btj == NULL) {
3458 if (po->op != OP_CALL)
3460 if (po->operand[0].type != OPT_LABEL)
3462 if (po->pp != NULL && po->pp->is_stdcall)
3464 if (adj_expect_unknown && first_pop >= 0)
3466 // assume it's another cdecl call
3470 if (first_pop >= 0) {
3471 // probably only 'pop ecx' was used
3479 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3481 struct parsed_op *po;
3485 ferr(ops, "%s: followed bad branch?\n", __func__);
3487 for (; i < opcnt; i++) {
3489 if (po->cc_scratch == magic)
3491 po->cc_scratch = magic;
3494 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3495 if (po->btj != NULL) {
3497 for (j = 0; j < po->btj->count; j++)
3498 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3502 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3503 if (!(po->flags & OPF_CJMP))
3506 if (po->flags & OPF_TAIL)
3511 static const struct parsed_proto *try_recover_pp(
3512 struct parsed_op *po, const struct parsed_opr *opr,
3513 int is_call, int *search_instead)
3515 const struct parsed_proto *pp = NULL;
3519 // maybe an arg of g_func?
3520 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3522 char ofs_reg[16] = { 0, };
3523 int arg, arg_s, arg_i;
3530 parse_stack_access(po, opr->name, ofs_reg,
3531 &offset, &stack_ra, NULL, 0);
3532 if (ofs_reg[0] != 0)
3533 ferr(po, "offset reg on arg access?\n");
3534 if (offset <= stack_ra) {
3535 // search who set the stack var instead
3536 if (search_instead != NULL)
3537 *search_instead = 1;
3541 arg_i = (offset - stack_ra - 4) / 4;
3542 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3543 if (g_func_pp->arg[arg].reg != NULL)
3549 if (arg == g_func_pp->argc)
3550 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3552 pp = g_func_pp->arg[arg].pp;
3555 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3556 check_func_pp(po, pp, "icall arg");
3559 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3561 p = strchr(opr->name + 1, '[');
3562 memcpy(buf, opr->name, p - opr->name);
3563 buf[p - opr->name] = 0;
3564 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3566 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3567 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3570 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3573 check_func_pp(po, pp, "reg-fptr ref");
3579 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3580 int magic, const struct parsed_proto **pp_found, int *pp_i,
3583 const struct parsed_proto *pp = NULL;
3584 struct parsed_op *po;
3585 struct label_ref *lr;
3587 ops[i].cc_scratch = magic;
3590 if (g_labels[i] != NULL) {
3591 lr = &g_label_refs[i];
3592 for (; lr != NULL; lr = lr->next) {
3593 check_i(&ops[i], lr->i);
3594 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3596 if (i > 0 && LAST_OP(i - 1))
3604 if (ops[i].cc_scratch == magic)
3606 ops[i].cc_scratch = magic;
3608 if (!(ops[i].flags & OPF_DATA))
3610 if (!is_opr_modified(opr, &ops[i]))
3612 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3613 // most probably trashed by some processing
3618 opr = &ops[i].operand[1];
3619 if (opr->type != OPT_REG)
3623 po = (i >= 0) ? &ops[i] : ops;
3626 // reached the top - can only be an arg-reg
3627 if (opr->type != OPT_REG || g_func_pp == NULL)
3630 for (i = 0; i < g_func_pp->argc; i++) {
3631 if (g_func_pp->arg[i].reg == NULL)
3633 if (IS(opr->name, g_func_pp->arg[i].reg))
3636 if (i == g_func_pp->argc)
3638 pp = g_func_pp->arg[i].pp;
3640 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3641 i + 1, g_func_pp->arg[i].reg);
3642 check_func_pp(po, pp, "icall reg-arg");
3645 pp = try_recover_pp(po, opr, 1, NULL);
3647 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3648 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3649 || (*pp_found)->is_stdcall != pp->is_stdcall
3650 //|| (*pp_found)->is_fptr != pp->is_fptr
3651 || (*pp_found)->argc != pp->argc
3652 || (*pp_found)->argc_reg != pp->argc_reg
3653 || (*pp_found)->argc_stack != pp->argc_stack)
3655 ferr(po, "icall: parsed_proto mismatch\n");
3665 static void add_label_ref(struct label_ref *lr, int op_i)
3667 struct label_ref *lr_new;
3674 lr_new = calloc(1, sizeof(*lr_new));
3676 lr_new->next = lr->next;
3680 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3682 struct parsed_op *po = &ops[i];
3683 struct parsed_data *pd;
3684 char label[NAMELEN], *p;
3687 p = strchr(po->operand[0].name, '[');
3691 len = p - po->operand[0].name;
3692 strncpy(label, po->operand[0].name, len);
3695 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3696 if (IS(g_func_pd[j].label, label)) {
3702 //ferr(po, "label '%s' not parsed?\n", label);
3705 if (pd->type != OPT_OFFSET)
3706 ferr(po, "label '%s' with non-offset data?\n", label);
3708 // find all labels, link
3709 for (j = 0; j < pd->count; j++) {
3710 for (l = 0; l < opcnt; l++) {
3711 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3712 add_label_ref(&g_label_refs[l], i);
3722 static void clear_labels(int count)
3726 for (i = 0; i < count; i++) {
3727 if (g_labels[i] != NULL) {
3734 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3739 for (i = 0; i < pp->argc; i++) {
3740 if (pp->arg[i].reg != NULL) {
3741 reg = char_array_i(regs_r32,
3742 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3744 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3745 pp->arg[i].reg, pp->name);
3746 regmask |= 1 << reg;
3753 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3758 if (pp->has_retreg) {
3759 for (i = 0; i < pp->argc; i++) {
3760 if (pp->arg[i].type.is_retreg) {
3761 reg = char_array_i(regs_r32,
3762 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3763 ferr_assert(ops, reg >= 0);
3764 regmask |= 1 << reg;
3769 if (strstr(pp->ret_type.name, "int64"))
3770 return regmask | (1 << xAX) | (1 << xDX);
3771 if (IS(pp->ret_type.name, "float")
3772 || IS(pp->ret_type.name, "double"))
3774 return regmask | mxST0;
3776 if (strcasecmp(pp->ret_type.name, "void") == 0)
3779 return regmask | mxAX;
3782 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3784 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3785 && memcmp(po1->operand, po2->operand,
3786 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3789 static void resolve_branches_parse_calls(int opcnt)
3791 static const struct {
3795 unsigned int regmask_src;
3796 unsigned int regmask_dst;
3798 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3799 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3800 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3801 // more precise? Wine gets away with just __ftol handler
3802 { "__ftol2", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3803 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3805 const struct parsed_proto *pp_c;
3806 struct parsed_proto *pp;
3807 struct parsed_data *pd;
3808 struct parsed_op *po;
3809 const char *tmpname;
3814 for (i = 0; i < opcnt; i++)
3820 if (po->datap != NULL) {
3821 pp = calloc(1, sizeof(*pp));
3822 my_assert_not(pp, NULL);
3824 ret = parse_protostr(po->datap, pp);
3826 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3832 if (po->op == OP_CALL) {
3837 else if (po->operand[0].type == OPT_LABEL)
3839 tmpname = opr_name(po, 0);
3840 if (IS_START(tmpname, "loc_")) {
3842 ferr(po, "call to loc_*\n");
3843 // eliminate_seh() must take care of it
3846 if (IS(tmpname, "__alloca_probe"))
3848 if (IS(tmpname, "__SEH_prolog")) {
3849 ferr_assert(po, g_seh_found == 0);
3853 if (IS(tmpname, "__SEH_epilog"))
3856 // convert some calls to pseudo-ops
3857 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3858 if (!IS(tmpname, pseudo_ops[l].name))
3861 po->op = pseudo_ops[l].op;
3862 po->operand_cnt = 0;
3863 po->regmask_src = pseudo_ops[l].regmask_src;
3864 po->regmask_dst = pseudo_ops[l].regmask_dst;
3865 po->flags = pseudo_ops[l].flags;
3866 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3869 if (l < ARRAY_SIZE(pseudo_ops))
3872 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3873 if (!g_header_mode && pp_c == NULL)
3874 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3877 pp = proto_clone(pp_c);
3878 my_assert_not(pp, NULL);
3884 check_func_pp(po, pp, "fptr var call");
3885 if (pp->is_noreturn) {
3886 po->flags |= OPF_TAIL;
3887 po->flags &= ~OPF_ATAIL; // most likely...
3894 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3897 if (po->operand[0].type == OPT_REGMEM) {
3898 pd = try_resolve_jumptab(i, opcnt);
3906 for (l = 0; l < opcnt; l++) {
3907 if (g_labels[l] != NULL
3908 && IS(po->operand[0].name, g_labels[l]))
3910 if (l == i + 1 && po->op == OP_JMP) {
3911 // yet another alignment type..
3912 po->flags |= OPF_RMD|OPF_DONE;
3915 add_label_ref(&g_label_refs[l], i);
3921 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3924 if (po->operand[0].type == OPT_LABEL)
3928 ferr(po, "unhandled branch\n");
3932 po->flags |= OPF_TAIL;
3933 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3934 if (prev_op == OP_POP)
3935 po->flags |= OPF_ATAIL;
3936 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3937 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3939 po->flags |= OPF_ATAIL;
3945 static int resolve_origin(int i, const struct parsed_opr *opr,
3946 int magic, int *op_i, int *is_caller);
3947 static void set_label(int i, const char *name);
3949 static void eliminate_seh_writes(int opcnt)
3951 const struct parsed_opr *opr;
3956 // assume all sf writes above g_seh_size to be seh related
3957 // (probably unsafe but oh well)
3958 for (i = 0; i < opcnt; i++) {
3959 if (ops[i].op != OP_MOV)
3961 opr = &ops[i].operand[0];
3962 if (opr->type != OPT_REGMEM)
3964 if (!is_stack_access(&ops[i], opr))
3968 parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
3970 if (offset < 0 && offset >= -g_seh_size)
3971 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3975 static void eliminate_seh_finally(int opcnt)
3977 const char *target_name = NULL;
3978 const char *return_name = NULL;
3979 int exits[MAX_EXITS];
3987 for (i = 0; i < opcnt; i++) {
3988 if (ops[i].op != OP_CALL)
3990 if (!IS_START(opr_name(&ops[i], 0), "loc_"))
3992 if (target_name != NULL)
3993 ferr(&ops[i], "multiple finally calls? (last was %s)\n",
3995 target_name = opr_name(&ops[i], 0);
3998 if (g_labels[i + 1] == NULL)
3999 set_label(i + 1, "seh_fin_done");
4000 return_name = g_labels[i + 1];
4008 // find finally code (bt_i is not set because it's call)
4009 for (i = 0; i < opcnt; i++) {
4010 if (g_labels[i] == NULL)
4012 if (!IS(g_labels[i], target_name))
4015 ferr_assert(&ops[i], target_i == -1);
4018 ferr_assert(&ops[0], target_i != -1);
4020 find_reachable_exits(target_i, opcnt, target_i + opcnt * 24,
4021 exits, &exit_count);
4022 ferr_assert(&ops[target_i], exit_count == 1);
4023 ferr_assert(&ops[target_i], ops[exits[0]].op == OP_RET);
4026 // convert to jumps, link
4027 ops[call_i].op = OP_JMP;
4028 ops[call_i].bt_i = target_i;
4029 add_label_ref(&g_label_refs[target_i], call_i);
4031 ops[tgend_i].op = OP_JMP;
4032 ops[tgend_i].flags &= ~OPF_TAIL;
4033 ops[tgend_i].flags |= OPF_JMP;
4034 ops[tgend_i].bt_i = return_i;
4035 ops[tgend_i].operand_cnt = 1;
4036 ops[tgend_i].operand[0].type = OPT_LABEL;
4037 snprintf(ops[tgend_i].operand[0].name, NAMELEN, "%s", return_name);
4038 add_label_ref(&g_label_refs[return_i], tgend_i);
4040 // rm seh finally entry code
4041 for (i = target_i - 1; i >= 0; i--) {
4042 if (g_labels[i] != NULL && g_label_refs[i].i != -1)
4044 if (ops[i].flags & OPF_CJMP)
4046 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4049 for (i = target_i - 1; i >= 0; i--) {
4050 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4052 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4056 static void eliminate_seh(int opcnt)
4060 for (i = 0; i < opcnt; i++) {
4061 if (ops[i].op != OP_MOV)
4063 if (ops[i].operand[0].segment != SEG_FS)
4065 if (!IS(opr_name(&ops[i], 0), "0"))
4068 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4069 if (ops[i].operand[1].reg == xSP) {
4070 for (j = i - 1; j >= 0; j--) {
4071 if (ops[j].op != OP_PUSH)
4073 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4075 if (ops[j].operand[0].val == ~0)
4077 if (ops[j].operand[0].type == OPT_REG) {
4079 ret = resolve_origin(j, &ops[j].operand[0],
4080 j + opcnt * 22, &k, NULL);
4082 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4086 ferr(ops, "missing seh terminator\n");
4090 ret = resolve_origin(i, &ops[i].operand[1],
4091 i + opcnt * 23, &k, NULL);
4093 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4097 eliminate_seh_writes(opcnt);
4098 eliminate_seh_finally(opcnt);
4101 static void eliminate_seh_calls(int opcnt)
4103 int epilog_found = 0;
4110 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4111 && ops[i].operand[0].type == OPT_CONST);
4112 g_stack_fsz = g_seh_size + ops[i].operand[0].val;
4113 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4116 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4117 && ops[i].operand[0].type == OPT_OFFSET);
4118 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4121 ferr_assert(&ops[i], ops[i].op == OP_CALL
4122 && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
4123 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4125 for (i++; i < opcnt; i++) {
4126 if (ops[i].op != OP_CALL)
4128 if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
4131 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4134 ferr_assert(ops, epilog_found);
4136 eliminate_seh_writes(opcnt);
4137 eliminate_seh_finally(opcnt);
4140 static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4144 for (; i < opcnt; i++)
4145 if (!(ops[i].flags & OPF_DONE))
4148 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4149 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4155 for (; i < opcnt; i++) {
4156 if (i > 0 && g_labels[i] != NULL)
4158 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
4160 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4161 && ops[i].operand[1].type == OPT_CONST)
4163 g_stack_fsz += opr_const(&ops[i], 1);
4164 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4169 if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4170 && ops[i].operand[1].type == OPT_CONST)
4172 for (j = i + 1; j < opcnt; j++)
4173 if (!(ops[j].flags & OPF_DONE))
4175 if (ops[j].op == OP_CALL
4176 && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4178 g_stack_fsz += opr_const(&ops[i], 1);
4179 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4180 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4191 static void scan_prologue_epilogue(int opcnt, int *stack_align)
4193 int ecx_push = 0, esp_sub = 0, pusha = 0;
4194 int sandard_epilogue;
4198 if (g_seh_found == 2) {
4199 eliminate_seh_calls(opcnt);
4203 eliminate_seh(opcnt);
4204 // ida treats seh as part of sf
4205 g_stack_fsz = g_seh_size;
4209 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4210 && ops[1].op == OP_MOV
4211 && IS(opr_name(&ops[1], 0), "ebp")
4212 && IS(opr_name(&ops[1], 1), "esp"))
4215 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4216 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4218 for (i = 2; i < opcnt; i++)
4219 if (!(ops[i].flags & OPF_DONE))
4222 if (ops[i].op == OP_PUSHA) {
4223 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4228 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4229 && ops[i].operand[1].type == OPT_CONST)
4231 l = ops[i].operand[1].val;
4233 if (j == -1 || (l >> j) != -1)
4234 ferr(&ops[i], "unhandled esp align: %x\n", l);
4235 if (stack_align != NULL)
4236 *stack_align = 1 << j;
4237 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4241 i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4245 for (; i < opcnt; i++)
4246 if (ops[i].flags & OPF_TAIL)
4249 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4250 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4256 sandard_epilogue = 0;
4257 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4259 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4260 // the standard epilogue is sometimes even used without a sf
4261 if (ops[j - 1].op == OP_MOV
4262 && IS(opr_name(&ops[j - 1], 0), "esp")
4263 && IS(opr_name(&ops[j - 1], 1), "ebp"))
4264 sandard_epilogue = 1;
4266 else if (ops[j].op == OP_LEAVE)
4268 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4269 sandard_epilogue = 1;
4271 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4272 && ops[i].pp->is_noreturn)
4274 // on noreturn, msvc sometimes cleans stack, sometimes not
4279 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4280 ferr(&ops[j], "'pop ebp' expected\n");
4282 if (g_stack_fsz != 0 || sandard_epilogue) {
4283 if (ops[j].op == OP_LEAVE)
4285 else if (sandard_epilogue) // mov esp, ebp
4287 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4290 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4292 ferr(&ops[j], "esp restore expected\n");
4295 if (ecx_push && j >= 0 && ops[j].op == OP_POP
4296 && IS(opr_name(&ops[j], 0), "ecx"))
4298 ferr(&ops[j], "unexpected ecx pop\n");
4303 if (ops[j].op == OP_POPA)
4304 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4306 ferr(&ops[j], "popa expected\n");
4311 } while (i < opcnt);
4314 ferr(ops, "missing ebp epilogue\n");
4319 i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4321 if (ecx_push && !esp_sub) {
4322 // could actually be args for a call..
4323 for (; i < opcnt; i++)
4324 if (ops[i].op != OP_PUSH)
4327 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4328 const struct parsed_proto *pp;
4329 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4330 j = pp ? pp->argc_stack : 0;
4331 while (i > 0 && j > 0) {
4333 if (ops[i].op == OP_PUSH) {
4334 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4339 ferr(&ops[i], "unhandled prologue\n");
4343 g_stack_fsz = g_seh_size;
4344 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4345 if (!(ops[i].flags & OPF_RMD))
4355 if (ecx_push || esp_sub)
4360 for (; i < opcnt; i++)
4361 if (ops[i].flags & OPF_TAIL)
4365 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4366 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4371 else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4372 // skip arg updates for arg-reuse tailcall
4373 for (; j >= 0; j--) {
4374 if (ops[j].op != OP_MOV)
4376 if (ops[j].operand[0].type != OPT_REGMEM)
4378 if (strstr(ops[j].operand[0].name, "arg_") == NULL)
4383 if (ecx_push > 0 && !esp_sub) {
4384 for (l = 0; l < ecx_push && j >= 0; l++) {
4385 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4387 else if (ops[j].op == OP_ADD
4388 && IS(opr_name(&ops[j], 0), "esp")
4389 && ops[j].operand[1].type == OPT_CONST)
4392 l += ops[j].operand[1].val / 4 - 1;
4397 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4400 if (l != ecx_push) {
4401 if (i < opcnt && ops[i].op == OP_CALL
4402 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4404 // noreturn tailcall with no epilogue
4409 ferr(&ops[j], "epilogue scan failed\n");
4416 if (ops[j].op != OP_ADD
4417 || !IS(opr_name(&ops[j], 0), "esp")
4418 || ops[j].operand[1].type != OPT_CONST)
4420 if (i < opcnt && ops[i].op == OP_CALL
4421 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4423 // noreturn tailcall with no epilogue
4428 ferr(&ops[j], "'add esp' expected\n");
4431 if (ops[j].operand[1].val < g_stack_fsz)
4432 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4434 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4435 if (ops[j].operand[1].val == 0)
4436 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4441 } while (i < opcnt);
4444 ferr(ops, "missing esp epilogue\n");
4448 // find an instruction that changed opr before i op
4449 // *op_i must be set to -1 by the caller
4450 // *is_caller is set to 1 if one source is determined to be g_func arg
4451 // returns 1 if found, *op_i is then set to origin
4452 // returns -1 if multiple origins are found
4453 static int resolve_origin(int i, const struct parsed_opr *opr,
4454 int magic, int *op_i, int *is_caller)
4456 struct label_ref *lr;
4460 if (g_labels[i] != NULL) {
4461 lr = &g_label_refs[i];
4462 for (; lr != NULL; lr = lr->next) {
4463 check_i(&ops[i], lr->i);
4464 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4466 if (i > 0 && LAST_OP(i - 1))
4472 if (is_caller != NULL)
4477 if (ops[i].cc_scratch == magic)
4479 ops[i].cc_scratch = magic;
4481 if (!(ops[i].flags & OPF_DATA))
4483 if (!is_opr_modified(opr, &ops[i]))
4487 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4498 // find an instruction that previously referenced opr
4499 // if multiple results are found - fail
4500 // *op_i must be set to -1 by the caller
4501 // returns 1 if found, *op_i is then set to referencer insn
4502 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4503 int magic, int *op_i)
4505 struct label_ref *lr;
4509 if (g_labels[i] != NULL) {
4510 lr = &g_label_refs[i];
4511 for (; lr != NULL; lr = lr->next) {
4512 check_i(&ops[i], lr->i);
4513 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4515 if (i > 0 && LAST_OP(i - 1))
4523 if (ops[i].cc_scratch == magic)
4525 ops[i].cc_scratch = magic;
4527 if (!is_opr_referenced(opr, &ops[i]))
4538 // adjust datap of all reachable 'op' insns when moving back
4539 // returns 1 if at least 1 op was found
4540 // returns -1 if path without an op was found
4541 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4543 struct label_ref *lr;
4546 if (ops[i].cc_scratch == magic)
4548 ops[i].cc_scratch = magic;
4551 if (g_labels[i] != NULL) {
4552 lr = &g_label_refs[i];
4553 for (; lr != NULL; lr = lr->next) {
4554 check_i(&ops[i], lr->i);
4555 ret |= adjust_prev_op(lr->i, op, magic, datap);
4557 if (i > 0 && LAST_OP(i - 1))
4565 if (ops[i].cc_scratch == magic)
4567 ops[i].cc_scratch = magic;
4569 if (ops[i].op != op)
4572 ops[i].datap = datap;
4577 // find next instruction that reads opr
4578 // *op_i must be set to -1 by the caller
4579 // on return, *op_i is set to first referencer insn
4580 // returns 1 if exactly 1 referencer is found
4581 static int find_next_read(int i, int opcnt,
4582 const struct parsed_opr *opr, int magic, int *op_i)
4584 struct parsed_op *po;
4587 for (; i < opcnt; i++)
4589 if (ops[i].cc_scratch == magic)
4591 ops[i].cc_scratch = magic;
4594 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4595 if (po->btj != NULL) {
4597 for (j = 0; j < po->btj->count; j++) {
4598 check_i(po, po->btj->d[j].bt_i);
4599 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4605 if (po->flags & OPF_RMD)
4607 check_i(po, po->bt_i);
4608 if (po->flags & OPF_CJMP) {
4609 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4618 if (!is_opr_read(opr, po)) {
4620 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4621 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4623 full_opr = po->operand[0].lmod >= opr->lmod;
4625 if (is_opr_modified(opr, po) && full_opr) {
4629 if (po->flags & OPF_TAIL)
4644 // find next instruction that reads opr
4645 // *op_i must be set to -1 by the caller
4646 // on return, *op_i is set to first flag user insn
4647 // returns 1 if exactly 1 flag user is found
4648 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4650 struct parsed_op *po;
4653 for (; i < opcnt; i++)
4655 if (ops[i].cc_scratch == magic)
4657 ops[i].cc_scratch = magic;
4660 if (po->op == OP_CALL)
4662 if (po->flags & OPF_JMP) {
4663 if (po->btj != NULL) {
4665 for (j = 0; j < po->btj->count; j++) {
4666 check_i(po, po->btj->d[j].bt_i);
4667 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4673 if (po->flags & OPF_RMD)
4675 check_i(po, po->bt_i);
4676 if (po->flags & OPF_CJMP)
4683 if (!(po->flags & OPF_CC)) {
4684 if (po->flags & OPF_FLAGS)
4687 if (po->flags & OPF_TAIL)
4703 static int try_resolve_const(int i, const struct parsed_opr *opr,
4704 int magic, unsigned int *val)
4709 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4712 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4715 *val = ops[i].operand[1].val;
4722 static int resolve_used_bits(int i, int opcnt, int reg,
4723 int *mask, int *is_z_check)
4725 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4729 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4733 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4735 fnote(&ops[j], "(first read)\n");
4736 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4739 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4740 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4742 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4743 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4745 *mask = ops[j].operand[1].val;
4746 if (ops[j].operand[0].lmod == OPLM_BYTE
4747 && ops[j].operand[0].name[1] == 'h')
4751 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4754 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4756 *is_z_check = ops[k].pfo == PFO_Z;
4761 static const struct parsed_proto *resolve_deref(int i, int magic,
4762 struct parsed_opr *opr, int level)
4764 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4765 const struct parsed_proto *pp = NULL;
4766 int from_caller = 0;
4775 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4776 if (ret != 2 || len != strlen(opr->name)) {
4777 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4778 if (ret != 1 || len != strlen(opr->name))
4782 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4787 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4791 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4792 && strlen(ops[j].operand[1].name) == 3
4793 && ops[j].operand[0].lmod == OPLM_DWORD
4794 && ops[j].pp == NULL // no hint
4797 // allow one simple dereference (com/directx)
4798 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4799 ops[j].operand[1].name);
4803 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4808 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4811 if (ops[j].pp != NULL) {
4815 else if (ops[j].operand[1].type == OPT_REGMEM) {
4816 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4818 // maybe structure ptr in structure
4819 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4822 else if (ops[j].operand[1].type == OPT_LABEL)
4823 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4824 else if (ops[j].operand[1].type == OPT_REG) {
4827 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4829 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4830 for (k = 0; k < g_func_pp->argc; k++) {
4831 if (g_func_pp->arg[k].reg == NULL)
4833 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4834 pp = g_func_pp->arg[k].pp;
4843 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4845 ferr(&ops[j], "expected struct, got '%s %s'\n",
4846 pp->type.name, pp->name);
4850 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4853 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4854 int *pp_i, int *multi_src)
4856 const struct parsed_proto *pp = NULL;
4857 int search_advice = 0;
4862 switch (ops[i].operand[0].type) {
4864 // try to resolve struct member calls
4865 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4871 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4877 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4885 static struct parsed_proto *process_call_early(int i, int opcnt,
4888 struct parsed_op *po = &ops[i];
4889 struct parsed_proto *pp;
4895 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4899 // look for and make use of esp adjust
4901 if (!pp->is_stdcall && pp->argc_stack > 0)
4902 ret = scan_for_esp_adjust(i + 1, opcnt,
4903 pp->argc_stack * 4, &adj, &multipath, 0);
4905 if (pp->argc_stack > adj / 4)
4909 if (ops[ret].op == OP_POP) {
4910 for (j = 1; j < adj / 4; j++) {
4911 if (ops[ret + j].op != OP_POP
4912 || ops[ret + j].operand[0].reg != xCX)
4924 static struct parsed_proto *process_call(int i, int opcnt)
4926 struct parsed_op *po = &ops[i];
4927 const struct parsed_proto *pp_c;
4928 struct parsed_proto *pp;
4929 const char *tmpname;
4930 int call_i = -1, ref_i = -1;
4931 int adj = 0, multipath = 0;
4934 tmpname = opr_name(po, 0);
4939 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4941 if (!pp_c->is_func && !pp_c->is_fptr)
4942 ferr(po, "call to non-func: %s\n", pp_c->name);
4943 pp = proto_clone(pp_c);
4944 my_assert_not(pp, NULL);
4946 // not resolved just to single func
4949 switch (po->operand[0].type) {
4951 // we resolved this call and no longer need the register
4952 po->regmask_src &= ~(1 << po->operand[0].reg);
4954 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4955 && ops[call_i].operand[1].type == OPT_LABEL)
4957 // no other source users?
4958 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4960 if (ret == 1 && call_i == ref_i) {
4961 // and nothing uses it after us?
4963 find_next_read(i + 1, opcnt, &po->operand[0],
4964 i + opcnt * 11, &ref_i);
4966 // then also don't need the source mov
4967 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4979 pp = calloc(1, sizeof(*pp));
4980 my_assert_not(pp, NULL);
4983 ret = scan_for_esp_adjust(i + 1, opcnt,
4984 -1, &adj, &multipath, 0);
4985 if (ret < 0 || adj < 0) {
4986 if (!g_allow_regfunc)
4987 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4988 pp->is_unresolved = 1;
4992 if (adj > ARRAY_SIZE(pp->arg))
4993 ferr(po, "esp adjust too large: %d\n", adj);
4994 pp->ret_type.name = strdup("int");
4995 pp->argc = pp->argc_stack = adj;
4996 for (arg = 0; arg < pp->argc; arg++)
4997 pp->arg[arg].type.name = strdup("int");
5002 // look for and make use of esp adjust
5005 if (!pp->is_stdcall && pp->argc_stack > 0) {
5006 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
5007 ret = scan_for_esp_adjust(i + 1, opcnt,
5008 adj_expect, &adj, &multipath, 0);
5011 if (pp->is_vararg) {
5012 if (adj / 4 < pp->argc_stack) {
5013 fnote(po, "(this call)\n");
5014 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
5015 adj, pp->argc_stack * 4);
5017 // modify pp to make it have varargs as normal args
5019 pp->argc += adj / 4 - pp->argc_stack;
5020 for (; arg < pp->argc; arg++) {
5021 pp->arg[arg].type.name = strdup("int");
5024 if (pp->argc > ARRAY_SIZE(pp->arg))
5025 ferr(po, "too many args for '%s'\n", tmpname);
5027 if (pp->argc_stack > adj / 4) {
5028 if (pp->is_noreturn)
5029 // assume no stack adjust was emited
5031 fnote(po, "(this call)\n");
5032 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
5033 tmpname, pp->argc_stack * 4, adj);
5036 scan_for_esp_adjust(i + 1, opcnt,
5037 pp->argc_stack * 4, &adj, &multipath, 1);
5039 else if (pp->is_vararg)
5040 ferr(po, "missing esp_adjust for vararg func '%s'\n",
5047 static void mark_float_arg(struct parsed_op *po,
5048 struct parsed_proto *pp, int arg, int *regmask_ffca)
5051 po->p_argnum = arg + 1;
5052 ferr_assert(po, pp->arg[arg].datap == NULL);
5053 pp->arg[arg].datap = po;
5054 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
5055 if (regmask_ffca != NULL)
5056 *regmask_ffca |= 1 << arg;
5059 static int check_for_stp(int i, int i_to)
5061 struct parsed_op *po;
5063 for (; i < i_to; i++) {
5065 if (po->op == OP_FST)
5067 if (g_labels[i] != NULL || (po->flags & OPF_JMP))
5069 if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
5071 if (po->op == OP_ADD && po->operand[0].reg == xSP)
5078 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
5081 struct parsed_op *po;
5087 for (base_arg = 0; base_arg < pp->argc; base_arg++)
5088 if (pp->arg[base_arg].reg == NULL)
5091 for (j = i; j > 0; )
5093 ferr_assert(&ops[j], g_labels[j] == NULL);
5097 ferr_assert(po, po->op != OP_PUSH);
5098 if (po->op == OP_FST)
5100 if (po->operand[0].type != OPT_REGMEM)
5102 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
5105 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
5106 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
5110 arg = base_arg + offset / 4;
5111 mark_float_arg(po, pp, arg, regmask_ffca);
5113 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5114 && po->operand[1].type == OPT_CONST)
5116 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5121 for (arg = base_arg; arg < pp->argc; arg++) {
5122 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
5123 po = pp->arg[arg].datap;
5125 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
5126 if (po->operand[0].lmod == OPLM_QWORD)
5133 static int collect_call_args_early(int i, struct parsed_proto *pp,
5134 int *regmask, int *regmask_ffca)
5136 struct parsed_op *po;
5141 for (arg = 0; arg < pp->argc; arg++)
5142 if (pp->arg[arg].reg == NULL)
5145 // first see if it can be easily done
5146 for (j = i; j > 0 && arg < pp->argc; )
5148 if (g_labels[j] != NULL)
5153 if (po->op == OP_CALL)
5155 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
5157 else if (po->op == OP_POP)
5159 else if (po->flags & OPF_CJMP)
5161 else if (po->op == OP_PUSH) {
5162 if (po->flags & (OPF_FARG|OPF_FARGNR))
5164 if (!g_header_mode) {
5165 ret = scan_for_mod(po, j + 1, i, 1);
5170 if (pp->arg[arg].type.is_va_list)
5174 for (arg++; arg < pp->argc; arg++)
5175 if (pp->arg[arg].reg == NULL)
5178 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5179 && po->operand[1].type == OPT_CONST)
5181 if (po->flags & (OPF_RMD|OPF_DONE))
5183 if (po->operand[1].val != pp->argc_stack * 4)
5184 ferr(po, "unexpected esp adjust: %d\n",
5185 po->operand[1].val * 4);
5186 ferr_assert(po, pp->argc - arg == pp->argc_stack);
5187 return collect_call_args_no_push(i, pp, regmask_ffca);
5195 for (arg = 0; arg < pp->argc; arg++)
5196 if (pp->arg[arg].reg == NULL)
5199 for (j = i; j > 0 && arg < pp->argc; )
5203 if (ops[j].op == OP_PUSH)
5205 ops[j].p_argnext = -1;
5206 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
5208 k = check_for_stp(j + 1, i);
5210 // push ecx; fstp dword ptr [esp]
5211 ret = parse_stack_esp_offset(&ops[k],
5212 ops[k].operand[0].name, &offset);
5213 if (ret == 0 && offset == 0) {
5214 if (!pp->arg[arg].type.is_float)
5215 ferr(&ops[i], "arg %d should be float\n", arg + 1);
5216 mark_float_arg(&ops[k], pp, arg, regmask_ffca);
5220 if (pp->arg[arg].datap == NULL) {
5221 pp->arg[arg].datap = &ops[j];
5222 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5223 *regmask |= 1 << ops[j].operand[0].reg;
5226 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5227 ops[j].flags &= ~OPF_RSAVE;
5230 for (arg++; arg < pp->argc; arg++)
5231 if (pp->arg[arg].reg == NULL)
5239 static int sync_argnum(struct parsed_op *po, int argnum)
5241 struct parsed_op *po_tmp;
5243 // see if other branches don't have higher argnum
5244 for (po_tmp = po; po_tmp != NULL; ) {
5245 if (argnum < po_tmp->p_argnum)
5246 argnum = po_tmp->p_argnum;
5247 // note: p_argnext is active on current collect_call_args only
5248 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5251 // make all argnums consistent
5252 for (po_tmp = po; po_tmp != NULL; ) {
5253 if (po_tmp->p_argnum != 0)
5254 po_tmp->p_argnum = argnum;
5255 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5261 static int collect_call_args_r(struct parsed_op *po, int i,
5262 struct parsed_proto *pp, int *regmask, int *arg_grp,
5263 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
5265 struct parsed_proto *pp_tmp;
5266 struct parsed_op *po_tmp;
5267 struct label_ref *lr;
5268 int need_to_save_current;
5269 int arg_grp_current = 0;
5270 int save_args_seen = 0;
5277 ferr(po, "dead label encountered\n");
5281 for (; arg < pp->argc; arg++, argnum++)
5282 if (pp->arg[arg].reg == NULL)
5284 magic = (magic & 0xffffff) | (arg << 24);
5286 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5288 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5289 if (ops[j].cc_scratch != magic) {
5290 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5294 // ok: have already been here
5297 ops[j].cc_scratch = magic;
5299 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5300 lr = &g_label_refs[j];
5301 if (lr->next != NULL)
5303 for (; lr->next; lr = lr->next) {
5304 check_i(&ops[j], lr->i);
5305 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5307 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5308 arg, argnum, magic, need_op_saving, may_reuse);
5313 check_i(&ops[j], lr->i);
5314 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5316 if (j > 0 && LAST_OP(j - 1)) {
5317 // follow last branch in reverse
5322 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5323 arg, argnum, magic, need_op_saving, may_reuse);
5329 if (ops[j].op == OP_CALL)
5331 if (pp->is_unresolved)
5336 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5337 arg, pp->argc, ops[j].operand[0].name);
5338 if (may_reuse && pp_tmp->argc_stack > 0)
5339 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5340 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5342 // esp adjust of 0 means we collected it before
5343 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5344 && (ops[j].operand[1].type != OPT_CONST
5345 || ops[j].operand[1].val != 0))
5347 if (pp->is_unresolved)
5350 fnote(po, "(this call)\n");
5351 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5352 arg, pp->argc, ops[j].operand[1].val);
5354 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5356 if (pp->is_unresolved)
5359 fnote(po, "(this call)\n");
5360 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5362 else if (ops[j].flags & OPF_CJMP)
5364 if (pp->is_unresolved)
5369 else if (ops[j].op == OP_PUSH
5370 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5372 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5375 ops[j].p_argnext = -1;
5376 po_tmp = pp->arg[arg].datap;
5378 ops[j].p_argnext = po_tmp - ops;
5379 pp->arg[arg].datap = &ops[j];
5381 argnum = sync_argnum(&ops[j], argnum);
5383 need_to_save_current = 0;
5385 if (ops[j].operand[0].type == OPT_REG)
5386 reg = ops[j].operand[0].reg;
5388 if (!need_op_saving) {
5389 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5390 need_to_save_current = (ret >= 0);
5392 if (need_op_saving || need_to_save_current) {
5393 // mark this arg as one that needs operand saving
5394 pp->arg[arg].is_saved = 1;
5396 if (save_args_seen & (1 << (argnum - 1))) {
5399 if (arg_grp_current >= MAX_ARG_GRP)
5400 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5404 else if (ops[j].p_argnum == 0)
5405 ops[j].flags |= OPF_RMD;
5407 // some PUSHes are reused by different calls on other branches,
5408 // but that can't happen if we didn't branch, so they
5409 // can be removed from future searches (handles nested calls)
5411 ops[j].flags |= OPF_FARGNR;
5413 ops[j].flags |= OPF_FARG;
5414 ops[j].flags &= ~OPF_RSAVE;
5416 // check for __VALIST
5417 if (!pp->is_unresolved && g_func_pp != NULL
5418 && pp->arg[arg].type.is_va_list)
5421 ret = resolve_origin(j, &ops[j].operand[0],
5422 magic + 1, &k, NULL);
5423 if (ret == 1 && k >= 0)
5425 if (ops[k].op == OP_LEA) {
5426 if (!g_func_pp->is_vararg)
5427 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5430 snprintf(buf, sizeof(buf), "arg_%X",
5431 g_func_pp->argc_stack * 4);
5432 if (strstr(ops[k].operand[1].name, buf)
5433 || strstr(ops[k].operand[1].name, "arglist"))
5435 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5436 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5437 pp->arg[arg].is_saved = 0;
5441 ferr(&ops[k], "va_list arg detection failed\n");
5443 // check for va_list from g_func_pp arg too
5444 else if (ops[k].op == OP_MOV
5445 && is_stack_access(&ops[k], &ops[k].operand[1]))
5447 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5448 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5450 ops[k].flags |= OPF_RMD | OPF_DONE;
5451 ops[j].flags |= OPF_RMD;
5452 ops[j].p_argpass = ret + 1;
5453 pp->arg[arg].is_saved = 0;
5460 if (pp->arg[arg].is_saved) {
5461 ops[j].flags &= ~OPF_RMD;
5462 ops[j].p_argnum = argnum;
5465 // tracking reg usage
5467 *regmask |= 1 << reg;
5471 if (!pp->is_unresolved) {
5473 for (; arg < pp->argc; arg++, argnum++)
5474 if (pp->arg[arg].reg == NULL)
5477 magic = (magic & 0xffffff) | (arg << 24);
5480 if (ops[j].p_arggrp > arg_grp_current) {
5482 arg_grp_current = ops[j].p_arggrp;
5484 if (ops[j].p_argnum > 0)
5485 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5488 if (arg < pp->argc) {
5489 ferr(po, "arg collect failed for '%s': %d/%d\n",
5490 pp->name, arg, pp->argc);
5494 if (arg_grp_current > *arg_grp)
5495 *arg_grp = arg_grp_current;
5500 static int collect_call_args(struct parsed_op *po, int i,
5501 struct parsed_proto *pp, int *regmask, int magic)
5503 // arg group is for cases when pushes for
5504 // multiple funcs are going on
5505 struct parsed_op *po_tmp;
5510 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5516 // propagate arg_grp
5517 for (a = 0; a < pp->argc; a++) {
5518 if (pp->arg[a].reg != NULL)
5521 po_tmp = pp->arg[a].datap;
5522 while (po_tmp != NULL) {
5523 po_tmp->p_arggrp = arg_grp;
5524 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5529 if (pp->is_unresolved) {
5531 pp->argc_stack += ret;
5532 for (a = 0; a < pp->argc; a++)
5533 if (pp->arg[a].type.name == NULL)
5534 pp->arg[a].type.name = strdup("int");
5540 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5541 int regmask_now, int *regmask,
5542 int regmask_save_now, int *regmask_save,
5543 int *regmask_init, int regmask_arg)
5545 struct parsed_op *po;
5553 for (; i < opcnt; i++)
5556 if (cbits[i >> 3] & (1 << (i & 7)))
5558 cbits[i >> 3] |= (1 << (i & 7));
5560 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5561 if (po->flags & (OPF_RMD|OPF_DONE))
5563 if (po->btj != NULL) {
5564 for (j = 0; j < po->btj->count; j++) {
5565 check_i(po, po->btj->d[j].bt_i);
5566 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5567 regmask_now, regmask, regmask_save_now, regmask_save,
5568 regmask_init, regmask_arg);
5573 check_i(po, po->bt_i);
5574 if (po->flags & OPF_CJMP)
5575 reg_use_pass(po->bt_i, opcnt, cbits,
5576 regmask_now, regmask, regmask_save_now, regmask_save,
5577 regmask_init, regmask_arg);
5583 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5584 && !g_func_pp->is_userstack
5585 && po->operand[0].type == OPT_REG)
5587 reg = po->operand[0].reg;
5588 ferr_assert(po, reg >= 0);
5591 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5592 if (regmask_now & (1 << reg)) {
5593 already_saved = regmask_save_now & (1 << reg);
5594 flags_set = OPF_RSAVE | OPF_DONE;
5597 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5599 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5600 reg, 0, 0, flags_set);
5603 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5605 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5610 ferr_assert(po, !already_saved);
5611 po->flags |= flags_set;
5613 if (regmask_now & (1 << reg)) {
5614 regmask_save_now |= (1 << reg);
5615 *regmask_save |= regmask_save_now;
5620 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5621 reg = po->operand[0].reg;
5622 ferr_assert(po, reg >= 0);
5624 if (regmask_save_now & (1 << reg))
5625 regmask_save_now &= ~(1 << reg);
5627 regmask_now &= ~(1 << reg);
5630 else if (po->op == OP_CALL) {
5631 if ((po->regmask_dst & (1 << xAX))
5632 && !(po->regmask_dst & (1 << xDX)))
5634 if (po->flags & OPF_TAIL)
5635 // don't need eax, will do "return f();" or "f(); return;"
5636 po->regmask_dst &= ~(1 << xAX);
5638 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5640 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5643 po->regmask_dst &= ~(1 << xAX);
5647 // not "full stack" mode and have something in stack
5648 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5649 ferr(po, "float stack is not empty on func call\n");
5652 if (po->flags & OPF_NOREGS)
5655 // if incomplete register is used, clear it on init to avoid
5656 // later use of uninitialized upper part in some situations
5657 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5658 && po->operand[0].lmod != OPLM_DWORD)
5660 reg = po->operand[0].reg;
5661 ferr_assert(po, reg >= 0);
5663 if (!(regmask_now & (1 << reg)))
5664 *regmask_init |= 1 << reg;
5667 regmask_op = po->regmask_src | po->regmask_dst;
5669 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5670 regmask_new &= ~(1 << xSP);
5671 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5672 regmask_new &= ~(1 << xBP);
5674 if (regmask_new != 0)
5675 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5677 if (regmask_op & (1 << xBP)) {
5678 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5679 if (po->regmask_dst & (1 << xBP))
5680 // compiler decided to drop bp frame and use ebp as scratch
5681 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5683 regmask_op &= ~(1 << xBP);
5687 if (po->flags & OPF_FPUSH) {
5688 if (regmask_now & mxST1)
5689 regmask_now |= mxSTa; // switch to "full stack" mode
5690 if (regmask_now & mxSTa)
5691 po->flags |= OPF_FSHIFT;
5692 if (!(regmask_now & mxST7_2)) {
5694 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5698 regmask_now |= regmask_op;
5699 *regmask |= regmask_now;
5702 if (po->flags & OPF_FPOPP) {
5703 if ((regmask_now & mxSTa) == 0)
5704 ferr(po, "float pop on empty stack?\n");
5705 if (regmask_now & mxST7_2)
5706 po->flags |= OPF_FSHIFT;
5707 if (!(regmask_now & mxST7_2))
5708 regmask_now &= ~mxST1_0;
5710 else if (po->flags & OPF_FPOP) {
5711 if ((regmask_now & mxSTa) == 0)
5712 ferr(po, "float pop on empty stack?\n");
5713 if (regmask_now & (mxST7_2 | mxST1))
5714 po->flags |= OPF_FSHIFT;
5715 if (!(regmask_now & mxST7_2)) {
5717 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5721 if (po->flags & OPF_TAIL) {
5722 if (!(regmask_now & mxST7_2)) {
5723 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5724 if (!(regmask_now & mxST0))
5725 ferr(po, "no st0 on float return, mask: %x\n",
5728 else if (regmask_now & mxST1_0)
5729 ferr(po, "float regs on tail: %x\n", regmask_now);
5732 // there is support for "conditional tailcall", sort of
5733 if (!(po->flags & OPF_CC))
5739 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5743 for (i = 0; i < pp->argc; i++)
5744 if (pp->arg[i].reg == NULL)
5748 memmove(&pp->arg[i + 1], &pp->arg[i],
5749 sizeof(pp->arg[0]) * pp->argc_stack);
5750 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5751 pp->arg[i].reg = strdup(reg);
5752 pp->arg[i].type.name = strdup("int");
5757 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5758 int *pfomask, const char *dst_opr_text)
5760 if (*pfomask & (1 << PFO_Z)) {
5761 fprintf(fout, "\n cond_z = (%s%s == 0);",
5762 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5763 *pfomask &= ~(1 << PFO_Z);
5767 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5768 int *pfomask, const char *dst_opr_text)
5770 if (*pfomask & (1 << PFO_S)) {
5771 fprintf(fout, "\n cond_s = (%s%s < 0);",
5772 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5773 *pfomask &= ~(1 << PFO_S);
5777 static void output_std_flags(FILE *fout, struct parsed_op *po,
5778 int *pfomask, const char *dst_opr_text)
5780 output_std_flag_z(fout, po, pfomask, dst_opr_text);
5781 output_std_flag_s(fout, po, pfomask, dst_opr_text);
5785 OPP_FORCE_NORETURN = (1 << 0),
5786 OPP_SIMPLE_ARGS = (1 << 1),
5787 OPP_ALIGN = (1 << 2),
5790 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5793 const char *cconv = "";
5795 if (pp->is_fastcall)
5796 cconv = "__fastcall ";
5797 else if (pp->is_stdcall && pp->argc_reg == 0)
5798 cconv = "__stdcall ";
5800 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5802 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5803 fprintf(fout, "noreturn ");
5806 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5811 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5815 output_pp_attrs(fout, pp, flags);
5818 fprintf(fout, "%s", pp->name);
5823 for (i = 0; i < pp->argc; i++) {
5825 fprintf(fout, ", ");
5826 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5827 && !(flags & OPP_SIMPLE_ARGS))
5830 output_pp(fout, pp->arg[i].pp, 0);
5832 else if (pp->arg[i].type.is_retreg) {
5833 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5836 fprintf(fout, "%s", pp->arg[i].type.name);
5838 fprintf(fout, " a%d", i + 1);
5841 if (pp->arg[i].type.is_64bit)
5844 if (pp->is_vararg) {
5846 fprintf(fout, ", ");
5847 fprintf(fout, "...");
5852 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5858 snprintf(buf1, sizeof(buf1), "%d", grp);
5859 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5864 static void gen_x_cleanup(int opcnt);
5866 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5868 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5869 struct parsed_opr *last_arith_dst = NULL;
5870 char buf1[256], buf2[256], buf3[256], cast[64];
5871 struct parsed_proto *pp, *pp_tmp;
5872 struct parsed_data *pd;
5873 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5874 unsigned char cbits[MAX_OPS / 8];
5875 const char *float_type;
5876 const char *float_st0;
5877 const char *float_st1;
5878 int need_float_stack = 0;
5879 int need_float_sw = 0; // status word
5880 int need_tmp_var = 0;
5884 int label_pending = 0;
5885 int need_double = 0;
5886 int stack_align = 0;
5887 int stack_fsz_adj = 0;
5888 int regmask_save = 0; // used regs saved/restored in this func
5889 int regmask_arg; // regs from this function args (fastcall, etc)
5890 int regmask_ret; // regs needed on ret
5891 int regmask_now; // temp
5892 int regmask_init = 0; // regs that need zero initialization
5893 int regmask_pp = 0; // regs used in complex push-pop graph
5894 int regmask_ffca = 0; // float function call args
5895 int regmask = 0; // used regs
5905 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5906 g_stack_frame_used = 0;
5908 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5909 regmask_init = g_regmask_init;
5911 g_func_pp = proto_parse(fhdr, funcn, 0);
5912 if (g_func_pp == NULL)
5913 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5915 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5916 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5919 // - resolve all branches
5920 // - parse calls with labels
5921 resolve_branches_parse_calls(opcnt);
5924 // - handle ebp/esp frame, remove ops related to it
5925 scan_prologue_epilogue(opcnt, &stack_align);
5927 // handle a case where sf size is unalignment, but is
5928 // placed in a way that elements are still aligned
5929 if (g_stack_fsz & 4) {
5930 for (i = 0; i < g_eqcnt; i++) {
5931 if (g_eqs[i].lmod != OPLM_QWORD)
5933 if (!(g_eqs[i].offset & 4)) {
5942 // - remove dead labels
5943 // - set regs needed at ret
5944 for (i = 0; i < opcnt; i++)
5946 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5951 if (ops[i].op == OP_RET)
5952 ops[i].regmask_src |= regmask_ret;
5956 // - process trivial calls
5957 for (i = 0; i < opcnt; i++)
5960 if (po->flags & (OPF_RMD|OPF_DONE))
5963 if (po->op == OP_CALL)
5965 pp = process_call_early(i, opcnt, &j);
5967 if (!(po->flags & OPF_ATAIL)) {
5968 // since we know the args, try to collect them
5969 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5977 // commit esp adjust
5978 if (ops[j].op != OP_POP)
5979 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5981 for (l = 0; l < pp->argc_stack; l++)
5982 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5986 if (strstr(pp->ret_type.name, "int64"))
5989 po->flags |= OPF_DONE;
5995 // - process calls, stage 2
5996 // - handle some push/pop pairs
5997 // - scan for STD/CLD, propagate DF
5998 // - try to resolve needed x87 status word bits
5999 for (i = 0; i < opcnt; i++)
6004 if (po->flags & OPF_RMD)
6007 if (po->op == OP_CALL)
6009 if (!(po->flags & OPF_DONE)) {
6010 pp = process_call(i, opcnt);
6012 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
6013 // since we know the args, collect them
6014 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6016 // for unresolved, collect after other passes
6020 ferr_assert(po, pp != NULL);
6022 po->regmask_src |= get_pp_arg_regmask_src(pp);
6023 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
6025 if (po->regmask_dst & mxST0)
6026 po->flags |= OPF_FPUSH;
6028 if (strstr(pp->ret_type.name, "int64"))
6034 if (po->flags & OPF_DONE)
6039 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
6040 && po->operand[0].type == OPT_CONST)
6042 scan_for_pop_const(i, opcnt, i + opcnt * 12);
6047 scan_pushes_for_pop(i, opcnt, ®mask_pp);
6051 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
6052 scan_propagate_df(i + 1, opcnt);
6057 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
6058 ferr(po, "TODO: fnstsw to mem\n");
6059 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
6061 ferr(po, "fnstsw resolve failed\n");
6062 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
6063 (void *)(long)(mask | (z_check << 16)));
6065 ferr(po, "failed to find fcom: %d\n", ret);
6074 // - find POPs for PUSHes, rm both
6075 // - scan for all used registers
6076 memset(cbits, 0, sizeof(cbits));
6077 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
6078 0, ®mask_save, ®mask_init, regmask_arg);
6080 need_float_stack = !!(regmask & mxST7_2);
6083 // - find flag set ops for their users
6084 // - do unresolved calls
6085 // - declare indirect functions
6086 // - other op specific processing
6087 for (i = 0; i < opcnt; i++)
6090 if (po->flags & (OPF_RMD|OPF_DONE))
6093 if (po->flags & OPF_CC)
6095 int setters[16], cnt = 0, branched = 0;
6097 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
6098 &branched, setters, &cnt);
6099 if (ret < 0 || cnt <= 0)
6100 ferr(po, "unable to trace flag setter(s)\n");
6101 if (cnt > ARRAY_SIZE(setters))
6102 ferr(po, "too many flag setters\n");
6104 for (j = 0; j < cnt; j++)
6106 tmp_op = &ops[setters[j]]; // flag setter
6109 // to get nicer code, we try to delay test and cmp;
6110 // if we can't because of operand modification, or if we
6111 // have arith op, or branch, make it calculate flags explicitly
6112 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
6114 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
6115 pfomask = 1 << po->pfo;
6117 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
6118 pfomask = 1 << po->pfo;
6121 // see if we'll be able to handle based on op result
6122 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
6123 && po->pfo != PFO_Z && po->pfo != PFO_S
6124 && po->pfo != PFO_P)
6126 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
6128 pfomask = 1 << po->pfo;
6131 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
6132 propagate_lmod(tmp_op, &tmp_op->operand[0],
6133 &tmp_op->operand[1]);
6134 if (tmp_op->operand[0].lmod == OPLM_DWORD)
6139 tmp_op->pfomask |= pfomask;
6140 cond_vars |= pfomask;
6142 // note: may overwrite, currently not a problem
6146 if (po->op == OP_RCL || po->op == OP_RCR
6147 || po->op == OP_ADC || po->op == OP_SBB)
6148 cond_vars |= 1 << PFO_C;
6154 cond_vars |= 1 << PFO_Z;
6158 if (po->operand[0].lmod == OPLM_DWORD)
6163 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
6168 // note: resolved non-reg calls are OPF_DONE already
6170 ferr_assert(po, pp != NULL);
6172 if (pp->is_unresolved) {
6173 int regmask_stack = 0;
6174 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6176 // this is pretty rough guess:
6177 // see ecx and edx were pushed (and not their saved versions)
6178 for (arg = 0; arg < pp->argc; arg++) {
6179 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
6182 tmp_op = pp->arg[arg].datap;
6184 ferr(po, "parsed_op missing for arg%d\n", arg);
6185 if (tmp_op->operand[0].type == OPT_REG)
6186 regmask_stack |= 1 << tmp_op->operand[0].reg;
6189 if (!((regmask_stack & (1 << xCX))
6190 && (regmask_stack & (1 << xDX))))
6192 if (pp->argc_stack != 0
6193 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
6195 pp_insert_reg_arg(pp, "ecx");
6196 pp->is_fastcall = 1;
6197 regmask_init |= 1 << xCX;
6198 regmask |= 1 << xCX;
6200 if (pp->argc_stack != 0
6201 || ((regmask | regmask_arg) & (1 << xDX)))
6203 pp_insert_reg_arg(pp, "edx");
6204 regmask_init |= 1 << xDX;
6205 regmask |= 1 << xDX;
6209 // note: __cdecl doesn't fall into is_unresolved category
6210 if (pp->argc_stack > 0)
6216 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6218 // <var> = offset <something>
6219 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6220 && !IS_START(po->operand[1].name, "off_"))
6222 if (!po->operand[0].pp->is_fptr)
6223 ferr(po, "%s not declared as fptr when it should be\n",
6224 po->operand[0].name);
6225 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6226 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6227 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6228 fnote(po, "var: %s\n", buf1);
6229 fnote(po, "func: %s\n", buf2);
6230 ferr(po, "^ mismatch\n");
6238 if (po->operand[0].lmod == OPLM_DWORD) {
6239 // 32bit division is common, look for it
6240 if (po->op == OP_DIV)
6241 ret = scan_for_reg_clear(i, xDX);
6243 ret = scan_for_cdq_edx(i);
6245 po->flags |= OPF_32BIT;
6254 po->flags |= OPF_RMD | OPF_DONE;
6264 if (po->operand[0].lmod == OPLM_QWORD)
6274 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
6276 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
6278 po->flags |= OPF_32BIT;
6286 // this might need it's own pass...
6287 if (po->op != OP_FST && po->p_argnum > 0)
6288 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6290 // correct for "full stack" mode late enable
6291 if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6292 && need_float_stack)
6293 po->flags |= OPF_FSHIFT;
6296 float_type = need_double ? "double" : "float";
6297 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6298 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6300 // output starts here
6303 fprintf(fout, "// had SEH\n");
6305 // define userstack size
6306 if (g_func_pp->is_userstack) {
6307 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6308 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6309 fprintf(fout, "#endif\n");
6312 // the function itself
6313 ferr_assert(ops, !g_func_pp->is_fptr);
6314 output_pp(fout, g_func_pp,
6315 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6316 fprintf(fout, "\n{\n");
6318 // declare indirect functions
6319 for (i = 0; i < opcnt; i++) {
6321 if (po->flags & OPF_RMD)
6324 if (po->op == OP_CALL) {
6327 ferr(po, "NULL pp\n");
6329 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6330 if (pp->name[0] != 0) {
6331 if (IS_START(pp->name, "guess"))
6334 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6335 memcpy(pp->name, "i_", 2);
6337 // might be declared already
6339 for (j = 0; j < i; j++) {
6340 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6341 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6351 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6354 output_pp(fout, pp, OPP_SIMPLE_ARGS);
6355 fprintf(fout, ";\n");
6360 // output LUTs/jumptables
6361 for (i = 0; i < g_func_pd_cnt; i++) {
6363 fprintf(fout, " static const ");
6364 if (pd->type == OPT_OFFSET) {
6365 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6367 for (j = 0; j < pd->count; j++) {
6369 fprintf(fout, ", ");
6370 fprintf(fout, "&&%s", pd->d[j].u.label);
6374 fprintf(fout, "%s %s[] =\n { ",
6375 lmod_type_u(ops, pd->lmod), pd->label);
6377 for (j = 0; j < pd->count; j++) {
6379 fprintf(fout, ", ");
6380 fprintf(fout, "%u", pd->d[j].u.val);
6383 fprintf(fout, " };\n");
6387 // declare stack frame, va_arg
6390 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6392 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6393 if (g_func_lmods & (1 << OPLM_WORD))
6394 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6395 if (g_func_lmods & (1 << OPLM_BYTE))
6396 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6397 if (g_func_lmods & (1 << OPLM_QWORD))
6398 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6400 if (stack_align > 8)
6401 ferr(ops, "unhandled stack align of %d\n", stack_align);
6402 else if (stack_align == 8)
6403 fprintf(fout, " u64 align;");
6404 fprintf(fout, " } sf;\n");
6408 if (g_func_pp->is_userstack) {
6409 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6410 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6414 if (g_func_pp->is_vararg) {
6415 fprintf(fout, " va_list ap;\n");
6419 // declare arg-registers
6420 for (i = 0; i < g_func_pp->argc; i++) {
6421 if (g_func_pp->arg[i].reg != NULL) {
6422 reg = char_array_i(regs_r32,
6423 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6424 if (regmask & (1 << reg)) {
6425 if (g_func_pp->arg[i].type.is_retreg)
6426 fprintf(fout, " u32 %s = *r_%s;\n",
6427 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6429 fprintf(fout, " u32 %s = (u32)a%d;\n",
6430 g_func_pp->arg[i].reg, i + 1);
6433 if (g_func_pp->arg[i].type.is_retreg)
6434 ferr(ops, "retreg '%s' is unused?\n",
6435 g_func_pp->arg[i].reg);
6436 fprintf(fout, " // %s = a%d; // unused\n",
6437 g_func_pp->arg[i].reg, i + 1);
6443 // declare normal registers
6444 regmask_now = regmask & ~regmask_arg & ~g_regmask_rm;
6445 regmask_now &= ~(1 << xSP);
6446 if (regmask_now & 0x00ff) {
6447 for (reg = 0; reg < 8; reg++) {
6448 if (regmask_now & (1 << reg)) {
6449 fprintf(fout, " u32 %s", regs_r32[reg]);
6450 if (regmask_init & (1 << reg))
6451 fprintf(fout, " = 0");
6452 fprintf(fout, ";\n");
6458 if (regmask_now & 0xff00) {
6459 for (reg = 8; reg < 16; reg++) {
6460 if (regmask_now & (1 << reg)) {
6461 fprintf(fout, " mmxr %s", regs_r32[reg]);
6462 if (regmask_init & (1 << reg))
6463 fprintf(fout, " = { 0, }");
6464 fprintf(fout, ";\n");
6470 if (need_float_stack) {
6471 fprintf(fout, " %s f_st[8];\n", float_type);
6472 fprintf(fout, " int f_stp = 0;\n");
6476 if (regmask_now & 0xff0000) {
6477 for (reg = 16; reg < 24; reg++) {
6478 if (regmask_now & (1 << reg)) {
6479 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6480 if (regmask_init & (1 << reg))
6481 fprintf(fout, " = 0");
6482 fprintf(fout, ";\n");
6489 if (need_float_sw) {
6490 fprintf(fout, " u16 f_sw;\n");
6495 for (reg = 0; reg < 8; reg++) {
6496 if (regmask_save & (1 << reg)) {
6497 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6503 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6504 if (save_arg_vars[i] == 0)
6506 for (reg = 0; reg < 32; reg++) {
6507 if (save_arg_vars[i] & (1 << reg)) {
6508 fprintf(fout, " u32 %s;\n",
6509 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6516 for (reg = 0; reg < 32; reg++) {
6517 if (regmask_ffca & (1 << reg)) {
6518 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6524 // declare push-pop temporaries
6526 for (reg = 0; reg < 8; reg++) {
6527 if (regmask_pp & (1 << reg)) {
6528 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6535 for (i = 0; i < 8; i++) {
6536 if (cond_vars & (1 << i)) {
6537 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6544 fprintf(fout, " u32 tmp;\n");
6549 fprintf(fout, " u64 tmp64;\n");
6554 fprintf(fout, "\n");
6556 // do stack clear, if needed
6557 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6559 if (g_stack_clear_len != 0) {
6560 if (g_stack_clear_len <= 4) {
6561 for (i = 0; i < g_stack_clear_len; i++)
6562 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6563 fprintf(fout, "0;\n");
6566 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6567 g_stack_clear_start, g_stack_clear_len * 4);
6571 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6574 if (g_func_pp->is_vararg) {
6575 if (g_func_pp->argc_stack == 0)
6576 ferr(ops, "vararg func without stack args?\n");
6577 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6581 for (i = 0; i < opcnt; i++)
6583 if (g_labels[i] != NULL) {
6584 fprintf(fout, "\n%s:\n", g_labels[i]);
6587 delayed_flag_op = NULL;
6588 last_arith_dst = NULL;
6592 if (po->flags & OPF_RMD)
6597 #define assert_operand_cnt(n_) \
6598 if (po->operand_cnt != n_) \
6599 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6601 // conditional/flag using op?
6602 if (po->flags & OPF_CC)
6608 // we go through all this trouble to avoid using parsed_flag_op,
6609 // which makes generated code much nicer
6610 if (delayed_flag_op != NULL)
6612 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6613 po->pfo, po->pfo_inv);
6616 else if (last_arith_dst != NULL
6617 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6618 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6621 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6622 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6623 last_arith_dst->lmod, buf3);
6626 else if (tmp_op != NULL) {
6627 // use preprocessed flag calc results
6628 if (!(tmp_op->pfomask & (1 << po->pfo)))
6629 ferr(po, "not prepared for pfo %d\n", po->pfo);
6631 // note: pfo_inv was not yet applied
6632 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6633 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6636 ferr(po, "all methods of finding comparison failed\n");
6639 if (po->flags & OPF_JMP) {
6640 fprintf(fout, " if %s", buf1);
6642 else if (po->op == OP_RCL || po->op == OP_RCR
6643 || po->op == OP_ADC || po->op == OP_SBB)
6646 fprintf(fout, " cond_%s = %s;\n",
6647 parsed_flag_op_names[po->pfo], buf1);
6649 else if (po->flags & OPF_DATA) { // SETcc
6650 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6651 fprintf(fout, " %s = %s;", buf2, buf1);
6654 ferr(po, "unhandled conditional op\n");
6658 pfomask = po->pfomask;
6663 assert_operand_cnt(2);
6664 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6665 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6666 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6667 fprintf(fout, " %s = %s;", buf1,
6668 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6673 assert_operand_cnt(2);
6674 po->operand[1].lmod = OPLM_DWORD; // always
6675 fprintf(fout, " %s = %s;",
6676 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6677 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6682 assert_operand_cnt(2);
6683 fprintf(fout, " %s = %s;",
6684 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6685 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6689 assert_operand_cnt(2);
6690 switch (po->operand[1].lmod) {
6692 strcpy(buf3, "(s8)");
6695 strcpy(buf3, "(s16)");
6698 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6700 fprintf(fout, " %s = %s;",
6701 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6702 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6707 assert_operand_cnt(2);
6708 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6709 fprintf(fout, " tmp = %s;",
6710 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6711 fprintf(fout, " %s = %s;",
6712 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6713 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6714 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6715 fprintf(fout, " %s = %stmp;",
6716 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6717 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6718 snprintf(g_comment, sizeof(g_comment), "xchg");
6722 assert_operand_cnt(1);
6723 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6724 fprintf(fout, " %s = ~%s;", buf1, buf1);
6728 assert_operand_cnt(2);
6729 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6730 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6731 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6732 strcpy(g_comment, "xlat");
6736 assert_operand_cnt(2);
6737 fprintf(fout, " %s = (s32)%s >> 31;",
6738 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6739 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6740 strcpy(g_comment, "cdq");
6744 assert_operand_cnt(1);
6745 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6746 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6750 if (po->flags & OPF_REP) {
6751 assert_operand_cnt(3);
6756 assert_operand_cnt(2);
6757 fprintf(fout, " %s = %sesi; esi %c= %d;",
6758 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6759 lmod_cast_u_ptr(po, po->operand[1].lmod),
6760 (po->flags & OPF_DF) ? '-' : '+',
6761 lmod_bytes(po, po->operand[1].lmod));
6762 strcpy(g_comment, "lods");
6767 if (po->flags & OPF_REP) {
6768 assert_operand_cnt(3);
6769 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6770 (po->flags & OPF_DF) ? '-' : '+',
6771 lmod_bytes(po, po->operand[1].lmod));
6772 fprintf(fout, " %sedi = eax;",
6773 lmod_cast_u_ptr(po, po->operand[1].lmod));
6774 strcpy(g_comment, "rep stos");
6777 assert_operand_cnt(2);
6778 fprintf(fout, " %sedi = eax; edi %c= %d;",
6779 lmod_cast_u_ptr(po, po->operand[1].lmod),
6780 (po->flags & OPF_DF) ? '-' : '+',
6781 lmod_bytes(po, po->operand[1].lmod));
6782 strcpy(g_comment, "stos");
6787 j = lmod_bytes(po, po->operand[0].lmod);
6788 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6789 l = (po->flags & OPF_DF) ? '-' : '+';
6790 if (po->flags & OPF_REP) {
6791 assert_operand_cnt(3);
6793 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6796 " %sedi = %sesi;", buf1, buf1);
6797 strcpy(g_comment, "rep movs");
6800 assert_operand_cnt(2);
6801 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6802 buf1, buf1, l, j, l, j);
6803 strcpy(g_comment, "movs");
6808 // repe ~ repeat while ZF=1
6809 j = lmod_bytes(po, po->operand[0].lmod);
6810 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6811 l = (po->flags & OPF_DF) ? '-' : '+';
6812 if (po->flags & OPF_REP) {
6813 assert_operand_cnt(3);
6815 " while (ecx != 0) {\n");
6816 if (pfomask & (1 << PFO_C)) {
6819 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6820 pfomask &= ~(1 << PFO_C);
6823 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6824 buf1, buf1, l, j, l, j);
6827 " if (cond_z %s 0) break;\n",
6828 (po->flags & OPF_REPZ) ? "==" : "!=");
6831 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6832 (po->flags & OPF_REPZ) ? "e" : "ne");
6835 assert_operand_cnt(2);
6837 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6838 buf1, buf1, l, j, l, j);
6839 strcpy(g_comment, "cmps");
6841 pfomask &= ~(1 << PFO_Z);
6842 last_arith_dst = NULL;
6843 delayed_flag_op = NULL;
6847 // only does ZF (for now)
6848 // repe ~ repeat while ZF=1
6849 j = lmod_bytes(po, po->operand[1].lmod);
6850 l = (po->flags & OPF_DF) ? '-' : '+';
6851 if (po->flags & OPF_REP) {
6852 assert_operand_cnt(3);
6854 " while (ecx != 0) {\n");
6856 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6857 lmod_cast_u(po, po->operand[1].lmod),
6858 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6861 " if (cond_z %s 0) break;\n",
6862 (po->flags & OPF_REPZ) ? "==" : "!=");
6865 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6866 (po->flags & OPF_REPZ) ? "e" : "ne");
6869 assert_operand_cnt(2);
6870 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6871 lmod_cast_u(po, po->operand[1].lmod),
6872 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6873 strcpy(g_comment, "scas");
6875 pfomask &= ~(1 << PFO_Z);
6876 last_arith_dst = NULL;
6877 delayed_flag_op = NULL;
6880 // arithmetic w/flags
6882 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6883 goto dualop_arith_const;
6884 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6888 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6889 if (po->operand[1].type == OPT_CONST) {
6890 j = lmod_bytes(po, po->operand[0].lmod);
6891 if (((1ull << j * 8) - 1) == po->operand[1].val)
6892 goto dualop_arith_const;
6897 assert_operand_cnt(2);
6898 fprintf(fout, " %s %s= %s;",
6899 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6901 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6902 output_std_flags(fout, po, &pfomask, buf1);
6903 last_arith_dst = &po->operand[0];
6904 delayed_flag_op = NULL;
6908 // and 0, or ~0 used instead mov
6909 assert_operand_cnt(2);
6910 fprintf(fout, " %s = %s;",
6911 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6912 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6913 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6914 output_std_flags(fout, po, &pfomask, buf1);
6915 last_arith_dst = &po->operand[0];
6916 delayed_flag_op = NULL;
6921 assert_operand_cnt(2);
6922 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6923 if (pfomask & (1 << PFO_C)) {
6924 if (po->operand[1].type == OPT_CONST) {
6925 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6926 j = po->operand[1].val;
6929 if (po->op == OP_SHL)
6933 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6937 ferr(po, "zero shift?\n");
6941 pfomask &= ~(1 << PFO_C);
6943 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6944 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6945 if (po->operand[1].type != OPT_CONST)
6946 fprintf(fout, " & 0x1f");
6948 output_std_flags(fout, po, &pfomask, buf1);
6949 last_arith_dst = &po->operand[0];
6950 delayed_flag_op = NULL;
6954 assert_operand_cnt(2);
6955 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6956 fprintf(fout, " %s = %s%s >> %s;", buf1,
6957 lmod_cast_s(po, po->operand[0].lmod), buf1,
6958 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6959 output_std_flags(fout, po, &pfomask, buf1);
6960 last_arith_dst = &po->operand[0];
6961 delayed_flag_op = NULL;
6966 assert_operand_cnt(3);
6967 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6968 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6969 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6970 if (po->operand[2].type != OPT_CONST) {
6971 // no handling for "undefined" case, hopefully not needed
6972 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6975 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6976 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6977 if (po->op == OP_SHLD) {
6978 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6979 buf1, buf3, buf1, buf2, l, buf3);
6980 strcpy(g_comment, "shld");
6983 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6984 buf1, buf3, buf1, buf2, l, buf3);
6985 strcpy(g_comment, "shrd");
6987 output_std_flags(fout, po, &pfomask, buf1);
6988 last_arith_dst = &po->operand[0];
6989 delayed_flag_op = NULL;
6994 assert_operand_cnt(2);
6995 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6996 if (po->operand[1].type == OPT_CONST) {
6997 j = po->operand[1].val;
6998 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6999 fprintf(fout, po->op == OP_ROL ?
7000 " %s = (%s << %d) | (%s >> %d);" :
7001 " %s = (%s >> %d) | (%s << %d);",
7002 buf1, buf1, j, buf1,
7003 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
7007 output_std_flags(fout, po, &pfomask, buf1);
7008 last_arith_dst = &po->operand[0];
7009 delayed_flag_op = NULL;
7014 assert_operand_cnt(2);
7015 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7016 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7017 if (po->operand[1].type == OPT_CONST) {
7018 j = po->operand[1].val % l;
7020 ferr(po, "zero rotate\n");
7021 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
7022 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
7023 if (po->op == OP_RCL) {
7025 " %s = (%s << %d) | (cond_c << %d)",
7026 buf1, buf1, j, j - 1);
7028 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
7032 " %s = (%s >> %d) | (cond_c << %d)",
7033 buf1, buf1, j, l - j);
7035 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
7037 fprintf(fout, ";\n");
7038 fprintf(fout, " cond_c = tmp;");
7042 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
7043 output_std_flags(fout, po, &pfomask, buf1);
7044 last_arith_dst = &po->operand[0];
7045 delayed_flag_op = NULL;
7049 assert_operand_cnt(2);
7050 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7051 if (IS(opr_name(po, 0), opr_name(po, 1))) {
7052 // special case for XOR
7053 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
7054 for (j = 0; j <= PFO_LE; j++) {
7055 if (pfomask & (1 << j)) {
7056 fprintf(fout, " cond_%s = %d;\n",
7057 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
7058 pfomask &= ~(1 << j);
7061 fprintf(fout, " %s = 0;",
7062 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7063 last_arith_dst = &po->operand[0];
7064 delayed_flag_op = NULL;
7070 assert_operand_cnt(2);
7071 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7072 if (pfomask & (1 << PFO_C)) {
7073 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7074 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7075 if (po->operand[0].lmod == OPLM_DWORD) {
7076 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
7077 fprintf(fout, " cond_c = tmp64 >> 32;\n");
7078 fprintf(fout, " %s = (u32)tmp64;",
7079 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7080 strcat(g_comment, " add64");
7083 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
7084 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
7085 fprintf(fout, " %s += %s;",
7086 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7089 pfomask &= ~(1 << PFO_C);
7090 output_std_flags(fout, po, &pfomask, buf1);
7091 last_arith_dst = &po->operand[0];
7092 delayed_flag_op = NULL;
7095 if (pfomask & (1 << PFO_LE)) {
7096 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
7097 fprintf(fout, " cond_%s = %s;\n",
7098 parsed_flag_op_names[PFO_LE], buf1);
7099 pfomask &= ~(1 << PFO_LE);
7104 assert_operand_cnt(2);
7105 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7106 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
7107 for (j = 0; j <= PFO_LE; j++) {
7108 if (!(pfomask & (1 << j)))
7110 if (j == PFO_Z || j == PFO_S)
7113 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7114 fprintf(fout, " cond_%s = %s;\n",
7115 parsed_flag_op_names[j], buf1);
7116 pfomask &= ~(1 << j);
7123 assert_operand_cnt(2);
7124 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7125 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7126 if (po->op == OP_SBB
7127 && IS(po->operand[0].name, po->operand[1].name))
7129 // avoid use of unitialized var
7130 fprintf(fout, " %s = -cond_c;", buf1);
7131 // carry remains what it was
7132 pfomask &= ~(1 << PFO_C);
7135 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
7136 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7138 output_std_flags(fout, po, &pfomask, buf1);
7139 last_arith_dst = &po->operand[0];
7140 delayed_flag_op = NULL;
7145 // on SKL, if src is 0, dst is left unchanged
7146 assert_operand_cnt(2);
7147 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7148 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7149 output_std_flag_z(fout, po, &pfomask, buf2);
7150 if (po->op == OP_BSF)
7151 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
7153 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
7154 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
7155 last_arith_dst = &po->operand[0];
7156 delayed_flag_op = NULL;
7157 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
7161 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
7162 for (j = 0; j <= PFO_LE; j++) {
7163 if (!(pfomask & (1 << j)))
7165 if (j == PFO_Z || j == PFO_S || j == PFO_C)
7168 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7169 fprintf(fout, " cond_%s = %s;\n",
7170 parsed_flag_op_names[j], buf1);
7171 pfomask &= ~(1 << j);
7177 if (pfomask & (1 << PFO_C))
7178 // carry is unaffected by inc/dec.. wtf?
7179 ferr(po, "carry propagation needed\n");
7181 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7182 if (po->operand[0].type == OPT_REG) {
7183 strcpy(buf2, po->op == OP_INC ? "++" : "--");
7184 fprintf(fout, " %s%s;", buf1, buf2);
7187 strcpy(buf2, po->op == OP_INC ? "+" : "-");
7188 fprintf(fout, " %s %s= 1;", buf1, buf2);
7190 output_std_flags(fout, po, &pfomask, buf1);
7191 last_arith_dst = &po->operand[0];
7192 delayed_flag_op = NULL;
7196 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7197 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
7198 fprintf(fout, " %s = -%s%s;", buf1,
7199 lmod_cast_s(po, po->operand[0].lmod), buf2);
7200 last_arith_dst = &po->operand[0];
7201 delayed_flag_op = NULL;
7202 if (pfomask & PFOB_C) {
7203 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
7206 output_std_flags(fout, po, &pfomask, buf1);
7210 if (po->operand_cnt == 2) {
7211 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7214 if (po->operand_cnt == 3)
7215 ferr(po, "TODO imul3\n");
7218 assert_operand_cnt(1);
7219 switch (po->operand[0].lmod) {
7221 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7222 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
7223 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7224 fprintf(fout, " edx = tmp64 >> 32;\n");
7225 fprintf(fout, " eax = tmp64;");
7228 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7229 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
7230 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7234 ferr(po, "TODO: unhandled mul type\n");
7237 last_arith_dst = NULL;
7238 delayed_flag_op = NULL;
7243 assert_operand_cnt(1);
7244 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7245 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7246 po->op == OP_IDIV));
7247 switch (po->operand[0].lmod) {
7249 if (po->flags & OPF_32BIT)
7250 snprintf(buf2, sizeof(buf2), "%seax", cast);
7252 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7253 snprintf(buf2, sizeof(buf2), "%stmp64",
7254 (po->op == OP_IDIV) ? "(s64)" : "");
7256 if (po->operand[0].type == OPT_REG
7257 && po->operand[0].reg == xDX)
7259 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
7260 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
7263 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
7264 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
7268 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
7269 snprintf(buf2, sizeof(buf2), "%stmp",
7270 (po->op == OP_IDIV) ? "(s32)" : "");
7271 if (po->operand[0].type == OPT_REG
7272 && po->operand[0].reg == xDX)
7274 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
7276 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
7280 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
7282 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
7285 strcat(g_comment, " div16");
7288 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7290 last_arith_dst = NULL;
7291 delayed_flag_op = NULL;
7296 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7298 for (j = 0; j < 8; j++) {
7299 if (pfomask & (1 << j)) {
7300 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7301 fprintf(fout, " cond_%s = %s;",
7302 parsed_flag_op_names[j], buf1);
7309 last_arith_dst = NULL;
7310 delayed_flag_op = po;
7314 // SETcc - should already be handled
7317 // note: we reuse OP_Jcc for SETcc, only flags differ
7319 fprintf(fout, "\n goto %s;", po->operand[0].name);
7323 fprintf(fout, " if (ecx == 0)\n");
7324 fprintf(fout, " goto %s;", po->operand[0].name);
7325 strcat(g_comment, " jecxz");
7329 fprintf(fout, " if (--ecx != 0)\n");
7330 fprintf(fout, " goto %s;", po->operand[0].name);
7331 strcat(g_comment, " loop");
7335 assert_operand_cnt(1);
7336 last_arith_dst = NULL;
7337 delayed_flag_op = NULL;
7339 if (po->operand[0].type == OPT_REGMEM) {
7340 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7343 ferr(po, "parse failure for jmp '%s'\n",
7344 po->operand[0].name);
7345 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
7348 else if (po->operand[0].type != OPT_LABEL)
7349 ferr(po, "unhandled jmp type\n");
7351 fprintf(fout, " goto %s;", po->operand[0].name);
7355 assert_operand_cnt(1);
7357 my_assert_not(pp, NULL);
7360 if (po->flags & OPF_CC) {
7361 // we treat conditional branch to another func
7362 // (yes such code exists..) as conditional tailcall
7364 fprintf(fout, " {\n");
7367 if (pp->is_fptr && !pp->is_arg) {
7368 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7369 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7372 if (pp->is_fptr && (pp->is_unresolved || pp->is_guessed)) {
7373 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7374 buf3, asmfn, po->asmln, pp->name);
7377 fprintf(fout, "%s", buf3);
7378 if (strstr(pp->ret_type.name, "int64")) {
7379 if (po->flags & OPF_TAIL)
7380 ferr(po, "int64 and tail?\n");
7381 fprintf(fout, "tmp64 = ");
7383 else if (!IS(pp->ret_type.name, "void")) {
7384 if (po->flags & OPF_TAIL) {
7385 if (regmask_ret & mxAX) {
7386 fprintf(fout, "return ");
7387 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7388 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7390 else if (regmask_ret & mxST0)
7391 ferr(po, "float tailcall\n");
7393 else if (po->regmask_dst & mxAX) {
7394 fprintf(fout, "eax = ");
7395 if (pp->ret_type.is_ptr)
7396 fprintf(fout, "(u32)");
7398 else if (po->regmask_dst & mxST0) {
7399 ferr_assert(po, po->flags & OPF_FPUSH);
7400 if (need_float_stack)
7401 fprintf(fout, "f_st[--f_stp & 7] = ");
7403 fprintf(fout, "f_st0 = ");
7407 if (pp->name[0] == 0)
7408 ferr(po, "missing pp->name\n");
7409 fprintf(fout, "%s%s(", pp->name,
7410 pp->has_structarg ? "_sa" : "");
7412 if (po->flags & OPF_ATAIL) {
7414 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7415 check_compat |= pp->argc_stack > 0;
7417 && (pp->argc_stack != g_func_pp->argc_stack
7418 || pp->is_stdcall != g_func_pp->is_stdcall))
7419 ferr(po, "incompatible arg-reuse tailcall\n");
7420 if (g_func_pp->has_retreg)
7421 ferr(po, "TODO: retreg+tailcall\n");
7423 for (arg = j = 0; arg < pp->argc; arg++) {
7425 fprintf(fout, ", ");
7428 if (pp->arg[arg].type.is_ptr)
7429 snprintf(cast, sizeof(cast), "(%s)",
7430 pp->arg[arg].type.name);
7432 if (pp->arg[arg].reg != NULL) {
7433 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7437 for (; j < g_func_pp->argc; j++)
7438 if (g_func_pp->arg[j].reg == NULL)
7440 fprintf(fout, "%sa%d", cast, j + 1);
7445 for (arg = 0; arg < pp->argc; arg++) {
7447 fprintf(fout, ", ");
7450 if (pp->arg[arg].type.is_ptr)
7451 snprintf(cast, sizeof(cast), "(%s)",
7452 pp->arg[arg].type.name);
7454 if (pp->arg[arg].reg != NULL) {
7455 if (pp->arg[arg].type.is_retreg)
7456 fprintf(fout, "&%s", pp->arg[arg].reg);
7457 else if (IS(pp->arg[arg].reg, "ebp")
7458 && g_bp_frame && !(po->flags & OPF_EBP_S))
7460 // rare special case
7461 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7462 strcat(g_comment, " bp_ref");
7465 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7470 tmp_op = pp->arg[arg].datap;
7472 ferr(po, "parsed_op missing for arg%d\n", arg);
7474 if (tmp_op->flags & OPF_VAPUSH) {
7475 fprintf(fout, "ap");
7477 else if (tmp_op->op == OP_FST) {
7478 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7479 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7482 else if (pp->arg[arg].type.is_64bit) {
7483 ferr_assert(po, tmp_op->p_argpass == 0);
7484 ferr_assert(po, !pp->arg[arg].is_saved);
7485 ferr_assert(po, !pp->arg[arg].type.is_float);
7486 ferr_assert(po, cast[0] == 0);
7487 out_src_opr(buf1, sizeof(buf1),
7488 tmp_op, &tmp_op->operand[0], cast, 0);
7489 tmp_op = pp->arg[++arg].datap;
7490 ferr_assert(po, tmp_op != NULL);
7491 out_src_opr(buf2, sizeof(buf2),
7492 tmp_op, &tmp_op->operand[0], cast, 0);
7493 fprintf(fout, "((u64)(%s) << 32) | (%s)",
7496 else if (tmp_op->p_argpass != 0) {
7497 ferr_assert(po, !pp->arg[arg].type.is_float);
7498 fprintf(fout, "a%d", tmp_op->p_argpass);
7500 else if (pp->arg[arg].is_saved) {
7501 ferr_assert(po, tmp_op->p_argnum > 0);
7502 ferr_assert(po, !pp->arg[arg].type.is_float);
7503 fprintf(fout, "%s%s", cast,
7504 saved_arg_name(buf1, sizeof(buf1),
7505 tmp_op->p_arggrp, tmp_op->p_argnum));
7507 else if (pp->arg[arg].type.is_float) {
7508 ferr_assert(po, !pp->arg[arg].type.is_64bit);
7510 out_src_opr_float(buf1, sizeof(buf1),
7511 tmp_op, &tmp_op->operand[0], need_float_stack));
7515 out_src_opr(buf1, sizeof(buf1),
7516 tmp_op, &tmp_op->operand[0], cast, 0));
7520 fprintf(fout, ");");
7522 if (strstr(pp->ret_type.name, "int64")) {
7523 fprintf(fout, "\n");
7524 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7525 fprintf(fout, "%seax = tmp64;", buf3);
7528 if (pp->is_unresolved) {
7529 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7531 strcat(g_comment, buf2);
7534 if (po->flags & OPF_TAIL) {
7536 if (i == opcnt - 1 || pp->is_noreturn)
7538 else if (IS(pp->ret_type.name, "void"))
7540 else if (!(regmask_ret & (1 << xAX)))
7542 // else already handled as 'return f()'
7545 fprintf(fout, "\n%sreturn;", buf3);
7546 strcat(g_comment, " ^ tailcall");
7549 strcat(g_comment, " tailcall");
7551 if ((regmask_ret & (1 << xAX))
7552 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7554 ferr(po, "int func -> void func tailcall?\n");
7557 if (pp->is_noreturn)
7558 strcat(g_comment, " noreturn");
7559 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7560 strcat(g_comment, " argframe");
7561 if (po->flags & OPF_CC)
7562 strcat(g_comment, " cond");
7564 if (po->flags & OPF_CC)
7565 fprintf(fout, "\n }");
7567 delayed_flag_op = NULL;
7568 last_arith_dst = NULL;
7572 if (g_func_pp->is_vararg)
7573 fprintf(fout, " va_end(ap);\n");
7574 if (g_func_pp->has_retreg) {
7575 for (arg = 0; arg < g_func_pp->argc; arg++)
7576 if (g_func_pp->arg[arg].type.is_retreg)
7577 fprintf(fout, " *r_%s = %s;\n",
7578 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7581 if (regmask_ret & mxST0) {
7582 fprintf(fout, " return %s;", float_st0);
7584 else if (!(regmask_ret & mxAX)) {
7585 if (i != opcnt - 1 || label_pending)
7586 fprintf(fout, " return;");
7588 else if (g_func_pp->ret_type.is_ptr) {
7589 fprintf(fout, " return (%s)eax;",
7590 g_func_pp->ret_type.name);
7592 else if (IS(g_func_pp->ret_type.name, "__int64"))
7593 fprintf(fout, " return ((u64)edx << 32) | eax;");
7595 fprintf(fout, " return eax;");
7597 last_arith_dst = NULL;
7598 delayed_flag_op = NULL;
7602 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7603 if (po->p_argnum != 0) {
7604 // special case - saved func arg
7605 fprintf(fout, " %s = %s;",
7606 saved_arg_name(buf2, sizeof(buf2),
7607 po->p_arggrp, po->p_argnum), buf1);
7610 else if (po->flags & OPF_RSAVE) {
7611 fprintf(fout, " s_%s = %s;", buf1, buf1);
7614 else if (po->flags & OPF_PPUSH) {
7616 ferr_assert(po, tmp_op != NULL);
7617 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7618 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7621 else if (g_func_pp->is_userstack) {
7622 fprintf(fout, " *(--esp) = %s;", buf1);
7625 if (!(g_ida_func_attr & IDAFA_NORETURN))
7626 ferr(po, "stray push encountered\n");
7631 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7632 if (po->flags & OPF_RSAVE) {
7633 fprintf(fout, " %s = s_%s;", buf1, buf1);
7636 else if (po->flags & OPF_PPUSH) {
7637 // push/pop graph / non-const
7638 ferr_assert(po, po->datap == NULL);
7639 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7642 else if (po->datap != NULL) {
7645 fprintf(fout, " %s = %s;", buf1,
7646 out_src_opr(buf2, sizeof(buf2),
7647 tmp_op, &tmp_op->operand[0],
7648 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7651 else if (g_func_pp->is_userstack) {
7652 fprintf(fout, " %s = *esp++;", buf1);
7656 ferr(po, "stray pop encountered\n");
7666 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7667 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7668 po->op == OPP_ALLSHL ? "<<" : ">>");
7669 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7670 strcat(g_comment, po->op == OPP_ALLSHL
7671 ? " allshl" : " allshr");
7676 if (need_float_stack) {
7677 out_src_opr_float(buf1, sizeof(buf1),
7678 po, &po->operand[0], 1);
7679 if (po->regmask_src & mxSTa) {
7680 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7684 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7687 if (po->flags & OPF_FSHIFT)
7688 fprintf(fout, " f_st1 = f_st0;");
7689 if (po->operand[0].type == OPT_REG
7690 && po->operand[0].reg == xST0)
7692 strcat(g_comment, " fld st");
7695 fprintf(fout, " f_st0 = %s;",
7696 out_src_opr_float(buf1, sizeof(buf1),
7697 po, &po->operand[0], 0));
7699 strcat(g_comment, " fld");
7703 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7704 lmod_cast(po, po->operand[0].lmod, 1), 0);
7705 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7706 if (need_float_stack) {
7707 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7710 if (po->flags & OPF_FSHIFT)
7711 fprintf(fout, " f_st1 = f_st0;");
7712 fprintf(fout, " f_st0 = %s;", buf2);
7714 strcat(g_comment, " fild");
7718 if (need_float_stack)
7719 fprintf(fout, " f_st[--f_stp & 7] = ");
7721 if (po->flags & OPF_FSHIFT)
7722 fprintf(fout, " f_st1 = f_st0;");
7723 fprintf(fout, " f_st0 = ");
7725 switch (po->operand[0].val) {
7726 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7727 case X87_CONST_L2T: fprintf(fout, "3.321928094887362;"); break;
7728 case X87_CONST_L2E: fprintf(fout, "M_LOG2E;"); break;
7729 case X87_CONST_PI: fprintf(fout, "M_PI;"); break;
7730 case X87_CONST_LG2: fprintf(fout, "0.301029995663981;"); break;
7731 case X87_CONST_LN2: fprintf(fout, "M_LN2;"); break;
7732 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7733 default: ferr_assert(po, 0); break;
7738 if (po->flags & OPF_FARG) {
7739 // store to stack as func arg
7740 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7744 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7746 dead_dst = po->operand[0].type == OPT_REG
7747 && po->operand[0].reg == xST0;
7750 fprintf(fout, " %s = %s;", buf1, float_st0);
7751 if (po->flags & OPF_FSHIFT) {
7752 if (need_float_stack)
7753 fprintf(fout, " f_stp++;");
7755 fprintf(fout, " f_st0 = f_st1;");
7757 if (dead_dst && !(po->flags & OPF_FSHIFT))
7760 strcat(g_comment, " fst");
7764 fprintf(fout, " %s = %s%s;",
7765 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7766 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7767 if (po->flags & OPF_FSHIFT) {
7768 if (need_float_stack)
7769 fprintf(fout, " f_stp++;");
7771 fprintf(fout, " f_st0 = f_st1;");
7773 strcat(g_comment, " fist");
7780 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7782 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7784 dead_dst = (po->flags & OPF_FPOP)
7785 && po->operand[0].type == OPT_REG
7786 && po->operand[0].reg == xST0;
7788 case OP_FADD: j = '+'; break;
7789 case OP_FDIV: j = '/'; break;
7790 case OP_FMUL: j = '*'; break;
7791 case OP_FSUB: j = '-'; break;
7792 default: j = 'x'; break;
7794 if (need_float_stack) {
7796 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7797 if (po->flags & OPF_FSHIFT)
7798 fprintf(fout, " f_stp++;");
7801 if (po->flags & OPF_FSHIFT) {
7802 // note: assumes only 2 regs handled
7804 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7806 fprintf(fout, " f_st0 = f_st1;");
7809 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7811 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7816 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7818 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7820 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7822 dead_dst = (po->flags & OPF_FPOP)
7823 && po->operand[0].type == OPT_REG
7824 && po->operand[0].reg == xST0;
7825 j = po->op == OP_FDIVR ? '/' : '-';
7826 if (need_float_stack) {
7828 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7829 if (po->flags & OPF_FSHIFT)
7830 fprintf(fout, " f_stp++;");
7833 if (po->flags & OPF_FSHIFT) {
7835 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7837 fprintf(fout, " f_st0 = f_st1;");
7840 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7842 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7850 case OP_FIADD: j = '+'; break;
7851 case OP_FIDIV: j = '/'; break;
7852 case OP_FIMUL: j = '*'; break;
7853 case OP_FISUB: j = '-'; break;
7854 default: j = 'x'; break;
7856 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7858 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7859 lmod_cast(po, po->operand[0].lmod, 1), 0));
7864 fprintf(fout, " %s = %s %c %s;", float_st0,
7865 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7867 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7872 ferr_assert(po, po->datap != NULL);
7873 mask = (long)po->datap & 0xffff;
7874 z_check = ((long)po->datap >> 16) & 1;
7875 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7877 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
7878 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7881 else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
7882 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7885 else if (mask == 0x4100) { // C3, C0
7887 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7889 strcat(g_comment, " z_chk_det");
7892 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7893 "(%s < %s ? 0x0100 : 0);",
7894 float_st0, buf1, float_st0, buf1);
7898 ferr(po, "unhandled sw mask: %x\n", mask);
7899 if (po->flags & OPF_FSHIFT) {
7900 if (need_float_stack) {
7901 if (po->flags & OPF_FPOPP)
7902 fprintf(fout, " f_stp += 2;");
7904 fprintf(fout, " f_stp++;");
7907 ferr_assert(po, !(po->flags & OPF_FPOPP));
7908 fprintf(fout, " f_st0 = f_st1;");
7915 fprintf(fout, " %s = f_sw;",
7916 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7920 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7924 fprintf(fout, " %s = cos%s(%s);", float_st0,
7925 need_double ? "" : "f", float_st0);
7929 if (need_float_stack) {
7930 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7931 need_double ? "" : "f", float_st1, float_st0);
7932 fprintf(fout, " f_stp++;");
7935 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7936 need_double ? "" : "f");
7941 if (need_float_stack) {
7942 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7943 float_st1, need_double ? "" : "f", float_st0);
7944 fprintf(fout, " f_stp++;");
7947 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7948 need_double ? "" : "f");
7950 strcat(g_comment, " fyl2x");
7954 fprintf(fout, " %s = sin%s(%s);", float_st0,
7955 need_double ? "" : "f", float_st0);
7959 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7960 need_double ? "" : "f", float_st0);
7964 dead_dst = po->operand[0].type == OPT_REG
7965 && po->operand[0].reg == xST0;
7967 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7969 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7970 float_st0, float_st0, buf1, buf1);
7971 strcat(g_comment, " fxch");
7978 ferr_assert(po, po->flags & OPF_32BIT);
7979 fprintf(fout, " eax = (s32)%s;", float_st0);
7980 if (po->flags & OPF_FSHIFT) {
7981 if (need_float_stack)
7982 fprintf(fout, " f_stp++;");
7984 fprintf(fout, " f_st0 = f_st1;");
7986 strcat(g_comment, " ftol");
7990 if (need_float_stack) {
7991 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
7992 need_double ? "" : "f", float_st1, float_st0);
7993 fprintf(fout, " f_stp++;");
7996 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
7997 need_double ? "" : "f");
7999 strcat(g_comment, " CIpow");
8003 fprintf(fout, " do_skip_code_abort();");
8008 fprintf(fout, " do_emms();");
8013 ferr(po, "unhandled op type %d, flags %x\n",
8018 if (g_comment[0] != 0) {
8019 char *p = g_comment;
8020 while (my_isblank(*p))
8022 fprintf(fout, " // %s", p);
8027 fprintf(fout, "\n");
8029 // some sanity checking
8030 if (po->flags & OPF_REP) {
8031 if (po->op != OP_STOS && po->op != OP_MOVS
8032 && po->op != OP_CMPS && po->op != OP_SCAS)
8033 ferr(po, "unexpected rep\n");
8034 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
8035 && (po->op == OP_CMPS || po->op == OP_SCAS))
8036 ferr(po, "cmps/scas with plain rep\n");
8038 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
8039 && po->op != OP_CMPS && po->op != OP_SCAS)
8040 ferr(po, "unexpected repz/repnz\n");
8043 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
8045 // see is delayed flag stuff is still valid
8046 if (delayed_flag_op != NULL && delayed_flag_op != po) {
8047 if (is_any_opr_modified(delayed_flag_op, po, 0))
8048 delayed_flag_op = NULL;
8051 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
8052 if (is_opr_modified(last_arith_dst, po))
8053 last_arith_dst = NULL;
8060 if (g_stack_fsz && !g_stack_frame_used)
8061 fprintf(fout, " (void)sf;\n");
8063 fprintf(fout, "}\n\n");
8065 gen_x_cleanup(opcnt);
8068 static void gen_x_cleanup(int opcnt)
8072 for (i = 0; i < opcnt; i++) {
8073 struct label_ref *lr, *lr_del;
8075 lr = g_label_refs[i].next;
8076 while (lr != NULL) {
8081 g_label_refs[i].i = -1;
8082 g_label_refs[i].next = NULL;
8084 if (ops[i].op == OP_CALL) {
8086 proto_release(ops[i].pp);
8092 struct func_proto_dep;
8094 struct func_prototype {
8099 int has_ret:3; // -1, 0, 1: unresolved, no, yes
8100 unsigned int dep_resolved:1;
8101 unsigned int is_stdcall:1;
8102 unsigned int eax_pass:1; // returns without touching eax
8103 struct func_proto_dep *dep_func;
8105 const struct parsed_proto *pp; // seed pp, if any
8108 struct func_proto_dep {
8110 struct func_prototype *proto;
8111 int regmask_live; // .. at the time of call
8112 unsigned int ret_dep:1; // return from this is caller's return
8115 static struct func_prototype *hg_fp;
8116 static int hg_fp_cnt;
8118 static struct scanned_var {
8120 enum opr_lenmod lmod;
8121 unsigned int is_seeded:1;
8122 unsigned int is_c_str:1;
8123 const struct parsed_proto *pp; // seed pp, if any
8125 static int hg_var_cnt;
8127 static char **hg_refs;
8128 static int hg_ref_cnt;
8130 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8133 static struct func_prototype *hg_fp_add(const char *funcn)
8135 struct func_prototype *fp;
8137 if ((hg_fp_cnt & 0xff) == 0) {
8138 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
8139 my_assert_not(hg_fp, NULL);
8140 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
8143 fp = &hg_fp[hg_fp_cnt];
8144 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
8146 fp->argc_stack = -1;
8152 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
8157 for (i = 0; i < fp->dep_func_cnt; i++)
8158 if (IS(fp->dep_func[i].name, name))
8159 return &fp->dep_func[i];
8164 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
8167 if (hg_fp_find_dep(fp, name))
8170 if ((fp->dep_func_cnt & 0xff) == 0) {
8171 fp->dep_func = realloc(fp->dep_func,
8172 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
8173 my_assert_not(fp->dep_func, NULL);
8174 memset(&fp->dep_func[fp->dep_func_cnt], 0,
8175 sizeof(fp->dep_func[0]) * 0x100);
8177 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
8181 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
8183 const struct func_prototype *p1 = p1_, *p2 = p2_;
8184 return strcmp(p1->name, p2->name);
8188 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
8190 const struct func_prototype *p1 = p1_, *p2 = p2_;
8191 return p1->id - p2->id;
8195 static void hg_ref_add(const char *name)
8197 if ((hg_ref_cnt & 0xff) == 0) {
8198 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8199 my_assert_not(hg_refs, NULL);
8200 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8203 hg_refs[hg_ref_cnt] = strdup(name);
8204 my_assert_not(hg_refs[hg_ref_cnt], NULL);
8208 // recursive register dep pass
8209 // - track saved regs (part 2)
8210 // - try to figure out arg-regs
8211 // - calculate reg deps
8212 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8213 struct func_prototype *fp, int regmask_save, int regmask_dst,
8214 int *regmask_dep, int *has_ret)
8216 struct func_proto_dep *dep;
8217 struct parsed_op *po;
8218 int from_caller = 0;
8223 for (; i < opcnt; i++)
8225 if (cbits[i >> 3] & (1 << (i & 7)))
8227 cbits[i >> 3] |= (1 << (i & 7));
8231 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8232 if (po->flags & OPF_RMD)
8235 if (po->btj != NULL) {
8237 for (j = 0; j < po->btj->count; j++) {
8238 check_i(po, po->btj->d[j].bt_i);
8239 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8240 regmask_save, regmask_dst, regmask_dep, has_ret);
8245 check_i(po, po->bt_i);
8246 if (po->flags & OPF_CJMP) {
8247 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8248 regmask_save, regmask_dst, regmask_dep, has_ret);
8256 if (po->flags & OPF_FARG)
8257 /* (just calculate register deps) */;
8258 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8260 reg = po->operand[0].reg;
8261 ferr_assert(po, reg >= 0);
8263 if (po->flags & OPF_RSAVE) {
8264 regmask_save |= 1 << reg;
8267 if (po->flags & OPF_DONE)
8270 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
8272 regmask_save |= 1 << reg;
8273 po->flags |= OPF_RMD;
8274 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
8278 else if (po->flags & OPF_RMD)
8280 else if (po->op == OP_CALL) {
8281 po->regmask_dst |= 1 << xAX;
8283 dep = hg_fp_find_dep(fp, po->operand[0].name);
8285 dep->regmask_live = regmask_save | regmask_dst;
8286 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8287 dep->regmask_live |= 1 << xBP;
8290 else if (po->op == OP_RET) {
8291 if (po->operand_cnt > 0) {
8293 if (fp->argc_stack >= 0
8294 && fp->argc_stack != po->operand[0].val / 4)
8295 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8296 fp->argc_stack = po->operand[0].val / 4;
8300 // if has_ret is 0, there is uninitialized eax path,
8301 // which means it's most likely void func
8302 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
8303 if (po->op == OP_CALL) {
8308 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
8311 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
8314 if (ret != 1 && from_caller) {
8315 // unresolved eax - probably void func
8320 if (j >= 0 && ops[j].op == OP_CALL) {
8321 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8332 l = regmask_save | regmask_dst;
8333 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8336 l = po->regmask_src & ~l;
8339 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8340 l, regmask_dst, regmask_save, po->flags);
8343 regmask_dst |= po->regmask_dst;
8345 if (po->flags & OPF_TAIL)
8350 static void gen_hdr(const char *funcn, int opcnt)
8352 unsigned char cbits[MAX_OPS / 8];
8353 const struct parsed_proto *pp_c;
8354 struct parsed_proto *pp;
8355 struct func_prototype *fp;
8356 struct parsed_op *po;
8357 int regmask_dummy = 0;
8359 int max_bp_offset = 0;
8364 pp_c = proto_parse(g_fhdr, funcn, 1);
8366 // already in seed, will add to hg_fp later
8369 fp = hg_fp_add(funcn);
8371 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8372 g_stack_frame_used = 0;
8376 // - resolve all branches
8377 // - parse calls with labels
8378 resolve_branches_parse_calls(opcnt);
8381 // - handle ebp/esp frame, remove ops related to it
8382 scan_prologue_epilogue(opcnt, NULL);
8385 // - remove dead labels
8387 for (i = 0; i < opcnt; i++)
8389 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8395 if (po->flags & (OPF_RMD|OPF_DONE))
8398 if (po->op == OP_CALL) {
8399 if (po->operand[0].type == OPT_LABEL)
8400 hg_fp_add_dep(fp, opr_name(po, 0));
8401 else if (po->pp != NULL)
8402 hg_fp_add_dep(fp, po->pp->name);
8407 // - handle push <const>/pop pairs
8408 for (i = 0; i < opcnt; i++)
8411 if (po->flags & (OPF_RMD|OPF_DONE))
8414 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8415 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8419 // - process trivial calls
8420 for (i = 0; i < opcnt; i++)
8423 if (po->flags & (OPF_RMD|OPF_DONE))
8426 if (po->op == OP_CALL)
8428 pp = process_call_early(i, opcnt, &j);
8430 if (!(po->flags & OPF_ATAIL))
8431 // since we know the args, try to collect them
8432 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8438 // commit esp adjust
8439 if (ops[j].op != OP_POP)
8440 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8442 for (l = 0; l < pp->argc_stack; l++)
8443 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8447 po->flags |= OPF_DONE;
8453 // - track saved regs (simple)
8455 for (i = 0; i < opcnt; i++)
8458 if (po->flags & (OPF_RMD|OPF_DONE))
8461 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8462 && po->operand[0].reg != xCX)
8464 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8466 // regmask_save |= 1 << po->operand[0].reg; // do it later
8467 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8468 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8471 else if (po->op == OP_CALL)
8473 pp = process_call(i, opcnt);
8475 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8476 // since we know the args, collect them
8477 ret = collect_call_args(po, i, pp, ®mask_dummy,
8484 memset(cbits, 0, sizeof(cbits));
8488 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
8490 // find unreachable code - must be fixed in IDA
8491 for (i = 0; i < opcnt; i++)
8493 if (cbits[i >> 3] & (1 << (i & 7)))
8496 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8497 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8499 // the compiler sometimes still generates code after
8500 // noreturn OS functions
8503 if (!(ops[i].flags & OPF_RMD)
8504 && ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8506 ferr(&ops[i], "unreachable code\n");
8510 for (i = 0; i < g_eqcnt; i++) {
8511 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8512 max_bp_offset = g_eqs[i].offset;
8515 if (fp->argc_stack < 0) {
8516 max_bp_offset = (max_bp_offset + 3) & ~3;
8517 fp->argc_stack = max_bp_offset / 4;
8518 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8522 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8523 fp->has_ret = has_ret;
8525 printf("// has_ret %d, regmask_dep %x\n",
8526 fp->has_ret, fp->regmask_dep);
8527 output_hdr_fp(stdout, fp, 1);
8528 if (IS(funcn, "sub_10007F72")) exit(1);
8531 gen_x_cleanup(opcnt);
8534 static void hg_fp_resolve_deps(struct func_prototype *fp)
8536 struct func_prototype fp_s;
8540 // this thing is recursive, so mark first..
8541 fp->dep_resolved = 1;
8543 for (i = 0; i < fp->dep_func_cnt; i++) {
8544 strcpy(fp_s.name, fp->dep_func[i].name);
8545 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8546 sizeof(hg_fp[0]), hg_fp_cmp_name);
8547 if (fp->dep_func[i].proto != NULL) {
8548 if (!fp->dep_func[i].proto->dep_resolved)
8549 hg_fp_resolve_deps(fp->dep_func[i].proto);
8551 dep = ~fp->dep_func[i].regmask_live
8552 & fp->dep_func[i].proto->regmask_dep;
8553 fp->regmask_dep |= dep;
8554 // printf("dep %s %s |= %x\n", fp->name,
8555 // fp->dep_func[i].name, dep);
8557 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8558 fp->has_ret = fp->dep_func[i].proto->has_ret;
8563 // make all thiscall/edx arg functions referenced from .data fastcall
8564 static void do_func_refs_from_data(void)
8566 struct func_prototype *fp, fp_s;
8569 for (i = 0; i < hg_ref_cnt; i++) {
8570 strcpy(fp_s.name, hg_refs[i]);
8571 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8572 sizeof(hg_fp[0]), hg_fp_cmp_name);
8576 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8577 fp->regmask_dep |= mxCX | mxDX;
8581 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8584 const struct parsed_proto *pp;
8585 char *p, namebuf[NAMELEN];
8591 for (; count > 0; count--, fp++) {
8592 if (fp->has_ret == -1)
8593 fprintf(fout, "// ret unresolved\n");
8595 fprintf(fout, "// dep:");
8596 for (j = 0; j < fp->dep_func_cnt; j++) {
8597 fprintf(fout, " %s/", fp->dep_func[j].name);
8598 if (fp->dep_func[j].proto != NULL)
8599 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8600 fp->dep_func[j].proto->has_ret);
8602 fprintf(fout, "\n");
8605 p = strchr(fp->name, '@');
8607 memcpy(namebuf, fp->name, p - fp->name);
8608 namebuf[p - fp->name] = 0;
8616 pp = proto_parse(g_fhdr, name, 1);
8617 if (pp != NULL && pp->is_include)
8620 if (fp->pp != NULL) {
8621 // part of seed, output later
8625 regmask_dep = fp->regmask_dep;
8626 argc_normal = fp->argc_stack;
8628 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8629 (fp->has_ret ? "int" : "void"));
8630 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8631 && (regmask_dep & ~mxCX) == 0)
8633 fprintf(fout, "/*__thiscall*/ ");
8637 else if ((regmask_dep == (mxCX | mxDX)
8638 && (fp->is_stdcall || fp->argc_stack == 0))
8639 || (regmask_dep == mxCX && fp->argc_stack == 0))
8641 fprintf(fout, " __fastcall ");
8642 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8648 else if (regmask_dep && !fp->is_stdcall) {
8649 fprintf(fout, "/*__usercall*/ ");
8651 else if (regmask_dep) {
8652 fprintf(fout, "/*__userpurge*/ ");
8654 else if (fp->is_stdcall)
8655 fprintf(fout, " __stdcall ");
8657 fprintf(fout, " __cdecl ");
8659 fprintf(fout, "%s(", name);
8662 for (j = 0; j < xSP; j++) {
8663 if (regmask_dep & (1 << j)) {
8666 fprintf(fout, ", ");
8668 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8670 fprintf(fout, "int");
8671 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8675 for (j = 0; j < argc_normal; j++) {
8678 fprintf(fout, ", ");
8679 if (fp->pp != NULL) {
8680 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8681 if (!fp->pp->arg[arg - 1].type.is_ptr)
8685 fprintf(fout, "int ");
8686 fprintf(fout, "a%d", arg);
8689 fprintf(fout, ");\n");
8693 static void output_hdr(FILE *fout)
8695 static const char *lmod_c_names[] = {
8696 [OPLM_UNSPEC] = "???",
8697 [OPLM_BYTE] = "uint8_t",
8698 [OPLM_WORD] = "uint16_t",
8699 [OPLM_DWORD] = "uint32_t",
8700 [OPLM_QWORD] = "uint64_t",
8702 const struct scanned_var *var;
8703 struct func_prototype *fp;
8704 char line[256] = { 0, };
8708 // add stuff from headers
8709 for (i = 0; i < pp_cache_size; i++) {
8710 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8711 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8713 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8714 fp = hg_fp_add(name);
8715 fp->pp = &pp_cache[i];
8716 fp->argc_stack = fp->pp->argc_stack;
8717 fp->is_stdcall = fp->pp->is_stdcall;
8718 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8719 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8723 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8724 for (i = 0; i < hg_fp_cnt; i++)
8725 hg_fp_resolve_deps(&hg_fp[i]);
8727 // adjust functions referenced from data segment
8728 do_func_refs_from_data();
8730 // final adjustments
8731 for (i = 0; i < hg_fp_cnt; i++) {
8732 if (hg_fp[i].eax_pass && (hg_fp[i].regmask_dep & mxAX))
8733 hg_fp[i].has_ret = 1;
8736 // note: messes up .proto ptr, don't use
8737 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8740 for (i = 0; i < hg_var_cnt; i++) {
8743 if (var->pp != NULL)
8746 else if (var->is_c_str)
8747 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8749 fprintf(fout, "extern %-8s %s;",
8750 lmod_c_names[var->lmod], var->name);
8753 fprintf(fout, " // seeded");
8754 fprintf(fout, "\n");
8757 fprintf(fout, "\n");
8759 // output function prototypes
8760 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8763 fprintf(fout, "\n// - seed -\n");
8766 while (fgets(line, sizeof(line), g_fhdr))
8767 fwrite(line, 1, strlen(line), fout);
8770 // '=' needs special treatment
8772 static char *next_word_s(char *w, size_t wsize, char *s)
8779 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8781 for (i = 1; i < wsize - 1; i++) {
8783 printf("warning: missing closing quote: \"%s\"\n", s);
8792 for (; i < wsize - 1; i++) {
8793 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8799 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8800 printf("warning: '%s' truncated\n", w);
8805 static int cmpstringp(const void *p1, const void *p2)
8807 return strcmp(*(char * const *)p1, *(char * const *)p2);
8810 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8815 if (strstr(p, "..."))
8816 // unable to determine, assume needed
8819 if (*p == '.') // .text, .data, ...
8820 // ref from other data or non-function -> no
8823 p2 = strpbrk(p, "+:\r\n\x18");
8826 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8827 // referenced from removed code
8833 static int ida_xrefs_show_need(FILE *fasm, char *p,
8834 char **rlist, int rlist_len)
8840 p = strrchr(p, ';');
8841 if (p != NULL && *p == ';') {
8842 if (IS_START(p + 2, "sctref"))
8844 if (IS_START(p + 2, "DATA XREF: ")) {
8846 if (is_xref_needed(p, rlist, rlist_len))
8854 if (!my_fgets(line, sizeof(line), fasm))
8856 // non-first line is always indented
8857 if (!my_isblank(line[0]))
8860 // should be no content, just comment
8865 p = strrchr(p, ';');
8868 if (IS_START(p, "sctref")) {
8873 // it's printed once, but no harm to check again
8874 if (IS_START(p, "DATA XREF: "))
8877 if (is_xref_needed(p, rlist, rlist_len)) {
8882 fseek(fasm, pos, SEEK_SET);
8886 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8888 struct scanned_var *var;
8889 char line[256] = { 0, };
8898 // skip to next data section
8899 while (my_fgets(line, sizeof(line), fasm))
8904 if (*p == 0 || *p == ';')
8907 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8908 if (*p == 0 || *p == ';')
8911 if (*p != 's' || !IS_START(p, "segment para public"))
8917 if (p == NULL || !IS_START(p, "segment para public"))
8921 if (!IS_START(p, "'DATA'"))
8925 while (my_fgets(line, sizeof(line), fasm))
8930 no_identifier = my_isblank(*p);
8933 if (*p == 0 || *p == ';')
8936 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8937 words[wordc][0] = 0;
8938 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8939 if (*p == 0 || *p == ';') {
8945 if (wordc == 2 && IS(words[1], "ends"))
8950 if (no_identifier) {
8951 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8952 hg_ref_add(words[2]);
8956 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8957 // when this starts, we don't need anything from this section
8961 // check refs comment(s)
8962 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8965 if ((hg_var_cnt & 0xff) == 0) {
8966 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8967 * (hg_var_cnt + 0x100));
8968 my_assert_not(hg_vars, NULL);
8969 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8972 var = &hg_vars[hg_var_cnt++];
8973 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8975 // maybe already in seed header?
8976 var->pp = proto_parse(g_fhdr, var->name, 1);
8977 if (var->pp != NULL) {
8978 if (var->pp->is_fptr) {
8979 var->lmod = OPLM_DWORD;
8982 else if (var->pp->is_func)
8984 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8985 aerr("unhandled C type '%s' for '%s'\n",
8986 var->pp->type.name, var->name);
8992 if (IS(words[1], "dd")) {
8993 var->lmod = OPLM_DWORD;
8994 if (wordc >= 4 && IS(words[2], "offset"))
8995 hg_ref_add(words[3]);
8997 else if (IS(words[1], "dw"))
8998 var->lmod = OPLM_WORD;
8999 else if (IS(words[1], "db")) {
9000 var->lmod = OPLM_BYTE;
9001 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
9002 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
9006 else if (IS(words[1], "dq"))
9007 var->lmod = OPLM_QWORD;
9008 //else if (IS(words[1], "dt"))
9010 aerr("type '%s' not known\n", words[1]);
9018 static void set_label(int i, const char *name)
9024 p = strchr(name, ':');
9028 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
9029 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
9030 g_labels[i] = realloc(g_labels[i], len + 1);
9031 my_assert_not(g_labels[i], NULL);
9032 memcpy(g_labels[i], name, len);
9033 g_labels[i][len] = 0;
9042 static struct chunk_item *func_chunks;
9043 static int func_chunk_cnt;
9044 static int func_chunk_alloc;
9046 static void add_func_chunk(FILE *fasm, const char *name, int line)
9048 if (func_chunk_cnt >= func_chunk_alloc) {
9049 func_chunk_alloc *= 2;
9050 func_chunks = realloc(func_chunks,
9051 func_chunk_alloc * sizeof(func_chunks[0]));
9052 my_assert_not(func_chunks, NULL);
9054 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
9055 func_chunks[func_chunk_cnt].name = strdup(name);
9056 func_chunks[func_chunk_cnt].asmln = line;
9060 static int cmp_chunks(const void *p1, const void *p2)
9062 const struct chunk_item *c1 = p1, *c2 = p2;
9063 return strcmp(c1->name, c2->name);
9066 static void scan_ahead_for_chunks(FILE *fasm)
9076 oldpos = ftell(fasm);
9079 while (my_fgets(line, sizeof(line), fasm))
9090 // get rid of random tabs
9091 for (i = 0; line[i] != 0; i++)
9092 if (line[i] == '\t')
9095 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9098 next_word(words[0], sizeof(words[0]), p);
9099 if (words[0][0] == 0)
9100 aerr("missing name for func chunk?\n");
9102 add_func_chunk(fasm, words[0], asmln);
9104 else if (IS_START(p, "; sctend"))
9110 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9111 words[wordc][0] = 0;
9112 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9113 if (*p == 0 || *p == ';') {
9119 if (wordc == 2 && IS(words[1], "ends"))
9123 fseek(fasm, oldpos, SEEK_SET);
9127 int main(int argc, char *argv[])
9129 FILE *fout, *fasm, *frlist;
9130 struct parsed_data *pd = NULL;
9132 char **rlist = NULL;
9134 int rlist_alloc = 0;
9135 int func_chunks_used = 0;
9136 int func_chunks_sorted = 0;
9137 int func_chunk_i = -1;
9138 long func_chunk_ret = 0;
9139 int func_chunk_ret_ln = 0;
9140 int scanned_ahead = 0;
9142 char words[20][256];
9143 enum opr_lenmod lmod;
9144 char *sctproto = NULL;
9146 int pending_endp = 0;
9148 int skip_code_end = 0;
9149 int skip_warned = 0;
9162 for (arg = 1; arg < argc; arg++) {
9163 if (IS(argv[arg], "-v"))
9165 else if (IS(argv[arg], "-rf"))
9166 g_allow_regfunc = 1;
9167 else if (IS(argv[arg], "-uc"))
9168 g_allow_user_icall = 1;
9169 else if (IS(argv[arg], "-m"))
9171 else if (IS(argv[arg], "-hdr"))
9172 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
9177 if (argc < arg + 3) {
9178 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
9179 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
9181 " -hdr - header generation mode\n"
9182 " -rf - allow unannotated indirect calls\n"
9183 " -uc - allow ind. calls/refs to __usercall\n"
9184 " -m - allow multiple .text sections\n"
9185 "[rlist] is a file with function names to skip,"
9193 asmfn = argv[arg++];
9194 fasm = fopen(asmfn, "r");
9195 my_assert_not(fasm, NULL);
9197 hdrfn = argv[arg++];
9198 g_fhdr = fopen(hdrfn, "r");
9199 my_assert_not(g_fhdr, NULL);
9202 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9203 my_assert_not(rlist, NULL);
9204 // needs special handling..
9205 rlist[rlist_len++] = "__alloca_probe";
9207 func_chunk_alloc = 32;
9208 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9209 my_assert_not(func_chunks, NULL);
9211 memset(words, 0, sizeof(words));
9213 for (; arg < argc; arg++) {
9216 frlist = fopen(argv[arg], "r");
9217 my_assert_not(frlist, NULL);
9219 while (my_fgets(line, sizeof(line), frlist)) {
9221 if (*p == 0 || *p == ';')
9224 if (IS_START(p, "#if 0")
9225 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9229 else if (IS_START(p, "#endif"))
9236 p = next_word(words[0], sizeof(words[0]), p);
9237 if (words[0][0] == 0)
9240 if (rlist_len >= rlist_alloc) {
9241 rlist_alloc = rlist_alloc * 2 + 64;
9242 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9243 my_assert_not(rlist, NULL);
9245 rlist[rlist_len++] = strdup(words[0]);
9253 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9255 fout = fopen(argv[arg_out], "w");
9256 my_assert_not(fout, NULL);
9259 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9260 my_assert_not(g_eqs, NULL);
9262 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9263 g_label_refs[i].i = -1;
9264 g_label_refs[i].next = NULL;
9268 scan_variables(fasm, rlist, rlist_len);
9270 while (my_fgets(line, sizeof(line), fasm))
9279 // get rid of random tabs
9280 for (i = 0; line[i] != 0; i++)
9281 if (line[i] == '\t')
9286 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9287 goto do_pending_endp; // eww..
9289 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9291 static const char *attrs[] = {
9300 // parse IDA's attribute-list comment
9301 g_ida_func_attr = 0;
9304 for (; *p != 0; p = sskip(p)) {
9305 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9306 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9307 g_ida_func_attr |= 1 << i;
9308 p += strlen(attrs[i]);
9312 if (i == ARRAY_SIZE(attrs)) {
9313 anote("unparsed IDA attr: %s\n", p);
9316 if (IS(attrs[i], "fpd=")) {
9317 p = next_word(words[0], sizeof(words[0]), p);
9322 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9324 static const char *attrs[] = {
9330 // parse manual attribute-list comment
9331 g_sct_func_attr = 0;
9334 for (; *p != 0; p = sskip(p)) {
9335 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9336 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9337 g_sct_func_attr |= 1 << i;
9338 p += strlen(attrs[i]);
9345 // clear_sf=start,len (in dwords)
9346 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9347 &g_stack_clear_len, &j);
9349 // clear_regmask=<mask>
9350 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9352 // rm_regmask=<mask>
9353 ret = sscanf(p, "=%x%n", &g_regmask_rm, &j) + 1;
9355 anote("unparsed attr value: %s\n", p);
9360 else if (i == ARRAY_SIZE(attrs)) {
9361 anote("unparsed sct attr: %s\n", p);
9366 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9369 next_word(words[0], sizeof(words[0]), p);
9370 if (words[0][0] == 0)
9371 aerr("missing name for func chunk?\n");
9373 if (!scanned_ahead) {
9374 add_func_chunk(fasm, words[0], asmln);
9375 func_chunks_sorted = 0;
9378 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9380 if (func_chunk_i >= 0) {
9381 if (func_chunk_i < func_chunk_cnt
9382 && IS(func_chunks[func_chunk_i].name, g_func))
9384 // move on to next chunk
9385 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9387 aerr("seek failed for '%s' chunk #%d\n",
9388 g_func, func_chunk_i);
9389 asmln = func_chunks[func_chunk_i].asmln;
9393 if (func_chunk_ret == 0)
9394 aerr("no return from chunk?\n");
9395 fseek(fasm, func_chunk_ret, SEEK_SET);
9396 asmln = func_chunk_ret_ln;
9402 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9403 func_chunks_used = 1;
9405 if (IS_START(g_func, "sub_")) {
9406 unsigned long addr = strtoul(p, NULL, 16);
9407 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9408 if (addr > f_addr && !scanned_ahead) {
9409 //anote("scan_ahead caused by '%s', addr %lx\n",
9411 scan_ahead_for_chunks(fasm);
9413 func_chunks_sorted = 0;
9421 for (i = wordc; i < ARRAY_SIZE(words); i++)
9423 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9424 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9425 if (*p == 0 || *p == ';') {
9430 if (*p != 0 && *p != ';')
9431 aerr("too many words\n");
9433 if (skip_code_end) {
9438 // allow asm patches in comments
9440 // skip IDA's forced non-removable comment
9441 if (!IS_START(p, "; sct") && (p2 = strchr(p + 1, ';')))
9444 if (*p == ';' && IS_START(p, "; sct")) {
9445 if (IS_START(p, "; sctpatch:")) {
9447 if (*p == 0 || *p == ';')
9449 goto parse_words; // lame
9451 if (IS_START(p, "; sctproto:")) {
9452 sctproto = strdup(p + 11);
9454 else if (IS_START(p, "; sctend")) {
9459 else if (IS_START(p, "; sctskip_start")) {
9460 if (in_func && !g_skip_func) {
9462 ops[pi].op = OPP_ABORT;
9463 ops[pi].asmln = asmln;
9469 else if (IS_START(p, "; sctskip_end")) {
9477 awarn("wordc == 0?\n");
9481 // don't care about this:
9482 if (words[0][0] == '.'
9483 || IS(words[0], "include")
9484 || IS(words[0], "assume") || IS(words[1], "segment")
9485 || IS(words[0], "align"))
9491 // do delayed endp processing to collect switch jumptables
9493 if (in_func && !g_skip_func && !end && wordc >= 2
9494 && ((words[0][0] == 'd' && words[0][2] == 0)
9495 || (words[1][0] == 'd' && words[1][2] == 0)))
9498 if (words[1][0] == 'd' && words[1][2] == 0) {
9500 if (g_func_pd_cnt >= pd_alloc) {
9501 pd_alloc = pd_alloc * 2 + 16;
9502 g_func_pd = realloc(g_func_pd,
9503 sizeof(g_func_pd[0]) * pd_alloc);
9504 my_assert_not(g_func_pd, NULL);
9506 pd = &g_func_pd[g_func_pd_cnt];
9508 memset(pd, 0, sizeof(*pd));
9509 strcpy(pd->label, words[0]);
9510 pd->type = OPT_CONST;
9511 pd->lmod = lmod_from_directive(words[1]);
9517 anote("skipping alignment byte?\n");
9520 lmod = lmod_from_directive(words[0]);
9521 if (lmod != pd->lmod)
9522 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9525 if (pd->count_alloc < pd->count + wordc) {
9526 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9527 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9528 my_assert_not(pd->d, NULL);
9530 for (; i < wordc; i++) {
9531 if (IS(words[i], "offset")) {
9532 pd->type = OPT_OFFSET;
9535 p = strchr(words[i], ',');
9538 if (pd->type == OPT_OFFSET)
9539 pd->d[pd->count].u.label = strdup(words[i]);
9541 pd->d[pd->count].u.val = parse_number(words[i], 0);
9542 pd->d[pd->count].bt_i = -1;
9548 if (in_func && !g_skip_func) {
9550 gen_hdr(g_func, pi);
9552 gen_func(fout, g_fhdr, g_func, pi);
9557 g_ida_func_attr = 0;
9558 g_sct_func_attr = 0;
9559 g_stack_clear_start = 0;
9560 g_stack_clear_len = 0;
9567 func_chunks_used = 0;
9570 memset(&ops, 0, pi * sizeof(ops[0]));
9575 for (i = 0; i < g_func_pd_cnt; i++) {
9577 if (pd->type == OPT_OFFSET) {
9578 for (j = 0; j < pd->count; j++)
9579 free(pd->d[j].u.label);
9594 if (IS(words[1], "proc")) {
9596 aerr("proc '%s' while in_func '%s'?\n",
9599 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9601 strcpy(g_func, words[0]);
9602 set_label(0, words[0]);
9607 if (IS(words[1], "endp"))
9610 aerr("endp '%s' while not in_func?\n", words[0]);
9611 if (!IS(g_func, words[0]))
9612 aerr("endp '%s' while in_func '%s'?\n",
9615 aerr("endp '%s' while skipping code\n", words[0]);
9617 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9618 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
9624 if (!g_skip_func && func_chunks_used) {
9625 // start processing chunks
9626 struct chunk_item *ci, key = { g_func, 0 };
9628 func_chunk_ret = ftell(fasm);
9629 func_chunk_ret_ln = asmln;
9630 if (!func_chunks_sorted) {
9631 qsort(func_chunks, func_chunk_cnt,
9632 sizeof(func_chunks[0]), cmp_chunks);
9633 func_chunks_sorted = 1;
9635 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9636 sizeof(func_chunks[0]), cmp_chunks);
9638 aerr("'%s' needs chunks, but none found\n", g_func);
9639 func_chunk_i = ci - func_chunks;
9640 for (; func_chunk_i > 0; func_chunk_i--)
9641 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9644 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9646 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9647 asmln = func_chunks[func_chunk_i].asmln;
9655 if (wordc == 2 && IS(words[1], "ends")) {
9659 goto do_pending_endp;
9663 // scan for next text segment
9664 while (my_fgets(line, sizeof(line), fasm)) {
9667 if (*p == 0 || *p == ';')
9670 if (strstr(p, "segment para public 'CODE' use32"))
9677 p = strchr(words[0], ':');
9679 set_label(pi, words[0]);
9683 if (!in_func || g_skip_func || skip_code) {
9684 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9686 anote("skipping from '%s'\n", g_labels[pi]);
9690 g_labels[pi] = NULL;
9694 if (wordc > 1 && IS(words[1], "="))
9697 aerr("unhandled equ, wc=%d\n", wordc);
9698 if (g_eqcnt >= eq_alloc) {
9700 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9701 my_assert_not(g_eqs, NULL);
9704 len = strlen(words[0]);
9705 if (len > sizeof(g_eqs[0].name) - 1)
9706 aerr("equ name too long: %d\n", len);
9707 strcpy(g_eqs[g_eqcnt].name, words[0]);
9709 if (!IS(words[3], "ptr"))
9710 aerr("unhandled equ\n");
9711 if (IS(words[2], "dword"))
9712 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9713 else if (IS(words[2], "word"))
9714 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9715 else if (IS(words[2], "byte"))
9716 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9717 else if (IS(words[2], "qword"))
9718 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9720 aerr("bad lmod: '%s'\n", words[2]);
9722 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9727 if (pi >= ARRAY_SIZE(ops))
9728 aerr("too many ops\n");
9730 parse_op(&ops[pi], words, wordc);
9732 ops[pi].datap = sctproto;
9747 // vim:ts=2:shiftwidth=2:expandtab