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 // exception: doesn't skip OPF_RSAVE stuff
2712 static int scan_for_pop(int i, int opcnt, int magic, int reg,
2713 int depth, int seen_noreturn, int save_level, int flags_set)
2715 struct parsed_op *po;
2720 for (; i < opcnt; i++) {
2722 if (po->cc_scratch == magic)
2723 return ret; // already checked
2724 po->cc_scratch = magic;
2726 if (po->flags & OPF_TAIL) {
2727 if (po->op == OP_CALL && po->pp != NULL && po->pp->is_noreturn) {
2728 // msvc sometimes generates stack cleanup code after
2729 // noreturn, set a flag and continue
2732 // ... but stop if there is another path to next insn -
2733 // if msvc skipped something stack tracking may mess up
2734 if (i + 1 < opcnt && g_labels[i + 1] != NULL)
2741 if (po->flags & OPF_FARG)
2743 if (po->flags & (OPF_RMD|OPF_DONE)) {
2744 if (!(po->flags & OPF_RSAVE))
2746 // reprocess, there might be another push in some "parallel"
2747 // path that took a pop what we should also take
2750 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2751 if (po->btj != NULL) {
2753 for (j = 0; j < po->btj->count; j++) {
2754 check_i(po, po->btj->d[j].bt_i);
2755 ret |= scan_for_pop(po->btj->d[j].bt_i, opcnt, magic, reg,
2756 depth, seen_noreturn, save_level, flags_set);
2758 return ret; // dead end
2763 check_i(po, po->bt_i);
2764 if (po->flags & OPF_CJMP) {
2765 ret |= scan_for_pop(po->bt_i, opcnt, magic, reg,
2766 depth, seen_noreturn, save_level, flags_set);
2768 return ret; // dead end
2777 if ((po->op == OP_POP || po->op == OP_PUSH)
2778 && po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
2783 if (po->op == OP_PUSH) {
2786 else if (po->op == OP_POP) {
2787 if (relevant && depth == 0) {
2788 if (flags_set == 0 && save_level > 0) {
2789 ret = scan_for_pop(i + 1, opcnt, magic, reg,
2790 depth, seen_noreturn, save_level - 1, flags_set);
2792 // no pop for other levels, current one must be false
2795 po->flags |= flags_set;
2803 // for noreturn, assume msvc skipped stack cleanup
2804 return seen_noreturn ? 1 : -1;
2807 // scan for 'reg' pop backwards starting from i
2808 // intended to use for register restore search, so other reg
2809 // references are considered an error
2810 static int scan_for_rsave_pop_reg(int i, int magic, int reg, int set_flags)
2812 struct parsed_op *po;
2813 struct label_ref *lr;
2816 ops[i].cc_scratch = magic;
2820 if (g_labels[i] != NULL) {
2821 lr = &g_label_refs[i];
2822 for (; lr != NULL; lr = lr->next) {
2823 check_i(&ops[i], lr->i);
2824 ret |= scan_for_rsave_pop_reg(lr->i, magic, reg, set_flags);
2828 if (i > 0 && LAST_OP(i - 1))
2836 if (ops[i].cc_scratch == magic)
2838 ops[i].cc_scratch = magic;
2841 if (po->op == OP_POP && po->operand[0].reg == reg) {
2842 if (po->flags & (OPF_RMD|OPF_DONE))
2845 po->flags |= set_flags;
2849 // this also covers the case where we reach corresponding push
2850 if ((po->regmask_dst | po->regmask_src) & (1 << reg))
2854 // nothing interesting on this path,
2855 // still return ret for something recursive calls could find
2859 static void find_reachable_exits(int i, int opcnt, int magic,
2860 int *exits, int *exit_count)
2862 struct parsed_op *po;
2865 for (; i < opcnt; i++)
2868 if (po->cc_scratch == magic)
2870 po->cc_scratch = magic;
2872 if (po->flags & OPF_TAIL) {
2873 ferr_assert(po, *exit_count < MAX_EXITS);
2874 exits[*exit_count] = i;
2879 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
2880 if (po->flags & OPF_RMD)
2883 if (po->btj != NULL) {
2884 for (j = 0; j < po->btj->count; j++) {
2885 check_i(po, po->btj->d[j].bt_i);
2886 find_reachable_exits(po->btj->d[j].bt_i, opcnt, magic,
2892 check_i(po, po->bt_i);
2893 if (po->flags & OPF_CJMP)
2894 find_reachable_exits(po->bt_i, opcnt, magic, exits, exit_count);
2902 // scan for 'reg' pop backwards starting from exits (all paths)
2903 static int scan_for_pop_ret(int i, int opcnt, int reg, int set_flags)
2905 static int exits[MAX_EXITS];
2906 static int exit_count;
2912 find_reachable_exits(i, opcnt, i + opcnt * 15, exits,
2914 ferr_assert(&ops[i], exit_count > 0);
2917 for (j = 0; j < exit_count; j++) {
2919 ret = scan_for_rsave_pop_reg(e, i + opcnt * 16 + set_flags,
2925 if (ops[e].op == OP_CALL && ops[e].pp != NULL
2926 && ops[e].pp->is_noreturn)
2928 // assume stack cleanup was skipped
2937 // scan for one or more pop of push <const>
2938 static int scan_for_pop_const_r(int i, int opcnt, int magic,
2939 int push_i, int is_probe)
2941 struct parsed_op *po;
2942 struct label_ref *lr;
2946 for (; i < opcnt; i++)
2949 if (po->cc_scratch == magic)
2950 return ret; // already checked
2951 po->cc_scratch = magic;
2953 if (po->flags & OPF_JMP) {
2954 if (po->flags & OPF_RMD)
2956 if (po->op == OP_CALL)
2959 if (po->btj != NULL) {
2960 for (j = 0; j < po->btj->count; j++) {
2961 check_i(po, po->btj->d[j].bt_i);
2962 ret |= scan_for_pop_const_r(po->btj->d[j].bt_i, opcnt, magic,
2970 check_i(po, po->bt_i);
2971 if (po->flags & OPF_CJMP) {
2972 ret |= scan_for_pop_const_r(po->bt_i, opcnt, magic, push_i,
2983 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_PUSH)
2986 if (g_labels[i] != NULL) {
2987 // all refs must be visited
2988 lr = &g_label_refs[i];
2989 for (; lr != NULL; lr = lr->next) {
2991 if (ops[lr->i].cc_scratch != magic)
2994 if (i > 0 && !LAST_OP(i - 1) && ops[i - 1].cc_scratch != magic)
2998 if (po->op == OP_POP)
3000 if (po->flags & (OPF_RMD|OPF_DONE))
3004 po->flags |= OPF_DONE;
3005 po->datap = &ops[push_i];
3014 static void scan_for_pop_const(int i, int opcnt, int magic)
3018 ret = scan_for_pop_const_r(i + 1, opcnt, magic, i, 1);
3020 ops[i].flags |= OPF_RMD | OPF_DONE;
3021 scan_for_pop_const_r(i + 1, opcnt, magic + 1, i, 0);
3025 // check if all branch targets within a marked path are also marked
3026 // note: the path checked must not be empty or end with a branch
3027 static int check_path_branches(int opcnt, int magic)
3029 struct parsed_op *po;
3032 for (i = 0; i < opcnt; i++) {
3034 if (po->cc_scratch != magic)
3037 if (po->flags & OPF_JMP) {
3038 if ((po->flags & OPF_RMD) || po->op == OP_CALL)
3041 if (po->btj != NULL) {
3042 for (j = 0; j < po->btj->count; j++) {
3043 check_i(po, po->btj->d[j].bt_i);
3044 if (ops[po->btj->d[j].bt_i].cc_scratch != magic)
3049 check_i(po, po->bt_i);
3050 if (ops[po->bt_i].cc_scratch != magic)
3052 if ((po->flags & OPF_CJMP) && ops[i + 1].cc_scratch != magic)
3060 // scan for multiple pushes for given pop
3061 static int scan_pushes_for_pop_r(int i, int magic, int pop_i,
3064 int reg = ops[pop_i].operand[0].reg;
3065 struct parsed_op *po;
3066 struct label_ref *lr;
3069 ops[i].cc_scratch = magic;
3073 if (g_labels[i] != NULL) {
3074 lr = &g_label_refs[i];
3075 for (; lr != NULL; lr = lr->next) {
3076 check_i(&ops[i], lr->i);
3077 ret |= scan_pushes_for_pop_r(lr->i, magic, pop_i, is_probe);
3081 if (i > 0 && LAST_OP(i - 1))
3089 if (ops[i].cc_scratch == magic)
3091 ops[i].cc_scratch = magic;
3094 if (po->op == OP_CALL)
3096 if ((po->flags & (OPF_TAIL|OPF_RSAVE)) || po->op == OP_POP)
3099 if (po->op == OP_PUSH)
3101 if (po->datap != NULL)
3103 if (po->operand[0].type == OPT_REG && po->operand[0].reg == reg)
3104 // leave this case for reg save/restore handlers
3108 po->flags |= OPF_PPUSH | OPF_DONE;
3109 po->datap = &ops[pop_i];
3118 static void scan_pushes_for_pop(int i, int opcnt, int *regmask_pp)
3120 int magic = i + opcnt * 14;
3123 ret = scan_pushes_for_pop_r(i, magic, i, 1);
3125 ret = check_path_branches(opcnt, magic);
3127 ops[i].flags |= OPF_PPUSH | OPF_DONE;
3128 *regmask_pp |= 1 << ops[i].operand[0].reg;
3129 scan_pushes_for_pop_r(i, magic + 1, i, 0);
3134 static void scan_propagate_df(int i, int opcnt)
3136 struct parsed_op *po = &ops[i];
3139 for (; i < opcnt; i++) {
3141 if (po->flags & OPF_DF)
3142 return; // already resolved
3143 po->flags |= OPF_DF;
3145 if (po->op == OP_CALL)
3146 ferr(po, "call with DF set?\n");
3148 if (po->flags & OPF_JMP) {
3149 if (po->btj != NULL) {
3151 for (j = 0; j < po->btj->count; j++) {
3152 check_i(po, po->btj->d[j].bt_i);
3153 scan_propagate_df(po->btj->d[j].bt_i, opcnt);
3158 if (po->flags & OPF_RMD)
3160 check_i(po, po->bt_i);
3161 if (po->flags & OPF_CJMP)
3162 scan_propagate_df(po->bt_i, opcnt);
3168 if (po->flags & OPF_TAIL)
3171 if (po->op == OP_CLD) {
3172 po->flags |= OPF_RMD | OPF_DONE;
3177 ferr(po, "missing DF clear?\n");
3180 // is operand 'opr' referenced by parsed_op 'po'?
3181 static int is_opr_referenced(const struct parsed_opr *opr,
3182 const struct parsed_op *po)
3186 if (opr->type == OPT_REG) {
3187 mask = po->regmask_dst | po->regmask_src;
3188 if (po->op == OP_CALL)
3189 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX);
3190 if ((1 << opr->reg) & mask)
3196 for (i = 0; i < po->operand_cnt; i++)
3197 if (IS(po->operand[0].name, opr->name))
3203 // is operand 'opr' read by parsed_op 'po'?
3204 static int is_opr_read(const struct parsed_opr *opr,
3205 const struct parsed_op *po)
3207 if (opr->type == OPT_REG) {
3208 if (po->regmask_src & (1 << opr->reg))
3218 // is operand 'opr' modified by parsed_op 'po'?
3219 static int is_opr_modified(const struct parsed_opr *opr,
3220 const struct parsed_op *po)
3224 if (opr->type == OPT_REG) {
3225 if (po->op == OP_CALL) {
3226 mask = po->regmask_dst;
3227 mask |= (1 << xAX) | (1 << xCX) | (1 << xDX); // ?
3228 if (mask & (1 << opr->reg))
3234 if (po->regmask_dst & (1 << opr->reg))
3240 return IS(po->operand[0].name, opr->name);
3243 // is any operand of parsed_op 'po_test' modified by parsed_op 'po'?
3244 static int is_any_opr_modified(const struct parsed_op *po_test,
3245 const struct parsed_op *po, int c_mode)
3250 if ((po->flags & OPF_RMD) || !(po->flags & OPF_DATA))
3253 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3256 if ((po_test->regmask_src | po_test->regmask_dst) & po->regmask_dst)
3259 // in reality, it can wreck any register, but in decompiled C
3260 // version it can only overwrite eax or edx:eax
3261 mask = (1 << xAX) | (1 << xDX);
3265 if (po->op == OP_CALL
3266 && ((po_test->regmask_src | po_test->regmask_dst) & mask))
3269 for (i = 0; i < po_test->operand_cnt; i++)
3270 if (IS(po_test->operand[i].name, po->operand[0].name))
3276 // scan for any po_test operand modification in range given
3277 static int scan_for_mod(struct parsed_op *po_test, int i, int opcnt,
3280 if (po_test->operand_cnt == 1 && po_test->operand[0].type == OPT_CONST)
3283 for (; i < opcnt; i++) {
3284 if (is_any_opr_modified(po_test, &ops[i], c_mode))
3291 // scan for po_test operand[0] modification in range given
3292 static int scan_for_mod_opr0(struct parsed_op *po_test,
3295 for (; i < opcnt; i++) {
3296 if (is_opr_modified(&po_test->operand[0], &ops[i]))
3303 static int try_resolve_const(int i, const struct parsed_opr *opr,
3304 int magic, unsigned int *val);
3306 static int scan_for_flag_set(int i, int opcnt, int magic,
3307 int *branched, int *setters, int *setter_cnt)
3309 struct label_ref *lr;
3313 if (ops[i].cc_scratch == magic) {
3314 // is this a problem?
3315 //ferr(&ops[i], "%s looped\n", __func__);
3318 ops[i].cc_scratch = magic;
3320 if (g_labels[i] != NULL) {
3323 lr = &g_label_refs[i];
3324 for (; lr->next; lr = lr->next) {
3325 check_i(&ops[i], lr->i);
3326 ret = scan_for_flag_set(lr->i, opcnt, magic,
3327 branched, setters, setter_cnt);
3332 check_i(&ops[i], lr->i);
3333 if (i > 0 && LAST_OP(i - 1)) {
3337 ret = scan_for_flag_set(lr->i, opcnt, magic,
3338 branched, setters, setter_cnt);
3344 if (ops[i].flags & OPF_FLAGS) {
3345 setters[*setter_cnt] = i;
3348 if (ops[i].flags & OPF_REP) {
3349 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xCX);
3352 ret = try_resolve_const(i, &opr, i + opcnt * 7, &uval);
3353 if (ret != 1 || uval == 0) {
3354 // can't treat it as full setter because of ecx=0 case,
3355 // also disallow delayed compare
3364 if ((ops[i].flags & (OPF_JMP|OPF_CJMP)) == OPF_JMP)
3371 // scan back for cdq, if anything modifies edx, fail
3372 static int scan_for_cdq_edx(int i)
3375 if (g_labels[i] != NULL) {
3376 if (g_label_refs[i].next != NULL)
3378 if (i > 0 && LAST_OP(i - 1)) {
3379 i = g_label_refs[i].i;
3386 if (ops[i].op == OP_CDQ)
3389 if (ops[i].regmask_dst & (1 << xDX))
3396 static int scan_for_reg_clear(int i, int reg)
3399 if (g_labels[i] != NULL) {
3400 if (g_label_refs[i].next != NULL)
3402 if (i > 0 && LAST_OP(i - 1)) {
3403 i = g_label_refs[i].i;
3410 if (ops[i].op == OP_XOR
3411 && ops[i].operand[0].lmod == OPLM_DWORD
3412 && ops[i].operand[0].reg == ops[i].operand[1].reg
3413 && ops[i].operand[0].reg == reg)
3416 if (ops[i].regmask_dst & (1 << reg))
3423 static void patch_esp_adjust(struct parsed_op *po, int adj)
3425 ferr_assert(po, po->op == OP_ADD);
3426 ferr_assert(po, IS(opr_name(po, 0), "esp"));
3427 ferr_assert(po, po->operand[1].type == OPT_CONST);
3429 // this is a bit of a hack, but deals with use of
3430 // single adj for multiple calls
3431 po->operand[1].val -= adj;
3432 po->flags |= OPF_RMD;
3433 if (po->operand[1].val == 0)
3434 po->flags |= OPF_DONE;
3435 ferr_assert(po, (int)po->operand[1].val >= 0);
3438 // scan for positive, constant esp adjust
3439 // multipath case is preliminary
3440 static int scan_for_esp_adjust(int i, int opcnt,
3441 int adj_expect, int *adj, int *is_multipath, int do_update)
3443 int adj_expect_unknown = 0;
3444 struct parsed_op *po;
3448 *adj = *is_multipath = 0;
3449 if (adj_expect < 0) {
3450 adj_expect_unknown = 1;
3451 adj_expect = 32 * 4; // enough?
3454 for (; i < opcnt && *adj < adj_expect; i++) {
3455 if (g_labels[i] != NULL)
3459 if (po->flags & OPF_DONE)
3462 if (po->op == OP_ADD && po->operand[0].reg == xSP) {
3463 if (po->operand[1].type != OPT_CONST)
3464 ferr(&ops[i], "non-const esp adjust?\n");
3465 *adj += po->operand[1].val;
3467 ferr(&ops[i], "unaligned esp adjust: %x\n", *adj);
3470 patch_esp_adjust(po, adj_expect);
3472 po->flags |= OPF_RMD;
3476 else if (po->op == OP_PUSH) {
3477 //if (first_pop == -1)
3478 // first_pop = -2; // none
3479 *adj -= lmod_bytes(po, po->operand[0].lmod);
3481 else if (po->op == OP_POP) {
3482 if (!(po->flags & OPF_DONE)) {
3483 // seems like msvc only uses 'pop ecx' for stack realignment..
3484 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xCX)
3486 if (first_pop == -1 && *adj >= 0)
3489 if (do_update && *adj >= 0) {
3490 po->flags |= OPF_RMD;
3492 po->flags |= OPF_DONE | OPF_NOREGS;
3495 *adj += lmod_bytes(po, po->operand[0].lmod);
3496 if (*adj > adj_best)
3499 else if (po->flags & (OPF_JMP|OPF_TAIL)) {
3500 if (po->op == OP_JMP && po->btj == NULL) {
3506 if (po->op != OP_CALL)
3508 if (po->operand[0].type != OPT_LABEL)
3510 if (po->pp != NULL && po->pp->is_stdcall)
3512 if (adj_expect_unknown && first_pop >= 0)
3514 // assume it's another cdecl call
3518 if (first_pop >= 0) {
3519 // probably only 'pop ecx' was used
3527 static void scan_fwd_set_flags(int i, int opcnt, int magic, int flags)
3529 struct parsed_op *po;
3533 ferr(ops, "%s: followed bad branch?\n", __func__);
3535 for (; i < opcnt; i++) {
3537 if (po->cc_scratch == magic)
3539 po->cc_scratch = magic;
3542 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
3543 if (po->btj != NULL) {
3545 for (j = 0; j < po->btj->count; j++)
3546 scan_fwd_set_flags(po->btj->d[j].bt_i, opcnt, magic, flags);
3550 scan_fwd_set_flags(po->bt_i, opcnt, magic, flags);
3551 if (!(po->flags & OPF_CJMP))
3554 if (po->flags & OPF_TAIL)
3559 static const struct parsed_proto *try_recover_pp(
3560 struct parsed_op *po, const struct parsed_opr *opr,
3561 int is_call, int *search_instead)
3563 const struct parsed_proto *pp = NULL;
3567 if (po->pp != NULL && (po->flags & OPF_DATA)) {
3568 // hint given in asm
3572 // maybe an arg of g_func?
3573 if (opr->type == OPT_REGMEM && is_stack_access(po, opr))
3575 char ofs_reg[16] = { 0, };
3576 int arg, arg_s, arg_i;
3583 parse_stack_access(po, opr->name, ofs_reg,
3584 &offset, &stack_ra, NULL, 0);
3585 if (ofs_reg[0] != 0)
3586 ferr(po, "offset reg on arg access?\n");
3587 if (offset <= stack_ra) {
3588 // search who set the stack var instead
3589 if (search_instead != NULL)
3590 *search_instead = 1;
3594 arg_i = (offset - stack_ra - 4) / 4;
3595 for (arg = arg_s = 0; arg < g_func_pp->argc; arg++) {
3596 if (g_func_pp->arg[arg].reg != NULL)
3602 if (arg == g_func_pp->argc)
3603 ferr(po, "stack arg %d not in prototype?\n", arg_i);
3605 pp = g_func_pp->arg[arg].pp;
3608 ferr(po, "icall arg: arg%d has no pp\n", arg + 1);
3609 check_func_pp(po, pp, "icall arg");
3612 else if (opr->type == OPT_REGMEM && strchr(opr->name + 1, '[')) {
3614 p = strchr(opr->name + 1, '[');
3615 memcpy(buf, opr->name, p - opr->name);
3616 buf[p - opr->name] = 0;
3617 pp = proto_parse(g_fhdr, buf, g_quiet_pp);
3619 else if (opr->type == OPT_OFFSET || opr->type == OPT_LABEL) {
3620 pp = proto_parse(g_fhdr, opr->name, g_quiet_pp);
3623 ferr(po, "proto_parse failed for icall to '%s'\n", opr->name);
3626 check_func_pp(po, pp, "reg-fptr ref");
3632 static void scan_for_call_type(int i, const struct parsed_opr *opr,
3633 int magic, int is_call_op, const struct parsed_proto **pp_found,
3634 int *pp_i, int *multi)
3636 const struct parsed_proto *pp = NULL;
3637 struct parsed_op *po;
3638 struct label_ref *lr;
3640 ops[i].cc_scratch = magic;
3643 if (g_labels[i] != NULL) {
3644 lr = &g_label_refs[i];
3645 for (; lr != NULL; lr = lr->next) {
3646 check_i(&ops[i], lr->i);
3647 scan_for_call_type(lr->i, opr, magic, is_call_op,
3648 pp_found, pp_i, multi);
3650 if (i > 0 && LAST_OP(i - 1))
3658 if (ops[i].cc_scratch == magic)
3660 ops[i].cc_scratch = magic;
3662 if (!(ops[i].flags & OPF_DATA))
3664 if (!is_opr_modified(opr, &ops[i]))
3666 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3667 // most probably trashed by some processing
3672 opr = &ops[i].operand[1];
3673 if (opr->type != OPT_REG)
3677 po = (i >= 0) ? &ops[i] : ops;
3680 // reached the top - can only be an arg-reg
3681 if (opr->type != OPT_REG || g_func_pp == NULL)
3684 for (i = 0; i < g_func_pp->argc; i++) {
3685 if (g_func_pp->arg[i].reg == NULL)
3687 if (IS(opr->name, g_func_pp->arg[i].reg))
3690 if (i == g_func_pp->argc)
3692 pp = g_func_pp->arg[i].pp;
3695 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3696 i + 1, g_func_pp->arg[i].reg);
3699 check_func_pp(po, pp, "icall reg-arg");
3702 pp = try_recover_pp(po, opr, is_call_op, NULL);
3704 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3705 if (pp_cmp_func(*pp_found, pp)) {
3706 if (pp_i != NULL && *pp_i != -1)
3707 fnote(&ops[*pp_i], "(other ref)\n");
3708 ferr(po, "icall: parsed_proto mismatch\n");
3720 static void add_label_ref(struct label_ref *lr, int op_i)
3722 struct label_ref *lr_new;
3729 lr_new = calloc(1, sizeof(*lr_new));
3731 lr_new->next = lr->next;
3735 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3737 struct parsed_op *po = &ops[i];
3738 struct parsed_data *pd;
3739 char label[NAMELEN], *p;
3742 p = strchr(po->operand[0].name, '[');
3746 len = p - po->operand[0].name;
3747 strncpy(label, po->operand[0].name, len);
3750 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3751 if (IS(g_func_pd[j].label, label)) {
3757 //ferr(po, "label '%s' not parsed?\n", label);
3760 if (pd->type != OPT_OFFSET)
3761 ferr(po, "label '%s' with non-offset data?\n", label);
3763 // find all labels, link
3764 for (j = 0; j < pd->count; j++) {
3765 for (l = 0; l < opcnt; l++) {
3766 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3767 add_label_ref(&g_label_refs[l], i);
3777 static void clear_labels(int count)
3781 for (i = 0; i < count; i++) {
3782 if (g_labels[i] != NULL) {
3789 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3794 for (i = 0; i < pp->argc; i++) {
3795 if (pp->arg[i].reg != NULL) {
3796 reg = char_array_i(regs_r32,
3797 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3799 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3800 pp->arg[i].reg, pp->name);
3801 regmask |= 1 << reg;
3808 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3813 if (pp->has_retreg) {
3814 for (i = 0; i < pp->argc; i++) {
3815 if (pp->arg[i].type.is_retreg) {
3816 reg = char_array_i(regs_r32,
3817 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3818 ferr_assert(ops, reg >= 0);
3819 regmask |= 1 << reg;
3824 if (strstr(pp->ret_type.name, "int64"))
3825 return regmask | (1 << xAX) | (1 << xDX);
3826 if (IS(pp->ret_type.name, "float")
3827 || IS(pp->ret_type.name, "double"))
3829 return regmask | mxST0;
3831 if (strcasecmp(pp->ret_type.name, "void") == 0)
3834 return regmask | mxAX;
3837 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3839 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3840 && memcmp(po1->operand, po2->operand,
3841 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3844 static void resolve_branches_parse_calls(int opcnt)
3846 static const struct {
3850 unsigned int regmask_src;
3851 unsigned int regmask_dst;
3853 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3854 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3855 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3856 // more precise? Wine gets away with just __ftol handler
3857 { "__ftol2", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3858 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3860 const struct parsed_proto *pp_c;
3861 struct parsed_proto *pp;
3862 struct parsed_data *pd;
3863 struct parsed_op *po;
3864 const char *tmpname;
3869 for (i = 0; i < opcnt; i++)
3875 if (po->datap != NULL) {
3876 pp = calloc(1, sizeof(*pp));
3877 my_assert_not(pp, NULL);
3879 ret = parse_protostr(po->datap, pp);
3881 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3887 if (po->op == OP_CALL) {
3892 else if (po->operand[0].type == OPT_LABEL)
3894 tmpname = opr_name(po, 0);
3895 if (IS_START(tmpname, "loc_")) {
3897 ferr(po, "call to loc_*\n");
3898 // eliminate_seh() must take care of it
3901 if (IS(tmpname, "__alloca_probe"))
3903 if (IS(tmpname, "__SEH_prolog")) {
3904 ferr_assert(po, g_seh_found == 0);
3908 if (IS(tmpname, "__SEH_epilog"))
3911 // convert some calls to pseudo-ops
3912 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3913 if (!IS(tmpname, pseudo_ops[l].name))
3916 po->op = pseudo_ops[l].op;
3917 po->operand_cnt = 0;
3918 po->regmask_src = pseudo_ops[l].regmask_src;
3919 po->regmask_dst = pseudo_ops[l].regmask_dst;
3920 po->flags = pseudo_ops[l].flags;
3921 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3924 if (l < ARRAY_SIZE(pseudo_ops))
3927 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3928 if (!g_header_mode && pp_c == NULL)
3929 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3932 pp = proto_clone(pp_c);
3933 my_assert_not(pp, NULL);
3939 check_func_pp(po, pp, "fptr var call");
3940 if (pp->is_noreturn) {
3941 po->flags |= OPF_TAIL;
3942 po->flags &= ~OPF_ATAIL; // most likely...
3949 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3952 if (po->operand[0].type == OPT_REGMEM) {
3953 pd = try_resolve_jumptab(i, opcnt);
3961 for (l = 0; l < opcnt; l++) {
3962 if (g_labels[l] != NULL
3963 && IS(po->operand[0].name, g_labels[l]))
3965 if (l == i + 1 && po->op == OP_JMP) {
3966 // yet another alignment type...
3967 po->flags |= OPF_RMD | OPF_DONE;
3968 po->flags &= ~OPF_JMP;
3972 add_label_ref(&g_label_refs[l], i);
3978 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3981 if (po->operand[0].type == OPT_LABEL)
3985 ferr(po, "unhandled branch\n");
3989 po->flags |= OPF_TAIL;
3990 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3991 if (prev_op == OP_POP)
3992 po->flags |= OPF_ATAIL;
3993 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3994 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3996 po->flags |= OPF_ATAIL;
4002 static int resolve_origin(int i, const struct parsed_opr *opr,
4003 int magic, int *op_i, int *is_caller);
4004 static void set_label(int i, const char *name);
4006 static void eliminate_seh_writes(int opcnt)
4008 const struct parsed_opr *opr;
4013 // assume all sf writes above g_seh_size to be seh related
4014 // (probably unsafe but oh well)
4015 for (i = 0; i < opcnt; i++) {
4016 if (ops[i].op != OP_MOV)
4018 opr = &ops[i].operand[0];
4019 if (opr->type != OPT_REGMEM)
4021 if (!is_stack_access(&ops[i], opr))
4025 parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
4027 if (offset < 0 && offset >= -g_seh_size)
4028 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4032 static void eliminate_seh_finally(int opcnt)
4034 const char *target_name = NULL;
4035 const char *return_name = NULL;
4036 int exits[MAX_EXITS];
4044 for (i = 0; i < opcnt; i++) {
4045 if (ops[i].op != OP_CALL)
4047 if (!IS_START(opr_name(&ops[i], 0), "loc_"))
4049 if (target_name != NULL)
4050 ferr(&ops[i], "multiple finally calls? (last was %s)\n",
4052 target_name = opr_name(&ops[i], 0);
4055 if (g_labels[i + 1] == NULL)
4056 set_label(i + 1, "seh_fin_done");
4057 return_name = g_labels[i + 1];
4065 // find finally code (bt_i is not set because it's call)
4066 for (i = 0; i < opcnt; i++) {
4067 if (g_labels[i] == NULL)
4069 if (!IS(g_labels[i], target_name))
4072 ferr_assert(&ops[i], target_i == -1);
4075 ferr_assert(&ops[0], target_i != -1);
4077 find_reachable_exits(target_i, opcnt, target_i + opcnt * 24,
4078 exits, &exit_count);
4079 ferr_assert(&ops[target_i], exit_count == 1);
4080 ferr_assert(&ops[target_i], ops[exits[0]].op == OP_RET);
4083 // convert to jumps, link
4084 ops[call_i].op = OP_JMP;
4085 ops[call_i].bt_i = target_i;
4086 add_label_ref(&g_label_refs[target_i], call_i);
4088 ops[tgend_i].op = OP_JMP;
4089 ops[tgend_i].flags &= ~OPF_TAIL;
4090 ops[tgend_i].flags |= OPF_JMP;
4091 ops[tgend_i].bt_i = return_i;
4092 ops[tgend_i].operand_cnt = 1;
4093 ops[tgend_i].operand[0].type = OPT_LABEL;
4094 snprintf(ops[tgend_i].operand[0].name, NAMELEN, "%s", return_name);
4095 add_label_ref(&g_label_refs[return_i], tgend_i);
4097 // rm seh finally entry code
4098 for (i = target_i - 1; i >= 0; i--) {
4099 if (g_labels[i] != NULL && g_label_refs[i].i != -1)
4101 if (ops[i].flags & OPF_CJMP)
4103 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4106 for (i = target_i - 1; i >= 0; i--) {
4107 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4109 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4113 static void eliminate_seh(int opcnt)
4117 for (i = 0; i < opcnt; i++) {
4118 if (ops[i].op != OP_MOV)
4120 if (ops[i].operand[0].segment != SEG_FS)
4122 if (!IS(opr_name(&ops[i], 0), "0"))
4125 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4126 if (ops[i].operand[1].reg == xSP) {
4127 for (j = i - 1; j >= 0; j--) {
4128 if (ops[j].op != OP_PUSH)
4130 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4132 if (ops[j].operand[0].val == ~0)
4134 if (ops[j].operand[0].type == OPT_REG) {
4136 ret = resolve_origin(j, &ops[j].operand[0],
4137 j + opcnt * 22, &k, NULL);
4139 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4143 ferr(ops, "missing seh terminator\n");
4147 ret = resolve_origin(i, &ops[i].operand[1],
4148 i + opcnt * 23, &k, NULL);
4150 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4154 eliminate_seh_writes(opcnt);
4155 eliminate_seh_finally(opcnt);
4158 static void eliminate_seh_calls(int opcnt)
4160 int epilog_found = 0;
4167 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4168 && ops[i].operand[0].type == OPT_CONST);
4169 g_stack_fsz = g_seh_size + ops[i].operand[0].val;
4170 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4173 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4174 && ops[i].operand[0].type == OPT_OFFSET);
4175 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4178 ferr_assert(&ops[i], ops[i].op == OP_CALL
4179 && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
4180 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4182 for (i++; i < opcnt; i++) {
4183 if (ops[i].op != OP_CALL)
4185 if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
4188 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4191 ferr_assert(ops, epilog_found);
4193 eliminate_seh_writes(opcnt);
4194 eliminate_seh_finally(opcnt);
4197 // check for prologue of many pushes and epilogue with pops
4198 static void check_simple_sequence(int opcnt, int *fsz)
4207 for (i = 0; i < opcnt && i < ARRAY_SIZE(seq); i++) {
4208 if (ops[i].op != OP_PUSH || ops[i].operand[0].type != OPT_REG)
4210 reg = ops[i].operand[0].reg;
4211 if (reg != xBX && reg != xSI && reg != xDI && reg != xBP)
4213 for (j = 0; j < i; j++)
4217 // probably something else is going on here
4225 for (; i < opcnt && seq_len > 0; i++) {
4226 if (!(ops[i].flags & OPF_TAIL))
4229 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4230 if (ops[j].op != OP_POP || ops[j].operand[0].type != OPT_REG)
4232 if (ops[j].operand[0].reg != seq[seq_p])
4236 found = seq_len = seq_p;
4241 for (i = 0; i < seq_len; i++)
4242 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4244 for (; i < opcnt && seq_len > 0; i++) {
4245 if (!(ops[i].flags & OPF_TAIL))
4248 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4249 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4254 // unlike pushes after sub esp,
4255 // IDA treats pushes like this as part of var area
4256 *fsz += seq_len * 4;
4259 static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4264 for (; i < opcnt; i++)
4265 if (!(ops[i].flags & OPF_DONE))
4268 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4269 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4275 for (; i < opcnt; i++) {
4276 if (i > 0 && g_labels[i] != NULL)
4278 if (ops[i].flags & (OPF_JMP|OPF_TAIL))
4280 if (ops[i].flags & OPF_DONE)
4282 if (ops[i].op == OP_PUSH)
4284 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4285 && ops[i].operand[1].type == OPT_CONST)
4287 g_stack_fsz += opr_const(&ops[i], 1);
4288 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4293 if (ops[i].op == OP_LEA && ops[i].operand[0].reg == xSP
4294 && ops[i].operand[1].type == OPT_REGMEM
4295 && IS_START(ops[i].operand[1].name, "esp-"))
4297 name = ops[i].operand[1].name;
4298 ret = sscanf(name, "esp-%x%n", &j, &len);
4299 ferr_assert(&ops[i], ret == 1 && len == strlen(name));
4301 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4306 if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4307 && ops[i].operand[1].type == OPT_CONST)
4309 for (j = i + 1; j < opcnt; j++)
4310 if (!(ops[j].flags & OPF_DONE))
4312 if (ops[j].op == OP_CALL
4313 && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4315 g_stack_fsz += opr_const(&ops[i], 1);
4316 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4317 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4328 static void scan_prologue_epilogue(int opcnt, int *stack_align)
4330 int ecx_push = 0, esp_sub = 0, pusha = 0;
4331 int sandard_epilogue;
4332 int found, ret, len;
4336 if (g_seh_found == 2) {
4337 eliminate_seh_calls(opcnt);
4341 eliminate_seh(opcnt);
4342 // ida treats seh as part of sf
4343 g_stack_fsz = g_seh_size;
4347 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4348 && ops[1].op == OP_MOV
4349 && IS(opr_name(&ops[1], 0), "ebp")
4350 && IS(opr_name(&ops[1], 1), "esp"))
4353 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4354 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4356 for (i = 2; i < opcnt; i++)
4357 if (!(ops[i].flags & OPF_DONE))
4360 if (ops[i].op == OP_PUSHA) {
4361 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4366 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4367 && ops[i].operand[1].type == OPT_CONST)
4369 l = ops[i].operand[1].val;
4371 if (j == -1 || (l >> j) != -1)
4372 ferr(&ops[i], "unhandled esp align: %x\n", l);
4373 if (stack_align != NULL)
4374 *stack_align = 1 << j;
4375 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4379 i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4383 for (; i < opcnt; i++)
4384 if (ops[i].flags & OPF_TAIL)
4387 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4388 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4394 sandard_epilogue = 0;
4395 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4397 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4398 // the standard epilogue is sometimes even used without a sf
4399 if (ops[j - 1].op == OP_MOV
4400 && IS(opr_name(&ops[j - 1], 0), "esp")
4401 && IS(opr_name(&ops[j - 1], 1), "ebp"))
4402 sandard_epilogue = 1;
4404 else if (ops[j].op == OP_LEAVE)
4406 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4407 sandard_epilogue = 1;
4409 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4410 && ops[i].pp->is_noreturn)
4412 // on noreturn, msvc sometimes cleans stack, sometimes not
4417 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4418 ferr(&ops[j], "'pop ebp' expected\n");
4420 if (g_stack_fsz != 0 || sandard_epilogue) {
4421 if (ops[j].op == OP_LEAVE)
4423 else if (sandard_epilogue) // mov esp, ebp
4425 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4428 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4430 ferr(&ops[j], "esp restore expected\n");
4433 if (ecx_push && j >= 0 && ops[j].op == OP_POP
4434 && IS(opr_name(&ops[j], 0), "ecx"))
4436 ferr(&ops[j], "unexpected ecx pop\n");
4441 if (ops[j].op == OP_POPA)
4442 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4444 ferr(&ops[j], "popa expected\n");
4449 } while (i < opcnt);
4452 ferr(ops, "missing ebp epilogue\n");
4457 check_simple_sequence(opcnt, &push_fsz);
4458 i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4460 if (ecx_push && !esp_sub) {
4461 // could actually be args for a call..
4462 for (; i < opcnt; i++)
4463 if (ops[i].op != OP_PUSH)
4466 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4467 const struct parsed_proto *pp;
4468 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4469 j = pp ? pp->argc_stack : 0;
4470 while (i > 0 && j > 0) {
4472 if (ops[i].op == OP_PUSH) {
4473 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4478 ferr(&ops[i], "unhandled prologue\n");
4482 g_stack_fsz = g_seh_size;
4483 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4484 if (!(ops[i].flags & OPF_RMD))
4494 if (ecx_push || esp_sub)
4499 for (; i < opcnt; i++)
4500 if (ops[i].flags & OPF_TAIL)
4504 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4505 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4510 else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4511 // skip arg updates for arg-reuse tailcall
4512 for (; j >= 0; j--) {
4513 if (ops[j].op != OP_MOV)
4515 if (ops[j].operand[0].type == OPT_REGMEM
4516 && strstr(ops[j].operand[0].name, "arg_") != NULL)
4518 if (ops[j].operand[0].type == OPT_REG)
4519 continue; // assume arg-reg mov
4524 for (; j >= 0; j--) {
4525 if ((ops[j].flags & (OPF_RMD | OPF_DONE | OPF_NOREGS)) !=
4526 (OPF_RMD | OPF_DONE | OPF_NOREGS))
4530 if (ecx_push > 0 && !esp_sub) {
4531 for (l = 0; l < ecx_push && j >= 0; l++) {
4532 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4534 else if (ops[j].op == OP_ADD
4535 && IS(opr_name(&ops[j], 0), "esp")
4536 && ops[j].operand[1].type == OPT_CONST)
4539 l += ops[j].operand[1].val / 4 - 1;
4544 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4547 if (l != ecx_push) {
4548 if (i < opcnt && ops[i].op == OP_CALL
4549 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4551 // noreturn tailcall with no epilogue
4556 ferr(&ops[j], "epilogue scan failed\n");
4563 if (ops[j].op == OP_ADD
4564 && IS(opr_name(&ops[j], 0), "esp")
4565 && ops[j].operand[1].type == OPT_CONST)
4567 if (ops[j].operand[1].val < g_stack_fsz)
4568 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4570 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4571 if (ops[j].operand[1].val == 0)
4572 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4575 else if (ops[j].op == OP_LEA && ops[j].operand[0].reg == xSP
4576 && ops[j].operand[1].type == OPT_REGMEM
4577 && IS_START(ops[j].operand[1].name, "esp+"))
4579 const char *name = ops[j].operand[1].name;
4580 ret = sscanf(name, "esp+%x%n", &l, &len);
4581 ferr_assert(&ops[j], ret == 1 && len == strlen(name));
4582 ferr_assert(&ops[j], l <= g_stack_fsz);
4583 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4586 else if (i < opcnt && ops[i].op == OP_CALL
4587 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4589 // noreturn tailcall with no epilogue
4593 ferr(&ops[j], "'add esp' expected\n");
4597 } while (i < opcnt);
4600 ferr(ops, "missing esp epilogue\n");
4603 if (g_stack_fsz != 0)
4604 // see check_simple_sequence
4605 g_stack_fsz += push_fsz;
4608 // find an instruction that changed opr before i op
4609 // *op_i must be set to -1 by the caller
4610 // *is_caller is set to 1 if one source is determined to be g_func arg
4611 // returns 1 if found, *op_i is then set to origin
4612 // returns -1 if multiple origins are found
4613 static int resolve_origin(int i, const struct parsed_opr *opr,
4614 int magic, int *op_i, int *is_caller)
4616 struct label_ref *lr;
4620 if (g_labels[i] != NULL) {
4621 lr = &g_label_refs[i];
4622 for (; lr != NULL; lr = lr->next) {
4623 check_i(&ops[i], lr->i);
4624 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4626 if (i > 0 && LAST_OP(i - 1))
4632 if (is_caller != NULL)
4637 if (ops[i].cc_scratch == magic)
4639 ops[i].cc_scratch = magic;
4641 if (!(ops[i].flags & OPF_DATA))
4643 if (!is_opr_modified(opr, &ops[i]))
4647 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4658 static int resolve_origin_reg(int i, int reg, int magic, int *op_i,
4661 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, reg);
4664 if (is_caller != NULL)
4666 return resolve_origin(i, &opr, magic, op_i, is_caller);
4669 // find an instruction that previously referenced opr
4670 // if multiple results are found - fail
4671 // *op_i must be set to -1 by the caller
4672 // returns 1 if found, *op_i is then set to referencer insn
4673 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4674 int magic, int *op_i)
4676 struct label_ref *lr;
4680 if (g_labels[i] != NULL) {
4681 lr = &g_label_refs[i];
4682 for (; lr != NULL; lr = lr->next) {
4683 check_i(&ops[i], lr->i);
4684 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4686 if (i > 0 && LAST_OP(i - 1))
4694 if (ops[i].cc_scratch == magic)
4696 ops[i].cc_scratch = magic;
4698 if (!is_opr_referenced(opr, &ops[i]))
4709 // adjust datap of all reachable 'op' insns when moving back
4710 // returns 1 if at least 1 op was found
4711 // returns -1 if path without an op was found
4712 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4714 struct label_ref *lr;
4717 if (ops[i].cc_scratch == magic)
4719 ops[i].cc_scratch = magic;
4722 if (g_labels[i] != NULL) {
4723 lr = &g_label_refs[i];
4724 for (; lr != NULL; lr = lr->next) {
4725 check_i(&ops[i], lr->i);
4726 ret |= adjust_prev_op(lr->i, op, magic, datap);
4728 if (i > 0 && LAST_OP(i - 1))
4736 if (ops[i].cc_scratch == magic)
4738 ops[i].cc_scratch = magic;
4740 if (ops[i].op != op)
4743 ops[i].datap = datap;
4748 // find next instruction that reads opr
4749 // *op_i must be set to -1 by the caller
4750 // on return, *op_i is set to first referencer insn
4751 // returns 1 if exactly 1 referencer is found
4752 static int find_next_read(int i, int opcnt,
4753 const struct parsed_opr *opr, int magic, int *op_i)
4755 struct parsed_op *po;
4758 for (; i < opcnt; i++)
4760 if (ops[i].cc_scratch == magic)
4762 ops[i].cc_scratch = magic;
4765 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4766 if (po->btj != NULL) {
4768 for (j = 0; j < po->btj->count; j++) {
4769 check_i(po, po->btj->d[j].bt_i);
4770 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4776 if (po->flags & OPF_RMD)
4778 check_i(po, po->bt_i);
4779 if (po->flags & OPF_CJMP) {
4780 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4789 if (!is_opr_read(opr, po)) {
4791 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4792 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4794 full_opr = po->operand[0].lmod >= opr->lmod;
4796 if (is_opr_modified(opr, po) && full_opr) {
4800 if (po->flags & OPF_TAIL)
4815 static int find_next_read_reg(int i, int opcnt, int reg,
4816 enum opr_lenmod lmod, int magic, int *op_i)
4818 struct parsed_opr opr = OPR_INIT(OPT_REG, lmod, reg);
4821 return find_next_read(i, opcnt, &opr, magic, op_i);
4824 // find next instruction that reads opr
4825 // *op_i must be set to -1 by the caller
4826 // on return, *op_i is set to first flag user insn
4827 // returns 1 if exactly 1 flag user is found
4828 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4830 struct parsed_op *po;
4833 for (; i < opcnt; i++)
4835 if (ops[i].cc_scratch == magic)
4837 ops[i].cc_scratch = magic;
4840 if (po->op == OP_CALL)
4842 if (po->flags & OPF_JMP) {
4843 if (po->btj != NULL) {
4845 for (j = 0; j < po->btj->count; j++) {
4846 check_i(po, po->btj->d[j].bt_i);
4847 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4853 if (po->flags & OPF_RMD)
4855 check_i(po, po->bt_i);
4856 if (po->flags & OPF_CJMP)
4863 if (!(po->flags & OPF_CC)) {
4864 if (po->flags & OPF_FLAGS)
4867 if (po->flags & OPF_TAIL)
4883 static int try_resolve_const(int i, const struct parsed_opr *opr,
4884 int magic, unsigned int *val)
4889 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4892 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4895 *val = ops[i].operand[1].val;
4902 static int resolve_used_bits(int i, int opcnt, int reg,
4903 int *mask, int *is_z_check)
4905 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4909 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4913 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4915 fnote(&ops[j], "(first read)\n");
4916 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4919 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4920 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4922 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4923 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4925 *mask = ops[j].operand[1].val;
4926 if (ops[j].operand[0].lmod == OPLM_BYTE
4927 && ops[j].operand[0].name[1] == 'h')
4931 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4934 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4936 *is_z_check = ops[k].pfo == PFO_Z;
4941 static const struct parsed_proto *resolve_deref(int i, int magic,
4942 const struct parsed_opr *opr, int level)
4944 const struct parsed_proto *pp = NULL;
4945 int from_caller = 0;
4954 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4955 if (ret != 2 || len != strlen(opr->name)) {
4956 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4957 if (ret != 1 || len != strlen(opr->name))
4961 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4965 ret = resolve_origin_reg(i, reg, i + magic, &j, NULL);
4969 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4970 && strlen(ops[j].operand[1].name) == 3
4971 && ops[j].operand[0].lmod == OPLM_DWORD
4972 && ops[j].pp == NULL // no hint
4975 // allow one simple dereference (com/directx)
4976 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4977 ops[j].operand[1].name);
4980 ret = resolve_origin_reg(j, reg, j + magic, &k, NULL);
4985 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4988 if (ops[j].pp != NULL) {
4992 else if (ops[j].operand[1].type == OPT_REGMEM) {
4993 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4995 // maybe structure ptr in structure
4996 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4999 else if (ops[j].operand[1].type == OPT_LABEL)
5000 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
5001 else if (ops[j].operand[1].type == OPT_REG) {
5004 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
5006 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
5007 for (k = 0; k < g_func_pp->argc; k++) {
5008 if (g_func_pp->arg[k].reg == NULL)
5010 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
5011 pp = g_func_pp->arg[k].pp;
5020 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
5022 ferr(&ops[j], "expected struct, got '%s %s'\n",
5023 pp->type.name, pp->name);
5027 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
5030 static const struct parsed_proto *resolve_func_ptr(int i, int opcnt,
5031 int is_call_op, const struct parsed_opr *opr,
5032 int *pp_i, int *multi_src)
5034 const struct parsed_proto *pp = NULL;
5035 int search_advice = 0;
5037 if (multi_src != NULL)
5042 switch (opr->type) {
5044 // try to resolve struct member calls
5045 pp = resolve_deref(i, i + opcnt * 19, opr, 0);
5051 pp = try_recover_pp(&ops[i], opr, is_call_op, &search_advice);
5056 scan_for_call_type(i, opr, i + opcnt * 9, is_call_op,
5057 &pp, pp_i, multi_src);
5064 static struct parsed_proto *process_call_early(int i, int opcnt,
5067 struct parsed_op *po = &ops[i];
5068 struct parsed_proto *pp;
5074 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
5078 // look for and make use of esp adjust
5080 if (!pp->is_stdcall && pp->argc_stack > 0)
5081 ret = scan_for_esp_adjust(i + 1, opcnt,
5082 pp->argc_stack * 4, &adj, &multipath, 0);
5084 if (pp->argc_stack > adj / 4)
5088 if (ops[ret].op == OP_POP) {
5089 for (j = 1; j < adj / 4; j++) {
5090 if (ops[ret + j].op != OP_POP
5091 || ops[ret + j].operand[0].reg != xCX)
5103 static struct parsed_proto *process_call(int i, int opcnt)
5105 struct parsed_op *po = &ops[i];
5106 const struct parsed_proto *pp_c;
5107 struct parsed_proto *pp;
5108 const char *tmpname;
5109 int call_i = -1, ref_i = -1;
5110 int adj = 0, multipath = 0;
5113 tmpname = opr_name(po, 0);
5118 pp_c = resolve_func_ptr(i, opcnt, 1, &ops[i].operand[0],
5119 &call_i, &multipath);
5121 if (!pp_c->is_func && !pp_c->is_fptr)
5122 ferr(po, "call to non-func: %s\n", pp_c->name);
5123 pp = proto_clone(pp_c);
5124 my_assert_not(pp, NULL);
5126 // not resolved just to single func
5129 switch (po->operand[0].type) {
5131 // we resolved this call and no longer need the register
5132 po->regmask_src &= ~(1 << po->operand[0].reg);
5134 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
5135 && ops[call_i].operand[1].type == OPT_LABEL)
5137 // no other source users?
5138 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
5140 if (ret == 1 && call_i == ref_i) {
5141 // and nothing uses it after us?
5143 find_next_read(i + 1, opcnt, &po->operand[0],
5144 i + opcnt * 11, &ref_i);
5146 // then also don't need the source mov
5147 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
5159 pp = calloc(1, sizeof(*pp));
5160 my_assert_not(pp, NULL);
5163 ret = scan_for_esp_adjust(i + 1, opcnt,
5164 -1, &adj, &multipath, 0);
5165 if (ret < 0 || adj < 0) {
5166 if (!g_allow_regfunc)
5167 ferr(po, "non-__cdecl indirect call unhandled yet\n");
5168 pp->is_unresolved = 1;
5172 if (adj > ARRAY_SIZE(pp->arg))
5173 ferr(po, "esp adjust too large: %d\n", adj);
5174 pp->ret_type.name = strdup("int");
5175 pp->argc = pp->argc_stack = adj;
5176 for (arg = 0; arg < pp->argc; arg++)
5177 pp->arg[arg].type.name = strdup("int");
5182 // look for and make use of esp adjust
5185 if (!pp->is_stdcall && pp->argc_stack > 0) {
5186 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
5187 ret = scan_for_esp_adjust(i + 1, opcnt,
5188 adj_expect, &adj, &multipath, 0);
5191 if (pp->is_vararg) {
5192 if (adj / 4 < pp->argc_stack) {
5193 fnote(po, "(this call)\n");
5194 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
5195 adj, pp->argc_stack * 4);
5197 // modify pp to make it have varargs as normal args
5199 pp->argc += adj / 4 - pp->argc_stack;
5200 for (; arg < pp->argc; arg++) {
5201 pp->arg[arg].type.name = strdup("int");
5204 if (pp->argc > ARRAY_SIZE(pp->arg))
5205 ferr(po, "too many args for '%s'\n", tmpname);
5207 if (pp->argc_stack > adj / 4) {
5208 if (pp->is_noreturn)
5209 // assume no stack adjust was emited
5211 fnote(po, "(this call)\n");
5212 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
5213 tmpname, pp->argc_stack * 4, adj);
5216 scan_for_esp_adjust(i + 1, opcnt,
5217 pp->argc_stack * 4, &adj, &multipath, 1);
5219 else if (pp->is_vararg)
5220 ferr(po, "missing esp_adjust for vararg func '%s'\n",
5227 static void check_fptr_args(int i, int opcnt, struct parsed_proto *pp)
5229 struct parsed_opr s_opr = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
5230 const struct parsed_proto *pp_arg, *pp_cmp;
5231 const struct parsed_op *po_a;
5236 for (arg = 0; arg < pp->argc; arg++) {
5240 pp_arg = pp->arg[arg].pp;
5241 if (pp_arg == NULL || !pp_arg->is_func)
5244 s_reg = pp->arg[arg].reg;
5245 if (s_reg != NULL) {
5246 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
5247 ferr_assert(&ops[i], reg >= 0);
5249 scan_for_call_type(i, &s_opr, i + arg + opcnt * 28, 0,
5250 &pp_cmp, &pp_cmp_i, NULL);
5253 po_a = pp->arg[arg].datap;
5254 if (po_a != NULL && po_a->op == OP_PUSH)
5255 pp_cmp = resolve_func_ptr(po_a - ops, opcnt, 0,
5256 &po_a->operand[0], &pp_cmp_i, NULL);
5258 pp_cmp_i = po_a - ops;
5261 if (pp_cmp != NULL && !pp_compatible_func(pp_arg, pp_cmp)) {
5263 fnote(&ops[pp_cmp_i], "(referenced here)\n");
5264 ferr(&ops[i], "incompatible fptr arg %d\n", arg + 1);
5269 static void mark_float_arg(struct parsed_op *po,
5270 struct parsed_proto *pp, int arg, int *regmask_ffca)
5273 po->p_argnum = arg + 1;
5274 ferr_assert(po, pp->arg[arg].datap == NULL);
5275 pp->arg[arg].datap = po;
5276 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
5277 if (regmask_ffca != NULL)
5278 *regmask_ffca |= 1 << arg;
5281 static int check_for_stp(int i, int i_to)
5283 struct parsed_op *po;
5285 for (; i < i_to; i++) {
5287 if (po->op == OP_FST)
5289 if (g_labels[i] != NULL || (po->flags & OPF_JMP))
5291 if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
5293 if (po->op == OP_ADD && po->operand[0].reg == xSP)
5300 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
5303 struct parsed_op *po;
5309 for (base_arg = 0; base_arg < pp->argc; base_arg++)
5310 if (pp->arg[base_arg].reg == NULL)
5313 for (j = i; j > 0; )
5315 ferr_assert(&ops[j], g_labels[j] == NULL);
5319 ferr_assert(po, po->op != OP_PUSH);
5320 if (po->op == OP_FST)
5322 if (po->operand[0].type != OPT_REGMEM)
5324 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
5327 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
5328 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
5332 arg = base_arg + offset / 4;
5333 mark_float_arg(po, pp, arg, regmask_ffca);
5335 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5336 && po->operand[1].type == OPT_CONST)
5338 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5343 for (arg = base_arg; arg < pp->argc; arg++) {
5344 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
5345 po = pp->arg[arg].datap;
5347 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
5348 if (po->operand[0].lmod == OPLM_QWORD)
5355 static int collect_call_args_early(int i, int opcnt,
5356 struct parsed_proto *pp, int *regmask, int *regmask_ffca)
5358 struct parsed_op *po;
5363 for (arg = 0; arg < pp->argc; arg++)
5364 if (pp->arg[arg].reg == NULL)
5367 // first see if it can be easily done
5368 for (j = i; j > 0 && arg < pp->argc; )
5370 if (g_labels[j] != NULL)
5375 if (po->op == OP_CALL)
5377 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
5379 else if (po->op == OP_POP)
5381 else if (po->flags & OPF_CJMP)
5383 else if (po->op == OP_PUSH) {
5384 if (po->flags & (OPF_FARG|OPF_FARGNR))
5386 if (!g_header_mode) {
5387 ret = scan_for_mod(po, j + 1, i, 1);
5392 if (pp->arg[arg].type.is_va_list)
5396 for (arg++; arg < pp->argc; arg++)
5397 if (pp->arg[arg].reg == NULL)
5400 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5401 && po->operand[1].type == OPT_CONST)
5403 if (po->flags & (OPF_RMD|OPF_DONE))
5405 if (po->operand[1].val != pp->argc_stack * 4)
5406 ferr(po, "unexpected esp adjust: %d\n",
5407 po->operand[1].val * 4);
5408 ferr_assert(po, pp->argc - arg == pp->argc_stack);
5409 return collect_call_args_no_push(i, pp, regmask_ffca);
5417 for (arg = 0; arg < pp->argc; arg++)
5418 if (pp->arg[arg].reg == NULL)
5421 for (j = i; j > 0 && arg < pp->argc; )
5425 if (ops[j].op == OP_PUSH)
5427 ops[j].p_argnext = -1;
5428 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
5430 k = check_for_stp(j + 1, i);
5432 // push ecx; fstp dword ptr [esp]
5433 ret = parse_stack_esp_offset(&ops[k],
5434 ops[k].operand[0].name, &offset);
5435 if (ret == 0 && offset == 0) {
5436 if (!pp->arg[arg].type.is_float)
5437 ferr(&ops[i], "arg %d should be float\n", arg + 1);
5438 mark_float_arg(&ops[k], pp, arg, regmask_ffca);
5442 if (pp->arg[arg].datap == NULL) {
5443 pp->arg[arg].datap = &ops[j];
5444 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5445 *regmask |= 1 << ops[j].operand[0].reg;
5448 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5449 ops[j].flags &= ~OPF_RSAVE;
5452 for (arg++; arg < pp->argc; arg++)
5453 if (pp->arg[arg].reg == NULL)
5459 check_fptr_args(i, opcnt, pp);
5464 static int sync_argnum(struct parsed_op *po, int argnum)
5466 struct parsed_op *po_tmp;
5468 // see if other branches don't have higher argnum
5469 for (po_tmp = po; po_tmp != NULL; ) {
5470 if (argnum < po_tmp->p_argnum)
5471 argnum = po_tmp->p_argnum;
5472 // note: p_argnext is active on current collect_call_args only
5473 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5476 // make all argnums consistent
5477 for (po_tmp = po; po_tmp != NULL; ) {
5478 if (po_tmp->p_argnum != 0)
5479 po_tmp->p_argnum = argnum;
5480 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5486 static int collect_call_args_r(struct parsed_op *po, int i,
5487 struct parsed_proto *pp, int *regmask, int *arg_grp,
5488 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
5490 struct parsed_proto *pp_tmp;
5491 struct parsed_op *po_tmp;
5492 struct label_ref *lr;
5493 int need_to_save_current;
5494 int arg_grp_current = 0;
5495 int save_args_seen = 0;
5502 ferr(po, "dead label encountered\n");
5506 for (; arg < pp->argc; arg++, argnum++)
5507 if (pp->arg[arg].reg == NULL)
5509 magic = (magic & 0xffffff) | (arg << 24);
5511 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5513 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5514 if (ops[j].cc_scratch != magic) {
5515 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5519 // ok: have already been here
5522 ops[j].cc_scratch = magic;
5524 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5525 lr = &g_label_refs[j];
5526 if (lr->next != NULL)
5528 for (; lr->next; lr = lr->next) {
5529 check_i(&ops[j], lr->i);
5530 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5532 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5533 arg, argnum, magic, need_op_saving, may_reuse);
5538 check_i(&ops[j], lr->i);
5539 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5541 if (j > 0 && LAST_OP(j - 1)) {
5542 // follow last branch in reverse
5547 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5548 arg, argnum, magic, need_op_saving, may_reuse);
5554 if (ops[j].op == OP_CALL)
5556 if (pp->is_unresolved)
5561 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5562 arg, pp->argc, ops[j].operand[0].name);
5563 if (may_reuse && pp_tmp->argc_stack > 0)
5564 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5565 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5567 // esp adjust of 0 means we collected it before
5568 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5569 && (ops[j].operand[1].type != OPT_CONST
5570 || ops[j].operand[1].val != 0))
5572 if (pp->is_unresolved)
5575 fnote(po, "(this call)\n");
5576 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5577 arg, pp->argc, ops[j].operand[1].val);
5579 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5581 if (pp->is_unresolved)
5584 fnote(po, "(this call)\n");
5585 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5587 else if (ops[j].flags & OPF_CJMP)
5589 if (pp->is_unresolved)
5594 else if (ops[j].op == OP_PUSH
5595 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5597 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5600 ops[j].p_argnext = -1;
5601 po_tmp = pp->arg[arg].datap;
5603 ops[j].p_argnext = po_tmp - ops;
5604 pp->arg[arg].datap = &ops[j];
5606 argnum = sync_argnum(&ops[j], argnum);
5608 need_to_save_current = 0;
5610 if (ops[j].operand[0].type == OPT_REG)
5611 reg = ops[j].operand[0].reg;
5613 if (!need_op_saving) {
5614 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5615 need_to_save_current = (ret >= 0);
5617 if (need_op_saving || need_to_save_current) {
5618 // mark this arg as one that needs operand saving
5619 pp->arg[arg].is_saved = 1;
5621 if (save_args_seen & (1 << (argnum - 1))) {
5624 if (arg_grp_current >= MAX_ARG_GRP)
5625 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5629 else if (ops[j].p_argnum == 0)
5630 ops[j].flags |= OPF_RMD;
5632 // some PUSHes are reused by different calls on other branches,
5633 // but that can't happen if we didn't branch, so they
5634 // can be removed from future searches (handles nested calls)
5636 ops[j].flags |= OPF_FARGNR;
5638 ops[j].flags |= OPF_FARG;
5639 ops[j].flags &= ~OPF_RSAVE;
5641 // check for __VALIST
5642 if (!pp->is_unresolved && g_func_pp != NULL
5643 && pp->arg[arg].type.is_va_list)
5646 ret = resolve_origin(j, &ops[j].operand[0],
5647 magic + 1, &k, NULL);
5648 if (ret == 1 && k >= 0)
5650 if (ops[k].op == OP_LEA) {
5651 if (!g_func_pp->is_vararg)
5652 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5655 snprintf(buf, sizeof(buf), "arg_%X",
5656 g_func_pp->argc_stack * 4);
5657 if (strstr(ops[k].operand[1].name, buf)
5658 || strstr(ops[k].operand[1].name, "arglist"))
5660 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5661 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5662 pp->arg[arg].is_saved = 0;
5666 ferr(&ops[k], "va_list arg detection failed\n");
5668 // check for va_list from g_func_pp arg too
5669 else if (ops[k].op == OP_MOV
5670 && is_stack_access(&ops[k], &ops[k].operand[1]))
5672 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5673 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5675 ops[k].flags |= OPF_RMD | OPF_DONE;
5676 ops[j].flags |= OPF_RMD;
5677 ops[j].p_argpass = ret + 1;
5678 pp->arg[arg].is_saved = 0;
5685 if (pp->arg[arg].is_saved) {
5686 ops[j].flags &= ~OPF_RMD;
5687 ops[j].p_argnum = argnum;
5690 // tracking reg usage
5692 *regmask |= 1 << reg;
5696 if (!pp->is_unresolved) {
5698 for (; arg < pp->argc; arg++, argnum++)
5699 if (pp->arg[arg].reg == NULL)
5702 magic = (magic & 0xffffff) | (arg << 24);
5705 if (ops[j].p_arggrp > arg_grp_current) {
5707 arg_grp_current = ops[j].p_arggrp;
5709 if (ops[j].p_argnum > 0)
5710 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5713 if (arg < pp->argc) {
5714 ferr(po, "arg collect failed for '%s': %d/%d\n",
5715 pp->name, arg, pp->argc);
5719 if (arg_grp_current > *arg_grp)
5720 *arg_grp = arg_grp_current;
5725 static int collect_call_args(struct parsed_op *po, int i, int opcnt,
5726 struct parsed_proto *pp, int *regmask, int magic)
5728 // arg group is for cases when pushes for
5729 // multiple funcs are going on
5730 struct parsed_op *po_tmp;
5735 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5740 if (pp->is_unresolved) {
5742 pp->argc_stack += ret;
5743 for (a = 0; a < pp->argc; a++)
5744 if (pp->arg[a].type.name == NULL)
5745 pp->arg[a].type.name = strdup("int");
5749 // propagate arg_grp
5750 for (a = 0; a < pp->argc; a++) {
5751 if (pp->arg[a].reg != NULL)
5754 po_tmp = pp->arg[a].datap;
5755 while (po_tmp != NULL) {
5756 po_tmp->p_arggrp = arg_grp;
5757 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5763 check_fptr_args(i, opcnt, pp);
5768 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5769 int regmask_now, int *regmask,
5770 int regmask_save_now, int *regmask_save,
5771 int *regmask_init, int regmask_arg)
5773 struct parsed_op *po;
5781 for (; i < opcnt; i++)
5784 if (cbits[i >> 3] & (1 << (i & 7)))
5786 cbits[i >> 3] |= (1 << (i & 7));
5788 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5789 if (po->flags & (OPF_RMD|OPF_DONE))
5791 if (po->btj != NULL) {
5792 for (j = 0; j < po->btj->count; j++) {
5793 check_i(po, po->btj->d[j].bt_i);
5794 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5795 regmask_now, regmask, regmask_save_now, regmask_save,
5796 regmask_init, regmask_arg);
5801 check_i(po, po->bt_i);
5802 if (po->flags & OPF_CJMP)
5803 reg_use_pass(po->bt_i, opcnt, cbits,
5804 regmask_now, regmask, regmask_save_now, regmask_save,
5805 regmask_init, regmask_arg);
5811 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5812 && !g_func_pp->is_userstack
5813 && po->operand[0].type == OPT_REG)
5817 reg = po->operand[0].reg;
5818 ferr_assert(po, reg >= 0);
5821 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5822 if (regmask_now & (1 << reg)) {
5823 already_saved = regmask_save_now & (1 << reg);
5824 flags_set = OPF_RSAVE | OPF_DONE;
5828 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3,
5829 reg, 0, 0, save_level, 0);
5831 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5832 reg, 0, 0, save_level, flags_set);
5835 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5837 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5842 ferr_assert(po, !already_saved);
5843 po->flags |= flags_set;
5845 if (regmask_now & (1 << reg)) {
5846 regmask_save_now |= (1 << reg);
5847 *regmask_save |= regmask_save_now;
5852 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5853 reg = po->operand[0].reg;
5854 ferr_assert(po, reg >= 0);
5856 if (regmask_save_now & (1 << reg))
5857 regmask_save_now &= ~(1 << reg);
5859 regmask_now &= ~(1 << reg);
5862 else if (po->op == OP_CALL) {
5863 if ((po->regmask_dst & (1 << xAX))
5864 && !(po->regmask_dst & (1 << xDX)))
5866 if (po->flags & OPF_TAIL)
5867 // don't need eax, will do "return f();" or "f(); return;"
5868 po->regmask_dst &= ~(1 << xAX);
5870 find_next_read_reg(i + 1, opcnt, xAX, OPLM_DWORD,
5871 i + opcnt * 17, &j);
5874 po->regmask_dst &= ~(1 << xAX);
5878 // not "full stack" mode and have something in stack
5879 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5880 ferr(po, "float stack is not empty on func call\n");
5883 if (po->flags & OPF_NOREGS)
5886 // if incomplete register is used, clear it on init to avoid
5887 // later use of uninitialized upper part in some situations
5888 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5889 && po->operand[0].lmod != OPLM_DWORD)
5891 reg = po->operand[0].reg;
5892 ferr_assert(po, reg >= 0);
5894 if (!(regmask_now & (1 << reg)))
5895 *regmask_init |= 1 << reg;
5898 regmask_op = po->regmask_src | po->regmask_dst;
5900 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5901 regmask_new &= ~(1 << xSP);
5902 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5903 regmask_new &= ~(1 << xBP);
5905 if (regmask_new != 0)
5906 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5908 if (regmask_op & (1 << xBP)) {
5909 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5910 if (po->regmask_dst & (1 << xBP))
5911 // compiler decided to drop bp frame and use ebp as scratch
5912 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5914 regmask_op &= ~(1 << xBP);
5918 if (po->flags & OPF_FPUSH) {
5919 if (regmask_now & mxST1)
5920 regmask_now |= mxSTa; // switch to "full stack" mode
5921 if (regmask_now & mxSTa)
5922 po->flags |= OPF_FSHIFT;
5923 if (!(regmask_now & mxST7_2)) {
5925 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5929 regmask_now |= regmask_op;
5930 *regmask |= regmask_now;
5933 if (po->flags & OPF_FPOPP) {
5934 if ((regmask_now & mxSTa) == 0)
5935 ferr(po, "float pop on empty stack?\n");
5936 if (regmask_now & mxST7_2)
5937 po->flags |= OPF_FSHIFT;
5938 if (!(regmask_now & mxST7_2))
5939 regmask_now &= ~mxST1_0;
5941 else if (po->flags & OPF_FPOP) {
5942 if ((regmask_now & mxSTa) == 0)
5943 ferr(po, "float pop on empty stack?\n");
5944 if (regmask_now & (mxST7_2 | mxST1))
5945 po->flags |= OPF_FSHIFT;
5946 if (!(regmask_now & mxST7_2)) {
5948 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5952 if (po->flags & OPF_TAIL) {
5953 if (!(regmask_now & mxST7_2)) {
5954 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5955 if (!(regmask_now & mxST0))
5956 ferr(po, "no st0 on float return, mask: %x\n",
5959 else if (regmask_now & mxST1_0)
5960 ferr(po, "float regs on tail: %x\n", regmask_now);
5963 // there is support for "conditional tailcall", sort of
5964 if (!(po->flags & OPF_CC))
5970 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5974 for (i = 0; i < pp->argc; i++)
5975 if (pp->arg[i].reg == NULL)
5979 memmove(&pp->arg[i + 1], &pp->arg[i],
5980 sizeof(pp->arg[0]) * pp->argc_stack);
5981 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5982 pp->arg[i].reg = strdup(reg);
5983 pp->arg[i].type.name = strdup("int");
5988 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5989 int *pfomask, const char *dst_opr_text)
5991 if (*pfomask & (1 << PFO_Z)) {
5992 fprintf(fout, "\n cond_z = (%s%s == 0);",
5993 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5994 *pfomask &= ~(1 << PFO_Z);
5998 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5999 int *pfomask, const char *dst_opr_text)
6001 if (*pfomask & (1 << PFO_S)) {
6002 fprintf(fout, "\n cond_s = (%s%s < 0);",
6003 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
6004 *pfomask &= ~(1 << PFO_S);
6008 static void output_std_flags(FILE *fout, struct parsed_op *po,
6009 int *pfomask, const char *dst_opr_text)
6011 output_std_flag_z(fout, po, pfomask, dst_opr_text);
6012 output_std_flag_s(fout, po, pfomask, dst_opr_text);
6016 OPP_FORCE_NORETURN = (1 << 0),
6017 OPP_SIMPLE_ARGS = (1 << 1),
6018 OPP_ALIGN = (1 << 2),
6021 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
6024 const char *cconv = "";
6026 if (pp->is_fastcall)
6027 cconv = "__fastcall ";
6028 else if (pp->is_stdcall && pp->argc_reg == 0)
6029 cconv = "__stdcall ";
6031 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
6033 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
6034 fprintf(fout, "noreturn ");
6037 static void output_pp(FILE *fout, const struct parsed_proto *pp,
6042 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
6046 output_pp_attrs(fout, pp, flags);
6049 fprintf(fout, "%s", pp->name);
6054 for (i = 0; i < pp->argc; i++) {
6056 fprintf(fout, ", ");
6057 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
6058 && !(flags & OPP_SIMPLE_ARGS))
6061 output_pp(fout, pp->arg[i].pp, 0);
6063 else if (pp->arg[i].type.is_retreg) {
6064 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
6067 fprintf(fout, "%s", pp->arg[i].type.name);
6069 fprintf(fout, " a%d", i + 1);
6072 if (pp->arg[i].type.is_64bit)
6075 if (pp->is_vararg) {
6077 fprintf(fout, ", ");
6078 fprintf(fout, "...");
6083 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
6089 snprintf(buf1, sizeof(buf1), "%d", grp);
6090 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
6095 static void gen_x_cleanup(int opcnt);
6097 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
6099 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
6100 struct parsed_opr *last_arith_dst = NULL;
6101 char buf1[256], buf2[256], buf3[256], cast[64];
6102 struct parsed_proto *pp, *pp_tmp;
6103 struct parsed_data *pd;
6104 int save_arg_vars[MAX_ARG_GRP] = { 0, };
6105 unsigned char cbits[MAX_OPS / 8];
6106 const char *float_type;
6107 const char *float_st0;
6108 const char *float_st1;
6109 int need_float_stack = 0;
6110 int need_float_sw = 0; // status word
6111 int need_tmp_var = 0;
6115 int label_pending = 0;
6116 int need_double = 0;
6117 int stack_align = 0;
6118 int stack_fsz_adj = 0;
6119 int lock_handled = 0;
6120 int regmask_save = 0; // used regs saved/restored in this func
6121 int regmask_arg; // regs from this function args (fastcall, etc)
6122 int regmask_ret; // regs needed on ret
6123 int regmask_now; // temp
6124 int regmask_init = 0; // regs that need zero initialization
6125 int regmask_pp = 0; // regs used in complex push-pop graph
6126 int regmask_ffca = 0; // float function call args
6127 int regmask = 0; // used regs
6137 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
6138 g_stack_frame_used = 0;
6140 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
6141 regmask_init = g_regmask_init;
6143 g_func_pp = proto_parse(fhdr, funcn, 0);
6144 if (g_func_pp == NULL)
6145 ferr(ops, "proto_parse failed for '%s'\n", funcn);
6147 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
6148 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
6151 // - resolve all branches
6152 // - parse calls with labels
6153 resolve_branches_parse_calls(opcnt);
6156 // - handle ebp/esp frame, remove ops related to it
6157 scan_prologue_epilogue(opcnt, &stack_align);
6159 // handle a case where sf size is unalignment, but is
6160 // placed in a way that elements are still aligned
6161 if (g_stack_fsz & 4) {
6162 for (i = 0; i < g_eqcnt; i++) {
6163 if (g_eqs[i].lmod != OPLM_QWORD)
6165 if (!(g_eqs[i].offset & 4)) {
6174 // - remove dead labels
6175 // - set regs needed at ret
6176 for (i = 0; i < opcnt; i++)
6178 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
6183 if (ops[i].op == OP_RET)
6184 ops[i].regmask_src |= regmask_ret;
6188 // - process trivial calls
6189 for (i = 0; i < opcnt; i++)
6192 if (po->flags & (OPF_RMD|OPF_DONE))
6195 if (po->op == OP_CALL)
6197 pp = process_call_early(i, opcnt, &j);
6199 if (!(po->flags & OPF_ATAIL)) {
6200 // since we know the args, try to collect them
6201 ret = collect_call_args_early(i, opcnt, pp,
6202 ®mask, ®mask_ffca);
6210 // commit esp adjust
6211 if (ops[j].op != OP_POP)
6212 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
6214 for (l = 0; l < pp->argc_stack; l++)
6215 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
6219 if (strstr(pp->ret_type.name, "int64"))
6222 po->flags |= OPF_DONE;
6228 // - process calls, stage 2
6229 // - handle some push/pop pairs
6230 // - scan for STD/CLD, propagate DF
6231 // - try to resolve needed x87 status word bits
6232 for (i = 0; i < opcnt; i++)
6237 if (po->flags & OPF_RMD)
6240 if (po->op == OP_CALL)
6242 if (!(po->flags & OPF_DONE)) {
6243 pp = process_call(i, opcnt);
6245 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
6246 // since we know the args, collect them
6247 collect_call_args(po, i, opcnt, pp, ®mask, i + opcnt * 2);
6249 // for unresolved, collect after other passes
6253 ferr_assert(po, pp != NULL);
6255 po->regmask_src |= get_pp_arg_regmask_src(pp);
6256 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
6258 if (po->regmask_dst & mxST0)
6259 po->flags |= OPF_FPUSH;
6261 if (strstr(pp->ret_type.name, "int64"))
6267 if (po->flags & OPF_DONE)
6272 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
6273 && po->operand[0].type == OPT_CONST)
6275 scan_for_pop_const(i, opcnt, i + opcnt * 12);
6280 scan_pushes_for_pop(i, opcnt, ®mask_pp);
6284 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
6285 scan_propagate_df(i + 1, opcnt);
6290 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
6291 ferr(po, "TODO: fnstsw to mem\n");
6292 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
6294 ferr(po, "fnstsw resolve failed\n");
6295 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
6296 (void *)(long)(mask | (z_check << 16)));
6298 ferr(po, "failed to find fcom: %d\n", ret);
6307 // - find POPs for PUSHes, rm both
6308 // - scan for all used registers
6309 memset(cbits, 0, sizeof(cbits));
6310 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
6311 0, ®mask_save, ®mask_init, regmask_arg);
6313 need_float_stack = !!(regmask & mxST7_2);
6316 // - find flag set ops for their users
6317 // - do unresolved calls
6318 // - declare indirect functions
6319 // - other op specific processing
6320 for (i = 0; i < opcnt; i++)
6323 if (po->flags & (OPF_RMD|OPF_DONE))
6326 if (po->flags & OPF_CC)
6328 int setters[16], cnt = 0, branched = 0;
6330 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
6331 &branched, setters, &cnt);
6332 if (ret < 0 || cnt <= 0)
6333 ferr(po, "unable to trace flag setter(s)\n");
6334 if (cnt > ARRAY_SIZE(setters))
6335 ferr(po, "too many flag setters\n");
6337 for (j = 0; j < cnt; j++)
6339 tmp_op = &ops[setters[j]]; // flag setter
6342 // to get nicer code, we try to delay test and cmp;
6343 // if we can't because of operand modification, or if we
6344 // have arith op, or branch, make it calculate flags explicitly
6345 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
6347 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
6348 pfomask = 1 << po->pfo;
6350 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
6351 pfomask = 1 << po->pfo;
6354 // see if we'll be able to handle based on op result
6355 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
6356 && po->pfo != PFO_Z && po->pfo != PFO_S
6357 && po->pfo != PFO_P)
6359 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
6361 pfomask = 1 << po->pfo;
6364 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
6365 propagate_lmod(tmp_op, &tmp_op->operand[0],
6366 &tmp_op->operand[1]);
6367 if (tmp_op->operand[0].lmod == OPLM_DWORD)
6372 tmp_op->pfomask |= pfomask;
6373 cond_vars |= pfomask;
6375 // note: may overwrite, currently not a problem
6379 if (po->op == OP_RCL || po->op == OP_RCR
6380 || po->op == OP_ADC || po->op == OP_SBB)
6381 cond_vars |= 1 << PFO_C;
6387 cond_vars |= 1 << PFO_Z;
6391 if (po->operand[0].lmod == OPLM_DWORD)
6396 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
6401 // note: resolved non-reg calls are OPF_DONE already
6403 ferr_assert(po, pp != NULL);
6405 if (pp->is_unresolved) {
6406 int regmask_stack = 0;
6407 collect_call_args(po, i, opcnt, pp, ®mask, i + opcnt * 2);
6409 // this is pretty rough guess:
6410 // see ecx and edx were pushed (and not their saved versions)
6411 for (arg = 0; arg < pp->argc; arg++) {
6412 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
6415 tmp_op = pp->arg[arg].datap;
6417 ferr(po, "parsed_op missing for arg%d\n", arg);
6418 if (tmp_op->operand[0].type == OPT_REG)
6419 regmask_stack |= 1 << tmp_op->operand[0].reg;
6422 // quick dumb check for potential reg-args
6423 for (j = i - 1; j >= 0 && ops[j].op == OP_MOV; j--)
6424 if (ops[j].operand[0].type == OPT_REG)
6425 regmask_stack &= ~(1 << ops[j].operand[0].reg);
6427 if ((regmask_stack & (mxCX|mxDX)) != (mxCX|mxDX)
6428 && ((regmask | regmask_arg) & (mxCX|mxDX)))
6430 if (pp->argc_stack != 0
6431 || ((regmask | regmask_arg) & (mxCX|mxDX)))
6433 pp_insert_reg_arg(pp, "ecx");
6434 pp->is_fastcall = 1;
6435 regmask_init |= 1 << xCX;
6436 regmask |= 1 << xCX;
6438 if (pp->argc_stack != 0
6439 || ((regmask | regmask_arg) & mxDX))
6441 pp_insert_reg_arg(pp, "edx");
6442 regmask_init |= 1 << xDX;
6443 regmask |= 1 << xDX;
6447 // note: __cdecl doesn't fall into is_unresolved category
6448 if (pp->argc_stack > 0)
6451 if (!(po->flags & OPF_TAIL)
6452 && !(g_sct_func_attr & SCTFA_NOWARN) && !g_nowarn_reguse)
6454 // treat al write as overwrite to avoid many false positives
6455 if (IS(pp->ret_type.name, "void") || pp->ret_type.is_float) {
6456 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
6457 i + opcnt * 25, &j);
6459 fnote(po, "eax used after void/float ret call\n");
6460 fnote(&ops[j], "(used here)\n");
6463 if (!strstr(pp->ret_type.name, "int64")) {
6464 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
6465 i + opcnt * 26, &j);
6466 // indirect calls are often guessed, don't warn
6467 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6468 fnote(po, "edx used after 32bit ret call\n");
6469 fnote(&ops[j], "(used here)\n");
6473 // msvc often relies on callee not modifying 'this'
6474 for (arg = 0; arg < pp->argc; arg++) {
6475 if (pp->arg[arg].reg && IS(pp->arg[arg].reg, "ecx")) {
6481 find_next_read_reg(i + 1, opcnt, xCX, OPLM_BYTE,
6482 i + opcnt * 27, &j);
6483 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6484 fnote(po, "ecx used after call\n");
6485 fnote(&ops[j], "(used here)\n");
6492 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6494 // <var> = offset <something>
6495 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6496 && !IS_START(po->operand[1].name, "off_"))
6498 if (!po->operand[0].pp->is_fptr)
6499 ferr(po, "%s not declared as fptr when it should be\n",
6500 po->operand[0].name);
6501 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6502 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6503 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6504 fnote(po, "var: %s\n", buf1);
6505 fnote(po, "func: %s\n", buf2);
6506 ferr(po, "^ mismatch\n");
6514 if (po->operand[0].lmod == OPLM_DWORD) {
6515 // 32bit division is common, look for it
6516 if (po->op == OP_DIV)
6517 ret = scan_for_reg_clear(i, xDX);
6519 ret = scan_for_cdq_edx(i);
6521 po->flags |= OPF_32BIT;
6530 po->flags |= OPF_RMD | OPF_DONE;
6540 if (po->operand[0].lmod == OPLM_QWORD)
6551 find_next_read_reg(i + 1, opcnt, xDX, OPLM_DWORD,
6552 i + opcnt * 18, &j);
6554 po->flags |= OPF_32BIT;
6562 // pass8: final adjustments
6563 for (i = 0; i < opcnt; i++)
6566 if (po->flags & (OPF_RMD|OPF_DONE))
6569 if (po->op != OP_FST && po->p_argnum > 0)
6570 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6572 // correct for "full stack" mode late enable
6573 if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6574 && need_float_stack)
6575 po->flags |= OPF_FSHIFT;
6578 float_type = need_double ? "double" : "float";
6579 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6580 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6582 // output starts here
6585 fprintf(fout, "// had SEH\n");
6587 // define userstack size
6588 if (g_func_pp->is_userstack) {
6589 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6590 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6591 fprintf(fout, "#endif\n");
6594 // the function itself
6595 ferr_assert(ops, !g_func_pp->is_fptr);
6596 output_pp(fout, g_func_pp,
6597 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6598 fprintf(fout, "\n{\n");
6600 // declare indirect functions
6601 for (i = 0; i < opcnt; i++) {
6603 if (po->flags & OPF_RMD)
6606 if (po->op == OP_CALL) {
6609 ferr(po, "NULL pp\n");
6611 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6612 if (pp->name[0] != 0) {
6613 if (IS_START(pp->name, "guess"))
6616 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6617 memcpy(pp->name, "i_", 2);
6619 // might be declared already
6621 for (j = 0; j < i; j++) {
6622 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6623 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6633 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6636 output_pp(fout, pp, OPP_SIMPLE_ARGS);
6637 fprintf(fout, ";\n");
6642 // output LUTs/jumptables
6643 for (i = 0; i < g_func_pd_cnt; i++) {
6645 fprintf(fout, " static const ");
6646 if (pd->type == OPT_OFFSET) {
6647 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6649 for (j = 0; j < pd->count; j++) {
6651 fprintf(fout, ", ");
6652 fprintf(fout, "&&%s", pd->d[j].u.label);
6656 fprintf(fout, "%s %s[] =\n { ",
6657 lmod_type_u(ops, pd->lmod), pd->label);
6659 for (j = 0; j < pd->count; j++) {
6661 fprintf(fout, ", ");
6662 fprintf(fout, "%u", pd->d[j].u.val);
6665 fprintf(fout, " };\n");
6669 // declare stack frame, va_arg
6672 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6674 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6675 if (g_func_lmods & (1 << OPLM_WORD))
6676 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6677 if (g_func_lmods & (1 << OPLM_BYTE))
6678 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6679 if (g_func_lmods & (1 << OPLM_QWORD))
6680 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6682 if (stack_align > 8)
6683 ferr(ops, "unhandled stack align of %d\n", stack_align);
6684 else if (stack_align == 8)
6685 fprintf(fout, " u64 align;");
6686 fprintf(fout, " } sf;\n");
6690 if ((g_sct_func_attr & SCTFA_ARGFRAME) && g_func_pp->argc_stack) {
6691 fprintf(fout, " struct { u32 ");
6692 for (i = j = 0; i < g_func_pp->argc; i++) {
6693 if (g_func_pp->arg[i].reg != NULL)
6696 fprintf(fout, ", ");
6697 fprintf(fout, "a%d", i + 1);
6699 fprintf(fout, "; } af = {\n ");
6700 for (i = j = 0; i < g_func_pp->argc; i++) {
6701 if (g_func_pp->arg[i].reg != NULL)
6704 fprintf(fout, ", ");
6705 if (g_func_pp->arg[i].type.is_ptr)
6706 fprintf(fout, "(u32)");
6707 fprintf(fout, "a%d", i + 1);
6709 fprintf(fout, "\n };\n");
6712 if (g_func_pp->is_userstack) {
6713 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6714 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6718 if (g_func_pp->is_vararg) {
6719 fprintf(fout, " va_list ap;\n");
6723 // declare arg-registers
6724 for (i = 0; i < g_func_pp->argc; i++) {
6725 if (g_func_pp->arg[i].reg != NULL) {
6726 reg = char_array_i(regs_r32,
6727 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6728 if (regmask & (1 << reg)) {
6729 if (g_func_pp->arg[i].type.is_retreg)
6730 fprintf(fout, " u32 %s = *r_%s;\n",
6731 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6733 fprintf(fout, " u32 %s = (u32)a%d;\n",
6734 g_func_pp->arg[i].reg, i + 1);
6737 if (g_func_pp->arg[i].type.is_retreg)
6738 ferr(ops, "retreg '%s' is unused?\n",
6739 g_func_pp->arg[i].reg);
6740 fprintf(fout, " // %s = a%d; // unused\n",
6741 g_func_pp->arg[i].reg, i + 1);
6747 // declare normal registers
6748 regmask_now = regmask & ~regmask_arg & ~g_regmask_rm;
6749 regmask_now &= ~(1 << xSP);
6750 if (regmask_now & 0x00ff) {
6751 for (reg = 0; reg < 8; reg++) {
6752 if (regmask_now & (1 << reg)) {
6753 fprintf(fout, " u32 %s", regs_r32[reg]);
6754 if (regmask_init & (1 << reg))
6755 fprintf(fout, " = 0");
6756 fprintf(fout, ";\n");
6762 if (regmask_now & 0xff00) {
6763 for (reg = 8; reg < 16; reg++) {
6764 if (regmask_now & (1 << reg)) {
6765 fprintf(fout, " mmxr %s", regs_r32[reg]);
6766 if (regmask_init & (1 << reg))
6767 fprintf(fout, " = { 0, }");
6768 fprintf(fout, ";\n");
6774 if (need_float_stack) {
6775 fprintf(fout, " %s f_st[8];\n", float_type);
6776 fprintf(fout, " int f_stp = 0;\n");
6780 if (regmask_now & 0xff0000) {
6781 for (reg = 16; reg < 24; reg++) {
6782 if (regmask_now & (1 << reg)) {
6783 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6784 if (regmask_init & (1 << reg))
6785 fprintf(fout, " = 0");
6786 fprintf(fout, ";\n");
6793 if (need_float_sw) {
6794 fprintf(fout, " u16 f_sw;\n");
6799 for (reg = 0; reg < 8; reg++) {
6800 if (regmask_save & (1 << reg)) {
6801 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6807 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6808 if (save_arg_vars[i] == 0)
6810 for (reg = 0; reg < 32; reg++) {
6811 if (save_arg_vars[i] & (1 << reg)) {
6812 fprintf(fout, " u32 %s;\n",
6813 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6820 for (reg = 0; reg < 32; reg++) {
6821 if (regmask_ffca & (1 << reg)) {
6822 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6828 // declare push-pop temporaries
6830 for (reg = 0; reg < 8; reg++) {
6831 if (regmask_pp & (1 << reg)) {
6832 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6839 for (i = 0; i < 8; i++) {
6840 if (cond_vars & (1 << i)) {
6841 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6848 fprintf(fout, " u32 tmp;\n");
6853 fprintf(fout, " u64 tmp64;\n");
6858 fprintf(fout, "\n");
6860 // do stack clear, if needed
6861 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6863 if (g_stack_clear_len != 0) {
6864 if (g_stack_clear_len <= 4) {
6865 for (i = 0; i < g_stack_clear_len; i++)
6866 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6867 fprintf(fout, "0;\n");
6870 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6871 g_stack_clear_start, g_stack_clear_len * 4);
6875 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6878 if (g_func_pp->is_vararg) {
6879 if (g_func_pp->argc_stack == 0)
6880 ferr(ops, "vararg func without stack args?\n");
6881 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6885 for (i = 0; i < opcnt; i++)
6887 if (g_labels[i] != NULL) {
6888 fprintf(fout, "\n%s:\n", g_labels[i]);
6891 delayed_flag_op = NULL;
6892 last_arith_dst = NULL;
6896 if (po->flags & OPF_RMD)
6902 #define assert_operand_cnt(n_) \
6903 if (po->operand_cnt != n_) \
6904 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6906 // conditional/flag using op?
6907 if (po->flags & OPF_CC)
6913 // we go through all this trouble to avoid using parsed_flag_op,
6914 // which makes generated code much nicer
6915 if (delayed_flag_op != NULL)
6917 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6918 po->pfo, po->pfo_inv);
6921 else if (last_arith_dst != NULL
6922 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6923 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6926 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6927 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6928 last_arith_dst->lmod, buf3);
6931 else if (tmp_op != NULL) {
6932 // use preprocessed flag calc results
6933 if (!(tmp_op->pfomask & (1 << po->pfo)))
6934 ferr(po, "not prepared for pfo %d\n", po->pfo);
6936 // note: pfo_inv was not yet applied
6937 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6938 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6941 ferr(po, "all methods of finding comparison failed\n");
6944 if (po->flags & OPF_JMP) {
6945 fprintf(fout, " if %s", buf1);
6947 else if (po->op == OP_RCL || po->op == OP_RCR
6948 || po->op == OP_ADC || po->op == OP_SBB)
6951 fprintf(fout, " cond_%s = %s;\n",
6952 parsed_flag_op_names[po->pfo], buf1);
6954 else if (po->flags & OPF_DATA) { // SETcc
6955 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6956 fprintf(fout, " %s = %s;", buf2, buf1);
6959 ferr(po, "unhandled conditional op\n");
6963 pfomask = po->pfomask;
6968 assert_operand_cnt(2);
6969 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6970 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6971 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6972 fprintf(fout, " %s = %s;", buf1,
6973 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6978 assert_operand_cnt(2);
6979 po->operand[1].lmod = OPLM_DWORD; // always
6980 fprintf(fout, " %s = %s;",
6981 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6982 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6987 assert_operand_cnt(2);
6988 fprintf(fout, " %s = %s;",
6989 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6990 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6994 assert_operand_cnt(2);
6995 switch (po->operand[1].lmod) {
6997 strcpy(buf3, "(s8)");
7000 strcpy(buf3, "(s16)");
7003 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
7005 fprintf(fout, " %s = %s;",
7006 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7007 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7012 assert_operand_cnt(2);
7013 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7014 fprintf(fout, " tmp = %s;",
7015 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
7016 fprintf(fout, " %s = %s;",
7017 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7018 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7019 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7020 fprintf(fout, " %s = %stmp;",
7021 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
7022 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
7023 snprintf(g_comment, sizeof(g_comment), "xchg");
7027 assert_operand_cnt(1);
7028 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7029 fprintf(fout, " %s = ~%s;", buf1, buf1);
7033 assert_operand_cnt(2);
7034 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7035 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7036 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
7037 strcpy(g_comment, "xlat");
7041 assert_operand_cnt(2);
7042 fprintf(fout, " %s = (s32)%s >> 31;",
7043 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7044 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7045 strcpy(g_comment, "cdq");
7049 assert_operand_cnt(1);
7050 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7051 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
7055 if (po->flags & OPF_REP) {
7056 assert_operand_cnt(3);
7061 assert_operand_cnt(2);
7062 fprintf(fout, " %s = %sesi; esi %c= %d;",
7063 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
7064 lmod_cast_u_ptr(po, po->operand[1].lmod),
7065 (po->flags & OPF_DF) ? '-' : '+',
7066 lmod_bytes(po, po->operand[1].lmod));
7067 strcpy(g_comment, "lods");
7072 if (po->flags & OPF_REP) {
7073 assert_operand_cnt(3);
7074 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
7075 (po->flags & OPF_DF) ? '-' : '+',
7076 lmod_bytes(po, po->operand[1].lmod));
7077 fprintf(fout, " %sedi = eax;\n",
7078 lmod_cast_u_ptr(po, po->operand[1].lmod));
7079 fprintf(fout, " barrier();");
7080 strcpy(g_comment, "^ rep stos");
7083 assert_operand_cnt(2);
7084 fprintf(fout, " %sedi = eax; edi %c= %d;",
7085 lmod_cast_u_ptr(po, po->operand[1].lmod),
7086 (po->flags & OPF_DF) ? '-' : '+',
7087 lmod_bytes(po, po->operand[1].lmod));
7088 strcpy(g_comment, "stos");
7093 j = lmod_bytes(po, po->operand[0].lmod);
7094 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
7095 l = (po->flags & OPF_DF) ? '-' : '+';
7096 if (po->flags & OPF_REP) {
7097 assert_operand_cnt(3);
7099 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
7102 " %sedi = %sesi;\n", buf1, buf1);
7103 // this can overwrite many variables
7104 fprintf(fout, " barrier();");
7105 strcpy(g_comment, "^ rep movs");
7108 assert_operand_cnt(2);
7109 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
7110 buf1, buf1, l, j, l, j);
7111 strcpy(g_comment, "movs");
7116 // repe ~ repeat while ZF=1
7117 j = lmod_bytes(po, po->operand[0].lmod);
7118 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
7119 l = (po->flags & OPF_DF) ? '-' : '+';
7120 if (po->flags & OPF_REP) {
7121 assert_operand_cnt(3);
7123 " while (ecx != 0) {\n");
7124 if (pfomask & (1 << PFO_C)) {
7127 " cond_c = %sesi < %sedi;\n", buf1, buf1);
7128 pfomask &= ~(1 << PFO_C);
7131 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
7132 buf1, buf1, l, j, l, j);
7135 " if (cond_z %s 0) break;\n",
7136 (po->flags & OPF_REPZ) ? "==" : "!=");
7139 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
7140 (po->flags & OPF_REPZ) ? "e" : "ne");
7143 assert_operand_cnt(2);
7145 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
7146 buf1, buf1, l, j, l, j);
7147 strcpy(g_comment, "cmps");
7149 pfomask &= ~(1 << PFO_Z);
7150 last_arith_dst = NULL;
7151 delayed_flag_op = NULL;
7155 // only does ZF (for now)
7156 // repe ~ repeat while ZF=1
7157 j = lmod_bytes(po, po->operand[1].lmod);
7158 l = (po->flags & OPF_DF) ? '-' : '+';
7159 if (po->flags & OPF_REP) {
7160 assert_operand_cnt(3);
7162 " while (ecx != 0) {\n");
7164 " cond_z = (%seax == %sedi); edi %c= %d;\n",
7165 lmod_cast_u(po, po->operand[1].lmod),
7166 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
7169 " if (cond_z %s 0) break;\n",
7170 (po->flags & OPF_REPZ) ? "==" : "!=");
7173 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
7174 (po->flags & OPF_REPZ) ? "e" : "ne");
7177 assert_operand_cnt(2);
7178 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
7179 lmod_cast_u(po, po->operand[1].lmod),
7180 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
7181 strcpy(g_comment, "scas");
7183 pfomask &= ~(1 << PFO_Z);
7184 last_arith_dst = NULL;
7185 delayed_flag_op = NULL;
7189 fprintf(fout, " tmp64 = ext_rdtsc();\n");
7190 fprintf(fout, " edx = tmp64 >> 32;\n");
7191 fprintf(fout, " eax = tmp64;");
7195 fprintf(fout, " ext_cpuid(&eax, &ebx, &ecx, &edx);");
7198 // arithmetic w/flags
7200 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
7201 goto dualop_arith_const;
7202 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7206 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7207 if (po->operand[1].type == OPT_CONST) {
7208 j = lmod_bytes(po, po->operand[0].lmod);
7209 if (((1ull << j * 8) - 1) == po->operand[1].val)
7210 goto dualop_arith_const;
7215 assert_operand_cnt(2);
7216 fprintf(fout, " %s %s= %s;",
7217 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7219 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7220 output_std_flags(fout, po, &pfomask, buf1);
7221 last_arith_dst = &po->operand[0];
7222 delayed_flag_op = NULL;
7226 // and 0, or ~0 used instead mov
7227 assert_operand_cnt(2);
7228 fprintf(fout, " %s = %s;",
7229 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7230 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7231 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7232 output_std_flags(fout, po, &pfomask, buf1);
7233 last_arith_dst = &po->operand[0];
7234 delayed_flag_op = NULL;
7239 assert_operand_cnt(2);
7240 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7241 if (pfomask & (1 << PFO_C)) {
7242 if (po->operand[1].type == OPT_CONST) {
7243 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7244 j = po->operand[1].val;
7247 if (po->op == OP_SHL)
7251 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
7255 ferr(po, "zero shift?\n");
7259 pfomask &= ~(1 << PFO_C);
7261 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
7262 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7263 if (po->operand[1].type != OPT_CONST)
7264 fprintf(fout, " & 0x1f");
7266 output_std_flags(fout, po, &pfomask, buf1);
7267 last_arith_dst = &po->operand[0];
7268 delayed_flag_op = NULL;
7272 assert_operand_cnt(2);
7273 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7274 fprintf(fout, " %s = %s%s >> %s;", buf1,
7275 lmod_cast_s(po, po->operand[0].lmod), buf1,
7276 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7277 output_std_flags(fout, po, &pfomask, buf1);
7278 last_arith_dst = &po->operand[0];
7279 delayed_flag_op = NULL;
7284 assert_operand_cnt(3);
7285 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7286 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7287 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
7288 if (po->operand[2].type != OPT_CONST) {
7289 // no handling for "undefined" case, hopefully not needed
7290 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
7293 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7294 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7295 if (po->op == OP_SHLD) {
7296 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
7297 buf1, buf3, buf1, buf2, l, buf3);
7298 strcpy(g_comment, "shld");
7301 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
7302 buf1, buf3, buf1, buf2, l, buf3);
7303 strcpy(g_comment, "shrd");
7305 output_std_flags(fout, po, &pfomask, buf1);
7306 last_arith_dst = &po->operand[0];
7307 delayed_flag_op = NULL;
7312 assert_operand_cnt(2);
7313 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7314 if (po->operand[1].type == OPT_CONST) {
7315 j = po->operand[1].val;
7316 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
7317 fprintf(fout, po->op == OP_ROL ?
7318 " %s = (%s << %d) | (%s >> %d);" :
7319 " %s = (%s >> %d) | (%s << %d);",
7320 buf1, buf1, j, buf1,
7321 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
7325 output_std_flags(fout, po, &pfomask, buf1);
7326 last_arith_dst = &po->operand[0];
7327 delayed_flag_op = NULL;
7332 assert_operand_cnt(2);
7333 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7334 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7335 if (po->operand[1].type == OPT_CONST) {
7336 j = po->operand[1].val % l;
7338 ferr(po, "zero rotate\n");
7339 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
7340 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
7341 if (po->op == OP_RCL) {
7343 " %s = (%s << %d) | (cond_c << %d)",
7344 buf1, buf1, j, j - 1);
7346 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
7350 " %s = (%s >> %d) | (cond_c << %d)",
7351 buf1, buf1, j, l - j);
7353 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
7355 fprintf(fout, ";\n");
7356 fprintf(fout, " cond_c = tmp;");
7360 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
7361 output_std_flags(fout, po, &pfomask, buf1);
7362 last_arith_dst = &po->operand[0];
7363 delayed_flag_op = NULL;
7367 assert_operand_cnt(2);
7368 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7369 if (IS(opr_name(po, 0), opr_name(po, 1))) {
7370 // special case for XOR
7371 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
7372 for (j = 0; j <= PFO_LE; j++) {
7373 if (pfomask & (1 << j)) {
7374 fprintf(fout, " cond_%s = %d;\n",
7375 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
7376 pfomask &= ~(1 << j);
7379 fprintf(fout, " %s = 0;",
7380 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7381 last_arith_dst = &po->operand[0];
7382 delayed_flag_op = NULL;
7388 assert_operand_cnt(2);
7389 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7390 if (pfomask & (1 << PFO_C)) {
7391 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7392 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7393 if (po->operand[0].lmod == OPLM_DWORD) {
7394 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
7395 fprintf(fout, " cond_c = tmp64 >> 32;\n");
7396 fprintf(fout, " %s = (u32)tmp64;",
7397 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7398 strcat(g_comment, " add64");
7401 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
7402 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
7403 fprintf(fout, " %s += %s;",
7404 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7407 pfomask &= ~(1 << PFO_C);
7408 output_std_flags(fout, po, &pfomask, buf1);
7409 last_arith_dst = &po->operand[0];
7410 delayed_flag_op = NULL;
7413 if (pfomask & (1 << PFO_LE)) {
7414 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
7415 fprintf(fout, " cond_%s = %s;\n",
7416 parsed_flag_op_names[PFO_LE], buf1);
7417 pfomask &= ~(1 << PFO_LE);
7422 assert_operand_cnt(2);
7423 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7424 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
7425 for (j = 0; j <= PFO_LE; j++) {
7426 if (!(pfomask & (1 << j)))
7428 if (j == PFO_Z || j == PFO_S)
7431 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7432 fprintf(fout, " cond_%s = %s;\n",
7433 parsed_flag_op_names[j], buf1);
7434 pfomask &= ~(1 << j);
7441 assert_operand_cnt(2);
7442 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7443 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7444 if (po->op == OP_SBB
7445 && IS(po->operand[0].name, po->operand[1].name))
7447 // avoid use of unitialized var
7448 fprintf(fout, " %s = -cond_c;", buf1);
7449 // carry remains what it was
7450 pfomask &= ~(1 << PFO_C);
7453 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
7454 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7456 output_std_flags(fout, po, &pfomask, buf1);
7457 last_arith_dst = &po->operand[0];
7458 delayed_flag_op = NULL;
7463 // on SKL, if src is 0, dst is left unchanged
7464 assert_operand_cnt(2);
7465 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7466 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7467 output_std_flag_z(fout, po, &pfomask, buf2);
7468 if (po->op == OP_BSF)
7469 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
7471 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
7472 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
7473 last_arith_dst = &po->operand[0];
7474 delayed_flag_op = NULL;
7475 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
7479 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
7480 for (j = 0; j <= PFO_LE; j++) {
7481 if (!(pfomask & (1 << j)))
7483 if (j == PFO_Z || j == PFO_S || j == PFO_C)
7486 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7487 fprintf(fout, " cond_%s = %s;\n",
7488 parsed_flag_op_names[j], buf1);
7489 pfomask &= ~(1 << j);
7495 if (pfomask & (1 << PFO_C))
7496 // carry is unaffected by inc/dec.. wtf?
7497 ferr(po, "carry propagation needed\n");
7499 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7500 if (po->operand[0].type == OPT_REG) {
7501 ferr_assert(po, !(po->flags & OPF_LOCK));
7502 strcpy(buf2, po->op == OP_INC ? "++" : "--");
7503 fprintf(fout, " %s%s;", buf1, buf2);
7505 else if (po->flags & OPF_LOCK) {
7506 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], "", 1);
7507 fprintf(fout, " __sync_fetch_and_%s((%s *)(%s), 1);",
7508 po->op == OP_INC ? "add" : "sub",
7509 lmod_type_u(po, po->operand[0].lmod), buf2);
7510 strcat(g_comment, " lock");
7514 strcpy(buf2, po->op == OP_INC ? "+" : "-");
7515 fprintf(fout, " %s %s= 1;", buf1, buf2);
7517 output_std_flags(fout, po, &pfomask, buf1);
7518 last_arith_dst = &po->operand[0];
7519 delayed_flag_op = NULL;
7523 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7524 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
7525 fprintf(fout, " %s = -%s%s;", buf1,
7526 lmod_cast_s(po, po->operand[0].lmod), buf2);
7527 last_arith_dst = &po->operand[0];
7528 delayed_flag_op = NULL;
7529 if (pfomask & PFOB_C) {
7530 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
7533 output_std_flags(fout, po, &pfomask, buf1);
7537 if (po->operand_cnt == 2) {
7538 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7541 if (po->operand_cnt == 3)
7542 ferr(po, "TODO imul3\n");
7545 assert_operand_cnt(1);
7546 switch (po->operand[0].lmod) {
7548 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7549 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
7550 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7551 fprintf(fout, " edx = tmp64 >> 32;\n");
7552 fprintf(fout, " eax = tmp64;");
7555 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7556 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
7557 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7561 ferr(po, "TODO: unhandled mul type\n");
7564 last_arith_dst = NULL;
7565 delayed_flag_op = NULL;
7570 assert_operand_cnt(1);
7571 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7572 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7573 po->op == OP_IDIV));
7574 switch (po->operand[0].lmod) {
7576 if (po->flags & OPF_32BIT)
7577 snprintf(buf2, sizeof(buf2), "%seax", cast);
7579 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7580 snprintf(buf2, sizeof(buf2), "%stmp64",
7581 (po->op == OP_IDIV) ? "(s64)" : "");
7583 if (po->operand[0].type == OPT_REG
7584 && po->operand[0].reg == xDX)
7586 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
7587 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
7590 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
7591 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
7595 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
7596 snprintf(buf2, sizeof(buf2), "%stmp",
7597 (po->op == OP_IDIV) ? "(s32)" : "");
7598 if (po->operand[0].type == OPT_REG
7599 && po->operand[0].reg == xDX)
7601 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
7603 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
7607 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
7609 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
7612 strcat(g_comment, " div16");
7615 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7617 last_arith_dst = NULL;
7618 delayed_flag_op = NULL;
7623 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7625 for (j = 0; j < 8; j++) {
7626 if (pfomask & (1 << j)) {
7627 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7628 fprintf(fout, " cond_%s = %s;",
7629 parsed_flag_op_names[j], buf1);
7636 last_arith_dst = NULL;
7637 delayed_flag_op = po;
7641 // SETcc - should already be handled
7644 // note: we reuse OP_Jcc for SETcc, only flags differ
7646 fprintf(fout, "\n goto %s;", po->operand[0].name);
7650 fprintf(fout, " if (ecx == 0)\n");
7651 fprintf(fout, " goto %s;", po->operand[0].name);
7652 strcat(g_comment, " jecxz");
7656 fprintf(fout, " if (--ecx != 0)\n");
7657 fprintf(fout, " goto %s;", po->operand[0].name);
7658 strcat(g_comment, " loop");
7662 assert_operand_cnt(1);
7663 last_arith_dst = NULL;
7664 delayed_flag_op = NULL;
7666 if (po->operand[0].type == OPT_REGMEM) {
7667 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7670 ferr(po, "parse failure for jmp '%s'\n",
7671 po->operand[0].name);
7672 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
7675 else if (po->operand[0].type != OPT_LABEL)
7676 ferr(po, "unhandled jmp type\n");
7678 fprintf(fout, " goto %s;", po->operand[0].name);
7682 assert_operand_cnt(1);
7684 my_assert_not(pp, NULL);
7687 if (po->flags & OPF_CC) {
7688 // we treat conditional branch to another func
7689 // (yes such code exists..) as conditional tailcall
7691 fprintf(fout, " {\n");
7694 if (pp->is_fptr && !pp->is_arg) {
7695 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7696 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7699 if (pp->is_fptr && (pp->is_unresolved || pp->is_guessed)) {
7700 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7701 buf3, asmfn, po->asmln, pp->name);
7704 fprintf(fout, "%s", buf3);
7705 if (strstr(pp->ret_type.name, "int64")) {
7706 if (po->flags & OPF_TAIL)
7707 ferr(po, "int64 and tail?\n");
7708 fprintf(fout, "tmp64 = ");
7710 else if (!IS(pp->ret_type.name, "void")) {
7711 if (po->flags & OPF_TAIL) {
7712 if (regmask_ret & mxAX) {
7713 fprintf(fout, "return ");
7714 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7715 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7717 else if (regmask_ret & mxST0)
7718 ferr(po, "float tailcall\n");
7720 else if (po->regmask_dst & mxAX) {
7721 fprintf(fout, "eax = ");
7722 if (pp->ret_type.is_ptr)
7723 fprintf(fout, "(u32)");
7725 else if (po->regmask_dst & mxST0) {
7726 ferr_assert(po, po->flags & OPF_FPUSH);
7727 if (need_float_stack)
7728 fprintf(fout, "f_st[--f_stp & 7] = ");
7730 fprintf(fout, "f_st0 = ");
7734 if (pp->name[0] == 0)
7735 ferr(po, "missing pp->name\n");
7736 fprintf(fout, "%s%s(", pp->name,
7737 pp->has_structarg ? "_sa" : "");
7739 if (po->flags & OPF_ATAIL) {
7741 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7742 check_compat |= pp->argc_stack > 0;
7744 && (pp->argc_stack != g_func_pp->argc_stack
7745 || pp->is_stdcall != g_func_pp->is_stdcall))
7746 ferr(po, "incompatible arg-reuse tailcall\n");
7747 if (g_func_pp->has_retreg)
7748 ferr(po, "TODO: retreg+tailcall\n");
7750 for (arg = j = 0; arg < pp->argc; arg++) {
7752 fprintf(fout, ", ");
7755 if (pp->arg[arg].type.is_ptr)
7756 snprintf(cast, sizeof(cast), "(%s)",
7757 pp->arg[arg].type.name);
7759 if (pp->arg[arg].reg != NULL) {
7760 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7764 for (; j < g_func_pp->argc; j++)
7765 if (g_func_pp->arg[j].reg == NULL)
7767 fprintf(fout, "%sa%d", cast, j + 1);
7772 for (arg = 0; arg < pp->argc; arg++) {
7774 fprintf(fout, ", ");
7777 if (pp->arg[arg].type.is_ptr)
7778 snprintf(cast, sizeof(cast), "(%s)",
7779 pp->arg[arg].type.name);
7781 if (pp->arg[arg].reg != NULL) {
7782 if (pp->arg[arg].type.is_retreg)
7783 fprintf(fout, "&%s", pp->arg[arg].reg);
7784 else if (IS(pp->arg[arg].reg, "ebp")
7785 && g_bp_frame && !(po->flags & OPF_EBP_S))
7787 // rare special case
7788 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7789 strcat(g_comment, " bp_ref");
7792 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7797 tmp_op = pp->arg[arg].datap;
7799 ferr(po, "parsed_op missing for arg%d\n", arg);
7801 if (tmp_op->flags & OPF_VAPUSH) {
7802 fprintf(fout, "ap");
7804 else if (tmp_op->op == OP_FST) {
7805 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7806 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7809 else if (pp->arg[arg].type.is_64bit) {
7810 ferr_assert(po, tmp_op->p_argpass == 0);
7811 ferr_assert(po, !pp->arg[arg].is_saved);
7812 ferr_assert(po, !pp->arg[arg].type.is_float);
7813 ferr_assert(po, cast[0] == 0);
7814 out_src_opr(buf1, sizeof(buf1),
7815 tmp_op, &tmp_op->operand[0], cast, 0);
7816 tmp_op = pp->arg[++arg].datap;
7817 ferr_assert(po, tmp_op != NULL);
7818 out_src_opr(buf2, sizeof(buf2),
7819 tmp_op, &tmp_op->operand[0], cast, 0);
7820 fprintf(fout, "((u64)(%s) << 32) | (%s)",
7823 else if (tmp_op->p_argpass != 0) {
7824 ferr_assert(po, !pp->arg[arg].type.is_float);
7825 fprintf(fout, "a%d", tmp_op->p_argpass);
7827 else if (pp->arg[arg].is_saved) {
7828 ferr_assert(po, tmp_op->p_argnum > 0);
7829 ferr_assert(po, !pp->arg[arg].type.is_float);
7830 fprintf(fout, "%s%s", cast,
7831 saved_arg_name(buf1, sizeof(buf1),
7832 tmp_op->p_arggrp, tmp_op->p_argnum));
7834 else if (pp->arg[arg].type.is_float) {
7835 ferr_assert(po, !pp->arg[arg].type.is_64bit);
7837 out_src_opr_float(buf1, sizeof(buf1),
7838 tmp_op, &tmp_op->operand[0], need_float_stack));
7842 out_src_opr(buf1, sizeof(buf1),
7843 tmp_op, &tmp_op->operand[0], cast, 0));
7847 fprintf(fout, ");");
7849 if (strstr(pp->ret_type.name, "int64")) {
7850 fprintf(fout, "\n");
7851 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7852 fprintf(fout, "%seax = tmp64;", buf3);
7855 if (pp->is_unresolved) {
7856 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7858 strcat(g_comment, buf2);
7861 if (po->flags & OPF_TAIL) {
7863 if (i == opcnt - 1 || pp->is_noreturn)
7865 else if (IS(pp->ret_type.name, "void"))
7867 else if (!(regmask_ret & (1 << xAX)))
7869 // else already handled as 'return f()'
7872 fprintf(fout, "\n%sreturn;", buf3);
7873 strcat(g_comment, " ^ tailcall");
7876 strcat(g_comment, " tailcall");
7878 if ((regmask_ret & (1 << xAX))
7879 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7881 ferr(po, "int func -> void func tailcall?\n");
7884 if (pp->is_noreturn)
7885 strcat(g_comment, " noreturn");
7886 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7887 strcat(g_comment, " argframe");
7888 if (po->flags & OPF_CC)
7889 strcat(g_comment, " cond");
7891 if (po->flags & OPF_CC)
7892 fprintf(fout, "\n }");
7894 delayed_flag_op = NULL;
7895 last_arith_dst = NULL;
7899 if (g_func_pp->is_vararg)
7900 fprintf(fout, " va_end(ap);\n");
7901 if (g_func_pp->has_retreg) {
7902 for (arg = 0; arg < g_func_pp->argc; arg++)
7903 if (g_func_pp->arg[arg].type.is_retreg)
7904 fprintf(fout, " *r_%s = %s;\n",
7905 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7908 if (regmask_ret & mxST0) {
7909 fprintf(fout, " return %s;", float_st0);
7911 else if (!(regmask_ret & mxAX)) {
7912 if (i != opcnt - 1 || label_pending)
7913 fprintf(fout, " return;");
7915 else if (g_func_pp->ret_type.is_ptr) {
7916 fprintf(fout, " return (%s)eax;",
7917 g_func_pp->ret_type.name);
7919 else if (IS(g_func_pp->ret_type.name, "__int64"))
7920 fprintf(fout, " return ((u64)edx << 32) | eax;");
7922 fprintf(fout, " return eax;");
7924 last_arith_dst = NULL;
7925 delayed_flag_op = NULL;
7929 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7930 if (po->p_argnum != 0) {
7931 // special case - saved func arg
7932 fprintf(fout, " %s = %s;",
7933 saved_arg_name(buf2, sizeof(buf2),
7934 po->p_arggrp, po->p_argnum), buf1);
7937 else if (po->flags & OPF_RSAVE) {
7938 fprintf(fout, " s_%s = %s;", buf1, buf1);
7941 else if (po->flags & OPF_PPUSH) {
7943 ferr_assert(po, tmp_op != NULL);
7944 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7945 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7948 else if (g_func_pp->is_userstack) {
7949 fprintf(fout, " *(--esp) = %s;", buf1);
7952 if (!(g_ida_func_attr & IDAFA_NORETURN))
7953 ferr(po, "stray push encountered\n");
7958 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7959 if (po->flags & OPF_RSAVE) {
7960 fprintf(fout, " %s = s_%s;", buf1, buf1);
7963 else if (po->flags & OPF_PPUSH) {
7964 // push/pop graph / non-const
7965 ferr_assert(po, po->datap == NULL);
7966 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7969 else if (po->datap != NULL) {
7972 fprintf(fout, " %s = %s;", buf1,
7973 out_src_opr(buf2, sizeof(buf2),
7974 tmp_op, &tmp_op->operand[0],
7975 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7978 else if (g_func_pp->is_userstack) {
7979 fprintf(fout, " %s = *esp++;", buf1);
7983 ferr(po, "stray pop encountered\n");
7993 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7994 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7995 po->op == OPP_ALLSHL ? "<<" : ">>");
7996 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7997 strcat(g_comment, po->op == OPP_ALLSHL
7998 ? " allshl" : " allshr");
8003 if (need_float_stack) {
8004 out_src_opr_float(buf1, sizeof(buf1),
8005 po, &po->operand[0], 1);
8006 if (po->regmask_src & mxSTa) {
8007 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
8011 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
8014 if (po->flags & OPF_FSHIFT)
8015 fprintf(fout, " f_st1 = f_st0;");
8016 if (po->operand[0].type == OPT_REG
8017 && po->operand[0].reg == xST0)
8019 strcat(g_comment, " fld st");
8022 fprintf(fout, " f_st0 = %s;",
8023 out_src_opr_float(buf1, sizeof(buf1),
8024 po, &po->operand[0], 0));
8026 strcat(g_comment, " fld");
8030 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
8031 lmod_cast(po, po->operand[0].lmod, 1), 0);
8032 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
8033 if (need_float_stack) {
8034 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
8037 if (po->flags & OPF_FSHIFT)
8038 fprintf(fout, " f_st1 = f_st0;");
8039 fprintf(fout, " f_st0 = %s;", buf2);
8041 strcat(g_comment, " fild");
8045 if (need_float_stack)
8046 fprintf(fout, " f_st[--f_stp & 7] = ");
8048 if (po->flags & OPF_FSHIFT)
8049 fprintf(fout, " f_st1 = f_st0;");
8050 fprintf(fout, " f_st0 = ");
8052 switch (po->operand[0].val) {
8053 case X87_CONST_1: fprintf(fout, "1.0;"); break;
8054 case X87_CONST_L2T: fprintf(fout, "3.321928094887362;"); break;
8055 case X87_CONST_L2E: fprintf(fout, "M_LOG2E;"); break;
8056 case X87_CONST_PI: fprintf(fout, "M_PI;"); break;
8057 case X87_CONST_LG2: fprintf(fout, "0.301029995663981;"); break;
8058 case X87_CONST_LN2: fprintf(fout, "M_LN2;"); break;
8059 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
8060 default: ferr_assert(po, 0); break;
8065 if (po->flags & OPF_FARG) {
8066 // store to stack as func arg
8067 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
8071 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8073 dead_dst = po->operand[0].type == OPT_REG
8074 && po->operand[0].reg == xST0;
8077 fprintf(fout, " %s = %s;", buf1, float_st0);
8078 if (po->flags & OPF_FSHIFT) {
8079 if (need_float_stack)
8080 fprintf(fout, " f_stp++;");
8082 fprintf(fout, " f_st0 = f_st1;");
8084 if (dead_dst && !(po->flags & OPF_FSHIFT))
8087 strcat(g_comment, " fst");
8091 fprintf(fout, " %s = %s%s;",
8092 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
8093 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
8094 if (po->flags & OPF_FSHIFT) {
8095 if (need_float_stack)
8096 fprintf(fout, " f_stp++;");
8098 fprintf(fout, " f_st0 = f_st1;");
8100 strcat(g_comment, " fist");
8107 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8109 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8111 dead_dst = (po->flags & OPF_FPOP)
8112 && po->operand[0].type == OPT_REG
8113 && po->operand[0].reg == xST0;
8115 case OP_FADD: j = '+'; break;
8116 case OP_FDIV: j = '/'; break;
8117 case OP_FMUL: j = '*'; break;
8118 case OP_FSUB: j = '-'; break;
8119 default: j = 'x'; break;
8121 if (need_float_stack) {
8123 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
8124 if (po->flags & OPF_FSHIFT)
8125 fprintf(fout, " f_stp++;");
8128 if (po->flags & OPF_FSHIFT) {
8129 // note: assumes only 2 regs handled
8131 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
8133 fprintf(fout, " f_st0 = f_st1;");
8136 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
8138 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
8143 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8145 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8147 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
8149 dead_dst = (po->flags & OPF_FPOP)
8150 && po->operand[0].type == OPT_REG
8151 && po->operand[0].reg == xST0;
8152 j = po->op == OP_FDIVR ? '/' : '-';
8153 if (need_float_stack) {
8155 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
8156 if (po->flags & OPF_FSHIFT)
8157 fprintf(fout, " f_stp++;");
8160 if (po->flags & OPF_FSHIFT) {
8162 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
8164 fprintf(fout, " f_st0 = f_st1;");
8167 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
8169 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
8177 case OP_FIADD: j = '+'; break;
8178 case OP_FIDIV: j = '/'; break;
8179 case OP_FIMUL: j = '*'; break;
8180 case OP_FISUB: j = '-'; break;
8181 default: j = 'x'; break;
8183 fprintf(fout, " %s %c= (%s)%s;", float_st0,
8185 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
8186 lmod_cast(po, po->operand[0].lmod, 1), 0));
8191 fprintf(fout, " %s = %s %c %s;", float_st0,
8192 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8194 po->op == OP_FIDIVR ? '/' : '-', float_st0);
8199 ferr_assert(po, po->datap != NULL);
8200 mask = (long)po->datap & 0xffff;
8201 z_check = ((long)po->datap >> 16) & 1;
8202 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8204 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
8205 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
8208 else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
8209 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
8212 else if (mask == 0x4100) { // C3, C0
8214 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
8216 strcat(g_comment, " z_chk_det");
8219 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
8220 "(%s < %s ? 0x0100 : 0);",
8221 float_st0, buf1, float_st0, buf1);
8225 ferr(po, "unhandled sw mask: %x\n", mask);
8226 if (po->flags & OPF_FSHIFT) {
8227 if (need_float_stack) {
8228 if (po->flags & OPF_FPOPP)
8229 fprintf(fout, " f_stp += 2;");
8231 fprintf(fout, " f_stp++;");
8234 ferr_assert(po, !(po->flags & OPF_FPOPP));
8235 fprintf(fout, " f_st0 = f_st1;");
8242 fprintf(fout, " %s = f_sw;",
8243 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
8247 fprintf(fout, " %s = -%s;", float_st0, float_st0);
8251 fprintf(fout, " %s = cos%s(%s);", float_st0,
8252 need_double ? "" : "f", float_st0);
8256 if (need_float_stack) {
8257 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
8258 need_double ? "" : "f", float_st1, float_st0);
8259 fprintf(fout, " f_stp++;");
8262 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
8263 need_double ? "" : "f");
8268 if (need_float_stack) {
8269 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
8270 float_st1, need_double ? "" : "f", float_st0);
8271 fprintf(fout, " f_stp++;");
8274 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
8275 need_double ? "" : "f");
8277 strcat(g_comment, " fyl2x");
8281 fprintf(fout, " %s = sin%s(%s);", float_st0,
8282 need_double ? "" : "f", float_st0);
8286 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
8287 need_double ? "" : "f", float_st0);
8291 dead_dst = po->operand[0].type == OPT_REG
8292 && po->operand[0].reg == xST0;
8294 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8296 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
8297 float_st0, float_st0, buf1, buf1);
8298 strcat(g_comment, " fxch");
8305 ferr_assert(po, po->flags & OPF_32BIT);
8306 fprintf(fout, " eax = (s32)%s;", float_st0);
8307 if (po->flags & OPF_FSHIFT) {
8308 if (need_float_stack)
8309 fprintf(fout, " f_stp++;");
8311 fprintf(fout, " f_st0 = f_st1;");
8313 strcat(g_comment, " ftol");
8317 if (need_float_stack) {
8318 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
8319 need_double ? "" : "f", float_st1, float_st0);
8320 fprintf(fout, " f_stp++;");
8323 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
8324 need_double ? "" : "f");
8326 strcat(g_comment, " CIpow");
8330 fprintf(fout, " do_skip_code_abort();");
8335 fprintf(fout, " do_emms();");
8340 ferr(po, "unhandled op type %d, flags %x\n",
8345 if (g_comment[0] != 0) {
8346 char *p = g_comment;
8347 while (my_isblank(*p))
8349 fprintf(fout, " // %s", p);
8354 fprintf(fout, "\n");
8356 // some sanity checking
8357 if (po->flags & OPF_REP) {
8358 if (po->op != OP_STOS && po->op != OP_MOVS
8359 && po->op != OP_CMPS && po->op != OP_SCAS)
8360 ferr(po, "unexpected rep\n");
8361 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
8362 && (po->op == OP_CMPS || po->op == OP_SCAS))
8363 ferr(po, "cmps/scas with plain rep\n");
8365 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
8366 && po->op != OP_CMPS && po->op != OP_SCAS)
8367 ferr(po, "unexpected repz/repnz\n");
8370 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
8372 if ((po->flags & OPF_LOCK) && !lock_handled)
8373 ferr(po, "unhandled lock\n");
8375 // see is delayed flag stuff is still valid
8376 if (delayed_flag_op != NULL && delayed_flag_op != po) {
8377 if (is_any_opr_modified(delayed_flag_op, po, 0))
8378 delayed_flag_op = NULL;
8381 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
8382 if (is_opr_modified(last_arith_dst, po))
8383 last_arith_dst = NULL;
8390 if (g_stack_fsz && !g_stack_frame_used)
8391 fprintf(fout, " (void)sf;\n");
8393 fprintf(fout, "}\n\n");
8395 gen_x_cleanup(opcnt);
8398 static void gen_x_cleanup(int opcnt)
8402 for (i = 0; i < opcnt; i++) {
8403 struct label_ref *lr, *lr_del;
8405 lr = g_label_refs[i].next;
8406 while (lr != NULL) {
8411 g_label_refs[i].i = -1;
8412 g_label_refs[i].next = NULL;
8414 if (ops[i].op == OP_CALL) {
8416 proto_release(ops[i].pp);
8422 struct func_proto_dep;
8424 struct func_prototype {
8428 int regmask_dep; // likely register args
8429 int regmask_use; // used registers
8430 int has_ret:3; // -1, 0, 1: unresolved, no, yes
8431 unsigned int has_ret64:1;
8432 unsigned int dep_resolved:1;
8433 unsigned int is_stdcall:1;
8434 unsigned int eax_pass:1; // returns without touching eax
8435 unsigned int ptr_taken:1; // pointer taken of this func
8436 struct func_proto_dep *dep_func;
8438 const struct parsed_proto *pp; // seed pp, if any
8441 struct func_proto_dep {
8443 struct func_prototype *proto;
8444 int regmask_live; // .. at the time of call
8445 unsigned int ret_dep:1; // return from this is caller's return
8446 unsigned int has_ret:1; // found from eax use after return
8447 unsigned int has_ret64:1;
8448 unsigned int ptr_taken:1; // pointer taken, not a call
8451 static struct func_prototype *hg_fp;
8452 static int hg_fp_cnt;
8454 static struct scanned_var {
8456 enum opr_lenmod lmod;
8457 unsigned int is_seeded:1;
8458 unsigned int is_c_str:1;
8459 const struct parsed_proto *pp; // seed pp, if any
8461 static int hg_var_cnt;
8463 static char **hg_refs;
8464 static int hg_ref_cnt;
8466 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8469 static struct func_prototype *hg_fp_add(const char *funcn)
8471 struct func_prototype *fp;
8473 if ((hg_fp_cnt & 0xff) == 0) {
8474 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
8475 my_assert_not(hg_fp, NULL);
8476 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
8479 fp = &hg_fp[hg_fp_cnt];
8480 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
8482 fp->argc_stack = -1;
8488 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
8493 for (i = 0; i < fp->dep_func_cnt; i++)
8494 if (IS(fp->dep_func[i].name, name))
8495 return &fp->dep_func[i];
8500 static void hg_fp_add_dep(struct func_prototype *fp, const char *name,
8501 unsigned int ptr_taken)
8503 struct func_proto_dep * dep;
8506 dep = hg_fp_find_dep(fp, name);
8507 if (dep != NULL && dep->ptr_taken == ptr_taken)
8510 if ((fp->dep_func_cnt & 0xff) == 0) {
8511 fp->dep_func = realloc(fp->dep_func,
8512 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
8513 my_assert_not(fp->dep_func, NULL);
8514 memset(&fp->dep_func[fp->dep_func_cnt], 0,
8515 sizeof(fp->dep_func[0]) * 0x100);
8517 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
8518 fp->dep_func[fp->dep_func_cnt].ptr_taken = ptr_taken;
8522 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
8524 const struct func_prototype *p1 = p1_, *p2 = p2_;
8525 return strcmp(p1->name, p2->name);
8529 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
8531 const struct func_prototype *p1 = p1_, *p2 = p2_;
8532 return p1->id - p2->id;
8536 static void hg_ref_add(const char *name)
8538 if ((hg_ref_cnt & 0xff) == 0) {
8539 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8540 my_assert_not(hg_refs, NULL);
8541 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8544 hg_refs[hg_ref_cnt] = strdup(name);
8545 my_assert_not(hg_refs[hg_ref_cnt], NULL);
8549 // recursive register dep pass
8550 // - track saved regs (part 2)
8551 // - try to figure out arg-regs
8552 // - calculate reg deps
8553 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8554 struct func_prototype *fp, int regmask_save, int regmask_dst,
8555 int *regmask_dep, int *regmask_use, int *has_ret)
8557 struct func_proto_dep *dep;
8558 struct parsed_op *po;
8559 int from_caller = 0;
8564 for (; i < opcnt; i++)
8566 if (cbits[i >> 3] & (1 << (i & 7)))
8568 cbits[i >> 3] |= (1 << (i & 7));
8572 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8573 if (po->flags & OPF_RMD)
8576 if (po->btj != NULL) {
8578 for (j = 0; j < po->btj->count; j++) {
8579 check_i(po, po->btj->d[j].bt_i);
8580 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8581 regmask_save, regmask_dst, regmask_dep, regmask_use,
8587 check_i(po, po->bt_i);
8588 if (po->flags & OPF_CJMP) {
8589 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8590 regmask_save, regmask_dst, regmask_dep, regmask_use,
8599 if (po->flags & OPF_FARG)
8600 /* (just calculate register deps) */;
8601 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8603 reg = po->operand[0].reg;
8604 ferr_assert(po, reg >= 0);
8606 if (po->flags & OPF_RSAVE) {
8607 regmask_save |= 1 << reg;
8610 if (po->flags & OPF_DONE)
8613 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2,
8616 regmask_save |= 1 << reg;
8617 po->flags |= OPF_RMD;
8618 scan_for_pop(i + 1, opcnt, i + opcnt * 3,
8619 reg, 0, 0, 0, OPF_RMD);
8623 else if (po->flags & OPF_RMD)
8625 else if (po->op == OP_CALL) {
8626 po->regmask_dst |= 1 << xAX;
8628 dep = hg_fp_find_dep(fp, po->operand[0].name);
8630 dep->regmask_live = regmask_save | regmask_dst;
8631 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8632 dep->regmask_live |= 1 << xBP;
8635 else if (po->op == OP_RET) {
8636 if (po->operand_cnt > 0) {
8638 if (fp->argc_stack >= 0
8639 && fp->argc_stack != po->operand[0].val / 4)
8640 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8641 fp->argc_stack = po->operand[0].val / 4;
8645 if (!fp->eax_pass && (po->flags & OPF_TAIL)) {
8646 if (po->op == OP_CALL) {
8653 ret = resolve_origin_reg(i, xAX, i + opcnt * 4, &j, &from_caller);
8656 if (ret != 1 && from_caller) {
8657 // unresolved eax - probably void func
8662 if (j >= 0 && ops[j].op == OP_CALL) {
8663 if (ops[j].pp != NULL && !ops[j].pp->is_unresolved) {
8664 int call_has_ret = !IS(ops[j].pp->ret_type.name, "void");
8665 if (ops[j].pp->is_noreturn) {
8666 // could be some fail path
8668 *has_ret = call_has_ret;
8671 *has_ret = call_has_ret;
8674 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8686 l = regmask_save | regmask_dst;
8687 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8690 l = po->regmask_src & ~l;
8693 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8694 l, regmask_dst, regmask_save, po->flags);
8697 *regmask_use |= (po->regmask_src | po->regmask_dst)
8699 regmask_dst |= po->regmask_dst;
8701 if (po->flags & OPF_TAIL) {
8702 if (!(po->flags & OPF_CC)) // not cond. tailcall
8708 static void gen_hdr(const char *funcn, int opcnt)
8710 unsigned char cbits[MAX_OPS / 8];
8711 const struct parsed_proto *pp_c;
8712 struct parsed_proto *pp;
8713 struct func_prototype *fp;
8714 struct func_proto_dep *dep;
8715 struct parsed_op *po;
8716 const char *tmpname;
8717 int regmask_dummy = 0;
8720 int max_bp_offset = 0;
8725 pp_c = proto_parse(g_fhdr, funcn, 1);
8727 // already in seed, will add to hg_fp later
8730 fp = hg_fp_add(funcn);
8732 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8733 g_stack_frame_used = 0;
8737 // - resolve all branches
8738 // - parse calls with labels
8739 resolve_branches_parse_calls(opcnt);
8742 // - handle ebp/esp frame, remove ops related to it
8743 scan_prologue_epilogue(opcnt, NULL);
8746 // - remove dead labels
8748 // - collect function ptr refs
8749 for (i = 0; i < opcnt; i++)
8751 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8757 if (po->flags & (OPF_RMD|OPF_DONE))
8760 if (po->op == OP_CALL) {
8761 if (po->operand[0].type == OPT_LABEL)
8762 hg_fp_add_dep(fp, opr_name(po, 0), 0);
8763 else if (po->pp != NULL)
8764 hg_fp_add_dep(fp, po->pp->name, 0);
8766 else if (po->op == OP_MOV && po->operand[1].type == OPT_OFFSET) {
8767 tmpname = opr_name(po, 1);
8768 if (IS_START(tmpname, "p_") || IS_START(tmpname, "sub_"))
8769 hg_fp_add_dep(fp, tmpname, 1);
8771 else if (po->op == OP_PUSH && po->operand[0].type == OPT_OFFSET) {
8772 tmpname = opr_name(po, 0);
8773 if (IS_START(tmpname, "p_") || IS_START(tmpname, "sub_"))
8774 hg_fp_add_dep(fp, tmpname, 1);
8779 // - handle push <const>/pop pairs
8780 for (i = 0; i < opcnt; i++)
8783 if (po->flags & (OPF_RMD|OPF_DONE))
8786 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8787 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8791 // - process trivial calls
8792 for (i = 0; i < opcnt; i++)
8795 if (po->flags & (OPF_RMD|OPF_DONE))
8798 if (po->op == OP_CALL)
8800 pp = process_call_early(i, opcnt, &j);
8802 if (!(po->flags & OPF_ATAIL))
8803 // since we know the args, try to collect them
8804 if (collect_call_args_early(i, opcnt, pp, NULL, NULL) != 0)
8810 // commit esp adjust
8811 if (ops[j].op != OP_POP)
8812 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8814 for (l = 0; l < pp->argc_stack; l++)
8815 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8819 po->flags |= OPF_DONE;
8825 // - track saved regs (simple)
8827 for (i = 0; i < opcnt; i++)
8830 if (po->flags & (OPF_RMD|OPF_DONE))
8833 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8834 && po->operand[0].reg != xCX)
8836 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8838 // regmask_save |= 1 << po->operand[0].reg; // do it later
8839 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8840 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8843 else if (po->op == OP_CALL)
8845 pp = process_call(i, opcnt);
8847 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8848 // since we know the args, collect them
8849 ret = collect_call_args(po, i, opcnt, pp, ®mask_dummy,
8852 if (!(po->flags & OPF_TAIL)
8853 && po->operand[0].type == OPT_LABEL)
8855 dep = hg_fp_find_dep(fp, opr_name(po, 0));
8856 ferr_assert(po, dep != NULL);
8857 // treat al write as overwrite to avoid many false positives
8858 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
8859 i + opcnt * 25, &j);
8862 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
8863 i + opcnt * 26, &j);
8864 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j]))
8871 memset(cbits, 0, (opcnt + 7) / 8);
8872 regmask_dep = regmask_use = 0;
8875 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0,
8876 ®mask_dep, ®mask_use, &has_ret);
8878 // find unreachable code - must be fixed in IDA
8879 for (i = 0; i < opcnt; i++)
8881 if (cbits[i >> 3] & (1 << (i & 7)))
8884 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8885 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8887 // the compiler sometimes still generates code after
8888 // noreturn OS functions
8891 if (!(ops[i].flags & OPF_RMD)
8892 && ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8894 ferr(&ops[i], "unreachable code\n");
8898 for (i = 0; i < g_eqcnt; i++) {
8899 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8900 max_bp_offset = g_eqs[i].offset;
8903 if (fp->argc_stack < 0) {
8904 max_bp_offset = (max_bp_offset + 3) & ~3;
8905 fp->argc_stack = max_bp_offset / 4;
8906 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8910 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8911 fp->regmask_use = regmask_use;
8912 fp->has_ret = has_ret;
8914 printf("// has_ret %d, regmask_dep %x\n",
8915 fp->has_ret, fp->regmask_dep);
8916 output_hdr_fp(stdout, fp, 1);
8917 if (IS(funcn, "sub_10007F72")) exit(1);
8920 gen_x_cleanup(opcnt);
8923 static void hg_fp_resolve_deps(struct func_prototype *fp)
8925 struct func_prototype fp_s;
8926 struct func_proto_dep *dep;
8930 // this thing is recursive, so mark first..
8931 fp->dep_resolved = 1;
8933 for (i = 0; i < fp->dep_func_cnt; i++) {
8934 dep = &fp->dep_func[i];
8936 strcpy(fp_s.name, dep->name);
8937 dep->proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8938 sizeof(hg_fp[0]), hg_fp_cmp_name);
8939 if (dep->proto != NULL) {
8940 if (dep->ptr_taken) {
8941 dep->proto->ptr_taken = 1;
8945 if (!dep->proto->dep_resolved)
8946 hg_fp_resolve_deps(dep->proto);
8948 regmask_dep = ~dep->regmask_live
8949 & dep->proto->regmask_dep;
8950 fp->regmask_dep |= regmask_dep;
8951 // printf("dep %s %s |= %x\n", fp->name,
8952 // fp->dep_func[i].name, regmask_dep);
8954 if (dep->has_ret && (dep->proto->regmask_use & mxAX))
8955 dep->proto->has_ret = 1;
8956 if (dep->has_ret64 && (dep->proto->regmask_use & mxDX))
8957 dep->proto->has_ret64 = 1;
8958 if (fp->has_ret == -1 && dep->ret_dep)
8959 fp->has_ret = dep->proto->has_ret;
8964 // make all thiscall/edx arg functions referenced from .data fastcall
8965 static void do_func_refs_from_data(void)
8967 struct func_prototype *fp, fp_s;
8970 for (i = 0; i < hg_ref_cnt; i++) {
8971 strcpy(fp_s.name, hg_refs[i]);
8972 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8973 sizeof(hg_fp[0]), hg_fp_cmp_name);
8979 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8982 const struct parsed_proto *pp;
8983 char *p, namebuf[NAMELEN];
8989 for (; count > 0; count--, fp++) {
8990 if (fp->has_ret == -1)
8991 fprintf(fout, "// ret unresolved\n");
8993 fprintf(fout, "// dep:");
8994 for (j = 0; j < fp->dep_func_cnt; j++) {
8995 fprintf(fout, " %s/", fp->dep_func[j].name);
8996 if (fp->dep_func[j].proto != NULL)
8997 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8998 fp->dep_func[j].proto->has_ret);
9000 fprintf(fout, "\n");
9003 p = strchr(fp->name, '@');
9005 memcpy(namebuf, fp->name, p - fp->name);
9006 namebuf[p - fp->name] = 0;
9014 pp = proto_parse(g_fhdr, name, 1);
9015 if (pp != NULL && pp->is_include)
9018 if (fp->pp != NULL) {
9019 // part of seed, output later
9023 regmask_dep = fp->regmask_dep;
9024 argc_normal = fp->argc_stack;
9025 if (fp->ptr_taken && regmask_dep
9026 && (regmask_dep & ~(mxCX|mxDX)) == 0)
9028 if ((regmask_dep & mxDX) || fp->argc_stack > 0)
9029 regmask_dep |= mxCX | mxDX;
9032 fprintf(fout, "%-5s",
9033 fp->pp ? fp->pp->ret_type.name :
9034 fp->has_ret64 ? "__int64" :
9035 fp->has_ret ? "int" : "void");
9036 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
9037 && (regmask_dep & ~mxCX) == 0)
9039 fprintf(fout, "/*__thiscall*/ ");
9043 else if ((regmask_dep == (mxCX | mxDX)
9044 && (fp->is_stdcall || fp->argc_stack == 0))
9045 || (regmask_dep == mxCX && fp->argc_stack == 0))
9047 fprintf(fout, " __fastcall ");
9048 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
9054 else if (regmask_dep && !fp->is_stdcall) {
9055 fprintf(fout, "/*__usercall*/ ");
9057 else if (regmask_dep) {
9058 fprintf(fout, "/*__userpurge*/ ");
9060 else if (fp->is_stdcall)
9061 fprintf(fout, " __stdcall ");
9063 fprintf(fout, " __cdecl ");
9065 fprintf(fout, "%s(", name);
9068 for (j = 0; j < xSP; j++) {
9069 if (regmask_dep & (1 << j)) {
9072 fprintf(fout, ", ");
9074 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
9076 fprintf(fout, "int");
9077 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
9081 for (j = 0; j < argc_normal; j++) {
9084 fprintf(fout, ", ");
9085 if (fp->pp != NULL) {
9086 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
9087 if (!fp->pp->arg[arg - 1].type.is_ptr)
9091 fprintf(fout, "int ");
9092 fprintf(fout, "a%d", arg);
9095 fprintf(fout, ");\n");
9099 static void output_hdr(FILE *fout)
9101 static const char *lmod_c_names[] = {
9102 [OPLM_UNSPEC] = "???",
9103 [OPLM_BYTE] = "uint8_t",
9104 [OPLM_WORD] = "uint16_t",
9105 [OPLM_DWORD] = "uint32_t",
9106 [OPLM_QWORD] = "uint64_t",
9108 const struct scanned_var *var;
9109 struct func_prototype *fp;
9110 char line[256] = { 0, };
9114 // add stuff from headers
9115 for (i = 0; i < pp_cache_size; i++) {
9116 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
9117 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
9119 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
9120 fp = hg_fp_add(name);
9121 fp->pp = &pp_cache[i];
9122 fp->argc_stack = fp->pp->argc_stack;
9123 fp->is_stdcall = fp->pp->is_stdcall;
9124 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
9125 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
9129 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
9130 for (i = 0; i < hg_fp_cnt; i++)
9131 hg_fp_resolve_deps(&hg_fp[i]);
9133 // adjust functions referenced from data segment
9134 do_func_refs_from_data();
9136 // final adjustments
9137 for (i = 0; i < hg_fp_cnt; i++) {
9138 if (hg_fp[i].eax_pass && (hg_fp[i].regmask_dep & mxAX))
9139 hg_fp[i].has_ret = 1;
9142 // note: messes up .proto ptr, don't use
9143 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
9146 for (i = 0; i < hg_var_cnt; i++) {
9149 if (var->pp != NULL)
9152 else if (var->is_c_str)
9153 fprintf(fout, "extern %-8s %s[];", "char", var->name);
9155 fprintf(fout, "extern %-8s %s;",
9156 lmod_c_names[var->lmod], var->name);
9159 fprintf(fout, " // seeded");
9160 fprintf(fout, "\n");
9163 fprintf(fout, "\n");
9165 // output function prototypes
9166 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
9169 fprintf(fout, "\n// - seed -\n");
9172 while (fgets(line, sizeof(line), g_fhdr))
9173 fwrite(line, 1, strlen(line), fout);
9176 // '=' needs special treatment
9178 static char *next_word_s(char *w, size_t wsize, char *s)
9185 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
9187 for (i = 1; i < wsize - 1; i++) {
9189 printf("warning: missing closing quote: \"%s\"\n", s);
9198 for (; i < wsize - 1; i++) {
9199 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
9205 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
9206 printf("warning: '%s' truncated\n", w);
9211 static int cmpstringp(const void *p1, const void *p2)
9213 return strcmp(*(char * const *)p1, *(char * const *)p2);
9216 static int is_xref_needed(char *p, char **rlist, int rlist_len)
9221 if (strstr(p, "..."))
9222 // unable to determine, assume needed
9225 if (*p == '.') // .text, .data, ...
9226 // ref from other data or non-function -> no
9229 p2 = strpbrk(p, "+:\r\n\x18");
9232 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9233 // referenced from removed code
9239 static int ida_xrefs_show_need(FILE *fasm, char *p,
9240 char **rlist, int rlist_len)
9246 p = strrchr(p, ';');
9247 if (p != NULL && *p == ';') {
9248 if (IS_START(p + 2, "sctref"))
9250 if (IS_START(p + 2, "DATA XREF: ")) {
9252 if (is_xref_needed(p, rlist, rlist_len))
9260 if (!my_fgets(line, sizeof(line), fasm))
9262 // non-first line is always indented
9263 if (!my_isblank(line[0]))
9266 // should be no content, just comment
9271 p = strrchr(p, ';');
9274 if (IS_START(p, "sctref")) {
9279 // it's printed once, but no harm to check again
9280 if (IS_START(p, "DATA XREF: "))
9283 if (is_xref_needed(p, rlist, rlist_len)) {
9288 fseek(fasm, pos, SEEK_SET);
9292 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
9294 struct scanned_var *var;
9295 char line[256] = { 0, };
9304 // skip to next data section
9305 while (my_fgets(line, sizeof(line), fasm))
9310 if (*p == 0 || *p == ';')
9313 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
9314 if (*p == 0 || *p == ';')
9317 if (*p != 's' || !IS_START(p, "segment para public"))
9323 if (p == NULL || !IS_START(p, "segment para public"))
9327 if (!IS_START(p, "'DATA'"))
9331 while (my_fgets(line, sizeof(line), fasm))
9336 no_identifier = my_isblank(*p);
9339 if (*p == 0 || *p == ';')
9342 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9343 words[wordc][0] = 0;
9344 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9345 if (*p == 0 || *p == ';') {
9351 if (wordc == 2 && IS(words[1], "ends"))
9356 if (no_identifier) {
9357 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
9358 hg_ref_add(words[2]);
9362 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
9363 // when this starts, we don't need anything from this section
9367 // check refs comment(s)
9368 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
9371 if ((hg_var_cnt & 0xff) == 0) {
9372 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
9373 * (hg_var_cnt + 0x100));
9374 my_assert_not(hg_vars, NULL);
9375 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
9378 var = &hg_vars[hg_var_cnt++];
9379 snprintf(var->name, sizeof(var->name), "%s", words[0]);
9381 // maybe already in seed header?
9382 var->pp = proto_parse(g_fhdr, var->name, 1);
9383 if (var->pp != NULL) {
9384 if (var->pp->is_fptr) {
9385 var->lmod = OPLM_DWORD;
9388 else if (var->pp->is_func)
9390 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
9391 aerr("unhandled C type '%s' for '%s'\n",
9392 var->pp->type.name, var->name);
9398 if (IS(words[1], "dd")) {
9399 var->lmod = OPLM_DWORD;
9400 if (wordc >= 4 && IS(words[2], "offset"))
9401 hg_ref_add(words[3]);
9403 else if (IS(words[1], "dw"))
9404 var->lmod = OPLM_WORD;
9405 else if (IS(words[1], "db")) {
9406 var->lmod = OPLM_BYTE;
9407 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
9408 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
9412 else if (IS(words[1], "dq"))
9413 var->lmod = OPLM_QWORD;
9414 //else if (IS(words[1], "dt"))
9416 aerr("type '%s' not known\n", words[1]);
9424 static void set_label(int i, const char *name)
9430 p = strchr(name, ':');
9434 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
9435 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
9436 g_labels[i] = realloc(g_labels[i], len + 1);
9437 my_assert_not(g_labels[i], NULL);
9438 memcpy(g_labels[i], name, len);
9439 g_labels[i][len] = 0;
9448 static struct chunk_item *func_chunks;
9449 static int func_chunk_cnt;
9450 static int func_chunk_alloc;
9452 static void add_func_chunk(FILE *fasm, const char *name, int line)
9454 if (func_chunk_cnt >= func_chunk_alloc) {
9455 func_chunk_alloc *= 2;
9456 func_chunks = realloc(func_chunks,
9457 func_chunk_alloc * sizeof(func_chunks[0]));
9458 my_assert_not(func_chunks, NULL);
9460 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
9461 func_chunks[func_chunk_cnt].name = strdup(name);
9462 func_chunks[func_chunk_cnt].asmln = line;
9466 static int cmp_chunks(const void *p1, const void *p2)
9468 const struct chunk_item *c1 = p1, *c2 = p2;
9469 return strcmp(c1->name, c2->name);
9472 static void scan_ahead_for_chunks(FILE *fasm)
9482 oldpos = ftell(fasm);
9485 while (my_fgets(line, sizeof(line), fasm))
9496 // get rid of random tabs
9497 for (i = 0; line[i] != 0; i++)
9498 if (line[i] == '\t')
9501 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9504 next_word(words[0], sizeof(words[0]), p);
9505 if (words[0][0] == 0)
9506 aerr("missing name for func chunk?\n");
9508 add_func_chunk(fasm, words[0], asmln);
9510 else if (IS_START(p, "; sctend"))
9516 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9517 words[wordc][0] = 0;
9518 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9519 if (*p == 0 || *p == ';') {
9525 if (wordc == 2 && IS(words[1], "ends"))
9529 fseek(fasm, oldpos, SEEK_SET);
9533 int main(int argc, char *argv[])
9535 FILE *fout, *fasm, *frlist;
9536 struct parsed_data *pd = NULL;
9538 char **rlist = NULL;
9540 int rlist_alloc = 0;
9541 int func_chunks_used = 0;
9542 int func_chunks_sorted = 0;
9543 int func_chunk_i = -1;
9544 long func_chunk_ret = 0;
9545 int func_chunk_ret_ln = 0;
9546 int scanned_ahead = 0;
9548 char words[20][256];
9549 enum opr_lenmod lmod;
9550 char *sctproto = NULL;
9552 int pending_endp = 0;
9554 int skip_code_end = 0;
9555 int skip_warned = 0;
9568 for (arg = 1; arg < argc; arg++) {
9569 if (IS(argv[arg], "-v"))
9571 else if (IS(argv[arg], "-rf"))
9572 g_allow_regfunc = 1;
9573 else if (IS(argv[arg], "-uc"))
9574 g_allow_user_icall = 1;
9575 else if (IS(argv[arg], "-wu"))
9576 g_nowarn_reguse = 1;
9577 else if (IS(argv[arg], "-m"))
9579 else if (IS(argv[arg], "-hdr"))
9580 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
9585 if (argc < arg + 3) {
9586 printf("usage:\n%s [options] <.c> <.asm> <hdr.h> [rlist]*\n"
9587 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
9589 " -hdr - header generation mode\n"
9590 " -rf - allow unannotated indirect calls\n"
9591 " -uc - allow ind. calls/refs to __usercall\n"
9592 " -m - allow multiple .text sections\n"
9593 " -wu - don't warn about bad reg use\n"
9594 "[rlist] is a file with function names to skip,"
9602 asmfn = argv[arg++];
9603 fasm = fopen(asmfn, "r");
9604 my_assert_not(fasm, NULL);
9606 hdrfn = argv[arg++];
9607 g_fhdr = fopen(hdrfn, "r");
9608 my_assert_not(g_fhdr, NULL);
9611 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9612 my_assert_not(rlist, NULL);
9613 // needs special handling..
9614 rlist[rlist_len++] = "__alloca_probe";
9616 func_chunk_alloc = 32;
9617 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9618 my_assert_not(func_chunks, NULL);
9620 memset(words, 0, sizeof(words));
9622 for (; arg < argc; arg++) {
9625 frlist = fopen(argv[arg], "r");
9626 my_assert_not(frlist, NULL);
9628 while (my_fgets(line, sizeof(line), frlist)) {
9630 if (*p == 0 || *p == ';')
9633 if (IS_START(p, "#if 0")
9634 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9638 else if (IS_START(p, "#endif"))
9645 p = next_word(words[0], sizeof(words[0]), p);
9646 if (words[0][0] == 0)
9649 if (rlist_len >= rlist_alloc) {
9650 rlist_alloc = rlist_alloc * 2 + 64;
9651 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9652 my_assert_not(rlist, NULL);
9654 rlist[rlist_len++] = strdup(words[0]);
9662 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9664 fout = fopen(argv[arg_out], "w");
9665 my_assert_not(fout, NULL);
9668 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9669 my_assert_not(g_eqs, NULL);
9671 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9672 g_label_refs[i].i = -1;
9673 g_label_refs[i].next = NULL;
9677 scan_variables(fasm, rlist, rlist_len);
9679 while (my_fgets(line, sizeof(line), fasm))
9688 // get rid of random tabs
9689 for (i = 0; line[i] != 0; i++)
9690 if (line[i] == '\t')
9695 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9696 goto do_pending_endp; // eww..
9698 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9700 static const char *attrs[] = {
9709 // parse IDA's attribute-list comment
9710 g_ida_func_attr = 0;
9713 for (; *p != 0; p = sskip(p)) {
9714 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9715 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9716 g_ida_func_attr |= 1 << i;
9717 p += strlen(attrs[i]);
9721 if (i == ARRAY_SIZE(attrs)) {
9722 anote("unparsed IDA attr: %s\n", p);
9725 if (IS(attrs[i], "fpd=")) {
9726 p = next_word(words[0], sizeof(words[0]), p);
9731 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9733 static const char *attrs[] = {
9741 // parse manual attribute-list comment
9742 g_sct_func_attr = 0;
9745 for (; *p != 0; p = sskip(p)) {
9746 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9747 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9748 g_sct_func_attr |= 1 << i;
9749 p += strlen(attrs[i]);
9756 // clear_sf=start,len (in dwords)
9757 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9758 &g_stack_clear_len, &j);
9760 // clear_regmask=<mask>
9761 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9763 // rm_regmask=<mask>
9764 ret = sscanf(p, "=%x%n", &g_regmask_rm, &j) + 1;
9766 anote("unparsed attr value: %s\n", p);
9771 else if (i == ARRAY_SIZE(attrs)) {
9772 anote("unparsed sct attr: %s\n", p);
9777 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9780 next_word(words[0], sizeof(words[0]), p);
9781 if (words[0][0] == 0)
9782 aerr("missing name for func chunk?\n");
9784 if (!scanned_ahead) {
9785 add_func_chunk(fasm, words[0], asmln);
9786 func_chunks_sorted = 0;
9789 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9791 if (func_chunk_i >= 0) {
9792 if (func_chunk_i < func_chunk_cnt
9793 && IS(func_chunks[func_chunk_i].name, g_func))
9795 // move on to next chunk
9796 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9798 aerr("seek failed for '%s' chunk #%d\n",
9799 g_func, func_chunk_i);
9800 asmln = func_chunks[func_chunk_i].asmln;
9804 if (func_chunk_ret == 0)
9805 aerr("no return from chunk?\n");
9806 fseek(fasm, func_chunk_ret, SEEK_SET);
9807 asmln = func_chunk_ret_ln;
9813 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9814 func_chunks_used = 1;
9816 if (IS_START(g_func, "sub_")) {
9817 unsigned long addr = strtoul(p, NULL, 16);
9818 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9819 if (addr > f_addr && !scanned_ahead) {
9820 //anote("scan_ahead caused by '%s', addr %lx\n",
9822 scan_ahead_for_chunks(fasm);
9824 func_chunks_sorted = 0;
9832 for (i = wordc; i < ARRAY_SIZE(words); i++)
9834 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9835 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9836 if (*p == 0 || *p == ';') {
9841 if (*p != 0 && *p != ';')
9842 aerr("too many words\n");
9844 if (skip_code_end) {
9849 // allow asm patches in comments
9851 // skip IDA's forced non-removable comment
9852 if (!IS_START(p, "; sct") && (p2 = strchr(p + 1, ';')))
9855 if (*p == ';' && IS_START(p, "; sct")) {
9856 if (IS_START(p, "; sctpatch:")) {
9858 if (*p == 0 || *p == ';')
9860 goto parse_words; // lame
9862 else if (IS_START(p, "; sctend")) {
9867 else if (g_skip_func)
9868 /* ignore remaining attrs */;
9869 else if (IS_START(p, "; sctproto:")) {
9870 sctproto = strdup(p + 11);
9872 else if (IS_START(p, "; sctskip_start")) {
9875 ops[pi].op = OPP_ABORT;
9876 ops[pi].asmln = asmln;
9882 else if (IS_START(p, "; sctskip_end")) {
9890 awarn("wordc == 0?\n");
9894 // don't care about this:
9895 if (words[0][0] == '.'
9896 || IS(words[0], "include")
9897 || IS(words[0], "assume") || IS(words[1], "segment")
9898 || IS(words[0], "align"))
9904 // do delayed endp processing to collect switch jumptables
9906 if (in_func && !g_skip_func && !end && wordc >= 2
9907 && ((words[0][0] == 'd' && words[0][2] == 0)
9908 || (words[1][0] == 'd' && words[1][2] == 0)))
9911 if (words[1][0] == 'd' && words[1][2] == 0) {
9913 if (g_func_pd_cnt >= pd_alloc) {
9914 pd_alloc = pd_alloc * 2 + 16;
9915 g_func_pd = realloc(g_func_pd,
9916 sizeof(g_func_pd[0]) * pd_alloc);
9917 my_assert_not(g_func_pd, NULL);
9919 pd = &g_func_pd[g_func_pd_cnt];
9921 memset(pd, 0, sizeof(*pd));
9922 strcpy(pd->label, words[0]);
9923 pd->type = OPT_CONST;
9924 pd->lmod = lmod_from_directive(words[1]);
9930 anote("skipping alignment byte?\n");
9933 lmod = lmod_from_directive(words[0]);
9934 if (lmod != pd->lmod)
9935 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9938 if (pd->count_alloc < pd->count + wordc) {
9939 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9940 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9941 my_assert_not(pd->d, NULL);
9943 for (; i < wordc; i++) {
9944 if (IS(words[i], "offset")) {
9945 pd->type = OPT_OFFSET;
9948 p = strchr(words[i], ',');
9951 if (pd->type == OPT_OFFSET)
9952 pd->d[pd->count].u.label = strdup(words[i]);
9954 pd->d[pd->count].u.val = parse_number(words[i], 0);
9955 pd->d[pd->count].bt_i = -1;
9961 if (in_func && !g_skip_func) {
9963 gen_hdr(g_func, pi);
9965 gen_func(fout, g_fhdr, g_func, pi);
9970 g_ida_func_attr = 0;
9971 g_sct_func_attr = 0;
9972 g_stack_clear_start = 0;
9973 g_stack_clear_len = 0;
9980 func_chunks_used = 0;
9983 memset(&ops, 0, pi * sizeof(ops[0]));
9988 for (i = 0; i < g_func_pd_cnt; i++) {
9990 if (pd->type == OPT_OFFSET) {
9991 for (j = 0; j < pd->count; j++)
9992 free(pd->d[j].u.label);
10007 if (IS(words[1], "proc")) {
10009 aerr("proc '%s' while in_func '%s'?\n",
10012 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
10014 strcpy(g_func, words[0]);
10015 set_label(0, words[0]);
10020 if (IS(words[1], "endp"))
10023 aerr("endp '%s' while not in_func?\n", words[0]);
10024 if (!IS(g_func, words[0]))
10025 aerr("endp '%s' while in_func '%s'?\n",
10028 aerr("endp '%s' while skipping code\n", words[0]);
10030 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
10031 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
10037 if (!g_skip_func && func_chunks_used) {
10038 // start processing chunks
10039 struct chunk_item *ci, key = { g_func, 0 };
10041 func_chunk_ret = ftell(fasm);
10042 func_chunk_ret_ln = asmln;
10043 if (!func_chunks_sorted) {
10044 qsort(func_chunks, func_chunk_cnt,
10045 sizeof(func_chunks[0]), cmp_chunks);
10046 func_chunks_sorted = 1;
10048 ci = bsearch(&key, func_chunks, func_chunk_cnt,
10049 sizeof(func_chunks[0]), cmp_chunks);
10051 aerr("'%s' needs chunks, but none found\n", g_func);
10052 func_chunk_i = ci - func_chunks;
10053 for (; func_chunk_i > 0; func_chunk_i--)
10054 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
10057 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
10059 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
10060 asmln = func_chunks[func_chunk_i].asmln;
10068 if (wordc == 2 && IS(words[1], "ends")) {
10072 goto do_pending_endp;
10076 // scan for next text segment
10077 while (my_fgets(line, sizeof(line), fasm)) {
10080 if (*p == 0 || *p == ';')
10083 if (strstr(p, "segment para public 'CODE' use32"))
10090 p = strchr(words[0], ':');
10092 set_label(pi, words[0]);
10096 if (!in_func || g_skip_func || skip_code) {
10097 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
10099 anote("skipping from '%s'\n", g_labels[pi]);
10102 free(g_labels[pi]);
10103 g_labels[pi] = NULL;
10107 if (wordc > 1 && IS(words[1], "="))
10110 aerr("unhandled equ, wc=%d\n", wordc);
10111 if (g_eqcnt >= eq_alloc) {
10113 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
10114 my_assert_not(g_eqs, NULL);
10117 len = strlen(words[0]);
10118 if (len > sizeof(g_eqs[0].name) - 1)
10119 aerr("equ name too long: %d\n", len);
10120 strcpy(g_eqs[g_eqcnt].name, words[0]);
10122 if (!IS(words[3], "ptr"))
10123 aerr("unhandled equ\n");
10124 if (IS(words[2], "dword"))
10125 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
10126 else if (IS(words[2], "word"))
10127 g_eqs[g_eqcnt].lmod = OPLM_WORD;
10128 else if (IS(words[2], "byte"))
10129 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
10130 else if (IS(words[2], "qword"))
10131 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
10133 aerr("bad lmod: '%s'\n", words[2]);
10135 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
10140 if (pi >= ARRAY_SIZE(ops))
10141 aerr("too many ops\n");
10143 parse_op(&ops[pi], words, wordc);
10145 ops[pi].datap = sctproto;
10160 // vim:ts=2:shiftwidth=2:expandtab