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,
2698 // still return ret for something recursive calls could find
2702 static void find_reachable_exits(int i, int opcnt, int magic,
2703 int *exits, int *exit_count)
2705 struct parsed_op *po;
2708 for (; i < opcnt; i++)
2711 if (po->cc_scratch == magic)
2713 po->cc_scratch = magic;
2715 if (po->flags & OPF_TAIL) {
2716 ferr_assert(po, *exit_count < MAX_EXITS);
2717 exits[*exit_count] = i;
2722 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2723 if (po->flags & OPF_RMD)
2726 if (po->btj != NULL) {
2727 for (j = 0; j < po->btj->count; j++) {
2728 check_i(po, po->btj->d[j].bt_i);
2729 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2735 check_i(po, po->bt_i);
2736 if (po->flags & OPF_CJMP)
2737 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2745 // scan for 'reg' pop backwards starting from exits (all paths)
2746 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2748 static int exits[MAX_EXITS];
2749 static int exit_count;
2755 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2757 ferr_assert(&ops[i], exit_count > 0);
2760 for (j = 0; j < exit_count; j++) {
2762 ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2768 if (ops[e].op == OP_CALL && ops[e].pp != NULL
2769 && ops[e].pp->is_noreturn)
2771 // assume stack cleanup was skipped
2780 // scan for one or more pop of push <const>
2781 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2782 int push_i, int is_probe)
2784 struct parsed_op *po;
2785 struct label_ref *lr;
2789 for (; i < opcnt; i++)
2792 if (po->cc_scratch == magic)
2793 return ret; // already checked
2794 po->cc_scratch = magic;
2796 if (po->flags & OPF_JMP) {
2797 if (po->flags & OPF_RMD)
2799 if (po->op == OP_CALL)
2802 if (po->btj != NULL) {
2803 for (j = 0; j < po->btj->count; j++) {
2804 check_i(po, po->btj->d[j].bt_i);
2805 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2813 check_i(po, po->bt_i);
2814 if (po->flags & OPF_CJMP) {
2815 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2826 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2829 if (g_labels[i] != NULL) {
2830 // all refs must be visited
2831 lr = &g_label_refs[i];
2832 for (; lr != NULL; lr = lr->next) {
2834 if (ops[lr->i].cc_scratch != magic)
2837 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2841 if (po->op == OP_POP)
2843 if (po->flags & (OPF_RMD|OPF_DONE))
2847 po->flags |= OPF_DONE;
2848 po->datap = &ops[push_i];
2857 static void scan_for_pop_const(int i, int opcnt, int magic)
2861 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
2863 ops[i].flags |= OPF_RMD | OPF_DONE;
2864 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
2868 // check if all branch targets within a marked path are also marked
2869 // note: the path checked must not be empty or end with a branch
2870 static int check_path_branches(int opcnt, int magic)
2872 struct parsed_op *po;
2875 for (i = 0; i < opcnt; i++) {
2877 if (po->cc_scratch != magic)
2880 if (po->flags & OPF_JMP) {
2881 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
2884 if (po->btj != NULL) {
2885 for (j = 0; j < po->btj->count; j++) {
2886 check_i(po, po->btj->d[j].bt_i);
2887 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
2892 check_i(po, po->bt_i);
2893 if (ops[po->bt_i].cc_scratch != magic)
2895 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
2903 // scan for multiple pushes for given pop
2904 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
2907 int reg = ops[pop_i].operand[0].reg;
2908 struct parsed_op *po;
2909 struct label_ref *lr;
2912 ops[i].cc_scratch = magic;
2916 if (g_labels[i] != NULL) {
2917 lr = &g_label_refs[i];
2918 for (; lr != NULL; lr = lr->next) {
2919 check_i(&ops[i], lr->i);
2920 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
2924 if (i > 0 && LAST_OP(i - 1))
2932 if (ops[i].cc_scratch == magic)
2934 ops[i].cc_scratch = magic;
2937 if (po->op == OP_CALL)
2939 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
2942 if (po->op == OP_PUSH)
2944 if (po->datap != NULL)
2946 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2947 // leave this case for reg save/restore handlers
2951 po->flags |= OPF_PPUSH | OPF_DONE;
2952 po->datap = &ops[pop_i];
2961 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
2963 int magic = i + opcnt * 14;
2966 ret = scan_pushes_for_pop_r(i, magic, i, 1);
2968 ret = check_path_branches(opcnt, magic);
2970 ops[i].flags |= OPF_PPUSH | OPF_DONE;
2971 *regmask_pp |= 1 << ops[i].operand[0].reg;
2972 scan_pushes_for_pop_r(i, magic + 1, i, 0);
2977 static void scan_propagate_df(int i, int opcnt)
2979 struct parsed_op *po = &ops[i];
2982 for (; i < opcnt; i++) {
2984 if (po->flags & OPF_DF)
2985 return; // already resolved
2986 po->flags |= OPF_DF;
2988 if (po->op == OP_CALL)
2989 ferr(po, "call with DF set?\n");
2991 if (po->flags & OPF_JMP) {
2992 if (po->btj != NULL) {
2994 for (j = 0; j < po->btj->count; j++) {
2995 check_i(po, po->btj->d[j].bt_i);
2996 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
3001 if (po->flags & OPF_RMD)
3003 check_i(po, po->bt_i);
3004 if (po->flags & OPF_CJMP)
3005 scan_propagate_df(po->bt_i, opcnt);
3011 if (po->flags & OPF_TAIL)
3014 if (po->op == OP_CLD) {
3015 po->flags |= OPF_RMD | OPF_DONE;
3020 ferr(po, "missing DF clear?\n");
3023 // is operand 'opr' referenced by parsed_op 'po'?
3024 static int is_opr_referenced(const struct parsed_opr *opr,
3025 const struct parsed_op *po)
3029 if (opr->type == OPT_REG) {
3030 mask = po->regmask_dst | po->regmask_src;
3031 if (po->op == OP_CALL)
3032 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3033 if ((1 << opr->reg) & mask)
3039 for (i = 0; i < po->operand_cnt; i++)
3040 if (IS(po->operand[0].name, opr->name))
3046 // is operand 'opr' read by parsed_op 'po'?
3047 static int is_opr_read(const struct parsed_opr *opr,
3048 const struct parsed_op *po)
3050 if (opr->type == OPT_REG) {
3051 if (po->regmask_src & (1 << opr->reg))
3061 // is operand 'opr' modified by parsed_op 'po'?
3062 static int is_opr_modified(const struct parsed_opr *opr,
3063 const struct parsed_op *po)
3067 if (opr->type == OPT_REG) {
3068 if (po->op == OP_CALL) {
3069 mask = po->regmask_dst;
3070 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3071 if (mask & (1 << opr->reg))
3077 if (po->regmask_dst & (1 << opr->reg))
3083 return IS(po->operand[0].name, opr->name);
3086 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3087 static int is_any_opr_modified(const struct parsed_op *po_test,
3088 const struct parsed_op *po, int c_mode)
3093 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3096 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3099 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3102 // in reality, it can wreck any register, but in decompiled C
3103 // version it can only overwrite eax or edx:eax
3104 mask = (1 << xAX) | (1 << xDX);
3108 if (po->op == OP_CALL
3109 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3112 for (i = 0; i < po_test->operand_cnt; i++)
3113 if (IS(po_test->operand[i].name, po->operand[0].name))
3119 // scan for any po_test operand modification in range given
3120 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3123 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3126 for (; i < opcnt; i++) {
3127 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3134 // scan for po_test operand[0] modification in range given
3135 static int scan_for_mod_opr0(struct parsed_op *po_test,
3138 for (; i < opcnt; i++) {
3139 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3146 static int try_resolve_const(int i, const struct parsed_opr *opr,
3147 int magic, unsigned int *val);
3149 static int scan_for_flag_set(int i, int opcnt, int magic,
3150 int *branched, int *setters, int *setter_cnt)
3152 struct label_ref *lr;
3156 if (ops[i].cc_scratch == magic) {
3157 // is this a problem?
3158 //ferr(&ops[i], "%s looped\n", __func__);
3161 ops[i].cc_scratch = magic;
3163 if (g_labels[i] != NULL) {
3166 lr = &g_label_refs[i];
3167 for (; lr->next; lr = lr->next) {
3168 check_i(&ops[i], lr->i);
3169 ret = scan_for_flag_set(lr->i, opcnt, magic,
3170 branched, setters, setter_cnt);
3175 check_i(&ops[i], lr->i);
3176 if (i > 0 && LAST_OP(i - 1)) {
3180 ret = scan_for_flag_set(lr->i, opcnt, magic,
3181 branched, setters, setter_cnt);
3187 if (ops[i].flags & OPF_FLAGS) {
3188 setters[*setter_cnt] = i;
3191 if (ops[i].flags & OPF_REP) {
3192 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3195 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3196 if (ret != 1 || uval == 0) {
3197 // can't treat it as full setter because of ecx=0 case,
3198 // also disallow delayed compare
3207 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3214 // scan back for cdq, if anything modifies edx, fail
3215 static int scan_for_cdq_edx(int i)
3218 if (g_labels[i] != NULL) {
3219 if (g_label_refs[i].next != NULL)
3221 if (i > 0 && LAST_OP(i - 1)) {
3222 i = g_label_refs[i].i;
3229 if (ops[i].op == OP_CDQ)
3232 if (ops[i].regmask_dst & (1 << xDX))
3239 static int scan_for_reg_clear(int i, int reg)
3242 if (g_labels[i] != NULL) {
3243 if (g_label_refs[i].next != NULL)
3245 if (i > 0 && LAST_OP(i - 1)) {
3246 i = g_label_refs[i].i;
3253 if (ops[i].op == OP_XOR
3254 && ops[i].operand[0].lmod == OPLM_DWORD
3255 && ops[i].operand[0].reg == ops[i].operand[1].reg
3256 && ops[i].operand[0].reg == reg)
3259 if (ops[i].regmask_dst & (1 << reg))
3266 static void patch_esp_adjust(struct parsed_op *po, int adj)
3268 ferr_assert(po, po->op == OP_ADD);
3269 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3270 ferr_assert(po, po->operand[1].type == OPT_CONST);
3272 // this is a bit of a hack, but deals with use of
3273 // single adj for multiple calls
3274 po->operand[1].val -= adj;
3275 po->flags |= OPF_RMD;
3276 if (po->operand[1].val == 0)
3277 po->flags |= OPF_DONE;
3278 ferr_assert(po, (int)po->operand[1].val >= 0);
3281 // scan for positive, constant esp adjust
3282 // multipath case is preliminary
3283 static int scan_for_esp_adjust(int i, int opcnt,
3284 int adj_expect, int *adj, int *is_multipath, int do_update)
3286 int adj_expect_unknown = 0;
3287 struct parsed_op *po;
3291 *adj = *is_multipath = 0;
3292 if (adj_expect < 0) {
3293 adj_expect_unknown = 1;
3294 adj_expect = 32 * 4; // enough?
3297 for (; i < opcnt && *adj < adj_expect; i++) {
3298 if (g_labels[i] != NULL)
3302 if (po->flags & OPF_DONE)
3305 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3306 if (po->operand[1].type != OPT_CONST)
3307 ferr(&ops[i], "non-const esp adjust?\n");
3308 *adj += po->operand[1].val;
3310 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3313 patch_esp_adjust(po, adj_expect);
3315 po->flags |= OPF_RMD;
3319 else if (po->op == OP_PUSH) {
3320 //if (first_pop == -1)
3321 // first_pop = -2; // none
3322 *adj -= lmod_bytes(po, po->operand[0].lmod);
3324 else if (po->op == OP_POP) {
3325 if (!(po->flags & OPF_DONE)) {
3326 // seems like msvc only uses 'pop ecx' for stack realignment..
3327 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3329 if (first_pop == -1 && *adj >= 0)
3332 if (do_update && *adj >= 0) {
3333 po->flags |= OPF_RMD;
3335 po->flags |= OPF_DONE | OPF_NOREGS;
3338 *adj += lmod_bytes(po, po->operand[0].lmod);
3339 if (*adj > adj_best)
3342 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3343 if (po->op == OP_JMP && po->btj == NULL) {
3349 if (po->op != OP_CALL)
3351 if (po->operand[0].type != OPT_LABEL)
3353 if (po->pp != NULL && po->pp->is_stdcall)
3355 if (adj_expect_unknown && first_pop >= 0)
3357 // assume it's another cdecl call
3361 if (first_pop >= 0) {
3362 // probably only 'pop ecx' was used
3370 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3372 struct parsed_op *po;
3376 ferr(ops, "%s: followed bad branch?\n", __func__);
3378 for (; i < opcnt; i++) {
3380 if (po->cc_scratch == magic)
3382 po->cc_scratch = magic;
3385 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3386 if (po->btj != NULL) {
3388 for (j = 0; j < po->btj->count; j++)
3389 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3393 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3394 if (!(po->flags & OPF_CJMP))
3397 if (po->flags & OPF_TAIL)
3402 static const struct parsed_proto *try_recover_pp(
3403 struct parsed_op *po, const struct parsed_opr *opr,
3404 int is_call, int *search_instead)
3406 const struct parsed_proto *pp = NULL;
3410 // maybe an arg of g_func?
3411 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3413 char ofs_reg[16] = { 0, };
3414 int arg, arg_s, arg_i;
3421 parse_stack_access(po, opr->name, ofs_reg,
3422 &offset, &stack_ra, NULL, 0);
3423 if (ofs_reg[0] != 0)
3424 ferr(po, "offset reg on arg access?\n");
3425 if (offset <= stack_ra) {
3426 // search who set the stack var instead
3427 if (search_instead != NULL)
3428 *search_instead = 1;
3432 arg_i = (offset - stack_ra - 4) / 4;
3433 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3434 if (g_func_pp->arg[arg].reg != NULL)
3440 if (arg == g_func_pp->argc)
3441 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3443 pp = g_func_pp->arg[arg].pp;
3446 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3447 check_func_pp(po, pp, "icall arg");
3450 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3452 p = strchr(opr->name + 1, '[');
3453 memcpy(buf, opr->name, p - opr->name);
3454 buf[p - opr->name] = 0;
3455 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3457 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3458 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3461 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3464 check_func_pp(po, pp, "reg-fptr ref");
3470 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3471 int magic, const struct parsed_proto **pp_found, int *pp_i,
3474 const struct parsed_proto *pp = NULL;
3475 struct parsed_op *po;
3476 struct label_ref *lr;
3478 ops[i].cc_scratch = magic;
3481 if (g_labels[i] != NULL) {
3482 lr = &g_label_refs[i];
3483 for (; lr != NULL; lr = lr->next) {
3484 check_i(&ops[i], lr->i);
3485 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3487 if (i > 0 && LAST_OP(i - 1))
3495 if (ops[i].cc_scratch == magic)
3497 ops[i].cc_scratch = magic;
3499 if (!(ops[i].flags & OPF_DATA))
3501 if (!is_opr_modified(opr, &ops[i]))
3503 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3504 // most probably trashed by some processing
3509 opr = &ops[i].operand[1];
3510 if (opr->type != OPT_REG)
3514 po = (i >= 0) ? &ops[i] : ops;
3517 // reached the top - can only be an arg-reg
3518 if (opr->type != OPT_REG || g_func_pp == NULL)
3521 for (i = 0; i < g_func_pp->argc; i++) {
3522 if (g_func_pp->arg[i].reg == NULL)
3524 if (IS(opr->name, g_func_pp->arg[i].reg))
3527 if (i == g_func_pp->argc)
3529 pp = g_func_pp->arg[i].pp;
3531 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3532 i + 1, g_func_pp->arg[i].reg);
3533 check_func_pp(po, pp, "icall reg-arg");
3536 pp = try_recover_pp(po, opr, 1, NULL);
3538 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3539 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3540 || (*pp_found)->is_stdcall != pp->is_stdcall
3541 || (*pp_found)->is_fptr != pp->is_fptr
3542 || (*pp_found)->argc != pp->argc
3543 || (*pp_found)->argc_reg != pp->argc_reg
3544 || (*pp_found)->argc_stack != pp->argc_stack)
3546 ferr(po, "icall: parsed_proto mismatch\n");
3556 static void add_label_ref(struct label_ref *lr, int op_i)
3558 struct label_ref *lr_new;
3565 lr_new = calloc(1, sizeof(*lr_new));
3567 lr_new->next = lr->next;
3571 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3573 struct parsed_op *po = &ops[i];
3574 struct parsed_data *pd;
3575 char label[NAMELEN], *p;
3578 p = strchr(po->operand[0].name, '[');
3582 len = p - po->operand[0].name;
3583 strncpy(label, po->operand[0].name, len);
3586 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3587 if (IS(g_func_pd[j].label, label)) {
3593 //ferr(po, "label '%s' not parsed?\n", label);
3596 if (pd->type != OPT_OFFSET)
3597 ferr(po, "label '%s' with non-offset data?\n", label);
3599 // find all labels, link
3600 for (j = 0; j < pd->count; j++) {
3601 for (l = 0; l < opcnt; l++) {
3602 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3603 add_label_ref(&g_label_refs[l], i);
3613 static void clear_labels(int count)
3617 for (i = 0; i < count; i++) {
3618 if (g_labels[i] != NULL) {
3625 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3630 for (i = 0; i < pp->argc; i++) {
3631 if (pp->arg[i].reg != NULL) {
3632 reg = char_array_i(regs_r32,
3633 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3635 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3636 pp->arg[i].reg, pp->name);
3637 regmask |= 1 << reg;
3644 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3649 if (pp->has_retreg) {
3650 for (i = 0; i < pp->argc; i++) {
3651 if (pp->arg[i].type.is_retreg) {
3652 reg = char_array_i(regs_r32,
3653 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3654 ferr_assert(ops, reg >= 0);
3655 regmask |= 1 << reg;
3660 if (strstr(pp->ret_type.name, "int64"))
3661 return regmask | (1 << xAX) | (1 << xDX);
3662 if (IS(pp->ret_type.name, "float")
3663 || IS(pp->ret_type.name, "double"))
3665 return regmask | mxST0;
3667 if (strcasecmp(pp->ret_type.name, "void") == 0)
3670 return regmask | mxAX;
3673 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3675 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3676 && memcmp(po1->operand, po2->operand,
3677 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3680 static void resolve_branches_parse_calls(int opcnt)
3682 static const struct {
3686 unsigned int regmask_src;
3687 unsigned int regmask_dst;
3689 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3690 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3691 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3692 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3694 const struct parsed_proto *pp_c;
3695 struct parsed_proto *pp;
3696 struct parsed_data *pd;
3697 struct parsed_op *po;
3698 const char *tmpname;
3703 for (i = 0; i < opcnt; i++)
3709 if (po->datap != NULL) {
3710 pp = calloc(1, sizeof(*pp));
3711 my_assert_not(pp, NULL);
3713 ret = parse_protostr(po->datap, pp);
3715 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3721 if (po->op == OP_CALL) {
3726 else if (po->operand[0].type == OPT_LABEL)
3728 tmpname = opr_name(po, 0);
3729 if (IS_START(tmpname, "loc_"))
3730 ferr(po, "call to loc_*\n");
3731 if (IS(tmpname, "__alloca_probe"))
3734 // convert some calls to pseudo-ops
3735 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3736 if (!IS(tmpname, pseudo_ops[l].name))
3739 po->op = pseudo_ops[l].op;
3740 po->operand_cnt = 0;
3741 po->regmask_src = pseudo_ops[l].regmask_src;
3742 po->regmask_dst = pseudo_ops[l].regmask_dst;
3743 po->flags = pseudo_ops[l].flags;
3744 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3747 if (l < ARRAY_SIZE(pseudo_ops))
3750 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3751 if (!g_header_mode && pp_c == NULL)
3752 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3755 pp = proto_clone(pp_c);
3756 my_assert_not(pp, NULL);
3762 check_func_pp(po, pp, "fptr var call");
3763 if (pp->is_noreturn) {
3764 po->flags |= OPF_TAIL;
3765 po->flags &= ~OPF_ATAIL; // most likely...
3772 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3775 if (po->operand[0].type == OPT_REGMEM) {
3776 pd = try_resolve_jumptab(i, opcnt);
3784 for (l = 0; l < opcnt; l++) {
3785 if (g_labels[l] != NULL
3786 && IS(po->operand[0].name, g_labels[l]))
3788 if (l == i + 1 && po->op == OP_JMP) {
3789 // yet another alignment type..
3790 po->flags |= OPF_RMD|OPF_DONE;
3793 add_label_ref(&g_label_refs[l], i);
3799 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3802 if (po->operand[0].type == OPT_LABEL)
3806 ferr(po, "unhandled branch\n");
3810 po->flags |= OPF_TAIL;
3811 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3812 if (prev_op == OP_POP)
3813 po->flags |= OPF_ATAIL;
3814 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3815 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3817 po->flags |= OPF_ATAIL;
3823 static void scan_prologue_epilogue(int opcnt)
3825 int ecx_push = 0, esp_sub = 0, pusha = 0;
3826 int sandard_epilogue;
3830 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
3831 && ops[1].op == OP_MOV
3832 && IS(opr_name(&ops[1], 0), "ebp")
3833 && IS(opr_name(&ops[1], 1), "esp"))
3836 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3837 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3840 if (ops[i].op == OP_PUSHA) {
3841 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3846 if (ops[i].op == OP_SUB && IS(opr_name(&ops[i], 0), "esp")) {
3847 g_stack_fsz = opr_const(&ops[i], 1);
3848 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3852 // another way msvc builds stack frame..
3853 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3855 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3859 // and another way..
3860 if (i == 2 && ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3861 && ops[i].operand[1].type == OPT_CONST
3862 && ops[i + 1].op == OP_CALL
3863 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3865 g_stack_fsz += ops[i].operand[1].val;
3866 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3868 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3875 for (; i < opcnt; i++)
3876 if (ops[i].flags & OPF_TAIL)
3879 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
3880 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
3886 sandard_epilogue = 0;
3887 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
3889 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3890 // the standard epilogue is sometimes even used without a sf
3891 if (ops[j - 1].op == OP_MOV
3892 && IS(opr_name(&ops[j - 1], 0), "esp")
3893 && IS(opr_name(&ops[j - 1], 1), "ebp"))
3894 sandard_epilogue = 1;
3896 else if (ops[j].op == OP_LEAVE)
3898 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3899 sandard_epilogue = 1;
3901 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
3902 && ops[i].pp->is_noreturn)
3904 // on noreturn, msvc sometimes cleans stack, sometimes not
3909 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3910 ferr(&ops[j], "'pop ebp' expected\n");
3912 if (g_stack_fsz != 0 || sandard_epilogue) {
3913 if (ops[j].op == OP_LEAVE)
3915 else if (sandard_epilogue) // mov esp, ebp
3917 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3920 else if (!(g_ida_func_attr & IDAFA_NORETURN))
3922 ferr(&ops[j], "esp restore expected\n");
3925 if (ecx_push && j >= 0 && ops[j].op == OP_POP
3926 && IS(opr_name(&ops[j], 0), "ecx"))
3928 ferr(&ops[j], "unexpected ecx pop\n");
3933 if (ops[j].op == OP_POPA)
3934 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3936 ferr(&ops[j], "popa expected\n");
3941 } while (i < opcnt);
3944 ferr(ops, "missing ebp epilogue\n");
3950 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
3951 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3957 for (; i < opcnt; i++) {
3958 if (ops[i].op == OP_PUSH || (ops[i].flags & (OPF_JMP|OPF_TAIL)))
3960 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
3961 && ops[i].operand[1].type == OPT_CONST)
3963 g_stack_fsz = ops[i].operand[1].val;
3964 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3969 else if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
3970 && ops[i].operand[1].type == OPT_CONST
3971 && ops[i + 1].op == OP_CALL
3972 && IS(opr_name(&ops[i + 1], 0), "__alloca_probe"))
3974 g_stack_fsz += ops[i].operand[1].val;
3975 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3977 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
3984 if (ecx_push && !esp_sub) {
3985 // could actually be args for a call..
3986 for (; i < opcnt; i++)
3987 if (ops[i].op != OP_PUSH)
3990 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
3991 const struct parsed_proto *pp;
3992 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
3993 j = pp ? pp->argc_stack : 0;
3994 while (i > 0 && j > 0) {
3996 if (ops[i].op == OP_PUSH) {
3997 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4002 ferr(&ops[i], "unhandled prologue\n");
4005 i = g_stack_fsz = ecx_push = 0;
4006 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4007 if (!(ops[i].flags & OPF_RMD))
4017 if (ecx_push || esp_sub)
4022 for (; i < opcnt; i++)
4023 if (ops[i].flags & OPF_TAIL)
4027 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4028 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4035 for (l = 0; l < ecx_push; l++) {
4036 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4038 else if (ops[j].op == OP_ADD
4039 && IS(opr_name(&ops[j], 0), "esp")
4040 && ops[j].operand[1].type == OPT_CONST)
4043 l += ops[j].operand[1].val / 4 - 1;
4048 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4051 if (l != ecx_push) {
4052 if (i < opcnt && ops[i].op == OP_CALL
4053 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4055 // noreturn tailcall with no epilogue
4060 ferr(&ops[j], "epilogue scan failed\n");
4067 if (ops[j].op != OP_ADD
4068 || !IS(opr_name(&ops[j], 0), "esp")
4069 || ops[j].operand[1].type != OPT_CONST
4070 || ops[j].operand[1].val != g_stack_fsz)
4072 if (i < opcnt && ops[i].op == OP_CALL
4073 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4075 // noreturn tailcall with no epilogue
4080 ferr(&ops[j], "'add esp' expected\n");
4083 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4084 ops[j].operand[1].val = 0; // hack for stack arg scanner
4089 } while (i < opcnt);
4092 ferr(ops, "missing esp epilogue\n");
4096 // find an instruction that changed opr before i op
4097 // *op_i must be set to -1 by the caller
4098 // *is_caller is set to 1 if one source is determined to be g_func arg
4099 // returns 1 if found, *op_i is then set to origin
4100 // returns -1 if multiple origins are found
4101 static int resolve_origin(int i, const struct parsed_opr *opr,
4102 int magic, int *op_i, int *is_caller)
4104 struct label_ref *lr;
4108 if (g_labels[i] != NULL) {
4109 lr = &g_label_refs[i];
4110 for (; lr != NULL; lr = lr->next) {
4111 check_i(&ops[i], lr->i);
4112 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4114 if (i > 0 && LAST_OP(i - 1))
4120 if (is_caller != NULL)
4125 if (ops[i].cc_scratch == magic)
4127 ops[i].cc_scratch = magic;
4129 if (!(ops[i].flags & OPF_DATA))
4131 if (!is_opr_modified(opr, &ops[i]))
4135 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4146 // find an instruction that previously referenced opr
4147 // if multiple results are found - fail
4148 // *op_i must be set to -1 by the caller
4149 // returns 1 if found, *op_i is then set to referencer insn
4150 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4151 int magic, int *op_i)
4153 struct label_ref *lr;
4157 if (g_labels[i] != NULL) {
4158 lr = &g_label_refs[i];
4159 for (; lr != NULL; lr = lr->next) {
4160 check_i(&ops[i], lr->i);
4161 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4163 if (i > 0 && LAST_OP(i - 1))
4171 if (ops[i].cc_scratch == magic)
4173 ops[i].cc_scratch = magic;
4175 if (!is_opr_referenced(opr, &ops[i]))
4186 // adjust datap of all reachable 'op' insns when moving back
4187 // returns 1 if at least 1 op was found
4188 // returns -1 if path without an op was found
4189 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4191 struct label_ref *lr;
4194 if (ops[i].cc_scratch == magic)
4196 ops[i].cc_scratch = magic;
4199 if (g_labels[i] != NULL) {
4200 lr = &g_label_refs[i];
4201 for (; lr != NULL; lr = lr->next) {
4202 check_i(&ops[i], lr->i);
4203 ret |= adjust_prev_op(lr->i, op, magic, datap);
4205 if (i > 0 && LAST_OP(i - 1))
4213 if (ops[i].cc_scratch == magic)
4215 ops[i].cc_scratch = magic;
4217 if (ops[i].op != op)
4220 ops[i].datap = datap;
4225 // find next instruction that reads opr
4226 // *op_i must be set to -1 by the caller
4227 // on return, *op_i is set to first referencer insn
4228 // returns 1 if exactly 1 referencer is found
4229 static int find_next_read(int i, int opcnt,
4230 const struct parsed_opr *opr, int magic, int *op_i)
4232 struct parsed_op *po;
4235 for (; i < opcnt; i++)
4237 if (ops[i].cc_scratch == magic)
4239 ops[i].cc_scratch = magic;
4242 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4243 if (po->btj != NULL) {
4245 for (j = 0; j < po->btj->count; j++) {
4246 check_i(po, po->btj->d[j].bt_i);
4247 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4253 if (po->flags & OPF_RMD)
4255 check_i(po, po->bt_i);
4256 if (po->flags & OPF_CJMP) {
4257 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4266 if (!is_opr_read(opr, po)) {
4268 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4269 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4271 full_opr = po->operand[0].lmod >= opr->lmod;
4273 if (is_opr_modified(opr, po) && full_opr) {
4277 if (po->flags & OPF_TAIL)
4292 // find next instruction that reads opr
4293 // *op_i must be set to -1 by the caller
4294 // on return, *op_i is set to first flag user insn
4295 // returns 1 if exactly 1 flag user is found
4296 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4298 struct parsed_op *po;
4301 for (; i < opcnt; i++)
4303 if (ops[i].cc_scratch == magic)
4305 ops[i].cc_scratch = magic;
4308 if (po->op == OP_CALL)
4310 if (po->flags & OPF_JMP) {
4311 if (po->btj != NULL) {
4313 for (j = 0; j < po->btj->count; j++) {
4314 check_i(po, po->btj->d[j].bt_i);
4315 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4321 if (po->flags & OPF_RMD)
4323 check_i(po, po->bt_i);
4324 if (po->flags & OPF_CJMP)
4331 if (!(po->flags & OPF_CC)) {
4332 if (po->flags & OPF_FLAGS)
4335 if (po->flags & OPF_TAIL)
4351 static int try_resolve_const(int i, const struct parsed_opr *opr,
4352 int magic, unsigned int *val)
4357 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4360 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4363 *val = ops[i].operand[1].val;
4370 static int resolve_used_bits(int i, int opcnt, int reg,
4371 int *mask, int *is_z_check)
4373 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4377 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4381 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4383 fnote(&ops[j], "(first read)\n");
4384 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4387 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4388 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4390 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4391 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4393 *mask = ops[j].operand[1].val;
4394 if (ops[j].operand[0].lmod == OPLM_BYTE
4395 && ops[j].operand[0].name[1] == 'h')
4399 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4402 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4404 *is_z_check = ops[k].pfo == PFO_Z;
4409 static const struct parsed_proto *resolve_deref(int i, int magic,
4410 struct parsed_opr *opr, int level)
4412 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4413 const struct parsed_proto *pp = NULL;
4414 int from_caller = 0;
4423 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4424 if (ret != 2 || len != strlen(opr->name)) {
4425 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4426 if (ret != 1 || len != strlen(opr->name))
4430 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4435 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4439 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4440 && strlen(ops[j].operand[1].name) == 3
4441 && ops[j].operand[0].lmod == OPLM_DWORD
4442 && ops[j].pp == NULL // no hint
4445 // allow one simple dereference (com/directx)
4446 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4447 ops[j].operand[1].name);
4451 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4456 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4459 if (ops[j].pp != NULL) {
4463 else if (ops[j].operand[1].type == OPT_REGMEM) {
4464 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4466 // maybe structure ptr in structure
4467 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4470 else if (ops[j].operand[1].type == OPT_LABEL)
4471 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4472 else if (ops[j].operand[1].type == OPT_REG) {
4475 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4477 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4478 for (k = 0; k < g_func_pp->argc; k++) {
4479 if (g_func_pp->arg[k].reg == NULL)
4481 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4482 pp = g_func_pp->arg[k].pp;
4491 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4493 ferr(&ops[j], "expected struct, got '%s %s'\n",
4494 pp->type.name, pp->name);
4498 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4501 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4502 int *pp_i, int *multi_src)
4504 const struct parsed_proto *pp = NULL;
4505 int search_advice = 0;
4510 switch (ops[i].operand[0].type) {
4512 // try to resolve struct member calls
4513 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4519 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4525 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4533 static struct parsed_proto *process_call_early(int i, int opcnt,
4536 struct parsed_op *po = &ops[i];
4537 struct parsed_proto *pp;
4543 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4547 // look for and make use of esp adjust
4549 if (!pp->is_stdcall && pp->argc_stack > 0)
4550 ret = scan_for_esp_adjust(i + 1, opcnt,
4551 pp->argc_stack * 4, &adj, &multipath, 0);
4553 if (pp->argc_stack > adj / 4)
4557 if (ops[ret].op == OP_POP) {
4558 for (j = 1; j < adj / 4; j++) {
4559 if (ops[ret + j].op != OP_POP
4560 || ops[ret + j].operand[0].reg != xCX)
4572 static struct parsed_proto *process_call(int i, int opcnt)
4574 struct parsed_op *po = &ops[i];
4575 const struct parsed_proto *pp_c;
4576 struct parsed_proto *pp;
4577 const char *tmpname;
4578 int call_i = -1, ref_i = -1;
4579 int adj = 0, multipath = 0;
4582 tmpname = opr_name(po, 0);
4587 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4589 if (!pp_c->is_func && !pp_c->is_fptr)
4590 ferr(po, "call to non-func: %s\n", pp_c->name);
4591 pp = proto_clone(pp_c);
4592 my_assert_not(pp, NULL);
4594 // not resolved just to single func
4597 switch (po->operand[0].type) {
4599 // we resolved this call and no longer need the register
4600 po->regmask_src &= ~(1 << po->operand[0].reg);
4602 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4603 && ops[call_i].operand[1].type == OPT_LABEL)
4605 // no other source users?
4606 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4608 if (ret == 1 && call_i == ref_i) {
4609 // and nothing uses it after us?
4611 find_next_read(i + 1, opcnt, &po->operand[0],
4612 i + opcnt * 11, &ref_i);
4614 // then also don't need the source mov
4615 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4627 pp = calloc(1, sizeof(*pp));
4628 my_assert_not(pp, NULL);
4631 ret = scan_for_esp_adjust(i + 1, opcnt,
4632 -1, &adj, &multipath, 0);
4633 if (ret < 0 || adj < 0) {
4634 if (!g_allow_regfunc)
4635 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4636 pp->is_unresolved = 1;
4640 if (adj > ARRAY_SIZE(pp->arg))
4641 ferr(po, "esp adjust too large: %d\n", adj);
4642 pp->ret_type.name = strdup("int");
4643 pp->argc = pp->argc_stack = adj;
4644 for (arg = 0; arg < pp->argc; arg++)
4645 pp->arg[arg].type.name = strdup("int");
4650 // look for and make use of esp adjust
4653 if (!pp->is_stdcall && pp->argc_stack > 0) {
4654 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4655 ret = scan_for_esp_adjust(i + 1, opcnt,
4656 adj_expect, &adj, &multipath, 0);
4659 if (pp->is_vararg) {
4660 if (adj / 4 < pp->argc_stack) {
4661 fnote(po, "(this call)\n");
4662 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4663 adj, pp->argc_stack * 4);
4665 // modify pp to make it have varargs as normal args
4667 pp->argc += adj / 4 - pp->argc_stack;
4668 for (; arg < pp->argc; arg++) {
4669 pp->arg[arg].type.name = strdup("int");
4672 if (pp->argc > ARRAY_SIZE(pp->arg))
4673 ferr(po, "too many args for '%s'\n", tmpname);
4675 if (pp->argc_stack > adj / 4) {
4676 if (pp->is_noreturn)
4677 // assume no stack adjust was emited
4679 fnote(po, "(this call)\n");
4680 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4681 tmpname, pp->argc_stack * 4, adj);
4684 scan_for_esp_adjust(i + 1, opcnt,
4685 pp->argc_stack * 4, &adj, &multipath, 1);
4687 else if (pp->is_vararg)
4688 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4695 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
4698 struct parsed_op *po;
4704 for (base_arg = 0; base_arg < pp->argc; base_arg++)
4705 if (pp->arg[base_arg].reg == NULL)
4708 for (j = i; j > 0; )
4710 ferr_assert(&ops[j], g_labels[j] == NULL);
4714 ferr_assert(po, po->op != OP_PUSH);
4715 if (po->op == OP_FST)
4717 if (po->operand[0].type != OPT_REGMEM)
4719 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
4722 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3))
4723 ferr(po, "bad offset %d (%d args)\n", offset, pp->argc_stack);
4725 arg = base_arg + offset / 4;
4727 po->p_argnum = arg + 1;
4728 ferr_assert(po, pp->arg[arg].datap == NULL);
4729 pp->arg[arg].datap = po;
4730 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
4731 if (regmask_ffca != NULL)
4732 *regmask_ffca |= 1 << arg;
4734 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4735 && po->operand[1].type == OPT_CONST)
4737 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4742 for (arg = base_arg; arg < pp->argc; arg++) {
4743 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
4744 po = pp->arg[arg].datap;
4746 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
4747 if (po->operand[0].lmod == OPLM_QWORD)
4754 static int collect_call_args_early(int i, struct parsed_proto *pp,
4755 int *regmask, int *regmask_ffca)
4757 struct parsed_op *po;
4761 for (arg = 0; arg < pp->argc; arg++)
4762 if (pp->arg[arg].reg == NULL)
4765 // first see if it can be easily done
4766 for (j = i; j > 0 && arg < pp->argc; )
4768 if (g_labels[j] != NULL)
4773 if (po->op == OP_CALL)
4775 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
4777 else if (po->op == OP_POP)
4779 else if (po->flags & OPF_CJMP)
4781 else if (po->op == OP_PUSH) {
4782 if (po->flags & (OPF_FARG|OPF_FARGNR))
4784 if (!g_header_mode) {
4785 ret = scan_for_mod(po, j + 1, i, 1);
4790 if (pp->arg[arg].type.is_va_list)
4794 for (arg++; arg < pp->argc; arg++)
4795 if (pp->arg[arg].reg == NULL)
4798 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4799 && po->operand[1].type == OPT_CONST)
4801 if (po->flags & (OPF_RMD|OPF_DONE))
4803 if (po->operand[1].val != pp->argc_stack * 4)
4804 ferr(po, "unexpected esp adjust: %d\n",
4805 po->operand[1].val * 4);
4806 ferr_assert(po, pp->argc - arg == pp->argc_stack);
4807 return collect_call_args_no_push(i, pp, regmask_ffca);
4815 for (arg = 0; arg < pp->argc; arg++)
4816 if (pp->arg[arg].reg == NULL)
4819 for (j = i; j > 0 && arg < pp->argc; )
4823 if (ops[j].op == OP_PUSH)
4825 ops[j].p_argnext = -1;
4826 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4827 pp->arg[arg].datap = &ops[j];
4829 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
4830 *regmask |= 1 << ops[j].operand[0].reg;
4832 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4833 ops[j].flags &= ~OPF_RSAVE;
4836 for (arg++; arg < pp->argc; arg++)
4837 if (pp->arg[arg].reg == NULL)
4845 static int sync_argnum(struct parsed_op *po, int argnum)
4847 struct parsed_op *po_tmp;
4849 // see if other branches don't have higher argnum
4850 for (po_tmp = po; po_tmp != NULL; ) {
4851 if (argnum < po_tmp->p_argnum)
4852 argnum = po_tmp->p_argnum;
4853 // note: p_argnext is active on current collect_call_args only
4854 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4857 // make all argnums consistent
4858 for (po_tmp = po; po_tmp != NULL; ) {
4859 if (po_tmp->p_argnum != 0)
4860 po_tmp->p_argnum = argnum;
4861 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4867 static int collect_call_args_r(struct parsed_op *po, int i,
4868 struct parsed_proto *pp, int *regmask, int *arg_grp,
4869 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
4871 struct parsed_proto *pp_tmp;
4872 struct parsed_op *po_tmp;
4873 struct label_ref *lr;
4874 int need_to_save_current;
4875 int arg_grp_current = 0;
4876 int save_args_seen = 0;
4883 ferr(po, "dead label encountered\n");
4887 for (; arg < pp->argc; arg++, argnum++)
4888 if (pp->arg[arg].reg == NULL)
4890 magic = (magic & 0xffffff) | (arg << 24);
4892 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4894 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4895 if (ops[j].cc_scratch != magic) {
4896 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4900 // ok: have already been here
4903 ops[j].cc_scratch = magic;
4905 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4906 lr = &g_label_refs[j];
4907 if (lr->next != NULL)
4909 for (; lr->next; lr = lr->next) {
4910 check_i(&ops[j], lr->i);
4911 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4913 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4914 arg, argnum, magic, need_op_saving, may_reuse);
4919 check_i(&ops[j], lr->i);
4920 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4922 if (j > 0 && LAST_OP(j - 1)) {
4923 // follow last branch in reverse
4928 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4929 arg, argnum, magic, need_op_saving, may_reuse);
4935 if (ops[j].op == OP_CALL)
4937 if (pp->is_unresolved)
4942 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
4943 arg, pp->argc, ops[j].operand[0].name);
4944 if (may_reuse && pp_tmp->argc_stack > 0)
4945 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4946 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4948 // esp adjust of 0 means we collected it before
4949 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4950 && (ops[j].operand[1].type != OPT_CONST
4951 || ops[j].operand[1].val != 0))
4953 if (pp->is_unresolved)
4956 fnote(po, "(this call)\n");
4957 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4958 arg, pp->argc, ops[j].operand[1].val);
4960 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4962 if (pp->is_unresolved)
4965 fnote(po, "(this call)\n");
4966 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4968 else if (ops[j].flags & OPF_CJMP)
4970 if (pp->is_unresolved)
4975 else if (ops[j].op == OP_PUSH
4976 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4978 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4981 ops[j].p_argnext = -1;
4982 po_tmp = pp->arg[arg].datap;
4984 ops[j].p_argnext = po_tmp - ops;
4985 pp->arg[arg].datap = &ops[j];
4987 argnum = sync_argnum(&ops[j], argnum);
4989 need_to_save_current = 0;
4991 if (ops[j].operand[0].type == OPT_REG)
4992 reg = ops[j].operand[0].reg;
4994 if (!need_op_saving) {
4995 ret = scan_for_mod(&ops[j], j + 1, i, 1);
4996 need_to_save_current = (ret >= 0);
4998 if (need_op_saving || need_to_save_current) {
4999 // mark this arg as one that needs operand saving
5000 pp->arg[arg].is_saved = 1;
5002 if (save_args_seen & (1 << (argnum - 1))) {
5005 if (arg_grp_current >= MAX_ARG_GRP)
5006 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5010 else if (ops[j].p_argnum == 0)
5011 ops[j].flags |= OPF_RMD;
5013 // some PUSHes are reused by different calls on other branches,
5014 // but that can't happen if we didn't branch, so they
5015 // can be removed from future searches (handles nested calls)
5017 ops[j].flags |= OPF_FARGNR;
5019 ops[j].flags |= OPF_FARG;
5020 ops[j].flags &= ~OPF_RSAVE;
5022 // check for __VALIST
5023 if (!pp->is_unresolved && g_func_pp != NULL
5024 && pp->arg[arg].type.is_va_list)
5027 ret = resolve_origin(j, &ops[j].operand[0],
5028 magic + 1, &k, NULL);
5029 if (ret == 1 && k >= 0)
5031 if (ops[k].op == OP_LEA) {
5032 if (!g_func_pp->is_vararg)
5033 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5036 snprintf(buf, sizeof(buf), "arg_%X",
5037 g_func_pp->argc_stack * 4);
5038 if (strstr(ops[k].operand[1].name, buf)
5039 || strstr(ops[k].operand[1].name, "arglist"))
5041 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5042 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5043 pp->arg[arg].is_saved = 0;
5047 ferr(&ops[k], "va_list arg detection failed\n");
5049 // check for va_list from g_func_pp arg too
5050 else if (ops[k].op == OP_MOV
5051 && is_stack_access(&ops[k], &ops[k].operand[1]))
5053 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5054 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5056 ops[k].flags |= OPF_RMD | OPF_DONE;
5057 ops[j].flags |= OPF_RMD;
5058 ops[j].p_argpass = ret + 1;
5059 pp->arg[arg].is_saved = 0;
5066 if (pp->arg[arg].is_saved) {
5067 ops[j].flags &= ~OPF_RMD;
5068 ops[j].p_argnum = argnum;
5071 // tracking reg usage
5073 *regmask |= 1 << reg;
5077 if (!pp->is_unresolved) {
5079 for (; arg < pp->argc; arg++, argnum++)
5080 if (pp->arg[arg].reg == NULL)
5083 magic = (magic & 0xffffff) | (arg << 24);
5086 if (ops[j].p_arggrp > arg_grp_current) {
5088 arg_grp_current = ops[j].p_arggrp;
5090 if (ops[j].p_argnum > 0)
5091 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5094 if (arg < pp->argc) {
5095 ferr(po, "arg collect failed for '%s': %d/%d\n",
5096 pp->name, arg, pp->argc);
5100 if (arg_grp_current > *arg_grp)
5101 *arg_grp = arg_grp_current;
5106 static int collect_call_args(struct parsed_op *po, int i,
5107 struct parsed_proto *pp, int *regmask, int magic)
5109 // arg group is for cases when pushes for
5110 // multiple funcs are going on
5111 struct parsed_op *po_tmp;
5116 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5122 // propagate arg_grp
5123 for (a = 0; a < pp->argc; a++) {
5124 if (pp->arg[a].reg != NULL)
5127 po_tmp = pp->arg[a].datap;
5128 while (po_tmp != NULL) {
5129 po_tmp->p_arggrp = arg_grp;
5130 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5135 if (pp->is_unresolved) {
5137 pp->argc_stack += ret;
5138 for (a = 0; a < pp->argc; a++)
5139 if (pp->arg[a].type.name == NULL)
5140 pp->arg[a].type.name = strdup("int");
5146 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5147 int regmask_now, int *regmask,
5148 int regmask_save_now, int *regmask_save,
5149 int *regmask_init, int regmask_arg)
5151 struct parsed_op *po;
5159 for (; i < opcnt; i++)
5162 if (cbits[i >> 3] & (1 << (i & 7)))
5164 cbits[i >> 3] |= (1 << (i & 7));
5166 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5167 if (po->flags & (OPF_RMD|OPF_DONE))
5169 if (po->btj != NULL) {
5170 for (j = 0; j < po->btj->count; j++) {
5171 check_i(po, po->btj->d[j].bt_i);
5172 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5173 regmask_now, regmask, regmask_save_now, regmask_save,
5174 regmask_init, regmask_arg);
5179 check_i(po, po->bt_i);
5180 if (po->flags & OPF_CJMP)
5181 reg_use_pass(po->bt_i, opcnt, cbits,
5182 regmask_now, regmask, regmask_save_now, regmask_save,
5183 regmask_init, regmask_arg);
5189 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5190 && !g_func_pp->is_userstack
5191 && po->operand[0].type == OPT_REG)
5193 reg = po->operand[0].reg;
5194 ferr_assert(po, reg >= 0);
5197 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5198 if (regmask_now & (1 << reg)) {
5199 already_saved = regmask_save_now & (1 << reg);
5200 flags_set = OPF_RSAVE | OPF_DONE;
5203 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5205 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5206 reg, 0, 0, flags_set);
5209 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5211 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5216 ferr_assert(po, !already_saved);
5217 po->flags |= flags_set;
5219 if (regmask_now & (1 << reg)) {
5220 regmask_save_now |= (1 << reg);
5221 *regmask_save |= regmask_save_now;
5226 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5227 reg = po->operand[0].reg;
5228 ferr_assert(po, reg >= 0);
5230 if (regmask_save_now & (1 << reg))
5231 regmask_save_now &= ~(1 << reg);
5233 regmask_now &= ~(1 << reg);
5236 else if (po->op == OP_CALL) {
5237 if ((po->regmask_dst & (1 << xAX))
5238 && !(po->regmask_dst & (1 << xDX)))
5240 if (po->flags & OPF_TAIL)
5241 // don't need eax, will do "return f();" or "f(); return;"
5242 po->regmask_dst &= ~(1 << xAX);
5244 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5246 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5249 po->regmask_dst &= ~(1 << xAX);
5253 // not "full stack" mode and have something in stack
5254 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5255 ferr(po, "float stack is not empty on func call\n");
5258 if (po->flags & OPF_NOREGS)
5261 // if incomplete register is used, clear it on init to avoid
5262 // later use of uninitialized upper part in some situations
5263 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5264 && po->operand[0].lmod != OPLM_DWORD)
5266 reg = po->operand[0].reg;
5267 ferr_assert(po, reg >= 0);
5269 if (!(regmask_now & (1 << reg)))
5270 *regmask_init |= 1 << reg;
5273 regmask_op = po->regmask_src | po->regmask_dst;
5275 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5276 regmask_new &= ~(1 << xSP);
5277 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5278 regmask_new &= ~(1 << xBP);
5280 if (regmask_new != 0)
5281 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5283 if (regmask_op & (1 << xBP)) {
5284 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5285 if (po->regmask_dst & (1 << xBP))
5286 // compiler decided to drop bp frame and use ebp as scratch
5287 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5289 regmask_op &= ~(1 << xBP);
5293 if (po->flags & OPF_FPUSH) {
5294 if (regmask_now & mxST1)
5295 regmask_now |= mxSTa; // switch to "full stack" mode
5296 if (regmask_now & mxSTa)
5297 po->flags |= OPF_FSHIFT;
5298 if (!(regmask_now & mxST7_2)) {
5300 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5304 regmask_now |= regmask_op;
5305 *regmask |= regmask_now;
5308 if (po->flags & OPF_FPOP) {
5309 if ((regmask_now & mxSTa) == 0)
5310 ferr(po, "float pop on empty stack?\n");
5311 if (regmask_now & (mxST7_2 | mxST1))
5312 po->flags |= OPF_FSHIFT;
5313 if (!(regmask_now & mxST7_2)) {
5315 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5319 if (po->flags & OPF_TAIL) {
5320 if (!(regmask_now & mxST7_2)) {
5321 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5322 if (!(regmask_now & mxST0))
5323 ferr(po, "no st0 on float return, mask: %x\n",
5326 else if (regmask_now & mxST1_0)
5327 ferr(po, "float regs on tail: %x\n", regmask_now);
5330 // there is support for "conditional tailcall", sort of
5331 if (!(po->flags & OPF_CC))
5337 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5341 for (i = 0; i < pp->argc; i++)
5342 if (pp->arg[i].reg == NULL)
5346 memmove(&pp->arg[i + 1], &pp->arg[i],
5347 sizeof(pp->arg[0]) * pp->argc_stack);
5348 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5349 pp->arg[i].reg = strdup(reg);
5350 pp->arg[i].type.name = strdup("int");
5355 static void output_std_flags(FILE *fout, struct parsed_op *po,
5356 int *pfomask, const char *dst_opr_text)
5358 if (*pfomask & (1 << PFO_Z)) {
5359 fprintf(fout, "\n cond_z = (%s%s == 0);",
5360 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5361 *pfomask &= ~(1 << PFO_Z);
5363 if (*pfomask & (1 << PFO_S)) {
5364 fprintf(fout, "\n cond_s = (%s%s < 0);",
5365 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5366 *pfomask &= ~(1 << PFO_S);
5371 OPP_FORCE_NORETURN = (1 << 0),
5372 OPP_SIMPLE_ARGS = (1 << 1),
5373 OPP_ALIGN = (1 << 2),
5376 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5379 const char *cconv = "";
5381 if (pp->is_fastcall)
5382 cconv = "__fastcall ";
5383 else if (pp->is_stdcall && pp->argc_reg == 0)
5384 cconv = "__stdcall ";
5386 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5388 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5389 fprintf(fout, "noreturn ");
5392 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5397 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5401 output_pp_attrs(fout, pp, flags);
5404 fprintf(fout, "%s", pp->name);
5409 for (i = 0; i < pp->argc; i++) {
5411 fprintf(fout, ", ");
5412 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5413 && !(flags & OPP_SIMPLE_ARGS))
5416 output_pp(fout, pp->arg[i].pp, 0);
5418 else if (pp->arg[i].type.is_retreg) {
5419 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5422 fprintf(fout, "%s", pp->arg[i].type.name);
5424 fprintf(fout, " a%d", i + 1);
5427 if (pp->is_vararg) {
5429 fprintf(fout, ", ");
5430 fprintf(fout, "...");
5435 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5441 snprintf(buf1, sizeof(buf1), "%d", grp);
5442 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5447 static void gen_x_cleanup(int opcnt);
5449 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5451 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5452 struct parsed_opr *last_arith_dst = NULL;
5453 char buf1[256], buf2[256], buf3[256], cast[64];
5454 struct parsed_proto *pp, *pp_tmp;
5455 struct parsed_data *pd;
5456 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5457 unsigned char cbits[MAX_OPS / 8];
5458 const char *float_type;
5459 const char *float_st0;
5460 const char *float_st1;
5461 int need_float_stack = 0;
5462 int need_float_sw = 0; // status word
5463 int need_tmp_var = 0;
5467 int label_pending = 0;
5468 int need_double = 0;
5469 int regmask_save = 0; // used regs saved/restored in this func
5470 int regmask_arg; // regs from this function args (fastcall, etc)
5471 int regmask_ret; // regs needed on ret
5472 int regmask_now; // temp
5473 int regmask_init = 0; // regs that need zero initialization
5474 int regmask_pp = 0; // regs used in complex push-pop graph
5475 int regmask_ffca = 0; // float function call args
5476 int regmask = 0; // used regs
5486 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5487 g_stack_frame_used = 0;
5488 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5489 regmask_init = g_regmask_init;
5491 g_func_pp = proto_parse(fhdr, funcn, 0);
5492 if (g_func_pp == NULL)
5493 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5495 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5496 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5499 // - resolve all branches
5500 // - parse calls with labels
5501 resolve_branches_parse_calls(opcnt);
5504 // - handle ebp/esp frame, remove ops related to it
5505 scan_prologue_epilogue(opcnt);
5508 // - remove dead labels
5509 // - set regs needed at ret
5510 for (i = 0; i < opcnt; i++)
5512 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5517 if (ops[i].op == OP_RET)
5518 ops[i].regmask_src |= regmask_ret;
5522 // - process trivial calls
5523 for (i = 0; i < opcnt; i++)
5526 if (po->flags & (OPF_RMD|OPF_DONE))
5529 if (po->op == OP_CALL)
5531 pp = process_call_early(i, opcnt, &j);
5533 if (!(po->flags & OPF_ATAIL)) {
5534 // since we know the args, try to collect them
5535 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5543 // commit esp adjust
5544 if (ops[j].op != OP_POP)
5545 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5547 for (l = 0; l < pp->argc_stack; l++)
5548 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5552 if (strstr(pp->ret_type.name, "int64"))
5555 po->flags |= OPF_DONE;
5561 // - process calls, stage 2
5562 // - handle some push/pop pairs
5563 // - scan for STD/CLD, propagate DF
5564 // - try to resolve needed x87 status word bits
5565 for (i = 0; i < opcnt; i++)
5570 if (po->flags & OPF_RMD)
5573 if (po->op == OP_CALL)
5575 if (!(po->flags & OPF_DONE)) {
5576 pp = process_call(i, opcnt);
5578 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5579 // since we know the args, collect them
5580 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5582 // for unresolved, collect after other passes
5586 ferr_assert(po, pp != NULL);
5588 po->regmask_src |= get_pp_arg_regmask_src(pp);
5589 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5591 if (po->regmask_dst & mxST0)
5592 po->flags |= OPF_FPUSH;
5594 if (strstr(pp->ret_type.name, "int64"))
5600 if (po->flags & OPF_DONE)
5605 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
5606 && po->operand[0].type == OPT_CONST)
5608 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5613 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5617 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5618 scan_propagate_df(i + 1, opcnt);
5623 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
5624 ferr(po, "TODO: fnstsw to mem\n");
5625 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
5627 ferr(po, "fnstsw resolve failed\n");
5628 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
5629 (void *)(long)(mask | (z_check << 16)));
5631 ferr(po, "failed to find fcom: %d\n", ret);
5640 // - find POPs for PUSHes, rm both
5641 // - scan for all used registers
5642 memset(cbits, 0, sizeof(cbits));
5643 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5644 0, ®mask_save, ®mask_init, regmask_arg);
5646 need_float_stack = !!(regmask & mxST7_2);
5649 // - find flag set ops for their users
5650 // - do unresolved calls
5651 // - declare indirect functions
5652 // - other op specific processing
5653 for (i = 0; i < opcnt; i++)
5656 if (po->flags & (OPF_RMD|OPF_DONE))
5659 if (po->flags & OPF_CC)
5661 int setters[16], cnt = 0, branched = 0;
5663 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
5664 &branched, setters, &cnt);
5665 if (ret < 0 || cnt <= 0)
5666 ferr(po, "unable to trace flag setter(s)\n");
5667 if (cnt > ARRAY_SIZE(setters))
5668 ferr(po, "too many flag setters\n");
5670 for (j = 0; j < cnt; j++)
5672 tmp_op = &ops[setters[j]]; // flag setter
5675 // to get nicer code, we try to delay test and cmp;
5676 // if we can't because of operand modification, or if we
5677 // have arith op, or branch, make it calculate flags explicitly
5678 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5680 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5681 pfomask = 1 << po->pfo;
5683 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5684 pfomask = 1 << po->pfo;
5687 // see if we'll be able to handle based on op result
5688 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5689 && po->pfo != PFO_Z && po->pfo != PFO_S
5690 && po->pfo != PFO_P)
5692 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5694 pfomask = 1 << po->pfo;
5697 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5698 propagate_lmod(tmp_op, &tmp_op->operand[0],
5699 &tmp_op->operand[1]);
5700 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5705 tmp_op->pfomask |= pfomask;
5706 cond_vars |= pfomask;
5708 // note: may overwrite, currently not a problem
5712 if (po->op == OP_RCL || po->op == OP_RCR
5713 || po->op == OP_ADC || po->op == OP_SBB)
5714 cond_vars |= 1 << PFO_C;
5720 cond_vars |= 1 << PFO_Z;
5724 if (po->operand[0].lmod == OPLM_DWORD)
5729 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
5734 // note: resolved non-reg calls are OPF_DONE already
5736 ferr_assert(po, pp != NULL);
5738 if (pp->is_unresolved) {
5739 int regmask_stack = 0;
5740 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5742 // this is pretty rough guess:
5743 // see ecx and edx were pushed (and not their saved versions)
5744 for (arg = 0; arg < pp->argc; arg++) {
5745 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
5748 tmp_op = pp->arg[arg].datap;
5750 ferr(po, "parsed_op missing for arg%d\n", arg);
5751 if (tmp_op->operand[0].type == OPT_REG)
5752 regmask_stack |= 1 << tmp_op->operand[0].reg;
5755 if (!((regmask_stack & (1 << xCX))
5756 && (regmask_stack & (1 << xDX))))
5758 if (pp->argc_stack != 0
5759 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5761 pp_insert_reg_arg(pp, "ecx");
5762 pp->is_fastcall = 1;
5763 regmask_init |= 1 << xCX;
5764 regmask |= 1 << xCX;
5766 if (pp->argc_stack != 0
5767 || ((regmask | regmask_arg) & (1 << xDX)))
5769 pp_insert_reg_arg(pp, "edx");
5770 regmask_init |= 1 << xDX;
5771 regmask |= 1 << xDX;
5775 // note: __cdecl doesn't fall into is_unresolved category
5776 if (pp->argc_stack > 0)
5782 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
5784 // <var> = offset <something>
5785 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5786 && !IS_START(po->operand[1].name, "off_"))
5788 if (!po->operand[0].pp->is_fptr)
5789 ferr(po, "%s not declared as fptr when it should be\n",
5790 po->operand[0].name);
5791 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5792 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5793 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5794 fnote(po, "var: %s\n", buf1);
5795 fnote(po, "func: %s\n", buf2);
5796 ferr(po, "^ mismatch\n");
5804 if (po->operand[0].lmod == OPLM_DWORD) {
5805 // 32bit division is common, look for it
5806 if (po->op == OP_DIV)
5807 ret = scan_for_reg_clear(i, xDX);
5809 ret = scan_for_cdq_edx(i);
5811 po->flags |= OPF_32BIT;
5820 po->flags |= OPF_RMD | OPF_DONE;
5830 if (po->operand[0].lmod == OPLM_QWORD)
5840 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5842 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5844 po->flags |= OPF_32BIT;
5852 // this might need it's own pass...
5853 if (po->op != OP_FST && po->p_argnum > 0)
5854 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
5856 // correct for "full stack" mode late enable
5857 if ((po->flags & (OPF_PPUSH|OPF_FPOP)) && need_float_stack)
5858 po->flags |= OPF_FSHIFT;
5861 float_type = need_double ? "double" : "float";
5862 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
5863 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
5865 // output starts here
5867 // define userstack size
5868 if (g_func_pp->is_userstack) {
5869 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5870 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5871 fprintf(fout, "#endif\n");
5874 // the function itself
5875 ferr_assert(ops, !g_func_pp->is_fptr);
5876 output_pp(fout, g_func_pp,
5877 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5878 fprintf(fout, "\n{\n");
5880 // declare indirect functions
5881 for (i = 0; i < opcnt; i++) {
5883 if (po->flags & OPF_RMD)
5886 if (po->op == OP_CALL) {
5889 ferr(po, "NULL pp\n");
5891 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5892 if (pp->name[0] != 0) {
5893 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5894 memcpy(pp->name, "i_", 2);
5896 // might be declared already
5898 for (j = 0; j < i; j++) {
5899 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5900 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5910 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5913 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5914 fprintf(fout, ";\n");
5919 // output LUTs/jumptables
5920 for (i = 0; i < g_func_pd_cnt; i++) {
5922 fprintf(fout, " static const ");
5923 if (pd->type == OPT_OFFSET) {
5924 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5926 for (j = 0; j < pd->count; j++) {
5928 fprintf(fout, ", ");
5929 fprintf(fout, "&&%s", pd->d[j].u.label);
5933 fprintf(fout, "%s %s[] =\n { ",
5934 lmod_type_u(ops, pd->lmod), pd->label);
5936 for (j = 0; j < pd->count; j++) {
5938 fprintf(fout, ", ");
5939 fprintf(fout, "%u", pd->d[j].u.val);
5942 fprintf(fout, " };\n");
5946 // declare stack frame, va_arg
5948 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5949 if (g_func_lmods & (1 << OPLM_WORD))
5950 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5951 if (g_func_lmods & (1 << OPLM_BYTE))
5952 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5953 if (g_func_lmods & (1 << OPLM_QWORD))
5954 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5955 fprintf(fout, " } sf;\n");
5959 if (g_func_pp->is_userstack) {
5960 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5961 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5965 if (g_func_pp->is_vararg) {
5966 fprintf(fout, " va_list ap;\n");
5970 // declare arg-registers
5971 for (i = 0; i < g_func_pp->argc; i++) {
5972 if (g_func_pp->arg[i].reg != NULL) {
5973 reg = char_array_i(regs_r32,
5974 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5975 if (regmask & (1 << reg)) {
5976 if (g_func_pp->arg[i].type.is_retreg)
5977 fprintf(fout, " u32 %s = *r_%s;\n",
5978 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5980 fprintf(fout, " u32 %s = (u32)a%d;\n",
5981 g_func_pp->arg[i].reg, i + 1);
5984 if (g_func_pp->arg[i].type.is_retreg)
5985 ferr(ops, "retreg '%s' is unused?\n",
5986 g_func_pp->arg[i].reg);
5987 fprintf(fout, " // %s = a%d; // unused\n",
5988 g_func_pp->arg[i].reg, i + 1);
5994 // declare normal registers
5995 regmask_now = regmask & ~regmask_arg;
5996 regmask_now &= ~(1 << xSP);
5997 if (regmask_now & 0x00ff) {
5998 for (reg = 0; reg < 8; reg++) {
5999 if (regmask_now & (1 << reg)) {
6000 fprintf(fout, " u32 %s", regs_r32[reg]);
6001 if (regmask_init & (1 << reg))
6002 fprintf(fout, " = 0");
6003 fprintf(fout, ";\n");
6009 if (regmask_now & 0xff00) {
6010 for (reg = 8; reg < 16; reg++) {
6011 if (regmask_now & (1 << reg)) {
6012 fprintf(fout, " mmxr %s", regs_r32[reg]);
6013 if (regmask_init & (1 << reg))
6014 fprintf(fout, " = { 0, }");
6015 fprintf(fout, ";\n");
6021 if (need_float_stack) {
6022 fprintf(fout, " %s f_st[8];\n", float_type);
6023 fprintf(fout, " int f_stp = 0;\n");
6027 if (regmask_now & 0xff0000) {
6028 for (reg = 16; reg < 24; reg++) {
6029 if (regmask_now & (1 << reg)) {
6030 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6031 if (regmask_init & (1 << reg))
6032 fprintf(fout, " = 0");
6033 fprintf(fout, ";\n");
6040 if (need_float_sw) {
6041 fprintf(fout, " u16 f_sw;\n");
6046 for (reg = 0; reg < 8; reg++) {
6047 if (regmask_save & (1 << reg)) {
6048 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6054 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6055 if (save_arg_vars[i] == 0)
6057 for (reg = 0; reg < 32; reg++) {
6058 if (save_arg_vars[i] & (1 << reg)) {
6059 fprintf(fout, " u32 %s;\n",
6060 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6067 for (reg = 0; reg < 32; reg++) {
6068 if (regmask_ffca & (1 << reg)) {
6069 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6075 // declare push-pop temporaries
6077 for (reg = 0; reg < 8; reg++) {
6078 if (regmask_pp & (1 << reg)) {
6079 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6086 for (i = 0; i < 8; i++) {
6087 if (cond_vars & (1 << i)) {
6088 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6095 fprintf(fout, " u32 tmp;\n");
6100 fprintf(fout, " u64 tmp64;\n");
6105 fprintf(fout, "\n");
6107 // do stack clear, if needed
6108 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6110 if (g_stack_clear_len != 0) {
6111 if (g_stack_clear_len <= 4) {
6112 for (i = 0; i < g_stack_clear_len; i++)
6113 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6114 fprintf(fout, "0;\n");
6117 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6118 g_stack_clear_start, g_stack_clear_len * 4);
6122 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6125 if (g_func_pp->is_vararg) {
6126 if (g_func_pp->argc_stack == 0)
6127 ferr(ops, "vararg func without stack args?\n");
6128 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6132 for (i = 0; i < opcnt; i++)
6134 if (g_labels[i] != NULL) {
6135 fprintf(fout, "\n%s:\n", g_labels[i]);
6138 delayed_flag_op = NULL;
6139 last_arith_dst = NULL;
6143 if (po->flags & OPF_RMD)
6148 #define assert_operand_cnt(n_) \
6149 if (po->operand_cnt != n_) \
6150 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6152 // conditional/flag using op?
6153 if (po->flags & OPF_CC)
6159 // we go through all this trouble to avoid using parsed_flag_op,
6160 // which makes generated code much nicer
6161 if (delayed_flag_op != NULL)
6163 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6164 po->pfo, po->pfo_inv);
6167 else if (last_arith_dst != NULL
6168 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6169 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6172 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6173 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6174 last_arith_dst->lmod, buf3);
6177 else if (tmp_op != NULL) {
6178 // use preprocessed flag calc results
6179 if (!(tmp_op->pfomask & (1 << po->pfo)))
6180 ferr(po, "not prepared for pfo %d\n", po->pfo);
6182 // note: pfo_inv was not yet applied
6183 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6184 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6187 ferr(po, "all methods of finding comparison failed\n");
6190 if (po->flags & OPF_JMP) {
6191 fprintf(fout, " if %s", buf1);
6193 else if (po->op == OP_RCL || po->op == OP_RCR
6194 || po->op == OP_ADC || po->op == OP_SBB)
6197 fprintf(fout, " cond_%s = %s;\n",
6198 parsed_flag_op_names[po->pfo], buf1);
6200 else if (po->flags & OPF_DATA) { // SETcc
6201 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6202 fprintf(fout, " %s = %s;", buf2, buf1);
6205 ferr(po, "unhandled conditional op\n");
6209 pfomask = po->pfomask;
6214 assert_operand_cnt(2);
6215 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6216 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6217 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6218 fprintf(fout, " %s = %s;", buf1,
6219 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6224 assert_operand_cnt(2);
6225 po->operand[1].lmod = OPLM_DWORD; // always
6226 fprintf(fout, " %s = %s;",
6227 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6228 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6233 assert_operand_cnt(2);
6234 fprintf(fout, " %s = %s;",
6235 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6236 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6240 assert_operand_cnt(2);
6241 switch (po->operand[1].lmod) {
6243 strcpy(buf3, "(s8)");
6246 strcpy(buf3, "(s16)");
6249 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6251 fprintf(fout, " %s = %s;",
6252 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6253 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6258 assert_operand_cnt(2);
6259 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6260 fprintf(fout, " tmp = %s;",
6261 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6262 fprintf(fout, " %s = %s;",
6263 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6264 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6265 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6266 fprintf(fout, " %s = %stmp;",
6267 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6268 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6269 snprintf(g_comment, sizeof(g_comment), "xchg");
6273 assert_operand_cnt(1);
6274 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6275 fprintf(fout, " %s = ~%s;", buf1, buf1);
6279 assert_operand_cnt(2);
6280 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6281 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6282 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6283 strcpy(g_comment, "xlat");
6287 assert_operand_cnt(2);
6288 fprintf(fout, " %s = (s32)%s >> 31;",
6289 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6290 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6291 strcpy(g_comment, "cdq");
6295 assert_operand_cnt(1);
6296 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6297 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6301 if (po->flags & OPF_REP) {
6302 assert_operand_cnt(3);
6307 assert_operand_cnt(2);
6308 fprintf(fout, " %s = %sesi; esi %c= %d;",
6309 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6310 lmod_cast_u_ptr(po, po->operand[1].lmod),
6311 (po->flags & OPF_DF) ? '-' : '+',
6312 lmod_bytes(po, po->operand[1].lmod));
6313 strcpy(g_comment, "lods");
6318 if (po->flags & OPF_REP) {
6319 assert_operand_cnt(3);
6320 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6321 (po->flags & OPF_DF) ? '-' : '+',
6322 lmod_bytes(po, po->operand[1].lmod));
6323 fprintf(fout, " %sedi = eax;",
6324 lmod_cast_u_ptr(po, po->operand[1].lmod));
6325 strcpy(g_comment, "rep stos");
6328 assert_operand_cnt(2);
6329 fprintf(fout, " %sedi = eax; edi %c= %d;",
6330 lmod_cast_u_ptr(po, po->operand[1].lmod),
6331 (po->flags & OPF_DF) ? '-' : '+',
6332 lmod_bytes(po, po->operand[1].lmod));
6333 strcpy(g_comment, "stos");
6338 j = lmod_bytes(po, po->operand[0].lmod);
6339 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6340 l = (po->flags & OPF_DF) ? '-' : '+';
6341 if (po->flags & OPF_REP) {
6342 assert_operand_cnt(3);
6344 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6347 " %sedi = %sesi;", buf1, buf1);
6348 strcpy(g_comment, "rep movs");
6351 assert_operand_cnt(2);
6352 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6353 buf1, buf1, l, j, l, j);
6354 strcpy(g_comment, "movs");
6359 // repe ~ repeat while ZF=1
6360 j = lmod_bytes(po, po->operand[0].lmod);
6361 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6362 l = (po->flags & OPF_DF) ? '-' : '+';
6363 if (po->flags & OPF_REP) {
6364 assert_operand_cnt(3);
6366 " while (ecx != 0) {\n");
6367 if (pfomask & (1 << PFO_C)) {
6370 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6371 pfomask &= ~(1 << PFO_C);
6374 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6375 buf1, buf1, l, j, l, j);
6378 " if (cond_z %s 0) break;\n",
6379 (po->flags & OPF_REPZ) ? "==" : "!=");
6382 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6383 (po->flags & OPF_REPZ) ? "e" : "ne");
6386 assert_operand_cnt(2);
6388 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6389 buf1, buf1, l, j, l, j);
6390 strcpy(g_comment, "cmps");
6392 pfomask &= ~(1 << PFO_Z);
6393 last_arith_dst = NULL;
6394 delayed_flag_op = NULL;
6398 // only does ZF (for now)
6399 // repe ~ repeat while ZF=1
6400 j = lmod_bytes(po, po->operand[1].lmod);
6401 l = (po->flags & OPF_DF) ? '-' : '+';
6402 if (po->flags & OPF_REP) {
6403 assert_operand_cnt(3);
6405 " while (ecx != 0) {\n");
6407 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6408 lmod_cast_u(po, po->operand[1].lmod),
6409 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6412 " if (cond_z %s 0) break;\n",
6413 (po->flags & OPF_REPZ) ? "==" : "!=");
6416 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6417 (po->flags & OPF_REPZ) ? "e" : "ne");
6420 assert_operand_cnt(2);
6421 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6422 lmod_cast_u(po, po->operand[1].lmod),
6423 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6424 strcpy(g_comment, "scas");
6426 pfomask &= ~(1 << PFO_Z);
6427 last_arith_dst = NULL;
6428 delayed_flag_op = NULL;
6431 // arithmetic w/flags
6433 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6434 goto dualop_arith_const;
6435 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6439 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6440 if (po->operand[1].type == OPT_CONST) {
6441 j = lmod_bytes(po, po->operand[0].lmod);
6442 if (((1ull << j * 8) - 1) == po->operand[1].val)
6443 goto dualop_arith_const;
6448 assert_operand_cnt(2);
6449 fprintf(fout, " %s %s= %s;",
6450 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6452 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6453 output_std_flags(fout, po, &pfomask, buf1);
6454 last_arith_dst = &po->operand[0];
6455 delayed_flag_op = NULL;
6459 // and 0, or ~0 used instead mov
6460 assert_operand_cnt(2);
6461 fprintf(fout, " %s = %s;",
6462 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6463 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6464 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6465 output_std_flags(fout, po, &pfomask, buf1);
6466 last_arith_dst = &po->operand[0];
6467 delayed_flag_op = NULL;
6472 assert_operand_cnt(2);
6473 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6474 if (pfomask & (1 << PFO_C)) {
6475 if (po->operand[1].type == OPT_CONST) {
6476 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6477 j = po->operand[1].val;
6480 if (po->op == OP_SHL)
6484 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6488 ferr(po, "zero shift?\n");
6492 pfomask &= ~(1 << PFO_C);
6494 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6495 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6496 if (po->operand[1].type != OPT_CONST)
6497 fprintf(fout, " & 0x1f");
6499 output_std_flags(fout, po, &pfomask, buf1);
6500 last_arith_dst = &po->operand[0];
6501 delayed_flag_op = NULL;
6505 assert_operand_cnt(2);
6506 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6507 fprintf(fout, " %s = %s%s >> %s;", buf1,
6508 lmod_cast_s(po, po->operand[0].lmod), buf1,
6509 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6510 output_std_flags(fout, po, &pfomask, buf1);
6511 last_arith_dst = &po->operand[0];
6512 delayed_flag_op = NULL;
6517 assert_operand_cnt(3);
6518 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6519 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6520 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6521 if (po->operand[2].type != OPT_CONST) {
6522 // no handling for "undefined" case, hopefully not needed
6523 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6526 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6527 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6528 if (po->op == OP_SHLD) {
6529 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6530 buf1, buf3, buf1, buf2, l, buf3);
6531 strcpy(g_comment, "shld");
6534 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6535 buf1, buf3, buf1, buf2, l, buf3);
6536 strcpy(g_comment, "shrd");
6538 output_std_flags(fout, po, &pfomask, buf1);
6539 last_arith_dst = &po->operand[0];
6540 delayed_flag_op = NULL;
6545 assert_operand_cnt(2);
6546 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6547 if (po->operand[1].type == OPT_CONST) {
6548 j = po->operand[1].val;
6549 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6550 fprintf(fout, po->op == OP_ROL ?
6551 " %s = (%s << %d) | (%s >> %d);" :
6552 " %s = (%s >> %d) | (%s << %d);",
6553 buf1, buf1, j, buf1,
6554 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6558 output_std_flags(fout, po, &pfomask, buf1);
6559 last_arith_dst = &po->operand[0];
6560 delayed_flag_op = NULL;
6565 assert_operand_cnt(2);
6566 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6567 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6568 if (po->operand[1].type == OPT_CONST) {
6569 j = po->operand[1].val % l;
6571 ferr(po, "zero rotate\n");
6572 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6573 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6574 if (po->op == OP_RCL) {
6576 " %s = (%s << %d) | (cond_c << %d)",
6577 buf1, buf1, j, j - 1);
6579 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6583 " %s = (%s >> %d) | (cond_c << %d)",
6584 buf1, buf1, j, l - j);
6586 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6588 fprintf(fout, ";\n");
6589 fprintf(fout, " cond_c = tmp;");
6593 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6594 output_std_flags(fout, po, &pfomask, buf1);
6595 last_arith_dst = &po->operand[0];
6596 delayed_flag_op = NULL;
6600 assert_operand_cnt(2);
6601 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6602 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6603 // special case for XOR
6604 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
6605 for (j = 0; j <= PFO_LE; j++) {
6606 if (pfomask & (1 << j)) {
6607 fprintf(fout, " cond_%s = %d;\n",
6608 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
6609 pfomask &= ~(1 << j);
6612 fprintf(fout, " %s = 0;",
6613 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6614 last_arith_dst = &po->operand[0];
6615 delayed_flag_op = NULL;
6621 assert_operand_cnt(2);
6622 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6623 if (pfomask & (1 << PFO_C)) {
6624 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6625 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6626 if (po->operand[0].lmod == OPLM_DWORD) {
6627 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6628 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6629 fprintf(fout, " %s = (u32)tmp64;",
6630 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6631 strcat(g_comment, " add64");
6634 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6635 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6636 fprintf(fout, " %s += %s;",
6637 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6640 pfomask &= ~(1 << PFO_C);
6641 output_std_flags(fout, po, &pfomask, buf1);
6642 last_arith_dst = &po->operand[0];
6643 delayed_flag_op = NULL;
6646 if (pfomask & (1 << PFO_LE)) {
6647 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
6648 fprintf(fout, " cond_%s = %s;\n",
6649 parsed_flag_op_names[PFO_LE], buf1);
6650 pfomask &= ~(1 << PFO_LE);
6655 assert_operand_cnt(2);
6656 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6657 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6658 for (j = 0; j <= PFO_LE; j++) {
6659 if (!(pfomask & (1 << j)))
6661 if (j == PFO_Z || j == PFO_S)
6664 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6665 fprintf(fout, " cond_%s = %s;\n",
6666 parsed_flag_op_names[j], buf1);
6667 pfomask &= ~(1 << j);
6674 assert_operand_cnt(2);
6675 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6676 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6677 if (po->op == OP_SBB
6678 && IS(po->operand[0].name, po->operand[1].name))
6680 // avoid use of unitialized var
6681 fprintf(fout, " %s = -cond_c;", buf1);
6682 // carry remains what it was
6683 pfomask &= ~(1 << PFO_C);
6686 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6687 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6689 output_std_flags(fout, po, &pfomask, buf1);
6690 last_arith_dst = &po->operand[0];
6691 delayed_flag_op = NULL;
6695 assert_operand_cnt(2);
6696 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6697 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6698 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6700 output_std_flags(fout, po, &pfomask, buf1);
6701 last_arith_dst = &po->operand[0];
6702 delayed_flag_op = NULL;
6703 strcat(g_comment, " bsf");
6707 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6708 for (j = 0; j <= PFO_LE; j++) {
6709 if (!(pfomask & (1 << j)))
6711 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6714 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6715 fprintf(fout, " cond_%s = %s;\n",
6716 parsed_flag_op_names[j], buf1);
6717 pfomask &= ~(1 << j);
6723 if (pfomask & (1 << PFO_C))
6724 // carry is unaffected by inc/dec.. wtf?
6725 ferr(po, "carry propagation needed\n");
6727 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6728 if (po->operand[0].type == OPT_REG) {
6729 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6730 fprintf(fout, " %s%s;", buf1, buf2);
6733 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6734 fprintf(fout, " %s %s= 1;", buf1, buf2);
6736 output_std_flags(fout, po, &pfomask, buf1);
6737 last_arith_dst = &po->operand[0];
6738 delayed_flag_op = NULL;
6742 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6743 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6744 fprintf(fout, " %s = -%s%s;", buf1,
6745 lmod_cast_s(po, po->operand[0].lmod), buf2);
6746 last_arith_dst = &po->operand[0];
6747 delayed_flag_op = NULL;
6748 if (pfomask & PFOB_C) {
6749 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6752 output_std_flags(fout, po, &pfomask, buf1);
6756 if (po->operand_cnt == 2) {
6757 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6760 if (po->operand_cnt == 3)
6761 ferr(po, "TODO imul3\n");
6764 assert_operand_cnt(1);
6765 switch (po->operand[0].lmod) {
6767 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6768 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6769 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6770 fprintf(fout, " edx = tmp64 >> 32;\n");
6771 fprintf(fout, " eax = tmp64;");
6774 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6775 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6776 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6780 ferr(po, "TODO: unhandled mul type\n");
6783 last_arith_dst = NULL;
6784 delayed_flag_op = NULL;
6789 assert_operand_cnt(1);
6790 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6791 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6792 po->op == OP_IDIV));
6793 switch (po->operand[0].lmod) {
6795 if (po->flags & OPF_32BIT)
6796 snprintf(buf2, sizeof(buf2), "%seax", cast);
6798 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6799 snprintf(buf2, sizeof(buf2), "%stmp64",
6800 (po->op == OP_IDIV) ? "(s64)" : "");
6802 if (po->operand[0].type == OPT_REG
6803 && po->operand[0].reg == xDX)
6805 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6806 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6809 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6810 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6814 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6815 snprintf(buf2, sizeof(buf2), "%stmp",
6816 (po->op == OP_IDIV) ? "(s32)" : "");
6817 if (po->operand[0].type == OPT_REG
6818 && po->operand[0].reg == xDX)
6820 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6822 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6826 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6828 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6831 strcat(g_comment, " div16");
6834 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6836 last_arith_dst = NULL;
6837 delayed_flag_op = NULL;
6842 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6844 for (j = 0; j < 8; j++) {
6845 if (pfomask & (1 << j)) {
6846 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6847 fprintf(fout, " cond_%s = %s;",
6848 parsed_flag_op_names[j], buf1);
6855 last_arith_dst = NULL;
6856 delayed_flag_op = po;
6860 // SETcc - should already be handled
6863 // note: we reuse OP_Jcc for SETcc, only flags differ
6865 fprintf(fout, "\n goto %s;", po->operand[0].name);
6869 fprintf(fout, " if (ecx == 0)\n");
6870 fprintf(fout, " goto %s;", po->operand[0].name);
6871 strcat(g_comment, " jecxz");
6875 fprintf(fout, " if (--ecx != 0)\n");
6876 fprintf(fout, " goto %s;", po->operand[0].name);
6877 strcat(g_comment, " loop");
6881 assert_operand_cnt(1);
6882 last_arith_dst = NULL;
6883 delayed_flag_op = NULL;
6885 if (po->operand[0].type == OPT_REGMEM) {
6886 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6889 ferr(po, "parse failure for jmp '%s'\n",
6890 po->operand[0].name);
6891 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6894 else if (po->operand[0].type != OPT_LABEL)
6895 ferr(po, "unhandled jmp type\n");
6897 fprintf(fout, " goto %s;", po->operand[0].name);
6901 assert_operand_cnt(1);
6903 my_assert_not(pp, NULL);
6906 if (po->flags & OPF_CC) {
6907 // we treat conditional branch to another func
6908 // (yes such code exists..) as conditional tailcall
6910 fprintf(fout, " {\n");
6913 if (pp->is_fptr && !pp->is_arg) {
6914 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6915 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6917 if (pp->is_unresolved)
6918 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6919 buf3, asmfn, po->asmln, pp->name);
6922 fprintf(fout, "%s", buf3);
6923 if (strstr(pp->ret_type.name, "int64")) {
6924 if (po->flags & OPF_TAIL)
6925 ferr(po, "int64 and tail?\n");
6926 fprintf(fout, "tmp64 = ");
6928 else if (!IS(pp->ret_type.name, "void")) {
6929 if (po->flags & OPF_TAIL) {
6930 if (regmask_ret & mxAX) {
6931 fprintf(fout, "return ");
6932 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6933 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6935 else if (regmask_ret & mxST0)
6936 ferr(po, "float tailcall\n");
6938 else if (po->regmask_dst & mxAX) {
6939 fprintf(fout, "eax = ");
6940 if (pp->ret_type.is_ptr)
6941 fprintf(fout, "(u32)");
6943 else if (po->regmask_dst & mxST0) {
6944 ferr_assert(po, po->flags & OPF_FPUSH);
6945 if (need_float_stack)
6946 fprintf(fout, "f_st[--f_stp & 7] = ");
6948 fprintf(fout, "f_st0 = ");
6952 if (pp->name[0] == 0)
6953 ferr(po, "missing pp->name\n");
6954 fprintf(fout, "%s%s(", pp->name,
6955 pp->has_structarg ? "_sa" : "");
6957 if (po->flags & OPF_ATAIL) {
6959 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
6960 check_compat |= pp->argc_stack > 0;
6962 && (pp->argc_stack != g_func_pp->argc_stack
6963 || pp->is_stdcall != g_func_pp->is_stdcall))
6964 ferr(po, "incompatible arg-reuse tailcall\n");
6965 if (g_func_pp->has_retreg)
6966 ferr(po, "TODO: retreg+tailcall\n");
6968 for (arg = j = 0; arg < pp->argc; arg++) {
6970 fprintf(fout, ", ");
6973 if (pp->arg[arg].type.is_ptr)
6974 snprintf(cast, sizeof(cast), "(%s)",
6975 pp->arg[arg].type.name);
6977 if (pp->arg[arg].reg != NULL) {
6978 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6982 for (; j < g_func_pp->argc; j++)
6983 if (g_func_pp->arg[j].reg == NULL)
6985 fprintf(fout, "%sa%d", cast, j + 1);
6990 for (arg = 0; arg < pp->argc; arg++) {
6992 fprintf(fout, ", ");
6995 if (pp->arg[arg].type.is_ptr)
6996 snprintf(cast, sizeof(cast), "(%s)",
6997 pp->arg[arg].type.name);
6999 if (pp->arg[arg].reg != NULL) {
7000 if (pp->arg[arg].type.is_retreg)
7001 fprintf(fout, "&%s", pp->arg[arg].reg);
7002 else if (IS(pp->arg[arg].reg, "ebp")
7003 && g_bp_frame && !(po->flags & OPF_EBP_S))
7005 // rare special case
7006 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7007 strcat(g_comment, " bp_ref");
7010 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7015 tmp_op = pp->arg[arg].datap;
7017 ferr(po, "parsed_op missing for arg%d\n", arg);
7019 if (tmp_op->flags & OPF_VAPUSH) {
7020 fprintf(fout, "ap");
7022 else if (tmp_op->op == OP_FST) {
7023 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7024 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7027 else if (tmp_op->p_argpass != 0) {
7028 fprintf(fout, "a%d", tmp_op->p_argpass);
7030 else if (pp->arg[arg].is_saved) {
7031 ferr_assert(po, tmp_op->p_argnum > 0);
7032 fprintf(fout, "%s%s", cast,
7033 saved_arg_name(buf1, sizeof(buf1),
7034 tmp_op->p_arggrp, tmp_op->p_argnum));
7038 out_src_opr(buf1, sizeof(buf1),
7039 tmp_op, &tmp_op->operand[0], cast, 0));
7043 fprintf(fout, ");");
7045 if (strstr(pp->ret_type.name, "int64")) {
7046 fprintf(fout, "\n");
7047 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7048 fprintf(fout, "%seax = tmp64;", buf3);
7051 if (pp->is_unresolved) {
7052 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7054 strcat(g_comment, buf2);
7057 if (po->flags & OPF_TAIL) {
7059 if (i == opcnt - 1 || pp->is_noreturn)
7061 else if (IS(pp->ret_type.name, "void"))
7063 else if (!(regmask_ret & (1 << xAX)))
7065 // else already handled as 'return f()'
7068 fprintf(fout, "\n%sreturn;", buf3);
7069 strcat(g_comment, " ^ tailcall");
7072 strcat(g_comment, " tailcall");
7074 if ((regmask_ret & (1 << xAX))
7075 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7077 ferr(po, "int func -> void func tailcall?\n");
7080 if (pp->is_noreturn)
7081 strcat(g_comment, " noreturn");
7082 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7083 strcat(g_comment, " argframe");
7084 if (po->flags & OPF_CC)
7085 strcat(g_comment, " cond");
7087 if (po->flags & OPF_CC)
7088 fprintf(fout, "\n }");
7090 delayed_flag_op = NULL;
7091 last_arith_dst = NULL;
7095 if (g_func_pp->is_vararg)
7096 fprintf(fout, " va_end(ap);\n");
7097 if (g_func_pp->has_retreg) {
7098 for (arg = 0; arg < g_func_pp->argc; arg++)
7099 if (g_func_pp->arg[arg].type.is_retreg)
7100 fprintf(fout, " *r_%s = %s;\n",
7101 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7104 if (regmask_ret & mxST0) {
7105 fprintf(fout, " return %s;", float_st0);
7107 else if (!(regmask_ret & mxAX)) {
7108 if (i != opcnt - 1 || label_pending)
7109 fprintf(fout, " return;");
7111 else if (g_func_pp->ret_type.is_ptr) {
7112 fprintf(fout, " return (%s)eax;",
7113 g_func_pp->ret_type.name);
7115 else if (IS(g_func_pp->ret_type.name, "__int64"))
7116 fprintf(fout, " return ((u64)edx << 32) | eax;");
7118 fprintf(fout, " return eax;");
7120 last_arith_dst = NULL;
7121 delayed_flag_op = NULL;
7125 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7126 if (po->p_argnum != 0) {
7127 // special case - saved func arg
7128 fprintf(fout, " %s = %s;",
7129 saved_arg_name(buf2, sizeof(buf2),
7130 po->p_arggrp, po->p_argnum), buf1);
7133 else if (po->flags & OPF_RSAVE) {
7134 fprintf(fout, " s_%s = %s;", buf1, buf1);
7137 else if (po->flags & OPF_PPUSH) {
7139 ferr_assert(po, tmp_op != NULL);
7140 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7141 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7144 else if (g_func_pp->is_userstack) {
7145 fprintf(fout, " *(--esp) = %s;", buf1);
7148 if (!(g_ida_func_attr & IDAFA_NORETURN))
7149 ferr(po, "stray push encountered\n");
7154 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7155 if (po->flags & OPF_RSAVE) {
7156 fprintf(fout, " %s = s_%s;", buf1, buf1);
7159 else if (po->flags & OPF_PPUSH) {
7160 // push/pop graph / non-const
7161 ferr_assert(po, po->datap == NULL);
7162 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7165 else if (po->datap != NULL) {
7168 fprintf(fout, " %s = %s;", buf1,
7169 out_src_opr(buf2, sizeof(buf2),
7170 tmp_op, &tmp_op->operand[0],
7171 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7174 else if (g_func_pp->is_userstack) {
7175 fprintf(fout, " %s = *esp++;", buf1);
7179 ferr(po, "stray pop encountered\n");
7189 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7190 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7191 po->op == OPP_ALLSHL ? "<<" : ">>");
7192 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7193 strcat(g_comment, po->op == OPP_ALLSHL
7194 ? " allshl" : " allshr");
7199 if (need_float_stack) {
7200 out_src_opr_float(buf1, sizeof(buf1),
7201 po, &po->operand[0], 1);
7202 if (po->regmask_src & mxSTa) {
7203 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7207 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7210 if (po->flags & OPF_FSHIFT)
7211 fprintf(fout, " f_st1 = f_st0;");
7212 if (po->operand[0].type == OPT_REG
7213 && po->operand[0].reg == xST0)
7215 strcat(g_comment, " fld st");
7218 fprintf(fout, " f_st0 = %s;",
7219 out_src_opr_float(buf1, sizeof(buf1),
7220 po, &po->operand[0], 0));
7222 strcat(g_comment, " fld");
7226 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7227 lmod_cast(po, po->operand[0].lmod, 1), 0);
7228 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7229 if (need_float_stack) {
7230 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7233 if (po->flags & OPF_FSHIFT)
7234 fprintf(fout, " f_st1 = f_st0;");
7235 fprintf(fout, " f_st0 = %s;", buf2);
7237 strcat(g_comment, " fild");
7241 if (need_float_stack)
7242 fprintf(fout, " f_st[--f_stp & 7] = ");
7244 if (po->flags & OPF_FSHIFT)
7245 fprintf(fout, " f_st1 = f_st0;");
7246 fprintf(fout, " f_st0 = ");
7248 switch (po->operand[0].val) {
7249 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7250 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
7251 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7252 default: ferr(po, "TODO\n"); break;
7257 if (po->flags & OPF_FARG) {
7258 // store to stack as func arg
7259 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7263 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7265 dead_dst = po->operand[0].type == OPT_REG
7266 && po->operand[0].reg == xST0;
7269 fprintf(fout, " %s = %s;", buf1, float_st0);
7270 if (po->flags & OPF_FSHIFT) {
7271 if (need_float_stack)
7272 fprintf(fout, " f_stp++;");
7274 fprintf(fout, " f_st0 = f_st1;");
7276 if (dead_dst && !(po->flags & OPF_FSHIFT))
7279 strcat(g_comment, " fst");
7283 fprintf(fout, " %s = %s%s;",
7284 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7285 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7286 if (po->flags & OPF_FSHIFT) {
7287 if (need_float_stack)
7288 fprintf(fout, " f_stp++;");
7290 fprintf(fout, " f_st0 = f_st1;");
7292 strcat(g_comment, " fist");
7299 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7301 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7303 dead_dst = (po->flags & OPF_FPOP)
7304 && po->operand[0].type == OPT_REG
7305 && po->operand[0].reg == xST0;
7307 case OP_FADD: j = '+'; break;
7308 case OP_FDIV: j = '/'; break;
7309 case OP_FMUL: j = '*'; break;
7310 case OP_FSUB: j = '-'; break;
7311 default: j = 'x'; break;
7313 if (need_float_stack) {
7315 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7316 if (po->flags & OPF_FSHIFT)
7317 fprintf(fout, " f_stp++;");
7320 if (po->flags & OPF_FSHIFT) {
7321 // note: assumes only 2 regs handled
7323 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7325 fprintf(fout, " f_st0 = f_st1;");
7328 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7330 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7335 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7337 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7339 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7341 dead_dst = (po->flags & OPF_FPOP)
7342 && po->operand[0].type == OPT_REG
7343 && po->operand[0].reg == xST0;
7344 j = po->op == OP_FDIVR ? '/' : '-';
7345 if (need_float_stack) {
7347 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7348 if (po->flags & OPF_FSHIFT)
7349 fprintf(fout, " f_stp++;");
7352 if (po->flags & OPF_FSHIFT) {
7354 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7356 fprintf(fout, " f_st0 = f_st1;");
7359 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7361 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7369 case OP_FIADD: j = '+'; break;
7370 case OP_FIDIV: j = '/'; break;
7371 case OP_FIMUL: j = '*'; break;
7372 case OP_FISUB: j = '-'; break;
7373 default: j = 'x'; break;
7375 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7377 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7378 lmod_cast(po, po->operand[0].lmod, 1), 0));
7383 fprintf(fout, " %s = %s %c %s;", float_st0,
7384 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7386 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7391 ferr_assert(po, po->datap != NULL);
7392 mask = (long)po->datap & 0xffff;
7393 z_check = ((long)po->datap >> 16) & 1;
7394 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7396 if (mask == 0x0100) { // C0 -> <
7397 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7400 else if (mask == 0x4000) { // C3 -> =
7401 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7404 else if (mask == 0x4100) { // C3, C0
7406 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7408 strcat(g_comment, " z_chk_det");
7411 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7412 "(%s < %s ? 0x0100 : 0);",
7413 float_st0, buf1, float_st0, buf1);
7417 ferr(po, "unhandled sw mask: %x\n", mask);
7418 if (po->flags & OPF_FSHIFT) {
7419 if (need_float_stack)
7420 fprintf(fout, " f_stp++;");
7422 fprintf(fout, " f_st0 = f_st1;");
7428 fprintf(fout, " %s = f_sw;",
7429 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7433 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7437 fprintf(fout, " %s = cos%s(%s);", float_st0,
7438 need_double ? "" : "f", float_st0);
7442 if (need_float_stack) {
7443 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7444 need_double ? "" : "f", float_st1, float_st0);
7445 fprintf(fout, " f_stp++;");
7448 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7449 need_double ? "" : "f");
7454 if (need_float_stack) {
7455 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7456 float_st1, need_double ? "" : "f", float_st0);
7457 fprintf(fout, " f_stp++;");
7460 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7461 need_double ? "" : "f");
7463 strcat(g_comment, " fyl2x");
7467 fprintf(fout, " %s = sin%s(%s);", float_st0,
7468 need_double ? "" : "f", float_st0);
7472 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7473 need_double ? "" : "f", float_st0);
7477 dead_dst = po->operand[0].type == OPT_REG
7478 && po->operand[0].reg == xST0;
7480 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7482 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7483 float_st0, float_st0, buf1, buf1);
7484 strcat(g_comment, " fxch");
7491 ferr_assert(po, po->flags & OPF_32BIT);
7492 fprintf(fout, " eax = (s32)%s;", float_st0);
7493 if (po->flags & OPF_FSHIFT) {
7494 if (need_float_stack)
7495 fprintf(fout, " f_stp++;");
7497 fprintf(fout, " f_st0 = f_st1;");
7499 strcat(g_comment, " ftol");
7503 if (need_float_stack) {
7504 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
7505 need_double ? "" : "f", float_st1, float_st0);
7506 fprintf(fout, " f_stp++;");
7509 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
7510 need_double ? "" : "f");
7512 strcat(g_comment, " CIpow");
7516 fprintf(fout, " do_skip_code_abort();");
7521 fprintf(fout, " do_emms();");
7526 ferr(po, "unhandled op type %d, flags %x\n",
7531 if (g_comment[0] != 0) {
7532 char *p = g_comment;
7533 while (my_isblank(*p))
7535 fprintf(fout, " // %s", p);
7540 fprintf(fout, "\n");
7542 // some sanity checking
7543 if (po->flags & OPF_REP) {
7544 if (po->op != OP_STOS && po->op != OP_MOVS
7545 && po->op != OP_CMPS && po->op != OP_SCAS)
7546 ferr(po, "unexpected rep\n");
7547 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7548 && (po->op == OP_CMPS || po->op == OP_SCAS))
7549 ferr(po, "cmps/scas with plain rep\n");
7551 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7552 && po->op != OP_CMPS && po->op != OP_SCAS)
7553 ferr(po, "unexpected repz/repnz\n");
7556 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
7558 // see is delayed flag stuff is still valid
7559 if (delayed_flag_op != NULL && delayed_flag_op != po) {
7560 if (is_any_opr_modified(delayed_flag_op, po, 0))
7561 delayed_flag_op = NULL;
7564 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7565 if (is_opr_modified(last_arith_dst, po))
7566 last_arith_dst = NULL;
7572 if (g_stack_fsz && !g_stack_frame_used)
7573 fprintf(fout, " (void)sf;\n");
7575 fprintf(fout, "}\n\n");
7577 gen_x_cleanup(opcnt);
7580 static void gen_x_cleanup(int opcnt)
7584 for (i = 0; i < opcnt; i++) {
7585 struct label_ref *lr, *lr_del;
7587 lr = g_label_refs[i].next;
7588 while (lr != NULL) {
7593 g_label_refs[i].i = -1;
7594 g_label_refs[i].next = NULL;
7596 if (ops[i].op == OP_CALL) {
7598 proto_release(ops[i].pp);
7604 struct func_proto_dep;
7606 struct func_prototype {
7611 int has_ret:3; // -1, 0, 1: unresolved, no, yes
7612 unsigned int dep_resolved:1;
7613 unsigned int is_stdcall:1;
7614 struct func_proto_dep *dep_func;
7616 const struct parsed_proto *pp; // seed pp, if any
7619 struct func_proto_dep {
7621 struct func_prototype *proto;
7622 int regmask_live; // .. at the time of call
7623 unsigned int ret_dep:1; // return from this is caller's return
7626 static struct func_prototype *hg_fp;
7627 static int hg_fp_cnt;
7629 static struct scanned_var {
7631 enum opr_lenmod lmod;
7632 unsigned int is_seeded:1;
7633 unsigned int is_c_str:1;
7634 const struct parsed_proto *pp; // seed pp, if any
7636 static int hg_var_cnt;
7638 static char **hg_refs;
7639 static int hg_ref_cnt;
7641 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7644 static struct func_prototype *hg_fp_add(const char *funcn)
7646 struct func_prototype *fp;
7648 if ((hg_fp_cnt & 0xff) == 0) {
7649 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7650 my_assert_not(hg_fp, NULL);
7651 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7654 fp = &hg_fp[hg_fp_cnt];
7655 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7657 fp->argc_stack = -1;
7663 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7668 for (i = 0; i < fp->dep_func_cnt; i++)
7669 if (IS(fp->dep_func[i].name, name))
7670 return &fp->dep_func[i];
7675 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7678 if (hg_fp_find_dep(fp, name))
7681 if ((fp->dep_func_cnt & 0xff) == 0) {
7682 fp->dep_func = realloc(fp->dep_func,
7683 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7684 my_assert_not(fp->dep_func, NULL);
7685 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7686 sizeof(fp->dep_func[0]) * 0x100);
7688 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7692 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7694 const struct func_prototype *p1 = p1_, *p2 = p2_;
7695 return strcmp(p1->name, p2->name);
7699 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7701 const struct func_prototype *p1 = p1_, *p2 = p2_;
7702 return p1->id - p2->id;
7706 static void hg_ref_add(const char *name)
7708 if ((hg_ref_cnt & 0xff) == 0) {
7709 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7710 my_assert_not(hg_refs, NULL);
7711 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7714 hg_refs[hg_ref_cnt] = strdup(name);
7715 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7719 // recursive register dep pass
7720 // - track saved regs (part 2)
7721 // - try to figure out arg-regs
7722 // - calculate reg deps
7723 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
7724 struct func_prototype *fp, int regmask_save, int regmask_dst,
7725 int *regmask_dep, int *has_ret)
7727 struct func_proto_dep *dep;
7728 struct parsed_op *po;
7729 int from_caller = 0;
7734 for (; i < opcnt; i++)
7736 if (cbits[i >> 3] & (1 << (i & 7)))
7738 cbits[i >> 3] |= (1 << (i & 7));
7742 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
7743 if (po->flags & OPF_RMD)
7746 if (po->btj != NULL) {
7748 for (j = 0; j < po->btj->count; j++) {
7749 check_i(po, po->btj->d[j].bt_i);
7750 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
7751 regmask_save, regmask_dst, regmask_dep, has_ret);
7756 check_i(po, po->bt_i);
7757 if (po->flags & OPF_CJMP) {
7758 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
7759 regmask_save, regmask_dst, regmask_dep, has_ret);
7767 if (po->flags & OPF_FARG)
7768 /* (just calculate register deps) */;
7769 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
7771 reg = po->operand[0].reg;
7772 ferr_assert(po, reg >= 0);
7774 if (po->flags & OPF_RSAVE) {
7775 regmask_save |= 1 << reg;
7778 if (po->flags & OPF_DONE)
7781 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
7783 regmask_save |= 1 << reg;
7784 po->flags |= OPF_RMD;
7785 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
7789 else if (po->flags & OPF_RMD)
7791 else if (po->op == OP_CALL) {
7792 po->regmask_dst |= 1 << xAX;
7794 dep = hg_fp_find_dep(fp, po->operand[0].name);
7796 dep->regmask_live = regmask_save | regmask_dst;
7797 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7798 dep->regmask_live |= 1 << xBP;
7801 else if (po->op == OP_RET) {
7802 if (po->operand_cnt > 0) {
7804 if (fp->argc_stack >= 0
7805 && fp->argc_stack != po->operand[0].val / 4)
7806 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
7807 fp->argc_stack = po->operand[0].val / 4;
7811 // if has_ret is 0, there is uninitialized eax path,
7812 // which means it's most likely void func
7813 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
7814 if (po->op == OP_CALL) {
7819 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
7822 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
7825 if (ret != 1 && from_caller) {
7826 // unresolved eax - probably void func
7830 if (j >= 0 && ops[j].op == OP_CALL) {
7831 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
7842 l = regmask_save | regmask_dst;
7843 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7846 l = po->regmask_src & ~l;
7849 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
7850 l, regmask_dst, regmask_save, po->flags);
7853 regmask_dst |= po->regmask_dst;
7855 if (po->flags & OPF_TAIL)
7860 static void gen_hdr(const char *funcn, int opcnt)
7862 unsigned char cbits[MAX_OPS / 8];
7863 const struct parsed_proto *pp_c;
7864 struct parsed_proto *pp;
7865 struct func_prototype *fp;
7866 struct parsed_op *po;
7867 int regmask_dummy = 0;
7869 int max_bp_offset = 0;
7874 pp_c = proto_parse(g_fhdr, funcn, 1);
7876 // already in seed, will add to hg_fp later
7879 fp = hg_fp_add(funcn);
7881 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7882 g_stack_frame_used = 0;
7885 // - resolve all branches
7886 // - parse calls with labels
7887 resolve_branches_parse_calls(opcnt);
7890 // - handle ebp/esp frame, remove ops related to it
7891 scan_prologue_epilogue(opcnt);
7894 // - remove dead labels
7896 for (i = 0; i < opcnt; i++)
7898 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7904 if (po->flags & (OPF_RMD|OPF_DONE))
7907 if (po->op == OP_CALL) {
7908 if (po->operand[0].type == OPT_LABEL)
7909 hg_fp_add_dep(fp, opr_name(po, 0));
7910 else if (po->pp != NULL)
7911 hg_fp_add_dep(fp, po->pp->name);
7916 // - remove dead labels
7917 // - handle push <const>/pop pairs
7918 for (i = 0; i < opcnt; i++)
7920 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7926 if (po->flags & (OPF_RMD|OPF_DONE))
7929 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
7930 scan_for_pop_const(i, opcnt, i + opcnt * 13);
7934 // - process trivial calls
7935 for (i = 0; i < opcnt; i++)
7938 if (po->flags & (OPF_RMD|OPF_DONE))
7941 if (po->op == OP_CALL)
7943 pp = process_call_early(i, opcnt, &j);
7945 if (!(po->flags & OPF_ATAIL))
7946 // since we know the args, try to collect them
7947 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
7953 // commit esp adjust
7954 if (ops[j].op != OP_POP)
7955 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
7957 for (l = 0; l < pp->argc_stack; l++)
7958 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
7962 po->flags |= OPF_DONE;
7968 // - track saved regs (simple)
7970 for (i = 0; i < opcnt; i++)
7973 if (po->flags & (OPF_RMD|OPF_DONE))
7976 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7977 && po->operand[0].reg != xCX)
7979 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
7981 // regmask_save |= 1 << po->operand[0].reg; // do it later
7982 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
7983 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
7986 else if (po->op == OP_CALL)
7988 pp = process_call(i, opcnt);
7990 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
7991 // since we know the args, collect them
7992 ret = collect_call_args(po, i, pp, ®mask_dummy,
7999 memset(cbits, 0, sizeof(cbits));
8003 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
8005 // find unreachable code - must be fixed in IDA
8006 for (i = 0; i < opcnt; i++)
8008 if (cbits[i >> 3] & (1 << (i & 7)))
8011 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8012 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8014 // the compiler sometimes still generates code after
8015 // noreturn OS functions
8018 if (ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8019 ferr(&ops[i], "unreachable code\n");
8022 for (i = 0; i < g_eqcnt; i++) {
8023 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8024 max_bp_offset = g_eqs[i].offset;
8027 if (fp->argc_stack < 0) {
8028 max_bp_offset = (max_bp_offset + 3) & ~3;
8029 fp->argc_stack = max_bp_offset / 4;
8030 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8034 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8035 fp->has_ret = has_ret;
8037 printf("// has_ret %d, regmask_dep %x\n",
8038 fp->has_ret, fp->regmask_dep);
8039 output_hdr_fp(stdout, fp, 1);
8040 if (IS(funcn, "sub_10007F72")) exit(1);
8043 gen_x_cleanup(opcnt);
8046 static void hg_fp_resolve_deps(struct func_prototype *fp)
8048 struct func_prototype fp_s;
8052 // this thing is recursive, so mark first..
8053 fp->dep_resolved = 1;
8055 for (i = 0; i < fp->dep_func_cnt; i++) {
8056 strcpy(fp_s.name, fp->dep_func[i].name);
8057 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8058 sizeof(hg_fp[0]), hg_fp_cmp_name);
8059 if (fp->dep_func[i].proto != NULL) {
8060 if (!fp->dep_func[i].proto->dep_resolved)
8061 hg_fp_resolve_deps(fp->dep_func[i].proto);
8063 dep = ~fp->dep_func[i].regmask_live
8064 & fp->dep_func[i].proto->regmask_dep;
8065 fp->regmask_dep |= dep;
8066 // printf("dep %s %s |= %x\n", fp->name,
8067 // fp->dep_func[i].name, dep);
8069 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8070 fp->has_ret = fp->dep_func[i].proto->has_ret;
8075 // make all thiscall/edx arg functions referenced from .data fastcall
8076 static void do_func_refs_from_data(void)
8078 struct func_prototype *fp, fp_s;
8081 for (i = 0; i < hg_ref_cnt; i++) {
8082 strcpy(fp_s.name, hg_refs[i]);
8083 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8084 sizeof(hg_fp[0]), hg_fp_cmp_name);
8088 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8089 fp->regmask_dep |= mxCX | mxDX;
8093 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8096 const struct parsed_proto *pp;
8097 char *p, namebuf[NAMELEN];
8103 for (; count > 0; count--, fp++) {
8104 if (fp->has_ret == -1)
8105 fprintf(fout, "// ret unresolved\n");
8107 fprintf(fout, "// dep:");
8108 for (j = 0; j < fp->dep_func_cnt; j++) {
8109 fprintf(fout, " %s/", fp->dep_func[j].name);
8110 if (fp->dep_func[j].proto != NULL)
8111 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8112 fp->dep_func[j].proto->has_ret);
8114 fprintf(fout, "\n");
8117 p = strchr(fp->name, '@');
8119 memcpy(namebuf, fp->name, p - fp->name);
8120 namebuf[p - fp->name] = 0;
8128 pp = proto_parse(g_fhdr, name, 1);
8129 if (pp != NULL && pp->is_include)
8132 if (fp->pp != NULL) {
8133 // part of seed, output later
8137 regmask_dep = fp->regmask_dep;
8138 argc_normal = fp->argc_stack;
8140 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8141 (fp->has_ret ? "int" : "void"));
8142 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8143 && (regmask_dep & ~mxCX) == 0)
8145 fprintf(fout, "/*__thiscall*/ ");
8149 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8150 && (regmask_dep & ~(mxCX | mxDX)) == 0)
8152 fprintf(fout, " __fastcall ");
8153 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8159 else if (regmask_dep && !fp->is_stdcall) {
8160 fprintf(fout, "/*__usercall*/ ");
8162 else if (regmask_dep) {
8163 fprintf(fout, "/*__userpurge*/ ");
8165 else if (fp->is_stdcall)
8166 fprintf(fout, " __stdcall ");
8168 fprintf(fout, " __cdecl ");
8170 fprintf(fout, "%s(", name);
8173 for (j = 0; j < xSP; j++) {
8174 if (regmask_dep & (1 << j)) {
8177 fprintf(fout, ", ");
8179 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8181 fprintf(fout, "int");
8182 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8186 for (j = 0; j < argc_normal; j++) {
8189 fprintf(fout, ", ");
8190 if (fp->pp != NULL) {
8191 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8192 if (!fp->pp->arg[arg - 1].type.is_ptr)
8196 fprintf(fout, "int ");
8197 fprintf(fout, "a%d", arg);
8200 fprintf(fout, ");\n");
8204 static void output_hdr(FILE *fout)
8206 static const char *lmod_c_names[] = {
8207 [OPLM_UNSPEC] = "???",
8208 [OPLM_BYTE] = "uint8_t",
8209 [OPLM_WORD] = "uint16_t",
8210 [OPLM_DWORD] = "uint32_t",
8211 [OPLM_QWORD] = "uint64_t",
8213 const struct scanned_var *var;
8214 struct func_prototype *fp;
8215 char line[256] = { 0, };
8219 // add stuff from headers
8220 for (i = 0; i < pp_cache_size; i++) {
8221 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8222 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8224 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8225 fp = hg_fp_add(name);
8226 fp->pp = &pp_cache[i];
8227 fp->argc_stack = fp->pp->argc_stack;
8228 fp->is_stdcall = fp->pp->is_stdcall;
8229 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8230 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8234 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8235 for (i = 0; i < hg_fp_cnt; i++)
8236 hg_fp_resolve_deps(&hg_fp[i]);
8238 // adjust functions referenced from data segment
8239 do_func_refs_from_data();
8241 // note: messes up .proto ptr, don't use
8242 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8245 for (i = 0; i < hg_var_cnt; i++) {
8248 if (var->pp != NULL)
8251 else if (var->is_c_str)
8252 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8254 fprintf(fout, "extern %-8s %s;",
8255 lmod_c_names[var->lmod], var->name);
8258 fprintf(fout, " // seeded");
8259 fprintf(fout, "\n");
8262 fprintf(fout, "\n");
8264 // output function prototypes
8265 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8268 fprintf(fout, "\n// - seed -\n");
8271 while (fgets(line, sizeof(line), g_fhdr))
8272 fwrite(line, 1, strlen(line), fout);
8275 // '=' needs special treatment
8277 static char *next_word_s(char *w, size_t wsize, char *s)
8284 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8286 for (i = 1; i < wsize - 1; i++) {
8288 printf("warning: missing closing quote: \"%s\"\n", s);
8297 for (; i < wsize - 1; i++) {
8298 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8304 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8305 printf("warning: '%s' truncated\n", w);
8310 static int cmpstringp(const void *p1, const void *p2)
8312 return strcmp(*(char * const *)p1, *(char * const *)p2);
8315 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8320 if (strstr(p, "..."))
8321 // unable to determine, assume needed
8324 if (*p == '.') // .text, .data, ...
8325 // ref from other data or non-function -> no
8328 p2 = strpbrk(p, "+:\r\n\x18");
8331 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8332 // referenced from removed code
8338 static int ida_xrefs_show_need(FILE *fasm, char *p,
8339 char **rlist, int rlist_len)
8345 p = strrchr(p, ';');
8346 if (p != NULL && *p == ';') {
8347 if (IS_START(p + 2, "sctref"))
8349 if (IS_START(p + 2, "DATA XREF: ")) {
8351 if (is_xref_needed(p, rlist, rlist_len))
8359 if (!my_fgets(line, sizeof(line), fasm))
8361 // non-first line is always indented
8362 if (!my_isblank(line[0]))
8365 // should be no content, just comment
8370 p = strrchr(p, ';');
8373 if (IS_START(p, "sctref")) {
8378 // it's printed once, but no harm to check again
8379 if (IS_START(p, "DATA XREF: "))
8382 if (is_xref_needed(p, rlist, rlist_len)) {
8387 fseek(fasm, pos, SEEK_SET);
8391 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8393 struct scanned_var *var;
8394 char line[256] = { 0, };
8403 // skip to next data section
8404 while (my_fgets(line, sizeof(line), fasm))
8409 if (*p == 0 || *p == ';')
8412 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8413 if (*p == 0 || *p == ';')
8416 if (*p != 's' || !IS_START(p, "segment para public"))
8422 if (p == NULL || !IS_START(p, "segment para public"))
8426 if (!IS_START(p, "'DATA'"))
8430 while (my_fgets(line, sizeof(line), fasm))
8435 no_identifier = my_isblank(*p);
8438 if (*p == 0 || *p == ';')
8441 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8442 words[wordc][0] = 0;
8443 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8444 if (*p == 0 || *p == ';') {
8450 if (wordc == 2 && IS(words[1], "ends"))
8455 if (no_identifier) {
8456 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8457 hg_ref_add(words[2]);
8461 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8462 // when this starts, we don't need anything from this section
8466 // check refs comment(s)
8467 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8470 if ((hg_var_cnt & 0xff) == 0) {
8471 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8472 * (hg_var_cnt + 0x100));
8473 my_assert_not(hg_vars, NULL);
8474 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8477 var = &hg_vars[hg_var_cnt++];
8478 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8480 // maybe already in seed header?
8481 var->pp = proto_parse(g_fhdr, var->name, 1);
8482 if (var->pp != NULL) {
8483 if (var->pp->is_fptr) {
8484 var->lmod = OPLM_DWORD;
8487 else if (var->pp->is_func)
8489 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8490 aerr("unhandled C type '%s' for '%s'\n",
8491 var->pp->type.name, var->name);
8497 if (IS(words[1], "dd")) {
8498 var->lmod = OPLM_DWORD;
8499 if (wordc >= 4 && IS(words[2], "offset"))
8500 hg_ref_add(words[3]);
8502 else if (IS(words[1], "dw"))
8503 var->lmod = OPLM_WORD;
8504 else if (IS(words[1], "db")) {
8505 var->lmod = OPLM_BYTE;
8506 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8507 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8511 else if (IS(words[1], "dq"))
8512 var->lmod = OPLM_QWORD;
8513 //else if (IS(words[1], "dt"))
8515 aerr("type '%s' not known\n", words[1]);
8523 static void set_label(int i, const char *name)
8529 p = strchr(name, ':');
8533 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8534 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8535 g_labels[i] = realloc(g_labels[i], len + 1);
8536 my_assert_not(g_labels[i], NULL);
8537 memcpy(g_labels[i], name, len);
8538 g_labels[i][len] = 0;
8547 static struct chunk_item *func_chunks;
8548 static int func_chunk_cnt;
8549 static int func_chunk_alloc;
8551 static void add_func_chunk(FILE *fasm, const char *name, int line)
8553 if (func_chunk_cnt >= func_chunk_alloc) {
8554 func_chunk_alloc *= 2;
8555 func_chunks = realloc(func_chunks,
8556 func_chunk_alloc * sizeof(func_chunks[0]));
8557 my_assert_not(func_chunks, NULL);
8559 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8560 func_chunks[func_chunk_cnt].name = strdup(name);
8561 func_chunks[func_chunk_cnt].asmln = line;
8565 static int cmp_chunks(const void *p1, const void *p2)
8567 const struct chunk_item *c1 = p1, *c2 = p2;
8568 return strcmp(c1->name, c2->name);
8571 static void scan_ahead_for_chunks(FILE *fasm)
8581 oldpos = ftell(fasm);
8584 while (my_fgets(line, sizeof(line), fasm))
8595 // get rid of random tabs
8596 for (i = 0; line[i] != 0; i++)
8597 if (line[i] == '\t')
8600 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8603 next_word(words[0], sizeof(words[0]), p);
8604 if (words[0][0] == 0)
8605 aerr("missing name for func chunk?\n");
8607 add_func_chunk(fasm, words[0], asmln);
8609 else if (IS_START(p, "; sctend"))
8615 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8616 words[wordc][0] = 0;
8617 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8618 if (*p == 0 || *p == ';') {
8624 if (wordc == 2 && IS(words[1], "ends"))
8628 fseek(fasm, oldpos, SEEK_SET);
8632 int main(int argc, char *argv[])
8634 FILE *fout, *fasm, *frlist;
8635 struct parsed_data *pd = NULL;
8637 char **rlist = NULL;
8639 int rlist_alloc = 0;
8640 int func_chunks_used = 0;
8641 int func_chunks_sorted = 0;
8642 int func_chunk_i = -1;
8643 long func_chunk_ret = 0;
8644 int func_chunk_ret_ln = 0;
8645 int scanned_ahead = 0;
8647 char words[20][256];
8648 enum opr_lenmod lmod;
8649 char *sctproto = NULL;
8651 int pending_endp = 0;
8653 int skip_code_end = 0;
8654 int skip_warned = 0;
8667 for (arg = 1; arg < argc; arg++) {
8668 if (IS(argv[arg], "-v"))
8670 else if (IS(argv[arg], "-rf"))
8671 g_allow_regfunc = 1;
8672 else if (IS(argv[arg], "-uc"))
8673 g_allow_user_icall = 1;
8674 else if (IS(argv[arg], "-m"))
8676 else if (IS(argv[arg], "-hdr"))
8677 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8682 if (argc < arg + 3) {
8683 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8684 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8686 " -hdr - header generation mode\n"
8687 " -rf - allow unannotated indirect calls\n"
8688 " -uc - allow ind. calls/refs to __usercall\n"
8689 " -m - allow multiple .text sections\n"
8690 "[rlist] is a file with function names to skip,"
8698 asmfn = argv[arg++];
8699 fasm = fopen(asmfn, "r");
8700 my_assert_not(fasm, NULL);
8702 hdrfn = argv[arg++];
8703 g_fhdr = fopen(hdrfn, "r");
8704 my_assert_not(g_fhdr, NULL);
8707 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8708 my_assert_not(rlist, NULL);
8709 // needs special handling..
8710 rlist[rlist_len++] = "__alloca_probe";
8712 func_chunk_alloc = 32;
8713 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8714 my_assert_not(func_chunks, NULL);
8716 memset(words, 0, sizeof(words));
8718 for (; arg < argc; arg++) {
8721 frlist = fopen(argv[arg], "r");
8722 my_assert_not(frlist, NULL);
8724 while (my_fgets(line, sizeof(line), frlist)) {
8726 if (*p == 0 || *p == ';')
8729 if (IS_START(p, "#if 0")
8730 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
8734 else if (IS_START(p, "#endif"))
8741 p = next_word(words[0], sizeof(words[0]), p);
8742 if (words[0][0] == 0)
8745 if (rlist_len >= rlist_alloc) {
8746 rlist_alloc = rlist_alloc * 2 + 64;
8747 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
8748 my_assert_not(rlist, NULL);
8750 rlist[rlist_len++] = strdup(words[0]);
8758 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
8760 fout = fopen(argv[arg_out], "w");
8761 my_assert_not(fout, NULL);
8764 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
8765 my_assert_not(g_eqs, NULL);
8767 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
8768 g_label_refs[i].i = -1;
8769 g_label_refs[i].next = NULL;
8773 scan_variables(fasm, rlist, rlist_len);
8775 while (my_fgets(line, sizeof(line), fasm))
8784 // get rid of random tabs
8785 for (i = 0; line[i] != 0; i++)
8786 if (line[i] == '\t')
8791 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
8792 goto do_pending_endp; // eww..
8794 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
8796 static const char *attrs[] = {
8805 // parse IDA's attribute-list comment
8806 g_ida_func_attr = 0;
8809 for (; *p != 0; p = sskip(p)) {
8810 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8811 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8812 g_ida_func_attr |= 1 << i;
8813 p += strlen(attrs[i]);
8817 if (i == ARRAY_SIZE(attrs)) {
8818 anote("unparsed IDA attr: %s\n", p);
8821 if (IS(attrs[i], "fpd=")) {
8822 p = next_word(words[0], sizeof(words[0]), p);
8827 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
8829 static const char *attrs[] = {
8834 // parse manual attribute-list comment
8835 g_sct_func_attr = 0;
8838 for (; *p != 0; p = sskip(p)) {
8839 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8840 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8841 g_sct_func_attr |= 1 << i;
8842 p += strlen(attrs[i]);
8849 // clear_sf=start,len (in dwords)
8850 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
8851 &g_stack_clear_len, &j);
8853 // clear_regmask=<mask>
8854 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
8856 anote("unparsed attr value: %s\n", p);
8861 else if (i == ARRAY_SIZE(attrs)) {
8862 anote("unparsed sct attr: %s\n", p);
8867 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8870 next_word(words[0], sizeof(words[0]), p);
8871 if (words[0][0] == 0)
8872 aerr("missing name for func chunk?\n");
8874 if (!scanned_ahead) {
8875 add_func_chunk(fasm, words[0], asmln);
8876 func_chunks_sorted = 0;
8879 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
8881 if (func_chunk_i >= 0) {
8882 if (func_chunk_i < func_chunk_cnt
8883 && IS(func_chunks[func_chunk_i].name, g_func))
8885 // move on to next chunk
8886 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8888 aerr("seek failed for '%s' chunk #%d\n",
8889 g_func, func_chunk_i);
8890 asmln = func_chunks[func_chunk_i].asmln;
8894 if (func_chunk_ret == 0)
8895 aerr("no return from chunk?\n");
8896 fseek(fasm, func_chunk_ret, SEEK_SET);
8897 asmln = func_chunk_ret_ln;
8903 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
8904 func_chunks_used = 1;
8906 if (IS_START(g_func, "sub_")) {
8907 unsigned long addr = strtoul(p, NULL, 16);
8908 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
8909 if (addr > f_addr && !scanned_ahead) {
8910 //anote("scan_ahead caused by '%s', addr %lx\n",
8912 scan_ahead_for_chunks(fasm);
8914 func_chunks_sorted = 0;
8922 for (i = wordc; i < ARRAY_SIZE(words); i++)
8924 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8925 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8926 if (*p == 0 || *p == ';') {
8931 if (*p != 0 && *p != ';')
8932 aerr("too many words\n");
8934 if (skip_code_end) {
8939 // allow asm patches in comments
8941 if (IS_START(p, "; sctpatch:")) {
8943 if (*p == 0 || *p == ';')
8945 goto parse_words; // lame
8947 if (IS_START(p, "; sctproto:")) {
8948 sctproto = strdup(p + 11);
8950 else if (IS_START(p, "; sctend")) {
8955 else if (IS_START(p, "; sctskip_start")) {
8956 if (in_func && !g_skip_func) {
8958 ops[pi].op = OPP_ABORT;
8959 ops[pi].asmln = asmln;
8965 else if (IS_START(p, "; sctskip_end")) {
8973 awarn("wordc == 0?\n");
8977 // don't care about this:
8978 if (words[0][0] == '.'
8979 || IS(words[0], "include")
8980 || IS(words[0], "assume") || IS(words[1], "segment")
8981 || IS(words[0], "align"))
8987 // do delayed endp processing to collect switch jumptables
8989 if (in_func && !g_skip_func && !end && wordc >= 2
8990 && ((words[0][0] == 'd' && words[0][2] == 0)
8991 || (words[1][0] == 'd' && words[1][2] == 0)))
8994 if (words[1][0] == 'd' && words[1][2] == 0) {
8996 if (g_func_pd_cnt >= pd_alloc) {
8997 pd_alloc = pd_alloc * 2 + 16;
8998 g_func_pd = realloc(g_func_pd,
8999 sizeof(g_func_pd[0]) * pd_alloc);
9000 my_assert_not(g_func_pd, NULL);
9002 pd = &g_func_pd[g_func_pd_cnt];
9004 memset(pd, 0, sizeof(*pd));
9005 strcpy(pd->label, words[0]);
9006 pd->type = OPT_CONST;
9007 pd->lmod = lmod_from_directive(words[1]);
9013 anote("skipping alignment byte?\n");
9016 lmod = lmod_from_directive(words[0]);
9017 if (lmod != pd->lmod)
9018 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9021 if (pd->count_alloc < pd->count + wordc) {
9022 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9023 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9024 my_assert_not(pd->d, NULL);
9026 for (; i < wordc; i++) {
9027 if (IS(words[i], "offset")) {
9028 pd->type = OPT_OFFSET;
9031 p = strchr(words[i], ',');
9034 if (pd->type == OPT_OFFSET)
9035 pd->d[pd->count].u.label = strdup(words[i]);
9037 pd->d[pd->count].u.val = parse_number(words[i], 0);
9038 pd->d[pd->count].bt_i = -1;
9044 if (in_func && !g_skip_func) {
9046 gen_hdr(g_func, pi);
9048 gen_func(fout, g_fhdr, g_func, pi);
9053 g_ida_func_attr = 0;
9054 g_sct_func_attr = 0;
9055 g_stack_clear_start = 0;
9056 g_stack_clear_len = 0;
9061 func_chunks_used = 0;
9064 memset(&ops, 0, pi * sizeof(ops[0]));
9069 for (i = 0; i < g_func_pd_cnt; i++) {
9071 if (pd->type == OPT_OFFSET) {
9072 for (j = 0; j < pd->count; j++)
9073 free(pd->d[j].u.label);
9088 if (IS(words[1], "proc")) {
9090 aerr("proc '%s' while in_func '%s'?\n",
9093 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9095 strcpy(g_func, words[0]);
9096 set_label(0, words[0]);
9101 if (IS(words[1], "endp"))
9104 aerr("endp '%s' while not in_func?\n", words[0]);
9105 if (!IS(g_func, words[0]))
9106 aerr("endp '%s' while in_func '%s'?\n",
9109 aerr("endp '%s' while skipping code\n", words[0]);
9111 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9112 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
9118 if (!g_skip_func && func_chunks_used) {
9119 // start processing chunks
9120 struct chunk_item *ci, key = { g_func, 0 };
9122 func_chunk_ret = ftell(fasm);
9123 func_chunk_ret_ln = asmln;
9124 if (!func_chunks_sorted) {
9125 qsort(func_chunks, func_chunk_cnt,
9126 sizeof(func_chunks[0]), cmp_chunks);
9127 func_chunks_sorted = 1;
9129 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9130 sizeof(func_chunks[0]), cmp_chunks);
9132 aerr("'%s' needs chunks, but none found\n", g_func);
9133 func_chunk_i = ci - func_chunks;
9134 for (; func_chunk_i > 0; func_chunk_i--)
9135 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9138 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9140 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9141 asmln = func_chunks[func_chunk_i].asmln;
9149 if (wordc == 2 && IS(words[1], "ends")) {
9153 goto do_pending_endp;
9157 // scan for next text segment
9158 while (my_fgets(line, sizeof(line), fasm)) {
9161 if (*p == 0 || *p == ';')
9164 if (strstr(p, "segment para public 'CODE' use32"))
9171 p = strchr(words[0], ':');
9173 set_label(pi, words[0]);
9177 if (!in_func || g_skip_func || skip_code) {
9178 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9180 anote("skipping from '%s'\n", g_labels[pi]);
9184 g_labels[pi] = NULL;
9188 if (wordc > 1 && IS(words[1], "="))
9191 aerr("unhandled equ, wc=%d\n", wordc);
9192 if (g_eqcnt >= eq_alloc) {
9194 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9195 my_assert_not(g_eqs, NULL);
9198 len = strlen(words[0]);
9199 if (len > sizeof(g_eqs[0].name) - 1)
9200 aerr("equ name too long: %d\n", len);
9201 strcpy(g_eqs[g_eqcnt].name, words[0]);
9203 if (!IS(words[3], "ptr"))
9204 aerr("unhandled equ\n");
9205 if (IS(words[2], "dword"))
9206 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9207 else if (IS(words[2], "word"))
9208 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9209 else if (IS(words[2], "byte"))
9210 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9211 else if (IS(words[2], "qword"))
9212 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9214 aerr("bad lmod: '%s'\n", words[2]);
9216 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9221 if (pi >= ARRAY_SIZE(ops))
9222 aerr("too many ops\n");
9224 parse_op(&ops[pi], words, wordc);
9226 ops[pi].datap = sctproto;
9241 // vim:ts=2:shiftwidth=2:expandtab