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
172 // must be sorted (larger len must be further in enum)
181 #define MAX_EXITS 128
183 #define MAX_OPERANDS 3
186 #define OPR_INIT(type_, lmod_, reg_) \
187 { type_, lmod_, reg_, }
191 enum opr_lenmod lmod;
193 unsigned int is_ptr:1; // pointer in C
194 unsigned int is_array:1; // array in C
195 unsigned int type_from_var:1; // .. in header, sometimes wrong
196 unsigned int size_mismatch:1; // type override differs from C
197 unsigned int size_lt:1; // type override is larger than C
198 unsigned int had_ds:1; // had ds: prefix
199 const struct parsed_proto *pp; // for OPT_LABEL
206 struct parsed_opr operand[MAX_OPERANDS];
209 unsigned char pfo_inv;
210 unsigned char operand_cnt;
211 unsigned char p_argnum; // arg push: altered before call arg #
212 unsigned char p_arggrp; // arg push: arg group # for above
213 unsigned char p_argpass;// arg push: arg of host func
214 short p_argnext;// arg push: same arg pushed elsewhere or -1
215 int regmask_src; // all referensed regs
217 int pfomask; // flagop: parsed_flag_op that can't be delayed
218 int cc_scratch; // scratch storage during analysis
219 int bt_i; // branch target for branches
220 struct parsed_data *btj;// branch targets for jumptables
221 struct parsed_proto *pp;// parsed_proto for OP_CALL
227 // on start: function/data type hint (sctproto)
229 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
230 // OP_PUSH - points to OP_POP in complex push/pop graph
231 // OP_POP - points to OP_PUSH in simple push/pop pair
232 // OP_FCOM - needed_status_word_bits | (is_z_check << 16)
236 enum opr_lenmod lmod;
243 enum opr_lenmod lmod;
257 struct label_ref *next;
261 IDAFA_BP_FRAME = (1 << 0),
262 IDAFA_LIB_FUNC = (1 << 1),
263 IDAFA_STATIC = (1 << 2),
264 IDAFA_NORETURN = (1 << 3),
265 IDAFA_THUNK = (1 << 4),
266 IDAFA_FPD = (1 << 5),
270 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
271 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
284 // note: limited to 32k due to p_argnext
286 #define MAX_ARG_GRP 2
288 static struct parsed_op ops[MAX_OPS];
289 static struct parsed_equ *g_eqs;
291 static char *g_labels[MAX_OPS];
292 static struct label_ref g_label_refs[MAX_OPS];
293 static const struct parsed_proto *g_func_pp;
294 static struct parsed_data *g_func_pd;
295 static int g_func_pd_cnt;
296 static int g_func_lmods;
297 static char g_func[256];
298 static char g_comment[256];
299 static int g_bp_frame;
300 static int g_sp_frame;
301 static int g_stack_frame_used;
302 static int g_stack_fsz;
303 static int g_ida_func_attr;
304 static int g_sct_func_attr;
305 static int g_stack_clear_start; // in dwords
306 static int g_stack_clear_len;
307 static int g_regmask_init;
308 static int g_skip_func;
309 static int g_allow_regfunc;
310 static int g_quiet_pp;
311 static int g_header_mode;
313 #define ferr(op_, fmt, ...) do { \
314 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
315 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
319 #define fnote(op_, fmt, ...) \
320 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
321 dump_op(op_), ##__VA_ARGS__)
323 #define ferr_assert(op_, cond) do { \
324 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
327 const char *regs_r32[] = {
328 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
329 // not r32, but list here for easy parsing and printing
330 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
331 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
333 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
334 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
335 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
341 xMM0, xMM1, xMM2, xMM3, // mmx
342 xMM4, xMM5, xMM6, xMM7,
343 xST0, xST1, xST2, xST3, // x87
344 xST4, xST5, xST6, xST7,
347 #define mxAX (1 << xAX)
348 #define mxCX (1 << xCX)
349 #define mxDX (1 << xDX)
350 #define mxST0 (1 << xST0)
351 #define mxST1 (1 << xST1)
352 #define mxST1_0 (mxST1 | mxST0)
353 #define mxST7_2 (0xfc << xST0)
354 #define mxSTa (0xff << xST0)
356 // possible basic comparison types (without inversion)
357 enum parsed_flag_op {
361 PFO_BE, // 6 CF=1||ZF=1
365 PFO_LE, // e ZF=1||SF!=OF
368 #define PFOB_O (1 << PFO_O)
369 #define PFOB_C (1 << PFO_C)
370 #define PFOB_Z (1 << PFO_Z)
371 #define PFOB_S (1 << PFO_S)
373 static const char *parsed_flag_op_names[] = {
374 "o", "c", "z", "be", "s", "p", "l", "le"
377 static int char_array_i(const char *array[], size_t len, const char *s)
381 for (i = 0; i < len; i++)
388 static void printf_number(char *buf, size_t buf_size,
389 unsigned long number)
391 // output in C-friendly form
392 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
395 static int check_segment_prefix(const char *s)
397 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
411 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
415 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
417 *reg_lmod = OPLM_QWORD;
421 *reg_lmod = OPLM_DWORD;
424 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
426 *reg_lmod = OPLM_WORD;
429 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
431 *reg_lmod = OPLM_BYTE;
434 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
436 *reg_lmod = OPLM_BYTE;
443 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
445 enum opr_lenmod lmod;
458 while (my_isblank(*s))
460 for (; my_issep(*s); d++, s++)
462 while (my_isblank(*s))
466 // skip '?s:' prefixes
467 if (check_segment_prefix(s))
470 s = next_idt(w, sizeof(w), s);
475 reg = parse_reg(&lmod, w);
477 *regmask |= 1 << reg;
481 if ('0' <= w[0] && w[0] <= '9') {
482 number = parse_number(w);
483 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
487 // probably some label/identifier - pass
490 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
494 strcpy(name, cvtbuf);
499 static int is_reg_in_str(const char *s)
503 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
506 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
507 if (!strncmp(s, regs_r32[i], 3))
513 static const char *parse_stack_el(const char *name, char *extra_reg,
516 const char *p, *p2, *s;
522 if (g_bp_frame || early_try)
525 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
527 if (extra_reg != NULL) {
528 strncpy(extra_reg, name, 3);
533 if (IS_START(p, "ebp+")) {
537 if (p2 != NULL && is_reg_in_str(p)) {
538 if (extra_reg != NULL) {
539 strncpy(extra_reg, p, p2 - p);
540 extra_reg[p2 - p] = 0;
545 if (!('0' <= *p && *p <= '9'))
552 if (!IS_START(name, "esp+"))
558 if (is_reg_in_str(s)) {
559 if (extra_reg != NULL) {
560 strncpy(extra_reg, s, p - s);
561 extra_reg[p - s] = 0;
566 aerr("%s IDA stackvar not set?\n", __func__);
568 if (!('0' <= *s && *s <= '9')) {
569 aerr("%s IDA stackvar offset not set?\n", __func__);
572 if (s[0] == '0' && s[1] == 'x')
575 if (len < sizeof(buf) - 1) {
576 strncpy(buf, s, len);
578 val = strtol(buf, &endp, 16);
579 if (val == 0 || *endp != 0) {
580 aerr("%s num parse fail for '%s'\n", __func__, buf);
589 if ('0' <= *p && *p <= '9')
595 static int guess_lmod_from_name(struct parsed_opr *opr)
597 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
598 opr->lmod = OPLM_DWORD;
601 if (IS_START(opr->name, "word_")) {
602 opr->lmod = OPLM_WORD;
605 if (IS_START(opr->name, "byte_")) {
606 opr->lmod = OPLM_BYTE;
609 if (IS_START(opr->name, "qword_")) {
610 opr->lmod = OPLM_QWORD;
616 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
617 const struct parsed_type *c_type)
619 static const char *dword_types[] = {
620 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
621 "WPARAM", "LPARAM", "UINT", "__int32",
622 "LONG", "HIMC", "BOOL", "size_t",
625 static const char *word_types[] = {
626 "uint16_t", "int16_t", "_WORD", "WORD",
627 "unsigned __int16", "__int16",
629 static const char *byte_types[] = {
630 "uint8_t", "int8_t", "char",
631 "unsigned __int8", "__int8", "BYTE", "_BYTE",
633 // structures.. deal the same as with _UNKNOWN for now
639 if (c_type->is_ptr) {
644 n = skip_type_mod(c_type->name);
646 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
647 if (IS(n, dword_types[i])) {
653 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
654 if (IS(n, word_types[i])) {
660 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
661 if (IS(n, byte_types[i])) {
670 static char *default_cast_to(char *buf, size_t buf_size,
671 struct parsed_opr *opr)
675 if (!opr->is_ptr || strchr(opr->name, '['))
677 if (opr->pp == NULL || opr->pp->type.name == NULL
680 snprintf(buf, buf_size, "%s", "(void *)");
684 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
688 static enum opr_type lmod_from_directive(const char *d)
692 else if (IS(d, "dw"))
694 else if (IS(d, "db"))
697 aerr("unhandled directive: '%s'\n", d);
701 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
707 *regmask |= 1 << reg;
710 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
713 static int parse_operand(struct parsed_opr *opr,
714 int *regmask, int *regmask_indirect,
715 char words[16][256], int wordc, int w, unsigned int op_flags)
717 const struct parsed_proto *pp = NULL;
718 enum opr_lenmod tmplmod;
719 unsigned long number;
727 aerr("parse_operand w %d, wordc %d\n", w, wordc);
731 for (i = w; i < wordc; i++) {
732 len = strlen(words[i]);
733 if (words[i][len - 1] == ',') {
734 words[i][len - 1] = 0;
740 wordc_in = wordc - w;
742 if ((op_flags & OPF_JMP) && wordc_in > 0
743 && !('0' <= words[w][0] && words[w][0] <= '9'))
745 const char *label = NULL;
747 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
748 && IS(words[w + 1], "ptr"))
749 label = words[w + 2];
750 else if (wordc_in == 2 && IS(words[w], "short"))
751 label = words[w + 1];
752 else if (wordc_in == 1
753 && strchr(words[w], '[') == NULL
754 && parse_reg(&tmplmod, words[w]) < 0)
758 opr->type = OPT_LABEL;
759 ret = check_segment_prefix(label);
762 aerr("fs/gs used\n");
766 strcpy(opr->name, label);
772 if (IS(words[w + 1], "ptr")) {
773 if (IS(words[w], "dword"))
774 opr->lmod = OPLM_DWORD;
775 else if (IS(words[w], "word"))
776 opr->lmod = OPLM_WORD;
777 else if (IS(words[w], "byte"))
778 opr->lmod = OPLM_BYTE;
779 else if (IS(words[w], "qword"))
780 opr->lmod = OPLM_QWORD;
782 aerr("type parsing failed\n");
784 wordc_in = wordc - w;
789 if (IS(words[w], "offset")) {
790 opr->type = OPT_OFFSET;
791 opr->lmod = OPLM_DWORD;
792 strcpy(opr->name, words[w + 1]);
793 pp = proto_parse(g_fhdr, opr->name, 1);
796 if (IS(words[w], "(offset")) {
797 p = strchr(words[w + 1], ')');
799 aerr("parse of bracketed offset failed\n");
801 opr->type = OPT_OFFSET;
802 strcpy(opr->name, words[w + 1]);
808 aerr("parse_operand 1 word expected\n");
810 ret = check_segment_prefix(words[w]);
813 aerr("fs/gs used\n");
815 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
817 strcpy(opr->name, words[w]);
819 if (words[w][0] == '[') {
820 opr->type = OPT_REGMEM;
821 ret = sscanf(words[w], "[%[^]]]", opr->name);
823 aerr("[] parse failure\n");
825 parse_indmode(opr->name, regmask_indirect, 1);
826 if (opr->lmod == OPLM_UNSPEC && parse_stack_el(opr->name, NULL, 1))
829 struct parsed_equ *eq =
830 equ_find(NULL, parse_stack_el(opr->name, NULL, 1), &i);
832 opr->lmod = eq->lmod;
834 // might be unaligned access
835 g_func_lmods |= 1 << OPLM_BYTE;
839 else if (strchr(words[w], '[')) {
841 p = strchr(words[w], '[');
842 opr->type = OPT_REGMEM;
843 parse_indmode(p, regmask_indirect, 0);
844 strncpy(buf, words[w], p - words[w]);
845 buf[p - words[w]] = 0;
846 pp = proto_parse(g_fhdr, buf, 1);
849 else if (('0' <= words[w][0] && words[w][0] <= '9')
850 || words[w][0] == '-')
852 number = parse_number(words[w]);
853 opr->type = OPT_CONST;
855 printf_number(opr->name, sizeof(opr->name), number);
859 ret = parse_reg(&tmplmod, opr->name);
861 setup_reg_opr(opr, ret, tmplmod, regmask);
865 // most likely var in data segment
866 opr->type = OPT_LABEL;
867 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
871 if (pp->is_fptr || pp->is_func) {
872 opr->lmod = OPLM_DWORD;
876 tmplmod = OPLM_UNSPEC;
877 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
878 anote("unhandled C type '%s' for '%s'\n",
879 pp->type.name, opr->name);
881 if (opr->lmod == OPLM_UNSPEC) {
883 opr->type_from_var = 1;
885 else if (opr->lmod != tmplmod) {
886 opr->size_mismatch = 1;
887 if (tmplmod < opr->lmod)
890 opr->is_ptr = pp->type.is_ptr;
892 opr->is_array = pp->type.is_array;
896 if (opr->lmod == OPLM_UNSPEC)
897 guess_lmod_from_name(opr);
901 static const struct {
906 { "repe", OPF_REP|OPF_REPZ },
907 { "repz", OPF_REP|OPF_REPZ },
908 { "repne", OPF_REP|OPF_REPNZ },
909 { "repnz", OPF_REP|OPF_REPNZ },
910 { "lock", OPF_LOCK }, // ignored for now..
913 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
915 static const struct {
918 unsigned short minopr;
919 unsigned short maxopr;
922 unsigned char pfo_inv;
924 { "nop", OP_NOP, 0, 0, 0 },
925 { "push", OP_PUSH, 1, 1, 0 },
926 { "pop", OP_POP, 1, 1, OPF_DATA },
927 { "pusha",OP_PUSHA, 0, 0, 0 },
928 { "popa", OP_POPA, 0, 0, OPF_DATA },
929 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
930 { "mov" , OP_MOV, 2, 2, OPF_DATA },
931 { "lea", OP_LEA, 2, 2, OPF_DATA },
932 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
933 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
934 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
935 { "not", OP_NOT, 1, 1, OPF_DATA },
936 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
937 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
938 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
939 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
940 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
941 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
942 { "stosb",OP_STOS, 0, 0, OPF_DATA },
943 { "stosw",OP_STOS, 0, 0, OPF_DATA },
944 { "stosd",OP_STOS, 0, 0, OPF_DATA },
945 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
946 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
947 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
948 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
949 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
950 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
951 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
952 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
953 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
954 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
955 { "cld", OP_CLD, 0, 0, OPF_DATA },
956 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
957 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
958 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
959 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
960 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
961 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
962 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
963 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
964 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
965 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
966 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
967 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
968 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
969 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
970 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
971 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
972 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
973 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
974 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
975 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
976 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
977 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
978 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
979 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
980 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
981 { "test", OP_TEST, 2, 2, OPF_FLAGS },
982 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
983 { "retn", OP_RET, 0, 1, OPF_TAIL },
984 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
985 { "jmp", OP_JMP, 1, 1, OPF_JMP },
986 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
987 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
988 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
989 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
990 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
991 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
992 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
993 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
994 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
995 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
996 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
997 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
998 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
999 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1000 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1001 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1002 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1003 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1004 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1005 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1006 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1007 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1008 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1009 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1010 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1011 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1012 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1013 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1014 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1015 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1016 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1017 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1018 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1019 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1020 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1021 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1022 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1023 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1024 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1025 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1026 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1027 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1028 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1029 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1030 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1031 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1032 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1033 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1034 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1035 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1036 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1037 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1038 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1039 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1040 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1041 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1042 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1043 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1044 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1045 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1047 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1048 { "fild", OP_FILD, 1, 1, OPF_FPUSH },
1049 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1050 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1051 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1052 { "fst", OP_FST, 1, 1, 0 },
1053 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1054 { "fist", OP_FIST, 1, 1, 0 },
1055 { "fistp", OP_FIST, 1, 1, OPF_FPOP },
1056 { "fadd", OP_FADD, 0, 2, 0 },
1057 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1058 { "fdiv", OP_FDIV, 0, 2, 0 },
1059 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1060 { "fmul", OP_FMUL, 0, 2, 0 },
1061 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1062 { "fsub", OP_FSUB, 0, 2, 0 },
1063 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1064 { "fdivr", OP_FDIVR, 0, 2, 0 },
1065 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1066 { "fsubr", OP_FSUBR, 0, 2, 0 },
1067 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1068 { "fiadd", OP_FIADD, 1, 1, 0 },
1069 { "fidiv", OP_FIDIV, 1, 1, 0 },
1070 { "fimul", OP_FIMUL, 1, 1, 0 },
1071 { "fisub", OP_FISUB, 1, 1, 0 },
1072 { "fidivr", OP_FIDIVR, 1, 1, 0 },
1073 { "fisubr", OP_FISUBR, 1, 1, 0 },
1074 { "fcom", OP_FCOM, 0, 1, 0 },
1075 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1076 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1077 { "fchs", OP_FCHS, 0, 0, 0 },
1078 { "fcos", OP_FCOS, 0, 0, 0 },
1079 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1080 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1081 { "fsin", OP_FSIN, 0, 0, 0 },
1082 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1083 { "fxch", OP_FXCH, 1, 1, 0 },
1084 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1086 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1087 { "movq", OP_MOV, 2, 2, OPF_DATA },
1088 // pseudo-ops for lib calls
1089 { "_allshl",OPP_ALLSHL },
1090 { "_allshr",OPP_ALLSHR },
1091 { "_ftol", OPP_FTOL },
1096 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1098 enum opr_lenmod lmod = OPLM_UNSPEC;
1099 int prefix_flags = 0;
1107 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1108 if (IS(words[w], pref_table[i].name)) {
1109 prefix_flags = pref_table[i].flags;
1116 aerr("lone prefix: '%s'\n", words[0]);
1121 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1122 if (IS(words[w], op_table[i].name))
1126 if (i == ARRAY_SIZE(op_table)) {
1128 aerr("unhandled op: '%s'\n", words[0]);
1133 op->op = op_table[i].op;
1134 op->flags = op_table[i].flags | prefix_flags;
1135 op->pfo = op_table[i].pfo;
1136 op->pfo_inv = op_table[i].pfo_inv;
1137 op->regmask_src = op->regmask_dst = 0;
1140 if (op->op == OP_UD2)
1143 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1144 if (opr >= op_table[i].minopr && w >= wordc)
1147 regmask = regmask_ind = 0;
1148 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1149 words, wordc, w, op->flags);
1151 if (opr == 0 && (op->flags & OPF_DATA))
1152 op->regmask_dst = regmask;
1154 op->regmask_src |= regmask;
1155 op->regmask_src |= regmask_ind;
1157 if (op->operand[opr].lmod != OPLM_UNSPEC)
1158 g_func_lmods |= 1 << op->operand[opr].lmod;
1162 aerr("parse_op %s incomplete: %d/%d\n",
1163 words[0], w, wordc);
1166 op->operand_cnt = opr;
1167 if (!strncmp(op_table[i].name, "set", 3))
1168 op->operand[0].lmod = OPLM_BYTE;
1171 // first operand is not dst
1174 op->regmask_src |= op->regmask_dst;
1175 op->regmask_dst = 0;
1178 // first operand is src too
1191 op->regmask_src |= op->regmask_dst;
1196 op->regmask_src |= op->regmask_dst;
1197 op->regmask_dst |= op->regmask_src;
1203 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1204 && op->operand[0].lmod == op->operand[1].lmod
1205 && op->operand[0].reg == op->operand[1].reg
1206 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1208 op->regmask_src = 0;
1211 op->regmask_src |= op->regmask_dst;
1214 // ops with implicit argumets
1216 op->operand_cnt = 2;
1217 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1218 op->regmask_dst = op->regmask_src;
1219 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1223 op->operand_cnt = 2;
1224 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1225 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1231 if (words[op_w][4] == 'b')
1233 else if (words[op_w][4] == 'w')
1235 else if (words[op_w][4] == 'd')
1238 op->regmask_src = 0;
1239 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1240 OPLM_DWORD, &op->regmask_src);
1241 op->regmask_dst = op->regmask_src;
1242 setup_reg_opr(&op->operand[j++], xAX, lmod,
1243 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1244 if (op->flags & OPF_REP) {
1245 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1246 op->regmask_dst |= 1 << xCX;
1248 op->operand_cnt = j;
1253 if (words[op_w][4] == 'b')
1255 else if (words[op_w][4] == 'w')
1257 else if (words[op_w][4] == 'd')
1260 op->regmask_src = 0;
1261 // note: lmod is not correct, don't have where to place it
1262 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1263 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1264 if (op->flags & OPF_REP)
1265 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1266 op->operand_cnt = j;
1267 op->regmask_dst = op->regmask_src;
1271 op->regmask_dst = 1 << xCX;
1274 op->operand_cnt = 2;
1275 op->regmask_src = 1 << xCX;
1276 op->operand[1].type = OPT_REG;
1277 op->operand[1].reg = xCX;
1278 op->operand[1].lmod = OPLM_DWORD;
1282 if (op->operand_cnt == 2) {
1283 if (op->operand[0].type != OPT_REG)
1284 aerr("reg expected\n");
1285 op->regmask_src |= 1 << op->operand[0].reg;
1287 if (op->operand_cnt != 1)
1292 op->regmask_src |= op->regmask_dst;
1293 op->regmask_dst = (1 << xDX) | (1 << xAX);
1294 if (op->operand[0].lmod == OPLM_UNSPEC)
1295 op->operand[0].lmod = OPLM_DWORD;
1300 // we could set up operands for edx:eax, but there is no real need to
1301 // (see is_opr_modified())
1302 op->regmask_src |= op->regmask_dst;
1303 op->regmask_dst = (1 << xDX) | (1 << xAX);
1304 if (op->operand[0].lmod == OPLM_UNSPEC)
1305 op->operand[0].lmod = OPLM_DWORD;
1313 op->regmask_src |= op->regmask_dst;
1314 if (op->operand[1].lmod == OPLM_UNSPEC)
1315 op->operand[1].lmod = OPLM_BYTE;
1320 op->regmask_src |= op->regmask_dst;
1321 if (op->operand[2].lmod == OPLM_UNSPEC)
1322 op->operand[2].lmod = OPLM_BYTE;
1326 op->regmask_src |= op->regmask_dst;
1327 op->regmask_dst = 0;
1328 if (op->operand[0].lmod == OPLM_UNSPEC
1329 && (op->operand[0].type == OPT_CONST
1330 || op->operand[0].type == OPT_OFFSET
1331 || op->operand[0].type == OPT_LABEL))
1332 op->operand[0].lmod = OPLM_DWORD;
1338 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1339 && op->operand[0].lmod == op->operand[1].lmod
1340 && op->operand[0].reg == op->operand[1].reg
1341 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1343 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1344 op->regmask_src = op->regmask_dst = 0;
1349 if (op->operand[0].type == OPT_REG
1350 && op->operand[1].type == OPT_REGMEM)
1353 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1354 if (IS(buf, op->operand[1].name))
1355 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1360 // trashed regs must be explicitly detected later
1361 op->regmask_dst = 0;
1365 op->regmask_dst = (1 << xBP) | (1 << xSP);
1366 op->regmask_src = 1 << xBP;
1371 op->regmask_dst |= mxST0;
1375 op->regmask_dst |= mxST0;
1376 if (IS(words[op_w] + 3, "1"))
1377 op->operand[0].val = X87_CONST_1;
1378 else if (IS(words[op_w] + 3, "ln2"))
1379 op->operand[0].val = X87_CONST_LN2;
1380 else if (IS(words[op_w] + 3, "z"))
1381 op->operand[0].val = X87_CONST_Z;
1388 op->regmask_src |= mxST0;
1397 op->regmask_src |= mxST0;
1398 if (op->operand_cnt == 2)
1399 op->regmask_src |= op->regmask_dst;
1400 else if (op->operand_cnt == 1) {
1401 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1402 op->operand[0].type = OPT_REG;
1403 op->operand[0].lmod = OPLM_QWORD;
1404 op->operand[0].reg = xST0;
1405 op->regmask_dst |= mxST0;
1408 // IDA doesn't use this
1409 aerr("no operands?\n");
1423 op->regmask_src |= mxST0;
1424 op->regmask_dst |= mxST0;
1429 op->regmask_src |= mxST0 | mxST1;
1430 op->regmask_dst |= mxST0;
1438 op->regmask_src |= mxST0;
1445 if (op->operand[0].type == OPT_REG
1446 && op->operand[1].type == OPT_CONST)
1448 struct parsed_opr *op1 = &op->operand[1];
1449 if ((op->op == OP_AND && op1->val == 0)
1452 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1453 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1455 op->regmask_src = 0;
1460 static const char *op_name(struct parsed_op *po)
1462 static char buf[16];
1466 if (po->op == OP_JCC || po->op == OP_SCC) {
1468 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1471 strcpy(p, parsed_flag_op_names[po->pfo]);
1475 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1476 if (op_table[i].op == po->op)
1477 return op_table[i].name;
1483 static const char *dump_op(struct parsed_op *po)
1485 static char out[128];
1492 snprintf(out, sizeof(out), "%s", op_name(po));
1493 for (i = 0; i < po->operand_cnt; i++) {
1497 snprintf(p, sizeof(out) - (p - out),
1498 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1499 po->operand[i].name);
1505 static const char *lmod_type_u(struct parsed_op *po,
1506 enum opr_lenmod lmod)
1518 ferr(po, "invalid lmod: %d\n", lmod);
1519 return "(_invalid_)";
1523 static const char *lmod_cast_u(struct parsed_op *po,
1524 enum opr_lenmod lmod)
1536 ferr(po, "invalid lmod: %d\n", lmod);
1537 return "(_invalid_)";
1541 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1542 enum opr_lenmod lmod)
1554 ferr(po, "invalid lmod: %d\n", lmod);
1555 return "(_invalid_)";
1559 static const char *lmod_cast_s(struct parsed_op *po,
1560 enum opr_lenmod lmod)
1572 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1573 return "(_invalid_)";
1577 static const char *lmod_cast(struct parsed_op *po,
1578 enum opr_lenmod lmod, int is_signed)
1581 lmod_cast_s(po, lmod) :
1582 lmod_cast_u(po, lmod);
1585 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1597 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1602 static const char *opr_name(struct parsed_op *po, int opr_num)
1604 if (opr_num >= po->operand_cnt)
1605 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1606 return po->operand[opr_num].name;
1609 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1611 if (opr_num >= po->operand_cnt)
1612 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1613 if (po->operand[opr_num].type != OPT_CONST)
1614 ferr(po, "opr %d: const expected\n", opr_num);
1615 return po->operand[opr_num].val;
1618 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1620 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1621 ferr(po, "invalid reg: %d\n", popr->reg);
1622 return regs_r32[popr->reg];
1625 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1627 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1629 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1631 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1633 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1638 *is_signed = cast[1] == 's' ? 1 : 0;
1642 static int check_deref_cast(const char *cast, int *bits)
1644 if (IS_START(cast, "*(u8 *)"))
1646 else if (IS_START(cast, "*(u16 *)"))
1648 else if (IS_START(cast, "*(u32 *)"))
1650 else if (IS_START(cast, "*(u64 *)"))
1658 // cast1 is the "final" cast
1659 static const char *simplify_cast(const char *cast1, const char *cast2)
1661 static char buf[256];
1669 if (IS(cast1, cast2))
1672 if (check_simple_cast(cast1, &bits1, &s1) == 0
1673 && check_simple_cast(cast2, &bits2, &s2) == 0)
1678 if (check_simple_cast(cast1, &bits1, &s1) == 0
1679 && check_deref_cast(cast2, &bits2) == 0)
1681 if (bits1 == bits2) {
1682 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1687 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1690 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1694 static const char *simplify_cast_num(const char *cast, unsigned int val)
1696 if (IS(cast, "(u8)") && val < 0x100)
1698 if (IS(cast, "(s8)") && val < 0x80)
1700 if (IS(cast, "(u16)") && val < 0x10000)
1702 if (IS(cast, "(s16)") && val < 0x8000)
1704 if (IS(cast, "(s32)") && val < 0x80000000)
1710 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1719 namelen = strlen(name);
1721 p = strchr(name, '+');
1725 ferr(po, "equ parse failed for '%s'\n", name);
1727 if (IS_START(p, "0x"))
1729 *extra_offs = strtol(p, &endp, 16);
1731 ferr(po, "equ parse failed for '%s'\n", name);
1734 for (i = 0; i < g_eqcnt; i++)
1735 if (strncmp(g_eqs[i].name, name, namelen) == 0
1736 && g_eqs[i].name[namelen] == 0)
1740 ferr(po, "unresolved equ name: '%s'\n", name);
1747 static int is_stack_access(struct parsed_op *po,
1748 const struct parsed_opr *popr)
1750 return (parse_stack_el(popr->name, NULL, 0)
1751 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1752 && IS_START(popr->name, "ebp")));
1755 static void parse_stack_access(struct parsed_op *po,
1756 const char *name, char *ofs_reg, int *offset_out,
1757 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1759 const char *bp_arg = "";
1760 const char *p = NULL;
1761 struct parsed_equ *eq;
1768 if (IS_START(name, "ebp-")
1769 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1772 if (IS_START(p, "0x"))
1774 offset = strtoul(p, &endp, 16);
1778 ferr(po, "ebp- parse of '%s' failed\n", name);
1781 bp_arg = parse_stack_el(name, ofs_reg, 0);
1782 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1783 eq = equ_find(po, bp_arg, &offset);
1785 ferr(po, "detected but missing eq\n");
1786 offset += eq->offset;
1789 if (!strncmp(name, "ebp", 3))
1792 // yes it sometimes LEAs ra for compares..
1793 if (!is_lea && ofs_reg[0] == 0
1794 && stack_ra <= offset && offset < stack_ra + 4)
1796 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1799 *offset_out = offset;
1800 *stack_ra_out = stack_ra;
1802 *bp_arg_out = bp_arg;
1805 static int stack_frame_access(struct parsed_op *po,
1806 struct parsed_opr *popr, char *buf, size_t buf_size,
1807 const char *name, const char *cast, int is_src, int is_lea)
1809 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1810 const char *prefix = "";
1811 const char *bp_arg = NULL;
1812 char ofs_reg[16] = { 0, };
1813 int i, arg_i, arg_s;
1821 if (po->flags & OPF_EBP_S)
1822 ferr(po, "stack_frame_access while ebp is scratch\n");
1824 parse_stack_access(po, name, ofs_reg, &offset,
1825 &stack_ra, &bp_arg, is_lea);
1827 if (offset > stack_ra)
1829 arg_i = (offset - stack_ra - 4) / 4;
1830 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1832 if (g_func_pp->is_vararg
1833 && arg_i == g_func_pp->argc_stack && is_lea)
1835 // should be va_list
1838 snprintf(buf, buf_size, "%sap", cast);
1841 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1842 offset, bp_arg, arg_i);
1844 if (ofs_reg[0] != 0)
1845 ferr(po, "offset reg on arg access?\n");
1847 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1848 if (g_func_pp->arg[i].reg != NULL)
1854 if (i == g_func_pp->argc)
1855 ferr(po, "arg %d not in prototype?\n", arg_i);
1857 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1864 ferr(po, "lea/byte to arg?\n");
1865 if (is_src && (offset & 3) == 0)
1866 snprintf(buf, buf_size, "%sa%d",
1867 simplify_cast(cast, "(u8)"), i + 1);
1869 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1870 cast, offset & 3, i + 1);
1875 ferr(po, "lea/word to arg?\n");
1880 ferr(po, "problematic arg store\n");
1881 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1882 simplify_cast(cast, "*(u16 *)"), i + 1);
1885 ferr(po, "unaligned arg word load\n");
1887 else if (is_src && (offset & 2) == 0)
1888 snprintf(buf, buf_size, "%sa%d",
1889 simplify_cast(cast, "(u16)"), i + 1);
1891 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1892 cast, (offset & 2) ? "HI" : "LO", i + 1);
1904 snprintf(buf, buf_size, "(u32)&a%d + %d",
1907 ferr(po, "unaligned arg store\n");
1909 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1910 snprintf(buf, buf_size, "%s(a%d >> %d)",
1911 prefix, i + 1, (offset & 3) * 8);
1915 snprintf(buf, buf_size, "%s%sa%d",
1916 prefix, is_lea ? "&" : "", i + 1);
1921 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1925 snprintf(g_comment, sizeof(g_comment), "%s unaligned", bp_arg);
1928 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
1929 if (tmp_lmod != OPLM_DWORD
1930 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
1931 < lmod_bytes(po, popr->lmod) + (offset & 3))))
1933 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
1934 i + 1, offset, g_func_pp->arg[i].type.name);
1936 // can't check this because msvc likes to reuse
1937 // arg space for scratch..
1938 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
1939 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
1943 if (g_stack_fsz == 0)
1944 ferr(po, "stack var access without stackframe\n");
1945 g_stack_frame_used = 1;
1947 sf_ofs = g_stack_fsz + offset;
1948 lim = (ofs_reg[0] != 0) ? -4 : 0;
1949 if (offset > 0 || sf_ofs < lim)
1950 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
1960 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1961 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1965 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
1966 // known unaligned or possibly unaligned
1967 strcat(g_comment, " unaligned");
1969 prefix = "*(u16 *)&";
1970 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1971 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1974 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
1978 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
1979 // known unaligned or possibly unaligned
1980 strcat(g_comment, " unaligned");
1982 prefix = "*(u32 *)&";
1983 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1984 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1987 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
1991 ferr_assert(po, !(sf_ofs & 7));
1992 ferr_assert(po, ofs_reg[0] == 0);
1993 // float callers set is_lea
1994 ferr_assert(po, is_lea);
1995 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
1999 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2006 static void check_func_pp(struct parsed_op *po,
2007 const struct parsed_proto *pp, const char *pfx)
2009 enum opr_lenmod tmp_lmod;
2013 if (pp->argc_reg != 0) {
2014 if (/*!g_allow_regfunc &&*/ !pp->is_fastcall) {
2015 pp_print(buf, sizeof(buf), pp);
2016 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2018 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2019 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2020 pfx, pp->argc_reg, pp->argc_stack);
2023 // fptrs must use 32bit args, callsite might have no information and
2024 // lack a cast to smaller types, which results in incorrectly masked
2025 // args passed (callee may assume masked args, it does on ARM)
2026 if (!pp->is_osinc) {
2027 for (i = 0; i < pp->argc; i++) {
2028 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2029 if (ret && tmp_lmod != OPLM_DWORD)
2030 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2031 i + 1, pp->arg[i].type.name);
2036 static const char *check_label_read_ref(struct parsed_op *po,
2039 const struct parsed_proto *pp;
2041 pp = proto_parse(g_fhdr, name, 0);
2043 ferr(po, "proto_parse failed for ref '%s'\n", name);
2046 check_func_pp(po, pp, "ref");
2051 static char *out_src_opr(char *buf, size_t buf_size,
2052 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2055 char tmp1[256], tmp2[256];
2064 switch (popr->type) {
2067 ferr(po, "lea from reg?\n");
2069 switch (popr->lmod) {
2071 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2074 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2077 snprintf(buf, buf_size, "%s%s",
2078 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2081 if (popr->name[1] == 'h') // XXX..
2082 snprintf(buf, buf_size, "%s(%s >> 8)",
2083 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2085 snprintf(buf, buf_size, "%s%s",
2086 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2089 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2094 if (is_stack_access(po, popr)) {
2095 stack_frame_access(po, popr, buf, buf_size,
2096 popr->name, cast, 1, is_lea);
2100 strcpy(expr, popr->name);
2101 if (strchr(expr, '[')) {
2102 // special case: '[' can only be left for label[reg] form
2103 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2105 ferr(po, "parse failure for '%s'\n", expr);
2106 if (tmp1[0] == '(') {
2107 // (off_4FFF50+3)[eax]
2108 p = strchr(tmp1 + 1, ')');
2109 if (p == NULL || p[1] != 0)
2110 ferr(po, "parse failure (2) for '%s'\n", expr);
2112 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2114 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2117 // XXX: do we need more parsing?
2119 snprintf(buf, buf_size, "%s", expr);
2123 snprintf(buf, buf_size, "%s(%s)",
2124 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2128 name = check_label_read_ref(po, popr->name);
2129 if (cast[0] == 0 && popr->is_ptr)
2133 snprintf(buf, buf_size, "(u32)&%s", name);
2134 else if (popr->size_lt)
2135 snprintf(buf, buf_size, "%s%s%s%s", cast,
2136 lmod_cast_u_ptr(po, popr->lmod),
2137 popr->is_array ? "" : "&", name);
2139 snprintf(buf, buf_size, "%s%s%s", cast, name,
2140 popr->is_array ? "[0]" : "");
2144 name = check_label_read_ref(po, popr->name);
2148 ferr(po, "lea an offset?\n");
2149 snprintf(buf, buf_size, "%s&%s", cast, name);
2154 ferr(po, "lea from const?\n");
2156 printf_number(tmp1, sizeof(tmp1), popr->val);
2157 if (popr->val == 0 && strchr(cast, '*'))
2158 snprintf(buf, buf_size, "NULL");
2160 snprintf(buf, buf_size, "%s%s",
2161 simplify_cast_num(cast, popr->val), tmp1);
2165 ferr(po, "invalid src type: %d\n", popr->type);
2171 // note: may set is_ptr (we find that out late for ebp frame..)
2172 static char *out_dst_opr(char *buf, size_t buf_size,
2173 struct parsed_op *po, struct parsed_opr *popr)
2175 switch (popr->type) {
2177 switch (popr->lmod) {
2179 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2182 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2186 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2190 if (popr->name[1] == 'h') // XXX..
2191 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2193 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2196 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2201 if (is_stack_access(po, popr)) {
2202 stack_frame_access(po, popr, buf, buf_size,
2203 popr->name, "", 0, 0);
2207 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2210 if (popr->size_mismatch)
2211 snprintf(buf, buf_size, "%s%s%s",
2212 lmod_cast_u_ptr(po, popr->lmod),
2213 popr->is_array ? "" : "&", popr->name);
2215 snprintf(buf, buf_size, "%s%s", popr->name,
2216 popr->is_array ? "[0]" : "");
2220 ferr(po, "invalid dst type: %d\n", popr->type);
2226 static char *out_src_opr_u32(char *buf, size_t buf_size,
2227 struct parsed_op *po, struct parsed_opr *popr)
2229 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2232 static char *out_src_opr_float(char *buf, size_t buf_size,
2233 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2235 const char *cast = NULL;
2238 switch (popr->type) {
2240 if (popr->reg < xST0 || popr->reg > xST7)
2241 ferr(po, "bad reg: %d\n", popr->reg);
2243 if (need_float_stack) {
2244 if (popr->reg == xST0)
2245 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2247 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2251 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2257 switch (popr->lmod) {
2265 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2268 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2269 snprintf(buf, buf_size, "*((%s *)%s)", cast, tmp);
2273 ferr(po, "invalid float type: %d\n", popr->type);
2279 static char *out_dst_opr_float(char *buf, size_t buf_size,
2280 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2283 return out_src_opr_float(buf, buf_size, po, popr, need_float_stack);
2286 static void out_test_for_cc(char *buf, size_t buf_size,
2287 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2288 enum opr_lenmod lmod, const char *expr)
2290 const char *cast, *scast;
2292 cast = lmod_cast_u(po, lmod);
2293 scast = lmod_cast_s(po, lmod);
2297 case PFO_BE: // CF=1||ZF=1; CF=0
2298 snprintf(buf, buf_size, "(%s%s %s 0)",
2299 cast, expr, is_inv ? "!=" : "==");
2303 case PFO_L: // SF!=OF; OF=0
2304 snprintf(buf, buf_size, "(%s%s %s 0)",
2305 scast, expr, is_inv ? ">=" : "<");
2308 case PFO_LE: // ZF=1||SF!=OF; OF=0
2309 snprintf(buf, buf_size, "(%s%s %s 0)",
2310 scast, expr, is_inv ? ">" : "<=");
2314 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2318 static void out_cmp_for_cc(char *buf, size_t buf_size,
2319 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2322 const char *cast, *scast, *cast_use;
2323 char buf1[256], buf2[256];
2324 enum opr_lenmod lmod;
2326 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2327 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2328 po->operand[0].lmod, po->operand[1].lmod);
2329 lmod = po->operand[0].lmod;
2331 cast = lmod_cast_u(po, lmod);
2332 scast = lmod_cast_s(po, lmod);
2348 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2351 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2352 if (po->op == OP_DEC)
2353 snprintf(buf2, sizeof(buf2), "1");
2356 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2358 strcat(cast_op2, "-");
2359 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2364 // note: must be unsigned compare
2365 snprintf(buf, buf_size, "(%s %s %s)",
2366 buf1, is_inv ? ">=" : "<", buf2);
2370 snprintf(buf, buf_size, "(%s %s %s)",
2371 buf1, is_inv ? "!=" : "==", buf2);
2375 // note: must be unsigned compare
2376 snprintf(buf, buf_size, "(%s %s %s)",
2377 buf1, is_inv ? ">" : "<=", buf2);
2380 if (is_inv && lmod == OPLM_BYTE
2381 && po->operand[1].type == OPT_CONST
2382 && po->operand[1].val == 0xff)
2384 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2385 snprintf(buf, buf_size, "(0)");
2389 // note: must be signed compare
2391 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2392 scast, buf1, buf2, is_inv ? ">=" : "<");
2396 snprintf(buf, buf_size, "(%s %s %s)",
2397 buf1, is_inv ? ">=" : "<", buf2);
2401 snprintf(buf, buf_size, "(%s %s %s)",
2402 buf1, is_inv ? ">" : "<=", buf2);
2410 static void out_cmp_test(char *buf, size_t buf_size,
2411 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2413 char buf1[256], buf2[256], buf3[256];
2415 if (po->op == OP_TEST) {
2416 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2417 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2420 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2421 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2422 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2424 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2425 po->operand[0].lmod, buf3);
2427 else if (po->op == OP_CMP) {
2428 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2431 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2434 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2435 struct parsed_opr *popr2)
2437 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2438 ferr(po, "missing lmod for both operands\n");
2440 if (popr1->lmod == OPLM_UNSPEC)
2441 popr1->lmod = popr2->lmod;
2442 else if (popr2->lmod == OPLM_UNSPEC)
2443 popr2->lmod = popr1->lmod;
2444 else if (popr1->lmod != popr2->lmod) {
2445 if (popr1->type_from_var) {
2446 popr1->size_mismatch = 1;
2447 if (popr1->lmod < popr2->lmod)
2449 popr1->lmod = popr2->lmod;
2451 else if (popr2->type_from_var) {
2452 popr2->size_mismatch = 1;
2453 if (popr2->lmod < popr1->lmod)
2455 popr2->lmod = popr1->lmod;
2458 ferr(po, "conflicting lmods: %d vs %d\n",
2459 popr1->lmod, popr2->lmod);
2463 static const char *op_to_c(struct parsed_op *po)
2487 ferr(po, "op_to_c was supplied with %d\n", po->op);
2491 // last op in stream - unconditional branch or ret
2492 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2493 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2494 && ops[_i].op != OP_CALL))
2496 #define check_i(po, i) \
2498 ferr(po, "bad " #i ": %d\n", i)
2500 // note: this skips over calls and rm'd stuff assuming they're handled
2501 // so it's intended to use at one of final passes
2502 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2503 int depth, int flags_set)
2505 struct parsed_op *po;
2510 for (; i < opcnt; i++) {
2512 if (po->cc_scratch == magic)
2513 return ret; // already checked
2514 po->cc_scratch = magic;
2516 if (po->flags & OPF_TAIL) {
2517 if (po->op == OP_CALL) {
2518 if (po->pp != NULL && po->pp->is_noreturn)
2519 // assume no stack cleanup for noreturn
2522 return -1; // deadend
2525 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2528 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2529 if (po->btj != NULL) {
2531 for (j = 0; j < po->btj->count; j++) {
2532 check_i(po, po->btj->d[j].bt_i);
2533 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2536 return ret; // dead end
2541 check_i(po, po->bt_i);
2542 if (po->flags & OPF_CJMP) {
2543 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2546 return ret; // dead end
2555 if ((po->op == OP_POP || po->op == OP_PUSH)
2556 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2561 if (po->op == OP_PUSH) {
2564 else if (po->op == OP_POP) {
2565 if (relevant && depth == 0) {
2566 po->flags |= flags_set;
2576 // scan for 'reg' pop backwards starting from i
2577 // intended to use for register restore search, so other reg
2578 // references are considered an error
2579 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2581 struct parsed_op *po;
2582 struct label_ref *lr;
2585 ops[i].cc_scratch = magic;
2589 if (g_labels[i] != NULL) {
2590 lr = &g_label_refs[i];
2591 for (; lr != NULL; lr = lr->next) {
2592 check_i(&ops[i], lr->i);
2593 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2597 if (i > 0 && LAST_OP(i - 1))
2605 if (ops[i].cc_scratch == magic)
2607 ops[i].cc_scratch = magic;
2610 if (po->op == OP_POP && po->operand[0].reg == reg) {
2611 if (po->flags & (OPF_RMD|OPF_DONE))
2614 po->flags |= set_flags;
2618 // this also covers the case where we reach corresponding push
2619 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2623 // nothing interesting on this path
2627 static void find_reachable_exits(int i, int opcnt, int magic,
2628 int *exits, int *exit_count)
2630 struct parsed_op *po;
2633 for (; i < opcnt; i++)
2636 if (po->cc_scratch == magic)
2638 po->cc_scratch = magic;
2640 if (po->flags & OPF_TAIL) {
2641 ferr_assert(po, *exit_count < MAX_EXITS);
2642 exits[*exit_count] = i;
2647 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2648 if (po->flags & OPF_RMD)
2651 if (po->btj != NULL) {
2652 for (j = 0; j < po->btj->count; j++) {
2653 check_i(po, po->btj->d[j].bt_i);
2654 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2660 check_i(po, po->bt_i);
2661 if (po->flags & OPF_CJMP)
2662 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2670 // scan for 'reg' pop backwards starting from exits (all paths)
2671 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2673 static int exits[MAX_EXITS];
2674 static int exit_count;
2679 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2681 ferr_assert(&ops[i], exit_count > 0);
2684 for (j = 0; j < exit_count; j++) {
2685 ret = scan_for_rsave_pop_reg(exits[j], i + opcnt * 16 + set_flags,
2694 // scan for one or more pop of push <const>
2695 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2696 int push_i, int is_probe)
2698 struct parsed_op *po;
2699 struct label_ref *lr;
2703 for (; i < opcnt; i++)
2706 if (po->cc_scratch == magic)
2707 return ret; // already checked
2708 po->cc_scratch = magic;
2710 if (po->flags & OPF_JMP) {
2711 if (po->flags & OPF_RMD)
2713 if (po->op == OP_CALL)
2716 if (po->btj != NULL) {
2717 for (j = 0; j < po->btj->count; j++) {
2718 check_i(po, po->btj->d[j].bt_i);
2719 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2727 check_i(po, po->bt_i);
2728 if (po->flags & OPF_CJMP) {
2729 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2740 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2743 if (g_labels[i] != NULL) {
2744 // all refs must be visited
2745 lr = &g_label_refs[i];
2746 for (; lr != NULL; lr = lr->next) {
2748 if (ops[lr->i].cc_scratch != magic)
2751 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2755 if (po->op == OP_POP)
2757 if (po->flags & (OPF_RMD|OPF_DONE))
2761 po->flags |= OPF_DONE;
2762 po->datap = &ops[push_i];
2771 static void scan_for_pop_const(int i, int opcnt, int magic)
2775 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2777 ops[i].flags |= OPF_RMD | OPF_DONE;
2778 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2782 // check if all branch targets within a marked path are also marked
2783 // note: the path checked must not be empty or end with a branch
2784 static int check_path_branches(int opcnt, int magic)
2786 struct parsed_op *po;
2789 for (i = 0; i < opcnt; i++) {
2791 if (po->cc_scratch != magic)
2794 if (po->flags & OPF_JMP) {
2795 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2798 if (po->btj != NULL) {
2799 for (j = 0; j < po->btj->count; j++) {
2800 check_i(po, po->btj->d[j].bt_i);
2801 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2806 check_i(po, po->bt_i);
2807 if (ops[po->bt_i].cc_scratch != magic)
2809 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2817 // scan for multiple pushes for given pop
2818 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2821 int reg = ops[pop_i].operand[0].reg;
2822 struct parsed_op *po;
2823 struct label_ref *lr;
2826 ops[i].cc_scratch = magic;
2830 if (g_labels[i] != NULL) {
2831 lr = &g_label_refs[i];
2832 for (; lr != NULL; lr = lr->next) {
2833 check_i(&ops[i], lr->i);
2834 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2838 if (i > 0 && LAST_OP(i - 1))
2846 if (ops[i].cc_scratch == magic)
2848 ops[i].cc_scratch = magic;
2851 if (po->op == OP_CALL)
2853 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2856 if (po->op == OP_PUSH)
2858 if (po->datap != NULL)
2860 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2861 // leave this case for reg save/restore handlers
2865 po->flags |= OPF_PPUSH | OPF_DONE;
2866 po->datap = &ops[pop_i];
2875 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2877 int magic = i + opcnt * 14;
2880 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2882 ret = check_path_branches(opcnt, magic);
2884 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2885 *regmask_pp |= 1 << ops[i].operand[0].reg;
2886 scan_pushes_for_pop_r(i, magic + 1, i, 0);
2891 static void scan_propagate_df(int i, int opcnt)
2893 struct parsed_op *po = &ops[i];
2896 for (; i < opcnt; i++) {
2898 if (po->flags & OPF_DF)
2899 return; // already resolved
2900 po->flags |= OPF_DF;
2902 if (po->op == OP_CALL)
2903 ferr(po, "call with DF set?\n");
2905 if (po->flags & OPF_JMP) {
2906 if (po->btj != NULL) {
2908 for (j = 0; j < po->btj->count; j++) {
2909 check_i(po, po->btj->d[j].bt_i);
2910 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
2915 if (po->flags & OPF_RMD)
2917 check_i(po, po->bt_i);
2918 if (po->flags & OPF_CJMP)
2919 scan_propagate_df(po->bt_i, opcnt);
2925 if (po->flags & OPF_TAIL)
2928 if (po->op == OP_CLD) {
2929 po->flags |= OPF_RMD | OPF_DONE;
2934 ferr(po, "missing DF clear?\n");
2937 // is operand 'opr' referenced by parsed_op 'po'?
2938 static int is_opr_referenced(const struct parsed_opr *opr,
2939 const struct parsed_op *po)
2943 if (opr->type == OPT_REG) {
2944 mask = po->regmask_dst | po->regmask_src;
2945 if (po->op == OP_CALL)
2946 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
2947 if ((1 << opr->reg) & mask)
2953 for (i = 0; i < po->operand_cnt; i++)
2954 if (IS(po->operand[0].name, opr->name))
2960 // is operand 'opr' read by parsed_op 'po'?
2961 static int is_opr_read(const struct parsed_opr *opr,
2962 const struct parsed_op *po)
2964 if (opr->type == OPT_REG) {
2965 if (po->regmask_src & (1 << opr->reg))
2975 // is operand 'opr' modified by parsed_op 'po'?
2976 static int is_opr_modified(const struct parsed_opr *opr,
2977 const struct parsed_op *po)
2981 if (opr->type == OPT_REG) {
2982 if (po->op == OP_CALL) {
2983 mask = po->regmask_dst;
2984 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
2985 if (mask & (1 << opr->reg))
2991 if (po->regmask_dst & (1 << opr->reg))
2997 return IS(po->operand[0].name, opr->name);
3000 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3001 static int is_any_opr_modified(const struct parsed_op *po_test,
3002 const struct parsed_op *po, int c_mode)
3007 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3010 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3013 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3016 // in reality, it can wreck any register, but in decompiled C
3017 // version it can only overwrite eax or edx:eax
3018 mask = (1 << xAX) | (1 << xDX);
3022 if (po->op == OP_CALL
3023 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3026 for (i = 0; i < po_test->operand_cnt; i++)
3027 if (IS(po_test->operand[i].name, po->operand[0].name))
3033 // scan for any po_test operand modification in range given
3034 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3037 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3040 for (; i < opcnt; i++) {
3041 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3048 // scan for po_test operand[0] modification in range given
3049 static int scan_for_mod_opr0(struct parsed_op *po_test,
3052 for (; i < opcnt; i++) {
3053 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3060 static int scan_for_flag_set(int i, int magic, int *branched,
3061 int *setters, int *setter_cnt)
3063 struct label_ref *lr;
3067 if (ops[i].cc_scratch == magic) {
3068 // is this a problem?
3069 //ferr(&ops[i], "%s looped\n", __func__);
3072 ops[i].cc_scratch = magic;
3074 if (g_labels[i] != NULL) {
3077 lr = &g_label_refs[i];
3078 for (; lr->next; lr = lr->next) {
3079 check_i(&ops[i], lr->i);
3080 ret = scan_for_flag_set(lr->i, magic,
3081 branched, setters, setter_cnt);
3086 check_i(&ops[i], lr->i);
3087 if (i > 0 && LAST_OP(i - 1)) {
3091 ret = scan_for_flag_set(lr->i, magic,
3092 branched, setters, setter_cnt);
3098 if (ops[i].flags & OPF_FLAGS) {
3099 setters[*setter_cnt] = i;
3104 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3111 // scan back for cdq, if anything modifies edx, fail
3112 static int scan_for_cdq_edx(int i)
3115 if (g_labels[i] != NULL) {
3116 if (g_label_refs[i].next != NULL)
3118 if (i > 0 && LAST_OP(i - 1)) {
3119 i = g_label_refs[i].i;
3126 if (ops[i].op == OP_CDQ)
3129 if (ops[i].regmask_dst & (1 << xDX))
3136 static int scan_for_reg_clear(int i, int reg)
3139 if (g_labels[i] != NULL) {
3140 if (g_label_refs[i].next != NULL)
3142 if (i > 0 && LAST_OP(i - 1)) {
3143 i = g_label_refs[i].i;
3150 if (ops[i].op == OP_XOR
3151 && ops[i].operand[0].lmod == OPLM_DWORD
3152 && ops[i].operand[0].reg == ops[i].operand[1].reg
3153 && ops[i].operand[0].reg == reg)
3156 if (ops[i].regmask_dst & (1 << reg))
3163 static void patch_esp_adjust(struct parsed_op *po, int adj)
3165 ferr_assert(po, po->op == OP_ADD);
3166 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3167 ferr_assert(po, po->operand[1].type == OPT_CONST);
3169 // this is a bit of a hack, but deals with use of
3170 // single adj for multiple calls
3171 po->operand[1].val -= adj;
3172 po->flags |= OPF_RMD;
3173 if (po->operand[1].val == 0)
3174 po->flags |= OPF_DONE;
3175 ferr_assert(po, (int)po->operand[1].val >= 0);
3178 // scan for positive, constant esp adjust
3179 // multipath case is preliminary
3180 static int scan_for_esp_adjust(int i, int opcnt,
3181 int adj_expect, int *adj, int *is_multipath, int do_update)
3183 int adj_expect_unknown = 0;
3184 struct parsed_op *po;
3188 *adj = *is_multipath = 0;
3189 if (adj_expect < 0) {
3190 adj_expect_unknown = 1;
3191 adj_expect = 32 * 4; // enough?
3194 for (; i < opcnt && *adj < adj_expect; i++) {
3195 if (g_labels[i] != NULL)
3199 if (po->flags & OPF_DONE)
3202 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3203 if (po->operand[1].type != OPT_CONST)
3204 ferr(&ops[i], "non-const esp adjust?\n");
3205 *adj += po->operand[1].val;
3207 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3210 patch_esp_adjust(po, adj_expect);
3212 po->flags |= OPF_RMD;
3216 else if (po->op == OP_PUSH) {
3217 //if (first_pop == -1)
3218 // first_pop = -2; // none
3219 *adj -= lmod_bytes(po, po->operand[0].lmod);
3221 else if (po->op == OP_POP) {
3222 if (!(po->flags & OPF_DONE)) {
3223 // seems like msvc only uses 'pop ecx' for stack realignment..
3224 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3226 if (first_pop == -1 && *adj >= 0)
3229 if (do_update && *adj >= 0) {
3230 po->flags |= OPF_RMD;
3232 po->flags |= OPF_DONE | OPF_NOREGS;
3235 *adj += lmod_bytes(po, po->operand[0].lmod);
3236 if (*adj > adj_best)
3239 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3240 if (po->op == OP_JMP && po->btj == NULL) {
3246 if (po->op != OP_CALL)
3248 if (po->operand[0].type != OPT_LABEL)
3250 if (po->pp != NULL && po->pp->is_stdcall)
3252 if (adj_expect_unknown && first_pop >= 0)
3254 // assume it's another cdecl call
3258 if (first_pop >= 0) {
3259 // probably only 'pop ecx' was used
3267 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3269 struct parsed_op *po;
3273 ferr(ops, "%s: followed bad branch?\n", __func__);
3275 for (; i < opcnt; i++) {
3277 if (po->cc_scratch == magic)
3279 po->cc_scratch = magic;
3282 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3283 if (po->btj != NULL) {
3285 for (j = 0; j < po->btj->count; j++)
3286 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3290 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3291 if (!(po->flags & OPF_CJMP))
3294 if (po->flags & OPF_TAIL)
3299 static const struct parsed_proto *try_recover_pp(
3300 struct parsed_op *po, const struct parsed_opr *opr, int *search_instead)
3302 const struct parsed_proto *pp = NULL;
3306 // maybe an arg of g_func?
3307 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3309 char ofs_reg[16] = { 0, };
3310 int arg, arg_s, arg_i;
3317 parse_stack_access(po, opr->name, ofs_reg,
3318 &offset, &stack_ra, NULL, 0);
3319 if (ofs_reg[0] != 0)
3320 ferr(po, "offset reg on arg access?\n");
3321 if (offset <= stack_ra) {
3322 // search who set the stack var instead
3323 if (search_instead != NULL)
3324 *search_instead = 1;
3328 arg_i = (offset - stack_ra - 4) / 4;
3329 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3330 if (g_func_pp->arg[arg].reg != NULL)
3336 if (arg == g_func_pp->argc)
3337 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3339 pp = g_func_pp->arg[arg].fptr;
3341 ferr(po, "icall sa: arg%d is not a fptr?\n", arg + 1);
3342 check_func_pp(po, pp, "icall arg");
3344 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3346 p = strchr(opr->name + 1, '[');
3347 memcpy(buf, opr->name, p - opr->name);
3348 buf[p - opr->name] = 0;
3349 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3351 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3352 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3355 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3358 check_func_pp(po, pp, "reg-fptr ref");
3364 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3365 int magic, const struct parsed_proto **pp_found, int *pp_i,
3368 const struct parsed_proto *pp = NULL;
3369 struct parsed_op *po;
3370 struct label_ref *lr;
3372 ops[i].cc_scratch = magic;
3375 if (g_labels[i] != NULL) {
3376 lr = &g_label_refs[i];
3377 for (; lr != NULL; lr = lr->next) {
3378 check_i(&ops[i], lr->i);
3379 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3381 if (i > 0 && LAST_OP(i - 1))
3389 if (ops[i].cc_scratch == magic)
3391 ops[i].cc_scratch = magic;
3393 if (!(ops[i].flags & OPF_DATA))
3395 if (!is_opr_modified(opr, &ops[i]))
3397 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3398 // most probably trashed by some processing
3403 opr = &ops[i].operand[1];
3404 if (opr->type != OPT_REG)
3408 po = (i >= 0) ? &ops[i] : ops;
3411 // reached the top - can only be an arg-reg
3412 if (opr->type != OPT_REG || g_func_pp == NULL)
3415 for (i = 0; i < g_func_pp->argc; i++) {
3416 if (g_func_pp->arg[i].reg == NULL)
3418 if (IS(opr->name, g_func_pp->arg[i].reg))
3421 if (i == g_func_pp->argc)
3423 pp = g_func_pp->arg[i].fptr;
3425 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3426 i + 1, g_func_pp->arg[i].reg);
3427 check_func_pp(po, pp, "icall reg-arg");
3430 pp = try_recover_pp(po, opr, NULL);
3432 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3433 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3434 || (*pp_found)->is_stdcall != pp->is_stdcall
3435 || (*pp_found)->is_fptr != pp->is_fptr
3436 || (*pp_found)->argc != pp->argc
3437 || (*pp_found)->argc_reg != pp->argc_reg
3438 || (*pp_found)->argc_stack != pp->argc_stack)
3440 ferr(po, "icall: parsed_proto mismatch\n");
3450 static void add_label_ref(struct label_ref *lr, int op_i)
3452 struct label_ref *lr_new;
3459 lr_new = calloc(1, sizeof(*lr_new));
3461 lr_new->next = lr->next;
3465 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3467 struct parsed_op *po = &ops[i];
3468 struct parsed_data *pd;
3469 char label[NAMELEN], *p;
3472 p = strchr(po->operand[0].name, '[');
3476 len = p - po->operand[0].name;
3477 strncpy(label, po->operand[0].name, len);
3480 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3481 if (IS(g_func_pd[j].label, label)) {
3487 //ferr(po, "label '%s' not parsed?\n", label);
3490 if (pd->type != OPT_OFFSET)
3491 ferr(po, "label '%s' with non-offset data?\n", label);
3493 // find all labels, link
3494 for (j = 0; j < pd->count; j++) {
3495 for (l = 0; l < opcnt; l++) {
3496 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3497 add_label_ref(&g_label_refs[l], i);
3507 static void clear_labels(int count)
3511 for (i = 0; i < count; i++) {
3512 if (g_labels[i] != NULL) {
3519 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3524 for (i = 0; i < pp->argc; i++) {
3525 if (pp->arg[i].reg != NULL) {
3526 reg = char_array_i(regs_r32,
3527 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3529 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3530 pp->arg[i].reg, pp->name);
3531 regmask |= 1 << reg;
3538 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3543 if (pp->has_retreg) {
3544 for (i = 0; i < pp->argc; i++) {
3545 if (pp->arg[i].type.is_retreg) {
3546 reg = char_array_i(regs_r32,
3547 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3548 ferr_assert(ops, reg >= 0);
3549 regmask |= 1 << reg;
3554 if (strstr(pp->ret_type.name, "int64"))
3555 return regmask | (1 << xAX) | (1 << xDX);
3556 if (IS(pp->ret_type.name, "float")
3557 || IS(pp->ret_type.name, "double"))
3559 return regmask | mxST0;
3561 if (strcasecmp(pp->ret_type.name, "void") == 0)
3564 return regmask | mxAX;
3567 static void resolve_branches_parse_calls(int opcnt)
3569 static const struct {
3573 unsigned int regmask_src;
3574 unsigned int regmask_dst;
3576 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3577 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3578 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3580 const struct parsed_proto *pp_c;
3581 struct parsed_proto *pp;
3582 struct parsed_data *pd;
3583 struct parsed_op *po;
3584 const char *tmpname;
3588 for (i = 0; i < opcnt; i++)
3594 if (po->datap != NULL) {
3595 pp = calloc(1, sizeof(*pp));
3596 my_assert_not(pp, NULL);
3598 ret = parse_protostr(po->datap, pp);
3600 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3606 if (po->op == OP_CALL) {
3611 else if (po->operand[0].type == OPT_LABEL)
3613 tmpname = opr_name(po, 0);
3614 if (IS_START(tmpname, "loc_"))
3615 ferr(po, "call to loc_*\n");
3616 if (IS(tmpname, "__alloca_probe"))
3619 // convert some calls to pseudo-ops
3620 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3621 if (!IS(tmpname, pseudo_ops[l].name))
3624 po->op = pseudo_ops[l].op;
3625 po->operand_cnt = 0;
3626 po->regmask_src = pseudo_ops[l].regmask_src;
3627 po->regmask_dst = pseudo_ops[l].regmask_dst;
3628 po->flags = pseudo_ops[l].flags;
3629 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3632 if (l < ARRAY_SIZE(pseudo_ops))
3635 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3636 if (!g_header_mode && pp_c == NULL)
3637 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3640 pp = proto_clone(pp_c);
3641 my_assert_not(pp, NULL);
3647 check_func_pp(po, pp, "fptr var call");
3648 if (pp->is_noreturn)
3649 po->flags |= OPF_TAIL;
3655 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3658 if (po->operand[0].type == OPT_REGMEM) {
3659 pd = try_resolve_jumptab(i, opcnt);
3667 for (l = 0; l < opcnt; l++) {
3668 if (g_labels[l] != NULL
3669 && IS(po->operand[0].name, g_labels[l]))
3671 if (l == i + 1 && po->op == OP_JMP) {
3672 // yet another alignment type..
3673 po->flags |= OPF_RMD|OPF_DONE;
3676 add_label_ref(&g_label_refs[l], i);
3682 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3685 if (po->operand[0].type == OPT_LABEL)
3689 ferr(po, "unhandled branch\n");
3693 po->flags |= OPF_TAIL;
3694 if (i > 0 && ops[i - 1].op == OP_POP)
3695 po->flags |= OPF_ATAIL;
3700 static void scan_prologue_epilogue(int opcnt)
3702 int ecx_push = 0, esp_sub = 0, pusha = 0;
3703 int sandard_epilogue;
3707 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3708 && ops[1].op == OP_MOV
3709 && IS(opr_name(&ops[1], 0), "ebp")
3710 && IS(opr_name(&ops[1], 1), "esp"))
3713 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3714 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3717 if (ops[i].op == OP_PUSHA) {
3718 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3723 if (ops[i].op == OP_SUB && IS(opr_name(&ops[i], 0), "esp")) {
3724 g_stack_fsz = opr_const(&ops[i], 1);
3725 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3729 // another way msvc builds stack frame..
3730 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3732 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3736 // and another way..
3737 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3738 && ops[i].operand[1].type == OPT_CONST
3739 && ops[i + 1].op == OP_CALL
3740 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3742 g_stack_fsz += ops[i].operand[1].val;
3743 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3745 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3752 for (; i < opcnt; i++)
3753 if (ops[i].flags & OPF_TAIL)
3756 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3757 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3763 sandard_epilogue = 0;
3764 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3766 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3767 // the standard epilogue is sometimes even used without a sf
3768 if (ops[j - 1].op == OP_MOV
3769 && IS(opr_name(&ops[j - 1], 0), "esp")
3770 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3771 sandard_epilogue = 1;
3773 else if (ops[j].op == OP_LEAVE)
3775 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3776 sandard_epilogue = 1;
3778 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3779 && ops[i].pp->is_noreturn)
3781 // on noreturn, msvc sometimes cleans stack, sometimes not
3786 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3787 ferr(&ops[j], "'pop ebp' expected\n");
3789 if (g_stack_fsz != 0 || sandard_epilogue) {
3790 if (ops[j].op == OP_LEAVE)
3792 else if (sandard_epilogue) // mov esp, ebp
3794 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3797 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3799 ferr(&ops[j], "esp restore expected\n");
3802 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3803 && IS(opr_name(&ops[j], 0), "ecx"))
3805 ferr(&ops[j], "unexpected ecx pop\n");
3810 if (ops[j].op == OP_POPA)
3811 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3813 ferr(&ops[j], "popa expected\n");
3818 } while (i < opcnt);
3821 ferr(ops, "missing ebp epilogue\n");
3827 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3828 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3834 for (; i < opcnt; i++) {
3835 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3837 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3838 && ops[i].operand[1].type == OPT_CONST)
3840 g_stack_fsz = ops[i].operand[1].val;
3841 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3846 else if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3847 && ops[i].operand[1].type == OPT_CONST
3848 && ops[i + 1].op == OP_CALL
3849 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3851 g_stack_fsz += ops[i].operand[1].val;
3852 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3854 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3861 if (ecx_push && !esp_sub) {
3862 // could actually be args for a call..
3863 for (; i < opcnt; i++)
3864 if (ops[i].op != OP_PUSH)
3867 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3868 const struct parsed_proto *pp;
3869 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3870 j = pp ? pp->argc_stack : 0;
3871 while (i > 0 && j > 0) {
3873 if (ops[i].op == OP_PUSH) {
3874 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
3879 ferr(&ops[i], "unhandled prologue\n");
3882 i = g_stack_fsz = ecx_push = 0;
3883 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3884 if (!(ops[i].flags & OPF_RMD))
3894 if (ecx_push || esp_sub)
3899 for (; i < opcnt; i++)
3900 if (ops[i].flags & OPF_TAIL)
3904 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3905 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3912 for (l = 0; l < ecx_push; l++) {
3913 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
3915 else if (ops[j].op == OP_ADD
3916 && IS(opr_name(&ops[j], 0), "esp")
3917 && ops[j].operand[1].type == OPT_CONST)
3920 l += ops[j].operand[1].val / 4 - 1;
3923 ferr(&ops[j], "'pop ecx' expected\n");
3925 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3929 ferr(&ops[j], "epilogue scan failed\n");
3935 if (ops[j].op != OP_ADD
3936 || !IS(opr_name(&ops[j], 0), "esp")
3937 || ops[j].operand[1].type != OPT_CONST
3938 || ops[j].operand[1].val != g_stack_fsz)
3940 if (ops[i].op == OP_CALL && ops[i].pp != NULL
3941 && ops[i].pp->is_noreturn)
3943 // noreturn tailcall with no epilogue
3947 ferr(&ops[j], "'add esp' expected\n");
3950 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3951 ops[j].operand[1].val = 0; // hack for stack arg scanner
3956 } while (i < opcnt);
3959 ferr(ops, "missing esp epilogue\n");
3963 // find an instruction that changed opr before i op
3964 // *op_i must be set to -1 by the caller
3965 // *is_caller is set to 1 if one source is determined to be g_func arg
3966 // returns 1 if found, *op_i is then set to origin
3967 // returns -1 if multiple origins are found
3968 static int resolve_origin(int i, const struct parsed_opr *opr,
3969 int magic, int *op_i, int *is_caller)
3971 struct label_ref *lr;
3974 if (ops[i].cc_scratch == magic)
3976 ops[i].cc_scratch = magic;
3979 if (g_labels[i] != NULL) {
3980 lr = &g_label_refs[i];
3981 for (; lr != NULL; lr = lr->next) {
3982 check_i(&ops[i], lr->i);
3983 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
3985 if (i > 0 && LAST_OP(i - 1))
3991 if (is_caller != NULL)
3996 if (ops[i].cc_scratch == magic)
3998 ops[i].cc_scratch = magic;
4000 if (!(ops[i].flags & OPF_DATA))
4002 if (!is_opr_modified(opr, &ops[i]))
4009 // XXX: could check if the other op does the same
4018 // find an instruction that previously referenced opr
4019 // if multiple results are found - fail
4020 // *op_i must be set to -1 by the caller
4021 // returns 1 if found, *op_i is then set to referencer insn
4022 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4023 int magic, int *op_i)
4025 struct label_ref *lr;
4028 if (ops[i].cc_scratch == magic)
4030 ops[i].cc_scratch = magic;
4033 if (g_labels[i] != NULL) {
4034 lr = &g_label_refs[i];
4035 for (; lr != NULL; lr = lr->next) {
4036 check_i(&ops[i], lr->i);
4037 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4039 if (i > 0 && LAST_OP(i - 1))
4047 if (ops[i].cc_scratch == magic)
4049 ops[i].cc_scratch = magic;
4051 if (!is_opr_referenced(opr, &ops[i]))
4062 // adjust datap of all reachable 'op' insns when moving back
4063 // returns 1 if at least 1 op was found
4064 // returns -1 if path without an op was found
4065 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4067 struct label_ref *lr;
4070 if (ops[i].cc_scratch == magic)
4072 ops[i].cc_scratch = magic;
4075 if (g_labels[i] != NULL) {
4076 lr = &g_label_refs[i];
4077 for (; lr != NULL; lr = lr->next) {
4078 check_i(&ops[i], lr->i);
4079 ret |= adjust_prev_op(lr->i, op, magic, datap);
4081 if (i > 0 && LAST_OP(i - 1))
4089 if (ops[i].cc_scratch == magic)
4091 ops[i].cc_scratch = magic;
4093 if (ops[i].op != op)
4096 ops[i].datap = datap;
4101 // find next instruction that reads opr
4102 // *op_i must be set to -1 by the caller
4103 // on return, *op_i is set to first referencer insn
4104 // returns 1 if exactly 1 referencer is found
4105 static int find_next_read(int i, int opcnt,
4106 const struct parsed_opr *opr, int magic, int *op_i)
4108 struct parsed_op *po;
4111 for (; i < opcnt; i++)
4113 if (ops[i].cc_scratch == magic)
4115 ops[i].cc_scratch = magic;
4118 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4119 if (po->btj != NULL) {
4121 for (j = 0; j < po->btj->count; j++) {
4122 check_i(po, po->btj->d[j].bt_i);
4123 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4129 if (po->flags & OPF_RMD)
4131 check_i(po, po->bt_i);
4132 if (po->flags & OPF_CJMP) {
4133 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4142 if (!is_opr_read(opr, po)) {
4144 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4145 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4147 full_opr = po->operand[0].lmod >= opr->lmod;
4149 if (is_opr_modified(opr, po) && full_opr) {
4153 if (po->flags & OPF_TAIL)
4168 // find next instruction that reads opr
4169 // *op_i must be set to -1 by the caller
4170 // on return, *op_i is set to first flag user insn
4171 // returns 1 if exactly 1 flag user is found
4172 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4174 struct parsed_op *po;
4177 for (; i < opcnt; i++)
4179 if (ops[i].cc_scratch == magic)
4181 ops[i].cc_scratch = magic;
4184 if (po->op == OP_CALL)
4186 if (po->flags & OPF_JMP) {
4187 if (po->btj != NULL) {
4189 for (j = 0; j < po->btj->count; j++) {
4190 check_i(po, po->btj->d[j].bt_i);
4191 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4197 if (po->flags & OPF_RMD)
4199 check_i(po, po->bt_i);
4200 if (po->flags & OPF_CJMP)
4207 if (!(po->flags & OPF_CC)) {
4208 if (po->flags & OPF_FLAGS)
4211 if (po->flags & OPF_TAIL)
4227 static int try_resolve_const(int i, const struct parsed_opr *opr,
4228 int magic, unsigned int *val)
4233 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4236 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4239 *val = ops[i].operand[1].val;
4246 static int resolve_used_bits(int i, int opcnt, int reg,
4247 int *mask, int *is_z_check)
4249 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4253 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4257 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4259 fnote(&ops[j], "(first read)\n");
4260 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4263 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4264 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4266 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4267 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4269 *mask = ops[j].operand[1].val;
4270 if (ops[j].operand[0].lmod == OPLM_BYTE
4271 && ops[j].operand[0].name[1] == 'h')
4275 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4278 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4280 *is_z_check = ops[k].pfo == PFO_Z;
4285 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4286 int *pp_i, int *multi_src)
4288 const struct parsed_proto *pp = NULL;
4289 int search_advice = 0;
4299 switch (ops[i].operand[0].type) {
4301 // try to resolve struct member calls
4302 ret = sscanf(ops[i].operand[0].name, "%3s+%x%n",
4303 s_reg, &offset, &len);
4304 if (ret == 2 && len == strlen(ops[i].operand[0].name))
4306 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4308 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4310 ret = resolve_origin(i, &opr, i + opcnt * 19, &j, NULL);
4313 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4314 && ops[j].operand[0].lmod == OPLM_DWORD
4315 && ops[j].pp == NULL) // no hint
4317 // allow one simple dereference (directx)
4318 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4319 ops[j].operand[1].name);
4322 struct parsed_opr opr2 = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4324 ret = resolve_origin(j, &opr2, j + opcnt * 19, &k, NULL);
4329 if (ops[j].op != OP_MOV)
4331 if (ops[j].operand[0].lmod != OPLM_DWORD)
4333 if (ops[j].pp != NULL) {
4337 else if (ops[j].operand[1].type == OPT_REGMEM) {
4338 // allow 'hello[ecx]' - assume array of same type items
4339 ret = sscanf(ops[j].operand[1].name, "%[^[][e%2s]",
4343 pp = proto_parse(g_fhdr, name, g_quiet_pp);
4345 else if (ops[j].operand[1].type == OPT_LABEL)
4346 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4351 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4355 pp = proto_lookup_struct(g_fhdr, pp->type.name, offset);
4362 pp = try_recover_pp(&ops[i], &ops[i].operand[0], &search_advice);
4367 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4375 static struct parsed_proto *process_call_early(int i, int opcnt,
4378 struct parsed_op *po = &ops[i];
4379 struct parsed_proto *pp;
4385 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4389 // look for and make use of esp adjust
4391 if (!pp->is_stdcall && pp->argc_stack > 0)
4392 ret = scan_for_esp_adjust(i + 1, opcnt,
4393 pp->argc_stack * 4, &adj, &multipath, 0);
4395 if (pp->argc_stack > adj / 4)
4399 if (ops[ret].op == OP_POP) {
4400 for (j = 1; j < adj / 4; j++) {
4401 if (ops[ret + j].op != OP_POP
4402 || ops[ret + j].operand[0].reg != xCX)
4414 static struct parsed_proto *process_call(int i, int opcnt)
4416 struct parsed_op *po = &ops[i];
4417 const struct parsed_proto *pp_c;
4418 struct parsed_proto *pp;
4419 const char *tmpname;
4420 int call_i = -1, ref_i = -1;
4421 int adj = 0, multipath = 0;
4424 tmpname = opr_name(po, 0);
4429 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4431 if (!pp_c->is_func && !pp_c->is_fptr)
4432 ferr(po, "call to non-func: %s\n", pp_c->name);
4433 pp = proto_clone(pp_c);
4434 my_assert_not(pp, NULL);
4436 // not resolved just to single func
4439 switch (po->operand[0].type) {
4441 // we resolved this call and no longer need the register
4442 po->regmask_src &= ~(1 << po->operand[0].reg);
4444 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4445 && ops[call_i].operand[1].type == OPT_LABEL)
4447 // no other source users?
4448 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4450 if (ret == 1 && call_i == ref_i) {
4451 // and nothing uses it after us?
4453 find_next_read(i + 1, opcnt, &po->operand[0],
4454 i + opcnt * 11, &ref_i);
4456 // then also don't need the source mov
4457 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4469 pp = calloc(1, sizeof(*pp));
4470 my_assert_not(pp, NULL);
4473 ret = scan_for_esp_adjust(i + 1, opcnt,
4474 -1, &adj, &multipath, 0);
4475 if (ret < 0 || adj < 0) {
4476 if (!g_allow_regfunc)
4477 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4478 pp->is_unresolved = 1;
4482 if (adj > ARRAY_SIZE(pp->arg))
4483 ferr(po, "esp adjust too large: %d\n", adj);
4484 pp->ret_type.name = strdup("int");
4485 pp->argc = pp->argc_stack = adj;
4486 for (arg = 0; arg < pp->argc; arg++)
4487 pp->arg[arg].type.name = strdup("int");
4492 // look for and make use of esp adjust
4495 if (!pp->is_stdcall && pp->argc_stack > 0) {
4496 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4497 ret = scan_for_esp_adjust(i + 1, opcnt,
4498 adj_expect, &adj, &multipath, 0);
4501 if (pp->is_vararg) {
4502 if (adj / 4 < pp->argc_stack) {
4503 fnote(po, "(this call)\n");
4504 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4505 adj, pp->argc_stack * 4);
4507 // modify pp to make it have varargs as normal args
4509 pp->argc += adj / 4 - pp->argc_stack;
4510 for (; arg < pp->argc; arg++) {
4511 pp->arg[arg].type.name = strdup("int");
4514 if (pp->argc > ARRAY_SIZE(pp->arg))
4515 ferr(po, "too many args for '%s'\n", tmpname);
4517 if (pp->argc_stack > adj / 4) {
4518 fnote(po, "(this call)\n");
4519 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4520 tmpname, pp->argc_stack * 4, adj);
4523 scan_for_esp_adjust(i + 1, opcnt,
4524 pp->argc_stack * 4, &adj, &multipath, 1);
4526 else if (pp->is_vararg)
4527 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4533 static int collect_call_args_early(struct parsed_op *po, int i,
4534 struct parsed_proto *pp, int *regmask)
4539 for (arg = 0; arg < pp->argc; arg++)
4540 if (pp->arg[arg].reg == NULL)
4543 // first see if it can be easily done
4544 for (j = i; j > 0 && arg < pp->argc; )
4546 if (g_labels[j] != NULL)
4550 if (ops[j].op == OP_CALL)
4552 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP)
4554 else if (ops[j].op == OP_POP)
4556 else if (ops[j].flags & OPF_CJMP)
4558 else if (ops[j].op == OP_PUSH) {
4559 if (ops[j].flags & (OPF_FARG|OPF_FARGNR))
4561 if (!g_header_mode) {
4562 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4567 if (pp->arg[arg].type.is_va_list)
4571 for (arg++; arg < pp->argc; arg++)
4572 if (pp->arg[arg].reg == NULL)
4581 for (arg = 0; arg < pp->argc; arg++)
4582 if (pp->arg[arg].reg == NULL)
4585 for (j = i; j > 0 && arg < pp->argc; )
4589 if (ops[j].op == OP_PUSH)
4591 ops[j].p_argnext = -1;
4592 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4593 pp->arg[arg].datap = &ops[j];
4595 if (ops[j].operand[0].type == OPT_REG)
4596 *regmask |= 1 << ops[j].operand[0].reg;
4598 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4599 ops[j].flags &= ~OPF_RSAVE;
4602 for (arg++; arg < pp->argc; arg++)
4603 if (pp->arg[arg].reg == NULL)
4611 static int collect_call_args_r(struct parsed_op *po, int i,
4612 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4613 int *arg_grp, int arg, int magic, int need_op_saving, int may_reuse)
4615 struct parsed_proto *pp_tmp;
4616 struct parsed_op *po_tmp;
4617 struct label_ref *lr;
4618 int need_to_save_current;
4619 int arg_grp_current = 0;
4620 int save_args_seen = 0;
4628 ferr(po, "dead label encountered\n");
4632 for (; arg < pp->argc; arg++)
4633 if (pp->arg[arg].reg == NULL)
4635 magic = (magic & 0xffffff) | (arg << 24);
4637 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4639 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4640 if (ops[j].cc_scratch != magic) {
4641 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4645 // ok: have already been here
4648 ops[j].cc_scratch = magic;
4650 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4651 lr = &g_label_refs[j];
4652 if (lr->next != NULL)
4654 for (; lr->next; lr = lr->next) {
4655 check_i(&ops[j], lr->i);
4656 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4658 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4659 arg_grp, arg, magic, need_op_saving, may_reuse);
4664 check_i(&ops[j], lr->i);
4665 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4667 if (j > 0 && LAST_OP(j - 1)) {
4668 // follow last branch in reverse
4673 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4674 arg_grp, arg, magic, need_op_saving, may_reuse);
4680 if (ops[j].op == OP_CALL)
4682 if (pp->is_unresolved)
4687 ferr(po, "arg collect hit unparsed call '%s'\n",
4688 ops[j].operand[0].name);
4689 if (may_reuse && pp_tmp->argc_stack > 0)
4690 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4691 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4693 // esp adjust of 0 means we collected it before
4694 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4695 && (ops[j].operand[1].type != OPT_CONST
4696 || ops[j].operand[1].val != 0))
4698 if (pp->is_unresolved)
4701 fnote(po, "(this call)\n");
4702 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4703 arg, pp->argc, ops[j].operand[1].val);
4705 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4707 if (pp->is_unresolved)
4710 fnote(po, "(this call)\n");
4711 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4713 else if (ops[j].flags & OPF_CJMP)
4715 if (pp->is_unresolved)
4720 else if (ops[j].op == OP_PUSH
4721 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4723 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4726 ops[j].p_argnext = -1;
4727 po_tmp = pp->arg[arg].datap;
4729 ops[j].p_argnext = po_tmp - ops;
4730 pp->arg[arg].datap = &ops[j];
4732 need_to_save_current = 0;
4735 if (ops[j].operand[0].type == OPT_REG)
4736 reg = ops[j].operand[0].reg;
4738 if (!need_op_saving) {
4739 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4740 need_to_save_current = (ret >= 0);
4742 if (need_op_saving || need_to_save_current) {
4743 // mark this push as one that needs operand saving
4744 ops[j].flags &= ~OPF_RMD;
4745 if (ops[j].p_argnum == 0) {
4746 ops[j].p_argnum = arg + 1;
4747 save_args |= 1 << arg;
4749 else if (ops[j].p_argnum < arg + 1) {
4750 // XXX: might kill valid var..
4751 //*save_arg_vars &= ~(1 << (ops[j].p_argnum - 1));
4752 ops[j].p_argnum = arg + 1;
4753 save_args |= 1 << arg;
4756 if (save_args_seen & (1 << (ops[j].p_argnum - 1))) {
4759 if (arg_grp_current >= MAX_ARG_GRP)
4760 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
4761 ops[j].p_argnum, pp->name);
4764 else if (ops[j].p_argnum == 0)
4765 ops[j].flags |= OPF_RMD;
4767 // some PUSHes are reused by different calls on other branches,
4768 // but that can't happen if we didn't branch, so they
4769 // can be removed from future searches (handles nested calls)
4771 ops[j].flags |= OPF_FARGNR;
4773 ops[j].flags |= OPF_FARG;
4774 ops[j].flags &= ~OPF_RSAVE;
4776 // check for __VALIST
4777 if (!pp->is_unresolved && g_func_pp != NULL
4778 && pp->arg[arg].type.is_va_list)
4781 ret = resolve_origin(j, &ops[j].operand[0],
4782 magic + 1, &k, NULL);
4783 if (ret == 1 && k >= 0)
4785 if (ops[k].op == OP_LEA) {
4786 if (!g_func_pp->is_vararg)
4787 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
4790 snprintf(buf, sizeof(buf), "arg_%X",
4791 g_func_pp->argc_stack * 4);
4792 if (strstr(ops[k].operand[1].name, buf)
4793 || strstr(ops[k].operand[1].name, "arglist"))
4795 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
4796 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
4797 save_args &= ~(1 << arg);
4801 ferr(&ops[k], "va_list arg detection failed\n");
4803 // check for va_list from g_func_pp arg too
4804 else if (ops[k].op == OP_MOV
4805 && is_stack_access(&ops[k], &ops[k].operand[1]))
4807 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
4808 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
4810 ops[k].flags |= OPF_RMD | OPF_DONE;
4811 ops[j].flags |= OPF_RMD;
4812 ops[j].p_argpass = ret + 1;
4813 save_args &= ~(1 << arg);
4820 *save_arg_vars |= save_args;
4822 // tracking reg usage
4824 *regmask |= 1 << reg;
4827 if (!pp->is_unresolved) {
4829 for (; arg < pp->argc; arg++)
4830 if (pp->arg[arg].reg == NULL)
4833 magic = (magic & 0xffffff) | (arg << 24);
4836 if (ops[j].p_arggrp > arg_grp_current) {
4838 arg_grp_current = ops[j].p_arggrp;
4840 if (ops[j].p_argnum > 0)
4841 save_args_seen |= 1 << (ops[j].p_argnum - 1);
4844 if (arg < pp->argc) {
4845 ferr(po, "arg collect failed for '%s': %d/%d\n",
4846 pp->name, arg, pp->argc);
4850 if (arg_grp_current > *arg_grp)
4851 *arg_grp = arg_grp_current;
4856 static int collect_call_args(struct parsed_op *po, int i,
4857 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4860 // arg group is for cases when pushes for
4861 // multiple funcs are going on
4862 struct parsed_op *po_tmp;
4863 int save_arg_vars_current = 0;
4868 ret = collect_call_args_r(po, i, pp, regmask,
4869 &save_arg_vars_current, &arg_grp, 0, magic, 0, 0);
4874 // propagate arg_grp
4875 for (a = 0; a < pp->argc; a++) {
4876 if (pp->arg[a].reg != NULL)
4879 po_tmp = pp->arg[a].datap;
4880 while (po_tmp != NULL) {
4881 po_tmp->p_arggrp = arg_grp;
4882 if (po_tmp->p_argnext > 0)
4883 po_tmp = &ops[po_tmp->p_argnext];
4889 save_arg_vars[arg_grp] |= save_arg_vars_current;
4891 if (pp->is_unresolved) {
4893 pp->argc_stack += ret;
4894 for (a = 0; a < pp->argc; a++)
4895 if (pp->arg[a].type.name == NULL)
4896 pp->arg[a].type.name = strdup("int");
4902 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
4903 int regmask_now, int *regmask,
4904 int regmask_save_now, int *regmask_save,
4905 int *regmask_init, int regmask_arg)
4907 struct parsed_op *po;
4915 for (; i < opcnt; i++)
4918 if (cbits[i >> 3] & (1 << (i & 7)))
4920 cbits[i >> 3] |= (1 << (i & 7));
4922 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4923 if (po->flags & (OPF_RMD|OPF_DONE))
4925 if (po->btj != NULL) {
4926 for (j = 0; j < po->btj->count; j++) {
4927 check_i(po, po->btj->d[j].bt_i);
4928 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
4929 regmask_now, regmask, regmask_save_now, regmask_save,
4930 regmask_init, regmask_arg);
4935 check_i(po, po->bt_i);
4936 if (po->flags & OPF_CJMP)
4937 reg_use_pass(po->bt_i, opcnt, cbits,
4938 regmask_now, regmask, regmask_save_now, regmask_save,
4939 regmask_init, regmask_arg);
4945 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
4946 && !g_func_pp->is_userstack
4947 && po->operand[0].type == OPT_REG)
4949 reg = po->operand[0].reg;
4950 ferr_assert(po, reg >= 0);
4953 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
4954 if (regmask_now & (1 << reg)) {
4955 already_saved = regmask_save_now & (1 << reg);
4956 flags_set = OPF_RSAVE | OPF_DONE;
4959 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0);
4961 scan_for_pop(i + 1, opcnt, i + opcnt * 4, reg, 0, flags_set);
4964 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
4966 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
4971 ferr_assert(po, !already_saved);
4972 po->flags |= flags_set;
4974 if (regmask_now & (1 << reg)) {
4975 regmask_save_now |= (1 << reg);
4976 *regmask_save |= regmask_save_now;
4981 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
4982 reg = po->operand[0].reg;
4983 ferr_assert(po, reg >= 0);
4985 if (regmask_save_now & (1 << reg))
4986 regmask_save_now &= ~(1 << reg);
4988 regmask_now &= ~(1 << reg);
4991 else if (po->op == OP_CALL) {
4992 if ((po->regmask_dst & (1 << xAX))
4993 && !(po->regmask_dst & (1 << xDX)))
4995 if (po->flags & OPF_TAIL)
4996 // don't need eax, will do "return f();" or "f(); return;"
4997 po->regmask_dst &= ~(1 << xAX);
4999 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5001 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5004 po->regmask_dst &= ~(1 << xAX);
5008 // not "full stack" mode and have something in stack
5009 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5010 ferr(po, "float stack is not empty on func call\n");
5013 if (po->flags & OPF_NOREGS)
5016 // if incomplete register is used, clear it on init to avoid
5017 // later use of uninitialized upper part in some situations
5018 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5019 && po->operand[0].lmod != OPLM_DWORD)
5021 reg = po->operand[0].reg;
5022 ferr_assert(po, reg >= 0);
5024 if (!(regmask_now & (1 << reg)))
5025 *regmask_init |= 1 << reg;
5028 regmask_op = po->regmask_src | po->regmask_dst;
5030 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5031 regmask_new &= ~(1 << xSP);
5032 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5033 regmask_new &= ~(1 << xBP);
5035 if (regmask_new != 0)
5036 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5038 if (regmask_op & (1 << xBP)) {
5039 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5040 if (po->regmask_dst & (1 << xBP))
5041 // compiler decided to drop bp frame and use ebp as scratch
5042 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5044 regmask_op &= ~(1 << xBP);
5048 if (po->flags & OPF_FPUSH) {
5049 if (regmask_now & mxST1)
5050 regmask_now |= mxSTa; // switch to "full stack" mode
5051 if (regmask_now & mxSTa)
5052 po->flags |= OPF_FSHIFT;
5053 if (!(regmask_now & mxST7_2)) {
5055 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5059 regmask_now |= regmask_op;
5060 *regmask |= regmask_now;
5063 if (po->flags & OPF_FPOP) {
5064 if ((regmask_now & mxSTa) == 0)
5065 ferr(po, "float pop on empty stack?\n");
5066 if (regmask_now & (mxST7_2 | mxST1))
5067 po->flags |= OPF_FSHIFT;
5068 if (!(regmask_now & mxST7_2)) {
5070 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5074 if (po->flags & OPF_TAIL) {
5075 if (!(regmask_now & mxST7_2)) {
5076 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5077 if (!(regmask_now & mxST0))
5078 ferr(po, "no st0 on float return, mask: %x\n",
5081 else if (regmask_now & mxST1_0)
5082 ferr(po, "float regs on tail: %x\n", regmask_now);
5085 // there is support for "conditional tailcall", sort of
5086 if (!(po->flags & OPF_CC))
5092 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5096 for (i = 0; i < pp->argc; i++)
5097 if (pp->arg[i].reg == NULL)
5101 memmove(&pp->arg[i + 1], &pp->arg[i],
5102 sizeof(pp->arg[0]) * pp->argc_stack);
5103 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5104 pp->arg[i].reg = strdup(reg);
5105 pp->arg[i].type.name = strdup("int");
5110 static void output_std_flags(FILE *fout, struct parsed_op *po,
5111 int *pfomask, const char *dst_opr_text)
5113 if (*pfomask & (1 << PFO_Z)) {
5114 fprintf(fout, "\n cond_z = (%s%s == 0);",
5115 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5116 *pfomask &= ~(1 << PFO_Z);
5118 if (*pfomask & (1 << PFO_S)) {
5119 fprintf(fout, "\n cond_s = (%s%s < 0);",
5120 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5121 *pfomask &= ~(1 << PFO_S);
5126 OPP_FORCE_NORETURN = (1 << 0),
5127 OPP_SIMPLE_ARGS = (1 << 1),
5128 OPP_ALIGN = (1 << 2),
5131 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5134 const char *cconv = "";
5136 if (pp->is_fastcall)
5137 cconv = "__fastcall ";
5138 else if (pp->is_stdcall && pp->argc_reg == 0)
5139 cconv = "__stdcall ";
5141 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5143 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5144 fprintf(fout, "noreturn ");
5147 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5152 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5156 output_pp_attrs(fout, pp, flags);
5159 fprintf(fout, "%s", pp->name);
5164 for (i = 0; i < pp->argc; i++) {
5166 fprintf(fout, ", ");
5167 if (pp->arg[i].fptr != NULL && !(flags & OPP_SIMPLE_ARGS)) {
5169 output_pp(fout, pp->arg[i].fptr, 0);
5171 else if (pp->arg[i].type.is_retreg) {
5172 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5175 fprintf(fout, "%s", pp->arg[i].type.name);
5177 fprintf(fout, " a%d", i + 1);
5180 if (pp->is_vararg) {
5182 fprintf(fout, ", ");
5183 fprintf(fout, "...");
5188 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5194 snprintf(buf1, sizeof(buf1), "%d", grp);
5195 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5200 static void gen_x_cleanup(int opcnt);
5202 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5204 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5205 struct parsed_opr *last_arith_dst = NULL;
5206 char buf1[256], buf2[256], buf3[256], cast[64];
5207 struct parsed_proto *pp, *pp_tmp;
5208 struct parsed_data *pd;
5210 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5211 unsigned char cbits[MAX_OPS / 8];
5212 const char *float_type;
5213 const char *float_st0;
5214 const char *float_st1;
5215 int need_float_stack = 0;
5216 int need_float_sw = 0; // status word
5217 int need_tmp_var = 0;
5221 int label_pending = 0;
5222 int need_double = 0;
5223 int regmask_save = 0; // used regs saved/restored in this func
5224 int regmask_arg; // regs from this function args (fastcall, etc)
5225 int regmask_ret; // regs needed on ret
5226 int regmask_now; // temp
5227 int regmask_init = 0; // regs that need zero initialization
5228 int regmask_pp = 0; // regs used in complex push-pop graph
5229 int regmask = 0; // used regs
5239 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5240 g_stack_frame_used = 0;
5241 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5242 regmask_init = g_regmask_init;
5244 g_func_pp = proto_parse(fhdr, funcn, 0);
5245 if (g_func_pp == NULL)
5246 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5248 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5249 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5252 // - resolve all branches
5253 // - parse calls with labels
5254 resolve_branches_parse_calls(opcnt);
5257 // - handle ebp/esp frame, remove ops related to it
5258 scan_prologue_epilogue(opcnt);
5261 // - remove dead labels
5262 // - set regs needed at ret
5263 for (i = 0; i < opcnt; i++)
5265 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5270 if (ops[i].op == OP_RET)
5271 ops[i].regmask_src |= regmask_ret;
5275 // - process trivial calls
5276 for (i = 0; i < opcnt; i++)
5279 if (po->flags & (OPF_RMD|OPF_DONE))
5282 if (po->op == OP_CALL)
5284 pp = process_call_early(i, opcnt, &j);
5286 if (!(po->flags & OPF_ATAIL))
5287 // since we know the args, try to collect them
5288 if (collect_call_args_early(po, i, pp, ®mask) != 0)
5294 // commit esp adjust
5295 if (ops[j].op != OP_POP)
5296 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5298 for (l = 0; l < pp->argc_stack; l++)
5299 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5303 if (strstr(pp->ret_type.name, "int64"))
5306 po->flags |= OPF_DONE;
5312 // - process calls, stage 2
5313 // - handle some push/pop pairs
5314 // - scan for STD/CLD, propagate DF
5315 // - try to resolve needed x87 status word bits
5316 for (i = 0; i < opcnt; i++)
5321 if (po->flags & OPF_RMD)
5324 if (po->op == OP_CALL)
5326 if (!(po->flags & OPF_DONE)) {
5327 pp = process_call(i, opcnt);
5329 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5330 // since we know the args, collect them
5331 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5334 // for unresolved, collect after other passes
5338 ferr_assert(po, pp != NULL);
5340 po->regmask_src |= get_pp_arg_regmask_src(pp);
5341 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5343 if (po->regmask_dst & mxST0)
5344 po->flags |= OPF_FPUSH;
5346 if (strstr(pp->ret_type.name, "int64"))
5352 if (po->flags & OPF_DONE)
5357 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
5358 && po->operand[0].type == OPT_CONST)
5360 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5365 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5369 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5370 scan_propagate_df(i + 1, opcnt);
5375 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
5376 ferr(po, "TODO: fnstsw to mem\n");
5377 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
5379 ferr(po, "fnstsw resolve failed\n");
5380 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
5381 (void *)(long)(mask | (z_check << 16)));
5383 ferr(po, "failed to find fcom: %d\n", ret);
5392 // - find POPs for PUSHes, rm both
5393 // - scan for all used registers
5394 memset(cbits, 0, sizeof(cbits));
5395 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5396 0, ®mask_save, ®mask_init, regmask_arg);
5399 // - find flag set ops for their users
5400 // - do unresolved calls
5401 // - declare indirect functions
5402 // - other op specific processing
5403 for (i = 0; i < opcnt; i++)
5406 if (po->flags & (OPF_RMD|OPF_DONE))
5409 if (po->flags & OPF_CC)
5411 int setters[16], cnt = 0, branched = 0;
5413 ret = scan_for_flag_set(i, i + opcnt * 6,
5414 &branched, setters, &cnt);
5415 if (ret < 0 || cnt <= 0)
5416 ferr(po, "unable to trace flag setter(s)\n");
5417 if (cnt > ARRAY_SIZE(setters))
5418 ferr(po, "too many flag setters\n");
5420 for (j = 0; j < cnt; j++)
5422 tmp_op = &ops[setters[j]]; // flag setter
5425 // to get nicer code, we try to delay test and cmp;
5426 // if we can't because of operand modification, or if we
5427 // have arith op, or branch, make it calculate flags explicitly
5428 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5430 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5431 pfomask = 1 << po->pfo;
5433 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5434 pfomask = 1 << po->pfo;
5437 // see if we'll be able to handle based on op result
5438 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5439 && po->pfo != PFO_Z && po->pfo != PFO_S
5440 && po->pfo != PFO_P)
5442 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5444 pfomask = 1 << po->pfo;
5447 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5448 propagate_lmod(tmp_op, &tmp_op->operand[0],
5449 &tmp_op->operand[1]);
5450 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5455 tmp_op->pfomask |= pfomask;
5456 cond_vars |= pfomask;
5458 // note: may overwrite, currently not a problem
5462 if (po->op == OP_RCL || po->op == OP_RCR
5463 || po->op == OP_ADC || po->op == OP_SBB)
5464 cond_vars |= 1 << PFO_C;
5470 cond_vars |= 1 << PFO_Z;
5474 if (po->operand[0].lmod == OPLM_DWORD)
5479 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
5484 // note: resolved non-reg calls are OPF_DONE already
5486 ferr_assert(po, pp != NULL);
5488 if (pp->is_unresolved) {
5489 int regmask_stack = 0;
5490 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5493 // this is pretty rough guess:
5494 // see ecx and edx were pushed (and not their saved versions)
5495 for (arg = 0; arg < pp->argc; arg++) {
5496 if (pp->arg[arg].reg != NULL)
5499 tmp_op = pp->arg[arg].datap;
5501 ferr(po, "parsed_op missing for arg%d\n", arg);
5502 if (tmp_op->p_argnum == 0 && tmp_op->operand[0].type == OPT_REG)
5503 regmask_stack |= 1 << tmp_op->operand[0].reg;
5506 if (!((regmask_stack & (1 << xCX))
5507 && (regmask_stack & (1 << xDX))))
5509 if (pp->argc_stack != 0
5510 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5512 pp_insert_reg_arg(pp, "ecx");
5513 pp->is_fastcall = 1;
5514 regmask_init |= 1 << xCX;
5515 regmask |= 1 << xCX;
5517 if (pp->argc_stack != 0
5518 || ((regmask | regmask_arg) & (1 << xDX)))
5520 pp_insert_reg_arg(pp, "edx");
5521 regmask_init |= 1 << xDX;
5522 regmask |= 1 << xDX;
5526 // note: __cdecl doesn't fall into is_unresolved category
5527 if (pp->argc_stack > 0)
5533 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
5535 // <var> = offset <something>
5536 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5537 && !IS_START(po->operand[1].name, "off_"))
5539 if (!po->operand[0].pp->is_fptr)
5540 ferr(po, "%s not declared as fptr when it should be\n",
5541 po->operand[0].name);
5542 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5543 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5544 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5545 fnote(po, "var: %s\n", buf1);
5546 fnote(po, "func: %s\n", buf2);
5547 ferr(po, "^ mismatch\n");
5555 if (po->operand[0].lmod == OPLM_DWORD) {
5556 // 32bit division is common, look for it
5557 if (po->op == OP_DIV)
5558 ret = scan_for_reg_clear(i, xDX);
5560 ret = scan_for_cdq_edx(i);
5562 po->flags |= OPF_32BIT;
5571 po->flags |= OPF_RMD | OPF_DONE;
5581 if (po->operand[0].lmod == OPLM_QWORD)
5591 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5593 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5595 po->flags |= OPF_32BIT;
5604 float_type = need_double ? "double" : "float";
5605 need_float_stack = !!(regmask & mxST7_2);
5606 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
5607 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
5609 // output starts here
5611 // define userstack size
5612 if (g_func_pp->is_userstack) {
5613 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5614 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5615 fprintf(fout, "#endif\n");
5618 // the function itself
5619 ferr_assert(ops, !g_func_pp->is_fptr);
5620 output_pp(fout, g_func_pp,
5621 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5622 fprintf(fout, "\n{\n");
5624 // declare indirect functions
5625 for (i = 0; i < opcnt; i++) {
5627 if (po->flags & OPF_RMD)
5630 if (po->op == OP_CALL) {
5633 ferr(po, "NULL pp\n");
5635 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5636 if (pp->name[0] != 0) {
5637 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5638 memcpy(pp->name, "i_", 2);
5640 // might be declared already
5642 for (j = 0; j < i; j++) {
5643 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5644 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5654 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5657 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5658 fprintf(fout, ";\n");
5663 // output LUTs/jumptables
5664 for (i = 0; i < g_func_pd_cnt; i++) {
5666 fprintf(fout, " static const ");
5667 if (pd->type == OPT_OFFSET) {
5668 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5670 for (j = 0; j < pd->count; j++) {
5672 fprintf(fout, ", ");
5673 fprintf(fout, "&&%s", pd->d[j].u.label);
5677 fprintf(fout, "%s %s[] =\n { ",
5678 lmod_type_u(ops, pd->lmod), pd->label);
5680 for (j = 0; j < pd->count; j++) {
5682 fprintf(fout, ", ");
5683 fprintf(fout, "%u", pd->d[j].u.val);
5686 fprintf(fout, " };\n");
5690 // declare stack frame, va_arg
5692 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5693 if (g_func_lmods & (1 << OPLM_WORD))
5694 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5695 if (g_func_lmods & (1 << OPLM_BYTE))
5696 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5697 if (g_func_lmods & (1 << OPLM_QWORD))
5698 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5699 fprintf(fout, " } sf;\n");
5703 if (g_func_pp->is_userstack) {
5704 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5705 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5709 if (g_func_pp->is_vararg) {
5710 fprintf(fout, " va_list ap;\n");
5714 // declare arg-registers
5715 for (i = 0; i < g_func_pp->argc; i++) {
5716 if (g_func_pp->arg[i].reg != NULL) {
5717 reg = char_array_i(regs_r32,
5718 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5719 if (regmask & (1 << reg)) {
5720 if (g_func_pp->arg[i].type.is_retreg)
5721 fprintf(fout, " u32 %s = *r_%s;\n",
5722 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5724 fprintf(fout, " u32 %s = (u32)a%d;\n",
5725 g_func_pp->arg[i].reg, i + 1);
5728 if (g_func_pp->arg[i].type.is_retreg)
5729 ferr(ops, "retreg '%s' is unused?\n",
5730 g_func_pp->arg[i].reg);
5731 fprintf(fout, " // %s = a%d; // unused\n",
5732 g_func_pp->arg[i].reg, i + 1);
5738 // declare normal registers
5739 regmask_now = regmask & ~regmask_arg;
5740 regmask_now &= ~(1 << xSP);
5741 if (regmask_now & 0x00ff) {
5742 for (reg = 0; reg < 8; reg++) {
5743 if (regmask_now & (1 << reg)) {
5744 fprintf(fout, " u32 %s", regs_r32[reg]);
5745 if (regmask_init & (1 << reg))
5746 fprintf(fout, " = 0");
5747 fprintf(fout, ";\n");
5753 if (regmask_now & 0xff00) {
5754 for (reg = 8; reg < 16; reg++) {
5755 if (regmask_now & (1 << reg)) {
5756 fprintf(fout, " mmxr %s", regs_r32[reg]);
5757 if (regmask_init & (1 << reg))
5758 fprintf(fout, " = { 0, }");
5759 fprintf(fout, ";\n");
5765 if (need_float_stack) {
5766 fprintf(fout, " %s f_st[8];\n", float_type);
5767 fprintf(fout, " int f_stp = 0;\n");
5771 if (regmask_now & 0xff0000) {
5772 for (reg = 16; reg < 24; reg++) {
5773 if (regmask_now & (1 << reg)) {
5774 fprintf(fout, " %s f_st%d", float_type, reg - 16);
5775 if (regmask_init & (1 << reg))
5776 fprintf(fout, " = 0");
5777 fprintf(fout, ";\n");
5784 if (need_float_sw) {
5785 fprintf(fout, " u16 f_sw;\n");
5790 for (reg = 0; reg < 8; reg++) {
5791 if (regmask_save & (1 << reg)) {
5792 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
5798 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
5799 if (save_arg_vars[i] == 0)
5801 for (reg = 0; reg < 32; reg++) {
5802 if (save_arg_vars[i] & (1 << reg)) {
5803 fprintf(fout, " u32 %s;\n",
5804 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
5810 // declare push-pop temporaries
5812 for (reg = 0; reg < 8; reg++) {
5813 if (regmask_pp & (1 << reg)) {
5814 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
5821 for (i = 0; i < 8; i++) {
5822 if (cond_vars & (1 << i)) {
5823 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
5830 fprintf(fout, " u32 tmp;\n");
5835 fprintf(fout, " u64 tmp64;\n");
5840 fprintf(fout, "\n");
5842 // do stack clear, if needed
5843 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
5845 if (g_stack_clear_len != 0) {
5846 if (g_stack_clear_len <= 4) {
5847 for (i = 0; i < g_stack_clear_len; i++)
5848 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
5849 fprintf(fout, "0;\n");
5852 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
5853 g_stack_clear_start, g_stack_clear_len * 4);
5857 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
5860 if (g_func_pp->is_vararg) {
5861 if (g_func_pp->argc_stack == 0)
5862 ferr(ops, "vararg func without stack args?\n");
5863 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
5867 for (i = 0; i < opcnt; i++)
5869 if (g_labels[i] != NULL) {
5870 fprintf(fout, "\n%s:\n", g_labels[i]);
5873 delayed_flag_op = NULL;
5874 last_arith_dst = NULL;
5878 if (po->flags & OPF_RMD)
5883 #define assert_operand_cnt(n_) \
5884 if (po->operand_cnt != n_) \
5885 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
5887 // conditional/flag using op?
5888 if (po->flags & OPF_CC)
5894 // we go through all this trouble to avoid using parsed_flag_op,
5895 // which makes generated code much nicer
5896 if (delayed_flag_op != NULL)
5898 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
5899 po->pfo, po->pfo_inv);
5902 else if (last_arith_dst != NULL
5903 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
5904 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
5907 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5908 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
5909 last_arith_dst->lmod, buf3);
5912 else if (tmp_op != NULL) {
5913 // use preprocessed flag calc results
5914 if (!(tmp_op->pfomask & (1 << po->pfo)))
5915 ferr(po, "not prepared for pfo %d\n", po->pfo);
5917 // note: pfo_inv was not yet applied
5918 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
5919 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
5922 ferr(po, "all methods of finding comparison failed\n");
5925 if (po->flags & OPF_JMP) {
5926 fprintf(fout, " if %s", buf1);
5928 else if (po->op == OP_RCL || po->op == OP_RCR
5929 || po->op == OP_ADC || po->op == OP_SBB)
5932 fprintf(fout, " cond_%s = %s;\n",
5933 parsed_flag_op_names[po->pfo], buf1);
5935 else if (po->flags & OPF_DATA) { // SETcc
5936 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
5937 fprintf(fout, " %s = %s;", buf2, buf1);
5940 ferr(po, "unhandled conditional op\n");
5944 pfomask = po->pfomask;
5946 if (po->flags & (OPF_REPZ|OPF_REPNZ)) {
5947 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
5948 ret = try_resolve_const(i, &opr, opcnt * 7 + i, &uval);
5950 if (ret != 1 || uval == 0) {
5951 // we need initial flags for ecx=0 case..
5952 if (i > 0 && ops[i - 1].op == OP_XOR
5953 && IS(ops[i - 1].operand[0].name,
5954 ops[i - 1].operand[1].name))
5956 fprintf(fout, " cond_z = ");
5957 if (pfomask & (1 << PFO_C))
5958 fprintf(fout, "cond_c = ");
5959 fprintf(fout, "0;\n");
5961 else if (last_arith_dst != NULL) {
5962 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5963 out_test_for_cc(buf1, sizeof(buf1), po, PFO_Z, 0,
5964 last_arith_dst->lmod, buf3);
5965 fprintf(fout, " cond_z = %s;\n", buf1);
5968 ferr(po, "missing initial ZF\n");
5975 assert_operand_cnt(2);
5976 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5977 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5978 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
5979 fprintf(fout, " %s = %s;", buf1,
5980 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5985 assert_operand_cnt(2);
5986 po->operand[1].lmod = OPLM_DWORD; // always
5987 fprintf(fout, " %s = %s;",
5988 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5989 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5994 assert_operand_cnt(2);
5995 fprintf(fout, " %s = %s;",
5996 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5997 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6001 assert_operand_cnt(2);
6002 switch (po->operand[1].lmod) {
6004 strcpy(buf3, "(s8)");
6007 strcpy(buf3, "(s16)");
6010 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6012 fprintf(fout, " %s = %s;",
6013 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6014 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6019 assert_operand_cnt(2);
6020 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6021 fprintf(fout, " tmp = %s;",
6022 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6023 fprintf(fout, " %s = %s;",
6024 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6025 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6026 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6027 fprintf(fout, " %s = %stmp;",
6028 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6029 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6030 snprintf(g_comment, sizeof(g_comment), "xchg");
6034 assert_operand_cnt(1);
6035 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6036 fprintf(fout, " %s = ~%s;", buf1, buf1);
6040 assert_operand_cnt(2);
6041 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6042 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6043 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6044 strcpy(g_comment, "xlat");
6048 assert_operand_cnt(2);
6049 fprintf(fout, " %s = (s32)%s >> 31;",
6050 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6051 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6052 strcpy(g_comment, "cdq");
6056 assert_operand_cnt(1);
6057 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6058 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6062 if (po->flags & OPF_REP) {
6063 assert_operand_cnt(3);
6068 assert_operand_cnt(2);
6069 fprintf(fout, " %s = %sesi; esi %c= %d;",
6070 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6071 lmod_cast_u_ptr(po, po->operand[1].lmod),
6072 (po->flags & OPF_DF) ? '-' : '+',
6073 lmod_bytes(po, po->operand[1].lmod));
6074 strcpy(g_comment, "lods");
6079 if (po->flags & OPF_REP) {
6080 assert_operand_cnt(3);
6081 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6082 (po->flags & OPF_DF) ? '-' : '+',
6083 lmod_bytes(po, po->operand[1].lmod));
6084 fprintf(fout, " %sedi = eax;",
6085 lmod_cast_u_ptr(po, po->operand[1].lmod));
6086 strcpy(g_comment, "rep stos");
6089 assert_operand_cnt(2);
6090 fprintf(fout, " %sedi = eax; edi %c= %d;",
6091 lmod_cast_u_ptr(po, po->operand[1].lmod),
6092 (po->flags & OPF_DF) ? '-' : '+',
6093 lmod_bytes(po, po->operand[1].lmod));
6094 strcpy(g_comment, "stos");
6099 j = lmod_bytes(po, po->operand[0].lmod);
6100 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6101 l = (po->flags & OPF_DF) ? '-' : '+';
6102 if (po->flags & OPF_REP) {
6103 assert_operand_cnt(3);
6105 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6108 " %sedi = %sesi;", buf1, buf1);
6109 strcpy(g_comment, "rep movs");
6112 assert_operand_cnt(2);
6113 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6114 buf1, buf1, l, j, l, j);
6115 strcpy(g_comment, "movs");
6120 // repe ~ repeat while ZF=1
6121 j = lmod_bytes(po, po->operand[0].lmod);
6122 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6123 l = (po->flags & OPF_DF) ? '-' : '+';
6124 if (po->flags & OPF_REP) {
6125 assert_operand_cnt(3);
6127 " for (; ecx != 0; ecx--) {\n");
6128 if (pfomask & (1 << PFO_C)) {
6131 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6132 pfomask &= ~(1 << PFO_C);
6135 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6136 buf1, buf1, l, j, l, j);
6138 " if (cond_z %s 0) break;\n",
6139 (po->flags & OPF_REPZ) ? "==" : "!=");
6142 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6143 (po->flags & OPF_REPZ) ? "e" : "ne");
6146 assert_operand_cnt(2);
6148 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6149 buf1, buf1, l, j, l, j);
6150 strcpy(g_comment, "cmps");
6152 pfomask &= ~(1 << PFO_Z);
6153 last_arith_dst = NULL;
6154 delayed_flag_op = NULL;
6158 // only does ZF (for now)
6159 // repe ~ repeat while ZF=1
6160 j = lmod_bytes(po, po->operand[1].lmod);
6161 l = (po->flags & OPF_DF) ? '-' : '+';
6162 if (po->flags & OPF_REP) {
6163 assert_operand_cnt(3);
6165 " for (; ecx != 0; ecx--) {\n");
6167 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6168 lmod_cast_u(po, po->operand[1].lmod),
6169 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6171 " if (cond_z %s 0) break;\n",
6172 (po->flags & OPF_REPZ) ? "==" : "!=");
6175 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6176 (po->flags & OPF_REPZ) ? "e" : "ne");
6179 assert_operand_cnt(2);
6180 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6181 lmod_cast_u(po, po->operand[1].lmod),
6182 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6183 strcpy(g_comment, "scas");
6185 pfomask &= ~(1 << PFO_Z);
6186 last_arith_dst = NULL;
6187 delayed_flag_op = NULL;
6190 // arithmetic w/flags
6192 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6193 goto dualop_arith_const;
6194 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6198 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6199 if (po->operand[1].type == OPT_CONST) {
6200 j = lmod_bytes(po, po->operand[0].lmod);
6201 if (((1ull << j * 8) - 1) == po->operand[1].val)
6202 goto dualop_arith_const;
6207 assert_operand_cnt(2);
6208 fprintf(fout, " %s %s= %s;",
6209 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6211 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6212 output_std_flags(fout, po, &pfomask, buf1);
6213 last_arith_dst = &po->operand[0];
6214 delayed_flag_op = NULL;
6218 // and 0, or ~0 used instead mov
6219 assert_operand_cnt(2);
6220 fprintf(fout, " %s = %s;",
6221 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6222 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6223 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6224 output_std_flags(fout, po, &pfomask, buf1);
6225 last_arith_dst = &po->operand[0];
6226 delayed_flag_op = NULL;
6231 assert_operand_cnt(2);
6232 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6233 if (pfomask & (1 << PFO_C)) {
6234 if (po->operand[1].type == OPT_CONST) {
6235 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6236 j = po->operand[1].val;
6239 if (po->op == OP_SHL)
6243 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6247 ferr(po, "zero shift?\n");
6251 pfomask &= ~(1 << PFO_C);
6253 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6254 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6255 if (po->operand[1].type != OPT_CONST)
6256 fprintf(fout, " & 0x1f");
6258 output_std_flags(fout, po, &pfomask, buf1);
6259 last_arith_dst = &po->operand[0];
6260 delayed_flag_op = NULL;
6264 assert_operand_cnt(2);
6265 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6266 fprintf(fout, " %s = %s%s >> %s;", buf1,
6267 lmod_cast_s(po, po->operand[0].lmod), buf1,
6268 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6269 output_std_flags(fout, po, &pfomask, buf1);
6270 last_arith_dst = &po->operand[0];
6271 delayed_flag_op = NULL;
6276 assert_operand_cnt(3);
6277 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6278 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6279 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6280 if (po->operand[2].type != OPT_CONST) {
6281 // no handling for "undefined" case, hopefully not needed
6282 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6285 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6286 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6287 if (po->op == OP_SHLD) {
6288 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6289 buf1, buf3, buf1, buf2, l, buf3);
6290 strcpy(g_comment, "shld");
6293 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6294 buf1, buf3, buf1, buf2, l, buf3);
6295 strcpy(g_comment, "shrd");
6297 output_std_flags(fout, po, &pfomask, buf1);
6298 last_arith_dst = &po->operand[0];
6299 delayed_flag_op = NULL;
6304 assert_operand_cnt(2);
6305 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6306 if (po->operand[1].type == OPT_CONST) {
6307 j = po->operand[1].val;
6308 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6309 fprintf(fout, po->op == OP_ROL ?
6310 " %s = (%s << %d) | (%s >> %d);" :
6311 " %s = (%s >> %d) | (%s << %d);",
6312 buf1, buf1, j, buf1,
6313 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6317 output_std_flags(fout, po, &pfomask, buf1);
6318 last_arith_dst = &po->operand[0];
6319 delayed_flag_op = NULL;
6324 assert_operand_cnt(2);
6325 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6326 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6327 if (po->operand[1].type == OPT_CONST) {
6328 j = po->operand[1].val % l;
6330 ferr(po, "zero rotate\n");
6331 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6332 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6333 if (po->op == OP_RCL) {
6335 " %s = (%s << %d) | (cond_c << %d)",
6336 buf1, buf1, j, j - 1);
6338 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6342 " %s = (%s >> %d) | (cond_c << %d)",
6343 buf1, buf1, j, l - j);
6345 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6347 fprintf(fout, ";\n");
6348 fprintf(fout, " cond_c = tmp;");
6352 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6353 output_std_flags(fout, po, &pfomask, buf1);
6354 last_arith_dst = &po->operand[0];
6355 delayed_flag_op = NULL;
6359 assert_operand_cnt(2);
6360 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6361 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6362 // special case for XOR
6363 if (pfomask & (1 << PFO_BE)) { // weird, but it happens..
6364 fprintf(fout, " cond_be = 1;\n");
6365 pfomask &= ~(1 << PFO_BE);
6367 fprintf(fout, " %s = 0;",
6368 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6369 last_arith_dst = &po->operand[0];
6370 delayed_flag_op = NULL;
6376 assert_operand_cnt(2);
6377 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6378 if (pfomask & (1 << PFO_C)) {
6379 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6380 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6381 if (po->operand[0].lmod == OPLM_DWORD) {
6382 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6383 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6384 fprintf(fout, " %s = (u32)tmp64;",
6385 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6386 strcat(g_comment, " add64");
6389 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6390 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6391 fprintf(fout, " %s += %s;",
6392 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6395 pfomask &= ~(1 << PFO_C);
6396 output_std_flags(fout, po, &pfomask, buf1);
6397 last_arith_dst = &po->operand[0];
6398 delayed_flag_op = NULL;
6401 if (pfomask & (1 << PFO_LE)) {
6402 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
6403 fprintf(fout, " cond_%s = %s;\n",
6404 parsed_flag_op_names[PFO_LE], buf1);
6405 pfomask &= ~(1 << PFO_LE);
6410 assert_operand_cnt(2);
6411 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6412 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6413 for (j = 0; j <= PFO_LE; j++) {
6414 if (!(pfomask & (1 << j)))
6416 if (j == PFO_Z || j == PFO_S)
6419 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6420 fprintf(fout, " cond_%s = %s;\n",
6421 parsed_flag_op_names[j], buf1);
6422 pfomask &= ~(1 << j);
6429 assert_operand_cnt(2);
6430 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6431 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6432 if (po->op == OP_SBB
6433 && IS(po->operand[0].name, po->operand[1].name))
6435 // avoid use of unitialized var
6436 fprintf(fout, " %s = -cond_c;", buf1);
6437 // carry remains what it was
6438 pfomask &= ~(1 << PFO_C);
6441 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6442 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6444 output_std_flags(fout, po, &pfomask, buf1);
6445 last_arith_dst = &po->operand[0];
6446 delayed_flag_op = NULL;
6450 assert_operand_cnt(2);
6451 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6452 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6453 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6455 output_std_flags(fout, po, &pfomask, buf1);
6456 last_arith_dst = &po->operand[0];
6457 delayed_flag_op = NULL;
6458 strcat(g_comment, " bsf");
6462 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6463 for (j = 0; j <= PFO_LE; j++) {
6464 if (!(pfomask & (1 << j)))
6466 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6469 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6470 fprintf(fout, " cond_%s = %s;\n",
6471 parsed_flag_op_names[j], buf1);
6472 pfomask &= ~(1 << j);
6478 if (pfomask & (1 << PFO_C))
6479 // carry is unaffected by inc/dec.. wtf?
6480 ferr(po, "carry propagation needed\n");
6482 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6483 if (po->operand[0].type == OPT_REG) {
6484 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6485 fprintf(fout, " %s%s;", buf1, buf2);
6488 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6489 fprintf(fout, " %s %s= 1;", buf1, buf2);
6491 output_std_flags(fout, po, &pfomask, buf1);
6492 last_arith_dst = &po->operand[0];
6493 delayed_flag_op = NULL;
6497 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6498 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6499 fprintf(fout, " %s = -%s%s;", buf1,
6500 lmod_cast_s(po, po->operand[0].lmod), buf2);
6501 last_arith_dst = &po->operand[0];
6502 delayed_flag_op = NULL;
6503 if (pfomask & (1 << PFO_C)) {
6504 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6505 pfomask &= ~(1 << PFO_C);
6510 if (po->operand_cnt == 2) {
6511 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6514 if (po->operand_cnt == 3)
6515 ferr(po, "TODO imul3\n");
6518 assert_operand_cnt(1);
6519 switch (po->operand[0].lmod) {
6521 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6522 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6523 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6524 fprintf(fout, " edx = tmp64 >> 32;\n");
6525 fprintf(fout, " eax = tmp64;");
6528 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6529 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6530 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6534 ferr(po, "TODO: unhandled mul type\n");
6537 last_arith_dst = NULL;
6538 delayed_flag_op = NULL;
6543 assert_operand_cnt(1);
6544 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6545 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6546 po->op == OP_IDIV));
6547 switch (po->operand[0].lmod) {
6549 if (po->flags & OPF_32BIT)
6550 snprintf(buf2, sizeof(buf2), "%seax", cast);
6552 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6553 snprintf(buf2, sizeof(buf2), "%stmp64",
6554 (po->op == OP_IDIV) ? "(s64)" : "");
6556 if (po->operand[0].type == OPT_REG
6557 && po->operand[0].reg == xDX)
6559 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6560 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6563 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6564 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6568 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6569 snprintf(buf2, sizeof(buf2), "%stmp",
6570 (po->op == OP_IDIV) ? "(s32)" : "");
6571 if (po->operand[0].type == OPT_REG
6572 && po->operand[0].reg == xDX)
6574 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6576 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6580 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6582 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6585 strcat(g_comment, " div16");
6588 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6590 last_arith_dst = NULL;
6591 delayed_flag_op = NULL;
6596 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6598 for (j = 0; j < 8; j++) {
6599 if (pfomask & (1 << j)) {
6600 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6601 fprintf(fout, " cond_%s = %s;",
6602 parsed_flag_op_names[j], buf1);
6609 last_arith_dst = NULL;
6610 delayed_flag_op = po;
6614 // SETcc - should already be handled
6617 // note: we reuse OP_Jcc for SETcc, only flags differ
6619 fprintf(fout, "\n goto %s;", po->operand[0].name);
6623 fprintf(fout, " if (ecx == 0)\n");
6624 fprintf(fout, " goto %s;", po->operand[0].name);
6625 strcat(g_comment, " jecxz");
6629 fprintf(fout, " if (--ecx != 0)\n");
6630 fprintf(fout, " goto %s;", po->operand[0].name);
6631 strcat(g_comment, " loop");
6635 assert_operand_cnt(1);
6636 last_arith_dst = NULL;
6637 delayed_flag_op = NULL;
6639 if (po->operand[0].type == OPT_REGMEM) {
6640 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6643 ferr(po, "parse failure for jmp '%s'\n",
6644 po->operand[0].name);
6645 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6648 else if (po->operand[0].type != OPT_LABEL)
6649 ferr(po, "unhandled jmp type\n");
6651 fprintf(fout, " goto %s;", po->operand[0].name);
6655 assert_operand_cnt(1);
6657 my_assert_not(pp, NULL);
6660 if (po->flags & OPF_CC) {
6661 // we treat conditional branch to another func
6662 // (yes such code exists..) as conditional tailcall
6664 fprintf(fout, " {\n");
6667 if (pp->is_fptr && !pp->is_arg) {
6668 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6669 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6671 if (pp->is_unresolved)
6672 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6673 buf3, asmfn, po->asmln, pp->name);
6676 fprintf(fout, "%s", buf3);
6677 if (strstr(pp->ret_type.name, "int64")) {
6678 if (po->flags & OPF_TAIL)
6679 ferr(po, "int64 and tail?\n");
6680 fprintf(fout, "tmp64 = ");
6682 else if (!IS(pp->ret_type.name, "void")) {
6683 if (po->flags & OPF_TAIL) {
6684 if (regmask_ret & mxAX) {
6685 fprintf(fout, "return ");
6686 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6687 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6689 else if (regmask_ret & mxST0)
6690 ferr(po, "float tailcall\n");
6692 else if (po->regmask_dst & mxAX) {
6693 fprintf(fout, "eax = ");
6694 if (pp->ret_type.is_ptr)
6695 fprintf(fout, "(u32)");
6697 else if (po->regmask_dst & mxST0) {
6698 ferr_assert(po, po->flags & OPF_FPUSH);
6699 if (need_float_stack)
6700 fprintf(fout, "f_st[--f_stp & 7] = ");
6702 fprintf(fout, "f_st0 = ");
6706 if (pp->name[0] == 0)
6707 ferr(po, "missing pp->name\n");
6708 fprintf(fout, "%s%s(", pp->name,
6709 pp->has_structarg ? "_sa" : "");
6711 if (po->flags & OPF_ATAIL) {
6712 if (pp->argc_stack != g_func_pp->argc_stack
6713 || (pp->argc_stack > 0
6714 && pp->is_stdcall != g_func_pp->is_stdcall))
6715 ferr(po, "incompatible tailcall\n");
6716 if (g_func_pp->has_retreg)
6717 ferr(po, "TODO: retreg+tailcall\n");
6719 for (arg = j = 0; arg < pp->argc; arg++) {
6721 fprintf(fout, ", ");
6724 if (pp->arg[arg].type.is_ptr)
6725 snprintf(cast, sizeof(cast), "(%s)",
6726 pp->arg[arg].type.name);
6728 if (pp->arg[arg].reg != NULL) {
6729 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6733 for (; j < g_func_pp->argc; j++)
6734 if (g_func_pp->arg[j].reg == NULL)
6736 fprintf(fout, "%sa%d", cast, j + 1);
6741 for (arg = 0; arg < pp->argc; arg++) {
6743 fprintf(fout, ", ");
6746 if (pp->arg[arg].type.is_ptr)
6747 snprintf(cast, sizeof(cast), "(%s)",
6748 pp->arg[arg].type.name);
6750 if (pp->arg[arg].reg != NULL) {
6751 if (pp->arg[arg].type.is_retreg)
6752 fprintf(fout, "&%s", pp->arg[arg].reg);
6754 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6759 tmp_op = pp->arg[arg].datap;
6761 ferr(po, "parsed_op missing for arg%d\n", arg);
6763 if (tmp_op->flags & OPF_VAPUSH) {
6764 fprintf(fout, "ap");
6766 else if (tmp_op->p_argpass != 0) {
6767 fprintf(fout, "a%d", tmp_op->p_argpass);
6769 else if (tmp_op->p_argnum != 0) {
6770 fprintf(fout, "%s%s", cast,
6771 saved_arg_name(buf1, sizeof(buf1),
6772 tmp_op->p_arggrp, tmp_op->p_argnum));
6776 out_src_opr(buf1, sizeof(buf1),
6777 tmp_op, &tmp_op->operand[0], cast, 0));
6781 fprintf(fout, ");");
6783 if (strstr(pp->ret_type.name, "int64")) {
6784 fprintf(fout, "\n");
6785 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
6786 fprintf(fout, "%seax = tmp64;", buf3);
6789 if (pp->is_unresolved) {
6790 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
6792 strcat(g_comment, buf2);
6795 if (po->flags & OPF_TAIL) {
6797 if (i == opcnt - 1 || pp->is_noreturn)
6799 else if (IS(pp->ret_type.name, "void"))
6801 else if (!(regmask_ret & (1 << xAX)))
6803 // else already handled as 'return f()'
6806 fprintf(fout, "\n%sreturn;", buf3);
6807 strcat(g_comment, " ^ tailcall");
6810 strcat(g_comment, " tailcall");
6812 if ((regmask_ret & (1 << xAX))
6813 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
6815 ferr(po, "int func -> void func tailcall?\n");
6818 if (pp->is_noreturn)
6819 strcat(g_comment, " noreturn");
6820 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
6821 strcat(g_comment, " argframe");
6822 if (po->flags & OPF_CC)
6823 strcat(g_comment, " cond");
6825 if (po->flags & OPF_CC)
6826 fprintf(fout, "\n }");
6828 delayed_flag_op = NULL;
6829 last_arith_dst = NULL;
6833 if (g_func_pp->is_vararg)
6834 fprintf(fout, " va_end(ap);\n");
6835 if (g_func_pp->has_retreg) {
6836 for (arg = 0; arg < g_func_pp->argc; arg++)
6837 if (g_func_pp->arg[arg].type.is_retreg)
6838 fprintf(fout, " *r_%s = %s;\n",
6839 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
6842 if (regmask_ret & mxST0) {
6843 fprintf(fout, " return %s;", float_st0);
6845 else if (!(regmask_ret & mxAX)) {
6846 if (i != opcnt - 1 || label_pending)
6847 fprintf(fout, " return;");
6849 else if (g_func_pp->ret_type.is_ptr) {
6850 fprintf(fout, " return (%s)eax;",
6851 g_func_pp->ret_type.name);
6853 else if (IS(g_func_pp->ret_type.name, "__int64"))
6854 fprintf(fout, " return ((u64)edx << 32) | eax;");
6856 fprintf(fout, " return eax;");
6858 last_arith_dst = NULL;
6859 delayed_flag_op = NULL;
6863 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6864 if (po->p_argnum != 0) {
6865 // special case - saved func arg
6866 fprintf(fout, " %s = %s;",
6867 saved_arg_name(buf2, sizeof(buf2),
6868 po->p_arggrp, po->p_argnum), buf1);
6871 else if (po->flags & OPF_RSAVE) {
6872 fprintf(fout, " s_%s = %s;", buf1, buf1);
6875 else if (po->flags & OPF_PPUSH) {
6877 ferr_assert(po, tmp_op != NULL);
6878 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
6879 fprintf(fout, " pp_%s = %s;", buf2, buf1);
6882 else if (g_func_pp->is_userstack) {
6883 fprintf(fout, " *(--esp) = %s;", buf1);
6886 if (!(g_ida_func_attr & IDAFA_NORETURN))
6887 ferr(po, "stray push encountered\n");
6892 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6893 if (po->flags & OPF_RSAVE) {
6894 fprintf(fout, " %s = s_%s;", buf1, buf1);
6897 else if (po->flags & OPF_PPUSH) {
6898 // push/pop graph / non-const
6899 ferr_assert(po, po->datap == NULL);
6900 fprintf(fout, " %s = pp_%s;", buf1, buf1);
6903 else if (po->datap != NULL) {
6906 fprintf(fout, " %s = %s;", buf1,
6907 out_src_opr(buf2, sizeof(buf2),
6908 tmp_op, &tmp_op->operand[0],
6909 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6912 else if (g_func_pp->is_userstack) {
6913 fprintf(fout, " %s = *esp++;", buf1);
6917 ferr(po, "stray pop encountered\n");
6927 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6928 fprintf(fout, " tmp64 = (s64)tmp64 %s= LOBYTE(ecx);\n",
6929 po->op == OPP_ALLSHL ? "<<" : ">>");
6930 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
6931 strcat(g_comment, po->op == OPP_ALLSHL
6932 ? " allshl" : " allshr");
6937 if (need_float_stack) {
6938 out_src_opr_float(buf1, sizeof(buf1),
6939 po, &po->operand[0], 1);
6940 if (po->regmask_src & mxSTa) {
6941 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
6945 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
6948 if (po->flags & OPF_FSHIFT)
6949 fprintf(fout, " f_st1 = f_st0;");
6950 if (po->operand[0].type == OPT_REG
6951 && po->operand[0].reg == xST0)
6953 strcat(g_comment, " fld st");
6956 fprintf(fout, " f_st0 = %s;",
6957 out_src_opr_float(buf1, sizeof(buf1),
6958 po, &po->operand[0], 0));
6960 strcat(g_comment, " fld");
6964 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6965 lmod_cast(po, po->operand[0].lmod, 1), 0);
6966 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
6967 if (need_float_stack) {
6968 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
6971 if (po->flags & OPF_FSHIFT)
6972 fprintf(fout, " f_st1 = f_st0;");
6973 fprintf(fout, " f_st0 = %s;", buf2);
6975 strcat(g_comment, " fild");
6979 if (need_float_stack)
6980 fprintf(fout, " f_st[--f_stp & 7] = ");
6982 if (po->flags & OPF_FSHIFT)
6983 fprintf(fout, " f_st1 = f_st0;");
6984 fprintf(fout, " f_st0 = ");
6986 switch (po->operand[0].val) {
6987 case X87_CONST_1: fprintf(fout, "1.0;"); break;
6988 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
6989 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
6990 default: ferr(po, "TODO\n"); break;
6995 dead_dst = po->operand[0].type == OPT_REG
6996 && po->operand[0].reg == xST0;
6998 fprintf(fout, " %s = %s;",
6999 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7000 need_float_stack), float_st0);
7002 if (po->flags & OPF_FSHIFT) {
7003 if (need_float_stack)
7004 fprintf(fout, " f_stp++;");
7006 fprintf(fout, " f_st0 = f_st1;");
7008 if (dead_dst && !(po->flags & OPF_FSHIFT))
7011 strcat(g_comment, " fst");
7015 fprintf(fout, " %s = %s%s;",
7016 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7017 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7018 if (po->flags & OPF_FSHIFT) {
7019 if (need_float_stack)
7020 fprintf(fout, " f_stp++;");
7022 fprintf(fout, " f_st0 = f_st1;");
7024 strcat(g_comment, " fist");
7031 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7033 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7035 dead_dst = (po->flags & OPF_FPOP)
7036 && po->operand[0].type == OPT_REG
7037 && po->operand[0].reg == xST0;
7039 case OP_FADD: j = '+'; break;
7040 case OP_FDIV: j = '/'; break;
7041 case OP_FMUL: j = '*'; break;
7042 case OP_FSUB: j = '-'; break;
7043 default: j = 'x'; break;
7045 if (need_float_stack) {
7047 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7048 if (po->flags & OPF_FSHIFT)
7049 fprintf(fout, " f_stp++;");
7052 if (po->flags & OPF_FSHIFT) {
7053 // note: assumes only 2 regs handled
7055 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7057 fprintf(fout, " f_st0 = f_st1;");
7060 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7062 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7067 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7069 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7071 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7073 dead_dst = (po->flags & OPF_FPOP)
7074 && po->operand[0].type == OPT_REG
7075 && po->operand[0].reg == xST0;
7076 j = po->op == OP_FDIVR ? '/' : '-';
7077 if (need_float_stack) {
7079 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7080 if (po->flags & OPF_FSHIFT)
7081 fprintf(fout, " f_stp++;");
7084 if (po->flags & OPF_FSHIFT) {
7086 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7088 fprintf(fout, " f_st0 = f_st1;");
7091 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7093 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7101 case OP_FIADD: j = '+'; break;
7102 case OP_FIDIV: j = '/'; break;
7103 case OP_FIMUL: j = '*'; break;
7104 case OP_FISUB: j = '-'; break;
7105 default: j = 'x'; break;
7107 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7109 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7110 lmod_cast(po, po->operand[0].lmod, 1), 0));
7115 fprintf(fout, " %s = %s %c %s;", float_st0,
7116 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7118 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7123 ferr_assert(po, po->datap != NULL);
7124 mask = (long)po->datap & 0xffff;
7125 z_check = ((long)po->datap >> 16) & 1;
7126 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7128 if (mask == 0x0100) { // C0 -> <
7129 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7132 else if (mask == 0x4000) { // C3 -> =
7133 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7136 else if (mask == 0x4100) { // C3, C0
7138 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7140 strcat(g_comment, " z_chk_det");
7143 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7144 "(%s < %s ? 0x0100 : 0);",
7145 float_st0, buf1, float_st0, buf1);
7149 ferr(po, "unhandled sw mask: %x\n", mask);
7150 if (po->flags & OPF_FSHIFT) {
7151 if (need_float_stack)
7152 fprintf(fout, " f_stp++;");
7154 fprintf(fout, " f_st0 = f_st1;");
7160 fprintf(fout, " %s = f_sw;",
7161 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7165 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7169 fprintf(fout, " %s = cos%s(%s);", float_st0,
7170 need_double ? "" : "f", float_st0);
7174 if (need_float_stack) {
7175 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7176 need_double ? "" : "f", float_st1, float_st0);
7177 fprintf(fout, " f_stp++;");
7180 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7181 need_double ? "" : "f");
7186 if (need_float_stack) {
7187 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7188 float_st1, need_double ? "" : "f", float_st0);
7189 fprintf(fout, " f_stp++;");
7192 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7193 need_double ? "" : "f");
7198 fprintf(fout, " %s = sin%s(%s);", float_st0,
7199 need_double ? "" : "f", float_st0);
7203 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7204 need_double ? "" : "f", float_st0);
7208 dead_dst = po->operand[0].type == OPT_REG
7209 && po->operand[0].reg == xST0;
7211 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7213 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7214 float_st0, float_st0, buf1, buf1);
7215 strcat(g_comment, " fxch");
7222 ferr_assert(po, po->flags & OPF_32BIT);
7223 fprintf(fout, " eax = (s32)%s;", float_st0);
7224 if (po->flags & OPF_FSHIFT) {
7225 if (need_float_stack)
7226 fprintf(fout, " f_stp++;");
7228 fprintf(fout, " f_st0 = f_st1;");
7230 strcat(g_comment, " ftol");
7235 strcpy(g_comment, " (emms)");
7240 ferr(po, "unhandled op type %d, flags %x\n",
7245 if (g_comment[0] != 0) {
7246 char *p = g_comment;
7247 while (my_isblank(*p))
7249 fprintf(fout, " // %s", p);
7254 fprintf(fout, "\n");
7256 // some sanity checking
7257 if (po->flags & OPF_REP) {
7258 if (po->op != OP_STOS && po->op != OP_MOVS
7259 && po->op != OP_CMPS && po->op != OP_SCAS)
7260 ferr(po, "unexpected rep\n");
7261 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7262 && (po->op == OP_CMPS || po->op == OP_SCAS))
7263 ferr(po, "cmps/scas with plain rep\n");
7265 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7266 && po->op != OP_CMPS && po->op != OP_SCAS)
7267 ferr(po, "unexpected repz/repnz\n");
7270 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
7272 // see is delayed flag stuff is still valid
7273 if (delayed_flag_op != NULL && delayed_flag_op != po) {
7274 if (is_any_opr_modified(delayed_flag_op, po, 0))
7275 delayed_flag_op = NULL;
7278 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7279 if (is_opr_modified(last_arith_dst, po))
7280 last_arith_dst = NULL;
7286 if (g_stack_fsz && !g_stack_frame_used)
7287 fprintf(fout, " (void)sf;\n");
7289 fprintf(fout, "}\n\n");
7291 gen_x_cleanup(opcnt);
7294 static void gen_x_cleanup(int opcnt)
7298 for (i = 0; i < opcnt; i++) {
7299 struct label_ref *lr, *lr_del;
7301 lr = g_label_refs[i].next;
7302 while (lr != NULL) {
7307 g_label_refs[i].i = -1;
7308 g_label_refs[i].next = NULL;
7310 if (ops[i].op == OP_CALL) {
7312 proto_release(ops[i].pp);
7318 struct func_proto_dep;
7320 struct func_prototype {
7325 int has_ret:3; // -1, 0, 1: unresolved, no, yes
7326 unsigned int dep_resolved:1;
7327 unsigned int is_stdcall:1;
7328 struct func_proto_dep *dep_func;
7330 const struct parsed_proto *pp; // seed pp, if any
7333 struct func_proto_dep {
7335 struct func_prototype *proto;
7336 int regmask_live; // .. at the time of call
7337 unsigned int ret_dep:1; // return from this is caller's return
7340 static struct func_prototype *hg_fp;
7341 static int hg_fp_cnt;
7343 static struct scanned_var {
7345 enum opr_lenmod lmod;
7346 unsigned int is_seeded:1;
7347 unsigned int is_c_str:1;
7348 const struct parsed_proto *pp; // seed pp, if any
7350 static int hg_var_cnt;
7352 static char **hg_refs;
7353 static int hg_ref_cnt;
7355 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7358 static struct func_prototype *hg_fp_add(const char *funcn)
7360 struct func_prototype *fp;
7362 if ((hg_fp_cnt & 0xff) == 0) {
7363 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7364 my_assert_not(hg_fp, NULL);
7365 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7368 fp = &hg_fp[hg_fp_cnt];
7369 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7371 fp->argc_stack = -1;
7377 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7382 for (i = 0; i < fp->dep_func_cnt; i++)
7383 if (IS(fp->dep_func[i].name, name))
7384 return &fp->dep_func[i];
7389 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7392 if (hg_fp_find_dep(fp, name))
7395 if ((fp->dep_func_cnt & 0xff) == 0) {
7396 fp->dep_func = realloc(fp->dep_func,
7397 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7398 my_assert_not(fp->dep_func, NULL);
7399 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7400 sizeof(fp->dep_func[0]) * 0x100);
7402 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7406 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7408 const struct func_prototype *p1 = p1_, *p2 = p2_;
7409 return strcmp(p1->name, p2->name);
7413 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7415 const struct func_prototype *p1 = p1_, *p2 = p2_;
7416 return p1->id - p2->id;
7420 static void hg_ref_add(const char *name)
7422 if ((hg_ref_cnt & 0xff) == 0) {
7423 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7424 my_assert_not(hg_refs, NULL);
7425 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7428 hg_refs[hg_ref_cnt] = strdup(name);
7429 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7433 // recursive register dep pass
7434 // - track saved regs (part 2)
7435 // - try to figure out arg-regs
7436 // - calculate reg deps
7437 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
7438 struct func_prototype *fp, int regmask_save, int regmask_dst,
7439 int *regmask_dep, int *has_ret)
7441 struct func_proto_dep *dep;
7442 struct parsed_op *po;
7443 int from_caller = 0;
7448 for (; i < opcnt; i++)
7450 if (cbits[i >> 3] & (1 << (i & 7)))
7452 cbits[i >> 3] |= (1 << (i & 7));
7456 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
7457 if (po->flags & OPF_RMD)
7460 if (po->btj != NULL) {
7462 for (j = 0; j < po->btj->count; j++) {
7463 check_i(po, po->btj->d[j].bt_i);
7464 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
7465 regmask_save, regmask_dst, regmask_dep, has_ret);
7470 check_i(po, po->bt_i);
7471 if (po->flags & OPF_CJMP) {
7472 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
7473 regmask_save, regmask_dst, regmask_dep, has_ret);
7481 if (po->flags & OPF_FARG)
7482 /* (just calculate register deps) */;
7483 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
7485 reg = po->operand[0].reg;
7486 ferr_assert(po, reg >= 0);
7488 if (po->flags & OPF_RSAVE) {
7489 regmask_save |= 1 << reg;
7492 if (po->flags & OPF_DONE)
7495 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0);
7497 regmask_save |= 1 << reg;
7498 po->flags |= OPF_RMD;
7499 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, OPF_RMD);
7503 else if (po->flags & OPF_RMD)
7505 else if (po->op == OP_CALL) {
7506 po->regmask_dst |= 1 << xAX;
7508 dep = hg_fp_find_dep(fp, po->operand[0].name);
7510 dep->regmask_live = regmask_save | regmask_dst;
7512 else if (po->op == OP_RET) {
7513 if (po->operand_cnt > 0) {
7515 if (fp->argc_stack >= 0
7516 && fp->argc_stack != po->operand[0].val / 4)
7517 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
7518 fp->argc_stack = po->operand[0].val / 4;
7522 // if has_ret is 0, there is uninitialized eax path,
7523 // which means it's most likely void func
7524 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
7525 if (po->op == OP_CALL) {
7530 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
7533 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
7536 if (ret != 1 && from_caller) {
7537 // unresolved eax - probably void func
7541 if (j >= 0 && ops[j].op == OP_CALL) {
7542 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
7553 l = regmask_save | regmask_dst;
7554 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7557 l = po->regmask_src & ~l;
7560 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
7561 l, regmask_dst, regmask_save, po->flags);
7564 regmask_dst |= po->regmask_dst;
7566 if (po->flags & OPF_TAIL)
7571 static void gen_hdr(const char *funcn, int opcnt)
7573 int save_arg_vars[MAX_ARG_GRP] = { 0, };
7574 unsigned char cbits[MAX_OPS / 8];
7575 const struct parsed_proto *pp_c;
7576 struct parsed_proto *pp;
7577 struct func_prototype *fp;
7578 struct parsed_op *po;
7579 int regmask_dummy = 0;
7581 int max_bp_offset = 0;
7586 pp_c = proto_parse(g_fhdr, funcn, 1);
7588 // already in seed, will add to hg_fp later
7591 fp = hg_fp_add(funcn);
7593 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7594 g_stack_frame_used = 0;
7597 // - resolve all branches
7598 // - parse calls with labels
7599 resolve_branches_parse_calls(opcnt);
7602 // - handle ebp/esp frame, remove ops related to it
7603 scan_prologue_epilogue(opcnt);
7606 // - remove dead labels
7608 for (i = 0; i < opcnt; i++)
7610 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7616 if (po->flags & (OPF_RMD|OPF_DONE))
7619 if (po->op == OP_CALL) {
7620 if (po->operand[0].type == OPT_LABEL)
7621 hg_fp_add_dep(fp, opr_name(po, 0));
7622 else if (po->pp != NULL)
7623 hg_fp_add_dep(fp, po->pp->name);
7628 // - remove dead labels
7629 // - handle push <const>/pop pairs
7630 for (i = 0; i < opcnt; i++)
7632 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7638 if (po->flags & (OPF_RMD|OPF_DONE))
7641 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
7642 scan_for_pop_const(i, opcnt, i + opcnt * 13);
7646 // - process trivial calls
7647 for (i = 0; i < opcnt; i++)
7650 if (po->flags & (OPF_RMD|OPF_DONE))
7653 if (po->op == OP_CALL)
7655 pp = process_call_early(i, opcnt, &j);
7657 if (!(po->flags & OPF_ATAIL))
7658 // since we know the args, try to collect them
7659 if (collect_call_args_early(po, i, pp, ®mask_dummy) != 0)
7665 // commit esp adjust
7666 if (ops[j].op != OP_POP)
7667 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
7669 for (l = 0; l < pp->argc_stack; l++)
7670 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
7674 po->flags |= OPF_DONE;
7680 // - track saved regs (simple)
7682 for (i = 0; i < opcnt; i++)
7685 if (po->flags & (OPF_RMD|OPF_DONE))
7688 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7689 && po->operand[0].reg != xCX)
7691 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
7693 // regmask_save |= 1 << po->operand[0].reg; // do it later
7694 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
7695 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
7698 else if (po->op == OP_CALL)
7700 pp = process_call(i, opcnt);
7702 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
7703 // since we know the args, collect them
7704 ret = collect_call_args(po, i, pp, ®mask_dummy, save_arg_vars,
7711 memset(cbits, 0, sizeof(cbits));
7715 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
7717 // find unreachable code - must be fixed in IDA
7718 for (i = 0; i < opcnt; i++)
7720 if (cbits[i >> 3] & (1 << (i & 7)))
7723 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
7724 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
7726 // the compiler sometimes still generates code after
7727 // noreturn OS functions
7730 if (ops[i].op != OP_NOP)
7731 ferr(&ops[i], "unreachable code\n");
7734 for (i = 0; i < g_eqcnt; i++) {
7735 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
7736 max_bp_offset = g_eqs[i].offset;
7739 if (fp->argc_stack < 0) {
7740 max_bp_offset = (max_bp_offset + 3) & ~3;
7741 fp->argc_stack = max_bp_offset / 4;
7742 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
7746 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
7747 fp->has_ret = has_ret;
7749 printf("// has_ret %d, regmask_dep %x\n",
7750 fp->has_ret, fp->regmask_dep);
7751 output_hdr_fp(stdout, fp, 1);
7752 if (IS(funcn, "sub_10007F72")) exit(1);
7755 gen_x_cleanup(opcnt);
7758 static void hg_fp_resolve_deps(struct func_prototype *fp)
7760 struct func_prototype fp_s;
7764 // this thing is recursive, so mark first..
7765 fp->dep_resolved = 1;
7767 for (i = 0; i < fp->dep_func_cnt; i++) {
7768 strcpy(fp_s.name, fp->dep_func[i].name);
7769 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7770 sizeof(hg_fp[0]), hg_fp_cmp_name);
7771 if (fp->dep_func[i].proto != NULL) {
7772 if (!fp->dep_func[i].proto->dep_resolved)
7773 hg_fp_resolve_deps(fp->dep_func[i].proto);
7775 dep = ~fp->dep_func[i].regmask_live
7776 & fp->dep_func[i].proto->regmask_dep;
7777 fp->regmask_dep |= dep;
7778 // printf("dep %s %s |= %x\n", fp->name,
7779 // fp->dep_func[i].name, dep);
7781 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
7782 fp->has_ret = fp->dep_func[i].proto->has_ret;
7787 // make all thiscall/edx arg functions referenced from .data fastcall
7788 static void do_func_refs_from_data(void)
7790 struct func_prototype *fp, fp_s;
7793 for (i = 0; i < hg_ref_cnt; i++) {
7794 strcpy(fp_s.name, hg_refs[i]);
7795 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7796 sizeof(hg_fp[0]), hg_fp_cmp_name);
7800 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
7801 fp->regmask_dep |= mxCX | mxDX;
7805 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7808 const struct parsed_proto *pp;
7809 char *p, namebuf[NAMELEN];
7815 for (; count > 0; count--, fp++) {
7816 if (fp->has_ret == -1)
7817 fprintf(fout, "// ret unresolved\n");
7819 fprintf(fout, "// dep:");
7820 for (j = 0; j < fp->dep_func_cnt; j++) {
7821 fprintf(fout, " %s/", fp->dep_func[j].name);
7822 if (fp->dep_func[j].proto != NULL)
7823 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
7824 fp->dep_func[j].proto->has_ret);
7826 fprintf(fout, "\n");
7829 p = strchr(fp->name, '@');
7831 memcpy(namebuf, fp->name, p - fp->name);
7832 namebuf[p - fp->name] = 0;
7840 pp = proto_parse(g_fhdr, name, 1);
7841 if (pp != NULL && pp->is_include)
7844 if (fp->pp != NULL) {
7845 // part of seed, output later
7849 regmask_dep = fp->regmask_dep;
7850 argc_normal = fp->argc_stack;
7852 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
7853 (fp->has_ret ? "int" : "void"));
7854 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
7855 && (regmask_dep & ~mxCX) == 0)
7857 fprintf(fout, "/*__thiscall*/ ");
7861 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
7862 && (regmask_dep & ~(mxCX | mxDX)) == 0)
7864 fprintf(fout, " __fastcall ");
7865 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
7871 else if (regmask_dep && !fp->is_stdcall) {
7872 fprintf(fout, "/*__usercall*/ ");
7874 else if (regmask_dep) {
7875 fprintf(fout, "/*__userpurge*/ ");
7877 else if (fp->is_stdcall)
7878 fprintf(fout, " __stdcall ");
7880 fprintf(fout, " __cdecl ");
7882 fprintf(fout, "%s(", name);
7885 for (j = 0; j < xSP; j++) {
7886 if (regmask_dep & (1 << j)) {
7889 fprintf(fout, ", ");
7891 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
7893 fprintf(fout, "int");
7894 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
7898 for (j = 0; j < argc_normal; j++) {
7901 fprintf(fout, ", ");
7902 if (fp->pp != NULL) {
7903 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
7904 if (!fp->pp->arg[arg - 1].type.is_ptr)
7908 fprintf(fout, "int ");
7909 fprintf(fout, "a%d", arg);
7912 fprintf(fout, ");\n");
7916 static void output_hdr(FILE *fout)
7918 static const char *lmod_c_names[] = {
7919 [OPLM_UNSPEC] = "???",
7920 [OPLM_BYTE] = "uint8_t",
7921 [OPLM_WORD] = "uint16_t",
7922 [OPLM_DWORD] = "uint32_t",
7923 [OPLM_QWORD] = "uint64_t",
7925 const struct scanned_var *var;
7926 struct func_prototype *fp;
7927 char line[256] = { 0, };
7931 // add stuff from headers
7932 for (i = 0; i < pp_cache_size; i++) {
7933 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
7934 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
7936 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
7937 fp = hg_fp_add(name);
7938 fp->pp = &pp_cache[i];
7939 fp->argc_stack = fp->pp->argc_stack;
7940 fp->is_stdcall = fp->pp->is_stdcall;
7941 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
7942 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
7946 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
7947 for (i = 0; i < hg_fp_cnt; i++)
7948 hg_fp_resolve_deps(&hg_fp[i]);
7950 // adjust functions referenced from data segment
7951 do_func_refs_from_data();
7953 // note: messes up .proto ptr, don't use
7954 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
7957 for (i = 0; i < hg_var_cnt; i++) {
7960 if (var->pp != NULL)
7963 else if (var->is_c_str)
7964 fprintf(fout, "extern %-8s %s[];", "char", var->name);
7966 fprintf(fout, "extern %-8s %s;",
7967 lmod_c_names[var->lmod], var->name);
7970 fprintf(fout, " // seeded");
7971 fprintf(fout, "\n");
7974 fprintf(fout, "\n");
7976 // output function prototypes
7977 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
7980 fprintf(fout, "\n// - seed -\n");
7983 while (fgets(line, sizeof(line), g_fhdr))
7984 fwrite(line, 1, strlen(line), fout);
7987 // '=' needs special treatment
7989 static char *next_word_s(char *w, size_t wsize, char *s)
7996 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
7998 for (i = 1; i < wsize - 1; i++) {
8000 printf("warning: missing closing quote: \"%s\"\n", s);
8009 for (; i < wsize - 1; i++) {
8010 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8016 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8017 printf("warning: '%s' truncated\n", w);
8022 static int cmpstringp(const void *p1, const void *p2)
8024 return strcmp(*(char * const *)p1, *(char * const *)p2);
8027 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8032 if (strstr(p, "..."))
8033 // unable to determine, assume needed
8036 if (*p == '.') // .text, .data, ...
8037 // ref from other data or non-function -> no
8040 p2 = strpbrk(p, "+:\r\n\x18");
8043 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8044 // referenced from removed code
8050 static int ida_xrefs_show_need(FILE *fasm, char *p,
8051 char **rlist, int rlist_len)
8057 p = strrchr(p, ';');
8058 if (p != NULL && *p == ';' && IS_START(p + 2, "DATA XREF: ")) {
8060 if (is_xref_needed(p, rlist, rlist_len))
8067 if (!my_fgets(line, sizeof(line), fasm))
8069 // non-first line is always indented
8070 if (!my_isblank(line[0]))
8073 // should be no content, just comment
8078 p = strrchr(p, ';');
8080 // it's printed once, but no harm to check again
8081 if (IS_START(p, "DATA XREF: "))
8084 if (is_xref_needed(p, rlist, rlist_len)) {
8089 fseek(fasm, pos, SEEK_SET);
8093 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8095 struct scanned_var *var;
8096 char line[256] = { 0, };
8105 // skip to next data section
8106 while (my_fgets(line, sizeof(line), fasm))
8111 if (*p == 0 || *p == ';')
8114 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8115 if (*p == 0 || *p == ';')
8118 if (*p != 's' || !IS_START(p, "segment para public"))
8124 if (p == NULL || !IS_START(p, "segment para public"))
8128 if (!IS_START(p, "'DATA'"))
8132 while (my_fgets(line, sizeof(line), fasm))
8137 no_identifier = my_isblank(*p);
8140 if (*p == 0 || *p == ';')
8143 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8144 words[wordc][0] = 0;
8145 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8146 if (*p == 0 || *p == ';') {
8152 if (wordc == 2 && IS(words[1], "ends"))
8157 if (no_identifier) {
8158 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8159 hg_ref_add(words[2]);
8163 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8164 // when this starts, we don't need anything from this section
8168 // check refs comment(s)
8169 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8172 if ((hg_var_cnt & 0xff) == 0) {
8173 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8174 * (hg_var_cnt + 0x100));
8175 my_assert_not(hg_vars, NULL);
8176 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8179 var = &hg_vars[hg_var_cnt++];
8180 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8182 // maybe already in seed header?
8183 var->pp = proto_parse(g_fhdr, var->name, 1);
8184 if (var->pp != NULL) {
8185 if (var->pp->is_fptr) {
8186 var->lmod = OPLM_DWORD;
8189 else if (var->pp->is_func)
8191 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8192 aerr("unhandled C type '%s' for '%s'\n",
8193 var->pp->type.name, var->name);
8199 if (IS(words[1], "dd")) {
8200 var->lmod = OPLM_DWORD;
8201 if (wordc >= 4 && IS(words[2], "offset"))
8202 hg_ref_add(words[3]);
8204 else if (IS(words[1], "dw"))
8205 var->lmod = OPLM_WORD;
8206 else if (IS(words[1], "db")) {
8207 var->lmod = OPLM_BYTE;
8208 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8209 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8213 else if (IS(words[1], "dq"))
8214 var->lmod = OPLM_QWORD;
8215 //else if (IS(words[1], "dt"))
8217 aerr("type '%s' not known\n", words[1]);
8225 static void set_label(int i, const char *name)
8231 p = strchr(name, ':');
8235 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8236 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8237 g_labels[i] = realloc(g_labels[i], len + 1);
8238 my_assert_not(g_labels[i], NULL);
8239 memcpy(g_labels[i], name, len);
8240 g_labels[i][len] = 0;
8249 static struct chunk_item *func_chunks;
8250 static int func_chunk_cnt;
8251 static int func_chunk_alloc;
8253 static void add_func_chunk(FILE *fasm, const char *name, int line)
8255 if (func_chunk_cnt >= func_chunk_alloc) {
8256 func_chunk_alloc *= 2;
8257 func_chunks = realloc(func_chunks,
8258 func_chunk_alloc * sizeof(func_chunks[0]));
8259 my_assert_not(func_chunks, NULL);
8261 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8262 func_chunks[func_chunk_cnt].name = strdup(name);
8263 func_chunks[func_chunk_cnt].asmln = line;
8267 static int cmp_chunks(const void *p1, const void *p2)
8269 const struct chunk_item *c1 = p1, *c2 = p2;
8270 return strcmp(c1->name, c2->name);
8273 static void scan_ahead(FILE *fasm)
8283 oldpos = ftell(fasm);
8286 while (my_fgets(line, sizeof(line), fasm))
8297 // get rid of random tabs
8298 for (i = 0; line[i] != 0; i++)
8299 if (line[i] == '\t')
8302 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8305 next_word(words[0], sizeof(words[0]), p);
8306 if (words[0][0] == 0)
8307 aerr("missing name for func chunk?\n");
8309 add_func_chunk(fasm, words[0], asmln);
8311 else if (IS_START(p, "; sctend"))
8317 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8318 words[wordc][0] = 0;
8319 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8320 if (*p == 0 || *p == ';') {
8326 if (wordc == 2 && IS(words[1], "ends"))
8330 fseek(fasm, oldpos, SEEK_SET);
8334 int main(int argc, char *argv[])
8336 FILE *fout, *fasm, *frlist;
8337 struct parsed_data *pd = NULL;
8339 char **rlist = NULL;
8341 int rlist_alloc = 0;
8342 int func_chunks_used = 0;
8343 int func_chunks_sorted = 0;
8344 int func_chunk_i = -1;
8345 long func_chunk_ret = 0;
8346 int func_chunk_ret_ln = 0;
8347 int scanned_ahead = 0;
8349 char words[20][256];
8350 enum opr_lenmod lmod;
8351 char *sctproto = NULL;
8353 int pending_endp = 0;
8355 int skip_warned = 0;
8368 for (arg = 1; arg < argc; arg++) {
8369 if (IS(argv[arg], "-v"))
8371 else if (IS(argv[arg], "-rf"))
8372 g_allow_regfunc = 1;
8373 else if (IS(argv[arg], "-m"))
8375 else if (IS(argv[arg], "-hdr"))
8376 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8381 if (argc < arg + 3) {
8382 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8383 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8385 " -hdr - header generation mode\n"
8386 " -rf - allow unannotated indirect calls\n"
8387 " -m - allow multiple .text sections\n"
8388 "[rlist] is a file with function names to skip,"
8396 asmfn = argv[arg++];
8397 fasm = fopen(asmfn, "r");
8398 my_assert_not(fasm, NULL);
8400 hdrfn = argv[arg++];
8401 g_fhdr = fopen(hdrfn, "r");
8402 my_assert_not(g_fhdr, NULL);
8405 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8406 my_assert_not(rlist, NULL);
8407 // needs special handling..
8408 rlist[rlist_len++] = "__alloca_probe";
8410 func_chunk_alloc = 32;
8411 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8412 my_assert_not(func_chunks, NULL);
8414 memset(words, 0, sizeof(words));
8416 for (; arg < argc; arg++) {
8417 frlist = fopen(argv[arg], "r");
8418 my_assert_not(frlist, NULL);
8420 while (my_fgets(line, sizeof(line), frlist)) {
8422 if (*p == 0 || *p == ';')
8425 if (IS_START(p, "#if 0")
8426 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
8430 else if (IS_START(p, "#endif"))
8437 p = next_word(words[0], sizeof(words[0]), p);
8438 if (words[0][0] == 0)
8441 if (rlist_len >= rlist_alloc) {
8442 rlist_alloc = rlist_alloc * 2 + 64;
8443 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
8444 my_assert_not(rlist, NULL);
8446 rlist[rlist_len++] = strdup(words[0]);
8455 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
8457 fout = fopen(argv[arg_out], "w");
8458 my_assert_not(fout, NULL);
8461 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
8462 my_assert_not(g_eqs, NULL);
8464 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
8465 g_label_refs[i].i = -1;
8466 g_label_refs[i].next = NULL;
8470 scan_variables(fasm, rlist, rlist_len);
8472 while (my_fgets(line, sizeof(line), fasm))
8481 // get rid of random tabs
8482 for (i = 0; line[i] != 0; i++)
8483 if (line[i] == '\t')
8488 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
8489 goto do_pending_endp; // eww..
8491 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
8493 static const char *attrs[] = {
8502 // parse IDA's attribute-list comment
8503 g_ida_func_attr = 0;
8506 for (; *p != 0; p = sskip(p)) {
8507 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8508 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8509 g_ida_func_attr |= 1 << i;
8510 p += strlen(attrs[i]);
8514 if (i == ARRAY_SIZE(attrs)) {
8515 anote("unparsed IDA attr: %s\n", p);
8518 if (IS(attrs[i], "fpd=")) {
8519 p = next_word(words[0], sizeof(words[0]), p);
8524 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
8526 static const char *attrs[] = {
8531 // parse manual attribute-list comment
8532 g_sct_func_attr = 0;
8535 for (; *p != 0; p = sskip(p)) {
8536 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8537 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8538 g_sct_func_attr |= 1 << i;
8539 p += strlen(attrs[i]);
8546 // clear_sf=start,len (in dwords)
8547 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
8548 &g_stack_clear_len, &j);
8550 // clear_regmask=<mask>
8551 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
8553 anote("unparsed attr value: %s\n", p);
8558 else if (i == ARRAY_SIZE(attrs)) {
8559 anote("unparsed sct attr: %s\n", p);
8564 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8567 next_word(words[0], sizeof(words[0]), p);
8568 if (words[0][0] == 0)
8569 aerr("missing name for func chunk?\n");
8571 if (!scanned_ahead) {
8572 add_func_chunk(fasm, words[0], asmln);
8573 func_chunks_sorted = 0;
8576 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
8578 if (func_chunk_i >= 0) {
8579 if (func_chunk_i < func_chunk_cnt
8580 && IS(func_chunks[func_chunk_i].name, g_func))
8582 // move on to next chunk
8583 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8585 aerr("seek failed for '%s' chunk #%d\n",
8586 g_func, func_chunk_i);
8587 asmln = func_chunks[func_chunk_i].asmln;
8591 if (func_chunk_ret == 0)
8592 aerr("no return from chunk?\n");
8593 fseek(fasm, func_chunk_ret, SEEK_SET);
8594 asmln = func_chunk_ret_ln;
8600 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
8601 func_chunks_used = 1;
8603 if (IS_START(g_func, "sub_")) {
8604 unsigned long addr = strtoul(p, NULL, 16);
8605 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
8606 if (addr > f_addr && !scanned_ahead) {
8607 //anote("scan_ahead caused by '%s', addr %lx\n",
8611 func_chunks_sorted = 0;
8619 for (i = wordc; i < ARRAY_SIZE(words); i++)
8621 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8622 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8623 if (*p == 0 || *p == ';') {
8628 if (*p != 0 && *p != ';')
8629 aerr("too many words\n");
8631 // alow asm patches in comments
8633 if (IS_START(p, "; sctpatch:")) {
8635 if (*p == 0 || *p == ';')
8637 goto parse_words; // lame
8639 if (IS_START(p, "; sctproto:")) {
8640 sctproto = strdup(p + 11);
8642 else if (IS_START(p, "; sctend")) {
8651 awarn("wordc == 0?\n");
8655 // don't care about this:
8656 if (words[0][0] == '.'
8657 || IS(words[0], "include")
8658 || IS(words[0], "assume") || IS(words[1], "segment")
8659 || IS(words[0], "align"))
8665 // do delayed endp processing to collect switch jumptables
8667 if (in_func && !g_skip_func && !end && wordc >= 2
8668 && ((words[0][0] == 'd' && words[0][2] == 0)
8669 || (words[1][0] == 'd' && words[1][2] == 0)))
8672 if (words[1][0] == 'd' && words[1][2] == 0) {
8674 if (g_func_pd_cnt >= pd_alloc) {
8675 pd_alloc = pd_alloc * 2 + 16;
8676 g_func_pd = realloc(g_func_pd,
8677 sizeof(g_func_pd[0]) * pd_alloc);
8678 my_assert_not(g_func_pd, NULL);
8680 pd = &g_func_pd[g_func_pd_cnt];
8682 memset(pd, 0, sizeof(*pd));
8683 strcpy(pd->label, words[0]);
8684 pd->type = OPT_CONST;
8685 pd->lmod = lmod_from_directive(words[1]);
8691 anote("skipping alignment byte?\n");
8694 lmod = lmod_from_directive(words[0]);
8695 if (lmod != pd->lmod)
8696 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
8699 if (pd->count_alloc < pd->count + wordc) {
8700 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
8701 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
8702 my_assert_not(pd->d, NULL);
8704 for (; i < wordc; i++) {
8705 if (IS(words[i], "offset")) {
8706 pd->type = OPT_OFFSET;
8709 p = strchr(words[i], ',');
8712 if (pd->type == OPT_OFFSET)
8713 pd->d[pd->count].u.label = strdup(words[i]);
8715 pd->d[pd->count].u.val = parse_number(words[i]);
8716 pd->d[pd->count].bt_i = -1;
8722 if (in_func && !g_skip_func) {
8724 gen_hdr(g_func, pi);
8726 gen_func(fout, g_fhdr, g_func, pi);
8731 g_ida_func_attr = 0;
8732 g_sct_func_attr = 0;
8733 g_stack_clear_start = 0;
8734 g_stack_clear_len = 0;
8739 func_chunks_used = 0;
8742 memset(&ops, 0, pi * sizeof(ops[0]));
8747 for (i = 0; i < g_func_pd_cnt; i++) {
8749 if (pd->type == OPT_OFFSET) {
8750 for (j = 0; j < pd->count; j++)
8751 free(pd->d[j].u.label);
8766 if (IS(words[1], "proc")) {
8768 aerr("proc '%s' while in_func '%s'?\n",
8771 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8773 strcpy(g_func, words[0]);
8774 set_label(0, words[0]);
8779 if (IS(words[1], "endp"))
8782 aerr("endp '%s' while not in_func?\n", words[0]);
8783 if (!IS(g_func, words[0]))
8784 aerr("endp '%s' while in_func '%s'?\n",
8787 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
8788 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
8794 if (!g_skip_func && func_chunks_used) {
8795 // start processing chunks
8796 struct chunk_item *ci, key = { g_func, 0 };
8798 func_chunk_ret = ftell(fasm);
8799 func_chunk_ret_ln = asmln;
8800 if (!func_chunks_sorted) {
8801 qsort(func_chunks, func_chunk_cnt,
8802 sizeof(func_chunks[0]), cmp_chunks);
8803 func_chunks_sorted = 1;
8805 ci = bsearch(&key, func_chunks, func_chunk_cnt,
8806 sizeof(func_chunks[0]), cmp_chunks);
8808 aerr("'%s' needs chunks, but none found\n", g_func);
8809 func_chunk_i = ci - func_chunks;
8810 for (; func_chunk_i > 0; func_chunk_i--)
8811 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
8814 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8816 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
8817 asmln = func_chunks[func_chunk_i].asmln;
8825 if (wordc == 2 && IS(words[1], "ends")) {
8829 goto do_pending_endp;
8833 // scan for next text segment
8834 while (my_fgets(line, sizeof(line), fasm)) {
8837 if (*p == 0 || *p == ';')
8840 if (strstr(p, "segment para public 'CODE' use32"))
8847 p = strchr(words[0], ':');
8849 set_label(pi, words[0]);
8853 if (!in_func || g_skip_func) {
8854 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
8856 anote("skipping from '%s'\n", g_labels[pi]);
8860 g_labels[pi] = NULL;
8864 if (wordc > 1 && IS(words[1], "="))
8867 aerr("unhandled equ, wc=%d\n", wordc);
8868 if (g_eqcnt >= eq_alloc) {
8870 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
8871 my_assert_not(g_eqs, NULL);
8874 len = strlen(words[0]);
8875 if (len > sizeof(g_eqs[0].name) - 1)
8876 aerr("equ name too long: %d\n", len);
8877 strcpy(g_eqs[g_eqcnt].name, words[0]);
8879 if (!IS(words[3], "ptr"))
8880 aerr("unhandled equ\n");
8881 if (IS(words[2], "dword"))
8882 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
8883 else if (IS(words[2], "word"))
8884 g_eqs[g_eqcnt].lmod = OPLM_WORD;
8885 else if (IS(words[2], "byte"))
8886 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
8887 else if (IS(words[2], "qword"))
8888 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
8890 aerr("bad lmod: '%s'\n", words[2]);
8892 g_eqs[g_eqcnt].offset = parse_number(words[4]);
8897 if (pi >= ARRAY_SIZE(ops))
8898 aerr("too many ops\n");
8900 parse_op(&ops[pi], words, wordc);
8902 ops[pi].datap = sctproto;
8917 // vim:ts=2:shiftwidth=2:expandtab