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 = strpbrk(name, "+-");
1742 ferr(po, "equ parse failed for '%s'\n", name);
1744 *extra_offs = strtol(p, &endp, 16);
1746 ferr(po, "equ parse failed for '%s'\n", name);
1749 for (i = 0; i < g_eqcnt; i++)
1750 if (strncmp(g_eqs[i].name, name, namelen) == 0
1751 && g_eqs[i].name[namelen] == 0)
1755 ferr(po, "unresolved equ name: '%s'\n", name);
1762 static int is_stack_access(struct parsed_op *po,
1763 const struct parsed_opr *popr)
1765 return (parse_stack_el(popr->name, NULL, NULL, 0)
1766 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1767 && IS_START(popr->name, "ebp")));
1770 static void parse_stack_access(struct parsed_op *po,
1771 const char *name, char *ofs_reg, int *offset_out,
1772 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1774 const char *bp_arg = "";
1775 const char *p = NULL;
1776 struct parsed_equ *eq;
1783 if (IS_START(name, "ebp-")
1784 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1787 if (IS_START(p, "0x"))
1789 offset = strtoul(p, &endp, 16);
1793 ferr(po, "ebp- parse of '%s' failed\n", name);
1796 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1797 eq = equ_find(po, bp_arg, &offset);
1799 ferr(po, "detected but missing eq\n");
1800 offset += eq->offset;
1803 if (!strncmp(name, "ebp", 3))
1806 // yes it sometimes LEAs ra for compares..
1807 if (!is_lea && ofs_reg[0] == 0
1808 && stack_ra <= offset && offset < stack_ra + 4)
1810 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1813 *offset_out = offset;
1815 *stack_ra_out = stack_ra;
1817 *bp_arg_out = bp_arg;
1820 static int parse_stack_esp_offset(struct parsed_op *po,
1821 const char *name, int *offset_out)
1823 char ofs_reg[16] = { 0, };
1824 struct parsed_equ *eq;
1830 if (strstr(name, "esp") == NULL)
1832 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1833 if (bp_arg == NULL) {
1834 // just plain offset?
1835 if (!IS_START(name, "esp+"))
1837 offset = strtol(name + 4, &endp, 0);
1838 if (endp == NULL || *endp != 0)
1840 *offset_out = offset;
1844 if (ofs_reg[0] != 0)
1846 eq = equ_find(po, bp_arg, &offset);
1848 ferr(po, "detected but missing eq\n");
1849 offset += eq->offset;
1850 *offset_out = base_val + offset;
1854 static int stack_frame_access(struct parsed_op *po,
1855 struct parsed_opr *popr, char *buf, size_t buf_size,
1856 const char *name, const char *cast, int is_src, int is_lea)
1858 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1859 const char *prefix = "";
1860 const char *bp_arg = NULL;
1861 char ofs_reg[16] = { 0, };
1862 int i, arg_i, arg_s;
1869 if (po->flags & OPF_EBP_S)
1870 ferr(po, "stack_frame_access while ebp is scratch\n");
1872 parse_stack_access(po, name, ofs_reg, &offset,
1873 &stack_ra, &bp_arg, is_lea);
1875 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1877 if (offset > stack_ra)
1879 arg_i = (offset - stack_ra - 4) / 4;
1880 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1882 if (g_func_pp->is_vararg
1883 && arg_i == g_func_pp->argc_stack && is_lea)
1885 // should be va_list
1888 snprintf(buf, buf_size, "%sap", cast);
1891 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1892 offset, bp_arg, arg_i);
1894 if (ofs_reg[0] != 0)
1895 ferr(po, "offset reg on arg access?\n");
1897 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1898 if (g_func_pp->arg[i].reg != NULL)
1904 if (i == g_func_pp->argc)
1905 ferr(po, "arg %d not in prototype?\n", arg_i);
1907 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1914 ferr(po, "lea/byte to arg?\n");
1915 if (is_src && (offset & 3) == 0)
1916 snprintf(buf, buf_size, "%sa%d",
1917 simplify_cast(cast, "(u8)"), i + 1);
1919 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1920 cast, offset & 3, i + 1);
1925 ferr(po, "lea/word to arg?\n");
1930 ferr(po, "problematic arg store\n");
1931 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1932 simplify_cast(cast, "*(u16 *)"), i + 1);
1935 ferr(po, "unaligned arg word load\n");
1937 else if (is_src && (offset & 2) == 0)
1938 snprintf(buf, buf_size, "%sa%d",
1939 simplify_cast(cast, "(u16)"), i + 1);
1941 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1942 cast, (offset & 2) ? "HI" : "LO", i + 1);
1954 snprintf(buf, buf_size, "(u32)&a%d + %d",
1957 ferr(po, "unaligned arg store\n");
1959 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1960 snprintf(buf, buf_size, "%s(a%d >> %d)",
1961 prefix, i + 1, (offset & 3) * 8);
1965 snprintf(buf, buf_size, "%s%sa%d",
1966 prefix, is_lea ? "&" : "", i + 1);
1971 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1975 strcat(g_comment, " unaligned");
1978 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
1979 if (tmp_lmod != OPLM_DWORD
1980 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
1981 < lmod_bytes(po, popr->lmod) + (offset & 3))))
1983 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
1984 i + 1, offset, g_func_pp->arg[i].type.name);
1986 // can't check this because msvc likes to reuse
1987 // arg space for scratch..
1988 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
1989 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
1993 if (g_stack_fsz == 0)
1994 ferr(po, "stack var access without stackframe\n");
1995 g_stack_frame_used = 1;
1997 sf_ofs = g_stack_fsz + offset;
1998 if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
1999 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2009 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2010 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2014 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2015 // known unaligned or possibly unaligned
2016 strcat(g_comment, " unaligned");
2018 prefix = "*(u16 *)&";
2019 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2020 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2023 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2027 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2028 // known unaligned or possibly unaligned
2029 strcat(g_comment, " unaligned");
2031 prefix = "*(u32 *)&";
2032 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2033 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2036 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2040 ferr_assert(po, !(sf_ofs & 7));
2041 ferr_assert(po, ofs_reg[0] == 0);
2042 // only used for x87 int64/float, float sets is_lea
2044 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2046 snprintf(buf, buf_size, "*(s64 *)&sf.q[%d]", sf_ofs / 8);
2050 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2057 static void check_func_pp(struct parsed_op *po,
2058 const struct parsed_proto *pp, const char *pfx)
2060 enum opr_lenmod tmp_lmod;
2064 if (pp->argc_reg != 0) {
2065 if (!g_allow_user_icall && !pp->is_fastcall) {
2066 pp_print(buf, sizeof(buf), pp);
2067 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2069 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2070 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2071 pfx, pp->argc_reg, pp->argc_stack);
2074 // fptrs must use 32bit args, callsite might have no information and
2075 // lack a cast to smaller types, which results in incorrectly masked
2076 // args passed (callee may assume masked args, it does on ARM)
2077 if (!pp->is_osinc) {
2078 for (i = 0; i < pp->argc; i++) {
2079 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2080 if (ret && tmp_lmod != OPLM_DWORD)
2081 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2082 i + 1, pp->arg[i].type.name);
2087 static const char *check_label_read_ref(struct parsed_op *po,
2090 const struct parsed_proto *pp;
2092 pp = proto_parse(g_fhdr, name, 0);
2094 ferr(po, "proto_parse failed for ref '%s'\n", name);
2097 check_func_pp(po, pp, "ref");
2102 static char *out_src_opr(char *buf, size_t buf_size,
2103 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2106 char tmp1[256], tmp2[256];
2115 switch (popr->type) {
2118 ferr(po, "lea from reg?\n");
2120 switch (popr->lmod) {
2122 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2125 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2128 snprintf(buf, buf_size, "%s%s",
2129 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2132 if (popr->name[1] == 'h') // XXX..
2133 snprintf(buf, buf_size, "%s(%s >> 8)",
2134 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2136 snprintf(buf, buf_size, "%s%s",
2137 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2140 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2145 if (is_stack_access(po, popr)) {
2146 stack_frame_access(po, popr, buf, buf_size,
2147 popr->name, cast, 1, is_lea);
2151 strcpy(expr, popr->name);
2152 if (strchr(expr, '[')) {
2153 // special case: '[' can only be left for label[reg] form
2154 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2156 ferr(po, "parse failure for '%s'\n", expr);
2157 if (tmp1[0] == '(') {
2158 // (off_4FFF50+3)[eax]
2159 p = strchr(tmp1 + 1, ')');
2160 if (p == NULL || p[1] != 0)
2161 ferr(po, "parse failure (2) for '%s'\n", expr);
2163 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2165 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2168 // XXX: do we need more parsing?
2170 snprintf(buf, buf_size, "%s", expr);
2174 snprintf(buf, buf_size, "%s(%s)",
2175 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2179 name = check_label_read_ref(po, popr->name);
2180 if (cast[0] == 0 && popr->is_ptr)
2184 snprintf(buf, buf_size, "(u32)&%s", name);
2185 else if (popr->size_lt)
2186 snprintf(buf, buf_size, "%s%s%s%s", cast,
2187 lmod_cast_u_ptr(po, popr->lmod),
2188 popr->is_array ? "" : "&", name);
2190 snprintf(buf, buf_size, "%s%s%s", cast, name,
2191 popr->is_array ? "[0]" : "");
2195 name = check_label_read_ref(po, popr->name);
2199 ferr(po, "lea an offset?\n");
2200 snprintf(buf, buf_size, "%s&%s", cast, name);
2205 ferr(po, "lea from const?\n");
2207 printf_number(tmp1, sizeof(tmp1), popr->val);
2208 if (popr->val == 0 && strchr(cast, '*'))
2209 snprintf(buf, buf_size, "NULL");
2211 snprintf(buf, buf_size, "%s%s",
2212 simplify_cast_num(cast, popr->val), tmp1);
2216 ferr(po, "invalid src type: %d\n", popr->type);
2222 // note: may set is_ptr (we find that out late for ebp frame..)
2223 static char *out_dst_opr(char *buf, size_t buf_size,
2224 struct parsed_op *po, struct parsed_opr *popr)
2226 switch (popr->type) {
2228 switch (popr->lmod) {
2230 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2233 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2237 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2241 if (popr->name[1] == 'h') // XXX..
2242 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2244 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2247 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2252 if (is_stack_access(po, popr)) {
2253 stack_frame_access(po, popr, buf, buf_size,
2254 popr->name, "", 0, 0);
2258 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2261 if (popr->size_mismatch)
2262 snprintf(buf, buf_size, "%s%s%s",
2263 lmod_cast_u_ptr(po, popr->lmod),
2264 popr->is_array ? "" : "&", popr->name);
2266 snprintf(buf, buf_size, "%s%s", popr->name,
2267 popr->is_array ? "[0]" : "");
2271 ferr(po, "invalid dst type: %d\n", popr->type);
2277 static char *out_src_opr_u32(char *buf, size_t buf_size,
2278 struct parsed_op *po, struct parsed_opr *popr)
2280 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2283 static char *out_src_opr_float(char *buf, size_t buf_size,
2284 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2286 const char *cast = NULL;
2289 switch (popr->type) {
2291 if (popr->reg < xST0 || popr->reg > xST7)
2292 ferr(po, "bad reg: %d\n", popr->reg);
2294 if (need_float_stack) {
2295 if (popr->reg == xST0)
2296 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2298 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2302 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2308 switch (popr->lmod) {
2316 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2319 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2320 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2324 ferr(po, "invalid float type: %d\n", popr->type);
2330 static char *out_dst_opr_float(char *buf, size_t buf_size,
2331 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2334 return out_src_opr_float(buf, buf_size, po, popr, need_float_stack);
2337 static void out_test_for_cc(char *buf, size_t buf_size,
2338 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2339 enum opr_lenmod lmod, const char *expr)
2341 const char *cast, *scast;
2343 cast = lmod_cast_u(po, lmod);
2344 scast = lmod_cast_s(po, lmod);
2348 case PFO_BE: // CF==1||ZF==1; CF=0
2349 snprintf(buf, buf_size, "(%s%s %s 0)",
2350 cast, expr, is_inv ? "!=" : "==");
2354 case PFO_L: // SF!=OF; OF=0
2355 snprintf(buf, buf_size, "(%s%s %s 0)",
2356 scast, expr, is_inv ? ">=" : "<");
2359 case PFO_LE: // ZF==1||SF!=OF; OF=0
2360 snprintf(buf, buf_size, "(%s%s %s 0)",
2361 scast, expr, is_inv ? ">" : "<=");
2366 snprintf(buf, buf_size, "(%d)", !!is_inv);
2370 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2374 static void out_cmp_for_cc(char *buf, size_t buf_size,
2375 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2378 const char *cast, *scast, *cast_use;
2379 char buf1[256], buf2[256];
2380 enum opr_lenmod lmod;
2382 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2383 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2384 po->operand[0].lmod, po->operand[1].lmod);
2385 lmod = po->operand[0].lmod;
2387 cast = lmod_cast_u(po, lmod);
2388 scast = lmod_cast_s(po, lmod);
2404 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2407 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2408 if (po->op == OP_DEC)
2409 snprintf(buf2, sizeof(buf2), "1");
2412 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2414 strcat(cast_op2, "-");
2415 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2420 // note: must be unsigned compare
2421 snprintf(buf, buf_size, "(%s %s %s)",
2422 buf1, is_inv ? ">=" : "<", buf2);
2426 snprintf(buf, buf_size, "(%s %s %s)",
2427 buf1, is_inv ? "!=" : "==", buf2);
2431 // note: must be unsigned compare
2432 snprintf(buf, buf_size, "(%s %s %s)",
2433 buf1, is_inv ? ">" : "<=", buf2);
2436 if (is_inv && lmod == OPLM_BYTE
2437 && po->operand[1].type == OPT_CONST
2438 && po->operand[1].val == 0xff)
2440 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2441 snprintf(buf, buf_size, "(0)");
2445 // note: must be signed compare
2447 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2448 scast, buf1, buf2, is_inv ? ">=" : "<");
2452 snprintf(buf, buf_size, "(%s %s %s)",
2453 buf1, is_inv ? ">=" : "<", buf2);
2457 snprintf(buf, buf_size, "(%s %s %s)",
2458 buf1, is_inv ? ">" : "<=", buf2);
2466 static void out_cmp_test(char *buf, size_t buf_size,
2467 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2469 char buf1[256], buf2[256], buf3[256];
2471 if (po->op == OP_TEST) {
2472 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2473 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2476 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2477 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2478 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2480 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2481 po->operand[0].lmod, buf3);
2483 else if (po->op == OP_CMP) {
2484 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2487 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2490 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2491 struct parsed_opr *popr2)
2493 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2494 ferr(po, "missing lmod for both operands\n");
2496 if (popr1->lmod == OPLM_UNSPEC)
2497 popr1->lmod = popr2->lmod;
2498 else if (popr2->lmod == OPLM_UNSPEC)
2499 popr2->lmod = popr1->lmod;
2500 else if (popr1->lmod != popr2->lmod) {
2501 if (popr1->type_from_var) {
2502 popr1->size_mismatch = 1;
2503 if (popr1->lmod < popr2->lmod)
2505 popr1->lmod = popr2->lmod;
2507 else if (popr2->type_from_var) {
2508 popr2->size_mismatch = 1;
2509 if (popr2->lmod < popr1->lmod)
2511 popr2->lmod = popr1->lmod;
2514 ferr(po, "conflicting lmods: %d vs %d\n",
2515 popr1->lmod, popr2->lmod);
2519 static const char *op_to_c(struct parsed_op *po)
2543 ferr(po, "op_to_c was supplied with %d\n", po->op);
2547 // last op in stream - unconditional branch or ret
2548 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2549 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2550 && ops[_i].op != OP_CALL))
2552 #define check_i(po, i) \
2554 ferr(po, "bad " #i ": %d\n", i)
2556 // note: this skips over calls and rm'd stuff assuming they're handled
2557 // so it's intended to use at one of final passes
2558 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2559 int depth, int seen_noreturn, int flags_set)
2561 struct parsed_op *po;
2566 for (; i < opcnt; i++) {
2568 if (po->cc_scratch == magic)
2569 return ret; // already checked
2570 po->cc_scratch = magic;
2572 if (po->flags & OPF_TAIL) {
2573 if (po->op == OP_CALL) {
2574 if (po->pp != NULL && po->pp->is_noreturn)
2580 return -1; // deadend
2583 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2586 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2587 if (po->btj != NULL) {
2589 for (j = 0; j < po->btj->count; j++) {
2590 check_i(po, po->btj->d[j].bt_i);
2591 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2592 depth, seen_noreturn, flags_set);
2594 return ret; // dead end
2599 check_i(po, po->bt_i);
2600 if (po->flags & OPF_CJMP) {
2601 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2602 depth, seen_noreturn, flags_set);
2604 return ret; // dead end
2613 if ((po->op == OP_POP || po->op == OP_PUSH)
2614 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2619 if (po->op == OP_PUSH) {
2622 else if (po->op == OP_POP) {
2623 if (relevant && depth == 0) {
2624 po->flags |= flags_set;
2631 // for noreturn, assume msvc skipped stack cleanup
2632 return seen_noreturn ? 1 : -1;
2635 // scan for 'reg' pop backwards starting from i
2636 // intended to use for register restore search, so other reg
2637 // references are considered an error
2638 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2640 struct parsed_op *po;
2641 struct label_ref *lr;
2644 ops[i].cc_scratch = magic;
2648 if (g_labels[i] != NULL) {
2649 lr = &g_label_refs[i];
2650 for (; lr != NULL; lr = lr->next) {
2651 check_i(&ops[i], lr->i);
2652 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2656 if (i > 0 && LAST_OP(i - 1))
2664 if (ops[i].cc_scratch == magic)
2666 ops[i].cc_scratch = magic;
2669 if (po->op == OP_POP && po->operand[0].reg == reg) {
2670 if (po->flags & (OPF_RMD|OPF_DONE))
2673 po->flags |= set_flags;
2677 // this also covers the case where we reach corresponding push
2678 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2682 // nothing interesting on this path
2686 static void find_reachable_exits(int i, int opcnt, int magic,
2687 int *exits, int *exit_count)
2689 struct parsed_op *po;
2692 for (; i < opcnt; i++)
2695 if (po->cc_scratch == magic)
2697 po->cc_scratch = magic;
2699 if (po->flags & OPF_TAIL) {
2700 ferr_assert(po, *exit_count < MAX_EXITS);
2701 exits[*exit_count] = i;
2706 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2707 if (po->flags & OPF_RMD)
2710 if (po->btj != NULL) {
2711 for (j = 0; j < po->btj->count; j++) {
2712 check_i(po, po->btj->d[j].bt_i);
2713 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2719 check_i(po, po->bt_i);
2720 if (po->flags & OPF_CJMP)
2721 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2729 // scan for 'reg' pop backwards starting from exits (all paths)
2730 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2732 static int exits[MAX_EXITS];
2733 static int exit_count;
2738 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2740 ferr_assert(&ops[i], exit_count > 0);
2743 for (j = 0; j < exit_count; j++) {
2744 ret = scan_for_rsave_pop_reg(exits[j], i + opcnt * 16 + set_flags,
2753 // scan for one or more pop of push <const>
2754 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2755 int push_i, int is_probe)
2757 struct parsed_op *po;
2758 struct label_ref *lr;
2762 for (; i < opcnt; i++)
2765 if (po->cc_scratch == magic)
2766 return ret; // already checked
2767 po->cc_scratch = magic;
2769 if (po->flags & OPF_JMP) {
2770 if (po->flags & OPF_RMD)
2772 if (po->op == OP_CALL)
2775 if (po->btj != NULL) {
2776 for (j = 0; j < po->btj->count; j++) {
2777 check_i(po, po->btj->d[j].bt_i);
2778 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2786 check_i(po, po->bt_i);
2787 if (po->flags & OPF_CJMP) {
2788 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2799 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2802 if (g_labels[i] != NULL) {
2803 // all refs must be visited
2804 lr = &g_label_refs[i];
2805 for (; lr != NULL; lr = lr->next) {
2807 if (ops[lr->i].cc_scratch != magic)
2810 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2814 if (po->op == OP_POP)
2816 if (po->flags & (OPF_RMD|OPF_DONE))
2820 po->flags |= OPF_DONE;
2821 po->datap = &ops[push_i];
2830 static void scan_for_pop_const(int i, int opcnt, int magic)
2834 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2836 ops[i].flags |= OPF_RMD | OPF_DONE;
2837 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2841 // check if all branch targets within a marked path are also marked
2842 // note: the path checked must not be empty or end with a branch
2843 static int check_path_branches(int opcnt, int magic)
2845 struct parsed_op *po;
2848 for (i = 0; i < opcnt; i++) {
2850 if (po->cc_scratch != magic)
2853 if (po->flags & OPF_JMP) {
2854 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2857 if (po->btj != NULL) {
2858 for (j = 0; j < po->btj->count; j++) {
2859 check_i(po, po->btj->d[j].bt_i);
2860 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2865 check_i(po, po->bt_i);
2866 if (ops[po->bt_i].cc_scratch != magic)
2868 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2876 // scan for multiple pushes for given pop
2877 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2880 int reg = ops[pop_i].operand[0].reg;
2881 struct parsed_op *po;
2882 struct label_ref *lr;
2885 ops[i].cc_scratch = magic;
2889 if (g_labels[i] != NULL) {
2890 lr = &g_label_refs[i];
2891 for (; lr != NULL; lr = lr->next) {
2892 check_i(&ops[i], lr->i);
2893 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2897 if (i > 0 && LAST_OP(i - 1))
2905 if (ops[i].cc_scratch == magic)
2907 ops[i].cc_scratch = magic;
2910 if (po->op == OP_CALL)
2912 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2915 if (po->op == OP_PUSH)
2917 if (po->datap != NULL)
2919 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2920 // leave this case for reg save/restore handlers
2924 po->flags |= OPF_PPUSH | OPF_DONE;
2925 po->datap = &ops[pop_i];
2934 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2936 int magic = i + opcnt * 14;
2939 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2941 ret = check_path_branches(opcnt, magic);
2943 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2944 *regmask_pp |= 1 << ops[i].operand[0].reg;
2945 scan_pushes_for_pop_r(i, magic + 1, i, 0);
2950 static void scan_propagate_df(int i, int opcnt)
2952 struct parsed_op *po = &ops[i];
2955 for (; i < opcnt; i++) {
2957 if (po->flags & OPF_DF)
2958 return; // already resolved
2959 po->flags |= OPF_DF;
2961 if (po->op == OP_CALL)
2962 ferr(po, "call with DF set?\n");
2964 if (po->flags & OPF_JMP) {
2965 if (po->btj != NULL) {
2967 for (j = 0; j < po->btj->count; j++) {
2968 check_i(po, po->btj->d[j].bt_i);
2969 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
2974 if (po->flags & OPF_RMD)
2976 check_i(po, po->bt_i);
2977 if (po->flags & OPF_CJMP)
2978 scan_propagate_df(po->bt_i, opcnt);
2984 if (po->flags & OPF_TAIL)
2987 if (po->op == OP_CLD) {
2988 po->flags |= OPF_RMD | OPF_DONE;
2993 ferr(po, "missing DF clear?\n");
2996 // is operand 'opr' referenced by parsed_op 'po'?
2997 static int is_opr_referenced(const struct parsed_opr *opr,
2998 const struct parsed_op *po)
3002 if (opr->type == OPT_REG) {
3003 mask = po->regmask_dst | po->regmask_src;
3004 if (po->op == OP_CALL)
3005 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3006 if ((1 << opr->reg) & mask)
3012 for (i = 0; i < po->operand_cnt; i++)
3013 if (IS(po->operand[0].name, opr->name))
3019 // is operand 'opr' read by parsed_op 'po'?
3020 static int is_opr_read(const struct parsed_opr *opr,
3021 const struct parsed_op *po)
3023 if (opr->type == OPT_REG) {
3024 if (po->regmask_src & (1 << opr->reg))
3034 // is operand 'opr' modified by parsed_op 'po'?
3035 static int is_opr_modified(const struct parsed_opr *opr,
3036 const struct parsed_op *po)
3040 if (opr->type == OPT_REG) {
3041 if (po->op == OP_CALL) {
3042 mask = po->regmask_dst;
3043 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3044 if (mask & (1 << opr->reg))
3050 if (po->regmask_dst & (1 << opr->reg))
3056 return IS(po->operand[0].name, opr->name);
3059 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3060 static int is_any_opr_modified(const struct parsed_op *po_test,
3061 const struct parsed_op *po, int c_mode)
3066 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3069 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3072 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3075 // in reality, it can wreck any register, but in decompiled C
3076 // version it can only overwrite eax or edx:eax
3077 mask = (1 << xAX) | (1 << xDX);
3081 if (po->op == OP_CALL
3082 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3085 for (i = 0; i < po_test->operand_cnt; i++)
3086 if (IS(po_test->operand[i].name, po->operand[0].name))
3092 // scan for any po_test operand modification in range given
3093 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3096 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3099 for (; i < opcnt; i++) {
3100 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3107 // scan for po_test operand[0] modification in range given
3108 static int scan_for_mod_opr0(struct parsed_op *po_test,
3111 for (; i < opcnt; i++) {
3112 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3119 static int try_resolve_const(int i, const struct parsed_opr *opr,
3120 int magic, unsigned int *val);
3122 static int scan_for_flag_set(int i, int opcnt, int magic,
3123 int *branched, int *setters, int *setter_cnt)
3125 struct label_ref *lr;
3129 if (ops[i].cc_scratch == magic) {
3130 // is this a problem?
3131 //ferr(&ops[i], "%s looped\n", __func__);
3134 ops[i].cc_scratch = magic;
3136 if (g_labels[i] != NULL) {
3139 lr = &g_label_refs[i];
3140 for (; lr->next; lr = lr->next) {
3141 check_i(&ops[i], lr->i);
3142 ret = scan_for_flag_set(lr->i, opcnt, magic,
3143 branched, setters, setter_cnt);
3148 check_i(&ops[i], lr->i);
3149 if (i > 0 && LAST_OP(i - 1)) {
3153 ret = scan_for_flag_set(lr->i, opcnt, magic,
3154 branched, setters, setter_cnt);
3160 if (ops[i].flags & OPF_FLAGS) {
3161 setters[*setter_cnt] = i;
3164 if (ops[i].flags & OPF_REP) {
3165 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3168 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3169 if (ret != 1 || uval == 0) {
3170 // can't treat it as full setter because of ecx=0 case,
3171 // also disallow delayed compare
3180 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3187 // scan back for cdq, if anything modifies edx, fail
3188 static int scan_for_cdq_edx(int i)
3191 if (g_labels[i] != NULL) {
3192 if (g_label_refs[i].next != NULL)
3194 if (i > 0 && LAST_OP(i - 1)) {
3195 i = g_label_refs[i].i;
3202 if (ops[i].op == OP_CDQ)
3205 if (ops[i].regmask_dst & (1 << xDX))
3212 static int scan_for_reg_clear(int i, int reg)
3215 if (g_labels[i] != NULL) {
3216 if (g_label_refs[i].next != NULL)
3218 if (i > 0 && LAST_OP(i - 1)) {
3219 i = g_label_refs[i].i;
3226 if (ops[i].op == OP_XOR
3227 && ops[i].operand[0].lmod == OPLM_DWORD
3228 && ops[i].operand[0].reg == ops[i].operand[1].reg
3229 && ops[i].operand[0].reg == reg)
3232 if (ops[i].regmask_dst & (1 << reg))
3239 static void patch_esp_adjust(struct parsed_op *po, int adj)
3241 ferr_assert(po, po->op == OP_ADD);
3242 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3243 ferr_assert(po, po->operand[1].type == OPT_CONST);
3245 // this is a bit of a hack, but deals with use of
3246 // single adj for multiple calls
3247 po->operand[1].val -= adj;
3248 po->flags |= OPF_RMD;
3249 if (po->operand[1].val == 0)
3250 po->flags |= OPF_DONE;
3251 ferr_assert(po, (int)po->operand[1].val >= 0);
3254 // scan for positive, constant esp adjust
3255 // multipath case is preliminary
3256 static int scan_for_esp_adjust(int i, int opcnt,
3257 int adj_expect, int *adj, int *is_multipath, int do_update)
3259 int adj_expect_unknown = 0;
3260 struct parsed_op *po;
3264 *adj = *is_multipath = 0;
3265 if (adj_expect < 0) {
3266 adj_expect_unknown = 1;
3267 adj_expect = 32 * 4; // enough?
3270 for (; i < opcnt && *adj < adj_expect; i++) {
3271 if (g_labels[i] != NULL)
3275 if (po->flags & OPF_DONE)
3278 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3279 if (po->operand[1].type != OPT_CONST)
3280 ferr(&ops[i], "non-const esp adjust?\n");
3281 *adj += po->operand[1].val;
3283 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3286 patch_esp_adjust(po, adj_expect);
3288 po->flags |= OPF_RMD;
3292 else if (po->op == OP_PUSH) {
3293 //if (first_pop == -1)
3294 // first_pop = -2; // none
3295 *adj -= lmod_bytes(po, po->operand[0].lmod);
3297 else if (po->op == OP_POP) {
3298 if (!(po->flags & OPF_DONE)) {
3299 // seems like msvc only uses 'pop ecx' for stack realignment..
3300 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3302 if (first_pop == -1 && *adj >= 0)
3305 if (do_update && *adj >= 0) {
3306 po->flags |= OPF_RMD;
3308 po->flags |= OPF_DONE | OPF_NOREGS;
3311 *adj += lmod_bytes(po, po->operand[0].lmod);
3312 if (*adj > adj_best)
3315 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3316 if (po->op == OP_JMP && po->btj == NULL) {
3322 if (po->op != OP_CALL)
3324 if (po->operand[0].type != OPT_LABEL)
3326 if (po->pp != NULL && po->pp->is_stdcall)
3328 if (adj_expect_unknown && first_pop >= 0)
3330 // assume it's another cdecl call
3334 if (first_pop >= 0) {
3335 // probably only 'pop ecx' was used
3343 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3345 struct parsed_op *po;
3349 ferr(ops, "%s: followed bad branch?\n", __func__);
3351 for (; i < opcnt; i++) {
3353 if (po->cc_scratch == magic)
3355 po->cc_scratch = magic;
3358 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3359 if (po->btj != NULL) {
3361 for (j = 0; j < po->btj->count; j++)
3362 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3366 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3367 if (!(po->flags & OPF_CJMP))
3370 if (po->flags & OPF_TAIL)
3375 static const struct parsed_proto *try_recover_pp(
3376 struct parsed_op *po, const struct parsed_opr *opr,
3377 int is_call, int *search_instead)
3379 const struct parsed_proto *pp = NULL;
3383 // maybe an arg of g_func?
3384 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3386 char ofs_reg[16] = { 0, };
3387 int arg, arg_s, arg_i;
3394 parse_stack_access(po, opr->name, ofs_reg,
3395 &offset, &stack_ra, NULL, 0);
3396 if (ofs_reg[0] != 0)
3397 ferr(po, "offset reg on arg access?\n");
3398 if (offset <= stack_ra) {
3399 // search who set the stack var instead
3400 if (search_instead != NULL)
3401 *search_instead = 1;
3405 arg_i = (offset - stack_ra - 4) / 4;
3406 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3407 if (g_func_pp->arg[arg].reg != NULL)
3413 if (arg == g_func_pp->argc)
3414 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3416 pp = g_func_pp->arg[arg].pp;
3419 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3420 check_func_pp(po, pp, "icall arg");
3423 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3425 p = strchr(opr->name + 1, '[');
3426 memcpy(buf, opr->name, p - opr->name);
3427 buf[p - opr->name] = 0;
3428 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3430 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3431 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3434 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3437 check_func_pp(po, pp, "reg-fptr ref");
3443 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3444 int magic, const struct parsed_proto **pp_found, int *pp_i,
3447 const struct parsed_proto *pp = NULL;
3448 struct parsed_op *po;
3449 struct label_ref *lr;
3451 ops[i].cc_scratch = magic;
3454 if (g_labels[i] != NULL) {
3455 lr = &g_label_refs[i];
3456 for (; lr != NULL; lr = lr->next) {
3457 check_i(&ops[i], lr->i);
3458 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3460 if (i > 0 && LAST_OP(i - 1))
3468 if (ops[i].cc_scratch == magic)
3470 ops[i].cc_scratch = magic;
3472 if (!(ops[i].flags & OPF_DATA))
3474 if (!is_opr_modified(opr, &ops[i]))
3476 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3477 // most probably trashed by some processing
3482 opr = &ops[i].operand[1];
3483 if (opr->type != OPT_REG)
3487 po = (i >= 0) ? &ops[i] : ops;
3490 // reached the top - can only be an arg-reg
3491 if (opr->type != OPT_REG || g_func_pp == NULL)
3494 for (i = 0; i < g_func_pp->argc; i++) {
3495 if (g_func_pp->arg[i].reg == NULL)
3497 if (IS(opr->name, g_func_pp->arg[i].reg))
3500 if (i == g_func_pp->argc)
3502 pp = g_func_pp->arg[i].pp;
3504 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3505 i + 1, g_func_pp->arg[i].reg);
3506 check_func_pp(po, pp, "icall reg-arg");
3509 pp = try_recover_pp(po, opr, 1, NULL);
3511 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3512 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3513 || (*pp_found)->is_stdcall != pp->is_stdcall
3514 || (*pp_found)->is_fptr != pp->is_fptr
3515 || (*pp_found)->argc != pp->argc
3516 || (*pp_found)->argc_reg != pp->argc_reg
3517 || (*pp_found)->argc_stack != pp->argc_stack)
3519 ferr(po, "icall: parsed_proto mismatch\n");
3529 static void add_label_ref(struct label_ref *lr, int op_i)
3531 struct label_ref *lr_new;
3538 lr_new = calloc(1, sizeof(*lr_new));
3540 lr_new->next = lr->next;
3544 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3546 struct parsed_op *po = &ops[i];
3547 struct parsed_data *pd;
3548 char label[NAMELEN], *p;
3551 p = strchr(po->operand[0].name, '[');
3555 len = p - po->operand[0].name;
3556 strncpy(label, po->operand[0].name, len);
3559 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3560 if (IS(g_func_pd[j].label, label)) {
3566 //ferr(po, "label '%s' not parsed?\n", label);
3569 if (pd->type != OPT_OFFSET)
3570 ferr(po, "label '%s' with non-offset data?\n", label);
3572 // find all labels, link
3573 for (j = 0; j < pd->count; j++) {
3574 for (l = 0; l < opcnt; l++) {
3575 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3576 add_label_ref(&g_label_refs[l], i);
3586 static void clear_labels(int count)
3590 for (i = 0; i < count; i++) {
3591 if (g_labels[i] != NULL) {
3598 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3603 for (i = 0; i < pp->argc; i++) {
3604 if (pp->arg[i].reg != NULL) {
3605 reg = char_array_i(regs_r32,
3606 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3608 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3609 pp->arg[i].reg, pp->name);
3610 regmask |= 1 << reg;
3617 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3622 if (pp->has_retreg) {
3623 for (i = 0; i < pp->argc; i++) {
3624 if (pp->arg[i].type.is_retreg) {
3625 reg = char_array_i(regs_r32,
3626 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3627 ferr_assert(ops, reg >= 0);
3628 regmask |= 1 << reg;
3633 if (strstr(pp->ret_type.name, "int64"))
3634 return regmask | (1 << xAX) | (1 << xDX);
3635 if (IS(pp->ret_type.name, "float")
3636 || IS(pp->ret_type.name, "double"))
3638 return regmask | mxST0;
3640 if (strcasecmp(pp->ret_type.name, "void") == 0)
3643 return regmask | mxAX;
3646 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3648 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3649 && memcmp(po1->operand, po2->operand,
3650 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3653 static void resolve_branches_parse_calls(int opcnt)
3655 static const struct {
3659 unsigned int regmask_src;
3660 unsigned int regmask_dst;
3662 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3663 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3664 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3665 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3667 const struct parsed_proto *pp_c;
3668 struct parsed_proto *pp;
3669 struct parsed_data *pd;
3670 struct parsed_op *po;
3671 const char *tmpname;
3675 for (i = 0; i < opcnt; i++)
3681 if (po->datap != NULL) {
3682 pp = calloc(1, sizeof(*pp));
3683 my_assert_not(pp, NULL);
3685 ret = parse_protostr(po->datap, pp);
3687 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3693 if (po->op == OP_CALL) {
3698 else if (po->operand[0].type == OPT_LABEL)
3700 tmpname = opr_name(po, 0);
3701 if (IS_START(tmpname, "loc_"))
3702 ferr(po, "call to loc_*\n");
3703 if (IS(tmpname, "__alloca_probe"))
3706 // convert some calls to pseudo-ops
3707 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3708 if (!IS(tmpname, pseudo_ops[l].name))
3711 po->op = pseudo_ops[l].op;
3712 po->operand_cnt = 0;
3713 po->regmask_src = pseudo_ops[l].regmask_src;
3714 po->regmask_dst = pseudo_ops[l].regmask_dst;
3715 po->flags = pseudo_ops[l].flags;
3716 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3719 if (l < ARRAY_SIZE(pseudo_ops))
3722 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3723 if (!g_header_mode && pp_c == NULL)
3724 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3727 pp = proto_clone(pp_c);
3728 my_assert_not(pp, NULL);
3734 check_func_pp(po, pp, "fptr var call");
3735 if (pp->is_noreturn)
3736 po->flags |= OPF_TAIL;
3742 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3745 if (po->operand[0].type == OPT_REGMEM) {
3746 pd = try_resolve_jumptab(i, opcnt);
3754 for (l = 0; l < opcnt; l++) {
3755 if (g_labels[l] != NULL
3756 && IS(po->operand[0].name, g_labels[l]))
3758 if (l == i + 1 && po->op == OP_JMP) {
3759 // yet another alignment type..
3760 po->flags |= OPF_RMD|OPF_DONE;
3763 add_label_ref(&g_label_refs[l], i);
3769 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3772 if (po->operand[0].type == OPT_LABEL)
3776 ferr(po, "unhandled branch\n");
3780 po->flags |= OPF_TAIL;
3781 if (i > 0 && ops[i - 1].op == OP_POP)
3782 po->flags |= OPF_ATAIL;
3787 static void scan_prologue_epilogue(int opcnt)
3789 int ecx_push = 0, esp_sub = 0, pusha = 0;
3790 int sandard_epilogue;
3794 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3795 && ops[1].op == OP_MOV
3796 && IS(opr_name(&ops[1], 0), "ebp")
3797 && IS(opr_name(&ops[1], 1), "esp"))
3800 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3801 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3804 if (ops[i].op == OP_PUSHA) {
3805 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3810 if (ops[i].op == OP_SUB && IS(opr_name(&ops[i], 0), "esp")) {
3811 g_stack_fsz = opr_const(&ops[i], 1);
3812 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3816 // another way msvc builds stack frame..
3817 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3819 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3823 // and another way..
3824 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3825 && ops[i].operand[1].type == OPT_CONST
3826 && ops[i + 1].op == OP_CALL
3827 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3829 g_stack_fsz += ops[i].operand[1].val;
3830 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3832 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3839 for (; i < opcnt; i++)
3840 if (ops[i].flags & OPF_TAIL)
3843 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3844 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3850 sandard_epilogue = 0;
3851 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3853 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3854 // the standard epilogue is sometimes even used without a sf
3855 if (ops[j - 1].op == OP_MOV
3856 && IS(opr_name(&ops[j - 1], 0), "esp")
3857 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3858 sandard_epilogue = 1;
3860 else if (ops[j].op == OP_LEAVE)
3862 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3863 sandard_epilogue = 1;
3865 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3866 && ops[i].pp->is_noreturn)
3868 // on noreturn, msvc sometimes cleans stack, sometimes not
3873 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3874 ferr(&ops[j], "'pop ebp' expected\n");
3876 if (g_stack_fsz != 0 || sandard_epilogue) {
3877 if (ops[j].op == OP_LEAVE)
3879 else if (sandard_epilogue) // mov esp, ebp
3881 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3884 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3886 ferr(&ops[j], "esp restore expected\n");
3889 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3890 && IS(opr_name(&ops[j], 0), "ecx"))
3892 ferr(&ops[j], "unexpected ecx pop\n");
3897 if (ops[j].op == OP_POPA)
3898 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3900 ferr(&ops[j], "popa expected\n");
3905 } while (i < opcnt);
3908 ferr(ops, "missing ebp epilogue\n");
3914 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3915 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3921 for (; i < opcnt; i++) {
3922 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3924 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3925 && ops[i].operand[1].type == OPT_CONST)
3927 g_stack_fsz = ops[i].operand[1].val;
3928 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3933 else if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3934 && ops[i].operand[1].type == OPT_CONST
3935 && ops[i + 1].op == OP_CALL
3936 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3938 g_stack_fsz += ops[i].operand[1].val;
3939 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3941 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3948 if (ecx_push && !esp_sub) {
3949 // could actually be args for a call..
3950 for (; i < opcnt; i++)
3951 if (ops[i].op != OP_PUSH)
3954 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3955 const struct parsed_proto *pp;
3956 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3957 j = pp ? pp->argc_stack : 0;
3958 while (i > 0 && j > 0) {
3960 if (ops[i].op == OP_PUSH) {
3961 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
3966 ferr(&ops[i], "unhandled prologue\n");
3969 i = g_stack_fsz = ecx_push = 0;
3970 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3971 if (!(ops[i].flags & OPF_RMD))
3981 if (ecx_push || esp_sub)
3986 for (; i < opcnt; i++)
3987 if (ops[i].flags & OPF_TAIL)
3991 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3992 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3999 for (l = 0; l < ecx_push; l++) {
4000 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4002 else if (ops[j].op == OP_ADD
4003 && IS(opr_name(&ops[j], 0), "esp")
4004 && ops[j].operand[1].type == OPT_CONST)
4007 l += ops[j].operand[1].val / 4 - 1;
4010 ferr(&ops[j], "'pop ecx' expected\n");
4012 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4016 ferr(&ops[j], "epilogue scan failed\n");
4022 if (ops[j].op != OP_ADD
4023 || !IS(opr_name(&ops[j], 0), "esp")
4024 || ops[j].operand[1].type != OPT_CONST
4025 || ops[j].operand[1].val != g_stack_fsz)
4027 if (ops[i].op == OP_CALL && ops[i].pp != NULL
4028 && ops[i].pp->is_noreturn)
4030 // noreturn tailcall with no epilogue
4034 ferr(&ops[j], "'add esp' expected\n");
4037 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4038 ops[j].operand[1].val = 0; // hack for stack arg scanner
4043 } while (i < opcnt);
4046 ferr(ops, "missing esp epilogue\n");
4050 // find an instruction that changed opr before i op
4051 // *op_i must be set to -1 by the caller
4052 // *is_caller is set to 1 if one source is determined to be g_func arg
4053 // returns 1 if found, *op_i is then set to origin
4054 // returns -1 if multiple origins are found
4055 static int resolve_origin(int i, const struct parsed_opr *opr,
4056 int magic, int *op_i, int *is_caller)
4058 struct label_ref *lr;
4062 if (g_labels[i] != NULL) {
4063 lr = &g_label_refs[i];
4064 for (; lr != NULL; lr = lr->next) {
4065 check_i(&ops[i], lr->i);
4066 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4068 if (i > 0 && LAST_OP(i - 1))
4074 if (is_caller != NULL)
4079 if (ops[i].cc_scratch == magic)
4081 ops[i].cc_scratch = magic;
4083 if (!(ops[i].flags & OPF_DATA))
4085 if (!is_opr_modified(opr, &ops[i]))
4089 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4100 // find an instruction that previously referenced opr
4101 // if multiple results are found - fail
4102 // *op_i must be set to -1 by the caller
4103 // returns 1 if found, *op_i is then set to referencer insn
4104 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4105 int magic, int *op_i)
4107 struct label_ref *lr;
4111 if (g_labels[i] != NULL) {
4112 lr = &g_label_refs[i];
4113 for (; lr != NULL; lr = lr->next) {
4114 check_i(&ops[i], lr->i);
4115 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4117 if (i > 0 && LAST_OP(i - 1))
4125 if (ops[i].cc_scratch == magic)
4127 ops[i].cc_scratch = magic;
4129 if (!is_opr_referenced(opr, &ops[i]))
4140 // adjust datap of all reachable 'op' insns when moving back
4141 // returns 1 if at least 1 op was found
4142 // returns -1 if path without an op was found
4143 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4145 struct label_ref *lr;
4148 if (ops[i].cc_scratch == magic)
4150 ops[i].cc_scratch = magic;
4153 if (g_labels[i] != NULL) {
4154 lr = &g_label_refs[i];
4155 for (; lr != NULL; lr = lr->next) {
4156 check_i(&ops[i], lr->i);
4157 ret |= adjust_prev_op(lr->i, op, magic, datap);
4159 if (i > 0 && LAST_OP(i - 1))
4167 if (ops[i].cc_scratch == magic)
4169 ops[i].cc_scratch = magic;
4171 if (ops[i].op != op)
4174 ops[i].datap = datap;
4179 // find next instruction that reads opr
4180 // *op_i must be set to -1 by the caller
4181 // on return, *op_i is set to first referencer insn
4182 // returns 1 if exactly 1 referencer is found
4183 static int find_next_read(int i, int opcnt,
4184 const struct parsed_opr *opr, int magic, int *op_i)
4186 struct parsed_op *po;
4189 for (; i < opcnt; i++)
4191 if (ops[i].cc_scratch == magic)
4193 ops[i].cc_scratch = magic;
4196 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4197 if (po->btj != NULL) {
4199 for (j = 0; j < po->btj->count; j++) {
4200 check_i(po, po->btj->d[j].bt_i);
4201 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4207 if (po->flags & OPF_RMD)
4209 check_i(po, po->bt_i);
4210 if (po->flags & OPF_CJMP) {
4211 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4220 if (!is_opr_read(opr, po)) {
4222 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4223 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4225 full_opr = po->operand[0].lmod >= opr->lmod;
4227 if (is_opr_modified(opr, po) && full_opr) {
4231 if (po->flags & OPF_TAIL)
4246 // find next instruction that reads opr
4247 // *op_i must be set to -1 by the caller
4248 // on return, *op_i is set to first flag user insn
4249 // returns 1 if exactly 1 flag user is found
4250 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4252 struct parsed_op *po;
4255 for (; i < opcnt; i++)
4257 if (ops[i].cc_scratch == magic)
4259 ops[i].cc_scratch = magic;
4262 if (po->op == OP_CALL)
4264 if (po->flags & OPF_JMP) {
4265 if (po->btj != NULL) {
4267 for (j = 0; j < po->btj->count; j++) {
4268 check_i(po, po->btj->d[j].bt_i);
4269 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4275 if (po->flags & OPF_RMD)
4277 check_i(po, po->bt_i);
4278 if (po->flags & OPF_CJMP)
4285 if (!(po->flags & OPF_CC)) {
4286 if (po->flags & OPF_FLAGS)
4289 if (po->flags & OPF_TAIL)
4305 static int try_resolve_const(int i, const struct parsed_opr *opr,
4306 int magic, unsigned int *val)
4311 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4314 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4317 *val = ops[i].operand[1].val;
4324 static int resolve_used_bits(int i, int opcnt, int reg,
4325 int *mask, int *is_z_check)
4327 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4331 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4335 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4337 fnote(&ops[j], "(first read)\n");
4338 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4341 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4342 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4344 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4345 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4347 *mask = ops[j].operand[1].val;
4348 if (ops[j].operand[0].lmod == OPLM_BYTE
4349 && ops[j].operand[0].name[1] == 'h')
4353 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4356 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4358 *is_z_check = ops[k].pfo == PFO_Z;
4363 static const struct parsed_proto *resolve_deref(int i, int magic,
4364 struct parsed_opr *opr, int level)
4366 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4367 const struct parsed_proto *pp = NULL;
4368 int from_caller = 0;
4377 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4378 if (ret != 2 || len != strlen(opr->name)) {
4379 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4380 if (ret != 1 || len != strlen(opr->name))
4384 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4389 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4393 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4394 && strlen(ops[j].operand[1].name) == 3
4395 && ops[j].operand[0].lmod == OPLM_DWORD
4396 && ops[j].pp == NULL // no hint
4399 // allow one simple dereference (com/directx)
4400 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4401 ops[j].operand[1].name);
4405 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4410 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4413 if (ops[j].pp != NULL) {
4417 else if (ops[j].operand[1].type == OPT_REGMEM) {
4418 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4420 // maybe structure ptr in structure
4421 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4424 else if (ops[j].operand[1].type == OPT_LABEL)
4425 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4426 else if (ops[j].operand[1].type == OPT_REG) {
4429 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4431 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4432 for (k = 0; k < g_func_pp->argc; k++) {
4433 if (g_func_pp->arg[k].reg == NULL)
4435 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4436 pp = g_func_pp->arg[k].pp;
4445 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4447 ferr(&ops[j], "expected struct, got '%s %s'\n",
4448 pp->type.name, pp->name);
4452 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4455 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4456 int *pp_i, int *multi_src)
4458 const struct parsed_proto *pp = NULL;
4459 int search_advice = 0;
4464 switch (ops[i].operand[0].type) {
4466 // try to resolve struct member calls
4467 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4473 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4479 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4487 static struct parsed_proto *process_call_early(int i, int opcnt,
4490 struct parsed_op *po = &ops[i];
4491 struct parsed_proto *pp;
4497 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4501 // look for and make use of esp adjust
4503 if (!pp->is_stdcall && pp->argc_stack > 0)
4504 ret = scan_for_esp_adjust(i + 1, opcnt,
4505 pp->argc_stack * 4, &adj, &multipath, 0);
4507 if (pp->argc_stack > adj / 4)
4511 if (ops[ret].op == OP_POP) {
4512 for (j = 1; j < adj / 4; j++) {
4513 if (ops[ret + j].op != OP_POP
4514 || ops[ret + j].operand[0].reg != xCX)
4526 static struct parsed_proto *process_call(int i, int opcnt)
4528 struct parsed_op *po = &ops[i];
4529 const struct parsed_proto *pp_c;
4530 struct parsed_proto *pp;
4531 const char *tmpname;
4532 int call_i = -1, ref_i = -1;
4533 int adj = 0, multipath = 0;
4536 tmpname = opr_name(po, 0);
4541 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4543 if (!pp_c->is_func && !pp_c->is_fptr)
4544 ferr(po, "call to non-func: %s\n", pp_c->name);
4545 pp = proto_clone(pp_c);
4546 my_assert_not(pp, NULL);
4548 // not resolved just to single func
4551 switch (po->operand[0].type) {
4553 // we resolved this call and no longer need the register
4554 po->regmask_src &= ~(1 << po->operand[0].reg);
4556 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4557 && ops[call_i].operand[1].type == OPT_LABEL)
4559 // no other source users?
4560 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4562 if (ret == 1 && call_i == ref_i) {
4563 // and nothing uses it after us?
4565 find_next_read(i + 1, opcnt, &po->operand[0],
4566 i + opcnt * 11, &ref_i);
4568 // then also don't need the source mov
4569 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4581 pp = calloc(1, sizeof(*pp));
4582 my_assert_not(pp, NULL);
4585 ret = scan_for_esp_adjust(i + 1, opcnt,
4586 -1, &adj, &multipath, 0);
4587 if (ret < 0 || adj < 0) {
4588 if (!g_allow_regfunc)
4589 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4590 pp->is_unresolved = 1;
4594 if (adj > ARRAY_SIZE(pp->arg))
4595 ferr(po, "esp adjust too large: %d\n", adj);
4596 pp->ret_type.name = strdup("int");
4597 pp->argc = pp->argc_stack = adj;
4598 for (arg = 0; arg < pp->argc; arg++)
4599 pp->arg[arg].type.name = strdup("int");
4604 // look for and make use of esp adjust
4607 if (!pp->is_stdcall && pp->argc_stack > 0) {
4608 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4609 ret = scan_for_esp_adjust(i + 1, opcnt,
4610 adj_expect, &adj, &multipath, 0);
4613 if (pp->is_vararg) {
4614 if (adj / 4 < pp->argc_stack) {
4615 fnote(po, "(this call)\n");
4616 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4617 adj, pp->argc_stack * 4);
4619 // modify pp to make it have varargs as normal args
4621 pp->argc += adj / 4 - pp->argc_stack;
4622 for (; arg < pp->argc; arg++) {
4623 pp->arg[arg].type.name = strdup("int");
4626 if (pp->argc > ARRAY_SIZE(pp->arg))
4627 ferr(po, "too many args for '%s'\n", tmpname);
4629 if (pp->argc_stack > adj / 4) {
4630 fnote(po, "(this call)\n");
4631 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4632 tmpname, pp->argc_stack * 4, adj);
4635 scan_for_esp_adjust(i + 1, opcnt,
4636 pp->argc_stack * 4, &adj, &multipath, 1);
4638 else if (pp->is_vararg)
4639 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4645 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
4648 struct parsed_op *po;
4654 for (base_arg = 0; base_arg < pp->argc; base_arg++)
4655 if (pp->arg[base_arg].reg == NULL)
4658 for (j = i; j > 0; )
4660 ferr_assert(&ops[j], g_labels[j] == NULL);
4664 ferr_assert(po, po->op != OP_PUSH);
4665 if (po->op == OP_FST)
4667 if (po->operand[0].type != OPT_REGMEM)
4669 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
4672 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3))
4673 ferr(po, "bad offset %d (%d args)\n", offset, pp->argc_stack);
4675 arg = base_arg + offset / 4;
4677 po->p_argnum = arg + 1;
4678 ferr_assert(po, pp->arg[arg].datap == NULL);
4679 pp->arg[arg].datap = po;
4680 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
4681 if (regmask_ffca != NULL)
4682 *regmask_ffca |= 1 << arg;
4684 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4685 && po->operand[1].type == OPT_CONST)
4687 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4692 for (arg = base_arg; arg < pp->argc; arg++) {
4693 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
4694 po = pp->arg[arg].datap;
4696 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
4697 if (po->operand[0].lmod == OPLM_QWORD)
4704 static int collect_call_args_early(int i, struct parsed_proto *pp,
4705 int *regmask, int *regmask_ffca)
4707 struct parsed_op *po;
4711 for (arg = 0; arg < pp->argc; arg++)
4712 if (pp->arg[arg].reg == NULL)
4715 // first see if it can be easily done
4716 for (j = i; j > 0 && arg < pp->argc; )
4718 if (g_labels[j] != NULL)
4723 if (po->op == OP_CALL)
4725 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
4727 else if (po->op == OP_POP)
4729 else if (po->flags & OPF_CJMP)
4731 else if (po->op == OP_PUSH) {
4732 if (po->flags & (OPF_FARG|OPF_FARGNR))
4734 if (!g_header_mode) {
4735 ret = scan_for_mod(po, j + 1, i, 1);
4740 if (pp->arg[arg].type.is_va_list)
4744 for (arg++; arg < pp->argc; arg++)
4745 if (pp->arg[arg].reg == NULL)
4748 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4749 && po->operand[1].type == OPT_CONST)
4751 if (po->flags & (OPF_RMD|OPF_DONE))
4753 if (po->operand[1].val != pp->argc_stack * 4)
4754 ferr(po, "unexpected esp adjust: %d\n",
4755 po->operand[1].val * 4);
4756 ferr_assert(po, pp->argc - arg == pp->argc_stack);
4757 return collect_call_args_no_push(i, pp, regmask_ffca);
4765 for (arg = 0; arg < pp->argc; arg++)
4766 if (pp->arg[arg].reg == NULL)
4769 for (j = i; j > 0 && arg < pp->argc; )
4773 if (ops[j].op == OP_PUSH)
4775 ops[j].p_argnext = -1;
4776 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4777 pp->arg[arg].datap = &ops[j];
4779 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
4780 *regmask |= 1 << ops[j].operand[0].reg;
4782 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4783 ops[j].flags &= ~OPF_RSAVE;
4786 for (arg++; arg < pp->argc; arg++)
4787 if (pp->arg[arg].reg == NULL)
4795 static int sync_argnum(struct parsed_op *po, int argnum)
4797 struct parsed_op *po_tmp;
4799 // see if other branches don't have higher argnum
4800 for (po_tmp = po; po_tmp != NULL; ) {
4801 if (argnum < po_tmp->p_argnum)
4802 argnum = po_tmp->p_argnum;
4803 // note: p_argnext is active on current collect_call_args only
4804 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4807 // make all argnums consistent
4808 for (po_tmp = po; po_tmp != NULL; ) {
4809 if (po_tmp->p_argnum != 0)
4810 po_tmp->p_argnum = argnum;
4811 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4817 static int collect_call_args_r(struct parsed_op *po, int i,
4818 struct parsed_proto *pp, int *regmask, int *arg_grp,
4819 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
4821 struct parsed_proto *pp_tmp;
4822 struct parsed_op *po_tmp;
4823 struct label_ref *lr;
4824 int need_to_save_current;
4825 int arg_grp_current = 0;
4826 int save_args_seen = 0;
4833 ferr(po, "dead label encountered\n");
4837 for (; arg < pp->argc; arg++, argnum++)
4838 if (pp->arg[arg].reg == NULL)
4840 magic = (magic & 0xffffff) | (arg << 24);
4842 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4844 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4845 if (ops[j].cc_scratch != magic) {
4846 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4850 // ok: have already been here
4853 ops[j].cc_scratch = magic;
4855 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4856 lr = &g_label_refs[j];
4857 if (lr->next != NULL)
4859 for (; lr->next; lr = lr->next) {
4860 check_i(&ops[j], lr->i);
4861 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4863 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4864 arg, argnum, magic, need_op_saving, may_reuse);
4869 check_i(&ops[j], lr->i);
4870 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4872 if (j > 0 && LAST_OP(j - 1)) {
4873 // follow last branch in reverse
4878 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4879 arg, argnum, magic, need_op_saving, may_reuse);
4885 if (ops[j].op == OP_CALL)
4887 if (pp->is_unresolved)
4892 ferr(po, "arg collect hit unparsed call '%s'\n",
4893 ops[j].operand[0].name);
4894 if (may_reuse && pp_tmp->argc_stack > 0)
4895 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4896 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4898 // esp adjust of 0 means we collected it before
4899 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4900 && (ops[j].operand[1].type != OPT_CONST
4901 || ops[j].operand[1].val != 0))
4903 if (pp->is_unresolved)
4906 fnote(po, "(this call)\n");
4907 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4908 arg, pp->argc, ops[j].operand[1].val);
4910 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4912 if (pp->is_unresolved)
4915 fnote(po, "(this call)\n");
4916 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4918 else if (ops[j].flags & OPF_CJMP)
4920 if (pp->is_unresolved)
4925 else if (ops[j].op == OP_PUSH
4926 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4928 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4931 ops[j].p_argnext = -1;
4932 po_tmp = pp->arg[arg].datap;
4934 ops[j].p_argnext = po_tmp - ops;
4935 pp->arg[arg].datap = &ops[j];
4937 argnum = sync_argnum(&ops[j], argnum);
4939 need_to_save_current = 0;
4941 if (ops[j].operand[0].type == OPT_REG)
4942 reg = ops[j].operand[0].reg;
4944 if (!need_op_saving) {
4945 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4946 need_to_save_current = (ret >= 0);
4948 if (need_op_saving || need_to_save_current) {
4949 // mark this arg as one that needs operand saving
4950 pp->arg[arg].is_saved = 1;
4952 if (save_args_seen & (1 << (argnum - 1))) {
4955 if (arg_grp_current >= MAX_ARG_GRP)
4956 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
4960 else if (ops[j].p_argnum == 0)
4961 ops[j].flags |= OPF_RMD;
4963 // some PUSHes are reused by different calls on other branches,
4964 // but that can't happen if we didn't branch, so they
4965 // can be removed from future searches (handles nested calls)
4967 ops[j].flags |= OPF_FARGNR;
4969 ops[j].flags |= OPF_FARG;
4970 ops[j].flags &= ~OPF_RSAVE;
4972 // check for __VALIST
4973 if (!pp->is_unresolved && g_func_pp != NULL
4974 && pp->arg[arg].type.is_va_list)
4977 ret = resolve_origin(j, &ops[j].operand[0],
4978 magic + 1, &k, NULL);
4979 if (ret == 1 && k >= 0)
4981 if (ops[k].op == OP_LEA) {
4982 if (!g_func_pp->is_vararg)
4983 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
4986 snprintf(buf, sizeof(buf), "arg_%X",
4987 g_func_pp->argc_stack * 4);
4988 if (strstr(ops[k].operand[1].name, buf)
4989 || strstr(ops[k].operand[1].name, "arglist"))
4991 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
4992 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
4993 pp->arg[arg].is_saved = 0;
4997 ferr(&ops[k], "va_list arg detection failed\n");
4999 // check for va_list from g_func_pp arg too
5000 else if (ops[k].op == OP_MOV
5001 && is_stack_access(&ops[k], &ops[k].operand[1]))
5003 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5004 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5006 ops[k].flags |= OPF_RMD | OPF_DONE;
5007 ops[j].flags |= OPF_RMD;
5008 ops[j].p_argpass = ret + 1;
5009 pp->arg[arg].is_saved = 0;
5016 if (pp->arg[arg].is_saved) {
5017 ops[j].flags &= ~OPF_RMD;
5018 ops[j].p_argnum = argnum;
5021 // tracking reg usage
5023 *regmask |= 1 << reg;
5027 if (!pp->is_unresolved) {
5029 for (; arg < pp->argc; arg++, argnum++)
5030 if (pp->arg[arg].reg == NULL)
5033 magic = (magic & 0xffffff) | (arg << 24);
5036 if (ops[j].p_arggrp > arg_grp_current) {
5038 arg_grp_current = ops[j].p_arggrp;
5040 if (ops[j].p_argnum > 0)
5041 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5044 if (arg < pp->argc) {
5045 ferr(po, "arg collect failed for '%s': %d/%d\n",
5046 pp->name, arg, pp->argc);
5050 if (arg_grp_current > *arg_grp)
5051 *arg_grp = arg_grp_current;
5056 static int collect_call_args(struct parsed_op *po, int i,
5057 struct parsed_proto *pp, int *regmask, int magic)
5059 // arg group is for cases when pushes for
5060 // multiple funcs are going on
5061 struct parsed_op *po_tmp;
5066 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5072 // propagate arg_grp
5073 for (a = 0; a < pp->argc; a++) {
5074 if (pp->arg[a].reg != NULL)
5077 po_tmp = pp->arg[a].datap;
5078 while (po_tmp != NULL) {
5079 po_tmp->p_arggrp = arg_grp;
5080 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5085 if (pp->is_unresolved) {
5087 pp->argc_stack += ret;
5088 for (a = 0; a < pp->argc; a++)
5089 if (pp->arg[a].type.name == NULL)
5090 pp->arg[a].type.name = strdup("int");
5096 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5097 int regmask_now, int *regmask,
5098 int regmask_save_now, int *regmask_save,
5099 int *regmask_init, int regmask_arg)
5101 struct parsed_op *po;
5109 for (; i < opcnt; i++)
5112 if (cbits[i >> 3] & (1 << (i & 7)))
5114 cbits[i >> 3] |= (1 << (i & 7));
5116 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5117 if (po->flags & (OPF_RMD|OPF_DONE))
5119 if (po->btj != NULL) {
5120 for (j = 0; j < po->btj->count; j++) {
5121 check_i(po, po->btj->d[j].bt_i);
5122 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5123 regmask_now, regmask, regmask_save_now, regmask_save,
5124 regmask_init, regmask_arg);
5129 check_i(po, po->bt_i);
5130 if (po->flags & OPF_CJMP)
5131 reg_use_pass(po->bt_i, opcnt, cbits,
5132 regmask_now, regmask, regmask_save_now, regmask_save,
5133 regmask_init, regmask_arg);
5139 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5140 && !g_func_pp->is_userstack
5141 && po->operand[0].type == OPT_REG)
5143 reg = po->operand[0].reg;
5144 ferr_assert(po, reg >= 0);
5147 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5148 if (regmask_now & (1 << reg)) {
5149 already_saved = regmask_save_now & (1 << reg);
5150 flags_set = OPF_RSAVE | OPF_DONE;
5153 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5155 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5156 reg, 0, 0, flags_set);
5159 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5161 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5166 ferr_assert(po, !already_saved);
5167 po->flags |= flags_set;
5169 if (regmask_now & (1 << reg)) {
5170 regmask_save_now |= (1 << reg);
5171 *regmask_save |= regmask_save_now;
5176 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5177 reg = po->operand[0].reg;
5178 ferr_assert(po, reg >= 0);
5180 if (regmask_save_now & (1 << reg))
5181 regmask_save_now &= ~(1 << reg);
5183 regmask_now &= ~(1 << reg);
5186 else if (po->op == OP_CALL) {
5187 if ((po->regmask_dst & (1 << xAX))
5188 && !(po->regmask_dst & (1 << xDX)))
5190 if (po->flags & OPF_TAIL)
5191 // don't need eax, will do "return f();" or "f(); return;"
5192 po->regmask_dst &= ~(1 << xAX);
5194 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5196 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5199 po->regmask_dst &= ~(1 << xAX);
5203 // not "full stack" mode and have something in stack
5204 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5205 ferr(po, "float stack is not empty on func call\n");
5208 if (po->flags & OPF_NOREGS)
5211 // if incomplete register is used, clear it on init to avoid
5212 // later use of uninitialized upper part in some situations
5213 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5214 && po->operand[0].lmod != OPLM_DWORD)
5216 reg = po->operand[0].reg;
5217 ferr_assert(po, reg >= 0);
5219 if (!(regmask_now & (1 << reg)))
5220 *regmask_init |= 1 << reg;
5223 regmask_op = po->regmask_src | po->regmask_dst;
5225 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5226 regmask_new &= ~(1 << xSP);
5227 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5228 regmask_new &= ~(1 << xBP);
5230 if (regmask_new != 0)
5231 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5233 if (regmask_op & (1 << xBP)) {
5234 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5235 if (po->regmask_dst & (1 << xBP))
5236 // compiler decided to drop bp frame and use ebp as scratch
5237 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5239 regmask_op &= ~(1 << xBP);
5243 if (po->flags & OPF_FPUSH) {
5244 if (regmask_now & mxST1)
5245 regmask_now |= mxSTa; // switch to "full stack" mode
5246 if (regmask_now & mxSTa)
5247 po->flags |= OPF_FSHIFT;
5248 if (!(regmask_now & mxST7_2)) {
5250 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5254 regmask_now |= regmask_op;
5255 *regmask |= regmask_now;
5258 if (po->flags & OPF_FPOP) {
5259 if ((regmask_now & mxSTa) == 0)
5260 ferr(po, "float pop on empty stack?\n");
5261 if (regmask_now & (mxST7_2 | mxST1))
5262 po->flags |= OPF_FSHIFT;
5263 if (!(regmask_now & mxST7_2)) {
5265 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5269 if (po->flags & OPF_TAIL) {
5270 if (!(regmask_now & mxST7_2)) {
5271 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5272 if (!(regmask_now & mxST0))
5273 ferr(po, "no st0 on float return, mask: %x\n",
5276 else if (regmask_now & mxST1_0)
5277 ferr(po, "float regs on tail: %x\n", regmask_now);
5280 // there is support for "conditional tailcall", sort of
5281 if (!(po->flags & OPF_CC))
5287 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5291 for (i = 0; i < pp->argc; i++)
5292 if (pp->arg[i].reg == NULL)
5296 memmove(&pp->arg[i + 1], &pp->arg[i],
5297 sizeof(pp->arg[0]) * pp->argc_stack);
5298 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5299 pp->arg[i].reg = strdup(reg);
5300 pp->arg[i].type.name = strdup("int");
5305 static void output_std_flags(FILE *fout, struct parsed_op *po,
5306 int *pfomask, const char *dst_opr_text)
5308 if (*pfomask & (1 << PFO_Z)) {
5309 fprintf(fout, "\n cond_z = (%s%s == 0);",
5310 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5311 *pfomask &= ~(1 << PFO_Z);
5313 if (*pfomask & (1 << PFO_S)) {
5314 fprintf(fout, "\n cond_s = (%s%s < 0);",
5315 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5316 *pfomask &= ~(1 << PFO_S);
5321 OPP_FORCE_NORETURN = (1 << 0),
5322 OPP_SIMPLE_ARGS = (1 << 1),
5323 OPP_ALIGN = (1 << 2),
5326 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5329 const char *cconv = "";
5331 if (pp->is_fastcall)
5332 cconv = "__fastcall ";
5333 else if (pp->is_stdcall && pp->argc_reg == 0)
5334 cconv = "__stdcall ";
5336 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5338 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5339 fprintf(fout, "noreturn ");
5342 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5347 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5351 output_pp_attrs(fout, pp, flags);
5354 fprintf(fout, "%s", pp->name);
5359 for (i = 0; i < pp->argc; i++) {
5361 fprintf(fout, ", ");
5362 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5363 && !(flags & OPP_SIMPLE_ARGS))
5366 output_pp(fout, pp->arg[i].pp, 0);
5368 else if (pp->arg[i].type.is_retreg) {
5369 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5372 fprintf(fout, "%s", pp->arg[i].type.name);
5374 fprintf(fout, " a%d", i + 1);
5377 if (pp->is_vararg) {
5379 fprintf(fout, ", ");
5380 fprintf(fout, "...");
5385 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5391 snprintf(buf1, sizeof(buf1), "%d", grp);
5392 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5397 static void gen_x_cleanup(int opcnt);
5399 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5401 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5402 struct parsed_opr *last_arith_dst = NULL;
5403 char buf1[256], buf2[256], buf3[256], cast[64];
5404 struct parsed_proto *pp, *pp_tmp;
5405 struct parsed_data *pd;
5406 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5407 unsigned char cbits[MAX_OPS / 8];
5408 const char *float_type;
5409 const char *float_st0;
5410 const char *float_st1;
5411 int need_float_stack = 0;
5412 int need_float_sw = 0; // status word
5413 int need_tmp_var = 0;
5417 int label_pending = 0;
5418 int need_double = 0;
5419 int regmask_save = 0; // used regs saved/restored in this func
5420 int regmask_arg; // regs from this function args (fastcall, etc)
5421 int regmask_ret; // regs needed on ret
5422 int regmask_now; // temp
5423 int regmask_init = 0; // regs that need zero initialization
5424 int regmask_pp = 0; // regs used in complex push-pop graph
5425 int regmask_ffca = 0; // float function call args
5426 int regmask = 0; // used regs
5436 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5437 g_stack_frame_used = 0;
5438 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5439 regmask_init = g_regmask_init;
5441 g_func_pp = proto_parse(fhdr, funcn, 0);
5442 if (g_func_pp == NULL)
5443 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5445 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5446 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5449 // - resolve all branches
5450 // - parse calls with labels
5451 resolve_branches_parse_calls(opcnt);
5454 // - handle ebp/esp frame, remove ops related to it
5455 scan_prologue_epilogue(opcnt);
5458 // - remove dead labels
5459 // - set regs needed at ret
5460 for (i = 0; i < opcnt; i++)
5462 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5467 if (ops[i].op == OP_RET)
5468 ops[i].regmask_src |= regmask_ret;
5472 // - process trivial calls
5473 for (i = 0; i < opcnt; i++)
5476 if (po->flags & (OPF_RMD|OPF_DONE))
5479 if (po->op == OP_CALL)
5481 pp = process_call_early(i, opcnt, &j);
5483 if (!(po->flags & OPF_ATAIL)) {
5484 // since we know the args, try to collect them
5485 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5493 // commit esp adjust
5494 if (ops[j].op != OP_POP)
5495 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5497 for (l = 0; l < pp->argc_stack; l++)
5498 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5502 if (strstr(pp->ret_type.name, "int64"))
5505 po->flags |= OPF_DONE;
5511 // - process calls, stage 2
5512 // - handle some push/pop pairs
5513 // - scan for STD/CLD, propagate DF
5514 // - try to resolve needed x87 status word bits
5515 for (i = 0; i < opcnt; i++)
5520 if (po->flags & OPF_RMD)
5523 if (po->op == OP_CALL)
5525 if (!(po->flags & OPF_DONE)) {
5526 pp = process_call(i, opcnt);
5528 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5529 // since we know the args, collect them
5530 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5532 // for unresolved, collect after other passes
5536 ferr_assert(po, pp != NULL);
5538 po->regmask_src |= get_pp_arg_regmask_src(pp);
5539 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5541 if (po->regmask_dst & mxST0)
5542 po->flags |= OPF_FPUSH;
5544 if (strstr(pp->ret_type.name, "int64"))
5550 if (po->flags & OPF_DONE)
5555 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
5556 && po->operand[0].type == OPT_CONST)
5558 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5563 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5567 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5568 scan_propagate_df(i + 1, opcnt);
5573 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
5574 ferr(po, "TODO: fnstsw to mem\n");
5575 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
5577 ferr(po, "fnstsw resolve failed\n");
5578 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
5579 (void *)(long)(mask | (z_check << 16)));
5581 ferr(po, "failed to find fcom: %d\n", ret);
5590 // - find POPs for PUSHes, rm both
5591 // - scan for all used registers
5592 memset(cbits, 0, sizeof(cbits));
5593 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5594 0, ®mask_save, ®mask_init, regmask_arg);
5596 need_float_stack = !!(regmask & mxST7_2);
5599 // - find flag set ops for their users
5600 // - do unresolved calls
5601 // - declare indirect functions
5602 // - other op specific processing
5603 for (i = 0; i < opcnt; i++)
5606 if (po->flags & (OPF_RMD|OPF_DONE))
5609 if (po->flags & OPF_CC)
5611 int setters[16], cnt = 0, branched = 0;
5613 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
5614 &branched, setters, &cnt);
5615 if (ret < 0 || cnt <= 0)
5616 ferr(po, "unable to trace flag setter(s)\n");
5617 if (cnt > ARRAY_SIZE(setters))
5618 ferr(po, "too many flag setters\n");
5620 for (j = 0; j < cnt; j++)
5622 tmp_op = &ops[setters[j]]; // flag setter
5625 // to get nicer code, we try to delay test and cmp;
5626 // if we can't because of operand modification, or if we
5627 // have arith op, or branch, make it calculate flags explicitly
5628 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5630 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5631 pfomask = 1 << po->pfo;
5633 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5634 pfomask = 1 << po->pfo;
5637 // see if we'll be able to handle based on op result
5638 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5639 && po->pfo != PFO_Z && po->pfo != PFO_S
5640 && po->pfo != PFO_P)
5642 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5644 pfomask = 1 << po->pfo;
5647 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5648 propagate_lmod(tmp_op, &tmp_op->operand[0],
5649 &tmp_op->operand[1]);
5650 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5655 tmp_op->pfomask |= pfomask;
5656 cond_vars |= pfomask;
5658 // note: may overwrite, currently not a problem
5662 if (po->op == OP_RCL || po->op == OP_RCR
5663 || po->op == OP_ADC || po->op == OP_SBB)
5664 cond_vars |= 1 << PFO_C;
5670 cond_vars |= 1 << PFO_Z;
5674 if (po->operand[0].lmod == OPLM_DWORD)
5679 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
5684 // note: resolved non-reg calls are OPF_DONE already
5686 ferr_assert(po, pp != NULL);
5688 if (pp->is_unresolved) {
5689 int regmask_stack = 0;
5690 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5692 // this is pretty rough guess:
5693 // see ecx and edx were pushed (and not their saved versions)
5694 for (arg = 0; arg < pp->argc; arg++) {
5695 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
5698 tmp_op = pp->arg[arg].datap;
5700 ferr(po, "parsed_op missing for arg%d\n", arg);
5701 if (tmp_op->operand[0].type == OPT_REG)
5702 regmask_stack |= 1 << tmp_op->operand[0].reg;
5705 if (!((regmask_stack & (1 << xCX))
5706 && (regmask_stack & (1 << xDX))))
5708 if (pp->argc_stack != 0
5709 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5711 pp_insert_reg_arg(pp, "ecx");
5712 pp->is_fastcall = 1;
5713 regmask_init |= 1 << xCX;
5714 regmask |= 1 << xCX;
5716 if (pp->argc_stack != 0
5717 || ((regmask | regmask_arg) & (1 << xDX)))
5719 pp_insert_reg_arg(pp, "edx");
5720 regmask_init |= 1 << xDX;
5721 regmask |= 1 << xDX;
5725 // note: __cdecl doesn't fall into is_unresolved category
5726 if (pp->argc_stack > 0)
5732 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
5734 // <var> = offset <something>
5735 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5736 && !IS_START(po->operand[1].name, "off_"))
5738 if (!po->operand[0].pp->is_fptr)
5739 ferr(po, "%s not declared as fptr when it should be\n",
5740 po->operand[0].name);
5741 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5742 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5743 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5744 fnote(po, "var: %s\n", buf1);
5745 fnote(po, "func: %s\n", buf2);
5746 ferr(po, "^ mismatch\n");
5754 if (po->operand[0].lmod == OPLM_DWORD) {
5755 // 32bit division is common, look for it
5756 if (po->op == OP_DIV)
5757 ret = scan_for_reg_clear(i, xDX);
5759 ret = scan_for_cdq_edx(i);
5761 po->flags |= OPF_32BIT;
5770 po->flags |= OPF_RMD | OPF_DONE;
5780 if (po->operand[0].lmod == OPLM_QWORD)
5790 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5792 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5794 po->flags |= OPF_32BIT;
5802 // this might need it's own pass...
5803 if (po->op != OP_FST && po->p_argnum > 0)
5804 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
5806 // correct for "full stack" mode late enable
5807 if ((po->flags & (OPF_PPUSH|OPF_FPOP)) && need_float_stack)
5808 po->flags |= OPF_FSHIFT;
5811 float_type = need_double ? "double" : "float";
5812 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
5813 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
5815 // output starts here
5817 // define userstack size
5818 if (g_func_pp->is_userstack) {
5819 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5820 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5821 fprintf(fout, "#endif\n");
5824 // the function itself
5825 ferr_assert(ops, !g_func_pp->is_fptr);
5826 output_pp(fout, g_func_pp,
5827 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5828 fprintf(fout, "\n{\n");
5830 // declare indirect functions
5831 for (i = 0; i < opcnt; i++) {
5833 if (po->flags & OPF_RMD)
5836 if (po->op == OP_CALL) {
5839 ferr(po, "NULL pp\n");
5841 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5842 if (pp->name[0] != 0) {
5843 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5844 memcpy(pp->name, "i_", 2);
5846 // might be declared already
5848 for (j = 0; j < i; j++) {
5849 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5850 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5860 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5863 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5864 fprintf(fout, ";\n");
5869 // output LUTs/jumptables
5870 for (i = 0; i < g_func_pd_cnt; i++) {
5872 fprintf(fout, " static const ");
5873 if (pd->type == OPT_OFFSET) {
5874 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5876 for (j = 0; j < pd->count; j++) {
5878 fprintf(fout, ", ");
5879 fprintf(fout, "&&%s", pd->d[j].u.label);
5883 fprintf(fout, "%s %s[] =\n { ",
5884 lmod_type_u(ops, pd->lmod), pd->label);
5886 for (j = 0; j < pd->count; j++) {
5888 fprintf(fout, ", ");
5889 fprintf(fout, "%u", pd->d[j].u.val);
5892 fprintf(fout, " };\n");
5896 // declare stack frame, va_arg
5898 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5899 if (g_func_lmods & (1 << OPLM_WORD))
5900 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5901 if (g_func_lmods & (1 << OPLM_BYTE))
5902 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5903 if (g_func_lmods & (1 << OPLM_QWORD))
5904 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5905 fprintf(fout, " } sf;\n");
5909 if (g_func_pp->is_userstack) {
5910 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5911 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5915 if (g_func_pp->is_vararg) {
5916 fprintf(fout, " va_list ap;\n");
5920 // declare arg-registers
5921 for (i = 0; i < g_func_pp->argc; i++) {
5922 if (g_func_pp->arg[i].reg != NULL) {
5923 reg = char_array_i(regs_r32,
5924 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5925 if (regmask & (1 << reg)) {
5926 if (g_func_pp->arg[i].type.is_retreg)
5927 fprintf(fout, " u32 %s = *r_%s;\n",
5928 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5930 fprintf(fout, " u32 %s = (u32)a%d;\n",
5931 g_func_pp->arg[i].reg, i + 1);
5934 if (g_func_pp->arg[i].type.is_retreg)
5935 ferr(ops, "retreg '%s' is unused?\n",
5936 g_func_pp->arg[i].reg);
5937 fprintf(fout, " // %s = a%d; // unused\n",
5938 g_func_pp->arg[i].reg, i + 1);
5944 // declare normal registers
5945 regmask_now = regmask & ~regmask_arg;
5946 regmask_now &= ~(1 << xSP);
5947 if (regmask_now & 0x00ff) {
5948 for (reg = 0; reg < 8; reg++) {
5949 if (regmask_now & (1 << reg)) {
5950 fprintf(fout, " u32 %s", regs_r32[reg]);
5951 if (regmask_init & (1 << reg))
5952 fprintf(fout, " = 0");
5953 fprintf(fout, ";\n");
5959 if (regmask_now & 0xff00) {
5960 for (reg = 8; reg < 16; reg++) {
5961 if (regmask_now & (1 << reg)) {
5962 fprintf(fout, " mmxr %s", regs_r32[reg]);
5963 if (regmask_init & (1 << reg))
5964 fprintf(fout, " = { 0, }");
5965 fprintf(fout, ";\n");
5971 if (need_float_stack) {
5972 fprintf(fout, " %s f_st[8];\n", float_type);
5973 fprintf(fout, " int f_stp = 0;\n");
5977 if (regmask_now & 0xff0000) {
5978 for (reg = 16; reg < 24; reg++) {
5979 if (regmask_now & (1 << reg)) {
5980 fprintf(fout, " %s f_st%d", float_type, reg - 16);
5981 if (regmask_init & (1 << reg))
5982 fprintf(fout, " = 0");
5983 fprintf(fout, ";\n");
5990 if (need_float_sw) {
5991 fprintf(fout, " u16 f_sw;\n");
5996 for (reg = 0; reg < 8; reg++) {
5997 if (regmask_save & (1 << reg)) {
5998 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6004 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6005 if (save_arg_vars[i] == 0)
6007 for (reg = 0; reg < 32; reg++) {
6008 if (save_arg_vars[i] & (1 << reg)) {
6009 fprintf(fout, " u32 %s;\n",
6010 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6017 for (reg = 0; reg < 32; reg++) {
6018 if (regmask_ffca & (1 << reg)) {
6019 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6025 // declare push-pop temporaries
6027 for (reg = 0; reg < 8; reg++) {
6028 if (regmask_pp & (1 << reg)) {
6029 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6036 for (i = 0; i < 8; i++) {
6037 if (cond_vars & (1 << i)) {
6038 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6045 fprintf(fout, " u32 tmp;\n");
6050 fprintf(fout, " u64 tmp64;\n");
6055 fprintf(fout, "\n");
6057 // do stack clear, if needed
6058 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6060 if (g_stack_clear_len != 0) {
6061 if (g_stack_clear_len <= 4) {
6062 for (i = 0; i < g_stack_clear_len; i++)
6063 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6064 fprintf(fout, "0;\n");
6067 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6068 g_stack_clear_start, g_stack_clear_len * 4);
6072 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6075 if (g_func_pp->is_vararg) {
6076 if (g_func_pp->argc_stack == 0)
6077 ferr(ops, "vararg func without stack args?\n");
6078 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6082 for (i = 0; i < opcnt; i++)
6084 if (g_labels[i] != NULL) {
6085 fprintf(fout, "\n%s:\n", g_labels[i]);
6088 delayed_flag_op = NULL;
6089 last_arith_dst = NULL;
6093 if (po->flags & OPF_RMD)
6098 #define assert_operand_cnt(n_) \
6099 if (po->operand_cnt != n_) \
6100 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6102 // conditional/flag using op?
6103 if (po->flags & OPF_CC)
6109 // we go through all this trouble to avoid using parsed_flag_op,
6110 // which makes generated code much nicer
6111 if (delayed_flag_op != NULL)
6113 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6114 po->pfo, po->pfo_inv);
6117 else if (last_arith_dst != NULL
6118 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6119 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6122 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6123 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6124 last_arith_dst->lmod, buf3);
6127 else if (tmp_op != NULL) {
6128 // use preprocessed flag calc results
6129 if (!(tmp_op->pfomask & (1 << po->pfo)))
6130 ferr(po, "not prepared for pfo %d\n", po->pfo);
6132 // note: pfo_inv was not yet applied
6133 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6134 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6137 ferr(po, "all methods of finding comparison failed\n");
6140 if (po->flags & OPF_JMP) {
6141 fprintf(fout, " if %s", buf1);
6143 else if (po->op == OP_RCL || po->op == OP_RCR
6144 || po->op == OP_ADC || po->op == OP_SBB)
6147 fprintf(fout, " cond_%s = %s;\n",
6148 parsed_flag_op_names[po->pfo], buf1);
6150 else if (po->flags & OPF_DATA) { // SETcc
6151 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6152 fprintf(fout, " %s = %s;", buf2, buf1);
6155 ferr(po, "unhandled conditional op\n");
6159 pfomask = po->pfomask;
6164 assert_operand_cnt(2);
6165 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6166 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6167 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6168 fprintf(fout, " %s = %s;", buf1,
6169 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6174 assert_operand_cnt(2);
6175 po->operand[1].lmod = OPLM_DWORD; // always
6176 fprintf(fout, " %s = %s;",
6177 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6178 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6183 assert_operand_cnt(2);
6184 fprintf(fout, " %s = %s;",
6185 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6186 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6190 assert_operand_cnt(2);
6191 switch (po->operand[1].lmod) {
6193 strcpy(buf3, "(s8)");
6196 strcpy(buf3, "(s16)");
6199 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6201 fprintf(fout, " %s = %s;",
6202 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6203 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6208 assert_operand_cnt(2);
6209 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6210 fprintf(fout, " tmp = %s;",
6211 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6212 fprintf(fout, " %s = %s;",
6213 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6214 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6215 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6216 fprintf(fout, " %s = %stmp;",
6217 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6218 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6219 snprintf(g_comment, sizeof(g_comment), "xchg");
6223 assert_operand_cnt(1);
6224 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6225 fprintf(fout, " %s = ~%s;", buf1, buf1);
6229 assert_operand_cnt(2);
6230 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6231 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6232 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6233 strcpy(g_comment, "xlat");
6237 assert_operand_cnt(2);
6238 fprintf(fout, " %s = (s32)%s >> 31;",
6239 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6240 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6241 strcpy(g_comment, "cdq");
6245 assert_operand_cnt(1);
6246 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6247 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6251 if (po->flags & OPF_REP) {
6252 assert_operand_cnt(3);
6257 assert_operand_cnt(2);
6258 fprintf(fout, " %s = %sesi; esi %c= %d;",
6259 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6260 lmod_cast_u_ptr(po, po->operand[1].lmod),
6261 (po->flags & OPF_DF) ? '-' : '+',
6262 lmod_bytes(po, po->operand[1].lmod));
6263 strcpy(g_comment, "lods");
6268 if (po->flags & OPF_REP) {
6269 assert_operand_cnt(3);
6270 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6271 (po->flags & OPF_DF) ? '-' : '+',
6272 lmod_bytes(po, po->operand[1].lmod));
6273 fprintf(fout, " %sedi = eax;",
6274 lmod_cast_u_ptr(po, po->operand[1].lmod));
6275 strcpy(g_comment, "rep stos");
6278 assert_operand_cnt(2);
6279 fprintf(fout, " %sedi = eax; edi %c= %d;",
6280 lmod_cast_u_ptr(po, po->operand[1].lmod),
6281 (po->flags & OPF_DF) ? '-' : '+',
6282 lmod_bytes(po, po->operand[1].lmod));
6283 strcpy(g_comment, "stos");
6288 j = lmod_bytes(po, po->operand[0].lmod);
6289 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6290 l = (po->flags & OPF_DF) ? '-' : '+';
6291 if (po->flags & OPF_REP) {
6292 assert_operand_cnt(3);
6294 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6297 " %sedi = %sesi;", buf1, buf1);
6298 strcpy(g_comment, "rep movs");
6301 assert_operand_cnt(2);
6302 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6303 buf1, buf1, l, j, l, j);
6304 strcpy(g_comment, "movs");
6309 // repe ~ repeat while ZF=1
6310 j = lmod_bytes(po, po->operand[0].lmod);
6311 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6312 l = (po->flags & OPF_DF) ? '-' : '+';
6313 if (po->flags & OPF_REP) {
6314 assert_operand_cnt(3);
6316 " while (ecx != 0) {\n");
6317 if (pfomask & (1 << PFO_C)) {
6320 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6321 pfomask &= ~(1 << PFO_C);
6324 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6325 buf1, buf1, l, j, l, j);
6328 " if (cond_z %s 0) break;\n",
6329 (po->flags & OPF_REPZ) ? "==" : "!=");
6332 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6333 (po->flags & OPF_REPZ) ? "e" : "ne");
6336 assert_operand_cnt(2);
6338 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6339 buf1, buf1, l, j, l, j);
6340 strcpy(g_comment, "cmps");
6342 pfomask &= ~(1 << PFO_Z);
6343 last_arith_dst = NULL;
6344 delayed_flag_op = NULL;
6348 // only does ZF (for now)
6349 // repe ~ repeat while ZF=1
6350 j = lmod_bytes(po, po->operand[1].lmod);
6351 l = (po->flags & OPF_DF) ? '-' : '+';
6352 if (po->flags & OPF_REP) {
6353 assert_operand_cnt(3);
6355 " while (ecx != 0) {\n");
6357 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6358 lmod_cast_u(po, po->operand[1].lmod),
6359 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6362 " if (cond_z %s 0) break;\n",
6363 (po->flags & OPF_REPZ) ? "==" : "!=");
6366 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6367 (po->flags & OPF_REPZ) ? "e" : "ne");
6370 assert_operand_cnt(2);
6371 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6372 lmod_cast_u(po, po->operand[1].lmod),
6373 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6374 strcpy(g_comment, "scas");
6376 pfomask &= ~(1 << PFO_Z);
6377 last_arith_dst = NULL;
6378 delayed_flag_op = NULL;
6381 // arithmetic w/flags
6383 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6384 goto dualop_arith_const;
6385 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6389 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6390 if (po->operand[1].type == OPT_CONST) {
6391 j = lmod_bytes(po, po->operand[0].lmod);
6392 if (((1ull << j * 8) - 1) == po->operand[1].val)
6393 goto dualop_arith_const;
6398 assert_operand_cnt(2);
6399 fprintf(fout, " %s %s= %s;",
6400 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6402 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6403 output_std_flags(fout, po, &pfomask, buf1);
6404 last_arith_dst = &po->operand[0];
6405 delayed_flag_op = NULL;
6409 // and 0, or ~0 used instead mov
6410 assert_operand_cnt(2);
6411 fprintf(fout, " %s = %s;",
6412 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6413 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6414 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6415 output_std_flags(fout, po, &pfomask, buf1);
6416 last_arith_dst = &po->operand[0];
6417 delayed_flag_op = NULL;
6422 assert_operand_cnt(2);
6423 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6424 if (pfomask & (1 << PFO_C)) {
6425 if (po->operand[1].type == OPT_CONST) {
6426 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6427 j = po->operand[1].val;
6430 if (po->op == OP_SHL)
6434 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6438 ferr(po, "zero shift?\n");
6442 pfomask &= ~(1 << PFO_C);
6444 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6445 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6446 if (po->operand[1].type != OPT_CONST)
6447 fprintf(fout, " & 0x1f");
6449 output_std_flags(fout, po, &pfomask, buf1);
6450 last_arith_dst = &po->operand[0];
6451 delayed_flag_op = NULL;
6455 assert_operand_cnt(2);
6456 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6457 fprintf(fout, " %s = %s%s >> %s;", buf1,
6458 lmod_cast_s(po, po->operand[0].lmod), buf1,
6459 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6460 output_std_flags(fout, po, &pfomask, buf1);
6461 last_arith_dst = &po->operand[0];
6462 delayed_flag_op = NULL;
6467 assert_operand_cnt(3);
6468 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6469 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6470 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6471 if (po->operand[2].type != OPT_CONST) {
6472 // no handling for "undefined" case, hopefully not needed
6473 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6476 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6477 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6478 if (po->op == OP_SHLD) {
6479 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6480 buf1, buf3, buf1, buf2, l, buf3);
6481 strcpy(g_comment, "shld");
6484 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6485 buf1, buf3, buf1, buf2, l, buf3);
6486 strcpy(g_comment, "shrd");
6488 output_std_flags(fout, po, &pfomask, buf1);
6489 last_arith_dst = &po->operand[0];
6490 delayed_flag_op = NULL;
6495 assert_operand_cnt(2);
6496 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6497 if (po->operand[1].type == OPT_CONST) {
6498 j = po->operand[1].val;
6499 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6500 fprintf(fout, po->op == OP_ROL ?
6501 " %s = (%s << %d) | (%s >> %d);" :
6502 " %s = (%s >> %d) | (%s << %d);",
6503 buf1, buf1, j, buf1,
6504 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6508 output_std_flags(fout, po, &pfomask, buf1);
6509 last_arith_dst = &po->operand[0];
6510 delayed_flag_op = NULL;
6515 assert_operand_cnt(2);
6516 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6517 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6518 if (po->operand[1].type == OPT_CONST) {
6519 j = po->operand[1].val % l;
6521 ferr(po, "zero rotate\n");
6522 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6523 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6524 if (po->op == OP_RCL) {
6526 " %s = (%s << %d) | (cond_c << %d)",
6527 buf1, buf1, j, j - 1);
6529 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6533 " %s = (%s >> %d) | (cond_c << %d)",
6534 buf1, buf1, j, l - j);
6536 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6538 fprintf(fout, ";\n");
6539 fprintf(fout, " cond_c = tmp;");
6543 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6544 output_std_flags(fout, po, &pfomask, buf1);
6545 last_arith_dst = &po->operand[0];
6546 delayed_flag_op = NULL;
6550 assert_operand_cnt(2);
6551 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6552 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6553 // special case for XOR
6554 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
6555 for (j = 0; j <= PFO_LE; j++) {
6556 if (pfomask & (1 << j)) {
6557 fprintf(fout, " cond_%s = %d;\n",
6558 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
6559 pfomask &= ~(1 << j);
6562 fprintf(fout, " %s = 0;",
6563 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6564 last_arith_dst = &po->operand[0];
6565 delayed_flag_op = NULL;
6571 assert_operand_cnt(2);
6572 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6573 if (pfomask & (1 << PFO_C)) {
6574 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6575 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6576 if (po->operand[0].lmod == OPLM_DWORD) {
6577 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6578 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6579 fprintf(fout, " %s = (u32)tmp64;",
6580 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6581 strcat(g_comment, " add64");
6584 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6585 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6586 fprintf(fout, " %s += %s;",
6587 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6590 pfomask &= ~(1 << PFO_C);
6591 output_std_flags(fout, po, &pfomask, buf1);
6592 last_arith_dst = &po->operand[0];
6593 delayed_flag_op = NULL;
6596 if (pfomask & (1 << PFO_LE)) {
6597 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
6598 fprintf(fout, " cond_%s = %s;\n",
6599 parsed_flag_op_names[PFO_LE], buf1);
6600 pfomask &= ~(1 << PFO_LE);
6605 assert_operand_cnt(2);
6606 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6607 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6608 for (j = 0; j <= PFO_LE; j++) {
6609 if (!(pfomask & (1 << j)))
6611 if (j == PFO_Z || j == PFO_S)
6614 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6615 fprintf(fout, " cond_%s = %s;\n",
6616 parsed_flag_op_names[j], buf1);
6617 pfomask &= ~(1 << j);
6624 assert_operand_cnt(2);
6625 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6626 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6627 if (po->op == OP_SBB
6628 && IS(po->operand[0].name, po->operand[1].name))
6630 // avoid use of unitialized var
6631 fprintf(fout, " %s = -cond_c;", buf1);
6632 // carry remains what it was
6633 pfomask &= ~(1 << PFO_C);
6636 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6637 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6639 output_std_flags(fout, po, &pfomask, buf1);
6640 last_arith_dst = &po->operand[0];
6641 delayed_flag_op = NULL;
6645 assert_operand_cnt(2);
6646 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6647 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6648 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6650 output_std_flags(fout, po, &pfomask, buf1);
6651 last_arith_dst = &po->operand[0];
6652 delayed_flag_op = NULL;
6653 strcat(g_comment, " bsf");
6657 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6658 for (j = 0; j <= PFO_LE; j++) {
6659 if (!(pfomask & (1 << j)))
6661 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6664 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6665 fprintf(fout, " cond_%s = %s;\n",
6666 parsed_flag_op_names[j], buf1);
6667 pfomask &= ~(1 << j);
6673 if (pfomask & (1 << PFO_C))
6674 // carry is unaffected by inc/dec.. wtf?
6675 ferr(po, "carry propagation needed\n");
6677 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6678 if (po->operand[0].type == OPT_REG) {
6679 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6680 fprintf(fout, " %s%s;", buf1, buf2);
6683 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6684 fprintf(fout, " %s %s= 1;", buf1, buf2);
6686 output_std_flags(fout, po, &pfomask, buf1);
6687 last_arith_dst = &po->operand[0];
6688 delayed_flag_op = NULL;
6692 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6693 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6694 fprintf(fout, " %s = -%s%s;", buf1,
6695 lmod_cast_s(po, po->operand[0].lmod), buf2);
6696 last_arith_dst = &po->operand[0];
6697 delayed_flag_op = NULL;
6698 if (pfomask & (1 << PFO_C)) {
6699 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6700 pfomask &= ~(1 << PFO_C);
6705 if (po->operand_cnt == 2) {
6706 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6709 if (po->operand_cnt == 3)
6710 ferr(po, "TODO imul3\n");
6713 assert_operand_cnt(1);
6714 switch (po->operand[0].lmod) {
6716 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6717 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6718 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6719 fprintf(fout, " edx = tmp64 >> 32;\n");
6720 fprintf(fout, " eax = tmp64;");
6723 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6724 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6725 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6729 ferr(po, "TODO: unhandled mul type\n");
6732 last_arith_dst = NULL;
6733 delayed_flag_op = NULL;
6738 assert_operand_cnt(1);
6739 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6740 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6741 po->op == OP_IDIV));
6742 switch (po->operand[0].lmod) {
6744 if (po->flags & OPF_32BIT)
6745 snprintf(buf2, sizeof(buf2), "%seax", cast);
6747 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6748 snprintf(buf2, sizeof(buf2), "%stmp64",
6749 (po->op == OP_IDIV) ? "(s64)" : "");
6751 if (po->operand[0].type == OPT_REG
6752 && po->operand[0].reg == xDX)
6754 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6755 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6758 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6759 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6763 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6764 snprintf(buf2, sizeof(buf2), "%stmp",
6765 (po->op == OP_IDIV) ? "(s32)" : "");
6766 if (po->operand[0].type == OPT_REG
6767 && po->operand[0].reg == xDX)
6769 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6771 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6775 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6777 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6780 strcat(g_comment, " div16");
6783 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6785 last_arith_dst = NULL;
6786 delayed_flag_op = NULL;
6791 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6793 for (j = 0; j < 8; j++) {
6794 if (pfomask & (1 << j)) {
6795 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6796 fprintf(fout, " cond_%s = %s;",
6797 parsed_flag_op_names[j], buf1);
6804 last_arith_dst = NULL;
6805 delayed_flag_op = po;
6809 // SETcc - should already be handled
6812 // note: we reuse OP_Jcc for SETcc, only flags differ
6814 fprintf(fout, "\n goto %s;", po->operand[0].name);
6818 fprintf(fout, " if (ecx == 0)\n");
6819 fprintf(fout, " goto %s;", po->operand[0].name);
6820 strcat(g_comment, " jecxz");
6824 fprintf(fout, " if (--ecx != 0)\n");
6825 fprintf(fout, " goto %s;", po->operand[0].name);
6826 strcat(g_comment, " loop");
6830 assert_operand_cnt(1);
6831 last_arith_dst = NULL;
6832 delayed_flag_op = NULL;
6834 if (po->operand[0].type == OPT_REGMEM) {
6835 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6838 ferr(po, "parse failure for jmp '%s'\n",
6839 po->operand[0].name);
6840 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6843 else if (po->operand[0].type != OPT_LABEL)
6844 ferr(po, "unhandled jmp type\n");
6846 fprintf(fout, " goto %s;", po->operand[0].name);
6850 assert_operand_cnt(1);
6852 my_assert_not(pp, NULL);
6855 if (po->flags & OPF_CC) {
6856 // we treat conditional branch to another func
6857 // (yes such code exists..) as conditional tailcall
6859 fprintf(fout, " {\n");
6862 if (pp->is_fptr && !pp->is_arg) {
6863 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6864 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6866 if (pp->is_unresolved)
6867 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6868 buf3, asmfn, po->asmln, pp->name);
6871 fprintf(fout, "%s", buf3);
6872 if (strstr(pp->ret_type.name, "int64")) {
6873 if (po->flags & OPF_TAIL)
6874 ferr(po, "int64 and tail?\n");
6875 fprintf(fout, "tmp64 = ");
6877 else if (!IS(pp->ret_type.name, "void")) {
6878 if (po->flags & OPF_TAIL) {
6879 if (regmask_ret & mxAX) {
6880 fprintf(fout, "return ");
6881 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6882 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6884 else if (regmask_ret & mxST0)
6885 ferr(po, "float tailcall\n");
6887 else if (po->regmask_dst & mxAX) {
6888 fprintf(fout, "eax = ");
6889 if (pp->ret_type.is_ptr)
6890 fprintf(fout, "(u32)");
6892 else if (po->regmask_dst & mxST0) {
6893 ferr_assert(po, po->flags & OPF_FPUSH);
6894 if (need_float_stack)
6895 fprintf(fout, "f_st[--f_stp & 7] = ");
6897 fprintf(fout, "f_st0 = ");
6901 if (pp->name[0] == 0)
6902 ferr(po, "missing pp->name\n");
6903 fprintf(fout, "%s%s(", pp->name,
6904 pp->has_structarg ? "_sa" : "");
6906 if (po->flags & OPF_ATAIL) {
6907 if (pp->argc_stack != g_func_pp->argc_stack
6908 || (pp->argc_stack > 0
6909 && pp->is_stdcall != g_func_pp->is_stdcall))
6910 ferr(po, "incompatible tailcall\n");
6911 if (g_func_pp->has_retreg)
6912 ferr(po, "TODO: retreg+tailcall\n");
6914 for (arg = j = 0; arg < pp->argc; arg++) {
6916 fprintf(fout, ", ");
6919 if (pp->arg[arg].type.is_ptr)
6920 snprintf(cast, sizeof(cast), "(%s)",
6921 pp->arg[arg].type.name);
6923 if (pp->arg[arg].reg != NULL) {
6924 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6928 for (; j < g_func_pp->argc; j++)
6929 if (g_func_pp->arg[j].reg == NULL)
6931 fprintf(fout, "%sa%d", cast, j + 1);
6936 for (arg = 0; arg < pp->argc; arg++) {
6938 fprintf(fout, ", ");
6941 if (pp->arg[arg].type.is_ptr)
6942 snprintf(cast, sizeof(cast), "(%s)",
6943 pp->arg[arg].type.name);
6945 if (pp->arg[arg].reg != NULL) {
6946 if (pp->arg[arg].type.is_retreg)
6947 fprintf(fout, "&%s", pp->arg[arg].reg);
6948 else if (IS(pp->arg[arg].reg, "ebp")
6949 && !(po->flags & OPF_EBP_S))
6951 // rare special case
6952 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
6953 strcat(g_comment, " bp_ref");
6956 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6961 tmp_op = pp->arg[arg].datap;
6963 ferr(po, "parsed_op missing for arg%d\n", arg);
6965 if (tmp_op->flags & OPF_VAPUSH) {
6966 fprintf(fout, "ap");
6968 else if (tmp_op->op == OP_FST) {
6969 fprintf(fout, "fs_%d", tmp_op->p_argnum);
6970 if (tmp_op->operand[0].lmod == OPLM_QWORD)
6973 else if (tmp_op->p_argpass != 0) {
6974 fprintf(fout, "a%d", tmp_op->p_argpass);
6976 else if (pp->arg[arg].is_saved) {
6977 ferr_assert(po, tmp_op->p_argnum > 0);
6978 fprintf(fout, "%s%s", cast,
6979 saved_arg_name(buf1, sizeof(buf1),
6980 tmp_op->p_arggrp, tmp_op->p_argnum));
6984 out_src_opr(buf1, sizeof(buf1),
6985 tmp_op, &tmp_op->operand[0], cast, 0));
6989 fprintf(fout, ");");
6991 if (strstr(pp->ret_type.name, "int64")) {
6992 fprintf(fout, "\n");
6993 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
6994 fprintf(fout, "%seax = tmp64;", buf3);
6997 if (pp->is_unresolved) {
6998 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7000 strcat(g_comment, buf2);
7003 if (po->flags & OPF_TAIL) {
7005 if (i == opcnt - 1 || pp->is_noreturn)
7007 else if (IS(pp->ret_type.name, "void"))
7009 else if (!(regmask_ret & (1 << xAX)))
7011 // else already handled as 'return f()'
7014 fprintf(fout, "\n%sreturn;", buf3);
7015 strcat(g_comment, " ^ tailcall");
7018 strcat(g_comment, " tailcall");
7020 if ((regmask_ret & (1 << xAX))
7021 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7023 ferr(po, "int func -> void func tailcall?\n");
7026 if (pp->is_noreturn)
7027 strcat(g_comment, " noreturn");
7028 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7029 strcat(g_comment, " argframe");
7030 if (po->flags & OPF_CC)
7031 strcat(g_comment, " cond");
7033 if (po->flags & OPF_CC)
7034 fprintf(fout, "\n }");
7036 delayed_flag_op = NULL;
7037 last_arith_dst = NULL;
7041 if (g_func_pp->is_vararg)
7042 fprintf(fout, " va_end(ap);\n");
7043 if (g_func_pp->has_retreg) {
7044 for (arg = 0; arg < g_func_pp->argc; arg++)
7045 if (g_func_pp->arg[arg].type.is_retreg)
7046 fprintf(fout, " *r_%s = %s;\n",
7047 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7050 if (regmask_ret & mxST0) {
7051 fprintf(fout, " return %s;", float_st0);
7053 else if (!(regmask_ret & mxAX)) {
7054 if (i != opcnt - 1 || label_pending)
7055 fprintf(fout, " return;");
7057 else if (g_func_pp->ret_type.is_ptr) {
7058 fprintf(fout, " return (%s)eax;",
7059 g_func_pp->ret_type.name);
7061 else if (IS(g_func_pp->ret_type.name, "__int64"))
7062 fprintf(fout, " return ((u64)edx << 32) | eax;");
7064 fprintf(fout, " return eax;");
7066 last_arith_dst = NULL;
7067 delayed_flag_op = NULL;
7071 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7072 if (po->p_argnum != 0) {
7073 // special case - saved func arg
7074 fprintf(fout, " %s = %s;",
7075 saved_arg_name(buf2, sizeof(buf2),
7076 po->p_arggrp, po->p_argnum), buf1);
7079 else if (po->flags & OPF_RSAVE) {
7080 fprintf(fout, " s_%s = %s;", buf1, buf1);
7083 else if (po->flags & OPF_PPUSH) {
7085 ferr_assert(po, tmp_op != NULL);
7086 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7087 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7090 else if (g_func_pp->is_userstack) {
7091 fprintf(fout, " *(--esp) = %s;", buf1);
7094 if (!(g_ida_func_attr & IDAFA_NORETURN))
7095 ferr(po, "stray push encountered\n");
7100 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7101 if (po->flags & OPF_RSAVE) {
7102 fprintf(fout, " %s = s_%s;", buf1, buf1);
7105 else if (po->flags & OPF_PPUSH) {
7106 // push/pop graph / non-const
7107 ferr_assert(po, po->datap == NULL);
7108 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7111 else if (po->datap != NULL) {
7114 fprintf(fout, " %s = %s;", buf1,
7115 out_src_opr(buf2, sizeof(buf2),
7116 tmp_op, &tmp_op->operand[0],
7117 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7120 else if (g_func_pp->is_userstack) {
7121 fprintf(fout, " %s = *esp++;", buf1);
7125 ferr(po, "stray pop encountered\n");
7135 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7136 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7137 po->op == OPP_ALLSHL ? "<<" : ">>");
7138 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7139 strcat(g_comment, po->op == OPP_ALLSHL
7140 ? " allshl" : " allshr");
7145 if (need_float_stack) {
7146 out_src_opr_float(buf1, sizeof(buf1),
7147 po, &po->operand[0], 1);
7148 if (po->regmask_src & mxSTa) {
7149 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7153 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7156 if (po->flags & OPF_FSHIFT)
7157 fprintf(fout, " f_st1 = f_st0;");
7158 if (po->operand[0].type == OPT_REG
7159 && po->operand[0].reg == xST0)
7161 strcat(g_comment, " fld st");
7164 fprintf(fout, " f_st0 = %s;",
7165 out_src_opr_float(buf1, sizeof(buf1),
7166 po, &po->operand[0], 0));
7168 strcat(g_comment, " fld");
7172 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7173 lmod_cast(po, po->operand[0].lmod, 1), 0);
7174 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7175 if (need_float_stack) {
7176 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7179 if (po->flags & OPF_FSHIFT)
7180 fprintf(fout, " f_st1 = f_st0;");
7181 fprintf(fout, " f_st0 = %s;", buf2);
7183 strcat(g_comment, " fild");
7187 if (need_float_stack)
7188 fprintf(fout, " f_st[--f_stp & 7] = ");
7190 if (po->flags & OPF_FSHIFT)
7191 fprintf(fout, " f_st1 = f_st0;");
7192 fprintf(fout, " f_st0 = ");
7194 switch (po->operand[0].val) {
7195 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7196 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
7197 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7198 default: ferr(po, "TODO\n"); break;
7203 if (po->flags & OPF_FARG) {
7204 // store to stack as func arg
7205 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7209 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7211 dead_dst = po->operand[0].type == OPT_REG
7212 && po->operand[0].reg == xST0;
7215 fprintf(fout, " %s = %s;", buf1, float_st0);
7216 if (po->flags & OPF_FSHIFT) {
7217 if (need_float_stack)
7218 fprintf(fout, " f_stp++;");
7220 fprintf(fout, " f_st0 = f_st1;");
7222 if (dead_dst && !(po->flags & OPF_FSHIFT))
7225 strcat(g_comment, " fst");
7229 fprintf(fout, " %s = %s%s;",
7230 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7231 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7232 if (po->flags & OPF_FSHIFT) {
7233 if (need_float_stack)
7234 fprintf(fout, " f_stp++;");
7236 fprintf(fout, " f_st0 = f_st1;");
7238 strcat(g_comment, " fist");
7245 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7247 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7249 dead_dst = (po->flags & OPF_FPOP)
7250 && po->operand[0].type == OPT_REG
7251 && po->operand[0].reg == xST0;
7253 case OP_FADD: j = '+'; break;
7254 case OP_FDIV: j = '/'; break;
7255 case OP_FMUL: j = '*'; break;
7256 case OP_FSUB: j = '-'; break;
7257 default: j = 'x'; break;
7259 if (need_float_stack) {
7261 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7262 if (po->flags & OPF_FSHIFT)
7263 fprintf(fout, " f_stp++;");
7266 if (po->flags & OPF_FSHIFT) {
7267 // note: assumes only 2 regs handled
7269 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7271 fprintf(fout, " f_st0 = f_st1;");
7274 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7276 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7281 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7283 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7285 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7287 dead_dst = (po->flags & OPF_FPOP)
7288 && po->operand[0].type == OPT_REG
7289 && po->operand[0].reg == xST0;
7290 j = po->op == OP_FDIVR ? '/' : '-';
7291 if (need_float_stack) {
7293 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7294 if (po->flags & OPF_FSHIFT)
7295 fprintf(fout, " f_stp++;");
7298 if (po->flags & OPF_FSHIFT) {
7300 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7302 fprintf(fout, " f_st0 = f_st1;");
7305 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7307 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7315 case OP_FIADD: j = '+'; break;
7316 case OP_FIDIV: j = '/'; break;
7317 case OP_FIMUL: j = '*'; break;
7318 case OP_FISUB: j = '-'; break;
7319 default: j = 'x'; break;
7321 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7323 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7324 lmod_cast(po, po->operand[0].lmod, 1), 0));
7329 fprintf(fout, " %s = %s %c %s;", float_st0,
7330 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7332 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7337 ferr_assert(po, po->datap != NULL);
7338 mask = (long)po->datap & 0xffff;
7339 z_check = ((long)po->datap >> 16) & 1;
7340 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7342 if (mask == 0x0100) { // C0 -> <
7343 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7346 else if (mask == 0x4000) { // C3 -> =
7347 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7350 else if (mask == 0x4100) { // C3, C0
7352 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7354 strcat(g_comment, " z_chk_det");
7357 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7358 "(%s < %s ? 0x0100 : 0);",
7359 float_st0, buf1, float_st0, buf1);
7363 ferr(po, "unhandled sw mask: %x\n", mask);
7364 if (po->flags & OPF_FSHIFT) {
7365 if (need_float_stack)
7366 fprintf(fout, " f_stp++;");
7368 fprintf(fout, " f_st0 = f_st1;");
7374 fprintf(fout, " %s = f_sw;",
7375 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7379 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7383 fprintf(fout, " %s = cos%s(%s);", float_st0,
7384 need_double ? "" : "f", float_st0);
7388 if (need_float_stack) {
7389 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7390 need_double ? "" : "f", float_st1, float_st0);
7391 fprintf(fout, " f_stp++;");
7394 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7395 need_double ? "" : "f");
7400 if (need_float_stack) {
7401 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7402 float_st1, need_double ? "" : "f", float_st0);
7403 fprintf(fout, " f_stp++;");
7406 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7407 need_double ? "" : "f");
7409 strcat(g_comment, " fyl2x");
7413 fprintf(fout, " %s = sin%s(%s);", float_st0,
7414 need_double ? "" : "f", float_st0);
7418 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7419 need_double ? "" : "f", float_st0);
7423 dead_dst = po->operand[0].type == OPT_REG
7424 && po->operand[0].reg == xST0;
7426 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7428 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7429 float_st0, float_st0, buf1, buf1);
7430 strcat(g_comment, " fxch");
7437 ferr_assert(po, po->flags & OPF_32BIT);
7438 fprintf(fout, " eax = (s32)%s;", float_st0);
7439 if (po->flags & OPF_FSHIFT) {
7440 if (need_float_stack)
7441 fprintf(fout, " f_stp++;");
7443 fprintf(fout, " f_st0 = f_st1;");
7445 strcat(g_comment, " ftol");
7449 if (need_float_stack) {
7450 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
7451 need_double ? "" : "f", float_st1, float_st0);
7452 fprintf(fout, " f_stp++;");
7455 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
7456 need_double ? "" : "f");
7458 strcat(g_comment, " CIpow");
7462 fprintf(fout, " do_skip_code_abort();");
7467 fprintf(fout, " do_emms();");
7472 ferr(po, "unhandled op type %d, flags %x\n",
7477 if (g_comment[0] != 0) {
7478 char *p = g_comment;
7479 while (my_isblank(*p))
7481 fprintf(fout, " // %s", p);
7486 fprintf(fout, "\n");
7488 // some sanity checking
7489 if (po->flags & OPF_REP) {
7490 if (po->op != OP_STOS && po->op != OP_MOVS
7491 && po->op != OP_CMPS && po->op != OP_SCAS)
7492 ferr(po, "unexpected rep\n");
7493 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7494 && (po->op == OP_CMPS || po->op == OP_SCAS))
7495 ferr(po, "cmps/scas with plain rep\n");
7497 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7498 && po->op != OP_CMPS && po->op != OP_SCAS)
7499 ferr(po, "unexpected repz/repnz\n");
7502 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
7504 // see is delayed flag stuff is still valid
7505 if (delayed_flag_op != NULL && delayed_flag_op != po) {
7506 if (is_any_opr_modified(delayed_flag_op, po, 0))
7507 delayed_flag_op = NULL;
7510 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7511 if (is_opr_modified(last_arith_dst, po))
7512 last_arith_dst = NULL;
7518 if (g_stack_fsz && !g_stack_frame_used)
7519 fprintf(fout, " (void)sf;\n");
7521 fprintf(fout, "}\n\n");
7523 gen_x_cleanup(opcnt);
7526 static void gen_x_cleanup(int opcnt)
7530 for (i = 0; i < opcnt; i++) {
7531 struct label_ref *lr, *lr_del;
7533 lr = g_label_refs[i].next;
7534 while (lr != NULL) {
7539 g_label_refs[i].i = -1;
7540 g_label_refs[i].next = NULL;
7542 if (ops[i].op == OP_CALL) {
7544 proto_release(ops[i].pp);
7550 struct func_proto_dep;
7552 struct func_prototype {
7557 int has_ret:3; // -1, 0, 1: unresolved, no, yes
7558 unsigned int dep_resolved:1;
7559 unsigned int is_stdcall:1;
7560 struct func_proto_dep *dep_func;
7562 const struct parsed_proto *pp; // seed pp, if any
7565 struct func_proto_dep {
7567 struct func_prototype *proto;
7568 int regmask_live; // .. at the time of call
7569 unsigned int ret_dep:1; // return from this is caller's return
7572 static struct func_prototype *hg_fp;
7573 static int hg_fp_cnt;
7575 static struct scanned_var {
7577 enum opr_lenmod lmod;
7578 unsigned int is_seeded:1;
7579 unsigned int is_c_str:1;
7580 const struct parsed_proto *pp; // seed pp, if any
7582 static int hg_var_cnt;
7584 static char **hg_refs;
7585 static int hg_ref_cnt;
7587 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7590 static struct func_prototype *hg_fp_add(const char *funcn)
7592 struct func_prototype *fp;
7594 if ((hg_fp_cnt & 0xff) == 0) {
7595 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7596 my_assert_not(hg_fp, NULL);
7597 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7600 fp = &hg_fp[hg_fp_cnt];
7601 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7603 fp->argc_stack = -1;
7609 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7614 for (i = 0; i < fp->dep_func_cnt; i++)
7615 if (IS(fp->dep_func[i].name, name))
7616 return &fp->dep_func[i];
7621 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7624 if (hg_fp_find_dep(fp, name))
7627 if ((fp->dep_func_cnt & 0xff) == 0) {
7628 fp->dep_func = realloc(fp->dep_func,
7629 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7630 my_assert_not(fp->dep_func, NULL);
7631 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7632 sizeof(fp->dep_func[0]) * 0x100);
7634 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7638 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7640 const struct func_prototype *p1 = p1_, *p2 = p2_;
7641 return strcmp(p1->name, p2->name);
7645 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7647 const struct func_prototype *p1 = p1_, *p2 = p2_;
7648 return p1->id - p2->id;
7652 static void hg_ref_add(const char *name)
7654 if ((hg_ref_cnt & 0xff) == 0) {
7655 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7656 my_assert_not(hg_refs, NULL);
7657 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7660 hg_refs[hg_ref_cnt] = strdup(name);
7661 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7665 // recursive register dep pass
7666 // - track saved regs (part 2)
7667 // - try to figure out arg-regs
7668 // - calculate reg deps
7669 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
7670 struct func_prototype *fp, int regmask_save, int regmask_dst,
7671 int *regmask_dep, int *has_ret)
7673 struct func_proto_dep *dep;
7674 struct parsed_op *po;
7675 int from_caller = 0;
7680 for (; i < opcnt; i++)
7682 if (cbits[i >> 3] & (1 << (i & 7)))
7684 cbits[i >> 3] |= (1 << (i & 7));
7688 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
7689 if (po->flags & OPF_RMD)
7692 if (po->btj != NULL) {
7694 for (j = 0; j < po->btj->count; j++) {
7695 check_i(po, po->btj->d[j].bt_i);
7696 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
7697 regmask_save, regmask_dst, regmask_dep, has_ret);
7702 check_i(po, po->bt_i);
7703 if (po->flags & OPF_CJMP) {
7704 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
7705 regmask_save, regmask_dst, regmask_dep, has_ret);
7713 if (po->flags & OPF_FARG)
7714 /* (just calculate register deps) */;
7715 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
7717 reg = po->operand[0].reg;
7718 ferr_assert(po, reg >= 0);
7720 if (po->flags & OPF_RSAVE) {
7721 regmask_save |= 1 << reg;
7724 if (po->flags & OPF_DONE)
7727 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
7729 regmask_save |= 1 << reg;
7730 po->flags |= OPF_RMD;
7731 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
7735 else if (po->flags & OPF_RMD)
7737 else if (po->op == OP_CALL) {
7738 po->regmask_dst |= 1 << xAX;
7740 dep = hg_fp_find_dep(fp, po->operand[0].name);
7742 dep->regmask_live = regmask_save | regmask_dst;
7744 else if (po->op == OP_RET) {
7745 if (po->operand_cnt > 0) {
7747 if (fp->argc_stack >= 0
7748 && fp->argc_stack != po->operand[0].val / 4)
7749 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
7750 fp->argc_stack = po->operand[0].val / 4;
7754 // if has_ret is 0, there is uninitialized eax path,
7755 // which means it's most likely void func
7756 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
7757 if (po->op == OP_CALL) {
7762 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
7765 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
7768 if (ret != 1 && from_caller) {
7769 // unresolved eax - probably void func
7773 if (j >= 0 && ops[j].op == OP_CALL) {
7774 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
7785 l = regmask_save | regmask_dst;
7786 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7789 l = po->regmask_src & ~l;
7792 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
7793 l, regmask_dst, regmask_save, po->flags);
7796 regmask_dst |= po->regmask_dst;
7798 if (po->flags & OPF_TAIL)
7803 static void gen_hdr(const char *funcn, int opcnt)
7805 unsigned char cbits[MAX_OPS / 8];
7806 const struct parsed_proto *pp_c;
7807 struct parsed_proto *pp;
7808 struct func_prototype *fp;
7809 struct parsed_op *po;
7810 int regmask_dummy = 0;
7812 int max_bp_offset = 0;
7817 pp_c = proto_parse(g_fhdr, funcn, 1);
7819 // already in seed, will add to hg_fp later
7822 fp = hg_fp_add(funcn);
7824 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7825 g_stack_frame_used = 0;
7828 // - resolve all branches
7829 // - parse calls with labels
7830 resolve_branches_parse_calls(opcnt);
7833 // - handle ebp/esp frame, remove ops related to it
7834 scan_prologue_epilogue(opcnt);
7837 // - remove dead labels
7839 for (i = 0; i < opcnt; i++)
7841 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7847 if (po->flags & (OPF_RMD|OPF_DONE))
7850 if (po->op == OP_CALL) {
7851 if (po->operand[0].type == OPT_LABEL)
7852 hg_fp_add_dep(fp, opr_name(po, 0));
7853 else if (po->pp != NULL)
7854 hg_fp_add_dep(fp, po->pp->name);
7859 // - remove dead labels
7860 // - handle push <const>/pop pairs
7861 for (i = 0; i < opcnt; i++)
7863 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7869 if (po->flags & (OPF_RMD|OPF_DONE))
7872 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
7873 scan_for_pop_const(i, opcnt, i + opcnt * 13);
7877 // - process trivial calls
7878 for (i = 0; i < opcnt; i++)
7881 if (po->flags & (OPF_RMD|OPF_DONE))
7884 if (po->op == OP_CALL)
7886 pp = process_call_early(i, opcnt, &j);
7888 if (!(po->flags & OPF_ATAIL))
7889 // since we know the args, try to collect them
7890 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
7896 // commit esp adjust
7897 if (ops[j].op != OP_POP)
7898 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
7900 for (l = 0; l < pp->argc_stack; l++)
7901 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
7905 po->flags |= OPF_DONE;
7911 // - track saved regs (simple)
7913 for (i = 0; i < opcnt; i++)
7916 if (po->flags & (OPF_RMD|OPF_DONE))
7919 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7920 && po->operand[0].reg != xCX)
7922 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
7924 // regmask_save |= 1 << po->operand[0].reg; // do it later
7925 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
7926 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
7929 else if (po->op == OP_CALL)
7931 pp = process_call(i, opcnt);
7933 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
7934 // since we know the args, collect them
7935 ret = collect_call_args(po, i, pp, ®mask_dummy,
7942 memset(cbits, 0, sizeof(cbits));
7946 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
7948 // find unreachable code - must be fixed in IDA
7949 for (i = 0; i < opcnt; i++)
7951 if (cbits[i >> 3] & (1 << (i & 7)))
7954 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
7955 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
7957 // the compiler sometimes still generates code after
7958 // noreturn OS functions
7961 if (ops[i].op != OP_NOP)
7962 ferr(&ops[i], "unreachable code\n");
7965 for (i = 0; i < g_eqcnt; i++) {
7966 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
7967 max_bp_offset = g_eqs[i].offset;
7970 if (fp->argc_stack < 0) {
7971 max_bp_offset = (max_bp_offset + 3) & ~3;
7972 fp->argc_stack = max_bp_offset / 4;
7973 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
7977 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
7978 fp->has_ret = has_ret;
7980 printf("// has_ret %d, regmask_dep %x\n",
7981 fp->has_ret, fp->regmask_dep);
7982 output_hdr_fp(stdout, fp, 1);
7983 if (IS(funcn, "sub_10007F72")) exit(1);
7986 gen_x_cleanup(opcnt);
7989 static void hg_fp_resolve_deps(struct func_prototype *fp)
7991 struct func_prototype fp_s;
7995 // this thing is recursive, so mark first..
7996 fp->dep_resolved = 1;
7998 for (i = 0; i < fp->dep_func_cnt; i++) {
7999 strcpy(fp_s.name, fp->dep_func[i].name);
8000 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8001 sizeof(hg_fp[0]), hg_fp_cmp_name);
8002 if (fp->dep_func[i].proto != NULL) {
8003 if (!fp->dep_func[i].proto->dep_resolved)
8004 hg_fp_resolve_deps(fp->dep_func[i].proto);
8006 dep = ~fp->dep_func[i].regmask_live
8007 & fp->dep_func[i].proto->regmask_dep;
8008 fp->regmask_dep |= dep;
8009 // printf("dep %s %s |= %x\n", fp->name,
8010 // fp->dep_func[i].name, dep);
8012 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8013 fp->has_ret = fp->dep_func[i].proto->has_ret;
8018 // make all thiscall/edx arg functions referenced from .data fastcall
8019 static void do_func_refs_from_data(void)
8021 struct func_prototype *fp, fp_s;
8024 for (i = 0; i < hg_ref_cnt; i++) {
8025 strcpy(fp_s.name, hg_refs[i]);
8026 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8027 sizeof(hg_fp[0]), hg_fp_cmp_name);
8031 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8032 fp->regmask_dep |= mxCX | mxDX;
8036 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8039 const struct parsed_proto *pp;
8040 char *p, namebuf[NAMELEN];
8046 for (; count > 0; count--, fp++) {
8047 if (fp->has_ret == -1)
8048 fprintf(fout, "// ret unresolved\n");
8050 fprintf(fout, "// dep:");
8051 for (j = 0; j < fp->dep_func_cnt; j++) {
8052 fprintf(fout, " %s/", fp->dep_func[j].name);
8053 if (fp->dep_func[j].proto != NULL)
8054 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8055 fp->dep_func[j].proto->has_ret);
8057 fprintf(fout, "\n");
8060 p = strchr(fp->name, '@');
8062 memcpy(namebuf, fp->name, p - fp->name);
8063 namebuf[p - fp->name] = 0;
8071 pp = proto_parse(g_fhdr, name, 1);
8072 if (pp != NULL && pp->is_include)
8075 if (fp->pp != NULL) {
8076 // part of seed, output later
8080 regmask_dep = fp->regmask_dep;
8081 argc_normal = fp->argc_stack;
8083 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8084 (fp->has_ret ? "int" : "void"));
8085 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8086 && (regmask_dep & ~mxCX) == 0)
8088 fprintf(fout, "/*__thiscall*/ ");
8092 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8093 && (regmask_dep & ~(mxCX | mxDX)) == 0)
8095 fprintf(fout, " __fastcall ");
8096 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8102 else if (regmask_dep && !fp->is_stdcall) {
8103 fprintf(fout, "/*__usercall*/ ");
8105 else if (regmask_dep) {
8106 fprintf(fout, "/*__userpurge*/ ");
8108 else if (fp->is_stdcall)
8109 fprintf(fout, " __stdcall ");
8111 fprintf(fout, " __cdecl ");
8113 fprintf(fout, "%s(", name);
8116 for (j = 0; j < xSP; j++) {
8117 if (regmask_dep & (1 << j)) {
8120 fprintf(fout, ", ");
8122 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8124 fprintf(fout, "int");
8125 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8129 for (j = 0; j < argc_normal; j++) {
8132 fprintf(fout, ", ");
8133 if (fp->pp != NULL) {
8134 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8135 if (!fp->pp->arg[arg - 1].type.is_ptr)
8139 fprintf(fout, "int ");
8140 fprintf(fout, "a%d", arg);
8143 fprintf(fout, ");\n");
8147 static void output_hdr(FILE *fout)
8149 static const char *lmod_c_names[] = {
8150 [OPLM_UNSPEC] = "???",
8151 [OPLM_BYTE] = "uint8_t",
8152 [OPLM_WORD] = "uint16_t",
8153 [OPLM_DWORD] = "uint32_t",
8154 [OPLM_QWORD] = "uint64_t",
8156 const struct scanned_var *var;
8157 struct func_prototype *fp;
8158 char line[256] = { 0, };
8162 // add stuff from headers
8163 for (i = 0; i < pp_cache_size; i++) {
8164 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8165 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8167 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8168 fp = hg_fp_add(name);
8169 fp->pp = &pp_cache[i];
8170 fp->argc_stack = fp->pp->argc_stack;
8171 fp->is_stdcall = fp->pp->is_stdcall;
8172 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8173 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8177 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8178 for (i = 0; i < hg_fp_cnt; i++)
8179 hg_fp_resolve_deps(&hg_fp[i]);
8181 // adjust functions referenced from data segment
8182 do_func_refs_from_data();
8184 // note: messes up .proto ptr, don't use
8185 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8188 for (i = 0; i < hg_var_cnt; i++) {
8191 if (var->pp != NULL)
8194 else if (var->is_c_str)
8195 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8197 fprintf(fout, "extern %-8s %s;",
8198 lmod_c_names[var->lmod], var->name);
8201 fprintf(fout, " // seeded");
8202 fprintf(fout, "\n");
8205 fprintf(fout, "\n");
8207 // output function prototypes
8208 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8211 fprintf(fout, "\n// - seed -\n");
8214 while (fgets(line, sizeof(line), g_fhdr))
8215 fwrite(line, 1, strlen(line), fout);
8218 // '=' needs special treatment
8220 static char *next_word_s(char *w, size_t wsize, char *s)
8227 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8229 for (i = 1; i < wsize - 1; i++) {
8231 printf("warning: missing closing quote: \"%s\"\n", s);
8240 for (; i < wsize - 1; i++) {
8241 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8247 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8248 printf("warning: '%s' truncated\n", w);
8253 static int cmpstringp(const void *p1, const void *p2)
8255 return strcmp(*(char * const *)p1, *(char * const *)p2);
8258 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8263 if (strstr(p, "..."))
8264 // unable to determine, assume needed
8267 if (*p == '.') // .text, .data, ...
8268 // ref from other data or non-function -> no
8271 p2 = strpbrk(p, "+:\r\n\x18");
8274 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8275 // referenced from removed code
8281 static int ida_xrefs_show_need(FILE *fasm, char *p,
8282 char **rlist, int rlist_len)
8288 p = strrchr(p, ';');
8289 if (p != NULL && *p == ';' && IS_START(p + 2, "DATA XREF: ")) {
8291 if (is_xref_needed(p, rlist, rlist_len))
8298 if (!my_fgets(line, sizeof(line), fasm))
8300 // non-first line is always indented
8301 if (!my_isblank(line[0]))
8304 // should be no content, just comment
8309 p = strrchr(p, ';');
8311 // it's printed once, but no harm to check again
8312 if (IS_START(p, "DATA XREF: "))
8315 if (is_xref_needed(p, rlist, rlist_len)) {
8320 fseek(fasm, pos, SEEK_SET);
8324 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8326 struct scanned_var *var;
8327 char line[256] = { 0, };
8336 // skip to next data section
8337 while (my_fgets(line, sizeof(line), fasm))
8342 if (*p == 0 || *p == ';')
8345 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8346 if (*p == 0 || *p == ';')
8349 if (*p != 's' || !IS_START(p, "segment para public"))
8355 if (p == NULL || !IS_START(p, "segment para public"))
8359 if (!IS_START(p, "'DATA'"))
8363 while (my_fgets(line, sizeof(line), fasm))
8368 no_identifier = my_isblank(*p);
8371 if (*p == 0 || *p == ';')
8374 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8375 words[wordc][0] = 0;
8376 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8377 if (*p == 0 || *p == ';') {
8383 if (wordc == 2 && IS(words[1], "ends"))
8388 if (no_identifier) {
8389 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8390 hg_ref_add(words[2]);
8394 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8395 // when this starts, we don't need anything from this section
8399 // check refs comment(s)
8400 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8403 if ((hg_var_cnt & 0xff) == 0) {
8404 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8405 * (hg_var_cnt + 0x100));
8406 my_assert_not(hg_vars, NULL);
8407 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8410 var = &hg_vars[hg_var_cnt++];
8411 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8413 // maybe already in seed header?
8414 var->pp = proto_parse(g_fhdr, var->name, 1);
8415 if (var->pp != NULL) {
8416 if (var->pp->is_fptr) {
8417 var->lmod = OPLM_DWORD;
8420 else if (var->pp->is_func)
8422 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8423 aerr("unhandled C type '%s' for '%s'\n",
8424 var->pp->type.name, var->name);
8430 if (IS(words[1], "dd")) {
8431 var->lmod = OPLM_DWORD;
8432 if (wordc >= 4 && IS(words[2], "offset"))
8433 hg_ref_add(words[3]);
8435 else if (IS(words[1], "dw"))
8436 var->lmod = OPLM_WORD;
8437 else if (IS(words[1], "db")) {
8438 var->lmod = OPLM_BYTE;
8439 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8440 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8444 else if (IS(words[1], "dq"))
8445 var->lmod = OPLM_QWORD;
8446 //else if (IS(words[1], "dt"))
8448 aerr("type '%s' not known\n", words[1]);
8456 static void set_label(int i, const char *name)
8462 p = strchr(name, ':');
8466 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8467 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8468 g_labels[i] = realloc(g_labels[i], len + 1);
8469 my_assert_not(g_labels[i], NULL);
8470 memcpy(g_labels[i], name, len);
8471 g_labels[i][len] = 0;
8480 static struct chunk_item *func_chunks;
8481 static int func_chunk_cnt;
8482 static int func_chunk_alloc;
8484 static void add_func_chunk(FILE *fasm, const char *name, int line)
8486 if (func_chunk_cnt >= func_chunk_alloc) {
8487 func_chunk_alloc *= 2;
8488 func_chunks = realloc(func_chunks,
8489 func_chunk_alloc * sizeof(func_chunks[0]));
8490 my_assert_not(func_chunks, NULL);
8492 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8493 func_chunks[func_chunk_cnt].name = strdup(name);
8494 func_chunks[func_chunk_cnt].asmln = line;
8498 static int cmp_chunks(const void *p1, const void *p2)
8500 const struct chunk_item *c1 = p1, *c2 = p2;
8501 return strcmp(c1->name, c2->name);
8504 static void scan_ahead(FILE *fasm)
8514 oldpos = ftell(fasm);
8517 while (my_fgets(line, sizeof(line), fasm))
8528 // get rid of random tabs
8529 for (i = 0; line[i] != 0; i++)
8530 if (line[i] == '\t')
8533 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8536 next_word(words[0], sizeof(words[0]), p);
8537 if (words[0][0] == 0)
8538 aerr("missing name for func chunk?\n");
8540 add_func_chunk(fasm, words[0], asmln);
8542 else if (IS_START(p, "; sctend"))
8548 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8549 words[wordc][0] = 0;
8550 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8551 if (*p == 0 || *p == ';') {
8557 if (wordc == 2 && IS(words[1], "ends"))
8561 fseek(fasm, oldpos, SEEK_SET);
8565 int main(int argc, char *argv[])
8567 FILE *fout, *fasm, *frlist;
8568 struct parsed_data *pd = NULL;
8570 char **rlist = NULL;
8572 int rlist_alloc = 0;
8573 int func_chunks_used = 0;
8574 int func_chunks_sorted = 0;
8575 int func_chunk_i = -1;
8576 long func_chunk_ret = 0;
8577 int func_chunk_ret_ln = 0;
8578 int scanned_ahead = 0;
8580 char words[20][256];
8581 enum opr_lenmod lmod;
8582 char *sctproto = NULL;
8584 int pending_endp = 0;
8586 int skip_code_end = 0;
8587 int skip_warned = 0;
8600 for (arg = 1; arg < argc; arg++) {
8601 if (IS(argv[arg], "-v"))
8603 else if (IS(argv[arg], "-rf"))
8604 g_allow_regfunc = 1;
8605 else if (IS(argv[arg], "-uc"))
8606 g_allow_user_icall = 1;
8607 else if (IS(argv[arg], "-m"))
8609 else if (IS(argv[arg], "-hdr"))
8610 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8615 if (argc < arg + 3) {
8616 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8617 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8619 " -hdr - header generation mode\n"
8620 " -rf - allow unannotated indirect calls\n"
8621 " -uc - allow ind. calls/refs to __usercall\n"
8622 " -m - allow multiple .text sections\n"
8623 "[rlist] is a file with function names to skip,"
8631 asmfn = argv[arg++];
8632 fasm = fopen(asmfn, "r");
8633 my_assert_not(fasm, NULL);
8635 hdrfn = argv[arg++];
8636 g_fhdr = fopen(hdrfn, "r");
8637 my_assert_not(g_fhdr, NULL);
8640 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8641 my_assert_not(rlist, NULL);
8642 // needs special handling..
8643 rlist[rlist_len++] = "__alloca_probe";
8645 func_chunk_alloc = 32;
8646 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8647 my_assert_not(func_chunks, NULL);
8649 memset(words, 0, sizeof(words));
8651 for (; arg < argc; arg++) {
8654 frlist = fopen(argv[arg], "r");
8655 my_assert_not(frlist, NULL);
8657 while (my_fgets(line, sizeof(line), frlist)) {
8659 if (*p == 0 || *p == ';')
8662 if (IS_START(p, "#if 0")
8663 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
8667 else if (IS_START(p, "#endif"))
8674 p = next_word(words[0], sizeof(words[0]), p);
8675 if (words[0][0] == 0)
8678 if (rlist_len >= rlist_alloc) {
8679 rlist_alloc = rlist_alloc * 2 + 64;
8680 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
8681 my_assert_not(rlist, NULL);
8683 rlist[rlist_len++] = strdup(words[0]);
8691 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
8693 fout = fopen(argv[arg_out], "w");
8694 my_assert_not(fout, NULL);
8697 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
8698 my_assert_not(g_eqs, NULL);
8700 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
8701 g_label_refs[i].i = -1;
8702 g_label_refs[i].next = NULL;
8706 scan_variables(fasm, rlist, rlist_len);
8708 while (my_fgets(line, sizeof(line), fasm))
8717 // get rid of random tabs
8718 for (i = 0; line[i] != 0; i++)
8719 if (line[i] == '\t')
8724 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
8725 goto do_pending_endp; // eww..
8727 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
8729 static const char *attrs[] = {
8738 // parse IDA's attribute-list comment
8739 g_ida_func_attr = 0;
8742 for (; *p != 0; p = sskip(p)) {
8743 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8744 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8745 g_ida_func_attr |= 1 << i;
8746 p += strlen(attrs[i]);
8750 if (i == ARRAY_SIZE(attrs)) {
8751 anote("unparsed IDA attr: %s\n", p);
8754 if (IS(attrs[i], "fpd=")) {
8755 p = next_word(words[0], sizeof(words[0]), p);
8760 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
8762 static const char *attrs[] = {
8767 // parse manual attribute-list comment
8768 g_sct_func_attr = 0;
8771 for (; *p != 0; p = sskip(p)) {
8772 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8773 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8774 g_sct_func_attr |= 1 << i;
8775 p += strlen(attrs[i]);
8782 // clear_sf=start,len (in dwords)
8783 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
8784 &g_stack_clear_len, &j);
8786 // clear_regmask=<mask>
8787 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
8789 anote("unparsed attr value: %s\n", p);
8794 else if (i == ARRAY_SIZE(attrs)) {
8795 anote("unparsed sct attr: %s\n", p);
8800 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8803 next_word(words[0], sizeof(words[0]), p);
8804 if (words[0][0] == 0)
8805 aerr("missing name for func chunk?\n");
8807 if (!scanned_ahead) {
8808 add_func_chunk(fasm, words[0], asmln);
8809 func_chunks_sorted = 0;
8812 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
8814 if (func_chunk_i >= 0) {
8815 if (func_chunk_i < func_chunk_cnt
8816 && IS(func_chunks[func_chunk_i].name, g_func))
8818 // move on to next chunk
8819 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8821 aerr("seek failed for '%s' chunk #%d\n",
8822 g_func, func_chunk_i);
8823 asmln = func_chunks[func_chunk_i].asmln;
8827 if (func_chunk_ret == 0)
8828 aerr("no return from chunk?\n");
8829 fseek(fasm, func_chunk_ret, SEEK_SET);
8830 asmln = func_chunk_ret_ln;
8836 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
8837 func_chunks_used = 1;
8839 if (IS_START(g_func, "sub_")) {
8840 unsigned long addr = strtoul(p, NULL, 16);
8841 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
8842 if (addr > f_addr && !scanned_ahead) {
8843 //anote("scan_ahead caused by '%s', addr %lx\n",
8847 func_chunks_sorted = 0;
8855 for (i = wordc; i < ARRAY_SIZE(words); i++)
8857 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8858 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8859 if (*p == 0 || *p == ';') {
8864 if (*p != 0 && *p != ';')
8865 aerr("too many words\n");
8867 if (skip_code_end) {
8872 // allow asm patches in comments
8874 if (IS_START(p, "; sctpatch:")) {
8876 if (*p == 0 || *p == ';')
8878 goto parse_words; // lame
8880 if (IS_START(p, "; sctproto:")) {
8881 sctproto = strdup(p + 11);
8883 else if (IS_START(p, "; sctend")) {
8888 else if (IS_START(p, "; sctskip_start")) {
8889 if (in_func && !g_skip_func) {
8891 ops[pi].op = OPP_ABORT;
8892 ops[pi].asmln = asmln;
8898 else if (IS_START(p, "; sctskip_end")) {
8906 awarn("wordc == 0?\n");
8910 // don't care about this:
8911 if (words[0][0] == '.'
8912 || IS(words[0], "include")
8913 || IS(words[0], "assume") || IS(words[1], "segment")
8914 || IS(words[0], "align"))
8920 // do delayed endp processing to collect switch jumptables
8922 if (in_func && !g_skip_func && !end && wordc >= 2
8923 && ((words[0][0] == 'd' && words[0][2] == 0)
8924 || (words[1][0] == 'd' && words[1][2] == 0)))
8927 if (words[1][0] == 'd' && words[1][2] == 0) {
8929 if (g_func_pd_cnt >= pd_alloc) {
8930 pd_alloc = pd_alloc * 2 + 16;
8931 g_func_pd = realloc(g_func_pd,
8932 sizeof(g_func_pd[0]) * pd_alloc);
8933 my_assert_not(g_func_pd, NULL);
8935 pd = &g_func_pd[g_func_pd_cnt];
8937 memset(pd, 0, sizeof(*pd));
8938 strcpy(pd->label, words[0]);
8939 pd->type = OPT_CONST;
8940 pd->lmod = lmod_from_directive(words[1]);
8946 anote("skipping alignment byte?\n");
8949 lmod = lmod_from_directive(words[0]);
8950 if (lmod != pd->lmod)
8951 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
8954 if (pd->count_alloc < pd->count + wordc) {
8955 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
8956 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
8957 my_assert_not(pd->d, NULL);
8959 for (; i < wordc; i++) {
8960 if (IS(words[i], "offset")) {
8961 pd->type = OPT_OFFSET;
8964 p = strchr(words[i], ',');
8967 if (pd->type == OPT_OFFSET)
8968 pd->d[pd->count].u.label = strdup(words[i]);
8970 pd->d[pd->count].u.val = parse_number(words[i]);
8971 pd->d[pd->count].bt_i = -1;
8977 if (in_func && !g_skip_func) {
8979 gen_hdr(g_func, pi);
8981 gen_func(fout, g_fhdr, g_func, pi);
8986 g_ida_func_attr = 0;
8987 g_sct_func_attr = 0;
8988 g_stack_clear_start = 0;
8989 g_stack_clear_len = 0;
8994 func_chunks_used = 0;
8997 memset(&ops, 0, pi * sizeof(ops[0]));
9002 for (i = 0; i < g_func_pd_cnt; i++) {
9004 if (pd->type == OPT_OFFSET) {
9005 for (j = 0; j < pd->count; j++)
9006 free(pd->d[j].u.label);
9021 if (IS(words[1], "proc")) {
9023 aerr("proc '%s' while in_func '%s'?\n",
9026 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9028 strcpy(g_func, words[0]);
9029 set_label(0, words[0]);
9034 if (IS(words[1], "endp"))
9037 aerr("endp '%s' while not in_func?\n", words[0]);
9038 if (!IS(g_func, words[0]))
9039 aerr("endp '%s' while in_func '%s'?\n",
9042 aerr("endp '%s' while skipping code\n", words[0]);
9044 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9045 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
9051 if (!g_skip_func && func_chunks_used) {
9052 // start processing chunks
9053 struct chunk_item *ci, key = { g_func, 0 };
9055 func_chunk_ret = ftell(fasm);
9056 func_chunk_ret_ln = asmln;
9057 if (!func_chunks_sorted) {
9058 qsort(func_chunks, func_chunk_cnt,
9059 sizeof(func_chunks[0]), cmp_chunks);
9060 func_chunks_sorted = 1;
9062 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9063 sizeof(func_chunks[0]), cmp_chunks);
9065 aerr("'%s' needs chunks, but none found\n", g_func);
9066 func_chunk_i = ci - func_chunks;
9067 for (; func_chunk_i > 0; func_chunk_i--)
9068 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9071 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9073 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9074 asmln = func_chunks[func_chunk_i].asmln;
9082 if (wordc == 2 && IS(words[1], "ends")) {
9086 goto do_pending_endp;
9090 // scan for next text segment
9091 while (my_fgets(line, sizeof(line), fasm)) {
9094 if (*p == 0 || *p == ';')
9097 if (strstr(p, "segment para public 'CODE' use32"))
9104 p = strchr(words[0], ':');
9106 set_label(pi, words[0]);
9110 if (!in_func || g_skip_func || skip_code) {
9111 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9113 anote("skipping from '%s'\n", g_labels[pi]);
9117 g_labels[pi] = NULL;
9121 if (wordc > 1 && IS(words[1], "="))
9124 aerr("unhandled equ, wc=%d\n", wordc);
9125 if (g_eqcnt >= eq_alloc) {
9127 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9128 my_assert_not(g_eqs, NULL);
9131 len = strlen(words[0]);
9132 if (len > sizeof(g_eqs[0].name) - 1)
9133 aerr("equ name too long: %d\n", len);
9134 strcpy(g_eqs[g_eqcnt].name, words[0]);
9136 if (!IS(words[3], "ptr"))
9137 aerr("unhandled equ\n");
9138 if (IS(words[2], "dword"))
9139 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9140 else if (IS(words[2], "word"))
9141 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9142 else if (IS(words[2], "byte"))
9143 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9144 else if (IS(words[2], "qword"))
9145 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9147 aerr("bad lmod: '%s'\n", words[2]);
9149 g_eqs[g_eqcnt].offset = parse_number(words[4]);
9154 if (pi >= ARRAY_SIZE(ops))
9155 aerr("too many ops\n");
9157 parse_op(&ops[pi], words, wordc);
9159 ops[pi].datap = sctproto;
9174 // vim:ts=2:shiftwidth=2:expandtab