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
174 // must be sorted (larger len must be further in enum)
183 #define MAX_EXITS 128
185 #define MAX_OPERANDS 3
188 #define OPR_INIT(type_, lmod_, reg_) \
189 { type_, lmod_, reg_, }
193 enum opr_lenmod lmod;
195 unsigned int is_ptr:1; // pointer in C
196 unsigned int is_array:1; // array in C
197 unsigned int type_from_var:1; // .. in header, sometimes wrong
198 unsigned int size_mismatch:1; // type override differs from C
199 unsigned int size_lt:1; // type override is larger than C
200 unsigned int had_ds:1; // had ds: prefix
201 const struct parsed_proto *pp; // for OPT_LABEL
208 struct parsed_opr operand[MAX_OPERANDS];
211 unsigned char pfo_inv;
212 unsigned char operand_cnt;
213 unsigned char p_argnum; // arg push: altered before call arg #
214 unsigned char p_arggrp; // arg push: arg group # for above
215 unsigned char p_argpass;// arg push: arg of host func
216 short p_argnext;// arg push: same arg pushed elsewhere or -1
217 int regmask_src; // all referensed regs
219 int pfomask; // flagop: parsed_flag_op that can't be delayed
220 int cc_scratch; // scratch storage during analysis
221 int bt_i; // branch target for branches
222 struct parsed_data *btj;// branch targets for jumptables
223 struct parsed_proto *pp;// parsed_proto for OP_CALL
229 // on start: function/data type hint (sctproto)
231 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
232 // OP_PUSH - points to OP_POP in complex push/pop graph
233 // OP_POP - points to OP_PUSH in simple push/pop pair
234 // OP_FCOM - needed_status_word_bits | (is_z_check << 16)
238 enum opr_lenmod lmod;
245 enum opr_lenmod lmod;
259 struct label_ref *next;
263 IDAFA_BP_FRAME = (1 << 0),
264 IDAFA_LIB_FUNC = (1 << 1),
265 IDAFA_STATIC = (1 << 2),
266 IDAFA_NORETURN = (1 << 3),
267 IDAFA_THUNK = (1 << 4),
268 IDAFA_FPD = (1 << 5),
272 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
273 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
286 // note: limited to 32k due to p_argnext
288 #define MAX_ARG_GRP 2
290 static struct parsed_op ops[MAX_OPS];
291 static struct parsed_equ *g_eqs;
293 static char *g_labels[MAX_OPS];
294 static struct label_ref g_label_refs[MAX_OPS];
295 static const struct parsed_proto *g_func_pp;
296 static struct parsed_data *g_func_pd;
297 static int g_func_pd_cnt;
298 static int g_func_lmods;
299 static char g_func[256];
300 static char g_comment[256];
301 static int g_bp_frame;
302 static int g_sp_frame;
303 static int g_stack_frame_used;
304 static int g_stack_fsz;
305 static int g_ida_func_attr;
306 static int g_sct_func_attr;
307 static int g_stack_clear_start; // in dwords
308 static int g_stack_clear_len;
309 static int g_regmask_init;
310 static int g_skip_func;
311 static int g_allow_regfunc;
312 static int g_allow_user_icall;
313 static int g_quiet_pp;
314 static int g_header_mode;
316 #define ferr(op_, fmt, ...) do { \
317 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
318 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
322 #define fnote(op_, fmt, ...) \
323 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
324 dump_op(op_), ##__VA_ARGS__)
326 #define ferr_assert(op_, cond) do { \
327 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
330 const char *regs_r32[] = {
331 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
332 // not r32, but list here for easy parsing and printing
333 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
334 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
336 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
337 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
338 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
344 xMM0, xMM1, xMM2, xMM3, // mmx
345 xMM4, xMM5, xMM6, xMM7,
346 xST0, xST1, xST2, xST3, // x87
347 xST4, xST5, xST6, xST7,
350 #define mxAX (1 << xAX)
351 #define mxCX (1 << xCX)
352 #define mxDX (1 << xDX)
353 #define mxST0 (1 << xST0)
354 #define mxST1 (1 << xST1)
355 #define mxST1_0 (mxST1 | mxST0)
356 #define mxST7_2 (0xfc << xST0)
357 #define mxSTa (0xff << xST0)
359 // possible basic comparison types (without inversion)
360 enum parsed_flag_op {
364 PFO_BE, // 6 CF=1||ZF=1
368 PFO_LE, // e ZF=1||SF!=OF
371 #define PFOB_O (1 << PFO_O)
372 #define PFOB_C (1 << PFO_C)
373 #define PFOB_Z (1 << PFO_Z)
374 #define PFOB_S (1 << PFO_S)
376 static const char *parsed_flag_op_names[] = {
377 "o", "c", "z", "be", "s", "p", "l", "le"
380 static int char_array_i(const char *array[], size_t len, const char *s)
384 for (i = 0; i < len; i++)
391 static void printf_number(char *buf, size_t buf_size,
392 unsigned long number)
394 // output in C-friendly form
395 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
398 static int check_segment_prefix(const char *s)
400 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
414 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
418 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
420 *reg_lmod = OPLM_QWORD;
424 *reg_lmod = OPLM_DWORD;
427 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
429 *reg_lmod = OPLM_WORD;
432 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
434 *reg_lmod = OPLM_BYTE;
437 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
439 *reg_lmod = OPLM_BYTE;
446 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
448 enum opr_lenmod lmod;
461 while (my_isblank(*s))
463 for (; my_issep(*s); d++, s++)
465 while (my_isblank(*s))
469 // skip '?s:' prefixes
470 if (check_segment_prefix(s))
473 s = next_idt(w, sizeof(w), s);
478 reg = parse_reg(&lmod, w);
480 *regmask |= 1 << reg;
484 if ('0' <= w[0] && w[0] <= '9') {
485 number = parse_number(w);
486 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
490 // probably some label/identifier - pass
493 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
497 strcpy(name, cvtbuf);
502 static int is_reg_in_str(const char *s)
506 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
509 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
510 if (!strncmp(s, regs_r32[i], 3))
516 static const char *parse_stack_el(const char *name, char *extra_reg,
517 int *base_val, int early_try)
519 const char *p, *p2, *s;
525 if (g_bp_frame || early_try)
528 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
530 if (extra_reg != NULL) {
531 strncpy(extra_reg, name, 3);
536 if (IS_START(p, "ebp+")) {
540 if (p2 != NULL && is_reg_in_str(p)) {
541 if (extra_reg != NULL) {
542 strncpy(extra_reg, p, p2 - p);
543 extra_reg[p2 - p] = 0;
548 if (!('0' <= *p && *p <= '9'))
555 if (!IS_START(name, "esp+"))
561 if (is_reg_in_str(s)) {
562 if (extra_reg != NULL) {
563 strncpy(extra_reg, s, p - s);
564 extra_reg[p - s] = 0;
569 aerr("%s IDA stackvar not set?\n", __func__);
571 if (!('0' <= *s && *s <= '9')) {
572 aerr("%s IDA stackvar offset not set?\n", __func__);
575 if (s[0] == '0' && s[1] == 'x')
578 if (len < sizeof(buf) - 1) {
579 strncpy(buf, s, len);
581 val = strtol(buf, &endp, 16);
582 if (val == 0 || *endp != 0) {
583 aerr("%s num parse fail for '%s'\n", __func__, buf);
592 if ('0' <= *p && *p <= '9')
595 if (base_val != NULL)
600 static int guess_lmod_from_name(struct parsed_opr *opr)
602 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
603 opr->lmod = OPLM_DWORD;
606 if (IS_START(opr->name, "word_")) {
607 opr->lmod = OPLM_WORD;
610 if (IS_START(opr->name, "byte_")) {
611 opr->lmod = OPLM_BYTE;
614 if (IS_START(opr->name, "qword_")) {
615 opr->lmod = OPLM_QWORD;
621 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
622 const struct parsed_type *c_type)
624 static const char *qword_types[] = {
625 "uint64_t", "int64_t", "__int64",
627 static const char *dword_types[] = {
628 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
629 "WPARAM", "LPARAM", "UINT", "__int32",
630 "LONG", "HIMC", "BOOL", "size_t",
633 static const char *word_types[] = {
634 "uint16_t", "int16_t", "_WORD", "WORD",
635 "unsigned __int16", "__int16",
637 static const char *byte_types[] = {
638 "uint8_t", "int8_t", "char",
639 "unsigned __int8", "__int8", "BYTE", "_BYTE",
641 // structures.. deal the same as with _UNKNOWN for now
647 if (c_type->is_ptr) {
652 n = skip_type_mod(c_type->name);
654 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
655 if (IS(n, dword_types[i])) {
661 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
662 if (IS(n, word_types[i])) {
668 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
669 if (IS(n, byte_types[i])) {
675 for (i = 0; i < ARRAY_SIZE(qword_types); i++) {
676 if (IS(n, qword_types[i])) {
685 static char *default_cast_to(char *buf, size_t buf_size,
686 struct parsed_opr *opr)
690 if (!opr->is_ptr || strchr(opr->name, '['))
692 if (opr->pp == NULL || opr->pp->type.name == NULL
695 snprintf(buf, buf_size, "%s", "(void *)");
699 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
703 static enum opr_type lmod_from_directive(const char *d)
707 else if (IS(d, "dw"))
709 else if (IS(d, "db"))
712 aerr("unhandled directive: '%s'\n", d);
716 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
722 *regmask |= 1 << reg;
725 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
728 static int parse_operand(struct parsed_opr *opr,
729 int *regmask, int *regmask_indirect,
730 char words[16][256], int wordc, int w, unsigned int op_flags)
732 const struct parsed_proto *pp = NULL;
733 enum opr_lenmod tmplmod;
734 unsigned long number;
742 aerr("parse_operand w %d, wordc %d\n", w, wordc);
746 for (i = w; i < wordc; i++) {
747 len = strlen(words[i]);
748 if (words[i][len - 1] == ',') {
749 words[i][len - 1] = 0;
755 wordc_in = wordc - w;
757 if ((op_flags & OPF_JMP) && wordc_in > 0
758 && !('0' <= words[w][0] && words[w][0] <= '9'))
760 const char *label = NULL;
762 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
763 && IS(words[w + 1], "ptr"))
764 label = words[w + 2];
765 else if (wordc_in == 2 && IS(words[w], "short"))
766 label = words[w + 1];
767 else if (wordc_in == 1
768 && strchr(words[w], '[') == NULL
769 && parse_reg(&tmplmod, words[w]) < 0)
773 opr->type = OPT_LABEL;
774 ret = check_segment_prefix(label);
777 aerr("fs/gs used\n");
781 strcpy(opr->name, label);
787 if (IS(words[w + 1], "ptr")) {
788 if (IS(words[w], "dword"))
789 opr->lmod = OPLM_DWORD;
790 else if (IS(words[w], "word"))
791 opr->lmod = OPLM_WORD;
792 else if (IS(words[w], "byte"))
793 opr->lmod = OPLM_BYTE;
794 else if (IS(words[w], "qword"))
795 opr->lmod = OPLM_QWORD;
797 aerr("type parsing failed\n");
799 wordc_in = wordc - w;
804 if (IS(words[w], "offset")) {
805 opr->type = OPT_OFFSET;
806 opr->lmod = OPLM_DWORD;
807 strcpy(opr->name, words[w + 1]);
808 pp = proto_parse(g_fhdr, opr->name, 1);
811 if (IS(words[w], "(offset")) {
812 p = strchr(words[w + 1], ')');
814 aerr("parse of bracketed offset failed\n");
816 opr->type = OPT_OFFSET;
817 strcpy(opr->name, words[w + 1]);
823 aerr("parse_operand 1 word expected\n");
825 ret = check_segment_prefix(words[w]);
828 aerr("fs/gs used\n");
830 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
832 strcpy(opr->name, words[w]);
834 if (words[w][0] == '[') {
835 opr->type = OPT_REGMEM;
836 ret = sscanf(words[w], "[%[^]]]", opr->name);
838 aerr("[] parse failure\n");
840 parse_indmode(opr->name, regmask_indirect, 1);
841 if (opr->lmod == OPLM_UNSPEC
842 && parse_stack_el(opr->name, NULL, NULL, 1))
845 struct parsed_equ *eq =
846 equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
848 opr->lmod = eq->lmod;
850 // might be unaligned access
851 g_func_lmods |= 1 << OPLM_BYTE;
855 else if (strchr(words[w], '[')) {
857 p = strchr(words[w], '[');
858 opr->type = OPT_REGMEM;
859 parse_indmode(p, regmask_indirect, 0);
860 strncpy(buf, words[w], p - words[w]);
861 buf[p - words[w]] = 0;
862 pp = proto_parse(g_fhdr, buf, 1);
865 else if (('0' <= words[w][0] && words[w][0] <= '9')
866 || words[w][0] == '-')
868 number = parse_number(words[w]);
869 opr->type = OPT_CONST;
871 printf_number(opr->name, sizeof(opr->name), number);
875 ret = parse_reg(&tmplmod, opr->name);
877 setup_reg_opr(opr, ret, tmplmod, regmask);
881 // most likely var in data segment
882 opr->type = OPT_LABEL;
883 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
887 if (pp->is_fptr || pp->is_func) {
888 opr->lmod = OPLM_DWORD;
892 tmplmod = OPLM_UNSPEC;
893 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
894 anote("unhandled C type '%s' for '%s'\n",
895 pp->type.name, opr->name);
897 if (opr->lmod == OPLM_UNSPEC) {
899 opr->type_from_var = 1;
901 else if (opr->lmod != tmplmod) {
902 opr->size_mismatch = 1;
903 if (tmplmod < opr->lmod)
906 opr->is_ptr = pp->type.is_ptr;
908 opr->is_array = pp->type.is_array;
912 if (opr->lmod == OPLM_UNSPEC)
913 guess_lmod_from_name(opr);
917 static const struct {
922 { "repe", OPF_REP|OPF_REPZ },
923 { "repz", OPF_REP|OPF_REPZ },
924 { "repne", OPF_REP|OPF_REPNZ },
925 { "repnz", OPF_REP|OPF_REPNZ },
926 { "lock", OPF_LOCK }, // ignored for now..
929 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
931 static const struct {
934 unsigned short minopr;
935 unsigned short maxopr;
938 unsigned char pfo_inv;
940 { "nop", OP_NOP, 0, 0, 0 },
941 { "push", OP_PUSH, 1, 1, 0 },
942 { "pop", OP_POP, 1, 1, OPF_DATA },
943 { "pusha",OP_PUSHA, 0, 0, 0 },
944 { "popa", OP_POPA, 0, 0, OPF_DATA },
945 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
946 { "mov" , OP_MOV, 2, 2, OPF_DATA },
947 { "lea", OP_LEA, 2, 2, OPF_DATA },
948 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
949 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
950 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
951 { "not", OP_NOT, 1, 1, OPF_DATA },
952 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
953 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
954 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
955 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
956 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
957 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
958 { "stosb",OP_STOS, 0, 0, OPF_DATA },
959 { "stosw",OP_STOS, 0, 0, OPF_DATA },
960 { "stosd",OP_STOS, 0, 0, OPF_DATA },
961 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
962 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
963 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
964 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
965 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
966 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
967 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
968 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
969 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
970 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
971 { "cld", OP_CLD, 0, 0, OPF_DATA },
972 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
973 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
974 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
975 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
976 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
977 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
978 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
979 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
980 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
981 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
982 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
983 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
984 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
985 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
986 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
987 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
988 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
989 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
990 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
991 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
992 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
993 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
994 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
995 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
996 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
997 { "test", OP_TEST, 2, 2, OPF_FLAGS },
998 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
999 { "retn", OP_RET, 0, 1, OPF_TAIL },
1000 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
1001 { "jmp", OP_JMP, 1, 1, OPF_JMP },
1002 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
1003 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
1004 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
1005 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
1006 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
1007 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
1008 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
1009 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1010 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1011 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
1012 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
1013 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
1014 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
1015 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1016 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1017 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1018 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1019 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1020 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1021 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1022 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1023 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1024 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1025 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1026 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1027 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1028 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1029 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1030 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1031 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1032 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1033 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1034 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1035 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1036 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1037 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1038 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1039 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1040 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1041 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1042 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1043 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1044 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1045 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1046 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1047 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1048 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1049 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1050 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1051 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1052 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1053 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1054 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1055 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1056 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1057 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1058 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1059 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1060 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1061 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1063 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1064 { "fild", OP_FILD, 1, 1, OPF_FPUSH },
1065 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1066 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1067 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1068 { "fst", OP_FST, 1, 1, 0 },
1069 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1070 { "fist", OP_FIST, 1, 1, 0 },
1071 { "fistp", OP_FIST, 1, 1, OPF_FPOP },
1072 { "fadd", OP_FADD, 0, 2, 0 },
1073 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1074 { "fdiv", OP_FDIV, 0, 2, 0 },
1075 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1076 { "fmul", OP_FMUL, 0, 2, 0 },
1077 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1078 { "fsub", OP_FSUB, 0, 2, 0 },
1079 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1080 { "fdivr", OP_FDIVR, 0, 2, 0 },
1081 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1082 { "fsubr", OP_FSUBR, 0, 2, 0 },
1083 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1084 { "fiadd", OP_FIADD, 1, 1, 0 },
1085 { "fidiv", OP_FIDIV, 1, 1, 0 },
1086 { "fimul", OP_FIMUL, 1, 1, 0 },
1087 { "fisub", OP_FISUB, 1, 1, 0 },
1088 { "fidivr", OP_FIDIVR, 1, 1, 0 },
1089 { "fisubr", OP_FISUBR, 1, 1, 0 },
1090 { "fcom", OP_FCOM, 0, 1, 0 },
1091 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1092 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1093 { "fchs", OP_FCHS, 0, 0, 0 },
1094 { "fcos", OP_FCOS, 0, 0, 0 },
1095 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1096 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1097 { "fsin", OP_FSIN, 0, 0, 0 },
1098 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1099 { "fxch", OP_FXCH, 1, 1, 0 },
1100 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1102 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1103 { "movq", OP_MOV, 2, 2, OPF_DATA },
1104 // pseudo-ops for lib calls
1105 { "_allshl",OPP_ALLSHL },
1106 { "_allshr",OPP_ALLSHR },
1107 { "_ftol", OPP_FTOL },
1108 { "_CIpow", OPP_CIPOW },
1113 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1115 enum opr_lenmod lmod = OPLM_UNSPEC;
1116 int prefix_flags = 0;
1124 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1125 if (IS(words[w], pref_table[i].name)) {
1126 prefix_flags = pref_table[i].flags;
1133 aerr("lone prefix: '%s'\n", words[0]);
1138 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1139 if (IS(words[w], op_table[i].name))
1143 if (i == ARRAY_SIZE(op_table)) {
1145 aerr("unhandled op: '%s'\n", words[0]);
1150 op->op = op_table[i].op;
1151 op->flags = op_table[i].flags | prefix_flags;
1152 op->pfo = op_table[i].pfo;
1153 op->pfo_inv = op_table[i].pfo_inv;
1154 op->regmask_src = op->regmask_dst = 0;
1157 if (op->op == OP_UD2)
1160 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1161 if (opr >= op_table[i].minopr && w >= wordc)
1164 regmask = regmask_ind = 0;
1165 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1166 words, wordc, w, op->flags);
1168 if (opr == 0 && (op->flags & OPF_DATA))
1169 op->regmask_dst = regmask;
1171 op->regmask_src |= regmask;
1172 op->regmask_src |= regmask_ind;
1174 if (op->operand[opr].lmod != OPLM_UNSPEC)
1175 g_func_lmods |= 1 << op->operand[opr].lmod;
1179 aerr("parse_op %s incomplete: %d/%d\n",
1180 words[0], w, wordc);
1183 op->operand_cnt = opr;
1184 if (!strncmp(op_table[i].name, "set", 3))
1185 op->operand[0].lmod = OPLM_BYTE;
1188 // first operand is not dst
1191 op->regmask_src |= op->regmask_dst;
1192 op->regmask_dst = 0;
1195 // first operand is src too
1208 op->regmask_src |= op->regmask_dst;
1213 op->regmask_src |= op->regmask_dst;
1214 op->regmask_dst |= op->regmask_src;
1220 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1221 && op->operand[0].lmod == op->operand[1].lmod
1222 && op->operand[0].reg == op->operand[1].reg
1223 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1225 op->regmask_src = 0;
1228 op->regmask_src |= op->regmask_dst;
1231 // ops with implicit argumets
1233 op->operand_cnt = 2;
1234 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1235 op->regmask_dst = op->regmask_src;
1236 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1240 op->operand_cnt = 2;
1241 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1242 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1248 if (words[op_w][4] == 'b')
1250 else if (words[op_w][4] == 'w')
1252 else if (words[op_w][4] == 'd')
1255 op->regmask_src = 0;
1256 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1257 OPLM_DWORD, &op->regmask_src);
1258 op->regmask_dst = op->regmask_src;
1259 setup_reg_opr(&op->operand[j++], xAX, lmod,
1260 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1261 if (op->flags & OPF_REP) {
1262 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1263 op->regmask_dst |= 1 << xCX;
1265 op->operand_cnt = j;
1270 if (words[op_w][4] == 'b')
1272 else if (words[op_w][4] == 'w')
1274 else if (words[op_w][4] == 'd')
1277 op->regmask_src = 0;
1278 // note: lmod is not correct, don't have where to place it
1279 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1280 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1281 if (op->flags & OPF_REP)
1282 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1283 op->operand_cnt = j;
1284 op->regmask_dst = op->regmask_src;
1288 op->regmask_dst = 1 << xCX;
1291 op->operand_cnt = 2;
1292 op->regmask_src = 1 << xCX;
1293 op->operand[1].type = OPT_REG;
1294 op->operand[1].reg = xCX;
1295 op->operand[1].lmod = OPLM_DWORD;
1299 if (op->operand_cnt == 2) {
1300 if (op->operand[0].type != OPT_REG)
1301 aerr("reg expected\n");
1302 op->regmask_src |= 1 << op->operand[0].reg;
1304 if (op->operand_cnt != 1)
1309 op->regmask_src |= op->regmask_dst;
1310 op->regmask_dst = (1 << xDX) | (1 << xAX);
1311 if (op->operand[0].lmod == OPLM_UNSPEC)
1312 op->operand[0].lmod = OPLM_DWORD;
1317 // we could set up operands for edx:eax, but there is no real need to
1318 // (see is_opr_modified())
1319 op->regmask_src |= op->regmask_dst;
1320 op->regmask_dst = (1 << xDX) | (1 << xAX);
1321 if (op->operand[0].lmod == OPLM_UNSPEC)
1322 op->operand[0].lmod = OPLM_DWORD;
1330 op->regmask_src |= op->regmask_dst;
1331 if (op->operand[1].lmod == OPLM_UNSPEC)
1332 op->operand[1].lmod = OPLM_BYTE;
1337 op->regmask_src |= op->regmask_dst;
1338 if (op->operand[2].lmod == OPLM_UNSPEC)
1339 op->operand[2].lmod = OPLM_BYTE;
1343 op->regmask_src |= op->regmask_dst;
1344 op->regmask_dst = 0;
1345 if (op->operand[0].lmod == OPLM_UNSPEC
1346 && (op->operand[0].type == OPT_CONST
1347 || op->operand[0].type == OPT_OFFSET
1348 || op->operand[0].type == OPT_LABEL))
1349 op->operand[0].lmod = OPLM_DWORD;
1355 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1356 && op->operand[0].lmod == op->operand[1].lmod
1357 && op->operand[0].reg == op->operand[1].reg
1358 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1360 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1361 op->regmask_src = op->regmask_dst = 0;
1366 if (op->operand[0].type == OPT_REG
1367 && op->operand[1].type == OPT_REGMEM)
1370 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1371 if (IS(buf, op->operand[1].name))
1372 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1377 // trashed regs must be explicitly detected later
1378 op->regmask_dst = 0;
1382 op->regmask_dst = (1 << xBP) | (1 << xSP);
1383 op->regmask_src = 1 << xBP;
1388 op->regmask_dst |= mxST0;
1392 op->regmask_dst |= mxST0;
1393 if (IS(words[op_w] + 3, "1"))
1394 op->operand[0].val = X87_CONST_1;
1395 else if (IS(words[op_w] + 3, "ln2"))
1396 op->operand[0].val = X87_CONST_LN2;
1397 else if (IS(words[op_w] + 3, "z"))
1398 op->operand[0].val = X87_CONST_Z;
1405 op->regmask_src |= mxST0;
1414 op->regmask_src |= mxST0;
1415 if (op->operand_cnt == 2)
1416 op->regmask_src |= op->regmask_dst;
1417 else if (op->operand_cnt == 1) {
1418 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1419 op->operand[0].type = OPT_REG;
1420 op->operand[0].lmod = OPLM_QWORD;
1421 op->operand[0].reg = xST0;
1422 op->regmask_dst |= mxST0;
1425 // IDA doesn't use this
1426 aerr("no operands?\n");
1440 op->regmask_src |= mxST0;
1441 op->regmask_dst |= mxST0;
1446 op->regmask_src |= mxST0 | mxST1;
1447 op->regmask_dst |= mxST0;
1455 op->regmask_src |= mxST0;
1462 if (op->operand[0].type == OPT_REG
1463 && op->operand[1].type == OPT_CONST)
1465 struct parsed_opr *op1 = &op->operand[1];
1466 if ((op->op == OP_AND && op1->val == 0)
1469 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1470 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1472 op->regmask_src = 0;
1477 static const char *op_name(struct parsed_op *po)
1479 static char buf[16];
1483 if (po->op == OP_JCC || po->op == OP_SCC) {
1485 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1488 strcpy(p, parsed_flag_op_names[po->pfo]);
1492 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1493 if (op_table[i].op == po->op)
1494 return op_table[i].name;
1500 static const char *dump_op(struct parsed_op *po)
1502 static char out[128];
1509 snprintf(out, sizeof(out), "%s", op_name(po));
1510 for (i = 0; i < po->operand_cnt; i++) {
1514 snprintf(p, sizeof(out) - (p - out),
1515 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1516 po->operand[i].name);
1522 static const char *lmod_type_u(struct parsed_op *po,
1523 enum opr_lenmod lmod)
1535 ferr(po, "invalid lmod: %d\n", lmod);
1536 return "(_invalid_)";
1540 static const char *lmod_cast_u(struct parsed_op *po,
1541 enum opr_lenmod lmod)
1553 ferr(po, "invalid lmod: %d\n", lmod);
1554 return "(_invalid_)";
1558 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1559 enum opr_lenmod lmod)
1571 ferr(po, "invalid lmod: %d\n", lmod);
1572 return "(_invalid_)";
1576 static const char *lmod_cast_s(struct parsed_op *po,
1577 enum opr_lenmod lmod)
1589 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1590 return "(_invalid_)";
1594 static const char *lmod_cast(struct parsed_op *po,
1595 enum opr_lenmod lmod, int is_signed)
1598 lmod_cast_s(po, lmod) :
1599 lmod_cast_u(po, lmod);
1602 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1614 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1619 static const char *opr_name(struct parsed_op *po, int opr_num)
1621 if (opr_num >= po->operand_cnt)
1622 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1623 return po->operand[opr_num].name;
1626 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1628 if (opr_num >= po->operand_cnt)
1629 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1630 if (po->operand[opr_num].type != OPT_CONST)
1631 ferr(po, "opr %d: const expected\n", opr_num);
1632 return po->operand[opr_num].val;
1635 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1637 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1638 ferr(po, "invalid reg: %d\n", popr->reg);
1639 return regs_r32[popr->reg];
1642 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1644 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1646 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1648 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1650 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1655 *is_signed = cast[1] == 's' ? 1 : 0;
1659 static int check_deref_cast(const char *cast, int *bits)
1661 if (IS_START(cast, "*(u8 *)"))
1663 else if (IS_START(cast, "*(u16 *)"))
1665 else if (IS_START(cast, "*(u32 *)"))
1667 else if (IS_START(cast, "*(u64 *)"))
1675 // cast1 is the "final" cast
1676 static const char *simplify_cast(const char *cast1, const char *cast2)
1678 static char buf[256];
1686 if (IS(cast1, cast2))
1689 if (check_simple_cast(cast1, &bits1, &s1) == 0
1690 && check_simple_cast(cast2, &bits2, &s2) == 0)
1695 if (check_simple_cast(cast1, &bits1, &s1) == 0
1696 && check_deref_cast(cast2, &bits2) == 0)
1698 if (bits1 == bits2) {
1699 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1704 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1707 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1711 static const char *simplify_cast_num(const char *cast, unsigned int val)
1713 if (IS(cast, "(u8)") && val < 0x100)
1715 if (IS(cast, "(s8)") && val < 0x80)
1717 if (IS(cast, "(u16)") && val < 0x10000)
1719 if (IS(cast, "(s16)") && val < 0x8000)
1721 if (IS(cast, "(s32)") && val < 0x80000000)
1727 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1736 namelen = strlen(name);
1738 p = strchr(name, '+');
1742 ferr(po, "equ parse failed for '%s'\n", name);
1744 if (IS_START(p, "0x"))
1746 *extra_offs = strtol(p, &endp, 16);
1748 ferr(po, "equ parse failed for '%s'\n", name);
1751 for (i = 0; i < g_eqcnt; i++)
1752 if (strncmp(g_eqs[i].name, name, namelen) == 0
1753 && g_eqs[i].name[namelen] == 0)
1757 ferr(po, "unresolved equ name: '%s'\n", name);
1764 static int is_stack_access(struct parsed_op *po,
1765 const struct parsed_opr *popr)
1767 return (parse_stack_el(popr->name, NULL, NULL, 0)
1768 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1769 && IS_START(popr->name, "ebp")));
1772 static void parse_stack_access(struct parsed_op *po,
1773 const char *name, char *ofs_reg, int *offset_out,
1774 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1776 const char *bp_arg = "";
1777 const char *p = NULL;
1778 struct parsed_equ *eq;
1785 if (IS_START(name, "ebp-")
1786 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1789 if (IS_START(p, "0x"))
1791 offset = strtoul(p, &endp, 16);
1795 ferr(po, "ebp- parse of '%s' failed\n", name);
1798 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1799 eq = equ_find(po, bp_arg, &offset);
1801 ferr(po, "detected but missing eq\n");
1802 offset += eq->offset;
1805 if (!strncmp(name, "ebp", 3))
1808 // yes it sometimes LEAs ra for compares..
1809 if (!is_lea && ofs_reg[0] == 0
1810 && stack_ra <= offset && offset < stack_ra + 4)
1812 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1815 *offset_out = offset;
1817 *stack_ra_out = stack_ra;
1819 *bp_arg_out = bp_arg;
1822 static int parse_stack_esp_offset(struct parsed_op *po,
1823 const char *name, int *offset_out)
1825 char ofs_reg[16] = { 0, };
1826 struct parsed_equ *eq;
1832 if (strstr(name, "esp") == NULL)
1834 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1835 if (bp_arg == NULL) {
1836 // just plain offset?
1837 if (!IS_START(name, "esp+"))
1839 offset = strtol(name + 4, &endp, 0);
1840 if (endp == NULL || *endp != 0)
1842 *offset_out = offset;
1846 if (ofs_reg[0] != 0)
1848 eq = equ_find(po, bp_arg, &offset);
1850 ferr(po, "detected but missing eq\n");
1851 offset += eq->offset;
1852 *offset_out = base_val + offset;
1856 static int stack_frame_access(struct parsed_op *po,
1857 struct parsed_opr *popr, char *buf, size_t buf_size,
1858 const char *name, const char *cast, int is_src, int is_lea)
1860 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1861 const char *prefix = "";
1862 const char *bp_arg = NULL;
1863 char ofs_reg[16] = { 0, };
1864 int i, arg_i, arg_s;
1872 if (po->flags & OPF_EBP_S)
1873 ferr(po, "stack_frame_access while ebp is scratch\n");
1875 parse_stack_access(po, name, ofs_reg, &offset,
1876 &stack_ra, &bp_arg, is_lea);
1878 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1880 if (offset > stack_ra)
1882 arg_i = (offset - stack_ra - 4) / 4;
1883 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1885 if (g_func_pp->is_vararg
1886 && arg_i == g_func_pp->argc_stack && is_lea)
1888 // should be va_list
1891 snprintf(buf, buf_size, "%sap", cast);
1894 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1895 offset, bp_arg, arg_i);
1897 if (ofs_reg[0] != 0)
1898 ferr(po, "offset reg on arg access?\n");
1900 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1901 if (g_func_pp->arg[i].reg != NULL)
1907 if (i == g_func_pp->argc)
1908 ferr(po, "arg %d not in prototype?\n", arg_i);
1910 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1917 ferr(po, "lea/byte to arg?\n");
1918 if (is_src && (offset & 3) == 0)
1919 snprintf(buf, buf_size, "%sa%d",
1920 simplify_cast(cast, "(u8)"), i + 1);
1922 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1923 cast, offset & 3, i + 1);
1928 ferr(po, "lea/word to arg?\n");
1933 ferr(po, "problematic arg store\n");
1934 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1935 simplify_cast(cast, "*(u16 *)"), i + 1);
1938 ferr(po, "unaligned arg word load\n");
1940 else if (is_src && (offset & 2) == 0)
1941 snprintf(buf, buf_size, "%sa%d",
1942 simplify_cast(cast, "(u16)"), i + 1);
1944 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1945 cast, (offset & 2) ? "HI" : "LO", i + 1);
1957 snprintf(buf, buf_size, "(u32)&a%d + %d",
1960 ferr(po, "unaligned arg store\n");
1962 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1963 snprintf(buf, buf_size, "%s(a%d >> %d)",
1964 prefix, i + 1, (offset & 3) * 8);
1968 snprintf(buf, buf_size, "%s%sa%d",
1969 prefix, is_lea ? "&" : "", i + 1);
1974 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1978 strcat(g_comment, " unaligned");
1981 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
1982 if (tmp_lmod != OPLM_DWORD
1983 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
1984 < lmod_bytes(po, popr->lmod) + (offset & 3))))
1986 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
1987 i + 1, offset, g_func_pp->arg[i].type.name);
1989 // can't check this because msvc likes to reuse
1990 // arg space for scratch..
1991 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
1992 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
1996 if (g_stack_fsz == 0)
1997 ferr(po, "stack var access without stackframe\n");
1998 g_stack_frame_used = 1;
2000 sf_ofs = g_stack_fsz + offset;
2001 lim = (ofs_reg[0] != 0) ? -4 : 0;
2002 if (offset > 0 || sf_ofs < lim)
2003 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2013 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2014 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2018 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2019 // known unaligned or possibly unaligned
2020 strcat(g_comment, " unaligned");
2022 prefix = "*(u16 *)&";
2023 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2024 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2027 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2031 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2032 // known unaligned or possibly unaligned
2033 strcat(g_comment, " unaligned");
2035 prefix = "*(u32 *)&";
2036 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2037 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2040 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2044 ferr_assert(po, !(sf_ofs & 7));
2045 ferr_assert(po, ofs_reg[0] == 0);
2046 // only used for x87 int64/float, float sets is_lea
2048 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2050 snprintf(buf, buf_size, "*(s64 *)&sf.q[%d]", sf_ofs / 8);
2054 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2061 static void check_func_pp(struct parsed_op *po,
2062 const struct parsed_proto *pp, const char *pfx)
2064 enum opr_lenmod tmp_lmod;
2068 if (pp->argc_reg != 0) {
2069 if (!g_allow_user_icall && !pp->is_fastcall) {
2070 pp_print(buf, sizeof(buf), pp);
2071 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2073 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2074 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2075 pfx, pp->argc_reg, pp->argc_stack);
2078 // fptrs must use 32bit args, callsite might have no information and
2079 // lack a cast to smaller types, which results in incorrectly masked
2080 // args passed (callee may assume masked args, it does on ARM)
2081 if (!pp->is_osinc) {
2082 for (i = 0; i < pp->argc; i++) {
2083 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2084 if (ret && tmp_lmod != OPLM_DWORD)
2085 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2086 i + 1, pp->arg[i].type.name);
2091 static const char *check_label_read_ref(struct parsed_op *po,
2094 const struct parsed_proto *pp;
2096 pp = proto_parse(g_fhdr, name, 0);
2098 ferr(po, "proto_parse failed for ref '%s'\n", name);
2101 check_func_pp(po, pp, "ref");
2106 static char *out_src_opr(char *buf, size_t buf_size,
2107 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2110 char tmp1[256], tmp2[256];
2119 switch (popr->type) {
2122 ferr(po, "lea from reg?\n");
2124 switch (popr->lmod) {
2126 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2129 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2132 snprintf(buf, buf_size, "%s%s",
2133 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2136 if (popr->name[1] == 'h') // XXX..
2137 snprintf(buf, buf_size, "%s(%s >> 8)",
2138 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2140 snprintf(buf, buf_size, "%s%s",
2141 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2144 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2149 if (is_stack_access(po, popr)) {
2150 stack_frame_access(po, popr, buf, buf_size,
2151 popr->name, cast, 1, is_lea);
2155 strcpy(expr, popr->name);
2156 if (strchr(expr, '[')) {
2157 // special case: '[' can only be left for label[reg] form
2158 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2160 ferr(po, "parse failure for '%s'\n", expr);
2161 if (tmp1[0] == '(') {
2162 // (off_4FFF50+3)[eax]
2163 p = strchr(tmp1 + 1, ')');
2164 if (p == NULL || p[1] != 0)
2165 ferr(po, "parse failure (2) for '%s'\n", expr);
2167 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2169 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2172 // XXX: do we need more parsing?
2174 snprintf(buf, buf_size, "%s", expr);
2178 snprintf(buf, buf_size, "%s(%s)",
2179 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2183 name = check_label_read_ref(po, popr->name);
2184 if (cast[0] == 0 && popr->is_ptr)
2188 snprintf(buf, buf_size, "(u32)&%s", name);
2189 else if (popr->size_lt)
2190 snprintf(buf, buf_size, "%s%s%s%s", cast,
2191 lmod_cast_u_ptr(po, popr->lmod),
2192 popr->is_array ? "" : "&", name);
2194 snprintf(buf, buf_size, "%s%s%s", cast, name,
2195 popr->is_array ? "[0]" : "");
2199 name = check_label_read_ref(po, popr->name);
2203 ferr(po, "lea an offset?\n");
2204 snprintf(buf, buf_size, "%s&%s", cast, name);
2209 ferr(po, "lea from const?\n");
2211 printf_number(tmp1, sizeof(tmp1), popr->val);
2212 if (popr->val == 0 && strchr(cast, '*'))
2213 snprintf(buf, buf_size, "NULL");
2215 snprintf(buf, buf_size, "%s%s",
2216 simplify_cast_num(cast, popr->val), tmp1);
2220 ferr(po, "invalid src type: %d\n", popr->type);
2226 // note: may set is_ptr (we find that out late for ebp frame..)
2227 static char *out_dst_opr(char *buf, size_t buf_size,
2228 struct parsed_op *po, struct parsed_opr *popr)
2230 switch (popr->type) {
2232 switch (popr->lmod) {
2234 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2237 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2241 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2245 if (popr->name[1] == 'h') // XXX..
2246 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2248 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2251 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2256 if (is_stack_access(po, popr)) {
2257 stack_frame_access(po, popr, buf, buf_size,
2258 popr->name, "", 0, 0);
2262 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2265 if (popr->size_mismatch)
2266 snprintf(buf, buf_size, "%s%s%s",
2267 lmod_cast_u_ptr(po, popr->lmod),
2268 popr->is_array ? "" : "&", popr->name);
2270 snprintf(buf, buf_size, "%s%s", popr->name,
2271 popr->is_array ? "[0]" : "");
2275 ferr(po, "invalid dst type: %d\n", popr->type);
2281 static char *out_src_opr_u32(char *buf, size_t buf_size,
2282 struct parsed_op *po, struct parsed_opr *popr)
2284 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2287 static char *out_src_opr_float(char *buf, size_t buf_size,
2288 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2290 const char *cast = NULL;
2293 switch (popr->type) {
2295 if (popr->reg < xST0 || popr->reg > xST7)
2296 ferr(po, "bad reg: %d\n", popr->reg);
2298 if (need_float_stack) {
2299 if (popr->reg == xST0)
2300 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2302 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2306 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2312 switch (popr->lmod) {
2320 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2323 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2324 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2328 ferr(po, "invalid float type: %d\n", popr->type);
2334 static char *out_dst_opr_float(char *buf, size_t buf_size,
2335 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2338 return out_src_opr_float(buf, buf_size, po, popr, need_float_stack);
2341 static void out_test_for_cc(char *buf, size_t buf_size,
2342 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2343 enum opr_lenmod lmod, const char *expr)
2345 const char *cast, *scast;
2347 cast = lmod_cast_u(po, lmod);
2348 scast = lmod_cast_s(po, lmod);
2352 case PFO_BE: // CF==1||ZF==1; CF=0
2353 snprintf(buf, buf_size, "(%s%s %s 0)",
2354 cast, expr, is_inv ? "!=" : "==");
2358 case PFO_L: // SF!=OF; OF=0
2359 snprintf(buf, buf_size, "(%s%s %s 0)",
2360 scast, expr, is_inv ? ">=" : "<");
2363 case PFO_LE: // ZF==1||SF!=OF; OF=0
2364 snprintf(buf, buf_size, "(%s%s %s 0)",
2365 scast, expr, is_inv ? ">" : "<=");
2370 snprintf(buf, buf_size, "(%d)", !!is_inv);
2374 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2378 static void out_cmp_for_cc(char *buf, size_t buf_size,
2379 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2382 const char *cast, *scast, *cast_use;
2383 char buf1[256], buf2[256];
2384 enum opr_lenmod lmod;
2386 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2387 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2388 po->operand[0].lmod, po->operand[1].lmod);
2389 lmod = po->operand[0].lmod;
2391 cast = lmod_cast_u(po, lmod);
2392 scast = lmod_cast_s(po, lmod);
2408 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2411 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2412 if (po->op == OP_DEC)
2413 snprintf(buf2, sizeof(buf2), "1");
2416 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2418 strcat(cast_op2, "-");
2419 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2424 // note: must be unsigned compare
2425 snprintf(buf, buf_size, "(%s %s %s)",
2426 buf1, is_inv ? ">=" : "<", buf2);
2430 snprintf(buf, buf_size, "(%s %s %s)",
2431 buf1, is_inv ? "!=" : "==", buf2);
2435 // note: must be unsigned compare
2436 snprintf(buf, buf_size, "(%s %s %s)",
2437 buf1, is_inv ? ">" : "<=", buf2);
2440 if (is_inv && lmod == OPLM_BYTE
2441 && po->operand[1].type == OPT_CONST
2442 && po->operand[1].val == 0xff)
2444 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2445 snprintf(buf, buf_size, "(0)");
2449 // note: must be signed compare
2451 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2452 scast, buf1, buf2, is_inv ? ">=" : "<");
2456 snprintf(buf, buf_size, "(%s %s %s)",
2457 buf1, is_inv ? ">=" : "<", buf2);
2461 snprintf(buf, buf_size, "(%s %s %s)",
2462 buf1, is_inv ? ">" : "<=", buf2);
2470 static void out_cmp_test(char *buf, size_t buf_size,
2471 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2473 char buf1[256], buf2[256], buf3[256];
2475 if (po->op == OP_TEST) {
2476 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2477 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2480 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2481 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2482 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2484 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2485 po->operand[0].lmod, buf3);
2487 else if (po->op == OP_CMP) {
2488 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2491 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2494 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2495 struct parsed_opr *popr2)
2497 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2498 ferr(po, "missing lmod for both operands\n");
2500 if (popr1->lmod == OPLM_UNSPEC)
2501 popr1->lmod = popr2->lmod;
2502 else if (popr2->lmod == OPLM_UNSPEC)
2503 popr2->lmod = popr1->lmod;
2504 else if (popr1->lmod != popr2->lmod) {
2505 if (popr1->type_from_var) {
2506 popr1->size_mismatch = 1;
2507 if (popr1->lmod < popr2->lmod)
2509 popr1->lmod = popr2->lmod;
2511 else if (popr2->type_from_var) {
2512 popr2->size_mismatch = 1;
2513 if (popr2->lmod < popr1->lmod)
2515 popr2->lmod = popr1->lmod;
2518 ferr(po, "conflicting lmods: %d vs %d\n",
2519 popr1->lmod, popr2->lmod);
2523 static const char *op_to_c(struct parsed_op *po)
2547 ferr(po, "op_to_c was supplied with %d\n", po->op);
2551 // last op in stream - unconditional branch or ret
2552 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2553 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2554 && ops[_i].op != OP_CALL))
2556 #define check_i(po, i) \
2558 ferr(po, "bad " #i ": %d\n", i)
2560 // note: this skips over calls and rm'd stuff assuming they're handled
2561 // so it's intended to use at one of final passes
2562 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2563 int depth, int seen_noreturn, int flags_set)
2565 struct parsed_op *po;
2570 for (; i < opcnt; i++) {
2572 if (po->cc_scratch == magic)
2573 return ret; // already checked
2574 po->cc_scratch = magic;
2576 if (po->flags & OPF_TAIL) {
2577 if (po->op == OP_CALL) {
2578 if (po->pp != NULL && po->pp->is_noreturn)
2584 return -1; // deadend
2587 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2590 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2591 if (po->btj != NULL) {
2593 for (j = 0; j < po->btj->count; j++) {
2594 check_i(po, po->btj->d[j].bt_i);
2595 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2596 depth, seen_noreturn, flags_set);
2598 return ret; // dead end
2603 check_i(po, po->bt_i);
2604 if (po->flags & OPF_CJMP) {
2605 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2606 depth, seen_noreturn, flags_set);
2608 return ret; // dead end
2617 if ((po->op == OP_POP || po->op == OP_PUSH)
2618 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2623 if (po->op == OP_PUSH) {
2626 else if (po->op == OP_POP) {
2627 if (relevant && depth == 0) {
2628 po->flags |= flags_set;
2635 // for noreturn, assume msvc skipped stack cleanup
2636 return seen_noreturn ? 1 : -1;
2639 // scan for 'reg' pop backwards starting from i
2640 // intended to use for register restore search, so other reg
2641 // references are considered an error
2642 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2644 struct parsed_op *po;
2645 struct label_ref *lr;
2648 ops[i].cc_scratch = magic;
2652 if (g_labels[i] != NULL) {
2653 lr = &g_label_refs[i];
2654 for (; lr != NULL; lr = lr->next) {
2655 check_i(&ops[i], lr->i);
2656 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2660 if (i > 0 && LAST_OP(i - 1))
2668 if (ops[i].cc_scratch == magic)
2670 ops[i].cc_scratch = magic;
2673 if (po->op == OP_POP && po->operand[0].reg == reg) {
2674 if (po->flags & (OPF_RMD|OPF_DONE))
2677 po->flags |= set_flags;
2681 // this also covers the case where we reach corresponding push
2682 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2686 // nothing interesting on this path
2690 static void find_reachable_exits(int i, int opcnt, int magic,
2691 int *exits, int *exit_count)
2693 struct parsed_op *po;
2696 for (; i < opcnt; i++)
2699 if (po->cc_scratch == magic)
2701 po->cc_scratch = magic;
2703 if (po->flags & OPF_TAIL) {
2704 ferr_assert(po, *exit_count < MAX_EXITS);
2705 exits[*exit_count] = i;
2710 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2711 if (po->flags & OPF_RMD)
2714 if (po->btj != NULL) {
2715 for (j = 0; j < po->btj->count; j++) {
2716 check_i(po, po->btj->d[j].bt_i);
2717 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2723 check_i(po, po->bt_i);
2724 if (po->flags & OPF_CJMP)
2725 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2733 // scan for 'reg' pop backwards starting from exits (all paths)
2734 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2736 static int exits[MAX_EXITS];
2737 static int exit_count;
2742 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2744 ferr_assert(&ops[i], exit_count > 0);
2747 for (j = 0; j < exit_count; j++) {
2748 ret = scan_for_rsave_pop_reg(exits[j], i + opcnt * 16 + set_flags,
2757 // scan for one or more pop of push <const>
2758 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2759 int push_i, int is_probe)
2761 struct parsed_op *po;
2762 struct label_ref *lr;
2766 for (; i < opcnt; i++)
2769 if (po->cc_scratch == magic)
2770 return ret; // already checked
2771 po->cc_scratch = magic;
2773 if (po->flags & OPF_JMP) {
2774 if (po->flags & OPF_RMD)
2776 if (po->op == OP_CALL)
2779 if (po->btj != NULL) {
2780 for (j = 0; j < po->btj->count; j++) {
2781 check_i(po, po->btj->d[j].bt_i);
2782 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2790 check_i(po, po->bt_i);
2791 if (po->flags & OPF_CJMP) {
2792 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2803 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2806 if (g_labels[i] != NULL) {
2807 // all refs must be visited
2808 lr = &g_label_refs[i];
2809 for (; lr != NULL; lr = lr->next) {
2811 if (ops[lr->i].cc_scratch != magic)
2814 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2818 if (po->op == OP_POP)
2820 if (po->flags & (OPF_RMD|OPF_DONE))
2824 po->flags |= OPF_DONE;
2825 po->datap = &ops[push_i];
2834 static void scan_for_pop_const(int i, int opcnt, int magic)
2838 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2840 ops[i].flags |= OPF_RMD | OPF_DONE;
2841 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2845 // check if all branch targets within a marked path are also marked
2846 // note: the path checked must not be empty or end with a branch
2847 static int check_path_branches(int opcnt, int magic)
2849 struct parsed_op *po;
2852 for (i = 0; i < opcnt; i++) {
2854 if (po->cc_scratch != magic)
2857 if (po->flags & OPF_JMP) {
2858 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2861 if (po->btj != NULL) {
2862 for (j = 0; j < po->btj->count; j++) {
2863 check_i(po, po->btj->d[j].bt_i);
2864 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2869 check_i(po, po->bt_i);
2870 if (ops[po->bt_i].cc_scratch != magic)
2872 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2880 // scan for multiple pushes for given pop
2881 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2884 int reg = ops[pop_i].operand[0].reg;
2885 struct parsed_op *po;
2886 struct label_ref *lr;
2889 ops[i].cc_scratch = magic;
2893 if (g_labels[i] != NULL) {
2894 lr = &g_label_refs[i];
2895 for (; lr != NULL; lr = lr->next) {
2896 check_i(&ops[i], lr->i);
2897 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2901 if (i > 0 && LAST_OP(i - 1))
2909 if (ops[i].cc_scratch == magic)
2911 ops[i].cc_scratch = magic;
2914 if (po->op == OP_CALL)
2916 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2919 if (po->op == OP_PUSH)
2921 if (po->datap != NULL)
2923 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2924 // leave this case for reg save/restore handlers
2928 po->flags |= OPF_PPUSH | OPF_DONE;
2929 po->datap = &ops[pop_i];
2938 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2940 int magic = i + opcnt * 14;
2943 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2945 ret = check_path_branches(opcnt, magic);
2947 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2948 *regmask_pp |= 1 << ops[i].operand[0].reg;
2949 scan_pushes_for_pop_r(i, magic + 1, i, 0);
2954 static void scan_propagate_df(int i, int opcnt)
2956 struct parsed_op *po = &ops[i];
2959 for (; i < opcnt; i++) {
2961 if (po->flags & OPF_DF)
2962 return; // already resolved
2963 po->flags |= OPF_DF;
2965 if (po->op == OP_CALL)
2966 ferr(po, "call with DF set?\n");
2968 if (po->flags & OPF_JMP) {
2969 if (po->btj != NULL) {
2971 for (j = 0; j < po->btj->count; j++) {
2972 check_i(po, po->btj->d[j].bt_i);
2973 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
2978 if (po->flags & OPF_RMD)
2980 check_i(po, po->bt_i);
2981 if (po->flags & OPF_CJMP)
2982 scan_propagate_df(po->bt_i, opcnt);
2988 if (po->flags & OPF_TAIL)
2991 if (po->op == OP_CLD) {
2992 po->flags |= OPF_RMD | OPF_DONE;
2997 ferr(po, "missing DF clear?\n");
3000 // is operand 'opr' referenced by parsed_op 'po'?
3001 static int is_opr_referenced(const struct parsed_opr *opr,
3002 const struct parsed_op *po)
3006 if (opr->type == OPT_REG) {
3007 mask = po->regmask_dst | po->regmask_src;
3008 if (po->op == OP_CALL)
3009 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3010 if ((1 << opr->reg) & mask)
3016 for (i = 0; i < po->operand_cnt; i++)
3017 if (IS(po->operand[0].name, opr->name))
3023 // is operand 'opr' read by parsed_op 'po'?
3024 static int is_opr_read(const struct parsed_opr *opr,
3025 const struct parsed_op *po)
3027 if (opr->type == OPT_REG) {
3028 if (po->regmask_src & (1 << opr->reg))
3038 // is operand 'opr' modified by parsed_op 'po'?
3039 static int is_opr_modified(const struct parsed_opr *opr,
3040 const struct parsed_op *po)
3044 if (opr->type == OPT_REG) {
3045 if (po->op == OP_CALL) {
3046 mask = po->regmask_dst;
3047 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3048 if (mask & (1 << opr->reg))
3054 if (po->regmask_dst & (1 << opr->reg))
3060 return IS(po->operand[0].name, opr->name);
3063 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3064 static int is_any_opr_modified(const struct parsed_op *po_test,
3065 const struct parsed_op *po, int c_mode)
3070 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3073 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3076 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3079 // in reality, it can wreck any register, but in decompiled C
3080 // version it can only overwrite eax or edx:eax
3081 mask = (1 << xAX) | (1 << xDX);
3085 if (po->op == OP_CALL
3086 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3089 for (i = 0; i < po_test->operand_cnt; i++)
3090 if (IS(po_test->operand[i].name, po->operand[0].name))
3096 // scan for any po_test operand modification in range given
3097 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3100 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3103 for (; i < opcnt; i++) {
3104 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3111 // scan for po_test operand[0] modification in range given
3112 static int scan_for_mod_opr0(struct parsed_op *po_test,
3115 for (; i < opcnt; i++) {
3116 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3123 static int try_resolve_const(int i, const struct parsed_opr *opr,
3124 int magic, unsigned int *val);
3126 static int scan_for_flag_set(int i, int opcnt, int magic,
3127 int *branched, int *setters, int *setter_cnt)
3129 struct label_ref *lr;
3133 if (ops[i].cc_scratch == magic) {
3134 // is this a problem?
3135 //ferr(&ops[i], "%s looped\n", __func__);
3138 ops[i].cc_scratch = magic;
3140 if (g_labels[i] != NULL) {
3143 lr = &g_label_refs[i];
3144 for (; lr->next; lr = lr->next) {
3145 check_i(&ops[i], lr->i);
3146 ret = scan_for_flag_set(lr->i, opcnt, magic,
3147 branched, setters, setter_cnt);
3152 check_i(&ops[i], lr->i);
3153 if (i > 0 && LAST_OP(i - 1)) {
3157 ret = scan_for_flag_set(lr->i, opcnt, magic,
3158 branched, setters, setter_cnt);
3164 if (ops[i].flags & OPF_FLAGS) {
3165 setters[*setter_cnt] = i;
3168 if (ops[i].flags & OPF_REP) {
3169 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3172 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3173 if (ret != 1 || uval == 0) {
3174 // can't treat it as full setter because of ecx=0 case,
3175 // also disallow delayed compare
3184 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3191 // scan back for cdq, if anything modifies edx, fail
3192 static int scan_for_cdq_edx(int i)
3195 if (g_labels[i] != NULL) {
3196 if (g_label_refs[i].next != NULL)
3198 if (i > 0 && LAST_OP(i - 1)) {
3199 i = g_label_refs[i].i;
3206 if (ops[i].op == OP_CDQ)
3209 if (ops[i].regmask_dst & (1 << xDX))
3216 static int scan_for_reg_clear(int i, int reg)
3219 if (g_labels[i] != NULL) {
3220 if (g_label_refs[i].next != NULL)
3222 if (i > 0 && LAST_OP(i - 1)) {
3223 i = g_label_refs[i].i;
3230 if (ops[i].op == OP_XOR
3231 && ops[i].operand[0].lmod == OPLM_DWORD
3232 && ops[i].operand[0].reg == ops[i].operand[1].reg
3233 && ops[i].operand[0].reg == reg)
3236 if (ops[i].regmask_dst & (1 << reg))
3243 static void patch_esp_adjust(struct parsed_op *po, int adj)
3245 ferr_assert(po, po->op == OP_ADD);
3246 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3247 ferr_assert(po, po->operand[1].type == OPT_CONST);
3249 // this is a bit of a hack, but deals with use of
3250 // single adj for multiple calls
3251 po->operand[1].val -= adj;
3252 po->flags |= OPF_RMD;
3253 if (po->operand[1].val == 0)
3254 po->flags |= OPF_DONE;
3255 ferr_assert(po, (int)po->operand[1].val >= 0);
3258 // scan for positive, constant esp adjust
3259 // multipath case is preliminary
3260 static int scan_for_esp_adjust(int i, int opcnt,
3261 int adj_expect, int *adj, int *is_multipath, int do_update)
3263 int adj_expect_unknown = 0;
3264 struct parsed_op *po;
3268 *adj = *is_multipath = 0;
3269 if (adj_expect < 0) {
3270 adj_expect_unknown = 1;
3271 adj_expect = 32 * 4; // enough?
3274 for (; i < opcnt && *adj < adj_expect; i++) {
3275 if (g_labels[i] != NULL)
3279 if (po->flags & OPF_DONE)
3282 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3283 if (po->operand[1].type != OPT_CONST)
3284 ferr(&ops[i], "non-const esp adjust?\n");
3285 *adj += po->operand[1].val;
3287 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3290 patch_esp_adjust(po, adj_expect);
3292 po->flags |= OPF_RMD;
3296 else if (po->op == OP_PUSH) {
3297 //if (first_pop == -1)
3298 // first_pop = -2; // none
3299 *adj -= lmod_bytes(po, po->operand[0].lmod);
3301 else if (po->op == OP_POP) {
3302 if (!(po->flags & OPF_DONE)) {
3303 // seems like msvc only uses 'pop ecx' for stack realignment..
3304 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3306 if (first_pop == -1 && *adj >= 0)
3309 if (do_update && *adj >= 0) {
3310 po->flags |= OPF_RMD;
3312 po->flags |= OPF_DONE | OPF_NOREGS;
3315 *adj += lmod_bytes(po, po->operand[0].lmod);
3316 if (*adj > adj_best)
3319 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3320 if (po->op == OP_JMP && po->btj == NULL) {
3326 if (po->op != OP_CALL)
3328 if (po->operand[0].type != OPT_LABEL)
3330 if (po->pp != NULL && po->pp->is_stdcall)
3332 if (adj_expect_unknown && first_pop >= 0)
3334 // assume it's another cdecl call
3338 if (first_pop >= 0) {
3339 // probably only 'pop ecx' was used
3347 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3349 struct parsed_op *po;
3353 ferr(ops, "%s: followed bad branch?\n", __func__);
3355 for (; i < opcnt; i++) {
3357 if (po->cc_scratch == magic)
3359 po->cc_scratch = magic;
3362 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3363 if (po->btj != NULL) {
3365 for (j = 0; j < po->btj->count; j++)
3366 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3370 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3371 if (!(po->flags & OPF_CJMP))
3374 if (po->flags & OPF_TAIL)
3379 static const struct parsed_proto *try_recover_pp(
3380 struct parsed_op *po, const struct parsed_opr *opr,
3381 int is_call, int *search_instead)
3383 const struct parsed_proto *pp = NULL;
3387 // maybe an arg of g_func?
3388 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3390 char ofs_reg[16] = { 0, };
3391 int arg, arg_s, arg_i;
3398 parse_stack_access(po, opr->name, ofs_reg,
3399 &offset, &stack_ra, NULL, 0);
3400 if (ofs_reg[0] != 0)
3401 ferr(po, "offset reg on arg access?\n");
3402 if (offset <= stack_ra) {
3403 // search who set the stack var instead
3404 if (search_instead != NULL)
3405 *search_instead = 1;
3409 arg_i = (offset - stack_ra - 4) / 4;
3410 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3411 if (g_func_pp->arg[arg].reg != NULL)
3417 if (arg == g_func_pp->argc)
3418 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3420 pp = g_func_pp->arg[arg].pp;
3423 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3424 check_func_pp(po, pp, "icall arg");
3427 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3429 p = strchr(opr->name + 1, '[');
3430 memcpy(buf, opr->name, p - opr->name);
3431 buf[p - opr->name] = 0;
3432 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3434 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3435 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3438 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3441 check_func_pp(po, pp, "reg-fptr ref");
3447 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3448 int magic, const struct parsed_proto **pp_found, int *pp_i,
3451 const struct parsed_proto *pp = NULL;
3452 struct parsed_op *po;
3453 struct label_ref *lr;
3455 ops[i].cc_scratch = magic;
3458 if (g_labels[i] != NULL) {
3459 lr = &g_label_refs[i];
3460 for (; lr != NULL; lr = lr->next) {
3461 check_i(&ops[i], lr->i);
3462 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3464 if (i > 0 && LAST_OP(i - 1))
3472 if (ops[i].cc_scratch == magic)
3474 ops[i].cc_scratch = magic;
3476 if (!(ops[i].flags & OPF_DATA))
3478 if (!is_opr_modified(opr, &ops[i]))
3480 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3481 // most probably trashed by some processing
3486 opr = &ops[i].operand[1];
3487 if (opr->type != OPT_REG)
3491 po = (i >= 0) ? &ops[i] : ops;
3494 // reached the top - can only be an arg-reg
3495 if (opr->type != OPT_REG || g_func_pp == NULL)
3498 for (i = 0; i < g_func_pp->argc; i++) {
3499 if (g_func_pp->arg[i].reg == NULL)
3501 if (IS(opr->name, g_func_pp->arg[i].reg))
3504 if (i == g_func_pp->argc)
3506 pp = g_func_pp->arg[i].pp;
3508 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3509 i + 1, g_func_pp->arg[i].reg);
3510 check_func_pp(po, pp, "icall reg-arg");
3513 pp = try_recover_pp(po, opr, 1, NULL);
3515 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3516 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3517 || (*pp_found)->is_stdcall != pp->is_stdcall
3518 || (*pp_found)->is_fptr != pp->is_fptr
3519 || (*pp_found)->argc != pp->argc
3520 || (*pp_found)->argc_reg != pp->argc_reg
3521 || (*pp_found)->argc_stack != pp->argc_stack)
3523 ferr(po, "icall: parsed_proto mismatch\n");
3533 static void add_label_ref(struct label_ref *lr, int op_i)
3535 struct label_ref *lr_new;
3542 lr_new = calloc(1, sizeof(*lr_new));
3544 lr_new->next = lr->next;
3548 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3550 struct parsed_op *po = &ops[i];
3551 struct parsed_data *pd;
3552 char label[NAMELEN], *p;
3555 p = strchr(po->operand[0].name, '[');
3559 len = p - po->operand[0].name;
3560 strncpy(label, po->operand[0].name, len);
3563 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3564 if (IS(g_func_pd[j].label, label)) {
3570 //ferr(po, "label '%s' not parsed?\n", label);
3573 if (pd->type != OPT_OFFSET)
3574 ferr(po, "label '%s' with non-offset data?\n", label);
3576 // find all labels, link
3577 for (j = 0; j < pd->count; j++) {
3578 for (l = 0; l < opcnt; l++) {
3579 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3580 add_label_ref(&g_label_refs[l], i);
3590 static void clear_labels(int count)
3594 for (i = 0; i < count; i++) {
3595 if (g_labels[i] != NULL) {
3602 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3607 for (i = 0; i < pp->argc; i++) {
3608 if (pp->arg[i].reg != NULL) {
3609 reg = char_array_i(regs_r32,
3610 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3612 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3613 pp->arg[i].reg, pp->name);
3614 regmask |= 1 << reg;
3621 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3626 if (pp->has_retreg) {
3627 for (i = 0; i < pp->argc; i++) {
3628 if (pp->arg[i].type.is_retreg) {
3629 reg = char_array_i(regs_r32,
3630 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3631 ferr_assert(ops, reg >= 0);
3632 regmask |= 1 << reg;
3637 if (strstr(pp->ret_type.name, "int64"))
3638 return regmask | (1 << xAX) | (1 << xDX);
3639 if (IS(pp->ret_type.name, "float")
3640 || IS(pp->ret_type.name, "double"))
3642 return regmask | mxST0;
3644 if (strcasecmp(pp->ret_type.name, "void") == 0)
3647 return regmask | mxAX;
3650 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3652 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3653 && memcmp(po1->operand, po2->operand,
3654 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3657 static void resolve_branches_parse_calls(int opcnt)
3659 static const struct {
3663 unsigned int regmask_src;
3664 unsigned int regmask_dst;
3666 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3667 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3668 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3669 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3671 const struct parsed_proto *pp_c;
3672 struct parsed_proto *pp;
3673 struct parsed_data *pd;
3674 struct parsed_op *po;
3675 const char *tmpname;
3679 for (i = 0; i < opcnt; i++)
3685 if (po->datap != NULL) {
3686 pp = calloc(1, sizeof(*pp));
3687 my_assert_not(pp, NULL);
3689 ret = parse_protostr(po->datap, pp);
3691 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3697 if (po->op == OP_CALL) {
3702 else if (po->operand[0].type == OPT_LABEL)
3704 tmpname = opr_name(po, 0);
3705 if (IS_START(tmpname, "loc_"))
3706 ferr(po, "call to loc_*\n");
3707 if (IS(tmpname, "__alloca_probe"))
3710 // convert some calls to pseudo-ops
3711 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3712 if (!IS(tmpname, pseudo_ops[l].name))
3715 po->op = pseudo_ops[l].op;
3716 po->operand_cnt = 0;
3717 po->regmask_src = pseudo_ops[l].regmask_src;
3718 po->regmask_dst = pseudo_ops[l].regmask_dst;
3719 po->flags = pseudo_ops[l].flags;
3720 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3723 if (l < ARRAY_SIZE(pseudo_ops))
3726 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3727 if (!g_header_mode && pp_c == NULL)
3728 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3731 pp = proto_clone(pp_c);
3732 my_assert_not(pp, NULL);
3738 check_func_pp(po, pp, "fptr var call");
3739 if (pp->is_noreturn)
3740 po->flags |= OPF_TAIL;
3746 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3749 if (po->operand[0].type == OPT_REGMEM) {
3750 pd = try_resolve_jumptab(i, opcnt);
3758 for (l = 0; l < opcnt; l++) {
3759 if (g_labels[l] != NULL
3760 && IS(po->operand[0].name, g_labels[l]))
3762 if (l == i + 1 && po->op == OP_JMP) {
3763 // yet another alignment type..
3764 po->flags |= OPF_RMD|OPF_DONE;
3767 add_label_ref(&g_label_refs[l], i);
3773 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3776 if (po->operand[0].type == OPT_LABEL)
3780 ferr(po, "unhandled branch\n");
3784 po->flags |= OPF_TAIL;
3785 if (i > 0 && ops[i - 1].op == OP_POP)
3786 po->flags |= OPF_ATAIL;
3791 static void scan_prologue_epilogue(int opcnt)
3793 int ecx_push = 0, esp_sub = 0, pusha = 0;
3794 int sandard_epilogue;
3798 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3799 && ops[1].op == OP_MOV
3800 && IS(opr_name(&ops[1], 0), "ebp")
3801 && IS(opr_name(&ops[1], 1), "esp"))
3804 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3805 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3808 if (ops[i].op == OP_PUSHA) {
3809 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3814 if (ops[i].op == OP_SUB && IS(opr_name(&ops[i], 0), "esp")) {
3815 g_stack_fsz = opr_const(&ops[i], 1);
3816 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3820 // another way msvc builds stack frame..
3821 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3823 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3827 // and another way..
3828 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3829 && ops[i].operand[1].type == OPT_CONST
3830 && ops[i + 1].op == OP_CALL
3831 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3833 g_stack_fsz += ops[i].operand[1].val;
3834 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3836 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3843 for (; i < opcnt; i++)
3844 if (ops[i].flags & OPF_TAIL)
3847 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3848 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3854 sandard_epilogue = 0;
3855 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3857 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3858 // the standard epilogue is sometimes even used without a sf
3859 if (ops[j - 1].op == OP_MOV
3860 && IS(opr_name(&ops[j - 1], 0), "esp")
3861 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3862 sandard_epilogue = 1;
3864 else if (ops[j].op == OP_LEAVE)
3866 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3867 sandard_epilogue = 1;
3869 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3870 && ops[i].pp->is_noreturn)
3872 // on noreturn, msvc sometimes cleans stack, sometimes not
3877 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3878 ferr(&ops[j], "'pop ebp' expected\n");
3880 if (g_stack_fsz != 0 || sandard_epilogue) {
3881 if (ops[j].op == OP_LEAVE)
3883 else if (sandard_epilogue) // mov esp, ebp
3885 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3888 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3890 ferr(&ops[j], "esp restore expected\n");
3893 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3894 && IS(opr_name(&ops[j], 0), "ecx"))
3896 ferr(&ops[j], "unexpected ecx pop\n");
3901 if (ops[j].op == OP_POPA)
3902 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3904 ferr(&ops[j], "popa expected\n");
3909 } while (i < opcnt);
3912 ferr(ops, "missing ebp epilogue\n");
3918 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3919 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3925 for (; i < opcnt; i++) {
3926 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3928 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3929 && ops[i].operand[1].type == OPT_CONST)
3931 g_stack_fsz = ops[i].operand[1].val;
3932 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3937 else if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3938 && ops[i].operand[1].type == OPT_CONST
3939 && ops[i + 1].op == OP_CALL
3940 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3942 g_stack_fsz += ops[i].operand[1].val;
3943 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3945 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3952 if (ecx_push && !esp_sub) {
3953 // could actually be args for a call..
3954 for (; i < opcnt; i++)
3955 if (ops[i].op != OP_PUSH)
3958 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3959 const struct parsed_proto *pp;
3960 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3961 j = pp ? pp->argc_stack : 0;
3962 while (i > 0 && j > 0) {
3964 if (ops[i].op == OP_PUSH) {
3965 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
3970 ferr(&ops[i], "unhandled prologue\n");
3973 i = g_stack_fsz = ecx_push = 0;
3974 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3975 if (!(ops[i].flags & OPF_RMD))
3985 if (ecx_push || esp_sub)
3990 for (; i < opcnt; i++)
3991 if (ops[i].flags & OPF_TAIL)
3995 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3996 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4003 for (l = 0; l < ecx_push; l++) {
4004 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4006 else if (ops[j].op == OP_ADD
4007 && IS(opr_name(&ops[j], 0), "esp")
4008 && ops[j].operand[1].type == OPT_CONST)
4011 l += ops[j].operand[1].val / 4 - 1;
4014 ferr(&ops[j], "'pop ecx' expected\n");
4016 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4020 ferr(&ops[j], "epilogue scan failed\n");
4026 if (ops[j].op != OP_ADD
4027 || !IS(opr_name(&ops[j], 0), "esp")
4028 || ops[j].operand[1].type != OPT_CONST
4029 || ops[j].operand[1].val != g_stack_fsz)
4031 if (ops[i].op == OP_CALL && ops[i].pp != NULL
4032 && ops[i].pp->is_noreturn)
4034 // noreturn tailcall with no epilogue
4038 ferr(&ops[j], "'add esp' expected\n");
4041 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4042 ops[j].operand[1].val = 0; // hack for stack arg scanner
4047 } while (i < opcnt);
4050 ferr(ops, "missing esp epilogue\n");
4054 // find an instruction that changed opr before i op
4055 // *op_i must be set to -1 by the caller
4056 // *is_caller is set to 1 if one source is determined to be g_func arg
4057 // returns 1 if found, *op_i is then set to origin
4058 // returns -1 if multiple origins are found
4059 static int resolve_origin(int i, const struct parsed_opr *opr,
4060 int magic, int *op_i, int *is_caller)
4062 struct label_ref *lr;
4066 if (g_labels[i] != NULL) {
4067 lr = &g_label_refs[i];
4068 for (; lr != NULL; lr = lr->next) {
4069 check_i(&ops[i], lr->i);
4070 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4072 if (i > 0 && LAST_OP(i - 1))
4078 if (is_caller != NULL)
4083 if (ops[i].cc_scratch == magic)
4085 ops[i].cc_scratch = magic;
4087 if (!(ops[i].flags & OPF_DATA))
4089 if (!is_opr_modified(opr, &ops[i]))
4093 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4104 // find an instruction that previously referenced opr
4105 // if multiple results are found - fail
4106 // *op_i must be set to -1 by the caller
4107 // returns 1 if found, *op_i is then set to referencer insn
4108 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4109 int magic, int *op_i)
4111 struct label_ref *lr;
4115 if (g_labels[i] != NULL) {
4116 lr = &g_label_refs[i];
4117 for (; lr != NULL; lr = lr->next) {
4118 check_i(&ops[i], lr->i);
4119 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4121 if (i > 0 && LAST_OP(i - 1))
4129 if (ops[i].cc_scratch == magic)
4131 ops[i].cc_scratch = magic;
4133 if (!is_opr_referenced(opr, &ops[i]))
4144 // adjust datap of all reachable 'op' insns when moving back
4145 // returns 1 if at least 1 op was found
4146 // returns -1 if path without an op was found
4147 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4149 struct label_ref *lr;
4152 if (ops[i].cc_scratch == magic)
4154 ops[i].cc_scratch = magic;
4157 if (g_labels[i] != NULL) {
4158 lr = &g_label_refs[i];
4159 for (; lr != NULL; lr = lr->next) {
4160 check_i(&ops[i], lr->i);
4161 ret |= adjust_prev_op(lr->i, op, magic, datap);
4163 if (i > 0 && LAST_OP(i - 1))
4171 if (ops[i].cc_scratch == magic)
4173 ops[i].cc_scratch = magic;
4175 if (ops[i].op != op)
4178 ops[i].datap = datap;
4183 // find next instruction that reads opr
4184 // *op_i must be set to -1 by the caller
4185 // on return, *op_i is set to first referencer insn
4186 // returns 1 if exactly 1 referencer is found
4187 static int find_next_read(int i, int opcnt,
4188 const struct parsed_opr *opr, int magic, int *op_i)
4190 struct parsed_op *po;
4193 for (; i < opcnt; i++)
4195 if (ops[i].cc_scratch == magic)
4197 ops[i].cc_scratch = magic;
4200 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4201 if (po->btj != NULL) {
4203 for (j = 0; j < po->btj->count; j++) {
4204 check_i(po, po->btj->d[j].bt_i);
4205 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4211 if (po->flags & OPF_RMD)
4213 check_i(po, po->bt_i);
4214 if (po->flags & OPF_CJMP) {
4215 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4224 if (!is_opr_read(opr, po)) {
4226 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4227 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4229 full_opr = po->operand[0].lmod >= opr->lmod;
4231 if (is_opr_modified(opr, po) && full_opr) {
4235 if (po->flags & OPF_TAIL)
4250 // find next instruction that reads opr
4251 // *op_i must be set to -1 by the caller
4252 // on return, *op_i is set to first flag user insn
4253 // returns 1 if exactly 1 flag user is found
4254 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4256 struct parsed_op *po;
4259 for (; i < opcnt; i++)
4261 if (ops[i].cc_scratch == magic)
4263 ops[i].cc_scratch = magic;
4266 if (po->op == OP_CALL)
4268 if (po->flags & OPF_JMP) {
4269 if (po->btj != NULL) {
4271 for (j = 0; j < po->btj->count; j++) {
4272 check_i(po, po->btj->d[j].bt_i);
4273 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4279 if (po->flags & OPF_RMD)
4281 check_i(po, po->bt_i);
4282 if (po->flags & OPF_CJMP)
4289 if (!(po->flags & OPF_CC)) {
4290 if (po->flags & OPF_FLAGS)
4293 if (po->flags & OPF_TAIL)
4309 static int try_resolve_const(int i, const struct parsed_opr *opr,
4310 int magic, unsigned int *val)
4315 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4318 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4321 *val = ops[i].operand[1].val;
4328 static int resolve_used_bits(int i, int opcnt, int reg,
4329 int *mask, int *is_z_check)
4331 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4335 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4339 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4341 fnote(&ops[j], "(first read)\n");
4342 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4345 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4346 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4348 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4349 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4351 *mask = ops[j].operand[1].val;
4352 if (ops[j].operand[0].lmod == OPLM_BYTE
4353 && ops[j].operand[0].name[1] == 'h')
4357 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4360 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4362 *is_z_check = ops[k].pfo == PFO_Z;
4367 static const struct parsed_proto *resolve_deref(int i, int magic,
4368 struct parsed_opr *opr, int level)
4370 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4371 const struct parsed_proto *pp = NULL;
4372 int from_caller = 0;
4381 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4382 if (ret != 2 || len != strlen(opr->name)) {
4383 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4384 if (ret != 1 || len != strlen(opr->name))
4388 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4393 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4397 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4398 && strlen(ops[j].operand[1].name) == 3
4399 && ops[j].operand[0].lmod == OPLM_DWORD
4400 && ops[j].pp == NULL // no hint
4403 // allow one simple dereference (com/directx)
4404 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4405 ops[j].operand[1].name);
4409 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4414 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4417 if (ops[j].pp != NULL) {
4421 else if (ops[j].operand[1].type == OPT_REGMEM) {
4422 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4424 // maybe structure ptr in structure
4425 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4428 else if (ops[j].operand[1].type == OPT_LABEL)
4429 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4430 else if (ops[j].operand[1].type == OPT_REG) {
4433 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4435 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4436 for (k = 0; k < g_func_pp->argc; k++) {
4437 if (g_func_pp->arg[k].reg == NULL)
4439 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4440 pp = g_func_pp->arg[k].pp;
4449 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4451 ferr(&ops[j], "expected struct, got '%s %s'\n",
4452 pp->type.name, pp->name);
4456 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4459 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4460 int *pp_i, int *multi_src)
4462 const struct parsed_proto *pp = NULL;
4463 int search_advice = 0;
4468 switch (ops[i].operand[0].type) {
4470 // try to resolve struct member calls
4471 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4477 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4483 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4491 static struct parsed_proto *process_call_early(int i, int opcnt,
4494 struct parsed_op *po = &ops[i];
4495 struct parsed_proto *pp;
4501 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4505 // look for and make use of esp adjust
4507 if (!pp->is_stdcall && pp->argc_stack > 0)
4508 ret = scan_for_esp_adjust(i + 1, opcnt,
4509 pp->argc_stack * 4, &adj, &multipath, 0);
4511 if (pp->argc_stack > adj / 4)
4515 if (ops[ret].op == OP_POP) {
4516 for (j = 1; j < adj / 4; j++) {
4517 if (ops[ret + j].op != OP_POP
4518 || ops[ret + j].operand[0].reg != xCX)
4530 static struct parsed_proto *process_call(int i, int opcnt)
4532 struct parsed_op *po = &ops[i];
4533 const struct parsed_proto *pp_c;
4534 struct parsed_proto *pp;
4535 const char *tmpname;
4536 int call_i = -1, ref_i = -1;
4537 int adj = 0, multipath = 0;
4540 tmpname = opr_name(po, 0);
4545 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4547 if (!pp_c->is_func && !pp_c->is_fptr)
4548 ferr(po, "call to non-func: %s\n", pp_c->name);
4549 pp = proto_clone(pp_c);
4550 my_assert_not(pp, NULL);
4552 // not resolved just to single func
4555 switch (po->operand[0].type) {
4557 // we resolved this call and no longer need the register
4558 po->regmask_src &= ~(1 << po->operand[0].reg);
4560 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4561 && ops[call_i].operand[1].type == OPT_LABEL)
4563 // no other source users?
4564 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4566 if (ret == 1 && call_i == ref_i) {
4567 // and nothing uses it after us?
4569 find_next_read(i + 1, opcnt, &po->operand[0],
4570 i + opcnt * 11, &ref_i);
4572 // then also don't need the source mov
4573 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4585 pp = calloc(1, sizeof(*pp));
4586 my_assert_not(pp, NULL);
4589 ret = scan_for_esp_adjust(i + 1, opcnt,
4590 -1, &adj, &multipath, 0);
4591 if (ret < 0 || adj < 0) {
4592 if (!g_allow_regfunc)
4593 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4594 pp->is_unresolved = 1;
4598 if (adj > ARRAY_SIZE(pp->arg))
4599 ferr(po, "esp adjust too large: %d\n", adj);
4600 pp->ret_type.name = strdup("int");
4601 pp->argc = pp->argc_stack = adj;
4602 for (arg = 0; arg < pp->argc; arg++)
4603 pp->arg[arg].type.name = strdup("int");
4608 // look for and make use of esp adjust
4611 if (!pp->is_stdcall && pp->argc_stack > 0) {
4612 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4613 ret = scan_for_esp_adjust(i + 1, opcnt,
4614 adj_expect, &adj, &multipath, 0);
4617 if (pp->is_vararg) {
4618 if (adj / 4 < pp->argc_stack) {
4619 fnote(po, "(this call)\n");
4620 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4621 adj, pp->argc_stack * 4);
4623 // modify pp to make it have varargs as normal args
4625 pp->argc += adj / 4 - pp->argc_stack;
4626 for (; arg < pp->argc; arg++) {
4627 pp->arg[arg].type.name = strdup("int");
4630 if (pp->argc > ARRAY_SIZE(pp->arg))
4631 ferr(po, "too many args for '%s'\n", tmpname);
4633 if (pp->argc_stack > adj / 4) {
4634 fnote(po, "(this call)\n");
4635 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4636 tmpname, pp->argc_stack * 4, adj);
4639 scan_for_esp_adjust(i + 1, opcnt,
4640 pp->argc_stack * 4, &adj, &multipath, 1);
4642 else if (pp->is_vararg)
4643 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4649 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
4652 struct parsed_op *po;
4658 for (base_arg = 0; base_arg < pp->argc; base_arg++)
4659 if (pp->arg[base_arg].reg == NULL)
4662 for (j = i; j > 0; )
4664 ferr_assert(&ops[j], g_labels[j] == NULL);
4668 ferr_assert(po, po->op != OP_PUSH);
4669 if (po->op == OP_FST)
4671 if (po->operand[0].type != OPT_REGMEM)
4673 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
4676 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3))
4677 ferr(po, "bad offset %d (%d args)\n", offset, pp->argc_stack);
4679 arg = base_arg + offset / 4;
4681 po->p_argnum = arg + 1;
4682 ferr_assert(po, pp->arg[arg].datap == NULL);
4683 pp->arg[arg].datap = po;
4684 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
4685 if (regmask_ffca != NULL)
4686 *regmask_ffca |= 1 << arg;
4688 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4689 && po->operand[1].type == OPT_CONST)
4691 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4696 for (arg = base_arg; arg < pp->argc; arg++) {
4697 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
4698 po = pp->arg[arg].datap;
4700 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
4701 if (po->operand[0].lmod == OPLM_QWORD)
4708 static int collect_call_args_early(int i, struct parsed_proto *pp,
4709 int *regmask, int *regmask_ffca)
4711 struct parsed_op *po;
4715 for (arg = 0; arg < pp->argc; arg++)
4716 if (pp->arg[arg].reg == NULL)
4719 // first see if it can be easily done
4720 for (j = i; j > 0 && arg < pp->argc; )
4722 if (g_labels[j] != NULL)
4727 if (po->op == OP_CALL)
4729 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
4731 else if (po->op == OP_POP)
4733 else if (po->flags & OPF_CJMP)
4735 else if (po->op == OP_PUSH) {
4736 if (po->flags & (OPF_FARG|OPF_FARGNR))
4738 if (!g_header_mode) {
4739 ret = scan_for_mod(po, j + 1, i, 1);
4744 if (pp->arg[arg].type.is_va_list)
4748 for (arg++; arg < pp->argc; arg++)
4749 if (pp->arg[arg].reg == NULL)
4752 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4753 && po->operand[1].type == OPT_CONST)
4755 if (po->flags & (OPF_RMD|OPF_DONE))
4757 if (po->operand[1].val != pp->argc_stack * 4)
4758 ferr(po, "unexpected esp adjust: %d\n",
4759 po->operand[1].val * 4);
4760 ferr_assert(po, pp->argc - arg == pp->argc_stack);
4761 return collect_call_args_no_push(i, pp, regmask_ffca);
4769 for (arg = 0; arg < pp->argc; arg++)
4770 if (pp->arg[arg].reg == NULL)
4773 for (j = i; j > 0 && arg < pp->argc; )
4777 if (ops[j].op == OP_PUSH)
4779 ops[j].p_argnext = -1;
4780 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4781 pp->arg[arg].datap = &ops[j];
4783 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
4784 *regmask |= 1 << ops[j].operand[0].reg;
4786 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4787 ops[j].flags &= ~OPF_RSAVE;
4790 for (arg++; arg < pp->argc; arg++)
4791 if (pp->arg[arg].reg == NULL)
4799 static int sync_argnum(struct parsed_op *po, int argnum)
4801 struct parsed_op *po_tmp;
4803 // see if other branches don't have higher argnum
4804 for (po_tmp = po; po_tmp != NULL; ) {
4805 if (argnum < po_tmp->p_argnum)
4806 argnum = po_tmp->p_argnum;
4807 // note: p_argnext is active on current collect_call_args only
4808 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4811 // make all argnums consistent
4812 for (po_tmp = po; po_tmp != NULL; ) {
4813 if (po_tmp->p_argnum != 0)
4814 po_tmp->p_argnum = argnum;
4815 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4821 static int collect_call_args_r(struct parsed_op *po, int i,
4822 struct parsed_proto *pp, int *regmask, int *arg_grp,
4823 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
4825 struct parsed_proto *pp_tmp;
4826 struct parsed_op *po_tmp;
4827 struct label_ref *lr;
4828 int need_to_save_current;
4829 int arg_grp_current = 0;
4830 int save_args_seen = 0;
4837 ferr(po, "dead label encountered\n");
4841 for (; arg < pp->argc; arg++, argnum++)
4842 if (pp->arg[arg].reg == NULL)
4844 magic = (magic & 0xffffff) | (arg << 24);
4846 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4848 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4849 if (ops[j].cc_scratch != magic) {
4850 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4854 // ok: have already been here
4857 ops[j].cc_scratch = magic;
4859 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4860 lr = &g_label_refs[j];
4861 if (lr->next != NULL)
4863 for (; lr->next; lr = lr->next) {
4864 check_i(&ops[j], lr->i);
4865 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4867 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4868 arg, argnum, magic, need_op_saving, may_reuse);
4873 check_i(&ops[j], lr->i);
4874 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4876 if (j > 0 && LAST_OP(j - 1)) {
4877 // follow last branch in reverse
4882 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4883 arg, argnum, magic, need_op_saving, may_reuse);
4889 if (ops[j].op == OP_CALL)
4891 if (pp->is_unresolved)
4896 ferr(po, "arg collect hit unparsed call '%s'\n",
4897 ops[j].operand[0].name);
4898 if (may_reuse && pp_tmp->argc_stack > 0)
4899 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4900 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4902 // esp adjust of 0 means we collected it before
4903 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4904 && (ops[j].operand[1].type != OPT_CONST
4905 || ops[j].operand[1].val != 0))
4907 if (pp->is_unresolved)
4910 fnote(po, "(this call)\n");
4911 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4912 arg, pp->argc, ops[j].operand[1].val);
4914 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4916 if (pp->is_unresolved)
4919 fnote(po, "(this call)\n");
4920 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4922 else if (ops[j].flags & OPF_CJMP)
4924 if (pp->is_unresolved)
4929 else if (ops[j].op == OP_PUSH
4930 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4932 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4935 ops[j].p_argnext = -1;
4936 po_tmp = pp->arg[arg].datap;
4938 ops[j].p_argnext = po_tmp - ops;
4939 pp->arg[arg].datap = &ops[j];
4941 argnum = sync_argnum(&ops[j], argnum);
4943 need_to_save_current = 0;
4945 if (ops[j].operand[0].type == OPT_REG)
4946 reg = ops[j].operand[0].reg;
4948 if (!need_op_saving) {
4949 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4950 need_to_save_current = (ret >= 0);
4952 if (need_op_saving || need_to_save_current) {
4953 // mark this arg as one that needs operand saving
4954 pp->arg[arg].is_saved = 1;
4956 if (save_args_seen & (1 << (argnum - 1))) {
4959 if (arg_grp_current >= MAX_ARG_GRP)
4960 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
4964 else if (ops[j].p_argnum == 0)
4965 ops[j].flags |= OPF_RMD;
4967 // some PUSHes are reused by different calls on other branches,
4968 // but that can't happen if we didn't branch, so they
4969 // can be removed from future searches (handles nested calls)
4971 ops[j].flags |= OPF_FARGNR;
4973 ops[j].flags |= OPF_FARG;
4974 ops[j].flags &= ~OPF_RSAVE;
4976 // check for __VALIST
4977 if (!pp->is_unresolved && g_func_pp != NULL
4978 && pp->arg[arg].type.is_va_list)
4981 ret = resolve_origin(j, &ops[j].operand[0],
4982 magic + 1, &k, NULL);
4983 if (ret == 1 && k >= 0)
4985 if (ops[k].op == OP_LEA) {
4986 if (!g_func_pp->is_vararg)
4987 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
4990 snprintf(buf, sizeof(buf), "arg_%X",
4991 g_func_pp->argc_stack * 4);
4992 if (strstr(ops[k].operand[1].name, buf)
4993 || strstr(ops[k].operand[1].name, "arglist"))
4995 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
4996 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
4997 pp->arg[arg].is_saved = 0;
5001 ferr(&ops[k], "va_list arg detection failed\n");
5003 // check for va_list from g_func_pp arg too
5004 else if (ops[k].op == OP_MOV
5005 && is_stack_access(&ops[k], &ops[k].operand[1]))
5007 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5008 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5010 ops[k].flags |= OPF_RMD | OPF_DONE;
5011 ops[j].flags |= OPF_RMD;
5012 ops[j].p_argpass = ret + 1;
5013 pp->arg[arg].is_saved = 0;
5020 if (pp->arg[arg].is_saved) {
5021 ops[j].flags &= ~OPF_RMD;
5022 ops[j].p_argnum = argnum;
5025 // tracking reg usage
5027 *regmask |= 1 << reg;
5031 if (!pp->is_unresolved) {
5033 for (; arg < pp->argc; arg++, argnum++)
5034 if (pp->arg[arg].reg == NULL)
5037 magic = (magic & 0xffffff) | (arg << 24);
5040 if (ops[j].p_arggrp > arg_grp_current) {
5042 arg_grp_current = ops[j].p_arggrp;
5044 if (ops[j].p_argnum > 0)
5045 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5048 if (arg < pp->argc) {
5049 ferr(po, "arg collect failed for '%s': %d/%d\n",
5050 pp->name, arg, pp->argc);
5054 if (arg_grp_current > *arg_grp)
5055 *arg_grp = arg_grp_current;
5060 static int collect_call_args(struct parsed_op *po, int i,
5061 struct parsed_proto *pp, int *regmask, int magic)
5063 // arg group is for cases when pushes for
5064 // multiple funcs are going on
5065 struct parsed_op *po_tmp;
5070 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5076 // propagate arg_grp
5077 for (a = 0; a < pp->argc; a++) {
5078 if (pp->arg[a].reg != NULL)
5081 po_tmp = pp->arg[a].datap;
5082 while (po_tmp != NULL) {
5083 po_tmp->p_arggrp = arg_grp;
5084 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5089 if (pp->is_unresolved) {
5091 pp->argc_stack += ret;
5092 for (a = 0; a < pp->argc; a++)
5093 if (pp->arg[a].type.name == NULL)
5094 pp->arg[a].type.name = strdup("int");
5100 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5101 int regmask_now, int *regmask,
5102 int regmask_save_now, int *regmask_save,
5103 int *regmask_init, int regmask_arg)
5105 struct parsed_op *po;
5113 for (; i < opcnt; i++)
5116 if (cbits[i >> 3] & (1 << (i & 7)))
5118 cbits[i >> 3] |= (1 << (i & 7));
5120 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5121 if (po->flags & (OPF_RMD|OPF_DONE))
5123 if (po->btj != NULL) {
5124 for (j = 0; j < po->btj->count; j++) {
5125 check_i(po, po->btj->d[j].bt_i);
5126 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5127 regmask_now, regmask, regmask_save_now, regmask_save,
5128 regmask_init, regmask_arg);
5133 check_i(po, po->bt_i);
5134 if (po->flags & OPF_CJMP)
5135 reg_use_pass(po->bt_i, opcnt, cbits,
5136 regmask_now, regmask, regmask_save_now, regmask_save,
5137 regmask_init, regmask_arg);
5143 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5144 && !g_func_pp->is_userstack
5145 && po->operand[0].type == OPT_REG)
5147 reg = po->operand[0].reg;
5148 ferr_assert(po, reg >= 0);
5151 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5152 if (regmask_now & (1 << reg)) {
5153 already_saved = regmask_save_now & (1 << reg);
5154 flags_set = OPF_RSAVE | OPF_DONE;
5157 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5159 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5160 reg, 0, 0, flags_set);
5163 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5165 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5170 ferr_assert(po, !already_saved);
5171 po->flags |= flags_set;
5173 if (regmask_now & (1 << reg)) {
5174 regmask_save_now |= (1 << reg);
5175 *regmask_save |= regmask_save_now;
5180 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5181 reg = po->operand[0].reg;
5182 ferr_assert(po, reg >= 0);
5184 if (regmask_save_now & (1 << reg))
5185 regmask_save_now &= ~(1 << reg);
5187 regmask_now &= ~(1 << reg);
5190 else if (po->op == OP_CALL) {
5191 if ((po->regmask_dst & (1 << xAX))
5192 && !(po->regmask_dst & (1 << xDX)))
5194 if (po->flags & OPF_TAIL)
5195 // don't need eax, will do "return f();" or "f(); return;"
5196 po->regmask_dst &= ~(1 << xAX);
5198 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5200 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5203 po->regmask_dst &= ~(1 << xAX);
5207 // not "full stack" mode and have something in stack
5208 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5209 ferr(po, "float stack is not empty on func call\n");
5212 if (po->flags & OPF_NOREGS)
5215 // if incomplete register is used, clear it on init to avoid
5216 // later use of uninitialized upper part in some situations
5217 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5218 && po->operand[0].lmod != OPLM_DWORD)
5220 reg = po->operand[0].reg;
5221 ferr_assert(po, reg >= 0);
5223 if (!(regmask_now & (1 << reg)))
5224 *regmask_init |= 1 << reg;
5227 regmask_op = po->regmask_src | po->regmask_dst;
5229 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5230 regmask_new &= ~(1 << xSP);
5231 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5232 regmask_new &= ~(1 << xBP);
5234 if (regmask_new != 0)
5235 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5237 if (regmask_op & (1 << xBP)) {
5238 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5239 if (po->regmask_dst & (1 << xBP))
5240 // compiler decided to drop bp frame and use ebp as scratch
5241 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5243 regmask_op &= ~(1 << xBP);
5247 if (po->flags & OPF_FPUSH) {
5248 if (regmask_now & mxST1)
5249 regmask_now |= mxSTa; // switch to "full stack" mode
5250 if (regmask_now & mxSTa)
5251 po->flags |= OPF_FSHIFT;
5252 if (!(regmask_now & mxST7_2)) {
5254 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5258 regmask_now |= regmask_op;
5259 *regmask |= regmask_now;
5262 if (po->flags & OPF_FPOP) {
5263 if ((regmask_now & mxSTa) == 0)
5264 ferr(po, "float pop on empty stack?\n");
5265 if (regmask_now & (mxST7_2 | mxST1))
5266 po->flags |= OPF_FSHIFT;
5267 if (!(regmask_now & mxST7_2)) {
5269 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5273 if (po->flags & OPF_TAIL) {
5274 if (!(regmask_now & mxST7_2)) {
5275 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5276 if (!(regmask_now & mxST0))
5277 ferr(po, "no st0 on float return, mask: %x\n",
5280 else if (regmask_now & mxST1_0)
5281 ferr(po, "float regs on tail: %x\n", regmask_now);
5284 // there is support for "conditional tailcall", sort of
5285 if (!(po->flags & OPF_CC))
5291 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5295 for (i = 0; i < pp->argc; i++)
5296 if (pp->arg[i].reg == NULL)
5300 memmove(&pp->arg[i + 1], &pp->arg[i],
5301 sizeof(pp->arg[0]) * pp->argc_stack);
5302 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5303 pp->arg[i].reg = strdup(reg);
5304 pp->arg[i].type.name = strdup("int");
5309 static void output_std_flags(FILE *fout, struct parsed_op *po,
5310 int *pfomask, const char *dst_opr_text)
5312 if (*pfomask & (1 << PFO_Z)) {
5313 fprintf(fout, "\n cond_z = (%s%s == 0);",
5314 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5315 *pfomask &= ~(1 << PFO_Z);
5317 if (*pfomask & (1 << PFO_S)) {
5318 fprintf(fout, "\n cond_s = (%s%s < 0);",
5319 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5320 *pfomask &= ~(1 << PFO_S);
5325 OPP_FORCE_NORETURN = (1 << 0),
5326 OPP_SIMPLE_ARGS = (1 << 1),
5327 OPP_ALIGN = (1 << 2),
5330 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5333 const char *cconv = "";
5335 if (pp->is_fastcall)
5336 cconv = "__fastcall ";
5337 else if (pp->is_stdcall && pp->argc_reg == 0)
5338 cconv = "__stdcall ";
5340 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5342 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5343 fprintf(fout, "noreturn ");
5346 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5351 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5355 output_pp_attrs(fout, pp, flags);
5358 fprintf(fout, "%s", pp->name);
5363 for (i = 0; i < pp->argc; i++) {
5365 fprintf(fout, ", ");
5366 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5367 && !(flags & OPP_SIMPLE_ARGS))
5370 output_pp(fout, pp->arg[i].pp, 0);
5372 else if (pp->arg[i].type.is_retreg) {
5373 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5376 fprintf(fout, "%s", pp->arg[i].type.name);
5378 fprintf(fout, " a%d", i + 1);
5381 if (pp->is_vararg) {
5383 fprintf(fout, ", ");
5384 fprintf(fout, "...");
5389 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5395 snprintf(buf1, sizeof(buf1), "%d", grp);
5396 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5401 static void gen_x_cleanup(int opcnt);
5403 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5405 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5406 struct parsed_opr *last_arith_dst = NULL;
5407 char buf1[256], buf2[256], buf3[256], cast[64];
5408 struct parsed_proto *pp, *pp_tmp;
5409 struct parsed_data *pd;
5410 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5411 unsigned char cbits[MAX_OPS / 8];
5412 const char *float_type;
5413 const char *float_st0;
5414 const char *float_st1;
5415 int need_float_stack = 0;
5416 int need_float_sw = 0; // status word
5417 int need_tmp_var = 0;
5421 int label_pending = 0;
5422 int need_double = 0;
5423 int regmask_save = 0; // used regs saved/restored in this func
5424 int regmask_arg; // regs from this function args (fastcall, etc)
5425 int regmask_ret; // regs needed on ret
5426 int regmask_now; // temp
5427 int regmask_init = 0; // regs that need zero initialization
5428 int regmask_pp = 0; // regs used in complex push-pop graph
5429 int regmask_ffca = 0; // float function call args
5430 int regmask = 0; // used regs
5440 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5441 g_stack_frame_used = 0;
5442 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5443 regmask_init = g_regmask_init;
5445 g_func_pp = proto_parse(fhdr, funcn, 0);
5446 if (g_func_pp == NULL)
5447 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5449 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5450 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5453 // - resolve all branches
5454 // - parse calls with labels
5455 resolve_branches_parse_calls(opcnt);
5458 // - handle ebp/esp frame, remove ops related to it
5459 scan_prologue_epilogue(opcnt);
5462 // - remove dead labels
5463 // - set regs needed at ret
5464 for (i = 0; i < opcnt; i++)
5466 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5471 if (ops[i].op == OP_RET)
5472 ops[i].regmask_src |= regmask_ret;
5476 // - process trivial calls
5477 for (i = 0; i < opcnt; i++)
5480 if (po->flags & (OPF_RMD|OPF_DONE))
5483 if (po->op == OP_CALL)
5485 pp = process_call_early(i, opcnt, &j);
5487 if (!(po->flags & OPF_ATAIL)) {
5488 // since we know the args, try to collect them
5489 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5497 // commit esp adjust
5498 if (ops[j].op != OP_POP)
5499 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5501 for (l = 0; l < pp->argc_stack; l++)
5502 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5506 if (strstr(pp->ret_type.name, "int64"))
5509 po->flags |= OPF_DONE;
5515 // - process calls, stage 2
5516 // - handle some push/pop pairs
5517 // - scan for STD/CLD, propagate DF
5518 // - try to resolve needed x87 status word bits
5519 for (i = 0; i < opcnt; i++)
5524 if (po->flags & OPF_RMD)
5527 if (po->op == OP_CALL)
5529 if (!(po->flags & OPF_DONE)) {
5530 pp = process_call(i, opcnt);
5532 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5533 // since we know the args, collect them
5534 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5536 // for unresolved, collect after other passes
5540 ferr_assert(po, pp != NULL);
5542 po->regmask_src |= get_pp_arg_regmask_src(pp);
5543 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5545 if (po->regmask_dst & mxST0)
5546 po->flags |= OPF_FPUSH;
5548 if (strstr(pp->ret_type.name, "int64"))
5554 if (po->flags & OPF_DONE)
5559 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
5560 && po->operand[0].type == OPT_CONST)
5562 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5567 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5571 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5572 scan_propagate_df(i + 1, opcnt);
5577 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
5578 ferr(po, "TODO: fnstsw to mem\n");
5579 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
5581 ferr(po, "fnstsw resolve failed\n");
5582 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
5583 (void *)(long)(mask | (z_check << 16)));
5585 ferr(po, "failed to find fcom: %d\n", ret);
5594 // - find POPs for PUSHes, rm both
5595 // - scan for all used registers
5596 memset(cbits, 0, sizeof(cbits));
5597 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5598 0, ®mask_save, ®mask_init, regmask_arg);
5600 need_float_stack = !!(regmask & mxST7_2);
5603 // - find flag set ops for their users
5604 // - do unresolved calls
5605 // - declare indirect functions
5606 // - other op specific processing
5607 for (i = 0; i < opcnt; i++)
5610 if (po->flags & (OPF_RMD|OPF_DONE))
5613 if (po->flags & OPF_CC)
5615 int setters[16], cnt = 0, branched = 0;
5617 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
5618 &branched, setters, &cnt);
5619 if (ret < 0 || cnt <= 0)
5620 ferr(po, "unable to trace flag setter(s)\n");
5621 if (cnt > ARRAY_SIZE(setters))
5622 ferr(po, "too many flag setters\n");
5624 for (j = 0; j < cnt; j++)
5626 tmp_op = &ops[setters[j]]; // flag setter
5629 // to get nicer code, we try to delay test and cmp;
5630 // if we can't because of operand modification, or if we
5631 // have arith op, or branch, make it calculate flags explicitly
5632 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5634 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5635 pfomask = 1 << po->pfo;
5637 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5638 pfomask = 1 << po->pfo;
5641 // see if we'll be able to handle based on op result
5642 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5643 && po->pfo != PFO_Z && po->pfo != PFO_S
5644 && po->pfo != PFO_P)
5646 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5648 pfomask = 1 << po->pfo;
5651 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5652 propagate_lmod(tmp_op, &tmp_op->operand[0],
5653 &tmp_op->operand[1]);
5654 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5659 tmp_op->pfomask |= pfomask;
5660 cond_vars |= pfomask;
5662 // note: may overwrite, currently not a problem
5666 if (po->op == OP_RCL || po->op == OP_RCR
5667 || po->op == OP_ADC || po->op == OP_SBB)
5668 cond_vars |= 1 << PFO_C;
5674 cond_vars |= 1 << PFO_Z;
5678 if (po->operand[0].lmod == OPLM_DWORD)
5683 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
5688 // note: resolved non-reg calls are OPF_DONE already
5690 ferr_assert(po, pp != NULL);
5692 if (pp->is_unresolved) {
5693 int regmask_stack = 0;
5694 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5696 // this is pretty rough guess:
5697 // see ecx and edx were pushed (and not their saved versions)
5698 for (arg = 0; arg < pp->argc; arg++) {
5699 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
5702 tmp_op = pp->arg[arg].datap;
5704 ferr(po, "parsed_op missing for arg%d\n", arg);
5705 if (tmp_op->operand[0].type == OPT_REG)
5706 regmask_stack |= 1 << tmp_op->operand[0].reg;
5709 if (!((regmask_stack & (1 << xCX))
5710 && (regmask_stack & (1 << xDX))))
5712 if (pp->argc_stack != 0
5713 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5715 pp_insert_reg_arg(pp, "ecx");
5716 pp->is_fastcall = 1;
5717 regmask_init |= 1 << xCX;
5718 regmask |= 1 << xCX;
5720 if (pp->argc_stack != 0
5721 || ((regmask | regmask_arg) & (1 << xDX)))
5723 pp_insert_reg_arg(pp, "edx");
5724 regmask_init |= 1 << xDX;
5725 regmask |= 1 << xDX;
5729 // note: __cdecl doesn't fall into is_unresolved category
5730 if (pp->argc_stack > 0)
5736 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
5738 // <var> = offset <something>
5739 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5740 && !IS_START(po->operand[1].name, "off_"))
5742 if (!po->operand[0].pp->is_fptr)
5743 ferr(po, "%s not declared as fptr when it should be\n",
5744 po->operand[0].name);
5745 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5746 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5747 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5748 fnote(po, "var: %s\n", buf1);
5749 fnote(po, "func: %s\n", buf2);
5750 ferr(po, "^ mismatch\n");
5758 if (po->operand[0].lmod == OPLM_DWORD) {
5759 // 32bit division is common, look for it
5760 if (po->op == OP_DIV)
5761 ret = scan_for_reg_clear(i, xDX);
5763 ret = scan_for_cdq_edx(i);
5765 po->flags |= OPF_32BIT;
5774 po->flags |= OPF_RMD | OPF_DONE;
5784 if (po->operand[0].lmod == OPLM_QWORD)
5794 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5796 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5798 po->flags |= OPF_32BIT;
5806 // this might need it's own pass...
5807 if (po->op != OP_FST && po->p_argnum > 0)
5808 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
5810 // correct for "full stack" mode late enable
5811 if ((po->flags & (OPF_PPUSH|OPF_FPOP)) && need_float_stack)
5812 po->flags |= OPF_FSHIFT;
5815 float_type = need_double ? "double" : "float";
5816 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
5817 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
5819 // output starts here
5821 // define userstack size
5822 if (g_func_pp->is_userstack) {
5823 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5824 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5825 fprintf(fout, "#endif\n");
5828 // the function itself
5829 ferr_assert(ops, !g_func_pp->is_fptr);
5830 output_pp(fout, g_func_pp,
5831 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5832 fprintf(fout, "\n{\n");
5834 // declare indirect functions
5835 for (i = 0; i < opcnt; i++) {
5837 if (po->flags & OPF_RMD)
5840 if (po->op == OP_CALL) {
5843 ferr(po, "NULL pp\n");
5845 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5846 if (pp->name[0] != 0) {
5847 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5848 memcpy(pp->name, "i_", 2);
5850 // might be declared already
5852 for (j = 0; j < i; j++) {
5853 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5854 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5864 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5867 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5868 fprintf(fout, ";\n");
5873 // output LUTs/jumptables
5874 for (i = 0; i < g_func_pd_cnt; i++) {
5876 fprintf(fout, " static const ");
5877 if (pd->type == OPT_OFFSET) {
5878 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5880 for (j = 0; j < pd->count; j++) {
5882 fprintf(fout, ", ");
5883 fprintf(fout, "&&%s", pd->d[j].u.label);
5887 fprintf(fout, "%s %s[] =\n { ",
5888 lmod_type_u(ops, pd->lmod), pd->label);
5890 for (j = 0; j < pd->count; j++) {
5892 fprintf(fout, ", ");
5893 fprintf(fout, "%u", pd->d[j].u.val);
5896 fprintf(fout, " };\n");
5900 // declare stack frame, va_arg
5902 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5903 if (g_func_lmods & (1 << OPLM_WORD))
5904 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5905 if (g_func_lmods & (1 << OPLM_BYTE))
5906 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5907 if (g_func_lmods & (1 << OPLM_QWORD))
5908 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5909 fprintf(fout, " } sf;\n");
5913 if (g_func_pp->is_userstack) {
5914 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5915 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5919 if (g_func_pp->is_vararg) {
5920 fprintf(fout, " va_list ap;\n");
5924 // declare arg-registers
5925 for (i = 0; i < g_func_pp->argc; i++) {
5926 if (g_func_pp->arg[i].reg != NULL) {
5927 reg = char_array_i(regs_r32,
5928 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5929 if (regmask & (1 << reg)) {
5930 if (g_func_pp->arg[i].type.is_retreg)
5931 fprintf(fout, " u32 %s = *r_%s;\n",
5932 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5934 fprintf(fout, " u32 %s = (u32)a%d;\n",
5935 g_func_pp->arg[i].reg, i + 1);
5938 if (g_func_pp->arg[i].type.is_retreg)
5939 ferr(ops, "retreg '%s' is unused?\n",
5940 g_func_pp->arg[i].reg);
5941 fprintf(fout, " // %s = a%d; // unused\n",
5942 g_func_pp->arg[i].reg, i + 1);
5948 // declare normal registers
5949 regmask_now = regmask & ~regmask_arg;
5950 regmask_now &= ~(1 << xSP);
5951 if (regmask_now & 0x00ff) {
5952 for (reg = 0; reg < 8; reg++) {
5953 if (regmask_now & (1 << reg)) {
5954 fprintf(fout, " u32 %s", regs_r32[reg]);
5955 if (regmask_init & (1 << reg))
5956 fprintf(fout, " = 0");
5957 fprintf(fout, ";\n");
5963 if (regmask_now & 0xff00) {
5964 for (reg = 8; reg < 16; reg++) {
5965 if (regmask_now & (1 << reg)) {
5966 fprintf(fout, " mmxr %s", regs_r32[reg]);
5967 if (regmask_init & (1 << reg))
5968 fprintf(fout, " = { 0, }");
5969 fprintf(fout, ";\n");
5975 if (need_float_stack) {
5976 fprintf(fout, " %s f_st[8];\n", float_type);
5977 fprintf(fout, " int f_stp = 0;\n");
5981 if (regmask_now & 0xff0000) {
5982 for (reg = 16; reg < 24; reg++) {
5983 if (regmask_now & (1 << reg)) {
5984 fprintf(fout, " %s f_st%d", float_type, reg - 16);
5985 if (regmask_init & (1 << reg))
5986 fprintf(fout, " = 0");
5987 fprintf(fout, ";\n");
5994 if (need_float_sw) {
5995 fprintf(fout, " u16 f_sw;\n");
6000 for (reg = 0; reg < 8; reg++) {
6001 if (regmask_save & (1 << reg)) {
6002 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6008 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6009 if (save_arg_vars[i] == 0)
6011 for (reg = 0; reg < 32; reg++) {
6012 if (save_arg_vars[i] & (1 << reg)) {
6013 fprintf(fout, " u32 %s;\n",
6014 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6021 for (reg = 0; reg < 32; reg++) {
6022 if (regmask_ffca & (1 << reg)) {
6023 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6029 // declare push-pop temporaries
6031 for (reg = 0; reg < 8; reg++) {
6032 if (regmask_pp & (1 << reg)) {
6033 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6040 for (i = 0; i < 8; i++) {
6041 if (cond_vars & (1 << i)) {
6042 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6049 fprintf(fout, " u32 tmp;\n");
6054 fprintf(fout, " u64 tmp64;\n");
6059 fprintf(fout, "\n");
6061 // do stack clear, if needed
6062 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6064 if (g_stack_clear_len != 0) {
6065 if (g_stack_clear_len <= 4) {
6066 for (i = 0; i < g_stack_clear_len; i++)
6067 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6068 fprintf(fout, "0;\n");
6071 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6072 g_stack_clear_start, g_stack_clear_len * 4);
6076 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6079 if (g_func_pp->is_vararg) {
6080 if (g_func_pp->argc_stack == 0)
6081 ferr(ops, "vararg func without stack args?\n");
6082 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6086 for (i = 0; i < opcnt; i++)
6088 if (g_labels[i] != NULL) {
6089 fprintf(fout, "\n%s:\n", g_labels[i]);
6092 delayed_flag_op = NULL;
6093 last_arith_dst = NULL;
6097 if (po->flags & OPF_RMD)
6102 #define assert_operand_cnt(n_) \
6103 if (po->operand_cnt != n_) \
6104 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6106 // conditional/flag using op?
6107 if (po->flags & OPF_CC)
6113 // we go through all this trouble to avoid using parsed_flag_op,
6114 // which makes generated code much nicer
6115 if (delayed_flag_op != NULL)
6117 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6118 po->pfo, po->pfo_inv);
6121 else if (last_arith_dst != NULL
6122 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6123 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6126 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6127 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6128 last_arith_dst->lmod, buf3);
6131 else if (tmp_op != NULL) {
6132 // use preprocessed flag calc results
6133 if (!(tmp_op->pfomask & (1 << po->pfo)))
6134 ferr(po, "not prepared for pfo %d\n", po->pfo);
6136 // note: pfo_inv was not yet applied
6137 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6138 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6141 ferr(po, "all methods of finding comparison failed\n");
6144 if (po->flags & OPF_JMP) {
6145 fprintf(fout, " if %s", buf1);
6147 else if (po->op == OP_RCL || po->op == OP_RCR
6148 || po->op == OP_ADC || po->op == OP_SBB)
6151 fprintf(fout, " cond_%s = %s;\n",
6152 parsed_flag_op_names[po->pfo], buf1);
6154 else if (po->flags & OPF_DATA) { // SETcc
6155 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6156 fprintf(fout, " %s = %s;", buf2, buf1);
6159 ferr(po, "unhandled conditional op\n");
6163 pfomask = po->pfomask;
6168 assert_operand_cnt(2);
6169 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6170 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6171 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6172 fprintf(fout, " %s = %s;", buf1,
6173 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6178 assert_operand_cnt(2);
6179 po->operand[1].lmod = OPLM_DWORD; // always
6180 fprintf(fout, " %s = %s;",
6181 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6182 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6187 assert_operand_cnt(2);
6188 fprintf(fout, " %s = %s;",
6189 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6190 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6194 assert_operand_cnt(2);
6195 switch (po->operand[1].lmod) {
6197 strcpy(buf3, "(s8)");
6200 strcpy(buf3, "(s16)");
6203 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6205 fprintf(fout, " %s = %s;",
6206 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6207 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6212 assert_operand_cnt(2);
6213 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6214 fprintf(fout, " tmp = %s;",
6215 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6216 fprintf(fout, " %s = %s;",
6217 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6218 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6219 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6220 fprintf(fout, " %s = %stmp;",
6221 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6222 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6223 snprintf(g_comment, sizeof(g_comment), "xchg");
6227 assert_operand_cnt(1);
6228 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6229 fprintf(fout, " %s = ~%s;", buf1, buf1);
6233 assert_operand_cnt(2);
6234 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6235 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6236 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6237 strcpy(g_comment, "xlat");
6241 assert_operand_cnt(2);
6242 fprintf(fout, " %s = (s32)%s >> 31;",
6243 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6244 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6245 strcpy(g_comment, "cdq");
6249 assert_operand_cnt(1);
6250 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6251 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6255 if (po->flags & OPF_REP) {
6256 assert_operand_cnt(3);
6261 assert_operand_cnt(2);
6262 fprintf(fout, " %s = %sesi; esi %c= %d;",
6263 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6264 lmod_cast_u_ptr(po, po->operand[1].lmod),
6265 (po->flags & OPF_DF) ? '-' : '+',
6266 lmod_bytes(po, po->operand[1].lmod));
6267 strcpy(g_comment, "lods");
6272 if (po->flags & OPF_REP) {
6273 assert_operand_cnt(3);
6274 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6275 (po->flags & OPF_DF) ? '-' : '+',
6276 lmod_bytes(po, po->operand[1].lmod));
6277 fprintf(fout, " %sedi = eax;",
6278 lmod_cast_u_ptr(po, po->operand[1].lmod));
6279 strcpy(g_comment, "rep stos");
6282 assert_operand_cnt(2);
6283 fprintf(fout, " %sedi = eax; edi %c= %d;",
6284 lmod_cast_u_ptr(po, po->operand[1].lmod),
6285 (po->flags & OPF_DF) ? '-' : '+',
6286 lmod_bytes(po, po->operand[1].lmod));
6287 strcpy(g_comment, "stos");
6292 j = lmod_bytes(po, po->operand[0].lmod);
6293 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6294 l = (po->flags & OPF_DF) ? '-' : '+';
6295 if (po->flags & OPF_REP) {
6296 assert_operand_cnt(3);
6298 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6301 " %sedi = %sesi;", buf1, buf1);
6302 strcpy(g_comment, "rep movs");
6305 assert_operand_cnt(2);
6306 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6307 buf1, buf1, l, j, l, j);
6308 strcpy(g_comment, "movs");
6313 // repe ~ repeat while ZF=1
6314 j = lmod_bytes(po, po->operand[0].lmod);
6315 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6316 l = (po->flags & OPF_DF) ? '-' : '+';
6317 if (po->flags & OPF_REP) {
6318 assert_operand_cnt(3);
6320 " while (ecx != 0) {\n");
6321 if (pfomask & (1 << PFO_C)) {
6324 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6325 pfomask &= ~(1 << PFO_C);
6328 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6329 buf1, buf1, l, j, l, j);
6332 " if (cond_z %s 0) break;\n",
6333 (po->flags & OPF_REPZ) ? "==" : "!=");
6336 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6337 (po->flags & OPF_REPZ) ? "e" : "ne");
6340 assert_operand_cnt(2);
6342 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6343 buf1, buf1, l, j, l, j);
6344 strcpy(g_comment, "cmps");
6346 pfomask &= ~(1 << PFO_Z);
6347 last_arith_dst = NULL;
6348 delayed_flag_op = NULL;
6352 // only does ZF (for now)
6353 // repe ~ repeat while ZF=1
6354 j = lmod_bytes(po, po->operand[1].lmod);
6355 l = (po->flags & OPF_DF) ? '-' : '+';
6356 if (po->flags & OPF_REP) {
6357 assert_operand_cnt(3);
6359 " while (ecx != 0) {\n");
6361 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6362 lmod_cast_u(po, po->operand[1].lmod),
6363 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6366 " if (cond_z %s 0) break;\n",
6367 (po->flags & OPF_REPZ) ? "==" : "!=");
6370 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6371 (po->flags & OPF_REPZ) ? "e" : "ne");
6374 assert_operand_cnt(2);
6375 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6376 lmod_cast_u(po, po->operand[1].lmod),
6377 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6378 strcpy(g_comment, "scas");
6380 pfomask &= ~(1 << PFO_Z);
6381 last_arith_dst = NULL;
6382 delayed_flag_op = NULL;
6385 // arithmetic w/flags
6387 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6388 goto dualop_arith_const;
6389 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6393 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6394 if (po->operand[1].type == OPT_CONST) {
6395 j = lmod_bytes(po, po->operand[0].lmod);
6396 if (((1ull << j * 8) - 1) == po->operand[1].val)
6397 goto dualop_arith_const;
6402 assert_operand_cnt(2);
6403 fprintf(fout, " %s %s= %s;",
6404 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6406 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6407 output_std_flags(fout, po, &pfomask, buf1);
6408 last_arith_dst = &po->operand[0];
6409 delayed_flag_op = NULL;
6413 // and 0, or ~0 used instead mov
6414 assert_operand_cnt(2);
6415 fprintf(fout, " %s = %s;",
6416 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6417 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6418 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6419 output_std_flags(fout, po, &pfomask, buf1);
6420 last_arith_dst = &po->operand[0];
6421 delayed_flag_op = NULL;
6426 assert_operand_cnt(2);
6427 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6428 if (pfomask & (1 << PFO_C)) {
6429 if (po->operand[1].type == OPT_CONST) {
6430 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6431 j = po->operand[1].val;
6434 if (po->op == OP_SHL)
6438 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6442 ferr(po, "zero shift?\n");
6446 pfomask &= ~(1 << PFO_C);
6448 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6449 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6450 if (po->operand[1].type != OPT_CONST)
6451 fprintf(fout, " & 0x1f");
6453 output_std_flags(fout, po, &pfomask, buf1);
6454 last_arith_dst = &po->operand[0];
6455 delayed_flag_op = NULL;
6459 assert_operand_cnt(2);
6460 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6461 fprintf(fout, " %s = %s%s >> %s;", buf1,
6462 lmod_cast_s(po, po->operand[0].lmod), buf1,
6463 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6464 output_std_flags(fout, po, &pfomask, buf1);
6465 last_arith_dst = &po->operand[0];
6466 delayed_flag_op = NULL;
6471 assert_operand_cnt(3);
6472 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6473 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6474 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6475 if (po->operand[2].type != OPT_CONST) {
6476 // no handling for "undefined" case, hopefully not needed
6477 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6480 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6481 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6482 if (po->op == OP_SHLD) {
6483 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6484 buf1, buf3, buf1, buf2, l, buf3);
6485 strcpy(g_comment, "shld");
6488 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6489 buf1, buf3, buf1, buf2, l, buf3);
6490 strcpy(g_comment, "shrd");
6492 output_std_flags(fout, po, &pfomask, buf1);
6493 last_arith_dst = &po->operand[0];
6494 delayed_flag_op = NULL;
6499 assert_operand_cnt(2);
6500 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6501 if (po->operand[1].type == OPT_CONST) {
6502 j = po->operand[1].val;
6503 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6504 fprintf(fout, po->op == OP_ROL ?
6505 " %s = (%s << %d) | (%s >> %d);" :
6506 " %s = (%s >> %d) | (%s << %d);",
6507 buf1, buf1, j, buf1,
6508 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6512 output_std_flags(fout, po, &pfomask, buf1);
6513 last_arith_dst = &po->operand[0];
6514 delayed_flag_op = NULL;
6519 assert_operand_cnt(2);
6520 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6521 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6522 if (po->operand[1].type == OPT_CONST) {
6523 j = po->operand[1].val % l;
6525 ferr(po, "zero rotate\n");
6526 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6527 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6528 if (po->op == OP_RCL) {
6530 " %s = (%s << %d) | (cond_c << %d)",
6531 buf1, buf1, j, j - 1);
6533 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6537 " %s = (%s >> %d) | (cond_c << %d)",
6538 buf1, buf1, j, l - j);
6540 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6542 fprintf(fout, ";\n");
6543 fprintf(fout, " cond_c = tmp;");
6547 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6548 output_std_flags(fout, po, &pfomask, buf1);
6549 last_arith_dst = &po->operand[0];
6550 delayed_flag_op = NULL;
6554 assert_operand_cnt(2);
6555 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6556 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6557 // special case for XOR
6558 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
6559 for (j = 0; j <= PFO_LE; j++) {
6560 if (pfomask & (1 << j)) {
6561 fprintf(fout, " cond_%s = %d;\n",
6562 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
6563 pfomask &= ~(1 << j);
6566 fprintf(fout, " %s = 0;",
6567 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6568 last_arith_dst = &po->operand[0];
6569 delayed_flag_op = NULL;
6575 assert_operand_cnt(2);
6576 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6577 if (pfomask & (1 << PFO_C)) {
6578 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6579 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6580 if (po->operand[0].lmod == OPLM_DWORD) {
6581 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6582 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6583 fprintf(fout, " %s = (u32)tmp64;",
6584 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6585 strcat(g_comment, " add64");
6588 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6589 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6590 fprintf(fout, " %s += %s;",
6591 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6594 pfomask &= ~(1 << PFO_C);
6595 output_std_flags(fout, po, &pfomask, buf1);
6596 last_arith_dst = &po->operand[0];
6597 delayed_flag_op = NULL;
6600 if (pfomask & (1 << PFO_LE)) {
6601 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
6602 fprintf(fout, " cond_%s = %s;\n",
6603 parsed_flag_op_names[PFO_LE], buf1);
6604 pfomask &= ~(1 << PFO_LE);
6609 assert_operand_cnt(2);
6610 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6611 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6612 for (j = 0; j <= PFO_LE; j++) {
6613 if (!(pfomask & (1 << j)))
6615 if (j == PFO_Z || j == PFO_S)
6618 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6619 fprintf(fout, " cond_%s = %s;\n",
6620 parsed_flag_op_names[j], buf1);
6621 pfomask &= ~(1 << j);
6628 assert_operand_cnt(2);
6629 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6630 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6631 if (po->op == OP_SBB
6632 && IS(po->operand[0].name, po->operand[1].name))
6634 // avoid use of unitialized var
6635 fprintf(fout, " %s = -cond_c;", buf1);
6636 // carry remains what it was
6637 pfomask &= ~(1 << PFO_C);
6640 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6641 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6643 output_std_flags(fout, po, &pfomask, buf1);
6644 last_arith_dst = &po->operand[0];
6645 delayed_flag_op = NULL;
6649 assert_operand_cnt(2);
6650 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6651 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6652 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6654 output_std_flags(fout, po, &pfomask, buf1);
6655 last_arith_dst = &po->operand[0];
6656 delayed_flag_op = NULL;
6657 strcat(g_comment, " bsf");
6661 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6662 for (j = 0; j <= PFO_LE; j++) {
6663 if (!(pfomask & (1 << j)))
6665 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6668 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6669 fprintf(fout, " cond_%s = %s;\n",
6670 parsed_flag_op_names[j], buf1);
6671 pfomask &= ~(1 << j);
6677 if (pfomask & (1 << PFO_C))
6678 // carry is unaffected by inc/dec.. wtf?
6679 ferr(po, "carry propagation needed\n");
6681 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6682 if (po->operand[0].type == OPT_REG) {
6683 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6684 fprintf(fout, " %s%s;", buf1, buf2);
6687 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6688 fprintf(fout, " %s %s= 1;", buf1, buf2);
6690 output_std_flags(fout, po, &pfomask, buf1);
6691 last_arith_dst = &po->operand[0];
6692 delayed_flag_op = NULL;
6696 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6697 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6698 fprintf(fout, " %s = -%s%s;", buf1,
6699 lmod_cast_s(po, po->operand[0].lmod), buf2);
6700 last_arith_dst = &po->operand[0];
6701 delayed_flag_op = NULL;
6702 if (pfomask & (1 << PFO_C)) {
6703 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6704 pfomask &= ~(1 << PFO_C);
6709 if (po->operand_cnt == 2) {
6710 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6713 if (po->operand_cnt == 3)
6714 ferr(po, "TODO imul3\n");
6717 assert_operand_cnt(1);
6718 switch (po->operand[0].lmod) {
6720 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6721 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6722 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6723 fprintf(fout, " edx = tmp64 >> 32;\n");
6724 fprintf(fout, " eax = tmp64;");
6727 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6728 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6729 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6733 ferr(po, "TODO: unhandled mul type\n");
6736 last_arith_dst = NULL;
6737 delayed_flag_op = NULL;
6742 assert_operand_cnt(1);
6743 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6744 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6745 po->op == OP_IDIV));
6746 switch (po->operand[0].lmod) {
6748 if (po->flags & OPF_32BIT)
6749 snprintf(buf2, sizeof(buf2), "%seax", cast);
6751 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6752 snprintf(buf2, sizeof(buf2), "%stmp64",
6753 (po->op == OP_IDIV) ? "(s64)" : "");
6755 if (po->operand[0].type == OPT_REG
6756 && po->operand[0].reg == xDX)
6758 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6759 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6762 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6763 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6767 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6768 snprintf(buf2, sizeof(buf2), "%stmp",
6769 (po->op == OP_IDIV) ? "(s32)" : "");
6770 if (po->operand[0].type == OPT_REG
6771 && po->operand[0].reg == xDX)
6773 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6775 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6779 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6781 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6784 strcat(g_comment, " div16");
6787 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6789 last_arith_dst = NULL;
6790 delayed_flag_op = NULL;
6795 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6797 for (j = 0; j < 8; j++) {
6798 if (pfomask & (1 << j)) {
6799 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6800 fprintf(fout, " cond_%s = %s;",
6801 parsed_flag_op_names[j], buf1);
6808 last_arith_dst = NULL;
6809 delayed_flag_op = po;
6813 // SETcc - should already be handled
6816 // note: we reuse OP_Jcc for SETcc, only flags differ
6818 fprintf(fout, "\n goto %s;", po->operand[0].name);
6822 fprintf(fout, " if (ecx == 0)\n");
6823 fprintf(fout, " goto %s;", po->operand[0].name);
6824 strcat(g_comment, " jecxz");
6828 fprintf(fout, " if (--ecx != 0)\n");
6829 fprintf(fout, " goto %s;", po->operand[0].name);
6830 strcat(g_comment, " loop");
6834 assert_operand_cnt(1);
6835 last_arith_dst = NULL;
6836 delayed_flag_op = NULL;
6838 if (po->operand[0].type == OPT_REGMEM) {
6839 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6842 ferr(po, "parse failure for jmp '%s'\n",
6843 po->operand[0].name);
6844 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6847 else if (po->operand[0].type != OPT_LABEL)
6848 ferr(po, "unhandled jmp type\n");
6850 fprintf(fout, " goto %s;", po->operand[0].name);
6854 assert_operand_cnt(1);
6856 my_assert_not(pp, NULL);
6859 if (po->flags & OPF_CC) {
6860 // we treat conditional branch to another func
6861 // (yes such code exists..) as conditional tailcall
6863 fprintf(fout, " {\n");
6866 if (pp->is_fptr && !pp->is_arg) {
6867 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6868 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6870 if (pp->is_unresolved)
6871 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6872 buf3, asmfn, po->asmln, pp->name);
6875 fprintf(fout, "%s", buf3);
6876 if (strstr(pp->ret_type.name, "int64")) {
6877 if (po->flags & OPF_TAIL)
6878 ferr(po, "int64 and tail?\n");
6879 fprintf(fout, "tmp64 = ");
6881 else if (!IS(pp->ret_type.name, "void")) {
6882 if (po->flags & OPF_TAIL) {
6883 if (regmask_ret & mxAX) {
6884 fprintf(fout, "return ");
6885 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6886 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6888 else if (regmask_ret & mxST0)
6889 ferr(po, "float tailcall\n");
6891 else if (po->regmask_dst & mxAX) {
6892 fprintf(fout, "eax = ");
6893 if (pp->ret_type.is_ptr)
6894 fprintf(fout, "(u32)");
6896 else if (po->regmask_dst & mxST0) {
6897 ferr_assert(po, po->flags & OPF_FPUSH);
6898 if (need_float_stack)
6899 fprintf(fout, "f_st[--f_stp & 7] = ");
6901 fprintf(fout, "f_st0 = ");
6905 if (pp->name[0] == 0)
6906 ferr(po, "missing pp->name\n");
6907 fprintf(fout, "%s%s(", pp->name,
6908 pp->has_structarg ? "_sa" : "");
6910 if (po->flags & OPF_ATAIL) {
6911 if (pp->argc_stack != g_func_pp->argc_stack
6912 || (pp->argc_stack > 0
6913 && pp->is_stdcall != g_func_pp->is_stdcall))
6914 ferr(po, "incompatible tailcall\n");
6915 if (g_func_pp->has_retreg)
6916 ferr(po, "TODO: retreg+tailcall\n");
6918 for (arg = j = 0; arg < pp->argc; arg++) {
6920 fprintf(fout, ", ");
6923 if (pp->arg[arg].type.is_ptr)
6924 snprintf(cast, sizeof(cast), "(%s)",
6925 pp->arg[arg].type.name);
6927 if (pp->arg[arg].reg != NULL) {
6928 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6932 for (; j < g_func_pp->argc; j++)
6933 if (g_func_pp->arg[j].reg == NULL)
6935 fprintf(fout, "%sa%d", cast, j + 1);
6940 for (arg = 0; arg < pp->argc; arg++) {
6942 fprintf(fout, ", ");
6945 if (pp->arg[arg].type.is_ptr)
6946 snprintf(cast, sizeof(cast), "(%s)",
6947 pp->arg[arg].type.name);
6949 if (pp->arg[arg].reg != NULL) {
6950 if (pp->arg[arg].type.is_retreg)
6951 fprintf(fout, "&%s", pp->arg[arg].reg);
6952 else if (IS(pp->arg[arg].reg, "ebp")
6953 && !(po->flags & OPF_EBP_S))
6955 // rare special case
6956 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
6957 strcat(g_comment, " bp_ref");
6960 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6965 tmp_op = pp->arg[arg].datap;
6967 ferr(po, "parsed_op missing for arg%d\n", arg);
6969 if (tmp_op->flags & OPF_VAPUSH) {
6970 fprintf(fout, "ap");
6972 else if (tmp_op->op == OP_FST) {
6973 fprintf(fout, "fs_%d", tmp_op->p_argnum);
6974 if (tmp_op->operand[0].lmod == OPLM_QWORD)
6977 else if (tmp_op->p_argpass != 0) {
6978 fprintf(fout, "a%d", tmp_op->p_argpass);
6980 else if (pp->arg[arg].is_saved) {
6981 ferr_assert(po, tmp_op->p_argnum > 0);
6982 fprintf(fout, "%s%s", cast,
6983 saved_arg_name(buf1, sizeof(buf1),
6984 tmp_op->p_arggrp, tmp_op->p_argnum));
6988 out_src_opr(buf1, sizeof(buf1),
6989 tmp_op, &tmp_op->operand[0], cast, 0));
6993 fprintf(fout, ");");
6995 if (strstr(pp->ret_type.name, "int64")) {
6996 fprintf(fout, "\n");
6997 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
6998 fprintf(fout, "%seax = tmp64;", buf3);
7001 if (pp->is_unresolved) {
7002 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7004 strcat(g_comment, buf2);
7007 if (po->flags & OPF_TAIL) {
7009 if (i == opcnt - 1 || pp->is_noreturn)
7011 else if (IS(pp->ret_type.name, "void"))
7013 else if (!(regmask_ret & (1 << xAX)))
7015 // else already handled as 'return f()'
7018 fprintf(fout, "\n%sreturn;", buf3);
7019 strcat(g_comment, " ^ tailcall");
7022 strcat(g_comment, " tailcall");
7024 if ((regmask_ret & (1 << xAX))
7025 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7027 ferr(po, "int func -> void func tailcall?\n");
7030 if (pp->is_noreturn)
7031 strcat(g_comment, " noreturn");
7032 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7033 strcat(g_comment, " argframe");
7034 if (po->flags & OPF_CC)
7035 strcat(g_comment, " cond");
7037 if (po->flags & OPF_CC)
7038 fprintf(fout, "\n }");
7040 delayed_flag_op = NULL;
7041 last_arith_dst = NULL;
7045 if (g_func_pp->is_vararg)
7046 fprintf(fout, " va_end(ap);\n");
7047 if (g_func_pp->has_retreg) {
7048 for (arg = 0; arg < g_func_pp->argc; arg++)
7049 if (g_func_pp->arg[arg].type.is_retreg)
7050 fprintf(fout, " *r_%s = %s;\n",
7051 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7054 if (regmask_ret & mxST0) {
7055 fprintf(fout, " return %s;", float_st0);
7057 else if (!(regmask_ret & mxAX)) {
7058 if (i != opcnt - 1 || label_pending)
7059 fprintf(fout, " return;");
7061 else if (g_func_pp->ret_type.is_ptr) {
7062 fprintf(fout, " return (%s)eax;",
7063 g_func_pp->ret_type.name);
7065 else if (IS(g_func_pp->ret_type.name, "__int64"))
7066 fprintf(fout, " return ((u64)edx << 32) | eax;");
7068 fprintf(fout, " return eax;");
7070 last_arith_dst = NULL;
7071 delayed_flag_op = NULL;
7075 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7076 if (po->p_argnum != 0) {
7077 // special case - saved func arg
7078 fprintf(fout, " %s = %s;",
7079 saved_arg_name(buf2, sizeof(buf2),
7080 po->p_arggrp, po->p_argnum), buf1);
7083 else if (po->flags & OPF_RSAVE) {
7084 fprintf(fout, " s_%s = %s;", buf1, buf1);
7087 else if (po->flags & OPF_PPUSH) {
7089 ferr_assert(po, tmp_op != NULL);
7090 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7091 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7094 else if (g_func_pp->is_userstack) {
7095 fprintf(fout, " *(--esp) = %s;", buf1);
7098 if (!(g_ida_func_attr & IDAFA_NORETURN))
7099 ferr(po, "stray push encountered\n");
7104 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7105 if (po->flags & OPF_RSAVE) {
7106 fprintf(fout, " %s = s_%s;", buf1, buf1);
7109 else if (po->flags & OPF_PPUSH) {
7110 // push/pop graph / non-const
7111 ferr_assert(po, po->datap == NULL);
7112 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7115 else if (po->datap != NULL) {
7118 fprintf(fout, " %s = %s;", buf1,
7119 out_src_opr(buf2, sizeof(buf2),
7120 tmp_op, &tmp_op->operand[0],
7121 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7124 else if (g_func_pp->is_userstack) {
7125 fprintf(fout, " %s = *esp++;", buf1);
7129 ferr(po, "stray pop encountered\n");
7139 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7140 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7141 po->op == OPP_ALLSHL ? "<<" : ">>");
7142 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7143 strcat(g_comment, po->op == OPP_ALLSHL
7144 ? " allshl" : " allshr");
7149 if (need_float_stack) {
7150 out_src_opr_float(buf1, sizeof(buf1),
7151 po, &po->operand[0], 1);
7152 if (po->regmask_src & mxSTa) {
7153 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7157 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7160 if (po->flags & OPF_FSHIFT)
7161 fprintf(fout, " f_st1 = f_st0;");
7162 if (po->operand[0].type == OPT_REG
7163 && po->operand[0].reg == xST0)
7165 strcat(g_comment, " fld st");
7168 fprintf(fout, " f_st0 = %s;",
7169 out_src_opr_float(buf1, sizeof(buf1),
7170 po, &po->operand[0], 0));
7172 strcat(g_comment, " fld");
7176 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7177 lmod_cast(po, po->operand[0].lmod, 1), 0);
7178 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7179 if (need_float_stack) {
7180 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7183 if (po->flags & OPF_FSHIFT)
7184 fprintf(fout, " f_st1 = f_st0;");
7185 fprintf(fout, " f_st0 = %s;", buf2);
7187 strcat(g_comment, " fild");
7191 if (need_float_stack)
7192 fprintf(fout, " f_st[--f_stp & 7] = ");
7194 if (po->flags & OPF_FSHIFT)
7195 fprintf(fout, " f_st1 = f_st0;");
7196 fprintf(fout, " f_st0 = ");
7198 switch (po->operand[0].val) {
7199 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7200 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
7201 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7202 default: ferr(po, "TODO\n"); break;
7207 if (po->flags & OPF_FARG) {
7208 // store to stack as func arg
7209 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7213 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7215 dead_dst = po->operand[0].type == OPT_REG
7216 && po->operand[0].reg == xST0;
7219 fprintf(fout, " %s = %s;", buf1, 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 if (dead_dst && !(po->flags & OPF_FSHIFT))
7229 strcat(g_comment, " fst");
7233 fprintf(fout, " %s = %s%s;",
7234 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7235 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7236 if (po->flags & OPF_FSHIFT) {
7237 if (need_float_stack)
7238 fprintf(fout, " f_stp++;");
7240 fprintf(fout, " f_st0 = f_st1;");
7242 strcat(g_comment, " fist");
7249 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7251 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7253 dead_dst = (po->flags & OPF_FPOP)
7254 && po->operand[0].type == OPT_REG
7255 && po->operand[0].reg == xST0;
7257 case OP_FADD: j = '+'; break;
7258 case OP_FDIV: j = '/'; break;
7259 case OP_FMUL: j = '*'; break;
7260 case OP_FSUB: j = '-'; break;
7261 default: j = 'x'; break;
7263 if (need_float_stack) {
7265 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7266 if (po->flags & OPF_FSHIFT)
7267 fprintf(fout, " f_stp++;");
7270 if (po->flags & OPF_FSHIFT) {
7271 // note: assumes only 2 regs handled
7273 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7275 fprintf(fout, " f_st0 = f_st1;");
7278 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7280 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7285 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7287 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7289 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7291 dead_dst = (po->flags & OPF_FPOP)
7292 && po->operand[0].type == OPT_REG
7293 && po->operand[0].reg == xST0;
7294 j = po->op == OP_FDIVR ? '/' : '-';
7295 if (need_float_stack) {
7297 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7298 if (po->flags & OPF_FSHIFT)
7299 fprintf(fout, " f_stp++;");
7302 if (po->flags & OPF_FSHIFT) {
7304 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7306 fprintf(fout, " f_st0 = f_st1;");
7309 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7311 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7319 case OP_FIADD: j = '+'; break;
7320 case OP_FIDIV: j = '/'; break;
7321 case OP_FIMUL: j = '*'; break;
7322 case OP_FISUB: j = '-'; break;
7323 default: j = 'x'; break;
7325 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7327 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7328 lmod_cast(po, po->operand[0].lmod, 1), 0));
7333 fprintf(fout, " %s = %s %c %s;", float_st0,
7334 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7336 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7341 ferr_assert(po, po->datap != NULL);
7342 mask = (long)po->datap & 0xffff;
7343 z_check = ((long)po->datap >> 16) & 1;
7344 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7346 if (mask == 0x0100) { // C0 -> <
7347 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7350 else if (mask == 0x4000) { // C3 -> =
7351 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7354 else if (mask == 0x4100) { // C3, C0
7356 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7358 strcat(g_comment, " z_chk_det");
7361 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7362 "(%s < %s ? 0x0100 : 0);",
7363 float_st0, buf1, float_st0, buf1);
7367 ferr(po, "unhandled sw mask: %x\n", mask);
7368 if (po->flags & OPF_FSHIFT) {
7369 if (need_float_stack)
7370 fprintf(fout, " f_stp++;");
7372 fprintf(fout, " f_st0 = f_st1;");
7378 fprintf(fout, " %s = f_sw;",
7379 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7383 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7387 fprintf(fout, " %s = cos%s(%s);", float_st0,
7388 need_double ? "" : "f", float_st0);
7392 if (need_float_stack) {
7393 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7394 need_double ? "" : "f", float_st1, float_st0);
7395 fprintf(fout, " f_stp++;");
7398 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7399 need_double ? "" : "f");
7404 if (need_float_stack) {
7405 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7406 float_st1, need_double ? "" : "f", float_st0);
7407 fprintf(fout, " f_stp++;");
7410 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7411 need_double ? "" : "f");
7413 strcat(g_comment, " fyl2x");
7417 fprintf(fout, " %s = sin%s(%s);", float_st0,
7418 need_double ? "" : "f", float_st0);
7422 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7423 need_double ? "" : "f", float_st0);
7427 dead_dst = po->operand[0].type == OPT_REG
7428 && po->operand[0].reg == xST0;
7430 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7432 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7433 float_st0, float_st0, buf1, buf1);
7434 strcat(g_comment, " fxch");
7441 ferr_assert(po, po->flags & OPF_32BIT);
7442 fprintf(fout, " eax = (s32)%s;", float_st0);
7443 if (po->flags & OPF_FSHIFT) {
7444 if (need_float_stack)
7445 fprintf(fout, " f_stp++;");
7447 fprintf(fout, " f_st0 = f_st1;");
7449 strcat(g_comment, " ftol");
7453 if (need_float_stack) {
7454 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
7455 need_double ? "" : "f", float_st1, float_st0);
7456 fprintf(fout, " f_stp++;");
7459 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
7460 need_double ? "" : "f");
7462 strcat(g_comment, " CIpow");
7466 fprintf(fout, " do_skip_code_abort();");
7471 fprintf(fout, " do_emms();");
7476 ferr(po, "unhandled op type %d, flags %x\n",
7481 if (g_comment[0] != 0) {
7482 char *p = g_comment;
7483 while (my_isblank(*p))
7485 fprintf(fout, " // %s", p);
7490 fprintf(fout, "\n");
7492 // some sanity checking
7493 if (po->flags & OPF_REP) {
7494 if (po->op != OP_STOS && po->op != OP_MOVS
7495 && po->op != OP_CMPS && po->op != OP_SCAS)
7496 ferr(po, "unexpected rep\n");
7497 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7498 && (po->op == OP_CMPS || po->op == OP_SCAS))
7499 ferr(po, "cmps/scas with plain rep\n");
7501 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7502 && po->op != OP_CMPS && po->op != OP_SCAS)
7503 ferr(po, "unexpected repz/repnz\n");
7506 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
7508 // see is delayed flag stuff is still valid
7509 if (delayed_flag_op != NULL && delayed_flag_op != po) {
7510 if (is_any_opr_modified(delayed_flag_op, po, 0))
7511 delayed_flag_op = NULL;
7514 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7515 if (is_opr_modified(last_arith_dst, po))
7516 last_arith_dst = NULL;
7522 if (g_stack_fsz && !g_stack_frame_used)
7523 fprintf(fout, " (void)sf;\n");
7525 fprintf(fout, "}\n\n");
7527 gen_x_cleanup(opcnt);
7530 static void gen_x_cleanup(int opcnt)
7534 for (i = 0; i < opcnt; i++) {
7535 struct label_ref *lr, *lr_del;
7537 lr = g_label_refs[i].next;
7538 while (lr != NULL) {
7543 g_label_refs[i].i = -1;
7544 g_label_refs[i].next = NULL;
7546 if (ops[i].op == OP_CALL) {
7548 proto_release(ops[i].pp);
7554 struct func_proto_dep;
7556 struct func_prototype {
7561 int has_ret:3; // -1, 0, 1: unresolved, no, yes
7562 unsigned int dep_resolved:1;
7563 unsigned int is_stdcall:1;
7564 struct func_proto_dep *dep_func;
7566 const struct parsed_proto *pp; // seed pp, if any
7569 struct func_proto_dep {
7571 struct func_prototype *proto;
7572 int regmask_live; // .. at the time of call
7573 unsigned int ret_dep:1; // return from this is caller's return
7576 static struct func_prototype *hg_fp;
7577 static int hg_fp_cnt;
7579 static struct scanned_var {
7581 enum opr_lenmod lmod;
7582 unsigned int is_seeded:1;
7583 unsigned int is_c_str:1;
7584 const struct parsed_proto *pp; // seed pp, if any
7586 static int hg_var_cnt;
7588 static char **hg_refs;
7589 static int hg_ref_cnt;
7591 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7594 static struct func_prototype *hg_fp_add(const char *funcn)
7596 struct func_prototype *fp;
7598 if ((hg_fp_cnt & 0xff) == 0) {
7599 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7600 my_assert_not(hg_fp, NULL);
7601 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7604 fp = &hg_fp[hg_fp_cnt];
7605 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7607 fp->argc_stack = -1;
7613 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7618 for (i = 0; i < fp->dep_func_cnt; i++)
7619 if (IS(fp->dep_func[i].name, name))
7620 return &fp->dep_func[i];
7625 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7628 if (hg_fp_find_dep(fp, name))
7631 if ((fp->dep_func_cnt & 0xff) == 0) {
7632 fp->dep_func = realloc(fp->dep_func,
7633 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7634 my_assert_not(fp->dep_func, NULL);
7635 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7636 sizeof(fp->dep_func[0]) * 0x100);
7638 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7642 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7644 const struct func_prototype *p1 = p1_, *p2 = p2_;
7645 return strcmp(p1->name, p2->name);
7649 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7651 const struct func_prototype *p1 = p1_, *p2 = p2_;
7652 return p1->id - p2->id;
7656 static void hg_ref_add(const char *name)
7658 if ((hg_ref_cnt & 0xff) == 0) {
7659 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7660 my_assert_not(hg_refs, NULL);
7661 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7664 hg_refs[hg_ref_cnt] = strdup(name);
7665 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7669 // recursive register dep pass
7670 // - track saved regs (part 2)
7671 // - try to figure out arg-regs
7672 // - calculate reg deps
7673 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
7674 struct func_prototype *fp, int regmask_save, int regmask_dst,
7675 int *regmask_dep, int *has_ret)
7677 struct func_proto_dep *dep;
7678 struct parsed_op *po;
7679 int from_caller = 0;
7684 for (; i < opcnt; i++)
7686 if (cbits[i >> 3] & (1 << (i & 7)))
7688 cbits[i >> 3] |= (1 << (i & 7));
7692 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
7693 if (po->flags & OPF_RMD)
7696 if (po->btj != NULL) {
7698 for (j = 0; j < po->btj->count; j++) {
7699 check_i(po, po->btj->d[j].bt_i);
7700 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
7701 regmask_save, regmask_dst, regmask_dep, has_ret);
7706 check_i(po, po->bt_i);
7707 if (po->flags & OPF_CJMP) {
7708 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
7709 regmask_save, regmask_dst, regmask_dep, has_ret);
7717 if (po->flags & OPF_FARG)
7718 /* (just calculate register deps) */;
7719 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
7721 reg = po->operand[0].reg;
7722 ferr_assert(po, reg >= 0);
7724 if (po->flags & OPF_RSAVE) {
7725 regmask_save |= 1 << reg;
7728 if (po->flags & OPF_DONE)
7731 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
7733 regmask_save |= 1 << reg;
7734 po->flags |= OPF_RMD;
7735 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
7739 else if (po->flags & OPF_RMD)
7741 else if (po->op == OP_CALL) {
7742 po->regmask_dst |= 1 << xAX;
7744 dep = hg_fp_find_dep(fp, po->operand[0].name);
7746 dep->regmask_live = regmask_save | regmask_dst;
7748 else if (po->op == OP_RET) {
7749 if (po->operand_cnt > 0) {
7751 if (fp->argc_stack >= 0
7752 && fp->argc_stack != po->operand[0].val / 4)
7753 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
7754 fp->argc_stack = po->operand[0].val / 4;
7758 // if has_ret is 0, there is uninitialized eax path,
7759 // which means it's most likely void func
7760 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
7761 if (po->op == OP_CALL) {
7766 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
7769 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
7772 if (ret != 1 && from_caller) {
7773 // unresolved eax - probably void func
7777 if (j >= 0 && ops[j].op == OP_CALL) {
7778 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
7789 l = regmask_save | regmask_dst;
7790 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7793 l = po->regmask_src & ~l;
7796 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
7797 l, regmask_dst, regmask_save, po->flags);
7800 regmask_dst |= po->regmask_dst;
7802 if (po->flags & OPF_TAIL)
7807 static void gen_hdr(const char *funcn, int opcnt)
7809 unsigned char cbits[MAX_OPS / 8];
7810 const struct parsed_proto *pp_c;
7811 struct parsed_proto *pp;
7812 struct func_prototype *fp;
7813 struct parsed_op *po;
7814 int regmask_dummy = 0;
7816 int max_bp_offset = 0;
7821 pp_c = proto_parse(g_fhdr, funcn, 1);
7823 // already in seed, will add to hg_fp later
7826 fp = hg_fp_add(funcn);
7828 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7829 g_stack_frame_used = 0;
7832 // - resolve all branches
7833 // - parse calls with labels
7834 resolve_branches_parse_calls(opcnt);
7837 // - handle ebp/esp frame, remove ops related to it
7838 scan_prologue_epilogue(opcnt);
7841 // - remove dead labels
7843 for (i = 0; i < opcnt; i++)
7845 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7851 if (po->flags & (OPF_RMD|OPF_DONE))
7854 if (po->op == OP_CALL) {
7855 if (po->operand[0].type == OPT_LABEL)
7856 hg_fp_add_dep(fp, opr_name(po, 0));
7857 else if (po->pp != NULL)
7858 hg_fp_add_dep(fp, po->pp->name);
7863 // - remove dead labels
7864 // - handle push <const>/pop pairs
7865 for (i = 0; i < opcnt; i++)
7867 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7873 if (po->flags & (OPF_RMD|OPF_DONE))
7876 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
7877 scan_for_pop_const(i, opcnt, i + opcnt * 13);
7881 // - process trivial calls
7882 for (i = 0; i < opcnt; i++)
7885 if (po->flags & (OPF_RMD|OPF_DONE))
7888 if (po->op == OP_CALL)
7890 pp = process_call_early(i, opcnt, &j);
7892 if (!(po->flags & OPF_ATAIL))
7893 // since we know the args, try to collect them
7894 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
7900 // commit esp adjust
7901 if (ops[j].op != OP_POP)
7902 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
7904 for (l = 0; l < pp->argc_stack; l++)
7905 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
7909 po->flags |= OPF_DONE;
7915 // - track saved regs (simple)
7917 for (i = 0; i < opcnt; i++)
7920 if (po->flags & (OPF_RMD|OPF_DONE))
7923 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7924 && po->operand[0].reg != xCX)
7926 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
7928 // regmask_save |= 1 << po->operand[0].reg; // do it later
7929 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
7930 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
7933 else if (po->op == OP_CALL)
7935 pp = process_call(i, opcnt);
7937 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
7938 // since we know the args, collect them
7939 ret = collect_call_args(po, i, pp, ®mask_dummy,
7946 memset(cbits, 0, sizeof(cbits));
7950 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
7952 // find unreachable code - must be fixed in IDA
7953 for (i = 0; i < opcnt; i++)
7955 if (cbits[i >> 3] & (1 << (i & 7)))
7958 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
7959 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
7961 // the compiler sometimes still generates code after
7962 // noreturn OS functions
7965 if (ops[i].op != OP_NOP)
7966 ferr(&ops[i], "unreachable code\n");
7969 for (i = 0; i < g_eqcnt; i++) {
7970 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
7971 max_bp_offset = g_eqs[i].offset;
7974 if (fp->argc_stack < 0) {
7975 max_bp_offset = (max_bp_offset + 3) & ~3;
7976 fp->argc_stack = max_bp_offset / 4;
7977 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
7981 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
7982 fp->has_ret = has_ret;
7984 printf("// has_ret %d, regmask_dep %x\n",
7985 fp->has_ret, fp->regmask_dep);
7986 output_hdr_fp(stdout, fp, 1);
7987 if (IS(funcn, "sub_10007F72")) exit(1);
7990 gen_x_cleanup(opcnt);
7993 static void hg_fp_resolve_deps(struct func_prototype *fp)
7995 struct func_prototype fp_s;
7999 // this thing is recursive, so mark first..
8000 fp->dep_resolved = 1;
8002 for (i = 0; i < fp->dep_func_cnt; i++) {
8003 strcpy(fp_s.name, fp->dep_func[i].name);
8004 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8005 sizeof(hg_fp[0]), hg_fp_cmp_name);
8006 if (fp->dep_func[i].proto != NULL) {
8007 if (!fp->dep_func[i].proto->dep_resolved)
8008 hg_fp_resolve_deps(fp->dep_func[i].proto);
8010 dep = ~fp->dep_func[i].regmask_live
8011 & fp->dep_func[i].proto->regmask_dep;
8012 fp->regmask_dep |= dep;
8013 // printf("dep %s %s |= %x\n", fp->name,
8014 // fp->dep_func[i].name, dep);
8016 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8017 fp->has_ret = fp->dep_func[i].proto->has_ret;
8022 // make all thiscall/edx arg functions referenced from .data fastcall
8023 static void do_func_refs_from_data(void)
8025 struct func_prototype *fp, fp_s;
8028 for (i = 0; i < hg_ref_cnt; i++) {
8029 strcpy(fp_s.name, hg_refs[i]);
8030 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8031 sizeof(hg_fp[0]), hg_fp_cmp_name);
8035 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8036 fp->regmask_dep |= mxCX | mxDX;
8040 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8043 const struct parsed_proto *pp;
8044 char *p, namebuf[NAMELEN];
8050 for (; count > 0; count--, fp++) {
8051 if (fp->has_ret == -1)
8052 fprintf(fout, "// ret unresolved\n");
8054 fprintf(fout, "// dep:");
8055 for (j = 0; j < fp->dep_func_cnt; j++) {
8056 fprintf(fout, " %s/", fp->dep_func[j].name);
8057 if (fp->dep_func[j].proto != NULL)
8058 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8059 fp->dep_func[j].proto->has_ret);
8061 fprintf(fout, "\n");
8064 p = strchr(fp->name, '@');
8066 memcpy(namebuf, fp->name, p - fp->name);
8067 namebuf[p - fp->name] = 0;
8075 pp = proto_parse(g_fhdr, name, 1);
8076 if (pp != NULL && pp->is_include)
8079 if (fp->pp != NULL) {
8080 // part of seed, output later
8084 regmask_dep = fp->regmask_dep;
8085 argc_normal = fp->argc_stack;
8087 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8088 (fp->has_ret ? "int" : "void"));
8089 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8090 && (regmask_dep & ~mxCX) == 0)
8092 fprintf(fout, "/*__thiscall*/ ");
8096 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8097 && (regmask_dep & ~(mxCX | mxDX)) == 0)
8099 fprintf(fout, " __fastcall ");
8100 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8106 else if (regmask_dep && !fp->is_stdcall) {
8107 fprintf(fout, "/*__usercall*/ ");
8109 else if (regmask_dep) {
8110 fprintf(fout, "/*__userpurge*/ ");
8112 else if (fp->is_stdcall)
8113 fprintf(fout, " __stdcall ");
8115 fprintf(fout, " __cdecl ");
8117 fprintf(fout, "%s(", name);
8120 for (j = 0; j < xSP; j++) {
8121 if (regmask_dep & (1 << j)) {
8124 fprintf(fout, ", ");
8126 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8128 fprintf(fout, "int");
8129 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8133 for (j = 0; j < argc_normal; j++) {
8136 fprintf(fout, ", ");
8137 if (fp->pp != NULL) {
8138 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8139 if (!fp->pp->arg[arg - 1].type.is_ptr)
8143 fprintf(fout, "int ");
8144 fprintf(fout, "a%d", arg);
8147 fprintf(fout, ");\n");
8151 static void output_hdr(FILE *fout)
8153 static const char *lmod_c_names[] = {
8154 [OPLM_UNSPEC] = "???",
8155 [OPLM_BYTE] = "uint8_t",
8156 [OPLM_WORD] = "uint16_t",
8157 [OPLM_DWORD] = "uint32_t",
8158 [OPLM_QWORD] = "uint64_t",
8160 const struct scanned_var *var;
8161 struct func_prototype *fp;
8162 char line[256] = { 0, };
8166 // add stuff from headers
8167 for (i = 0; i < pp_cache_size; i++) {
8168 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8169 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8171 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8172 fp = hg_fp_add(name);
8173 fp->pp = &pp_cache[i];
8174 fp->argc_stack = fp->pp->argc_stack;
8175 fp->is_stdcall = fp->pp->is_stdcall;
8176 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8177 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8181 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8182 for (i = 0; i < hg_fp_cnt; i++)
8183 hg_fp_resolve_deps(&hg_fp[i]);
8185 // adjust functions referenced from data segment
8186 do_func_refs_from_data();
8188 // note: messes up .proto ptr, don't use
8189 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8192 for (i = 0; i < hg_var_cnt; i++) {
8195 if (var->pp != NULL)
8198 else if (var->is_c_str)
8199 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8201 fprintf(fout, "extern %-8s %s;",
8202 lmod_c_names[var->lmod], var->name);
8205 fprintf(fout, " // seeded");
8206 fprintf(fout, "\n");
8209 fprintf(fout, "\n");
8211 // output function prototypes
8212 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8215 fprintf(fout, "\n// - seed -\n");
8218 while (fgets(line, sizeof(line), g_fhdr))
8219 fwrite(line, 1, strlen(line), fout);
8222 // '=' needs special treatment
8224 static char *next_word_s(char *w, size_t wsize, char *s)
8231 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8233 for (i = 1; i < wsize - 1; i++) {
8235 printf("warning: missing closing quote: \"%s\"\n", s);
8244 for (; i < wsize - 1; i++) {
8245 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8251 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8252 printf("warning: '%s' truncated\n", w);
8257 static int cmpstringp(const void *p1, const void *p2)
8259 return strcmp(*(char * const *)p1, *(char * const *)p2);
8262 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8267 if (strstr(p, "..."))
8268 // unable to determine, assume needed
8271 if (*p == '.') // .text, .data, ...
8272 // ref from other data or non-function -> no
8275 p2 = strpbrk(p, "+:\r\n\x18");
8278 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8279 // referenced from removed code
8285 static int ida_xrefs_show_need(FILE *fasm, char *p,
8286 char **rlist, int rlist_len)
8292 p = strrchr(p, ';');
8293 if (p != NULL && *p == ';' && IS_START(p + 2, "DATA XREF: ")) {
8295 if (is_xref_needed(p, rlist, rlist_len))
8302 if (!my_fgets(line, sizeof(line), fasm))
8304 // non-first line is always indented
8305 if (!my_isblank(line[0]))
8308 // should be no content, just comment
8313 p = strrchr(p, ';');
8315 // it's printed once, but no harm to check again
8316 if (IS_START(p, "DATA XREF: "))
8319 if (is_xref_needed(p, rlist, rlist_len)) {
8324 fseek(fasm, pos, SEEK_SET);
8328 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8330 struct scanned_var *var;
8331 char line[256] = { 0, };
8340 // skip to next data section
8341 while (my_fgets(line, sizeof(line), fasm))
8346 if (*p == 0 || *p == ';')
8349 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8350 if (*p == 0 || *p == ';')
8353 if (*p != 's' || !IS_START(p, "segment para public"))
8359 if (p == NULL || !IS_START(p, "segment para public"))
8363 if (!IS_START(p, "'DATA'"))
8367 while (my_fgets(line, sizeof(line), fasm))
8372 no_identifier = my_isblank(*p);
8375 if (*p == 0 || *p == ';')
8378 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8379 words[wordc][0] = 0;
8380 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8381 if (*p == 0 || *p == ';') {
8387 if (wordc == 2 && IS(words[1], "ends"))
8392 if (no_identifier) {
8393 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8394 hg_ref_add(words[2]);
8398 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8399 // when this starts, we don't need anything from this section
8403 // check refs comment(s)
8404 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8407 if ((hg_var_cnt & 0xff) == 0) {
8408 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8409 * (hg_var_cnt + 0x100));
8410 my_assert_not(hg_vars, NULL);
8411 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8414 var = &hg_vars[hg_var_cnt++];
8415 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8417 // maybe already in seed header?
8418 var->pp = proto_parse(g_fhdr, var->name, 1);
8419 if (var->pp != NULL) {
8420 if (var->pp->is_fptr) {
8421 var->lmod = OPLM_DWORD;
8424 else if (var->pp->is_func)
8426 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8427 aerr("unhandled C type '%s' for '%s'\n",
8428 var->pp->type.name, var->name);
8434 if (IS(words[1], "dd")) {
8435 var->lmod = OPLM_DWORD;
8436 if (wordc >= 4 && IS(words[2], "offset"))
8437 hg_ref_add(words[3]);
8439 else if (IS(words[1], "dw"))
8440 var->lmod = OPLM_WORD;
8441 else if (IS(words[1], "db")) {
8442 var->lmod = OPLM_BYTE;
8443 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8444 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8448 else if (IS(words[1], "dq"))
8449 var->lmod = OPLM_QWORD;
8450 //else if (IS(words[1], "dt"))
8452 aerr("type '%s' not known\n", words[1]);
8460 static void set_label(int i, const char *name)
8466 p = strchr(name, ':');
8470 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8471 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8472 g_labels[i] = realloc(g_labels[i], len + 1);
8473 my_assert_not(g_labels[i], NULL);
8474 memcpy(g_labels[i], name, len);
8475 g_labels[i][len] = 0;
8484 static struct chunk_item *func_chunks;
8485 static int func_chunk_cnt;
8486 static int func_chunk_alloc;
8488 static void add_func_chunk(FILE *fasm, const char *name, int line)
8490 if (func_chunk_cnt >= func_chunk_alloc) {
8491 func_chunk_alloc *= 2;
8492 func_chunks = realloc(func_chunks,
8493 func_chunk_alloc * sizeof(func_chunks[0]));
8494 my_assert_not(func_chunks, NULL);
8496 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8497 func_chunks[func_chunk_cnt].name = strdup(name);
8498 func_chunks[func_chunk_cnt].asmln = line;
8502 static int cmp_chunks(const void *p1, const void *p2)
8504 const struct chunk_item *c1 = p1, *c2 = p2;
8505 return strcmp(c1->name, c2->name);
8508 static void scan_ahead(FILE *fasm)
8518 oldpos = ftell(fasm);
8521 while (my_fgets(line, sizeof(line), fasm))
8532 // get rid of random tabs
8533 for (i = 0; line[i] != 0; i++)
8534 if (line[i] == '\t')
8537 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8540 next_word(words[0], sizeof(words[0]), p);
8541 if (words[0][0] == 0)
8542 aerr("missing name for func chunk?\n");
8544 add_func_chunk(fasm, words[0], asmln);
8546 else if (IS_START(p, "; sctend"))
8552 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8553 words[wordc][0] = 0;
8554 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8555 if (*p == 0 || *p == ';') {
8561 if (wordc == 2 && IS(words[1], "ends"))
8565 fseek(fasm, oldpos, SEEK_SET);
8569 int main(int argc, char *argv[])
8571 FILE *fout, *fasm, *frlist;
8572 struct parsed_data *pd = NULL;
8574 char **rlist = NULL;
8576 int rlist_alloc = 0;
8577 int func_chunks_used = 0;
8578 int func_chunks_sorted = 0;
8579 int func_chunk_i = -1;
8580 long func_chunk_ret = 0;
8581 int func_chunk_ret_ln = 0;
8582 int scanned_ahead = 0;
8584 char words[20][256];
8585 enum opr_lenmod lmod;
8586 char *sctproto = NULL;
8588 int pending_endp = 0;
8590 int skip_code_end = 0;
8591 int skip_warned = 0;
8604 for (arg = 1; arg < argc; arg++) {
8605 if (IS(argv[arg], "-v"))
8607 else if (IS(argv[arg], "-rf"))
8608 g_allow_regfunc = 1;
8609 else if (IS(argv[arg], "-uc"))
8610 g_allow_user_icall = 1;
8611 else if (IS(argv[arg], "-m"))
8613 else if (IS(argv[arg], "-hdr"))
8614 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8619 if (argc < arg + 3) {
8620 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8621 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8623 " -hdr - header generation mode\n"
8624 " -rf - allow unannotated indirect calls\n"
8625 " -uc - allow ind. calls/refs to __usercall\n"
8626 " -m - allow multiple .text sections\n"
8627 "[rlist] is a file with function names to skip,"
8635 asmfn = argv[arg++];
8636 fasm = fopen(asmfn, "r");
8637 my_assert_not(fasm, NULL);
8639 hdrfn = argv[arg++];
8640 g_fhdr = fopen(hdrfn, "r");
8641 my_assert_not(g_fhdr, NULL);
8644 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8645 my_assert_not(rlist, NULL);
8646 // needs special handling..
8647 rlist[rlist_len++] = "__alloca_probe";
8649 func_chunk_alloc = 32;
8650 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8651 my_assert_not(func_chunks, NULL);
8653 memset(words, 0, sizeof(words));
8655 for (; arg < argc; arg++) {
8658 frlist = fopen(argv[arg], "r");
8659 my_assert_not(frlist, NULL);
8661 while (my_fgets(line, sizeof(line), frlist)) {
8663 if (*p == 0 || *p == ';')
8666 if (IS_START(p, "#if 0")
8667 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
8671 else if (IS_START(p, "#endif"))
8678 p = next_word(words[0], sizeof(words[0]), p);
8679 if (words[0][0] == 0)
8682 if (rlist_len >= rlist_alloc) {
8683 rlist_alloc = rlist_alloc * 2 + 64;
8684 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
8685 my_assert_not(rlist, NULL);
8687 rlist[rlist_len++] = strdup(words[0]);
8695 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
8697 fout = fopen(argv[arg_out], "w");
8698 my_assert_not(fout, NULL);
8701 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
8702 my_assert_not(g_eqs, NULL);
8704 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
8705 g_label_refs[i].i = -1;
8706 g_label_refs[i].next = NULL;
8710 scan_variables(fasm, rlist, rlist_len);
8712 while (my_fgets(line, sizeof(line), fasm))
8721 // get rid of random tabs
8722 for (i = 0; line[i] != 0; i++)
8723 if (line[i] == '\t')
8728 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
8729 goto do_pending_endp; // eww..
8731 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
8733 static const char *attrs[] = {
8742 // parse IDA's attribute-list comment
8743 g_ida_func_attr = 0;
8746 for (; *p != 0; p = sskip(p)) {
8747 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8748 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8749 g_ida_func_attr |= 1 << i;
8750 p += strlen(attrs[i]);
8754 if (i == ARRAY_SIZE(attrs)) {
8755 anote("unparsed IDA attr: %s\n", p);
8758 if (IS(attrs[i], "fpd=")) {
8759 p = next_word(words[0], sizeof(words[0]), p);
8764 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
8766 static const char *attrs[] = {
8771 // parse manual attribute-list comment
8772 g_sct_func_attr = 0;
8775 for (; *p != 0; p = sskip(p)) {
8776 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8777 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8778 g_sct_func_attr |= 1 << i;
8779 p += strlen(attrs[i]);
8786 // clear_sf=start,len (in dwords)
8787 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
8788 &g_stack_clear_len, &j);
8790 // clear_regmask=<mask>
8791 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
8793 anote("unparsed attr value: %s\n", p);
8798 else if (i == ARRAY_SIZE(attrs)) {
8799 anote("unparsed sct attr: %s\n", p);
8804 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8807 next_word(words[0], sizeof(words[0]), p);
8808 if (words[0][0] == 0)
8809 aerr("missing name for func chunk?\n");
8811 if (!scanned_ahead) {
8812 add_func_chunk(fasm, words[0], asmln);
8813 func_chunks_sorted = 0;
8816 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
8818 if (func_chunk_i >= 0) {
8819 if (func_chunk_i < func_chunk_cnt
8820 && IS(func_chunks[func_chunk_i].name, g_func))
8822 // move on to next chunk
8823 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8825 aerr("seek failed for '%s' chunk #%d\n",
8826 g_func, func_chunk_i);
8827 asmln = func_chunks[func_chunk_i].asmln;
8831 if (func_chunk_ret == 0)
8832 aerr("no return from chunk?\n");
8833 fseek(fasm, func_chunk_ret, SEEK_SET);
8834 asmln = func_chunk_ret_ln;
8840 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
8841 func_chunks_used = 1;
8843 if (IS_START(g_func, "sub_")) {
8844 unsigned long addr = strtoul(p, NULL, 16);
8845 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
8846 if (addr > f_addr && !scanned_ahead) {
8847 //anote("scan_ahead caused by '%s', addr %lx\n",
8851 func_chunks_sorted = 0;
8859 for (i = wordc; i < ARRAY_SIZE(words); i++)
8861 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8862 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8863 if (*p == 0 || *p == ';') {
8868 if (*p != 0 && *p != ';')
8869 aerr("too many words\n");
8871 if (skip_code_end) {
8876 // allow asm patches in comments
8878 if (IS_START(p, "; sctpatch:")) {
8880 if (*p == 0 || *p == ';')
8882 goto parse_words; // lame
8884 if (IS_START(p, "; sctproto:")) {
8885 sctproto = strdup(p + 11);
8887 else if (IS_START(p, "; sctend")) {
8892 else if (IS_START(p, "; sctskip_start")) {
8893 if (in_func && !g_skip_func) {
8895 ops[pi].op = OPP_ABORT;
8896 ops[pi].asmln = asmln;
8902 else if (IS_START(p, "; sctskip_end")) {
8910 awarn("wordc == 0?\n");
8914 // don't care about this:
8915 if (words[0][0] == '.'
8916 || IS(words[0], "include")
8917 || IS(words[0], "assume") || IS(words[1], "segment")
8918 || IS(words[0], "align"))
8924 // do delayed endp processing to collect switch jumptables
8926 if (in_func && !g_skip_func && !end && wordc >= 2
8927 && ((words[0][0] == 'd' && words[0][2] == 0)
8928 || (words[1][0] == 'd' && words[1][2] == 0)))
8931 if (words[1][0] == 'd' && words[1][2] == 0) {
8933 if (g_func_pd_cnt >= pd_alloc) {
8934 pd_alloc = pd_alloc * 2 + 16;
8935 g_func_pd = realloc(g_func_pd,
8936 sizeof(g_func_pd[0]) * pd_alloc);
8937 my_assert_not(g_func_pd, NULL);
8939 pd = &g_func_pd[g_func_pd_cnt];
8941 memset(pd, 0, sizeof(*pd));
8942 strcpy(pd->label, words[0]);
8943 pd->type = OPT_CONST;
8944 pd->lmod = lmod_from_directive(words[1]);
8950 anote("skipping alignment byte?\n");
8953 lmod = lmod_from_directive(words[0]);
8954 if (lmod != pd->lmod)
8955 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
8958 if (pd->count_alloc < pd->count + wordc) {
8959 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
8960 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
8961 my_assert_not(pd->d, NULL);
8963 for (; i < wordc; i++) {
8964 if (IS(words[i], "offset")) {
8965 pd->type = OPT_OFFSET;
8968 p = strchr(words[i], ',');
8971 if (pd->type == OPT_OFFSET)
8972 pd->d[pd->count].u.label = strdup(words[i]);
8974 pd->d[pd->count].u.val = parse_number(words[i]);
8975 pd->d[pd->count].bt_i = -1;
8981 if (in_func && !g_skip_func) {
8983 gen_hdr(g_func, pi);
8985 gen_func(fout, g_fhdr, g_func, pi);
8990 g_ida_func_attr = 0;
8991 g_sct_func_attr = 0;
8992 g_stack_clear_start = 0;
8993 g_stack_clear_len = 0;
8998 func_chunks_used = 0;
9001 memset(&ops, 0, pi * sizeof(ops[0]));
9006 for (i = 0; i < g_func_pd_cnt; i++) {
9008 if (pd->type == OPT_OFFSET) {
9009 for (j = 0; j < pd->count; j++)
9010 free(pd->d[j].u.label);
9025 if (IS(words[1], "proc")) {
9027 aerr("proc '%s' while in_func '%s'?\n",
9030 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9032 strcpy(g_func, words[0]);
9033 set_label(0, words[0]);
9038 if (IS(words[1], "endp"))
9041 aerr("endp '%s' while not in_func?\n", words[0]);
9042 if (!IS(g_func, words[0]))
9043 aerr("endp '%s' while in_func '%s'?\n",
9046 aerr("endp '%s' while skipping code\n", words[0]);
9048 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9049 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
9055 if (!g_skip_func && func_chunks_used) {
9056 // start processing chunks
9057 struct chunk_item *ci, key = { g_func, 0 };
9059 func_chunk_ret = ftell(fasm);
9060 func_chunk_ret_ln = asmln;
9061 if (!func_chunks_sorted) {
9062 qsort(func_chunks, func_chunk_cnt,
9063 sizeof(func_chunks[0]), cmp_chunks);
9064 func_chunks_sorted = 1;
9066 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9067 sizeof(func_chunks[0]), cmp_chunks);
9069 aerr("'%s' needs chunks, but none found\n", g_func);
9070 func_chunk_i = ci - func_chunks;
9071 for (; func_chunk_i > 0; func_chunk_i--)
9072 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9075 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9077 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9078 asmln = func_chunks[func_chunk_i].asmln;
9086 if (wordc == 2 && IS(words[1], "ends")) {
9090 goto do_pending_endp;
9094 // scan for next text segment
9095 while (my_fgets(line, sizeof(line), fasm)) {
9098 if (*p == 0 || *p == ';')
9101 if (strstr(p, "segment para public 'CODE' use32"))
9108 p = strchr(words[0], ':');
9110 set_label(pi, words[0]);
9114 if (!in_func || g_skip_func || skip_code) {
9115 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9117 anote("skipping from '%s'\n", g_labels[pi]);
9121 g_labels[pi] = NULL;
9125 if (wordc > 1 && IS(words[1], "="))
9128 aerr("unhandled equ, wc=%d\n", wordc);
9129 if (g_eqcnt >= eq_alloc) {
9131 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9132 my_assert_not(g_eqs, NULL);
9135 len = strlen(words[0]);
9136 if (len > sizeof(g_eqs[0].name) - 1)
9137 aerr("equ name too long: %d\n", len);
9138 strcpy(g_eqs[g_eqcnt].name, words[0]);
9140 if (!IS(words[3], "ptr"))
9141 aerr("unhandled equ\n");
9142 if (IS(words[2], "dword"))
9143 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9144 else if (IS(words[2], "word"))
9145 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9146 else if (IS(words[2], "byte"))
9147 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9148 else if (IS(words[2], "qword"))
9149 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9151 aerr("bad lmod: '%s'\n", words[2]);
9153 g_eqs[g_eqcnt].offset = parse_number(words[4]);
9158 if (pi >= ARRAY_SIZE(ops))
9159 aerr("too many ops\n");
9161 parse_op(&ops[pi], words, wordc);
9163 ops[pi].datap = sctproto;
9178 // vim:ts=2:shiftwidth=2:expandtab