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, const struct parsed_proto **pp_found, int *pp_i,
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, pp_found, pp_i, multi);
3649 if (i > 0 && LAST_OP(i - 1))
3657 if (ops[i].cc_scratch == magic)
3659 ops[i].cc_scratch = magic;
3661 if (!(ops[i].flags & OPF_DATA))
3663 if (!is_opr_modified(opr, &ops[i]))
3665 if (ops[i].op != OP_MOV && ops[i].op != OP_LEA) {
3666 // most probably trashed by some processing
3671 opr = &ops[i].operand[1];
3672 if (opr->type != OPT_REG)
3676 po = (i >= 0) ? &ops[i] : ops;
3679 // reached the top - can only be an arg-reg
3680 if (opr->type != OPT_REG || g_func_pp == NULL)
3683 for (i = 0; i < g_func_pp->argc; i++) {
3684 if (g_func_pp->arg[i].reg == NULL)
3686 if (IS(opr->name, g_func_pp->arg[i].reg))
3689 if (i == g_func_pp->argc)
3691 pp = g_func_pp->arg[i].pp;
3693 ferr(po, "icall: arg%d (%s) is not a fptr?\n",
3694 i + 1, g_func_pp->arg[i].reg);
3695 check_func_pp(po, pp, "icall reg-arg");
3698 pp = try_recover_pp(po, opr, 1, NULL);
3700 if (*pp_found != NULL && pp != NULL && *pp_found != pp) {
3701 if (!IS((*pp_found)->ret_type.name, pp->ret_type.name)
3702 || (*pp_found)->is_stdcall != pp->is_stdcall
3703 //|| (*pp_found)->is_fptr != pp->is_fptr
3704 || (*pp_found)->argc != pp->argc
3705 || (*pp_found)->argc_reg != pp->argc_reg
3706 || (*pp_found)->argc_stack != pp->argc_stack)
3708 ferr(po, "icall: parsed_proto mismatch\n");
3718 static void add_label_ref(struct label_ref *lr, int op_i)
3720 struct label_ref *lr_new;
3727 lr_new = calloc(1, sizeof(*lr_new));
3729 lr_new->next = lr->next;
3733 static struct parsed_data *try_resolve_jumptab(int i, int opcnt)
3735 struct parsed_op *po = &ops[i];
3736 struct parsed_data *pd;
3737 char label[NAMELEN], *p;
3740 p = strchr(po->operand[0].name, '[');
3744 len = p - po->operand[0].name;
3745 strncpy(label, po->operand[0].name, len);
3748 for (j = 0, pd = NULL; j < g_func_pd_cnt; j++) {
3749 if (IS(g_func_pd[j].label, label)) {
3755 //ferr(po, "label '%s' not parsed?\n", label);
3758 if (pd->type != OPT_OFFSET)
3759 ferr(po, "label '%s' with non-offset data?\n", label);
3761 // find all labels, link
3762 for (j = 0; j < pd->count; j++) {
3763 for (l = 0; l < opcnt; l++) {
3764 if (g_labels[l] != NULL && IS(g_labels[l], pd->d[j].u.label)) {
3765 add_label_ref(&g_label_refs[l], i);
3775 static void clear_labels(int count)
3779 for (i = 0; i < count; i++) {
3780 if (g_labels[i] != NULL) {
3787 static int get_pp_arg_regmask_src(const struct parsed_proto *pp)
3792 for (i = 0; i < pp->argc; i++) {
3793 if (pp->arg[i].reg != NULL) {
3794 reg = char_array_i(regs_r32,
3795 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3797 ferr(ops, "arg '%s' of func '%s' is not a reg?\n",
3798 pp->arg[i].reg, pp->name);
3799 regmask |= 1 << reg;
3806 static int get_pp_arg_regmask_dst(const struct parsed_proto *pp)
3811 if (pp->has_retreg) {
3812 for (i = 0; i < pp->argc; i++) {
3813 if (pp->arg[i].type.is_retreg) {
3814 reg = char_array_i(regs_r32,
3815 ARRAY_SIZE(regs_r32), pp->arg[i].reg);
3816 ferr_assert(ops, reg >= 0);
3817 regmask |= 1 << reg;
3822 if (strstr(pp->ret_type.name, "int64"))
3823 return regmask | (1 << xAX) | (1 << xDX);
3824 if (IS(pp->ret_type.name, "float")
3825 || IS(pp->ret_type.name, "double"))
3827 return regmask | mxST0;
3829 if (strcasecmp(pp->ret_type.name, "void") == 0)
3832 return regmask | mxAX;
3835 static int are_ops_same(struct parsed_op *po1, struct parsed_op *po2)
3837 return po1->op == po2->op && po1->operand_cnt == po2->operand_cnt
3838 && memcmp(po1->operand, po2->operand,
3839 sizeof(po1->operand[0]) * po1->operand_cnt) == 0;
3842 static void resolve_branches_parse_calls(int opcnt)
3844 static const struct {
3848 unsigned int regmask_src;
3849 unsigned int regmask_dst;
3851 { "__allshl", OPP_ALLSHL, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3852 { "__allshr", OPP_ALLSHR, OPF_DATA, mxAX|mxDX|mxCX, mxAX|mxDX },
3853 { "__ftol", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3854 // more precise? Wine gets away with just __ftol handler
3855 { "__ftol2", OPP_FTOL, OPF_FPOP, mxST0, mxAX | mxDX },
3856 { "__CIpow", OPP_CIPOW, OPF_FPOP, mxST0|mxST1, mxST0 },
3858 const struct parsed_proto *pp_c;
3859 struct parsed_proto *pp;
3860 struct parsed_data *pd;
3861 struct parsed_op *po;
3862 const char *tmpname;
3867 for (i = 0; i < opcnt; i++)
3873 if (po->datap != NULL) {
3874 pp = calloc(1, sizeof(*pp));
3875 my_assert_not(pp, NULL);
3877 ret = parse_protostr(po->datap, pp);
3879 ferr(po, "bad protostr supplied: %s\n", (char *)po->datap);
3885 if (po->op == OP_CALL) {
3890 else if (po->operand[0].type == OPT_LABEL)
3892 tmpname = opr_name(po, 0);
3893 if (IS_START(tmpname, "loc_")) {
3895 ferr(po, "call to loc_*\n");
3896 // eliminate_seh() must take care of it
3899 if (IS(tmpname, "__alloca_probe"))
3901 if (IS(tmpname, "__SEH_prolog")) {
3902 ferr_assert(po, g_seh_found == 0);
3906 if (IS(tmpname, "__SEH_epilog"))
3909 // convert some calls to pseudo-ops
3910 for (l = 0; l < ARRAY_SIZE(pseudo_ops); l++) {
3911 if (!IS(tmpname, pseudo_ops[l].name))
3914 po->op = pseudo_ops[l].op;
3915 po->operand_cnt = 0;
3916 po->regmask_src = pseudo_ops[l].regmask_src;
3917 po->regmask_dst = pseudo_ops[l].regmask_dst;
3918 po->flags = pseudo_ops[l].flags;
3919 po->flags |= po->regmask_dst ? OPF_DATA : 0;
3922 if (l < ARRAY_SIZE(pseudo_ops))
3925 pp_c = proto_parse(g_fhdr, tmpname, g_header_mode);
3926 if (!g_header_mode && pp_c == NULL)
3927 ferr(po, "proto_parse failed for call '%s'\n", tmpname);
3930 pp = proto_clone(pp_c);
3931 my_assert_not(pp, NULL);
3937 check_func_pp(po, pp, "fptr var call");
3938 if (pp->is_noreturn) {
3939 po->flags |= OPF_TAIL;
3940 po->flags &= ~OPF_ATAIL; // most likely...
3947 if (!(po->flags & OPF_JMP) || po->op == OP_RET)
3950 if (po->operand[0].type == OPT_REGMEM) {
3951 pd = try_resolve_jumptab(i, opcnt);
3959 for (l = 0; l < opcnt; l++) {
3960 if (g_labels[l] != NULL
3961 && IS(po->operand[0].name, g_labels[l]))
3963 if (l == i + 1 && po->op == OP_JMP) {
3964 // yet another alignment type...
3965 po->flags |= OPF_RMD | OPF_DONE;
3966 po->flags &= ~OPF_JMP;
3970 add_label_ref(&g_label_refs[l], i);
3976 if (po->bt_i != -1 || (po->flags & OPF_RMD))
3979 if (po->operand[0].type == OPT_LABEL)
3983 ferr(po, "unhandled branch\n");
3987 po->flags |= OPF_TAIL;
3988 prev_op = i > 0 ? ops[i - 1].op : OP_UD2;
3989 if (prev_op == OP_POP)
3990 po->flags |= OPF_ATAIL;
3991 if (g_stack_fsz + g_bp_frame == 0 && prev_op != OP_PUSH
3992 && (g_func_pp == NULL || g_func_pp->argc_stack > 0))
3994 po->flags |= OPF_ATAIL;
4000 static int resolve_origin(int i, const struct parsed_opr *opr,
4001 int magic, int *op_i, int *is_caller);
4002 static void set_label(int i, const char *name);
4004 static void eliminate_seh_writes(int opcnt)
4006 const struct parsed_opr *opr;
4011 // assume all sf writes above g_seh_size to be seh related
4012 // (probably unsafe but oh well)
4013 for (i = 0; i < opcnt; i++) {
4014 if (ops[i].op != OP_MOV)
4016 opr = &ops[i].operand[0];
4017 if (opr->type != OPT_REGMEM)
4019 if (!is_stack_access(&ops[i], opr))
4023 parse_stack_access(&ops[i], opr->name, ofs_reg, &offset,
4025 if (offset < 0 && offset >= -g_seh_size)
4026 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4030 static void eliminate_seh_finally(int opcnt)
4032 const char *target_name = NULL;
4033 const char *return_name = NULL;
4034 int exits[MAX_EXITS];
4042 for (i = 0; i < opcnt; i++) {
4043 if (ops[i].op != OP_CALL)
4045 if (!IS_START(opr_name(&ops[i], 0), "loc_"))
4047 if (target_name != NULL)
4048 ferr(&ops[i], "multiple finally calls? (last was %s)\n",
4050 target_name = opr_name(&ops[i], 0);
4053 if (g_labels[i + 1] == NULL)
4054 set_label(i + 1, "seh_fin_done");
4055 return_name = g_labels[i + 1];
4063 // find finally code (bt_i is not set because it's call)
4064 for (i = 0; i < opcnt; i++) {
4065 if (g_labels[i] == NULL)
4067 if (!IS(g_labels[i], target_name))
4070 ferr_assert(&ops[i], target_i == -1);
4073 ferr_assert(&ops[0], target_i != -1);
4075 find_reachable_exits(target_i, opcnt, target_i + opcnt * 24,
4076 exits, &exit_count);
4077 ferr_assert(&ops[target_i], exit_count == 1);
4078 ferr_assert(&ops[target_i], ops[exits[0]].op == OP_RET);
4081 // convert to jumps, link
4082 ops[call_i].op = OP_JMP;
4083 ops[call_i].bt_i = target_i;
4084 add_label_ref(&g_label_refs[target_i], call_i);
4086 ops[tgend_i].op = OP_JMP;
4087 ops[tgend_i].flags &= ~OPF_TAIL;
4088 ops[tgend_i].flags |= OPF_JMP;
4089 ops[tgend_i].bt_i = return_i;
4090 ops[tgend_i].operand_cnt = 1;
4091 ops[tgend_i].operand[0].type = OPT_LABEL;
4092 snprintf(ops[tgend_i].operand[0].name, NAMELEN, "%s", return_name);
4093 add_label_ref(&g_label_refs[return_i], tgend_i);
4095 // rm seh finally entry code
4096 for (i = target_i - 1; i >= 0; i--) {
4097 if (g_labels[i] != NULL && g_label_refs[i].i != -1)
4099 if (ops[i].flags & OPF_CJMP)
4101 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4104 for (i = target_i - 1; i >= 0; i--) {
4105 if (ops[i].flags & (OPF_JMP | OPF_TAIL))
4107 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4111 static void eliminate_seh(int opcnt)
4115 for (i = 0; i < opcnt; i++) {
4116 if (ops[i].op != OP_MOV)
4118 if (ops[i].operand[0].segment != SEG_FS)
4120 if (!IS(opr_name(&ops[i], 0), "0"))
4123 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4124 if (ops[i].operand[1].reg == xSP) {
4125 for (j = i - 1; j >= 0; j--) {
4126 if (ops[j].op != OP_PUSH)
4128 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4130 if (ops[j].operand[0].val == ~0)
4132 if (ops[j].operand[0].type == OPT_REG) {
4134 ret = resolve_origin(j, &ops[j].operand[0],
4135 j + opcnt * 22, &k, NULL);
4137 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4141 ferr(ops, "missing seh terminator\n");
4145 ret = resolve_origin(i, &ops[i].operand[1],
4146 i + opcnt * 23, &k, NULL);
4148 ops[k].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4152 eliminate_seh_writes(opcnt);
4153 eliminate_seh_finally(opcnt);
4156 static void eliminate_seh_calls(int opcnt)
4158 int epilog_found = 0;
4165 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4166 && ops[i].operand[0].type == OPT_CONST);
4167 g_stack_fsz = g_seh_size + ops[i].operand[0].val;
4168 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4171 ferr_assert(&ops[i], ops[i].op == OP_PUSH
4172 && ops[i].operand[0].type == OPT_OFFSET);
4173 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4176 ferr_assert(&ops[i], ops[i].op == OP_CALL
4177 && IS(opr_name(&ops[i], 0), "__SEH_prolog"));
4178 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4180 for (i++; i < opcnt; i++) {
4181 if (ops[i].op != OP_CALL)
4183 if (!IS(opr_name(&ops[i], 0), "__SEH_epilog"))
4186 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4189 ferr_assert(ops, epilog_found);
4191 eliminate_seh_writes(opcnt);
4192 eliminate_seh_finally(opcnt);
4195 // check for prologue of many pushes and epilogue with pops
4196 static void check_simple_sequence(int opcnt, int *fsz)
4205 for (i = 0; i < opcnt && i < ARRAY_SIZE(seq); i++) {
4206 if (ops[i].op != OP_PUSH || ops[i].operand[0].type != OPT_REG)
4208 reg = ops[i].operand[0].reg;
4209 if (reg != xBX && reg != xSI && reg != xDI && reg != xBP)
4211 for (j = 0; j < i; j++)
4215 // probably something else is going on here
4223 for (; i < opcnt && seq_len > 0; i++) {
4224 if (!(ops[i].flags & OPF_TAIL))
4227 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4228 if (ops[j].op != OP_POP || ops[j].operand[0].type != OPT_REG)
4230 if (ops[j].operand[0].reg != seq[seq_p])
4234 found = seq_len = seq_p;
4239 for (i = 0; i < seq_len; i++)
4240 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4242 for (; i < opcnt && seq_len > 0; i++) {
4243 if (!(ops[i].flags & OPF_TAIL))
4246 for (j = i - 1, seq_p = 0; j >= 0 && seq_p < seq_len; j--) {
4247 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4252 // unlike pushes after sub esp,
4253 // IDA treats pushes like this as part of var area
4254 *fsz += seq_len * 4;
4257 static int scan_prologue(int i, int opcnt, int *ecx_push, int *esp_sub)
4262 for (; i < opcnt; i++)
4263 if (!(ops[i].flags & OPF_DONE))
4266 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4267 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4273 for (; i < opcnt; i++) {
4274 if (i > 0 && g_labels[i] != NULL)
4276 if (ops[i].flags & (OPF_JMP|OPF_TAIL))
4278 if (ops[i].flags & OPF_DONE)
4280 if (ops[i].op == OP_PUSH)
4282 if (ops[i].op == OP_SUB && ops[i].operand[0].reg == xSP
4283 && ops[i].operand[1].type == OPT_CONST)
4285 g_stack_fsz += opr_const(&ops[i], 1);
4286 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4291 if (ops[i].op == OP_LEA && ops[i].operand[0].reg == xSP
4292 && ops[i].operand[1].type == OPT_REGMEM
4293 && IS_START(ops[i].operand[1].name, "esp-"))
4295 name = ops[i].operand[1].name;
4296 ret = sscanf(name, "esp-%x%n", &j, &len);
4297 ferr_assert(&ops[i], ret == 1 && len == strlen(name));
4299 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4304 if (ops[i].op == OP_MOV && ops[i].operand[0].reg == xAX
4305 && ops[i].operand[1].type == OPT_CONST)
4307 for (j = i + 1; j < opcnt; j++)
4308 if (!(ops[j].flags & OPF_DONE))
4310 if (ops[j].op == OP_CALL
4311 && IS(opr_name(&ops[j], 0), "__alloca_probe"))
4313 g_stack_fsz += opr_const(&ops[i], 1);
4314 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4315 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4326 static void scan_prologue_epilogue(int opcnt, int *stack_align)
4328 int ecx_push = 0, esp_sub = 0, pusha = 0;
4329 int sandard_epilogue;
4330 int found, ret, len;
4334 if (g_seh_found == 2) {
4335 eliminate_seh_calls(opcnt);
4339 eliminate_seh(opcnt);
4340 // ida treats seh as part of sf
4341 g_stack_fsz = g_seh_size;
4345 if (ops[0].op == OP_PUSH && IS(opr_name(&ops[0], 0), "ebp")
4346 && ops[1].op == OP_MOV
4347 && IS(opr_name(&ops[1], 0), "ebp")
4348 && IS(opr_name(&ops[1], 1), "esp"))
4351 ops[0].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4352 ops[1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4354 for (i = 2; i < opcnt; i++)
4355 if (!(ops[i].flags & OPF_DONE))
4358 if (ops[i].op == OP_PUSHA) {
4359 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4364 if (ops[i].op == OP_AND && ops[i].operand[0].reg == xSP
4365 && ops[i].operand[1].type == OPT_CONST)
4367 l = ops[i].operand[1].val;
4369 if (j == -1 || (l >> j) != -1)
4370 ferr(&ops[i], "unhandled esp align: %x\n", l);
4371 if (stack_align != NULL)
4372 *stack_align = 1 << j;
4373 ops[i].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4377 i = scan_prologue(i, opcnt, &ecx_push, &esp_sub);
4381 for (; i < opcnt; i++)
4382 if (ops[i].flags & OPF_TAIL)
4385 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4386 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4392 sandard_epilogue = 0;
4393 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ebp"))
4395 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4396 // the standard epilogue is sometimes even used without a sf
4397 if (ops[j - 1].op == OP_MOV
4398 && IS(opr_name(&ops[j - 1], 0), "esp")
4399 && IS(opr_name(&ops[j - 1], 1), "ebp"))
4400 sandard_epilogue = 1;
4402 else if (ops[j].op == OP_LEAVE)
4404 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4405 sandard_epilogue = 1;
4407 else if (ops[i].op == OP_CALL && ops[i].pp != NULL
4408 && ops[i].pp->is_noreturn)
4410 // on noreturn, msvc sometimes cleans stack, sometimes not
4415 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4416 ferr(&ops[j], "'pop ebp' expected\n");
4418 if (g_stack_fsz != 0 || sandard_epilogue) {
4419 if (ops[j].op == OP_LEAVE)
4421 else if (sandard_epilogue) // mov esp, ebp
4423 ops[j - 1].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4426 else if (!(g_ida_func_attr & IDAFA_NORETURN))
4428 ferr(&ops[j], "esp restore expected\n");
4431 if (ecx_push && j >= 0 && ops[j].op == OP_POP
4432 && IS(opr_name(&ops[j], 0), "ecx"))
4434 ferr(&ops[j], "unexpected ecx pop\n");
4439 if (ops[j].op == OP_POPA)
4440 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4442 ferr(&ops[j], "popa expected\n");
4447 } while (i < opcnt);
4450 ferr(ops, "missing ebp epilogue\n");
4455 check_simple_sequence(opcnt, &push_fsz);
4456 i = scan_prologue(0, opcnt, &ecx_push, &esp_sub);
4458 if (ecx_push && !esp_sub) {
4459 // could actually be args for a call..
4460 for (; i < opcnt; i++)
4461 if (ops[i].op != OP_PUSH)
4464 if (ops[i].op == OP_CALL && ops[i].operand[0].type == OPT_LABEL) {
4465 const struct parsed_proto *pp;
4466 pp = proto_parse(g_fhdr, opr_name(&ops[i], 0), 1);
4467 j = pp ? pp->argc_stack : 0;
4468 while (i > 0 && j > 0) {
4470 if (ops[i].op == OP_PUSH) {
4471 ops[i].flags &= ~(OPF_RMD | OPF_DONE | OPF_NOREGS);
4476 ferr(&ops[i], "unhandled prologue\n");
4480 g_stack_fsz = g_seh_size;
4481 while (ops[i].op == OP_PUSH && IS(opr_name(&ops[i], 0), "ecx")) {
4482 if (!(ops[i].flags & OPF_RMD))
4492 if (ecx_push || esp_sub)
4497 for (; i < opcnt; i++)
4498 if (ops[i].flags & OPF_TAIL)
4502 if (i == opcnt && (ops[j].flags & OPF_JMP)) {
4503 if (ops[j].bt_i != -1 || ops[j].btj != NULL)
4508 else if (i < opcnt && (ops[i].flags & OPF_ATAIL)) {
4509 // skip arg updates for arg-reuse tailcall
4510 for (; j >= 0; j--) {
4511 if (ops[j].op != OP_MOV)
4513 if (ops[j].operand[0].type == OPT_REGMEM
4514 && strstr(ops[j].operand[0].name, "arg_") != NULL)
4516 if (ops[j].operand[0].type == OPT_REG)
4517 continue; // assume arg-reg mov
4522 for (; j >= 0; j--) {
4523 if ((ops[j].flags & (OPF_RMD | OPF_DONE | OPF_NOREGS)) !=
4524 (OPF_RMD | OPF_DONE | OPF_NOREGS))
4528 if (ecx_push > 0 && !esp_sub) {
4529 for (l = 0; l < ecx_push && j >= 0; l++) {
4530 if (ops[j].op == OP_POP && IS(opr_name(&ops[j], 0), "ecx"))
4532 else if (ops[j].op == OP_ADD
4533 && IS(opr_name(&ops[j], 0), "esp")
4534 && ops[j].operand[1].type == OPT_CONST)
4537 l += ops[j].operand[1].val / 4 - 1;
4542 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4545 if (l != ecx_push) {
4546 if (i < opcnt && ops[i].op == OP_CALL
4547 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4549 // noreturn tailcall with no epilogue
4554 ferr(&ops[j], "epilogue scan failed\n");
4561 if (ops[j].op == OP_ADD
4562 && IS(opr_name(&ops[j], 0), "esp")
4563 && ops[j].operand[1].type == OPT_CONST)
4565 if (ops[j].operand[1].val < g_stack_fsz)
4566 ferr(&ops[j], "esp adj is too low (need %d)\n", g_stack_fsz);
4568 ops[j].operand[1].val -= g_stack_fsz; // for stack arg scanner
4569 if (ops[j].operand[1].val == 0)
4570 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4573 else if (ops[j].op == OP_LEA && ops[j].operand[0].reg == xSP
4574 && ops[j].operand[1].type == OPT_REGMEM
4575 && IS_START(ops[j].operand[1].name, "esp+"))
4577 const char *name = ops[j].operand[1].name;
4578 ret = sscanf(name, "esp+%x%n", &l, &len);
4579 ferr_assert(&ops[j], ret == 1 && len == strlen(name));
4580 ferr_assert(&ops[j], l <= g_stack_fsz);
4581 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_NOREGS;
4584 else if (i < opcnt && ops[i].op == OP_CALL
4585 && ops[i].pp != NULL && ops[i].pp->is_noreturn)
4587 // noreturn tailcall with no epilogue
4591 ferr(&ops[j], "'add esp' expected\n");
4595 } while (i < opcnt);
4598 ferr(ops, "missing esp epilogue\n");
4601 if (g_stack_fsz != 0)
4602 // see check_simple_sequence
4603 g_stack_fsz += push_fsz;
4606 // find an instruction that changed opr before i op
4607 // *op_i must be set to -1 by the caller
4608 // *is_caller is set to 1 if one source is determined to be g_func arg
4609 // returns 1 if found, *op_i is then set to origin
4610 // returns -1 if multiple origins are found
4611 static int resolve_origin(int i, const struct parsed_opr *opr,
4612 int magic, int *op_i, int *is_caller)
4614 struct label_ref *lr;
4618 if (g_labels[i] != NULL) {
4619 lr = &g_label_refs[i];
4620 for (; lr != NULL; lr = lr->next) {
4621 check_i(&ops[i], lr->i);
4622 ret |= resolve_origin(lr->i, opr, magic, op_i, is_caller);
4624 if (i > 0 && LAST_OP(i - 1))
4630 if (is_caller != NULL)
4635 if (ops[i].cc_scratch == magic)
4637 ops[i].cc_scratch = magic;
4639 if (!(ops[i].flags & OPF_DATA))
4641 if (!is_opr_modified(opr, &ops[i]))
4645 if (*op_i == i || are_ops_same(&ops[*op_i], &ops[i]))
4656 // find an instruction that previously referenced opr
4657 // if multiple results are found - fail
4658 // *op_i must be set to -1 by the caller
4659 // returns 1 if found, *op_i is then set to referencer insn
4660 static int resolve_last_ref(int i, const struct parsed_opr *opr,
4661 int magic, int *op_i)
4663 struct label_ref *lr;
4667 if (g_labels[i] != NULL) {
4668 lr = &g_label_refs[i];
4669 for (; lr != NULL; lr = lr->next) {
4670 check_i(&ops[i], lr->i);
4671 ret |= resolve_last_ref(lr->i, opr, magic, op_i);
4673 if (i > 0 && LAST_OP(i - 1))
4681 if (ops[i].cc_scratch == magic)
4683 ops[i].cc_scratch = magic;
4685 if (!is_opr_referenced(opr, &ops[i]))
4696 // adjust datap of all reachable 'op' insns when moving back
4697 // returns 1 if at least 1 op was found
4698 // returns -1 if path without an op was found
4699 static int adjust_prev_op(int i, enum op_op op, int magic, void *datap)
4701 struct label_ref *lr;
4704 if (ops[i].cc_scratch == magic)
4706 ops[i].cc_scratch = magic;
4709 if (g_labels[i] != NULL) {
4710 lr = &g_label_refs[i];
4711 for (; lr != NULL; lr = lr->next) {
4712 check_i(&ops[i], lr->i);
4713 ret |= adjust_prev_op(lr->i, op, magic, datap);
4715 if (i > 0 && LAST_OP(i - 1))
4723 if (ops[i].cc_scratch == magic)
4725 ops[i].cc_scratch = magic;
4727 if (ops[i].op != op)
4730 ops[i].datap = datap;
4735 // find next instruction that reads opr
4736 // *op_i must be set to -1 by the caller
4737 // on return, *op_i is set to first referencer insn
4738 // returns 1 if exactly 1 referencer is found
4739 static int find_next_read(int i, int opcnt,
4740 const struct parsed_opr *opr, int magic, int *op_i)
4742 struct parsed_op *po;
4745 for (; i < opcnt; i++)
4747 if (ops[i].cc_scratch == magic)
4749 ops[i].cc_scratch = magic;
4752 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
4753 if (po->btj != NULL) {
4755 for (j = 0; j < po->btj->count; j++) {
4756 check_i(po, po->btj->d[j].bt_i);
4757 ret |= find_next_read(po->btj->d[j].bt_i, opcnt, opr,
4763 if (po->flags & OPF_RMD)
4765 check_i(po, po->bt_i);
4766 if (po->flags & OPF_CJMP) {
4767 ret |= find_next_read(po->bt_i, opcnt, opr, magic, op_i);
4776 if (!is_opr_read(opr, po)) {
4778 if (opr->type == OPT_REG && po->operand[0].type == OPT_REG
4779 && opr->reg == po->operand[0].reg && (po->flags & OPF_DATA))
4781 full_opr = po->operand[0].lmod >= opr->lmod;
4783 if (is_opr_modified(opr, po) && full_opr) {
4787 if (po->flags & OPF_TAIL)
4802 static int find_next_read_reg(int i, int opcnt, int reg,
4803 enum opr_lenmod lmod, int magic, int *op_i)
4805 struct parsed_opr opr = OPR_INIT(OPT_REG, lmod, reg);
4808 return find_next_read(i, opcnt, &opr, magic, op_i);
4811 // find next instruction that reads opr
4812 // *op_i must be set to -1 by the caller
4813 // on return, *op_i is set to first flag user insn
4814 // returns 1 if exactly 1 flag user is found
4815 static int find_next_flag_use(int i, int opcnt, int magic, int *op_i)
4817 struct parsed_op *po;
4820 for (; i < opcnt; i++)
4822 if (ops[i].cc_scratch == magic)
4824 ops[i].cc_scratch = magic;
4827 if (po->op == OP_CALL)
4829 if (po->flags & OPF_JMP) {
4830 if (po->btj != NULL) {
4832 for (j = 0; j < po->btj->count; j++) {
4833 check_i(po, po->btj->d[j].bt_i);
4834 ret |= find_next_flag_use(po->btj->d[j].bt_i, opcnt,
4840 if (po->flags & OPF_RMD)
4842 check_i(po, po->bt_i);
4843 if (po->flags & OPF_CJMP)
4850 if (!(po->flags & OPF_CC)) {
4851 if (po->flags & OPF_FLAGS)
4854 if (po->flags & OPF_TAIL)
4870 static int try_resolve_const(int i, const struct parsed_opr *opr,
4871 int magic, unsigned int *val)
4876 ret = resolve_origin(i, opr, magic, &s_i, NULL);
4879 if (ops[i].op != OP_MOV && ops[i].operand[1].type != OPT_CONST)
4882 *val = ops[i].operand[1].val;
4889 static int resolve_used_bits(int i, int opcnt, int reg,
4890 int *mask, int *is_z_check)
4892 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_WORD, reg);
4896 ret = find_next_read(i, opcnt, &opr, i + opcnt * 20, &j);
4900 find_next_read(j + 1, opcnt, &opr, i + opcnt * 20 + 1, &k);
4902 fnote(&ops[j], "(first read)\n");
4903 ferr(&ops[k], "TODO: bit resolve: multiple readers\n");
4906 if (ops[j].op != OP_TEST || ops[j].operand[1].type != OPT_CONST)
4907 ferr(&ops[j], "TODO: bit resolve: not a const test\n");
4909 ferr_assert(&ops[j], ops[j].operand[0].type == OPT_REG);
4910 ferr_assert(&ops[j], ops[j].operand[0].reg == reg);
4912 *mask = ops[j].operand[1].val;
4913 if (ops[j].operand[0].lmod == OPLM_BYTE
4914 && ops[j].operand[0].name[1] == 'h')
4918 ferr_assert(&ops[j], (*mask & ~0xffff) == 0);
4921 ret = find_next_flag_use(j + 1, opcnt, i + opcnt * 20 + 2, &k);
4923 *is_z_check = ops[k].pfo == PFO_Z;
4928 static const struct parsed_proto *resolve_deref(int i, int magic,
4929 struct parsed_opr *opr, int level)
4931 struct parsed_opr opr_s = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
4932 const struct parsed_proto *pp = NULL;
4933 int from_caller = 0;
4942 ret = sscanf(opr->name, "%3s+%x%n", s_reg, &offset, &len);
4943 if (ret != 2 || len != strlen(opr->name)) {
4944 ret = sscanf(opr->name, "%3s%n", s_reg, &len);
4945 if (ret != 1 || len != strlen(opr->name))
4949 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
4954 ret = resolve_origin(i, &opr_s, i + magic, &j, NULL);
4958 if (ops[j].op == OP_MOV && ops[j].operand[1].type == OPT_REGMEM
4959 && strlen(ops[j].operand[1].name) == 3
4960 && ops[j].operand[0].lmod == OPLM_DWORD
4961 && ops[j].pp == NULL // no hint
4964 // allow one simple dereference (com/directx)
4965 reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32),
4966 ops[j].operand[1].name);
4970 ret = resolve_origin(j, &opr_s, j + magic, &k, NULL);
4975 if (ops[j].op != OP_MOV || ops[j].operand[0].lmod != OPLM_DWORD)
4978 if (ops[j].pp != NULL) {
4982 else if (ops[j].operand[1].type == OPT_REGMEM) {
4983 pp = try_recover_pp(&ops[j], &ops[j].operand[1], 0, NULL);
4985 // maybe structure ptr in structure
4986 pp = resolve_deref(j, magic, &ops[j].operand[1], level + 1);
4989 else if (ops[j].operand[1].type == OPT_LABEL)
4990 pp = proto_parse(g_fhdr, ops[j].operand[1].name, g_quiet_pp);
4991 else if (ops[j].operand[1].type == OPT_REG) {
4994 ret = resolve_origin(j, &ops[j].operand[1], i + magic,
4996 if (ret != 1 && from_caller && k == -1 && g_func_pp != NULL) {
4997 for (k = 0; k < g_func_pp->argc; k++) {
4998 if (g_func_pp->arg[k].reg == NULL)
5000 if (IS(g_func_pp->arg[k].reg, ops[j].operand[1].name)) {
5001 pp = g_func_pp->arg[k].pp;
5010 if (pp->is_func || pp->is_fptr || !pp->type.is_struct) {
5012 ferr(&ops[j], "expected struct, got '%s %s'\n",
5013 pp->type.name, pp->name);
5017 return proto_lookup_struct(g_fhdr, pp->type.name, offset);
5020 static const struct parsed_proto *resolve_icall(int i, int opcnt,
5021 int *pp_i, int *multi_src)
5023 const struct parsed_proto *pp = NULL;
5024 int search_advice = 0;
5029 switch (ops[i].operand[0].type) {
5031 // try to resolve struct member calls
5032 pp = resolve_deref(i, i + opcnt * 19, &ops[i].operand[0], 0);
5038 pp = try_recover_pp(&ops[i], &ops[i].operand[0],
5044 scan_for_call_type(i, &ops[i].operand[0], i + opcnt * 9, &pp,
5052 static struct parsed_proto *process_call_early(int i, int opcnt,
5055 struct parsed_op *po = &ops[i];
5056 struct parsed_proto *pp;
5062 if (pp == NULL || pp->is_vararg || pp->argc_reg != 0)
5066 // look for and make use of esp adjust
5068 if (!pp->is_stdcall && pp->argc_stack > 0)
5069 ret = scan_for_esp_adjust(i + 1, opcnt,
5070 pp->argc_stack * 4, &adj, &multipath, 0);
5072 if (pp->argc_stack > adj / 4)
5076 if (ops[ret].op == OP_POP) {
5077 for (j = 1; j < adj / 4; j++) {
5078 if (ops[ret + j].op != OP_POP
5079 || ops[ret + j].operand[0].reg != xCX)
5091 static struct parsed_proto *process_call(int i, int opcnt)
5093 struct parsed_op *po = &ops[i];
5094 const struct parsed_proto *pp_c;
5095 struct parsed_proto *pp;
5096 const char *tmpname;
5097 int call_i = -1, ref_i = -1;
5098 int adj = 0, multipath = 0;
5101 tmpname = opr_name(po, 0);
5106 pp_c = resolve_icall(i, opcnt, &call_i, &multipath);
5108 if (!pp_c->is_func && !pp_c->is_fptr)
5109 ferr(po, "call to non-func: %s\n", pp_c->name);
5110 pp = proto_clone(pp_c);
5111 my_assert_not(pp, NULL);
5113 // not resolved just to single func
5116 switch (po->operand[0].type) {
5118 // we resolved this call and no longer need the register
5119 po->regmask_src &= ~(1 << po->operand[0].reg);
5121 if (!multipath && i != call_i && ops[call_i].op == OP_MOV
5122 && ops[call_i].operand[1].type == OPT_LABEL)
5124 // no other source users?
5125 ret = resolve_last_ref(i, &po->operand[0], i + opcnt * 10,
5127 if (ret == 1 && call_i == ref_i) {
5128 // and nothing uses it after us?
5130 find_next_read(i + 1, opcnt, &po->operand[0],
5131 i + opcnt * 11, &ref_i);
5133 // then also don't need the source mov
5134 ops[call_i].flags |= OPF_RMD | OPF_NOREGS;
5146 pp = calloc(1, sizeof(*pp));
5147 my_assert_not(pp, NULL);
5150 ret = scan_for_esp_adjust(i + 1, opcnt,
5151 -1, &adj, &multipath, 0);
5152 if (ret < 0 || adj < 0) {
5153 if (!g_allow_regfunc)
5154 ferr(po, "non-__cdecl indirect call unhandled yet\n");
5155 pp->is_unresolved = 1;
5159 if (adj > ARRAY_SIZE(pp->arg))
5160 ferr(po, "esp adjust too large: %d\n", adj);
5161 pp->ret_type.name = strdup("int");
5162 pp->argc = pp->argc_stack = adj;
5163 for (arg = 0; arg < pp->argc; arg++)
5164 pp->arg[arg].type.name = strdup("int");
5169 // look for and make use of esp adjust
5172 if (!pp->is_stdcall && pp->argc_stack > 0) {
5173 int adj_expect = pp->is_vararg ? -1 : pp->argc_stack * 4;
5174 ret = scan_for_esp_adjust(i + 1, opcnt,
5175 adj_expect, &adj, &multipath, 0);
5178 if (pp->is_vararg) {
5179 if (adj / 4 < pp->argc_stack) {
5180 fnote(po, "(this call)\n");
5181 ferr(&ops[ret], "esp adjust is too small: %x < %x\n",
5182 adj, pp->argc_stack * 4);
5184 // modify pp to make it have varargs as normal args
5186 pp->argc += adj / 4 - pp->argc_stack;
5187 for (; arg < pp->argc; arg++) {
5188 pp->arg[arg].type.name = strdup("int");
5191 if (pp->argc > ARRAY_SIZE(pp->arg))
5192 ferr(po, "too many args for '%s'\n", tmpname);
5194 if (pp->argc_stack > adj / 4) {
5195 if (pp->is_noreturn)
5196 // assume no stack adjust was emited
5198 fnote(po, "(this call)\n");
5199 ferr(&ops[ret], "stack tracking failed for '%s': %x %x\n",
5200 tmpname, pp->argc_stack * 4, adj);
5203 scan_for_esp_adjust(i + 1, opcnt,
5204 pp->argc_stack * 4, &adj, &multipath, 1);
5206 else if (pp->is_vararg)
5207 ferr(po, "missing esp_adjust for vararg func '%s'\n",
5214 static void mark_float_arg(struct parsed_op *po,
5215 struct parsed_proto *pp, int arg, int *regmask_ffca)
5218 po->p_argnum = arg + 1;
5219 ferr_assert(po, pp->arg[arg].datap == NULL);
5220 pp->arg[arg].datap = po;
5221 po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
5222 if (regmask_ffca != NULL)
5223 *regmask_ffca |= 1 << arg;
5226 static int check_for_stp(int i, int i_to)
5228 struct parsed_op *po;
5230 for (; i < i_to; i++) {
5232 if (po->op == OP_FST)
5234 if (g_labels[i] != NULL || (po->flags & OPF_JMP))
5236 if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
5238 if (po->op == OP_ADD && po->operand[0].reg == xSP)
5245 static int collect_call_args_no_push(int i, struct parsed_proto *pp,
5248 struct parsed_op *po;
5254 for (base_arg = 0; base_arg < pp->argc; base_arg++)
5255 if (pp->arg[base_arg].reg == NULL)
5258 for (j = i; j > 0; )
5260 ferr_assert(&ops[j], g_labels[j] == NULL);
5264 ferr_assert(po, po->op != OP_PUSH);
5265 if (po->op == OP_FST)
5267 if (po->operand[0].type != OPT_REGMEM)
5269 ret = parse_stack_esp_offset(po, po->operand[0].name, &offset);
5272 if (offset < 0 || offset >= pp->argc_stack * 4 || (offset & 3)) {
5273 //ferr(po, "offset %d, %d args\n", offset, pp->argc_stack);
5277 arg = base_arg + offset / 4;
5278 mark_float_arg(po, pp, arg, regmask_ffca);
5280 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5281 && po->operand[1].type == OPT_CONST)
5283 po->flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5288 for (arg = base_arg; arg < pp->argc; arg++) {
5289 ferr_assert(&ops[i], pp->arg[arg].reg == NULL);
5290 po = pp->arg[arg].datap;
5292 ferr(&ops[i], "arg %d/%d not found\n", arg, pp->argc);
5293 if (po->operand[0].lmod == OPLM_QWORD)
5300 static int collect_call_args_early(int i, struct parsed_proto *pp,
5301 int *regmask, int *regmask_ffca)
5303 struct parsed_op *po;
5308 for (arg = 0; arg < pp->argc; arg++)
5309 if (pp->arg[arg].reg == NULL)
5312 // first see if it can be easily done
5313 for (j = i; j > 0 && arg < pp->argc; )
5315 if (g_labels[j] != NULL)
5320 if (po->op == OP_CALL)
5322 else if (po->op == OP_ADD && po->operand[0].reg == xSP)
5324 else if (po->op == OP_POP)
5326 else if (po->flags & OPF_CJMP)
5328 else if (po->op == OP_PUSH) {
5329 if (po->flags & (OPF_FARG|OPF_FARGNR))
5331 if (!g_header_mode) {
5332 ret = scan_for_mod(po, j + 1, i, 1);
5337 if (pp->arg[arg].type.is_va_list)
5341 for (arg++; arg < pp->argc; arg++)
5342 if (pp->arg[arg].reg == NULL)
5345 else if (po->op == OP_SUB && po->operand[0].reg == xSP
5346 && po->operand[1].type == OPT_CONST)
5348 if (po->flags & (OPF_RMD|OPF_DONE))
5350 if (po->operand[1].val != pp->argc_stack * 4)
5351 ferr(po, "unexpected esp adjust: %d\n",
5352 po->operand[1].val * 4);
5353 ferr_assert(po, pp->argc - arg == pp->argc_stack);
5354 return collect_call_args_no_push(i, pp, regmask_ffca);
5362 for (arg = 0; arg < pp->argc; arg++)
5363 if (pp->arg[arg].reg == NULL)
5366 for (j = i; j > 0 && arg < pp->argc; )
5370 if (ops[j].op == OP_PUSH)
5372 ops[j].p_argnext = -1;
5373 ferr_assert(&ops[j], pp->arg[arg].datap == NULL);
5375 k = check_for_stp(j + 1, i);
5377 // push ecx; fstp dword ptr [esp]
5378 ret = parse_stack_esp_offset(&ops[k],
5379 ops[k].operand[0].name, &offset);
5380 if (ret == 0 && offset == 0) {
5381 if (!pp->arg[arg].type.is_float)
5382 ferr(&ops[i], "arg %d should be float\n", arg + 1);
5383 mark_float_arg(&ops[k], pp, arg, regmask_ffca);
5387 if (pp->arg[arg].datap == NULL) {
5388 pp->arg[arg].datap = &ops[j];
5389 if (regmask != NULL && ops[j].operand[0].type == OPT_REG)
5390 *regmask |= 1 << ops[j].operand[0].reg;
5393 ops[j].flags |= OPF_RMD | OPF_DONE | OPF_FARGNR | OPF_FARG;
5394 ops[j].flags &= ~OPF_RSAVE;
5397 for (arg++; arg < pp->argc; arg++)
5398 if (pp->arg[arg].reg == NULL)
5406 static int sync_argnum(struct parsed_op *po, int argnum)
5408 struct parsed_op *po_tmp;
5410 // see if other branches don't have higher argnum
5411 for (po_tmp = po; po_tmp != NULL; ) {
5412 if (argnum < po_tmp->p_argnum)
5413 argnum = po_tmp->p_argnum;
5414 // note: p_argnext is active on current collect_call_args only
5415 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5418 // make all argnums consistent
5419 for (po_tmp = po; po_tmp != NULL; ) {
5420 if (po_tmp->p_argnum != 0)
5421 po_tmp->p_argnum = argnum;
5422 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5428 static int collect_call_args_r(struct parsed_op *po, int i,
5429 struct parsed_proto *pp, int *regmask, int *arg_grp,
5430 int arg, int argnum, int magic, int need_op_saving, int may_reuse)
5432 struct parsed_proto *pp_tmp;
5433 struct parsed_op *po_tmp;
5434 struct label_ref *lr;
5435 int need_to_save_current;
5436 int arg_grp_current = 0;
5437 int save_args_seen = 0;
5444 ferr(po, "dead label encountered\n");
5448 for (; arg < pp->argc; arg++, argnum++)
5449 if (pp->arg[arg].reg == NULL)
5451 magic = (magic & 0xffffff) | (arg << 24);
5453 for (j = i; j >= 0 && (arg < pp->argc || pp->is_unresolved); )
5455 if (((ops[j].cc_scratch ^ magic) & 0xffffff) == 0) {
5456 if (ops[j].cc_scratch != magic) {
5457 ferr(&ops[j], "arg collect hit same path with diff args for %s\n",
5461 // ok: have already been here
5464 ops[j].cc_scratch = magic;
5466 if (g_labels[j] != NULL && g_label_refs[j].i != -1) {
5467 lr = &g_label_refs[j];
5468 if (lr->next != NULL)
5470 for (; lr->next; lr = lr->next) {
5471 check_i(&ops[j], lr->i);
5472 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5474 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5475 arg, argnum, magic, need_op_saving, may_reuse);
5480 check_i(&ops[j], lr->i);
5481 if ((ops[lr->i].flags & (OPF_JMP|OPF_CJMP)) != OPF_JMP)
5483 if (j > 0 && LAST_OP(j - 1)) {
5484 // follow last branch in reverse
5489 ret = collect_call_args_r(po, lr->i, pp, regmask, arg_grp,
5490 arg, argnum, magic, need_op_saving, may_reuse);
5496 if (ops[j].op == OP_CALL)
5498 if (pp->is_unresolved)
5503 ferr(po, "arg collect %d/%d hit unparsed call '%s'\n",
5504 arg, pp->argc, ops[j].operand[0].name);
5505 if (may_reuse && pp_tmp->argc_stack > 0)
5506 ferr(po, "arg collect %d/%d hit '%s' with %d stack args\n",
5507 arg, pp->argc, opr_name(&ops[j], 0), pp_tmp->argc_stack);
5509 // esp adjust of 0 means we collected it before
5510 else if (ops[j].op == OP_ADD && ops[j].operand[0].reg == xSP
5511 && (ops[j].operand[1].type != OPT_CONST
5512 || ops[j].operand[1].val != 0))
5514 if (pp->is_unresolved)
5517 fnote(po, "(this call)\n");
5518 ferr(&ops[j], "arg collect %d/%d hit esp adjust of %d\n",
5519 arg, pp->argc, ops[j].operand[1].val);
5521 else if (ops[j].op == OP_POP && !(ops[j].flags & OPF_DONE))
5523 if (pp->is_unresolved)
5526 fnote(po, "(this call)\n");
5527 ferr(&ops[j], "arg collect %d/%d hit pop\n", arg, pp->argc);
5529 else if (ops[j].flags & OPF_CJMP)
5531 if (pp->is_unresolved)
5536 else if (ops[j].op == OP_PUSH
5537 && !(ops[j].flags & (OPF_FARGNR|OPF_DONE)))
5539 if (pp->is_unresolved && (ops[j].flags & OPF_RMD))
5542 ops[j].p_argnext = -1;
5543 po_tmp = pp->arg[arg].datap;
5545 ops[j].p_argnext = po_tmp - ops;
5546 pp->arg[arg].datap = &ops[j];
5548 argnum = sync_argnum(&ops[j], argnum);
5550 need_to_save_current = 0;
5552 if (ops[j].operand[0].type == OPT_REG)
5553 reg = ops[j].operand[0].reg;
5555 if (!need_op_saving) {
5556 ret = scan_for_mod(&ops[j], j + 1, i, 1);
5557 need_to_save_current = (ret >= 0);
5559 if (need_op_saving || need_to_save_current) {
5560 // mark this arg as one that needs operand saving
5561 pp->arg[arg].is_saved = 1;
5563 if (save_args_seen & (1 << (argnum - 1))) {
5566 if (arg_grp_current >= MAX_ARG_GRP)
5567 ferr(&ops[j], "out of arg groups (arg%d), f %s\n",
5571 else if (ops[j].p_argnum == 0)
5572 ops[j].flags |= OPF_RMD;
5574 // some PUSHes are reused by different calls on other branches,
5575 // but that can't happen if we didn't branch, so they
5576 // can be removed from future searches (handles nested calls)
5578 ops[j].flags |= OPF_FARGNR;
5580 ops[j].flags |= OPF_FARG;
5581 ops[j].flags &= ~OPF_RSAVE;
5583 // check for __VALIST
5584 if (!pp->is_unresolved && g_func_pp != NULL
5585 && pp->arg[arg].type.is_va_list)
5588 ret = resolve_origin(j, &ops[j].operand[0],
5589 magic + 1, &k, NULL);
5590 if (ret == 1 && k >= 0)
5592 if (ops[k].op == OP_LEA) {
5593 if (!g_func_pp->is_vararg)
5594 ferr(&ops[k], "lea <arg> used, but %s is not vararg?\n",
5597 snprintf(buf, sizeof(buf), "arg_%X",
5598 g_func_pp->argc_stack * 4);
5599 if (strstr(ops[k].operand[1].name, buf)
5600 || strstr(ops[k].operand[1].name, "arglist"))
5602 ops[k].flags |= OPF_RMD | OPF_NOREGS | OPF_DONE;
5603 ops[j].flags |= OPF_RMD | OPF_NOREGS | OPF_VAPUSH;
5604 pp->arg[arg].is_saved = 0;
5608 ferr(&ops[k], "va_list arg detection failed\n");
5610 // check for va_list from g_func_pp arg too
5611 else if (ops[k].op == OP_MOV
5612 && is_stack_access(&ops[k], &ops[k].operand[1]))
5614 ret = stack_frame_access(&ops[k], &ops[k].operand[1],
5615 buf, sizeof(buf), ops[k].operand[1].name, "", 1, 0);
5617 ops[k].flags |= OPF_RMD | OPF_DONE;
5618 ops[j].flags |= OPF_RMD;
5619 ops[j].p_argpass = ret + 1;
5620 pp->arg[arg].is_saved = 0;
5627 if (pp->arg[arg].is_saved) {
5628 ops[j].flags &= ~OPF_RMD;
5629 ops[j].p_argnum = argnum;
5632 // tracking reg usage
5634 *regmask |= 1 << reg;
5638 if (!pp->is_unresolved) {
5640 for (; arg < pp->argc; arg++, argnum++)
5641 if (pp->arg[arg].reg == NULL)
5644 magic = (magic & 0xffffff) | (arg << 24);
5647 if (ops[j].p_arggrp > arg_grp_current) {
5649 arg_grp_current = ops[j].p_arggrp;
5651 if (ops[j].p_argnum > 0)
5652 save_args_seen |= 1 << (ops[j].p_argnum - 1);
5655 if (arg < pp->argc) {
5656 ferr(po, "arg collect failed for '%s': %d/%d\n",
5657 pp->name, arg, pp->argc);
5661 if (arg_grp_current > *arg_grp)
5662 *arg_grp = arg_grp_current;
5667 static int collect_call_args(struct parsed_op *po, int i,
5668 struct parsed_proto *pp, int *regmask, int magic)
5670 // arg group is for cases when pushes for
5671 // multiple funcs are going on
5672 struct parsed_op *po_tmp;
5677 ret = collect_call_args_r(po, i, pp, regmask, &arg_grp,
5682 if (pp->is_unresolved) {
5684 pp->argc_stack += ret;
5685 for (a = 0; a < pp->argc; a++)
5686 if (pp->arg[a].type.name == NULL)
5687 pp->arg[a].type.name = strdup("int");
5691 // propagate arg_grp
5692 for (a = 0; a < pp->argc; a++) {
5693 if (pp->arg[a].reg != NULL)
5696 po_tmp = pp->arg[a].datap;
5697 while (po_tmp != NULL) {
5698 po_tmp->p_arggrp = arg_grp;
5699 po_tmp = po_tmp->p_argnext >= 0 ? &ops[po_tmp->p_argnext] : NULL;
5707 static void reg_use_pass(int i, int opcnt, unsigned char *cbits,
5708 int regmask_now, int *regmask,
5709 int regmask_save_now, int *regmask_save,
5710 int *regmask_init, int regmask_arg)
5712 struct parsed_op *po;
5720 for (; i < opcnt; i++)
5723 if (cbits[i >> 3] & (1 << (i & 7)))
5725 cbits[i >> 3] |= (1 << (i & 7));
5727 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
5728 if (po->flags & (OPF_RMD|OPF_DONE))
5730 if (po->btj != NULL) {
5731 for (j = 0; j < po->btj->count; j++) {
5732 check_i(po, po->btj->d[j].bt_i);
5733 reg_use_pass(po->btj->d[j].bt_i, opcnt, cbits,
5734 regmask_now, regmask, regmask_save_now, regmask_save,
5735 regmask_init, regmask_arg);
5740 check_i(po, po->bt_i);
5741 if (po->flags & OPF_CJMP)
5742 reg_use_pass(po->bt_i, opcnt, cbits,
5743 regmask_now, regmask, regmask_save_now, regmask_save,
5744 regmask_init, regmask_arg);
5750 if (po->op == OP_PUSH && !(po->flags & (OPF_FARG|OPF_DONE))
5751 && !g_func_pp->is_userstack
5752 && po->operand[0].type == OPT_REG)
5756 reg = po->operand[0].reg;
5757 ferr_assert(po, reg >= 0);
5760 flags_set = OPF_RSAVE | OPF_RMD | OPF_DONE;
5761 if (regmask_now & (1 << reg)) {
5762 already_saved = regmask_save_now & (1 << reg);
5763 flags_set = OPF_RSAVE | OPF_DONE;
5767 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 3,
5768 reg, 0, 0, save_level, 0);
5770 scan_for_pop(i + 1, opcnt, i + opcnt * 4,
5771 reg, 0, 0, save_level, flags_set);
5774 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
5776 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg,
5781 ferr_assert(po, !already_saved);
5782 po->flags |= flags_set;
5784 if (regmask_now & (1 << reg)) {
5785 regmask_save_now |= (1 << reg);
5786 *regmask_save |= regmask_save_now;
5791 else if (po->op == OP_POP && (po->flags & OPF_RSAVE)) {
5792 reg = po->operand[0].reg;
5793 ferr_assert(po, reg >= 0);
5795 if (regmask_save_now & (1 << reg))
5796 regmask_save_now &= ~(1 << reg);
5798 regmask_now &= ~(1 << reg);
5801 else if (po->op == OP_CALL) {
5802 if ((po->regmask_dst & (1 << xAX))
5803 && !(po->regmask_dst & (1 << xDX)))
5805 if (po->flags & OPF_TAIL)
5806 // don't need eax, will do "return f();" or "f(); return;"
5807 po->regmask_dst &= ~(1 << xAX);
5809 find_next_read_reg(i + 1, opcnt, xAX, OPLM_DWORD,
5810 i + opcnt * 17, &j);
5813 po->regmask_dst &= ~(1 << xAX);
5817 // not "full stack" mode and have something in stack
5818 if (!(regmask_now & mxST7_2) && (regmask_now & mxST1_0))
5819 ferr(po, "float stack is not empty on func call\n");
5822 if (po->flags & OPF_NOREGS)
5825 // if incomplete register is used, clear it on init to avoid
5826 // later use of uninitialized upper part in some situations
5827 if ((po->flags & OPF_DATA) && po->operand[0].type == OPT_REG
5828 && po->operand[0].lmod != OPLM_DWORD)
5830 reg = po->operand[0].reg;
5831 ferr_assert(po, reg >= 0);
5833 if (!(regmask_now & (1 << reg)))
5834 *regmask_init |= 1 << reg;
5837 regmask_op = po->regmask_src | po->regmask_dst;
5839 regmask_new = po->regmask_src & ~regmask_now & ~regmask_arg;
5840 regmask_new &= ~(1 << xSP);
5841 if (g_bp_frame && !(po->flags & OPF_EBP_S))
5842 regmask_new &= ~(1 << xBP);
5844 if (regmask_new != 0)
5845 fnote(po, "uninitialized reg mask: %x\n", regmask_new);
5847 if (regmask_op & (1 << xBP)) {
5848 if (g_bp_frame && !(po->flags & OPF_EBP_S)) {
5849 if (po->regmask_dst & (1 << xBP))
5850 // compiler decided to drop bp frame and use ebp as scratch
5851 scan_fwd_set_flags(i + 1, opcnt, i + opcnt * 5, OPF_EBP_S);
5853 regmask_op &= ~(1 << xBP);
5857 if (po->flags & OPF_FPUSH) {
5858 if (regmask_now & mxST1)
5859 regmask_now |= mxSTa; // switch to "full stack" mode
5860 if (regmask_now & mxSTa)
5861 po->flags |= OPF_FSHIFT;
5862 if (!(regmask_now & mxST7_2)) {
5864 (regmask_now & ~mxST1_0) | ((regmask_now & mxST0) << 1);
5868 regmask_now |= regmask_op;
5869 *regmask |= regmask_now;
5872 if (po->flags & OPF_FPOPP) {
5873 if ((regmask_now & mxSTa) == 0)
5874 ferr(po, "float pop on empty stack?\n");
5875 if (regmask_now & mxST7_2)
5876 po->flags |= OPF_FSHIFT;
5877 if (!(regmask_now & mxST7_2))
5878 regmask_now &= ~mxST1_0;
5880 else if (po->flags & OPF_FPOP) {
5881 if ((regmask_now & mxSTa) == 0)
5882 ferr(po, "float pop on empty stack?\n");
5883 if (regmask_now & (mxST7_2 | mxST1))
5884 po->flags |= OPF_FSHIFT;
5885 if (!(regmask_now & mxST7_2)) {
5887 (regmask_now & ~mxST1_0) | ((regmask_now & mxST1) >> 1);
5891 if (po->flags & OPF_TAIL) {
5892 if (!(regmask_now & mxST7_2)) {
5893 if (get_pp_arg_regmask_dst(g_func_pp) & mxST0) {
5894 if (!(regmask_now & mxST0))
5895 ferr(po, "no st0 on float return, mask: %x\n",
5898 else if (regmask_now & mxST1_0)
5899 ferr(po, "float regs on tail: %x\n", regmask_now);
5902 // there is support for "conditional tailcall", sort of
5903 if (!(po->flags & OPF_CC))
5909 static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
5913 for (i = 0; i < pp->argc; i++)
5914 if (pp->arg[i].reg == NULL)
5918 memmove(&pp->arg[i + 1], &pp->arg[i],
5919 sizeof(pp->arg[0]) * pp->argc_stack);
5920 memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
5921 pp->arg[i].reg = strdup(reg);
5922 pp->arg[i].type.name = strdup("int");
5927 static void output_std_flag_z(FILE *fout, struct parsed_op *po,
5928 int *pfomask, const char *dst_opr_text)
5930 if (*pfomask & (1 << PFO_Z)) {
5931 fprintf(fout, "\n cond_z = (%s%s == 0);",
5932 lmod_cast_u(po, po->operand[0].lmod), dst_opr_text);
5933 *pfomask &= ~(1 << PFO_Z);
5937 static void output_std_flag_s(FILE *fout, struct parsed_op *po,
5938 int *pfomask, const char *dst_opr_text)
5940 if (*pfomask & (1 << PFO_S)) {
5941 fprintf(fout, "\n cond_s = (%s%s < 0);",
5942 lmod_cast_s(po, po->operand[0].lmod), dst_opr_text);
5943 *pfomask &= ~(1 << PFO_S);
5947 static void output_std_flags(FILE *fout, struct parsed_op *po,
5948 int *pfomask, const char *dst_opr_text)
5950 output_std_flag_z(fout, po, pfomask, dst_opr_text);
5951 output_std_flag_s(fout, po, pfomask, dst_opr_text);
5955 OPP_FORCE_NORETURN = (1 << 0),
5956 OPP_SIMPLE_ARGS = (1 << 1),
5957 OPP_ALIGN = (1 << 2),
5960 static void output_pp_attrs(FILE *fout, const struct parsed_proto *pp,
5963 const char *cconv = "";
5965 if (pp->is_fastcall)
5966 cconv = "__fastcall ";
5967 else if (pp->is_stdcall && pp->argc_reg == 0)
5968 cconv = "__stdcall ";
5970 fprintf(fout, (flags & OPP_ALIGN) ? "%-16s" : "%s", cconv);
5972 if (pp->is_noreturn || (flags & OPP_FORCE_NORETURN))
5973 fprintf(fout, "noreturn ");
5976 static void output_pp(FILE *fout, const struct parsed_proto *pp,
5981 fprintf(fout, (flags & OPP_ALIGN) ? "%-5s" : "%s ",
5985 output_pp_attrs(fout, pp, flags);
5988 fprintf(fout, "%s", pp->name);
5993 for (i = 0; i < pp->argc; i++) {
5995 fprintf(fout, ", ");
5996 if (pp->arg[i].pp != NULL && pp->arg[i].pp->is_func
5997 && !(flags & OPP_SIMPLE_ARGS))
6000 output_pp(fout, pp->arg[i].pp, 0);
6002 else if (pp->arg[i].type.is_retreg) {
6003 fprintf(fout, "u32 *r_%s", pp->arg[i].reg);
6006 fprintf(fout, "%s", pp->arg[i].type.name);
6008 fprintf(fout, " a%d", i + 1);
6011 if (pp->arg[i].type.is_64bit)
6014 if (pp->is_vararg) {
6016 fprintf(fout, ", ");
6017 fprintf(fout, "...");
6022 static char *saved_arg_name(char *buf, size_t buf_size, int grp, int num)
6028 snprintf(buf1, sizeof(buf1), "%d", grp);
6029 snprintf(buf, buf_size, "s%s_a%d", buf1, num);
6034 static void gen_x_cleanup(int opcnt);
6036 static void gen_func(FILE *fout, FILE *fhdr, const char *funcn, int opcnt)
6038 struct parsed_op *po, *delayed_flag_op = NULL, *tmp_op;
6039 struct parsed_opr *last_arith_dst = NULL;
6040 char buf1[256], buf2[256], buf3[256], cast[64];
6041 struct parsed_proto *pp, *pp_tmp;
6042 struct parsed_data *pd;
6043 int save_arg_vars[MAX_ARG_GRP] = { 0, };
6044 unsigned char cbits[MAX_OPS / 8];
6045 const char *float_type;
6046 const char *float_st0;
6047 const char *float_st1;
6048 int need_float_stack = 0;
6049 int need_float_sw = 0; // status word
6050 int need_tmp_var = 0;
6054 int label_pending = 0;
6055 int need_double = 0;
6056 int stack_align = 0;
6057 int stack_fsz_adj = 0;
6058 int lock_handled = 0;
6059 int regmask_save = 0; // used regs saved/restored in this func
6060 int regmask_arg; // regs from this function args (fastcall, etc)
6061 int regmask_ret; // regs needed on ret
6062 int regmask_now; // temp
6063 int regmask_init = 0; // regs that need zero initialization
6064 int regmask_pp = 0; // regs used in complex push-pop graph
6065 int regmask_ffca = 0; // float function call args
6066 int regmask = 0; // used regs
6076 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
6077 g_stack_frame_used = 0;
6079 if (g_sct_func_attr & SCTFA_CLEAR_REGS)
6080 regmask_init = g_regmask_init;
6082 g_func_pp = proto_parse(fhdr, funcn, 0);
6083 if (g_func_pp == NULL)
6084 ferr(ops, "proto_parse failed for '%s'\n", funcn);
6086 regmask_arg = get_pp_arg_regmask_src(g_func_pp);
6087 regmask_ret = get_pp_arg_regmask_dst(g_func_pp);
6090 // - resolve all branches
6091 // - parse calls with labels
6092 resolve_branches_parse_calls(opcnt);
6095 // - handle ebp/esp frame, remove ops related to it
6096 scan_prologue_epilogue(opcnt, &stack_align);
6098 // handle a case where sf size is unalignment, but is
6099 // placed in a way that elements are still aligned
6100 if (g_stack_fsz & 4) {
6101 for (i = 0; i < g_eqcnt; i++) {
6102 if (g_eqs[i].lmod != OPLM_QWORD)
6104 if (!(g_eqs[i].offset & 4)) {
6113 // - remove dead labels
6114 // - set regs needed at ret
6115 for (i = 0; i < opcnt; i++)
6117 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
6122 if (ops[i].op == OP_RET)
6123 ops[i].regmask_src |= regmask_ret;
6127 // - process trivial calls
6128 for (i = 0; i < opcnt; i++)
6131 if (po->flags & (OPF_RMD|OPF_DONE))
6134 if (po->op == OP_CALL)
6136 pp = process_call_early(i, opcnt, &j);
6138 if (!(po->flags & OPF_ATAIL)) {
6139 // since we know the args, try to collect them
6140 ret = collect_call_args_early(i, pp, ®mask, ®mask_ffca);
6148 // commit esp adjust
6149 if (ops[j].op != OP_POP)
6150 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
6152 for (l = 0; l < pp->argc_stack; l++)
6153 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
6157 if (strstr(pp->ret_type.name, "int64"))
6160 po->flags |= OPF_DONE;
6166 // - process calls, stage 2
6167 // - handle some push/pop pairs
6168 // - scan for STD/CLD, propagate DF
6169 // - try to resolve needed x87 status word bits
6170 for (i = 0; i < opcnt; i++)
6175 if (po->flags & OPF_RMD)
6178 if (po->op == OP_CALL)
6180 if (!(po->flags & OPF_DONE)) {
6181 pp = process_call(i, opcnt);
6183 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
6184 // since we know the args, collect them
6185 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6187 // for unresolved, collect after other passes
6191 ferr_assert(po, pp != NULL);
6193 po->regmask_src |= get_pp_arg_regmask_src(pp);
6194 po->regmask_dst |= get_pp_arg_regmask_dst(pp);
6196 if (po->regmask_dst & mxST0)
6197 po->flags |= OPF_FPUSH;
6199 if (strstr(pp->ret_type.name, "int64"))
6205 if (po->flags & OPF_DONE)
6210 if (!(po->flags & OPF_FARG) && !(po->flags & OPF_RSAVE)
6211 && po->operand[0].type == OPT_CONST)
6213 scan_for_pop_const(i, opcnt, i + opcnt * 12);
6218 scan_pushes_for_pop(i, opcnt, ®mask_pp);
6222 po->flags |= OPF_DF | OPF_RMD | OPF_DONE;
6223 scan_propagate_df(i + 1, opcnt);
6228 if (po->operand[0].type != OPT_REG || po->operand[0].reg != xAX)
6229 ferr(po, "TODO: fnstsw to mem\n");
6230 ret = resolve_used_bits(i + 1, opcnt, xAX, &mask, &z_check);
6232 ferr(po, "fnstsw resolve failed\n");
6233 ret = adjust_prev_op(i, OP_FCOM, i + opcnt * 21,
6234 (void *)(long)(mask | (z_check << 16)));
6236 ferr(po, "failed to find fcom: %d\n", ret);
6245 // - find POPs for PUSHes, rm both
6246 // - scan for all used registers
6247 memset(cbits, 0, sizeof(cbits));
6248 reg_use_pass(0, opcnt, cbits, regmask_init, ®mask,
6249 0, ®mask_save, ®mask_init, regmask_arg);
6251 need_float_stack = !!(regmask & mxST7_2);
6254 // - find flag set ops for their users
6255 // - do unresolved calls
6256 // - declare indirect functions
6257 // - other op specific processing
6258 for (i = 0; i < opcnt; i++)
6261 if (po->flags & (OPF_RMD|OPF_DONE))
6264 if (po->flags & OPF_CC)
6266 int setters[16], cnt = 0, branched = 0;
6268 ret = scan_for_flag_set(i, opcnt, i + opcnt * 6,
6269 &branched, setters, &cnt);
6270 if (ret < 0 || cnt <= 0)
6271 ferr(po, "unable to trace flag setter(s)\n");
6272 if (cnt > ARRAY_SIZE(setters))
6273 ferr(po, "too many flag setters\n");
6275 for (j = 0; j < cnt; j++)
6277 tmp_op = &ops[setters[j]]; // flag setter
6280 // to get nicer code, we try to delay test and cmp;
6281 // if we can't because of operand modification, or if we
6282 // have arith op, or branch, make it calculate flags explicitly
6283 if (tmp_op->op == OP_TEST || tmp_op->op == OP_CMP)
6285 if (branched || scan_for_mod(tmp_op, setters[j] + 1, i, 0) >= 0)
6286 pfomask = 1 << po->pfo;
6288 else if (tmp_op->op == OP_CMPS || tmp_op->op == OP_SCAS) {
6289 pfomask = 1 << po->pfo;
6292 // see if we'll be able to handle based on op result
6293 if ((tmp_op->op != OP_AND && tmp_op->op != OP_OR
6294 && po->pfo != PFO_Z && po->pfo != PFO_S
6295 && po->pfo != PFO_P)
6297 || scan_for_mod_opr0(tmp_op, setters[j] + 1, i) >= 0)
6299 pfomask = 1 << po->pfo;
6302 if (tmp_op->op == OP_ADD && po->pfo == PFO_C) {
6303 propagate_lmod(tmp_op, &tmp_op->operand[0],
6304 &tmp_op->operand[1]);
6305 if (tmp_op->operand[0].lmod == OPLM_DWORD)
6310 tmp_op->pfomask |= pfomask;
6311 cond_vars |= pfomask;
6313 // note: may overwrite, currently not a problem
6317 if (po->op == OP_RCL || po->op == OP_RCR
6318 || po->op == OP_ADC || po->op == OP_SBB)
6319 cond_vars |= 1 << PFO_C;
6325 cond_vars |= 1 << PFO_Z;
6329 if (po->operand[0].lmod == OPLM_DWORD)
6334 if (po->operand_cnt == 1 && po->operand[0].lmod == OPLM_DWORD)
6339 // note: resolved non-reg calls are OPF_DONE already
6341 ferr_assert(po, pp != NULL);
6343 if (pp->is_unresolved) {
6344 int regmask_stack = 0;
6345 collect_call_args(po, i, pp, ®mask, i + opcnt * 2);
6347 // this is pretty rough guess:
6348 // see ecx and edx were pushed (and not their saved versions)
6349 for (arg = 0; arg < pp->argc; arg++) {
6350 if (pp->arg[arg].reg != NULL && !pp->arg[arg].is_saved)
6353 tmp_op = pp->arg[arg].datap;
6355 ferr(po, "parsed_op missing for arg%d\n", arg);
6356 if (tmp_op->operand[0].type == OPT_REG)
6357 regmask_stack |= 1 << tmp_op->operand[0].reg;
6360 // quick dumb check for potential reg-args
6361 for (j = i - 1; j >= 0 && ops[j].op == OP_MOV; j--)
6362 if (ops[j].operand[0].type == OPT_REG)
6363 regmask_stack &= ~(1 << ops[j].operand[0].reg);
6365 if ((regmask_stack & (mxCX|mxDX)) != (mxCX|mxDX)
6366 && ((regmask | regmask_arg) & (mxCX|mxDX)))
6368 if (pp->argc_stack != 0
6369 || ((regmask | regmask_arg) & (mxCX|mxDX)))
6371 pp_insert_reg_arg(pp, "ecx");
6372 pp->is_fastcall = 1;
6373 regmask_init |= 1 << xCX;
6374 regmask |= 1 << xCX;
6376 if (pp->argc_stack != 0
6377 || ((regmask | regmask_arg) & mxDX))
6379 pp_insert_reg_arg(pp, "edx");
6380 regmask_init |= 1 << xDX;
6381 regmask |= 1 << xDX;
6385 // note: __cdecl doesn't fall into is_unresolved category
6386 if (pp->argc_stack > 0)
6389 if (!(po->flags & OPF_TAIL)
6390 && !(g_sct_func_attr & SCTFA_NOWARN) && !g_nowarn_reguse)
6392 // treat al write as overwrite to avoid many false positives
6393 if (IS(pp->ret_type.name, "void") || pp->ret_type.is_float) {
6394 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
6395 i + opcnt * 25, &j);
6397 fnote(po, "eax used after void/float ret call\n");
6398 fnote(&ops[j], "(used here)\n");
6401 if (!strstr(pp->ret_type.name, "int64")) {
6402 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
6403 i + opcnt * 26, &j);
6404 // indirect calls are often guessed, don't warn
6405 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6406 fnote(po, "edx used after 32bit ret call\n");
6407 fnote(&ops[j], "(used here)\n");
6411 // msvc often relies on callee not modifying 'this'
6412 for (arg = 0; arg < pp->argc; arg++) {
6413 if (pp->arg[arg].reg && IS(pp->arg[arg].reg, "ecx")) {
6419 find_next_read_reg(i + 1, opcnt, xCX, OPLM_BYTE,
6420 i + opcnt * 27, &j);
6421 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j])) {
6422 fnote(po, "ecx used after call\n");
6423 fnote(&ops[j], "(used here)\n");
6430 if (po->operand[0].pp != NULL && po->operand[1].pp != NULL)
6432 // <var> = offset <something>
6433 if ((po->operand[1].pp->is_func || po->operand[1].pp->is_fptr)
6434 && !IS_START(po->operand[1].name, "off_"))
6436 if (!po->operand[0].pp->is_fptr)
6437 ferr(po, "%s not declared as fptr when it should be\n",
6438 po->operand[0].name);
6439 if (pp_cmp_func(po->operand[0].pp, po->operand[1].pp)) {
6440 pp_print(buf1, sizeof(buf1), po->operand[0].pp);
6441 pp_print(buf2, sizeof(buf2), po->operand[1].pp);
6442 fnote(po, "var: %s\n", buf1);
6443 fnote(po, "func: %s\n", buf2);
6444 ferr(po, "^ mismatch\n");
6452 if (po->operand[0].lmod == OPLM_DWORD) {
6453 // 32bit division is common, look for it
6454 if (po->op == OP_DIV)
6455 ret = scan_for_reg_clear(i, xDX);
6457 ret = scan_for_cdq_edx(i);
6459 po->flags |= OPF_32BIT;
6468 po->flags |= OPF_RMD | OPF_DONE;
6478 if (po->operand[0].lmod == OPLM_QWORD)
6489 find_next_read_reg(i + 1, opcnt, xDX, OPLM_DWORD,
6490 i + opcnt * 18, &j);
6492 po->flags |= OPF_32BIT;
6500 // pass8: final adjustments
6501 for (i = 0; i < opcnt; i++)
6504 if (po->flags & (OPF_RMD|OPF_DONE))
6507 if (po->op != OP_FST && po->p_argnum > 0)
6508 save_arg_vars[po->p_arggrp] |= 1 << (po->p_argnum - 1);
6510 // correct for "full stack" mode late enable
6511 if ((po->flags & (OPF_PPUSH|OPF_FPOP|OPF_FPOPP))
6512 && need_float_stack)
6513 po->flags |= OPF_FSHIFT;
6516 float_type = need_double ? "double" : "float";
6517 float_st0 = need_float_stack ? "f_st[f_stp & 7]" : "f_st0";
6518 float_st1 = need_float_stack ? "f_st[(f_stp + 1) & 7]" : "f_st1";
6520 // output starts here
6523 fprintf(fout, "// had SEH\n");
6525 // define userstack size
6526 if (g_func_pp->is_userstack) {
6527 fprintf(fout, "#ifndef US_SZ_%s\n", g_func_pp->name);
6528 fprintf(fout, "#define US_SZ_%s USERSTACK_SIZE\n", g_func_pp->name);
6529 fprintf(fout, "#endif\n");
6532 // the function itself
6533 ferr_assert(ops, !g_func_pp->is_fptr);
6534 output_pp(fout, g_func_pp,
6535 (g_ida_func_attr & IDAFA_NORETURN) ? OPP_FORCE_NORETURN : 0);
6536 fprintf(fout, "\n{\n");
6538 // declare indirect functions
6539 for (i = 0; i < opcnt; i++) {
6541 if (po->flags & OPF_RMD)
6544 if (po->op == OP_CALL) {
6547 ferr(po, "NULL pp\n");
6549 if (pp->is_fptr && !(pp->name[0] != 0 && pp->is_arg)) {
6550 if (pp->name[0] != 0) {
6551 if (IS_START(pp->name, "guess"))
6554 memmove(pp->name + 2, pp->name, strlen(pp->name) + 1);
6555 memcpy(pp->name, "i_", 2);
6557 // might be declared already
6559 for (j = 0; j < i; j++) {
6560 if (ops[j].op == OP_CALL && (pp_tmp = ops[j].pp)) {
6561 if (pp_tmp->is_fptr && IS(pp->name, pp_tmp->name)) {
6571 snprintf(pp->name, sizeof(pp->name), "icall%d", i);
6574 output_pp(fout, pp, OPP_SIMPLE_ARGS);
6575 fprintf(fout, ";\n");
6580 // output LUTs/jumptables
6581 for (i = 0; i < g_func_pd_cnt; i++) {
6583 fprintf(fout, " static const ");
6584 if (pd->type == OPT_OFFSET) {
6585 fprintf(fout, "void *jt_%s[] =\n { ", pd->label);
6587 for (j = 0; j < pd->count; j++) {
6589 fprintf(fout, ", ");
6590 fprintf(fout, "&&%s", pd->d[j].u.label);
6594 fprintf(fout, "%s %s[] =\n { ",
6595 lmod_type_u(ops, pd->lmod), pd->label);
6597 for (j = 0; j < pd->count; j++) {
6599 fprintf(fout, ", ");
6600 fprintf(fout, "%u", pd->d[j].u.val);
6603 fprintf(fout, " };\n");
6607 // declare stack frame, va_arg
6610 fprintf(fout, " // stack_fsz_adj %d\n", stack_fsz_adj);
6612 fprintf(fout, " union { u32 d[%d];", (g_stack_fsz + 3) / 4);
6613 if (g_func_lmods & (1 << OPLM_WORD))
6614 fprintf(fout, " u16 w[%d];", (g_stack_fsz + 1) / 2);
6615 if (g_func_lmods & (1 << OPLM_BYTE))
6616 fprintf(fout, " u8 b[%d];", g_stack_fsz);
6617 if (g_func_lmods & (1 << OPLM_QWORD))
6618 fprintf(fout, " double q[%d];", (g_stack_fsz + 7) / 8);
6620 if (stack_align > 8)
6621 ferr(ops, "unhandled stack align of %d\n", stack_align);
6622 else if (stack_align == 8)
6623 fprintf(fout, " u64 align;");
6624 fprintf(fout, " } sf;\n");
6628 if ((g_sct_func_attr & SCTFA_ARGFRAME) && g_func_pp->argc_stack) {
6629 fprintf(fout, " struct { u32 ");
6630 for (i = j = 0; i < g_func_pp->argc; i++) {
6631 if (g_func_pp->arg[i].reg != NULL)
6634 fprintf(fout, ", ");
6635 fprintf(fout, "a%d", i + 1);
6637 fprintf(fout, "; } af = {\n ");
6638 for (i = j = 0; i < g_func_pp->argc; i++) {
6639 if (g_func_pp->arg[i].reg != NULL)
6642 fprintf(fout, ", ");
6643 if (g_func_pp->arg[i].type.is_ptr)
6644 fprintf(fout, "(u32)");
6645 fprintf(fout, "a%d", i + 1);
6647 fprintf(fout, "\n };\n");
6650 if (g_func_pp->is_userstack) {
6651 fprintf(fout, " u32 fake_sf[US_SZ_%s / 4];\n", g_func_pp->name);
6652 fprintf(fout, " u32 *esp = &fake_sf[sizeof(fake_sf) / 4];\n");
6656 if (g_func_pp->is_vararg) {
6657 fprintf(fout, " va_list ap;\n");
6661 // declare arg-registers
6662 for (i = 0; i < g_func_pp->argc; i++) {
6663 if (g_func_pp->arg[i].reg != NULL) {
6664 reg = char_array_i(regs_r32,
6665 ARRAY_SIZE(regs_r32), g_func_pp->arg[i].reg);
6666 if (regmask & (1 << reg)) {
6667 if (g_func_pp->arg[i].type.is_retreg)
6668 fprintf(fout, " u32 %s = *r_%s;\n",
6669 g_func_pp->arg[i].reg, g_func_pp->arg[i].reg);
6671 fprintf(fout, " u32 %s = (u32)a%d;\n",
6672 g_func_pp->arg[i].reg, i + 1);
6675 if (g_func_pp->arg[i].type.is_retreg)
6676 ferr(ops, "retreg '%s' is unused?\n",
6677 g_func_pp->arg[i].reg);
6678 fprintf(fout, " // %s = a%d; // unused\n",
6679 g_func_pp->arg[i].reg, i + 1);
6685 // declare normal registers
6686 regmask_now = regmask & ~regmask_arg & ~g_regmask_rm;
6687 regmask_now &= ~(1 << xSP);
6688 if (regmask_now & 0x00ff) {
6689 for (reg = 0; reg < 8; reg++) {
6690 if (regmask_now & (1 << reg)) {
6691 fprintf(fout, " u32 %s", regs_r32[reg]);
6692 if (regmask_init & (1 << reg))
6693 fprintf(fout, " = 0");
6694 fprintf(fout, ";\n");
6700 if (regmask_now & 0xff00) {
6701 for (reg = 8; reg < 16; reg++) {
6702 if (regmask_now & (1 << reg)) {
6703 fprintf(fout, " mmxr %s", regs_r32[reg]);
6704 if (regmask_init & (1 << reg))
6705 fprintf(fout, " = { 0, }");
6706 fprintf(fout, ";\n");
6712 if (need_float_stack) {
6713 fprintf(fout, " %s f_st[8];\n", float_type);
6714 fprintf(fout, " int f_stp = 0;\n");
6718 if (regmask_now & 0xff0000) {
6719 for (reg = 16; reg < 24; reg++) {
6720 if (regmask_now & (1 << reg)) {
6721 fprintf(fout, " %s f_st%d", float_type, reg - 16);
6722 if (regmask_init & (1 << reg))
6723 fprintf(fout, " = 0");
6724 fprintf(fout, ";\n");
6731 if (need_float_sw) {
6732 fprintf(fout, " u16 f_sw;\n");
6737 for (reg = 0; reg < 8; reg++) {
6738 if (regmask_save & (1 << reg)) {
6739 fprintf(fout, " u32 s_%s;\n", regs_r32[reg]);
6745 for (i = 0; i < ARRAY_SIZE(save_arg_vars); i++) {
6746 if (save_arg_vars[i] == 0)
6748 for (reg = 0; reg < 32; reg++) {
6749 if (save_arg_vars[i] & (1 << reg)) {
6750 fprintf(fout, " u32 %s;\n",
6751 saved_arg_name(buf1, sizeof(buf1), i, reg + 1));
6758 for (reg = 0; reg < 32; reg++) {
6759 if (regmask_ffca & (1 << reg)) {
6760 fprintf(fout, " %s fs_%d;\n", float_type, reg + 1);
6766 // declare push-pop temporaries
6768 for (reg = 0; reg < 8; reg++) {
6769 if (regmask_pp & (1 << reg)) {
6770 fprintf(fout, " u32 pp_%s;\n", regs_r32[reg]);
6777 for (i = 0; i < 8; i++) {
6778 if (cond_vars & (1 << i)) {
6779 fprintf(fout, " u32 cond_%s;\n", parsed_flag_op_names[i]);
6786 fprintf(fout, " u32 tmp;\n");
6791 fprintf(fout, " u64 tmp64;\n");
6796 fprintf(fout, "\n");
6798 // do stack clear, if needed
6799 if (g_sct_func_attr & SCTFA_CLEAR_SF) {
6801 if (g_stack_clear_len != 0) {
6802 if (g_stack_clear_len <= 4) {
6803 for (i = 0; i < g_stack_clear_len; i++)
6804 fprintf(fout, "sf.d[%d] = ", g_stack_clear_start + i);
6805 fprintf(fout, "0;\n");
6808 fprintf(fout, "memset(&sf[%d], 0, %d);\n",
6809 g_stack_clear_start, g_stack_clear_len * 4);
6813 fprintf(fout, "memset(&sf, 0, sizeof(sf));\n");
6816 if (g_func_pp->is_vararg) {
6817 if (g_func_pp->argc_stack == 0)
6818 ferr(ops, "vararg func without stack args?\n");
6819 fprintf(fout, " va_start(ap, a%d);\n", g_func_pp->argc);
6823 for (i = 0; i < opcnt; i++)
6825 if (g_labels[i] != NULL) {
6826 fprintf(fout, "\n%s:\n", g_labels[i]);
6829 delayed_flag_op = NULL;
6830 last_arith_dst = NULL;
6834 if (po->flags & OPF_RMD)
6840 #define assert_operand_cnt(n_) \
6841 if (po->operand_cnt != n_) \
6842 ferr(po, "operand_cnt is %d/%d\n", po->operand_cnt, n_)
6844 // conditional/flag using op?
6845 if (po->flags & OPF_CC)
6851 // we go through all this trouble to avoid using parsed_flag_op,
6852 // which makes generated code much nicer
6853 if (delayed_flag_op != NULL)
6855 out_cmp_test(buf1, sizeof(buf1), delayed_flag_op,
6856 po->pfo, po->pfo_inv);
6859 else if (last_arith_dst != NULL
6860 && (po->pfo == PFO_Z || po->pfo == PFO_S || po->pfo == PFO_P
6861 || (tmp_op && (tmp_op->op == OP_AND || tmp_op->op == OP_OR))
6864 out_src_opr_u32(buf3, sizeof(buf3), po, last_arith_dst);
6865 out_test_for_cc(buf1, sizeof(buf1), po, po->pfo, po->pfo_inv,
6866 last_arith_dst->lmod, buf3);
6869 else if (tmp_op != NULL) {
6870 // use preprocessed flag calc results
6871 if (!(tmp_op->pfomask & (1 << po->pfo)))
6872 ferr(po, "not prepared for pfo %d\n", po->pfo);
6874 // note: pfo_inv was not yet applied
6875 snprintf(buf1, sizeof(buf1), "(%scond_%s)",
6876 po->pfo_inv ? "!" : "", parsed_flag_op_names[po->pfo]);
6879 ferr(po, "all methods of finding comparison failed\n");
6882 if (po->flags & OPF_JMP) {
6883 fprintf(fout, " if %s", buf1);
6885 else if (po->op == OP_RCL || po->op == OP_RCR
6886 || po->op == OP_ADC || po->op == OP_SBB)
6889 fprintf(fout, " cond_%s = %s;\n",
6890 parsed_flag_op_names[po->pfo], buf1);
6892 else if (po->flags & OPF_DATA) { // SETcc
6893 out_dst_opr(buf2, sizeof(buf2), po, &po->operand[0]);
6894 fprintf(fout, " %s = %s;", buf2, buf1);
6897 ferr(po, "unhandled conditional op\n");
6901 pfomask = po->pfomask;
6906 assert_operand_cnt(2);
6907 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6908 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6909 default_cast_to(buf3, sizeof(buf3), &po->operand[0]);
6910 fprintf(fout, " %s = %s;", buf1,
6911 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6916 assert_operand_cnt(2);
6917 po->operand[1].lmod = OPLM_DWORD; // always
6918 fprintf(fout, " %s = %s;",
6919 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6920 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6925 assert_operand_cnt(2);
6926 fprintf(fout, " %s = %s;",
6927 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6928 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6932 assert_operand_cnt(2);
6933 switch (po->operand[1].lmod) {
6935 strcpy(buf3, "(s8)");
6938 strcpy(buf3, "(s16)");
6941 ferr(po, "invalid src lmod: %d\n", po->operand[1].lmod);
6943 fprintf(fout, " %s = %s;",
6944 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6945 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6950 assert_operand_cnt(2);
6951 propagate_lmod(po, &po->operand[0], &po->operand[1]);
6952 fprintf(fout, " tmp = %s;",
6953 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0], "", 0));
6954 fprintf(fout, " %s = %s;",
6955 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6956 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
6957 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
6958 fprintf(fout, " %s = %stmp;",
6959 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
6960 default_cast_to(buf3, sizeof(buf3), &po->operand[1]));
6961 snprintf(g_comment, sizeof(g_comment), "xchg");
6965 assert_operand_cnt(1);
6966 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6967 fprintf(fout, " %s = ~%s;", buf1, buf1);
6971 assert_operand_cnt(2);
6972 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6973 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
6974 fprintf(fout, " %s = *(u8 *)(%s + %s);", buf1, buf2, buf1);
6975 strcpy(g_comment, "xlat");
6979 assert_operand_cnt(2);
6980 fprintf(fout, " %s = (s32)%s >> 31;",
6981 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
6982 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
6983 strcpy(g_comment, "cdq");
6987 assert_operand_cnt(1);
6988 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
6989 fprintf(fout, " %s = __builtin_bswap32(%s);", buf1, buf1);
6993 if (po->flags & OPF_REP) {
6994 assert_operand_cnt(3);
6999 assert_operand_cnt(2);
7000 fprintf(fout, " %s = %sesi; esi %c= %d;",
7001 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[1]),
7002 lmod_cast_u_ptr(po, po->operand[1].lmod),
7003 (po->flags & OPF_DF) ? '-' : '+',
7004 lmod_bytes(po, po->operand[1].lmod));
7005 strcpy(g_comment, "lods");
7010 if (po->flags & OPF_REP) {
7011 assert_operand_cnt(3);
7012 fprintf(fout, " for (; ecx != 0; ecx--, edi %c= %d)\n",
7013 (po->flags & OPF_DF) ? '-' : '+',
7014 lmod_bytes(po, po->operand[1].lmod));
7015 fprintf(fout, " %sedi = eax;\n",
7016 lmod_cast_u_ptr(po, po->operand[1].lmod));
7017 fprintf(fout, " barrier();");
7018 strcpy(g_comment, "^ rep stos");
7021 assert_operand_cnt(2);
7022 fprintf(fout, " %sedi = eax; edi %c= %d;",
7023 lmod_cast_u_ptr(po, po->operand[1].lmod),
7024 (po->flags & OPF_DF) ? '-' : '+',
7025 lmod_bytes(po, po->operand[1].lmod));
7026 strcpy(g_comment, "stos");
7031 j = lmod_bytes(po, po->operand[0].lmod);
7032 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
7033 l = (po->flags & OPF_DF) ? '-' : '+';
7034 if (po->flags & OPF_REP) {
7035 assert_operand_cnt(3);
7037 " for (; ecx != 0; ecx--, edi %c= %d, esi %c= %d)\n",
7040 " %sedi = %sesi;\n", buf1, buf1);
7041 // this can overwrite many variables
7042 fprintf(fout, " barrier();");
7043 strcpy(g_comment, "^ rep movs");
7046 assert_operand_cnt(2);
7047 fprintf(fout, " %sedi = %sesi; edi %c= %d; esi %c= %d;",
7048 buf1, buf1, l, j, l, j);
7049 strcpy(g_comment, "movs");
7054 // repe ~ repeat while ZF=1
7055 j = lmod_bytes(po, po->operand[0].lmod);
7056 strcpy(buf1, lmod_cast_u_ptr(po, po->operand[0].lmod));
7057 l = (po->flags & OPF_DF) ? '-' : '+';
7058 if (po->flags & OPF_REP) {
7059 assert_operand_cnt(3);
7061 " while (ecx != 0) {\n");
7062 if (pfomask & (1 << PFO_C)) {
7065 " cond_c = %sesi < %sedi;\n", buf1, buf1);
7066 pfomask &= ~(1 << PFO_C);
7069 " cond_z = (%sesi == %sedi); esi %c= %d, edi %c= %d;\n",
7070 buf1, buf1, l, j, l, j);
7073 " if (cond_z %s 0) break;\n",
7074 (po->flags & OPF_REPZ) ? "==" : "!=");
7077 snprintf(g_comment, sizeof(g_comment), "rep%s cmps",
7078 (po->flags & OPF_REPZ) ? "e" : "ne");
7081 assert_operand_cnt(2);
7083 " cond_z = (%sesi == %sedi); esi %c= %d; edi %c= %d;",
7084 buf1, buf1, l, j, l, j);
7085 strcpy(g_comment, "cmps");
7087 pfomask &= ~(1 << PFO_Z);
7088 last_arith_dst = NULL;
7089 delayed_flag_op = NULL;
7093 // only does ZF (for now)
7094 // repe ~ repeat while ZF=1
7095 j = lmod_bytes(po, po->operand[1].lmod);
7096 l = (po->flags & OPF_DF) ? '-' : '+';
7097 if (po->flags & OPF_REP) {
7098 assert_operand_cnt(3);
7100 " while (ecx != 0) {\n");
7102 " cond_z = (%seax == %sedi); edi %c= %d;\n",
7103 lmod_cast_u(po, po->operand[1].lmod),
7104 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
7107 " if (cond_z %s 0) break;\n",
7108 (po->flags & OPF_REPZ) ? "==" : "!=");
7111 snprintf(g_comment, sizeof(g_comment), "rep%s scas",
7112 (po->flags & OPF_REPZ) ? "e" : "ne");
7115 assert_operand_cnt(2);
7116 fprintf(fout, " cond_z = (%seax == %sedi); edi %c= %d;",
7117 lmod_cast_u(po, po->operand[1].lmod),
7118 lmod_cast_u_ptr(po, po->operand[1].lmod), l, j);
7119 strcpy(g_comment, "scas");
7121 pfomask &= ~(1 << PFO_Z);
7122 last_arith_dst = NULL;
7123 delayed_flag_op = NULL;
7127 fprintf(fout, " tmp64 = ext_rdtsc();\n");
7128 fprintf(fout, " edx = tmp64 >> 32;\n");
7129 fprintf(fout, " eax = tmp64;");
7133 fprintf(fout, " ext_cpuid(&eax, &ebx, &ecx, &edx);");
7136 // arithmetic w/flags
7138 if (po->operand[1].type == OPT_CONST && !po->operand[1].val)
7139 goto dualop_arith_const;
7140 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7144 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7145 if (po->operand[1].type == OPT_CONST) {
7146 j = lmod_bytes(po, po->operand[0].lmod);
7147 if (((1ull << j * 8) - 1) == po->operand[1].val)
7148 goto dualop_arith_const;
7153 assert_operand_cnt(2);
7154 fprintf(fout, " %s %s= %s;",
7155 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7157 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7158 output_std_flags(fout, po, &pfomask, buf1);
7159 last_arith_dst = &po->operand[0];
7160 delayed_flag_op = NULL;
7164 // and 0, or ~0 used instead mov
7165 assert_operand_cnt(2);
7166 fprintf(fout, " %s = %s;",
7167 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7168 out_src_opr(buf2, sizeof(buf2), po, &po->operand[1],
7169 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7170 output_std_flags(fout, po, &pfomask, buf1);
7171 last_arith_dst = &po->operand[0];
7172 delayed_flag_op = NULL;
7177 assert_operand_cnt(2);
7178 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7179 if (pfomask & (1 << PFO_C)) {
7180 if (po->operand[1].type == OPT_CONST) {
7181 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7182 j = po->operand[1].val;
7185 if (po->op == OP_SHL)
7189 fprintf(fout, " cond_c = (%s >> %d) & 1;\n",
7193 ferr(po, "zero shift?\n");
7197 pfomask &= ~(1 << PFO_C);
7199 fprintf(fout, " %s %s= %s", buf1, op_to_c(po),
7200 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7201 if (po->operand[1].type != OPT_CONST)
7202 fprintf(fout, " & 0x1f");
7204 output_std_flags(fout, po, &pfomask, buf1);
7205 last_arith_dst = &po->operand[0];
7206 delayed_flag_op = NULL;
7210 assert_operand_cnt(2);
7211 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7212 fprintf(fout, " %s = %s%s >> %s;", buf1,
7213 lmod_cast_s(po, po->operand[0].lmod), buf1,
7214 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7215 output_std_flags(fout, po, &pfomask, buf1);
7216 last_arith_dst = &po->operand[0];
7217 delayed_flag_op = NULL;
7222 assert_operand_cnt(3);
7223 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7224 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7225 out_src_opr_u32(buf3, sizeof(buf3), po, &po->operand[2]);
7226 if (po->operand[2].type != OPT_CONST) {
7227 // no handling for "undefined" case, hopefully not needed
7228 snprintf(buf2, sizeof(buf2), "(%s & 0x1f)", buf3);
7231 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7232 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7233 if (po->op == OP_SHLD) {
7234 fprintf(fout, " %s <<= %s; %s |= %s >> (%d - %s);",
7235 buf1, buf3, buf1, buf2, l, buf3);
7236 strcpy(g_comment, "shld");
7239 fprintf(fout, " %s >>= %s; %s |= %s << (%d - %s);",
7240 buf1, buf3, buf1, buf2, l, buf3);
7241 strcpy(g_comment, "shrd");
7243 output_std_flags(fout, po, &pfomask, buf1);
7244 last_arith_dst = &po->operand[0];
7245 delayed_flag_op = NULL;
7250 assert_operand_cnt(2);
7251 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7252 if (po->operand[1].type == OPT_CONST) {
7253 j = po->operand[1].val;
7254 j %= lmod_bytes(po, po->operand[0].lmod) * 8;
7255 fprintf(fout, po->op == OP_ROL ?
7256 " %s = (%s << %d) | (%s >> %d);" :
7257 " %s = (%s >> %d) | (%s << %d);",
7258 buf1, buf1, j, buf1,
7259 lmod_bytes(po, po->operand[0].lmod) * 8 - j);
7263 output_std_flags(fout, po, &pfomask, buf1);
7264 last_arith_dst = &po->operand[0];
7265 delayed_flag_op = NULL;
7270 assert_operand_cnt(2);
7271 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7272 l = lmod_bytes(po, po->operand[0].lmod) * 8;
7273 if (po->operand[1].type == OPT_CONST) {
7274 j = po->operand[1].val % l;
7276 ferr(po, "zero rotate\n");
7277 fprintf(fout, " tmp = (%s >> %d) & 1;\n",
7278 buf1, (po->op == OP_RCL) ? (l - j) : (j - 1));
7279 if (po->op == OP_RCL) {
7281 " %s = (%s << %d) | (cond_c << %d)",
7282 buf1, buf1, j, j - 1);
7284 fprintf(fout, " | (%s >> %d)", buf1, l + 1 - j);
7288 " %s = (%s >> %d) | (cond_c << %d)",
7289 buf1, buf1, j, l - j);
7291 fprintf(fout, " | (%s << %d)", buf1, l + 1 - j);
7293 fprintf(fout, ";\n");
7294 fprintf(fout, " cond_c = tmp;");
7298 strcpy(g_comment, (po->op == OP_RCL) ? "rcl" : "rcr");
7299 output_std_flags(fout, po, &pfomask, buf1);
7300 last_arith_dst = &po->operand[0];
7301 delayed_flag_op = NULL;
7305 assert_operand_cnt(2);
7306 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7307 if (IS(opr_name(po, 0), opr_name(po, 1))) {
7308 // special case for XOR
7309 int z = PFOB_O | PFOB_C | PFOB_S | (1 << PFO_L);
7310 for (j = 0; j <= PFO_LE; j++) {
7311 if (pfomask & (1 << j)) {
7312 fprintf(fout, " cond_%s = %d;\n",
7313 parsed_flag_op_names[j], (1 << j) & z ? 0 : 1);
7314 pfomask &= ~(1 << j);
7317 fprintf(fout, " %s = 0;",
7318 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7319 last_arith_dst = &po->operand[0];
7320 delayed_flag_op = NULL;
7326 assert_operand_cnt(2);
7327 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7328 if (pfomask & (1 << PFO_C)) {
7329 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7330 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7331 if (po->operand[0].lmod == OPLM_DWORD) {
7332 fprintf(fout, " tmp64 = (u64)%s + %s;\n", buf1, buf2);
7333 fprintf(fout, " cond_c = tmp64 >> 32;\n");
7334 fprintf(fout, " %s = (u32)tmp64;",
7335 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
7336 strcat(g_comment, " add64");
7339 fprintf(fout, " cond_c = ((u32)%s + %s) >> %d;\n",
7340 buf1, buf2, lmod_bytes(po, po->operand[0].lmod) * 8);
7341 fprintf(fout, " %s += %s;",
7342 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
7345 pfomask &= ~(1 << PFO_C);
7346 output_std_flags(fout, po, &pfomask, buf1);
7347 last_arith_dst = &po->operand[0];
7348 delayed_flag_op = NULL;
7351 if (pfomask & (1 << PFO_LE)) {
7352 out_cmp_for_cc(buf1, sizeof(buf1), po, PFO_LE, 0, 1);
7353 fprintf(fout, " cond_%s = %s;\n",
7354 parsed_flag_op_names[PFO_LE], buf1);
7355 pfomask &= ~(1 << PFO_LE);
7360 assert_operand_cnt(2);
7361 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7362 if (pfomask & ~((1 << PFO_Z) | (1 << PFO_S))) {
7363 for (j = 0; j <= PFO_LE; j++) {
7364 if (!(pfomask & (1 << j)))
7366 if (j == PFO_Z || j == PFO_S)
7369 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7370 fprintf(fout, " cond_%s = %s;\n",
7371 parsed_flag_op_names[j], buf1);
7372 pfomask &= ~(1 << j);
7379 assert_operand_cnt(2);
7380 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7381 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7382 if (po->op == OP_SBB
7383 && IS(po->operand[0].name, po->operand[1].name))
7385 // avoid use of unitialized var
7386 fprintf(fout, " %s = -cond_c;", buf1);
7387 // carry remains what it was
7388 pfomask &= ~(1 << PFO_C);
7391 fprintf(fout, " %s %s= %s + cond_c;", buf1, op_to_c(po),
7392 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]));
7394 output_std_flags(fout, po, &pfomask, buf1);
7395 last_arith_dst = &po->operand[0];
7396 delayed_flag_op = NULL;
7401 // on SKL, if src is 0, dst is left unchanged
7402 assert_operand_cnt(2);
7403 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7404 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[1]);
7405 output_std_flag_z(fout, po, &pfomask, buf2);
7406 if (po->op == OP_BSF)
7407 snprintf(buf3, sizeof(buf3), "__builtin_ffs(%s) - 1", buf2);
7409 snprintf(buf3, sizeof(buf3), "31 - __builtin_clz(%s)", buf2);
7410 fprintf(fout, " if (%s) %s = %s;", buf2, buf1, buf3);
7411 last_arith_dst = &po->operand[0];
7412 delayed_flag_op = NULL;
7413 strcat(g_comment, po->op == OP_BSF ? " bsf" : " bsr");
7417 if (pfomask & ~(PFOB_S | PFOB_S | PFOB_C)) {
7418 for (j = 0; j <= PFO_LE; j++) {
7419 if (!(pfomask & (1 << j)))
7421 if (j == PFO_Z || j == PFO_S || j == PFO_C)
7424 out_cmp_for_cc(buf1, sizeof(buf1), po, j, 0, 0);
7425 fprintf(fout, " cond_%s = %s;\n",
7426 parsed_flag_op_names[j], buf1);
7427 pfomask &= ~(1 << j);
7433 if (pfomask & (1 << PFO_C))
7434 // carry is unaffected by inc/dec.. wtf?
7435 ferr(po, "carry propagation needed\n");
7437 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7438 if (po->operand[0].type == OPT_REG) {
7439 ferr_assert(po, !(po->flags & OPF_LOCK));
7440 strcpy(buf2, po->op == OP_INC ? "++" : "--");
7441 fprintf(fout, " %s%s;", buf1, buf2);
7443 else if (po->flags & OPF_LOCK) {
7444 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0], "", 1);
7445 fprintf(fout, " __sync_fetch_and_%s((%s *)(%s), 1);",
7446 po->op == OP_INC ? "add" : "sub",
7447 lmod_type_u(po, po->operand[0].lmod), buf2);
7448 strcat(g_comment, " lock");
7452 strcpy(buf2, po->op == OP_INC ? "+" : "-");
7453 fprintf(fout, " %s %s= 1;", buf1, buf2);
7455 output_std_flags(fout, po, &pfomask, buf1);
7456 last_arith_dst = &po->operand[0];
7457 delayed_flag_op = NULL;
7461 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7462 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]);
7463 fprintf(fout, " %s = -%s%s;", buf1,
7464 lmod_cast_s(po, po->operand[0].lmod), buf2);
7465 last_arith_dst = &po->operand[0];
7466 delayed_flag_op = NULL;
7467 if (pfomask & PFOB_C) {
7468 fprintf(fout, "\n cond_c = (%s != 0);", buf1);
7471 output_std_flags(fout, po, &pfomask, buf1);
7475 if (po->operand_cnt == 2) {
7476 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7479 if (po->operand_cnt == 3)
7480 ferr(po, "TODO imul3\n");
7483 assert_operand_cnt(1);
7484 switch (po->operand[0].lmod) {
7486 strcpy(buf1, po->op == OP_IMUL ? "(s64)(s32)" : "(u64)");
7487 fprintf(fout, " tmp64 = %seax * %s%s;\n", buf1, buf1,
7488 out_src_opr_u32(buf2, sizeof(buf2), po, &po->operand[0]));
7489 fprintf(fout, " edx = tmp64 >> 32;\n");
7490 fprintf(fout, " eax = tmp64;");
7493 strcpy(buf1, po->op == OP_IMUL ? "(s16)(s8)" : "(u16)(u8)");
7494 fprintf(fout, " LOWORD(eax) = %seax * %s;", buf1,
7495 out_src_opr(buf2, sizeof(buf2), po, &po->operand[0],
7499 ferr(po, "TODO: unhandled mul type\n");
7502 last_arith_dst = NULL;
7503 delayed_flag_op = NULL;
7508 assert_operand_cnt(1);
7509 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7510 strcpy(cast, lmod_cast(po, po->operand[0].lmod,
7511 po->op == OP_IDIV));
7512 switch (po->operand[0].lmod) {
7514 if (po->flags & OPF_32BIT)
7515 snprintf(buf2, sizeof(buf2), "%seax", cast);
7517 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7518 snprintf(buf2, sizeof(buf2), "%stmp64",
7519 (po->op == OP_IDIV) ? "(s64)" : "");
7521 if (po->operand[0].type == OPT_REG
7522 && po->operand[0].reg == xDX)
7524 fprintf(fout, " eax = %s / %s%s;\n", buf2, cast, buf1);
7525 fprintf(fout, " edx = %s %% %s%s;", buf2, cast, buf1);
7528 fprintf(fout, " edx = %s %% %s%s;\n", buf2, cast, buf1);
7529 fprintf(fout, " eax = %s / %s%s;", buf2, cast, buf1);
7533 fprintf(fout, " tmp = (edx << 16) | (eax & 0xffff);\n");
7534 snprintf(buf2, sizeof(buf2), "%stmp",
7535 (po->op == OP_IDIV) ? "(s32)" : "");
7536 if (po->operand[0].type == OPT_REG
7537 && po->operand[0].reg == xDX)
7539 fprintf(fout, " LOWORD(eax) = %s / %s%s;\n",
7541 fprintf(fout, " LOWORD(edx) = %s %% %s%s;",
7545 fprintf(fout, " LOWORD(edx) = %s %% %s%s;\n",
7547 fprintf(fout, " LOWORD(eax) = %s / %s%s;",
7550 strcat(g_comment, " div16");
7553 ferr(po, "unhandled div lmod %d\n", po->operand[0].lmod);
7555 last_arith_dst = NULL;
7556 delayed_flag_op = NULL;
7561 propagate_lmod(po, &po->operand[0], &po->operand[1]);
7563 for (j = 0; j < 8; j++) {
7564 if (pfomask & (1 << j)) {
7565 out_cmp_test(buf1, sizeof(buf1), po, j, 0);
7566 fprintf(fout, " cond_%s = %s;",
7567 parsed_flag_op_names[j], buf1);
7574 last_arith_dst = NULL;
7575 delayed_flag_op = po;
7579 // SETcc - should already be handled
7582 // note: we reuse OP_Jcc for SETcc, only flags differ
7584 fprintf(fout, "\n goto %s;", po->operand[0].name);
7588 fprintf(fout, " if (ecx == 0)\n");
7589 fprintf(fout, " goto %s;", po->operand[0].name);
7590 strcat(g_comment, " jecxz");
7594 fprintf(fout, " if (--ecx != 0)\n");
7595 fprintf(fout, " goto %s;", po->operand[0].name);
7596 strcat(g_comment, " loop");
7600 assert_operand_cnt(1);
7601 last_arith_dst = NULL;
7602 delayed_flag_op = NULL;
7604 if (po->operand[0].type == OPT_REGMEM) {
7605 ret = sscanf(po->operand[0].name, "%[^[][%[^*]*4]",
7608 ferr(po, "parse failure for jmp '%s'\n",
7609 po->operand[0].name);
7610 fprintf(fout, " goto *jt_%s[%s];", buf1, buf2);
7613 else if (po->operand[0].type != OPT_LABEL)
7614 ferr(po, "unhandled jmp type\n");
7616 fprintf(fout, " goto %s;", po->operand[0].name);
7620 assert_operand_cnt(1);
7622 my_assert_not(pp, NULL);
7625 if (po->flags & OPF_CC) {
7626 // we treat conditional branch to another func
7627 // (yes such code exists..) as conditional tailcall
7629 fprintf(fout, " {\n");
7632 if (pp->is_fptr && !pp->is_arg) {
7633 fprintf(fout, "%s%s = %s;\n", buf3, pp->name,
7634 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7637 if (pp->is_fptr && (pp->is_unresolved || pp->is_guessed)) {
7638 fprintf(fout, "%sunresolved_call(\"%s:%d\", %s);\n",
7639 buf3, asmfn, po->asmln, pp->name);
7642 fprintf(fout, "%s", buf3);
7643 if (strstr(pp->ret_type.name, "int64")) {
7644 if (po->flags & OPF_TAIL)
7645 ferr(po, "int64 and tail?\n");
7646 fprintf(fout, "tmp64 = ");
7648 else if (!IS(pp->ret_type.name, "void")) {
7649 if (po->flags & OPF_TAIL) {
7650 if (regmask_ret & mxAX) {
7651 fprintf(fout, "return ");
7652 if (g_func_pp->ret_type.is_ptr != pp->ret_type.is_ptr)
7653 fprintf(fout, "(%s)", g_func_pp->ret_type.name);
7655 else if (regmask_ret & mxST0)
7656 ferr(po, "float tailcall\n");
7658 else if (po->regmask_dst & mxAX) {
7659 fprintf(fout, "eax = ");
7660 if (pp->ret_type.is_ptr)
7661 fprintf(fout, "(u32)");
7663 else if (po->regmask_dst & mxST0) {
7664 ferr_assert(po, po->flags & OPF_FPUSH);
7665 if (need_float_stack)
7666 fprintf(fout, "f_st[--f_stp & 7] = ");
7668 fprintf(fout, "f_st0 = ");
7672 if (pp->name[0] == 0)
7673 ferr(po, "missing pp->name\n");
7674 fprintf(fout, "%s%s(", pp->name,
7675 pp->has_structarg ? "_sa" : "");
7677 if (po->flags & OPF_ATAIL) {
7679 g_func_pp->is_stdcall && g_func_pp->argc_stack > 0;
7680 check_compat |= pp->argc_stack > 0;
7682 && (pp->argc_stack != g_func_pp->argc_stack
7683 || pp->is_stdcall != g_func_pp->is_stdcall))
7684 ferr(po, "incompatible arg-reuse tailcall\n");
7685 if (g_func_pp->has_retreg)
7686 ferr(po, "TODO: retreg+tailcall\n");
7688 for (arg = j = 0; arg < pp->argc; arg++) {
7690 fprintf(fout, ", ");
7693 if (pp->arg[arg].type.is_ptr)
7694 snprintf(cast, sizeof(cast), "(%s)",
7695 pp->arg[arg].type.name);
7697 if (pp->arg[arg].reg != NULL) {
7698 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7702 for (; j < g_func_pp->argc; j++)
7703 if (g_func_pp->arg[j].reg == NULL)
7705 fprintf(fout, "%sa%d", cast, j + 1);
7710 for (arg = 0; arg < pp->argc; arg++) {
7712 fprintf(fout, ", ");
7715 if (pp->arg[arg].type.is_ptr)
7716 snprintf(cast, sizeof(cast), "(%s)",
7717 pp->arg[arg].type.name);
7719 if (pp->arg[arg].reg != NULL) {
7720 if (pp->arg[arg].type.is_retreg)
7721 fprintf(fout, "&%s", pp->arg[arg].reg);
7722 else if (IS(pp->arg[arg].reg, "ebp")
7723 && g_bp_frame && !(po->flags & OPF_EBP_S))
7725 // rare special case
7726 fprintf(fout, "%s(u32)&sf.b[sizeof(sf)]", cast);
7727 strcat(g_comment, " bp_ref");
7730 fprintf(fout, "%s%s", cast, pp->arg[arg].reg);
7735 tmp_op = pp->arg[arg].datap;
7737 ferr(po, "parsed_op missing for arg%d\n", arg);
7739 if (tmp_op->flags & OPF_VAPUSH) {
7740 fprintf(fout, "ap");
7742 else if (tmp_op->op == OP_FST) {
7743 fprintf(fout, "fs_%d", tmp_op->p_argnum);
7744 if (tmp_op->operand[0].lmod == OPLM_QWORD)
7747 else if (pp->arg[arg].type.is_64bit) {
7748 ferr_assert(po, tmp_op->p_argpass == 0);
7749 ferr_assert(po, !pp->arg[arg].is_saved);
7750 ferr_assert(po, !pp->arg[arg].type.is_float);
7751 ferr_assert(po, cast[0] == 0);
7752 out_src_opr(buf1, sizeof(buf1),
7753 tmp_op, &tmp_op->operand[0], cast, 0);
7754 tmp_op = pp->arg[++arg].datap;
7755 ferr_assert(po, tmp_op != NULL);
7756 out_src_opr(buf2, sizeof(buf2),
7757 tmp_op, &tmp_op->operand[0], cast, 0);
7758 fprintf(fout, "((u64)(%s) << 32) | (%s)",
7761 else if (tmp_op->p_argpass != 0) {
7762 ferr_assert(po, !pp->arg[arg].type.is_float);
7763 fprintf(fout, "a%d", tmp_op->p_argpass);
7765 else if (pp->arg[arg].is_saved) {
7766 ferr_assert(po, tmp_op->p_argnum > 0);
7767 ferr_assert(po, !pp->arg[arg].type.is_float);
7768 fprintf(fout, "%s%s", cast,
7769 saved_arg_name(buf1, sizeof(buf1),
7770 tmp_op->p_arggrp, tmp_op->p_argnum));
7772 else if (pp->arg[arg].type.is_float) {
7773 ferr_assert(po, !pp->arg[arg].type.is_64bit);
7775 out_src_opr_float(buf1, sizeof(buf1),
7776 tmp_op, &tmp_op->operand[0], need_float_stack));
7780 out_src_opr(buf1, sizeof(buf1),
7781 tmp_op, &tmp_op->operand[0], cast, 0));
7785 fprintf(fout, ");");
7787 if (strstr(pp->ret_type.name, "int64")) {
7788 fprintf(fout, "\n");
7789 fprintf(fout, "%sedx = tmp64 >> 32;\n", buf3);
7790 fprintf(fout, "%seax = tmp64;", buf3);
7793 if (pp->is_unresolved) {
7794 snprintf(buf2, sizeof(buf2), " unresolved %dreg",
7796 strcat(g_comment, buf2);
7799 if (po->flags & OPF_TAIL) {
7801 if (i == opcnt - 1 || pp->is_noreturn)
7803 else if (IS(pp->ret_type.name, "void"))
7805 else if (!(regmask_ret & (1 << xAX)))
7807 // else already handled as 'return f()'
7810 fprintf(fout, "\n%sreturn;", buf3);
7811 strcat(g_comment, " ^ tailcall");
7814 strcat(g_comment, " tailcall");
7816 if ((regmask_ret & (1 << xAX))
7817 && IS(pp->ret_type.name, "void") && !pp->is_noreturn)
7819 ferr(po, "int func -> void func tailcall?\n");
7822 if (pp->is_noreturn)
7823 strcat(g_comment, " noreturn");
7824 if ((po->flags & OPF_ATAIL) && pp->argc_stack > 0)
7825 strcat(g_comment, " argframe");
7826 if (po->flags & OPF_CC)
7827 strcat(g_comment, " cond");
7829 if (po->flags & OPF_CC)
7830 fprintf(fout, "\n }");
7832 delayed_flag_op = NULL;
7833 last_arith_dst = NULL;
7837 if (g_func_pp->is_vararg)
7838 fprintf(fout, " va_end(ap);\n");
7839 if (g_func_pp->has_retreg) {
7840 for (arg = 0; arg < g_func_pp->argc; arg++)
7841 if (g_func_pp->arg[arg].type.is_retreg)
7842 fprintf(fout, " *r_%s = %s;\n",
7843 g_func_pp->arg[arg].reg, g_func_pp->arg[arg].reg);
7846 if (regmask_ret & mxST0) {
7847 fprintf(fout, " return %s;", float_st0);
7849 else if (!(regmask_ret & mxAX)) {
7850 if (i != opcnt - 1 || label_pending)
7851 fprintf(fout, " return;");
7853 else if (g_func_pp->ret_type.is_ptr) {
7854 fprintf(fout, " return (%s)eax;",
7855 g_func_pp->ret_type.name);
7857 else if (IS(g_func_pp->ret_type.name, "__int64"))
7858 fprintf(fout, " return ((u64)edx << 32) | eax;");
7860 fprintf(fout, " return eax;");
7862 last_arith_dst = NULL;
7863 delayed_flag_op = NULL;
7867 out_src_opr_u32(buf1, sizeof(buf1), po, &po->operand[0]);
7868 if (po->p_argnum != 0) {
7869 // special case - saved func arg
7870 fprintf(fout, " %s = %s;",
7871 saved_arg_name(buf2, sizeof(buf2),
7872 po->p_arggrp, po->p_argnum), buf1);
7875 else if (po->flags & OPF_RSAVE) {
7876 fprintf(fout, " s_%s = %s;", buf1, buf1);
7879 else if (po->flags & OPF_PPUSH) {
7881 ferr_assert(po, tmp_op != NULL);
7882 out_dst_opr(buf2, sizeof(buf2), po, &tmp_op->operand[0]);
7883 fprintf(fout, " pp_%s = %s;", buf2, buf1);
7886 else if (g_func_pp->is_userstack) {
7887 fprintf(fout, " *(--esp) = %s;", buf1);
7890 if (!(g_ida_func_attr & IDAFA_NORETURN))
7891 ferr(po, "stray push encountered\n");
7896 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]);
7897 if (po->flags & OPF_RSAVE) {
7898 fprintf(fout, " %s = s_%s;", buf1, buf1);
7901 else if (po->flags & OPF_PPUSH) {
7902 // push/pop graph / non-const
7903 ferr_assert(po, po->datap == NULL);
7904 fprintf(fout, " %s = pp_%s;", buf1, buf1);
7907 else if (po->datap != NULL) {
7910 fprintf(fout, " %s = %s;", buf1,
7911 out_src_opr(buf2, sizeof(buf2),
7912 tmp_op, &tmp_op->operand[0],
7913 default_cast_to(buf3, sizeof(buf3), &po->operand[0]), 0));
7916 else if (g_func_pp->is_userstack) {
7917 fprintf(fout, " %s = *esp++;", buf1);
7921 ferr(po, "stray pop encountered\n");
7931 fprintf(fout, " tmp64 = ((u64)edx << 32) | eax;\n");
7932 fprintf(fout, " tmp64 = (s64)tmp64 %s LOBYTE(ecx);\n",
7933 po->op == OPP_ALLSHL ? "<<" : ">>");
7934 fprintf(fout, " edx = tmp64 >> 32; eax = tmp64;");
7935 strcat(g_comment, po->op == OPP_ALLSHL
7936 ? " allshl" : " allshr");
7941 if (need_float_stack) {
7942 out_src_opr_float(buf1, sizeof(buf1),
7943 po, &po->operand[0], 1);
7944 if (po->regmask_src & mxSTa) {
7945 fprintf(fout, " f_st[(f_stp - 1) & 7] = %s; f_stp--;",
7949 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf1);
7952 if (po->flags & OPF_FSHIFT)
7953 fprintf(fout, " f_st1 = f_st0;");
7954 if (po->operand[0].type == OPT_REG
7955 && po->operand[0].reg == xST0)
7957 strcat(g_comment, " fld st");
7960 fprintf(fout, " f_st0 = %s;",
7961 out_src_opr_float(buf1, sizeof(buf1),
7962 po, &po->operand[0], 0));
7964 strcat(g_comment, " fld");
7968 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
7969 lmod_cast(po, po->operand[0].lmod, 1), 0);
7970 snprintf(buf2, sizeof(buf2), "(%s)%s", float_type, buf1);
7971 if (need_float_stack) {
7972 fprintf(fout, " f_st[--f_stp & 7] = %s;", buf2);
7975 if (po->flags & OPF_FSHIFT)
7976 fprintf(fout, " f_st1 = f_st0;");
7977 fprintf(fout, " f_st0 = %s;", buf2);
7979 strcat(g_comment, " fild");
7983 if (need_float_stack)
7984 fprintf(fout, " f_st[--f_stp & 7] = ");
7986 if (po->flags & OPF_FSHIFT)
7987 fprintf(fout, " f_st1 = f_st0;");
7988 fprintf(fout, " f_st0 = ");
7990 switch (po->operand[0].val) {
7991 case X87_CONST_1: fprintf(fout, "1.0;"); break;
7992 case X87_CONST_L2T: fprintf(fout, "3.321928094887362;"); break;
7993 case X87_CONST_L2E: fprintf(fout, "M_LOG2E;"); break;
7994 case X87_CONST_PI: fprintf(fout, "M_PI;"); break;
7995 case X87_CONST_LG2: fprintf(fout, "0.301029995663981;"); break;
7996 case X87_CONST_LN2: fprintf(fout, "M_LN2;"); break;
7997 case X87_CONST_Z: fprintf(fout, "0.0;"); break;
7998 default: ferr_assert(po, 0); break;
8003 if (po->flags & OPF_FARG) {
8004 // store to stack as func arg
8005 snprintf(buf1, sizeof(buf1), "fs_%d", po->p_argnum);
8009 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8011 dead_dst = po->operand[0].type == OPT_REG
8012 && po->operand[0].reg == xST0;
8015 fprintf(fout, " %s = %s;", buf1, float_st0);
8016 if (po->flags & OPF_FSHIFT) {
8017 if (need_float_stack)
8018 fprintf(fout, " f_stp++;");
8020 fprintf(fout, " f_st0 = f_st1;");
8022 if (dead_dst && !(po->flags & OPF_FSHIFT))
8025 strcat(g_comment, " fst");
8029 fprintf(fout, " %s = %s%s;",
8030 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]),
8031 lmod_cast(po, po->operand[0].lmod, 1), float_st0);
8032 if (po->flags & OPF_FSHIFT) {
8033 if (need_float_stack)
8034 fprintf(fout, " f_stp++;");
8036 fprintf(fout, " f_st0 = f_st1;");
8038 strcat(g_comment, " fist");
8045 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8047 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8049 dead_dst = (po->flags & OPF_FPOP)
8050 && po->operand[0].type == OPT_REG
8051 && po->operand[0].reg == xST0;
8053 case OP_FADD: j = '+'; break;
8054 case OP_FDIV: j = '/'; break;
8055 case OP_FMUL: j = '*'; break;
8056 case OP_FSUB: j = '-'; break;
8057 default: j = 'x'; break;
8059 if (need_float_stack) {
8061 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
8062 if (po->flags & OPF_FSHIFT)
8063 fprintf(fout, " f_stp++;");
8066 if (po->flags & OPF_FSHIFT) {
8067 // note: assumes only 2 regs handled
8069 fprintf(fout, " f_st0 = f_st1 %c f_st0;", j);
8071 fprintf(fout, " f_st0 = f_st1;");
8074 fprintf(fout, " %s %c= %s;", buf1, j, buf2);
8076 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
8081 out_dst_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8083 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8085 out_src_opr_float(buf3, sizeof(buf3), po, &po->operand[0],
8087 dead_dst = (po->flags & OPF_FPOP)
8088 && po->operand[0].type == OPT_REG
8089 && po->operand[0].reg == xST0;
8090 j = po->op == OP_FDIVR ? '/' : '-';
8091 if (need_float_stack) {
8093 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
8094 if (po->flags & OPF_FSHIFT)
8095 fprintf(fout, " f_stp++;");
8098 if (po->flags & OPF_FSHIFT) {
8100 fprintf(fout, " f_st0 = f_st0 %c f_st1;", j);
8102 fprintf(fout, " f_st0 = f_st1;");
8105 fprintf(fout, " %s = %s %c %s;", buf1, buf2, j, buf3);
8107 no_output = (dead_dst && !(po->flags & OPF_FSHIFT));
8115 case OP_FIADD: j = '+'; break;
8116 case OP_FIDIV: j = '/'; break;
8117 case OP_FIMUL: j = '*'; break;
8118 case OP_FISUB: j = '-'; break;
8119 default: j = 'x'; break;
8121 fprintf(fout, " %s %c= (%s)%s;", float_st0,
8123 out_src_opr(buf1, sizeof(buf1), po, &po->operand[0],
8124 lmod_cast(po, po->operand[0].lmod, 1), 0));
8129 fprintf(fout, " %s = %s %c %s;", float_st0,
8130 out_src_opr_float(buf2, sizeof(buf2), po, &po->operand[1],
8132 po->op == OP_FIDIVR ? '/' : '-', float_st0);
8137 ferr_assert(po, po->datap != NULL);
8138 mask = (long)po->datap & 0xffff;
8139 z_check = ((long)po->datap >> 16) & 1;
8140 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8142 if (mask == 0x0100 || mask == 0x0500) { // C0 -> <
8143 fprintf(fout, " f_sw = %s < %s ? 0x0100 : 0;",
8146 else if (mask == 0x4000 || mask == 0x4400) { // C3 -> =
8147 fprintf(fout, " f_sw = %s == %s ? 0x4000 : 0;",
8150 else if (mask == 0x4100) { // C3, C0
8152 fprintf(fout, " f_sw = %s <= %s ? 0x4100 : 0;",
8154 strcat(g_comment, " z_chk_det");
8157 fprintf(fout, " f_sw = %s == %s ? 0x4000 : "
8158 "(%s < %s ? 0x0100 : 0);",
8159 float_st0, buf1, float_st0, buf1);
8163 ferr(po, "unhandled sw mask: %x\n", mask);
8164 if (po->flags & OPF_FSHIFT) {
8165 if (need_float_stack) {
8166 if (po->flags & OPF_FPOPP)
8167 fprintf(fout, " f_stp += 2;");
8169 fprintf(fout, " f_stp++;");
8172 ferr_assert(po, !(po->flags & OPF_FPOPP));
8173 fprintf(fout, " f_st0 = f_st1;");
8180 fprintf(fout, " %s = f_sw;",
8181 out_dst_opr(buf1, sizeof(buf1), po, &po->operand[0]));
8185 fprintf(fout, " %s = -%s;", float_st0, float_st0);
8189 fprintf(fout, " %s = cos%s(%s);", float_st0,
8190 need_double ? "" : "f", float_st0);
8194 if (need_float_stack) {
8195 fprintf(fout, " %s = atan%s(%s / %s);", float_st1,
8196 need_double ? "" : "f", float_st1, float_st0);
8197 fprintf(fout, " f_stp++;");
8200 fprintf(fout, " f_st0 = atan%s(f_st1 / f_st0);",
8201 need_double ? "" : "f");
8206 if (need_float_stack) {
8207 fprintf(fout, " %s = %s * log2%s(%s);", float_st1,
8208 float_st1, need_double ? "" : "f", float_st0);
8209 fprintf(fout, " f_stp++;");
8212 fprintf(fout, " f_st0 = f_st1 * log2%s(f_st0);",
8213 need_double ? "" : "f");
8215 strcat(g_comment, " fyl2x");
8219 fprintf(fout, " %s = sin%s(%s);", float_st0,
8220 need_double ? "" : "f", float_st0);
8224 fprintf(fout, " %s = sqrt%s(%s);", float_st0,
8225 need_double ? "" : "f", float_st0);
8229 dead_dst = po->operand[0].type == OPT_REG
8230 && po->operand[0].reg == xST0;
8232 out_src_opr_float(buf1, sizeof(buf1), po, &po->operand[0],
8234 fprintf(fout, " { %s t = %s; %s = %s; %s = t; }", float_type,
8235 float_st0, float_st0, buf1, buf1);
8236 strcat(g_comment, " fxch");
8243 ferr_assert(po, po->flags & OPF_32BIT);
8244 fprintf(fout, " eax = (s32)%s;", float_st0);
8245 if (po->flags & OPF_FSHIFT) {
8246 if (need_float_stack)
8247 fprintf(fout, " f_stp++;");
8249 fprintf(fout, " f_st0 = f_st1;");
8251 strcat(g_comment, " ftol");
8255 if (need_float_stack) {
8256 fprintf(fout, " %s = pow%s(%s, %s);", float_st1,
8257 need_double ? "" : "f", float_st1, float_st0);
8258 fprintf(fout, " f_stp++;");
8261 fprintf(fout, " f_st0 = pow%s(f_st1, f_st0);",
8262 need_double ? "" : "f");
8264 strcat(g_comment, " CIpow");
8268 fprintf(fout, " do_skip_code_abort();");
8273 fprintf(fout, " do_emms();");
8278 ferr(po, "unhandled op type %d, flags %x\n",
8283 if (g_comment[0] != 0) {
8284 char *p = g_comment;
8285 while (my_isblank(*p))
8287 fprintf(fout, " // %s", p);
8292 fprintf(fout, "\n");
8294 // some sanity checking
8295 if (po->flags & OPF_REP) {
8296 if (po->op != OP_STOS && po->op != OP_MOVS
8297 && po->op != OP_CMPS && po->op != OP_SCAS)
8298 ferr(po, "unexpected rep\n");
8299 if (!(po->flags & (OPF_REPZ|OPF_REPNZ))
8300 && (po->op == OP_CMPS || po->op == OP_SCAS))
8301 ferr(po, "cmps/scas with plain rep\n");
8303 if ((po->flags & (OPF_REPZ|OPF_REPNZ))
8304 && po->op != OP_CMPS && po->op != OP_SCAS)
8305 ferr(po, "unexpected repz/repnz\n");
8308 ferr(po, "missed flag calc, pfomask=%x\n", pfomask);
8310 if ((po->flags & OPF_LOCK) && !lock_handled)
8311 ferr(po, "unhandled lock\n");
8313 // see is delayed flag stuff is still valid
8314 if (delayed_flag_op != NULL && delayed_flag_op != po) {
8315 if (is_any_opr_modified(delayed_flag_op, po, 0))
8316 delayed_flag_op = NULL;
8319 if (last_arith_dst != NULL && last_arith_dst != &po->operand[0]) {
8320 if (is_opr_modified(last_arith_dst, po))
8321 last_arith_dst = NULL;
8328 if (g_stack_fsz && !g_stack_frame_used)
8329 fprintf(fout, " (void)sf;\n");
8331 fprintf(fout, "}\n\n");
8333 gen_x_cleanup(opcnt);
8336 static void gen_x_cleanup(int opcnt)
8340 for (i = 0; i < opcnt; i++) {
8341 struct label_ref *lr, *lr_del;
8343 lr = g_label_refs[i].next;
8344 while (lr != NULL) {
8349 g_label_refs[i].i = -1;
8350 g_label_refs[i].next = NULL;
8352 if (ops[i].op == OP_CALL) {
8354 proto_release(ops[i].pp);
8360 struct func_proto_dep;
8362 struct func_prototype {
8366 int regmask_dep; // likely register args
8367 int regmask_use; // used registers
8368 int has_ret:3; // -1, 0, 1: unresolved, no, yes
8369 unsigned int has_ret64:1;
8370 unsigned int dep_resolved:1;
8371 unsigned int is_stdcall:1;
8372 unsigned int eax_pass:1; // returns without touching eax
8373 unsigned int ptr_taken:1; // pointer taken of this func
8374 struct func_proto_dep *dep_func;
8376 const struct parsed_proto *pp; // seed pp, if any
8379 struct func_proto_dep {
8381 struct func_prototype *proto;
8382 int regmask_live; // .. at the time of call
8383 unsigned int ret_dep:1; // return from this is caller's return
8384 unsigned int has_ret:1; // found from eax use after return
8385 unsigned int has_ret64:1;
8386 unsigned int ptr_taken:1; // pointer taken, not a call
8389 static struct func_prototype *hg_fp;
8390 static int hg_fp_cnt;
8392 static struct scanned_var {
8394 enum opr_lenmod lmod;
8395 unsigned int is_seeded:1;
8396 unsigned int is_c_str:1;
8397 const struct parsed_proto *pp; // seed pp, if any
8399 static int hg_var_cnt;
8401 static char **hg_refs;
8402 static int hg_ref_cnt;
8404 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8407 static struct func_prototype *hg_fp_add(const char *funcn)
8409 struct func_prototype *fp;
8411 if ((hg_fp_cnt & 0xff) == 0) {
8412 hg_fp = realloc(hg_fp, sizeof(hg_fp[0]) * (hg_fp_cnt + 0x100));
8413 my_assert_not(hg_fp, NULL);
8414 memset(hg_fp + hg_fp_cnt, 0, sizeof(hg_fp[0]) * 0x100);
8417 fp = &hg_fp[hg_fp_cnt];
8418 snprintf(fp->name, sizeof(fp->name), "%s", funcn);
8420 fp->argc_stack = -1;
8426 static struct func_proto_dep *hg_fp_find_dep(struct func_prototype *fp,
8431 for (i = 0; i < fp->dep_func_cnt; i++)
8432 if (IS(fp->dep_func[i].name, name))
8433 return &fp->dep_func[i];
8438 static void hg_fp_add_dep(struct func_prototype *fp, const char *name,
8439 unsigned int ptr_taken)
8441 struct func_proto_dep * dep;
8444 dep = hg_fp_find_dep(fp, name);
8445 if (dep != NULL && dep->ptr_taken == ptr_taken)
8448 if ((fp->dep_func_cnt & 0xff) == 0) {
8449 fp->dep_func = realloc(fp->dep_func,
8450 sizeof(fp->dep_func[0]) * (fp->dep_func_cnt + 0x100));
8451 my_assert_not(fp->dep_func, NULL);
8452 memset(&fp->dep_func[fp->dep_func_cnt], 0,
8453 sizeof(fp->dep_func[0]) * 0x100);
8455 fp->dep_func[fp->dep_func_cnt].name = strdup(name);
8456 fp->dep_func[fp->dep_func_cnt].ptr_taken = ptr_taken;
8460 static int hg_fp_cmp_name(const void *p1_, const void *p2_)
8462 const struct func_prototype *p1 = p1_, *p2 = p2_;
8463 return strcmp(p1->name, p2->name);
8467 static int hg_fp_cmp_id(const void *p1_, const void *p2_)
8469 const struct func_prototype *p1 = p1_, *p2 = p2_;
8470 return p1->id - p2->id;
8474 static void hg_ref_add(const char *name)
8476 if ((hg_ref_cnt & 0xff) == 0) {
8477 hg_refs = realloc(hg_refs, sizeof(hg_refs[0]) * (hg_ref_cnt + 0x100));
8478 my_assert_not(hg_refs, NULL);
8479 memset(hg_refs + hg_ref_cnt, 0, sizeof(hg_refs[0]) * 0x100);
8482 hg_refs[hg_ref_cnt] = strdup(name);
8483 my_assert_not(hg_refs[hg_ref_cnt], NULL);
8487 // recursive register dep pass
8488 // - track saved regs (part 2)
8489 // - try to figure out arg-regs
8490 // - calculate reg deps
8491 static void gen_hdr_dep_pass(int i, int opcnt, unsigned char *cbits,
8492 struct func_prototype *fp, int regmask_save, int regmask_dst,
8493 int *regmask_dep, int *regmask_use, int *has_ret)
8495 struct func_proto_dep *dep;
8496 struct parsed_op *po;
8497 int from_caller = 0;
8502 for (; i < opcnt; i++)
8504 if (cbits[i >> 3] & (1 << (i & 7)))
8506 cbits[i >> 3] |= (1 << (i & 7));
8510 if ((po->flags & OPF_JMP) && po->op != OP_CALL) {
8511 if (po->flags & OPF_RMD)
8514 if (po->btj != NULL) {
8516 for (j = 0; j < po->btj->count; j++) {
8517 check_i(po, po->btj->d[j].bt_i);
8518 gen_hdr_dep_pass(po->btj->d[j].bt_i, opcnt, cbits, fp,
8519 regmask_save, regmask_dst, regmask_dep, regmask_use,
8525 check_i(po, po->bt_i);
8526 if (po->flags & OPF_CJMP) {
8527 gen_hdr_dep_pass(po->bt_i, opcnt, cbits, fp,
8528 regmask_save, regmask_dst, regmask_dep, regmask_use,
8537 if (po->flags & OPF_FARG)
8538 /* (just calculate register deps) */;
8539 else if (po->op == OP_PUSH && po->operand[0].type == OPT_REG)
8541 reg = po->operand[0].reg;
8542 ferr_assert(po, reg >= 0);
8544 if (po->flags & OPF_RSAVE) {
8545 regmask_save |= 1 << reg;
8548 if (po->flags & OPF_DONE)
8551 ret = scan_for_pop(i + 1, opcnt, i + opcnt * 2,
8554 regmask_save |= 1 << reg;
8555 po->flags |= OPF_RMD;
8556 scan_for_pop(i + 1, opcnt, i + opcnt * 3,
8557 reg, 0, 0, 0, OPF_RMD);
8561 else if (po->flags & OPF_RMD)
8563 else if (po->op == OP_CALL) {
8564 po->regmask_dst |= 1 << xAX;
8566 dep = hg_fp_find_dep(fp, po->operand[0].name);
8568 dep->regmask_live = regmask_save | regmask_dst;
8569 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8570 dep->regmask_live |= 1 << xBP;
8573 else if (po->op == OP_RET) {
8574 if (po->operand_cnt > 0) {
8576 if (fp->argc_stack >= 0
8577 && fp->argc_stack != po->operand[0].val / 4)
8578 ferr(po, "ret mismatch? (%d)\n", fp->argc_stack * 4);
8579 fp->argc_stack = po->operand[0].val / 4;
8583 if (!fp->eax_pass && (po->flags & OPF_TAIL)) {
8584 if (po->op == OP_CALL) {
8589 struct parsed_opr opr = OPR_INIT(OPT_REG, OPLM_DWORD, xAX);
8592 ret = resolve_origin(i, &opr, i + opcnt * 4, &j, &from_caller);
8595 if (ret != 1 && from_caller) {
8596 // unresolved eax - probably void func
8601 if (j >= 0 && ops[j].op == OP_CALL) {
8602 if (ops[j].pp != NULL && !ops[j].pp->is_unresolved) {
8603 int call_has_ret = !IS(ops[j].pp->ret_type.name, "void");
8604 if (ops[j].pp->is_noreturn) {
8605 // could be some fail path
8607 *has_ret = call_has_ret;
8610 *has_ret = call_has_ret;
8613 dep = hg_fp_find_dep(fp, ops[j].operand[0].name);
8625 l = regmask_save | regmask_dst;
8626 if (g_bp_frame && !(po->flags & OPF_EBP_S))
8629 l = po->regmask_src & ~l;
8632 fnote(po, "dep |= %04x, dst %04x, save %04x (f %x)\n",
8633 l, regmask_dst, regmask_save, po->flags);
8636 *regmask_use |= (po->regmask_src | po->regmask_dst)
8638 regmask_dst |= po->regmask_dst;
8640 if (po->flags & OPF_TAIL) {
8641 if (!(po->flags & OPF_CC)) // not cond. tailcall
8647 static void gen_hdr(const char *funcn, int opcnt)
8649 unsigned char cbits[MAX_OPS / 8];
8650 const struct parsed_proto *pp_c;
8651 struct parsed_proto *pp;
8652 struct func_prototype *fp;
8653 struct func_proto_dep *dep;
8654 struct parsed_op *po;
8655 const char *tmpname;
8656 int regmask_dummy = 0;
8659 int max_bp_offset = 0;
8664 pp_c = proto_parse(g_fhdr, funcn, 1);
8666 // already in seed, will add to hg_fp later
8669 fp = hg_fp_add(funcn);
8671 g_bp_frame = g_sp_frame = g_stack_fsz = 0;
8672 g_stack_frame_used = 0;
8676 // - resolve all branches
8677 // - parse calls with labels
8678 resolve_branches_parse_calls(opcnt);
8681 // - handle ebp/esp frame, remove ops related to it
8682 scan_prologue_epilogue(opcnt, NULL);
8685 // - remove dead labels
8687 // - collect function ptr refs
8688 for (i = 0; i < opcnt; i++)
8690 if (g_labels[i] != NULL && g_label_refs[i].i == -1) {
8696 if (po->flags & (OPF_RMD|OPF_DONE))
8699 if (po->op == OP_CALL) {
8700 if (po->operand[0].type == OPT_LABEL)
8701 hg_fp_add_dep(fp, opr_name(po, 0), 0);
8702 else if (po->pp != NULL)
8703 hg_fp_add_dep(fp, po->pp->name, 0);
8705 else if (po->op == OP_MOV && po->operand[1].type == OPT_OFFSET) {
8706 tmpname = opr_name(po, 1);
8707 if (IS_START(tmpname, "p_") || IS_START(tmpname, "sub_"))
8708 hg_fp_add_dep(fp, tmpname, 1);
8710 else if (po->op == OP_PUSH && po->operand[0].type == OPT_OFFSET) {
8711 tmpname = opr_name(po, 0);
8712 if (IS_START(tmpname, "p_") || IS_START(tmpname, "sub_"))
8713 hg_fp_add_dep(fp, tmpname, 1);
8718 // - handle push <const>/pop pairs
8719 for (i = 0; i < opcnt; i++)
8722 if (po->flags & (OPF_RMD|OPF_DONE))
8725 if (po->op == OP_PUSH && po->operand[0].type == OPT_CONST)
8726 scan_for_pop_const(i, opcnt, i + opcnt * 13);
8730 // - process trivial calls
8731 for (i = 0; i < opcnt; i++)
8734 if (po->flags & (OPF_RMD|OPF_DONE))
8737 if (po->op == OP_CALL)
8739 pp = process_call_early(i, opcnt, &j);
8741 if (!(po->flags & OPF_ATAIL))
8742 // since we know the args, try to collect them
8743 if (collect_call_args_early(i, pp, NULL, NULL) != 0)
8749 // commit esp adjust
8750 if (ops[j].op != OP_POP)
8751 patch_esp_adjust(&ops[j], pp->argc_stack * 4);
8753 for (l = 0; l < pp->argc_stack; l++)
8754 ops[j + l].flags |= OPF_DONE | OPF_RMD | OPF_NOREGS;
8758 po->flags |= OPF_DONE;
8764 // - track saved regs (simple)
8766 for (i = 0; i < opcnt; i++)
8769 if (po->flags & (OPF_RMD|OPF_DONE))
8772 if (po->op == OP_PUSH && po->operand[0].type == OPT_REG
8773 && po->operand[0].reg != xCX)
8775 ret = scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, 0);
8777 // regmask_save |= 1 << po->operand[0].reg; // do it later
8778 po->flags |= OPF_RSAVE | OPF_RMD | OPF_DONE;
8779 scan_for_pop_ret(i + 1, opcnt, po->operand[0].reg, OPF_RMD);
8782 else if (po->op == OP_CALL)
8784 pp = process_call(i, opcnt);
8786 if (!pp->is_unresolved && !(po->flags & OPF_ATAIL)) {
8787 // since we know the args, collect them
8788 ret = collect_call_args(po, i, pp, ®mask_dummy,
8791 if (!(po->flags & OPF_TAIL)
8792 && po->operand[0].type == OPT_LABEL)
8794 dep = hg_fp_find_dep(fp, opr_name(po, 0));
8795 ferr_assert(po, dep != NULL);
8796 // treat al write as overwrite to avoid many false positives
8797 find_next_read_reg(i + 1, opcnt, xAX, OPLM_BYTE,
8798 i + opcnt * 25, &j);
8801 find_next_read_reg(i + 1, opcnt, xDX, OPLM_BYTE,
8802 i + opcnt * 26, &j);
8803 if (j != -1 && !IS_OP_INDIRECT_CALL(&ops[j]))
8810 memset(cbits, 0, (opcnt + 7) / 8);
8811 regmask_dep = regmask_use = 0;
8814 gen_hdr_dep_pass(0, opcnt, cbits, fp, 0, 0,
8815 ®mask_dep, ®mask_use, &has_ret);
8817 // find unreachable code - must be fixed in IDA
8818 for (i = 0; i < opcnt; i++)
8820 if (cbits[i >> 3] & (1 << (i & 7)))
8823 if (g_labels[i] == NULL && i > 0 && ops[i - 1].op == OP_CALL
8824 && ops[i - 1].pp != NULL && ops[i - 1].pp->is_osinc)
8826 // the compiler sometimes still generates code after
8827 // noreturn OS functions
8830 if (!(ops[i].flags & OPF_RMD)
8831 && ops[i].op != OP_NOP && ops[i].op != OPP_ABORT)
8833 ferr(&ops[i], "unreachable code\n");
8837 for (i = 0; i < g_eqcnt; i++) {
8838 if (g_eqs[i].offset > max_bp_offset && g_eqs[i].offset < 4*32)
8839 max_bp_offset = g_eqs[i].offset;
8842 if (fp->argc_stack < 0) {
8843 max_bp_offset = (max_bp_offset + 3) & ~3;
8844 fp->argc_stack = max_bp_offset / 4;
8845 if ((g_ida_func_attr & IDAFA_BP_FRAME) && fp->argc_stack > 0)
8849 fp->regmask_dep = regmask_dep & ~((1 << xSP) | mxSTa);
8850 fp->regmask_use = regmask_use;
8851 fp->has_ret = has_ret;
8853 printf("// has_ret %d, regmask_dep %x\n",
8854 fp->has_ret, fp->regmask_dep);
8855 output_hdr_fp(stdout, fp, 1);
8856 if (IS(funcn, "sub_10007F72")) exit(1);
8859 gen_x_cleanup(opcnt);
8862 static void hg_fp_resolve_deps(struct func_prototype *fp)
8864 struct func_prototype fp_s;
8865 struct func_proto_dep *dep;
8869 // this thing is recursive, so mark first..
8870 fp->dep_resolved = 1;
8872 for (i = 0; i < fp->dep_func_cnt; i++) {
8873 dep = &fp->dep_func[i];
8875 strcpy(fp_s.name, dep->name);
8876 dep->proto = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8877 sizeof(hg_fp[0]), hg_fp_cmp_name);
8878 if (dep->proto != NULL) {
8879 if (dep->ptr_taken) {
8880 dep->proto->ptr_taken = 1;
8884 if (!dep->proto->dep_resolved)
8885 hg_fp_resolve_deps(dep->proto);
8887 regmask_dep = ~dep->regmask_live
8888 & dep->proto->regmask_dep;
8889 fp->regmask_dep |= regmask_dep;
8890 // printf("dep %s %s |= %x\n", fp->name,
8891 // fp->dep_func[i].name, regmask_dep);
8893 if (dep->has_ret && (dep->proto->regmask_use & mxAX))
8894 dep->proto->has_ret = 1;
8895 if (dep->has_ret64 && (dep->proto->regmask_use & mxDX))
8896 dep->proto->has_ret64 = 1;
8897 if (fp->has_ret == -1 && dep->ret_dep)
8898 fp->has_ret = dep->proto->has_ret;
8903 // make all thiscall/edx arg functions referenced from .data fastcall
8904 static void do_func_refs_from_data(void)
8906 struct func_prototype *fp, fp_s;
8909 for (i = 0; i < hg_ref_cnt; i++) {
8910 strcpy(fp_s.name, hg_refs[i]);
8911 fp = bsearch(&fp_s, hg_fp, hg_fp_cnt,
8912 sizeof(hg_fp[0]), hg_fp_cmp_name);
8918 static void output_hdr_fp(FILE *fout, const struct func_prototype *fp,
8921 const struct parsed_proto *pp;
8922 char *p, namebuf[NAMELEN];
8928 for (; count > 0; count--, fp++) {
8929 if (fp->has_ret == -1)
8930 fprintf(fout, "// ret unresolved\n");
8932 fprintf(fout, "// dep:");
8933 for (j = 0; j < fp->dep_func_cnt; j++) {
8934 fprintf(fout, " %s/", fp->dep_func[j].name);
8935 if (fp->dep_func[j].proto != NULL)
8936 fprintf(fout, "%04x/%d", fp->dep_func[j].proto->regmask_dep,
8937 fp->dep_func[j].proto->has_ret);
8939 fprintf(fout, "\n");
8942 p = strchr(fp->name, '@');
8944 memcpy(namebuf, fp->name, p - fp->name);
8945 namebuf[p - fp->name] = 0;
8953 pp = proto_parse(g_fhdr, name, 1);
8954 if (pp != NULL && pp->is_include)
8957 if (fp->pp != NULL) {
8958 // part of seed, output later
8962 regmask_dep = fp->regmask_dep;
8963 argc_normal = fp->argc_stack;
8964 if (fp->ptr_taken && regmask_dep
8965 && (regmask_dep & ~(mxCX|mxDX)) == 0)
8967 if ((regmask_dep & mxDX) || fp->argc_stack > 0)
8968 regmask_dep |= mxCX | mxDX;
8971 fprintf(fout, "%-5s",
8972 fp->pp ? fp->pp->ret_type.name :
8973 fp->has_ret64 ? "__int64" :
8974 fp->has_ret ? "int" : "void");
8975 if (regmask_dep && (fp->is_stdcall || fp->argc_stack > 0)
8976 && (regmask_dep & ~mxCX) == 0)
8978 fprintf(fout, "/*__thiscall*/ ");
8982 else if ((regmask_dep == (mxCX | mxDX)
8983 && (fp->is_stdcall || fp->argc_stack == 0))
8984 || (regmask_dep == mxCX && fp->argc_stack == 0))
8986 fprintf(fout, " __fastcall ");
8987 if (!(regmask_dep & (1 << xDX)) && fp->argc_stack == 0)
8993 else if (regmask_dep && !fp->is_stdcall) {
8994 fprintf(fout, "/*__usercall*/ ");
8996 else if (regmask_dep) {
8997 fprintf(fout, "/*__userpurge*/ ");
8999 else if (fp->is_stdcall)
9000 fprintf(fout, " __stdcall ");
9002 fprintf(fout, " __cdecl ");
9004 fprintf(fout, "%s(", name);
9007 for (j = 0; j < xSP; j++) {
9008 if (regmask_dep & (1 << j)) {
9011 fprintf(fout, ", ");
9013 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
9015 fprintf(fout, "int");
9016 fprintf(fout, " a%d/*<%s>*/", arg, regs_r32[j]);
9020 for (j = 0; j < argc_normal; j++) {
9023 fprintf(fout, ", ");
9024 if (fp->pp != NULL) {
9025 fprintf(fout, "%s", fp->pp->arg[arg - 1].type.name);
9026 if (!fp->pp->arg[arg - 1].type.is_ptr)
9030 fprintf(fout, "int ");
9031 fprintf(fout, "a%d", arg);
9034 fprintf(fout, ");\n");
9038 static void output_hdr(FILE *fout)
9040 static const char *lmod_c_names[] = {
9041 [OPLM_UNSPEC] = "???",
9042 [OPLM_BYTE] = "uint8_t",
9043 [OPLM_WORD] = "uint16_t",
9044 [OPLM_DWORD] = "uint32_t",
9045 [OPLM_QWORD] = "uint64_t",
9047 const struct scanned_var *var;
9048 struct func_prototype *fp;
9049 char line[256] = { 0, };
9053 // add stuff from headers
9054 for (i = 0; i < pp_cache_size; i++) {
9055 if (pp_cache[i].is_cinc && !pp_cache[i].is_stdcall)
9056 snprintf(name, sizeof(name), "_%s", pp_cache[i].name);
9058 snprintf(name, sizeof(name), "%s", pp_cache[i].name);
9059 fp = hg_fp_add(name);
9060 fp->pp = &pp_cache[i];
9061 fp->argc_stack = fp->pp->argc_stack;
9062 fp->is_stdcall = fp->pp->is_stdcall;
9063 fp->regmask_dep = get_pp_arg_regmask_src(fp->pp);
9064 fp->has_ret = !IS(fp->pp->ret_type.name, "void");
9068 qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_name);
9069 for (i = 0; i < hg_fp_cnt; i++)
9070 hg_fp_resolve_deps(&hg_fp[i]);
9072 // adjust functions referenced from data segment
9073 do_func_refs_from_data();
9075 // final adjustments
9076 for (i = 0; i < hg_fp_cnt; i++) {
9077 if (hg_fp[i].eax_pass && (hg_fp[i].regmask_dep & mxAX))
9078 hg_fp[i].has_ret = 1;
9081 // note: messes up .proto ptr, don't use
9082 //qsort(hg_fp, hg_fp_cnt, sizeof(hg_fp[0]), hg_fp_cmp_id);
9085 for (i = 0; i < hg_var_cnt; i++) {
9088 if (var->pp != NULL)
9091 else if (var->is_c_str)
9092 fprintf(fout, "extern %-8s %s[];", "char", var->name);
9094 fprintf(fout, "extern %-8s %s;",
9095 lmod_c_names[var->lmod], var->name);
9098 fprintf(fout, " // seeded");
9099 fprintf(fout, "\n");
9102 fprintf(fout, "\n");
9104 // output function prototypes
9105 output_hdr_fp(fout, hg_fp, hg_fp_cnt);
9108 fprintf(fout, "\n// - seed -\n");
9111 while (fgets(line, sizeof(line), g_fhdr))
9112 fwrite(line, 1, strlen(line), fout);
9115 // '=' needs special treatment
9117 static char *next_word_s(char *w, size_t wsize, char *s)
9124 if (*s == '\'' && s[1] != '\r' && s[1] != '\n') {
9126 for (i = 1; i < wsize - 1; i++) {
9128 printf("warning: missing closing quote: \"%s\"\n", s);
9137 for (; i < wsize - 1; i++) {
9138 if (s[i] == 0 || my_isblank(s[i]) || (s[i] == '=' && i > 0))
9144 if (s[i] != 0 && !my_isblank(s[i]) && s[i] != '=')
9145 printf("warning: '%s' truncated\n", w);
9150 static int cmpstringp(const void *p1, const void *p2)
9152 return strcmp(*(char * const *)p1, *(char * const *)p2);
9155 static int is_xref_needed(char *p, char **rlist, int rlist_len)
9160 if (strstr(p, "..."))
9161 // unable to determine, assume needed
9164 if (*p == '.') // .text, .data, ...
9165 // ref from other data or non-function -> no
9168 p2 = strpbrk(p, "+:\r\n\x18");
9171 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9172 // referenced from removed code
9178 static int ida_xrefs_show_need(FILE *fasm, char *p,
9179 char **rlist, int rlist_len)
9185 p = strrchr(p, ';');
9186 if (p != NULL && *p == ';') {
9187 if (IS_START(p + 2, "sctref"))
9189 if (IS_START(p + 2, "DATA XREF: ")) {
9191 if (is_xref_needed(p, rlist, rlist_len))
9199 if (!my_fgets(line, sizeof(line), fasm))
9201 // non-first line is always indented
9202 if (!my_isblank(line[0]))
9205 // should be no content, just comment
9210 p = strrchr(p, ';');
9213 if (IS_START(p, "sctref")) {
9218 // it's printed once, but no harm to check again
9219 if (IS_START(p, "DATA XREF: "))
9222 if (is_xref_needed(p, rlist, rlist_len)) {
9227 fseek(fasm, pos, SEEK_SET);
9231 static void scan_variables(FILE *fasm, char **rlist, int rlist_len)
9233 struct scanned_var *var;
9234 char line[256] = { 0, };
9243 // skip to next data section
9244 while (my_fgets(line, sizeof(line), fasm))
9249 if (*p == 0 || *p == ';')
9252 p = sskip(next_word_s(words[0], sizeof(words[0]), p));
9253 if (*p == 0 || *p == ';')
9256 if (*p != 's' || !IS_START(p, "segment para public"))
9262 if (p == NULL || !IS_START(p, "segment para public"))
9266 if (!IS_START(p, "'DATA'"))
9270 while (my_fgets(line, sizeof(line), fasm))
9275 no_identifier = my_isblank(*p);
9278 if (*p == 0 || *p == ';')
9281 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9282 words[wordc][0] = 0;
9283 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9284 if (*p == 0 || *p == ';') {
9290 if (wordc == 2 && IS(words[1], "ends"))
9295 if (no_identifier) {
9296 if (wordc >= 3 && IS(words[0], "dd") && IS(words[1], "offset"))
9297 hg_ref_add(words[2]);
9301 if (IS_START(words[0], "__IMPORT_DESCRIPTOR_")) {
9302 // when this starts, we don't need anything from this section
9306 // check refs comment(s)
9307 if (!ida_xrefs_show_need(fasm, p, rlist, rlist_len))
9310 if ((hg_var_cnt & 0xff) == 0) {
9311 hg_vars = realloc(hg_vars, sizeof(hg_vars[0])
9312 * (hg_var_cnt + 0x100));
9313 my_assert_not(hg_vars, NULL);
9314 memset(hg_vars + hg_var_cnt, 0, sizeof(hg_vars[0]) * 0x100);
9317 var = &hg_vars[hg_var_cnt++];
9318 snprintf(var->name, sizeof(var->name), "%s", words[0]);
9320 // maybe already in seed header?
9321 var->pp = proto_parse(g_fhdr, var->name, 1);
9322 if (var->pp != NULL) {
9323 if (var->pp->is_fptr) {
9324 var->lmod = OPLM_DWORD;
9327 else if (var->pp->is_func)
9329 else if (!guess_lmod_from_c_type(&var->lmod, &var->pp->type))
9330 aerr("unhandled C type '%s' for '%s'\n",
9331 var->pp->type.name, var->name);
9337 if (IS(words[1], "dd")) {
9338 var->lmod = OPLM_DWORD;
9339 if (wordc >= 4 && IS(words[2], "offset"))
9340 hg_ref_add(words[3]);
9342 else if (IS(words[1], "dw"))
9343 var->lmod = OPLM_WORD;
9344 else if (IS(words[1], "db")) {
9345 var->lmod = OPLM_BYTE;
9346 if (wordc >= 3 && (l = strlen(words[2])) > 4) {
9347 if (words[2][0] == '\'' && IS(words[2] + l - 2, ",0"))
9351 else if (IS(words[1], "dq"))
9352 var->lmod = OPLM_QWORD;
9353 //else if (IS(words[1], "dt"))
9355 aerr("type '%s' not known\n", words[1]);
9363 static void set_label(int i, const char *name)
9369 p = strchr(name, ':');
9373 if (g_labels[i] != NULL && !IS_START(g_labels[i], "algn_"))
9374 aerr("dupe label '%s' vs '%s'?\n", name, g_labels[i]);
9375 g_labels[i] = realloc(g_labels[i], len + 1);
9376 my_assert_not(g_labels[i], NULL);
9377 memcpy(g_labels[i], name, len);
9378 g_labels[i][len] = 0;
9387 static struct chunk_item *func_chunks;
9388 static int func_chunk_cnt;
9389 static int func_chunk_alloc;
9391 static void add_func_chunk(FILE *fasm, const char *name, int line)
9393 if (func_chunk_cnt >= func_chunk_alloc) {
9394 func_chunk_alloc *= 2;
9395 func_chunks = realloc(func_chunks,
9396 func_chunk_alloc * sizeof(func_chunks[0]));
9397 my_assert_not(func_chunks, NULL);
9399 func_chunks[func_chunk_cnt].fptr = ftell(fasm);
9400 func_chunks[func_chunk_cnt].name = strdup(name);
9401 func_chunks[func_chunk_cnt].asmln = line;
9405 static int cmp_chunks(const void *p1, const void *p2)
9407 const struct chunk_item *c1 = p1, *c2 = p2;
9408 return strcmp(c1->name, c2->name);
9411 static void scan_ahead_for_chunks(FILE *fasm)
9421 oldpos = ftell(fasm);
9424 while (my_fgets(line, sizeof(line), fasm))
9435 // get rid of random tabs
9436 for (i = 0; line[i] != 0; i++)
9437 if (line[i] == '\t')
9440 if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9443 next_word(words[0], sizeof(words[0]), p);
9444 if (words[0][0] == 0)
9445 aerr("missing name for func chunk?\n");
9447 add_func_chunk(fasm, words[0], asmln);
9449 else if (IS_START(p, "; sctend"))
9455 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9456 words[wordc][0] = 0;
9457 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9458 if (*p == 0 || *p == ';') {
9464 if (wordc == 2 && IS(words[1], "ends"))
9468 fseek(fasm, oldpos, SEEK_SET);
9472 int main(int argc, char *argv[])
9474 FILE *fout, *fasm, *frlist;
9475 struct parsed_data *pd = NULL;
9477 char **rlist = NULL;
9479 int rlist_alloc = 0;
9480 int func_chunks_used = 0;
9481 int func_chunks_sorted = 0;
9482 int func_chunk_i = -1;
9483 long func_chunk_ret = 0;
9484 int func_chunk_ret_ln = 0;
9485 int scanned_ahead = 0;
9487 char words[20][256];
9488 enum opr_lenmod lmod;
9489 char *sctproto = NULL;
9491 int pending_endp = 0;
9493 int skip_code_end = 0;
9494 int skip_warned = 0;
9507 for (arg = 1; arg < argc; arg++) {
9508 if (IS(argv[arg], "-v"))
9510 else if (IS(argv[arg], "-rf"))
9511 g_allow_regfunc = 1;
9512 else if (IS(argv[arg], "-uc"))
9513 g_allow_user_icall = 1;
9514 else if (IS(argv[arg], "-wu"))
9515 g_nowarn_reguse = 1;
9516 else if (IS(argv[arg], "-m"))
9518 else if (IS(argv[arg], "-hdr"))
9519 g_header_mode = g_quiet_pp = g_allow_regfunc = 1;
9524 if (argc < arg + 3) {
9525 printf("usage:\n%s [options] <.c> <.asm> <hdr.h> [rlist]*\n"
9526 "%s -hdr <out.h> <.asm> <seed.h> [rlist]*\n"
9528 " -hdr - header generation mode\n"
9529 " -rf - allow unannotated indirect calls\n"
9530 " -uc - allow ind. calls/refs to __usercall\n"
9531 " -m - allow multiple .text sections\n"
9532 " -wu - don't warn about bad reg use\n"
9533 "[rlist] is a file with function names to skip,"
9541 asmfn = argv[arg++];
9542 fasm = fopen(asmfn, "r");
9543 my_assert_not(fasm, NULL);
9545 hdrfn = argv[arg++];
9546 g_fhdr = fopen(hdrfn, "r");
9547 my_assert_not(g_fhdr, NULL);
9550 rlist = malloc(rlist_alloc * sizeof(rlist[0]));
9551 my_assert_not(rlist, NULL);
9552 // needs special handling..
9553 rlist[rlist_len++] = "__alloca_probe";
9555 func_chunk_alloc = 32;
9556 func_chunks = malloc(func_chunk_alloc * sizeof(func_chunks[0]));
9557 my_assert_not(func_chunks, NULL);
9559 memset(words, 0, sizeof(words));
9561 for (; arg < argc; arg++) {
9564 frlist = fopen(argv[arg], "r");
9565 my_assert_not(frlist, NULL);
9567 while (my_fgets(line, sizeof(line), frlist)) {
9569 if (*p == 0 || *p == ';')
9572 if (IS_START(p, "#if 0")
9573 || (g_allow_regfunc && IS_START(p, "#if NO_REGFUNC")))
9577 else if (IS_START(p, "#endif"))
9584 p = next_word(words[0], sizeof(words[0]), p);
9585 if (words[0][0] == 0)
9588 if (rlist_len >= rlist_alloc) {
9589 rlist_alloc = rlist_alloc * 2 + 64;
9590 rlist = realloc(rlist, rlist_alloc * sizeof(rlist[0]));
9591 my_assert_not(rlist, NULL);
9593 rlist[rlist_len++] = strdup(words[0]);
9601 qsort(rlist, rlist_len, sizeof(rlist[0]), cmpstringp);
9603 fout = fopen(argv[arg_out], "w");
9604 my_assert_not(fout, NULL);
9607 g_eqs = malloc(eq_alloc * sizeof(g_eqs[0]));
9608 my_assert_not(g_eqs, NULL);
9610 for (i = 0; i < ARRAY_SIZE(g_label_refs); i++) {
9611 g_label_refs[i].i = -1;
9612 g_label_refs[i].next = NULL;
9616 scan_variables(fasm, rlist, rlist_len);
9618 while (my_fgets(line, sizeof(line), fasm))
9627 // get rid of random tabs
9628 for (i = 0; line[i] != 0; i++)
9629 if (line[i] == '\t')
9634 if (p[2] == '=' && IS_START(p, "; =============== S U B"))
9635 goto do_pending_endp; // eww..
9637 if (p[2] == 'A' && IS_START(p, "; Attributes:"))
9639 static const char *attrs[] = {
9648 // parse IDA's attribute-list comment
9649 g_ida_func_attr = 0;
9652 for (; *p != 0; p = sskip(p)) {
9653 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9654 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9655 g_ida_func_attr |= 1 << i;
9656 p += strlen(attrs[i]);
9660 if (i == ARRAY_SIZE(attrs)) {
9661 anote("unparsed IDA attr: %s\n", p);
9664 if (IS(attrs[i], "fpd=")) {
9665 p = next_word(words[0], sizeof(words[0]), p);
9670 else if (p[2] == 's' && IS_START(p, "; sctattr:"))
9672 static const char *attrs[] = {
9680 // parse manual attribute-list comment
9681 g_sct_func_attr = 0;
9684 for (; *p != 0; p = sskip(p)) {
9685 for (i = 0; i < ARRAY_SIZE(attrs); i++) {
9686 if (!strncmp(p, attrs[i], strlen(attrs[i]))) {
9687 g_sct_func_attr |= 1 << i;
9688 p += strlen(attrs[i]);
9695 // clear_sf=start,len (in dwords)
9696 ret = sscanf(p, "=%d,%d%n", &g_stack_clear_start,
9697 &g_stack_clear_len, &j);
9699 // clear_regmask=<mask>
9700 ret = sscanf(p, "=%x%n", &g_regmask_init, &j) + 1;
9702 // rm_regmask=<mask>
9703 ret = sscanf(p, "=%x%n", &g_regmask_rm, &j) + 1;
9705 anote("unparsed attr value: %s\n", p);
9710 else if (i == ARRAY_SIZE(attrs)) {
9711 anote("unparsed sct attr: %s\n", p);
9716 else if (p[2] == 'S' && IS_START(p, "; START OF FUNCTION CHUNK FOR "))
9719 next_word(words[0], sizeof(words[0]), p);
9720 if (words[0][0] == 0)
9721 aerr("missing name for func chunk?\n");
9723 if (!scanned_ahead) {
9724 add_func_chunk(fasm, words[0], asmln);
9725 func_chunks_sorted = 0;
9728 else if (p[2] == 'E' && IS_START(p, "; END OF FUNCTION CHUNK"))
9730 if (func_chunk_i >= 0) {
9731 if (func_chunk_i < func_chunk_cnt
9732 && IS(func_chunks[func_chunk_i].name, g_func))
9734 // move on to next chunk
9735 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9737 aerr("seek failed for '%s' chunk #%d\n",
9738 g_func, func_chunk_i);
9739 asmln = func_chunks[func_chunk_i].asmln;
9743 if (func_chunk_ret == 0)
9744 aerr("no return from chunk?\n");
9745 fseek(fasm, func_chunk_ret, SEEK_SET);
9746 asmln = func_chunk_ret_ln;
9752 else if (p[2] == 'F' && IS_START(p, "; FUNCTION CHUNK AT ")) {
9753 func_chunks_used = 1;
9755 if (IS_START(g_func, "sub_")) {
9756 unsigned long addr = strtoul(p, NULL, 16);
9757 unsigned long f_addr = strtoul(g_func + 4, NULL, 16);
9758 if (addr > f_addr && !scanned_ahead) {
9759 //anote("scan_ahead caused by '%s', addr %lx\n",
9761 scan_ahead_for_chunks(fasm);
9763 func_chunks_sorted = 0;
9771 for (i = wordc; i < ARRAY_SIZE(words); i++)
9773 for (wordc = 0; wordc < ARRAY_SIZE(words); wordc++) {
9774 p = sskip(next_word_s(words[wordc], sizeof(words[0]), p));
9775 if (*p == 0 || *p == ';') {
9780 if (*p != 0 && *p != ';')
9781 aerr("too many words\n");
9783 if (skip_code_end) {
9788 // allow asm patches in comments
9790 // skip IDA's forced non-removable comment
9791 if (!IS_START(p, "; sct") && (p2 = strchr(p + 1, ';')))
9794 if (*p == ';' && IS_START(p, "; sct")) {
9795 if (IS_START(p, "; sctpatch:")) {
9797 if (*p == 0 || *p == ';')
9799 goto parse_words; // lame
9801 else if (IS_START(p, "; sctend")) {
9806 else if (g_skip_func)
9807 /* ignore remaining attrs */;
9808 else if (IS_START(p, "; sctproto:")) {
9809 sctproto = strdup(p + 11);
9811 else if (IS_START(p, "; sctskip_start")) {
9814 ops[pi].op = OPP_ABORT;
9815 ops[pi].asmln = asmln;
9821 else if (IS_START(p, "; sctskip_end")) {
9829 awarn("wordc == 0?\n");
9833 // don't care about this:
9834 if (words[0][0] == '.'
9835 || IS(words[0], "include")
9836 || IS(words[0], "assume") || IS(words[1], "segment")
9837 || IS(words[0], "align"))
9843 // do delayed endp processing to collect switch jumptables
9845 if (in_func && !g_skip_func && !end && wordc >= 2
9846 && ((words[0][0] == 'd' && words[0][2] == 0)
9847 || (words[1][0] == 'd' && words[1][2] == 0)))
9850 if (words[1][0] == 'd' && words[1][2] == 0) {
9852 if (g_func_pd_cnt >= pd_alloc) {
9853 pd_alloc = pd_alloc * 2 + 16;
9854 g_func_pd = realloc(g_func_pd,
9855 sizeof(g_func_pd[0]) * pd_alloc);
9856 my_assert_not(g_func_pd, NULL);
9858 pd = &g_func_pd[g_func_pd_cnt];
9860 memset(pd, 0, sizeof(*pd));
9861 strcpy(pd->label, words[0]);
9862 pd->type = OPT_CONST;
9863 pd->lmod = lmod_from_directive(words[1]);
9869 anote("skipping alignment byte?\n");
9872 lmod = lmod_from_directive(words[0]);
9873 if (lmod != pd->lmod)
9874 aerr("lmod change? %d->%d\n", pd->lmod, lmod);
9877 if (pd->count_alloc < pd->count + wordc) {
9878 pd->count_alloc = pd->count_alloc * 2 + 14 + wordc;
9879 pd->d = realloc(pd->d, sizeof(pd->d[0]) * pd->count_alloc);
9880 my_assert_not(pd->d, NULL);
9882 for (; i < wordc; i++) {
9883 if (IS(words[i], "offset")) {
9884 pd->type = OPT_OFFSET;
9887 p = strchr(words[i], ',');
9890 if (pd->type == OPT_OFFSET)
9891 pd->d[pd->count].u.label = strdup(words[i]);
9893 pd->d[pd->count].u.val = parse_number(words[i], 0);
9894 pd->d[pd->count].bt_i = -1;
9900 if (in_func && !g_skip_func) {
9902 gen_hdr(g_func, pi);
9904 gen_func(fout, g_fhdr, g_func, pi);
9909 g_ida_func_attr = 0;
9910 g_sct_func_attr = 0;
9911 g_stack_clear_start = 0;
9912 g_stack_clear_len = 0;
9919 func_chunks_used = 0;
9922 memset(&ops, 0, pi * sizeof(ops[0]));
9927 for (i = 0; i < g_func_pd_cnt; i++) {
9929 if (pd->type == OPT_OFFSET) {
9930 for (j = 0; j < pd->count; j++)
9931 free(pd->d[j].u.label);
9946 if (IS(words[1], "proc")) {
9948 aerr("proc '%s' while in_func '%s'?\n",
9951 if (bsearch(&p, rlist, rlist_len, sizeof(rlist[0]), cmpstringp))
9953 strcpy(g_func, words[0]);
9954 set_label(0, words[0]);
9959 if (IS(words[1], "endp"))
9962 aerr("endp '%s' while not in_func?\n", words[0]);
9963 if (!IS(g_func, words[0]))
9964 aerr("endp '%s' while in_func '%s'?\n",
9967 aerr("endp '%s' while skipping code\n", words[0]);
9969 if ((g_ida_func_attr & IDAFA_THUNK) && pi == 1
9970 && ops[0].op == OP_JMP && ops[0].operand[0].segment)
9976 if (!g_skip_func && func_chunks_used) {
9977 // start processing chunks
9978 struct chunk_item *ci, key = { g_func, 0 };
9980 func_chunk_ret = ftell(fasm);
9981 func_chunk_ret_ln = asmln;
9982 if (!func_chunks_sorted) {
9983 qsort(func_chunks, func_chunk_cnt,
9984 sizeof(func_chunks[0]), cmp_chunks);
9985 func_chunks_sorted = 1;
9987 ci = bsearch(&key, func_chunks, func_chunk_cnt,
9988 sizeof(func_chunks[0]), cmp_chunks);
9990 aerr("'%s' needs chunks, but none found\n", g_func);
9991 func_chunk_i = ci - func_chunks;
9992 for (; func_chunk_i > 0; func_chunk_i--)
9993 if (!IS(func_chunks[func_chunk_i - 1].name, g_func))
9996 ret = fseek(fasm, func_chunks[func_chunk_i].fptr, SEEK_SET);
9998 aerr("seek failed for '%s' chunk #%d\n", g_func, func_chunk_i);
9999 asmln = func_chunks[func_chunk_i].asmln;
10007 if (wordc == 2 && IS(words[1], "ends")) {
10011 goto do_pending_endp;
10015 // scan for next text segment
10016 while (my_fgets(line, sizeof(line), fasm)) {
10019 if (*p == 0 || *p == ';')
10022 if (strstr(p, "segment para public 'CODE' use32"))
10029 p = strchr(words[0], ':');
10031 set_label(pi, words[0]);
10035 if (!in_func || g_skip_func || skip_code) {
10036 if (!skip_warned && !g_skip_func && g_labels[pi] != NULL) {
10038 anote("skipping from '%s'\n", g_labels[pi]);
10041 free(g_labels[pi]);
10042 g_labels[pi] = NULL;
10046 if (wordc > 1 && IS(words[1], "="))
10049 aerr("unhandled equ, wc=%d\n", wordc);
10050 if (g_eqcnt >= eq_alloc) {
10052 g_eqs = realloc(g_eqs, eq_alloc * sizeof(g_eqs[0]));
10053 my_assert_not(g_eqs, NULL);
10056 len = strlen(words[0]);
10057 if (len > sizeof(g_eqs[0].name) - 1)
10058 aerr("equ name too long: %d\n", len);
10059 strcpy(g_eqs[g_eqcnt].name, words[0]);
10061 if (!IS(words[3], "ptr"))
10062 aerr("unhandled equ\n");
10063 if (IS(words[2], "dword"))
10064 g_eqs[g_eqcnt].lmod = OPLM_DWORD;
10065 else if (IS(words[2], "word"))
10066 g_eqs[g_eqcnt].lmod = OPLM_WORD;
10067 else if (IS(words[2], "byte"))
10068 g_eqs[g_eqcnt].lmod = OPLM_BYTE;
10069 else if (IS(words[2], "qword"))
10070 g_eqs[g_eqcnt].lmod = OPLM_QWORD;
10072 aerr("bad lmod: '%s'\n", words[2]);
10074 g_eqs[g_eqcnt].offset = parse_number(words[4], 0);
10079 if (pi >= ARRAY_SIZE(ops))
10080 aerr("too many ops\n");
10082 parse_op(&ops[pi], words, wordc);
10084 ops[pi].datap = sctproto;
10099 // vim:ts=2:shiftwidth=2:expandtab