5 * This work is licensed under the terms of 3-clause BSD license.
6 * See COPYING file in the top-level directory.
14 #include "my_assert.h"
18 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
19 #define IS(w, y) !strcmp(w, y)
20 #define IS_START(w, y) !strncmp(w, y, strlen(y))
22 #include "protoparse.h"
24 static const char *asmfn;
28 #define anote(fmt, ...) \
29 printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
30 #define awarn(fmt, ...) \
31 printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
32 #define aerr(fmt, ...) do { \
33 printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
38 #include "masm_tools.h"
41 OPF_RMD = (1 << 0), /* removed from code generation */
42 OPF_DATA = (1 << 1), /* data processing - writes to dst opr */
43 OPF_FLAGS = (1 << 2), /* sets flags */
44 OPF_JMP = (1 << 3), /* branch, call */
45 OPF_CJMP = (1 << 4), /* cond. branch (cc or jecxz/loop) */
46 OPF_CC = (1 << 5), /* uses flags */
47 OPF_TAIL = (1 << 6), /* ret or tail call */
48 OPF_RSAVE = (1 << 7), /* push/pop is local reg save/load */
49 OPF_REP = (1 << 8), /* prefixed by rep */
50 OPF_REPZ = (1 << 9), /* rep is repe/repz */
51 OPF_REPNZ = (1 << 10), /* rep is repne/repnz */
52 OPF_FARG = (1 << 11), /* push collected as func arg */
53 OPF_FARGNR = (1 << 12), /* push collected as func arg (no reuse) */
54 OPF_EBP_S = (1 << 13), /* ebp used as scratch here, not BP */
55 OPF_DF = (1 << 14), /* DF flag set */
56 OPF_ATAIL = (1 << 15), /* tail call with reused arg frame */
57 OPF_32BIT = (1 << 16), /* 32bit division */
58 OPF_LOCK = (1 << 17), /* op has lock prefix */
59 OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
60 OPF_DONE = (1 << 19), /* already fully handled by analysis */
61 OPF_PPUSH = (1 << 20), /* part of complex push-pop graph */
62 OPF_NOREGS = (1 << 21), /* don't track regs of this op */
63 OPF_FPUSH = (1 << 22), /* pushes x87 stack */
64 OPF_FPOP = (1 << 23), /* pops x87 stack */
65 OPF_FSHIFT = (1 << 24), /* x87 stack shift is actually needed */
155 // pseudo-ops for lib calls
173 // must be sorted (larger len must be further in enum)
182 #define MAX_EXITS 128
184 #define MAX_OPERANDS 3
187 #define OPR_INIT(type_, lmod_, reg_) \
188 { type_, lmod_, reg_, }
192 enum opr_lenmod lmod;
194 unsigned int is_ptr:1; // pointer in C
195 unsigned int is_array:1; // array in C
196 unsigned int type_from_var:1; // .. in header, sometimes wrong
197 unsigned int size_mismatch:1; // type override differs from C
198 unsigned int size_lt:1; // type override is larger than C
199 unsigned int had_ds:1; // had ds: prefix
200 const struct parsed_proto *pp; // for OPT_LABEL
207 struct parsed_opr operand[MAX_OPERANDS];
210 unsigned char pfo_inv;
211 unsigned char operand_cnt;
212 unsigned char p_argnum; // arg push: altered before call arg #
213 unsigned char p_arggrp; // arg push: arg group # for above
214 unsigned char p_argpass;// arg push: arg of host func
215 short p_argnext;// arg push: same arg pushed elsewhere or -1
216 int regmask_src; // all referensed regs
218 int pfomask; // flagop: parsed_flag_op that can't be delayed
219 int cc_scratch; // scratch storage during analysis
220 int bt_i; // branch target for branches
221 struct parsed_data *btj;// branch targets for jumptables
222 struct parsed_proto *pp;// parsed_proto for OP_CALL
228 // on start: function/data type hint (sctproto)
230 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
231 // OP_PUSH - points to OP_POP in complex push/pop graph
232 // OP_POP - points to OP_PUSH in simple push/pop pair
233 // OP_FCOM - needed_status_word_bits | (is_z_check << 16)
237 enum opr_lenmod lmod;
244 enum opr_lenmod lmod;
258 struct label_ref *next;
262 IDAFA_BP_FRAME = (1 << 0),
263 IDAFA_LIB_FUNC = (1 << 1),
264 IDAFA_STATIC = (1 << 2),
265 IDAFA_NORETURN = (1 << 3),
266 IDAFA_THUNK = (1 << 4),
267 IDAFA_FPD = (1 << 5),
271 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
272 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
285 // note: limited to 32k due to p_argnext
287 #define MAX_ARG_GRP 2
289 static struct parsed_op ops[MAX_OPS];
290 static struct parsed_equ *g_eqs;
292 static char *g_labels[MAX_OPS];
293 static struct label_ref g_label_refs[MAX_OPS];
294 static const struct parsed_proto *g_func_pp;
295 static struct parsed_data *g_func_pd;
296 static int g_func_pd_cnt;
297 static int g_func_lmods;
298 static char g_func[256];
299 static char g_comment[256];
300 static int g_bp_frame;
301 static int g_sp_frame;
302 static int g_stack_frame_used;
303 static int g_stack_fsz;
304 static int g_ida_func_attr;
305 static int g_sct_func_attr;
306 static int g_stack_clear_start; // in dwords
307 static int g_stack_clear_len;
308 static int g_regmask_init;
309 static int g_skip_func;
310 static int g_allow_regfunc;
311 static int g_allow_user_icall;
312 static int g_quiet_pp;
313 static int g_header_mode;
315 #define ferr(op_, fmt, ...) do { \
316 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
317 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
321 #define fnote(op_, fmt, ...) \
322 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
323 dump_op(op_), ##__VA_ARGS__)
325 #define ferr_assert(op_, cond) do { \
326 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
329 const char *regs_r32[] = {
330 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
331 // not r32, but list here for easy parsing and printing
332 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
333 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
335 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
336 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
337 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
343 xMM0, xMM1, xMM2, xMM3, // mmx
344 xMM4, xMM5, xMM6, xMM7,
345 xST0, xST1, xST2, xST3, // x87
346 xST4, xST5, xST6, xST7,
349 #define mxAX (1 << xAX)
350 #define mxCX (1 << xCX)
351 #define mxDX (1 << xDX)
352 #define mxST0 (1 << xST0)
353 #define mxST1 (1 << xST1)
354 #define mxST1_0 (mxST1 | mxST0)
355 #define mxST7_2 (0xfc << xST0)
356 #define mxSTa (0xff << xST0)
358 // possible basic comparison types (without inversion)
359 enum parsed_flag_op {
363 PFO_BE, // 6 CF=1||ZF=1
367 PFO_LE, // e ZF=1||SF!=OF
370 #define PFOB_O (1 << PFO_O)
371 #define PFOB_C (1 << PFO_C)
372 #define PFOB_Z (1 << PFO_Z)
373 #define PFOB_S (1 << PFO_S)
375 static const char *parsed_flag_op_names[] = {
376 "o", "c", "z", "be", "s", "p", "l", "le"
379 static int char_array_i(const char *array[], size_t len, const char *s)
383 for (i = 0; i < len; i++)
390 static void printf_number(char *buf, size_t buf_size,
391 unsigned long number)
393 // output in C-friendly form
394 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
397 static int check_segment_prefix(const char *s)
399 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
413 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
417 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
419 *reg_lmod = OPLM_QWORD;
423 *reg_lmod = OPLM_DWORD;
426 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
428 *reg_lmod = OPLM_WORD;
431 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
433 *reg_lmod = OPLM_BYTE;
436 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
438 *reg_lmod = OPLM_BYTE;
445 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
447 enum opr_lenmod lmod;
460 while (my_isblank(*s))
462 for (; my_issep(*s); d++, s++)
464 while (my_isblank(*s))
468 // skip '?s:' prefixes
469 if (check_segment_prefix(s))
472 s = next_idt(w, sizeof(w), s);
477 reg = parse_reg(&lmod, w);
479 *regmask |= 1 << reg;
483 if ('0' <= w[0] && w[0] <= '9') {
484 number = parse_number(w);
485 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
489 // probably some label/identifier - pass
492 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
496 strcpy(name, cvtbuf);
501 static int is_reg_in_str(const char *s)
505 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
508 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
509 if (!strncmp(s, regs_r32[i], 3))
515 static const char *parse_stack_el(const char *name, char *extra_reg,
516 int *base_val, int early_try)
518 const char *p, *p2, *s;
524 if (g_bp_frame || early_try)
527 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
529 if (extra_reg != NULL) {
530 strncpy(extra_reg, name, 3);
535 if (IS_START(p, "ebp+")) {
539 if (p2 != NULL && is_reg_in_str(p)) {
540 if (extra_reg != NULL) {
541 strncpy(extra_reg, p, p2 - p);
542 extra_reg[p2 - p] = 0;
547 if (!('0' <= *p && *p <= '9'))
554 if (!IS_START(name, "esp+"))
560 if (is_reg_in_str(s)) {
561 if (extra_reg != NULL) {
562 strncpy(extra_reg, s, p - s);
563 extra_reg[p - s] = 0;
568 aerr("%s IDA stackvar not set?\n", __func__);
570 if (!('0' <= *s && *s <= '9')) {
571 aerr("%s IDA stackvar offset not set?\n", __func__);
574 if (s[0] == '0' && s[1] == 'x')
577 if (len < sizeof(buf) - 1) {
578 strncpy(buf, s, len);
580 val = strtol(buf, &endp, 16);
581 if (val == 0 || *endp != 0) {
582 aerr("%s num parse fail for '%s'\n", __func__, buf);
591 if ('0' <= *p && *p <= '9')
594 if (base_val != NULL)
599 static int guess_lmod_from_name(struct parsed_opr *opr)
601 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
602 opr->lmod = OPLM_DWORD;
605 if (IS_START(opr->name, "word_")) {
606 opr->lmod = OPLM_WORD;
609 if (IS_START(opr->name, "byte_")) {
610 opr->lmod = OPLM_BYTE;
613 if (IS_START(opr->name, "qword_")) {
614 opr->lmod = OPLM_QWORD;
620 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
621 const struct parsed_type *c_type)
623 static const char *dword_types[] = {
624 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
625 "WPARAM", "LPARAM", "UINT", "__int32",
626 "LONG", "HIMC", "BOOL", "size_t",
629 static const char *word_types[] = {
630 "uint16_t", "int16_t", "_WORD", "WORD",
631 "unsigned __int16", "__int16",
633 static const char *byte_types[] = {
634 "uint8_t", "int8_t", "char",
635 "unsigned __int8", "__int8", "BYTE", "_BYTE",
637 // structures.. deal the same as with _UNKNOWN for now
643 if (c_type->is_ptr) {
648 n = skip_type_mod(c_type->name);
650 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
651 if (IS(n, dword_types[i])) {
657 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
658 if (IS(n, word_types[i])) {
664 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
665 if (IS(n, byte_types[i])) {
674 static char *default_cast_to(char *buf, size_t buf_size,
675 struct parsed_opr *opr)
679 if (!opr->is_ptr || strchr(opr->name, '['))
681 if (opr->pp == NULL || opr->pp->type.name == NULL
684 snprintf(buf, buf_size, "%s", "(void *)");
688 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
692 static enum opr_type lmod_from_directive(const char *d)
696 else if (IS(d, "dw"))
698 else if (IS(d, "db"))
701 aerr("unhandled directive: '%s'\n", d);
705 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
711 *regmask |= 1 << reg;
714 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
717 static int parse_operand(struct parsed_opr *opr,
718 int *regmask, int *regmask_indirect,
719 char words[16][256], int wordc, int w, unsigned int op_flags)
721 const struct parsed_proto *pp = NULL;
722 enum opr_lenmod tmplmod;
723 unsigned long number;
731 aerr("parse_operand w %d, wordc %d\n", w, wordc);
735 for (i = w; i < wordc; i++) {
736 len = strlen(words[i]);
737 if (words[i][len - 1] == ',') {
738 words[i][len - 1] = 0;
744 wordc_in = wordc - w;
746 if ((op_flags & OPF_JMP) && wordc_in > 0
747 && !('0' <= words[w][0] && words[w][0] <= '9'))
749 const char *label = NULL;
751 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
752 && IS(words[w + 1], "ptr"))
753 label = words[w + 2];
754 else if (wordc_in == 2 && IS(words[w], "short"))
755 label = words[w + 1];
756 else if (wordc_in == 1
757 && strchr(words[w], '[') == NULL
758 && parse_reg(&tmplmod, words[w]) < 0)
762 opr->type = OPT_LABEL;
763 ret = check_segment_prefix(label);
766 aerr("fs/gs used\n");
770 strcpy(opr->name, label);
776 if (IS(words[w + 1], "ptr")) {
777 if (IS(words[w], "dword"))
778 opr->lmod = OPLM_DWORD;
779 else if (IS(words[w], "word"))
780 opr->lmod = OPLM_WORD;
781 else if (IS(words[w], "byte"))
782 opr->lmod = OPLM_BYTE;
783 else if (IS(words[w], "qword"))
784 opr->lmod = OPLM_QWORD;
786 aerr("type parsing failed\n");
788 wordc_in = wordc - w;
793 if (IS(words[w], "offset")) {
794 opr->type = OPT_OFFSET;
795 opr->lmod = OPLM_DWORD;
796 strcpy(opr->name, words[w + 1]);
797 pp = proto_parse(g_fhdr, opr->name, 1);
800 if (IS(words[w], "(offset")) {
801 p = strchr(words[w + 1], ')');
803 aerr("parse of bracketed offset failed\n");
805 opr->type = OPT_OFFSET;
806 strcpy(opr->name, words[w + 1]);
812 aerr("parse_operand 1 word expected\n");
814 ret = check_segment_prefix(words[w]);
817 aerr("fs/gs used\n");
819 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
821 strcpy(opr->name, words[w]);
823 if (words[w][0] == '[') {
824 opr->type = OPT_REGMEM;
825 ret = sscanf(words[w], "[%[^]]]", opr->name);
827 aerr("[] parse failure\n");
829 parse_indmode(opr->name, regmask_indirect, 1);
830 if (opr->lmod == OPLM_UNSPEC
831 && parse_stack_el(opr->name, NULL, NULL, 1))
834 struct parsed_equ *eq =
835 equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
837 opr->lmod = eq->lmod;
839 // might be unaligned access
840 g_func_lmods |= 1 << OPLM_BYTE;
844 else if (strchr(words[w], '[')) {
846 p = strchr(words[w], '[');
847 opr->type = OPT_REGMEM;
848 parse_indmode(p, regmask_indirect, 0);
849 strncpy(buf, words[w], p - words[w]);
850 buf[p - words[w]] = 0;
851 pp = proto_parse(g_fhdr, buf, 1);
854 else if (('0' <= words[w][0] && words[w][0] <= '9')
855 || words[w][0] == '-')
857 number = parse_number(words[w]);
858 opr->type = OPT_CONST;
860 printf_number(opr->name, sizeof(opr->name), number);
864 ret = parse_reg(&tmplmod, opr->name);
866 setup_reg_opr(opr, ret, tmplmod, regmask);
870 // most likely var in data segment
871 opr->type = OPT_LABEL;
872 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
876 if (pp->is_fptr || pp->is_func) {
877 opr->lmod = OPLM_DWORD;
881 tmplmod = OPLM_UNSPEC;
882 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
883 anote("unhandled C type '%s' for '%s'\n",
884 pp->type.name, opr->name);
886 if (opr->lmod == OPLM_UNSPEC) {
888 opr->type_from_var = 1;
890 else if (opr->lmod != tmplmod) {
891 opr->size_mismatch = 1;
892 if (tmplmod < opr->lmod)
895 opr->is_ptr = pp->type.is_ptr;
897 opr->is_array = pp->type.is_array;
901 if (opr->lmod == OPLM_UNSPEC)
902 guess_lmod_from_name(opr);
906 static const struct {
911 { "repe", OPF_REP|OPF_REPZ },
912 { "repz", OPF_REP|OPF_REPZ },
913 { "repne", OPF_REP|OPF_REPNZ },
914 { "repnz", OPF_REP|OPF_REPNZ },
915 { "lock", OPF_LOCK }, // ignored for now..
918 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
920 static const struct {
923 unsigned short minopr;
924 unsigned short maxopr;
927 unsigned char pfo_inv;
929 { "nop", OP_NOP, 0, 0, 0 },
930 { "push", OP_PUSH, 1, 1, 0 },
931 { "pop", OP_POP, 1, 1, OPF_DATA },
932 { "pusha",OP_PUSHA, 0, 0, 0 },
933 { "popa", OP_POPA, 0, 0, OPF_DATA },
934 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
935 { "mov" , OP_MOV, 2, 2, OPF_DATA },
936 { "lea", OP_LEA, 2, 2, OPF_DATA },
937 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
938 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
939 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
940 { "not", OP_NOT, 1, 1, OPF_DATA },
941 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
942 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
943 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
944 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
945 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
946 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
947 { "stosb",OP_STOS, 0, 0, OPF_DATA },
948 { "stosw",OP_STOS, 0, 0, OPF_DATA },
949 { "stosd",OP_STOS, 0, 0, OPF_DATA },
950 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
951 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
952 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
953 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
954 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
955 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
956 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
957 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
958 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
959 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
960 { "cld", OP_CLD, 0, 0, OPF_DATA },
961 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
962 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
963 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
964 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
965 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
966 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
967 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
968 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
969 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
970 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
971 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
972 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
973 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
974 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
975 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
976 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
977 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
978 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
979 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
980 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
981 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
982 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
983 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
984 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
985 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
986 { "test", OP_TEST, 2, 2, OPF_FLAGS },
987 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
988 { "retn", OP_RET, 0, 1, OPF_TAIL },
989 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
990 { "jmp", OP_JMP, 1, 1, OPF_JMP },
991 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
992 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
993 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
994 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
995 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
996 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
997 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
998 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
999 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1000 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
1001 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
1002 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
1003 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
1004 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1005 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1006 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1007 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1008 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1009 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1010 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1011 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1012 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1013 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1014 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1015 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1016 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1017 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1018 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1019 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1020 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1021 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1022 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1023 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1024 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1025 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1026 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1027 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1028 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1029 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1030 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1031 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1032 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1033 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1034 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1035 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1036 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1037 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1038 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1039 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1040 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1041 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1042 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1043 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1044 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1045 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1046 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1047 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1048 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1049 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1050 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1052 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1053 { "fild", OP_FILD, 1, 1, OPF_FPUSH },
1054 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1055 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1056 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1057 { "fst", OP_FST, 1, 1, 0 },
1058 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1059 { "fist", OP_FIST, 1, 1, 0 },
1060 { "fistp", OP_FIST, 1, 1, OPF_FPOP },
1061 { "fadd", OP_FADD, 0, 2, 0 },
1062 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1063 { "fdiv", OP_FDIV, 0, 2, 0 },
1064 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1065 { "fmul", OP_FMUL, 0, 2, 0 },
1066 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1067 { "fsub", OP_FSUB, 0, 2, 0 },
1068 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1069 { "fdivr", OP_FDIVR, 0, 2, 0 },
1070 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1071 { "fsubr", OP_FSUBR, 0, 2, 0 },
1072 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1073 { "fiadd", OP_FIADD, 1, 1, 0 },
1074 { "fidiv", OP_FIDIV, 1, 1, 0 },
1075 { "fimul", OP_FIMUL, 1, 1, 0 },
1076 { "fisub", OP_FISUB, 1, 1, 0 },
1077 { "fidivr", OP_FIDIVR, 1, 1, 0 },
1078 { "fisubr", OP_FISUBR, 1, 1, 0 },
1079 { "fcom", OP_FCOM, 0, 1, 0 },
1080 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1081 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1082 { "fchs", OP_FCHS, 0, 0, 0 },
1083 { "fcos", OP_FCOS, 0, 0, 0 },
1084 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1085 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1086 { "fsin", OP_FSIN, 0, 0, 0 },
1087 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1088 { "fxch", OP_FXCH, 1, 1, 0 },
1089 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1091 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1092 { "movq", OP_MOV, 2, 2, OPF_DATA },
1093 // pseudo-ops for lib calls
1094 { "_allshl",OPP_ALLSHL },
1095 { "_allshr",OPP_ALLSHR },
1096 { "_ftol", OPP_FTOL },
1097 { "_CIpow", OPP_CIPOW },
1102 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1104 enum opr_lenmod lmod = OPLM_UNSPEC;
1105 int prefix_flags = 0;
1113 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1114 if (IS(words[w], pref_table[i].name)) {
1115 prefix_flags = pref_table[i].flags;
1122 aerr("lone prefix: '%s'\n", words[0]);
1127 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1128 if (IS(words[w], op_table[i].name))
1132 if (i == ARRAY_SIZE(op_table)) {
1134 aerr("unhandled op: '%s'\n", words[0]);
1139 op->op = op_table[i].op;
1140 op->flags = op_table[i].flags | prefix_flags;
1141 op->pfo = op_table[i].pfo;
1142 op->pfo_inv = op_table[i].pfo_inv;
1143 op->regmask_src = op->regmask_dst = 0;
1146 if (op->op == OP_UD2)
1149 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1150 if (opr >= op_table[i].minopr && w >= wordc)
1153 regmask = regmask_ind = 0;
1154 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1155 words, wordc, w, op->flags);
1157 if (opr == 0 && (op->flags & OPF_DATA))
1158 op->regmask_dst = regmask;
1160 op->regmask_src |= regmask;
1161 op->regmask_src |= regmask_ind;
1163 if (op->operand[opr].lmod != OPLM_UNSPEC)
1164 g_func_lmods |= 1 << op->operand[opr].lmod;
1168 aerr("parse_op %s incomplete: %d/%d\n",
1169 words[0], w, wordc);
1172 op->operand_cnt = opr;
1173 if (!strncmp(op_table[i].name, "set", 3))
1174 op->operand[0].lmod = OPLM_BYTE;
1177 // first operand is not dst
1180 op->regmask_src |= op->regmask_dst;
1181 op->regmask_dst = 0;
1184 // first operand is src too
1197 op->regmask_src |= op->regmask_dst;
1202 op->regmask_src |= op->regmask_dst;
1203 op->regmask_dst |= op->regmask_src;
1209 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1210 && op->operand[0].lmod == op->operand[1].lmod
1211 && op->operand[0].reg == op->operand[1].reg
1212 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1214 op->regmask_src = 0;
1217 op->regmask_src |= op->regmask_dst;
1220 // ops with implicit argumets
1222 op->operand_cnt = 2;
1223 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1224 op->regmask_dst = op->regmask_src;
1225 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1229 op->operand_cnt = 2;
1230 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1231 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1237 if (words[op_w][4] == 'b')
1239 else if (words[op_w][4] == 'w')
1241 else if (words[op_w][4] == 'd')
1244 op->regmask_src = 0;
1245 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1246 OPLM_DWORD, &op->regmask_src);
1247 op->regmask_dst = op->regmask_src;
1248 setup_reg_opr(&op->operand[j++], xAX, lmod,
1249 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1250 if (op->flags & OPF_REP) {
1251 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1252 op->regmask_dst |= 1 << xCX;
1254 op->operand_cnt = j;
1259 if (words[op_w][4] == 'b')
1261 else if (words[op_w][4] == 'w')
1263 else if (words[op_w][4] == 'd')
1266 op->regmask_src = 0;
1267 // note: lmod is not correct, don't have where to place it
1268 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1269 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1270 if (op->flags & OPF_REP)
1271 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1272 op->operand_cnt = j;
1273 op->regmask_dst = op->regmask_src;
1277 op->regmask_dst = 1 << xCX;
1280 op->operand_cnt = 2;
1281 op->regmask_src = 1 << xCX;
1282 op->operand[1].type = OPT_REG;
1283 op->operand[1].reg = xCX;
1284 op->operand[1].lmod = OPLM_DWORD;
1288 if (op->operand_cnt == 2) {
1289 if (op->operand[0].type != OPT_REG)
1290 aerr("reg expected\n");
1291 op->regmask_src |= 1 << op->operand[0].reg;
1293 if (op->operand_cnt != 1)
1298 op->regmask_src |= op->regmask_dst;
1299 op->regmask_dst = (1 << xDX) | (1 << xAX);
1300 if (op->operand[0].lmod == OPLM_UNSPEC)
1301 op->operand[0].lmod = OPLM_DWORD;
1306 // we could set up operands for edx:eax, but there is no real need to
1307 // (see is_opr_modified())
1308 op->regmask_src |= op->regmask_dst;
1309 op->regmask_dst = (1 << xDX) | (1 << xAX);
1310 if (op->operand[0].lmod == OPLM_UNSPEC)
1311 op->operand[0].lmod = OPLM_DWORD;
1319 op->regmask_src |= op->regmask_dst;
1320 if (op->operand[1].lmod == OPLM_UNSPEC)
1321 op->operand[1].lmod = OPLM_BYTE;
1326 op->regmask_src |= op->regmask_dst;
1327 if (op->operand[2].lmod == OPLM_UNSPEC)
1328 op->operand[2].lmod = OPLM_BYTE;
1332 op->regmask_src |= op->regmask_dst;
1333 op->regmask_dst = 0;
1334 if (op->operand[0].lmod == OPLM_UNSPEC
1335 && (op->operand[0].type == OPT_CONST
1336 || op->operand[0].type == OPT_OFFSET
1337 || op->operand[0].type == OPT_LABEL))
1338 op->operand[0].lmod = OPLM_DWORD;
1344 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1345 && op->operand[0].lmod == op->operand[1].lmod
1346 && op->operand[0].reg == op->operand[1].reg
1347 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1349 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1350 op->regmask_src = op->regmask_dst = 0;
1355 if (op->operand[0].type == OPT_REG
1356 && op->operand[1].type == OPT_REGMEM)
1359 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1360 if (IS(buf, op->operand[1].name))
1361 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1366 // trashed regs must be explicitly detected later
1367 op->regmask_dst = 0;
1371 op->regmask_dst = (1 << xBP) | (1 << xSP);
1372 op->regmask_src = 1 << xBP;
1377 op->regmask_dst |= mxST0;
1381 op->regmask_dst |= mxST0;
1382 if (IS(words[op_w] + 3, "1"))
1383 op->operand[0].val = X87_CONST_1;
1384 else if (IS(words[op_w] + 3, "ln2"))
1385 op->operand[0].val = X87_CONST_LN2;
1386 else if (IS(words[op_w] + 3, "z"))
1387 op->operand[0].val = X87_CONST_Z;
1394 op->regmask_src |= mxST0;
1403 op->regmask_src |= mxST0;
1404 if (op->operand_cnt == 2)
1405 op->regmask_src |= op->regmask_dst;
1406 else if (op->operand_cnt == 1) {
1407 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1408 op->operand[0].type = OPT_REG;
1409 op->operand[0].lmod = OPLM_QWORD;
1410 op->operand[0].reg = xST0;
1411 op->regmask_dst |= mxST0;
1414 // IDA doesn't use this
1415 aerr("no operands?\n");
1429 op->regmask_src |= mxST0;
1430 op->regmask_dst |= mxST0;
1435 op->regmask_src |= mxST0 | mxST1;
1436 op->regmask_dst |= mxST0;
1444 op->regmask_src |= mxST0;
1451 if (op->operand[0].type == OPT_REG
1452 && op->operand[1].type == OPT_CONST)
1454 struct parsed_opr *op1 = &op->operand[1];
1455 if ((op->op == OP_AND && op1->val == 0)
1458 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1459 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1461 op->regmask_src = 0;
1466 static const char *op_name(struct parsed_op *po)
1468 static char buf[16];
1472 if (po->op == OP_JCC || po->op == OP_SCC) {
1474 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1477 strcpy(p, parsed_flag_op_names[po->pfo]);
1481 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1482 if (op_table[i].op == po->op)
1483 return op_table[i].name;
1489 static const char *dump_op(struct parsed_op *po)
1491 static char out[128];
1498 snprintf(out, sizeof(out), "%s", op_name(po));
1499 for (i = 0; i < po->operand_cnt; i++) {
1503 snprintf(p, sizeof(out) - (p - out),
1504 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1505 po->operand[i].name);
1511 static const char *lmod_type_u(struct parsed_op *po,
1512 enum opr_lenmod lmod)
1524 ferr(po, "invalid lmod: %d\n", lmod);
1525 return "(_invalid_)";
1529 static const char *lmod_cast_u(struct parsed_op *po,
1530 enum opr_lenmod lmod)
1542 ferr(po, "invalid lmod: %d\n", lmod);
1543 return "(_invalid_)";
1547 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1548 enum opr_lenmod lmod)
1560 ferr(po, "invalid lmod: %d\n", lmod);
1561 return "(_invalid_)";
1565 static const char *lmod_cast_s(struct parsed_op *po,
1566 enum opr_lenmod lmod)
1578 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1579 return "(_invalid_)";
1583 static const char *lmod_cast(struct parsed_op *po,
1584 enum opr_lenmod lmod, int is_signed)
1587 lmod_cast_s(po, lmod) :
1588 lmod_cast_u(po, lmod);
1591 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1603 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1608 static const char *opr_name(struct parsed_op *po, int opr_num)
1610 if (opr_num >= po->operand_cnt)
1611 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1612 return po->operand[opr_num].name;
1615 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1617 if (opr_num >= po->operand_cnt)
1618 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1619 if (po->operand[opr_num].type != OPT_CONST)
1620 ferr(po, "opr %d: const expected\n", opr_num);
1621 return po->operand[opr_num].val;
1624 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1626 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1627 ferr(po, "invalid reg: %d\n", popr->reg);
1628 return regs_r32[popr->reg];
1631 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1633 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1635 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1637 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1639 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1644 *is_signed = cast[1] == 's' ? 1 : 0;
1648 static int check_deref_cast(const char *cast, int *bits)
1650 if (IS_START(cast, "*(u8 *)"))
1652 else if (IS_START(cast, "*(u16 *)"))
1654 else if (IS_START(cast, "*(u32 *)"))
1656 else if (IS_START(cast, "*(u64 *)"))
1664 // cast1 is the "final" cast
1665 static const char *simplify_cast(const char *cast1, const char *cast2)
1667 static char buf[256];
1675 if (IS(cast1, cast2))
1678 if (check_simple_cast(cast1, &bits1, &s1) == 0
1679 && check_simple_cast(cast2, &bits2, &s2) == 0)
1684 if (check_simple_cast(cast1, &bits1, &s1) == 0
1685 && check_deref_cast(cast2, &bits2) == 0)
1687 if (bits1 == bits2) {
1688 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1693 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1696 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1700 static const char *simplify_cast_num(const char *cast, unsigned int val)
1702 if (IS(cast, "(u8)") && val < 0x100)
1704 if (IS(cast, "(s8)") && val < 0x80)
1706 if (IS(cast, "(u16)") && val < 0x10000)
1708 if (IS(cast, "(s16)") && val < 0x8000)
1710 if (IS(cast, "(s32)") && val < 0x80000000)
1716 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1725 namelen = strlen(name);
1727 p = strchr(name, '+');
1731 ferr(po, "equ parse failed for '%s'\n", name);
1733 if (IS_START(p, "0x"))
1735 *extra_offs = strtol(p, &endp, 16);
1737 ferr(po, "equ parse failed for '%s'\n", name);
1740 for (i = 0; i < g_eqcnt; i++)
1741 if (strncmp(g_eqs[i].name, name, namelen) == 0
1742 && g_eqs[i].name[namelen] == 0)
1746 ferr(po, "unresolved equ name: '%s'\n", name);
1753 static int is_stack_access(struct parsed_op *po,
1754 const struct parsed_opr *popr)
1756 return (parse_stack_el(popr->name, NULL, NULL, 0)
1757 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1758 && IS_START(popr->name, "ebp")));
1761 static void parse_stack_access(struct parsed_op *po,
1762 const char *name, char *ofs_reg, int *offset_out,
1763 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1765 const char *bp_arg = "";
1766 const char *p = NULL;
1767 struct parsed_equ *eq;
1774 if (IS_START(name, "ebp-")
1775 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1778 if (IS_START(p, "0x"))
1780 offset = strtoul(p, &endp, 16);
1784 ferr(po, "ebp- parse of '%s' failed\n", name);
1787 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1788 eq = equ_find(po, bp_arg, &offset);
1790 ferr(po, "detected but missing eq\n");
1791 offset += eq->offset;
1794 if (!strncmp(name, "ebp", 3))
1797 // yes it sometimes LEAs ra for compares..
1798 if (!is_lea && ofs_reg[0] == 0
1799 && stack_ra <= offset && offset < stack_ra + 4)
1801 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1804 *offset_out = offset;
1806 *stack_ra_out = stack_ra;
1808 *bp_arg_out = bp_arg;
1811 static int parse_stack_esp_offset(struct parsed_op *po,
1812 const char *name, int *offset_out)
1814 char ofs_reg[16] = { 0, };
1815 struct parsed_equ *eq;
1821 if (strstr(name, "esp") == NULL)
1823 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1824 if (bp_arg == NULL) {
1825 // just plain offset?
1826 if (!IS_START(name, "esp+"))
1828 offset = strtol(name + 4, &endp, 0);
1829 if (endp == NULL || *endp != 0)
1831 *offset_out = offset;
1835 if (ofs_reg[0] != 0)
1837 eq = equ_find(po, bp_arg, &offset);
1839 ferr(po, "detected but missing eq\n");
1840 offset += eq->offset;
1841 *offset_out = base_val + offset;
1845 static int stack_frame_access(struct parsed_op *po,
1846 struct parsed_opr *popr, char *buf, size_t buf_size,
1847 const char *name, const char *cast, int is_src, int is_lea)
1849 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1850 const char *prefix = "";
1851 const char *bp_arg = NULL;
1852 char ofs_reg[16] = { 0, };
1853 int i, arg_i, arg_s;
1861 if (po->flags & OPF_EBP_S)
1862 ferr(po, "stack_frame_access while ebp is scratch\n");
1864 parse_stack_access(po, name, ofs_reg, &offset,
1865 &stack_ra, &bp_arg, is_lea);
1867 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1869 if (offset > stack_ra)
1871 arg_i = (offset - stack_ra - 4) / 4;
1872 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1874 if (g_func_pp->is_vararg
1875 && arg_i == g_func_pp->argc_stack && is_lea)
1877 // should be va_list
1880 snprintf(buf, buf_size, "%sap", cast);
1883 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1884 offset, bp_arg, arg_i);
1886 if (ofs_reg[0] != 0)
1887 ferr(po, "offset reg on arg access?\n");
1889 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1890 if (g_func_pp->arg[i].reg != NULL)
1896 if (i == g_func_pp->argc)
1897 ferr(po, "arg %d not in prototype?\n", arg_i);
1899 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1906 ferr(po, "lea/byte to arg?\n");
1907 if (is_src && (offset & 3) == 0)
1908 snprintf(buf, buf_size, "%sa%d",
1909 simplify_cast(cast, "(u8)"), i + 1);
1911 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1912 cast, offset & 3, i + 1);
1917 ferr(po, "lea/word to arg?\n");
1922 ferr(po, "problematic arg store\n");
1923 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1924 simplify_cast(cast, "*(u16 *)"), i + 1);
1927 ferr(po, "unaligned arg word load\n");
1929 else if (is_src && (offset & 2) == 0)
1930 snprintf(buf, buf_size, "%sa%d",
1931 simplify_cast(cast, "(u16)"), i + 1);
1933 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1934 cast, (offset & 2) ? "HI" : "LO", i + 1);
1946 snprintf(buf, buf_size, "(u32)&a%d + %d",
1949 ferr(po, "unaligned arg store\n");
1951 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1952 snprintf(buf, buf_size, "%s(a%d >> %d)",
1953 prefix, i + 1, (offset & 3) * 8);
1957 snprintf(buf, buf_size, "%s%sa%d",
1958 prefix, is_lea ? "&" : "", i + 1);
1963 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1967 strcat(g_comment, " unaligned");
1970 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
1971 if (tmp_lmod != OPLM_DWORD
1972 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
1973 < lmod_bytes(po, popr->lmod) + (offset & 3))))
1975 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
1976 i + 1, offset, g_func_pp->arg[i].type.name);
1978 // can't check this because msvc likes to reuse
1979 // arg space for scratch..
1980 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
1981 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
1985 if (g_stack_fsz == 0)
1986 ferr(po, "stack var access without stackframe\n");
1987 g_stack_frame_used = 1;
1989 sf_ofs = g_stack_fsz + offset;
1990 lim = (ofs_reg[0] != 0) ? -4 : 0;
1991 if (offset > 0 || sf_ofs < lim)
1992 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2002 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2003 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2007 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2008 // known unaligned or possibly unaligned
2009 strcat(g_comment, " unaligned");
2011 prefix = "*(u16 *)&";
2012 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2013 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2016 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2020 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2021 // known unaligned or possibly unaligned
2022 strcat(g_comment, " unaligned");
2024 prefix = "*(u32 *)&";
2025 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2026 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2029 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2033 ferr_assert(po, !(sf_ofs & 7));
2034 ferr_assert(po, ofs_reg[0] == 0);
2035 // only used for x87 int64/float, float sets is_lea
2037 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2039 snprintf(buf, buf_size, "*(s64 *)&sf.q[%d]", sf_ofs / 8);
2043 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2050 static void check_func_pp(struct parsed_op *po,
2051 const struct parsed_proto *pp, const char *pfx)
2053 enum opr_lenmod tmp_lmod;
2057 if (pp->argc_reg != 0) {
2058 if (!g_allow_user_icall && !pp->is_fastcall) {
2059 pp_print(buf, sizeof(buf), pp);
2060 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2062 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2063 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2064 pfx, pp->argc_reg, pp->argc_stack);
2067 // fptrs must use 32bit args, callsite might have no information and
2068 // lack a cast to smaller types, which results in incorrectly masked
2069 // args passed (callee may assume masked args, it does on ARM)
2070 if (!pp->is_osinc) {
2071 for (i = 0; i < pp->argc; i++) {
2072 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2073 if (ret && tmp_lmod != OPLM_DWORD)
2074 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2075 i + 1, pp->arg[i].type.name);
2080 static const char *check_label_read_ref(struct parsed_op *po,
2083 const struct parsed_proto *pp;
2085 pp = proto_parse(g_fhdr, name, 0);
2087 ferr(po, "proto_parse failed for ref '%s'\n", name);
2090 check_func_pp(po, pp, "ref");
2095 static char *out_src_opr(char *buf, size_t buf_size,
2096 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2099 char tmp1[256], tmp2[256];
2108 switch (popr->type) {
2111 ferr(po, "lea from reg?\n");
2113 switch (popr->lmod) {
2115 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2118 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2121 snprintf(buf, buf_size, "%s%s",
2122 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2125 if (popr->name[1] == 'h') // XXX..
2126 snprintf(buf, buf_size, "%s(%s >> 8)",
2127 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2129 snprintf(buf, buf_size, "%s%s",
2130 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2133 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2138 if (is_stack_access(po, popr)) {
2139 stack_frame_access(po, popr, buf, buf_size,
2140 popr->name, cast, 1, is_lea);
2144 strcpy(expr, popr->name);
2145 if (strchr(expr, '[')) {
2146 // special case: '[' can only be left for label[reg] form
2147 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2149 ferr(po, "parse failure for '%s'\n", expr);
2150 if (tmp1[0] == '(') {
2151 // (off_4FFF50+3)[eax]
2152 p = strchr(tmp1 + 1, ')');
2153 if (p == NULL || p[1] != 0)
2154 ferr(po, "parse failure (2) for '%s'\n", expr);
2156 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2158 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2161 // XXX: do we need more parsing?
2163 snprintf(buf, buf_size, "%s", expr);
2167 snprintf(buf, buf_size, "%s(%s)",
2168 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2172 name = check_label_read_ref(po, popr->name);
2173 if (cast[0] == 0 && popr->is_ptr)
2177 snprintf(buf, buf_size, "(u32)&%s", name);
2178 else if (popr->size_lt)
2179 snprintf(buf, buf_size, "%s%s%s%s", cast,
2180 lmod_cast_u_ptr(po, popr->lmod),
2181 popr->is_array ? "" : "&", name);
2183 snprintf(buf, buf_size, "%s%s%s", cast, name,
2184 popr->is_array ? "[0]" : "");
2188 name = check_label_read_ref(po, popr->name);
2192 ferr(po, "lea an offset?\n");
2193 snprintf(buf, buf_size, "%s&%s", cast, name);
2198 ferr(po, "lea from const?\n");
2200 printf_number(tmp1, sizeof(tmp1), popr->val);
2201 if (popr->val == 0 && strchr(cast, '*'))
2202 snprintf(buf, buf_size, "NULL");
2204 snprintf(buf, buf_size, "%s%s",
2205 simplify_cast_num(cast, popr->val), tmp1);
2209 ferr(po, "invalid src type: %d\n", popr->type);
2215 // note: may set is_ptr (we find that out late for ebp frame..)
2216 static char *out_dst_opr(char *buf, size_t buf_size,
2217 struct parsed_op *po, struct parsed_opr *popr)
2219 switch (popr->type) {
2221 switch (popr->lmod) {
2223 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2226 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2230 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2234 if (popr->name[1] == 'h') // XXX..
2235 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2237 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2240 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2245 if (is_stack_access(po, popr)) {
2246 stack_frame_access(po, popr, buf, buf_size,
2247 popr->name, "", 0, 0);
2251 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2254 if (popr->size_mismatch)
2255 snprintf(buf, buf_size, "%s%s%s",
2256 lmod_cast_u_ptr(po, popr->lmod),
2257 popr->is_array ? "" : "&", popr->name);
2259 snprintf(buf, buf_size, "%s%s", popr->name,
2260 popr->is_array ? "[0]" : "");
2264 ferr(po, "invalid dst type: %d\n", popr->type);
2270 static char *out_src_opr_u32(char *buf, size_t buf_size,
2271 struct parsed_op *po, struct parsed_opr *popr)
2273 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2276 static char *out_src_opr_float(char *buf, size_t buf_size,
2277 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2279 const char *cast = NULL;
2282 switch (popr->type) {
2284 if (popr->reg < xST0 || popr->reg > xST7)
2285 ferr(po, "bad reg: %d\n", popr->reg);
2287 if (need_float_stack) {
2288 if (popr->reg == xST0)
2289 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2291 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2295 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2301 switch (popr->lmod) {
2309 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2312 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2313 snprintf(buf, buf_size, "*((%s *)%s)", cast, tmp);
2317 ferr(po, "invalid float type: %d\n", popr->type);
2323 static char *out_dst_opr_float(char *buf, size_t buf_size,
2324 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2327 return out_src_opr_float(buf, buf_size, po, popr, need_float_stack);
2330 static void out_test_for_cc(char *buf, size_t buf_size,
2331 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2332 enum opr_lenmod lmod, const char *expr)
2334 const char *cast, *scast;
2336 cast = lmod_cast_u(po, lmod);
2337 scast = lmod_cast_s(po, lmod);
2341 case PFO_BE: // CF==1||ZF==1; CF=0
2342 snprintf(buf, buf_size, "(%s%s %s 0)",
2343 cast, expr, is_inv ? "!=" : "==");
2347 case PFO_L: // SF!=OF; OF=0
2348 snprintf(buf, buf_size, "(%s%s %s 0)",
2349 scast, expr, is_inv ? ">=" : "<");
2352 case PFO_LE: // ZF==1||SF!=OF; OF=0
2353 snprintf(buf, buf_size, "(%s%s %s 0)",
2354 scast, expr, is_inv ? ">" : "<=");
2359 snprintf(buf, buf_size, "(%d)", !!is_inv);
2363 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2367 static void out_cmp_for_cc(char *buf, size_t buf_size,
2368 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2371 const char *cast, *scast, *cast_use;
2372 char buf1[256], buf2[256];
2373 enum opr_lenmod lmod;
2375 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2376 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2377 po->operand[0].lmod, po->operand[1].lmod);
2378 lmod = po->operand[0].lmod;
2380 cast = lmod_cast_u(po, lmod);
2381 scast = lmod_cast_s(po, lmod);
2397 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2400 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2401 if (po->op == OP_DEC)
2402 snprintf(buf2, sizeof(buf2), "1");
2405 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2407 strcat(cast_op2, "-");
2408 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2413 // note: must be unsigned compare
2414 snprintf(buf, buf_size, "(%s %s %s)",
2415 buf1, is_inv ? ">=" : "<", buf2);
2419 snprintf(buf, buf_size, "(%s %s %s)",
2420 buf1, is_inv ? "!=" : "==", buf2);
2424 // note: must be unsigned compare
2425 snprintf(buf, buf_size, "(%s %s %s)",
2426 buf1, is_inv ? ">" : "<=", buf2);
2429 if (is_inv && lmod == OPLM_BYTE
2430 && po->operand[1].type == OPT_CONST
2431 && po->operand[1].val == 0xff)
2433 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2434 snprintf(buf, buf_size, "(0)");
2438 // note: must be signed compare
2440 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2441 scast, buf1, buf2, is_inv ? ">=" : "<");
2445 snprintf(buf, buf_size, "(%s %s %s)",
2446 buf1, is_inv ? ">=" : "<", buf2);
2450 snprintf(buf, buf_size, "(%s %s %s)",
2451 buf1, is_inv ? ">" : "<=", buf2);
2459 static void out_cmp_test(char *buf, size_t buf_size,
2460 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2462 char buf1[256], buf2[256], buf3[256];
2464 if (po->op == OP_TEST) {
2465 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2466 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2469 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2470 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2471 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2473 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2474 po->operand[0].lmod, buf3);
2476 else if (po->op == OP_CMP) {
2477 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2480 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2483 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2484 struct parsed_opr *popr2)
2486 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2487 ferr(po, "missing lmod for both operands\n");
2489 if (popr1->lmod == OPLM_UNSPEC)
2490 popr1->lmod = popr2->lmod;
2491 else if (popr2->lmod == OPLM_UNSPEC)
2492 popr2->lmod = popr1->lmod;
2493 else if (popr1->lmod != popr2->lmod) {
2494 if (popr1->type_from_var) {
2495 popr1->size_mismatch = 1;
2496 if (popr1->lmod < popr2->lmod)
2498 popr1->lmod = popr2->lmod;
2500 else if (popr2->type_from_var) {
2501 popr2->size_mismatch = 1;
2502 if (popr2->lmod < popr1->lmod)
2504 popr2->lmod = popr1->lmod;
2507 ferr(po, "conflicting lmods: %d vs %d\n",
2508 popr1->lmod, popr2->lmod);
2512 static const char *op_to_c(struct parsed_op *po)
2536 ferr(po, "op_to_c was supplied with %d\n", po->op);
2540 // last op in stream - unconditional branch or ret
2541 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2542 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2543 && ops[_i].op != OP_CALL))
2545 #define check_i(po, i) \
2547 ferr(po, "bad " #i ": %d\n", i)
2549 // note: this skips over calls and rm'd stuff assuming they're handled
2550 // so it's intended to use at one of final passes
2551 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2552 int depth, int seen_noreturn, int flags_set)
2554 struct parsed_op *po;
2559 for (; i < opcnt; i++) {
2561 if (po->cc_scratch == magic)
2562 return ret; // already checked
2563 po->cc_scratch = magic;
2565 if (po->flags & OPF_TAIL) {
2566 if (po->op == OP_CALL) {
2567 if (po->pp != NULL && po->pp->is_noreturn)
2573 return -1; // deadend
2576 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2579 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2580 if (po->btj != NULL) {
2582 for (j = 0; j < po->btj->count; j++) {
2583 check_i(po, po->btj->d[j].bt_i);
2584 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2585 depth, seen_noreturn, flags_set);
2587 return ret; // dead end
2592 check_i(po, po->bt_i);
2593 if (po->flags & OPF_CJMP) {
2594 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2595 depth, seen_noreturn, flags_set);
2597 return ret; // dead end
2606 if ((po->op == OP_POP || po->op == OP_PUSH)
2607 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2612 if (po->op == OP_PUSH) {
2615 else if (po->op == OP_POP) {
2616 if (relevant && depth == 0) {
2617 po->flags |= flags_set;
2624 // for noreturn, assume msvc skipped stack cleanup
2625 return seen_noreturn ? 1 : -1;
2628 // scan for 'reg' pop backwards starting from i
2629 // intended to use for register restore search, so other reg
2630 // references are considered an error
2631 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2633 struct parsed_op *po;
2634 struct label_ref *lr;
2637 ops[i].cc_scratch = magic;
2641 if (g_labels[i] != NULL) {
2642 lr = &g_label_refs[i];
2643 for (; lr != NULL; lr = lr->next) {
2644 check_i(&ops[i], lr->i);
2645 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2649 if (i > 0 && LAST_OP(i - 1))
2657 if (ops[i].cc_scratch == magic)
2659 ops[i].cc_scratch = magic;
2662 if (po->op == OP_POP && po->operand[0].reg == reg) {
2663 if (po->flags & (OPF_RMD|OPF_DONE))
2666 po->flags |= set_flags;
2670 // this also covers the case where we reach corresponding push
2671 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2675 // nothing interesting on this path
2679 static void find_reachable_exits(int i, int opcnt, int magic,
2680 int *exits, int *exit_count)
2682 struct parsed_op *po;
2685 for (; i < opcnt; i++)
2688 if (po->cc_scratch == magic)
2690 po->cc_scratch = magic;
2692 if (po->flags & OPF_TAIL) {
2693 ferr_assert(po, *exit_count < MAX_EXITS);
2694 exits[*exit_count] = i;
2699 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2700 if (po->flags & OPF_RMD)
2703 if (po->btj != NULL) {
2704 for (j = 0; j < po->btj->count; j++) {
2705 check_i(po, po->btj->d[j].bt_i);
2706 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2712 check_i(po, po->bt_i);
2713 if (po->flags & OPF_CJMP)
2714 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2722 // scan for 'reg' pop backwards starting from exits (all paths)
2723 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2725 static int exits[MAX_EXITS];
2726 static int exit_count;
2731 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2733 ferr_assert(&ops[i], exit_count > 0);
2736 for (j = 0; j < exit_count; j++) {
2737 ret = scan_for_rsave_pop_reg(exits[j], i + opcnt * 16 + set_flags,
2746 // scan for one or more pop of push <const>
2747 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2748 int push_i, int is_probe)
2750 struct parsed_op *po;
2751 struct label_ref *lr;
2755 for (; i < opcnt; i++)
2758 if (po->cc_scratch == magic)
2759 return ret; // already checked
2760 po->cc_scratch = magic;
2762 if (po->flags & OPF_JMP) {
2763 if (po->flags & OPF_RMD)
2765 if (po->op == OP_CALL)
2768 if (po->btj != NULL) {
2769 for (j = 0; j < po->btj->count; j++) {
2770 check_i(po, po->btj->d[j].bt_i);
2771 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2779 check_i(po, po->bt_i);
2780 if (po->flags & OPF_CJMP) {
2781 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2792 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2795 if (g_labels[i] != NULL) {
2796 // all refs must be visited
2797 lr = &g_label_refs[i];
2798 for (; lr != NULL; lr = lr->next) {
2800 if (ops[lr->i].cc_scratch != magic)
2803 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2807 if (po->op == OP_POP)
2809 if (po->flags & (OPF_RMD|OPF_DONE))
2813 po->flags |= OPF_DONE;
2814 po->datap = &ops[push_i];
2823 static void scan_for_pop_const(int i, int opcnt, int magic)
2827 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2829 ops[i].flags |= OPF_RMD | OPF_DONE;
2830 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2834 // check if all branch targets within a marked path are also marked
2835 // note: the path checked must not be empty or end with a branch
2836 static int check_path_branches(int opcnt, int magic)
2838 struct parsed_op *po;
2841 for (i = 0; i < opcnt; i++) {
2843 if (po->cc_scratch != magic)
2846 if (po->flags & OPF_JMP) {
2847 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2850 if (po->btj != NULL) {
2851 for (j = 0; j < po->btj->count; j++) {
2852 check_i(po, po->btj->d[j].bt_i);
2853 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2858 check_i(po, po->bt_i);
2859 if (ops[po->bt_i].cc_scratch != magic)
2861 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2869 // scan for multiple pushes for given pop
2870 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2873 int reg = ops[pop_i].operand[0].reg;
2874 struct parsed_op *po;
2875 struct label_ref *lr;
2878 ops[i].cc_scratch = magic;
2882 if (g_labels[i] != NULL) {
2883 lr = &g_label_refs[i];
2884 for (; lr != NULL; lr = lr->next) {
2885 check_i(&ops[i], lr->i);
2886 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2890 if (i > 0 && LAST_OP(i - 1))
2898 if (ops[i].cc_scratch == magic)
2900 ops[i].cc_scratch = magic;
2903 if (po->op == OP_CALL)
2905 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2908 if (po->op == OP_PUSH)
2910 if (po->datap != NULL)
2912 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2913 // leave this case for reg save/restore handlers
2917 po->flags |= OPF_PPUSH | OPF_DONE;
2918 po->datap = &ops[pop_i];
2927 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2929 int magic = i + opcnt * 14;
2932 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2934 ret = check_path_branches(opcnt, magic);
2936 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2937 *regmask_pp |= 1 << ops[i].operand[0].reg;
2938 scan_pushes_for_pop_r(i, magic + 1, i, 0);
2943 static void scan_propagate_df(int i, int opcnt)
2945 struct parsed_op *po = &ops[i];
2948 for (; i < opcnt; i++) {
2950 if (po->flags & OPF_DF)
2951 return; // already resolved
2952 po->flags |= OPF_DF;
2954 if (po->op == OP_CALL)
2955 ferr(po, "call with DF set?\n");
2957 if (po->flags & OPF_JMP) {
2958 if (po->btj != NULL) {
2960 for (j = 0; j < po->btj->count; j++) {
2961 check_i(po, po->btj->d[j].bt_i);
2962 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
2967 if (po->flags & OPF_RMD)
2969 check_i(po, po->bt_i);
2970 if (po->flags & OPF_CJMP)
2971 scan_propagate_df(po->bt_i, opcnt);
2977 if (po->flags & OPF_TAIL)
2980 if (po->op == OP_CLD) {
2981 po->flags |= OPF_RMD | OPF_DONE;
2986 ferr(po, "missing DF clear?\n");
2989 // is operand 'opr' referenced by parsed_op 'po'?
2990 static int is_opr_referenced(const struct parsed_opr *opr,
2991 const struct parsed_op *po)
2995 if (opr->type == OPT_REG) {
2996 mask = po->regmask_dst | po->regmask_src;
2997 if (po->op == OP_CALL)
2998 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
2999 if ((1 << opr->reg) & mask)
3005 for (i = 0; i < po->operand_cnt; i++)
3006 if (IS(po->operand[0].name, opr->name))
3012 // is operand 'opr' read by parsed_op 'po'?
3013 static int is_opr_read(const struct parsed_opr *opr,
3014 const struct parsed_op *po)
3016 if (opr->type == OPT_REG) {
3017 if (po->regmask_src & (1 << opr->reg))
3027 // is operand 'opr' modified by parsed_op 'po'?
3028 static int is_opr_modified(const struct parsed_opr *opr,
3029 const struct parsed_op *po)
3033 if (opr->type == OPT_REG) {
3034 if (po->op == OP_CALL) {
3035 mask = po->regmask_dst;
3036 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3037 if (mask & (1 << opr->reg))
3043 if (po->regmask_dst & (1 << opr->reg))
3049 return IS(po->operand[0].name, opr->name);
3052 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3053 static int is_any_opr_modified(const struct parsed_op *po_test,
3054 const struct parsed_op *po, int c_mode)
3059 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3062 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3065 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3068 // in reality, it can wreck any register, but in decompiled C
3069 // version it can only overwrite eax or edx:eax
3070 mask = (1 << xAX) | (1 << xDX);
3074 if (po->op == OP_CALL
3075 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3078 for (i = 0; i < po_test->operand_cnt; i++)
3079 if (IS(po_test->operand[i].name, po->operand[0].name))
3085 // scan for any po_test operand modification in range given
3086 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3089 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3092 for (; i < opcnt; i++) {
3093 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3100 // scan for po_test operand[0] modification in range given
3101 static int scan_for_mod_opr0(struct parsed_op *po_test,
3104 for (; i < opcnt; i++) {
3105 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3112 static int try_resolve_const(int i, const struct parsed_opr *opr,
3113 int magic, unsigned int *val);
3115 static int scan_for_flag_set(int i, int opcnt, int magic,
3116 int *branched, int *setters, int *setter_cnt)
3118 struct label_ref *lr;
3122 if (ops[i].cc_scratch == magic) {
3123 // is this a problem?
3124 //ferr(&ops[i], "%s looped\n", __func__);
3127 ops[i].cc_scratch = magic;
3129 if (g_labels[i] != NULL) {
3132 lr = &g_label_refs[i];
3133 for (; lr->next; lr = lr->next) {
3134 check_i(&ops[i], lr->i);
3135 ret = scan_for_flag_set(lr->i, opcnt, magic,
3136 branched, setters, setter_cnt);
3141 check_i(&ops[i], lr->i);
3142 if (i > 0 && LAST_OP(i - 1)) {
3146 ret = scan_for_flag_set(lr->i, opcnt, magic,
3147 branched, setters, setter_cnt);
3153 if (ops[i].flags & OPF_FLAGS) {
3154 setters[*setter_cnt] = i;
3157 if (ops[i].flags & OPF_REP) {
3158 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3161 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3162 if (ret != 1 || uval == 0) {
3163 // can't treat it as full setter because of ecx=0 case,
3164 // also disallow delayed compare
3173 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3180 // scan back for cdq, if anything modifies edx, fail
3181 static int scan_for_cdq_edx(int i)
3184 if (g_labels[i] != NULL) {
3185 if (g_label_refs[i].next != NULL)
3187 if (i > 0 && LAST_OP(i - 1)) {
3188 i = g_label_refs[i].i;
3195 if (ops[i].op == OP_CDQ)
3198 if (ops[i].regmask_dst & (1 << xDX))
3205 static int scan_for_reg_clear(int i, int reg)
3208 if (g_labels[i] != NULL) {
3209 if (g_label_refs[i].next != NULL)
3211 if (i > 0 && LAST_OP(i - 1)) {
3212 i = g_label_refs[i].i;
3219 if (ops[i].op == OP_XOR
3220 && ops[i].operand[0].lmod == OPLM_DWORD
3221 && ops[i].operand[0].reg == ops[i].operand[1].reg
3222 && ops[i].operand[0].reg == reg)
3225 if (ops[i].regmask_dst & (1 << reg))
3232 static void patch_esp_adjust(struct parsed_op *po, int adj)
3234 ferr_assert(po, po->op == OP_ADD);
3235 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3236 ferr_assert(po, po->operand[1].type == OPT_CONST);
3238 // this is a bit of a hack, but deals with use of
3239 // single adj for multiple calls
3240 po->operand[1].val -= adj;
3241 po->flags |= OPF_RMD;
3242 if (po->operand[1].val == 0)
3243 po->flags |= OPF_DONE;
3244 ferr_assert(po, (int)po->operand[1].val >= 0);
3247 // scan for positive, constant esp adjust
3248 // multipath case is preliminary
3249 static int scan_for_esp_adjust(int i, int opcnt,
3250 int adj_expect, int *adj, int *is_multipath, int do_update)
3252 int adj_expect_unknown = 0;
3253 struct parsed_op *po;
3257 *adj = *is_multipath = 0;
3258 if (adj_expect < 0) {
3259 adj_expect_unknown = 1;
3260 adj_expect = 32 * 4; // enough?
3263 for (; i < opcnt && *adj < adj_expect; i++) {
3264 if (g_labels[i] != NULL)
3268 if (po->flags & OPF_DONE)
3271 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3272 if (po->operand[1].type != OPT_CONST)
3273 ferr(&ops[i], "non-const esp adjust?\n");
3274 *adj += po->operand[1].val;
3276 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3279 patch_esp_adjust(po, adj_expect);
3281 po->flags |= OPF_RMD;
3285 else if (po->op == OP_PUSH) {
3286 //if (first_pop == -1)
3287 // first_pop = -2; // none
3288 *adj -= lmod_bytes(po, po->operand[0].lmod);
3290 else if (po->op == OP_POP) {
3291 if (!(po->flags & OPF_DONE)) {
3292 // seems like msvc only uses 'pop ecx' for stack realignment..
3293 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3295 if (first_pop == -1 && *adj >= 0)
3298 if (do_update && *adj >= 0) {
3299 po->flags |= OPF_RMD;
3301 po->flags |= OPF_DONE | OPF_NOREGS;
3304 *adj += lmod_bytes(po, po->operand[0].lmod);
3305 if (*adj > adj_best)
3308 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3309 if (po->op == OP_JMP && po->btj == NULL) {
3315 if (po->op != OP_CALL)
3317 if (po->operand[0].type != OPT_LABEL)
3319 if (po->pp != NULL && po->pp->is_stdcall)
3321 if (adj_expect_unknown && first_pop >= 0)
3323 // assume it's another cdecl call
3327 if (first_pop >= 0) {
3328 // probably only 'pop ecx' was used
3336 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3338 struct parsed_op *po;
3342 ferr(ops, "%s: followed bad branch?\n", __func__);
3344 for (; i < opcnt; i++) {
3346 if (po->cc_scratch == magic)
3348 po->cc_scratch = magic;
3351 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3352 if (po->btj != NULL) {
3354 for (j = 0; j < po->btj->count; j++)
3355 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3359 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3360 if (!(po->flags & OPF_CJMP))
3363 if (po->flags & OPF_TAIL)
3368 static const struct parsed_proto *try_recover_pp(
3369 struct parsed_op *po, const struct parsed_opr *opr,
3370 int is_call, int *search_instead)
3372 const struct parsed_proto *pp = NULL;
3376 // maybe an arg of g_func?
3377 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3379 char ofs_reg[16] = { 0, };
3380 int arg, arg_s, arg_i;
3387 parse_stack_access(po, opr->name, ofs_reg,
3388 &offset, &stack_ra, NULL, 0);
3389 if (ofs_reg[0] != 0)
3390 ferr(po, "offset reg on arg access?\n");
3391 if (offset <= stack_ra) {
3392 // search who set the stack var instead
3393 if (search_instead != NULL)
3394 *search_instead = 1;
3398 arg_i = (offset - stack_ra - 4) / 4;
3399 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3400 if (g_func_pp->arg[arg].reg != NULL)
3406 if (arg == g_func_pp->argc)
3407 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3409 pp = g_func_pp->arg[arg].pp;
3412 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3413 check_func_pp(po, pp, "icall arg");
3416 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3418 p = strchr(opr->name + 1, '[');
3419 memcpy(buf, opr->name, p - opr->name);
3420 buf[p - opr->name] = 0;
3421 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3423 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3424 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3427 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3430 check_func_pp(po, pp, "reg-fptr ref");
3436 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3437 int magic, const struct parsed_proto **pp_found, int *pp_i,
3440 const struct parsed_proto *pp = NULL;
3441 struct parsed_op *po;
3442 struct label_ref *lr;
3444 ops[i].cc_scratch = magic;
3447 if (g_labels[i] != NULL) {
3448 lr = &g_label_refs[i];
3449 for (; lr != NULL; lr = lr->next) {
3450 check_i(&ops[i], lr->i);
3451 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3453 if (i > 0 && LAST_OP(i - 1))
3461 if (ops[i].cc_scratch == magic)
3463 ops[i].cc_scratch = magic;
3465 if (!(ops[i].flags & OPF_DATA))
3467 if (!is_opr_modified(opr, &ops[i]))
3469 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3470 // most probably trashed by some processing
3475 opr = &ops[i].operand[1];
3476 if (opr->type != OPT_REG)
3480 po = (i >= 0) ? &ops[i] : ops;
3483 // reached the top - can only be an arg-reg
3484 if (opr->type != OPT_REG || g_func_pp == NULL)
3487 for (i = 0; i < g_func_pp->argc; i++) {
3488 if (g_func_pp->arg[i].reg == NULL)
3490 if (IS(opr->name, g_func_pp->arg[i].reg))
3493 if (i == g_func_pp->argc)
3495 pp = g_func_pp->arg[i].pp;
3497 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3498 i + 1, g_func_pp->arg[i].reg);
3499 check_func_pp(po, pp, "icall reg-arg");
3502 pp = try_recover_pp(po, opr, 1, NULL);
3504 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3505 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3506 || (*pp_found)->is_stdcall != pp->is_stdcall
3507 || (*pp_found)->is_fptr != pp->is_fptr
3508 || (*pp_found)->argc != pp->argc
3509 || (*pp_found)->argc_reg != pp->argc_reg
3510 || (*pp_found)->argc_stack != pp->argc_stack)
3512 ferr(po, "icall: parsed_proto mismatch\n");
3522 static void add_label_ref(struct label_ref *lr, int op_i)
3524 struct label_ref *lr_new;
3531 lr_new = calloc(1, sizeof(*lr_new));
3533 lr_new->next = lr->next;
3537 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3539 struct parsed_op *po = &ops[i];
3540 struct parsed_data *pd;
3541 char label[NAMELEN], *p;
3544 p = strchr(po->operand[0].name, '[');
3548 len = p - po->operand[0].name;
3549 strncpy(label, po->operand[0].name, len);
3552 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3553 if (IS(g_func_pd[j].label, label)) {
3559 //ferr(po, "label '%s' not parsed?\n", label);
3562 if (pd->type != OPT_OFFSET)
3563 ferr(po, "label '%s' with non-offset data?\n", label);
3565 // find all labels, link
3566 for (j = 0; j < pd->count; j++) {
3567 for (l = 0; l < opcnt; l++) {
3568 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3569 add_label_ref(&g_label_refs[l], i);
3579 static void clear_labels(int count)
3583 for (i = 0; i < count; i++) {
3584 if (g_labels[i] != NULL) {
3591 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3596 for (i = 0; i < pp->argc; i++) {
3597 if (pp->arg[i].reg != NULL) {
3598 reg = char_array_i(regs_r32,
3599 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3601 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3602 pp->arg[i].reg, pp->name);
3603 regmask |= 1 << reg;
3610 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3615 if (pp->has_retreg) {
3616 for (i = 0; i < pp->argc; i++) {
3617 if (pp->arg[i].type.is_retreg) {
3618 reg = char_array_i(regs_r32,
3619 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3620 ferr_assert(ops, reg >= 0);
3621 regmask |= 1 << reg;
3626 if (strstr(pp->ret_type.name, "int64"))
3627 return regmask | (1 << xAX) | (1 << xDX);
3628 if (IS(pp->ret_type.name, "float")
3629 || IS(pp->ret_type.name, "double"))
3631 return regmask | mxST0;
3633 if (strcasecmp(pp->ret_type.name, "void") == 0)
3636 return regmask | mxAX;
3639 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3641 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3642 && memcmp(po1->operand, po2->operand,
3643 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3646 static void resolve_branches_parse_calls(int opcnt)
3648 static const struct {
3652 unsigned int regmask_src;
3653 unsigned int regmask_dst;
3655 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3656 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3657 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3658 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3660 const struct parsed_proto *pp_c;
3661 struct parsed_proto *pp;
3662 struct parsed_data *pd;
3663 struct parsed_op *po;
3664 const char *tmpname;
3668 for (i = 0; i < opcnt; i++)
3674 if (po->datap != NULL) {
3675 pp = calloc(1, sizeof(*pp));
3676 my_assert_not(pp, NULL);
3678 ret = parse_protostr(po->datap, pp);
3680 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3686 if (po->op == OP_CALL) {
3691 else if (po->operand[0].type == OPT_LABEL)
3693 tmpname = opr_name(po, 0);
3694 if (IS_START(tmpname, "loc_"))
3695 ferr(po, "call to loc_*\n");
3696 if (IS(tmpname, "__alloca_probe"))
3699 // convert some calls to pseudo-ops
3700 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3701 if (!IS(tmpname, pseudo_ops[l].name))
3704 po->op = pseudo_ops[l].op;
3705 po->operand_cnt = 0;
3706 po->regmask_src = pseudo_ops[l].regmask_src;
3707 po->regmask_dst = pseudo_ops[l].regmask_dst;
3708 po->flags = pseudo_ops[l].flags;
3709 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3712 if (l < ARRAY_SIZE(pseudo_ops))
3715 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3716 if (!g_header_mode && pp_c == NULL)
3717 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3720 pp = proto_clone(pp_c);
3721 my_assert_not(pp, NULL);
3727 check_func_pp(po, pp, "fptr var call");
3728 if (pp->is_noreturn)
3729 po->flags |= OPF_TAIL;
3735 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3738 if (po->operand[0].type == OPT_REGMEM) {
3739 pd = try_resolve_jumptab(i, opcnt);
3747 for (l = 0; l < opcnt; l++) {
3748 if (g_labels[l] != NULL
3749 && IS(po->operand[0].name, g_labels[l]))
3751 if (l == i + 1 && po->op == OP_JMP) {
3752 // yet another alignment type..
3753 po->flags |= OPF_RMD|OPF_DONE;
3756 add_label_ref(&g_label_refs[l], i);
3762 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3765 if (po->operand[0].type == OPT_LABEL)
3769 ferr(po, "unhandled branch\n");
3773 po->flags |= OPF_TAIL;
3774 if (i > 0 && ops[i - 1].op == OP_POP)
3775 po->flags |= OPF_ATAIL;
3780 static void scan_prologue_epilogue(int opcnt)
3782 int ecx_push = 0, esp_sub = 0, pusha = 0;
3783 int sandard_epilogue;
3787 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3788 && ops[1].op == OP_MOV
3789 && IS(opr_name(&ops[1], 0), "ebp")
3790 && IS(opr_name(&ops[1], 1), "esp"))
3793 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3794 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3797 if (ops[i].op == OP_PUSHA) {
3798 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3803 if (ops[i].op == OP_SUB && IS(opr_name(&ops[i], 0), "esp")) {
3804 g_stack_fsz = opr_const(&ops[i], 1);
3805 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3809 // another way msvc builds stack frame..
3810 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3812 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3816 // and another way..
3817 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3818 && ops[i].operand[1].type == OPT_CONST
3819 && ops[i + 1].op == OP_CALL
3820 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3822 g_stack_fsz += ops[i].operand[1].val;
3823 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3825 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3832 for (; i < opcnt; i++)
3833 if (ops[i].flags & OPF_TAIL)
3836 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3837 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3843 sandard_epilogue = 0;
3844 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3846 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3847 // the standard epilogue is sometimes even used without a sf
3848 if (ops[j - 1].op == OP_MOV
3849 && IS(opr_name(&ops[j - 1], 0), "esp")
3850 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3851 sandard_epilogue = 1;
3853 else if (ops[j].op == OP_LEAVE)
3855 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3856 sandard_epilogue = 1;
3858 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3859 && ops[i].pp->is_noreturn)
3861 // on noreturn, msvc sometimes cleans stack, sometimes not
3866 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3867 ferr(&ops[j], "'pop ebp' expected\n");
3869 if (g_stack_fsz != 0 || sandard_epilogue) {
3870 if (ops[j].op == OP_LEAVE)
3872 else if (sandard_epilogue) // mov esp, ebp
3874 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3877 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3879 ferr(&ops[j], "esp restore expected\n");
3882 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3883 && IS(opr_name(&ops[j], 0), "ecx"))
3885 ferr(&ops[j], "unexpected ecx pop\n");
3890 if (ops[j].op == OP_POPA)
3891 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3893 ferr(&ops[j], "popa expected\n");
3898 } while (i < opcnt);
3901 ferr(ops, "missing ebp epilogue\n");
3907 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3908 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3914 for (; i < opcnt; i++) {
3915 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3917 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3918 && ops[i].operand[1].type == OPT_CONST)
3920 g_stack_fsz = ops[i].operand[1].val;
3921 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3926 else if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3927 && ops[i].operand[1].type == OPT_CONST
3928 && ops[i + 1].op == OP_CALL
3929 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3931 g_stack_fsz += ops[i].operand[1].val;
3932 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3934 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3941 if (ecx_push && !esp_sub) {
3942 // could actually be args for a call..
3943 for (; i < opcnt; i++)
3944 if (ops[i].op != OP_PUSH)
3947 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3948 const struct parsed_proto *pp;
3949 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3950 j = pp ? pp->argc_stack : 0;
3951 while (i > 0 && j > 0) {
3953 if (ops[i].op == OP_PUSH) {
3954 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
3959 ferr(&ops[i], "unhandled prologue\n");
3962 i = g_stack_fsz = ecx_push = 0;
3963 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3964 if (!(ops[i].flags & OPF_RMD))
3974 if (ecx_push || esp_sub)
3979 for (; i < opcnt; i++)
3980 if (ops[i].flags & OPF_TAIL)
3984 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3985 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3992 for (l = 0; l < ecx_push; l++) {
3993 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
3995 else if (ops[j].op == OP_ADD
3996 && IS(opr_name(&ops[j], 0), "esp")
3997 && ops[j].operand[1].type == OPT_CONST)
4000 l += ops[j].operand[1].val / 4 - 1;
4003 ferr(&ops[j], "'pop ecx' expected\n");
4005 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4009 ferr(&ops[j], "epilogue scan failed\n");
4015 if (ops[j].op != OP_ADD
4016 || !IS(opr_name(&ops[j], 0), "esp")
4017 || ops[j].operand[1].type != OPT_CONST
4018 || ops[j].operand[1].val != g_stack_fsz)
4020 if (ops[i].op == OP_CALL && ops[i].pp != NULL
4021 && ops[i].pp->is_noreturn)
4023 // noreturn tailcall with no epilogue
4027 ferr(&ops[j], "'add esp' expected\n");
4030 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4031 ops[j].operand[1].val = 0; // hack for stack arg scanner
4036 } while (i < opcnt);
4039 ferr(ops, "missing esp epilogue\n");
4043 // find an instruction that changed opr before i op
4044 // *op_i must be set to -1 by the caller
4045 // *is_caller is set to 1 if one source is determined to be g_func arg
4046 // returns 1 if found, *op_i is then set to origin
4047 // returns -1 if multiple origins are found
4048 static int resolve_origin(int i, const struct parsed_opr *opr,
4049 int magic, int *op_i, int *is_caller)
4051 struct label_ref *lr;
4055 if (g_labels[i] != NULL) {
4056 lr = &g_label_refs[i];
4057 for (; lr != NULL; lr = lr->next) {
4058 check_i(&ops[i], lr->i);
4059 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4061 if (i > 0 && LAST_OP(i - 1))
4067 if (is_caller != NULL)
4072 if (ops[i].cc_scratch == magic)
4074 ops[i].cc_scratch = magic;
4076 if (!(ops[i].flags & OPF_DATA))
4078 if (!is_opr_modified(opr, &ops[i]))
4082 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4093 // find an instruction that previously referenced opr
4094 // if multiple results are found - fail
4095 // *op_i must be set to -1 by the caller
4096 // returns 1 if found, *op_i is then set to referencer insn
4097 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4098 int magic, int *op_i)
4100 struct label_ref *lr;
4104 if (g_labels[i] != NULL) {
4105 lr = &g_label_refs[i];
4106 for (; lr != NULL; lr = lr->next) {
4107 check_i(&ops[i], lr->i);
4108 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4110 if (i > 0 && LAST_OP(i - 1))
4118 if (ops[i].cc_scratch == magic)
4120 ops[i].cc_scratch = magic;
4122 if (!is_opr_referenced(opr, &ops[i]))
4133 // adjust datap of all reachable 'op' insns when moving back
4134 // returns 1 if at least 1 op was found
4135 // returns -1 if path without an op was found
4136 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4138 struct label_ref *lr;
4141 if (ops[i].cc_scratch == magic)
4143 ops[i].cc_scratch = magic;
4146 if (g_labels[i] != NULL) {
4147 lr = &g_label_refs[i];
4148 for (; lr != NULL; lr = lr->next) {
4149 check_i(&ops[i], lr->i);
4150 ret |= adjust_prev_op(lr->i, op, magic, datap);
4152 if (i > 0 && LAST_OP(i - 1))
4160 if (ops[i].cc_scratch == magic)
4162 ops[i].cc_scratch = magic;
4164 if (ops[i].op != op)
4167 ops[i].datap = datap;
4172 // find next instruction that reads opr
4173 // *op_i must be set to -1 by the caller
4174 // on return, *op_i is set to first referencer insn
4175 // returns 1 if exactly 1 referencer is found
4176 static int find_next_read(int i, int opcnt,
4177 const struct parsed_opr *opr, int magic, int *op_i)
4179 struct parsed_op *po;
4182 for (; i < opcnt; i++)
4184 if (ops[i].cc_scratch == magic)
4186 ops[i].cc_scratch = magic;
4189 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4190 if (po->btj != NULL) {
4192 for (j = 0; j < po->btj->count; j++) {
4193 check_i(po, po->btj->d[j].bt_i);
4194 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4200 if (po->flags & OPF_RMD)
4202 check_i(po, po->bt_i);
4203 if (po->flags & OPF_CJMP) {
4204 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4213 if (!is_opr_read(opr, po)) {
4215 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4216 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4218 full_opr = po->operand[0].lmod >= opr->lmod;
4220 if (is_opr_modified(opr, po) && full_opr) {
4224 if (po->flags & OPF_TAIL)
4239 // find next instruction that reads opr
4240 // *op_i must be set to -1 by the caller
4241 // on return, *op_i is set to first flag user insn
4242 // returns 1 if exactly 1 flag user is found
4243 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4245 struct parsed_op *po;
4248 for (; i < opcnt; i++)
4250 if (ops[i].cc_scratch == magic)
4252 ops[i].cc_scratch = magic;
4255 if (po->op == OP_CALL)
4257 if (po->flags & OPF_JMP) {
4258 if (po->btj != NULL) {
4260 for (j = 0; j < po->btj->count; j++) {
4261 check_i(po, po->btj->d[j].bt_i);
4262 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4268 if (po->flags & OPF_RMD)
4270 check_i(po, po->bt_i);
4271 if (po->flags & OPF_CJMP)
4278 if (!(po->flags & OPF_CC)) {
4279 if (po->flags & OPF_FLAGS)
4282 if (po->flags & OPF_TAIL)
4298 static int try_resolve_const(int i, const struct parsed_opr *opr,
4299 int magic, unsigned int *val)
4304 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4307 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4310 *val = ops[i].operand[1].val;
4317 static int resolve_used_bits(int i, int opcnt, int reg,
4318 int *mask, int *is_z_check)
4320 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4324 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4328 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4330 fnote(&ops[j], "(first read)\n");
4331 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4334 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4335 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4337 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4338 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4340 *mask = ops[j].operand[1].val;
4341 if (ops[j].operand[0].lmod == OPLM_BYTE
4342 && ops[j].operand[0].name[1] == 'h')
4346 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4349 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4351 *is_z_check = ops[k].pfo == PFO_Z;
4356 static const struct parsed_proto *resolve_deref(int i, int magic,
4357 struct parsed_opr *opr, int level)
4359 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4360 const struct parsed_proto *pp = NULL;
4361 int from_caller = 0;
4370 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4371 if (ret != 2 || len != strlen(opr->name)) {
4372 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4373 if (ret != 1 || len != strlen(opr->name))
4377 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4382 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4386 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4387 && strlen(ops[j].operand[1].name) == 3
4388 && ops[j].operand[0].lmod == OPLM_DWORD
4389 && ops[j].pp == NULL // no hint
4392 // allow one simple dereference (com/directx)
4393 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4394 ops[j].operand[1].name);
4398 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4403 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4406 if (ops[j].pp != NULL) {
4410 else if (ops[j].operand[1].type == OPT_REGMEM) {
4411 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4413 // maybe structure ptr in structure
4414 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4417 else if (ops[j].operand[1].type == OPT_LABEL)
4418 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4419 else if (ops[j].operand[1].type == OPT_REG) {
4422 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4424 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4425 for (k = 0; k < g_func_pp->argc; k++) {
4426 if (g_func_pp->arg[k].reg == NULL)
4428 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4429 pp = g_func_pp->arg[k].pp;
4438 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4440 ferr(&ops[j], "expected struct, got '%s %s'\n",
4441 pp->type.name, pp->name);
4445 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4448 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4449 int *pp_i, int *multi_src)
4451 const struct parsed_proto *pp = NULL;
4452 int search_advice = 0;
4457 switch (ops[i].operand[0].type) {
4459 // try to resolve struct member calls
4460 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4466 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4472 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4480 static struct parsed_proto *process_call_early(int i, int opcnt,
4483 struct parsed_op *po = &ops[i];
4484 struct parsed_proto *pp;
4490 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4494 // look for and make use of esp adjust
4496 if (!pp->is_stdcall && pp->argc_stack > 0)
4497 ret = scan_for_esp_adjust(i + 1, opcnt,
4498 pp->argc_stack * 4, &adj, &multipath, 0);
4500 if (pp->argc_stack > adj / 4)
4504 if (ops[ret].op == OP_POP) {
4505 for (j = 1; j < adj / 4; j++) {
4506 if (ops[ret + j].op != OP_POP
4507 || ops[ret + j].operand[0].reg != xCX)
4519 static struct parsed_proto *process_call(int i, int opcnt)
4521 struct parsed_op *po = &ops[i];
4522 const struct parsed_proto *pp_c;
4523 struct parsed_proto *pp;
4524 const char *tmpname;
4525 int call_i = -1, ref_i = -1;
4526 int adj = 0, multipath = 0;
4529 tmpname = opr_name(po, 0);
4534 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4536 if (!pp_c->is_func && !pp_c->is_fptr)
4537 ferr(po, "call to non-func: %s\n", pp_c->name);
4538 pp = proto_clone(pp_c);
4539 my_assert_not(pp, NULL);
4541 // not resolved just to single func
4544 switch (po->operand[0].type) {
4546 // we resolved this call and no longer need the register
4547 po->regmask_src &= ~(1 << po->operand[0].reg);
4549 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4550 && ops[call_i].operand[1].type == OPT_LABEL)
4552 // no other source users?
4553 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4555 if (ret == 1 && call_i == ref_i) {
4556 // and nothing uses it after us?
4558 find_next_read(i + 1, opcnt, &po->operand[0],
4559 i + opcnt * 11, &ref_i);
4561 // then also don't need the source mov
4562 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4574 pp = calloc(1, sizeof(*pp));
4575 my_assert_not(pp, NULL);
4578 ret = scan_for_esp_adjust(i + 1, opcnt,
4579 -1, &adj, &multipath, 0);
4580 if (ret < 0 || adj < 0) {
4581 if (!g_allow_regfunc)
4582 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4583 pp->is_unresolved = 1;
4587 if (adj > ARRAY_SIZE(pp->arg))
4588 ferr(po, "esp adjust too large: %d\n", adj);
4589 pp->ret_type.name = strdup("int");
4590 pp->argc = pp->argc_stack = adj;
4591 for (arg = 0; arg < pp->argc; arg++)
4592 pp->arg[arg].type.name = strdup("int");
4597 // look for and make use of esp adjust
4600 if (!pp->is_stdcall && pp->argc_stack > 0) {
4601 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4602 ret = scan_for_esp_adjust(i + 1, opcnt,
4603 adj_expect, &adj, &multipath, 0);
4606 if (pp->is_vararg) {
4607 if (adj / 4 < pp->argc_stack) {
4608 fnote(po, "(this call)\n");
4609 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4610 adj, pp->argc_stack * 4);
4612 // modify pp to make it have varargs as normal args
4614 pp->argc += adj / 4 - pp->argc_stack;
4615 for (; arg < pp->argc; arg++) {
4616 pp->arg[arg].type.name = strdup("int");
4619 if (pp->argc > ARRAY_SIZE(pp->arg))
4620 ferr(po, "too many args for '%s'\n", tmpname);
4622 if (pp->argc_stack > adj / 4) {
4623 fnote(po, "(this call)\n");
4624 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4625 tmpname, pp->argc_stack * 4, adj);
4628 scan_for_esp_adjust(i + 1, opcnt,
4629 pp->argc_stack * 4, &adj, &multipath, 1);
4631 else if (pp->is_vararg)
4632 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4638 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
4641 struct parsed_op *po;
4647 for (base_arg = 0; base_arg < pp->argc; base_arg++)
4648 if (pp->arg[base_arg].reg == NULL)
4651 for (j = i; j > 0; )
4653 ferr_assert(&ops[j], g_labels[j] == NULL);
4657 ferr_assert(po, po->op != OP_PUSH);
4658 if (po->op == OP_FST)
4660 if (po->operand[0].type != OPT_REGMEM)
4662 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
4665 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3))
4666 ferr(po, "bad offset %d (%d args)\n", offset, pp->argc_stack);
4668 arg = base_arg + offset / 4;
4670 po->p_argnum = arg + 1;
4671 ferr_assert(po, pp->arg[arg].datap == NULL);
4672 pp->arg[arg].datap = po;
4673 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
4674 if (regmask_ffca != NULL)
4675 *regmask_ffca |= 1 << arg;
4677 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4678 && po->operand[1].type == OPT_CONST)
4680 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4685 for (arg = base_arg; arg < pp->argc; arg++) {
4686 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
4687 po = pp->arg[arg].datap;
4689 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
4690 if (po->operand[0].lmod == OPLM_QWORD)
4697 static int collect_call_args_early(int i, struct parsed_proto *pp,
4698 int *regmask, int *regmask_ffca)
4700 struct parsed_op *po;
4704 for (arg = 0; arg < pp->argc; arg++)
4705 if (pp->arg[arg].reg == NULL)
4708 // first see if it can be easily done
4709 for (j = i; j > 0 && arg < pp->argc; )
4711 if (g_labels[j] != NULL)
4716 if (po->op == OP_CALL)
4718 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
4720 else if (po->op == OP_POP)
4722 else if (po->flags & OPF_CJMP)
4724 else if (po->op == OP_PUSH) {
4725 if (po->flags & (OPF_FARG|OPF_FARGNR))
4727 if (!g_header_mode) {
4728 ret = scan_for_mod(po, j + 1, i, 1);
4733 if (pp->arg[arg].type.is_va_list)
4737 for (arg++; arg < pp->argc; arg++)
4738 if (pp->arg[arg].reg == NULL)
4741 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4742 && po->operand[1].type == OPT_CONST)
4744 if (po->flags & (OPF_RMD|OPF_DONE))
4746 if (po->operand[1].val != pp->argc_stack * 4)
4747 ferr(po, "unexpected esp adjust: %d\n",
4748 po->operand[1].val * 4);
4749 ferr_assert(po, pp->argc - arg == pp->argc_stack);
4750 return collect_call_args_no_push(i, pp, regmask_ffca);
4758 for (arg = 0; arg < pp->argc; arg++)
4759 if (pp->arg[arg].reg == NULL)
4762 for (j = i; j > 0 && arg < pp->argc; )
4766 if (ops[j].op == OP_PUSH)
4768 ops[j].p_argnext = -1;
4769 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4770 pp->arg[arg].datap = &ops[j];
4772 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
4773 *regmask |= 1 << ops[j].operand[0].reg;
4775 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4776 ops[j].flags &= ~OPF_RSAVE;
4779 for (arg++; arg < pp->argc; arg++)
4780 if (pp->arg[arg].reg == NULL)
4788 static int sync_argnum(struct parsed_op *po, int argnum)
4790 struct parsed_op *po_tmp;
4792 // see if other branches don't have higher argnum
4793 for (po_tmp = po; po_tmp != NULL; ) {
4794 if (argnum < po_tmp->p_argnum)
4795 argnum = po_tmp->p_argnum;
4796 // note: p_argnext is active on current collect_call_args only
4797 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4800 // make all argnums consistent
4801 for (po_tmp = po; po_tmp != NULL; ) {
4802 if (po_tmp->p_argnum != 0)
4803 po_tmp->p_argnum = argnum;
4804 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4810 static int collect_call_args_r(struct parsed_op *po, int i,
4811 struct parsed_proto *pp, int *regmask, int *arg_grp,
4812 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
4814 struct parsed_proto *pp_tmp;
4815 struct parsed_op *po_tmp;
4816 struct label_ref *lr;
4817 int need_to_save_current;
4818 int arg_grp_current = 0;
4819 int save_args_seen = 0;
4826 ferr(po, "dead label encountered\n");
4830 for (; arg < pp->argc; arg++, argnum++)
4831 if (pp->arg[arg].reg == NULL)
4833 magic = (magic & 0xffffff) | (arg << 24);
4835 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4837 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4838 if (ops[j].cc_scratch != magic) {
4839 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4843 // ok: have already been here
4846 ops[j].cc_scratch = magic;
4848 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4849 lr = &g_label_refs[j];
4850 if (lr->next != NULL)
4852 for (; lr->next; lr = lr->next) {
4853 check_i(&ops[j], lr->i);
4854 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4856 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4857 arg, argnum, magic, need_op_saving, may_reuse);
4862 check_i(&ops[j], lr->i);
4863 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4865 if (j > 0 && LAST_OP(j - 1)) {
4866 // follow last branch in reverse
4871 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4872 arg, argnum, magic, need_op_saving, may_reuse);
4878 if (ops[j].op == OP_CALL)
4880 if (pp->is_unresolved)
4885 ferr(po, "arg collect hit unparsed call '%s'\n",
4886 ops[j].operand[0].name);
4887 if (may_reuse && pp_tmp->argc_stack > 0)
4888 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4889 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4891 // esp adjust of 0 means we collected it before
4892 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4893 && (ops[j].operand[1].type != OPT_CONST
4894 || ops[j].operand[1].val != 0))
4896 if (pp->is_unresolved)
4899 fnote(po, "(this call)\n");
4900 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4901 arg, pp->argc, ops[j].operand[1].val);
4903 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4905 if (pp->is_unresolved)
4908 fnote(po, "(this call)\n");
4909 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4911 else if (ops[j].flags & OPF_CJMP)
4913 if (pp->is_unresolved)
4918 else if (ops[j].op == OP_PUSH
4919 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4921 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4924 ops[j].p_argnext = -1;
4925 po_tmp = pp->arg[arg].datap;
4927 ops[j].p_argnext = po_tmp - ops;
4928 pp->arg[arg].datap = &ops[j];
4930 argnum = sync_argnum(&ops[j], argnum);
4932 need_to_save_current = 0;
4934 if (ops[j].operand[0].type == OPT_REG)
4935 reg = ops[j].operand[0].reg;
4937 if (!need_op_saving) {
4938 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4939 need_to_save_current = (ret >= 0);
4941 if (need_op_saving || need_to_save_current) {
4942 // mark this arg as one that needs operand saving
4943 pp->arg[arg].is_saved = 1;
4945 if (save_args_seen & (1 << (argnum - 1))) {
4948 if (arg_grp_current >= MAX_ARG_GRP)
4949 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
4953 else if (ops[j].p_argnum == 0)
4954 ops[j].flags |= OPF_RMD;
4956 // some PUSHes are reused by different calls on other branches,
4957 // but that can't happen if we didn't branch, so they
4958 // can be removed from future searches (handles nested calls)
4960 ops[j].flags |= OPF_FARGNR;
4962 ops[j].flags |= OPF_FARG;
4963 ops[j].flags &= ~OPF_RSAVE;
4965 // check for __VALIST
4966 if (!pp->is_unresolved && g_func_pp != NULL
4967 && pp->arg[arg].type.is_va_list)
4970 ret = resolve_origin(j, &ops[j].operand[0],
4971 magic + 1, &k, NULL);
4972 if (ret == 1 && k >= 0)
4974 if (ops[k].op == OP_LEA) {
4975 if (!g_func_pp->is_vararg)
4976 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
4979 snprintf(buf, sizeof(buf), "arg_%X",
4980 g_func_pp->argc_stack * 4);
4981 if (strstr(ops[k].operand[1].name, buf)
4982 || strstr(ops[k].operand[1].name, "arglist"))
4984 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
4985 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
4986 pp->arg[arg].is_saved = 0;
4990 ferr(&ops[k], "va_list arg detection failed\n");
4992 // check for va_list from g_func_pp arg too
4993 else if (ops[k].op == OP_MOV
4994 && is_stack_access(&ops[k], &ops[k].operand[1]))
4996 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
4997 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
4999 ops[k].flags |= OPF_RMD | OPF_DONE;
5000 ops[j].flags |= OPF_RMD;
5001 ops[j].p_argpass = ret + 1;
5002 pp->arg[arg].is_saved = 0;
5009 if (pp->arg[arg].is_saved) {
5010 ops[j].flags &= ~OPF_RMD;
5011 ops[j].p_argnum = argnum;
5014 // tracking reg usage
5016 *regmask |= 1 << reg;
5020 if (!pp->is_unresolved) {
5022 for (; arg < pp->argc; arg++, argnum++)
5023 if (pp->arg[arg].reg == NULL)
5026 magic = (magic & 0xffffff) | (arg << 24);
5029 if (ops[j].p_arggrp > arg_grp_current) {
5031 arg_grp_current = ops[j].p_arggrp;
5033 if (ops[j].p_argnum > 0)
5034 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5037 if (arg < pp->argc) {
5038 ferr(po, "arg collect failed for '%s': %d/%d\n",
5039 pp->name, arg, pp->argc);
5043 if (arg_grp_current > *arg_grp)
5044 *arg_grp = arg_grp_current;
5049 static int collect_call_args(struct parsed_op *po, int i,
5050 struct parsed_proto *pp, int *regmask, int magic)
5052 // arg group is for cases when pushes for
5053 // multiple funcs are going on
5054 struct parsed_op *po_tmp;
5059 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5065 // propagate arg_grp
5066 for (a = 0; a < pp->argc; a++) {
5067 if (pp->arg[a].reg != NULL)
5070 po_tmp = pp->arg[a].datap;
5071 while (po_tmp != NULL) {
5072 po_tmp->p_arggrp = arg_grp;
5073 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5078 if (pp->is_unresolved) {
5080 pp->argc_stack += ret;
5081 for (a = 0; a < pp->argc; a++)
5082 if (pp->arg[a].type.name == NULL)
5083 pp->arg[a].type.name = strdup("int");
5089 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5090 int regmask_now, int *regmask,
5091 int regmask_save_now, int *regmask_save,
5092 int *regmask_init, int regmask_arg)
5094 struct parsed_op *po;
5102 for (; i < opcnt; i++)
5105 if (cbits[i >> 3] & (1 << (i & 7)))
5107 cbits[i >> 3] |= (1 << (i & 7));
5109 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5110 if (po->flags & (OPF_RMD|OPF_DONE))
5112 if (po->btj != NULL) {
5113 for (j = 0; j < po->btj->count; j++) {
5114 check_i(po, po->btj->d[j].bt_i);
5115 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5116 regmask_now, regmask, regmask_save_now, regmask_save,
5117 regmask_init, regmask_arg);
5122 check_i(po, po->bt_i);
5123 if (po->flags & OPF_CJMP)
5124 reg_use_pass(po->bt_i, opcnt, cbits,
5125 regmask_now, regmask, regmask_save_now, regmask_save,
5126 regmask_init, regmask_arg);
5132 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5133 && !g_func_pp->is_userstack
5134 && po->operand[0].type == OPT_REG)
5136 reg = po->operand[0].reg;
5137 ferr_assert(po, reg >= 0);
5140 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5141 if (regmask_now & (1 << reg)) {
5142 already_saved = regmask_save_now & (1 << reg);
5143 flags_set = OPF_RSAVE | OPF_DONE;
5146 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5148 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5149 reg, 0, 0, flags_set);
5152 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5154 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5159 ferr_assert(po, !already_saved);
5160 po->flags |= flags_set;
5162 if (regmask_now & (1 << reg)) {
5163 regmask_save_now |= (1 << reg);
5164 *regmask_save |= regmask_save_now;
5169 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5170 reg = po->operand[0].reg;
5171 ferr_assert(po, reg >= 0);
5173 if (regmask_save_now & (1 << reg))
5174 regmask_save_now &= ~(1 << reg);
5176 regmask_now &= ~(1 << reg);
5179 else if (po->op == OP_CALL) {
5180 if ((po->regmask_dst & (1 << xAX))
5181 && !(po->regmask_dst & (1 << xDX)))
5183 if (po->flags & OPF_TAIL)
5184 // don't need eax, will do "return f();" or "f(); return;"
5185 po->regmask_dst &= ~(1 << xAX);
5187 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5189 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5192 po->regmask_dst &= ~(1 << xAX);
5196 // not "full stack" mode and have something in stack
5197 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5198 ferr(po, "float stack is not empty on func call\n");
5201 if (po->flags & OPF_NOREGS)
5204 // if incomplete register is used, clear it on init to avoid
5205 // later use of uninitialized upper part in some situations
5206 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5207 && po->operand[0].lmod != OPLM_DWORD)
5209 reg = po->operand[0].reg;
5210 ferr_assert(po, reg >= 0);
5212 if (!(regmask_now & (1 << reg)))
5213 *regmask_init |= 1 << reg;
5216 regmask_op = po->regmask_src | po->regmask_dst;
5218 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5219 regmask_new &= ~(1 << xSP);
5220 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5221 regmask_new &= ~(1 << xBP);
5223 if (regmask_new != 0)
5224 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5226 if (regmask_op & (1 << xBP)) {
5227 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5228 if (po->regmask_dst & (1 << xBP))
5229 // compiler decided to drop bp frame and use ebp as scratch
5230 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5232 regmask_op &= ~(1 << xBP);
5236 if (po->flags & OPF_FPUSH) {
5237 if (regmask_now & mxST1)
5238 regmask_now |= mxSTa; // switch to "full stack" mode
5239 if (regmask_now & mxSTa)
5240 po->flags |= OPF_FSHIFT;
5241 if (!(regmask_now & mxST7_2)) {
5243 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5247 regmask_now |= regmask_op;
5248 *regmask |= regmask_now;
5251 if (po->flags & OPF_FPOP) {
5252 if ((regmask_now & mxSTa) == 0)
5253 ferr(po, "float pop on empty stack?\n");
5254 if (regmask_now & (mxST7_2 | mxST1))
5255 po->flags |= OPF_FSHIFT;
5256 if (!(regmask_now & mxST7_2)) {
5258 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5262 if (po->flags & OPF_TAIL) {
5263 if (!(regmask_now & mxST7_2)) {
5264 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5265 if (!(regmask_now & mxST0))
5266 ferr(po, "no st0 on float return, mask: %x\n",
5269 else if (regmask_now & mxST1_0)
5270 ferr(po, "float regs on tail: %x\n", regmask_now);
5273 // there is support for "conditional tailcall", sort of
5274 if (!(po->flags & OPF_CC))
5280 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5284 for (i = 0; i < pp->argc; i++)
5285 if (pp->arg[i].reg == NULL)
5289 memmove(&pp->arg[i + 1], &pp->arg[i],
5290 sizeof(pp->arg[0]) * pp->argc_stack);
5291 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5292 pp->arg[i].reg = strdup(reg);
5293 pp->arg[i].type.name = strdup("int");
5298 static void output_std_flags(FILE *fout, struct parsed_op *po,
5299 int *pfomask, const char *dst_opr_text)
5301 if (*pfomask & (1 << PFO_Z)) {
5302 fprintf(fout, "\n cond_z = (%s%s == 0);",
5303 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5304 *pfomask &= ~(1 << PFO_Z);
5306 if (*pfomask & (1 << PFO_S)) {
5307 fprintf(fout, "\n cond_s = (%s%s < 0);",
5308 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5309 *pfomask &= ~(1 << PFO_S);
5314 OPP_FORCE_NORETURN = (1 << 0),
5315 OPP_SIMPLE_ARGS = (1 << 1),
5316 OPP_ALIGN = (1 << 2),
5319 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5322 const char *cconv = "";
5324 if (pp->is_fastcall)
5325 cconv = "__fastcall ";
5326 else if (pp->is_stdcall && pp->argc_reg == 0)
5327 cconv = "__stdcall ";
5329 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5331 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5332 fprintf(fout, "noreturn ");
5335 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5340 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5344 output_pp_attrs(fout, pp, flags);
5347 fprintf(fout, "%s", pp->name);
5352 for (i = 0; i < pp->argc; i++) {
5354 fprintf(fout, ", ");
5355 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5356 && !(flags & OPP_SIMPLE_ARGS))
5359 output_pp(fout, pp->arg[i].pp, 0);
5361 else if (pp->arg[i].type.is_retreg) {
5362 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5365 fprintf(fout, "%s", pp->arg[i].type.name);
5367 fprintf(fout, " a%d", i + 1);
5370 if (pp->is_vararg) {
5372 fprintf(fout, ", ");
5373 fprintf(fout, "...");
5378 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5384 snprintf(buf1, sizeof(buf1), "%d", grp);
5385 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5390 static void gen_x_cleanup(int opcnt);
5392 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5394 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5395 struct parsed_opr *last_arith_dst = NULL;
5396 char buf1[256], buf2[256], buf3[256], cast[64];
5397 struct parsed_proto *pp, *pp_tmp;
5398 struct parsed_data *pd;
5399 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5400 unsigned char cbits[MAX_OPS / 8];
5401 const char *float_type;
5402 const char *float_st0;
5403 const char *float_st1;
5404 int need_float_stack = 0;
5405 int need_float_sw = 0; // status word
5406 int need_tmp_var = 0;
5410 int label_pending = 0;
5411 int need_double = 0;
5412 int regmask_save = 0; // used regs saved/restored in this func
5413 int regmask_arg; // regs from this function args (fastcall, etc)
5414 int regmask_ret; // regs needed on ret
5415 int regmask_now; // temp
5416 int regmask_init = 0; // regs that need zero initialization
5417 int regmask_pp = 0; // regs used in complex push-pop graph
5418 int regmask_ffca = 0; // float function call args
5419 int regmask = 0; // used regs
5429 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5430 g_stack_frame_used = 0;
5431 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5432 regmask_init = g_regmask_init;
5434 g_func_pp = proto_parse(fhdr, funcn, 0);
5435 if (g_func_pp == NULL)
5436 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5438 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5439 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5442 // - resolve all branches
5443 // - parse calls with labels
5444 resolve_branches_parse_calls(opcnt);
5447 // - handle ebp/esp frame, remove ops related to it
5448 scan_prologue_epilogue(opcnt);
5451 // - remove dead labels
5452 // - set regs needed at ret
5453 for (i = 0; i < opcnt; i++)
5455 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5460 if (ops[i].op == OP_RET)
5461 ops[i].regmask_src |= regmask_ret;
5465 // - process trivial calls
5466 for (i = 0; i < opcnt; i++)
5469 if (po->flags & (OPF_RMD|OPF_DONE))
5472 if (po->op == OP_CALL)
5474 pp = process_call_early(i, opcnt, &j);
5476 if (!(po->flags & OPF_ATAIL)) {
5477 // since we know the args, try to collect them
5478 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5486 // commit esp adjust
5487 if (ops[j].op != OP_POP)
5488 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5490 for (l = 0; l < pp->argc_stack; l++)
5491 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5495 if (strstr(pp->ret_type.name, "int64"))
5498 po->flags |= OPF_DONE;
5504 // - process calls, stage 2
5505 // - handle some push/pop pairs
5506 // - scan for STD/CLD, propagate DF
5507 // - try to resolve needed x87 status word bits
5508 for (i = 0; i < opcnt; i++)
5513 if (po->flags & OPF_RMD)
5516 if (po->op == OP_CALL)
5518 if (!(po->flags & OPF_DONE)) {
5519 pp = process_call(i, opcnt);
5521 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5522 // since we know the args, collect them
5523 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5525 // for unresolved, collect after other passes
5529 ferr_assert(po, pp != NULL);
5531 po->regmask_src |= get_pp_arg_regmask_src(pp);
5532 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5534 if (po->regmask_dst & mxST0)
5535 po->flags |= OPF_FPUSH;
5537 if (strstr(pp->ret_type.name, "int64"))
5543 if (po->flags & OPF_DONE)
5548 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
5549 && po->operand[0].type == OPT_CONST)
5551 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5556 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5560 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5561 scan_propagate_df(i + 1, opcnt);
5566 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
5567 ferr(po, "TODO: fnstsw to mem\n");
5568 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
5570 ferr(po, "fnstsw resolve failed\n");
5571 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
5572 (void *)(long)(mask | (z_check << 16)));
5574 ferr(po, "failed to find fcom: %d\n", ret);
5583 // - find POPs for PUSHes, rm both
5584 // - scan for all used registers
5585 memset(cbits, 0, sizeof(cbits));
5586 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5587 0, ®mask_save, ®mask_init, regmask_arg);
5590 // - find flag set ops for their users
5591 // - do unresolved calls
5592 // - declare indirect functions
5593 // - other op specific processing
5594 for (i = 0; i < opcnt; i++)
5597 if (po->flags & (OPF_RMD|OPF_DONE))
5600 if (po->flags & OPF_CC)
5602 int setters[16], cnt = 0, branched = 0;
5604 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
5605 &branched, setters, &cnt);
5606 if (ret < 0 || cnt <= 0)
5607 ferr(po, "unable to trace flag setter(s)\n");
5608 if (cnt > ARRAY_SIZE(setters))
5609 ferr(po, "too many flag setters\n");
5611 for (j = 0; j < cnt; j++)
5613 tmp_op = &ops[setters[j]]; // flag setter
5616 // to get nicer code, we try to delay test and cmp;
5617 // if we can't because of operand modification, or if we
5618 // have arith op, or branch, make it calculate flags explicitly
5619 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5621 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5622 pfomask = 1 << po->pfo;
5624 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5625 pfomask = 1 << po->pfo;
5628 // see if we'll be able to handle based on op result
5629 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5630 && po->pfo != PFO_Z && po->pfo != PFO_S
5631 && po->pfo != PFO_P)
5633 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5635 pfomask = 1 << po->pfo;
5638 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5639 propagate_lmod(tmp_op, &tmp_op->operand[0],
5640 &tmp_op->operand[1]);
5641 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5646 tmp_op->pfomask |= pfomask;
5647 cond_vars |= pfomask;
5649 // note: may overwrite, currently not a problem
5653 if (po->op == OP_RCL || po->op == OP_RCR
5654 || po->op == OP_ADC || po->op == OP_SBB)
5655 cond_vars |= 1 << PFO_C;
5661 cond_vars |= 1 << PFO_Z;
5665 if (po->operand[0].lmod == OPLM_DWORD)
5670 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
5675 // note: resolved non-reg calls are OPF_DONE already
5677 ferr_assert(po, pp != NULL);
5679 if (pp->is_unresolved) {
5680 int regmask_stack = 0;
5681 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5683 // this is pretty rough guess:
5684 // see ecx and edx were pushed (and not their saved versions)
5685 for (arg = 0; arg < pp->argc; arg++) {
5686 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
5689 tmp_op = pp->arg[arg].datap;
5691 ferr(po, "parsed_op missing for arg%d\n", arg);
5692 if (tmp_op->operand[0].type == OPT_REG)
5693 regmask_stack |= 1 << tmp_op->operand[0].reg;
5696 if (!((regmask_stack & (1 << xCX))
5697 && (regmask_stack & (1 << xDX))))
5699 if (pp->argc_stack != 0
5700 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5702 pp_insert_reg_arg(pp, "ecx");
5703 pp->is_fastcall = 1;
5704 regmask_init |= 1 << xCX;
5705 regmask |= 1 << xCX;
5707 if (pp->argc_stack != 0
5708 || ((regmask | regmask_arg) & (1 << xDX)))
5710 pp_insert_reg_arg(pp, "edx");
5711 regmask_init |= 1 << xDX;
5712 regmask |= 1 << xDX;
5716 // note: __cdecl doesn't fall into is_unresolved category
5717 if (pp->argc_stack > 0)
5723 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
5725 // <var> = offset <something>
5726 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5727 && !IS_START(po->operand[1].name, "off_"))
5729 if (!po->operand[0].pp->is_fptr)
5730 ferr(po, "%s not declared as fptr when it should be\n",
5731 po->operand[0].name);
5732 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5733 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5734 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5735 fnote(po, "var: %s\n", buf1);
5736 fnote(po, "func: %s\n", buf2);
5737 ferr(po, "^ mismatch\n");
5745 if (po->operand[0].lmod == OPLM_DWORD) {
5746 // 32bit division is common, look for it
5747 if (po->op == OP_DIV)
5748 ret = scan_for_reg_clear(i, xDX);
5750 ret = scan_for_cdq_edx(i);
5752 po->flags |= OPF_32BIT;
5761 po->flags |= OPF_RMD | OPF_DONE;
5771 if (po->operand[0].lmod == OPLM_QWORD)
5781 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5783 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5785 po->flags |= OPF_32BIT;
5793 // this might need it's own pass...
5794 if (po->op != OP_FST && po->p_argnum > 0)
5795 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
5798 float_type = need_double ? "double" : "float";
5799 need_float_stack = !!(regmask & mxST7_2);
5800 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
5801 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
5803 // output starts here
5805 // define userstack size
5806 if (g_func_pp->is_userstack) {
5807 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5808 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5809 fprintf(fout, "#endif\n");
5812 // the function itself
5813 ferr_assert(ops, !g_func_pp->is_fptr);
5814 output_pp(fout, g_func_pp,
5815 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5816 fprintf(fout, "\n{\n");
5818 // declare indirect functions
5819 for (i = 0; i < opcnt; i++) {
5821 if (po->flags & OPF_RMD)
5824 if (po->op == OP_CALL) {
5827 ferr(po, "NULL pp\n");
5829 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5830 if (pp->name[0] != 0) {
5831 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5832 memcpy(pp->name, "i_", 2);
5834 // might be declared already
5836 for (j = 0; j < i; j++) {
5837 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5838 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5848 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5851 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5852 fprintf(fout, ";\n");
5857 // output LUTs/jumptables
5858 for (i = 0; i < g_func_pd_cnt; i++) {
5860 fprintf(fout, " static const ");
5861 if (pd->type == OPT_OFFSET) {
5862 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5864 for (j = 0; j < pd->count; j++) {
5866 fprintf(fout, ", ");
5867 fprintf(fout, "&&%s", pd->d[j].u.label);
5871 fprintf(fout, "%s %s[] =\n { ",
5872 lmod_type_u(ops, pd->lmod), pd->label);
5874 for (j = 0; j < pd->count; j++) {
5876 fprintf(fout, ", ");
5877 fprintf(fout, "%u", pd->d[j].u.val);
5880 fprintf(fout, " };\n");
5884 // declare stack frame, va_arg
5886 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5887 if (g_func_lmods & (1 << OPLM_WORD))
5888 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5889 if (g_func_lmods & (1 << OPLM_BYTE))
5890 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5891 if (g_func_lmods & (1 << OPLM_QWORD))
5892 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5893 fprintf(fout, " } sf;\n");
5897 if (g_func_pp->is_userstack) {
5898 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5899 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5903 if (g_func_pp->is_vararg) {
5904 fprintf(fout, " va_list ap;\n");
5908 // declare arg-registers
5909 for (i = 0; i < g_func_pp->argc; i++) {
5910 if (g_func_pp->arg[i].reg != NULL) {
5911 reg = char_array_i(regs_r32,
5912 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5913 if (regmask & (1 << reg)) {
5914 if (g_func_pp->arg[i].type.is_retreg)
5915 fprintf(fout, " u32 %s = *r_%s;\n",
5916 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5918 fprintf(fout, " u32 %s = (u32)a%d;\n",
5919 g_func_pp->arg[i].reg, i + 1);
5922 if (g_func_pp->arg[i].type.is_retreg)
5923 ferr(ops, "retreg '%s' is unused?\n",
5924 g_func_pp->arg[i].reg);
5925 fprintf(fout, " // %s = a%d; // unused\n",
5926 g_func_pp->arg[i].reg, i + 1);
5932 // declare normal registers
5933 regmask_now = regmask & ~regmask_arg;
5934 regmask_now &= ~(1 << xSP);
5935 if (regmask_now & 0x00ff) {
5936 for (reg = 0; reg < 8; reg++) {
5937 if (regmask_now & (1 << reg)) {
5938 fprintf(fout, " u32 %s", regs_r32[reg]);
5939 if (regmask_init & (1 << reg))
5940 fprintf(fout, " = 0");
5941 fprintf(fout, ";\n");
5947 if (regmask_now & 0xff00) {
5948 for (reg = 8; reg < 16; reg++) {
5949 if (regmask_now & (1 << reg)) {
5950 fprintf(fout, " mmxr %s", regs_r32[reg]);
5951 if (regmask_init & (1 << reg))
5952 fprintf(fout, " = { 0, }");
5953 fprintf(fout, ";\n");
5959 if (need_float_stack) {
5960 fprintf(fout, " %s f_st[8];\n", float_type);
5961 fprintf(fout, " int f_stp = 0;\n");
5965 if (regmask_now & 0xff0000) {
5966 for (reg = 16; reg < 24; reg++) {
5967 if (regmask_now & (1 << reg)) {
5968 fprintf(fout, " %s f_st%d", float_type, reg - 16);
5969 if (regmask_init & (1 << reg))
5970 fprintf(fout, " = 0");
5971 fprintf(fout, ";\n");
5978 if (need_float_sw) {
5979 fprintf(fout, " u16 f_sw;\n");
5984 for (reg = 0; reg < 8; reg++) {
5985 if (regmask_save & (1 << reg)) {
5986 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
5992 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
5993 if (save_arg_vars[i] == 0)
5995 for (reg = 0; reg < 32; reg++) {
5996 if (save_arg_vars[i] & (1 << reg)) {
5997 fprintf(fout, " u32 %s;\n",
5998 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6005 for (reg = 0; reg < 32; reg++) {
6006 if (regmask_ffca & (1 << reg)) {
6007 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6013 // declare push-pop temporaries
6015 for (reg = 0; reg < 8; reg++) {
6016 if (regmask_pp & (1 << reg)) {
6017 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6024 for (i = 0; i < 8; i++) {
6025 if (cond_vars & (1 << i)) {
6026 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6033 fprintf(fout, " u32 tmp;\n");
6038 fprintf(fout, " u64 tmp64;\n");
6043 fprintf(fout, "\n");
6045 // do stack clear, if needed
6046 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6048 if (g_stack_clear_len != 0) {
6049 if (g_stack_clear_len <= 4) {
6050 for (i = 0; i < g_stack_clear_len; i++)
6051 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6052 fprintf(fout, "0;\n");
6055 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6056 g_stack_clear_start, g_stack_clear_len * 4);
6060 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6063 if (g_func_pp->is_vararg) {
6064 if (g_func_pp->argc_stack == 0)
6065 ferr(ops, "vararg func without stack args?\n");
6066 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6070 for (i = 0; i < opcnt; i++)
6072 if (g_labels[i] != NULL) {
6073 fprintf(fout, "\n%s:\n", g_labels[i]);
6076 delayed_flag_op = NULL;
6077 last_arith_dst = NULL;
6081 if (po->flags & OPF_RMD)
6086 #define assert_operand_cnt(n_) \
6087 if (po->operand_cnt != n_) \
6088 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6090 // conditional/flag using op?
6091 if (po->flags & OPF_CC)
6097 // we go through all this trouble to avoid using parsed_flag_op,
6098 // which makes generated code much nicer
6099 if (delayed_flag_op != NULL)
6101 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6102 po->pfo, po->pfo_inv);
6105 else if (last_arith_dst != NULL
6106 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6107 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6110 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6111 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6112 last_arith_dst->lmod, buf3);
6115 else if (tmp_op != NULL) {
6116 // use preprocessed flag calc results
6117 if (!(tmp_op->pfomask & (1 << po->pfo)))
6118 ferr(po, "not prepared for pfo %d\n", po->pfo);
6120 // note: pfo_inv was not yet applied
6121 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6122 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6125 ferr(po, "all methods of finding comparison failed\n");
6128 if (po->flags & OPF_JMP) {
6129 fprintf(fout, " if %s", buf1);
6131 else if (po->op == OP_RCL || po->op == OP_RCR
6132 || po->op == OP_ADC || po->op == OP_SBB)
6135 fprintf(fout, " cond_%s = %s;\n",
6136 parsed_flag_op_names[po->pfo], buf1);
6138 else if (po->flags & OPF_DATA) { // SETcc
6139 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6140 fprintf(fout, " %s = %s;", buf2, buf1);
6143 ferr(po, "unhandled conditional op\n");
6147 pfomask = po->pfomask;
6152 assert_operand_cnt(2);
6153 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6154 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6155 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6156 fprintf(fout, " %s = %s;", buf1,
6157 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6162 assert_operand_cnt(2);
6163 po->operand[1].lmod = OPLM_DWORD; // always
6164 fprintf(fout, " %s = %s;",
6165 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6166 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6171 assert_operand_cnt(2);
6172 fprintf(fout, " %s = %s;",
6173 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6174 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6178 assert_operand_cnt(2);
6179 switch (po->operand[1].lmod) {
6181 strcpy(buf3, "(s8)");
6184 strcpy(buf3, "(s16)");
6187 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6189 fprintf(fout, " %s = %s;",
6190 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6191 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6196 assert_operand_cnt(2);
6197 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6198 fprintf(fout, " tmp = %s;",
6199 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6200 fprintf(fout, " %s = %s;",
6201 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6202 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6203 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6204 fprintf(fout, " %s = %stmp;",
6205 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6206 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6207 snprintf(g_comment, sizeof(g_comment), "xchg");
6211 assert_operand_cnt(1);
6212 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6213 fprintf(fout, " %s = ~%s;", buf1, buf1);
6217 assert_operand_cnt(2);
6218 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6219 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6220 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6221 strcpy(g_comment, "xlat");
6225 assert_operand_cnt(2);
6226 fprintf(fout, " %s = (s32)%s >> 31;",
6227 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6228 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6229 strcpy(g_comment, "cdq");
6233 assert_operand_cnt(1);
6234 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6235 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6239 if (po->flags & OPF_REP) {
6240 assert_operand_cnt(3);
6245 assert_operand_cnt(2);
6246 fprintf(fout, " %s = %sesi; esi %c= %d;",
6247 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6248 lmod_cast_u_ptr(po, po->operand[1].lmod),
6249 (po->flags & OPF_DF) ? '-' : '+',
6250 lmod_bytes(po, po->operand[1].lmod));
6251 strcpy(g_comment, "lods");
6256 if (po->flags & OPF_REP) {
6257 assert_operand_cnt(3);
6258 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6259 (po->flags & OPF_DF) ? '-' : '+',
6260 lmod_bytes(po, po->operand[1].lmod));
6261 fprintf(fout, " %sedi = eax;",
6262 lmod_cast_u_ptr(po, po->operand[1].lmod));
6263 strcpy(g_comment, "rep stos");
6266 assert_operand_cnt(2);
6267 fprintf(fout, " %sedi = eax; edi %c= %d;",
6268 lmod_cast_u_ptr(po, po->operand[1].lmod),
6269 (po->flags & OPF_DF) ? '-' : '+',
6270 lmod_bytes(po, po->operand[1].lmod));
6271 strcpy(g_comment, "stos");
6276 j = lmod_bytes(po, po->operand[0].lmod);
6277 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6278 l = (po->flags & OPF_DF) ? '-' : '+';
6279 if (po->flags & OPF_REP) {
6280 assert_operand_cnt(3);
6282 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6285 " %sedi = %sesi;", buf1, buf1);
6286 strcpy(g_comment, "rep movs");
6289 assert_operand_cnt(2);
6290 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6291 buf1, buf1, l, j, l, j);
6292 strcpy(g_comment, "movs");
6297 // repe ~ repeat while ZF=1
6298 j = lmod_bytes(po, po->operand[0].lmod);
6299 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6300 l = (po->flags & OPF_DF) ? '-' : '+';
6301 if (po->flags & OPF_REP) {
6302 assert_operand_cnt(3);
6304 " while (ecx != 0) {\n");
6305 if (pfomask & (1 << PFO_C)) {
6308 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6309 pfomask &= ~(1 << PFO_C);
6312 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6313 buf1, buf1, l, j, l, j);
6316 " if (cond_z %s 0) break;\n",
6317 (po->flags & OPF_REPZ) ? "==" : "!=");
6320 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6321 (po->flags & OPF_REPZ) ? "e" : "ne");
6324 assert_operand_cnt(2);
6326 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6327 buf1, buf1, l, j, l, j);
6328 strcpy(g_comment, "cmps");
6330 pfomask &= ~(1 << PFO_Z);
6331 last_arith_dst = NULL;
6332 delayed_flag_op = NULL;
6336 // only does ZF (for now)
6337 // repe ~ repeat while ZF=1
6338 j = lmod_bytes(po, po->operand[1].lmod);
6339 l = (po->flags & OPF_DF) ? '-' : '+';
6340 if (po->flags & OPF_REP) {
6341 assert_operand_cnt(3);
6343 " while (ecx != 0) {\n");
6345 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6346 lmod_cast_u(po, po->operand[1].lmod),
6347 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6350 " if (cond_z %s 0) break;\n",
6351 (po->flags & OPF_REPZ) ? "==" : "!=");
6354 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6355 (po->flags & OPF_REPZ) ? "e" : "ne");
6358 assert_operand_cnt(2);
6359 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6360 lmod_cast_u(po, po->operand[1].lmod),
6361 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6362 strcpy(g_comment, "scas");
6364 pfomask &= ~(1 << PFO_Z);
6365 last_arith_dst = NULL;
6366 delayed_flag_op = NULL;
6369 // arithmetic w/flags
6371 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6372 goto dualop_arith_const;
6373 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6377 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6378 if (po->operand[1].type == OPT_CONST) {
6379 j = lmod_bytes(po, po->operand[0].lmod);
6380 if (((1ull << j * 8) - 1) == po->operand[1].val)
6381 goto dualop_arith_const;
6386 assert_operand_cnt(2);
6387 fprintf(fout, " %s %s= %s;",
6388 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6390 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6391 output_std_flags(fout, po, &pfomask, buf1);
6392 last_arith_dst = &po->operand[0];
6393 delayed_flag_op = NULL;
6397 // and 0, or ~0 used instead mov
6398 assert_operand_cnt(2);
6399 fprintf(fout, " %s = %s;",
6400 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6401 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6402 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6403 output_std_flags(fout, po, &pfomask, buf1);
6404 last_arith_dst = &po->operand[0];
6405 delayed_flag_op = NULL;
6410 assert_operand_cnt(2);
6411 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6412 if (pfomask & (1 << PFO_C)) {
6413 if (po->operand[1].type == OPT_CONST) {
6414 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6415 j = po->operand[1].val;
6418 if (po->op == OP_SHL)
6422 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6426 ferr(po, "zero shift?\n");
6430 pfomask &= ~(1 << PFO_C);
6432 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6433 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6434 if (po->operand[1].type != OPT_CONST)
6435 fprintf(fout, " & 0x1f");
6437 output_std_flags(fout, po, &pfomask, buf1);
6438 last_arith_dst = &po->operand[0];
6439 delayed_flag_op = NULL;
6443 assert_operand_cnt(2);
6444 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6445 fprintf(fout, " %s = %s%s >> %s;", buf1,
6446 lmod_cast_s(po, po->operand[0].lmod), buf1,
6447 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6448 output_std_flags(fout, po, &pfomask, buf1);
6449 last_arith_dst = &po->operand[0];
6450 delayed_flag_op = NULL;
6455 assert_operand_cnt(3);
6456 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6457 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6458 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6459 if (po->operand[2].type != OPT_CONST) {
6460 // no handling for "undefined" case, hopefully not needed
6461 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6464 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6465 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6466 if (po->op == OP_SHLD) {
6467 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6468 buf1, buf3, buf1, buf2, l, buf3);
6469 strcpy(g_comment, "shld");
6472 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6473 buf1, buf3, buf1, buf2, l, buf3);
6474 strcpy(g_comment, "shrd");
6476 output_std_flags(fout, po, &pfomask, buf1);
6477 last_arith_dst = &po->operand[0];
6478 delayed_flag_op = NULL;
6483 assert_operand_cnt(2);
6484 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6485 if (po->operand[1].type == OPT_CONST) {
6486 j = po->operand[1].val;
6487 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6488 fprintf(fout, po->op == OP_ROL ?
6489 " %s = (%s << %d) | (%s >> %d);" :
6490 " %s = (%s >> %d) | (%s << %d);",
6491 buf1, buf1, j, buf1,
6492 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6496 output_std_flags(fout, po, &pfomask, buf1);
6497 last_arith_dst = &po->operand[0];
6498 delayed_flag_op = NULL;
6503 assert_operand_cnt(2);
6504 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6505 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6506 if (po->operand[1].type == OPT_CONST) {
6507 j = po->operand[1].val % l;
6509 ferr(po, "zero rotate\n");
6510 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6511 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6512 if (po->op == OP_RCL) {
6514 " %s = (%s << %d) | (cond_c << %d)",
6515 buf1, buf1, j, j - 1);
6517 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6521 " %s = (%s >> %d) | (cond_c << %d)",
6522 buf1, buf1, j, l - j);
6524 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6526 fprintf(fout, ";\n");
6527 fprintf(fout, " cond_c = tmp;");
6531 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6532 output_std_flags(fout, po, &pfomask, buf1);
6533 last_arith_dst = &po->operand[0];
6534 delayed_flag_op = NULL;
6538 assert_operand_cnt(2);
6539 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6540 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6541 // special case for XOR
6542 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
6543 for (j = 0; j <= PFO_LE; j++) {
6544 if (pfomask & (1 << j)) {
6545 fprintf(fout, " cond_%s = %d;\n",
6546 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
6547 pfomask &= ~(1 << j);
6550 fprintf(fout, " %s = 0;",
6551 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6552 last_arith_dst = &po->operand[0];
6553 delayed_flag_op = NULL;
6559 assert_operand_cnt(2);
6560 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6561 if (pfomask & (1 << PFO_C)) {
6562 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6563 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6564 if (po->operand[0].lmod == OPLM_DWORD) {
6565 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6566 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6567 fprintf(fout, " %s = (u32)tmp64;",
6568 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6569 strcat(g_comment, " add64");
6572 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6573 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6574 fprintf(fout, " %s += %s;",
6575 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6578 pfomask &= ~(1 << PFO_C);
6579 output_std_flags(fout, po, &pfomask, buf1);
6580 last_arith_dst = &po->operand[0];
6581 delayed_flag_op = NULL;
6584 if (pfomask & (1 << PFO_LE)) {
6585 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
6586 fprintf(fout, " cond_%s = %s;\n",
6587 parsed_flag_op_names[PFO_LE], buf1);
6588 pfomask &= ~(1 << PFO_LE);
6593 assert_operand_cnt(2);
6594 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6595 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6596 for (j = 0; j <= PFO_LE; j++) {
6597 if (!(pfomask & (1 << j)))
6599 if (j == PFO_Z || j == PFO_S)
6602 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6603 fprintf(fout, " cond_%s = %s;\n",
6604 parsed_flag_op_names[j], buf1);
6605 pfomask &= ~(1 << j);
6612 assert_operand_cnt(2);
6613 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6614 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6615 if (po->op == OP_SBB
6616 && IS(po->operand[0].name, po->operand[1].name))
6618 // avoid use of unitialized var
6619 fprintf(fout, " %s = -cond_c;", buf1);
6620 // carry remains what it was
6621 pfomask &= ~(1 << PFO_C);
6624 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6625 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6627 output_std_flags(fout, po, &pfomask, buf1);
6628 last_arith_dst = &po->operand[0];
6629 delayed_flag_op = NULL;
6633 assert_operand_cnt(2);
6634 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6635 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6636 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6638 output_std_flags(fout, po, &pfomask, buf1);
6639 last_arith_dst = &po->operand[0];
6640 delayed_flag_op = NULL;
6641 strcat(g_comment, " bsf");
6645 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6646 for (j = 0; j <= PFO_LE; j++) {
6647 if (!(pfomask & (1 << j)))
6649 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6652 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6653 fprintf(fout, " cond_%s = %s;\n",
6654 parsed_flag_op_names[j], buf1);
6655 pfomask &= ~(1 << j);
6661 if (pfomask & (1 << PFO_C))
6662 // carry is unaffected by inc/dec.. wtf?
6663 ferr(po, "carry propagation needed\n");
6665 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6666 if (po->operand[0].type == OPT_REG) {
6667 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6668 fprintf(fout, " %s%s;", buf1, buf2);
6671 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6672 fprintf(fout, " %s %s= 1;", buf1, buf2);
6674 output_std_flags(fout, po, &pfomask, buf1);
6675 last_arith_dst = &po->operand[0];
6676 delayed_flag_op = NULL;
6680 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6681 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6682 fprintf(fout, " %s = -%s%s;", buf1,
6683 lmod_cast_s(po, po->operand[0].lmod), buf2);
6684 last_arith_dst = &po->operand[0];
6685 delayed_flag_op = NULL;
6686 if (pfomask & (1 << PFO_C)) {
6687 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6688 pfomask &= ~(1 << PFO_C);
6693 if (po->operand_cnt == 2) {
6694 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6697 if (po->operand_cnt == 3)
6698 ferr(po, "TODO imul3\n");
6701 assert_operand_cnt(1);
6702 switch (po->operand[0].lmod) {
6704 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6705 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6706 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6707 fprintf(fout, " edx = tmp64 >> 32;\n");
6708 fprintf(fout, " eax = tmp64;");
6711 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6712 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6713 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6717 ferr(po, "TODO: unhandled mul type\n");
6720 last_arith_dst = NULL;
6721 delayed_flag_op = NULL;
6726 assert_operand_cnt(1);
6727 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6728 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6729 po->op == OP_IDIV));
6730 switch (po->operand[0].lmod) {
6732 if (po->flags & OPF_32BIT)
6733 snprintf(buf2, sizeof(buf2), "%seax", cast);
6735 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6736 snprintf(buf2, sizeof(buf2), "%stmp64",
6737 (po->op == OP_IDIV) ? "(s64)" : "");
6739 if (po->operand[0].type == OPT_REG
6740 && po->operand[0].reg == xDX)
6742 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6743 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6746 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6747 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6751 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6752 snprintf(buf2, sizeof(buf2), "%stmp",
6753 (po->op == OP_IDIV) ? "(s32)" : "");
6754 if (po->operand[0].type == OPT_REG
6755 && po->operand[0].reg == xDX)
6757 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6759 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6763 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6765 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6768 strcat(g_comment, " div16");
6771 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6773 last_arith_dst = NULL;
6774 delayed_flag_op = NULL;
6779 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6781 for (j = 0; j < 8; j++) {
6782 if (pfomask & (1 << j)) {
6783 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6784 fprintf(fout, " cond_%s = %s;",
6785 parsed_flag_op_names[j], buf1);
6792 last_arith_dst = NULL;
6793 delayed_flag_op = po;
6797 // SETcc - should already be handled
6800 // note: we reuse OP_Jcc for SETcc, only flags differ
6802 fprintf(fout, "\n goto %s;", po->operand[0].name);
6806 fprintf(fout, " if (ecx == 0)\n");
6807 fprintf(fout, " goto %s;", po->operand[0].name);
6808 strcat(g_comment, " jecxz");
6812 fprintf(fout, " if (--ecx != 0)\n");
6813 fprintf(fout, " goto %s;", po->operand[0].name);
6814 strcat(g_comment, " loop");
6818 assert_operand_cnt(1);
6819 last_arith_dst = NULL;
6820 delayed_flag_op = NULL;
6822 if (po->operand[0].type == OPT_REGMEM) {
6823 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6826 ferr(po, "parse failure for jmp '%s'\n",
6827 po->operand[0].name);
6828 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6831 else if (po->operand[0].type != OPT_LABEL)
6832 ferr(po, "unhandled jmp type\n");
6834 fprintf(fout, " goto %s;", po->operand[0].name);
6838 assert_operand_cnt(1);
6840 my_assert_not(pp, NULL);
6843 if (po->flags & OPF_CC) {
6844 // we treat conditional branch to another func
6845 // (yes such code exists..) as conditional tailcall
6847 fprintf(fout, " {\n");
6850 if (pp->is_fptr && !pp->is_arg) {
6851 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6852 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6854 if (pp->is_unresolved)
6855 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6856 buf3, asmfn, po->asmln, pp->name);
6859 fprintf(fout, "%s", buf3);
6860 if (strstr(pp->ret_type.name, "int64")) {
6861 if (po->flags & OPF_TAIL)
6862 ferr(po, "int64 and tail?\n");
6863 fprintf(fout, "tmp64 = ");
6865 else if (!IS(pp->ret_type.name, "void")) {
6866 if (po->flags & OPF_TAIL) {
6867 if (regmask_ret & mxAX) {
6868 fprintf(fout, "return ");
6869 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6870 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6872 else if (regmask_ret & mxST0)
6873 ferr(po, "float tailcall\n");
6875 else if (po->regmask_dst & mxAX) {
6876 fprintf(fout, "eax = ");
6877 if (pp->ret_type.is_ptr)
6878 fprintf(fout, "(u32)");
6880 else if (po->regmask_dst & mxST0) {
6881 ferr_assert(po, po->flags & OPF_FPUSH);
6882 if (need_float_stack)
6883 fprintf(fout, "f_st[--f_stp & 7] = ");
6885 fprintf(fout, "f_st0 = ");
6889 if (pp->name[0] == 0)
6890 ferr(po, "missing pp->name\n");
6891 fprintf(fout, "%s%s(", pp->name,
6892 pp->has_structarg ? "_sa" : "");
6894 if (po->flags & OPF_ATAIL) {
6895 if (pp->argc_stack != g_func_pp->argc_stack
6896 || (pp->argc_stack > 0
6897 && pp->is_stdcall != g_func_pp->is_stdcall))
6898 ferr(po, "incompatible tailcall\n");
6899 if (g_func_pp->has_retreg)
6900 ferr(po, "TODO: retreg+tailcall\n");
6902 for (arg = j = 0; arg < pp->argc; arg++) {
6904 fprintf(fout, ", ");
6907 if (pp->arg[arg].type.is_ptr)
6908 snprintf(cast, sizeof(cast), "(%s)",
6909 pp->arg[arg].type.name);
6911 if (pp->arg[arg].reg != NULL) {
6912 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6916 for (; j < g_func_pp->argc; j++)
6917 if (g_func_pp->arg[j].reg == NULL)
6919 fprintf(fout, "%sa%d", cast, j + 1);
6924 for (arg = 0; arg < pp->argc; arg++) {
6926 fprintf(fout, ", ");
6929 if (pp->arg[arg].type.is_ptr)
6930 snprintf(cast, sizeof(cast), "(%s)",
6931 pp->arg[arg].type.name);
6933 if (pp->arg[arg].reg != NULL) {
6934 if (pp->arg[arg].type.is_retreg)
6935 fprintf(fout, "&%s", pp->arg[arg].reg);
6936 else if (IS(pp->arg[arg].reg, "ebp")
6937 && !(po->flags & OPF_EBP_S))
6939 // rare special case
6940 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
6941 strcat(g_comment, " bp_ref");
6944 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6949 tmp_op = pp->arg[arg].datap;
6951 ferr(po, "parsed_op missing for arg%d\n", arg);
6953 if (tmp_op->flags & OPF_VAPUSH) {
6954 fprintf(fout, "ap");
6956 else if (tmp_op->op == OP_FST) {
6957 fprintf(fout, "fs_%d", tmp_op->p_argnum);
6958 if (tmp_op->operand[0].lmod == OPLM_QWORD)
6961 else if (tmp_op->p_argpass != 0) {
6962 fprintf(fout, "a%d", tmp_op->p_argpass);
6964 else if (pp->arg[arg].is_saved) {
6965 ferr_assert(po, tmp_op->p_argnum > 0);
6966 fprintf(fout, "%s%s", cast,
6967 saved_arg_name(buf1, sizeof(buf1),
6968 tmp_op->p_arggrp, tmp_op->p_argnum));
6972 out_src_opr(buf1, sizeof(buf1),
6973 tmp_op, &tmp_op->operand[0], cast, 0));
6977 fprintf(fout, ");");
6979 if (strstr(pp->ret_type.name, "int64")) {
6980 fprintf(fout, "\n");
6981 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
6982 fprintf(fout, "%seax = tmp64;", buf3);
6985 if (pp->is_unresolved) {
6986 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
6988 strcat(g_comment, buf2);
6991 if (po->flags & OPF_TAIL) {
6993 if (i == opcnt - 1 || pp->is_noreturn)
6995 else if (IS(pp->ret_type.name, "void"))
6997 else if (!(regmask_ret & (1 << xAX)))
6999 // else already handled as 'return f()'
7002 fprintf(fout, "\n%sreturn;", buf3);
7003 strcat(g_comment, " ^ tailcall");
7006 strcat(g_comment, " tailcall");
7008 if ((regmask_ret & (1 << xAX))
7009 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7011 ferr(po, "int func -> void func tailcall?\n");
7014 if (pp->is_noreturn)
7015 strcat(g_comment, " noreturn");
7016 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7017 strcat(g_comment, " argframe");
7018 if (po->flags & OPF_CC)
7019 strcat(g_comment, " cond");
7021 if (po->flags & OPF_CC)
7022 fprintf(fout, "\n }");
7024 delayed_flag_op = NULL;
7025 last_arith_dst = NULL;
7029 if (g_func_pp->is_vararg)
7030 fprintf(fout, " va_end(ap);\n");
7031 if (g_func_pp->has_retreg) {
7032 for (arg = 0; arg < g_func_pp->argc; arg++)
7033 if (g_func_pp->arg[arg].type.is_retreg)
7034 fprintf(fout, " *r_%s = %s;\n",
7035 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7038 if (regmask_ret & mxST0) {
7039 fprintf(fout, " return %s;", float_st0);
7041 else if (!(regmask_ret & mxAX)) {
7042 if (i != opcnt - 1 || label_pending)
7043 fprintf(fout, " return;");
7045 else if (g_func_pp->ret_type.is_ptr) {
7046 fprintf(fout, " return (%s)eax;",
7047 g_func_pp->ret_type.name);
7049 else if (IS(g_func_pp->ret_type.name, "__int64"))
7050 fprintf(fout, " return ((u64)edx << 32) | eax;");
7052 fprintf(fout, " return eax;");
7054 last_arith_dst = NULL;
7055 delayed_flag_op = NULL;
7059 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7060 if (po->p_argnum != 0) {
7061 // special case - saved func arg
7062 fprintf(fout, " %s = %s;",
7063 saved_arg_name(buf2, sizeof(buf2),
7064 po->p_arggrp, po->p_argnum), buf1);
7067 else if (po->flags & OPF_RSAVE) {
7068 fprintf(fout, " s_%s = %s;", buf1, buf1);
7071 else if (po->flags & OPF_PPUSH) {
7073 ferr_assert(po, tmp_op != NULL);
7074 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7075 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7078 else if (g_func_pp->is_userstack) {
7079 fprintf(fout, " *(--esp) = %s;", buf1);
7082 if (!(g_ida_func_attr & IDAFA_NORETURN))
7083 ferr(po, "stray push encountered\n");
7088 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7089 if (po->flags & OPF_RSAVE) {
7090 fprintf(fout, " %s = s_%s;", buf1, buf1);
7093 else if (po->flags & OPF_PPUSH) {
7094 // push/pop graph / non-const
7095 ferr_assert(po, po->datap == NULL);
7096 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7099 else if (po->datap != NULL) {
7102 fprintf(fout, " %s = %s;", buf1,
7103 out_src_opr(buf2, sizeof(buf2),
7104 tmp_op, &tmp_op->operand[0],
7105 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7108 else if (g_func_pp->is_userstack) {
7109 fprintf(fout, " %s = *esp++;", buf1);
7113 ferr(po, "stray pop encountered\n");
7123 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7124 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7125 po->op == OPP_ALLSHL ? "<<" : ">>");
7126 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7127 strcat(g_comment, po->op == OPP_ALLSHL
7128 ? " allshl" : " allshr");
7133 if (need_float_stack) {
7134 out_src_opr_float(buf1, sizeof(buf1),
7135 po, &po->operand[0], 1);
7136 if (po->regmask_src & mxSTa) {
7137 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7141 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7144 if (po->flags & OPF_FSHIFT)
7145 fprintf(fout, " f_st1 = f_st0;");
7146 if (po->operand[0].type == OPT_REG
7147 && po->operand[0].reg == xST0)
7149 strcat(g_comment, " fld st");
7152 fprintf(fout, " f_st0 = %s;",
7153 out_src_opr_float(buf1, sizeof(buf1),
7154 po, &po->operand[0], 0));
7156 strcat(g_comment, " fld");
7160 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7161 lmod_cast(po, po->operand[0].lmod, 1), 0);
7162 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7163 if (need_float_stack) {
7164 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7167 if (po->flags & OPF_FSHIFT)
7168 fprintf(fout, " f_st1 = f_st0;");
7169 fprintf(fout, " f_st0 = %s;", buf2);
7171 strcat(g_comment, " fild");
7175 if (need_float_stack)
7176 fprintf(fout, " f_st[--f_stp & 7] = ");
7178 if (po->flags & OPF_FSHIFT)
7179 fprintf(fout, " f_st1 = f_st0;");
7180 fprintf(fout, " f_st0 = ");
7182 switch (po->operand[0].val) {
7183 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7184 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
7185 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7186 default: ferr(po, "TODO\n"); break;
7191 if (po->flags & OPF_FARG) {
7192 // store to stack as func arg
7193 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7197 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7199 dead_dst = po->operand[0].type == OPT_REG
7200 && po->operand[0].reg == xST0;
7203 fprintf(fout, " %s = %s;", buf1, float_st0);
7204 if (po->flags & OPF_FSHIFT) {
7205 if (need_float_stack)
7206 fprintf(fout, " f_stp++;");
7208 fprintf(fout, " f_st0 = f_st1;");
7210 if (dead_dst && !(po->flags & OPF_FSHIFT))
7213 strcat(g_comment, " fst");
7217 fprintf(fout, " %s = %s%s;",
7218 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7219 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7220 if (po->flags & OPF_FSHIFT) {
7221 if (need_float_stack)
7222 fprintf(fout, " f_stp++;");
7224 fprintf(fout, " f_st0 = f_st1;");
7226 strcat(g_comment, " fist");
7233 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7235 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7237 dead_dst = (po->flags & OPF_FPOP)
7238 && po->operand[0].type == OPT_REG
7239 && po->operand[0].reg == xST0;
7241 case OP_FADD: j = '+'; break;
7242 case OP_FDIV: j = '/'; break;
7243 case OP_FMUL: j = '*'; break;
7244 case OP_FSUB: j = '-'; break;
7245 default: j = 'x'; break;
7247 if (need_float_stack) {
7249 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7250 if (po->flags & OPF_FSHIFT)
7251 fprintf(fout, " f_stp++;");
7254 if (po->flags & OPF_FSHIFT) {
7255 // note: assumes only 2 regs handled
7257 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7259 fprintf(fout, " f_st0 = f_st1;");
7262 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7264 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7269 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7271 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7273 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7275 dead_dst = (po->flags & OPF_FPOP)
7276 && po->operand[0].type == OPT_REG
7277 && po->operand[0].reg == xST0;
7278 j = po->op == OP_FDIVR ? '/' : '-';
7279 if (need_float_stack) {
7281 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7282 if (po->flags & OPF_FSHIFT)
7283 fprintf(fout, " f_stp++;");
7286 if (po->flags & OPF_FSHIFT) {
7288 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7290 fprintf(fout, " f_st0 = f_st1;");
7293 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7295 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7303 case OP_FIADD: j = '+'; break;
7304 case OP_FIDIV: j = '/'; break;
7305 case OP_FIMUL: j = '*'; break;
7306 case OP_FISUB: j = '-'; break;
7307 default: j = 'x'; break;
7309 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7311 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7312 lmod_cast(po, po->operand[0].lmod, 1), 0));
7317 fprintf(fout, " %s = %s %c %s;", float_st0,
7318 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7320 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7325 ferr_assert(po, po->datap != NULL);
7326 mask = (long)po->datap & 0xffff;
7327 z_check = ((long)po->datap >> 16) & 1;
7328 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7330 if (mask == 0x0100) { // C0 -> <
7331 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7334 else if (mask == 0x4000) { // C3 -> =
7335 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7338 else if (mask == 0x4100) { // C3, C0
7340 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7342 strcat(g_comment, " z_chk_det");
7345 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7346 "(%s < %s ? 0x0100 : 0);",
7347 float_st0, buf1, float_st0, buf1);
7351 ferr(po, "unhandled sw mask: %x\n", mask);
7352 if (po->flags & OPF_FSHIFT) {
7353 if (need_float_stack)
7354 fprintf(fout, " f_stp++;");
7356 fprintf(fout, " f_st0 = f_st1;");
7362 fprintf(fout, " %s = f_sw;",
7363 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7367 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7371 fprintf(fout, " %s = cos%s(%s);", float_st0,
7372 need_double ? "" : "f", float_st0);
7376 if (need_float_stack) {
7377 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7378 need_double ? "" : "f", float_st1, float_st0);
7379 fprintf(fout, " f_stp++;");
7382 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7383 need_double ? "" : "f");
7388 if (need_float_stack) {
7389 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7390 float_st1, need_double ? "" : "f", float_st0);
7391 fprintf(fout, " f_stp++;");
7394 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7395 need_double ? "" : "f");
7397 strcat(g_comment, " fyl2x");
7401 fprintf(fout, " %s = sin%s(%s);", float_st0,
7402 need_double ? "" : "f", float_st0);
7406 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7407 need_double ? "" : "f", float_st0);
7411 dead_dst = po->operand[0].type == OPT_REG
7412 && po->operand[0].reg == xST0;
7414 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7416 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7417 float_st0, float_st0, buf1, buf1);
7418 strcat(g_comment, " fxch");
7425 ferr_assert(po, po->flags & OPF_32BIT);
7426 fprintf(fout, " eax = (s32)%s;", float_st0);
7427 if (po->flags & OPF_FSHIFT) {
7428 if (need_float_stack)
7429 fprintf(fout, " f_stp++;");
7431 fprintf(fout, " f_st0 = f_st1;");
7433 strcat(g_comment, " ftol");
7437 if (need_float_stack) {
7438 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
7439 need_double ? "" : "f", float_st1, float_st0);
7440 fprintf(fout, " f_stp++;");
7443 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
7444 need_double ? "" : "f");
7446 strcat(g_comment, " CIpow");
7451 strcpy(g_comment, " (emms)");
7456 ferr(po, "unhandled op type %d, flags %x\n",
7461 if (g_comment[0] != 0) {
7462 char *p = g_comment;
7463 while (my_isblank(*p))
7465 fprintf(fout, " // %s", p);
7470 fprintf(fout, "\n");
7472 // some sanity checking
7473 if (po->flags & OPF_REP) {
7474 if (po->op != OP_STOS && po->op != OP_MOVS
7475 && po->op != OP_CMPS && po->op != OP_SCAS)
7476 ferr(po, "unexpected rep\n");
7477 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7478 && (po->op == OP_CMPS || po->op == OP_SCAS))
7479 ferr(po, "cmps/scas with plain rep\n");
7481 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7482 && po->op != OP_CMPS && po->op != OP_SCAS)
7483 ferr(po, "unexpected repz/repnz\n");
7486 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
7488 // see is delayed flag stuff is still valid
7489 if (delayed_flag_op != NULL && delayed_flag_op != po) {
7490 if (is_any_opr_modified(delayed_flag_op, po, 0))
7491 delayed_flag_op = NULL;
7494 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7495 if (is_opr_modified(last_arith_dst, po))
7496 last_arith_dst = NULL;
7502 if (g_stack_fsz && !g_stack_frame_used)
7503 fprintf(fout, " (void)sf;\n");
7505 fprintf(fout, "}\n\n");
7507 gen_x_cleanup(opcnt);
7510 static void gen_x_cleanup(int opcnt)
7514 for (i = 0; i < opcnt; i++) {
7515 struct label_ref *lr, *lr_del;
7517 lr = g_label_refs[i].next;
7518 while (lr != NULL) {
7523 g_label_refs[i].i = -1;
7524 g_label_refs[i].next = NULL;
7526 if (ops[i].op == OP_CALL) {
7528 proto_release(ops[i].pp);
7534 struct func_proto_dep;
7536 struct func_prototype {
7541 int has_ret:3; // -1, 0, 1: unresolved, no, yes
7542 unsigned int dep_resolved:1;
7543 unsigned int is_stdcall:1;
7544 struct func_proto_dep *dep_func;
7546 const struct parsed_proto *pp; // seed pp, if any
7549 struct func_proto_dep {
7551 struct func_prototype *proto;
7552 int regmask_live; // .. at the time of call
7553 unsigned int ret_dep:1; // return from this is caller's return
7556 static struct func_prototype *hg_fp;
7557 static int hg_fp_cnt;
7559 static struct scanned_var {
7561 enum opr_lenmod lmod;
7562 unsigned int is_seeded:1;
7563 unsigned int is_c_str:1;
7564 const struct parsed_proto *pp; // seed pp, if any
7566 static int hg_var_cnt;
7568 static char **hg_refs;
7569 static int hg_ref_cnt;
7571 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7574 static struct func_prototype *hg_fp_add(const char *funcn)
7576 struct func_prototype *fp;
7578 if ((hg_fp_cnt & 0xff) == 0) {
7579 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7580 my_assert_not(hg_fp, NULL);
7581 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7584 fp = &hg_fp[hg_fp_cnt];
7585 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7587 fp->argc_stack = -1;
7593 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7598 for (i = 0; i < fp->dep_func_cnt; i++)
7599 if (IS(fp->dep_func[i].name, name))
7600 return &fp->dep_func[i];
7605 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7608 if (hg_fp_find_dep(fp, name))
7611 if ((fp->dep_func_cnt & 0xff) == 0) {
7612 fp->dep_func = realloc(fp->dep_func,
7613 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7614 my_assert_not(fp->dep_func, NULL);
7615 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7616 sizeof(fp->dep_func[0]) * 0x100);
7618 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7622 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7624 const struct func_prototype *p1 = p1_, *p2 = p2_;
7625 return strcmp(p1->name, p2->name);
7629 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7631 const struct func_prototype *p1 = p1_, *p2 = p2_;
7632 return p1->id - p2->id;
7636 static void hg_ref_add(const char *name)
7638 if ((hg_ref_cnt & 0xff) == 0) {
7639 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7640 my_assert_not(hg_refs, NULL);
7641 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7644 hg_refs[hg_ref_cnt] = strdup(name);
7645 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7649 // recursive register dep pass
7650 // - track saved regs (part 2)
7651 // - try to figure out arg-regs
7652 // - calculate reg deps
7653 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
7654 struct func_prototype *fp, int regmask_save, int regmask_dst,
7655 int *regmask_dep, int *has_ret)
7657 struct func_proto_dep *dep;
7658 struct parsed_op *po;
7659 int from_caller = 0;
7664 for (; i < opcnt; i++)
7666 if (cbits[i >> 3] & (1 << (i & 7)))
7668 cbits[i >> 3] |= (1 << (i & 7));
7672 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
7673 if (po->flags & OPF_RMD)
7676 if (po->btj != NULL) {
7678 for (j = 0; j < po->btj->count; j++) {
7679 check_i(po, po->btj->d[j].bt_i);
7680 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
7681 regmask_save, regmask_dst, regmask_dep, has_ret);
7686 check_i(po, po->bt_i);
7687 if (po->flags & OPF_CJMP) {
7688 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
7689 regmask_save, regmask_dst, regmask_dep, has_ret);
7697 if (po->flags & OPF_FARG)
7698 /* (just calculate register deps) */;
7699 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
7701 reg = po->operand[0].reg;
7702 ferr_assert(po, reg >= 0);
7704 if (po->flags & OPF_RSAVE) {
7705 regmask_save |= 1 << reg;
7708 if (po->flags & OPF_DONE)
7711 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
7713 regmask_save |= 1 << reg;
7714 po->flags |= OPF_RMD;
7715 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
7719 else if (po->flags & OPF_RMD)
7721 else if (po->op == OP_CALL) {
7722 po->regmask_dst |= 1 << xAX;
7724 dep = hg_fp_find_dep(fp, po->operand[0].name);
7726 dep->regmask_live = regmask_save | regmask_dst;
7728 else if (po->op == OP_RET) {
7729 if (po->operand_cnt > 0) {
7731 if (fp->argc_stack >= 0
7732 && fp->argc_stack != po->operand[0].val / 4)
7733 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
7734 fp->argc_stack = po->operand[0].val / 4;
7738 // if has_ret is 0, there is uninitialized eax path,
7739 // which means it's most likely void func
7740 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
7741 if (po->op == OP_CALL) {
7746 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
7749 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
7752 if (ret != 1 && from_caller) {
7753 // unresolved eax - probably void func
7757 if (j >= 0 && ops[j].op == OP_CALL) {
7758 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
7769 l = regmask_save | regmask_dst;
7770 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7773 l = po->regmask_src & ~l;
7776 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
7777 l, regmask_dst, regmask_save, po->flags);
7780 regmask_dst |= po->regmask_dst;
7782 if (po->flags & OPF_TAIL)
7787 static void gen_hdr(const char *funcn, int opcnt)
7789 unsigned char cbits[MAX_OPS / 8];
7790 const struct parsed_proto *pp_c;
7791 struct parsed_proto *pp;
7792 struct func_prototype *fp;
7793 struct parsed_op *po;
7794 int regmask_dummy = 0;
7796 int max_bp_offset = 0;
7801 pp_c = proto_parse(g_fhdr, funcn, 1);
7803 // already in seed, will add to hg_fp later
7806 fp = hg_fp_add(funcn);
7808 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7809 g_stack_frame_used = 0;
7812 // - resolve all branches
7813 // - parse calls with labels
7814 resolve_branches_parse_calls(opcnt);
7817 // - handle ebp/esp frame, remove ops related to it
7818 scan_prologue_epilogue(opcnt);
7821 // - remove dead labels
7823 for (i = 0; i < opcnt; i++)
7825 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7831 if (po->flags & (OPF_RMD|OPF_DONE))
7834 if (po->op == OP_CALL) {
7835 if (po->operand[0].type == OPT_LABEL)
7836 hg_fp_add_dep(fp, opr_name(po, 0));
7837 else if (po->pp != NULL)
7838 hg_fp_add_dep(fp, po->pp->name);
7843 // - remove dead labels
7844 // - handle push <const>/pop pairs
7845 for (i = 0; i < opcnt; i++)
7847 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7853 if (po->flags & (OPF_RMD|OPF_DONE))
7856 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
7857 scan_for_pop_const(i, opcnt, i + opcnt * 13);
7861 // - process trivial calls
7862 for (i = 0; i < opcnt; i++)
7865 if (po->flags & (OPF_RMD|OPF_DONE))
7868 if (po->op == OP_CALL)
7870 pp = process_call_early(i, opcnt, &j);
7872 if (!(po->flags & OPF_ATAIL))
7873 // since we know the args, try to collect them
7874 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
7880 // commit esp adjust
7881 if (ops[j].op != OP_POP)
7882 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
7884 for (l = 0; l < pp->argc_stack; l++)
7885 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
7889 po->flags |= OPF_DONE;
7895 // - track saved regs (simple)
7897 for (i = 0; i < opcnt; i++)
7900 if (po->flags & (OPF_RMD|OPF_DONE))
7903 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7904 && po->operand[0].reg != xCX)
7906 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
7908 // regmask_save |= 1 << po->operand[0].reg; // do it later
7909 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
7910 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
7913 else if (po->op == OP_CALL)
7915 pp = process_call(i, opcnt);
7917 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
7918 // since we know the args, collect them
7919 ret = collect_call_args(po, i, pp, ®mask_dummy,
7926 memset(cbits, 0, sizeof(cbits));
7930 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
7932 // find unreachable code - must be fixed in IDA
7933 for (i = 0; i < opcnt; i++)
7935 if (cbits[i >> 3] & (1 << (i & 7)))
7938 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
7939 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
7941 // the compiler sometimes still generates code after
7942 // noreturn OS functions
7945 if (ops[i].op != OP_NOP)
7946 ferr(&ops[i], "unreachable code\n");
7949 for (i = 0; i < g_eqcnt; i++) {
7950 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
7951 max_bp_offset = g_eqs[i].offset;
7954 if (fp->argc_stack < 0) {
7955 max_bp_offset = (max_bp_offset + 3) & ~3;
7956 fp->argc_stack = max_bp_offset / 4;
7957 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
7961 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
7962 fp->has_ret = has_ret;
7964 printf("// has_ret %d, regmask_dep %x\n",
7965 fp->has_ret, fp->regmask_dep);
7966 output_hdr_fp(stdout, fp, 1);
7967 if (IS(funcn, "sub_10007F72")) exit(1);
7970 gen_x_cleanup(opcnt);
7973 static void hg_fp_resolve_deps(struct func_prototype *fp)
7975 struct func_prototype fp_s;
7979 // this thing is recursive, so mark first..
7980 fp->dep_resolved = 1;
7982 for (i = 0; i < fp->dep_func_cnt; i++) {
7983 strcpy(fp_s.name, fp->dep_func[i].name);
7984 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7985 sizeof(hg_fp[0]), hg_fp_cmp_name);
7986 if (fp->dep_func[i].proto != NULL) {
7987 if (!fp->dep_func[i].proto->dep_resolved)
7988 hg_fp_resolve_deps(fp->dep_func[i].proto);
7990 dep = ~fp->dep_func[i].regmask_live
7991 & fp->dep_func[i].proto->regmask_dep;
7992 fp->regmask_dep |= dep;
7993 // printf("dep %s %s |= %x\n", fp->name,
7994 // fp->dep_func[i].name, dep);
7996 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
7997 fp->has_ret = fp->dep_func[i].proto->has_ret;
8002 // make all thiscall/edx arg functions referenced from .data fastcall
8003 static void do_func_refs_from_data(void)
8005 struct func_prototype *fp, fp_s;
8008 for (i = 0; i < hg_ref_cnt; i++) {
8009 strcpy(fp_s.name, hg_refs[i]);
8010 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8011 sizeof(hg_fp[0]), hg_fp_cmp_name);
8015 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8016 fp->regmask_dep |= mxCX | mxDX;
8020 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8023 const struct parsed_proto *pp;
8024 char *p, namebuf[NAMELEN];
8030 for (; count > 0; count--, fp++) {
8031 if (fp->has_ret == -1)
8032 fprintf(fout, "// ret unresolved\n");
8034 fprintf(fout, "// dep:");
8035 for (j = 0; j < fp->dep_func_cnt; j++) {
8036 fprintf(fout, " %s/", fp->dep_func[j].name);
8037 if (fp->dep_func[j].proto != NULL)
8038 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8039 fp->dep_func[j].proto->has_ret);
8041 fprintf(fout, "\n");
8044 p = strchr(fp->name, '@');
8046 memcpy(namebuf, fp->name, p - fp->name);
8047 namebuf[p - fp->name] = 0;
8055 pp = proto_parse(g_fhdr, name, 1);
8056 if (pp != NULL && pp->is_include)
8059 if (fp->pp != NULL) {
8060 // part of seed, output later
8064 regmask_dep = fp->regmask_dep;
8065 argc_normal = fp->argc_stack;
8067 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8068 (fp->has_ret ? "int" : "void"));
8069 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8070 && (regmask_dep & ~mxCX) == 0)
8072 fprintf(fout, "/*__thiscall*/ ");
8076 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8077 && (regmask_dep & ~(mxCX | mxDX)) == 0)
8079 fprintf(fout, " __fastcall ");
8080 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8086 else if (regmask_dep && !fp->is_stdcall) {
8087 fprintf(fout, "/*__usercall*/ ");
8089 else if (regmask_dep) {
8090 fprintf(fout, "/*__userpurge*/ ");
8092 else if (fp->is_stdcall)
8093 fprintf(fout, " __stdcall ");
8095 fprintf(fout, " __cdecl ");
8097 fprintf(fout, "%s(", name);
8100 for (j = 0; j < xSP; j++) {
8101 if (regmask_dep & (1 << j)) {
8104 fprintf(fout, ", ");
8106 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8108 fprintf(fout, "int");
8109 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8113 for (j = 0; j < argc_normal; j++) {
8116 fprintf(fout, ", ");
8117 if (fp->pp != NULL) {
8118 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8119 if (!fp->pp->arg[arg - 1].type.is_ptr)
8123 fprintf(fout, "int ");
8124 fprintf(fout, "a%d", arg);
8127 fprintf(fout, ");\n");
8131 static void output_hdr(FILE *fout)
8133 static const char *lmod_c_names[] = {
8134 [OPLM_UNSPEC] = "???",
8135 [OPLM_BYTE] = "uint8_t",
8136 [OPLM_WORD] = "uint16_t",
8137 [OPLM_DWORD] = "uint32_t",
8138 [OPLM_QWORD] = "uint64_t",
8140 const struct scanned_var *var;
8141 struct func_prototype *fp;
8142 char line[256] = { 0, };
8146 // add stuff from headers
8147 for (i = 0; i < pp_cache_size; i++) {
8148 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8149 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8151 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8152 fp = hg_fp_add(name);
8153 fp->pp = &pp_cache[i];
8154 fp->argc_stack = fp->pp->argc_stack;
8155 fp->is_stdcall = fp->pp->is_stdcall;
8156 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8157 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8161 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8162 for (i = 0; i < hg_fp_cnt; i++)
8163 hg_fp_resolve_deps(&hg_fp[i]);
8165 // adjust functions referenced from data segment
8166 do_func_refs_from_data();
8168 // note: messes up .proto ptr, don't use
8169 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8172 for (i = 0; i < hg_var_cnt; i++) {
8175 if (var->pp != NULL)
8178 else if (var->is_c_str)
8179 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8181 fprintf(fout, "extern %-8s %s;",
8182 lmod_c_names[var->lmod], var->name);
8185 fprintf(fout, " // seeded");
8186 fprintf(fout, "\n");
8189 fprintf(fout, "\n");
8191 // output function prototypes
8192 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8195 fprintf(fout, "\n// - seed -\n");
8198 while (fgets(line, sizeof(line), g_fhdr))
8199 fwrite(line, 1, strlen(line), fout);
8202 // '=' needs special treatment
8204 static char *next_word_s(char *w, size_t wsize, char *s)
8211 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8213 for (i = 1; i < wsize - 1; i++) {
8215 printf("warning: missing closing quote: \"%s\"\n", s);
8224 for (; i < wsize - 1; i++) {
8225 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8231 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8232 printf("warning: '%s' truncated\n", w);
8237 static int cmpstringp(const void *p1, const void *p2)
8239 return strcmp(*(char * const *)p1, *(char * const *)p2);
8242 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8247 if (strstr(p, "..."))
8248 // unable to determine, assume needed
8251 if (*p == '.') // .text, .data, ...
8252 // ref from other data or non-function -> no
8255 p2 = strpbrk(p, "+:\r\n\x18");
8258 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8259 // referenced from removed code
8265 static int ida_xrefs_show_need(FILE *fasm, char *p,
8266 char **rlist, int rlist_len)
8272 p = strrchr(p, ';');
8273 if (p != NULL && *p == ';' && IS_START(p + 2, "DATA XREF: ")) {
8275 if (is_xref_needed(p, rlist, rlist_len))
8282 if (!my_fgets(line, sizeof(line), fasm))
8284 // non-first line is always indented
8285 if (!my_isblank(line[0]))
8288 // should be no content, just comment
8293 p = strrchr(p, ';');
8295 // it's printed once, but no harm to check again
8296 if (IS_START(p, "DATA XREF: "))
8299 if (is_xref_needed(p, rlist, rlist_len)) {
8304 fseek(fasm, pos, SEEK_SET);
8308 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8310 struct scanned_var *var;
8311 char line[256] = { 0, };
8320 // skip to next data section
8321 while (my_fgets(line, sizeof(line), fasm))
8326 if (*p == 0 || *p == ';')
8329 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8330 if (*p == 0 || *p == ';')
8333 if (*p != 's' || !IS_START(p, "segment para public"))
8339 if (p == NULL || !IS_START(p, "segment para public"))
8343 if (!IS_START(p, "'DATA'"))
8347 while (my_fgets(line, sizeof(line), fasm))
8352 no_identifier = my_isblank(*p);
8355 if (*p == 0 || *p == ';')
8358 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8359 words[wordc][0] = 0;
8360 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8361 if (*p == 0 || *p == ';') {
8367 if (wordc == 2 && IS(words[1], "ends"))
8372 if (no_identifier) {
8373 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8374 hg_ref_add(words[2]);
8378 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8379 // when this starts, we don't need anything from this section
8383 // check refs comment(s)
8384 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8387 if ((hg_var_cnt & 0xff) == 0) {
8388 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8389 * (hg_var_cnt + 0x100));
8390 my_assert_not(hg_vars, NULL);
8391 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8394 var = &hg_vars[hg_var_cnt++];
8395 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8397 // maybe already in seed header?
8398 var->pp = proto_parse(g_fhdr, var->name, 1);
8399 if (var->pp != NULL) {
8400 if (var->pp->is_fptr) {
8401 var->lmod = OPLM_DWORD;
8404 else if (var->pp->is_func)
8406 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8407 aerr("unhandled C type '%s' for '%s'\n",
8408 var->pp->type.name, var->name);
8414 if (IS(words[1], "dd")) {
8415 var->lmod = OPLM_DWORD;
8416 if (wordc >= 4 && IS(words[2], "offset"))
8417 hg_ref_add(words[3]);
8419 else if (IS(words[1], "dw"))
8420 var->lmod = OPLM_WORD;
8421 else if (IS(words[1], "db")) {
8422 var->lmod = OPLM_BYTE;
8423 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8424 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8428 else if (IS(words[1], "dq"))
8429 var->lmod = OPLM_QWORD;
8430 //else if (IS(words[1], "dt"))
8432 aerr("type '%s' not known\n", words[1]);
8440 static void set_label(int i, const char *name)
8446 p = strchr(name, ':');
8450 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8451 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8452 g_labels[i] = realloc(g_labels[i], len + 1);
8453 my_assert_not(g_labels[i], NULL);
8454 memcpy(g_labels[i], name, len);
8455 g_labels[i][len] = 0;
8464 static struct chunk_item *func_chunks;
8465 static int func_chunk_cnt;
8466 static int func_chunk_alloc;
8468 static void add_func_chunk(FILE *fasm, const char *name, int line)
8470 if (func_chunk_cnt >= func_chunk_alloc) {
8471 func_chunk_alloc *= 2;
8472 func_chunks = realloc(func_chunks,
8473 func_chunk_alloc * sizeof(func_chunks[0]));
8474 my_assert_not(func_chunks, NULL);
8476 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8477 func_chunks[func_chunk_cnt].name = strdup(name);
8478 func_chunks[func_chunk_cnt].asmln = line;
8482 static int cmp_chunks(const void *p1, const void *p2)
8484 const struct chunk_item *c1 = p1, *c2 = p2;
8485 return strcmp(c1->name, c2->name);
8488 static void scan_ahead(FILE *fasm)
8498 oldpos = ftell(fasm);
8501 while (my_fgets(line, sizeof(line), fasm))
8512 // get rid of random tabs
8513 for (i = 0; line[i] != 0; i++)
8514 if (line[i] == '\t')
8517 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8520 next_word(words[0], sizeof(words[0]), p);
8521 if (words[0][0] == 0)
8522 aerr("missing name for func chunk?\n");
8524 add_func_chunk(fasm, words[0], asmln);
8526 else if (IS_START(p, "; sctend"))
8532 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8533 words[wordc][0] = 0;
8534 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8535 if (*p == 0 || *p == ';') {
8541 if (wordc == 2 && IS(words[1], "ends"))
8545 fseek(fasm, oldpos, SEEK_SET);
8549 int main(int argc, char *argv[])
8551 FILE *fout, *fasm, *frlist;
8552 struct parsed_data *pd = NULL;
8554 char **rlist = NULL;
8556 int rlist_alloc = 0;
8557 int func_chunks_used = 0;
8558 int func_chunks_sorted = 0;
8559 int func_chunk_i = -1;
8560 long func_chunk_ret = 0;
8561 int func_chunk_ret_ln = 0;
8562 int scanned_ahead = 0;
8564 char words[20][256];
8565 enum opr_lenmod lmod;
8566 char *sctproto = NULL;
8568 int pending_endp = 0;
8570 int skip_warned = 0;
8583 for (arg = 1; arg < argc; arg++) {
8584 if (IS(argv[arg], "-v"))
8586 else if (IS(argv[arg], "-rf"))
8587 g_allow_regfunc = 1;
8588 else if (IS(argv[arg], "-uc"))
8589 g_allow_user_icall = 1;
8590 else if (IS(argv[arg], "-m"))
8592 else if (IS(argv[arg], "-hdr"))
8593 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8598 if (argc < arg + 3) {
8599 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8600 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8602 " -hdr - header generation mode\n"
8603 " -rf - allow unannotated indirect calls\n"
8604 " -uc - allow ind. calls/refs to __usercall\n"
8605 " -m - allow multiple .text sections\n"
8606 "[rlist] is a file with function names to skip,"
8614 asmfn = argv[arg++];
8615 fasm = fopen(asmfn, "r");
8616 my_assert_not(fasm, NULL);
8618 hdrfn = argv[arg++];
8619 g_fhdr = fopen(hdrfn, "r");
8620 my_assert_not(g_fhdr, NULL);
8623 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8624 my_assert_not(rlist, NULL);
8625 // needs special handling..
8626 rlist[rlist_len++] = "__alloca_probe";
8628 func_chunk_alloc = 32;
8629 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8630 my_assert_not(func_chunks, NULL);
8632 memset(words, 0, sizeof(words));
8634 for (; arg < argc; arg++) {
8635 frlist = fopen(argv[arg], "r");
8636 my_assert_not(frlist, NULL);
8638 while (my_fgets(line, sizeof(line), frlist)) {
8640 if (*p == 0 || *p == ';')
8643 if (IS_START(p, "#if 0")
8644 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
8648 else if (IS_START(p, "#endif"))
8655 p = next_word(words[0], sizeof(words[0]), p);
8656 if (words[0][0] == 0)
8659 if (rlist_len >= rlist_alloc) {
8660 rlist_alloc = rlist_alloc * 2 + 64;
8661 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
8662 my_assert_not(rlist, NULL);
8664 rlist[rlist_len++] = strdup(words[0]);
8673 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
8675 fout = fopen(argv[arg_out], "w");
8676 my_assert_not(fout, NULL);
8679 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
8680 my_assert_not(g_eqs, NULL);
8682 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
8683 g_label_refs[i].i = -1;
8684 g_label_refs[i].next = NULL;
8688 scan_variables(fasm, rlist, rlist_len);
8690 while (my_fgets(line, sizeof(line), fasm))
8699 // get rid of random tabs
8700 for (i = 0; line[i] != 0; i++)
8701 if (line[i] == '\t')
8706 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
8707 goto do_pending_endp; // eww..
8709 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
8711 static const char *attrs[] = {
8720 // parse IDA's attribute-list comment
8721 g_ida_func_attr = 0;
8724 for (; *p != 0; p = sskip(p)) {
8725 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8726 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8727 g_ida_func_attr |= 1 << i;
8728 p += strlen(attrs[i]);
8732 if (i == ARRAY_SIZE(attrs)) {
8733 anote("unparsed IDA attr: %s\n", p);
8736 if (IS(attrs[i], "fpd=")) {
8737 p = next_word(words[0], sizeof(words[0]), p);
8742 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
8744 static const char *attrs[] = {
8749 // parse manual attribute-list comment
8750 g_sct_func_attr = 0;
8753 for (; *p != 0; p = sskip(p)) {
8754 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8755 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8756 g_sct_func_attr |= 1 << i;
8757 p += strlen(attrs[i]);
8764 // clear_sf=start,len (in dwords)
8765 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
8766 &g_stack_clear_len, &j);
8768 // clear_regmask=<mask>
8769 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
8771 anote("unparsed attr value: %s\n", p);
8776 else if (i == ARRAY_SIZE(attrs)) {
8777 anote("unparsed sct attr: %s\n", p);
8782 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8785 next_word(words[0], sizeof(words[0]), p);
8786 if (words[0][0] == 0)
8787 aerr("missing name for func chunk?\n");
8789 if (!scanned_ahead) {
8790 add_func_chunk(fasm, words[0], asmln);
8791 func_chunks_sorted = 0;
8794 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
8796 if (func_chunk_i >= 0) {
8797 if (func_chunk_i < func_chunk_cnt
8798 && IS(func_chunks[func_chunk_i].name, g_func))
8800 // move on to next chunk
8801 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8803 aerr("seek failed for '%s' chunk #%d\n",
8804 g_func, func_chunk_i);
8805 asmln = func_chunks[func_chunk_i].asmln;
8809 if (func_chunk_ret == 0)
8810 aerr("no return from chunk?\n");
8811 fseek(fasm, func_chunk_ret, SEEK_SET);
8812 asmln = func_chunk_ret_ln;
8818 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
8819 func_chunks_used = 1;
8821 if (IS_START(g_func, "sub_")) {
8822 unsigned long addr = strtoul(p, NULL, 16);
8823 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
8824 if (addr > f_addr && !scanned_ahead) {
8825 //anote("scan_ahead caused by '%s', addr %lx\n",
8829 func_chunks_sorted = 0;
8837 for (i = wordc; i < ARRAY_SIZE(words); i++)
8839 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8840 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8841 if (*p == 0 || *p == ';') {
8846 if (*p != 0 && *p != ';')
8847 aerr("too many words\n");
8849 // alow asm patches in comments
8851 if (IS_START(p, "; sctpatch:")) {
8853 if (*p == 0 || *p == ';')
8855 goto parse_words; // lame
8857 if (IS_START(p, "; sctproto:")) {
8858 sctproto = strdup(p + 11);
8860 else if (IS_START(p, "; sctend")) {
8869 awarn("wordc == 0?\n");
8873 // don't care about this:
8874 if (words[0][0] == '.'
8875 || IS(words[0], "include")
8876 || IS(words[0], "assume") || IS(words[1], "segment")
8877 || IS(words[0], "align"))
8883 // do delayed endp processing to collect switch jumptables
8885 if (in_func && !g_skip_func && !end && wordc >= 2
8886 && ((words[0][0] == 'd' && words[0][2] == 0)
8887 || (words[1][0] == 'd' && words[1][2] == 0)))
8890 if (words[1][0] == 'd' && words[1][2] == 0) {
8892 if (g_func_pd_cnt >= pd_alloc) {
8893 pd_alloc = pd_alloc * 2 + 16;
8894 g_func_pd = realloc(g_func_pd,
8895 sizeof(g_func_pd[0]) * pd_alloc);
8896 my_assert_not(g_func_pd, NULL);
8898 pd = &g_func_pd[g_func_pd_cnt];
8900 memset(pd, 0, sizeof(*pd));
8901 strcpy(pd->label, words[0]);
8902 pd->type = OPT_CONST;
8903 pd->lmod = lmod_from_directive(words[1]);
8909 anote("skipping alignment byte?\n");
8912 lmod = lmod_from_directive(words[0]);
8913 if (lmod != pd->lmod)
8914 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
8917 if (pd->count_alloc < pd->count + wordc) {
8918 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
8919 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
8920 my_assert_not(pd->d, NULL);
8922 for (; i < wordc; i++) {
8923 if (IS(words[i], "offset")) {
8924 pd->type = OPT_OFFSET;
8927 p = strchr(words[i], ',');
8930 if (pd->type == OPT_OFFSET)
8931 pd->d[pd->count].u.label = strdup(words[i]);
8933 pd->d[pd->count].u.val = parse_number(words[i]);
8934 pd->d[pd->count].bt_i = -1;
8940 if (in_func && !g_skip_func) {
8942 gen_hdr(g_func, pi);
8944 gen_func(fout, g_fhdr, g_func, pi);
8949 g_ida_func_attr = 0;
8950 g_sct_func_attr = 0;
8951 g_stack_clear_start = 0;
8952 g_stack_clear_len = 0;
8957 func_chunks_used = 0;
8960 memset(&ops, 0, pi * sizeof(ops[0]));
8965 for (i = 0; i < g_func_pd_cnt; i++) {
8967 if (pd->type == OPT_OFFSET) {
8968 for (j = 0; j < pd->count; j++)
8969 free(pd->d[j].u.label);
8984 if (IS(words[1], "proc")) {
8986 aerr("proc '%s' while in_func '%s'?\n",
8989 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8991 strcpy(g_func, words[0]);
8992 set_label(0, words[0]);
8997 if (IS(words[1], "endp"))
9000 aerr("endp '%s' while not in_func?\n", words[0]);
9001 if (!IS(g_func, words[0]))
9002 aerr("endp '%s' while in_func '%s'?\n",
9005 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9006 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
9012 if (!g_skip_func && func_chunks_used) {
9013 // start processing chunks
9014 struct chunk_item *ci, key = { g_func, 0 };
9016 func_chunk_ret = ftell(fasm);
9017 func_chunk_ret_ln = asmln;
9018 if (!func_chunks_sorted) {
9019 qsort(func_chunks, func_chunk_cnt,
9020 sizeof(func_chunks[0]), cmp_chunks);
9021 func_chunks_sorted = 1;
9023 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9024 sizeof(func_chunks[0]), cmp_chunks);
9026 aerr("'%s' needs chunks, but none found\n", g_func);
9027 func_chunk_i = ci - func_chunks;
9028 for (; func_chunk_i > 0; func_chunk_i--)
9029 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9032 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9034 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9035 asmln = func_chunks[func_chunk_i].asmln;
9043 if (wordc == 2 && IS(words[1], "ends")) {
9047 goto do_pending_endp;
9051 // scan for next text segment
9052 while (my_fgets(line, sizeof(line), fasm)) {
9055 if (*p == 0 || *p == ';')
9058 if (strstr(p, "segment para public 'CODE' use32"))
9065 p = strchr(words[0], ':');
9067 set_label(pi, words[0]);
9071 if (!in_func || g_skip_func) {
9072 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9074 anote("skipping from '%s'\n", g_labels[pi]);
9078 g_labels[pi] = NULL;
9082 if (wordc > 1 && IS(words[1], "="))
9085 aerr("unhandled equ, wc=%d\n", wordc);
9086 if (g_eqcnt >= eq_alloc) {
9088 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9089 my_assert_not(g_eqs, NULL);
9092 len = strlen(words[0]);
9093 if (len > sizeof(g_eqs[0].name) - 1)
9094 aerr("equ name too long: %d\n", len);
9095 strcpy(g_eqs[g_eqcnt].name, words[0]);
9097 if (!IS(words[3], "ptr"))
9098 aerr("unhandled equ\n");
9099 if (IS(words[2], "dword"))
9100 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9101 else if (IS(words[2], "word"))
9102 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9103 else if (IS(words[2], "byte"))
9104 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9105 else if (IS(words[2], "qword"))
9106 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9108 aerr("bad lmod: '%s'\n", words[2]);
9110 g_eqs[g_eqcnt].offset = parse_number(words[4]);
9115 if (pi >= ARRAY_SIZE(ops))
9116 aerr("too many ops\n");
9118 parse_op(&ops[pi], words, wordc);
9120 ops[pi].datap = sctproto;
9135 // vim:ts=2:shiftwidth=2:expandtab