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 */
150 // pseudo-ops for lib calls
167 // must be sorted (larger len must be further in enum)
176 #define MAX_EXITS 128
178 #define MAX_OPERANDS 3
181 #define OPR_INIT(type_, lmod_, reg_) \
182 { type_, lmod_, reg_, }
186 enum opr_lenmod lmod;
188 unsigned int is_ptr:1; // pointer in C
189 unsigned int is_array:1; // array in C
190 unsigned int type_from_var:1; // .. in header, sometimes wrong
191 unsigned int size_mismatch:1; // type override differs from C
192 unsigned int size_lt:1; // type override is larger than C
193 unsigned int had_ds:1; // had ds: prefix
194 const struct parsed_proto *pp; // for OPT_LABEL
201 struct parsed_opr operand[MAX_OPERANDS];
204 unsigned char pfo_inv;
205 unsigned char operand_cnt;
206 unsigned char p_argnum; // arg push: altered before call arg #
207 unsigned char p_arggrp; // arg push: arg group # for above
208 unsigned char p_argpass;// arg push: arg of host func
209 short p_argnext;// arg push: same arg pushed elsewhere or -1
210 int regmask_src; // all referensed regs
212 int pfomask; // flagop: parsed_flag_op that can't be delayed
213 int cc_scratch; // scratch storage during analysis
214 int bt_i; // branch target for branches
215 struct parsed_data *btj;// branch targets for jumptables
216 struct parsed_proto *pp;// parsed_proto for OP_CALL
222 // on start: function/data type hint (sctproto)
224 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
225 // OP_PUSH - points to OP_POP in complex push/pop graph
226 // OP_POP - points to OP_PUSH in simple push/pop pair
230 enum opr_lenmod lmod;
237 enum opr_lenmod lmod;
251 struct label_ref *next;
255 IDAFA_BP_FRAME = (1 << 0),
256 IDAFA_LIB_FUNC = (1 << 1),
257 IDAFA_STATIC = (1 << 2),
258 IDAFA_NORETURN = (1 << 3),
259 IDAFA_THUNK = (1 << 4),
260 IDAFA_FPD = (1 << 5),
264 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
265 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
278 // note: limited to 32k due to p_argnext
280 #define MAX_ARG_GRP 2
282 static struct parsed_op ops[MAX_OPS];
283 static struct parsed_equ *g_eqs;
285 static char *g_labels[MAX_OPS];
286 static struct label_ref g_label_refs[MAX_OPS];
287 static const struct parsed_proto *g_func_pp;
288 static struct parsed_data *g_func_pd;
289 static int g_func_pd_cnt;
290 static int g_func_lmods;
291 static char g_func[256];
292 static char g_comment[256];
293 static int g_bp_frame;
294 static int g_sp_frame;
295 static int g_stack_frame_used;
296 static int g_stack_fsz;
297 static int g_ida_func_attr;
298 static int g_sct_func_attr;
299 static int g_stack_clear_start; // in dwords
300 static int g_stack_clear_len;
301 static int g_regmask_init;
302 static int g_skip_func;
303 static int g_allow_regfunc;
304 static int g_quiet_pp;
305 static int g_header_mode;
307 #define ferr(op_, fmt, ...) do { \
308 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
309 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
313 #define fnote(op_, fmt, ...) \
314 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
315 dump_op(op_), ##__VA_ARGS__)
317 #define ferr_assert(op_, cond) do { \
318 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
321 const char *regs_r32[] = {
322 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
323 // not r32, but list here for easy parsing and printing
324 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
325 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
327 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
328 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
329 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
335 xMM0, xMM1, xMM2, xMM3, // mmx
336 xMM4, xMM5, xMM6, xMM7,
337 xST0, xST1, xST2, xST3, // x87
338 xST4, xST5, xST6, xST7,
341 #define mxAX (1 << xAX)
342 #define mxCX (1 << xCX)
343 #define mxDX (1 << xDX)
344 #define mxST0 (1 << xST0)
345 #define mxST1 (1 << xST1)
346 #define mxST1_0 (mxST1 | mxST0)
347 #define mxST7_2 (0xfc << xST0)
348 #define mxSTa (0xff << xST0)
350 // possible basic comparison types (without inversion)
351 enum parsed_flag_op {
355 PFO_BE, // 6 CF=1||ZF=1
359 PFO_LE, // e ZF=1||SF!=OF
362 #define PFOB_O (1 << PFO_O)
363 #define PFOB_C (1 << PFO_C)
364 #define PFOB_Z (1 << PFO_Z)
365 #define PFOB_S (1 << PFO_S)
367 static const char *parsed_flag_op_names[] = {
368 "o", "c", "z", "be", "s", "p", "l", "le"
371 static int char_array_i(const char *array[], size_t len, const char *s)
375 for (i = 0; i < len; i++)
382 static void printf_number(char *buf, size_t buf_size,
383 unsigned long number)
385 // output in C-friendly form
386 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
389 static int check_segment_prefix(const char *s)
391 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
405 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
409 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
411 *reg_lmod = OPLM_QWORD;
415 *reg_lmod = OPLM_DWORD;
418 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
420 *reg_lmod = OPLM_WORD;
423 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
425 *reg_lmod = OPLM_BYTE;
428 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
430 *reg_lmod = OPLM_BYTE;
437 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
439 enum opr_lenmod lmod;
452 while (my_isblank(*s))
454 for (; my_issep(*s); d++, s++)
456 while (my_isblank(*s))
460 // skip '?s:' prefixes
461 if (check_segment_prefix(s))
464 s = next_idt(w, sizeof(w), s);
469 reg = parse_reg(&lmod, w);
471 *regmask |= 1 << reg;
475 if ('0' <= w[0] && w[0] <= '9') {
476 number = parse_number(w);
477 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
481 // probably some label/identifier - pass
484 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
488 strcpy(name, cvtbuf);
493 static int is_reg_in_str(const char *s)
497 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
500 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
501 if (!strncmp(s, regs_r32[i], 3))
507 static const char *parse_stack_el(const char *name, char *extra_reg,
510 const char *p, *p2, *s;
516 if (g_bp_frame || early_try)
519 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
521 if (extra_reg != NULL) {
522 strncpy(extra_reg, name, 3);
527 if (IS_START(p, "ebp+")) {
531 if (p2 != NULL && is_reg_in_str(p)) {
532 if (extra_reg != NULL) {
533 strncpy(extra_reg, p, p2 - p);
534 extra_reg[p2 - p] = 0;
539 if (!('0' <= *p && *p <= '9'))
546 if (!IS_START(name, "esp+"))
552 if (is_reg_in_str(s)) {
553 if (extra_reg != NULL) {
554 strncpy(extra_reg, s, p - s);
555 extra_reg[p - s] = 0;
560 aerr("%s IDA stackvar not set?\n", __func__);
562 if (!('0' <= *s && *s <= '9')) {
563 aerr("%s IDA stackvar offset not set?\n", __func__);
566 if (s[0] == '0' && s[1] == 'x')
569 if (len < sizeof(buf) - 1) {
570 strncpy(buf, s, len);
572 val = strtol(buf, &endp, 16);
573 if (val == 0 || *endp != 0) {
574 aerr("%s num parse fail for '%s'\n", __func__, buf);
583 if ('0' <= *p && *p <= '9')
589 static int guess_lmod_from_name(struct parsed_opr *opr)
591 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
592 opr->lmod = OPLM_DWORD;
595 if (IS_START(opr->name, "word_")) {
596 opr->lmod = OPLM_WORD;
599 if (IS_START(opr->name, "byte_")) {
600 opr->lmod = OPLM_BYTE;
603 if (IS_START(opr->name, "qword_")) {
604 opr->lmod = OPLM_QWORD;
610 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
611 const struct parsed_type *c_type)
613 static const char *dword_types[] = {
614 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
615 "WPARAM", "LPARAM", "UINT", "__int32",
616 "LONG", "HIMC", "BOOL", "size_t",
619 static const char *word_types[] = {
620 "uint16_t", "int16_t", "_WORD", "WORD",
621 "unsigned __int16", "__int16",
623 static const char *byte_types[] = {
624 "uint8_t", "int8_t", "char",
625 "unsigned __int8", "__int8", "BYTE", "_BYTE",
627 // structures.. deal the same as with _UNKNOWN for now
633 if (c_type->is_ptr) {
638 n = skip_type_mod(c_type->name);
640 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
641 if (IS(n, dword_types[i])) {
647 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
648 if (IS(n, word_types[i])) {
654 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
655 if (IS(n, byte_types[i])) {
664 static char *default_cast_to(char *buf, size_t buf_size,
665 struct parsed_opr *opr)
669 if (!opr->is_ptr || strchr(opr->name, '['))
671 if (opr->pp == NULL || opr->pp->type.name == NULL
674 snprintf(buf, buf_size, "%s", "(void *)");
678 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
682 static enum opr_type lmod_from_directive(const char *d)
686 else if (IS(d, "dw"))
688 else if (IS(d, "db"))
691 aerr("unhandled directive: '%s'\n", d);
695 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
701 *regmask |= 1 << reg;
704 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
707 static int parse_operand(struct parsed_opr *opr,
708 int *regmask, int *regmask_indirect,
709 char words[16][256], int wordc, int w, unsigned int op_flags)
711 const struct parsed_proto *pp = NULL;
712 enum opr_lenmod tmplmod;
713 unsigned long number;
721 aerr("parse_operand w %d, wordc %d\n", w, wordc);
725 for (i = w; i < wordc; i++) {
726 len = strlen(words[i]);
727 if (words[i][len - 1] == ',') {
728 words[i][len - 1] = 0;
734 wordc_in = wordc - w;
736 if ((op_flags & OPF_JMP) && wordc_in > 0
737 && !('0' <= words[w][0] && words[w][0] <= '9'))
739 const char *label = NULL;
741 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
742 && IS(words[w + 1], "ptr"))
743 label = words[w + 2];
744 else if (wordc_in == 2 && IS(words[w], "short"))
745 label = words[w + 1];
746 else if (wordc_in == 1
747 && strchr(words[w], '[') == NULL
748 && parse_reg(&tmplmod, words[w]) < 0)
752 opr->type = OPT_LABEL;
753 ret = check_segment_prefix(label);
756 aerr("fs/gs used\n");
760 strcpy(opr->name, label);
766 if (IS(words[w + 1], "ptr")) {
767 if (IS(words[w], "dword"))
768 opr->lmod = OPLM_DWORD;
769 else if (IS(words[w], "word"))
770 opr->lmod = OPLM_WORD;
771 else if (IS(words[w], "byte"))
772 opr->lmod = OPLM_BYTE;
773 else if (IS(words[w], "qword"))
774 opr->lmod = OPLM_QWORD;
776 aerr("type parsing failed\n");
778 wordc_in = wordc - w;
783 if (IS(words[w], "offset")) {
784 opr->type = OPT_OFFSET;
785 opr->lmod = OPLM_DWORD;
786 strcpy(opr->name, words[w + 1]);
787 pp = proto_parse(g_fhdr, opr->name, 1);
790 if (IS(words[w], "(offset")) {
791 p = strchr(words[w + 1], ')');
793 aerr("parse of bracketed offset failed\n");
795 opr->type = OPT_OFFSET;
796 strcpy(opr->name, words[w + 1]);
802 aerr("parse_operand 1 word expected\n");
804 ret = check_segment_prefix(words[w]);
807 aerr("fs/gs used\n");
809 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
811 strcpy(opr->name, words[w]);
813 if (words[w][0] == '[') {
814 opr->type = OPT_REGMEM;
815 ret = sscanf(words[w], "[%[^]]]", opr->name);
817 aerr("[] parse failure\n");
819 parse_indmode(opr->name, regmask_indirect, 1);
820 if (opr->lmod == OPLM_UNSPEC && parse_stack_el(opr->name, NULL, 1))
823 struct parsed_equ *eq =
824 equ_find(NULL, parse_stack_el(opr->name, NULL, 1), &i);
826 opr->lmod = eq->lmod;
828 // might be unaligned access
829 g_func_lmods |= 1 << OPLM_BYTE;
833 else if (strchr(words[w], '[')) {
835 p = strchr(words[w], '[');
836 opr->type = OPT_REGMEM;
837 parse_indmode(p, regmask_indirect, 0);
838 strncpy(buf, words[w], p - words[w]);
839 buf[p - words[w]] = 0;
840 pp = proto_parse(g_fhdr, buf, 1);
843 else if (('0' <= words[w][0] && words[w][0] <= '9')
844 || words[w][0] == '-')
846 number = parse_number(words[w]);
847 opr->type = OPT_CONST;
849 printf_number(opr->name, sizeof(opr->name), number);
853 ret = parse_reg(&tmplmod, opr->name);
855 setup_reg_opr(opr, ret, tmplmod, regmask);
859 // most likely var in data segment
860 opr->type = OPT_LABEL;
861 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
865 if (pp->is_fptr || pp->is_func) {
866 opr->lmod = OPLM_DWORD;
870 tmplmod = OPLM_UNSPEC;
871 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
872 anote("unhandled C type '%s' for '%s'\n",
873 pp->type.name, opr->name);
875 if (opr->lmod == OPLM_UNSPEC) {
877 opr->type_from_var = 1;
879 else if (opr->lmod != tmplmod) {
880 opr->size_mismatch = 1;
881 if (tmplmod < opr->lmod)
884 opr->is_ptr = pp->type.is_ptr;
886 opr->is_array = pp->type.is_array;
890 if (opr->lmod == OPLM_UNSPEC)
891 guess_lmod_from_name(opr);
895 static const struct {
900 { "repe", OPF_REP|OPF_REPZ },
901 { "repz", OPF_REP|OPF_REPZ },
902 { "repne", OPF_REP|OPF_REPNZ },
903 { "repnz", OPF_REP|OPF_REPNZ },
904 { "lock", OPF_LOCK }, // ignored for now..
907 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
909 static const struct {
912 unsigned short minopr;
913 unsigned short maxopr;
916 unsigned char pfo_inv;
918 { "nop", OP_NOP, 0, 0, 0 },
919 { "push", OP_PUSH, 1, 1, 0 },
920 { "pop", OP_POP, 1, 1, OPF_DATA },
921 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
922 { "mov" , OP_MOV, 2, 2, OPF_DATA },
923 { "lea", OP_LEA, 2, 2, OPF_DATA },
924 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
925 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
926 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
927 { "not", OP_NOT, 1, 1, OPF_DATA },
928 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
929 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
930 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
931 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
932 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
933 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
934 { "stosb",OP_STOS, 0, 0, OPF_DATA },
935 { "stosw",OP_STOS, 0, 0, OPF_DATA },
936 { "stosd",OP_STOS, 0, 0, OPF_DATA },
937 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
938 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
939 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
940 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
941 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
942 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
943 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
944 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
945 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
946 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
947 { "cld", OP_CLD, 0, 0, OPF_DATA },
948 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
949 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
950 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
951 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
952 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
953 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
954 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
955 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
956 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
957 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
958 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
959 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
960 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
961 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
962 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
963 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
964 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
965 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
966 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
967 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
968 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
969 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
970 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
971 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
972 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
973 { "test", OP_TEST, 2, 2, OPF_FLAGS },
974 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
975 { "retn", OP_RET, 0, 1, OPF_TAIL },
976 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
977 { "jmp", OP_JMP, 1, 1, OPF_JMP },
978 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
979 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
980 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
981 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
982 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
983 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
984 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
985 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
986 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
987 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
988 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
989 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
990 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
991 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
992 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
993 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
994 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
995 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
996 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
997 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
998 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
999 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1000 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1001 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1002 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1003 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1004 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1005 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1006 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1007 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1008 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1009 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1010 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1011 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1012 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1013 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1014 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1015 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1016 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1017 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1018 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1019 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1020 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1021 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1022 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1023 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1024 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1025 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1026 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1027 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1028 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1029 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1030 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1031 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1032 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1033 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1034 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1035 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1036 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1037 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1039 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1040 { "fild", OP_FILD, 1, 1, OPF_FPUSH },
1041 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1042 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1043 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1044 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1045 { "fst", OP_FST, 1, 1, 0 },
1046 { "fadd", OP_FADD, 0, 2, 0 },
1047 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1048 { "fdiv", OP_FDIV, 0, 2, 0 },
1049 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1050 { "fmul", OP_FMUL, 0, 2, 0 },
1051 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1052 { "fsub", OP_FSUB, 0, 2, 0 },
1053 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1054 { "fdivr", OP_FDIVR, 0, 2, 0 },
1055 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1056 { "fsubr", OP_FSUBR, 0, 2, 0 },
1057 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1058 { "fiadd", OP_FIADD, 1, 1, 0 },
1059 { "fidiv", OP_FIDIV, 1, 1, 0 },
1060 { "fimul", OP_FIMUL, 1, 1, 0 },
1061 { "fisub", OP_FISUB, 1, 1, 0 },
1062 { "fidivr", OP_FIDIVR, 1, 1, 0 },
1063 { "fisubr", OP_FISUBR, 1, 1, 0 },
1064 { "fchs", OP_FCHS, 0, 0, 0 },
1065 { "fcos", OP_FCOS, 0, 0, 0 },
1066 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1067 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1068 { "fsin", OP_FSIN, 0, 0, 0 },
1069 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1070 { "fxch", OP_FXCH, 1, 1, 0 },
1071 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1073 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1074 { "movq", OP_MOV, 2, 2, OPF_DATA },
1075 // pseudo-ops for lib calls
1076 { "_allshl",OPP_ALLSHL },
1077 { "_allshr",OPP_ALLSHR },
1078 { "_ftol", OPP_FTOL },
1083 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1085 enum opr_lenmod lmod = OPLM_UNSPEC;
1086 int prefix_flags = 0;
1094 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1095 if (IS(words[w], pref_table[i].name)) {
1096 prefix_flags = pref_table[i].flags;
1103 aerr("lone prefix: '%s'\n", words[0]);
1108 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1109 if (IS(words[w], op_table[i].name))
1113 if (i == ARRAY_SIZE(op_table)) {
1115 aerr("unhandled op: '%s'\n", words[0]);
1120 op->op = op_table[i].op;
1121 op->flags = op_table[i].flags | prefix_flags;
1122 op->pfo = op_table[i].pfo;
1123 op->pfo_inv = op_table[i].pfo_inv;
1124 op->regmask_src = op->regmask_dst = 0;
1127 if (op->op == OP_UD2)
1130 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1131 if (opr >= op_table[i].minopr && w >= wordc)
1134 regmask = regmask_ind = 0;
1135 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1136 words, wordc, w, op->flags);
1138 if (opr == 0 && (op->flags & OPF_DATA))
1139 op->regmask_dst = regmask;
1141 op->regmask_src |= regmask;
1142 op->regmask_src |= regmask_ind;
1144 if (op->operand[opr].lmod != OPLM_UNSPEC)
1145 g_func_lmods |= 1 << op->operand[opr].lmod;
1149 aerr("parse_op %s incomplete: %d/%d\n",
1150 words[0], w, wordc);
1153 op->operand_cnt = opr;
1154 if (!strncmp(op_table[i].name, "set", 3))
1155 op->operand[0].lmod = OPLM_BYTE;
1158 // first operand is not dst
1161 op->regmask_src |= op->regmask_dst;
1162 op->regmask_dst = 0;
1165 // first operand is src too
1178 op->regmask_src |= op->regmask_dst;
1183 op->regmask_src |= op->regmask_dst;
1184 op->regmask_dst |= op->regmask_src;
1190 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1191 && op->operand[0].lmod == op->operand[1].lmod
1192 && op->operand[0].reg == op->operand[1].reg
1193 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1195 op->regmask_src = 0;
1198 op->regmask_src |= op->regmask_dst;
1201 // ops with implicit argumets
1203 op->operand_cnt = 2;
1204 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1205 op->regmask_dst = op->regmask_src;
1206 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1210 op->operand_cnt = 2;
1211 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1212 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1218 if (words[op_w][4] == 'b')
1220 else if (words[op_w][4] == 'w')
1222 else if (words[op_w][4] == 'd')
1225 op->regmask_src = 0;
1226 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1227 OPLM_DWORD, &op->regmask_src);
1228 op->regmask_dst = op->regmask_src;
1229 setup_reg_opr(&op->operand[j++], xAX, lmod,
1230 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1231 if (op->flags & OPF_REP) {
1232 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1233 op->regmask_dst |= 1 << xCX;
1235 op->operand_cnt = j;
1240 if (words[op_w][4] == 'b')
1242 else if (words[op_w][4] == 'w')
1244 else if (words[op_w][4] == 'd')
1247 op->regmask_src = 0;
1248 // note: lmod is not correct, don't have where to place it
1249 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1250 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1251 if (op->flags & OPF_REP)
1252 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1253 op->operand_cnt = j;
1254 op->regmask_dst = op->regmask_src;
1258 op->regmask_dst = 1 << xCX;
1261 op->operand_cnt = 2;
1262 op->regmask_src = 1 << xCX;
1263 op->operand[1].type = OPT_REG;
1264 op->operand[1].reg = xCX;
1265 op->operand[1].lmod = OPLM_DWORD;
1269 if (op->operand_cnt == 2) {
1270 if (op->operand[0].type != OPT_REG)
1271 aerr("reg expected\n");
1272 op->regmask_src |= 1 << op->operand[0].reg;
1274 if (op->operand_cnt != 1)
1279 op->regmask_src |= op->regmask_dst;
1280 op->regmask_dst = (1 << xDX) | (1 << xAX);
1281 if (op->operand[0].lmod == OPLM_UNSPEC)
1282 op->operand[0].lmod = OPLM_DWORD;
1287 // we could set up operands for edx:eax, but there is no real need to
1288 // (see is_opr_modified())
1289 op->regmask_src |= op->regmask_dst;
1290 op->regmask_dst = (1 << xDX) | (1 << xAX);
1291 if (op->operand[0].lmod == OPLM_UNSPEC)
1292 op->operand[0].lmod = OPLM_DWORD;
1300 op->regmask_src |= op->regmask_dst;
1301 if (op->operand[1].lmod == OPLM_UNSPEC)
1302 op->operand[1].lmod = OPLM_BYTE;
1307 op->regmask_src |= op->regmask_dst;
1308 if (op->operand[2].lmod == OPLM_UNSPEC)
1309 op->operand[2].lmod = OPLM_BYTE;
1313 op->regmask_src |= op->regmask_dst;
1314 op->regmask_dst = 0;
1315 if (op->operand[0].lmod == OPLM_UNSPEC
1316 && (op->operand[0].type == OPT_CONST
1317 || op->operand[0].type == OPT_OFFSET
1318 || op->operand[0].type == OPT_LABEL))
1319 op->operand[0].lmod = OPLM_DWORD;
1325 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1326 && op->operand[0].lmod == op->operand[1].lmod
1327 && op->operand[0].reg == op->operand[1].reg
1328 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1330 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1331 op->regmask_src = op->regmask_dst = 0;
1336 if (op->operand[0].type == OPT_REG
1337 && op->operand[1].type == OPT_REGMEM)
1340 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1341 if (IS(buf, op->operand[1].name))
1342 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1347 // trashed regs must be explicitly detected later
1348 op->regmask_dst = 0;
1352 op->regmask_dst = (1 << xBP) | (1 << xSP);
1353 op->regmask_src = 1 << xBP;
1358 op->regmask_dst |= mxST0;
1362 op->regmask_dst |= mxST0;
1363 if (IS(words[op_w] + 3, "1"))
1364 op->operand[0].val = X87_CONST_1;
1365 else if (IS(words[op_w] + 3, "ln2"))
1366 op->operand[0].val = X87_CONST_LN2;
1367 else if (IS(words[op_w] + 3, "z"))
1368 op->operand[0].val = X87_CONST_Z;
1374 op->regmask_src |= mxST0;
1383 op->regmask_src |= mxST0;
1384 if (op->operand_cnt == 2)
1385 op->regmask_src |= op->regmask_dst;
1386 else if (op->operand_cnt == 1) {
1387 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1388 op->operand[0].type = OPT_REG;
1389 op->operand[0].lmod = OPLM_QWORD;
1390 op->operand[0].reg = xST0;
1391 op->regmask_dst |= mxST0;
1394 // IDA doesn't use this
1395 aerr("no operands?\n");
1409 op->regmask_src |= mxST0;
1410 op->regmask_dst |= mxST0;
1415 op->regmask_src |= mxST0 | mxST1;
1416 op->regmask_dst |= mxST0;
1427 if (op->operand[0].type == OPT_REG
1428 && op->operand[1].type == OPT_CONST)
1430 struct parsed_opr *op1 = &op->operand[1];
1431 if ((op->op == OP_AND && op1->val == 0)
1434 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1435 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1437 op->regmask_src = 0;
1442 static const char *op_name(struct parsed_op *po)
1444 static char buf[16];
1448 if (po->op == OP_JCC || po->op == OP_SCC) {
1450 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1453 strcpy(p, parsed_flag_op_names[po->pfo]);
1457 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1458 if (op_table[i].op == po->op)
1459 return op_table[i].name;
1465 static const char *dump_op(struct parsed_op *po)
1467 static char out[128];
1474 snprintf(out, sizeof(out), "%s", op_name(po));
1475 for (i = 0; i < po->operand_cnt; i++) {
1479 snprintf(p, sizeof(out) - (p - out),
1480 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1481 po->operand[i].name);
1487 static const char *lmod_type_u(struct parsed_op *po,
1488 enum opr_lenmod lmod)
1500 ferr(po, "invalid lmod: %d\n", lmod);
1501 return "(_invalid_)";
1505 static const char *lmod_cast_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_ptr(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_s(struct parsed_op *po,
1542 enum opr_lenmod lmod)
1554 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1555 return "(_invalid_)";
1559 static const char *lmod_cast(struct parsed_op *po,
1560 enum opr_lenmod lmod, int is_signed)
1563 lmod_cast_s(po, lmod) :
1564 lmod_cast_u(po, lmod);
1567 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1579 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1584 static const char *opr_name(struct parsed_op *po, int opr_num)
1586 if (opr_num >= po->operand_cnt)
1587 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1588 return po->operand[opr_num].name;
1591 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1593 if (opr_num >= po->operand_cnt)
1594 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1595 if (po->operand[opr_num].type != OPT_CONST)
1596 ferr(po, "opr %d: const expected\n", opr_num);
1597 return po->operand[opr_num].val;
1600 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1602 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1603 ferr(po, "invalid reg: %d\n", popr->reg);
1604 return regs_r32[popr->reg];
1607 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1609 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1611 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1613 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1615 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1620 *is_signed = cast[1] == 's' ? 1 : 0;
1624 static int check_deref_cast(const char *cast, int *bits)
1626 if (IS_START(cast, "*(u8 *)"))
1628 else if (IS_START(cast, "*(u16 *)"))
1630 else if (IS_START(cast, "*(u32 *)"))
1632 else if (IS_START(cast, "*(u64 *)"))
1640 // cast1 is the "final" cast
1641 static const char *simplify_cast(const char *cast1, const char *cast2)
1643 static char buf[256];
1651 if (IS(cast1, cast2))
1654 if (check_simple_cast(cast1, &bits1, &s1) == 0
1655 && check_simple_cast(cast2, &bits2, &s2) == 0)
1660 if (check_simple_cast(cast1, &bits1, &s1) == 0
1661 && check_deref_cast(cast2, &bits2) == 0)
1663 if (bits1 == bits2) {
1664 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1669 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1672 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1676 static const char *simplify_cast_num(const char *cast, unsigned int val)
1678 if (IS(cast, "(u8)") && val < 0x100)
1680 if (IS(cast, "(s8)") && val < 0x80)
1682 if (IS(cast, "(u16)") && val < 0x10000)
1684 if (IS(cast, "(s16)") && val < 0x8000)
1686 if (IS(cast, "(s32)") && val < 0x80000000)
1692 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1701 namelen = strlen(name);
1703 p = strchr(name, '+');
1707 ferr(po, "equ parse failed for '%s'\n", name);
1709 if (IS_START(p, "0x"))
1711 *extra_offs = strtol(p, &endp, 16);
1713 ferr(po, "equ parse failed for '%s'\n", name);
1716 for (i = 0; i < g_eqcnt; i++)
1717 if (strncmp(g_eqs[i].name, name, namelen) == 0
1718 && g_eqs[i].name[namelen] == 0)
1722 ferr(po, "unresolved equ name: '%s'\n", name);
1729 static int is_stack_access(struct parsed_op *po,
1730 const struct parsed_opr *popr)
1732 return (parse_stack_el(popr->name, NULL, 0)
1733 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1734 && IS_START(popr->name, "ebp")));
1737 static void parse_stack_access(struct parsed_op *po,
1738 const char *name, char *ofs_reg, int *offset_out,
1739 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1741 const char *bp_arg = "";
1742 const char *p = NULL;
1743 struct parsed_equ *eq;
1750 if (IS_START(name, "ebp-")
1751 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1754 if (IS_START(p, "0x"))
1756 offset = strtoul(p, &endp, 16);
1760 ferr(po, "ebp- parse of '%s' failed\n", name);
1763 bp_arg = parse_stack_el(name, ofs_reg, 0);
1764 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1765 eq = equ_find(po, bp_arg, &offset);
1767 ferr(po, "detected but missing eq\n");
1768 offset += eq->offset;
1771 if (!strncmp(name, "ebp", 3))
1774 // yes it sometimes LEAs ra for compares..
1775 if (!is_lea && ofs_reg[0] == 0
1776 && stack_ra <= offset && offset < stack_ra + 4)
1778 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1781 *offset_out = offset;
1782 *stack_ra_out = stack_ra;
1784 *bp_arg_out = bp_arg;
1787 static int stack_frame_access(struct parsed_op *po,
1788 struct parsed_opr *popr, char *buf, size_t buf_size,
1789 const char *name, const char *cast, int is_src, int is_lea)
1791 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1792 const char *prefix = "";
1793 const char *bp_arg = NULL;
1794 char ofs_reg[16] = { 0, };
1795 int i, arg_i, arg_s;
1803 if (po->flags & OPF_EBP_S)
1804 ferr(po, "stack_frame_access while ebp is scratch\n");
1806 parse_stack_access(po, name, ofs_reg, &offset,
1807 &stack_ra, &bp_arg, is_lea);
1809 if (offset > stack_ra)
1811 arg_i = (offset - stack_ra - 4) / 4;
1812 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1814 if (g_func_pp->is_vararg
1815 && arg_i == g_func_pp->argc_stack && is_lea)
1817 // should be va_list
1820 snprintf(buf, buf_size, "%sap", cast);
1823 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1824 offset, bp_arg, arg_i);
1826 if (ofs_reg[0] != 0)
1827 ferr(po, "offset reg on arg access?\n");
1829 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1830 if (g_func_pp->arg[i].reg != NULL)
1836 if (i == g_func_pp->argc)
1837 ferr(po, "arg %d not in prototype?\n", arg_i);
1839 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1846 ferr(po, "lea/byte to arg?\n");
1847 if (is_src && (offset & 3) == 0)
1848 snprintf(buf, buf_size, "%sa%d",
1849 simplify_cast(cast, "(u8)"), i + 1);
1851 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1852 cast, offset & 3, i + 1);
1857 ferr(po, "lea/word to arg?\n");
1862 ferr(po, "problematic arg store\n");
1863 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1864 simplify_cast(cast, "*(u16 *)"), i + 1);
1867 ferr(po, "unaligned arg word load\n");
1869 else if (is_src && (offset & 2) == 0)
1870 snprintf(buf, buf_size, "%sa%d",
1871 simplify_cast(cast, "(u16)"), i + 1);
1873 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1874 cast, (offset & 2) ? "HI" : "LO", i + 1);
1886 snprintf(buf, buf_size, "(u32)&a%d + %d",
1889 ferr(po, "unaligned arg store\n");
1891 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1892 snprintf(buf, buf_size, "%s(a%d >> %d)",
1893 prefix, i + 1, (offset & 3) * 8);
1897 snprintf(buf, buf_size, "%s%sa%d",
1898 prefix, is_lea ? "&" : "", i + 1);
1903 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1907 snprintf(g_comment, sizeof(g_comment), "%s unaligned", bp_arg);
1910 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
1911 if (tmp_lmod != OPLM_DWORD
1912 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
1913 < lmod_bytes(po, popr->lmod) + (offset & 3))))
1915 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
1916 i + 1, offset, g_func_pp->arg[i].type.name);
1918 // can't check this because msvc likes to reuse
1919 // arg space for scratch..
1920 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
1921 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
1925 if (g_stack_fsz == 0)
1926 ferr(po, "stack var access without stackframe\n");
1927 g_stack_frame_used = 1;
1929 sf_ofs = g_stack_fsz + offset;
1930 lim = (ofs_reg[0] != 0) ? -4 : 0;
1931 if (offset > 0 || sf_ofs < lim)
1932 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
1942 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1943 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1947 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
1948 // known unaligned or possibly unaligned
1949 strcat(g_comment, " unaligned");
1951 prefix = "*(u16 *)&";
1952 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1953 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1956 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
1960 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
1961 // known unaligned or possibly unaligned
1962 strcat(g_comment, " unaligned");
1964 prefix = "*(u32 *)&";
1965 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
1966 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
1969 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
1973 ferr_assert(po, !(sf_ofs & 7));
1974 ferr_assert(po, ofs_reg[0] == 0);
1975 // float callers set is_lea
1976 ferr_assert(po, is_lea);
1977 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
1981 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
1988 static void check_func_pp(struct parsed_op *po,
1989 const struct parsed_proto *pp, const char *pfx)
1991 enum opr_lenmod tmp_lmod;
1995 if (pp->argc_reg != 0) {
1996 if (/*!g_allow_regfunc &&*/ !pp->is_fastcall) {
1997 pp_print(buf, sizeof(buf), pp);
1998 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2000 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2001 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2002 pfx, pp->argc_reg, pp->argc_stack);
2005 // fptrs must use 32bit args, callsite might have no information and
2006 // lack a cast to smaller types, which results in incorrectly masked
2007 // args passed (callee may assume masked args, it does on ARM)
2008 if (!pp->is_osinc) {
2009 for (i = 0; i < pp->argc; i++) {
2010 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2011 if (ret && tmp_lmod != OPLM_DWORD)
2012 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2013 i + 1, pp->arg[i].type.name);
2018 static const char *check_label_read_ref(struct parsed_op *po,
2021 const struct parsed_proto *pp;
2023 pp = proto_parse(g_fhdr, name, 0);
2025 ferr(po, "proto_parse failed for ref '%s'\n", name);
2028 check_func_pp(po, pp, "ref");
2033 static char *out_src_opr(char *buf, size_t buf_size,
2034 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2037 char tmp1[256], tmp2[256];
2046 switch (popr->type) {
2049 ferr(po, "lea from reg?\n");
2051 switch (popr->lmod) {
2053 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2056 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2059 snprintf(buf, buf_size, "%s%s",
2060 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2063 if (popr->name[1] == 'h') // XXX..
2064 snprintf(buf, buf_size, "%s(%s >> 8)",
2065 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2067 snprintf(buf, buf_size, "%s%s",
2068 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2071 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2076 if (is_stack_access(po, popr)) {
2077 stack_frame_access(po, popr, buf, buf_size,
2078 popr->name, cast, 1, is_lea);
2082 strcpy(expr, popr->name);
2083 if (strchr(expr, '[')) {
2084 // special case: '[' can only be left for label[reg] form
2085 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2087 ferr(po, "parse failure for '%s'\n", expr);
2088 if (tmp1[0] == '(') {
2089 // (off_4FFF50+3)[eax]
2090 p = strchr(tmp1 + 1, ')');
2091 if (p == NULL || p[1] != 0)
2092 ferr(po, "parse failure (2) for '%s'\n", expr);
2094 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2096 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2099 // XXX: do we need more parsing?
2101 snprintf(buf, buf_size, "%s", expr);
2105 snprintf(buf, buf_size, "%s(%s)",
2106 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2110 name = check_label_read_ref(po, popr->name);
2111 if (cast[0] == 0 && popr->is_ptr)
2115 snprintf(buf, buf_size, "(u32)&%s", name);
2116 else if (popr->size_lt)
2117 snprintf(buf, buf_size, "%s%s%s%s", cast,
2118 lmod_cast_u_ptr(po, popr->lmod),
2119 popr->is_array ? "" : "&", name);
2121 snprintf(buf, buf_size, "%s%s%s", cast, name,
2122 popr->is_array ? "[0]" : "");
2126 name = check_label_read_ref(po, popr->name);
2130 ferr(po, "lea an offset?\n");
2131 snprintf(buf, buf_size, "%s&%s", cast, name);
2136 ferr(po, "lea from const?\n");
2138 printf_number(tmp1, sizeof(tmp1), popr->val);
2139 if (popr->val == 0 && strchr(cast, '*'))
2140 snprintf(buf, buf_size, "NULL");
2142 snprintf(buf, buf_size, "%s%s",
2143 simplify_cast_num(cast, popr->val), tmp1);
2147 ferr(po, "invalid src type: %d\n", popr->type);
2153 // note: may set is_ptr (we find that out late for ebp frame..)
2154 static char *out_dst_opr(char *buf, size_t buf_size,
2155 struct parsed_op *po, struct parsed_opr *popr)
2157 switch (popr->type) {
2159 switch (popr->lmod) {
2161 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2164 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2168 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2172 if (popr->name[1] == 'h') // XXX..
2173 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2175 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2178 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2183 if (is_stack_access(po, popr)) {
2184 stack_frame_access(po, popr, buf, buf_size,
2185 popr->name, "", 0, 0);
2189 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2192 if (popr->size_mismatch)
2193 snprintf(buf, buf_size, "%s%s%s",
2194 lmod_cast_u_ptr(po, popr->lmod),
2195 popr->is_array ? "" : "&", popr->name);
2197 snprintf(buf, buf_size, "%s%s", popr->name,
2198 popr->is_array ? "[0]" : "");
2202 ferr(po, "invalid dst type: %d\n", popr->type);
2208 static char *out_src_opr_u32(char *buf, size_t buf_size,
2209 struct parsed_op *po, struct parsed_opr *popr)
2211 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2214 static char *out_src_opr_float(char *buf, size_t buf_size,
2215 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2217 const char *cast = NULL;
2220 switch (popr->type) {
2222 if (popr->reg < xST0 || popr->reg > xST7)
2223 ferr(po, "bad reg: %d\n", popr->reg);
2225 if (need_float_stack) {
2226 if (popr->reg == xST0)
2227 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2229 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2233 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2239 switch (popr->lmod) {
2247 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2250 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2251 snprintf(buf, buf_size, "*((%s *)%s)", cast, tmp);
2255 ferr(po, "invalid float type: %d\n", popr->type);
2261 static char *out_dst_opr_float(char *buf, size_t buf_size,
2262 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2265 return out_src_opr_float(buf, buf_size, po, popr, need_float_stack);
2268 static void out_test_for_cc(char *buf, size_t buf_size,
2269 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2270 enum opr_lenmod lmod, const char *expr)
2272 const char *cast, *scast;
2274 cast = lmod_cast_u(po, lmod);
2275 scast = lmod_cast_s(po, lmod);
2279 case PFO_BE: // CF=1||ZF=1; CF=0
2280 snprintf(buf, buf_size, "(%s%s %s 0)",
2281 cast, expr, is_inv ? "!=" : "==");
2285 case PFO_L: // SF!=OF; OF=0
2286 snprintf(buf, buf_size, "(%s%s %s 0)",
2287 scast, expr, is_inv ? ">=" : "<");
2290 case PFO_LE: // ZF=1||SF!=OF; OF=0
2291 snprintf(buf, buf_size, "(%s%s %s 0)",
2292 scast, expr, is_inv ? ">" : "<=");
2296 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2300 static void out_cmp_for_cc(char *buf, size_t buf_size,
2301 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2303 const char *cast, *scast, *cast_use;
2304 char buf1[256], buf2[256];
2305 enum opr_lenmod lmod;
2307 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2308 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2309 po->operand[0].lmod, po->operand[1].lmod);
2310 lmod = po->operand[0].lmod;
2312 cast = lmod_cast_u(po, lmod);
2313 scast = lmod_cast_s(po, lmod);
2329 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2332 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2333 if (po->op == OP_DEC)
2334 snprintf(buf2, sizeof(buf2), "1");
2336 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_use, 0);
2340 // note: must be unsigned compare
2341 snprintf(buf, buf_size, "(%s %s %s)",
2342 buf1, is_inv ? ">=" : "<", buf2);
2346 snprintf(buf, buf_size, "(%s %s %s)",
2347 buf1, is_inv ? "!=" : "==", buf2);
2351 // note: must be unsigned compare
2352 snprintf(buf, buf_size, "(%s %s %s)",
2353 buf1, is_inv ? ">" : "<=", buf2);
2356 if (is_inv && lmod == OPLM_BYTE
2357 && po->operand[1].type == OPT_CONST
2358 && po->operand[1].val == 0xff)
2360 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2361 snprintf(buf, buf_size, "(0)");
2365 // note: must be signed compare
2367 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2368 scast, buf1, buf2, is_inv ? ">=" : "<");
2372 snprintf(buf, buf_size, "(%s %s %s)",
2373 buf1, is_inv ? ">=" : "<", buf2);
2377 snprintf(buf, buf_size, "(%s %s %s)",
2378 buf1, is_inv ? ">" : "<=", buf2);
2386 static void out_cmp_test(char *buf, size_t buf_size,
2387 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2389 char buf1[256], buf2[256], buf3[256];
2391 if (po->op == OP_TEST) {
2392 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2393 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2396 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2397 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2398 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2400 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2401 po->operand[0].lmod, buf3);
2403 else if (po->op == OP_CMP) {
2404 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv);
2407 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2410 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2411 struct parsed_opr *popr2)
2413 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2414 ferr(po, "missing lmod for both operands\n");
2416 if (popr1->lmod == OPLM_UNSPEC)
2417 popr1->lmod = popr2->lmod;
2418 else if (popr2->lmod == OPLM_UNSPEC)
2419 popr2->lmod = popr1->lmod;
2420 else if (popr1->lmod != popr2->lmod) {
2421 if (popr1->type_from_var) {
2422 popr1->size_mismatch = 1;
2423 if (popr1->lmod < popr2->lmod)
2425 popr1->lmod = popr2->lmod;
2427 else if (popr2->type_from_var) {
2428 popr2->size_mismatch = 1;
2429 if (popr2->lmod < popr1->lmod)
2431 popr2->lmod = popr1->lmod;
2434 ferr(po, "conflicting lmods: %d vs %d\n",
2435 popr1->lmod, popr2->lmod);
2439 static const char *op_to_c(struct parsed_op *po)
2463 ferr(po, "op_to_c was supplied with %d\n", po->op);
2467 // last op in stream - unconditional branch or ret
2468 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2469 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2470 && ops[_i].op != OP_CALL))
2472 #define check_i(po, i) \
2474 ferr(po, "bad " #i ": %d\n", i)
2476 // note: this skips over calls and rm'd stuff assuming they're handled
2477 // so it's intended to use at one of final passes
2478 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2479 int depth, int flags_set)
2481 struct parsed_op *po;
2486 for (; i < opcnt; i++) {
2488 if (po->cc_scratch == magic)
2489 return ret; // already checked
2490 po->cc_scratch = magic;
2492 if (po->flags & OPF_TAIL) {
2493 if (po->op == OP_CALL) {
2494 if (po->pp != NULL && po->pp->is_noreturn)
2495 // assume no stack cleanup for noreturn
2498 return -1; // deadend
2501 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2504 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2505 if (po->btj != NULL) {
2507 for (j = 0; j < po->btj->count; j++) {
2508 check_i(po, po->btj->d[j].bt_i);
2509 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2512 return ret; // dead end
2517 check_i(po, po->bt_i);
2518 if (po->flags & OPF_CJMP) {
2519 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2522 return ret; // dead end
2531 if ((po->op == OP_POP || po->op == OP_PUSH)
2532 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2537 if (po->op == OP_PUSH) {
2540 else if (po->op == OP_POP) {
2541 if (relevant && depth == 0) {
2542 po->flags |= flags_set;
2552 // scan for 'reg' pop backwards starting from i
2553 // intended to use for register restore search, so other reg
2554 // references are considered an error
2555 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2557 struct parsed_op *po;
2558 struct label_ref *lr;
2561 ops[i].cc_scratch = magic;
2565 if (g_labels[i] != NULL) {
2566 lr = &g_label_refs[i];
2567 for (; lr != NULL; lr = lr->next) {
2568 check_i(&ops[i], lr->i);
2569 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2573 if (i > 0 && LAST_OP(i - 1))
2581 if (ops[i].cc_scratch == magic)
2583 ops[i].cc_scratch = magic;
2586 if (po->op == OP_POP && po->operand[0].reg == reg) {
2587 if (po->flags & (OPF_RMD|OPF_DONE))
2590 po->flags |= set_flags;
2594 // this also covers the case where we reach corresponding push
2595 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2599 // nothing interesting on this path
2603 static void find_reachable_exits(int i, int opcnt, int magic,
2604 int *exits, int *exit_count)
2606 struct parsed_op *po;
2609 for (; i < opcnt; i++)
2612 if (po->cc_scratch == magic)
2614 po->cc_scratch = magic;
2616 if (po->flags & OPF_TAIL) {
2617 ferr_assert(po, *exit_count < MAX_EXITS);
2618 exits[*exit_count] = i;
2623 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2624 if (po->flags & OPF_RMD)
2627 if (po->btj != NULL) {
2628 for (j = 0; j < po->btj->count; j++) {
2629 check_i(po, po->btj->d[j].bt_i);
2630 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2636 check_i(po, po->bt_i);
2637 if (po->flags & OPF_CJMP)
2638 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2646 // scan for 'reg' pop backwards starting from exits (all paths)
2647 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2649 static int exits[MAX_EXITS];
2650 static int exit_count;
2655 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2657 ferr_assert(&ops[i], exit_count > 0);
2660 for (j = 0; j < exit_count; j++) {
2661 ret = scan_for_rsave_pop_reg(exits[j], i + opcnt * 16 + set_flags,
2670 // scan for one or more pop of push <const>
2671 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2672 int push_i, int is_probe)
2674 struct parsed_op *po;
2675 struct label_ref *lr;
2679 for (; i < opcnt; i++)
2682 if (po->cc_scratch == magic)
2683 return ret; // already checked
2684 po->cc_scratch = magic;
2686 if (po->flags & OPF_JMP) {
2687 if (po->flags & OPF_RMD)
2689 if (po->op == OP_CALL)
2692 if (po->btj != NULL) {
2693 for (j = 0; j < po->btj->count; j++) {
2694 check_i(po, po->btj->d[j].bt_i);
2695 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2703 check_i(po, po->bt_i);
2704 if (po->flags & OPF_CJMP) {
2705 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2716 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2719 if (g_labels[i] != NULL) {
2720 // all refs must be visited
2721 lr = &g_label_refs[i];
2722 for (; lr != NULL; lr = lr->next) {
2724 if (ops[lr->i].cc_scratch != magic)
2727 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2731 if (po->op == OP_POP)
2733 if (po->flags & (OPF_RMD|OPF_DONE))
2737 po->flags |= OPF_DONE;
2738 po->datap = &ops[push_i];
2747 static void scan_for_pop_const(int i, int opcnt, int magic)
2751 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2753 ops[i].flags |= OPF_RMD | OPF_DONE;
2754 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2758 // check if all branch targets within a marked path are also marked
2759 // note: the path checked must not be empty or end with a branch
2760 static int check_path_branches(int opcnt, int magic)
2762 struct parsed_op *po;
2765 for (i = 0; i < opcnt; i++) {
2767 if (po->cc_scratch != magic)
2770 if (po->flags & OPF_JMP) {
2771 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2774 if (po->btj != NULL) {
2775 for (j = 0; j < po->btj->count; j++) {
2776 check_i(po, po->btj->d[j].bt_i);
2777 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2782 check_i(po, po->bt_i);
2783 if (ops[po->bt_i].cc_scratch != magic)
2785 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2793 // scan for multiple pushes for given pop
2794 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2797 int reg = ops[pop_i].operand[0].reg;
2798 struct parsed_op *po;
2799 struct label_ref *lr;
2802 ops[i].cc_scratch = magic;
2806 if (g_labels[i] != NULL) {
2807 lr = &g_label_refs[i];
2808 for (; lr != NULL; lr = lr->next) {
2809 check_i(&ops[i], lr->i);
2810 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2814 if (i > 0 && LAST_OP(i - 1))
2822 if (ops[i].cc_scratch == magic)
2824 ops[i].cc_scratch = magic;
2827 if (po->op == OP_CALL)
2829 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2832 if (po->op == OP_PUSH)
2834 if (po->datap != NULL)
2836 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2837 // leave this case for reg save/restore handlers
2841 po->flags |= OPF_PPUSH | OPF_DONE;
2842 po->datap = &ops[pop_i];
2851 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2853 int magic = i + opcnt * 14;
2856 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2858 ret = check_path_branches(opcnt, magic);
2860 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2861 *regmask_pp |= 1 << ops[i].operand[0].reg;
2862 scan_pushes_for_pop_r(i, magic + 1, i, 0);
2867 static void scan_propagate_df(int i, int opcnt)
2869 struct parsed_op *po = &ops[i];
2872 for (; i < opcnt; i++) {
2874 if (po->flags & OPF_DF)
2875 return; // already resolved
2876 po->flags |= OPF_DF;
2878 if (po->op == OP_CALL)
2879 ferr(po, "call with DF set?\n");
2881 if (po->flags & OPF_JMP) {
2882 if (po->btj != NULL) {
2884 for (j = 0; j < po->btj->count; j++) {
2885 check_i(po, po->btj->d[j].bt_i);
2886 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
2891 if (po->flags & OPF_RMD)
2893 check_i(po, po->bt_i);
2894 if (po->flags & OPF_CJMP)
2895 scan_propagate_df(po->bt_i, opcnt);
2901 if (po->flags & OPF_TAIL)
2904 if (po->op == OP_CLD) {
2905 po->flags |= OPF_RMD | OPF_DONE;
2910 ferr(po, "missing DF clear?\n");
2913 // is operand 'opr' referenced by parsed_op 'po'?
2914 static int is_opr_referenced(const struct parsed_opr *opr,
2915 const struct parsed_op *po)
2919 if (opr->type == OPT_REG) {
2920 mask = po->regmask_dst | po->regmask_src;
2921 if (po->op == OP_CALL)
2922 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
2923 if ((1 << opr->reg) & mask)
2929 for (i = 0; i < po->operand_cnt; i++)
2930 if (IS(po->operand[0].name, opr->name))
2936 // is operand 'opr' read by parsed_op 'po'?
2937 static int is_opr_read(const struct parsed_opr *opr,
2938 const struct parsed_op *po)
2940 if (opr->type == OPT_REG) {
2941 if (po->regmask_src & (1 << opr->reg))
2951 // is operand 'opr' modified by parsed_op 'po'?
2952 static int is_opr_modified(const struct parsed_opr *opr,
2953 const struct parsed_op *po)
2957 if (opr->type == OPT_REG) {
2958 if (po->op == OP_CALL) {
2959 mask = po->regmask_dst;
2960 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
2961 if (mask & (1 << opr->reg))
2967 if (po->regmask_dst & (1 << opr->reg))
2973 return IS(po->operand[0].name, opr->name);
2976 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
2977 static int is_any_opr_modified(const struct parsed_op *po_test,
2978 const struct parsed_op *po, int c_mode)
2983 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
2986 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
2989 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
2992 // in reality, it can wreck any register, but in decompiled C
2993 // version it can only overwrite eax or edx:eax
2994 mask = (1 << xAX) | (1 << xDX);
2998 if (po->op == OP_CALL
2999 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3002 for (i = 0; i < po_test->operand_cnt; i++)
3003 if (IS(po_test->operand[i].name, po->operand[0].name))
3009 // scan for any po_test operand modification in range given
3010 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3013 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3016 for (; i < opcnt; i++) {
3017 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3024 // scan for po_test operand[0] modification in range given
3025 static int scan_for_mod_opr0(struct parsed_op *po_test,
3028 for (; i < opcnt; i++) {
3029 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3036 static int scan_for_flag_set(int i, int magic, int *branched,
3037 int *setters, int *setter_cnt)
3039 struct label_ref *lr;
3043 if (ops[i].cc_scratch == magic) {
3044 // is this a problem?
3045 //ferr(&ops[i], "%s looped\n", __func__);
3048 ops[i].cc_scratch = magic;
3050 if (g_labels[i] != NULL) {
3053 lr = &g_label_refs[i];
3054 for (; lr->next; lr = lr->next) {
3055 check_i(&ops[i], lr->i);
3056 ret = scan_for_flag_set(lr->i, magic,
3057 branched, setters, setter_cnt);
3062 check_i(&ops[i], lr->i);
3063 if (i > 0 && LAST_OP(i - 1)) {
3067 ret = scan_for_flag_set(lr->i, magic,
3068 branched, setters, setter_cnt);
3074 if (ops[i].flags & OPF_FLAGS) {
3075 setters[*setter_cnt] = i;
3080 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3087 // scan back for cdq, if anything modifies edx, fail
3088 static int scan_for_cdq_edx(int i)
3091 if (g_labels[i] != NULL) {
3092 if (g_label_refs[i].next != NULL)
3094 if (i > 0 && LAST_OP(i - 1)) {
3095 i = g_label_refs[i].i;
3102 if (ops[i].op == OP_CDQ)
3105 if (ops[i].regmask_dst & (1 << xDX))
3112 static int scan_for_reg_clear(int i, int reg)
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_XOR
3127 && ops[i].operand[0].lmod == OPLM_DWORD
3128 && ops[i].operand[0].reg == ops[i].operand[1].reg
3129 && ops[i].operand[0].reg == reg)
3132 if (ops[i].regmask_dst & (1 << reg))
3139 static void patch_esp_adjust(struct parsed_op *po, int adj)
3141 ferr_assert(po, po->op == OP_ADD);
3142 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3143 ferr_assert(po, po->operand[1].type == OPT_CONST);
3145 // this is a bit of a hack, but deals with use of
3146 // single adj for multiple calls
3147 po->operand[1].val -= adj;
3148 po->flags |= OPF_RMD;
3149 if (po->operand[1].val == 0)
3150 po->flags |= OPF_DONE;
3151 ferr_assert(po, (int)po->operand[1].val >= 0);
3154 // scan for positive, constant esp adjust
3155 // multipath case is preliminary
3156 static int scan_for_esp_adjust(int i, int opcnt,
3157 int adj_expect, int *adj, int *is_multipath, int do_update)
3159 int adj_expect_unknown = 0;
3160 struct parsed_op *po;
3164 *adj = *is_multipath = 0;
3165 if (adj_expect < 0) {
3166 adj_expect_unknown = 1;
3167 adj_expect = 32 * 4; // enough?
3170 for (; i < opcnt && *adj < adj_expect; i++) {
3171 if (g_labels[i] != NULL)
3175 if (po->flags & OPF_DONE)
3178 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3179 if (po->operand[1].type != OPT_CONST)
3180 ferr(&ops[i], "non-const esp adjust?\n");
3181 *adj += po->operand[1].val;
3183 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3186 patch_esp_adjust(po, adj_expect);
3188 po->flags |= OPF_RMD;
3192 else if (po->op == OP_PUSH) {
3193 //if (first_pop == -1)
3194 // first_pop = -2; // none
3195 *adj -= lmod_bytes(po, po->operand[0].lmod);
3197 else if (po->op == OP_POP) {
3198 if (!(po->flags & OPF_DONE)) {
3199 // seems like msvc only uses 'pop ecx' for stack realignment..
3200 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3202 if (first_pop == -1 && *adj >= 0)
3205 if (do_update && *adj >= 0) {
3206 po->flags |= OPF_RMD;
3208 po->flags |= OPF_DONE | OPF_NOREGS;
3211 *adj += lmod_bytes(po, po->operand[0].lmod);
3212 if (*adj > adj_best)
3215 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3216 if (po->op == OP_JMP && po->btj == NULL) {
3222 if (po->op != OP_CALL)
3224 if (po->operand[0].type != OPT_LABEL)
3226 if (po->pp != NULL && po->pp->is_stdcall)
3228 if (adj_expect_unknown && first_pop >= 0)
3230 // assume it's another cdecl call
3234 if (first_pop >= 0) {
3235 // probably only 'pop ecx' was used
3243 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3245 struct parsed_op *po;
3249 ferr(ops, "%s: followed bad branch?\n", __func__);
3251 for (; i < opcnt; i++) {
3253 if (po->cc_scratch == magic)
3255 po->cc_scratch = magic;
3258 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3259 if (po->btj != NULL) {
3261 for (j = 0; j < po->btj->count; j++)
3262 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3266 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3267 if (!(po->flags & OPF_CJMP))
3270 if (po->flags & OPF_TAIL)
3275 static const struct parsed_proto *try_recover_pp(
3276 struct parsed_op *po, const struct parsed_opr *opr, int *search_instead)
3278 const struct parsed_proto *pp = NULL;
3282 // maybe an arg of g_func?
3283 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3285 char ofs_reg[16] = { 0, };
3286 int arg, arg_s, arg_i;
3293 parse_stack_access(po, opr->name, ofs_reg,
3294 &offset, &stack_ra, NULL, 0);
3295 if (ofs_reg[0] != 0)
3296 ferr(po, "offset reg on arg access?\n");
3297 if (offset <= stack_ra) {
3298 // search who set the stack var instead
3299 if (search_instead != NULL)
3300 *search_instead = 1;
3304 arg_i = (offset - stack_ra - 4) / 4;
3305 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3306 if (g_func_pp->arg[arg].reg != NULL)
3312 if (arg == g_func_pp->argc)
3313 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3315 pp = g_func_pp->arg[arg].fptr;
3317 ferr(po, "icall sa: arg%d is not a fptr?\n", arg + 1);
3318 check_func_pp(po, pp, "icall arg");
3320 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3322 p = strchr(opr->name + 1, '[');
3323 memcpy(buf, opr->name, p - opr->name);
3324 buf[p - opr->name] = 0;
3325 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3327 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3328 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3331 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3334 check_func_pp(po, pp, "reg-fptr ref");
3340 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3341 int magic, const struct parsed_proto **pp_found, int *pp_i,
3344 const struct parsed_proto *pp = NULL;
3345 struct parsed_op *po;
3346 struct label_ref *lr;
3348 ops[i].cc_scratch = magic;
3351 if (g_labels[i] != NULL) {
3352 lr = &g_label_refs[i];
3353 for (; lr != NULL; lr = lr->next) {
3354 check_i(&ops[i], lr->i);
3355 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3357 if (i > 0 && LAST_OP(i - 1))
3365 if (ops[i].cc_scratch == magic)
3367 ops[i].cc_scratch = magic;
3369 if (!(ops[i].flags & OPF_DATA))
3371 if (!is_opr_modified(opr, &ops[i]))
3373 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3374 // most probably trashed by some processing
3379 opr = &ops[i].operand[1];
3380 if (opr->type != OPT_REG)
3384 po = (i >= 0) ? &ops[i] : ops;
3387 // reached the top - can only be an arg-reg
3388 if (opr->type != OPT_REG || g_func_pp == NULL)
3391 for (i = 0; i < g_func_pp->argc; i++) {
3392 if (g_func_pp->arg[i].reg == NULL)
3394 if (IS(opr->name, g_func_pp->arg[i].reg))
3397 if (i == g_func_pp->argc)
3399 pp = g_func_pp->arg[i].fptr;
3401 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3402 i + 1, g_func_pp->arg[i].reg);
3403 check_func_pp(po, pp, "icall reg-arg");
3406 pp = try_recover_pp(po, opr, NULL);
3408 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3409 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3410 || (*pp_found)->is_stdcall != pp->is_stdcall
3411 || (*pp_found)->is_fptr != pp->is_fptr
3412 || (*pp_found)->argc != pp->argc
3413 || (*pp_found)->argc_reg != pp->argc_reg
3414 || (*pp_found)->argc_stack != pp->argc_stack)
3416 ferr(po, "icall: parsed_proto mismatch\n");
3426 static void add_label_ref(struct label_ref *lr, int op_i)
3428 struct label_ref *lr_new;
3435 lr_new = calloc(1, sizeof(*lr_new));
3437 lr_new->next = lr->next;
3441 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3443 struct parsed_op *po = &ops[i];
3444 struct parsed_data *pd;
3445 char label[NAMELEN], *p;
3448 p = strchr(po->operand[0].name, '[');
3452 len = p - po->operand[0].name;
3453 strncpy(label, po->operand[0].name, len);
3456 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3457 if (IS(g_func_pd[j].label, label)) {
3463 //ferr(po, "label '%s' not parsed?\n", label);
3466 if (pd->type != OPT_OFFSET)
3467 ferr(po, "label '%s' with non-offset data?\n", label);
3469 // find all labels, link
3470 for (j = 0; j < pd->count; j++) {
3471 for (l = 0; l < opcnt; l++) {
3472 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3473 add_label_ref(&g_label_refs[l], i);
3483 static void clear_labels(int count)
3487 for (i = 0; i < count; i++) {
3488 if (g_labels[i] != NULL) {
3495 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3500 for (i = 0; i < pp->argc; i++) {
3501 if (pp->arg[i].reg != NULL) {
3502 reg = char_array_i(regs_r32,
3503 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3505 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3506 pp->arg[i].reg, pp->name);
3507 regmask |= 1 << reg;
3514 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3519 if (pp->has_retreg) {
3520 for (i = 0; i < pp->argc; i++) {
3521 if (pp->arg[i].type.is_retreg) {
3522 reg = char_array_i(regs_r32,
3523 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3524 ferr_assert(ops, reg >= 0);
3525 regmask |= 1 << reg;
3530 if (strstr(pp->ret_type.name, "int64"))
3531 return regmask | (1 << xAX) | (1 << xDX);
3532 if (IS(pp->ret_type.name, "float")
3533 || IS(pp->ret_type.name, "double"))
3535 return regmask | mxST0;
3537 if (strcasecmp(pp->ret_type.name, "void") == 0)
3540 return regmask | mxAX;
3543 static void resolve_branches_parse_calls(int opcnt)
3545 static const struct {
3549 unsigned int regmask_src;
3550 unsigned int regmask_dst;
3552 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3553 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3554 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3556 const struct parsed_proto *pp_c;
3557 struct parsed_proto *pp;
3558 struct parsed_data *pd;
3559 struct parsed_op *po;
3560 const char *tmpname;
3564 for (i = 0; i < opcnt; i++)
3570 if (po->datap != NULL) {
3571 pp = calloc(1, sizeof(*pp));
3572 my_assert_not(pp, NULL);
3574 ret = parse_protostr(po->datap, pp);
3576 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3582 if (po->op == OP_CALL) {
3587 else if (po->operand[0].type == OPT_LABEL)
3589 tmpname = opr_name(po, 0);
3590 if (IS_START(tmpname, "loc_"))
3591 ferr(po, "call to loc_*\n");
3593 // convert some calls to pseudo-ops
3594 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3595 if (!IS(tmpname, pseudo_ops[l].name))
3598 po->op = pseudo_ops[l].op;
3599 po->operand_cnt = 0;
3600 po->regmask_src = pseudo_ops[l].regmask_src;
3601 po->regmask_dst = pseudo_ops[l].regmask_dst;
3602 po->flags = pseudo_ops[l].flags;
3603 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3606 if (l < ARRAY_SIZE(pseudo_ops))
3609 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3610 if (!g_header_mode && pp_c == NULL)
3611 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3614 pp = proto_clone(pp_c);
3615 my_assert_not(pp, NULL);
3621 check_func_pp(po, pp, "fptr var call");
3622 if (pp->is_noreturn)
3623 po->flags |= OPF_TAIL;
3629 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3632 if (po->operand[0].type == OPT_REGMEM) {
3633 pd = try_resolve_jumptab(i, opcnt);
3641 for (l = 0; l < opcnt; l++) {
3642 if (g_labels[l] != NULL
3643 && IS(po->operand[0].name, g_labels[l]))
3645 if (l == i + 1 && po->op == OP_JMP) {
3646 // yet another alignment type..
3647 po->flags |= OPF_RMD|OPF_DONE;
3650 add_label_ref(&g_label_refs[l], i);
3656 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3659 if (po->operand[0].type == OPT_LABEL)
3663 ferr(po, "unhandled branch\n");
3667 po->flags |= OPF_TAIL;
3668 if (i > 0 && ops[i - 1].op == OP_POP)
3669 po->flags |= OPF_ATAIL;
3674 static void scan_prologue_epilogue(int opcnt)
3676 int ecx_push = 0, esp_sub = 0;
3680 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3681 && ops[1].op == OP_MOV
3682 && IS(opr_name(&ops[1], 0), "ebp")
3683 && IS(opr_name(&ops[1], 1), "esp"))
3686 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3687 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3690 if (ops[2].op == OP_SUB && IS(opr_name(&ops[2], 0), "esp")) {
3691 g_stack_fsz = opr_const(&ops[2], 1);
3692 ops[2].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3696 // another way msvc builds stack frame..
3698 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3700 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3704 // and another way..
3705 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3706 && ops[i].operand[1].type == OPT_CONST
3707 && ops[i + 1].op == OP_CALL
3708 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3710 g_stack_fsz += ops[i].operand[1].val;
3711 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3713 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3720 for (; i < opcnt; i++)
3721 if (ops[i].flags & OPF_TAIL)
3724 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3725 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3731 if ((ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3732 || ops[j].op == OP_LEAVE)
3734 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3736 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3737 && ops[i].pp->is_noreturn)
3739 // on noreturn, msvc sometimes cleans stack, sometimes not
3744 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3745 ferr(&ops[j], "'pop ebp' expected\n");
3747 if (g_stack_fsz != 0) {
3748 if (ops[j].op == OP_LEAVE)
3750 else if (ops[j].op == OP_POP
3751 && ops[j - 1].op == OP_MOV
3752 && IS(opr_name(&ops[j - 1], 0), "esp")
3753 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3755 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3758 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3760 ferr(&ops[j], "esp restore expected\n");
3763 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3764 && IS(opr_name(&ops[j], 0), "ecx"))
3766 ferr(&ops[j], "unexpected ecx pop\n");
3772 } while (i < opcnt);
3775 ferr(ops, "missing ebp epilogue\n");
3781 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3782 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3788 for (; i < opcnt; i++) {
3789 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3791 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3792 && ops[i].operand[1].type == OPT_CONST)
3794 g_stack_fsz = ops[i].operand[1].val;
3795 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3801 if (ecx_push && !esp_sub) {
3802 // could actually be args for a call..
3803 for (; i < opcnt; i++)
3804 if (ops[i].op != OP_PUSH)
3807 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3808 const struct parsed_proto *pp;
3809 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3810 j = pp ? pp->argc_stack : 0;
3811 while (i > 0 && j > 0) {
3813 if (ops[i].op == OP_PUSH) {
3814 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
3819 ferr(&ops[i], "unhandled prologue\n");
3822 i = g_stack_fsz = ecx_push = 0;
3823 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3824 if (!(ops[i].flags & OPF_RMD))
3834 if (ecx_push || esp_sub)
3839 for (; i < opcnt; i++)
3840 if (ops[i].flags & OPF_TAIL)
3844 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3845 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3852 for (l = 0; l < ecx_push; l++) {
3853 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
3855 else if (ops[j].op == OP_ADD
3856 && IS(opr_name(&ops[j], 0), "esp")
3857 && ops[j].operand[1].type == OPT_CONST)
3860 l += ops[j].operand[1].val / 4 - 1;
3863 ferr(&ops[j], "'pop ecx' expected\n");
3865 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3869 ferr(&ops[j], "epilogue scan failed\n");
3875 if (ops[j].op != OP_ADD
3876 || !IS(opr_name(&ops[j], 0), "esp")
3877 || ops[j].operand[1].type != OPT_CONST
3878 || ops[j].operand[1].val != g_stack_fsz)
3880 if (ops[i].op == OP_CALL && ops[i].pp != NULL
3881 && ops[i].pp->is_noreturn)
3883 // noreturn tailcall with no epilogue
3887 ferr(&ops[j], "'add esp' expected\n");
3890 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3891 ops[j].operand[1].val = 0; // hack for stack arg scanner
3896 } while (i < opcnt);
3899 ferr(ops, "missing esp epilogue\n");
3903 // find an instruction that changed opr before i op
3904 // *op_i must be set to -1 by the caller
3905 // *is_caller is set to 1 if one source is determined to be g_func arg
3906 // returns 1 if found, *op_i is then set to origin
3907 // returns -1 if multiple origins are found
3908 static int resolve_origin(int i, const struct parsed_opr *opr,
3909 int magic, int *op_i, int *is_caller)
3911 struct label_ref *lr;
3914 if (ops[i].cc_scratch == magic)
3916 ops[i].cc_scratch = magic;
3919 if (g_labels[i] != NULL) {
3920 lr = &g_label_refs[i];
3921 for (; lr != NULL; lr = lr->next) {
3922 check_i(&ops[i], lr->i);
3923 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
3925 if (i > 0 && LAST_OP(i - 1))
3931 if (is_caller != NULL)
3936 if (ops[i].cc_scratch == magic)
3938 ops[i].cc_scratch = magic;
3940 if (!(ops[i].flags & OPF_DATA))
3942 if (!is_opr_modified(opr, &ops[i]))
3949 // XXX: could check if the other op does the same
3958 // find an instruction that previously referenced opr
3959 // if multiple results are found - fail
3960 // *op_i must be set to -1 by the caller
3961 // returns 1 if found, *op_i is then set to referencer insn
3962 static int resolve_last_ref(int i, const struct parsed_opr *opr,
3963 int magic, int *op_i)
3965 struct label_ref *lr;
3968 if (ops[i].cc_scratch == magic)
3970 ops[i].cc_scratch = magic;
3973 if (g_labels[i] != NULL) {
3974 lr = &g_label_refs[i];
3975 for (; lr != NULL; lr = lr->next) {
3976 check_i(&ops[i], lr->i);
3977 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
3979 if (i > 0 && LAST_OP(i - 1))
3987 if (ops[i].cc_scratch == magic)
3989 ops[i].cc_scratch = magic;
3991 if (!is_opr_referenced(opr, &ops[i]))
4002 // find next instruction that reads opr
4003 // *op_i must be set to -1 by the caller
4004 // on return, *op_i is set to first referencer insn
4005 // returns 1 if exactly 1 referencer is found
4006 static int find_next_read(int i, int opcnt,
4007 const struct parsed_opr *opr, int magic, int *op_i)
4009 struct parsed_op *po;
4012 for (; i < opcnt; i++)
4014 if (ops[i].cc_scratch == magic)
4016 ops[i].cc_scratch = magic;
4019 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4020 if (po->btj != NULL) {
4022 for (j = 0; j < po->btj->count; j++) {
4023 check_i(po, po->btj->d[j].bt_i);
4024 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4030 if (po->flags & OPF_RMD)
4032 check_i(po, po->bt_i);
4033 if (po->flags & OPF_CJMP) {
4034 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4043 if (!is_opr_read(opr, po)) {
4044 if (is_opr_modified(opr, po)
4045 && (po->op == OP_CALL
4046 || ((po->flags & OPF_DATA)
4047 && po->operand[0].lmod == OPLM_DWORD)))
4052 if (po->flags & OPF_TAIL)
4067 static int try_resolve_const(int i, const struct parsed_opr *opr,
4068 int magic, unsigned int *val)
4073 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4076 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4079 *val = ops[i].operand[1].val;
4086 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4087 int *pp_i, int *multi_src)
4089 const struct parsed_proto *pp = NULL;
4090 int search_advice = 0;
4100 switch (ops[i].operand[0].type) {
4102 // try to resolve struct member calls
4103 ret = sscanf(ops[i].operand[0].name, "%3s+%x%n",
4104 s_reg, &offset, &len);
4105 if (ret == 2 && len == strlen(ops[i].operand[0].name))
4107 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4109 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4111 ret = resolve_origin(i, &opr, i + opcnt * 19, &j, NULL);
4114 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4115 && ops[j].operand[0].lmod == OPLM_DWORD
4116 && ops[j].pp == NULL) // no hint
4118 // allow one simple dereference (directx)
4119 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4120 ops[j].operand[1].name);
4123 struct parsed_opr opr2 = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4125 ret = resolve_origin(j, &opr2, j + opcnt * 19, &k, NULL);
4130 if (ops[j].op != OP_MOV)
4132 if (ops[j].operand[0].lmod != OPLM_DWORD)
4134 if (ops[j].pp != NULL) {
4138 else if (ops[j].operand[1].type == OPT_REGMEM) {
4139 // allow 'hello[ecx]' - assume array of same type items
4140 ret = sscanf(ops[j].operand[1].name, "%[^[][e%2s]",
4144 pp = proto_parse(g_fhdr, name, g_quiet_pp);
4146 else if (ops[j].operand[1].type == OPT_LABEL)
4147 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4152 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4156 pp = proto_lookup_struct(g_fhdr, pp->type.name, offset);
4163 pp = try_recover_pp(&ops[i], &ops[i].operand[0], &search_advice);
4168 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4176 static struct parsed_proto *process_call_early(int i, int opcnt,
4179 struct parsed_op *po = &ops[i];
4180 struct parsed_proto *pp;
4186 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4190 // look for and make use of esp adjust
4192 if (!pp->is_stdcall && pp->argc_stack > 0)
4193 ret = scan_for_esp_adjust(i + 1, opcnt,
4194 pp->argc_stack * 4, &adj, &multipath, 0);
4196 if (pp->argc_stack > adj / 4)
4200 if (ops[ret].op == OP_POP) {
4201 for (j = 1; j < adj / 4; j++) {
4202 if (ops[ret + j].op != OP_POP
4203 || ops[ret + j].operand[0].reg != xCX)
4215 static struct parsed_proto *process_call(int i, int opcnt)
4217 struct parsed_op *po = &ops[i];
4218 const struct parsed_proto *pp_c;
4219 struct parsed_proto *pp;
4220 const char *tmpname;
4221 int call_i = -1, ref_i = -1;
4222 int adj = 0, multipath = 0;
4225 tmpname = opr_name(po, 0);
4230 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4232 if (!pp_c->is_func && !pp_c->is_fptr)
4233 ferr(po, "call to non-func: %s\n", pp_c->name);
4234 pp = proto_clone(pp_c);
4235 my_assert_not(pp, NULL);
4237 // not resolved just to single func
4240 switch (po->operand[0].type) {
4242 // we resolved this call and no longer need the register
4243 po->regmask_src &= ~(1 << po->operand[0].reg);
4245 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4246 && ops[call_i].operand[1].type == OPT_LABEL)
4248 // no other source users?
4249 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4251 if (ret == 1 && call_i == ref_i) {
4252 // and nothing uses it after us?
4254 find_next_read(i + 1, opcnt, &po->operand[0],
4255 i + opcnt * 11, &ref_i);
4257 // then also don't need the source mov
4258 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4270 pp = calloc(1, sizeof(*pp));
4271 my_assert_not(pp, NULL);
4274 ret = scan_for_esp_adjust(i + 1, opcnt,
4275 -1, &adj, &multipath, 0);
4276 if (ret < 0 || adj < 0) {
4277 if (!g_allow_regfunc)
4278 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4279 pp->is_unresolved = 1;
4283 if (adj > ARRAY_SIZE(pp->arg))
4284 ferr(po, "esp adjust too large: %d\n", adj);
4285 pp->ret_type.name = strdup("int");
4286 pp->argc = pp->argc_stack = adj;
4287 for (arg = 0; arg < pp->argc; arg++)
4288 pp->arg[arg].type.name = strdup("int");
4293 // look for and make use of esp adjust
4296 if (!pp->is_stdcall && pp->argc_stack > 0) {
4297 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4298 ret = scan_for_esp_adjust(i + 1, opcnt,
4299 adj_expect, &adj, &multipath, 0);
4302 if (pp->is_vararg) {
4303 if (adj / 4 < pp->argc_stack) {
4304 fnote(po, "(this call)\n");
4305 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4306 adj, pp->argc_stack * 4);
4308 // modify pp to make it have varargs as normal args
4310 pp->argc += adj / 4 - pp->argc_stack;
4311 for (; arg < pp->argc; arg++) {
4312 pp->arg[arg].type.name = strdup("int");
4315 if (pp->argc > ARRAY_SIZE(pp->arg))
4316 ferr(po, "too many args for '%s'\n", tmpname);
4318 if (pp->argc_stack > adj / 4) {
4319 fnote(po, "(this call)\n");
4320 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4321 tmpname, pp->argc_stack * 4, adj);
4324 scan_for_esp_adjust(i + 1, opcnt,
4325 pp->argc_stack * 4, &adj, &multipath, 1);
4327 else if (pp->is_vararg)
4328 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4334 static int collect_call_args_early(struct parsed_op *po, int i,
4335 struct parsed_proto *pp, int *regmask)
4340 for (arg = 0; arg < pp->argc; arg++)
4341 if (pp->arg[arg].reg == NULL)
4344 // first see if it can be easily done
4345 for (j = i; j > 0 && arg < pp->argc; )
4347 if (g_labels[j] != NULL)
4351 if (ops[j].op == OP_CALL)
4353 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP)
4355 else if (ops[j].op == OP_POP)
4357 else if (ops[j].flags & OPF_CJMP)
4359 else if (ops[j].op == OP_PUSH) {
4360 if (ops[j].flags & (OPF_FARG|OPF_FARGNR))
4362 if (!g_header_mode) {
4363 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4368 if (pp->arg[arg].type.is_va_list)
4372 for (arg++; arg < pp->argc; arg++)
4373 if (pp->arg[arg].reg == NULL)
4382 for (arg = 0; arg < pp->argc; arg++)
4383 if (pp->arg[arg].reg == NULL)
4386 for (j = i; j > 0 && arg < pp->argc; )
4390 if (ops[j].op == OP_PUSH)
4392 ops[j].p_argnext = -1;
4393 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4394 pp->arg[arg].datap = &ops[j];
4396 if (ops[j].operand[0].type == OPT_REG)
4397 *regmask |= 1 << ops[j].operand[0].reg;
4399 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4400 ops[j].flags &= ~OPF_RSAVE;
4403 for (arg++; arg < pp->argc; arg++)
4404 if (pp->arg[arg].reg == NULL)
4412 static int collect_call_args_r(struct parsed_op *po, int i,
4413 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4414 int *arg_grp, int arg, int magic, int need_op_saving, int may_reuse)
4416 struct parsed_proto *pp_tmp;
4417 struct parsed_op *po_tmp;
4418 struct label_ref *lr;
4419 int need_to_save_current;
4420 int arg_grp_current = 0;
4421 int save_args_seen = 0;
4429 ferr(po, "dead label encountered\n");
4433 for (; arg < pp->argc; arg++)
4434 if (pp->arg[arg].reg == NULL)
4436 magic = (magic & 0xffffff) | (arg << 24);
4438 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4440 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4441 if (ops[j].cc_scratch != magic) {
4442 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4446 // ok: have already been here
4449 ops[j].cc_scratch = magic;
4451 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4452 lr = &g_label_refs[j];
4453 if (lr->next != NULL)
4455 for (; lr->next; lr = lr->next) {
4456 check_i(&ops[j], lr->i);
4457 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4459 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4460 arg_grp, arg, magic, need_op_saving, may_reuse);
4465 check_i(&ops[j], lr->i);
4466 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4468 if (j > 0 && LAST_OP(j - 1)) {
4469 // follow last branch in reverse
4474 ret = collect_call_args_r(po, lr->i, pp, regmask, save_arg_vars,
4475 arg_grp, arg, magic, need_op_saving, may_reuse);
4481 if (ops[j].op == OP_CALL)
4483 if (pp->is_unresolved)
4488 ferr(po, "arg collect hit unparsed call '%s'\n",
4489 ops[j].operand[0].name);
4490 if (may_reuse && pp_tmp->argc_stack > 0)
4491 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4492 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4494 // esp adjust of 0 means we collected it before
4495 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4496 && (ops[j].operand[1].type != OPT_CONST
4497 || ops[j].operand[1].val != 0))
4499 if (pp->is_unresolved)
4502 fnote(po, "(this call)\n");
4503 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4504 arg, pp->argc, ops[j].operand[1].val);
4506 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4508 if (pp->is_unresolved)
4511 fnote(po, "(this call)\n");
4512 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4514 else if (ops[j].flags & OPF_CJMP)
4516 if (pp->is_unresolved)
4521 else if (ops[j].op == OP_PUSH
4522 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4524 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4527 ops[j].p_argnext = -1;
4528 po_tmp = pp->arg[arg].datap;
4530 ops[j].p_argnext = po_tmp - ops;
4531 pp->arg[arg].datap = &ops[j];
4533 need_to_save_current = 0;
4536 if (ops[j].operand[0].type == OPT_REG)
4537 reg = ops[j].operand[0].reg;
4539 if (!need_op_saving) {
4540 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4541 need_to_save_current = (ret >= 0);
4543 if (need_op_saving || need_to_save_current) {
4544 // mark this push as one that needs operand saving
4545 ops[j].flags &= ~OPF_RMD;
4546 if (ops[j].p_argnum == 0) {
4547 ops[j].p_argnum = arg + 1;
4548 save_args |= 1 << arg;
4550 else if (ops[j].p_argnum < arg + 1) {
4551 // XXX: might kill valid var..
4552 //*save_arg_vars &= ~(1 << (ops[j].p_argnum - 1));
4553 ops[j].p_argnum = arg + 1;
4554 save_args |= 1 << arg;
4557 if (save_args_seen & (1 << (ops[j].p_argnum - 1))) {
4560 if (arg_grp_current >= MAX_ARG_GRP)
4561 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
4562 ops[j].p_argnum, pp->name);
4565 else if (ops[j].p_argnum == 0)
4566 ops[j].flags |= OPF_RMD;
4568 // some PUSHes are reused by different calls on other branches,
4569 // but that can't happen if we didn't branch, so they
4570 // can be removed from future searches (handles nested calls)
4572 ops[j].flags |= OPF_FARGNR;
4574 ops[j].flags |= OPF_FARG;
4575 ops[j].flags &= ~OPF_RSAVE;
4577 // check for __VALIST
4578 if (!pp->is_unresolved && g_func_pp != NULL
4579 && pp->arg[arg].type.is_va_list)
4582 ret = resolve_origin(j, &ops[j].operand[0],
4583 magic + 1, &k, NULL);
4584 if (ret == 1 && k >= 0)
4586 if (ops[k].op == OP_LEA) {
4587 if (!g_func_pp->is_vararg)
4588 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
4591 snprintf(buf, sizeof(buf), "arg_%X",
4592 g_func_pp->argc_stack * 4);
4593 if (strstr(ops[k].operand[1].name, buf)
4594 || strstr(ops[k].operand[1].name, "arglist"))
4596 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
4597 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
4598 save_args &= ~(1 << arg);
4602 ferr(&ops[k], "va_list arg detection failed\n");
4604 // check for va_list from g_func_pp arg too
4605 else if (ops[k].op == OP_MOV
4606 && is_stack_access(&ops[k], &ops[k].operand[1]))
4608 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
4609 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
4611 ops[k].flags |= OPF_RMD | OPF_DONE;
4612 ops[j].flags |= OPF_RMD;
4613 ops[j].p_argpass = ret + 1;
4614 save_args &= ~(1 << arg);
4621 *save_arg_vars |= save_args;
4623 // tracking reg usage
4625 *regmask |= 1 << reg;
4628 if (!pp->is_unresolved) {
4630 for (; arg < pp->argc; arg++)
4631 if (pp->arg[arg].reg == NULL)
4634 magic = (magic & 0xffffff) | (arg << 24);
4637 if (ops[j].p_arggrp > arg_grp_current) {
4639 arg_grp_current = ops[j].p_arggrp;
4641 if (ops[j].p_argnum > 0)
4642 save_args_seen |= 1 << (ops[j].p_argnum - 1);
4645 if (arg < pp->argc) {
4646 ferr(po, "arg collect failed for '%s': %d/%d\n",
4647 pp->name, arg, pp->argc);
4651 if (arg_grp_current > *arg_grp)
4652 *arg_grp = arg_grp_current;
4657 static int collect_call_args(struct parsed_op *po, int i,
4658 struct parsed_proto *pp, int *regmask, int *save_arg_vars,
4661 // arg group is for cases when pushes for
4662 // multiple funcs are going on
4663 struct parsed_op *po_tmp;
4664 int save_arg_vars_current = 0;
4669 ret = collect_call_args_r(po, i, pp, regmask,
4670 &save_arg_vars_current, &arg_grp, 0, magic, 0, 0);
4675 // propagate arg_grp
4676 for (a = 0; a < pp->argc; a++) {
4677 if (pp->arg[a].reg != NULL)
4680 po_tmp = pp->arg[a].datap;
4681 while (po_tmp != NULL) {
4682 po_tmp->p_arggrp = arg_grp;
4683 if (po_tmp->p_argnext > 0)
4684 po_tmp = &ops[po_tmp->p_argnext];
4690 save_arg_vars[arg_grp] |= save_arg_vars_current;
4692 if (pp->is_unresolved) {
4694 pp->argc_stack += ret;
4695 for (a = 0; a < pp->argc; a++)
4696 if (pp->arg[a].type.name == NULL)
4697 pp->arg[a].type.name = strdup("int");
4703 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
4704 int regmask_now, int *regmask,
4705 int regmask_save_now, int *regmask_save,
4706 int *regmask_init, int regmask_arg)
4708 struct parsed_op *po;
4716 for (; i < opcnt; i++)
4719 if (cbits[i >> 3] & (1 << (i & 7)))
4721 cbits[i >> 3] |= (1 << (i & 7));
4723 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4724 if (po->flags & (OPF_RMD|OPF_DONE))
4726 if (po->btj != NULL) {
4727 for (j = 0; j < po->btj->count; j++) {
4728 check_i(po, po->btj->d[j].bt_i);
4729 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
4730 regmask_now, regmask, regmask_save_now, regmask_save,
4731 regmask_init, regmask_arg);
4736 check_i(po, po->bt_i);
4737 if (po->flags & OPF_CJMP)
4738 reg_use_pass(po->bt_i, opcnt, cbits,
4739 regmask_now, regmask, regmask_save_now, regmask_save,
4740 regmask_init, regmask_arg);
4746 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
4747 && !g_func_pp->is_userstack
4748 && po->operand[0].type == OPT_REG)
4750 reg = po->operand[0].reg;
4751 ferr_assert(po, reg >= 0);
4754 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
4755 if (regmask_now & (1 << reg)) {
4756 already_saved = regmask_save_now & (1 << reg);
4757 flags_set = OPF_RSAVE | OPF_DONE;
4760 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0);
4762 scan_for_pop(i + 1, opcnt, i + opcnt * 4, reg, 0, flags_set);
4765 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
4767 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
4772 ferr_assert(po, !already_saved);
4773 po->flags |= flags_set;
4775 if (regmask_now & (1 << reg)) {
4776 regmask_save_now |= (1 << reg);
4777 *regmask_save |= regmask_save_now;
4782 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
4783 reg = po->operand[0].reg;
4784 ferr_assert(po, reg >= 0);
4786 if (regmask_save_now & (1 << reg))
4787 regmask_save_now &= ~(1 << reg);
4789 regmask_now &= ~(1 << reg);
4792 else if (po->op == OP_CALL) {
4793 if ((po->regmask_dst & (1 << xAX))
4794 && !(po->regmask_dst & (1 << xDX)))
4796 if (po->flags & OPF_TAIL)
4797 // don't need eax, will do "return f();" or "f(); return;"
4798 po->regmask_dst &= ~(1 << xAX);
4800 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
4802 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
4805 po->regmask_dst &= ~(1 << xAX);
4809 // not "full stack" mode and have something in stack
4810 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
4811 ferr(po, "float stack is not empty on func call\n");
4814 if (po->flags & OPF_NOREGS)
4817 // if incomplete register is used, clear it on init to avoid
4818 // later use of uninitialized upper part in some situations
4819 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
4820 && po->operand[0].lmod != OPLM_DWORD)
4822 reg = po->operand[0].reg;
4823 ferr_assert(po, reg >= 0);
4825 if (!(regmask_now & (1 << reg)))
4826 *regmask_init |= 1 << reg;
4829 regmask_op = po->regmask_src | po->regmask_dst;
4831 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
4832 regmask_new &= ~(1 << xSP);
4833 if (g_bp_frame && !(po->flags & OPF_EBP_S))
4834 regmask_new &= ~(1 << xBP);
4836 if (regmask_new != 0)
4837 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
4839 if (regmask_op & (1 << xBP)) {
4840 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
4841 if (po->regmask_dst & (1 << xBP))
4842 // compiler decided to drop bp frame and use ebp as scratch
4843 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
4845 regmask_op &= ~(1 << xBP);
4849 if (po->flags & OPF_FPUSH) {
4850 if (regmask_now & mxST1)
4851 regmask_now |= mxSTa; // switch to "full stack" mode
4852 if (regmask_now & mxSTa)
4853 po->flags |= OPF_FSHIFT;
4854 if (!(regmask_now & mxST7_2)) {
4856 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
4860 regmask_now |= regmask_op;
4861 *regmask |= regmask_now;
4864 if (po->flags & OPF_FPOP) {
4865 if ((regmask_now & mxSTa) == 0)
4866 ferr(po, "float pop on empty stack?\n");
4867 if (regmask_now & (mxST7_2 | mxST1))
4868 po->flags |= OPF_FSHIFT;
4869 if (!(regmask_now & mxST7_2)) {
4871 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
4875 if (po->flags & OPF_TAIL) {
4876 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
4877 ferr(po, "float regs on tail: %x\n", regmask_now);
4879 // there is support for "conditional tailcall", sort of
4880 if (!(po->flags & OPF_CC))
4886 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
4890 for (i = 0; i < pp->argc; i++)
4891 if (pp->arg[i].reg == NULL)
4895 memmove(&pp->arg[i + 1], &pp->arg[i],
4896 sizeof(pp->arg[0]) * pp->argc_stack);
4897 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
4898 pp->arg[i].reg = strdup(reg);
4899 pp->arg[i].type.name = strdup("int");
4904 static void output_std_flags(FILE *fout, struct parsed_op *po,
4905 int *pfomask, const char *dst_opr_text)
4907 if (*pfomask & (1 << PFO_Z)) {
4908 fprintf(fout, "\n cond_z = (%s%s == 0);",
4909 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
4910 *pfomask &= ~(1 << PFO_Z);
4912 if (*pfomask & (1 << PFO_S)) {
4913 fprintf(fout, "\n cond_s = (%s%s < 0);",
4914 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
4915 *pfomask &= ~(1 << PFO_S);
4920 OPP_FORCE_NORETURN = (1 << 0),
4921 OPP_SIMPLE_ARGS = (1 << 1),
4922 OPP_ALIGN = (1 << 2),
4925 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
4928 const char *cconv = "";
4930 if (pp->is_fastcall)
4931 cconv = "__fastcall ";
4932 else if (pp->is_stdcall && pp->argc_reg == 0)
4933 cconv = "__stdcall ";
4935 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
4937 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
4938 fprintf(fout, "noreturn ");
4941 static void output_pp(FILE *fout, const struct parsed_proto *pp,
4946 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
4950 output_pp_attrs(fout, pp, flags);
4953 fprintf(fout, "%s", pp->name);
4958 for (i = 0; i < pp->argc; i++) {
4960 fprintf(fout, ", ");
4961 if (pp->arg[i].fptr != NULL && !(flags & OPP_SIMPLE_ARGS)) {
4963 output_pp(fout, pp->arg[i].fptr, 0);
4965 else if (pp->arg[i].type.is_retreg) {
4966 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
4969 fprintf(fout, "%s", pp->arg[i].type.name);
4971 fprintf(fout, " a%d", i + 1);
4974 if (pp->is_vararg) {
4976 fprintf(fout, ", ");
4977 fprintf(fout, "...");
4982 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
4988 snprintf(buf1, sizeof(buf1), "%d", grp);
4989 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
4994 static void gen_x_cleanup(int opcnt);
4996 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
4998 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
4999 struct parsed_opr *last_arith_dst = NULL;
5000 char buf1[256], buf2[256], buf3[256], cast[64];
5001 struct parsed_proto *pp, *pp_tmp;
5002 struct parsed_data *pd;
5004 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5005 unsigned char cbits[MAX_OPS / 8];
5006 const char *float_type;
5007 const char *float_st0;
5008 const char *float_st1;
5009 int need_float_stack = 0;
5010 int need_tmp_var = 0;
5014 int label_pending = 0;
5015 int need_double = 0;
5016 int regmask_save = 0; // regs saved/restored in this func
5017 int regmask_arg; // regs from this function args (fastcall, etc)
5018 int regmask_ret; // regs needed on ret
5019 int regmask_now; // temp
5020 int regmask_init = 0; // regs that need zero initialization
5021 int regmask_pp = 0; // regs used in complex push-pop graph
5022 int regmask = 0; // used regs
5032 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5033 g_stack_frame_used = 0;
5034 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5035 regmask_init = g_regmask_init;
5037 g_func_pp = proto_parse(fhdr, funcn, 0);
5038 if (g_func_pp == NULL)
5039 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5041 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5042 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5045 // - resolve all branches
5046 // - parse calls with labels
5047 resolve_branches_parse_calls(opcnt);
5050 // - handle ebp/esp frame, remove ops related to it
5051 scan_prologue_epilogue(opcnt);
5054 // - remove dead labels
5055 // - set regs needed at ret
5056 for (i = 0; i < opcnt; i++)
5058 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5063 if (ops[i].op == OP_RET)
5064 ops[i].regmask_src |= regmask_ret;
5068 // - process trivial calls
5069 for (i = 0; i < opcnt; i++)
5072 if (po->flags & (OPF_RMD|OPF_DONE))
5075 if (po->op == OP_CALL)
5077 pp = process_call_early(i, opcnt, &j);
5079 if (!(po->flags & OPF_ATAIL))
5080 // since we know the args, try to collect them
5081 if (collect_call_args_early(po, i, pp, ®mask) != 0)
5087 // commit esp adjust
5088 if (ops[j].op != OP_POP)
5089 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5091 for (l = 0; l < pp->argc_stack; l++)
5092 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5096 if (strstr(pp->ret_type.name, "int64"))
5099 po->flags |= OPF_DONE;
5105 // - process calls, stage 2
5106 // - handle some push/pop pairs
5107 // - scan for STD/CLD, propagate DF
5108 for (i = 0; i < opcnt; i++)
5111 if (po->flags & OPF_RMD)
5114 if (po->op == OP_CALL)
5116 if (!(po->flags & OPF_DONE)) {
5117 pp = process_call(i, opcnt);
5119 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5120 // since we know the args, collect them
5121 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5124 // for unresolved, collect after other passes
5128 ferr_assert(po, pp != NULL);
5130 po->regmask_src |= get_pp_arg_regmask_src(pp);
5131 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5133 if (po->regmask_dst & mxST0)
5134 po->flags |= OPF_FPUSH;
5136 if (strstr(pp->ret_type.name, "int64"))
5142 if (po->flags & OPF_DONE)
5145 if (po->op == OP_PUSH && !(po->flags & OPF_FARG)
5146 && !(po->flags & OPF_RSAVE) && po->operand[0].type == OPT_CONST)
5148 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5150 else if (po->op == OP_POP)
5151 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5152 else if (po->op == OP_STD) {
5153 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5154 scan_propagate_df(i + 1, opcnt);
5159 // - find POPs for PUSHes, rm both
5160 // - scan for all used registers
5161 memset(cbits, 0, sizeof(cbits));
5162 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5163 0, ®mask_save, ®mask_init, regmask_arg);
5166 // - find flag set ops for their users
5167 // - do unresolved calls
5168 // - declare indirect functions
5169 for (i = 0; i < opcnt; i++)
5172 if (po->flags & (OPF_RMD|OPF_DONE))
5175 if (po->flags & OPF_CC)
5177 int setters[16], cnt = 0, branched = 0;
5179 ret = scan_for_flag_set(i, i + opcnt * 6,
5180 &branched, setters, &cnt);
5181 if (ret < 0 || cnt <= 0)
5182 ferr(po, "unable to trace flag setter(s)\n");
5183 if (cnt > ARRAY_SIZE(setters))
5184 ferr(po, "too many flag setters\n");
5186 for (j = 0; j < cnt; j++)
5188 tmp_op = &ops[setters[j]]; // flag setter
5191 // to get nicer code, we try to delay test and cmp;
5192 // if we can't because of operand modification, or if we
5193 // have arith op, or branch, make it calculate flags explicitly
5194 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5196 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5197 pfomask = 1 << po->pfo;
5199 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5200 pfomask = 1 << po->pfo;
5203 // see if we'll be able to handle based on op result
5204 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5205 && po->pfo != PFO_Z && po->pfo != PFO_S
5206 && po->pfo != PFO_P)
5208 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5210 pfomask = 1 << po->pfo;
5213 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5214 propagate_lmod(tmp_op, &tmp_op->operand[0],
5215 &tmp_op->operand[1]);
5216 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5221 tmp_op->pfomask |= pfomask;
5222 cond_vars |= pfomask;
5224 // note: may overwrite, currently not a problem
5228 if (po->op == OP_RCL || po->op == OP_RCR
5229 || po->op == OP_ADC || po->op == OP_SBB)
5230 cond_vars |= 1 << PFO_C;
5236 cond_vars |= 1 << PFO_Z;
5240 if (po->operand[0].lmod == OPLM_DWORD)
5245 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
5250 // note: resolved non-reg calls are OPF_DONE already
5252 ferr_assert(po, pp != NULL);
5254 if (pp->is_unresolved) {
5255 int regmask_stack = 0;
5256 collect_call_args(po, i, pp, ®mask, save_arg_vars,
5259 // this is pretty rough guess:
5260 // see ecx and edx were pushed (and not their saved versions)
5261 for (arg = 0; arg < pp->argc; arg++) {
5262 if (pp->arg[arg].reg != NULL)
5265 tmp_op = pp->arg[arg].datap;
5267 ferr(po, "parsed_op missing for arg%d\n", arg);
5268 if (tmp_op->p_argnum == 0 && tmp_op->operand[0].type == OPT_REG)
5269 regmask_stack |= 1 << tmp_op->operand[0].reg;
5272 if (!((regmask_stack & (1 << xCX))
5273 && (regmask_stack & (1 << xDX))))
5275 if (pp->argc_stack != 0
5276 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5278 pp_insert_reg_arg(pp, "ecx");
5279 pp->is_fastcall = 1;
5280 regmask_init |= 1 << xCX;
5281 regmask |= 1 << xCX;
5283 if (pp->argc_stack != 0
5284 || ((regmask | regmask_arg) & (1 << xDX)))
5286 pp_insert_reg_arg(pp, "edx");
5287 regmask_init |= 1 << xDX;
5288 regmask |= 1 << xDX;
5292 // note: __cdecl doesn't fall into is_unresolved category
5293 if (pp->argc_stack > 0)
5299 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
5301 // <var> = offset <something>
5302 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5303 && !IS_START(po->operand[1].name, "off_"))
5305 if (!po->operand[0].pp->is_fptr)
5306 ferr(po, "%s not declared as fptr when it should be\n",
5307 po->operand[0].name);
5308 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5309 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5310 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5311 fnote(po, "var: %s\n", buf1);
5312 fnote(po, "func: %s\n", buf2);
5313 ferr(po, "^ mismatch\n");
5321 if (po->operand[0].lmod == OPLM_DWORD) {
5322 // 32bit division is common, look for it
5323 if (po->op == OP_DIV)
5324 ret = scan_for_reg_clear(i, xDX);
5326 ret = scan_for_cdq_edx(i);
5328 po->flags |= OPF_32BIT;
5337 po->flags |= OPF_RMD | OPF_DONE;
5347 if (po->operand[0].lmod == OPLM_QWORD)
5357 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5359 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5361 po->flags |= OPF_32BIT;
5370 float_type = need_double ? "double" : "float";
5371 need_float_stack = !!(regmask & mxST7_2);
5372 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
5373 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
5375 // output starts here
5377 // define userstack size
5378 if (g_func_pp->is_userstack) {
5379 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5380 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5381 fprintf(fout, "#endif\n");
5384 // the function itself
5385 ferr_assert(ops, !g_func_pp->is_fptr);
5386 output_pp(fout, g_func_pp,
5387 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5388 fprintf(fout, "\n{\n");
5390 // declare indirect functions
5391 for (i = 0; i < opcnt; i++) {
5393 if (po->flags & OPF_RMD)
5396 if (po->op == OP_CALL) {
5399 ferr(po, "NULL pp\n");
5401 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5402 if (pp->name[0] != 0) {
5403 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5404 memcpy(pp->name, "i_", 2);
5406 // might be declared already
5408 for (j = 0; j < i; j++) {
5409 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5410 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5420 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5423 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5424 fprintf(fout, ";\n");
5429 // output LUTs/jumptables
5430 for (i = 0; i < g_func_pd_cnt; i++) {
5432 fprintf(fout, " static const ");
5433 if (pd->type == OPT_OFFSET) {
5434 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5436 for (j = 0; j < pd->count; j++) {
5438 fprintf(fout, ", ");
5439 fprintf(fout, "&&%s", pd->d[j].u.label);
5443 fprintf(fout, "%s %s[] =\n { ",
5444 lmod_type_u(ops, pd->lmod), pd->label);
5446 for (j = 0; j < pd->count; j++) {
5448 fprintf(fout, ", ");
5449 fprintf(fout, "%u", pd->d[j].u.val);
5452 fprintf(fout, " };\n");
5456 // declare stack frame, va_arg
5458 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5459 if (g_func_lmods & (1 << OPLM_WORD))
5460 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5461 if (g_func_lmods & (1 << OPLM_BYTE))
5462 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5463 if (g_func_lmods & (1 << OPLM_QWORD))
5464 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5465 fprintf(fout, " } sf;\n");
5469 if (g_func_pp->is_userstack) {
5470 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5471 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5475 if (g_func_pp->is_vararg) {
5476 fprintf(fout, " va_list ap;\n");
5480 // declare arg-registers
5481 for (i = 0; i < g_func_pp->argc; i++) {
5482 if (g_func_pp->arg[i].reg != NULL) {
5483 reg = char_array_i(regs_r32,
5484 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5485 if (regmask & (1 << reg)) {
5486 if (g_func_pp->arg[i].type.is_retreg)
5487 fprintf(fout, " u32 %s = *r_%s;\n",
5488 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5490 fprintf(fout, " u32 %s = (u32)a%d;\n",
5491 g_func_pp->arg[i].reg, i + 1);
5494 if (g_func_pp->arg[i].type.is_retreg)
5495 ferr(ops, "retreg '%s' is unused?\n",
5496 g_func_pp->arg[i].reg);
5497 fprintf(fout, " // %s = a%d; // unused\n",
5498 g_func_pp->arg[i].reg, i + 1);
5504 // declare normal registers
5505 regmask_now = regmask & ~regmask_arg;
5506 regmask_now &= ~(1 << xSP);
5507 if (regmask_now & 0x00ff) {
5508 for (reg = 0; reg < 8; reg++) {
5509 if (regmask_now & (1 << reg)) {
5510 fprintf(fout, " u32 %s", regs_r32[reg]);
5511 if (regmask_init & (1 << reg))
5512 fprintf(fout, " = 0");
5513 fprintf(fout, ";\n");
5519 if (regmask_now & 0xff00) {
5520 for (reg = 8; reg < 16; reg++) {
5521 if (regmask_now & (1 << reg)) {
5522 fprintf(fout, " mmxr %s", regs_r32[reg]);
5523 if (regmask_init & (1 << reg))
5524 fprintf(fout, " = { 0, }");
5525 fprintf(fout, ";\n");
5531 if (need_float_stack) {
5532 fprintf(fout, " %s f_st[8];\n", float_type);
5533 fprintf(fout, " int f_stp = 0;\n");
5537 if (regmask_now & 0xff0000) {
5538 for (reg = 16; reg < 24; reg++) {
5539 if (regmask_now & (1 << reg)) {
5540 fprintf(fout, " %s f_st%d", float_type, reg - 16);
5541 if (regmask_init & (1 << reg))
5542 fprintf(fout, " = 0");
5543 fprintf(fout, ";\n");
5551 for (reg = 0; reg < 8; reg++) {
5552 if (regmask_save & (1 << reg)) {
5553 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
5559 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
5560 if (save_arg_vars[i] == 0)
5562 for (reg = 0; reg < 32; reg++) {
5563 if (save_arg_vars[i] & (1 << reg)) {
5564 fprintf(fout, " u32 %s;\n",
5565 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
5571 // declare push-pop temporaries
5573 for (reg = 0; reg < 8; reg++) {
5574 if (regmask_pp & (1 << reg)) {
5575 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
5582 for (i = 0; i < 8; i++) {
5583 if (cond_vars & (1 << i)) {
5584 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
5591 fprintf(fout, " u32 tmp;\n");
5596 fprintf(fout, " u64 tmp64;\n");
5601 fprintf(fout, "\n");
5603 // do stack clear, if needed
5604 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
5606 if (g_stack_clear_len != 0) {
5607 if (g_stack_clear_len <= 4) {
5608 for (i = 0; i < g_stack_clear_len; i++)
5609 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
5610 fprintf(fout, "0;\n");
5613 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
5614 g_stack_clear_start, g_stack_clear_len * 4);
5618 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
5621 if (g_func_pp->is_vararg) {
5622 if (g_func_pp->argc_stack == 0)
5623 ferr(ops, "vararg func without stack args?\n");
5624 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
5628 for (i = 0; i < opcnt; i++)
5630 if (g_labels[i] != NULL) {
5631 fprintf(fout, "\n%s:\n", g_labels[i]);
5634 delayed_flag_op = NULL;
5635 last_arith_dst = NULL;
5639 if (po->flags & OPF_RMD)
5644 #define assert_operand_cnt(n_) \
5645 if (po->operand_cnt != n_) \
5646 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
5648 // conditional/flag using op?
5649 if (po->flags & OPF_CC)
5655 // we go through all this trouble to avoid using parsed_flag_op,
5656 // which makes generated code much nicer
5657 if (delayed_flag_op != NULL)
5659 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
5660 po->pfo, po->pfo_inv);
5663 else if (last_arith_dst != NULL
5664 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
5665 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
5668 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5669 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
5670 last_arith_dst->lmod, buf3);
5673 else if (tmp_op != NULL) {
5674 // use preprocessed flag calc results
5675 if (!(tmp_op->pfomask & (1 << po->pfo)))
5676 ferr(po, "not prepared for pfo %d\n", po->pfo);
5678 // note: pfo_inv was not yet applied
5679 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
5680 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
5683 ferr(po, "all methods of finding comparison failed\n");
5686 if (po->flags & OPF_JMP) {
5687 fprintf(fout, " if %s", buf1);
5689 else if (po->op == OP_RCL || po->op == OP_RCR
5690 || po->op == OP_ADC || po->op == OP_SBB)
5693 fprintf(fout, " cond_%s = %s;\n",
5694 parsed_flag_op_names[po->pfo], buf1);
5696 else if (po->flags & OPF_DATA) { // SETcc
5697 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
5698 fprintf(fout, " %s = %s;", buf2, buf1);
5701 ferr(po, "unhandled conditional op\n");
5705 pfomask = po->pfomask;
5707 if (po->flags & (OPF_REPZ|OPF_REPNZ)) {
5708 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
5709 ret = try_resolve_const(i, &opr, opcnt * 7 + i, &uval);
5711 if (ret != 1 || uval == 0) {
5712 // we need initial flags for ecx=0 case..
5713 if (i > 0 && ops[i - 1].op == OP_XOR
5714 && IS(ops[i - 1].operand[0].name,
5715 ops[i - 1].operand[1].name))
5717 fprintf(fout, " cond_z = ");
5718 if (pfomask & (1 << PFO_C))
5719 fprintf(fout, "cond_c = ");
5720 fprintf(fout, "0;\n");
5722 else if (last_arith_dst != NULL) {
5723 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
5724 out_test_for_cc(buf1, sizeof(buf1), po, PFO_Z, 0,
5725 last_arith_dst->lmod, buf3);
5726 fprintf(fout, " cond_z = %s;\n", buf1);
5729 ferr(po, "missing initial ZF\n");
5736 assert_operand_cnt(2);
5737 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5738 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5739 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
5740 fprintf(fout, " %s = %s;", buf1,
5741 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5746 assert_operand_cnt(2);
5747 po->operand[1].lmod = OPLM_DWORD; // always
5748 fprintf(fout, " %s = %s;",
5749 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5750 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5755 assert_operand_cnt(2);
5756 fprintf(fout, " %s = %s;",
5757 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5758 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5762 assert_operand_cnt(2);
5763 switch (po->operand[1].lmod) {
5765 strcpy(buf3, "(s8)");
5768 strcpy(buf3, "(s16)");
5771 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
5773 fprintf(fout, " %s = %s;",
5774 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5775 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5780 assert_operand_cnt(2);
5781 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5782 fprintf(fout, " tmp = %s;",
5783 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
5784 fprintf(fout, " %s = %s;",
5785 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5786 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5787 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5788 fprintf(fout, " %s = %stmp;",
5789 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
5790 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
5791 snprintf(g_comment, sizeof(g_comment), "xchg");
5795 assert_operand_cnt(1);
5796 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5797 fprintf(fout, " %s = ~%s;", buf1, buf1);
5801 assert_operand_cnt(2);
5802 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5803 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
5804 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
5805 strcpy(g_comment, "xlat");
5809 assert_operand_cnt(2);
5810 fprintf(fout, " %s = (s32)%s >> 31;",
5811 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5812 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5813 strcpy(g_comment, "cdq");
5817 assert_operand_cnt(1);
5818 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5819 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
5823 if (po->flags & OPF_REP) {
5824 assert_operand_cnt(3);
5829 assert_operand_cnt(2);
5830 fprintf(fout, " %s = %sesi; esi %c= %d;",
5831 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
5832 lmod_cast_u_ptr(po, po->operand[1].lmod),
5833 (po->flags & OPF_DF) ? '-' : '+',
5834 lmod_bytes(po, po->operand[1].lmod));
5835 strcpy(g_comment, "lods");
5840 if (po->flags & OPF_REP) {
5841 assert_operand_cnt(3);
5842 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
5843 (po->flags & OPF_DF) ? '-' : '+',
5844 lmod_bytes(po, po->operand[1].lmod));
5845 fprintf(fout, " %sedi = eax;",
5846 lmod_cast_u_ptr(po, po->operand[1].lmod));
5847 strcpy(g_comment, "rep stos");
5850 assert_operand_cnt(2);
5851 fprintf(fout, " %sedi = eax; edi %c= %d;",
5852 lmod_cast_u_ptr(po, po->operand[1].lmod),
5853 (po->flags & OPF_DF) ? '-' : '+',
5854 lmod_bytes(po, po->operand[1].lmod));
5855 strcpy(g_comment, "stos");
5860 j = lmod_bytes(po, po->operand[0].lmod);
5861 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
5862 l = (po->flags & OPF_DF) ? '-' : '+';
5863 if (po->flags & OPF_REP) {
5864 assert_operand_cnt(3);
5866 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
5869 " %sedi = %sesi;", buf1, buf1);
5870 strcpy(g_comment, "rep movs");
5873 assert_operand_cnt(2);
5874 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
5875 buf1, buf1, l, j, l, j);
5876 strcpy(g_comment, "movs");
5881 // repe ~ repeat while ZF=1
5882 j = lmod_bytes(po, po->operand[0].lmod);
5883 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
5884 l = (po->flags & OPF_DF) ? '-' : '+';
5885 if (po->flags & OPF_REP) {
5886 assert_operand_cnt(3);
5888 " for (; ecx != 0; ecx--) {\n");
5889 if (pfomask & (1 << PFO_C)) {
5892 " cond_c = %sesi < %sedi;\n", buf1, buf1);
5893 pfomask &= ~(1 << PFO_C);
5896 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
5897 buf1, buf1, l, j, l, j);
5899 " if (cond_z %s 0) break;\n",
5900 (po->flags & OPF_REPZ) ? "==" : "!=");
5903 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
5904 (po->flags & OPF_REPZ) ? "e" : "ne");
5907 assert_operand_cnt(2);
5909 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
5910 buf1, buf1, l, j, l, j);
5911 strcpy(g_comment, "cmps");
5913 pfomask &= ~(1 << PFO_Z);
5914 last_arith_dst = NULL;
5915 delayed_flag_op = NULL;
5919 // only does ZF (for now)
5920 // repe ~ repeat while ZF=1
5921 j = lmod_bytes(po, po->operand[1].lmod);
5922 l = (po->flags & OPF_DF) ? '-' : '+';
5923 if (po->flags & OPF_REP) {
5924 assert_operand_cnt(3);
5926 " for (; ecx != 0; ecx--) {\n");
5928 " cond_z = (%seax == %sedi); edi %c= %d;\n",
5929 lmod_cast_u(po, po->operand[1].lmod),
5930 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
5932 " if (cond_z %s 0) break;\n",
5933 (po->flags & OPF_REPZ) ? "==" : "!=");
5936 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
5937 (po->flags & OPF_REPZ) ? "e" : "ne");
5940 assert_operand_cnt(2);
5941 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
5942 lmod_cast_u(po, po->operand[1].lmod),
5943 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
5944 strcpy(g_comment, "scas");
5946 pfomask &= ~(1 << PFO_Z);
5947 last_arith_dst = NULL;
5948 delayed_flag_op = NULL;
5951 // arithmetic w/flags
5953 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
5954 goto dualop_arith_const;
5955 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5959 propagate_lmod(po, &po->operand[0], &po->operand[1]);
5960 if (po->operand[1].type == OPT_CONST) {
5961 j = lmod_bytes(po, po->operand[0].lmod);
5962 if (((1ull << j * 8) - 1) == po->operand[1].val)
5963 goto dualop_arith_const;
5968 assert_operand_cnt(2);
5969 fprintf(fout, " %s %s= %s;",
5970 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5972 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
5973 output_std_flags(fout, po, &pfomask, buf1);
5974 last_arith_dst = &po->operand[0];
5975 delayed_flag_op = NULL;
5979 // and 0, or ~0 used instead mov
5980 assert_operand_cnt(2);
5981 fprintf(fout, " %s = %s;",
5982 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
5983 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
5984 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
5985 output_std_flags(fout, po, &pfomask, buf1);
5986 last_arith_dst = &po->operand[0];
5987 delayed_flag_op = NULL;
5992 assert_operand_cnt(2);
5993 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
5994 if (pfomask & (1 << PFO_C)) {
5995 if (po->operand[1].type == OPT_CONST) {
5996 l = lmod_bytes(po, po->operand[0].lmod) * 8;
5997 j = po->operand[1].val;
6000 if (po->op == OP_SHL)
6004 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6008 ferr(po, "zero shift?\n");
6012 pfomask &= ~(1 << PFO_C);
6014 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6015 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6016 if (po->operand[1].type != OPT_CONST)
6017 fprintf(fout, " & 0x1f");
6019 output_std_flags(fout, po, &pfomask, buf1);
6020 last_arith_dst = &po->operand[0];
6021 delayed_flag_op = NULL;
6025 assert_operand_cnt(2);
6026 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6027 fprintf(fout, " %s = %s%s >> %s;", buf1,
6028 lmod_cast_s(po, po->operand[0].lmod), buf1,
6029 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6030 output_std_flags(fout, po, &pfomask, buf1);
6031 last_arith_dst = &po->operand[0];
6032 delayed_flag_op = NULL;
6037 assert_operand_cnt(3);
6038 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6039 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6040 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6041 if (po->operand[2].type != OPT_CONST) {
6042 // no handling for "undefined" case, hopefully not needed
6043 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6046 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6047 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6048 if (po->op == OP_SHLD) {
6049 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6050 buf1, buf3, buf1, buf2, l, buf3);
6051 strcpy(g_comment, "shld");
6054 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6055 buf1, buf3, buf1, buf2, l, buf3);
6056 strcpy(g_comment, "shrd");
6058 output_std_flags(fout, po, &pfomask, buf1);
6059 last_arith_dst = &po->operand[0];
6060 delayed_flag_op = NULL;
6065 assert_operand_cnt(2);
6066 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6067 if (po->operand[1].type == OPT_CONST) {
6068 j = po->operand[1].val;
6069 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6070 fprintf(fout, po->op == OP_ROL ?
6071 " %s = (%s << %d) | (%s >> %d);" :
6072 " %s = (%s >> %d) | (%s << %d);",
6073 buf1, buf1, j, buf1,
6074 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6078 output_std_flags(fout, po, &pfomask, buf1);
6079 last_arith_dst = &po->operand[0];
6080 delayed_flag_op = NULL;
6085 assert_operand_cnt(2);
6086 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6087 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6088 if (po->operand[1].type == OPT_CONST) {
6089 j = po->operand[1].val % l;
6091 ferr(po, "zero rotate\n");
6092 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6093 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6094 if (po->op == OP_RCL) {
6096 " %s = (%s << %d) | (cond_c << %d)",
6097 buf1, buf1, j, j - 1);
6099 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6103 " %s = (%s >> %d) | (cond_c << %d)",
6104 buf1, buf1, j, l - j);
6106 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6108 fprintf(fout, ";\n");
6109 fprintf(fout, " cond_c = tmp;");
6113 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6114 output_std_flags(fout, po, &pfomask, buf1);
6115 last_arith_dst = &po->operand[0];
6116 delayed_flag_op = NULL;
6120 assert_operand_cnt(2);
6121 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6122 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6123 // special case for XOR
6124 if (pfomask & (1 << PFO_BE)) { // weird, but it happens..
6125 fprintf(fout, " cond_be = 1;\n");
6126 pfomask &= ~(1 << PFO_BE);
6128 fprintf(fout, " %s = 0;",
6129 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6130 last_arith_dst = &po->operand[0];
6131 delayed_flag_op = NULL;
6137 assert_operand_cnt(2);
6138 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6139 if (pfomask & (1 << PFO_C)) {
6140 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6141 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6142 if (po->operand[0].lmod == OPLM_DWORD) {
6143 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6144 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6145 fprintf(fout, " %s = (u32)tmp64;",
6146 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6147 strcat(g_comment, " add64");
6150 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6151 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6152 fprintf(fout, " %s += %s;",
6153 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6156 pfomask &= ~(1 << PFO_C);
6157 output_std_flags(fout, po, &pfomask, buf1);
6158 last_arith_dst = &po->operand[0];
6159 delayed_flag_op = NULL;
6165 assert_operand_cnt(2);
6166 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6167 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6168 for (j = 0; j <= PFO_LE; j++) {
6169 if (!(pfomask & (1 << j)))
6171 if (j == PFO_Z || j == PFO_S)
6174 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
6175 fprintf(fout, " cond_%s = %s;\n",
6176 parsed_flag_op_names[j], buf1);
6177 pfomask &= ~(1 << j);
6184 assert_operand_cnt(2);
6185 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6186 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6187 if (po->op == OP_SBB
6188 && IS(po->operand[0].name, po->operand[1].name))
6190 // avoid use of unitialized var
6191 fprintf(fout, " %s = -cond_c;", buf1);
6192 // carry remains what it was
6193 pfomask &= ~(1 << PFO_C);
6196 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6197 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6199 output_std_flags(fout, po, &pfomask, buf1);
6200 last_arith_dst = &po->operand[0];
6201 delayed_flag_op = NULL;
6205 assert_operand_cnt(2);
6206 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6207 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6208 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6210 output_std_flags(fout, po, &pfomask, buf1);
6211 last_arith_dst = &po->operand[0];
6212 delayed_flag_op = NULL;
6213 strcat(g_comment, " bsf");
6217 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6218 for (j = 0; j <= PFO_LE; j++) {
6219 if (!(pfomask & (1 << j)))
6221 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6224 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0);
6225 fprintf(fout, " cond_%s = %s;\n",
6226 parsed_flag_op_names[j], buf1);
6227 pfomask &= ~(1 << j);
6233 if (pfomask & (1 << PFO_C))
6234 // carry is unaffected by inc/dec.. wtf?
6235 ferr(po, "carry propagation needed\n");
6237 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6238 if (po->operand[0].type == OPT_REG) {
6239 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6240 fprintf(fout, " %s%s;", buf1, buf2);
6243 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6244 fprintf(fout, " %s %s= 1;", buf1, buf2);
6246 output_std_flags(fout, po, &pfomask, buf1);
6247 last_arith_dst = &po->operand[0];
6248 delayed_flag_op = NULL;
6252 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6253 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6254 fprintf(fout, " %s = -%s%s;", buf1,
6255 lmod_cast_s(po, po->operand[0].lmod), buf2);
6256 last_arith_dst = &po->operand[0];
6257 delayed_flag_op = NULL;
6258 if (pfomask & (1 << PFO_C)) {
6259 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6260 pfomask &= ~(1 << PFO_C);
6265 if (po->operand_cnt == 2) {
6266 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6269 if (po->operand_cnt == 3)
6270 ferr(po, "TODO imul3\n");
6273 assert_operand_cnt(1);
6274 switch (po->operand[0].lmod) {
6276 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6277 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6278 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6279 fprintf(fout, " edx = tmp64 >> 32;\n");
6280 fprintf(fout, " eax = tmp64;");
6283 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6284 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6285 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6289 ferr(po, "TODO: unhandled mul type\n");
6292 last_arith_dst = NULL;
6293 delayed_flag_op = NULL;
6298 assert_operand_cnt(1);
6299 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6300 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6301 po->op == OP_IDIV));
6302 switch (po->operand[0].lmod) {
6304 if (po->flags & OPF_32BIT)
6305 snprintf(buf2, sizeof(buf2), "%seax", cast);
6307 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6308 snprintf(buf2, sizeof(buf2), "%stmp64",
6309 (po->op == OP_IDIV) ? "(s64)" : "");
6311 if (po->operand[0].type == OPT_REG
6312 && po->operand[0].reg == xDX)
6314 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6315 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6318 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6319 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6323 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6324 snprintf(buf2, sizeof(buf2), "%stmp",
6325 (po->op == OP_IDIV) ? "(s32)" : "");
6326 if (po->operand[0].type == OPT_REG
6327 && po->operand[0].reg == xDX)
6329 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6331 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6335 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6337 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6340 strcat(g_comment, " div16");
6343 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6345 last_arith_dst = NULL;
6346 delayed_flag_op = NULL;
6351 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6353 for (j = 0; j < 8; j++) {
6354 if (pfomask & (1 << j)) {
6355 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6356 fprintf(fout, " cond_%s = %s;",
6357 parsed_flag_op_names[j], buf1);
6364 last_arith_dst = NULL;
6365 delayed_flag_op = po;
6369 // SETcc - should already be handled
6372 // note: we reuse OP_Jcc for SETcc, only flags differ
6374 fprintf(fout, "\n goto %s;", po->operand[0].name);
6378 fprintf(fout, " if (ecx == 0)\n");
6379 fprintf(fout, " goto %s;", po->operand[0].name);
6380 strcat(g_comment, " jecxz");
6384 fprintf(fout, " if (--ecx != 0)\n");
6385 fprintf(fout, " goto %s;", po->operand[0].name);
6386 strcat(g_comment, " loop");
6390 assert_operand_cnt(1);
6391 last_arith_dst = NULL;
6392 delayed_flag_op = NULL;
6394 if (po->operand[0].type == OPT_REGMEM) {
6395 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6398 ferr(po, "parse failure for jmp '%s'\n",
6399 po->operand[0].name);
6400 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6403 else if (po->operand[0].type != OPT_LABEL)
6404 ferr(po, "unhandled jmp type\n");
6406 fprintf(fout, " goto %s;", po->operand[0].name);
6410 assert_operand_cnt(1);
6412 my_assert_not(pp, NULL);
6415 if (po->flags & OPF_CC) {
6416 // we treat conditional branch to another func
6417 // (yes such code exists..) as conditional tailcall
6419 fprintf(fout, " {\n");
6422 if (pp->is_fptr && !pp->is_arg) {
6423 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6424 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6426 if (pp->is_unresolved)
6427 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6428 buf3, asmfn, po->asmln, pp->name);
6431 fprintf(fout, "%s", buf3);
6432 if (strstr(pp->ret_type.name, "int64")) {
6433 if (po->flags & OPF_TAIL)
6434 ferr(po, "int64 and tail?\n");
6435 fprintf(fout, "tmp64 = ");
6437 else if (!IS(pp->ret_type.name, "void")) {
6438 if (po->flags & OPF_TAIL) {
6439 if (regmask_ret & mxAX) {
6440 fprintf(fout, "return ");
6441 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6442 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6444 else if (regmask_ret & mxST0)
6445 ferr(po, "float tailcall\n");
6447 else if (po->regmask_dst & mxAX) {
6448 fprintf(fout, "eax = ");
6449 if (pp->ret_type.is_ptr)
6450 fprintf(fout, "(u32)");
6452 else if (po->regmask_dst & mxST0) {
6453 ferr_assert(po, po->flags & OPF_FPUSH);
6454 if (need_float_stack)
6455 fprintf(fout, "f_st[--f_stp & 7] = ");
6457 fprintf(fout, "f_st0 = ");
6461 if (pp->name[0] == 0)
6462 ferr(po, "missing pp->name\n");
6463 fprintf(fout, "%s%s(", pp->name,
6464 pp->has_structarg ? "_sa" : "");
6466 if (po->flags & OPF_ATAIL) {
6467 if (pp->argc_stack != g_func_pp->argc_stack
6468 || (pp->argc_stack > 0
6469 && pp->is_stdcall != g_func_pp->is_stdcall))
6470 ferr(po, "incompatible tailcall\n");
6471 if (g_func_pp->has_retreg)
6472 ferr(po, "TODO: retreg+tailcall\n");
6474 for (arg = j = 0; arg < pp->argc; arg++) {
6476 fprintf(fout, ", ");
6479 if (pp->arg[arg].type.is_ptr)
6480 snprintf(cast, sizeof(cast), "(%s)",
6481 pp->arg[arg].type.name);
6483 if (pp->arg[arg].reg != NULL) {
6484 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6488 for (; j < g_func_pp->argc; j++)
6489 if (g_func_pp->arg[j].reg == NULL)
6491 fprintf(fout, "%sa%d", cast, j + 1);
6496 for (arg = 0; arg < pp->argc; arg++) {
6498 fprintf(fout, ", ");
6501 if (pp->arg[arg].type.is_ptr)
6502 snprintf(cast, sizeof(cast), "(%s)",
6503 pp->arg[arg].type.name);
6505 if (pp->arg[arg].reg != NULL) {
6506 if (pp->arg[arg].type.is_retreg)
6507 fprintf(fout, "&%s", pp->arg[arg].reg);
6509 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6514 tmp_op = pp->arg[arg].datap;
6516 ferr(po, "parsed_op missing for arg%d\n", arg);
6518 if (tmp_op->flags & OPF_VAPUSH) {
6519 fprintf(fout, "ap");
6521 else if (tmp_op->p_argpass != 0) {
6522 fprintf(fout, "a%d", tmp_op->p_argpass);
6524 else if (tmp_op->p_argnum != 0) {
6525 fprintf(fout, "%s%s", cast,
6526 saved_arg_name(buf1, sizeof(buf1),
6527 tmp_op->p_arggrp, tmp_op->p_argnum));
6531 out_src_opr(buf1, sizeof(buf1),
6532 tmp_op, &tmp_op->operand[0], cast, 0));
6536 fprintf(fout, ");");
6538 if (strstr(pp->ret_type.name, "int64")) {
6539 fprintf(fout, "\n");
6540 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
6541 fprintf(fout, "%seax = tmp64;", buf3);
6544 if (pp->is_unresolved) {
6545 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
6547 strcat(g_comment, buf2);
6550 if (po->flags & OPF_TAIL) {
6552 if (i == opcnt - 1 || pp->is_noreturn)
6554 else if (IS(pp->ret_type.name, "void"))
6556 else if (!(regmask_ret & (1 << xAX)))
6558 // else already handled as 'return f()'
6561 fprintf(fout, "\n%sreturn;", buf3);
6562 strcat(g_comment, " ^ tailcall");
6565 strcat(g_comment, " tailcall");
6567 if ((regmask_ret & (1 << xAX))
6568 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
6570 ferr(po, "int func -> void func tailcall?\n");
6573 if (pp->is_noreturn)
6574 strcat(g_comment, " noreturn");
6575 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
6576 strcat(g_comment, " argframe");
6577 if (po->flags & OPF_CC)
6578 strcat(g_comment, " cond");
6580 if (po->flags & OPF_CC)
6581 fprintf(fout, "\n }");
6583 delayed_flag_op = NULL;
6584 last_arith_dst = NULL;
6588 if (g_func_pp->is_vararg)
6589 fprintf(fout, " va_end(ap);\n");
6590 if (g_func_pp->has_retreg) {
6591 for (arg = 0; arg < g_func_pp->argc; arg++)
6592 if (g_func_pp->arg[arg].type.is_retreg)
6593 fprintf(fout, " *r_%s = %s;\n",
6594 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
6597 if (!(regmask_ret & (1 << xAX))) {
6598 if (i != opcnt - 1 || label_pending)
6599 fprintf(fout, " return;");
6601 else if (g_func_pp->ret_type.is_ptr) {
6602 fprintf(fout, " return (%s)eax;",
6603 g_func_pp->ret_type.name);
6605 else if (IS(g_func_pp->ret_type.name, "__int64"))
6606 fprintf(fout, " return ((u64)edx << 32) | eax;");
6608 fprintf(fout, " return eax;");
6610 last_arith_dst = NULL;
6611 delayed_flag_op = NULL;
6615 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6616 if (po->p_argnum != 0) {
6617 // special case - saved func arg
6618 fprintf(fout, " %s = %s;",
6619 saved_arg_name(buf2, sizeof(buf2),
6620 po->p_arggrp, po->p_argnum), buf1);
6623 else if (po->flags & OPF_RSAVE) {
6624 fprintf(fout, " s_%s = %s;", buf1, buf1);
6627 else if (po->flags & OPF_PPUSH) {
6629 ferr_assert(po, tmp_op != NULL);
6630 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
6631 fprintf(fout, " pp_%s = %s;", buf2, buf1);
6634 else if (g_func_pp->is_userstack) {
6635 fprintf(fout, " *(--esp) = %s;", buf1);
6638 if (!(g_ida_func_attr & IDAFA_NORETURN))
6639 ferr(po, "stray push encountered\n");
6644 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6645 if (po->flags & OPF_RSAVE) {
6646 fprintf(fout, " %s = s_%s;", buf1, buf1);
6649 else if (po->flags & OPF_PPUSH) {
6650 // push/pop graph / non-const
6651 ferr_assert(po, po->datap == NULL);
6652 fprintf(fout, " %s = pp_%s;", buf1, buf1);
6655 else if (po->datap != NULL) {
6658 fprintf(fout, " %s = %s;", buf1,
6659 out_src_opr(buf2, sizeof(buf2),
6660 tmp_op, &tmp_op->operand[0],
6661 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6664 else if (g_func_pp->is_userstack) {
6665 fprintf(fout, " %s = *esp++;", buf1);
6669 ferr(po, "stray pop encountered\n");
6679 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6680 fprintf(fout, " tmp64 = (s64)tmp64 %s= LOBYTE(ecx);\n",
6681 po->op == OPP_ALLSHL ? "<<" : ">>");
6682 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
6683 strcat(g_comment, po->op == OPP_ALLSHL
6684 ? " allshl" : " allshr");
6689 if (need_float_stack) {
6690 out_src_opr_float(buf1, sizeof(buf1),
6691 po, &po->operand[0], 1);
6692 if (po->regmask_src & mxSTa) {
6693 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
6697 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
6700 if (po->flags & OPF_FSHIFT)
6701 fprintf(fout, " f_st1 = f_st0;");
6702 if (po->operand[0].type == OPT_REG
6703 && po->operand[0].reg == xST0)
6705 strcat(g_comment, " fld st");
6708 fprintf(fout, " f_st0 = %s;",
6709 out_src_opr_float(buf1, sizeof(buf1),
6710 po, &po->operand[0], 0));
6712 strcat(g_comment, " fld");
6716 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6717 lmod_cast(po, po->operand[0].lmod, 1), 0);
6718 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
6719 if (need_float_stack) {
6720 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
6723 if (po->flags & OPF_FSHIFT)
6724 fprintf(fout, " f_st1 = f_st0;");
6725 fprintf(fout, " f_st0 = %s;", buf2);
6727 strcat(g_comment, " fild");
6731 if (need_float_stack)
6732 fprintf(fout, " f_st[--f_stp & 7] = ");
6734 if (po->flags & OPF_FSHIFT)
6735 fprintf(fout, " f_st1 = f_st0;");
6736 fprintf(fout, " f_st0 = ");
6738 switch (po->operand[0].val) {
6739 case X87_CONST_1: fprintf(fout, "1.0;"); break;
6740 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
6741 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
6742 default: ferr(po, "TODO\n"); break;
6747 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
6749 dead_dst = po->operand[0].type == OPT_REG
6750 && po->operand[0].reg == xST0;
6751 if (need_float_stack) {
6753 fprintf(fout, " %s = f_st[f_stp & 7];", buf1);
6754 if (po->flags & OPF_FSHIFT)
6755 fprintf(fout, " f_stp++;");
6759 fprintf(fout, " %s = f_st0;", buf1);
6760 if (po->flags & OPF_FSHIFT)
6761 fprintf(fout, " f_st0 = f_st1;");
6763 if (dead_dst && !(po->flags & OPF_FSHIFT))
6766 strcat(g_comment, " fst");
6773 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
6775 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
6777 dead_dst = (po->flags & OPF_FPOP)
6778 && po->operand[0].type == OPT_REG
6779 && po->operand[0].reg == xST0;
6781 case OP_FADD: j = '+'; break;
6782 case OP_FDIV: j = '/'; break;
6783 case OP_FMUL: j = '*'; break;
6784 case OP_FSUB: j = '-'; break;
6785 default: j = 'x'; break;
6787 if (need_float_stack) {
6789 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
6790 if (po->flags & OPF_FSHIFT)
6791 fprintf(fout, " f_stp++;");
6794 if (po->flags & OPF_FSHIFT) {
6795 // note: assumes only 2 regs handled
6797 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
6799 fprintf(fout, " f_st0 = f_st1;");
6802 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
6804 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
6809 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
6811 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
6813 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
6815 dead_dst = (po->flags & OPF_FPOP)
6816 && po->operand[0].type == OPT_REG
6817 && po->operand[0].reg == xST0;
6818 j = po->op == OP_FDIVR ? '/' : '-';
6819 if (need_float_stack) {
6821 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
6822 if (po->flags & OPF_FSHIFT)
6823 fprintf(fout, " f_stp++;");
6826 if (po->flags & OPF_FSHIFT) {
6828 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
6830 fprintf(fout, " f_st0 = f_st1;");
6833 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
6835 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
6843 case OP_FIADD: j = '+'; break;
6844 case OP_FIDIV: j = '/'; break;
6845 case OP_FIMUL: j = '*'; break;
6846 case OP_FISUB: j = '-'; break;
6847 default: j = 'x'; break;
6849 fprintf(fout, " %s %c= (%s)%s;", float_st0,
6851 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6852 lmod_cast(po, po->operand[0].lmod, 1), 0));
6857 fprintf(fout, " %s = %s %c %s;", float_st0,
6858 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
6860 po->op == OP_FIDIVR ? '/' : '-', float_st0);
6864 fprintf(fout, " %s = -%s;", float_st0, float_st0);
6868 fprintf(fout, " %s = cos%s(%s);", float_st0,
6869 need_double ? "" : "f", float_st0);
6873 if (need_float_stack) {
6874 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
6875 need_double ? "" : "f", float_st1, float_st0);
6876 fprintf(fout, " f_stp++;");
6879 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
6880 need_double ? "" : "f");
6885 if (need_float_stack) {
6886 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
6887 float_st1, need_double ? "" : "f", float_st0);
6888 fprintf(fout, " f_stp++;");
6891 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
6892 need_double ? "" : "f");
6897 fprintf(fout, " %s = sin%s(%s);", float_st0,
6898 need_double ? "" : "f", float_st0);
6902 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
6903 need_double ? "" : "f", float_st0);
6907 dead_dst = po->operand[0].type == OPT_REG
6908 && po->operand[0].reg == xST0;
6910 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
6912 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
6913 float_st0, float_st0, buf1, buf1);
6914 strcat(g_comment, " fxch");
6921 ferr_assert(po, po->flags & OPF_32BIT);
6922 fprintf(fout, " eax = (s32)%s;", float_st0);
6923 if (po->flags & OPF_FSHIFT) {
6924 if (need_float_stack)
6925 fprintf(fout, " f_stp++;");
6927 fprintf(fout, " f_st0 = f_st1;");
6929 strcat(g_comment, " ftol");
6934 strcpy(g_comment, " (emms)");
6939 ferr(po, "unhandled op type %d, flags %x\n",
6944 if (g_comment[0] != 0) {
6945 char *p = g_comment;
6946 while (my_isblank(*p))
6948 fprintf(fout, " // %s", p);
6953 fprintf(fout, "\n");
6955 // some sanity checking
6956 if (po->flags & OPF_REP) {
6957 if (po->op != OP_STOS && po->op != OP_MOVS
6958 && po->op != OP_CMPS && po->op != OP_SCAS)
6959 ferr(po, "unexpected rep\n");
6960 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
6961 && (po->op == OP_CMPS || po->op == OP_SCAS))
6962 ferr(po, "cmps/scas with plain rep\n");
6964 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
6965 && po->op != OP_CMPS && po->op != OP_SCAS)
6966 ferr(po, "unexpected repz/repnz\n");
6969 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
6971 // see is delayed flag stuff is still valid
6972 if (delayed_flag_op != NULL && delayed_flag_op != po) {
6973 if (is_any_opr_modified(delayed_flag_op, po, 0))
6974 delayed_flag_op = NULL;
6977 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
6978 if (is_opr_modified(last_arith_dst, po))
6979 last_arith_dst = NULL;
6985 if (g_stack_fsz && !g_stack_frame_used)
6986 fprintf(fout, " (void)sf;\n");
6988 fprintf(fout, "}\n\n");
6990 gen_x_cleanup(opcnt);
6993 static void gen_x_cleanup(int opcnt)
6997 for (i = 0; i < opcnt; i++) {
6998 struct label_ref *lr, *lr_del;
7000 lr = g_label_refs[i].next;
7001 while (lr != NULL) {
7006 g_label_refs[i].i = -1;
7007 g_label_refs[i].next = NULL;
7009 if (ops[i].op == OP_CALL) {
7011 proto_release(ops[i].pp);
7017 struct func_proto_dep;
7019 struct func_prototype {
7024 int has_ret:3; // -1, 0, 1: unresolved, no, yes
7025 unsigned int dep_resolved:1;
7026 unsigned int is_stdcall:1;
7027 struct func_proto_dep *dep_func;
7029 const struct parsed_proto *pp; // seed pp, if any
7032 struct func_proto_dep {
7034 struct func_prototype *proto;
7035 int regmask_live; // .. at the time of call
7036 unsigned int ret_dep:1; // return from this is caller's return
7039 static struct func_prototype *hg_fp;
7040 static int hg_fp_cnt;
7042 static struct scanned_var {
7044 enum opr_lenmod lmod;
7045 unsigned int is_seeded:1;
7046 unsigned int is_c_str:1;
7047 const struct parsed_proto *pp; // seed pp, if any
7049 static int hg_var_cnt;
7051 static char **hg_refs;
7052 static int hg_ref_cnt;
7054 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7057 static struct func_prototype *hg_fp_add(const char *funcn)
7059 struct func_prototype *fp;
7061 if ((hg_fp_cnt & 0xff) == 0) {
7062 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7063 my_assert_not(hg_fp, NULL);
7064 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7067 fp = &hg_fp[hg_fp_cnt];
7068 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7070 fp->argc_stack = -1;
7076 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7081 for (i = 0; i < fp->dep_func_cnt; i++)
7082 if (IS(fp->dep_func[i].name, name))
7083 return &fp->dep_func[i];
7088 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7091 if (hg_fp_find_dep(fp, name))
7094 if ((fp->dep_func_cnt & 0xff) == 0) {
7095 fp->dep_func = realloc(fp->dep_func,
7096 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7097 my_assert_not(fp->dep_func, NULL);
7098 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7099 sizeof(fp->dep_func[0]) * 0x100);
7101 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7105 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7107 const struct func_prototype *p1 = p1_, *p2 = p2_;
7108 return strcmp(p1->name, p2->name);
7112 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7114 const struct func_prototype *p1 = p1_, *p2 = p2_;
7115 return p1->id - p2->id;
7119 static void hg_ref_add(const char *name)
7121 if ((hg_ref_cnt & 0xff) == 0) {
7122 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7123 my_assert_not(hg_refs, NULL);
7124 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7127 hg_refs[hg_ref_cnt] = strdup(name);
7128 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7132 // recursive register dep pass
7133 // - track saved regs (part 2)
7134 // - try to figure out arg-regs
7135 // - calculate reg deps
7136 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
7137 struct func_prototype *fp, int regmask_save, int regmask_dst,
7138 int *regmask_dep, int *has_ret)
7140 struct func_proto_dep *dep;
7141 struct parsed_op *po;
7142 int from_caller = 0;
7147 for (; i < opcnt; i++)
7149 if (cbits[i >> 3] & (1 << (i & 7)))
7151 cbits[i >> 3] |= (1 << (i & 7));
7155 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
7156 if (po->flags & OPF_RMD)
7159 if (po->btj != NULL) {
7161 for (j = 0; j < po->btj->count; j++) {
7162 check_i(po, po->btj->d[j].bt_i);
7163 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
7164 regmask_save, regmask_dst, regmask_dep, has_ret);
7169 check_i(po, po->bt_i);
7170 if (po->flags & OPF_CJMP) {
7171 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
7172 regmask_save, regmask_dst, regmask_dep, has_ret);
7180 if (po->flags & OPF_FARG)
7181 /* (just calculate register deps) */;
7182 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
7184 reg = po->operand[0].reg;
7185 ferr_assert(po, reg >= 0);
7187 if (po->flags & OPF_RSAVE) {
7188 regmask_save |= 1 << reg;
7191 if (po->flags & OPF_DONE)
7194 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0);
7196 regmask_save |= 1 << reg;
7197 po->flags |= OPF_RMD;
7198 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, OPF_RMD);
7202 else if (po->flags & OPF_RMD)
7204 else if (po->op == OP_CALL) {
7205 po->regmask_dst |= 1 << xAX;
7207 dep = hg_fp_find_dep(fp, po->operand[0].name);
7209 dep->regmask_live = regmask_save | regmask_dst;
7211 else if (po->op == OP_RET) {
7212 if (po->operand_cnt > 0) {
7214 if (fp->argc_stack >= 0
7215 && fp->argc_stack != po->operand[0].val / 4)
7216 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
7217 fp->argc_stack = po->operand[0].val / 4;
7221 // if has_ret is 0, there is uninitialized eax path,
7222 // which means it's most likely void func
7223 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
7224 if (po->op == OP_CALL) {
7229 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
7232 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
7235 if (ret != 1 && from_caller) {
7236 // unresolved eax - probably void func
7240 if (j >= 0 && ops[j].op == OP_CALL) {
7241 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
7252 l = regmask_save | regmask_dst;
7253 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7256 l = po->regmask_src & ~l;
7259 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
7260 l, regmask_dst, regmask_save, po->flags);
7263 regmask_dst |= po->regmask_dst;
7265 if (po->flags & OPF_TAIL)
7270 static void gen_hdr(const char *funcn, int opcnt)
7272 int save_arg_vars[MAX_ARG_GRP] = { 0, };
7273 unsigned char cbits[MAX_OPS / 8];
7274 const struct parsed_proto *pp_c;
7275 struct parsed_proto *pp;
7276 struct func_prototype *fp;
7277 struct parsed_op *po;
7278 int regmask_dummy = 0;
7280 int max_bp_offset = 0;
7285 pp_c = proto_parse(g_fhdr, funcn, 1);
7287 // already in seed, will add to hg_fp later
7290 fp = hg_fp_add(funcn);
7292 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7293 g_stack_frame_used = 0;
7296 // - resolve all branches
7297 // - parse calls with labels
7298 resolve_branches_parse_calls(opcnt);
7301 // - handle ebp/esp frame, remove ops related to it
7302 scan_prologue_epilogue(opcnt);
7305 // - remove dead labels
7307 for (i = 0; i < opcnt; i++)
7309 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7315 if (po->flags & (OPF_RMD|OPF_DONE))
7318 if (po->op == OP_CALL) {
7319 if (po->operand[0].type == OPT_LABEL)
7320 hg_fp_add_dep(fp, opr_name(po, 0));
7321 else if (po->pp != NULL)
7322 hg_fp_add_dep(fp, po->pp->name);
7327 // - remove dead labels
7328 // - handle push <const>/pop pairs
7329 for (i = 0; i < opcnt; i++)
7331 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7337 if (po->flags & (OPF_RMD|OPF_DONE))
7340 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
7341 scan_for_pop_const(i, opcnt, i + opcnt * 13);
7345 // - process trivial calls
7346 for (i = 0; i < opcnt; i++)
7349 if (po->flags & (OPF_RMD|OPF_DONE))
7352 if (po->op == OP_CALL)
7354 pp = process_call_early(i, opcnt, &j);
7356 if (!(po->flags & OPF_ATAIL))
7357 // since we know the args, try to collect them
7358 if (collect_call_args_early(po, i, pp, ®mask_dummy) != 0)
7364 // commit esp adjust
7365 if (ops[j].op != OP_POP)
7366 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
7368 for (l = 0; l < pp->argc_stack; l++)
7369 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
7373 po->flags |= OPF_DONE;
7379 // - track saved regs (simple)
7381 for (i = 0; i < opcnt; i++)
7384 if (po->flags & (OPF_RMD|OPF_DONE))
7387 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7388 && po->operand[0].reg != xCX)
7390 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
7392 // regmask_save |= 1 << po->operand[0].reg; // do it later
7393 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
7394 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
7397 else if (po->op == OP_CALL)
7399 pp = process_call(i, opcnt);
7401 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
7402 // since we know the args, collect them
7403 ret = collect_call_args(po, i, pp, ®mask_dummy, save_arg_vars,
7410 memset(cbits, 0, sizeof(cbits));
7414 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
7416 // find unreachable code - must be fixed in IDA
7417 for (i = 0; i < opcnt; i++)
7419 if (cbits[i >> 3] & (1 << (i & 7)))
7422 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
7423 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
7425 // the compiler sometimes still generates code after
7426 // noreturn OS functions
7429 if (ops[i].op != OP_NOP)
7430 ferr(&ops[i], "unreachable code\n");
7433 for (i = 0; i < g_eqcnt; i++) {
7434 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
7435 max_bp_offset = g_eqs[i].offset;
7438 if (fp->argc_stack < 0) {
7439 max_bp_offset = (max_bp_offset + 3) & ~3;
7440 fp->argc_stack = max_bp_offset / 4;
7441 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
7445 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
7446 fp->has_ret = has_ret;
7448 printf("// has_ret %d, regmask_dep %x\n",
7449 fp->has_ret, fp->regmask_dep);
7450 output_hdr_fp(stdout, fp, 1);
7451 if (IS(funcn, "sub_10007F72")) exit(1);
7454 gen_x_cleanup(opcnt);
7457 static void hg_fp_resolve_deps(struct func_prototype *fp)
7459 struct func_prototype fp_s;
7463 // this thing is recursive, so mark first..
7464 fp->dep_resolved = 1;
7466 for (i = 0; i < fp->dep_func_cnt; i++) {
7467 strcpy(fp_s.name, fp->dep_func[i].name);
7468 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7469 sizeof(hg_fp[0]), hg_fp_cmp_name);
7470 if (fp->dep_func[i].proto != NULL) {
7471 if (!fp->dep_func[i].proto->dep_resolved)
7472 hg_fp_resolve_deps(fp->dep_func[i].proto);
7474 dep = ~fp->dep_func[i].regmask_live
7475 & fp->dep_func[i].proto->regmask_dep;
7476 fp->regmask_dep |= dep;
7477 // printf("dep %s %s |= %x\n", fp->name,
7478 // fp->dep_func[i].name, dep);
7480 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
7481 fp->has_ret = fp->dep_func[i].proto->has_ret;
7486 // make all thiscall/edx arg functions referenced from .data fastcall
7487 static void do_func_refs_from_data(void)
7489 struct func_prototype *fp, fp_s;
7492 for (i = 0; i < hg_ref_cnt; i++) {
7493 strcpy(fp_s.name, hg_refs[i]);
7494 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
7495 sizeof(hg_fp[0]), hg_fp_cmp_name);
7499 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
7500 fp->regmask_dep |= mxCX | mxDX;
7504 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7507 const struct parsed_proto *pp;
7508 char *p, namebuf[NAMELEN];
7514 for (; count > 0; count--, fp++) {
7515 if (fp->has_ret == -1)
7516 fprintf(fout, "// ret unresolved\n");
7518 fprintf(fout, "// dep:");
7519 for (j = 0; j < fp->dep_func_cnt; j++) {
7520 fprintf(fout, " %s/", fp->dep_func[j].name);
7521 if (fp->dep_func[j].proto != NULL)
7522 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
7523 fp->dep_func[j].proto->has_ret);
7525 fprintf(fout, "\n");
7528 p = strchr(fp->name, '@');
7530 memcpy(namebuf, fp->name, p - fp->name);
7531 namebuf[p - fp->name] = 0;
7539 pp = proto_parse(g_fhdr, name, 1);
7540 if (pp != NULL && pp->is_include)
7543 if (fp->pp != NULL) {
7544 // part of seed, output later
7548 regmask_dep = fp->regmask_dep;
7549 argc_normal = fp->argc_stack;
7551 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
7552 (fp->has_ret ? "int" : "void"));
7553 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
7554 && (regmask_dep & ~mxCX) == 0)
7556 fprintf(fout, "/*__thiscall*/ ");
7560 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
7561 && (regmask_dep & ~(mxCX | mxDX)) == 0)
7563 fprintf(fout, " __fastcall ");
7564 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
7570 else if (regmask_dep && !fp->is_stdcall) {
7571 fprintf(fout, "/*__usercall*/ ");
7573 else if (regmask_dep) {
7574 fprintf(fout, "/*__userpurge*/ ");
7576 else if (fp->is_stdcall)
7577 fprintf(fout, " __stdcall ");
7579 fprintf(fout, " __cdecl ");
7581 fprintf(fout, "%s(", name);
7584 for (j = 0; j < xSP; j++) {
7585 if (regmask_dep & (1 << j)) {
7588 fprintf(fout, ", ");
7590 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
7592 fprintf(fout, "int");
7593 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
7597 for (j = 0; j < argc_normal; j++) {
7600 fprintf(fout, ", ");
7601 if (fp->pp != NULL) {
7602 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
7603 if (!fp->pp->arg[arg - 1].type.is_ptr)
7607 fprintf(fout, "int ");
7608 fprintf(fout, "a%d", arg);
7611 fprintf(fout, ");\n");
7615 static void output_hdr(FILE *fout)
7617 static const char *lmod_c_names[] = {
7618 [OPLM_UNSPEC] = "???",
7619 [OPLM_BYTE] = "uint8_t",
7620 [OPLM_WORD] = "uint16_t",
7621 [OPLM_DWORD] = "uint32_t",
7622 [OPLM_QWORD] = "uint64_t",
7624 const struct scanned_var *var;
7625 struct func_prototype *fp;
7626 char line[256] = { 0, };
7630 // add stuff from headers
7631 for (i = 0; i < pp_cache_size; i++) {
7632 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
7633 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
7635 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
7636 fp = hg_fp_add(name);
7637 fp->pp = &pp_cache[i];
7638 fp->argc_stack = fp->pp->argc_stack;
7639 fp->is_stdcall = fp->pp->is_stdcall;
7640 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
7641 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
7645 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
7646 for (i = 0; i < hg_fp_cnt; i++)
7647 hg_fp_resolve_deps(&hg_fp[i]);
7649 // adjust functions referenced from data segment
7650 do_func_refs_from_data();
7652 // note: messes up .proto ptr, don't use
7653 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
7656 for (i = 0; i < hg_var_cnt; i++) {
7659 if (var->pp != NULL)
7662 else if (var->is_c_str)
7663 fprintf(fout, "extern %-8s %s[];", "char", var->name);
7665 fprintf(fout, "extern %-8s %s;",
7666 lmod_c_names[var->lmod], var->name);
7669 fprintf(fout, " // seeded");
7670 fprintf(fout, "\n");
7673 fprintf(fout, "\n");
7675 // output function prototypes
7676 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
7679 fprintf(fout, "\n// - seed -\n");
7682 while (fgets(line, sizeof(line), g_fhdr))
7683 fwrite(line, 1, strlen(line), fout);
7686 // '=' needs special treatment
7688 static char *next_word_s(char *w, size_t wsize, char *s)
7695 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
7697 for (i = 1; i < wsize - 1; i++) {
7699 printf("warning: missing closing quote: \"%s\"\n", s);
7708 for (; i < wsize - 1; i++) {
7709 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
7715 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
7716 printf("warning: '%s' truncated\n", w);
7721 static int cmpstringp(const void *p1, const void *p2)
7723 return strcmp(*(char * const *)p1, *(char * const *)p2);
7726 static int is_xref_needed(char *p, char **rlist, int rlist_len)
7731 if (strstr(p, "..."))
7732 // unable to determine, assume needed
7735 if (*p == '.') // .text, .data, ...
7736 // ref from other data or non-function -> no
7739 p2 = strpbrk(p, "+:\r\n\x18");
7742 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
7743 // referenced from removed code
7749 static int ida_xrefs_show_need(FILE *fasm, char *p,
7750 char **rlist, int rlist_len)
7756 p = strrchr(p, ';');
7757 if (p != NULL && *p == ';' && IS_START(p + 2, "DATA XREF: ")) {
7759 if (is_xref_needed(p, rlist, rlist_len))
7766 if (!my_fgets(line, sizeof(line), fasm))
7768 // non-first line is always indented
7769 if (!my_isblank(line[0]))
7772 // should be no content, just comment
7777 p = strrchr(p, ';');
7779 // it's printed once, but no harm to check again
7780 if (IS_START(p, "DATA XREF: "))
7783 if (is_xref_needed(p, rlist, rlist_len)) {
7788 fseek(fasm, pos, SEEK_SET);
7792 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
7794 struct scanned_var *var;
7795 char line[256] = { 0, };
7804 // skip to next data section
7805 while (my_fgets(line, sizeof(line), fasm))
7810 if (*p == 0 || *p == ';')
7813 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
7814 if (*p == 0 || *p == ';')
7817 if (*p != 's' || !IS_START(p, "segment para public"))
7823 if (p == NULL || !IS_START(p, "segment para public"))
7827 if (!IS_START(p, "'DATA'"))
7831 while (my_fgets(line, sizeof(line), fasm))
7836 no_identifier = my_isblank(*p);
7839 if (*p == 0 || *p == ';')
7842 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
7843 words[wordc][0] = 0;
7844 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
7845 if (*p == 0 || *p == ';') {
7851 if (wordc == 2 && IS(words[1], "ends"))
7856 if (no_identifier) {
7857 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
7858 hg_ref_add(words[2]);
7862 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
7863 // when this starts, we don't need anything from this section
7867 // check refs comment(s)
7868 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
7871 if ((hg_var_cnt & 0xff) == 0) {
7872 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
7873 * (hg_var_cnt + 0x100));
7874 my_assert_not(hg_vars, NULL);
7875 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
7878 var = &hg_vars[hg_var_cnt++];
7879 snprintf(var->name, sizeof(var->name), "%s", words[0]);
7881 // maybe already in seed header?
7882 var->pp = proto_parse(g_fhdr, var->name, 1);
7883 if (var->pp != NULL) {
7884 if (var->pp->is_fptr) {
7885 var->lmod = OPLM_DWORD;
7888 else if (var->pp->is_func)
7890 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
7891 aerr("unhandled C type '%s' for '%s'\n",
7892 var->pp->type.name, var->name);
7898 if (IS(words[1], "dd")) {
7899 var->lmod = OPLM_DWORD;
7900 if (wordc >= 4 && IS(words[2], "offset"))
7901 hg_ref_add(words[3]);
7903 else if (IS(words[1], "dw"))
7904 var->lmod = OPLM_WORD;
7905 else if (IS(words[1], "db")) {
7906 var->lmod = OPLM_BYTE;
7907 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
7908 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
7912 else if (IS(words[1], "dq"))
7913 var->lmod = OPLM_QWORD;
7914 //else if (IS(words[1], "dt"))
7916 aerr("type '%s' not known\n", words[1]);
7924 static void set_label(int i, const char *name)
7930 p = strchr(name, ':');
7934 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
7935 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
7936 g_labels[i] = realloc(g_labels[i], len + 1);
7937 my_assert_not(g_labels[i], NULL);
7938 memcpy(g_labels[i], name, len);
7939 g_labels[i][len] = 0;
7948 static struct chunk_item *func_chunks;
7949 static int func_chunk_cnt;
7950 static int func_chunk_alloc;
7952 static void add_func_chunk(FILE *fasm, const char *name, int line)
7954 if (func_chunk_cnt >= func_chunk_alloc) {
7955 func_chunk_alloc *= 2;
7956 func_chunks = realloc(func_chunks,
7957 func_chunk_alloc * sizeof(func_chunks[0]));
7958 my_assert_not(func_chunks, NULL);
7960 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
7961 func_chunks[func_chunk_cnt].name = strdup(name);
7962 func_chunks[func_chunk_cnt].asmln = line;
7966 static int cmp_chunks(const void *p1, const void *p2)
7968 const struct chunk_item *c1 = p1, *c2 = p2;
7969 return strcmp(c1->name, c2->name);
7972 static void scan_ahead(FILE *fasm)
7982 oldpos = ftell(fasm);
7985 while (my_fgets(line, sizeof(line), fasm))
7996 // get rid of random tabs
7997 for (i = 0; line[i] != 0; i++)
7998 if (line[i] == '\t')
8001 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8004 next_word(words[0], sizeof(words[0]), p);
8005 if (words[0][0] == 0)
8006 aerr("missing name for func chunk?\n");
8008 add_func_chunk(fasm, words[0], asmln);
8010 else if (IS_START(p, "; sctend"))
8016 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8017 words[wordc][0] = 0;
8018 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8019 if (*p == 0 || *p == ';') {
8025 if (wordc == 2 && IS(words[1], "ends"))
8029 fseek(fasm, oldpos, SEEK_SET);
8033 int main(int argc, char *argv[])
8035 FILE *fout, *fasm, *frlist;
8036 struct parsed_data *pd = NULL;
8038 char **rlist = NULL;
8040 int rlist_alloc = 0;
8041 int func_chunks_used = 0;
8042 int func_chunks_sorted = 0;
8043 int func_chunk_i = -1;
8044 long func_chunk_ret = 0;
8045 int func_chunk_ret_ln = 0;
8046 int scanned_ahead = 0;
8048 char words[20][256];
8049 enum opr_lenmod lmod;
8050 char *sctproto = NULL;
8052 int pending_endp = 0;
8054 int skip_warned = 0;
8067 for (arg = 1; arg < argc; arg++) {
8068 if (IS(argv[arg], "-v"))
8070 else if (IS(argv[arg], "-rf"))
8071 g_allow_regfunc = 1;
8072 else if (IS(argv[arg], "-m"))
8074 else if (IS(argv[arg], "-hdr"))
8075 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8080 if (argc < arg + 3) {
8081 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8082 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8084 " -hdr - header generation mode\n"
8085 " -rf - allow unannotated indirect calls\n"
8086 " -m - allow multiple .text sections\n"
8087 "[rlist] is a file with function names to skip,"
8095 asmfn = argv[arg++];
8096 fasm = fopen(asmfn, "r");
8097 my_assert_not(fasm, NULL);
8099 hdrfn = argv[arg++];
8100 g_fhdr = fopen(hdrfn, "r");
8101 my_assert_not(g_fhdr, NULL);
8104 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8105 my_assert_not(rlist, NULL);
8106 // needs special handling..
8107 rlist[rlist_len++] = "__alloca_probe";
8109 func_chunk_alloc = 32;
8110 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8111 my_assert_not(func_chunks, NULL);
8113 memset(words, 0, sizeof(words));
8115 for (; arg < argc; arg++) {
8116 frlist = fopen(argv[arg], "r");
8117 my_assert_not(frlist, NULL);
8119 while (my_fgets(line, sizeof(line), frlist)) {
8121 if (*p == 0 || *p == ';')
8124 if (IS_START(p, "#if 0")
8125 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
8129 else if (IS_START(p, "#endif"))
8136 p = next_word(words[0], sizeof(words[0]), p);
8137 if (words[0][0] == 0)
8140 if (rlist_len >= rlist_alloc) {
8141 rlist_alloc = rlist_alloc * 2 + 64;
8142 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
8143 my_assert_not(rlist, NULL);
8145 rlist[rlist_len++] = strdup(words[0]);
8154 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
8156 fout = fopen(argv[arg_out], "w");
8157 my_assert_not(fout, NULL);
8160 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
8161 my_assert_not(g_eqs, NULL);
8163 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
8164 g_label_refs[i].i = -1;
8165 g_label_refs[i].next = NULL;
8169 scan_variables(fasm, rlist, rlist_len);
8171 while (my_fgets(line, sizeof(line), fasm))
8180 // get rid of random tabs
8181 for (i = 0; line[i] != 0; i++)
8182 if (line[i] == '\t')
8187 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
8188 goto do_pending_endp; // eww..
8190 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
8192 static const char *attrs[] = {
8201 // parse IDA's attribute-list comment
8202 g_ida_func_attr = 0;
8205 for (; *p != 0; p = sskip(p)) {
8206 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8207 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8208 g_ida_func_attr |= 1 << i;
8209 p += strlen(attrs[i]);
8213 if (i == ARRAY_SIZE(attrs)) {
8214 anote("unparsed IDA attr: %s\n", p);
8217 if (IS(attrs[i], "fpd=")) {
8218 p = next_word(words[0], sizeof(words[0]), p);
8223 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
8225 static const char *attrs[] = {
8230 // parse manual attribute-list comment
8231 g_sct_func_attr = 0;
8234 for (; *p != 0; p = sskip(p)) {
8235 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8236 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8237 g_sct_func_attr |= 1 << i;
8238 p += strlen(attrs[i]);
8245 // clear_sf=start,len (in dwords)
8246 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
8247 &g_stack_clear_len, &j);
8249 // clear_regmask=<mask>
8250 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
8252 anote("unparsed attr value: %s\n", p);
8257 else if (i == ARRAY_SIZE(attrs)) {
8258 anote("unparsed sct attr: %s\n", p);
8263 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8266 next_word(words[0], sizeof(words[0]), p);
8267 if (words[0][0] == 0)
8268 aerr("missing name for func chunk?\n");
8270 if (!scanned_ahead) {
8271 add_func_chunk(fasm, words[0], asmln);
8272 func_chunks_sorted = 0;
8275 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
8277 if (func_chunk_i >= 0) {
8278 if (func_chunk_i < func_chunk_cnt
8279 && IS(func_chunks[func_chunk_i].name, g_func))
8281 // move on to next chunk
8282 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8284 aerr("seek failed for '%s' chunk #%d\n",
8285 g_func, func_chunk_i);
8286 asmln = func_chunks[func_chunk_i].asmln;
8290 if (func_chunk_ret == 0)
8291 aerr("no return from chunk?\n");
8292 fseek(fasm, func_chunk_ret, SEEK_SET);
8293 asmln = func_chunk_ret_ln;
8299 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
8300 func_chunks_used = 1;
8302 if (IS_START(g_func, "sub_")) {
8303 unsigned long addr = strtoul(p, NULL, 16);
8304 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
8305 if (addr > f_addr && !scanned_ahead) {
8306 //anote("scan_ahead caused by '%s', addr %lx\n",
8310 func_chunks_sorted = 0;
8318 for (i = wordc; i < ARRAY_SIZE(words); i++)
8320 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8321 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8322 if (*p == 0 || *p == ';') {
8327 if (*p != 0 && *p != ';')
8328 aerr("too many words\n");
8330 // alow asm patches in comments
8332 if (IS_START(p, "; sctpatch:")) {
8334 if (*p == 0 || *p == ';')
8336 goto parse_words; // lame
8338 if (IS_START(p, "; sctproto:")) {
8339 sctproto = strdup(p + 11);
8341 else if (IS_START(p, "; sctend")) {
8350 awarn("wordc == 0?\n");
8354 // don't care about this:
8355 if (words[0][0] == '.'
8356 || IS(words[0], "include")
8357 || IS(words[0], "assume") || IS(words[1], "segment")
8358 || IS(words[0], "align"))
8364 // do delayed endp processing to collect switch jumptables
8366 if (in_func && !g_skip_func && !end && wordc >= 2
8367 && ((words[0][0] == 'd' && words[0][2] == 0)
8368 || (words[1][0] == 'd' && words[1][2] == 0)))
8371 if (words[1][0] == 'd' && words[1][2] == 0) {
8373 if (g_func_pd_cnt >= pd_alloc) {
8374 pd_alloc = pd_alloc * 2 + 16;
8375 g_func_pd = realloc(g_func_pd,
8376 sizeof(g_func_pd[0]) * pd_alloc);
8377 my_assert_not(g_func_pd, NULL);
8379 pd = &g_func_pd[g_func_pd_cnt];
8381 memset(pd, 0, sizeof(*pd));
8382 strcpy(pd->label, words[0]);
8383 pd->type = OPT_CONST;
8384 pd->lmod = lmod_from_directive(words[1]);
8390 anote("skipping alignment byte?\n");
8393 lmod = lmod_from_directive(words[0]);
8394 if (lmod != pd->lmod)
8395 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
8398 if (pd->count_alloc < pd->count + wordc) {
8399 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
8400 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
8401 my_assert_not(pd->d, NULL);
8403 for (; i < wordc; i++) {
8404 if (IS(words[i], "offset")) {
8405 pd->type = OPT_OFFSET;
8408 p = strchr(words[i], ',');
8411 if (pd->type == OPT_OFFSET)
8412 pd->d[pd->count].u.label = strdup(words[i]);
8414 pd->d[pd->count].u.val = parse_number(words[i]);
8415 pd->d[pd->count].bt_i = -1;
8421 if (in_func && !g_skip_func) {
8423 gen_hdr(g_func, pi);
8425 gen_func(fout, g_fhdr, g_func, pi);
8430 g_ida_func_attr = 0;
8431 g_sct_func_attr = 0;
8432 g_stack_clear_start = 0;
8433 g_stack_clear_len = 0;
8438 func_chunks_used = 0;
8441 memset(&ops, 0, pi * sizeof(ops[0]));
8446 for (i = 0; i < g_func_pd_cnt; i++) {
8448 if (pd->type == OPT_OFFSET) {
8449 for (j = 0; j < pd->count; j++)
8450 free(pd->d[j].u.label);
8465 if (IS(words[1], "proc")) {
8467 aerr("proc '%s' while in_func '%s'?\n",
8470 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8472 strcpy(g_func, words[0]);
8473 set_label(0, words[0]);
8478 if (IS(words[1], "endp"))
8481 aerr("endp '%s' while not in_func?\n", words[0]);
8482 if (!IS(g_func, words[0]))
8483 aerr("endp '%s' while in_func '%s'?\n",
8486 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
8487 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
8493 if (!g_skip_func && func_chunks_used) {
8494 // start processing chunks
8495 struct chunk_item *ci, key = { g_func, 0 };
8497 func_chunk_ret = ftell(fasm);
8498 func_chunk_ret_ln = asmln;
8499 if (!func_chunks_sorted) {
8500 qsort(func_chunks, func_chunk_cnt,
8501 sizeof(func_chunks[0]), cmp_chunks);
8502 func_chunks_sorted = 1;
8504 ci = bsearch(&key, func_chunks, func_chunk_cnt,
8505 sizeof(func_chunks[0]), cmp_chunks);
8507 aerr("'%s' needs chunks, but none found\n", g_func);
8508 func_chunk_i = ci - func_chunks;
8509 for (; func_chunk_i > 0; func_chunk_i--)
8510 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
8513 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8515 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
8516 asmln = func_chunks[func_chunk_i].asmln;
8524 if (wordc == 2 && IS(words[1], "ends")) {
8528 goto do_pending_endp;
8532 // scan for next text segment
8533 while (my_fgets(line, sizeof(line), fasm)) {
8536 if (*p == 0 || *p == ';')
8539 if (strstr(p, "segment para public 'CODE' use32"))
8546 p = strchr(words[0], ':');
8548 set_label(pi, words[0]);
8552 if (!in_func || g_skip_func) {
8553 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
8555 anote("skipping from '%s'\n", g_labels[pi]);
8559 g_labels[pi] = NULL;
8563 if (wordc > 1 && IS(words[1], "="))
8566 aerr("unhandled equ, wc=%d\n", wordc);
8567 if (g_eqcnt >= eq_alloc) {
8569 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
8570 my_assert_not(g_eqs, NULL);
8573 len = strlen(words[0]);
8574 if (len > sizeof(g_eqs[0].name) - 1)
8575 aerr("equ name too long: %d\n", len);
8576 strcpy(g_eqs[g_eqcnt].name, words[0]);
8578 if (!IS(words[3], "ptr"))
8579 aerr("unhandled equ\n");
8580 if (IS(words[2], "dword"))
8581 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
8582 else if (IS(words[2], "word"))
8583 g_eqs[g_eqcnt].lmod = OPLM_WORD;
8584 else if (IS(words[2], "byte"))
8585 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
8586 else if (IS(words[2], "qword"))
8587 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
8589 aerr("bad lmod: '%s'\n", words[2]);
8591 g_eqs[g_eqcnt].offset = parse_number(words[4]);
8596 if (pi >= ARRAY_SIZE(ops))
8597 aerr("too many ops\n");
8599 parse_op(&ops[pi], words, wordc);
8601 ops[pi].datap = sctproto;
8616 // vim:ts=2:shiftwidth=2:expandtab