5 * This work is licensed under the terms of 3-clause BSD license.
6 * See COPYING file in the top-level directory.
8 * recognized asm hint comments:
9 * sctattr - function attributes (see code)
10 * sctend - force end of function/chunk
11 * sctpatch: <p> - replace current asm line with <p>
12 * sctproto: <p> - prototype of ref'd function or struct
13 * sctref - variable is referenced, make global
14 * sctskip_start - start of skipped code chunk (inclusive)
15 * sctskip_end - end of skipped code chunk (inclusive)
24 #include "my_assert.h"
28 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
29 #define IS(w, y) !strcmp(w, y)
30 #define IS_START(w, y) !strncmp(w, y, strlen(y))
32 #include "protoparse.h"
34 static const char *asmfn;
38 #define anote(fmt, ...) \
39 printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
40 #define awarn(fmt, ...) \
41 printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
42 #define aerr(fmt, ...) do { \
43 printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
48 #include "masm_tools.h"
51 OPF_RMD = (1 << 0), /* removed from code generation */
52 OPF_DATA = (1 << 1), /* data processing - writes to dst opr */
53 OPF_FLAGS = (1 << 2), /* sets flags */
54 OPF_JMP = (1 << 3), /* branch, call */
55 OPF_CJMP = (1 << 4), /* cond. branch (cc or jecxz/loop) */
56 OPF_CC = (1 << 5), /* uses flags */
57 OPF_TAIL = (1 << 6), /* ret or tail call */
58 OPF_RSAVE = (1 << 7), /* push/pop is local reg save/load */
59 OPF_REP = (1 << 8), /* prefixed by rep */
60 OPF_REPZ = (1 << 9), /* rep is repe/repz */
61 OPF_REPNZ = (1 << 10), /* rep is repne/repnz */
62 OPF_FARG = (1 << 11), /* push collected as func arg */
63 OPF_FARGNR = (1 << 12), /* push collected as func arg (no reuse) */
64 OPF_EBP_S = (1 << 13), /* ebp used as scratch here, not BP */
65 OPF_DF = (1 << 14), /* DF flag set */
66 OPF_ATAIL = (1 << 15), /* tail call with reused arg frame */
67 OPF_32BIT = (1 << 16), /* 32bit division */
68 OPF_LOCK = (1 << 17), /* op has lock prefix */
69 OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
70 OPF_DONE = (1 << 19), /* already fully handled by analysis */
71 OPF_PPUSH = (1 << 20), /* part of complex push-pop graph */
72 OPF_NOREGS = (1 << 21), /* don't track regs of this op */
73 OPF_FPUSH = (1 << 22), /* pushes x87 stack */
74 OPF_FPOP = (1 << 23), /* pops x87 stack */
75 OPF_FSHIFT = (1 << 24), /* x87 stack shift is actually needed */
165 // pseudo-ops for lib calls
184 // must be sorted (larger len must be further in enum)
193 #define MAX_EXITS 128
195 #define MAX_OPERANDS 3
198 #define OPR_INIT(type_, lmod_, reg_) \
199 { type_, lmod_, reg_, }
203 enum opr_lenmod lmod;
205 unsigned int is_ptr:1; // pointer in C
206 unsigned int is_array:1; // array in C
207 unsigned int type_from_var:1; // .. in header, sometimes wrong
208 unsigned int size_mismatch:1; // type override differs from C
209 unsigned int size_lt:1; // type override is larger than C
210 unsigned int had_ds:1; // had ds: prefix
211 const struct parsed_proto *pp; // for OPT_LABEL
218 struct parsed_opr operand[MAX_OPERANDS];
221 unsigned char pfo_inv;
222 unsigned char operand_cnt;
223 unsigned char p_argnum; // arg push: altered before call arg #
224 unsigned char p_arggrp; // arg push: arg group # for above
225 unsigned char p_argpass;// arg push: arg of host func
226 short p_argnext;// arg push: same arg pushed elsewhere or -1
227 int regmask_src; // all referensed regs
229 int pfomask; // flagop: parsed_flag_op that can't be delayed
230 int cc_scratch; // scratch storage during analysis
231 int bt_i; // branch target for branches
232 struct parsed_data *btj;// branch targets for jumptables
233 struct parsed_proto *pp;// parsed_proto for OP_CALL
239 // on start: function/data type hint (sctproto)
241 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
242 // OP_PUSH - points to OP_POP in complex push/pop graph
243 // OP_POP - points to OP_PUSH in simple push/pop pair
244 // OP_FCOM - needed_status_word_bits | (is_z_check << 16)
248 enum opr_lenmod lmod;
255 enum opr_lenmod lmod;
269 struct label_ref *next;
273 IDAFA_BP_FRAME = (1 << 0),
274 IDAFA_LIB_FUNC = (1 << 1),
275 IDAFA_STATIC = (1 << 2),
276 IDAFA_NORETURN = (1 << 3),
277 IDAFA_THUNK = (1 << 4),
278 IDAFA_FPD = (1 << 5),
282 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
283 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
296 // note: limited to 32k due to p_argnext
298 #define MAX_ARG_GRP 2
300 static struct parsed_op ops[MAX_OPS];
301 static struct parsed_equ *g_eqs;
303 static char *g_labels[MAX_OPS];
304 static struct label_ref g_label_refs[MAX_OPS];
305 static const struct parsed_proto *g_func_pp;
306 static struct parsed_data *g_func_pd;
307 static int g_func_pd_cnt;
308 static int g_func_lmods;
309 static char g_func[256];
310 static char g_comment[256];
311 static int g_bp_frame;
312 static int g_sp_frame;
313 static int g_stack_frame_used;
314 static int g_stack_fsz;
315 static int g_ida_func_attr;
316 static int g_sct_func_attr;
317 static int g_stack_clear_start; // in dwords
318 static int g_stack_clear_len;
319 static int g_regmask_init;
320 static int g_skip_func;
321 static int g_allow_regfunc;
322 static int g_allow_user_icall;
323 static int g_quiet_pp;
324 static int g_header_mode;
326 #define ferr(op_, fmt, ...) do { \
327 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
328 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
332 #define fnote(op_, fmt, ...) \
333 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
334 dump_op(op_), ##__VA_ARGS__)
336 #define ferr_assert(op_, cond) do { \
337 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
340 const char *regs_r32[] = {
341 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
342 // not r32, but list here for easy parsing and printing
343 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
344 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
346 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
347 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
348 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
354 xMM0, xMM1, xMM2, xMM3, // mmx
355 xMM4, xMM5, xMM6, xMM7,
356 xST0, xST1, xST2, xST3, // x87
357 xST4, xST5, xST6, xST7,
360 #define mxAX (1 << xAX)
361 #define mxCX (1 << xCX)
362 #define mxDX (1 << xDX)
363 #define mxST0 (1 << xST0)
364 #define mxST1 (1 << xST1)
365 #define mxST1_0 (mxST1 | mxST0)
366 #define mxST7_2 (0xfc << xST0)
367 #define mxSTa (0xff << xST0)
369 // possible basic comparison types (without inversion)
370 enum parsed_flag_op {
374 PFO_BE, // 6 CF=1||ZF=1
378 PFO_LE, // e ZF=1||SF!=OF
381 #define PFOB_O (1 << PFO_O)
382 #define PFOB_C (1 << PFO_C)
383 #define PFOB_Z (1 << PFO_Z)
384 #define PFOB_S (1 << PFO_S)
386 static const char *parsed_flag_op_names[] = {
387 "o", "c", "z", "be", "s", "p", "l", "le"
390 static int char_array_i(const char *array[], size_t len, const char *s)
394 for (i = 0; i < len; i++)
401 static void printf_number(char *buf, size_t buf_size,
402 unsigned long number)
404 // output in C-friendly form
405 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
408 static int check_segment_prefix(const char *s)
410 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
424 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
428 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
430 *reg_lmod = OPLM_QWORD;
434 *reg_lmod = OPLM_DWORD;
437 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
439 *reg_lmod = OPLM_WORD;
442 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
444 *reg_lmod = OPLM_BYTE;
447 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
449 *reg_lmod = OPLM_BYTE;
456 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
458 enum opr_lenmod lmod;
471 while (my_isblank(*s))
473 for (; my_issep(*s); d++, s++)
475 while (my_isblank(*s))
479 // skip '?s:' prefixes
480 if (check_segment_prefix(s))
483 s = next_idt(w, sizeof(w), s);
488 reg = parse_reg(&lmod, w);
490 *regmask |= 1 << reg;
494 if ('0' <= w[0] && w[0] <= '9') {
495 number = parse_number(w, 0);
496 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
500 // probably some label/identifier - pass
503 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
507 strcpy(name, cvtbuf);
512 static int is_reg_in_str(const char *s)
516 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
519 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
520 if (!strncmp(s, regs_r32[i], 3))
526 static const char *parse_stack_el(const char *name, char *extra_reg,
527 int *base_val, int early_try)
529 const char *p, *p2, *s;
535 if (g_bp_frame || early_try)
538 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
540 if (extra_reg != NULL) {
541 strncpy(extra_reg, name, 3);
546 if (IS_START(p, "ebp+")) {
550 if (p2 != NULL && is_reg_in_str(p)) {
551 if (extra_reg != NULL) {
552 strncpy(extra_reg, p, p2 - p);
553 extra_reg[p2 - p] = 0;
558 if (!('0' <= *p && *p <= '9'))
565 if (!IS_START(name, "esp+"))
571 if (is_reg_in_str(s)) {
572 if (extra_reg != NULL) {
573 strncpy(extra_reg, s, p - s);
574 extra_reg[p - s] = 0;
579 aerr("%s IDA stackvar not set?\n", __func__);
581 if (!('0' <= *s && *s <= '9')) {
582 aerr("%s IDA stackvar offset not set?\n", __func__);
585 if (s[0] == '0' && s[1] == 'x')
588 if (len < sizeof(buf) - 1) {
589 strncpy(buf, s, len);
592 val = strtol(buf, &endp, 16);
593 if (val == 0 || *endp != 0 || errno != 0) {
594 aerr("%s num parse fail for '%s'\n", __func__, buf);
603 if ('0' <= *p && *p <= '9')
606 if (base_val != NULL)
611 static int guess_lmod_from_name(struct parsed_opr *opr)
613 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
614 opr->lmod = OPLM_DWORD;
617 if (IS_START(opr->name, "word_")) {
618 opr->lmod = OPLM_WORD;
621 if (IS_START(opr->name, "byte_")) {
622 opr->lmod = OPLM_BYTE;
625 if (IS_START(opr->name, "qword_")) {
626 opr->lmod = OPLM_QWORD;
632 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
633 const struct parsed_type *c_type)
635 static const char *qword_types[] = {
636 "uint64_t", "int64_t", "__int64",
638 static const char *dword_types[] = {
639 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
640 "WPARAM", "LPARAM", "UINT", "__int32",
641 "LONG", "HIMC", "BOOL", "size_t",
644 static const char *word_types[] = {
645 "uint16_t", "int16_t", "_WORD", "WORD",
646 "unsigned __int16", "__int16",
648 static const char *byte_types[] = {
649 "uint8_t", "int8_t", "char",
650 "unsigned __int8", "__int8", "BYTE", "_BYTE",
652 // structures.. deal the same as with _UNKNOWN for now
658 if (c_type->is_ptr) {
663 n = skip_type_mod(c_type->name);
665 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
666 if (IS(n, dword_types[i])) {
672 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
673 if (IS(n, word_types[i])) {
679 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
680 if (IS(n, byte_types[i])) {
686 for (i = 0; i < ARRAY_SIZE(qword_types); i++) {
687 if (IS(n, qword_types[i])) {
696 static char *default_cast_to(char *buf, size_t buf_size,
697 struct parsed_opr *opr)
701 if (!opr->is_ptr || strchr(opr->name, '['))
703 if (opr->pp == NULL || opr->pp->type.name == NULL
706 snprintf(buf, buf_size, "%s", "(void *)");
710 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
714 static enum opr_type lmod_from_directive(const char *d)
718 else if (IS(d, "dw"))
720 else if (IS(d, "db"))
723 aerr("unhandled directive: '%s'\n", d);
727 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
733 *regmask |= 1 << reg;
736 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
739 static int parse_operand(struct parsed_opr *opr,
740 int *regmask, int *regmask_indirect,
741 char words[16][256], int wordc, int w, unsigned int op_flags)
743 const struct parsed_proto *pp = NULL;
744 enum opr_lenmod tmplmod;
745 unsigned long number;
753 aerr("parse_operand w %d, wordc %d\n", w, wordc);
757 for (i = w; i < wordc; i++) {
758 len = strlen(words[i]);
759 if (words[i][len - 1] == ',') {
760 words[i][len - 1] = 0;
766 wordc_in = wordc - w;
768 if ((op_flags & OPF_JMP) && wordc_in > 0
769 && !('0' <= words[w][0] && words[w][0] <= '9'))
771 const char *label = NULL;
773 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
774 && IS(words[w + 1], "ptr"))
775 label = words[w + 2];
776 else if (wordc_in == 2 && IS(words[w], "short"))
777 label = words[w + 1];
778 else if (wordc_in == 1
779 && strchr(words[w], '[') == NULL
780 && parse_reg(&tmplmod, words[w]) < 0)
784 opr->type = OPT_LABEL;
785 ret = check_segment_prefix(label);
788 aerr("fs/gs used\n");
792 strcpy(opr->name, label);
798 if (IS(words[w + 1], "ptr")) {
799 if (IS(words[w], "dword"))
800 opr->lmod = OPLM_DWORD;
801 else if (IS(words[w], "word"))
802 opr->lmod = OPLM_WORD;
803 else if (IS(words[w], "byte"))
804 opr->lmod = OPLM_BYTE;
805 else if (IS(words[w], "qword"))
806 opr->lmod = OPLM_QWORD;
808 aerr("type parsing failed\n");
810 wordc_in = wordc - w;
815 if (IS(words[w], "offset")) {
816 opr->type = OPT_OFFSET;
817 opr->lmod = OPLM_DWORD;
818 strcpy(opr->name, words[w + 1]);
819 pp = proto_parse(g_fhdr, opr->name, 1);
822 if (IS(words[w], "(offset")) {
823 p = strchr(words[w + 1], ')');
825 aerr("parse of bracketed offset failed\n");
827 opr->type = OPT_OFFSET;
828 strcpy(opr->name, words[w + 1]);
834 aerr("parse_operand 1 word expected\n");
836 ret = check_segment_prefix(words[w]);
839 aerr("fs/gs used\n");
841 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
843 strcpy(opr->name, words[w]);
845 if (words[w][0] == '[') {
846 opr->type = OPT_REGMEM;
847 ret = sscanf(words[w], "[%[^]]]", opr->name);
849 aerr("[] parse failure\n");
851 parse_indmode(opr->name, regmask_indirect, 1);
852 if (opr->lmod == OPLM_UNSPEC
853 && parse_stack_el(opr->name, NULL, NULL, 1))
856 struct parsed_equ *eq =
857 equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
859 opr->lmod = eq->lmod;
861 // might be unaligned access
862 g_func_lmods |= 1 << OPLM_BYTE;
866 else if (strchr(words[w], '[')) {
868 p = strchr(words[w], '[');
869 opr->type = OPT_REGMEM;
870 parse_indmode(p, regmask_indirect, 0);
871 strncpy(buf, words[w], p - words[w]);
872 buf[p - words[w]] = 0;
873 pp = proto_parse(g_fhdr, buf, 1);
876 else if (('0' <= words[w][0] && words[w][0] <= '9')
877 || words[w][0] == '-')
879 number = parse_number(words[w], 0);
880 opr->type = OPT_CONST;
882 printf_number(opr->name, sizeof(opr->name), number);
886 ret = parse_reg(&tmplmod, opr->name);
888 setup_reg_opr(opr, ret, tmplmod, regmask);
892 // most likely var in data segment
893 opr->type = OPT_LABEL;
894 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
898 if (pp->is_fptr || pp->is_func) {
899 opr->lmod = OPLM_DWORD;
903 tmplmod = OPLM_UNSPEC;
904 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
905 anote("unhandled C type '%s' for '%s'\n",
906 pp->type.name, opr->name);
908 if (opr->lmod == OPLM_UNSPEC) {
910 opr->type_from_var = 1;
912 else if (opr->lmod != tmplmod) {
913 opr->size_mismatch = 1;
914 if (tmplmod < opr->lmod)
917 opr->is_ptr = pp->type.is_ptr;
919 opr->is_array = pp->type.is_array;
923 if (opr->lmod == OPLM_UNSPEC)
924 guess_lmod_from_name(opr);
928 static const struct {
933 { "repe", OPF_REP|OPF_REPZ },
934 { "repz", OPF_REP|OPF_REPZ },
935 { "repne", OPF_REP|OPF_REPNZ },
936 { "repnz", OPF_REP|OPF_REPNZ },
937 { "lock", OPF_LOCK }, // ignored for now..
940 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
942 static const struct {
945 unsigned short minopr;
946 unsigned short maxopr;
949 unsigned char pfo_inv;
951 { "nop", OP_NOP, 0, 0, 0 },
952 { "push", OP_PUSH, 1, 1, 0 },
953 { "pop", OP_POP, 1, 1, OPF_DATA },
954 { "pusha",OP_PUSHA, 0, 0, 0 },
955 { "popa", OP_POPA, 0, 0, OPF_DATA },
956 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
957 { "mov" , OP_MOV, 2, 2, OPF_DATA },
958 { "lea", OP_LEA, 2, 2, OPF_DATA },
959 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
960 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
961 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
962 { "not", OP_NOT, 1, 1, OPF_DATA },
963 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
964 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
965 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
966 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
967 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
968 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
969 { "stosb",OP_STOS, 0, 0, OPF_DATA },
970 { "stosw",OP_STOS, 0, 0, OPF_DATA },
971 { "stosd",OP_STOS, 0, 0, OPF_DATA },
972 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
973 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
974 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
975 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
976 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
977 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
978 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
979 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
980 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
981 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
982 { "cld", OP_CLD, 0, 0, OPF_DATA },
983 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
984 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
985 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
986 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
987 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
988 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
989 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
990 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
991 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
992 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
993 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
994 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
995 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
996 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
997 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
998 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
999 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1000 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
1001 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
1002 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
1003 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
1004 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
1005 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
1006 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
1007 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
1008 { "test", OP_TEST, 2, 2, OPF_FLAGS },
1009 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
1010 { "retn", OP_RET, 0, 1, OPF_TAIL },
1011 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
1012 { "jmp", OP_JMP, 1, 1, OPF_JMP },
1013 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
1014 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
1015 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
1016 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
1017 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
1018 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
1019 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
1020 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1021 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1022 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
1023 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
1024 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
1025 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
1026 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1027 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1028 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1029 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1030 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1031 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1032 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1033 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1034 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1035 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1036 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1037 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1038 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1039 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1040 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1041 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1042 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1043 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1044 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1045 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1046 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1047 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1048 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1049 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1050 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1051 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1052 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1053 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1054 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1055 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1056 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1057 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1058 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1059 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1060 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1061 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1062 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1063 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1064 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1065 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1066 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1067 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1068 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1069 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1070 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1071 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1072 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1074 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1075 { "fild", OP_FILD, 1, 1, OPF_FPUSH },
1076 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1077 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1078 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1079 { "fst", OP_FST, 1, 1, 0 },
1080 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1081 { "fist", OP_FIST, 1, 1, 0 },
1082 { "fistp", OP_FIST, 1, 1, OPF_FPOP },
1083 { "fadd", OP_FADD, 0, 2, 0 },
1084 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1085 { "fdiv", OP_FDIV, 0, 2, 0 },
1086 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1087 { "fmul", OP_FMUL, 0, 2, 0 },
1088 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1089 { "fsub", OP_FSUB, 0, 2, 0 },
1090 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1091 { "fdivr", OP_FDIVR, 0, 2, 0 },
1092 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1093 { "fsubr", OP_FSUBR, 0, 2, 0 },
1094 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1095 { "fiadd", OP_FIADD, 1, 1, 0 },
1096 { "fidiv", OP_FIDIV, 1, 1, 0 },
1097 { "fimul", OP_FIMUL, 1, 1, 0 },
1098 { "fisub", OP_FISUB, 1, 1, 0 },
1099 { "fidivr", OP_FIDIVR, 1, 1, 0 },
1100 { "fisubr", OP_FISUBR, 1, 1, 0 },
1101 { "fcom", OP_FCOM, 0, 1, 0 },
1102 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1103 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1104 { "fchs", OP_FCHS, 0, 0, 0 },
1105 { "fcos", OP_FCOS, 0, 0, 0 },
1106 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1107 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1108 { "fsin", OP_FSIN, 0, 0, 0 },
1109 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1110 { "fxch", OP_FXCH, 1, 1, 0 },
1111 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1113 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1114 { "movq", OP_MOV, 2, 2, OPF_DATA },
1115 // pseudo-ops for lib calls
1116 { "_allshl",OPP_ALLSHL },
1117 { "_allshr",OPP_ALLSHR },
1118 { "_ftol", OPP_FTOL },
1119 { "_CIpow", OPP_CIPOW },
1124 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1126 enum opr_lenmod lmod = OPLM_UNSPEC;
1127 int prefix_flags = 0;
1135 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1136 if (IS(words[w], pref_table[i].name)) {
1137 prefix_flags = pref_table[i].flags;
1144 aerr("lone prefix: '%s'\n", words[0]);
1149 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1150 if (IS(words[w], op_table[i].name))
1154 if (i == ARRAY_SIZE(op_table)) {
1156 aerr("unhandled op: '%s'\n", words[0]);
1161 op->op = op_table[i].op;
1162 op->flags = op_table[i].flags | prefix_flags;
1163 op->pfo = op_table[i].pfo;
1164 op->pfo_inv = op_table[i].pfo_inv;
1165 op->regmask_src = op->regmask_dst = 0;
1168 if (op->op == OP_UD2)
1171 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1172 if (opr >= op_table[i].minopr && w >= wordc)
1175 regmask = regmask_ind = 0;
1176 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1177 words, wordc, w, op->flags);
1179 if (opr == 0 && (op->flags & OPF_DATA))
1180 op->regmask_dst = regmask;
1182 op->regmask_src |= regmask;
1183 op->regmask_src |= regmask_ind;
1185 if (op->operand[opr].lmod != OPLM_UNSPEC)
1186 g_func_lmods |= 1 << op->operand[opr].lmod;
1190 aerr("parse_op %s incomplete: %d/%d\n",
1191 words[0], w, wordc);
1194 op->operand_cnt = opr;
1195 if (!strncmp(op_table[i].name, "set", 3))
1196 op->operand[0].lmod = OPLM_BYTE;
1199 // first operand is not dst
1202 op->regmask_src |= op->regmask_dst;
1203 op->regmask_dst = 0;
1206 // first operand is src too
1219 op->regmask_src |= op->regmask_dst;
1224 op->regmask_src |= op->regmask_dst;
1225 op->regmask_dst |= op->regmask_src;
1231 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1232 && op->operand[0].lmod == op->operand[1].lmod
1233 && op->operand[0].reg == op->operand[1].reg
1234 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1236 op->regmask_src = 0;
1239 op->regmask_src |= op->regmask_dst;
1242 // ops with implicit argumets
1244 op->operand_cnt = 2;
1245 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1246 op->regmask_dst = op->regmask_src;
1247 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1251 op->operand_cnt = 2;
1252 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1253 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1259 if (words[op_w][4] == 'b')
1261 else if (words[op_w][4] == 'w')
1263 else if (words[op_w][4] == 'd')
1266 op->regmask_src = 0;
1267 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1268 OPLM_DWORD, &op->regmask_src);
1269 op->regmask_dst = op->regmask_src;
1270 setup_reg_opr(&op->operand[j++], xAX, lmod,
1271 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1272 if (op->flags & OPF_REP) {
1273 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1274 op->regmask_dst |= 1 << xCX;
1276 op->operand_cnt = j;
1281 if (words[op_w][4] == 'b')
1283 else if (words[op_w][4] == 'w')
1285 else if (words[op_w][4] == 'd')
1288 op->regmask_src = 0;
1289 // note: lmod is not correct, don't have where to place it
1290 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1291 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1292 if (op->flags & OPF_REP)
1293 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1294 op->operand_cnt = j;
1295 op->regmask_dst = op->regmask_src;
1299 op->regmask_dst = 1 << xCX;
1302 op->operand_cnt = 2;
1303 op->regmask_src = 1 << xCX;
1304 op->operand[1].type = OPT_REG;
1305 op->operand[1].reg = xCX;
1306 op->operand[1].lmod = OPLM_DWORD;
1310 if (op->operand_cnt == 2) {
1311 if (op->operand[0].type != OPT_REG)
1312 aerr("reg expected\n");
1313 op->regmask_src |= 1 << op->operand[0].reg;
1315 if (op->operand_cnt != 1)
1320 op->regmask_src |= op->regmask_dst;
1321 op->regmask_dst = (1 << xDX) | (1 << xAX);
1322 if (op->operand[0].lmod == OPLM_UNSPEC)
1323 op->operand[0].lmod = OPLM_DWORD;
1328 // we could set up operands for edx:eax, but there is no real need to
1329 // (see is_opr_modified())
1330 op->regmask_src |= op->regmask_dst;
1331 op->regmask_dst = (1 << xDX) | (1 << xAX);
1332 if (op->operand[0].lmod == OPLM_UNSPEC)
1333 op->operand[0].lmod = OPLM_DWORD;
1341 op->regmask_src |= op->regmask_dst;
1342 if (op->operand[1].lmod == OPLM_UNSPEC)
1343 op->operand[1].lmod = OPLM_BYTE;
1348 op->regmask_src |= op->regmask_dst;
1349 if (op->operand[2].lmod == OPLM_UNSPEC)
1350 op->operand[2].lmod = OPLM_BYTE;
1354 op->regmask_src |= op->regmask_dst;
1355 op->regmask_dst = 0;
1356 if (op->operand[0].lmod == OPLM_UNSPEC
1357 && (op->operand[0].type == OPT_CONST
1358 || op->operand[0].type == OPT_OFFSET
1359 || op->operand[0].type == OPT_LABEL))
1360 op->operand[0].lmod = OPLM_DWORD;
1366 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1367 && op->operand[0].lmod == op->operand[1].lmod
1368 && op->operand[0].reg == op->operand[1].reg
1369 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1371 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1372 op->regmask_src = op->regmask_dst = 0;
1377 if (op->operand[0].type == OPT_REG
1378 && op->operand[1].type == OPT_REGMEM)
1381 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1382 if (IS(buf, op->operand[1].name))
1383 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1388 // trashed regs must be explicitly detected later
1389 op->regmask_dst = 0;
1393 op->regmask_dst = (1 << xBP) | (1 << xSP);
1394 op->regmask_src = 1 << xBP;
1399 op->regmask_dst |= mxST0;
1403 op->regmask_dst |= mxST0;
1404 if (IS(words[op_w] + 3, "1"))
1405 op->operand[0].val = X87_CONST_1;
1406 else if (IS(words[op_w] + 3, "ln2"))
1407 op->operand[0].val = X87_CONST_LN2;
1408 else if (IS(words[op_w] + 3, "z"))
1409 op->operand[0].val = X87_CONST_Z;
1416 op->regmask_src |= mxST0;
1425 op->regmask_src |= mxST0;
1426 if (op->operand_cnt == 2)
1427 op->regmask_src |= op->regmask_dst;
1428 else if (op->operand_cnt == 1) {
1429 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1430 op->operand[0].type = OPT_REG;
1431 op->operand[0].lmod = OPLM_QWORD;
1432 op->operand[0].reg = xST0;
1433 op->regmask_dst |= mxST0;
1436 // IDA doesn't use this
1437 aerr("no operands?\n");
1451 op->regmask_src |= mxST0;
1452 op->regmask_dst |= mxST0;
1457 op->regmask_src |= mxST0 | mxST1;
1458 op->regmask_dst |= mxST0;
1466 op->regmask_src |= mxST0;
1473 if (op->operand[0].type == OPT_REG
1474 && op->operand[1].type == OPT_CONST)
1476 struct parsed_opr *op1 = &op->operand[1];
1477 if ((op->op == OP_AND && op1->val == 0)
1480 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1481 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1483 op->regmask_src = 0;
1488 static const char *op_name(struct parsed_op *po)
1490 static char buf[16];
1494 if (po->op == OP_JCC || po->op == OP_SCC) {
1496 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1499 strcpy(p, parsed_flag_op_names[po->pfo]);
1503 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1504 if (op_table[i].op == po->op)
1505 return op_table[i].name;
1511 static const char *dump_op(struct parsed_op *po)
1513 static char out[128];
1520 snprintf(out, sizeof(out), "%s", op_name(po));
1521 for (i = 0; i < po->operand_cnt; i++) {
1525 snprintf(p, sizeof(out) - (p - out),
1526 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1527 po->operand[i].name);
1533 static const char *lmod_type_u(struct parsed_op *po,
1534 enum opr_lenmod lmod)
1546 ferr(po, "invalid lmod: %d\n", lmod);
1547 return "(_invalid_)";
1551 static const char *lmod_cast_u(struct parsed_op *po,
1552 enum opr_lenmod lmod)
1564 ferr(po, "invalid lmod: %d\n", lmod);
1565 return "(_invalid_)";
1569 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1570 enum opr_lenmod lmod)
1582 ferr(po, "invalid lmod: %d\n", lmod);
1583 return "(_invalid_)";
1587 static const char *lmod_cast_s(struct parsed_op *po,
1588 enum opr_lenmod lmod)
1600 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1601 return "(_invalid_)";
1605 static const char *lmod_cast(struct parsed_op *po,
1606 enum opr_lenmod lmod, int is_signed)
1609 lmod_cast_s(po, lmod) :
1610 lmod_cast_u(po, lmod);
1613 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1625 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1630 static const char *opr_name(struct parsed_op *po, int opr_num)
1632 if (opr_num >= po->operand_cnt)
1633 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1634 return po->operand[opr_num].name;
1637 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1639 if (opr_num >= po->operand_cnt)
1640 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1641 if (po->operand[opr_num].type != OPT_CONST)
1642 ferr(po, "opr %d: const expected\n", opr_num);
1643 return po->operand[opr_num].val;
1646 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1648 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1649 ferr(po, "invalid reg: %d\n", popr->reg);
1650 return regs_r32[popr->reg];
1653 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1655 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1657 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1659 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1661 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1666 *is_signed = cast[1] == 's' ? 1 : 0;
1670 static int check_deref_cast(const char *cast, int *bits)
1672 if (IS_START(cast, "*(u8 *)"))
1674 else if (IS_START(cast, "*(u16 *)"))
1676 else if (IS_START(cast, "*(u32 *)"))
1678 else if (IS_START(cast, "*(u64 *)"))
1686 // cast1 is the "final" cast
1687 static const char *simplify_cast(const char *cast1, const char *cast2)
1689 static char buf[256];
1697 if (IS(cast1, cast2))
1700 if (check_simple_cast(cast1, &bits1, &s1) == 0
1701 && check_simple_cast(cast2, &bits2, &s2) == 0)
1706 if (check_simple_cast(cast1, &bits1, &s1) == 0
1707 && check_deref_cast(cast2, &bits2) == 0)
1709 if (bits1 == bits2) {
1710 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1715 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1718 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1722 static const char *simplify_cast_num(const char *cast, unsigned int val)
1724 if (IS(cast, "(u8)") && val < 0x100)
1726 if (IS(cast, "(s8)") && val < 0x80)
1728 if (IS(cast, "(u16)") && val < 0x10000)
1730 if (IS(cast, "(s16)") && val < 0x8000)
1732 if (IS(cast, "(s32)") && val < 0x80000000)
1738 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1747 namelen = strlen(name);
1749 p = strpbrk(name, "+-");
1753 ferr(po, "equ parse failed for '%s'\n", name);
1756 *extra_offs = strtol(p, &endp, 16);
1757 if (*endp != 0 || errno != 0)
1758 ferr(po, "equ parse failed for '%s'\n", name);
1761 for (i = 0; i < g_eqcnt; i++)
1762 if (strncmp(g_eqs[i].name, name, namelen) == 0
1763 && g_eqs[i].name[namelen] == 0)
1767 ferr(po, "unresolved equ name: '%s'\n", name);
1774 static int is_stack_access(struct parsed_op *po,
1775 const struct parsed_opr *popr)
1777 return (parse_stack_el(popr->name, NULL, NULL, 0)
1778 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1779 && IS_START(popr->name, "ebp")));
1782 static void parse_stack_access(struct parsed_op *po,
1783 const char *name, char *ofs_reg, int *offset_out,
1784 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1786 const char *bp_arg = "";
1787 const char *p = NULL;
1788 struct parsed_equ *eq;
1795 if (IS_START(name, "ebp-")
1796 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1799 if (IS_START(p, "0x"))
1802 offset = strtoul(p, &endp, 16);
1805 if (*endp != 0 || errno != 0)
1806 ferr(po, "ebp- parse of '%s' failed\n", name);
1809 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1810 eq = equ_find(po, bp_arg, &offset);
1812 ferr(po, "detected but missing eq\n");
1813 offset += eq->offset;
1816 if (!strncmp(name, "ebp", 3))
1819 // yes it sometimes LEAs ra for compares..
1820 if (!is_lea && ofs_reg[0] == 0
1821 && stack_ra <= offset && offset < stack_ra + 4)
1823 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1826 *offset_out = offset;
1828 *stack_ra_out = stack_ra;
1830 *bp_arg_out = bp_arg;
1833 static int parse_stack_esp_offset(struct parsed_op *po,
1834 const char *name, int *offset_out)
1836 char ofs_reg[16] = { 0, };
1837 struct parsed_equ *eq;
1843 if (strstr(name, "esp") == NULL)
1845 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1846 if (bp_arg == NULL) {
1847 // just plain offset?
1848 if (!IS_START(name, "esp+"))
1851 offset = strtol(name + 4, &endp, 0);
1852 if (endp == NULL || *endp != 0 || errno != 0)
1854 *offset_out = offset;
1858 if (ofs_reg[0] != 0)
1860 eq = equ_find(po, bp_arg, &offset);
1862 ferr(po, "detected but missing eq\n");
1863 offset += eq->offset;
1864 *offset_out = base_val + offset;
1868 static int stack_frame_access(struct parsed_op *po,
1869 struct parsed_opr *popr, char *buf, size_t buf_size,
1870 const char *name, const char *cast, int is_src, int is_lea)
1872 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1873 const char *prefix = "";
1874 const char *bp_arg = NULL;
1875 char ofs_reg[16] = { 0, };
1876 int i, arg_i, arg_s;
1883 if (po->flags & OPF_EBP_S)
1884 ferr(po, "stack_frame_access while ebp is scratch\n");
1886 parse_stack_access(po, name, ofs_reg, &offset,
1887 &stack_ra, &bp_arg, is_lea);
1889 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1891 if (offset > stack_ra)
1893 arg_i = (offset - stack_ra - 4) / 4;
1894 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1896 if (g_func_pp->is_vararg
1897 && arg_i == g_func_pp->argc_stack && is_lea)
1899 // should be va_list
1902 snprintf(buf, buf_size, "%sap", cast);
1905 ferr(po, "offset %d (%s,%d) doesn't map to any arg\n",
1906 offset, bp_arg, arg_i);
1908 if (ofs_reg[0] != 0)
1909 ferr(po, "offset reg on arg access?\n");
1911 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1912 if (g_func_pp->arg[i].reg != NULL)
1918 if (i == g_func_pp->argc)
1919 ferr(po, "arg %d not in prototype?\n", arg_i);
1921 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1928 ferr(po, "lea/byte to arg?\n");
1929 if (is_src && (offset & 3) == 0)
1930 snprintf(buf, buf_size, "%sa%d",
1931 simplify_cast(cast, "(u8)"), i + 1);
1933 snprintf(buf, buf_size, "%sBYTE%d(a%d)",
1934 cast, offset & 3, i + 1);
1939 ferr(po, "lea/word to arg?\n");
1944 ferr(po, "problematic arg store\n");
1945 snprintf(buf, buf_size, "%s((char *)&a%d + 1)",
1946 simplify_cast(cast, "*(u16 *)"), i + 1);
1949 ferr(po, "unaligned arg word load\n");
1951 else if (is_src && (offset & 2) == 0)
1952 snprintf(buf, buf_size, "%sa%d",
1953 simplify_cast(cast, "(u16)"), i + 1);
1955 snprintf(buf, buf_size, "%s%sWORD(a%d)",
1956 cast, (offset & 2) ? "HI" : "LO", i + 1);
1968 snprintf(buf, buf_size, "(u32)&a%d + %d",
1971 ferr(po, "unaligned arg store\n");
1973 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
1974 snprintf(buf, buf_size, "%s(a%d >> %d)",
1975 prefix, i + 1, (offset & 3) * 8);
1979 snprintf(buf, buf_size, "%s%sa%d",
1980 prefix, is_lea ? "&" : "", i + 1);
1985 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
1989 strcat(g_comment, " unaligned");
1992 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
1993 if (tmp_lmod != OPLM_DWORD
1994 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
1995 < lmod_bytes(po, popr->lmod) + (offset & 3))))
1997 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
1998 i + 1, offset, g_func_pp->arg[i].type.name);
2000 // can't check this because msvc likes to reuse
2001 // arg space for scratch..
2002 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
2003 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2007 if (g_stack_fsz == 0)
2008 ferr(po, "stack var access without stackframe\n");
2009 g_stack_frame_used = 1;
2011 sf_ofs = g_stack_fsz + offset;
2012 if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2013 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2023 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2024 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2028 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2029 // known unaligned or possibly unaligned
2030 strcat(g_comment, " unaligned");
2032 prefix = "*(u16 *)&";
2033 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2034 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2037 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2041 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2042 // known unaligned or possibly unaligned
2043 strcat(g_comment, " unaligned");
2045 prefix = "*(u32 *)&";
2046 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2047 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2050 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2054 ferr_assert(po, !(sf_ofs & 7));
2055 ferr_assert(po, ofs_reg[0] == 0);
2056 // only used for x87 int64/float, float sets is_lea
2058 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2060 snprintf(buf, buf_size, "*(s64 *)&sf.q[%d]", sf_ofs / 8);
2064 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2071 static void check_func_pp(struct parsed_op *po,
2072 const struct parsed_proto *pp, const char *pfx)
2074 enum opr_lenmod tmp_lmod;
2078 if (pp->argc_reg != 0) {
2079 if (!g_allow_user_icall && !pp->is_fastcall) {
2080 pp_print(buf, sizeof(buf), pp);
2081 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2083 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2084 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2085 pfx, pp->argc_reg, pp->argc_stack);
2088 // fptrs must use 32bit args, callsite might have no information and
2089 // lack a cast to smaller types, which results in incorrectly masked
2090 // args passed (callee may assume masked args, it does on ARM)
2091 if (!pp->is_osinc) {
2092 for (i = 0; i < pp->argc; i++) {
2093 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2094 if (ret && tmp_lmod != OPLM_DWORD)
2095 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2096 i + 1, pp->arg[i].type.name);
2101 static const char *check_label_read_ref(struct parsed_op *po,
2104 const struct parsed_proto *pp;
2106 pp = proto_parse(g_fhdr, name, 0);
2108 ferr(po, "proto_parse failed for ref '%s'\n", name);
2111 check_func_pp(po, pp, "ref");
2116 static char *out_src_opr(char *buf, size_t buf_size,
2117 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2120 char tmp1[256], tmp2[256];
2129 switch (popr->type) {
2132 ferr(po, "lea from reg?\n");
2134 switch (popr->lmod) {
2136 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2139 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2142 snprintf(buf, buf_size, "%s%s",
2143 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2146 if (popr->name[1] == 'h') // XXX..
2147 snprintf(buf, buf_size, "%s(%s >> 8)",
2148 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2150 snprintf(buf, buf_size, "%s%s",
2151 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2154 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2159 if (is_stack_access(po, popr)) {
2160 stack_frame_access(po, popr, buf, buf_size,
2161 popr->name, cast, 1, is_lea);
2165 strcpy(expr, popr->name);
2166 if (strchr(expr, '[')) {
2167 // special case: '[' can only be left for label[reg] form
2168 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2170 ferr(po, "parse failure for '%s'\n", expr);
2171 if (tmp1[0] == '(') {
2172 // (off_4FFF50+3)[eax]
2173 p = strchr(tmp1 + 1, ')');
2174 if (p == NULL || p[1] != 0)
2175 ferr(po, "parse failure (2) for '%s'\n", expr);
2177 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2179 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2182 // XXX: do we need more parsing?
2184 snprintf(buf, buf_size, "%s", expr);
2188 snprintf(buf, buf_size, "%s(%s)",
2189 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2193 name = check_label_read_ref(po, popr->name);
2194 if (cast[0] == 0 && popr->is_ptr)
2198 snprintf(buf, buf_size, "(u32)&%s", name);
2199 else if (popr->size_lt)
2200 snprintf(buf, buf_size, "%s%s%s%s", cast,
2201 lmod_cast_u_ptr(po, popr->lmod),
2202 popr->is_array ? "" : "&", name);
2204 snprintf(buf, buf_size, "%s%s%s", cast, name,
2205 popr->is_array ? "[0]" : "");
2209 name = check_label_read_ref(po, popr->name);
2213 ferr(po, "lea an offset?\n");
2214 snprintf(buf, buf_size, "%s&%s", cast, name);
2219 ferr(po, "lea from const?\n");
2221 printf_number(tmp1, sizeof(tmp1), popr->val);
2222 if (popr->val == 0 && strchr(cast, '*'))
2223 snprintf(buf, buf_size, "NULL");
2225 snprintf(buf, buf_size, "%s%s",
2226 simplify_cast_num(cast, popr->val), tmp1);
2230 ferr(po, "invalid src type: %d\n", popr->type);
2236 // note: may set is_ptr (we find that out late for ebp frame..)
2237 static char *out_dst_opr(char *buf, size_t buf_size,
2238 struct parsed_op *po, struct parsed_opr *popr)
2240 switch (popr->type) {
2242 switch (popr->lmod) {
2244 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2247 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2251 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2255 if (popr->name[1] == 'h') // XXX..
2256 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2258 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2261 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2266 if (is_stack_access(po, popr)) {
2267 stack_frame_access(po, popr, buf, buf_size,
2268 popr->name, "", 0, 0);
2272 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2275 if (popr->size_mismatch)
2276 snprintf(buf, buf_size, "%s%s%s",
2277 lmod_cast_u_ptr(po, popr->lmod),
2278 popr->is_array ? "" : "&", popr->name);
2280 snprintf(buf, buf_size, "%s%s", popr->name,
2281 popr->is_array ? "[0]" : "");
2285 ferr(po, "invalid dst type: %d\n", popr->type);
2291 static char *out_src_opr_u32(char *buf, size_t buf_size,
2292 struct parsed_op *po, struct parsed_opr *popr)
2294 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2297 static char *out_src_opr_float(char *buf, size_t buf_size,
2298 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2300 const char *cast = NULL;
2303 switch (popr->type) {
2305 if (popr->reg < xST0 || popr->reg > xST7)
2306 ferr(po, "bad reg: %d\n", popr->reg);
2308 if (need_float_stack) {
2309 if (popr->reg == xST0)
2310 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2312 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2316 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2322 switch (popr->lmod) {
2330 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2333 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2334 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2338 ferr(po, "invalid float type: %d\n", popr->type);
2344 static char *out_dst_opr_float(char *buf, size_t buf_size,
2345 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2348 return out_src_opr_float(buf, buf_size, po, popr, need_float_stack);
2351 static void out_test_for_cc(char *buf, size_t buf_size,
2352 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2353 enum opr_lenmod lmod, const char *expr)
2355 const char *cast, *scast;
2357 cast = lmod_cast_u(po, lmod);
2358 scast = lmod_cast_s(po, lmod);
2362 case PFO_BE: // CF==1||ZF==1; CF=0
2363 snprintf(buf, buf_size, "(%s%s %s 0)",
2364 cast, expr, is_inv ? "!=" : "==");
2368 case PFO_L: // SF!=OF; OF=0
2369 snprintf(buf, buf_size, "(%s%s %s 0)",
2370 scast, expr, is_inv ? ">=" : "<");
2373 case PFO_LE: // ZF==1||SF!=OF; OF=0
2374 snprintf(buf, buf_size, "(%s%s %s 0)",
2375 scast, expr, is_inv ? ">" : "<=");
2380 snprintf(buf, buf_size, "(%d)", !!is_inv);
2384 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2388 static void out_cmp_for_cc(char *buf, size_t buf_size,
2389 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2392 const char *cast, *scast, *cast_use;
2393 char buf1[256], buf2[256];
2394 enum opr_lenmod lmod;
2396 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2397 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2398 po->operand[0].lmod, po->operand[1].lmod);
2399 lmod = po->operand[0].lmod;
2401 cast = lmod_cast_u(po, lmod);
2402 scast = lmod_cast_s(po, lmod);
2418 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2421 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2422 if (po->op == OP_DEC)
2423 snprintf(buf2, sizeof(buf2), "1");
2426 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2428 strcat(cast_op2, "-");
2429 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2434 // note: must be unsigned compare
2435 snprintf(buf, buf_size, "(%s %s %s)",
2436 buf1, is_inv ? ">=" : "<", buf2);
2440 snprintf(buf, buf_size, "(%s %s %s)",
2441 buf1, is_inv ? "!=" : "==", buf2);
2445 // note: must be unsigned compare
2446 snprintf(buf, buf_size, "(%s %s %s)",
2447 buf1, is_inv ? ">" : "<=", buf2);
2450 if (is_inv && lmod == OPLM_BYTE
2451 && po->operand[1].type == OPT_CONST
2452 && po->operand[1].val == 0xff)
2454 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2455 snprintf(buf, buf_size, "(0)");
2459 // note: must be signed compare
2461 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2462 scast, buf1, buf2, is_inv ? ">=" : "<");
2466 snprintf(buf, buf_size, "(%s %s %s)",
2467 buf1, is_inv ? ">=" : "<", buf2);
2471 snprintf(buf, buf_size, "(%s %s %s)",
2472 buf1, is_inv ? ">" : "<=", buf2);
2480 static void out_cmp_test(char *buf, size_t buf_size,
2481 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2483 char buf1[256], buf2[256], buf3[256];
2485 if (po->op == OP_TEST) {
2486 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2487 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2490 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2491 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2492 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2494 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2495 po->operand[0].lmod, buf3);
2497 else if (po->op == OP_CMP) {
2498 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2501 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2504 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2505 struct parsed_opr *popr2)
2507 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2508 ferr(po, "missing lmod for both operands\n");
2510 if (popr1->lmod == OPLM_UNSPEC)
2511 popr1->lmod = popr2->lmod;
2512 else if (popr2->lmod == OPLM_UNSPEC)
2513 popr2->lmod = popr1->lmod;
2514 else if (popr1->lmod != popr2->lmod) {
2515 if (popr1->type_from_var) {
2516 popr1->size_mismatch = 1;
2517 if (popr1->lmod < popr2->lmod)
2519 popr1->lmod = popr2->lmod;
2521 else if (popr2->type_from_var) {
2522 popr2->size_mismatch = 1;
2523 if (popr2->lmod < popr1->lmod)
2525 popr2->lmod = popr1->lmod;
2528 ferr(po, "conflicting lmods: %d vs %d\n",
2529 popr1->lmod, popr2->lmod);
2533 static const char *op_to_c(struct parsed_op *po)
2557 ferr(po, "op_to_c was supplied with %d\n", po->op);
2561 // last op in stream - unconditional branch or ret
2562 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2563 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2564 && ops[_i].op != OP_CALL))
2566 #define check_i(po, i) \
2568 ferr(po, "bad " #i ": %d\n", i)
2570 // note: this skips over calls and rm'd stuff assuming they're handled
2571 // so it's intended to use at one of final passes
2572 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2573 int depth, int seen_noreturn, int flags_set)
2575 struct parsed_op *po;
2580 for (; i < opcnt; i++) {
2582 if (po->cc_scratch == magic)
2583 return ret; // already checked
2584 po->cc_scratch = magic;
2586 if (po->flags & OPF_TAIL) {
2587 if (po->op == OP_CALL) {
2588 if (po->pp != NULL && po->pp->is_noreturn)
2597 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2600 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2601 if (po->btj != NULL) {
2603 for (j = 0; j < po->btj->count; j++) {
2604 check_i(po, po->btj->d[j].bt_i);
2605 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2606 depth, seen_noreturn, flags_set);
2608 return ret; // dead end
2613 check_i(po, po->bt_i);
2614 if (po->flags & OPF_CJMP) {
2615 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2616 depth, seen_noreturn, flags_set);
2618 return ret; // dead end
2627 if ((po->op == OP_POP || po->op == OP_PUSH)
2628 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2633 if (po->op == OP_PUSH) {
2636 else if (po->op == OP_POP) {
2637 if (relevant && depth == 0) {
2638 po->flags |= flags_set;
2646 // for noreturn, assume msvc skipped stack cleanup
2647 return seen_noreturn ? 1 : -1;
2650 // scan for 'reg' pop backwards starting from i
2651 // intended to use for register restore search, so other reg
2652 // references are considered an error
2653 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2655 struct parsed_op *po;
2656 struct label_ref *lr;
2659 ops[i].cc_scratch = magic;
2663 if (g_labels[i] != NULL) {
2664 lr = &g_label_refs[i];
2665 for (; lr != NULL; lr = lr->next) {
2666 check_i(&ops[i], lr->i);
2667 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2671 if (i > 0 && LAST_OP(i - 1))
2679 if (ops[i].cc_scratch == magic)
2681 ops[i].cc_scratch = magic;
2684 if (po->op == OP_POP && po->operand[0].reg == reg) {
2685 if (po->flags & (OPF_RMD|OPF_DONE))
2688 po->flags |= set_flags;
2692 // this also covers the case where we reach corresponding push
2693 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2697 // nothing interesting on this path
2701 static void find_reachable_exits(int i, int opcnt, int magic,
2702 int *exits, int *exit_count)
2704 struct parsed_op *po;
2707 for (; i < opcnt; i++)
2710 if (po->cc_scratch == magic)
2712 po->cc_scratch = magic;
2714 if (po->flags & OPF_TAIL) {
2715 ferr_assert(po, *exit_count < MAX_EXITS);
2716 exits[*exit_count] = i;
2721 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2722 if (po->flags & OPF_RMD)
2725 if (po->btj != NULL) {
2726 for (j = 0; j < po->btj->count; j++) {
2727 check_i(po, po->btj->d[j].bt_i);
2728 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2734 check_i(po, po->bt_i);
2735 if (po->flags & OPF_CJMP)
2736 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2744 // scan for 'reg' pop backwards starting from exits (all paths)
2745 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2747 static int exits[MAX_EXITS];
2748 static int exit_count;
2753 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2755 ferr_assert(&ops[i], exit_count > 0);
2758 for (j = 0; j < exit_count; j++) {
2759 ret = scan_for_rsave_pop_reg(exits[j], i + opcnt * 16 + set_flags,
2768 // scan for one or more pop of push <const>
2769 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2770 int push_i, int is_probe)
2772 struct parsed_op *po;
2773 struct label_ref *lr;
2777 for (; i < opcnt; i++)
2780 if (po->cc_scratch == magic)
2781 return ret; // already checked
2782 po->cc_scratch = magic;
2784 if (po->flags & OPF_JMP) {
2785 if (po->flags & OPF_RMD)
2787 if (po->op == OP_CALL)
2790 if (po->btj != NULL) {
2791 for (j = 0; j < po->btj->count; j++) {
2792 check_i(po, po->btj->d[j].bt_i);
2793 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2801 check_i(po, po->bt_i);
2802 if (po->flags & OPF_CJMP) {
2803 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2814 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2817 if (g_labels[i] != NULL) {
2818 // all refs must be visited
2819 lr = &g_label_refs[i];
2820 for (; lr != NULL; lr = lr->next) {
2822 if (ops[lr->i].cc_scratch != magic)
2825 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2829 if (po->op == OP_POP)
2831 if (po->flags & (OPF_RMD|OPF_DONE))
2835 po->flags |= OPF_DONE;
2836 po->datap = &ops[push_i];
2845 static void scan_for_pop_const(int i, int opcnt, int magic)
2849 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2851 ops[i].flags |= OPF_RMD | OPF_DONE;
2852 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2856 // check if all branch targets within a marked path are also marked
2857 // note: the path checked must not be empty or end with a branch
2858 static int check_path_branches(int opcnt, int magic)
2860 struct parsed_op *po;
2863 for (i = 0; i < opcnt; i++) {
2865 if (po->cc_scratch != magic)
2868 if (po->flags & OPF_JMP) {
2869 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2872 if (po->btj != NULL) {
2873 for (j = 0; j < po->btj->count; j++) {
2874 check_i(po, po->btj->d[j].bt_i);
2875 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2880 check_i(po, po->bt_i);
2881 if (ops[po->bt_i].cc_scratch != magic)
2883 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2891 // scan for multiple pushes for given pop
2892 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2895 int reg = ops[pop_i].operand[0].reg;
2896 struct parsed_op *po;
2897 struct label_ref *lr;
2900 ops[i].cc_scratch = magic;
2904 if (g_labels[i] != NULL) {
2905 lr = &g_label_refs[i];
2906 for (; lr != NULL; lr = lr->next) {
2907 check_i(&ops[i], lr->i);
2908 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2912 if (i > 0 && LAST_OP(i - 1))
2920 if (ops[i].cc_scratch == magic)
2922 ops[i].cc_scratch = magic;
2925 if (po->op == OP_CALL)
2927 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2930 if (po->op == OP_PUSH)
2932 if (po->datap != NULL)
2934 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2935 // leave this case for reg save/restore handlers
2939 po->flags |= OPF_PPUSH | OPF_DONE;
2940 po->datap = &ops[pop_i];
2949 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2951 int magic = i + opcnt * 14;
2954 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2956 ret = check_path_branches(opcnt, magic);
2958 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2959 *regmask_pp |= 1 << ops[i].operand[0].reg;
2960 scan_pushes_for_pop_r(i, magic + 1, i, 0);
2965 static void scan_propagate_df(int i, int opcnt)
2967 struct parsed_op *po = &ops[i];
2970 for (; i < opcnt; i++) {
2972 if (po->flags & OPF_DF)
2973 return; // already resolved
2974 po->flags |= OPF_DF;
2976 if (po->op == OP_CALL)
2977 ferr(po, "call with DF set?\n");
2979 if (po->flags & OPF_JMP) {
2980 if (po->btj != NULL) {
2982 for (j = 0; j < po->btj->count; j++) {
2983 check_i(po, po->btj->d[j].bt_i);
2984 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
2989 if (po->flags & OPF_RMD)
2991 check_i(po, po->bt_i);
2992 if (po->flags & OPF_CJMP)
2993 scan_propagate_df(po->bt_i, opcnt);
2999 if (po->flags & OPF_TAIL)
3002 if (po->op == OP_CLD) {
3003 po->flags |= OPF_RMD | OPF_DONE;
3008 ferr(po, "missing DF clear?\n");
3011 // is operand 'opr' referenced by parsed_op 'po'?
3012 static int is_opr_referenced(const struct parsed_opr *opr,
3013 const struct parsed_op *po)
3017 if (opr->type == OPT_REG) {
3018 mask = po->regmask_dst | po->regmask_src;
3019 if (po->op == OP_CALL)
3020 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3021 if ((1 << opr->reg) & mask)
3027 for (i = 0; i < po->operand_cnt; i++)
3028 if (IS(po->operand[0].name, opr->name))
3034 // is operand 'opr' read by parsed_op 'po'?
3035 static int is_opr_read(const struct parsed_opr *opr,
3036 const struct parsed_op *po)
3038 if (opr->type == OPT_REG) {
3039 if (po->regmask_src & (1 << opr->reg))
3049 // is operand 'opr' modified by parsed_op 'po'?
3050 static int is_opr_modified(const struct parsed_opr *opr,
3051 const struct parsed_op *po)
3055 if (opr->type == OPT_REG) {
3056 if (po->op == OP_CALL) {
3057 mask = po->regmask_dst;
3058 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3059 if (mask & (1 << opr->reg))
3065 if (po->regmask_dst & (1 << opr->reg))
3071 return IS(po->operand[0].name, opr->name);
3074 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3075 static int is_any_opr_modified(const struct parsed_op *po_test,
3076 const struct parsed_op *po, int c_mode)
3081 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3084 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3087 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3090 // in reality, it can wreck any register, but in decompiled C
3091 // version it can only overwrite eax or edx:eax
3092 mask = (1 << xAX) | (1 << xDX);
3096 if (po->op == OP_CALL
3097 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3100 for (i = 0; i < po_test->operand_cnt; i++)
3101 if (IS(po_test->operand[i].name, po->operand[0].name))
3107 // scan for any po_test operand modification in range given
3108 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3111 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3114 for (; i < opcnt; i++) {
3115 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3122 // scan for po_test operand[0] modification in range given
3123 static int scan_for_mod_opr0(struct parsed_op *po_test,
3126 for (; i < opcnt; i++) {
3127 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3134 static int try_resolve_const(int i, const struct parsed_opr *opr,
3135 int magic, unsigned int *val);
3137 static int scan_for_flag_set(int i, int opcnt, int magic,
3138 int *branched, int *setters, int *setter_cnt)
3140 struct label_ref *lr;
3144 if (ops[i].cc_scratch == magic) {
3145 // is this a problem?
3146 //ferr(&ops[i], "%s looped\n", __func__);
3149 ops[i].cc_scratch = magic;
3151 if (g_labels[i] != NULL) {
3154 lr = &g_label_refs[i];
3155 for (; lr->next; lr = lr->next) {
3156 check_i(&ops[i], lr->i);
3157 ret = scan_for_flag_set(lr->i, opcnt, magic,
3158 branched, setters, setter_cnt);
3163 check_i(&ops[i], lr->i);
3164 if (i > 0 && LAST_OP(i - 1)) {
3168 ret = scan_for_flag_set(lr->i, opcnt, magic,
3169 branched, setters, setter_cnt);
3175 if (ops[i].flags & OPF_FLAGS) {
3176 setters[*setter_cnt] = i;
3179 if (ops[i].flags & OPF_REP) {
3180 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3183 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3184 if (ret != 1 || uval == 0) {
3185 // can't treat it as full setter because of ecx=0 case,
3186 // also disallow delayed compare
3195 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3202 // scan back for cdq, if anything modifies edx, fail
3203 static int scan_for_cdq_edx(int i)
3206 if (g_labels[i] != NULL) {
3207 if (g_label_refs[i].next != NULL)
3209 if (i > 0 && LAST_OP(i - 1)) {
3210 i = g_label_refs[i].i;
3217 if (ops[i].op == OP_CDQ)
3220 if (ops[i].regmask_dst & (1 << xDX))
3227 static int scan_for_reg_clear(int i, int reg)
3230 if (g_labels[i] != NULL) {
3231 if (g_label_refs[i].next != NULL)
3233 if (i > 0 && LAST_OP(i - 1)) {
3234 i = g_label_refs[i].i;
3241 if (ops[i].op == OP_XOR
3242 && ops[i].operand[0].lmod == OPLM_DWORD
3243 && ops[i].operand[0].reg == ops[i].operand[1].reg
3244 && ops[i].operand[0].reg == reg)
3247 if (ops[i].regmask_dst & (1 << reg))
3254 static void patch_esp_adjust(struct parsed_op *po, int adj)
3256 ferr_assert(po, po->op == OP_ADD);
3257 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3258 ferr_assert(po, po->operand[1].type == OPT_CONST);
3260 // this is a bit of a hack, but deals with use of
3261 // single adj for multiple calls
3262 po->operand[1].val -= adj;
3263 po->flags |= OPF_RMD;
3264 if (po->operand[1].val == 0)
3265 po->flags |= OPF_DONE;
3266 ferr_assert(po, (int)po->operand[1].val >= 0);
3269 // scan for positive, constant esp adjust
3270 // multipath case is preliminary
3271 static int scan_for_esp_adjust(int i, int opcnt,
3272 int adj_expect, int *adj, int *is_multipath, int do_update)
3274 int adj_expect_unknown = 0;
3275 struct parsed_op *po;
3279 *adj = *is_multipath = 0;
3280 if (adj_expect < 0) {
3281 adj_expect_unknown = 1;
3282 adj_expect = 32 * 4; // enough?
3285 for (; i < opcnt && *adj < adj_expect; i++) {
3286 if (g_labels[i] != NULL)
3290 if (po->flags & OPF_DONE)
3293 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3294 if (po->operand[1].type != OPT_CONST)
3295 ferr(&ops[i], "non-const esp adjust?\n");
3296 *adj += po->operand[1].val;
3298 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3301 patch_esp_adjust(po, adj_expect);
3303 po->flags |= OPF_RMD;
3307 else if (po->op == OP_PUSH) {
3308 //if (first_pop == -1)
3309 // first_pop = -2; // none
3310 *adj -= lmod_bytes(po, po->operand[0].lmod);
3312 else if (po->op == OP_POP) {
3313 if (!(po->flags & OPF_DONE)) {
3314 // seems like msvc only uses 'pop ecx' for stack realignment..
3315 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3317 if (first_pop == -1 && *adj >= 0)
3320 if (do_update && *adj >= 0) {
3321 po->flags |= OPF_RMD;
3323 po->flags |= OPF_DONE | OPF_NOREGS;
3326 *adj += lmod_bytes(po, po->operand[0].lmod);
3327 if (*adj > adj_best)
3330 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3331 if (po->op == OP_JMP && po->btj == NULL) {
3337 if (po->op != OP_CALL)
3339 if (po->operand[0].type != OPT_LABEL)
3341 if (po->pp != NULL && po->pp->is_stdcall)
3343 if (adj_expect_unknown && first_pop >= 0)
3345 // assume it's another cdecl call
3349 if (first_pop >= 0) {
3350 // probably only 'pop ecx' was used
3358 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3360 struct parsed_op *po;
3364 ferr(ops, "%s: followed bad branch?\n", __func__);
3366 for (; i < opcnt; i++) {
3368 if (po->cc_scratch == magic)
3370 po->cc_scratch = magic;
3373 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3374 if (po->btj != NULL) {
3376 for (j = 0; j < po->btj->count; j++)
3377 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3381 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3382 if (!(po->flags & OPF_CJMP))
3385 if (po->flags & OPF_TAIL)
3390 static const struct parsed_proto *try_recover_pp(
3391 struct parsed_op *po, const struct parsed_opr *opr,
3392 int is_call, int *search_instead)
3394 const struct parsed_proto *pp = NULL;
3398 // maybe an arg of g_func?
3399 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3401 char ofs_reg[16] = { 0, };
3402 int arg, arg_s, arg_i;
3409 parse_stack_access(po, opr->name, ofs_reg,
3410 &offset, &stack_ra, NULL, 0);
3411 if (ofs_reg[0] != 0)
3412 ferr(po, "offset reg on arg access?\n");
3413 if (offset <= stack_ra) {
3414 // search who set the stack var instead
3415 if (search_instead != NULL)
3416 *search_instead = 1;
3420 arg_i = (offset - stack_ra - 4) / 4;
3421 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3422 if (g_func_pp->arg[arg].reg != NULL)
3428 if (arg == g_func_pp->argc)
3429 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3431 pp = g_func_pp->arg[arg].pp;
3434 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3435 check_func_pp(po, pp, "icall arg");
3438 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3440 p = strchr(opr->name + 1, '[');
3441 memcpy(buf, opr->name, p - opr->name);
3442 buf[p - opr->name] = 0;
3443 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3445 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3446 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3449 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3452 check_func_pp(po, pp, "reg-fptr ref");
3458 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3459 int magic, const struct parsed_proto **pp_found, int *pp_i,
3462 const struct parsed_proto *pp = NULL;
3463 struct parsed_op *po;
3464 struct label_ref *lr;
3466 ops[i].cc_scratch = magic;
3469 if (g_labels[i] != NULL) {
3470 lr = &g_label_refs[i];
3471 for (; lr != NULL; lr = lr->next) {
3472 check_i(&ops[i], lr->i);
3473 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3475 if (i > 0 && LAST_OP(i - 1))
3483 if (ops[i].cc_scratch == magic)
3485 ops[i].cc_scratch = magic;
3487 if (!(ops[i].flags & OPF_DATA))
3489 if (!is_opr_modified(opr, &ops[i]))
3491 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3492 // most probably trashed by some processing
3497 opr = &ops[i].operand[1];
3498 if (opr->type != OPT_REG)
3502 po = (i >= 0) ? &ops[i] : ops;
3505 // reached the top - can only be an arg-reg
3506 if (opr->type != OPT_REG || g_func_pp == NULL)
3509 for (i = 0; i < g_func_pp->argc; i++) {
3510 if (g_func_pp->arg[i].reg == NULL)
3512 if (IS(opr->name, g_func_pp->arg[i].reg))
3515 if (i == g_func_pp->argc)
3517 pp = g_func_pp->arg[i].pp;
3519 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3520 i + 1, g_func_pp->arg[i].reg);
3521 check_func_pp(po, pp, "icall reg-arg");
3524 pp = try_recover_pp(po, opr, 1, NULL);
3526 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3527 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3528 || (*pp_found)->is_stdcall != pp->is_stdcall
3529 || (*pp_found)->is_fptr != pp->is_fptr
3530 || (*pp_found)->argc != pp->argc
3531 || (*pp_found)->argc_reg != pp->argc_reg
3532 || (*pp_found)->argc_stack != pp->argc_stack)
3534 ferr(po, "icall: parsed_proto mismatch\n");
3544 static void add_label_ref(struct label_ref *lr, int op_i)
3546 struct label_ref *lr_new;
3553 lr_new = calloc(1, sizeof(*lr_new));
3555 lr_new->next = lr->next;
3559 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3561 struct parsed_op *po = &ops[i];
3562 struct parsed_data *pd;
3563 char label[NAMELEN], *p;
3566 p = strchr(po->operand[0].name, '[');
3570 len = p - po->operand[0].name;
3571 strncpy(label, po->operand[0].name, len);
3574 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3575 if (IS(g_func_pd[j].label, label)) {
3581 //ferr(po, "label '%s' not parsed?\n", label);
3584 if (pd->type != OPT_OFFSET)
3585 ferr(po, "label '%s' with non-offset data?\n", label);
3587 // find all labels, link
3588 for (j = 0; j < pd->count; j++) {
3589 for (l = 0; l < opcnt; l++) {
3590 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3591 add_label_ref(&g_label_refs[l], i);
3601 static void clear_labels(int count)
3605 for (i = 0; i < count; i++) {
3606 if (g_labels[i] != NULL) {
3613 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3618 for (i = 0; i < pp->argc; i++) {
3619 if (pp->arg[i].reg != NULL) {
3620 reg = char_array_i(regs_r32,
3621 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3623 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3624 pp->arg[i].reg, pp->name);
3625 regmask |= 1 << reg;
3632 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3637 if (pp->has_retreg) {
3638 for (i = 0; i < pp->argc; i++) {
3639 if (pp->arg[i].type.is_retreg) {
3640 reg = char_array_i(regs_r32,
3641 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3642 ferr_assert(ops, reg >= 0);
3643 regmask |= 1 << reg;
3648 if (strstr(pp->ret_type.name, "int64"))
3649 return regmask | (1 << xAX) | (1 << xDX);
3650 if (IS(pp->ret_type.name, "float")
3651 || IS(pp->ret_type.name, "double"))
3653 return regmask | mxST0;
3655 if (strcasecmp(pp->ret_type.name, "void") == 0)
3658 return regmask | mxAX;
3661 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3663 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3664 && memcmp(po1->operand, po2->operand,
3665 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3668 static void resolve_branches_parse_calls(int opcnt)
3670 static const struct {
3674 unsigned int regmask_src;
3675 unsigned int regmask_dst;
3677 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3678 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3679 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3680 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3682 const struct parsed_proto *pp_c;
3683 struct parsed_proto *pp;
3684 struct parsed_data *pd;
3685 struct parsed_op *po;
3686 const char *tmpname;
3690 for (i = 0; i < opcnt; i++)
3696 if (po->datap != NULL) {
3697 pp = calloc(1, sizeof(*pp));
3698 my_assert_not(pp, NULL);
3700 ret = parse_protostr(po->datap, pp);
3702 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3708 if (po->op == OP_CALL) {
3713 else if (po->operand[0].type == OPT_LABEL)
3715 tmpname = opr_name(po, 0);
3716 if (IS_START(tmpname, "loc_"))
3717 ferr(po, "call to loc_*\n");
3718 if (IS(tmpname, "__alloca_probe"))
3721 // convert some calls to pseudo-ops
3722 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3723 if (!IS(tmpname, pseudo_ops[l].name))
3726 po->op = pseudo_ops[l].op;
3727 po->operand_cnt = 0;
3728 po->regmask_src = pseudo_ops[l].regmask_src;
3729 po->regmask_dst = pseudo_ops[l].regmask_dst;
3730 po->flags = pseudo_ops[l].flags;
3731 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3734 if (l < ARRAY_SIZE(pseudo_ops))
3737 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3738 if (!g_header_mode && pp_c == NULL)
3739 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3742 pp = proto_clone(pp_c);
3743 my_assert_not(pp, NULL);
3749 check_func_pp(po, pp, "fptr var call");
3750 if (pp->is_noreturn)
3751 po->flags |= OPF_TAIL;
3757 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3760 if (po->operand[0].type == OPT_REGMEM) {
3761 pd = try_resolve_jumptab(i, opcnt);
3769 for (l = 0; l < opcnt; l++) {
3770 if (g_labels[l] != NULL
3771 && IS(po->operand[0].name, g_labels[l]))
3773 if (l == i + 1 && po->op == OP_JMP) {
3774 // yet another alignment type..
3775 po->flags |= OPF_RMD|OPF_DONE;
3778 add_label_ref(&g_label_refs[l], i);
3784 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3787 if (po->operand[0].type == OPT_LABEL)
3791 ferr(po, "unhandled branch\n");
3795 po->flags |= OPF_TAIL;
3796 if (i > 0 && ops[i - 1].op == OP_POP)
3797 po->flags |= OPF_ATAIL;
3802 static void scan_prologue_epilogue(int opcnt)
3804 int ecx_push = 0, esp_sub = 0, pusha = 0;
3805 int sandard_epilogue;
3809 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3810 && ops[1].op == OP_MOV
3811 && IS(opr_name(&ops[1], 0), "ebp")
3812 && IS(opr_name(&ops[1], 1), "esp"))
3815 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3816 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3819 if (ops[i].op == OP_PUSHA) {
3820 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3825 if (ops[i].op == OP_SUB && IS(opr_name(&ops[i], 0), "esp")) {
3826 g_stack_fsz = opr_const(&ops[i], 1);
3827 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3831 // another way msvc builds stack frame..
3832 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3834 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3838 // and another way..
3839 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3840 && ops[i].operand[1].type == OPT_CONST
3841 && ops[i + 1].op == OP_CALL
3842 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3844 g_stack_fsz += ops[i].operand[1].val;
3845 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3847 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3854 for (; i < opcnt; i++)
3855 if (ops[i].flags & OPF_TAIL)
3858 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3859 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3865 sandard_epilogue = 0;
3866 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3868 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3869 // the standard epilogue is sometimes even used without a sf
3870 if (ops[j - 1].op == OP_MOV
3871 && IS(opr_name(&ops[j - 1], 0), "esp")
3872 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3873 sandard_epilogue = 1;
3875 else if (ops[j].op == OP_LEAVE)
3877 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3878 sandard_epilogue = 1;
3880 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3881 && ops[i].pp->is_noreturn)
3883 // on noreturn, msvc sometimes cleans stack, sometimes not
3888 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3889 ferr(&ops[j], "'pop ebp' expected\n");
3891 if (g_stack_fsz != 0 || sandard_epilogue) {
3892 if (ops[j].op == OP_LEAVE)
3894 else if (sandard_epilogue) // mov esp, ebp
3896 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3899 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3901 ferr(&ops[j], "esp restore expected\n");
3904 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3905 && IS(opr_name(&ops[j], 0), "ecx"))
3907 ferr(&ops[j], "unexpected ecx pop\n");
3912 if (ops[j].op == OP_POPA)
3913 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3915 ferr(&ops[j], "popa expected\n");
3920 } while (i < opcnt);
3923 ferr(ops, "missing ebp epilogue\n");
3929 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3930 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3936 for (; i < opcnt; i++) {
3937 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3939 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3940 && ops[i].operand[1].type == OPT_CONST)
3942 g_stack_fsz = ops[i].operand[1].val;
3943 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3948 else if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3949 && ops[i].operand[1].type == OPT_CONST
3950 && ops[i + 1].op == OP_CALL
3951 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3953 g_stack_fsz += ops[i].operand[1].val;
3954 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3956 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3963 if (ecx_push && !esp_sub) {
3964 // could actually be args for a call..
3965 for (; i < opcnt; i++)
3966 if (ops[i].op != OP_PUSH)
3969 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3970 const struct parsed_proto *pp;
3971 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3972 j = pp ? pp->argc_stack : 0;
3973 while (i > 0 && j > 0) {
3975 if (ops[i].op == OP_PUSH) {
3976 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
3981 ferr(&ops[i], "unhandled prologue\n");
3984 i = g_stack_fsz = ecx_push = 0;
3985 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3986 if (!(ops[i].flags & OPF_RMD))
3996 if (ecx_push || esp_sub)
4001 for (; i < opcnt; i++)
4002 if (ops[i].flags & OPF_TAIL)
4006 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4007 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4014 for (l = 0; l < ecx_push; l++) {
4015 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4017 else if (ops[j].op == OP_ADD
4018 && IS(opr_name(&ops[j], 0), "esp")
4019 && ops[j].operand[1].type == OPT_CONST)
4022 l += ops[j].operand[1].val / 4 - 1;
4025 ferr(&ops[j], "'pop ecx' expected\n");
4027 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4031 ferr(&ops[j], "epilogue scan failed\n");
4037 if (ops[j].op != OP_ADD
4038 || !IS(opr_name(&ops[j], 0), "esp")
4039 || ops[j].operand[1].type != OPT_CONST
4040 || ops[j].operand[1].val != g_stack_fsz)
4042 if (ops[i].op == OP_CALL && ops[i].pp != NULL
4043 && ops[i].pp->is_noreturn)
4045 // noreturn tailcall with no epilogue
4049 ferr(&ops[j], "'add esp' expected\n");
4052 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4053 ops[j].operand[1].val = 0; // hack for stack arg scanner
4058 } while (i < opcnt);
4061 ferr(ops, "missing esp epilogue\n");
4065 // find an instruction that changed opr before i op
4066 // *op_i must be set to -1 by the caller
4067 // *is_caller is set to 1 if one source is determined to be g_func arg
4068 // returns 1 if found, *op_i is then set to origin
4069 // returns -1 if multiple origins are found
4070 static int resolve_origin(int i, const struct parsed_opr *opr,
4071 int magic, int *op_i, int *is_caller)
4073 struct label_ref *lr;
4077 if (g_labels[i] != NULL) {
4078 lr = &g_label_refs[i];
4079 for (; lr != NULL; lr = lr->next) {
4080 check_i(&ops[i], lr->i);
4081 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4083 if (i > 0 && LAST_OP(i - 1))
4089 if (is_caller != NULL)
4094 if (ops[i].cc_scratch == magic)
4096 ops[i].cc_scratch = magic;
4098 if (!(ops[i].flags & OPF_DATA))
4100 if (!is_opr_modified(opr, &ops[i]))
4104 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4115 // find an instruction that previously referenced opr
4116 // if multiple results are found - fail
4117 // *op_i must be set to -1 by the caller
4118 // returns 1 if found, *op_i is then set to referencer insn
4119 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4120 int magic, int *op_i)
4122 struct label_ref *lr;
4126 if (g_labels[i] != NULL) {
4127 lr = &g_label_refs[i];
4128 for (; lr != NULL; lr = lr->next) {
4129 check_i(&ops[i], lr->i);
4130 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4132 if (i > 0 && LAST_OP(i - 1))
4140 if (ops[i].cc_scratch == magic)
4142 ops[i].cc_scratch = magic;
4144 if (!is_opr_referenced(opr, &ops[i]))
4155 // adjust datap of all reachable 'op' insns when moving back
4156 // returns 1 if at least 1 op was found
4157 // returns -1 if path without an op was found
4158 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4160 struct label_ref *lr;
4163 if (ops[i].cc_scratch == magic)
4165 ops[i].cc_scratch = magic;
4168 if (g_labels[i] != NULL) {
4169 lr = &g_label_refs[i];
4170 for (; lr != NULL; lr = lr->next) {
4171 check_i(&ops[i], lr->i);
4172 ret |= adjust_prev_op(lr->i, op, magic, datap);
4174 if (i > 0 && LAST_OP(i - 1))
4182 if (ops[i].cc_scratch == magic)
4184 ops[i].cc_scratch = magic;
4186 if (ops[i].op != op)
4189 ops[i].datap = datap;
4194 // find next instruction that reads opr
4195 // *op_i must be set to -1 by the caller
4196 // on return, *op_i is set to first referencer insn
4197 // returns 1 if exactly 1 referencer is found
4198 static int find_next_read(int i, int opcnt,
4199 const struct parsed_opr *opr, int magic, int *op_i)
4201 struct parsed_op *po;
4204 for (; i < opcnt; i++)
4206 if (ops[i].cc_scratch == magic)
4208 ops[i].cc_scratch = magic;
4211 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4212 if (po->btj != NULL) {
4214 for (j = 0; j < po->btj->count; j++) {
4215 check_i(po, po->btj->d[j].bt_i);
4216 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4222 if (po->flags & OPF_RMD)
4224 check_i(po, po->bt_i);
4225 if (po->flags & OPF_CJMP) {
4226 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4235 if (!is_opr_read(opr, po)) {
4237 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4238 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4240 full_opr = po->operand[0].lmod >= opr->lmod;
4242 if (is_opr_modified(opr, po) && full_opr) {
4246 if (po->flags & OPF_TAIL)
4261 // find next instruction that reads opr
4262 // *op_i must be set to -1 by the caller
4263 // on return, *op_i is set to first flag user insn
4264 // returns 1 if exactly 1 flag user is found
4265 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4267 struct parsed_op *po;
4270 for (; i < opcnt; i++)
4272 if (ops[i].cc_scratch == magic)
4274 ops[i].cc_scratch = magic;
4277 if (po->op == OP_CALL)
4279 if (po->flags & OPF_JMP) {
4280 if (po->btj != NULL) {
4282 for (j = 0; j < po->btj->count; j++) {
4283 check_i(po, po->btj->d[j].bt_i);
4284 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4290 if (po->flags & OPF_RMD)
4292 check_i(po, po->bt_i);
4293 if (po->flags & OPF_CJMP)
4300 if (!(po->flags & OPF_CC)) {
4301 if (po->flags & OPF_FLAGS)
4304 if (po->flags & OPF_TAIL)
4320 static int try_resolve_const(int i, const struct parsed_opr *opr,
4321 int magic, unsigned int *val)
4326 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4329 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4332 *val = ops[i].operand[1].val;
4339 static int resolve_used_bits(int i, int opcnt, int reg,
4340 int *mask, int *is_z_check)
4342 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4346 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4350 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4352 fnote(&ops[j], "(first read)\n");
4353 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4356 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4357 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4359 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4360 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4362 *mask = ops[j].operand[1].val;
4363 if (ops[j].operand[0].lmod == OPLM_BYTE
4364 && ops[j].operand[0].name[1] == 'h')
4368 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4371 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4373 *is_z_check = ops[k].pfo == PFO_Z;
4378 static const struct parsed_proto *resolve_deref(int i, int magic,
4379 struct parsed_opr *opr, int level)
4381 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4382 const struct parsed_proto *pp = NULL;
4383 int from_caller = 0;
4392 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4393 if (ret != 2 || len != strlen(opr->name)) {
4394 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4395 if (ret != 1 || len != strlen(opr->name))
4399 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4404 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4408 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4409 && strlen(ops[j].operand[1].name) == 3
4410 && ops[j].operand[0].lmod == OPLM_DWORD
4411 && ops[j].pp == NULL // no hint
4414 // allow one simple dereference (com/directx)
4415 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4416 ops[j].operand[1].name);
4420 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4425 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4428 if (ops[j].pp != NULL) {
4432 else if (ops[j].operand[1].type == OPT_REGMEM) {
4433 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4435 // maybe structure ptr in structure
4436 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4439 else if (ops[j].operand[1].type == OPT_LABEL)
4440 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4441 else if (ops[j].operand[1].type == OPT_REG) {
4444 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4446 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4447 for (k = 0; k < g_func_pp->argc; k++) {
4448 if (g_func_pp->arg[k].reg == NULL)
4450 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4451 pp = g_func_pp->arg[k].pp;
4460 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4462 ferr(&ops[j], "expected struct, got '%s %s'\n",
4463 pp->type.name, pp->name);
4467 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4470 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4471 int *pp_i, int *multi_src)
4473 const struct parsed_proto *pp = NULL;
4474 int search_advice = 0;
4479 switch (ops[i].operand[0].type) {
4481 // try to resolve struct member calls
4482 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4488 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4494 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4502 static struct parsed_proto *process_call_early(int i, int opcnt,
4505 struct parsed_op *po = &ops[i];
4506 struct parsed_proto *pp;
4512 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4516 // look for and make use of esp adjust
4518 if (!pp->is_stdcall && pp->argc_stack > 0)
4519 ret = scan_for_esp_adjust(i + 1, opcnt,
4520 pp->argc_stack * 4, &adj, &multipath, 0);
4522 if (pp->argc_stack > adj / 4)
4526 if (ops[ret].op == OP_POP) {
4527 for (j = 1; j < adj / 4; j++) {
4528 if (ops[ret + j].op != OP_POP
4529 || ops[ret + j].operand[0].reg != xCX)
4541 static struct parsed_proto *process_call(int i, int opcnt)
4543 struct parsed_op *po = &ops[i];
4544 const struct parsed_proto *pp_c;
4545 struct parsed_proto *pp;
4546 const char *tmpname;
4547 int call_i = -1, ref_i = -1;
4548 int adj = 0, multipath = 0;
4551 tmpname = opr_name(po, 0);
4556 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4558 if (!pp_c->is_func && !pp_c->is_fptr)
4559 ferr(po, "call to non-func: %s\n", pp_c->name);
4560 pp = proto_clone(pp_c);
4561 my_assert_not(pp, NULL);
4563 // not resolved just to single func
4566 switch (po->operand[0].type) {
4568 // we resolved this call and no longer need the register
4569 po->regmask_src &= ~(1 << po->operand[0].reg);
4571 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4572 && ops[call_i].operand[1].type == OPT_LABEL)
4574 // no other source users?
4575 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4577 if (ret == 1 && call_i == ref_i) {
4578 // and nothing uses it after us?
4580 find_next_read(i + 1, opcnt, &po->operand[0],
4581 i + opcnt * 11, &ref_i);
4583 // then also don't need the source mov
4584 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4596 pp = calloc(1, sizeof(*pp));
4597 my_assert_not(pp, NULL);
4600 ret = scan_for_esp_adjust(i + 1, opcnt,
4601 -1, &adj, &multipath, 0);
4602 if (ret < 0 || adj < 0) {
4603 if (!g_allow_regfunc)
4604 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4605 pp->is_unresolved = 1;
4609 if (adj > ARRAY_SIZE(pp->arg))
4610 ferr(po, "esp adjust too large: %d\n", adj);
4611 pp->ret_type.name = strdup("int");
4612 pp->argc = pp->argc_stack = adj;
4613 for (arg = 0; arg < pp->argc; arg++)
4614 pp->arg[arg].type.name = strdup("int");
4619 // look for and make use of esp adjust
4622 if (!pp->is_stdcall && pp->argc_stack > 0) {
4623 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4624 ret = scan_for_esp_adjust(i + 1, opcnt,
4625 adj_expect, &adj, &multipath, 0);
4628 if (pp->is_vararg) {
4629 if (adj / 4 < pp->argc_stack) {
4630 fnote(po, "(this call)\n");
4631 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4632 adj, pp->argc_stack * 4);
4634 // modify pp to make it have varargs as normal args
4636 pp->argc += adj / 4 - pp->argc_stack;
4637 for (; arg < pp->argc; arg++) {
4638 pp->arg[arg].type.name = strdup("int");
4641 if (pp->argc > ARRAY_SIZE(pp->arg))
4642 ferr(po, "too many args for '%s'\n", tmpname);
4644 if (pp->argc_stack > adj / 4) {
4645 fnote(po, "(this call)\n");
4646 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4647 tmpname, pp->argc_stack * 4, adj);
4650 scan_for_esp_adjust(i + 1, opcnt,
4651 pp->argc_stack * 4, &adj, &multipath, 1);
4653 else if (pp->is_vararg)
4654 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4660 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
4663 struct parsed_op *po;
4669 for (base_arg = 0; base_arg < pp->argc; base_arg++)
4670 if (pp->arg[base_arg].reg == NULL)
4673 for (j = i; j > 0; )
4675 ferr_assert(&ops[j], g_labels[j] == NULL);
4679 ferr_assert(po, po->op != OP_PUSH);
4680 if (po->op == OP_FST)
4682 if (po->operand[0].type != OPT_REGMEM)
4684 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
4687 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3))
4688 ferr(po, "bad offset %d (%d args)\n", offset, pp->argc_stack);
4690 arg = base_arg + offset / 4;
4692 po->p_argnum = arg + 1;
4693 ferr_assert(po, pp->arg[arg].datap == NULL);
4694 pp->arg[arg].datap = po;
4695 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
4696 if (regmask_ffca != NULL)
4697 *regmask_ffca |= 1 << arg;
4699 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4700 && po->operand[1].type == OPT_CONST)
4702 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4707 for (arg = base_arg; arg < pp->argc; arg++) {
4708 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
4709 po = pp->arg[arg].datap;
4711 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
4712 if (po->operand[0].lmod == OPLM_QWORD)
4719 static int collect_call_args_early(int i, struct parsed_proto *pp,
4720 int *regmask, int *regmask_ffca)
4722 struct parsed_op *po;
4726 for (arg = 0; arg < pp->argc; arg++)
4727 if (pp->arg[arg].reg == NULL)
4730 // first see if it can be easily done
4731 for (j = i; j > 0 && arg < pp->argc; )
4733 if (g_labels[j] != NULL)
4738 if (po->op == OP_CALL)
4740 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
4742 else if (po->op == OP_POP)
4744 else if (po->flags & OPF_CJMP)
4746 else if (po->op == OP_PUSH) {
4747 if (po->flags & (OPF_FARG|OPF_FARGNR))
4749 if (!g_header_mode) {
4750 ret = scan_for_mod(po, j + 1, i, 1);
4755 if (pp->arg[arg].type.is_va_list)
4759 for (arg++; arg < pp->argc; arg++)
4760 if (pp->arg[arg].reg == NULL)
4763 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4764 && po->operand[1].type == OPT_CONST)
4766 if (po->flags & (OPF_RMD|OPF_DONE))
4768 if (po->operand[1].val != pp->argc_stack * 4)
4769 ferr(po, "unexpected esp adjust: %d\n",
4770 po->operand[1].val * 4);
4771 ferr_assert(po, pp->argc - arg == pp->argc_stack);
4772 return collect_call_args_no_push(i, pp, regmask_ffca);
4780 for (arg = 0; arg < pp->argc; arg++)
4781 if (pp->arg[arg].reg == NULL)
4784 for (j = i; j > 0 && arg < pp->argc; )
4788 if (ops[j].op == OP_PUSH)
4790 ops[j].p_argnext = -1;
4791 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4792 pp->arg[arg].datap = &ops[j];
4794 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
4795 *regmask |= 1 << ops[j].operand[0].reg;
4797 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4798 ops[j].flags &= ~OPF_RSAVE;
4801 for (arg++; arg < pp->argc; arg++)
4802 if (pp->arg[arg].reg == NULL)
4810 static int sync_argnum(struct parsed_op *po, int argnum)
4812 struct parsed_op *po_tmp;
4814 // see if other branches don't have higher argnum
4815 for (po_tmp = po; po_tmp != NULL; ) {
4816 if (argnum < po_tmp->p_argnum)
4817 argnum = po_tmp->p_argnum;
4818 // note: p_argnext is active on current collect_call_args only
4819 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4822 // make all argnums consistent
4823 for (po_tmp = po; po_tmp != NULL; ) {
4824 if (po_tmp->p_argnum != 0)
4825 po_tmp->p_argnum = argnum;
4826 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4832 static int collect_call_args_r(struct parsed_op *po, int i,
4833 struct parsed_proto *pp, int *regmask, int *arg_grp,
4834 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
4836 struct parsed_proto *pp_tmp;
4837 struct parsed_op *po_tmp;
4838 struct label_ref *lr;
4839 int need_to_save_current;
4840 int arg_grp_current = 0;
4841 int save_args_seen = 0;
4848 ferr(po, "dead label encountered\n");
4852 for (; arg < pp->argc; arg++, argnum++)
4853 if (pp->arg[arg].reg == NULL)
4855 magic = (magic & 0xffffff) | (arg << 24);
4857 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4859 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4860 if (ops[j].cc_scratch != magic) {
4861 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4865 // ok: have already been here
4868 ops[j].cc_scratch = magic;
4870 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4871 lr = &g_label_refs[j];
4872 if (lr->next != NULL)
4874 for (; lr->next; lr = lr->next) {
4875 check_i(&ops[j], lr->i);
4876 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4878 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4879 arg, argnum, magic, need_op_saving, may_reuse);
4884 check_i(&ops[j], lr->i);
4885 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4887 if (j > 0 && LAST_OP(j - 1)) {
4888 // follow last branch in reverse
4893 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4894 arg, argnum, magic, need_op_saving, may_reuse);
4900 if (ops[j].op == OP_CALL)
4902 if (pp->is_unresolved)
4907 ferr(po, "arg collect hit unparsed call '%s'\n",
4908 ops[j].operand[0].name);
4909 if (may_reuse && pp_tmp->argc_stack > 0)
4910 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4911 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4913 // esp adjust of 0 means we collected it before
4914 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4915 && (ops[j].operand[1].type != OPT_CONST
4916 || ops[j].operand[1].val != 0))
4918 if (pp->is_unresolved)
4921 fnote(po, "(this call)\n");
4922 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4923 arg, pp->argc, ops[j].operand[1].val);
4925 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4927 if (pp->is_unresolved)
4930 fnote(po, "(this call)\n");
4931 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4933 else if (ops[j].flags & OPF_CJMP)
4935 if (pp->is_unresolved)
4940 else if (ops[j].op == OP_PUSH
4941 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4943 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4946 ops[j].p_argnext = -1;
4947 po_tmp = pp->arg[arg].datap;
4949 ops[j].p_argnext = po_tmp - ops;
4950 pp->arg[arg].datap = &ops[j];
4952 argnum = sync_argnum(&ops[j], argnum);
4954 need_to_save_current = 0;
4956 if (ops[j].operand[0].type == OPT_REG)
4957 reg = ops[j].operand[0].reg;
4959 if (!need_op_saving) {
4960 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4961 need_to_save_current = (ret >= 0);
4963 if (need_op_saving || need_to_save_current) {
4964 // mark this arg as one that needs operand saving
4965 pp->arg[arg].is_saved = 1;
4967 if (save_args_seen & (1 << (argnum - 1))) {
4970 if (arg_grp_current >= MAX_ARG_GRP)
4971 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
4975 else if (ops[j].p_argnum == 0)
4976 ops[j].flags |= OPF_RMD;
4978 // some PUSHes are reused by different calls on other branches,
4979 // but that can't happen if we didn't branch, so they
4980 // can be removed from future searches (handles nested calls)
4982 ops[j].flags |= OPF_FARGNR;
4984 ops[j].flags |= OPF_FARG;
4985 ops[j].flags &= ~OPF_RSAVE;
4987 // check for __VALIST
4988 if (!pp->is_unresolved && g_func_pp != NULL
4989 && pp->arg[arg].type.is_va_list)
4992 ret = resolve_origin(j, &ops[j].operand[0],
4993 magic + 1, &k, NULL);
4994 if (ret == 1 && k >= 0)
4996 if (ops[k].op == OP_LEA) {
4997 if (!g_func_pp->is_vararg)
4998 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5001 snprintf(buf, sizeof(buf), "arg_%X",
5002 g_func_pp->argc_stack * 4);
5003 if (strstr(ops[k].operand[1].name, buf)
5004 || strstr(ops[k].operand[1].name, "arglist"))
5006 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5007 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5008 pp->arg[arg].is_saved = 0;
5012 ferr(&ops[k], "va_list arg detection failed\n");
5014 // check for va_list from g_func_pp arg too
5015 else if (ops[k].op == OP_MOV
5016 && is_stack_access(&ops[k], &ops[k].operand[1]))
5018 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5019 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5021 ops[k].flags |= OPF_RMD | OPF_DONE;
5022 ops[j].flags |= OPF_RMD;
5023 ops[j].p_argpass = ret + 1;
5024 pp->arg[arg].is_saved = 0;
5031 if (pp->arg[arg].is_saved) {
5032 ops[j].flags &= ~OPF_RMD;
5033 ops[j].p_argnum = argnum;
5036 // tracking reg usage
5038 *regmask |= 1 << reg;
5042 if (!pp->is_unresolved) {
5044 for (; arg < pp->argc; arg++, argnum++)
5045 if (pp->arg[arg].reg == NULL)
5048 magic = (magic & 0xffffff) | (arg << 24);
5051 if (ops[j].p_arggrp > arg_grp_current) {
5053 arg_grp_current = ops[j].p_arggrp;
5055 if (ops[j].p_argnum > 0)
5056 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5059 if (arg < pp->argc) {
5060 ferr(po, "arg collect failed for '%s': %d/%d\n",
5061 pp->name, arg, pp->argc);
5065 if (arg_grp_current > *arg_grp)
5066 *arg_grp = arg_grp_current;
5071 static int collect_call_args(struct parsed_op *po, int i,
5072 struct parsed_proto *pp, int *regmask, int magic)
5074 // arg group is for cases when pushes for
5075 // multiple funcs are going on
5076 struct parsed_op *po_tmp;
5081 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5087 // propagate arg_grp
5088 for (a = 0; a < pp->argc; a++) {
5089 if (pp->arg[a].reg != NULL)
5092 po_tmp = pp->arg[a].datap;
5093 while (po_tmp != NULL) {
5094 po_tmp->p_arggrp = arg_grp;
5095 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5100 if (pp->is_unresolved) {
5102 pp->argc_stack += ret;
5103 for (a = 0; a < pp->argc; a++)
5104 if (pp->arg[a].type.name == NULL)
5105 pp->arg[a].type.name = strdup("int");
5111 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5112 int regmask_now, int *regmask,
5113 int regmask_save_now, int *regmask_save,
5114 int *regmask_init, int regmask_arg)
5116 struct parsed_op *po;
5124 for (; i < opcnt; i++)
5127 if (cbits[i >> 3] & (1 << (i & 7)))
5129 cbits[i >> 3] |= (1 << (i & 7));
5131 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5132 if (po->flags & (OPF_RMD|OPF_DONE))
5134 if (po->btj != NULL) {
5135 for (j = 0; j < po->btj->count; j++) {
5136 check_i(po, po->btj->d[j].bt_i);
5137 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5138 regmask_now, regmask, regmask_save_now, regmask_save,
5139 regmask_init, regmask_arg);
5144 check_i(po, po->bt_i);
5145 if (po->flags & OPF_CJMP)
5146 reg_use_pass(po->bt_i, opcnt, cbits,
5147 regmask_now, regmask, regmask_save_now, regmask_save,
5148 regmask_init, regmask_arg);
5154 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5155 && !g_func_pp->is_userstack
5156 && po->operand[0].type == OPT_REG)
5158 reg = po->operand[0].reg;
5159 ferr_assert(po, reg >= 0);
5162 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5163 if (regmask_now & (1 << reg)) {
5164 already_saved = regmask_save_now & (1 << reg);
5165 flags_set = OPF_RSAVE | OPF_DONE;
5168 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5170 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5171 reg, 0, 0, flags_set);
5174 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5176 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5181 ferr_assert(po, !already_saved);
5182 po->flags |= flags_set;
5184 if (regmask_now & (1 << reg)) {
5185 regmask_save_now |= (1 << reg);
5186 *regmask_save |= regmask_save_now;
5191 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5192 reg = po->operand[0].reg;
5193 ferr_assert(po, reg >= 0);
5195 if (regmask_save_now & (1 << reg))
5196 regmask_save_now &= ~(1 << reg);
5198 regmask_now &= ~(1 << reg);
5201 else if (po->op == OP_CALL) {
5202 if ((po->regmask_dst & (1 << xAX))
5203 && !(po->regmask_dst & (1 << xDX)))
5205 if (po->flags & OPF_TAIL)
5206 // don't need eax, will do "return f();" or "f(); return;"
5207 po->regmask_dst &= ~(1 << xAX);
5209 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5211 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5214 po->regmask_dst &= ~(1 << xAX);
5218 // not "full stack" mode and have something in stack
5219 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5220 ferr(po, "float stack is not empty on func call\n");
5223 if (po->flags & OPF_NOREGS)
5226 // if incomplete register is used, clear it on init to avoid
5227 // later use of uninitialized upper part in some situations
5228 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5229 && po->operand[0].lmod != OPLM_DWORD)
5231 reg = po->operand[0].reg;
5232 ferr_assert(po, reg >= 0);
5234 if (!(regmask_now & (1 << reg)))
5235 *regmask_init |= 1 << reg;
5238 regmask_op = po->regmask_src | po->regmask_dst;
5240 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5241 regmask_new &= ~(1 << xSP);
5242 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5243 regmask_new &= ~(1 << xBP);
5245 if (regmask_new != 0)
5246 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5248 if (regmask_op & (1 << xBP)) {
5249 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5250 if (po->regmask_dst & (1 << xBP))
5251 // compiler decided to drop bp frame and use ebp as scratch
5252 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5254 regmask_op &= ~(1 << xBP);
5258 if (po->flags & OPF_FPUSH) {
5259 if (regmask_now & mxST1)
5260 regmask_now |= mxSTa; // switch to "full stack" mode
5261 if (regmask_now & mxSTa)
5262 po->flags |= OPF_FSHIFT;
5263 if (!(regmask_now & mxST7_2)) {
5265 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5269 regmask_now |= regmask_op;
5270 *regmask |= regmask_now;
5273 if (po->flags & OPF_FPOP) {
5274 if ((regmask_now & mxSTa) == 0)
5275 ferr(po, "float pop on empty stack?\n");
5276 if (regmask_now & (mxST7_2 | mxST1))
5277 po->flags |= OPF_FSHIFT;
5278 if (!(regmask_now & mxST7_2)) {
5280 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5284 if (po->flags & OPF_TAIL) {
5285 if (!(regmask_now & mxST7_2)) {
5286 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5287 if (!(regmask_now & mxST0))
5288 ferr(po, "no st0 on float return, mask: %x\n",
5291 else if (regmask_now & mxST1_0)
5292 ferr(po, "float regs on tail: %x\n", regmask_now);
5295 // there is support for "conditional tailcall", sort of
5296 if (!(po->flags & OPF_CC))
5302 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5306 for (i = 0; i < pp->argc; i++)
5307 if (pp->arg[i].reg == NULL)
5311 memmove(&pp->arg[i + 1], &pp->arg[i],
5312 sizeof(pp->arg[0]) * pp->argc_stack);
5313 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5314 pp->arg[i].reg = strdup(reg);
5315 pp->arg[i].type.name = strdup("int");
5320 static void output_std_flags(FILE *fout, struct parsed_op *po,
5321 int *pfomask, const char *dst_opr_text)
5323 if (*pfomask & (1 << PFO_Z)) {
5324 fprintf(fout, "\n cond_z = (%s%s == 0);",
5325 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5326 *pfomask &= ~(1 << PFO_Z);
5328 if (*pfomask & (1 << PFO_S)) {
5329 fprintf(fout, "\n cond_s = (%s%s < 0);",
5330 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5331 *pfomask &= ~(1 << PFO_S);
5336 OPP_FORCE_NORETURN = (1 << 0),
5337 OPP_SIMPLE_ARGS = (1 << 1),
5338 OPP_ALIGN = (1 << 2),
5341 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5344 const char *cconv = "";
5346 if (pp->is_fastcall)
5347 cconv = "__fastcall ";
5348 else if (pp->is_stdcall && pp->argc_reg == 0)
5349 cconv = "__stdcall ";
5351 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5353 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5354 fprintf(fout, "noreturn ");
5357 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5362 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5366 output_pp_attrs(fout, pp, flags);
5369 fprintf(fout, "%s", pp->name);
5374 for (i = 0; i < pp->argc; i++) {
5376 fprintf(fout, ", ");
5377 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5378 && !(flags & OPP_SIMPLE_ARGS))
5381 output_pp(fout, pp->arg[i].pp, 0);
5383 else if (pp->arg[i].type.is_retreg) {
5384 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5387 fprintf(fout, "%s", pp->arg[i].type.name);
5389 fprintf(fout, " a%d", i + 1);
5392 if (pp->is_vararg) {
5394 fprintf(fout, ", ");
5395 fprintf(fout, "...");
5400 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5406 snprintf(buf1, sizeof(buf1), "%d", grp);
5407 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5412 static void gen_x_cleanup(int opcnt);
5414 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5416 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5417 struct parsed_opr *last_arith_dst = NULL;
5418 char buf1[256], buf2[256], buf3[256], cast[64];
5419 struct parsed_proto *pp, *pp_tmp;
5420 struct parsed_data *pd;
5421 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5422 unsigned char cbits[MAX_OPS / 8];
5423 const char *float_type;
5424 const char *float_st0;
5425 const char *float_st1;
5426 int need_float_stack = 0;
5427 int need_float_sw = 0; // status word
5428 int need_tmp_var = 0;
5432 int label_pending = 0;
5433 int need_double = 0;
5434 int regmask_save = 0; // used regs saved/restored in this func
5435 int regmask_arg; // regs from this function args (fastcall, etc)
5436 int regmask_ret; // regs needed on ret
5437 int regmask_now; // temp
5438 int regmask_init = 0; // regs that need zero initialization
5439 int regmask_pp = 0; // regs used in complex push-pop graph
5440 int regmask_ffca = 0; // float function call args
5441 int regmask = 0; // used regs
5451 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5452 g_stack_frame_used = 0;
5453 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5454 regmask_init = g_regmask_init;
5456 g_func_pp = proto_parse(fhdr, funcn, 0);
5457 if (g_func_pp == NULL)
5458 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5460 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5461 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5464 // - resolve all branches
5465 // - parse calls with labels
5466 resolve_branches_parse_calls(opcnt);
5469 // - handle ebp/esp frame, remove ops related to it
5470 scan_prologue_epilogue(opcnt);
5473 // - remove dead labels
5474 // - set regs needed at ret
5475 for (i = 0; i < opcnt; i++)
5477 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5482 if (ops[i].op == OP_RET)
5483 ops[i].regmask_src |= regmask_ret;
5487 // - process trivial calls
5488 for (i = 0; i < opcnt; i++)
5491 if (po->flags & (OPF_RMD|OPF_DONE))
5494 if (po->op == OP_CALL)
5496 pp = process_call_early(i, opcnt, &j);
5498 if (!(po->flags & OPF_ATAIL)) {
5499 // since we know the args, try to collect them
5500 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5508 // commit esp adjust
5509 if (ops[j].op != OP_POP)
5510 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5512 for (l = 0; l < pp->argc_stack; l++)
5513 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5517 if (strstr(pp->ret_type.name, "int64"))
5520 po->flags |= OPF_DONE;
5526 // - process calls, stage 2
5527 // - handle some push/pop pairs
5528 // - scan for STD/CLD, propagate DF
5529 // - try to resolve needed x87 status word bits
5530 for (i = 0; i < opcnt; i++)
5535 if (po->flags & OPF_RMD)
5538 if (po->op == OP_CALL)
5540 if (!(po->flags & OPF_DONE)) {
5541 pp = process_call(i, opcnt);
5543 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5544 // since we know the args, collect them
5545 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5547 // for unresolved, collect after other passes
5551 ferr_assert(po, pp != NULL);
5553 po->regmask_src |= get_pp_arg_regmask_src(pp);
5554 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5556 if (po->regmask_dst & mxST0)
5557 po->flags |= OPF_FPUSH;
5559 if (strstr(pp->ret_type.name, "int64"))
5565 if (po->flags & OPF_DONE)
5570 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
5571 && po->operand[0].type == OPT_CONST)
5573 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5578 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5582 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5583 scan_propagate_df(i + 1, opcnt);
5588 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
5589 ferr(po, "TODO: fnstsw to mem\n");
5590 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
5592 ferr(po, "fnstsw resolve failed\n");
5593 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
5594 (void *)(long)(mask | (z_check << 16)));
5596 ferr(po, "failed to find fcom: %d\n", ret);
5605 // - find POPs for PUSHes, rm both
5606 // - scan for all used registers
5607 memset(cbits, 0, sizeof(cbits));
5608 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5609 0, ®mask_save, ®mask_init, regmask_arg);
5611 need_float_stack = !!(regmask & mxST7_2);
5614 // - find flag set ops for their users
5615 // - do unresolved calls
5616 // - declare indirect functions
5617 // - other op specific processing
5618 for (i = 0; i < opcnt; i++)
5621 if (po->flags & (OPF_RMD|OPF_DONE))
5624 if (po->flags & OPF_CC)
5626 int setters[16], cnt = 0, branched = 0;
5628 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
5629 &branched, setters, &cnt);
5630 if (ret < 0 || cnt <= 0)
5631 ferr(po, "unable to trace flag setter(s)\n");
5632 if (cnt > ARRAY_SIZE(setters))
5633 ferr(po, "too many flag setters\n");
5635 for (j = 0; j < cnt; j++)
5637 tmp_op = &ops[setters[j]]; // flag setter
5640 // to get nicer code, we try to delay test and cmp;
5641 // if we can't because of operand modification, or if we
5642 // have arith op, or branch, make it calculate flags explicitly
5643 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5645 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5646 pfomask = 1 << po->pfo;
5648 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5649 pfomask = 1 << po->pfo;
5652 // see if we'll be able to handle based on op result
5653 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5654 && po->pfo != PFO_Z && po->pfo != PFO_S
5655 && po->pfo != PFO_P)
5657 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5659 pfomask = 1 << po->pfo;
5662 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5663 propagate_lmod(tmp_op, &tmp_op->operand[0],
5664 &tmp_op->operand[1]);
5665 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5670 tmp_op->pfomask |= pfomask;
5671 cond_vars |= pfomask;
5673 // note: may overwrite, currently not a problem
5677 if (po->op == OP_RCL || po->op == OP_RCR
5678 || po->op == OP_ADC || po->op == OP_SBB)
5679 cond_vars |= 1 << PFO_C;
5685 cond_vars |= 1 << PFO_Z;
5689 if (po->operand[0].lmod == OPLM_DWORD)
5694 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
5699 // note: resolved non-reg calls are OPF_DONE already
5701 ferr_assert(po, pp != NULL);
5703 if (pp->is_unresolved) {
5704 int regmask_stack = 0;
5705 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5707 // this is pretty rough guess:
5708 // see ecx and edx were pushed (and not their saved versions)
5709 for (arg = 0; arg < pp->argc; arg++) {
5710 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
5713 tmp_op = pp->arg[arg].datap;
5715 ferr(po, "parsed_op missing for arg%d\n", arg);
5716 if (tmp_op->operand[0].type == OPT_REG)
5717 regmask_stack |= 1 << tmp_op->operand[0].reg;
5720 if (!((regmask_stack & (1 << xCX))
5721 && (regmask_stack & (1 << xDX))))
5723 if (pp->argc_stack != 0
5724 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5726 pp_insert_reg_arg(pp, "ecx");
5727 pp->is_fastcall = 1;
5728 regmask_init |= 1 << xCX;
5729 regmask |= 1 << xCX;
5731 if (pp->argc_stack != 0
5732 || ((regmask | regmask_arg) & (1 << xDX)))
5734 pp_insert_reg_arg(pp, "edx");
5735 regmask_init |= 1 << xDX;
5736 regmask |= 1 << xDX;
5740 // note: __cdecl doesn't fall into is_unresolved category
5741 if (pp->argc_stack > 0)
5747 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
5749 // <var> = offset <something>
5750 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5751 && !IS_START(po->operand[1].name, "off_"))
5753 if (!po->operand[0].pp->is_fptr)
5754 ferr(po, "%s not declared as fptr when it should be\n",
5755 po->operand[0].name);
5756 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5757 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5758 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5759 fnote(po, "var: %s\n", buf1);
5760 fnote(po, "func: %s\n", buf2);
5761 ferr(po, "^ mismatch\n");
5769 if (po->operand[0].lmod == OPLM_DWORD) {
5770 // 32bit division is common, look for it
5771 if (po->op == OP_DIV)
5772 ret = scan_for_reg_clear(i, xDX);
5774 ret = scan_for_cdq_edx(i);
5776 po->flags |= OPF_32BIT;
5785 po->flags |= OPF_RMD | OPF_DONE;
5795 if (po->operand[0].lmod == OPLM_QWORD)
5805 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5807 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5809 po->flags |= OPF_32BIT;
5817 // this might need it's own pass...
5818 if (po->op != OP_FST && po->p_argnum > 0)
5819 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
5821 // correct for "full stack" mode late enable
5822 if ((po->flags & (OPF_PPUSH|OPF_FPOP)) && need_float_stack)
5823 po->flags |= OPF_FSHIFT;
5826 float_type = need_double ? "double" : "float";
5827 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
5828 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
5830 // output starts here
5832 // define userstack size
5833 if (g_func_pp->is_userstack) {
5834 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5835 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5836 fprintf(fout, "#endif\n");
5839 // the function itself
5840 ferr_assert(ops, !g_func_pp->is_fptr);
5841 output_pp(fout, g_func_pp,
5842 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5843 fprintf(fout, "\n{\n");
5845 // declare indirect functions
5846 for (i = 0; i < opcnt; i++) {
5848 if (po->flags & OPF_RMD)
5851 if (po->op == OP_CALL) {
5854 ferr(po, "NULL pp\n");
5856 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5857 if (pp->name[0] != 0) {
5858 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5859 memcpy(pp->name, "i_", 2);
5861 // might be declared already
5863 for (j = 0; j < i; j++) {
5864 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5865 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5875 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5878 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5879 fprintf(fout, ";\n");
5884 // output LUTs/jumptables
5885 for (i = 0; i < g_func_pd_cnt; i++) {
5887 fprintf(fout, " static const ");
5888 if (pd->type == OPT_OFFSET) {
5889 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5891 for (j = 0; j < pd->count; j++) {
5893 fprintf(fout, ", ");
5894 fprintf(fout, "&&%s", pd->d[j].u.label);
5898 fprintf(fout, "%s %s[] =\n { ",
5899 lmod_type_u(ops, pd->lmod), pd->label);
5901 for (j = 0; j < pd->count; j++) {
5903 fprintf(fout, ", ");
5904 fprintf(fout, "%u", pd->d[j].u.val);
5907 fprintf(fout, " };\n");
5911 // declare stack frame, va_arg
5913 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5914 if (g_func_lmods & (1 << OPLM_WORD))
5915 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5916 if (g_func_lmods & (1 << OPLM_BYTE))
5917 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5918 if (g_func_lmods & (1 << OPLM_QWORD))
5919 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5920 fprintf(fout, " } sf;\n");
5924 if (g_func_pp->is_userstack) {
5925 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5926 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5930 if (g_func_pp->is_vararg) {
5931 fprintf(fout, " va_list ap;\n");
5935 // declare arg-registers
5936 for (i = 0; i < g_func_pp->argc; i++) {
5937 if (g_func_pp->arg[i].reg != NULL) {
5938 reg = char_array_i(regs_r32,
5939 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5940 if (regmask & (1 << reg)) {
5941 if (g_func_pp->arg[i].type.is_retreg)
5942 fprintf(fout, " u32 %s = *r_%s;\n",
5943 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5945 fprintf(fout, " u32 %s = (u32)a%d;\n",
5946 g_func_pp->arg[i].reg, i + 1);
5949 if (g_func_pp->arg[i].type.is_retreg)
5950 ferr(ops, "retreg '%s' is unused?\n",
5951 g_func_pp->arg[i].reg);
5952 fprintf(fout, " // %s = a%d; // unused\n",
5953 g_func_pp->arg[i].reg, i + 1);
5959 // declare normal registers
5960 regmask_now = regmask & ~regmask_arg;
5961 regmask_now &= ~(1 << xSP);
5962 if (regmask_now & 0x00ff) {
5963 for (reg = 0; reg < 8; reg++) {
5964 if (regmask_now & (1 << reg)) {
5965 fprintf(fout, " u32 %s", regs_r32[reg]);
5966 if (regmask_init & (1 << reg))
5967 fprintf(fout, " = 0");
5968 fprintf(fout, ";\n");
5974 if (regmask_now & 0xff00) {
5975 for (reg = 8; reg < 16; reg++) {
5976 if (regmask_now & (1 << reg)) {
5977 fprintf(fout, " mmxr %s", regs_r32[reg]);
5978 if (regmask_init & (1 << reg))
5979 fprintf(fout, " = { 0, }");
5980 fprintf(fout, ";\n");
5986 if (need_float_stack) {
5987 fprintf(fout, " %s f_st[8];\n", float_type);
5988 fprintf(fout, " int f_stp = 0;\n");
5992 if (regmask_now & 0xff0000) {
5993 for (reg = 16; reg < 24; reg++) {
5994 if (regmask_now & (1 << reg)) {
5995 fprintf(fout, " %s f_st%d", float_type, reg - 16);
5996 if (regmask_init & (1 << reg))
5997 fprintf(fout, " = 0");
5998 fprintf(fout, ";\n");
6005 if (need_float_sw) {
6006 fprintf(fout, " u16 f_sw;\n");
6011 for (reg = 0; reg < 8; reg++) {
6012 if (regmask_save & (1 << reg)) {
6013 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6019 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6020 if (save_arg_vars[i] == 0)
6022 for (reg = 0; reg < 32; reg++) {
6023 if (save_arg_vars[i] & (1 << reg)) {
6024 fprintf(fout, " u32 %s;\n",
6025 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6032 for (reg = 0; reg < 32; reg++) {
6033 if (regmask_ffca & (1 << reg)) {
6034 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6040 // declare push-pop temporaries
6042 for (reg = 0; reg < 8; reg++) {
6043 if (regmask_pp & (1 << reg)) {
6044 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6051 for (i = 0; i < 8; i++) {
6052 if (cond_vars & (1 << i)) {
6053 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6060 fprintf(fout, " u32 tmp;\n");
6065 fprintf(fout, " u64 tmp64;\n");
6070 fprintf(fout, "\n");
6072 // do stack clear, if needed
6073 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6075 if (g_stack_clear_len != 0) {
6076 if (g_stack_clear_len <= 4) {
6077 for (i = 0; i < g_stack_clear_len; i++)
6078 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6079 fprintf(fout, "0;\n");
6082 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6083 g_stack_clear_start, g_stack_clear_len * 4);
6087 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6090 if (g_func_pp->is_vararg) {
6091 if (g_func_pp->argc_stack == 0)
6092 ferr(ops, "vararg func without stack args?\n");
6093 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6097 for (i = 0; i < opcnt; i++)
6099 if (g_labels[i] != NULL) {
6100 fprintf(fout, "\n%s:\n", g_labels[i]);
6103 delayed_flag_op = NULL;
6104 last_arith_dst = NULL;
6108 if (po->flags & OPF_RMD)
6113 #define assert_operand_cnt(n_) \
6114 if (po->operand_cnt != n_) \
6115 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6117 // conditional/flag using op?
6118 if (po->flags & OPF_CC)
6124 // we go through all this trouble to avoid using parsed_flag_op,
6125 // which makes generated code much nicer
6126 if (delayed_flag_op != NULL)
6128 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6129 po->pfo, po->pfo_inv);
6132 else if (last_arith_dst != NULL
6133 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6134 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6137 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6138 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6139 last_arith_dst->lmod, buf3);
6142 else if (tmp_op != NULL) {
6143 // use preprocessed flag calc results
6144 if (!(tmp_op->pfomask & (1 << po->pfo)))
6145 ferr(po, "not prepared for pfo %d\n", po->pfo);
6147 // note: pfo_inv was not yet applied
6148 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6149 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6152 ferr(po, "all methods of finding comparison failed\n");
6155 if (po->flags & OPF_JMP) {
6156 fprintf(fout, " if %s", buf1);
6158 else if (po->op == OP_RCL || po->op == OP_RCR
6159 || po->op == OP_ADC || po->op == OP_SBB)
6162 fprintf(fout, " cond_%s = %s;\n",
6163 parsed_flag_op_names[po->pfo], buf1);
6165 else if (po->flags & OPF_DATA) { // SETcc
6166 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6167 fprintf(fout, " %s = %s;", buf2, buf1);
6170 ferr(po, "unhandled conditional op\n");
6174 pfomask = po->pfomask;
6179 assert_operand_cnt(2);
6180 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6181 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6182 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6183 fprintf(fout, " %s = %s;", buf1,
6184 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6189 assert_operand_cnt(2);
6190 po->operand[1].lmod = OPLM_DWORD; // always
6191 fprintf(fout, " %s = %s;",
6192 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6193 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6198 assert_operand_cnt(2);
6199 fprintf(fout, " %s = %s;",
6200 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6201 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6205 assert_operand_cnt(2);
6206 switch (po->operand[1].lmod) {
6208 strcpy(buf3, "(s8)");
6211 strcpy(buf3, "(s16)");
6214 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6216 fprintf(fout, " %s = %s;",
6217 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6218 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6223 assert_operand_cnt(2);
6224 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6225 fprintf(fout, " tmp = %s;",
6226 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6227 fprintf(fout, " %s = %s;",
6228 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6229 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6230 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6231 fprintf(fout, " %s = %stmp;",
6232 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6233 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6234 snprintf(g_comment, sizeof(g_comment), "xchg");
6238 assert_operand_cnt(1);
6239 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6240 fprintf(fout, " %s = ~%s;", buf1, buf1);
6244 assert_operand_cnt(2);
6245 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6246 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6247 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6248 strcpy(g_comment, "xlat");
6252 assert_operand_cnt(2);
6253 fprintf(fout, " %s = (s32)%s >> 31;",
6254 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6255 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6256 strcpy(g_comment, "cdq");
6260 assert_operand_cnt(1);
6261 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6262 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6266 if (po->flags & OPF_REP) {
6267 assert_operand_cnt(3);
6272 assert_operand_cnt(2);
6273 fprintf(fout, " %s = %sesi; esi %c= %d;",
6274 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6275 lmod_cast_u_ptr(po, po->operand[1].lmod),
6276 (po->flags & OPF_DF) ? '-' : '+',
6277 lmod_bytes(po, po->operand[1].lmod));
6278 strcpy(g_comment, "lods");
6283 if (po->flags & OPF_REP) {
6284 assert_operand_cnt(3);
6285 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6286 (po->flags & OPF_DF) ? '-' : '+',
6287 lmod_bytes(po, po->operand[1].lmod));
6288 fprintf(fout, " %sedi = eax;",
6289 lmod_cast_u_ptr(po, po->operand[1].lmod));
6290 strcpy(g_comment, "rep stos");
6293 assert_operand_cnt(2);
6294 fprintf(fout, " %sedi = eax; edi %c= %d;",
6295 lmod_cast_u_ptr(po, po->operand[1].lmod),
6296 (po->flags & OPF_DF) ? '-' : '+',
6297 lmod_bytes(po, po->operand[1].lmod));
6298 strcpy(g_comment, "stos");
6303 j = lmod_bytes(po, po->operand[0].lmod);
6304 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6305 l = (po->flags & OPF_DF) ? '-' : '+';
6306 if (po->flags & OPF_REP) {
6307 assert_operand_cnt(3);
6309 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6312 " %sedi = %sesi;", buf1, buf1);
6313 strcpy(g_comment, "rep movs");
6316 assert_operand_cnt(2);
6317 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6318 buf1, buf1, l, j, l, j);
6319 strcpy(g_comment, "movs");
6324 // repe ~ repeat while ZF=1
6325 j = lmod_bytes(po, po->operand[0].lmod);
6326 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6327 l = (po->flags & OPF_DF) ? '-' : '+';
6328 if (po->flags & OPF_REP) {
6329 assert_operand_cnt(3);
6331 " while (ecx != 0) {\n");
6332 if (pfomask & (1 << PFO_C)) {
6335 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6336 pfomask &= ~(1 << PFO_C);
6339 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6340 buf1, buf1, l, j, l, j);
6343 " if (cond_z %s 0) break;\n",
6344 (po->flags & OPF_REPZ) ? "==" : "!=");
6347 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6348 (po->flags & OPF_REPZ) ? "e" : "ne");
6351 assert_operand_cnt(2);
6353 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6354 buf1, buf1, l, j, l, j);
6355 strcpy(g_comment, "cmps");
6357 pfomask &= ~(1 << PFO_Z);
6358 last_arith_dst = NULL;
6359 delayed_flag_op = NULL;
6363 // only does ZF (for now)
6364 // repe ~ repeat while ZF=1
6365 j = lmod_bytes(po, po->operand[1].lmod);
6366 l = (po->flags & OPF_DF) ? '-' : '+';
6367 if (po->flags & OPF_REP) {
6368 assert_operand_cnt(3);
6370 " while (ecx != 0) {\n");
6372 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6373 lmod_cast_u(po, po->operand[1].lmod),
6374 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6377 " if (cond_z %s 0) break;\n",
6378 (po->flags & OPF_REPZ) ? "==" : "!=");
6381 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6382 (po->flags & OPF_REPZ) ? "e" : "ne");
6385 assert_operand_cnt(2);
6386 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6387 lmod_cast_u(po, po->operand[1].lmod),
6388 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6389 strcpy(g_comment, "scas");
6391 pfomask &= ~(1 << PFO_Z);
6392 last_arith_dst = NULL;
6393 delayed_flag_op = NULL;
6396 // arithmetic w/flags
6398 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6399 goto dualop_arith_const;
6400 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6404 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6405 if (po->operand[1].type == OPT_CONST) {
6406 j = lmod_bytes(po, po->operand[0].lmod);
6407 if (((1ull << j * 8) - 1) == po->operand[1].val)
6408 goto dualop_arith_const;
6413 assert_operand_cnt(2);
6414 fprintf(fout, " %s %s= %s;",
6415 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6417 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6418 output_std_flags(fout, po, &pfomask, buf1);
6419 last_arith_dst = &po->operand[0];
6420 delayed_flag_op = NULL;
6424 // and 0, or ~0 used instead mov
6425 assert_operand_cnt(2);
6426 fprintf(fout, " %s = %s;",
6427 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6428 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6429 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6430 output_std_flags(fout, po, &pfomask, buf1);
6431 last_arith_dst = &po->operand[0];
6432 delayed_flag_op = NULL;
6437 assert_operand_cnt(2);
6438 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6439 if (pfomask & (1 << PFO_C)) {
6440 if (po->operand[1].type == OPT_CONST) {
6441 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6442 j = po->operand[1].val;
6445 if (po->op == OP_SHL)
6449 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6453 ferr(po, "zero shift?\n");
6457 pfomask &= ~(1 << PFO_C);
6459 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6460 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6461 if (po->operand[1].type != OPT_CONST)
6462 fprintf(fout, " & 0x1f");
6464 output_std_flags(fout, po, &pfomask, buf1);
6465 last_arith_dst = &po->operand[0];
6466 delayed_flag_op = NULL;
6470 assert_operand_cnt(2);
6471 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6472 fprintf(fout, " %s = %s%s >> %s;", buf1,
6473 lmod_cast_s(po, po->operand[0].lmod), buf1,
6474 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6475 output_std_flags(fout, po, &pfomask, buf1);
6476 last_arith_dst = &po->operand[0];
6477 delayed_flag_op = NULL;
6482 assert_operand_cnt(3);
6483 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6484 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6485 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6486 if (po->operand[2].type != OPT_CONST) {
6487 // no handling for "undefined" case, hopefully not needed
6488 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6491 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6492 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6493 if (po->op == OP_SHLD) {
6494 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6495 buf1, buf3, buf1, buf2, l, buf3);
6496 strcpy(g_comment, "shld");
6499 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6500 buf1, buf3, buf1, buf2, l, buf3);
6501 strcpy(g_comment, "shrd");
6503 output_std_flags(fout, po, &pfomask, buf1);
6504 last_arith_dst = &po->operand[0];
6505 delayed_flag_op = NULL;
6510 assert_operand_cnt(2);
6511 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6512 if (po->operand[1].type == OPT_CONST) {
6513 j = po->operand[1].val;
6514 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6515 fprintf(fout, po->op == OP_ROL ?
6516 " %s = (%s << %d) | (%s >> %d);" :
6517 " %s = (%s >> %d) | (%s << %d);",
6518 buf1, buf1, j, buf1,
6519 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6523 output_std_flags(fout, po, &pfomask, buf1);
6524 last_arith_dst = &po->operand[0];
6525 delayed_flag_op = NULL;
6530 assert_operand_cnt(2);
6531 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6532 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6533 if (po->operand[1].type == OPT_CONST) {
6534 j = po->operand[1].val % l;
6536 ferr(po, "zero rotate\n");
6537 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6538 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6539 if (po->op == OP_RCL) {
6541 " %s = (%s << %d) | (cond_c << %d)",
6542 buf1, buf1, j, j - 1);
6544 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6548 " %s = (%s >> %d) | (cond_c << %d)",
6549 buf1, buf1, j, l - j);
6551 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6553 fprintf(fout, ";\n");
6554 fprintf(fout, " cond_c = tmp;");
6558 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6559 output_std_flags(fout, po, &pfomask, buf1);
6560 last_arith_dst = &po->operand[0];
6561 delayed_flag_op = NULL;
6565 assert_operand_cnt(2);
6566 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6567 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6568 // special case for XOR
6569 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
6570 for (j = 0; j <= PFO_LE; j++) {
6571 if (pfomask & (1 << j)) {
6572 fprintf(fout, " cond_%s = %d;\n",
6573 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
6574 pfomask &= ~(1 << j);
6577 fprintf(fout, " %s = 0;",
6578 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6579 last_arith_dst = &po->operand[0];
6580 delayed_flag_op = NULL;
6586 assert_operand_cnt(2);
6587 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6588 if (pfomask & (1 << PFO_C)) {
6589 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6590 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6591 if (po->operand[0].lmod == OPLM_DWORD) {
6592 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6593 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6594 fprintf(fout, " %s = (u32)tmp64;",
6595 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6596 strcat(g_comment, " add64");
6599 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6600 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6601 fprintf(fout, " %s += %s;",
6602 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6605 pfomask &= ~(1 << PFO_C);
6606 output_std_flags(fout, po, &pfomask, buf1);
6607 last_arith_dst = &po->operand[0];
6608 delayed_flag_op = NULL;
6611 if (pfomask & (1 << PFO_LE)) {
6612 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
6613 fprintf(fout, " cond_%s = %s;\n",
6614 parsed_flag_op_names[PFO_LE], buf1);
6615 pfomask &= ~(1 << PFO_LE);
6620 assert_operand_cnt(2);
6621 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6622 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6623 for (j = 0; j <= PFO_LE; j++) {
6624 if (!(pfomask & (1 << j)))
6626 if (j == PFO_Z || j == PFO_S)
6629 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6630 fprintf(fout, " cond_%s = %s;\n",
6631 parsed_flag_op_names[j], buf1);
6632 pfomask &= ~(1 << j);
6639 assert_operand_cnt(2);
6640 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6641 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6642 if (po->op == OP_SBB
6643 && IS(po->operand[0].name, po->operand[1].name))
6645 // avoid use of unitialized var
6646 fprintf(fout, " %s = -cond_c;", buf1);
6647 // carry remains what it was
6648 pfomask &= ~(1 << PFO_C);
6651 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6652 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6654 output_std_flags(fout, po, &pfomask, buf1);
6655 last_arith_dst = &po->operand[0];
6656 delayed_flag_op = NULL;
6660 assert_operand_cnt(2);
6661 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6662 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6663 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6665 output_std_flags(fout, po, &pfomask, buf1);
6666 last_arith_dst = &po->operand[0];
6667 delayed_flag_op = NULL;
6668 strcat(g_comment, " bsf");
6672 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6673 for (j = 0; j <= PFO_LE; j++) {
6674 if (!(pfomask & (1 << j)))
6676 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6679 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6680 fprintf(fout, " cond_%s = %s;\n",
6681 parsed_flag_op_names[j], buf1);
6682 pfomask &= ~(1 << j);
6688 if (pfomask & (1 << PFO_C))
6689 // carry is unaffected by inc/dec.. wtf?
6690 ferr(po, "carry propagation needed\n");
6692 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6693 if (po->operand[0].type == OPT_REG) {
6694 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6695 fprintf(fout, " %s%s;", buf1, buf2);
6698 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6699 fprintf(fout, " %s %s= 1;", buf1, buf2);
6701 output_std_flags(fout, po, &pfomask, buf1);
6702 last_arith_dst = &po->operand[0];
6703 delayed_flag_op = NULL;
6707 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6708 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6709 fprintf(fout, " %s = -%s%s;", buf1,
6710 lmod_cast_s(po, po->operand[0].lmod), buf2);
6711 last_arith_dst = &po->operand[0];
6712 delayed_flag_op = NULL;
6713 if (pfomask & PFOB_C) {
6714 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6717 output_std_flags(fout, po, &pfomask, buf1);
6721 if (po->operand_cnt == 2) {
6722 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6725 if (po->operand_cnt == 3)
6726 ferr(po, "TODO imul3\n");
6729 assert_operand_cnt(1);
6730 switch (po->operand[0].lmod) {
6732 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6733 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6734 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6735 fprintf(fout, " edx = tmp64 >> 32;\n");
6736 fprintf(fout, " eax = tmp64;");
6739 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6740 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6741 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6745 ferr(po, "TODO: unhandled mul type\n");
6748 last_arith_dst = NULL;
6749 delayed_flag_op = NULL;
6754 assert_operand_cnt(1);
6755 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6756 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6757 po->op == OP_IDIV));
6758 switch (po->operand[0].lmod) {
6760 if (po->flags & OPF_32BIT)
6761 snprintf(buf2, sizeof(buf2), "%seax", cast);
6763 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6764 snprintf(buf2, sizeof(buf2), "%stmp64",
6765 (po->op == OP_IDIV) ? "(s64)" : "");
6767 if (po->operand[0].type == OPT_REG
6768 && po->operand[0].reg == xDX)
6770 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6771 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6774 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6775 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6779 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6780 snprintf(buf2, sizeof(buf2), "%stmp",
6781 (po->op == OP_IDIV) ? "(s32)" : "");
6782 if (po->operand[0].type == OPT_REG
6783 && po->operand[0].reg == xDX)
6785 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6787 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6791 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6793 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6796 strcat(g_comment, " div16");
6799 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6801 last_arith_dst = NULL;
6802 delayed_flag_op = NULL;
6807 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6809 for (j = 0; j < 8; j++) {
6810 if (pfomask & (1 << j)) {
6811 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6812 fprintf(fout, " cond_%s = %s;",
6813 parsed_flag_op_names[j], buf1);
6820 last_arith_dst = NULL;
6821 delayed_flag_op = po;
6825 // SETcc - should already be handled
6828 // note: we reuse OP_Jcc for SETcc, only flags differ
6830 fprintf(fout, "\n goto %s;", po->operand[0].name);
6834 fprintf(fout, " if (ecx == 0)\n");
6835 fprintf(fout, " goto %s;", po->operand[0].name);
6836 strcat(g_comment, " jecxz");
6840 fprintf(fout, " if (--ecx != 0)\n");
6841 fprintf(fout, " goto %s;", po->operand[0].name);
6842 strcat(g_comment, " loop");
6846 assert_operand_cnt(1);
6847 last_arith_dst = NULL;
6848 delayed_flag_op = NULL;
6850 if (po->operand[0].type == OPT_REGMEM) {
6851 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6854 ferr(po, "parse failure for jmp '%s'\n",
6855 po->operand[0].name);
6856 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6859 else if (po->operand[0].type != OPT_LABEL)
6860 ferr(po, "unhandled jmp type\n");
6862 fprintf(fout, " goto %s;", po->operand[0].name);
6866 assert_operand_cnt(1);
6868 my_assert_not(pp, NULL);
6871 if (po->flags & OPF_CC) {
6872 // we treat conditional branch to another func
6873 // (yes such code exists..) as conditional tailcall
6875 fprintf(fout, " {\n");
6878 if (pp->is_fptr && !pp->is_arg) {
6879 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6880 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6882 if (pp->is_unresolved)
6883 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6884 buf3, asmfn, po->asmln, pp->name);
6887 fprintf(fout, "%s", buf3);
6888 if (strstr(pp->ret_type.name, "int64")) {
6889 if (po->flags & OPF_TAIL)
6890 ferr(po, "int64 and tail?\n");
6891 fprintf(fout, "tmp64 = ");
6893 else if (!IS(pp->ret_type.name, "void")) {
6894 if (po->flags & OPF_TAIL) {
6895 if (regmask_ret & mxAX) {
6896 fprintf(fout, "return ");
6897 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6898 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6900 else if (regmask_ret & mxST0)
6901 ferr(po, "float tailcall\n");
6903 else if (po->regmask_dst & mxAX) {
6904 fprintf(fout, "eax = ");
6905 if (pp->ret_type.is_ptr)
6906 fprintf(fout, "(u32)");
6908 else if (po->regmask_dst & mxST0) {
6909 ferr_assert(po, po->flags & OPF_FPUSH);
6910 if (need_float_stack)
6911 fprintf(fout, "f_st[--f_stp & 7] = ");
6913 fprintf(fout, "f_st0 = ");
6917 if (pp->name[0] == 0)
6918 ferr(po, "missing pp->name\n");
6919 fprintf(fout, "%s%s(", pp->name,
6920 pp->has_structarg ? "_sa" : "");
6922 if (po->flags & OPF_ATAIL) {
6923 if (pp->argc_stack != g_func_pp->argc_stack
6924 || (pp->argc_stack > 0
6925 && pp->is_stdcall != g_func_pp->is_stdcall))
6926 ferr(po, "incompatible tailcall\n");
6927 if (g_func_pp->has_retreg)
6928 ferr(po, "TODO: retreg+tailcall\n");
6930 for (arg = j = 0; arg < pp->argc; arg++) {
6932 fprintf(fout, ", ");
6935 if (pp->arg[arg].type.is_ptr)
6936 snprintf(cast, sizeof(cast), "(%s)",
6937 pp->arg[arg].type.name);
6939 if (pp->arg[arg].reg != NULL) {
6940 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6944 for (; j < g_func_pp->argc; j++)
6945 if (g_func_pp->arg[j].reg == NULL)
6947 fprintf(fout, "%sa%d", cast, j + 1);
6952 for (arg = 0; arg < pp->argc; arg++) {
6954 fprintf(fout, ", ");
6957 if (pp->arg[arg].type.is_ptr)
6958 snprintf(cast, sizeof(cast), "(%s)",
6959 pp->arg[arg].type.name);
6961 if (pp->arg[arg].reg != NULL) {
6962 if (pp->arg[arg].type.is_retreg)
6963 fprintf(fout, "&%s", pp->arg[arg].reg);
6964 else if (IS(pp->arg[arg].reg, "ebp")
6965 && g_bp_frame && !(po->flags & OPF_EBP_S))
6967 // rare special case
6968 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
6969 strcat(g_comment, " bp_ref");
6972 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6977 tmp_op = pp->arg[arg].datap;
6979 ferr(po, "parsed_op missing for arg%d\n", arg);
6981 if (tmp_op->flags & OPF_VAPUSH) {
6982 fprintf(fout, "ap");
6984 else if (tmp_op->op == OP_FST) {
6985 fprintf(fout, "fs_%d", tmp_op->p_argnum);
6986 if (tmp_op->operand[0].lmod == OPLM_QWORD)
6989 else if (tmp_op->p_argpass != 0) {
6990 fprintf(fout, "a%d", tmp_op->p_argpass);
6992 else if (pp->arg[arg].is_saved) {
6993 ferr_assert(po, tmp_op->p_argnum > 0);
6994 fprintf(fout, "%s%s", cast,
6995 saved_arg_name(buf1, sizeof(buf1),
6996 tmp_op->p_arggrp, tmp_op->p_argnum));
7000 out_src_opr(buf1, sizeof(buf1),
7001 tmp_op, &tmp_op->operand[0], cast, 0));
7005 fprintf(fout, ");");
7007 if (strstr(pp->ret_type.name, "int64")) {
7008 fprintf(fout, "\n");
7009 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7010 fprintf(fout, "%seax = tmp64;", buf3);
7013 if (pp->is_unresolved) {
7014 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7016 strcat(g_comment, buf2);
7019 if (po->flags & OPF_TAIL) {
7021 if (i == opcnt - 1 || pp->is_noreturn)
7023 else if (IS(pp->ret_type.name, "void"))
7025 else if (!(regmask_ret & (1 << xAX)))
7027 // else already handled as 'return f()'
7030 fprintf(fout, "\n%sreturn;", buf3);
7031 strcat(g_comment, " ^ tailcall");
7034 strcat(g_comment, " tailcall");
7036 if ((regmask_ret & (1 << xAX))
7037 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7039 ferr(po, "int func -> void func tailcall?\n");
7042 if (pp->is_noreturn)
7043 strcat(g_comment, " noreturn");
7044 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7045 strcat(g_comment, " argframe");
7046 if (po->flags & OPF_CC)
7047 strcat(g_comment, " cond");
7049 if (po->flags & OPF_CC)
7050 fprintf(fout, "\n }");
7052 delayed_flag_op = NULL;
7053 last_arith_dst = NULL;
7057 if (g_func_pp->is_vararg)
7058 fprintf(fout, " va_end(ap);\n");
7059 if (g_func_pp->has_retreg) {
7060 for (arg = 0; arg < g_func_pp->argc; arg++)
7061 if (g_func_pp->arg[arg].type.is_retreg)
7062 fprintf(fout, " *r_%s = %s;\n",
7063 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7066 if (regmask_ret & mxST0) {
7067 fprintf(fout, " return %s;", float_st0);
7069 else if (!(regmask_ret & mxAX)) {
7070 if (i != opcnt - 1 || label_pending)
7071 fprintf(fout, " return;");
7073 else if (g_func_pp->ret_type.is_ptr) {
7074 fprintf(fout, " return (%s)eax;",
7075 g_func_pp->ret_type.name);
7077 else if (IS(g_func_pp->ret_type.name, "__int64"))
7078 fprintf(fout, " return ((u64)edx << 32) | eax;");
7080 fprintf(fout, " return eax;");
7082 last_arith_dst = NULL;
7083 delayed_flag_op = NULL;
7087 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7088 if (po->p_argnum != 0) {
7089 // special case - saved func arg
7090 fprintf(fout, " %s = %s;",
7091 saved_arg_name(buf2, sizeof(buf2),
7092 po->p_arggrp, po->p_argnum), buf1);
7095 else if (po->flags & OPF_RSAVE) {
7096 fprintf(fout, " s_%s = %s;", buf1, buf1);
7099 else if (po->flags & OPF_PPUSH) {
7101 ferr_assert(po, tmp_op != NULL);
7102 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7103 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7106 else if (g_func_pp->is_userstack) {
7107 fprintf(fout, " *(--esp) = %s;", buf1);
7110 if (!(g_ida_func_attr & IDAFA_NORETURN))
7111 ferr(po, "stray push encountered\n");
7116 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7117 if (po->flags & OPF_RSAVE) {
7118 fprintf(fout, " %s = s_%s;", buf1, buf1);
7121 else if (po->flags & OPF_PPUSH) {
7122 // push/pop graph / non-const
7123 ferr_assert(po, po->datap == NULL);
7124 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7127 else if (po->datap != NULL) {
7130 fprintf(fout, " %s = %s;", buf1,
7131 out_src_opr(buf2, sizeof(buf2),
7132 tmp_op, &tmp_op->operand[0],
7133 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7136 else if (g_func_pp->is_userstack) {
7137 fprintf(fout, " %s = *esp++;", buf1);
7141 ferr(po, "stray pop encountered\n");
7151 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7152 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7153 po->op == OPP_ALLSHL ? "<<" : ">>");
7154 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7155 strcat(g_comment, po->op == OPP_ALLSHL
7156 ? " allshl" : " allshr");
7161 if (need_float_stack) {
7162 out_src_opr_float(buf1, sizeof(buf1),
7163 po, &po->operand[0], 1);
7164 if (po->regmask_src & mxSTa) {
7165 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7169 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7172 if (po->flags & OPF_FSHIFT)
7173 fprintf(fout, " f_st1 = f_st0;");
7174 if (po->operand[0].type == OPT_REG
7175 && po->operand[0].reg == xST0)
7177 strcat(g_comment, " fld st");
7180 fprintf(fout, " f_st0 = %s;",
7181 out_src_opr_float(buf1, sizeof(buf1),
7182 po, &po->operand[0], 0));
7184 strcat(g_comment, " fld");
7188 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7189 lmod_cast(po, po->operand[0].lmod, 1), 0);
7190 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7191 if (need_float_stack) {
7192 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7195 if (po->flags & OPF_FSHIFT)
7196 fprintf(fout, " f_st1 = f_st0;");
7197 fprintf(fout, " f_st0 = %s;", buf2);
7199 strcat(g_comment, " fild");
7203 if (need_float_stack)
7204 fprintf(fout, " f_st[--f_stp & 7] = ");
7206 if (po->flags & OPF_FSHIFT)
7207 fprintf(fout, " f_st1 = f_st0;");
7208 fprintf(fout, " f_st0 = ");
7210 switch (po->operand[0].val) {
7211 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7212 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
7213 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7214 default: ferr(po, "TODO\n"); break;
7219 if (po->flags & OPF_FARG) {
7220 // store to stack as func arg
7221 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7225 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7227 dead_dst = po->operand[0].type == OPT_REG
7228 && po->operand[0].reg == xST0;
7231 fprintf(fout, " %s = %s;", buf1, float_st0);
7232 if (po->flags & OPF_FSHIFT) {
7233 if (need_float_stack)
7234 fprintf(fout, " f_stp++;");
7236 fprintf(fout, " f_st0 = f_st1;");
7238 if (dead_dst && !(po->flags & OPF_FSHIFT))
7241 strcat(g_comment, " fst");
7245 fprintf(fout, " %s = %s%s;",
7246 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7247 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7248 if (po->flags & OPF_FSHIFT) {
7249 if (need_float_stack)
7250 fprintf(fout, " f_stp++;");
7252 fprintf(fout, " f_st0 = f_st1;");
7254 strcat(g_comment, " fist");
7261 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7263 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7265 dead_dst = (po->flags & OPF_FPOP)
7266 && po->operand[0].type == OPT_REG
7267 && po->operand[0].reg == xST0;
7269 case OP_FADD: j = '+'; break;
7270 case OP_FDIV: j = '/'; break;
7271 case OP_FMUL: j = '*'; break;
7272 case OP_FSUB: j = '-'; break;
7273 default: j = 'x'; break;
7275 if (need_float_stack) {
7277 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7278 if (po->flags & OPF_FSHIFT)
7279 fprintf(fout, " f_stp++;");
7282 if (po->flags & OPF_FSHIFT) {
7283 // note: assumes only 2 regs handled
7285 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7287 fprintf(fout, " f_st0 = f_st1;");
7290 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7292 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7297 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7299 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7301 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7303 dead_dst = (po->flags & OPF_FPOP)
7304 && po->operand[0].type == OPT_REG
7305 && po->operand[0].reg == xST0;
7306 j = po->op == OP_FDIVR ? '/' : '-';
7307 if (need_float_stack) {
7309 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7310 if (po->flags & OPF_FSHIFT)
7311 fprintf(fout, " f_stp++;");
7314 if (po->flags & OPF_FSHIFT) {
7316 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7318 fprintf(fout, " f_st0 = f_st1;");
7321 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7323 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7331 case OP_FIADD: j = '+'; break;
7332 case OP_FIDIV: j = '/'; break;
7333 case OP_FIMUL: j = '*'; break;
7334 case OP_FISUB: j = '-'; break;
7335 default: j = 'x'; break;
7337 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7339 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7340 lmod_cast(po, po->operand[0].lmod, 1), 0));
7345 fprintf(fout, " %s = %s %c %s;", float_st0,
7346 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7348 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7353 ferr_assert(po, po->datap != NULL);
7354 mask = (long)po->datap & 0xffff;
7355 z_check = ((long)po->datap >> 16) & 1;
7356 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7358 if (mask == 0x0100) { // C0 -> <
7359 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7362 else if (mask == 0x4000) { // C3 -> =
7363 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7366 else if (mask == 0x4100) { // C3, C0
7368 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7370 strcat(g_comment, " z_chk_det");
7373 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7374 "(%s < %s ? 0x0100 : 0);",
7375 float_st0, buf1, float_st0, buf1);
7379 ferr(po, "unhandled sw mask: %x\n", mask);
7380 if (po->flags & OPF_FSHIFT) {
7381 if (need_float_stack)
7382 fprintf(fout, " f_stp++;");
7384 fprintf(fout, " f_st0 = f_st1;");
7390 fprintf(fout, " %s = f_sw;",
7391 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7395 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7399 fprintf(fout, " %s = cos%s(%s);", float_st0,
7400 need_double ? "" : "f", float_st0);
7404 if (need_float_stack) {
7405 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7406 need_double ? "" : "f", float_st1, float_st0);
7407 fprintf(fout, " f_stp++;");
7410 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7411 need_double ? "" : "f");
7416 if (need_float_stack) {
7417 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7418 float_st1, need_double ? "" : "f", float_st0);
7419 fprintf(fout, " f_stp++;");
7422 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7423 need_double ? "" : "f");
7425 strcat(g_comment, " fyl2x");
7429 fprintf(fout, " %s = sin%s(%s);", float_st0,
7430 need_double ? "" : "f", float_st0);
7434 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7435 need_double ? "" : "f", float_st0);
7439 dead_dst = po->operand[0].type == OPT_REG
7440 && po->operand[0].reg == xST0;
7442 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7444 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7445 float_st0, float_st0, buf1, buf1);
7446 strcat(g_comment, " fxch");
7453 ferr_assert(po, po->flags & OPF_32BIT);
7454 fprintf(fout, " eax = (s32)%s;", float_st0);
7455 if (po->flags & OPF_FSHIFT) {
7456 if (need_float_stack)
7457 fprintf(fout, " f_stp++;");
7459 fprintf(fout, " f_st0 = f_st1;");
7461 strcat(g_comment, " ftol");
7465 if (need_float_stack) {
7466 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
7467 need_double ? "" : "f", float_st1, float_st0);
7468 fprintf(fout, " f_stp++;");
7471 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
7472 need_double ? "" : "f");
7474 strcat(g_comment, " CIpow");
7478 fprintf(fout, " do_skip_code_abort();");
7483 fprintf(fout, " do_emms();");
7488 ferr(po, "unhandled op type %d, flags %x\n",
7493 if (g_comment[0] != 0) {
7494 char *p = g_comment;
7495 while (my_isblank(*p))
7497 fprintf(fout, " // %s", p);
7502 fprintf(fout, "\n");
7504 // some sanity checking
7505 if (po->flags & OPF_REP) {
7506 if (po->op != OP_STOS && po->op != OP_MOVS
7507 && po->op != OP_CMPS && po->op != OP_SCAS)
7508 ferr(po, "unexpected rep\n");
7509 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7510 && (po->op == OP_CMPS || po->op == OP_SCAS))
7511 ferr(po, "cmps/scas with plain rep\n");
7513 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7514 && po->op != OP_CMPS && po->op != OP_SCAS)
7515 ferr(po, "unexpected repz/repnz\n");
7518 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
7520 // see is delayed flag stuff is still valid
7521 if (delayed_flag_op != NULL && delayed_flag_op != po) {
7522 if (is_any_opr_modified(delayed_flag_op, po, 0))
7523 delayed_flag_op = NULL;
7526 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7527 if (is_opr_modified(last_arith_dst, po))
7528 last_arith_dst = NULL;
7534 if (g_stack_fsz && !g_stack_frame_used)
7535 fprintf(fout, " (void)sf;\n");
7537 fprintf(fout, "}\n\n");
7539 gen_x_cleanup(opcnt);
7542 static void gen_x_cleanup(int opcnt)
7546 for (i = 0; i < opcnt; i++) {
7547 struct label_ref *lr, *lr_del;
7549 lr = g_label_refs[i].next;
7550 while (lr != NULL) {
7555 g_label_refs[i].i = -1;
7556 g_label_refs[i].next = NULL;
7558 if (ops[i].op == OP_CALL) {
7560 proto_release(ops[i].pp);
7566 struct func_proto_dep;
7568 struct func_prototype {
7573 int has_ret:3; // -1, 0, 1: unresolved, no, yes
7574 unsigned int dep_resolved:1;
7575 unsigned int is_stdcall:1;
7576 struct func_proto_dep *dep_func;
7578 const struct parsed_proto *pp; // seed pp, if any
7581 struct func_proto_dep {
7583 struct func_prototype *proto;
7584 int regmask_live; // .. at the time of call
7585 unsigned int ret_dep:1; // return from this is caller's return
7588 static struct func_prototype *hg_fp;
7589 static int hg_fp_cnt;
7591 static struct scanned_var {
7593 enum opr_lenmod lmod;
7594 unsigned int is_seeded:1;
7595 unsigned int is_c_str:1;
7596 const struct parsed_proto *pp; // seed pp, if any
7598 static int hg_var_cnt;
7600 static char **hg_refs;
7601 static int hg_ref_cnt;
7603 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7606 static struct func_prototype *hg_fp_add(const char *funcn)
7608 struct func_prototype *fp;
7610 if ((hg_fp_cnt & 0xff) == 0) {
7611 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7612 my_assert_not(hg_fp, NULL);
7613 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7616 fp = &hg_fp[hg_fp_cnt];
7617 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7619 fp->argc_stack = -1;
7625 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7630 for (i = 0; i < fp->dep_func_cnt; i++)
7631 if (IS(fp->dep_func[i].name, name))
7632 return &fp->dep_func[i];
7637 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7640 if (hg_fp_find_dep(fp, name))
7643 if ((fp->dep_func_cnt & 0xff) == 0) {
7644 fp->dep_func = realloc(fp->dep_func,
7645 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7646 my_assert_not(fp->dep_func, NULL);
7647 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7648 sizeof(fp->dep_func[0]) * 0x100);
7650 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7654 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7656 const struct func_prototype *p1 = p1_, *p2 = p2_;
7657 return strcmp(p1->name, p2->name);
7661 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7663 const struct func_prototype *p1 = p1_, *p2 = p2_;
7664 return p1->id - p2->id;
7668 static void hg_ref_add(const char *name)
7670 if ((hg_ref_cnt & 0xff) == 0) {
7671 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7672 my_assert_not(hg_refs, NULL);
7673 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7676 hg_refs[hg_ref_cnt] = strdup(name);
7677 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7681 // recursive register dep pass
7682 // - track saved regs (part 2)
7683 // - try to figure out arg-regs
7684 // - calculate reg deps
7685 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
7686 struct func_prototype *fp, int regmask_save, int regmask_dst,
7687 int *regmask_dep, int *has_ret)
7689 struct func_proto_dep *dep;
7690 struct parsed_op *po;
7691 int from_caller = 0;
7696 for (; i < opcnt; i++)
7698 if (cbits[i >> 3] & (1 << (i & 7)))
7700 cbits[i >> 3] |= (1 << (i & 7));
7704 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
7705 if (po->flags & OPF_RMD)
7708 if (po->btj != NULL) {
7710 for (j = 0; j < po->btj->count; j++) {
7711 check_i(po, po->btj->d[j].bt_i);
7712 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
7713 regmask_save, regmask_dst, regmask_dep, has_ret);
7718 check_i(po, po->bt_i);
7719 if (po->flags & OPF_CJMP) {
7720 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
7721 regmask_save, regmask_dst, regmask_dep, has_ret);
7729 if (po->flags & OPF_FARG)
7730 /* (just calculate register deps) */;
7731 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
7733 reg = po->operand[0].reg;
7734 ferr_assert(po, reg >= 0);
7736 if (po->flags & OPF_RSAVE) {
7737 regmask_save |= 1 << reg;
7740 if (po->flags & OPF_DONE)
7743 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
7745 regmask_save |= 1 << reg;
7746 po->flags |= OPF_RMD;
7747 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
7751 else if (po->flags & OPF_RMD)
7753 else if (po->op == OP_CALL) {
7754 po->regmask_dst |= 1 << xAX;
7756 dep = hg_fp_find_dep(fp, po->operand[0].name);
7758 dep->regmask_live = regmask_save | regmask_dst;
7759 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7760 dep->regmask_live |= 1 << xBP;
7763 else if (po->op == OP_RET) {
7764 if (po->operand_cnt > 0) {
7766 if (fp->argc_stack >= 0
7767 && fp->argc_stack != po->operand[0].val / 4)
7768 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
7769 fp->argc_stack = po->operand[0].val / 4;
7773 // if has_ret is 0, there is uninitialized eax path,
7774 // which means it's most likely void func
7775 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
7776 if (po->op == OP_CALL) {
7781 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
7784 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
7787 if (ret != 1 && from_caller) {
7788 // unresolved eax - probably void func
7792 if (j >= 0 && ops[j].op == OP_CALL) {
7793 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
7804 l = regmask_save | regmask_dst;
7805 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7808 l = po->regmask_src & ~l;
7811 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
7812 l, regmask_dst, regmask_save, po->flags);
7815 regmask_dst |= po->regmask_dst;
7817 if (po->flags & OPF_TAIL)
7822 static void gen_hdr(const char *funcn, int opcnt)
7824 unsigned char cbits[MAX_OPS / 8];
7825 const struct parsed_proto *pp_c;
7826 struct parsed_proto *pp;
7827 struct func_prototype *fp;
7828 struct parsed_op *po;
7829 int regmask_dummy = 0;
7831 int max_bp_offset = 0;
7836 pp_c = proto_parse(g_fhdr, funcn, 1);
7838 // already in seed, will add to hg_fp later
7841 fp = hg_fp_add(funcn);
7843 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7844 g_stack_frame_used = 0;
7847 // - resolve all branches
7848 // - parse calls with labels
7849 resolve_branches_parse_calls(opcnt);
7852 // - handle ebp/esp frame, remove ops related to it
7853 scan_prologue_epilogue(opcnt);
7856 // - remove dead labels
7858 for (i = 0; i < opcnt; i++)
7860 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7866 if (po->flags & (OPF_RMD|OPF_DONE))
7869 if (po->op == OP_CALL) {
7870 if (po->operand[0].type == OPT_LABEL)
7871 hg_fp_add_dep(fp, opr_name(po, 0));
7872 else if (po->pp != NULL)
7873 hg_fp_add_dep(fp, po->pp->name);
7878 // - remove dead labels
7879 // - handle push <const>/pop pairs
7880 for (i = 0; i < opcnt; i++)
7882 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7888 if (po->flags & (OPF_RMD|OPF_DONE))
7891 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
7892 scan_for_pop_const(i, opcnt, i + opcnt * 13);
7896 // - process trivial calls
7897 for (i = 0; i < opcnt; i++)
7900 if (po->flags & (OPF_RMD|OPF_DONE))
7903 if (po->op == OP_CALL)
7905 pp = process_call_early(i, opcnt, &j);
7907 if (!(po->flags & OPF_ATAIL))
7908 // since we know the args, try to collect them
7909 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
7915 // commit esp adjust
7916 if (ops[j].op != OP_POP)
7917 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
7919 for (l = 0; l < pp->argc_stack; l++)
7920 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
7924 po->flags |= OPF_DONE;
7930 // - track saved regs (simple)
7932 for (i = 0; i < opcnt; i++)
7935 if (po->flags & (OPF_RMD|OPF_DONE))
7938 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7939 && po->operand[0].reg != xCX)
7941 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
7943 // regmask_save |= 1 << po->operand[0].reg; // do it later
7944 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
7945 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
7948 else if (po->op == OP_CALL)
7950 pp = process_call(i, opcnt);
7952 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
7953 // since we know the args, collect them
7954 ret = collect_call_args(po, i, pp, ®mask_dummy,
7961 memset(cbits, 0, sizeof(cbits));
7965 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
7967 // find unreachable code - must be fixed in IDA
7968 for (i = 0; i < opcnt; i++)
7970 if (cbits[i >> 3] & (1 << (i & 7)))
7973 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
7974 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
7976 // the compiler sometimes still generates code after
7977 // noreturn OS functions
7980 if (ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
7981 ferr(&ops[i], "unreachable code\n");
7984 for (i = 0; i < g_eqcnt; i++) {
7985 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
7986 max_bp_offset = g_eqs[i].offset;
7989 if (fp->argc_stack < 0) {
7990 max_bp_offset = (max_bp_offset + 3) & ~3;
7991 fp->argc_stack = max_bp_offset / 4;
7992 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
7996 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
7997 fp->has_ret = has_ret;
7999 printf("// has_ret %d, regmask_dep %x\n",
8000 fp->has_ret, fp->regmask_dep);
8001 output_hdr_fp(stdout, fp, 1);
8002 if (IS(funcn, "sub_10007F72")) exit(1);
8005 gen_x_cleanup(opcnt);
8008 static void hg_fp_resolve_deps(struct func_prototype *fp)
8010 struct func_prototype fp_s;
8014 // this thing is recursive, so mark first..
8015 fp->dep_resolved = 1;
8017 for (i = 0; i < fp->dep_func_cnt; i++) {
8018 strcpy(fp_s.name, fp->dep_func[i].name);
8019 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8020 sizeof(hg_fp[0]), hg_fp_cmp_name);
8021 if (fp->dep_func[i].proto != NULL) {
8022 if (!fp->dep_func[i].proto->dep_resolved)
8023 hg_fp_resolve_deps(fp->dep_func[i].proto);
8025 dep = ~fp->dep_func[i].regmask_live
8026 & fp->dep_func[i].proto->regmask_dep;
8027 fp->regmask_dep |= dep;
8028 // printf("dep %s %s |= %x\n", fp->name,
8029 // fp->dep_func[i].name, dep);
8031 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8032 fp->has_ret = fp->dep_func[i].proto->has_ret;
8037 // make all thiscall/edx arg functions referenced from .data fastcall
8038 static void do_func_refs_from_data(void)
8040 struct func_prototype *fp, fp_s;
8043 for (i = 0; i < hg_ref_cnt; i++) {
8044 strcpy(fp_s.name, hg_refs[i]);
8045 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8046 sizeof(hg_fp[0]), hg_fp_cmp_name);
8050 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8051 fp->regmask_dep |= mxCX | mxDX;
8055 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8058 const struct parsed_proto *pp;
8059 char *p, namebuf[NAMELEN];
8065 for (; count > 0; count--, fp++) {
8066 if (fp->has_ret == -1)
8067 fprintf(fout, "// ret unresolved\n");
8069 fprintf(fout, "// dep:");
8070 for (j = 0; j < fp->dep_func_cnt; j++) {
8071 fprintf(fout, " %s/", fp->dep_func[j].name);
8072 if (fp->dep_func[j].proto != NULL)
8073 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8074 fp->dep_func[j].proto->has_ret);
8076 fprintf(fout, "\n");
8079 p = strchr(fp->name, '@');
8081 memcpy(namebuf, fp->name, p - fp->name);
8082 namebuf[p - fp->name] = 0;
8090 pp = proto_parse(g_fhdr, name, 1);
8091 if (pp != NULL && pp->is_include)
8094 if (fp->pp != NULL) {
8095 // part of seed, output later
8099 regmask_dep = fp->regmask_dep;
8100 argc_normal = fp->argc_stack;
8102 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8103 (fp->has_ret ? "int" : "void"));
8104 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8105 && (regmask_dep & ~mxCX) == 0)
8107 fprintf(fout, "/*__thiscall*/ ");
8111 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8112 && (regmask_dep & ~(mxCX | mxDX)) == 0)
8114 fprintf(fout, " __fastcall ");
8115 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8121 else if (regmask_dep && !fp->is_stdcall) {
8122 fprintf(fout, "/*__usercall*/ ");
8124 else if (regmask_dep) {
8125 fprintf(fout, "/*__userpurge*/ ");
8127 else if (fp->is_stdcall)
8128 fprintf(fout, " __stdcall ");
8130 fprintf(fout, " __cdecl ");
8132 fprintf(fout, "%s(", name);
8135 for (j = 0; j < xSP; j++) {
8136 if (regmask_dep & (1 << j)) {
8139 fprintf(fout, ", ");
8141 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8143 fprintf(fout, "int");
8144 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8148 for (j = 0; j < argc_normal; j++) {
8151 fprintf(fout, ", ");
8152 if (fp->pp != NULL) {
8153 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8154 if (!fp->pp->arg[arg - 1].type.is_ptr)
8158 fprintf(fout, "int ");
8159 fprintf(fout, "a%d", arg);
8162 fprintf(fout, ");\n");
8166 static void output_hdr(FILE *fout)
8168 static const char *lmod_c_names[] = {
8169 [OPLM_UNSPEC] = "???",
8170 [OPLM_BYTE] = "uint8_t",
8171 [OPLM_WORD] = "uint16_t",
8172 [OPLM_DWORD] = "uint32_t",
8173 [OPLM_QWORD] = "uint64_t",
8175 const struct scanned_var *var;
8176 struct func_prototype *fp;
8177 char line[256] = { 0, };
8181 // add stuff from headers
8182 for (i = 0; i < pp_cache_size; i++) {
8183 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8184 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8186 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8187 fp = hg_fp_add(name);
8188 fp->pp = &pp_cache[i];
8189 fp->argc_stack = fp->pp->argc_stack;
8190 fp->is_stdcall = fp->pp->is_stdcall;
8191 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8192 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8196 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8197 for (i = 0; i < hg_fp_cnt; i++)
8198 hg_fp_resolve_deps(&hg_fp[i]);
8200 // adjust functions referenced from data segment
8201 do_func_refs_from_data();
8203 // note: messes up .proto ptr, don't use
8204 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8207 for (i = 0; i < hg_var_cnt; i++) {
8210 if (var->pp != NULL)
8213 else if (var->is_c_str)
8214 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8216 fprintf(fout, "extern %-8s %s;",
8217 lmod_c_names[var->lmod], var->name);
8220 fprintf(fout, " // seeded");
8221 fprintf(fout, "\n");
8224 fprintf(fout, "\n");
8226 // output function prototypes
8227 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8230 fprintf(fout, "\n// - seed -\n");
8233 while (fgets(line, sizeof(line), g_fhdr))
8234 fwrite(line, 1, strlen(line), fout);
8237 // '=' needs special treatment
8239 static char *next_word_s(char *w, size_t wsize, char *s)
8246 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8248 for (i = 1; i < wsize - 1; i++) {
8250 printf("warning: missing closing quote: \"%s\"\n", s);
8259 for (; i < wsize - 1; i++) {
8260 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8266 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8267 printf("warning: '%s' truncated\n", w);
8272 static int cmpstringp(const void *p1, const void *p2)
8274 return strcmp(*(char * const *)p1, *(char * const *)p2);
8277 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8282 if (strstr(p, "..."))
8283 // unable to determine, assume needed
8286 if (*p == '.') // .text, .data, ...
8287 // ref from other data or non-function -> no
8290 p2 = strpbrk(p, "+:\r\n\x18");
8293 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8294 // referenced from removed code
8300 static int ida_xrefs_show_need(FILE *fasm, char *p,
8301 char **rlist, int rlist_len)
8307 p = strrchr(p, ';');
8308 if (p != NULL && *p == ';') {
8309 if (IS_START(p + 2, "sctref"))
8311 if (IS_START(p + 2, "DATA XREF: ")) {
8313 if (is_xref_needed(p, rlist, rlist_len))
8321 if (!my_fgets(line, sizeof(line), fasm))
8323 // non-first line is always indented
8324 if (!my_isblank(line[0]))
8327 // should be no content, just comment
8332 p = strrchr(p, ';');
8335 if (IS_START(p, "sctref")) {
8340 // it's printed once, but no harm to check again
8341 if (IS_START(p, "DATA XREF: "))
8344 if (is_xref_needed(p, rlist, rlist_len)) {
8349 fseek(fasm, pos, SEEK_SET);
8353 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8355 struct scanned_var *var;
8356 char line[256] = { 0, };
8365 // skip to next data section
8366 while (my_fgets(line, sizeof(line), fasm))
8371 if (*p == 0 || *p == ';')
8374 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8375 if (*p == 0 || *p == ';')
8378 if (*p != 's' || !IS_START(p, "segment para public"))
8384 if (p == NULL || !IS_START(p, "segment para public"))
8388 if (!IS_START(p, "'DATA'"))
8392 while (my_fgets(line, sizeof(line), fasm))
8397 no_identifier = my_isblank(*p);
8400 if (*p == 0 || *p == ';')
8403 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8404 words[wordc][0] = 0;
8405 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8406 if (*p == 0 || *p == ';') {
8412 if (wordc == 2 && IS(words[1], "ends"))
8417 if (no_identifier) {
8418 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8419 hg_ref_add(words[2]);
8423 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8424 // when this starts, we don't need anything from this section
8428 // check refs comment(s)
8429 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8432 if ((hg_var_cnt & 0xff) == 0) {
8433 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8434 * (hg_var_cnt + 0x100));
8435 my_assert_not(hg_vars, NULL);
8436 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8439 var = &hg_vars[hg_var_cnt++];
8440 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8442 // maybe already in seed header?
8443 var->pp = proto_parse(g_fhdr, var->name, 1);
8444 if (var->pp != NULL) {
8445 if (var->pp->is_fptr) {
8446 var->lmod = OPLM_DWORD;
8449 else if (var->pp->is_func)
8451 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8452 aerr("unhandled C type '%s' for '%s'\n",
8453 var->pp->type.name, var->name);
8459 if (IS(words[1], "dd")) {
8460 var->lmod = OPLM_DWORD;
8461 if (wordc >= 4 && IS(words[2], "offset"))
8462 hg_ref_add(words[3]);
8464 else if (IS(words[1], "dw"))
8465 var->lmod = OPLM_WORD;
8466 else if (IS(words[1], "db")) {
8467 var->lmod = OPLM_BYTE;
8468 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8469 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8473 else if (IS(words[1], "dq"))
8474 var->lmod = OPLM_QWORD;
8475 //else if (IS(words[1], "dt"))
8477 aerr("type '%s' not known\n", words[1]);
8485 static void set_label(int i, const char *name)
8491 p = strchr(name, ':');
8495 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8496 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8497 g_labels[i] = realloc(g_labels[i], len + 1);
8498 my_assert_not(g_labels[i], NULL);
8499 memcpy(g_labels[i], name, len);
8500 g_labels[i][len] = 0;
8509 static struct chunk_item *func_chunks;
8510 static int func_chunk_cnt;
8511 static int func_chunk_alloc;
8513 static void add_func_chunk(FILE *fasm, const char *name, int line)
8515 if (func_chunk_cnt >= func_chunk_alloc) {
8516 func_chunk_alloc *= 2;
8517 func_chunks = realloc(func_chunks,
8518 func_chunk_alloc * sizeof(func_chunks[0]));
8519 my_assert_not(func_chunks, NULL);
8521 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8522 func_chunks[func_chunk_cnt].name = strdup(name);
8523 func_chunks[func_chunk_cnt].asmln = line;
8527 static int cmp_chunks(const void *p1, const void *p2)
8529 const struct chunk_item *c1 = p1, *c2 = p2;
8530 return strcmp(c1->name, c2->name);
8533 static void scan_ahead_for_chunks(FILE *fasm)
8543 oldpos = ftell(fasm);
8546 while (my_fgets(line, sizeof(line), fasm))
8557 // get rid of random tabs
8558 for (i = 0; line[i] != 0; i++)
8559 if (line[i] == '\t')
8562 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8565 next_word(words[0], sizeof(words[0]), p);
8566 if (words[0][0] == 0)
8567 aerr("missing name for func chunk?\n");
8569 add_func_chunk(fasm, words[0], asmln);
8571 else if (IS_START(p, "; sctend"))
8577 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8578 words[wordc][0] = 0;
8579 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8580 if (*p == 0 || *p == ';') {
8586 if (wordc == 2 && IS(words[1], "ends"))
8590 fseek(fasm, oldpos, SEEK_SET);
8594 int main(int argc, char *argv[])
8596 FILE *fout, *fasm, *frlist;
8597 struct parsed_data *pd = NULL;
8599 char **rlist = NULL;
8601 int rlist_alloc = 0;
8602 int func_chunks_used = 0;
8603 int func_chunks_sorted = 0;
8604 int func_chunk_i = -1;
8605 long func_chunk_ret = 0;
8606 int func_chunk_ret_ln = 0;
8607 int scanned_ahead = 0;
8609 char words[20][256];
8610 enum opr_lenmod lmod;
8611 char *sctproto = NULL;
8613 int pending_endp = 0;
8615 int skip_code_end = 0;
8616 int skip_warned = 0;
8629 for (arg = 1; arg < argc; arg++) {
8630 if (IS(argv[arg], "-v"))
8632 else if (IS(argv[arg], "-rf"))
8633 g_allow_regfunc = 1;
8634 else if (IS(argv[arg], "-uc"))
8635 g_allow_user_icall = 1;
8636 else if (IS(argv[arg], "-m"))
8638 else if (IS(argv[arg], "-hdr"))
8639 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8644 if (argc < arg + 3) {
8645 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8646 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8648 " -hdr - header generation mode\n"
8649 " -rf - allow unannotated indirect calls\n"
8650 " -uc - allow ind. calls/refs to __usercall\n"
8651 " -m - allow multiple .text sections\n"
8652 "[rlist] is a file with function names to skip,"
8660 asmfn = argv[arg++];
8661 fasm = fopen(asmfn, "r");
8662 my_assert_not(fasm, NULL);
8664 hdrfn = argv[arg++];
8665 g_fhdr = fopen(hdrfn, "r");
8666 my_assert_not(g_fhdr, NULL);
8669 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8670 my_assert_not(rlist, NULL);
8671 // needs special handling..
8672 rlist[rlist_len++] = "__alloca_probe";
8674 func_chunk_alloc = 32;
8675 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8676 my_assert_not(func_chunks, NULL);
8678 memset(words, 0, sizeof(words));
8680 for (; arg < argc; arg++) {
8683 frlist = fopen(argv[arg], "r");
8684 my_assert_not(frlist, NULL);
8686 while (my_fgets(line, sizeof(line), frlist)) {
8688 if (*p == 0 || *p == ';')
8691 if (IS_START(p, "#if 0")
8692 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
8696 else if (IS_START(p, "#endif"))
8703 p = next_word(words[0], sizeof(words[0]), p);
8704 if (words[0][0] == 0)
8707 if (rlist_len >= rlist_alloc) {
8708 rlist_alloc = rlist_alloc * 2 + 64;
8709 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
8710 my_assert_not(rlist, NULL);
8712 rlist[rlist_len++] = strdup(words[0]);
8720 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
8722 fout = fopen(argv[arg_out], "w");
8723 my_assert_not(fout, NULL);
8726 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
8727 my_assert_not(g_eqs, NULL);
8729 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
8730 g_label_refs[i].i = -1;
8731 g_label_refs[i].next = NULL;
8735 scan_variables(fasm, rlist, rlist_len);
8737 while (my_fgets(line, sizeof(line), fasm))
8746 // get rid of random tabs
8747 for (i = 0; line[i] != 0; i++)
8748 if (line[i] == '\t')
8753 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
8754 goto do_pending_endp; // eww..
8756 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
8758 static const char *attrs[] = {
8767 // parse IDA's attribute-list comment
8768 g_ida_func_attr = 0;
8771 for (; *p != 0; p = sskip(p)) {
8772 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8773 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8774 g_ida_func_attr |= 1 << i;
8775 p += strlen(attrs[i]);
8779 if (i == ARRAY_SIZE(attrs)) {
8780 anote("unparsed IDA attr: %s\n", p);
8783 if (IS(attrs[i], "fpd=")) {
8784 p = next_word(words[0], sizeof(words[0]), p);
8789 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
8791 static const char *attrs[] = {
8796 // parse manual attribute-list comment
8797 g_sct_func_attr = 0;
8800 for (; *p != 0; p = sskip(p)) {
8801 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8802 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8803 g_sct_func_attr |= 1 << i;
8804 p += strlen(attrs[i]);
8811 // clear_sf=start,len (in dwords)
8812 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
8813 &g_stack_clear_len, &j);
8815 // clear_regmask=<mask>
8816 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
8818 anote("unparsed attr value: %s\n", p);
8823 else if (i == ARRAY_SIZE(attrs)) {
8824 anote("unparsed sct attr: %s\n", p);
8829 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8832 next_word(words[0], sizeof(words[0]), p);
8833 if (words[0][0] == 0)
8834 aerr("missing name for func chunk?\n");
8836 if (!scanned_ahead) {
8837 add_func_chunk(fasm, words[0], asmln);
8838 func_chunks_sorted = 0;
8841 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
8843 if (func_chunk_i >= 0) {
8844 if (func_chunk_i < func_chunk_cnt
8845 && IS(func_chunks[func_chunk_i].name, g_func))
8847 // move on to next chunk
8848 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8850 aerr("seek failed for '%s' chunk #%d\n",
8851 g_func, func_chunk_i);
8852 asmln = func_chunks[func_chunk_i].asmln;
8856 if (func_chunk_ret == 0)
8857 aerr("no return from chunk?\n");
8858 fseek(fasm, func_chunk_ret, SEEK_SET);
8859 asmln = func_chunk_ret_ln;
8865 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
8866 func_chunks_used = 1;
8868 if (IS_START(g_func, "sub_")) {
8869 unsigned long addr = strtoul(p, NULL, 16);
8870 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
8871 if (addr > f_addr && !scanned_ahead) {
8872 //anote("scan_ahead caused by '%s', addr %lx\n",
8874 scan_ahead_for_chunks(fasm);
8876 func_chunks_sorted = 0;
8884 for (i = wordc; i < ARRAY_SIZE(words); i++)
8886 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8887 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8888 if (*p == 0 || *p == ';') {
8893 if (*p != 0 && *p != ';')
8894 aerr("too many words\n");
8896 if (skip_code_end) {
8901 // allow asm patches in comments
8903 if (IS_START(p, "; sctpatch:")) {
8905 if (*p == 0 || *p == ';')
8907 goto parse_words; // lame
8909 if (IS_START(p, "; sctproto:")) {
8910 sctproto = strdup(p + 11);
8912 else if (IS_START(p, "; sctend")) {
8917 else if (IS_START(p, "; sctskip_start")) {
8918 if (in_func && !g_skip_func) {
8920 ops[pi].op = OPP_ABORT;
8921 ops[pi].asmln = asmln;
8927 else if (IS_START(p, "; sctskip_end")) {
8935 awarn("wordc == 0?\n");
8939 // don't care about this:
8940 if (words[0][0] == '.'
8941 || IS(words[0], "include")
8942 || IS(words[0], "assume") || IS(words[1], "segment")
8943 || IS(words[0], "align"))
8949 // do delayed endp processing to collect switch jumptables
8951 if (in_func && !g_skip_func && !end && wordc >= 2
8952 && ((words[0][0] == 'd' && words[0][2] == 0)
8953 || (words[1][0] == 'd' && words[1][2] == 0)))
8956 if (words[1][0] == 'd' && words[1][2] == 0) {
8958 if (g_func_pd_cnt >= pd_alloc) {
8959 pd_alloc = pd_alloc * 2 + 16;
8960 g_func_pd = realloc(g_func_pd,
8961 sizeof(g_func_pd[0]) * pd_alloc);
8962 my_assert_not(g_func_pd, NULL);
8964 pd = &g_func_pd[g_func_pd_cnt];
8966 memset(pd, 0, sizeof(*pd));
8967 strcpy(pd->label, words[0]);
8968 pd->type = OPT_CONST;
8969 pd->lmod = lmod_from_directive(words[1]);
8975 anote("skipping alignment byte?\n");
8978 lmod = lmod_from_directive(words[0]);
8979 if (lmod != pd->lmod)
8980 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
8983 if (pd->count_alloc < pd->count + wordc) {
8984 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
8985 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
8986 my_assert_not(pd->d, NULL);
8988 for (; i < wordc; i++) {
8989 if (IS(words[i], "offset")) {
8990 pd->type = OPT_OFFSET;
8993 p = strchr(words[i], ',');
8996 if (pd->type == OPT_OFFSET)
8997 pd->d[pd->count].u.label = strdup(words[i]);
8999 pd->d[pd->count].u.val = parse_number(words[i], 0);
9000 pd->d[pd->count].bt_i = -1;
9006 if (in_func && !g_skip_func) {
9008 gen_hdr(g_func, pi);
9010 gen_func(fout, g_fhdr, g_func, pi);
9015 g_ida_func_attr = 0;
9016 g_sct_func_attr = 0;
9017 g_stack_clear_start = 0;
9018 g_stack_clear_len = 0;
9023 func_chunks_used = 0;
9026 memset(&ops, 0, pi * sizeof(ops[0]));
9031 for (i = 0; i < g_func_pd_cnt; i++) {
9033 if (pd->type == OPT_OFFSET) {
9034 for (j = 0; j < pd->count; j++)
9035 free(pd->d[j].u.label);
9050 if (IS(words[1], "proc")) {
9052 aerr("proc '%s' while in_func '%s'?\n",
9055 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9057 strcpy(g_func, words[0]);
9058 set_label(0, words[0]);
9063 if (IS(words[1], "endp"))
9066 aerr("endp '%s' while not in_func?\n", words[0]);
9067 if (!IS(g_func, words[0]))
9068 aerr("endp '%s' while in_func '%s'?\n",
9071 aerr("endp '%s' while skipping code\n", words[0]);
9073 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9074 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
9080 if (!g_skip_func && func_chunks_used) {
9081 // start processing chunks
9082 struct chunk_item *ci, key = { g_func, 0 };
9084 func_chunk_ret = ftell(fasm);
9085 func_chunk_ret_ln = asmln;
9086 if (!func_chunks_sorted) {
9087 qsort(func_chunks, func_chunk_cnt,
9088 sizeof(func_chunks[0]), cmp_chunks);
9089 func_chunks_sorted = 1;
9091 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9092 sizeof(func_chunks[0]), cmp_chunks);
9094 aerr("'%s' needs chunks, but none found\n", g_func);
9095 func_chunk_i = ci - func_chunks;
9096 for (; func_chunk_i > 0; func_chunk_i--)
9097 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9100 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9102 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9103 asmln = func_chunks[func_chunk_i].asmln;
9111 if (wordc == 2 && IS(words[1], "ends")) {
9115 goto do_pending_endp;
9119 // scan for next text segment
9120 while (my_fgets(line, sizeof(line), fasm)) {
9123 if (*p == 0 || *p == ';')
9126 if (strstr(p, "segment para public 'CODE' use32"))
9133 p = strchr(words[0], ':');
9135 set_label(pi, words[0]);
9139 if (!in_func || g_skip_func || skip_code) {
9140 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9142 anote("skipping from '%s'\n", g_labels[pi]);
9146 g_labels[pi] = NULL;
9150 if (wordc > 1 && IS(words[1], "="))
9153 aerr("unhandled equ, wc=%d\n", wordc);
9154 if (g_eqcnt >= eq_alloc) {
9156 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9157 my_assert_not(g_eqs, NULL);
9160 len = strlen(words[0]);
9161 if (len > sizeof(g_eqs[0].name) - 1)
9162 aerr("equ name too long: %d\n", len);
9163 strcpy(g_eqs[g_eqcnt].name, words[0]);
9165 if (!IS(words[3], "ptr"))
9166 aerr("unhandled equ\n");
9167 if (IS(words[2], "dword"))
9168 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9169 else if (IS(words[2], "word"))
9170 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9171 else if (IS(words[2], "byte"))
9172 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9173 else if (IS(words[2], "qword"))
9174 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9176 aerr("bad lmod: '%s'\n", words[2]);
9178 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9183 if (pi >= ARRAY_SIZE(ops))
9184 aerr("too many ops\n");
9186 parse_op(&ops[pi], words, wordc);
9188 ops[pi].datap = sctproto;
9203 // vim:ts=2:shiftwidth=2:expandtab