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)
25 #include "my_assert.h"
29 #include "protoparse.h"
31 static const char *asmfn;
35 #define anote(fmt, ...) \
36 printf("%s:%d: note: " fmt, asmfn, asmln, ##__VA_ARGS__)
37 #define awarn(fmt, ...) \
38 printf("%s:%d: warning: " fmt, asmfn, asmln, ##__VA_ARGS__)
39 #define aerr(fmt, ...) do { \
40 printf("%s:%d: error: " fmt, asmfn, asmln, ##__VA_ARGS__); \
45 #include "masm_tools.h"
48 OPF_RMD = (1 << 0), /* removed from code generation */
49 OPF_DATA = (1 << 1), /* data processing - writes to dst opr */
50 OPF_FLAGS = (1 << 2), /* sets flags */
51 OPF_JMP = (1 << 3), /* branch, call */
52 OPF_CJMP = (1 << 4), /* cond. branch (cc or jecxz/loop) */
53 OPF_CC = (1 << 5), /* uses flags */
54 OPF_TAIL = (1 << 6), /* ret or tail call */
55 OPF_RSAVE = (1 << 7), /* push/pop is local reg save/load */
56 OPF_REP = (1 << 8), /* prefixed by rep */
57 OPF_REPZ = (1 << 9), /* rep is repe/repz */
58 OPF_REPNZ = (1 << 10), /* rep is repne/repnz */
59 OPF_FARG = (1 << 11), /* push collected as func arg */
60 OPF_FARGNR = (1 << 12), /* push collected as func arg (no reuse) */
61 OPF_EBP_S = (1 << 13), /* ebp used as scratch here, not BP */
62 OPF_DF = (1 << 14), /* DF flag set */
63 OPF_ATAIL = (1 << 15), /* tail call with reused arg frame */
64 OPF_32BIT = (1 << 16), /* enough to do 32bit for this op */
65 OPF_LOCK = (1 << 17), /* op has lock prefix */
66 OPF_VAPUSH = (1 << 18), /* vararg ptr push (as call arg) */
67 OPF_DONE = (1 << 19), /* already fully handled by analysis */
68 OPF_PPUSH = (1 << 20), /* part of complex push-pop graph */
69 OPF_NOREGS = (1 << 21), /* don't track regs of this op */
70 OPF_FPUSH = (1 << 22), /* pushes x87 stack */
71 OPF_FPOP = (1 << 23), /* pops x87 stack */
72 OPF_FPOPP = (1 << 24), /* pops x87 stack twice */
73 OPF_FSHIFT = (1 << 25), /* x87 stack shift is actually needed */
74 OPF_FINT = (1 << 26), /* integer float op arg */
167 // pseudo-ops for lib calls
186 // must be sorted (larger len must be further in enum)
195 #define MAX_EXITS 128
197 #define MAX_OPERANDS 3
200 #define OPR_INIT(type_, lmod_, reg_) \
201 { type_, lmod_, reg_, }
205 enum opr_lenmod lmod;
207 unsigned int is_ptr:1; // pointer in C
208 unsigned int is_array:1; // array in C
209 unsigned int type_from_var:1; // .. in header, sometimes wrong
210 unsigned int size_mismatch:1; // type override differs from C
211 unsigned int size_lt:1; // type override is larger than C
212 unsigned int segment:7; // had segment override (enum segment)
213 const struct parsed_proto *pp; // for OPT_LABEL
220 struct parsed_opr operand[MAX_OPERANDS];
223 unsigned char pfo_inv;
224 unsigned char operand_cnt;
225 unsigned char p_argnum; // arg push: altered before call arg #
226 unsigned char p_arggrp; // arg push: arg group # for above
227 unsigned char p_argpass;// arg push: arg of host func
228 short p_argnext;// arg push: same arg pushed elsewhere or -1
229 int regmask_src; // all referensed regs
231 int pfomask; // flagop: parsed_flag_op that can't be delayed
232 int cc_scratch; // scratch storage during analysis
233 int bt_i; // branch target for branches
234 struct parsed_data *btj;// branch targets for jumptables
235 struct parsed_proto *pp;// parsed_proto for OP_CALL
241 // on start: function/data type hint (sctproto)
243 // (OPF_CC) - points to one of (OPF_FLAGS) that affects cc op
244 // OP_PUSH - points to OP_POP in complex push/pop graph
245 // OP_POP - points to OP_PUSH in simple push/pop pair
246 // OP_FCOM - needed_status_word_bits | (is_z_check << 16)
250 enum opr_lenmod lmod;
257 enum opr_lenmod lmod;
271 struct label_ref *next;
275 IDAFA_BP_FRAME = (1 << 0),
276 IDAFA_LIB_FUNC = (1 << 1),
277 IDAFA_STATIC = (1 << 2),
278 IDAFA_NORETURN = (1 << 3),
279 IDAFA_THUNK = (1 << 4),
280 IDAFA_FPD = (1 << 5),
285 SCTFA_CLEAR_SF = (1 << 0), // clear stack frame
286 SCTFA_CLEAR_REGS = (1 << 1), // clear registers (mask)
287 SCTFA_RM_REGS = (1 << 2), // don't emit regs (mask)
288 SCTFA_NOWARN = (1 << 3), // don't try to detect problems
289 SCTFA_ARGFRAME = (1 << 4), // copy all args to a struct, in order
311 // note: limited to 32k due to p_argnext
313 #define MAX_ARG_GRP 2
315 static struct parsed_op ops[MAX_OPS];
316 static struct parsed_equ *g_eqs;
318 static char *g_labels[MAX_OPS];
319 static struct label_ref g_label_refs[MAX_OPS];
320 static const struct parsed_proto *g_func_pp;
321 static struct parsed_data *g_func_pd;
322 static int g_func_pd_cnt;
323 static int g_func_lmods;
324 static char g_func[256];
325 static char g_comment[256];
326 static int g_bp_frame;
327 static int g_sp_frame;
328 static int g_stack_frame_used;
329 static int g_stack_fsz;
330 static int g_seh_found;
331 static int g_seh_size;
332 static int g_ida_func_attr;
333 static int g_sct_func_attr;
334 static int g_stack_clear_start; // in dwords
335 static int g_stack_clear_len;
336 static int g_regmask_init;
337 static int g_regmask_rm;
338 static int g_skip_func;
339 static int g_allow_regfunc;
340 static int g_allow_user_icall;
341 static int g_nowarn_reguse;
342 static int g_quiet_pp;
343 static int g_header_mode;
345 #define ferr(op_, fmt, ...) do { \
346 printf("%s:%d: error %u: [%s] '%s': " fmt, asmfn, (op_)->asmln, \
347 __LINE__, g_func, dump_op(op_), ##__VA_ARGS__); \
351 #define fnote(op_, fmt, ...) \
352 printf("%s:%d: note: [%s] '%s': " fmt, asmfn, (op_)->asmln, g_func, \
353 dump_op(op_), ##__VA_ARGS__)
355 #define ferr_assert(op_, cond) do { \
356 if (!(cond)) ferr(op_, "assertion '%s' failed\n", #cond); \
359 #define IS_OP_INDIRECT_CALL(op_) \
360 ((op_)->op == OP_CALL && (op_)->operand[0].type != OPT_LABEL)
362 const char *regs_r32[] = {
363 "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp",
364 // not r32, but list here for easy parsing and printing
365 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
366 "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"
368 const char *regs_r16[] = { "ax", "bx", "cx", "dx", "si", "di", "bp", "sp" };
369 const char *regs_r8l[] = { "al", "bl", "cl", "dl" };
370 const char *regs_r8h[] = { "ah", "bh", "ch", "dh" };
376 xMM0, xMM1, xMM2, xMM3, // mmx
377 xMM4, xMM5, xMM6, xMM7,
378 xST0, xST1, xST2, xST3, // x87
379 xST4, xST5, xST6, xST7,
382 #define mxAX (1 << xAX)
383 #define mxBX (1 << xBX)
384 #define mxCX (1 << xCX)
385 #define mxDX (1 << xDX)
386 #define mxSP (1 << xSP)
387 #define mxST0 (1 << xST0)
388 #define mxST1 (1 << xST1)
389 #define mxST1_0 (mxST1 | mxST0)
390 #define mxST7_2 (0xfc << xST0)
391 #define mxSTa (0xff << xST0)
393 // possible basic comparison types (without inversion)
394 enum parsed_flag_op {
398 PFO_BE, // 6 CF=1||ZF=1
402 PFO_LE, // e ZF=1||SF!=OF
405 #define PFOB_O (1 << PFO_O)
406 #define PFOB_C (1 << PFO_C)
407 #define PFOB_Z (1 << PFO_Z)
408 #define PFOB_S (1 << PFO_S)
410 static const char *parsed_flag_op_names[] = {
411 "o", "c", "z", "be", "s", "p", "l", "le"
414 static int char_array_i(const char *array[], size_t len, const char *s)
418 for (i = 0; i < len; i++)
425 static void printf_number(char *buf, size_t buf_size,
426 unsigned long number)
428 // output in C-friendly form
429 snprintf(buf, buf_size, number < 10 ? "%lu" : "0x%02lx", number);
432 static int check_segment_prefix(const char *s)
434 if (s[0] == 0 || s[1] != 's' || s[2] != ':')
438 case 'c': return SEG_CS;
439 case 'd': return SEG_DS;
440 case 's': return SEG_SS;
441 case 'e': return SEG_ES;
442 case 'f': return SEG_FS;
443 case 'g': return SEG_GS;
448 static int parse_reg(enum opr_lenmod *reg_lmod, const char *s)
452 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s);
454 *reg_lmod = OPLM_QWORD;
458 *reg_lmod = OPLM_DWORD;
461 reg = char_array_i(regs_r16, ARRAY_SIZE(regs_r16), s);
463 *reg_lmod = OPLM_WORD;
466 reg = char_array_i(regs_r8h, ARRAY_SIZE(regs_r8h), s);
468 *reg_lmod = OPLM_BYTE;
471 reg = char_array_i(regs_r8l, ARRAY_SIZE(regs_r8l), s);
473 *reg_lmod = OPLM_BYTE;
480 static int parse_indmode(char *name, int *regmask, int need_c_cvt)
482 enum opr_lenmod lmod;
495 while (my_isblank(*s))
497 for (; my_issep(*s); d++, s++)
499 while (my_isblank(*s))
503 // skip '?s:' prefixes
504 if (check_segment_prefix(s))
507 s = next_idt(w, sizeof(w), s);
512 reg = parse_reg(&lmod, w);
514 *regmask |= 1 << reg;
518 if ('0' <= w[0] && w[0] <= '9') {
519 number = parse_number(w, 0);
520 printf_number(d, sizeof(cvtbuf) - (d - cvtbuf), number);
524 // probably some label/identifier - pass
527 snprintf(d, sizeof(cvtbuf) - (d - cvtbuf), "%s", w);
531 strcpy(name, cvtbuf);
536 static int is_reg_in_str(const char *s)
540 if (strlen(s) < 3 || (s[3] && !my_issep(s[3]) && !my_isblank(s[3])))
543 for (i = 0; i < ARRAY_SIZE(regs_r32); i++)
544 if (!strncmp(s, regs_r32[i], 3))
550 static const char *parse_stack_el(const char *name, char *extra_reg,
551 int *base_val, int early_try)
553 const char *p, *p2, *s;
559 if (g_bp_frame || early_try)
562 if (IS_START(p + 3, "+ebp+") && is_reg_in_str(p)) {
564 if (extra_reg != NULL) {
565 strncpy(extra_reg, name, 3);
570 if (IS_START(p, "ebp+")) {
574 if (p2 != NULL && is_reg_in_str(p)) {
575 if (extra_reg != NULL) {
576 strncpy(extra_reg, p, p2 - p);
577 extra_reg[p2 - p] = 0;
582 if (!('0' <= *p && *p <= '9'))
589 if (!IS_START(name, "esp+"))
595 if (is_reg_in_str(s)) {
596 if (extra_reg != NULL) {
597 strncpy(extra_reg, s, p - s);
598 extra_reg[p - s] = 0;
603 aerr("%s IDA stackvar not set?\n", __func__);
605 if ('0' <= *s && *s <= '9') {
606 if (s[0] == '0' && s[1] == 'x')
609 if (len < sizeof(buf) - 1) {
610 strncpy(buf, s, len);
613 val = strtol(buf, &endp, 16);
614 if (val == 0 || *endp != 0 || errno != 0) {
615 aerr("%s num parse fail for '%s'\n", __func__, buf);
622 // probably something like [esp+arg_4+2]
630 if ('0' <= *p && *p <= '9')
633 if (base_val != NULL)
638 static int guess_lmod_from_name(struct parsed_opr *opr)
640 if (IS_START(opr->name, "dword_") || IS_START(opr->name, "off_")) {
641 opr->lmod = OPLM_DWORD;
644 if (IS_START(opr->name, "word_")) {
645 opr->lmod = OPLM_WORD;
648 if (IS_START(opr->name, "byte_")) {
649 opr->lmod = OPLM_BYTE;
652 if (IS_START(opr->name, "qword_")) {
653 opr->lmod = OPLM_QWORD;
659 static int guess_lmod_from_c_type(enum opr_lenmod *lmod,
660 const struct parsed_type *c_type)
662 static const char *qword_types[] = {
663 "uint64_t", "int64_t", "__int64",
665 static const char *dword_types[] = {
666 "uint32_t", "int", "_DWORD", "UINT_PTR", "DWORD",
667 "WPARAM", "LPARAM", "UINT", "__int32",
668 "LONG", "HIMC", "BOOL", "size_t",
671 static const char *word_types[] = {
672 "uint16_t", "int16_t", "_WORD", "WORD",
673 "unsigned __int16", "__int16",
675 static const char *byte_types[] = {
676 "uint8_t", "int8_t", "char",
677 "unsigned __int8", "__int8", "BYTE", "_BYTE",
679 // structures.. deal the same as with _UNKNOWN for now
685 if (c_type->is_ptr) {
690 n = skip_type_mod(c_type->name);
692 for (i = 0; i < ARRAY_SIZE(dword_types); i++) {
693 if (IS(n, dword_types[i])) {
699 for (i = 0; i < ARRAY_SIZE(word_types); i++) {
700 if (IS(n, word_types[i])) {
706 for (i = 0; i < ARRAY_SIZE(byte_types); i++) {
707 if (IS(n, byte_types[i])) {
713 for (i = 0; i < ARRAY_SIZE(qword_types); i++) {
714 if (IS(n, qword_types[i])) {
723 static char *default_cast_to(char *buf, size_t buf_size,
724 struct parsed_opr *opr)
728 if (!opr->is_ptr || strchr(opr->name, '['))
730 if (opr->pp == NULL || opr->pp->type.name == NULL
733 snprintf(buf, buf_size, "%s", "(void *)");
737 snprintf(buf, buf_size, "(%s)", opr->pp->type.name);
741 static enum opr_type lmod_from_directive(const char *d)
745 else if (IS(d, "dw"))
747 else if (IS(d, "db"))
750 aerr("unhandled directive: '%s'\n", d);
754 static void setup_reg_opr(struct parsed_opr *opr, int reg, enum opr_lenmod lmod,
760 *regmask |= 1 << reg;
763 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
766 static int parse_operand(struct parsed_opr *opr,
767 int *regmask, int *regmask_indirect,
768 char words[16][256], int wordc, int w, unsigned int op_flags)
770 const struct parsed_proto *pp = NULL;
771 enum opr_lenmod tmplmod;
772 unsigned long number;
780 aerr("parse_operand w %d, wordc %d\n", w, wordc);
784 for (i = w; i < wordc; i++) {
785 len = strlen(words[i]);
786 if (words[i][len - 1] == ',') {
787 words[i][len - 1] = 0;
793 wordc_in = wordc - w;
795 if ((op_flags & OPF_JMP) && wordc_in > 0
796 && !('0' <= words[w][0] && words[w][0] <= '9'))
798 const char *label = NULL;
800 if (wordc_in == 3 && !strncmp(words[w], "near", 4)
801 && IS(words[w + 1], "ptr"))
802 label = words[w + 2];
803 else if (wordc_in == 2 && IS(words[w], "short"))
804 label = words[w + 1];
805 else if (wordc_in == 1
806 && strchr(words[w], '[') == NULL
807 && parse_reg(&tmplmod, words[w]) < 0)
811 opr->type = OPT_LABEL;
812 ret = check_segment_prefix(label);
817 strcpy(opr->name, label);
823 if (IS(words[w + 1], "ptr")) {
824 if (IS(words[w], "dword"))
825 opr->lmod = OPLM_DWORD;
826 else if (IS(words[w], "word"))
827 opr->lmod = OPLM_WORD;
828 else if (IS(words[w], "byte"))
829 opr->lmod = OPLM_BYTE;
830 else if (IS(words[w], "qword"))
831 opr->lmod = OPLM_QWORD;
833 aerr("type parsing failed\n");
835 wordc_in = wordc - w;
840 if (IS(words[w], "offset")) {
841 opr->type = OPT_OFFSET;
842 opr->lmod = OPLM_DWORD;
843 strcpy(opr->name, words[w + 1]);
844 pp = proto_parse(g_fhdr, opr->name, 1);
847 if (IS(words[w], "(offset")) {
848 p = strchr(words[w + 1], ')');
850 aerr("parse of bracketed offset failed\n");
852 opr->type = OPT_OFFSET;
853 strcpy(opr->name, words[w + 1]);
859 aerr("parse_operand 1 word expected\n");
861 ret = check_segment_prefix(words[w]);
864 memmove(words[w], words[w] + 3, strlen(words[w]) - 2);
865 if (ret == SEG_FS && IS(words[w], "0"))
868 strcpy(opr->name, words[w]);
870 if (words[w][0] == '[') {
871 opr->type = OPT_REGMEM;
872 ret = sscanf(words[w], "[%[^]]]", opr->name);
874 aerr("[] parse failure\n");
876 parse_indmode(opr->name, regmask_indirect, 1);
877 if (opr->lmod == OPLM_UNSPEC
878 && parse_stack_el(opr->name, NULL, NULL, 1))
881 struct parsed_equ *eq =
882 equ_find(NULL, parse_stack_el(opr->name, NULL, NULL, 1), &i);
884 opr->lmod = eq->lmod;
886 // might be unaligned access
887 g_func_lmods |= 1 << OPLM_BYTE;
891 else if (strchr(words[w], '[')) {
893 p = strchr(words[w], '[');
894 opr->type = OPT_REGMEM;
895 parse_indmode(p, regmask_indirect, 0);
896 strncpy(buf, words[w], p - words[w]);
897 buf[p - words[w]] = 0;
898 pp = proto_parse(g_fhdr, buf, 1);
901 else if (('0' <= words[w][0] && words[w][0] <= '9')
902 || words[w][0] == '-')
904 number = parse_number(words[w], 0);
905 opr->type = OPT_CONST;
907 printf_number(opr->name, sizeof(opr->name), number);
911 ret = parse_reg(&tmplmod, opr->name);
913 setup_reg_opr(opr, ret, tmplmod, regmask);
917 // most likely var in data segment
918 opr->type = OPT_LABEL;
919 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
923 if (pp->is_fptr || pp->is_func) {
924 opr->lmod = OPLM_DWORD;
928 tmplmod = OPLM_UNSPEC;
929 if (!guess_lmod_from_c_type(&tmplmod, &pp->type))
930 anote("unhandled C type '%s' for '%s'\n",
931 pp->type.name, opr->name);
933 if (opr->lmod == OPLM_UNSPEC) {
935 opr->type_from_var = 1;
937 else if (opr->lmod != tmplmod) {
938 opr->size_mismatch = 1;
939 if (tmplmod < opr->lmod)
942 opr->is_ptr = pp->type.is_ptr;
944 opr->is_array = pp->type.is_array;
948 if (opr->lmod == OPLM_UNSPEC)
949 guess_lmod_from_name(opr);
953 static const struct {
958 { "repe", OPF_REP|OPF_REPZ },
959 { "repz", OPF_REP|OPF_REPZ },
960 { "repne", OPF_REP|OPF_REPNZ },
961 { "repnz", OPF_REP|OPF_REPNZ },
962 { "lock", OPF_LOCK },
965 #define OPF_CJMP_CC (OPF_JMP|OPF_CJMP|OPF_CC)
967 static const struct {
970 unsigned short minopr;
971 unsigned short maxopr;
974 unsigned char pfo_inv;
976 { "nop", OP_NOP, 0, 0, 0 },
977 { "push", OP_PUSH, 1, 1, 0 },
978 { "pop", OP_POP, 1, 1, OPF_DATA },
979 { "pusha",OP_PUSHA, 0, 0, 0 },
980 { "popa", OP_POPA, 0, 0, OPF_DATA },
981 { "leave",OP_LEAVE, 0, 0, OPF_DATA },
982 { "mov" , OP_MOV, 2, 2, OPF_DATA },
983 { "lea", OP_LEA, 2, 2, OPF_DATA },
984 { "movzx",OP_MOVZX, 2, 2, OPF_DATA },
985 { "movsx",OP_MOVSX, 2, 2, OPF_DATA },
986 { "xchg", OP_XCHG, 2, 2, OPF_DATA },
987 { "not", OP_NOT, 1, 1, OPF_DATA },
988 { "xlat", OP_XLAT, 0, 0, OPF_DATA },
989 { "cdq", OP_CDQ, 0, 0, OPF_DATA },
990 { "bswap",OP_BSWAP, 1, 1, OPF_DATA },
991 { "lodsb",OP_LODS, 0, 0, OPF_DATA },
992 { "lodsw",OP_LODS, 0, 0, OPF_DATA },
993 { "lodsd",OP_LODS, 0, 0, OPF_DATA },
994 { "stosb",OP_STOS, 0, 0, OPF_DATA },
995 { "stosw",OP_STOS, 0, 0, OPF_DATA },
996 { "stosd",OP_STOS, 0, 0, OPF_DATA },
997 { "movsb",OP_MOVS, 0, 0, OPF_DATA },
998 { "movsw",OP_MOVS, 0, 0, OPF_DATA },
999 { "movsd",OP_MOVS, 0, 0, OPF_DATA },
1000 { "cmpsb",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
1001 { "cmpsw",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
1002 { "cmpsd",OP_CMPS, 0, 0, OPF_DATA|OPF_FLAGS },
1003 { "scasb",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
1004 { "scasw",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
1005 { "scasd",OP_SCAS, 0, 0, OPF_DATA|OPF_FLAGS },
1006 { "rdtsc",OP_RDTSC, 0, 0, OPF_DATA },
1007 { "cpuid",OP_CPUID, 0, 0, OPF_DATA },
1008 { "std", OP_STD, 0, 0, OPF_DATA }, // special flag
1009 { "cld", OP_CLD, 0, 0, OPF_DATA },
1010 { "add", OP_ADD, 2, 2, OPF_DATA|OPF_FLAGS },
1011 { "sub", OP_SUB, 2, 2, OPF_DATA|OPF_FLAGS },
1012 { "and", OP_AND, 2, 2, OPF_DATA|OPF_FLAGS },
1013 { "or", OP_OR, 2, 2, OPF_DATA|OPF_FLAGS },
1014 { "xor", OP_XOR, 2, 2, OPF_DATA|OPF_FLAGS },
1015 { "shl", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
1016 { "shr", OP_SHR, 2, 2, OPF_DATA|OPF_FLAGS },
1017 { "sal", OP_SHL, 2, 2, OPF_DATA|OPF_FLAGS },
1018 { "sar", OP_SAR, 2, 2, OPF_DATA|OPF_FLAGS },
1019 { "shld", OP_SHLD, 3, 3, OPF_DATA|OPF_FLAGS },
1020 { "shrd", OP_SHRD, 3, 3, OPF_DATA|OPF_FLAGS },
1021 { "rol", OP_ROL, 2, 2, OPF_DATA|OPF_FLAGS },
1022 { "ror", OP_ROR, 2, 2, OPF_DATA|OPF_FLAGS },
1023 { "rcl", OP_RCL, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1024 { "rcr", OP_RCR, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1025 { "adc", OP_ADC, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1026 { "sbb", OP_SBB, 2, 2, OPF_DATA|OPF_FLAGS|OPF_CC, PFO_C },
1027 { "bsf", OP_BSF, 2, 2, OPF_DATA|OPF_FLAGS },
1028 { "bsr", OP_BSR, 2, 2, OPF_DATA|OPF_FLAGS },
1029 { "inc", OP_INC, 1, 1, OPF_DATA|OPF_FLAGS },
1030 { "dec", OP_DEC, 1, 1, OPF_DATA|OPF_FLAGS },
1031 { "neg", OP_NEG, 1, 1, OPF_DATA|OPF_FLAGS },
1032 { "mul", OP_MUL, 1, 1, OPF_DATA|OPF_FLAGS },
1033 { "imul", OP_IMUL, 1, 3, OPF_DATA|OPF_FLAGS },
1034 { "div", OP_DIV, 1, 1, OPF_DATA|OPF_FLAGS },
1035 { "idiv", OP_IDIV, 1, 1, OPF_DATA|OPF_FLAGS },
1036 { "test", OP_TEST, 2, 2, OPF_FLAGS },
1037 { "cmp", OP_CMP, 2, 2, OPF_FLAGS },
1038 { "retn", OP_RET, 0, 1, OPF_TAIL },
1039 { "call", OP_CALL, 1, 1, OPF_JMP|OPF_DATA|OPF_FLAGS },
1040 { "jmp", OP_JMP, 1, 1, OPF_JMP },
1041 { "jecxz",OP_JECXZ, 1, 1, OPF_JMP|OPF_CJMP },
1042 { "loop", OP_LOOP, 1, 1, OPF_JMP|OPF_CJMP|OPF_DATA },
1043 { "jo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 0 }, // 70 OF=1
1044 { "jno", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_O, 1 }, // 71 OF=0
1045 { "jc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72 CF=1
1046 { "jb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 0 }, // 72
1047 { "jnc", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73 CF=0
1048 { "jnb", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1049 { "jae", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_C, 1 }, // 73
1050 { "jz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74 ZF=1
1051 { "je", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 0 }, // 74
1052 { "jnz", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75 ZF=0
1053 { "jne", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_Z, 1 }, // 75
1054 { "jbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76 CF=1||ZF=1
1055 { "jna", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 0 }, // 76
1056 { "ja", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77 CF=0&&ZF=0
1057 { "jnbe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_BE, 1 }, // 77
1058 { "js", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 0 }, // 78 SF=1
1059 { "jns", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_S, 1 }, // 79 SF=0
1060 { "jp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a PF=1
1061 { "jpe", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 0 }, // 7a
1062 { "jnp", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b PF=0
1063 { "jpo", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_P, 1 }, // 7b
1064 { "jl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c SF!=OF
1065 { "jnge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 0 }, // 7c
1066 { "jge", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d SF=OF
1067 { "jnl", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_L, 1 }, // 7d
1068 { "jle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e ZF=1||SF!=OF
1069 { "jng", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 0 }, // 7e
1070 { "jg", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f ZF=0&&SF=OF
1071 { "jnle", OP_JCC, 1, 1, OPF_CJMP_CC, PFO_LE, 1 }, // 7f
1072 { "seto", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 0 },
1073 { "setno", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_O, 1 },
1074 { "setc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1075 { "setb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 0 },
1076 { "setnc", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1077 { "setae", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1078 { "setnb", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_C, 1 },
1079 { "setz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1080 { "sete", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 0 },
1081 { "setnz", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1082 { "setne", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_Z, 1 },
1083 { "setbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1084 { "setna", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 0 },
1085 { "seta", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1086 { "setnbe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_BE, 1 },
1087 { "sets", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 0 },
1088 { "setns", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_S, 1 },
1089 { "setp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1090 { "setpe", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 0 },
1091 { "setnp", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1092 { "setpo", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_P, 1 },
1093 { "setl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1094 { "setnge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 0 },
1095 { "setge", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1096 { "setnl", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_L, 1 },
1097 { "setle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1098 { "setng", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 0 },
1099 { "setg", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1100 { "setnle", OP_SCC, 1, 1, OPF_DATA|OPF_CC, PFO_LE, 1 },
1102 { "fld", OP_FLD, 1, 1, OPF_FPUSH },
1103 { "fild", OP_FILD, 1, 1, OPF_FPUSH|OPF_FINT },
1104 { "fld1", OP_FLDc, 0, 0, OPF_FPUSH },
1105 { "fldl2t", OP_FLDc, 0, 0, OPF_FPUSH },
1106 { "fldl2e", OP_FLDc, 0, 0, OPF_FPUSH },
1107 { "fldpi", OP_FLDc, 0, 0, OPF_FPUSH },
1108 { "fldlg2", OP_FLDc, 0, 0, OPF_FPUSH },
1109 { "fldln2", OP_FLDc, 0, 0, OPF_FPUSH },
1110 { "fldz", OP_FLDc, 0, 0, OPF_FPUSH },
1111 { "fst", OP_FST, 1, 1, 0 },
1112 { "fstp", OP_FST, 1, 1, OPF_FPOP },
1113 { "fist", OP_FIST, 1, 1, OPF_FINT },
1114 { "fistp", OP_FIST, 1, 1, OPF_FPOP|OPF_FINT },
1115 { "fadd", OP_FADD, 0, 2, 0 },
1116 { "faddp", OP_FADD, 0, 2, OPF_FPOP },
1117 { "fdiv", OP_FDIV, 0, 2, 0 },
1118 { "fdivp", OP_FDIV, 0, 2, OPF_FPOP },
1119 { "fmul", OP_FMUL, 0, 2, 0 },
1120 { "fmulp", OP_FMUL, 0, 2, OPF_FPOP },
1121 { "fsub", OP_FSUB, 0, 2, 0 },
1122 { "fsubp", OP_FSUB, 0, 2, OPF_FPOP },
1123 { "fdivr", OP_FDIVR, 0, 2, 0 },
1124 { "fdivrp", OP_FDIVR, 0, 2, OPF_FPOP },
1125 { "fsubr", OP_FSUBR, 0, 2, 0 },
1126 { "fsubrp", OP_FSUBR, 0, 2, OPF_FPOP },
1127 { "fiadd", OP_FIADD, 1, 1, OPF_FINT },
1128 { "fidiv", OP_FIDIV, 1, 1, OPF_FINT },
1129 { "fimul", OP_FIMUL, 1, 1, OPF_FINT },
1130 { "fisub", OP_FISUB, 1, 1, OPF_FINT },
1131 { "fidivr", OP_FIDIVR, 1, 1, OPF_FINT },
1132 { "fisubr", OP_FISUBR, 1, 1, OPF_FINT },
1133 { "fcom", OP_FCOM, 0, 1, 0 },
1134 { "fcomp", OP_FCOM, 0, 1, OPF_FPOP },
1135 { "fcompp", OP_FCOM, 0, 0, OPF_FPOPP },
1136 { "fucom", OP_FCOM, 0, 1, 0 },
1137 { "fucomp", OP_FCOM, 0, 1, OPF_FPOP },
1138 { "fucompp",OP_FCOM, 0, 0, OPF_FPOPP },
1139 { "fnstsw", OP_FNSTSW, 1, 1, OPF_DATA },
1140 { "fchs", OP_FCHS, 0, 0, 0 },
1141 { "fcos", OP_FCOS, 0, 0, 0 },
1142 { "fpatan", OP_FPATAN, 0, 0, OPF_FPOP },
1143 { "fptan", OP_FPTAN, 0, 0, OPF_FPUSH },
1144 { "fsin", OP_FSIN, 0, 0, 0 },
1145 { "fsqrt", OP_FSQRT, 0, 0, 0 },
1146 { "fxch", OP_FXCH, 1, 1, 0 },
1147 { "fyl2x", OP_FYL2X, 0, 0, OPF_FPOP },
1149 { "emms", OP_EMMS, 0, 0, OPF_DATA },
1150 { "movq", OP_MOV, 2, 2, OPF_DATA },
1151 // pseudo-ops for lib calls
1152 { "_allshl",OPP_ALLSHL },
1153 { "_allshr",OPP_ALLSHR },
1154 { "_ftol", OPP_FTOL },
1155 { "_CIpow", OPP_CIPOW },
1156 { "abort", OPP_ABORT },
1161 static void parse_op(struct parsed_op *op, char words[16][256], int wordc)
1163 enum opr_lenmod lmod = OPLM_UNSPEC;
1164 int prefix_flags = 0;
1172 for (i = 0; i < ARRAY_SIZE(pref_table); i++) {
1173 if (IS(words[w], pref_table[i].name)) {
1174 prefix_flags = pref_table[i].flags;
1181 aerr("lone prefix: '%s'\n", words[0]);
1186 for (i = 0; i < ARRAY_SIZE(op_table); i++) {
1187 if (IS(words[w], op_table[i].name))
1191 if (i == ARRAY_SIZE(op_table)) {
1193 aerr("unhandled op: '%s'\n", words[0]);
1198 op->op = op_table[i].op;
1199 op->flags = op_table[i].flags | prefix_flags;
1200 op->pfo = op_table[i].pfo;
1201 op->pfo_inv = op_table[i].pfo_inv;
1202 op->regmask_src = op->regmask_dst = 0;
1205 if (op->op == OP_UD2)
1208 for (opr = 0; opr < op_table[i].maxopr; opr++) {
1209 if (opr >= op_table[i].minopr && w >= wordc)
1212 regmask = regmask_ind = 0;
1213 w = parse_operand(&op->operand[opr], ®mask, ®mask_ind,
1214 words, wordc, w, op->flags);
1216 if (opr == 0 && (op->flags & OPF_DATA))
1217 op->regmask_dst = regmask;
1219 op->regmask_src |= regmask;
1220 op->regmask_src |= regmask_ind;
1222 if (op->operand[opr].lmod != OPLM_UNSPEC)
1223 g_func_lmods |= 1 << op->operand[opr].lmod;
1227 aerr("parse_op %s incomplete: %d/%d\n",
1228 words[0], w, wordc);
1231 op->operand_cnt = opr;
1232 if (!strncmp(op_table[i].name, "set", 3))
1233 op->operand[0].lmod = OPLM_BYTE;
1236 // first operand is not dst
1239 op->regmask_src |= op->regmask_dst;
1240 op->regmask_dst = 0;
1243 // first operand is src too
1256 op->regmask_src |= op->regmask_dst;
1261 op->regmask_src |= op->regmask_dst;
1262 op->regmask_dst |= op->regmask_src;
1268 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1269 && op->operand[0].lmod == op->operand[1].lmod
1270 && op->operand[0].reg == op->operand[1].reg
1271 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1273 op->regmask_src = 0;
1276 op->regmask_src |= op->regmask_dst;
1279 // ops with implicit argumets
1281 op->operand_cnt = 2;
1282 setup_reg_opr(&op->operand[0], xAX, OPLM_BYTE, &op->regmask_src);
1283 op->regmask_dst = op->regmask_src;
1284 setup_reg_opr(&op->operand[1], xBX, OPLM_DWORD, &op->regmask_src);
1288 op->operand_cnt = 2;
1289 setup_reg_opr(&op->operand[0], xDX, OPLM_DWORD, &op->regmask_dst);
1290 setup_reg_opr(&op->operand[1], xAX, OPLM_DWORD, &op->regmask_src);
1296 if (words[op_w][4] == 'b')
1298 else if (words[op_w][4] == 'w')
1300 else if (words[op_w][4] == 'd')
1303 op->regmask_src = 0;
1304 setup_reg_opr(&op->operand[j++], op->op == OP_LODS ? xSI : xDI,
1305 OPLM_DWORD, &op->regmask_src);
1306 op->regmask_dst = op->regmask_src;
1307 setup_reg_opr(&op->operand[j++], xAX, lmod,
1308 op->op == OP_LODS ? &op->regmask_dst : &op->regmask_src);
1309 if (op->flags & OPF_REP) {
1310 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1311 op->regmask_dst |= 1 << xCX;
1313 op->operand_cnt = j;
1318 if (words[op_w][4] == 'b')
1320 else if (words[op_w][4] == 'w')
1322 else if (words[op_w][4] == 'd')
1325 op->regmask_src = 0;
1326 // note: lmod is not correct, don't have where to place it
1327 setup_reg_opr(&op->operand[j++], xDI, lmod, &op->regmask_src);
1328 setup_reg_opr(&op->operand[j++], xSI, OPLM_DWORD, &op->regmask_src);
1329 if (op->flags & OPF_REP)
1330 setup_reg_opr(&op->operand[j++], xCX, OPLM_DWORD, &op->regmask_src);
1331 op->operand_cnt = j;
1332 op->regmask_dst = op->regmask_src;
1336 op->regmask_dst = mxAX | mxDX;
1340 // for now, ignore ecx dep for eax={4,7,b,d}
1341 op->regmask_src = mxAX;
1342 op->regmask_dst = mxAX | mxBX | mxCX | mxDX;
1346 op->regmask_dst = 1 << xCX;
1349 op->operand_cnt = 2;
1350 op->regmask_src = 1 << xCX;
1351 op->operand[1].type = OPT_REG;
1352 op->operand[1].reg = xCX;
1353 op->operand[1].lmod = OPLM_DWORD;
1357 if (op->operand_cnt == 2) {
1358 if (op->operand[0].type != OPT_REG)
1359 aerr("reg expected\n");
1360 op->regmask_src |= 1 << op->operand[0].reg;
1362 if (op->operand_cnt != 1)
1367 if (op->operand[0].lmod == OPLM_UNSPEC)
1368 op->operand[0].lmod = OPLM_DWORD;
1369 op->regmask_src = mxAX | op->regmask_dst;
1370 op->regmask_dst = mxAX;
1371 if (op->operand[0].lmod != OPLM_BYTE)
1372 op->regmask_dst |= mxDX;
1377 // we could set up operands for edx:eax, but there is no real need to
1378 // (see is_opr_modified())
1379 if (op->operand[0].lmod == OPLM_UNSPEC)
1380 op->operand[0].lmod = OPLM_DWORD;
1381 op->regmask_src = mxAX | op->regmask_dst;
1382 op->regmask_dst = mxAX;
1383 if (op->operand[0].lmod != OPLM_BYTE) {
1384 op->regmask_src |= mxDX;
1385 op->regmask_dst |= mxDX;
1394 op->regmask_src |= op->regmask_dst;
1395 if (op->operand[1].lmod == OPLM_UNSPEC)
1396 op->operand[1].lmod = OPLM_BYTE;
1401 op->regmask_src |= op->regmask_dst;
1402 if (op->operand[2].lmod == OPLM_UNSPEC)
1403 op->operand[2].lmod = OPLM_BYTE;
1407 op->regmask_src |= op->regmask_dst;
1408 op->regmask_dst = 0;
1409 if (op->operand[0].lmod == OPLM_UNSPEC
1410 && (op->operand[0].type == OPT_CONST
1411 || op->operand[0].type == OPT_OFFSET
1412 || op->operand[0].type == OPT_LABEL))
1413 op->operand[0].lmod = OPLM_DWORD;
1419 if (op->operand[0].type == OPT_REG && op->operand[1].type == OPT_REG
1420 && op->operand[0].lmod == op->operand[1].lmod
1421 && op->operand[0].reg == op->operand[1].reg
1422 && IS(op->operand[0].name, op->operand[1].name)) // ! ah, al..
1424 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1425 op->regmask_src = op->regmask_dst = 0;
1430 if (op->operand[0].type == OPT_REG
1431 && op->operand[1].type == OPT_REGMEM)
1434 snprintf(buf, sizeof(buf), "%s+0", op->operand[0].name);
1435 if (IS(buf, op->operand[1].name))
1436 op->flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
1441 // needed because of OPF_DATA
1442 op->regmask_src |= op->regmask_dst;
1443 // trashed regs must be explicitly detected later
1444 op->regmask_dst = 0;
1448 op->regmask_dst = (1 << xBP) | (1 << xSP);
1449 op->regmask_src = 1 << xBP;
1454 op->regmask_dst |= mxST0;
1458 op->regmask_dst |= mxST0;
1459 if (IS(words[op_w] + 3, "1"))
1460 op->operand[0].val = X87_CONST_1;
1461 else if (IS(words[op_w] + 3, "l2t"))
1462 op->operand[0].val = X87_CONST_L2T;
1463 else if (IS(words[op_w] + 3, "l2e"))
1464 op->operand[0].val = X87_CONST_L2E;
1465 else if (IS(words[op_w] + 3, "pi"))
1466 op->operand[0].val = X87_CONST_PI;
1467 else if (IS(words[op_w] + 3, "lg2"))
1468 op->operand[0].val = X87_CONST_LG2;
1469 else if (IS(words[op_w] + 3, "ln2"))
1470 op->operand[0].val = X87_CONST_LN2;
1471 else if (IS(words[op_w] + 3, "z"))
1472 op->operand[0].val = X87_CONST_Z;
1474 aerr("fld what?\n");
1479 op->regmask_src |= mxST0;
1488 op->regmask_src |= mxST0;
1489 if (op->operand_cnt == 2)
1490 op->regmask_src |= op->regmask_dst;
1491 else if (op->operand_cnt == 1) {
1492 memcpy(&op->operand[1], &op->operand[0], sizeof(op->operand[1]));
1493 op->operand[0].type = OPT_REG;
1494 op->operand[0].lmod = OPLM_QWORD;
1495 op->operand[0].reg = xST0;
1496 op->regmask_dst |= mxST0;
1499 // IDA doesn't use this
1500 aerr("no operands?\n");
1514 op->regmask_src |= mxST0;
1515 op->regmask_dst |= mxST0;
1520 op->regmask_src |= mxST0 | mxST1;
1521 op->regmask_dst |= mxST0;
1529 op->regmask_src |= mxST0;
1530 if (op->operand_cnt == 0) {
1531 op->operand_cnt = 1;
1532 op->operand[0].type = OPT_REG;
1533 op->operand[0].lmod = OPLM_QWORD;
1534 op->operand[0].reg = xST1;
1535 op->regmask_src |= mxST1;
1543 if (op->operand[0].type == OPT_REG
1544 && op->operand[1].type == OPT_CONST)
1546 struct parsed_opr *op1 = &op->operand[1];
1547 if ((op->op == OP_AND && op1->val == 0)
1550 || (op->operand[0].lmod == OPLM_WORD && op1->val == 0xffff)
1551 || (op->operand[0].lmod == OPLM_BYTE && op1->val == 0xff))))
1553 op->regmask_src = 0;
1558 static const char *op_name(struct parsed_op *po)
1560 static char buf[16];
1564 if (po->op == OP_JCC || po->op == OP_SCC) {
1566 *p++ = (po->op == OP_JCC) ? 'j' : 's';
1569 strcpy(p, parsed_flag_op_names[po->pfo]);
1573 for (i = 0; i < ARRAY_SIZE(op_table); i++)
1574 if (op_table[i].op == po->op)
1575 return op_table[i].name;
1581 static const char *dump_op(struct parsed_op *po)
1583 static char out[128];
1590 snprintf(out, sizeof(out), "%s", op_name(po));
1591 for (i = 0; i < po->operand_cnt; i++) {
1595 snprintf(p, sizeof(out) - (p - out),
1596 po->operand[i].type == OPT_REGMEM ? " [%s]" : " %s",
1597 po->operand[i].name);
1603 static const char *lmod_type_u(struct parsed_op *po,
1604 enum opr_lenmod lmod)
1616 ferr(po, "invalid lmod: %d\n", lmod);
1617 return "(_invalid_)";
1621 static const char *lmod_cast_u(struct parsed_op *po,
1622 enum opr_lenmod lmod)
1634 ferr(po, "invalid lmod: %d\n", lmod);
1635 return "(_invalid_)";
1639 static const char *lmod_cast_u_ptr(struct parsed_op *po,
1640 enum opr_lenmod lmod)
1652 ferr(po, "invalid lmod: %d\n", lmod);
1653 return "(_invalid_)";
1657 static const char *lmod_cast_s(struct parsed_op *po,
1658 enum opr_lenmod lmod)
1670 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1671 return "(_invalid_)";
1675 static const char *lmod_cast(struct parsed_op *po,
1676 enum opr_lenmod lmod, int is_signed)
1679 lmod_cast_s(po, lmod) :
1680 lmod_cast_u(po, lmod);
1683 static int lmod_bytes(struct parsed_op *po, enum opr_lenmod lmod)
1695 ferr(po, "%s: invalid lmod: %d\n", __func__, lmod);
1700 static const char *opr_name(struct parsed_op *po, int opr_num)
1702 if (opr_num >= po->operand_cnt)
1703 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1704 return po->operand[opr_num].name;
1707 static unsigned int opr_const(struct parsed_op *po, int opr_num)
1709 if (opr_num >= po->operand_cnt)
1710 ferr(po, "opr OOR: %d/%d\n", opr_num, po->operand_cnt);
1711 if (po->operand[opr_num].type != OPT_CONST)
1712 ferr(po, "opr %d: const expected\n", opr_num);
1713 return po->operand[opr_num].val;
1716 static const char *opr_reg_p(struct parsed_op *po, struct parsed_opr *popr)
1718 if ((unsigned int)popr->reg >= ARRAY_SIZE(regs_r32))
1719 ferr(po, "invalid reg: %d\n", popr->reg);
1720 return regs_r32[popr->reg];
1723 static int check_simple_cast(const char *cast, int *bits, int *is_signed)
1725 if (IS_START(cast, "(s8)") || IS_START(cast, "(u8)"))
1727 else if (IS_START(cast, "(s16)") || IS_START(cast, "(u16)"))
1729 else if (IS_START(cast, "(s32)") || IS_START(cast, "(u32)"))
1731 else if (IS_START(cast, "(s64)") || IS_START(cast, "(u64)"))
1736 *is_signed = cast[1] == 's' ? 1 : 0;
1740 static int check_deref_cast(const char *cast, int *bits)
1742 if (IS_START(cast, "*(u8 *)"))
1744 else if (IS_START(cast, "*(u16 *)"))
1746 else if (IS_START(cast, "*(u32 *)"))
1748 else if (IS_START(cast, "*(u64 *)"))
1756 // cast1 is the "final" cast
1757 static const char *simplify_cast(const char *cast1, const char *cast2)
1759 static char buf[256];
1767 if (IS(cast1, cast2))
1770 if (check_simple_cast(cast1, &bits1, &s1) == 0
1771 && check_simple_cast(cast2, &bits2, &s2) == 0)
1776 if (check_simple_cast(cast1, &bits1, &s1) == 0
1777 && check_deref_cast(cast2, &bits2) == 0)
1779 if (bits1 == bits2) {
1780 snprintf(buf, sizeof(buf), "*(%c%d *)", s1 ? 's' : 'u', bits1);
1785 if (strchr(cast1, '*') && IS_START(cast2, "(u32)"))
1788 snprintf(buf, sizeof(buf), "%s%s", cast1, cast2);
1792 static const char *simplify_cast_num(const char *cast, unsigned int val)
1794 if (IS(cast, "(u8)") && val < 0x100)
1796 if (IS(cast, "(s8)") && val < 0x80)
1798 if (IS(cast, "(u16)") && val < 0x10000)
1800 if (IS(cast, "(s16)") && val < 0x8000)
1802 if (IS(cast, "(s32)") && val < 0x80000000)
1808 static struct parsed_equ *equ_find(struct parsed_op *po, const char *name,
1817 namelen = strlen(name);
1819 p = strpbrk(name, "+-");
1823 ferr(po, "equ parse failed for '%s'\n", name);
1826 *extra_offs = strtol(p, &endp, 16);
1827 if (*endp != 0 || errno != 0)
1828 ferr(po, "equ parse failed for '%s'\n", name);
1831 for (i = 0; i < g_eqcnt; i++)
1832 if (strncmp(g_eqs[i].name, name, namelen) == 0
1833 && g_eqs[i].name[namelen] == 0)
1837 ferr(po, "unresolved equ name: '%s'\n", name);
1844 static int is_stack_access(struct parsed_op *po,
1845 const struct parsed_opr *popr)
1847 return (parse_stack_el(popr->name, NULL, NULL, 0)
1848 || (g_bp_frame && !(po->flags & OPF_EBP_S)
1849 && IS_START(popr->name, "ebp")));
1852 static void parse_stack_access(struct parsed_op *po,
1853 const char *name, char *ofs_reg, int *offset_out,
1854 int *stack_ra_out, const char **bp_arg_out, int is_lea)
1856 const char *bp_arg = "";
1857 const char *p = NULL;
1858 struct parsed_equ *eq;
1865 if (IS_START(name, "ebp-")
1866 || (IS_START(name, "ebp+") && '0' <= name[4] && name[4] <= '9'))
1869 if (IS_START(p, "0x"))
1872 offset = strtoul(p, &endp, 16);
1875 if (*endp != 0 || errno != 0)
1876 ferr(po, "ebp- parse of '%s' failed\n", name);
1879 bp_arg = parse_stack_el(name, ofs_reg, NULL, 0);
1880 eq = equ_find(po, bp_arg, &offset);
1882 ferr(po, "detected but missing eq\n");
1883 offset += eq->offset;
1886 if (!strncmp(name, "ebp", 3))
1889 // yes it sometimes LEAs ra for compares..
1890 if (!is_lea && ofs_reg[0] == 0
1891 && stack_ra <= offset && offset < stack_ra + 4)
1893 ferr(po, "reference to ra? %d %d\n", offset, stack_ra);
1896 *offset_out = offset;
1898 *stack_ra_out = stack_ra;
1900 *bp_arg_out = bp_arg;
1903 static int parse_stack_esp_offset(struct parsed_op *po,
1904 const char *name, int *offset_out)
1906 char ofs_reg[16] = { 0, };
1907 struct parsed_equ *eq;
1913 if (strstr(name, "esp") == NULL)
1915 bp_arg = parse_stack_el(name, ofs_reg, &base_val, 0);
1916 if (bp_arg == NULL) {
1917 // just plain offset?
1918 if (!IS_START(name, "esp+"))
1921 offset = strtol(name + 4, &endp, 0);
1922 if (endp == NULL || *endp != 0 || errno != 0)
1924 *offset_out = offset;
1928 if (ofs_reg[0] != 0)
1930 eq = equ_find(po, bp_arg, &offset);
1932 ferr(po, "detected but missing eq\n");
1933 offset += eq->offset;
1934 *offset_out = base_val + offset;
1938 static int stack_frame_access(struct parsed_op *po,
1939 struct parsed_opr *popr, char *buf, size_t buf_size,
1940 const char *name, const char *cast, int is_src, int is_lea)
1942 enum opr_lenmod tmp_lmod = OPLM_UNSPEC;
1943 const char *prefix = "";
1944 const char *bp_arg = NULL;
1945 char ofs_reg[16] = { 0, };
1947 int i, arg_i, arg_s;
1954 if (g_bp_frame && (po->flags & OPF_EBP_S)
1955 && !(po->regmask_src & mxSP))
1956 ferr(po, "stack_frame_access while ebp is scratch\n");
1958 parse_stack_access(po, name, ofs_reg, &offset,
1959 &stack_ra, &bp_arg, is_lea);
1961 snprintf(g_comment, sizeof(g_comment), "%s", bp_arg);
1963 if (offset > stack_ra)
1965 arg_i = (offset - stack_ra - 4) / 4;
1966 if (arg_i < 0 || arg_i >= g_func_pp->argc_stack)
1968 if (g_func_pp->is_vararg
1969 && arg_i == g_func_pp->argc_stack && is_lea)
1971 // should be va_list
1974 snprintf(buf, buf_size, "%sap", cast);
1977 ferr(po, "offset 0x%x (%s,%d) doesn't map to any arg\n",
1978 offset, bp_arg, arg_i);
1980 if (ofs_reg[0] != 0)
1981 ferr(po, "offset reg on arg access?\n");
1983 for (i = arg_s = 0; i < g_func_pp->argc; i++) {
1984 if (g_func_pp->arg[i].reg != NULL)
1990 if (i == g_func_pp->argc)
1991 ferr(po, "arg %d not in prototype?\n", arg_i);
1993 popr->is_ptr = g_func_pp->arg[i].type.is_ptr;
1996 snprintf(argname, sizeof(argname), "%sa%d",
1997 g_sct_func_attr & SCTFA_ARGFRAME ? "af." : "", i + 1);
2003 ferr(po, "lea/byte to arg?\n");
2004 if (is_src && (offset & 3) == 0)
2005 snprintf(buf, buf_size, "%s%s",
2006 simplify_cast(cast, "(u8)"), argname);
2008 snprintf(buf, buf_size, "%sBYTE%d(%s)",
2009 cast, offset & 3, argname);
2014 ferr(po, "lea/word to arg?\n");
2019 ferr(po, "problematic arg store\n");
2020 snprintf(buf, buf_size, "%s((char *)&%s + 1)",
2021 simplify_cast(cast, "*(u16 *)"), argname);
2024 ferr(po, "unaligned arg word load\n");
2026 else if (is_src && (offset & 2) == 0)
2027 snprintf(buf, buf_size, "%s%s",
2028 simplify_cast(cast, "(u16)"), argname);
2030 snprintf(buf, buf_size, "%s%sWORD(%s)",
2031 cast, (offset & 2) ? "HI" : "LO", argname);
2043 snprintf(buf, buf_size, "(u32)&%s + %d",
2044 argname, offset & 3);
2046 ferr(po, "unaligned arg store\n");
2048 // mov edx, [ebp+arg_4+2]; movsx ecx, dx
2049 snprintf(buf, buf_size, "%s(%s >> %d)",
2050 prefix, argname, (offset & 3) * 8);
2054 snprintf(buf, buf_size, "%s%s%s",
2055 prefix, is_lea ? "&" : "", argname);
2060 ferr_assert(po, !(offset & 7));
2063 snprintf(buf, buf_size, "%s%s%s",
2064 prefix, is_lea ? "&" : "", argname);
2068 ferr(po, "bp_arg bad lmod: %d\n", popr->lmod);
2072 strcat(g_comment, " unaligned");
2075 guess_lmod_from_c_type(&tmp_lmod, &g_func_pp->arg[i].type);
2076 if (tmp_lmod != OPLM_DWORD
2077 && (unaligned || (!is_src && lmod_bytes(po, tmp_lmod)
2078 < lmod_bytes(po, popr->lmod) + (offset & 3))))
2080 ferr(po, "bp_arg arg%d/w offset %d and type '%s' is too small\n",
2081 i + 1, offset, g_func_pp->arg[i].type.name);
2083 // can't check this because msvc likes to reuse
2084 // arg space for scratch..
2085 //if (popr->is_ptr && popr->lmod != OPLM_DWORD)
2086 // ferr(po, "bp_arg arg%d: non-dword ptr access\n", i + 1);
2090 if (g_stack_fsz == 0)
2091 ferr(po, "stack var access without stackframe\n");
2092 g_stack_frame_used = 1;
2094 sf_ofs = g_stack_fsz + offset;
2095 if (ofs_reg[0] == 0 && (offset > 0 || sf_ofs < 0))
2096 ferr(po, "bp_stack offset %d/%d\n", offset, g_stack_fsz);
2106 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2107 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2111 if ((sf_ofs & 1) || ofs_reg[0] != 0) {
2112 // known unaligned or possibly unaligned
2113 strcat(g_comment, " unaligned");
2115 prefix = "*(u16 *)&";
2116 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2117 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2120 snprintf(buf, buf_size, "%ssf.w[%d]", prefix, sf_ofs / 2);
2124 if ((sf_ofs & 3) || ofs_reg[0] != 0) {
2125 // known unaligned or possibly unaligned
2126 strcat(g_comment, " unaligned");
2128 prefix = "*(u32 *)&";
2129 snprintf(buf, buf_size, "%ssf.b[%d%s%s]",
2130 prefix, sf_ofs, ofs_reg[0] ? "+" : "", ofs_reg);
2133 snprintf(buf, buf_size, "%ssf.d[%d]", prefix, sf_ofs / 4);
2137 ferr_assert(po, !(sf_ofs & 7));
2138 ferr_assert(po, ofs_reg[0] == 0);
2139 // only used for x87 int64/float, float sets is_lea
2140 if (!is_lea && (po->flags & OPF_FINT))
2141 prefix = "*(s64 *)&";
2142 snprintf(buf, buf_size, "%ssf.q[%d]", prefix, sf_ofs / 8);
2146 ferr(po, "bp_stack bad lmod: %d\n", popr->lmod);
2153 static void check_func_pp(struct parsed_op *po,
2154 const struct parsed_proto *pp, const char *pfx)
2156 enum opr_lenmod tmp_lmod;
2160 if (pp->argc_reg != 0) {
2161 if (!g_allow_user_icall && !pp->is_fastcall) {
2162 pp_print(buf, sizeof(buf), pp);
2163 ferr(po, "%s: unexpected reg arg in icall: %s\n", pfx, buf);
2165 if (pp->argc_stack > 0 && pp->argc_reg != 2)
2166 ferr(po, "%s: %d reg arg(s) with %d stack arg(s)\n",
2167 pfx, pp->argc_reg, pp->argc_stack);
2170 // fptrs must use 32bit args, callsite might have no information and
2171 // lack a cast to smaller types, which results in incorrectly masked
2172 // args passed (callee may assume masked args, it does on ARM)
2173 if (!pp->is_osinc) {
2174 for (i = 0; i < pp->argc; i++) {
2175 ret = guess_lmod_from_c_type(&tmp_lmod, &pp->arg[i].type);
2176 if (ret && tmp_lmod != OPLM_DWORD)
2177 ferr(po, "reference to %s with arg%d '%s'\n", pp->name,
2178 i + 1, pp->arg[i].type.name);
2183 static const char *check_label_read_ref(struct parsed_op *po,
2184 const char *name, int *is_import)
2186 const struct parsed_proto *pp;
2188 pp = proto_parse(g_fhdr, name, 0);
2190 ferr(po, "proto_parse failed for ref '%s'\n", name);
2193 check_func_pp(po, pp, "ref");
2195 if (is_import != NULL)
2196 *is_import = pp->is_import;
2201 static void check_opr(struct parsed_op *po, struct parsed_opr *popr)
2203 if (popr->segment == SEG_FS)
2204 ferr(po, "fs: used\n");
2205 if (popr->segment == SEG_GS)
2206 ferr(po, "gs: used\n");
2209 static char *out_src_opr(char *buf, size_t buf_size,
2210 struct parsed_op *po, struct parsed_opr *popr, const char *cast,
2213 char tmp1[256], tmp2[256];
2220 check_opr(po, popr);
2225 switch (popr->type) {
2228 ferr(po, "lea from reg?\n");
2230 switch (popr->lmod) {
2232 snprintf(buf, buf_size, "%s%s.q", cast, opr_reg_p(po, popr));
2235 snprintf(buf, buf_size, "%s%s", cast, opr_reg_p(po, popr));
2238 snprintf(buf, buf_size, "%s%s",
2239 simplify_cast(cast, "(u16)"), opr_reg_p(po, popr));
2242 if (popr->name[1] == 'h') // XXX..
2243 snprintf(buf, buf_size, "%s(%s >> 8)",
2244 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2246 snprintf(buf, buf_size, "%s%s",
2247 simplify_cast(cast, "(u8)"), opr_reg_p(po, popr));
2250 ferr(po, "invalid src lmod: %d\n", popr->lmod);
2255 if (is_stack_access(po, popr)) {
2256 stack_frame_access(po, popr, buf, buf_size,
2257 popr->name, cast, 1, is_lea);
2261 strcpy(expr, popr->name);
2262 if (strchr(expr, '[')) {
2263 // special case: '[' can only be left for label[reg] form
2264 ret = sscanf(expr, "%[^[][%[^]]]", tmp1, tmp2);
2266 ferr(po, "parse failure for '%s'\n", expr);
2267 if (tmp1[0] == '(') {
2268 // (off_4FFF50+3)[eax]
2269 p = strchr(tmp1 + 1, ')');
2270 if (p == NULL || p[1] != 0)
2271 ferr(po, "parse failure (2) for '%s'\n", expr);
2273 memmove(tmp1, tmp1 + 1, strlen(tmp1));
2275 snprintf(expr, sizeof(expr), "(u32)&%s + %s", tmp1, tmp2);
2278 // XXX: do we need more parsing?
2280 snprintf(buf, buf_size, "%s", expr);
2284 snprintf(buf, buf_size, "%s(%s)",
2285 simplify_cast(cast, lmod_cast_u_ptr(po, popr->lmod)), expr);
2289 name = check_label_read_ref(po, popr->name, &is_import);
2291 // for imported data, asm is loading the offset
2294 if (cast[0] == 0 && popr->is_ptr)
2298 snprintf(buf, buf_size, "(u32)&%s", name);
2299 else if (popr->size_lt)
2300 snprintf(buf, buf_size, "%s%s%s%s", cast,
2301 lmod_cast_u_ptr(po, popr->lmod),
2302 popr->is_array ? "" : "&", name);
2304 snprintf(buf, buf_size, "%s%s%s", cast, name,
2305 popr->is_array ? "[0]" : "");
2310 name = check_label_read_ref(po, popr->name, NULL);
2314 ferr(po, "lea an offset?\n");
2315 snprintf(buf, buf_size, "%s&%s", cast, name);
2320 ferr(po, "lea from const?\n");
2322 printf_number(tmp1, sizeof(tmp1), popr->val);
2323 if (popr->val == 0 && strchr(cast, '*'))
2324 snprintf(buf, buf_size, "NULL");
2326 snprintf(buf, buf_size, "%s%s",
2327 simplify_cast_num(cast, popr->val), tmp1);
2331 ferr(po, "invalid src type: %d\n", popr->type);
2337 // note: may set is_ptr (we find that out late for ebp frame..)
2338 static char *out_dst_opr(char *buf, size_t buf_size,
2339 struct parsed_op *po, struct parsed_opr *popr)
2341 check_opr(po, popr);
2343 switch (popr->type) {
2345 switch (popr->lmod) {
2347 snprintf(buf, buf_size, "%s.q", opr_reg_p(po, popr));
2350 snprintf(buf, buf_size, "%s", opr_reg_p(po, popr));
2354 snprintf(buf, buf_size, "LOWORD(%s)", opr_reg_p(po, popr));
2358 if (popr->name[1] == 'h') // XXX..
2359 snprintf(buf, buf_size, "BYTE1(%s)", opr_reg_p(po, popr));
2361 snprintf(buf, buf_size, "LOBYTE(%s)", opr_reg_p(po, popr));
2364 ferr(po, "invalid dst lmod: %d\n", popr->lmod);
2369 if (is_stack_access(po, popr)) {
2370 stack_frame_access(po, popr, buf, buf_size,
2371 popr->name, "", 0, 0);
2375 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2378 if (popr->size_mismatch)
2379 snprintf(buf, buf_size, "%s%s%s",
2380 lmod_cast_u_ptr(po, popr->lmod),
2381 popr->is_array ? "" : "&", popr->name);
2383 snprintf(buf, buf_size, "%s%s", popr->name,
2384 popr->is_array ? "[0]" : "");
2388 ferr(po, "invalid dst type: %d\n", popr->type);
2394 static char *out_src_opr_u32(char *buf, size_t buf_size,
2395 struct parsed_op *po, struct parsed_opr *popr)
2397 return out_src_opr(buf, buf_size, po, popr, NULL, 0);
2400 static char *out_opr_float(char *buf, size_t buf_size,
2401 struct parsed_op *po, struct parsed_opr *popr, int is_src,
2402 int need_float_stack)
2404 const char *cast = NULL;
2411 switch (popr->type) {
2413 if (popr->reg < xST0 || popr->reg > xST7) {
2415 ferr_assert(po, po->op == OP_PUSH);
2416 ferr_assert(po, popr->lmod == OPLM_DWORD);
2417 snprintf(buf, buf_size, "*(float *)&%s", opr_reg_p(po, popr));
2421 if (need_float_stack) {
2422 if (popr->reg == xST0)
2423 snprintf(buf, buf_size, "f_st[f_stp & 7]");
2425 snprintf(buf, buf_size, "f_st[(f_stp + %d) & 7]",
2429 snprintf(buf, buf_size, "f_st%d", popr->reg - xST0);
2433 if (popr->lmod == OPLM_QWORD && is_stack_access(po, popr)) {
2434 stack_frame_access(po, popr, buf, buf_size,
2435 popr->name, "", is_src, 0);
2441 switch (popr->lmod) {
2449 ferr(po, "unhandled lmod: %d\n", popr->lmod);
2452 out_src_opr(tmp, sizeof(tmp), po, popr, "", 1);
2453 snprintf(buf, buf_size, "*(%s *)(%s)", cast, tmp);
2457 // only for func float args pushes
2458 ferr_assert(po, po->op == OP_PUSH);
2459 u.i = po->operand[0].val;
2460 if (ceilf(u.f) == u.f)
2461 snprintf(buf, buf_size, "%.1ff", u.f);
2463 snprintf(buf, buf_size, "%.8ff", u.f);
2467 ferr(po, "invalid float type: %d\n", popr->type);
2473 static char *out_src_opr_float(char *buf, size_t buf_size,
2474 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2476 return out_opr_float(buf, buf_size, po, popr, 1, need_float_stack);
2479 static char *out_dst_opr_float(char *buf, size_t buf_size,
2480 struct parsed_op *po, struct parsed_opr *popr, int need_float_stack)
2482 return out_opr_float(buf, buf_size, po, popr, 0, need_float_stack);
2485 static void out_test_for_cc(char *buf, size_t buf_size,
2486 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2487 enum opr_lenmod lmod, const char *expr)
2489 const char *cast, *scast;
2491 cast = lmod_cast_u(po, lmod);
2492 scast = lmod_cast_s(po, lmod);
2496 case PFO_BE: // CF==1||ZF==1; CF=0
2497 snprintf(buf, buf_size, "(%s%s %s 0)",
2498 cast, expr, is_inv ? "!=" : "==");
2502 case PFO_L: // SF!=OF; OF=0
2503 snprintf(buf, buf_size, "(%s%s %s 0)",
2504 scast, expr, is_inv ? ">=" : "<");
2507 case PFO_LE: // ZF==1||SF!=OF; OF=0
2508 snprintf(buf, buf_size, "(%s%s %s 0)",
2509 scast, expr, is_inv ? ">" : "<=");
2514 snprintf(buf, buf_size, "(%d)", !!is_inv);
2517 case PFO_P: // PF==1
2518 snprintf(buf, buf_size, "(%sdo_parity(%s))",
2519 is_inv ? "!" : "", expr);
2523 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2527 static void out_cmp_for_cc(char *buf, size_t buf_size,
2528 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv,
2531 const char *cast, *scast, *cast_use;
2532 char buf1[256], buf2[256];
2533 enum opr_lenmod lmod;
2535 if (po->op != OP_DEC && po->operand[0].lmod != po->operand[1].lmod)
2536 ferr(po, "%s: lmod mismatch: %d %d\n", __func__,
2537 po->operand[0].lmod, po->operand[1].lmod);
2538 lmod = po->operand[0].lmod;
2540 cast = lmod_cast_u(po, lmod);
2541 scast = lmod_cast_s(po, lmod);
2557 ferr(po, "%s: unhandled parsed_flag_op: %d\n", __func__, pfo);
2560 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], cast_use, 0);
2561 if (po->op == OP_DEC)
2562 snprintf(buf2, sizeof(buf2), "1");
2565 snprintf(cast_op2, sizeof(cast_op2) - 1, "%s", cast_use);
2567 strcat(cast_op2, "-");
2568 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1], cast_op2, 0);
2573 // note: must be unsigned compare
2574 snprintf(buf, buf_size, "(%s %s %s)",
2575 buf1, is_inv ? ">=" : "<", buf2);
2579 snprintf(buf, buf_size, "(%s %s %s)",
2580 buf1, is_inv ? "!=" : "==", buf2);
2584 // note: must be unsigned compare
2585 snprintf(buf, buf_size, "(%s %s %s)",
2586 buf1, is_inv ? ">" : "<=", buf2);
2589 if (is_inv && lmod == OPLM_BYTE
2590 && po->operand[1].type == OPT_CONST
2591 && po->operand[1].val == 0xff)
2593 snprintf(g_comment, sizeof(g_comment), "if %s", buf);
2594 snprintf(buf, buf_size, "(0)");
2598 // note: must be signed compare
2600 snprintf(buf, buf_size, "(%s(%s - %s) %s 0)",
2601 scast, buf1, buf2, is_inv ? ">=" : "<");
2605 snprintf(buf, buf_size, "(%s %s %s)",
2606 buf1, is_inv ? ">=" : "<", buf2);
2610 snprintf(buf, buf_size, "(%s %s %s)",
2611 buf1, is_inv ? ">" : "<=", buf2);
2619 static void out_cmp_test(char *buf, size_t buf_size,
2620 struct parsed_op *po, enum parsed_flag_op pfo, int is_inv)
2622 char buf1[256], buf2[256], buf3[256];
2624 if (po->op == OP_TEST) {
2625 if (IS(opr_name(po, 0), opr_name(po, 1))) {
2626 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[0]);
2629 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
2630 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
2631 snprintf(buf3, sizeof(buf3), "(%s & %s)", buf1, buf2);
2633 out_test_for_cc(buf, buf_size, po, pfo, is_inv,
2634 po->operand[0].lmod, buf3);
2636 else if (po->op == OP_CMP) {
2637 out_cmp_for_cc(buf, buf_size, po, pfo, is_inv, 0);
2640 ferr(po, "%s: unhandled op: %d\n", __func__, po->op);
2643 static void propagate_lmod(struct parsed_op *po, struct parsed_opr *popr1,
2644 struct parsed_opr *popr2)
2646 if (popr1->lmod == OPLM_UNSPEC && popr2->lmod == OPLM_UNSPEC)
2647 ferr(po, "missing lmod for both operands\n");
2649 if (popr1->lmod == OPLM_UNSPEC)
2650 popr1->lmod = popr2->lmod;
2651 else if (popr2->lmod == OPLM_UNSPEC)
2652 popr2->lmod = popr1->lmod;
2653 else if (popr1->lmod != popr2->lmod) {
2654 if (popr1->type_from_var) {
2655 popr1->size_mismatch = 1;
2656 if (popr1->lmod < popr2->lmod)
2658 popr1->lmod = popr2->lmod;
2660 else if (popr2->type_from_var) {
2661 popr2->size_mismatch = 1;
2662 if (popr2->lmod < popr1->lmod)
2664 popr2->lmod = popr1->lmod;
2667 ferr(po, "conflicting lmods: %d vs %d\n",
2668 popr1->lmod, popr2->lmod);
2672 static const char *op_to_c(struct parsed_op *po)
2696 ferr(po, "op_to_c was supplied with %d\n", po->op);
2700 // last op in stream - unconditional branch or ret
2701 #define LAST_OP(_i) ((ops[_i].flags & OPF_TAIL) \
2702 || ((ops[_i].flags & (OPF_JMP|OPF_CJMP|OPF_RMD)) == OPF_JMP \
2703 && ops[_i].op != OP_CALL))
2705 #define check_i(po, i) \
2707 ferr(po, "bad " #i ": %d\n", i)
2709 // note: this skips over calls and rm'd stuff assuming they're handled
2710 // so it's intended to use at one of final passes
2711 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2712 int depth, int seen_noreturn, int flags_set)
2714 struct parsed_op *po;
2719 for (; i < opcnt; i++) {
2721 if (po->cc_scratch == magic)
2722 return ret; // already checked
2723 po->cc_scratch = magic;
2725 if (po->flags & OPF_TAIL) {
2726 if (po->op == OP_CALL) {
2727 if (po->pp != NULL && po->pp->is_noreturn)
2736 if (po->flags & (OPF_RMD|OPF_DONE|OPF_FARG))
2739 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2740 if (po->btj != NULL) {
2742 for (j = 0; j < po->btj->count; j++) {
2743 check_i(po, po->btj->d[j].bt_i);
2744 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2745 depth, seen_noreturn, flags_set);
2747 return ret; // dead end
2752 check_i(po, po->bt_i);
2753 if (po->flags & OPF_CJMP) {
2754 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2755 depth, seen_noreturn, flags_set);
2757 return ret; // dead end
2766 if ((po->op == OP_POP || po->op == OP_PUSH)
2767 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2772 if (po->op == OP_PUSH) {
2775 else if (po->op == OP_POP) {
2776 if (relevant && depth == 0) {
2777 po->flags |= flags_set;
2785 // for noreturn, assume msvc skipped stack cleanup
2786 return seen_noreturn ? 1 : -1;
2789 // scan for 'reg' pop backwards starting from i
2790 // intended to use for register restore search, so other reg
2791 // references are considered an error
2792 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2794 struct parsed_op *po;
2795 struct label_ref *lr;
2798 ops[i].cc_scratch = magic;
2802 if (g_labels[i] != NULL) {
2803 lr = &g_label_refs[i];
2804 for (; lr != NULL; lr = lr->next) {
2805 check_i(&ops[i], lr->i);
2806 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2810 if (i > 0 && LAST_OP(i - 1))
2818 if (ops[i].cc_scratch == magic)
2820 ops[i].cc_scratch = magic;
2823 if (po->op == OP_POP && po->operand[0].reg == reg) {
2824 if (po->flags & (OPF_RMD|OPF_DONE))
2827 po->flags |= set_flags;
2831 // this also covers the case where we reach corresponding push
2832 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2836 // nothing interesting on this path,
2837 // still return ret for something recursive calls could find
2841 static void find_reachable_exits(int i, int opcnt, int magic,
2842 int *exits, int *exit_count)
2844 struct parsed_op *po;
2847 for (; i < opcnt; i++)
2850 if (po->cc_scratch == magic)
2852 po->cc_scratch = magic;
2854 if (po->flags & OPF_TAIL) {
2855 ferr_assert(po, *exit_count < MAX_EXITS);
2856 exits[*exit_count] = i;
2861 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2862 if (po->flags & OPF_RMD)
2865 if (po->btj != NULL) {
2866 for (j = 0; j < po->btj->count; j++) {
2867 check_i(po, po->btj->d[j].bt_i);
2868 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2874 check_i(po, po->bt_i);
2875 if (po->flags & OPF_CJMP)
2876 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2884 // scan for 'reg' pop backwards starting from exits (all paths)
2885 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2887 static int exits[MAX_EXITS];
2888 static int exit_count;
2894 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2896 ferr_assert(&ops[i], exit_count > 0);
2899 for (j = 0; j < exit_count; j++) {
2901 ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2907 if (ops[e].op == OP_CALL && ops[e].pp != NULL
2908 && ops[e].pp->is_noreturn)
2910 // assume stack cleanup was skipped
2919 // scan for one or more pop of push <const>
2920 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2921 int push_i, int is_probe)
2923 struct parsed_op *po;
2924 struct label_ref *lr;
2928 for (; i < opcnt; i++)
2931 if (po->cc_scratch == magic)
2932 return ret; // already checked
2933 po->cc_scratch = magic;
2935 if (po->flags & OPF_JMP) {
2936 if (po->flags & OPF_RMD)
2938 if (po->op == OP_CALL)
2941 if (po->btj != NULL) {
2942 for (j = 0; j < po->btj->count; j++) {
2943 check_i(po, po->btj->d[j].bt_i);
2944 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2952 check_i(po, po->bt_i);
2953 if (po->flags & OPF_CJMP) {
2954 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2965 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2968 if (g_labels[i] != NULL) {
2969 // all refs must be visited
2970 lr = &g_label_refs[i];
2971 for (; lr != NULL; lr = lr->next) {
2973 if (ops[lr->i].cc_scratch != magic)
2976 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2980 if (po->op == OP_POP)
2982 if (po->flags & (OPF_RMD|OPF_DONE))
2986 po->flags |= OPF_DONE;
2987 po->datap = &ops[push_i];
2996 static void scan_for_pop_const(int i, int opcnt, int magic)
3000 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
3002 ops[i].flags |= OPF_RMD | OPF_DONE;
3003 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
3007 // check if all branch targets within a marked path are also marked
3008 // note: the path checked must not be empty or end with a branch
3009 static int check_path_branches(int opcnt, int magic)
3011 struct parsed_op *po;
3014 for (i = 0; i < opcnt; i++) {
3016 if (po->cc_scratch != magic)
3019 if (po->flags & OPF_JMP) {
3020 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
3023 if (po->btj != NULL) {
3024 for (j = 0; j < po->btj->count; j++) {
3025 check_i(po, po->btj->d[j].bt_i);
3026 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
3031 check_i(po, po->bt_i);
3032 if (ops[po->bt_i].cc_scratch != magic)
3034 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
3042 // scan for multiple pushes for given pop
3043 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
3046 int reg = ops[pop_i].operand[0].reg;
3047 struct parsed_op *po;
3048 struct label_ref *lr;
3051 ops[i].cc_scratch = magic;
3055 if (g_labels[i] != NULL) {
3056 lr = &g_label_refs[i];
3057 for (; lr != NULL; lr = lr->next) {
3058 check_i(&ops[i], lr->i);
3059 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
3063 if (i > 0 && LAST_OP(i - 1))
3071 if (ops[i].cc_scratch == magic)
3073 ops[i].cc_scratch = magic;
3076 if (po->op == OP_CALL)
3078 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
3081 if (po->op == OP_PUSH)
3083 if (po->datap != NULL)
3085 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
3086 // leave this case for reg save/restore handlers
3090 po->flags |= OPF_PPUSH | OPF_DONE;
3091 po->datap = &ops[pop_i];
3100 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
3102 int magic = i + opcnt * 14;
3105 ret = scan_pushes_for_pop_r(i, magic, i, 1);
3107 ret = check_path_branches(opcnt, magic);
3109 ops[i].flags |= OPF_PPUSH | OPF_DONE;
3110 *regmask_pp |= 1 << ops[i].operand[0].reg;
3111 scan_pushes_for_pop_r(i, magic + 1, i, 0);
3116 static void scan_propagate_df(int i, int opcnt)
3118 struct parsed_op *po = &ops[i];
3121 for (; i < opcnt; i++) {
3123 if (po->flags & OPF_DF)
3124 return; // already resolved
3125 po->flags |= OPF_DF;
3127 if (po->op == OP_CALL)
3128 ferr(po, "call with DF set?\n");
3130 if (po->flags & OPF_JMP) {
3131 if (po->btj != NULL) {
3133 for (j = 0; j < po->btj->count; j++) {
3134 check_i(po, po->btj->d[j].bt_i);
3135 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
3140 if (po->flags & OPF_RMD)
3142 check_i(po, po->bt_i);
3143 if (po->flags & OPF_CJMP)
3144 scan_propagate_df(po->bt_i, opcnt);
3150 if (po->flags & OPF_TAIL)
3153 if (po->op == OP_CLD) {
3154 po->flags |= OPF_RMD | OPF_DONE;
3159 ferr(po, "missing DF clear?\n");
3162 // is operand 'opr' referenced by parsed_op 'po'?
3163 static int is_opr_referenced(const struct parsed_opr *opr,
3164 const struct parsed_op *po)
3168 if (opr->type == OPT_REG) {
3169 mask = po->regmask_dst | po->regmask_src;
3170 if (po->op == OP_CALL)
3171 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3172 if ((1 << opr->reg) & mask)
3178 for (i = 0; i < po->operand_cnt; i++)
3179 if (IS(po->operand[0].name, opr->name))
3185 // is operand 'opr' read by parsed_op 'po'?
3186 static int is_opr_read(const struct parsed_opr *opr,
3187 const struct parsed_op *po)
3189 if (opr->type == OPT_REG) {
3190 if (po->regmask_src & (1 << opr->reg))
3200 // is operand 'opr' modified by parsed_op 'po'?
3201 static int is_opr_modified(const struct parsed_opr *opr,
3202 const struct parsed_op *po)
3206 if (opr->type == OPT_REG) {
3207 if (po->op == OP_CALL) {
3208 mask = po->regmask_dst;
3209 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3210 if (mask & (1 << opr->reg))
3216 if (po->regmask_dst & (1 << opr->reg))
3222 return IS(po->operand[0].name, opr->name);
3225 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3226 static int is_any_opr_modified(const struct parsed_op *po_test,
3227 const struct parsed_op *po, int c_mode)
3232 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3235 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3238 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3241 // in reality, it can wreck any register, but in decompiled C
3242 // version it can only overwrite eax or edx:eax
3243 mask = (1 << xAX) | (1 << xDX);
3247 if (po->op == OP_CALL
3248 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3251 for (i = 0; i < po_test->operand_cnt; i++)
3252 if (IS(po_test->operand[i].name, po->operand[0].name))
3258 // scan for any po_test operand modification in range given
3259 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3262 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3265 for (; i < opcnt; i++) {
3266 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3273 // scan for po_test operand[0] modification in range given
3274 static int scan_for_mod_opr0(struct parsed_op *po_test,
3277 for (; i < opcnt; i++) {
3278 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3285 static int try_resolve_const(int i, const struct parsed_opr *opr,
3286 int magic, unsigned int *val);
3288 static int scan_for_flag_set(int i, int opcnt, int magic,
3289 int *branched, int *setters, int *setter_cnt)
3291 struct label_ref *lr;
3295 if (ops[i].cc_scratch == magic) {
3296 // is this a problem?
3297 //ferr(&ops[i], "%s looped\n", __func__);
3300 ops[i].cc_scratch = magic;
3302 if (g_labels[i] != NULL) {
3305 lr = &g_label_refs[i];
3306 for (; lr->next; lr = lr->next) {
3307 check_i(&ops[i], lr->i);
3308 ret = scan_for_flag_set(lr->i, opcnt, magic,
3309 branched, setters, setter_cnt);
3314 check_i(&ops[i], lr->i);
3315 if (i > 0 && LAST_OP(i - 1)) {
3319 ret = scan_for_flag_set(lr->i, opcnt, magic,
3320 branched, setters, setter_cnt);
3326 if (ops[i].flags & OPF_FLAGS) {
3327 setters[*setter_cnt] = i;
3330 if (ops[i].flags & OPF_REP) {
3331 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3334 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3335 if (ret != 1 || uval == 0) {
3336 // can't treat it as full setter because of ecx=0 case,
3337 // also disallow delayed compare
3346 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3353 // scan back for cdq, if anything modifies edx, fail
3354 static int scan_for_cdq_edx(int i)
3357 if (g_labels[i] != NULL) {
3358 if (g_label_refs[i].next != NULL)
3360 if (i > 0 && LAST_OP(i - 1)) {
3361 i = g_label_refs[i].i;
3368 if (ops[i].op == OP_CDQ)
3371 if (ops[i].regmask_dst & (1 << xDX))
3378 static int scan_for_reg_clear(int i, int reg)
3381 if (g_labels[i] != NULL) {
3382 if (g_label_refs[i].next != NULL)
3384 if (i > 0 && LAST_OP(i - 1)) {
3385 i = g_label_refs[i].i;
3392 if (ops[i].op == OP_XOR
3393 && ops[i].operand[0].lmod == OPLM_DWORD
3394 && ops[i].operand[0].reg == ops[i].operand[1].reg
3395 && ops[i].operand[0].reg == reg)
3398 if (ops[i].regmask_dst & (1 << reg))
3405 static void patch_esp_adjust(struct parsed_op *po, int adj)
3407 ferr_assert(po, po->op == OP_ADD);
3408 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3409 ferr_assert(po, po->operand[1].type == OPT_CONST);
3411 // this is a bit of a hack, but deals with use of
3412 // single adj for multiple calls
3413 po->operand[1].val -= adj;
3414 po->flags |= OPF_RMD;
3415 if (po->operand[1].val == 0)
3416 po->flags |= OPF_DONE;
3417 ferr_assert(po, (int)po->operand[1].val >= 0);
3420 // scan for positive, constant esp adjust
3421 // multipath case is preliminary
3422 static int scan_for_esp_adjust(int i, int opcnt,
3423 int adj_expect, int *adj, int *is_multipath, int do_update)
3425 int adj_expect_unknown = 0;
3426 struct parsed_op *po;
3430 *adj = *is_multipath = 0;
3431 if (adj_expect < 0) {
3432 adj_expect_unknown = 1;
3433 adj_expect = 32 * 4; // enough?
3436 for (; i < opcnt && *adj < adj_expect; i++) {
3437 if (g_labels[i] != NULL)
3441 if (po->flags & OPF_DONE)
3444 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3445 if (po->operand[1].type != OPT_CONST)
3446 ferr(&ops[i], "non-const esp adjust?\n");
3447 *adj += po->operand[1].val;
3449 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3452 patch_esp_adjust(po, adj_expect);
3454 po->flags |= OPF_RMD;
3458 else if (po->op == OP_PUSH) {
3459 //if (first_pop == -1)
3460 // first_pop = -2; // none
3461 *adj -= lmod_bytes(po, po->operand[0].lmod);
3463 else if (po->op == OP_POP) {
3464 if (!(po->flags & OPF_DONE)) {
3465 // seems like msvc only uses 'pop ecx' for stack realignment..
3466 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3468 if (first_pop == -1 && *adj >= 0)
3471 if (do_update && *adj >= 0) {
3472 po->flags |= OPF_RMD;
3474 po->flags |= OPF_DONE | OPF_NOREGS;
3477 *adj += lmod_bytes(po, po->operand[0].lmod);
3478 if (*adj > adj_best)
3481 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3482 if (po->op == OP_JMP && po->btj == NULL) {
3488 if (po->op != OP_CALL)
3490 if (po->operand[0].type != OPT_LABEL)
3492 if (po->pp != NULL && po->pp->is_stdcall)
3494 if (adj_expect_unknown && first_pop >= 0)
3496 // assume it's another cdecl call
3500 if (first_pop >= 0) {
3501 // probably only 'pop ecx' was used
3509 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3511 struct parsed_op *po;
3515 ferr(ops, "%s: followed bad branch?\n", __func__);
3517 for (; i < opcnt; i++) {
3519 if (po->cc_scratch == magic)
3521 po->cc_scratch = magic;
3524 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3525 if (po->btj != NULL) {
3527 for (j = 0; j < po->btj->count; j++)
3528 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3532 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3533 if (!(po->flags & OPF_CJMP))
3536 if (po->flags & OPF_TAIL)
3541 static const struct parsed_proto *try_recover_pp(
3542 struct parsed_op *po, const struct parsed_opr *opr,
3543 int is_call, int *search_instead)
3545 const struct parsed_proto *pp = NULL;
3549 if (po->pp != NULL && (po->flags & OPF_DATA)) {
3550 // hint given in asm
3554 // maybe an arg of g_func?
3555 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3557 char ofs_reg[16] = { 0, };
3558 int arg, arg_s, arg_i;
3565 parse_stack_access(po, opr->name, ofs_reg,
3566 &offset, &stack_ra, NULL, 0);
3567 if (ofs_reg[0] != 0)
3568 ferr(po, "offset reg on arg access?\n");
3569 if (offset <= stack_ra) {
3570 // search who set the stack var instead
3571 if (search_instead != NULL)
3572 *search_instead = 1;
3576 arg_i = (offset - stack_ra - 4) / 4;
3577 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3578 if (g_func_pp->arg[arg].reg != NULL)
3584 if (arg == g_func_pp->argc)
3585 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3587 pp = g_func_pp->arg[arg].pp;
3590 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3591 check_func_pp(po, pp, "icall arg");
3594 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3596 p = strchr(opr->name + 1, '[');
3597 memcpy(buf, opr->name, p - opr->name);
3598 buf[p - opr->name] = 0;
3599 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3601 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3602 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3605 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3608 check_func_pp(po, pp, "reg-fptr ref");
3614 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3615 int magic, const struct parsed_proto **pp_found, int *pp_i,
3618 const struct parsed_proto *pp = NULL;
3619 struct parsed_op *po;
3620 struct label_ref *lr;
3622 ops[i].cc_scratch = magic;
3625 if (g_labels[i] != NULL) {
3626 lr = &g_label_refs[i];
3627 for (; lr != NULL; lr = lr->next) {
3628 check_i(&ops[i], lr->i);
3629 scan_for_call_type(lr->i, opr, magic, pp_found, pp_i, multi);
3631 if (i > 0 && LAST_OP(i - 1))
3639 if (ops[i].cc_scratch == magic)
3641 ops[i].cc_scratch = magic;
3643 if (!(ops[i].flags & OPF_DATA))
3645 if (!is_opr_modified(opr, &ops[i]))
3647 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3648 // most probably trashed by some processing
3653 opr = &ops[i].operand[1];
3654 if (opr->type != OPT_REG)
3658 po = (i >= 0) ? &ops[i] : ops;
3661 // reached the top - can only be an arg-reg
3662 if (opr->type != OPT_REG || g_func_pp == NULL)
3665 for (i = 0; i < g_func_pp->argc; i++) {
3666 if (g_func_pp->arg[i].reg == NULL)
3668 if (IS(opr->name, g_func_pp->arg[i].reg))
3671 if (i == g_func_pp->argc)
3673 pp = g_func_pp->arg[i].pp;
3675 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3676 i + 1, g_func_pp->arg[i].reg);
3677 check_func_pp(po, pp, "icall reg-arg");
3680 pp = try_recover_pp(po, opr, 1, NULL);
3682 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3683 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3684 || (*pp_found)->is_stdcall != pp->is_stdcall
3685 //|| (*pp_found)->is_fptr != pp->is_fptr
3686 || (*pp_found)->argc != pp->argc
3687 || (*pp_found)->argc_reg != pp->argc_reg
3688 || (*pp_found)->argc_stack != pp->argc_stack)
3690 ferr(po, "icall: parsed_proto mismatch\n");
3700 static void add_label_ref(struct label_ref *lr, int op_i)
3702 struct label_ref *lr_new;
3709 lr_new = calloc(1, sizeof(*lr_new));
3711 lr_new->next = lr->next;
3715 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3717 struct parsed_op *po = &ops[i];
3718 struct parsed_data *pd;
3719 char label[NAMELEN], *p;
3722 p = strchr(po->operand[0].name, '[');
3726 len = p - po->operand[0].name;
3727 strncpy(label, po->operand[0].name, len);
3730 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3731 if (IS(g_func_pd[j].label, label)) {
3737 //ferr(po, "label '%s' not parsed?\n", label);
3740 if (pd->type != OPT_OFFSET)
3741 ferr(po, "label '%s' with non-offset data?\n", label);
3743 // find all labels, link
3744 for (j = 0; j < pd->count; j++) {
3745 for (l = 0; l < opcnt; l++) {
3746 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3747 add_label_ref(&g_label_refs[l], i);
3757 static void clear_labels(int count)
3761 for (i = 0; i < count; i++) {
3762 if (g_labels[i] != NULL) {
3769 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3774 for (i = 0; i < pp->argc; i++) {
3775 if (pp->arg[i].reg != NULL) {
3776 reg = char_array_i(regs_r32,
3777 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3779 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3780 pp->arg[i].reg, pp->name);
3781 regmask |= 1 << reg;
3788 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3793 if (pp->has_retreg) {
3794 for (i = 0; i < pp->argc; i++) {
3795 if (pp->arg[i].type.is_retreg) {
3796 reg = char_array_i(regs_r32,
3797 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3798 ferr_assert(ops, reg >= 0);
3799 regmask |= 1 << reg;
3804 if (strstr(pp->ret_type.name, "int64"))
3805 return regmask | (1 << xAX) | (1 << xDX);
3806 if (IS(pp->ret_type.name, "float")
3807 || IS(pp->ret_type.name, "double"))
3809 return regmask | mxST0;
3811 if (strcasecmp(pp->ret_type.name, "void") == 0)
3814 return regmask | mxAX;
3817 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3819 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3820 && memcmp(po1->operand, po2->operand,
3821 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3824 static void resolve_branches_parse_calls(int opcnt)
3826 static const struct {
3830 unsigned int regmask_src;
3831 unsigned int regmask_dst;
3833 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3834 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3835 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3836 // more precise? Wine gets away with just __ftol handler
3837 { "__ftol2", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3838 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3840 const struct parsed_proto *pp_c;
3841 struct parsed_proto *pp;
3842 struct parsed_data *pd;
3843 struct parsed_op *po;
3844 const char *tmpname;
3849 for (i = 0; i < opcnt; i++)
3855 if (po->datap != NULL) {
3856 pp = calloc(1, sizeof(*pp));
3857 my_assert_not(pp, NULL);
3859 ret = parse_protostr(po->datap, pp);
3861 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3867 if (po->op == OP_CALL) {
3872 else if (po->operand[0].type == OPT_LABEL)
3874 tmpname = opr_name(po, 0);
3875 if (IS_START(tmpname, "loc_")) {
3877 ferr(po, "call to loc_*\n");
3878 // eliminate_seh() must take care of it
3881 if (IS(tmpname, "__alloca_probe"))
3883 if (IS(tmpname, "__SEH_prolog")) {
3884 ferr_assert(po, g_seh_found == 0);
3888 if (IS(tmpname, "__SEH_epilog"))
3891 // convert some calls to pseudo-ops
3892 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3893 if (!IS(tmpname, pseudo_ops[l].name))
3896 po->op = pseudo_ops[l].op;
3897 po->operand_cnt = 0;
3898 po->regmask_src = pseudo_ops[l].regmask_src;
3899 po->regmask_dst = pseudo_ops[l].regmask_dst;
3900 po->flags = pseudo_ops[l].flags;
3901 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3904 if (l < ARRAY_SIZE(pseudo_ops))
3907 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3908 if (!g_header_mode && pp_c == NULL)
3909 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3912 pp = proto_clone(pp_c);
3913 my_assert_not(pp, NULL);
3919 check_func_pp(po, pp, "fptr var call");
3920 if (pp->is_noreturn) {
3921 po->flags |= OPF_TAIL;
3922 po->flags &= ~OPF_ATAIL; // most likely...
3929 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3932 if (po->operand[0].type == OPT_REGMEM) {
3933 pd = try_resolve_jumptab(i, opcnt);
3941 for (l = 0; l < opcnt; l++) {
3942 if (g_labels[l] != NULL
3943 && IS(po->operand[0].name, g_labels[l]))
3945 if (l == i + 1 && po->op == OP_JMP) {
3946 // yet another alignment type...
3947 po->flags |= OPF_RMD | OPF_DONE;
3948 po->flags &= ~OPF_JMP;
3952 add_label_ref(&g_label_refs[l], i);
3958 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3961 if (po->operand[0].type == OPT_LABEL)
3965 ferr(po, "unhandled branch\n");
3969 po->flags |= OPF_TAIL;
3970 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3971 if (prev_op == OP_POP)
3972 po->flags |= OPF_ATAIL;
3973 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3974 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3976 po->flags |= OPF_ATAIL;
3982 static int resolve_origin(int i, const struct parsed_opr *opr,
3983 int magic, int *op_i, int *is_caller);
3984 static void set_label(int i, const char *name);
3986 static void eliminate_seh_writes(int opcnt)
3988 const struct parsed_opr *opr;
3993 // assume all sf writes above g_seh_size to be seh related
3994 // (probably unsafe but oh well)
3995 for (i = 0; i < opcnt; i++) {
3996 if (ops[i].op != OP_MOV)
3998 opr = &ops[i].operand[0];
3999 if (opr->type != OPT_REGMEM)
4001 if (!is_stack_access(&ops[i], opr))
4005 parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
4007 if (offset < 0 && offset >= -g_seh_size)
4008 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4012 static void eliminate_seh_finally(int opcnt)
4014 const char *target_name = NULL;
4015 const char *return_name = NULL;
4016 int exits[MAX_EXITS];
4024 for (i = 0; i < opcnt; i++) {
4025 if (ops[i].op != OP_CALL)
4027 if (!IS_START(opr_name(&ops[i], 0), "loc_"))
4029 if (target_name != NULL)
4030 ferr(&ops[i], "multiple finally calls? (last was %s)\n",
4032 target_name = opr_name(&ops[i], 0);
4035 if (g_labels[i + 1] == NULL)
4036 set_label(i + 1, "seh_fin_done");
4037 return_name = g_labels[i + 1];
4045 // find finally code (bt_i is not set because it's call)
4046 for (i = 0; i < opcnt; i++) {
4047 if (g_labels[i] == NULL)
4049 if (!IS(g_labels[i], target_name))
4052 ferr_assert(&ops[i], target_i == -1);
4055 ferr_assert(&ops[0], target_i != -1);
4057 find_reachable_exits(target_i, opcnt, target_i + opcnt * 24,
4058 exits, &exit_count);
4059 ferr_assert(&ops[target_i], exit_count == 1);
4060 ferr_assert(&ops[target_i], ops[exits[0]].op == OP_RET);
4063 // convert to jumps, link
4064 ops[call_i].op = OP_JMP;
4065 ops[call_i].bt_i = target_i;
4066 add_label_ref(&g_label_refs[target_i], call_i);
4068 ops[tgend_i].op = OP_JMP;
4069 ops[tgend_i].flags &= ~OPF_TAIL;
4070 ops[tgend_i].flags |= OPF_JMP;
4071 ops[tgend_i].bt_i = return_i;
4072 ops[tgend_i].operand_cnt = 1;
4073 ops[tgend_i].operand[0].type = OPT_LABEL;
4074 snprintf(ops[tgend_i].operand[0].name, NAMELEN, "%s", return_name);
4075 add_label_ref(&g_label_refs[return_i], tgend_i);
4077 // rm seh finally entry code
4078 for (i = target_i - 1; i >= 0; i--) {
4079 if (g_labels[i] != NULL && g_label_refs[i].i != -1)
4081 if (ops[i].flags & OPF_CJMP)
4083 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4086 for (i = target_i - 1; i >= 0; i--) {
4087 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4089 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4093 static void eliminate_seh(int opcnt)
4097 for (i = 0; i < opcnt; i++) {
4098 if (ops[i].op != OP_MOV)
4100 if (ops[i].operand[0].segment != SEG_FS)
4102 if (!IS(opr_name(&ops[i], 0), "0"))
4105 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4106 if (ops[i].operand[1].reg == xSP) {
4107 for (j = i - 1; j >= 0; j--) {
4108 if (ops[j].op != OP_PUSH)
4110 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4112 if (ops[j].operand[0].val == ~0)
4114 if (ops[j].operand[0].type == OPT_REG) {
4116 ret = resolve_origin(j, &ops[j].operand[0],
4117 j + opcnt * 22, &k, NULL);
4119 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4123 ferr(ops, "missing seh terminator\n");
4127 ret = resolve_origin(i, &ops[i].operand[1],
4128 i + opcnt * 23, &k, NULL);
4130 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4134 eliminate_seh_writes(opcnt);
4135 eliminate_seh_finally(opcnt);
4138 static void eliminate_seh_calls(int opcnt)
4140 int epilog_found = 0;
4147 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4148 && ops[i].operand[0].type == OPT_CONST);
4149 g_stack_fsz = g_seh_size + ops[i].operand[0].val;
4150 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4153 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4154 && ops[i].operand[0].type == OPT_OFFSET);
4155 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4158 ferr_assert(&ops[i], ops[i].op == OP_CALL
4159 && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
4160 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4162 for (i++; i < opcnt; i++) {
4163 if (ops[i].op != OP_CALL)
4165 if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
4168 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4171 ferr_assert(ops, epilog_found);
4173 eliminate_seh_writes(opcnt);
4174 eliminate_seh_finally(opcnt);
4177 // check for prologue of many pushes and epilogue with pops
4178 static void check_simple_sequence(int opcnt, int *fsz)
4187 for (i = 0; i < opcnt && i < ARRAY_SIZE(seq); i++) {
4188 if (ops[i].op != OP_PUSH || ops[i].operand[0].type != OPT_REG)
4190 reg = ops[i].operand[0].reg;
4191 if (reg != xBX && reg != xSI && reg != xDI && reg != xBP)
4193 for (j = 0; j < i; j++)
4197 // probably something else is going on here
4205 for (; i < opcnt && seq_len > 0; i++) {
4206 if (!(ops[i].flags & OPF_TAIL))
4209 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4210 if (ops[j].op != OP_POP || ops[j].operand[0].type != OPT_REG)
4212 if (ops[j].operand[0].reg != seq[seq_p])
4216 found = seq_len = seq_p;
4221 for (i = 0; i < seq_len; i++)
4222 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4224 for (; i < opcnt && seq_len > 0; i++) {
4225 if (!(ops[i].flags & OPF_TAIL))
4228 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4229 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4234 // unlike pushes after sub esp,
4235 // IDA treats pushes like this as part of var area
4236 *fsz += seq_len * 4;
4239 static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4244 for (; i < opcnt; i++)
4245 if (!(ops[i].flags & OPF_DONE))
4248 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4249 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4255 for (; i < opcnt; i++) {
4256 if (i > 0 && g_labels[i] != NULL)
4258 if (ops[i].flags & (OPF_JMP|OPF_TAIL))
4260 if (ops[i].flags & OPF_DONE)
4262 if (ops[i].op == OP_PUSH)
4264 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4265 && ops[i].operand[1].type == OPT_CONST)
4267 g_stack_fsz += opr_const(&ops[i], 1);
4268 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4273 if (ops[i].op == OP_LEA && ops[i].operand[0].reg == xSP
4274 && ops[i].operand[1].type == OPT_REGMEM
4275 && IS_START(ops[i].operand[1].name, "esp-"))
4277 name = ops[i].operand[1].name;
4278 ret = sscanf(name, "esp-%x%n", &j, &len);
4279 ferr_assert(&ops[i], ret == 1 && len == strlen(name));
4281 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4286 if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4287 && ops[i].operand[1].type == OPT_CONST)
4289 for (j = i + 1; j < opcnt; j++)
4290 if (!(ops[j].flags & OPF_DONE))
4292 if (ops[j].op == OP_CALL
4293 && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4295 g_stack_fsz += opr_const(&ops[i], 1);
4296 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4297 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4308 static void scan_prologue_epilogue(int opcnt, int *stack_align)
4310 int ecx_push = 0, esp_sub = 0, pusha = 0;
4311 int sandard_epilogue;
4312 int found, ret, len;
4316 if (g_seh_found == 2) {
4317 eliminate_seh_calls(opcnt);
4321 eliminate_seh(opcnt);
4322 // ida treats seh as part of sf
4323 g_stack_fsz = g_seh_size;
4327 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4328 && ops[1].op == OP_MOV
4329 && IS(opr_name(&ops[1], 0), "ebp")
4330 && IS(opr_name(&ops[1], 1), "esp"))
4333 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4334 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4336 for (i = 2; i < opcnt; i++)
4337 if (!(ops[i].flags & OPF_DONE))
4340 if (ops[i].op == OP_PUSHA) {
4341 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4346 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4347 && ops[i].operand[1].type == OPT_CONST)
4349 l = ops[i].operand[1].val;
4351 if (j == -1 || (l >> j) != -1)
4352 ferr(&ops[i], "unhandled esp align: %x\n", l);
4353 if (stack_align != NULL)
4354 *stack_align = 1 << j;
4355 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4359 i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4363 for (; i < opcnt; i++)
4364 if (ops[i].flags & OPF_TAIL)
4367 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4368 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4374 sandard_epilogue = 0;
4375 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4377 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4378 // the standard epilogue is sometimes even used without a sf
4379 if (ops[j - 1].op == OP_MOV
4380 && IS(opr_name(&ops[j - 1], 0), "esp")
4381 && IS(opr_name(&ops[j - 1], 1), "ebp"))
4382 sandard_epilogue = 1;
4384 else if (ops[j].op == OP_LEAVE)
4386 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4387 sandard_epilogue = 1;
4389 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4390 && ops[i].pp->is_noreturn)
4392 // on noreturn, msvc sometimes cleans stack, sometimes not
4397 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4398 ferr(&ops[j], "'pop ebp' expected\n");
4400 if (g_stack_fsz != 0 || sandard_epilogue) {
4401 if (ops[j].op == OP_LEAVE)
4403 else if (sandard_epilogue) // mov esp, ebp
4405 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4408 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4410 ferr(&ops[j], "esp restore expected\n");
4413 if (ecx_push && j >= 0 && ops[j].op == OP_POP
4414 && IS(opr_name(&ops[j], 0), "ecx"))
4416 ferr(&ops[j], "unexpected ecx pop\n");
4421 if (ops[j].op == OP_POPA)
4422 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4424 ferr(&ops[j], "popa expected\n");
4429 } while (i < opcnt);
4432 ferr(ops, "missing ebp epilogue\n");
4437 check_simple_sequence(opcnt, &push_fsz);
4438 i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4440 if (ecx_push && !esp_sub) {
4441 // could actually be args for a call..
4442 for (; i < opcnt; i++)
4443 if (ops[i].op != OP_PUSH)
4446 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4447 const struct parsed_proto *pp;
4448 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4449 j = pp ? pp->argc_stack : 0;
4450 while (i > 0 && j > 0) {
4452 if (ops[i].op == OP_PUSH) {
4453 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4458 ferr(&ops[i], "unhandled prologue\n");
4462 g_stack_fsz = g_seh_size;
4463 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4464 if (!(ops[i].flags & OPF_RMD))
4474 if (ecx_push || esp_sub)
4479 for (; i < opcnt; i++)
4480 if (ops[i].flags & OPF_TAIL)
4484 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4485 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4490 else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4491 // skip arg updates for arg-reuse tailcall
4492 for (; j >= 0; j--) {
4493 if (ops[j].op != OP_MOV)
4495 if (ops[j].operand[0].type == OPT_REGMEM
4496 && strstr(ops[j].operand[0].name, "arg_") != NULL)
4498 if (ops[j].operand[0].type == OPT_REG)
4499 continue; // assume arg-reg mov
4504 for (; j >= 0; j--) {
4505 if ((ops[j].flags & (OPF_RMD | OPF_DONE | OPF_NOREGS)) !=
4506 (OPF_RMD | OPF_DONE | OPF_NOREGS))
4510 if (ecx_push > 0 && !esp_sub) {
4511 for (l = 0; l < ecx_push && j >= 0; l++) {
4512 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4514 else if (ops[j].op == OP_ADD
4515 && IS(opr_name(&ops[j], 0), "esp")
4516 && ops[j].operand[1].type == OPT_CONST)
4519 l += ops[j].operand[1].val / 4 - 1;
4524 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4527 if (l != ecx_push) {
4528 if (i < opcnt && ops[i].op == OP_CALL
4529 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4531 // noreturn tailcall with no epilogue
4536 ferr(&ops[j], "epilogue scan failed\n");
4543 if (ops[j].op == OP_ADD
4544 && IS(opr_name(&ops[j], 0), "esp")
4545 && ops[j].operand[1].type == OPT_CONST)
4547 if (ops[j].operand[1].val < g_stack_fsz)
4548 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4550 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4551 if (ops[j].operand[1].val == 0)
4552 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4555 else if (ops[j].op == OP_LEA && ops[j].operand[0].reg == xSP
4556 && ops[j].operand[1].type == OPT_REGMEM
4557 && IS_START(ops[j].operand[1].name, "esp+"))
4559 const char *name = ops[j].operand[1].name;
4560 ret = sscanf(name, "esp+%x%n", &l, &len);
4561 ferr_assert(&ops[j], ret == 1 && len == strlen(name));
4562 ferr_assert(&ops[j], l <= g_stack_fsz);
4563 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4566 else if (i < opcnt && ops[i].op == OP_CALL
4567 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4569 // noreturn tailcall with no epilogue
4573 ferr(&ops[j], "'add esp' expected\n");
4577 } while (i < opcnt);
4580 ferr(ops, "missing esp epilogue\n");
4583 if (g_stack_fsz != 0)
4584 // see check_simple_sequence
4585 g_stack_fsz += push_fsz;
4588 // find an instruction that changed opr before i op
4589 // *op_i must be set to -1 by the caller
4590 // *is_caller is set to 1 if one source is determined to be g_func arg
4591 // returns 1 if found, *op_i is then set to origin
4592 // returns -1 if multiple origins are found
4593 static int resolve_origin(int i, const struct parsed_opr *opr,
4594 int magic, int *op_i, int *is_caller)
4596 struct label_ref *lr;
4600 if (g_labels[i] != NULL) {
4601 lr = &g_label_refs[i];
4602 for (; lr != NULL; lr = lr->next) {
4603 check_i(&ops[i], lr->i);
4604 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4606 if (i > 0 && LAST_OP(i - 1))
4612 if (is_caller != NULL)
4617 if (ops[i].cc_scratch == magic)
4619 ops[i].cc_scratch = magic;
4621 if (!(ops[i].flags & OPF_DATA))
4623 if (!is_opr_modified(opr, &ops[i]))
4627 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4638 // find an instruction that previously referenced opr
4639 // if multiple results are found - fail
4640 // *op_i must be set to -1 by the caller
4641 // returns 1 if found, *op_i is then set to referencer insn
4642 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4643 int magic, int *op_i)
4645 struct label_ref *lr;
4649 if (g_labels[i] != NULL) {
4650 lr = &g_label_refs[i];
4651 for (; lr != NULL; lr = lr->next) {
4652 check_i(&ops[i], lr->i);
4653 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4655 if (i > 0 && LAST_OP(i - 1))
4663 if (ops[i].cc_scratch == magic)
4665 ops[i].cc_scratch = magic;
4667 if (!is_opr_referenced(opr, &ops[i]))
4678 // adjust datap of all reachable 'op' insns when moving back
4679 // returns 1 if at least 1 op was found
4680 // returns -1 if path without an op was found
4681 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4683 struct label_ref *lr;
4686 if (ops[i].cc_scratch == magic)
4688 ops[i].cc_scratch = magic;
4691 if (g_labels[i] != NULL) {
4692 lr = &g_label_refs[i];
4693 for (; lr != NULL; lr = lr->next) {
4694 check_i(&ops[i], lr->i);
4695 ret |= adjust_prev_op(lr->i, op, magic, datap);
4697 if (i > 0 && LAST_OP(i - 1))
4705 if (ops[i].cc_scratch == magic)
4707 ops[i].cc_scratch = magic;
4709 if (ops[i].op != op)
4712 ops[i].datap = datap;
4717 // find next instruction that reads opr
4718 // *op_i must be set to -1 by the caller
4719 // on return, *op_i is set to first referencer insn
4720 // returns 1 if exactly 1 referencer is found
4721 static int find_next_read(int i, int opcnt,
4722 const struct parsed_opr *opr, int magic, int *op_i)
4724 struct parsed_op *po;
4727 for (; i < opcnt; i++)
4729 if (ops[i].cc_scratch == magic)
4731 ops[i].cc_scratch = magic;
4734 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4735 if (po->btj != NULL) {
4737 for (j = 0; j < po->btj->count; j++) {
4738 check_i(po, po->btj->d[j].bt_i);
4739 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4745 if (po->flags & OPF_RMD)
4747 check_i(po, po->bt_i);
4748 if (po->flags & OPF_CJMP) {
4749 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4758 if (!is_opr_read(opr, po)) {
4760 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4761 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4763 full_opr = po->operand[0].lmod >= opr->lmod;
4765 if (is_opr_modified(opr, po) && full_opr) {
4769 if (po->flags & OPF_TAIL)
4784 static int find_next_read_reg(int i, int opcnt, int reg,
4785 enum opr_lenmod lmod, int magic, int *op_i)
4787 struct parsed_opr opr = OPR_INIT(OPT_REG, lmod, reg);
4790 return find_next_read(i, opcnt, &opr, magic, op_i);
4793 // find next instruction that reads opr
4794 // *op_i must be set to -1 by the caller
4795 // on return, *op_i is set to first flag user insn
4796 // returns 1 if exactly 1 flag user is found
4797 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4799 struct parsed_op *po;
4802 for (; i < opcnt; i++)
4804 if (ops[i].cc_scratch == magic)
4806 ops[i].cc_scratch = magic;
4809 if (po->op == OP_CALL)
4811 if (po->flags & OPF_JMP) {
4812 if (po->btj != NULL) {
4814 for (j = 0; j < po->btj->count; j++) {
4815 check_i(po, po->btj->d[j].bt_i);
4816 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4822 if (po->flags & OPF_RMD)
4824 check_i(po, po->bt_i);
4825 if (po->flags & OPF_CJMP)
4832 if (!(po->flags & OPF_CC)) {
4833 if (po->flags & OPF_FLAGS)
4836 if (po->flags & OPF_TAIL)
4852 static int try_resolve_const(int i, const struct parsed_opr *opr,
4853 int magic, unsigned int *val)
4858 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4861 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4864 *val = ops[i].operand[1].val;
4871 static int resolve_used_bits(int i, int opcnt, int reg,
4872 int *mask, int *is_z_check)
4874 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4878 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4882 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4884 fnote(&ops[j], "(first read)\n");
4885 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4888 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4889 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4891 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4892 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4894 *mask = ops[j].operand[1].val;
4895 if (ops[j].operand[0].lmod == OPLM_BYTE
4896 && ops[j].operand[0].name[1] == 'h')
4900 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4903 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4905 *is_z_check = ops[k].pfo == PFO_Z;
4910 static const struct parsed_proto *resolve_deref(int i, int magic,
4911 struct parsed_opr *opr, int level)
4913 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4914 const struct parsed_proto *pp = NULL;
4915 int from_caller = 0;
4924 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4925 if (ret != 2 || len != strlen(opr->name)) {
4926 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4927 if (ret != 1 || len != strlen(opr->name))
4931 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4936 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4940 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4941 && strlen(ops[j].operand[1].name) == 3
4942 && ops[j].operand[0].lmod == OPLM_DWORD
4943 && ops[j].pp == NULL // no hint
4946 // allow one simple dereference (com/directx)
4947 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4948 ops[j].operand[1].name);
4952 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4957 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4960 if (ops[j].pp != NULL) {
4964 else if (ops[j].operand[1].type == OPT_REGMEM) {
4965 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4967 // maybe structure ptr in structure
4968 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4971 else if (ops[j].operand[1].type == OPT_LABEL)
4972 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4973 else if (ops[j].operand[1].type == OPT_REG) {
4976 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4978 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4979 for (k = 0; k < g_func_pp->argc; k++) {
4980 if (g_func_pp->arg[k].reg == NULL)
4982 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
4983 pp = g_func_pp->arg[k].pp;
4992 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
4994 ferr(&ops[j], "expected struct, got '%s %s'\n",
4995 pp->type.name, pp->name);
4999 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
5002 static const struct parsed_proto *resolve_icall(int i, int opcnt,
5003 int *pp_i, int *multi_src)
5005 const struct parsed_proto *pp = NULL;
5006 int search_advice = 0;
5011 switch (ops[i].operand[0].type) {
5013 // try to resolve struct member calls
5014 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
5020 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
5026 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
5034 static struct parsed_proto *process_call_early(int i, int opcnt,
5037 struct parsed_op *po = &ops[i];
5038 struct parsed_proto *pp;
5044 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
5048 // look for and make use of esp adjust
5050 if (!pp->is_stdcall && pp->argc_stack > 0)
5051 ret = scan_for_esp_adjust(i + 1, opcnt,
5052 pp->argc_stack * 4, &adj, &multipath, 0);
5054 if (pp->argc_stack > adj / 4)
5058 if (ops[ret].op == OP_POP) {
5059 for (j = 1; j < adj / 4; j++) {
5060 if (ops[ret + j].op != OP_POP
5061 || ops[ret + j].operand[0].reg != xCX)
5073 static struct parsed_proto *process_call(int i, int opcnt)
5075 struct parsed_op *po = &ops[i];
5076 const struct parsed_proto *pp_c;
5077 struct parsed_proto *pp;
5078 const char *tmpname;
5079 int call_i = -1, ref_i = -1;
5080 int adj = 0, multipath = 0;
5083 tmpname = opr_name(po, 0);
5088 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
5090 if (!pp_c->is_func && !pp_c->is_fptr)
5091 ferr(po, "call to non-func: %s\n", pp_c->name);
5092 pp = proto_clone(pp_c);
5093 my_assert_not(pp, NULL);
5095 // not resolved just to single func
5098 switch (po->operand[0].type) {
5100 // we resolved this call and no longer need the register
5101 po->regmask_src &= ~(1 << po->operand[0].reg);
5103 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
5104 && ops[call_i].operand[1].type == OPT_LABEL)
5106 // no other source users?
5107 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
5109 if (ret == 1 && call_i == ref_i) {
5110 // and nothing uses it after us?
5112 find_next_read(i + 1, opcnt, &po->operand[0],
5113 i + opcnt * 11, &ref_i);
5115 // then also don't need the source mov
5116 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
5128 pp = calloc(1, sizeof(*pp));
5129 my_assert_not(pp, NULL);
5132 ret = scan_for_esp_adjust(i + 1, opcnt,
5133 -1, &adj, &multipath, 0);
5134 if (ret < 0 || adj < 0) {
5135 if (!g_allow_regfunc)
5136 ferr(po, "non-__cdecl indirect call unhandled yet\n");
5137 pp->is_unresolved = 1;
5141 if (adj > ARRAY_SIZE(pp->arg))
5142 ferr(po, "esp adjust too large: %d\n", adj);
5143 pp->ret_type.name = strdup("int");
5144 pp->argc = pp->argc_stack = adj;
5145 for (arg = 0; arg < pp->argc; arg++)
5146 pp->arg[arg].type.name = strdup("int");
5151 // look for and make use of esp adjust
5154 if (!pp->is_stdcall && pp->argc_stack > 0) {
5155 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
5156 ret = scan_for_esp_adjust(i + 1, opcnt,
5157 adj_expect, &adj, &multipath, 0);
5160 if (pp->is_vararg) {
5161 if (adj / 4 < pp->argc_stack) {
5162 fnote(po, "(this call)\n");
5163 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
5164 adj, pp->argc_stack * 4);
5166 // modify pp to make it have varargs as normal args
5168 pp->argc += adj / 4 - pp->argc_stack;
5169 for (; arg < pp->argc; arg++) {
5170 pp->arg[arg].type.name = strdup("int");
5173 if (pp->argc > ARRAY_SIZE(pp->arg))
5174 ferr(po, "too many args for '%s'\n", tmpname);
5176 if (pp->argc_stack > adj / 4) {
5177 if (pp->is_noreturn)
5178 // assume no stack adjust was emited
5180 fnote(po, "(this call)\n");
5181 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
5182 tmpname, pp->argc_stack * 4, adj);
5185 scan_for_esp_adjust(i + 1, opcnt,
5186 pp->argc_stack * 4, &adj, &multipath, 1);
5188 else if (pp->is_vararg)
5189 ferr(po, "missing esp_adjust for vararg func '%s'\n",
5196 static void mark_float_arg(struct parsed_op *po,
5197 struct parsed_proto *pp, int arg, int *regmask_ffca)
5200 po->p_argnum = arg + 1;
5201 ferr_assert(po, pp->arg[arg].datap == NULL);
5202 pp->arg[arg].datap = po;
5203 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
5204 if (regmask_ffca != NULL)
5205 *regmask_ffca |= 1 << arg;
5208 static int check_for_stp(int i, int i_to)
5210 struct parsed_op *po;
5212 for (; i < i_to; i++) {
5214 if (po->op == OP_FST)
5216 if (g_labels[i] != NULL || (po->flags & OPF_JMP))
5218 if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
5220 if (po->op == OP_ADD && po->operand[0].reg == xSP)
5227 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
5230 struct parsed_op *po;
5236 for (base_arg = 0; base_arg < pp->argc; base_arg++)
5237 if (pp->arg[base_arg].reg == NULL)
5240 for (j = i; j > 0; )
5242 ferr_assert(&ops[j], g_labels[j] == NULL);
5246 ferr_assert(po, po->op != OP_PUSH);
5247 if (po->op == OP_FST)
5249 if (po->operand[0].type != OPT_REGMEM)
5251 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
5254 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
5255 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
5259 arg = base_arg + offset / 4;
5260 mark_float_arg(po, pp, arg, regmask_ffca);
5262 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5263 && po->operand[1].type == OPT_CONST)
5265 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5270 for (arg = base_arg; arg < pp->argc; arg++) {
5271 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
5272 po = pp->arg[arg].datap;
5274 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
5275 if (po->operand[0].lmod == OPLM_QWORD)
5282 static int collect_call_args_early(int i, struct parsed_proto *pp,
5283 int *regmask, int *regmask_ffca)
5285 struct parsed_op *po;
5290 for (arg = 0; arg < pp->argc; arg++)
5291 if (pp->arg[arg].reg == NULL)
5294 // first see if it can be easily done
5295 for (j = i; j > 0 && arg < pp->argc; )
5297 if (g_labels[j] != NULL)
5302 if (po->op == OP_CALL)
5304 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
5306 else if (po->op == OP_POP)
5308 else if (po->flags & OPF_CJMP)
5310 else if (po->op == OP_PUSH) {
5311 if (po->flags & (OPF_FARG|OPF_FARGNR))
5313 if (!g_header_mode) {
5314 ret = scan_for_mod(po, j + 1, i, 1);
5319 if (pp->arg[arg].type.is_va_list)
5323 for (arg++; arg < pp->argc; arg++)
5324 if (pp->arg[arg].reg == NULL)
5327 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5328 && po->operand[1].type == OPT_CONST)
5330 if (po->flags & (OPF_RMD|OPF_DONE))
5332 if (po->operand[1].val != pp->argc_stack * 4)
5333 ferr(po, "unexpected esp adjust: %d\n",
5334 po->operand[1].val * 4);
5335 ferr_assert(po, pp->argc - arg == pp->argc_stack);
5336 return collect_call_args_no_push(i, pp, regmask_ffca);
5344 for (arg = 0; arg < pp->argc; arg++)
5345 if (pp->arg[arg].reg == NULL)
5348 for (j = i; j > 0 && arg < pp->argc; )
5352 if (ops[j].op == OP_PUSH)
5354 ops[j].p_argnext = -1;
5355 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
5357 k = check_for_stp(j + 1, i);
5359 // push ecx; fstp dword ptr [esp]
5360 ret = parse_stack_esp_offset(&ops[k],
5361 ops[k].operand[0].name, &offset);
5362 if (ret == 0 && offset == 0) {
5363 if (!pp->arg[arg].type.is_float)
5364 ferr(&ops[i], "arg %d should be float\n", arg + 1);
5365 mark_float_arg(&ops[k], pp, arg, regmask_ffca);
5369 if (pp->arg[arg].datap == NULL) {
5370 pp->arg[arg].datap = &ops[j];
5371 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5372 *regmask |= 1 << ops[j].operand[0].reg;
5375 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5376 ops[j].flags &= ~OPF_RSAVE;
5379 for (arg++; arg < pp->argc; arg++)
5380 if (pp->arg[arg].reg == NULL)
5388 static int sync_argnum(struct parsed_op *po, int argnum)
5390 struct parsed_op *po_tmp;
5392 // see if other branches don't have higher argnum
5393 for (po_tmp = po; po_tmp != NULL; ) {
5394 if (argnum < po_tmp->p_argnum)
5395 argnum = po_tmp->p_argnum;
5396 // note: p_argnext is active on current collect_call_args only
5397 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5400 // make all argnums consistent
5401 for (po_tmp = po; po_tmp != NULL; ) {
5402 if (po_tmp->p_argnum != 0)
5403 po_tmp->p_argnum = argnum;
5404 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5410 static int collect_call_args_r(struct parsed_op *po, int i,
5411 struct parsed_proto *pp, int *regmask, int *arg_grp,
5412 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
5414 struct parsed_proto *pp_tmp;
5415 struct parsed_op *po_tmp;
5416 struct label_ref *lr;
5417 int need_to_save_current;
5418 int arg_grp_current = 0;
5419 int save_args_seen = 0;
5426 ferr(po, "dead label encountered\n");
5430 for (; arg < pp->argc; arg++, argnum++)
5431 if (pp->arg[arg].reg == NULL)
5433 magic = (magic & 0xffffff) | (arg << 24);
5435 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5437 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5438 if (ops[j].cc_scratch != magic) {
5439 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5443 // ok: have already been here
5446 ops[j].cc_scratch = magic;
5448 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5449 lr = &g_label_refs[j];
5450 if (lr->next != NULL)
5452 for (; lr->next; lr = lr->next) {
5453 check_i(&ops[j], lr->i);
5454 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5456 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5457 arg, argnum, magic, need_op_saving, may_reuse);
5462 check_i(&ops[j], lr->i);
5463 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5465 if (j > 0 && LAST_OP(j - 1)) {
5466 // follow last branch in reverse
5471 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5472 arg, argnum, magic, need_op_saving, may_reuse);
5478 if (ops[j].op == OP_CALL)
5480 if (pp->is_unresolved)
5485 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5486 arg, pp->argc, ops[j].operand[0].name);
5487 if (may_reuse && pp_tmp->argc_stack > 0)
5488 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5489 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5491 // esp adjust of 0 means we collected it before
5492 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5493 && (ops[j].operand[1].type != OPT_CONST
5494 || ops[j].operand[1].val != 0))
5496 if (pp->is_unresolved)
5499 fnote(po, "(this call)\n");
5500 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5501 arg, pp->argc, ops[j].operand[1].val);
5503 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5505 if (pp->is_unresolved)
5508 fnote(po, "(this call)\n");
5509 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5511 else if (ops[j].flags & OPF_CJMP)
5513 if (pp->is_unresolved)
5518 else if (ops[j].op == OP_PUSH
5519 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5521 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5524 ops[j].p_argnext = -1;
5525 po_tmp = pp->arg[arg].datap;
5527 ops[j].p_argnext = po_tmp - ops;
5528 pp->arg[arg].datap = &ops[j];
5530 argnum = sync_argnum(&ops[j], argnum);
5532 need_to_save_current = 0;
5534 if (ops[j].operand[0].type == OPT_REG)
5535 reg = ops[j].operand[0].reg;
5537 if (!need_op_saving) {
5538 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5539 need_to_save_current = (ret >= 0);
5541 if (need_op_saving || need_to_save_current) {
5542 // mark this arg as one that needs operand saving
5543 pp->arg[arg].is_saved = 1;
5545 if (save_args_seen & (1 << (argnum - 1))) {
5548 if (arg_grp_current >= MAX_ARG_GRP)
5549 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5553 else if (ops[j].p_argnum == 0)
5554 ops[j].flags |= OPF_RMD;
5556 // some PUSHes are reused by different calls on other branches,
5557 // but that can't happen if we didn't branch, so they
5558 // can be removed from future searches (handles nested calls)
5560 ops[j].flags |= OPF_FARGNR;
5562 ops[j].flags |= OPF_FARG;
5563 ops[j].flags &= ~OPF_RSAVE;
5565 // check for __VALIST
5566 if (!pp->is_unresolved && g_func_pp != NULL
5567 && pp->arg[arg].type.is_va_list)
5570 ret = resolve_origin(j, &ops[j].operand[0],
5571 magic + 1, &k, NULL);
5572 if (ret == 1 && k >= 0)
5574 if (ops[k].op == OP_LEA) {
5575 if (!g_func_pp->is_vararg)
5576 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5579 snprintf(buf, sizeof(buf), "arg_%X",
5580 g_func_pp->argc_stack * 4);
5581 if (strstr(ops[k].operand[1].name, buf)
5582 || strstr(ops[k].operand[1].name, "arglist"))
5584 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5585 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5586 pp->arg[arg].is_saved = 0;
5590 ferr(&ops[k], "va_list arg detection failed\n");
5592 // check for va_list from g_func_pp arg too
5593 else if (ops[k].op == OP_MOV
5594 && is_stack_access(&ops[k], &ops[k].operand[1]))
5596 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5597 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5599 ops[k].flags |= OPF_RMD | OPF_DONE;
5600 ops[j].flags |= OPF_RMD;
5601 ops[j].p_argpass = ret + 1;
5602 pp->arg[arg].is_saved = 0;
5609 if (pp->arg[arg].is_saved) {
5610 ops[j].flags &= ~OPF_RMD;
5611 ops[j].p_argnum = argnum;
5614 // tracking reg usage
5616 *regmask |= 1 << reg;
5620 if (!pp->is_unresolved) {
5622 for (; arg < pp->argc; arg++, argnum++)
5623 if (pp->arg[arg].reg == NULL)
5626 magic = (magic & 0xffffff) | (arg << 24);
5629 if (ops[j].p_arggrp > arg_grp_current) {
5631 arg_grp_current = ops[j].p_arggrp;
5633 if (ops[j].p_argnum > 0)
5634 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5637 if (arg < pp->argc) {
5638 ferr(po, "arg collect failed for '%s': %d/%d\n",
5639 pp->name, arg, pp->argc);
5643 if (arg_grp_current > *arg_grp)
5644 *arg_grp = arg_grp_current;
5649 static int collect_call_args(struct parsed_op *po, int i,
5650 struct parsed_proto *pp, int *regmask, int magic)
5652 // arg group is for cases when pushes for
5653 // multiple funcs are going on
5654 struct parsed_op *po_tmp;
5659 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5664 if (pp->is_unresolved) {
5666 pp->argc_stack += ret;
5667 for (a = 0; a < pp->argc; a++)
5668 if (pp->arg[a].type.name == NULL)
5669 pp->arg[a].type.name = strdup("int");
5673 // propagate arg_grp
5674 for (a = 0; a < pp->argc; a++) {
5675 if (pp->arg[a].reg != NULL)
5678 po_tmp = pp->arg[a].datap;
5679 while (po_tmp != NULL) {
5680 po_tmp->p_arggrp = arg_grp;
5681 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5689 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5690 int regmask_now, int *regmask,
5691 int regmask_save_now, int *regmask_save,
5692 int *regmask_init, int regmask_arg)
5694 struct parsed_op *po;
5702 for (; i < opcnt; i++)
5705 if (cbits[i >> 3] & (1 << (i & 7)))
5707 cbits[i >> 3] |= (1 << (i & 7));
5709 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5710 if (po->flags & (OPF_RMD|OPF_DONE))
5712 if (po->btj != NULL) {
5713 for (j = 0; j < po->btj->count; j++) {
5714 check_i(po, po->btj->d[j].bt_i);
5715 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5716 regmask_now, regmask, regmask_save_now, regmask_save,
5717 regmask_init, regmask_arg);
5722 check_i(po, po->bt_i);
5723 if (po->flags & OPF_CJMP)
5724 reg_use_pass(po->bt_i, opcnt, cbits,
5725 regmask_now, regmask, regmask_save_now, regmask_save,
5726 regmask_init, regmask_arg);
5732 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5733 && !g_func_pp->is_userstack
5734 && po->operand[0].type == OPT_REG)
5736 reg = po->operand[0].reg;
5737 ferr_assert(po, reg >= 0);
5740 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5741 if (regmask_now & (1 << reg)) {
5742 already_saved = regmask_save_now & (1 << reg);
5743 flags_set = OPF_RSAVE | OPF_DONE;
5746 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, 0);
5748 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5749 reg, 0, 0, flags_set);
5752 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5754 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5759 ferr_assert(po, !already_saved);
5760 po->flags |= flags_set;
5762 if (regmask_now & (1 << reg)) {
5763 regmask_save_now |= (1 << reg);
5764 *regmask_save |= regmask_save_now;
5769 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5770 reg = po->operand[0].reg;
5771 ferr_assert(po, reg >= 0);
5773 if (regmask_save_now & (1 << reg))
5774 regmask_save_now &= ~(1 << reg);
5776 regmask_now &= ~(1 << reg);
5779 else if (po->op == OP_CALL) {
5780 if ((po->regmask_dst & (1 << xAX))
5781 && !(po->regmask_dst & (1 << xDX)))
5783 if (po->flags & OPF_TAIL)
5784 // don't need eax, will do "return f();" or "f(); return;"
5785 po->regmask_dst &= ~(1 << xAX);
5787 find_next_read_reg(i + 1, opcnt, xAX, OPLM_DWORD,
5788 i + opcnt * 17, &j);
5791 po->regmask_dst &= ~(1 << xAX);
5795 // not "full stack" mode and have something in stack
5796 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5797 ferr(po, "float stack is not empty on func call\n");
5800 if (po->flags & OPF_NOREGS)
5803 // if incomplete register is used, clear it on init to avoid
5804 // later use of uninitialized upper part in some situations
5805 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5806 && po->operand[0].lmod != OPLM_DWORD)
5808 reg = po->operand[0].reg;
5809 ferr_assert(po, reg >= 0);
5811 if (!(regmask_now & (1 << reg)))
5812 *regmask_init |= 1 << reg;
5815 regmask_op = po->regmask_src | po->regmask_dst;
5817 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5818 regmask_new &= ~(1 << xSP);
5819 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5820 regmask_new &= ~(1 << xBP);
5822 if (regmask_new != 0)
5823 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5825 if (regmask_op & (1 << xBP)) {
5826 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5827 if (po->regmask_dst & (1 << xBP))
5828 // compiler decided to drop bp frame and use ebp as scratch
5829 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5831 regmask_op &= ~(1 << xBP);
5835 if (po->flags & OPF_FPUSH) {
5836 if (regmask_now & mxST1)
5837 regmask_now |= mxSTa; // switch to "full stack" mode
5838 if (regmask_now & mxSTa)
5839 po->flags |= OPF_FSHIFT;
5840 if (!(regmask_now & mxST7_2)) {
5842 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5846 regmask_now |= regmask_op;
5847 *regmask |= regmask_now;
5850 if (po->flags & OPF_FPOPP) {
5851 if ((regmask_now & mxSTa) == 0)
5852 ferr(po, "float pop on empty stack?\n");
5853 if (regmask_now & mxST7_2)
5854 po->flags |= OPF_FSHIFT;
5855 if (!(regmask_now & mxST7_2))
5856 regmask_now &= ~mxST1_0;
5858 else if (po->flags & OPF_FPOP) {
5859 if ((regmask_now & mxSTa) == 0)
5860 ferr(po, "float pop on empty stack?\n");
5861 if (regmask_now & (mxST7_2 | mxST1))
5862 po->flags |= OPF_FSHIFT;
5863 if (!(regmask_now & mxST7_2)) {
5865 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5869 if (po->flags & OPF_TAIL) {
5870 if (!(regmask_now & mxST7_2)) {
5871 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5872 if (!(regmask_now & mxST0))
5873 ferr(po, "no st0 on float return, mask: %x\n",
5876 else if (regmask_now & mxST1_0)
5877 ferr(po, "float regs on tail: %x\n", regmask_now);
5880 // there is support for "conditional tailcall", sort of
5881 if (!(po->flags & OPF_CC))
5887 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5891 for (i = 0; i < pp->argc; i++)
5892 if (pp->arg[i].reg == NULL)
5896 memmove(&pp->arg[i + 1], &pp->arg[i],
5897 sizeof(pp->arg[0]) * pp->argc_stack);
5898 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5899 pp->arg[i].reg = strdup(reg);
5900 pp->arg[i].type.name = strdup("int");
5905 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5906 int *pfomask, const char *dst_opr_text)
5908 if (*pfomask & (1 << PFO_Z)) {
5909 fprintf(fout, "\n cond_z = (%s%s == 0);",
5910 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5911 *pfomask &= ~(1 << PFO_Z);
5915 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5916 int *pfomask, const char *dst_opr_text)
5918 if (*pfomask & (1 << PFO_S)) {
5919 fprintf(fout, "\n cond_s = (%s%s < 0);",
5920 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5921 *pfomask &= ~(1 << PFO_S);
5925 static void output_std_flags(FILE *fout, struct parsed_op *po,
5926 int *pfomask, const char *dst_opr_text)
5928 output_std_flag_z(fout, po, pfomask, dst_opr_text);
5929 output_std_flag_s(fout, po, pfomask, dst_opr_text);
5933 OPP_FORCE_NORETURN = (1 << 0),
5934 OPP_SIMPLE_ARGS = (1 << 1),
5935 OPP_ALIGN = (1 << 2),
5938 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5941 const char *cconv = "";
5943 if (pp->is_fastcall)
5944 cconv = "__fastcall ";
5945 else if (pp->is_stdcall && pp->argc_reg == 0)
5946 cconv = "__stdcall ";
5948 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5950 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5951 fprintf(fout, "noreturn ");
5954 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5959 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5963 output_pp_attrs(fout, pp, flags);
5966 fprintf(fout, "%s", pp->name);
5971 for (i = 0; i < pp->argc; i++) {
5973 fprintf(fout, ", ");
5974 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5975 && !(flags & OPP_SIMPLE_ARGS))
5978 output_pp(fout, pp->arg[i].pp, 0);
5980 else if (pp->arg[i].type.is_retreg) {
5981 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
5984 fprintf(fout, "%s", pp->arg[i].type.name);
5986 fprintf(fout, " a%d", i + 1);
5989 if (pp->arg[i].type.is_64bit)
5992 if (pp->is_vararg) {
5994 fprintf(fout, ", ");
5995 fprintf(fout, "...");
6000 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
6006 snprintf(buf1, sizeof(buf1), "%d", grp);
6007 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
6012 static void gen_x_cleanup(int opcnt);
6014 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
6016 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
6017 struct parsed_opr *last_arith_dst = NULL;
6018 char buf1[256], buf2[256], buf3[256], cast[64];
6019 struct parsed_proto *pp, *pp_tmp;
6020 struct parsed_data *pd;
6021 int save_arg_vars[MAX_ARG_GRP] = { 0, };
6022 unsigned char cbits[MAX_OPS / 8];
6023 const char *float_type;
6024 const char *float_st0;
6025 const char *float_st1;
6026 int need_float_stack = 0;
6027 int need_float_sw = 0; // status word
6028 int need_tmp_var = 0;
6032 int label_pending = 0;
6033 int need_double = 0;
6034 int stack_align = 0;
6035 int stack_fsz_adj = 0;
6036 int lock_handled = 0;
6037 int regmask_save = 0; // used regs saved/restored in this func
6038 int regmask_arg; // regs from this function args (fastcall, etc)
6039 int regmask_ret; // regs needed on ret
6040 int regmask_now; // temp
6041 int regmask_init = 0; // regs that need zero initialization
6042 int regmask_pp = 0; // regs used in complex push-pop graph
6043 int regmask_ffca = 0; // float function call args
6044 int regmask = 0; // used regs
6054 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
6055 g_stack_frame_used = 0;
6057 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
6058 regmask_init = g_regmask_init;
6060 g_func_pp = proto_parse(fhdr, funcn, 0);
6061 if (g_func_pp == NULL)
6062 ferr(ops, "proto_parse failed for '%s'\n", funcn);
6064 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
6065 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
6068 // - resolve all branches
6069 // - parse calls with labels
6070 resolve_branches_parse_calls(opcnt);
6073 // - handle ebp/esp frame, remove ops related to it
6074 scan_prologue_epilogue(opcnt, &stack_align);
6076 // handle a case where sf size is unalignment, but is
6077 // placed in a way that elements are still aligned
6078 if (g_stack_fsz & 4) {
6079 for (i = 0; i < g_eqcnt; i++) {
6080 if (g_eqs[i].lmod != OPLM_QWORD)
6082 if (!(g_eqs[i].offset & 4)) {
6091 // - remove dead labels
6092 // - set regs needed at ret
6093 for (i = 0; i < opcnt; i++)
6095 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
6100 if (ops[i].op == OP_RET)
6101 ops[i].regmask_src |= regmask_ret;
6105 // - process trivial calls
6106 for (i = 0; i < opcnt; i++)
6109 if (po->flags & (OPF_RMD|OPF_DONE))
6112 if (po->op == OP_CALL)
6114 pp = process_call_early(i, opcnt, &j);
6116 if (!(po->flags & OPF_ATAIL)) {
6117 // since we know the args, try to collect them
6118 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
6126 // commit esp adjust
6127 if (ops[j].op != OP_POP)
6128 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
6130 for (l = 0; l < pp->argc_stack; l++)
6131 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
6135 if (strstr(pp->ret_type.name, "int64"))
6138 po->flags |= OPF_DONE;
6144 // - process calls, stage 2
6145 // - handle some push/pop pairs
6146 // - scan for STD/CLD, propagate DF
6147 // - try to resolve needed x87 status word bits
6148 for (i = 0; i < opcnt; i++)
6153 if (po->flags & OPF_RMD)
6156 if (po->op == OP_CALL)
6158 if (!(po->flags & OPF_DONE)) {
6159 pp = process_call(i, opcnt);
6161 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
6162 // since we know the args, collect them
6163 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6165 // for unresolved, collect after other passes
6169 ferr_assert(po, pp != NULL);
6171 po->regmask_src |= get_pp_arg_regmask_src(pp);
6172 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
6174 if (po->regmask_dst & mxST0)
6175 po->flags |= OPF_FPUSH;
6177 if (strstr(pp->ret_type.name, "int64"))
6183 if (po->flags & OPF_DONE)
6188 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
6189 && po->operand[0].type == OPT_CONST)
6191 scan_for_pop_const(i, opcnt, i + opcnt * 12);
6196 scan_pushes_for_pop(i, opcnt, ®mask_pp);
6200 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
6201 scan_propagate_df(i + 1, opcnt);
6206 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
6207 ferr(po, "TODO: fnstsw to mem\n");
6208 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
6210 ferr(po, "fnstsw resolve failed\n");
6211 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
6212 (void *)(long)(mask | (z_check << 16)));
6214 ferr(po, "failed to find fcom: %d\n", ret);
6223 // - find POPs for PUSHes, rm both
6224 // - scan for all used registers
6225 memset(cbits, 0, sizeof(cbits));
6226 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
6227 0, ®mask_save, ®mask_init, regmask_arg);
6229 need_float_stack = !!(regmask & mxST7_2);
6232 // - find flag set ops for their users
6233 // - do unresolved calls
6234 // - declare indirect functions
6235 // - other op specific processing
6236 for (i = 0; i < opcnt; i++)
6239 if (po->flags & (OPF_RMD|OPF_DONE))
6242 if (po->flags & OPF_CC)
6244 int setters[16], cnt = 0, branched = 0;
6246 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
6247 &branched, setters, &cnt);
6248 if (ret < 0 || cnt <= 0)
6249 ferr(po, "unable to trace flag setter(s)\n");
6250 if (cnt > ARRAY_SIZE(setters))
6251 ferr(po, "too many flag setters\n");
6253 for (j = 0; j < cnt; j++)
6255 tmp_op = &ops[setters[j]]; // flag setter
6258 // to get nicer code, we try to delay test and cmp;
6259 // if we can't because of operand modification, or if we
6260 // have arith op, or branch, make it calculate flags explicitly
6261 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
6263 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
6264 pfomask = 1 << po->pfo;
6266 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
6267 pfomask = 1 << po->pfo;
6270 // see if we'll be able to handle based on op result
6271 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
6272 && po->pfo != PFO_Z && po->pfo != PFO_S
6273 && po->pfo != PFO_P)
6275 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
6277 pfomask = 1 << po->pfo;
6280 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
6281 propagate_lmod(tmp_op, &tmp_op->operand[0],
6282 &tmp_op->operand[1]);
6283 if (tmp_op->operand[0].lmod == OPLM_DWORD)
6288 tmp_op->pfomask |= pfomask;
6289 cond_vars |= pfomask;
6291 // note: may overwrite, currently not a problem
6295 if (po->op == OP_RCL || po->op == OP_RCR
6296 || po->op == OP_ADC || po->op == OP_SBB)
6297 cond_vars |= 1 << PFO_C;
6303 cond_vars |= 1 << PFO_Z;
6307 if (po->operand[0].lmod == OPLM_DWORD)
6312 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
6317 // note: resolved non-reg calls are OPF_DONE already
6319 ferr_assert(po, pp != NULL);
6321 if (pp->is_unresolved) {
6322 int regmask_stack = 0;
6323 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6325 // this is pretty rough guess:
6326 // see ecx and edx were pushed (and not their saved versions)
6327 for (arg = 0; arg < pp->argc; arg++) {
6328 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
6331 tmp_op = pp->arg[arg].datap;
6333 ferr(po, "parsed_op missing for arg%d\n", arg);
6334 if (tmp_op->operand[0].type == OPT_REG)
6335 regmask_stack |= 1 << tmp_op->operand[0].reg;
6338 // quick dumb check for potential reg-args
6339 for (j = i - 1; j >= 0 && ops[j].op == OP_MOV; j--)
6340 if (ops[j].operand[0].type == OPT_REG)
6341 regmask_stack &= ~(1 << ops[j].operand[0].reg);
6343 if ((regmask_stack & (mxCX|mxDX)) != (mxCX|mxDX)
6344 && ((regmask | regmask_arg) & (mxCX|mxDX)))
6346 if (pp->argc_stack != 0
6347 || ((regmask | regmask_arg) & (mxCX|mxDX)))
6349 pp_insert_reg_arg(pp, "ecx");
6350 pp->is_fastcall = 1;
6351 regmask_init |= 1 << xCX;
6352 regmask |= 1 << xCX;
6354 if (pp->argc_stack != 0
6355 || ((regmask | regmask_arg) & mxDX))
6357 pp_insert_reg_arg(pp, "edx");
6358 regmask_init |= 1 << xDX;
6359 regmask |= 1 << xDX;
6363 // note: __cdecl doesn't fall into is_unresolved category
6364 if (pp->argc_stack > 0)
6367 if (!(po->flags & OPF_TAIL)
6368 && !(g_sct_func_attr & SCTFA_NOWARN) && !g_nowarn_reguse)
6370 // treat al write as overwrite to avoid many false positives
6371 if (IS(pp->ret_type.name, "void") || pp->ret_type.is_float) {
6372 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
6373 i + opcnt * 25, &j);
6375 fnote(po, "eax used after void/float ret call\n");
6376 fnote(&ops[j], "(used here)\n");
6379 if (!strstr(pp->ret_type.name, "int64")) {
6380 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
6381 i + opcnt * 26, &j);
6382 // indirect calls are often guessed, don't warn
6383 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6384 fnote(po, "edx used after 32bit ret call\n");
6385 fnote(&ops[j], "(used here)\n");
6389 // msvc often relies on callee not modifying 'this'
6390 for (arg = 0; arg < pp->argc; arg++) {
6391 if (pp->arg[arg].reg && IS(pp->arg[arg].reg, "ecx")) {
6397 find_next_read_reg(i + 1, opcnt, xCX, OPLM_BYTE,
6398 i + opcnt * 27, &j);
6399 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6400 fnote(po, "ecx used after call\n");
6401 fnote(&ops[j], "(used here)\n");
6408 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6410 // <var> = offset <something>
6411 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6412 && !IS_START(po->operand[1].name, "off_"))
6414 if (!po->operand[0].pp->is_fptr)
6415 ferr(po, "%s not declared as fptr when it should be\n",
6416 po->operand[0].name);
6417 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6418 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6419 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6420 fnote(po, "var: %s\n", buf1);
6421 fnote(po, "func: %s\n", buf2);
6422 ferr(po, "^ mismatch\n");
6430 if (po->operand[0].lmod == OPLM_DWORD) {
6431 // 32bit division is common, look for it
6432 if (po->op == OP_DIV)
6433 ret = scan_for_reg_clear(i, xDX);
6435 ret = scan_for_cdq_edx(i);
6437 po->flags |= OPF_32BIT;
6446 po->flags |= OPF_RMD | OPF_DONE;
6456 if (po->operand[0].lmod == OPLM_QWORD)
6467 find_next_read_reg(i + 1, opcnt, xDX, OPLM_DWORD,
6468 i + opcnt * 18, &j);
6470 po->flags |= OPF_32BIT;
6478 // pass8: final adjustments
6479 for (i = 0; i < opcnt; i++)
6482 if (po->flags & (OPF_RMD|OPF_DONE))
6485 if (po->op != OP_FST && po->p_argnum > 0)
6486 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6488 // correct for "full stack" mode late enable
6489 if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6490 && need_float_stack)
6491 po->flags |= OPF_FSHIFT;
6494 float_type = need_double ? "double" : "float";
6495 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6496 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6498 // output starts here
6501 fprintf(fout, "// had SEH\n");
6503 // define userstack size
6504 if (g_func_pp->is_userstack) {
6505 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6506 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6507 fprintf(fout, "#endif\n");
6510 // the function itself
6511 ferr_assert(ops, !g_func_pp->is_fptr);
6512 output_pp(fout, g_func_pp,
6513 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6514 fprintf(fout, "\n{\n");
6516 // declare indirect functions
6517 for (i = 0; i < opcnt; i++) {
6519 if (po->flags & OPF_RMD)
6522 if (po->op == OP_CALL) {
6525 ferr(po, "NULL pp\n");
6527 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6528 if (pp->name[0] != 0) {
6529 if (IS_START(pp->name, "guess"))
6532 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6533 memcpy(pp->name, "i_", 2);
6535 // might be declared already
6537 for (j = 0; j < i; j++) {
6538 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6539 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6549 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6552 output_pp(fout, pp, OPP_SIMPLE_ARGS);
6553 fprintf(fout, ";\n");
6558 // output LUTs/jumptables
6559 for (i = 0; i < g_func_pd_cnt; i++) {
6561 fprintf(fout, " static const ");
6562 if (pd->type == OPT_OFFSET) {
6563 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6565 for (j = 0; j < pd->count; j++) {
6567 fprintf(fout, ", ");
6568 fprintf(fout, "&&%s", pd->d[j].u.label);
6572 fprintf(fout, "%s %s[] =\n { ",
6573 lmod_type_u(ops, pd->lmod), pd->label);
6575 for (j = 0; j < pd->count; j++) {
6577 fprintf(fout, ", ");
6578 fprintf(fout, "%u", pd->d[j].u.val);
6581 fprintf(fout, " };\n");
6585 // declare stack frame, va_arg
6588 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6590 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6591 if (g_func_lmods & (1 << OPLM_WORD))
6592 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6593 if (g_func_lmods & (1 << OPLM_BYTE))
6594 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6595 if (g_func_lmods & (1 << OPLM_QWORD))
6596 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6598 if (stack_align > 8)
6599 ferr(ops, "unhandled stack align of %d\n", stack_align);
6600 else if (stack_align == 8)
6601 fprintf(fout, " u64 align;");
6602 fprintf(fout, " } sf;\n");
6606 if ((g_sct_func_attr & SCTFA_ARGFRAME) && g_func_pp->argc_stack) {
6607 fprintf(fout, " struct { u32 ");
6608 for (i = j = 0; i < g_func_pp->argc; i++) {
6609 if (g_func_pp->arg[i].reg != NULL)
6612 fprintf(fout, ", ");
6613 fprintf(fout, "a%d", i + 1);
6615 fprintf(fout, "; } af = {\n ");
6616 for (i = j = 0; i < g_func_pp->argc; i++) {
6617 if (g_func_pp->arg[i].reg != NULL)
6620 fprintf(fout, ", ");
6621 if (g_func_pp->arg[i].type.is_ptr)
6622 fprintf(fout, "(u32)");
6623 fprintf(fout, "a%d", i + 1);
6625 fprintf(fout, "\n };\n");
6628 if (g_func_pp->is_userstack) {
6629 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6630 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6634 if (g_func_pp->is_vararg) {
6635 fprintf(fout, " va_list ap;\n");
6639 // declare arg-registers
6640 for (i = 0; i < g_func_pp->argc; i++) {
6641 if (g_func_pp->arg[i].reg != NULL) {
6642 reg = char_array_i(regs_r32,
6643 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6644 if (regmask & (1 << reg)) {
6645 if (g_func_pp->arg[i].type.is_retreg)
6646 fprintf(fout, " u32 %s = *r_%s;\n",
6647 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6649 fprintf(fout, " u32 %s = (u32)a%d;\n",
6650 g_func_pp->arg[i].reg, i + 1);
6653 if (g_func_pp->arg[i].type.is_retreg)
6654 ferr(ops, "retreg '%s' is unused?\n",
6655 g_func_pp->arg[i].reg);
6656 fprintf(fout, " // %s = a%d; // unused\n",
6657 g_func_pp->arg[i].reg, i + 1);
6663 // declare normal registers
6664 regmask_now = regmask & ~regmask_arg & ~g_regmask_rm;
6665 regmask_now &= ~(1 << xSP);
6666 if (regmask_now & 0x00ff) {
6667 for (reg = 0; reg < 8; reg++) {
6668 if (regmask_now & (1 << reg)) {
6669 fprintf(fout, " u32 %s", regs_r32[reg]);
6670 if (regmask_init & (1 << reg))
6671 fprintf(fout, " = 0");
6672 fprintf(fout, ";\n");
6678 if (regmask_now & 0xff00) {
6679 for (reg = 8; reg < 16; reg++) {
6680 if (regmask_now & (1 << reg)) {
6681 fprintf(fout, " mmxr %s", regs_r32[reg]);
6682 if (regmask_init & (1 << reg))
6683 fprintf(fout, " = { 0, }");
6684 fprintf(fout, ";\n");
6690 if (need_float_stack) {
6691 fprintf(fout, " %s f_st[8];\n", float_type);
6692 fprintf(fout, " int f_stp = 0;\n");
6696 if (regmask_now & 0xff0000) {
6697 for (reg = 16; reg < 24; reg++) {
6698 if (regmask_now & (1 << reg)) {
6699 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6700 if (regmask_init & (1 << reg))
6701 fprintf(fout, " = 0");
6702 fprintf(fout, ";\n");
6709 if (need_float_sw) {
6710 fprintf(fout, " u16 f_sw;\n");
6715 for (reg = 0; reg < 8; reg++) {
6716 if (regmask_save & (1 << reg)) {
6717 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6723 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6724 if (save_arg_vars[i] == 0)
6726 for (reg = 0; reg < 32; reg++) {
6727 if (save_arg_vars[i] & (1 << reg)) {
6728 fprintf(fout, " u32 %s;\n",
6729 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6736 for (reg = 0; reg < 32; reg++) {
6737 if (regmask_ffca & (1 << reg)) {
6738 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6744 // declare push-pop temporaries
6746 for (reg = 0; reg < 8; reg++) {
6747 if (regmask_pp & (1 << reg)) {
6748 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6755 for (i = 0; i < 8; i++) {
6756 if (cond_vars & (1 << i)) {
6757 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6764 fprintf(fout, " u32 tmp;\n");
6769 fprintf(fout, " u64 tmp64;\n");
6774 fprintf(fout, "\n");
6776 // do stack clear, if needed
6777 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6779 if (g_stack_clear_len != 0) {
6780 if (g_stack_clear_len <= 4) {
6781 for (i = 0; i < g_stack_clear_len; i++)
6782 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6783 fprintf(fout, "0;\n");
6786 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6787 g_stack_clear_start, g_stack_clear_len * 4);
6791 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6794 if (g_func_pp->is_vararg) {
6795 if (g_func_pp->argc_stack == 0)
6796 ferr(ops, "vararg func without stack args?\n");
6797 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6801 for (i = 0; i < opcnt; i++)
6803 if (g_labels[i] != NULL) {
6804 fprintf(fout, "\n%s:\n", g_labels[i]);
6807 delayed_flag_op = NULL;
6808 last_arith_dst = NULL;
6812 if (po->flags & OPF_RMD)
6818 #define assert_operand_cnt(n_) \
6819 if (po->operand_cnt != n_) \
6820 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6822 // conditional/flag using op?
6823 if (po->flags & OPF_CC)
6829 // we go through all this trouble to avoid using parsed_flag_op,
6830 // which makes generated code much nicer
6831 if (delayed_flag_op != NULL)
6833 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6834 po->pfo, po->pfo_inv);
6837 else if (last_arith_dst != NULL
6838 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6839 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6842 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6843 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6844 last_arith_dst->lmod, buf3);
6847 else if (tmp_op != NULL) {
6848 // use preprocessed flag calc results
6849 if (!(tmp_op->pfomask & (1 << po->pfo)))
6850 ferr(po, "not prepared for pfo %d\n", po->pfo);
6852 // note: pfo_inv was not yet applied
6853 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6854 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6857 ferr(po, "all methods of finding comparison failed\n");
6860 if (po->flags & OPF_JMP) {
6861 fprintf(fout, " if %s", buf1);
6863 else if (po->op == OP_RCL || po->op == OP_RCR
6864 || po->op == OP_ADC || po->op == OP_SBB)
6867 fprintf(fout, " cond_%s = %s;\n",
6868 parsed_flag_op_names[po->pfo], buf1);
6870 else if (po->flags & OPF_DATA) { // SETcc
6871 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6872 fprintf(fout, " %s = %s;", buf2, buf1);
6875 ferr(po, "unhandled conditional op\n");
6879 pfomask = po->pfomask;
6884 assert_operand_cnt(2);
6885 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6886 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6887 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6888 fprintf(fout, " %s = %s;", buf1,
6889 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6894 assert_operand_cnt(2);
6895 po->operand[1].lmod = OPLM_DWORD; // always
6896 fprintf(fout, " %s = %s;",
6897 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6898 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6903 assert_operand_cnt(2);
6904 fprintf(fout, " %s = %s;",
6905 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6906 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6910 assert_operand_cnt(2);
6911 switch (po->operand[1].lmod) {
6913 strcpy(buf3, "(s8)");
6916 strcpy(buf3, "(s16)");
6919 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6921 fprintf(fout, " %s = %s;",
6922 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6923 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6928 assert_operand_cnt(2);
6929 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6930 fprintf(fout, " tmp = %s;",
6931 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6932 fprintf(fout, " %s = %s;",
6933 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6934 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6935 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6936 fprintf(fout, " %s = %stmp;",
6937 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6938 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6939 snprintf(g_comment, sizeof(g_comment), "xchg");
6943 assert_operand_cnt(1);
6944 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6945 fprintf(fout, " %s = ~%s;", buf1, buf1);
6949 assert_operand_cnt(2);
6950 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6951 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6952 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6953 strcpy(g_comment, "xlat");
6957 assert_operand_cnt(2);
6958 fprintf(fout, " %s = (s32)%s >> 31;",
6959 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6960 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6961 strcpy(g_comment, "cdq");
6965 assert_operand_cnt(1);
6966 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6967 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6971 if (po->flags & OPF_REP) {
6972 assert_operand_cnt(3);
6977 assert_operand_cnt(2);
6978 fprintf(fout, " %s = %sesi; esi %c= %d;",
6979 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6980 lmod_cast_u_ptr(po, po->operand[1].lmod),
6981 (po->flags & OPF_DF) ? '-' : '+',
6982 lmod_bytes(po, po->operand[1].lmod));
6983 strcpy(g_comment, "lods");
6988 if (po->flags & OPF_REP) {
6989 assert_operand_cnt(3);
6990 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
6991 (po->flags & OPF_DF) ? '-' : '+',
6992 lmod_bytes(po, po->operand[1].lmod));
6993 fprintf(fout, " %sedi = eax;\n",
6994 lmod_cast_u_ptr(po, po->operand[1].lmod));
6995 fprintf(fout, " barrier();");
6996 strcpy(g_comment, "^ rep stos");
6999 assert_operand_cnt(2);
7000 fprintf(fout, " %sedi = eax; edi %c= %d;",
7001 lmod_cast_u_ptr(po, po->operand[1].lmod),
7002 (po->flags & OPF_DF) ? '-' : '+',
7003 lmod_bytes(po, po->operand[1].lmod));
7004 strcpy(g_comment, "stos");
7009 j = lmod_bytes(po, po->operand[0].lmod);
7010 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
7011 l = (po->flags & OPF_DF) ? '-' : '+';
7012 if (po->flags & OPF_REP) {
7013 assert_operand_cnt(3);
7015 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
7018 " %sedi = %sesi;\n", buf1, buf1);
7019 // this can overwrite many variables
7020 fprintf(fout, " barrier();");
7021 strcpy(g_comment, "^ rep movs");
7024 assert_operand_cnt(2);
7025 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
7026 buf1, buf1, l, j, l, j);
7027 strcpy(g_comment, "movs");
7032 // repe ~ repeat while ZF=1
7033 j = lmod_bytes(po, po->operand[0].lmod);
7034 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
7035 l = (po->flags & OPF_DF) ? '-' : '+';
7036 if (po->flags & OPF_REP) {
7037 assert_operand_cnt(3);
7039 " while (ecx != 0) {\n");
7040 if (pfomask & (1 << PFO_C)) {
7043 " cond_c = %sesi < %sedi;\n", buf1, buf1);
7044 pfomask &= ~(1 << PFO_C);
7047 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
7048 buf1, buf1, l, j, l, j);
7051 " if (cond_z %s 0) break;\n",
7052 (po->flags & OPF_REPZ) ? "==" : "!=");
7055 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
7056 (po->flags & OPF_REPZ) ? "e" : "ne");
7059 assert_operand_cnt(2);
7061 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
7062 buf1, buf1, l, j, l, j);
7063 strcpy(g_comment, "cmps");
7065 pfomask &= ~(1 << PFO_Z);
7066 last_arith_dst = NULL;
7067 delayed_flag_op = NULL;
7071 // only does ZF (for now)
7072 // repe ~ repeat while ZF=1
7073 j = lmod_bytes(po, po->operand[1].lmod);
7074 l = (po->flags & OPF_DF) ? '-' : '+';
7075 if (po->flags & OPF_REP) {
7076 assert_operand_cnt(3);
7078 " while (ecx != 0) {\n");
7080 " cond_z = (%seax == %sedi); edi %c= %d;\n",
7081 lmod_cast_u(po, po->operand[1].lmod),
7082 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
7085 " if (cond_z %s 0) break;\n",
7086 (po->flags & OPF_REPZ) ? "==" : "!=");
7089 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
7090 (po->flags & OPF_REPZ) ? "e" : "ne");
7093 assert_operand_cnt(2);
7094 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
7095 lmod_cast_u(po, po->operand[1].lmod),
7096 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
7097 strcpy(g_comment, "scas");
7099 pfomask &= ~(1 << PFO_Z);
7100 last_arith_dst = NULL;
7101 delayed_flag_op = NULL;
7105 fprintf(fout, " tmp64 = ext_rdtsc();\n");
7106 fprintf(fout, " edx = tmp64 >> 32;\n");
7107 fprintf(fout, " eax = tmp64;");
7111 fprintf(fout, " ext_cpuid(&eax, &ebx, &ecx, &edx);");
7114 // arithmetic w/flags
7116 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
7117 goto dualop_arith_const;
7118 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7122 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7123 if (po->operand[1].type == OPT_CONST) {
7124 j = lmod_bytes(po, po->operand[0].lmod);
7125 if (((1ull << j * 8) - 1) == po->operand[1].val)
7126 goto dualop_arith_const;
7131 assert_operand_cnt(2);
7132 fprintf(fout, " %s %s= %s;",
7133 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7135 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7136 output_std_flags(fout, po, &pfomask, buf1);
7137 last_arith_dst = &po->operand[0];
7138 delayed_flag_op = NULL;
7142 // and 0, or ~0 used instead mov
7143 assert_operand_cnt(2);
7144 fprintf(fout, " %s = %s;",
7145 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7146 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7147 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7148 output_std_flags(fout, po, &pfomask, buf1);
7149 last_arith_dst = &po->operand[0];
7150 delayed_flag_op = NULL;
7155 assert_operand_cnt(2);
7156 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7157 if (pfomask & (1 << PFO_C)) {
7158 if (po->operand[1].type == OPT_CONST) {
7159 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7160 j = po->operand[1].val;
7163 if (po->op == OP_SHL)
7167 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
7171 ferr(po, "zero shift?\n");
7175 pfomask &= ~(1 << PFO_C);
7177 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
7178 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7179 if (po->operand[1].type != OPT_CONST)
7180 fprintf(fout, " & 0x1f");
7182 output_std_flags(fout, po, &pfomask, buf1);
7183 last_arith_dst = &po->operand[0];
7184 delayed_flag_op = NULL;
7188 assert_operand_cnt(2);
7189 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7190 fprintf(fout, " %s = %s%s >> %s;", buf1,
7191 lmod_cast_s(po, po->operand[0].lmod), buf1,
7192 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7193 output_std_flags(fout, po, &pfomask, buf1);
7194 last_arith_dst = &po->operand[0];
7195 delayed_flag_op = NULL;
7200 assert_operand_cnt(3);
7201 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7202 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7203 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
7204 if (po->operand[2].type != OPT_CONST) {
7205 // no handling for "undefined" case, hopefully not needed
7206 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
7209 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7210 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7211 if (po->op == OP_SHLD) {
7212 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
7213 buf1, buf3, buf1, buf2, l, buf3);
7214 strcpy(g_comment, "shld");
7217 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
7218 buf1, buf3, buf1, buf2, l, buf3);
7219 strcpy(g_comment, "shrd");
7221 output_std_flags(fout, po, &pfomask, buf1);
7222 last_arith_dst = &po->operand[0];
7223 delayed_flag_op = NULL;
7228 assert_operand_cnt(2);
7229 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7230 if (po->operand[1].type == OPT_CONST) {
7231 j = po->operand[1].val;
7232 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
7233 fprintf(fout, po->op == OP_ROL ?
7234 " %s = (%s << %d) | (%s >> %d);" :
7235 " %s = (%s >> %d) | (%s << %d);",
7236 buf1, buf1, j, buf1,
7237 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
7241 output_std_flags(fout, po, &pfomask, buf1);
7242 last_arith_dst = &po->operand[0];
7243 delayed_flag_op = NULL;
7248 assert_operand_cnt(2);
7249 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7250 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7251 if (po->operand[1].type == OPT_CONST) {
7252 j = po->operand[1].val % l;
7254 ferr(po, "zero rotate\n");
7255 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
7256 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
7257 if (po->op == OP_RCL) {
7259 " %s = (%s << %d) | (cond_c << %d)",
7260 buf1, buf1, j, j - 1);
7262 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
7266 " %s = (%s >> %d) | (cond_c << %d)",
7267 buf1, buf1, j, l - j);
7269 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
7271 fprintf(fout, ";\n");
7272 fprintf(fout, " cond_c = tmp;");
7276 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
7277 output_std_flags(fout, po, &pfomask, buf1);
7278 last_arith_dst = &po->operand[0];
7279 delayed_flag_op = NULL;
7283 assert_operand_cnt(2);
7284 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7285 if (IS(opr_name(po, 0), opr_name(po, 1))) {
7286 // special case for XOR
7287 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
7288 for (j = 0; j <= PFO_LE; j++) {
7289 if (pfomask & (1 << j)) {
7290 fprintf(fout, " cond_%s = %d;\n",
7291 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
7292 pfomask &= ~(1 << j);
7295 fprintf(fout, " %s = 0;",
7296 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7297 last_arith_dst = &po->operand[0];
7298 delayed_flag_op = NULL;
7304 assert_operand_cnt(2);
7305 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7306 if (pfomask & (1 << PFO_C)) {
7307 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7308 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7309 if (po->operand[0].lmod == OPLM_DWORD) {
7310 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
7311 fprintf(fout, " cond_c = tmp64 >> 32;\n");
7312 fprintf(fout, " %s = (u32)tmp64;",
7313 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7314 strcat(g_comment, " add64");
7317 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
7318 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
7319 fprintf(fout, " %s += %s;",
7320 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7323 pfomask &= ~(1 << PFO_C);
7324 output_std_flags(fout, po, &pfomask, buf1);
7325 last_arith_dst = &po->operand[0];
7326 delayed_flag_op = NULL;
7329 if (pfomask & (1 << PFO_LE)) {
7330 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
7331 fprintf(fout, " cond_%s = %s;\n",
7332 parsed_flag_op_names[PFO_LE], buf1);
7333 pfomask &= ~(1 << PFO_LE);
7338 assert_operand_cnt(2);
7339 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7340 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
7341 for (j = 0; j <= PFO_LE; j++) {
7342 if (!(pfomask & (1 << j)))
7344 if (j == PFO_Z || j == PFO_S)
7347 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7348 fprintf(fout, " cond_%s = %s;\n",
7349 parsed_flag_op_names[j], buf1);
7350 pfomask &= ~(1 << j);
7357 assert_operand_cnt(2);
7358 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7359 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7360 if (po->op == OP_SBB
7361 && IS(po->operand[0].name, po->operand[1].name))
7363 // avoid use of unitialized var
7364 fprintf(fout, " %s = -cond_c;", buf1);
7365 // carry remains what it was
7366 pfomask &= ~(1 << PFO_C);
7369 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
7370 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7372 output_std_flags(fout, po, &pfomask, buf1);
7373 last_arith_dst = &po->operand[0];
7374 delayed_flag_op = NULL;
7379 // on SKL, if src is 0, dst is left unchanged
7380 assert_operand_cnt(2);
7381 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7382 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7383 output_std_flag_z(fout, po, &pfomask, buf2);
7384 if (po->op == OP_BSF)
7385 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
7387 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
7388 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
7389 last_arith_dst = &po->operand[0];
7390 delayed_flag_op = NULL;
7391 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
7395 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
7396 for (j = 0; j <= PFO_LE; j++) {
7397 if (!(pfomask & (1 << j)))
7399 if (j == PFO_Z || j == PFO_S || j == PFO_C)
7402 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7403 fprintf(fout, " cond_%s = %s;\n",
7404 parsed_flag_op_names[j], buf1);
7405 pfomask &= ~(1 << j);
7411 if (pfomask & (1 << PFO_C))
7412 // carry is unaffected by inc/dec.. wtf?
7413 ferr(po, "carry propagation needed\n");
7415 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7416 if (po->operand[0].type == OPT_REG) {
7417 ferr_assert(po, !(po->flags & OPF_LOCK));
7418 strcpy(buf2, po->op == OP_INC ? "++" : "--");
7419 fprintf(fout, " %s%s;", buf1, buf2);
7421 else if (po->flags & OPF_LOCK) {
7422 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], "", 1);
7423 fprintf(fout, " __sync_fetch_and_%s((%s *)(%s), 1);",
7424 po->op == OP_INC ? "add" : "sub",
7425 lmod_type_u(po, po->operand[0].lmod), buf2);
7426 strcat(g_comment, " lock");
7430 strcpy(buf2, po->op == OP_INC ? "+" : "-");
7431 fprintf(fout, " %s %s= 1;", buf1, buf2);
7433 output_std_flags(fout, po, &pfomask, buf1);
7434 last_arith_dst = &po->operand[0];
7435 delayed_flag_op = NULL;
7439 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7440 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
7441 fprintf(fout, " %s = -%s%s;", buf1,
7442 lmod_cast_s(po, po->operand[0].lmod), buf2);
7443 last_arith_dst = &po->operand[0];
7444 delayed_flag_op = NULL;
7445 if (pfomask & PFOB_C) {
7446 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
7449 output_std_flags(fout, po, &pfomask, buf1);
7453 if (po->operand_cnt == 2) {
7454 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7457 if (po->operand_cnt == 3)
7458 ferr(po, "TODO imul3\n");
7461 assert_operand_cnt(1);
7462 switch (po->operand[0].lmod) {
7464 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7465 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
7466 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7467 fprintf(fout, " edx = tmp64 >> 32;\n");
7468 fprintf(fout, " eax = tmp64;");
7471 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7472 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
7473 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7477 ferr(po, "TODO: unhandled mul type\n");
7480 last_arith_dst = NULL;
7481 delayed_flag_op = NULL;
7486 assert_operand_cnt(1);
7487 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7488 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7489 po->op == OP_IDIV));
7490 switch (po->operand[0].lmod) {
7492 if (po->flags & OPF_32BIT)
7493 snprintf(buf2, sizeof(buf2), "%seax", cast);
7495 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7496 snprintf(buf2, sizeof(buf2), "%stmp64",
7497 (po->op == OP_IDIV) ? "(s64)" : "");
7499 if (po->operand[0].type == OPT_REG
7500 && po->operand[0].reg == xDX)
7502 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
7503 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
7506 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
7507 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
7511 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
7512 snprintf(buf2, sizeof(buf2), "%stmp",
7513 (po->op == OP_IDIV) ? "(s32)" : "");
7514 if (po->operand[0].type == OPT_REG
7515 && po->operand[0].reg == xDX)
7517 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
7519 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
7523 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
7525 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
7528 strcat(g_comment, " div16");
7531 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7533 last_arith_dst = NULL;
7534 delayed_flag_op = NULL;
7539 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7541 for (j = 0; j < 8; j++) {
7542 if (pfomask & (1 << j)) {
7543 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7544 fprintf(fout, " cond_%s = %s;",
7545 parsed_flag_op_names[j], buf1);
7552 last_arith_dst = NULL;
7553 delayed_flag_op = po;
7557 // SETcc - should already be handled
7560 // note: we reuse OP_Jcc for SETcc, only flags differ
7562 fprintf(fout, "\n goto %s;", po->operand[0].name);
7566 fprintf(fout, " if (ecx == 0)\n");
7567 fprintf(fout, " goto %s;", po->operand[0].name);
7568 strcat(g_comment, " jecxz");
7572 fprintf(fout, " if (--ecx != 0)\n");
7573 fprintf(fout, " goto %s;", po->operand[0].name);
7574 strcat(g_comment, " loop");
7578 assert_operand_cnt(1);
7579 last_arith_dst = NULL;
7580 delayed_flag_op = NULL;
7582 if (po->operand[0].type == OPT_REGMEM) {
7583 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7586 ferr(po, "parse failure for jmp '%s'\n",
7587 po->operand[0].name);
7588 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
7591 else if (po->operand[0].type != OPT_LABEL)
7592 ferr(po, "unhandled jmp type\n");
7594 fprintf(fout, " goto %s;", po->operand[0].name);
7598 assert_operand_cnt(1);
7600 my_assert_not(pp, NULL);
7603 if (po->flags & OPF_CC) {
7604 // we treat conditional branch to another func
7605 // (yes such code exists..) as conditional tailcall
7607 fprintf(fout, " {\n");
7610 if (pp->is_fptr && !pp->is_arg) {
7611 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7612 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7615 if (pp->is_fptr && (pp->is_unresolved || pp->is_guessed)) {
7616 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7617 buf3, asmfn, po->asmln, pp->name);
7620 fprintf(fout, "%s", buf3);
7621 if (strstr(pp->ret_type.name, "int64")) {
7622 if (po->flags & OPF_TAIL)
7623 ferr(po, "int64 and tail?\n");
7624 fprintf(fout, "tmp64 = ");
7626 else if (!IS(pp->ret_type.name, "void")) {
7627 if (po->flags & OPF_TAIL) {
7628 if (regmask_ret & mxAX) {
7629 fprintf(fout, "return ");
7630 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7631 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7633 else if (regmask_ret & mxST0)
7634 ferr(po, "float tailcall\n");
7636 else if (po->regmask_dst & mxAX) {
7637 fprintf(fout, "eax = ");
7638 if (pp->ret_type.is_ptr)
7639 fprintf(fout, "(u32)");
7641 else if (po->regmask_dst & mxST0) {
7642 ferr_assert(po, po->flags & OPF_FPUSH);
7643 if (need_float_stack)
7644 fprintf(fout, "f_st[--f_stp & 7] = ");
7646 fprintf(fout, "f_st0 = ");
7650 if (pp->name[0] == 0)
7651 ferr(po, "missing pp->name\n");
7652 fprintf(fout, "%s%s(", pp->name,
7653 pp->has_structarg ? "_sa" : "");
7655 if (po->flags & OPF_ATAIL) {
7657 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7658 check_compat |= pp->argc_stack > 0;
7660 && (pp->argc_stack != g_func_pp->argc_stack
7661 || pp->is_stdcall != g_func_pp->is_stdcall))
7662 ferr(po, "incompatible arg-reuse tailcall\n");
7663 if (g_func_pp->has_retreg)
7664 ferr(po, "TODO: retreg+tailcall\n");
7666 for (arg = j = 0; arg < pp->argc; arg++) {
7668 fprintf(fout, ", ");
7671 if (pp->arg[arg].type.is_ptr)
7672 snprintf(cast, sizeof(cast), "(%s)",
7673 pp->arg[arg].type.name);
7675 if (pp->arg[arg].reg != NULL) {
7676 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7680 for (; j < g_func_pp->argc; j++)
7681 if (g_func_pp->arg[j].reg == NULL)
7683 fprintf(fout, "%sa%d", cast, j + 1);
7688 for (arg = 0; arg < pp->argc; arg++) {
7690 fprintf(fout, ", ");
7693 if (pp->arg[arg].type.is_ptr)
7694 snprintf(cast, sizeof(cast), "(%s)",
7695 pp->arg[arg].type.name);
7697 if (pp->arg[arg].reg != NULL) {
7698 if (pp->arg[arg].type.is_retreg)
7699 fprintf(fout, "&%s", pp->arg[arg].reg);
7700 else if (IS(pp->arg[arg].reg, "ebp")
7701 && g_bp_frame && !(po->flags & OPF_EBP_S))
7703 // rare special case
7704 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7705 strcat(g_comment, " bp_ref");
7708 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7713 tmp_op = pp->arg[arg].datap;
7715 ferr(po, "parsed_op missing for arg%d\n", arg);
7717 if (tmp_op->flags & OPF_VAPUSH) {
7718 fprintf(fout, "ap");
7720 else if (tmp_op->op == OP_FST) {
7721 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7722 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7725 else if (pp->arg[arg].type.is_64bit) {
7726 ferr_assert(po, tmp_op->p_argpass == 0);
7727 ferr_assert(po, !pp->arg[arg].is_saved);
7728 ferr_assert(po, !pp->arg[arg].type.is_float);
7729 ferr_assert(po, cast[0] == 0);
7730 out_src_opr(buf1, sizeof(buf1),
7731 tmp_op, &tmp_op->operand[0], cast, 0);
7732 tmp_op = pp->arg[++arg].datap;
7733 ferr_assert(po, tmp_op != NULL);
7734 out_src_opr(buf2, sizeof(buf2),
7735 tmp_op, &tmp_op->operand[0], cast, 0);
7736 fprintf(fout, "((u64)(%s) << 32) | (%s)",
7739 else if (tmp_op->p_argpass != 0) {
7740 ferr_assert(po, !pp->arg[arg].type.is_float);
7741 fprintf(fout, "a%d", tmp_op->p_argpass);
7743 else if (pp->arg[arg].is_saved) {
7744 ferr_assert(po, tmp_op->p_argnum > 0);
7745 ferr_assert(po, !pp->arg[arg].type.is_float);
7746 fprintf(fout, "%s%s", cast,
7747 saved_arg_name(buf1, sizeof(buf1),
7748 tmp_op->p_arggrp, tmp_op->p_argnum));
7750 else if (pp->arg[arg].type.is_float) {
7751 ferr_assert(po, !pp->arg[arg].type.is_64bit);
7753 out_src_opr_float(buf1, sizeof(buf1),
7754 tmp_op, &tmp_op->operand[0], need_float_stack));
7758 out_src_opr(buf1, sizeof(buf1),
7759 tmp_op, &tmp_op->operand[0], cast, 0));
7763 fprintf(fout, ");");
7765 if (strstr(pp->ret_type.name, "int64")) {
7766 fprintf(fout, "\n");
7767 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7768 fprintf(fout, "%seax = tmp64;", buf3);
7771 if (pp->is_unresolved) {
7772 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7774 strcat(g_comment, buf2);
7777 if (po->flags & OPF_TAIL) {
7779 if (i == opcnt - 1 || pp->is_noreturn)
7781 else if (IS(pp->ret_type.name, "void"))
7783 else if (!(regmask_ret & (1 << xAX)))
7785 // else already handled as 'return f()'
7788 fprintf(fout, "\n%sreturn;", buf3);
7789 strcat(g_comment, " ^ tailcall");
7792 strcat(g_comment, " tailcall");
7794 if ((regmask_ret & (1 << xAX))
7795 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7797 ferr(po, "int func -> void func tailcall?\n");
7800 if (pp->is_noreturn)
7801 strcat(g_comment, " noreturn");
7802 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7803 strcat(g_comment, " argframe");
7804 if (po->flags & OPF_CC)
7805 strcat(g_comment, " cond");
7807 if (po->flags & OPF_CC)
7808 fprintf(fout, "\n }");
7810 delayed_flag_op = NULL;
7811 last_arith_dst = NULL;
7815 if (g_func_pp->is_vararg)
7816 fprintf(fout, " va_end(ap);\n");
7817 if (g_func_pp->has_retreg) {
7818 for (arg = 0; arg < g_func_pp->argc; arg++)
7819 if (g_func_pp->arg[arg].type.is_retreg)
7820 fprintf(fout, " *r_%s = %s;\n",
7821 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7824 if (regmask_ret & mxST0) {
7825 fprintf(fout, " return %s;", float_st0);
7827 else if (!(regmask_ret & mxAX)) {
7828 if (i != opcnt - 1 || label_pending)
7829 fprintf(fout, " return;");
7831 else if (g_func_pp->ret_type.is_ptr) {
7832 fprintf(fout, " return (%s)eax;",
7833 g_func_pp->ret_type.name);
7835 else if (IS(g_func_pp->ret_type.name, "__int64"))
7836 fprintf(fout, " return ((u64)edx << 32) | eax;");
7838 fprintf(fout, " return eax;");
7840 last_arith_dst = NULL;
7841 delayed_flag_op = NULL;
7845 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7846 if (po->p_argnum != 0) {
7847 // special case - saved func arg
7848 fprintf(fout, " %s = %s;",
7849 saved_arg_name(buf2, sizeof(buf2),
7850 po->p_arggrp, po->p_argnum), buf1);
7853 else if (po->flags & OPF_RSAVE) {
7854 fprintf(fout, " s_%s = %s;", buf1, buf1);
7857 else if (po->flags & OPF_PPUSH) {
7859 ferr_assert(po, tmp_op != NULL);
7860 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7861 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7864 else if (g_func_pp->is_userstack) {
7865 fprintf(fout, " *(--esp) = %s;", buf1);
7868 if (!(g_ida_func_attr & IDAFA_NORETURN))
7869 ferr(po, "stray push encountered\n");
7874 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7875 if (po->flags & OPF_RSAVE) {
7876 fprintf(fout, " %s = s_%s;", buf1, buf1);
7879 else if (po->flags & OPF_PPUSH) {
7880 // push/pop graph / non-const
7881 ferr_assert(po, po->datap == NULL);
7882 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7885 else if (po->datap != NULL) {
7888 fprintf(fout, " %s = %s;", buf1,
7889 out_src_opr(buf2, sizeof(buf2),
7890 tmp_op, &tmp_op->operand[0],
7891 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7894 else if (g_func_pp->is_userstack) {
7895 fprintf(fout, " %s = *esp++;", buf1);
7899 ferr(po, "stray pop encountered\n");
7909 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7910 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7911 po->op == OPP_ALLSHL ? "<<" : ">>");
7912 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7913 strcat(g_comment, po->op == OPP_ALLSHL
7914 ? " allshl" : " allshr");
7919 if (need_float_stack) {
7920 out_src_opr_float(buf1, sizeof(buf1),
7921 po, &po->operand[0], 1);
7922 if (po->regmask_src & mxSTa) {
7923 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7927 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7930 if (po->flags & OPF_FSHIFT)
7931 fprintf(fout, " f_st1 = f_st0;");
7932 if (po->operand[0].type == OPT_REG
7933 && po->operand[0].reg == xST0)
7935 strcat(g_comment, " fld st");
7938 fprintf(fout, " f_st0 = %s;",
7939 out_src_opr_float(buf1, sizeof(buf1),
7940 po, &po->operand[0], 0));
7942 strcat(g_comment, " fld");
7946 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7947 lmod_cast(po, po->operand[0].lmod, 1), 0);
7948 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7949 if (need_float_stack) {
7950 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7953 if (po->flags & OPF_FSHIFT)
7954 fprintf(fout, " f_st1 = f_st0;");
7955 fprintf(fout, " f_st0 = %s;", buf2);
7957 strcat(g_comment, " fild");
7961 if (need_float_stack)
7962 fprintf(fout, " f_st[--f_stp & 7] = ");
7964 if (po->flags & OPF_FSHIFT)
7965 fprintf(fout, " f_st1 = f_st0;");
7966 fprintf(fout, " f_st0 = ");
7968 switch (po->operand[0].val) {
7969 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7970 case X87_CONST_L2T: fprintf(fout, "3.321928094887362;"); break;
7971 case X87_CONST_L2E: fprintf(fout, "M_LOG2E;"); break;
7972 case X87_CONST_PI: fprintf(fout, "M_PI;"); break;
7973 case X87_CONST_LG2: fprintf(fout, "0.301029995663981;"); break;
7974 case X87_CONST_LN2: fprintf(fout, "M_LN2;"); break;
7975 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7976 default: ferr_assert(po, 0); break;
7981 if (po->flags & OPF_FARG) {
7982 // store to stack as func arg
7983 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
7987 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
7989 dead_dst = po->operand[0].type == OPT_REG
7990 && po->operand[0].reg == xST0;
7993 fprintf(fout, " %s = %s;", buf1, float_st0);
7994 if (po->flags & OPF_FSHIFT) {
7995 if (need_float_stack)
7996 fprintf(fout, " f_stp++;");
7998 fprintf(fout, " f_st0 = f_st1;");
8000 if (dead_dst && !(po->flags & OPF_FSHIFT))
8003 strcat(g_comment, " fst");
8007 fprintf(fout, " %s = %s%s;",
8008 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
8009 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
8010 if (po->flags & OPF_FSHIFT) {
8011 if (need_float_stack)
8012 fprintf(fout, " f_stp++;");
8014 fprintf(fout, " f_st0 = f_st1;");
8016 strcat(g_comment, " fist");
8023 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8025 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8027 dead_dst = (po->flags & OPF_FPOP)
8028 && po->operand[0].type == OPT_REG
8029 && po->operand[0].reg == xST0;
8031 case OP_FADD: j = '+'; break;
8032 case OP_FDIV: j = '/'; break;
8033 case OP_FMUL: j = '*'; break;
8034 case OP_FSUB: j = '-'; break;
8035 default: j = 'x'; break;
8037 if (need_float_stack) {
8039 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
8040 if (po->flags & OPF_FSHIFT)
8041 fprintf(fout, " f_stp++;");
8044 if (po->flags & OPF_FSHIFT) {
8045 // note: assumes only 2 regs handled
8047 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
8049 fprintf(fout, " f_st0 = f_st1;");
8052 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
8054 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
8059 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8061 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8063 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
8065 dead_dst = (po->flags & OPF_FPOP)
8066 && po->operand[0].type == OPT_REG
8067 && po->operand[0].reg == xST0;
8068 j = po->op == OP_FDIVR ? '/' : '-';
8069 if (need_float_stack) {
8071 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
8072 if (po->flags & OPF_FSHIFT)
8073 fprintf(fout, " f_stp++;");
8076 if (po->flags & OPF_FSHIFT) {
8078 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
8080 fprintf(fout, " f_st0 = f_st1;");
8083 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
8085 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
8093 case OP_FIADD: j = '+'; break;
8094 case OP_FIDIV: j = '/'; break;
8095 case OP_FIMUL: j = '*'; break;
8096 case OP_FISUB: j = '-'; break;
8097 default: j = 'x'; break;
8099 fprintf(fout, " %s %c= (%s)%s;", float_st0,
8101 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
8102 lmod_cast(po, po->operand[0].lmod, 1), 0));
8107 fprintf(fout, " %s = %s %c %s;", float_st0,
8108 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8110 po->op == OP_FIDIVR ? '/' : '-', float_st0);
8115 ferr_assert(po, po->datap != NULL);
8116 mask = (long)po->datap & 0xffff;
8117 z_check = ((long)po->datap >> 16) & 1;
8118 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8120 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
8121 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
8124 else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
8125 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
8128 else if (mask == 0x4100) { // C3, C0
8130 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
8132 strcat(g_comment, " z_chk_det");
8135 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
8136 "(%s < %s ? 0x0100 : 0);",
8137 float_st0, buf1, float_st0, buf1);
8141 ferr(po, "unhandled sw mask: %x\n", mask);
8142 if (po->flags & OPF_FSHIFT) {
8143 if (need_float_stack) {
8144 if (po->flags & OPF_FPOPP)
8145 fprintf(fout, " f_stp += 2;");
8147 fprintf(fout, " f_stp++;");
8150 ferr_assert(po, !(po->flags & OPF_FPOPP));
8151 fprintf(fout, " f_st0 = f_st1;");
8158 fprintf(fout, " %s = f_sw;",
8159 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
8163 fprintf(fout, " %s = -%s;", float_st0, float_st0);
8167 fprintf(fout, " %s = cos%s(%s);", float_st0,
8168 need_double ? "" : "f", float_st0);
8172 if (need_float_stack) {
8173 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
8174 need_double ? "" : "f", float_st1, float_st0);
8175 fprintf(fout, " f_stp++;");
8178 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
8179 need_double ? "" : "f");
8184 if (need_float_stack) {
8185 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
8186 float_st1, need_double ? "" : "f", float_st0);
8187 fprintf(fout, " f_stp++;");
8190 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
8191 need_double ? "" : "f");
8193 strcat(g_comment, " fyl2x");
8197 fprintf(fout, " %s = sin%s(%s);", float_st0,
8198 need_double ? "" : "f", float_st0);
8202 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
8203 need_double ? "" : "f", float_st0);
8207 dead_dst = po->operand[0].type == OPT_REG
8208 && po->operand[0].reg == xST0;
8210 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8212 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
8213 float_st0, float_st0, buf1, buf1);
8214 strcat(g_comment, " fxch");
8221 ferr_assert(po, po->flags & OPF_32BIT);
8222 fprintf(fout, " eax = (s32)%s;", float_st0);
8223 if (po->flags & OPF_FSHIFT) {
8224 if (need_float_stack)
8225 fprintf(fout, " f_stp++;");
8227 fprintf(fout, " f_st0 = f_st1;");
8229 strcat(g_comment, " ftol");
8233 if (need_float_stack) {
8234 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
8235 need_double ? "" : "f", float_st1, float_st0);
8236 fprintf(fout, " f_stp++;");
8239 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
8240 need_double ? "" : "f");
8242 strcat(g_comment, " CIpow");
8246 fprintf(fout, " do_skip_code_abort();");
8251 fprintf(fout, " do_emms();");
8256 ferr(po, "unhandled op type %d, flags %x\n",
8261 if (g_comment[0] != 0) {
8262 char *p = g_comment;
8263 while (my_isblank(*p))
8265 fprintf(fout, " // %s", p);
8270 fprintf(fout, "\n");
8272 // some sanity checking
8273 if (po->flags & OPF_REP) {
8274 if (po->op != OP_STOS && po->op != OP_MOVS
8275 && po->op != OP_CMPS && po->op != OP_SCAS)
8276 ferr(po, "unexpected rep\n");
8277 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
8278 && (po->op == OP_CMPS || po->op == OP_SCAS))
8279 ferr(po, "cmps/scas with plain rep\n");
8281 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
8282 && po->op != OP_CMPS && po->op != OP_SCAS)
8283 ferr(po, "unexpected repz/repnz\n");
8286 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
8288 if ((po->flags & OPF_LOCK) && !lock_handled)
8289 ferr(po, "unhandled lock\n");
8291 // see is delayed flag stuff is still valid
8292 if (delayed_flag_op != NULL && delayed_flag_op != po) {
8293 if (is_any_opr_modified(delayed_flag_op, po, 0))
8294 delayed_flag_op = NULL;
8297 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
8298 if (is_opr_modified(last_arith_dst, po))
8299 last_arith_dst = NULL;
8306 if (g_stack_fsz && !g_stack_frame_used)
8307 fprintf(fout, " (void)sf;\n");
8309 fprintf(fout, "}\n\n");
8311 gen_x_cleanup(opcnt);
8314 static void gen_x_cleanup(int opcnt)
8318 for (i = 0; i < opcnt; i++) {
8319 struct label_ref *lr, *lr_del;
8321 lr = g_label_refs[i].next;
8322 while (lr != NULL) {
8327 g_label_refs[i].i = -1;
8328 g_label_refs[i].next = NULL;
8330 if (ops[i].op == OP_CALL) {
8332 proto_release(ops[i].pp);
8338 struct func_proto_dep;
8340 struct func_prototype {
8344 int regmask_dep; // likely register args
8345 int regmask_use; // used registers
8346 int has_ret:3; // -1, 0, 1: unresolved, no, yes
8347 unsigned int has_ret64:1;
8348 unsigned int dep_resolved:1;
8349 unsigned int is_stdcall:1;
8350 unsigned int eax_pass:1; // returns without touching eax
8351 unsigned int ptr_taken:1; // pointer taken of this func
8352 struct func_proto_dep *dep_func;
8354 const struct parsed_proto *pp; // seed pp, if any
8357 struct func_proto_dep {
8359 struct func_prototype *proto;
8360 int regmask_live; // .. at the time of call
8361 unsigned int ret_dep:1; // return from this is caller's return
8362 unsigned int has_ret:1; // found from eax use after return
8363 unsigned int has_ret64:1;
8364 unsigned int ptr_taken:1; // pointer taken, not a call
8367 static struct func_prototype *hg_fp;
8368 static int hg_fp_cnt;
8370 static struct scanned_var {
8372 enum opr_lenmod lmod;
8373 unsigned int is_seeded:1;
8374 unsigned int is_c_str:1;
8375 const struct parsed_proto *pp; // seed pp, if any
8377 static int hg_var_cnt;
8379 static char **hg_refs;
8380 static int hg_ref_cnt;
8382 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8385 static struct func_prototype *hg_fp_add(const char *funcn)
8387 struct func_prototype *fp;
8389 if ((hg_fp_cnt & 0xff) == 0) {
8390 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
8391 my_assert_not(hg_fp, NULL);
8392 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
8395 fp = &hg_fp[hg_fp_cnt];
8396 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
8398 fp->argc_stack = -1;
8404 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
8409 for (i = 0; i < fp->dep_func_cnt; i++)
8410 if (IS(fp->dep_func[i].name, name))
8411 return &fp->dep_func[i];
8416 static void hg_fp_add_dep(struct func_prototype *fp, const char *name,
8417 unsigned int ptr_taken)
8419 struct func_proto_dep * dep;
8422 dep = hg_fp_find_dep(fp, name);
8423 if (dep != NULL && dep->ptr_taken == ptr_taken)
8426 if ((fp->dep_func_cnt & 0xff) == 0) {
8427 fp->dep_func = realloc(fp->dep_func,
8428 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
8429 my_assert_not(fp->dep_func, NULL);
8430 memset(&fp->dep_func[fp->dep_func_cnt], 0,
8431 sizeof(fp->dep_func[0]) * 0x100);
8433 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
8434 fp->dep_func[fp->dep_func_cnt].ptr_taken = ptr_taken;
8438 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
8440 const struct func_prototype *p1 = p1_, *p2 = p2_;
8441 return strcmp(p1->name, p2->name);
8445 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
8447 const struct func_prototype *p1 = p1_, *p2 = p2_;
8448 return p1->id - p2->id;
8452 static void hg_ref_add(const char *name)
8454 if ((hg_ref_cnt & 0xff) == 0) {
8455 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8456 my_assert_not(hg_refs, NULL);
8457 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8460 hg_refs[hg_ref_cnt] = strdup(name);
8461 my_assert_not(hg_refs[hg_ref_cnt], NULL);
8465 // recursive register dep pass
8466 // - track saved regs (part 2)
8467 // - try to figure out arg-regs
8468 // - calculate reg deps
8469 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8470 struct func_prototype *fp, int regmask_save, int regmask_dst,
8471 int *regmask_dep, int *regmask_use, int *has_ret)
8473 struct func_proto_dep *dep;
8474 struct parsed_op *po;
8475 int from_caller = 0;
8480 for (; i < opcnt; i++)
8482 if (cbits[i >> 3] & (1 << (i & 7)))
8484 cbits[i >> 3] |= (1 << (i & 7));
8488 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8489 if (po->flags & OPF_RMD)
8492 if (po->btj != NULL) {
8494 for (j = 0; j < po->btj->count; j++) {
8495 check_i(po, po->btj->d[j].bt_i);
8496 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8497 regmask_save, regmask_dst, regmask_dep, regmask_use,
8503 check_i(po, po->bt_i);
8504 if (po->flags & OPF_CJMP) {
8505 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8506 regmask_save, regmask_dst, regmask_dep, regmask_use,
8515 if (po->flags & OPF_FARG)
8516 /* (just calculate register deps) */;
8517 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8519 reg = po->operand[0].reg;
8520 ferr_assert(po, reg >= 0);
8522 if (po->flags & OPF_RSAVE) {
8523 regmask_save |= 1 << reg;
8526 if (po->flags & OPF_DONE)
8529 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2, reg, 0, 0, 0);
8531 regmask_save |= 1 << reg;
8532 po->flags |= OPF_RMD;
8533 scan_for_pop(i + 1, opcnt, i + opcnt * 3, reg, 0, 0, OPF_RMD);
8537 else if (po->flags & OPF_RMD)
8539 else if (po->op == OP_CALL) {
8540 po->regmask_dst |= 1 << xAX;
8542 dep = hg_fp_find_dep(fp, po->operand[0].name);
8544 dep->regmask_live = regmask_save | regmask_dst;
8545 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8546 dep->regmask_live |= 1 << xBP;
8549 else if (po->op == OP_RET) {
8550 if (po->operand_cnt > 0) {
8552 if (fp->argc_stack >= 0
8553 && fp->argc_stack != po->operand[0].val / 4)
8554 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8555 fp->argc_stack = po->operand[0].val / 4;
8559 if (!fp->eax_pass && (po->flags & OPF_TAIL)) {
8560 if (po->op == OP_CALL) {
8565 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
8568 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
8571 if (ret != 1 && from_caller) {
8572 // unresolved eax - probably void func
8577 if (j >= 0 && ops[j].op == OP_CALL) {
8578 if (ops[j].pp != NULL && !ops[j].pp->is_unresolved) {
8579 int call_has_ret = !IS(ops[j].pp->ret_type.name, "void");
8580 if (ops[j].pp->is_noreturn) {
8581 // could be some fail path
8583 *has_ret = call_has_ret;
8586 *has_ret = call_has_ret;
8589 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8601 l = regmask_save | regmask_dst;
8602 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8605 l = po->regmask_src & ~l;
8608 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8609 l, regmask_dst, regmask_save, po->flags);
8612 *regmask_use |= (po->regmask_src | po->regmask_dst)
8614 regmask_dst |= po->regmask_dst;
8616 if (po->flags & OPF_TAIL) {
8617 if (!(po->flags & OPF_CC)) // not cond. tailcall
8623 static void gen_hdr(const char *funcn, int opcnt)
8625 unsigned char cbits[MAX_OPS / 8];
8626 const struct parsed_proto *pp_c;
8627 struct parsed_proto *pp;
8628 struct func_prototype *fp;
8629 struct func_proto_dep *dep;
8630 struct parsed_op *po;
8631 const char *tmpname;
8632 int regmask_dummy = 0;
8635 int max_bp_offset = 0;
8640 pp_c = proto_parse(g_fhdr, funcn, 1);
8642 // already in seed, will add to hg_fp later
8645 fp = hg_fp_add(funcn);
8647 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8648 g_stack_frame_used = 0;
8652 // - resolve all branches
8653 // - parse calls with labels
8654 resolve_branches_parse_calls(opcnt);
8657 // - handle ebp/esp frame, remove ops related to it
8658 scan_prologue_epilogue(opcnt, NULL);
8661 // - remove dead labels
8663 // - collect function ptr refs
8664 for (i = 0; i < opcnt; i++)
8666 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8672 if (po->flags & (OPF_RMD|OPF_DONE))
8675 if (po->op == OP_CALL) {
8676 if (po->operand[0].type == OPT_LABEL)
8677 hg_fp_add_dep(fp, opr_name(po, 0), 0);
8678 else if (po->pp != NULL)
8679 hg_fp_add_dep(fp, po->pp->name, 0);
8681 else if (po->op == OP_MOV && po->operand[1].type == OPT_OFFSET) {
8682 tmpname = opr_name(po, 1);
8683 if (IS_START(tmpname, "p_") || IS_START(tmpname, "sub_"))
8684 hg_fp_add_dep(fp, tmpname, 1);
8686 else if (po->op == OP_PUSH && po->operand[0].type == OPT_OFFSET) {
8687 tmpname = opr_name(po, 0);
8688 if (IS_START(tmpname, "p_") || IS_START(tmpname, "sub_"))
8689 hg_fp_add_dep(fp, tmpname, 1);
8694 // - handle push <const>/pop pairs
8695 for (i = 0; i < opcnt; i++)
8698 if (po->flags & (OPF_RMD|OPF_DONE))
8701 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8702 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8706 // - process trivial calls
8707 for (i = 0; i < opcnt; i++)
8710 if (po->flags & (OPF_RMD|OPF_DONE))
8713 if (po->op == OP_CALL)
8715 pp = process_call_early(i, opcnt, &j);
8717 if (!(po->flags & OPF_ATAIL))
8718 // since we know the args, try to collect them
8719 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8725 // commit esp adjust
8726 if (ops[j].op != OP_POP)
8727 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8729 for (l = 0; l < pp->argc_stack; l++)
8730 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8734 po->flags |= OPF_DONE;
8740 // - track saved regs (simple)
8742 for (i = 0; i < opcnt; i++)
8745 if (po->flags & (OPF_RMD|OPF_DONE))
8748 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8749 && po->operand[0].reg != xCX)
8751 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8753 // regmask_save |= 1 << po->operand[0].reg; // do it later
8754 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8755 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8758 else if (po->op == OP_CALL)
8760 pp = process_call(i, opcnt);
8762 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8763 // since we know the args, collect them
8764 ret = collect_call_args(po, i, pp, ®mask_dummy,
8767 if (!(po->flags & OPF_TAIL)
8768 && po->operand[0].type == OPT_LABEL)
8770 dep = hg_fp_find_dep(fp, opr_name(po, 0));
8771 ferr_assert(po, dep != NULL);
8772 // treat al write as overwrite to avoid many false positives
8773 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
8774 i + opcnt * 25, &j);
8777 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
8778 i + opcnt * 26, &j);
8779 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j]))
8786 memset(cbits, 0, (opcnt + 7) / 8);
8787 regmask_dep = regmask_use = 0;
8790 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0,
8791 ®mask_dep, ®mask_use, &has_ret);
8793 // find unreachable code - must be fixed in IDA
8794 for (i = 0; i < opcnt; i++)
8796 if (cbits[i >> 3] & (1 << (i & 7)))
8799 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8800 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8802 // the compiler sometimes still generates code after
8803 // noreturn OS functions
8806 if (!(ops[i].flags & OPF_RMD)
8807 && ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8809 ferr(&ops[i], "unreachable code\n");
8813 for (i = 0; i < g_eqcnt; i++) {
8814 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8815 max_bp_offset = g_eqs[i].offset;
8818 if (fp->argc_stack < 0) {
8819 max_bp_offset = (max_bp_offset + 3) & ~3;
8820 fp->argc_stack = max_bp_offset / 4;
8821 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8825 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8826 fp->regmask_use = regmask_use;
8827 fp->has_ret = has_ret;
8829 printf("// has_ret %d, regmask_dep %x\n",
8830 fp->has_ret, fp->regmask_dep);
8831 output_hdr_fp(stdout, fp, 1);
8832 if (IS(funcn, "sub_10007F72")) exit(1);
8835 gen_x_cleanup(opcnt);
8838 static void hg_fp_resolve_deps(struct func_prototype *fp)
8840 struct func_prototype fp_s;
8841 struct func_proto_dep *dep;
8845 // this thing is recursive, so mark first..
8846 fp->dep_resolved = 1;
8848 for (i = 0; i < fp->dep_func_cnt; i++) {
8849 dep = &fp->dep_func[i];
8851 strcpy(fp_s.name, dep->name);
8852 dep->proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8853 sizeof(hg_fp[0]), hg_fp_cmp_name);
8854 if (dep->proto != NULL) {
8855 if (dep->ptr_taken) {
8856 dep->proto->ptr_taken = 1;
8860 if (!dep->proto->dep_resolved)
8861 hg_fp_resolve_deps(dep->proto);
8863 regmask_dep = ~dep->regmask_live
8864 & dep->proto->regmask_dep;
8865 fp->regmask_dep |= regmask_dep;
8866 // printf("dep %s %s |= %x\n", fp->name,
8867 // fp->dep_func[i].name, regmask_dep);
8869 if (dep->has_ret && (dep->proto->regmask_use & mxAX))
8870 dep->proto->has_ret = 1;
8871 if (dep->has_ret64 && (dep->proto->regmask_use & mxDX))
8872 dep->proto->has_ret64 = 1;
8873 if (fp->has_ret == -1 && dep->ret_dep)
8874 fp->has_ret = dep->proto->has_ret;
8879 // make all thiscall/edx arg functions referenced from .data fastcall
8880 static void do_func_refs_from_data(void)
8882 struct func_prototype *fp, fp_s;
8885 for (i = 0; i < hg_ref_cnt; i++) {
8886 strcpy(fp_s.name, hg_refs[i]);
8887 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8888 sizeof(hg_fp[0]), hg_fp_cmp_name);
8894 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8897 const struct parsed_proto *pp;
8898 char *p, namebuf[NAMELEN];
8904 for (; count > 0; count--, fp++) {
8905 if (fp->has_ret == -1)
8906 fprintf(fout, "// ret unresolved\n");
8908 fprintf(fout, "// dep:");
8909 for (j = 0; j < fp->dep_func_cnt; j++) {
8910 fprintf(fout, " %s/", fp->dep_func[j].name);
8911 if (fp->dep_func[j].proto != NULL)
8912 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8913 fp->dep_func[j].proto->has_ret);
8915 fprintf(fout, "\n");
8918 p = strchr(fp->name, '@');
8920 memcpy(namebuf, fp->name, p - fp->name);
8921 namebuf[p - fp->name] = 0;
8929 pp = proto_parse(g_fhdr, name, 1);
8930 if (pp != NULL && pp->is_include)
8933 if (fp->pp != NULL) {
8934 // part of seed, output later
8938 regmask_dep = fp->regmask_dep;
8939 argc_normal = fp->argc_stack;
8940 if (fp->ptr_taken && regmask_dep
8941 && (regmask_dep & ~(mxCX|mxDX)) == 0)
8943 if ((regmask_dep & mxDX) || fp->argc_stack > 0)
8944 regmask_dep |= mxCX | mxDX;
8947 fprintf(fout, "%-5s",
8948 fp->pp ? fp->pp->ret_type.name :
8949 fp->has_ret64 ? "__int64" :
8950 fp->has_ret ? "int" : "void");
8951 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8952 && (regmask_dep & ~mxCX) == 0)
8954 fprintf(fout, "/*__thiscall*/ ");
8958 else if ((regmask_dep == (mxCX | mxDX)
8959 && (fp->is_stdcall || fp->argc_stack == 0))
8960 || (regmask_dep == mxCX && fp->argc_stack == 0))
8962 fprintf(fout, " __fastcall ");
8963 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8969 else if (regmask_dep && !fp->is_stdcall) {
8970 fprintf(fout, "/*__usercall*/ ");
8972 else if (regmask_dep) {
8973 fprintf(fout, "/*__userpurge*/ ");
8975 else if (fp->is_stdcall)
8976 fprintf(fout, " __stdcall ");
8978 fprintf(fout, " __cdecl ");
8980 fprintf(fout, "%s(", name);
8983 for (j = 0; j < xSP; j++) {
8984 if (regmask_dep & (1 << j)) {
8987 fprintf(fout, ", ");
8989 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
8991 fprintf(fout, "int");
8992 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
8996 for (j = 0; j < argc_normal; j++) {
8999 fprintf(fout, ", ");
9000 if (fp->pp != NULL) {
9001 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
9002 if (!fp->pp->arg[arg - 1].type.is_ptr)
9006 fprintf(fout, "int ");
9007 fprintf(fout, "a%d", arg);
9010 fprintf(fout, ");\n");
9014 static void output_hdr(FILE *fout)
9016 static const char *lmod_c_names[] = {
9017 [OPLM_UNSPEC] = "???",
9018 [OPLM_BYTE] = "uint8_t",
9019 [OPLM_WORD] = "uint16_t",
9020 [OPLM_DWORD] = "uint32_t",
9021 [OPLM_QWORD] = "uint64_t",
9023 const struct scanned_var *var;
9024 struct func_prototype *fp;
9025 char line[256] = { 0, };
9029 // add stuff from headers
9030 for (i = 0; i < pp_cache_size; i++) {
9031 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
9032 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
9034 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
9035 fp = hg_fp_add(name);
9036 fp->pp = &pp_cache[i];
9037 fp->argc_stack = fp->pp->argc_stack;
9038 fp->is_stdcall = fp->pp->is_stdcall;
9039 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
9040 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
9044 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
9045 for (i = 0; i < hg_fp_cnt; i++)
9046 hg_fp_resolve_deps(&hg_fp[i]);
9048 // adjust functions referenced from data segment
9049 do_func_refs_from_data();
9051 // final adjustments
9052 for (i = 0; i < hg_fp_cnt; i++) {
9053 if (hg_fp[i].eax_pass && (hg_fp[i].regmask_dep & mxAX))
9054 hg_fp[i].has_ret = 1;
9057 // note: messes up .proto ptr, don't use
9058 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
9061 for (i = 0; i < hg_var_cnt; i++) {
9064 if (var->pp != NULL)
9067 else if (var->is_c_str)
9068 fprintf(fout, "extern %-8s %s[];", "char", var->name);
9070 fprintf(fout, "extern %-8s %s;",
9071 lmod_c_names[var->lmod], var->name);
9074 fprintf(fout, " // seeded");
9075 fprintf(fout, "\n");
9078 fprintf(fout, "\n");
9080 // output function prototypes
9081 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
9084 fprintf(fout, "\n// - seed -\n");
9087 while (fgets(line, sizeof(line), g_fhdr))
9088 fwrite(line, 1, strlen(line), fout);
9091 // '=' needs special treatment
9093 static char *next_word_s(char *w, size_t wsize, char *s)
9100 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
9102 for (i = 1; i < wsize - 1; i++) {
9104 printf("warning: missing closing quote: \"%s\"\n", s);
9113 for (; i < wsize - 1; i++) {
9114 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
9120 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
9121 printf("warning: '%s' truncated\n", w);
9126 static int cmpstringp(const void *p1, const void *p2)
9128 return strcmp(*(char * const *)p1, *(char * const *)p2);
9131 static int is_xref_needed(char *p, char **rlist, int rlist_len)
9136 if (strstr(p, "..."))
9137 // unable to determine, assume needed
9140 if (*p == '.') // .text, .data, ...
9141 // ref from other data or non-function -> no
9144 p2 = strpbrk(p, "+:\r\n\x18");
9147 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9148 // referenced from removed code
9154 static int ida_xrefs_show_need(FILE *fasm, char *p,
9155 char **rlist, int rlist_len)
9161 p = strrchr(p, ';');
9162 if (p != NULL && *p == ';') {
9163 if (IS_START(p + 2, "sctref"))
9165 if (IS_START(p + 2, "DATA XREF: ")) {
9167 if (is_xref_needed(p, rlist, rlist_len))
9175 if (!my_fgets(line, sizeof(line), fasm))
9177 // non-first line is always indented
9178 if (!my_isblank(line[0]))
9181 // should be no content, just comment
9186 p = strrchr(p, ';');
9189 if (IS_START(p, "sctref")) {
9194 // it's printed once, but no harm to check again
9195 if (IS_START(p, "DATA XREF: "))
9198 if (is_xref_needed(p, rlist, rlist_len)) {
9203 fseek(fasm, pos, SEEK_SET);
9207 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
9209 struct scanned_var *var;
9210 char line[256] = { 0, };
9219 // skip to next data section
9220 while (my_fgets(line, sizeof(line), fasm))
9225 if (*p == 0 || *p == ';')
9228 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
9229 if (*p == 0 || *p == ';')
9232 if (*p != 's' || !IS_START(p, "segment para public"))
9238 if (p == NULL || !IS_START(p, "segment para public"))
9242 if (!IS_START(p, "'DATA'"))
9246 while (my_fgets(line, sizeof(line), fasm))
9251 no_identifier = my_isblank(*p);
9254 if (*p == 0 || *p == ';')
9257 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9258 words[wordc][0] = 0;
9259 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9260 if (*p == 0 || *p == ';') {
9266 if (wordc == 2 && IS(words[1], "ends"))
9271 if (no_identifier) {
9272 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
9273 hg_ref_add(words[2]);
9277 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
9278 // when this starts, we don't need anything from this section
9282 // check refs comment(s)
9283 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
9286 if ((hg_var_cnt & 0xff) == 0) {
9287 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
9288 * (hg_var_cnt + 0x100));
9289 my_assert_not(hg_vars, NULL);
9290 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
9293 var = &hg_vars[hg_var_cnt++];
9294 snprintf(var->name, sizeof(var->name), "%s", words[0]);
9296 // maybe already in seed header?
9297 var->pp = proto_parse(g_fhdr, var->name, 1);
9298 if (var->pp != NULL) {
9299 if (var->pp->is_fptr) {
9300 var->lmod = OPLM_DWORD;
9303 else if (var->pp->is_func)
9305 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
9306 aerr("unhandled C type '%s' for '%s'\n",
9307 var->pp->type.name, var->name);
9313 if (IS(words[1], "dd")) {
9314 var->lmod = OPLM_DWORD;
9315 if (wordc >= 4 && IS(words[2], "offset"))
9316 hg_ref_add(words[3]);
9318 else if (IS(words[1], "dw"))
9319 var->lmod = OPLM_WORD;
9320 else if (IS(words[1], "db")) {
9321 var->lmod = OPLM_BYTE;
9322 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
9323 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
9327 else if (IS(words[1], "dq"))
9328 var->lmod = OPLM_QWORD;
9329 //else if (IS(words[1], "dt"))
9331 aerr("type '%s' not known\n", words[1]);
9339 static void set_label(int i, const char *name)
9345 p = strchr(name, ':');
9349 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
9350 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
9351 g_labels[i] = realloc(g_labels[i], len + 1);
9352 my_assert_not(g_labels[i], NULL);
9353 memcpy(g_labels[i], name, len);
9354 g_labels[i][len] = 0;
9363 static struct chunk_item *func_chunks;
9364 static int func_chunk_cnt;
9365 static int func_chunk_alloc;
9367 static void add_func_chunk(FILE *fasm, const char *name, int line)
9369 if (func_chunk_cnt >= func_chunk_alloc) {
9370 func_chunk_alloc *= 2;
9371 func_chunks = realloc(func_chunks,
9372 func_chunk_alloc * sizeof(func_chunks[0]));
9373 my_assert_not(func_chunks, NULL);
9375 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
9376 func_chunks[func_chunk_cnt].name = strdup(name);
9377 func_chunks[func_chunk_cnt].asmln = line;
9381 static int cmp_chunks(const void *p1, const void *p2)
9383 const struct chunk_item *c1 = p1, *c2 = p2;
9384 return strcmp(c1->name, c2->name);
9387 static void scan_ahead_for_chunks(FILE *fasm)
9397 oldpos = ftell(fasm);
9400 while (my_fgets(line, sizeof(line), fasm))
9411 // get rid of random tabs
9412 for (i = 0; line[i] != 0; i++)
9413 if (line[i] == '\t')
9416 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9419 next_word(words[0], sizeof(words[0]), p);
9420 if (words[0][0] == 0)
9421 aerr("missing name for func chunk?\n");
9423 add_func_chunk(fasm, words[0], asmln);
9425 else if (IS_START(p, "; sctend"))
9431 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9432 words[wordc][0] = 0;
9433 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9434 if (*p == 0 || *p == ';') {
9440 if (wordc == 2 && IS(words[1], "ends"))
9444 fseek(fasm, oldpos, SEEK_SET);
9448 int main(int argc, char *argv[])
9450 FILE *fout, *fasm, *frlist;
9451 struct parsed_data *pd = NULL;
9453 char **rlist = NULL;
9455 int rlist_alloc = 0;
9456 int func_chunks_used = 0;
9457 int func_chunks_sorted = 0;
9458 int func_chunk_i = -1;
9459 long func_chunk_ret = 0;
9460 int func_chunk_ret_ln = 0;
9461 int scanned_ahead = 0;
9463 char words[20][256];
9464 enum opr_lenmod lmod;
9465 char *sctproto = NULL;
9467 int pending_endp = 0;
9469 int skip_code_end = 0;
9470 int skip_warned = 0;
9483 for (arg = 1; arg < argc; arg++) {
9484 if (IS(argv[arg], "-v"))
9486 else if (IS(argv[arg], "-rf"))
9487 g_allow_regfunc = 1;
9488 else if (IS(argv[arg], "-uc"))
9489 g_allow_user_icall = 1;
9490 else if (IS(argv[arg], "-wu"))
9491 g_nowarn_reguse = 1;
9492 else if (IS(argv[arg], "-m"))
9494 else if (IS(argv[arg], "-hdr"))
9495 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
9500 if (argc < arg + 3) {
9501 printf("usage:\n%s [options] <.c> <.asm> <hdr.h> [rlist]*\n"
9502 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
9504 " -hdr - header generation mode\n"
9505 " -rf - allow unannotated indirect calls\n"
9506 " -uc - allow ind. calls/refs to __usercall\n"
9507 " -m - allow multiple .text sections\n"
9508 " -wu - don't warn about bad reg use\n"
9509 "[rlist] is a file with function names to skip,"
9517 asmfn = argv[arg++];
9518 fasm = fopen(asmfn, "r");
9519 my_assert_not(fasm, NULL);
9521 hdrfn = argv[arg++];
9522 g_fhdr = fopen(hdrfn, "r");
9523 my_assert_not(g_fhdr, NULL);
9526 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9527 my_assert_not(rlist, NULL);
9528 // needs special handling..
9529 rlist[rlist_len++] = "__alloca_probe";
9531 func_chunk_alloc = 32;
9532 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9533 my_assert_not(func_chunks, NULL);
9535 memset(words, 0, sizeof(words));
9537 for (; arg < argc; arg++) {
9540 frlist = fopen(argv[arg], "r");
9541 my_assert_not(frlist, NULL);
9543 while (my_fgets(line, sizeof(line), frlist)) {
9545 if (*p == 0 || *p == ';')
9548 if (IS_START(p, "#if 0")
9549 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9553 else if (IS_START(p, "#endif"))
9560 p = next_word(words[0], sizeof(words[0]), p);
9561 if (words[0][0] == 0)
9564 if (rlist_len >= rlist_alloc) {
9565 rlist_alloc = rlist_alloc * 2 + 64;
9566 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9567 my_assert_not(rlist, NULL);
9569 rlist[rlist_len++] = strdup(words[0]);
9577 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9579 fout = fopen(argv[arg_out], "w");
9580 my_assert_not(fout, NULL);
9583 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9584 my_assert_not(g_eqs, NULL);
9586 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9587 g_label_refs[i].i = -1;
9588 g_label_refs[i].next = NULL;
9592 scan_variables(fasm, rlist, rlist_len);
9594 while (my_fgets(line, sizeof(line), fasm))
9603 // get rid of random tabs
9604 for (i = 0; line[i] != 0; i++)
9605 if (line[i] == '\t')
9610 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9611 goto do_pending_endp; // eww..
9613 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9615 static const char *attrs[] = {
9624 // parse IDA's attribute-list comment
9625 g_ida_func_attr = 0;
9628 for (; *p != 0; p = sskip(p)) {
9629 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9630 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9631 g_ida_func_attr |= 1 << i;
9632 p += strlen(attrs[i]);
9636 if (i == ARRAY_SIZE(attrs)) {
9637 anote("unparsed IDA attr: %s\n", p);
9640 if (IS(attrs[i], "fpd=")) {
9641 p = next_word(words[0], sizeof(words[0]), p);
9646 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9648 static const char *attrs[] = {
9656 // parse manual attribute-list comment
9657 g_sct_func_attr = 0;
9660 for (; *p != 0; p = sskip(p)) {
9661 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9662 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9663 g_sct_func_attr |= 1 << i;
9664 p += strlen(attrs[i]);
9671 // clear_sf=start,len (in dwords)
9672 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9673 &g_stack_clear_len, &j);
9675 // clear_regmask=<mask>
9676 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9678 // rm_regmask=<mask>
9679 ret = sscanf(p, "=%x%n", &g_regmask_rm, &j) + 1;
9681 anote("unparsed attr value: %s\n", p);
9686 else if (i == ARRAY_SIZE(attrs)) {
9687 anote("unparsed sct attr: %s\n", p);
9692 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9695 next_word(words[0], sizeof(words[0]), p);
9696 if (words[0][0] == 0)
9697 aerr("missing name for func chunk?\n");
9699 if (!scanned_ahead) {
9700 add_func_chunk(fasm, words[0], asmln);
9701 func_chunks_sorted = 0;
9704 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9706 if (func_chunk_i >= 0) {
9707 if (func_chunk_i < func_chunk_cnt
9708 && IS(func_chunks[func_chunk_i].name, g_func))
9710 // move on to next chunk
9711 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9713 aerr("seek failed for '%s' chunk #%d\n",
9714 g_func, func_chunk_i);
9715 asmln = func_chunks[func_chunk_i].asmln;
9719 if (func_chunk_ret == 0)
9720 aerr("no return from chunk?\n");
9721 fseek(fasm, func_chunk_ret, SEEK_SET);
9722 asmln = func_chunk_ret_ln;
9728 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9729 func_chunks_used = 1;
9731 if (IS_START(g_func, "sub_")) {
9732 unsigned long addr = strtoul(p, NULL, 16);
9733 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9734 if (addr > f_addr && !scanned_ahead) {
9735 //anote("scan_ahead caused by '%s', addr %lx\n",
9737 scan_ahead_for_chunks(fasm);
9739 func_chunks_sorted = 0;
9747 for (i = wordc; i < ARRAY_SIZE(words); i++)
9749 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9750 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9751 if (*p == 0 || *p == ';') {
9756 if (*p != 0 && *p != ';')
9757 aerr("too many words\n");
9759 if (skip_code_end) {
9764 // allow asm patches in comments
9766 // skip IDA's forced non-removable comment
9767 if (!IS_START(p, "; sct") && (p2 = strchr(p + 1, ';')))
9770 if (*p == ';' && IS_START(p, "; sct")) {
9771 if (IS_START(p, "; sctpatch:")) {
9773 if (*p == 0 || *p == ';')
9775 goto parse_words; // lame
9777 else if (IS_START(p, "; sctend")) {
9782 else if (g_skip_func)
9783 /* ignore remaining attrs */;
9784 else if (IS_START(p, "; sctproto:")) {
9785 sctproto = strdup(p + 11);
9787 else if (IS_START(p, "; sctskip_start")) {
9790 ops[pi].op = OPP_ABORT;
9791 ops[pi].asmln = asmln;
9797 else if (IS_START(p, "; sctskip_end")) {
9805 awarn("wordc == 0?\n");
9809 // don't care about this:
9810 if (words[0][0] == '.'
9811 || IS(words[0], "include")
9812 || IS(words[0], "assume") || IS(words[1], "segment")
9813 || IS(words[0], "align"))
9819 // do delayed endp processing to collect switch jumptables
9821 if (in_func && !g_skip_func && !end && wordc >= 2
9822 && ((words[0][0] == 'd' && words[0][2] == 0)
9823 || (words[1][0] == 'd' && words[1][2] == 0)))
9826 if (words[1][0] == 'd' && words[1][2] == 0) {
9828 if (g_func_pd_cnt >= pd_alloc) {
9829 pd_alloc = pd_alloc * 2 + 16;
9830 g_func_pd = realloc(g_func_pd,
9831 sizeof(g_func_pd[0]) * pd_alloc);
9832 my_assert_not(g_func_pd, NULL);
9834 pd = &g_func_pd[g_func_pd_cnt];
9836 memset(pd, 0, sizeof(*pd));
9837 strcpy(pd->label, words[0]);
9838 pd->type = OPT_CONST;
9839 pd->lmod = lmod_from_directive(words[1]);
9845 anote("skipping alignment byte?\n");
9848 lmod = lmod_from_directive(words[0]);
9849 if (lmod != pd->lmod)
9850 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9853 if (pd->count_alloc < pd->count + wordc) {
9854 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9855 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9856 my_assert_not(pd->d, NULL);
9858 for (; i < wordc; i++) {
9859 if (IS(words[i], "offset")) {
9860 pd->type = OPT_OFFSET;
9863 p = strchr(words[i], ',');
9866 if (pd->type == OPT_OFFSET)
9867 pd->d[pd->count].u.label = strdup(words[i]);
9869 pd->d[pd->count].u.val = parse_number(words[i], 0);
9870 pd->d[pd->count].bt_i = -1;
9876 if (in_func && !g_skip_func) {
9878 gen_hdr(g_func, pi);
9880 gen_func(fout, g_fhdr, g_func, pi);
9885 g_ida_func_attr = 0;
9886 g_sct_func_attr = 0;
9887 g_stack_clear_start = 0;
9888 g_stack_clear_len = 0;
9895 func_chunks_used = 0;
9898 memset(&ops, 0, pi * sizeof(ops[0]));
9903 for (i = 0; i < g_func_pd_cnt; i++) {
9905 if (pd->type == OPT_OFFSET) {
9906 for (j = 0; j < pd->count; j++)
9907 free(pd->d[j].u.label);
9922 if (IS(words[1], "proc")) {
9924 aerr("proc '%s' while in_func '%s'?\n",
9927 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9929 strcpy(g_func, words[0]);
9930 set_label(0, words[0]);
9935 if (IS(words[1], "endp"))
9938 aerr("endp '%s' while not in_func?\n", words[0]);
9939 if (!IS(g_func, words[0]))
9940 aerr("endp '%s' while in_func '%s'?\n",
9943 aerr("endp '%s' while skipping code\n", words[0]);
9945 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9946 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
9952 if (!g_skip_func && func_chunks_used) {
9953 // start processing chunks
9954 struct chunk_item *ci, key = { g_func, 0 };
9956 func_chunk_ret = ftell(fasm);
9957 func_chunk_ret_ln = asmln;
9958 if (!func_chunks_sorted) {
9959 qsort(func_chunks, func_chunk_cnt,
9960 sizeof(func_chunks[0]), cmp_chunks);
9961 func_chunks_sorted = 1;
9963 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9964 sizeof(func_chunks[0]), cmp_chunks);
9966 aerr("'%s' needs chunks, but none found\n", g_func);
9967 func_chunk_i = ci - func_chunks;
9968 for (; func_chunk_i > 0; func_chunk_i--)
9969 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9972 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9974 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9975 asmln = func_chunks[func_chunk_i].asmln;
9983 if (wordc == 2 && IS(words[1], "ends")) {
9987 goto do_pending_endp;
9991 // scan for next text segment
9992 while (my_fgets(line, sizeof(line), fasm)) {
9995 if (*p == 0 || *p == ';')
9998 if (strstr(p, "segment para public 'CODE' use32"))
10005 p = strchr(words[0], ':');
10007 set_label(pi, words[0]);
10011 if (!in_func || g_skip_func || skip_code) {
10012 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
10014 anote("skipping from '%s'\n", g_labels[pi]);
10017 free(g_labels[pi]);
10018 g_labels[pi] = NULL;
10022 if (wordc > 1 && IS(words[1], "="))
10025 aerr("unhandled equ, wc=%d\n", wordc);
10026 if (g_eqcnt >= eq_alloc) {
10028 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
10029 my_assert_not(g_eqs, NULL);
10032 len = strlen(words[0]);
10033 if (len > sizeof(g_eqs[0].name) - 1)
10034 aerr("equ name too long: %d\n", len);
10035 strcpy(g_eqs[g_eqcnt].name, words[0]);
10037 if (!IS(words[3], "ptr"))
10038 aerr("unhandled equ\n");
10039 if (IS(words[2], "dword"))
10040 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
10041 else if (IS(words[2], "word"))
10042 g_eqs[g_eqcnt].lmod = OPLM_WORD;
10043 else if (IS(words[2], "byte"))
10044 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
10045 else if (IS(words[2], "qword"))
10046 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
10048 aerr("bad lmod: '%s'\n", words[2]);
10050 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
10055 if (pi >= ARRAY_SIZE(ops))
10056 aerr("too many ops\n");
10058 parse_op(&ops[pi], words, wordc);
10060 ops[pi].datap = sctproto;
10075 // vim:ts=2:shiftwidth=2:expandtab