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)
4071 if (i < opcnt && ops[i].op == OP_CALL
4072 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4074 // noreturn tailcall with no epilogue
4079 ferr(&ops[j], "'add esp' expected\n");
4082 if (ops[j].operand[1].val < g_stack_fsz)
4083 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4085 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4086 if (ops[j].operand[1].val == 0)
4087 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4092 } while (i < opcnt);
4095 ferr(ops, "missing esp epilogue\n");
4099 // find an instruction that changed opr before i op
4100 // *op_i must be set to -1 by the caller
4101 // *is_caller is set to 1 if one source is determined to be g_func arg
4102 // returns 1 if found, *op_i is then set to origin
4103 // returns -1 if multiple origins are found
4104 static int resolve_origin(int i, const struct parsed_opr *opr,
4105 int magic, int *op_i, int *is_caller)
4107 struct label_ref *lr;
4111 if (g_labels[i] != NULL) {
4112 lr = &g_label_refs[i];
4113 for (; lr != NULL; lr = lr->next) {
4114 check_i(&ops[i], lr->i);
4115 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4117 if (i > 0 && LAST_OP(i - 1))
4123 if (is_caller != NULL)
4128 if (ops[i].cc_scratch == magic)
4130 ops[i].cc_scratch = magic;
4132 if (!(ops[i].flags & OPF_DATA))
4134 if (!is_opr_modified(opr, &ops[i]))
4138 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4149 // find an instruction that previously referenced opr
4150 // if multiple results are found - fail
4151 // *op_i must be set to -1 by the caller
4152 // returns 1 if found, *op_i is then set to referencer insn
4153 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4154 int magic, int *op_i)
4156 struct label_ref *lr;
4160 if (g_labels[i] != NULL) {
4161 lr = &g_label_refs[i];
4162 for (; lr != NULL; lr = lr->next) {
4163 check_i(&ops[i], lr->i);
4164 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4166 if (i > 0 && LAST_OP(i - 1))
4174 if (ops[i].cc_scratch == magic)
4176 ops[i].cc_scratch = magic;
4178 if (!is_opr_referenced(opr, &ops[i]))
4189 // adjust datap of all reachable 'op' insns when moving back
4190 // returns 1 if at least 1 op was found
4191 // returns -1 if path without an op was found
4192 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4194 struct label_ref *lr;
4197 if (ops[i].cc_scratch == magic)
4199 ops[i].cc_scratch = magic;
4202 if (g_labels[i] != NULL) {
4203 lr = &g_label_refs[i];
4204 for (; lr != NULL; lr = lr->next) {
4205 check_i(&ops[i], lr->i);
4206 ret |= adjust_prev_op(lr->i, op, magic, datap);
4208 if (i > 0 && LAST_OP(i - 1))
4216 if (ops[i].cc_scratch == magic)
4218 ops[i].cc_scratch = magic;
4220 if (ops[i].op != op)
4223 ops[i].datap = datap;
4228 // find next instruction that reads opr
4229 // *op_i must be set to -1 by the caller
4230 // on return, *op_i is set to first referencer insn
4231 // returns 1 if exactly 1 referencer is found
4232 static int find_next_read(int i, int opcnt,
4233 const struct parsed_opr *opr, int magic, int *op_i)
4235 struct parsed_op *po;
4238 for (; i < opcnt; i++)
4240 if (ops[i].cc_scratch == magic)
4242 ops[i].cc_scratch = magic;
4245 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4246 if (po->btj != NULL) {
4248 for (j = 0; j < po->btj->count; j++) {
4249 check_i(po, po->btj->d[j].bt_i);
4250 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4256 if (po->flags & OPF_RMD)
4258 check_i(po, po->bt_i);
4259 if (po->flags & OPF_CJMP) {
4260 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4269 if (!is_opr_read(opr, po)) {
4271 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4272 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4274 full_opr = po->operand[0].lmod >= opr->lmod;
4276 if (is_opr_modified(opr, po) && full_opr) {
4280 if (po->flags & OPF_TAIL)
4295 // find next instruction that reads opr
4296 // *op_i must be set to -1 by the caller
4297 // on return, *op_i is set to first flag user insn
4298 // returns 1 if exactly 1 flag user is found
4299 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4301 struct parsed_op *po;
4304 for (; i < opcnt; i++)
4306 if (ops[i].cc_scratch == magic)
4308 ops[i].cc_scratch = magic;
4311 if (po->op == OP_CALL)
4313 if (po->flags & OPF_JMP) {
4314 if (po->btj != NULL) {
4316 for (j = 0; j < po->btj->count; j++) {
4317 check_i(po, po->btj->d[j].bt_i);
4318 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4324 if (po->flags & OPF_RMD)
4326 check_i(po, po->bt_i);
4327 if (po->flags & OPF_CJMP)
4334 if (!(po->flags & OPF_CC)) {
4335 if (po->flags & OPF_FLAGS)
4338 if (po->flags & OPF_TAIL)
4354 static int try_resolve_const(int i, const struct parsed_opr *opr,
4355 int magic, unsigned int *val)
4360 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4363 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4366 *val = ops[i].operand[1].val;
4373 static int resolve_used_bits(int i, int opcnt, int reg,
4374 int *mask, int *is_z_check)
4376 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4380 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4384 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4386 fnote(&ops[j], "(first read)\n");
4387 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4390 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4391 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4393 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4394 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4396 *mask = ops[j].operand[1].val;
4397 if (ops[j].operand[0].lmod == OPLM_BYTE
4398 && ops[j].operand[0].name[1] == 'h')
4402 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4405 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4407 *is_z_check = ops[k].pfo == PFO_Z;
4412 static const struct parsed_proto *resolve_deref(int i, int magic,
4413 struct parsed_opr *opr, int level)
4415 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4416 const struct parsed_proto *pp = NULL;
4417 int from_caller = 0;
4426 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4427 if (ret != 2 || len != strlen(opr->name)) {
4428 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4429 if (ret != 1 || len != strlen(opr->name))
4433 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4438 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4442 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4443 && strlen(ops[j].operand[1].name) == 3
4444 && ops[j].operand[0].lmod == OPLM_DWORD
4445 && ops[j].pp == NULL // no hint
4448 // allow one simple dereference (com/directx)
4449 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4450 ops[j].operand[1].name);
4454 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4459 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4462 if (ops[j].pp != NULL) {
4466 else if (ops[j].operand[1].type == OPT_REGMEM) {
4467 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4469 // maybe structure ptr in structure
4470 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4473 else if (ops[j].operand[1].type == OPT_LABEL)
4474 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4475 else if (ops[j].operand[1].type == OPT_REG) {
4478 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4480 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4481 for (k = 0; k < g_func_pp->argc; k++) {
4482 if (g_func_pp->arg[k].reg == NULL)
4484 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4485 pp = g_func_pp->arg[k].pp;
4494 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4496 ferr(&ops[j], "expected struct, got '%s %s'\n",
4497 pp->type.name, pp->name);
4501 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
4504 static const struct parsed_proto *resolve_icall(int i, int opcnt,
4505 int *pp_i, int *multi_src)
4507 const struct parsed_proto *pp = NULL;
4508 int search_advice = 0;
4513 switch (ops[i].operand[0].type) {
4515 // try to resolve struct member calls
4516 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
4522 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
4528 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
4536 static struct parsed_proto *process_call_early(int i, int opcnt,
4539 struct parsed_op *po = &ops[i];
4540 struct parsed_proto *pp;
4546 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
4550 // look for and make use of esp adjust
4552 if (!pp->is_stdcall && pp->argc_stack > 0)
4553 ret = scan_for_esp_adjust(i + 1, opcnt,
4554 pp->argc_stack * 4, &adj, &multipath, 0);
4556 if (pp->argc_stack > adj / 4)
4560 if (ops[ret].op == OP_POP) {
4561 for (j = 1; j < adj / 4; j++) {
4562 if (ops[ret + j].op != OP_POP
4563 || ops[ret + j].operand[0].reg != xCX)
4575 static struct parsed_proto *process_call(int i, int opcnt)
4577 struct parsed_op *po = &ops[i];
4578 const struct parsed_proto *pp_c;
4579 struct parsed_proto *pp;
4580 const char *tmpname;
4581 int call_i = -1, ref_i = -1;
4582 int adj = 0, multipath = 0;
4585 tmpname = opr_name(po, 0);
4590 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
4592 if (!pp_c->is_func && !pp_c->is_fptr)
4593 ferr(po, "call to non-func: %s\n", pp_c->name);
4594 pp = proto_clone(pp_c);
4595 my_assert_not(pp, NULL);
4597 // not resolved just to single func
4600 switch (po->operand[0].type) {
4602 // we resolved this call and no longer need the register
4603 po->regmask_src &= ~(1 << po->operand[0].reg);
4605 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
4606 && ops[call_i].operand[1].type == OPT_LABEL)
4608 // no other source users?
4609 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
4611 if (ret == 1 && call_i == ref_i) {
4612 // and nothing uses it after us?
4614 find_next_read(i + 1, opcnt, &po->operand[0],
4615 i + opcnt * 11, &ref_i);
4617 // then also don't need the source mov
4618 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
4630 pp = calloc(1, sizeof(*pp));
4631 my_assert_not(pp, NULL);
4634 ret = scan_for_esp_adjust(i + 1, opcnt,
4635 -1, &adj, &multipath, 0);
4636 if (ret < 0 || adj < 0) {
4637 if (!g_allow_regfunc)
4638 ferr(po, "non-__cdecl indirect call unhandled yet\n");
4639 pp->is_unresolved = 1;
4643 if (adj > ARRAY_SIZE(pp->arg))
4644 ferr(po, "esp adjust too large: %d\n", adj);
4645 pp->ret_type.name = strdup("int");
4646 pp->argc = pp->argc_stack = adj;
4647 for (arg = 0; arg < pp->argc; arg++)
4648 pp->arg[arg].type.name = strdup("int");
4653 // look for and make use of esp adjust
4656 if (!pp->is_stdcall && pp->argc_stack > 0) {
4657 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
4658 ret = scan_for_esp_adjust(i + 1, opcnt,
4659 adj_expect, &adj, &multipath, 0);
4662 if (pp->is_vararg) {
4663 if (adj / 4 < pp->argc_stack) {
4664 fnote(po, "(this call)\n");
4665 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
4666 adj, pp->argc_stack * 4);
4668 // modify pp to make it have varargs as normal args
4670 pp->argc += adj / 4 - pp->argc_stack;
4671 for (; arg < pp->argc; arg++) {
4672 pp->arg[arg].type.name = strdup("int");
4675 if (pp->argc > ARRAY_SIZE(pp->arg))
4676 ferr(po, "too many args for '%s'\n", tmpname);
4678 if (pp->argc_stack > adj / 4) {
4679 if (pp->is_noreturn)
4680 // assume no stack adjust was emited
4682 fnote(po, "(this call)\n");
4683 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
4684 tmpname, pp->argc_stack * 4, adj);
4687 scan_for_esp_adjust(i + 1, opcnt,
4688 pp->argc_stack * 4, &adj, &multipath, 1);
4690 else if (pp->is_vararg)
4691 ferr(po, "missing esp_adjust for vararg func '%s'\n",
4698 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
4701 struct parsed_op *po;
4707 for (base_arg = 0; base_arg < pp->argc; base_arg++)
4708 if (pp->arg[base_arg].reg == NULL)
4711 for (j = i; j > 0; )
4713 ferr_assert(&ops[j], g_labels[j] == NULL);
4717 ferr_assert(po, po->op != OP_PUSH);
4718 if (po->op == OP_FST)
4720 if (po->operand[0].type != OPT_REGMEM)
4722 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
4725 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
4726 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
4730 arg = base_arg + offset / 4;
4732 po->p_argnum = arg + 1;
4733 ferr_assert(po, pp->arg[arg].datap == NULL);
4734 pp->arg[arg].datap = po;
4735 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
4736 if (regmask_ffca != NULL)
4737 *regmask_ffca |= 1 << arg;
4739 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4740 && po->operand[1].type == OPT_CONST)
4742 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4747 for (arg = base_arg; arg < pp->argc; arg++) {
4748 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
4749 po = pp->arg[arg].datap;
4751 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
4752 if (po->operand[0].lmod == OPLM_QWORD)
4759 static int collect_call_args_early(int i, struct parsed_proto *pp,
4760 int *regmask, int *regmask_ffca)
4762 struct parsed_op *po;
4766 for (arg = 0; arg < pp->argc; arg++)
4767 if (pp->arg[arg].reg == NULL)
4770 // first see if it can be easily done
4771 for (j = i; j > 0 && arg < pp->argc; )
4773 if (g_labels[j] != NULL)
4778 if (po->op == OP_CALL)
4780 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
4782 else if (po->op == OP_POP)
4784 else if (po->flags & OPF_CJMP)
4786 else if (po->op == OP_PUSH) {
4787 if (po->flags & (OPF_FARG|OPF_FARGNR))
4789 if (!g_header_mode) {
4790 ret = scan_for_mod(po, j + 1, i, 1);
4795 if (pp->arg[arg].type.is_va_list)
4799 for (arg++; arg < pp->argc; arg++)
4800 if (pp->arg[arg].reg == NULL)
4803 else if (po->op == OP_SUB && po->operand[0].reg == xSP
4804 && po->operand[1].type == OPT_CONST)
4806 if (po->flags & (OPF_RMD|OPF_DONE))
4808 if (po->operand[1].val != pp->argc_stack * 4)
4809 ferr(po, "unexpected esp adjust: %d\n",
4810 po->operand[1].val * 4);
4811 ferr_assert(po, pp->argc - arg == pp->argc_stack);
4812 return collect_call_args_no_push(i, pp, regmask_ffca);
4820 for (arg = 0; arg < pp->argc; arg++)
4821 if (pp->arg[arg].reg == NULL)
4824 for (j = i; j > 0 && arg < pp->argc; )
4828 if (ops[j].op == OP_PUSH)
4830 ops[j].p_argnext = -1;
4831 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
4832 pp->arg[arg].datap = &ops[j];
4834 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
4835 *regmask |= 1 << ops[j].operand[0].reg;
4837 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
4838 ops[j].flags &= ~OPF_RSAVE;
4841 for (arg++; arg < pp->argc; arg++)
4842 if (pp->arg[arg].reg == NULL)
4850 static int sync_argnum(struct parsed_op *po, int argnum)
4852 struct parsed_op *po_tmp;
4854 // see if other branches don't have higher argnum
4855 for (po_tmp = po; po_tmp != NULL; ) {
4856 if (argnum < po_tmp->p_argnum)
4857 argnum = po_tmp->p_argnum;
4858 // note: p_argnext is active on current collect_call_args only
4859 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4862 // make all argnums consistent
4863 for (po_tmp = po; po_tmp != NULL; ) {
4864 if (po_tmp->p_argnum != 0)
4865 po_tmp->p_argnum = argnum;
4866 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
4872 static int collect_call_args_r(struct parsed_op *po, int i,
4873 struct parsed_proto *pp, int *regmask, int *arg_grp,
4874 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
4876 struct parsed_proto *pp_tmp;
4877 struct parsed_op *po_tmp;
4878 struct label_ref *lr;
4879 int need_to_save_current;
4880 int arg_grp_current = 0;
4881 int save_args_seen = 0;
4888 ferr(po, "dead label encountered\n");
4892 for (; arg < pp->argc; arg++, argnum++)
4893 if (pp->arg[arg].reg == NULL)
4895 magic = (magic & 0xffffff) | (arg << 24);
4897 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
4899 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
4900 if (ops[j].cc_scratch != magic) {
4901 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
4905 // ok: have already been here
4908 ops[j].cc_scratch = magic;
4910 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
4911 lr = &g_label_refs[j];
4912 if (lr->next != NULL)
4914 for (; lr->next; lr = lr->next) {
4915 check_i(&ops[j], lr->i);
4916 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4918 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4919 arg, argnum, magic, need_op_saving, may_reuse);
4924 check_i(&ops[j], lr->i);
4925 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
4927 if (j > 0 && LAST_OP(j - 1)) {
4928 // follow last branch in reverse
4933 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
4934 arg, argnum, magic, need_op_saving, may_reuse);
4940 if (ops[j].op == OP_CALL)
4942 if (pp->is_unresolved)
4947 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
4948 arg, pp->argc, ops[j].operand[0].name);
4949 if (may_reuse && pp_tmp->argc_stack > 0)
4950 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
4951 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
4953 // esp adjust of 0 means we collected it before
4954 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
4955 && (ops[j].operand[1].type != OPT_CONST
4956 || ops[j].operand[1].val != 0))
4958 if (pp->is_unresolved)
4961 fnote(po, "(this call)\n");
4962 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
4963 arg, pp->argc, ops[j].operand[1].val);
4965 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
4967 if (pp->is_unresolved)
4970 fnote(po, "(this call)\n");
4971 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
4973 else if (ops[j].flags & OPF_CJMP)
4975 if (pp->is_unresolved)
4980 else if (ops[j].op == OP_PUSH
4981 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
4983 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
4986 ops[j].p_argnext = -1;
4987 po_tmp = pp->arg[arg].datap;
4989 ops[j].p_argnext = po_tmp - ops;
4990 pp->arg[arg].datap = &ops[j];
4992 argnum = sync_argnum(&ops[j], argnum);
4994 need_to_save_current = 0;
4996 if (ops[j].operand[0].type == OPT_REG)
4997 reg = ops[j].operand[0].reg;
4999 if (!need_op_saving) {
5000 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5001 need_to_save_current = (ret >= 0);
5003 if (need_op_saving || need_to_save_current) {
5004 // mark this arg as one that needs operand saving
5005 pp->arg[arg].is_saved = 1;
5007 if (save_args_seen & (1 << (argnum - 1))) {
5010 if (arg_grp_current >= MAX_ARG_GRP)
5011 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5015 else if (ops[j].p_argnum == 0)
5016 ops[j].flags |= OPF_RMD;
5018 // some PUSHes are reused by different calls on other branches,
5019 // but that can't happen if we didn't branch, so they
5020 // can be removed from future searches (handles nested calls)
5022 ops[j].flags |= OPF_FARGNR;
5024 ops[j].flags |= OPF_FARG;
5025 ops[j].flags &= ~OPF_RSAVE;
5027 // check for __VALIST
5028 if (!pp->is_unresolved && g_func_pp != NULL
5029 && pp->arg[arg].type.is_va_list)
5032 ret = resolve_origin(j, &ops[j].operand[0],
5033 magic + 1, &k, NULL);
5034 if (ret == 1 && k >= 0)
5036 if (ops[k].op == OP_LEA) {
5037 if (!g_func_pp->is_vararg)
5038 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5041 snprintf(buf, sizeof(buf), "arg_%X",
5042 g_func_pp->argc_stack * 4);
5043 if (strstr(ops[k].operand[1].name, buf)
5044 || strstr(ops[k].operand[1].name, "arglist"))
5046 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5047 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5048 pp->arg[arg].is_saved = 0;
5052 ferr(&ops[k], "va_list arg detection failed\n");
5054 // check for va_list from g_func_pp arg too
5055 else if (ops[k].op == OP_MOV
5056 && is_stack_access(&ops[k], &ops[k].operand[1]))
5058 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5059 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5061 ops[k].flags |= OPF_RMD | OPF_DONE;
5062 ops[j].flags |= OPF_RMD;
5063 ops[j].p_argpass = ret + 1;
5064 pp->arg[arg].is_saved = 0;
5071 if (pp->arg[arg].is_saved) {
5072 ops[j].flags &= ~OPF_RMD;
5073 ops[j].p_argnum = argnum;
5076 // tracking reg usage
5078 *regmask |= 1 << reg;
5082 if (!pp->is_unresolved) {
5084 for (; arg < pp->argc; arg++, argnum++)
5085 if (pp->arg[arg].reg == NULL)
5088 magic = (magic & 0xffffff) | (arg << 24);
5091 if (ops[j].p_arggrp > arg_grp_current) {
5093 arg_grp_current = ops[j].p_arggrp;
5095 if (ops[j].p_argnum > 0)
5096 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5099 if (arg < pp->argc) {
5100 ferr(po, "arg collect failed for '%s': %d/%d\n",
5101 pp->name, arg, pp->argc);
5105 if (arg_grp_current > *arg_grp)
5106 *arg_grp = arg_grp_current;
5111 static int collect_call_args(struct parsed_op *po, int i,
5112 struct parsed_proto *pp, int *regmask, int magic)
5114 // arg group is for cases when pushes for
5115 // multiple funcs are going on
5116 struct parsed_op *po_tmp;
5121 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5127 // propagate arg_grp
5128 for (a = 0; a < pp->argc; a++) {
5129 if (pp->arg[a].reg != NULL)
5132 po_tmp = pp->arg[a].datap;
5133 while (po_tmp != NULL) {
5134 po_tmp->p_arggrp = arg_grp;
5135 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5140 if (pp->is_unresolved) {
5142 pp->argc_stack += ret;
5143 for (a = 0; a < pp->argc; a++)
5144 if (pp->arg[a].type.name == NULL)
5145 pp->arg[a].type.name = strdup("int");
5151 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5152 int regmask_now, int *regmask,
5153 int regmask_save_now, int *regmask_save,
5154 int *regmask_init, int regmask_arg)
5156 struct parsed_op *po;
5164 for (; i < opcnt; i++)
5167 if (cbits[i >> 3] & (1 << (i & 7)))
5169 cbits[i >> 3] |= (1 << (i & 7));
5171 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5172 if (po->flags & (OPF_RMD|OPF_DONE))
5174 if (po->btj != NULL) {
5175 for (j = 0; j < po->btj->count; j++) {
5176 check_i(po, po->btj->d[j].bt_i);
5177 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5178 regmask_now, regmask, regmask_save_now, regmask_save,
5179 regmask_init, regmask_arg);
5184 check_i(po, po->bt_i);
5185 if (po->flags & OPF_CJMP)
5186 reg_use_pass(po->bt_i, opcnt, cbits,
5187 regmask_now, regmask, regmask_save_now, regmask_save,
5188 regmask_init, regmask_arg);
5194 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5195 && !g_func_pp->is_userstack
5196 && po->operand[0].type == OPT_REG)
5198 reg = po->operand[0].reg;
5199 ferr_assert(po, reg >= 0);
5202 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5203 if (regmask_now & (1 << reg)) {
5204 already_saved = regmask_save_now & (1 << reg);
5205 flags_set = OPF_RSAVE | OPF_DONE;
5208 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5210 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5211 reg, 0, 0, flags_set);
5214 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5216 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5221 ferr_assert(po, !already_saved);
5222 po->flags |= flags_set;
5224 if (regmask_now & (1 << reg)) {
5225 regmask_save_now |= (1 << reg);
5226 *regmask_save |= regmask_save_now;
5231 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5232 reg = po->operand[0].reg;
5233 ferr_assert(po, reg >= 0);
5235 if (regmask_save_now & (1 << reg))
5236 regmask_save_now &= ~(1 << reg);
5238 regmask_now &= ~(1 << reg);
5241 else if (po->op == OP_CALL) {
5242 if ((po->regmask_dst & (1 << xAX))
5243 && !(po->regmask_dst & (1 << xDX)))
5245 if (po->flags & OPF_TAIL)
5246 // don't need eax, will do "return f();" or "f(); return;"
5247 po->regmask_dst &= ~(1 << xAX);
5249 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
5251 find_next_read(i + 1, opcnt, &opr, i + opcnt * 17, &j);
5254 po->regmask_dst &= ~(1 << xAX);
5258 // not "full stack" mode and have something in stack
5259 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5260 ferr(po, "float stack is not empty on func call\n");
5263 if (po->flags & OPF_NOREGS)
5266 // if incomplete register is used, clear it on init to avoid
5267 // later use of uninitialized upper part in some situations
5268 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5269 && po->operand[0].lmod != OPLM_DWORD)
5271 reg = po->operand[0].reg;
5272 ferr_assert(po, reg >= 0);
5274 if (!(regmask_now & (1 << reg)))
5275 *regmask_init |= 1 << reg;
5278 regmask_op = po->regmask_src | po->regmask_dst;
5280 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5281 regmask_new &= ~(1 << xSP);
5282 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5283 regmask_new &= ~(1 << xBP);
5285 if (regmask_new != 0)
5286 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5288 if (regmask_op & (1 << xBP)) {
5289 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5290 if (po->regmask_dst & (1 << xBP))
5291 // compiler decided to drop bp frame and use ebp as scratch
5292 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5294 regmask_op &= ~(1 << xBP);
5298 if (po->flags & OPF_FPUSH) {
5299 if (regmask_now & mxST1)
5300 regmask_now |= mxSTa; // switch to "full stack" mode
5301 if (regmask_now & mxSTa)
5302 po->flags |= OPF_FSHIFT;
5303 if (!(regmask_now & mxST7_2)) {
5305 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5309 regmask_now |= regmask_op;
5310 *regmask |= regmask_now;
5313 if (po->flags & OPF_FPOP) {
5314 if ((regmask_now & mxSTa) == 0)
5315 ferr(po, "float pop on empty stack?\n");
5316 if (regmask_now & (mxST7_2 | mxST1))
5317 po->flags |= OPF_FSHIFT;
5318 if (!(regmask_now & mxST7_2)) {
5320 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5324 if (po->flags & OPF_TAIL) {
5325 if (!(regmask_now & mxST7_2)) {
5326 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5327 if (!(regmask_now & mxST0))
5328 ferr(po, "no st0 on float return, mask: %x\n",
5331 else if (regmask_now & mxST1_0)
5332 ferr(po, "float regs on tail: %x\n", regmask_now);
5335 // there is support for "conditional tailcall", sort of
5336 if (!(po->flags & OPF_CC))
5342 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5346 for (i = 0; i < pp->argc; i++)
5347 if (pp->arg[i].reg == NULL)
5351 memmove(&pp->arg[i + 1], &pp->arg[i],
5352 sizeof(pp->arg[0]) * pp->argc_stack);
5353 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5354 pp->arg[i].reg = strdup(reg);
5355 pp->arg[i].type.name = strdup("int");
5360 static void output_std_flags(FILE *fout, struct parsed_op *po,
5361 int *pfomask, const char *dst_opr_text)
5363 if (*pfomask & (1 << PFO_Z)) {
5364 fprintf(fout, "\n cond_z = (%s%s == 0);",
5365 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5366 *pfomask &= ~(1 << PFO_Z);
5368 if (*pfomask & (1 << PFO_S)) {
5369 fprintf(fout, "\n cond_s = (%s%s < 0);",
5370 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5371 *pfomask &= ~(1 << PFO_S);
5376 OPP_FORCE_NORETURN = (1 << 0),
5377 OPP_SIMPLE_ARGS = (1 << 1),
5378 OPP_ALIGN = (1 << 2),
5381 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5384 const char *cconv = "";
5386 if (pp->is_fastcall)
5387 cconv = "__fastcall ";
5388 else if (pp->is_stdcall && pp->argc_reg == 0)
5389 cconv = "__stdcall ";
5391 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5393 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5394 fprintf(fout, "noreturn ");
5397 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5402 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5406 output_pp_attrs(fout, pp, flags);
5409 fprintf(fout, "%s", pp->name);
5414 for (i = 0; i < pp->argc; i++) {
5416 fprintf(fout, ", ");
5417 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5418 && !(flags & OPP_SIMPLE_ARGS))
5421 output_pp(fout, pp->arg[i].pp, 0);
5423 else if (pp->arg[i].type.is_retreg) {
5424 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5427 fprintf(fout, "%s", pp->arg[i].type.name);
5429 fprintf(fout, " a%d", i + 1);
5432 if (pp->is_vararg) {
5434 fprintf(fout, ", ");
5435 fprintf(fout, "...");
5440 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
5446 snprintf(buf1, sizeof(buf1), "%d", grp);
5447 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
5452 static void gen_x_cleanup(int opcnt);
5454 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
5456 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
5457 struct parsed_opr *last_arith_dst = NULL;
5458 char buf1[256], buf2[256], buf3[256], cast[64];
5459 struct parsed_proto *pp, *pp_tmp;
5460 struct parsed_data *pd;
5461 int save_arg_vars[MAX_ARG_GRP] = { 0, };
5462 unsigned char cbits[MAX_OPS / 8];
5463 const char *float_type;
5464 const char *float_st0;
5465 const char *float_st1;
5466 int need_float_stack = 0;
5467 int need_float_sw = 0; // status word
5468 int need_tmp_var = 0;
5472 int label_pending = 0;
5473 int need_double = 0;
5474 int regmask_save = 0; // used regs saved/restored in this func
5475 int regmask_arg; // regs from this function args (fastcall, etc)
5476 int regmask_ret; // regs needed on ret
5477 int regmask_now; // temp
5478 int regmask_init = 0; // regs that need zero initialization
5479 int regmask_pp = 0; // regs used in complex push-pop graph
5480 int regmask_ffca = 0; // float function call args
5481 int regmask = 0; // used regs
5491 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
5492 g_stack_frame_used = 0;
5493 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
5494 regmask_init = g_regmask_init;
5496 g_func_pp = proto_parse(fhdr, funcn, 0);
5497 if (g_func_pp == NULL)
5498 ferr(ops, "proto_parse failed for '%s'\n", funcn);
5500 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
5501 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
5504 // - resolve all branches
5505 // - parse calls with labels
5506 resolve_branches_parse_calls(opcnt);
5509 // - handle ebp/esp frame, remove ops related to it
5510 scan_prologue_epilogue(opcnt);
5513 // - remove dead labels
5514 // - set regs needed at ret
5515 for (i = 0; i < opcnt; i++)
5517 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
5522 if (ops[i].op == OP_RET)
5523 ops[i].regmask_src |= regmask_ret;
5527 // - process trivial calls
5528 for (i = 0; i < opcnt; i++)
5531 if (po->flags & (OPF_RMD|OPF_DONE))
5534 if (po->op == OP_CALL)
5536 pp = process_call_early(i, opcnt, &j);
5538 if (!(po->flags & OPF_ATAIL)) {
5539 // since we know the args, try to collect them
5540 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
5548 // commit esp adjust
5549 if (ops[j].op != OP_POP)
5550 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
5552 for (l = 0; l < pp->argc_stack; l++)
5553 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
5557 if (strstr(pp->ret_type.name, "int64"))
5560 po->flags |= OPF_DONE;
5566 // - process calls, stage 2
5567 // - handle some push/pop pairs
5568 // - scan for STD/CLD, propagate DF
5569 // - try to resolve needed x87 status word bits
5570 for (i = 0; i < opcnt; i++)
5575 if (po->flags & OPF_RMD)
5578 if (po->op == OP_CALL)
5580 if (!(po->flags & OPF_DONE)) {
5581 pp = process_call(i, opcnt);
5583 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
5584 // since we know the args, collect them
5585 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5587 // for unresolved, collect after other passes
5591 ferr_assert(po, pp != NULL);
5593 po->regmask_src |= get_pp_arg_regmask_src(pp);
5594 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
5596 if (po->regmask_dst & mxST0)
5597 po->flags |= OPF_FPUSH;
5599 if (strstr(pp->ret_type.name, "int64"))
5605 if (po->flags & OPF_DONE)
5610 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
5611 && po->operand[0].type == OPT_CONST)
5613 scan_for_pop_const(i, opcnt, i + opcnt * 12);
5618 scan_pushes_for_pop(i, opcnt, ®mask_pp);
5622 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
5623 scan_propagate_df(i + 1, opcnt);
5628 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
5629 ferr(po, "TODO: fnstsw to mem\n");
5630 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
5632 ferr(po, "fnstsw resolve failed\n");
5633 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
5634 (void *)(long)(mask | (z_check << 16)));
5636 ferr(po, "failed to find fcom: %d\n", ret);
5645 // - find POPs for PUSHes, rm both
5646 // - scan for all used registers
5647 memset(cbits, 0, sizeof(cbits));
5648 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
5649 0, ®mask_save, ®mask_init, regmask_arg);
5651 need_float_stack = !!(regmask & mxST7_2);
5654 // - find flag set ops for their users
5655 // - do unresolved calls
5656 // - declare indirect functions
5657 // - other op specific processing
5658 for (i = 0; i < opcnt; i++)
5661 if (po->flags & (OPF_RMD|OPF_DONE))
5664 if (po->flags & OPF_CC)
5666 int setters[16], cnt = 0, branched = 0;
5668 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
5669 &branched, setters, &cnt);
5670 if (ret < 0 || cnt <= 0)
5671 ferr(po, "unable to trace flag setter(s)\n");
5672 if (cnt > ARRAY_SIZE(setters))
5673 ferr(po, "too many flag setters\n");
5675 for (j = 0; j < cnt; j++)
5677 tmp_op = &ops[setters[j]]; // flag setter
5680 // to get nicer code, we try to delay test and cmp;
5681 // if we can't because of operand modification, or if we
5682 // have arith op, or branch, make it calculate flags explicitly
5683 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
5685 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
5686 pfomask = 1 << po->pfo;
5688 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
5689 pfomask = 1 << po->pfo;
5692 // see if we'll be able to handle based on op result
5693 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
5694 && po->pfo != PFO_Z && po->pfo != PFO_S
5695 && po->pfo != PFO_P)
5697 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
5699 pfomask = 1 << po->pfo;
5702 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
5703 propagate_lmod(tmp_op, &tmp_op->operand[0],
5704 &tmp_op->operand[1]);
5705 if (tmp_op->operand[0].lmod == OPLM_DWORD)
5710 tmp_op->pfomask |= pfomask;
5711 cond_vars |= pfomask;
5713 // note: may overwrite, currently not a problem
5717 if (po->op == OP_RCL || po->op == OP_RCR
5718 || po->op == OP_ADC || po->op == OP_SBB)
5719 cond_vars |= 1 << PFO_C;
5725 cond_vars |= 1 << PFO_Z;
5729 if (po->operand[0].lmod == OPLM_DWORD)
5734 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
5739 // note: resolved non-reg calls are OPF_DONE already
5741 ferr_assert(po, pp != NULL);
5743 if (pp->is_unresolved) {
5744 int regmask_stack = 0;
5745 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
5747 // this is pretty rough guess:
5748 // see ecx and edx were pushed (and not their saved versions)
5749 for (arg = 0; arg < pp->argc; arg++) {
5750 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
5753 tmp_op = pp->arg[arg].datap;
5755 ferr(po, "parsed_op missing for arg%d\n", arg);
5756 if (tmp_op->operand[0].type == OPT_REG)
5757 regmask_stack |= 1 << tmp_op->operand[0].reg;
5760 if (!((regmask_stack & (1 << xCX))
5761 && (regmask_stack & (1 << xDX))))
5763 if (pp->argc_stack != 0
5764 || ((regmask | regmask_arg) & ((1 << xCX)|(1 << xDX))))
5766 pp_insert_reg_arg(pp, "ecx");
5767 pp->is_fastcall = 1;
5768 regmask_init |= 1 << xCX;
5769 regmask |= 1 << xCX;
5771 if (pp->argc_stack != 0
5772 || ((regmask | regmask_arg) & (1 << xDX)))
5774 pp_insert_reg_arg(pp, "edx");
5775 regmask_init |= 1 << xDX;
5776 regmask |= 1 << xDX;
5780 // note: __cdecl doesn't fall into is_unresolved category
5781 if (pp->argc_stack > 0)
5787 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
5789 // <var> = offset <something>
5790 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
5791 && !IS_START(po->operand[1].name, "off_"))
5793 if (!po->operand[0].pp->is_fptr)
5794 ferr(po, "%s not declared as fptr when it should be\n",
5795 po->operand[0].name);
5796 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
5797 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
5798 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
5799 fnote(po, "var: %s\n", buf1);
5800 fnote(po, "func: %s\n", buf2);
5801 ferr(po, "^ mismatch\n");
5809 if (po->operand[0].lmod == OPLM_DWORD) {
5810 // 32bit division is common, look for it
5811 if (po->op == OP_DIV)
5812 ret = scan_for_reg_clear(i, xDX);
5814 ret = scan_for_cdq_edx(i);
5816 po->flags |= OPF_32BIT;
5825 po->flags |= OPF_RMD | OPF_DONE;
5835 if (po->operand[0].lmod == OPLM_QWORD)
5845 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xDX);
5847 find_next_read(i + 1, opcnt, &opr, i + opcnt * 18, &j);
5849 po->flags |= OPF_32BIT;
5857 // this might need it's own pass...
5858 if (po->op != OP_FST && po->p_argnum > 0)
5859 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
5861 // correct for "full stack" mode late enable
5862 if ((po->flags & (OPF_PPUSH|OPF_FPOP)) && need_float_stack)
5863 po->flags |= OPF_FSHIFT;
5866 float_type = need_double ? "double" : "float";
5867 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
5868 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
5870 // output starts here
5872 // define userstack size
5873 if (g_func_pp->is_userstack) {
5874 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
5875 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
5876 fprintf(fout, "#endif\n");
5879 // the function itself
5880 ferr_assert(ops, !g_func_pp->is_fptr);
5881 output_pp(fout, g_func_pp,
5882 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
5883 fprintf(fout, "\n{\n");
5885 // declare indirect functions
5886 for (i = 0; i < opcnt; i++) {
5888 if (po->flags & OPF_RMD)
5891 if (po->op == OP_CALL) {
5894 ferr(po, "NULL pp\n");
5896 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
5897 if (pp->name[0] != 0) {
5898 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
5899 memcpy(pp->name, "i_", 2);
5901 // might be declared already
5903 for (j = 0; j < i; j++) {
5904 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
5905 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
5915 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
5918 output_pp(fout, pp, OPP_SIMPLE_ARGS);
5919 fprintf(fout, ";\n");
5924 // output LUTs/jumptables
5925 for (i = 0; i < g_func_pd_cnt; i++) {
5927 fprintf(fout, " static const ");
5928 if (pd->type == OPT_OFFSET) {
5929 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
5931 for (j = 0; j < pd->count; j++) {
5933 fprintf(fout, ", ");
5934 fprintf(fout, "&&%s", pd->d[j].u.label);
5938 fprintf(fout, "%s %s[] =\n { ",
5939 lmod_type_u(ops, pd->lmod), pd->label);
5941 for (j = 0; j < pd->count; j++) {
5943 fprintf(fout, ", ");
5944 fprintf(fout, "%u", pd->d[j].u.val);
5947 fprintf(fout, " };\n");
5951 // declare stack frame, va_arg
5953 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
5954 if (g_func_lmods & (1 << OPLM_WORD))
5955 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
5956 if (g_func_lmods & (1 << OPLM_BYTE))
5957 fprintf(fout, " u8 b[%d];", g_stack_fsz);
5958 if (g_func_lmods & (1 << OPLM_QWORD))
5959 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
5960 fprintf(fout, " } sf;\n");
5964 if (g_func_pp->is_userstack) {
5965 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
5966 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
5970 if (g_func_pp->is_vararg) {
5971 fprintf(fout, " va_list ap;\n");
5975 // declare arg-registers
5976 for (i = 0; i < g_func_pp->argc; i++) {
5977 if (g_func_pp->arg[i].reg != NULL) {
5978 reg = char_array_i(regs_r32,
5979 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
5980 if (regmask & (1 << reg)) {
5981 if (g_func_pp->arg[i].type.is_retreg)
5982 fprintf(fout, " u32 %s = *r_%s;\n",
5983 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
5985 fprintf(fout, " u32 %s = (u32)a%d;\n",
5986 g_func_pp->arg[i].reg, i + 1);
5989 if (g_func_pp->arg[i].type.is_retreg)
5990 ferr(ops, "retreg '%s' is unused?\n",
5991 g_func_pp->arg[i].reg);
5992 fprintf(fout, " // %s = a%d; // unused\n",
5993 g_func_pp->arg[i].reg, i + 1);
5999 // declare normal registers
6000 regmask_now = regmask & ~regmask_arg;
6001 regmask_now &= ~(1 << xSP);
6002 if (regmask_now & 0x00ff) {
6003 for (reg = 0; reg < 8; reg++) {
6004 if (regmask_now & (1 << reg)) {
6005 fprintf(fout, " u32 %s", regs_r32[reg]);
6006 if (regmask_init & (1 << reg))
6007 fprintf(fout, " = 0");
6008 fprintf(fout, ";\n");
6014 if (regmask_now & 0xff00) {
6015 for (reg = 8; reg < 16; reg++) {
6016 if (regmask_now & (1 << reg)) {
6017 fprintf(fout, " mmxr %s", regs_r32[reg]);
6018 if (regmask_init & (1 << reg))
6019 fprintf(fout, " = { 0, }");
6020 fprintf(fout, ";\n");
6026 if (need_float_stack) {
6027 fprintf(fout, " %s f_st[8];\n", float_type);
6028 fprintf(fout, " int f_stp = 0;\n");
6032 if (regmask_now & 0xff0000) {
6033 for (reg = 16; reg < 24; reg++) {
6034 if (regmask_now & (1 << reg)) {
6035 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6036 if (regmask_init & (1 << reg))
6037 fprintf(fout, " = 0");
6038 fprintf(fout, ";\n");
6045 if (need_float_sw) {
6046 fprintf(fout, " u16 f_sw;\n");
6051 for (reg = 0; reg < 8; reg++) {
6052 if (regmask_save & (1 << reg)) {
6053 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6059 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6060 if (save_arg_vars[i] == 0)
6062 for (reg = 0; reg < 32; reg++) {
6063 if (save_arg_vars[i] & (1 << reg)) {
6064 fprintf(fout, " u32 %s;\n",
6065 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6072 for (reg = 0; reg < 32; reg++) {
6073 if (regmask_ffca & (1 << reg)) {
6074 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6080 // declare push-pop temporaries
6082 for (reg = 0; reg < 8; reg++) {
6083 if (regmask_pp & (1 << reg)) {
6084 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6091 for (i = 0; i < 8; i++) {
6092 if (cond_vars & (1 << i)) {
6093 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6100 fprintf(fout, " u32 tmp;\n");
6105 fprintf(fout, " u64 tmp64;\n");
6110 fprintf(fout, "\n");
6112 // do stack clear, if needed
6113 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6115 if (g_stack_clear_len != 0) {
6116 if (g_stack_clear_len <= 4) {
6117 for (i = 0; i < g_stack_clear_len; i++)
6118 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6119 fprintf(fout, "0;\n");
6122 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6123 g_stack_clear_start, g_stack_clear_len * 4);
6127 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6130 if (g_func_pp->is_vararg) {
6131 if (g_func_pp->argc_stack == 0)
6132 ferr(ops, "vararg func without stack args?\n");
6133 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6137 for (i = 0; i < opcnt; i++)
6139 if (g_labels[i] != NULL) {
6140 fprintf(fout, "\n%s:\n", g_labels[i]);
6143 delayed_flag_op = NULL;
6144 last_arith_dst = NULL;
6148 if (po->flags & OPF_RMD)
6153 #define assert_operand_cnt(n_) \
6154 if (po->operand_cnt != n_) \
6155 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6157 // conditional/flag using op?
6158 if (po->flags & OPF_CC)
6164 // we go through all this trouble to avoid using parsed_flag_op,
6165 // which makes generated code much nicer
6166 if (delayed_flag_op != NULL)
6168 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6169 po->pfo, po->pfo_inv);
6172 else if (last_arith_dst != NULL
6173 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6174 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6177 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6178 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6179 last_arith_dst->lmod, buf3);
6182 else if (tmp_op != NULL) {
6183 // use preprocessed flag calc results
6184 if (!(tmp_op->pfomask & (1 << po->pfo)))
6185 ferr(po, "not prepared for pfo %d\n", po->pfo);
6187 // note: pfo_inv was not yet applied
6188 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6189 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6192 ferr(po, "all methods of finding comparison failed\n");
6195 if (po->flags & OPF_JMP) {
6196 fprintf(fout, " if %s", buf1);
6198 else if (po->op == OP_RCL || po->op == OP_RCR
6199 || po->op == OP_ADC || po->op == OP_SBB)
6202 fprintf(fout, " cond_%s = %s;\n",
6203 parsed_flag_op_names[po->pfo], buf1);
6205 else if (po->flags & OPF_DATA) { // SETcc
6206 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6207 fprintf(fout, " %s = %s;", buf2, buf1);
6210 ferr(po, "unhandled conditional op\n");
6214 pfomask = po->pfomask;
6219 assert_operand_cnt(2);
6220 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6221 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6222 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6223 fprintf(fout, " %s = %s;", buf1,
6224 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6229 assert_operand_cnt(2);
6230 po->operand[1].lmod = OPLM_DWORD; // always
6231 fprintf(fout, " %s = %s;",
6232 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6233 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6238 assert_operand_cnt(2);
6239 fprintf(fout, " %s = %s;",
6240 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6241 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6245 assert_operand_cnt(2);
6246 switch (po->operand[1].lmod) {
6248 strcpy(buf3, "(s8)");
6251 strcpy(buf3, "(s16)");
6254 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6256 fprintf(fout, " %s = %s;",
6257 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6258 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6263 assert_operand_cnt(2);
6264 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6265 fprintf(fout, " tmp = %s;",
6266 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6267 fprintf(fout, " %s = %s;",
6268 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6269 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6270 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6271 fprintf(fout, " %s = %stmp;",
6272 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6273 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6274 snprintf(g_comment, sizeof(g_comment), "xchg");
6278 assert_operand_cnt(1);
6279 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6280 fprintf(fout, " %s = ~%s;", buf1, buf1);
6284 assert_operand_cnt(2);
6285 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6286 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6287 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6288 strcpy(g_comment, "xlat");
6292 assert_operand_cnt(2);
6293 fprintf(fout, " %s = (s32)%s >> 31;",
6294 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6295 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6296 strcpy(g_comment, "cdq");
6300 assert_operand_cnt(1);
6301 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6302 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6306 if (po->flags & OPF_REP) {
6307 assert_operand_cnt(3);
6312 assert_operand_cnt(2);
6313 fprintf(fout, " %s = %sesi; esi %c= %d;",
6314 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6315 lmod_cast_u_ptr(po, po->operand[1].lmod),
6316 (po->flags & OPF_DF) ? '-' : '+',
6317 lmod_bytes(po, po->operand[1].lmod));
6318 strcpy(g_comment, "lods");
6323 if (po->flags & OPF_REP) {
6324 assert_operand_cnt(3);
6325 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6326 (po->flags & OPF_DF) ? '-' : '+',
6327 lmod_bytes(po, po->operand[1].lmod));
6328 fprintf(fout, " %sedi = eax;",
6329 lmod_cast_u_ptr(po, po->operand[1].lmod));
6330 strcpy(g_comment, "rep stos");
6333 assert_operand_cnt(2);
6334 fprintf(fout, " %sedi = eax; edi %c= %d;",
6335 lmod_cast_u_ptr(po, po->operand[1].lmod),
6336 (po->flags & OPF_DF) ? '-' : '+',
6337 lmod_bytes(po, po->operand[1].lmod));
6338 strcpy(g_comment, "stos");
6343 j = lmod_bytes(po, po->operand[0].lmod);
6344 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6345 l = (po->flags & OPF_DF) ? '-' : '+';
6346 if (po->flags & OPF_REP) {
6347 assert_operand_cnt(3);
6349 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
6352 " %sedi = %sesi;", buf1, buf1);
6353 strcpy(g_comment, "rep movs");
6356 assert_operand_cnt(2);
6357 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
6358 buf1, buf1, l, j, l, j);
6359 strcpy(g_comment, "movs");
6364 // repe ~ repeat while ZF=1
6365 j = lmod_bytes(po, po->operand[0].lmod);
6366 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
6367 l = (po->flags & OPF_DF) ? '-' : '+';
6368 if (po->flags & OPF_REP) {
6369 assert_operand_cnt(3);
6371 " while (ecx != 0) {\n");
6372 if (pfomask & (1 << PFO_C)) {
6375 " cond_c = %sesi < %sedi;\n", buf1, buf1);
6376 pfomask &= ~(1 << PFO_C);
6379 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
6380 buf1, buf1, l, j, l, j);
6383 " if (cond_z %s 0) break;\n",
6384 (po->flags & OPF_REPZ) ? "==" : "!=");
6387 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
6388 (po->flags & OPF_REPZ) ? "e" : "ne");
6391 assert_operand_cnt(2);
6393 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
6394 buf1, buf1, l, j, l, j);
6395 strcpy(g_comment, "cmps");
6397 pfomask &= ~(1 << PFO_Z);
6398 last_arith_dst = NULL;
6399 delayed_flag_op = NULL;
6403 // only does ZF (for now)
6404 // repe ~ repeat while ZF=1
6405 j = lmod_bytes(po, po->operand[1].lmod);
6406 l = (po->flags & OPF_DF) ? '-' : '+';
6407 if (po->flags & OPF_REP) {
6408 assert_operand_cnt(3);
6410 " while (ecx != 0) {\n");
6412 " cond_z = (%seax == %sedi); edi %c= %d;\n",
6413 lmod_cast_u(po, po->operand[1].lmod),
6414 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6417 " if (cond_z %s 0) break;\n",
6418 (po->flags & OPF_REPZ) ? "==" : "!=");
6421 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
6422 (po->flags & OPF_REPZ) ? "e" : "ne");
6425 assert_operand_cnt(2);
6426 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
6427 lmod_cast_u(po, po->operand[1].lmod),
6428 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
6429 strcpy(g_comment, "scas");
6431 pfomask &= ~(1 << PFO_Z);
6432 last_arith_dst = NULL;
6433 delayed_flag_op = NULL;
6436 // arithmetic w/flags
6438 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
6439 goto dualop_arith_const;
6440 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6444 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6445 if (po->operand[1].type == OPT_CONST) {
6446 j = lmod_bytes(po, po->operand[0].lmod);
6447 if (((1ull << j * 8) - 1) == po->operand[1].val)
6448 goto dualop_arith_const;
6453 assert_operand_cnt(2);
6454 fprintf(fout, " %s %s= %s;",
6455 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6457 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6458 output_std_flags(fout, po, &pfomask, buf1);
6459 last_arith_dst = &po->operand[0];
6460 delayed_flag_op = NULL;
6464 // and 0, or ~0 used instead mov
6465 assert_operand_cnt(2);
6466 fprintf(fout, " %s = %s;",
6467 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6468 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6469 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6470 output_std_flags(fout, po, &pfomask, buf1);
6471 last_arith_dst = &po->operand[0];
6472 delayed_flag_op = NULL;
6477 assert_operand_cnt(2);
6478 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6479 if (pfomask & (1 << PFO_C)) {
6480 if (po->operand[1].type == OPT_CONST) {
6481 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6482 j = po->operand[1].val;
6485 if (po->op == OP_SHL)
6489 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
6493 ferr(po, "zero shift?\n");
6497 pfomask &= ~(1 << PFO_C);
6499 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
6500 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6501 if (po->operand[1].type != OPT_CONST)
6502 fprintf(fout, " & 0x1f");
6504 output_std_flags(fout, po, &pfomask, buf1);
6505 last_arith_dst = &po->operand[0];
6506 delayed_flag_op = NULL;
6510 assert_operand_cnt(2);
6511 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6512 fprintf(fout, " %s = %s%s >> %s;", buf1,
6513 lmod_cast_s(po, po->operand[0].lmod), buf1,
6514 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6515 output_std_flags(fout, po, &pfomask, buf1);
6516 last_arith_dst = &po->operand[0];
6517 delayed_flag_op = NULL;
6522 assert_operand_cnt(3);
6523 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6524 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6525 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
6526 if (po->operand[2].type != OPT_CONST) {
6527 // no handling for "undefined" case, hopefully not needed
6528 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
6531 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6532 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6533 if (po->op == OP_SHLD) {
6534 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
6535 buf1, buf3, buf1, buf2, l, buf3);
6536 strcpy(g_comment, "shld");
6539 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
6540 buf1, buf3, buf1, buf2, l, buf3);
6541 strcpy(g_comment, "shrd");
6543 output_std_flags(fout, po, &pfomask, buf1);
6544 last_arith_dst = &po->operand[0];
6545 delayed_flag_op = NULL;
6550 assert_operand_cnt(2);
6551 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6552 if (po->operand[1].type == OPT_CONST) {
6553 j = po->operand[1].val;
6554 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
6555 fprintf(fout, po->op == OP_ROL ?
6556 " %s = (%s << %d) | (%s >> %d);" :
6557 " %s = (%s >> %d) | (%s << %d);",
6558 buf1, buf1, j, buf1,
6559 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
6563 output_std_flags(fout, po, &pfomask, buf1);
6564 last_arith_dst = &po->operand[0];
6565 delayed_flag_op = NULL;
6570 assert_operand_cnt(2);
6571 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6572 l = lmod_bytes(po, po->operand[0].lmod) * 8;
6573 if (po->operand[1].type == OPT_CONST) {
6574 j = po->operand[1].val % l;
6576 ferr(po, "zero rotate\n");
6577 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
6578 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
6579 if (po->op == OP_RCL) {
6581 " %s = (%s << %d) | (cond_c << %d)",
6582 buf1, buf1, j, j - 1);
6584 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
6588 " %s = (%s >> %d) | (cond_c << %d)",
6589 buf1, buf1, j, l - j);
6591 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
6593 fprintf(fout, ";\n");
6594 fprintf(fout, " cond_c = tmp;");
6598 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
6599 output_std_flags(fout, po, &pfomask, buf1);
6600 last_arith_dst = &po->operand[0];
6601 delayed_flag_op = NULL;
6605 assert_operand_cnt(2);
6606 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6607 if (IS(opr_name(po, 0), opr_name(po, 1))) {
6608 // special case for XOR
6609 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
6610 for (j = 0; j <= PFO_LE; j++) {
6611 if (pfomask & (1 << j)) {
6612 fprintf(fout, " cond_%s = %d;\n",
6613 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
6614 pfomask &= ~(1 << j);
6617 fprintf(fout, " %s = 0;",
6618 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6619 last_arith_dst = &po->operand[0];
6620 delayed_flag_op = NULL;
6626 assert_operand_cnt(2);
6627 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6628 if (pfomask & (1 << PFO_C)) {
6629 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6630 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6631 if (po->operand[0].lmod == OPLM_DWORD) {
6632 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
6633 fprintf(fout, " cond_c = tmp64 >> 32;\n");
6634 fprintf(fout, " %s = (u32)tmp64;",
6635 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
6636 strcat(g_comment, " add64");
6639 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
6640 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
6641 fprintf(fout, " %s += %s;",
6642 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6645 pfomask &= ~(1 << PFO_C);
6646 output_std_flags(fout, po, &pfomask, buf1);
6647 last_arith_dst = &po->operand[0];
6648 delayed_flag_op = NULL;
6651 if (pfomask & (1 << PFO_LE)) {
6652 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
6653 fprintf(fout, " cond_%s = %s;\n",
6654 parsed_flag_op_names[PFO_LE], buf1);
6655 pfomask &= ~(1 << PFO_LE);
6660 assert_operand_cnt(2);
6661 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6662 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
6663 for (j = 0; j <= PFO_LE; j++) {
6664 if (!(pfomask & (1 << j)))
6666 if (j == PFO_Z || j == PFO_S)
6669 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6670 fprintf(fout, " cond_%s = %s;\n",
6671 parsed_flag_op_names[j], buf1);
6672 pfomask &= ~(1 << j);
6679 assert_operand_cnt(2);
6680 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6681 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6682 if (po->op == OP_SBB
6683 && IS(po->operand[0].name, po->operand[1].name))
6685 // avoid use of unitialized var
6686 fprintf(fout, " %s = -cond_c;", buf1);
6687 // carry remains what it was
6688 pfomask &= ~(1 << PFO_C);
6691 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
6692 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6694 output_std_flags(fout, po, &pfomask, buf1);
6695 last_arith_dst = &po->operand[0];
6696 delayed_flag_op = NULL;
6700 assert_operand_cnt(2);
6701 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6702 fprintf(fout, " %s = %s ? __builtin_ffs(%s) - 1 : 0;",
6703 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6705 output_std_flags(fout, po, &pfomask, buf1);
6706 last_arith_dst = &po->operand[0];
6707 delayed_flag_op = NULL;
6708 strcat(g_comment, " bsf");
6712 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
6713 for (j = 0; j <= PFO_LE; j++) {
6714 if (!(pfomask & (1 << j)))
6716 if (j == PFO_Z || j == PFO_S || j == PFO_C)
6719 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
6720 fprintf(fout, " cond_%s = %s;\n",
6721 parsed_flag_op_names[j], buf1);
6722 pfomask &= ~(1 << j);
6728 if (pfomask & (1 << PFO_C))
6729 // carry is unaffected by inc/dec.. wtf?
6730 ferr(po, "carry propagation needed\n");
6732 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6733 if (po->operand[0].type == OPT_REG) {
6734 strcpy(buf2, po->op == OP_INC ? "++" : "--");
6735 fprintf(fout, " %s%s;", buf1, buf2);
6738 strcpy(buf2, po->op == OP_INC ? "+" : "-");
6739 fprintf(fout, " %s %s= 1;", buf1, buf2);
6741 output_std_flags(fout, po, &pfomask, buf1);
6742 last_arith_dst = &po->operand[0];
6743 delayed_flag_op = NULL;
6747 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6748 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
6749 fprintf(fout, " %s = -%s%s;", buf1,
6750 lmod_cast_s(po, po->operand[0].lmod), buf2);
6751 last_arith_dst = &po->operand[0];
6752 delayed_flag_op = NULL;
6753 if (pfomask & PFOB_C) {
6754 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
6757 output_std_flags(fout, po, &pfomask, buf1);
6761 if (po->operand_cnt == 2) {
6762 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6765 if (po->operand_cnt == 3)
6766 ferr(po, "TODO imul3\n");
6769 assert_operand_cnt(1);
6770 switch (po->operand[0].lmod) {
6772 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
6773 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
6774 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
6775 fprintf(fout, " edx = tmp64 >> 32;\n");
6776 fprintf(fout, " eax = tmp64;");
6779 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
6780 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
6781 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
6785 ferr(po, "TODO: unhandled mul type\n");
6788 last_arith_dst = NULL;
6789 delayed_flag_op = NULL;
6794 assert_operand_cnt(1);
6795 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
6796 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
6797 po->op == OP_IDIV));
6798 switch (po->operand[0].lmod) {
6800 if (po->flags & OPF_32BIT)
6801 snprintf(buf2, sizeof(buf2), "%seax", cast);
6803 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
6804 snprintf(buf2, sizeof(buf2), "%stmp64",
6805 (po->op == OP_IDIV) ? "(s64)" : "");
6807 if (po->operand[0].type == OPT_REG
6808 && po->operand[0].reg == xDX)
6810 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
6811 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
6814 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
6815 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
6819 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
6820 snprintf(buf2, sizeof(buf2), "%stmp",
6821 (po->op == OP_IDIV) ? "(s32)" : "");
6822 if (po->operand[0].type == OPT_REG
6823 && po->operand[0].reg == xDX)
6825 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
6827 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
6831 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
6833 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
6836 strcat(g_comment, " div16");
6839 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
6841 last_arith_dst = NULL;
6842 delayed_flag_op = NULL;
6847 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6849 for (j = 0; j < 8; j++) {
6850 if (pfomask & (1 << j)) {
6851 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
6852 fprintf(fout, " cond_%s = %s;",
6853 parsed_flag_op_names[j], buf1);
6860 last_arith_dst = NULL;
6861 delayed_flag_op = po;
6865 // SETcc - should already be handled
6868 // note: we reuse OP_Jcc for SETcc, only flags differ
6870 fprintf(fout, "\n goto %s;", po->operand[0].name);
6874 fprintf(fout, " if (ecx == 0)\n");
6875 fprintf(fout, " goto %s;", po->operand[0].name);
6876 strcat(g_comment, " jecxz");
6880 fprintf(fout, " if (--ecx != 0)\n");
6881 fprintf(fout, " goto %s;", po->operand[0].name);
6882 strcat(g_comment, " loop");
6886 assert_operand_cnt(1);
6887 last_arith_dst = NULL;
6888 delayed_flag_op = NULL;
6890 if (po->operand[0].type == OPT_REGMEM) {
6891 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
6894 ferr(po, "parse failure for jmp '%s'\n",
6895 po->operand[0].name);
6896 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
6899 else if (po->operand[0].type != OPT_LABEL)
6900 ferr(po, "unhandled jmp type\n");
6902 fprintf(fout, " goto %s;", po->operand[0].name);
6906 assert_operand_cnt(1);
6908 my_assert_not(pp, NULL);
6911 if (po->flags & OPF_CC) {
6912 // we treat conditional branch to another func
6913 // (yes such code exists..) as conditional tailcall
6915 fprintf(fout, " {\n");
6918 if (pp->is_fptr && !pp->is_arg) {
6919 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
6920 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
6922 if (pp->is_unresolved)
6923 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
6924 buf3, asmfn, po->asmln, pp->name);
6927 fprintf(fout, "%s", buf3);
6928 if (strstr(pp->ret_type.name, "int64")) {
6929 if (po->flags & OPF_TAIL)
6930 ferr(po, "int64 and tail?\n");
6931 fprintf(fout, "tmp64 = ");
6933 else if (!IS(pp->ret_type.name, "void")) {
6934 if (po->flags & OPF_TAIL) {
6935 if (regmask_ret & mxAX) {
6936 fprintf(fout, "return ");
6937 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
6938 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
6940 else if (regmask_ret & mxST0)
6941 ferr(po, "float tailcall\n");
6943 else if (po->regmask_dst & mxAX) {
6944 fprintf(fout, "eax = ");
6945 if (pp->ret_type.is_ptr)
6946 fprintf(fout, "(u32)");
6948 else if (po->regmask_dst & mxST0) {
6949 ferr_assert(po, po->flags & OPF_FPUSH);
6950 if (need_float_stack)
6951 fprintf(fout, "f_st[--f_stp & 7] = ");
6953 fprintf(fout, "f_st0 = ");
6957 if (pp->name[0] == 0)
6958 ferr(po, "missing pp->name\n");
6959 fprintf(fout, "%s%s(", pp->name,
6960 pp->has_structarg ? "_sa" : "");
6962 if (po->flags & OPF_ATAIL) {
6964 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
6965 check_compat |= pp->argc_stack > 0;
6967 && (pp->argc_stack != g_func_pp->argc_stack
6968 || pp->is_stdcall != g_func_pp->is_stdcall))
6969 ferr(po, "incompatible arg-reuse tailcall\n");
6970 if (g_func_pp->has_retreg)
6971 ferr(po, "TODO: retreg+tailcall\n");
6973 for (arg = j = 0; arg < pp->argc; arg++) {
6975 fprintf(fout, ", ");
6978 if (pp->arg[arg].type.is_ptr)
6979 snprintf(cast, sizeof(cast), "(%s)",
6980 pp->arg[arg].type.name);
6982 if (pp->arg[arg].reg != NULL) {
6983 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
6987 for (; j < g_func_pp->argc; j++)
6988 if (g_func_pp->arg[j].reg == NULL)
6990 fprintf(fout, "%sa%d", cast, j + 1);
6995 for (arg = 0; arg < pp->argc; arg++) {
6997 fprintf(fout, ", ");
7000 if (pp->arg[arg].type.is_ptr)
7001 snprintf(cast, sizeof(cast), "(%s)",
7002 pp->arg[arg].type.name);
7004 if (pp->arg[arg].reg != NULL) {
7005 if (pp->arg[arg].type.is_retreg)
7006 fprintf(fout, "&%s", pp->arg[arg].reg);
7007 else if (IS(pp->arg[arg].reg, "ebp")
7008 && g_bp_frame && !(po->flags & OPF_EBP_S))
7010 // rare special case
7011 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7012 strcat(g_comment, " bp_ref");
7015 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7020 tmp_op = pp->arg[arg].datap;
7022 ferr(po, "parsed_op missing for arg%d\n", arg);
7024 if (tmp_op->flags & OPF_VAPUSH) {
7025 fprintf(fout, "ap");
7027 else if (tmp_op->op == OP_FST) {
7028 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7029 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7032 else if (tmp_op->p_argpass != 0) {
7033 fprintf(fout, "a%d", tmp_op->p_argpass);
7035 else if (pp->arg[arg].is_saved) {
7036 ferr_assert(po, tmp_op->p_argnum > 0);
7037 fprintf(fout, "%s%s", cast,
7038 saved_arg_name(buf1, sizeof(buf1),
7039 tmp_op->p_arggrp, tmp_op->p_argnum));
7043 out_src_opr(buf1, sizeof(buf1),
7044 tmp_op, &tmp_op->operand[0], cast, 0));
7048 fprintf(fout, ");");
7050 if (strstr(pp->ret_type.name, "int64")) {
7051 fprintf(fout, "\n");
7052 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7053 fprintf(fout, "%seax = tmp64;", buf3);
7056 if (pp->is_unresolved) {
7057 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7059 strcat(g_comment, buf2);
7062 if (po->flags & OPF_TAIL) {
7064 if (i == opcnt - 1 || pp->is_noreturn)
7066 else if (IS(pp->ret_type.name, "void"))
7068 else if (!(regmask_ret & (1 << xAX)))
7070 // else already handled as 'return f()'
7073 fprintf(fout, "\n%sreturn;", buf3);
7074 strcat(g_comment, " ^ tailcall");
7077 strcat(g_comment, " tailcall");
7079 if ((regmask_ret & (1 << xAX))
7080 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7082 ferr(po, "int func -> void func tailcall?\n");
7085 if (pp->is_noreturn)
7086 strcat(g_comment, " noreturn");
7087 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7088 strcat(g_comment, " argframe");
7089 if (po->flags & OPF_CC)
7090 strcat(g_comment, " cond");
7092 if (po->flags & OPF_CC)
7093 fprintf(fout, "\n }");
7095 delayed_flag_op = NULL;
7096 last_arith_dst = NULL;
7100 if (g_func_pp->is_vararg)
7101 fprintf(fout, " va_end(ap);\n");
7102 if (g_func_pp->has_retreg) {
7103 for (arg = 0; arg < g_func_pp->argc; arg++)
7104 if (g_func_pp->arg[arg].type.is_retreg)
7105 fprintf(fout, " *r_%s = %s;\n",
7106 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7109 if (regmask_ret & mxST0) {
7110 fprintf(fout, " return %s;", float_st0);
7112 else if (!(regmask_ret & mxAX)) {
7113 if (i != opcnt - 1 || label_pending)
7114 fprintf(fout, " return;");
7116 else if (g_func_pp->ret_type.is_ptr) {
7117 fprintf(fout, " return (%s)eax;",
7118 g_func_pp->ret_type.name);
7120 else if (IS(g_func_pp->ret_type.name, "__int64"))
7121 fprintf(fout, " return ((u64)edx << 32) | eax;");
7123 fprintf(fout, " return eax;");
7125 last_arith_dst = NULL;
7126 delayed_flag_op = NULL;
7130 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7131 if (po->p_argnum != 0) {
7132 // special case - saved func arg
7133 fprintf(fout, " %s = %s;",
7134 saved_arg_name(buf2, sizeof(buf2),
7135 po->p_arggrp, po->p_argnum), buf1);
7138 else if (po->flags & OPF_RSAVE) {
7139 fprintf(fout, " s_%s = %s;", buf1, buf1);
7142 else if (po->flags & OPF_PPUSH) {
7144 ferr_assert(po, tmp_op != NULL);
7145 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7146 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7149 else if (g_func_pp->is_userstack) {
7150 fprintf(fout, " *(--esp) = %s;", buf1);
7153 if (!(g_ida_func_attr & IDAFA_NORETURN))
7154 ferr(po, "stray push encountered\n");
7159 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7160 if (po->flags & OPF_RSAVE) {
7161 fprintf(fout, " %s = s_%s;", buf1, buf1);
7164 else if (po->flags & OPF_PPUSH) {
7165 // push/pop graph / non-const
7166 ferr_assert(po, po->datap == NULL);
7167 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7170 else if (po->datap != NULL) {
7173 fprintf(fout, " %s = %s;", buf1,
7174 out_src_opr(buf2, sizeof(buf2),
7175 tmp_op, &tmp_op->operand[0],
7176 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7179 else if (g_func_pp->is_userstack) {
7180 fprintf(fout, " %s = *esp++;", buf1);
7184 ferr(po, "stray pop encountered\n");
7194 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7195 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7196 po->op == OPP_ALLSHL ? "<<" : ">>");
7197 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7198 strcat(g_comment, po->op == OPP_ALLSHL
7199 ? " allshl" : " allshr");
7204 if (need_float_stack) {
7205 out_src_opr_float(buf1, sizeof(buf1),
7206 po, &po->operand[0], 1);
7207 if (po->regmask_src & mxSTa) {
7208 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7212 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7215 if (po->flags & OPF_FSHIFT)
7216 fprintf(fout, " f_st1 = f_st0;");
7217 if (po->operand[0].type == OPT_REG
7218 && po->operand[0].reg == xST0)
7220 strcat(g_comment, " fld st");
7223 fprintf(fout, " f_st0 = %s;",
7224 out_src_opr_float(buf1, sizeof(buf1),
7225 po, &po->operand[0], 0));
7227 strcat(g_comment, " fld");
7231 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7232 lmod_cast(po, po->operand[0].lmod, 1), 0);
7233 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7234 if (need_float_stack) {
7235 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7238 if (po->flags & OPF_FSHIFT)
7239 fprintf(fout, " f_st1 = f_st0;");
7240 fprintf(fout, " f_st0 = %s;", buf2);
7242 strcat(g_comment, " fild");
7246 if (need_float_stack)
7247 fprintf(fout, " f_st[--f_stp & 7] = ");
7249 if (po->flags & OPF_FSHIFT)
7250 fprintf(fout, " f_st1 = f_st0;");
7251 fprintf(fout, " f_st0 = ");
7253 switch (po->operand[0].val) {
7254 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7255 case X87_CONST_LN2: fprintf(fout, "0.693147180559945;"); break;
7256 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7257 default: ferr(po, "TODO\n"); break;
7262 if (po->flags & OPF_FARG) {
7263 // store to stack as func arg
7264 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7268 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7270 dead_dst = po->operand[0].type == OPT_REG
7271 && po->operand[0].reg == xST0;
7274 fprintf(fout, " %s = %s;", buf1, float_st0);
7275 if (po->flags & OPF_FSHIFT) {
7276 if (need_float_stack)
7277 fprintf(fout, " f_stp++;");
7279 fprintf(fout, " f_st0 = f_st1;");
7281 if (dead_dst && !(po->flags & OPF_FSHIFT))
7284 strcat(g_comment, " fst");
7288 fprintf(fout, " %s = %s%s;",
7289 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7290 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
7291 if (po->flags & OPF_FSHIFT) {
7292 if (need_float_stack)
7293 fprintf(fout, " f_stp++;");
7295 fprintf(fout, " f_st0 = f_st1;");
7297 strcat(g_comment, " fist");
7304 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7306 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7308 dead_dst = (po->flags & OPF_FPOP)
7309 && po->operand[0].type == OPT_REG
7310 && po->operand[0].reg == xST0;
7312 case OP_FADD: j = '+'; break;
7313 case OP_FDIV: j = '/'; break;
7314 case OP_FMUL: j = '*'; break;
7315 case OP_FSUB: j = '-'; break;
7316 default: j = 'x'; break;
7318 if (need_float_stack) {
7320 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7321 if (po->flags & OPF_FSHIFT)
7322 fprintf(fout, " f_stp++;");
7325 if (po->flags & OPF_FSHIFT) {
7326 // note: assumes only 2 regs handled
7328 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
7330 fprintf(fout, " f_st0 = f_st1;");
7333 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
7335 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7340 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7342 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7344 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
7346 dead_dst = (po->flags & OPF_FPOP)
7347 && po->operand[0].type == OPT_REG
7348 && po->operand[0].reg == xST0;
7349 j = po->op == OP_FDIVR ? '/' : '-';
7350 if (need_float_stack) {
7352 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7353 if (po->flags & OPF_FSHIFT)
7354 fprintf(fout, " f_stp++;");
7357 if (po->flags & OPF_FSHIFT) {
7359 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
7361 fprintf(fout, " f_st0 = f_st1;");
7364 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
7366 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
7374 case OP_FIADD: j = '+'; break;
7375 case OP_FIDIV: j = '/'; break;
7376 case OP_FIMUL: j = '*'; break;
7377 case OP_FISUB: j = '-'; break;
7378 default: j = 'x'; break;
7380 fprintf(fout, " %s %c= (%s)%s;", float_st0,
7382 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7383 lmod_cast(po, po->operand[0].lmod, 1), 0));
7388 fprintf(fout, " %s = %s %c %s;", float_st0,
7389 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
7391 po->op == OP_FIDIVR ? '/' : '-', float_st0);
7396 ferr_assert(po, po->datap != NULL);
7397 mask = (long)po->datap & 0xffff;
7398 z_check = ((long)po->datap >> 16) & 1;
7399 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7401 if (mask == 0x0100) { // C0 -> <
7402 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
7405 else if (mask == 0x4000) { // C3 -> =
7406 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
7409 else if (mask == 0x4100) { // C3, C0
7411 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
7413 strcat(g_comment, " z_chk_det");
7416 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
7417 "(%s < %s ? 0x0100 : 0);",
7418 float_st0, buf1, float_st0, buf1);
7422 ferr(po, "unhandled sw mask: %x\n", mask);
7423 if (po->flags & OPF_FSHIFT) {
7424 if (need_float_stack)
7425 fprintf(fout, " f_stp++;");
7427 fprintf(fout, " f_st0 = f_st1;");
7433 fprintf(fout, " %s = f_sw;",
7434 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7438 fprintf(fout, " %s = -%s;", float_st0, float_st0);
7442 fprintf(fout, " %s = cos%s(%s);", float_st0,
7443 need_double ? "" : "f", float_st0);
7447 if (need_float_stack) {
7448 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
7449 need_double ? "" : "f", float_st1, float_st0);
7450 fprintf(fout, " f_stp++;");
7453 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
7454 need_double ? "" : "f");
7459 if (need_float_stack) {
7460 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
7461 float_st1, need_double ? "" : "f", float_st0);
7462 fprintf(fout, " f_stp++;");
7465 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
7466 need_double ? "" : "f");
7468 strcat(g_comment, " fyl2x");
7472 fprintf(fout, " %s = sin%s(%s);", float_st0,
7473 need_double ? "" : "f", float_st0);
7477 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
7478 need_double ? "" : "f", float_st0);
7482 dead_dst = po->operand[0].type == OPT_REG
7483 && po->operand[0].reg == xST0;
7485 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7487 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
7488 float_st0, float_st0, buf1, buf1);
7489 strcat(g_comment, " fxch");
7496 ferr_assert(po, po->flags & OPF_32BIT);
7497 fprintf(fout, " eax = (s32)%s;", float_st0);
7498 if (po->flags & OPF_FSHIFT) {
7499 if (need_float_stack)
7500 fprintf(fout, " f_stp++;");
7502 fprintf(fout, " f_st0 = f_st1;");
7504 strcat(g_comment, " ftol");
7508 if (need_float_stack) {
7509 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
7510 need_double ? "" : "f", float_st1, float_st0);
7511 fprintf(fout, " f_stp++;");
7514 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
7515 need_double ? "" : "f");
7517 strcat(g_comment, " CIpow");
7521 fprintf(fout, " do_skip_code_abort();");
7526 fprintf(fout, " do_emms();");
7531 ferr(po, "unhandled op type %d, flags %x\n",
7536 if (g_comment[0] != 0) {
7537 char *p = g_comment;
7538 while (my_isblank(*p))
7540 fprintf(fout, " // %s", p);
7545 fprintf(fout, "\n");
7547 // some sanity checking
7548 if (po->flags & OPF_REP) {
7549 if (po->op != OP_STOS && po->op != OP_MOVS
7550 && po->op != OP_CMPS && po->op != OP_SCAS)
7551 ferr(po, "unexpected rep\n");
7552 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
7553 && (po->op == OP_CMPS || po->op == OP_SCAS))
7554 ferr(po, "cmps/scas with plain rep\n");
7556 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
7557 && po->op != OP_CMPS && po->op != OP_SCAS)
7558 ferr(po, "unexpected repz/repnz\n");
7561 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
7563 // see is delayed flag stuff is still valid
7564 if (delayed_flag_op != NULL && delayed_flag_op != po) {
7565 if (is_any_opr_modified(delayed_flag_op, po, 0))
7566 delayed_flag_op = NULL;
7569 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
7570 if (is_opr_modified(last_arith_dst, po))
7571 last_arith_dst = NULL;
7577 if (g_stack_fsz && !g_stack_frame_used)
7578 fprintf(fout, " (void)sf;\n");
7580 fprintf(fout, "}\n\n");
7582 gen_x_cleanup(opcnt);
7585 static void gen_x_cleanup(int opcnt)
7589 for (i = 0; i < opcnt; i++) {
7590 struct label_ref *lr, *lr_del;
7592 lr = g_label_refs[i].next;
7593 while (lr != NULL) {
7598 g_label_refs[i].i = -1;
7599 g_label_refs[i].next = NULL;
7601 if (ops[i].op == OP_CALL) {
7603 proto_release(ops[i].pp);
7609 struct func_proto_dep;
7611 struct func_prototype {
7616 int has_ret:3; // -1, 0, 1: unresolved, no, yes
7617 unsigned int dep_resolved:1;
7618 unsigned int is_stdcall:1;
7619 struct func_proto_dep *dep_func;
7621 const struct parsed_proto *pp; // seed pp, if any
7624 struct func_proto_dep {
7626 struct func_prototype *proto;
7627 int regmask_live; // .. at the time of call
7628 unsigned int ret_dep:1; // return from this is caller's return
7631 static struct func_prototype *hg_fp;
7632 static int hg_fp_cnt;
7634 static struct scanned_var {
7636 enum opr_lenmod lmod;
7637 unsigned int is_seeded:1;
7638 unsigned int is_c_str:1;
7639 const struct parsed_proto *pp; // seed pp, if any
7641 static int hg_var_cnt;
7643 static char **hg_refs;
7644 static int hg_ref_cnt;
7646 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
7649 static struct func_prototype *hg_fp_add(const char *funcn)
7651 struct func_prototype *fp;
7653 if ((hg_fp_cnt & 0xff) == 0) {
7654 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
7655 my_assert_not(hg_fp, NULL);
7656 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
7659 fp = &hg_fp[hg_fp_cnt];
7660 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
7662 fp->argc_stack = -1;
7668 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
7673 for (i = 0; i < fp->dep_func_cnt; i++)
7674 if (IS(fp->dep_func[i].name, name))
7675 return &fp->dep_func[i];
7680 static void hg_fp_add_dep(struct func_prototype *fp, const char *name)
7683 if (hg_fp_find_dep(fp, name))
7686 if ((fp->dep_func_cnt & 0xff) == 0) {
7687 fp->dep_func = realloc(fp->dep_func,
7688 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
7689 my_assert_not(fp->dep_func, NULL);
7690 memset(&fp->dep_func[fp->dep_func_cnt], 0,
7691 sizeof(fp->dep_func[0]) * 0x100);
7693 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
7697 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
7699 const struct func_prototype *p1 = p1_, *p2 = p2_;
7700 return strcmp(p1->name, p2->name);
7704 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
7706 const struct func_prototype *p1 = p1_, *p2 = p2_;
7707 return p1->id - p2->id;
7711 static void hg_ref_add(const char *name)
7713 if ((hg_ref_cnt & 0xff) == 0) {
7714 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
7715 my_assert_not(hg_refs, NULL);
7716 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
7719 hg_refs[hg_ref_cnt] = strdup(name);
7720 my_assert_not(hg_refs[hg_ref_cnt], NULL);
7724 // recursive register dep pass
7725 // - track saved regs (part 2)
7726 // - try to figure out arg-regs
7727 // - calculate reg deps
7728 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
7729 struct func_prototype *fp, int regmask_save, int regmask_dst,
7730 int *regmask_dep, int *has_ret)
7732 struct func_proto_dep *dep;
7733 struct parsed_op *po;
7734 int from_caller = 0;
7739 for (; i < opcnt; i++)
7741 if (cbits[i >> 3] & (1 << (i & 7)))
7743 cbits[i >> 3] |= (1 << (i & 7));
7747 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
7748 if (po->flags & OPF_RMD)
7751 if (po->btj != NULL) {
7753 for (j = 0; j < po->btj->count; j++) {
7754 check_i(po, po->btj->d[j].bt_i);
7755 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
7756 regmask_save, regmask_dst, regmask_dep, has_ret);
7761 check_i(po, po->bt_i);
7762 if (po->flags & OPF_CJMP) {
7763 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
7764 regmask_save, regmask_dst, regmask_dep, has_ret);
7772 if (po->flags & OPF_FARG)
7773 /* (just calculate register deps) */;
7774 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
7776 reg = po->operand[0].reg;
7777 ferr_assert(po, reg >= 0);
7779 if (po->flags & OPF_RSAVE) {
7780 regmask_save |= 1 << reg;
7783 if (po->flags & OPF_DONE)
7786 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
7788 regmask_save |= 1 << reg;
7789 po->flags |= OPF_RMD;
7790 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
7794 else if (po->flags & OPF_RMD)
7796 else if (po->op == OP_CALL) {
7797 po->regmask_dst |= 1 << xAX;
7799 dep = hg_fp_find_dep(fp, po->operand[0].name);
7801 dep->regmask_live = regmask_save | regmask_dst;
7802 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7803 dep->regmask_live |= 1 << xBP;
7806 else if (po->op == OP_RET) {
7807 if (po->operand_cnt > 0) {
7809 if (fp->argc_stack >= 0
7810 && fp->argc_stack != po->operand[0].val / 4)
7811 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
7812 fp->argc_stack = po->operand[0].val / 4;
7816 // if has_ret is 0, there is uninitialized eax path,
7817 // which means it's most likely void func
7818 if (*has_ret != 0 && (po->flags & OPF_TAIL)) {
7819 if (po->op == OP_CALL) {
7824 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
7827 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
7830 if (ret != 1 && from_caller) {
7831 // unresolved eax - probably void func
7835 if (j >= 0 && ops[j].op == OP_CALL) {
7836 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
7847 l = regmask_save | regmask_dst;
7848 if (g_bp_frame && !(po->flags & OPF_EBP_S))
7851 l = po->regmask_src & ~l;
7854 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
7855 l, regmask_dst, regmask_save, po->flags);
7858 regmask_dst |= po->regmask_dst;
7860 if (po->flags & OPF_TAIL)
7865 static void gen_hdr(const char *funcn, int opcnt)
7867 unsigned char cbits[MAX_OPS / 8];
7868 const struct parsed_proto *pp_c;
7869 struct parsed_proto *pp;
7870 struct func_prototype *fp;
7871 struct parsed_op *po;
7872 int regmask_dummy = 0;
7874 int max_bp_offset = 0;
7879 pp_c = proto_parse(g_fhdr, funcn, 1);
7881 // already in seed, will add to hg_fp later
7884 fp = hg_fp_add(funcn);
7886 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
7887 g_stack_frame_used = 0;
7890 // - resolve all branches
7891 // - parse calls with labels
7892 resolve_branches_parse_calls(opcnt);
7895 // - handle ebp/esp frame, remove ops related to it
7896 scan_prologue_epilogue(opcnt);
7899 // - remove dead labels
7901 for (i = 0; i < opcnt; i++)
7903 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7909 if (po->flags & (OPF_RMD|OPF_DONE))
7912 if (po->op == OP_CALL) {
7913 if (po->operand[0].type == OPT_LABEL)
7914 hg_fp_add_dep(fp, opr_name(po, 0));
7915 else if (po->pp != NULL)
7916 hg_fp_add_dep(fp, po->pp->name);
7921 // - remove dead labels
7922 // - handle push <const>/pop pairs
7923 for (i = 0; i < opcnt; i++)
7925 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
7931 if (po->flags & (OPF_RMD|OPF_DONE))
7934 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
7935 scan_for_pop_const(i, opcnt, i + opcnt * 13);
7939 // - process trivial calls
7940 for (i = 0; i < opcnt; i++)
7943 if (po->flags & (OPF_RMD|OPF_DONE))
7946 if (po->op == OP_CALL)
7948 pp = process_call_early(i, opcnt, &j);
7950 if (!(po->flags & OPF_ATAIL))
7951 // since we know the args, try to collect them
7952 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
7958 // commit esp adjust
7959 if (ops[j].op != OP_POP)
7960 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
7962 for (l = 0; l < pp->argc_stack; l++)
7963 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
7967 po->flags |= OPF_DONE;
7973 // - track saved regs (simple)
7975 for (i = 0; i < opcnt; i++)
7978 if (po->flags & (OPF_RMD|OPF_DONE))
7981 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
7982 && po->operand[0].reg != xCX)
7984 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
7986 // regmask_save |= 1 << po->operand[0].reg; // do it later
7987 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
7988 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
7991 else if (po->op == OP_CALL)
7993 pp = process_call(i, opcnt);
7995 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
7996 // since we know the args, collect them
7997 ret = collect_call_args(po, i, pp, ®mask_dummy,
8004 memset(cbits, 0, sizeof(cbits));
8008 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0, ®mask_dep, &has_ret);
8010 // find unreachable code - must be fixed in IDA
8011 for (i = 0; i < opcnt; i++)
8013 if (cbits[i >> 3] & (1 << (i & 7)))
8016 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8017 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8019 // the compiler sometimes still generates code after
8020 // noreturn OS functions
8023 if (ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8024 ferr(&ops[i], "unreachable code\n");
8027 for (i = 0; i < g_eqcnt; i++) {
8028 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8029 max_bp_offset = g_eqs[i].offset;
8032 if (fp->argc_stack < 0) {
8033 max_bp_offset = (max_bp_offset + 3) & ~3;
8034 fp->argc_stack = max_bp_offset / 4;
8035 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8039 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8040 fp->has_ret = has_ret;
8042 printf("// has_ret %d, regmask_dep %x\n",
8043 fp->has_ret, fp->regmask_dep);
8044 output_hdr_fp(stdout, fp, 1);
8045 if (IS(funcn, "sub_10007F72")) exit(1);
8048 gen_x_cleanup(opcnt);
8051 static void hg_fp_resolve_deps(struct func_prototype *fp)
8053 struct func_prototype fp_s;
8057 // this thing is recursive, so mark first..
8058 fp->dep_resolved = 1;
8060 for (i = 0; i < fp->dep_func_cnt; i++) {
8061 strcpy(fp_s.name, fp->dep_func[i].name);
8062 fp->dep_func[i].proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8063 sizeof(hg_fp[0]), hg_fp_cmp_name);
8064 if (fp->dep_func[i].proto != NULL) {
8065 if (!fp->dep_func[i].proto->dep_resolved)
8066 hg_fp_resolve_deps(fp->dep_func[i].proto);
8068 dep = ~fp->dep_func[i].regmask_live
8069 & fp->dep_func[i].proto->regmask_dep;
8070 fp->regmask_dep |= dep;
8071 // printf("dep %s %s |= %x\n", fp->name,
8072 // fp->dep_func[i].name, dep);
8074 if (fp->has_ret == -1 && fp->dep_func[i].ret_dep)
8075 fp->has_ret = fp->dep_func[i].proto->has_ret;
8080 // make all thiscall/edx arg functions referenced from .data fastcall
8081 static void do_func_refs_from_data(void)
8083 struct func_prototype *fp, fp_s;
8086 for (i = 0; i < hg_ref_cnt; i++) {
8087 strcpy(fp_s.name, hg_refs[i]);
8088 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8089 sizeof(hg_fp[0]), hg_fp_cmp_name);
8093 if (fp->argc_stack != 0 && (fp->regmask_dep & (mxCX | mxDX)))
8094 fp->regmask_dep |= mxCX | mxDX;
8098 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8101 const struct parsed_proto *pp;
8102 char *p, namebuf[NAMELEN];
8108 for (; count > 0; count--, fp++) {
8109 if (fp->has_ret == -1)
8110 fprintf(fout, "// ret unresolved\n");
8112 fprintf(fout, "// dep:");
8113 for (j = 0; j < fp->dep_func_cnt; j++) {
8114 fprintf(fout, " %s/", fp->dep_func[j].name);
8115 if (fp->dep_func[j].proto != NULL)
8116 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8117 fp->dep_func[j].proto->has_ret);
8119 fprintf(fout, "\n");
8122 p = strchr(fp->name, '@');
8124 memcpy(namebuf, fp->name, p - fp->name);
8125 namebuf[p - fp->name] = 0;
8133 pp = proto_parse(g_fhdr, name, 1);
8134 if (pp != NULL && pp->is_include)
8137 if (fp->pp != NULL) {
8138 // part of seed, output later
8142 regmask_dep = fp->regmask_dep;
8143 argc_normal = fp->argc_stack;
8145 fprintf(fout, "%-5s", fp->pp ? fp->pp->ret_type.name :
8146 (fp->has_ret ? "int" : "void"));
8147 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8148 && (regmask_dep & ~mxCX) == 0)
8150 fprintf(fout, "/*__thiscall*/ ");
8154 else if (regmask_dep && (fp->is_stdcall || fp->argc_stack == 0)
8155 && (regmask_dep & ~(mxCX | mxDX)) == 0)
8157 fprintf(fout, " __fastcall ");
8158 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8164 else if (regmask_dep && !fp->is_stdcall) {
8165 fprintf(fout, "/*__usercall*/ ");
8167 else if (regmask_dep) {
8168 fprintf(fout, "/*__userpurge*/ ");
8170 else if (fp->is_stdcall)
8171 fprintf(fout, " __stdcall ");
8173 fprintf(fout, " __cdecl ");
8175 fprintf(fout, "%s(", name);
8178 for (j = 0; j < xSP; j++) {
8179 if (regmask_dep & (1 << j)) {
8182 fprintf(fout, ", ");
8184 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8186 fprintf(fout, "int");
8187 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8191 for (j = 0; j < argc_normal; j++) {
8194 fprintf(fout, ", ");
8195 if (fp->pp != NULL) {
8196 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8197 if (!fp->pp->arg[arg - 1].type.is_ptr)
8201 fprintf(fout, "int ");
8202 fprintf(fout, "a%d", arg);
8205 fprintf(fout, ");\n");
8209 static void output_hdr(FILE *fout)
8211 static const char *lmod_c_names[] = {
8212 [OPLM_UNSPEC] = "???",
8213 [OPLM_BYTE] = "uint8_t",
8214 [OPLM_WORD] = "uint16_t",
8215 [OPLM_DWORD] = "uint32_t",
8216 [OPLM_QWORD] = "uint64_t",
8218 const struct scanned_var *var;
8219 struct func_prototype *fp;
8220 char line[256] = { 0, };
8224 // add stuff from headers
8225 for (i = 0; i < pp_cache_size; i++) {
8226 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
8227 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
8229 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
8230 fp = hg_fp_add(name);
8231 fp->pp = &pp_cache[i];
8232 fp->argc_stack = fp->pp->argc_stack;
8233 fp->is_stdcall = fp->pp->is_stdcall;
8234 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
8235 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
8239 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
8240 for (i = 0; i < hg_fp_cnt; i++)
8241 hg_fp_resolve_deps(&hg_fp[i]);
8243 // adjust functions referenced from data segment
8244 do_func_refs_from_data();
8246 // note: messes up .proto ptr, don't use
8247 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
8250 for (i = 0; i < hg_var_cnt; i++) {
8253 if (var->pp != NULL)
8256 else if (var->is_c_str)
8257 fprintf(fout, "extern %-8s %s[];", "char", var->name);
8259 fprintf(fout, "extern %-8s %s;",
8260 lmod_c_names[var->lmod], var->name);
8263 fprintf(fout, " // seeded");
8264 fprintf(fout, "\n");
8267 fprintf(fout, "\n");
8269 // output function prototypes
8270 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
8273 fprintf(fout, "\n// - seed -\n");
8276 while (fgets(line, sizeof(line), g_fhdr))
8277 fwrite(line, 1, strlen(line), fout);
8280 // '=' needs special treatment
8282 static char *next_word_s(char *w, size_t wsize, char *s)
8289 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
8291 for (i = 1; i < wsize - 1; i++) {
8293 printf("warning: missing closing quote: \"%s\"\n", s);
8302 for (; i < wsize - 1; i++) {
8303 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
8309 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
8310 printf("warning: '%s' truncated\n", w);
8315 static int cmpstringp(const void *p1, const void *p2)
8317 return strcmp(*(char * const *)p1, *(char * const *)p2);
8320 static int is_xref_needed(char *p, char **rlist, int rlist_len)
8325 if (strstr(p, "..."))
8326 // unable to determine, assume needed
8329 if (*p == '.') // .text, .data, ...
8330 // ref from other data or non-function -> no
8333 p2 = strpbrk(p, "+:\r\n\x18");
8336 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
8337 // referenced from removed code
8343 static int ida_xrefs_show_need(FILE *fasm, char *p,
8344 char **rlist, int rlist_len)
8350 p = strrchr(p, ';');
8351 if (p != NULL && *p == ';') {
8352 if (IS_START(p + 2, "sctref"))
8354 if (IS_START(p + 2, "DATA XREF: ")) {
8356 if (is_xref_needed(p, rlist, rlist_len))
8364 if (!my_fgets(line, sizeof(line), fasm))
8366 // non-first line is always indented
8367 if (!my_isblank(line[0]))
8370 // should be no content, just comment
8375 p = strrchr(p, ';');
8378 if (IS_START(p, "sctref")) {
8383 // it's printed once, but no harm to check again
8384 if (IS_START(p, "DATA XREF: "))
8387 if (is_xref_needed(p, rlist, rlist_len)) {
8392 fseek(fasm, pos, SEEK_SET);
8396 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
8398 struct scanned_var *var;
8399 char line[256] = { 0, };
8408 // skip to next data section
8409 while (my_fgets(line, sizeof(line), fasm))
8414 if (*p == 0 || *p == ';')
8417 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
8418 if (*p == 0 || *p == ';')
8421 if (*p != 's' || !IS_START(p, "segment para public"))
8427 if (p == NULL || !IS_START(p, "segment para public"))
8431 if (!IS_START(p, "'DATA'"))
8435 while (my_fgets(line, sizeof(line), fasm))
8440 no_identifier = my_isblank(*p);
8443 if (*p == 0 || *p == ';')
8446 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8447 words[wordc][0] = 0;
8448 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8449 if (*p == 0 || *p == ';') {
8455 if (wordc == 2 && IS(words[1], "ends"))
8460 if (no_identifier) {
8461 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
8462 hg_ref_add(words[2]);
8466 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
8467 // when this starts, we don't need anything from this section
8471 // check refs comment(s)
8472 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
8475 if ((hg_var_cnt & 0xff) == 0) {
8476 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
8477 * (hg_var_cnt + 0x100));
8478 my_assert_not(hg_vars, NULL);
8479 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
8482 var = &hg_vars[hg_var_cnt++];
8483 snprintf(var->name, sizeof(var->name), "%s", words[0]);
8485 // maybe already in seed header?
8486 var->pp = proto_parse(g_fhdr, var->name, 1);
8487 if (var->pp != NULL) {
8488 if (var->pp->is_fptr) {
8489 var->lmod = OPLM_DWORD;
8492 else if (var->pp->is_func)
8494 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
8495 aerr("unhandled C type '%s' for '%s'\n",
8496 var->pp->type.name, var->name);
8502 if (IS(words[1], "dd")) {
8503 var->lmod = OPLM_DWORD;
8504 if (wordc >= 4 && IS(words[2], "offset"))
8505 hg_ref_add(words[3]);
8507 else if (IS(words[1], "dw"))
8508 var->lmod = OPLM_WORD;
8509 else if (IS(words[1], "db")) {
8510 var->lmod = OPLM_BYTE;
8511 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
8512 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
8516 else if (IS(words[1], "dq"))
8517 var->lmod = OPLM_QWORD;
8518 //else if (IS(words[1], "dt"))
8520 aerr("type '%s' not known\n", words[1]);
8528 static void set_label(int i, const char *name)
8534 p = strchr(name, ':');
8538 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
8539 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
8540 g_labels[i] = realloc(g_labels[i], len + 1);
8541 my_assert_not(g_labels[i], NULL);
8542 memcpy(g_labels[i], name, len);
8543 g_labels[i][len] = 0;
8552 static struct chunk_item *func_chunks;
8553 static int func_chunk_cnt;
8554 static int func_chunk_alloc;
8556 static void add_func_chunk(FILE *fasm, const char *name, int line)
8558 if (func_chunk_cnt >= func_chunk_alloc) {
8559 func_chunk_alloc *= 2;
8560 func_chunks = realloc(func_chunks,
8561 func_chunk_alloc * sizeof(func_chunks[0]));
8562 my_assert_not(func_chunks, NULL);
8564 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
8565 func_chunks[func_chunk_cnt].name = strdup(name);
8566 func_chunks[func_chunk_cnt].asmln = line;
8570 static int cmp_chunks(const void *p1, const void *p2)
8572 const struct chunk_item *c1 = p1, *c2 = p2;
8573 return strcmp(c1->name, c2->name);
8576 static void scan_ahead_for_chunks(FILE *fasm)
8586 oldpos = ftell(fasm);
8589 while (my_fgets(line, sizeof(line), fasm))
8600 // get rid of random tabs
8601 for (i = 0; line[i] != 0; i++)
8602 if (line[i] == '\t')
8605 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8608 next_word(words[0], sizeof(words[0]), p);
8609 if (words[0][0] == 0)
8610 aerr("missing name for func chunk?\n");
8612 add_func_chunk(fasm, words[0], asmln);
8614 else if (IS_START(p, "; sctend"))
8620 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8621 words[wordc][0] = 0;
8622 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8623 if (*p == 0 || *p == ';') {
8629 if (wordc == 2 && IS(words[1], "ends"))
8633 fseek(fasm, oldpos, SEEK_SET);
8637 int main(int argc, char *argv[])
8639 FILE *fout, *fasm, *frlist;
8640 struct parsed_data *pd = NULL;
8642 char **rlist = NULL;
8644 int rlist_alloc = 0;
8645 int func_chunks_used = 0;
8646 int func_chunks_sorted = 0;
8647 int func_chunk_i = -1;
8648 long func_chunk_ret = 0;
8649 int func_chunk_ret_ln = 0;
8650 int scanned_ahead = 0;
8652 char words[20][256];
8653 enum opr_lenmod lmod;
8654 char *sctproto = NULL;
8656 int pending_endp = 0;
8658 int skip_code_end = 0;
8659 int skip_warned = 0;
8672 for (arg = 1; arg < argc; arg++) {
8673 if (IS(argv[arg], "-v"))
8675 else if (IS(argv[arg], "-rf"))
8676 g_allow_regfunc = 1;
8677 else if (IS(argv[arg], "-uc"))
8678 g_allow_user_icall = 1;
8679 else if (IS(argv[arg], "-m"))
8681 else if (IS(argv[arg], "-hdr"))
8682 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
8687 if (argc < arg + 3) {
8688 printf("usage:\n%s [-v] [-rf] [-m] <.c> <.asm> <hdr.h> [rlist]*\n"
8689 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
8691 " -hdr - header generation mode\n"
8692 " -rf - allow unannotated indirect calls\n"
8693 " -uc - allow ind. calls/refs to __usercall\n"
8694 " -m - allow multiple .text sections\n"
8695 "[rlist] is a file with function names to skip,"
8703 asmfn = argv[arg++];
8704 fasm = fopen(asmfn, "r");
8705 my_assert_not(fasm, NULL);
8707 hdrfn = argv[arg++];
8708 g_fhdr = fopen(hdrfn, "r");
8709 my_assert_not(g_fhdr, NULL);
8712 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
8713 my_assert_not(rlist, NULL);
8714 // needs special handling..
8715 rlist[rlist_len++] = "__alloca_probe";
8717 func_chunk_alloc = 32;
8718 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
8719 my_assert_not(func_chunks, NULL);
8721 memset(words, 0, sizeof(words));
8723 for (; arg < argc; arg++) {
8726 frlist = fopen(argv[arg], "r");
8727 my_assert_not(frlist, NULL);
8729 while (my_fgets(line, sizeof(line), frlist)) {
8731 if (*p == 0 || *p == ';')
8734 if (IS_START(p, "#if 0")
8735 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
8739 else if (IS_START(p, "#endif"))
8746 p = next_word(words[0], sizeof(words[0]), p);
8747 if (words[0][0] == 0)
8750 if (rlist_len >= rlist_alloc) {
8751 rlist_alloc = rlist_alloc * 2 + 64;
8752 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
8753 my_assert_not(rlist, NULL);
8755 rlist[rlist_len++] = strdup(words[0]);
8763 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
8765 fout = fopen(argv[arg_out], "w");
8766 my_assert_not(fout, NULL);
8769 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
8770 my_assert_not(g_eqs, NULL);
8772 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
8773 g_label_refs[i].i = -1;
8774 g_label_refs[i].next = NULL;
8778 scan_variables(fasm, rlist, rlist_len);
8780 while (my_fgets(line, sizeof(line), fasm))
8789 // get rid of random tabs
8790 for (i = 0; line[i] != 0; i++)
8791 if (line[i] == '\t')
8796 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
8797 goto do_pending_endp; // eww..
8799 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
8801 static const char *attrs[] = {
8810 // parse IDA's attribute-list comment
8811 g_ida_func_attr = 0;
8814 for (; *p != 0; p = sskip(p)) {
8815 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8816 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8817 g_ida_func_attr |= 1 << i;
8818 p += strlen(attrs[i]);
8822 if (i == ARRAY_SIZE(attrs)) {
8823 anote("unparsed IDA attr: %s\n", p);
8826 if (IS(attrs[i], "fpd=")) {
8827 p = next_word(words[0], sizeof(words[0]), p);
8832 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
8834 static const char *attrs[] = {
8839 // parse manual attribute-list comment
8840 g_sct_func_attr = 0;
8843 for (; *p != 0; p = sskip(p)) {
8844 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
8845 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
8846 g_sct_func_attr |= 1 << i;
8847 p += strlen(attrs[i]);
8854 // clear_sf=start,len (in dwords)
8855 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
8856 &g_stack_clear_len, &j);
8858 // clear_regmask=<mask>
8859 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
8861 anote("unparsed attr value: %s\n", p);
8866 else if (i == ARRAY_SIZE(attrs)) {
8867 anote("unparsed sct attr: %s\n", p);
8872 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
8875 next_word(words[0], sizeof(words[0]), p);
8876 if (words[0][0] == 0)
8877 aerr("missing name for func chunk?\n");
8879 if (!scanned_ahead) {
8880 add_func_chunk(fasm, words[0], asmln);
8881 func_chunks_sorted = 0;
8884 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
8886 if (func_chunk_i >= 0) {
8887 if (func_chunk_i < func_chunk_cnt
8888 && IS(func_chunks[func_chunk_i].name, g_func))
8890 // move on to next chunk
8891 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
8893 aerr("seek failed for '%s' chunk #%d\n",
8894 g_func, func_chunk_i);
8895 asmln = func_chunks[func_chunk_i].asmln;
8899 if (func_chunk_ret == 0)
8900 aerr("no return from chunk?\n");
8901 fseek(fasm, func_chunk_ret, SEEK_SET);
8902 asmln = func_chunk_ret_ln;
8908 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
8909 func_chunks_used = 1;
8911 if (IS_START(g_func, "sub_")) {
8912 unsigned long addr = strtoul(p, NULL, 16);
8913 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
8914 if (addr > f_addr && !scanned_ahead) {
8915 //anote("scan_ahead caused by '%s', addr %lx\n",
8917 scan_ahead_for_chunks(fasm);
8919 func_chunks_sorted = 0;
8927 for (i = wordc; i < ARRAY_SIZE(words); i++)
8929 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
8930 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
8931 if (*p == 0 || *p == ';') {
8936 if (*p != 0 && *p != ';')
8937 aerr("too many words\n");
8939 if (skip_code_end) {
8944 // allow asm patches in comments
8946 if (IS_START(p, "; sctpatch:")) {
8948 if (*p == 0 || *p == ';')
8950 goto parse_words; // lame
8952 if (IS_START(p, "; sctproto:")) {
8953 sctproto = strdup(p + 11);
8955 else if (IS_START(p, "; sctend")) {
8960 else if (IS_START(p, "; sctskip_start")) {
8961 if (in_func && !g_skip_func) {
8963 ops[pi].op = OPP_ABORT;
8964 ops[pi].asmln = asmln;
8970 else if (IS_START(p, "; sctskip_end")) {
8978 awarn("wordc == 0?\n");
8982 // don't care about this:
8983 if (words[0][0] == '.'
8984 || IS(words[0], "include")
8985 || IS(words[0], "assume") || IS(words[1], "segment")
8986 || IS(words[0], "align"))
8992 // do delayed endp processing to collect switch jumptables
8994 if (in_func && !g_skip_func && !end && wordc >= 2
8995 && ((words[0][0] == 'd' && words[0][2] == 0)
8996 || (words[1][0] == 'd' && words[1][2] == 0)))
8999 if (words[1][0] == 'd' && words[1][2] == 0) {
9001 if (g_func_pd_cnt >= pd_alloc) {
9002 pd_alloc = pd_alloc * 2 + 16;
9003 g_func_pd = realloc(g_func_pd,
9004 sizeof(g_func_pd[0]) * pd_alloc);
9005 my_assert_not(g_func_pd, NULL);
9007 pd = &g_func_pd[g_func_pd_cnt];
9009 memset(pd, 0, sizeof(*pd));
9010 strcpy(pd->label, words[0]);
9011 pd->type = OPT_CONST;
9012 pd->lmod = lmod_from_directive(words[1]);
9018 anote("skipping alignment byte?\n");
9021 lmod = lmod_from_directive(words[0]);
9022 if (lmod != pd->lmod)
9023 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9026 if (pd->count_alloc < pd->count + wordc) {
9027 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9028 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9029 my_assert_not(pd->d, NULL);
9031 for (; i < wordc; i++) {
9032 if (IS(words[i], "offset")) {
9033 pd->type = OPT_OFFSET;
9036 p = strchr(words[i], ',');
9039 if (pd->type == OPT_OFFSET)
9040 pd->d[pd->count].u.label = strdup(words[i]);
9042 pd->d[pd->count].u.val = parse_number(words[i], 0);
9043 pd->d[pd->count].bt_i = -1;
9049 if (in_func && !g_skip_func) {
9051 gen_hdr(g_func, pi);
9053 gen_func(fout, g_fhdr, g_func, pi);
9058 g_ida_func_attr = 0;
9059 g_sct_func_attr = 0;
9060 g_stack_clear_start = 0;
9061 g_stack_clear_len = 0;
9066 func_chunks_used = 0;
9069 memset(&ops, 0, pi * sizeof(ops[0]));
9074 for (i = 0; i < g_func_pd_cnt; i++) {
9076 if (pd->type == OPT_OFFSET) {
9077 for (j = 0; j < pd->count; j++)
9078 free(pd->d[j].u.label);
9093 if (IS(words[1], "proc")) {
9095 aerr("proc '%s' while in_func '%s'?\n",
9098 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9100 strcpy(g_func, words[0]);
9101 set_label(0, words[0]);
9106 if (IS(words[1], "endp"))
9109 aerr("endp '%s' while not in_func?\n", words[0]);
9110 if (!IS(g_func, words[0]))
9111 aerr("endp '%s' while in_func '%s'?\n",
9114 aerr("endp '%s' while skipping code\n", words[0]);
9116 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9117 && ops[0].op == OP_JMP && ops[0].operand[0].had_ds)
9123 if (!g_skip_func && func_chunks_used) {
9124 // start processing chunks
9125 struct chunk_item *ci, key = { g_func, 0 };
9127 func_chunk_ret = ftell(fasm);
9128 func_chunk_ret_ln = asmln;
9129 if (!func_chunks_sorted) {
9130 qsort(func_chunks, func_chunk_cnt,
9131 sizeof(func_chunks[0]), cmp_chunks);
9132 func_chunks_sorted = 1;
9134 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9135 sizeof(func_chunks[0]), cmp_chunks);
9137 aerr("'%s' needs chunks, but none found\n", g_func);
9138 func_chunk_i = ci - func_chunks;
9139 for (; func_chunk_i > 0; func_chunk_i--)
9140 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9143 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9145 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9146 asmln = func_chunks[func_chunk_i].asmln;
9154 if (wordc == 2 && IS(words[1], "ends")) {
9158 goto do_pending_endp;
9162 // scan for next text segment
9163 while (my_fgets(line, sizeof(line), fasm)) {
9166 if (*p == 0 || *p == ';')
9169 if (strstr(p, "segment para public 'CODE' use32"))
9176 p = strchr(words[0], ':');
9178 set_label(pi, words[0]);
9182 if (!in_func || g_skip_func || skip_code) {
9183 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
9185 anote("skipping from '%s'\n", g_labels[pi]);
9189 g_labels[pi] = NULL;
9193 if (wordc > 1 && IS(words[1], "="))
9196 aerr("unhandled equ, wc=%d\n", wordc);
9197 if (g_eqcnt >= eq_alloc) {
9199 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
9200 my_assert_not(g_eqs, NULL);
9203 len = strlen(words[0]);
9204 if (len > sizeof(g_eqs[0].name) - 1)
9205 aerr("equ name too long: %d\n", len);
9206 strcpy(g_eqs[g_eqcnt].name, words[0]);
9208 if (!IS(words[3], "ptr"))
9209 aerr("unhandled equ\n");
9210 if (IS(words[2], "dword"))
9211 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
9212 else if (IS(words[2], "word"))
9213 g_eqs[g_eqcnt].lmod = OPLM_WORD;
9214 else if (IS(words[2], "byte"))
9215 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
9216 else if (IS(words[2], "qword"))
9217 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
9219 aerr("bad lmod: '%s'\n", words[2]);
9221 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
9226 if (pi >= ARRAY_SIZE(ops))
9227 aerr("too many ops\n");
9229 parse_op(&ops[pi], words, wordc);
9231 ops[pi].datap = sctproto;
9246 // vim:ts=2:shiftwidth=2:expandtab